Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Trouble Switching to Protected Mode x86

assembly kernel

This topic has been archived. This means that you cannot reply to this topic.
3 replies to this topic

#1 Poe

Poe

    CC Resident

  • Advanced Member
  • PipPipPipPip
  • 81 posts

Posted 03 May 2015 - 09:31 AM

i've recently been trying to get a good understanding of operating systems by writing a "toy" os.  And when doing so in 16 bits I had no trouble.  However at the moment i'm trying to switch to protected mode and when I run it it assembles fine but then I can't tell if its in protected mode because the print_pm function will not work, or maybe its not making the jump correctly?

 

Here i the code:

boot.s:

[ORG 0x7C00] ; set origin area to standardized bootloader
[BITS 16]
	;	setup initial stack
	xor ax, ax
	mov ds, ax
		
	cli
		
	lgdt [gdtr]
	call open_gate
	call begin_pm
		
	open_gate:	in al, 0x93
		or al, 2
		and al, ~1
		out 0x92, al
		
		ret
		
	begin_pm:	mov eax, cr0
		or eax, 1
		mov cr0, eax
		jmp (CODE_DESC - NULL_DESC) : protected_mode
	
%include '../lib/asm/gdt.s'
%include '../lib/asm/print_pm.s'

[BITS 32] ; Move to modern day code xD
	
	protected_mode: mov ebx, PROTMSG
                call print_pm

LOADMSG:	db 'Loading...', 0
PROTMSG:	db 'Now in Protected Mode...', 0

times 510 - ($-$$) db 0
dw 0xAA55

gdt.s:

NULL_DESC:
    dd 0            ; null descriptor
    dd 0

CODE_DESC:
    dw 0xFFFF       ; limit low
    dw 0            ; base low
    db 0            ; base middle
    db 10011010b    ; access
    db 11001111b    ; granularity
    db 0            ; base high

DATA_DESC:
    dw 0xFFFF       ; limit low
    dw 0            ; base low
    db 0            ; base middle
    db 10010010b    ; access
    db 11001111b    ; granularity
    db 0            ; base high

gdtr:
    Limit dw gdtr - NULL_DESC - 1 ; length of GDT
    Base dd NULL_DESC   ; base of GDT

print_pm.s:

[BITS 32]
VIDEOMEM: equ 0xb800
FONTCOLOR:	equ 0x0F

print_pm:	pusha
	mov edx, VIDEOMEM

pm_string_loop:	mov al, [ebx]
	mov ah, FONTCOLOR
	
	cmp al, 0
	je pm_string_done
	
	mov [edx], ax
	add ebx, 1
	add edx, 2
	
	jmp pm_string_loop
	
pm_string_done:	popa
	ret

if anyone can point me in the direction of why this just sits blank instead of printing the message it would greatly help me on my quest!


Edited by Poe, 03 May 2015 - 09:40 AM.

"Portability is for those who can't write new programs" - Linus Torvalds


#2 dargueta

dargueta

    I chown trolls.

  • Moderator
  • 4854 posts

Posted 03 May 2015 - 12:58 PM

Three problems:

1) VIDEOMEM should be 0xb8000, not 0xb800. The reason is that the 8086 calculated addresses as (segment << 4) + offset. Thus, b800:0000 translates to a flat address of 0xb8000.

 

2) You don't set DS to your data segment (0x10). You must do this as soon as you jump into protected mode before you use it, otherwise you'll get a protection error and the processor will reboot. I also strongly recommend setting ES = DS.

 

3) The processor is gonna keep going after your call to print_pm and try to execute LOADMSG and PROTMSG as code. Put the instructions cli and hlt right after your call to hang the processor.

 

 

Irrelevant to your problem but still issues:

1) I see a cli but no corresponding sti after setting up the GDT. I recommend you put this immediately after entering protected mode.

 

2) You're calling begin_pm but never returning, thus leaving your stack misaligned with a 16-bit address when you jump into 32-bit code. A simple jmp begin_pm will suffice.


Edited by dargueta, 03 May 2015 - 01:08 PM.

sudo rm -rf / && echo $'Sanitize your inputs!'


#3 Poe

Poe

    CC Resident

  • Advanced Member
  • PipPipPipPip
  • 81 posts

Posted 03 May 2015 - 01:21 PM

Three problems:

1) VIDEOMEM should be 0xb8000, not 0xb800. The reason is that the 8086 calculated addresses as (segment << 4) + offset. Thus, b800:0000 translates to a flat address of 0xb8000.

 

2) You don't set DS to your data segment (0x10). You must do this as soon as you jump into protected mode before you use it, otherwise you'll get a protection error and the processor will reboot. I also strongly recommend setting ES = DS.

 

3) The processor is gonna keep going after your call to print_pm and try to execute LOADMSG and PROTMSG as code. Put the instructions cli and hlt right after your call to hang the processor.

 

 

Irrelevant to your problem but still issues:

1) I see a cli but no corresponding sti after setting up the GDT. I recommend you put this immediately after entering protected mode.

 

2) You're calling begin_pm but never returning, thus leaving your stack misaligned with a 16-bit address when you jump into 32-bit code. A simple jmp begin_pm will suffice.

i love you dargueta


"Portability is for those who can't write new programs" - Linus Torvalds


#4 dargueta

dargueta

    I chown trolls.

  • Moderator
  • 4854 posts

Posted 03 May 2015 - 01:45 PM

i love you dargueta

 

I take it that means it worked?  :)

 

Edit: You must also set SS to your data segment descriptor. Otherwise any accesses to the stack will make the CPU explode.

 

Edit 2: Actually, don't execute sti until you've set up the IDTR. More explosions.  :biggrin:


Edited by dargueta, 03 May 2015 - 02:07 PM.

sudo rm -rf / && echo $'Sanitize your inputs!'