| | |
protected mode switch
![]() |
•
•
Join Date: May 2009
Posts: 14
Reputation:
Solved Threads: 0
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:
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:
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!!!!
assembly Syntax (Toggle Plain Text)
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:
Assembly Syntax (Toggle Plain Text)
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!!!!
Last edited by xixpsychoxix; May 24th, 2009 at 10:27 am. Reason: put wrong bochs output in
•
•
Join Date: Nov 2006
Posts: 134
Reputation:
Solved Threads: 3
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
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
Last edited by mathematician; Jun 25th, 2009 at 8:53 pm.
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.
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.
•
•
Join Date: Nov 2006
Posts: 134
Reputation:
Solved Threads: 3
•
•
•
•
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.
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.
•
•
Join Date: Nov 2006
Posts: 134
Reputation:
Solved Threads: 3
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?
Or am I missing something?
•
•
Join Date: Nov 2006
Posts: 134
Reputation:
Solved Threads: 3
•
•
•
•
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?
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.
Last edited by mathematician; Jun 26th, 2009 at 5:17 pm.
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!
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!
•
•
Join Date: May 2009
Posts: 14
Reputation:
Solved Threads: 0
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
![]() |
Similar Threads
- How to Switch into Protected Mode (Assembly)
- protected mode programming guide (Assembly)
- Help needed for a project concerning protected mode (Assembly)
- 32 BIt Flat Real mode (C)
- 32 BIt Flat Real mode (Community Introductions)
Other Threads in the Assembly Forum
- Previous Thread: Printing prime numbers in MIPS
- Next Thread: write() error code
| Thread Tools | Search this Thread |





