Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions arch/x86_64/asm/pxs.asm
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,47 @@ header_start:
; checksum = -(magic + arch + length)
dd -(0xE85250D6 + 0 + (header_end - header_start))

; Framebuffer tag - request specific graphics mode
align 8
framebuffer_tag_start:
dw 5 ; type = framebuffer
dw 0 ; flags
dd 24 ; size
dd 1024 ; width
dd 768 ; height
dd 32 ; depth (bits per pixel)
framebuffer_tag_end:

; VBE tag - request VBE info
align 8
vbe_tag_start:
dw 7 ; type = VBE
dw 0 ; flags
dd vbe_tag_end - vbe_tag_start ; size
vbe_tag_end:

; End tag - required
align 8
dw 0 ; type
dw 0 ; flags
dd 8 ; size
header_end:

;section .multiboot
;header_start:
; dd 0xE85250D6 ; Multiboot2 magic number
; dd 0 ; Architecture 0 (protected mode i386)
; dd header_end - header_start ; header length
; ; checksum = -(magic + arch + length)
; dd -(0xE85250D6 + 0 + (header_end - header_start))
;
; ; End tag - required
; dw 0 ; type
; dw 0 ; flags
; dd 8 ; size
;header_end:
; fallback

bits 32

section .text
Expand Down
1 change: 0 additions & 1 deletion drivers/Keyboard.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "Keyboard.h"
#include "Io.h"
#include "Console.h"

#define KEYBOARD_DATA_PORT 0x60
#define KEYBOARD_STATUS_PORT 0x64
Expand Down
7 changes: 2 additions & 5 deletions drivers/Pic.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@

void PitInstall() {
uint16_t divisor = 1193180 / PIT_FREQUENCY_HZ;

outb(0x43, 0x36); // Command byte: channel 0, lobyte/hibyte, rate generator
outb(0x40, divisor & 0xFF); // Low byte
outb(0x40, (divisor >> 8) & 0xFF); // High byte
}



void PicInstall() {
uint8_t a1, a2;

Expand All @@ -38,8 +37,6 @@ void PicInstall() {
outb(PIC1_DATA, ICW4_8086);
outb(PIC2_DATA, ICW4_8086);

outb(PIC2_DATA, ICW4_8086);

// Mask all interrupts initially
outb(PIC1_DATA, 0xFF); // Mask all on master PIC
outb(PIC2_DATA, 0xFF); // Mask all on slave PIC
Expand All @@ -53,7 +50,7 @@ void PicInstall() {
// Read current mask, clear bit 0, write back
uint8_t pic1_mask = inb(PIC1_DATA);
outb(PIC1_DATA, pic1_mask & ~0x01); // Clear bit 0 (IRQ0)

// Initialize PIT after PIC
PitInstall();
}
200 changes: 178 additions & 22 deletions drivers/Serial.c
Original file line number Diff line number Diff line change
@@ -1,47 +1,203 @@
#include "Serial.h"
#include "Io.h"

#define COM1 0x3f8 // COM1
// Serial port register offsets
#define SERIAL_DATA_REG 0 // Data register (DLAB=0)
#define SERIAL_IER_REG 1 // Interrupt Enable Register (DLAB=0)
#define SERIAL_DIVISOR_LOW 0 // Divisor low byte (DLAB=1)
#define SERIAL_DIVISOR_HIGH 1 // Divisor high byte (DLAB=1)
#define SERIAL_FIFO_REG 2 // FIFO Control Register
#define SERIAL_LCR_REG 3 // Line Control Register
#define SERIAL_MCR_REG 4 // Modem Control Register
#define SERIAL_LSR_REG 5 // Line Status Register
#define SERIAL_MSR_REG 6 // Modem Status Register

void SerialInit(void) {
outb(COM1 + 1, 0x00); // Disable all interrupts
outb(COM1 + 3, 0x80); // Enable DLAB (set baud rate divisor)
outb(COM1 + 0, 0x03); // Set divisor to 3 (lo byte) -> 38400 baud
outb(COM1 + 1, 0x00); // (hi byte)
outb(COM1 + 3, 0x03); // 8 bits, no parity, one stop bit
// FIFO: enable (bit0), clear RX (bit1), clear TX (bit2), trigger=14 bytes (bits 6-7=11)
outb(COM1 + 2, 0xC7);
// Modem Control: DTR | RTS | OUT2 (keeps IRQ line enabled at PIC; actual serial IRQs still disabled since IER=0)
outb(COM1 + 4, 0x0B);
// Line Control Register bits
#define SERIAL_LCR_DLAB 0x80 // Divisor Latch Access Bit
#define SERIAL_LCR_8BITS 0x03 // 8 data bits
#define SERIAL_LCR_1STOP 0x00 // 1 stop bit
#define SERIAL_LCR_NOPARITY 0x00 // No parity

// Line Status Register bits
#define SERIAL_LSR_DATA_READY 0x01 // Data available
#define SERIAL_LSR_TRANSMIT_EMPTY 0x20 // Transmit buffer empty
#define SERIAL_LSR_IDLE 0x40 // Transmitter idle

// FIFO Control Register bits
#define SERIAL_FIFO_ENABLE 0x01
#define SERIAL_FIFO_CLEAR_RX 0x02
#define SERIAL_FIFO_CLEAR_TX 0x04
#define SERIAL_FIFO_TRIGGER_14 0xC0

// Modem Control Register bits
#define SERIAL_MCR_DTR 0x01
#define SERIAL_MCR_RTS 0x02
#define SERIAL_MCR_OUT2 0x08

static uint16_t serial_port = COM1;
static int serial_initialized = 0;

int SerialInit(void) {
return SerialInitPort(COM1);
}

int SerialInitPort(uint16_t port) {
serial_port = port;

// Test if serial port exists by writing to scratch register
outb(port + 7, 0xAE);
if (inb(port + 7) != 0xAE) {
return -1; // Port doesn't exist
}

// Disable all interrupts
outb(port + SERIAL_IER_REG, 0x00);

// Enable DLAB to set baud rate
outb(port + SERIAL_LCR_REG, SERIAL_LCR_DLAB);

// Set divisor to 3 (38400 baud)
outb(port + SERIAL_DIVISOR_LOW, 0x03);
outb(port + SERIAL_DIVISOR_HIGH, 0x00);

// Configure: 8 bits, no parity, 1 stop bit
outb(port + SERIAL_LCR_REG, SERIAL_LCR_8BITS | SERIAL_LCR_NOPARITY | SERIAL_LCR_1STOP);

// Enable and configure FIFO
outb(port + SERIAL_FIFO_REG, SERIAL_FIFO_ENABLE | SERIAL_FIFO_CLEAR_RX |
SERIAL_FIFO_CLEAR_TX | SERIAL_FIFO_TRIGGER_14);

// Enable DTR, RTS, and OUT2
outb(port + SERIAL_MCR_REG, SERIAL_MCR_DTR | SERIAL_MCR_RTS | SERIAL_MCR_OUT2);

// Test serial chip (loopback test)
outb(port + SERIAL_MCR_REG, SERIAL_MCR_DTR | SERIAL_MCR_RTS | SERIAL_MCR_OUT2 | 0x10);
outb(port + SERIAL_DATA_REG, 0xAE);

if (inb(port + SERIAL_DATA_REG) != 0xAE) {
return -2; // Serial chip failed
}

// Restore normal operation
outb(port + SERIAL_MCR_REG, SERIAL_MCR_DTR | SERIAL_MCR_RTS | SERIAL_MCR_OUT2);

serial_initialized = 1;
return 0; // Success
}
int is_transmit_empty(void) {
return inb(COM1 + 5) & 0x20;

int SerialTransmitEmpty(void) {
if (!serial_initialized) return 0;
return inb(serial_port + SERIAL_LSR_REG) & SERIAL_LSR_TRANSMIT_EMPTY;
}

int SerialDataAvailable(void) {
if (!serial_initialized) return 0;
return inb(serial_port + SERIAL_LSR_REG) & SERIAL_LSR_DATA_READY;
}

void SerialWriteChar(const char a) {
int SerialWriteChar(const char a) {
if (!serial_initialized) return -1;

// Timeout counter to prevent infinite loops
int timeout = 65536;

// If newline, emit CR first, then LF
if (a == '\n') {
while ((inb(COM1 + 5) & 0x20) == 0) {}
outb(COM1, '\r');
while (!SerialTransmitEmpty() && --timeout > 0);
if (timeout <= 0) return -1;
outb(serial_port + SERIAL_DATA_REG, '\r');
timeout = 65536; // Reset timeout
}

while (!SerialTransmitEmpty() && --timeout > 0);
if (timeout <= 0) return -1;

outb(serial_port + SERIAL_DATA_REG, a);
return 0;
}

int SerialReadChar(void) {
if (!serial_initialized) return -1;

if (!SerialDataAvailable()) {
return -1; // No data available
}
while ((inb(COM1 + 5) & 0x20) == 0) {}
outb(COM1, a);

return inb(serial_port + SERIAL_DATA_REG);
}

void SerialWrite(const char* str) {
int SerialWrite(const char* str) {
if (!str || !serial_initialized) return -1;

for (int i = 0; str[i] != '\0'; i++) {
SerialWriteChar(str[i]);
if (SerialWriteChar(str[i]) < 0) {
return -1;
}
}
return 0;
}

void SerialWriteHex(uint64_t value) {
if (!serial_initialized) return;

const char hex[] = "0123456789ABCDEF";
char buffer[17];
buffer[16] = '\0';

for (int i = 15; i >= 0; i--) {
buffer[15-i] = hex[(value >> (i * 4)) & 0xF];
}

SerialWrite(buffer);
}

void SerialWriteDec(uint64_t value) {
if (!serial_initialized) return;

if (value == 0) {
SerialWriteChar('0');
return;
}

char buffer[21]; // Max digits for uint64_t
int pos = 0;

while (value > 0) {
buffer[pos++] = '0' + (value % 10);
value /= 10;
}

// Reverse the string
for (int i = pos - 1; i >= 0; i--) {
SerialWriteChar(buffer[i]);
}
}

// Read a line from serial (with basic line editing)
int SerialReadLine(char* buffer, int max_length) {
if (!buffer || !serial_initialized || max_length <= 0) return -1;

int pos = 0;
int c;

while (pos < max_length - 1) {
c = SerialReadChar();
if (c < 0) continue; // No data, keep waiting

if (c == '\r' || c == '\n') {
SerialWriteChar('\n'); // Echo newline
break;
} else if (c == '\b' || c == 0x7F) { // Backspace or DEL
if (pos > 0) {
pos--;
SerialWrite("\b \b"); // Erase character on terminal
}
} else if (c >= 32 && c < 127) { // Printable characters
buffer[pos++] = c;
SerialWriteChar(c); // Echo character
}
}

buffer[pos] = '\0';
return pos;
}
39 changes: 34 additions & 5 deletions drivers/Serial.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,39 @@
#ifndef VOIDFRAME_SERIAL_H
#define VOIDFRAME_SERIAL_H
#include "stdint.h"

void SerialInit(void);
void SerialWriteChar(char c);
void SerialWrite(const char* str);
#include <stdint.h>

#define COM1 0x3f8 // COM1
#define COM2 0x2f8 // COM2
#define COM3 0x3e8 // COM3
#define COM4 0x2e8 // COM4

// Serial port addresses
#define SERIAL_COM1 0x3F8
#define SERIAL_COM2 0x2F8
#define SERIAL_COM3 0x3E8
#define SERIAL_COM4 0x2E8

// Initialize serial port (defaults to COM1)
int SerialInit(void);

// Initialize specific serial port
int SerialInitPort(uint16_t port);

// Status functions
int SerialTransmitEmpty(void);
int SerialDataAvailable(void);

// Character I/O
int SerialWriteChar(const char c);
int SerialReadChar(void);

// String I/O
int SerialWrite(const char* str);
int SerialReadLine(char* buffer, int max_length);

// Number output
void SerialWriteHex(uint64_t value);
void SerialWriteDec(uint64_t value);

Comment on lines +35 to 38
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Return-type inconsistency hampers error handling

All other I/O functions now return int for status; SerialWriteHex / SerialWriteDec still return void, so callers cannot detect transmit time-outs or un-initialised port.

-void SerialWriteHex(uint64_t value);
-void SerialWriteDec(uint64_t value);
+int  SerialWriteHex(uint64_t value);
+int  SerialWriteDec(uint64_t value);

Propagate the return codes inside the implementations for uniform API.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Number output
void SerialWriteHex(uint64_t value);
void SerialWriteDec(uint64_t value);
// Number output
int SerialWriteHex(uint64_t value);
int SerialWriteDec(uint64_t value);
🤖 Prompt for AI Agents
In drivers/Serial.h at lines 30 to 33, change the return type of SerialWriteHex
and SerialWriteDec from void to int to match other I/O functions. Update their
implementations to return status codes indicating success or failure, such as
transmit time-outs or uninitialized port errors, so callers can handle errors
uniformly.

#endif // VOIDFRAME_SERIAL_H
#endif // VOIDFRAME_SERIAL_H
Loading