rearraged files, set up to use grub bootloader

This commit is contained in:
2026-06-10 18:28:33 -05:00
parent 0f8d5f8ce7
commit eb1e096bac
19 changed files with 270 additions and 386 deletions

7
.gitignore vendored
View File

@@ -1,8 +1,11 @@
*.iso *.iso
isodir *.img
sysroot *.o
*.bin
*.elf
.idea .idea
.vscode .vscode
build build
isodir

View File

@@ -1,14 +0,0 @@
ENTRY(_start)
SECTIONS
{
. = 0x7C00;
.text : {
*(.text)
}
.data : {
*(.data)
}
}

View File

@@ -1,129 +0,0 @@
.code16
.text
.global _start
_start:
ljmp $0x07C0, $something
something:
cli
cld
mov %cs, %ax
mov %ax, %ds
mov %ax, %es
# stack stuff
mov $0x0000, %ax
mov %ax, %ss
mov $0xFFF0, %sp
# copy the first 12 bytes of our MBR table entry
mov %dl, (disk_number)
mov $mbr_entry, %di
mov $12, %cx
rep movsb
mov $0, %ah
int $0x13
mov $0x08, %ah
int $0x13
and 0b00111111, %cl
mov %cl, (total_sectors)
mov %ch, (total_cylinders)
mov %dh, (total_heads)
mov $0x1000, %ax
mov %ax, %es
mov $0x0000, %bx
mov (disk_number), %dl
mov $0, %ch #cylinder
mov $0, %dh #head
mov $2, %cl #sector
load_sector:
mov $1, %al
mov $0x02, %ah
int $0x13
mov (kernel_sectors), %ax
cmp $0xffff, %ax
jne check_last_sector
mov %es:20, %eax
shr $9, %eax
inc %eax
check_last_sector:
dec %ax
mov %ax, kernel_sectors
cmp $0, %ax
je done
move: # inc our offset. If it hits 0, we've moved a segment, inc that too.
add $512, %bx
cmp $0, %bx
jnz read_next_sector
mov %es, %ax
add $1000, %ax
mov %ax, %es
read_next_sector: # find the next valid sector, head, cylinder combo on the disk
inc %cl
mov (total_sectors), %al
cmp %al, %cl
jle load_sector
mov $1, %cl #go back to sector 1.. of the next head
inc %dh #next head
mov (total_heads), %al
cmp %al, %dh
jle load_sector
mov $0, %dh # go back to head 0.. of the next cylinder
inc %ch # next cylinder
mov (total_cylinders), %al
cmp %al, %ch
jle load_sector
# no more disk... fall through
done:
mov $0, %ah
int $0x13
mov $0x1000, %ax
mov %ax, %ds
ljmp $0x1000, $0x0000
disk_number:
.byte 0
total_cylinders:
.byte 0
total_heads:
.byte 0
total_sectors:
.byte 0
kernel_sectors:
.word 0xFFFF
mbr_entry:
partition_status:
.byte 0
partition_start_chs:
.byte 0
.byte 0
.byte 0
partition_type:
.byte 0
partition_stop_chs:
.byte 0
.byte 0
.byte 0
partition_start_lba:
.long 0
partition_start_length:
.long 0
.org 510
magic:
.word 0xAA55

View File

@@ -1,45 +1,19 @@
[ [
{ {
"file": "boot.s", "file": "kernel/kmain.c",
"arguments": [ "arguments": [
"/home/slinky/opt/cross/bin/i686-elf-gcc", "/home/slinky/opt/cross/bin/i686-elf-gcc",
"-m32",
"-c", "-c",
"boot.s", "kernel/kmain.c",
"-o", "-o",
"boot.o" "obj/kernel/kmain.o",
],
"directory": "/home/slinky/source/RockOS",
"output": "boot.o"
},
{
"file": "prekernel.s",
"arguments": [
"/home/slinky/opt/cross/bin/i686-elf-gcc",
"-m32",
"-c",
"prekernel.s",
"-o",
"prekernel.o"
],
"directory": "/home/slinky/source/RockOS",
"output": "prekernel.o"
},
{
"file": "kmain.c",
"arguments": [
"/home/slinky/opt/cross/bin/i686-elf-gcc",
"-m32",
"-ffreestanding", "-ffreestanding",
"-O2", "-O2",
"-Wall", "-Wall",
"-Wextra", "-Wextra",
"-c", "-Ikernel"
"kmain.c",
"-o",
"kmain.o"
], ],
"directory": "/home/slinky/source/RockOS", "directory": "/home/slinky/source/RockOS",
"output": "kmain.o" "output": "obj/kernel/kmain.o"
} }
] ]

3
grub.cfg Normal file
View File

@@ -0,0 +1,3 @@
menuentry "RockOS" {
multiboot /boot/rockos
}

28
kernel/boot/boot.s Normal file
View File

@@ -0,0 +1,28 @@
.set ALIGN, 1<<0 /* align loaded modules on page boundaries */
.set MEMINFO, 1<<1 /* provide memory map */
.set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */
.set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */
.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */
.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
.section .bss
.align 16
stack_bottom:
.skip 16384 # 16 KiB
stack_top:
.section .text
.global _start
.type _start, @function
_start:
mov $stack_top, %esp
call kernel_main
cli
1: hlt
jmp 1b

View File

@@ -0,0 +1,72 @@
#include <stddef.h>
#include <stdint.h>
#include <lib/stream.h>
#define VGA_WIDTH 80
#define VGA_HEIGHT 25
#define VGA_MEMORY 0xB8000
enum vga_color {
VGA_COLOR_BLACK = 0,
VGA_COLOR_BLUE = 1,
VGA_COLOR_GREEN = 2,
VGA_COLOR_CYAN = 3,
VGA_COLOR_RED = 4,
VGA_COLOR_MAGENTA = 5,
VGA_COLOR_BROWN = 6,
VGA_COLOR_LIGHT_GREY = 7,
VGA_COLOR_DARK_GREY = 8,
VGA_COLOR_LIGHT_BLUE = 9,
VGA_COLOR_LIGHT_GREEN = 10,
VGA_COLOR_LIGHT_CYAN = 11,
VGA_COLOR_LIGHT_RED = 12,
VGA_COLOR_LIGHT_MAGENTA = 13,
VGA_COLOR_LIGHT_BROWN = 14,
VGA_COLOR_WHITE = 15,
};
size_t terminal_row;
size_t terminal_column;
uint8_t terminal_color;
uint16_t* terminal_buffer = (uint16_t*)VGA_MEMORY;
static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg)
{
return fg | bg << 4;
}
static inline uint16_t vga_entry(unsigned char uc, uint8_t color)
{
return (uint16_t) uc | (uint16_t) color << 8;
}
void vga_initialize()
{
terminal_row = 0;
terminal_column = 0;
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
for (size_t y = 0; y < VGA_HEIGHT; y++) {
for (size_t x = 0; x < VGA_WIDTH; x++) {
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = vga_entry(' ', terminal_color);
}
}
}
void vga_putchar(char c)
{
const size_t index = terminal_row * VGA_WIDTH + terminal_column;
terminal_buffer[index] = vga_entry(c, terminal_color);
if (++terminal_column == VGA_WIDTH) {
terminal_column = 0;
if (++terminal_row == VGA_HEIGHT)
terminal_row = 0;
}
}
print_stream_t vga_print_stream = {
.putchar = vga_putchar,
.trunc = vga_initialize,
};

62
kernel/gdt.c Normal file
View File

@@ -0,0 +1,62 @@
#include <stdint.h>
#define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type (0 for system, 1 for code/data)
#define SEG_PRES(x) ((x) << 0x07) // Present
#define SEG_SAVL(x) ((x) << 0x0C) // Available for system use
#define SEG_LONG(x) ((x) << 0x0D) // Long mode
#define SEG_SIZE(x) ((x) << 0x0E) // Size (0 for 16-bit, 1 for 32)
#define SEG_GRAN(x) ((x) << 0x0F) // Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB)
#define SEG_PRIV(x) (((x) & 0x03) << 0x05) // Set privilege level (0 - 3)
#define SEG_DATA_RD 0x00 // Read-Only
#define SEG_DATA_RDA 0x01 // Read-Only, accessed
#define SEG_DATA_RDWR 0x02 // Read/Write
#define SEG_DATA_RDWRA 0x03 // Read/Write, accessed
#define SEG_DATA_RDEXPD 0x04 // Read-Only, expand-down
#define SEG_DATA_RDEXPDA 0x05 // Read-Only, expand-down, accessed
#define SEG_DATA_RDWREXPD 0x06 // Read/Write, expand-down
#define SEG_DATA_RDWREXPDA 0x07 // Read/Write, expand-down, accessed
#define SEG_CODE_EX 0x08 // Execute-Only
#define SEG_CODE_EXA 0x09 // Execute-Only, accessed
#define SEG_CODE_EXRD 0x0A // Execute/Read
#define SEG_CODE_EXRDA 0x0B // Execute/Read, accessed
#define SEG_CODE_EXC 0x0C // Execute-Only, conforming
#define SEG_CODE_EXCA 0x0D // Execute-Only, conforming, accessed
#define SEG_CODE_EXRDC 0x0E // Execute/Read, conforming
#define SEG_CODE_EXRDCA 0x0F // Execute/Read, conforming, accessed
#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
SEG_PRIV(0) | SEG_CODE_EXRD
#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
SEG_PRIV(0) | SEG_DATA_RDWR
#define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
SEG_PRIV(3) | SEG_CODE_EXRD
#define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
SEG_PRIV(3) | SEG_DATA_RDWR
uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag)
{
uint64_t descriptor;
// Create the high 32 bit segment
descriptor = limit & 0x000F0000; // set limit bits 19:16
descriptor |= (flag << 8) & 0x00F0FF00; // set type, p, dpl, s, g, d/b, l and avl fields
descriptor |= (base >> 16) & 0x000000FF; // set base bits 23:16
descriptor |= base & 0xFF000000; // set base bits 31:24
// Shift by 32 to allow for low part of segment
descriptor <<= 32;
// Create the low 32 bit segment
descriptor |= base << 16; // set base bits 15:0
descriptor |= limit & 0x0000FFFF; // set limit bits 15:0
return descriptor;
}

3
kernel/globals.c Normal file
View File

@@ -0,0 +1,3 @@
#include <lib/stream.h>
print_stream_t* kout;

View File

@@ -1,24 +0,0 @@
ENTRY(_start)
SECTIONS
{
. = 0x10000;
.text : {
*(.text)
}
.rodata : {
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
_end = .;
}

View File

@@ -1,28 +1,12 @@
#include <stdint.h> #include <lib/print.h>
#include <lib/stream.h>
extern void halt(); void kernel_main(void)
extern void idt_load(); {
extern void reboot(); extern print_stream_t vga_print_stream;
extern print_stream_t* kout;
kout = &vga_print_stream;
kout->trunc();
typedef struct { kprint("RockOS booting...");
uint16_t offset_low;
uint16_t selector;
uint8_t zero;
uint8_t flags;
uint16_t offset_high;
} idt_entry_t __attribute__((packed));
typedef struct {
uint16_t limit;
uint32_t base;
} idt_ptr_t;
idt_entry_t idt[256];
idt_ptr_t idtr;
void load_idt() {}
void kmain() {
load_idt();
halt();
} }

11
kernel/lib/print.c Normal file
View File

@@ -0,0 +1,11 @@
#include "print.h"
#include "stream.h"
extern print_stream_t* kout;
void kprint(const char *str) {
while (*str) {
kout->putchar(*str);
str++;
}
}

6
kernel/lib/print.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef KLIBPRINT_H
#define KLIBPRINT_H
void kprint(const char* str);
#endif

3
kernel/lib/stream.c Normal file
View File

@@ -0,0 +1,3 @@
#include "stream.h"
print_stream_t* pout;

9
kernel/lib/stream.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef KSTREAM_H
#define KSTREAM_H
typedef struct {
void (*putchar)(char c);
void (*trunc)();
} print_stream_t;
#endif

28
kernel/linker.ld Normal file
View File

@@ -0,0 +1,28 @@
ENTRY(_start)
SECTIONS
{
. = 2M;
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
}

View File

@@ -1,118 +0,0 @@
.code16
.text
.global _start
_start:
jmp everything
.org 20
.global kernel_size
kernel_size:
.long _end - _start
everything:
mov $0x1000, %ax
mov %ax, %es
mov %ax, %ds
# reset disk
mov $0, %ah
int $0x13
# stop the cursor
mov $1, %ah
mov $0,%cl
mov $0x20,%ch
int $0x11
# get the system memory, if this call fails then halt
clc
mov $0, %bx
mov $0xe801, %ax
int $0x15
jc halt
shr $10, %ax
shr $4, %bx
add %ax, %bx
mov %bx, total_mem_mb-_start
# vga text mode
mov $0x0003, %ax
int $0x10
enable_a20:
#enable the a20 gate
inb $0x92, %al
orb $2, %al
outb %al, $0x92
prep_protected:
cli
lgdt gdt_init-_start
mov %cr0, %eax
or $0x01, %eax
mov %eax, %cr0 # protected bit set
ljmpl $8, $protected
halt16:
jmp halt16
.code32
protected:
mov $16, %ax
mov %ax, %es
mov %ax, %ds
mov %ax, %ss
mov $5*8, %ax
ltr %ax
mov $0, %ax
mov %ax, %fs
mov %ax, %gs
mov $0xFFF0, %sp
mov $0xFFF0, %bp
ljmpl $8, $kmain
# some assembly stubs we can call from the kernel
.global idt_load
.extern idtr
idt_load:
lidt idtr
ret
.global reboot
reboot:
cli
lidt reboot_struct
int $1
reboot_struct:
.word 0
.long 0
.global halt
halt:
cli
hlt
jmp halt
# kernel data structures
.align 16
.global gdt
gdt:
.word 0,0,0,0
.word 0xffff, 0x0000, 0x9a00, 0x00cf
.word 0xffff, 0x0000, 0x9200, 0x00cf
.word 0xffff, 0x0000, 0xfa00, 0x00cf
.word 0xffff, 0x0000, 0xf200, 0x00cf
.word 0x0068, (tss-_start), 0x8901, 0x00cf
gdt_init:
.word gdt_init-gdt
.long gdt
.align 16
.global tss
tss:
.long 0
.global total_mem_mb
total_mem_mb:
.word 0

View File

@@ -1,55 +1,38 @@
CC = i686-elf-gcc CC = i686-elf-gcc
LD = i686-elf-ld LD = i686-elf-ld
OBJCOPY = i686-elf-objcopy
CFLAGS = -m32 -ffreestanding -O2 -Wall -Wextra -nostdlib OSNAME := rockos
ASFLAGS = -m32
BOOT_DIR := boot C_SOURCES := $(shell find kernel -type f -name '*.c')
KERNEL_DIR := kernel S_SOURCES := $(shell find kernel -type f -name '*.s')
BUILD_DIR := build
BOOT_BIN := $(BUILD_DIR)/boot.bin OBJECTS := $(patsubst %.c, obj/%.o, $(C_SOURCES)) $(patsubst %.s, obj/%.o, $(S_SOURCES))
KERNEL_BIN := $(BUILD_DIR)/kernel.bin
IMAGE := os.img
.PHONY: all clean run CFLAGS := -ffreestanding -O2 -Wall -Wextra -Ikernel
LDFLAGS := -T kernel/linker.ld
all: $(IMAGE) .PHONY: all run clean
$(BUILD_DIR)/%.o: $(BOOT_DIR)/%.s | $(BUILD_DIR) $(OSNAME).bin: $(OBJECTS)
$(CC) $(ASFLAGS) -c $< -o $@ $(LD) $(LDFLAGS) -o $@ $(OBJECTS)
$(BUILD_DIR)/%.o: $(KERNEL_DIR)/%.s | $(BUILD_DIR) $(OSNAME).iso: $(OSNAME).bin grub.cfg
$(CC) $(ASFLAGS) -c $< -o $@ mkdir -p isodir/boot/grub
cp $(OSNAME).bin isodir/boot/$(OSNAME)
cp grub.cfg isodir/boot/grub/grub.cfg
grub-mkrescue -o $(OSNAME).iso isodir
$(BUILD_DIR)/%.o: $(KERNEL_DIR)/%.c | $(BUILD_DIR) obj/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@ @mkdir -p $(dir $@)
$(CC) -c $< -o $@ $(CFLAGS)
$(BUILD_DIR)/boot.elf: $(BUILD_DIR)/boot.o $(BOOT_DIR)/boot.ld obj/%.o: %.s
$(LD) -T $(BOOT_DIR)/boot.ld -o $@ $(BUILD_DIR)/boot.o @mkdir -p $(dir $@)
$(CC) -c $< -o $@ $(CFLAGS)
$(BOOT_BIN): $(BUILD_DIR)/boot.elf run: $(OSNAME).iso
$(OBJCOPY) -O binary $< $@ qemu-system-i386 -cdrom $(OSNAME).iso
KERNEL_OBJS := $(BUILD_DIR)/prekernel.o $(BUILD_DIR)/kmain.o
$(BUILD_DIR)/kernel.elf: $(KERNEL_OBJS) $(KERNEL_DIR)/kernel.ld
$(LD) -T $(KERNEL_DIR)/kernel.ld -o $@ $(KERNEL_OBJS)
$(KERNEL_BIN): $(BUILD_DIR)/kernel.elf
$(OBJCOPY) -O binary $< $@
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
$(IMAGE): $(BOOT_BIN) $(KERNEL_BIN)
dd if=$(BOOT_BIN) of=$@ bs=512 count=1
dd if=$(KERNEL_BIN) of=$@ bs=512 seek=1
truncate -s 1440k $@
run: $(IMAGE)
qemu-system-i386 -drive format=raw,file=$(IMAGE)
clean: clean:
rm -rf $(BUILD_DIR) $(IMAGE) @echo "Cleaning up build artifacts..."
rm -rf $(OSNAME).iso $(OSNAME).bin obj isodir

BIN
os.img

Binary file not shown.