Hi
I'm having trouble with my code that switches to PMode and I'm not sure what I'm doing wrong.
Here is the code:
; Segment Descriptor Defenitions
; 0x00cf9a000000ffff Supervisor code from 0x00000000 to 4GB
; 0x00cf92000000ffff Supervisor data from 0x00000000 to 4GB
; 0x00cffa000000ffff User code from 0x00000000 to 4GB
; 0x00cff2000000ffff User data from 0x00000000 to 4GB
_switch_to_pmode:
cli
; Clearing the first 128KB of RAM with 00s
; ready for the GDT and IDT to be placed into it
; Not the best method, but should work ok
mov cx, 0xFFFF ; Want to clear room for 2KB RAM
.Lower_64K
mov ax, 0
mov es, ax ; Want to clear segement 0
; NOTE!! Interrupts MUST be disabled or
; a crash is certain!!
mov ax, 0
mov bx, cx
mov [es:bx], al
loop .Lower_64K
mov cx, 0xFFFF ; Want to clear room for 2KB RAM
.Upper_64K
mov ax, 0
mov es, ax ; Want to clear segement 0
; NOTE!! Interrupts MUST be disabled or
; a crash is certain!!
mov ax, 1
mov bx, cx
mov [es:bx], al
; loop .Upper_64K
;.setup_idt
;lidt [idtr_details]
.setup_gdt
xor ax, ax
mov es, ax
;------------------------------------
; First Setup the Segment Descriptors
;------------------------------------
; First 0x00 - The Null Selector
mov dword [es:GDT_LOCATION] , 0x00000000
mov dword [es:GDT_LOCATION+4], 0x00000000
; Now 0x08 - the Supervisor mode code segment
mov dword [es:GDT_LOCATION+8] , 0x0000ffff
mov dword [es:GDT_LOCATION+12], 0x00cf9a00
; Now 0x10 - the Supervisor mode data segment
mov dword [es:GDT_LOCATION+16], 0x0000ffff
mov dword [es:GDT_LOCATION+20], 0x00cf9200
; Now 0x18 - the User mode code segment
mov dword [es:GDT_LOCATION+24], 0x0000ffff
mov dword [es:GDT_LOCATION+28], 0x00cffa00
; Now 0x20 - the User mode data segment
mov dword [es:GDT_LOCATION+32], 0x0000ffff
mov dword [es:GDT_LOCATION+36], 0x00cff200
; Finally load the GDT into the GDTR
lgdt [gdtr_details]
;--------------------------------
; Now To switch to Protected Mode
;--------------------------------
mov eax, cr0 ; Read in CR0 Register
or eax, 1 ; Toggle PE Bit
mov cr0, eax ; Save to CR0
[Bits 32]
; That's it, we're in Protected Mode!
; Next, Flush the Prefetch Que
Jmp short .flush
.flush
;-------------------------------
; Now to setup Segment Selectors
;-------------------------------
mov ax, 0x10
mov ds, ax ; Setup data selectors with 0x10 + TI=0b + RPL=00b
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; To change cs, jump to new location
mov ax, 0x08
push ax
push word .ToHere
retf
.ToHere mov byte [ds:0xb8000], 'A'
Jmp $
;pop eax
;retn
; Data #######################################################################
; As this is a tiny mode program, all data is still in the code segment
gdtr_details dw 0xFFFF
dd 0x0800
This program is supposed to first clear the first 128KB RAM with 0s ready for my tables to go in. Then I put in the idt (will be done at a later date) and the GDT. After that it is switched into pmode and the selectors are set up. Finally, there is a line that prints the char A to the top left had of the screen to test that it has all worked.
My problem is that I can't get this to work and I don't know that the problem is with it.
Thanks for your help
srg
Switch to PMode Problem
-
Curufir
Re:Switch to PMode Problem
Ok, I don't know how many times people have said it on this board but it's plenty. It is NOT a good idea to trash the IVT and BIOS data area by putting code below 0x600 linear. You lose all that free information from the BIOS, and the real mode vesa interrupts are lost forever. End of rant.
Took a quick peek at your code (Dunno why people are so afraid of making their descriptors legible with defines, but that's personal choice I guess
). First glance brought up this problem.
The PMode switch must be a far jump. Reason being is a short jump will not load CS with the selector, a short jump only loads IP with an offset into the code segment.
**
My bad, I see the retf you're using to set CS. I don't like it though, you're loading DS with a selector and pushing onto the stack without loading CS with one. Maybe there isn't anything wrong with that, but it feels...yuck. Use a far jump to set CS at the same time you flush the prefetch queue.
The other thing is this clearing memory business. Why bother? Seeing as you're overwriting it then so long as you set up start and limit correctly on the GDT/IDT it doesn't matter what was there originally.
Is that GDT location constant defined as 0x800? Seeing as you've hardcoded the gdt base then it had better be.
Took a quick peek at your code (Dunno why people are so afraid of making their descriptors legible with defines, but that's personal choice I guess
The PMode switch must be a far jump. Reason being is a short jump will not load CS with the selector, a short jump only loads IP with an offset into the code segment.
**
My bad, I see the retf you're using to set CS. I don't like it though, you're loading DS with a selector and pushing onto the stack without loading CS with one. Maybe there isn't anything wrong with that, but it feels...yuck. Use a far jump to set CS at the same time you flush the prefetch queue.
The other thing is this clearing memory business. Why bother? Seeing as you're overwriting it then so long as you set up start and limit correctly on the GDT/IDT it doesn't matter what was there originally.
Is that GDT location constant defined as 0x800? Seeing as you've hardcoded the gdt base then it had better be.
-
srg
Re:Switch to PMode Problem
OK slap on the had taken, I shall make it more self explanitery. 
Anyway, without the clearing memory stuff, I get tripple faults!
I'll change the Jump which'll kill two birds with one stone, and make my program smaller.
When in pmode, is the line
mov byte [ds:0xb8000], 'A'
ok for printing the text onto screen.
thanks
srg
P.S. How do I get the FritzOS PM code?
Anyway, without the clearing memory stuff, I get tripple faults!
I'll change the Jump which'll kill two birds with one stone, and make my program smaller.
When in pmode, is the line
mov byte [ds:0xb8000], 'A'
ok for printing the text onto screen.
thanks
srg
P.S. How do I get the FritzOS PM code?
-
Curufir
Re:Switch to PMode Problem
Yes, but remember that there are 2 bytes, 1 for the character, one for the display properties of the character so be sure to make certain the character isn't displaying as black background with black text on a black screen (Another one of my own personal favourite mistakessrg wrote: When in pmode, is the line
mov byte [ds:0xb8000], 'A'
ok for printing the text onto screen.
-
srg
Re:Switch to PMode Problem
right, I have revised my code but I'm still having problems, more seriouse this time.
_switch_to_pmode:
;Test Point A
?????? push ds
?????? mov ax, 0xb800
?????? mov ds, ax
?????? mov byte [ds:0], 'A'
?????? pop ds
??????
.setup_idt
lidt [IDT_location]
???
.setup_gdt
??? lgdt [GDT_location]
??????
?????? ???
?????? ;--------------------------------
?????? ; Now To switch to Protected Mode
?????? ;--------------------------------
?????? mov eax, cr0 ; Read in CR0 Register
?????? or eax, 1??????; Toggle PE Bit
?????? mov cr0, eax??????; Save to CR0
?????? ; That's it, we're in Protected Mode!
?????? ; Next, Flush the Prefetch Que
?????? Jmp Supervisor_code_selector:.ToHere
??????
[Bits 32]
.ToHere
;-------------------------------
?????? ; Now to setup Segment Selectors
;-------------------------------
mov ax, Supervisor_data_selector
?????? mov ds, ax ; Setup data selectors with 0x10 + TI=0b + RPL=00b
mov es, ax
?????? mov fs, ax
mov gs, ax
?????? mov ss, ax
mov esp, 0xFFFF
??????
?????? ;Test Point B
mov byte [ds:0xb8000], 'B'
??????
?????? retn
; Data #######################################################################
; As this is a tiny mode program, all data is still in the code segment
IDT_location dw IDT_end - IDT - 1
dd IDT
GDT_location dw GDT_end - GDT - 1
dd GDT
; Interrupt Gates
; NULL Till IDT Limit
IDT:
resq 256
IDT_end:
; Segment Descriptor Defenitions
; Null
; 0x00cf9a000000ffff Supervisor code from 0x00000000 to 4GB
; 0x00cf92000000ffff Supervisor data from 0x00000000 to 4GB
; 0x00cffa000000ffff User code from 0x00000000 to 4GB
; 0x00cff2000000ffff User data from 0x00000000 to 4GB
; Unused till GDT Limit
GDT: ; our descriptors
???; NULL descriptor
???dw 0 ; limit 15:0
???dw 0 ; base 15:0
???db 0 ; base 23:16
???db 0 ; type 15:8
???db 0 ; limit 19:16, flags
???db 0 ; base 31:24
???; Supervisor code from 0x00000000 to 4GB
???Supervisor_code_selector???EQU $-GDT
???dw 0xFFFF?????????
???dw 0????????????
???db 0????????????
???db 0x9a????????????
???db 0xCF????????????
???db 0????????????
???
???; Supervisor data from 0x00000000 to 4GB
???Supervisor_data_selector???EQU $-GDT
???dw 0xFFFF?????????
???dw 0????????????
???db 0????????????
???db 0x92????????????
???db 0xCF????????????
???db 0????????????
???; User code from 0x00000000 to 4GB
???User_code_selector???EQU $-GDT
???dw 0xFFFF?????????
???dw 0????????????
???db 0????????????
???db 0xfa????????????
???db 0xCF????????????
???db 0????????????
???
???; User data from 0x00000000 to 4GB
???User_data_selector???EQU $-GDT
???dw 0xFFFF?????????
???dw 0????????????
???db 0????????????
???db 0xf2????????????
???db 0xCF????????????
???db 0????????????
resq 251
GDT_end:
The problem is that at the line:
Jmp Supervisor_code_selector:.ToHere
I get a tripple fault witch shuts down or resets the machine (I know that a tripple fault makes the 386 reset).
What is the problem?
_switch_to_pmode:
;Test Point A
?????? push ds
?????? mov ax, 0xb800
?????? mov ds, ax
?????? mov byte [ds:0], 'A'
?????? pop ds
??????
.setup_idt
lidt [IDT_location]
???
.setup_gdt
??? lgdt [GDT_location]
??????
?????? ???
?????? ;--------------------------------
?????? ; Now To switch to Protected Mode
?????? ;--------------------------------
?????? mov eax, cr0 ; Read in CR0 Register
?????? or eax, 1??????; Toggle PE Bit
?????? mov cr0, eax??????; Save to CR0
?????? ; That's it, we're in Protected Mode!
?????? ; Next, Flush the Prefetch Que
?????? Jmp Supervisor_code_selector:.ToHere
??????
[Bits 32]
.ToHere
;-------------------------------
?????? ; Now to setup Segment Selectors
;-------------------------------
mov ax, Supervisor_data_selector
?????? mov ds, ax ; Setup data selectors with 0x10 + TI=0b + RPL=00b
mov es, ax
?????? mov fs, ax
mov gs, ax
?????? mov ss, ax
mov esp, 0xFFFF
??????
?????? ;Test Point B
mov byte [ds:0xb8000], 'B'
??????
?????? retn
; Data #######################################################################
; As this is a tiny mode program, all data is still in the code segment
IDT_location dw IDT_end - IDT - 1
dd IDT
GDT_location dw GDT_end - GDT - 1
dd GDT
; Interrupt Gates
; NULL Till IDT Limit
IDT:
resq 256
IDT_end:
; Segment Descriptor Defenitions
; Null
; 0x00cf9a000000ffff Supervisor code from 0x00000000 to 4GB
; 0x00cf92000000ffff Supervisor data from 0x00000000 to 4GB
; 0x00cffa000000ffff User code from 0x00000000 to 4GB
; 0x00cff2000000ffff User data from 0x00000000 to 4GB
; Unused till GDT Limit
GDT: ; our descriptors
???; NULL descriptor
???dw 0 ; limit 15:0
???dw 0 ; base 15:0
???db 0 ; base 23:16
???db 0 ; type 15:8
???db 0 ; limit 19:16, flags
???db 0 ; base 31:24
???; Supervisor code from 0x00000000 to 4GB
???Supervisor_code_selector???EQU $-GDT
???dw 0xFFFF?????????
???dw 0????????????
???db 0????????????
???db 0x9a????????????
???db 0xCF????????????
???db 0????????????
???
???; Supervisor data from 0x00000000 to 4GB
???Supervisor_data_selector???EQU $-GDT
???dw 0xFFFF?????????
???dw 0????????????
???db 0????????????
???db 0x92????????????
???db 0xCF????????????
???db 0????????????
???; User code from 0x00000000 to 4GB
???User_code_selector???EQU $-GDT
???dw 0xFFFF?????????
???dw 0????????????
???db 0????????????
???db 0xfa????????????
???db 0xCF????????????
???db 0????????????
???
???; User data from 0x00000000 to 4GB
???User_data_selector???EQU $-GDT
???dw 0xFFFF?????????
???dw 0????????????
???db 0????????????
???db 0xf2????????????
???db 0xCF????????????
???db 0????????????
resq 251
GDT_end:
The problem is that at the line:
Jmp Supervisor_code_selector:.ToHere
I get a tripple fault witch shuts down or resets the machine (I know that a tripple fault makes the 386 reset).
What is the problem?
-
Slasher
Re:Switch to PMode Problem
hi,
first disable interrupts while the code is setting up Pmode.
You did no put the selector in AX before using AX to setup you SS,DS,ES,FS and GS registers.
also you are returning at the end of the code, WHY!!!
remove retn
replace with jmp $ (this is a loop to the current address)
first disable interrupts while the code is setting up Pmode.
You did no put the selector in AX before using AX to setup you SS,DS,ES,FS and GS registers.
uncomment mov ax, Supervisor_data_selector; Now to setup Segment Selectors
;-------------------------------
;mov ax, Supervisor_data_selector
mov ds, ax ; Setup data selectors with 0x10 + TI=0b + RPL=00b
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0xFFFF
;Test Point B
mov byte [ds:0xb8000], 'B'
retn
also you are returning at the end of the code, WHY!!!
remove retn
replace with jmp $ (this is a loop to the current address)
-
srg
Re:Switch to PMode Problem
Right, I've modified my last post and uncommented that line.
I wasn't sure if this was relavent to this but this program is part of a larger program wrtten in C using Turbo C++ 1.01, but with my own custom startup code, hence the retn.
Also this program needs to be able to be run EITHER from a bootsector/bootloader OR from the DOS prompt.
Thanks
srg
I wasn't sure if this was relavent to this but this program is part of a larger program wrtten in C using Turbo C++ 1.01, but with my own custom startup code, hence the retn.
Also this program needs to be able to be run EITHER from a bootsector/bootloader OR from the DOS prompt.
Thanks
srg
-
Slasher
Re:Switch to PMode Problem
boot sectors/codes do not return! At thee end of the boot code function should be a call to the kernel/code to continue in pmode!!
call _kernel
call _kernel
-
srg
Re:Switch to PMode Problem
No no no this is a function in the C program hehe
Also Interrupts were disabled earlier on in the program.
and the A20 gate was opened.