blob: 9e0955ed85c9064621d770be8f7905acb6d1fd32 [file] [log] [blame]
// Copyright 2017 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 <stdio.h>
#include <string.h>
#include <xefi.h>
#include <zircon/pixelformat.h>
#include "osboot.h"
static efi_guid AcpiTableGUID = ACPI_TABLE_GUID;
static efi_guid Acpi2TableGUID = ACPI_20_TABLE_GUID;
static efi_guid SmbiosTableGUID = SMBIOS_TABLE_GUID;
static efi_guid Smbios3TableGUID = SMBIOS3_TABLE_GUID;
static uint8_t ACPI_RSD_PTR[8] = "RSD PTR ";
static uint8_t SmbiosAnchor[4] = "_SM_";
static uint8_t Smbios3Anchor[5] = "_SM3_";
uint64_t find_acpi_root(efi_handle img, efi_system_table* sys) {
efi_configuration_table* cfgtab = sys->ConfigurationTable;
for (size_t i = 0; i < sys->NumberOfTableEntries; i++) {
if (xefi_cmp_guid(&cfgtab[i].VendorGuid, &AcpiTableGUID) &&
xefi_cmp_guid(&cfgtab[i].VendorGuid, &Acpi2TableGUID)) {
// not an ACPI table
continue;
}
if (memcmp(cfgtab[i].VendorTable, ACPI_RSD_PTR, 8)) {
// not the Root Description Pointer
continue;
}
return (uint64_t)cfgtab[i].VendorTable;
}
return 0;
}
uint64_t find_smbios(efi_handle img, efi_system_table* sys) {
efi_configuration_table* cfgtab = sys->ConfigurationTable;
for (size_t i = 0; i < sys->NumberOfTableEntries; i++) {
if (!xefi_cmp_guid(&cfgtab[i].VendorGuid, &SmbiosTableGUID)) {
if (!memcmp(cfgtab[i].VendorTable, SmbiosAnchor, sizeof(SmbiosAnchor))) {
return (uint64_t)cfgtab[i].VendorTable;
}
} else if (!xefi_cmp_guid(&cfgtab[i].VendorGuid, &Smbios3TableGUID)) {
if (!memcmp(cfgtab[i].VendorTable, Smbios3Anchor, sizeof(Smbios3Anchor))) {
return (uint64_t)cfgtab[i].VendorTable;
}
}
}
return 0;
}
static void get_bit_range(uint32_t mask, int* high, int* low) {
*high = -1;
*low = -1;
int idx = 0;
while (mask) {
if (*low < 0 && (mask & 1))
*low = idx;
idx++;
mask >>= 1;
}
*high = idx - 1;
}
static int get_zx_pixel_format_from_bitmask(efi_pixel_bitmask bitmask) {
int r_hi = -1, r_lo = -1, g_hi = -1, g_lo = -1, b_hi = -1, b_lo = -1;
get_bit_range(bitmask.RedMask, &r_hi, &r_lo);
get_bit_range(bitmask.GreenMask, &g_hi, &g_lo);
get_bit_range(bitmask.BlueMask, &b_hi, &b_lo);
if (r_lo < 0 || g_lo < 0 || b_lo < 0) {
goto unsupported;
}
if ((r_hi == 23 && r_lo == 16) && (g_hi == 15 && g_lo == 8) && (b_hi == 7 && b_lo == 0)) {
return ZX_PIXEL_FORMAT_RGB_x888;
}
if ((r_hi == 7 && r_lo == 5) && (g_hi == 4 && g_lo == 2) && (b_hi == 1 && b_lo == 0)) {
return ZX_PIXEL_FORMAT_RGB_332;
}
if ((r_hi == 15 && r_lo == 11) && (g_hi == 10 && g_lo == 5) && (b_hi == 4 && b_lo == 0)) {
return ZX_PIXEL_FORMAT_RGB_565;
}
if ((r_hi == 7 && r_lo == 6) && (g_hi == 5 && g_lo == 4) && (b_hi == 3 && b_lo == 2)) {
return ZX_PIXEL_FORMAT_RGB_2220;
}
unsupported:
printf("unsupported pixel format bitmask: r %08x / g %08x / b %08x\n", bitmask.RedMask,
bitmask.GreenMask, bitmask.BlueMask);
return ZX_PIXEL_FORMAT_NONE;
}
uint32_t get_zx_pixel_format(efi_graphics_output_protocol* gop) {
efi_graphics_pixel_format efi_fmt = gop->Mode->Info->PixelFormat;
switch (efi_fmt) {
case PixelBlueGreenRedReserved8BitPerColor:
return ZX_PIXEL_FORMAT_RGB_x888;
case PixelBitMask:
return get_zx_pixel_format_from_bitmask(gop->Mode->Info->PixelInformation);
default:
printf("unsupported pixel format %d!\n", efi_fmt);
return ZX_PIXEL_FORMAT_NONE;
}
}