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