org 0x7c00
BOOTDRIVE equ 0x9000
flatcode equ 0x0008
flatdata equ 0x0010
flatstack equ 0x0010
[bits 16]
section .text
bspstart:
xor ax,ax ;some BIOS required
mov ds,ax
mov byte [BOOTDRIVE],dl
mov ax,0x8000
mov ss,ax
mov sp,0
mov cx,2000 ;80x25*2
xor si,si
mov di,1
mov ax,0xb800
mov ds,ax
cleanscreen:
mov byte [ds:si],0x0
add si,2
mov byte [ds:di],0xf
add di,2
loop cleanscreen
xor ax,ax
mov ds,ax ;restore ax to load GDTR
Read_Disk_INT0x13: ;Read/Write Harddisk/Floppy provided by BIOS INT 0x13 ;cannot use in 32bits mode and 64bits mode
mov ah,0x2 ;function ID 0x2 read_sector; 0x3 write_sector
mov al,0x2 ;count of read/write sector
mov ch,0x0 ;location(cylider)
mov dh,0x0 ;location()
mov cl,0x2 ;location(sector)
mov byte dl,[BOOTDRIVE] ;type of drive(0x0~0x7f floppy drive;0x80~0xff hard drive)
mov bx,0x0
mov es,bx ;es:bx target memory area
mov bx,0x7e00
int 13h
cli ;after int 0x13 inst execute, the IF bit was enabled. we must to disable it.
jc Read_Disk_Error
Read_Disk_OK:
lgdt [GDT_PROP]
in al,0x92
or al,2
out 0x92,al
mov eax,0x1
mov cr0,eax
jmp dword flatcode:bsp_protected_mode_init_segreg
[bits 32]
bsp_protected_mode_init_segreg:
mov ax,flatdata
mov ds,ax
mov ax,flatstack
mov ss,ax
mov esp,0x00200000
loadpage:
mov eax,flatdata
mov ds,eax
mov es,eax
mov esi,temp_pt
mov edi,0x00100000
mov ecx,temp_pt_end - temp_pt
cld
rep movsb
mov esi,temp_pdt
mov edi,0x00101000
mov ecx,temp_pdt_end - temp_pdt
cld
rep movsb
mov esi,temp_pdpt
mov edi,0x00102000
mov ecx,temp_pdpt_end - temp_pdpt
cld
rep movsb
mov esi,temp_pml4
mov edi,0x00103000
mov ecx,temp_pml4_end - temp_pml4
cld
rep movsb
bsp_init_long_mode:
call checkcpuid
call checkia32e
mov ax,flatdata
mov ds,ax
mov eax,0x20
mov cr4,eax
mov eax,0x00103000 ;pml4
mov cr3,eax
mov ecx,0xc0000080
rdmsr
or eax,1 << 8
wrmsr
cli
mov eax,0x80000001
mov cr0,eax
jmp dword flatcode:bsp_long_mode
temp_pt:
dq 0x00000000000b8001
dq 0x00000000000b8001
dq 0x0000000000000001
dq 0x0000000000000001
dq 0x0000000000000001
dq 0x0000000000000001
dq 0x0000000000104001 ;stack at 0x00104000
dq 0x0000000000007001 ;bootloader
temp_pt_end:
temp_pdt:
dq 0x0000000000100001
temp_pdt_end:
temp_pdpt:
dq 0x0000000000101001
temp_pdpt_end:
temp_pml4:
dq 0x0000000000102001
temp_pml4_end:
GDT_PROP:
dw GDT_TABLE_32_END - GDT_TABLE_ENTRY_32 - 1
dd GDT_TABLE_ENTRY_32
GDT_TABLE_ENTRY_32:
dq 0x0000000000000000 ;Empty Entry
dq 0x00cf9a000000ffff ;code
dq 0x00cf92000000ffff ;data&stack
GDT_TABLE_32_END:
GDT_PROP_64:
dw GDT_TABLE_64_END - GDT_TABLE_ENTRY_64 - 1
dq GDT_TABLE_ENTRY_64
GDT_TABLE_ENTRY_64:
dq 0x0000000000000000
dq 0x00af9a000000ffff
dq 0x00af92000000ffff
GDT_TABLE_64_END:
[bits 16]
BIOS_13H_ERROR:
db 'PizzaLoader:(0x0) Disk Error! System Halted.'
Read_Disk_Error:
mov ax,0x0
mov ds,ax
xor si,si
mov bx,BIOS_13H_ERROR
mov cx,44
Print_Disk_Error:
mov dx,0x0
mov ds,dx
mov byte al,[ds:bx] ;read BIOS_13H_ERROR
add bx,1
mov dx,0xb800
mov ds,dx
mov byte [ds:si],al ;write 0xb8000
add si,2
loop Print_Disk_Error
jmp cpuhlt
cpuhlt:
hlt
times 510 - ($ - $$) db 0x0
db 0x55, 0xaa
[bits 32]
NO_CPUID_ERROR:
db 'PizzaLoader:(0x1)The Processor does not support CPUID instruction, System Halted.'
checkcpuid:
pushfd
pop eax
mov ecx,eax
xor eax,1<<21
push eax
popfd
pushfd
pop eax
push ecx
popfd
xor eax,ecx
jz nocpuid
ret
nocpuid:
mov ax,flatdata
mov ds,ax
mov esi,0x000b8000
mov ebx,NO_CPUID_ERROR
mov ecx,81
Print_no_CPUID_Error:
mov byte al,[ebx] ;read NO_CPUID_ERROR
add ebx,1
mov byte [esi],al ;write 0xb8000
add esi,2
loop Print_no_CPUID_Error
hlt
NO_IA32E_ERROR:
db 'PizzaLoader:(0x2)The Processor does not support 64-bits mode, System Halted.'
checkia32e:
mov eax, 0x80000000 ; Set the A-register to 0x80000000.
cpuid ; CPU identification.
cmp eax, 0x80000001 ; Compare the A-register with 0x80000001.
jb noia32e ; It is less, there is no long mode.
ret
noia32e:
mov ax,flatdata
mov ds,ax
mov esi,0x000b8000
mov ebx,NO_IA32E_ERROR
mov ecx,76
Print_no_IA32E_Error:
mov byte al,[ebx] ;read NO_CPUID_ERROR
add ebx,1
mov byte [esi],al ;write 0xb8000
add esi,2
loop Print_no_IA32E_Error
hlt
[bits 64]
bsp_long_mode:
lgdt [GDT_PROP_64]
mov rax,flatdata
mov ds,rax
mov ss,rax
mov sp,0x00006000
call Load_Kernel
hlt
Load_Kernel:
mov rsi,0x00000000
mov rbx,loading_kernel_Message
mov rcx,21
Print_Loading_Kernel_Message:
mov byte al,[rbx] ;read message
add rbx,1
mov byte [rsi],al ;write 0x000b8000
add rsi,2
loop Print_Loading_Kernel_Message
ret
loading_kernel_Message:
db 'Loading Mio Kernel...'
[bits 64]
restart:
mov dx,0xcf9
mov al,0xe
out dx,al
Here are my full codes, and running result is this:
Kn’chmf?Lhn?Jdqmdk———
The text output has ASCII codes 1 lower than they should be, so earlier in the alphabet by 1 letter. Should be "Loading..."
bsp_long_mode:
lgdt [GDT_PROP_64]
mov rax,flatdata
mov ds,rax
mov ss,rax
mov sp,0x00006000
call Load_Kernel
hlt
After loading your 64-bit GDT, you reload DS and SS, but not CS. You need to do a far jump with your new code segment selector 0x8 to actually enter 64-bit mode. (This also means that [BITS 64]
should go after that jump.)
Or, as I see you just posted in a comment, move lgdt [GDT_PROP_64]
before the jmp dword flatcode:bsp_long_mode
.
As it stands, your intended 64-bit code is being executed in 32-bit mode. And as Peter Cordes deduced, the REX prefix on your intended 64-bit instructions decodes in 32-bit mode as dec eax
, causing your bytes to be decremented before being stored into video memory.
Then there is another bug: mov sp,0x00006000
should be mov rsp, ...
, else you only load the low 16 bits and leave the upper 48 bits alone, resulting in a page fault (and hence triple fault) when your call
instruction tries to push to the stack. And since according to your comment, you want the stack on page 0x6000 (i.e. virtual addresses 0x6000-0x6fff), and the stack grows down, you actually want to initialize rsp
to 0x7000
.
(mov esp, 0x7000
has identical effect, since 32-bit register writes are zero-extended in 64-bit mode, but it looks odd.)
The following version of the code works for me:
bsp_long_mode:
lgdt [GDT_PROP_64]
jmp 0x8:actual_long_mode
[bits 64]
actual_long_mode:
mov rax,flatdata
mov ds,rax
mov ss,rax
mov rsp,0x00007000
call Load_Kernel
hlt