blob: 8f31171068538634bc21e1a7720e93c57ed78d3c [file] [log] [blame]
Randall Spangler7993f252013-01-29 15:01:12 -08001/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
Bill Richardson253a58e2011-10-03 14:00:58 -07002 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
Bill Richardson94d70342011-10-04 08:36:09 -07005 * Delay/beep functions used in dev-mode kernel selection.
Bill Richardson253a58e2011-10-03 14:00:58 -07006 */
7
Bill Richardson0c3ba242013-03-29 11:09:30 -07008#include "sysincludes.h"
9
Bill Richardson94d70342011-10-04 08:36:09 -070010#include "crc32.h"
Bill Richardson253a58e2011-10-03 14:00:58 -070011#include "gbb_header.h"
12#include "utility.h"
13#include "vboot_api.h"
14#include "vboot_audio.h"
Bill Richardson94d70342011-10-04 08:36:09 -070015#include "vboot_audio_private.h"
Bill Richardson253a58e2011-10-03 14:00:58 -070016#include "vboot_common.h"
17
Bill Richardson931728a2011-11-10 17:08:23 -080018/* BIOS doesn't have /usr/include */
19#ifndef UINT_MAX
20#define UINT_MAX 4294967295U /* 0xffffffff */
21#endif
Bill Richardson253a58e2011-10-03 14:00:58 -070022
Randall Spangler7993f252013-01-29 15:01:12 -080023/*
24 * Need one second of noise in the first 22 seconds.
Alexandru M Stan30617772015-12-18 15:28:32 -080025 * Total delay >= 30 seconds, <= 5 minutes.
Randall Spangler7993f252013-01-29 15:01:12 -080026 */
Alexandru M Stan30617772015-12-18 15:28:32 -080027#define REQUIRED_NOISE_TIME 1000
28#define REQUIRED_NOISE_WITHIN 22000
29#define REQUIRED_TOTAL_DELAY 30000
30#define MAX_CUSTOM_DELAY 300000
Bill Richardson253a58e2011-10-03 14:00:58 -070031
Bill Richardson94d70342011-10-04 08:36:09 -070032/* These are visible externally only to make testing easier */
33VbDevMusicNote default_notes_[] = { {20000, 0}, /* 20 seconds */
34 {250, 400}, /* two beeps */
35 {250, 0},
36 {250, 400},
37 {9250, 0} }; /* total 30 seconds */
38uint32_t default_count_ = sizeof(default_notes_) / sizeof(VbDevMusicNote);
Bill Richardson253a58e2011-10-03 14:00:58 -070039
Bill Richardson94d70342011-10-04 08:36:09 -070040VbDevMusicNote short_notes_[] = { {2000, 0} }; /* two seconds */
41uint32_t short_count_ = sizeof(short_notes_) / sizeof(VbDevMusicNote);
42
43/* No need to dynamically allocate this, is there? */
44static VbAudioContext au;
Bill Richardson253a58e2011-10-03 14:00:58 -070045
Bill Richardson037dba22012-01-19 13:47:33 -080046/* Convert from msecs to VbExGetTimer() units. */
47static uint64_t ticks_per_msec = 0; /* Initialized by VbAudioOpen() */
48static uint64_t VbMsecToTicks(uint16_t msec) {
49 return ticks_per_msec * msec;
Bill Richardson253a58e2011-10-03 14:00:58 -070050}
51
Randall Spangler7993f252013-01-29 15:01:12 -080052/**
53 * Find and return a valid set of note events.
54 *
55 * We'll use the user's struct if possible, but we will still enforce the
56 * 30-second timeout and require at least a second of audible noise within that
57 * period. We allocate storage for two reasons: the user's struct will be in
58 * flash, which is slow to read, and we may need one extra note at the end to
59 * pad out the user's notes to a full 30 seconds. The caller should free it
60 * when finished.
Bill Richardson94d70342011-10-04 08:36:09 -070061 */
Randall Spangler7993f252013-01-29 15:01:12 -080062static void VbGetDevMusicNotes(VbAudioContext *audio, int use_short)
63{
64 VbDevMusicNote *notebuf = 0;
65 VbDevMusicNote *builtin = 0;
66 VbDevMusic *hdr = CUSTOM_MUSIC_NOTES;
67 uint32_t maxsize = CUSTOM_MUSIC_MAXSIZE; /* always <= flash size (8M) */
68 uint32_t maxnotes, mysum, mylen, i;
69 uint32_t this_msecs, on_msecs, total_msecs;
70 uint32_t count;
Bill Richardson253a58e2011-10-03 14:00:58 -070071
Vadim Bendebury7aa250f2013-08-09 16:02:28 -070072 VBDEBUG(("VbGetDevMusicNotes: use_short is %d, hdr is %p, "
Randall Spangler7993f252013-01-29 15:01:12 -080073 "maxsize is %d\n", use_short, hdr, maxsize));
Bill Richardson253a58e2011-10-03 14:00:58 -070074
Randall Spangler7993f252013-01-29 15:01:12 -080075 if (use_short) {
76 builtin = short_notes_;
77 count = short_count_;
78 goto nope;
79 }
Bill Richardson253a58e2011-10-03 14:00:58 -070080
Randall Spangler7993f252013-01-29 15:01:12 -080081 builtin = default_notes_;
82 count = default_count_;
Bill Richardson94d70342011-10-04 08:36:09 -070083
Randall Spangler7993f252013-01-29 15:01:12 -080084 /* If we can't beep in the background, don't allow customization. */
85 if (!audio->background_beep)
86 goto nope;
Bill Richardson94d70342011-10-04 08:36:09 -070087
Randall Spangler7993f252013-01-29 15:01:12 -080088 if (!hdr || maxsize < sizeof(VbDevMusic))
89 goto nope;
Bill Richardson94d70342011-10-04 08:36:09 -070090
Randall Spangler664096b2016-10-13 16:16:41 -070091 if (0 != memcmp(hdr->sig, "$SND", sizeof(hdr->sig))) {
Randall Spangler7993f252013-01-29 15:01:12 -080092 VBDEBUG(("VbGetDevMusicNotes: bad sig\n"));
93 goto nope;
94 }
Bill Richardson94d70342011-10-04 08:36:09 -070095
Randall Spangler7993f252013-01-29 15:01:12 -080096 /*
97 * How many notes will fit in the flash region? One more than you'd
98 * think, because there's one note in the header itself.
99 */
100 maxnotes = 1 + (maxsize - sizeof(VbDevMusic)) / sizeof(VbDevMusicNote);
101 if (hdr->count == 0 || hdr->count > maxnotes) {
102 VBDEBUG(("VbGetDevMusicNotes: count=%d maxnotes=%d\n",
103 hdr->count, maxnotes));
104 goto nope;
105 }
Bill Richardson94d70342011-10-04 08:36:09 -0700106
Randall Spangler7993f252013-01-29 15:01:12 -0800107 /*
108 * CUSTOM_MUSIC_MAXSIZE can't be larger than the size of the flash
109 * (around 8M or so) so this isn't really necessary, but let's be safe
110 * anyway.
111 */
112 if ((sizeof(VbDevMusicNote) > UINT_MAX / hdr->count) ||
113 (sizeof(hdr->count) >
114 UINT_MAX - hdr->count * sizeof(VbDevMusicNote))) {
Vadim Bendebury7aa250f2013-08-09 16:02:28 -0700115 VBDEBUG(("VbGetDevMusicNotes: count=%d, just isn't right\n",
116 hdr->count));
Randall Spangler7993f252013-01-29 15:01:12 -0800117 goto nope;
118 }
Bill Richardson931728a2011-11-10 17:08:23 -0800119
Randall Spangler7993f252013-01-29 15:01:12 -0800120 /* Now we know this won't overflow */
121 mylen = (uint32_t)(sizeof(hdr->count) +
122 hdr->count * sizeof(VbDevMusicNote));
123 mysum = Crc32(&(hdr->count), mylen);
Bill Richardson94d70342011-10-04 08:36:09 -0700124
Randall Spangler7993f252013-01-29 15:01:12 -0800125 if (mysum != hdr->checksum) {
126 VBDEBUG(("VbGetDevMusicNotes: mysum=%08x, want=%08x\n",
127 mysum, hdr->checksum));
128 goto nope;
129 }
Bill Richardson94d70342011-10-04 08:36:09 -0700130
Vadim Bendebury7aa250f2013-08-09 16:02:28 -0700131 VBDEBUG(("VbGetDevMusicNotes: custom notes struct at %p\n", hdr));
Bill Richardson94d70342011-10-04 08:36:09 -0700132
Randall Spangler7993f252013-01-29 15:01:12 -0800133 /*
134 * Measure the audible sound up to the first 22 seconds, being careful
135 * to avoid rollover. The note time is 16 bits, and the note count is
136 * 32 bits. The product should fit in 64 bits.
137 */
138 total_msecs = 0;
139 on_msecs = 0;
140 for (i=0; i < hdr->count; i++) {
141 this_msecs = hdr->notes[i].msec ;
142 if (this_msecs) {
143 total_msecs += this_msecs;
144 if (total_msecs <= REQUIRED_NOISE_WITHIN &&
145 hdr->notes[i].frequency >= 100 &&
146 hdr->notes[i].frequency <= 2000)
147 on_msecs += this_msecs;
148 }
149 }
Bill Richardson94d70342011-10-04 08:36:09 -0700150
Randall Spangler7993f252013-01-29 15:01:12 -0800151 /* We require at least one second of noise in the first 22 seconds */
Vadim Bendebury7aa250f2013-08-09 16:02:28 -0700152 VBDEBUG(("VbGetDevMusicNotes: with %d msecs of sound to begin\n",
Randall Spangler7993f252013-01-29 15:01:12 -0800153 on_msecs));
154 if (on_msecs < REQUIRED_NOISE_TIME)
155 goto nope;
Bill Richardson94d70342011-10-04 08:36:09 -0700156
Randall Spangler7993f252013-01-29 15:01:12 -0800157 /*
Alexandru M Stan30617772015-12-18 15:28:32 -0800158 * We'll also require that the total time be less than 5 minutes. No
Randall Spangler7993f252013-01-29 15:01:12 -0800159 * real reason, it just gives us less to worry about.
160 */
Vadim Bendebury7aa250f2013-08-09 16:02:28 -0700161 VBDEBUG(("VbGetDevMusicNotes: lasting %d msecs\n", total_msecs));
Randall Spangler7993f252013-01-29 15:01:12 -0800162 if (total_msecs > MAX_CUSTOM_DELAY) {
163 goto nope;
164 }
Bill Richardson94d70342011-10-04 08:36:09 -0700165
Randall Spangler7993f252013-01-29 15:01:12 -0800166 /* One more check, just to be paranoid. */
167 if (hdr->count > (UINT_MAX / sizeof(VbDevMusicNote) - 1)) {
168 VBDEBUG(("VbGetDevMusicNotes: they're all out to get me!\n"));
169 goto nope;
170 }
Bill Richardson931728a2011-11-10 17:08:23 -0800171
Randall Spangler7993f252013-01-29 15:01:12 -0800172 /* Looks good. Allocate the space (plus one) and copy it over. */
Randall Spangler559a1102016-10-18 14:41:22 -0700173 notebuf = malloc((hdr->count + 1) * sizeof(VbDevMusicNote));
Randall Spangler664096b2016-10-13 16:16:41 -0700174 memcpy(notebuf, hdr->notes, hdr->count * sizeof(VbDevMusicNote));
Randall Spangler7993f252013-01-29 15:01:12 -0800175 count = hdr->count;
Bill Richardson94d70342011-10-04 08:36:09 -0700176
Randall Spangler7993f252013-01-29 15:01:12 -0800177 /* We also require at least 30 seconds of delay. */
178 if (total_msecs < REQUIRED_TOTAL_DELAY) {
179 /*
180 * If the total time is less than 30 seconds, the needed
181 * difference will fit in 16 bits.
182 */
183 this_msecs = (REQUIRED_TOTAL_DELAY - total_msecs) & 0xffff;
184 notebuf[hdr->count].msec = this_msecs;
185 notebuf[hdr->count].frequency = 0;
186 count++;
Vadim Bendebury7aa250f2013-08-09 16:02:28 -0700187 VBDEBUG(("VbGetDevMusicNotes: adding %d msecs of silence\n",
Randall Spangler7993f252013-01-29 15:01:12 -0800188 this_msecs));
189 }
Bill Richardson94d70342011-10-04 08:36:09 -0700190
Randall Spangler7993f252013-01-29 15:01:12 -0800191 /* Done */
192 audio->music_notes = notebuf;
193 audio->note_count = count;
194 audio->free_notes_when_done = 1;
195 return;
Bill Richardson94d70342011-10-04 08:36:09 -0700196
Randall Spangler7993f252013-01-29 15:01:12 -0800197 nope:
198 /* No custom notes, use the default. The count is already set. */
199 VBDEBUG(("VbGetDevMusicNotes: using %d default notes\n", count));
200 audio->music_notes = builtin;
201 audio->note_count = count;
202 audio->free_notes_when_done = 0;
Bill Richardson253a58e2011-10-03 14:00:58 -0700203}
204
205
Randall Spangler7993f252013-01-29 15:01:12 -0800206/**
207 * Initialization function. Returns context for processing dev-mode delay.
208 */
209VbAudioContext *VbAudioOpen(VbCommonParams *cparams)
210{
Simon Glass527ba812013-07-25 08:48:47 -0600211 GoogleBinaryBlockHeader *gbb = cparams->gbb;
Randall Spangler7993f252013-01-29 15:01:12 -0800212 VbAudioContext *audio = &au;
213 int use_short = 0;
214 uint64_t a, b;
Bill Richardson253a58e2011-10-03 14:00:58 -0700215
Randall Spangler7993f252013-01-29 15:01:12 -0800216 /* Note: may need to allocate things here in future */
Bill Richardson253a58e2011-10-03 14:00:58 -0700217
Randall Spangler7993f252013-01-29 15:01:12 -0800218 /* Calibrate audio delay */
219 a = VbExGetTimer();
220 VbExSleepMs(10);
221 b = VbExGetTimer();
222 ticks_per_msec = (b - a) / 10ULL ;
Simon Glass981cb2a2013-08-12 15:12:47 -0600223 VBDEBUG(("VbAudioOpen() - ticks_per_msec is %" PRIu64 "\n",
224 ticks_per_msec));
Bill Richardson037dba22012-01-19 13:47:33 -0800225
Randall Spangler7993f252013-01-29 15:01:12 -0800226 /* Initialize */
Randall Spangler664096b2016-10-13 16:16:41 -0700227 memset(audio, 0, sizeof(*audio));
Randall Spangler7993f252013-01-29 15:01:12 -0800228 audio->background_beep = 1;
229 audio->play_until = b; /* "zero" starts now */
Bill Richardson253a58e2011-10-03 14:00:58 -0700230
Randall Spangler7993f252013-01-29 15:01:12 -0800231 /* See if we have full background sound capability or not. */
232 if (VBERROR_SUCCESS != VbExBeep(0,0)) {
233 VBDEBUG(("VbAudioOpen() - VbExBeep() is limited\n"));
234 audio->background_beep = 0;
235 }
Bill Richardson253a58e2011-10-03 14:00:58 -0700236
Randall Spangler7993f252013-01-29 15:01:12 -0800237 /*
238 * Prepare to generate audio/delay event. Use a short developer screen
239 * delay if indicated by GBB flags.
240 */
241 if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1
242 && (gbb->flags & GBB_FLAG_DEV_SCREEN_SHORT_DELAY)) {
243 VBDEBUG(("VbAudioOpen() - using short dev screen delay\n"));
244 use_short = 1;
245 }
Bill Richardson253a58e2011-10-03 14:00:58 -0700246
Randall Spangler7993f252013-01-29 15:01:12 -0800247 VbGetDevMusicNotes(audio, use_short);
248 VBDEBUG(("VbAudioOpen() - note count %d\n", audio->note_count));
Bill Richardson253a58e2011-10-03 14:00:58 -0700249
Randall Spangler7993f252013-01-29 15:01:12 -0800250 return audio;
Bill Richardson253a58e2011-10-03 14:00:58 -0700251}
252
Randall Spangler7993f252013-01-29 15:01:12 -0800253/**
254 * Caller should loop without extra delay until this returns false.
255 */
256int VbAudioLooping(VbAudioContext *audio)
257{
258 uint64_t now;
259 uint16_t freq = audio->current_frequency;
260 uint16_t msec = 0;
261 int looping = 1;
Bill Richardson253a58e2011-10-03 14:00:58 -0700262
Randall Spangler7993f252013-01-29 15:01:12 -0800263 now = VbExGetTimer();
264 while (audio->next_note < audio->note_count &&
265 now >= audio->play_until) {
266 freq = audio->music_notes[audio->next_note].frequency;
267 msec = audio->music_notes[audio->next_note].msec;
268 audio->play_until += VbMsecToTicks(msec);
269 audio->next_note++;
270 }
Bill Richardson253a58e2011-10-03 14:00:58 -0700271
Randall Spangler7993f252013-01-29 15:01:12 -0800272 if (now >= audio->play_until) {
273 looping = 0;
274 freq = 0;
275 }
Bill Richardson253a58e2011-10-03 14:00:58 -0700276
Randall Spangler7993f252013-01-29 15:01:12 -0800277 /* Do action here. */
278 if (audio->background_beep) {
279 if (audio->current_frequency != freq) {
280 VbExBeep(0, freq);
281 audio->current_frequency = freq;
282 }
283 } else if (freq && msec) {
284 VbExBeep(msec, freq);
285 now = VbExGetTimer();
286 }
Bill Richardson253a58e2011-10-03 14:00:58 -0700287
Randall Spangler7993f252013-01-29 15:01:12 -0800288 audio->last_time = now;
289 return looping;
Bill Richardson253a58e2011-10-03 14:00:58 -0700290}
291
Randall Spangler7993f252013-01-29 15:01:12 -0800292/**
293 * Caller should call this prior to booting.
294 */
295void VbAudioClose(VbAudioContext *audio)
296{
297 VbExBeep(0,0);
298 if (audio->free_notes_when_done)
Randall Spangler559a1102016-10-18 14:41:22 -0700299 free(audio->music_notes);
Bill Richardson253a58e2011-10-03 14:00:58 -0700300}