VOGONS

Common searches


First post, by videogamer555

User metadata
Rank Member
Rank
Member

Here's my code for simply switching to protected mode, and then running an infinite loop. Unfortunately it crashes. Below is the full NASM assembly language code for this program. It is fully commented, so you can easily see what each piece of code does. The line of code that isn't working is marked with a comment that has 5 asterisks on each end of the comment. Somebody, please look over my code, and tell me what I'm doing wrong.

USE16 ;start with 16bit code
org 0x100 ;starting offset is 0x100 within the code segment as is required for a DOS .COM file.

Start:
SwitchToProtected:
;calculate linear address of GDT
mov eax,GDT
xor edx,edx
mov dx,ds
lea edx,[edx*4]
lea eax,[edx*4+eax]
mov [GDTD+2],eax ;and place this linear address in the address field of the Global Descriptor Table Descriptor (a small structure containing the linear address and limit of the GDT in memory)

cli ;Prevent any interrupt from ever being used, because if interrupts are used in protected mode, the program will crash
lgdt [GDTD] ;load the CPU's GDTR register with the Global Descriptor Table Descriptor

;Switch into 16bit protected mode
mov eax,cr0
or eax,1
mov cr0,eax

;Switch into 32bit protected mode by doing a far jump
jmp 0x0008:FinalizeProtMode

FinalizeProtMode:
USE32 ;all code from this point forward will need to be 32bit code, so the assembler is now being told to assemble all further code in 32bit mode

;Set the remaining important segment registers to the corresponding GDT entries.
mov ax,0x10 ;*****Execution of this line of code in DOS Box causes a jump in the location of the execution pointer, even though this isn't a JMP instruction. Of course it jumps to an invalid location and crashes.*****
mov ds,ax
mov ax,0x18
mov ss,ax

Loop:
jmp Loop ;Keep the program running by just jumping back and looping indefinitely. Unfortunately, because of the above mentioned crash, the program execution never reaches this point.


GDTD:
dw 32
dd 0

GDT:
GDT_Entry_BLANK:
dq 0

GDT_Entry_CS:
.Limit0 dw 0xFFFF
.Base0 dw 0x1FE0 ;Base of 0x1FE0 corresponds to real mode memory segment 0x1FE, which is the default real-mode Code segment in DOS, or at least in DOS Box.
;This ensures that I don't have to change how the assembler calculates addresses for the remaining code.
.Base1 db 0x00
.Access db 0x9A
.FlagsAndLimit1 db 0x40
.Base2 db 0x00

GDT_Entry_DS:
.Limit0 dw 0xFFFF
.Base0 dw 0x1FE0 ;Base of 0x1FE0 corresponds to real mode memory segment 0x1FE, which is the default real-mode Data segment in DOS, or at least in DOS Box.
;This ensures that I don't have to change how the assembler calculates addresses for the remaining data.
.Base1 db 0x00
.Access db 0x92
Show last 10 lines
 .FlagsAndLimit1 db 0x40
.Base2 db 0x00

GDT_Entry_SS:
.Limit0 dw 0x0FFF
.Base0 dw 0x1FDF
.Base1 db 0x01 ;Base of stack segment starts at the highest address of the data segment.
.Access db 0x96
.FlagsAndLimit1 db 0x40
.Base2 db 0x00

Reply 1 of 18, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

What is the CS and IP after the jump far?

Are you sure you are not supposed to have the base0 as 0x1FE instead of 0x1FE0? The address calculation will take that base shift it left by 4 and then add the offset. Looks like you are preshifting it in the GDT.

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 2 of 18, by videogamer555

User metadata
Rank Member
Rank
Member
vladstamate wrote:

What is the CS and IP after the jump far?

Are you sure you are not supposed to have the base0 as 0x1FE instead of 0x1FE0? The address calculation will take that base shift it left by 4 and then add the offset. Looks like you are preshifting it in the GDT.

Yes. I'm sure it is supposed to be pre-shifted. If it's not preshifted, it ends up in the wrong location immediately after the jump. I've tested this already in the DOSBox Debugger.
If it is pre-shfited, it ends up in the CORRECT location immediately after the jump. However, the moment it tries to execute the next line of code (which is itself not a JMP instruction) it magically does another jump somewhere else, and of course the program crashes after that.

Reply 5 of 18, by videogamer555

User metadata
Rank Member
Rank
Member
ripa wrote:

Try stackoverflow. At least there's a reward in virtual points for looking at other people's buggy code 😉

I doubt that most people even know about old DOS stuff like this. DOS exclusive forums like vogons is my only hope.
Please, just look over my code. I've got a sense that I'm VERY close to the correct code, as it's already mostly doing what it should (and may even simply be an issue involving the difference between DOS Box, and real DOS computers). So I'm guessing I'm only going to need to make a few tweaks. Can you please look over my code and tell me what's wrong with it?

Reply 6 of 18, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

Few questions:

1) How are you debugging this code? Are you using DOS debug.exe? Can you single step the code?
2) If you are single stepping, or at least put a breakpoint at the code AFTER the jmp far, can you show us what the debugger thinks it is at that line of code (including the address)?Try -u command.

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 7 of 18, by mrau

User metadata
Rank Oldbie
Rank
Oldbie

im relatively certain that you cannot view in debug a transition from real to prot mode; i can tell you that for me it was the GDT definition that caused the most trouble - copying sample GDT from wiki might help?

Reply 8 of 18, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

Yes I know you cannot single step the code between mov cr0. ax and the end of the jmp. Because INT 3 will not work due to IDT not working properly. I was hoping he can put a breakpoint AFTER that.

But yes, your advice is good, trying an unmodified example known to work first is a good idea.

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 10 of 18, by mrau

User metadata
Rank Oldbie
Rank
Oldbie

didnt dosbox have some slow stepping mode? or was that bochs maybe? simics certainly does but its commercial i wouldnt even know if it can be had still

regarding the debuggin: i believe theres another problem: after the switch the code that actually outputs the values in registers etc might not work anymore? it is not adjusted to the new memory addressing scheme in my understanding; maybe im wrong here? ill admit i stopped doing this stuff shortly after reaching simple prot mode functionality;

Reply 11 of 18, by mrau

User metadata
Rank Oldbie
Rank
Oldbie
ripa wrote:

You could also try debugging in VirtualBox or some other VM:
https://www.virtualbox.org/manual/ch12.html#ts_debugger

sexy find! wil lthis work with the system debugger only or can all/most debuggers connect like that?

Reply 12 of 18, by ripa

User metadata
Rank Oldbie
Rank
Oldbie

I'm not sure what you mean and I haven't used VirtualBox debugger myself, but I suggested a VM debugger because it shouldn't have any limitations w.r.t debugging transitions between CPU modes because it doesn't rely on patching the code like INT3.

Reply 16 of 18, by mrau

User metadata
Rank Oldbie
Rank
Oldbie
peterferrie wrote:

From where did you get the value 0x1FE0? It's not correct, at least for the DOSBox that I'm using. In my copy, it's 0x1950, and then the Loop label is reached.

its not documented as a stale value, so one should never assume the value but rather calculate it;

Reply 17 of 18, by Azarien

User metadata
Rank Oldbie
Rank
Oldbie

;Switch into 32bit protected mode by doing a far jump
jmp 0x0008:FinalizeProtMode

Shouldn't it be

jmp dword 8:FinalizeProtMode

?

If I remember correctly, you need to fill all 32 bits of EIP, so the jump instruction should have 0x65 prefix to force 32-bit addressing. Otherwise you're writing only to IP, which is low 16 bits of EIP, and when the 32-bit mode kicks in, garbage in high 16 bits of EIP results in "misjump".

Or so I think.

;Switch into 16bit protected mode mov eax,cr0 or eax,1 mov cr0,eax […]
Show full quote

;Switch into 16bit protected mode
mov eax,cr0
or eax,1
mov cr0,eax

This is not "switching into 16bit protected mode", this is enabling protection. Whether it will be 16 or 32-bit depends solely on the segment you're jumping to in the very next instruction.