assemblyx86x86-64bootloader

Why these ascii characters in this string in asm code will automatically subtract 1?


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..."

enter image description here


Solution

  • 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