Jump to content

New to posting, have a question about Protected mode switch

- - - - -

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

#1
xixpsychoxix

xixpsychoxix

    Newbie

  • Members
  • Pip
  • 4 posts
Hi. I am trying to write a small operating system just as a personal project, for the fun u know? but here is the thing. i am trying to switch the processor into protected mode with a small application i developed using a borrowed boot sector. here is the code i managed to piece together from the intel documentation:


bits 16

org 0x00


	jmp start_os


;these lines are the messages to be printed by our OS


switching_msg db "Currently placing processor in 32-bit Protected mode...",0

done_msg      db "Done with placing processor in 32-bit Protected mode. I can't believe I finally made it!!!",0

cur_char      dw 0x0


;these functions print messages on the screen in 16-bit and 32-bit mode, respectively

print_ln_16:


	mov ah,0x0e

	mov bx,0x0007


.print_loop


	lodsb

	or al,al

	jz .done


	int 0x10

	jmp .print_loop


.done


	retn


bits 32

print_ln_32:


	mov ax,video_selector

	mov gs,ax


.print_loop:


	lodsb

	or al,al

	jz .done


	mov ah,0x07

	mov word [gs:cur_char],ax

	inc word [cur_char]

	inc word [cur_char]


	jmp .print_loop


.done:


	retn


bits 16

start_os:


	mov ax,0x0050

	mov ds,ax

	mov es,ax


	mov si,switching_msg

	call print_ln_16


	cli


	lgdt [global_descriptor]

	mov eax,cr0

	or al,0x01

	mov cr0,eax

	jmp code_selector:pmode_jmp


bits 32

pmode_jmp:


	jmp pmode_jmp


	mov ax,data_selector

	mov ds,ax

	mov es,ax


	mov ax,video_selector

	mov gs,ax


	mov word [gs:0],0x741


hang:


	jmp hang

	

bits 16

global_descriptor:


	dw gdt_end - gdt_begin -1	;total length of global descriptor table

	dd gdt_begin			;beginning of global descriptor table


gdt_begin:


empty_selector equ $-gdt_begin		;empty selector located at 0x0 in the table


gdt_0					;first entry is to be a null descriptor


	dd 0x0				;make all the entries in

	dd 0x0				;this descriptor null


code_selector equ $-gdt_begin		;code selector located at 0x08 in the table


gdt_code				;this entry is our code selector


	dw 0xFFFF			;4 Gb limit

	dw 0x0000			;base is at 0x0

	db 0x00				;no actual idea what this field does

	db 0x9A				;this field sets the status of the segment to be executable

	db 0xCF				;this sets some more of those status bits

	db 0x00				;no idea about this one either


data_selector equ $-gdt_begin		;data selector located at 0x10


gdt_data				;this entry is the data selector


	dw 0xFFFF			;4 Gb limit

	dw 0x0000			;base is at 0x0

	db 0x00				;still no clue about this field

	db 0x92				;sets the status of the segment to be data

	db 0xCF				;this does God only knows what

	db 0x00				;this sprinkles magic pixie dust over the whole shabang


video_selector equ $-gdt_begin		;video selector at 0x18


gdt_video				;video selector


	dw 3999				;this selector should have a limit of ((80*25)*2)-1 or 3999 decimal

	dw 0xb800			;and should start at 0xB800, video memory

	db 0x00				;no idea

	db 0x92				;no idea

	db 0x00				;still no idea

	db 0x00				;no freakin clue


gdt_end


alot of this came from the tutorial "Write your own toy os" as well. I am loading this program at 0050:0000 and I am using Microsoft Virtual PC to test it. I am assembling it using NASM. Whenever I run this code, the VM says that an unrecoverable processor error has occurred. It happens right at the switch to protected mode at the jump to clear the prefetch buffer. anyone have an idea what's wrong?

#2
TkTech

TkTech

    The Crazy One

  • Moderators
  • 1,396 posts
If your new to OS Dev, a better place to start would be JamesM's tutorials which are far more detailed.


lgdt [global_descriptor]

mov eax,cr0

or al,0x01     ;<------ or eax,1

mov cr0,eax

jmp 08h:pmode_jmp ;<--- Just use 08h...


To clarify, lets sum it up:
lgdt [global_descriptor] - Load global descriptor table; loads the address of global_descriptor.
mov eax,cr0 - copies the value of cr0, a control register, to eax
or eax,1 - sets the least significant bit of cr0, this is what determines if we're in pmode or not
mov cr0,eax - restore the value of cr0
jmp 08h:pmode_jmp - does a long jump to your protected mode code

#3
xixpsychoxix

xixpsychoxix

    Newbie

  • Members
  • Pip
  • 4 posts
So then my code is not in error aside from using al instead of eax? The tutorial listed uses GRUB to switch to protected mode but i am trying to learn to make this transition with my own code. I can't seem to find any other documents that explain this switch. Can anyone help?? I booted this using bochs and it seems that i am getting a page fault, though i cant quite understand the output of the core dump:

00136807775i[BIOS ] Booting from 0000:7c00
00138714123i[CPU0 ] CPU is in protected mode (active)
00138714123i[CPU0 ] CS.d_b = 32 bit
00138714123i[CPU0 ] SS.d_b = 16 bit
00138714123i[CPU0 ] EFER   = 0x00000000
00138714123i[CPU0 ] | RAX=0000000060000011  RBX=0000000000000007
00138714123i[CPU0 ] | RCX=0000000000000003  RDX=0000000000000fff
00138714123i[CPU0 ] | RSP=000000000000fffb  RBP=0000000000000000
00138714123i[CPU0 ] | RSI=00000000ffff003b  RDI=0000000000080005
00138714123i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00138714123i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00138714123i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00138714123i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00138714123i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00138714123i[CPU0 ] | SEG selector     base    limit G D
00138714123i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00138714123i[CPU0 ] |  CS:0008( 0001| 0|  0) ffc0004d 0003f000 0 1
00138714123i[CPU0 ] |  DS:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00138714123i[CPU0 ] |  SS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00138714123i[CPU0 ] |  ES:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00138714123i[CPU0 ] |  FS:07c0( 0005| 0|  0) 00007c00 0000ffff 0 0
00138714123i[CPU0 ] |  GS:07c0( 0005| 0|  0) 00007c00 0000ffff 0 0
00138714123i[CPU0 ] |  MSR_FS_BASE:0000000000007c00
00138714123i[CPU0 ] |  MSR_GS_BASE:0000000000007c00
00138714123i[CPU0 ] | RIP=00000000000000ec (00000000000000ec)
00138714123i[CPU0 ] | CR0=0x60000011 CR1=0x0 CR2=0x0000000000000000
00138714123i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00138714123i[CPU0 ] >> (invalid)  : FFFF
00138714123e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00138714123i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called
00138714123i[CPU0 ] cpu software reset
00138714123i[APIC0] local apic in CPU 0 initializing
00138717426i[BIOS ] $Revision: 1.209 $ $Date: 2008/06/02 20:08:10 $
00139032561i[KBD  ] reset-disable command received
00150755000p[WGUI ] >>PANIC<< Window closed, exiting!
00150755000i[CPU0 ] CPU is in real mode (active)
00150755000i[CPU0 ] CS.d_b = 16 bit
00150755000i[CPU0 ] SS.d_b = 16 bit
00150755000i[CPU0 ] EFER   = 0x00000000
00150755000i[CPU0 ] | RAX=0000000000091300  RBX=0000000000000002
00150755000i[CPU0 ] | RCX=000000000009ff7c  RDX=00000000000003da
00150755000i[CPU0 ] | RSP=000000000000ffe4  RBP=0000000000005cdc
00150755000i[CPU0 ] | RSI=0000000000000000  RDI=000000000000b6c1
00150755000i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00150755000i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00150755000i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00150755000i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00150755000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df IF tf sf ZF af PF cf
00150755000i[CPU0 ] | SEG selector     base    limit G D
00150755000i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00150755000i[CPU0 ] |  CS:c000( 1e00| 0|  0) 000c0000 0000ffff 0 0
00150755000i[CPU0 ] |  DS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00150755000i[CPU0 ] |  SS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00150755000i[CPU0 ] |  ES:c000( 0000| 0|  0) 000c0000 0000ffff 0 0
00150755000i[CPU0 ] |  FS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00150755000i[CPU0 ] |  GS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00150755000i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00150755000i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00150755000i[CPU0 ] | RIP=00000000000028ec (00000000000028ec)
00150755000i[CPU0 ] | CR0=0x60000010 CR1=0x0 CR2=0x0000000000000000
00150755000i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00150755000i[CPU0 ] >> in al, dx : EC
00150755000i[CMOS ] Last time is 1242739445 (Tue May 19 09:24:05 2009)
00150755000i[     ] restoring default signal behavior
00150755000i[CTRL ] quit_sim called with exit code 1

anyone figure out why this is failing? I'm just soooo frustrated!

#4
woodywood245

woodywood245

    Newbie

  • Members
  • Pip
  • 3 posts
I am having the same problem with my code. Did you ever find a solution? Tomorrow I'm going to try to run my bootloader on a real machine and see if the processor resets.

#5
xixpsychoxix

xixpsychoxix

    Newbie

  • Members
  • Pip
  • 4 posts
Sorry man i have no idea how i fixed it... i started a tutorial from another site Brokenthorn.com and in the process of developing a bootloader i had to make the protected mode switch and for some reason, though the code was pretty much identical, that version worked even though mine didnt... sry its been a long time since i thought about this post.

#6
woodywood245

woodywood245

    Newbie

  • Members
  • Pip
  • 3 posts
It's okay, thanks for responding. I've dragged an old computer I had lying around in my room and set it up as a test platform. I'm having trouble enabling A20 on it, but I think I can work around that. Thanks again.

#7
TkTech

TkTech

    The Crazy One

  • Moderators
  • 1,396 posts
A20 Line - OSDev Wiki

#8
woodywood245

woodywood245

    Newbie

  • Members
  • Pip
  • 3 posts
Okay, I'm obviously doing something wrong. I'm writing this in NASM, and everywhere I look it gives me the same basic code for starting protected mode. I got A20 enabled, but when I do this part, both Virtual PC and the real computer do a CPU reset.

	

	cli

	;enter pmode

	mov eax, cr0

	or eax, 1

	mov cr0,eax

	

	jmp FLUSH


	



[BITS 32]

FLUSH:

	;refresh all segment registers

	mov eax,DATASEL

	mov ds,eax

	mov es,eax

	mov fs,eax

	mov gs,eax

	mov ss,eax

	mov esp,0xffff

	

	;jmp 1000h:0000      ; Jump to the kernel


	hlt		; halt the cpu

Based on what I did with Virtual PC, I think it's the problem occurs right when I move EAX to CR0. Thanks ahead of time!

#9
xixpsychoxix

xixpsychoxix

    Newbie

  • Members
  • Pip
  • 4 posts
The main thing that i see is that you are performing a near jump:



 jmp FLUSH



Try a far jump instead:



 jmp CODE_DESC:FLUSH



replacing CODE_DESC with the location of your code descriptor. Also if your code descriptor is the first entry you can do this:



jmp 0x08:FLUSH



which is what i do. Try that and see what happens. The intel documentation specifies that you must perform a far jump to set CS to the appropriate descriptor and flush the prefetch cache.