coreboot.c
1 /* 2 * 3 * Copyright (C) 2008 Advanced Micro Devices, Inc. 4 * Copyright (C) 2009 coresystems GmbH 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <libpayload-config.h> 31 #include <libpayload.h> 32 #include <commonlib/bsd/cbmem_id.h> 33 #include <coreboot_tables.h> 34 #include <stdint.h> 35 36 /* 37 * The code in this file applies to all coreboot architectures. Some coreboot 38 * table tags are architecture specific, they are handled by their respective 39 * cb_parse_arch_specific() functions. 40 */ 41 42 /* === Parsing code === */ 43 /* This is the generic parsing code. */ 44 45 static void cb_parse_memory(void *ptr, struct sysinfo_t *info) 46 { 47 struct cb_memory *mem = ptr; 48 int count = MEM_RANGE_COUNT(mem); 49 int i; 50 51 if (count > SYSINFO_MAX_MEM_RANGES) 52 count = SYSINFO_MAX_MEM_RANGES; 53 54 info->n_memranges = 0; 55 56 for (i = 0; i < count; i++) { 57 struct cb_memory_range *range = MEM_RANGE_PTR(mem, i); 58 59 #if CONFIG(LP_MEMMAP_RAM_ONLY) 60 if (range->type != CB_MEM_RAM) 61 continue; 62 #endif 63 64 info->memrange[info->n_memranges].base = range->start; 65 info->memrange[info->n_memranges].size = range->size; 66 info->memrange[info->n_memranges].type = range->type; 67 68 info->n_memranges++; 69 } 70 } 71 72 static void cb_parse_serial(void *ptr, struct sysinfo_t *info) 73 { 74 info->cb_serial = virt_to_phys(ptr); 75 } 76 77 static void cb_parse_vbnv(unsigned char *ptr, struct sysinfo_t *info) 78 { 79 struct lb_range *vbnv = (struct lb_range *)ptr; 80 81 info->vbnv_start = vbnv->range_start; 82 info->vbnv_size = vbnv->range_size; 83 } 84 85 static void cb_parse_mmc_info(unsigned char *ptr, struct sysinfo_t *info) 86 { 87 struct cb_mmc_info *mmc_info = (struct cb_mmc_info *)ptr; 88 89 info->mmc_early_wake_status = mmc_info->early_cmd1_status; 90 } 91 92 static void cb_parse_gpios(unsigned char *ptr, struct sysinfo_t *info) 93 { 94 int i; 95 struct cb_gpios *gpios = (struct cb_gpios *)ptr; 96 97 info->num_gpios = (gpios->count < SYSINFO_MAX_GPIOS) ? 98 (gpios->count) : SYSINFO_MAX_GPIOS; 99 100 for (i = 0; i < info->num_gpios; i++) 101 info->gpios[i] = gpios->gpios[i]; 102 } 103 104 static void cb_parse_mac_addresses(unsigned char *ptr, 105 struct sysinfo_t *info) 106 { 107 struct cb_macs *macs = (struct cb_macs *)ptr; 108 int i; 109 110 info->num_macs = (macs->count < ARRAY_SIZE(info->macs)) ? 111 macs->count : ARRAY_SIZE(info->macs); 112 113 for (i = 0; i < info->num_macs; i++) 114 info->macs[i] = macs->mac_addrs[i]; 115 } 116 117 static void cb_parse_board_config(unsigned char *ptr, struct sysinfo_t *info) 118 { 119 struct cb_board_config *const config = (struct cb_board_config *)ptr; 120 info->fw_config = config->fw_config; 121 info->board_id = config->board_id; 122 info->ram_code = config->ram_code; 123 info->sku_id = config->sku_id; 124 } 125 126 #if CONFIG(LP_NVRAM) 127 static void cb_parse_optiontable(void *ptr, struct sysinfo_t *info) 128 { 129 /* ptr is already virtual, but we want to keep physical addresses */ 130 info->cmos_option_table = virt_to_phys(ptr); 131 } 132 133 static void cb_parse_checksum(void *ptr, struct sysinfo_t *info) 134 { 135 struct cb_cmos_checksum *cmos_cksum = ptr; 136 info->cmos_range_start = cmos_cksum->range_start; 137 info->cmos_range_end = cmos_cksum->range_end; 138 info->cmos_checksum_location = cmos_cksum->location; 139 } 140 #endif 141 142 #if CONFIG(LP_COREBOOT_VIDEO_CONSOLE) 143 static void cb_parse_framebuffer(void *ptr, struct sysinfo_t *info) 144 { 145 info->framebuffer = *(struct cb_framebuffer *)ptr; 146 } 147 #endif 148 149 static void cb_parse_string(const void *const ptr, uintptr_t *const info) 150 { 151 /* ptr is already virtual (str->string just an offset to that), 152 but we want to keep physical addresses */ 153 const struct cb_string *const str = ptr; 154 *info = virt_to_phys(str->string); 155 } 156 157 static void cb_parse_ramoops(void *ptr, struct sysinfo_t *info) 158 { 159 struct lb_range *ramoops = (struct lb_range *)ptr; 160 161 info->ramoops_buffer = ramoops->range_start; 162 info->ramoops_buffer_size = ramoops->range_size; 163 } 164 165 static void cb_parse_mtc(void *ptr, struct sysinfo_t *info) 166 { 167 struct lb_range *mtc = (struct lb_range *)ptr; 168 169 info->mtc_start = mtc->range_start; 170 info->mtc_size = mtc->range_size; 171 } 172 173 static void cb_parse_spi_flash(void *ptr, struct sysinfo_t *info) 174 { 175 struct cb_spi_flash *flash = (struct cb_spi_flash *)ptr; 176 177 info->spi_flash.size = flash->flash_size; 178 info->spi_flash.sector_size = flash->sector_size; 179 info->spi_flash.erase_cmd = flash->erase_cmd; 180 181 if (flash->mmap_count == 0) 182 return; 183 184 info->spi_flash.mmap_window_count = MIN(flash->mmap_count, SYSINFO_MAX_MMAP_WINDOWS); 185 memcpy(info->spi_flash.mmap_table, flash->mmap_table, 186 info->spi_flash.mmap_window_count * sizeof(struct flash_mmap_window)); 187 } 188 189 static void cb_parse_boot_media_params(unsigned char *ptr, 190 struct sysinfo_t *info) 191 { 192 struct cb_boot_media_params *const bmp = 193 (struct cb_boot_media_params *)ptr; 194 info->fmap_offset = bmp->fmap_offset; 195 info->cbfs_offset = bmp->cbfs_offset; 196 info->cbfs_size = bmp->cbfs_size; 197 info->boot_media_size = bmp->boot_media_size; 198 } 199 200 #if CONFIG(LP_TIMER_RDTSC) 201 static void cb_parse_tsc_info(void *ptr, struct sysinfo_t *info) 202 { 203 const struct cb_tsc_info *tsc_info = ptr; 204 205 if (tsc_info->freq_khz == 0) 206 return; 207 208 /* Honor the TSC frequency passed to the payload. */ 209 info->cpu_khz = tsc_info->freq_khz; 210 } 211 #endif 212 213 static void cb_parse_cbmem_entry(void *ptr, struct sysinfo_t *info) 214 { 215 const struct cb_cbmem_entry *cbmem_entry = ptr; 216 217 if (cbmem_entry->size != sizeof(*cbmem_entry)) 218 return; 219 220 switch (cbmem_entry->id) { 221 case CBMEM_ID_ACPI_CNVS: 222 info->acpi_cnvs = cbmem_entry->address; 223 break; 224 case CBMEM_ID_ACPI_GNVS: 225 info->acpi_gnvs = cbmem_entry->address; 226 break; 227 case CBMEM_ID_SMBIOS: 228 info->smbios = cbmem_entry->address; 229 break; 230 case CBMEM_ID_CBFS_RO_MCACHE: 231 info->cbfs_ro_mcache_offset = cbmem_entry->address; 232 info->cbfs_ro_mcache_size = cbmem_entry->entry_size; 233 break; 234 case CBMEM_ID_CBFS_RW_MCACHE: 235 info->cbfs_rw_mcache_offset = cbmem_entry->address; 236 info->cbfs_rw_mcache_size = cbmem_entry->entry_size; 237 break; 238 case CBMEM_ID_CONSOLE: 239 info->cbmem_cons = cbmem_entry->address; 240 break; 241 case CBMEM_ID_MRCDATA: 242 info->mrc_cache = cbmem_entry->address; 243 break; 244 case CBMEM_ID_VBOOT_WORKBUF: 245 info->vboot_workbuf = cbmem_entry->address; 246 break; 247 case CBMEM_ID_TIMESTAMP: 248 info->tstamp_table = cbmem_entry->address; 249 break; 250 case CBMEM_ID_VPD: 251 info->chromeos_vpd = cbmem_entry->address; 252 break; 253 case CBMEM_ID_FMAP: 254 info->fmap_cache = cbmem_entry->address; 255 break; 256 case CBMEM_ID_WIFI_CALIBRATION: 257 info->wifi_calibration = cbmem_entry->address; 258 break; 259 case CBMEM_ID_TYPE_C_INFO: 260 info->type_c_info = cbmem_entry->address; 261 break; 262 case CBMEM_ID_MEM_CHIP_INFO: 263 info->mem_chip_base = cbmem_entry->address; 264 break; 265 case CBMEM_ID_CSE_BP_INFO: 266 info->cse_bp_info = cbmem_entry->address; 267 break; 268 case CBMEM_ID_CSE_INFO: 269 info->cse_info = cbmem_entry->address; 270 break; 271 default: 272 break; 273 } 274 } 275 276 static void cb_parse_pcie(void *ptr, struct sysinfo_t *info) 277 { 278 const struct cb_pcie *pcie = ptr; 279 280 info->pcie_ctrl_base = pcie->ctrl_base; 281 } 282 283 static void cb_parse_rsdp(void *ptr, struct sysinfo_t *info) 284 { 285 const struct cb_acpi_rsdp *cb_acpi_rsdp = ptr; 286 info->acpi_rsdp = cb_acpi_rsdp->rsdp_pointer; 287 } 288 289 int cb_parse_header(void *addr, int len, struct sysinfo_t *info) 290 { 291 struct cb_header *header; 292 unsigned char *ptr = addr; 293 void *forward; 294 int i; 295 296 for (i = 0; i < len; i += 16, ptr += 16) { 297 header = (struct cb_header *)ptr; 298 if (!strncmp((const char *)header->signature, "LBIO", 4)) 299 break; 300 } 301 302 /* We walked the entire space and didn't find anything. */ 303 if (i >= len) 304 return -1; 305 306 /* Make sure the checksums match. */ 307 if (ipchksum((u16 *) header, sizeof(*header)) != 0) 308 return -1; 309 310 if (!header->table_bytes) 311 return 0; 312 313 if (ipchksum((u16 *) (ptr + sizeof(*header)), 314 header->table_bytes) != header->table_checksum) 315 return -1; 316 317 info->cb_header = virt_to_phys(header); 318 319 /* Initialize IDs as undefined in case they don't show up in table. */ 320 info->board_id = UNDEFINED_STRAPPING_ID; 321 info->ram_code = UNDEFINED_STRAPPING_ID; 322 info->sku_id = UNDEFINED_STRAPPING_ID; 323 info->fw_config = UNDEFINED_FW_CONFIG; 324 325 /* Now, walk the tables. */ 326 ptr += header->header_bytes; 327 328 for (i = 0; i < header->table_entries; i++) { 329 struct cb_record *rec = (struct cb_record *)ptr; 330 331 /* We only care about a few tags here (maybe more later). */ 332 switch (rec->tag) { 333 case CB_TAG_FORWARD: 334 forward = phys_to_virt((void *)(unsigned long) 335 ((struct cb_forward *)rec)->forward); 336 return cb_parse_header(forward, len, info); 337 case CB_TAG_MEMORY: 338 cb_parse_memory(ptr, info); 339 break; 340 case CB_TAG_SERIAL: 341 cb_parse_serial(ptr, info); 342 break; 343 case CB_TAG_VERSION: 344 cb_parse_string(ptr, &info->cb_version); 345 break; 346 case CB_TAG_EXTRA_VERSION: 347 cb_parse_string(ptr, &info->extra_version); 348 break; 349 case CB_TAG_BUILD: 350 cb_parse_string(ptr, &info->build); 351 break; 352 case CB_TAG_COMPILE_TIME: 353 cb_parse_string(ptr, &info->compile_time); 354 break; 355 case CB_TAG_COMPILE_BY: 356 cb_parse_string(ptr, &info->compile_by); 357 break; 358 case CB_TAG_COMPILE_HOST: 359 cb_parse_string(ptr, &info->compile_host); 360 break; 361 case CB_TAG_COMPILE_DOMAIN: 362 cb_parse_string(ptr, &info->compile_domain); 363 break; 364 case CB_TAG_COMPILER: 365 cb_parse_string(ptr, &info->compiler); 366 break; 367 case CB_TAG_LINKER: 368 cb_parse_string(ptr, &info->linker); 369 break; 370 case CB_TAG_ASSEMBLER: 371 cb_parse_string(ptr, &info->assembler); 372 break; 373 #if CONFIG(LP_NVRAM) 374 case CB_TAG_CMOS_OPTION_TABLE: 375 cb_parse_optiontable(ptr, info); 376 break; 377 case CB_TAG_OPTION_CHECKSUM: 378 cb_parse_checksum(ptr, info); 379 break; 380 #endif 381 #if CONFIG(LP_COREBOOT_VIDEO_CONSOLE) 382 // FIXME we should warn on serial if coreboot set up a 383 // framebuffer buf the payload does not know about it. 384 case CB_TAG_FRAMEBUFFER: 385 cb_parse_framebuffer(ptr, info); 386 break; 387 #endif 388 case CB_TAG_MAINBOARD: 389 info->cb_mainboard = virt_to_phys(ptr); 390 break; 391 case CB_TAG_GPIO: 392 cb_parse_gpios(ptr, info); 393 break; 394 case CB_TAG_VBNV: 395 cb_parse_vbnv(ptr, info); 396 break; 397 case CB_TAG_MAC_ADDRS: 398 cb_parse_mac_addresses(ptr, info); 399 break; 400 case CB_TAG_SERIALNO: 401 cb_parse_string(ptr, &info->serialno); 402 break; 403 case CB_TAG_BOARD_CONFIG: 404 cb_parse_board_config(ptr, info); 405 break; 406 case CB_TAG_RAM_OOPS: 407 cb_parse_ramoops(ptr, info); 408 break; 409 case CB_TAG_SPI_FLASH: 410 cb_parse_spi_flash(ptr, info); 411 break; 412 case CB_TAG_MMC_INFO: 413 cb_parse_mmc_info(ptr, info); 414 break; 415 case CB_TAG_MTC: 416 cb_parse_mtc(ptr, info); 417 break; 418 case CB_TAG_BOOT_MEDIA_PARAMS: 419 cb_parse_boot_media_params(ptr, info); 420 break; 421 case CB_TAG_CBMEM_ENTRY: 422 cb_parse_cbmem_entry(ptr, info); 423 break; 424 #if CONFIG(LP_TIMER_RDTSC) 425 case CB_TAG_TSC_INFO: 426 cb_parse_tsc_info(ptr, info); 427 break; 428 #endif 429 case CB_TAG_ACPI_RSDP: 430 cb_parse_rsdp(ptr, info); 431 break; 432 case CB_TAG_PCIE: 433 cb_parse_pcie(ptr, info); 434 break; 435 default: 436 cb_parse_arch_specific(rec, info); 437 break; 438 } 439 440 ptr += rec->size; 441 } 442 443 return 0; 444 }