1
/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2
* Use of this source code is governed by a BSD-style license that can be
3
* found in the LICENSE file.
5
* Delay/beep functions used in dev-mode kernel selection.
9
#include "gbb_header.h"
11
#include "vboot_api.h"
12
#include "vboot_audio.h"
13
#include "vboot_audio_private.h"
14
#include "vboot_common.h"
16
/* BIOS doesn't have /usr/include */
18
#define UINT_MAX 4294967295U /* 0xffffffff */
21
/* Need one second of noise in the first 22 seconds.
22
* Total delay >= 30 seconds, <= 60 seconds. */
23
#define REQUIRED_NOISE_TIME 1000
24
#define REQUIRED_NOISE_WITHIN 22000
25
#define REQUIRED_TOTAL_DELAY 30000
26
#define MAX_CUSTOM_DELAY 60000
28
/* These are visible externally only to make testing easier */
29
VbDevMusicNote default_notes_[] = { {20000, 0}, /* 20 seconds */
30
{250, 400}, /* two beeps */
33
{9250, 0} }; /* total 30 seconds */
34
uint32_t default_count_ = sizeof(default_notes_) / sizeof(VbDevMusicNote);
36
VbDevMusicNote short_notes_[] = { {2000, 0} }; /* two seconds */
37
uint32_t short_count_ = sizeof(short_notes_) / sizeof(VbDevMusicNote);
39
/* No need to dynamically allocate this, is there? */
40
static VbAudioContext au;
43
/* Convert from msecs to VbExGetTimer() units. */
44
static uint64_t ticks_per_msec = 0; /* Initialized by VbAudioOpen() */
45
static uint64_t VbMsecToTicks(uint16_t msec) {
46
return ticks_per_msec * msec;
49
/* Find and return a valid set of note events. We'll use the user's struct
50
* if possible, but we will still enforce the 30-second timeout and require at
51
* least a second of audible noise within that period. We allocate storage for
52
* two reasons: the user's struct will be in flash, which is slow to read, and
53
* we may need one extra note at the end to pad out the user's notes to a full
54
* 30 seconds. The caller should free it when finished.
56
static void VbGetDevMusicNotes(VbAudioContext *audio, int use_short) {
57
VbDevMusicNote *notebuf = 0;
58
VbDevMusicNote *builtin = 0;
59
VbDevMusic *hdr = CUSTOM_MUSIC_NOTES;
60
uint32_t maxsize = CUSTOM_MUSIC_MAXSIZE; /* always <= flash size (8M) */
61
uint32_t maxnotes, mysum, mylen, i;
62
uint32_t this_msecs, on_msecs, total_msecs;
65
VBDEBUG(("VbGetDevMusicNotes: use_short is %d, hdr is %lx, maxsize is %d\n",
66
use_short, hdr, maxsize));
69
builtin = short_notes_;
74
builtin = default_notes_;
75
count = default_count_;
77
/* If we can't beep in the background, don't allow customization. */
78
if (!audio->background_beep)
81
if (!hdr || maxsize < sizeof(VbDevMusic))
84
if (0 != Memcmp(hdr->sig, "$SND", sizeof(hdr->sig))) {
85
VBDEBUG(("VbGetDevMusicNotes: bad sig\n"));
89
/* How many notes will fit in the flash region? One more than you'd think,
90
* because there's one note in the header itself.
92
maxnotes = 1 + (maxsize - sizeof(VbDevMusic)) / sizeof(VbDevMusicNote);
93
if (hdr->count == 0 || hdr->count > maxnotes) {
94
VBDEBUG(("VbGetDevMusicNotes: count=%d maxnotes=%d\n",
95
hdr->count, maxnotes));
99
/* CUSTOM_MUSIC_MAXSIZE can't be larger than the size of the flash (around 8M
100
* or so) so this isn't really necessary, but let's be safe anyway.
102
if ((sizeof(VbDevMusicNote) > UINT_MAX / hdr->count) ||
103
(sizeof(hdr->count) > UINT_MAX - hdr->count * sizeof(VbDevMusicNote))) {
104
VBDEBUG(("VbGetDevMusicNotes: count=%d, just isn't right\n"));
108
/* Now we know this won't overflow */
109
mylen = (uint32_t)(sizeof(hdr->count) + hdr->count * sizeof(VbDevMusicNote));
110
mysum = Crc32(&(hdr->count), mylen);
112
if (mysum != hdr->checksum) {
113
VBDEBUG(("VbGetDevMusicNotes: mysum=%08x, want=%08x\n",
114
mysum, hdr->checksum));
118
VBDEBUG(("VbGetDevMusicNotes: custom notes struct found at %lx\n", hdr));
120
/* Measure the audible sound up to the first 22 seconds, being careful to
121
* avoid rollover. The note time is 16 bits, and the note count is 32 bits.
122
* The product should fit in 64 bits.
126
for (i=0; i < hdr->count; i++) {
127
this_msecs = hdr->notes[i].msec ;
129
total_msecs += this_msecs;
130
if (total_msecs <= REQUIRED_NOISE_WITHIN &&
131
hdr->notes[i].frequency >= 100 && hdr->notes[i].frequency <= 2000)
132
on_msecs += this_msecs;
136
/* We require at least one second of noise in the first 22 seconds */
137
VBDEBUG(("VbGetDevMusicNotes: with %ld msecs of sound to begin\n",
139
if (on_msecs < REQUIRED_NOISE_TIME) {
143
/* We'll also require that the total time be less than a minute. No real
144
* reason, it just gives us less to worry about.
146
VBDEBUG(("VbGetDevMusicNotes: lasting %ld msecs\n", total_msecs));
147
if (total_msecs > MAX_CUSTOM_DELAY) {
151
/* One more check, just to be paranoid. */
152
if (hdr->count > (UINT_MAX / sizeof(VbDevMusicNote) - 1)) {
153
VBDEBUG(("VbGetDevMusicNotes: they're all out to get me!\n"));
157
/* Okay, it looks good. Allocate the space (plus one) and copy it over. */
158
notebuf = VbExMalloc((hdr->count + 1) * sizeof(VbDevMusicNote));
159
Memcpy(notebuf, hdr->notes, hdr->count * sizeof(VbDevMusicNote));
162
/* We also require at least 30 seconds of delay. */
163
if (total_msecs < REQUIRED_TOTAL_DELAY) {
164
/* If the total time is less than 30 seconds, the needed difference will
167
this_msecs = (REQUIRED_TOTAL_DELAY - total_msecs) & 0xffff;
168
notebuf[hdr->count].msec = this_msecs;
169
notebuf[hdr->count].frequency = 0;
171
VBDEBUG(("VbGetDevMusicNotes: adding %ld msecs of silence\n",
176
audio->music_notes = notebuf;
177
audio->note_count = count;
178
audio->free_notes_when_done = 1;
182
/* No custom notes, use the default. The count is already set. */
183
VBDEBUG(("VbGetDevMusicNotes: using %d default notes\n", count));
184
audio->music_notes = builtin;
185
audio->note_count = count;
186
audio->free_notes_when_done = 0;
190
/* Initialization function. Returns context for processing dev-mode delay */
191
VbAudioContext* VbAudioOpen(VbCommonParams* cparams) {
192
GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data;
193
VbAudioContext* audio = &au;
197
/* Note: may need to allocate things here in future */
199
/* Calibrate audio delay */
203
ticks_per_msec = (b - a) / 10ULL ;
204
VBDEBUG(("VbAudioOpen() - ticks_per_msec is %llu\n", ticks_per_msec));
207
Memset(audio, 0, sizeof(*audio));
208
audio->background_beep = 1;
209
audio->play_until = b; /* "zero" starts now */
211
/* See if we have full background sound capability or not. */
212
if (VBERROR_SUCCESS != VbExBeep(0,0)) {
213
VBDEBUG(("VbAudioOpen() - VbExBeep() is limited\n"));
214
audio->background_beep = 0;
217
/* Prepare to generate audio/delay event. Use a short developer screen delay
218
* if indicated by GBB flags.
220
if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1
221
&& (gbb->flags & GBB_FLAG_DEV_SCREEN_SHORT_DELAY)) {
222
VBDEBUG(("VbAudioOpen() - using short developer screen delay\n"));
226
VbGetDevMusicNotes(audio, use_short);
227
VBDEBUG(("VbAudioOpen() - note count %d\n", audio->note_count));
232
/* Caller should loop without extra delay until this returns false */
233
int VbAudioLooping(VbAudioContext* audio) {
235
uint16_t freq = audio->current_frequency;
239
#if defined(CONFIG_SANDBOX)
243
now = VbExGetTimer();
244
while (audio->next_note < audio->note_count && now >= audio->play_until) {
245
freq = audio->music_notes[audio->next_note].frequency;
246
msec = audio->music_notes[audio->next_note].msec;
247
audio->play_until += VbMsecToTicks(msec);
251
if (now >= audio->play_until) {
257
if (audio->background_beep) {
258
if (audio->current_frequency != freq) {
260
audio->current_frequency = freq;
262
} else if (freq && msec) {
263
VbExBeep(msec, freq);
264
now = VbExGetTimer();
267
audio->last_time = now;
271
/* Caller should call this prior to booting */
272
void VbAudioClose(VbAudioContext* audio) {
274
if (audio->free_notes_when_done)
275
VbExFree(audio->music_notes);