// Copyright 2016 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include #include static efi_graphics_output_protocol* fb_get_gop() { static efi_graphics_output_protocol* gop = NULL; if (!gop) { gBS->LocateProtocol(&GraphicsOutputProtocol, NULL, (void**)&gop); } return gop; } uint32_t get_gfx_mode() { efi_graphics_output_protocol* gop = fb_get_gop(); return gop->Mode->Mode; } uint32_t get_gfx_max_mode() { efi_graphics_output_protocol* gop = fb_get_gop(); return gop->Mode->MaxMode; } uint32_t get_gfx_hres() { efi_graphics_output_protocol* gop = fb_get_gop(); efi_graphics_output_mode_information* mode_info; size_t info_size = 0; efi_status status = gop->QueryMode(gop, gop->Mode->Mode, &info_size, &mode_info); if (EFI_ERROR(status)) { return 0; } return mode_info->HorizontalResolution; } uint32_t get_gfx_vres() { efi_graphics_output_protocol* gop = fb_get_gop(); efi_graphics_output_mode_information* mode_info; size_t info_size = 0; efi_status status = gop->QueryMode(gop, gop->Mode->Mode, &info_size, &mode_info); if (EFI_ERROR(status)) { return 0; } return mode_info->VerticalResolution; } void set_gfx_mode(uint32_t mode) { efi_graphics_output_protocol* gop = fb_get_gop(); if (!gop) return; if (mode >= gop->Mode->MaxMode) { printf("invalid framebuffer mode: %u\n", mode); return; } efi_status s = gop->SetMode(gop, mode); if (EFI_ERROR(s)) { printf("could not set mode: %s\n", xefi_strerror(s)); } gBS->Stall(1000); gSys->ConOut->SetCursorPosition(gSys->ConOut, 0, 0); } void set_gfx_mode_from_cmdline(const char* fbres) { if (!fbres) return; efi_graphics_output_protocol* gop = fb_get_gop(); if (!gop) return; uint32_t hres = 0; hres = atol(fbres); char* x = strchr(fbres, 'x'); if (!x) return; x++; uint32_t vres = 0; vres = atol(x); if (!hres || !vres) return; uint32_t max_mode = gop->Mode->MaxMode; for (uint32_t i = 0; i < max_mode; i++) { efi_graphics_output_mode_information* mode_info; size_t info_size = 0; efi_status status = gop->QueryMode(gop, i, &info_size, &mode_info); if (EFI_ERROR(status)) { printf("Could not retrieve mode %d: %s\n", i, xefi_strerror(status)); continue; } if (mode_info->HorizontalResolution == hres && mode_info->VerticalResolution == vres) { set_gfx_mode(i); return; } } printf("Could not find framebuffer mode %ux%u; using default mode = %ux%u\n", hres, vres, gop->Mode->Info->HorizontalResolution, gop->Mode->Info->VerticalResolution); gBS->Stall(5000000); } void print_fb_modes() { efi_graphics_output_protocol* gop = fb_get_gop(); uint32_t max_mode = gop->Mode->MaxMode; uint32_t cur_mode = gop->Mode->Mode; for (uint32_t i = 0; i < max_mode; i++) { efi_graphics_output_mode_information* mode_info; size_t info_size = 0; efi_status status = gop->QueryMode(gop, i, &info_size, &mode_info); if (EFI_ERROR(status)) continue; printf(" (%u) %u x %u%s\n", i, mode_info->HorizontalResolution, mode_info->VerticalResolution, i == cur_mode ? " (current)" : ""); } } #include "logo.h" static efi_graphics_output_blt_pixel font_white = { .Red = 0xFF, .Green = 0xFF, .Blue = 0xFF, }; static efi_graphics_output_blt_pixel font_black = { .Red = 0x0, .Green = 0x0, .Blue = 0x0, }; static efi_graphics_output_blt_pixel font_fuchsia = { .Red = 0xFF, .Green = 0x0, .Blue = 0x80, }; void draw_logo() { efi_graphics_output_protocol* gop = fb_get_gop(); if (!gop) return; const uint32_t h_res = gop->Mode->Info->HorizontalResolution; const uint32_t v_res = gop->Mode->Info->VerticalResolution; // Blank the screen, removing vendor UEFI logos gop->Blt(gop, &font_black, EfiBltVideoFill, 0, 0, 0, 0, h_res, v_res, 0); efi_graphics_output_blt_pixel* tmp; unsigned sz = sizeof(efi_graphics_output_blt_pixel) * logo_width * logo_height; if (EFI_ERROR(gBS->AllocatePool(EfiLoaderData, sz, (void*)&tmp))) { // Draw the Fuchsia stripe on the top of the screen gop->Blt(gop, &font_fuchsia, EfiBltVideoFill, 0, 0, 0, 0, h_res, v_res / 100, 0); return; } // Un-RLE the logo unsigned char* iptr = logo_rle; efi_graphics_output_blt_pixel* optr = tmp; unsigned entries = sizeof(logo_rle) / 2; while (entries-- > 0) { unsigned count = *iptr++; unsigned alpha = *iptr++; efi_graphics_output_blt_pixel px = { .Red = (alpha * 0xFF) / 255, .Green = 0, .Blue = (alpha * 0x80) / 255, }; while (count-- > 0) { *optr++ = px; } } gop->Blt(gop, tmp, EfiBltBufferToVideo, 0, 0, h_res - logo_width - (h_res / 75), v_res - logo_height - (v_res / 75), logo_width, logo_height, 0); } #include #include static void putchar(efi_graphics_output_protocol* gop, fb_font* font, unsigned ch, unsigned x, unsigned y, unsigned scale_x, unsigned scale_y, efi_graphics_output_blt_pixel* fg, efi_graphics_output_blt_pixel* bg) { const uint16_t* cdata = font->data + ch * font->height; unsigned fw = font->width; for (unsigned i = 0; i <= font->height; i++) { uint16_t xdata = *cdata++; for (unsigned j = 0; j < fw; j++) { gop->Blt(gop, (xdata & 1) ? fg : bg, EfiBltVideoFill, 0, 0, x + scale_x * j, y + scale_y * i, scale_x, scale_y, 0); xdata >>= 1; } } } void draw_text(const char* text, size_t length, fb_font* font, int x, int y) { efi_graphics_output_protocol* gop = fb_get_gop(); efi_graphics_output_blt_pixel* fg_color = &font_white; if (!gop) return; if (font->color != NULL) { fg_color = font->color; } size_t offset = 0; size_t scale = 1; for (size_t i = 0; i < length; ++i) { unsigned char c = text[i]; if (c > 127) continue; putchar(gop, font, c, x + offset, y, scale, scale, fg_color, &font_black); offset += font->width * scale; } } void draw_nodename(const char* nodename) { efi_graphics_output_protocol* gop = fb_get_gop(); if (!gop) return; fb_font font = { .data = FONT18X32, .width = FONT18X32_WIDTH, .height = FONT18X32_HEIGHT, .color = &font_white, }; const uint32_t h_res = gop->Mode->Info->HorizontalResolution; const uint32_t v_res = gop->Mode->Info->VerticalResolution; size_t length = strlen(nodename); draw_text(nodename, length, &font, h_res - (length + 1) * font.width, v_res / 100 + font.height); } void draw_version(const char* version) { efi_graphics_output_protocol* gop = fb_get_gop(); if (!gop) return; const char* prefix = "GigaBoot 20X6 - Version"; size_t prefix_len = strlen(prefix); size_t version_len = strlen(version); fb_font font = { .data = FONT9X16, .width = FONT9X16_WIDTH, .height = FONT9X16_HEIGHT, .color = &font_fuchsia, }; draw_text(prefix, prefix_len, &font, 0, 0); draw_text(version, version_len, &font, (prefix_len + 1) * font.width, 0); }