I can't switch to 32-bit protected mode.

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
Chandra
Member
Member
Posts: 487
Joined: Sat Jul 17, 2010 12:45 am

Re: I can't switch to 32-bit protected mode.

Post 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.
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: I can't switch to 32-bit protected mode.

Post 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
If a trainstation is where trains stop, what is a workstation ?
User avatar
Chandra
Member
Member
Posts: 487
Joined: Sat Jul 17, 2010 12:45 am

Re: I can't switch to 32-bit protected mode.

Post 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.
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: I can't switch to 32-bit protected mode.

Post 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.
If a trainstation is where trains stop, what is a workstation ?
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: I can't switch to 32-bit protected mode.

Post 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.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: I can't switch to 32-bit protected mode.

Post 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.
User avatar
Chandra
Member
Member
Posts: 487
Joined: Sat Jul 17, 2010 12:45 am

Re: I can't switch to 32-bit protected mode.

Post 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.
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
ThatGuy2244
Posts: 15
Joined: Wed Feb 02, 2011 2:15 pm

Re: I can't switch to 32-bit protected mode.

Post 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.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: I can't switch to 32-bit protected mode.

Post 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.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
ThatGuy2244
Posts: 15
Joined: Wed Feb 02, 2011 2:15 pm

Re: I can't switch to 32-bit protected mode.

Post 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
User avatar
Owen
Member
Member
Posts: 1700
Joined: Fri Jun 13, 2008 3:21 pm
Location: Cambridge, United Kingdom
Contact:

Re: I can't switch to 32-bit protected mode.

Post by Owen »

...You're doing a 16-bit arithmetic on a 20-bit number...
Post Reply