Page 1 of 1

Enabling paging causes reboot

Posted: Sun Apr 19, 2015 9:32 am
by osdever
When i'm implemented paging, all is compiled and linked fine, but when i start OS it immediately reboots. How to fix it?

Re: Enabling paging causes reboot

Posted: Sun Apr 19, 2015 10:53 am
by kzinti
By debugging it.

Re: Enabling paging causes reboot

Posted: Sun Apr 19, 2015 11:24 am
by iansjack
This is pretty elementary stuff and demonstrates that you probably don't understand what you are doing. (Have you read the Intel programmer's manual?) Most likely cause is an invalid page table. I was going to say that it was difficult to be sure as you hadn't posted your code. On reflection, that might only encourage you to post it in the expectation that someone would debug it for you.

The good news is that you now have an incentive to learn how to debug code. Take some time out to master this.

Re: Enabling paging causes reboot

Posted: Sun Apr 19, 2015 11:16 pm
by osdever
My code is from Setting Up Paging article.

Re: Enabling paging causes reboot

Posted: Sun Apr 19, 2015 11:35 pm
by Roman
catnikita255 wrote:My code is from Setting Up Paging article.
The code is probably not suited for the environment you set up. Anyway, we can't know what's wrong. I used the information from the wiki, and everything worked excellent.

Re: Enabling paging causes reboot

Posted: Mon Apr 20, 2015 12:04 am
by iansjack
catnikita255 wrote:My code is from Setting Up Paging article.
It looks like you have identity mapped the first 4 MB of RAM. Is your code running at an address in that mapped space?

Re: Enabling paging causes reboot

Posted: Sat Apr 25, 2015 7:49 am
by digo_rp
Forgive for my poor english, but...

First of all you need to make sure that all page_dir and page_tables everything is 4kb aligned something like. 0x9A000, 0x9B000, 0x9C000 got it?
and then all that memory address must be insided of mapped address, let me try to explain... if you map the first 4MB all page dir and page table must be inside that
4MB memory, in case of your kernel be bigger then 4MB you need to map the first 2 page_dir[0] and page_dir[1] and so... got it?

load pagedir into cr3... and then change bit 31 into cr0 with something like set_cr0( get_cr0() | 0x80000000 );

try to halt system on isr 14...

like

printf("Address of fault %Xh\n", cr2);
for(;;);

this helps a lot...

sorry this is only that I can write, again sorry about my poor english :D

Re: Enabling paging causes reboot

Posted: Sat Apr 25, 2015 9:44 am
by iansjack
all that memory address must be insided of mapped address, let me try to explain... if you map the first 4MB all page dir and page table must be inside that
4MB memory
That is incorrect. Page Directories and Page Tables use physical addresses and can be anywhere in available physical memory.

Re: Enabling paging causes reboot

Posted: Sat Apr 25, 2015 10:47 am
by KemyLand
Again, my example/actual bootstrap code, maybe it helps?

Code: Select all

.set ALIGN,	1<<0			 # align loaded modules on page boundaries
.set MEMINFO,  1<<1			 # provide memory map
.set FLAGS,	ALIGN | MEMINFO  # this is the Multiboot 'flag' field
.set MAGIC,	0x1BADB002		# 'magic number' lets bootloader find the header
.set CHECKSUM, -(MAGIC + FLAGS) # checksum of above, to prove we are multiboot

.section .multiboot
.long MAGIC
.long FLAGS
.long CHECKSUM

.section .stack, "aw", @nobits
stackBottom:
	.skip 16384
stackTop:

.set KVIRT_BASE, 0xC0000000
.set KPAGE_NUM,	(KVIRT_BASE >> 12)

.section .bss
.align 0x1000
pageDirectory:
	.skip 0x1000		# Page directory
pageTables:
	.skip 0x1000		# First identity-mapped 4MiB
	.skip 0x1000 * 256	# 3GiB to 4GiB area

gdtPtr:
	.skip 6		# GDT Pointer
gdt:
	.skip 8 * 3	# Actual GDT

idtPtr:
	.skip 6			# IDT Pointer
idt:
	.skip 8 * 256	# Actual IDT

.section .boot
.global __start__
__start__:
	# A Multiboot-compliant bootloader just yielded
	# execution to the OS here. At this moment,
	# everything is loaded at 1MiB, but the code
	# thinks it's on 3GiB! The solution? Subtract
	# 3GiB from *each* address used, so it resolves
	# to the correct physical address. That's the job
	# of the 'subl $KVIRT_BASE, %edx' stuff all around
	# this function. Once the paging structures are fully
	# calculated and loaded, __start__() can work with virtual
	# addresses. It then passes control to realStart(), the
	# routine responsible for parsing the Multiboot information (TODO),
	# setting up the descriptor tables (GDT and IDT), and
	# finally calling KernelInit. If something fails,
	# criticalError() is a minimalistic asm version of KTPipe
	# that writes some string in red/white to VGA memory and halts.
		
	# Load the stack (I can't live up from the registers!)
	movl $stackTop, %esp
	subl $KVIRT_BASE, %esp
	
	# Save Multiboot Information (%ebx) and Bootloader Magic (%eax) 
	push %eax
	push %ebx
	
	# Map the first 4MiB to the first page table
	movl $pageDirectory, %edx
	subl $KVIRT_BASE, %edx
	movl $pageTables, %eax
	subl $KVIRT_BASE, %eax
	orl $0x00000003, %eax
	movl %eax, (%edx)
	
	# Identity map the first page table
	movl $pageTables, %edi
	subl $KVIRT_BASE, %edi
	movl $1024, %ecx
	movl %ecx, %ebx
	.identmap:
		movl %ebx, %eax
		subl %ecx, %eax
		movl %eax, %esi
		shll $12, %esi
		orl $0x00000003, %esi
		movl $4, %edx
		mull %edx
		movl %edi, %edx
		addl %eax, %edx
		movl %esi, (%edx)
		loop .identmap
	
	# Map the first Gigabyte to 3GiB upwards
	movl $pageTables, %edi
	subl $KVIRT_BASE, %edi
	addl $0x1000, %edi
	movl $256, %ecx
	movl $0, %edx
	.highmap:
		movl %ecx, %ebx
		movl $1024, %ecx
		
		.highmap2:
			movl %edx, %eax
			shll $12, %eax
			orl $0x00000003, %eax
			movl %eax, (%edi)
			incl %edx
			addl $4, %edi
			loop .highmap2
		
		movl %ebx, %ecx
		loop .highmap
	
	# Load the higher-half tables
	movl $pageDirectory, %edx
	subl $KVIRT_BASE, %edx
	addl $3072, %edx
	movl $256, %ecx
	movl %ecx, %ebx
	.filltop:
		movl %ebx, %esi
		subl %ecx, %esi
		movl %edx, %edi
		movl $0x1000, %eax
		mull %esi
		movl %edi, %edx
		movl $pageTables, %edi
		subl $KVIRT_BASE, %edi
		addl $0x1000, %edi
		addl %eax, %edi
		orl $0x00000003, %edi
		movl %edx, %ebp
		movl $4, %eax
		mull %esi
		movl %ebp, %edx
		addl %edx, %eax
		movl %edi, (%eax)
		loop .filltop
	
	# Load the page directory
	movl $pageDirectory, %edx
	subl $KVIRT_BASE, %edx
	movl %edx, %cr3
	
	# Enable paging
	movl %cr0, %edx
	orl $0x80000000, %edx
	movl %edx, %cr0
	
	# Jump to some code that *really* assumes it's on $KVIRT_BASE
	movl $realStart, %edx
	jmp *%edx

.text
realStart:
	# Load the virtual value of $stackTop
	# And, to comply with the ABI, load %esp into %ebp
	addl $KVIRT_BASE, %esp
	movl %esp, %ebp
	
	# Setup the Global Descriptor Table (GDT) Pointer
	movl $gdtPtr, %edx
	movl $gdt, %eax
	movw $23, (%edx)
	movl %eax, 2(%edx)
	
	# Load the Null GDT Entry
	push $0
	push $0
	push $0
	push $0
	push $0
	call setGDTEntry
	addl $20, %esp
	
	# Load the Kernel Code GDT Entry
	push $0xCF
	push $0x9A
	push $0xFFFFFFFF
	push $0
	push $1
	call setGDTEntry
	addl $20, %esp
	
	# Load the Kernel Data GDT Entry
	push $0xCF
	push $0x92
	push $0xFFFFFFFF
	push $0
	push $2
	call setGDTEntry
	addl $20, %esp
	
	# Actually load the full GDT
	movl $gdtPtr, %eax
	lgdt (%eax)				# Do it!
	movw $0x10, %ax			# Load the data segment registers
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %fs
	movw %ax, %gs
	ljmp $0x08, $.gdtReady	# Some black magic to load %cs
	.gdtReady:
	
	# Do the same as above, but with the Interrupt Descriptor Table (IDT) Pointer
	movl $idtPtr, %edx
	movl $idt, %eax
	movw $384, (%edx)
	movl %eax, 2(%edx)
	
	# We'll load *all* the ISRs, so we need to use as less code as possible,
	# but stack memory is infinite, as far as the processor is concerned :)
	subl $192, %esp
	
	#define ISR(no, who) \
		movl $__inthand_ ## who ## __, %eax; \
		movl %eax, no(%esp);
	
	ISR(0, exc0)
	ISR(4, exc1)
	ISR(8, exc2)
	ISR(12, exc3)
	ISR(16, exc4)
	ISR(20, exc5)
	ISR(24, exc6)
	ISR(28, exc7)
	ISR(32, exc8)
	ISR(36, exc9)
	ISR(40, exc10)
	ISR(44, exc11)
	ISR(48, exc12)
	ISR(52, exc13)
	ISR(56, exc14)
	ISR(60, exc15)
	ISR(64, exc16)
	ISR(68, exc17)
	ISR(72, exc18)
	ISR(76, exc19)
	ISR(80, exc20)
	ISR(84, exc21)
	ISR(88, exc22)
	ISR(92, exc23)
	ISR(96, exc24)
	ISR(100, exc25)
	ISR(104, exc26)
	ISR(108, exc27)
	ISR(112, exc28)
	ISR(116, exc29)
	ISR(120, exc30)
	ISR(124, exc31)
	ISR(128, irq0)
	ISR(132, irq1)
	ISR(136, irq2)
	ISR(140, irq3)
	ISR(144, irq4)
	ISR(148, irq5)
	ISR(152, irq6)
	ISR(156, irq7)
	ISR(160, irq8)
	ISR(164, irq9)
	ISR(168, irq10)
	ISR(172, irq11)
	ISR(176, irq12)
	ISR(180, irq13)
	ISR(184, irq14)
	ISR(188, irq15)
	
	#undef ISR
	
	# Actually set the IDT entries
	movl $48, %ecx
	.idtLoop:
		movl %ecx, %ebx
		movl $48, %esi
		subl %ebx, %esi
		movl (%esp, %esi, 4), %eax
		push $0x8E
		push $0x08
		push %eax
		push %esi
		call setIDTEntry
		addl $16, %esp
		movl %ebx, %ecx
		loop .idtLoop
	addl $192, %esp	# Free up that stack space
	
	# Load the IDT and we'll be done
	movl $idtPtr, %eax
	lidt (%eax)	# Do it! 
	
	# Reconfigure the PICs, so stupid stuff doesn't happens
	inb $0x21, %al
	movb %al, %bl
	inb $0xA1, %al
	movb %al, %cl
	movb $0x11, %al
	outb %al, $0x20
	outb %al, $0xA0
	movb $0x20, %al
	outb %al, $0x21
	movb $0x28, %al
	outb %al, $0xA1
	movb $0x04, %al
	outb %al, $0x21
	movb $0x02, %al
	outb %al, $0xA1
	movb $0x01, %al
	outb %al, $0x21
	outb %al, $0xA1
	movb %bl, %al
	outb %al, $0x21
	movb %cl, %al
	outb %al, $0xA1
	
	# Get Multiboot Information (%ebx) and Bootloader Magic (%eax)
	pop %ebx
	pop %eax
	
	# Check the Bootloader magic. If it's invalid, panic!
	cmp $0x2BADB002, %eax
	je .noerror
	# Error! **** it up!
	push $.ENOTMULTIBOOT # "Not using a Multiboot-compliant bootloader"
	push $0x01 # Error Code
	call criticalError
	.noerror:
	
	# Parse the first-level Multiboot Structure (TODO)
	addl $KVIRT_BASE, %ebx # Physical to Virtual
	
	# Call trivial global constructors
	call _init
	
	# Pass it to KernelInit()...
	push %ebx
	
	# Should I put a comment here? Anyway, I did it.
	call KernelInit
	
	# If KernelInit() somehow returns, halt the machine.
	# Non-maskable interrupt? Don't worry! Just loop forever.
	.hang:
		cli
		hlt
		jmp .hang

setGDTEntry:
	push %ebp
	movl %esp, %ebp
	
	push %esi					# We need some extra memory
	
	movl 8(%ebp), %eax			# GDT Index
	movl $gdt, %ecx
	
	movl 12(%ebp), %edx			# The base
	movw %dx, 2(%ecx, %eax, 8)	# Set low base
	shrl $16, %edx
	movb %dl, 4(%ecx, %eax, 8)	# Set middle base
	movb %dh, 7(%ecx, %eax, 8)	# Set high base
	
	movl 16(%ebp), %edx			# The limit
	movw %dx, (%ecx, %eax, 8)	# Set low limit
	
	movl 24(%ebp), %esi			# Granularity
	shrl $16, %edx
	andl $0x0F, %edx
	andl $0xF0, %esi
	orl %esi, %edx
	movb %dl, 6(%ecx, %eax, 8)	# Set granularity
	
	movl 20(%ebp), %edx			# Access
	movb %dl, 5(%ecx, %eax, 8)	# Set access
	
	pop %esi
	
	movl %ebp, %esp
	pop %ebp
	ret

setIDTEntry:
	push %ebp
	movl %esp, %ebp
	
	movl 8(%ebp), %eax			# IDT Index
	movl $idt, %ecx
	
	movl 12(%ebp), %edx			# The base
	movw %dx, (%ecx, %eax, 8)	# Set low base
	shrl $16, %edx
	movw %dx, 6(%ecx, %eax, 8)	# Set high base
	
	movl 16(%ebp), %edx			# The selector
	movw %dx, 2(%ecx, %eax, 8)	# Set selector
	
	movl 20(%ebp), %edx			# Flags
	movb %dl, 5(%ecx, %eax, 8)	# Set flags
	
	movb $0, 4(%ecx, %eax, 8)	# Always 0
	
	movl %ebp, %esp
	pop %ebp
	ret

criticalError:
	# %ebx is the offset over VGA memory used
	# by the criticalPrint* functions.
	movl $0, %ebx
	
	# "Fatal Error Code "
	movl $.EERROR, %eax
	call criticalPrintString
	
	pop %eax # Error Code
	call criticalPrintHex
	
	movb $0x3A, %al # ':' Character
	call criticalPrintChar
	movb $0x20, %al # ' ' Character
	call criticalPrintChar
	
	pop %eax # Error Message
	call criticalPrintString
	
	movl $.EHALT, %eax
	call criticalPrintString
	
	# Halt
	cli
	hlt

criticalPrintString:
	# Parameters:
	#	%eax: Address of null-terminated string to print
	
	.strloop:
		movb (%eax), %al
		cmp $0x00, %al
		je .strloopend
		call criticalPrintChar
		incl %eax
		incl %ebx
		jmp .strloop
	.strloopend:
		ret

criticalPrintHex:
	# Parameters:
	#	%eax: Integer to print
	
	movb $0x30, %al # '0' Character
	call criticalPrintChar 
	incl %ebx
	movb $0x78, %al # 'x' Character
	call criticalPrintChar
	incl %ebx
	
	movl $8, %ecx
	.hexloop:
		movl %ecx, %esi
		decl %esi
		push %eax
		movl %eax, %edi
		movl $4, %eax
		mull %esi
		xchg %eax, %ecx
		shrl %cl, %edi
		xchg %eax, %ecx
		movl %edi, %edx
		
		push %ecx
		movl $2, %ecx
		.hexbitloop:
			push %edx
			andb $0x0F, %dl
			
			# Get the real value...
			.hextest:
				cmpb $0x0A, %dl
				jb .hextestdecimal
				jae .hextesthexa
			.hextestdecimal:
				addb $0x30, %dl # Calculates character between '0' and '9'
				jmp .hextestend
			.hextesthexa:
				subb $0x0A, %dl # For offsetting
				addb $0x41, %dl
				jmp .hextestend
			.hextestend:
				movb %dl, %al
				call criticalPrintChar
				incl %ebx
				pop %edx
				shrl $4, %edx
				loop .hexbitloop
		
		pop %ecx
		pop %eax
		loop .hexloop
	ret

criticalPrintChar:
	# Parameters:
	#	%al: Character to print
	#	%ebx: Offset over VGA Memory
	# Uses:
	#	%dx: Actual value written to VGA Memory
	
	movb $0x4F, %dh				# White text on red background
	movb %al, %dl				# Mix it...
	movw %dx, 0xB8000(,%ebx, 2)	# Print!
	
	ret

.section rodata
# Concatenated on every error
.EERROR:
	.asciz "Fatal Error Code "
.EHALT:
	.asciz ". System halted! Please reboot manually."

# The actual errors
.ENOTMULTIBOOT:
.asciz "Not using a Multiboot-compliant bootloader"