uboot/arch/x86/lib/coreboot/cb_sysinfo.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause
   2/*
   3 * This file is part of the libpayload project.
   4 *
   5 * Copyright (C) 2008 Advanced Micro Devices, Inc.
   6 * Copyright (C) 2009 coresystems GmbH
   7 */
   8
   9#include <common.h>
  10#include <asm/cb_sysinfo.h>
  11#include <init.h>
  12#include <mapmem.h>
  13#include <net.h>
  14#include <asm/global_data.h>
  15
  16DECLARE_GLOBAL_DATA_PTR;
  17
  18/*
  19 * This needs to be in the .data section so that it's copied over during
  20 * relocation. By default it's put in the .bss section which is simply filled
  21 * with zeroes when transitioning from "ROM", which is really RAM, to other
  22 * RAM.
  23 */
  24struct sysinfo_t lib_sysinfo __section(".data");
  25
  26/*
  27 * Some of this is x86 specific, and the rest of it is generic. Right now,
  28 * since we only support x86, we'll avoid trying to make lots of infrastructure
  29 * we don't need. If in the future, we want to use coreboot on some other
  30 * architecture, then take out the generic parsing code and move it elsewhere.
  31 */
  32
  33/* === Parsing code === */
  34/* This is the generic parsing code */
  35
  36static void cb_parse_memory(unsigned char *ptr, struct sysinfo_t *info)
  37{
  38        struct cb_memory *mem = (struct cb_memory *)ptr;
  39        int count = MEM_RANGE_COUNT(mem);
  40        int i;
  41
  42        if (count > SYSINFO_MAX_MEM_RANGES)
  43                count = SYSINFO_MAX_MEM_RANGES;
  44
  45        info->n_memranges = 0;
  46
  47        for (i = 0; i < count; i++) {
  48                struct cb_memory_range *range =
  49                    (struct cb_memory_range *)MEM_RANGE_PTR(mem, i);
  50
  51                info->memrange[info->n_memranges].base =
  52                    UNPACK_CB64(range->start);
  53
  54                info->memrange[info->n_memranges].size =
  55                    UNPACK_CB64(range->size);
  56
  57                info->memrange[info->n_memranges].type = range->type;
  58
  59                info->n_memranges++;
  60        }
  61}
  62
  63static void cb_parse_serial(unsigned char *ptr, struct sysinfo_t *info)
  64{
  65        struct cb_serial *ser = (struct cb_serial *)ptr;
  66
  67        info->serial = ser;
  68}
  69
  70static void cb_parse_vboot_handoff(unsigned char *ptr, struct sysinfo_t *info)
  71{
  72        struct lb_range *vbho = (struct lb_range *)ptr;
  73
  74        info->vboot_handoff = (void *)(uintptr_t)vbho->range_start;
  75        info->vboot_handoff_size = vbho->range_size;
  76}
  77
  78static void cb_parse_vbnv(unsigned char *ptr, struct sysinfo_t *info)
  79{
  80        struct lb_range *vbnv = (struct lb_range *)ptr;
  81
  82        info->vbnv_start = vbnv->range_start;
  83        info->vbnv_size = vbnv->range_size;
  84}
  85
  86static void cb_parse_cbmem_entry(unsigned char *ptr, struct sysinfo_t *info)
  87{
  88        struct cb_cbmem_entry *entry = (struct cb_cbmem_entry *)ptr;
  89
  90        if (entry->id != CBMEM_ID_SMBIOS)
  91                return;
  92
  93        info->smbios_start = entry->address;
  94        info->smbios_size = entry->entry_size;
  95}
  96
  97static void cb_parse_gpios(unsigned char *ptr, struct sysinfo_t *info)
  98{
  99        int i;
 100        struct cb_gpios *gpios = (struct cb_gpios *)ptr;
 101
 102        info->num_gpios = (gpios->count < SYSINFO_MAX_GPIOS) ?
 103                                (gpios->count) : SYSINFO_MAX_GPIOS;
 104
 105        for (i = 0; i < info->num_gpios; i++)
 106                info->gpios[i] = gpios->gpios[i];
 107}
 108
 109static void cb_parse_vdat(unsigned char *ptr, struct sysinfo_t *info)
 110{
 111        struct lb_range *vdat = (struct lb_range *)ptr;
 112
 113        info->vdat_addr = map_sysmem(vdat->range_start, vdat->range_size);
 114        info->vdat_size = vdat->range_size;
 115}
 116
 117static void cb_parse_mac_addresses(unsigned char *ptr,
 118                                   struct sysinfo_t *info)
 119{
 120        struct cb_macs *macs = (struct cb_macs *)ptr;
 121        int i;
 122
 123        info->num_macs = (macs->count < ARRAY_SIZE(info->macs)) ?
 124                macs->count : ARRAY_SIZE(info->macs);
 125
 126        for (i = 0; i < info->num_macs; i++)
 127                info->macs[i] = macs->mac_addrs[i];
 128}
 129
 130static void cb_parse_tstamp(void *ptr, struct sysinfo_t *info)
 131{
 132        struct cb_cbmem_tab *const cbmem = ptr;
 133
 134        info->tstamp_table = map_sysmem(cbmem->cbmem_tab, 0);
 135}
 136
 137static void cb_parse_cbmem_cons(void *ptr, struct sysinfo_t *info)
 138{
 139        struct cb_cbmem_tab *const cbmem = ptr;
 140
 141        info->cbmem_cons = map_sysmem(cbmem->cbmem_tab, 0);
 142}
 143
 144static void cb_parse_acpi_gnvs(unsigned char *ptr, struct sysinfo_t *info)
 145{
 146        struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr;
 147
 148        info->acpi_gnvs = map_sysmem(cbmem->cbmem_tab, 0);
 149}
 150
 151static void cb_parse_board_id(unsigned char *ptr, struct sysinfo_t *info)
 152{
 153        struct cb_board_id *const cbbid = (struct cb_board_id *)ptr;
 154
 155        info->board_id = cbbid->board_id;
 156}
 157
 158static void cb_parse_ram_code(unsigned char *ptr, struct sysinfo_t *info)
 159{
 160        struct cb_ram_code *const ram_code = (struct cb_ram_code *)ptr;
 161
 162        info->ram_code = ram_code->ram_code;
 163}
 164
 165static void cb_parse_optiontable(void *ptr, struct sysinfo_t *info)
 166{
 167        /* ptr points to a coreboot table entry and is already virtual */
 168        info->option_table = ptr;
 169}
 170
 171static void cb_parse_checksum(void *ptr, struct sysinfo_t *info)
 172{
 173        struct cb_cmos_checksum *cmos_cksum = ptr;
 174
 175        info->cmos_range_start = cmos_cksum->range_start;
 176        info->cmos_range_end = cmos_cksum->range_end;
 177        info->cmos_checksum_location = cmos_cksum->location;
 178}
 179
 180static void cb_parse_framebuffer(void *ptr, struct sysinfo_t *info)
 181{
 182        /* ptr points to a coreboot table entry and is already virtual */
 183        info->framebuffer = ptr;
 184}
 185
 186static void cb_parse_string(unsigned char *ptr, char **info)
 187{
 188        *info = (char *)((struct cb_string *)ptr)->string;
 189}
 190
 191static void cb_parse_wifi_calibration(void *ptr, struct sysinfo_t *info)
 192{
 193        struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr;
 194
 195        info->wifi_calibration = map_sysmem(cbmem->cbmem_tab, 0);
 196}
 197
 198static void cb_parse_ramoops(void *ptr, struct sysinfo_t *info)
 199{
 200        struct lb_range *ramoops = (struct lb_range *)ptr;
 201
 202        info->ramoops_buffer = ramoops->range_start;
 203        info->ramoops_buffer_size = ramoops->range_size;
 204}
 205
 206static void cb_parse_mtc(void *ptr, struct sysinfo_t *info)
 207{
 208        struct lb_range *mtc = (struct lb_range *)ptr;
 209
 210        info->mtc_start = mtc->range_start;
 211        info->mtc_size = mtc->range_size;
 212}
 213
 214static void cb_parse_spi_flash(void *ptr, struct sysinfo_t *info)
 215{
 216        struct cb_spi_flash *flash = (struct cb_spi_flash *)ptr;
 217
 218        info->spi_flash.size = flash->flash_size;
 219        info->spi_flash.sector_size = flash->sector_size;
 220        info->spi_flash.erase_cmd = flash->erase_cmd;
 221}
 222
 223static void cb_parse_boot_media_params(unsigned char *ptr,
 224                                       struct sysinfo_t *info)
 225{
 226        struct cb_boot_media_params *const bmp =
 227                        (struct cb_boot_media_params *)ptr;
 228
 229        info->fmap_offset = bmp->fmap_offset;
 230        info->cbfs_offset = bmp->cbfs_offset;
 231        info->cbfs_size = bmp->cbfs_size;
 232        info->boot_media_size = bmp->boot_media_size;
 233}
 234
 235static void cb_parse_vpd(void *ptr, struct sysinfo_t *info)
 236{
 237        struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr;
 238
 239        info->chromeos_vpd = map_sysmem(cbmem->cbmem_tab, 0);
 240}
 241
 242static void cb_parse_tsc_info(void *ptr, struct sysinfo_t *info)
 243{
 244        const struct cb_tsc_info *tsc_info = ptr;
 245
 246        if (tsc_info->freq_khz == 0)
 247                return;
 248
 249        /* Honor the TSC frequency passed to the payload */
 250        info->cpu_khz = tsc_info->freq_khz;
 251}
 252
 253static void cb_parse_x86_rom_var_mtrr(void *ptr, struct sysinfo_t *info)
 254{
 255        struct cb_x86_rom_mtrr *rom_mtrr = ptr;
 256
 257        info->x86_rom_var_mtrr_index = rom_mtrr->index;
 258}
 259
 260static void cb_parse_mrc_cache(void *ptr, struct sysinfo_t *info)
 261{
 262        struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr;
 263
 264        info->mrc_cache = map_sysmem(cbmem->cbmem_tab, 0);
 265}
 266
 267__weak void cb_parse_unhandled(u32 tag, unsigned char *ptr)
 268{
 269}
 270
 271static int cb_parse_header(void *addr, int len, struct sysinfo_t *info)
 272{
 273        unsigned char *ptr = addr;
 274        struct cb_header *header;
 275        int i;
 276
 277        header = (struct cb_header *)ptr;
 278        if (!header->table_bytes)
 279                return 0;
 280
 281        /* Make sure the checksums match */
 282        if (!ip_checksum_ok(header, sizeof(*header)))
 283                return -1;
 284
 285        if (compute_ip_checksum(ptr + sizeof(*header), header->table_bytes) !=
 286            header->table_checksum)
 287                return -1;
 288
 289        info->header = header;
 290
 291        /*
 292         * Board straps represented by numerical values are small numbers.
 293         * Preset them to an invalid value in case the firmware does not
 294         * supply the info.
 295         */
 296        info->board_id = ~0;
 297        info->ram_code = ~0;
 298
 299        /* Now, walk the tables */
 300        ptr += header->header_bytes;
 301
 302        /* Inintialize some fields to sentinel values */
 303        info->vbnv_start = info->vbnv_size = (uint32_t)(-1);
 304
 305        for (i = 0; i < header->table_entries; i++) {
 306                struct cb_record *rec = (struct cb_record *)ptr;
 307
 308                /* We only care about a few tags here (maybe more later) */
 309                switch (rec->tag) {
 310                case CB_TAG_FORWARD:
 311                        return cb_parse_header(
 312                                (void *)(unsigned long)
 313                                ((struct cb_forward *)rec)->forward,
 314                                len, info);
 315                        continue;
 316                case CB_TAG_MEMORY:
 317                        cb_parse_memory(ptr, info);
 318                        break;
 319                case CB_TAG_SERIAL:
 320                        cb_parse_serial(ptr, info);
 321                        break;
 322                case CB_TAG_VERSION:
 323                        cb_parse_string(ptr, &info->cb_version);
 324                        break;
 325                case CB_TAG_EXTRA_VERSION:
 326                        cb_parse_string(ptr, &info->extra_version);
 327                        break;
 328                case CB_TAG_BUILD:
 329                        cb_parse_string(ptr, &info->build);
 330                        break;
 331                case CB_TAG_COMPILE_TIME:
 332                        cb_parse_string(ptr, &info->compile_time);
 333                        break;
 334                case CB_TAG_COMPILE_BY:
 335                        cb_parse_string(ptr, &info->compile_by);
 336                        break;
 337                case CB_TAG_COMPILE_HOST:
 338                        cb_parse_string(ptr, &info->compile_host);
 339                        break;
 340                case CB_TAG_COMPILE_DOMAIN:
 341                        cb_parse_string(ptr, &info->compile_domain);
 342                        break;
 343                case CB_TAG_COMPILER:
 344                        cb_parse_string(ptr, &info->compiler);
 345                        break;
 346                case CB_TAG_LINKER:
 347                        cb_parse_string(ptr, &info->linker);
 348                        break;
 349                case CB_TAG_ASSEMBLER:
 350                        cb_parse_string(ptr, &info->assembler);
 351                        break;
 352                case CB_TAG_CMOS_OPTION_TABLE:
 353                        cb_parse_optiontable(ptr, info);
 354                        break;
 355                case CB_TAG_OPTION_CHECKSUM:
 356                        cb_parse_checksum(ptr, info);
 357                        break;
 358                /*
 359                 * FIXME we should warn on serial if coreboot set up a
 360                 * framebuffer buf the payload does not know about it.
 361                 */
 362                case CB_TAG_FRAMEBUFFER:
 363                        cb_parse_framebuffer(ptr, info);
 364                        break;
 365                case CB_TAG_MAINBOARD:
 366                        info->mainboard = (struct cb_mainboard *)ptr;
 367                        break;
 368                case CB_TAG_GPIO:
 369                        cb_parse_gpios(ptr, info);
 370                        break;
 371                case CB_TAG_VDAT:
 372                        cb_parse_vdat(ptr, info);
 373                        break;
 374                case CB_TAG_VBNV:
 375                        cb_parse_vbnv(ptr, info);
 376                        break;
 377                case CB_TAG_VBOOT_HANDOFF:
 378                        cb_parse_vboot_handoff(ptr, info);
 379                        break;
 380                case CB_TAG_MAC_ADDRS:
 381                        cb_parse_mac_addresses(ptr, info);
 382                        break;
 383                case CB_TAG_SERIALNO:
 384                        cb_parse_string(ptr, &info->serialno);
 385                        break;
 386                case CB_TAG_TIMESTAMPS:
 387                        cb_parse_tstamp(ptr, info);
 388                        break;
 389                case CB_TAG_CBMEM_CONSOLE:
 390                        cb_parse_cbmem_cons(ptr, info);
 391                        break;
 392                case CB_TAG_ACPI_GNVS:
 393                        cb_parse_acpi_gnvs(ptr, info);
 394                        break;
 395                case CB_TAG_CBMEM_ENTRY:
 396                        cb_parse_cbmem_entry(ptr, info);
 397                        break;
 398                case CB_TAG_BOARD_ID:
 399                        cb_parse_board_id(ptr, info);
 400                        break;
 401                case CB_TAG_RAM_CODE:
 402                        cb_parse_ram_code(ptr, info);
 403                        break;
 404                case CB_TAG_WIFI_CALIBRATION:
 405                        cb_parse_wifi_calibration(ptr, info);
 406                        break;
 407                case CB_TAG_RAM_OOPS:
 408                        cb_parse_ramoops(ptr, info);
 409                        break;
 410                case CB_TAG_SPI_FLASH:
 411                        cb_parse_spi_flash(ptr, info);
 412                        break;
 413                case CB_TAG_MTC:
 414                        cb_parse_mtc(ptr, info);
 415                        break;
 416                case CB_TAG_BOOT_MEDIA_PARAMS:
 417                        cb_parse_boot_media_params(ptr, info);
 418                        break;
 419                case CB_TAG_TSC_INFO:
 420                        cb_parse_tsc_info(ptr, info);
 421                        break;
 422                case CB_TAG_VPD:
 423                        cb_parse_vpd(ptr, info);
 424                        break;
 425                case CB_TAG_X86_ROM_MTRR:
 426                        cb_parse_x86_rom_var_mtrr(rec, info);
 427                        break;
 428                case CB_TAG_MRC_CACHE:
 429                        cb_parse_mrc_cache(rec, info);
 430                        break;
 431                default:
 432                        cb_parse_unhandled(rec->tag, ptr);
 433                        break;
 434                }
 435
 436                ptr += rec->size;
 437        }
 438
 439        return 1;
 440}
 441
 442/* == Architecture specific == */
 443/* This is the x86 specific stuff */
 444
 445int get_coreboot_info(struct sysinfo_t *info)
 446{
 447        long addr;
 448        int ret;
 449
 450        addr = locate_coreboot_table();
 451        if (addr < 0)
 452                return addr;
 453        ret = cb_parse_header((void *)addr, 0x1000, info);
 454        if (!ret)
 455                return -ENOENT;
 456        gd->arch.coreboot_table = addr;
 457        gd->flags |= GD_FLG_SKIP_LL_INIT;
 458
 459        return 0;
 460}
 461
 462const struct sysinfo_t *cb_get_sysinfo(void)
 463{
 464        if (!ll_boot_init())
 465                return &lib_sysinfo;
 466
 467        return NULL;
 468}
 469