Page 2 of 2
Re: I can't switch to 32-bit protected mode.
Posted: Mon Jun 20, 2011 12:00 am
by Chandra
gerryg400 wrote:The solution is, as Combuter posted just 5 minutes after the question was asked and that Owen clarified shortly after, this ....
Code: Select all
GDTInfo:
dw GDTEnd - GDTStart - 1
dd GDTStart ; <<===== This should be a linear address calculated at RUNTIME equal to GDTStart + (DS >> 4) NOT a segment relative value
It's very frustrating that the answer when given was simply ignored.
I don't see why you've to calculate the linear address at RUNTIME. The ORG directive is already specified, which tells the assembler at what
offset the code is to be linked. Now since the only problem is that we don't know what the segment is likely to be when the control is transferred to this code, that can be resolved by simply setting up the segment registers at the start of code so that all the CS:IP and DS:offset pair references to the memory locations where this code was orignally linked. I'm not saying that calculating the linear address is not the solution, I'm just saying that there are simpler alternatives.
Cheers.
Re: I can't switch to 32-bit protected mode.
Posted: Mon Jun 20, 2011 12:11 am
by gerryg400
Now since the only problem is that we don't know what the segment is likely to be when the control is transferred to this code,
Actually that's not the (only) problem. The problem is that LGDT needs a linear address not a segment relative address.
Lets say that DOS has loaded the COM file at 0x5000. This would mean that CS=DS=0x500. Also let's assume that the ORG directive has caused GDSStart to be at the segment relative address 0x120.
To make the LGDT work correctly GDSStart must be 0x5120. The only way to do that is to read DS, multiply by 16 and add 0x120
Re: I can't switch to 32-bit protected mode.
Posted: Mon Jun 20, 2011 12:41 am
by Chandra
gerryg400 wrote:Actually that's not the (only) problem. The problem is that LGDT needs a linear address not a segment relative address.
True. LGDT needs a linear address. But it's upto the assembler to pass the address of the label
GDTStart as an operand to the LGDT instruction, when spitting the final binary. And if I'm not wrong, it uses one of the segment register(as it is) and then supplies the offset portion equivalent to memory location of
GDTStart. Now since the offset is already specified by the
ORG directive, all we need to do is make sure all the segment registers are properly set so that
segment:offset references necessarily point to the linear address of the GDT in memory. If that's done, the final address passed would be a valid linear address.
Re: I can't switch to 32-bit protected mode.
Posted: Mon Jun 20, 2011 1:11 am
by gerryg400
There is just no way that the assembler can know (at assemble or link time) where in memory DOS will load a COM file. The thing about COM files is that they are loaded within a single 64k segment and have no knowledge of other segments unless that information is calculated at runtime.
Re: I can't switch to 32-bit protected mode.
Posted: Mon Jun 20, 2011 1:25 am
by Combuster
Chandra wrote:But it's upto the assembler to pass the address of the label GDTStart as an operand to the LGDT instruction, when spitting the final binary. And if I'm not wrong, it uses one of the segment register(as it is) and then supplies the offset portion equivalent to memory location of GDTStart. Now since the offset is already specified by the ORG directive, all we need to do is make sure all the segment registers are properly set so that segment:offset references necessarily point to the linear address of the GDT in memory. If that's done, the final address passed would be a valid linear address.
No, no, no. DOS is not a bootloader that loads your code at a fixed physical address, but an OS that supports some (neanderthal form of) multitasking and can have multiple programs loaded in memory at once. It can do that because programs expect DOS to set CS/DS/ES to the location where it loads the program. That trick makes all 16-bit offsets correct independent of where the program was loaded and thus avoids all need for linking at run time (something you still need to do for DOS .EXE files).
The flipside of this is that you can not assume what the value of CS/DS is and that the assembler or linker cannot possibly generate physical addresses (after all, it does not know DS and therefore can't compute the needed segment * 16 + offset). Specifically, segment will never ever be zero, since that would imply that your code doubles as the interrupt vector table.
Even worse, suggesting to change CS/DS at runtime shows your lack of real-mode experience. Changing segment registers does not magically move the actual data in physical memory, and so the location of the GDT and GDTR will still be at initial segment * 16 + offset. Which is that very physical address you don't know at link time.
Homework for Chandra: write a bootloader that also works when it isn't loaded at 0x7C00 but rather any unused location in RAM. Your task will be to load sector 2 of the boot drive directly after the bootloader. The only thing you know is that it jumps to the first byte in it (which can be
any CS and
any IP). To make it easy, you may assume SS:SP already points to a valid stack not overlapping anything else. At least, please refrain from contributing to discussion until you have tested an implementation of this exercise, or you tested and confirmed a working fix for the OP's program.
Re: I can't switch to 32-bit protected mode.
Posted: Mon Jun 20, 2011 1:29 am
by bluemoon
If DOS is no longer needed after you enter protected mode, you may consider relocate your com image to a fixed address, say 0000:7C00 (possibly overwrite DOS memory, but you don't care, right? )
that make it easier to switch between addressing mode since the base & offset will remain the same throughout your code.
Re: I can't switch to 32-bit protected mode.
Posted: Mon Jun 20, 2011 2:19 am
by Chandra
Even worse, suggesting to change CS/DS at runtime shows your lack of real-mode experience.
No, infact it suggests my lack of experience with DOS. Yes, I was wrong because I was assuming DOS would load the COM file within the first 64k segment. I apologize for stupid argument.
Homework for Chandra: write a bootloader that also works when it isn't loaded at 0x7C00 but rather any unused location in RAM.
Oh come on, don't act childish. I've written lots of position independent codes, and I don't need to prove myself. That's insulting.
Re: I can't switch to 32-bit protected mode.
Posted: Mon Jun 20, 2011 9:40 am
by ThatGuy2244
gerryg400 wrote:My apologies. If your code is working add "[Solved]" to the subject line of the thread and we can consider the thread closed.
In response to gerryg400: This is not why I started this thread, yes I have gotten my code to work in 16 bit mode, but I started the thread for help switching to 32-bit mode.
With all these different suggestions I'm starting to get confused on what I should do.
But I have also have tried to do "dd GDTStart + (ds << 4)" as suggested and the nasm said I couldn't do that by giving an error.
Re: I can't switch to 32-bit protected mode.
Posted: Mon Jun 20, 2011 11:15 am
by Combuster
ThatGuy2244 wrote:But I have also have tried to do "dd GDTStart + (ds << 4)" as suggested and the nasm said I couldn't do that by giving an error.
Earlier, I wrote:after all, it [the assembler] does not know DS and therefore can't compute the needed segment * 16 + offset
Earlier, gerryg400 wrote:This should be a linear address calculated at RUNTIME equal to GDTStart + (DS << 4)
Actually reading helps.
With all these different suggestions
Of which the wrong ones have been bashed over and over. Again, reading helps.
Re: I can't switch to 32-bit protected mode.
Posted: Mon Jun 20, 2011 11:55 am
by ThatGuy2244
I did calculate it at run time as well and got an error, here is a portion of my code:
Code: Select all
mov ax, ds
shl ax, 4
add [Pointer], ax
lgdt [GDTInfo]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x08:pmode
GDTInfo:
dw GDTEnd - GDTStart - 1
Pointer:
dd GDTStart
Re: I can't switch to 32-bit protected mode.
Posted: Mon Jun 20, 2011 12:14 pm
by Owen
...You're doing a 16-bit arithmetic on a 20-bit number...