| /** @file | |
| This program generates a hex array to be manually coppied into | |
| OvmfXen.fdf. | |
| The purpose is for the flash device image to be recognize as an ELF. | |
| Copyright (c) 2019, Citrix Systems, Inc. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "elf.h" | |
| #include "fcntl.h" | |
| #include "stdbool.h" | |
| #include "stddef.h" | |
| #include "stdio.h" | |
| #include "stdlib.h" | |
| void | |
| print_hdr ( | |
| FILE *file, | |
| void *s, | |
| size_t size, | |
| bool end_delimiter | |
| ) | |
| { | |
| char *c = s; | |
| fprintf (file, " "); | |
| while (size-- > 1) { | |
| fprintf (file, "0x%02hhx, ", *(c++)); | |
| } | |
| if (end_delimiter) { | |
| fprintf (file, "0x%02hhx,", *c); | |
| } else { | |
| fprintf (file, "0x%02hhx", *c); | |
| } | |
| } | |
| /* Format for the XEN_ELFNOTE_PHYS32_ENTRY program segment */ | |
| #define XEN_ELFNOTE_PHYS32_ENTRY 18 | |
| typedef struct { | |
| uint32_t name_size; | |
| uint32_t desc_size; | |
| uint32_t type; | |
| char name[4]; | |
| uint32_t desc; | |
| } xen_elfnote_phys32_entry; | |
| #define LICENSE_HDR "\ | |
| ## @file\r\n\ | |
| # FDF include file that defines a PVH ELF header.\r\n\ | |
| #\r\n\ | |
| # Copyright (c) 2022, Intel Corporation. All rights reserved.\r\n\ | |
| #\r\n\ | |
| # SPDX-License-Identifier: BSD-2-Clause-Patent\r\n\ | |
| #\r\n\ | |
| ##\r\n\ | |
| \r\n\ | |
| " | |
| int | |
| main ( | |
| int argc, | |
| char *argv[] | |
| ) | |
| { | |
| /* FW_SIZE */ | |
| size_t ovmf_blob_size = 0x00200000; | |
| /* Load OVMF at 1MB when running as PVH guest */ | |
| uint32_t ovmf_base_address = 0x00100000; | |
| uint32_t ovmfxen_pvh_entry_point; | |
| size_t offset_into_file = 0; | |
| char *endptr, *str; | |
| long param; | |
| FILE *file = stdout; | |
| /* Parse the size parameter */ | |
| if (argc > 1) { | |
| str = argv[1]; | |
| param = strtol (str, &endptr, 10); | |
| if (endptr != str) { | |
| ovmf_blob_size = (size_t)param; | |
| } | |
| } | |
| /* Parse the filepath parameter */ | |
| if (argc > 2) { | |
| file = fopen (argv[2], "w"); | |
| fprintf (file, LICENSE_HDR); | |
| } | |
| /* Xen PVH entry point */ | |
| ovmfxen_pvh_entry_point = ovmf_base_address + ovmf_blob_size - 0x30; | |
| /* ELF file header */ | |
| #ifdef PVH64 | |
| Elf64_Ehdr hdr = { | |
| #else | |
| Elf32_Ehdr hdr = { | |
| #endif | |
| .e_ident = ELFMAG, | |
| .e_type = ET_EXEC, | |
| .e_machine = EM_386, | |
| .e_version = EV_CURRENT, | |
| .e_entry = ovmfxen_pvh_entry_point, | |
| .e_flags = R_386_NONE, | |
| .e_ehsize = sizeof (hdr), | |
| #ifdef PVH64 | |
| .e_phentsize = sizeof (Elf64_Phdr), | |
| #else | |
| .e_phentsize = sizeof (Elf32_Phdr), | |
| #endif | |
| }; | |
| offset_into_file += sizeof (hdr); | |
| #ifdef PVH64 | |
| hdr.e_ident[EI_CLASS] = ELFCLASS64; | |
| #else | |
| hdr.e_ident[EI_CLASS] = ELFCLASS32; | |
| #endif | |
| hdr.e_ident[EI_DATA] = ELFDATA2LSB; | |
| hdr.e_ident[EI_VERSION] = EV_CURRENT; | |
| hdr.e_ident[EI_OSABI] = ELFOSABI_LINUX; | |
| /* Placing program headers just after hdr */ | |
| hdr.e_phoff = sizeof (hdr); | |
| /* program header */ | |
| #ifdef PVH64 | |
| Elf64_Phdr phdr_load = { | |
| #else | |
| Elf32_Phdr phdr_load = { | |
| #endif | |
| .p_type = PT_LOAD, | |
| .p_offset = 0, /* load everything */ | |
| .p_paddr = ovmf_base_address, | |
| .p_filesz = ovmf_blob_size, | |
| .p_memsz = ovmf_blob_size, | |
| .p_flags = PF_X | PF_W | PF_R, | |
| #ifdef PVH64 | |
| .p_align = 4, | |
| #else | |
| .p_align = 0, | |
| #endif | |
| }; | |
| phdr_load.p_vaddr = phdr_load.p_paddr; | |
| hdr.e_phnum += 1; | |
| offset_into_file += sizeof (phdr_load); | |
| /* Xen ELF Note. */ | |
| xen_elfnote_phys32_entry xen_elf_note = { | |
| .type = XEN_ELFNOTE_PHYS32_ENTRY, | |
| .name = "Xen", | |
| .desc = ovmfxen_pvh_entry_point, | |
| .name_size = | |
| offsetof (xen_elfnote_phys32_entry, desc) - | |
| offsetof (xen_elfnote_phys32_entry, name), | |
| .desc_size = | |
| sizeof (xen_elfnote_phys32_entry) - | |
| offsetof (xen_elfnote_phys32_entry, desc), | |
| }; | |
| #ifdef PVH64 | |
| Elf64_Phdr phdr_note = { | |
| #else | |
| Elf32_Phdr phdr_note = { | |
| #endif | |
| .p_type = PT_NOTE, | |
| .p_filesz = sizeof (xen_elf_note), | |
| .p_memsz = sizeof (xen_elf_note), | |
| .p_flags = PF_R, | |
| #ifdef PVH64 | |
| .p_align = 4, | |
| #else | |
| .p_align = 0, | |
| #endif | |
| }; | |
| hdr.e_phnum += 1; | |
| offset_into_file += sizeof (phdr_note); | |
| phdr_note.p_offset = offset_into_file; | |
| phdr_note.p_paddr = ovmf_base_address + phdr_note.p_offset; | |
| phdr_note.p_vaddr = phdr_note.p_paddr; | |
| /* | |
| * print elf header | |
| */ | |
| size_t i; | |
| size_t hdr_size = sizeof (hdr); | |
| size_t entry_off = offsetof (typeof(hdr), e_entry); | |
| fprintf (file, "DATA = {\r\n"); | |
| fprintf (file, " # ELF file header\r\n"); | |
| print_hdr (file, &hdr, entry_off, true); | |
| fprintf (file, "\r\n"); | |
| print_hdr (file, &hdr.e_entry, sizeof (hdr.e_entry), true); | |
| fprintf (file, " # hdr.e_entry\r\n"); | |
| print_hdr (file, &hdr.e_entry + 1, hdr_size - entry_off - sizeof (hdr.e_entry), true); | |
| fprintf (file, "\r\n\r\n # ELF Program segment headers\r\n"); | |
| fprintf (file, " # - Load segment\r\n"); | |
| for (i = 0; i < sizeof (phdr_load); i += 4) { | |
| print_hdr (file, ((char *)&phdr_load) + i, 4, true); | |
| fprintf (file, "\r\n"); | |
| } | |
| fprintf (file, " # - ELFNOTE segment\r\n"); | |
| for (i = 0; i < sizeof (phdr_note); i += 4) { | |
| print_hdr (file, ((char *)&phdr_note) + i, 4, true); | |
| fprintf (file, "\r\n"); | |
| } | |
| fprintf (file, "\r\n # XEN_ELFNOTE_PHYS32_ENTRY\r\n"); | |
| for (i = 0; i < sizeof (xen_elf_note); i += 4) { | |
| print_hdr (file, ((char *)&xen_elf_note) + i, 4, (sizeof (xen_elf_note) - i) > 4); | |
| fprintf (file, "\r\n"); | |
| } | |
| fprintf (file, "}\r\n"); | |
| return 0; | |
| } |