2 * Copyright 2015 Google Inc.
4 * See file CREDITS for list of people who contributed to this
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but without any warranty; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
18 #include <libpayload.h>
20 #include <gbb_header.h>
21 #include <vboot_api.h>
22 #include <vboot/screens.h>
23 #include "base/graphics.h"
24 #include "drivers/flash/cbfs.h"
25 #include "drivers/video/display.h"
26 #include "vboot/util/commonparams.h"
29 * This is the base used to specify the size and the coordinate of the image.
30 * For example, height = 40 means 4.0% of the canvas (=drawing area) height.
33 #define VB_SCALE_HALF (VB_SCALE / 2) /* 50.0% */
35 /* Height of the text image per line relative to the canvas size */
36 #define VB_TEXT_HEIGHT 40 /* 4.0% */
38 /* Indicate width or height is automatically set based on the other value */
39 #define VB_SIZE_AUTO 0
41 /* Height of the icons relative to the canvas size */
42 #define VB_ICON_HEIGHT 160
44 /* Vertical position and size of the dividers */
45 #define VB_DIVIDER_WIDTH 800 /* 80.0% */
46 #define VB_DIVIDER_V_OFFSET 160 /* 16.0% */
48 /* Space between 'MODEL' and a model name */
49 #define VB_MODEL_PADDING 10 /* 1.0 % */
51 #define RETURN_ON_ERROR(function_call) do { \
52 VbError_t rv = (function_call); \
57 static char initialized = 0;
58 static struct directory *base_graphics;
59 static struct directory *font_graphics;
60 static struct cbfs_media *ro_cbfs;
65 /* pointer to the localized graphics data and its locale */
66 uint32_t archive_locale;
67 struct directory *archive;
69 /* number of supported language and codes: en, ja, ... */
75 * Load archive into RAM
77 static VbError_t load_archive(const char *name, struct directory **dest)
79 struct directory *dir;
84 printf("%s: loading %s\n", __func__, name);
87 /* load archive from cbfs */
88 dir = cbfs_get_file_content(ro_cbfs, name, CBFS_TYPE_RAW, &size);
90 printf("%s: failed to load %s\n", __func__, name);
91 return VBERROR_INVALID_BMPFV;
94 /* convert endianness of archive header */
95 dir->count = le32toh(dir->count);
96 dir->size = le32toh(dir->size);
98 /* validate the total size */
99 if (dir->size != size) {
100 printf("%s: archive size does not match\n", __func__);
101 return VBERROR_INVALID_BMPFV;
104 /* validate magic field */
105 if (memcmp(dir->magic, CBAR_MAGIC, sizeof(CBAR_MAGIC))) {
106 printf("%s: invalid archive magic\n", __func__);
107 return VBERROR_INVALID_BMPFV;
110 /* validate count field */
111 if (get_first_offset(dir) > dir->size) {
112 printf("%s: invalid count\n", __func__);
113 return VBERROR_INVALID_BMPFV;
116 /* convert endianness of file headers */
117 entry = get_first_dentry(dir);
118 for (i = 0; i < dir->count; i++) {
119 entry[i].offset = le32toh(entry[i].offset);
120 entry[i].size = le32toh(entry[i].size);
125 return VBERROR_SUCCESS;
128 static VbError_t load_localized_graphics(uint32_t locale)
132 /* check whether we've already loaded the archive for this locale */
133 if (locale_data.archive) {
134 if (locale_data.archive_locale == locale)
135 return VBERROR_SUCCESS;
136 /* No need to keep more than one locale graphics at a time */
137 free(locale_data.archive);
140 /* compose archive name using the language code */
141 snprintf(str, sizeof(str), "locale_%s.bin", locale_data.codes[locale]);
142 RETURN_ON_ERROR(load_archive(str, &locale_data.archive));
144 /* Remember what's cached */
145 locale_data.archive_locale = locale;
147 return VBERROR_SUCCESS;
150 static struct dentry *find_file_in_archive(const struct directory *dir,
153 struct dentry *entry;
158 printf("%s: archive not loaded\n", __func__);
162 /* calculate start of the file content section */
163 start = get_first_offset(dir);
164 entry = get_first_dentry(dir);
165 for (i = 0; i < dir->count; i++) {
166 if (strncmp(entry[i].name, name, NAME_LENGTH))
168 /* validate offset & size */
169 if (entry[i].offset < start
170 || entry[i].offset + entry[i].size > dir->size
171 || entry[i].offset > dir->size
172 || entry[i].size > dir->size) {
173 printf("%s: '%s' has invalid offset or size\n",
180 printf("%s: file '%s' not found\n", __func__, name);
186 * Find and draw image in archive
188 static VbError_t draw(struct directory *dir, const char *image_name,
189 int32_t x, int32_t y, int32_t width, int32_t height,
194 file = find_file_in_archive(dir, image_name);
196 return VBERROR_NO_IMAGE_PRESENT;
199 .x = { .n = x, .d = VB_SCALE, },
200 .y = { .n = y, .d = VB_SCALE, },
203 .x = { .n = width, .d = VB_SCALE, },
204 .y = { .n = height, .d = VB_SCALE, },
207 return draw_bitmap((uint8_t *)dir + file->offset, file->size,
211 static VbError_t draw_image(const char *image_name,
212 int32_t x, int32_t y, int32_t width, int32_t height,
215 return draw(base_graphics, image_name, x, y, width, height, pivot);
218 static VbError_t draw_image_locale(const char *image_name, uint32_t locale,
219 int32_t x, int32_t y,
220 int32_t width, int32_t height, char pivot)
223 RETURN_ON_ERROR(load_localized_graphics(locale));
224 rv = draw(locale_data.archive, image_name, x, y, width, height, pivot);
225 if (rv == CBGFX_ERROR_BOUNDARY && width == VB_SIZE_AUTO) {
226 printf("%s: '%s' overflowed. fit it to canvas width\n",
227 __func__, image_name);
228 rv = draw(locale_data.archive, image_name,
229 x, y, VB_SCALE, VB_SIZE_AUTO, pivot);
234 static VbError_t get_image_size(struct directory *dir, const char *image_name,
235 int32_t *width, int32_t *height)
240 file = find_file_in_archive(dir, image_name);
242 return VBERROR_NO_IMAGE_PRESENT;
245 .x = { .n = *width, .d = VB_SCALE, },
246 .y = { .n = *height, .d = VB_SCALE, },
249 rv = get_bitmap_dimension((uint8_t *)dir + file->offset,
252 return VBERROR_UNKNOWN;
254 *width = dim.x.n * VB_SCALE / dim.x.d;
255 *height = dim.y.n * VB_SCALE / dim.y.d;
257 return VBERROR_SUCCESS;
260 static VbError_t get_image_size_locale(const char *image_name, uint32_t locale,
261 int32_t *width, int32_t *height)
263 RETURN_ON_ERROR(load_localized_graphics(locale));
264 return get_image_size(locale_data.archive, image_name, width, height);
267 static int draw_icon(const char *image_name)
269 return draw_image(image_name,
270 VB_SCALE_HALF, VB_SCALE_HALF,
271 VB_SIZE_AUTO, VB_ICON_HEIGHT,
272 PIVOT_H_CENTER|PIVOT_V_BOTTOM);
275 static int draw_text(const char *text, int32_t x, int32_t y,
276 int32_t height, char pivot)
281 sprintf(str, "idx%03d_%02x.bmp", *text, *text);
284 RETURN_ON_ERROR(get_image_size(font_graphics, str, &w, &h));
285 RETURN_ON_ERROR(draw(font_graphics, str,
286 x, y, VB_SIZE_AUTO, height, pivot));
290 return VBERROR_SUCCESS;
293 static int get_text_width(const char *text, int32_t *width, int32_t *height)
298 sprintf(str, "idx%03d_%02x.bmp", *text, *text);
301 RETURN_ON_ERROR(get_image_size(font_graphics, str, &w, &h));
305 return VBERROR_SUCCESS;
308 static VbError_t vboot_draw_footer(uint32_t locale)
311 int32_t x, y, w1, h1, w2, h2, w3, h3;
314 * Draw help URL line: 'For help visit http://.../'. It consits of
315 * three parts: [for_help_left.bmp][URL][for_help_right.bmp].
316 * Since the widths vary, we need to get the widths first then calculate
317 * the horizontal positions of the images.
321 RETURN_ON_ERROR(get_image_size_locale("for_help_left.bmp", locale,
325 RETURN_ON_ERROR(get_image_size(base_graphics, "Url.bmp", &w2, &h2));
329 RETURN_ON_ERROR(get_image_size_locale("for_help_right.bmp", locale,
332 /* Calculate horizontal position to centralize the combined images */
333 x = (VB_SCALE - w1 - w2 - w3) / 2;
334 y = VB_SCALE - VB_DIVIDER_V_OFFSET;
336 /* images are too wide. need to fit them to canvas width */
339 printf("%s: help line overflowed. fit it to canvas width\n",
341 total = w1 + w2 + w3;
343 w1 = VB_SCALE * w1 / total;
344 w2 = VB_SCALE * w2 / total;
345 w3 = VB_SCALE * w3 / total;
347 RETURN_ON_ERROR(draw_image_locale("for_help_left.bmp", locale,
348 x, y, w1, VB_SIZE_AUTO,
349 PIVOT_H_LEFT|PIVOT_V_TOP));
351 RETURN_ON_ERROR(draw_image("Url.bmp",
352 x, y, w2, VB_SIZE_AUTO,
353 PIVOT_H_LEFT|PIVOT_V_TOP));
355 RETURN_ON_ERROR(draw_image_locale("for_help_right.bmp", locale,
356 x, y, w3, VB_SIZE_AUTO,
357 PIVOT_H_LEFT|PIVOT_V_TOP));
360 * Draw model line: 'Model XYZ'. It consists of two parts: 'Model',
361 * which is locale dependent, and 'XYZ', a model name. Model name
362 * consists of individual font images: 'X' 'Y' 'Z'.
364 if (is_cparams_initialized()) {
365 GoogleBinaryBlockHeader *gbb = cparams.gbb_data;
367 hwid = (char *)((uintptr_t)gbb + gbb->hwid_offset);
374 RETURN_ON_ERROR(get_image_size_locale("model_left.bmp", locale,
376 w1 += VB_MODEL_PADDING;
380 RETURN_ON_ERROR(get_text_width(hwid, &w2, &h2));
381 w2 += VB_MODEL_PADDING;
385 RETURN_ON_ERROR(get_image_size_locale("model_right.bmp", locale,
388 /* Calculate horizontal position to centralize the combined images. */
390 * No clever way to redraw the combined images when they overflow but
391 * luckily there is plenty of space for just 'model' + model name.
393 x = (VB_SCALE - w1 - w2 - w3) / 2;
395 RETURN_ON_ERROR(draw_image_locale("model_left.bmp", locale,
396 x, y, VB_SIZE_AUTO, VB_TEXT_HEIGHT,
397 PIVOT_H_LEFT|PIVOT_V_TOP));
399 RETURN_ON_ERROR(draw_text(hwid, x, y, VB_TEXT_HEIGHT,
400 PIVOT_H_LEFT|PIVOT_V_TOP));
402 RETURN_ON_ERROR(draw_image_locale("model_right.bmp", locale,
403 x, y, VB_SIZE_AUTO, VB_TEXT_HEIGHT,
404 PIVOT_H_LEFT|PIVOT_V_TOP));
406 return VBERROR_SUCCESS;
410 * Draws the language section at the top right corner. The language text image
411 * is placed in the middle surrounded by arrows on each side.
413 static VbError_t vboot_draw_language(uint32_t locale)
418 * Right arrow starts from the right edge of the divider, which is
419 * positioned horizontally in the center.
421 x = VB_SCALE_HALF + VB_DIVIDER_WIDTH / 2;
423 /* Draw the right arrow */
426 RETURN_ON_ERROR(get_image_size(base_graphics, "arrow_right.bmp",
429 RETURN_ON_ERROR(draw_image("arrow_right.bmp",
430 x, VB_DIVIDER_V_OFFSET, VB_SIZE_AUTO, VB_TEXT_HEIGHT,
431 PIVOT_H_LEFT|PIVOT_V_BOTTOM));
433 /* Draw the language name */
436 RETURN_ON_ERROR(get_image_size_locale("language.bmp", locale, &w, &h));
438 RETURN_ON_ERROR(draw_image_locale("language.bmp", locale,
439 x, VB_DIVIDER_V_OFFSET, VB_SIZE_AUTO, VB_TEXT_HEIGHT,
440 PIVOT_H_LEFT|PIVOT_V_BOTTOM));
442 /* Draw the left arrow */
445 RETURN_ON_ERROR(get_image_size(base_graphics, "arrow_left.bmp",
448 RETURN_ON_ERROR(draw_image("arrow_left.bmp",
449 x, VB_DIVIDER_V_OFFSET, VB_SIZE_AUTO, VB_TEXT_HEIGHT,
450 PIVOT_H_LEFT|PIVOT_V_BOTTOM));
452 return VBERROR_SUCCESS;
455 static VbError_t draw_base_screen(uint32_t locale, int show_language)
457 const struct rgb_color white = { 0xff, 0xff, 0xff };
459 if (clear_screen(&white))
460 return VBERROR_UNKNOWN;
461 RETURN_ON_ERROR(draw_image("chrome_logo.bmp",
462 (VB_SCALE - VB_DIVIDER_WIDTH)/2,
463 /* '-10' to keep the logo lifted up from the divider */
464 VB_DIVIDER_V_OFFSET - 10,
465 VB_SIZE_AUTO, VB_TEXT_HEIGHT,
466 PIVOT_H_LEFT|PIVOT_V_BOTTOM));
469 RETURN_ON_ERROR(vboot_draw_language(locale));
471 RETURN_ON_ERROR(draw_image("divider_top.bmp",
472 VB_SCALE_HALF, VB_DIVIDER_V_OFFSET,
473 VB_DIVIDER_WIDTH, VB_SIZE_AUTO,
474 PIVOT_H_CENTER|PIVOT_V_TOP));
475 RETURN_ON_ERROR(draw_image("divider_btm.bmp",
476 VB_SCALE_HALF, VB_SCALE - VB_DIVIDER_V_OFFSET,
477 VB_DIVIDER_WIDTH, VB_SIZE_AUTO,
478 PIVOT_H_CENTER|PIVOT_V_BOTTOM));
480 RETURN_ON_ERROR(vboot_draw_footer(locale));
482 return VBERROR_SUCCESS;
485 static VbError_t vboot_draw_base_screen(uint32_t locale)
487 return draw_base_screen(locale, 1);
490 static VbError_t vboot_draw_base_screen_without_language(uint32_t locale)
492 return draw_base_screen(locale, 0);
495 static VbError_t vboot_draw_blank(uint32_t locale)
497 video_console_clear();
498 return VBERROR_SUCCESS;
501 static VbError_t vboot_draw_developer_warning(uint32_t locale)
503 RETURN_ON_ERROR(vboot_draw_base_screen(locale));
504 RETURN_ON_ERROR(draw_icon("VerificationOff.bmp"));
505 RETURN_ON_ERROR(draw_image_locale("verif_off.bmp", locale,
506 VB_SCALE_HALF, VB_SCALE_HALF,
507 VB_SIZE_AUTO, VB_TEXT_HEIGHT,
508 PIVOT_H_CENTER|PIVOT_V_TOP));
509 RETURN_ON_ERROR(draw_image_locale("devmode.bmp", locale,
510 VB_SCALE_HALF, VB_SCALE_HALF + VB_TEXT_HEIGHT,
511 VB_SIZE_AUTO, VB_TEXT_HEIGHT,
512 PIVOT_H_CENTER|PIVOT_V_TOP));
513 return VBERROR_SUCCESS;
516 static VbError_t vboot_draw_recovery_remove(uint32_t locale)
518 RETURN_ON_ERROR(vboot_draw_base_screen(locale));
519 RETURN_ON_ERROR(draw_image_locale("remove.bmp", locale,
520 VB_SCALE_HALF, VB_SCALE_HALF - VB_ICON_HEIGHT,
521 VB_SIZE_AUTO, VB_TEXT_HEIGHT,
522 PIVOT_H_CENTER|PIVOT_V_BOTTOM));
523 RETURN_ON_ERROR(draw_image("RemoveDevices.bmp",
524 VB_SCALE_HALF, VB_SCALE_HALF,
525 VB_SIZE_AUTO, VB_ICON_HEIGHT * 2,
526 PIVOT_H_CENTER|PIVOT_V_CENTER));
527 return VBERROR_SUCCESS;
530 static VbError_t vboot_draw_recovery_no_good(uint32_t locale)
532 RETURN_ON_ERROR(vboot_draw_base_screen(locale));
533 RETURN_ON_ERROR(draw_image_locale("yuck.bmp", locale,
534 VB_SCALE_HALF, VB_SCALE_HALF,
535 VB_SIZE_AUTO, VB_TEXT_HEIGHT,
536 PIVOT_H_CENTER|PIVOT_V_BOTTOM));
537 RETURN_ON_ERROR(draw_image("BadDevices.bmp",
538 VB_SCALE_HALF, VB_SCALE_HALF,
539 VB_SIZE_AUTO, VB_ICON_HEIGHT,
540 PIVOT_H_CENTER|PIVOT_V_TOP));
541 return VBERROR_SUCCESS;
544 static VbError_t vboot_draw_recovery_insert(uint32_t locale)
546 RETURN_ON_ERROR(vboot_draw_base_screen(locale));
547 RETURN_ON_ERROR(draw_image_locale("insert.bmp", locale,
548 VB_SCALE_HALF, VB_SCALE_HALF - VB_ICON_HEIGHT,
549 VB_SIZE_AUTO, VB_TEXT_HEIGHT,
550 PIVOT_H_CENTER|PIVOT_V_BOTTOM));
551 RETURN_ON_ERROR(draw_image("InsertDevices.bmp",
552 VB_SCALE_HALF, VB_SCALE_HALF,
553 VB_SIZE_AUTO, VB_ICON_HEIGHT * 2,
554 PIVOT_H_CENTER|PIVOT_V_CENTER));
555 return VBERROR_SUCCESS;
558 static VbError_t vboot_draw_recovery_to_dev(uint32_t locale)
560 RETURN_ON_ERROR(vboot_draw_base_screen(locale));
561 RETURN_ON_ERROR(draw_image_locale("todev.bmp", locale,
562 VB_SCALE_HALF, VB_SCALE_HALF,
563 VB_SIZE_AUTO, VB_TEXT_HEIGHT * 4,
564 PIVOT_H_CENTER|PIVOT_V_CENTER));
565 return VBERROR_SUCCESS;
568 static VbError_t vboot_draw_developer_to_norm(uint32_t locale)
570 RETURN_ON_ERROR(vboot_draw_base_screen(locale));
571 RETURN_ON_ERROR(draw_icon("VerificationOff.bmp"));
572 RETURN_ON_ERROR(draw_image_locale("verif_off.bmp", locale,
573 VB_SCALE_HALF, VB_SCALE_HALF,
574 VB_SIZE_AUTO, VB_TEXT_HEIGHT,
575 PIVOT_H_CENTER|PIVOT_V_TOP));
576 RETURN_ON_ERROR(draw_image_locale("tonorm.bmp", locale,
577 VB_SCALE_HALF, VB_SCALE_HALF + VB_TEXT_HEIGHT,
578 VB_SIZE_AUTO, VB_TEXT_HEIGHT * 3,
579 PIVOT_H_CENTER|PIVOT_V_TOP));
580 return VBERROR_SUCCESS;
583 static VbError_t vboot_draw_wait(uint32_t locale)
586 * Currently, language cannot be changed while EC software sync is
587 * taking place because keyboard is disabled.
589 RETURN_ON_ERROR(vboot_draw_base_screen_without_language(locale));
590 RETURN_ON_ERROR(draw_image_locale("update.bmp", locale,
591 VB_SCALE_HALF, VB_SCALE_HALF,
592 VB_SIZE_AUTO, VB_TEXT_HEIGHT * 3,
593 PIVOT_H_CENTER|PIVOT_V_CENTER));
594 return VBERROR_SUCCESS;
597 static VbError_t vboot_draw_to_norm_confirmed(uint32_t locale)
599 RETURN_ON_ERROR(vboot_draw_base_screen(locale));
600 RETURN_ON_ERROR(draw_icon("VerificationOn.bmp"));
601 RETURN_ON_ERROR(draw_image_locale("verif_on.bmp", locale,
602 VB_SCALE_HALF, VB_SCALE_HALF,
603 VB_SIZE_AUTO, VB_TEXT_HEIGHT,
604 PIVOT_H_CENTER|PIVOT_V_TOP));
605 RETURN_ON_ERROR(draw_image_locale("reboot_erase.bmp", locale,
606 VB_SCALE_HALF, VB_SCALE_HALF + VB_TEXT_HEIGHT,
607 VB_SIZE_AUTO, VB_TEXT_HEIGHT,
608 PIVOT_H_CENTER|PIVOT_V_TOP));
609 return VBERROR_SUCCESS;
612 static VbError_t vboot_draw_os_broken(uint32_t locale)
614 RETURN_ON_ERROR(vboot_draw_base_screen(locale));
615 RETURN_ON_ERROR(draw_icon("Warning.bmp"));
616 RETURN_ON_ERROR(draw_image_locale("os_broken.bmp", locale,
617 VB_SCALE_HALF, VB_SCALE_HALF,
618 VB_SIZE_AUTO, VB_TEXT_HEIGHT * 2,
619 PIVOT_H_CENTER|PIVOT_V_TOP));
620 return VBERROR_SUCCESS;
623 /* we may export this in the future for the board customization */
624 struct vboot_screen_descriptor {
625 uint32_t id; /* VB_SCREEN_* */
626 VbError_t (*draw)(uint32_t locale); /* draw function */
627 const char *mesg; /* fallback message */
630 static const struct vboot_screen_descriptor vboot_screens[] = {
632 .id = VB_SCREEN_BLANK,
633 .draw = vboot_draw_blank,
637 .id = VB_SCREEN_DEVELOPER_WARNING,
638 .draw = vboot_draw_developer_warning,
639 .mesg = "OS verification is OFF\n"
640 "Press SPACE to re-enable.\n",
643 .id = VB_SCREEN_RECOVERY_REMOVE,
644 .draw = vboot_draw_recovery_remove,
645 .mesg = "Please remove all external devices to begin recovery\n",
648 .id = VB_SCREEN_RECOVERY_NO_GOOD,
649 .draw = vboot_draw_recovery_no_good,
650 .mesg = "The device you inserted does not contain Chrome OS.\n",
653 .id = VB_SCREEN_RECOVERY_INSERT,
654 .draw = vboot_draw_recovery_insert,
655 .mesg = "Chrome OS is missing or damaged.\n"
656 "Please insert a recovery USB stick or SD card.\n",
659 .id = VB_SCREEN_RECOVERY_TO_DEV,
660 .draw = vboot_draw_recovery_to_dev,
661 .mesg = "To turn OS verificaion OFF, press ENTER.\n"
662 "Your system will reboot and local data will be cleared.\n"
663 "To go back, press ESC.\n",
666 .id = VB_SCREEN_DEVELOPER_TO_NORM,
667 .draw = vboot_draw_developer_to_norm,
668 .mesg = "OS verification is OFF\n"
669 "Press ENTER to confirm you wish to turn OS verification on.\n"
670 "Your system will reboot and local data will be cleared.\n"
671 "To go back, press ESC.\n",
674 .id = VB_SCREEN_WAIT,
675 .draw = vboot_draw_wait,
676 .mesg = "Your system is applying a critical update.\n"
677 "Please do not turn off.\n",
680 .id = VB_SCREEN_TO_NORM_CONFIRMED,
681 .draw = vboot_draw_to_norm_confirmed,
682 .mesg = "OS verification is ON\n"
683 "Your system will reboot and local data will be cleared.\n",
686 .id = VB_SCREEN_OS_BROKEN,
687 .draw = vboot_draw_os_broken,
688 .mesg = "Chrome OS may be broken.\n"
689 "Remove media and initiate recovery.\n",
693 static const struct vboot_screen_descriptor *get_screen_descriptor(uint32_t id)
696 for (i = 0; i < ARRAY_SIZE(vboot_screens); i++) {
697 if (vboot_screens[i].id == id)
698 return &vboot_screens[i];
703 static void print_fallback_message(const struct vboot_screen_descriptor *desc)
705 const struct rgb_color white = { 0xff, 0xff, 0xff };
708 graphics_print_single_text_block(desc->mesg, &white, 0, 15,
709 VIDEO_PRINTF_ALIGN_CENTER);
711 clear_screen(&white);
714 static VbError_t draw_screen(uint32_t screen_type, uint32_t locale)
716 VbError_t rv = VBERROR_UNKNOWN;
717 const struct vboot_screen_descriptor *desc;
719 desc = get_screen_descriptor(screen_type);
721 printf("Not a valid screen type: 0x%x\n", screen_type);
722 return VBERROR_INVALID_SCREEN_INDEX;
725 if (locale >= locale_data.count) {
726 printf("Unsupported locale (%d)\n", locale);
727 print_fallback_message(desc);
728 return VBERROR_INVALID_PARAMETER;
731 /* if no drawing function is registered, fallback msg will be printed */
733 rv = desc->draw(locale);
735 printf("Drawing failed (0x%x)\n", rv);
738 print_fallback_message(desc);
739 return VBERROR_SCREEN_DRAW;
742 return VBERROR_SUCCESS;
745 static void vboot_init_locale(void)
747 char *locales, *loc_start, *loc;
750 locale_data.count = 0;
752 /* Load locale list from cbfs */
753 locales = cbfs_get_file_content(ro_cbfs, "locales",
754 CBFS_TYPE_RAW, &size);
755 if (!locales || !size) {
756 printf("%s: locale list not found\n", __func__);
760 /* Copy the file and null-terminate it */
761 loc_start = malloc(size + 1);
763 printf("%s: out of memory\n", __func__);
767 memcpy(loc_start, locales, size);
768 loc_start[size] = '\0';
771 printf("%s: Supported locales:", __func__);
773 while (loc - loc_start < size
774 && locale_data.count < ARRAY_SIZE(locale_data.codes)) {
775 char *lang = strsep(&loc, "\n");
776 if (!lang || !strlen(lang))
778 printf(" %s,", lang);
779 locale_data.codes[locale_data.count] = lang;
784 printf(" (%d locales)\n", locale_data.count);
787 static VbError_t vboot_init_screen(void)
789 if (ro_cbfs == NULL) {
790 ro_cbfs = cbfs_ro_media();
791 if (ro_cbfs == NULL) {
792 printf("No RO CBFS found.\n");
793 return VBERROR_UNKNOWN;
798 return VBERROR_UNKNOWN;
800 /* create a list of supported locales */
803 /* load generic (location-free) graphics data. ignore errors.
804 * fallback screens will be drawn for missing data */
805 load_archive("vbgfx.bin", &base_graphics);
807 /* load font graphics */
808 load_archive("font.bin", &font_graphics);
810 /* reset localized graphics. we defer loading it. */
811 locale_data.archive = NULL;
815 return VBERROR_SUCCESS;
818 int vboot_draw_screen(uint32_t screen, uint32_t locale)
820 static uint32_t current_screen = VB_SCREEN_BLANK;
822 printf("%s: screen=0x%x locale=%d\n", __func__, screen, locale);
825 if (vboot_init_screen())
826 return VBERROR_UNKNOWN;
829 /* If requested screen is the same as the current one, we're done. */
830 if (screen == current_screen && locale == locale_data.current)
831 return VBERROR_SUCCESS;
833 /* If the screen is blank, turn off the backlight; else turn it on. */
834 backlight_update(VB_SCREEN_BLANK == screen ? 0 : 1);
836 /* TODO: draw only locale dependent part if current_screen == screen */
837 RETURN_ON_ERROR(draw_screen(screen, locale));
839 current_screen = screen;
840 locale_data.current = locale;
842 return VBERROR_SUCCESS;
845 int vboot_get_locale_count(void)
848 if (vboot_init_screen())
849 return VBERROR_UNKNOWN;
851 return locale_data.count;