Quick commit, haven't done anything in a while

This commit is contained in:
vanten-s 2024-08-05 00:59:07 +02:00
parent fc95fb5ff6
commit c8ce4a2de0
Signed by: vanten-s
GPG key ID: DE3060396884D3F2
16 changed files with 512 additions and 109 deletions

2
.gitignore vendored
View file

@ -1 +1 @@
/build bochsout.txt

View file

@ -21,11 +21,13 @@ $(ASFLAGS)
KERNEL_OBJS=\ KERNEL_OBJS=\
kernel/kernel.o \ kernel/kernel.o \
kernel/debugging.o \ kernel/debugging.o \
kernel/elf.o \
LIB_OBJS=\ LIB_OBJS=\
$(ARCHDIR)/bootstrap.o \ $(ARCHDIR)/bootstrap.o \
$(ARCHDIR)/tty.o \ $(ARCHDIR)/tty.o \
$(ARCHDIR)/strlib.o \ $(ARCHDIR)/strlib.o \
$(ARCHDIR)/idt.o \
$(ARCHDIR)/interrupt.o \ $(ARCHDIR)/interrupt.o \
$(ARCHDIR)/gdt.o \ $(ARCHDIR)/gdt.o \
@ -48,10 +50,13 @@ clean:
rm -f myos.iso rm -f myos.iso
rm -f isodir/boot/myos.kernel rm -f isodir/boot/myos.kernel
.c.o: $(ARCHDIR)/interrupt.o: CFLAGS += -mgeneral-regs-only
kernel/elf.o: CFLAGS += -masm=intel
%.o : %.c
i686-elf-gcc -c $< -o $@ $(CFLAGS) i686-elf-gcc -c $< -o $@ $(CFLAGS)
.s.o: %.o : %.s
i686-elf-as $< -o $@ $(ASFLAGS) i686-elf-as $< -o $@ $(ASFLAGS)
myos.kernel: $(OBJS) myos.kernel: $(OBJS)
@ -67,7 +72,7 @@ debug: ASFLAGS += -g
debug: all debug: all
run: myos.iso run: myos.iso
qemu-system-i386 myos.iso -display curses qemu-system-i386 myos.iso
run-debug: debug run-debug: debug
qemu-system-i386 -S -gdb tcp::9000 myos.iso -display curses qemu-system-i386 -S -gdb tcp::9000 myos.iso

View file

@ -30,6 +30,7 @@ System V ABI standard and de-facto extensions. The compiler will assume the
stack is properly aligned and failure to align the stack will result in stack is properly aligned and failure to align the stack will result in
undefined behavior. undefined behavior.
*/ */
.section .bss .section .bss
.align 16 .align 16
stack_bottom: stack_bottom:
@ -69,15 +70,15 @@ _start:
call gdt_init call gdt_init
movw %ax, 0x10 movw 0x10, %ax
movw %ds, %ax movw %ax, %ds
movw %es, %ax movw %ax, %es
movw %fs, %ax movw %ax, %fs
movw %gs, %ax movw %ax, %gs
movw %ss, %ax movw %ax, %ss
# jmp kernel # jmp kernel
ljmp $0x08, $kernel ljmp $0x08, $kernel
kernel: kernel:
/* /*
This is a good place to initialize crucial processor state before the This is a good place to initialize crucial processor state before the
@ -99,8 +100,6 @@ kernel:
preserved and the call is well defined. preserved and the call is well defined.
*/ */
mov %esp, %edx
call kernel_main call kernel_main
.global keyboard_test .global keyboard_test

View file

@ -3,7 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#define NUM_ENTRIES 3 #define NUM_ENTRIES 6
struct SegmentDescriptor { struct SegmentDescriptor {
uint32_t limit; uint32_t limit;
@ -17,6 +17,39 @@ struct GDT {
uint64_t* base; uint64_t* base;
} __attribute__((packed)); } __attribute__((packed));
struct tss_entry_struct {
uint32_t prev_tss; // The previous TSS - with hardware task switching these form a kind of backward linked list.
uint32_t esp0; // The stack pointer to load when changing to kernel mode.
uint32_t ss0; // The stack segment to load when changing to kernel mode.
// Everything below here is unused.
uint32_t esp1; // esp and ss 1 and 2 would be used when switching to rings 1 or 2.
uint32_t ss1;
uint32_t esp2;
uint32_t ss2;
uint32_t cr3;
uint32_t eip;
uint32_t eflags;
uint32_t eax;
uint32_t ecx;
uint32_t edx;
uint32_t ebx;
uint32_t esp;
uint32_t ebp;
uint32_t esi;
uint32_t edi;
uint32_t es;
uint32_t cs;
uint32_t ss;
uint32_t ds;
uint32_t fs;
uint32_t gs;
uint32_t ldt;
uint16_t trap;
uint16_t iomap_base;
} __attribute__((packed));
struct tss_entry_struct tss;
static uint64_t entries[NUM_ENTRIES]; static uint64_t entries[NUM_ENTRIES];
static size_t current_entry = 0; static size_t current_entry = 0;
struct GDT gdt; struct GDT gdt;
@ -71,16 +104,13 @@ static void load_gdt()
gdt.size = NUM_ENTRIES * 8 - 1; gdt.size = NUM_ENTRIES * 8 - 1;
gdt.base = entries; gdt.base = entries;
for (int i = 0; i < NUM_ENTRIES; i++) {
print_hex_bytes(gdt.base + i, 8);
terminal_putchar('\n');
}
asm ( "lgdt %0" : : "m"(gdt) ); asm ( "lgdt %0" : : "m"(gdt) );
} }
void gdt_init() void gdt_init()
{ {
// https://wiki.osdev.org/Global_Descriptor_Table
terminal_initialize(); terminal_initialize();
struct SegmentDescriptor null; struct SegmentDescriptor null;
null.limit = 0; null.limit = 0;
@ -106,15 +136,47 @@ void gdt_init()
terminal_putchar('\n'); terminal_putchar('\n');
struct SegmentDescriptor kernel_data; struct SegmentDescriptor kernel_data;
kernel_code.limit = 0x000003FF; kernel_data.limit = 0x000003FF;
kernel_data.base = 0x00400000; kernel_data.base = 0x00400000;
kernel_data.access_byte = 0b10010010; kernel_data.access_byte = 0b10010010;
kernel_data.flags = 0b1100; kernel_data.flags = 0b1100;
terminal_writestring("Kernel Data: "); terminal_writestring("Kernel Data: ");
add_entry(kernel_data); add_entry(kernel_data);
terminal_putchar('\n'); terminal_putchar('\n');
struct SegmentDescriptor user_code;
user_code.limit = 0x000003FF;
user_code.base = 0x00800000;
user_code.access_byte = 0b11111010;
user_code.flags = 0b1100;
terminal_writestring("User Code: ");
add_entry(user_code);
terminal_putchar('\n');
struct SegmentDescriptor user_data;
user_data.limit = 0x000FFFFF;
user_data.base = 0x00c00000;
user_data.access_byte = 0b11110010;
user_data.flags = 0b1100;
terminal_writestring("User Data: ");
add_entry(user_data);
terminal_putchar('\n');
struct SegmentDescriptor tss_segment;
tss_segment.limit = sizeof(tss_segment) - 1;
tss_segment.base = (uint32_t) &tss;
tss_segment.access_byte = 0x89;
tss_segment.flags = 0b0000;
terminal_writestring("TSS Segment: ");
add_entry(tss_segment);
terminal_putchar('\n');
load_gdt(); load_gdt();
} }

165
arch/i686/idt.c Normal file
View file

@ -0,0 +1,165 @@
#include <kernel/tty.h>
#include <kernel/gdt.h>
#include <debugging.h>
#include "interrupt.h"
#include <stdint.h>
#include <stddef.h>
#define NUM_ENTRIES 0x100
struct InterruptDescriptor {
uint32_t offset;
uint32_t selector;
uint8_t gate_type;
uint8_t ring;
bool present;
};
struct IDT {
uint16_t size;
uint64_t* base;
} __attribute__((packed));
static uint64_t entries[NUM_ENTRIES];
struct IDT idt;
enum EntryTypes {
DivisionByZero = 0x00,
_Reserved0 = 0x01,
NMIInterrupt = 0x02,
Breakpoint = 0x03,
Overflow = 0x04,
BoundsExceeded = 0x05,
InvalidOpcode = 0x06,
DeviceNotAvail = 0x07,
DoubleFault = 0x08,
CoprocSegORun = 0x09,
InvalidTSS = 0x0A,
SegNotPresent = 0x0B,
StackSegFault = 0x0C,
GenerProtFault = 0x0D,
PageFault = 0x0E,
_Reserved1 = 0x0F,
x87FPUError = 0x10,
AlignmentCheck = 0x11,
MachineCheck = 0x12,
SIMDFloatExcep = 0x13,
};
static void encodeIdtEntry(uint8_t *target, struct InterruptDescriptor source)
{
// Encode the present bit
if (source.present) {
target[5] |= 0x80;
} else {
// Not present, return
return;
}
// Encode the offset
target[0] = (source.offset >> 0x00) & 0xFF;
target[1] = (source.offset >> 0x08) & 0xFF;
target[6] = (source.offset >> 0x10) & 0xFF;
target[7] = (source.offset >> 0x18) & 0xFF;
// Encode the base
target[2] = (source.selector >> 0x00) & 0xFF;
target[3] = (source.selector >> 0x08) & 0xFF;
// Encode the gate type
target[5] |= source.gate_type;
// Encode the DPL
target[5] |= (source.ring << 5);
}
static void add_entry(struct InterruptDescriptor entry, uint8_t index)
{
uint64_t descriptor = 0;
encodeIdtEntry((uint8_t*) &descriptor, entry);
entries[index] = descriptor;
}
static void load_idt()
{
idt.size = NUM_ENTRIES * 8 - 1;
idt.base = entries;
asm ( "lidt %0" : : "m"(idt) );
asm ( "sti" );
}
struct InterruptDescriptor generate_entry(bool present, void isr(struct interrupt_frame*), uint8_t gate_type, uint8_t ring, uint8_t selector)
{
struct InterruptDescriptor entry;
entry.present = present;
entry.offset = (uint32_t)isr;
entry.gate_type = gate_type;
entry.ring = ring;
entry.selector = selector;
return entry;
}
static inline void outb(uint16_t port, uint8_t val)
{
__asm__ volatile ( "outb %b0, %w1" : : "a"(val), "Nd"(port) : "memory");
/* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint).
* Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint).
* The outb %al, %dx encoding is the only option for all other cases.
* %1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type */
}
void idt_init()
{
outb(0x21,0xfd);
outb(0xa1,0xff);
struct InterruptDescriptor entry;
entry = generate_entry(true, exception, 0xF, 0, 0x8);
for (int i = 0; i < 0x20; i++)
{
add_entry(entry, i);
}
entry = generate_entry(true, irq, 0xF, 0, 0x8);
for (int i = 0x20; i < 0x28; i++)
{
add_entry(entry, i);
}
entry = generate_entry(true, divide_by_zero, 0xF, 0, 0x8);
add_entry(entry, DivisionByZero);
entry = generate_entry(true, general_protection_fault, 0xF, 0, 0x8);
add_entry(entry, GenerProtFault);
entry = generate_entry(true, double_fault, 0xF, 0, 0x8);
add_entry(entry, DoubleFault);
struct InterruptDescriptor print_entry;
print_entry.present = true;
print_entry.offset = (uint32_t)print;
print_entry.gate_type = 0xE;
print_entry.ring = 3;
print_entry.selector = 0x8;
add_entry(print_entry, 0x80);
struct InterruptDescriptor input_entry;
input_entry.present = true;
input_entry.offset = (uint32_t)input;
input_entry.gate_type = 0xE;
input_entry.ring = 0;
input_entry.selector = 0x8;
add_entry(input_entry, 0x81);
load_idt();
tss.ss0 = 0x10;
asm("mov %%esp, %0" : "=r" (tss.esp0));
asm("mov $0x28, %ax");
asm("ltr %ax");
}

View file

@ -1,88 +1,114 @@
#include <kernel/tty.h> #include <kernel/tty.h>
#include <debugging.h>
#include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <debugging.h>
#define NUM_ENTRIES 0 struct interrupt_frame {
uint32_t eflags;
struct InterruptDescriptor { uint32_t cs;
uint32_t offset; uint32_t eip;
uint32_t selector;
uint8_t gate_type;
uint8_t ring;
bool present;
}; };
struct IDT { uint8_t test = 'a';
uint16_t size;
uint64_t* base;
} __attribute__((packed));
static uint64_t entries[NUM_ENTRIES]; static void stack_trace()
static size_t current_entry = 0;
struct IDT idt;
static void encodeIdtEntry(uint8_t *target, struct InterruptDescriptor source)
{ {
// Encode the present bit uint32_t* stack = 0;
if (source.present) { asm("mov %%esp, %0" : "=r" (stack));
target[5] |= 0xF0; for (int i = 0; i < 25; i++) {
} else { uint32_t* current_address = stack + (i * 4);
// Not present, return print_hex_bytes(&current_address, 4);
return; terminal_writestring(": ");
} print_hex_bytes(current_address, 4);
// Encode the offset
target[0] = (source.offset >> 0x00) & 0xFF;
target[1] = (source.offset >> 0x08) & 0xFF;
target[6] = (source.offset >> 0x10) & 0xFF;
target[7] = (source.offset >> 0x18) & 0xFF;
// Encode the base
target[2] = (source.selector >> 0x00) & 0xFF;
target[3] = (source.selector >> 0x08) & 0xFF;
// Encode the gate type
target[5] |= source.gate_type;
// Encode the DPL
target[5] |= (source.ring >> 5);
print_hex_bytes(target, 8);
}
static void add_entry(struct InterruptDescriptor entry)
{
if (current_entry == NUM_ENTRIES) {
terminal_writestring("WARNING: More IDT entries than NUM_ENTRIES.\n");
return;
}
uint64_t descriptor = 0;
encodeIdtEntry((uint8_t*) &descriptor, entry);
entries[current_entry] = descriptor;
current_entry++;
}
static void load_idt()
{
idt.size = NUM_ENTRIES * 8 - 1;
idt.base = entries;
for (int i = 0; i < NUM_ENTRIES; i++) {
print_hex_bytes(idt.base + i, 8);
terminal_putchar('\n'); terminal_putchar('\n');
} }
asm ( "lidt %0" : : "m"(idt) );
} }
void idt_init() __attribute__((interrupt)) void divide_by_zero(struct interrupt_frame* frame)
{ {
terminal_writestring("TODO: Add interrupts"); terminal_initialize();
terminal_putchar('\n'); stack_trace();
terminal_writestring("Yo dude u cant divide by zero yao\n");
// load_idt(); while (1) { }
} }
__attribute__((interrupt)) void general_protection_fault(struct interrupt_frame* frame)
{
/* terminal_initialize();
stack_trace();
terminal_writestring("General protection fault\n");
terminal_writestring("Error code:\n");
print_hex_bytes(frame, sizeof(frame));
terminal_putchar('\n'); */
while (1) { }
}
__attribute__((interrupt)) void double_fault(struct interrupt_frame* frame)
{
// terminal_writestring("2 Errors in a row, u better behave naughty naughty\n");
// while (1) { }
}
__attribute__((interrupt)) void exception(struct interrupt_frame* frame)
{
/* terminal_initialize();
stack_trace();
terminal_writestring("Some weird error code stuff\n");
terminal_writestring("Error code:\n");
print_hex_bytes(frame, sizeof(frame));
terminal_putchar('\n'); */
while (1) { }
}
__attribute__((interrupt)) void print(struct interrupt_frame* frame)
{
/* terminal_initialize();
terminal_putchar(test);
test++; */
char* start;
asm("mov %%edx, %0" : "=r" (start));
terminal_writestring(start);
/* uint8_t* stack;
asm("mov %%esp, %0" : "=r" (stack));
terminal_writestring("\nSTACK:\n");
print_hex_bytes(stack - 24, 4);
terminal_putchar('\n');
print_hex_bytes(stack - 20, 4);
terminal_putchar('\n');
print_hex_bytes(stack - 16, 4);
terminal_putchar('\n');
print_hex_bytes(stack - 12, 4);
terminal_putchar('\n');
print_hex_bytes(stack - 8, 4);
terminal_putchar('\n');
print_hex_bytes(stack - 4, 4);
terminal_putchar('\n'); */
}
__attribute__((interrupt)) void input(struct interrupt_frame* frame)
{
char* buffer;
asm("mov %%edx, %0" : "=r" (buffer));
size_t index = 0;
char current_character = get_last_key_pressed();
while (current_character != '\n') {
char tmp = get_last_key_pressed();
if (current_character != -1 && tmp != current_character) {
buffer[index] = current_character;
terminal_putchar(current_character);
index++;
}
current_character = tmp;
}
buffer[index] = '\0';
}
__attribute__((interrupt)) void irq(struct interrupt_frame* frame)
{
}

12
arch/i686/interrupt.h Normal file
View file

@ -0,0 +1,12 @@
struct interrupt_frame;
__attribute__((interrupt)) void divide_by_zero(struct interrupt_frame* frame);
__attribute__((interrupt)) void general_protection_fault(struct interrupt_frame* frame);
__attribute__((interrupt)) void double_fault(struct interrupt_frame* frame);
__attribute__((interrupt)) void exception(struct interrupt_frame* frame);
__attribute__((interrupt)) void print(struct interrupt_frame* frame);
__attribute__((interrupt)) void input(struct interrupt_frame* frame);
__attribute__((interrupt)) void irq(struct interrupt_frame* frame);

4
bochsrc.txt Normal file
View file

@ -0,0 +1,4 @@
megs: 32
log: ./bochsout.txt
ata0-master: type=disk, path="myos.iso",
boot: disk

5
include/kernel/elf.h Normal file
View file

@ -0,0 +1,5 @@
#include <stdint.h>
#include <stddef.h>
void run_program(uint8_t* program, size_t length);

34
include/kernel/gdt.h Normal file
View file

@ -0,0 +1,34 @@
#include <stdint.h>
struct tss_entry_struct {
uint32_t prev_tss; // The previous TSS - with hardware task switching these form a kind of backward linked list.
uint32_t esp0; // The stack pointer to load when changing to kernel mode.
uint32_t ss0; // The stack segment to load when changing to kernel mode.
// Everything below here is unused.
uint32_t esp1; // esp and ss 1 and 2 would be used when switching to rings 1 or 2.
uint32_t ss1;
uint32_t esp2;
uint32_t ss2;
uint32_t cr3;
uint32_t eip;
uint32_t eflags;
uint32_t eax;
uint32_t ecx;
uint32_t edx;
uint32_t ebx;
uint32_t esp;
uint32_t ebp;
uint32_t esi;
uint32_t edi;
uint32_t es;
uint32_t cs;
uint32_t ss;
uint32_t ds;
uint32_t fs;
uint32_t gs;
uint32_t ldt;
uint16_t trap;
uint16_t iomap_base;
} __attribute__((packed));
extern struct tss_entry_struct tss;

45
kernel/elf.c Normal file
View file

@ -0,0 +1,45 @@
#include <stdint.h>
#include <stddef.h>
#include <debugging.h>
#include <kernel/tty.h>
#include <kernel/gdt.h>
void run_program(uint8_t* program, size_t length)
{
uint8_t* userland_code = (uint8_t*) 0x00800004;
for (size_t i = 0; i < length; i++) {
userland_code[i] = program[i];
}
tss.ss0 = 0x10;
asm("sti");
asm("int 0x80");
asm("mov %0, esp" : "=r" (tss.esp0));
// Generates segfault
// asm("mov esp, %0" : "=r" (tss.esp0));
asm("mov ax, 0x23 # Load registers with the correct GDT segments values");
asm("mov ds, ax");
asm("mov es, ax");
asm("mov fs, ax");
asm("mov gs, ax");
asm("push 0x23");
asm("push 0x00c00100");
asm("pushfd");
asm("pop eax");
asm("or eax, 0x200");
asm("push eax");
asm("push 0x1b");
asm("push 0x00800000");
asm("iret");
asm("int 0x21");
}

3
kernel/heap.c Normal file
View file

@ -0,0 +1,3 @@
#include <stdint.h>
uint8_t heap[2000];

View file

@ -1,28 +1,58 @@
#include <kernel/tty.h> #include <kernel/tty.h>
#include <kernel/interrupt.h> #include <kernel/idt.h>
#include <debugging.h> #include <debugging.h>
#include <kernel/elf.h>
/* Check if the compiler thinks you are targeting the wrong operating system. */ /* Check if the compiler thinks you are targeting the wrong operating system. */
#if defined(__linux__) #if defined(__linux__)
#error "You are not using a cross-compiler, you will most certainly run into trouble" #error "You are not using a cross-compiler, you will most certainly run into trouble"
#endif #endif
uint8_t program[] = {
/* 0xcd,
0x80,
0xc6,
0x05,
0x00,
0x80,
0x0b,
0x00,
0x62,
0xeb,
0xfe, */
/* 0x90,
0xe9,
0xfa,
0x7f,
0x7b,
0xf8, */
/* 0x90,
0xeb,
0xfd, */
0x6a,
0x69,
0xeb,
0xfc,
};
void kernel_main(void) void kernel_main(void)
{ {
/* Initialize terminal interface */ /* Initialize terminal interface */
terminal_initialize(); // terminal_initialize();
// TODO: Add interrupts idt_init();
// idt_init();
terminal_putchar(get_last_key_pressed()); run_program(program, 15);
char current_character = get_last_key_pressed(); /*
while (current_character != ',') { char buf[100];
char tmp = get_last_key_pressed();
if (current_character != -1 && tmp != current_character) { while (true) {
terminal_putchar(current_character); asm("mov %0, %%edx" :: "r" (buf));
} asm("int $0x81");
current_character = tmp; terminal_writestring("newline");
terminal_putchar('\n');
} }
*/
} }

2
libc/include/stdio.h Normal file
View file

@ -0,0 +1,2 @@
void print(char* s);
void input(char* buf);

11
libc/stdio.c Normal file
View file

@ -0,0 +1,11 @@
void print(char* s)
{
asm("mov %0, %%edx" :: "r" (s));
asm("int $0x21");
}
void input(char* buf)
{
asm("mov %0, %%edx" :: "r" (buf));
asm("int $0x22");
}