diff options
Diffstat (limited to 'arch/x86/lib/coreboot_table.c')
-rw-r--r-- | arch/x86/lib/coreboot_table.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/arch/x86/lib/coreboot_table.c b/arch/x86/lib/coreboot_table.c new file mode 100644 index 0000000..cb45a79 --- /dev/null +++ b/arch/x86/lib/coreboot_table.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <vbe.h> +#include <asm/coreboot_tables.h> +#include <asm/e820.h> + +/** + * cb_table_init() - initialize a coreboot table header + * + * This fills in the coreboot table header signature and the header bytes. + * Other fields are set to zero. + * + * @cbh: coreboot table header address + */ +static void cb_table_init(struct cb_header *cbh) +{ + memset(cbh, 0, sizeof(struct cb_header)); + memcpy(cbh->signature, "LBIO", 4); + cbh->header_bytes = sizeof(struct cb_header); +} + +/** + * cb_table_add_entry() - add a coreboot table entry + * + * This increases the coreboot table entry size with added table entry length + * and increases entry count by 1. + * + * @cbh: coreboot table header address + * @cbr: to be added table entry address + * @return: pointer to next table entry address + */ +static u32 cb_table_add_entry(struct cb_header *cbh, struct cb_record *cbr) +{ + cbh->table_bytes += cbr->size; + cbh->table_entries++; + + return (u32)cbr + cbr->size; +} + +/** + * cb_table_finalize() - finalize the coreboot table + * + * This calculates the checksum for all coreboot table entries as well as + * the checksum for the coreboot header itself. + * + * @cbh: coreboot table header address + */ +static void cb_table_finalize(struct cb_header *cbh) +{ + struct cb_record *cbr = (struct cb_record *)(cbh + 1); + + cbh->table_checksum = compute_ip_checksum(cbr, cbh->table_bytes); + cbh->header_checksum = compute_ip_checksum(cbh, cbh->header_bytes); +} + +void write_coreboot_table(u32 addr, struct memory_area *cfg_tables) +{ + struct cb_header *cbh = (struct cb_header *)addr; + struct cb_record *cbr; + struct cb_memory *mem; + struct cb_memory_range *map; + struct e820entry e820[32]; + struct cb_framebuffer *fb; + struct vesa_mode_info *vesa; + int i, num; + + cb_table_init(cbh); + cbr = (struct cb_record *)(cbh + 1); + + /* + * Two type of coreboot table entries are generated by us. + * They are 'struct cb_memory' and 'struct cb_framebuffer'. + */ + + /* populate memory map table */ + mem = (struct cb_memory *)cbr; + mem->tag = CB_TAG_MEMORY; + map = mem->map; + + /* first install e820 defined memory maps */ + num = install_e820_map(ARRAY_SIZE(e820), e820); + for (i = 0; i < num; i++) { + map->start.lo = e820[i].addr & 0xffffffff; + map->start.hi = e820[i].addr >> 32; + map->size.lo = e820[i].size & 0xffffffff; + map->size.hi = e820[i].size >> 32; + map->type = e820[i].type; + map++; + } + + /* then install all configuration tables */ + while (cfg_tables->size) { + map->start.lo = cfg_tables->start & 0xffffffff; + map->start.hi = cfg_tables->start >> 32; + map->size.lo = cfg_tables->size & 0xffffffff; + map->size.hi = cfg_tables->size >> 32; + map->type = CB_MEM_TABLE; + map++; + num++; + cfg_tables++; + } + mem->size = num * sizeof(struct cb_memory_range) + + sizeof(struct cb_record); + cbr = (struct cb_record *)cb_table_add_entry(cbh, cbr); + + /* populate framebuffer table if we have sane vesa info */ + vesa = &mode_info.vesa; + if (vesa->x_resolution && vesa->y_resolution) { + fb = (struct cb_framebuffer *)cbr; + fb->tag = CB_TAG_FRAMEBUFFER; + fb->size = sizeof(struct cb_framebuffer); + + fb->x_resolution = vesa->x_resolution; + fb->y_resolution = vesa->y_resolution; + fb->bits_per_pixel = vesa->bits_per_pixel; + fb->bytes_per_line = vesa->bytes_per_scanline; + fb->physical_address = vesa->phys_base_ptr; + fb->red_mask_size = vesa->red_mask_size; + fb->red_mask_pos = vesa->red_mask_pos; + fb->green_mask_size = vesa->green_mask_size; + fb->green_mask_pos = vesa->green_mask_pos; + fb->blue_mask_size = vesa->blue_mask_size; + fb->blue_mask_pos = vesa->blue_mask_pos; + fb->reserved_mask_size = vesa->reserved_mask_size; + fb->reserved_mask_pos = vesa->reserved_mask_pos; + + cbr = (struct cb_record *)cb_table_add_entry(cbh, cbr); + } + + cb_table_finalize(cbh); +} |