2

As you can see down at bottom on my stage 2 boot loader, I have a VGA write thing (Prints out "Starting kernel...", but when I use it, the system starts to boot loop, I have no idea why this is happening. I would like it to print start_kernel on row 8 (if you count the first row as row 1) and then halt the system.

ORG 0x7E00
BITS 16
stage2:
    cli
    xor ax, ax
    mov ds, ax
    mov ss, ax
    mov sp, 0x7C00
    sti

    mov [BootDrive], dl

    mov ah, 0x02
    mov bh, 0x00
    mov dh, 0x02
    mov dl, 0x00
    int 0x10

    push ds
    mov si, load_gdt
    call print
    lgdt [gdtinfo]
    mov si, enter_pmode
    call print
    mov eax, cr0
    or eax, 1
    mov cr0, eax
    jmp 0x08:pmode

unreal:
    pop ds
    xor ax, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    sti
    mov si, enter_unreal
    call print
    jmp boot

print:
    lodsb
    or al, al
    jz .done
    mov ah, 0x0E
    mov bh, 0x00
    mov bl, 0x07
    int 0x10
    jmp print
.done:
    ret

boot:
    mov si, load_disk
    call print

    mov dl, [BootDrive]
    xor ax, ax
    int 0x13
    jc disk_error

    mov ax, 0x1000
    mov es, ax
    mov bx, 0

    mov dl, [BootDrive]
    mov dh, 0
    mov ch, 0
    mov cl, 4
    mov al, 16
    mov ah, 0x02

    int 0x13
    jc disk_error

    cmp al, 0
    je disk_error

    mov ax, [es:0]
    cmp ax, 0
    je no_kernel

    jmp kernel

disk_error:
    mov si, error_disk_read
    call print
    jmp halt

no_kernel:
    mov si, error_no_kernel
    call print
    jmp halt

kernel:
    mov si, enter_pmode
    call print

    lgdt [gdtinfo]
    mov eax, cr0
    or eax, 1
    mov cr0, eax

    jmp 0x08:kernel32

halt:
    cli
    hlt
    jmp halt

load_disk db "Loading kernel...",0x0D, 0x0A, 0
load_gdt db "Loading GDT...", 0x0D, 0x0A, 0
enter_pmode db "Entering protected mode...", 0x0D, 0x0A, 0
enter_unreal db "Entering unREAL mode...", 0x0D, 0x0A, 0
error_disk_read db "Disk read error!", 0x0D, 0x0A, 0
error_no_kernel db "No kernel found!", 0x0D, 0x0A, 0
BootDrive db 0

align 8
gdt:
    dd 0,0
flatcode:
    db 0xff,0xff,0,0,0,10011010b,10001111b,0
flatdata:
    db 0xff,0xff,0,0,0,10010010b,11001111b,0
gdt_end:
gdtinfo:
    dw gdt_end - gdt - 1
    dd gdt

[BITS 32]
pmode:
    mov bx, 0x10
    mov ds, bx
    mov es, bx
    mov fs, bx
    mov gs, bx
    mov ss, bx
    mov eax, cr0
    and eax, 0xFFFFFFFE
    mov cr0, eax
    jmp 0x0:unreal

kernel32:

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov esp, 0x90000

    mov esi, start_kernel
    mov edi, 0xB8000
    mov ah, 0x0F  
.print_loop:
    lodsb
    or al, al
    jz .done
    stosw
    jmp .print_loop
.done:

.hang:
    cli
    hlt
    jmp .hang

start_kernel db "Starting kernel...", 0
7
  • This instruction may cause a problem pmode: mov bx, 0x10. You are in protected mode so cpu needs 32-bit operand bb 10 00 ?? ?? so next instruction will be included mov ds, bx (8e db) creating 66 bb 10 00 8e db. ds segment will not be initialized properly. Commented Nov 24 at 8:13
  • And later ah = 02h, int 13h tries to read 16 sectors but no data is available on disk image so this leads to no_kernel: + halt: code. Commented Nov 24 at 8:33
  • 2
    @Nassau mov bx can be encoded in a bits 32 section just fine, using an osize prefix (o16 in that case). Commented Nov 24 at 13:03
  • 1
    Curious what your need for unreal mode is? Do you do this so you can read the kernel into memory and then copy it to addresses above the 1MiB? Something else? You don't need unreal mode to get into 32-bit protected mode. Commented Nov 24 at 22:26
  • 1
    Code on the disk image you provided in the link below loads data in real mode. First sector (0 0 2) with some parameters used later in big loop to load rest of the code: iteration 1: 64 sectors (0x8000), iteration 2: 1 sector (0x10000) and iteration 3 is skipped because eax > 0. After that GDT data is generated and LGDT loads these values to GDTR. Switches to PM, jmps to previously loaded code 0x08:0x9e61 and that's it. Commented Nov 25 at 14:57

2 Answers 2

0

It works but I commented out this part:

;    mov eax, cr0 
;    and eax, 0xFFFFFFFE
;    mov cr0, eax
;    jmp 0x0:unreal

kernel32:

;    mov ax, 0x10
;    mov ds, ax
;    mov es, ax
;    mov fs, ax
;    mov gs, ax
;    mov ss, ax
;    mov esp, 0x90000

and d/b bit in flatcode's segment descriptor should be 1 to generate 32-bit addresses.

flatcode:                         V    
    db 0xff,0xff,0,0,0,10011010b,11001111b,0

Code:

simple mbr to load rest of the code

ORG 0x7c00
BITS 16

cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7c00

mov ax, 0x0201
mov cx, 0x0002
mov dx, 0x0000
mov bx, 0x7e00
int 13h

jmp 0:0x7e00

times 510 - ($ - $$) db 0x0
dw 0xaa55

and your code

ORG 0x7E00
BITS 16
stage2:
    cli
    xor ax, ax
    mov ds, ax
    mov ss, ax
    mov sp, 0x7C00
    sti

    mov [BootDrive], dl

    mov ah, 0x02
    mov bh, 0x00
    mov dh, 0x02
    mov dl, 0x00
    int 0x10

    push ds
    mov si, load_gdt
    call print
    lgdt [gdtinfo]
    mov si, enter_pmode
    call print
    mov eax, cr0
    or eax, 1
    mov cr0, eax
    jmp 0x08:pmode

unreal:
    pop ds
    xor ax, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    sti
    mov si, enter_unreal
    call print
    jmp boot

print:
    lodsb
    or al, al
    jz .done
    mov ah, 0x0E
    mov bh, 0x00
    mov bl, 0x07
    int 0x10
    jmp print
.done:
    ret

boot:
    mov si, load_disk
    call print

    mov dl, [BootDrive]
    xor ax, ax
    int 0x13
    jc disk_error

    mov ax, 0x1000
    mov es, ax
    mov bx, 0

    mov dl, [BootDrive]
    mov dh, 0
    mov ch, 0
    mov cl, 4
    mov al, 16
    mov ah, 0x02

    int 0x13
    jc disk_error

    cmp al, 0
    je disk_error

    mov ax, [es:0]
    cmp ax, 0
    je no_kernel

    jmp kernel

disk_error:
    mov si, error_disk_read
    call print
    jmp halt

no_kernel:
    mov si, error_no_kernel
    call print
    jmp halt

kernel:
    mov si, enter_pmode
    call print

    lgdt [gdtinfo]
    mov eax, cr0
    or eax, 1
    mov cr0, eax

    jmp 0x08:kernel32

halt:
    cli
    hlt
    jmp halt

load_disk db "Loading kernel...",0x0D, 0x0A, 0
load_gdt db "Loading GDT...", 0x0D, 0x0A, 0
enter_pmode db "Entering protected mode...", 0x0D, 0x0A, 0
enter_unreal db "Entering unREAL mode...", 0x0D, 0x0A, 0
error_disk_read db "Disk read error!", 0x0D, 0x0A, 0
error_no_kernel db "No kernel found!", 0x0D, 0x0A, 0
BootDrive db 0

align 8
gdt:
    dd 0,0
flatcode:                         V    
    db 0xff,0xff,0,0,0,10011010b,11001111b,0
flatdata:
    db 0xff,0xff,0,0,0,10010010b,11001111b,0
gdt_end:
gdtinfo:
    dw gdt_end - gdt - 1
    dd gdt

[BITS 32]
pmode:
    os16 mov bx, 0x10   ; 66 bb 10 00
    ; mov ebx, 0x10
    mov ds, bx
    mov es, bx
    mov fs, bx
    mov gs, bx
    mov ss, bx
;   mov eax, cr0 
;    and eax, 0xFFFFFFFE
;    mov cr0, eax
;   jmp 0x0:unreal

kernel32:

;    mov ax, 0x10
;    mov ds, ax
;    mov es, ax
;    mov fs, ax
;    mov gs, ax
;    mov ss, ax
;    mov esp, 0x90000

    mov esi, start_kernel
    mov edi, 0xB8000
    mov ah, 0x0F  
.print_loop:
    lodsb
    or al, al
    jz .done
    stosw
    jmp .print_loop
.done:

.hang:
    cli
    hlt
    jmp .hang

start_kernel db "Starting kernel...", 0

Sign up to request clarification or add additional context in comments.

3 Comments

This makes it bootloop :( when it enters protected mode for the unreal mode
Code I gave you (without unreal mode) works fine because I tested it. I see white text "Starting kernel...". Problem could be in boot:, you want to read 16 sectors from a disk, I don't know how your disk image looks like. I tested this in bochs debugger and this part mov ax, [es:0], cmp ax, 0, je no_kernel was executed because ah=0x02, int 13h loaded nothing.
It is the main branch on here github.com/The-cheeseDOS-Project/cheeseDOS
-2
; cheeseDOS - My x86 DOS
; Copyright (C) 2025  Connor Thomson
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program.  If not, see <https://www.gnu.org/licenses/>.

ORG 0x7E00

[BITS 16]
stage2:   
   cli
   mov [BootDrive], dl
   xor ax, ax       
   mov ds, ax             
   mov ss, ax             
   mov sp, 0x9c00
   mov si, enable_a20
   call print
   call a20
   mov si, set_idt
   call print
   call setup_idt
   mov si, set_gdt
   call print
   lgdt [gdtinfo]         
   mov si, enter_pmode
   call print
   mov eax, cr0          
   or al, 1
   mov cr0, eax
   mov bx, 0x10
   mov ds, bx
   mov es, bx
   mov fs, bx
   mov gs, bx
   mov ss, bx
   and al, 0xFE            
   mov cr0, eax
   xor ax, ax
   mov ds, ax
   mov ss, ax
   mov sp, 0x9c00
   sti                     
   mov si, enter_unreal
   call print
   cli                     
   jmp boot

boot:
    mov si, load_disk
    call print
    mov dl, [BootDrive]
    xor ax, ax
    int 0x13
    jc disk_error
    mov ax, 0x1000
    mov es, ax
    mov bx, 0
    mov dl, [BootDrive]
    mov dh, 0
    mov ch, 0
    mov cl, 4
    mov al, 16
    mov ah, 0x02
    int 0x13
    jc disk_error
    cmp al, 0
    je disk_error
    mov ax, [es:0]
    cmp ax, 0
    je no_kernel
    mov si, enter_pmode
    call print
    lidt [idtinfo]
    lgdt [gdtinfo]
    mov eax, cr0
    or al, 1
    mov cr0, eax
    jmp 0x08:pmode32

setup_idt:
   push ax
   push cx
   push di
   push es
   xor ax, ax
   mov es, ax
   mov di, idt
   mov cx, 256
.loop:
   mov eax, default_isr
   mov [es:di], ax
   add di, 2
   mov word [es:di], 0x08
   add di, 2
   mov byte [es:di], 0
   inc di
   mov byte [es:di], 0x8E
   inc di
   shr eax, 16
   mov [es:di], ax
   add di, 2
   loop .loop
   pop es
   pop di
   pop cx
   pop ax
   ret

print:
    lodsb
    or al, al
    jz .done
    mov ah, 0x0E
    mov bh, 0x00
    mov bl, 0x07
    int 0x10
    jmp print
.done:
    ret

a20:
    in al, 0x64
    test al, 2
    jnz a20
    mov al, 0xD1
    out 0x64, al
.wait1:
    in al, 0x64
    test al, 2
    jnz .wait1
    mov al, 0xDF
    out 0x60, al
.wait2:
    in al, 0x64
    test al, 2
    jnz .wait2
    ret

gdtinfo:
   dw gdt_end - gdt - 1   
   dd gdt                 

gdt:    
   dd 0,0                 

codedesc:                 
   dw 0xFFFF              
   dw 0x0000              
   db 0x00                
   db 10011010b           
   db 11001111b           
   db 0x00                

flatdesc:                 
   dw 0xFFFF              
   dw 0x0000              
   db 0x00                
   db 10010010b           
   db 11001111b           
   db 0x00                

gdt_end:

idtinfo:
   dw (256 * 8) - 1       
   dd idt                 

set_idt db "Setting IDT...", 0x0D, 0x0A, 0
enter_pmode db "Entering protected mode...", 0x0D, 0x0A, 0
set_gdt db "Setting GDT...", 0x0D, 0x0A, 0
enter_unreal db "Entering unreal mode...", 0x0D, 0x0A, 0
load_disk db "Loading kernel...",0x0D, 0x0A, 0
no_kernel db "No kernel found!", 0x0D, 0x0A, 0
disk_error db "Disk read error!", 0x0D, 0x0A, 0
enable_a20 db "Enabling A20...", 0x0D, 0x0A, 0
BootDrive db 0

[BITS 32]
pmode32:
    mov ax, 0x10           
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov esp, 0x9c00    
    mov edi, 0xB8000 + (8 * 160)
    mov esi, start_kernel
    mov ah, 0x07
.loop:
    lodsb
    test al, al
    jz .done
    stosw
    jmp .loop
.done:
    jmp 0x08:0x10000

default_isr:
    iretd

start_kernel db "Starting kernel...",0

align 8
idt:
   times (256 * 8) db 0
New contributor
Connor Thomson is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

5 Comments

You should explain this answer. A wall of code is not very helpful.
I rewrote it that's it
Describe in words at least some of the important bugs that existed in the old version. And/or any gotchas you took care to avoid in this version. Or at least any interesting features this bootloader has which standard examples such as stackoverflow.com/questions/33603842/… don't have, like what advantage you get from setting up unreal mode mode for the BIOS disk-read calls.
Code-only answers are unhelpful for future viewers. Please edit your answer to explain how and why your code answers the question.
I get larger kernel support

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.