GNU Assembler - Enter Long Mode

Programming, for all ages and all languages.
Locked
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

GNU Assembler - Enter Long Mode

Post by teodori »

Hello,
I need help, I want to switch to long mode using GNU Assembler. I'm stuck setting up the different page tables. I saw an example, but it is in Intel Assembly. Can anyone explain me how to proceed, please?

Here is the example: (I don't know what exectly what he is doing between enabling physical-address extensions and loading page-map level-4 base)
http://board.flatassembler.net/topic.php?t=6206

Here is my code: (I am stuck within "load CR3 with PML4" part)

Code: Select all

INITSEG = 0x0050
INITOFF = 0x0000

.section .rodata

gdt:
	# Null Descriptor
	.word 0x0000, 0x0000
	.byte 0x00, 0b00000000, 0b00000000, 0x00
	# Code Descriptor
	.word 0xffff, (INITSEG * 0x10 + INITOFF)
	.byte 0x00, 0b10011010, 0b11001111, 0x00
	# Data Descriptor
	.word 0xffff, (INITSEG * 0x10 + INITOFF)
	.byte 0x00, 0b10010010, 0b11001111, 0x00
gdt_end:

gdt32ptr:
	.word (gdt_end - gdt - 1)
	.long (gdt + INITSEG * 0x10 + INITOFF)

gdt64ptr:
	.word (gdt_end - gdt - 1)
	.quad (gdt + INITSEG * 0x10 + INITOFF)

.section .text

.globl Start

Start:
	.code16

	# Load Global Descriptor Table
	lgdt gdt32ptr

	# Load Control Register CR0
	# Enable Protected Mode (Bit0 in CR0)
	# Store Control Register CR0
	movl %cr0, %eax
	orl $(1<<0), %eax
	movl %eax, %cr0

	# Setup all Segment Registers
	# and reload Code Segment, Instruction Pointer
	movw $0x0010, %ax
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %fs
	movw %ax, %gs
	movw %ax, %ss
	ljmp $0x0008, $JumpToPM
JumpToPM:

	.code32

	# Load Control Register CR4
	# Enable Physical Address Extension (Bit5 in CR4)
	# Store Control Register CR4
	movl %cr4, %eax
	orl $(1<<5), %eax
	movl %eax, %cr4

#----------------- load CR3 with PML4 -----------------------------------------------
	movl $0x8000, %edi

	movl $0x0100, %ecx
PT:
	movw 0x0000, %ax
	pushw %ax
	loop PT

#	movl PML4, %eax
#	movl %eax, %cr3
#----------------- load CR3 with PML4 -----------------------------------------------

	# Use Model Specific Register 0xC0000080
	# Read from Model Specific Register
	# Enable Long Mode (Bit8)
	# Write to Model Specific Register
	movl $0xc0000080, %ecx
	rdmsr
	orl $(1<<8), %eax
	wrmsr

#----------------- halt, next instruction triple faults -----------------------------------------------
hlt
#----------------- halt, next instruction triple faults -----------------------------------------------

	# Load Control Register CR0
	# Enable Paging (Bit31 in CR0)
	# Store Control Register CR0
	movl %cr0, %eax
	orl $(1<<31), %eax
	movl %eax, %cr0

	.code64

	# Reload Global Descriptor Table
	lgdt gdt64ptr

	# Enter into the kernel
	call kmain

Hang:
	# Halt the CPU
	# Infinit loop if Halt doesn't work
	hlt
	jmp Hang
Thank you for any useful help!
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: GNU Assembler - Enter Long Mode

Post by Combuster »

I don't know what exectly what he is doing between enabling physical-address extensions and loading page-map level-4 base
Writing page tables to a fixed address in memory.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
sortie
Member
Member
Posts: 931
Joined: Wed Mar 21, 2012 3:01 pm
Libera.chat IRC: sortie

Re: GNU Assembler - Enter Long Mode

Post by sortie »

That kind of code is tedious to write and easy to forget. Here is my code for that purpose in GNU assembler syntax: https://gitorious.org/sortix/sortix/blo ... x64/boot.s

Perhaps you'll be able to find the relevant parts and adapt it for your needs. :-)
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

Re: GNU Assembler - Enter Long Mode

Post by teodori »

:D thank you
It is what I need, but I can't get it working. I'm doing something wrong in my paging tables. The error lies between the 2 "load CR3 with PML4".
I don't understand exactly what you are doing between line 60 and line 93. Can you give me some explications, please?
To make it simple I have also pasted the MBR code with loads and jumps to this part.

Code: Select all

INITSEG = 0x07e0
INITOFF = 0x0000

.section .rodata

gdt:
	# Null Descriptor
	.word 0x0000, 0x0000
	.byte 0x00, 0b00000000, 0b00000000, 0x00
	# Code Descriptor
	.word 0xffff, 0x0000
	.byte 0x00, 0b10011010, 0b11001111, 0x00
	# Data Descriptor
	.word 0xffff, 0x0000
	.byte 0x00, 0b10010010, 0b11001111, 0x00
gdt_end:

gdt32ptr:
	.word (gdt_end - gdt - 1)
	.long (gdt + INITSEG * 0x10 + INITOFF)

gdt64ptr:
	.word (gdt_end - gdt - 1)
	.quad (gdt + INITSEG * 0x10 + INITOFF)

.section .text

.globl Start

Start:
	.code16

	# Load Global Descriptor Table
	lgdt gdt32ptr

	# Load Control Register CR0
	# Enable Protected Mode (Bit0 in CR0)
	# Store Control Register CR0
	movl %cr0, %eax
	orl $(1<<0), %eax
	movl %eax, %cr0

	# Setup all Segment Registers
	# and reload Code Segment, Instruction Pointer
	movw $0x0010, %ax
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %fs
	movw %ax, %gs
	movw %ax, %ss
	ljmp $0x0008, $(JumpToPM + INITSEG * 0x10 + INITOFF)
JumpToPM:

	.code32

#----------------- load CR3 with PML4 -----------------------------------------------
	# Clear the first 0xE000 bytes following 0x1000000.
	movl $0x01000000, %edi
	movl %edi, %cr3
	clrl %eax
	movl $0x0000e000, %ecx
	rep stosl
	movl %cr3, %edi

	# Set the initial page tables.
	# Note that we OR with 0x7 here to allow user-space access, except in the
	# first 2 MiB. We also do this with 0x200 to allow forking the page.

	# Page-Map Level 4
	movl $0x01002000, (%edi)
	addl $0x00001000, %edi

	# Page-Directory Pointer Table
	movl $0x01004000, (%edi)
	addl $0x00001000, %edi

	# Page-Directory (no user-space access here)
	movl $0x01006000, (%edi) # (First 2 MiB)
	movl $0x01008000, 8(%edi) # (Second 2 MiB)
	addl $0x1000, %edi

	# Page-Table
	# Memory map the first 4 MiB.
	clrl %ebx
	movl $1024, %ecx

SetEntry:
	mov %ebx, (%edi)
	add $0x1000, %ebx
	add $8, %edi
	loop SetEntry
#----------------- load CR3 with PML4 -----------------------------------------------

	# Load Control Register CR4
	# Enable Physical Address Extension (Bit5 in CR4)
	# Store Control Register CR4
	movl %cr4, %eax
	orl $(1<<5), %eax
	movl %eax, %cr4

	# Use Model Specific Register 0xC0000080
	# Read from Model Specific Register
	# Enable Long Mode (Bit8)
	# Write to Model Specific Register
	movl $0xc0000080, %ecx
	rdmsr
	orl $(1<<8), %eax
	wrmsr

#-------------------- stop before error -----------------------------------------------
hlt
#-------------------- stop before error -----------------------------------------------

	# Load Control Register CR0
	# Enable Paging (Bit31 in CR0)
	# Store Control Register CR0
	movl %cr0, %eax
	orl $(1<<31), %eax
	movl %eax, %cr0

	.code64

	# Reload Global Descriptor Table
	lgdt gdt64ptr

	# Enter into the kernel
	call kmain

Hang:
	# Halt the CPU
	# Infinit loop if Halt doesn't work
	hlt
	jmp Hang

Code: Select all

BOOTSEG = 0x07c0
INITSEG = 0x07e0
INITOFF = 0x0000

.section .rodata

msg:
	.asciz "loading system..."
msgend:

msglen:
	.word (msgend - msg)

errmsg:
	.asciz "boot error!"
errmsgend:

errmsglen:
	.word (errmsgend - errmsg)

lba:
	# LBA packet size, always 0
	.byte 0x10, 0x00
	# sectors to read, always 0
	.byte 0xff, 0x00
	# load address
	.long (INITSEG * 0x10 + INITOFF)
	# start read from 2nd sector
	.long 0x00000001

.section .text

.globl Start

Start:
	.code16

	# Disable Interrupts during setup
	cli

	# Setup all Segment Registers
	# and reload Code Segment, Instruction Pointer
	movw $BOOTSEG, %ax
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %fs
	movw %ax, %gs
	movw %ax, %ss
	ljmp $BOOTSEG, $ReloadCSIP
ReloadCSIP:

	# Setup Stack
	# Save Boot Device to Stack
	movw $0x0200, %sp
	movw %sp, %bp
	pushw %dx

	# Enable Interrupts temporarily
	sti

	# Set Video Mode AH=0x00
	# 80x25 Mode AL=0x03
	# Video Interrupt INT=0x10
	clrb %ah
	movb $0x03, %al
	int $0x10

	# Clear Screen AH=0x06
	# Lines to scroll (0 is entire window) AL=0x00
	# Color attributes (0F is Black and White) BH=0x0F
	# Upper Left Corner CH=00/CL=00
	# Lower Right Corner DH=25/DL=80
	# Video Interrupt INT=0x10
	movb $0x06, %ah
	clrb %al
	movb $0x0f, %bh
	clrw %cx
	movb $25, %dh
	movb $80, %dl
	int $0x10

	# String to print ES:BP
	# Print String AH=0x13
	# Char only - Cursor moved AL=0x01
	# Page Number BH=0x00
	# Color attributes (0F is Black and White) BL=0x0F
	# Message Length CX
	# Row DH=0
	# Column DL=0
	# Video Interrupt INT=0x10
	movw $BOOTSEG, %ax
	movw %ax, %es
	movw $msg, %bp
	movb $0x13, %ah
	movb $0x01, %al
	clrb %bh
	movb $0x0f, %bl
	movw msglen, %cx
	movb $0, %dh
	movb $0, %dl
	int $0x10

	# Enable A20 Gate AX=0x2401
	# System Interrupt INT=0x15
	movw $0x2401, %ax
	int $0x15
	jc Error

	# Reset Disk AH=0x00
	# Drive Number DL=(from stack)
	# Disk Interrupt INT=0x13
	clrb %ah
	popw %dx
	int $0x13
	jc Error

	# Extension Test AH=0x41
	# BX=0x55AA
	# Drive Number DL=(from stack)
	# Disk Interrupt INT=0x13
	movb $0x41, %ah
	movw $0x55aa, %bx
	int $0x13
	jc Error

	# LBA Packet DS:SI
	# Extended Read AH=0x42
	# Drive Number DL=(from stack)
	movw $lba, %si
	movb $0x42, %ah
	int $0x13
	jc Error

	# Disable Interrupts before jumping to 2nd stage bootloader
	cli

	# Setup all Segment Registers
	# and jump to 2nd stage bootloader
	movw $INITSEG, %ax
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %fs
	movw %ax, %gs
	movw %ax, %ss
	ljmp $INITSEG, $INITOFF

Error:
	# String to print ES:BP
	# Print String AH=0x13
	# Char only - Cursor moved AL=0x01
	# Page Number BH=0x00
	# Color attributes (0F is Black and Red) BL=0x04
	# Message Length CX
	# Row DH=1
	# Column DL=0
	# Video Interrupt INT=0x10
	movw $BOOTSEG, %ax
	movw %ax, %es
	movw $errmsg, %bp
	movb $0x13, %ah
	movb $0x01, %al
	clrb %bh
	movb $0x04, %bl
	movw errmsglen, %cx
	movb $1, %dh
	movb $0, %dl
	int $0x10

	# Disable Interrupts before Halt
	cli

Hang:
	# Halt the CPU
	# Infinit loop if Halt doesn't work
	hlt
	jmp Hang
User avatar
sortie
Member
Member
Posts: 931
Joined: Wed Mar 21, 2012 3:01 pm
Libera.chat IRC: sortie

Re: GNU Assembler - Enter Long Mode

Post by sortie »

Honestly, even I am a bit confused what those lines do.

Read the comments, I'm setting up paging at addresses below 1 MiB that are reasonably safe. Notice how I am setting up long paging, but paging isn't enabled yet. When I enable PAE, it knows to use the bigger paging structures, when I switch to long mode it goes into the 32-bit compatibility mode, then I enable paging (the first 4 MiB are identity mapped) and do a long jump to long mode.
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

Re: GNU Assembler - Enter Long Mode

Post by teodori »

I don't understand the paging setup part... And I am not that good in assembly :(
Here is what my bochs machine says:

Code: Select all

00128534728i[BIOS ] Booting from 0000:7c00
00128750221i[CPU0 ] CPU is in compatibility mode (active)
00128750221i[CPU0 ] CS.d_b = 32 bit
00128750221i[CPU0 ] SS.d_b = 32 bit
00128750221i[CPU0 ] EFER   = 0x00000500
00128750221i[CPU0 ] | RAX=00000000e0000011  RBX=0000000000400000
00128750221i[CPU0 ] | RCX=00000000c0000080  RDX=0000000000000000
00128750221i[CPU0 ] | RSP=0000000000000200  RBP=0000000000000099
00128750221i[CPU0 ] | RSI=00000000000e00bb  RDI=0000000000035000
00128750221i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00128750221i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00128750221i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00128750221i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00128750221i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf SF zf af PF cf
00128750221i[CPU0 ] | SEG selector     base    limit G D
00128750221i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00128750221i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00128750221i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00128750221i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00128750221i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00128750221i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00128750221i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00128750221i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00128750221i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00128750221i[CPU0 ] | RIP=0000000000007e96 (0000000000007e96)
00128750221i[CPU0 ] | CR0=0xe0000011 CR2=0x0000000000000080
00128750221i[CPU0 ] | CR3=0x00030000 CR4=0x00000020
00128750221i[CPU0 ] 0x0000000000007e96: (instruction unavailable) page not present
00128750221e[CPU0 ] exception(): 3rd (14) exception with no resolution, shutdown status is 00h, resetting
00128750221i[SYS  ] bx_pc_system_c::Reset(HARDWARE) called
00128750221i[CPU0 ] cpu hardware reset
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: GNU Assembler - Enter Long Mode

Post by Combuster »

teodori wrote:0x0000000000007e96: (instruction unavailable) page not present
Obvious error is obvious.

Nevertheless, fire up the debugger and start poking around in memory to see what ended up where. It's a good exercise and it shows you what things should be fixed where.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

Re: GNU Assembler - Enter Long Mode

Post by teodori »

@sorti
look over this page http://www.lowlevel.eu/wiki/Paging#Paging_im_Long_Mode (It is in german).
As far as I can see, in your code you don't set those bits explained on this web page.
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

Re: GNU Assembler - Enter Long Mode

Post by teodori »

@Combuster
Can you help me setting up my PML4, PDP, PD, and PT, please?
I don't understand how it works exactly and how to define them.
For now I try to define them between 0x30000 and 0x40000, a little after my boot code and under the 1 MB barrier.

Code: Select all

#----------------- load CR3 with PML4 -----------------------------------------------
	# Clear the first 0x10000 bytes following 0x30000.
	movl $0x00030000, %edi
	movl %edi, %cr3
	clrl %eax
	movl $0x00010000, %ecx
	rep stosl
	movl %cr3, %edi

	# Page-Map Level 4
	movl $0x00031000, (%edi)
	movl $0x00000003, 4(%edi)
	addl $0x00001000, %edi

	# Page-Directory Pointer Table
	movl $0x00032000, (%edi)
	movl $0x00000003, 4(%edi)
	addl $0x00001000, %edi

	# Page-Directory, the First 2 MiB and the Second 2 MiB 
	movl $0x00033000, (%edi)
	movl $0x00000003, 4(%edi)
	movl $0x00034000, 8(%edi)
	movl $0x00000003, 12(%edi)
	addl $0x00001000, %edi

	# Page-Table
	# Memory map the first 4 MiB (0x400 = 1024 entries)
	movl $0x00000003, %ebx
	movl $0x00000400, %ecx

SetEntry:
	mov %ebx, (%edi)
	addl $0x1000, %ebx
	addl $8, %edi
	loop SetEntry
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: GNU Assembler - Enter Long Mode

Post by Combuster »

teodori wrote:@Combuster
Can you help
Smart questions forum rule wrote:You are likely to be ignored, or written off as a loser, if you:
(...)
post a personal e-mail to somebody who is neither an acquaintance of yours nor personally responsible for solving your problem
------
I wrote:fire up the debugger and start poking around in memory to see what ended up where.
Until you can show me the exact eight bytes (in both quadword and byte units) at 0x30000, I'll consider you a lazy beggar.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

Re: GNU Assembler - Enter Long Mode

Post by teodori »

You don't need to be pissed off, because I am asking for help. I wouldn't be asking all those questions, if I know all these things. Not everyone is assembly expert. You are no better then me, if you cannot help me.
Locked