Began rewrite

This commit is contained in:
2025-02-16 16:27:46 +01:00
parent 295e3d9c18
commit 7d41cf45ed
82 changed files with 99 additions and 3028 deletions
-31
View File
@@ -1,31 +0,0 @@
include ../defaults.mk
BIN = ./bin
STAGE1_SRC = ./stage1
STAGE2_SRC = ./stage2
STAGE1_SRCS = $(wildcard $(STAGE1_SRC)/*.s)
STAGE2_SRCS = $(wildcard $(STAGE2_SRC)/*.c)
STAGE2_OBJS = $(patsubst $(STAGE2_SRC)/%.c, $(BIN)/%.o, $(STAGE2_SRCS))
LINKER = $(STAGE2_SRC)/linker.ld
STAGE1 = stage1.bin
STAGE2 = stage2.bin
.PHONY: all clean
all: $(STAGE1) $(STAGE2)
$(STAGE1): $(STAGE1_SRCS)
$(AS) $(ASFLAGS) -fbin -o $@ $(STAGE1_SRC)/bootsect.s
$(STAGE2): $(STAGE2_OBJS)
$(LD) $(LDFLAGS) -T$(LINKER) -o $@ $^
$(BIN)/%.o: $(STAGE2_SRC)/%.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -fr $(BIN) $(STAGE1) $(STAGE2)
-133
View File
@@ -1,133 +0,0 @@
; KBOOT - Kern Bootloader
; Most of the code is taken from Limine (https://github.com/limine-bootloader/limine)
; I tried to add more documentation than the Limine code had, but it's not everything
; Any of my code is pretty bad, so i recommend using an existing bootloader
[org 0x7c00]
[bits 16]
; BPB Requires these
jmp short .bpb_end
nop
; FAT32 Bios Parameter Block
; Some BIOSes mess with it so we just leave it blank
.bpb:
.bpb_oem_id: db "KERN "
.bpb_sector_size: dw 0
.bpb_sects_per_clust: db 0
.bpb_reserved_sects: dw 0
.bpb_fat_count: db 0
.bpb_root_dir_entries: dw 0
.bpb_sector_count: dw 0
.bpb_media_type: db 0
.bpb_sects_per_fat: dw 0
.bpb_sects_per_track: dw 18
.bpb_heads_count: dw 2
.bpb_hidden_sects: dd 0
.bpb_sect_count_big: dd 0
; Extended BPB
.bpb_drive_num: db 0
.bpb_reserved: db 0
.bpb_signature: db 0
.bpb_volume_id: dd 0
.bpb_volume_label: dd "KERN "
.bpb_fs_type: times 8 db 0
.bpb_end:
cli
cld
jmp 0x0000:.init_codeseg ; Long jump to set CS = 0
; Zero out segment regs (Because segmentation is shit)
.init_codeseg:
xor si, si ; We cannot change segment regs directly
mov ds, si ; Data Segment
mov es, si ; Extra Segment
mov ss, si ; Stack Segment
mov sp, 0x7c00 ; Set Stack Pointer
sti
; We probably won't be booting from a floppy, so
; ignore if boot drive is < 0x80 and assume an error
cmp dl, 0x80
jl err.0
; Also anything above 0x8f is "dubious" so we also
; just assume an error
cmp dl, 0x8f
jg err.1
; Check that int 13h extensions are supported
.int13chk:
mov ah, 0x41
mov bx, 0x55aa ; Expects bx to be this magic value
int 0x13 ; Will se CF if unsupported
jc err.2
cmp bx, 0xaa55 ; Also sets bx to this magic
jne err.3
; Load the stage 2 bootloader code to 0x70000
.load_stage2:
mov eax, 1 ; LBA
mov cx, 20 ; Read 20 sectors (we have space for 2048)
; Destination - 0x70000
push 0x7000
pop es
xor bx, bx
call read_sectors
jc err.4 ; Failed to read stage 2
.enable_protected:
; Load GDT Pointer
lgdt [gdtp]
; Set PE (Protected mode Enable) flag
cli
mov eax, cr0
or eax, 1 ; Bit 1 - PE
mov cr0, eax
; Far jump to protected mode
jmp code_seg:vector
%include "stage1/disk.s" ; Disk I/O helper functions
%include "stage1/gdt.s" ; Global Descriptor Table
; Handles an error
err:
; Error codes
.4: inc si ; Failed to read stage2 from disk
.3: inc si ; Int 13h extensions unsupported (BX wasn't magic)
.2: inc si ; Int 13h extensions unsupported (CF was set)
.1: inc si ; Invalid boot drive number (> 0x8f)
.0: ; Invalid boot drive number (< 0x80)
; Common error handler
add si, '0' | (0x4f << 8) ; Store error code number char in SI, white on red
push 0xb800 ; VGA Text mode video memory
pop es ; ES = 0xb800
mov word [es:0], si ; Write character
; Hang
sti
.h: hlt
jmp .h
[bits 32]
; Protected mode entry vector
vector:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
and edx, 0xff ; Still should be boot drive number
; Call stage 2 bootloader
call code_seg:0x70000
; Padding and boot signature
times 510-($-$$) db 0
dw 0xaa55
-26
View File
@@ -1,26 +0,0 @@
; Reads sectors from disk
; eax - LBA
; cx - Sector count
; dl - Drive number
; es:dx - Destination
read_sectors:
pusha
; Fill out Disk Address Packet
mov si, .da_packet
mov word [si], 0x10 ; Packet Size and Unused
mov word [si+2], cx ; Sector count
mov word [si+4], bx ; Dest. offset
mov word [si+6], es ; Dest. segment
mov dword [si+8], eax ; LBA
mov ah, 0x42 ; Extended read
clc ; Clear CF
int 0x13
.done:
popa
ret
; Disk Address Packet
.da_packet: equ 0x8000
-28
View File
@@ -1,28 +0,0 @@
; Global Descriptor Table
gdt:
.null_desc: ; Just zeros, no clue why it even exists
dq 0
.code_desc: ; 32-bit code
dw 0xffff ; Limit (low 16-bits)
dw 0x0000 ; Base (low 16 bits)
db 0x00 ; Base (mid 8 bits)
db 0b10011011 ; Access flags
db 0b11001111 ; Low 4 bits - Granularity, High 4 bits - Limit (high 4 bits)
db 0x00 ; Base (high 8 bits)
.data_desc: ; 32-bit data
dw 0xffff ; Limit (low 16-bits)
dw 0x0000 ; Base (low 16 bits)
db 0x00 ; Base (mid 8 bits)
db 0b10010011 ; Access flags
db 0b11001111 ; Low 4 bits - Granularity, High 4 bits - Limit (high 4 bits)
db 0x00 ; Base (high 8 bits)
.end:
; GDT Pointer
gdtp:
dw gdt.end - gdt - 1 ; Size
dd gdt ; Pointer
; Segments
code_seg: equ gdt.code_desc - gdt
data_seg: equ gdt.data_desc - gdt
-10
View File
@@ -1,10 +0,0 @@
#ifndef _DEFS_H
#define _DEFS_H
#define __packed __attribute__((packed))
#define __naked __attribute__((naked))
#define __section(_sect) __attribute__((section(_sect)))
#define noreturn __attribute__((noreturn))
#define sizeof_array(_a) (sizeof(_a) / sizeof(_a[0]))
#endif
-38
View File
@@ -1,38 +0,0 @@
#include "stdint.h"
#include "port.h"
#include "disk.h"
void readSectors(uint32_t lba, size_t count, void* dst) {
outb(PIO_PORT + 6, ((lba >> 24) & 0x0f) | 0xe0);
outb(PIO_PORT + 2, count);
outb(PIO_PORT + 3, lba & 0xff);
outb(PIO_PORT + 4, (lba >> 8) & 0xff);
outb(PIO_PORT + 5, (lba >> 16) & 0xff);
outb(PIO_PORT + 7, PIO_CMD_READ);
uint16_t* buf = (uint16_t*)dst;
for (size_t i = 0; i < count; i++) {
while (inb(PIO_PORT + 7) & (1 << 7)); // Wait until BSY is cleared
for (size_t j = 0; j < SECTOR_SIZE / 2; j++) *buf++ = inw(PIO_PORT);
for (uint8_t wait = 0; wait < 4; wait++) inb(PIO_ALT_STATUS);
}
}
void writeSectors(uint32_t lba, size_t count, void* src) {
outb(PIO_PORT + 6, ((lba >> 24) & 0x0f) | 0xe0);
outb(PIO_PORT + 2, count);
outb(PIO_PORT + 3, lba & 0xff);
outb(PIO_PORT + 4, (lba >> 8) & 0xff);
outb(PIO_PORT + 5, (lba >> 16) & 0xff);
outb(PIO_PORT + 7, PIO_CMD_WRITE);
uint16_t* buf = (uint16_t*)src;
for (size_t i = 0; i < count; i++) {
while (inb(PIO_PORT + 7) & (1 << 7)); // Wait until BSY is cleared
for (size_t j = 0; j < SECTOR_SIZE / 2; j++) outw(PIO_PORT, *buf++);
for (uint8_t wait = 0; wait < 4; wait++) inb(PIO_ALT_STATUS);
}
}
-37
View File
@@ -1,37 +0,0 @@
#ifndef DISK_H
#define DISK_H
#include "stdint.h"
#include "defs.h"
#define SECTOR_SIZE 512
#define PIO_PORT 0x1f0
#define PIO_ALT_STATUS 0x3f6
#define PIO_MASTER 0xa0
#define PIO_CMD_READ 0x20
#define PIO_CMD_WRITE 0x30
#define PIO_CMD_FLUSH 0 // TODO
#define BOOTABLE 0x80
#define LBA_TO_OFFSET(_a) ((_a) * SECTOR_SIZE)
struct partition {
uint8_t bootable;
uint8_t startCHS[3];
uint8_t type;
uint8_t endCHS[3];
uint32_t startLBA;
uint32_t size;
} __packed;
struct MBR {
uint8_t bootstrap[446];
struct partition partitions[4];
uint16_t signature;
} __packed;
void readSectors(uint32_t lba, size_t count, void* buffer);
void writeSectors(uint32_t lba, size_t count, void* buffer);
#endif
-115
View File
@@ -1,115 +0,0 @@
#include "stdint.h"
#include "fat32.h"
#include "stdio.h"
#include "defs.h"
#include "disk.h"
#include "menu.h"
#include "kbd.h"
noreturn void panic() {
setAttr(0x04);
text(COLS/2, ROWS/2, "[ PANIC ]");
while (1) __asm__ volatile ("cli; hlt");
}
void drawPartitions(struct MBR* mbr, uint8_t sel);
void partitonInfo(struct partition* part);
struct partition* menu(struct MBR* mbr);
__section("entry")
noreturn void main() {
keyboardInit();
struct MBR mbr;
readSectors(0, 1, &mbr);
struct partition* bootpart = menu(&mbr);
setAttr(0x0f);
cls();
showCursor();
if (fat32_init(bootpart) != 0) {
setAttr(0x0c);
printf("Failed to initialize FAT32.");
panic();
}
while (1);
}
struct partition* menu(struct MBR* mbr) {
// Select bootable partition by default
uint8_t selected = 0;
for (size_t i = 0; i < 4; i++) {
if (mbr->partitions[i].bootable != BOOTABLE) continue;
selected = i;
break;
}
// Initial draw
setAttr(0x0f);
cls();
hideCursor();
rect(0, 0, COLS, ROWS);
hline(0, 2, COLS);
setAttr(0x02);
text(COLS / 2, 1, "KBOOT");
drawPartitions(mbr, selected);
partitonInfo(&mbr->partitions[selected]);
while (1) {
// Check for up/down arrow keys or enter
uint8_t scancode = getScancode();
if (scancode == SC_ENTER) { // Boot selected
if (mbr->partitions[selected].type != 0) break;
// Don't allow booting an unused partition
setAttr(0x4f);
text(COLS / 2, ROWS / 2 + 6, "Unused Partition");
} else if (scancode != SC_EXTENDED) continue; // Not an arrow key
scancode = getScancode();
if (scancode == SCE_ARROW_UP) selected--;
else if (scancode == SCE_ARROW_DOWN) selected++;
else continue;
if (selected == 0xff) selected = 3;
else if (selected == 4) selected = 0;
// Redraw
drawPartitions(mbr, selected);
partitonInfo(&mbr->partitions[selected]);
}
return &mbr->partitions[selected];
}
void drawPartitions(struct MBR* mbr, uint8_t sel) {
uint32_t basey = ROWS / 2 - 2;
for (size_t i = 0; i < 4; i++) {
if (i == sel) setAttr(0xf0);
else if (mbr->partitions[i].type == 0) setAttr(0x04);
else setAttr(0x0f);
text(COLS / 2, basey + i, " [ Partition %d ] ", i+1);
}
}
void partitonInfo(struct partition* part) {
uint32_t basey = ROWS / 2 + 6;
setAttr(0x02);
// Clear previous text
fill(1, basey, COLS - 2, 3, '\0');
if (part->type == 0) {
text(COLS / 2, basey, "Unused Partition");
return;
}
text(COLS / 2, basey, "Type: %02x%s", part->type,
(part->bootable == BOOTABLE) ? " Bootable" : "");
text(COLS / 2, basey + 1, "Start LBA: %d; End LBA: %d",
part->startLBA, part->startLBA + part->size);
text(COLS / 2, basey + 2, "Length: 0x%x", part->size);
}
-33
View File
@@ -1,33 +0,0 @@
#include "stdint.h"
#include "string.h"
#include "disk.h"
#include "fat32.h"
// Local context
struct fat32_ctx ctx;
int fat32_init(struct partition* p) {
readSectors(p->startLBA, 1, &ctx.bpb);
ctx.offsetBase = p->startLBA;
if (ctx.bpb.bytesPerSect != SECTOR_SIZE) return 1;
ctx.offsetFats = ctx.offsetBase + ctx.bpb.reservedSects;
ctx.offsetClusts = ctx.offsetFats + ctx.bpb.fatCount * ctx.bpb.sectsPerFat_32;
return 0;
}
int fat32_open(char* filename, int flags, ...) {
// TODO: flags
//struct fat32_traversed res = fat32_traverse(ctx, filename);
//if (!res.dir) return -1;
}
void fat32_close(void* file) {}
int fat32_read(const void* buf, size_t size, size_t count, void* file) {}
-124
View File
@@ -1,124 +0,0 @@
#ifndef _FAT32_H
#define _FAT32_H
#include "stdint.h"
#include "defs.h"
#include "disk.h"
// Macros
#define FAT32_PTR(_p) ((struct fat32_ctx*)(_p))
#define FAT32_DIR_PTR(_p) ((struct fat32_fd*)(_p))
#define FAT32_FULL_CLUST(_hi, _lo) (((uint32_t)(_hi) << 16) | (_lo))
#define FAT32_INODE_GEN(_dir, _i) ((_dir) * 100 + (_i))
// Long File Name (LFN)
#define LFN_MAX 20
#define LFN_MAX_CHARS 256
// Attributes
#define FAT32_ATTR_READ_ONLY (1 << 0)
#define FAT32_ATTR_HIDDEN (1 << 1)
#define FAT32_ATTR_SYSTEM (1 << 2)
#define FAT32_ATTR_VOLUME_ID (1 << 3)
#define FAT32_ATTR_DIRECTORY (1 << 4)
#define FAT32_ATTR_ARCHIVE (1 << 5)
#define FAT32_ATTR_LFN \
(FAT32_ATTR_READ_ONLY | FAT32_ATTR_HIDDEN \
FAT32_ATTR_SYSTEM | FAT32_ATTR_VOLUME_ID)
/* On-disk structures */
// FAT32 Bios Parameter Block & Extended BPB
struct fat32_bpb {
uint8_t bootjmp[3];
char oemName[8];
uint16_t bytesPerSect;
uint8_t sectsPerClust;
uint16_t reservedSects;
uint8_t fatCount;
uint16_t rootEntryCount;
uint16_t totalSects_16;
uint8_t mediaType;
uint16_t sectsPerFat_16;
uint16_t sectsPerTrack;
uint16_t headCount;
uint32_t hiddenSects;
uint32_t sectCount_32;
// Extended
uint32_t sectsPerFat_32;
uint16_t flags;
uint16_t fatVersion;
uint32_t rootClust;
uint16_t fsinfoSect;
uint16_t backupBootsect;
uint8_t _reserved[12];
uint8_t driveNum;
uint8_t winNTFlags;
uint8_t signature;
uint32_t volumeID;
char volumeLabel[11];
char systemID[8];
uint8_t bootcode[420];
uint16_t bootsig;
} __packed;
// FAT32 Directory Entry
struct fat32_dentry {
char name[8];
char ext[3];
uint8_t attr;
uint8_t userattr;
char undelete;
uint16_t createTime;
uint16_t createDate;
uint16_t accessDate;
uint16_t clustHigh;
uint16_t modifyTime;
uint16_t modifyDate;
uint16_t clustLow;
uint32_t size;
} __packed;
// FAT32 Long File Name entry
struct fat32_lfn {
uint8_t order;
uint8_t name1[10];
uint8_t attr;
uint8_t type;
uint8_t checksum;
uint8_t name2[12];
uint16_t zero;
uint8_t name3[4];
} __packed;
/* In memory structures */
struct fat32_ctx {
size_t offsetBase;
size_t offsetFats;
size_t offsetClusts;
struct fat32_bpb bpb;
};
struct fat32_fd {
uint32_t ptr;
uint8_t index;
uint32_t dirStart;
uint32_t dirCurrent;
struct fat32_dentry dentry;
};
// Handlers
int fat32_init(struct partition* p);
int fat32_open(char* filename, int flags, ...); /* We won't use the va_args */
void* fat32_fopen(const char* path, const char* mode);
void fat32_fclose(void* file);
int fat32_fgetc(void* file);
char* fat32_fgets(char* s, size_t n, void* file);
int fat32_fread(const void* buf, size_t size, size_t count, void* file);
int fat32_fseek(void* file, size_t offset, int whence);
long fat32_ftell(void* file);
#endif
-12
View File
@@ -1,12 +0,0 @@
#include "stdint.h"
#include "port.h"
#include "kbd.h"
// TODO: Maybe do some setup?
int keyboardInit() { return 0; }
uint8_t getScancode() {
while ((inb(PS2_STAT_PORT) & 0x01) == 0);
return inb(PS2_DATA_PORT);
}
-19
View File
@@ -1,19 +0,0 @@
#ifndef _KBD_H
#define _KBD_H
#include "stdint.h"
#define PS2_DATA_PORT 0x60
#define PS2_STAT_PORT 0x64
// Scancodes
#define SC_ENTER 0x1C
#define SC_EXTENDED 0xE0
// Extended scancodes
#define SCE_ARROW_UP 0x48
#define SCE_ARROW_DOWN 0x50
int keyboardInit();
uint8_t getScancode();
#endif
-24
View File
@@ -1,24 +0,0 @@
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386)
SECTIONS {
. = 0x70000;
.text : {
*(entry)
*(.text)
}
.rodata : {
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(COMMON)
*(.bss)
}
}
-73
View File
@@ -1,73 +0,0 @@
#include "stdarg.h"
#include "stdint.h"
#include "string.h"
#include "stdio.h"
#include "menu.h"
/*
* The reason we subtract one from the width and height (or length) is because
* we use the (in this example) width to offset from the (in this example) x
* position. If something has a width of 1 character, the end of it should be
* at 'x + w', so if 'w' were 1, it would be off by one. Therefore we subtract
* one from the given dimensions.
*/
void rect(uint32_t x, uint32_t y, uint32_t _w, uint32_t _h) {
if (_w < 2 || _h < 2) return;
uint32_t w = _w - 1;
uint32_t h = _h - 1;
// Top
putat(y, x, CORNER_TL);
for (size_t dx = 1; dx < w; dx++) putat(y, x + dx, LINE_H);
putat(y, x + w, CORNER_TR);
// Sides
for (size_t dy = 1; dy < h; dy++) {
putat(y + dy, x, LINE_V);
putat(y + dy, x + w, LINE_V);
}
// Bottom
putat(y + h, x, CORNER_BL);
for (size_t dx = 1; dx < w; dx++) putat(y + h, x + dx, LINE_H);
putat(y + h, x + w, CORNER_BR);
}
void fill(uint32_t x, uint32_t y, uint32_t w, uint32_t h, char c) {
// We don't add one to the dimensions here
for (size_t dy = 0; dy < h; dy++) {
for (size_t dx = 0; dx < w; dx++) {
putat(y + dy, x + dx, c);
}
}
}
void hline(uint32_t x, uint32_t y, uint32_t _len) {
uint32_t len = _len - 1;
putat(y, x, LINE_T_RIGHT);
for (size_t dx = 1; dx < len; dx++) putat(y, x + dx, LINE_H);
putat(y, x + len, LINE_T_LEFT);
}
void vline(uint32_t x, uint32_t y, uint32_t _len) {
uint32_t len = _len - 1;
putat(y, x, LINE_T_DOWN);
for (size_t dy = 1; dy < len; dy++) putat(y + dy, x, LINE_V);
putat(y + len, x, LINE_T_UP);
}
void text(uint32_t x, uint32_t y, char* fmt, ...) {
va_list args;
va_start(args, fmt);
char buf[256];
vsnprintf(buf, 256, fmt, args);
va_end(args);
uint32_t len = strlen(buf);
uint32_t basex = x - len / 2;
size_t i = 0;
while (buf[i] != '\0') putat(y, basex + i, buf[i++]);
}
-33
View File
@@ -1,33 +0,0 @@
#ifndef _MENU_H
#define _MENU_H
// Box drawing characters
#define SHADE_LIGHT 0xB0
#define SHADE_MEDIUM 0xB1
#define SHADE_DARK 0xB2
#define LINE_V 0xB3
#define LINE_T_LEFT 0xB4
#define CORNER_TR 0xBF
#define CORNER_BL 0xC0
#define LINE_T_UP 0xC1
#define LINE_T_DOWN 0xC2
#define LINE_T_RIGHT 0xC3
#define LINE_H 0xC4
#define LINE_CROSS 0xC5
#define CORNER_BR 0xD9
#define CORNER_TL 0xDA
#define BLOCK 0xDB
#define BLOCK_UPPER 0xDC
#define BLOCK_LEFT 0xDD
#define BLOCK_RIGHT 0xDE
#define BLOCK_LOWER 0xDF
#define INT_UPPER 0xF4
#define INT_LOWER 0xF5
void rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h);
void fill(uint32_t x, uint32_t y, uint32_t w, uint32_t h, char c);
void hline(uint32_t x, uint32_t y, uint32_t len);
void vline(uint32_t x, uint32_t y, uint32_t len);
void text(uint32_t x, uint32_t y, char* fmt, ...);
#endif
-33
View File
@@ -1,33 +0,0 @@
#ifndef PORT_H
#define PORT_H
#include "stdint.h"
inline uint8_t inb(uint16_t port) {
uint8_t result;
__asm__ volatile("inb %1, %0" : "=a"(result) : "Nd"(port));
return result;
}
inline void outb(uint16_t port, uint8_t data) {
__asm__ volatile("outb %0, %1" :: "a"(data), "Nd"(port));
}
inline uint16_t inw(uint16_t port) {
uint16_t result;
__asm__ volatile("inw %1, %0" : "=a"(result) : "Nd"(port));
return result;
}
inline void outw(uint16_t port, uint16_t data) {
__asm__ volatile("outw %0, %1" :: "a"(data), "Nd"(port));
}
inline uint32_t inl(uint16_t port) {
uint32_t result;
__asm__ volatile("inl %1, %0" : "=a"(result) : "Nd"(port));
return result;
}
inline void outl(uint16_t port, uint32_t data) {
__asm__ volatile("outl %0, %1" :: "a"(data), "Nd"(port));
}
#endif
-10
View File
@@ -1,10 +0,0 @@
#ifndef _STDARG_H
#define _STDARG_H
typedef char* va_list;
#define va_start(ap, paramn) (void)((ap) = (char*)(&(paramn) + 1))
#define va_end(ap) (void)((ap) = 0)
#define va_arg(ap, type) (((type*)((ap) = ((ap) + sizeof(type))))[-1])
#endif
-22
View File
@@ -1,22 +0,0 @@
#ifndef _STDINT_H
#define _STDINT_H
#define NULL ((void*)0)
// Naitive size
typedef unsigned int size_t;
typedef signed int ssize_t;
// Signed ints
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
// Unsigned ints
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#endif
-143
View File
@@ -1,143 +0,0 @@
#include "stdarg.h"
#include "stdint.h"
#include "string.h"
#include "stdio.h"
#include "port.h"
static uint32_t xpos;
static uint32_t ypos;
static uint8_t attr;
void setAttr(uint8_t newattr) { attr = newattr; }
void setCursor(uint32_t row, uint32_t col) {
xpos = col;
ypos = row;
updateCursor();
}
void updateCursor() {
uint16_t pos = xpos + ypos * COLS;
outb(0x3d4, 0x0f);
outb(0x3d5, pos & 0xff);
outb(0x3d4, 0x0e);
outb(0x3d5, (pos >> 8) & 0xff);
}
void hideCursor() {
outb(0x3d4, 0x0a);
outb(0x3d5, 0x20);
}
void showCursor() {
uint8_t start = 0;
uint8_t end = 15;
outb(0x3d4, 0x0a);
outb(0x3d5, (inb(0x3d5) & 0xc0) | start);
outb(0x3d4, 0x0b);
outb(0x3d5, (inb(0x3d5) & 0xe0) | end);
}
void cls() {
uint8_t* vidmem = (uint8_t*)VIDMEM;
for (size_t i = 0; i < ROWS * COLS; i++) {
vidmem[i * 2] = 0;
vidmem[i * 2 + 1] = attr;
}
xpos = 0;
ypos = 0;
updateCursor();
}
void putat(uint32_t row, uint32_t col, int c) {
uint8_t* vidmem = (uint8_t*)VIDMEM;
vidmem[(col + row * COLS) * 2] = c & 0xFF;
vidmem[(col + row * COLS) * 2 + 1] = attr;
}
void newline() {
xpos = 0;
ypos++;
if (ypos >= ROWS) ypos = 0;
updateCursor();
}
void putc(int c) {
putat(ypos, xpos, c);
xpos++;
if (xpos >= COLS) newline();
updateCursor();
}
void puts(char* s) {
while (*s != '\0') {
if (*s == '\n' || *s == '\r') {
newline();
s++;
} else putc(*s++);
}
}
int vsnprintf(void* buf, size_t len, char* fmt, va_list args) {
char* str = (char*)buf;
size_t pos = 0;
while (*fmt != '\0') {
if (*fmt != '%') {
if (pos < len - 1) str[pos++] = *fmt++;
continue;
}
fmt++;
char pad = ' ';
int width = 0;
if (*fmt == '0') pad = '0';
while (*fmt >= '0' && *fmt <= '9') {
width *= 10;
width += *fmt++ - '0';
}
// DO NOT TALK ABOUT THIS ABOMINATION
char* s;
switch (*fmt++) {
case 'd': s = itoa(va_arg(args, int), 10); goto string;
case 'x': s = itoa(va_arg(args, int), 16); goto string;
case 's': s = va_arg(args, char*); goto string;
case 'c': if (pos < len - 1) str[pos++] = va_arg(args, char); break;
case '%': if (pos < len - 1) str[pos++] = '%'; break;
default:
if (pos < len - 1) str[pos++] = '%';
if (pos < len - 1) str[pos++] = *(fmt - 1);
break;
string:
width -= strlen(s) - 1;
if (width < 0) width = 0;
while (width-- && pos < len - 1) str[pos++] = pad;
while (*s && pos < len - 1) str[pos++] = *s++;
break;
}
}
if (len > 0) {
if (pos < len) str[pos++] = '\0';
else str[len - 1] = '\0'; // Shouldn't be able to be reached, but who knows
}
return pos;
}
int printf(char* fmt, ...) {
va_list args;
va_start(args, fmt);
char buf[256];
int ret = vsnprintf(buf, 256, fmt, args);
va_end(args);
puts(buf);
return ret;
}
-25
View File
@@ -1,25 +0,0 @@
#ifndef _STDIO_H
#define _STDIO_H
#include "stdarg.h"
#include "stdint.h"
#define VIDMEM 0xb8000
#define COLS 80
#define ROWS 25
void setAttr(uint8_t attr);
void setCursor(uint32_t row, uint32_t col);
void updateCursor();
void hideCursor();
void showCursor();
void cls();
void newline();
void putc(int c);
void puts(char* s);
int printf(char* fmt, ...);
int vsnprintf(void* buf, size_t len, char* fmt, va_list args);
void putat(uint32_t row, uint32_t col, int c);
#endif
-74
View File
@@ -1,74 +0,0 @@
#include "stdint.h"
#include "string.h"
char* itoa(size_t val, int base) {
static char buf[32] = { 0 };
if (base == 0 || base > 16) return NULL;
if (val == 0) {
buf[0] = '0';
buf[1] = '\0';
return buf;
}
int i;
buf[31] = '\0';
for (i = 30; val && i; i--, val /= base) {
buf[i] = "0123456789abcdef"[val % base];
}
return &buf[i + 1];
}
void* memcpy(void* src, void* dst, size_t length) {
uint8_t* p = dst;
size_t i = 0;
while (i < length) p[i] = *(uint8_t*)(src + i);
return dst;
}
void* memset(void* dst, uint8_t val, size_t length) {
uint8_t* p = dst;
size_t i = 0;
while (i < length) p[i++] = val;
return dst;
}
char* strcpy(char* str1, const char* str2) {
char* p = str1;
while (*str2 != '\0') *p++ = *str2++;
return str1;
}
char* strcat(char* str1, const char* str2) {
char* p = str1;
while (*str2++ != '\0');
while (*str2 != '\0') *p++ = *str2++;
return str1;
}
char* strchr(const char* str, char c) {
char* p = (char*)str;
while (*p != '\0' && *p != c) p++;
return (*p == c) ? p : NULL;
}
int strcmp(const char* str1, const char* str2) {
while (*str1 != '\0' && *str1 == *str2) {
str1++;
str2++;
}
uint8_t c1 = (*(uint8_t*)str1);
uint8_t c2 = (*(uint8_t*)str2);
return ((c1 < c2) ? -1 : (c1 > c2));
}
size_t strlen(const char* str) {
size_t len = 0;
while (str[len++] != '\0');
return len;
}
-15
View File
@@ -1,15 +0,0 @@
#ifndef _STRING_H
#define _STRING_H
#include "stdint.h"
char* itoa(size_t val, int base);
void* memcpy(void* src, void* dst, size_t length);
void* memset(void* dst, uint8_t value, size_t length);
char* strcpy(char* str1, const char* str2);
char* strcat(char* str1, const char* str2);
char* strchr(const char* str, char c);
int strcmp(const char* str1, const char* str2);
size_t strlen(const char* str);
#endif
+7 -7
View File
@@ -1,17 +1,17 @@
# Tools
HOSTCC = cc
CC = i686-elf-gcc
LD = i686-elf-ld
CC = cc
LD = ld
AS = nasm
AR = i686-elf-ar
OBJCOPY = i686-elf-objcopy
AR = ar
OBJCOPY = objcopy
MAKE = make
# Flags
HOSTCFLAGS = -Wall -Wextra -Wpedantic -Os -std=c17 -g
CFLAGS = -Wall -Wextra -Wpedantic -Wno-pointer-arith\
HOSTCCFLAGS = -Wall -Wextra -Wpedantic -Os -std=c17
CCFLAGS = -Wall -Wextra -Wpedantic -Wno-pointer-arith\
-ffreestanding -fno-stack-protector -fno-builtin -fno-pie -fcommon\
-O2 -std=c17 -nostdinc -nostdlib -z notext -march=i386 -g
-O2 -std=c17 -nostdinc -nostdlib -z notext -march=i386 -m32
LDFLAGS = -melf_i386
ASFLAGS =
ARFLAGS =
+24
View File
@@ -0,0 +1,24 @@
#ifndef _KERNEL_H
#define _KERNEL_H
/*
* Attribute definitions
*/
#define __align(_b) __attribute__((aligned(_b)))
#define __depricated __attribute__((depricated))
#define __packed __attribute__((packed))
#define __noreturn __attribute__((noreturn))
#define __const __attribute__((const))
#define __pure __attribute__((pure))
#define __inline __attribute__((always_inline))
#define __no_inline __attribute__((never_inline))
#define __section(_s) __attribute__((section(_s)))
#define __cold __attribute__((cold))
#define __hot __attribute__((hot))
#define __naked __attribute__((naked))
/*
* Utility macros
*/
#define sizeof_array(_a) ()
#endif
-22
View File
@@ -1,22 +0,0 @@
#ifndef _STDINT_H
#define _STDINT_H
#define NULL ((void*)0)
// Naitive size
typedef unsigned int size_t;
typedef signed int ssize_t;
// Signed ints
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
// Unsigned ints
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#endif
+9
View File
@@ -0,0 +1,9 @@
#ifndef _TTY_H
#define _TTY_H
int tty_init(void);
int tty_write(char* buf, size_t len);
int tty_putc(char c);
int tty_puts(char* s);
#endif
+13 -34
View File
@@ -1,52 +1,31 @@
OUTPUT_FORMAT(binary)
ENTRY(start)
OUTPUT_FORMAT("elf32-i386")
ENTRY(_start)
SECTIONS {
. = 0x00100000;
kernel_start = .;
/* 1MB is a conventional place for kernels */
. = 1M;
/* Multiboot Header */
.multiboot ALIGN(4K) : {
/* We need the multiboot header in the first 8192 bytes */
.text BLOCK(4K) : ALIGN(4K) {
*(.multiboot)
}
.boot ALIGN(4K) : {
*(.boot)
}
. += 0xC000000;
/* Kernel Code */
.text ALIGN(4) : AT(ADDR(.text) - 0xC000000) {
*(.text)
*(.text.*)
}
/* Read-Only Data */
.rodata ALIGN(4) : AT(ADDR(.rodata) - 0xC000000) {
/* Read-only data */
.rodata BLOCK(4K) : ALIGN(4K) {
*(.rodata)
*(.rodata.*)
}
/* Read/Write Data */
.data ALIGN(4) : AT(ADDR(.data) - 0xC000000) {
/* Initalized r/w data */
.data BLOCK(4K) : ALIGN(4K) {
*(.data)
*(.data.*)
}
/* BSS Section */
.bss ALIGN(4) : AT(ADDR(.bss) - 0xC000000) {
/* Uninitialized r/w data and stack */
.bss BLOCK(4K) : ALIGN(4K) {
*(COMMON)
*(.bss)
*(.bss.*)
}
/* Discarded Sections */
/DISCARD/ : {
*(.note)
*(.note.*)
*(.comment)
}
kernel_end = .;
. = 4M;
}
+10 -13
View File
@@ -1,30 +1,27 @@
include ../defaults.mk
INC = ./include
SRC = ./src
BIN = ./bin
SRCS_C = $(shell find $(SRC) -name '*.c')
SRCS_S = $(shell find $(SRC) -name '*.s')
OBJS = $(patsubst $(SRC)/%.c, $(BIN)/%.o, $(SRCS_C)) \
$(patsubst $(SRC)/%.s, $(BIN)/%.s.o, $(SRCS_S))
INC = ./include
SRCS_C = $(wildcard $(SRC)/*.c)
SRCS_S = $(wildcard $(SRC)/*.s)
OBJS_C = $(patsubst $(SRC)/%.c, $(BIN)/%.o, $(SRCS_C))
OBJS_S = $(patsubst $(SRC)/%.s, $(BIN)/%.o, $(SRCS_S))
OUT = ./kernel.elf
LINKER = ./linker.ld
OUT = ./kern.bin
.PHONY: all clean
all: $(OUT)
$(OUT): $(OBJS)
$(OUT): $(OBJS_C) $(OBJS_S)
$(LD) $(LDFLAGS) -T$(LINKER) -o $@ $^
$(BIN)/%.o: $(SRC)/%.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -I$(INC) -c -o $@ $<
$(CC) $(CCFLAGS) -I$(INC) -c -o $@ $^
$(BIN)/%.s.o: $(SRC)/%.s
$(BIN)/%.o: $(SRC)/%.s
@mkdir -p $(dir $@)
$(AS) $(ASFLAGS) -felf32 -o $@ $<
$(AS) $(ASFLAGS) -felf32 -o $@ $^
clean:
rm -fr $(BIN) $(OUT)
+26 -94
View File
@@ -1,108 +1,40 @@
;
; Kernel entry point
;
MBH_MAGIC equ 0xe85250d6
MBH_ARCH equ 0x00000000
STACK_SIZE equ 4096
global VIRT_BASE
KERN_VIRT_BASE equ 0xC000000
KERN_PAGE_NUM equ (KERN_VIRT_BASE >> 22)
bits 32
; Multiboot2 Header
; Flag bits
%define ALIGN 1<<0
%define MEMINFO 1<<1
; Field values
%define MAGIC 0x1BADB002
%define FLAGS (ALIGN | MEMINFO)
%define CHECK -(MAGIC + FLAGS)
; Multiboot 1 header
section .multiboot
align 64
mbh:
; Magic fields
.magic: dd MBH_MAGIC
.arch: dd MBH_ARCH
.size: dd (mbh.end - mbh)
.checksum: dd 0x10000000 - (MBH_MAGIC + MBH_ARCH + (mbh.end - mbh))
align 4
multiboot:
dd MAGIC
dd FLAGS
dd CHECK
; Framebuffer Tag
align 8
dw 5 ; Type - Framebuffer
dw 1 ; Flags - Optional
dd 20 ; Size
dd 1920 ; Width
dd 1080 ; Height
dd 32 ; Depth
; Zero Tag
align 8
dw 0 ; Type - Zero
dw 0 ; Flags
dd 8 ; Size
.end:
; Stack
; Initialize stack
section .bss
align 16
stack_bottom:
resb 16384*8
resb 16384 ; 16kB
stack_top:
; Entry section
section .boot
global start
extern kmain
start:
; Init temporary paging
mov eax, (initpd - 0xC0000000)
mov cr3, eax
mov ecx, cr4
or ecx, 0x10 ; Paging enable bit
mov cr4, ecx
mov ecx, cr0
or ecx, 0x8000000
mov cr0, ecx
jmp higher_half
Shutdown:
mov ax, 0x1000
mov ss, ax
mov sp, 0xf000
mov ax, 0x5307
mov bx, 0x0001
mov cx, 0x0003
int 0x15
; Entry point
section .text
higher_half:
mov esp, stack_top ; Stack Pointer
global _start
extern kmain
_start:
mov esp, stack_top
add ebx, KERN_VIRT_BASE ; Make address in EBX virtual
push ebx ; Push multiboot mem info pointer
call kmain ; Call kernel main
call kmain
; Halt on return
; Hang if kernel returns
cli
h: hlt
jmp h
section .data
; Inital Page Directory
align 4096
global initpd
initpd:
dd 0b10000011 ; Initial 4MB identity map
times 768-1 dd 0 ; Padding
; Higher half kernel start, map 16MB
dd (0 << 22) | 0b10000011
dd (1 << 22) | 0b10000011
dd (2 << 22) | 0b10000011
dd (3 << 22) | 0b10000011
times 256-4 dd 0 ; More padding
.hlt: hlt
jmp .hlt
+6 -2
View File
@@ -1,4 +1,8 @@
#include <stdint.h>
#include <kernel.h>
void kmain(uint32_t addr) {}
__noreturn
void kmain(void) {
*(char*)0xb8000 = 'a';
while (1) __asm__ volatile ("movl $69, %eax");
}
-115
View File
@@ -1,115 +0,0 @@
#include <ctype.h>
const unsigned char _CTYPE_TABLE[256] = {
// Control characters (ASCII 0-31)
_CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, // 0-7
_CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, // 8-15
_CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, // 16-23
_CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, _CNTRL_MASK, // 24-31
// Space (ASCII 32)
_SPACE_MASK | _PRINT_MASK,
// Punctuation (ASCII 33-47)
_PUNCT_MASK | _PRINT_MASK, // '!' (ASCII 33)
_PUNCT_MASK | _PRINT_MASK, // '"' (ASCII 34)
_PUNCT_MASK | _PRINT_MASK, // '#' (ASCII 35)
_PUNCT_MASK | _PRINT_MASK, // '$' (ASCII 36)
_PUNCT_MASK | _PRINT_MASK, // '%' (ASCII 37)
_PUNCT_MASK | _PRINT_MASK, // '&' (ASCII 38)
_PUNCT_MASK | _PRINT_MASK, // '\'' (ASCII 39)
_PUNCT_MASK | _PRINT_MASK, // '(' (ASCII 40)
_PUNCT_MASK | _PRINT_MASK, // ')' (ASCII 41)
_PUNCT_MASK | _PRINT_MASK, // '*' (ASCII 42)
_PUNCT_MASK | _PRINT_MASK, // '+' (ASCII 43)
_PUNCT_MASK | _PRINT_MASK, // ',' (ASCII 44)
_PUNCT_MASK | _PRINT_MASK, // '-' (ASCII 45)
_PUNCT_MASK | _PRINT_MASK, // '.' (ASCII 46)
_PUNCT_MASK | _PRINT_MASK, // '/' (ASCII 47)
// Digits (ASCII 48-57)
_DIGIT_MASK | _PRINT_MASK, // '0' (ASCII 48)
_DIGIT_MASK | _PRINT_MASK, // '1' (ASCII 49)
_DIGIT_MASK | _PRINT_MASK, // '2' (ASCII 50)
_DIGIT_MASK | _PRINT_MASK, // '3' (ASCII 51)
_DIGIT_MASK | _PRINT_MASK, // '4' (ASCII 52)
_DIGIT_MASK | _PRINT_MASK, // '5' (ASCII 53)
_DIGIT_MASK | _PRINT_MASK, // '6' (ASCII 54)
_DIGIT_MASK | _PRINT_MASK, // '7' (ASCII 55)
_DIGIT_MASK | _PRINT_MASK, // '8' (ASCII 56)
_DIGIT_MASK | _PRINT_MASK, // '9' (ASCII 57)
// Punctuation (ASCII 58-64)
_PUNCT_MASK | _PRINT_MASK, // ':' (ASCII 58)
_PUNCT_MASK | _PRINT_MASK, // ';' (ASCII 59)
_PUNCT_MASK | _PRINT_MASK, // '<' (ASCII 60)
_PUNCT_MASK | _PRINT_MASK, // '=' (ASCII 61)
_PUNCT_MASK | _PRINT_MASK, // '>' (ASCII 62)
_PUNCT_MASK | _PRINT_MASK, // '?' (ASCII 63)
_PUNCT_MASK | _PRINT_MASK, // '@' (ASCII 64)
// Upperchase letters (ASCII 65-90)
_ALPHA_MASK | _PRINT_MASK, // 'A' (ASCII 65)
_ALPHA_MASK | _PRINT_MASK, // 'B' (ASCII 66)
_ALPHA_MASK | _PRINT_MASK, // 'C' (ASCII 67)
_ALPHA_MASK | _PRINT_MASK, // 'D' (ASCII 68)
_ALPHA_MASK | _PRINT_MASK, // 'E' (ASCII 69)
_ALPHA_MASK | _PRINT_MASK, // 'F' (ASCII 70)
_ALPHA_MASK | _PRINT_MASK, // 'G' (ASCII 71)
_ALPHA_MASK | _PRINT_MASK, // 'H' (ASCII 72)
_ALPHA_MASK | _PRINT_MASK, // 'I' (ASCII 73)
_ALPHA_MASK | _PRINT_MASK, // 'J' (ASCII 74)
_ALPHA_MASK | _PRINT_MASK, // 'K' (ASCII 75)
_ALPHA_MASK | _PRINT_MASK, // 'L' (ASCII 76)
_ALPHA_MASK | _PRINT_MASK, // 'M' (ASCII 77)
_ALPHA_MASK | _PRINT_MASK, // 'N' (ASCII 78)
_ALPHA_MASK | _PRINT_MASK, // 'O' (ASCII 79)
_ALPHA_MASK | _PRINT_MASK, // 'P' (ASCII 80)
_ALPHA_MASK | _PRINT_MASK, // 'Q' (ASCII 81)
_ALPHA_MASK | _PRINT_MASK, // 'R' (ASCII 82)
_ALPHA_MASK | _PRINT_MASK, // 'S' (ASCII 83)
_ALPHA_MASK | _PRINT_MASK, // 'T' (ASCII 84)
_ALPHA_MASK | _PRINT_MASK, // 'U' (ASCII 85)
_ALPHA_MASK | _PRINT_MASK, // 'V' (ASCII 86)
_ALPHA_MASK | _PRINT_MASK, // 'W' (ASCII 87)
_ALPHA_MASK | _PRINT_MASK, // 'X' (ASCII 88)
_ALPHA_MASK | _PRINT_MASK, // 'Y' (ASCII 89)
_ALPHA_MASK | _PRINT_MASK, // 'Z' (ASCII 90)
// Punctuation (ASCII 91-96)
_PUNCT_MASK | _PRINT_MASK, // '[' (ASCII 91)
_PUNCT_MASK | _PRINT_MASK, // '\' (ASCII 92)
_PUNCT_MASK | _PRINT_MASK, // ']' (ASCII 93)
_PUNCT_MASK | _PRINT_MASK, // '^' (ASCII 94)
_PUNCT_MASK | _PRINT_MASK, // '_' (ASCII 95)
_PUNCT_MASK | _PRINT_MASK, // '`' (ASCII 96)
// Lowercase letters (ASCII 97-122)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'a' (ASCII 97)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'b' (ASCII 98)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'c' (ASCII 99)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'd' (ASCII 100)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'e' (ASCII 101)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'f' (ASCII 102)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'g' (ASCII 103)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'h' (ASCII 104)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'i' (ASCII 105)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'j' (ASCII 106)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'k' (ASCII 107)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'l' (ASCII 108)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'm' (ASCII 109)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'n' (ASCII 110)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'o' (ASCII 111)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'p' (ASCII 112)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'q' (ASCII 113)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'r' (ASCII 114)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 's' (ASCII 115)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 't' (ASCII 116)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'u' (ASCII 117)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'v' (ASCII 118)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'w' (ASCII 119)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'x' (ASCII 120)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'y' (ASCII 121)
_ALPHA_MASK | _LOWER_MASK | _PRINT_MASK, // 'z' (ASCII 122)
// Punctuation (ASCII 123-126
_PUNCT_MASK | _PRINT_MASK, // '{' (ASCII 123)
_PUNCT_MASK | _PRINT_MASK, // '|' (ASCII 124)
_PUNCT_MASK | _PRINT_MASK, // '}' (ASCII 125)
_PUNCT_MASK | _PRINT_MASK, // '~' (ASCII 126)
// Control character (ASCII 127)
_CNTRL_MASK // DEL (ASCII 127)
};
-4
View File
@@ -1,4 +0,0 @@
#include <errno.h>
int errno = 0;
-8
View File
@@ -1,8 +0,0 @@
#ifndef _ASSERT_H
#define _ASSERT_H
// TODO:
#define assert(_ignore) ((void)0)
#endif
-51
View File
@@ -1,51 +0,0 @@
#ifndef _CTYPE_H
#define _CTYPE_H
/*
* Bitfield values
*
* Property | Bit
* ------------|-----
* Digit | 0
* Letter | 1
* Lowercase | 2
* Punct | 3
* Space | 4
* Control | 5
* Printable | 6
* Hex digit | 7
*/
#define _DIGIT_MASK (1<<0)
#define _ALPHA_MASK (1<<1)
#define _LOWER_MASK (1<<2)
#define _PUNCT_MASK (1<<3)
#define _SPACE_MASK (1<<4)
#define _CNTRL_MASK (1<<5)
#define _PRINT_MASK (1<<6)
#define _HEXDG_MASK (1<<7)
// A table for the ASCII character set
extern const unsigned char _CTYPE_TABLE[256];
// Just a macro to make this easier
#define _CTYPE_CHECK(_c, _mask) (_CTYPE_TABLE[(unsigned char)(_c)] & (_mask))
#define isalnum(_c) (isalpha((_c)) || isdigit((_c))
#define isalpha(_c) _CTYPE_CHECK((_c), _ALPHA_MASK)
#define islower(_c) _CTYPE_CHECK((_c), _LOWER_MASK)
#define isupper(_c) (!islower((_c)) && isalpha((_c)))
#define isdigit(_c) _CTYPE_CHECK((_c), _DIGIT_MASK)
#define iscntrl(_c) _CTYPE_CHECK((_c), _CNTRL_MASK)
#define isgraph(_c) (!isblank((_c)))
#define isspace(_c) _CTYPE_CHECK((_c), _SPACE_MASK)
#define isblank(_c) (iscntrl((_c)) || isspace((_c)))
#define isprint(_c) _CTYPE_CHECK((_c), _PRINT_MASK)
#define ispunct(_c) _CTYPE_CHECK((_c), _PUNCT_MASK)
// Why is this one's name longer :((
#define isxdigit(_c) _CTYPE_CHECK((_c), _HEXDG_MASK);
// TODO:
// tolower()
// toupper()
#endif
-46
View File
@@ -1,46 +0,0 @@
#ifndef _ERRNO_H
#define _ERRNO_H
// Basic POSIX defined error idk
enum {
EPERM = 1, // Operation not permitted
ENOENT, // No such file or directory
ESRCH, // No such process
EINTR, // Interrupted system call
EIO, // I/O error
ENXIO, // No such device or address
E2BIG, // Argument list too long
ENOEXEC, // Exec format error
EBADF, // Bad file descriptor
ECHILD, // No child processes
EAGAIN, // Resource temporarily unavailable
ENOMEM, // Out of memory
EACCES, // Permission denied
EFAULT, // Bad address
EBUSY, // Device or resource busy
EEXIST, // File exists
ENOTDIR, // Not a directory
EISDIR, // Is a directory
EIMPL, // TODO: Implementation defined
ENOMSG, // No message of desired type
EINVAL, // Invalid argument
ENFILE, // File table overflow
EMFILE, // Too many open files
ENOTTY, // Not a typewriter
ETXTBSY, // Text file busy
EFBIG, // File too large
ENOSPC, // No space left on device
ESPIPE, // Illegal seek
EROFS, // Read-only file system
EMLINK, // Too many links
EPIPE, // Broken pipe
EDQUOT, // Disk quota exceeded
EDOM, // Function arg domain error
ERANGE, // Out of range
// TODO: more
EILSEQ = 42,// Invalid byte seqence
};
extern int errno;
#endif
-23
View File
@@ -1,23 +0,0 @@
#ifndef _FCNTL_H
#define _FCNTL_H
/* Standard file decriptors */
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
/* File access modes */
#define O_CREAT 0x0001 // Create if does not exist
#define O_RDONLY 0x0002 // Read only
#define O_WRONLY 0x0004 // Write only
#define O_RDWR 0x0008 // Read and write
#define O_APPEND 0x0010 // Always writes at the end (appends)
#define O_TRUNC 0x0020 // Truncate file size and position to 0 on Open
#define O_EXCL 0x0040 // Error if file exists (with O_CREAT)
#define O_BIN 0x0080 // Read bytes, not text
#define O_DIRECTORY 0x0100 // Error if file is not a directory
// TODO: more!
/* TODO: File lock */
#endif
-33
View File
@@ -1,33 +0,0 @@
#ifndef _FLOAT_H
#define _FLOAT_H
#define FLT_DIG 6 // Float precision: 6 decimal digits
#define DBL_DIG 15 // Double precision: 15 decimal digits
#define LDBL_DIG 18 // Long double precision: 18 decimal digits
#define FLT_MAX 3.40282347e+38F // Maximum float value
#define DBL_MAX 1.7976931348623157e+308 // Maximum double value
#define LDBL_MAX 1.189731495357231765e+4932L // Max long double
#define FLT_MIN 1.17549435e-38F // Minimum positive normalized float
#define DBL_MIN 2.2250738585072014e-308 // Min positive double
#define LDBL_MIN 3.36210314311209350626e-4932L // Min positive long double
#define FLT_EPSILON 1.19209290e-7F // Smallest float increment
#define DBL_EPSILON 2.2204460492503131e-16 // Smallest double increment
#define LDBL_EPSILON 1.08420217248550443401e-19L // Smallest long double increment
#define FLT_MAX_EXP 128 // Max exponent for float
#define DBL_MAX_EXP 1024 // Max exponent for double
#define LDBL_MAX_EXP 16384 // Max exponent for long double
#define FLT_MIN_EXP -125 // Min exponent for float
#define DBL_MIN_EXP -1021 // Min exponent for double
#define LDBL_MIN_EXP -16381 // Min exponent for long double
#define FLT_RADIX 2 // Floating-point base (usually 2)
#define FLT_MANT_DIG 24 // Number of digits in float mantissa
#define DBL_MANT_DIG 53 // Number of digits in double mantissa
#define LDBL_MANT_DIG 64 // Number of digits in long double mantissa
#endif
-29
View File
@@ -1,29 +0,0 @@
#ifndef _LIMITS_H
#define _LIMITS_H
// Chars are spectial :)
#define CHAR_BIT 8
#define CHAR_MIN 0
// Signed min
#define SCHAR_MIN -127
#define SHRT_MIN -32768
#define INT_MIN -2147483648
#define LONG_MIN -2147483648L
#define LLONG_MIN -9223372036854775808LL
// Signed max
#define SCHAR_MAX 127
#define SHRT_MAX 32767
#define INT_MAX 2147483647
#define LONG_MAX 2147483647L
#define LLONG_MAX 9223372036854775807LL
// Unsigned max
#define CHAR_MAX 255
#define USHRT_MAX 65535
#define UINT_MAX 4294967295U
#define ULONG_MAX 4294967295UL
#define ULLONG_MAX 18446744073709551615ULL
#endif
-69
View File
@@ -1,69 +0,0 @@
#ifndef _MATH_H
#define _MATH_H
// Constants
#define M_E 2.71828182845904523536 // e
#define M_LOG2E 1.44269504088896340736 // log_2 e
#define M_LOG10E 0.43429448190325182765 // log_10 e
#define M_LN2 0.69314718055994530941 // ln(2)
#define M_LN10 2.30258509299404568402 // ln(10)
#define M_PI 3.14159265358979323846 // pi
#define M_PI_2 1.57079632679489661923 // pi/2
#define M_PI_4 0.78539816339744830961 // pi/4
#define M_1_PI 0.31830988618379067153 // 1/pi
#define M_2_PI 0.63661977236758134307 // 2/pi
#define M_SQRT2 1.41421356237309504880 // sqrt(2)
#define M_SQRT1_2 0.70710678118654752440 // 1/sqrt(2)
// TODO:
#define NAN (__builtin_inff())
#define INFINITY (__builtin_nanf(""))
// Absolute value
int abs(int n);
double fabs(double n);
// Exponential & logarithmic
double exp(double x);
double exp2(double x);
double log(double x);
double log2(double x);
double log10(double x);
double logn(double x, double n);
// Power
double sqrt(double x);
double cbrt(double x);
double hypot(double x, double y);
double pow(double base, double expn);
// Trigonometric
double sin(double x);
double cos(double x);
double tan(double x);
double asin(double x);
double acos(double x);
double atan(double x);
double atan2(double y, double x);
// Hyperbolic
double sinh(double x);
double cosh(double x);
double tanh(double x);
// Rounding & remainder
double floor(double x);
double ceil(double x);
double round(double x);
double trunc(double x);
double fmod(double x, double y);
double modf(double x, double* iptr);
// Error handling
double nan(const char* tagp);
double inf();
int isfinite(double x);
int isinf(double x);
int isnan(double x);
#endif
-13
View File
@@ -1,13 +0,0 @@
#ifndef _SETJMP_H
#define _SETJMP_H
typedef struct {
void* _bp; // Base pointer
void* _sp; // Stack pointer
void* _pc; // Program counter
} jmp_buf;
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int value);
#endif
-10
View File
@@ -1,10 +0,0 @@
#ifndef _STDARG_H
#define _STDARG_H
typedef char* va_list;
#define va_start(ap, paramn) (void)((ap) = (char*)(&(paramn) + 1))
#define va_end(ap) (void)((ap) = 0)
#define va_arg(ap, type) (((type*)((ap) = ((ap) + sizeof(type))))[-1])
#endif
-8
View File
@@ -1,8 +0,0 @@
#ifndef _BOOL_H
#define _BOOL_H
#define bool _Bool
#define true 1
#define false 0
#endif
-9
View File
@@ -1,9 +0,0 @@
#ifndef _STDDEF_H
#define _STDDEF_H
#define NULL ((void*)0)
typedef unsigned int size_t;
typedef signed int ssize_t;
#endif
-18
View File
@@ -1,18 +0,0 @@
#ifndef _STDINT_H
#define _STDINT_H
#include <stddef.h>
// Signed ints
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
// Unsigned ints
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#endif
-84
View File
@@ -1,84 +0,0 @@
#ifndef _STDIO_H
#define _STDIO_H
#include <stddef.h>
#include <stdarg.h>
// End Of File
#define EOF (-1)
// File related macros
#define BUFSIZ 512
#define FILENAME_MAX 255
#define FOPEN_MAX 32
// Seek positions
#define SEEK_CUR 0
#define SEEK_END 1
#define SEEK_SET 2
/* The FILE struct */
typedef struct _iobuf { // 24B
unsigned char* _ptr; // File buffer base
unsigned int _size; // Size of buffer
int _offset; // Offset into file
unsigned short _flag; // Open flags
int _file; // File descriptor
char __reserved[6];
} FILE;
// Standard file pointers
extern FILE* stdin;
extern FILE* stdout;
extern FILE* stderr;
/* File operations */
FILE* fopen(const char* path, const char* mode);
int fclose(FILE* stream);
size_t fread(void* ptr, size_t size, size_t count, FILE* stream);
size_t fwrite(void* ptr, size_t size, size_t count, FILE* stream);
int fseek(FILE* stream, long offset, int whence);
long ftell(FILE* stream);
void rewind(FILE* stream);
int fflush(FILE* stream);
/* Character I/O */
int getchar(void);
int putchar(int c);
int getc(FILE* stream);
int putc(int c, FILE* stream);
int ungetc(int c, FILE* stream);
/* Line I/O */
char* fgets(char* str, int n, FILE* stream);
int fputs(const char* str, FILE* stream);
char* gets(char* str, int n);
int puts(const char* str);
/* TODO: Error handling
void perror(const char* s);
int feof(FILE* stream);
int ferror(FILE* stream);
void clearerr(FILE* stream);
*/
/* Formatted I/O */
int printf(const char* fmt, ...);
int vprintf(const char* fmt, va_list va);
int fprintf(FILE* stream, const char* fmt, ...);
int vfprintf(FILE* stream, const char* fmt, va_list va);
// NOTE: (v)sprinf() Has been depricated and removed as it is unsafe (potencial buffer overflow). Please use (v)snprintf()
int snprintf(char* str, size_t size, const char* fmt, ...);
int vsnprintf(char* str, size_t size, const char* fmt, va_list va);
int pprintf(void (*outfn)(char c, void* arg), void* arg, const char* fmt, ...);
int vpprintf(void (*outfn)(char c, void* arg), void* arg, const char* fmt, va_list va);
int scanf(const char* fmt, ...);
int vscanf(const char* fmt, va_list va);
int fscanf(FILE* stream, const char* fmt, ...);
int vfscanf(FILE* stream, const char* fmt, va_list va);
int sscanf(const char* str, const char* fmt, ...);
int vsscanf(const char* str, const char* fmt, va_list va);
#endif
-30
View File
@@ -1,30 +0,0 @@
#ifndef _STDLIB_H
#define _STDLIB_H
#include <stddef.h>
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#define RAND_MAX 0x7FFFFFF
/* Memory allocation */
void* malloc(size_t size);
void* calloc(size_t count, size_t size);
void* realloc(void* ptr, size_t size);
void free(void* ptr);
/* Process controll */
void _Exit(int status);
void exit(int status);
// TODO: move atoi() here
/* Random number generator */
int rand(void);
void srand(unsigned int seed);
/* Sort & search */
void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
void* bsearch(const void* key, const void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
#endif
-29
View File
@@ -1,29 +0,0 @@
#ifndef _STRING_H
#define _STRING_H
#include <stdint.h>
#include <stddef.h>
void* memcpy(void* src, void* dst, size_t length);
void* memcpy32(void* src, void* dst, size_t length);
void* memset(void* dst, uint8_t value, size_t length);
void* memset32(void* dst, uint32_t value, size_t length);
char* itoa(size_t val, int base);
uint32_t atoi(const char* str);
char* strcpy(char* str1, const char* str2);
char* strncpy(char* str1, const char* str2, size_t n);
char* strcat(char* str1, const char* str2);
char* strncat(char* str1, const char* str2, size_t n);
char* strchr(const char* str, char c);
char* strrchr(const char* str, char c);
int strcmp(const char* str1, const char* str2);
int strncmp(const char* str1, const char* str2, size_t n);
size_t strlen(const char* str);
#endif
-15
View File
@@ -1,15 +0,0 @@
#ifndef _SYS_GFX_H
#define _SYS_GFX_H
#define BLACK 0x00000000 // 0
#define RED 0x00ff0000 // 1
#define GREEN 0x0000ff00 // 2
#define YELLOW 0x00ffff00 // 3
#define BLUE 0x000000ff // 4
#define MAGENTA 0x00ff00ff // 5
#define CYAN 0x0000ffff // 6
#define WHITE 0x00ffffff // 7
uint32_t codeToColor(uint8_t code);
#endif
-108
View File
@@ -1,108 +0,0 @@
#ifndef SOUND_NOTES_H
#define SOUND_NOTES_H
/*
0 1 2 3 4 5 6 7 8
C 16.35 32.7 65.41 130.81 261.63 523.25 1046.5 2093 4186
C# 17.32 34.65 69.3 138.59 277.18 554.37 1108.73 2217.46 4434.92
D 18.35 36.71 73.42 146.83 293.66 587.33 1174.66 2349.32 4698.63
D# 19.45 38.89 77.78 155.56 311.13 622.25 1244.51 2489 4978
E 20.6 41.2 82.41 164.81 329.63 659.25 1318.51 2637 5274
F 21.83 43.65 87.31 174.61 349.23 698.46 1396.91 2793.83 5587.65
F# 23.12 46.25 92.5 185 369.99 739.99 1479.98 2959.96 5919.91
G 24.5 49 98 196 392 783.99 1567.98 3135.96 6271.93
G# 25.96 51.91 103.83 207.65 415.3 830.61 1661.22 3322.44 6644.88
A 27.5 55 110 220 440 880 1760 3520 7040
A# 29.14 58.27 116.54 233.08 466.16 932.33 1864.66 3729.31 7458.62
B 30.87 61.74 123.47 246.94 493.88 987.77 1975.53 3951 7902.13
*/
// Note frequencies in Hz (rounded down)
// b - Flat
// s - Sharp (#)
typedef enum {
// 2nd Octave
C2 = 65,
Cs2 = 69,
Db2 = Cs2,
D2 = 73,
Ds2 = 77,
Eb2 = Ds2,
E2 = 82,
F2 = 87,
Fs2 = 92,
Gb2 = Fs2,
G2 = 98,
Gs2 = 103,
Ab2 = Gs2,
A2 = 110,
As2 = 116,
Hb2 = As2,
H2 = 123,
// 3rd Octave
C3 = 130,
Cs3 = 138,
Db3 = Cs3,
D3 = 146,
Ds3 = 155,
Eb3 = Ds3,
E3 = 164,
F3 = 174,
Fs3 = 185,
Gb3 = Fs3,
G3 = 196,
Gs3 = 207,
Ab3 = Gs3,
A3 = 220,
As3 = 233,
Hb3 = As3,
H3 = 246,
// 4th Octave
C4 = 261,
Cs4 = 277,
Db4 = Cs4,
D4 = 293,
Ds4 = 311,
Eb4 = Ds4,
E4 = 329,
F4 = 349,
Fs4 = 370,
Gb4 = Fs4,
G4 = 392,
Gs4 = 415,
Ab4 = Gs4,
A4 = 440, // Standard A, 440Hz
As4 = 466,
Hb4 = As4,
H4 = 493,
// 5th Octave
C5 = 523,
Cs5 = 554,
Db5 = Cs5,
D5 = 587,
Ds5 = 622,
Eb5 = Ds5,
E5 = 659,
F5 = 698,
Fs5 = 739,
Gb5 = Fs5,
G5 = 783,
Gs5 = 830,
Ab5 = Gs5,
A5 = 880,
As5 = 932,
Hb5 = As5,
H5 = 987,
} note_t;
typedef enum {
WHOLE = 1,
HALF = 2,
QUARTER = 4,
EIGHT = 8,
SIXTEENTH = 16,
THIRTYSECONDTH = 32,
} beatType_t;
#endif
-48
View File
@@ -1,48 +0,0 @@
#ifndef _SYSCALL_H
#define _SYSCALL_H
#include <stddef.h>
#define SYSCALL_COUNT 9
typedef enum {
SYS_EXIT,
SYS_READ,
SYS_WRITE,
SYS_OPEN,
SYS_CLOSE,
SYS_SEEK,
SYS_MALLOC,
SYS_FREE,
SYS_SLEEP,
} SYSCALL_NUMBERS;
inline int syscall(int nr, int a0, int a1, int a2, int a3, int a4) {
int ret;
__asm__ volatile (
"movl %1, %%eax\n" // Syscall number
"movl %2, %%ebx\n" // Arg 0
"movl %3, %%ecx\n" // Arg 1
"movl %4, %%edx\n" // Arg 2
"movl %5, %%esi\n" // Arg 3
"movl %6, %%edi\n" // Arg 4
"int $0x80\n" // Trigger syscall
"movl %%eax, %0" // Return
: "=r"(ret) // Output
: "r"(nr), "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4) // Input
);
return ret;
}
/* Syscall wrappers */
static inline int _exit(int status) { return syscall(SYS_EXIT, status, 0, 0, 0, 0); }
static inline int read(int fd, void* ptr, size_t count) { return syscall(SYS_READ, fd, (int)ptr, (int)count, 0, 0); }
static inline int write(int fd, const void* ptr, size_t count) { return syscall(SYS_WRITE, fd, (int)ptr, (int)count, 0, 0); }
static inline int open(const char* path, int oflag) { return syscall(SYS_OPEN, (int)path, oflag, 0, 0, 0); }
static inline int close(int fd) { return syscall(SYS_CLOSE, fd, 0, 0, 0, 0); }
static inline int seek(int fd, size_t offset, int whence) { return syscall(SYS_SEEK, fd, offset, whence, 0, 0); }
static inline int _malloc(int size) { return syscall(SYS_MALLOC, size, 0, 0, 0, 0); }
static inline int _free(void* ptr) { return syscall(SYS_FREE, (int)ptr, 0, 0, 0, 0); }
static inline int _sleep(int t) { return syscall(SYS_SLEEP, t, 0, 0, 0, 0); }
#endif
-10
View File
@@ -1,10 +0,0 @@
#ifndef _TIME_H
#define _TIME_H
#include <stddef.h>
void sleep(size_t s);
void msleep(size_t ms);
void usleep(size_t us);
#endif
-22
View File
@@ -1,22 +0,0 @@
include ../defaults.mk
INC = ./include
BIN = ./bin
SRCS = $(shell find . -name '*.c')
OBJS = $(patsubst %.c, $(BIN)/%.o, $(SRCS))
OUT = ./libc.o
.PHONY: all clean
all: $(OUT)
$(OUT): $(OBJS)
$(AR) $(ARFLAGS) rcs $@ $^
$(BIN)/%.o: %.c
@mkdir -p $(BIN)/$(dir $<)
$(CC) $(CFLAGS) -I$(INC) -c -o $@ $<
clean:
rm -fr $(BIN) $(OUT)
-10
View File
@@ -1,10 +0,0 @@
#include <math.h>
int abs(int n) {
return (n < 0) ? -n : n;
}
double fabs(double x) {
return (x < 0.0) ? -x : x;
}
-44
View File
@@ -1,44 +0,0 @@
#include <math.h>
#include <string.h>
double nan(const char* tagp) {
(void)tagp;
// Create a NaN bit pattern in IEEE 754
uint64_t nanBits = 0x7ff8000000000000ULL;
double result;
memcpy(&result, &nanBits, sizeof(result));
return result;
}
double inf() {
// Create an infinity bit pattern in IEEE 754
uint64_t infBits = 0x7ff0000000000000ULL;
double result;
memcpy(&result, &infBits, sizeof(result));
return result;
}
int isfinite(double x) {
uint64_t bits;
memcpy(&bits, &x, sizeof(bits));
uint64_t exponent = (bits >> 52) & 0x7ff;
return exponent != 0x7ff;
}
int isinf(double x) {
uint64_t bits;
memcpy(&bits, &x, sizeof(bits));
uint64_t exponent = (bits >> 52) & 0x7ff;
uint64_t mantissa = bits & 0xfffffffffffff;
return (exponent == 0x7ff && mantissa == 0);
}
int isnan(double x) {
uint64_t bits;
memcpy(&bits, &x, sizeof(bits));
uint64_t exponent = (bits >> 52) & 0x7ff;
uint64_t mantissa = bits & 0xfffffffffffff;
return (exponent == 0x7ff && mantissa != 0);
}
-46
View File
@@ -1,46 +0,0 @@
#include <math.h>
#define _EXP_TAYLOR_TERMS 10
#define _EXP2_TAYLOR_TERMS 5
double exp(double x) {
if (x == 0.0) return 1.0;
if (x < 0.0) return 1.0 / exp(-x);
double sum = 1.0; // Result
double term = 1.0; // Curent term in the series
/*
Calculate the Taylor series:
e^x = 1 + x + x^2/2! + x^3/3! + ...
*/
for (int i = 1; i < _EXP_TAYLOR_TERMS; i++) {
term *= x / (double)i;
sum += term;
}
return sum;
}
double exp2(double x) {
if (x == 0.0) return 1.0;
if (x < 0.0) return 1.0 / exp2(-x);
int n = (int)x; // Integer part
double frac = x - n;// Fractional part
// Integer power of 2
double result = (double)(1 << n); // 2^n is just 1 << n
// Approximate the fractional part
double sum = 1.0;
double term = frac;
for (int i = 1; i < _EXP2_TAYLOR_TERMS; i++) {
sum += term;
term *= frac / (i+1);
}
return result * sum;
}
-16
View File
@@ -1,16 +0,0 @@
#include <math.h>
double sinh(double x) {
return (exp(x) - exp(-x)) / 2.0;
}
double cosh(double x) {
return (exp(x) + exp(-x)) / 2.0;
}
double tanh(double x) {
double ex = exp(x);
double emx = exp(-x);
return (ex - emx) / (ex + emx);
}
-35
View File
@@ -1,35 +0,0 @@
#include <math.h>
#define _LOG_TERMS 20
double log(double x) {
if (x <= 0.0) return -INFINITY;
double result = 0.0;
double term = (x - 1.0) / (x + 1.0);
double termSquared = term*term;
double numerator = term;
for (int i = 1; i < _LOG_TERMS; i++) {
result += numerator / (double)i;
numerator *= termSquared;
}
return 2.0 * result;
}
double log2(double x) {
if (x <= 0.0) return -INFINITY;
return log(x) / M_LN2;
}
double log10(double x) {
if (x <= 0.0) return -INFINITY;
return log(x) / M_LN10;
}
double logn(double x, double n) {
if (x <= 0.0) return -INFINITY;
return log(x) / log(n);
}
-42
View File
@@ -1,42 +0,0 @@
#include <math.h>
#define _POW_LOOP_MAX 60
double sqrt(double x) {
if (x < 0.0) return -NAN;
double result = x;
double oldResult = 0.0;
while (result != oldResult) {
oldResult = result;
result = 0.5 * (result + x/result);
}
return result;
}
double cbrt(double x) {
double result = x;
double oldResult = 0.0;
while (result != oldResult) {
oldResult = result;
result = (2.0 * result + x/(result * result)) / 3.0;
}
return result;
}
double hypot(double x, double y) {
return sqrt(x*x + y*y);
}
double pow(double base, double expn) { // exp is a function so we have to use expn
if (base == 0.0 && expn == 0.0) return NAN;
if (base == 0.0) return 0.0;
if (expn == 0.0) return 1.0;
return exp(expn * log(base));
}
-46
View File
@@ -1,46 +0,0 @@
#include <math.h>
double round(double x) {
double res;
__asm__ volatile (
"fldl %1\n" // Load x to the FPU stack
"frndint\n" // Round to nearest integer
"fstpl %0" // Store result
: "=m"(res)
: "m"(x)
);
if ((x - res) == 0.5 || (x - res) == -0.5) {
// Halfway cases: round away from zero
res += (x > 0) ? 1.0 : -1.0;
}
return res;
}
double floor(double x) {
double res = round(x);
if (res > x) { res -= 1.0; }
return res;
}
double ceil(double x){
double res = round(x);
if (res < x) { res += 1.0; }
return res;
}
double trunc(double x) {
double res = round(x);
if (x < 0 && x != res) { res -= 1.0; }
return res;
}
double fmod(double x, double y) {
return x - y * floor(x / y);
}
double modf(double x, double* iptr) {
double whole = trunc(x);
*iptr = whole;
return x - whole;
}
-61
View File
@@ -1,61 +0,0 @@
#include <math.h>
double sin(double x) {
double res;
__asm__ volatile (
"fldl %1\n" // Load x to the FPU stack
"fsin\n" // Compute sin(x)
"fstpl %0" // Store result
: "=m"(res) : "m"(x)
);
return res;
}
double cos(double x) {
double res;
__asm__ volatile (
"fldl %1\n" // Load x to the FPU stack
"fcos\n" // Compute cos(x)
"fstpl %0" // Store result
: "=m"(res) : "m"(x)
);
return res;
}
double tan(double x) {
return sin(x) / cos(x);
}
double asin(double x) {
return atan2(x, sqrt(1 - x*x));
}
double acos(double x) {
return M_PI_2 - asin(x);
}
double atan(double x) {
double res;
__asm__ volatile (
"fld1\n" // Load 1.0 to the FPU stack
"fldl %1\n" // Load x to the FPU stack
"fpatan\n" // Compute atan(x)
"fstpl %0" // Store result
: "=m"(res) : "m"(x)
);
return res;
}
double atan2(double y, double x) {
double res;
__asm__ volatile (
"fldl %2\n" // Load x to the FPU stack
"fldl %1\n" // Load y to the FPU stack
"fpatan\n" // Compute atan2(y, x)
"fstpl %0" // Store the result
: "=m"(res) : "m"(y), "m"(x)
);
return res;
}
-27
View File
@@ -1,27 +0,0 @@
#include <setjmp.h>
int setjmp(jmp_buf env) {
__asm__ volatile (
"mov %%ebp, %0\n" // Save BP
"mov %%esp, %1\n" // Save SP
"call 1f\n" // Call label to push PC to the stack
"1:\n" // Label
"pop %2\n" // Save PC
: "=m"(env._bp), "=m"(env._sp), "=m"(env._pc) // Locations
);
return 0;
}
void longjmp(jmp_buf env, int value) {
if (value == 0) return;
__asm__ volatile (
"mov %0, %%ebp\n" // Restore BP
"mov %1, %%esp\n" // Restore SP
"mov %2, %%eax\n" // Put return address into A
"jmp *%%eax\n" // Jump to A
:: "m"(env._bp), "m"(env._sp), "m"(env._pc)
);
// This point is unreachable :)
}
-29
View File
@@ -1,29 +0,0 @@
#include <stdio.h>
#include <syscall.h>
int getchar(void) { return getc(stdin); }
int putchar(int c) { return putc(c, stdout); }
int getc(FILE* stream) {
if (!stream) { return EOF; }
unsigned char ch = '\0';
ssize_t res = read(stream->_file, &ch, 1);
if (res <= 0) { return EOF; }
return (int)ch;
}
int putc(int c, FILE* stream) {
if (!stream) { return EOF; }
unsigned char ch = (unsigned char)c;
ssize_t res = write(stream->_file, &c, 1);
if (res <= 0) { return EOF; }
return (int)ch;
}
// TODO:
int ungetc(int c, FILE* stream) { return EOF; }
-78
View File
@@ -1,78 +0,0 @@
#include <stdio.h>
#include <syscall.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
FILE* stdin;
FILE* stdout;
FILE* stderr;
FILE* fopen(const char* path, const char* mode) {
FILE* fp = (FILE*)malloc(sizeof(FILE));
if (!fp) { return NULL; }
int flags = 0;
if (strcmp(mode, "r") == 0) { flags = O_RDONLY; }
else if (strcmp(mode, "w") == 0) { flags = O_WRONLY | O_CREAT | O_TRUNC; }
else if (strcmp(mode, "a") == 0) { flags = O_WRONLY | O_CREAT | O_APPEND; }
else if (strcmp(mode, "r+") == 0) { flags = O_RDWR; }
else if (strcmp(mode, "w+") == 0) { flags = O_RDWR | O_CREAT | O_TRUNC; }
else if (strcmp(mode, "a+") == 0) { flags = O_RDWR | O_CREAT | O_APPEND; }
else { // Unsuppored mode
free(fp);
return NULL;
}
int fd = open(path, flags);
if (fd == -1) {
free(fp);
return NULL;
}
fp->_file = fd;
fp->_ptr = NULL;
fp->_size = 0;
fp->_offset = 0;
fp->_flag = flags;
return fp;
}
int fclose(FILE* stream) {
if (!stream) { return -1; }
int ret = close(stream->_file);
free(stream);
return ret;
}
size_t fread(void* ptr, size_t size, size_t count, FILE* stream) {
if (!stream || !ptr || size == 0 || count == 0) { return 0; }
size_t total = size * count;
ssize_t readb = read(stream->_file, ptr, total);
if (readb < 0) return 0;
stream->_offset += readb;
return readb / size;
}
size_t fwrite(void* ptr, size_t size, size_t count, FILE* stream) {
if (!stream || !ptr || size == 0 || count == 0) { return 0; }
size_t total = size * count;
ssize_t writtenb = write(stream->_file, ptr, total);
if (writtenb < 0) return 0;
stream->_offset += writtenb;
return writtenb / size;
}
// TODO
int fseek(FILE* stream, long offset, int whence);
long ftell(FILE* stream);
void rewind(FILE* stream);
int fflush(FILE* stream);
-32
View File
@@ -1,32 +0,0 @@
#include <stdio.h>
#include <stddef.h>
char* fgets(char* str, int n, FILE* stream) {
if (!str || !stream || n <= 1) { return NULL; }
char* dest = str;
int ch;
while (--n > 0 && (ch = getc(stream)) != EOF) {
*dest++ = ch;
if (ch == '\n') break; // Stop at newline
}
*dest = '\0'; // Null terminate
return (dest == str) ? NULL : str;
}
int fputs(const char* str, FILE* stream) {
if (!str || !stream) { return EOF; }
while (*str) {
if (putc(*str++, stream) == EOF) { return EOF; }
}
return 0;
}
inline char* gets(char* str, int n) { return fgets(str, n, stdin); }
inline int puts(const char* str) { return fputs(str, stdout); }
-224
View File
@@ -1,224 +0,0 @@
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* Internal definitions */
typedef struct {
int buflen;
int offset;
char* buf;
} printfEnv_t;
/* Helpers */
// Digit to character
static char _dtoc(int digit) { return digit < 10 ? '0' + digit : 'a' + (digit - 10); }
static double _fabs(double x) { return (x < 0.0) ? -x : x; }
static void _fmtInt(void (*outfn)(char c, void* arg), void* arg, int n, int base, int width, char padc) {
char buf[32];
int negative = 0;
int i = 0;
if (n < 0 && base == 10) {
negative = 1;
n = -n;
}
// Convert number, this will be done in reverse
do {
buf[i++] = _dtoc(n % base);
n /= base;
} while (n > 0);
// Padding
while (i < width) { buf[i++] = padc; }
// Add negative sign
if (negative) { buf[i++] = '-'; }
// Funny arrow
while (i --> 0) { outfn(buf[i], arg); }
}
static void _fmtFloat(void (*outfn)(char c, void* arg), void* arg, double f) {
int whole = (int)f;
double frac = _fabs(f - whole);
int decPlaces = 6;
// Add negative sign
if (f < 0) { outfn('-', arg); }
// Print whole part
_fmtInt(outfn, arg, whole, 10, 0, ' ');
// Print decimal point
outfn('.', arg);
// Format fractional part
for (int i = 0; i < decPlaces; i++) {
frac *= 10;
int digit = (int)frac;
outfn('0' + digit, arg);
frac -= digit;
}
}
static void _dynamicPutc(char c, void* arg) {
printfEnv_t* env = (printfEnv_t*)arg;
if (!env->buf) { return; }
if (env->offset < env->buflen) {
env->buf[env->offset++] = c;
} else {
env->buflen *= 2;
env->buf = realloc(env->buf, env->buflen);
// If there's not enough memory, we chatch the NULL pointer in the fwrite() call
if (!env->buf) { return; }
env->buf[env->offset++] = c;
}
}
static void _staticPutc(char c, void* arg) {
printfEnv_t* env = (printfEnv_t*)arg;
if (!env->buf) { return; }
if (env->offset < env->buflen) {
env->buf[env->offset] = c;
env->offset++;
}
}
/* Impementation */
int vpprintf(void (*outfn)(char c, void* arg), void* arg, const char* fmt, va_list va) {
int i = 0;
while (fmt[i] != '\0') {
if (fmt[i] != '%') { // Just print the character
outfn(fmt[i++], arg);
continue;
}
i++; // Consume the %
if (fmt[i] == '\0') { // End of string
outfn('%', arg);
break;
}
// Parse fmt string
int width = 0;
char pad = ' ';
// Check for zero pad and parse width
if (isdigit(fmt[i])) {
if (fmt[i] == '0') { pad = '0'; i++; }
while (isdigit(fmt[i])) { // Parse width
width *= 10;
width += fmt[i++] - '0';
}
}
// Parse specifier
switch (fmt[i]) {
case 'c': { // Character
char c = va_arg(va, char);
outfn(c, arg);
break;
} case 's': { // String
char* s = va_arg(va, char*);
while (*s) { outfn(*s++, arg); }
break;
} case 'd': { // Decimal number
int d = va_arg(va, int);
_fmtInt(outfn, arg, d, 10, width, pad);
break;
} case 'x': { // Hex number
int x = va_arg(va, int);
_fmtInt(outfn, arg, x, 16, width, pad);
break;
} case 'f': { // Float
double f = va_arg(va, double);
_fmtFloat(outfn, arg, f);
break;
} default: {
outfn(fmt[i], arg);
break;
}
}
i++;
}
return i;
}
int vsnprintf(char* str, size_t size, const char* fmt, va_list va) {
printfEnv_t env;
env.buflen = size;
env.offset = 0;
env.buf = str;
// Format the string
int ret = vpprintf(_staticPutc, &env, fmt, va);
return ret;
}
int vfprintf(FILE* stream, const char* fmt, va_list va) {
printfEnv_t env;
env.buflen = 128;
env.offset = 0;
env.buf = malloc(env.buflen);
if (!env.buf) { return -1; }
// Format the string
int ret = vpprintf(_dynamicPutc, &env, fmt, va);
// Write to stream
if (fwrite(env.buf, 1, ret, stream) != 1) { return -1; }
free(env.buf);
return ret;
}
int vprintf(const char* fmt, va_list va) { return vfprintf(stdout, fmt, va); }
// Print using an custom putc function
int pprintf(void (*outfn)(char c, void* arg), void* arg, const char* fmt, ...) {
va_list va;
va_start(va, fmt);
int ret = vpprintf(outfn, arg, fmt, va);
va_end(va);
return ret;
}
// Print to a buffer
int snprintf(char* str, size_t size, const char* fmt, ...) {
va_list va;
va_start(va, fmt);
int ret = vsnprintf(str, size, fmt, va);
va_end(va);
return ret;
}
// Print to a stream
int fprintf(FILE* stream, const char* fmt, ...) {
va_list va;
va_start(va, fmt);
int ret = vfprintf(stream, fmt, va);
va_end(va);
return ret;
}
// Print to stdout
int printf(const char* fmt, ...) {
va_list va;
va_start(va, fmt);
int ret = vfprintf(stdout, fmt, va);
va_end(va);
return ret;
}
-37
View File
@@ -1,37 +0,0 @@
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <syscall.h>
void* malloc(size_t size) { return (void*)_malloc(size); }
void* calloc(size_t count, size_t size) {
size_t total = count * size;
void* ptr = malloc(total);
if (!ptr) { return NULL; }
memset(ptr, 0, total);
return ptr;
}
void* realloc(void* ptr, size_t size) {
if (size == 0) {
free(ptr);
return NULL;
}
if (ptr == NULL) { return malloc(size); }
void* newptr = malloc(size);
if (!newptr) { return NULL; }
// TODO: retrieve the old size
memcpy(newptr, ptr, size);
free(ptr);
return newptr;
}
void free(void* ptr) { _free(ptr); }
-13
View File
@@ -1,13 +0,0 @@
#include <stdlib.h>
#include <syscall.h>
// Exits without cleaning up
void _Exit(int status) { _exit(status); }
void exit(int status) {
// TODO: Close open files
// TODO: Free malloced buffers
_Exit(status);
}
-15
View File
@@ -1,15 +0,0 @@
#include <stdlib.h>
// taken from glibc
#define RAND_A 1103515245
#define RAND_C 12345
static size_t _next = 1;
int rand(void) {
_next = (RAND_A * _next + RAND_C) & RAND_MAX;
return (int)(_next % (size_t)(RAND_MAX + 1));
}
void srand(size_t seed) { _next = seed; }
-25
View File
@@ -1,25 +0,0 @@
#include <stdlib.h>
#include <stddef.h>
void* bsearch(const void* key, const void* base, size_t nitem, size_t size, int (*compar)(const void*, const void*)) {
size_t left = 0;
size_t right = nitem;
while (left < right) {
size_t mid = left + (right - left) / 2;
void* midEl = (char*)base + mid * size;
int cmp = compar(key, midEl);
if (cmp < 0) {
right = mid;
} else if (cmp > 0) {
left = mid + 1;
} else {
return midEl;
}
}
return NULL;
}
-37
View File
@@ -1,37 +0,0 @@
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
void swap(void* a, void* b, size_t size) {
char temp[size];
memcpy(temp, a, size);
memcpy(a, b, size);
memcpy(b, temp, size);
}
void* partition(void* base, size_t nitem, size_t size, int (*compar)(const void*, const void*)) {
char* pivot = (char*)base + (nitem - 1) * size;
char* i = (char*)base;
for (char* j = (char*)base; j < pivot; j += size) {
if (compar(j, pivot) < 0) {
swap(i, j, size);
i += size;
}
}
swap(i, pivot, size);
return i;
}
void qsort(void* base, size_t nitem, size_t size, int (*compar)(const void*, const void*)) {
if (nitem <= 1) { return; }
char* pivot = (char*)partition(base, nitem, size, compar);
size_t lsize = (pivot - (char*)base) / size;
size_t rsize = nitem - lsize - 1;
qsort(base, lsize, size, compar);
qsort(pivot + size, rsize, size, compar);
}
-13
View File
@@ -1,13 +0,0 @@
#include <string.h>
unsigned int atoi(const char* str) {
unsigned int res = 0;
// TODO: Add error checking
while (*str >= '0' && *str <= '9') {
res = res * 10 + (*str++ - '0');
}
return res;
}
-21
View File
@@ -1,21 +0,0 @@
#include <string.h>
// Source: http://www.strudel.org.uk/itoa/
char* itoa(size_t val, int base) {
static char buf[32] = { 0 };
if (base == 0 || base > 16) { return NULL; }
if (val == 0) {
buf[0] = '0';
buf[1] = '\0';
return buf;
}
int i;
for (i = 30; val && i; i--, val /= base) {
buf[i] = "0123456789abcdef"[val % base];
}
return &buf[i + 1];
}
-17
View File
@@ -1,17 +0,0 @@
#include <string.h>
#include <stdint.h>
void* memcpy(void* src, void* dst, uint32_t length) {
for (uint32_t i = 0; i < length; i++) {
*((uint8_t*)dst + i) = *((uint8_t*)src + i);
}
return dst;
}
void* memcpy32(void* src, void* dst, uint32_t length) {
for (uint32_t i = 0; i * 4 < length; i++) {
*((uint32_t*)dst + i) = *((uint32_t*)src + i);
}
return dst;
}
-18
View File
@@ -1,18 +0,0 @@
#include <string.h>
#include <stdint.h>
#include <stddef.h>
void* memset(void* dst, uint8_t value, size_t length) {
for (size_t i = 0; i < length; i++) {
*(uint8_t*)(dst + i) = value;
}
return dst;
}
void* memset32(void* dst, uint32_t value, size_t length) {
for (size_t i = 0; i < length; i++) {
*(uint32_t*)(dst + i) = value;
}
return dst;
}
-15
View File
@@ -1,15 +0,0 @@
#include <string.h>
char* strcat(char* str1, const char* str2) {
char* s = str1;
while (*s != '\0') { s++; }
strcpy(s, str2);
return str1;
}
char* strncat(char* str1, const char* str2, size_t n) {
char* s = str1;
while (*s != '\0') { s++; }
strncpy(s, str2, n);
return str1;
}
-10
View File
@@ -1,10 +0,0 @@
#include <string.h>
char* strchr(const char* str, char c) {
const char* s = str;
while (*s != '\0' && *s != c) { s++; }
return (*s == c) ? (char*)s : NULL;
}
char* strrchr(const char* str, char c) { return NULL; } // TODO
-27
View File
@@ -1,27 +0,0 @@
#include <string.h>
int strcmp(const char* str1, const char* str2) {
while (*str1 != '\0' && *str1 == *str2) {
str1++;
str2++;
}
uint8_t c1 = (*(uint8_t*)str1);
uint8_t c2 = (*(uint8_t*)str2);
return ((c1 < c2) ? -1 : (c1 > c2));
}
int strncmp(const char* str1, const char* str2, size_t n) {
if (n == 0) { return 0; }
while (n-- > 0 && *str1 == *str2) {
if (n == 0 || *str1 == '\0') { return 0; }
str1++;
str2++;
}
uint8_t c1 = (*(uint8_t*)str1);
uint8_t c2 = (*(uint8_t*)str2);
return ((c1 < c2) ? -1 : (c1 > c2));
}
-22
View File
@@ -1,22 +0,0 @@
#include <string.h>
char* strcpy(char* str1, const char* str2) {
char* dst = str1;
const char* src = str2;
while ((*dst++ = *src++) != '\0');
return str1;
}
char* strncpy(char* str1, const char* str2, size_t n) {
char* dst = str1;
const char* src = str2;
while (n > 0) {
n--;
if ((*dst++ = *src++) == '\0') {
memset(dst, '\0', n);
break;
}
}
return str1;
}
-8
View File
@@ -1,8 +0,0 @@
#include <string.h>
#include <stddef.h>
size_t strlen(const char* str) {
const char* p = str;
while (*++p != '\0');
return (size_t)(p - str);
}
-17
View File
@@ -1,17 +0,0 @@
#include <stdint.h>
#include <sys/gfx.h>
uint32_t codeToColor(uint8_t code) {
switch (code) {
case 0: return BLACK;
case 1: return RED;
case 2: return GREEN;
case 3: return YELLOW;
case 4: return BLUE;
case 5: return MAGENTA;
case 6: return CYAN;
case 7: return WHITE;
default: return BLACK;
}
}
-13
View File
@@ -1,13 +0,0 @@
#include <time.h>
#include <syscall.h>
#include <stdint.h>
// Seconds sleep
void sleep(size_t s) { _sleep(s*1000); }
// Millisecond sleep
void msleep(size_t ms) { _sleep(ms); }
// Microsecond sleep
void usleep(size_t us) { /* TODO */ }
+3 -17
View File
@@ -1,24 +1,10 @@
IMG = kern.img
BOOT = ./boot
KERNEL = ./kernel
LIBC = ./libc
MODULES = $(BOOT)\
$(KERNEL)\
$(LIBC)
MODULES = $(KERNEL)
.PHONY: all clean $(MODULES) qemu
all: $(IMG)
$(IMG): $(MODULES)
dd if=/dev/zero of=$(IMG) bs=512 count=131072
dd if=$(BOOT)/stage1.bin of=$(IMG) bs=512 seek=0 conv=notrunc
dd if=$(BOOT)/stage2.bin of=$(IMG) bs=512 seek=1 conv=notrunc
echo ',,b,*' | sfdisk $(IMG) >/dev/null
echo 'drive A:\n\tfile="$(IMG)"\n\tpartition=1' > ~/.mtoolsrc
mformat -F 'A:'
mcopy $(KERNEL)/kern.bin 'A:'
all: $(MODULES)
$(MODULES):
$(MAKE) -C $@
@@ -31,5 +17,5 @@ qemu:
-drive format=raw,file=$(IMG),index=0,media=disk\
-m 256M -accel tcg -monitor stdio -net none\
-rtc base=localtime,clock=host,driftfix=slew\
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0
-audiodev pipewire,id=audio0 -machine pcspk-audiodev=audio0