;=----------------------------------------------------------------------------=; ; GNU GPL OS/K ; ; ; ; Authors: spectral` ; ; NeoX ; ; ; ; Desc: Kernel (second stage) Loader for OS/K ; ; (x86_64 architecture only) ; ;=----------------------------------------------------------------------------=; %define TRAM 0x0B8000 ; [T]ext[RAM] %define VRAM 0x0A0000 ; [V]ideo[RAM] [BITS 16] [ORG 0x1000] mov ax, cs mov ds, ax mov es, ax mov [Bootdrv], dl jmp 0x0000:main ;; DATA Bootdrv db 0 VGA_HEIGHT dq 0 VIDEO_MODE dw 0 ;; GDT WITH DOC GDT64: NULL_SELECTOR: ;; null selector within 64 bits dw GDT_LENGTH ; limit of GDT dw GDT64 ; linear address of GDT dd 0x0 CODE_SELECTOR: ;; 32-bit code selector (ring 0) dw 0x0FFFF ; Segment Limit 15:00 db 0x0, 0x0, 0x0 ; Base Address 23:00 db 10011010b ; |7|6|5|4|3|2|1|0| ; | | | | | | | `----- 1 when segment used. ; | | | | | | `------ 1 when writable. ; | | | | | `------- 1 if "conformant". Don't know what is it... spectral ? xD ; | | | | `-------- 1 always ; | | | `--------- 1 for segment descriptor, 0 for system descriptor ; | | `---------- DPL !!! 0 for ring 0 ; | `----------- DPL (2/2) ; `------------ 1 if in physical memory, 0 if page fault db 11001111b ; |7|6|5|4|3|2|1|0| ; | | | | | | | `----- Limit 16 ; | | | | | | `------ Limit 17 ; | | | | | `------- Limit 18 ; | | | | `-------- Limit 19 ; | | | `--------- available for use ; | | `---------- 0 always ; | `----------- size of data. 1 for 32bits ; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko) db 0x0 ; Base Address 31:24 DATA_SELECTOR: ;; flat data selector (ring 0) dw 0x0FFFF ; Segment Limit 15:00 db 0x0, 0x0, 0x0 ; Base Address 23:00 db 10010010b ; |7|6|5|4|3|2|1|0| ; | | | | | | | `----- 1 when segment used. ; | | | | | | `------ 1 when writable. ; | | | | | `------- expansion direction. 1 for a LIFO ; | | | | `-------- 1 always ; | | | `--------- 1 for segment descriptor, 0 for system descriptor ; | | `---------- DPL !!! 0 for ring 0 ; | `----------- DPL (2/2) ; `------------ 1 if in physical memory, 0 if page fault db 10001111b ; |7|6|5|4|3|2|1|0| ; | | | | | | | `----- Limit 16 ; | | | | | | `------ Limit 17 ; | | | | | `------- Limit 18 ; | | | | `-------- Limit 19 ; | | | `--------- available for use ; | | `---------- 0 always ; | `----------- size of data. 1 for 32bits ; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko) db 0x0 ; Base Address 31:24 LONG_SELECTOR: ;; 64-bit code selector (ring 0) dw 0x0FFFF ; Segment Limit 15:00 db 0x0, 0x0, 0x0 ; Base Address 23:00 db 10011010b ; |7|6|5|4|3|2|1|0| ; | | | | | | | `----- 1 when segment used. ; | | | | | | `------ 1 when writable. ; | | | | | `------- 1 if "conformant". Don't know what is it... spectral ? xD ; | | | | `-------- 1 always ; | | | `--------- 1 for segment descriptor, 0 for system descriptor ; | | `---------- DPL !!! 0 for ring 0 ; | `----------- DPL (2/2) ; `------------ 1 if in physical memory, 0 if page fault db 10101111b ; |7|6|5|4|3|2|1|0| ; | | | | | | | `----- Limit 16 ; | | | | | | `------ Limit 17 ; | | | | | `------- Limit 18 ; | | | | `-------- Limit 19 ; | | | `--------- available for use ; | | `---------- 0 always ; | `----------- size of data. 1 for 32bits ; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko) db 0x0 ; Base Address 31:24 GDT_LENGTH: disable_cursor: pushf push eax push edx mov dx, 0x3D4 mov al, 0xA ; low cursor shape register out dx, al inc dx mov al, 0x20 ; bits 6-7 unused, bit 5 disables the cursor, bits 0-4 control the cursor shape out dx, al pop edx pop eax popf ret get_dimensions: push eax push ebx mov ah, 0x0F int 0x10 mov [VGA_HEIGHT], ah mov [VIDEO_MODE], al pop ebx pop eax ret ;-----------------------------------------------------------------------; ; Checks if the CPU is compatible with 64-bits operating systems ; ; If the 21th bit of the eax register is set, then CPUID is supported ; ; We then test CPUID's result to see if long mode is supported ; ;-----------------------------------------------------------------------; Is64bits: pushfd ; recovering the flags in eax pop eax mov ecx, eax xor eax, 0x200000 push eax popfd pushfd pop eax xor eax, ecx shr eax, 21 and eax, 1 ; magical spell of murta push ecx popfd test eax, eax jz .NonCompat ; if (CPUID non supporté) goto NonCompat mov eax, 0x80000000 cpuid cmp eax, 0x80000001 jb .NonCompat ; if (eax <= 0x80000001) goto NonCompat mov eax, 0x80000001 cpuid test edx, 1 << 29 jz .NonCompat ; if (edx != 1 << 29) goto NonCompat ret ; back to mbr.s .NonCompat: stc ret PrintB: ;---------------------------------------------------; ; Print out a simple string. ; ; ; ; Expects: DS:SI = String to print ; ; ; ; Returns: None ; ; ; ;---------------------------------------------------; lodsb ; Load byte from ds:si to al or al, al ; If al is empty stop looping jz .done ; Done looping and return mov ah, 0x0e ; Teletype output int 0x10 ; Video interupt jmp PrintB ; Loop untill string is null .done: ret main: ;; compatibility check mov si, Init call PrintB pop si call Is64bits jc ErrorNo64 push si mov si, Pass call PrintB ;; Enabling A20 mov si, EnA20 call PrintB pop si in al, 0x92 or al, 2 out 0x92, al push si mov si, Pass call PrintB ;; DISABLING CURSOR BLINKING AND GETTING INFOS call get_dimensions call disable_cursor ;;GO GDT64 cli ; disable interrupts lgdt [GDT64] ;; ACTIVATE PROTECTED MODE mov eax, cr0 or al, 1b ; PE = 1 mov cr0, eax ;; DISABLE PAGING mov eax, cr0 and eax, 0x7FFFFFFF ; PG = 0 ; |0|111111111111111111111111111111 ; | ; `------ Paging bit mov cr0, eax push dword [VIDEO_MODE] push dword [VGA_HEIGHT] jmp (CODE_SELECTOR-GDT64):main32 [BITS 32] VIDEO_MODE32 dw 0 VGA_HEIGHT32 dw 0 main32: pop dword [VGA_HEIGHT32] pop dword [VIDEO_MODE32] ;; INITIALIZE PROTECTED MODE SEGMENT REGISTERS mov ax, DATA_SELECTOR-GDT64 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax ;; ACTIVATE PHYSICAL ADRESS EXTENSION mov eax, cr4 or eax, 100000b ; PAE = 1 = 4 Mo / page. 0 = 4 Ko mov cr4, eax ;;cleanup mov edi, 0x70000 mov ecx, 0x10000 xor eax, eax rep stosd ;;formatting mov dword [0x70000], 0x71000 + 7 ; first PDP table mov dword [0x71000], 0x72000 + 7 ; first page directory mov dword [0x72000], 0x73000 + 7 ; first page table mov edi, 0x73000 ; address of first page table mov eax, 7 mov ecx, 256 ; number of pages to map (1 MB) .make_page_entries: stosd add edi, 4 add eax, 0x1000 loop .make_page_entries ;; pointing pml4 mov eax, 0x70000 ; Bass address of PML4 mov cr3, eax ; load page-map level-4 base ;; ACTIVATE LONG MODE mov ecx, 0xC0000080 ; address of MSR rdmsr ; read MSR or eax, 100000000b ; LME = 1. (Long Mode Enable) wrmsr ; write MSR ;; ACTIVATE PAGING mov eax, cr0 or eax, 0x80000000 ; make bit 31 (PG = Paging) to 1 : ; |1|000000000000000000000000000000 ; | ; `------ Paging bit mov cr0, eax push dword 0 push dword [VIDEO_MODE] push dword 0 push dword [VGA_HEIGHT] jmp (LONG_SELECTOR-GDT64):main64 [BITS 64] ;; FUNCTIONS clear: ;-----------------------------------------------------------------------; ; x64/LM Clear Text Screen Function ; ;-----------------------------------------------------------------------; mov qword [NextTRAM], TRAM mov edi, TRAM push rsi push rdi push rcx mov ah, 0 mov al, 0 mov rcx, 0x4000 ; traditionnal value rep stosw ; fill screen with al while cx > 0 pop rcx pop rsi pop rdi ret write: ;-----------------------------------------------------------------------; ; x64/LM Text Printing Functions ; ; bl : color code ; ; esi : string address ; ;-----------------------------------------------------------------------; mov edi, [NextTRAM] ;TRAM ADDRESS push rsi push rdi .pLoop: lodsb cmp al, 0 ; while @al, i.e. while we're not hitting '\0' je .pEnd cmp al, 0x0A ; LF je .lf cmp al, 0x0D ; CR je .cr stosb ; text subpixel mov al, bl stosb ; color subpixel add qword [NextTRAM], 0x2 ; Cursor moving add qword [VGA_X], 0x2 ; coord + 2 because 2 subpixels jmp .pLoop .pEnd: pop rdi pop rsi ret .lf: mov rax, [VGA_HEIGHT64] add [NextTRAM], rax ; Cursor moving add [NextTRAM], rax add edi, eax ; Address moving add edi, eax jmp .pLoop .cr: push rax mov rax, qword [VGA_X] sub qword [NextTRAM], rax ; pos = X + Y * VGA_HEIGHT64. Donc pos - X = début de ligne sub edi, edx mov qword [VGA_X], 0 pop rax jmp .pLoop .scroll: jmp .pLoop ;; DATA txt db 0x09, " Switching to Long Mode... OK", 0x0A, 0x0D, 0 Init db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0x09, " Checking CPUID...",0 Reinit db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0 CPUIDD db 0x09, " Checking CPUID...", 0 EnA20 db 0x09, " Enabling A20 line...", 0 NoLongMode db 0x0A, 0x0D, "ERROR : Your computer is not designed for x64 OS", 0 Pass db " OK", 0x0A, 0x0D, 0 NextTRAM dq 0x0B8000 ; Last position of cursor VIDEO_MODE64 dq 0 VGA_HEIGHT64 dq 0 VGA_X dq 0x0 msg db "The system is now in x64 mode. Is this not beautiful ?", 0x0A, 0x0D, 0 main64: pop qword [VGA_HEIGHT64] pop qword [VIDEO_MODE64] ;; INITIALIZE STACK mov rsp, 0x9F000 call clear ;; Printing mov bl, 0x0B mov esi, Reinit call write mov bl, 0x0F mov esi, CPUIDD call write mov bl, 0x0A mov esi, Pass call write mov bl, 0x0F mov esi, EnA20 call write mov bl, 0x0A mov esi, Pass call write mov bl, 0x0A mov esi, txt call write mov bl, 0x0D mov esi, msg call write jmp Die [BITS 16] ErrorNo64: mov si, NoLongMode call PrintB Die: cli hlt ; die nooooow retf ; For conveniance '-' KERNEL: