Merge branch 'feature/rewrite'
This commit is contained in:
commit
a6f98cddb6
|
@ -1,2 +1,2 @@
|
|||
i386-elf-toolchain-aur
|
||||
i386-elf-tools-aur-pkgs
|
||||
bin/
|
||||
obj/
|
83
Makefile
83
Makefile
|
@ -1,56 +1,67 @@
|
|||
# $@ = target file
|
||||
# $< = first dependency
|
||||
# $^ = all dependencies
|
||||
ASM := nasm
|
||||
|
||||
GDB = gdb
|
||||
CC := x86_64-elf-gcc
|
||||
CCFLAGS :=
|
||||
|
||||
C_FILES = $(shell find src/ -type f -name '*.c')
|
||||
CO_FILES = $(patsubst src/%.c, obj/%.o, $(C_FILES))
|
||||
ASM_FILES = $(shell find src/kernel/ -type f -name '*.asm')
|
||||
AO_FILES = $(patsubst src/kernel/%.asm, obj/kernel/%.o, $(ASM_FILES))
|
||||
ABIN_FILES = $(patsubst src/%.asm, bin/%.bin, $(ASM_FILES))
|
||||
LD := x86_64-elf-ld
|
||||
LDFLAGS :=
|
||||
|
||||
os-image.bin: bin/boot.bin bin/kernel.bin
|
||||
cat $^ > $@
|
||||
INCLUDE := include/
|
||||
|
||||
bin/boot.bin: src/boot/boot.asm bin/kernel.bin .FORCE
|
||||
sed -i.orig "s@CH_REPLACE_BOOTSECTORCOUNT@$(shell ./getinblocks.py $(shell du -b "bin/kernel.bin" | cut -f 1))@g" src/boot/kernel.asm
|
||||
nasm -Isrc/boot/ $< -f bin -o $@
|
||||
mv src/boot/kernel.asm.orig src/boot/kernel.asm
|
||||
# Target: kernel, type: C ASM
|
||||
kernel_c_source_files = $(shell find src/kernel/ -type f -name *.c)
|
||||
kernel_c_object_files = $(patsubst src/%.c,obj/%.o,$(kernel_c_source_files))
|
||||
kernel_asm_source_files = $(shell find src/kernel/ -type f -name *.asm)
|
||||
kernel_asm_object_files = $(patsubst src/%.asm,obj/%.o,$(kernel_asm_source_files))
|
||||
kernel_source_files = $(kernel_c_source_files) $(kernel_asm_object_files)
|
||||
kernel_object_files = $(kernel_c_object_files) $(kernel_asm_object_files)
|
||||
|
||||
.FORCE:
|
||||
# Target: libc, type: C ASM
|
||||
libc_c_source_files = $(shell find src/libc/ -type f -name *.c)
|
||||
libc_c_object_files = $(patsubst src/%.c,obj/%.o,$(libc_c_source_files))
|
||||
libc_asm_source_files = $(shell find src/libc/ -type f -name *.asm)
|
||||
libc_asm_object_files = $(patsubst src/%.asm,obj/%.o,$(libc_c_object_files))
|
||||
libc_source_files = $(libc_c_source_files) $(libc_asm_source_files)
|
||||
libc_object_files = $(libc_c_object_files) $(libc_asm_object_files)
|
||||
|
||||
bin/kernel.bin: obj/kernel/entry.o ${CO_FILES} ${AO_FILES}
|
||||
i386-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
|
||||
# Target: sboot, type: ASM
|
||||
# Override: 32-bit
|
||||
sboot_asm_source_files = $(shell find src/boot/ -type f -name *.asm)
|
||||
sboot_asm_object_files = $(patsubst src/%.asm,obj/%.o,$(sboot_asm_source_files))
|
||||
sboot_source_files = $(sboot_asm_source_files)
|
||||
sboot_object_files = $(sboot_asm_object_files)
|
||||
|
||||
kernel.elf: obj/kernel/entry.o ${CO_FILES} ${AO_FILES}
|
||||
i386-elf-ld -o $@ -Ttext 0x1000 $^
|
||||
shade_bin_ldfile = src/linker.ld
|
||||
|
||||
run: clean os-image.bin
|
||||
qemu-system-x86_64 -hdd os-image.bin
|
||||
default: run
|
||||
|
||||
debug: clean os-image.bin kernel.elf
|
||||
qemu-system-x86_64 -s -S -hdd os-image.bin &
|
||||
${GDB} os-image.bin -ex "symbol-file kernel.elf" -ex "target remote localhost:1234"
|
||||
bin/shade.iso: bin/shade.bin
|
||||
cp bin/shade.bin src/iso/boot/shade.bin
|
||||
grub-mkrescue src/iso/ -o $@
|
||||
rm src/iso/boot/shade.bin
|
||||
|
||||
bin/shade.bin: $(sboot_object_files) $(kernel_object_files) $(libc_object_files)
|
||||
mkdir -p "$(@D)"
|
||||
$(LD) $(LDFLAGS) -n -T $(shade_bin_ldfile) $^ -o $@
|
||||
grub-file --is-x86-multiboot2 $@
|
||||
|
||||
# Generics
|
||||
# Source file types: C ASM
|
||||
|
||||
# C
|
||||
obj/%.o: src/%.c
|
||||
mkdir -p "$(@D)"
|
||||
i386-elf-gcc -g -ffreestanding -c $< -o $@
|
||||
$(CC) $(CCFLAGS) -I $(INCLUDE) -ffreestanding -c $< -o $@
|
||||
|
||||
# ASM
|
||||
obj/%.o: src/%.asm
|
||||
mkdir -p "$(@D)"
|
||||
nasm -f elf $< -o $@
|
||||
$(ASM) -felf64 $< -o $@
|
||||
|
||||
bin/%.bin: src/%.asm
|
||||
mkdir -p "$(@D)"
|
||||
nasm -f bin $< -o $@
|
||||
# Other
|
||||
run: clean bin/shade.iso
|
||||
qemu-system-x86_64 -drive file=bin/shade.iso,index=0,media=disk,format=raw
|
||||
|
||||
clean:
|
||||
find obj -type f -name '*.o' -exec rm {} +
|
||||
find obj -type f -name '*.bin' -exec rm {} +
|
||||
find bin -type f -name '*.o' -exec rm {} +
|
||||
find bin -type f -name '*.bin' -exec rm {} +
|
||||
find . -type f -name '*.dis' -exec rm {} +
|
||||
rm -f kernel.elf
|
||||
rm -rf bin/*
|
||||
rm -rf obj/*
|
BIN
bin/kernel.bin
BIN
bin/kernel.bin
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,57 @@
|
|||
# configuration file generated by Bochs
|
||||
plugin_ctrl: unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, iodebug=true, pcidev=false, usb_uhci=false
|
||||
config_interface: textconfig
|
||||
display_library: x
|
||||
memory: host=32, guest=32
|
||||
romimage: file="/usr/share/bochs/BIOS-bochs-latest", address=0x00000000, options=none
|
||||
vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest"
|
||||
boot: floppy
|
||||
floppy_bootsig_check: disabled=0
|
||||
floppya: type=1_44
|
||||
# no floppyb
|
||||
ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
|
||||
ata0-master: type=disk, path="bin/shade.iso", mode=flat, cylinders=0, heads=0, spt=0, sect_size=512, model="Generic 1234", biosdetect=auto, translation=auto
|
||||
ata0-slave: type=none
|
||||
ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15
|
||||
ata1-master: type=none
|
||||
ata1-slave: type=none
|
||||
ata2: enabled=false
|
||||
ata3: enabled=false
|
||||
optromimage1: file=none
|
||||
optromimage2: file=none
|
||||
optromimage3: file=none
|
||||
optromimage4: file=none
|
||||
optramimage1: file=none
|
||||
optramimage2: file=none
|
||||
optramimage3: file=none
|
||||
optramimage4: file=none
|
||||
pci: enabled=1, chipset=i440fx, slot1=none, slot2=none, slot3=none, slot4=none, slot5=none
|
||||
vga: extension=vbe, update_freq=5, realtime=1, ddc=builtin
|
||||
cpu: count=1:1:1, ips=4000000, quantum=16, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
|
||||
cpuid: level=6, stepping=3, model=3, family=6, vendor_string="AuthenticAMD", brand_string="AMD Athlon(tm) processor"
|
||||
cpuid: mmx=true, apic=xapic, simd=sse2, sse4a=false, misaligned_sse=false, sep=true
|
||||
cpuid: movbe=false, adx=false, aes=false, sha=false, xsave=false, xsaveopt=false, avx_f16c=false
|
||||
cpuid: avx_fma=false, bmi=0, xop=false, fma4=false, tbm=false, x86_64=true, 1g_pages=false
|
||||
cpuid: pcid=false, fsgsbase=false, smep=false, smap=false, mwait=true
|
||||
print_timestamps: enabled=0
|
||||
debugger_log: -
|
||||
magic_break: enabled=0
|
||||
port_e9_hack: enabled=0
|
||||
private_colormap: enabled=0
|
||||
clock: sync=none, time0=local, rtc_sync=0
|
||||
# no cmosimage
|
||||
log: -
|
||||
logprefix: %t%e%d
|
||||
debug: action=ignore
|
||||
info: action=report
|
||||
error: action=report
|
||||
panic: action=ask
|
||||
keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none
|
||||
mouse: type=ps2, enabled=false, toggle=ctrl+mbutton
|
||||
speaker: enabled=true, mode=system
|
||||
parport1: enabled=true, file=none
|
||||
parport2: enabled=false
|
||||
com1: enabled=true, mode=null
|
||||
com2: enabled=false
|
||||
com3: enabled=false
|
||||
com4: enabled=false
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,56 @@
|
|||
# $@ = target file
|
||||
# $< = first dependency
|
||||
# $^ = all dependencies
|
||||
|
||||
GDB = gdb
|
||||
|
||||
C_FILES = $(shell find src/ -type f -name '*.c')
|
||||
CO_FILES = $(patsubst src/%.c, obj/%.o, $(C_FILES))
|
||||
ASM_FILES = $(shell find src/kernel/ -type f -name '*.asm')
|
||||
AO_FILES = $(patsubst src/kernel/%.asm, obj/kernel/%.o, $(ASM_FILES))
|
||||
ABIN_FILES = $(patsubst src/%.asm, bin/%.bin, $(ASM_FILES))
|
||||
|
||||
os-image.bin: bin/boot.bin bin/kernel.bin
|
||||
cat $^ > $@
|
||||
|
||||
bin/boot.bin: src/boot/boot.asm bin/kernel.bin .FORCE
|
||||
sed -i.orig "s@CH_REPLACE_BOOTSECTORCOUNT@$(shell ./getinblocks.py $(shell du -b "bin/kernel.bin" | cut -f 1))@g" src/boot/kernel.asm
|
||||
nasm -Isrc/boot/ $< -f bin -o $@
|
||||
mv src/boot/kernel.asm.orig src/boot/kernel.asm
|
||||
|
||||
.FORCE:
|
||||
|
||||
bin/kernel.bin: obj/kernel/entry.o ${CO_FILES} ${AO_FILES}
|
||||
i386-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
|
||||
|
||||
kernel.elf: obj/kernel/entry.o ${CO_FILES} ${AO_FILES}
|
||||
i386-elf-ld -o $@ -Ttext 0x1000 $^
|
||||
|
||||
run: clean os-image.bin
|
||||
qemu-system-x86_64 -hdd os-image.bin -d int
|
||||
|
||||
debug: clean os-image.bin kernel.elf
|
||||
qemu-system-x86_64 -s -S -hdd os-image.bin &
|
||||
${GDB} os-image.bin -ex "symbol-file kernel.elf" -ex "target remote localhost:1234"
|
||||
|
||||
|
||||
|
||||
obj/%.o: src/%.c
|
||||
mkdir -p "$(@D)"
|
||||
i386-elf-gcc -g -ffreestanding -c $< -o $@
|
||||
|
||||
obj/%.o: src/%.asm
|
||||
mkdir -p "$(@D)"
|
||||
nasm -f elf $< -o $@
|
||||
|
||||
bin/%.bin: src/%.asm
|
||||
mkdir -p "$(@D)"
|
||||
nasm -f bin $< -o $@
|
||||
|
||||
clean:
|
||||
find obj -type f -name '*.o' -exec rm {} +
|
||||
find obj -type f -name '*.bin' -exec rm {} +
|
||||
find bin -type f -name '*.o' -exec rm {} +
|
||||
find bin -type f -name '*.bin' -exec rm {} +
|
||||
find . -type f -name '*.dis' -exec rm {} +
|
||||
rm -f kernel.elf
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,3 +1,4 @@
|
|||
|
||||
gdt_start: ; use labels to compute sizes and jumps
|
||||
; gdt starts with 8 byte null
|
||||
dd 0x0
|
||||
|
@ -14,12 +15,12 @@ gdt_code:
|
|||
|
||||
; GDT for data segment
|
||||
gdt_data:
|
||||
dw 0xffff
|
||||
dw 0x0
|
||||
db 0x0
|
||||
db 10010010b
|
||||
db 11001111b
|
||||
db 0x0
|
||||
dw 0xffff ; segment length
|
||||
dw 0x0 ; segment base
|
||||
db 0x0 ; segment base
|
||||
db 10010010b ; flags
|
||||
db 11001111b ; flags + segment length
|
||||
db 0x0 ; segment base
|
||||
|
||||
gdt_end:
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
#include "./platform/drivers/ports.h"
|
||||
#include "print.h"
|
||||
#include "./platform/types.h"
|
||||
#include "./platform/interrupts/int.h"
|
||||
|
||||
void dummy_test_entrypoint() {}
|
||||
|
||||
void kernel_welcome() {
|
||||
print_str("Welcome to ");
|
||||
print_set_color(PRINT_COLOR_CYAN, PRINT_COLOR_BLACK);
|
||||
print_str("Shade");
|
||||
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
|
||||
print_str("!\n");
|
||||
|
||||
print_str("shadeOS kernel version ");
|
||||
|
||||
print_set_color(PRINT_COLOR_YELLOW, PRINT_COLOR_BLACK);
|
||||
print_str("0.2.2");
|
||||
|
||||
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
|
||||
print_newline();
|
||||
|
||||
print_str("Running on ");
|
||||
|
||||
print_set_color(PRINT_COLOR_YELLOW, PRINT_COLOR_BLACK);
|
||||
print_str("shade-development");
|
||||
|
||||
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
|
||||
|
||||
print_newline();
|
||||
}
|
||||
|
||||
// kMain
|
||||
void main() {
|
||||
// Initialize screen buffer
|
||||
struct Char* buffer = (struct Char*) 0xb8000;
|
||||
|
||||
clear_all(); // Clear screen
|
||||
set_cursor_pos(0, 0); // Set cursor position
|
||||
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK); // Set print color
|
||||
|
||||
// welcome messages
|
||||
kernel_msg_ok("Initialized display successfully\n");
|
||||
kernel_welcome();
|
||||
|
||||
print_str("Copyright (c) e3team 2022. All rights reserved.\n");
|
||||
print_str("This program is provided \"as-is\" and no express or implied warranty is provided.\n");
|
||||
print_str("The full license can be found at /sys/LICENCE on this system or ./LICENCE in the source tree.\n");
|
||||
|
||||
idt_init();
|
||||
kernel_msg_ok("Interrupts initialized");
|
||||
|
||||
__asm__ __volatile__("int $2");
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
unsigned char port_byte_in(unsigned short port);
|
||||
void port_byte_out(unsigned short port, unsigned char data);
|
||||
unsigned short port_word_in(unsigned short port);
|
||||
void port_word_out(unsigned short port, unsigned short data);
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef GDT_H
|
||||
#define GDT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// the GDT descriptor format makes literally no sense, who came up with this
|
||||
typedef struct {
|
||||
uint16_t limit_low16; // Low 16 bits of limit
|
||||
uint16_t base_low16; // Low 16 bits of base
|
||||
uint8_t base_mid8; // Middle 8 bits of base
|
||||
uint8_t access; // 7: present, 6-5: priv level, 4: type, 3: executable, 2: dc, 1: rw, 0: accessed (zero)
|
||||
uint8_t limit_flags; // High 4 bits of limit AND flags (?? why). flags: 3: granularity, 2: size, 1: long, 0: reserved
|
||||
uint8_t base_high8; // High 8 bits of base
|
||||
} __attribute__((packed)) gdt_entry_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t size; // GDT size (bytes) - 1
|
||||
uint32_t offset; // Address of element 0 of the GDT
|
||||
} __attribute__((packed)) gdt_ptr_t;
|
||||
|
||||
static gdt_entry_t gdt[8192];
|
||||
static gdt_ptr_t gdtr;
|
||||
|
||||
void init_gdt();
|
||||
void gdt_set_segment(int limit, int base, int access);
|
||||
void load_gdt();
|
||||
|
||||
#endif
|
|
@ -1,8 +1,14 @@
|
|||
#include "int.h"
|
||||
#include "../../print.h"
|
||||
|
||||
void exception_handler() {
|
||||
int count = 0;
|
||||
|
||||
void exception_handler(registers_t r) {
|
||||
print_str("I");
|
||||
count++;
|
||||
if (count > 4) {
|
||||
__asm__ __volatile__("cli; hlt");
|
||||
}
|
||||
}
|
||||
|
||||
void idt_set_descriptor(u8 vector, void* isr, u8 flags) {
|
|
@ -21,8 +21,15 @@ typedef struct {
|
|||
|
||||
static idtr_t idtr;
|
||||
|
||||
typedef struct {
|
||||
u32 ds; /* Data segment selector */
|
||||
u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */
|
||||
u32 int_no, err_code; /* Interrupt number and error code (if applicable) */
|
||||
u32 eip, cs, eflags, useresp, ss; /* Pushed by the processor automatically */
|
||||
} registers_t;
|
||||
|
||||
__attribute__((noreturn))
|
||||
void exception_handler(void);
|
||||
void exception_handler(registers_t r);
|
||||
|
||||
void idt_set_descriptor(u8 vector, void* isr, u8 flags);
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
%macro isr_err_stub 1
|
||||
isr_stub_%+%1:
|
||||
push byte %1 ; Push interrupt no to stack
|
||||
|
||||
; 1. Save CPU state
|
||||
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
|
||||
mov ax, ds ; Lower 16-bits of eax = ds.
|
||||
push eax ; save the data segment descriptor
|
||||
mov ax, 0x10 ; kernel data segment descriptor
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; 2. Call C handler
|
||||
call exception_handler
|
||||
|
||||
; 3. Restore state
|
||||
pop eax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
popa
|
||||
add esp, 8 ; Cleans up the pushed error code and pushed ISR number
|
||||
sti
|
||||
iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
|
||||
%endmacro
|
||||
; if writing for 64-bit, use iretq instead
|
||||
%macro isr_no_err_stub 1
|
||||
isr_stub_%+%1:
|
||||
push byte 0 ; No error occured
|
||||
push byte %1 ; Push interrupt no to stack
|
||||
|
||||
; 1. Save CPU state
|
||||
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
|
||||
mov ax, ds ; Lower 16-bits of eax = ds.
|
||||
push eax ; save the data segment descriptor
|
||||
mov ax, 0x10 ; kernel data segment descriptor
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; 2. Call C handler
|
||||
call exception_handler
|
||||
|
||||
; 3. Restore state
|
||||
pop eax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
popa
|
||||
add esp, 8 ; Cleans up the pushed error code and pushed ISR number
|
||||
sti
|
||||
iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
|
||||
%endmacro
|
||||
|
||||
extern exception_handler
|
||||
|
||||
isr_no_err_stub 0
|
||||
isr_no_err_stub 1
|
||||
isr_no_err_stub 2
|
||||
isr_no_err_stub 3
|
||||
isr_no_err_stub 4
|
||||
isr_no_err_stub 5
|
||||
isr_no_err_stub 6
|
||||
isr_no_err_stub 7
|
||||
isr_err_stub 8
|
||||
isr_no_err_stub 9
|
||||
isr_err_stub 10
|
||||
isr_err_stub 11
|
||||
isr_err_stub 12
|
||||
isr_err_stub 13
|
||||
isr_err_stub 14
|
||||
isr_no_err_stub 15
|
||||
isr_no_err_stub 16
|
||||
isr_err_stub 17
|
||||
isr_no_err_stub 18
|
||||
isr_no_err_stub 19
|
||||
isr_no_err_stub 20
|
||||
isr_no_err_stub 21
|
||||
isr_no_err_stub 22
|
||||
isr_no_err_stub 23
|
||||
isr_no_err_stub 24
|
||||
isr_no_err_stub 25
|
||||
isr_no_err_stub 26
|
||||
isr_no_err_stub 27
|
||||
isr_no_err_stub 28
|
||||
isr_no_err_stub 29
|
||||
isr_err_stub 30
|
||||
isr_no_err_stub 31
|
||||
|
||||
global isr_stub_table
|
||||
isr_stub_table:
|
||||
%assign i 0
|
||||
%rep 32
|
||||
dd isr_stub_%+i ; use DQ instead if targeting 64-bit
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
#include "print.h"
|
||||
#include "./platform/drivers/ports.h"
|
||||
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
char color = PRINT_COLOR_WHITE | PRINT_COLOR_BLACK << 4;
|
||||
|
||||
void clear_row(int row) {
|
||||
struct Char* buffer = (struct Char*) 0xb8000;
|
||||
|
||||
struct Char empty = (struct Char) {
|
||||
character: ' ',
|
||||
color: color,
|
||||
};
|
||||
|
||||
for (int x = 0; x < NUM_COLS; x++) {
|
||||
buffer[x + NUM_COLS * row] = empty;
|
||||
}
|
||||
set_cursor_pos(col, row);
|
||||
}
|
||||
|
||||
void clear_all() {
|
||||
for (int i = 0; i < NUM_ROWS; i++) {
|
||||
clear_row(i);
|
||||
}
|
||||
set_cursor_pos(col, row);
|
||||
}
|
||||
|
||||
void print_newline() {
|
||||
struct Char* buffer = (struct Char*) 0xb8000;
|
||||
|
||||
col = 0;
|
||||
|
||||
if (row < NUM_ROWS - 1) {
|
||||
row++;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int row = 1; row < NUM_ROWS; row++) {
|
||||
for (int col = 0; col < NUM_COLS; col++) {
|
||||
struct Char character = buffer[col + NUM_COLS * row];
|
||||
buffer[col + NUM_COLS * (row - 1)] = character;
|
||||
}
|
||||
}
|
||||
|
||||
clear_row(NUM_COLS - 1);
|
||||
set_cursor_pos(col, row);
|
||||
}
|
||||
|
||||
void print_char(char character) {
|
||||
struct Char* buffer = (struct Char*) 0xb8000;
|
||||
|
||||
if (character == '\n') {
|
||||
print_newline();
|
||||
return;
|
||||
}
|
||||
|
||||
if (col > NUM_COLS) {
|
||||
print_newline();
|
||||
}
|
||||
|
||||
struct Char cr = (struct Char) {
|
||||
character: character,
|
||||
color: color,
|
||||
};
|
||||
buffer[col + NUM_COLS * row] = cr;
|
||||
|
||||
col++;
|
||||
set_cursor_pos(col, row);
|
||||
}
|
||||
|
||||
void print_str(char* str) {
|
||||
for (int i = 0; 1; i++) {
|
||||
char character = (char) str[i];
|
||||
|
||||
if (character == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
print_char(character);
|
||||
}
|
||||
}
|
||||
|
||||
void print_set_color(char foreground, char background) {
|
||||
color = foreground + (background << 4);
|
||||
}
|
||||
|
||||
void set_cursor_pos(int col, int row) {
|
||||
int offset = col + NUM_COLS * row;
|
||||
port_byte_out(REG_SCREEN_CTRL, 14);
|
||||
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8));
|
||||
port_byte_out(REG_SCREEN_CTRL, 15);
|
||||
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset & 0xff));
|
||||
}
|
||||
|
||||
void kernel_msg_ok(char* msg) {
|
||||
char ok_p1[] = "[ ";
|
||||
char ok_p2[] = "OK ";
|
||||
char ok_p3[] = "] ";
|
||||
|
||||
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
|
||||
print_str(ok_p1);
|
||||
|
||||
print_set_color(PRINT_COLOR_GREEN, PRINT_COLOR_BLACK);
|
||||
print_str(ok_p2);
|
||||
|
||||
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
|
||||
print_str(ok_p3);
|
||||
print_str(msg);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef PRINT_H
|
||||
#define PRINT_H
|
||||
#define REG_SCREEN_CTRL 0x3d4
|
||||
#define REG_SCREEN_DATA 0x3d5
|
||||
|
||||
enum {
|
||||
PRINT_COLOR_BLACK = 0,
|
||||
PRINT_COLOR_BLUE = 1,
|
||||
PRINT_COLOR_GREEN = 2,
|
||||
PRINT_COLOR_CYAN = 3,
|
||||
PRINT_COLOR_RED = 4,
|
||||
PRINT_COLOR_MAGENTA = 5,
|
||||
PRINT_COLOR_BROWN = 6,
|
||||
PRINT_COLOR_LIGHT_GRAY = 7,
|
||||
PRINT_COLOR_DARK_GRAY = 8,
|
||||
PRINT_COLOR_LIGHT_BLUE = 9,
|
||||
PRINT_COLOR_LIGHT_GREEN = 10,
|
||||
PRINT_COLOR_LIGHT_CYAN = 11,
|
||||
PRINT_COLOR_LIGHT_RED = 12,
|
||||
PRINT_COLOR_PINK = 13,
|
||||
PRINT_COLOR_YELLOW = 14,
|
||||
PRINT_COLOR_WHITE = 15,
|
||||
};
|
||||
|
||||
const static int NUM_COLS = 80;
|
||||
const static int NUM_ROWS = 25;
|
||||
|
||||
struct Char {
|
||||
char character;
|
||||
char color;
|
||||
};
|
||||
|
||||
void clear_row(int row);
|
||||
void clear_all();
|
||||
|
||||
void print_newline();
|
||||
void print_char(char character);
|
||||
void print_set_color(char foreground, char background);
|
||||
void print_str(char* str);
|
||||
|
||||
void set_cursor_pos(int col, int row);
|
||||
|
||||
void kernel_msg_ok(char* msg);
|
||||
#endif
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef STRINGS_H
|
||||
#define STRINGS_H
|
||||
|
||||
void itoa(int n, char str[]);
|
||||
void strrev(char s[]);
|
||||
int strlen(char s[]);
|
||||
char* strcpy(char* strDest, const char* strSrc);
|
||||
char* strcnc(char* str1, char* str2);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
#include "util.h"
|
||||
|
||||
void memcpy(char *source, char *dest, int nbytes) {
|
||||
int i;
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
*(dest + i) = *(source + i);
|
||||
}
|
||||
}
|
||||
|
||||
void memset(char *dest, char val, int len) {
|
||||
char *temp = (char *)dest;
|
||||
for(; len !=0; len--) *temp++ = val;
|
||||
}
|
||||
|
||||
void int_to_ascii(int n, char str[]) {
|
||||
int i, sign;
|
||||
if ((sign = n) < 0) n = -n;
|
||||
i = 0;
|
||||
do {
|
||||
str[i++] = n % 10 + '0';
|
||||
} while ((n /= 10) > 0);
|
||||
|
||||
if (sign < 0) str[i++] = '-';
|
||||
str[i] = '\0';
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
void memcpy(char *source, char *dest, int nbytes);
|
||||
void memset(char *dest, char val, int len);
|
||||
void int_to_ascii(int n, char str[]);
|
||||
|
||||
#endif
|
BIN
os-image.bin
BIN
os-image.bin
Binary file not shown.
|
@ -0,0 +1,141 @@
|
|||
|
||||
|
||||
global entry_x86
|
||||
extern entry_x64
|
||||
|
||||
section .text
|
||||
bits 32
|
||||
entry_x86:
|
||||
mov esp, stack_top
|
||||
|
||||
call check_mb2_boot
|
||||
call check_cpuid
|
||||
call check_x64_supported
|
||||
|
||||
call setup_page_tables
|
||||
call enable_paging
|
||||
|
||||
lgdt [gdt64.pointer]
|
||||
jmp gdt64.code_segment:entry_x64 ; Jump into 64 bit entry
|
||||
|
||||
hlt
|
||||
|
||||
check_mb2_boot:
|
||||
cmp eax, 0x36d76289 ; compare eax to mb2 magic number
|
||||
jne .mb2_not_booted
|
||||
ret
|
||||
.mb2_not_booted:
|
||||
mov al, "B" ; err code B - boot error
|
||||
jmp error
|
||||
|
||||
check_cpuid:
|
||||
pushfd ; Put flags on stack so we can mess with them
|
||||
pop eax ; then put the stack into EAX so we can easily modify it
|
||||
mov ecx, eax ; Make a copy of eax in ecx for comparison
|
||||
xor eax, 1 << 21 ; Attempt to flip the CPUID bit which is bit 21
|
||||
push eax ; Put eax back onto stack
|
||||
popfd ; Write flags back
|
||||
pushfd ; Copy flags onto stack so we can check if the bit did flip
|
||||
pop eax ; Put stack into EAX for comparison
|
||||
push ecx ; Put original flags into stack so we can make sure they remain unchanged
|
||||
popfd; Push original flags back onto the flags register
|
||||
cmp eax, ecx ; Compare the modifided? flags to the original flags
|
||||
je .cpuid_unsupported ; Flags were not changed, cpuid not supported
|
||||
ret
|
||||
|
||||
.cpuid_unsupported:
|
||||
mov al, "C" ; err code C - cpuid unsupported
|
||||
jmp error
|
||||
|
||||
check_x64_supported:
|
||||
mov eax, 0x80000000 ; Magic code that i dont understand
|
||||
cpuid ; Magic code that i dont understand
|
||||
cmp eax, 0x80000001 ; Magic code that i dont undetstand
|
||||
jb .x64_unsupported ; Something went wrong so x64 isnt supported
|
||||
|
||||
mov eax, 0x80000001 ; Set magic value 0x80000001 into EAX for cpuid
|
||||
cpuid ; Get "extended features list" from CPU info
|
||||
test edx, 1 << 29 ; Check if x64 is supported by checking bit 29
|
||||
jz .x64_unsupported ; If zero, x64 unsupported so jump to no x64
|
||||
|
||||
ret
|
||||
.x64_unsupported:
|
||||
mov al, "L" ; err code L, long mode/x64 unsupported
|
||||
jmp error
|
||||
|
||||
; Magic paging code that I don't understand
|
||||
setup_page_tables:
|
||||
mov eax, page_table_l3
|
||||
or eax, 0b11 ; present, writable
|
||||
mov [page_table_l4], eax
|
||||
|
||||
mov eax, page_table_l2
|
||||
or eax, 0b11 ; present, writable
|
||||
mov [page_table_l3], eax
|
||||
|
||||
mov ecx, 0 ; counter
|
||||
.loop:
|
||||
|
||||
mov eax, 0x200000 ; 2MiB
|
||||
mul ecx
|
||||
or eax, 0b10000011 ; present, writable, huge page
|
||||
mov [page_table_l2 + ecx * 8], eax
|
||||
|
||||
inc ecx ; increment counter
|
||||
cmp ecx, 512 ; checks if the whole table is mapped
|
||||
jne .loop ; if not, continue
|
||||
|
||||
ret
|
||||
|
||||
enable_paging:
|
||||
; pass page table location to cpu
|
||||
mov eax, page_table_l4
|
||||
mov cr3, eax
|
||||
|
||||
; enable PAE
|
||||
mov eax, cr4
|
||||
or eax, 1 << 5
|
||||
mov cr4, eax
|
||||
|
||||
; enable long mode
|
||||
mov ecx, 0xC0000080
|
||||
rdmsr
|
||||
or eax, 1 << 8
|
||||
wrmsr
|
||||
|
||||
; enable paging
|
||||
mov eax, cr0
|
||||
or eax, 1 << 31
|
||||
mov cr0, eax
|
||||
|
||||
ret
|
||||
|
||||
error:
|
||||
; print "ERR: X" where X is the error code
|
||||
mov dword [0xb8000], 0x4f524f45
|
||||
mov dword [0xb8004], 0x4f3a4f52
|
||||
mov dword [0xb8008], 0x4f204f20
|
||||
mov byte [0xb800a], al
|
||||
hlt
|
||||
|
||||
section .bss
|
||||
align 4096
|
||||
page_table_l4:
|
||||
resb 4096
|
||||
page_table_l3:
|
||||
resb 4096
|
||||
page_table_l2:
|
||||
resb 4096
|
||||
stack_bottom:
|
||||
resb 4096 * 4
|
||||
stack_top:
|
||||
|
||||
section .rodata
|
||||
gdt64:
|
||||
dd 0 ; zero entry
|
||||
dd 0
|
||||
.code_segment: equ $ - gdt64
|
||||
dq (1 << 43) | (1 << 44) | (1 << 47) | (1 << 53) ; code segment
|
||||
.pointer:
|
||||
dw $ - gdt64 - 1 ; length
|
||||
dq gdt64 ; address
|
|
@ -0,0 +1,17 @@
|
|||
global entry_x64
|
||||
extern kmain
|
||||
|
||||
section .text
|
||||
bits 64
|
||||
entry_x64:
|
||||
; Nullify all data registers
|
||||
mov ax, 0
|
||||
mov ss, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
call kmain ; Jump into C kernel entry
|
||||
|
||||
hlt
|
|
@ -0,0 +1,16 @@
|
|||
section .mb2_header
|
||||
header_start:
|
||||
; https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html for more information, section 3.1.1
|
||||
dd 0xe85250d6 ; multiboot2 magic number
|
||||
|
||||
dd 0 ; i386 protected 32 bit mode
|
||||
|
||||
dd header_end - header_start ; Header length
|
||||
|
||||
dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start)) ; Checksum, total is 0
|
||||
|
||||
; Ending tag
|
||||
dw 0
|
||||
dw 0
|
||||
dd 8
|
||||
header_end:
|
|
@ -0,0 +1,7 @@
|
|||
set timeout=5
|
||||
set default=0
|
||||
|
||||
menuentry "shadeOS Development Build" {
|
||||
multiboot2 /boot/shade.bin
|
||||
boot
|
||||
}
|
|
@ -1,9 +1,5 @@
|
|||
#include "./platform/drivers/ports.h"
|
||||
#include "print.h"
|
||||
#include "./platform/types.h"
|
||||
#include "./platform/interrupts/int.h"
|
||||
|
||||
void dummy_test_entrypoint() {}
|
||||
#include <shade/platform/ports.h>
|
||||
#include <shade/print.h>
|
||||
|
||||
void kernel_welcome() {
|
||||
print_str("Welcome to ");
|
||||
|
@ -31,7 +27,7 @@ void kernel_welcome() {
|
|||
}
|
||||
|
||||
// kMain
|
||||
void main() {
|
||||
void kmain() {
|
||||
// Initialize screen buffer
|
||||
struct Char* buffer = (struct Char*) 0xb8000;
|
||||
|
||||
|
@ -47,8 +43,4 @@ void main() {
|
|||
print_str("This program is provided \"as-is\" and no express or implied warranty is provided.\n");
|
||||
print_str("The full license can be found at /sys/LICENCE on this system or ./LICENCE in the source tree.\n");
|
||||
|
||||
idt_init();
|
||||
kernel_msg_ok("Interrupts initialized");
|
||||
|
||||
__asm__ __volatile__("int $2");
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
%macro isr_err_stub 1
|
||||
isr_stub_%+%1:
|
||||
call exception_handler
|
||||
iret
|
||||
%endmacro
|
||||
; if writing for 64-bit, use iretq instead
|
||||
%macro isr_no_err_stub 1
|
||||
isr_stub_%+%1:
|
||||
call exception_handler
|
||||
iret
|
||||
%endmacro
|
||||
|
||||
extern exception_handler
|
||||
isr_no_err_stub 0
|
||||
isr_no_err_stub 1
|
||||
isr_no_err_stub 2
|
||||
isr_no_err_stub 3
|
||||
isr_no_err_stub 4
|
||||
isr_no_err_stub 5
|
||||
isr_no_err_stub 6
|
||||
isr_no_err_stub 7
|
||||
isr_err_stub 8
|
||||
isr_no_err_stub 9
|
||||
isr_err_stub 10
|
||||
isr_err_stub 11
|
||||
isr_err_stub 12
|
||||
isr_err_stub 13
|
||||
isr_err_stub 14
|
||||
isr_no_err_stub 15
|
||||
isr_no_err_stub 16
|
||||
isr_err_stub 17
|
||||
isr_no_err_stub 18
|
||||
isr_no_err_stub 19
|
||||
isr_no_err_stub 20
|
||||
isr_no_err_stub 21
|
||||
isr_no_err_stub 22
|
||||
isr_no_err_stub 23
|
||||
isr_no_err_stub 24
|
||||
isr_no_err_stub 25
|
||||
isr_no_err_stub 26
|
||||
isr_no_err_stub 27
|
||||
isr_no_err_stub 28
|
||||
isr_no_err_stub 29
|
||||
isr_err_stub 30
|
||||
isr_no_err_stub 31
|
||||
|
||||
global isr_stub_table
|
||||
isr_stub_table:
|
||||
%assign i 0
|
||||
%rep 32
|
||||
dd isr_stub_%+i ; use DQ instead if targeting 64-bit
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Read 1 byte from specified port
|
||||
*/
|
||||
unsigned char port_byte_in(unsigned short port) {
|
||||
unsigned char result;
|
||||
// source and dest are backwards.
|
||||
// "=a (result)" set the C variable to the value of register e'a'x
|
||||
// '"d" (port) map the C variable port into e'd'x register
|
||||
__asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
|
||||
}
|
||||
|
||||
void port_byte_out(unsigned short port, unsigned char data) {
|
||||
// both regs are C vars, nothing is returned, so no '=' in asm syntax
|
||||
// comma because two vars in input area and none in return area
|
||||
__asm__("out %%al, %%dx" : : "a" (data), "d" (port));
|
||||
}
|
||||
|
||||
unsigned short port_word_in(unsigned short port) {
|
||||
unsigned short result;
|
||||
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
|
||||
return result;
|
||||
}
|
||||
|
||||
void port_word_out(unsigned short port, unsigned short data) {
|
||||
__asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
#include "print.h"
|
||||
#include "./platform/drivers/ports.h"
|
||||
#include <shade/print.h>
|
||||
#include <shade/platform/ports.h>
|
||||
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "util.h"
|
||||
#include <shade/util.h>
|
||||
|
||||
void memcpy(char *source, char *dest, int nbytes) {
|
||||
int i;
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
#include <strings.h>
|
||||
#include <stddef.h>
|
||||
|
||||
void itoa(int n, char str[]) {
|
||||
int i, sign;
|
||||
if ((sign = n) < 0) n = -n;
|
||||
i = 0;
|
||||
do {
|
||||
str[i++] = n % 10 + '0';
|
||||
} while ((n /= 10) > 0);
|
||||
|
||||
if (sign < 0) str[i++] = '-';
|
||||
str[i] = '\0';
|
||||
|
||||
strrev(str);
|
||||
}
|
||||
|
||||
/* K&R */
|
||||
void strrev(char s[]) {
|
||||
int c, i, j;
|
||||
for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
|
||||
c = s[i];
|
||||
s[i] = s[j];
|
||||
s[j] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/* K&R */
|
||||
int strlen(char s[]) {
|
||||
int i = 0;
|
||||
while (s[i] != '\0') ++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
char* strcpy(char* strDest, const char* strSrc) {
|
||||
if ( (strDest == NULL) || (strSrc == NULL) ) {
|
||||
return NULL;
|
||||
}
|
||||
char* strDestCopy = strDest;
|
||||
while ((*strDest++=*strSrc++)!='\0');
|
||||
return strDestCopy;
|
||||
}
|
||||
|
||||
char* strcnc(char* str1, char* str2) {
|
||||
char* str_dest;
|
||||
strcpy(str_dest, str1);
|
||||
strcpy(str_dest, str2);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
ENTRY(entry_x86)
|
||||
|
||||
SECTIONS {
|
||||
. = 1M;
|
||||
|
||||
.text BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.mb2_header)
|
||||
*(.text)
|
||||
}
|
||||
|
||||
/* Read-only data. */
|
||||
.rodata BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
/* Read-write data (initialized) */
|
||||
.data BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
|
||||
/* Read-write data (uninitialized) and stack */
|
||||
.bss BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue