more userspace stuff

This commit is contained in:
2026-07-01 20:00:22 -05:00
parent af6c1c94cf
commit b6ee4fc3de
21 changed files with 161 additions and 121 deletions

21
deploy_programs.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
cd rocklibc
make clean
make
cd ..
cd programs
make clean
make
cd ..
make clean
make
cd initrd
./make_img.sh
cd ..
make -B

View File

@@ -29,14 +29,19 @@ liftoff:
mov %ax, %fs
mov %ax, %gs
push $0x23
push %ebx
push $0x202
push $0x1B
push %ecx
pushl $0x23 # User Data Segment (SS)
pushl %ebx # User Stack Pointer (ESP)
pushl $0x202 # EFLAGS (Interrupts enabled, bit 1 standard)
pushl $0x1B # User Code Segment (CS)
pushl %ecx # User Entry Point (EIP)
xor %eax, %eax
xor %ebx, %ebx
xor %ecx, %ecx
xor %edx, %edx
xor %esi, %esi
xor %edi, %edi
xor %ebp, %ebp
iret
@@ -121,5 +126,3 @@ outsw:
fetch_cr3:
mov %cr3, %eax
ret
.global set_cr3

View File

@@ -7,4 +7,6 @@ void enable_interrupts();
void disable_interrupts();
uint32_t fetch_cr3();
void liftoff(uint32_t entry_point, uint32_t user_stack) __attribute__((noreturn));
#endif

View File

@@ -33,9 +33,9 @@ init_pic:
outb %al, $PIC2_DATA
# mask
mov $0xF8, %al
mov $0xFF, %al
outb %al, $PIC1_DATA
mov $0x3F, %al
mov $0xFF, %al
outb %al, $PIC2_DATA
ret

View File

@@ -34,6 +34,7 @@ typedef struct __attribute__((packed)) {
} tss_entry_t;
void init_gdt();
void tss_flush();
extern tss_entry_t tss;

View File

@@ -110,7 +110,7 @@ void common_interrupt_handler(registers *args) {
case 13:
case 15:
case 16:
kprintf("CPU Error: %s", err_messages[args->int_no]);
kprintf("CPU Error: %s, %d\n", err_messages[args->int_no], args->error_code);
break;
case 14:{
uint32_t faulting_address;
@@ -119,6 +119,9 @@ void common_interrupt_handler(registers *args) {
kprintf("Faulted Virtual Address: 0x%x\n", faulting_address);
kprintf("Error Code: 0x%x\n", args->error_code);
kprintf("Instruction Pointer: 0x%x\n", args->eip);
kprintf("Stack Pointer: 0x%x\n", args->useresp);
kprintf("EAX: 0x%x\n", args->eax);
kprintf("EFLAGS: 0x%x\n", args->eflags);
kprintf("Caused by: %s, %s, running in %s mode\n",
(args->error_code & 0x01) ? "Protection Violation" : "Page Not Present",
(args->error_code & 0x02) ? "Write" : "Read",
@@ -127,15 +130,18 @@ void common_interrupt_handler(registers *args) {
break;
}
case 33: {
kprintf("ps2 keyboard interrupt\n");
uint8_t data = ps2_read_data();
send_eoi_master();
break;
}
case 46: { // IDE PRIMARY
kprintf("IDE PRIMARY interrupt\n");
send_eoi_slave();
break;
}
case 47: { // IDE SLAVE
kprintf("IDE SLAVE interrupt\n");
send_eoi_slave();
break;
}

View File

@@ -1,10 +1,11 @@
#include "multiboot.h"
#include "interrupts.h"
#include "gdt.h"
#include "scheduler.h"
#include "common.h"
#include "scheduler.h"
#include "vfs.h"
#include "elf.h"
#include "gdt.h"
#include <lib/print.h>
#include <lib/stream.h>
@@ -26,6 +27,9 @@
extern char __kernel_start;
extern char __kernel_end;
extern uint32_t page_directory[1024];
void* kernel_cr3 = page_directory;
void parse_multiboot_modules(uint32_t mbi_vaddr) {
// find where grub put the boot module containing initrd
multiboot_info* mbi = (multiboot_info*)mbi_vaddr;
@@ -52,7 +56,8 @@ vfs_node_t* load_initrd() {
return cpio_read_fs(initrd_module->mod_start);
}
void load_program(const char* path) {
void load_root_program(const char* path) {
uint32_t kernel_cr3 = fetch_cr3();
void* cr3 = create_task_pd();
load_pd(cr3);
flush_tlb();
@@ -93,12 +98,12 @@ void load_program(const char* path) {
for (uint32_t v = page_start; v < page_end; v += PAGE_SIZE) {
void* phys_frame = p_alloc_frame();
map_page(v, (uint32_t)phys_frame, 0x07);
map_page(v, (uint32_t)phys_frame, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
}
uint32_t data_ptr = ph->p_offset;
fseek(fd, data_ptr);
read(fd, (void*)vstart, ph->p_memsz);
read(fd, (void*)vstart, ph->p_filesz);
// 0 out bss
if (ph->p_memsz > ph->p_filesz) {
@@ -110,15 +115,24 @@ void load_program(const char* path) {
ph_table_ptr += sizeof(elf_program_header_t);
}
uint32_t esp = 0xBFFF0000;
void* pesp = p_alloc_frame();
map_page(esp - PAGE_SIZE, (uint32_t)pesp, 0x07);
create_task(e_hdr->e_entry, fetch_cr3(), 1);
uint32_t stack_sz = PAGE_SIZE * 16;
uint32_t stack_top = 0xBFFF0000;
uint32_t stack_bottom = stack_top - stack_sz;
for (uint32_t vaddr = stack_bottom; vaddr < stack_top; vaddr += PAGE_SIZE) {
void* phys_frame = p_alloc_frame();
map_page(vaddr, (uint32_t)phys_frame, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
}
void start_origin() {
load_program("/origin.elf");
uint32_t* u_esp = (uint32_t*)stack_top;
*(--u_esp) = 0; // envp = NULL
*(--u_esp) = 0; // argv = NULL
*(--u_esp) = 0; // argc = 0
create_task(e_hdr->e_entry, (uint32_t)cr3, 1, (uint32_t)u_esp);
load_pd((void*)kernel_cr3);
flush_tlb();
kprintf("task created for origin program %s\n", path);
}
void kmain(uint32_t magic, multiboot_info* mbi) {
@@ -150,13 +164,14 @@ void kmain(uint32_t magic, multiboot_info* mbi) {
if (!initrd_root) {
kprintf("failed to load initrd\n");
}
mount(vfs_root, initrd_root);
kprintf("initrd read, mounted @ /\n");
disable_interrupts();
init_scheduler();
enable_interrupts();
kprintf("loading user program\n");
start_origin();
kprintf("loading origin program\n");
load_root_program("/origin.elf");
yield();
}

View File

@@ -135,3 +135,7 @@ void* kalloc(size_t sz) {
return kalloc(sz);
}
void kfree(void* ptr) {
}

View File

@@ -14,6 +14,6 @@ char* strcpy(char* dest, const char* src);
void kgrow(size_t pages);
void* kalloc(size_t sz);
void kfree(void* ptr);
#endif

View File

@@ -18,6 +18,9 @@ extern uint32_t page_directory[1024];
#define TEMP_MAPPING_VADDR 0xDFFF0000
#define USR_PAGE 0x07
#define SUP_PAGE 0x03
static uint32_t max_address = 0;
static uint32_t total_available_memory = 0;
static uint8_t memory_bitmap[BITMAP_SIZE];

View File

@@ -10,15 +10,21 @@ typedef enum {
STATE_DEAD
} process_state_t;
typedef enum {
PROCESS_FLAG_NONE = 0,
PROCESS_FLAG_KERNEL = 1 << 0,
PROCESS_FLAG_USER = 1 << 1
} process_flags_t;
typedef struct {
uint32_t pid;
uint32_t esp;
uint32_t esp0;
uint32_t kstack_top;
uint32_t cr3;
process_state_t state;
uint32_t sleep;
void* next;
uint32_t heap_end;
uint32_t flags;
} __attribute__((packed)) process_t;
#endif

View File

@@ -18,8 +18,6 @@ yield: # void yield()
movl %ebx, 4(%esp) # Move Return EIP over CS
addl $4, %esp # Adjust stack pointer up.
# the stack now looks like a hardware interrupt just happened, even though we never called one.
pushal
pushl %esp

View File

@@ -1,4 +1,5 @@
#include <lib/tasks.h>
#include <lib/print.h>
#include <lib/memory.h>
#include <memory/mm.h>
@@ -69,7 +70,9 @@ uint32_t switch_context(uint32_t current_esp) {
current_process = next_process;
tss.esp0 = process_table[current_process].esp0;
if (process_table[current_process].flags & PROCESS_FLAG_USER ) {
tss.esp0 = process_table[current_process].kstack_top;
}
if (fetch_cr3() != process_table[current_process].cr3) {
load_pd((void*)process_table[current_process].cr3);
@@ -88,14 +91,15 @@ void init_scheduler() {
process->cr3 = fetch_cr3();
process->state = STATE_READY;
process->sleep = 0;
process->flags = PROCESS_FLAG_KERNEL;
total_processes++;
create_task((uint32_t)idle_task, fetch_cr3(), 0);
create_task((uint32_t)idle_task, fetch_cr3(), 0, 0);
current_process = 0;
}
int create_task(uint32_t entry_point, uint32_t cr3, int user) {
int create_task(uint32_t entry_point, uint32_t cr3, int user, uint32_t u_esp) {
if (total_processes >= 16) {
return 0;
}
@@ -103,12 +107,14 @@ int create_task(uint32_t entry_point, uint32_t cr3, int user) {
lock_scheduler();
// default to a new task, but if we find a dead one, re use it
int reuse = 0;
process_t* process = &process_table[total_processes];
uint32_t pid = total_processes;
for (uint32_t i = 0; i < total_processes; i++) {
if (process_table[i].state == STATE_DEAD) {
process = &process_table[i];
pid = i;
reuse = 1;
}
}
@@ -116,22 +122,26 @@ int create_task(uint32_t entry_point, uint32_t cr3, int user) {
process->cr3 = cr3;
process->state = STATE_READY;
process->sleep = 0;
process->flags = user ? PROCESS_FLAG_USER : PROCESS_FLAG_KERNEL;
void* stack_bottom = kalloc(4096);
uint32_t* esp = (uint32_t*)((uint32_t)stack_bottom + 4096);
process->esp0 = (uint32_t)esp;
void* kstack_bottom = kalloc(PAGE_SIZE);
uint32_t kstack_top = (uint32_t)kstack_bottom + PAGE_SIZE;
process->kstack_top = kstack_top;
uint32_t* esp = (uint32_t*)kstack_top;
if (user) {
*(--esp) = 0x23; // User Data Segment (SS) with RPL 3 (0x20 | 3)
*(--esp) = 0xBFFFF000; // User Stack Pointer (ESP) - location mapped in user space
*(--esp) = u_esp; // User Stack Pointer (ESP) - location mapped in user space
*(--esp) = 0x0202; // EFLAGS (Interrupts enabled)
*(--esp) = 0x1B; // User Code Segment (CS) with RPL 3 (0x18 | 3)
*(--esp) = entry_point; // EIP
*(--esp) = 0x23;
} else {
// IRET values for Ring 0
*(--esp) = 0x0202; // EFLAGS
*(--esp) = 0x08; // Kernel Code Segment (CS)
*(--esp) = entry_point; // EIP
*(--esp) = 0x10;
}
*(--esp) = 0; // EAX
@@ -144,7 +154,9 @@ int create_task(uint32_t entry_point, uint32_t cr3, int user) {
*(--esp) = 0; // EDI
process->esp = (uint32_t)esp;
if (!reuse) {
total_processes++;
}
unlock_scheduler();
return 1;
}

View File

@@ -6,7 +6,7 @@
void init_scheduler();
int create_task(uint32_t entry_point, uint32_t cr3, int user);
int create_task(uint32_t entry_point, uint32_t cr3, int user, uint32_t u_esp);
process_t* current_task();
void sleep(uint32_t ms);

View File

@@ -4,33 +4,33 @@
syscall_handler:
cli
push $0
push $0x80
pushfl
pushl %cs
pusha
movl 8(%esp), %eax
pushl %eax
movl 4(%esp), %ebx # Get CS
movl %ebx, 8(%esp) # Move CS over Old EIP
movl 0(%esp), %ebx # Get Return EIP
movl %ebx, 4(%esp) # Move Return EIP over CS
addl $4, %esp # Adjust stack pointer
push %ds
push %es
push %fs
push %gs
movw %ds, %ax
pushl %eax
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
pushal
push %esp
call syscall
add $4, %esp
pushl %esp
call switch_context
movl %eax, %esp
mov 28(%esp), %eax
popal
pop %gs
pop %fs
pop %es
pop %ds
popl %eax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
popa
add $8, %esp
sti
iret

View File

@@ -7,6 +7,8 @@
#include <drivers/vga/vga.h>
#include <lib/print.h>
typedef struct registers {
uint32_t gs, fs, es, ds; // Pushed manually
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha
@@ -16,7 +18,7 @@ typedef struct registers {
static int32_t sys_exit(int status) {
exit();
asm volatile("hlt");
return 0;
}

View File

@@ -1,24 +1,21 @@
.global _start
.intel_syntax noprefix
.section .text
_start:
xor ebp, ebp
push ebp
mov ebp, esp
xor %ebp, %ebp
push %ebp
mov %esp, %ebp
mov eax, [esp + 4]
lea ebx, [esp + 8]
lea ecx, [esp + 12]
mov (%esp), %eax
lea 4(%esp), %ebx
lea 8(%esp, %eax, 4), %ecx
push ecx
push ebx
push eax
push %ecx
push %ebx
push %eax
call main
push eax
push %eax
call exit
1: hlt
jmp 1b
1: jmp 1b

View File

@@ -1,28 +0,0 @@
# 0 "crt0.S"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "crt0.S"
.global _start
.intel_syntax noprefix
.section .text
_start:
xor ebp, ebp
push ebp
mov ebp, esp
mov eax, [esp + 4]
lea ebx, [esp + 8]
lea ecx, [esp + 12]
push ecx
push ebx
push eax
call main
push eax
call exit
1: hlt
jmp 1b

View File

@@ -1,8 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
printf("Hello, World from RockOS!\n");
int main() {
printf("RockOS booting...\n");
return 0;
}

View File

@@ -8,8 +8,8 @@ TARGET = origin.elf
all: $(TARGET)
crt0.o: crt0.s
$(CC) $(CFLAGS) -c crt0.s -o crt0.o
crt0.o: crt0.S
$(CC) $(CFLAGS) -c crt0.S -o crt0.o
main.o: main.c
$(CC) $(CFLAGS) -c main.c -o main.o

View File

@@ -1,5 +1,6 @@
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
typedef int _PDCLIB_fd_t;
@@ -14,13 +15,8 @@ static inline int32_t inline_syscall(uint32_t num, uint32_t arg1, uint32_t arg2,
return ret;
}
void _exit(int status) {
inline_syscall(1, (uint32_t)status, 0, 0);
while(1) { asm volatile("hlt"); }
}
void _PDCLIB_exit(int status) {
_exit(status);
inline_syscall(1, (uint32_t)status, 0, 0);;
}
int _PDCLIB_read(_PDCLIB_fd_t fd, void *buf, size_t count) {
@@ -112,3 +108,7 @@ void * sbrk(intptr_t increment) {
return (void *)-1;
}
void exit(int status) {
_PDCLIB_exit(status);
}