| /* |
| * Our pretty trivial BIOS emulation |
| */ |
| |
| #include <kvm/bios.h> |
| #include <kvm/assembly.h> |
| |
| .org 0 |
| .code16gcc |
| |
| #define EFLAGS_CF (1 << 0) |
| |
| #include "macro.S" |
| |
| /* If you change these macros, remember to update 'struct biosregs' */ |
| .macro SAVE_BIOSREGS |
| pushl %fs |
| pushl %es |
| pushl %ds |
| pushl %edi |
| pushl %esi |
| pushl %ebp |
| pushl %esp |
| pushl %edx |
| pushl %ecx |
| pushl %ebx |
| pushl %eax |
| .endm |
| |
| .macro RESTORE_BIOSREGS |
| popl %eax |
| popl %ebx |
| popl %ecx |
| popl %edx |
| popl %esp |
| popl %ebp |
| popl %esi |
| popl %edi |
| popl %ds |
| popl %es |
| popl %fs |
| .endm |
| |
| /* |
| * fake interrupt handler, nothing can be faster ever |
| */ |
| ENTRY(bios_intfake) |
| /* |
| * Set CF to indicate failure. We don't want callers to think that the |
| * interrupt handler succeeded and then treat the return values in |
| * registers as valid data. |
| */ |
| orl $EFLAGS_CF, 0x4(%esp) |
| |
| IRET |
| ENTRY_END(bios_intfake) |
| |
| /* |
| * int 10 - video - service |
| */ |
| ENTRY(bios_int10) |
| SAVE_BIOSREGS |
| |
| movl %esp, %eax |
| /* this is way easier than doing it in assembly */ |
| /* just push all the regs and jump to a C handler */ |
| call int10_handler |
| |
| RESTORE_BIOSREGS |
| |
| /* Clear CF to indicate success. */ |
| andl $~EFLAGS_CF, 0x4(%esp) |
| |
| IRET |
| ENTRY_END(bios_int10) |
| |
| ENTRY(bios_int15) |
| SAVE_BIOSREGS |
| |
| movl %esp, %eax |
| call int15_handler |
| |
| RESTORE_BIOSREGS |
| |
| IRET |
| ENTRY_END(bios_int15) |
| |
| GLOBAL(__locals) |
| |
| #include "local.S" |
| |
| END(__locals) |
| |
| /* |
| * Add this section to ensure final binary has a non-executable stack. |
| */ |
| .section .note.GNU-stack,"",@progbits |