19292f776SCyrill Gorcunov #include "kvm/kvm.h" 2*b3594ec7SCyrill Gorcunov #include "kvm/boot-protocol.h" 3*b3594ec7SCyrill Gorcunov #include "kvm/e820.h" 49292f776SCyrill Gorcunov #include "kvm/interrupt.h" 59292f776SCyrill Gorcunov #include "kvm/util.h" 69292f776SCyrill Gorcunov 79292f776SCyrill Gorcunov #include <string.h> 89292f776SCyrill Gorcunov 928ce0d66SCyrill Gorcunov #include "bios/bios-rom.h" 1028ce0d66SCyrill Gorcunov 11ca82361eSPekka Enberg struct irq_handler { 12ca82361eSPekka Enberg unsigned long address; 13ca82361eSPekka Enberg unsigned int irq; 14ca82361eSPekka Enberg void *handler; 15ca82361eSPekka Enberg size_t size; 169292f776SCyrill Gorcunov }; 179292f776SCyrill Gorcunov 1828ce0d66SCyrill Gorcunov #define BIOS_IRQ_ADDR(name) (MB_BIOS_BEGIN + BIOS_OFFSET__##name) 1928ce0d66SCyrill Gorcunov #define BIOS_IRQ_FUNC(name) ((char *)&bios_rom[BIOS_OFFSET__##name]) 2028ce0d66SCyrill Gorcunov #define BIOS_IRQ_SIZE(name) (BIOS_ENTRY_SIZE(BIOS_OFFSET__##name)) 2128ce0d66SCyrill Gorcunov 22ca82361eSPekka Enberg #define DEFINE_BIOS_IRQ_HANDLER(_irq, _handler) \ 23ca82361eSPekka Enberg { \ 24ca82361eSPekka Enberg .irq = _irq, \ 25ca82361eSPekka Enberg .address = BIOS_IRQ_ADDR(_handler), \ 26ca82361eSPekka Enberg .handler = BIOS_IRQ_FUNC(_handler), \ 27ca82361eSPekka Enberg .size = BIOS_IRQ_SIZE(_handler), \ 28ca82361eSPekka Enberg } 29ca82361eSPekka Enberg 30ca82361eSPekka Enberg static struct irq_handler bios_irq_handlers[] = { 31ca82361eSPekka Enberg DEFINE_BIOS_IRQ_HANDLER(0x10, bios_int10), 32ca82361eSPekka Enberg DEFINE_BIOS_IRQ_HANDLER(0x15, bios_int15), 33ca82361eSPekka Enberg }; 34ca82361eSPekka Enberg 35ca82361eSPekka Enberg static void setup_irq_handler(struct kvm *kvm, struct irq_handler *handler) 36ca82361eSPekka Enberg { 37ca82361eSPekka Enberg struct real_intr_desc intr_desc; 38ca82361eSPekka Enberg void *p; 39ca82361eSPekka Enberg 40ca82361eSPekka Enberg p = guest_flat_to_host(kvm, handler->address); 41ca82361eSPekka Enberg memcpy(p, handler->handler, handler->size); 42ca82361eSPekka Enberg 43ca82361eSPekka Enberg intr_desc = (struct real_intr_desc) { 44ca82361eSPekka Enberg .segment = REAL_SEGMENT(handler->address), 45ca82361eSPekka Enberg .offset = REAL_OFFSET(handler->address), 46ca82361eSPekka Enberg }; 47ca82361eSPekka Enberg 48ca82361eSPekka Enberg interrupt_table__set(&kvm->interrupt_table, &intr_desc, handler->irq); 49ca82361eSPekka Enberg } 50ca82361eSPekka Enberg 51*b3594ec7SCyrill Gorcunov /** 52*b3594ec7SCyrill Gorcunov * e820_setup - setup some simple E820 memory map 53*b3594ec7SCyrill Gorcunov * @kvm - guest system descriptor 54*b3594ec7SCyrill Gorcunov */ 55*b3594ec7SCyrill Gorcunov static void e820_setup(struct kvm *kvm) 56*b3594ec7SCyrill Gorcunov { 57*b3594ec7SCyrill Gorcunov struct e820_entry *mem_map; 58*b3594ec7SCyrill Gorcunov unsigned char *size; 59*b3594ec7SCyrill Gorcunov unsigned int i = 0; 60*b3594ec7SCyrill Gorcunov 61*b3594ec7SCyrill Gorcunov size = guest_flat_to_host(kvm, E820_MAP_SIZE); 62*b3594ec7SCyrill Gorcunov mem_map = guest_flat_to_host(kvm, E820_MAP_START); 63*b3594ec7SCyrill Gorcunov 64*b3594ec7SCyrill Gorcunov *size = E820_MEM_AREAS; 65*b3594ec7SCyrill Gorcunov 66*b3594ec7SCyrill Gorcunov mem_map[i++] = (struct e820_entry) { 67*b3594ec7SCyrill Gorcunov .addr = REAL_MODE_IVT_BEGIN, 68*b3594ec7SCyrill Gorcunov .size = EBDA_START - REAL_MODE_IVT_BEGIN, 69*b3594ec7SCyrill Gorcunov .type = E820_MEM_USABLE, 70*b3594ec7SCyrill Gorcunov }; 71*b3594ec7SCyrill Gorcunov mem_map[i++] = (struct e820_entry) { 72*b3594ec7SCyrill Gorcunov .addr = EBDA_START, 73*b3594ec7SCyrill Gorcunov .size = VGA_RAM_BEGIN - EBDA_START, 74*b3594ec7SCyrill Gorcunov .type = E820_MEM_RESERVED, 75*b3594ec7SCyrill Gorcunov }; 76*b3594ec7SCyrill Gorcunov mem_map[i++] = (struct e820_entry) { 77*b3594ec7SCyrill Gorcunov .addr = MB_BIOS_BEGIN, 78*b3594ec7SCyrill Gorcunov .size = MB_BIOS_END - MB_BIOS_BEGIN, 79*b3594ec7SCyrill Gorcunov .type = E820_MEM_RESERVED, 80*b3594ec7SCyrill Gorcunov }; 81*b3594ec7SCyrill Gorcunov mem_map[i++] = (struct e820_entry) { 82*b3594ec7SCyrill Gorcunov .addr = BZ_KERNEL_START, 83*b3594ec7SCyrill Gorcunov .size = kvm->ram_size - BZ_KERNEL_START, 84*b3594ec7SCyrill Gorcunov .type = E820_MEM_USABLE, 85*b3594ec7SCyrill Gorcunov }; 86*b3594ec7SCyrill Gorcunov 87*b3594ec7SCyrill Gorcunov BUILD_BUG_ON(i > E820_MEM_AREAS); 88*b3594ec7SCyrill Gorcunov } 89*b3594ec7SCyrill Gorcunov 90*b3594ec7SCyrill Gorcunov /** 91*b3594ec7SCyrill Gorcunov * setup_bios - inject BIOS into guest memory 92*b3594ec7SCyrill Gorcunov * @kvm - guest system descriptor 93*b3594ec7SCyrill Gorcunov */ 949292f776SCyrill Gorcunov void setup_bios(struct kvm *kvm) 959292f776SCyrill Gorcunov { 969292f776SCyrill Gorcunov unsigned long address = MB_BIOS_BEGIN; 979292f776SCyrill Gorcunov struct real_intr_desc intr_desc; 98ca82361eSPekka Enberg unsigned int i; 999292f776SCyrill Gorcunov void *p; 1009292f776SCyrill Gorcunov 10115c2b0a0SCyrill Gorcunov /* 10215c2b0a0SCyrill Gorcunov * before anything else -- clean some known areas 10315c2b0a0SCyrill Gorcunov * we definitely don't want any trash here 10415c2b0a0SCyrill Gorcunov */ 10515c2b0a0SCyrill Gorcunov p = guest_flat_to_host(kvm, BDA_START); 10615c2b0a0SCyrill Gorcunov memset(p, 0, BDA_END - BDA_START); 10715c2b0a0SCyrill Gorcunov 10815c2b0a0SCyrill Gorcunov p = guest_flat_to_host(kvm, EBDA_START); 10915c2b0a0SCyrill Gorcunov memset(p, 0, EBDA_END - EBDA_START); 11015c2b0a0SCyrill Gorcunov 11115c2b0a0SCyrill Gorcunov p = guest_flat_to_host(kvm, MB_BIOS_BEGIN); 11215c2b0a0SCyrill Gorcunov memset(p, 0, MB_BIOS_END - MB_BIOS_BEGIN); 11315c2b0a0SCyrill Gorcunov 11415c2b0a0SCyrill Gorcunov p = guest_flat_to_host(kvm, VGA_ROM_BEGIN); 11515c2b0a0SCyrill Gorcunov memset(p, 0, VGA_ROM_END - VGA_ROM_BEGIN); 11615c2b0a0SCyrill Gorcunov 11728ce0d66SCyrill Gorcunov /* just copy the bios rom into the place */ 11828ce0d66SCyrill Gorcunov p = guest_flat_to_host(kvm, MB_BIOS_BEGIN); 11928ce0d66SCyrill Gorcunov memcpy(p, bios_rom, bios_rom_size); 12028ce0d66SCyrill Gorcunov 121*b3594ec7SCyrill Gorcunov /* E820 memory map must be present */ 122*b3594ec7SCyrill Gorcunov e820_setup(kvm); 123*b3594ec7SCyrill Gorcunov 1249292f776SCyrill Gorcunov /* 1259292f776SCyrill Gorcunov * Setup a *fake* real mode vector table, it has only 1269292f776SCyrill Gorcunov * one real hadler which does just iret 1279292f776SCyrill Gorcunov */ 12828ce0d66SCyrill Gorcunov address = BIOS_IRQ_ADDR(bios_intfake); 1299292f776SCyrill Gorcunov intr_desc = (struct real_intr_desc) { 1309292f776SCyrill Gorcunov .segment = REAL_SEGMENT(address), 1319292f776SCyrill Gorcunov .offset = REAL_OFFSET(address), 1329292f776SCyrill Gorcunov }; 1339292f776SCyrill Gorcunov interrupt_table__setup(&kvm->interrupt_table, &intr_desc); 1349292f776SCyrill Gorcunov 135ca82361eSPekka Enberg for (i = 0; i < ARRAY_SIZE(bios_irq_handlers); i++) 136ca82361eSPekka Enberg setup_irq_handler(kvm, &bios_irq_handlers[i]); 1379292f776SCyrill Gorcunov 13828ce0d66SCyrill Gorcunov /* we almost done */ 1399292f776SCyrill Gorcunov p = guest_flat_to_host(kvm, 0); 1409292f776SCyrill Gorcunov interrupt_table__copy(&kvm->interrupt_table, p, REAL_INTR_SIZE); 1419292f776SCyrill Gorcunov } 142