akaros/user/vmm/coreboot_table.c
<<
>>
Prefs
   1/*
   2 * This file is part of the coreboot project.
   3 *
   4 * Copyright (C) 2003-2004 Eric Biederman
   5 * Copyright (C) 2005-2010 coresystems GmbH
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License as
   9 * published by the Free Software Foundation; version 2 of
  10 * the License.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
  20 * MA 02110-1301 USA
  21 */
  22
  23#include <parlib/common.h>
  24#include <parlib/stdio.h>
  25
  26#include <stdarg.h>
  27#include <string.h>
  28#include <vmm/coreboot_tables.h>
  29
  30static struct lb_header *lb_table_init(void *addr)
  31{
  32        struct lb_header *header;
  33
  34        /* 16 byte align the address */
  35        header = (void *)(((unsigned long)addr + 15) & ~15);
  36        header->signature[0] = 'L';
  37        header->signature[1] = 'B';
  38        header->signature[2] = 'I';
  39        header->signature[3] = 'O';
  40        header->header_bytes = sizeof(*header);
  41        header->header_checksum = 0;
  42        header->table_bytes = 0;
  43        header->table_checksum = 0;
  44        header->table_entries = 0;
  45        return header;
  46}
  47
  48static struct lb_record *lb_first_record(struct lb_header *header)
  49{
  50        struct lb_record *rec;
  51        rec = (void *)(((char *)header) + sizeof(*header));
  52        return rec;
  53}
  54
  55static struct lb_record *lb_last_record(struct lb_header *header)
  56{
  57        struct lb_record *rec;
  58        rec = (void *)(((char *)header) + sizeof(*header) + header->table_bytes);
  59        return rec;
  60}
  61
  62struct lb_record *lb_new_record(struct lb_header *header)
  63{
  64        struct lb_record *rec;
  65        rec = lb_last_record(header);
  66        if (header->table_entries) {
  67                header->table_bytes += rec->size;
  68        }
  69        rec = lb_last_record(header);
  70        header->table_entries++;
  71        rec->tag = LB_TAG_UNUSED;
  72        rec->size = sizeof(*rec);
  73        return rec;
  74}
  75
  76static struct lb_memory *lb_memory(struct lb_header *header)
  77{
  78        struct lb_record *rec;
  79        struct lb_memory *mem;
  80        rec = lb_new_record(header);
  81        mem = (struct lb_memory *)rec;
  82        mem->tag = LB_TAG_MEMORY;
  83        mem->size = sizeof(*mem);
  84        return mem;
  85}
  86
  87void lb_add_serial(struct lb_serial *new_serial, void *data)
  88{
  89        struct lb_header *header = (struct lb_header *)data;
  90        struct lb_serial *serial;
  91
  92        serial = (struct lb_serial *)lb_new_record(header);
  93        serial->tag = LB_TAG_SERIAL;
  94        serial->size = sizeof(*serial);
  95        serial->type = new_serial->type;
  96        serial->baseaddr = new_serial->baseaddr;
  97        serial->baud = new_serial->baud;
  98        serial->regwidth = new_serial->regwidth;
  99}
 100
 101void lb_add_console(uint16_t consoletype, void *data)
 102{
 103        struct lb_header *header = (struct lb_header *)data;
 104        struct lb_console *console;
 105
 106        console = (struct lb_console *)lb_new_record(header);
 107        console->tag = LB_TAG_CONSOLE;
 108        console->size = sizeof(*console);
 109        console->type = consoletype;
 110}
 111
 112static void lb_framebuffer(struct lb_header *header)
 113{
 114#if 0 //CONFIG_FRAMEBUFFER_KEEP_VESA_MODE || CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT
 115        void fill_lb_framebuffer(struct lb_framebuffer *framebuffer);
 116        int vbe_mode_info_valid(void);
 117
 118        // If there isn't any mode info to put in the table, don't ask for it
 119        // to be filled with junk.
 120        if (!vbe_mode_info_valid())
 121                return;
 122        struct lb_framebuffer *framebuffer;
 123        framebuffer = (struct lb_framebuffer *)lb_new_record(header);
 124        fill_lb_framebuffer(framebuffer);
 125        framebuffer->tag = LB_TAG_FRAMEBUFFER;
 126        framebuffer->size = sizeof(*framebuffer);
 127#endif
 128}
 129
 130void fill_lb_gpio(struct lb_gpio *gpio, int num,
 131                         int polarity, const char *name, int value)
 132{
 133        memset(gpio, 0, sizeof(*gpio));
 134        gpio->port = num;
 135        gpio->polarity = polarity;
 136        if (value >= 0)
 137                gpio->value = value;
 138        strncpy((char *)gpio->name, name, GPIO_MAX_NAME_LENGTH);
 139}
 140
 141#if CONFIG_CHROMEOS
 142static void lb_gpios(struct lb_header *header)
 143{
 144        struct lb_gpios *gpios;
 145
 146        gpios = (struct lb_gpios *)lb_new_record(header);
 147        gpios->tag = LB_TAG_GPIO;
 148        gpios->size = sizeof(*gpios);
 149        gpios->count = 0;
 150        fill_lb_gpios(gpios);
 151}
 152
 153static void lb_vdat(struct lb_header *header)
 154{
 155#if CONFIG_HAVE_ACPI_TABLES
 156        struct lb_range *vdat;
 157
 158        vdat = (struct lb_range *)lb_new_record(header);
 159        vdat->tag = LB_TAG_VDAT;
 160        vdat->size = sizeof(*vdat);
 161        acpi_get_vdat_info(&vdat->range_start, &vdat->range_size);
 162#endif
 163}
 164
 165static void lb_vbnv(struct lb_header *header)
 166{
 167#if CONFIG_PC80_SYSTEM
 168        struct lb_range *vbnv;
 169
 170        vbnv = (struct lb_range *)lb_new_record(header);
 171        vbnv->tag = LB_TAG_VBNV;
 172        vbnv->size = sizeof(*vbnv);
 173        vbnv->range_start = CONFIG_VBNV_OFFSET + 14;
 174        vbnv->range_size = CONFIG_VBNV_SIZE;
 175#endif
 176}
 177
 178#if CONFIG_VBOOT_VERIFY_FIRMWARE
 179static void lb_vboot_handoff(struct lb_header *header)
 180{
 181        void *addr;
 182        uint32_t size;
 183        struct lb_range *vbho;
 184
 185        if (vboot_get_handoff_info(&addr, &size))
 186                return;
 187
 188        vbho = (struct lb_range *)lb_new_record(header);
 189        vbho->tag = LB_TAB_VBOOT_HANDOFF;
 190        vbho->size = sizeof(*vbho);
 191        vbho->range_start = (intptr_t)addr;
 192        vbho->range_size = size;
 193}
 194#else
 195static inline void lb_vboot_handoff(struct lb_header *header) {}
 196#endif /* CONFIG_VBOOT_VERIFY_FIRMWARE */
 197#endif /* CONFIG_CHROMEOS */
 198
 199static void lb_board_id(struct lb_header *header)
 200{
 201#if 0 // CONFIG_BOARD_ID_AUTO || CONFIG_BOARD_ID_MANUAL
 202        struct lb_board_id  *bid;
 203
 204        bid = (struct lb_board_id *)lb_new_record(header);
 205
 206        bid->tag = LB_TAG_BOARD_ID;
 207        bid->size = sizeof(*bid);
 208        bid->board_id = board_id();
 209#endif
 210}
 211
 212static void lb_strings(struct lb_header *header)
 213{
 214        static const struct {
 215                uint32_t tag;
 216                const char *string;
 217        } strings[] = {
 218                // we may want this at some point.
 219        };
 220        unsigned int i;
 221        for(i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) {
 222                struct lb_string *rec;
 223                size_t len;
 224                rec = (struct lb_string *)lb_new_record(header);
 225                len = strlen(strings[i].string);
 226                rec->tag = strings[i].tag;
 227                rec->size = (sizeof(*rec) + len + 1 + 3) & ~3;
 228                memcpy(rec->string, strings[i].string, len+1);
 229        }
 230
 231}
 232
 233static void lb_record_version_timestamp(struct lb_header *header)
 234{
 235        struct lb_timestamp *rec;
 236        rec = (struct lb_timestamp *)lb_new_record(header);
 237        rec->tag = LB_TAG_VERSION_TIMESTAMP;
 238        rec->size = sizeof(*rec);
 239        // TODO
 240        //rec->timestamp = coreboot_version_timestamp;
 241}
 242
 243void __attribute__((weak)) lb_board(struct lb_header *header) { /* NOOP */ }
 244
 245static struct lb_forward *lb_forward(struct lb_header *header, struct lb_header *next_header)
 246{
 247        struct lb_record *rec;
 248        struct lb_forward *forward;
 249        rec = lb_new_record(header);
 250        forward = (struct lb_forward *)rec;
 251        forward->tag = LB_TAG_FORWARD;
 252        forward->size = sizeof(*forward);
 253        forward->forward = (uint64_t)(unsigned long)next_header;
 254        return forward;
 255}
 256
 257/* enough with the ip dependency already. This is a trivial checksum. */
 258static inline uint16_t cb_checksum(const void *ptr, unsigned len)
 259{
 260        uint32_t sum;
 261        const uint8_t *addr = ptr;
 262
 263        sum = 0;
 264
 265        while(len > 0) {
 266                sum += addr[0]<<8 | addr[1] ;
 267                len -= 2;
 268                addr += 2;
 269        }
 270
 271        sum = (sum & 0xffff) + (sum >> 16);
 272        sum = (sum & 0xffff) + (sum >> 16);
 273
 274        return (sum^0xffff);
 275}
 276
 277static void *lb_table_fini(struct lb_header *head)
 278{
 279        struct lb_record *rec, *first_rec;
 280        rec = lb_last_record(head);
 281        if (head->table_entries) {
 282                head->table_bytes += rec->size;
 283        }
 284
 285        first_rec = lb_first_record(head);
 286        head->table_checksum = cb_checksum((void *)first_rec, head->table_bytes);
 287        head->header_checksum = 0;
 288        head->header_checksum = cb_checksum((void *)head, sizeof(*head));
 289        printf("Wrote coreboot table at: %p, 0x%x bytes, checksum %x\n",
 290               head, head->table_bytes, head->table_checksum);
 291        printf("header checksum (not worth using in a kernel) 0x%x\n", head->header_checksum);
 292        return rec + rec->size;
 293}
 294
 295void * write_coreboot_table(void *where, void *base, uint64_t len)
 296{
 297        struct lb_header *head;
 298        struct lb_memory *m;
 299        struct lb_memory_range *mem;
 300
 301        printf("Writing coreboot table at %p with mem %p len 0x%lx\n", where, base, len);
 302
 303        head = lb_table_init(where);
 304        m = lb_memory(head);
 305        mem = (void *)(&m[1]);
 306        mem->start = pack_lb64((uint64_t) 0);
 307        mem->size = pack_lb64((uint64_t) base-1);
 308        mem->type = LB_MEM_RESERVED;
 309        m->size += sizeof(*mem);
 310        mem = (void *)(&mem[1]);
 311        mem->start = pack_lb64((uint64_t) base);
 312        mem->size = pack_lb64((uint64_t) len);
 313        mem->type = LB_MEM_RAM;
 314        m->size += sizeof(*mem);
 315        printf("Head is %p, mem is %p, m is %p, m->size is %d, mem->size is %d\n",
 316                head, mem, m, m->size, mem->size);
 317        return lb_table_fini(head);
 318}
 319