[SOLVED]Entering protected mode: tutorial disambiguation

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.
guilherme
Member
Member
Posts: 35
Joined: Mon Jan 31, 2011 6:58 am
Location: Brasil

[SOLVED]Entering protected mode: tutorial disambiguation

Post by guilherme »

Sorry, i know how simple this must be, but anyway: How do i enter and exit 32-bit protected mode in NASM compiler?
I looked for it in many sources, including OsDev itself, but all they
are very, very confused: Each one describes the entering procedure and GDT descriptor in a different way, and all they seems trusty.
The worst part of that is that i didn't found anything about returning to the 16-bit real-mode.
My idea is create a simple procedure that will enter 32-bit protected mode, will copy data from base memory to extended memory, and then return to the 16-bit real-mode leaving all registers and flags untouched.
I tried to ( following some sources) create a bootstrap that enter protected mode, then print a single character on CGA video and then freezes, but all it does is reset my computer (it is booting):

Code: Select all

[BITS 16]                ;set instructions to 16-bit
[ORG 0x7C00]          ;set compiler offset to 007C00h  
CLI                        ;clear automatic interrupts
Xor ax, ax               ;set ax to 0000h
Push ax                  ;push ax (0000h)
Popf                       ;pop 0000h from ax into flags register
Mov ds,ax               ;move 0000h from ax into DS register 
lgdt [GDTP]             ;load GDT (see above)  
Mov eax, CR0          ;Move CR0 to eax
Or eax, 000000001h ;set the first bit, wich will be the PE bit 
Mov CR0, eax          ;move eax to CR0, setting Protected mode
Jmp 08h:CLEAR        ;flush pipe-line  
[BITS 32]                ;set instructions to 32-bit 
CLEAR:             ;declaration of CLEAR offset   
mov ax, 08h  ;set segment identifier (first segment after the null one)
mov ds, ax       ;move 0008h from ax into ds
mov ss, ax       ;move 0008h from ax into ss
Mov ebp,080000h       ;set the stack somewhere away from the code 
Mov esp, 08FFFFh
Mov ax,0F01h            ;set ax to CGA character code (white smile) 
Mov [0B8000h],ax      ;put ax on first character of CGA video 
HANG:                      
jmp HANG                 ;infinite loop, just to be possible see the smile
GDT:
dq 00000000000000000h    ;null 8-bytes entrie
dw 0FFFFh      ;limit low word 
dw 00000h      ;base low word
db 000h          ;base middle byte
db 010011010b   ;acess byte (code, readable, system, unconforming)
db 011001111b   ;4 granularity (4Kb) bits and limit high 4 bits
db 000h             ;base high byte
dw 0FFFFh      ;limit low word     
dw 00000h      ;base low word
db 000h          ;base middle byte
db 010010010b   ;acess byte (data, writeable, system, unconforming)
db 011001111b  ;4 granularity (4Kb) bits and limit high 4 bits
db 000h            ;base high byte
GDTP:              ;GDT pointer declaration
dw GDTP-GDT    ;GDT limit = GDT end - GDT init - 1
dd GDT             ;32-bit offset of GDT
times 510-($-$$) db 000h ;fill with zeroes until byte 01FEh
dw 0AA55h         ;boot identifier
Thanks!!!.
Last edited by guilherme on Wed Feb 09, 2011 10:27 am, edited 3 times in total.
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: Entering protected mode: tutorial disambiguation

Post by Combuster »

- No stack set up in time (SS/SP undefined and still used)
- Using a code selector (0x08) in a data register (DS is not writable, SS crashes because it must be writable).
"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 ]
guilherme
Member
Member
Posts: 35
Joined: Mon Jan 31, 2011 6:58 am
Location: Brasil

Re: Entering protected mode: tutorial disambiguation

Post by guilherme »

I know that about the code segment is not writeable, but i defined both, the code segment and the data segment in whole memory, so i thought it was to act like the both at sime time.
And another question: Can i use interrupts in protected mode?
And if i can't, can i get their segment and offset from Interrupt table
so i can call them? The tutorials don't let it too clear.
Tosi
Member
Member
Posts: 255
Joined: Tue Jun 15, 2010 9:27 am
Location: Flyover State, United States
Contact:

Re: Entering protected mode: tutorial disambiguation

Post by Tosi »

You can use interrupts in protected mode, but since you can't use the BIOS you have to write your own. The reason being is that all the basic BIOS functions are intended to be run in real mode, and once you switch modes that's done. If you are writing your own bootloader, make sure to get everything you want from the BIOS in the second stage loader or any time before you switch to protected mode.
Protected mode uses the IDT instead of the IVT, and has a more complicated structure.
guilherme
Member
Member
Posts: 35
Joined: Mon Jan 31, 2011 6:58 am
Location: Brasil

Re: Entering protected mode: tutorial disambiguation

Post by guilherme »

Ok, now i fixed the problem about the stack, and i put
the code segment and data segment in different areas.
But it still resets the machine!
I think there's more steps to enter protected mode than those i wrote.
Anyway, that is the new code:

Code: Select all

[BITS 16]               ;set code to 16-bit operand-size
[ORG 0x7C00]     ;set loading offset on 0000h:07C00h (boot sector)
CLI                          ;Clear hardware generated interrupts
Xor ax, ax             ;set ax to zero
Push ax                ;push zero from ax
Popf                      ;pop zero from ax into flags register
Mov ds,ax           ;move zero from ax into ds
Mov ss,ax           ;move zero from ax into ss
Mov bp,07E00h      ;set stack base just after the boot sector
Mov sp,07FFEh     ;set stack top 01FEh bytes after base
lgdt [GDTP]            ;Load the new GDT
Mov eax,CR0         ;move CR0 to eax, so i can manipulate it's values
Or eax,000000001h  ;Or value coming from CR0 with 1, setting PE flag
Mov CR0,eax      ;move manipulated value back into CR0
Jmp 08h:CLEAR         ;jump far into new code segment (08h)
[BITS 32]               ;set code to 32-bit operand-size
CLEAR:                  ;offset declaration, used in the far jump
Mov ax,010h         ;move eax to data segment identifier (010h)
Mov ds,ax             ;move data segment identifier into ds
Mov ss,ax             ;move data segment identifier into ss
Mov ebp,0C8000h   ;set stack base on absolute address 0180000h 
Mov esp,0108000h     ;set stack top on absolute address 01C0000h
Mov ax,0FF01h           ;set ax to white smile character code
Mov [0000h],ax   ;set first video character to ax (white smile)
HANG:         ;offset declaration used on hang
jmp HANG     ;infinite loop

GDT:    ;GDT offset declaration

dq 00000000000000000h     ;null segment entrie

;the next entrie must be like that: start on absolute address 0500h, end on absolute address 090000h
;this must be: Executable, unconforming, system ring, readable, 1 byte granularity, 32-bit operand size. 

dw 0FB00h  
dw 00500h  
db 00h    
db 010011010b 
db 001001000b 
db 00h  

;the next entrie must be like that: start on absolute address 0B8000h, end on absolute address 06A00000h
;this must be: Data segment, unconforming, system ring, writeable, 4Kbyte granularity, 32-bit operand size. 

dw 06948h  
dw 08000h
db 0Bh   
db 010010010b 
db 011000000b
db 00h   


GDTP:                             ;declaration of the GDT pointer offset
dw GDTP-GDT-1         ;GDT size less 1
dd GDT                           ;GDT 32-bit offset in memory
times 510-($-$$) db 00h                  ;fill with zeroes until byte 510
dw 0AA55h          ;boot key


Thanks.
User avatar
Muneer
Member
Member
Posts: 104
Joined: Tue Nov 02, 2010 2:05 am
Location: India

Re: Entering protected mode: tutorial disambiguation

Post by Muneer »

Hi guilherme,

I tested your code and it gave me a triple fault. The code looked fine, though the instructions

Code: Select all

Mov ss,ax           ;move zero from ax into ss
Mov bp,07E00h      ;set stack base just after the boot sector
Mov sp,07FFEh 
serves no purpose as you change the stack immediately after entering the protected mode.

The problem was in the GDT entries itself . The code works once replacing your GDT entries with the following simple entries for Ring 0 code and data segments

Code: Select all

		dd	0x00000000 ,   0x00000000		;	Null
		dd	0x0000FFFF ,   0x00CF9A00		;	Kernel Code
		dd	0x0000FFFF ,   0x00CF9200		;	Kernel Data
Note: when you split a double word "dd 0xA50CDE12" to two words you have to make it
to "dw 0xDE12"
"dw 0xA50C"
and not the other way round.

Cheers
Even the smallest person could change the course of the future - Lord Of The Rings.

In the end all that matters is what you have done - Alexander.

Even after a decade oh god those still gives me the shivers.
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: Entering protected mode: tutorial disambiguation

Post by Combuster »

Hardcoder pointed out the most likely source of the crash, however:
Mov ebp,0C8000h ;set stack base on absolute address 0180000h
Mov esp,0108000h ;set stack top on absolute address 01C0000h
Do you see the error?
(code) serves no purpose as you change the stack immediately after entering the protected mode.
The other observation is that you still have not defined a stack before you use it. (and that the stack you defined overlaps with your code)
"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 ]
guilherme
Member
Member
Posts: 35
Joined: Mon Jan 31, 2011 6:58 am
Location: Brasil

Re: Entering protected mode: tutorial disambiguation

Post by guilherme »

I didn't see the error about the stack.
I thought that, if the absolute starting address of the segment is 0B8000h, any addresses inside the segment would be 0B8000h + address.
And, i have more two questions:
1: What especifically was wrong in the GDT entries?
2: How i exit protected mode to real-mode again?
Thanks by the help.
User avatar
Muneer
Member
Member
Posts: 104
Joined: Tue Nov 02, 2010 2:05 am
Location: India

Re: Entering protected mode: tutorial disambiguation

Post by Muneer »

Hi ,

Earlier I just substituted my simple GDT entries for your code and it just worked. But after rechecking your GDT Entries, I found yours was also correct. And I went through the code again and found out the real problem.

When you make your far jump after switching to protected mode, i.e 08h:CLEAR , the ORG you provided was 0x0000:0x7C00. So the "CLEAR" label gets an address relative to 7C00 (7C25 in this case). So your code actually looks like

Code: Select all

Jmp 08:0x00007C25
. But Once you jump to protected mode, you provide your code segment base as 0x500 (as opposed to 0x0000 earlier ). So your far jump will attempt to jump to BaseAddress + 7C25 i.e (0x500 + 0x7C25 = 0x8125). So inorder for the code to work properly, change your far jump to

Code: Select all

Jmp 08h:CLEAR - 0x500        ; Far jump adjusted to base
.

After changing the far jump you can see the white smile character code blinking. :D
Also out of curiosity, why do you need such a complex Kernel Code with a base of 0x500 and data segment(not to mention the limit fields) when you could go with a simple Flat model of 0 base and 4G limit.
Even the smallest person could change the course of the future - Lord Of The Rings.

In the end all that matters is what you have done - Alexander.

Even after a decade oh god those still gives me the shivers.
guilherme
Member
Member
Posts: 35
Joined: Mon Jan 31, 2011 6:58 am
Location: Brasil

Re: Entering protected mode: tutorial disambiguation

Post by guilherme »

My idea is create a procedure to be called by a real-mode program, that will enter protected-mode, copy data from base memory to extended memory and vice-versa, leave protected memory, and return to the program, to create a type of buffer.
guilherme
Member
Member
Posts: 35
Joined: Mon Jan 31, 2011 6:58 am
Location: Brasil

Re: Entering protected mode: tutorial disambiguation

Post by guilherme »

Ok, now the process about entering the protected mode is working, and now i have made the other part, following some sources, to return to the real mode.
This code is a 16-bit boot sector that load and jumps to a kernel, and this kernel will enter protected mode, print that blinking smile, exit protected mode and return to the boot code, and the boot code will print the message "press any key to reboot..." and when you press any key, the system reboots.
The code boots, Jumps to the kernel, the kernel enter the protected mode, print the blinking smile, but does not return to the boot code, and the system freezes, simply don't respond.
I think the returning procedure ain't right, anyway:
Obs: now i did a flat memory model.

BOOTSECTOR:

Code: Select all

[BITS 16]   
[Org 0x7C00] 
CLI
Xor ax,ax
Push ax
Popf     
Mov es,ax
Mov ds,ax
Mov ss,ax
Mov bp,07E00h
Mov sp,07FFEh
RESET:
Xor ax,ax
Mov dx,ax
Int 013h
Jc RESET
Mov ax,0201h
Mov bx,08000h
Mov cx,0002h
Xor dx,dx
Int 013h
Jc RESET
Jmp 0000h:08000h 
CLI 
Xor ax,ax   
Push ax
Popf
Mov ds,ax
Mov ss,ax 
Or ax,0B800h
Mov es,ax
Mov bp,07E00h
Mov sp,07FFEh
Mov di,02h
Mov si,PAK 
Mov ah,0Fh
Mov cx,01Ah
LOOPRINT: 
Lodsb
Stosw
Loop LOOPRINT
Xor ax,ax
Int 016h
Jmp 0FFFFh:0000h
PAK db "Press any key to reboot..."    
times 510-($-$$) db 00h                 
dw 0AA55h       


KERNEL:

Code: Select all

[BITS 16]            
[ORG 0x8000]      
CLI
Xor ax,ax
Push ax
Popf
Mov ds,ax        
lgdt [GDTP]          
Mov eax,CR0           
Or eax,000000001h      
Mov CR0,eax    
Jmp 08h:CLEAR
[BITS 32]           
CLEAR:           
Mov ax,010h       
Mov ds,ax  
Mov ax,0FF01h         
Mov [0B8000h],ax       
Mov eax,CR0            
Xor eax,000000001h  
Mov CR0,eax 
Jmp 0000h:07C2Dh

GDT:  
dq 00000000000000000h  
dw 0FFFFh  
dw 00000h
db 00h   
db 010011010b 
db 011001111b
db 00h   
dw 0FFFFh  
dw 00000h
db 00h   
db 010010010b 
db 011001111b
db 00h   
GDTP:                           
dw GDTP-GDT-1        
dd GDT                      
Thanks.
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Entering protected mode: tutorial disambiguation

Post by neon »

Hello,

You need to do the following to properly leave protected mode:

-jump into 16 bit protected mode;
-disable protected mode, reset segments. fall back into real mode

Do take note: The BIOS expects the system to be in the same state it was at startup. This can be increasingly difficult as devices are initialized.

Also, a few comments on code layout:

-Never, ever have code like Jmp 0000h:07C2Dh unless there is a good reason. Code like this is very easy to break;
-Provide comments to your code. This doesnt just help you but helps anyone reading the code;
-Spaces and newlines help with readability
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
Chandra
Member
Member
Posts: 487
Joined: Sat Jul 17, 2010 12:45 am

Re: Entering protected mode: tutorial disambiguation

Post by Chandra »

guilherme wrote:My idea is create a procedure to be called by a real-mode program, that will enter protected-mode, copy data from base memory to extended memory and vice-versa, leave protected memory, and return to the program, to create a type of buffer.
For this 'Unreal Mode' serves the best.
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
guilherme
Member
Member
Posts: 35
Joined: Mon Jan 31, 2011 6:58 am
Location: Brasil

Re: Entering protected mode: tutorial disambiguation

Post by guilherme »

Ok, now i did some progress, but as the code got more complex, the problems turned more complex too.
I know that this reply is big, but please, be patient and read this all.
Ok, will explain: i made a routine that Pushes all flags, general and segment registers, enters the protected mode, with a flat memory model, do something, returns to the real mode and then Pop all that Pushed stuff.
The routine's GDT is made up of five entries: one null, one for 32-bit code, one for 32-bit,one for 16-bit code and one for 16-bit data, all they taking all the addressable space.
There's the code:

Code: Select all

[BITS 16]            
[ORG 0x8000]      
Pushfd 
Pushad 
Push ds
Push es
Push fs
Push gs
Mov [LASTSS],ss
Mov  [LASTEBP],ebp
Mov  [LASTESP],esp
Xor eax,eax
Mov ds,eax        
Mov es,eax
Mov fs,eax
Mov gs,eax
Mov ss,eax
lgdt [GDTP]          
Mov eax,CR0           
Or eax,01h      
Mov CR0,eax    
Jmp 08h:CLEAR
[BITS 32]           
CLEAR:           
Mov eax,010h       
Mov ds,eax        
Mov es,eax
Mov fs,eax
Mov gs,eax
Mov ss,eax
Mov ebp,0180000h
Mov esp,01C0000h
;--------------YOUR CODE STARTS HERE--------------------




;------------YOUR CODE ENDS HERE--------------------------
RETURN:
Jmp 018h:RETURN1
[BITS 16]      
RETURN1:  
Mov eax,020h
Mov ds,eax        
Mov es,eax
Mov fs,eax
Mov gs,eax
Mov ss,eax
Mov eax,CR0           
Xor eax,01h      
Mov CR0,eax    
Jmp 0000h:RETURN2
RETURN2:
Mov eax,[LASTSS]
Mov ss,eax
Mov ebp,[LASTEBP]
Mov esp,[LASTESP]
Pop gs
Pop fs
Pop es
Pop ds
Popad
Popfd
RETF

LASTSS dd 00000000h
LASTESP dd 00000000h
LASTEBP dd 00000000h

GDT:  

dq 00000000000000000h  

dw 0FFFFh  
dw 00000h
db 00h   
db 010011010b 
db 011001111b
db 00h   

dw 0FFFFh  
dw 00000h
db 00h   
db 010010010b 
db 011001111b
db 00h  

dw 0FFFFh  
dw 00000h
db 00h   
db 010011010b 
db 010001111b
db 00h   

dw 0FFFFh  
dw 00000h
db 00h   
db 010010010b 
db 010001111b
db 00h  

GDTP:                           
dw GDTP-GDT-1        
dd GDT           

I tested this with a real-mode code that sets the video-mode to text vieo-mode, clears the screen and calls the routine, and inside that routine i wrote a code to fill the screen with blank characters, and it repeats this process (clear and fill, clear and fill), so i had a way to be sure that this procedure was entering and exiting the protected mode.
But there's the problem:
I tried to use this in a application that stores data from disk on memory, but it freezes, so i tried removing the part that call this routine, and the rest of the application worked out, so i thought the code inside the routine would be with some problem, so i removed it, letting only that code above, but it still freezes.
I don't know where i'm wrong, because this procedure works fine with another applications, but this application in particular has been tested
hundreds of times, and this only works without using this routine.
HELP, PLEASE!!!.
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Entering protected mode: tutorial disambiguation

Post by neon »

Hello,

If the posted code works fine with other software but not with a particular software, it means theres a hidden dependency that breaks with that one software.

Have you single stepped the code? Verify the stack remains intact.. I see it reading from 0x20:LASTSS but writing to ds:LASTSS. Cant tell if thats a problem but I dont think it was intended either. Where does it fail? Does it not get into protected mode or return from it? Does it not return from the posted routine?

Regarding design:

-If the software you are using requires calling Bios interrupt services frequently, consider using v86 mode instead.
-If any system tables or device is reconfigured, your code might break when calling BIOS services. Please keep that in mind.

Need more detail in order to provide assistance.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Post Reply