[BITS 64] [ORG 0000000000200000h] %INCLUDE "bmdev.asm" start: ; Start of program label ; Set RTC rate to 2Hz mov rbx, 1111b call set_rtc_rate lea rax, [custom_interrupt_handler] ; Install new handler for RTC mov rcx, 28h lea rdx, [ORIGINAL_HANDLER] ; Save old handler address to ORIGINAL_HANDLER call install_interrupt_handler loop: xor rax, rax ; Check value of FLAG mov al, [FLAG] test al, al jz loop ; Loop while value is 0 mov byte [FLAG], 0 mov rsi, hello_message ; Load RSI with memory address of string call b_print_string ; Print the string that RSI points to mov rax, [ORIGINAL_HANDLER] ; Restore old handler mov rcx, 28h lea rdx, [ORIGINAL_HANDLER] call install_interrupt_handler ; Restore RTC rate mov rbx, [ORIGINAL_STATUSA] call set_rtc_rate ret ; Return to OS IDTR: times 10 db 0 ORIGINAL_HANDLER: times 8 db 0 ORIGINAL_STATUSA: db 0 ; Installs a new interrupt handler ; RCX interrupt ID (16 bit) ; RAX address of new handler ; RDX memory location to store address of old handler install_interrupt_handler: push rax ; Save rax push rbx ; Save rbx push rcx ; Save rcx cli ; Disable interrupts sidt [IDTR] ; Store value of IDTR to memory (2 + 8 bytes) lea rbx, [IDTR + 2] ; Select offset from IDTR mov rbx, [rbx] ; Read offset of IDT into RBX cmp rcx, 0FFFFh ; Skip installing handler if ID is out of range jge install_interrupt_handler cmp cx, word [IDTR] jge install_interrupt_handler shl rcx, 4 ; Address of IDT entry RCX (entry size is 16 bytes) lea rbx, [rbx + rcx] push rax ; Save the address of the new interrupt handler on the stack xor rax, rax ; Address of old interrupt handler mov eax, [rbx + 8] ; Load upper 32 bits of old interrupt handler from offset 8 shl rax, 32 mov ax, [rbx + 6] ; Load next 16 bits of old interrupt handler from offset 6 shl rax, 16 mov ax, [rbx] ; Load remaining 16 bits of old interrupt handler from offset 0 mov [rdx], rax ; Store address of old interrupt handler pop rax ; Address of new interrupt handler mov [rbx], ax ; Store lower 16 bits of new interrupt handler at offset 0 shr rax, 16 ; Store next 16 bits of new interrupt handler at offset 6 mov [rbx + 6], ax shr rax, 16 ; Store remaining 32 bits of new interrupt handler at offset 8 mov [rbx + 8], eax end_install_interrupt_handler: sti ; Enable interrupts pop rcx ; Restore rcx pop rbx ; Restore rbx pop rax ; Restore rax ret ; Set RTC trigger rate from 2Hz to 32kHz ; RBX lower 4 bit content of the Status Register (rate component) set_rtc_rate: push rax ; Save rax cli ; Disable interrupts mov al, 0Ah ; Select Status Register A out 70h, al in al, 71h ; Read current content mov [ORIGINAL_STATUSA], al and al, 0F0h ; Preserve upper 4 bits of AL and bl, 0Fh ; Clear upper 4 bits of BL or al, bl ; Set RTC rate bits from BL out 71h, al ; Write new content sti ; Enable interrupts pop rax ; Restore rax ret FLAG: db 0 hello_message: db 'Hello, world!', 13, 0 COUNT: db 0 custom_interrupt_handler: inc byte [COUNT] cmp byte [COUNT], 8 jne end_custom_interrupt_handler mov byte [FLAG], 1 end_custom_interrupt_handler: jmp [ORIGINAL_HANDLER]