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 9*ca82361eSPekka Enberg struct irq_handler { 10*ca82361eSPekka Enberg unsigned long address; 11*ca82361eSPekka Enberg unsigned int irq; 12*ca82361eSPekka Enberg void *handler; 13*ca82361eSPekka 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 20*ca82361eSPekka Enberg #define DEFINE_BIOS_IRQ_HANDLER(_irq, _handler) \ 21*ca82361eSPekka Enberg { \ 22*ca82361eSPekka Enberg .irq = _irq, \ 23*ca82361eSPekka Enberg .address = BIOS_IRQ_ADDR(_handler), \ 24*ca82361eSPekka Enberg .handler = BIOS_IRQ_FUNC(_handler), \ 25*ca82361eSPekka Enberg .size = BIOS_IRQ_SIZE(_handler), \ 26*ca82361eSPekka Enberg } 27*ca82361eSPekka Enberg 28*ca82361eSPekka Enberg static struct irq_handler bios_irq_handlers[] = { 29*ca82361eSPekka Enberg DEFINE_BIOS_IRQ_HANDLER(0x10, bios_int10), 30*ca82361eSPekka Enberg DEFINE_BIOS_IRQ_HANDLER(0x15, bios_int15), 31*ca82361eSPekka Enberg }; 32*ca82361eSPekka Enberg 33*ca82361eSPekka Enberg static void setup_irq_handler(struct kvm *kvm, struct irq_handler *handler) 34*ca82361eSPekka Enberg { 35*ca82361eSPekka Enberg struct real_intr_desc intr_desc; 36*ca82361eSPekka Enberg void *p; 37*ca82361eSPekka Enberg 38*ca82361eSPekka Enberg p = guest_flat_to_host(kvm, handler->address); 39*ca82361eSPekka Enberg memcpy(p, handler->handler, handler->size); 40*ca82361eSPekka Enberg 41*ca82361eSPekka Enberg intr_desc = (struct real_intr_desc) { 42*ca82361eSPekka Enberg .segment = REAL_SEGMENT(handler->address), 43*ca82361eSPekka Enberg .offset = REAL_OFFSET(handler->address), 44*ca82361eSPekka Enberg }; 45*ca82361eSPekka Enberg 46*ca82361eSPekka Enberg interrupt_table__set(&kvm->interrupt_table, &intr_desc, handler->irq); 47*ca82361eSPekka Enberg } 48*ca82361eSPekka 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; 53*ca82361eSPekka Enberg unsigned int i; 549292f776SCyrill Gorcunov void *p; 559292f776SCyrill Gorcunov 5628ce0d66SCyrill Gorcunov /* just copy the bios rom into the place */ 5728ce0d66SCyrill Gorcunov p = guest_flat_to_host(kvm, MB_BIOS_BEGIN); 5828ce0d66SCyrill Gorcunov memcpy(p, bios_rom, bios_rom_size); 5928ce0d66SCyrill Gorcunov 609292f776SCyrill Gorcunov /* 619292f776SCyrill Gorcunov * Setup a *fake* real mode vector table, it has only 629292f776SCyrill Gorcunov * one real hadler which does just iret 639292f776SCyrill Gorcunov */ 6428ce0d66SCyrill Gorcunov address = BIOS_IRQ_ADDR(bios_intfake); 659292f776SCyrill Gorcunov intr_desc = (struct real_intr_desc) { 669292f776SCyrill Gorcunov .segment = REAL_SEGMENT(address), 679292f776SCyrill Gorcunov .offset = REAL_OFFSET(address), 689292f776SCyrill Gorcunov }; 699292f776SCyrill Gorcunov interrupt_table__setup(&kvm->interrupt_table, &intr_desc); 709292f776SCyrill Gorcunov 71*ca82361eSPekka Enberg for (i = 0; i < ARRAY_SIZE(bios_irq_handlers); i++) 72*ca82361eSPekka Enberg setup_irq_handler(kvm, &bios_irq_handlers[i]); 739292f776SCyrill Gorcunov 7428ce0d66SCyrill Gorcunov /* we almost done */ 759292f776SCyrill Gorcunov p = guest_flat_to_host(kvm, 0); 769292f776SCyrill Gorcunov interrupt_table__copy(&kvm->interrupt_table, p, REAL_INTR_SIZE); 779292f776SCyrill Gorcunov } 78