Page 1 of 1
protected mode, but still 64k limit on esp
Posted: Wed Jun 13, 2007 7:15 am
by spectrum
hi all,
i've some trouble after have switched to protected mode: all is working fine, except for the stack. I've created a GDT, with a code, and data/stack segment descriptors. Segment limit is at 0xFFFFFF, granularity at 4K. For some reason, if i set "esp" register to a value greater than 0xffff, (major than 64K), all the stack read/write operations fail.
I attach the pm mode setup steps, and gdt.
Code: Select all
jmp $8, $protected
/* clear 16 bit pipeline garbage */
.code32
protected:
mov $datasel, %ax
mov %ax, %ds
mov %ax, %ss
mov %ax, %fs
mov %ax, %es
movl $0x10000, %esp
mov $videosel, %ax
mov %ax, %gs
call _kmain
gdtinfo: .word (gdtend - gdt -1)
.long gdt
gdt: .long 0 /* null descriptor, as per convention gdt0 is 0 */
.long 0
.equ codesel, .- gdt
desc_code: /* 32bit Flat Data, 0-4GB Writable */
.word 0xFFFF /* segment limit 0:15 */
.word 0 /* base address 0:15 */
.byte 0 /* base address 16:23 */
.byte 0x9A /* 1xP|2xDPL|1xS|4xtype 0x9A = 1|0 0|1|1010 */
.byte 0xCF /* 1xG|1xD/B|1x0|1xAVL|4xlimit 0xCF = 1|1|0|0|1111 */
.byte 0 /* base address 24:31 */
.equ datasel, .- gdt
desc_data:
.word 0xFFFF /* segment limit 0:15 */
.word 0 /* base address 0:15 */
.byte 0 /* base address 16:23 */
.byte 0x92 /* 1xP|2xDPL|1xS|4xtype 0x92 = 1|0 0|1|0010 */
.byte 0xCF /* 1xG|1xD/B|1x0|1xAVL|4xlimit 0xCF = 1|1|0|0|1111 */
.byte 0 /* base address 24:31 */
.equ videosel, .- gdt
desc_video:
.word 3999 /* segment limit 0:15 */
.word 0x8000 /* base address 0:15 */
.byte 0x0b /* base address 16:23 */
.byte 0x92 /* 1xP|2xDPL|1xS|4xtype 0x92 = 1|0 0|1|0010 */
.byte 0x00 /* 1xG|1xD/B|1x0|1xAVL|4xlimit 0x00 = 0|0|0|0|0000 */
.byte 0 /* base address 24:31 */
gdtend:
Every help or suggestion is very appreciated.
Angelo
[/code]
Re: protected mode, but still 64k limit on esp
Posted: Wed Jun 13, 2007 7:57 am
by Brendan
Hi,
Just 2 questions....
Where are you loading SS with the new descriptor? Inside the CPU there's a hidden base address and a hidden limit for each segment, that are only ever changed when the segment register itself is changed. Unless you do something like "mov $datasel, %ax; mov %ax, %ss" the hidden base and limit of SS won't change.
Why do you need "desc_video" if you can access video display memory via. "desc_data" without messing about with segment registers or using segment override prefixes (which don't work for instructions like "rep stosw")?
Cheers,
Brendan
Posted: Wed Jun 13, 2007 8:42 am
by spectrum
hi brendan,
thanks for the reply
the
mov $datasel, %ax
mov %ax, %ds
mov %ax, %ss
has been done, as you can see in the code i posted. So %ss and %ds point to the same data/stack descriptor entry of gdt. It should be right.
about the "desc_video", i know. It's still there since i've started from a sample code. Sure, i can access it in the data addrress space.
angelo
Posted: Wed Jun 13, 2007 9:56 am
by jnc100
Your code looks okay at first glance, so can I ask how do you know that there is a problem with stack operations? Is it from a bochs error? If so, could we see the error you get?
Regards,
John.
Posted: Thu Jun 14, 2007 1:36 am
by spectrum
thanks,
in particular,
the problem happen after i call _kmain(), that is the first C protected mode code routine.
If i set esp to a value > 64K, when i allocate an array on the stack, any adressing reference on the array is not working, seems like i'm not writing or reading from the right memory address.
Code: Select all
void foo ()
{
char array[1024];
array[0] = 't';
array[1] = 'e';
array[2] = 's';
array[3] = 't';
array[4] = 0;
kprint(array);
}
but i get nothing as output on the screen.
Instade, if i set %esp to < 64K, the same routine works.
Disassembled code seems using the stack segment esp in the right way.
Thanks again , angelo
.
Posted: Thu Jun 14, 2007 6:16 am
by Brendan
Hi,
Sorry about earlier - you're right SS is being set correctly, and jnc100 is also right (nothing looks wrong in any of the code posted).
spectrum wrote:If i set esp to a value > 64K, when i allocate an array on the stack, any adressing reference on the array is not working, seems like i'm not writing or reading from the right memory address.
Something about that "> 64K" seems too neat to be a pure coincidence to me though...
Anyway, is there something like a bootable floppy I could download and run on Bochs (that has ESP set to a value > 64K)? Sometimes watching each instruction execute is the easiest way of finding out exactly what is going on...
Cheers,
Brendan
Posted: Thu Jun 14, 2007 6:47 am
by os64dev
just for getting it straight. you've mapped the pages after the 64 KiB right? Assuming that you use pageing?
could you also give information regarding your memory map, system table etc. it might be helpfull.
Posted: Fri Jun 15, 2007 2:48 am
by spectrum
sorry for the late reply, i've got some time to install bochs(very very good tool) .
jnc100:
i've create a little hd (2M) image for you, so you can see what happen.
i've set the stack to
movl $0x20000, %esp
just to go over 64K.
than, after switching to protected mode, i call the _kmain, as in the code below, end just after a foo routine
Code: Select all
void foo ()
{
char array[1024];
array[0] = 't';
array[1] = 'e';
array[2] = 's';
array[3] = 't';
array[4] = 0;
kprint (_KM "test foo, = ");
kprint (array);
kprint ("\r\n");
}
this code display nothing (prob a 0 in memory),
os64dev:
probably this is the issue, i didn't set up any paging management, i have ony enabled A20 gate, but i was expecting that i could adress over 64K also without paging, but probably i should set up some pages, as you said.
angelo
Posted: Fri Jun 15, 2007 3:58 am
by os64dev
well paging is not required to do the stuff you want, but an os with virtual memory can not do without paging.
Posted: Fri Jun 15, 2007 5:07 am
by Brendan
Hi,
The problem seems to be in your "kprint" function - it uses SI to access the string it's printing, instead of ESI. This means when you want to print any string that is in memory above 64 KB it won't work (regardless of whether it's on the stack or not), and the stack itself is working well.
Your complete "kprint" function is:
Code: Select all
00007e7b: push ebp ; 55
00007e7c: mov ebp, esp ; 89e5
00007e7e: push esi ; 56
00007e7f: push ebx ; 53
00007e80: movzx ebx, byte ptr ds:0x96a1 ; 0fb61da1960000
00007e87: movzx edx, byte ptr ds:0x96a0 ; 0fb615a0960000
00007e8e: mov esi, dword ptr ss:[ebp+0x8] ; 8b7508
00007e91: mov eax, 0x00000050 ; b850000000
00007e96: mov cl, byte ptr ds:[si] ; 678a0c
00007e99: test cl, cl ; 84c9
00007e9b: jz .+0x00000033 ; 7433
00007e9d: cmp cl, 0x0a ; 80f90a
00007ea0: jnz .+0x00000010 ; 7510
00007ea2: inc bl ; fec3
00007ea4: cmp bl, 0x19 ; 80fb19
00007ea7: jl .+0x00000023 ; 7c23
00007ea9: dec bl ; fecb
00007eab: call .+0xffffffa1 ; e8a1ffffff
00007eb0: jmp .+0x0000001a ; eb1a
00007eb2: cmp cl, 0x0d ; 80f90d
00007eb5: jnz .+0x00000004 ; 7504
00007eb7: xor dl, dl ; 30d2
00007eb9: jmp .+0x00000011 ; eb11
00007ebb: mul al, bl ; f6e3
00007ebd: add ax, dx ; 6601d0
00007ec0: shl ax, 1 ; 66d1e0
00007ec3: mov byte ptr gs:[eax], cl ; 658808
00007ec6: mov byte ptr gs:[eax+0x1], 0x0e ; 65c640010e
00007ecb: inc edx ; 42
00007ecc: inc si ; 6646
00007ece: jmp .+0xffffffc1 ; ebc1
00007ed0: mov byte ptr ds:0x96a1, bl ; 881da1960000
00007ed6: mov byte ptr ds:0x96a0, dl ; 8815a0960000
00007edc: pop ebx ; 5b
00007edd: pop esi ; 5e
00007ede: pop ebp ; 5d
00007edf: ret ; c3
The problem is this instruction:
Code: Select all
00007e96: mov cl, byte ptr ds:[si] ; 678a0c
I don't know if you're doing something unusual with type casts or perhaps doing a "source = source & 0xFFFF", or if GCC is stuffing it up...
Cheers,
Brendan
Posted: Fri Jun 15, 2007 7:45 am
by spectrum
many thanks to all, this is a great forum, with a great support!
brendan, infinite thanks, i really hope you haven't lost too much time to debug my bad code.
Stupid me!! The error is just there as you have seen it, i've written the kprint routine in assembly, and used %si intade of 32bit %esi.
I would really like to debug myself with bochs, but my linux version (2.3) seems not to allow the instruction steps/disassembly.
Btw, thanks all again
Angelo
Posted: Fri Jun 15, 2007 8:12 am
by Brendan
Hi,
spectrum wrote:brendan, infinite thanks, i really hope you haven't lost too much time to debug my bad code.
It doesn't take me too long - it's the way I normally debug my own messed up code..
spectrum wrote:I would really like to debug myself with bochs, but my linux version (2.3) seems not to allow the instruction steps/disassembly.
There's a large number of compile-time options for Bochs - if it should support FPU, or MMX, or SSE, APICs, PCI, VBE, long mode, etc. One of these options is " --enable-debugger" and another is "--enable-disasm" and (if your system has the relevant library) another is "--enable-readline".
What I do is have a collection of different scripts to configure Bochs to emulate different CPUs - one for 80486, one for Pentium, one for PentiumPro, etc. Then I have 2 versions of each script - one for no debugging and one with all the debugging options.
I use these scripts to build many different versions of Bochs and assign some of them to keyboard shortcuts, so that (for e.g.) pressing the F5 function key starts an 80486 version of Bochs with no debugging, pressing Shift+F5 starts an 80486 version of Bochs with all the debugging, pressing F8 or Shift+F8 starts a Pentium 4 emulation, etc.
Anyway, I'm guessing the version of Bochs you've got wasn't configured with the debugging options....
Cheers,
Brendan
Posted: Fri Jun 15, 2007 9:48 am
by urxae
Brendan wrote:spectrum wrote:I would really like to debug myself with bochs, but my linux version (2.3) seems not to allow the instruction steps/disassembly.
[snip]
Anyway, I'm guessing the version of Bochs you've got wasn't configured with the debugging options....
Or it was, but he was referring to the bug that doesn't allow stepping when a breakpoint is hit. I hate that one, but luckily it's easy enough to work around (IIRC by using "next" instead of "step").
Posted: Sun Jun 17, 2007 2:28 pm
by Candy
urxae wrote:Brendan wrote:spectrum wrote:I would really like to debug myself with bochs, but my linux version (2.3) seems not to allow the instruction steps/disassembly.
[snip]
Anyway, I'm guessing the version of Bochs you've got wasn't configured with the debugging options....
Or it was, but he was referring to the bug that doesn't allow stepping when a breakpoint is hit. I hate that one, but luckily it's easy enough to work around (IIRC by using "next" instead of "step").
IIRC the 2.3 release didn't allow that in any way (tried next and step, but it kept breaking on the breakpoint). You had to delete the breakpoint, step and re-add it, which is a pain in the *** if you want to hit that breakpoint 10 times.
I have noticed that breakpoints aren't 100% reliable - had a few times that the code just ran on beyond the breakpoint (and since my code usually crashes about 10k instructions later, it usually crashes before I notice).
Posted: Mon Jun 18, 2007 12:38 am
by Brendan
Hi,
Candy wrote:I have noticed that breakpoints aren't 100% reliable - had a few times that the code just ran on beyond the breakpoint (and since my code usually crashes about 10k instructions later, it usually crashes before I notice).
My biggest problem with breakpoints is working out the correct address to place them (searching for the right instruction in a disassembly, for e.g.).
Instead, I tend to use something like this:
Code: Select all
push ecx
xor ecx,ecx
.zz:
jecxz .zz
pop ecx
When Bochs gets to this code it goes into an infinite loop. I press "control+C" to stop Bochs and type "set ecx=1" to break out of the infinite loop, then step from there......
It's still annoying if you hit the same spot 10 times in a loop, but for that you can add some code to branch around the "not-quite-infinite loop" (which can give you very specific control over when to stop and when not to stop).
Cheers,
Brendan