;=----------------------------------------------------------------------------=; ; GNU GPL OS/K ; ; ; ; Authors: spectral` ; ; NeoX ; ; ; ; Desc: Kernel (second stage) Loader for OS/K ; ; (x86_64 architecture only) ; ;=----------------------------------------------------------------------------=; ;;VIDEO %define TRAM 0x0B8000 ; [T]ext[RAM] %define VRAM 0x0A0000 ; [V]ideo[RAM] ;; BPB %define OEMName bp+0x03 ; Disk label %define bytesPerSector bp+0x0b ; Bytes per sector %define sectorsPerCluster bp+0x0d ; Sectors per cluster %define reservedSectors bp+0x0e ; Reserved sectors %define fats bp+0x10 ; Number of fats %define rootDirEntries bp+0x11 ; Number of entries in root dir %define sectors bp+0x13 ; Logical sectors %define mediaType bp+0x15 ; Media descriptor byte %define fatSectors bp+0x16 ; Sectors per FAT %define sectorsPerTrack bp+0x18 ; Sectors per track %define heads bp+0x1a ; Number of sides/heads %define hiddenSectors bp+0x1c ; Hidden sectors %define hugeSectors bp+0x20 ; LBA sectors %define biosBootdrvNum bp+0x24 ; Bootdrv number %define reserved bp+0x25 ; This is not used %define bootSignature bp+0x26 ; Bootdrv signature %define volumeId bp+0x27 ; Volume ID %define volumeLabel bp+0x2b ; Volume Label %define fatTypeLabel bp+0x36 ; File system type [BITS 16] [ORG 0x1000] mov ax, cs ; correcting cs after the horrible far jump mov ds, ax ; hm... And ds too mov es, ax ; And es because it is jealous mov [Bootdrv], dl xor dl, dl jmp 0x0000:main ;; 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 0x0000FFFF ; Segment Limit db 0x0, 0x0, 0x0 ; Base Address 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 DATA_SELECTOR: ;; flat data selector (ring 0) dw 0x0000FFFF ; Segment Limit db 0x0, 0x0, 0x0 ; Base Address 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 LONG_SELECTOR: ;; 64-bit code selector (ring 0) dw 0x0000FFFF ; Segment Limit db 0x0, 0x0, 0x0 ; Base Address 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 GDT_LENGTH: %include "boot/loader16.inc" main: ;; compatibility check push si mov si, Init call PrintB pop si call Is64bits jc ErrorNo64 push si mov si, Pass call PrintB pop si ;; Enabling A20 push si mov si, EnA20 call PrintB pop si in al, 0x92 or al, 2 out 0x92, al push si mov si, Pass call PrintB pop si ;; 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 ErrorNo64: mov si, NoLongMode call PrintB Die: cli hlt ; die nooooow jmp 0xF000:0xFFF0 [BITS 32] main32: pop dword [VGA_HEIGHT32] pop dword [VIDEO_MODE32] ;; VERIFY A20 pushad mov edi,0x112345 ;odd megabyte address. mov esi,0x012345 ;even megabyte address. mov [esi],esi ;making sure that both addresses contain diffrent values. mov [edi],edi ;(if A20 line is cleared the two pointers would point to the address 0x012345 that would contain 0x112345 (edi)) cmpsd ;compare addresses to see if the're equivalent. popad jne .A20_on ;if not equivalent , A20 line is set. mov WORD [A20_OK], 0 jmp .A20_end .A20_on: mov BYTE [A20_OK], 1 .A20_end: ;; 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] %include "boot/loader64.inc" ;; DATA Init db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0x09, " Checking CPUID...",0 CPUIDD db 0x09, " Checking CPUID...", 0 EnA20 db 0x09, " Enabling A20 line...", 0 ReadAttempt db 0x09, " Attempt to read a sector with ATA commands...", 0x0A, 0x0D, 0x0A, 0x0D,0 txt db 0x09, " Switching to Long Mode... ", 0 Reinit db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0 Pass db " OK", 0x0A, 0x0D, 0 Fail db " FAIL!", 0x0A, 0x0D, 0 msg db "The system is now in x64 mode. Is this not beautiful ?", 0x0A, 0x0D, 0 NoLongMode db 0x0A, 0x0D, "ERROR : Your computer is not designed for x64 OS", 0 FileNotFound db "Second Stage Error : The Kernel was not found.", 0x0A, 0x0D, 0 DiskError db "Second Stage Error : The Disk has crashed.", 0x0A, 0x0D, 0 filename db "KERNEL BIN" Bootdrv db 0 UserData dw 0 VGA_HEIGHT dq 0 VIDEO_MODE dw 0 VIDEO_MODE32 dw 0 VGA_HEIGHT32 dw 0 NextTRAM dq 0x0B8000 ; Last position of cursor VIDEO_MODE64 dq 0 VGA_HEIGHT64 dq 0 VGA_X dq 0 A20_OK db 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 cmp BYTE [A20_OK], 1 je .A20Success mov bl, 0x0C mov esi, Fail call write jmp Die .A20Success: mov bl, 0x0A mov esi, Pass call write mov bl, 0x0F mov esi, txt call write mov bl, 0x0A mov esi, Pass call write mov bl, 0x0D mov esi, msg call write mov bl, 0x0F mov esi, ReadAttempt call write mov rcx, 2 .looping: nop nop nop loop .looping ; Temporized because the ATA drive must be ready call ata_read jmp Die ; times 1024 nop ; XXX ; ; It seems impossible to have an executable > 2.0 kB...