Help with Higher Half Bootloader

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
enigma
Posts: 18
Joined: Tue Dec 25, 2007 10:52 am

Help with Higher Half Bootloader

Post by enigma »

Okay, I tried using the GRUB/GDT trick, but GRUB wouldn't load my OS image no matter what I tried. So instead, I tried creating a bootloader that could load the kernel, enable A20 and Pmode, and set up paging to map the kernel at 0xC0010000. The problem is that the bootloader loads the kernel, and does everything else fine, but then it just hangs.

Code: Select all

[BITS 16]

[ORG 0x7C00]


reset_drive:
        mov ah, 0               ; RESET-command
        int 13h                 ; Call interrupt 13h
        or ah, ah               ; Check for error code
        jnz reset_drive         ; Try again if ah != 0

        mov ax, 0x1000
        mov es, ax
        mov bx, 0x0          ; Destination address = 0x10000

        mov ah, 02h             ; READ SECTOR-command
        mov al, 36             ; Number of sectors to read = 36
        mov ch, 0               ; Cylinder = 0
        mov cl, 02h             ; Sector = 2
        mov dh, 0               ; Head = 0
        int 13h                 ; Call interrupt 13h
        or ah, ah               ; Check for error code
        jnz reset_drive         ; Try again if ah != 0

        cli                     ; Disable interrupts, we want to be alone

        xor ax, ax
        mov ds, ax              ; Set DS-register to 0 - used by lgdt

        lgdt [gdt_desc]
        
        call enable_A20

        mov ax, 0x9C00
        mov es, ax
        xor di, di
        mov ax, 0
        mov bx, 3

init_1st_page:

        mov cx, 0x100
        stosw
        xchg bx, ax
        stosw
        add bx, 0x1000
        xchg ax, bx
        loop init_1st_page
        
        mov cx, 0x200
        xor ax, ax
        rep stosd

init_2nd_page:

        mov cx, 0x10
        rep stosd
        mov cx, 0x3F0
        mov eax, 0x10000
        mov ebx, 3
        stosw
        xchg ebx, eax
        stosw
        xchg eax, ebx
        add eax, 0x1000
        loop init_2nd_page

        mov eax, 0x9C003
        stosd
        mov ax, 767
        xchg ax, cx
        rep stosd
        mov eax, 0x9D003
        stosd

        mov eax, 0x9E000
        mov cr3, eax
        mov eax, cr0
        or  eax, 0x80000001     ; enables paging and Pmode
        mov cr0, eax

        jmp 08h:clear_pipe      ; Jump to code segment, offset clear_pipe

enable_A20:
        in	al, 0x64
        test	al, 2
        jnz	enable_A20
        mov	al, 0xD1
        out	0x64, al
.6:
        in	al, 0x64
        and	ax, byte 2
        jnz	.6
        mov	al, 0xDF
        out	0x60, al


 
[BITS 32]
clear_pipe:

        mov eax, 0x10
        mov ds, eax
        mov es, eax
        mov fs, eax
        mov gs, eax
        mov ss, eax
        jmp 8:0x10000


gdt:                    ; Address for the GDT

gdt_null:               ; Null Segment
        dd 0
        dd 0

gdt_code:               ; Code segment, read/execute, nonconforming
        dw 0FFFFh
        dw 0
        db 0
        db 10011010b
        db 11001111b
        db 0

gdt_data:               ; Data segment, read/write, expand down
        dw 0FFFFh
        dw 0
        db 0
        db 10010010b
        db 11001111b
        db 0

gdt_end:                ; Used to calculate the size of the GDT

gdt_desc:                       ; The GDT descriptor
        dw gdt_end - gdt - 1    ; Limit (size)
        dd gdt                  ; Address of the GDT


times 510-($-$$) db 0

        dw 0AA55h                ; Boot sector identifyer
User avatar
codemastersnake
Member
Member
Posts: 148
Joined: Sun Nov 07, 2004 12:00 am
Contact:

Re: Help with Higher Half Bootloader

Post by codemastersnake »

Have you tried your kernel in other emulators or on a real PC?
enigma
Posts: 18
Joined: Tue Dec 25, 2007 10:52 am

Re: Help with Higher Half Bootloader

Post by enigma »

no, but i figure that i should try to make it work successfully on the emulator i have (qemu 0.9.0) before tackling other emulators
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: Help with Higher Half Bootloader

Post by AJ »

Hi,

Whan your bootloader just hangs, where is EIP? Where is ESP? Are they where you would expect? What is the instruction that it is hanging on (in other words, do you have a JMP $ anywhere - sorry to be patronising but I've done this myself before :? )

I'm not familiar with Qemu, just Bochs, but if Qemu gives you a Bochs-style final register dump, could you post that register dump here, please?

Cheers,
Adam
xyzzy
Member
Member
Posts: 391
Joined: Wed Jul 25, 2007 8:45 am
Libera.chat IRC: aejsmith
Location: London, UK
Contact:

Re: Help with Higher Half Bootloader

Post by xyzzy »

AJ wrote:Hi,

Whan your bootloader just hangs, where is EIP? Where is ESP? Are they where you would expect? What is the instruction that it is hanging on (in other words, do you have a JMP $ anywhere - sorry to be patronising but I've done this myself before :? )

I'm not familiar with Qemu, just Bochs, but if Qemu gives you a Bochs-style final register dump, could you post that register dump here, please?

Cheers,
Adam
Its not as easy to get a register dump from QEMU. Only way I know of while its running is to switch into the monitor (Ctrl+Alt+2) and type "info registers", but AFAIK you can't copy and paste that.
enigma
Posts: 18
Joined: Tue Dec 25, 2007 10:52 am

Re: Help with Higher Half Bootloader

Post by enigma »

AlexExtreme wrote:
AJ wrote:Hi,

Whan your bootloader just hangs, where is EIP? Where is ESP? Are they where you would expect? What is the instruction that it is hanging on (in other words, do you have a JMP $ anywhere - sorry to be patronising but I've done this myself before :? )

I'm not familiar with Qemu, just Bochs, but if Qemu gives you a Bochs-style final register dump, could you post that register dump here, please?

Cheers,
Adam
Its not as easy to get a register dump from QEMU. Only way I know of while its running is to switch into the monitor (Ctrl+Alt+2) and type "info registers", but AFAIK you can't copy and paste that.
Thanks for that, I have a screenshot of the register dump now.

Based on the values, it seems that the loader enables the A20, but the values for cr0 seem wrong as does EIP. :? Now I'm even more confused as there doesn't seem to be any sort of jump instruction to 0x3c, and protected mode and paging should be initialized.

Linker Map:

Code: Select all

Allocating common symbols
Common symbol       size              file

idtp                0x6               idt.o
lower_mem           0x400             mm.o
idt                 0x800             idt.o
upper_mem           0x1fc00           mm.o

Memory Configuration

Name             Origin             Length             Attributes
*default*        0x00000000         0xffffffff

Linker script and memory map

                0xc0010000                . = 0xc0010000

.text           0xc0010000     0x155a load address 0x00010000
 *(.text)
 .text          0xc0010000      0x27b start.o
                0xc001004c                isr4
                0xc0010147                isr27
                0xc001009e                isr13
                0xc0010227                irq12
                0xc0010115                isr22
                0xc00100cf                isr15
                0xc0010213                irq10
                0xc001023b                irq14
                0xc001007c                isr9
                0xc00101ff                irq8
                0xc001011f                isr23
                0xc001015b                isr29
                0xc001016f                isr31
                0xc001010b                isr21
                0xc001021d                irq11
                0xc0010151                isr28
                0xc0010074                isr8
                0xc00101e1                irq5
                0xc0010101                isr20
                0xc00100a6                isr14
                0xc0010056                isr5
                0xc00101eb                irq6
                0xc00101b9                irq1
                0xc001002e                isr1
                0xc0010209                irq9
                0xc001013d                isr26
                0xc001008e                isr11
                0xc0010231                irq13
                0xc0010096                isr12
                0xc001001c                idt_load
                0xc0010024                isr0
                0xc00101c3                irq2
                0xc0010129                isr24
                0xc00100d9                isr16
                0xc0010042                isr3
                0xc0010060                isr6
                0xc00101f5                irq7
                0xc00100ed                isr18
                0xc00101af                irq0
                0xc0010086                isr10
                0xc0010000                start
                0xc00100e3                isr17
                0xc0010038                isr2
                0xc00100f7                isr19
                0xc0010165                isr30
                0xc0010245                irq15
                0xc001006a                isr7
                0xc0010133                isr25
                0xc00101d7                irq4
                0xc00101cd                irq3
 *fill*         0xc001027b        0x1 00
 .text          0xc001027c      0x66f kernel.o
                0xc00106b9                printf
                0xc0010283                sys_halt
                0xc0010625                inportb
                0xc00104c2                putch
                0xc0010280                debug_int
                0xc0010645                move_csr
                0xc0010604                outportb
                0xc0010381                out_ok
                0xc00102b1                k_main
                0xc001028a                panic
                0xc0010405                scroll
                0xc001027c                enable_ints
                0xc001061a                outportw
                0xc001027e                disable_ints
                0xc0010286                halt
                0xc0010288                nop
                0xc00103b0                clear_screen
 *fill*         0xc00108eb        0x5 00
 .text          0xc00108f0       0x1e paging.o
                0xc00108ff                read_cr3
                0xc00108f4                write_cr0
                0xc0010903                write_cr3
                0xc00108f0                read_cr0
 *fill*         0xc001090e        0x2 00
 .text          0xc0010910       0xce memory.o
                0xc0010980                memsetw
                0xc0010910                memcpy
                0xc001094c                memset
                0xc00109b7                strlen
 *fill*         0xc00109de        0x2 00
 .text          0xc00109e0      0x178 mm.o
                0xc0010a12                upper_alloc
                0xc0010a44                init_paging
                0xc0010aff                mem_init
                0xc0010a27                upper_free
                0xc00109e0                lower_alloc
                0xc00109f5                lower_free
 .text          0xc0010b58       0xbc idt.o
                0xc0010bdd                idt_install
                0xc0010b58                idt_set_gate
 .text          0xc0010c14      0x3ba isrs.o
                0xc0010efb                fault_handler
                0xc0010c14                isrs_install
 *fill*         0xc0010fce        0x2 00
 .text          0xc0010fd0      0x2a8 irq.o
                0xc0010fe0                irq_uninstall_handler
                0xc001109c                irq_install
                0xc0010fd0                irq_install_handler
                0xc0011218                irq_handler
                0xc0010ff0                irq_remap
 .text          0xc0011278       0xa7 pit.o
                0xc00112d1                timer_handler
                0xc00112e6                sleep
                0xc0011278                timer_phase
                0xc00112f9                timer_install
 *fill*         0xc001131f        0x1 00
 .text          0xc0011320      0x23a kb.o
                0xc0011541                keyboard_install
                0xc0011320                keyboard_handler

.data           0xc0012000      0x59e load address 0x00012000
 *(.data)
 .data          0xc0012000       0x26 start.o
 *fill*         0xc0012026        0x2 00
 .data          0xc0012028        0xc kernel.o
                0xc0012030                page_table
                0xc001202c                attrib
                0xc0012028                textmemptr
 .data          0xc0012034        0x0 memory.o
 .data          0xc0012034       0x18 mm.o
                0xc0012034                top_lower_stack
                0xc0012044                page_table_k_start
                0xc0012048                page_table_page_directory
                0xc0012038                top_upper_stack
                0xc0012040                page_table0
                0xc001203c                page_directory
 .data          0xc001204c        0x0 idt.o
 *fill*         0xc001204c       0x14 00
 .data          0xc0012060       0x7c isrs.o
                0xc0012060                exception_messages
 .data          0xc00120dc        0x0 irq.o
 .data          0xc00120dc        0x0 pit.o
 *fill*         0xc00120dc        0x4 00
 .data          0xc00120e0      0x200 kb.o
                0xc0012160                shift_kbdus
                0xc00120e0                kbdus
                0xc00121e0                caps_kbdus
                0xc0012260                shift_caps_kbdus
 *(.rodata*)
 .rodata        0xc00122e0       0xf0 kernel.o
 .rodata        0xc00123d0      0x1ce isrs.o

.bss            0xc0013000    0x24886 load address 0x00013000
 *(COMMON*)
 COMMON         0xc0013000    0x20000 mm.o
                0xc0013000                lower_mem
                0xc0013400                upper_mem
 COMMON         0xc0033000      0x820 idt.o
                0xc0033000                idtp
                0xc0033020                idt
 *(.bss*)
 .bss           0xc0033820     0x4000 start.o
 .bss           0xc0037820        0x8 kernel.o
                0xc0037820                csr_x
                0xc0037824                csr_y
 .bss           0xc0037828        0x0 memory.o
 .bss           0xc0037828        0x0 mm.o
 .bss           0xc0037828        0x0 idt.o
 .bss           0xc0037828        0x0 isrs.o
 *fill*         0xc0037828       0x18 00
 .bss           0xc0037840       0x40 irq.o
                0xc0037840                irq_routines
 .bss           0xc0037880        0x4 pit.o
                0xc0037880                count_down
 .bss           0xc0037884        0x2 kb.o
                0xc0037885                temp_char
                0xc0037884                keystate

.rel.dyn        0xc0037888        0x0 load address 0x00037888
 .rel.text      0x00000000        0x0 start.o
LOAD start.o
LOAD kernel.o
LOAD paging.o
LOAD memory.o
LOAD mm.o
LOAD idt.o
LOAD isrs.o
LOAD irq.o
LOAD pit.o
LOAD kb.o
OUTPUT(a.out elf32-i386)
Attachments
Register dump
Register dump
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: Help with Higher Half Bootloader

Post by AJ »

Hmmm...I think you need to step through your binary instruction-by-instruction to sort this one out. Again, if you can't do this in qemu, try Bochs (the user WindowsNT has made an excelent frontend for the Windows Bochs debugger).

Just one thing - could you start your boot loader with a far jump to reset_drive in order to ensure you have a valid CS:IP?

If all else fails, write a JMP $ at the start of your code and see if Qemu gives you the expected CS:IP result on termination. If so, move that JMP $ down through your code until you hit the problem point. Tedious, but it works!

Cheers,
Adam
User avatar
Brynet-Inc
Member
Member
Posts: 2426
Joined: Tue Oct 17, 2006 9:29 pm
Libera.chat IRC: brynet
Location: Canada
Contact:

Re: Help with Higher Half Bootloader

Post by Brynet-Inc »

AlexExtreme wrote:Its not as easy to get a register dump from QEMU. Only way I know of while its running is to switch into the monitor (Ctrl+Alt+2) and type "info registers", but AFAIK you can't copy and paste that.
It most definitely is easy to get a register dump.. -monitor stdio. :roll:
Image
Twitter: @canadianbryan. Award by smcerm, I stole it. Original was larger.
xyzzy
Member
Member
Posts: 391
Joined: Wed Jul 25, 2007 8:45 am
Libera.chat IRC: aejsmith
Location: London, UK
Contact:

Re: Help with Higher Half Bootloader

Post by xyzzy »

Brynet-Inc wrote:
AlexExtreme wrote:Its not as easy to get a register dump from QEMU. Only way I know of while its running is to switch into the monitor (Ctrl+Alt+2) and type "info registers", but AFAIK you can't copy and paste that.
It most definitely is easy to get a register dump.. -monitor stdio. :roll:
Well you learn something new every day, never knew about that! Thanks!
enigma
Posts: 18
Joined: Tue Dec 25, 2007 10:52 am

Re: Help with Higher Half Bootloader

Post by enigma »

Alright, I've tried using bochs to emulate my bootloader/OS, but I can't even get it to boot properly. I'm wondering if this may be due to the way I create a disk image, by just putting the bootloader and kernel together back to back without padding it to a proper floppy size. Qemu tackled this just fine, but I haven't used bochs at all really. If anyone could help out with this, or knows how to implement breakpoints in qemu, I'd be much obliged.
enigma
Posts: 18
Joined: Tue Dec 25, 2007 10:52 am

Re: Help with Higher Half Bootloader

Post by enigma »

AJ wrote:Hmmm...I think you need to step through your binary instruction-by-instruction to sort this one out. Again, if you can't do this in qemu, try Bochs (the user WindowsNT has made an excelent frontend for the Windows Bochs debugger).

Just one thing - could you start your boot loader with a far jump to reset_drive in order to ensure you have a valid CS:IP?

If all else fails, write a JMP $ at the start of your code and see if Qemu gives you the expected CS:IP result on termination. If so, move that JMP $ down through your code until you hit the problem point. Tedious, but it works!

Cheers,
Adam
Thanks so much for telling me about that. I got bochs working, but if not for that debugger, I never would have seen that the A20 enabling code was missing it's "ret" #-o

Now to work out the tedious little logic errors in the pages.
User avatar
ivannz
Posts: 2
Joined: Tue Jun 27, 2006 2:28 pm
Location: USSR

Re: Help with Higher Half Bootloader

Post by ivannz »

Hello,

Maybe this topic is a bit outdated, but here is where your problems stems from, besides missing ret:
you use 'loop' instruction, which uses cx/ecx as a counter, but inside your loop you Reinitialize cx/ecx counter each iteration.
So each time counter is reinitialized and the cycle goes on and on forever.

Here is what you have got in your code:
this part, as far as i see, is responsible for filling 2 page tables id mapping 1st Mb and mapping first 4Mb excpet for first 64Kb.

Code: Select all

	mov ax, 0x9C00
	mov es, ax
	xor di, di
	mov ax, 0
	mov bx, 3

init_1st_page:

	mov cx, 0x100		; this is the problem
	stosw
	xchg bx, ax
	stosw
	add bx, 0x1000
	xchg ax, bx
	loop init_1st_page
       
	mov cx, 0x200
	xor ax, ax
	rep stosd

init_2nd_page:

	mov cx, 0x10
	rep stosd
	mov cx, 0x3F0		; this is the problem
	mov eax, 0x10000
	mov ebx, 3
	stosw
	xchg ebx, eax
	stosw
	xchg eax, ebx
	add eax, 0x1000
	loop init_2nd_page
After some analysis I might suggest this solution, but note that this solution is not the best and the most size eficient and somehow else optimal:

Code: Select all

        mov ax, 0x9C00
        mov es, ax
        xor di, di

        xor dx, dx
        mov ax, 3		; dx:ax = page table entry. AX bits 0-11 are flags!!

        mov cx, 0x100		; ID map first Mb
	call fill_pt

        xor ax, ax

        mov cx, (0xC00)*2	; unmap everything else
        rep stosw

        mov cx, (0x10)*2	; unmap first 64Kb
        rep stosw


        mov dx, 1
        mov ax, 3		; dx:ax = 00010003

        mov cx, 0x3F0		; map the rest of first 4 Mb
	call fill_pt

;; put this function somewhere at the end of your code
;; In:	dx:ax - base address with page table entry flags
;;	es:di - page table (4Kb aligned)
;;	cx - count of entires to fill
fill_pt:
        stosw			; store low word
        xchg dx, ax
        stosw			; store high word
        xchg ax, dx
        add ax, 0x1000
	adc dx, 0
        loop fill_pt
	ret
Post Reply