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 * Some of this is x86 specific, and the rest of it is generic. Right now, 37 * since we only support x86, we'll avoid trying to make lots of infrastructure 38 * we don't need. If in the future, we want to use coreboot on some other 39 * architecture, then take out the generic parsing code and move it elsewhere. 40 */ 41 42 /* === Parsing code === */ 43 /* This is the generic parsing code. */ 44 45 static void cb_parse_memory(unsigned char *ptr, struct sysinfo_t *info) 46 { 47 struct cb_memory *mem = (struct cb_memory *)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 = 58 (struct cb_memory_range *)MEM_RANGE_PTR(mem, i); 59 60 info->memrange[info->n_memranges].base = 61 UNPACK_CB64(range->start); 62 63 info->memrange[info->n_memranges].size = 64 UNPACK_CB64(range->size); 65 66 info->memrange[info->n_memranges].type = range->type; 67 68 info->n_memranges++; 69 } 70 } 71 72 static void cb_parse_serial(unsigned char *ptr, struct sysinfo_t *info) 73 { 74 struct cb_serial *ser = (struct cb_serial *)ptr; 75 if (ser->type != CB_SERIAL_TYPE_IO_MAPPED) 76 return; 77 info->ser_ioport = ser->baseaddr; 78 } 79 80 static void cb_parse_optiontable(unsigned char *ptr, struct sysinfo_t *info) 81 { 82 info->option_table = (struct cb_cmos_option_table *)ptr; 83 } 84 85 static void cb_parse_checksum(unsigned char *ptr, struct sysinfo_t *info) 86 { 87 struct cb_cmos_checksum *cmos_cksum = (struct cb_cmos_checksum *)ptr; 88 info->cmos_range_start = cmos_cksum->range_start; 89 info->cmos_range_end = cmos_cksum->range_end; 90 info->cmos_checksum_location = cmos_cksum->location; 91 } 92 93 static void cb_parse_framebuffer(unsigned char *ptr, struct sysinfo_t *info) 94 { 95 info->framebuffer = (struct cb_framebuffer *)ptr; 96 } 97 98 static int cb_parse_header(void *addr, int len, struct sysinfo_t *info) 99 { 100 struct cb_header *header; 101 unsigned char *ptr = (unsigned char *)addr; 102 int i; 103 104 for (i = 0; i < len; i += 16, ptr += 16) { 105 header = (struct cb_header *)ptr; 106 if (!strncmp((const char *)header->signature, "LBIO", 4)) 107 break; 108 } 109 110 /* We walked the entire space and didn't find anything. */ 111 if (i >= len) 112 return -1; 113 114 if (!header->table_bytes) 115 return 0; 116 117 /* Make sure the checksums match. */ 118 if (ipchksum((u16 *) header, sizeof(*header)) != 0) 119 return -1; 120 121 if (ipchksum((u16 *) (ptr + sizeof(*header)), 122 header->table_bytes) != header->table_checksum) 123 return -1; 124 125 /* Now, walk the tables. */ 126 ptr += header->header_bytes; 127 128 for (i = 0; i < header->table_entries; i++) { 129 struct cb_record *rec = (struct cb_record *)ptr; 130 131 /* We only care about a few tags here (maybe more later). */ 132 switch (rec->tag) { 133 case CB_TAG_FORWARD: 134 return cb_parse_header( 135 (void *)(unsigned long) 136 ((struct cb_forward *)rec)->forward, 137 len, info); 138 continue; 139 case CB_TAG_MEMORY: 140 cb_parse_memory(ptr, info); 141 break; 142 case CB_TAG_SERIAL: 143 cb_parse_serial(ptr, info); 144 break; 145 case CB_TAG_CMOS_OPTION_TABLE: 146 cb_parse_optiontable(ptr, info); 147 break; 148 case CB_TAG_OPTION_CHECKSUM: 149 cb_parse_checksum(ptr, info); 150 break; 151 /* 152 * FIXME we should warn on serial if coreboot set up a 153 * framebuffer buf the payload does not know about it. 154 */ 155 case CB_TAG_FRAMEBUFFER: 156 cb_parse_framebuffer(ptr, info); 157 break; 158 } 159 160 ptr += rec->size; 161 } 162 163 return 1; 164 } 165 166 /* == Architecture specific == */ 167 /* This is the x86 specific stuff. */ 168 169 /* Assume no translation or that memory is identity mapped. */ 170 static void *phys_to_virt(unsigned long virt) 171 { 172 return (void *)(uintptr_t)virt; 173 } 174 175 int get_coreboot_info(struct sysinfo_t *info) 176 { 177 int ret = cb_parse_header(phys_to_virt(0x00000000), 0x1000, info); 178 179 if (ret != 1) 180 ret = cb_parse_header(phys_to_virt(0x000f0000), 0x1000, info); 181 182 return (ret == 1) ? 0 : -1; 183 } 184