basic os stuff
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
CLAUDE.md
|
||||
*.err
|
||||
95
Makefile
Normal file
95
Makefile
Normal file
@@ -0,0 +1,95 @@
|
||||
# -------------------------------------------------------
|
||||
# Real Mode OS Makefile
|
||||
# Tools: NASM, OpenWatcom (wcc/wlink), QEMU
|
||||
# -------------------------------------------------------
|
||||
|
||||
# Tools
|
||||
NASM := nasm
|
||||
WCC := wcc
|
||||
WLINK := wlink
|
||||
QEMU := qemu-system-i386
|
||||
DD := dd
|
||||
|
||||
# Flags
|
||||
NASM_BIN := -f bin
|
||||
NASM_OBJ := -f obj
|
||||
WCC_FLAGS := -ms -0 -wx -s -ecc # small model, 8086, warnings, no stack check, cdecl
|
||||
QEMU_FLAGS = -fda $(IMG) -monitor stdio
|
||||
|
||||
# Output names
|
||||
BOOT_SRC := boot.asm
|
||||
ENTRY_SRC := entry.asm
|
||||
KMAIN_SRC := kmain.c
|
||||
LINK_FILE := kernel.lnk
|
||||
|
||||
BOOT_BIN := bootloader.bin
|
||||
ENTRY_OBJ := entry.obj
|
||||
KMAIN_OBJ := kmain.obj
|
||||
KERNEL_BIN := kernel.bin
|
||||
IMG := floppy.img
|
||||
|
||||
BIOS_SRC := bios.asm
|
||||
BIOS_OBJ := bios.obj
|
||||
|
||||
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Default target
|
||||
# -------------------------------------------------------
|
||||
.PHONY: all clean run debug
|
||||
|
||||
all: $(IMG)
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Bootloader — flat binary
|
||||
# -------------------------------------------------------
|
||||
$(BOOT_BIN): $(BOOT_SRC)
|
||||
$(NASM) $(NASM_BIN) $< -o $@
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Kernel entry point — OMF object
|
||||
# -------------------------------------------------------
|
||||
$(ENTRY_OBJ): $(ENTRY_SRC)
|
||||
$(NASM) $(NASM_OBJ) $< -o $@
|
||||
|
||||
# -------------------------------------------------------
|
||||
# C kernel — OMF object via OpenWatcom
|
||||
# -------------------------------------------------------
|
||||
$(KMAIN_OBJ): $(KMAIN_SRC)
|
||||
$(WCC) $< $(WCC_FLAGS) -fo=$@
|
||||
|
||||
$(BIOS_OBJ): $(BIOS_SRC)
|
||||
$(NASM) $(NASM_OBJ) $< -o $@
|
||||
|
||||
$(KERNEL_BIN): $(ENTRY_OBJ) $(BIOS_OBJ) $(KMAIN_OBJ) $(LINK_FILE)
|
||||
$(WLINK) @$(LINK_FILE)
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Floppy image
|
||||
# -------------------------------------------------------
|
||||
$(IMG): $(BOOT_BIN) $(KERNEL_BIN)
|
||||
$(DD) if=/dev/zero of=$@ bs=512 count=2880
|
||||
$(DD) if=$(BOOT_BIN) of=$@ conv=notrunc
|
||||
$(DD) if=$(KERNEL_BIN) of=$@ seek=1 conv=notrunc bs=512
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Run in QEMU
|
||||
# -------------------------------------------------------
|
||||
run: $(IMG)
|
||||
$(QEMU) $(QEMU_FLAGS)
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Debug — QEMU with GDB stub and interrupt logging
|
||||
# -------------------------------------------------------
|
||||
debug: $(IMG)
|
||||
$(QEMU) $(QEMU_FLAGS) \
|
||||
-s -S \
|
||||
-d int \
|
||||
-D qemu.log
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Clean
|
||||
# -------------------------------------------------------
|
||||
clean:
|
||||
rm -f $(BOOT_BIN) $(ENTRY_OBJ) $(KMAIN_OBJ) $(KERNEL_BIN) $(IMG) $(BIOS_OBJ)\
|
||||
kernel.map qemu.log
|
||||
58
bios.asm
Normal file
58
bios.asm
Normal file
@@ -0,0 +1,58 @@
|
||||
[BITS 16]
|
||||
|
||||
global _print_char
|
||||
global _get_char
|
||||
global _check_key
|
||||
global _set_cursor
|
||||
global _get_cursor_pos
|
||||
global _set_cursor_pos
|
||||
segment _TEXT class=CODE
|
||||
|
||||
_print_char:
|
||||
push bp
|
||||
mov bp, sp
|
||||
mov ah, 0x0E ; BIOS TTY write
|
||||
mov al, [bp+4] ; first arg: char c
|
||||
xor bh, bh ; page 0
|
||||
int 0x10
|
||||
pop bp
|
||||
ret
|
||||
_get_char:
|
||||
; Returns: AL = ASCII char, AH = scancode
|
||||
; Blocks until a key is pressed
|
||||
xor ah, ah ; Function 0: wait for keypress
|
||||
int 0x16
|
||||
xor ah, ah
|
||||
ret
|
||||
|
||||
_check_key:
|
||||
; Non-blocking: returns ZF=1 if no key waiting
|
||||
mov ah, 0x01 ; Function 1: check buffer
|
||||
int 0x16
|
||||
jz .empty
|
||||
mov ax, 1
|
||||
ret ; ZF=0 means key available, AL/AH = key
|
||||
.empty:
|
||||
xor ax, ax
|
||||
ret
|
||||
_set_cursor:
|
||||
mov ah, 0x01
|
||||
mov cx, 0x0607
|
||||
ret
|
||||
_get_cursor_pos:
|
||||
mov ah, 0x03
|
||||
xor bh, bh
|
||||
int 0x10 ; DH = row, DL = col
|
||||
mov ax, dx ; DH->AH, DL->AL in one shot
|
||||
ret
|
||||
|
||||
_set_cursor_pos:
|
||||
push bp
|
||||
mov bp, sp
|
||||
mov ah, 0x02 ; AH=02h: set cursor position
|
||||
xor bh, bh ; page 0
|
||||
mov dh, [bp+4] ; row
|
||||
mov dl, [bp+6] ; col
|
||||
int 0x10
|
||||
pop bp
|
||||
ret
|
||||
70
boot.asm
Normal file
70
boot.asm
Normal file
@@ -0,0 +1,70 @@
|
||||
[BITS 16]
|
||||
[ORG 0x7C00]
|
||||
|
||||
KERNEL_SEGMENT equ 0x1000
|
||||
KERNEL_SECTORS equ 32
|
||||
boot:
|
||||
jmp 0x0000: .init
|
||||
.init:
|
||||
cli
|
||||
xor ax,ax
|
||||
mov ds,ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
mov sp, 0x7C00
|
||||
sti
|
||||
|
||||
mov [boot_drive], dl
|
||||
xor ax,ax
|
||||
int 0x13
|
||||
|
||||
jc .disk_error
|
||||
|
||||
call load_kernel
|
||||
|
||||
mov ax, KERNEL_SEGMENT
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
|
||||
jmp KERNEL_SEGMENT:0x0000
|
||||
|
||||
.disk_error:
|
||||
mov si, disk_err
|
||||
call print_str
|
||||
cli
|
||||
hlt
|
||||
load_kernel:
|
||||
mov ax, KERNEL_SEGMENT
|
||||
mov es,ax
|
||||
xor bx, bx
|
||||
|
||||
mov ah, 0x02
|
||||
mov al, KERNEL_SECTORS
|
||||
mov ch, 0
|
||||
mov cl, 2
|
||||
mov dh, 0
|
||||
mov dl, [boot_drive]
|
||||
int 0x13
|
||||
jc .disk_error
|
||||
ret
|
||||
.disk_error:
|
||||
mov si, disk_err
|
||||
call print_str
|
||||
cli
|
||||
hlt
|
||||
|
||||
|
||||
print_str:
|
||||
lodsb
|
||||
or al, al
|
||||
jz .done
|
||||
mov ah, 0x0E
|
||||
int 0x10
|
||||
jmp print_str
|
||||
.done:
|
||||
ret
|
||||
|
||||
boot_drive: db 0
|
||||
disk_err: db "Disk error", 0x0D, 0X0A, 0
|
||||
times 510 - ($-$$) db 0
|
||||
dw 0xAA55
|
||||
28
entry.asm
Normal file
28
entry.asm
Normal file
@@ -0,0 +1,28 @@
|
||||
[BITS 16]
|
||||
|
||||
|
||||
|
||||
extern _kmain
|
||||
|
||||
global kernel_entry
|
||||
global _small_code_ ; Watcom small model expects this
|
||||
|
||||
segment _TEXT class=CODE
|
||||
|
||||
_small_code_: ; Must be at start of CODE segment
|
||||
kernel_entry:
|
||||
cli
|
||||
mov ax, 0x1000
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
mov sp, 0x7000 ; Just use a fixed address for stack
|
||||
xor bp, bp
|
||||
sti
|
||||
call _kmain
|
||||
.halt:
|
||||
cli
|
||||
hlt
|
||||
jmp .halt
|
||||
segment _BSS class=BSS
|
||||
resb 4096
|
||||
10
kernel.lnk
Normal file
10
kernel.lnk
Normal file
@@ -0,0 +1,10 @@
|
||||
FORMAT RAW BIN
|
||||
ORDER CLNAME CODE CLNAME DATA CLNAME BSS
|
||||
OPTION OFFSET=0x0000
|
||||
OPTION MAP=kernel.map
|
||||
OPTION STACK=4096
|
||||
OPTION NODEFAULTLIBS
|
||||
FILE entry.obj
|
||||
FILE bios.obj
|
||||
FILE kmain.obj
|
||||
NAME kernel.bin
|
||||
79
kmain.c
Normal file
79
kmain.c
Normal file
@@ -0,0 +1,79 @@
|
||||
#define BUF_SIZE 64
|
||||
#define HEAP_SIZE 8192
|
||||
static char heap[HEAP_SIZE];
|
||||
static int heap_top = 0;
|
||||
|
||||
void* kmalloc(int size) {
|
||||
void* ptr;
|
||||
if (heap_top + size > HEAP_SIZE) return 0;
|
||||
ptr = &heap[heap_top];
|
||||
heap_top += size;
|
||||
return ptr;
|
||||
}
|
||||
void print_char(char c);
|
||||
char get_char(void);
|
||||
int check_key(void);
|
||||
void set_cursor(void);
|
||||
void set_cursor_pos(char row, char col);
|
||||
int get_cursor_pos();
|
||||
int str_eq(char* a, char* b) {
|
||||
int i = 0;
|
||||
while (a[i] && b[i]) {
|
||||
if (a[i] != b[i]) return 0;
|
||||
i++;
|
||||
}
|
||||
return a[i] == b[i];
|
||||
}
|
||||
void print_string(char* str){
|
||||
int i = 0;
|
||||
while (str[i] != '\0'){
|
||||
print_char(str[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
void print_hex(unsigned int n) {
|
||||
char hex[] = "0x0000";
|
||||
int i;
|
||||
int nibble;
|
||||
for (i = 5; i >= 2; i--) {
|
||||
nibble = n & 0xF;
|
||||
hex[i] = nibble < 10 ? '0' + nibble : 'A' + nibble - 10;
|
||||
n >>= 4;
|
||||
}
|
||||
print_string(hex);
|
||||
}
|
||||
|
||||
|
||||
void read_line(char* buf) {
|
||||
int i = 0;
|
||||
char c;
|
||||
while (i < BUF_SIZE - 1) {
|
||||
c = get_char();
|
||||
if (c == '\r') break; /* Enter */
|
||||
if (c == '\b' && i > 0) { /* Backspace */
|
||||
i--;
|
||||
print_char('\b');
|
||||
print_char(' ');
|
||||
print_char('\b');
|
||||
} else {
|
||||
buf[i++] = c;
|
||||
print_char(c); /* echo */
|
||||
}
|
||||
}
|
||||
buf[i] = '\0';
|
||||
}
|
||||
void kmain(void) {
|
||||
char buf[BUF_SIZE];
|
||||
set_cursor();
|
||||
print_string("senkOS> ");
|
||||
while (1) {
|
||||
read_line(buf);
|
||||
print_char('\n');
|
||||
if (str_eq(buf, "hello")) {
|
||||
print_string("world\n");
|
||||
} else {
|
||||
print_string("unknown command\n");
|
||||
}
|
||||
print_string("senkOS> ");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user