19292f776SCyrill Gorcunov #include "kvm/kvm.h" 2b3594ec7SCyrill Gorcunov #include "kvm/boot-protocol.h" 3b3594ec7SCyrill Gorcunov #include "kvm/e820.h" 49292f776SCyrill Gorcunov #include "kvm/interrupt.h" 59292f776SCyrill Gorcunov #include "kvm/util.h" 69292f776SCyrill Gorcunov 79292f776SCyrill Gorcunov #include <string.h> 88cb0027cSSasha Levin #include <asm/e820.h> 99292f776SCyrill Gorcunov 1028ce0d66SCyrill Gorcunov #include "bios/bios-rom.h" 1128ce0d66SCyrill Gorcunov 12ca82361eSPekka Enberg struct irq_handler { 13ca82361eSPekka Enberg unsigned long address; 14ca82361eSPekka Enberg unsigned int irq; 15ca82361eSPekka Enberg void *handler; 16ca82361eSPekka Enberg size_t size; 179292f776SCyrill Gorcunov }; 189292f776SCyrill Gorcunov 1906e80d53SCyrill Gorcunov #define BIOS_IRQ_PA_ADDR(name) (MB_BIOS_BEGIN + BIOS_OFFSET__##name) 2028ce0d66SCyrill Gorcunov #define BIOS_IRQ_FUNC(name) ((char *)&bios_rom[BIOS_OFFSET__##name]) 2128ce0d66SCyrill Gorcunov #define BIOS_IRQ_SIZE(name) (BIOS_ENTRY_SIZE(BIOS_OFFSET__##name)) 2228ce0d66SCyrill Gorcunov 23ca82361eSPekka Enberg #define DEFINE_BIOS_IRQ_HANDLER(_irq, _handler) \ 24ca82361eSPekka Enberg { \ 25ca82361eSPekka Enberg .irq = _irq, \ 2606e80d53SCyrill Gorcunov .address = BIOS_IRQ_PA_ADDR(_handler), \ 27ca82361eSPekka Enberg .handler = BIOS_IRQ_FUNC(_handler), \ 28ca82361eSPekka Enberg .size = BIOS_IRQ_SIZE(_handler), \ 29ca82361eSPekka Enberg } 30ca82361eSPekka Enberg 31ca82361eSPekka Enberg static struct irq_handler bios_irq_handlers[] = { 32ca82361eSPekka Enberg DEFINE_BIOS_IRQ_HANDLER(0x10, bios_int10), 33ca82361eSPekka Enberg DEFINE_BIOS_IRQ_HANDLER(0x15, bios_int15), 34ca82361eSPekka Enberg }; 35ca82361eSPekka Enberg 36ca82361eSPekka Enberg static void setup_irq_handler(struct kvm *kvm, struct irq_handler *handler) 37ca82361eSPekka Enberg { 38ca82361eSPekka Enberg struct real_intr_desc intr_desc; 39ca82361eSPekka Enberg void *p; 40ca82361eSPekka Enberg 41ca82361eSPekka Enberg p = guest_flat_to_host(kvm, handler->address); 42ca82361eSPekka Enberg memcpy(p, handler->handler, handler->size); 43ca82361eSPekka Enberg 44ca82361eSPekka Enberg intr_desc = (struct real_intr_desc) { 4506e80d53SCyrill Gorcunov .segment = REAL_SEGMENT(MB_BIOS_BEGIN), 4606e80d53SCyrill Gorcunov .offset = handler->address - MB_BIOS_BEGIN, 47ca82361eSPekka Enberg }; 48ca82361eSPekka Enberg 493a60be06SSasha Levin DIE_IF((handler->address - MB_BIOS_BEGIN) > 0xffffUL); 5006e80d53SCyrill Gorcunov 51ca82361eSPekka Enberg interrupt_table__set(&kvm->interrupt_table, &intr_desc, handler->irq); 52ca82361eSPekka Enberg } 53ca82361eSPekka Enberg 54b3594ec7SCyrill Gorcunov /** 55b3594ec7SCyrill Gorcunov * e820_setup - setup some simple E820 memory map 56b3594ec7SCyrill Gorcunov * @kvm - guest system descriptor 57b3594ec7SCyrill Gorcunov */ 58b3594ec7SCyrill Gorcunov static void e820_setup(struct kvm *kvm) 59b3594ec7SCyrill Gorcunov { 608cb0027cSSasha Levin struct e820map *e820; 618cb0027cSSasha Levin struct e820entry *mem_map; 62b3594ec7SCyrill Gorcunov unsigned int i = 0; 63b3594ec7SCyrill Gorcunov 648cb0027cSSasha Levin e820 = guest_flat_to_host(kvm, E820_MAP_START); 658cb0027cSSasha Levin mem_map = e820->map; 66b3594ec7SCyrill Gorcunov 678cb0027cSSasha Levin mem_map[i++] = (struct e820entry) { 68b3594ec7SCyrill Gorcunov .addr = REAL_MODE_IVT_BEGIN, 69b3594ec7SCyrill Gorcunov .size = EBDA_START - REAL_MODE_IVT_BEGIN, 708cb0027cSSasha Levin .type = E820_RAM, 71b3594ec7SCyrill Gorcunov }; 728cb0027cSSasha Levin mem_map[i++] = (struct e820entry) { 73b3594ec7SCyrill Gorcunov .addr = EBDA_START, 74b3594ec7SCyrill Gorcunov .size = VGA_RAM_BEGIN - EBDA_START, 758cb0027cSSasha Levin .type = E820_RESERVED, 76b3594ec7SCyrill Gorcunov }; 778cb0027cSSasha Levin mem_map[i++] = (struct e820entry) { 78b3594ec7SCyrill Gorcunov .addr = MB_BIOS_BEGIN, 79b3594ec7SCyrill Gorcunov .size = MB_BIOS_END - MB_BIOS_BEGIN, 808cb0027cSSasha Levin .type = E820_RESERVED, 81b3594ec7SCyrill Gorcunov }; 82874467f8SSasha Levin if (kvm->ram_size < KVM_32BIT_GAP_START) { 838cb0027cSSasha Levin mem_map[i++] = (struct e820entry) { 84b3594ec7SCyrill Gorcunov .addr = BZ_KERNEL_START, 85b3594ec7SCyrill Gorcunov .size = kvm->ram_size - BZ_KERNEL_START, 868cb0027cSSasha Levin .type = E820_RAM, 87b3594ec7SCyrill Gorcunov }; 88874467f8SSasha Levin } else { 898cb0027cSSasha Levin mem_map[i++] = (struct e820entry) { 90874467f8SSasha Levin .addr = BZ_KERNEL_START, 91874467f8SSasha Levin .size = KVM_32BIT_GAP_START - BZ_KERNEL_START, 928cb0027cSSasha Levin .type = E820_RAM, 93874467f8SSasha Levin }; 948cb0027cSSasha Levin mem_map[i++] = (struct e820entry) { 95*f7abc4cdSHongyong Zang .addr = KVM_32BIT_MAX_MEM_SIZE, 96*f7abc4cdSHongyong Zang .size = kvm->ram_size - KVM_32BIT_MAX_MEM_SIZE, 978cb0027cSSasha Levin .type = E820_RAM, 98874467f8SSasha Levin }; 99874467f8SSasha Levin } 100b3594ec7SCyrill Gorcunov 101a2857479SCyrill Gorcunov BUG_ON(i > E820_X_MAX); 102874467f8SSasha Levin 1038cb0027cSSasha Levin e820->nr_map = i; 104b3594ec7SCyrill Gorcunov } 105b3594ec7SCyrill Gorcunov 10655290abcSCyrill Gorcunov static void setup_vga_rom(struct kvm *kvm) 10755290abcSCyrill Gorcunov { 10855290abcSCyrill Gorcunov u16 *mode; 10955290abcSCyrill Gorcunov void *p; 11055290abcSCyrill Gorcunov 11155290abcSCyrill Gorcunov p = guest_flat_to_host(kvm, VGA_ROM_OEM_STRING); 11255290abcSCyrill Gorcunov memset(p, 0, VGA_ROM_OEM_STRING_SIZE); 11355290abcSCyrill Gorcunov strncpy(p, "KVM VESA", VGA_ROM_OEM_STRING_SIZE); 11455290abcSCyrill Gorcunov 11555290abcSCyrill Gorcunov mode = guest_flat_to_host(kvm, VGA_ROM_MODES); 11655290abcSCyrill Gorcunov mode[0] = 0x0112; 11755290abcSCyrill Gorcunov mode[1] = 0xffff; 11855290abcSCyrill Gorcunov } 11955290abcSCyrill Gorcunov 120b3594ec7SCyrill Gorcunov /** 121b3594ec7SCyrill Gorcunov * setup_bios - inject BIOS into guest memory 122b3594ec7SCyrill Gorcunov * @kvm - guest system descriptor 123b3594ec7SCyrill Gorcunov */ 1249292f776SCyrill Gorcunov void setup_bios(struct kvm *kvm) 1259292f776SCyrill Gorcunov { 1269292f776SCyrill Gorcunov unsigned long address = MB_BIOS_BEGIN; 1279292f776SCyrill Gorcunov struct real_intr_desc intr_desc; 128ca82361eSPekka Enberg unsigned int i; 1299292f776SCyrill Gorcunov void *p; 1309292f776SCyrill Gorcunov 13115c2b0a0SCyrill Gorcunov /* 13215c2b0a0SCyrill Gorcunov * before anything else -- clean some known areas 13315c2b0a0SCyrill Gorcunov * we definitely don't want any trash here 13415c2b0a0SCyrill Gorcunov */ 13515c2b0a0SCyrill Gorcunov p = guest_flat_to_host(kvm, BDA_START); 13615c2b0a0SCyrill Gorcunov memset(p, 0, BDA_END - BDA_START); 13715c2b0a0SCyrill Gorcunov 13815c2b0a0SCyrill Gorcunov p = guest_flat_to_host(kvm, EBDA_START); 13915c2b0a0SCyrill Gorcunov memset(p, 0, EBDA_END - EBDA_START); 14015c2b0a0SCyrill Gorcunov 14115c2b0a0SCyrill Gorcunov p = guest_flat_to_host(kvm, MB_BIOS_BEGIN); 14215c2b0a0SCyrill Gorcunov memset(p, 0, MB_BIOS_END - MB_BIOS_BEGIN); 14315c2b0a0SCyrill Gorcunov 14415c2b0a0SCyrill Gorcunov p = guest_flat_to_host(kvm, VGA_ROM_BEGIN); 14515c2b0a0SCyrill Gorcunov memset(p, 0, VGA_ROM_END - VGA_ROM_BEGIN); 14615c2b0a0SCyrill Gorcunov 14728ce0d66SCyrill Gorcunov /* just copy the bios rom into the place */ 14828ce0d66SCyrill Gorcunov p = guest_flat_to_host(kvm, MB_BIOS_BEGIN); 14928ce0d66SCyrill Gorcunov memcpy(p, bios_rom, bios_rom_size); 15028ce0d66SCyrill Gorcunov 151b3594ec7SCyrill Gorcunov /* E820 memory map must be present */ 152b3594ec7SCyrill Gorcunov e820_setup(kvm); 153b3594ec7SCyrill Gorcunov 15455290abcSCyrill Gorcunov /* VESA needs own tricks */ 15555290abcSCyrill Gorcunov setup_vga_rom(kvm); 15655290abcSCyrill Gorcunov 1579292f776SCyrill Gorcunov /* 1589292f776SCyrill Gorcunov * Setup a *fake* real mode vector table, it has only 159e85eb87eSXiaochen Wang * one real handler which does just iret 1609292f776SCyrill Gorcunov */ 16106e80d53SCyrill Gorcunov address = BIOS_IRQ_PA_ADDR(bios_intfake); 1629292f776SCyrill Gorcunov intr_desc = (struct real_intr_desc) { 16306e80d53SCyrill Gorcunov .segment = REAL_SEGMENT(MB_BIOS_BEGIN), 16406e80d53SCyrill Gorcunov .offset = address - MB_BIOS_BEGIN, 1659292f776SCyrill Gorcunov }; 1669292f776SCyrill Gorcunov interrupt_table__setup(&kvm->interrupt_table, &intr_desc); 1679292f776SCyrill Gorcunov 168ca82361eSPekka Enberg for (i = 0; i < ARRAY_SIZE(bios_irq_handlers); i++) 169ca82361eSPekka Enberg setup_irq_handler(kvm, &bios_irq_handlers[i]); 1709292f776SCyrill Gorcunov 17128ce0d66SCyrill Gorcunov /* we almost done */ 1729292f776SCyrill Gorcunov p = guest_flat_to_host(kvm, 0); 1739292f776SCyrill Gorcunov interrupt_table__copy(&kvm->interrupt_table, p, REAL_INTR_SIZE); 1749292f776SCyrill Gorcunov } 175