First post, by videogamer555
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
.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