Yoooooo userland execution :3

This commit is contained in:
vanten-s 2024-08-08 21:34:30 +02:00
parent c8ce4a2de0
commit cac521ded0
Signed by: vanten-s
GPG key ID: DE3060396884D3F2
10 changed files with 105 additions and 109 deletions

View file

@ -51,7 +51,7 @@ clean:
rm -f isodir/boot/myos.kernel rm -f isodir/boot/myos.kernel
$(ARCHDIR)/interrupt.o: CFLAGS += -mgeneral-regs-only $(ARCHDIR)/interrupt.o: CFLAGS += -mgeneral-regs-only
kernel/elf.o: CFLAGS += -masm=intel # kernel/elf.o: CFLAGS += -masm=intel
%.o : %.c %.o : %.c
i686-elf-gcc -c $< -o $@ $(CFLAGS) i686-elf-gcc -c $< -o $@ $(CFLAGS)
@ -71,7 +71,7 @@ debug: CFLAGS += -g -O0
debug: ASFLAGS += -g debug: ASFLAGS += -g
debug: all debug: all
run: myos.iso run: all
qemu-system-i386 myos.iso qemu-system-i386 myos.iso
run-debug: debug run-debug: debug

View file

@ -70,7 +70,7 @@ _start:
call gdt_init call gdt_init
movw 0x10, %ax movw $0x10, %ax
movw %ax, %ds movw %ax, %ds
movw %ax, %es movw %ax, %es
movw %ax, %fs movw %ax, %fs

View file

@ -3,7 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#define NUM_ENTRIES 6 #define NUM_ENTRIES 256
struct SegmentDescriptor { struct SegmentDescriptor {
uint32_t limit; uint32_t limit;
@ -101,7 +101,7 @@ static void add_entry(struct SegmentDescriptor entry)
static void load_gdt() static void load_gdt()
{ {
gdt.size = NUM_ENTRIES * 8 - 1; gdt.size = NUM_ENTRIES * sizeof(struct SegmentDescriptor) - 1;
gdt.base = entries; gdt.base = entries;
asm ( "lgdt %0" : : "m"(gdt) ); asm ( "lgdt %0" : : "m"(gdt) );
@ -125,7 +125,7 @@ void gdt_init()
terminal_putchar('\n'); terminal_putchar('\n');
struct SegmentDescriptor kernel_code; struct SegmentDescriptor kernel_code;
kernel_code.limit = 0x000003FF; kernel_code.limit = 0xFFFFF;
kernel_code.base = 0x00000000; kernel_code.base = 0x00000000;
kernel_code.access_byte = 0b10011010; kernel_code.access_byte = 0b10011010;
kernel_code.flags = 0b1100; kernel_code.flags = 0b1100;
@ -136,8 +136,8 @@ void gdt_init()
terminal_putchar('\n'); terminal_putchar('\n');
struct SegmentDescriptor kernel_data; struct SegmentDescriptor kernel_data;
kernel_data.limit = 0x000003FF; kernel_data.limit = 0xFFFFF;
kernel_data.base = 0x00400000; kernel_data.base = 0x00000000;
kernel_data.access_byte = 0b10010010; kernel_data.access_byte = 0b10010010;
kernel_data.flags = 0b1100; kernel_data.flags = 0b1100;
@ -146,8 +146,8 @@ void gdt_init()
terminal_putchar('\n'); terminal_putchar('\n');
struct SegmentDescriptor user_code; struct SegmentDescriptor user_code;
user_code.limit = 0x000003FF; user_code.limit = 0xFFFFF;
user_code.base = 0x00800000; user_code.base = 0x00000000;
user_code.access_byte = 0b11111010; user_code.access_byte = 0b11111010;
user_code.flags = 0b1100; user_code.flags = 0b1100;
@ -157,8 +157,8 @@ void gdt_init()
terminal_putchar('\n'); terminal_putchar('\n');
struct SegmentDescriptor user_data; struct SegmentDescriptor user_data;
user_data.limit = 0x000FFFFF; user_data.limit = 0xFFFFF;
user_data.base = 0x00c00000; user_data.base = 0x00000000;
user_data.access_byte = 0b11110010; user_data.access_byte = 0b11110010;
user_data.flags = 0b1100; user_data.flags = 0b1100;
@ -179,4 +179,9 @@ void gdt_init()
terminal_putchar('\n'); terminal_putchar('\n');
load_gdt(); load_gdt();
tss.ss0 = 0x10;
asm("mov %%esp, %0" : "=r" (tss.esp0));
asm ("ltr %%ax" : : "a"(0x28));
} }

View file

@ -1,9 +1,10 @@
#include <kernel/tty.h>
#include <kernel/gdt.h> #include <kernel/gdt.h>
#include <kernel/tty.h>
#include <debugging.h> #include <debugging.h>
#include "interrupt.h" #include "interrupt.h"
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "io.h"
#define NUM_ENTRIES 0x100 #define NUM_ENTRIES 0x100
@ -101,20 +102,9 @@ struct InterruptDescriptor generate_entry(bool present, void isr(struct interrup
return entry; 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() void idt_init()
{ {
outb(0x21,0xfd); terminal_initialize();
outb(0xa1,0xff);
struct InterruptDescriptor entry; struct InterruptDescriptor entry;
entry = generate_entry(true, exception, 0xF, 0, 0x8); entry = generate_entry(true, exception, 0xF, 0, 0x8);
@ -123,12 +113,6 @@ void idt_init()
add_entry(entry, 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); entry = generate_entry(true, divide_by_zero, 0xF, 0, 0x8);
add_entry(entry, DivisionByZero); add_entry(entry, DivisionByZero);
@ -138,11 +122,18 @@ void idt_init()
entry = generate_entry(true, double_fault, 0xF, 0, 0x8); entry = generate_entry(true, double_fault, 0xF, 0, 0x8);
add_entry(entry, DoubleFault); add_entry(entry, DoubleFault);
outb(0x21,0x20); // Tell the PIC to use interrupts 0x20 - 0x27
entry = generate_entry(true, irq, 0xE, 0, 0x8);
for (int i = 0x20; i < 0x28; i++)
{
add_entry(entry, i);
}
struct InterruptDescriptor print_entry; struct InterruptDescriptor print_entry;
print_entry.present = true; print_entry.present = true;
print_entry.offset = (uint32_t)print; print_entry.offset = (uint32_t)print;
print_entry.gate_type = 0xE; print_entry.gate_type = 0xE;
print_entry.ring = 3; print_entry.ring = 0;
print_entry.selector = 0x8; print_entry.selector = 0x8;
add_entry(print_entry, 0x80); add_entry(print_entry, 0x80);
@ -157,9 +148,4 @@ void idt_init()
add_entry(input_entry, 0x81); add_entry(input_entry, 0x81);
load_idt(); load_idt();
tss.ss0 = 0x10;
asm("mov %%esp, %0" : "=r" (tss.esp0));
asm("mov $0x28, %ax");
asm("ltr %ax");
} }

View file

@ -1,6 +1,7 @@
#include <kernel/tty.h> #include <kernel/tty.h>
#include <stddef.h> #include <stddef.h>
#include <debugging.h> #include <debugging.h>
#include "io.h"
struct interrupt_frame { struct interrupt_frame {
uint32_t eflags; uint32_t eflags;
@ -25,35 +26,26 @@ static void stack_trace()
__attribute__((interrupt)) void divide_by_zero(struct interrupt_frame* frame) __attribute__((interrupt)) void divide_by_zero(struct interrupt_frame* frame)
{ {
terminal_initialize();
stack_trace();
terminal_writestring("Yo dude u cant divide by zero yao\n"); terminal_writestring("Yo dude u cant divide by zero yao\n");
while (1) { } while (1) { }
} }
__attribute__((interrupt)) void general_protection_fault(struct interrupt_frame* frame) __attribute__((interrupt)) void general_protection_fault(struct interrupt_frame* frame)
{ {
/* terminal_initialize(); terminal_writestring("GPF handler called\n");
stack_trace();
terminal_writestring("General protection fault\n");
terminal_writestring("Error code:\n");
print_hex_bytes(frame, sizeof(frame));
terminal_putchar('\n'); */
while (1) { } while (1) { }
} }
__attribute__((interrupt)) void double_fault(struct interrupt_frame* frame) __attribute__((interrupt)) void double_fault(struct interrupt_frame* frame)
{ {
// terminal_writestring("2 Errors in a row, u better behave naughty naughty\n"); terminal_writestring("2 Errors in a row, u better behave naughty naughty\n");
// while (1) { } while (1) { }
} }
__attribute__((interrupt)) void exception(struct interrupt_frame* frame) __attribute__((interrupt)) void exception(struct interrupt_frame* frame)
{ {
/* terminal_initialize();
stack_trace();
terminal_writestring("Some weird error code stuff\n"); terminal_writestring("Some weird error code stuff\n");
terminal_writestring("Error code:\n"); /* terminal_writestring("Error code:\n");
print_hex_bytes(frame, sizeof(frame)); print_hex_bytes(frame, sizeof(frame));
terminal_putchar('\n'); */ terminal_putchar('\n'); */
while (1) { } while (1) { }
@ -109,6 +101,7 @@ __attribute__((interrupt)) void input(struct interrupt_frame* frame)
__attribute__((interrupt)) void irq(struct interrupt_frame* frame) __attribute__((interrupt)) void irq(struct interrupt_frame* frame)
{ {
terminal_writestring("Test");
outb(0x20, 0x20);
} }

19
arch/i686/io.h Normal file
View file

@ -0,0 +1,19 @@
#include <stdint.h>
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 */
}
static inline void inb(uint16_t port, uint8_t val)
{
__asm__ volatile ( "inb %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 */
}

17
arch/i686/pic.c Normal file
View file

@ -0,0 +1,17 @@
#include "io.h"
#define ICW1_ICW4 0x01 /* Indicates that ICW4 will be present */
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
#define ICW1_INIT 0x10 /* Initialization - required! */
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
void init_pic() {
}

0
arch/i686/pic.h Normal file
View file

View file

@ -3,43 +3,35 @@
#include <debugging.h> #include <debugging.h>
#include <kernel/tty.h> #include <kernel/tty.h>
#include <kernel/gdt.h> #include <kernel/gdt.h>
#include <debugging.h>
static void* memcpy(void* restrict dstptr, const void* restrict srcptr, size_t size) {
unsigned char* dst = (unsigned char*) dstptr;
const unsigned char* src = (const unsigned char*) srcptr;
for (size_t i = 0; i < size; i++)
dst[i] = src[i];
return dstptr;
}
void run_program(uint8_t* program, size_t length) void run_program(uint8_t* program, size_t length)
{ {
uint8_t* userland_code = (uint8_t*) 0x00800004; uint8_t* userland_code = (uint8_t*) 0x0;
memcpy(userland_code, program, length);
for (size_t i = 0; i < length; i++) { print_hex_bytes(userland_code, 1);
userland_code[i] = program[i]; terminal_putchar('\n');
}
asm ("\
tss.ss0 = 0x10; mov $0x20 | 0x3, %%ax;\
movw %%ax, %%ds;\
asm("sti"); movw %%ax, %%es;\
asm("int 0x80"); movw %%ax, %%fs;\
movw %%ax, %%gs;\
asm("mov %0, esp" : "=r" (tss.esp0)); pushl $0x20 | 0x3; /* SS selector */ \
pushl $0x00c00100; /* ESP */ \
// Generates segfault pushf; /* EFLAGS */ \
// asm("mov esp, %0" : "=r" (tss.esp0)); popl %%eax; orl $0x200, %%eax; pushl %%eax; /* Set interrupts in USERPACE */\
pushl $0x18 | 0x3; /* CS selector */\
asm("mov ax, 0x23 # Load registers with the correct GDT segments values"); pushl $0x0; /* EIP */ \
asm("mov ds, ax"); iret;":::"eax");
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");
} }

View file

@ -9,30 +9,8 @@
#endif #endif
uint8_t program[] = { uint8_t program[] = {
/* 0xcd, 0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, 0x0 (Just a simple NOP-like instruction)
0x80, 0xF4 // hlt (halts the CPU, should trap to kernel if interrupts enabled)
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)
@ -42,6 +20,12 @@ void kernel_main(void)
idt_init(); idt_init();
// asm("int $13");
// asm("ljmp $0x18, $0x00c00100"); // Example: Far jump to user code segment with selector 0x18
print_hex_bytes(idt_init, 4);
terminal_putchar('\n');
run_program(program, 15); run_program(program, 15);
/* /*