qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

pvh_main.c (4537B)


      1 /*
      2  * PVH Option ROM for fw_cfg DMA
      3  *
      4  * This program is free software; you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation; either version 2 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     12  * GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program; if not, see <http://www.gnu.org/licenses/>.
     16  *
     17  * Copyright (c) 2019 Red Hat Inc.
     18  *   Authors:
     19  *     Stefano Garzarella <sgarzare@redhat.com>
     20  */
     21 
     22 asm (".code32"); /* this code will be executed in protected mode */
     23 
     24 #include <stddef.h>
     25 #include <stdint.h>
     26 #include "optrom.h"
     27 #include "optrom_fw_cfg.h"
     28 #include "../../include/hw/xen/start_info.h"
     29 
     30 #define RSDP_SIGNATURE          0x2052545020445352LL /* "RSD PTR " */
     31 #define RSDP_AREA_ADDR          0x000E0000
     32 #define RSDP_AREA_SIZE          0x00020000
     33 #define EBDA_BASE_ADDR          0x0000040E
     34 #define EBDA_SIZE               1024
     35 
     36 #define E820_MAXENTRIES         128
     37 #define CMDLINE_BUFSIZE         4096
     38 
     39 /* e820 table filled in pvh.S using int 0x15 */
     40 struct pvh_e820_table {
     41     uint32_t entries;
     42     uint32_t reserved;
     43     struct hvm_memmap_table_entry table[E820_MAXENTRIES];
     44 };
     45 
     46 struct pvh_e820_table pvh_e820 asm("pvh_e820") __attribute__ ((aligned));
     47 
     48 static struct hvm_start_info start_info;
     49 static struct hvm_modlist_entry ramdisk_mod;
     50 static uint8_t cmdline_buffer[CMDLINE_BUFSIZE];
     51 
     52 
     53 /* Search RSDP signature. */
     54 static uintptr_t search_rsdp(uint32_t start_addr, uint32_t end_addr)
     55 {
     56     uint64_t *rsdp_p;
     57 
     58     /* RSDP signature is always on a 16 byte boundary */
     59     for (rsdp_p = (uint64_t *)start_addr; rsdp_p < (uint64_t *)end_addr;
     60          rsdp_p += 2) {
     61         if (*rsdp_p == RSDP_SIGNATURE) {
     62             return (uintptr_t)rsdp_p;
     63         }
     64     }
     65 
     66     return 0;
     67 }
     68 
     69 /* Force the asm name without leading underscore, even on Win32. */
     70 extern void pvh_load_kernel(void) asm("pvh_load_kernel");
     71 
     72 void pvh_load_kernel(void)
     73 {
     74     void *cmdline_addr = &cmdline_buffer;
     75     void *kernel_entry, *initrd_addr;
     76     uint32_t cmdline_size, initrd_size, fw_cfg_version = bios_cfg_version();
     77 
     78     start_info.magic = XEN_HVM_START_MAGIC_VALUE;
     79     start_info.version = 1;
     80 
     81     /*
     82      * pvh_e820 is filled in the pvh.S before to switch in protected mode,
     83      * because we can use int 0x15 only in real mode.
     84      */
     85     start_info.memmap_entries = pvh_e820.entries;
     86     start_info.memmap_paddr = (uintptr_t)pvh_e820.table;
     87 
     88     /*
     89      * Search RSDP in the main BIOS area below 1 MB.
     90      * SeaBIOS store the RSDP in this area, so we try it first.
     91      */
     92     start_info.rsdp_paddr = search_rsdp(RSDP_AREA_ADDR,
     93                                         RSDP_AREA_ADDR + RSDP_AREA_SIZE);
     94 
     95     /* Search RSDP in the EBDA if it is not found */
     96     if (!start_info.rsdp_paddr) {
     97         /*
     98          * Th EBDA address is stored at EBDA_BASE_ADDR. It contains 2 bytes
     99          * segment pointer to EBDA, so we must convert it to a linear address.
    100          */
    101         uint32_t ebda_paddr = ((uint32_t)*((uint16_t *)EBDA_BASE_ADDR)) << 4;
    102         if (ebda_paddr > 0x400) {
    103             uint32_t *ebda = (uint32_t *)ebda_paddr;
    104 
    105             start_info.rsdp_paddr = search_rsdp(*ebda, *ebda + EBDA_SIZE);
    106         }
    107     }
    108 
    109     bios_cfg_read_entry(&cmdline_size, FW_CFG_CMDLINE_SIZE, 4, fw_cfg_version);
    110     bios_cfg_read_entry(cmdline_addr, FW_CFG_CMDLINE_DATA, cmdline_size,
    111                         fw_cfg_version);
    112     start_info.cmdline_paddr = (uintptr_t)cmdline_addr;
    113 
    114     /* Check if we have the initrd to load */
    115     bios_cfg_read_entry(&initrd_size, FW_CFG_INITRD_SIZE, 4, fw_cfg_version);
    116     if (initrd_size) {
    117         bios_cfg_read_entry(&initrd_addr, FW_CFG_INITRD_ADDR, 4,
    118                             fw_cfg_version);
    119         bios_cfg_read_entry(initrd_addr, FW_CFG_INITRD_DATA, initrd_size,
    120                             fw_cfg_version);
    121 
    122         ramdisk_mod.paddr = (uintptr_t)initrd_addr;
    123         ramdisk_mod.size = initrd_size;
    124 
    125         /* The first module is always ramdisk. */
    126         start_info.modlist_paddr = (uintptr_t)&ramdisk_mod;
    127         start_info.nr_modules = 1;
    128     }
    129 
    130     bios_cfg_read_entry(&kernel_entry, FW_CFG_KERNEL_ENTRY, 4, fw_cfg_version);
    131 
    132     asm volatile("jmp *%1" : : "b"(&start_info), "c"(kernel_entry));
    133 }