Initial commit

This commit is contained in:
mid
2026-05-01 12:43:49 +03:00
commit 08f9c590e3
14 changed files with 1338 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.bin
/kernel

26
build.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash
set -e
export LC_ALL=C
nasm -fbin -o 1.bin src/boot/x86/1.asm
nasm -DSTAGE2_SIZE=$(stat --printf="%s" 1.bin) -fbin -o 0.bin src/boot/x86/0.asm
i386-unknown-elf-gcc -s -Wl,--export-dynamic -fno-pic -flto -Os -mgeneral-regs-only -Isrc/kernel/ -ffreestanding -nostdlib -nostartfiles -o kernel src/kernel/x86/ppm.c src/kernel/x86/vpm.c src/kernel/x86/log.c src/kernel/tinyubsan.c src/kernel/main.c -fsanitize=undefined
dd if=/dev/zero of=drive.bin bs=1024 count=10240
/bin/echo -e 'mklabel msdos\nmkpart primary 8192b -1s\nquit\n' | parted drive.bin
[[ "$(udisksctl loop-setup -f drive.bin)" =~ (/dev/loop[0-9]+) ]] && LOOPDEV="${BASH_REMATCH[1]}"
sudo mkfs.ext2 -E root_perms=777 -b 1024 "${LOOPDEV}p1"
sleep 0.5
[[ "$(udisksctl mount -b ${LOOPDEV}p1)" =~ (/run/.+) ]] && MOUNTDIR="${BASH_REMATCH[1]}"
cp ./kernel "${MOUNTDIR}/kernel"
udisksctl unmount -b "${LOOPDEV}p1"
udisksctl loop-delete -b "${LOOPDEV}"
# Copy first stage bootloader without overwriting MBR
dd if=0.bin of=drive.bin bs=1 count=440 seek=0 conv=notrunc,nocreat
# Copy second stage bootloader, hope it's not too fat
dd if=1.bin of=drive.bin bs=1 seek=512 conv=notrunc,nocreat

53
src/boot/x86/0.asm Normal file
View File

@@ -0,0 +1,53 @@
bits 16
org 0x7C00
jmp 0x0:_start
_start:
mov ax, 0
mov ds, ax
mov es, ax
mov ss, ax
mov fs, ax
mov gs, ax
mov ax, 0x2403
int 0x15
jc a20_ns
test ah, ah
jnz a20_ns
mov ax, 0x2402
int 0x15
jc a20_failed
test ah, ah
jnz a20_failed
test al, al
jnz a20_activated
mov ax, 0x2401
int 0x15
jc a20_failed
test ah, ah
jnz a20_failed
a20_activated:
mov ah, 0x02
mov al, (STAGE2_SIZE + 511) / 512
mov ch, 0
mov dh, 0
mov dl, 0x80
mov cl, 2
mov bx, 0x1000
int 0x13
jmp 0x0:0x1000
a20_ns:
a20_failed:
mov ax, 0xB800
mov ds, ax
mov [0], byte 'L'
jmp $
times 510 - ($ - $$) db 0
dw 0xAA55

337
src/boot/x86/1.asm Normal file
View File

@@ -0,0 +1,337 @@
bits 16
org 0x1000
; This bootloader should get the kernel in a fully running state,
; instead of the kernel initializing itself
;
; It attempts to load a file named "kernel" from the root of an ext2
; partition, and set necessary state by peeking into the kernel's
; exported symbols, e.g. ppm_Bitmap.
;
; See 1_elf.asm and 1_fs.asm.
MBR_PARTITION_TABLE equ 0x7DBE
KERNEL_INITIAL_LOAD equ 0xA000
KERNEL_BASE equ 0x2000
PAGE_PRESENT equ 1
PAGE_RW equ 2
PAGE_GLOBAL equ 256
start:
mov esp, 0x1000
cld
push 0xB800
pop fs
mov bx, 0
.clear_screen:
mov [fs:bx], byte ' '
add bx, 2
cmp bx, 4000
jne .clear_screen
; Get first partition's starting LBA
mov eax, MBR_PARTITION_TABLE
mov ebx, [eax + 0x08]
mov [PARTITION_START], ebx
call ext2_test
jnc .exist
mov eax, msg_partition_not_found
call print_string
jmp $
.exist:
call find_kernel_inode
test eax, eax
jnz .kernel_found
mov eax, msg_kernel_not_found
call print_string
jmp $
.kernel_found:
call load_kernel
jnc .kernel_loaded
mov eax, msg_kernel_fail
call print_string
jmp $
.kernel_loaded:
; Use edi to dynamically allocate anything with an unknown size
; Start allocation immediately after the kernel's image
mov edi, [KERNEL_END]
add edi, 4095
and edi, ~4095
; Create template page directory and page table
; Necessary as the kernel will use this in vpm_create_space
mov eax, 0
mov ecx, 8192
rep stosb
sub edi, 8192
mov dword [edi + 0], edi ; First 4MB of memory will be identity mapped, with the exception of 0 - 0x1000
add dword [edi + 0], 4096 | PAGE_PRESENT | PAGE_RW | PAGE_GLOBAL
mov dword [edi + 4092], edi ; Recursively map last 4MB
add dword [edi + 4092], PAGE_PRESENT | PAGE_RW | PAGE_GLOBAL
mov ecx, 1
mov eax, 4096 | PAGE_PRESENT | PAGE_RW
.identity_map_lup:
mov dword [edi + 4096 + ecx * 4], eax
add eax, 4096
inc ecx
cmp ecx, 1024
jb .identity_map_lup
mov cr3, edi
add edi, 8192
; Get memory map, setup ppm_Bitmap
mov eax, string_ppm_Bitmap
call elf_find_symbol
mov eax, [eax + ELFSym.st_value]
add eax, KERNEL_BASE
mov [eax], edi
xor cx, cx
xor dx, dx
mov ax, 0xE801 ; do not care enough for E820 at the moment
int 0x15
jc short .err
cmp ah, 0x86
je short .err
cmp ah, 0x80
jne short .nerr
.err:
mov eax, msg_memory_fail
call print_string
jmp $
.nerr:
jcxz .useax
mov ax, cx ; amount of mem starting at 1MB, in kB units
mov bx, dx ; amount of mem starting at 16MB, in 64kB units
.useax:
mov [edi], dword 0x100000
mov [edi + 4], dword 0
movzx eax, ax
shr eax, 2 ; divide by 4 to get 4kB (page) units
mov [edi + 8], eax
mov [edi + 12], dword 0
add edi, 16
mov ecx, eax
add ecx, 7
shr ecx, 3 ; ecx = number of bytes belonging to bitmap
mov al, 0
rep stosb
; Save kernel's k_init
mov eax, string_k_init
call elf_find_symbol
test eax, eax
jnz .k_init_found
mov eax, msg_kernel_fail
call print_dword_hex
jmp $
.k_init_found:
mov eax, [eax + ELFSym.st_value]
add eax, KERNEL_BASE
mov [FUNC_k_init], eax
; Up to now, our stack is within 0-0x1000, which will be unmapped in
; protected mode, so lastly, we allocate 8kB for the kernel stack
add edi, 8192 + 15
add edi, ~15
mov esp, edi
; nasm doesn't support arithmetic on labels so we have to
; dynamically compute the TSS segment's base
mov eax, TSS
mov [GDT + 42], ax
shr eax, 16
mov [GDT + 44], al
mov [GDT + 47], ah
; Finally enter protected mode
cli
lgdt [GDT]
mov eax, cr0
or eax, 0x80000001
mov cr0, eax
jmp 0x08:.inPE
bits 32
.inPE:
mov ax, 0x10
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ax, 0x28
ltr ax
mov eax, [FUNC_k_init]
call eax
jmp $
bits 16
; compare C-strings in eax and ebx
; after calling, eax and ebx point to respective null terminators
streq:
push edx
.scanlup:
mov dl, [eax]
cmp dl, [ebx]
jnz .end
test dl, dl
jz .end
cmp byte [ebx], 0
jz .end
inc eax
inc ebx
jmp .scanlup
.end:
pushfd
.inceaxlup:
cmp byte [eax], 0
jz .endier
inc eax
jmp .inceaxlup
.endier:
.incebxlup:
cmp byte [ebx], 0
jz .endierier
inc ebx
jmp .incebxlup
.endierier:
popfd
pop edx
ret
print_char:
push ebx
mov ebx, [.offset]
mov [fs:ebx], al
pop ebx
add [.offset], dword 2
ret
.offset dd 0
print_string:
push ebx
push eax
mov ebx, eax
.lup:
cmp byte [ebx], 0
je .end
movzx eax, byte [ebx]
call print_char
inc ebx
jmp .lup
.end:
pop eax
pop ebx
ret
; in eax = dword to print
print_dword_hex:
pushad
mov ecx, 8
.lup:
rol eax, 4
push eax
and al, 15
cmp al, 10
jb .d
add al, 'A' - '0' - 10
.d:
add al, '0'
call print_char
pop eax
dec ecx
jnz .lup
mov al, 10
call print_char
popad
ret
%include "src/boot/x86/1_elf.asm"
%include "src/boot/x86/1_fs.asm"
DAPACK:
db 0x10
db 0
.blkcnt: dw 0
.db_add: dw READ_LBA_RESULT
dw 0
.d_lba: dd 0
dd 0
GDT:
; Use null descriptor space for gdtr
dw GDT.end - GDT - 1
dd GDT
dw 0
; Kernel code (08)
db 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00
; Kernel data (10)
db 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
; User code (18)
db 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFA, 0xCF, 0x00
; User data (20)
db 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xF2, 0xCF, 0x00
; TSS(filled later) (28)
db 0x07, 0x01, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00
.end:
TSS:
dd 0
TSS.esp0:
dd 0
TSS.ss0:
dd 0
times 96 db 0
elf_DYNSTR_TABLE: dd 0
elf_DYNSYM_TABLE: dd 0
elf_DYNSYMS: dd 0
READ_LBA_RESULT: times 512 db 0
PARTITION_START: dd 0
INODES_PER_GROUP: dd 0
INODE_SIZE: dd 0
KERNEL_END: dd 0
FUNC_k_init: dd 0
string_reldyn: db ".rel.dyn", 0
string_dynstr: db ".dynstr", 0
string_dynsym: db ".dynsym", 0
string_ppm_Bitmap: db "ppm_Bitmap", 0
string_scheduler_spawn: db "scheduler_spawn", 0
string_k_init: db "k_init", 0
msg_partition_not_found: db "Failed to find partition.", 0
msg_kernel_not_found: db "Failed to find kernel.", 0
msg_kernel_fail: db "Failed to load kernel.", 0
msg_memory_fail: db "Failed to determine memory.", 0
; Align to sector size
times (512 - ($ - $$) % 512) % 512 db 0
AFTER_THIS equ $
BLOCK_SCRATCH1 equ AFTER_THIS
ext2_read_inode_bytes_SCRATCH equ (AFTER_THIS + 1024)
ext2_get_inode_data_SCRATCH equ (ext2_read_inode_bytes_SCRATCH + 1024)

279
src/boot/x86/1_elf.asm Normal file
View File

@@ -0,0 +1,279 @@
struc ELFHeader
.e_ident resb 16
.e_type resw 1
.e_machine resw 1
.e_version resd 1
.e_entry resd 1
.e_phoff resd 1
.e_shoff resd 1
.e_flags resd 1
.e_ehsize resw 1
.e_phentsize resw 1
.e_phnum resw 1
.e_shentsize resw 1
.e_shnum resw 1
.e_shstrndx resw 1
endstruc
struc ELFSection
.sh_name resd 1
.sh_type resd 1
.sh_flags resd 1
.sh_addr resd 1
.sh_offset resd 1
.sh_size resd 1
.sh_link resd 1
.sh_info resd 1
.sh_addralign resd 1
.sh_entsize resd 1
endstruc
struc ELFProgram
.p_type resd 1
.p_offset resd 1
.p_vaddr resd 1
.p_paddr resd 1
.p_filesz resd 1
.p_memsz resd 1
.p_flags resd 1
.p_align resd 1
endstruc
struc ELFSym
.st_name resd 1
.st_value resd 1
.st_size resd 1
.st_info resb 1
.st_other resb 1
.st_shndx resw 1
endstruc
; in eax = kernel file inode
load_kernel:
pushad
mov edi, ext2_get_inode_data_SCRATCH
call ext2_get_inode_data
mov esi, ext2_get_inode_data_SCRATCH
mov eax, 0
mov ecx, [ext2_get_inode_data_SCRATCH + 4] ; filesize
mov edi, KERNEL_INITIAL_LOAD
call ext2_read_inode_bytes
cmp dword [KERNEL_INITIAL_LOAD], 0x464C457F ;ELF signature
je .pass_signature
popad
stc
ret
.pass_signature:
; follow the LOAD program header instructions
movzx ecx, word [KERNEL_INITIAL_LOAD + ELFHeader.e_phnum]
movzx ebp, word [KERNEL_INITIAL_LOAD + ELFHeader.e_phentsize]
mov eax, KERNEL_INITIAL_LOAD
add eax, [eax + ELFHeader.e_phoff]
.lup0:
cmp dword [eax + ELFProgram.p_type], 1 ; PT_LOAD
jne .skip0
pushad
mov esi, [eax + ELFProgram.p_offset]
mov ecx, [eax + ELFProgram.p_memsz]
add ecx, esi
add ecx, 4095
and ecx, ~4095
and esi, ~4095
sub ecx, esi
add esi, KERNEL_INITIAL_LOAD
mov edi, [eax + ELFProgram.p_vaddr]
and edi, ~4095
add edi, KERNEL_BASE
test ecx, ecx
jz .skipcopy
rep movsb
.skipcopy:
mov edi, [eax + ELFProgram.p_vaddr]
add edi, KERNEL_BASE
add edi, [eax + ELFProgram.p_filesz]
mov ecx, [eax + ELFProgram.p_memsz]
sub ecx, [eax + ELFProgram.p_filesz]
test ecx, ecx
jz .skipbss
mov eax, 0
rep stosb
.skipbss:
cmp edi, [KERNEL_END]
jbe .maxkernelend
mov [KERNEL_END], edi
.maxkernelend:
popad
.skip0:
add eax, ebp
dec ecx
jnz .lup0
; fix up the relocations
mov esi, KERNEL_INITIAL_LOAD
mov eax, string_reldyn
call elf_find_array_section_by_name
.lup2:
mov ebx, [eax]
add dword [KERNEL_BASE + ebx], KERNEL_BASE
add eax, ebp
dec ecx
jnz .lup2
; Save .dynstr for elf_find_symbol to use
mov esi, KERNEL_INITIAL_LOAD
mov eax, string_dynstr
call elf_find_array_section_by_name
mov [elf_DYNSTR_TABLE], eax
; Save .dynsym for elf_find_symbol to use
mov esi, KERNEL_INITIAL_LOAD
mov eax, string_dynsym
call elf_find_array_section_by_name
mov [elf_DYNSYM_TABLE], eax
mov [elf_DYNSYMS], ecx
popad
clc
ret
; in esi = ptr to elf file
; in eax = section name ptr
; out eax = ptr to section data (or 0)
; out ebp = section entry size
; out ecx = section entry count
elf_find_array_section_by_name:
push ebx
push edx
; ebx = section name ptr
mov ebx, eax
; ebp = section table entry size
movzx ebp, word [esi + ELFHeader.e_shentsize]
movzx eax, word [esi + ELFHeader.e_shstrndx]
mul ebp
; edx = section table
mov edx, [esi + ELFHeader.e_shoff]
add edx, esi
; eax = string table
add eax, edx
mov eax, [eax + ELFSection.sh_offset]
add eax, esi
; ecx = section index counter
mov ecx, 0
.lup:
push eax
push ebx
add eax, [edx + ELFSection.sh_name]
call streq
pop ebx
pop eax
je .found
add edx, ebp
inc ecx
cmp cx, word [esi + ELFHeader.e_shnum]
jb .lup
mov eax, 0
jmp .notfound
.found:
; eax = section header
mov eax, ecx
mul ebp
add eax, [esi + ELFHeader.e_shoff]
add eax, esi
; ebp = section entry size
mov ebp, [eax + ELFSection.sh_entsize]
; ecx = entry count
mov ecx, 0
test ebp, ebp
jz .zeroentitysize
push eax
mov eax, [eax + ELFSection.sh_size]
mov edx, 0
div ebp
mov ecx, eax
pop eax
.zeroentitysize:
mov eax, [eax + ELFSection.sh_offset]
add eax, esi
.notfound:
pop edx
pop ebx
ret
elf_find_symbol:
cmp dword [elf_DYNSTR_TABLE], 0
jnz .inited1
; table not loaded
ret
.inited1:
cmp dword [elf_DYNSYM_TABLE], 0
jnz .inited2
; table not loaded
ret
.inited2:
push edx
push ecx
push ebx
mov edx, [elf_DYNSYM_TABLE]
mov ecx, 0
.lup:
mov ebx, [elf_DYNSTR_TABLE]
add ebx, [edx + ELFSym.st_name]
push eax
call streq
pop eax
je .found
add edx, 16 ; symbol size
inc ecx
cmp ecx, [elf_DYNSYMS]
jne .lup
; symbol not found
mov edx, 0
.found:
mov eax, edx
pop ebx
pop ecx
pop edx
ret

248
src/boot/x86/1_fs.asm Normal file
View File

@@ -0,0 +1,248 @@
; Only searches first block of root directory
find_kernel_inode:
push edi
push esi
push ecx
mov eax, 2
mov edi, ext2_get_inode_data_SCRATCH
call ext2_get_inode_data
mov esi, ext2_get_inode_data_SCRATCH
mov eax, 0
mov edi, BLOCK_SCRATCH1
call ext2_read_inode_block
mov eax, 0 ; null inode
.lup:
cmp byte [edi + 6], 6 ; length of "kernel"
jne .skip
cmp [edi + 8], dword 'kern'
jne .skip
cmp [edi + 12], word 'el'
jne .skip
mov eax, [edi + 0] ; inode
jmp .end
.skip:
movzx ecx, word [edi + 4] ; record length
add edi, ecx
cmp edi, BLOCK_SCRATCH1 + 1024
jb .lup
.end:
pop ecx
pop esi
pop edi
ret
; in esi = ptr to inode structure
; in eax = start offset byte
; in ecx = number of bytes to read
; in es:edi = pointer to destination
ext2_read_inode_bytes:
pushad
push eax
and eax, 1023
mov [.BLOCK_OFFSET], eax
pop eax
mov [.BYTES_REMAINING], ecx
lea edx, [eax + ecx - 1]
shr edx, 10
shr eax, 10
mov ebp, eax
; ebp = start block
; eax = counter
; edx = end block (inclusive)
.lup:
push edi
mov edi, ext2_read_inode_bytes_SCRATCH
call ext2_read_inode_block
mov esi, edi
mov ecx, 1024
pop edi
cmp eax, ebp
jne .not_start
; dont copy entire block, only what we need
add esi, [.BLOCK_OFFSET]
sub ecx, [.BLOCK_OFFSET]
.not_start:
.copy:
; ensure byte count < remaining
cmp ecx, [.BYTES_REMAINING]
jbe .nomin
mov ecx, [.BYTES_REMAINING]
.nomin:
sub [.BYTES_REMAINING], ecx
rep movsb
inc eax
cmp eax, edx
jbe .lup
popad
ret
.BLOCK_OFFSET dd 0
.BYTES_REMAINING dd 0
; in esi = ptr to inode structure
; in eax = block number
; in es:edi = pointer to destination
ext2_read_inode_block:
pushad
cmp eax, 12
jae .skip
mov eax, [esi + 40 + eax * 4]
shl eax, 10
mov ecx, 1024
call read_absolute_bytes
.skip:
popad
ret
; in eax = inode number
; in es:edi = pointer to destination
ext2_get_inode_data:
pushad
mov edx, 0
dec eax
div dword [INODES_PER_GROUP]
; edx is now inode index in group
; eax is now block group index
call ext2_get_inode_table_index_from_block_group_index
; eax is now inode table block index
shl eax, 10
imul edx, dword [INODE_SIZE]
; edx is now inode offset within block group (bytes)
add eax, edx
mov ecx, [INODE_SIZE]
call read_absolute_bytes
popad
ret
ext2_get_inode_table_index_from_block_group_index:
push eax
mov eax, 4
call read_lba
pop eax
shl eax, 5 ;*32
mov eax, [READ_LBA_RESULT + eax + 8]
ret
ext2_test:
push eax
mov eax, 2
call read_lba
cmp [READ_LBA_RESULT + 56], word 0xEF53 ; ext2 signature
jne .fail
cmp [READ_LBA_RESULT + 24], word 0x0000 ; 1024 bytes per block
jne .fail
.signature_pass:
mov eax, [READ_LBA_RESULT + 40]
mov [INODES_PER_GROUP], eax
movzx eax, word [READ_LBA_RESULT + 88]
mov [INODE_SIZE], eax
pop eax
clc
ret
.fail:
pop eax
stc
ret
; in eax = starting byte
; in ecx = number of bytes to read
; in es:edi = pointer to destination
read_absolute_bytes:
pushad
cmp ecx, 0
jne .not_empty
; nothing to copy
ret
.not_empty:
push eax
and eax, 511
mov [.BLOCK_OFFSET], eax
pop eax
mov [.BYTES_REMAINING], ecx
lea edx, [eax + ecx - 1]
shr edx, 9
shr eax, 9
mov ebp, eax
; ebp = start sector
; eax = counter
; edx = end sector (inclusive)
.lup:
;call print_dword_hex
call read_lba
mov esi, READ_LBA_RESULT
mov ecx, 512
cmp eax, ebp
jne .not_start
; dont copy entire sector, only what we need
add esi, [.BLOCK_OFFSET]
sub ecx, [.BLOCK_OFFSET]
.not_start:
.copy:
; ensure byte count < remaining
cmp ecx, [.BYTES_REMAINING]
jbe .nomin
mov ecx, [.BYTES_REMAINING]
.nomin:
sub [.BYTES_REMAINING], ecx
rep movsb
inc eax
cmp eax, edx
jbe .lup
popad
ret
.BLOCK_OFFSET dd 0
.BYTES_REMAINING dd 0
; in eax = lba number
; out carry = error
read_lba:
push eax
push esi
push edx
add eax, dword [PARTITION_START]
.int:
mov [DAPACK.blkcnt], word 1
mov [DAPACK.d_lba], dword eax
mov si, DAPACK
mov ah, 0x42
mov dl, 0x80
int 0x13
cld
pop edx
pop esi
pop eax
ret
; in eax = lba number
; out carry = error
read_absolute_lba:
push eax
push esi
push edx
jmp read_lba.int

3
src/kernel/log.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
void print(const char *fmt, ...);

17
src/kernel/main.c Normal file
View File

@@ -0,0 +1,17 @@
#include"log.h"
#include<stdint.h>
void k_init() {
uint8_t *ptr = (void*) 0xB8000;
ptr[0] = 'Y';
ptr[2] = 'o';
ptr[4] = ',';
ptr[6] = ' ';
ptr[8] = 'b';
ptr[10] = 'i';
ptr[12] = 't';
ptr[14] = 'c';
ptr[16] = 'h';
ptr[18] = '.';
}

18
src/kernel/ppm.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include<stddef.h>
#include<stdbool.h>
#include<stdint.h>
typedef struct __attribute__((packed)) {
uint64_t start_ptr;
uint64_t page_count;
uint8_t bitmap[];
} PPMBitmap;
extern PPMBitmap *ppm_Bitmap;
size_t ppm_alloc(size_t page_count);
bool ppm_free(size_t start_ptr, size_t page_count);
size_t ppm_page_size();

180
src/kernel/tinyubsan.c Normal file
View File

@@ -0,0 +1,180 @@
#include<stdint.h>
struct tu_source_location
{
const char *file;
uint32_t line;
uint32_t column;
};
struct tu_type_descriptor
{
uint16_t kind;
uint16_t info;
char name[];
};
struct tu_overflow_data
{
struct tu_source_location location;
struct tu_type_descriptor *type;
};
struct tu_shift_out_of_bounds_data
{
struct tu_source_location location;
struct tu_type_descriptor *left_type;
struct tu_type_descriptor *right_type;
};
struct tu_invalid_value_data
{
struct tu_source_location location;
struct tu_type_descriptor *type;
};
struct tu_array_out_of_bounds_data
{
struct tu_source_location location;
struct tu_type_descriptor *array_type;
struct tu_type_descriptor *index_type;
};
struct tu_type_mismatch_v1_data
{
struct tu_source_location location;
struct tu_type_descriptor *type;
unsigned char log_alignment;
unsigned char type_check_kind;
};
struct tu_negative_vla_data
{
struct tu_source_location location;
struct tu_type_descriptor *type;
};
struct tu_nonnull_return_data
{
struct tu_source_location location;
};
struct tu_nonnull_arg_data
{
struct tu_source_location location;
};
struct tu_unreachable_data
{
struct tu_source_location location;
};
struct tu_invalid_builtin_data
{
struct tu_source_location location;
unsigned char kind;
};
void print(const char *fmt, ...);
#ifdef __cplusplus
extern "C"
{
#endif
static void tu_print_location(const char *message, struct tu_source_location loc)
{
print("tinyubsan: %s at file %s, line %d, column %d\n", message, loc.file, loc.line, loc.column);
}
void __ubsan_handle_add_overflow(struct tu_overflow_data *data)
{
tu_print_location("addition overflow", data->location);
}
void __ubsan_handle_sub_overflow(struct tu_overflow_data *data)
{
tu_print_location("subtraction overflow", data->location);
}
void __ubsan_handle_mul_overflow(struct tu_overflow_data *data)
{
tu_print_location("multiplication overflow", data->location);
}
void __ubsan_handle_divrem_overflow(struct tu_overflow_data *data)
{
tu_print_location("division overflow", data->location);
}
void __ubsan_handle_negate_overflow(struct tu_overflow_data *data)
{
tu_print_location("negation overflow", data->location);
}
void __ubsan_handle_pointer_overflow(struct tu_overflow_data *data)
{
tu_print_location("pointer overflow", data->location);
}
void __ubsan_handle_shift_out_of_bounds(struct tu_shift_out_of_bounds_data *data, void *lhs, void *rhs)
{
tu_print_location("shift out of bounds", data->location);
}
void __ubsan_handle_load_invalid_value(struct tu_invalid_value_data *data)
{
tu_print_location("invalid load value", data->location);
}
void __ubsan_handle_out_of_bounds(struct tu_array_out_of_bounds_data *data)
{
tu_print_location("array out of bounds", data->location);
}
void __ubsan_handle_type_mismatch_v1(struct tu_type_mismatch_v1_data *data, uintptr_t ptr)
{
if (!ptr)
{
tu_print_location("use of NULL pointer", data->location);
}
else if (ptr & ((1 << data->log_alignment) - 1))
{
tu_print_location("use of misaligned pointer", data->location);
}
else
{
tu_print_location("no space for object", data->location);
}
}
void __ubsan_handle_vla_bound_not_positive(struct tu_negative_vla_data *data)
{
tu_print_location("variable-length argument is negative", data->location);
}
void __ubsan_handle_nonnull_return(struct tu_nonnull_return_data *data)
{
tu_print_location("non-null return is null", data->location);
}
void __ubsan_handle_nonnull_arg(struct tu_nonnull_arg_data *data)
{
tu_print_location("non-null argument is null", data->location);
}
void __ubsan_handle_builtin_unreachable(struct tu_unreachable_data *data)
{
tu_print_location("unreachable code reached", data->location);
}
void __ubsan_handle_invalid_builtin(struct tu_invalid_builtin_data *data)
{
tu_print_location("invalid builtin", data->location);
}
#ifdef __cplusplus
}
#endif

8
src/kernel/vpm.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include<stddef.h>
#include<stdint.h>
#include<stdbool.h>
uintptr_t vpm_map(uintptr_t cr3, bool kernel, uintptr_t virt, uintptr_t phys, size_t len_bytes);
void vpm_unmap(uintptr_t cr3, uintptr_t virt, size_t len_bytes);

51
src/kernel/x86/log.c Normal file
View File

@@ -0,0 +1,51 @@
#include<log.h>
#include<stdarg.h>
#include<stddef.h>
typedef struct {
char buf[256];
size_t i;
} Ctx;
static void add_char(Ctx *ctx, char c) {
if(ctx->i < sizeof(ctx->buf)) {
ctx->buf[ctx->i++] = c;
}
}
void print(const char *fmt, ...) {
Ctx ctx = {};
va_list args;
va_start(args, fmt);
while(*fmt) {
if(*fmt == '%') {
fmt++;
if(*fmt == 0) {
break;
}
if(*fmt == 's') {
fmt++;
const char *src = va_arg(args, const char*);
while(*src) {
add_char(&ctx, *src);
src++;
}
} else {
fmt++;
}
} else {
add_char(&ctx, *fmt);
fmt++;
}
}
for(size_t i = 0; i < ctx.i; i++) {
asm volatile("outb %%al, $0xE9" :: "a"(ctx.buf[i]):);
}
}

93
src/kernel/x86/ppm.c Normal file
View File

@@ -0,0 +1,93 @@
#include<ppm.h>
PPMBitmap *ppm_Bitmap;
static bool ppmbitmap_page_free(PPMBitmap *bm, size_t pg_idx) {
size_t byte_idx = pg_idx / 8;
int bit_idx = pg_idx % 8;
return (byte_idx >> bit_idx) & 1;
}
static bool ppm_find_free_range(size_t page_count, PPMBitmap **ret_bm, size_t *ret_pg_i) {
if(page_count == 0) {
return false;
}
PPMBitmap *bm = ppm_Bitmap;
while(bm->page_count) {
size_t byte_count = (bm->page_count + 7) / 8;
size_t run = 0;
for(size_t i = 0; i < bm->page_count; i++) {
if(ppmbitmap_page_free(bm, i)) {
run++;
if(run == page_count) {
*ret_bm = bm;
*ret_pg_i = i - run + 1;
return true;
}
} else {
run = 0;
}
}
bm = (void*) ((uintptr_t) bm + sizeof(*bm) + byte_count);
}
return false;
}
size_t ppm_alloc(size_t page_count) {
PPMBitmap *bm;
size_t pg_start;
if(!ppm_find_free_range(page_count, &bm, &pg_start)) {
return 0;
}
for(size_t pg = pg_start; pg < pg_start + page_count; pg++) {
size_t byte_idx = pg / 8;
int bit_idx = pg % 8;
bm->bitmap[byte_idx] |= (1 << bit_idx);
}
return bm->start_ptr + pg_start * ppm_page_size();
}
bool ppm_free(size_t start_ptr, size_t page_count) {
if(start_ptr % ppm_page_size() != 0) {
return false;
}
size_t end_ptr = start_ptr + page_count * ppm_page_size();
PPMBitmap *bm = ppm_Bitmap;
while(bm->page_count) {
if(
(bm->start_ptr <= start_ptr && start_ptr < bm->start_ptr + bm->page_count * ppm_page_size())
&& (bm->start_ptr <= end_ptr && end_ptr < bm->start_ptr + bm->page_count * ppm_page_size())
) {
break;
}
bm = (void*) ((uintptr_t) bm + sizeof(*bm) + (bm->page_count + 7) / 8);
}
if(bm->page_count == 0) {
return false;
}
size_t start_pg = (start_ptr - bm->start_ptr) / ppm_page_size();
for(size_t pg = 0; pg < page_count; pg++) {
size_t byte_idx = (pg + start_pg) / 8;
int bit_idx = (pg + start_pg) % 8;
bm->bitmap[byte_idx] &= ~(1 << bit_idx);
}
return true;
}
size_t ppm_page_size() {
return 4096;
}

23
src/kernel/x86/vpm.c Normal file
View File

@@ -0,0 +1,23 @@
#include"vpm.h"
static void invlpg(uintptr_t ptr) {
// if(INVLPG_SUPPORTED) {
asm volatile("invlpg %0" : : "m"(*(char*) ptr) : "memory");
// } else {
// print("Attempt to invlpg on 386\n");
// }
}
static void *move_4k_window(uintptr_t ptr) {
*(volatile uint32_t*) 0xFFFFFFF8 = ptr | 3;
invlpg(0xFFFFE000);
return (void*) 0xFFFFE000;
}
/*uintptr_t vpm_map(uintptr_t cr3, bool kernel, uintptr_t virt, uintptr_t phys, size_t len_bytes) {
move_window(cr3);
}
void vpm_unmap(uintptr_t cr3, uintptr_t virt, size_t len_bytes) {
}*/