vboot_audio.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /* Copyright (c) 2013 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.
  4. *
  5. * Delay/beep functions used in dev-mode kernel selection.
  6. */
  7. #include "2sysincludes.h"
  8. #include "2common.h"
  9. #include "sysincludes.h"
  10. #include "crc32.h"
  11. #include "gbb_header.h"
  12. #include "utility.h"
  13. #include "vboot_api.h"
  14. #include "vboot_audio.h"
  15. #include "vboot_audio_private.h"
  16. #include "vboot_common.h"
  17. /* BIOS doesn't have /usr/include */
  18. #ifndef UINT_MAX
  19. #define UINT_MAX 4294967295U /* 0xffffffff */
  20. #endif
  21. /*
  22. * Need one second of noise in the first 22 seconds.
  23. * Total delay >= 30 seconds, <= 5 minutes.
  24. */
  25. #define REQUIRED_NOISE_TIME 1000
  26. #define REQUIRED_NOISE_WITHIN 22000
  27. #define REQUIRED_TOTAL_DELAY 30000
  28. #define MAX_CUSTOM_DELAY 300000
  29. /* These are visible externally only to make testing easier */
  30. VbDevMusicNote default_notes_[] = { {20000, 0}, /* 20 seconds */
  31. {250, 400}, /* two beeps */
  32. {250, 0},
  33. {250, 400},
  34. {9250, 0} }; /* total 30 seconds */
  35. 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);
  38. /* No need to dynamically allocate this, is there? */
  39. static VbAudioContext au;
  40. /* Convert from msecs to VbExGetTimer() units. */
  41. static uint64_t ticks_per_msec = 0; /* Initialized by VbAudioOpen() */
  42. static uint64_t VbMsecToTicks(uint16_t msec) {
  43. return ticks_per_msec * msec;
  44. }
  45. /**
  46. * Find and return a valid set of note events.
  47. *
  48. * We'll use the user's struct if possible, but we will still enforce the
  49. * 30-second timeout and require at least a second of audible noise within that
  50. * period. We allocate storage for two reasons: the user's struct will be in
  51. * flash, which is slow to read, and we may need one extra note at the end to
  52. * pad out the user's notes to a full 30 seconds. The caller should free it
  53. * when finished.
  54. */
  55. static void VbGetDevMusicNotes(VbAudioContext *audio, int use_short)
  56. {
  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;
  63. uint32_t count;
  64. VB2_DEBUG("VbGetDevMusicNotes: use_short is %d, hdr is %p, "
  65. "maxsize is %d\n", use_short, hdr, maxsize);
  66. if (use_short) {
  67. builtin = short_notes_;
  68. count = short_count_;
  69. goto nope;
  70. }
  71. builtin = default_notes_;
  72. count = default_count_;
  73. /* If we can't beep in the background, don't allow customization. */
  74. if (!audio->background_beep)
  75. goto nope;
  76. if (!hdr || maxsize < sizeof(VbDevMusic))
  77. goto nope;
  78. if (0 != memcmp(hdr->sig, "$SND", sizeof(hdr->sig))) {
  79. VB2_DEBUG("VbGetDevMusicNotes: bad sig\n");
  80. goto nope;
  81. }
  82. /*
  83. * How many notes will fit in the flash region? One more than you'd
  84. * think, because there's one note in the header itself.
  85. */
  86. maxnotes = 1 + (maxsize - sizeof(VbDevMusic)) / sizeof(VbDevMusicNote);
  87. if (hdr->count == 0 || hdr->count > maxnotes) {
  88. VB2_DEBUG("VbGetDevMusicNotes: count=%d maxnotes=%d\n",
  89. hdr->count, maxnotes);
  90. goto nope;
  91. }
  92. /*
  93. * CUSTOM_MUSIC_MAXSIZE can't be larger than the size of the flash
  94. * (around 8M or so) so this isn't really necessary, but let's be safe
  95. * anyway.
  96. */
  97. if ((sizeof(VbDevMusicNote) > UINT_MAX / hdr->count) ||
  98. (sizeof(hdr->count) >
  99. UINT_MAX - hdr->count * sizeof(VbDevMusicNote))) {
  100. VB2_DEBUG("VbGetDevMusicNotes: count=%d, just isn't right\n",
  101. hdr->count);
  102. goto nope;
  103. }
  104. /* Now we know this won't overflow */
  105. mylen = (uint32_t)(sizeof(hdr->count) +
  106. hdr->count * sizeof(VbDevMusicNote));
  107. mysum = Crc32(&(hdr->count), mylen);
  108. if (mysum != hdr->checksum) {
  109. VB2_DEBUG("VbGetDevMusicNotes: mysum=%08x, want=%08x\n",
  110. mysum, hdr->checksum);
  111. goto nope;
  112. }
  113. VB2_DEBUG("VbGetDevMusicNotes: custom notes struct at %p\n", hdr);
  114. /*
  115. * Measure the audible sound up to the first 22 seconds, being careful
  116. * to avoid rollover. The note time is 16 bits, and the note count is
  117. * 32 bits. The product should fit in 64 bits.
  118. */
  119. total_msecs = 0;
  120. on_msecs = 0;
  121. for (i=0; i < hdr->count; i++) {
  122. this_msecs = hdr->notes[i].msec ;
  123. if (this_msecs) {
  124. total_msecs += this_msecs;
  125. if (total_msecs <= REQUIRED_NOISE_WITHIN &&
  126. hdr->notes[i].frequency >= 100 &&
  127. hdr->notes[i].frequency <= 2000)
  128. on_msecs += this_msecs;
  129. }
  130. }
  131. /* We require at least one second of noise in the first 22 seconds */
  132. VB2_DEBUG("VbGetDevMusicNotes: with %d msecs of sound to begin\n",
  133. on_msecs);
  134. if (on_msecs < REQUIRED_NOISE_TIME)
  135. goto nope;
  136. /*
  137. * We'll also require that the total time be less than 5 minutes. No
  138. * real reason, it just gives us less to worry about.
  139. */
  140. VB2_DEBUG("VbGetDevMusicNotes: lasting %d msecs\n", total_msecs);
  141. if (total_msecs > MAX_CUSTOM_DELAY) {
  142. goto nope;
  143. }
  144. /* One more check, just to be paranoid. */
  145. if (hdr->count > (UINT_MAX / sizeof(VbDevMusicNote) - 1)) {
  146. VB2_DEBUG("VbGetDevMusicNotes: they're all out to get me!\n");
  147. goto nope;
  148. }
  149. /* Looks good. Allocate the space (plus one) and copy it over. */
  150. notebuf = malloc((hdr->count + 1) * sizeof(VbDevMusicNote));
  151. memcpy(notebuf, hdr->notes, hdr->count * sizeof(VbDevMusicNote));
  152. count = hdr->count;
  153. /* We also require at least 30 seconds of delay. */
  154. if (total_msecs < REQUIRED_TOTAL_DELAY) {
  155. /*
  156. * If the total time is less than 30 seconds, the needed
  157. * difference will fit in 16 bits.
  158. */
  159. this_msecs = (REQUIRED_TOTAL_DELAY - total_msecs) & 0xffff;
  160. notebuf[hdr->count].msec = this_msecs;
  161. notebuf[hdr->count].frequency = 0;
  162. count++;
  163. VB2_DEBUG("VbGetDevMusicNotes: adding %d msecs of silence\n",
  164. this_msecs);
  165. }
  166. /* Done */
  167. audio->music_notes = notebuf;
  168. audio->note_count = count;
  169. audio->free_notes_when_done = 1;
  170. return;
  171. nope:
  172. /* No custom notes, use the default. The count is already set. */
  173. VB2_DEBUG("VbGetDevMusicNotes: using %d default notes\n", count);
  174. audio->music_notes = builtin;
  175. audio->note_count = count;
  176. audio->free_notes_when_done = 0;
  177. }
  178. /**
  179. * Initialization function. Returns context for processing dev-mode delay.
  180. */
  181. VbAudioContext *VbAudioOpen(VbCommonParams *cparams)
  182. {
  183. GoogleBinaryBlockHeader *gbb = cparams->gbb;
  184. VbAudioContext *audio = &au;
  185. int use_short = 0;
  186. uint64_t a, b;
  187. /* Note: may need to allocate things here in future */
  188. /* Calibrate audio delay */
  189. a = VbExGetTimer();
  190. VbExSleepMs(10);
  191. b = VbExGetTimer();
  192. ticks_per_msec = (b - a) / 10ULL ;
  193. VB2_DEBUG("VbAudioOpen() - ticks_per_msec is %" PRIu64 "\n",
  194. ticks_per_msec);
  195. /* Initialize */
  196. memset(audio, 0, sizeof(*audio));
  197. audio->background_beep = 1;
  198. audio->play_until = b; /* "zero" starts now */
  199. /* See if we have full background sound capability or not. */
  200. if (VBERROR_SUCCESS != VbExBeep(0,0)) {
  201. VB2_DEBUG("VbAudioOpen() - VbExBeep() is limited\n");
  202. audio->background_beep = 0;
  203. }
  204. /*
  205. * Prepare to generate audio/delay event. Use a short developer screen
  206. * delay if indicated by GBB flags.
  207. */
  208. if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1
  209. && (gbb->flags & GBB_FLAG_DEV_SCREEN_SHORT_DELAY)) {
  210. VB2_DEBUG("VbAudioOpen() - using short dev screen delay\n");
  211. use_short = 1;
  212. }
  213. VbGetDevMusicNotes(audio, use_short);
  214. VB2_DEBUG("VbAudioOpen() - note count %d\n", audio->note_count);
  215. return audio;
  216. }
  217. /**
  218. * Caller should loop without extra delay until this returns false.
  219. */
  220. int VbAudioLooping(VbAudioContext *audio)
  221. {
  222. uint64_t now;
  223. uint16_t freq = audio->current_frequency;
  224. uint16_t msec = 0;
  225. int looping = 1;
  226. now = VbExGetTimer();
  227. while (audio->next_note < audio->note_count &&
  228. now >= audio->play_until) {
  229. freq = audio->music_notes[audio->next_note].frequency;
  230. msec = audio->music_notes[audio->next_note].msec;
  231. audio->play_until += VbMsecToTicks(msec);
  232. audio->next_note++;
  233. }
  234. if (now >= audio->play_until) {
  235. looping = 0;
  236. freq = 0;
  237. }
  238. /* Do action here. */
  239. if (audio->background_beep) {
  240. if (audio->current_frequency != freq) {
  241. VbExBeep(0, freq);
  242. audio->current_frequency = freq;
  243. }
  244. } else if (freq && msec) {
  245. VbExBeep(msec, freq);
  246. now = VbExGetTimer();
  247. }
  248. audio->last_time = now;
  249. return looping;
  250. }
  251. /**
  252. * Caller should call this prior to booting.
  253. */
  254. void VbAudioClose(VbAudioContext *audio)
  255. {
  256. VbExBeep(0,0);
  257. if (audio->free_notes_when_done)
  258. free(audio->music_notes);
  259. }