diff --git a/kernel/ps2.c b/kernel/ps2.c new file mode 100644 index 0000000..d908bd9 --- /dev/null +++ b/kernel/ps2.c @@ -0,0 +1,107 @@ +#include "ps2.h" +#include "io.h" + +/* --- Controller Synchronization --- */ + +// Wait until the controller is ready to receive a byte +static void ps2_wait_write() { + while (inb(PS2_STATUS_REG) & PS2_STATUS_INPUT); +} + +// Wait until the controller has a byte for us to read +static void ps2_wait_read() { + while (!(inb(PS2_STATUS_REG) & PS2_STATUS_OUTPUT)); +} + +/* --- Initialization --- */ + +void ps2_write_device(uint8_t command) { + ps2_wait_write(); + outb(PS2_DATA_PORT, command); +} + +void ps2_write_mouse(uint8_t data) { + ps2_wait_write(); + outb(PS2_COMMAND_REG, PS2_CMD_WRITE_MOUSE); // "Next byte goes to mouse" + ps2_wait_write(); + outb(PS2_DATA_PORT, data); +} + +void ps2_init(void) { + // 1. Disable Devices + ps2_wait_write(); + outb(PS2_COMMAND_REG, PS2_CMD_DISABLE_KB); + ps2_wait_write(); + outb(PS2_COMMAND_REG, PS2_CMD_DISABLE_MS); + + // 2. Flush Output Buffer + while (inb(PS2_STATUS_REG) & PS2_STATUS_OUTPUT) { + inb(PS2_DATA_PORT); + } + + // 3. Set Controller Configuration Byte + // Bit 0: KB Interrupt, Bit 1: Mouse Interrupt, Bit 6: Translation + ps2_wait_write(); + outb(PS2_COMMAND_REG, PS2_CMD_READ_CONFIG); + ps2_wait_read(); + uint8_t status = inb(PS2_DATA_PORT); + status |= (1 << 0) | (1 << 1); // Enable IRQ 1 and IRQ 12 + + ps2_wait_write(); + outb(PS2_COMMAND_REG, PS2_CMD_WRITE_CONFIG); + ps2_wait_write(); + outb(PS2_DATA_PORT, status); + + // 4. Enable Devices + ps2_wait_write(); + outb(PS2_COMMAND_REG, PS2_CMD_ENABLE_KB); + ps2_wait_write(); + outb(PS2_COMMAND_REG, PS2_CMD_ENABLE_MS); + + // 5. Initialize Mouse (The mouse won't send IRQs until you tell it to) + ps2_write_mouse(MOUSE_CMD_SET_DEFAULTS); + ps2_wait_read(); inb(PS2_DATA_PORT); // Read ACK (0xFA) + + ps2_write_mouse(MOUSE_CMD_ENABLE_SCAN); + ps2_wait_read(); inb(PS2_DATA_PORT); // Read ACK (0xFA) +} + +/* --- IRQ Handlers --- */ + +// Called from IRQ 1 (Keyboard) +void ps2_keyboard_handler(void) { + uint8_t scancode = inb(PS2_DATA_PORT); + // Process scancode (e.g., put it into a circular buffer) +} + +// Called from IRQ 12 (Mouse) +static uint8_t mouse_cycle = 0; +static uint8_t mouse_bytes[3]; + +void ps2_mouse_handler(void) { + uint8_t status = inb(PS2_STATUS_REG); + + // Ensure this is actually mouse data + if (!(status & PS2_STATUS_MOUSE)) return; + + mouse_bytes[mouse_cycle++] = inb(PS2_DATA_PORT); + + if (mouse_cycle == 3) { + mouse_cycle = 0; + + // Byte 0: Flags (Buttons, Signs) + // Byte 1: X Delta + // Byte 2: Y Delta + + mouse_state_t state; + state.left_button = (mouse_bytes[0] & 0x01); + state.right_button = (mouse_bytes[0] & 0x02); + state.middle_button = (mouse_bytes[0] & 0x04); + + // Handle negative deltas (signed 9-bit logic) + state.x_delta = (int8_t)mouse_bytes[1]; + state.y_delta = (int8_t)mouse_bytes[2]; + + // Update your kernel's internal mouse position here + } +} diff --git a/kernel/ps2.h b/kernel/ps2.h new file mode 100644 index 0000000..6b3d3d3 --- /dev/null +++ b/kernel/ps2.h @@ -0,0 +1,45 @@ +#ifndef PS2_H +#define PS2_H + +#include +#include + +/* I/O Ports */ +#define PS2_DATA_PORT 0x60 +#define PS2_STATUS_REG 0x64 +#define PS2_COMMAND_REG 0x64 + +/* Status Register Bits */ +#define PS2_STATUS_OUTPUT 0x01 // 1 = Data ready to be read +#define PS2_STATUS_INPUT 0x02 // 1 = Controller busy, don't write yet +#define PS2_STATUS_SYS 0x04 // System flag +#define PS2_STATUS_CMD_DATA 0x08 // 0 = Data written to 0x60, 1 = Cmd to 0x64 +#define PS2_STATUS_MOUSE 0x20 // 1 = Mouse data, 0 = Keyboard data + +/* Controller Commands */ +#define PS2_CMD_READ_CONFIG 0x20 +#define PS2_CMD_WRITE_CONFIG 0x60 +#define PS2_CMD_DISABLE_MS 0xA7 +#define PS2_CMD_ENABLE_MS 0xA8 +#define PS2_CMD_DISABLE_KB 0xAD +#define PS2_CMD_ENABLE_KB 0xAE +#define PS2_CMD_WRITE_MOUSE 0xD4 + +/* Mouse Commands */ +#define MOUSE_CMD_SET_DEFAULTS 0xF6 +#define MOUSE_CMD_ENABLE_SCAN 0xF4 + +typedef struct { + int8_t x_delta; + int8_t y_delta; + bool left_button; + bool right_button; + bool middle_button; +} mouse_state_t; + +/* Public API */ +void ps2_init(void); +void ps2_keyboard_handler(void); +void ps2_mouse_handler(void); + +#endif diff --git a/kernel/threading.c b/kernel/threading.c index 64e22a7..2d77e68 100644 --- a/kernel/threading.c +++ b/kernel/threading.c @@ -4,8 +4,8 @@ #include "print.h" #include "threading.h" -#define MAX_THREADS 16 // Maximum number of threads -#define THREAD_STACK_SIZE 8192 // Stack size for each thread +#define MAX_THREADS 16 // Maximum number of threads +#define THREAD_STACK_SIZE 8192 // Stack size for each thread // The thread table stores information about all threads static Thread thread_table[MAX_THREADS]; @@ -16,103 +16,106 @@ static uint32_t num_threads = 0; // Number of active threads static volatile int mutex_locked = 0; // Function declaration for context_switch -void context_switch(Thread *next); +void context_switch(Thread* next); // Initialize the threading system void thread_init(void) { - memset(thread_table, 0, sizeof(thread_table)); - num_threads = 0; + memset(thread_table, 0, sizeof(thread_table)); + num_threads = 0; } // Create a new thread -void thread_create(Thread *thread __attribute__((unused)), void (*start_routine)(void *), void *arg) { - if (num_threads >= MAX_THREADS) { - my_printf("Error: Maximum thread count reached.\n"); - return; - } +void thread_create(Thread* thread __attribute__((unused)), + void (*start_routine)(void*), void* arg) { + if (num_threads >= MAX_THREADS) { + my_printf("Error: Maximum thread count reached.\n"); + return; + } - // Find an empty slot for the new thread - int index = num_threads++; - thread_table[index] = (Thread){0}; - - // Set up the new thread - thread_table[index].start_routine = start_routine; - thread_table[index].arg = arg; - thread_table[index].stack_size = THREAD_STACK_SIZE; - thread_table[index].stack = (uint32_t*)malloc(THREAD_STACK_SIZE); - thread_table[index].stack_top = thread_table[index].stack + THREAD_STACK_SIZE / sizeof(uint32_t); + // Find an empty slot for the new thread + int index = num_threads++; + thread_table[index] = (Thread){0}; - // Initialize the stack (simulate pushing the function's return address) - uint32_t *stack_top = thread_table[index].stack_top; - *(--stack_top) = (uint32_t)start_routine; // Return address (the thread's entry point) - *(--stack_top) = (uint32_t)arg; // Argument to pass to the thread + // Set up the new thread + thread_table[index].start_routine = start_routine; + thread_table[index].arg = arg; + thread_table[index].stack_size = THREAD_STACK_SIZE; + thread_table[index].stack = (uint32_t*)malloc(THREAD_STACK_SIZE); + thread_table[index].stack_top = + thread_table[index].stack + THREAD_STACK_SIZE / sizeof(uint32_t); - // Set the thread's state to ready - thread_table[index].state = THREAD_READY; + // Initialize the stack (simulate pushing the function's return address) + uint32_t* stack_top = thread_table[index].stack_top; + *(--stack_top) = + (uint32_t)start_routine; // Return address (the thread's entry point) + *(--stack_top) = (uint32_t)arg; // Argument to pass to the thread - // If this is the first thread, switch to it - if (index == 0) { - scheduler(); - } + // Set the thread's state to ready + thread_table[index].state = THREAD_READY; + + // If this is the first thread, switch to it + if (index == 0) { + scheduler(); + } } // Yield the CPU to another thread void thread_yield(void) { - // Find the next thread in a round-robin manner - uint32_t next_thread = (current_thread + 1) % num_threads; - while (next_thread != current_thread && thread_table[next_thread].state != THREAD_READY) { - next_thread = (next_thread + 1) % num_threads; - } + // Find the next thread in a round-robin manner + uint32_t next_thread = (current_thread + 1) % num_threads; + while (next_thread != current_thread && + thread_table[next_thread].state != THREAD_READY) { + next_thread = (next_thread + 1) % num_threads; + } - if (next_thread != current_thread) { - current_thread = next_thread; - scheduler(); - } + if (next_thread != current_thread) { + current_thread = next_thread; + scheduler(); + } } // Exit the current thread void thread_exit(void) { - thread_table[current_thread].state = THREAD_BLOCKED; // Mark the thread as blocked (finished) - free(thread_table[current_thread].stack); // Free the thread's stack - num_threads--; // Decrease thread count + thread_table[current_thread].state = + THREAD_BLOCKED; // Mark the thread as blocked (finished) + free(thread_table[current_thread].stack); // Free the thread's stack + num_threads--; // Decrease thread count - // Yield to the next thread - thread_yield(); + // Yield to the next thread + thread_yield(); } // Scheduler: This function selects the next thread to run void scheduler(void) { - // Find the next ready thread - uint32_t next_thread = (current_thread + 1) % num_threads; - while (thread_table[next_thread].state != THREAD_READY) { - next_thread = (next_thread + 1) % num_threads; - } + // Find the next ready thread + uint32_t next_thread = (current_thread + 1) % num_threads; + while (thread_table[next_thread].state != THREAD_READY) { + next_thread = (next_thread + 1) % num_threads; + } - if (next_thread != current_thread) { - current_thread = next_thread; - context_switch(&thread_table[current_thread]); - } + if (next_thread != current_thread) { + current_thread = next_thread; + context_switch(&thread_table[current_thread]); + } } -// Context switch to the next thread (assembly would go here to save/load registers) -void context_switch(Thread *next) { - // For simplicity, context switching in this example would involve saving/restoring registers. - // In a real system, you would need to save the CPU state (registers) and restore the next thread's state. - my_printf("Switching to thread...\n"); - next->start_routine(next->arg); // Start running the next thread +// Context switch to the next thread (assembly would go here to save/load +// registers) +void context_switch(Thread* next) { + // For simplicity, context switching in this example would involve + // saving/restoring registers. In a real system, you would need to save the + // CPU state (registers) and restore the next thread's state. + my_printf("Switching to thread...\n"); + next->start_routine(next->arg); // Start running the next thread } // Simple mutex functions (spinlock) -void mutex_init(void) { - mutex_locked = 0; -} +void mutex_init(void) { mutex_locked = 0; } void mutex_lock(void) { - while (__sync_lock_test_and_set(&mutex_locked, 1)) { - // Busy wait (spinlock) - } + while (__sync_lock_test_and_set(&mutex_locked, 1)) { + // Busy wait (spinlock) + } } -void mutex_unlock(void) { - __sync_lock_release(&mutex_locked); -} +void mutex_unlock(void) { __sync_lock_release(&mutex_locked); }