diff --git a/.gitignore b/.gitignore index 580a621..25975d7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ iso_root/ boredos.iso disk.img disk.qcow2 +run.ps1 edk2-vars.fd qemu-debug.log boredos.dump diff --git a/Makefile b/Makefile index 4e05fc8..af07e16 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,7 @@ C_SOURCES = $(wildcard $(SRC_DIR)/core/*.c) \ $(wildcard $(SRC_DIR)/net/nic/*.c) \ $(wildcard $(SRC_DIR)/fs/*.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/ipv4/*.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)/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)/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)/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)/drivers \ -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 \ -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) +<<<<<<< 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 unsafe +>>>>>>> 335d1c8 (Add new VGA fix and USB system) all: $(call PRINT_STEP,STARTING BOREDOS BUILD) $(MAKE) $(ISO_IMAGE) $(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): $(call PRINT_STEP,CREATING BUILD DIRECTORY) mkdir -p $(BUILD_DIR) @@ -170,6 +181,16 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/wm/%.c | $(BUILD_DIR) limine-setup mkdir -p $(dir $@) $(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 @printf "$(YELLOW)[CC]$(RESET)[lwIP] $< -> $@" mkdir -p $(dir $@) diff --git a/docs/build/toolchain.md b/docs/build/toolchain.md index d3e6c79..a00c020 100644 --- a/docs/build/toolchain.md +++ b/docs/build/toolchain.md @@ -20,6 +20,11 @@ To build BoredOS, you need the following tools: 4. **QEMU** (Optional but highly recommended for testing): - `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 ### Availability Issue diff --git a/src/core/main.c b/src/core/main.c index 866858b..9784e45 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -36,6 +36,9 @@ #include "input/keymap.h" #include "input/keyboard.h" #include "../drivers/acpi.h" +#include "../usb/usb.h" +#include "../usb/hid.h" +#include "../usb/logitech_b110.h" extern void sysfs_init_subsystems(void); @@ -499,6 +502,10 @@ void kmain(void) { ps2_init(); asm("sti"); + usb_init(); + usb_enumerate_devices(); + usb_hid_init(); + keymap_init(); serial_write("[INIT] Keymap initialized"); diff --git a/src/dev/ps2.c b/src/dev/ps2.c index 9225c3a..2ba5085 100644 --- a/src/dev/ps2.c +++ b/src/dev/ps2.c @@ -10,6 +10,7 @@ #include #include "input/keyboard.h" #include "input/keymap.h" +#include "../usb/logitech_b110.h" extern void serial_print(const char *s); extern void serial_print_hex(uint64_t n); @@ -151,6 +152,7 @@ uint64_t mouse_handler(registers_t *regs) { if (!(status & 0x20)) { outb(0x20, 0x20); outb(0xA0, 0x20); + logitech_b110_poll(); return (uint64_t)regs; } @@ -158,7 +160,6 @@ uint64_t mouse_handler(registers_t *regs) { if (mouse_cycle == 0) { if ((b & 0x08) == 0) { - // Out of sync } else { mouse_byte[0] = b; mouse_cycle++; @@ -187,6 +188,7 @@ uint64_t mouse_handler(registers_t *regs) { outb(0x20, 0x20); outb(0xA0, 0x20); + logitech_b110_poll(); return (uint64_t)regs; } diff --git a/src/usb/hid.c b/src/usb/hid.c new file mode 100644 index 0000000..e1e1d7e --- /dev/null +++ b/src/usb/hid.c @@ -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 + +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); + } + } + } +} diff --git a/src/usb/hid.h b/src/usb/hid.h new file mode 100644 index 0000000..b0fec22 --- /dev/null +++ b/src/usb/hid.h @@ -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 +#include + +#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 diff --git a/src/usb/logitech_b110.c b/src/usb/logitech_b110.c new file mode 100644 index 0000000..6c25cfe --- /dev/null +++ b/src/usb/logitech_b110.c @@ -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); + } +} diff --git a/src/usb/logitech_b110.h b/src/usb/logitech_b110.h new file mode 100644 index 0000000..6294928 --- /dev/null +++ b/src/usb/logitech_b110.h @@ -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 +#include + +#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 diff --git a/src/usb/uhci.c b/src/usb/uhci.c new file mode 100644 index 0000000..19bf42a --- /dev/null +++ b/src/usb/uhci.c @@ -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 + +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; +} diff --git a/src/usb/uhci.h b/src/usb/uhci.h new file mode 100644 index 0000000..0159fae --- /dev/null +++ b/src/usb/uhci.h @@ -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 +#include + +#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 diff --git a/src/usb/usb.c b/src/usb/usb.c new file mode 100644 index 0000000..b7b9449 --- /dev/null +++ b/src/usb/usb.c @@ -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 + +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]; +} diff --git a/src/usb/usb.h b/src/usb/usb.h new file mode 100644 index 0000000..6aacdab --- /dev/null +++ b/src/usb/usb.h @@ -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 +#include + +#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 diff --git a/src/userland/Makefile b/src/userland/Makefile index a6ac9ab..80150c3 100644 --- a/src/userland/Makefile +++ b/src/userland/Makefile @@ -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_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 - 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 - 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_DIR = sdk @@ -118,10 +118,10 @@ sdk: $(LIBC_OBJS) $(BIN_DIR)/libui.o mkdir -p $(SDK_DIR)/lib $(SDK_DIR)/include/sys cp libc/*.h $(SDK_DIR)/include/ 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/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: rm -rf $(BIN_DIR) $(SDK_DIR) diff --git a/src/userland/cli/third_party/tcc/build_libtcc1.sh b/src/userland/cli/third_party/tcc/build_libtcc1.sh index 1c7a4d4..fb134bb 100644 --- a/src/userland/cli/third_party/tcc/build_libtcc1.sh +++ b/src/userland/cli/third_party/tcc/build_libtcc1.sh @@ -1,9 +1,9 @@ #!/bin/bash -CC=x86_64-elf-gcc -AR=x86_64-elf-ar +CC=${CC:-x86_64-elf-gcc} +AR=${AR:-x86_64-elf-ar} 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 $AR rcs libtcc1.a libtcc1.o rm libtcc1.o diff --git a/src/wm/vga.c b/src/wm/vga.c index 78cca4f..120c5f6 100644 --- a/src/wm/vga.c +++ b/src/wm/vga.c @@ -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) { - // 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; - // Standard VGA compatible controller is Class 0x03, Subclass 0x00 if (!pci_find_device_by_class(0x03, 0x00, &bga_dev)) { serial_write("[VGA] Error: VGA compatible controller not found via PCI!\n"); return false; } - // Read BAR0 (offset 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; - if (phys_base == 0) { + if (phys_base == 0 || phys_base == 0xFFFFFFF0) { serial_write("[VGA] Error: Invalid BAR0 physical base.\n"); 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("\n"); - // Map physical to virtual using p2v void *vram_ptr = (void *)p2v(phys_base); - // 2. Disable BGA extensions first - vga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED); + uint16_t bga_id = inw(VBE_DISPI_IOPORT_INDEX); + 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_YRES, height); 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); + 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) { *out_framebuffer = vram_ptr; }