19292f776SCyrill Gorcunov #include "kvm/kvm.h" 29292f776SCyrill Gorcunov #include "kvm/interrupt.h" 39292f776SCyrill Gorcunov #include "kvm/util.h" 49292f776SCyrill Gorcunov 59292f776SCyrill Gorcunov #include <string.h> 69292f776SCyrill Gorcunov 728ce0d66SCyrill Gorcunov #include "bios/bios-rom.h" 828ce0d66SCyrill Gorcunov 9ca82361eSPekka Enberg struct irq_handler { 10ca82361eSPekka Enberg unsigned long address; 11ca82361eSPekka Enberg unsigned int irq; 12ca82361eSPekka Enberg void *handler; 13ca82361eSPekka Enberg size_t size; 149292f776SCyrill Gorcunov }; 159292f776SCyrill Gorcunov 1628ce0d66SCyrill Gorcunov #define BIOS_IRQ_ADDR(name) (MB_BIOS_BEGIN + BIOS_OFFSET__##name) 1728ce0d66SCyrill Gorcunov #define BIOS_IRQ_FUNC(name) ((char *)&bios_rom[BIOS_OFFSET__##name]) 1828ce0d66SCyrill Gorcunov #define BIOS_IRQ_SIZE(name) (BIOS_ENTRY_SIZE(BIOS_OFFSET__##name)) 1928ce0d66SCyrill Gorcunov 20ca82361eSPekka Enberg #define DEFINE_BIOS_IRQ_HANDLER(_irq, _handler) \ 21ca82361eSPekka Enberg { \ 22ca82361eSPekka Enberg .irq = _irq, \ 23ca82361eSPekka Enberg .address = BIOS_IRQ_ADDR(_handler), \ 24ca82361eSPekka Enberg .handler = BIOS_IRQ_FUNC(_handler), \ 25ca82361eSPekka Enberg .size = BIOS_IRQ_SIZE(_handler), \ 26ca82361eSPekka Enberg } 27ca82361eSPekka Enberg 28ca82361eSPekka Enberg static struct irq_handler bios_irq_handlers[] = { 29ca82361eSPekka Enberg DEFINE_BIOS_IRQ_HANDLER(0x10, bios_int10), 30ca82361eSPekka Enberg DEFINE_BIOS_IRQ_HANDLER(0x15, bios_int15), 31ca82361eSPekka Enberg }; 32ca82361eSPekka Enberg 33ca82361eSPekka Enberg static void setup_irq_handler(struct kvm *kvm, struct irq_handler *handler) 34ca82361eSPekka Enberg { 35ca82361eSPekka Enberg struct real_intr_desc intr_desc; 36ca82361eSPekka Enberg void *p; 37ca82361eSPekka Enberg 38ca82361eSPekka Enberg p = guest_flat_to_host(kvm, handler->address); 39ca82361eSPekka Enberg memcpy(p, handler->handler, handler->size); 40ca82361eSPekka Enberg 41ca82361eSPekka Enberg intr_desc = (struct real_intr_desc) { 42ca82361eSPekka Enberg .segment = REAL_SEGMENT(handler->address), 43ca82361eSPekka Enberg .offset = REAL_OFFSET(handler->address), 44ca82361eSPekka Enberg }; 45ca82361eSPekka Enberg 46ca82361eSPekka Enberg interrupt_table__set(&kvm->interrupt_table, &intr_desc, handler->irq); 47ca82361eSPekka Enberg } 48ca82361eSPekka Enberg 499292f776SCyrill Gorcunov void setup_bios(struct kvm *kvm) 509292f776SCyrill Gorcunov { 519292f776SCyrill Gorcunov unsigned long address = MB_BIOS_BEGIN; 529292f776SCyrill Gorcunov struct real_intr_desc intr_desc; 53ca82361eSPekka Enberg unsigned int i; 549292f776SCyrill Gorcunov void *p; 559292f776SCyrill Gorcunov 56*15c2b0a0SCyrill Gorcunov /* 57*15c2b0a0SCyrill Gorcunov * before anything else -- clean some known areas 58*15c2b0a0SCyrill Gorcunov * we definitely don't want any trash here 59*15c2b0a0SCyrill Gorcunov */ 60*15c2b0a0SCyrill Gorcunov p = guest_flat_to_host(kvm, BDA_START); 61*15c2b0a0SCyrill Gorcunov memset(p, 0, BDA_END - BDA_START); 62*15c2b0a0SCyrill Gorcunov 63*15c2b0a0SCyrill Gorcunov p = guest_flat_to_host(kvm, EBDA_START); 64*15c2b0a0SCyrill Gorcunov memset(p, 0, EBDA_END - EBDA_START); 65*15c2b0a0SCyrill Gorcunov 66*15c2b0a0SCyrill Gorcunov p = guest_flat_to_host(kvm, MB_BIOS_BEGIN); 67*15c2b0a0SCyrill Gorcunov memset(p, 0, MB_BIOS_END - MB_BIOS_BEGIN); 68*15c2b0a0SCyrill Gorcunov 69*15c2b0a0SCyrill Gorcunov p = guest_flat_to_host(kvm, VGA_ROM_BEGIN); 70*15c2b0a0SCyrill Gorcunov memset(p, 0, VGA_ROM_END - VGA_ROM_BEGIN); 71*15c2b0a0SCyrill Gorcunov 7228ce0d66SCyrill Gorcunov /* just copy the bios rom into the place */ 7328ce0d66SCyrill Gorcunov p = guest_flat_to_host(kvm, MB_BIOS_BEGIN); 7428ce0d66SCyrill Gorcunov memcpy(p, bios_rom, bios_rom_size); 7528ce0d66SCyrill Gorcunov 769292f776SCyrill Gorcunov /* 779292f776SCyrill Gorcunov * Setup a *fake* real mode vector table, it has only 789292f776SCyrill Gorcunov * one real hadler which does just iret 799292f776SCyrill Gorcunov */ 8028ce0d66SCyrill Gorcunov address = BIOS_IRQ_ADDR(bios_intfake); 819292f776SCyrill Gorcunov intr_desc = (struct real_intr_desc) { 829292f776SCyrill Gorcunov .segment = REAL_SEGMENT(address), 839292f776SCyrill Gorcunov .offset = REAL_OFFSET(address), 849292f776SCyrill Gorcunov }; 859292f776SCyrill Gorcunov interrupt_table__setup(&kvm->interrupt_table, &intr_desc); 869292f776SCyrill Gorcunov 87ca82361eSPekka Enberg for (i = 0; i < ARRAY_SIZE(bios_irq_handlers); i++) 88ca82361eSPekka Enberg setup_irq_handler(kvm, &bios_irq_handlers[i]); 899292f776SCyrill Gorcunov 9028ce0d66SCyrill Gorcunov /* we almost done */ 919292f776SCyrill Gorcunov p = guest_flat_to_host(kvm, 0); 929292f776SCyrill Gorcunov interrupt_table__copy(&kvm->interrupt_table, p, REAL_INTR_SIZE); 939292f776SCyrill Gorcunov } 94