From 04085ee0dae312f417e59696edcae758c3036177 Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Wed, 16 Jan 2019 09:10:19 +0100 Subject: [PATCH 1/4] Correcting gitignore --- .gitignore | 5 +++-- build/obj/boot/loader.bin | Bin 1944 -> 1944 bytes 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 285c341..7840e6a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,12 +11,11 @@ test-*.c *.elf *.S + # Linker output *.ilk *.map *.exp -*.bin -*.img # Precompiled Headers *.gch @@ -41,6 +40,8 @@ test-*.c *.i*86 *.x86_64 *.hex +*.bin +*.img # Debug files *.dSYM/ diff --git a/build/obj/boot/loader.bin b/build/obj/boot/loader.bin index 096e80a677dc1a99d6ef20f8c99f89342a5542a8..90de8d805d7a30da4c8674924be9dfc30f6a568e 100644 GIT binary patch delta 14 WcmbQiKZAe61tvz3%@>)Dvj6}n00lPy delta 14 WcmbQiKZAe61tvy?%@>)Dvj6}nNCiUx From 874b2c9e4fc2cfd1fc8ad481aa1168cbf12e959f Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Wed, 16 Jan 2019 09:33:01 +0100 Subject: [PATCH 2/4] Bug correcting stuff ;) --- boot/loader64.inc | 2 +- build/bin/disk.img | Bin 18944000 -> 18944000 bytes build/obj/boot/loader.bin | Bin 1944 -> 1944 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/loader64.inc b/boot/loader64.inc index 6042ddf..d3a51fa 100644 --- a/boot/loader64.inc +++ b/boot/loader64.inc @@ -170,7 +170,7 @@ ata_read: out dx, al mov dx, 0x1f7 ;Command port - mov al, 20 ;Read with retry. + mov al, 0x20 ;Read with retry. out dx, al still_going: in al, dx diff --git a/build/bin/disk.img b/build/bin/disk.img index 087b3f3ae05ffe22a18c93b8211107f2d59cde34..e4692fd669b29f0ed863445b3ba1b42e58f12953 100644 GIT binary patch delta 1529 zcmY+A37A!57{|}K&6qniHI16?vH|smIgfoagtw|L_04-}{~Oj-PsU@%X@#9ny8Xr{@o@>6qH4 zI^AKdp3!sDsARuhgL(~$qI8Hw(UhVnS~5E784U^VZc%A;>%f}9Gy1mwuPTW}b$8Af zJ)l0_7_TU*ZcWF})D*W4D6G%i-;k*t+p*1v&AOH6zRy?X?#iDtaA28sioDyt@*fh%L5xSBlErMGt0Y{rK2pF+%5T)zbuPUhcJP|FQ4zHS9IkBMP!?3H2lk&AOZi<^) zUN|I4C&iUL)}(uUl=MxUZ}V^vEHzqEr+;I`g_kGm|_1e_8XlM-Q*R zZ%%w+Ds}F#+A+i8PPL0m;(qnR9*f7ubN#z> z;_V6(Lt;ru8!3=NSx1T__{Gvz+DVDDmkv@Y9i>dxl}^%G$|WP~3DQNnN;g?wHjoWv zBiUFskxiw$Y$g@5xoja@N)Opeww7(Ar)(?RNiW%6c90!qC)rtg%Pz93>?XU*9@0nl zl)a>{>@EFdAK6#-lm4>543J7WKn|3H*(aI zC4zvxl3zP)f2RZ~w104fp mfpr6&0-XcpflOe%K+?ZUplhI8VEw=bfeiy2#gDUbyy9PsNHF~X delta 2390 zcmeH``+t^m7{~AX+15_2wY5FHE9)SmC`m*_Qq!|gTUb%n0qdkvB7_n?ltbDu=R-~v z5~B!DRy603lyeU0*>V_#tax1CXUp>95AcH@KHuy5UZ?wY-`D+~ecx5dvrWsIC6(X3 zBhY2Vg5Gg!2bU%_+xxbt>%M1C9^P$Gw?Upa-fWI{TcYP}ndEi#26~0wFfZM^rC-_L zMSartR5_bdap$5*1N^+QY16&R^t|~A zL+l*2Dz9UP7tZVGdvklv?eoa!3sOs}5-zli=WR<|8}t0~sbBhYS`}Duf)_nJWVU98 z9eAOt_}rpkd1ZB=L%{4IJp!%ri!2ieT^XM{**V)j9$CC5bX|OIiQPiJD{r)Zm0z`O zWr0h(;!x-Mbmxt3?&R``t^K|km6;_gYyIsdlPXe5!j+kk{wp>g@4px~%gvh~pIdC^ z1+O;QixlpPMk`XogR(s@GT!;=;jLNbpXvM*`%>n|YSQg%nV)Cz*}Ze!tNPP3Dw>AJ zx{7WVt?pIV*wVIsRCkxmY#fypY2q$v;qzRg&Kj!Y>&h4G2y8E{P5OUn|IMZGkEKP% zxqU~=yU*~~l{F8vcgs5=MqGYyVPOMttM?{uOapPd|3=)H7;%M;xcmm3ZU(#E8pW-MGB)>P-8)`!yiv1{!iB&D0}T;1Ea+4|WK+4{69n99kospAsJ9 z;<1|a@NO6HZ*fB|_J%R!#<_}vEn0nKJ#w*@ocd9Rx@1P5Eyr(}m>3!EqCf44wunXdx4z3<-xuyd4gQ9`{MXE{UhkUL2wwz5oQM|*qKQZp zNg`RKh*Z&3q={xCT{IUNB2%;wSt45mMN5HbC0dI%Vjqzs+KP6fz33qJ6&=NXB3JA$ z4iKG0XK|o7NOTch#lfPRI7D<8hl(EJFmbr(DUJ|FieBOkjNJU#fjo1ak3aB28#kwD29kr#Hr#mQ6z?nVd8Xgh8QkJh%-g87%4`H z(PE4^OPnpv5hY@*7$?Sy31Xr+S4w67i^bOgt`@iYLS}@uYZ4REVd=Gh(?| zA)Xb_iIw7c@q&0!gvBcHlBg7`#TxOlctxxgRpM3gns{BjA>I^kiMPc%@s4;`yeHO+ z_r(VBf!HWEi4Vm`;$!iN_*8r*J{OzC7vf9tmH1k05#NZdA|k3qjo2o>72k>P#SfxZ z{3w1B+r`} ulxAvXN;fq(WtcKeElgRaY*WzG(&Xm1GPO3fG3{f@F|{?d^Ow@z-}xsh0ETt| diff --git a/build/obj/boot/loader.bin b/build/obj/boot/loader.bin index 90de8d805d7a30da4c8674924be9dfc30f6a568e..096e80a677dc1a99d6ef20f8c99f89342a5542a8 100644 GIT binary patch delta 14 WcmbQiKZAe61tvy?%@>)Dvj6}nNCiUx delta 14 WcmbQiKZAe61tvz3%@>)Dvj6}n00lPy From f40ad6526386b5a4c1239860dc0c800e41fb65b2 Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Wed, 16 Jan 2019 11:01:18 +0100 Subject: [PATCH 3/4] Big reorganization stuff '-' --- Makefile | 11 +- boot/elf/elf.c | 10 -- boot/loader.asm | 357 -------------------------------------- boot/loader16.inc | 89 ---------- boot/loader64.inc | 200 --------------------- boot/mbr.asm | 175 ------------------- boot/mbr.inc | 161 ----------------- build/bin/disk.img | Bin 18944000 -> 18944000 bytes build/bin/loader.bin | Bin 1944 -> 1966 bytes build/obj/boot/loader.bin | Bin 1944 -> 1966 bytes 10 files changed, 6 insertions(+), 997 deletions(-) delete mode 100644 boot/elf/elf.c delete mode 100644 boot/loader.asm delete mode 100644 boot/loader16.inc delete mode 100644 boot/loader64.inc delete mode 100644 boot/mbr.asm delete mode 100644 boot/mbr.inc diff --git a/Makefile b/Makefile index e990b7d..6458c3c 100644 --- a/Makefile +++ b/Makefile @@ -29,15 +29,16 @@ ASM=nasm ASMFLAGS= BOOTFLAGS=-f bin -BOOTDIR=boot +MBRDIR=boot/mbr +LOADERDIR=boot/loader OBJDIR=build/obj BINDIR=build/bin -boot.mbr.asm: $(BOOTDIR)/mbr.asm $(BOOTDIR)/mbr.inc - $(ASM) $(BOOTFLAGS) $(BOOTDIR)/mbr.asm -o $(OBJDIR)/boot/mbr.bin +boot.mbr.asm: $(MBRDIR)/mbr.asm $(MBRDIR)/mbr.inc + $(ASM) $(BOOTFLAGS) $(MBRDIR)/mbr.asm -o $(OBJDIR)/boot/mbr.bin -boot.loader.asm: $(BOOTDIR)/loader.asm - $(ASM) $(BOOTFLAGS) $(BOOTDIR)/loader.asm -o $(OBJDIR)/boot/loader.bin +boot.loader.asm: $(LOADERDIR)/loader.asm + $(ASM) $(BOOTFLAGS) $(LOADERDIR)/loader.asm -o $(OBJDIR)/boot/loader.bin bootloader: boot.mbr.asm boot.loader.asm cp $(OBJDIR)/boot/mbr.bin $(BINDIR)/mbr.bin diff --git a/boot/elf/elf.c b/boot/elf/elf.c deleted file mode 100644 index 1781d7b..0000000 --- a/boot/elf/elf.c +++ /dev/null @@ -1,10 +0,0 @@ -//----------------------------------------------------------------------------// -// GNU GPL OS/K // -// // -// Authors: spectral` // -// NeoX // -// // -// Desc: ELF64 Parser and Loader // -//----------------------------------------------------------------------------// - -//STUB diff --git a/boot/loader.asm b/boot/loader.asm deleted file mode 100644 index 43f5fe8..0000000 --- a/boot/loader.asm +++ /dev/null @@ -1,357 +0,0 @@ -;=----------------------------------------------------------------------------=; -; 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... diff --git a/boot/loader16.inc b/boot/loader16.inc deleted file mode 100644 index a30cff9..0000000 --- a/boot/loader16.inc +++ /dev/null @@ -1,89 +0,0 @@ -;=----------------------------------------------------------------------------=; -; GNU GPL OS/K ; -; ; -; Authors: spectral` ; -; NeoX ; -; ; -; Desc: Kernel (second stage) Loader for OS/K INCLUDED FUNCTIONS ; -; (x86_64 architecture only) ; -;=----------------------------------------------------------------------------=; - -[BITS 16] - -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 - -Is64bits: -;-----------------------------------------------------------------------; -; 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 ; -;-----------------------------------------------------------------------; - 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 diff --git a/boot/loader64.inc b/boot/loader64.inc deleted file mode 100644 index d3a51fa..0000000 --- a/boot/loader64.inc +++ /dev/null @@ -1,200 +0,0 @@ -;=----------------------------------------------------------------------------=; -; GNU GPL OS/K ; -; ; -; Authors: spectral` ; -; NeoX ; -; ; -; Desc: Kernel (second stage) Loader for OS/K INCLUDED FUNCTIONS ; -; (x86_64 architecture only) ; -;=----------------------------------------------------------------------------=; - -[BITS 64] - -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: - ; XXX I don't think I'll implement this, but never know...; - jmp .pLoop - -dump: -;-----------------------------------------------------------------------; -; x64/LM Dump Printing Functions ; -; bl : color code ; -; esi : string address ; -;-----------------------------------------------------------------------; - mov edi, [NextTRAM] ; TRAM ADDRESS - push rsi - push rdi - push rcx - mov rcx, 512 -.pLoop: - lodsb - 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 - loop .pLoop - pop rcx - pop rdi - pop rsi - ret - -ata_read: -;-----------------------------------------------------------------------; -; x64/LM ATA Reading function ; -; ; -; ; -;-----------------------------------------------------------------------; - -; Technical infos about the ports (Intel Doc): -; -; Port Access Mode Misc -; -; 1f0 r/w Data register, the bytes of the disk itself -; 1f1 r Error register that can be handled -; 1f2 r/w Sector count, how many sectors to read -; 1f3 r/w Sector number, the actual sector wanted -; 1f4 r/w Cylinder low, cylinders is 0-1024 -; 1f5 r/w Cylinder high, this makes up the rest of the 1024 -; 1f6 r/w Drive/head -; bit 7 = 1 -; bit 6 = 0 -; bit 5 = 1 -; bit 4 = 0 drive 0 select -; = 1 drive 1 select -; bit 3-0 head select bits -; 1f7 r Status register -; bit 7 = 1 controller is executing a command -; bit 6 = 1 drive is ready -; bit 5 = 1 write fault -; bit 4 = 1 seek complete -; bit 3 = 1 sector buffer requires servicing -; bit 2 = 1 disk data read corrected -; bit 1 = 1 index - set to 1 each revolution -; bit 0 = 1 previous command ended in an error -; 1f7 w Command register -; commands: -; 50h format track -; 20h read sectors with retry -; 21h read sectors without retry -; 22h read long with retry -; 23h read long without retry -; 30h write sectors with retry -; 31h write sectors without retry -; 32h write long with retry -; 33h write long without retry -; - - push rax - push rbx - push rdx - push rcx - push rdi - mov dx, 0x1f6 ;Drive and head port - mov al, 0x0a0 ;Drive 0, head 0 - out dx,al - - mov dx, 0x1f2 ;Sector count port - mov al, 1 ;Read one sector - out dx, al - - mov dx, 0x1f3 ;Sector number port - mov al, 1 ;Read sector one - out dx, al - - mov dx, 0x1f4 ;Cylinder low port - mov al, 0 ;Cylinder 0 - out dx, al - - mov dx, 0x1f5 ;Cylinder high port - mov al, 0 ;The rest of the cylinder 0 - out dx, al - - mov dx, 0x1f7 ;Command port - mov al, 0x20 ;Read with retry. - out dx, al -still_going: - in al, dx - test al, 8 ;This means the sector buffer requires - ;servicing. - jz still_going ;Don't continue until the sector buffer - ;is ready. - - mov cx, 512/2 ;One sector /2 - mov rdi, buffer - mov dx, 0x1f0 ;Data port - data comes in and out of here. - rep insw - pop rdi - pop rcx - pop rdx - pop rbx - pop rax - mov bl, 0x0F - mov esi, buffer - call dump - mov bl, 0x0A - mov esi, end - call write - ret - - buffer: times 512 db "_" - end: db "[End of Sector]", 0x0 diff --git a/boot/mbr.asm b/boot/mbr.asm deleted file mode 100644 index f7a3066..0000000 --- a/boot/mbr.asm +++ /dev/null @@ -1,175 +0,0 @@ -;=----------------------------------------------------------------------------=; -; GNU GPL OS/K ; -; ; -; Authors: spectral` ; -; NeoX ; -; ; -; Desc: Bootsector for OS/K ; -; (x86_64 architecture only) ; -;=----------------------------------------------------------------------------=; - -;; BOOT "SEGMENT" -%define BOOT_SEG 0x07c0 ; (BOOT_SEG << 4) + BOOT_OFF = 0x007c00 -%define BOOT_OFF 0x0000 - -;; STACK "SEGMENT" -%define STACK_SEG 0x0600 ; (STACK_SEG << 4) + STACK_OFF = 0x007000 -%define STACK_OFF 0x1000 - -;; DISK BUFFER "SEGMENT" -%define BUFFER_SEG 0x2000 ; (BUFFER_SEG << 4) + BUFFER_OFF = 0x020000 -%define BUFFER_OFF 0x0000 - -;; SECOND STAGE LOADER "SEGMENT" -%define LOAD_SEG 0x0000 ; (LOAD_SEG << 4) + LOAD_OFF = 0x001000 -%define LOAD_OFF 0x1000 - -[BITS 16] ; Ensure 16-bit code (because fuck UEFI) - -Intro: - - jmp short _start ; Jump over the BIOS PARAMETER BLOCK - nop ; Required by BIOS to recognize the Disk loul -BPB: - ;---------------------------------------------------; - ; Disk description table ; - ;---------------------------------------------------; - %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 - - times 0x3b db 0x00 ; ALLOCATE THE SECTORS FOR THE BPB - -;; ENTRY POINT -_start: - jmp BOOT_SEG:$+5 ; Fix the cs:ip registers with a vaudou magical trip - -bootstrap: - jmp go - -;; LOVELY DATA -FileNotFound db "First Stage ERROR : NO LOADER", 0 -DiskError db "First Stage ERROR : DISK", 0 -UserData dw 0 -Bootdrv db 0 -filename db "LOADER BIN" - - -;; GO ! -go: - mov ax, BOOT_SEG ; Set segments to the location of the bootloader - mov ds, ax - mov es, ax - - ;; INIT STACK - cli - mov ax, STACK_SEG ; Init the stack - mov ss, ax ; Continue init the stack - mov sp, STACK_OFF ; Ok man, the stack is in 4K :O - sti - mov bp, (0x7c0-STACK_SEG) << 4 ; Correct bp (the disk description table) - - ;; INITIALIZE BOOT DISK - or dl, dl ; Verifying dl points actually to the boot drive - jz load_root - mov byte [Bootdrv], dl ; Another soul (the disk) saved! - mov ah, 0x08 - int 0x13 ; int 0x13 : read drive parameters/geom - jc load_root - and cx, 0x003f ; Maximum sector number is the high bits 6-7 of cl - mov word [sectorsPerTrack], cx ; And whose low 8 bits are in ch - mov dl, dh ; Convert the maximum head number to a word with another vaudou magical trip - xor dh, dh - inc dx ; because head numbers start at zero - mov word [heads], dx ; Another soul (the heads number) saved! - - - ;; LOAD THE ROOT DIRECTORY FROM DISK -load_root: - xor cx, cx - mov ax, 32 ; Size of root dir = (rootDirEntries * 32) / bytesPerSector - mul word [rootDirEntries] ; multiply by the total size of the root directory - div word [bytesPerSector] ; divide by the number of bytes used per sector - xchg cx, ax - - mov al, byte [fats] ; Location of root dir = (fats * fatSectors) + reservedSectors - mul word [fatSectors] ; multiply by the sectors used - add ax, word [reservedSectors] ; increase ax by the reserved sectors - mov word [UserData], ax ; Start of user data = startOfRoot + numberOfRoot - add word [UserData], cx ; Add the size and location of the root directory - - mov di, BUFFER_SEG ; Set the extra segment to the disk buffer - mov es, di - mov di, BUFFER_OFF ; Set es:di and load the root directory into the disk buffer - call read_sectors ; Read the sectors - - ;; FIND THE SECOND STAGE LOADER - mov di, BUFFER_OFF ; Set es:di to the disk buffer - mov cx, word [rootDirEntries] ; Search through all of the root dir entries - xor ax, ax ; Clear ax for the file entry offset -search_root: - xchg cx, dx ; Save cx because it's a loop counter - mov si, filename ; Load the filename - mov cx, 11 ; Compare first 11 bytes - rep cmpsb ; Compare si and di cx times - je load_fat ; We found the loader - add ax, 32 ; File entry offset - mov di, BUFFER_OFF ; Point back to the start of the entry - add di, ax ; Add the offset to point to the next entry - xchg dx, cx - loop search_root ; Continue to search for the file - - ;; ERROR... - mov si, FileNotFound ; Could not find the file - call print - call reboot - - ;; LOAD THE FAT FROM THE FILE -load_fat: - mov ax, word [es:di + 15] ; Get the file cluster at offset 26 - push ax ; Store the FAT cluster - xor ax, ax ; Size of fat = (fats * fatSectors) - mov al, byte [fats] ; Move number of fats into al - mul word [fatSectors] ; Move fat sectors into bx - mov cx, ax ; Store in cx - mov ax, word [reservedSectors] ; Convert the first fat on the disk - mov di, BUFFER_OFF ; Set es:di and load the fat sectors into the disk buffer - call read_sectors ; Read the sectors - - ;; LOAD THE CLUSTERS OF THE LOADER AND JUMP - mov di, LOAD_SEG - mov es, di ; Set es:bx to where the file will load - mov di, LOAD_OFF - pop ax ; File cluster restored - call read_clusters ; Read clusters from the file - mov dl, byte [Bootdrv] ; Pass the boot Bootdrv into dl - jmp LOAD_SEG:LOAD_OFF ; Jump to the file loaded! - - hlt ; This should never be hit... - ; ... - ; ... - ; I hope.... - ; ... - call reboot - -%include "boot/mbr.inc" - -;; END - times 510 - ($ - $$) db 0 ; Pad remainder of boot sector with zeros - dw 0xaa55 ; Boot signature diff --git a/boot/mbr.inc b/boot/mbr.inc deleted file mode 100644 index dc11db1..0000000 --- a/boot/mbr.inc +++ /dev/null @@ -1,161 +0,0 @@ -;=----------------------------------------------------------------------------=; -; GNU GPL OS/K ; -; ; -; Authors: spectral` ; -; NeoX ; -; ; -; Desc: Bootsector for OS/K INCLUDED FUNCTIONS ; -; (x86_64 architecture only) ; -;=----------------------------------------------------------------------------=; -[BITS 16] - -read_clusters: -;---------------------------------------------------; -; Read file clusters, starting at the given cluster,; -; expects FAT to be loaded into the disk buffer. ; -; Please note that this may allocate up to 128KB ; -; of ram. ; -; ; -; Expects: AX = Starting cluster ; -; ES:DI = Location to load clusters ; -; ; -; Returns: None ; -; ; -;---------------------------------------------------; - pusha - push es - .cluster_loop: - xor bh, bh - xor dx, dx - push ax ; Get the cluster start = (cluster - 2) * sectorsPerCluster + UserData - sub ax, 2 ; Subtract 2 - mov bl, byte [sectorsPerCluster] ; Sectors per cluster is a byte value - mul bx ; multiply (cluster - 2) * sectorsPerCluster - add ax, word [UserData] ; add the UserData - xor ch, ch - mov cl, byte [sectorsPerCluster] ; Sectors to read - call read_sectors ; Read the sectors - pop ax ; Current cluster number - xor dx, dx - ;; Calculate next sector for FAT16 (cluster * 2) - mov bx, 2 ; Multiply the cluster by two (cluster is in ax) - mul bx - ;; Load sector in RAM - push ds - push si - mov si, BUFFER_SEG - mov ds, si ; Temporarly set ds:si to the FAT buffer - mov si, BUFFER_OFF - add si, ax ; Point to the next cluster in the FAT entry - mov ax, word [ds:si] ; Load ax to the next cluster in FAT - pop si - pop ds - ;; Next - cmp ax, 0xfff8 ; Check if we are at the end of the file? - jae .done - add di, 512 ; Add to the pointer offset - jnc .cluster_loop - ;; Correct the buffer because an error will occur if the buffer in memory - mov dx, es ; overlaps a 64k page boundry, when di overflows - add dh, 0x10 ; it will trigger the carry flag, so correct - mov es, dx ; extra segment by 0x1000 - jmp .cluster_loop ; Load the next file cluster - .done: - pop es - popa - ret - - -read_sectors: -;---------------------------------------------------; -; Read sectors starting at a given sector by ; -; the given times and load into a buffer. Please ; -; note that this may allocate up to 128KB of ram. ; -; ; -; Expects: AX = Starting sector ; -; CX = Number of sectors to read ; -; ES:DI = Location to load sectors ; -; ; -; Returns: None ; -; ; -;---------------------------------------------------; - pusha - push es - mov bx, di ; Convert es:di to es:bx for int 13h - .sector_loop: - push ax - push cx - xor dx, dx - div word [sectorsPerTrack] ; Divide the lba (value in ax) by sectorsPerTrack - mov cx, dx ; Save the absolute sector value - inc cx - xor dx, dx ; Divide by the number of heads - div word [heads] ; to get absolute head and track values - mov dh, dl ; Move the absolute head into dh - mov ch, al ; Low 8 bits of absolute track - shl ah, 1 ; High 2 bits of absolute track - shl ah, 1 - shl ah, 1 - shl ah, 1 - shl ah, 1 - shl ah, 1 - or cl, ah ; Now cx is set with respective track and sector numbers - mov dl, byte [Bootdrv] ; Set correct Bootdrv for int 13h - mov di, 21 ; Try five times to read the sector because i love 21 - .attempt_read: - mov ax, 0x0201 ; Read Sectors func of int 13h, read one sector - int 0x13 ; Call int 13h (BIOS disk I/O) - jnc .read_ok ; If no carry set, the sector has been read - xor ah, ah ; Reset Bootdrv func of int 13h - int 0x13 ; Call int 13h (BIOS disk I/O) - dec di ; Decrease read attempt counter - jnz .attempt_read ; Try to read the sector again - mov si, DiskError ; Error reading the disk :/ - call print - jmp reboot - .read_ok: - pop cx - pop ax - inc ax ; Increase the next sector to read - add bx, word [bytesPerSector] ; Add to the buffer address for the next sector - jnc .next_sector - ;; Fixing buffer because an error will occur if the buffer in memory - mov dx, es ; overlaps a 64k page boundry, when bx overflows - add dh, 0x10 ; it will trigger the carry flag, so correct - mov es, dx ; es segment by 0x1000 - .next_sector: - loop .sector_loop - pop es - popa - ret - -print: -;---------------------------------------------------; -; 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 print ; Loop untill string is null - .done: - ret - -reboot: - xor ax, ax - int 0x16 ; Get a single keypress - mov ah, 0x0e ; Teletype output - mov al, 0x0d ; Carriage return - int 0x10 ; Video interupt - mov al, 0x0a ; Line feed - int 0x10 ; Video interupt - mov al, 0x0a ; Line feed - int 0x10 ; Video interupt - xor ax, ax - int 0x19 ; Reboot the system diff --git a/build/bin/disk.img b/build/bin/disk.img index e4692fd669b29f0ed863445b3ba1b42e58f12953..51ab1ef32c3eaaecf956123a736393ba26570add 100644 GIT binary patch delta 12802 zcmeI23wRXO6~|{b4?;pnvYQ0LL&CFCC@RS3J^cQR+s zoO@?>=9hEtf9{l4&Tn2Swy9;5d)0AAmu<_^!}g9Si)tDCjXgUiX7?W6d$?ifHpST3 z%rM@WX7n&}jXuU`BhFZ!Sw4b;;?B$3yo$FKMfG*{e)-V*@rL`zDzl%vG(PP5@;vn$E_yuZMk z<)4|A=b4r4-R3XI^VBDKpOD}_zZF_5?qa{U*k2!KChv9+IbgQVlHUCThB^=BCPW#Y zgm~|CfBo@8wSJ>^NyKocVJwLlCV$88%;=n8crrSh#=-#$2d%$(R!rfZh!ojl7&Xmy zTb}8jalpJcJxhX94S)ZkvOUzTm0`3tjMDV3nrjv(Y;NJ1muwi`iPF&5%J27Yj+S$k zK&}L;-ODP>o{^b*!n$9YH{2N@nPM{2iNU$cNu7=xCd64*(FQtpCOxkIk{(z+UAD$niFzm zVm!C#mB~^+&T~*ZAEFp%F~s6$Iy{H!qBTap zB=fY(ip9`W(Vpa8TvNqQhhb={7%GYXRk6%Iqgbq2Vq0sL7*H(MEU`}Kk_nPky={M) zdCDwrR_7As^67B=;zsC)6B`xKbgkLsx*!3a;tUedd!4p`&UKy<&=P7)xk&H+0dzGc zpts0`d`ZMp^0#pTT_SsI0j-`bpq-nFX;b;D z57N>X#NR4KCcxj*>Ie9HO#J|VR!)GwWfJ!~?L>>e(xAj*^#lA(KH0|V&EoGSZ8cra z^Rj@@dY;(CAxtxSIemA_Z9UAW;uD424Ks7+rBD=uptOpj1?7A4JA7xK=rqa7czHnC zFV;6lZf1zba~54fbH;|Hn9pm@XphusW{Ahe76C&%ela}C%(0hB7X1|Ns5OrjPV-Ha zayf4Fjbrj<=66xcnag(MPQ45?O`4h3-AHO+a%vEhhDw~dw!|@1;+*)T5~o6XYmhiw z)elIVD)j>r$I1yvoHB`fU3Q`+aqbC9oTYw1;!FvaIAgVyHJdypp085Z2S@4pV3V9p zUJg1t&Aj&NovN@Ku$&?{wxLvpl=sCrh+9jAOX+*Eh@TXO$}x^;vnz%0$6%vi;Ei5q+D+CwIL1 zLY|R7s`Lb&QEpK`fFjioplIa;P+Tf;Z-Sj@p;#h*?}p6Vbw^+X*MA-9&3Z;TMtmDZ zhs-v76^h~wArxD9F2N-mmEUJk{5Xbp+88>tGJYucy?RW>^oglOg{ir>PAD##Io9~U zVLAAGE-xI*qp|`T!ctbw>^F2TK`dQ@<@uzYk7<=%Evtg6rByjEg=z_!paTp8!@&qJ z5^M%Wfz82aFa~S^#)2)uI4~Ye0G*%R5r{uo>iJ_NeK72w0*O7IczQE(Ml0j>rs!JmL@z@LI^!FAxz!1W-($G|G^ zac~3pb8sX01h@%&5_}5W3~m9R2DgISz+Zsd!5!c;;IrT_K@YeS+yy=d{tB!Hp9fz6 zcY}MtUxU8^e+&K&{5|+0xEK5b_!9U>@MZ8%;49#t!M}j}z*oV)f`0>F1OE=b4!!}t z3BCpH2M>V%0N)1R0S|)jf?m)E9s+B?!{B@1Kf(9GTJQ*X6g&nV2kXFpf&T_S06zrl z!4u#~@Dz9&^glrJL7HL?u`sc4u?Vq9v1VdXV$H>(#bU%-h{cMv6pIs!7fTRxin+uR h#gfF5#afBA7E2LpBi2@|omhLZE5tgO8<}cO{s{Wy#0&rc delta 13298 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 Kfd*Cs4Fmw_YY(Xa diff --git a/build/obj/boot/loader.bin b/build/obj/boot/loader.bin index 096e80a677dc1a99d6ef20f8c99f89342a5542a8..39723e4850df1a06b50ed872260499334026f15f 100644 GIT binary patch delta 708 zcmZuuO=uHQ5T4yO+t{Y==ErDGjV%FtDT*3U0zCzmg3uU9Q-f7$U8RQ>>U#39f(R`w zO_~L%MS4)d5Q42HM5?j|RuV5(5upVUp-9|h59XkU)}QCRYRD>E%J|f zVeZZR=6q?|d)IUHL;bq|s+T*laPG{)u`VU!zQ5|05>i~x*-J84*#A~Af9h4CEC3!t z&@8>Pd^))sufX8fw1cgt<9bZ8vP3j@SIbz6U zhiANHf%lgj4BuTsFP#k#LKF-n62v)3FypRAop#Wif-ymMe$*QT8cAEh4Un`wMSJm8 zxW@@vxQBt6;7tFcOV>N3icP@`fZ0|?q>9XK*D4a@Ku%`R*Sik_98!I@zv>Onr;c)w zBR4|2QEVs|0@)vG zm%Bop@~Q0fW>&mK6#y&+>lB!uE{y2nY-^y5k;qu-Jrub32b8P_m%C~$x;W8x@#K-rP*Jz?s`%Dv8EYUc{3B>sIXjnA0_6HALui#R;d#kYP9 z$AJ>IEqrGMUVl9twogj*#oPaJFXsF&@(tT}Ui8I-|8ZgaLPTHO_#gLV5)ad}Nnp`a zKqaaFU-U*UQ~m${e?5?$_TLO>$$ztLVy~nGIT-edi@lig z|JRpSAO16Z=x047#=y|edH_gHj%O6(c>-iGFuZ0z#`;8TawB7_&6zkYW!_h_vQ)kf|UM5Qum^%ewspXYH~?_QS4+1rhgL!jVFsSX92C9yng3X!%;_&Xf2a@Q4D9Q%08-VPcK$kL1m@whd?-v5U Kfd*Cs4Fmw_YY(Xa From c7aed282e8b096a9e0cf4133fbb30392ba9940c5 Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Wed, 16 Jan 2019 11:04:44 +0100 Subject: [PATCH 4/4] REAL reorganization stuff --- boot/loader/cpu/cpu.asm | 22 ++++ boot/loader/cpu/cpuid.asm | 50 ++++++++ boot/loader/elf/elf.c | 10 ++ boot/loader/fs/fat.asm | 18 +++ boot/loader/io/ata.asm | 138 ++++++++++++++++++++++ boot/loader/io/lmmem.asm | 28 +++++ boot/loader/io/lmterm.asm | 116 +++++++++++++++++++ boot/loader/io/rmmem.asm | 98 ++++++++++++++++ boot/loader/io/rmterm.asm | 55 +++++++++ boot/loader/loader.asm | 233 ++++++++++++++++++++++++++++++++++++++ boot/mbr/mbr.asm | 175 ++++++++++++++++++++++++++++ boot/mbr/mbr.inc | 161 ++++++++++++++++++++++++++ build/bin/disk.img | Bin 18944000 -> 18944000 bytes 13 files changed, 1104 insertions(+) create mode 100644 boot/loader/cpu/cpu.asm create mode 100644 boot/loader/cpu/cpuid.asm create mode 100644 boot/loader/elf/elf.c create mode 100644 boot/loader/fs/fat.asm create mode 100644 boot/loader/io/ata.asm create mode 100644 boot/loader/io/lmmem.asm create mode 100644 boot/loader/io/lmterm.asm create mode 100644 boot/loader/io/rmmem.asm create mode 100644 boot/loader/io/rmterm.asm create mode 100644 boot/loader/loader.asm create mode 100644 boot/mbr/mbr.asm create mode 100644 boot/mbr/mbr.inc diff --git a/boot/loader/cpu/cpu.asm b/boot/loader/cpu/cpu.asm new file mode 100644 index 0000000..206097a --- /dev/null +++ b/boot/loader/cpu/cpu.asm @@ -0,0 +1,22 @@ +;=----------------------------------------------------------------------------=; +; GNU GPL OS/K ; +; ; +; Authors: spectral` ; +; NeoX ; +; ; +; Desc: Basic longmode CPU functions ; +; (x86_64 architecture only) ; +;=----------------------------------------------------------------------------=; + +[BITS 64] + +temporize: + push rcx + mov rcx, 2000 +.looping: + nop + nop + nop + loop .looping + pop rcx + ret diff --git a/boot/loader/cpu/cpuid.asm b/boot/loader/cpu/cpuid.asm new file mode 100644 index 0000000..ac82eff --- /dev/null +++ b/boot/loader/cpu/cpuid.asm @@ -0,0 +1,50 @@ +;=----------------------------------------------------------------------------=; +; GNU GPL OS/K ; +; ; +; Authors: spectral` ; +; NeoX ; +; ; +; Desc: Basic realmode CPU Detection ; +; (x86_64 architecture only) ; +;=----------------------------------------------------------------------------=; + +[BITS 16] + +;; GLOBAL DATA +NoLongMode db 0x0A, 0x0D, "ERROR : Your computer is not designed for x64 OS", 0 + +;; TEXT + +Is64bits: +;-----------------------------------------------------------------------; +; 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 ; +;-----------------------------------------------------------------------; + 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 diff --git a/boot/loader/elf/elf.c b/boot/loader/elf/elf.c new file mode 100644 index 0000000..c30d834 --- /dev/null +++ b/boot/loader/elf/elf.c @@ -0,0 +1,10 @@ +//----------------------------------------------------------------------------// +// GNU GPL OS/K // +// // +// Authors: spectral` // +// NeoX // +// // +// Desc: ELF64 Parser and Loader // +//----------------------------------------------------------------------------// + +int stub; diff --git a/boot/loader/fs/fat.asm b/boot/loader/fs/fat.asm new file mode 100644 index 0000000..d9bca9b --- /dev/null +++ b/boot/loader/fs/fat.asm @@ -0,0 +1,18 @@ +;=----------------------------------------------------------------------------=; +; GNU GPL OS/K ; +; ; +; Authors: spectral` ; +; NeoX ; +; ; +; Desc: Basic File Allocation Table Long mode Driver ; +; (x86_64 architecture only) ; +;=----------------------------------------------------------------------------=; + +[BITS 64] + +;; GLOBAL DATA +UserData dw 0 + +;; TEXT + +nop diff --git a/boot/loader/io/ata.asm b/boot/loader/io/ata.asm new file mode 100644 index 0000000..bc9c2ef --- /dev/null +++ b/boot/loader/io/ata.asm @@ -0,0 +1,138 @@ +;=----------------------------------------------------------------------------=; +; GNU GPL OS/K ; +; ; +; Authors: spectral` ; +; NeoX ; +; ; +; Desc: Basic Read Only ATA Long mode Driver ; +; (x86_64 architecture only) ; +;=----------------------------------------------------------------------------=; + +[BITS 64] + +;; 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 + +;; GLOBAL DATA + +Bootdrv db 0 +end db "[End of Sector]", 0x0 +buffer: times 513 db "_" + +;; TEXT + +ata_read: +;-----------------------------------------------------------------------; +; x64/LM ATA Reading function ; +; ; +; ; +;-----------------------------------------------------------------------; + +; Technical infos about the ports (Intel Doc): +; +; Port Access Mode Misc +; +; 1f0 r/w Data register, the bytes of the disk itself +; 1f1 r Error register that can be handled +; 1f2 r/w Sector count, how many sectors to read +; 1f3 r/w Sector number, the actual sector wanted +; 1f4 r/w Cylinder low, cylinders is 0-1024 +; 1f5 r/w Cylinder high, this makes up the rest of the 1024 +; 1f6 r/w Drive/head +; bit 7 = 1 +; bit 6 = 0 +; bit 5 = 1 +; bit 4 = 0 drive 0 select +; = 1 drive 1 select +; bit 3-0 head select bits +; 1f7 r Status register +; bit 7 = 1 controller is executing a command +; bit 6 = 1 drive is ready +; bit 5 = 1 write fault +; bit 4 = 1 seek complete +; bit 3 = 1 sector buffer requires servicing +; bit 2 = 1 disk data read corrected +; bit 1 = 1 index - set to 1 each revolution +; bit 0 = 1 previous command ended in an error +; 1f7 w Command register +; commands: +; 50h format track +; 20h read sectors with retry +; 21h read sectors without retry +; 22h read long with retry +; 23h read long without retry +; 30h write sectors with retry +; 31h write sectors without retry +; 32h write long with retry +; 33h write long without retry +; + + push rax + push rbx + push rdx + push rcx + push rdi + mov dx, 0x1f6 ; Drive and head port + mov al, 0x0a0 ; Drive 0, head 0 + out dx,al + + mov dx, 0x1f2 ; Sector count port + mov al, 1 ; Read one sector + out dx, al + + mov dx, 0x1f3 ; Sector number port + mov al, 1 ; Read sector one + out dx, al + + mov dx, 0x1f4 ; Cylinder low port + mov al, 0 ; Cylinder 0 + out dx, al + + mov dx, 0x1f5 ; Cylinder high port + mov al, 0 ; The rest of the cylinder 0 + out dx, al + + mov dx, 0x1f7 ; Command port + mov al, 0x20 ; Read with retry. + out dx, al +still_going: + in al, dx + test al, 8 ; This means the sector buffer requires + ;servicing. + jz still_going ; Don't continue until the sector buffer + ;is ready. + + mov cx, 512/2 ; One sector /2 because it copies words + mov rdi, buffer + mov dx, 0x1f0 ; Data port - data comes in and out of here. + rep insw + pop rdi + pop rcx + pop rdx + pop rbx + pop rax + mov bl, 0x0F + mov esi, buffer + call dump + mov bl, 0x0A + mov esi, end + call write + ret diff --git a/boot/loader/io/lmmem.asm b/boot/loader/io/lmmem.asm new file mode 100644 index 0000000..a82330e --- /dev/null +++ b/boot/loader/io/lmmem.asm @@ -0,0 +1,28 @@ +;=----------------------------------------------------------------------------=; +; GNU GPL OS/K ; +; ; +; Authors: spectral` ; +; NeoX ; +; ; +; Desc: Basic Memory Long mode Functions ; +; (x86_64 architecture only) ; +;=----------------------------------------------------------------------------=; +[BITS 64] + +;; GLOBAL DATA +A20_OK db 0 + +;; TEXT + +check_a20: + 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 + ret diff --git a/boot/loader/io/lmterm.asm b/boot/loader/io/lmterm.asm new file mode 100644 index 0000000..3fa0ccb --- /dev/null +++ b/boot/loader/io/lmterm.asm @@ -0,0 +1,116 @@ +;=----------------------------------------------------------------------------=; +; GNU GPL OS/K ; +; ; +; Authors: spectral` ; +; NeoX ; +; ; +; Desc: Basic Colored VGA Terminal Long mode Driver ; +; (x86_64 architecture only) ; +;=----------------------------------------------------------------------------=; + +;;VIDEO +%define TRAM 0x0B8000 ; [T]ext[RAM] +%define VRAM 0x0A0000 ; [V]ideo[RAM] + +;; GLOBAL DATA + +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 + +;; TEXT + +[BITS 64] + +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: + ; XXX I don't think I'll implement this, but never know...; + jmp .pLoop + +dump: +;-----------------------------------------------------------------------; +; x64/LM Dump Printing Functions ; +; bl : color code ; +; esi : string address ; +;-----------------------------------------------------------------------; + mov edi, [NextTRAM] ; TRAM ADDRESS + push rsi + push rdi + push rcx + mov rcx, 512 +.pLoop: + lodsb + 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 + loop .pLoop + pop rcx + pop rdi + pop rsi + ret diff --git a/boot/loader/io/rmmem.asm b/boot/loader/io/rmmem.asm new file mode 100644 index 0000000..2348083 --- /dev/null +++ b/boot/loader/io/rmmem.asm @@ -0,0 +1,98 @@ +;=----------------------------------------------------------------------------=; +; GNU GPL OS/K ; +; ; +; Authors: spectral` ; +; NeoX ; +; ; +; Desc: Basic Memory Realmode Driver ; +; (x86_64 architecture only) ; +;=----------------------------------------------------------------------------=; + +[BITS 16] + +;; 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: + +;; TEXT + +set_a20: + push ax + in al, 0x92 + or al, 2 + out 0x92, al + pop ax + ret diff --git a/boot/loader/io/rmterm.asm b/boot/loader/io/rmterm.asm new file mode 100644 index 0000000..7bedfca --- /dev/null +++ b/boot/loader/io/rmterm.asm @@ -0,0 +1,55 @@ +;=----------------------------------------------------------------------------=; +; GNU GPL OS/K ; +; ; +; Authors: spectral` ; +; NeoX ; +; ; +; Desc: Basic realmode terminal functions ; +; (x86_64 architecture only) ; +;=----------------------------------------------------------------------------=; + +[BITS 16] + +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 + +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 diff --git a/boot/loader/loader.asm b/boot/loader/loader.asm new file mode 100644 index 0000000..897ba5a --- /dev/null +++ b/boot/loader/loader.asm @@ -0,0 +1,233 @@ +;=----------------------------------------------------------------------------=; +; GNU GPL OS/K ; +; ; +; Authors: spectral` ; +; NeoX ; +; ; +; Desc: Kernel (second stage) Loader for OS/K ; +; (x86_64 architecture only) ; +;=----------------------------------------------------------------------------=; + +[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 + +%include "boot/loader/cpu/cpuid.asm" +%include "boot/loader/io/rmterm.asm" +%include "boot/loader/io/rmmem.asm" + +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 + + call set_a20 + + 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 + +;; THE HOLE ----------------------------------------------------------------- ;; +ErrorNo64: + mov si, NoLongMode + call PrintB +Die: + cli + hlt ; die nooooow + jmp 0xF000:0xFFF0 +;; END OF THE HOLE ---------------------------------------------------------- ;; + +[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] + +;; 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 +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" + +%include "boot/loader/io/lmmem.asm" +%include "boot/loader/io/lmterm.asm" +%include "boot/loader/io/ata.asm" +%include "boot/loader/cpu/cpu.asm" +%include "boot/loader/fs/fat.asm" + +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 + + call check_a20 + + 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 + + call temporize ; 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... diff --git a/boot/mbr/mbr.asm b/boot/mbr/mbr.asm new file mode 100644 index 0000000..42f0dbd --- /dev/null +++ b/boot/mbr/mbr.asm @@ -0,0 +1,175 @@ +;=----------------------------------------------------------------------------=; +; GNU GPL OS/K ; +; ; +; Authors: spectral` ; +; NeoX ; +; ; +; Desc: Bootsector for OS/K ; +; (x86_64 architecture only) ; +;=----------------------------------------------------------------------------=; + +;; BOOT "SEGMENT" +%define BOOT_SEG 0x07c0 ; (BOOT_SEG << 4) + BOOT_OFF = 0x007c00 +%define BOOT_OFF 0x0000 + +;; STACK "SEGMENT" +%define STACK_SEG 0x0600 ; (STACK_SEG << 4) + STACK_OFF = 0x007000 +%define STACK_OFF 0x1000 + +;; DISK BUFFER "SEGMENT" +%define BUFFER_SEG 0x2000 ; (BUFFER_SEG << 4) + BUFFER_OFF = 0x020000 +%define BUFFER_OFF 0x0000 + +;; SECOND STAGE LOADER "SEGMENT" +%define LOAD_SEG 0x0000 ; (LOAD_SEG << 4) + LOAD_OFF = 0x001000 +%define LOAD_OFF 0x1000 + +[BITS 16] ; Ensure 16-bit code (because fuck UEFI) + +Intro: + + jmp short _start ; Jump over the BIOS PARAMETER BLOCK + nop ; Required by BIOS to recognize the Disk loul +BPB: + ;---------------------------------------------------; + ; Disk description table ; + ;---------------------------------------------------; + %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 + + times 0x3b db 0x00 ; ALLOCATE THE SECTORS FOR THE BPB + +;; ENTRY POINT +_start: + jmp BOOT_SEG:$+5 ; Fix the cs:ip registers with a vaudou magical trip + +bootstrap: + jmp go + +;; LOVELY DATA +FileNotFound db "First Stage ERROR : NO LOADER", 0 +DiskError db "First Stage ERROR : DISK", 0 +UserData dw 0 +Bootdrv db 0 +filename db "LOADER BIN" + + +;; GO ! +go: + mov ax, BOOT_SEG ; Set segments to the location of the bootloader + mov ds, ax + mov es, ax + + ;; INIT STACK + cli + mov ax, STACK_SEG ; Init the stack + mov ss, ax ; Continue init the stack + mov sp, STACK_OFF ; Ok man, the stack is in 4K :O + sti + mov bp, (0x7c0-STACK_SEG) << 4 ; Correct bp (the disk description table) + + ;; INITIALIZE BOOT DISK + or dl, dl ; Verifying dl points actually to the boot drive + jz load_root + mov byte [Bootdrv], dl ; Another soul (the disk) saved! + mov ah, 0x08 + int 0x13 ; int 0x13 : read drive parameters/geom + jc load_root + and cx, 0x003f ; Maximum sector number is the high bits 6-7 of cl + mov word [sectorsPerTrack], cx ; And whose low 8 bits are in ch + mov dl, dh ; Convert the maximum head number to a word with another vaudou magical trip + xor dh, dh + inc dx ; because head numbers start at zero + mov word [heads], dx ; Another soul (the heads number) saved! + + + ;; LOAD THE ROOT DIRECTORY FROM DISK +load_root: + xor cx, cx + mov ax, 32 ; Size of root dir = (rootDirEntries * 32) / bytesPerSector + mul word [rootDirEntries] ; multiply by the total size of the root directory + div word [bytesPerSector] ; divide by the number of bytes used per sector + xchg cx, ax + + mov al, byte [fats] ; Location of root dir = (fats * fatSectors) + reservedSectors + mul word [fatSectors] ; multiply by the sectors used + add ax, word [reservedSectors] ; increase ax by the reserved sectors + mov word [UserData], ax ; Start of user data = startOfRoot + numberOfRoot + add word [UserData], cx ; Add the size and location of the root directory + + mov di, BUFFER_SEG ; Set the extra segment to the disk buffer + mov es, di + mov di, BUFFER_OFF ; Set es:di and load the root directory into the disk buffer + call read_sectors ; Read the sectors + + ;; FIND THE SECOND STAGE LOADER + mov di, BUFFER_OFF ; Set es:di to the disk buffer + mov cx, word [rootDirEntries] ; Search through all of the root dir entries + xor ax, ax ; Clear ax for the file entry offset +search_root: + xchg cx, dx ; Save cx because it's a loop counter + mov si, filename ; Load the filename + mov cx, 11 ; Compare first 11 bytes + rep cmpsb ; Compare si and di cx times + je load_fat ; We found the loader + add ax, 32 ; File entry offset + mov di, BUFFER_OFF ; Point back to the start of the entry + add di, ax ; Add the offset to point to the next entry + xchg dx, cx + loop search_root ; Continue to search for the file + + ;; ERROR... + mov si, FileNotFound ; Could not find the file + call print + call reboot + + ;; LOAD THE FAT FROM THE FILE +load_fat: + mov ax, word [es:di + 15] ; Get the file cluster at offset 26 + push ax ; Store the FAT cluster + xor ax, ax ; Size of fat = (fats * fatSectors) + mov al, byte [fats] ; Move number of fats into al + mul word [fatSectors] ; Move fat sectors into bx + mov cx, ax ; Store in cx + mov ax, word [reservedSectors] ; Convert the first fat on the disk + mov di, BUFFER_OFF ; Set es:di and load the fat sectors into the disk buffer + call read_sectors ; Read the sectors + + ;; LOAD THE CLUSTERS OF THE LOADER AND JUMP + mov di, LOAD_SEG + mov es, di ; Set es:bx to where the file will load + mov di, LOAD_OFF + pop ax ; File cluster restored + call read_clusters ; Read clusters from the file + mov dl, byte [Bootdrv] ; Pass the boot Bootdrv into dl + jmp LOAD_SEG:LOAD_OFF ; Jump to the file loaded! + + hlt ; This should never be hit... + ; ... + ; ... + ; I hope.... + ; ... + call reboot + +%include "boot/mbr/mbr.inc" + +;; END + times 510 - ($ - $$) db 0 ; Pad remainder of boot sector with zeros + dw 0xaa55 ; Boot signature diff --git a/boot/mbr/mbr.inc b/boot/mbr/mbr.inc new file mode 100644 index 0000000..dc11db1 --- /dev/null +++ b/boot/mbr/mbr.inc @@ -0,0 +1,161 @@ +;=----------------------------------------------------------------------------=; +; GNU GPL OS/K ; +; ; +; Authors: spectral` ; +; NeoX ; +; ; +; Desc: Bootsector for OS/K INCLUDED FUNCTIONS ; +; (x86_64 architecture only) ; +;=----------------------------------------------------------------------------=; +[BITS 16] + +read_clusters: +;---------------------------------------------------; +; Read file clusters, starting at the given cluster,; +; expects FAT to be loaded into the disk buffer. ; +; Please note that this may allocate up to 128KB ; +; of ram. ; +; ; +; Expects: AX = Starting cluster ; +; ES:DI = Location to load clusters ; +; ; +; Returns: None ; +; ; +;---------------------------------------------------; + pusha + push es + .cluster_loop: + xor bh, bh + xor dx, dx + push ax ; Get the cluster start = (cluster - 2) * sectorsPerCluster + UserData + sub ax, 2 ; Subtract 2 + mov bl, byte [sectorsPerCluster] ; Sectors per cluster is a byte value + mul bx ; multiply (cluster - 2) * sectorsPerCluster + add ax, word [UserData] ; add the UserData + xor ch, ch + mov cl, byte [sectorsPerCluster] ; Sectors to read + call read_sectors ; Read the sectors + pop ax ; Current cluster number + xor dx, dx + ;; Calculate next sector for FAT16 (cluster * 2) + mov bx, 2 ; Multiply the cluster by two (cluster is in ax) + mul bx + ;; Load sector in RAM + push ds + push si + mov si, BUFFER_SEG + mov ds, si ; Temporarly set ds:si to the FAT buffer + mov si, BUFFER_OFF + add si, ax ; Point to the next cluster in the FAT entry + mov ax, word [ds:si] ; Load ax to the next cluster in FAT + pop si + pop ds + ;; Next + cmp ax, 0xfff8 ; Check if we are at the end of the file? + jae .done + add di, 512 ; Add to the pointer offset + jnc .cluster_loop + ;; Correct the buffer because an error will occur if the buffer in memory + mov dx, es ; overlaps a 64k page boundry, when di overflows + add dh, 0x10 ; it will trigger the carry flag, so correct + mov es, dx ; extra segment by 0x1000 + jmp .cluster_loop ; Load the next file cluster + .done: + pop es + popa + ret + + +read_sectors: +;---------------------------------------------------; +; Read sectors starting at a given sector by ; +; the given times and load into a buffer. Please ; +; note that this may allocate up to 128KB of ram. ; +; ; +; Expects: AX = Starting sector ; +; CX = Number of sectors to read ; +; ES:DI = Location to load sectors ; +; ; +; Returns: None ; +; ; +;---------------------------------------------------; + pusha + push es + mov bx, di ; Convert es:di to es:bx for int 13h + .sector_loop: + push ax + push cx + xor dx, dx + div word [sectorsPerTrack] ; Divide the lba (value in ax) by sectorsPerTrack + mov cx, dx ; Save the absolute sector value + inc cx + xor dx, dx ; Divide by the number of heads + div word [heads] ; to get absolute head and track values + mov dh, dl ; Move the absolute head into dh + mov ch, al ; Low 8 bits of absolute track + shl ah, 1 ; High 2 bits of absolute track + shl ah, 1 + shl ah, 1 + shl ah, 1 + shl ah, 1 + shl ah, 1 + or cl, ah ; Now cx is set with respective track and sector numbers + mov dl, byte [Bootdrv] ; Set correct Bootdrv for int 13h + mov di, 21 ; Try five times to read the sector because i love 21 + .attempt_read: + mov ax, 0x0201 ; Read Sectors func of int 13h, read one sector + int 0x13 ; Call int 13h (BIOS disk I/O) + jnc .read_ok ; If no carry set, the sector has been read + xor ah, ah ; Reset Bootdrv func of int 13h + int 0x13 ; Call int 13h (BIOS disk I/O) + dec di ; Decrease read attempt counter + jnz .attempt_read ; Try to read the sector again + mov si, DiskError ; Error reading the disk :/ + call print + jmp reboot + .read_ok: + pop cx + pop ax + inc ax ; Increase the next sector to read + add bx, word [bytesPerSector] ; Add to the buffer address for the next sector + jnc .next_sector + ;; Fixing buffer because an error will occur if the buffer in memory + mov dx, es ; overlaps a 64k page boundry, when bx overflows + add dh, 0x10 ; it will trigger the carry flag, so correct + mov es, dx ; es segment by 0x1000 + .next_sector: + loop .sector_loop + pop es + popa + ret + +print: +;---------------------------------------------------; +; 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 print ; Loop untill string is null + .done: + ret + +reboot: + xor ax, ax + int 0x16 ; Get a single keypress + mov ah, 0x0e ; Teletype output + mov al, 0x0d ; Carriage return + int 0x10 ; Video interupt + mov al, 0x0a ; Line feed + int 0x10 ; Video interupt + mov al, 0x0a ; Line feed + int 0x10 ; Video interupt + xor ax, ax + int 0x19 ; Reboot the system diff --git a/build/bin/disk.img b/build/bin/disk.img index 51ab1ef32c3eaaecf956123a736393ba26570add..d3916c3b23024e906cc1b5687cb89ac0fc947099 100644 GIT binary patch delta 1202 zcmWmE_n!}R0LSsi_s*T$%k5ccC=HD}N=k)xDh;$yu9V$W>T*{{hiiy-XVsUAYtf)1 zp({jXr6^l_(4zAE{P2AJ2k&=PLrr28jpfluMs-EBwjvrKhFDq`JsnL*sbtqf)eLm9?!Mlh1wxScz=le@T^QQX75 zjOIS>r-}y{Lp3!#$V1dJmT^2x9pjn6MCy5jM|q6LnZy%JW(rU86i@RE&+;74^8yV_ zWg63&!AxG{C8Eq?HZSuEuQG?ZH1Zm+^9FD77W0_T+q}cOyvG6-@;*&0Vlf}Egb!KD zGM4iZ&3w!!tY9Up_>|SG;WIwx3)ZrZ^=x1xU$Tj>_?pdZ;TyhXE8E!44tBDO-R$8z zzUK#i$v0l#tYrw2<_WjF8NbtdLeA*&#V0xgmKW`5^@%g&{>D#UUjjr6FaJCif6&t~>}1 C7adOk delta 1202 zcmWmE_n#MX0LSsi_g1&}o~Woq5qB9;R!CGTWtGH{goMbry5n%TA~WimzU|B2S1CFx ztBI_(omFPf&kxVnfAD_SG}R^5&|Ddf#L#>Vu&SULRXI9NV;(pM^i}^ z-8qJ1IgaD$!3ms5PkM0@Cvys?avHrkoijL-KAc5g&gLBY(VqdF%RmM(nDZFIP|oK9 zF61IEW*Eb{gb`fING{`Ys=0zI8O2qM=4!@p4cBrVW4WGj+`x_8#CUGz7A9~jw{bgn zP{TwfQA-_nau@a7%{|;p1NU)1575YDrtlySF_njTghzRd$9aNjJjqi`X9i8oWEQiT z!(8U^G*RZWfQ2k#F-urVGs}2}XL*k2d4U&siI;hWS9y)sd4m>~vx1ep$tqU!7H_kL zR^H)V-s62fU@af=5g+pjpR$hiY+xgs*vw~q&KGRqOTOZ3zTsQ8vW@NRU?;oS&3Amy z5B$ha{LC-x;a7g+cmCi{_Og$^_?v(Dm;d;`!S)*oi3y1fi3^DjNeF2Zk{FT{k{pr} yk{Xg0k{*%~k{OZ}k{yy0k{gm2k{?nKQW#PcQXEneQW{bgQXWzfX>kvc*6RHruN_kW