Page 1 of 1

bochs and unreal mode

Posted: Mon May 21, 2007 10:42 am
by Lauwe
I'm having trouble using my unreal mode bootloader in bochs. I have enabled A20, set up my GDT, switched to protected mode, changed DS and switched back to real mode. But when i try to write some data to 0x00100000 bochs doesn't seem to want to accept it.

boot.S:

Code: Select all

[BITS 16]
[ORG 0x7C00]
 
%macro   PRINTS   1
 mov  si,%1
 call print
%endmacro
 
jmp   boot
 
boot_msg db 'Starting bootloader..',13,10,0
reboot_msg  db 'Press any key to reboot..',13,10,0
noi386_msg  db 'No i386+ detected..',13,10,0
noA20_msg   db 'A20 line not enabled..',13,10,0
 
reboot:
 PRINTS(reboot_msg)
 xor  ax,ax 
 int  0x16
 db   0x0EA
 dw   0x0000
 dw   0xFFFF

print:
 mov  ax, 0x0E00
 mov  bl, 0x07
.print_nextchar:
 lodsb
 or   al, al
 jz   .print_ret
 int  0x10
 jmp  .print_nextchar
.print_ret:
 ret

wait_kbdbuf:
 in   al, 0x64
 test al, 0x02
 loopnz  wait_kbdbuf
 ret

check_i386:
 pushf
 xor  ah, ah
 push ax
 popf
 pushf
 pop  ax
 and  ah, 0xF0
 cmp  ah, 0xF0
 je   .check_i386_failed
 mov  ah, 0xF0
 push ax
 popf
 pushf
 pop  ax
 and  ah, 0xF0
 jz   .check_i386_failed
 popf
 ret
.check_i386_failed:
 PRINTS(noi386_msg)
 jmp  reboot

enable_a20:
 xor  cx, cx
 call wait_kbdbuf
 mov  al, 0xD1
 out  0x64, al
 call wait_kbdbuf
 mov  al, 0xDF
 out  0x60, al
 call wait_kbdbuf
 push ds
 push es
 xor  ax, ax
 mov  ds, ax
 dec  ax,
 mov  es, ax
 mov  ax,[es:0x10]
 not  ax
 push WORD  [0]
 mov  [0], ax
 mov  ax,[0]
 cmp  ax,[es:0x10]
 pop  WORD  [0]
 pop  es
 pop  ds
 jz   .enable_a20_failed
 ret
.enable_a20_failed:
 PRINTS(noA20_msg)
 jmp  reboot

go_unreal:
 push ds
 lgdt [gdtr]
 mov  eax, cr0
 or   al,0x01
 mov  cr0, eax
 mov  bx, 0x08
 mov  ds, bx
 and  al, 0xFE
 mov  cr0, eax
 pop  ds
 ret


boot:
 cli
 xor  ax, ax
 mov  ds, ax
 mov  es, ax
 mov  ax, 0x9000
 mov  ss, ax
 mov  sp, 0xFFFF
 PRINTS(boot_msg)
 call check_i386
 call enable_a20
 call go_unreal
 mov  bx, 0xDADA
 mov  edi, 0x100000
                                        ;next instruction causes problems
 mov  [ds:edi], bx
 jmp  reboot

gdtr:
 dw   gdt_end - gdt_null - 1
 dd   gdt_null

gdt_null:
 db   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
gdt_data:
 db   0xFF, 0xFF, 0x00, 0x00, 0x00, 10010010b, 01001111b, 0x00
gdt_end:

times 510-($-$$)  db 0
dw 0xAA55
dump_cpu gives me the following when i break just before the ' mov [ds:edi], bx':
eax:0x00000010, ebx:0x0000dada, ecx:0x0000fffd, edx:0x00000000
ebp:0x00000000, esp:0x0000ffff, esi:0x00007c1b, edi:0x00100000
eip:0x00007d33, eflags:0x00000002, inhibit_mask:0
cs:s=0x0000, dl=0x0000ffff, dh=0x00009b00, valid=1
ss:s=0x9000, dl=0x0000ffff, dh=0x00009309, valid=7
ds:s=0x0000, dl=0x0000ffff, dh=0x004f9300, valid=1
es:s=0x0000, dl=0x0000ffff, dh=0x00009300, valid=1
fs:s=0x0000, dl=0x0000ffff, dh=0x00009300, valid=1
gs:s=0x0000, dl=0x0000ffff, dh=0x00009300, valid=1
ldtr:s=0x0000, dl=0x0000ffff, dh=0x00008200, valid=1
tr:s=0x0000, dl=0x0000ffff, dh=0x00008300, valid=1
gdtr:base=0x00007d40, limit=0xf
idtr:base=0x00000000, limit=0xffff
dr0:0x00000000, dr1:0x00000000, dr2:0x00000000
dr3:0x00000000, dr6:0xffff0ff0, dr7:0x00000400
cr0:0x00000010, cr1:0x00000000, cr2:0x00000000
cr3:0x00000000, cr4:0x00000000
when executing the mov
(0) [0x00007d33] 0000:7d33 (unk. ctxt): mov word ptr ds:[edi], bx ; 3e67891f
bochs debug gives me this:
00001451421d[CPU ] write_virtual_checks(): write beyond limit (real mode)
00001451421d[CPU ] exception(0x0D)
00001451421d[CPU ] interrupt(): vector = 13, INT = 0, EXT = 1
Is it me, am i missing something or doing something completely wrong? or is it bochs? Most of the unreal-related code is taken from the babysteps-tutorial and writing the smiley to the screen like in the tutorial works without any problems.

edit: also, what are the dl, dh and valid fields next to the segment-registers in dump_cpu?

Posted: Mon May 21, 2007 1:12 pm
by Combuster
it has to do with what you put in the GDT. the 10010010b, 01001111b part says the following:
present (1), DPL=0 (00), data segment (10), expand-up (0), writable (1), not accessed (0)
byte-granular (0), big (1), unused(00), top 4 bits of limit(1111)

now when you load ds the limit is calculated: the limit bits are taken and concatenated: 0xfffff, making an offset of 0xfffff the highest address that can be addressed without error. the 1mb mark is 0x100000, one byte further. The result is a completely valid GPF

To change the limit to 4GB instead of 1MB you should set the granularity bit (01001111b becomes 11001111b). This multiplies the limit by 4096 so that it becomes 0xfffff * 4096 + 0xfff = 0xffffffff which is probably what you want.

Posted: Mon May 21, 2007 2:29 pm
by Lauwe
Thank you, this was indeed the problem. I guess this is what happens when you blindly copy code without fully understanding it.

Posted: Tue May 22, 2007 1:22 pm
by xsix
yes, that's whysometimes OS's bugs are being fixed for a very long time, cause programmer uses code, which he doesn't understand and that's why it is the best to understand and write your own code

Posted: Tue May 22, 2007 2:16 pm
by Candy
Lauwe wrote:Thank you, this was indeed the problem. I guess this is what happens when you blindly copy code without fully understanding it.
I think this bug is in the code on the Wiki, since I've copied that (yep - mostly the GDT) and hit the same error.

Posted: Tue May 22, 2007 4:03 pm
by Combuster
Candy wrote:I think this bug is in the code on the Wiki, since I've copied that (yep - mostly the GDT) and hit the same error.
Went ahead and fixed it. It must've been one nasty bug to make even the guru here trip over it :D

Posted: Thu May 24, 2007 9:38 am
by Candy
Combuster wrote:
Candy wrote:I think this bug is in the code on the Wiki, since I've copied that (yep - mostly the GDT) and hit the same error.
Went ahead and fixed it. It must've been one nasty bug to make even the guru here trip over it :D
Not so much the bug that caused a delay, Bochs didn't properly simulate the triple fault that should've followed. Bug report filed a week ago or so.

Posted: Mon May 28, 2007 5:21 am
by Combuster
I wouldn't expect a triple-fault: the segment limit > 64k, when accessing 1Mb it will GPF, the fault handler will be loaded from the IVT, which sends execution to the bios which will then try do something with that. Most likely it will halt the processor at some point.

Posted: Mon May 28, 2007 5:29 am
by Candy
Combuster wrote:I wouldn't expect a triple-fault: the segment limit > 64k, when accessing 1Mb it will GPF, the fault handler will be loaded from the IVT, which sends execution to the bios which will then try do something with that. Most likely it will halt the processor at some point.
At the best case, it shouldn't freeze up at that instruction. I was thinking about it for a moment, given the segment limit you'd expect a GPF, given that it's realmode you'd expect it not to give a GPF (since real mode doesn't have GPFs). That's why I expected it to somehow reboot.

Posted: Mon May 28, 2007 6:52 am
by Combuster
IMO lockups are better than triple-faults - they allow you to read any debug information that you have printed before the error.

Besides, locking up on an exception is afaik typical behaviour for the PC bios, so at any rate I wouldn't call it a bug. Its more like a feature. Agreed though that an error message might be more appropriate.