I have searched the past three days, read wiki and intel documentation, but I can simply not figure it out.
So what i'm basically trying to achieve is to setup the IDT and PIC such that I can read a keystroke like I do when I boot my system with BIOS.
I have used more or less the same code from my BIOS version which works.
But no matter what I try when I'm coming from UEFI I cannot get the pieces together.
I have attached the code at the bottom, I'm hoping its not too long, but I guess it is more clear what I'm trying to do.
From UEFI I have used BS->AllocatePool with memory type "EfiRuntimeServicesCode" to allocate a buffer where I can load my test "kernel".
I make sure that the buffer is 4k aligned because I later remap this address to virtual address 0, such that I can compile my test kernel and not worry about where it is placed in memory.
(I know I can use AllocatePage in UEFI but no matter what I try I get an error from the function, maybe I should make another post for this? )
When I have remapped my buffer to virtual address 0 I try to setup GDT and later IDT.
I have placed comments in the code, I guess it explains my situation better then I can do here.
I hope my code is readable, my point is clear and really hope someone can point my in a direction?
Code: Select all
%define CODE_SEG 0x0008
%define DATA_SEG 0x0010
BITS 64
push r8 ; Contain the frame buffer addr, register value set in UEFI
push r9 ; Contain the addr of the buffer where this code is located, register value set in UEFI
; ... CODE THAT REMAP THE PYSICAL ADDR IN R9 TO VIRTUAL ADDR 0 ... ; Works
pop r9
pop r8
cli
; What I want here, is to load my own GDT and set CS to point to the record 0x08 in the GDT
; Not working :(
; By my searching this is the conclusion on how the code should look?
;lgdt [GDT]
;push QWORD 0x08
;push QWORD white
;retfq
jmp white ; Regular jmp works (just to confirm that the remapping is working).
hlt
white:
; Write 4 white pixels to screen, to see we have reached this part.
mov DWORD [r8], 0x00FFFFFF
add r8, 4
mov DWORD [r8], 0x00FFFFFF
add r8, 4
mov DWORD [r8], 0x00FFFFFF
add r8, 4
mov DWORD [r8], 0x00FFFFFF
lidt [IDT]
; Enable Keyboard only
mov al, 0xfd
out 0x21, al
mov al, 0xff
out 0xa1, al
;sti ; Under current conditions if sti is set then System reboots
; But I guess that the problem is the GDT is not set correctly
kernel_loop:
nop
hlt ; Make a loop to get keyboard interrupt
jmp kernel_loop
cli
hlt
; Global Descriptor Table
GDT:
.Null:
dq 0x0000000000000000 ; Null Descriptor - should be present.
.Code:
dw 0xffff ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10011010b ; Access (exec/read).
db 10101111b ; Granularity, 64 bits flag, limit19:16.
db 0 ; Base (high).
.Data
dw 0xffff ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10010010b ; Access (read/write).
db 00001111b ; Granularity.
db 0 ; Base (high).
ALIGN 4
dw 0 ; Padding to make the "address of the GDT" field aligned on a 4-byte boundary
.Pointer:
dw $ - GDT - 1 ; 16-bit Size (Limit) of GDT.
dw GDT ; 32-bit Base Address of GDT. (CPU will zero extend to 64-bit)
ALIGN 8
IDT_table:
; Entry 0x00: Division by Zero
dw div_by_zero;
dw 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
db 0 ; OBS bits 0..2 holds Interrupt Stack Table offset, rest of bits zero
db 0x8e; /* INTERRUPT_GATE */
dw 0; offset bits 16..31
dd 0 ; offset bits 32..63
dd 0 ; reserved
; Entry 0x01:
times 16 db 0
; Entry 0x02:
times 16 db 0
; Entry 0x03:
times 16 db 0
; Entry 0x04:
times 16 db 0
; Entry 0x05:
times 16 db 0
; Entry 0x06:
times 16 db 0
; Entry 0x07:
times 16 db 0
; Entry 0x08: Double fault
dw general_protection_fault ; using this routine as stub
dw 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
db 0 ; OBS bits 0..2 holds Interrupt Stack Table offset, rest of bits zero
db 0x8e; /* INTERRUPT_GATE */
dw 0; offset bits 16..31
dd 0 ; offset bits 32..63
dd 0 ; reserved
; Entry 0x09:
times 16 db 0
; Entry 0x0A:
times 16 db 0
; Entry 0x0B:
times 16 db 0
; Entry 0x0C: Stack fault
dw general_protection_fault ; using this rutine as stub
dw 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
db 0 ; OBS bits 0..2 holds Interrupt Stack Table offset, rest of bits zero
db 0x8e; /* INTERRUPT_GATE */
dw 0; offset bits 16..31
dd 0 ; offset bits 32..63
dd 0 ; reserved
; Entry 0x0D: General protection fault
dw general_protection_fault;
dw 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
db 0 ; OBS bits 0..2 holds Interrupt Stack Table offset, rest of bits zero
db 0x8e; /* INTERRUPT_GATE */
dw 0; offset bits 16..31
dd 0 ; offset bits 32..63
dd 0 ; reserved
; Entry 0x0E: page fault
dw page_fault;
dw 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
db 0 ; OBS bits 0..2 holds Interrupt Stack Table offset, rest of bits zero
db 0x8e; /* INTERRUPT_GATE */
dw 0; offset bits 16..31
dd 0 ; offset bits 32..63
dd 0 ; reserved
; Entry 0x0F:
times 16 db 0
; Entry 0x10:
times 16 db 0
; Entry 0x11:
times 16 db 0
; Entry 0x12:
times 16 db 0
; Entry 0x13:
times 16 db 0
; Entry 0x14:
times 16 db 0
; Entry 0x15:
times 16 db 0
; Entry 0x16:
times 16 db 0
; Entry 0x17:
times 16 db 0
; Entry 0x18:
times 16 db 0
; Entry 0x19:
times 16 db 0
; Entry 0x1A:
times 16 db 0
; Entry 0x1B:
times 16 db 0
; Entry 0x1C:
times 16 db 0
; Entry 0x1D:
times 16 db 0
; Entry 0x1E:
times 16 db 0
; Entry 0x1F:
times 16 db 0
; Now we go on with our own:
; Entry 0x20:
dw irq0;
dw 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
db 0 ; OBS bits 0..2 holds Interrupt Stack Table offset, rest of bits zero
db 0x8e; /* INTERRUPT_GATE */
dw 0; offset bits 16..31
dd 0 ; offset bits 32..63
dd 0 ; reserved
; Entry 0x21:
dw irq1;
dw 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
db 0 ; OBS bits 0..2 holds Interrupt Stack Table offset, rest of bits zero
db 0x8e; /* INTERRUPT_GATE */
dw 0; offset bits 16..31
dd 0 ; offset bits 32..63
dd 0 ; reserved
IDT:
.Length dw $ - IDT_table - 1
.Base dq IDT_table
div_by_zero:
;mov rsi, .div_by_zero_string
;call print
add QWORD [rsp], 2
iretq
cli
hlt
.div_by_zero_string db "Division by zero detected", 0
general_protection_fault:
;mov rsi, .div_by_zero_string
;call print
cli
hlt
iretq
.general_protection_fault_string db "General protection fault: ", 0
page_fault:
;mov rsi, .div_by_zero_string
;call print
cli
hlt
iretq
.page_fault_string db "Normal page fault: ", 0
irq0:
mov al, 0x20
out 0x20, al
iretq
irq1:
.read_port:
xor rax, rax
mov dx, 0x60 ; the keyboard controller
in al, dx
.ack
mov al, 0x20
out 0x20, al
; Write another white pixel to the screen, to see that we have got the IRQ correct.
add r8, 4
mov DWORD [r8], 0x00FFFFFF
iretq