mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
Initial commit: SUB-OS 64-Bit Production Monolithic Operating System with LazyBox userland suite
This commit is contained in:
commit
cd9c786d14
88 files changed
+7132
No files matched your search
@@ -0,0 +1,135 @@
|
||||
#include <drivers/ata.h>
|
||||
#include <arch/x86_64/io.h>
|
||||
#include <kernel/printk.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
static ata_device_t primary_master;
|
||||
|
||||
static void ata_wait_ready(uint16_t io_base) {
|
||||
// 400ns delay
|
||||
inb(io_base + 7);
|
||||
inb(io_base + 7);
|
||||
inb(io_base + 7);
|
||||
inb(io_base + 7);
|
||||
|
||||
while (inb(io_base + 7) & 0x80); // Wait while BSY (Busy) bit is set
|
||||
}
|
||||
|
||||
static void ata_wait_drq(uint16_t io_base) {
|
||||
while (!(inb(io_base + 7) & 0x08)); // Wait while DRQ (Data Request) bit is clear
|
||||
}
|
||||
|
||||
bool ata_init(void) {
|
||||
memset(&primary_master, 0, sizeof(ata_device_t));
|
||||
|
||||
// Select Primary Master (Drive 0, LBA mode)
|
||||
outb(ATA_PRIMARY_IO + 6, 0xA0);
|
||||
outb(ATA_PRIMARY_IO + 2, 0);
|
||||
outb(ATA_PRIMARY_IO + 3, 0);
|
||||
outb(ATA_PRIMARY_IO + 4, 0);
|
||||
outb(ATA_PRIMARY_IO + 5, 0);
|
||||
outb(ATA_PRIMARY_IO + 7, 0xEC); // IDENTIFY Command
|
||||
|
||||
uint8_t status = inb(ATA_PRIMARY_IO + 7);
|
||||
if (status == 0 || status == 0xFF) {
|
||||
return false; // No drive
|
||||
}
|
||||
|
||||
ata_wait_ready(ATA_PRIMARY_IO);
|
||||
|
||||
uint8_t mid = inb(ATA_PRIMARY_IO + 4);
|
||||
uint8_t hi = inb(ATA_PRIMARY_IO + 5);
|
||||
if (mid != 0 || hi != 0) {
|
||||
return false; // ATAPI or not ATA
|
||||
}
|
||||
|
||||
ata_wait_drq(ATA_PRIMARY_IO);
|
||||
|
||||
uint16_t identify_data[256];
|
||||
for (int i = 0; i < 256; i++) {
|
||||
identify_data[i] = inw(ATA_PRIMARY_IO);
|
||||
}
|
||||
|
||||
primary_master.present = true;
|
||||
primary_master.is_master = true;
|
||||
primary_master.sector_count = (uint32_t)identify_data[60] | ((uint32_t)identify_data[61] << 16);
|
||||
|
||||
// Model String (Words 27-46, byte-swapped)
|
||||
char* model_ptr = (char*)&identify_data[27];
|
||||
for (int i = 0; i < 40; i += 2) {
|
||||
primary_master.model[i] = model_ptr[i + 1];
|
||||
primary_master.model[i + 1] = model_ptr[i];
|
||||
}
|
||||
primary_master.model[40] = '\0';
|
||||
|
||||
// Trim trailing spaces in model
|
||||
for (int i = 39; i >= 0 && primary_master.model[i] == ' '; i--) {
|
||||
primary_master.model[i] = '\0';
|
||||
}
|
||||
|
||||
printk(KERN_INFO "ATA: Primary Master Disk: %s (%llu MB, %u sectors)\n",
|
||||
primary_master.model,
|
||||
((uint64_t)primary_master.sector_count * 512) / (1024 * 1024),
|
||||
primary_master.sector_count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ata_read_sectors(uint32_t lba, uint8_t count, void* buffer) {
|
||||
if (!primary_master.present || !buffer || count == 0) return false;
|
||||
|
||||
ata_wait_ready(ATA_PRIMARY_IO);
|
||||
|
||||
outb(ATA_PRIMARY_IO + 6, 0xE0 | ((lba >> 24) & 0x0F)); // Master, LBA mode
|
||||
outb(ATA_PRIMARY_IO + 2, count);
|
||||
outb(ATA_PRIMARY_IO + 3, (uint8_t)lba);
|
||||
outb(ATA_PRIMARY_IO + 4, (uint8_t)(lba >> 8));
|
||||
outb(ATA_PRIMARY_IO + 5, (uint8_t)(lba >> 16));
|
||||
outb(ATA_PRIMARY_IO + 7, 0x20); // READ SECTORS command
|
||||
|
||||
uint16_t* ptr = (uint16_t*)buffer;
|
||||
|
||||
for (uint8_t s = 0; s < count; s++) {
|
||||
ata_wait_ready(ATA_PRIMARY_IO);
|
||||
ata_wait_drq(ATA_PRIMARY_IO);
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
*ptr++ = inw(ATA_PRIMARY_IO);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ata_write_sectors(uint32_t lba, uint8_t count, const void* buffer) {
|
||||
if (!primary_master.present || !buffer || count == 0) return false;
|
||||
|
||||
ata_wait_ready(ATA_PRIMARY_IO);
|
||||
|
||||
outb(ATA_PRIMARY_IO + 6, 0xE0 | ((lba >> 24) & 0x0F));
|
||||
outb(ATA_PRIMARY_IO + 2, count);
|
||||
outb(ATA_PRIMARY_IO + 3, (uint8_t)lba);
|
||||
outb(ATA_PRIMARY_IO + 4, (uint8_t)(lba >> 8));
|
||||
outb(ATA_PRIMARY_IO + 5, (uint8_t)(lba >> 16));
|
||||
outb(ATA_PRIMARY_IO + 7, 0x30); // WRITE SECTORS command
|
||||
|
||||
const uint16_t* ptr = (const uint16_t*)buffer;
|
||||
|
||||
for (uint8_t s = 0; s < count; s++) {
|
||||
ata_wait_ready(ATA_PRIMARY_IO);
|
||||
ata_wait_drq(ATA_PRIMARY_IO);
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
outw(ATA_PRIMARY_IO, *ptr++);
|
||||
}
|
||||
}
|
||||
|
||||
// Flush Cache
|
||||
outb(ATA_PRIMARY_IO + 7, 0xE7);
|
||||
ata_wait_ready(ATA_PRIMARY_IO);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const ata_device_t* ata_get_primary_master(void) {
|
||||
return &primary_master;
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
#include <drivers/keyboard.h>
|
||||
#include <drivers/tty.h>
|
||||
#include <arch/x86_64/isr.h>
|
||||
#include <arch/x86_64/pic.h>
|
||||
#include <arch/x86_64/io.h>
|
||||
|
||||
#define KEYBOARD_DATA_PORT 0x60
|
||||
#define KEYBOARD_STATUS_PORT 0x64
|
||||
#define KEYBOARD_BUFFER_SIZE 128
|
||||
|
||||
static volatile uint16_t key_buffer[KEYBOARD_BUFFER_SIZE];
|
||||
static volatile int buffer_head = 0;
|
||||
static volatile int buffer_tail = 0;
|
||||
|
||||
static bool shift_pressed = false;
|
||||
static bool ctrl_pressed = false;
|
||||
static bool alt_pressed = false;
|
||||
static bool capslock = false;
|
||||
static bool extended_code = false;
|
||||
|
||||
static const char scancode_ascii[128] = {
|
||||
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||
0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
|
||||
0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0,
|
||||
'*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static const char scancode_ascii_shift[128] = {
|
||||
0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
|
||||
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
|
||||
0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',
|
||||
0, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0,
|
||||
'*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static void buffer_enqueue(uint16_t key) {
|
||||
int next = (buffer_head + 1) % KEYBOARD_BUFFER_SIZE;
|
||||
if (next != buffer_tail) {
|
||||
key_buffer[buffer_head] = key;
|
||||
buffer_head = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void keyboard_interrupt_handler(registers_t* regs) {
|
||||
(void)regs;
|
||||
uint8_t scancode = inb(KEYBOARD_DATA_PORT);
|
||||
|
||||
if (scancode == 0xE0) {
|
||||
extended_code = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (scancode & 0x80) { // Key Release
|
||||
uint8_t released = scancode & 0x7F;
|
||||
if (released == 0x2A || released == 0x36) shift_pressed = false;
|
||||
else if (released == 0x1D) ctrl_pressed = false;
|
||||
else if (released == 0x38) alt_pressed = false;
|
||||
extended_code = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Key Press
|
||||
if (scancode == 0x2A || scancode == 0x36) { shift_pressed = true; return; }
|
||||
if (scancode == 0x1D) { ctrl_pressed = true; return; }
|
||||
if (scancode == 0x38) { alt_pressed = true; return; }
|
||||
if (scancode == 0x3A) { capslock = !capslock; return; }
|
||||
|
||||
// Alt + F1..F4 -> Switch Virtual Consoles
|
||||
if (alt_pressed) {
|
||||
if (scancode >= 0x3B && scancode <= 0x3E) { // F1 - F4
|
||||
tty_switch(scancode - 0x3B);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (extended_code) {
|
||||
extended_code = false;
|
||||
switch (scancode) {
|
||||
case 0x48: buffer_enqueue(KEY_UP); return;
|
||||
case 0x50: buffer_enqueue(KEY_DOWN); return;
|
||||
case 0x4B: buffer_enqueue(KEY_LEFT); return;
|
||||
case 0x4D: buffer_enqueue(KEY_RIGHT); return;
|
||||
case 0x47: buffer_enqueue(KEY_HOME); return;
|
||||
case 0x4F: buffer_enqueue(KEY_END); return;
|
||||
case 0x49: buffer_enqueue(KEY_PAGE_UP); return;
|
||||
case 0x51: buffer_enqueue(KEY_PAGE_DOWN); return;
|
||||
case 0x52: buffer_enqueue(KEY_INSERT); return;
|
||||
case 0x53: buffer_enqueue(KEY_DELETE); return;
|
||||
}
|
||||
}
|
||||
|
||||
// Function Keys F1-F12
|
||||
if (scancode >= 0x3B && scancode <= 0x44) {
|
||||
buffer_enqueue(KEY_F1 + (scancode - 0x3B));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctrl_pressed) {
|
||||
if (scancode == 0x2E) { buffer_enqueue(0x03); return; } // Ctrl+C
|
||||
if (scancode == 0x26) { buffer_enqueue(0x0C); return; } // Ctrl+L
|
||||
if (scancode == 0x20) { buffer_enqueue(0x04); return; } // Ctrl+D
|
||||
}
|
||||
|
||||
bool use_shift = shift_pressed ^ capslock;
|
||||
char c = use_shift ? scancode_ascii_shift[scancode] : scancode_ascii[scancode];
|
||||
if (c) {
|
||||
buffer_enqueue((uint16_t)c);
|
||||
}
|
||||
}
|
||||
|
||||
void keyboard_init(void) {
|
||||
buffer_head = 0;
|
||||
buffer_tail = 0;
|
||||
|
||||
isr_register_handler(33, keyboard_interrupt_handler); // IRQ1
|
||||
pic_clear_mask(1);
|
||||
}
|
||||
|
||||
bool keyboard_has_key(void) {
|
||||
return buffer_head != buffer_tail;
|
||||
}
|
||||
|
||||
uint16_t keyboard_get_key(void) {
|
||||
while (!keyboard_has_key()) {
|
||||
hlt();
|
||||
}
|
||||
uint16_t key = key_buffer[buffer_tail];
|
||||
buffer_tail = (buffer_tail + 1) % KEYBOARD_BUFFER_SIZE;
|
||||
return key;
|
||||
}
|
||||
|
||||
char keyboard_get_char(void) {
|
||||
uint16_t key = keyboard_get_key();
|
||||
if (key & KEY_SPECIAL_FLAG) return 0;
|
||||
return (char)(key & 0xFF);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#include <drivers/serial.h>
|
||||
#include <arch/x86_64/io.h>
|
||||
|
||||
void serial_init(void) {
|
||||
outb(COM1_PORT + 1, 0x00); // Disable all interrupts
|
||||
outb(COM1_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
|
||||
outb(COM1_PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
|
||||
outb(COM1_PORT + 1, 0x00); // (hi byte)
|
||||
outb(COM1_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
|
||||
outb(COM1_PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
||||
outb(COM1_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
||||
}
|
||||
|
||||
static bool serial_is_transmit_empty(void) {
|
||||
return (inb(COM1_PORT + 5) & 0x20) != 0;
|
||||
}
|
||||
|
||||
void serial_write_char(char c) {
|
||||
while (!serial_is_transmit_empty());
|
||||
outb(COM1_PORT, c);
|
||||
}
|
||||
|
||||
void serial_write_string(const char* str) {
|
||||
while (*str) {
|
||||
if (*str == '\n') {
|
||||
serial_write_char('\r');
|
||||
}
|
||||
serial_write_char(*str++);
|
||||
}
|
||||
}
|
||||
|
||||
bool serial_received(void) {
|
||||
return (inb(COM1_PORT + 5) & 1) != 0;
|
||||
}
|
||||
|
||||
char serial_read_char(void) {
|
||||
while (!serial_received());
|
||||
return inb(COM1_PORT);
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
#include <drivers/tty.h>
|
||||
#include <drivers/vga.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t buffer[TTY_HEIGHT][TTY_WIDTH];
|
||||
int cursor_row;
|
||||
int cursor_col;
|
||||
uint8_t current_color;
|
||||
} tty_t;
|
||||
|
||||
static tty_t ttys[MAX_TTYS];
|
||||
static int current_tty = 0;
|
||||
|
||||
static volatile uint16_t* const VGA_MEM = (uint16_t*)VGA_MEMORY;
|
||||
|
||||
static void tty_render_current(void) {
|
||||
tty_t* t = &ttys[current_tty];
|
||||
for (int y = 0; y < TTY_HEIGHT; y++) {
|
||||
for (int x = 0; x < TTY_WIDTH; x++) {
|
||||
VGA_MEM[y * TTY_WIDTH + x] = t->buffer[y][x];
|
||||
}
|
||||
}
|
||||
vga_set_cursor(t->cursor_row, t->cursor_col);
|
||||
}
|
||||
|
||||
void tty_switch(int index) {
|
||||
if (index < 0 || index >= MAX_TTYS) return;
|
||||
current_tty = index;
|
||||
tty_render_current();
|
||||
}
|
||||
|
||||
int tty_get_current(void) {
|
||||
return current_tty;
|
||||
}
|
||||
|
||||
static void tty_scroll(tty_t* t) {
|
||||
for (int y = 0; y < TTY_HEIGHT - 1; y++) {
|
||||
for (int x = 0; x < TTY_WIDTH; x++) {
|
||||
t->buffer[y][x] = t->buffer[y + 1][x];
|
||||
}
|
||||
}
|
||||
for (int x = 0; x < TTY_WIDTH; x++) {
|
||||
t->buffer[TTY_HEIGHT - 1][x] = vga_entry(' ', t->current_color);
|
||||
}
|
||||
t->cursor_row = TTY_HEIGHT - 1;
|
||||
}
|
||||
|
||||
void tty_clear(void) {
|
||||
tty_t* t = &ttys[current_tty];
|
||||
for (int y = 0; y < TTY_HEIGHT; y++) {
|
||||
for (int x = 0; x < TTY_WIDTH; x++) {
|
||||
t->buffer[y][x] = vga_entry(' ', t->current_color);
|
||||
}
|
||||
}
|
||||
t->cursor_row = 0;
|
||||
t->cursor_col = 0;
|
||||
tty_render_current();
|
||||
}
|
||||
|
||||
void tty_set_cursor(int row, int col) {
|
||||
tty_t* t = &ttys[current_tty];
|
||||
t->cursor_row = row;
|
||||
t->cursor_col = col;
|
||||
vga_set_cursor(row, col);
|
||||
}
|
||||
|
||||
void tty_write(const char* data, size_t size) {
|
||||
tty_t* t = &ttys[current_tty];
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
char c = data[i];
|
||||
|
||||
// Basic ANSI escape sequence parser (e.g. \033[31m)
|
||||
if (c == '\033' && i + 1 < size && data[i + 1] == '[') {
|
||||
i += 2;
|
||||
int code = 0;
|
||||
while (i < size && data[i] >= '0' && data[i] <= '9') {
|
||||
code = code * 10 + (data[i] - '0');
|
||||
i++;
|
||||
}
|
||||
if (i < size && data[i] == 'm') {
|
||||
if (code == 0) t->current_color = 0x07; // Reset
|
||||
else if (code == 31) t->current_color = 0x04; // Red
|
||||
else if (code == 32) t->current_color = 0x02; // Green
|
||||
else if (code == 33) t->current_color = 0x06; // Brown/Yellow
|
||||
else if (code == 34) t->current_color = 0x01; // Blue
|
||||
else if (code == 35) t->current_color = 0x05; // Magenta
|
||||
else if (code == 36) t->current_color = 0x03; // Cyan
|
||||
else if (code == 37) t->current_color = 0x07; // White
|
||||
else if (code == 90) t->current_color = 0x08; // Bright Black (Dark Grey)
|
||||
else if (code == 91) t->current_color = 0x0C; // Bright Red
|
||||
else if (code == 92) t->current_color = 0x0A; // Bright Green
|
||||
else if (code == 93) t->current_color = 0x0E; // Bright Yellow
|
||||
else if (code == 94) t->current_color = 0x09; // Bright Blue
|
||||
else if (code == 95) t->current_color = 0x0D; // Bright Magenta
|
||||
else if (code == 96) t->current_color = 0x0B; // Bright Cyan
|
||||
else if (code == 97) t->current_color = 0x0F; // Bright White
|
||||
} else if (i < size && data[i] == 'K') {
|
||||
// Clear from cursor to end of line
|
||||
for (int x = t->cursor_col; x < TTY_WIDTH; x++) {
|
||||
t->buffer[t->cursor_row][x] = vga_entry(' ', t->current_color);
|
||||
}
|
||||
} else if (i < size && data[i] == 'D') {
|
||||
// Move cursor left
|
||||
if (t->cursor_col > 0) t->cursor_col--;
|
||||
} else if (i < size && data[i] == 'C') {
|
||||
// Move cursor right
|
||||
if (t->cursor_col < TTY_WIDTH - 1) t->cursor_col++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\n') {
|
||||
t->cursor_col = 0;
|
||||
if (++t->cursor_row >= TTY_HEIGHT) {
|
||||
tty_scroll(t);
|
||||
}
|
||||
} else if (c == '\r') {
|
||||
t->cursor_col = 0;
|
||||
} else if (c == '\t') {
|
||||
t->cursor_col = (t->cursor_col + 8) & ~7;
|
||||
if (t->cursor_col >= TTY_WIDTH) {
|
||||
t->cursor_col = 0;
|
||||
if (++t->cursor_row >= TTY_HEIGHT) {
|
||||
tty_scroll(t);
|
||||
}
|
||||
}
|
||||
} else if (c == '\b') {
|
||||
if (t->cursor_col > 0) {
|
||||
t->cursor_col--;
|
||||
t->buffer[t->cursor_row][t->cursor_col] = vga_entry(' ', t->current_color);
|
||||
}
|
||||
} else {
|
||||
t->buffer[t->cursor_row][t->cursor_col] = vga_entry(c, t->current_color);
|
||||
if (++t->cursor_col >= TTY_WIDTH) {
|
||||
t->cursor_col = 0;
|
||||
if (++t->cursor_row >= TTY_HEIGHT) {
|
||||
tty_scroll(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tty_render_current();
|
||||
}
|
||||
|
||||
void tty_write_string(const char* data) {
|
||||
tty_write(data, strlen(data));
|
||||
}
|
||||
|
||||
void tty_init(void) {
|
||||
vga_init();
|
||||
for (int i = 0; i < MAX_TTYS; i++) {
|
||||
ttys[i].cursor_row = 0;
|
||||
ttys[i].cursor_col = 0;
|
||||
ttys[i].current_color = 0x07;
|
||||
for (int y = 0; y < TTY_HEIGHT; y++) {
|
||||
for (int x = 0; x < TTY_WIDTH; x++) {
|
||||
ttys[i].buffer[y][x] = vga_entry(' ', 0x07);
|
||||
}
|
||||
}
|
||||
}
|
||||
current_tty = 0;
|
||||
tty_render_current();
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
#include <drivers/vga.h>
|
||||
#include <arch/x86_64/io.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
static volatile uint16_t* const VGA_BUFFER = (uint16_t*)VGA_MEMORY;
|
||||
static uint8_t vga_color = 0x07;
|
||||
static int vga_row = 0;
|
||||
static int vga_col = 0;
|
||||
|
||||
void vga_set_cursor(int row, int col) {
|
||||
vga_row = row;
|
||||
vga_col = col;
|
||||
uint16_t pos = row * VGA_WIDTH + col;
|
||||
|
||||
outb(0x3D4, 0x0F);
|
||||
outb(0x3D5, (uint8_t)(pos & 0xFF));
|
||||
outb(0x3D4, 0x0E);
|
||||
outb(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
|
||||
}
|
||||
|
||||
void vga_get_cursor(int* row, int* col) {
|
||||
if (row) *row = vga_row;
|
||||
if (col) *col = vga_col;
|
||||
}
|
||||
|
||||
void vga_enable_cursor(uint8_t cursor_start, uint8_t cursor_end) {
|
||||
outb(0x3D4, 0x0A);
|
||||
outb(0x3D5, (inb(0x3D5) & 0xC0) | cursor_start);
|
||||
outb(0x3D4, 0x0B);
|
||||
outb(0x3D5, (inb(0x3D5) & 0xE0) | cursor_end);
|
||||
}
|
||||
|
||||
void vga_disable_cursor(void) {
|
||||
outb(0x3D4, 0x0A);
|
||||
outb(0x3D5, 0x20);
|
||||
}
|
||||
|
||||
void vga_set_color(enum vga_color fg, enum vga_color bg) {
|
||||
vga_color = vga_entry_color(fg, bg);
|
||||
}
|
||||
|
||||
void vga_clear(void) {
|
||||
for (int y = 0; y < VGA_HEIGHT; y++) {
|
||||
for (int x = 0; x < VGA_WIDTH; x++) {
|
||||
VGA_BUFFER[y * VGA_WIDTH + x] = vga_entry(' ', vga_color);
|
||||
}
|
||||
}
|
||||
vga_set_cursor(0, 0);
|
||||
}
|
||||
|
||||
static void vga_scroll(void) {
|
||||
for (int y = 0; y < VGA_HEIGHT - 1; y++) {
|
||||
for (int x = 0; x < VGA_WIDTH; x++) {
|
||||
VGA_BUFFER[y * VGA_WIDTH + x] = VGA_BUFFER[(y + 1) * VGA_WIDTH + x];
|
||||
}
|
||||
}
|
||||
for (int x = 0; x < VGA_WIDTH; x++) {
|
||||
VGA_BUFFER[(VGA_HEIGHT - 1) * VGA_WIDTH + x] = vga_entry(' ', vga_color);
|
||||
}
|
||||
vga_row = VGA_HEIGHT - 1;
|
||||
}
|
||||
|
||||
void vga_putc(char c) {
|
||||
if (c == '\n') {
|
||||
vga_col = 0;
|
||||
if (++vga_row >= VGA_HEIGHT) {
|
||||
vga_scroll();
|
||||
}
|
||||
} else if (c == '\r') {
|
||||
vga_col = 0;
|
||||
} else if (c == '\t') {
|
||||
vga_col = (vga_col + 8) & ~7;
|
||||
if (vga_col >= VGA_WIDTH) {
|
||||
vga_col = 0;
|
||||
if (++vga_row >= VGA_HEIGHT) {
|
||||
vga_scroll();
|
||||
}
|
||||
}
|
||||
} else if (c == '\b') {
|
||||
if (vga_col > 0) {
|
||||
vga_col--;
|
||||
VGA_BUFFER[vga_row * VGA_WIDTH + vga_col] = vga_entry(' ', vga_color);
|
||||
}
|
||||
} else {
|
||||
VGA_BUFFER[vga_row * VGA_WIDTH + vga_col] = vga_entry(c, vga_color);
|
||||
if (++vga_col >= VGA_WIDTH) {
|
||||
vga_col = 0;
|
||||
if (++vga_row >= VGA_HEIGHT) {
|
||||
vga_scroll();
|
||||
}
|
||||
}
|
||||
}
|
||||
vga_set_cursor(vga_row, vga_col);
|
||||
}
|
||||
|
||||
void vga_write(const char* str) {
|
||||
while (*str) {
|
||||
vga_putc(*str++);
|
||||
}
|
||||
}
|
||||
|
||||
void vga_init(void) {
|
||||
vga_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
|
||||
vga_clear();
|
||||
vga_enable_cursor(14, 15);
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
#include <drivers/e1000.h>
|
||||
#include <drivers/pci.h>
|
||||
#include <net/net.h>
|
||||
#include <mm/kmalloc.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <arch/x86_64/isr.h>
|
||||
#include <arch/x86_64/pic.h>
|
||||
#include <arch/x86_64/io.h>
|
||||
#include <lib/string.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
#define REG_CTRL 0x0000
|
||||
#define REG_STATUS 0x0008
|
||||
#define REG_EEPROM 0x0014
|
||||
#define REG_ICR 0x00C0
|
||||
#define REG_IMS 0x00D0
|
||||
#define REG_IMC 0x00D8
|
||||
#define REG_RCTL 0x0100
|
||||
#define REG_RDBAL 0x2800
|
||||
#define REG_RDBAH 0x2804
|
||||
#define REG_RDLEN 0x2808
|
||||
#define REG_RDH 0x2810
|
||||
#define REG_RDT 0x2818
|
||||
#define REG_TCTL 0x0400
|
||||
#define REG_TDBAL 0x3800
|
||||
#define REG_TDBAH 0x3804
|
||||
#define REG_TDLEN 0x3808
|
||||
#define REG_TDH 0x3810
|
||||
#define REG_TDT 0x3818
|
||||
|
||||
#define NUM_RX_DESCRIPTORS 32
|
||||
#define NUM_TX_DESCRIPTORS 16
|
||||
#define RX_BUFFER_SIZE 2048
|
||||
|
||||
typedef struct {
|
||||
uint64_t buffer_addr;
|
||||
uint16_t length;
|
||||
uint16_t checksum;
|
||||
uint8_t status;
|
||||
uint8_t errors;
|
||||
uint16_t special;
|
||||
} __attribute__((packed)) e1000_rx_desc_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t buffer_addr;
|
||||
uint16_t length;
|
||||
uint8_t cso;
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
uint8_t css;
|
||||
uint16_t special;
|
||||
} __attribute__((packed)) e1000_tx_desc_t;
|
||||
|
||||
static pci_device_t* e1000_pci_dev = NULL;
|
||||
static uint64_t mmio_base = 0;
|
||||
static uint16_t io_base = 0;
|
||||
static bool use_mmio = true;
|
||||
static uint8_t mac_addr[6] = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56};
|
||||
|
||||
static e1000_rx_desc_t* rx_descriptors = NULL;
|
||||
static uint8_t* rx_buffers[NUM_RX_DESCRIPTORS];
|
||||
static uint16_t rx_cur = 0;
|
||||
|
||||
static e1000_tx_desc_t* tx_descriptors = NULL;
|
||||
static uint8_t* tx_buffers[NUM_TX_DESCRIPTORS];
|
||||
static uint16_t tx_cur = 0;
|
||||
|
||||
static uint64_t stats_rx_packets = 0;
|
||||
static uint64_t stats_tx_packets = 0;
|
||||
static uint64_t stats_rx_bytes = 0;
|
||||
static uint64_t stats_tx_bytes = 0;
|
||||
|
||||
static inline void e1000_write32(uint32_t reg, uint32_t val) {
|
||||
if (use_mmio && mmio_base) {
|
||||
*((volatile uint32_t*)(mmio_base + reg)) = val;
|
||||
} else if (io_base) {
|
||||
outl(io_base, reg);
|
||||
outl(io_base + 4, val);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t e1000_read32(uint32_t reg) {
|
||||
if (use_mmio && mmio_base) {
|
||||
return *((volatile uint32_t*)(mmio_base + reg));
|
||||
} else if (io_base) {
|
||||
outl(io_base, reg);
|
||||
return inl(io_base + 4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void e1000_read_mac(void) {
|
||||
uint32_t ral = e1000_read32(0x5400);
|
||||
uint32_t rah = e1000_read32(0x5404);
|
||||
|
||||
if (ral != 0 || (rah & 0xFFFF) != 0) {
|
||||
mac_addr[0] = ral & 0xFF;
|
||||
mac_addr[1] = (ral >> 8) & 0xFF;
|
||||
mac_addr[2] = (ral >> 16) & 0xFF;
|
||||
mac_addr[3] = (ral >> 24) & 0xFF;
|
||||
mac_addr[4] = rah & 0xFF;
|
||||
mac_addr[5] = (rah >> 8) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
static void e1000_handle_receive(void) {
|
||||
while (rx_descriptors[rx_cur].status & 0x01) {
|
||||
uint16_t len = rx_descriptors[rx_cur].length;
|
||||
uint8_t* buf = rx_buffers[rx_cur];
|
||||
|
||||
stats_rx_packets++;
|
||||
stats_rx_bytes += len;
|
||||
|
||||
// Forward to network stack
|
||||
net_receive(buf, len);
|
||||
|
||||
rx_descriptors[rx_cur].status = 0;
|
||||
uint16_t old_cur = rx_cur;
|
||||
rx_cur = (rx_cur + 1) % NUM_RX_DESCRIPTORS;
|
||||
e1000_write32(REG_RDT, old_cur);
|
||||
}
|
||||
}
|
||||
|
||||
static void e1000_interrupt_handler(registers_t* regs) {
|
||||
(void)regs;
|
||||
uint32_t icr = e1000_read32(REG_ICR);
|
||||
|
||||
if (icr & 0x80) {
|
||||
e1000_handle_receive();
|
||||
}
|
||||
if (icr & 0x04) {
|
||||
printk(KERN_INFO "[E1000] Link status changed: %s\n", e1000_is_link_up() ? "UP" : "DOWN");
|
||||
}
|
||||
}
|
||||
|
||||
static void e1000_init_rx(void) {
|
||||
rx_descriptors = (e1000_rx_desc_t*)kzalloc(sizeof(e1000_rx_desc_t) * NUM_RX_DESCRIPTORS + 16);
|
||||
rx_descriptors = (e1000_rx_desc_t*)(((uint64_t)rx_descriptors + 15) & ~15);
|
||||
|
||||
for (int i = 0; i < NUM_RX_DESCRIPTORS; i++) {
|
||||
rx_buffers[i] = (uint8_t*)kmalloc(RX_BUFFER_SIZE + 16);
|
||||
rx_descriptors[i].buffer_addr = (uint64_t)rx_buffers[i];
|
||||
rx_descriptors[i].status = 0;
|
||||
}
|
||||
|
||||
uint64_t rx_desc_phys = (uint64_t)rx_descriptors;
|
||||
e1000_write32(REG_RDBAL, (uint32_t)(rx_desc_phys & 0xFFFFFFFF));
|
||||
e1000_write32(REG_RDBAH, (uint32_t)(rx_desc_phys >> 32));
|
||||
e1000_write32(REG_RDLEN, NUM_RX_DESCRIPTORS * sizeof(e1000_rx_desc_t));
|
||||
e1000_write32(REG_RDH, 0);
|
||||
e1000_write32(REG_RDT, NUM_RX_DESCRIPTORS - 1);
|
||||
rx_cur = 0;
|
||||
|
||||
// RCTL: Enable, Broadcast, Strip CRC, Multicast
|
||||
e1000_write32(REG_RCTL, (1 << 1) | (1 << 15) | (1 << 26) | (1 << 4));
|
||||
}
|
||||
|
||||
static void e1000_init_tx(void) {
|
||||
tx_descriptors = (e1000_tx_desc_t*)kzalloc(sizeof(e1000_tx_desc_t) * NUM_TX_DESCRIPTORS + 16);
|
||||
tx_descriptors = (e1000_tx_desc_t*)(((uint64_t)tx_descriptors + 15) & ~15);
|
||||
|
||||
for (int i = 0; i < NUM_TX_DESCRIPTORS; i++) {
|
||||
tx_buffers[i] = (uint8_t*)kmalloc(RX_BUFFER_SIZE + 16);
|
||||
tx_descriptors[i].buffer_addr = (uint64_t)tx_buffers[i];
|
||||
tx_descriptors[i].status = 1;
|
||||
tx_descriptors[i].cmd = 0;
|
||||
}
|
||||
|
||||
uint64_t tx_desc_phys = (uint64_t)tx_descriptors;
|
||||
e1000_write32(REG_TDBAL, (uint32_t)(tx_desc_phys & 0xFFFFFFFF));
|
||||
e1000_write32(REG_TDBAH, (uint32_t)(tx_desc_phys >> 32));
|
||||
e1000_write32(REG_TDLEN, NUM_TX_DESCRIPTORS * sizeof(e1000_tx_desc_t));
|
||||
e1000_write32(REG_TDH, 0);
|
||||
e1000_write32(REG_TDT, 0);
|
||||
tx_cur = 0;
|
||||
|
||||
// TCTL: Enable, Pad Short Packets, Collisions
|
||||
e1000_write32(REG_TCTL, (1 << 1) | (1 << 3) | (0x0F << 4) | (0x40 << 12));
|
||||
}
|
||||
|
||||
bool e1000_init(void) {
|
||||
e1000_pci_dev = pci_find_device(E1000_VENDOR_ID, E1000_DEV_82540EM);
|
||||
if (!e1000_pci_dev) e1000_pci_dev = pci_find_device(E1000_VENDOR_ID, E1000_DEV_82545EM);
|
||||
if (!e1000_pci_dev) e1000_pci_dev = pci_find_class(PCI_CLASS_NETWORK, PCI_SUBCLASS_ETHERNET);
|
||||
|
||||
if (!e1000_pci_dev) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pci_enable_bus_mastering(e1000_pci_dev);
|
||||
|
||||
if (e1000_pci_dev->bar_type[0] == 0 && e1000_pci_dev->bar[0] != 0) {
|
||||
mmio_base = e1000_pci_dev->bar[0] & ~0xF;
|
||||
use_mmio = true;
|
||||
} else {
|
||||
io_base = (uint16_t)(e1000_pci_dev->bar[1] & ~0x3);
|
||||
use_mmio = false;
|
||||
}
|
||||
|
||||
e1000_read_mac();
|
||||
|
||||
uint8_t irq = e1000_pci_dev->irq;
|
||||
if (irq > 0 && irq <= 15) {
|
||||
isr_register_handler(32 + irq, e1000_interrupt_handler);
|
||||
pic_clear_mask(irq);
|
||||
}
|
||||
|
||||
e1000_init_rx();
|
||||
e1000_init_tx();
|
||||
|
||||
e1000_write32(REG_IMS, (1 << 7) | (1 << 4) | (1 << 6) | (1 << 2));
|
||||
e1000_read32(REG_ICR);
|
||||
|
||||
printk(KERN_INFO "[E1000] Initialized. MAC: %02x:%02x:%02x:%02x:%02x:%02x (IRQ %d)\n",
|
||||
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], irq);
|
||||
return true;
|
||||
}
|
||||
|
||||
void e1000_send(const void* data, uint16_t len) {
|
||||
if (!data || len == 0) return;
|
||||
|
||||
while (!(tx_descriptors[tx_cur].status & 0x01)) {
|
||||
io_wait();
|
||||
}
|
||||
|
||||
memcpy(tx_buffers[tx_cur], data, len);
|
||||
tx_descriptors[tx_cur].length = len;
|
||||
tx_descriptors[tx_cur].cmd = (1 << 0) | (1 << 1) | (1 << 3); // EOP, RS, IFCS
|
||||
tx_descriptors[tx_cur].status = 0;
|
||||
|
||||
tx_cur = (tx_cur + 1) % NUM_TX_DESCRIPTORS;
|
||||
stats_tx_packets++;
|
||||
stats_tx_bytes += len;
|
||||
|
||||
e1000_write32(REG_TDT, tx_cur);
|
||||
}
|
||||
|
||||
void e1000_get_mac(uint8_t* mac_out) {
|
||||
if (mac_out) {
|
||||
memcpy(mac_out, mac_addr, 6);
|
||||
}
|
||||
}
|
||||
|
||||
bool e1000_is_link_up(void) {
|
||||
uint32_t status = e1000_read32(REG_STATUS);
|
||||
return (status & (1 << 1)) != 0;
|
||||
}
|
||||
|
||||
uint64_t e1000_get_rx_packets(void) { return stats_rx_packets; }
|
||||
uint64_t e1000_get_tx_packets(void) { return stats_tx_packets; }
|
||||
uint64_t e1000_get_rx_bytes(void) { return stats_rx_bytes; }
|
||||
uint64_t e1000_get_tx_bytes(void) { return stats_tx_bytes; }
|
||||
@@ -0,0 +1,138 @@
|
||||
#include <drivers/pci.h>
|
||||
#include <arch/x86_64/io.h>
|
||||
#include <mm/kmalloc.h>
|
||||
#include <kernel/printk.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
static pci_device_t* pci_device_list = NULL;
|
||||
|
||||
uint32_t pci_config_read32(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
|
||||
uint32_t address = (uint32_t)((1U << 31) |
|
||||
((uint32_t)bus << 16) |
|
||||
((uint32_t)slot << 11) |
|
||||
((uint32_t)func << 8) |
|
||||
(offset & 0xFC));
|
||||
outl(PCI_CONFIG_ADDRESS, address);
|
||||
return inl(PCI_CONFIG_DATA);
|
||||
}
|
||||
|
||||
uint16_t pci_config_read16(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
|
||||
uint32_t val = pci_config_read32(bus, slot, func, offset);
|
||||
return (uint16_t)((val >> ((offset & 2) * 8)) & 0xFFFF);
|
||||
}
|
||||
|
||||
uint8_t pci_config_read8(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
|
||||
uint32_t val = pci_config_read32(bus, slot, func, offset);
|
||||
return (uint8_t)((val >> ((offset & 3) * 8)) & 0xFF);
|
||||
}
|
||||
|
||||
void pci_config_write32(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t val) {
|
||||
uint32_t address = (uint32_t)((1U << 31) |
|
||||
((uint32_t)bus << 16) |
|
||||
((uint32_t)slot << 11) |
|
||||
((uint32_t)func << 8) |
|
||||
(offset & 0xFC));
|
||||
outl(PCI_CONFIG_ADDRESS, address);
|
||||
outl(PCI_CONFIG_DATA, val);
|
||||
}
|
||||
|
||||
void pci_config_write16(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint16_t val) {
|
||||
uint32_t old = pci_config_read32(bus, slot, func, offset);
|
||||
uint32_t shift = (offset & 2) * 8;
|
||||
uint32_t mask = 0xFFFF << shift;
|
||||
uint32_t new_val = (old & ~mask) | ((uint32_t)val << shift);
|
||||
pci_config_write32(bus, slot, func, offset, new_val);
|
||||
}
|
||||
|
||||
void pci_enable_bus_mastering(pci_device_t* dev) {
|
||||
if (!dev) return;
|
||||
uint16_t cmd = pci_config_read16(dev->bus, dev->slot, dev->function, 0x04);
|
||||
cmd |= (1 << 2) | (1 << 0) | (1 << 1); // Bus Master, I/O Space, Memory Space
|
||||
pci_config_write16(dev->bus, dev->slot, dev->function, 0x04, cmd);
|
||||
}
|
||||
|
||||
static void pci_check_function(uint8_t bus, uint8_t slot, uint8_t func) {
|
||||
uint16_t vendor = pci_config_read16(bus, slot, func, 0x00);
|
||||
if (vendor == 0xFFFF || vendor == 0x0000) return;
|
||||
|
||||
uint16_t device = pci_config_read16(bus, slot, func, 0x02);
|
||||
uint8_t class_id = pci_config_read8(bus, slot, func, 0x0B);
|
||||
uint8_t subclass_id = pci_config_read8(bus, slot, func, 0x0A);
|
||||
uint8_t prog_if = pci_config_read8(bus, slot, func, 0x09);
|
||||
uint8_t revision = pci_config_read8(bus, slot, func, 0x08);
|
||||
uint8_t irq = pci_config_read8(bus, slot, func, 0x3C);
|
||||
|
||||
pci_device_t* dev = (pci_device_t*)kmalloc(sizeof(pci_device_t));
|
||||
if (!dev) return;
|
||||
|
||||
dev->bus = bus;
|
||||
dev->slot = slot;
|
||||
dev->function = func;
|
||||
dev->vendor_id = vendor;
|
||||
dev->device_id = device;
|
||||
dev->class_id = class_id;
|
||||
dev->subclass_id = subclass_id;
|
||||
dev->prog_if = prog_if;
|
||||
dev->revision = revision;
|
||||
dev->irq = irq;
|
||||
|
||||
// Read BARs 0-5
|
||||
for (int b = 0; b < 6; b++) {
|
||||
uint32_t bar = pci_config_read32(bus, slot, func, 0x10 + b * 4);
|
||||
dev->bar[b] = bar;
|
||||
dev->bar_type[b] = (bar & 1); // 0 = Memory, 1 = I/O
|
||||
}
|
||||
|
||||
dev->next = pci_device_list;
|
||||
pci_device_list = dev;
|
||||
|
||||
printk(KERN_INFO "PCI: %02x:%02x.%d [%04x:%04x] Class %02x.%02x (IRQ %d)\n",
|
||||
bus, slot, func, vendor, device, class_id, subclass_id, irq);
|
||||
}
|
||||
|
||||
void pci_init(void) {
|
||||
pci_device_list = NULL;
|
||||
|
||||
for (uint16_t bus = 0; bus < 256; bus++) {
|
||||
for (uint8_t slot = 0; slot < 32; slot++) {
|
||||
uint16_t vendor = pci_config_read16((uint8_t)bus, slot, 0, 0x00);
|
||||
if (vendor == 0xFFFF) continue;
|
||||
|
||||
pci_check_function((uint8_t)bus, slot, 0);
|
||||
|
||||
uint8_t header_type = pci_config_read8((uint8_t)bus, slot, 0, 0x0E);
|
||||
if (header_type & 0x80) {
|
||||
// Multi-function device
|
||||
for (uint8_t func = 1; func < 8; func++) {
|
||||
pci_check_function((uint8_t)bus, slot, func);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pci_device_t* pci_get_devices(void) {
|
||||
return pci_device_list;
|
||||
}
|
||||
|
||||
pci_device_t* pci_find_device(uint16_t vendor_id, uint16_t device_id) {
|
||||
pci_device_t* curr = pci_device_list;
|
||||
while (curr) {
|
||||
if (curr->vendor_id == vendor_id && curr->device_id == device_id) {
|
||||
return curr;
|
||||
}
|
||||
curr = curr->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pci_device_t* pci_find_class(uint8_t class_id, uint8_t subclass_id) {
|
||||
pci_device_t* curr = pci_device_list;
|
||||
while (curr) {
|
||||
if (curr->class_id == class_id && curr->subclass_id == subclass_id) {
|
||||
return curr;
|
||||
}
|
||||
curr = curr->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#include <drivers/speaker.h>
|
||||
#include <arch/x86_64/pit.h>
|
||||
#include <arch/x86_64/io.h>
|
||||
|
||||
void speaker_on(uint32_t frequency) {
|
||||
if (frequency == 0) return;
|
||||
uint32_t divisor = 1193180 / frequency;
|
||||
|
||||
// Set PIT Channel 2
|
||||
outb(0x43, 0xB6);
|
||||
outb(0x42, (uint8_t)(divisor & 0xFF));
|
||||
outb(0x42, (uint8_t)((divisor >> 8) & 0xFF));
|
||||
|
||||
// Enable speaker via Port 0x61
|
||||
uint8_t tmp = inb(0x61);
|
||||
if (tmp != (tmp | 3)) {
|
||||
outb(0x61, tmp | 3);
|
||||
}
|
||||
}
|
||||
|
||||
void speaker_off(void) {
|
||||
uint8_t tmp = inb(0x61) & 0xFC;
|
||||
outb(0x61, tmp);
|
||||
}
|
||||
|
||||
void speaker_beep(uint32_t frequency, uint32_t duration_ms) {
|
||||
speaker_on(frequency);
|
||||
pit_sleep(duration_ms);
|
||||
speaker_off();
|
||||
}
|
||||
Reference in new issue
Block a user