os

Toy OS
git clone git://git.margiolis.net/os.git
Log | Files | Refs | README | LICENSE

lm.asm (2657B)


      1 ; call in pm_mode
      2 	call	lm_check
      3 
      4 ; Check for Long Mode.
      5 lm_check:
      6 	pusha
      7 	pushfd			; Push EFLAGS register to the stack.
      8 	pop	eax		; Pop EFLAGS registers to `eax`.
      9 	mov	ecx, eax	; Keep a backup in `ecx`.
     10 	xor	eax, 1 << 21	; Flip the 21st bit if the it's not 1.
     11 	push	eax
     12 	popfd			; Pop `eax` to EFLAGS.
     13 
     14 	pushfd
     15 	pop	eax		; Copy EFLAGS back to `eax`.
     16 	push	ecx
     17 	popfd			; Restore the flipped version.
     18 	xor	eax, ecx
     19 	jz	lm_fail		; If EFLAGS' value hasn't changed, we have CPUID.
     20 
     21 	mov	eax, 0x80000000	; CPUID argument.
     22 	cpuid			; CPU identification. `eax` is now populated with info.
     23 	cmp	eax, 0x80000001	; If it's less than 0x80000000 we cannot have Long Mode.
     24 	jb	lm_fail
     25 
     26 	mov	eax, 0x80000001	; Get extended processor information.
     27 	cpuid
     28 	test	edx, 1 << 29
     29 	jz	lm_fail		; If the 29th bit is 0, we cannot have Long Mode.
     30 
     31 	popa
     32 	ret
     33 
     34 ; No long mode.
     35 lm_fail:
     36 	popa
     37 	call	kernel_exec
     38 	jmp	$		; Safety hang.
     39 
     40 ; We'll check for (and switch to) Long Mode here.
     41 lm_enter:
     42 	cli
     43 	mov	eax, cr0
     44 	or	eax, 1 << 31	; Paging Enable.
     45 	mov	cr0, eax
     46 ; Set up PAE paging.
     47 	mov	edi, 0x1000	; Page table starts 4KiB in memory.
     48 	mov	cr3, edi	; Hold the location of the highest page table.
     49 	xor	eax, eax	; Clear memory space.
     50 	mov	ecx, 4096
     51 	rep	stosd		; Write 4096 dwords with the value 0.	
     52 	mov	edi, 0x1000	; Go to the initial location.
     53 
     54 ; Page table locations:
     55 ;	Page Map Level 4 Table (PML4T):		0x1000
     56 ;	Page Directory Pointer Table (PDPT):	0x2000
     57 ;	Page Directory Table (PDT):		0x3000
     58 ;	Page Table (PT);			0x4000
     59 ;
     60 ; In order for each table to point to each other we'll use a size directive.
     61 ; Since tables are 4KiB away from each other we'll move dwords.
     62 	mov	dword [edi], 0x2003	; PML4T -> PDPT
     63 	add	edi, 0x1000		; Move 4KiB forward.
     64 	mov	dword [edi], 0x3003	; PDPT -> PDT
     65 	add	edi, 0x1000
     66 	mov	dword [edi], 0x4003	; PDT -> PT
     67 	add	edi, 0x1000
     68 
     69 	mov	dword ebx, 3	; Map beginning of code.
     70 	mov	ecx, 512	; Do it 512 times.
     71 setentry:
     72 	mov	dword [edi], ebx
     73 	add	ebx, 0x1000
     74 	add	edi, 8		; Go to the next entry in the page table.
     75 	loop	setentry
     76 
     77 ; Enable the 6th bit in CR4 (Physical Address Extension Bit) to tell
     78 ; the CPU that we're using PAE paging.
     79 	mov	eax, cr4
     80 	or	eax, 1 << 5
     81 	mov	cr4, eax
     82 
     83 ; Activate Long Mode and Paging using the EFER.
     84 	mov	ecx, 0xc0000080
     85 	rdmsr			; Copy the contents of EFER to `eax`. 
     86 	or	eax, 1 << 8	; Set LME bit to enable Long Mode.
     87 	wrmsr			; Write `eax` back to EFER.	
     88 	
     89 	lgdt	[gdt_ptr]		; Load the GDT.
     90 	jmp	GDT_CODESEG:lm_init	; Switch to Long Mode.
     91 
     92 ; We're in Long Mode now.
     93 [bits 64]
     94 lm_init:
     95 	mov	ax, GDT_DATASEG
     96 	mov	ds, ax
     97 	mov	ss, ax
     98 	mov	es, ax
     99 	mov	fs, ax
    100 	mov	gs, ax
    101 
    102 	mov	rbp, 0x90000
    103 	mov	rsp, rbp
    104 	call	kernel_exec
    105 	jmp	$	
    106