Add new VGA fix and USB system

This commit is contained in:
rwusmm 2026-05-11 19:50:32 +03:00
parent e48f3674c7
commit ae37574e94
16 changed files with 782 additions and 19 deletions

1
.gitignore vendored
View file

@ -4,6 +4,7 @@ iso_root/
boredos.iso boredos.iso
disk.img disk.img
disk.qcow2 disk.qcow2
run.ps1
edk2-vars.fd edk2-vars.fd
qemu-debug.log qemu-debug.log
boredos.dump boredos.dump

View file

@ -46,6 +46,7 @@ C_SOURCES = $(wildcard $(SRC_DIR)/core/*.c) \
$(wildcard $(SRC_DIR)/net/nic/*.c) \ $(wildcard $(SRC_DIR)/net/nic/*.c) \
$(wildcard $(SRC_DIR)/fs/*.c) \ $(wildcard $(SRC_DIR)/fs/*.c) \
$(wildcard $(SRC_DIR)/wm/*.c) \ $(wildcard $(SRC_DIR)/wm/*.c) \
$(wildcard $(SRC_DIR)/usb/*.c) \
$(wildcard $(SRC_DIR)/net/third_party/lwip/core/*.c) \ $(wildcard $(SRC_DIR)/net/third_party/lwip/core/*.c) \
$(wildcard $(SRC_DIR)/net/third_party/lwip/core/ipv4/*.c) \ $(wildcard $(SRC_DIR)/net/third_party/lwip/core/ipv4/*.c) \
$(SRC_DIR)/net/third_party/lwip/netif/ethernet.c \ $(SRC_DIR)/net/third_party/lwip/netif/ethernet.c \
@ -62,6 +63,7 @@ OBJ_FILES = $(patsubst $(SRC_DIR)/core/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_D
$(patsubst $(SRC_DIR)/net/nic/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/net/nic/*.c)) \ $(patsubst $(SRC_DIR)/net/nic/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/net/nic/*.c)) \
$(patsubst $(SRC_DIR)/fs/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/fs/*.c)) \ $(patsubst $(SRC_DIR)/fs/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/fs/*.c)) \
$(patsubst $(SRC_DIR)/wm/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/wm/*.c)) \ $(patsubst $(SRC_DIR)/wm/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/wm/*.c)) \
$(patsubst $(SRC_DIR)/usb/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/usb/*.c)) \
$(patsubst $(SRC_DIR)/net/third_party/lwip/%.c, $(BUILD_DIR)/lwip/%.o, $(filter $(SRC_DIR)/net/third_party/lwip/%.c, $(C_SOURCES))) \ $(patsubst $(SRC_DIR)/net/third_party/lwip/%.c, $(BUILD_DIR)/lwip/%.o, $(filter $(SRC_DIR)/net/third_party/lwip/%.c, $(C_SOURCES))) \
$(patsubst $(SRC_DIR)/arch/%.asm, $(BUILD_DIR)/%.o, $(ASM_SOURCES)) $(patsubst $(SRC_DIR)/arch/%.asm, $(BUILD_DIR)/%.o, $(ASM_SOURCES))
@ -72,7 +74,7 @@ CFLAGS = -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding \
-I$(SRC_DIR)/sys -I$(SRC_DIR)/mem -I$(SRC_DIR)/dev \ -I$(SRC_DIR)/sys -I$(SRC_DIR)/mem -I$(SRC_DIR)/dev \
-I$(SRC_DIR)/drivers \ -I$(SRC_DIR)/drivers \
-I$(SRC_DIR)/net -I$(SRC_DIR)/net/nic -I$(SRC_DIR)/fs \ -I$(SRC_DIR)/net -I$(SRC_DIR)/net/nic -I$(SRC_DIR)/fs \
-I$(SRC_DIR)/wm -I$(SRC_DIR)/input -I$(SRC_DIR)/wm -I$(SRC_DIR)/input -I$(SRC_DIR)/usb
LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \ LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \
-z text -z max-page-size=0x1000 -T linker.ld -z text -z max-page-size=0x1000 -T linker.ld
@ -84,13 +86,22 @@ LIMINE_URL_BASE = https://github.com/limine-bootloader/limine/raw/v$(LIMINE_VERS
HOST_OS := $(shell uname -s 2>/dev/null || echo Windows) HOST_OS := $(shell uname -s 2>/dev/null || echo Windows)
<<<<<<< HEAD
.PHONY: all clean run run-hd limine-setup run-windows run-mac run-linux run-hd-mac run-hd-windows run-hd-linux .PHONY: all clean run run-hd limine-setup run-windows run-mac run-linux run-hd-mac run-hd-windows run-hd-linux
=======
.PHONY: all clean run run-hd limine-setup run-windows run-mac run-linux run-hd-mac run-hd-windows run-hd-linux unsafe
>>>>>>> 335d1c8 (Add new VGA fix and USB system)
all: all:
$(call PRINT_STEP,STARTING BOREDOS BUILD) $(call PRINT_STEP,STARTING BOREDOS BUILD)
$(MAKE) $(ISO_IMAGE) $(MAKE) $(ISO_IMAGE)
$(call PRINT_STEP,BUILD COMPLETE) $(call PRINT_STEP,BUILD COMPLETE)
unsafe:
$(call PRINT_STEP,STARTING BOREDOS BUILD (UNSAFE MODE))
$(MAKE) $(ISO_IMAGE) LD=ld AR=ar CC=gcc TCC_CC=gcc TCC_AR=ar
$(call PRINT_STEP,BUILD COMPLETE)
$(BUILD_DIR): $(BUILD_DIR):
$(call PRINT_STEP,CREATING BUILD DIRECTORY) $(call PRINT_STEP,CREATING BUILD DIRECTORY)
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)
@ -170,6 +181,16 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/wm/%.c | $(BUILD_DIR) limine-setup
mkdir -p $(dir $@) mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/%.o: $(SRC_DIR)/usb/%.c | $(BUILD_DIR) limine-setup
@printf "$(YELLOW)[CC]$(RESET)[usb] $< -> $@"
mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/uhci.o: $(SRC_DIR)/usb/uhci.c | $(BUILD_DIR) limine-setup
@printf "$(YELLOW)[CC]$(RESET)[usb] $< -> $@"
mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/lwip/%.o: $(SRC_DIR)/net/third_party/lwip/%.c | $(BUILD_DIR) limine-setup $(BUILD_DIR)/lwip/%.o: $(SRC_DIR)/net/third_party/lwip/%.c | $(BUILD_DIR) limine-setup
@printf "$(YELLOW)[CC]$(RESET)[lwIP] $< -> $@" @printf "$(YELLOW)[CC]$(RESET)[lwIP] $< -> $@"
mkdir -p $(dir $@) mkdir -p $(dir $@)

View file

@ -20,6 +20,11 @@ To build BoredOS, you need the following tools:
4. **QEMU** (Optional but highly recommended for testing): 4. **QEMU** (Optional but highly recommended for testing):
- `qemu-system-x86_64` is used to virtualize the OS for testing or to mess around. - `qemu-system-x86_64` is used to virtualize the OS for testing or to mess around.
## WSL2 Unconfigured support
BoredOS supports WSL2 but unconfigured for x86-64-elf-ld, to use it you can run "make unsafe" but you need to install the following packages:
sudo apt install build-essential nasm xorriso qemu-system-x86 gcc-x86-64-linux-gnu
This is implemented as because downloading that package isn't as easy as doing "sudo apt install x86_64_elf or sum""
It should also properly build TCC files
## Building the Cross-Compiler on Linux ## Building the Cross-Compiler on Linux
### Availability Issue ### Availability Issue

View file

@ -36,6 +36,9 @@
#include "input/keymap.h" #include "input/keymap.h"
#include "input/keyboard.h" #include "input/keyboard.h"
#include "../drivers/acpi.h" #include "../drivers/acpi.h"
#include "../usb/usb.h"
#include "../usb/hid.h"
#include "../usb/logitech_b110.h"
extern void sysfs_init_subsystems(void); extern void sysfs_init_subsystems(void);
@ -499,6 +502,10 @@ void kmain(void) {
ps2_init(); ps2_init();
asm("sti"); asm("sti");
usb_init();
usb_enumerate_devices();
usb_hid_init();
keymap_init(); keymap_init();
serial_write("[INIT] Keymap initialized"); serial_write("[INIT] Keymap initialized");

View file

@ -10,6 +10,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "input/keyboard.h" #include "input/keyboard.h"
#include "input/keymap.h" #include "input/keymap.h"
#include "../usb/logitech_b110.h"
extern void serial_print(const char *s); extern void serial_print(const char *s);
extern void serial_print_hex(uint64_t n); extern void serial_print_hex(uint64_t n);
@ -151,6 +152,7 @@ uint64_t mouse_handler(registers_t *regs) {
if (!(status & 0x20)) { if (!(status & 0x20)) {
outb(0x20, 0x20); outb(0x20, 0x20);
outb(0xA0, 0x20); outb(0xA0, 0x20);
logitech_b110_poll();
return (uint64_t)regs; return (uint64_t)regs;
} }
@ -158,7 +160,6 @@ uint64_t mouse_handler(registers_t *regs) {
if (mouse_cycle == 0) { if (mouse_cycle == 0) {
if ((b & 0x08) == 0) { if ((b & 0x08) == 0) {
// Out of sync
} else { } else {
mouse_byte[0] = b; mouse_byte[0] = b;
mouse_cycle++; mouse_cycle++;
@ -187,6 +188,7 @@ uint64_t mouse_handler(registers_t *regs) {
outb(0x20, 0x20); outb(0x20, 0x20);
outb(0xA0, 0x20); outb(0xA0, 0x20);
logitech_b110_poll();
return (uint64_t)regs; return (uint64_t)regs;
} }

125
src/usb/hid.c Normal file
View file

@ -0,0 +1,125 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#include "hid.h"
#include "logitech_b110.h"
#include "../core/io.h"
#include <string.h>
extern void serial_write(const char *str);
static usb_device_t hid_mouse_devices[8];
static int hid_mouse_count = 0;
bool hid_parse_mouse_descriptor(const uint8_t *desc, int len, hid_mouse_desc_t *out) {
if (!desc || !out || len < 10) return false;
memset(out, 0, sizeof(hid_mouse_desc_t));
int i = 0;
while (i < len) {
uint8_t prefix = desc[i++];
uint8_t size = prefix & 0x03;
uint8_t type = (prefix >> 2) & 0x03;
uint8_t tag = prefix >> 4;
uint32_t value = 0;
if (size == 1) {
value = desc[i++];
} else if (size == 2) {
value = desc[i];
i++;
value |= (desc[i] << 8);
i++;
} else if (size == 3) {
value = desc[i];
i++;
value |= (desc[i] << 8);
i++;
value |= (desc[i] << 16);
i++;
value |= (desc[i] << 24);
i++;
}
if (type == 1) {
if (tag == 0x04) out->usage_page = value;
if (tag == 0x08) out->usage = value;
}
if (type == 2) {
if (tag == 0x01 && value == 0x30) out->max_x = 32767;
if (tag == 0x01 && value == 0x31) out->max_y = 32767;
if (tag == 0x09 && value == 0x38) out->has_wheel = true;
}
}
out->button_count = 3;
out->usage_page = 0x01;
out->usage = 0x02;
return true;
}
bool hid_init_mouse(usb_device_t *dev) {
if (hid_mouse_count >= 8) return false;
usb_setup_packet_t setup;
setup.bmRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
setup.bRequest = USB_REQ_SET_PROTOCOL;
setup.wValue = 0;
setup.wIndex = dev->interface_number;
setup.wLength = 0;
usb_control_transfer(dev, &setup, NULL);
setup.bmRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
setup.bRequest = USB_REQ_SET_IDLE;
setup.wValue = 0;
setup.wIndex = dev->interface_number;
setup.wLength = 0;
usb_control_transfer(dev, &setup, NULL);
hid_mouse_devices[hid_mouse_count++] = *dev;
dev->initialized = true;
serial_write("[HID] Mouse initialized\n");
return true;
}
int hid_mouse_get_report(usb_device_t *dev, hid_mouse_report_t *report) {
if (!dev || !report) return -1;
uint8_t buffer[8];
int len = usb_interrupt_in(dev, dev->endpoint_in, buffer, sizeof(buffer));
if (len < 3) return -1;
report->buttons = buffer[0];
report->x = (int8_t)buffer[1];
report->y = (int8_t)buffer[2];
report->wheel = (len >= 4) ? (int8_t)buffer[3] : 0;
return len;
}
void usb_hid_init(void) {
serial_write("[HID] Initializing HID subsystem\n");
int device_count = usb_get_device_count();
for (int i = 0; i < device_count; i++) {
usb_device_t *dev = usb_get_device(i);
if (dev && dev->device_class == USB_CLASS_HID) {
serial_write("[HID] Found HID device\n");
if (logitech_b110_probe(dev)) {
serial_write("[HID] Initializing LT-B110\n");
logitech_b110_init(dev);
}
}
}
}

35
src/usb/hid.h Normal file
View file

@ -0,0 +1,35 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#ifndef HID_H
#define HID_H
#include "usb.h"
#include <stdint.h>
#include <stdbool.h>
#define HID_REPORT_DESC_MAX 256
typedef struct {
uint8_t usage_page;
uint8_t usage;
uint16_t max_x;
uint16_t max_y;
uint8_t button_count;
bool has_wheel;
} hid_mouse_desc_t;
typedef struct {
int8_t x;
int8_t y;
int8_t wheel;
uint8_t buttons;
} hid_mouse_report_t;
bool hid_parse_mouse_descriptor(const uint8_t *desc, int len, hid_mouse_desc_t *out);
bool hid_init_mouse(usb_device_t *dev);
int hid_mouse_get_report(usb_device_t *dev, hid_mouse_report_t *report);
void usb_hid_init(void);
#endif

46
src/usb/logitech_b110.c Normal file
View file

@ -0,0 +1,46 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#include "logitech_b110.h"
#include "../core/io.h"
extern void serial_write(const char *str);
extern void wm_handle_mouse(int dx, int dy, int buttons, int wheel);
static usb_device_t b110_device;
static bool b110_initialized = false;
bool logitech_b110_probe(usb_device_t *dev) {
if (dev->vendor_id == LOGITECH_VID && dev->product_id == LOGITECH_B110_PID) {
serial_write("[B110] Logitech B110 mouse detected\n");
return true;
}
return false;
}
bool logitech_b110_init(usb_device_t *dev) {
if (!logitech_b110_probe(dev)) return false;
b110_device = *dev;
b110_initialized = hid_init_mouse(dev);
if (b110_initialized) {
serial_write("[LT-B110] Mouse USB driver initialized\n");
}
return b110_initialized;
}
void logitech_b110_poll(void) {
if (!b110_initialized) return;
hid_mouse_report_t report;
if (hid_mouse_get_report(&b110_device, &report) > 0) {
int buttons = 0;
if (report.buttons & 0x01) buttons |= 0x01;
if (report.buttons & 0x02) buttons |= 0x02;
if (report.buttons & 0x04) buttons |= 0x04;
wm_handle_mouse(report.x, report.y, buttons, report.wheel);
}
}

18
src/usb/logitech_b110.h Normal file
View file

@ -0,0 +1,18 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#ifndef LOGITECH_B110_H
#define LOGITECH_B110_H
#include "hid.h"
#include <stdint.h>
#include <stdbool.h>
#define LOGITECH_VID 0x046D
#define LOGITECH_B110_PID 0xC05A
bool logitech_b110_probe(usb_device_t *dev);
bool logitech_b110_init(usb_device_t *dev);
void logitech_b110_poll(void);
#endif

117
src/usb/uhci.c Normal file
View file

@ -0,0 +1,117 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#include "uhci.h"
#include "../core/io.h"
#include "../core/platform.h"
#include "../mem/memory_manager.h"
#include "../dev/pci.h"
#include <string.h>
extern void serial_write(const char *str);
extern void serial_write_hex(uint64_t n);
static uhci_hc_t uhci_controller;
static uint8_t *frame_list;
static uhci_qh_t *qh_pool;
static uhci_td_t *td_pool;
#define FRAME_LIST_SIZE 1024
#define POOL_SIZE 64
bool uhci_init(usb_hc_t *hc) {
serial_write("[UHCI] Initializing UHCI controller\n");
uint32_t bar = hc->bar0 & 0xFFFFFFF0;
if (bar == 0) {
serial_write("[UHCI] Invalid BAR0\n");
return false;
}
uhci_controller.base = (uint8_t *)p2v(bar);
uhci_controller.regs = (uhci_regs_t *)uhci_controller.base;
uint16_t cmd = inw((uint32_t)&uhci_controller.regs->cmd);
outw((uint32_t)&uhci_controller.regs->cmd, cmd & ~UHCI_CMD_RUN);
for (volatile int i = 0; i < 10000; i++);
outw((uint32_t)&uhci_controller.regs->cmd, cmd | UHCI_CMD_HCRESET);
for (volatile int i = 0; i < 10000; i++);
frame_list = (uint8_t *)kmalloc(FRAME_LIST_SIZE * 4);
if (!frame_list) {
serial_write("[UHCI] Failed to allocate frame list\n");
return false;
}
memset(frame_list, 0, FRAME_LIST_SIZE * 4);
qh_pool = (uhci_qh_t *)kmalloc(sizeof(uhci_qh_t) * POOL_SIZE);
td_pool = (uhci_td_t *)kmalloc(sizeof(uhci_td_t) * POOL_SIZE);
if (!qh_pool || !td_pool) {
serial_write("[UHCI] Failed to allocate pools\n");
return false;
}
memset(qh_pool, 0, sizeof(uhci_qh_t) * POOL_SIZE);
memset(td_pool, 0, sizeof(uhci_td_t) * POOL_SIZE);
uint32_t frame_list_phys = v2p((uint64_t)frame_list);
outl((uint32_t)&uhci_controller.regs->frame_base, frame_list_phys);
outw((uint32_t)&uhci_controller.regs->cmd, UHCI_CMD_RUN | UHCI_CMD_MAXP);
uint16_t port1 = inw((uint32_t)&uhci_controller.regs->port1);
if (port1 & UHCI_PORT_CCS) {
serial_write("[UHCI] Device detected on port 1\n");
outw((uint32_t)&uhci_controller.regs->port1, port1 | UHCI_PORT_PED);
}
uint16_t port2 = inw((uint32_t)&uhci_controller.regs->port2);
if (port2 & UHCI_PORT_CCS) {
serial_write("[UHCI] Device detected on port 2\n");
outw((uint32_t)&uhci_controller.regs->port2, port2 | UHCI_PORT_PED);
}
uhci_controller.initialized = true;
serial_write("[UHCI] Initialization complete\n");
return true;
}
void uhci_reset_port(usb_hc_t *hc, int port) {
(void)hc;
uhci_hc_t *controller = &uhci_controller;
uint16_t port_reg = (port == 1) ? (uint32_t)&controller->regs->port1 : (uint32_t)&controller->regs->port2;
uint16_t status = inw(port_reg);
outw(port_reg, status | UHCI_PORT_PR);
for (volatile int i = 0; i < 10000; i++);
status = inw(port_reg);
outw(port_reg, status & ~UHCI_PORT_PR);
for (volatile int i = 0; i < 10000; i++);
status = inw(port_reg);
outw(port_reg, status | UHCI_PORT_PED);
}
int uhci_control_transfer(usb_hc_t *hc, usb_setup_packet_t *setup, void *data, uint16_t len) {
(void)hc;
(void)setup;
(void)data;
(void)len;
return -1;
}
int uhci_interrupt_in(usb_hc_t *hc, uint8_t endpoint, void *data, uint16_t len) {
(void)hc;
(void)endpoint;
(void)data;
(void)len;
return -1;
}

80
src/usb/uhci.h Normal file
View file

@ -0,0 +1,80 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#ifndef UHCI_H
#define UHCI_H
#include "usb.h"
#include <stdint.h>
#include <stdbool.h>
#define UHCI_CMD_REG 0x00
#define UHCI_STATUS_REG 0x02
#define UHCI_INT_EN_REG 0x04
#define UHCI_FRAME_NUM_REG 0x06
#define UHCI_FRAME_BASE_REG 0x08
#define UHCI_SOF_MOD_REG 0x0C
#define UHCI_PORT1_REG 0x10
#define UHCI_PORT2_REG 0x12
#define UHCI_CMD_RUN 0x0001
#define UHCI_CMD_HCRESET 0x0002
#define UHCI_CMD_GRESET 0x0004
#define UHCI_CMD_EGSM 0x0008
#define UHCI_CMD_FGR 0x0010
#define UHCI_CMD_MAXP 0x0080
#define UHCI_STATUS_USBINT 0x0001
#define UHCI_STATUS_USBERRINT 0x0002
#define UHCI_STATUS_RD 0x0004
#define UHCI_STATUS_HSE 0x0008
#define UHCI_STATUS_HCPE 0x0010
#define UHCI_STATUS_HCH 0x0020
#define UHCI_PORT_CCS 0x0001
#define UHCI_PORT_CSC 0x0002
#define UHCI_PORT_PED 0x0004
#define UHCI_PORT_PEC 0x0008
#define UHCI_PORT_PO 0x0010
#define UHCI_PORT_PR 0x0200
#define UHCI_PORT_LS 0x0300
typedef struct {
uint16_t cmd;
uint16_t status;
uint16_t int_en;
uint16_t frame_num;
uint32_t frame_base;
uint16_t sof_mod;
uint16_t reserved1;
uint16_t port1;
uint16_t port2;
} __attribute__((packed)) uhci_regs_t;
typedef struct {
uint32_t link;
uint32_t actual_len;
uint32_t status;
uint32_t buffer;
uint32_t next_td;
uint32_t next_qh;
uint32_t reserved;
} __attribute__((packed)) uhci_td_t;
typedef struct {
uint32_t link;
uint32_t element_link;
} __attribute__((packed)) uhci_qh_t;
typedef struct {
uint8_t *base;
uhci_regs_t *regs;
bool initialized;
} uhci_hc_t;
bool uhci_init(usb_hc_t *hc);
int uhci_control_transfer(usb_hc_t *hc, usb_setup_packet_t *setup, void *data, uint16_t len);
int uhci_interrupt_in(usb_hc_t *hc, uint8_t endpoint, void *data, uint16_t len);
void uhci_reset_port(usb_hc_t *hc, int port);
#endif

182
src/usb/usb.c Normal file
View file

@ -0,0 +1,182 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it has in it, as per the GPL license terms.
#include "usb.h"
#include "uhci.h"
#include "../dev/pci.h"
#include "../core/io.h"
#include "../mem/memory_manager.h"
#include <string.h>
extern void serial_write(const char *str);
extern void serial_write_hex(uint64_t n);
static usb_hc_t usb_controllers[8];
static int usb_controller_count = 0;
static usb_device_t usb_devices[USB_MAX_DEVICES];
static int usb_device_count = 0;
static uint8_t device_address_counter = 1;
extern uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset);
extern void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value);
extern int pci_find_device_by_class(uint8_t class_code, uint8_t subclass, pci_device_t *dev);
usb_hc_type_t usb_detect_controller(usb_hc_t *hc) {
uint32_t class_code = pci_read_config(hc->bus, hc->device, hc->function, 0x08) >> 24;
uint32_t prog_if = pci_read_config(hc->bus, hc->device, hc->function, 0x09) & 0xFF;
if (class_code == 0x0C) {
if (prog_if == 0x00) return USB_HC_UHCI;
if (prog_if == 0x10) return USB_HC_OHCI;
if (prog_if == 0x20) return USB_HC_EHCI;
if (prog_if == 0x30) return USB_HC_XHCI;
}
return USB_HC_UNKNOWN;
}
void usb_init(void) {
serial_write("[USB] Initializing USB stack...\n");
int idx = 0;
for (int bus = 0; bus < 256; bus++) {
for (int device = 0; device < 32; device++) {
for (int function = 0; function < 8; function++) {
uint32_t vendor_id = pci_read_config(bus, device, function, 0x00) & 0xFFFF;
if (vendor_id == 0xFFFF) continue;
uint32_t class_code = pci_read_config(bus, device, function, 0x08) >> 24;
if (class_code == 0x0C && idx < 8) {
usb_controllers[idx].bus = bus;
usb_controllers[idx].device = device;
usb_controllers[idx].function = function;
usb_controllers[idx].bar0 = pci_read_config(bus, device, function, 0x10);
usb_controllers[idx].bar1 = pci_read_config(bus, device, function, 0x14);
usb_controllers[idx].bar2 = pci_read_config(bus, device, function, 0x18);
usb_controllers[idx].bar3 = pci_read_config(bus, device, function, 0x1C);
usb_controllers[idx].bar4 = pci_read_config(bus, device, function, 0x20);
usb_hc_type_t type = usb_detect_controller(&usb_controllers[idx]);
const char *type_str = "UNKNOWN";
if (type == USB_HC_UHCI) type_str = "UHCI";
else if (type == USB_HC_OHCI) type_str = "OHCI";
else if (type == USB_HC_EHCI) type_str = "EHCI";
else if (type == USB_HC_XHCI) type_str = "XHCI";
serial_write("[USB] Found controller: ");
serial_write(type_str);
serial_write("\n");
if (type == USB_HC_UHCI) {
if (uhci_init(&usb_controllers[idx])) {
serial_write("[USB] UHCI initialized\n");
}
}
idx++;
}
}
}
}
usb_controller_count = idx;
serial_write("[USB] Total controllers found: ");
serial_write_hex(usb_controller_count);
serial_write("\n");
}
bool usb_enumerate_device(usb_device_t *dev) {
if (usb_device_count >= USB_MAX_DEVICES) return false;
usb_setup_packet_t setup;
uint8_t desc[18];
setup.bmRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
setup.bRequest = USB_REQ_GET_DESCRIPTOR;
setup.wValue = (USB_DESC_DEVICE << 8) | 0;
setup.wIndex = 0;
setup.wLength = 18;
if (usb_control_transfer(dev, &setup, desc) < 0) {
return false;
}
dev->vendor_id = desc[8] | (desc[9] << 8);
dev->product_id = desc[10] | (desc[11] << 8);
dev->device_class = desc[4];
dev->device_subclass = desc[5];
dev->device_protocol = desc[6];
dev->max_packet_size = desc[7];
setup.bmRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
setup.bRequest = USB_REQ_SET_ADDRESS;
setup.wValue = device_address_counter;
setup.wIndex = 0;
setup.wLength = 0;
if (usb_control_transfer(dev, &setup, NULL) < 0) {
return false;
}
dev->config_value = 1;
dev->interface_number = 0;
dev->endpoint_in = 0x81;
dev->endpoint_out = 0x01;
usb_devices[usb_device_count++] = *dev;
device_address_counter++;
return true;
}
int usb_control_transfer(usb_device_t *dev, usb_setup_packet_t *setup, void *data) {
(void)dev;
if (usb_controller_count == 0) return -1;
usb_hc_t *hc = &usb_controllers[0];
uint16_t len = setup->wLength;
return uhci_control_transfer(hc, setup, data, len);
}
int usb_interrupt_in(usb_device_t *dev, uint8_t endpoint, void *data, uint16_t len) {
(void)dev;
if (usb_controller_count == 0) return -1;
usb_hc_t *hc = &usb_controllers[0];
return uhci_interrupt_in(hc, endpoint, data, len);
}
void usb_enumerate_devices(void) {
serial_write("[USB] Starting device enumeration\n");
if (usb_controller_count == 0) {
serial_write("[USB] No controllers available\n");
return;
}
for (int port = 1; port <= 2; port++) {
usb_device_t dev;
memset(&dev, 0, sizeof(usb_device_t));
if (usb_enumerate_device(&dev)) {
serial_write("[USB] Device enumerated: VID=");
serial_write_hex(dev.vendor_id);
serial_write(" PID=");
serial_write_hex(dev.product_id);
serial_write("\n");
}
}
}
int usb_get_device_count(void) {
return usb_device_count;
}
usb_device_t* usb_get_device(int index) {
if (index < 0 || index >= usb_device_count) return NULL;
return &usb_devices[index];
}

98
src/usb/usb.h Normal file
View file

@ -0,0 +1,98 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it has in it, as per the GPL license terms.
#ifndef USB_H
#define USB_H
#include <stdint.h>
#include <stdbool.h>
#define USB_MAX_DEVICES 128
#define USB_MAX_ENDPOINTS 16
typedef struct {
uint8_t bus;
uint8_t device;
uint8_t function;
uint32_t bar0;
uint32_t bar1;
uint32_t bar2;
uint32_t bar3;
uint32_t bar4;
} usb_hc_t;
typedef enum {
USB_HC_UHCI,
USB_HC_OHCI,
USB_HC_EHCI,
USB_HC_XHCI,
USB_HC_UNKNOWN
} usb_hc_type_t;
typedef struct {
uint16_t vendor_id;
uint16_t product_id;
uint8_t device_class;
uint8_t device_subclass;
uint8_t device_protocol;
uint8_t config_value;
uint8_t interface_number;
uint8_t alternate_setting;
uint8_t endpoint_in;
uint8_t endpoint_out;
uint16_t max_packet_size;
bool initialized;
} usb_device_t;
typedef struct {
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} __attribute__((packed)) usb_setup_packet_t;
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SET_IDLE 0x0A
#define USB_REQ_SET_PROTOCOL 0x0B
#define USB_DESC_DEVICE 0x01
#define USB_DESC_CONFIG 0x02
#define USB_DESC_STRING 0x03
#define USB_DESC_INTERFACE 0x04
#define USB_DESC_ENDPOINT 0x05
#define USB_DESC_HID 0x21
#define USB_DIR_OUT 0x00
#define USB_DIR_IN 0x80
#define USB_TYPE_STANDARD 0x00
#define USB_TYPE_CLASS 0x20
#define USB_TYPE_VENDOR 0x40
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_CLASS_HID 0x03
#define USB_CLASS_MASS_STORAGE 0x08
void usb_init(void);
usb_hc_type_t usb_detect_controller(usb_hc_t *hc);
bool usb_enumerate_device(usb_device_t *dev);
int usb_control_transfer(usb_device_t *dev, usb_setup_packet_t *setup, void *data);
int usb_interrupt_in(usb_device_t *dev, uint8_t endpoint, void *data, uint16_t len);
void usb_enumerate_devices(void);
int usb_get_device_count(void);
usb_device_t* usb_get_device(int index);
#endif

View file

@ -108,9 +108,9 @@ $(BIN_DIR)/lua.elf: $(LIBC_OBJS) $(BIN_DIR)/lua_onelua.o $(BIN_DIR)/lua.note.o
# TCC - Tiny C Compiler # TCC - Tiny C Compiler
TCC_DIR = cli/third_party/tcc TCC_DIR = cli/third_party/tcc
$(BIN_DIR)/tcc.elf: $(LIBC_OBJS) $(BIN_DIR)/tcc.note.o sdk $(TCC_DIR)/tcc.c $(TCC_DIR)/config.h $(TCC_DIR)/tcc.h $(BIN_DIR)/tcc.elf: $(LIBC_OBJS) $(BIN_DIR)/tcc.note.o sdk $(TCC_DIR)/tcc.c $(TCC_DIR)/config.h $(TCC_DIR)/tcc.h
cd $(TCC_DIR) && x86_64-elf-gcc -O2 -m64 -march=x86-64 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -ffreestanding -nostdlib -static -no-pie -DONE_SOURCE=1 -DTARGETOS_BoredOS=1 -I. -I../../../sdk/include -Ttext=0x40000000 tcc.c -o tcc.elf ../../../sdk/lib/libboredos.a cd $(TCC_DIR) && $(TCC_CC) -O2 -m64 -march=x86-64 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -ffreestanding -nostdlib -static -no-pie -DONE_SOURCE=1 -DTARGETOS_BoredOS=1 -I. -I../../../sdk/include -Ttext=0x40000000 tcc.c -o tcc.elf ../../../sdk/lib/libboredos.a
cp $(TCC_DIR)/tcc.elf $(BIN_DIR)/tcc.elf cp $(TCC_DIR)/tcc.elf $(BIN_DIR)/tcc.elf
cd $(TCC_DIR) && sh build_libtcc1.sh cd $(TCC_DIR) && CC=$(TCC_CC) AR=$(TCC_AR) sh build_libtcc1.sh && ls -la libtcc1.a
# SDK target # SDK target
SDK_DIR = sdk SDK_DIR = sdk
@ -118,10 +118,10 @@ sdk: $(LIBC_OBJS) $(BIN_DIR)/libui.o
mkdir -p $(SDK_DIR)/lib $(SDK_DIR)/include/sys mkdir -p $(SDK_DIR)/lib $(SDK_DIR)/include/sys
cp libc/*.h $(SDK_DIR)/include/ cp libc/*.h $(SDK_DIR)/include/
cp libc/sys/*.h $(SDK_DIR)/include/sys/ cp libc/sys/*.h $(SDK_DIR)/include/sys/
x86_64-elf-ar rcs $(SDK_DIR)/lib/libboredos.a $(LIBC_OBJS) $(AR) rcs $(SDK_DIR)/lib/libboredos.a $(LIBC_OBJS)
cp $(SDK_DIR)/lib/libboredos.a $(SDK_DIR)/lib/libc.a cp $(SDK_DIR)/lib/libboredos.a $(SDK_DIR)/lib/libc.a
cp $(SDK_DIR)/lib/libboredos.a $(SDK_DIR)/lib/libm.a cp $(SDK_DIR)/lib/libboredos.a $(SDK_DIR)/lib/libm.a
x86_64-elf-ar rcs $(SDK_DIR)/lib/libui.a $(BIN_DIR)/libui.o $(AR) rcs $(SDK_DIR)/lib/libui.a $(BIN_DIR)/libui.o
clean: clean:
rm -rf $(BIN_DIR) $(SDK_DIR) rm -rf $(BIN_DIR) $(SDK_DIR)

View file

@ -1,9 +1,9 @@
#!/bin/bash #!/bin/bash
CC=x86_64-elf-gcc CC=${CC:-x86_64-elf-gcc}
AR=x86_64-elf-ar AR=${AR:-x86_64-elf-ar}
CFLAGS="-O2 -m64 -march=x86-64 -fno-stack-protector -ffreestanding -nostdlib -I. -I./include -I../../../sdk/include" CFLAGS="-O2 -m64 -march=x86-64 -fno-stack-protector -ffreestanding -nostdlib -I. -I./include -I../../../sdk/include"
echo "Building libtcc1.a..." echo "Building libtcc1.a with CC=$CC, AR=$AR..."
$CC $CFLAGS -c lib/libtcc1.c -o libtcc1.o $CC $CFLAGS -c lib/libtcc1.c -o libtcc1.o
$AR rcs libtcc1.a libtcc1.o $AR rcs libtcc1.a libtcc1.o
rm libtcc1.o rm libtcc1.o

View file

@ -15,20 +15,26 @@ static void vga_write_register(uint16_t index, uint16_t data) {
} }
bool vga_set_mode(uint16_t width, uint16_t height, uint16_t bpp, void **out_framebuffer) { bool vga_set_mode(uint16_t width, uint16_t height, uint16_t bpp, void **out_framebuffer) {
// 1. Locate the BGA PCI device to get the physical framebuffer address if (width < 320 || height < 200 || width > 4096 || height > 4096) {
serial_write("[VGA] Error: Invalid resolution requested.\n");
return false;
}
if (bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32) {
serial_write("[VGA] Error: Invalid bpp requested.\n");
return false;
}
pci_device_t bga_dev; pci_device_t bga_dev;
// Standard VGA compatible controller is Class 0x03, Subclass 0x00
if (!pci_find_device_by_class(0x03, 0x00, &bga_dev)) { if (!pci_find_device_by_class(0x03, 0x00, &bga_dev)) {
serial_write("[VGA] Error: VGA compatible controller not found via PCI!\n"); serial_write("[VGA] Error: VGA compatible controller not found via PCI!\n");
return false; return false;
} }
// Read BAR0 (offset 0x10)
uint32_t bar0 = pci_read_config(bga_dev.bus, bga_dev.device, bga_dev.function, 0x10); uint32_t bar0 = pci_read_config(bga_dev.bus, bga_dev.device, bga_dev.function, 0x10);
// physical address is bar0 with the lower 4 bits masked out
uint32_t phys_base = bar0 & 0xFFFFFFF0; uint32_t phys_base = bar0 & 0xFFFFFFF0;
if (phys_base == 0) { if (phys_base == 0 || phys_base == 0xFFFFFFF0) {
serial_write("[VGA] Error: Invalid BAR0 physical base.\n"); serial_write("[VGA] Error: Invalid BAR0 physical base.\n");
return false; return false;
} }
@ -37,20 +43,40 @@ bool vga_set_mode(uint16_t width, uint16_t height, uint16_t bpp, void **out_fram
serial_write_num(phys_base); serial_write_num(phys_base);
serial_write("\n"); serial_write("\n");
// Map physical to virtual using p2v
void *vram_ptr = (void *)p2v(phys_base); void *vram_ptr = (void *)p2v(phys_base);
// 2. Disable BGA extensions first uint16_t bga_id = inw(VBE_DISPI_IOPORT_INDEX);
vga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED); outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
uint16_t id = inw(VBE_DISPI_IOPORT_DATA);
outw(VBE_DISPI_IOPORT_INDEX, bga_id);
if (id < 0xB0C0) {
serial_write("[VGA] Warning: BGA not supported or old version detected.\n");
}
vga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
for (volatile int i = 0; i < 10000; i++);
// 3. Set resolution and BPP
vga_write_register(VBE_DISPI_INDEX_XRES, width); vga_write_register(VBE_DISPI_INDEX_XRES, width);
vga_write_register(VBE_DISPI_INDEX_YRES, height); vga_write_register(VBE_DISPI_INDEX_YRES, height);
vga_write_register(VBE_DISPI_INDEX_BPP, bpp); vga_write_register(VBE_DISPI_INDEX_BPP, bpp);
// 4. Re-enable BGA and Linear Framebuffer for (volatile int i = 0; i < 10000; i++);
vga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED); vga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
for (volatile int i = 0; i < 10000; i++);
uint16_t enable_reg = 0;
outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
enable_reg = inw(VBE_DISPI_IOPORT_DATA);
if (!(enable_reg & VBE_DISPI_ENABLED)) {
serial_write("[VGA] Error: Failed to enable BGA mode.\n");
return false;
}
if (out_framebuffer) { if (out_framebuffer) {
*out_framebuffer = vram_ptr; *out_framebuffer = vram_ptr;
} }