Newer
Older
ubix-64 / src / sys / boot / setup64.s
##                Align modules on page boundaries ----+
##                Always provide memory information --+|
##                Header contains video mode fields -+||
##                Not an ELF image ----+             |||
##                                     |             |||
##                                     v             vvv
	.equ	MBHF, 0b00000000000000010000000000000011

# Fool LD!
	.global	_start
_start:
	
##                 magic    flags       checksum
mbhdr:	.long	0x1BADB002, MBHF, -(0x1BADB002 + MBHF)
	.long	mbhdr, 0x100000, 0, 0, start
##	       hdraddr loadaddr le bss entry	(le = load end addr)

magic:	.long	0
mbptr:	.long	0
cpuid_d: .long	0
cpuidx_d: .long	0
	.equ	initial_stack, 0x106000
	
	.code32
start:		# Set up stack
	movl	$initial_stack, %esp
	movl	%esp, %ebp
	pushl	$2			# only reserved bit set
	popf
	cld

	# save some vars
	movl	%eax, (magic)
	movl	%ebx, (mbptr)

	# get highest normal function
	movl	$0, %eax
	cpuid
	cmpl	$1, %eax
	jb	halt

	# get function bits
	incl	%eax
	cpuid
	movl	%edx, (cpuid_d)
	
	# get highest EXT function
	movl	$0x80000000, %eax
	cpuid
	cmpl	$0x80000001, %eax
	jb	halt

	# get EXT function bits
	incl	%eax
	cpuid
	btl	$29, %edx	# Long Mode
	jz	halt
	movl	%edx, (cpuidx_d) # save edx

	movl	$0xC0000080, %eax
	rdmsr
	btsl	$8, %eax	# LME
	btl	$20, (cpuidx_d)	# NX?
	jnc	1f
	btsl	$11, %eax	# NX
1:	wrmsr

	# Use the area at (0x3F0000-0x400000) for pagetables.
	.equ	pg_l4t,		0x3F0000
	.equ	pg_pdpt,	0x3F1000
	.equ	pg_dir0,	0x3F2000
	.equ	pg_dir3,	0x3F3000
	.equ	pg_dir0_tbl0,	0x3F4000
	.equ	pg_dir0_tbl1,	0x3F5000
	.equ	pg_dir0_tbl2,	0x3F6000
	.equ	pg_dir3_tbl0,	0x3F7000
	.equ	pg_dir3_tbl1,	0x3F8000
	.equ	pg_dir3_tbl383,	0x3F9000
	.equ	pg_dir3_tbl384,	0x3FA000

	# Zero 'em all!
	movl	$0x3F0000, %edi
	movb	$0,	   %al
	movl	$0xB000,   %ecx
	rep
	stosb

	# These addresses are all 64-bits, but
	# we don't have to specify the zero high-ends
	# since everything was zeroed above.

	# One l4t entry.
	movl	$pg_pdpt | 0x7, (pg_l4t)
	
	# Two PDPT entries.
	movl	$pg_dir0 | 0x7, (pg_pdpt)
	movl	$pg_dir3 | 0x7, (pg_pdpt+24)

	# Pagedir 0: 3 PDEs.
	movl	$pg_dir0_tbl0 | 0x7, (pg_dir0)
	movl	$pg_dir0_tbl1 | 0x7, (pg_dir0+8)
	movl	$pg_dir0_tbl2 | 0x7, (pg_dir0+16)
	# Pagedir 3: 4 PDEs.
	movl	$pg_dir3_tbl0 | 0x7, (pg_dir3)
	movl	$pg_dir3_tbl1 | 0x7, (pg_dir3+8)
	movl	$pg_dir3_tbl383 | 0x7, (pg_dir3+3064)
	movl	$pg_dir3_tbl384 | 0x7, (pg_dir3+3072)
	jmp	1f

map:	movl	%ebx, %eax
	movl	%edx, %ecx
	movl	%eax, (%edi)
	addl	$8, %edi
	addl	$0x1000, %eax
	dec	%ecx
	jnz	map
	ret

	# ID-map 0-6M.
1:	movl	$0x000003, %ebx		# addr
	movl	$0x200, %edx		# count
	
	movl	$pg_dir0_tbl0, %edi
	call	map
	addl	$0x200000, %ebx
	
	movl	$pg_dir0_tbl1, %edi
	call	map
	addl	$0x200000, %ebx
	
	movl	$pg_dir0_tbl2, %edi
	call	map

	# Map kernel.
	movl	$0xC0000003, %ebx

	movl	$pg_dir3_tbl0, %edi
	call	map
	addl	$0x200000, %ebx

	movl	$pg_dir3_tbl1, %edi
	call	map

	# Map VRAM.
	movl	$0xB8000 | 0x3, (pg_dir3_tbl384)

	# Map and use stack.
	movl	$0x100000 | 0x3, (pg_dir3_tbl383+4088)
	addl	$0xEFEFF000, %esp

	# Map the pagetables with a fractal recursive memory mapper.
	movl	$pg_l4t | 0x3, (pg_l4t+4088)

	# Enable paging.
	movl	$pg_l4t, %eax
	movl	%eax, %cr3
	
	movl	%cr4, %eax
	btl	$6, (cpuid_d)	# PAE?
	jnc	halt
	btsl	$5, %eax	# PAE
	
	btl	$14, (cpuid_d)	# MCE?
	jnc	1f
	btsl	$6, %eax	# MCE
	
1:	btl	$24, (cpuid_d)	# FXSR?
	jnc	1f
	btsl	$9, %eax	# OSFXSR
	
1:	btl	$25, (cpuid_d)	# SSE?
	jnc	1f
	btsl	$10, %eax	# OSXMMEXCPT
	movl	%eax, %cr4

	movl	%cr0, %eax
	btsl	$31, %eax	# PG
	movl	%eax, %cr0
	jmp	1f		# We're paging, in compatiblility mode.

1:	lgdt	(gdtr)
	movw	$0x10, %ax
	movw	%ax, %ds
	movw	%ax, %es
	movw	%ax, %fs
	movw	%ax, %gs
	movw	%ax, %ss
	ljmp	$0x18, $64f

	.code64
64:	cmpl	$0x464C457F, (kernel)	# 45=E 4C=L 46=F: the ELF signature in little-endian order.
	jnz	halt

	movzwq	(kernel+54), %r8		# e_phentsize
	movw	(kernel+56), %r9w	# e_phnum
	xorq	%r10, %r10
	movq	$kernel, %rax
	addq	(kernel+32), %rax	# e_phoff

	# rax -> first Phdr
phdr:	cmpl	$1, (%rax)	# p_type == PT_LOAD?
	jnz	2f
	movq	$kernel, %rsi
	addq	8(%rax), %rsi	# p_offset: rsi = addr to read from
	movq	16(%rax), %rdi	# p_vaddr:  rdi = addr to write to
	subl	$0xBFC06000, %edi  # Load relative to 0x400000 instead of 0xC0006000
	movq	32(%rax), %rcx	# p_filesz
	rep
	movsb
	movq	%rcx, %rbx
	movq	40(%rax), %rcx	# p_memsz
	subq	%rcx, %rbx	# subtract p_filesz = BSS size
	jz	1f
	
	pushq	%rax
	movb	$0, %al
	rep
	stosb
	popq	%rax

1:	movq	40(%rax), %rbx	# p_memsz
	addq	16(%rax), %rbx	# p_vaddr
	subl	$0xC0006000, %ebx
	cmpq	%rbx, %r10
	jl	2f
	movq	%rbx, %r10	# store highest offset in r10
2:	addq	%r8, %rax
	decw	%r9w
	jnz	phdr

	movq	(kernel+24), %r11 # entry point

	# Launch kernel
	movl	(magic), %r8d
	movl	(mbptr), %r9d
	
	movq	%r8, %rdi	# First arg
	movq	%r9, %rsi	# Second arg
	movq	%r10, %rdx	# Third arg
	call	*%r11

halt:	cli
	hlt
1:	jmp	1b

	# DATA

gdt:	.byte	0,    0,    0, 0, 0, 0,    0,    0	# null
	.byte	0xFF, 0xFF, 0, 0, 0, 0x9B, 0xDF, 0	# code32
	.byte	0xFF, 0xFF, 0, 0, 0, 0x93, 0xDF, 0	# data
	.byte	0xFF, 0xFF, 0, 0, 0, 0x9B, 0xAF, 0	# code64

gdtr:	.word	0x20
	.long	gdt

##1:	.space	0x6000-1b
1:      .space  0x5FFF
kernel: