;=----------------------------------------------------------------------------=; ; 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 staaaaaack mov ss, ax ; Continue init the staaaaaaaack 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 sectoooooooors ! ;; 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 LOADEEEEEEEER!!! 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 sectooooooooooors !!! ;; 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