1 /* 2 * This file is part of the libpayload project. 3 * 4 * Copyright (C) 2008 Advanced Micro Devices, Inc. 5 * Copyright (C) 2009 coresystems GmbH 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <asm/arch-coreboot/ipchecksum.h> 32 #include <asm/arch-coreboot/sysinfo.h> 33 #include <asm/arch-coreboot/tables.h> 34 35 /* 36 * This needs to be in the .data section so that it's copied over during 37 * relocation. By default it's put in the .bss section which is simply filled 38 * with zeroes when transitioning from "ROM", which is really RAM, to other 39 * RAM. 40 */ 41 struct sysinfo_t lib_sysinfo __attribute__((section(".data"))); 42 43 /* 44 * Some of this is x86 specific, and the rest of it is generic. Right now, 45 * since we only support x86, we'll avoid trying to make lots of infrastructure 46 * we don't need. If in the future, we want to use coreboot on some other 47 * architecture, then take out the generic parsing code and move it elsewhere. 48 */ 49 50 /* === Parsing code === */ 51 /* This is the generic parsing code. */ 52 53 static void cb_parse_memory(unsigned char *ptr, struct sysinfo_t *info) 54 { 55 struct cb_memory *mem = (struct cb_memory *)ptr; 56 int count = MEM_RANGE_COUNT(mem); 57 int i; 58 59 if (count > SYSINFO_MAX_MEM_RANGES) 60 count = SYSINFO_MAX_MEM_RANGES; 61 62 info->n_memranges = 0; 63 64 for (i = 0; i < count; i++) { 65 struct cb_memory_range *range = 66 (struct cb_memory_range *)MEM_RANGE_PTR(mem, i); 67 68 info->memrange[info->n_memranges].base = 69 UNPACK_CB64(range->start); 70 71 info->memrange[info->n_memranges].size = 72 UNPACK_CB64(range->size); 73 74 info->memrange[info->n_memranges].type = range->type; 75 76 info->n_memranges++; 77 } 78 } 79 80 static void cb_parse_serial(unsigned char *ptr, struct sysinfo_t *info) 81 { 82 struct cb_serial *ser = (struct cb_serial *)ptr; 83 if (ser->type != CB_SERIAL_TYPE_IO_MAPPED) 84 return; 85 info->ser_ioport = ser->baseaddr; 86 } 87 88 static void cb_parse_optiontable(unsigned char *ptr, struct sysinfo_t *info) 89 { 90 info->option_table = (struct cb_cmos_option_table *)ptr; 91 } 92 93 static void cb_parse_checksum(unsigned char *ptr, struct sysinfo_t *info) 94 { 95 struct cb_cmos_checksum *cmos_cksum = (struct cb_cmos_checksum *)ptr; 96 info->cmos_range_start = cmos_cksum->range_start; 97 info->cmos_range_end = cmos_cksum->range_end; 98 info->cmos_checksum_location = cmos_cksum->location; 99 } 100 101 static void cb_parse_framebuffer(unsigned char *ptr, struct sysinfo_t *info) 102 { 103 info->framebuffer = (struct cb_framebuffer *)ptr; 104 } 105 106 static int cb_parse_header(void *addr, int len, struct sysinfo_t *info) 107 { 108 struct cb_header *header; 109 unsigned char *ptr = (unsigned char *)addr; 110 int i; 111 112 for (i = 0; i < len; i += 16, ptr += 16) { 113 header = (struct cb_header *)ptr; 114 if (!strncmp((const char *)header->signature, "LBIO", 4)) 115 break; 116 } 117 118 /* We walked the entire space and didn't find anything. */ 119 if (i >= len) 120 return -1; 121 122 if (!header->table_bytes) 123 return 0; 124 125 /* Make sure the checksums match. */ 126 if (ipchksum((u16 *) header, sizeof(*header)) != 0) 127 return -1; 128 129 if (ipchksum((u16 *) (ptr + sizeof(*header)), 130 header->table_bytes) != header->table_checksum) 131 return -1; 132 133 /* Now, walk the tables. */ 134 ptr += header->header_bytes; 135 136 for (i = 0; i < header->table_entries; i++) { 137 struct cb_record *rec = (struct cb_record *)ptr; 138 139 /* We only care about a few tags here (maybe more later). */ 140 switch (rec->tag) { 141 case CB_TAG_FORWARD: 142 return cb_parse_header( 143 (void *)(unsigned long) 144 ((struct cb_forward *)rec)->forward, 145 len, info); 146 continue; 147 case CB_TAG_MEMORY: 148 cb_parse_memory(ptr, info); 149 break; 150 case CB_TAG_SERIAL: 151 cb_parse_serial(ptr, info); 152 break; 153 case CB_TAG_CMOS_OPTION_TABLE: 154 cb_parse_optiontable(ptr, info); 155 break; 156 case CB_TAG_OPTION_CHECKSUM: 157 cb_parse_checksum(ptr, info); 158 break; 159 /* 160 * FIXME we should warn on serial if coreboot set up a 161 * framebuffer buf the payload does not know about it. 162 */ 163 case CB_TAG_FRAMEBUFFER: 164 cb_parse_framebuffer(ptr, info); 165 break; 166 } 167 168 ptr += rec->size; 169 } 170 171 return 1; 172 } 173 174 /* == Architecture specific == */ 175 /* This is the x86 specific stuff. */ 176 177 /* Assume no translation or that memory is identity mapped. */ 178 static void *phys_to_virt(unsigned long virt) 179 { 180 return (void *)(uintptr_t)virt; 181 } 182 183 int get_coreboot_info(struct sysinfo_t *info) 184 { 185 int ret = cb_parse_header(phys_to_virt(0x00000000), 0x1000, info); 186 187 if (ret != 1) 188 ret = cb_parse_header(phys_to_virt(0x000f0000), 0x1000, info); 189 190 return (ret == 1) ? 0 : -1; 191 } 192