Trouble moving into protected mode.
Posted: Fri Mar 17, 2017 10:07 pm
I've written (most) of this simple MBR bootstrap/bootloader. I've gotten up to the point where it load's up to 127 sectors of the first DOS partition with the boot flag set into memory. I've double-triple checked using the QEMU monitor command "pmemsave" that it loads the partition into memory. I've just "dd"ed my kernel right onto the raw partition. Now I'm looking to enter protected mode, and exec my kernel. However, when I far jump to my kernels "_start" address at 0x9000 at a 4K offset from the start of my ELF (which I load into 0x8000), it doesn't seem to be jumping to the correct location, just executing some random somewhere else in memory. I'm using GDB to debug, and I switch architectures to i386 just after I call "kexec".
Here is a link to my full bootloader code, https://github.com/Izzette/izixboot/blob/master/boot.s (GAS syntax). At the very end of the file I've got my protected mode code:
Right at the "ljmp" instruction, things go haywire:
QEMU shows that "cr0" does not have the lowest order bit set.
Here is my kernel "_start", not that I think it matters.
Clearly, I'm not understanding segmentation correctly?
Can anyone kindly point me in the right direction?
Here is a link to my full bootloader code, https://github.com/Izzette/izixboot/blob/master/boot.s (GAS syntax). At the very end of the file I've got my protected mode code:
Code: Select all
// More code up here ...
// The GDT registry
.set gdtr, 0x0500
// Kernel entry point
.set kentryseg, 0x08
.set kentryoffset, 0x8f80
// We're moving into 32-bit protected mode.
.code32
// Enter protected mode and execute the kernel.
// void kexec () {
kexec:
// There's no coming back from here,
// so forget about saving the base pointer.
// push %bp
mov %sp, %bp
// Load the GDT registry.
lgdt gdtr
// set PE (Protection Enable) bit in CR0 (Control Register 0)
mov %cr0, %eax
or $1, %eax
mov %eax, %cr0
ljmp $kentryseg, $kentryoffset
// This function should never return,
// so forget about restoring the stack and base pointers.
// mov %bp, %sp
// pop %bp
// ret
// }
Code: Select all
The target architecture is assumed to be i8086
Breakpoint 1 at 0x7c00
Breakpoint 1, 0x00007c00 in ?? ()
=> 0x00007c00: fa cli
(gdb) b *(0x7e00 + 0x160)
Breakpoint 2 at 0x7f60
(gdb) c
Continuing.
Breakpoint 2, 0x00007f60 in ?? ()
=> 0x00007f60: 66 89 e5 mov %esp,%ebp
(gdb) si
0x00007f63 in ?? ()
=> 0x00007f63: 0f 01 15 lgdtw (%di)
(gdb)
0x00007f66 in ?? ()
=> 0x00007f66: 00 05 add %al,(%di)
(gdb)
0x00007f68 in ?? ()
=> 0x00007f68: 00 00 add %al,(%bx,%si)
(gdb)
0x00007f6a in ?? ()
=> 0x00007f6a: 0f 20 c0 mov %cr0,%eax
(gdb) set architecture i386
The target architecture is assumed to be i386
(gdb) si
0x00007f6d in ?? ()
=> 0x00007f6d: 83 c8 01 or $0x1,%eax
(gdb) si
0x00007f70 in ?? ()
=> 0x00007f70: 0f 22 c0 mov %eax,%cr0
(gdb) si
0x00007f73 in ?? ()
=> 0x00007f73: ea 80 8f 00 00 08 00 ljmp $0x8,$0x8f80
(gdb) si
0x0000e05b in ?? ()
=> 0x0000e05b: 12 16 adc (%esi),%dl
(gdb) si
0x0000e05b in ?? ()
=> 0x0000e05b: 12 16 adc (%esi),%dl
(gdb) info registers
eax 0x0 0
ecx 0x0 0
edx 0x663 1635
ebx 0x0 0
esp 0x0 0x0
ebp 0x0 0x0
esi 0x0 0
edi 0x0 0
eip 0xe05b 0xe05b
eflags 0x2 [ ]
cs 0xf000 61440
ss 0x0 0
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb)
Code: Select all
QEMU 2.8.0 monitor - type 'help' for more information
(qemu) info registers
EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000663
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
EIP=0000e05b EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0000 00000000 0000ffff 00009300
CS =f000 000f0000 0000ffff 00009b00
SS =0000 00000000 0000ffff 00009300
DS =0000 00000000 0000ffff 00009300
FS =0000 00000000 0000ffff 00009300
GS =0000 00000000 0000ffff 00009300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT= 00000000 0000ffff
IDT= 00000000 0000ffff
CR0=60000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
(qemu)
Code: Select all
.code32
.section .text
.global _start
.type _start, @function
_start:
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
mov $0x8000, %esp
mov %esp, %ebp
call kernel_main
cli
freeze:
hlt
jmp freeze
.size _start, . - _start
Can anyone kindly point me in the right direction?