Page 2 of 2

Re: x64 Bootloader questions

Posted: Tue Apr 09, 2013 11:07 pm
by xenos
You don't need an IDT right now. The basic things you need to get into long mode are the GDT and the page tables, so let's keep it simple and focus on these two structures only. I had another look at your code and the page tables look more or less fine to me - however, I also found a problem with your code:

Code: Select all

org 0x200000
So your kernel starts at the 2MB mark.

Code: Select all

mov ebx, 0x00000003          ; Set the B-register to 0x00000003.
mov ecx, 512                 ; Set the C-register to 512.
.SetEntry:
mov DWORD [edi], ebx         ; Set the double word at the destination index to the B-register.
add ebx, 0x1000              ; Add 0x1000 to the B-register.
add edi, 8                   ; Add eight to the destination index.
loop .SetEntry               ; Set the next entry.
This identity maps the first 512 * 4k = 2MB. But your kernel is above 2MB and not mapped at all.

Re: x64 Bootloader questions

Posted: Wed Apr 10, 2013 9:37 pm
by PearOs
Thank you so much! Changing it from org 0x200000 to org 0x100000 worked like a charm! I have booted 64bit code! But now I have a problem. I went to do call somelabel and the CPU crashes with exception 13? Does that have something to do with Pages, IDT, or the GDT? Thanks, Matt :)

Re: x64 Bootloader questions

Posted: Thu Apr 11, 2013 1:59 am
by xenos
Well, 13 is the GPF - the error code should tell you what's wrong. If this happens in Bochs, you should also get some log output and can figure out where it crashes and why.

Re: x64 Bootloader questions

Posted: Thu Apr 11, 2013 2:40 pm
by PearOs
XenOS wrote:Well, 13 is the GPF - the error code should tell you what's wrong. If this happens in Bochs, you should also get some log output and can figure out where it crashes and why.
Thanks, I looked and found I just needed to add a valid GDT. Once I did that everything started to work again. Thanks, Matt

Re: x64 Bootloader questions

Posted: Thu Apr 11, 2013 10:33 pm
by PearOs
Hey guys, I have spent quite a few hours here trying to get interrupts working. But for some reason I get keeping the error in bochs:

Code: Select all

00005742028i[BIOS ] IDE time out
00017843905i[BIOS ] Booting from 07c0:0000
00017916169i[MEM0 ] allocate_block: block=0x1 used 0x3 of 0x20
00018521821e[CPU0 ] interrupt(long mode): not accessible or not code segment
00018521821e[CPU0 ] interrupt(long mode): not accessible or not code segment
00018521821e[CPU0 ] interrupt(long mode): not accessible or not code segment
00018521821i[CPU0 ] CPU is in long mode (active)
00018521821i[CPU0 ] CS.mode = 64 bit
00018521821i[CPU0 ] SS.mode = 64 bit
00018521821i[CPU0 ] EFER   = 0x00000500
00018521821i[CPU0 ] | RAX=00000000000b8000  RBX=000000000000002e
00018521821i[CPU0 ] | RCX=0000000000000000  RDX=00000000000000a1
00018521821i[CPU0 ] | RSP=0000000000008018  RBP=0000000000000000
00018521821i[CPU0 ] | RSI=0000000000000000  RDI=000000000010054c
00018521821i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00018521821i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00018521821i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00018521821i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00018521821i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df IF tf sf ZF af PF cf
00018521821i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00018521821i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 00000000 0 0
00018521821i[CPU0 ] |  DS:0000( 0000| 0|  0) 00000000 00000000 0 0
00018521821i[CPU0 ] |  SS:0000( 0000| 0|  0) 00000000 00000000 0 0
00018521821i[CPU0 ] |  ES:0000( 0000| 0|  0) 00000000 00000000 0 0
00018521821i[CPU0 ] |  FS:0000( 0000| 0|  0) 00000000 00000000 0 0
00018521821i[CPU0 ] |  GS:0000( 0000| 0|  0) 00000000 00000000 0 0
00018521821i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00018521821i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00018521821i[CPU0 ] | RIP=00000000001001c1 (00000000001001c1)
00018521821i[CPU0 ] | CR0=0xe0000011 CR2=0x0000000000000000
00018521821i[CPU0 ] | CR3=0x00001000 CR4=0x00000020
(0).[18521821] [0x0000001001c1] 0008:00000000001001c1 (unk. ctxt): jmp .-2 (0x00
000000001001c1) ; ebfe
00018521821e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown

My code for interrupts looks like this:

Code: Select all

align 16
GDTR64:					; Global Descriptors Table Register
	dw gdt64_end - gdt64 - 1	; limit of GDT (size minus one)
	dq 0x0000000000001000		; linear address of GDT

gdt64:					; This structure is copied to 0x0000000000001000
SYS64_NULL_SEL equ $-gdt64		; Null Segment
	dq 0x0000000000000000
SYS64_CODE_SEL equ $-gdt64		; Code segment, read/execute, nonconforming
	dq 0x0020980000000000		; 0x00209A0000000000
SYS64_DATA_SEL equ $-gdt64		; Data segment, read/write, expand down
	dq 0x0000900000000000		; 0x0020920000000000
gdt64_end:
IDTR64:					; Interrupt Descriptor Table Register
	dw 256*16-1			; limit of IDT (size minus one) (4096 bytes - 1)
	dq 0x0000000000000000		; linear address of IDT
IDTR64_Content: Times 4095 db 0

IDT_Setup:
mov qword[IDTR64+2], IDTR64_Content ;Set the IDT Pointer
;First clear interrupts.
cli ;Just to make sure.
;Set all the IDT Entrys! Well just the ones we will need for the
;ISR.
push 0
push isr0
call IDT_Set
push 1
push isr1
call IDT_Set
push 2
push isr2
call IDT_Set
push 3
push isr3
call IDT_Set
push 4
push isr4
call IDT_Set
push 5
push isr5
call IDT_Set
push 6
push isr6
call IDT_Set
push 7
push isr7
call IDT_Set
push 8
push isr8
call IDT_Set
push 9
push isr9
call IDT_Set
push 10
push isr10
call IDT_Set
push 11
push isr11
call IDT_Set
push 12
push isr12
call IDT_Set
push 13
push isr13
call IDT_Set
push 14
push isr14
call IDT_Set
push 15
push isr15
call IDT_Set
push 16
push isr16
call IDT_Set
push 17
push isr17
call IDT_Set
push 18
push isr18
call IDT_Set
push 19
push isr19
call IDT_Set
push 20
push isr20
call IDT_Set
push 21
push isr21
call IDT_Set
push 22
push isr22
call IDT_Set
push 23
push isr23
call IDT_Set
push 24
push isr24
call IDT_Set
push 25
push isr25
call IDT_Set
push 26
push isr26
call IDT_Set
push 27
push isr27
call IDT_Set
push 28
push isr28
call IDT_Set
push 29
push isr29
call IDT_Set
push 30
push isr30
call IDT_Set
push 31
push isr31
call IDT_Set      
;IRQs
;Must set the PIC though..
push 0x20
push 0x11
call IOPort_Write_8
push 0xA0
push 0x11
call IOPort_Write_8
push 0x21
push 0x20
call IOPort_Write_8
push 0xA1
push 0x28
call IOPort_Write_8
push 0x21
push 0x04
call IOPort_Write_8
push 0xA1
push 0x02
call IOPort_Write_8
push 0x21
push 0x01
call IOPort_Write_8
push 0xA1
push 0x01
call IOPort_Write_8
push 0x21
push 0x0
call IOPort_Write_8
push 0xA1
push 0x0
call IOPort_Write_8
;Now actually set the IRQs
push 32
push irq0
call IDT_Set  
push 33
push irq1
call IDT_Set
push 34
push irq3
call IDT_Set  
push 35
push irq4
call IDT_Set
push 36
push irq5
call IDT_Set
push 37
push irq6
call IDT_Set
push 38
push irq7
call IDT_Set
push 39
push irq8
call IDT_Set
push 40
push irq9
call IDT_Set
push 41
push irq10
call IDT_Set
push 42
push irq11
call IDT_Set
push 43
push irq12
call IDT_Set
push 44
push irq13
call IDT_Set
push 45
push irq14
call IDT_Set
push 46
push irq15
call IDT_Set
lidt[IDTR64] ;Load the IDT in.
sti
call Main



;Input:
; - (int) Index
; - (int) Address
;Description Sets an IDT Entry.
IDT_Set_Return: dq 0
IDT_Set:
pop qword[IDT_Set_Return] ;Save the return address
pop rax ;Address
pop rdi ;Index
shl rdi, 4 ;Multiply by 16
add rdi, IDTR64_Content
;Offset Low
push rax ;Save it
;and rax, 0x0000ffff
stosw
pop rax
;Selector
push rax
mov ax, 0x8
stosw
pop rax
;Type And Attributes and Zero
push rax
mov ax, 0x8E00
stosw
pop rax
;Offset High
push rax ;Save it
shr rax, 16
;and rax, 0x0000ffff
stosw
pop rax
;Offset High Extra
shr rax, 32
;and rax, 0xffffffff
stosd
;Reserved
mov rax, 0
stosd
push qword[IDT_Set_Return] ;Restore the return address
ret ;Return



My 64 bit kernel code:

Code: Select all

[BITS 64]
Kernel64:
cli                           ; Clear the interrupt flag.
xor rax, rax			; aka r0
xor rbx, rbx			; aka r3
xor rcx, rcx			; aka r1
xor rdx, rdx			; aka r2
xor rsi, rsi			; aka r6
xor rdi, rdi			; aka r7
xor rbp, rbp			; aka r5
mov rsp, 0x8000			; aka r4
xor r8, r8
xor r9, r9
xor r10, r10
xor r11, r11
xor r12, r12
xor r13, r13
xor r14, r14
xor r15, r15
mov ds, ax			; Clear the legacy segment registers
mov es, ax
mov ss, ax
mov fs, ax
mov gs, ax
;Now we want to create a stack for the Kernel
;mov rax, EndCode
;mov rbp, rax
;add rax, 4000
;mov rsp, rax
xor rax, rax
lgdt [GDTR64]			; Reload the GDT
call PIC_Setup
push 100
call PIT_Setup
jmp IDT_Setup

Main:
mov rax, 0xB8000
mov byte[rax], 'h'
jmp os_hang
I cannot figure out what's wrong, weather its the GDT, or the IDT. I would assume IDT but I used the Bochs debugger and no luck there. Thanks, Matt

Though my best hint, would be that there is something wrong with storing the entry address, I think that might be the problem but there really isn't any docs on storing that.

Re: x64 Bootloader questions

Posted: Thu Apr 11, 2013 11:05 pm
by PearOs
Went over my code, and found I had set the GDT to a address that wasn't where the GDT Content was located, so I changed that and Interrupts started working! Thanks guys, :D