Hi, I am having a lot of trouble with this code.


;disk buffer
mov ax, word   ; 0x1000
mov es, ax
xor bx, bx

mov ax, 0x90 ;start at 4:0-1 (144 sector) :: TEMP -- will obtain sector via code eventually

.loop:
pusha
call linear_to_chs      ; checked, OK
call kread_cylinder    ; checked, OK
popa

pusha
add word , 512
mov ax,
mov es, ax
xor bx, bx
popa

add ax, 18 ;progress next 18 sectors

pusha
xor dx, dx
test dx, dx
jnz .no_marker
;progress marker
;mov al, 0xDB
;call kputchar
.no_marker:
popa

cmp ax, 0x91 + ((0x400*24)/0x200)
jle .loop

;stop motor
mov dx, 0x3F2
xor al, al
out dx, al

push ds
push es
pushad

mov cx, 0
mov es, cx
mov ds, cx
mov esi, 0x10000
mov edi, 0x100000
mov ecx, (0x400*24)/4  ; size of kernel :: TEMP -- will obtain actual size via code eventually
a32 rep movsd

popad
pop es
pop ds

ret


What happens is I begin in real mode and I jump to org 0x2000. Then I setup A20 and GDT stuff, after which I enter Unreal Mode and I then attempt to run the above code which should load my kernel from floppy disk into memory at 0x100000.


cli

mov eax, cr0
or al, 1
mov cr0, eax

jmp dword 0x8: _protected ; switch to 32 bits



_protected:

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

mov esp, 0x200000 - 0x10

push vbe_info

call 0x100000 ; start kernel


I then jump to Protected Mode and I attempt to then jmp to 0x100000, but the system hangs. I verified that I have loaded the entire kernel to the address 0x100000 correctly by comparing the data at 0x100000 to an incbin'd copy of the same kernel. I also double-checked my results against a hex editor. I am loading a flat binary, so I should be able to jump right to it, but for some reason I cannot. I am hoping that someone with better ASM skills than I can take a look at my code and help me fix it. I am completely stuck in this one spot and I would really appreciate the help. So, thanks in advance.

Dave
Posted on 2010-06-02 18:33:50 by DaveT
Your attempt to relocate the kernel will (should) fail. To ensure that Unreal Mode is achieved, the segment selectors in question must be set while in Protected Mode. Any attempt to change them while back in Real Mode can be unpredictable.

Also, DS/ES, if intended to be used via Unreal Mode, would be invalid in your example... GDT entry 0 is designed to be a NULL entry.

Please review Unreal Mode @ OSDev.org Wiki for a working example.
Posted on 2010-06-02 18:52:38 by SpooK
Hi, I do enter unreal mode by first switching to protected mode. I'm sorry I didn't say all that originally. Here is that code.


enter_unreal_mode:
mov eax, cr0
inc ax
mov cr0, eax
jmp 8:.pm_entry

.pm_entry:
mov ax, 0x10
mov ds, ax
mov es, ax

mov ax, 0x38
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x30:.pm_return


.pm_return:
mov eax, cr0
dec ax
mov cr0, eax
jmp 0:.rm_entry

.rm_entry:
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax

ret


Shouldn't I be able to relocate my kernel having done the above?

Posted on 2010-06-02 19:30:15 by DaveT

Shouldn't I be able to relocate my kernel having done the above?


I don't see any reference to the GDT you are using. Please list that information as well.
Posted on 2010-06-02 22:56:21 by SpooK
Hi, here is my GDT:


gdt:
dw 0, 0, 0, 0

db 0xFF
db 0xFF
db 0x00
db 0x00
db 0x00
db 10011010b
db 0xCF
db 0x00

db 0xFF
db 0xFF
db 0x00
db 0x00
db 0x00
db 10010010b
db 0xCF
db 0x00

db 0xFF
db 0xFF
db 0x00
db 0x00
db 0x00
db 11111010b
db 0xCF
db 0x00

db 0xFF
db 0xFF
db 0x00
db 0x00
db 0x00
db 11110010b
db 0xCF
db 0x00

db 0x00
db 0x00
db 0x00
db 0x00
db 0x00
db 0; 10001001b
db 0; 01000000b
db 0x00

;; code segment for realmode
db 0xFF, 0xFF
db 0, 0, 0
db 0x9A
db 0x8F, 0

;; data segment for realmode
db 0xFF, 0xFF
db 0, 0, 0
db 0x92
db 0x8F, 0

gd_reg:
dw 8192
dd gdt


I hope this helps. I've been banging my head against the wall for a week because of my inability to move past this. Thanks for helping me with this.
Posted on 2010-06-03 00:59:29 by DaveT

Hi, here is my GDT:


Also where you use the lgdt instruction.

At this rate, it's better to attach/upload all the files that comprise the boot loader... easier to analyze as a whole.
Posted on 2010-06-03 01:42:54 by SpooK
Well, I've pretty much gave you everything relevant to my issue. I load the GDT right at the start of my loader. This would be the second stage. I setup the stack: mov sp, 0xFFF0, install A20 and trust me, there is nothing of interest there. Then I xor ax and mov it into ds. Next I lgdt my GDT. And, then a plethora of irrelevant things occur. Next, we come to the code I am having issues with (i.e., relocating the kernel and jumping to it). And, that is basically everything. I hope this helps.
Posted on 2010-06-03 01:51:37 by DaveT
Conventionally -- between your code, explanation and analysis -- it looks like it should work.

Is the kernel code you are loading set to do nothing but jmp $, as a sanity check?
Posted on 2010-06-03 03:33:12 by SpooK
DaveT,

Below is small working example (FASM) of loading flat descriptor for ds and using it to display blinking smiling face in upper-left corner.

        org    0x7C00
        cli
        mov    eax, cr0
        push    eax
        or      eax, 1
        mov    cr0, eax
        lgdt   
        mov    ax, 8
        mov    ds, ax
        pop    eax
        mov    cr0, eax
        sti
        mov    , word 0x8f01
        jmp    $

gdtr:  dw      gdt.limit
        dd      gdt

gdt    dq      0
        dw      -1, 0          ; flat r/w PL 0 present 16-bit data descriptor (selector 8)
        db      0, 10010010b, 10001111b, 0
gdt.limit = $-gdt-1

        rb      $$+510-$
        db      0x55, 0xAA


Compare it to your code and decide what you've got wrong.
Posted on 2010-06-03 03:36:54 by baldr
Oh, no I hope this wasn't supposed to jump out at me. Here is what I do:


xor ax, ax
mov ds, ax

lgdt ; install GDT


I thought I should also mention that my code was originally working before I decided to further develop it. I was originally incbin my kernel and I would load a bunc of sectors to memory, then right before the jmp to my kernel, I would rep movsd the start of the incbin'd kernel, and jmp to the kernel at 0x100000.

No, my kernel is a fully working kernel, it should load right up and present a shell terminal.

And, don't let all this code fool you. It took me a very long time to get this far and ASM is not my best language. Thanks for all the help. Any more ideas?
Posted on 2010-06-03 04:11:24 by DaveT
DaveT,

Well, I have one. How do you think, what all those mov segreg, ax after .rm_entry: xor ax, ax will do to corresponding descriptors you've loaded in PM?
Posted on 2010-06-03 05:47:08 by baldr

Well, I have one. How do you think, what all those mov segreg, ax after .rm_entry: xor ax, ax will do to corresponding descriptors you've loaded in PM?


I've expressed this concern in my initial reply, and I never do it that way, but according to Unreal Mode @ OSDev.org Wiki, this should not be an issue.

Still, it's worth a shot to see if that theory holds.

Also, and unless you are loading more than 512KB of kernel in one shot, you could simply relocate the kernel right before the jump to 0010:0000, after you are already in Protected Mode. Obviously, if you have more than 64KB of kernel you'll have to deal with real mode segmenting issues as usual, but that's easy to automate. Even if you don't want to do it this way, it may be a good step in determining what the problem is, as your kernel is only around 9KB anyhow and thus doesn't cross any segment boundaries at the moment.
Posted on 2010-06-03 10:00:32 by SpooK
I think you might have uncovered something that I haven't noticed. My kernel is 24 KB, I thought I loaded all of it correctly, what made you think it was 9KB? Whatever that was, might be my issue.
Posted on 2010-06-03 14:23:24 by DaveT

I think you might have uncovered something that I haven't noticed. My kernel is 24 KB, I thought I loaded all of it correctly, what made you think it was 9KB? Whatever that was, might be my issue.


No, the only thing I've uncovered is that I need to get more sleep :|

It is Indeed 24KB, but that is still under 64KB and is good enough to test in the manner indicated in my last reply.
Posted on 2010-06-03 14:35:30 by SpooK
lol, that's OK. I wouldn't be surprised at all if any of my calculations are off. :)

I tried a few things with that. I tried removing it, I tried setting it to various values, until I realized that I had no idea what I was doing and none of it worked anyway, so I kind of started looking somewhere else. I can tell you this with all certainty. If I incbin my kernel, I could load an n amount of sectors to let's say 0x400000, then once i come out of unreal mode and then jump into protected mode, right before I make the jump to kernel, I could relocate the kernel and make the jump successfully. I guess this tells me that I am not loading the kernel correctly. But, if I read the buffer starting at 0x100000, after all had been loaded, I run it through 256 bytes at a time, and I can confirm that it is all there by comparing it to a hex editor. But, then again, when I test the buffers (i.e., my incbin kernel and the loaded kernel), I notice after 32*256 bytes, they differ, but I just assumed this was probably a mistake I made in my kdump32 routine, since it it compares just fine to the hex editor I used to view my kernel in. I guess I'm not really sure what needs to be different. I don't see it or don't know what it needs to be different. To me, it looks like it should work too. I don't know.

I've just confirmed this:
So, despite all that happens before it.
If I incbin my kernel:

krnl32Bin:
incbin 'kernel'


I can do this:



_protected:

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

mov esp, 0x200000 - 0x10

mov esi, krnl32Bin ;start of kernel
mov edi, 0x100000 ;kernel origin (0x00100000)
mov ecx, (0x400*24/4) + 1   ;end of kernel
rep movsd

call 0x100000 ; start kernel


And, my kernel loads right up.
Posted on 2010-06-03 14:53:59 by DaveT
How about add word , (512 >> 4) instead of add word , 512?
Posted on 2010-06-03 15:38:27 by SpooK
You almost made me choke on my sandwich. lol. That did it!!!!!!!!!!!!!!!! I had to do ((512*18) >> 4) and it worked! Thank you so much. Words can't express how happy I am. Thank you!
Posted on 2010-06-03 15:50:17 by DaveT
No problem. I overlooked that about 5 times, as initially it sounded like your loading mechanism was working as expected.

When you said 32*256, I thought 32*256 = 8192 = 0x2000 = (0x0200 << 4), with 0x0200 (512) obviously being the standard sector size, which lead me to double check your segmentation arithmetic.

Posted on 2010-06-03 15:58:14 by SpooK

I've expressed this concern in my initial reply, and I never do it that way, but according to Unreal Mode @ OSDev.org Wiki, this should not be an issue.

Still, it's worth a shot to see if that theory holds.


I stand corrected: mov segreg, value appears to update only descriptor's base (with 0x10*value). Yet I remember those issues back in the 486 days (limit was reset to 64 KiB) on something like Am5x86/Cx6x86. They probably were built up to Intel specs (while in fact only cs descriptor's limit behaved so).

----8<----
DaveT,

It seems that I've spotted something. Your ss descriptor is 16-bit (B bit is 0), so when IRQ occurs, only ip is saved/restored, and after iret CPU lands somewhere in first 64 KiB (I don't have ICE hardware, this was tested under Bochs and, partially, on real CPU; also see CPU manual).

The same for jmp/jcc: without opsize prefix target offset is masked with 0xFFFF.

Probably you may try to address HMA as usual (0xFFFF:offset), though this will limit the kernel to 64 Ki-16 bytes.
Posted on 2010-06-03 17:10:30 by baldr
As far as i'm concerned, the info in the link posted
When this register given a "selector", a "segment descriptor cache register" is filled with the descriptor values, including the size (or limit). After the switch back to real mode, these values are not modified, regardless of what value is in the 16-bit segment register.

is incorrect.
As said, unreal mode just consists in using cr0.pe = 1 in order to alter the LIMIT field of some segment descriptors, which are not accessible in real mode, except the BASE value through segregs. Once altered, jusmp back to RM and everything is as usual except the limit field, so you can use 32b offsets. Before doing this, you could use 32b offsets via data size override prefixes too but it would hang on exception.
So, on return, it acts like before : moving things to seg regs alters BASE value the same way as before : linear base = value *16.
Else ints and irqs, which do things like pop cs or ds, would not work anymore.

Interesting to see people still struggling with this :)
Posted on 2010-06-04 00:20:38 by HeLLoWorld