1// Copyright 2017 The Fuchsia 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#include "osboot.h"
6
7#include <stdio.h>
8#include <string.h>
9#include <xefi.h>
10
11#include <zircon/pixelformat.h>
12
13static efi_guid AcpiTableGUID = ACPI_TABLE_GUID;
14static efi_guid Acpi2TableGUID = ACPI_20_TABLE_GUID;
15static efi_guid SmbiosTableGUID = SMBIOS_TABLE_GUID;
16static efi_guid Smbios3TableGUID = SMBIOS3_TABLE_GUID;
17static uint8_t ACPI_RSD_PTR[8] = "RSD PTR ";
18static uint8_t SmbiosAnchor[4] = "_SM_";
19static uint8_t Smbios3Anchor[5] = "_SM3_";
20
21uint64_t find_acpi_root(efi_handle img, efi_system_table* sys) {
22    efi_configuration_table* cfgtab = sys->ConfigurationTable;
23    int i;
24
25    for (i = 0; i < sys->NumberOfTableEntries; i++) {
26        if (xefi_cmp_guid(&cfgtab[i].VendorGuid, &AcpiTableGUID) &&
27            xefi_cmp_guid(&cfgtab[i].VendorGuid, &Acpi2TableGUID)) {
28            // not an ACPI table
29            continue;
30        }
31        if (memcmp(cfgtab[i].VendorTable, ACPI_RSD_PTR, 8)) {
32            // not the Root Description Pointer
33            continue;
34        }
35        return (uint64_t)cfgtab[i].VendorTable;
36    }
37    return 0;
38}
39
40uint64_t find_smbios(efi_handle img, efi_system_table* sys) {
41    efi_configuration_table* cfgtab = sys->ConfigurationTable;
42    int i;
43
44    for (i = 0; i < sys->NumberOfTableEntries; i++) {
45        if (!xefi_cmp_guid(&cfgtab[i].VendorGuid, &SmbiosTableGUID)) {
46            if (!memcmp(cfgtab[i].VendorTable, SmbiosAnchor, sizeof(SmbiosAnchor))) {
47                return (uint64_t)cfgtab[i].VendorTable;
48            }
49        } else if (!xefi_cmp_guid(&cfgtab[i].VendorGuid, &Smbios3TableGUID)) {
50            if (!memcmp(cfgtab[i].VendorTable, Smbios3Anchor, sizeof(Smbios3Anchor))) {
51                return (uint64_t)cfgtab[i].VendorTable;
52            }
53        }
54    }
55    return 0;
56}
57
58static void get_bit_range(uint32_t mask, int* high, int* low) {
59    *high = -1;
60    *low = -1;
61    int idx = 0;
62    while (mask) {
63        if (*low < 0 && (mask & 1)) *low = idx;
64        idx++;
65        mask >>= 1;
66    }
67    *high = idx - 1;
68}
69
70static int get_zx_pixel_format_from_bitmask(efi_pixel_bitmask bitmask) {
71    int r_hi = -1, r_lo = -1, g_hi = -1, g_lo = -1, b_hi = -1, b_lo = -1;
72
73    get_bit_range(bitmask.RedMask, &r_hi, &r_lo);
74    get_bit_range(bitmask.GreenMask, &g_hi, &g_lo);
75    get_bit_range(bitmask.BlueMask, &b_hi, &b_lo);
76
77    if (r_lo < 0 || g_lo < 0 || b_lo < 0) {
78        goto unsupported;
79    }
80
81    if ((r_hi == 23 && r_lo == 16) &&
82        (g_hi == 15 && g_lo == 8) &&
83        (b_hi == 7 && b_lo == 0)) {
84        return ZX_PIXEL_FORMAT_RGB_x888;
85    }
86
87    if ((r_hi == 7 && r_lo == 5) &&
88        (g_hi == 4 && g_lo == 2) &&
89        (b_hi == 1 && b_lo == 0)) {
90        return ZX_PIXEL_FORMAT_RGB_332;
91    }
92
93    if ((r_hi == 15 && r_lo == 11) &&
94        (g_hi == 10 && g_lo == 5) &&
95        (b_hi == 4 && b_lo == 0)) {
96        return ZX_PIXEL_FORMAT_RGB_565;
97    }
98
99    if ((r_hi == 7 && r_lo == 6) &&
100        (g_hi == 5 && g_lo == 4) &&
101        (b_hi == 3 && b_lo == 2)) {
102        return ZX_PIXEL_FORMAT_RGB_2220;
103    }
104
105unsupported:
106    printf("unsupported pixel format bitmask: r %08x / g %08x / b %08x\n",
107            bitmask.RedMask, bitmask.GreenMask, bitmask.BlueMask);
108    return ZX_PIXEL_FORMAT_NONE;
109}
110
111uint32_t get_zx_pixel_format(efi_graphics_output_protocol* gop) {
112    efi_graphics_pixel_format efi_fmt = gop->Mode->Info->PixelFormat;
113    switch (efi_fmt) {
114    case PixelBlueGreenRedReserved8BitPerColor:
115        return ZX_PIXEL_FORMAT_RGB_x888;
116    case PixelBitMask:
117        return get_zx_pixel_format_from_bitmask(gop->Mode->Info->PixelInformation);
118    default:
119        printf("unsupported pixel format %d!\n", efi_fmt);
120        return ZX_PIXEL_FORMAT_NONE;
121    }
122}
123