1 /* 2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <cbmem_console.h> 9 #include <coreboot.h> 10 #include <debug.h> 11 #include <mmio.h> 12 #include <string.h> 13 #include <xlat_tables_v2.h> 14 15 /* 16 * Structures describing coreboot's in-memory descriptor tables. See 17 * <coreboot>/src/commonlib/include/commonlib/coreboot_tables.h for 18 * canonical implementation. 19 */ 20 21 typedef struct { 22 char signature[4]; 23 uint32_t header_bytes; 24 uint32_t header_checksum; 25 uint32_t table_bytes; 26 uint32_t table_checksum; 27 uint32_t table_entries; 28 } cb_header_t; 29 30 typedef enum { 31 CB_TAG_SERIAL = 0xf, 32 CB_TAG_CBMEM_CONSOLE = 0x17, 33 } cb_tag_t; 34 35 typedef struct { 36 uint32_t tag; 37 uint32_t size; 38 union { 39 coreboot_serial_t serial; 40 uint64_t uint64; 41 }; 42 } cb_entry_t; 43 44 coreboot_serial_t coreboot_serial; 45 46 /* 47 * The coreboot table is parsed before the MMU is enabled (i.e. with strongly 48 * ordered memory), so we cannot make unaligned accesses. The table entries 49 * immediately follow one another without padding, so nothing after the header 50 * is guaranteed to be naturally aligned. Therefore, we need to define safety 51 * functions that can read unaligned integers. 52 */ 53 static uint32_t read_le32(uint32_t *p) 54 { 55 uintptr_t addr = (uintptr_t)p; 56 return mmio_read_8(addr) | 57 mmio_read_8(addr + 1) << 8 | 58 mmio_read_8(addr + 2) << 16 | 59 mmio_read_8(addr + 3) << 24; 60 } 61 static uint64_t read_le64(uint64_t *p) 62 { 63 return read_le32((void *)p) | (uint64_t)read_le32((void *)p + 4) << 32; 64 } 65 66 static void expand_and_mmap(uintptr_t baseaddr, size_t size) 67 { 68 uintptr_t pageaddr = round_down(baseaddr, PAGE_SIZE); 69 size_t expanded = round_up(baseaddr - pageaddr + size, PAGE_SIZE); 70 mmap_add_region(pageaddr, pageaddr, expanded, 71 MT_MEMORY | MT_RW | MT_NS | MT_EXECUTE_NEVER); 72 } 73 74 static void setup_cbmem_console(uintptr_t baseaddr) 75 { 76 static console_cbmc_t console; 77 assert(!console.base); /* should only have one CBMEM console */ 78 79 /* CBMEM console structure stores its size in first header field. */ 80 uint32_t size = *(uint32_t *)baseaddr; 81 expand_and_mmap(baseaddr, size); 82 console_cbmc_register(baseaddr, &console); 83 console_set_scope(&console.console, CONSOLE_FLAG_BOOT | 84 CONSOLE_FLAG_RUNTIME | 85 CONSOLE_FLAG_CRASH); 86 } 87 88 void coreboot_table_setup(void *base) 89 { 90 cb_header_t *header = base; 91 void *ptr; 92 int i; 93 94 if (strncmp(header->signature, "LBIO", 4)) { 95 ERROR("coreboot table signature corrupt!\n"); 96 return; 97 } 98 99 ptr = base + header->header_bytes; 100 for (i = 0; i < header->table_entries; i++) { 101 cb_entry_t *entry = ptr; 102 103 if (ptr - base >= header->header_bytes + header->table_bytes) { 104 ERROR("coreboot table exceeds its bounds!\n"); 105 break; 106 } 107 108 switch (read_le32(&entry->tag)) { 109 case CB_TAG_SERIAL: 110 memcpy(&coreboot_serial, &entry->serial, 111 sizeof(coreboot_serial)); 112 break; 113 case CB_TAG_CBMEM_CONSOLE: 114 setup_cbmem_console(read_le64(&entry->uint64)); 115 break; 116 default: 117 /* There are many tags TF doesn't need to care about. */ 118 break; 119 } 120 121 ptr += read_le32(&entry->size); 122 } 123 } 124