64 Bit Higher Half

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
mmk
Posts: 8
Joined: Mon Aug 24, 2015 6:42 am

64 Bit Higher Half

Post by mmk »

I have created a bootstrap portion that initializes paging and long mode: identity mapping (2MB) and mapping virtual address 0xffff800000000000 -> 0x0 (2MB of mapping)
However, when I try to call kernel_main I get a triple fault (as no IDT is in place at the moment, and everything prior to seems okay) with the following from Bochs:

00150944080e[CPU0 ] interrupt(long mode): vector must be within IDT table limits, IDT.limit = 0x0
00150944080e[CPU0 ] interrupt(long mode): vector must be within IDT table limits, IDT.limit = 0x0
00150944080i[CPU0 ] CPU is in long mode (active)
00150944080i[CPU0 ] CS.mode = 64 bit
00150944080i[CPU0 ] SS.mode = 64 bit
00150944080i[CPU0 ] EFER = 0x00000500
00150944080i[CPU0 ] | RAX=000000b8e5894855 RBX=0000000000010000
00150944080i[CPU0 ] | RCX=00000000c0000080 RDX=0000000000000000
00150944080i[CPU0 ] | RSP=000000000007fef8 RBP=0000000000000000
00150944080i[CPU0 ] | RSI=0000000000000000 RDI=0000000000000000
00150944080i[CPU0 ] | R8=0000000000000000 R9=0000000000000000
00150944080i[CPU0 ] | R10=0000000000000000 R11=0000000000000000
00150944080i[CPU0 ] | R12=0000000000000000 R13=0000000000000000
00150944080i[CPU0 ] | R14=0000000000000000 R15=0000000000000000
00150944080i[CPU0 ] | IOPL=0 ID vip vif ac vm RF nt of df if tf SF zf af PF cf
00150944080i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00150944080i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 00000000 0 0
00150944080i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 00000000 0 0
00150944080i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 00000000 0 0
00150944080i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 00000000 0 0
00150944080i[CPU0 ] | FS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00150944080i[CPU0 ] | GS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00150944080i[CPU0 ] | MSR_FS_BASE:0000000000000000
00150944080i[CPU0 ] | MSR_GS_BASE:0000000000000000
00150944080i[CPU0 ] | RIP=000000b8e5894855 (000000b8e5894855)
00150944080i[CPU0 ] | CR0=0xe0000011 CR2=0x000000b8e5894855
00150944080i[CPU0 ] | CR3=0x00101000 CR4=0x00000020
00150944080e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00150944080i[SYS ] bx_pc_system_c::Reset(HARDWARE) called
00150944080i[CPU0 ] cpu hardware reset
00150944080i[APIC0 ] allocate APIC id=0 (MMIO enabled) to 0x0000fee00000

My bootstrap code:

Code: Select all

[BITS 32]

MBALIGN     equ  1<<0                   ; align loaded modules on page boundaries
MEMINFO     equ  1<<1                   ; provide memory map
FLAGS       equ  MBALIGN | MEMINFO      ; this is the Multiboot 'flag' field
MAGIC       equ  0x1BADB002             ; 'magic number' lets bootloader find the header
CHECKSUM    equ -(MAGIC + FLAGS)        ; checksum of above, to prove we are multiboot

; Multiboot Header
section .multiboot
align 4
	dd MAGIC
	dd FLAGS
	dd CHECKSUM

section .bootstrap
global entry32
entry32:

; With all that multiboot stuff out of the way...
; It's time to do some 32-bit -> 64-bit stuff

; Paging Structures (4 KiB pages, PAE)

align 4096
pml4_table:
	times 4096 db 0
pdpt1_table:
	times 4096 db 0
pd1_table:
	times 4096 db 0
pt1_table:
	times 4096 db 0
pdpt2_table:
	times 4096 db 0
pd2_table:
	times 4096 db 0
pt2_table:
	times 4096 db 0

; Setup Identity Mapping

mov eax, pdpt1_table
or eax, 0b11 ; present + writable
mov [pml4_table], eax

mov eax, pd1_table
or eax, 0b11 ; present + writable
mov [pdpt1_table], eax

mov eax, pt1_table
or eax, 0b11 ; present + writable
mov [pd1_table], eax

mov ecx, 0

.map_pt1_table:
	mov eax, 0x1000
	mul ecx

	or eax, 0b11 ; present + writable
	mov [pt1_table + ecx * 8], eax

	inc ecx
	cmp ecx, 512
	jne .map_pt1_table

; Map 0xffff800000000000 -> 0x0000000000000000

mov eax, pdpt2_table
or eax, 0b11 ; present + writable
mov [pml4_table + 256 * 8], eax

mov eax, pd2_table
or eax, 0b11 ; present + writable
mov [pdpt2_table], eax

mov eax, pt2_table
or eax, 0b11 ; present + writable
mov [pd2_table], eax

mov ecx, 0

.map_pt2_table:
	mov eax, 0x1000
	mul ecx

	or eax, 0b11 ; present + writable
	mov [pt2_table + ecx * 8], eax

	inc ecx
	cmp ecx, 512
	jne .map_pt2_table

; Enable Paging
enable_paging:

mov eax, pml4_table
mov cr3, eax

; Set PAE bit

mov eax, cr4
or eax, 1 << 5
mov cr4, eax

; Set Long Mode Bit
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
wrmsr

mov eax, cr0
or eax, 1 << 31
mov cr0, eax

; 64-bit GDT

; Load GDT
lgdt [gdt64.ptr]
jmp gdt64.code:entry64

gdt64:
    dq 0 ; zero entry
.code: equ $ - gdt64 ; new
    dq (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53) ; code segment
.data: equ $ - gdt64 ; new
    dq (1<<44) | (1<<47) | (1<<41) ; data segment
.ptr:
	dw $ - gdt64 - 1
	dq gdt64


[BITS 64]
entry64:
	mov ax, gdt64.data
	mov ss, ax
	mov ds, ax
	mov es, ax

	mov rsp, stack_top
	extern kernel_main

	mov rax, [qword kernel_main]
	jmp rax

	cli
	hlt

; Stack
section .my_stack, nobits
align 4
stack_bottom:
resb 16384
stack_top:

And my linker script:

Code: Select all

ENTRY(entry32)

SECTIONS
{
	. = 1M;
	KERNEL_VMA = 0xffff800000000000;

	.multiboot ALIGN(4K):
	{
		*(.multiboot)
	}

	.bootstrap ALIGN(4K):
	{
		arch/x86_64/boot/entry32.o (.text)
	}

	. += KERNEL_VMA;

	.text ALIGN(4K): AT(ADDR(.text) - KERNEL_VMA)
	{
		*(EXCLUDE_FILE(*arch/x86_64/boot/entry64.o) .text)
		*(.rodata*)
	}

	.data ALIGN(4K): AT(ADDR(.data) - KERNEL_VMA)
	{
		*(.data)
	}

	.bss ALIGN(4K): AT(ADDR(.bss) - KERNEL_VMA)
	{
		*(COMMON)
		*(.bss)
		*(.my_stack)
	}

	.eh_frame ALIGN(4K): AT(ADDR(.eh_frame) - KERNEL_VMA)
	{
		*(.eh_frame)
	}
}
MDenham
Member
Member
Posts: 62
Joined: Sat Nov 10, 2012 1:16 pm

Re: 64 Bit Higher Half

Post by MDenham »

My psychic powers of debugging tell me that you're getting an IRQ after entering protected mode.
User avatar
xenos
Member
Member
Posts: 1121
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: 64 Bit Higher Half

Post by xenos »

The Bochs log tells me that RAX contains bogus and this is not where you want to jump. And the assembly tells me that you are moving the value stored at kernel_main into RAX, but you should move the address kernel_main in there. (I'm not very familiar with NASM syntax, though.)
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
mariuszp
Member
Member
Posts: 587
Joined: Sat Oct 16, 2010 3:38 pm

Re: 64 Bit Higher Half

Post by mariuszp »

This:

Code: Select all

   mov rax, [qword kernel_main]
   jmp rax
is wrong for multiple reasons. Firstly, as XenOS already said, you're loading the 64-bit value at [kernel_main] into RAX, not the address of kernel_main. You meant:

Code: Select all

mov rax, kernel_main
jmp rax
Secondly, "[qword x]" is never valid. You can't have an immediate 64-bit address.
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: 64 Bit Higher Half

Post by Octocontrabass »

mariuszp wrote:Secondly, "[qword x]" is never valid. You can't have an immediate 64-bit address.
It is valid, but only when moving to/from AL, AX, EAX, or RAX. (Opcodes 0xA0, 0xA1, 0xA2, and 0xA3.)
mmk
Posts: 8
Joined: Mon Aug 24, 2015 6:42 am

Re: 64 Bit Higher Half

Post by mmk »

Changing to this:

Code: Select all

mov rax, kernel_main
jmp rax
fixed the issue. I also forgot to have a cli/hlt in kernel_main, so I still got a triple fault
(since it started executing random stuff after it finished with whatever was in kernel_main), but that has been fixed as well.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: 64 Bit Higher Half

Post by Combuster »

You might also want to avoid executing your empty page tables.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply