uboot/arch/x86/lib/sfi.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015 Google, Inc
   3 * Written by Simon Glass <sjg@chromium.org>
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8/*
   9 * Intel Simple Firmware Interface (SFI)
  10 *
  11 * Yet another way to pass information to the Linux kernel.
  12 *
  13 * See https://simplefirmware.org/ for details
  14 */
  15
  16#include <common.h>
  17#include <cpu.h>
  18#include <dm.h>
  19#include <asm/cpu.h>
  20#include <asm/ioapic.h>
  21#include <asm/sfi.h>
  22#include <asm/tables.h>
  23#include <dm/uclass-internal.h>
  24
  25struct table_info {
  26        u32 base;
  27        int ptr;
  28        u32 entry_start;
  29        u64 table[SFI_TABLE_MAX_ENTRIES];
  30        int count;
  31};
  32
  33static void *get_entry_start(struct table_info *tab)
  34{
  35        if (tab->count == SFI_TABLE_MAX_ENTRIES)
  36                return NULL;
  37        tab->entry_start = tab->base + tab->ptr;
  38        tab->table[tab->count] = tab->entry_start;
  39        tab->entry_start += sizeof(struct sfi_table_header);
  40
  41        return (void *)(uintptr_t)tab->entry_start;
  42}
  43
  44static void finish_table(struct table_info *tab, const char *sig, void *entry)
  45{
  46        struct sfi_table_header *hdr;
  47
  48        hdr = (struct sfi_table_header *)(uintptr_t)(tab->base + tab->ptr);
  49        strcpy(hdr->sig, sig);
  50        hdr->len = sizeof(*hdr) + ((ulong)entry - tab->entry_start);
  51        hdr->rev = 1;
  52        strncpy(hdr->oem_id, "U-Boot", SFI_OEM_ID_SIZE);
  53        strncpy(hdr->oem_table_id, "Table v1", SFI_OEM_TABLE_ID_SIZE);
  54        hdr->csum = 0;
  55        hdr->csum = table_compute_checksum(hdr, hdr->len);
  56        tab->ptr += hdr->len;
  57        tab->ptr = ALIGN(tab->ptr, 16);
  58        tab->count++;
  59}
  60
  61static int sfi_write_system_header(struct table_info *tab)
  62{
  63        u64 *entry = get_entry_start(tab);
  64        int i;
  65
  66        if (!entry)
  67                return -ENOSPC;
  68
  69        for (i = 0; i < tab->count; i++)
  70                *entry++ = tab->table[i];
  71        finish_table(tab, SFI_SIG_SYST, entry);
  72
  73        return 0;
  74}
  75
  76static int sfi_write_cpus(struct table_info *tab)
  77{
  78        struct sfi_cpu_table_entry *entry = get_entry_start(tab);
  79        struct udevice *dev;
  80        int count = 0;
  81
  82        if (!entry)
  83                return -ENOSPC;
  84
  85        for (uclass_find_first_device(UCLASS_CPU, &dev);
  86             dev;
  87             uclass_find_next_device(&dev)) {
  88                struct cpu_platdata *plat = dev_get_parent_platdata(dev);
  89
  90                if (!device_active(dev))
  91                        continue;
  92                entry->apic_id = plat->cpu_id;
  93                entry++;
  94                count++;
  95        }
  96
  97        /* Omit the table if there is only one CPU */
  98        if (count > 1)
  99                finish_table(tab, SFI_SIG_CPUS, entry);
 100
 101        return 0;
 102}
 103
 104static int sfi_write_apic(struct table_info *tab)
 105{
 106        struct sfi_apic_table_entry *entry = get_entry_start(tab);
 107
 108        if (!entry)
 109                return -ENOSPC;
 110
 111        entry->phys_addr = IO_APIC_ADDR;
 112        entry++;
 113        finish_table(tab, SFI_SIG_APIC, entry);
 114
 115        return 0;
 116}
 117
 118static int sfi_write_xsdt(struct table_info *tab)
 119{
 120        struct sfi_xsdt_header *entry = get_entry_start(tab);
 121
 122        if (!entry)
 123                return -ENOSPC;
 124
 125        entry->oem_revision = 1;
 126        entry->creator_id = 1;
 127        entry->creator_revision = 1;
 128        entry++;
 129        finish_table(tab, SFI_SIG_XSDT, entry);
 130
 131        return 0;
 132}
 133
 134ulong write_sfi_table(ulong base)
 135{
 136        struct table_info table;
 137
 138        table.base = base;
 139        table.ptr = 0;
 140        table.count = 0;
 141        sfi_write_cpus(&table);
 142        sfi_write_apic(&table);
 143
 144        /*
 145         * The SFI specification marks the XSDT table as option, but Linux 4.0
 146         * crashes on start-up when it is not provided.
 147         */
 148        sfi_write_xsdt(&table);
 149
 150        /* Finally, write out the system header which points to the others */
 151        sfi_write_system_header(&table);
 152
 153        return base + table.ptr;
 154}
 155