diff options
author | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
---|---|---|
committer | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/qboot/tables.c | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/qboot/tables.c')
-rw-r--r-- | roms/qboot/tables.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/roms/qboot/tables.c b/roms/qboot/tables.c new file mode 100644 index 000000000..9934a913a --- /dev/null +++ b/roms/qboot/tables.c @@ -0,0 +1,159 @@ +#include "bios.h" +#include "stdio.h" +#include "fw_cfg.h" +#include "string.h" +#include "start_info.h" + +extern struct hvm_start_info start_info; + +struct loader_cmd { + uint32_t cmd; + union { +#define CMD_QUIT 0 +#define CMD_ALLOC 1 + struct { + char file[56]; + uint32_t align; + uint8_t zone; + } alloc; +#define CMD_PTR 2 + struct { + char dest[56]; + char src[56]; + uint32_t offset; + uint8_t size; + } ptr; +#define CMD_CHECKSUM 3 + struct { + char file[56]; + uint32_t offset; + uint32_t start; + uint32_t len; + } checksum; + uint8_t pad[124]; + }; +} __attribute__((__packed__)); + +enum { + ALLOC_HIGH = 1, + ALLOC_FSEG = 2 +}; + +static uint8_t *file_address[20]; + +static inline void *id_to_addr(int fw_cfg_id) +{ + return file_address[fw_cfg_id]; +} + +static inline void set_file_addr(int fw_cfg_id, void *p) +{ + file_address[fw_cfg_id] = p; +} + +static void do_alloc(char *file, uint32_t align, uint8_t zone) +{ + int id = fw_cfg_file_id(file); + int n = fw_cfg_file_size(id); + char *p; + + if (id == -1) + panic(); + + if (align < 16) + align = 16; + + if (zone == ALLOC_FSEG) + p = malloc_fseg_align(n, align); + else + p = malloc_align(n, align); + + set_file_addr(id, p); + fw_cfg_read_file(id, p, n); + + /* For PVH boot, save the PA where the RSDP is stored */ + if (zone == ALLOC_FSEG) { + if (!memcmp(p, "RSD PTR ", 8)) { + start_info.rsdp_paddr = (uintptr_t)id_to_addr(id); + } + } +} + +static void do_ptr(char *dest, char *src, uint32_t offset, uint8_t size) +{ + char *p, *q; + int id; + union { + long long ll; + char b[8]; + } data; + + id = fw_cfg_file_id(src); + p = id_to_addr(id); + if (!p) + panic(); + + id = fw_cfg_file_id(dest); + q = id_to_addr(id); + if (!q) + panic(); + + q += offset; + + /* Assumes little endian */ + data.ll = 0; + memcpy(&data.b, q, size); + data.ll += (uintptr_t) p; + memcpy(q, &data.b, size); +} + +static void do_checksum(char *file, uint32_t offset, uint32_t start, uint32_t len) +{ + uint8_t *p; + int id; + int n; + + id = fw_cfg_file_id(file); + p = id_to_addr(id); + if (!p) + panic(); + + n = fw_cfg_file_size(id); + if (offset >= n || n < start || len > n - start) + panic(); + + p[offset] -= csum8(&p[start], len); +} + +void extract_acpi(void) +{ + int id = fw_cfg_file_id("etc/table-loader"); + int n = fw_cfg_file_size(id); + struct loader_cmd script[n / sizeof(struct loader_cmd)]; + int i; + + if (!n) + return; + + fw_cfg_read_file(id, script, n); + + for (i = 0; i < ARRAY_SIZE(script); i++) { + struct loader_cmd *s = &script[i]; + switch(script[i].cmd) { + case CMD_ALLOC: + do_alloc(s->alloc.file, s->alloc.align, s->alloc.zone); + break; + case CMD_PTR: + do_ptr(s->ptr.dest, s->ptr.src, s->ptr.offset, s->ptr.size); + break; + case CMD_CHECKSUM: + do_checksum(s->checksum.file, s->checksum.offset, + s->checksum.start, s->checksum.len); + break; + case CMD_QUIT: + return; + default: + panic(); + } + } +} |