Far Jump in Protected Mode to clear the prefetch queue

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.
Post Reply
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

Far Jump in Protected Mode to clear the prefetch queue

Post by teodori »

Hello,
my OS is tripple faulting at 'ljmp $0x8, $ExecKMain'.
If I leave out the far jump the processor is halted.

Code: Select all

00056533559i[BIOS ] Booting from 0000:7c00
00056656013e[CPU0 ] check_cs(0x0008): not a valid code segment !
00056656013e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00056656013e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00056656013i[CPU0 ] CPU is in protected mode (active)
00056656013i[CPU0 ] CS.d_b = 16 bit
00056656013i[CPU0 ] SS.d_b = 16 bit
00056656013i[CPU0 ] EFER   = 0x00000000
00056656013i[CPU0 ] | RAX=0000000060000011  RBX=0000000000000003
00056656013i[CPU0 ] | RCX=000000000009000a  RDX=0000000000000301
00056656013i[CPU0 ] | RSP=000000000000ffd6  RBP=0000000000000117
00056656013i[CPU0 ] | RSI=00000000000e474c  RDI=000000000000ffac
00056656013i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00056656013i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00056656013i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00056656013i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00056656013i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00056656013i[CPU0 ] | SEG selector     base    limit G D
00056656013i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00056656013i[CPU0 ] |  CS:0050( 0004| 0|  0) 00000500 0000ffff 0 0
00056656013i[CPU0 ] |  DS:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00056656013i[CPU0 ] |  SS:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00056656013i[CPU0 ] |  ES:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00056656013i[CPU0 ] |  FS:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00056656013i[CPU0 ] |  GS:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00056656013i[CPU0 ] |  MSR_FS_BASE:0000000000000500
00056656013i[CPU0 ] |  MSR_GS_BASE:0000000000000500
00056656013i[CPU0 ] | RIP=0000000000000030 (0000000000000030)
00056656013i[CPU0 ] | CR0=0x60000011 CR2=0x0000000000000000
00056656013i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00056656013i[CPU0 ] 0x0000000000000030>> jmp far 0008:0035 : EA35000800
00056656013e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00056656013i[SYS  ] bx_pc_system_c::Reset(HARDWARE) called
00056656013i[CPU0 ] cpu hardware reset
Here is my code which is loaded to 0x50:0x0 by MBR using BIOS interrupts:

Code: Select all

.section .rodata

msg:
	.asciz "kernel..."
msgend:

msglen:
	.word (msgend - msg)

gdt:
	# Null Descriptor
	.word 0x0000
	.word 0x0000
	.byte 0x00
	.byte 0x00
	.byte 0x00
	.byte 0x00

	# Code Descriptor
	.word 0xffff
	.word 0x0000
	.byte 0x00
	.byte 0x9a
	.byte 0xcf
	.byte 0x00

	# Data Descriptor
	.word	0xffff
	.word	0x0000
	.byte 0x00
	.byte	0x92
	.byte 0xcf
	.byte 0x00
gdt_end:

gdtptr:
	.word (gdt_end - gdt - 1)
	.long gdt

.section .text

.globl Start

Start:
	.code16

PrintMsg:
	mov $0x0050, %ax
	mov %ax, %es				# Set Extra Segment to 0x0050
	mov $msg, %bp				# Set base pointer to msg location

	mov $0x13, %ah			# Print String
	mov $0x01, %al			# Char only - Cursor moved
	clr %bh							# Page Number
	mov $0x03, %bl			# Color Black Blue
	mov msglen, %cx			# Message Length
	mov $3, %dh					# Row 3 
	mov $1, %dl					# Column 1
	int $0x10						# Video Interrupt

	cli

SetA20:
	inb $0x92, %al			# Enable A20 Gate
	testb	$0x2, %al			# to access to more than
	outb %al, $0x92			# 1 Mega Byte of memory

LoadGDT:
	lgdt gdtptr					# Load Global Descriptor Table

EnterProtectedMode:
	movl %cr0, %eax			# Read from Control Register CR0
	orl $0x1, %eax			# Set Protected Mode Bit
	movl %eax, %cr0			# Write to Control Register CR

	# In Real Mode			:	ljmp Segment, Offset
	# In Protected Mode	: ljmp Selector, Offset
	# Selector:
	#  0x0	= NullDescriptor
	#  0x8	= CodeDescriptor
	#  0x10	= DataDescriptor
	ljmp $0x8, $ExecKMain

	.code32

ExecKMain:
	sti
	call kmain
	cli

Hang:
	hlt
	jmp Hang
User avatar
Griwes
Member
Member
Posts: 374
Joined: Sat Jul 30, 2011 10:07 am
Libera.chat IRC: Griwes
Location: Wrocław/Racibórz, Poland
Contact:

Re: Far Jump in Protected Mode to clear the prefetch queue

Post by Griwes »

I would guess that this part is important:

Code: Select all

00056656013e[CPU0 ] check_cs(0x0008): not a valid code segment !
Reaver Project :: Repository :: Ohloh project page
<klange> This is a horror story about what happens when you need a hammer and all you have is the skulls of the damned.
<drake1> as long as the lock is read and modified by atomic operations
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

Re: Far Jump in Protected Mode to clear the prefetch queue

Post by teodori »

Hii,
yep you are right, but why?
Am I loading garbage into the GDTR or is my GDT entry wrong?

In my boot loader I load 10 sectors to 0x50, 0x0, set registers (DS, ES, etc..),
then far jump to 0x50, 0x0.
The kernel freshly loaded to memory displays "kernel...", then tripple faults.

Can you show me what I need to put in my GDT entry Code and Data?

Thank you
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Far Jump in Protected Mode to clear the prefetch queue

Post by Brendan »

Hi,
teodori wrote:Here is my code which is loaded to 0x50:0x0 by MBR using BIOS interrupts:
teodori wrote:

Code: Select all

gdtptr:
	.word (gdt_end - gdt - 1)
	.long gdt
For "gdtptr", the address of the GDT is a linear address (e.g. "gdt + 0x0050 * 16") and not a virtual address (e.g. "gdt").


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

Re: Far Jump in Protected Mode to clear the prefetch queue

Post by teodori »

:D yep so I loaded garbage into GDTR.
But if what you said is correct "kernel..." should also not be displayed?

Here is my boot loader:

Code: Select all

.section .rodata

msg:
	.asciz "booting..."
msgend:

msglen:
	.word (msgend - msg)

errmsg:
	.asciz "disk error!"
errmsgend:

errmsglen:
	.word (errmsgend - errmsg)

.section .text

.globl Start

Start:
	.code16

SaveDriveNumber:
	# Save Boot Device Number just before MBR load address
	# This byte is set by the BIOS into registry DL
	mov %dl, 0x7bff

SetVideoMode:
	clr %ah							# Set Video Mode
	mov $0x03, %al			# 3rd Mode -> 80x25
	int $0x10						# Video Interrupt

PrintBootMsg:
	mov $0x06, %ah			# Clear Screen
	clr %al							# Lines to scroll (0 = clear -> CX & DX)
	mov $0x0f, %bh			# Color Black White
	clr %cx							# Upper Left Corner
	mov $25, %dh				# 25 Lines
	mov $80, %dl				# 80 Columns
	int $0x10						# Video Interrupt

	clr %ax
	mov %ax, %es				# Set Extra Segment to 0x0
	mov $msg, %bp				# Set base pointer to msg location

	mov $0x13, %ah			# Print String
	mov $0x01, %al			# Char only - Cursor moved
	clr %bh							# Page Number
	mov $0x0f, %bl			# Color Black White
	mov msglen, %cx			# Message Length
	mov $1, %dh					# Row 1 
	mov $1, %dl					# Column 1
	int $0x10						# Video Interrupt

ResetDisk:
	clr %ah							# Reset Disk
	mov 0x7bff, %dl			# Drive (from Memory Loacation)
	int $0x13						# Disk Interrupt

	jc PrintErrorMsg		# If CF set jump to PrintErrorMsg

LoadFromDisk:
	mov $0x0050, %ax
	mov %ax, %es				# Set Extra Segment to 0x0050

	mov $0x02, %ah			# Read Disk Sectors
	mov $0x01, %al			# Read one sector only (512 bytes per sector)
	clr %bx							# Offset 0 - Start of Segment
	clr %ch							# Track 0
	mov $0x02, %cl			# Sector 2
	clr %dh							#	Head 0
	mov 0x7bff, %dl			# Drive (from Memory Loacation)
	int $0x13						# Disk Interrupt

	jc PrintErrorMsg		# If CF set jump to PrintErrorMsg

SetupSegments:
	mov $0x0050, %ax		# Segment 0x0050
	mov %ax, %ds				# Set Data Segment
	mov %ax, %es				# Set Extra Segment
	mov %ax, %fs				# Set Data2 Segment
	mov %ax, %gs				# Set Data3 Segment
	mov %ax, %ss				# Set Stack Segment

	ljmp $0x0050, $0x0	# Far Jump to CS:IP

PrintErrorMsg:
	clr %ax
	mov %ax, %es				# Set Extra Segment to 0x0
	mov $errmsg, %bp		# Set base pointer to msg location

	mov $0x13, %ah			# Print String
	mov $0x01, %al			# Char only - Cursor moved
	clr %bh							# Page Number
	mov $0x04, %bl			# Color Black Red
	mov errmsglen, %cx	# Message Length
	mov $3, %dh					# Row 3
	mov $1, %dl					# Column 1
	int $0x10						# Print Message

	cli									# Disable Interrupts

Hang:
	hlt									# Halt CPU
	jmp Hang						# Infinit loop if Halt does not work
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

Re: Far Jump in Protected Mode to clear the prefetch queue

Post by teodori »

Thank you Brendan,
you pointed me to the right direction, I loaded garbage instead of my GDT, because I used a wrong address. :D
User avatar
Griwes
Member
Member
Posts: 374
Joined: Sat Jul 30, 2011 10:07 am
Libera.chat IRC: Griwes
Location: Wrocław/Racibórz, Poland
Contact:

Re: Far Jump in Protected Mode to clear the prefetch queue

Post by Griwes »

teodori wrote::D yep so I loaded garbage into GDTR.
But if what you said is correct "kernel..." should also not be displayed?
There is a difference between how local data is accessed (as in, it takes segments into consideration), and how CPU loads GDT internally (without thinking about which segment you may have in mind). It just loads physical address specified by pointer.
Reaver Project :: Repository :: Ohloh project page
<klange> This is a horror story about what happens when you need a hammer and all you have is the skulls of the damned.
<drake1> as long as the lock is read and modified by atomic operations
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

Re: Far Jump in Protected Mode to clear the prefetch queue

Post by teodori »

Sorry, next problem :(
but small victory: CS.d_b = 32 bit

Code: Select all

00042492025i[CPU0 ] LOCK prefix unallowed (op1=0x57, modrm=0x00)
00042492025e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
00042492025e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00042492025e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00042492025i[CPU0 ] CPU is in protected mode (active)
00042492025i[CPU0 ] CS.d_b = 32 bit
00042492025i[CPU0 ] SS.d_b = 16 bit
00042492025i[CPU0 ] EFER   = 0x00000000
00042492025i[CPU0 ] | RAX=0000000060000011  RBX=0000000000000003
00042492025i[CPU0 ] | RCX=000000000009000a  RDX=0000000000000301
00042492025i[CPU0 ] | RSP=000000000000ffd6  RBP=0000000000000127
00042492025i[CPU0 ] | RSI=00000000000e474c  RDI=000000000000ffac
00042492025i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00042492025i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00042492025i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00042492025i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00042492025i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00042492025i[CPU0 ] | SEG selector     base    limit G D
00042492025i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00042492025i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00042492025i[CPU0 ] |  DS:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00042492025i[CPU0 ] |  SS:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00042492025i[CPU0 ] |  ES:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00042492025i[CPU0 ] |  FS:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00042492025i[CPU0 ] |  GS:0050( 0005| 0|  0) 00000500 0000ffff 0 0
00042492025i[CPU0 ] |  MSR_FS_BASE:0000000000000500
00042492025i[CPU0 ] |  MSR_GS_BASE:0000000000000500
00042492025i[CPU0 ] | RIP=0000000000000035 (0000000000000035)
00042492025i[CPU0 ] | CR0=0x60000011 CR2=0x0000000000000000
00042492025i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00042492025i[CPU0 ] 0x0000000000000035>> inc dword ptr ds:[eax] : FF00
00042492025e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00042492025i[SYS  ] bx_pc_system_c::Reset(HARDWARE) called
00042492025i[CPU0 ] cpu hardware reset
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Far Jump in Protected Mode to clear the prefetch queue

Post by Brendan »

Hi,
teodori wrote:

Code: Select all

	# In Protected Mode	: ljmp Selector, Offset
	# Selector:
	#  0x0	= NullDescriptor
	#  0x8	= CodeDescriptor
	#  0x10	= DataDescriptor
	ljmp $0x8, $ExecKMain

	.code32

ExecKMain:
	sti
	call kmain
	cli
It's probably a good idea to load an IDT and setup valid (for protected mode) interrupt descriptors before you enable interrupts with STI. Otherwise the CPU gets all confused and thinks the real mode IVT (the one with 4-byte entries) is an IDT (with 8-byte entries) and can execute random code (or crash, or both).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Far Jump in Protected Mode to clear the prefetch queue

Post by gerryg400 »

Code: Select all

ExecKMain:
   sti
   call kmain
   cli
Don't use sti (enable interrupts) until you have a valid IDT.
If a trainstation is where trains stop, what is a workstation ?
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

Re: Far Jump in Protected Mode to clear the prefetch queue

Post by teodori »

:) Problem corrected the base address for code and data GDT was wrong set it to 0x0500, now it's working.
Brendan and gerryg400: you are right :) that's exactly what I'll do now.
My idea is to write a bootloader and a small kernel using GNU tools (as, ld and gcc) for a tutorial,
so that anyone can understand how a PC boots and write an OS from scratch.

Here is the result:

Code: Select all

00014041550i[BIOS ] Booting from 0000:7c00
00014164025i[CPU0 ] WARNING: HLT instruction with IF=0!
00218284000p[SDL  ] >>PANIC<< User requested shutdown.
00218284000i[CPU0 ] CPU is in protected mode (halted)
00218284000i[CPU0 ] CS.d_b = 32 bit
00218284000i[CPU0 ] SS.d_b = 32 bit
00218284000i[CPU0 ] EFER   = 0x00000000
00218284000i[CPU0 ] | RAX=00000000000a0001  RBX=0000000000000003
00218284000i[CPU0 ] | RCX=000000000009000a  RDX=0000000000000301
00218284000i[CPU0 ] | RSP=000000000000ffd6  RBP=000000000000012f
00218284000i[CPU0 ] | RSI=00000000000e474c  RDI=000000000000ffac
00218284000i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00218284000i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00218284000i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00218284000i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00218284000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af pf cf
00218284000i[CPU0 ] | SEG selector     base    limit G D
00218284000i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00218284000i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000500 ffffffff 1 1
00218284000i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000500 ffffffff 1 1
00218284000i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000500 ffffffff 1 1
00218284000i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000500 ffffffff 1 1
00218284000i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000500 ffffffff 1 1
00218284000i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000500 ffffffff 1 1
00218284000i[CPU0 ] |  MSR_FS_BASE:0000000000000500
00218284000i[CPU0 ] |  MSR_GS_BASE:0000000000000500
00218284000i[CPU0 ] | RIP=000000000000004b (000000000000004b)
00218284000i[CPU0 ] | CR0=0x60000011 CR2=0x0000000000000000
00218284000i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00218284000i[CPU0 ] 0x000000000000004b>> jmp .-3 (0x0000054a) : EBFD
00218284000i[CMOS ] Last time is 1352946238 (Thu Nov 15 03:23:58 2012)
00218284000i[     ] restoring default signal behavior
00218284000i[CTRL ] quit_sim called with exit code 1
Post Reply