initial commit

This commit is contained in:
'mr software' 2024-01-10 11:13:45 -08:00
commit 7ac42a5c9d
26 changed files with 3238 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
test.mp3

20
b Executable file
View File

@ -0,0 +1,20 @@
#!/bin/sh
# needs to be configured in boot.s as well
LDADDR=0x100000
BNAME=32.com
[ "$1" = "init" ] && for i in tool/*.c; do cc $i -O3 -o $(echo "$i" | sed 's/\.c$//') | true; done &&
tool/genisr > include/isr.i
[ "$1" = "clean" ] && rm obj/* $BNAME
[ "$1" = "prog" ] && for i in src/*.s; do nasm -felf $i; done &&
for i in src/*.c; do i386-elf-gcc -c $i -ffreestanding -Iinclude -Os | true; done &&
mv *.o src/*.o obj &&
i386-elf-ld -o obj/kernel -Ttext $LDADDR obj/entry.o $(ls obj/*.o | grep -v entry.o) --oformat binary &&
cat obj/boot obj/kernel > $BNAME
[ -z "$1" ] && nasm boot/boot.s -o obj/boot | true && $0 prog | true
[ "$1" = "all" ] && ./b clean | true && ./b | true && dosbox-x $BNAME | true

119
boot/boot.s Normal file
View File

@ -0,0 +1,119 @@
[org 0x100]
[bits 16]
cli
mov ax, ds
mov [torm+3], ax
mov gs, ax
mov [oldss], ss
mov [oldsp], sp
in al, 0x92
or al, 2
out 0x92, al
; TODO maybe choose a better entrypoint than the start of hma
cld
mov cx, 65280-bindat
mov si, bindat
mov ax, 0xFFFF
mov es, ax
mov di, 0x10
rep movsb
; relocate jump target
xor eax, eax
mov ax, ds
shl eax, 4
add [gdt+2], eax
add [gdt_end+2], eax
mov [gds+2], ax
mov [gds16+2], ax
mov [gcs16+2], ax
shr eax, 16
mov [gds+4], al
mov [gds16+4], al
mov [gcs16+4], al
lgdt [gdt]
mov eax, cr0
or al, 1
mov cr0, eax
ijmp: jmp dsseg:init
[bits 32]
init:
; retain stack pointer
; esp = ebp = (ss << 4) + sp
xor ebp, ebp
xor ebx, ebx
mov bp, ss
mov bx, sp
shl ebp, 4
add ebp, ebx
mov esp, ebp
mov ax, data
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
call code:0x100000 ; start
cli
jf: jmp cs16:in16
[bits 16]
in16:
mov ax, ds16
mov ds, ax
lidt [idt]
mov eax, cr0
and al, 0xFE
mov cr0, eax
torm: jmp 0:inrm
inrm: mov ax, gs
mov ds, ax
mov es, ax
mov fs, ax
mov ss, [oldss]
mov sp, [oldsp]
sti
xor ax, ax
int 21h
ret
idt: dw 0x3FF
dd 0
gdt: dw gdt_end - gdt - 1
dd gdt
dw 0
gcode: dd 0x0000ffff
code equ gcode - gdt
db 0, 10011011b, 11001111b, 0
gdata: dd 0x0000ffff
data equ gdata - gdt
db 0, 10010011b, 11001111b, 0
gds: dd 0x0000ffff
dsseg equ gds - gdt
db 0, 10011111b, 01001111b, 0
gds16: dd 0x0000ffff
ds16 equ gds16 - gdt
db 0, 10010111b, 00001111b, 0
gcs16: dd 0x0000ffff
cs16 equ gcs16 - gdt
db 0, 10011111b, 00001111b, 0
gdt_end:
oldss: dw 0
oldsp: dw 0
bindat equ $

1293
dosbox-x.conf Normal file

File diff suppressed because it is too large Load Diff

23
include/alloc.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef ALLOC
#define ALLOC
#include <stdint.h>
#include <string.h>
typedef struct malloc_entry {
void* ptr;
uint32_t size;
#define MALLOC_USED 1
#define MALLOC_FREE 0
uint8_t state;
} __attribute__((packed)) malloc_entry;
void init_hashtable();
void* malloc(uint32_t size);
void free(void* ptr);
void* realloc(void* ptr, uint32_t size);
/*
extern void* malloc_base_pointer;
extern unsigned int highest_size;
*/
#endif

36
include/ata-pio.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef ATA_PIO
#define ATA_PIO
#include <stdint.h>
#include <ports.h>
// register stuff
#define ATA_IO_BASE 0x1F0
#define ATA_CONTROL_BASE 0x3F0
#define ATA_SECONDARY_OFFSET 128
#define ATA_DATA_REGISTER 0
#define ATA_ERROR_REGISTER 1
#define ATA_FEATURES_REGISTER 1
#define ATA_SECTOR_COUNT_REGISTER 2
#define ATA_SECTOR_REGISTER 3
#define ATA_CYL_LOW_REGISTER 4
#define ATA_CYL_HIGH_REGISTER 5
#define ATA_DRIVE_REGISTER 6
#define ATA_STATUS_REGISTER 7
#define ATA_COMMAND_REGISTER 7
#define ATA_ALTERNATE_STATUS_REGISTER 0
#define ATA_DEVICE_CONTROL_REGISTER 0
#define ATA_DRIVE_ADDRESS_REGISTER 1
// bitfield stuff
// declarations
int ata_init(uint8_t bus, uint8_t drive);
int ata_read(uint8_t bus, uint8_t drive, uint16_t* buf, uint16_t sectors, uint16_t lba_high, uint32_t lba_low);
int ata_write(uint8_t bus, uint8_t drive, uint16_t* buf, uint16_t sectors, uint16_t lba_high, uint32_t lba_low);
extern uint16_t ata_identify[256];
#endif

38
include/interrupt.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef INTERRUPT
#define INTERRUPT
extern uint8_t isr_base[];
typedef struct {
uint16_t lo;
uint16_t sel;
uint8_t reserved;
uint8_t flags;
uint16_t hi;
} __attribute__((packed)) idt_gate;
typedef struct {
uint16_t limit;
idt_gate* base;
} __attribute__((packed)) idtrc;
typedef struct {
uint32_t ds;
uint32_t edi, esi, ebp, uesp, ebx, edx, ecx, eax;
uint32_t ino, err;
uint32_t eip, cs, eflags, esp, ss;
} registers;
extern idtrc idtr;
extern idt_gate idt[256];
typedef void (*isr)(registers*);
void regint(uint8_t ino, isr i);
void set_idt(uint8_t n, uint32_t i);
void lidt();
void isr_init();
void isr_handler(registers* r);
void noint(registers* r);
#endif

1280
include/isr.i Normal file

File diff suppressed because it is too large Load Diff

9
include/keyboard.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef KEYBOARD
#define KEYBOARD
#include <stdint.h>
extern uint8_t keys[256];
void kbmode(uint8_t mode);
#endif

11
include/ports.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef PORTS
#define PORTS
#include <stdint.h>
uint8_t inb(uint16_t port);
uint16_t inw(uint16_t port);
void outb(uint16_t port, uint8_t data);
void outw(uint16_t port, uint16_t data);
#endif

4
include/stddef.h Normal file
View File

@ -0,0 +1,4 @@
#ifndef STDDEF
#define STDDEF
#define NULL (void*)0
#endif

7
include/stdlib.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef STDLIB
#define STDLIB
#include <stdint.h>
int abs(int i);
char* itox(uint32_t x);
#endif

9
include/string.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef STRING
#define STRING
#include <stdint.h>
uint32_t strlen(char* str);
void memcpy(uint8_t* dest, uint8_t* src, uint32_t len);
void memset(uint8_t* dest, uint8_t set, uint32_t len);
#endif

15
include/video.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef VIDEO
#define VIDEO
extern char* vga;
#define VGA_CCTRL 0x3d4
#define VGA_CDATA 0x3d5
#define ROWS 25
#define COLS 80
void cls();
void setcursor(unsigned int);
int getcursor();
#endif

73
src/alloc.c Normal file
View File

@ -0,0 +1,73 @@
#include <alloc.h>
#include <stddef.h>
#define POINTER uint32_t
#define BUCKET_NUM 256
#define BUCKET_SIZE 6371
unsigned int highest_size = 0;
// TODO determine this
void* malloc_base_pointer = (void*) 0x01000000;
#define table(BUCKET, SLOT) hashtable[(BUCKET*BUCKET_NUM)+SLOT]
malloc_entry* hashtable = (void*) 0x100000;
void init_hashtable() {
memset((uint8_t*)hashtable, 0, 0xE00000);
}
void* malloc(uint32_t size) {
if(size == 0) return NULL;
// TODO not hardcode this
if(highest_size > 1073742000) return NULL;
malloc_entry candidate_entry = (malloc_entry) {NULL, 0xFFFFFFFF, 0};
int candidate_slot = 0xFFFFFF, foundpage = 0;
if(size > highest_size) goto nocandidate;
// TODO search more efficiently? maybe hashtable[0x10000][0x100]?
// TODO combining nearby blocks
// TODO if block is at highest pointer update hash table instead of reallocating
for(int bi = 0; bi < 256; bi++) {
for(int si = 0; si < BUCKET_SIZE; si++) {
if(
table(bi,si).state == MALLOC_FREE &&
table(bi,si).size < candidate_entry.size &&
table(bi,si).size >= size
) {
candidate_entry = table(bi,si);
candidate_entry.size = size;
// candidate_bucket = bi;
candidate_slot = si;
}
}
}
if(candidate_slot == 0xFFFFFF) {
nocandidate:
candidate_entry = (malloc_entry) {malloc_base_pointer + highest_size + 1, size, MALLOC_USED};
highest_size += size;
for(candidate_slot = 0; candidate_slot < BUCKET_SIZE; candidate_slot++) if(
table((POINTER) candidate_entry.ptr & 0xFF,candidate_slot).ptr == NULL &&
table((POINTER) candidate_entry.ptr & 0xFF,candidate_slot).state == 0
) {foundpage = 1; break;}
if(!foundpage) return NULL;
} else candidate_entry.state = MALLOC_USED;
table((POINTER) candidate_entry.ptr & 0xFF,candidate_slot) = candidate_entry;
if(size > highest_size) highest_size = size;
return candidate_entry.ptr;
}
void free(void* ptr) {
if(ptr != NULL) for(int i = 0; i < BUCKET_SIZE; i++) if(table((POINTER) ptr & 0xFF,i).ptr == ptr) {
table((POINTER) ptr & 0xFF,i).state = MALLOC_FREE;
}
}
void* realloc(void* ptr, uint32_t size) {
if(ptr != NULL) for(int i = 0; i < BUCKET_SIZE; i++) if(table((POINTER) ptr & 0xFF,i).ptr == ptr) {
if(size <= table((POINTER) ptr & 0xFF,i).size) return ptr;
free(ptr);
void* newptr = malloc(size);
memcpy(newptr, ptr, table((POINTER) ptr & 0xFF,i).size);
return newptr;
}
return NULL;
}

51
src/ata-pio.c Normal file
View File

@ -0,0 +1,51 @@
#include <ata-pio.h>
#include <video.h>
uint16_t ata_identify[256];
// 0: disk is initialized
// 1: no disks
// 2: no disk on requested interface
// 3: ATAPI
int ata_init(uint8_t bus, uint8_t drive) {
uint16_t io_base = ATA_IO_BASE - (bus ? ATA_SECONDARY_OFFSET : 0);
if(inb(io_base + ATA_STATUS_REGISTER) == 0xFF) return 1;
outb(io_base + ATA_DRIVE_REGISTER, drive ? 0xB0 : 0xA0);
for(int i = 2; i < 6; i++) outb(io_base + i, 0);
outb(io_base + ATA_STATUS_REGISTER, 0xEC);
uint8_t status;
do {
status = inb(io_base + ATA_STATUS_REGISTER);
if(!status) return 2;
} while((status & 0x80));
if(inb(io_base + 4) || inb(io_base + 5)) return 3;
do {
status = inb(io_base + ATA_STATUS_REGISTER);
if(status & 1) return inb(io_base + ATA_ERROR_REGISTER);
} while(!(status & 8));
uint16_t err = inb(io_base + ATA_ERROR_REGISTER);
if(err) return err;
for(int i = 0; i < 256; i++) ata_identify[i] = inw(io_base);
return 0;
}
uint16_t ata_setuprw(uint8_t bus, uint8_t drive, uint16_t sectors, uint16_t lba_high, uint32_t lba_low) {
uint16_t io_base = ATA_IO_BASE - (bus ? ATA_SECONDARY_OFFSET : 0);
outb(io_base + ATA_DRIVE_REGISTER, 0x40 | ((!!drive) << 4));
uint8_t mports[4] = {2, 3, 4, 5};
uint8_t dat[8] = {sectors >> 8, lba_low >> 24, lba_high >> 8, lba_high, sectors, lba_low, lba_low >> 8, lba_low >> 16};
for(int i = 0; i < 8; i++) outb(io_base + mports[i % 4], dat[i]);
return io_base;
}
int ata_read(uint8_t bus, uint8_t drive, uint16_t* buf, uint16_t sectors, uint16_t lba_high, uint32_t lba_low) {
uint16_t io_base = ata_setuprw(bus, drive, sectors, lba_high, lba_low);
outb(io_base + ATA_COMMAND_REGISTER, 0x24);
for(int i = 0; i < sectors * 256; i++) buf[i] = inw(io_base);
}
int ata_write(uint8_t bus, uint8_t drive, uint16_t* buf, uint16_t sectors, uint16_t lba_high, uint32_t lba_low) {
uint16_t io_base = ata_setuprw(bus, drive, sectors, lba_high, lba_low);
outb(io_base + ATA_COMMAND_REGISTER, 0x34);
for(int i = 0; i < sectors * 256; i++) outw(io_base, buf[i]);
outb(io_base + ATA_COMMAND_REGISTER, 0xE7);
}

7
src/entry.s Normal file
View File

@ -0,0 +1,7 @@
[bits 32]
[extern entry]
global _start
_start:
call entry
retf

28
src/interrupt.s Normal file
View File

@ -0,0 +1,28 @@
[extern isr_handler]
global isr_base
isr: pusha
mov ax, ds
push eax
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
push esp
cld
call isr_handler
pop eax
pop eax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
popa
add esp, 8
sti
iret
isr_base:
%include "include/isr.i"

60
src/interrupts.c Normal file
View File

@ -0,0 +1,60 @@
#include <ports.h>
#include <interrupt.h>
#include <video.h>
#include <stdlib.h>
idt_gate idt[256];
idtrc idtr = {2047, idt}; // 256*8-1
isr isrs[256];
void noint(registers* r) {
*((uint16_t*)0xB8000) = 0x0F00 | r->ino;
}
void set_idt(uint8_t n, uint32_t i) {
idt[n].hi = (i >> 16) & 0xFFFF;
idt[n].lo = i & 0xFFFF;
idt[n].sel = 0x8; // TODO macro
idt[n].flags = 0x8E;
idt[n].reserved = 0;
}
void lidt() {
asm volatile("lidtl (%0)" : : "r" (&idtr));
}
void isr_init() {
uint8_t portouts[20] = {
0x20, 0x11,
0xA0, 0x11,
0x21, 0x20,
0xA1, 0x28,
0x21, 0x04,
0xA1, 0x02,
0x21, 0x01,
0xA1, 0x01,
0x21, 0x0,
0xA1, 0x0
};
for(int i = 0; i < 20; i+=2) outb(portouts[i], portouts[i+1]); // remap pic TODO undo function
for(int i = 0; i < 256; i++) { // TODO this can be done at compile time (even with relocation?)
set_idt(i, ((uint32_t)isr_base) + (13*i));
isrs[i] = noint;
}
lidt();
asm volatile("sti");
}
void regint(uint8_t ino, isr i) {isrs[ino] = i;}
void isr_handler(registers* t){
if(t->ino >= 32 && t->ino <= 47) { // from the pic
if(t->ino >= 40) outb(0xA0, 0x20);
outb(0x20, 0x20);
}
isrs[(uint8_t)t->ino](t);
}

33
src/kernel.c Normal file
View File

@ -0,0 +1,33 @@
#include <ports.h>
#include <video.h>
#include <keyboard.h>
#include <interrupt.h>
#include <ata-pio.h>
#include <alloc.h>
#include <video.h>
#include <stdlib.h>
uint32_t tick = 0;
void clock_update(registers* r) {
tick++;
for(int i = 0; i < 80 * 25; i++) {((uint16_t*)0xB8000)[i] = 0xF000 | (tick & 0xFF);}
}
void setclock(uint32_t f) {
uint32_t divisor = 1193182 / f;
outb(0x43, 0x36);
outb(0x40, divisor & 0xFF);
outb(0x40, (divisor >> 8) & 0xFF);
}
void entry() {
isr_init();
regint(32, clock_update);
kbmode(1);
setclock(8);
while(1) for(int i = 0; i < 80 * 25; i++) {
((uint16_t*)0xB8000)[i] = 0xF000 | (tick & 0xFF);
}
}

32
src/keyboard.c Normal file
View File

@ -0,0 +1,32 @@
#include <video.h>
#include <ports.h>
#include <keyboard.h>
#include <interrupt.h>
uint8_t keys[256];
void array_keyboard(registers* r) {
// TODO ?????
uint8_t scancode = inb(0x60);
if(scancode > 0x39) keys[scancode-0x80] = 0;
else keys[scancode] = 1;
vga[44] = scancode;
}
void no_keyboard(registers* r) {
inb(0x60);
}
void kbmode(uint8_t mode) {
switch(mode) {
case 0:
// ignore keyboard
regint(33, no_keyboard);
break;
case 1:
// nonblocking, array based keyboard
regint(33, array_keyboard);
break;
// TODO getc-like mode
}
}

21
src/ports.c Normal file
View File

@ -0,0 +1,21 @@
#include <ports.h>
uint8_t inb(uint16_t port) {
unsigned char result;
asm("in %%dx, %%al" : "=a" (result) : "d" (port));
return result;
}
void outb(uint16_t port, uint8_t data) {
asm("out %%al, %%dx" : : "a" (data), "d" (port));
}
uint16_t inw(uint16_t port){
uint16_t ret;
asm volatile ("inw %1, %0" : "=a" (ret) : "dN" (port));
return ret;
}
void outw(uint16_t port, uint16_t data){
asm volatile ("outw %1, %0" : : "dN" (port), "a" (data));
}

14
src/stdlib.c Normal file
View File

@ -0,0 +1,14 @@
#include <stdlib.h>
int abs(int i) {
return (i < 0) ? -i : i;
}
char itoxret[8];
char* itox(uint32_t x) {
for(int i = 0; i < 8; i++) {
itoxret[7-i] = (x >> (i*4)) & 0xF;
itoxret[7-i] += (itoxret[7-i] > 9) ? ('A' - 10) : '0';
}
return itoxret;
}

15
src/string.c Normal file
View File

@ -0,0 +1,15 @@
#include <string.h>
uint32_t strlen(char* str) {
uint32_t n = 0;
while(*str++ != 0) n++;
return n;
}
void memcpy(uint8_t* dest, uint8_t* src, uint32_t len) {
while(len-- > 0) *dest++ = *src++;
}
void memset(uint8_t* dest, uint8_t set, uint32_t len) {
while(len-- > 0) *dest++ = set;
}

26
src/video.c Normal file
View File

@ -0,0 +1,26 @@
#include <video.h>
#include <ports.h>
#include <string.h>
// start in 80x25 mode
char* vga = (char*)0xB8000;
void cls() {
for(int i; i < 2000; i++) vga[i*2] = ' ';
setcursor(0);
}
void setcursor(unsigned int i) {
outb(VGA_CCTRL, 14);
outb(VGA_CDATA, i >> 8);
outb(VGA_CCTRL, 15);
outb(VGA_CDATA, i & 0xff);
}
int getcursor() {
outb(VGA_CCTRL, 14);
uint8_t ofs = inb(VGA_CDATA) << 8;
outb(VGA_CCTRL, 15);
ofs += inb(VGA_CDATA);
return ofs;
}

13
tool/genisr.c Normal file
View File

@ -0,0 +1,13 @@
#include <stdio.h>
// these exceptions have error codes
const char ex[10] = {8, 10, 11, 12, 13, 14, 17, 21, 29, 30};
int main() {
for(int i = 0; i < 256; i++) {
int s = 0;
for(int e = 0; e < 10; e++) if(i == ex[e]) {s = 1; break;}
printf("\ni%i: cli\n%spush dword strict %i\njmp strict near isr\n%s", i, s ? "" : "push byte 0\n", i, s ? "cs nop\n" : "");
}
}