Grub stuff
This commit is contained in:
parent
01e0c9fe01
commit
8114333370
|
@ -27,12 +27,13 @@ This folder contains the source for OS/K's bootloader.
|
||||||
OS/K being intended to only run on x86-64 systems, we have not divided
|
OS/K being intended to only run on x86-64 systems, we have not divided
|
||||||
this folder into one sub-folder per architecture.
|
this folder into one sub-folder per architecture.
|
||||||
|
|
||||||
It is divided in two parts each of exactly 512 bytes:
|
The bootloader itself is external to the OS/K project. We are using GRUB 2 to load
|
||||||
- mbr.s (and its auxiliary file mbr.inc)
|
our kernel loader in memory.
|
||||||
This is our Master Boot Record (MBR). It switches to long mode
|
|
||||||
(64 bits mode) then loads the second half of the bootloader.
|
|
||||||
The MBR must be placed precisely on the first sector of the hard drive.
|
|
||||||
|
|
||||||
- loader.s
|
The kernel loader, that we call the loader, is the main subject of this folder.
|
||||||
This is the Kernel Loader. It switches to long mode and makes stuff.
|
This loader is intended to load the ELF64 kernel at the specified address and
|
||||||
|
prepare it for the hard work it have to do :
|
||||||
|
|
||||||
|
- Parsing the ELF64
|
||||||
|
- Load the kernel
|
||||||
|
- Prepare a structure for it with memory map, cpu infos, and other devices infos.
|
||||||
|
|
191
boot/mbr/mbr.asm
191
boot/mbr/mbr.asm
|
@ -1,191 +0,0 @@
|
||||||
;=----------------------------------------------------------------------------=;
|
|
||||||
; GNU GPL OS/K ;
|
|
||||||
; ;
|
|
||||||
; Desc: Bootsector for OS/K ;
|
|
||||||
; (x86_64 architecture only) ;
|
|
||||||
; ;
|
|
||||||
; ;
|
|
||||||
; Copyright © 2018-2019 The OS/K Team ;
|
|
||||||
; ;
|
|
||||||
; This file is part of OS/K. ;
|
|
||||||
; ;
|
|
||||||
; OS/K is free software: you can redistribute it and/or modify ;
|
|
||||||
; it under the terms of the GNU General Public License as published by ;
|
|
||||||
; the Free Software Foundation, either version 3 of the License, or ;
|
|
||||||
; any later version. ;
|
|
||||||
; ;
|
|
||||||
; OS/K is distributed in the hope that it will be useful, ;
|
|
||||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of ;
|
|
||||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;
|
|
||||||
; GNU General Public License for more details. ;
|
|
||||||
; ;
|
|
||||||
; You should have received a copy of the GNU General Public License ;
|
|
||||||
; along with OS/K. If not, see <https://www.gnu.org/licenses/>. ;
|
|
||||||
;=----------------------------------------------------------------------------=;
|
|
||||||
|
|
||||||
;; 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
|
|
177
boot/mbr/mbr.inc
177
boot/mbr/mbr.inc
|
@ -1,177 +0,0 @@
|
||||||
;=----------------------------------------------------------------------------=;
|
|
||||||
; GNU GPL OS/K ;
|
|
||||||
; ;
|
|
||||||
; Desc: Bootsector for OS/K INCLUDED FUNCTIONS ;
|
|
||||||
; (x86_64 architecture only) ;
|
|
||||||
; ;
|
|
||||||
; ;
|
|
||||||
; Copyright © 2018-2019 The OS/K Team ;
|
|
||||||
; ;
|
|
||||||
; This file is part of OS/K. ;
|
|
||||||
; ;
|
|
||||||
; OS/K is free software: you can redistribute it and/or modify ;
|
|
||||||
; it under the terms of the GNU General Public License as published by ;
|
|
||||||
; the Free Software Foundation, either version 3 of the License, or ;
|
|
||||||
; any later version. ;
|
|
||||||
; ;
|
|
||||||
; OS/K is distributed in the hope that it will be useful, ;
|
|
||||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of ;
|
|
||||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;
|
|
||||||
; GNU General Public License for more details. ;
|
|
||||||
; ;
|
|
||||||
; You should have received a copy of the GNU General Public License ;
|
|
||||||
; along with OS/K. If not, see <https://www.gnu.org/licenses/>. ;
|
|
||||||
;=----------------------------------------------------------------------------=;
|
|
||||||
|
|
||||||
[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
|
|
Loading…
Reference in New Issue