Hello all. I am attempting to write a small operating system, just for kicks (i'm a strange person...), only problem is, i can't seem to make the protected mode switch. I am targeting Intel 80386 and better using NASM to assemble the source. Here is that source:

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 eax,0x01
	mov cr0,eax

	jmp 0x08:pmode_jmp

bits 32
pmode_jmp:

	mov ax,0x10
	mov ds,ax
	mov es,ax

	mov ax,0x18
	mov gs,ax

	mov word [gs:0],0x0641

	jmp pmode_jmp

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				
	db 0x9A
	db 0xCF				
	db 0x00				

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				
	db 0x92				
	db 0xCF				
	db 0x00				

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 0x8000			;and should start at 0xB800, video memory
	db 0x0B				
	db 0x92				
	db 0x00				
	db 0x00
				
gdt_end

Alot of this was borrowed from a tutorial and i would credit them if i could remember the name. This code just makes the processor reset over and over. What is going wrong with this code? I am using bochs to test the code and here is the log file concerning the processor around reset:

00105544372i[BIOS ] Booting from 0000:7c00
00107450657e[CPU0 ] check_cs(0x0008): not a valid code segment !
00107450657i[CPU0 ] CPU is in protected mode (active)
00107450657i[CPU0 ] CS.d_b = 16 bit
00107450657i[CPU0 ] SS.d_b = 16 bit
00107450657i[CPU0 ] EFER   = 0x00000000
00107450657i[CPU0 ] | RAX=0000000060000011  RBX=0000000000000007
00107450657i[CPU0 ] | RCX=0000000000000003  RDX=0000000000000fff
00107450657i[CPU0 ] | RSP=000000000000fffb  RBP=0000000000000000
00107450657i[CPU0 ] | RSI=00000000ffff003b  RDI=0000000000080005
00107450657i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00107450657i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00107450657i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00107450657i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00107450657i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00107450657i[CPU0 ] | SEG selector     base    limit G D
00107450657i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00107450657i[CPU0 ] |  CS:0050( 0004| 0|  0) 00000500 0000ffff 0 0
00107450657i[CPU0 ] |  DS:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00107450657i[CPU0 ] |  SS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00107450657i[CPU0 ] |  ES:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00107450657i[CPU0 ] |  FS:07c0( 0005| 0|  0) 00007c00 0000ffff 0 0
00107450657i[CPU0 ] |  GS:07c0( 0005| 0|  0) 00007c00 0000ffff 0 0
00107450657i[CPU0 ] |  MSR_FS_BASE:0000000000007c00
00107450657i[CPU0 ] |  MSR_GS_BASE:0000000000007c00
00107450657i[CPU0 ] | RIP=00000000000000eb (00000000000000eb)
00107450657i[CPU0 ] | CR0=0x60000011 CR1=0x0 CR2=0x0000000000000000
00107450657i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00107450657i[CPU0 ] >> jmp far 0008:00f0 : EAF0000800
00107450657e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00107450657i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called
00107450657i[CPU0 ] cpu software reset

Sorry this is so long but i just can't seem to figure out where i am going wrong. I studied all of intel's documents but cant seem to find out where i am going wrong!!!!

The triple fault seems to happen when you execute the jump following the switch into protected mode. That makes me wonder whether the org 0 at the beginning of the file corresponds to where you have the file loaded.

Let's say the pmode_jmp label is 256 bytes into the file.
Then jmp 0x08:pmode_jmp will translate into jmp 0x8:0x100, which is fine if you want to end up in the middle of the interrupt vector table. If the file was loaded at 0x8000 (say) what you would really want is jmp 0x8:0x8100.

To get that you would need to have an org 0x8000 at the beginning of the file. Correspondingly, the jump in the boot sector would then be

jmp 0x0000:0x8000

You're reseting the processor so you come up in real mode, you set your CS and DS segment registers and the first thing you do is use the stack in your video interrupt call!

Shouldn't you be setting up your stack as well before you use it?

(Just a thought!)

Once you get this working your next step will probably be instituting a thunk mechanism so you can thunk down from 32-bit to 16-bit for doing your hardware I/O operations.

Oh and if I remember correctly, you have to initiate the video card before using any of the VIDEO bios interrupts! The graphics chip has to be configured!

You're reseting the processor so you come up in real mode, you set your CS and DS segment registers and the first thing you do is use the stack in your video interrupt call!

Shouldn't you be setting up your stack as well before you use it?

(Just a thought!)

Once you get this working your next step will probably be instituting a thunk mechanism so you can thunk down from 32-bit to 16-bit for doing your hardware I/O operations.

He can carry on using the stack he set up in the boot sector, until after he has switched into protected mode.

One of the great joys of writing protected mode operating systems is that, once in protected mode, you can no longer use the BIOS calls (because they were writtent for real mode). Therefore you have to do what the BIOS itself does, and program the hardware directly; usually via i/o ports.

Oh and if I remember correctly, you have to initiate the video card before using any of the VIDEO bios interrupts! The graphics chip has to be configured!

No configuration is needed before you can use int 10h to put text on the screen. Any configuration which may have been necessary will already have been done by the BIOS, which, after all, commonly writes to the screen itself during start up.

Okay then I'm confused. The original poster xixpsychoxix wants to write his own operating system and he's starting from the reset entry vector. Nothing is initialized at that time. Thus the Video Bios initialization has to be called to configure the GPU so it can be used properly.

Or am I missing something?

Okay then I'm confused. The original poster xixpsychoxix wants to write his own operating system and he's starting from the reset entry vector. Nothing is initialized at that time. Thus the Video Bios initialization has to be called to configure the GPU so it can be used properly.

Or am I missing something?

I am not sure why he has decided to load his OS at 0x50000, because that location usually contains the tail end of the bios data area and a table used by the floppy disk driver.

When a PC boots it starts executing at the address 0xFFFF:0000. Since it is running in real mode, and that address is very near the top of the first 1mb, that just leaves room for a jump instruction to a more sensible location. The BIOS code then sets about the business of initioalising the CRT controller, the Programmable interval timer, the keyboard controller, the peripheral interrupt controller, the floppy disk controller, and others. Having done that, it then reads the first sector from track 0 of the floppy disk, if there is one in the drive. By convention that sector is read into memory at 0x0:7c00. The bios then performs a far jump to that location, and the OS bootstrap code begins executing. From looking at his code it appears that he has arranged for the bootstrap code to read his kernel into memory at 0x50:0000. By the time the kernel is read into memory, the CRT controller, which is the only thing which needs initialising for text mode, has already been set up by the BIOS.

The "reset" he refers to in his post is known as a triple fault. In this case it is probably the result of an attempt to execute an invalid opcode. The processor then generates an exception, only to find that, as yet, no exception handler has been installed. So then it generates another exception, and then another. Upon the third attempt it gives up the unequal struggle and resets itself.

Yes you're absolutely right. I work with too many processor families and got my INT0 mixed up with Reset on the 80x86 family.

And so now it makes more sense, he's not creating an embedded 80x86 product, he's using an off the shelf PC and wants to create his own Operating System for that.

Of course you are correct, BIOS is up and running, fully initialized!

Well, i'm just tinkering around with creating my own os for the fun of it, not really because i want to make my own to use. i just program this sort of thing to entertain me and keep my thought process running strong. so i will try to use your ideas here to save my poor operating system and see what i can do. thanx guys

This article has been dead for over six months. Start a new discussion instead.