diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 53b1ccea..c5dc8240 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,21 +18,21 @@ jobs: fail-fast: false matrix: config: - - name: MacOS (Arm64) - os: macos - os-version: 15 - toolchain_arch: darwin-arm64 + - name: Linux (x64) + os: ubuntu + os-version: 22.04 + toolchain_arch: x86_64 steps: - uses: actions/checkout@v4 with: fetch-depth: '0' - - name: Install MacOS Dependencies - if: matrix.config.os == 'macos' + - name: Install Linux Dependencies + if: matrix.config.os == 'ubuntu' run: | - brew update - brew install make + sudo apt-get update + sudo apt-get install -y qemu-system-aarch64 qemu-utils make mtools dosfstools wget xz-utils - name: Install Toolchain run: | @@ -44,7 +44,7 @@ jobs: - name: Build run: | mkdir -pv fs/redos/user - make all + make all LOAD_ADDR=0x41000000 - name: Upload artifacts uses: actions/upload-artifact@v4 @@ -54,7 +54,7 @@ jobs: kernel.elf kernel.img disk.img - run + run_virt debug createfs - fs/redos/user/*.elf + fs/redos/user/*.elf \ No newline at end of file diff --git a/.gitignore b/.gitignore index b40b9743..24a9643d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ libshared.a *.a dump.dtb +fs diff --git a/Makefile b/Makefile index 5e688684..084366e5 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,6 @@ -.PHONY: all kernel user shared clean +MODE ?= virt + +.PHONY: all kernel user shared clean raspi virt run debug all: shared user kernel @echo "Build complete." @@ -11,15 +13,23 @@ user: $(MAKE) -C user kernel: - $(MAKE) -C kernel + $(MAKE) -C kernel LOAD_ADDR=$(LOAD_ADDR) clean: $(MAKE) -C shared clean $(MAKE) -C kernel clean $(MAKE) -C user clean -run: all - ./run +raspi: + $(MAKE) LOAD_ADDR=0x80000 all + +virt: + $(MAKE) LOAD_ADDR=0x41000000 all + +debug: + $(MAKE) $(MODE) + ./rundebug MODE=$(MODE) $(ARGS) -debug: all - ./rundebug \ No newline at end of file +run: + $(MAKE) $(MODE) + ./run_$(MODE) \ No newline at end of file diff --git a/createfs b/createfs index 34953033..5fb68023 100755 --- a/createfs +++ b/createfs @@ -1,62 +1,45 @@ #!/bin/bash -IMG="disk.img" FOLDER="fs" -SIZE_MB=64 -VOLUME_NAME="REDOS" +VOLUME_LABEL="REDACTED OS" +IMAGE=disk.img -[ -f "$IMG" ] && rm "$IMG" -[ -f "$IMG.dmg" ] && rm "$IMG.dmg" - -function need_executable() { +if ! command -v "mcopy" >/dev/null 2>&1; then + echo "Error: this script depends on mtools. Please install it" >&2 + exit 1 +fi - EXECUTABLE="$1" +if ! command -v "mkfs.fat" >/dev/null 2>&1; then + echo "Error: this script depends on dosfstools. Please install it" >&2 + exit 1 +fi - RECOMMENDED_PACKAGE="$2" - if ! command -v "$EXECUTABLE" >/dev/null 2>&1; then - echo "Error: this script needs the '$EXECUTABLE' executable, please install it" >&2 - if [ -n "$RECOMMENDED_PACKAGE" ]; then - echo "The recommended package to install for this program is: '$RECOMMENDED_PACKAGE'" >&2 - fi - exit 1 - fi +if [[ "$OSTYPE" == "darwin"* ]]; then + SIZE_KB=$(du -sk "$FOLDER" | cut -f1) +else + SIZE_KB=$(du -s -B1 "$FOLDER" | awk '{print int($1/1024)}') +fi +power_of_two() { + local n=$1 + local p=1 + while (( p < n )); do + (( p *= 2 )) + done + echo $p } -OS_TYPE="$(uname)" - -if [[ "$OS_TYPE" == "Darwin" ]]; then - echo "Running on macOS" - need_executable hdiutil +SIZE_MB=$(( (SIZE_KB * 12 / 10 + 1023) / 1024 )) - DEV_INFO=$(hdiutil create -size ${SIZE_MB}m -fs "ExFAT" -layout NONE -volname "$VOLUME_NAME" "$IMG" -attach) - MOUNTPOINT=$(echo "$DEV_INFO" | awk '/\/Volumes\// {print $NF}') - DEVICE=$(echo "$DEV_INFO" | awk '/\/dev\/disk/ {print $1; exit}') +SIZE_MB=$(power_of_two "$SIZE_MB") - cp -R "$FOLDER/" "$MOUNTPOINT/" - - #.fseventsd is not getting deleted i think - find "$MOUNTPOINT/" -type f \( -name '.DS_Store' -o -name '.fseventsd' -o -name '._*' \) -delete - - echo "$MOUNTPOINT" - echo "DEV: $DEVICE" - - hdiutil detach "$DEVICE" - mv "$IMG.dmg" "$IMG" - -elif [[ "$OS_TYPE" == "Linux" ]]; then - echo "Running on Linux" +if ((SIZE_MB < 64)); then + SIZE_MB=64 +fi - need_executable dd - need_executable mkfs.exfat "exfatprogs" +dd if=/dev/zero of=$IMAGE bs=1M count=$SIZE_MB - # 1. Create an empty image file - dd if=/dev/zero of="$IMG" bs=1M count="$SIZE_MB" +mkfs.fat -F 32 -n "$VOLUME_LABEL" $IMAGE - # 2. Format it as ExFAT - mkfs.exfat -n "$VOLUME_NAME" "$IMG" -else - echo "Unknown OS: $OS_TYPE" >&2 - exit 1 -fi +mcopy -i $IMAGE -s "$FOLDER"/* :: \ No newline at end of file diff --git a/kernel/Makefile b/kernel/Makefile index db95c26a..cf9780d7 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -4,7 +4,8 @@ LD = $(ARCH)-ld OBJCOPY = $(ARCH)-objcopy CFLAGS = -g -O0 -std=c17 -nostdlib -ffreestanding -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wextra -mcpu=cortex-a72 -I. -I../shared -I../user -LDFLAGS = -T $(shell ls *.ld) + +LDFLAGS = -T $(shell ls *.ld) --defsym=LOAD_ADDR=$(LOAD_ADDR) C_SRC = $(shell find . -name '*.c') ASM_SRC = $(shell find . -name '*.S') diff --git a/kernel/async.c b/kernel/async.c new file mode 100644 index 00000000..37ab9aa9 --- /dev/null +++ b/kernel/async.c @@ -0,0 +1,31 @@ +#include "async.h" +#include "console/kio.h" + +void delay(uint32_t ms) { + uint64_t freq; + asm volatile ("mrs %0, cntfrq_el0" : "=r"(freq)); + + uint64_t ticks; + asm volatile ("mrs %0, cntpct_el0" : "=r"(ticks)); + + uint64_t target = ticks + (freq / 1000) * ms; + + while (1) { + uint64_t now; + asm volatile ("mrs %0, cntpct_el0" : "=r"(now)); + if (now >= target) break; + } +} + +bool wait(uint32_t *reg, uint32_t expected_value, bool match, uint32_t timeout){ + bool condition; + do { + delay(1); + timeout--; + if (timeout == 0) + return false; + condition = (*reg & expected_value) == expected_value; + } while ((match > 0) ^ condition); + + return true; +} \ No newline at end of file diff --git a/kernel/async.h b/kernel/async.h new file mode 100644 index 00000000..8eaab384 --- /dev/null +++ b/kernel/async.h @@ -0,0 +1,12 @@ +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif +void delay(uint32_t count); +bool wait(uint32_t *reg, uint32_t expected_value, bool match, uint32_t timeout); +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/kernel/boot.S b/kernel/boot.S index ae1e7d65..cc4b195d 100644 --- a/kernel/boot.S +++ b/kernel/boot.S @@ -1,11 +1,115 @@ .global _start +.section .text _start: + mrs x0, mpidr_el1 + and x0, x0, #3 + cbz x0, setup_vars +half: + wfe + b half + +setup_vars: + ldr x5, =__bss_start + ldr x6, =__bss_end +clear_bss: + cmp x5, x6 + b.ge check_hw + str xzr, [x5], #8 + b clear_bss + +check_hw: + adr x0, . + + movz x1, #0x4100, lsl #16 + and x2, x0, #0xFFF00000 + cmp x2, x1 + b.eq virt + + movz x1, #0x4000, lsl #16 + and x2, x0, #0xFFF00000 + cmp x2, x1 + b.eq virt + + mov x1, #0x80000 + and x2, x0, #0xFFFFF000 + cmp x2, x1 + b.eq rpi + + mov x1, #0x100000 + and x2, x0, #0xFFFFF000 + cmp x2, x1 + b.eq rpi + + b .//Halt if none + +virt: + mov w0, #1 + adrp x1, BOARD_TYPE + strb w0, [x1, #:lo12:BOARD_TYPE] + b stack_setup +rpi: + mov w0, #2 + adrp x1, BOARD_TYPE + strb w0, [x1, #:lo12:BOARD_TYPE] + b drop_el3 + +drop_el3: + mrs x0, CurrentEL + lsr x0, x0, #2 + cmp x0, #3 + b.ne el2_entry + + msr sctlr_el2, xzr + mrs x0, hcr_el2 + orr x0, x0, #(1<<19) + msr hcr_el2, x0 + + mrs x0, scr_el3 + orr x0, x0, #(1<<10) + orr x0, x0, #(1<<0) + msr scr_el3, x0 + + mov x0, #0b01001//DAIF 0000 + msr spsr_el3, x0 + + adr x0, el2_entry + msr elr_el3, x0 + eret + +el2_entry: + mrs x0, CurrentEL + lsr x0, x0, #2 + cmp x0, #2 + b.ne el1_non_secure + + mov x0, #3 << 20 + msr cpacr_el1, x0 + + ldr x0, =0x30C00800 + msr sctlr_el1, x0 + + mrs x0, hcr_el2 + orr x0, x0, #(1<<31) + msr hcr_el2, x0 + + mov x0, 0x1C5 + msr spsr_el2, x0 + + adr x0, el1_non_secure + msr elr_el2, x0 + + eret + +el1_non_secure: +stack_setup: ldr x1, =stack_top mov sp, x1 + mov x29, xzr mov x30, xzr - mrs x0, CPACR_EL1 - orr x0, x0, #(3 << 20) - msr CPACR_EL1, x0 + mrs x1, CPACR_EL1 + orr x1, x1, #(3 << 20) + msr CPACR_EL1, x1 bl kernel_main + b . \ No newline at end of file diff --git a/kernel/console/kconsole/kconsole.cpp b/kernel/console/kconsole/kconsole.cpp index 5690e221..948ddf4c 100644 --- a/kernel/console/kconsole/kconsole.cpp +++ b/kernel/console/kconsole/kconsole.cpp @@ -22,7 +22,6 @@ bool KernelConsole::check_ready(){ void KernelConsole::resize() { gpu_size screen = gpu_get_screen_size(); - uart_puthex(screen.width); columns = screen.width / char_width; rows = screen.height / char_height; diff --git a/kernel/console/serial/uart.c b/kernel/console/serial/uart.c index 3173a7b0..1427062d 100644 --- a/kernel/console/serial/uart.c +++ b/kernel/console/serial/uart.c @@ -1,6 +1,8 @@ #include "console/serial/uart.h" #include "memory/memory_access.h" #include "exceptions/irq.h" +#include "gpio.h" +#include "hw/hw.h" #define UART0_DR (UART0_BASE + 0x00) #define UART0_FR (UART0_BASE + 0x18) @@ -16,6 +18,11 @@ uint64_t get_uart_base(){ void enable_uart() { write32(UART0_CR, 0x0); + if (BOARD_TYPE == 2){ + enable_gpio_pin(14); + enable_gpio_pin(15); + } + write32(UART0_IBRD, 1); write32(UART0_FBRD, 40); diff --git a/kernel/console/serial/uart.h b/kernel/console/serial/uart.h index 9bb386d3..cb01c8e1 100644 --- a/kernel/console/serial/uart.h +++ b/kernel/console/serial/uart.h @@ -5,8 +5,7 @@ extern "C" { #endif #include "types.h" - -#define UART0_BASE 0x09000000 +#include "hw/hw.h" uint64_t get_uart_base(); void enable_uart(); diff --git a/kernel/exceptions/irq.c b/kernel/exceptions/irq.c index 08d3d56c..a1c0ea74 100644 --- a/kernel/exceptions/irq.c +++ b/kernel/exceptions/irq.c @@ -2,9 +2,9 @@ #include "console/kio.h" #include "memory/memory_access.h" #include "process/scheduler.h" +#include "input/input_dispatch.h" #include "input/xhci_types.h" #include "pci.h" -#include "input/xhci.h" #include "console/serial/uart.h" #include "networking/network.h" @@ -71,7 +71,7 @@ void irq_el1_handler() { write32(GICC_BASE + 0x10, irq); switch_proc(INTERRUPT); } else if (irq == MSI_OFFSET + XHCI_IRQ){ - xhci_handle_interrupt(); + handle_input_interrupt(); write32(GICC_BASE + 0x10, irq); process_restore(); } else if (irq == SLEEP_TIMER){ diff --git a/kernel/exceptions/irq.h b/kernel/exceptions/irq.h index 67eeb7f7..a8fae41e 100644 --- a/kernel/exceptions/irq.h +++ b/kernel/exceptions/irq.h @@ -1,9 +1,7 @@ #pragma once #include "types.h" - -#define GICD_BASE 0x08000000 -#define GICC_BASE 0x08010000 +#include "hw/hw.h" void irq_init(); void irq_el1_handler(); diff --git a/kernel/filesystem/disk.c b/kernel/filesystem/disk.c deleted file mode 100644 index 7fe50076..00000000 --- a/kernel/filesystem/disk.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "disk.h" -#include "exfat.h" -#include "virtio_blk_pci.h" - -static bool disk_enable_verbose; - -void disk_verbose(){ - disk_enable_verbose = true; - vblk_disk_verbose(); -} - -#define kprintfv(fmt, ...) \ - ({ \ - if (mmu_verbose){\ - uint64_t _args[] = { __VA_ARGS__ }; \ - kprintf_args_raw((fmt), _args, sizeof(_args) / sizeof(_args[0])); \ - }\ - }) - -bool find_disk(){ - return vblk_find_disk(); -} - -bool disk_init(){ - return ef_init(); -} - -void disk_write(const void *buffer, uint32_t sector, uint32_t count){ - vblk_write(buffer, sector, count); -} - -void disk_read(void *buffer, uint32_t sector, uint32_t count){ - vblk_read(buffer, sector, count); -} - -void* read_file(const char *path){ - return ef_read_file(path); -} - -string_list* list_directory_contents(const char *path){ - return ef_list_contents(path); -} \ No newline at end of file diff --git a/kernel/filesystem/disk.cpp b/kernel/filesystem/disk.cpp new file mode 100644 index 00000000..39ba9067 --- /dev/null +++ b/kernel/filesystem/disk.cpp @@ -0,0 +1,57 @@ +#include "disk.h" +#include "exfat.hpp" +#include "fat32.hpp" +#include "virtio_blk_pci.h" +#include "sdhci.hpp" +#include "hw/hw.h" + +static bool disk_enable_verbose; +SDHCI sdhci_driver; +FAT32FS fs_driver; + +void disk_verbose(){ + disk_enable_verbose = true; + vblk_disk_verbose(); + if (BOARD_TYPE == 2){ + sdhci_driver.enable_verbose(); + } +} + +#define kprintfv(fmt, ...) \ + ({ \ + if (mmu_verbose){\ + uint64_t _args[] = { __VA_ARGS__ }; \ + kprintf_args_raw((fmt), _args, sizeof(_args) / sizeof(_args[0])); \ + }\ + }) + + +bool find_disk(){ + if (BOARD_TYPE == 2) + return sdhci_driver.init(); + else + return vblk_find_disk(); +} + +bool disk_init(){ + return fs_driver.init(); +} + +void disk_write(const void *buffer, uint32_t sector, uint32_t count){ + vblk_write(buffer, sector, count); +} + +void disk_read(void *buffer, uint32_t sector, uint32_t count){ + if (BOARD_TYPE == 2) + sdhci_driver.read(buffer, sector, count); + else + vblk_read(buffer, sector, count); +} + +void* read_file(char *path){ + return fs_driver.read_file(path); +} + +string_list* list_directory_contents(char *path){ + return fs_driver.list_contents(path); +} \ No newline at end of file diff --git a/kernel/filesystem/disk.h b/kernel/filesystem/disk.h index bff6a946..8d4de64e 100644 --- a/kernel/filesystem/disk.h +++ b/kernel/filesystem/disk.h @@ -14,8 +14,8 @@ bool disk_init(); void disk_write(const void *buffer, uint32_t sector, uint32_t count); void disk_read(void *buffer, uint32_t sector, uint32_t count); -void* read_file(const char *path); -string_list* list_directory_contents(const char *path); +void* read_file(char *path); +string_list* list_directory_contents(char *path); #ifdef __cplusplus } diff --git a/kernel/filesystem/exfat.c b/kernel/filesystem/exfat.c deleted file mode 100644 index f9e39267..00000000 --- a/kernel/filesystem/exfat.c +++ /dev/null @@ -1,292 +0,0 @@ -#include "exfat.h" -#include "disk.h" -#include "memory/page_allocator.h" -#include "console/kio.h" -#include "std/string.h" -#include "std/memfunctions.h" - -void *fs_page; - -typedef struct exfat_mbs { - uint8_t jumpboot[3];//3 - char fsname[8];//8 - uint8_t mustbezero[53]; - uint64_t partition_offset; - uint64_t volume_length; - uint32_t fat_offset; - uint32_t fat_length; - uint32_t cluster_heap_offset; - uint32_t cluster_count; - uint32_t first_cluster_of_root_directory; - uint32_t volume_serial_number; - uint16_t fs_revision; - uint16_t volume_flags; - uint8_t bytes_per_sector_shift; - uint8_t sectors_per_cluster_shift; - uint8_t number_of_fats; - uint8_t drive_select; - uint8_t percent_in_use; - uint8_t rsvd[7]; - char bootcode[390]; - uint16_t bootsignature; -}__attribute__((packed)) exfat_mbs; - -typedef struct file_entry { - uint8_t entry_type; - uint8_t entry_count; - uint16_t checksum; - struct { - uint16_t read_only: 1; - uint16_t hidden: 1; - uint16_t system: 1; - uint16_t rsvd: 1; - uint16_t directory: 1; - uint16_t archive: 1; - uint16_t rsvd2: 10; - } flags; - - uint16_t rsvd; - uint32_t create_timestamp; - uint32_t last_modified; - uint32_t last_accessed; - uint8_t create10msincrement; - uint8_t lastmod10msincrement; - uint8_t createutcoffset; - uint8_t lastmodutcoffset; - uint8_t lastaccutcoffset; - - uint8_t rsvd2[7]; -}__attribute__((packed)) file_entry; - -typedef struct fileinfo_entry { - uint8_t entry_type; - uint8_t flags; - uint8_t rsvd; - uint8_t name_length; - uint16_t name_hash; - uint16_t rsvd2; - uint64_t valid_filesize; - uint32_t rsvd3; - uint32_t first_cluster; - uint64_t filesize; -}__attribute__((packed)) fileinfo_entry; - -typedef struct filename_entry { - uint8_t entry_type; - uint8_t flags; - uint16_t name[15]; -}__attribute__((packed)) filename_entry; - -exfat_mbs* mbs; - -void* ef_read_cluster(uint32_t cluster_start, uint32_t cluster_size, uint32_t cluster_count, uint32_t root_index){ - uint32_t count = cluster_count * cluster_size; - - uint32_t lba = cluster_start + ((root_index - 2) * cluster_size); - - kprintf("Reading cluster(s) %i-%i, starting from %i (LBA %i)", root_index, root_index+cluster_count, cluster_start, lba); - - void* buffer = (char*)allocate_in_page(fs_page, cluster_count * cluster_size * 512, ALIGN_64B, true, true); - - disk_read(buffer, lba, count); - - return buffer; -} - -const char* advance_path(const char *path){ - while (*path != '/' && *path != '\0') - path++; - path++; - return path; -} - -typedef void* (*ef_entry_handler)(file_entry*, fileinfo_entry*, filename_entry*, const char *seek); - -void* ef_walk_directory(uint32_t cluster_count, uint32_t root_index, const char *seek, ef_entry_handler handler) { - uint32_t cluster_size = 1 << mbs->sectors_per_cluster_shift; - char *buffer = (char*)ef_read_cluster(mbs->cluster_heap_offset, cluster_size, cluster_count, root_index); - file_entry *entry = 0; - fileinfo_entry *entry1 = 0; - filename_entry *entry2 = 0; - - for (uint64_t i = 0; i < cluster_size * 512; i++) { - char c = buffer[i]; - if (c == 0x85) { - entry = (file_entry *)&buffer[i]; - i += sizeof(file_entry) - 1; - } else if (c == 0xC0) { - entry1 = (fileinfo_entry *)&buffer[i]; - i += sizeof(fileinfo_entry) - 1; - } else if (c == 0xC1) { - entry2 = (filename_entry *)&buffer[i]; - if (entry && entry1 && entry2) { - void *result = handler(entry, entry1, entry2, seek); - if (result) - return result; - } - i += sizeof(filename_entry) - 1; - } - } - - return 0; -} - -void* ef_list_directory(uint32_t cluster_count, uint32_t root_index) { - uint32_t cluster_size = 1 << mbs->sectors_per_cluster_shift; - char *buffer = (char*)ef_read_cluster(mbs->cluster_heap_offset, cluster_size, cluster_count, root_index); - file_entry *entry = 0; - fileinfo_entry *entry1 = 0; - filename_entry *entry2 = 0; - void *list_buffer = (char*)allocate_in_page(fs_page, 0x1000 * cluster_count, ALIGN_64B, true, true); - uint32_t len = 0; - uint32_t count = 0; - - char *write_ptr = (char*)list_buffer + 4; - - for (uint64_t i = 0; i < cluster_size * 512; i++) { - char c = buffer[i]; - if (c == 0x85) { - entry = (file_entry *)&buffer[i]; - i += sizeof(file_entry) - 1; - } else if (c == 0xC0) { - entry1 = (fileinfo_entry *)&buffer[i]; - i += sizeof(fileinfo_entry) - 1; - } else if (c == 0xC1) { - entry2 = (filename_entry *)&buffer[i]; - if (entry && entry1 && entry2) { - count++; - char filename[15]; - utf16tochar(entry2->name, filename, 15); - for (int j = 0; j < 15 && filename[j]; j++) - *write_ptr++ = filename[j]; - *write_ptr++ = '\0'; - } - i += sizeof(filename_entry) - 1; - } - } - - *(uint32_t*)list_buffer = count; - - return list_buffer; -} - -void* ef_read_full_file(uint32_t cluster_start, uint32_t cluster_size, uint32_t cluster_count, uint64_t file_size, uint32_t root_index){ - - char *buffer = (char*)ef_read_cluster(cluster_start, cluster_size, cluster_count, root_index); - - void *file = allocate_in_page(fs_page, file_size, ALIGN_64B, true, true); - - memcpy(file, (void*)buffer, file_size); - - return file; -} - -void ef_read_dump(uint32_t cluster_start, uint32_t cluster_size, uint32_t cluster_count, uint32_t root_index){ - - char *buffer = (char*)ef_read_cluster(cluster_start, cluster_size, cluster_count, root_index); - - for (uint64_t i = 0; i < cluster_size * cluster_count * 512; i++){ - // if (i % 8 == 0){ puts("\n["); puthex(i/8); puts("]: "); } - char c = buffer[i]; - if (c >= 0x20 && c <= 0x7E) putc(c); - // else puthex(c); - } - // puts("Done printing"); - putc('\n'); -} - -void ef_read_FAT(uint32_t location, uint32_t size, uint8_t count){ - uint32_t* fat = (uint32_t*)allocate_in_page(fs_page, size * count * 512, ALIGN_64B, true, true); - disk_read((void*)fat, location, size); - kprintf("FAT: %x (%x)",location*512,size * count * 512); - uint32_t total_entries = (size * count * 512) / 4; - for (uint32_t i = 0; i < total_entries; i++) - if (fat[i] != 0) kprintf("[%i] = %x", i, fat[i]); -} - -bool ef_init(){ - fs_page = alloc_page(0x1000, true, true, false); - - mbs = (exfat_mbs*)allocate_in_page(fs_page, 512, ALIGN_64B, true, true); - - disk_read((void*)mbs, 0, 1); - - if (mbs->bootsignature != 0xAA55){ - kprintf("[exfat] Wrong boot signature %x",mbs->bootsignature); - return false; - } - if (strcmp("EXFAT ", mbs->fsname) != 0){ - kprintf("[exfat error] Wrong filesystem type %s",(uintptr_t)mbs->fsname); - return false; - } - uintptr_t extended = (1 << mbs->bytes_per_sector_shift) - 512; - if (extended > 0){ - kprintf("[exfat implementation error] we don't support extended boot sector yet"); - // return false; - } - - if (mbs->first_cluster_of_root_directory > mbs->cluster_count){ - kprintf("[exfat error] root directory cluster not found"); - return false; - } - - kprintf("EXFAT Volume uses %i cluster size", 1 << mbs->bytes_per_sector_shift); - - kprintf("Cluster at %x (%x * %x of size %x each)",mbs->fat_offset + mbs->fat_length * mbs->number_of_fats, mbs->cluster_heap_offset,mbs->cluster_count, 1 << mbs->sectors_per_cluster_shift); - ef_read_FAT(mbs->fat_offset, mbs->fat_length, mbs->number_of_fats); - return true; -} - -static void* read_entry_handler(file_entry *entry, fileinfo_entry *info, filename_entry *name, const char *seek) { - char filename[15]; - utf16tochar(name->name, filename, 15); - - if (strstart(seek, filename) != 0) - return 0; - - uint32_t filecluster = info->first_cluster; - uint32_t bps = 1 << mbs->bytes_per_sector_shift; - uint32_t spc = 1 << mbs->sectors_per_cluster_shift; - uint32_t bpc = bps * spc; - uint32_t count = (info->filesize + bpc - 1) / bpc; - - return entry->flags.directory - ? ef_walk_directory(count, filecluster, advance_path(seek), read_entry_handler) - : ef_read_full_file(mbs->cluster_heap_offset, 1 << mbs->sectors_per_cluster_shift, count, info->filesize, filecluster); -} - -void* ef_read_file(const char *path){ - path = advance_path(path); - - return ef_walk_directory(1, mbs->first_cluster_of_root_directory, path, read_entry_handler); -} - -static void* list_entries_handler(file_entry *entry, fileinfo_entry *info, filename_entry *name, const char *seek) { - char filename[15]; - utf16tochar(name->name, filename, 15); - - if (strstart(seek, filename) != 0) - return 0; - - bool is_last = *advance_path(seek) == '\0'; - - uint32_t filecluster = info->first_cluster; - uint32_t bps = 1 << mbs->bytes_per_sector_shift; - uint32_t spc = 1 << mbs->sectors_per_cluster_shift; - uint32_t bpc = bps * spc; - uint32_t count = (info->filesize + bpc - 1) / bpc; - - kprintf("Now handling %s. Last %i",(uintptr_t)seek, is_last); - - if (is_last) - return ef_list_directory(count, filecluster); - if (entry->flags.directory) - return ef_walk_directory(count, filecluster, advance_path(seek), list_entries_handler); - return 0; -} - -string_list* ef_list_contents(const char *path){ - path = advance_path(path); - - return (string_list*)ef_walk_directory(1, mbs->first_cluster_of_root_directory, path, list_entries_handler); -} \ No newline at end of file diff --git a/kernel/filesystem/exfat.cpp b/kernel/filesystem/exfat.cpp new file mode 100644 index 00000000..d9c8f7ea --- /dev/null +++ b/kernel/filesystem/exfat.cpp @@ -0,0 +1,202 @@ +#include "exfat.hpp" +#include "disk.h" +#include "memory/page_allocator.h" +#include "console/kio.h" +#include "std/string.h" +#include "std/memfunctions.h" + +char* ExFATFS::advance_path(char *path){ + while (*path != '/' && *path != '\0') + path++; + path++; + return path; +} + +void* ExFATFS::read_cluster(uint32_t cluster_start, uint32_t cluster_size, uint32_t cluster_count, uint32_t root_index){ + uint32_t count = cluster_count * cluster_size; + + uint32_t lba = cluster_start + ((root_index - 2) * cluster_size); + + kprintf("Reading cluster(s) %i-%i, starting from %i (LBA %i)", root_index, root_index+cluster_count, cluster_start, lba); + + void* buffer = (char*)allocate_in_page(fs_page, cluster_count * cluster_size * 512, ALIGN_64B, true, true); + + disk_read(buffer, lba, count); + + return buffer; +} + +void* ExFATFS::walk_directory(uint32_t cluster_count, uint32_t root_index, char *seek, ef_entry_handler handler) { + uint32_t cluster_size = 1 << mbs->sectors_per_cluster_shift; + char *buffer = (char*)read_cluster(mbs->cluster_heap_offset, cluster_size, cluster_count, root_index); + file_entry *entry = 0; + fileinfo_entry *entry1 = 0; + filename_entry *entry2 = 0; + + for (uint64_t i = 0; i < cluster_size * 512; i++) { + char c = buffer[i]; + if (c == 0x85) { + entry = (file_entry *)&buffer[i]; + i += sizeof(file_entry) - 1; + } else if (c == 0xC0) { + entry1 = (fileinfo_entry *)&buffer[i]; + i += sizeof(fileinfo_entry) - 1; + } else if (c == 0xC1) { + entry2 = (filename_entry *)&buffer[i]; + if (entry && entry1 && entry2) { + void *result = handler(this,entry, entry1, entry2, seek); + if (result) + return result; + } + i += sizeof(filename_entry) - 1; + } + } + + return 0; +} + +void* ExFATFS::list_directory(uint32_t cluster_count, uint32_t root_index) { + uint32_t cluster_size = 1 << mbs->sectors_per_cluster_shift; + char *buffer = (char*)read_cluster(mbs->cluster_heap_offset, cluster_size, cluster_count, root_index); + file_entry *entry = 0; + fileinfo_entry *entry1 = 0; + filename_entry *entry2 = 0; + void *list_buffer = (char*)allocate_in_page(fs_page, 0x1000 * cluster_count, ALIGN_64B, true, true); + uint32_t len = 0; + uint32_t count = 0; + + char *write_ptr = (char*)list_buffer + 4; + + for (uint64_t i = 0; i < cluster_size * 512; i++) { + char c = buffer[i]; + if (c == 0x85) { + entry = (file_entry *)&buffer[i]; + i += sizeof(file_entry) - 1; + } else if (c == 0xC0) { + entry1 = (fileinfo_entry *)&buffer[i]; + i += sizeof(fileinfo_entry) - 1; + } else if (c == 0xC1) { + entry2 = (filename_entry *)&buffer[i]; + if (entry && entry1 && entry2) { + count++; + char filename[15]; + utf16tochar(entry2->name, filename, 15); + for (int j = 0; j < 15 && filename[j]; j++) + *write_ptr++ = filename[j]; + *write_ptr++ = '\0'; + } + i += sizeof(filename_entry) - 1; + } + } + + *(uint32_t*)list_buffer = count; + + return list_buffer; +} + +void* ExFATFS::read_full_file(uint32_t cluster_start, uint32_t cluster_size, uint32_t cluster_count, uint64_t file_size, uint32_t root_index){ + + char *buffer = (char*)read_cluster(cluster_start, cluster_size, cluster_count, root_index); + + void *file = allocate_in_page(fs_page, file_size, ALIGN_64B, true, true); + + memcpy(file, (void*)buffer, file_size); + + return file; +} + +void ExFATFS::read_FAT(uint32_t location, uint32_t size, uint8_t count){ + uint32_t* fat = (uint32_t*)allocate_in_page(fs_page, size * count * 512, ALIGN_64B, true, true); + disk_read((void*)fat, location, size); + kprintf("FAT: %x (%x)",location*512,size * count * 512); + uint32_t total_entries = (size * count * 512) / 4; + // for (uint32_t i = 0; i < total_entries; i++) + // if (fat[i] != 0) kprintf("[%i] = %x", i, fat[i]); +} + +bool ExFATFS::init(){ + fs_page = alloc_page(0x1000, true, true, false); + + mbs = (exfat_mbs*)allocate_in_page(fs_page, 512, ALIGN_64B, true, true); + + disk_read((void*)mbs, 0, 1); + + if (mbs->bootsignature != 0xAA55){ + kprintf("[exfat] Wrong boot signature %x",mbs->bootsignature); + return false; + } + if (strcmp("EXFAT ", mbs->fsname, false) != 0){ + kprintf("[exfat error] Wrong filesystem type %s",(uintptr_t)mbs->fsname); + return false; + } + uintptr_t extended = (1 << mbs->bytes_per_sector_shift) - 512; + if (extended > 0){ + kprintf("[exfat implementation error] we don't support extended boot sector yet"); + // return false; + } + + if (mbs->first_cluster_of_root_directory > mbs->cluster_count){ + kprintf("[exfat error] root directory cluster not found"); + return false; + } + + kprintf("EXFAT Volume uses %i cluster size", 1 << mbs->bytes_per_sector_shift); + + kprintf("Cluster at %x (%x * %x of size %x each)",mbs->fat_offset + mbs->fat_length * mbs->number_of_fats, mbs->cluster_heap_offset,mbs->cluster_count, 1 << mbs->sectors_per_cluster_shift); + read_FAT(mbs->fat_offset, mbs->fat_length, mbs->number_of_fats); + return true; +} + +void* ExFATFS::read_entry_handler(ExFATFS *instance, file_entry *entry, fileinfo_entry *info, filename_entry *name, char *seek) { + char filename[15]; + utf16tochar(name->name, filename, 15); + + if (strstart(seek, filename, false) != 0) + return 0; + + uint32_t filecluster = info->first_cluster; + uint32_t bps = 1 << instance->mbs->bytes_per_sector_shift; + uint32_t spc = 1 << instance->mbs->sectors_per_cluster_shift; + uint32_t bpc = bps * spc; + uint32_t count = (info->filesize + bpc - 1) / bpc; + + return entry->flags.directory + ? instance->walk_directory(count, filecluster, instance->advance_path(seek), read_entry_handler) + : instance->read_full_file(instance->mbs->cluster_heap_offset, 1 << instance->mbs->sectors_per_cluster_shift, count, info->filesize, filecluster); +} + +void* ExFATFS::read_file(char *path){ + path = advance_path(path); + + return walk_directory(1, mbs->first_cluster_of_root_directory, path, read_entry_handler); +} + +void* ExFATFS::list_entries_handler(ExFATFS *instance, file_entry *entry, fileinfo_entry *info, filename_entry *name, char *seek) { + char filename[15]; + utf16tochar(name->name, filename, 15); + + if (strstart(seek, filename, false) != 0) + return 0; + + bool is_last = *instance->advance_path(seek) == '\0'; + + uint32_t filecluster = info->first_cluster; + uint32_t bps = 1 << instance->mbs->bytes_per_sector_shift; + uint32_t spc = 1 << instance->mbs->sectors_per_cluster_shift; + uint32_t bpc = bps * spc; + uint32_t count = (info->filesize + bpc - 1) / bpc; + + kprintf("Now handling %s. Last %i",(uintptr_t)seek, is_last); + + if (is_last) + return instance->list_directory(count, filecluster); + if (entry->flags.directory) + return instance->walk_directory(count, filecluster, instance->advance_path(seek), list_entries_handler); + return 0; +} + +string_list* ExFATFS::list_contents(char *path){ + path = advance_path(path); + + return (string_list*)walk_directory(1, mbs->first_cluster_of_root_directory, path, list_entries_handler); +} \ No newline at end of file diff --git a/kernel/filesystem/exfat.h b/kernel/filesystem/exfat.h deleted file mode 100644 index 9f124374..00000000 --- a/kernel/filesystem/exfat.h +++ /dev/null @@ -1,8 +0,0 @@ -#include "types.h" -#include "std/string.h" - -bool ef_init(); -void ef_read_dump(uint32_t cluster_start, uint32_t cluster_size, uint32_t cluster_count, uint32_t root_index); -void* ef_read_full_file(uint32_t cluster_start, uint32_t cluster_size, uint32_t cluster_count, uint64_t file_size, uint32_t root_index); -void* ef_read_file(const char *path); -string_list* ef_list_contents(const char *path); \ No newline at end of file diff --git a/kernel/filesystem/exfat.hpp b/kernel/filesystem/exfat.hpp new file mode 100644 index 00000000..b044bf39 --- /dev/null +++ b/kernel/filesystem/exfat.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include "types.h" +#include "std/string.h" + +typedef struct exfat_mbs { + uint8_t jumpboot[3];//3 + char fsname[8];//8 + uint8_t mustbezero[53]; + uint64_t partition_offset; + uint64_t volume_length; + uint32_t fat_offset; + uint32_t fat_length; + uint32_t cluster_heap_offset; + uint32_t cluster_count; + uint32_t first_cluster_of_root_directory; + uint32_t volume_serial_number; + uint16_t fs_revision; + uint16_t volume_flags; + uint8_t bytes_per_sector_shift; + uint8_t sectors_per_cluster_shift; + uint8_t number_of_fats; + uint8_t drive_select; + uint8_t percent_in_use; + uint8_t rsvd[7]; + char bootcode[390]; + uint16_t bootsignature; +}__attribute__((packed)) exfat_mbs; + +typedef struct file_entry { + uint8_t entry_type; + uint8_t entry_count; + uint16_t checksum; + struct { + uint16_t read_only: 1; + uint16_t hidden: 1; + uint16_t system: 1; + uint16_t rsvd: 1; + uint16_t directory: 1; + uint16_t archive: 1; + uint16_t rsvd2: 10; + } flags; + + uint16_t rsvd; + uint32_t create_timestamp; + uint32_t last_modified; + uint32_t last_accessed; + uint8_t create10msincrement; + uint8_t lastmod10msincrement; + uint8_t createutcoffset; + uint8_t lastmodutcoffset; + uint8_t lastaccutcoffset; + + uint8_t rsvd2[7]; +}__attribute__((packed)) file_entry; + +typedef struct fileinfo_entry { + uint8_t entry_type; + uint8_t flags; + uint8_t rsvd; + uint8_t name_length; + uint16_t name_hash; + uint16_t rsvd2; + uint64_t valid_filesize; + uint32_t rsvd3; + uint32_t first_cluster; + uint64_t filesize; +}__attribute__((packed)) fileinfo_entry; + +typedef struct filename_entry { + uint8_t entry_type; + uint8_t flags; + uint16_t name[15]; +}__attribute__((packed)) filename_entry; + +class ExFATFS; + +typedef void* (*ef_entry_handler)(ExFATFS *instance, file_entry*, fileinfo_entry*, filename_entry*, char *seek); + +class ExFATFS { +public: + bool init(); + void* read_full_file(uint32_t cluster_start, uint32_t cluster_size, uint32_t cluster_count, uint64_t file_size, uint32_t root_index); + void* read_file(char *path); + string_list* list_contents(char *path); + +protected: + void read_FAT(uint32_t location, uint32_t size, uint8_t count); + void* list_directory(uint32_t cluster_count, uint32_t root_index); + void* walk_directory(uint32_t cluster_count, uint32_t root_index, char *seek, ef_entry_handler handler); + void* read_cluster(uint32_t cluster_start, uint32_t cluster_size, uint32_t cluster_count, uint32_t root_index); + char* advance_path(char *path); + + exfat_mbs* mbs; + void *fs_page; + + static void* read_entry_handler(ExFATFS *instance, file_entry *entry, fileinfo_entry *info, filename_entry *name, char *seek); + static void* list_entries_handler(ExFATFS *instance, file_entry *entry, fileinfo_entry *info, filename_entry *name, char *seek); +}; \ No newline at end of file diff --git a/kernel/filesystem/fat32.cpp b/kernel/filesystem/fat32.cpp new file mode 100644 index 00000000..b51264c3 --- /dev/null +++ b/kernel/filesystem/fat32.cpp @@ -0,0 +1,285 @@ +#include "fat32.hpp" +#include "disk.h" +#include "memory/page_allocator.h" +#include "console/kio.h" +#include "std/string.h" +#include "std/memfunctions.h" +#include "math/math.h" + +#define kprintfv(fmt, ...) \ + ({ \ + if (verbose){\ + uint64_t _args[] = { __VA_ARGS__ }; \ + kprintf_args((fmt), _args, sizeof(_args) / sizeof(_args[0])); \ + }\ + }) + +char* FAT32FS::advance_path(char *path){ + while (*path != '/' && *path != '\0') + path++; + path++; + return path; +} + +void* FAT32FS::read_cluster(uint32_t cluster_start, uint32_t cluster_size, uint32_t cluster_count, uint32_t root_index){ + + uint32_t lba = cluster_start + ((root_index - 2) * cluster_size); + + kprintfv("Reading cluster(s) %i-%i, starting from %i (LBA %i) Address %x", root_index, root_index+cluster_count, cluster_start, lba, lba * 512); + + void* buffer = (char*)allocate_in_page(fs_page, cluster_count * cluster_size * 512, ALIGN_64B, true, true); + + if (cluster_count > 0){ + uint32_t next_index = root_index; + for (int i = 0; i < cluster_count; i++){ + kprintfv("Cluster %i = %x (%x)",i,next_index,(cluster_start + ((next_index - 2) * cluster_size)) * 512); + disk_read(buffer + (i * cluster_size * 512), cluster_start + ((next_index - 2) * cluster_size), cluster_size); + next_index = fat[next_index]; + if (next_index >= 0x0FFFFFF8) return buffer; + } + } + + return buffer; +} + +void FAT32FS::parse_longnames(f32longname entries[], uint16_t count, char* out){ + if (count == 0) return; + uint16_t total = ((5+6+2)*count) + 1; + uint16_t *filename = (uint16_t*)allocate_in_page(fs_page, total*2, ALIGN_64B, true, true); + uint16_t f = 0; + for (int i = count-1; i >= 0; i--){ + uint8_t *buffer = (uint8_t*)&entries[i]; + for (int j = 0; j < 5; j++){ + filename[f++] = (buffer[1+(j*2)] << 8) | buffer[1+(j*2) + 1]; + } + for (int j = 0; j < 6; j++){ + filename[f++] = (buffer[14+(j*2)] << 8) | buffer[1+(j*2) + 1]; + } + for (int j = 0; j < 2; j++){ + filename[f++] = (buffer[18+(j*2)] << 8) | buffer[1+(j*2) + 1]; + } + } + filename[f++] = '\0'; + utf16tochar(filename, out, f); + free_from_page(filename, total*2); +} + +void FAT32FS::parse_shortnames(f32file_entry* entry, char* out){ + int j = 0; + bool ext_found = false; + for (int i = 0; i < 11 && entry->filename[i]; i++){ + if (entry->filename[i] != ' ') + out[j++] = entry->filename[i]; + else if (!ext_found){ + out[j++] = '.'; + ext_found = true; + } + } + out[j++] = '\0'; +} + +void* FAT32FS::walk_directory(uint32_t cluster_count, uint32_t root_index, char *seek, f32_entry_handler handler) { + uint32_t cluster_size = mbs->sectors_per_cluster; + char *buffer = (char*)read_cluster(data_start_sector, cluster_size, cluster_count, root_index); + f32file_entry *entry = 0; + + for (uint64_t i = 0; i < cluster_count * cluster_size * 512;) { + if (buffer[i] == 0) return 0; + if (buffer[i] == 0xE5){ + i += sizeof(f32file_entry); + continue; + } + bool long_name = buffer[i + 0xB] == 0xF; + char *filename = (char*)allocate_in_page(fs_page, 255, ALIGN_64B, true, true); + if (long_name){ + uint8_t order; + f32longname *first_longname = (f32longname*)&buffer[i]; + uint16_t count = 0; + do { + i += sizeof(f32longname); + count++; + } while (buffer[i + 0xB] == 0xF); + parse_longnames(first_longname, count, filename); + } + entry = (f32file_entry *)&buffer[i]; + if (!long_name){ + parse_shortnames(entry, filename); + } + void *result = handler(this, entry, filename, seek); + free_from_page(filename, 255); + if (result) + return result; + i += sizeof(f32file_entry); + } + + return 0; +} + +void* FAT32FS::list_directory(uint32_t cluster_count, uint32_t root_index) { + uint32_t cluster_size = mbs->sectors_per_cluster; + char *buffer = (char*)read_cluster(data_start_sector, cluster_size, cluster_count, root_index); + f32file_entry *entry = 0; + void *list_buffer = (char*)allocate_in_page(fs_page, 0x1000 * cluster_count, ALIGN_64B, true, true); + uint32_t len = 0; + uint32_t count = 0; + + char *write_ptr = (char*)list_buffer + 4; + + for (uint64_t i = 0; i < cluster_count * cluster_size * 512;) { + if (buffer[i] == 0) break; + if (buffer[i] == 0xE5){ + i += sizeof(f32file_entry); + continue; + } + char c = buffer[i]; + count++; + bool long_name = buffer[i + 0xB] == 0xF; + char *filename = (char*)allocate_in_page(fs_page, 255, ALIGN_64B, true, true); + if (long_name){ + uint8_t order; + f32longname *first_longname = (f32longname*)&buffer[i]; + uint16_t count = 0; + do { + i += sizeof(f32longname); + count++; + } while (buffer[i + 0xB] == 0xF); + parse_longnames(first_longname, count, filename); + } + entry = (f32file_entry *)&buffer[i]; + if (!long_name){ + parse_shortnames(entry, filename); + } + char *f = filename; + while (*f) { + *write_ptr++ = *f; + f++; + } + *write_ptr++ = '\0'; + free_from_page(filename, 255); + i += sizeof(f32file_entry); + } + + *(uint32_t*)list_buffer = count; + + return list_buffer; +} + +void* FAT32FS::read_full_file(uint32_t cluster_start, uint32_t cluster_size, uint32_t cluster_count, uint64_t file_size, uint32_t root_index){ + + char *buffer = (char*)read_cluster(cluster_start, cluster_size, cluster_count, root_index); + + void *file = allocate_in_page(fs_page, file_size, ALIGN_64B, true, true); + + memcpy(file, (void*)buffer, file_size); + + return file; +} + +void FAT32FS::read_FAT(uint32_t location, uint32_t size, uint8_t count){ + fat = (uint32_t*)allocate_in_page(fs_page, size * count * 512, ALIGN_64B, true, true); + disk_read((void*)fat, location, size); + total_fat_entries = (size * count * 512) / 4; +} + +uint32_t FAT32FS::count_FAT(uint32_t first){ + uint32_t entry = fat[first]; + int count = 1; + while (entry < 0x0FFFFFF8){ + entry = fat[entry]; + count++; + } + return count; +} + +uint16_t read_unaligned16(const uint8_t *p) { + return (uint16_t)p[0] | ((uint16_t)p[1] << 8); +} + +#define MBS_NUM_SECTORS read_unaligned16(mbs8 + 0x13) + +bool FAT32FS::init(){ + fs_page = alloc_page(0x1000, true, true, false); + + mbs = (fat32_mbs*)allocate_in_page(fs_page, 512, ALIGN_64B, true, true); + + disk_read((void*)mbs, 0, 1); + + if (mbs->boot_signature != 0xAA55){ + kprintf("[fat32] Wrong boot signature %x",mbs->boot_signature); + return false; + } + if (mbs->signature != 0x29 && mbs->signature != 0x28){ + kprintf("[fat32 error] Wrong signature %x",mbs->signature); + return false; + } + + uint8_t *mbs8 = (uint8_t*)mbs; + + cluster_count = (MBS_NUM_SECTORS == 0 ? mbs->large_num_sectors : MBS_NUM_SECTORS)/mbs->sectors_per_cluster; + data_start_sector = mbs->reserved_sectors + (mbs->sectors_per_fat * mbs->number_of_fats); + + if (mbs->first_cluster_of_root_directory > cluster_count){ + kprintf("[fat32 error] root directory cluster not found"); + return false; + } + + bytes_per_sector = read_unaligned16(mbs8 + 0xB); + + kprintf("FAT32 Volume uses %i cluster size", bytes_per_sector); + kprintf("Data start at %x",data_start_sector*512); + + read_FAT(mbs->reserved_sectors, mbs->sectors_per_fat, mbs->number_of_fats); + + return true; +} + +void* FAT32FS::read_entry_handler(FAT32FS *instance, f32file_entry *entry, char *filename, char *seek) { + if (entry->flags.volume_id) return 0; + + bool is_last = *instance->advance_path(seek) == '\0'; + if (!is_last && strstart(seek, filename, true) == 0) return 0; + if (is_last && strcmp(seek, filename, true) != 0) return 0; + + uint32_t filecluster = (entry->hi_first_cluster << 16) | entry->lo_first_cluster; + uint32_t bps = instance->bytes_per_sector; + uint32_t spc = instance->mbs->sectors_per_cluster; + uint32_t bpc = bps * spc; + uint32_t count = entry->filesize > 0 ? ((entry->filesize + bpc - 1) / bpc) : instance->count_FAT(filecluster); + + return entry->flags.directory + ? instance->walk_directory(count, filecluster, instance->advance_path(seek), read_entry_handler) + : instance->read_full_file(instance->data_start_sector, instance->mbs->sectors_per_cluster, count, entry->filesize, filecluster); +} + +void* FAT32FS::read_file(char *path){ + path = advance_path(path); + + uint32_t count = count_FAT(mbs->first_cluster_of_root_directory); + return walk_directory(count, mbs->first_cluster_of_root_directory, path, read_entry_handler); +} + +void* FAT32FS::list_entries_handler(FAT32FS *instance, f32file_entry *entry, char *filename, char *seek) { + + if (entry->flags.volume_id) return 0; + if (strstart(seek, filename, true) == 0) return 0; + + bool is_last = *instance->advance_path(seek) == '\0'; + + uint32_t filecluster = (entry->hi_first_cluster << 16) | entry->lo_first_cluster; + + uint32_t bps = instance->bytes_per_sector; + uint32_t spc = instance->mbs->sectors_per_cluster; + uint32_t bpc = bps * spc; + uint32_t count = instance->count_FAT(filecluster); + + if (is_last) return instance->list_directory(count, filecluster); + if (entry->flags.directory) return instance->walk_directory(count, filecluster, instance->advance_path(seek), list_entries_handler); + return 0; +} + +string_list* FAT32FS::list_contents(char *path){ + path = advance_path(path); + + uint32_t count = count_FAT(mbs->first_cluster_of_root_directory); + return (string_list*)walk_directory(count, mbs->first_cluster_of_root_directory, path, list_entries_handler); +} \ No newline at end of file diff --git a/kernel/filesystem/fat32.hpp b/kernel/filesystem/fat32.hpp new file mode 100644 index 00000000..b142535e --- /dev/null +++ b/kernel/filesystem/fat32.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include "types.h" +#include "std/string.h" + +typedef struct fat32_mbs { + uint8_t jumpboot[3];//3 + char fsname[8];//8 + uint16_t bytes_per_sector; + uint8_t sectors_per_cluster; + uint16_t reserved_sectors; + uint8_t number_of_fats; + uint16_t root_directory_entries; + uint16_t num_sectors;//Could be 0, in which case it's stored in large_num_sectors + uint8_t media_descriptor_type; + uint16_t num_sectors_fat;//Used only in 12/16 + uint16_t num_sectors_track; + uint16_t num_heads; + uint32_t num_hidden_sectors; + uint32_t large_num_sectors; + + uint32_t sectors_per_fat; + uint16_t flags; + uint16_t fat_version;//high major low minor + uint32_t first_cluster_of_root_directory; + uint16_t fsinfo_sector; + uint16_t backup_boot_sector; + uint8_t reserved[12]; + uint8_t drive_number; + uint8_t reserved_flags; + uint8_t signature;//0x28 or 0x29 + uint32_t volume_id; + char volume_label[11]; + char system_identifier[8]; + uint8_t boot_code[420]; + uint16_t boot_signature; +}__attribute__((packed)) fat32_mbs; + +typedef struct f32file_entry { + char filename[11]; + struct { + uint8_t read_only: 1; + uint8_t hidden: 1; + uint8_t system: 1; + uint8_t volume_id: 1; + uint8_t directory: 1; + uint8_t archive: 1; + uint8_t long_filename: 1; + } flags; + + uint8_t rsvd;//Can be used for case sensitivity + + uint8_t create10msincrement; + uint16_t create_timestamp;//Multiply seconds by 2 + uint16_t create_date; + uint16_t last_accessed_date; + uint16_t hi_first_cluster; + uint16_t last_modified_time; + uint16_t last_modified_date; + uint16_t lo_first_cluster; + uint32_t filesize; + +}__attribute__((packed)) f32file_entry; + +typedef struct f32longname { + uint8_t order; + uint16_t name1[5]; + uint8_t attribute; + uint8_t long_type; + uint8_t checksum; + uint16_t name2[6]; + uint16_t rsvd2; + uint16_t name3[2]; +}__attribute__((packed)) f32longname; + +class FAT32FS; + +typedef void* (*f32_entry_handler)(FAT32FS *instance, f32file_entry*, char *filename, char *seek); + +class FAT32FS { +public: + bool init(); + void* read_file(char *path); + string_list* list_contents(char *path); + +protected: + void* read_full_file(uint32_t cluster_start, uint32_t cluster_size, uint32_t cluster_count, uint64_t file_size, uint32_t root_index); + void read_FAT(uint32_t location, uint32_t size, uint8_t count); + uint32_t count_FAT(uint32_t first); + void* list_directory(uint32_t cluster_count, uint32_t root_index); + void* walk_directory(uint32_t cluster_count, uint32_t root_index, char *seek, f32_entry_handler handler); + void* read_cluster(uint32_t cluster_start, uint32_t cluster_size, uint32_t cluster_count, uint32_t root_index); + char* advance_path(char *path); + + fat32_mbs* mbs; + void *fs_page; + uint32_t cluster_count; + uint32_t data_start_sector; + uint32_t* fat; + uint32_t total_fat_entries; + uint16_t bytes_per_sector; + + static void* read_entry_handler(FAT32FS *instance, f32file_entry *entry, char *filename, char *seek); + static void* list_entries_handler(FAT32FS *instance, f32file_entry *entry, char *filename, char *seek); + + void parse_longnames(f32longname entries[], uint16_t count, char* out); + void parse_shortnames(f32file_entry* entry, char* out); + + bool verbose = false; +}; \ No newline at end of file diff --git a/kernel/filesystem/sdhci.cpp b/kernel/filesystem/sdhci.cpp new file mode 100644 index 00000000..917196ca --- /dev/null +++ b/kernel/filesystem/sdhci.cpp @@ -0,0 +1,302 @@ +#include "sdhci.hpp" +#include "console/kio.h" +#include "hw/hw.h" +#include "mailbox/mailbox.h" +#include "syscalls/syscalls.h" +#include "memory/mmu.h" +#include "std/memfunctions.h" +#include "async.h" + +#define CMD_INDEX(x) ((x) << 8) +#define RESP_TYPE(x) (x) +#define CRC_ENABLE (1 << 3) +#define IDX_ENABLE (1 << 4) +#define IS_DATA (1 << 5) + +#define SEND_CID (CMD_INDEX(2) | RESP_TYPE(1) | CRC_ENABLE) +#define IF_COND (CMD_INDEX(8) | RESP_TYPE(2) | CRC_ENABLE | IDX_ENABLE) +#define RCA (CMD_INDEX(3) | RESP_TYPE(2) | CRC_ENABLE) +#define APP (CMD_INDEX(55) | RESP_TYPE(2) | CRC_ENABLE | IDX_ENABLE) +#define SELECT_CARD (CMD_INDEX(7) | RESP_TYPE(3) | CRC_ENABLE | IDX_ENABLE) +#define OCR (CMD_INDEX(41) | RESP_TYPE(2)) +#define READ_ONE (CMD_INDEX(17) | RESP_TYPE(2) | CRC_ENABLE | IS_DATA) +#define READ_MULTIPLE (CMD_INDEX(18) | RESP_TYPE(2) | CRC_ENABLE | IS_DATA) +#define STOP_TRANSMISSION (CMD_INDEX(12) | RESP_TYPE(2) | CRC_ENABLE) +#define SET_BLOCKLEN (CMD_INDEX(16) | RESP_TYPE(2) | CRC_ENABLE) + +#define kprintfv(fmt, ...) \ + ({ \ + if (verbose){\ + uint64_t _args[] = { __VA_ARGS__ }; \ + kprintf_args_raw((fmt), _args, sizeof(_args) / sizeof(_args[0])); \ + }\ + }) + +void SDHCI::enable_verbose(){ + verbose = true; +} + +uint32_t SDHCI::clock_divider(uint32_t target_rate) { + uint32_t target_div = 1; + + if (target_rate <= clock_rate) { + target_div = clock_rate / target_rate; + + if (clock_rate % target_rate) { + target_div = 0; + } + } + + int div = -1; + for (int fb = 31; fb >= 0; fb--) { + uint32_t bt = (1 << fb); + + if (target_div & bt) { + div = fb; + target_div &= ~(bt); + + if (target_div) { + div++; + } + + break; + } + } + + if (div == -1) + div = 31; + + if (div >= 32) + div = 31; + + if (div != 0) + div = (1 << (div - 1)); + + if (div >= 0x400) + div = 0x3FF; + + uint32_t freq = div & 0xff; + uint32_t hi = (div >> 8) & 0x3; + uint32_t ret = (freq << 8) | (hi << 6) | (0 << 5); + + return ret; +} + +bool SDHCI::switch_clock_rate(uint32_t target_rate) { + uint32_t div = clock_divider(target_rate); + + if (!wait(®s->status,0b11, false, 2000)) return false; + + regs->ctrl1 &= ~(1 << 2); + + delay(3); + + regs->ctrl1 = (regs->ctrl1 | div) & ~0xFFE0; + + delay(3); + + regs->ctrl1 |= (1 << 2); + + delay(3); + + return true; +} + +volatile uint32_t mbox[8] __attribute__((aligned(16))) = { + 32, + 0, + 0x00030002, 8, 0, 1, 0,//Request clock rate for 1 (EMMC) + 0 +}; + +bool SDHCI::setup_clock(){ + regs->ctrl2 = 0; + + if (!mailbox_call(mbox,8)) return false; + + clock_rate = mbox[6]; + + regs->ctrl1 |= 1; + regs->ctrl1 |= clock_divider(400000); + regs->ctrl1 &= ~(0xf << 16); + regs->ctrl1 |= (11 << 16); + regs->ctrl1 |= (1 << 2); + + if (!wait(®s->ctrl1, (1 << 1), true, 2000)) return false; + + delay(30); + + regs->ctrl1 |= 4; + + delay(30); + + return true; +} + +bool SDHCI::init() { + if (!SDHCI_BASE) return false; + + register_device_memory(SDHCI_BASE, SDHCI_BASE); + + regs = (sdhci_regs*)SDHCI_BASE; + + regs->ctrl1 |= (1 << 24);//Reset + if (!wait(®s->ctrl1,(1 << 24), false, 2000)) return false; + + if (RPI_BOARD >= 4){ + regs->ctrl0 |= 0x0F << 8;//VDD1 bus power + delay(3); + } + + kprintfv("[SDHCI] Controller reset"); + + setup_clock(); + + kprintf("[SDHCI] Controller ready"); + + regs->interrupt = 0; + regs->irpt_en = 0xFFFFFFFF; + regs->irpt_mask = 0xFFFFFFFF; + + delay(203); + + if (!issue_command(0, 0)){ + kprintf("[SDHCI error] Failed setting to idle"); + return false; + } + kprintfv("[SDHCI] Idle"); + + switch_clock_rate(25000000); + + bool v2_card = 0; + if (!issue_command(IF_COND, 0)){ + if (!(regs->interrupt & 0x10000)){ + kprintf("[SDHCI error] IFCOND error"); + return false; + } + kprintfv("[SDHCI] Timeout on IFCOND. Defaulting to V1"); + } else { + if ((regs->resp0 & 0xFF) != 0xAA) { + kprintf("[SDHCI error] IFCOND pattern mismatch"); + return false; + } + v2_card = true; + } + + kprintfv("[SDHCI] V2 = %i",v2_card); + + while (true){ + if (!issue_app_command(OCR, 0xFF8000 | (v2_card << 30))){ + kprintf("[SDHCI error] Get OCR Failed"); + return false; + } + if (regs->resp0 & (1 << 31)) break; + else delay(500); + } + + kprintfv("[SDHCI] OCR %x",regs->resp0); + + delay(1000); + + if (!issue_command(SEND_CID, 0)){ + kprintf("[SDHCI error] Failed requesting card id"); + return false; + } + kprintf("[SDHCI] Card ID: %x.%x.%x.%x",regs->resp0, regs->resp1,regs->resp2,regs->resp3); + if (!issue_command(RCA, 0)){ + kprintf("[SDHCI error] Failed to send relative address"); + return false; + } + + rca = (regs->resp0 >> 16) & 0xFFFF; + kprintfv("[SDHCI] RCA %x",rca); + + if (!issue_command(SELECT_CARD, rca << 16)){ + kprintf("[SDHCI error] Failed to select card"); + return false; + } + + if (!issue_command(SET_BLOCKLEN, 512)){ + kprintf("[SDHCI error] Failed to set block length"); + return false; + } + + return true; +} + +bool SDHCI::issue_app_command(uint32_t cmd, uint32_t arg, uint32_t flags) { + if (issue_command(APP, 0, 1 << 3)) + return issue_command(cmd, arg); + + return false; +} + +bool SDHCI::issue_command(uint32_t cmd, uint32_t arg, uint32_t flags) { + + if (!wait(®s->status, 0b11, false, 2000)) { + kprintf("[SDHCI error] Timeout waiting for CMD/DAT inhibit"); + return false; + } + + regs->interrupt = 0xFFFFFFFF; + + regs->arg1 = arg; + regs->cmd_transfmode = (cmd << 16) | flags; + + kprintfv("[SDHCI] Sent command %b.",(cmd << 16) | flags); + + if (!wait(®s->interrupt,0x1, true, 2000)) { + kprintf("[SDHCI warning] Issue command timeout %x",regs->interrupt); + return false; + } + + kprintfv("[SDHCI] Command finished %x",regs->interrupt); + + if (regs->interrupt & 0x8000) return false;//Error + if (!(regs->interrupt & 0x0001)) return false;//No finish + + return true; +} + +bool SDHCI::read(void *buffer, uint32_t sector, uint32_t count){ + bool multiple = count > 1; + regs->blksize_count = (count << 16) | 512; + uint32_t command = multiple ? READ_MULTIPLE : READ_ONE; + uint32_t flags = multiple ? 0b110110 : 0b010000; + for (int i = 5; i >= 0; i--){ + //TODO: Byte addressing works here, instead of block addressing. Not sure that's normal or if it's card-specific + if (issue_command(command, sector * 512, flags)) break; + if (i == 0) { kprintf("[SDHCI error] read request timeout"); return false; } + delay(500); + } + + uint32_t* dest = (uint32_t*)buffer; + for (uint32_t i = 0; i < count; i++) { + if (!wait(®s->interrupt,(1 << 5), true, 2000)){ + kprintf("[SDHCI error] Read operation timed out on block %i %x",i,regs->interrupt); + memset(buffer,0,count * 128); + return false; + } + + regs->interrupt = 0xFFFFFFFF; + + for (int j = 0; j < 128; j++) + dest[(i * 128) + j] = regs->data; + + if (regs->interrupt & (1 << 1)) + break; + } + + if (multiple) { + if (!wait(®s->interrupt, (1 << 1), true, 2000)) { + kprintf("[SDHCI error] Timed out waiting for DATA_DONE"); + return false; + } + regs->interrupt = 0xFFFFFFFF; + } + + return true; +} + +//TODO: Write (CMD24 block, CMD25 multiple). Read can be generalized. +//TODO: DMA \ No newline at end of file diff --git a/kernel/filesystem/sdhci.hpp b/kernel/filesystem/sdhci.hpp new file mode 100644 index 00000000..c2ba2037 --- /dev/null +++ b/kernel/filesystem/sdhci.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include "types.h" + +typedef struct sdhci_regs { + uint32_t arg2; + uint32_t blksize_count; + uint32_t arg1; + uint32_t cmd_transfmode; + uint32_t resp0; + uint32_t resp1; + uint32_t resp2; + uint32_t resp3; + uint32_t data; + uint32_t status; + uint32_t ctrl0; + uint32_t ctrl1; + uint32_t interrupt; + uint32_t irpt_mask; + uint32_t irpt_en; + uint32_t ctrl2; + uint32_t __reserved[0x2F]; + uint32_t slotisr_ver; +} sdhci_regs; + +class SDHCI { +public: + bool init(); + void write(void *buffer, uint32_t sector, uint32_t count); + bool read(void *buffer, uint32_t sector, uint32_t count); + void enable_verbose(); +private: + sdhci_regs* regs; + bool issue_command(uint32_t cmd_index, uint32_t arg, uint32_t flags = 0); + bool issue_app_command(uint32_t cmd, uint32_t arg, uint32_t flags = 0); + bool setup_clock(); + uint32_t clock_divider(uint32_t target_rate); + bool switch_clock_rate(uint32_t target_rate); + uint32_t clock_rate; + uint32_t rca; + bool verbose; +}; \ No newline at end of file diff --git a/kernel/filesystem/virtio_blk_pci.c b/kernel/filesystem/virtio_blk_pci.c index 88e0aab4..9df79f8c 100644 --- a/kernel/filesystem/virtio_blk_pci.c +++ b/kernel/filesystem/virtio_blk_pci.c @@ -40,7 +40,7 @@ void vblk_disk_verbose(){ #define kprintfv(fmt, ...) \ ({ \ - if (mmu_verbose){\ + if (blk_disk_enable_verbose){\ uint64_t _args[] = { __VA_ARGS__ }; \ kprintf_args_raw((fmt), _args, sizeof(_args) / sizeof(_args[0])); \ }\ diff --git a/kernel/filesystem/virtio_blk_pci.h b/kernel/filesystem/virtio_blk_pci.h index 91333df4..d67c17d5 100644 --- a/kernel/filesystem/virtio_blk_pci.h +++ b/kernel/filesystem/virtio_blk_pci.h @@ -2,7 +2,14 @@ #include "types.h" +#ifdef __cplusplus +extern "C" { +#endif +//TODO port to c++ bool vblk_find_disk(); void vblk_disk_verbose(); void vblk_write(const void *buffer, uint32_t sector, uint32_t count); -void vblk_read(void *buffer, uint32_t sector, uint32_t count); \ No newline at end of file +void vblk_read(void *buffer, uint32_t sector, uint32_t count); +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/kernel/gpio.c b/kernel/gpio.c new file mode 100644 index 00000000..b8ae7656 --- /dev/null +++ b/kernel/gpio.c @@ -0,0 +1,14 @@ +#include "gpio.h" +#include "hw/hw.h" +#include "async.h" +#include "memory/memory_access.h" + +void reset_gpio(){ + write32(GPIO_BASE + GPIO_PIN_BASE + 0x94, 0x0); + delay(150); +} + +void enable_gpio_pin(uint8_t pin){ + uint32_t v = read32(GPIO_BASE + GPIO_PIN_BASE + 0x98); + write32(GPIO_BASE + GPIO_PIN_BASE + 0x98, v | (1 << pin)); +} \ No newline at end of file diff --git a/kernel/gpio.h b/kernel/gpio.h new file mode 100644 index 00000000..8b50b0a0 --- /dev/null +++ b/kernel/gpio.h @@ -0,0 +1,6 @@ +#pragma once + +#include "types.h" + +void reset_gpio(); +void enable_gpio_pin(uint8_t pin); \ No newline at end of file diff --git a/kernel/graph/drivers/ramfb_driver/ramfb.cpp b/kernel/graph/drivers/ramfb_driver/ramfb.cpp index dec71dbb..ad133dc0 100644 --- a/kernel/graph/drivers/ramfb_driver/ramfb.cpp +++ b/kernel/graph/drivers/ramfb_driver/ramfb.cpp @@ -98,8 +98,7 @@ void RamFBGPUDriver::flush(){ } void RamFBGPUDriver::clear(color color){ - fb_clear((uint32_t*)back_framebuffer, screen_size.width, screen_size.height, color); - mark_dirty(0,0,screen_size.width,screen_size.height); + fb_clear((uint32_t*)back_framebuffer, color); } void RamFBGPUDriver::draw_pixel(uint32_t x, uint32_t y, color color){ @@ -109,17 +108,14 @@ void RamFBGPUDriver::draw_pixel(uint32_t x, uint32_t y, color color){ void RamFBGPUDriver::fill_rect(uint32_t x, uint32_t y, uint32_t width, uint32_t height, color color){ fb_fill_rect((uint32_t*)back_framebuffer, x, y, width, height, color); - mark_dirty(x,y,width,height); } void RamFBGPUDriver::draw_line(uint32_t x0, uint32_t y0, uint32_t x1,uint32_t y1, color color){ gpu_rect rect = fb_draw_line((uint32_t*)framebuffer, x0, y0, x1, y1, color); - mark_dirty(rect.point.x,rect.point.y,rect.size.width,rect.size.height); } void RamFBGPUDriver::draw_char(uint32_t x, uint32_t y, char c, uint32_t scale, uint32_t color){ fb_draw_char((uint32_t*)back_framebuffer, x, y, c, scale, color); - mark_dirty(x,y,8*scale,8*scale); } gpu_size RamFBGPUDriver::get_screen_size(){ @@ -128,45 +124,8 @@ gpu_size RamFBGPUDriver::get_screen_size(){ void RamFBGPUDriver::draw_string(string s, uint32_t x, uint32_t y, uint32_t scale, uint32_t color){ gpu_size drawn_string = fb_draw_string((uint32_t*)back_framebuffer, s, x, y, scale, color); - mark_dirty(x,y,drawn_string.width,drawn_string.height); } uint32_t RamFBGPUDriver::get_char_size(uint32_t scale){ return fb_get_char_size(scale); -} - -int RamFBGPUDriver::try_merge(gpu_rect* a, gpu_rect* b) { - uint32_t ax2 = a->point.x + a->size.width; - uint32_t ay2 = a->point.y + a->size.height; - uint32_t bx2 = b->point.x + b->size.width; - uint32_t by2 = b->point.y + b->size.height; - - if (a->point.x > bx2 || b->point.x > ax2 || a->point.y > by2 || b->point.y > ay2) - return 0; - - uint32_t min_x = a->point.x < b->point.x ? a->point.x : b->point.x; - uint32_t min_y = a->point.y < b->point.y ? a->point.y : b->point.y; - uint32_t max_x = ax2 > bx2 ? ax2 : bx2; - uint32_t max_y = ay2 > by2 ? ay2 : by2; - - a->point.x = min_x; - a->point.y = min_y; - a->size.width = max_x - min_x; - a->size.height = max_y - min_y; - - return 1; -} - -void RamFBGPUDriver::mark_dirty(uint32_t x, uint32_t y, uint32_t w, uint32_t h) { - gpu_rect new_rect = { x, y, w, h }; - - for (uint32_t i = 0; i < dirty_count; i++) { - if (try_merge(&dirty_rects[i], &new_rect)) - return; - } - - if (dirty_count < MAX_DIRTY_RECTS_RFB) - dirty_rects[dirty_count++] = new_rect; - else - full_redraw = true; } \ No newline at end of file diff --git a/kernel/graph/drivers/ramfb_driver/ramfb.hpp b/kernel/graph/drivers/ramfb_driver/ramfb.hpp index c0344b65..5d8352d6 100644 --- a/kernel/graph/drivers/ramfb_driver/ramfb.hpp +++ b/kernel/graph/drivers/ramfb_driver/ramfb.hpp @@ -2,8 +2,6 @@ #include "../gpu_driver.hpp" -#define MAX_DIRTY_RECTS_RFB 64 - class RamFBGPUDriver : public GPUDriver { public: static RamFBGPUDriver* try_init(gpu_size preferred_screen_size); @@ -28,10 +26,5 @@ class RamFBGPUDriver : public GPUDriver { uintptr_t back_framebuffer; uint64_t framebuffer_size; gpu_size screen_size; - gpu_rect dirty_rects[MAX_DIRTY_RECTS_RFB]; - uint32_t dirty_count = 0; - bool full_redraw = false; - int try_merge(gpu_rect* a, gpu_rect* b); - void mark_dirty(uint32_t x, uint32_t y, uint32_t w, uint32_t h); uint32_t stride; }; \ No newline at end of file diff --git a/kernel/graph/drivers/videocore/videocore.cpp b/kernel/graph/drivers/videocore/videocore.cpp new file mode 100644 index 00000000..44c83cc2 --- /dev/null +++ b/kernel/graph/drivers/videocore/videocore.cpp @@ -0,0 +1,139 @@ +#include "videocore.hpp" +#include "fw/fw_cfg.h" +#include "memory/kalloc.h" +#include "console/kio.h" +#include "graph/font8x8_bridge.h" +#include "ui/draw/draw.h" +#include "memory/memory_access.h" +#include "std/std.hpp" +#include "std/memfunctions.h" +#include "mailbox/mailbox.h" +#include "math/math.h" +#include "memory/mmu.h" + +#define RGB_FORMAT_XRGB8888 ((uint32_t)('X') | ((uint32_t)('R') << 8) | ((uint32_t)('2') << 16) | ((uint32_t)('4') << 24)) + +VideoCoreGPUDriver* VideoCoreGPUDriver::try_init(gpu_size preferred_screen_size){ + VideoCoreGPUDriver* driver = new VideoCoreGPUDriver(); + if (driver->init(preferred_screen_size)) + return driver; + delete driver; + return nullptr; +} + +volatile uint32_t rmbox[36] __attribute__((aligned(16))) = { + 25 * 4,// Buf size + 0,// Request. Code 0 + 0x00048003, 8, 0, 640, 480,// Physical size + 0x00048004, 8, 0, 0, 0,// Virtual size + 0x00048005, 4, 0, 32,// Depth + 0x00040008, 4, 0, 0,//Pitch + 0x00048006, 4, 0, 0, //BGR + 0,// End +};//TODO: Screen resolution seems fixed at 640x480 (on QEMU at least). Setting it to anything else hangs the system + +volatile uint32_t fb_mbox[36] __attribute__((aligned(16))) = { + 32, 0, + 0x00040001, 8, 0, 16, 0, + 0 +}; + +bool VideoCoreGPUDriver::init(gpu_size preferred_screen_size){ + kprintf("Initializing VideoCore GPU"); + if (mailbox_call(rmbox, 8)) { + uint32_t phys_w = rmbox[5]; + uint32_t phys_h = rmbox[6]; + uint32_t virt_w = rmbox[10]; + uint32_t virt_h = rmbox[11]; + uint32_t depth = rmbox[15]; + stride = rmbox[19]; + + bpp = depth/8; + + screen_size = (gpu_size){phys_w,phys_h}; + kprintf("Size %ix%i (%ix%i) (%ix%i) | %i (%i)",phys_w,phys_h,virt_w,virt_h,screen_size.width,screen_size.height,depth, stride); + + fb_set_stride(bpp * screen_size.width); + fb_set_bounds(screen_size.width,screen_size.height); + if (!mailbox_call(fb_mbox, 8)){ + kprintf("Error"); + return false; + } + framebuffer = fb_mbox[5]; + size_t fb_size = fb_mbox[6]; + page = alloc_page(0x1000, true, true, false); + back_framebuffer = (uintptr_t)allocate_in_page(page, fb_size, ALIGN_16B, true, true); + kprintf("Framebuffer allocated to %x. BPP %i. Stride %i",framebuffer, bpp, stride/bpp); + //TODO: Mark the fb memory as used in the page allocator manually + for (size_t i = framebuffer; i < framebuffer + fb_size; i += GRANULE_4KB) + register_device_memory(i,i); + return true; + } + return false; +} + +void VideoCoreGPUDriver::flush(){ + if (full_redraw) { + memcpy((void*)framebuffer, (void*)back_framebuffer, screen_size.width * screen_size.height * bpp); + dirty_count = 0; + full_redraw = false; + return; + } + + volatile uint32_t* fb = (volatile uint32_t*)framebuffer; + volatile uint32_t* bfb = (volatile uint32_t*)back_framebuffer; + + for (uint32_t i = 0; i < dirty_count; i++) { + gpu_rect r = dirty_rects[i]; + + for (uint32_t y = 0; y < r.size.height; y++) { + uint32_t dest_y = r.point.y + y; + if (dest_y >= screen_size.height) break; + + uint32_t* dst = (uint32_t*)&fb[dest_y * (stride / 4) + r.point.x]; + uint32_t* src = (uint32_t*)&bfb[dest_y * (stride / 4) + r.point.x]; + + uint32_t copy_width = r.size.width; + if (r.point.x + copy_width > screen_size.width) + copy_width = screen_size.width - r.point.x; + + memcpy(dst, src, copy_width * sizeof(uint32_t)); + } + } + + full_redraw = false; + dirty_count = 0; +} + +void VideoCoreGPUDriver::clear(color color){ + fb_clear((uint32_t*)back_framebuffer, color); +} + +void VideoCoreGPUDriver::draw_pixel(uint32_t x, uint32_t y, color color){ + fb_draw_pixel((uint32_t*)back_framebuffer, x, y, color); + mark_dirty(x,y,1,1); +} + +void VideoCoreGPUDriver::fill_rect(uint32_t x, uint32_t y, uint32_t width, uint32_t height, color color){ + fb_fill_rect((uint32_t*)back_framebuffer, x, y, width, height, color); +} + +void VideoCoreGPUDriver::draw_line(uint32_t x0, uint32_t y0, uint32_t x1,uint32_t y1, color color){ + fb_draw_line((uint32_t*)back_framebuffer, x0, y0, x1, y1, color); +} + +void VideoCoreGPUDriver::draw_char(uint32_t x, uint32_t y, char c, uint32_t scale, uint32_t color){ + fb_draw_char((uint32_t*)back_framebuffer, x, y, c, scale, color); +} + +gpu_size VideoCoreGPUDriver::get_screen_size(){ + return screen_size; +} + +void VideoCoreGPUDriver::draw_string(string s, uint32_t x, uint32_t y, uint32_t scale, uint32_t color){ + fb_draw_string((uint32_t*)back_framebuffer, s, x, y, scale, color); +} + +uint32_t VideoCoreGPUDriver::get_char_size(uint32_t scale){ + return fb_get_char_size(max(1,scale-1));//TODO: Screen resolution seems fixed at 640x480 (on QEMU at least). So we make the font smaller +} \ No newline at end of file diff --git a/kernel/graph/drivers/videocore/videocore.hpp b/kernel/graph/drivers/videocore/videocore.hpp new file mode 100644 index 00000000..3a703551 --- /dev/null +++ b/kernel/graph/drivers/videocore/videocore.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "../gpu_driver.hpp" + +class VideoCoreGPUDriver : public GPUDriver { +public: + static VideoCoreGPUDriver* try_init(gpu_size preferred_screen_size); + VideoCoreGPUDriver(){} + bool init(gpu_size preferred_screen_size) override; + + void flush() override; + + void clear(color color) override; + void draw_pixel(uint32_t x, uint32_t y, color color) override; + void fill_rect(uint32_t x, uint32_t y, uint32_t width, uint32_t height, color color) override; + void draw_line(uint32_t x0, uint32_t y0, uint32_t x1,uint32_t y1, color color) override; + void draw_char(uint32_t x, uint32_t y, char c, uint32_t scale, uint32_t color) override; + gpu_size get_screen_size() override; + void draw_string(string s, uint32_t x, uint32_t y, uint32_t scale, uint32_t color) override; + uint32_t get_char_size(uint32_t scale) override; + ~VideoCoreGPUDriver() = default; + +private: + gpu_size screen_size; + uintptr_t framebuffer; + uintptr_t back_framebuffer; + + void* page; + + uint8_t bpp; + uint32_t stride; +}; \ No newline at end of file diff --git a/kernel/graph/drivers/virtio_gpu_pci/virtio_gpu_pci.cpp b/kernel/graph/drivers/virtio_gpu_pci/virtio_gpu_pci.cpp index d75e7fba..f9c440e7 100644 --- a/kernel/graph/drivers/virtio_gpu_pci/virtio_gpu_pci.cpp +++ b/kernel/graph/drivers/virtio_gpu_pci/virtio_gpu_pci.cpp @@ -54,6 +54,8 @@ bool VirtioGPUDriver::init(gpu_size preferred_screen_size){ } fb_set_stride(screen_size.width * BPP); + + kprintf("Stride %i",screen_size.width * BPP); framebuffer_size = screen_size.width * screen_size.height * BPP; framebuffer_size = (framebuffer_size); @@ -385,58 +387,8 @@ void VirtioGPUDriver::flush() { return; } -int VirtioGPUDriver::try_merge(gpu_rect* a, gpu_rect* b) { - uint32_t ax2 = a->point.x + a->size.width; - uint32_t ay2 = a->point.y + a->size.height; - uint32_t bx2 = b->point.x + b->size.width; - uint32_t by2 = b->point.y + b->size.height; - - if (a->point.x > bx2 || b->point.x > ax2 || a->point.y > by2 || b->point.y > ay2) - return 0; - - uint32_t min_x = a->point.x < b->point.x ? a->point.x : b->point.x; - uint32_t min_y = a->point.y < b->point.y ? a->point.y : b->point.y; - uint32_t max_x = ax2 > bx2 ? ax2 : bx2; - uint32_t max_y = ay2 > by2 ? ay2 : by2; - - a->point.x = min_x; - a->point.y = min_y; - a->size.width = max_x - min_x; - a->size.height = max_y - min_y; - - return 1; -} - -void VirtioGPUDriver::mark_dirty(uint32_t x, uint32_t y, uint32_t w, uint32_t h) { - if (x >= screen_size.width || y >= screen_size.height) - return; - - if (x + w > screen_size.width) - w = screen_size.width - x; - - if (y + h > screen_size.height) - h = screen_size.height - y; - - if (w == 0 || h == 0) - return; - - gpu_rect new_rect = { x, y, w, h }; - - for (uint32_t i = 0; i < dirty_count; i++) { - if (try_merge(&dirty_rects[i], &new_rect)) - return; - } - - if (dirty_count < MAX_DIRTY_RECTS_VGP) - dirty_rects[dirty_count++] = new_rect; - else - full_redraw = true; -} - - void VirtioGPUDriver::clear(uint32_t color) { - fb_clear((uint32_t*)framebuffer, screen_size.width, screen_size.height, color); - mark_dirty(0,0,screen_size.width,screen_size.height); + fb_clear((uint32_t*)framebuffer, color); } void VirtioGPUDriver::draw_pixel(uint32_t x, uint32_t y, color color){ @@ -446,22 +398,18 @@ void VirtioGPUDriver::draw_pixel(uint32_t x, uint32_t y, color color){ void VirtioGPUDriver::fill_rect(uint32_t x, uint32_t y, uint32_t width, uint32_t height, color color){ fb_fill_rect((uint32_t*)framebuffer, x, y, width, height, color); - mark_dirty(x,y,width,height); } void VirtioGPUDriver::draw_line(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, color color){ - gpu_rect rect = fb_draw_line((uint32_t*)framebuffer, x0, y0, x1, y1, color); - mark_dirty(rect.point.x,rect.point.y,rect.size.width,rect.size.height); + fb_draw_line((uint32_t*)framebuffer, x0, y0, x1, y1, color); } void VirtioGPUDriver::draw_char(uint32_t x, uint32_t y, char c, uint32_t scale, uint32_t color){ fb_draw_char((uint32_t*)framebuffer, x, y, c, scale, color); - mark_dirty(x,y,8*scale,8*scale); } void VirtioGPUDriver::draw_string(string s, uint32_t x, uint32_t y, uint32_t scale, uint32_t color){ - gpu_size drawn_string = fb_draw_string((uint32_t*)framebuffer, s, x, y, scale, color); - mark_dirty(x,y,drawn_string.width,drawn_string.height); + fb_draw_string((uint32_t*)framebuffer, s, x, y, scale, color); } uint32_t VirtioGPUDriver::get_char_size(uint32_t scale){ diff --git a/kernel/graph/drivers/virtio_gpu_pci/virtio_gpu_pci.hpp b/kernel/graph/drivers/virtio_gpu_pci/virtio_gpu_pci.hpp index a97992aa..47341c89 100644 --- a/kernel/graph/drivers/virtio_gpu_pci/virtio_gpu_pci.hpp +++ b/kernel/graph/drivers/virtio_gpu_pci/virtio_gpu_pci.hpp @@ -3,8 +3,6 @@ #include "virtio/virtio_pci.h" #include "../gpu_driver.hpp" -#define MAX_DIRTY_RECTS_VGP 64 - class VirtioGPUDriver : public GPUDriver { public: static VirtioGPUDriver* try_init(gpu_size preferred_screen_size); @@ -35,12 +33,6 @@ class VirtioGPUDriver : public GPUDriver { bool set_scanout(); bool transfer_to_host(gpu_rect rect); - gpu_rect dirty_rects[MAX_DIRTY_RECTS_VGP]; - uint32_t dirty_count = 0; - bool full_redraw = false; - int try_merge(gpu_rect* a, gpu_rect* b); - void mark_dirty(uint32_t x, uint32_t y, uint32_t w, uint32_t h); - bool scanout_found; uint64_t scanout_id; }; \ No newline at end of file diff --git a/kernel/graph/graphics.cpp b/kernel/graph/graphics.cpp index c0ca916c..c59fa1ac 100644 --- a/kernel/graph/graphics.cpp +++ b/kernel/graph/graphics.cpp @@ -3,8 +3,10 @@ #include "drivers/virtio_gpu_pci/virtio_gpu_pci.hpp" #include "drivers/ramfb_driver/ramfb.hpp" +#include "drivers/videocore/videocore.hpp" #include "std/std.hpp" +#include "hw/hw.h" static gpu_size screen_size; static bool _gpu_ready; @@ -16,6 +18,8 @@ void gpu_init(gpu_size preferred_screen_size){ gpu_driver = vgd; } else if (RamFBGPUDriver *rfb = RamFBGPUDriver::try_init(preferred_screen_size)){ gpu_driver = rfb; + } else if (BOARD_TYPE == 2){ + gpu_driver = VideoCoreGPUDriver::try_init(preferred_screen_size); } screen_size = preferred_screen_size; _gpu_ready = true; diff --git a/kernel/hw/hw.c b/kernel/hw/hw.c new file mode 100644 index 00000000..0067a6b6 --- /dev/null +++ b/kernel/hw/hw.c @@ -0,0 +1,67 @@ +#include "hw.h" +#include "console/kio.h" +#include "gpio.h" + +uint8_t BOARD_TYPE; +uint8_t USE_DTB = 0; +uint8_t USE_PCI = 0; +uintptr_t RAM_START = 0; +uintptr_t RAM_SIZE = 0; +uintptr_t CRAM_START = 0; +uintptr_t CRAM_END = 0; +uintptr_t UART0_BASE = 0; +uintptr_t XHCI_BASE = 0; +uintptr_t MMIO_BASE = 0; +uintptr_t GICD_BASE = 0; +uintptr_t GICC_BASE = 0; +uintptr_t SDHCI_BASE = 0; + +uint8_t RPI_BOARD; +uint8_t GPIO_BASE; +uint8_t GPIO_PIN_BASE; + +void detect_hardware(){ + if (BOARD_TYPE == 1){ + UART0_BASE = 0x9000000; + MMIO_BASE = 0x10010000; + CRAM_END = 0x60000000; + RAM_START = 0x40000000; + CRAM_START = 0x43600000; + USE_PCI = 1; + GICD_BASE = 0x08000000; + GICC_BASE = 0x08010000; + + } else { + uint32_t reg; + asm volatile ("mrs %x0, midr_el1" : "=r" (reg)); + uint32_t raspi = (reg >> 4) & 0xFFF; + switch (raspi) { + case 0xD08: //4B. Cortex A72 + MMIO_BASE = 0xFE000000; + RPI_BOARD = 4; + GPIO_PIN_BASE = 0x50; + break; + case 0xD0B: //5. Cortex A76 + MMIO_BASE = 0x107C000000UL; + RPI_BOARD = 5; + GPIO_PIN_BASE = 0x50; + break; + default: MMIO_BASE = 0x3F000000; break; + } + GPIO_BASE = MMIO_BASE + 0x200000; + GICD_BASE = MMIO_BASE + 0x1841000; + GICC_BASE = MMIO_BASE + 0x1842000; + UART0_BASE = MMIO_BASE + 0x201000; + SDHCI_BASE = MMIO_BASE + 0x300000; + XHCI_BASE = MMIO_BASE + 0x9C0000; + RAM_START = 0x10000000; + CRAM_END = (MMIO_BASE - 0x10000000) & 0xF0000000; + RAM_START = 0x10000000; + CRAM_START = 0x13600000; + reset_gpio(); + } +} + +void print_hardware(){ + kprintf("Board type %i",BOARD_TYPE); +} \ No newline at end of file diff --git a/kernel/hw/hw.h b/kernel/hw/hw.h new file mode 100644 index 00000000..7633c348 --- /dev/null +++ b/kernel/hw/hw.h @@ -0,0 +1,33 @@ +#pragma once + +// #include "elfvirt.h" +#include "types.h" + +extern uint8_t BOARD_TYPE; + +extern uint8_t USE_DTB; +extern uint8_t USE_PCI; + +extern uintptr_t RAM_START; +extern uintptr_t RAM_SIZE; +extern uintptr_t CRAM_START; +extern uintptr_t CRAM_END; + +extern uintptr_t UART0_BASE; +extern uintptr_t XHCI_BASE; + +extern uintptr_t MMIO_BASE; + +extern uintptr_t GICD_BASE; +extern uintptr_t GICC_BASE; + +extern uintptr_t SDHCI_BASE; + +extern uint8_t GPIO_BASE; + +extern uint8_t GPIO_PIN_BASE; + +extern uint8_t RPI_BOARD; + +void detect_hardware(); +void print_hardware(); \ No newline at end of file diff --git a/kernel/input/USBDevice.cpp b/kernel/input/USBDevice.cpp new file mode 100644 index 00000000..0a65e9ca --- /dev/null +++ b/kernel/input/USBDevice.cpp @@ -0,0 +1,43 @@ +#include "USBDevice.hpp" +#include "USBKeyboard.hpp" +#include "xhci_types.h" +#include "console/kio.h" + +USBDevice::USBDevice(uint32_t capacity, uint8_t address) : address(address) { + endpoints = IndexMap(capacity); +}; + +void USBDevice::request_data(uint8_t endpoint_id, USBDriver *driver){ + if (endpoint_id >= endpoints.max_size()) return;//TODO: check if it exists + USBEndpoint *ep = endpoints[endpoint_id]; + if (ep) + ep->request_data(driver); +} + +void USBDevice::process_data(uint8_t endpoint_id, USBDriver *driver){ + if (endpoint_id >= endpoints.max_size()) return;//TODO: check if it exists + USBEndpoint *ep = endpoints[endpoint_id]; + if (ep) + ep->process_data(driver); +} + +void USBDevice::register_endpoint(uint8_t endpoint, xhci_device_types type, uint16_t packet_size){ + if (endpoint >= endpoints.max_size()) return; + USBEndpoint *newendpoint; + switch (type){ + case KEYBOARD: + newendpoint = new USBKeyboard(address, endpoint, packet_size); + break; + default: return; + } + if (!newendpoint) return; + endpoints.add(endpoint,newendpoint); +} + +void USBDevice::poll_inputs(USBDriver *driver){ + for (uint8_t i = 0; i < endpoints.max_size(); i++){ + USBEndpoint *ep = endpoints[i]; + if (ep && ep->type == KEYBOARD) + ep->request_data(driver); + } +} \ No newline at end of file diff --git a/kernel/input/USBDevice.hpp b/kernel/input/USBDevice.hpp new file mode 100644 index 00000000..a3e4a4e2 --- /dev/null +++ b/kernel/input/USBDevice.hpp @@ -0,0 +1,34 @@ +#pragma once +#include "types.h" +#include "xhci_types.h" +#include "std/std.hpp" +#include "console/kio.h" + +class USBDriver; + +class USBEndpoint { +public: + USBEndpoint(uint8_t endpoint, xhci_device_types type, uint16_t packet_size): endpoint(endpoint), type(type), packet_size(packet_size) { } + virtual void request_data(USBDriver *driver) = 0; + + virtual void process_data(USBDriver *driver) = 0; + + uint8_t endpoint; + xhci_device_types type; + uint16_t packet_size; +}; + +class USBDevice { +public: + USBDevice(uint32_t capacity, uint8_t address); + void request_data(uint8_t endpoint_id, USBDriver *driver); + + void process_data(uint8_t endpoint_id, USBDriver *driver); + + void register_endpoint(uint8_t endpoint, xhci_device_types type, uint16_t packet_size); + + void poll_inputs(USBDriver *driver); + + IndexMap endpoints; + uint8_t address; +}; \ No newline at end of file diff --git a/kernel/input/USBKeyboard.cpp b/kernel/input/USBKeyboard.cpp new file mode 100644 index 00000000..a37d5760 --- /dev/null +++ b/kernel/input/USBKeyboard.cpp @@ -0,0 +1,50 @@ +#include "USBKeyboard.hpp" +#include "input_dispatch.h" +#include "console/kio.h" +#include "memory/page_allocator.h" +#include "usb.hpp" + +void USBKeyboard::request_data(USBDriver *driver){ + requesting = true; + + if (buffer == 0){ + buffer = alloc_page(packet_size, true, true, true); + } + + if (!driver->poll(slot_id, endpoint, buffer, packet_size)){ + + return; + } + + if (!driver->use_interrupts){ + process_keypress((keypress*)buffer); + return; + } +} + +void USBKeyboard::process_data(USBDriver *driver){ + if (!requesting){ + return; + } + + process_keypress((keypress*)buffer); + + request_data(driver); +} + +void USBKeyboard::process_keypress(keypress *rkp){ + keypress kp; + if (is_new_keypress(rkp, &last_keypress) || repeated_keypresses > 3){ + if (is_new_keypress(rkp, &last_keypress)) + repeated_keypresses = 0; + kp.modifier = rkp->modifier; + // kprintf_raw("Mod: %i", kp.modifier); + for (int i = 0; i < 6; i++){ + kp.keys[i] = rkp->keys[i]; + // kprintf_raw("Key [%i]: %i", i, kp.keys[i]); + } + last_keypress = kp; + register_keypress(kp); + } else + repeated_keypresses++; +} \ No newline at end of file diff --git a/kernel/input/USBKeyboard.hpp b/kernel/input/USBKeyboard.hpp new file mode 100644 index 00000000..1d0b7883 --- /dev/null +++ b/kernel/input/USBKeyboard.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "types.h" +#include "USBDevice.hpp" +#include "keypress.h" +#include "xhci_types.h" + +class USBKeyboard: public USBEndpoint { +public: + USBKeyboard(uint8_t new_slot_id, uint8_t endpoint, uint16_t packet_size) : USBEndpoint(endpoint, KEYBOARD, packet_size), slot_id(new_slot_id) {} + void request_data(USBDriver *driver) override; + void process_data(USBDriver *driver) override; +private: + void process_keypress(keypress *rkp); + trb* latest_ring; + bool requesting = false; + uint8_t slot_id; + + keypress last_keypress; + + int repeated_keypresses = 0; + + void* buffer; +}; \ No newline at end of file diff --git a/kernel/input/USBManager.cpp b/kernel/input/USBManager.cpp new file mode 100644 index 00000000..3efd8f75 --- /dev/null +++ b/kernel/input/USBManager.cpp @@ -0,0 +1,45 @@ +#include "USBManager.hpp" +#include "USBDevice.hpp" +#include "USBKeyboard.hpp" +#include "console/kio.h" + +USBManager::USBManager(uint32_t capacity){ + devices = IndexMap(capacity); +}; + +void USBManager::register_device(uint8_t address){ + if (address >= devices.max_size()) return; + USBDevice *newdevice = new USBDevice(8,address); + if (!newdevice) return; + devices.add(address,newdevice); +} + +void USBManager::register_endpoint(uint8_t slot_id, uint8_t endpoint, xhci_device_types type, uint16_t packet_size){ + if (slot_id >= devices.max_size()) return; + USBDevice *dev = devices[slot_id]; + if (dev) + dev->register_endpoint(endpoint, type, packet_size); +} + +void USBManager::request_data(uint8_t slot_id, uint8_t endpoint_id, USBDriver *driver){ + if (slot_id >= devices.max_size()) return;//TODO: check if it exists + USBDevice *dev = devices[slot_id]; + if (dev) + dev->request_data(endpoint_id, driver); +} + +void USBManager::process_data(uint8_t slot_id, uint8_t endpoint_id, USBDriver *driver){ + if (slot_id >= devices.max_size()) return;//TODO: check if it exists + USBDevice *dev = devices[slot_id]; + if (dev) + dev->process_data(endpoint_id, driver); +} + +void USBManager::poll_inputs(USBDriver *driver){ + for (uint8_t i = 0; i < devices.max_size(); i++){ + USBDevice *device = devices[i]; + if (device){ + device->poll_inputs(driver); + } + } +} \ No newline at end of file diff --git a/kernel/input/USBManager.hpp b/kernel/input/USBManager.hpp new file mode 100644 index 00000000..efcb9830 --- /dev/null +++ b/kernel/input/USBManager.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "types.h" +#include "xhci_types.h" +#include "std/std.hpp" +#include "USBDevice.hpp" + +class USBDriver; + +class USBManager { +public: + USBManager(uint32_t capacity); + IndexMap devices; + + void register_device(uint8_t address); + void register_endpoint(uint8_t slot_id, uint8_t endpoint, xhci_device_types type, uint16_t packet_size); + void request_data(uint8_t slot_id, uint8_t endpoint_id, USBDriver *driver); + void process_data(uint8_t slot_id, uint8_t endpoint_id, USBDriver *driver); + void poll_inputs(USBDriver *driver); +}; \ No newline at end of file diff --git a/kernel/input/dwc2.cpp b/kernel/input/dwc2.cpp new file mode 100644 index 00000000..5da780f6 --- /dev/null +++ b/kernel/input/dwc2.cpp @@ -0,0 +1,235 @@ +#include "dwc2.hpp" +#include "async.h" +#include "console/kio.h" +#include "memory/page_allocator.h" +#include "std/string.h" +#include "memory/mmu.h" + +#define DWC2_BASE 0xFE980000 + +dwc2_host_channel* DWC2Driver::get_channel(uint16_t channel){ + return (dwc2_host_channel *)(DWC2_BASE + 0x500 + (channel * 0x20)); +} + +uint8_t DWC2Driver::assign_channel(uint8_t device, uint8_t endpoint, uint8_t ep_type){ + uint8_t new_chan = ++next_channel; + dwc2_host_channel *channel = get_channel(new_chan); + channel->cchar = (device << 22) | (endpoint << 11) | (ep_type << 18); + channel_map[device << 8 | endpoint] = new_chan; + return new_chan; +} + +bool DWC2Driver::port_reset(uint32_t *port){ + *port &= ~0b101110; + *port |= (1 << 8); + + delay(50); + + *port &= ~0b101110; + *port &= ~(1 << 8); + + return wait(port, (1 << 8), false, 2000); +} + +bool DWC2Driver::init() { + + use_interrupts = false; + + dwc2 = (dwc2_regs*)DWC2_BASE; + host = (dwc2_host*)(DWC2_BASE + 0x400); + + *(uint32_t*)(DWC2_BASE + 0xE00) = 0;//Power reset + + dwc2->grstctl |= 1; + if (!wait(&dwc2->grstctl, 1, false, 2000)){ + kprintf("[DWC2] Failed to reset"); + return false; + } + + dwc2->gusbcfg &= ~(1 << 30);//Device mode disable + dwc2->gusbcfg |= (1 << 29);//Host mode enable + + dwc2->gahbcfg |= (1 << 5);//DMA + + dwc2->gintmsk = 0xffffffff; + + //Device setup0 + + host->port |= (1 << 12); + + if (!wait(&host->port, 1, true, 2000)){ + kprintf("[DWC2] No device connected %x",host->port); + return false; + } + + if (!port_reset(&host->port)){ + kprintf("[DWC2] failed port reset %b",host->port); + return false; + } + + channel_map = IndexMap(127 * 5); + usb_manager = new USBManager(127); + + kprintf("Port reset %x",host->port); + + port_speed = (host->port >> 17) & 0x3; + kprintf("Port speed %i",port_speed); + + mem_page = alloc_page(0x1000, true, true, false); + + setup_device(0,0); + + register_device_memory(DWC2_BASE, DWC2_BASE); + + return true; +} + +uint8_t DWC2Driver::address_device(uint8_t address){ + uint8_t new_address = ++next_address; + request_sized_descriptor(0, 0, 0x0, 0x5, 0, new_address, 0, 0, 0); + channel_map[new_address << 8] = assign_channel(new_address, 0, 0); + get_channel(0)->splt = 0; + return new_address; +} + +bool DWC2Driver::make_transfer(dwc2_host_channel *channel, bool in, uint8_t pid, sizedptr data){ + channel->dma = data.ptr; + uint16_t max_size = packet_size(port_speed); + uint32_t pkt_count = (data.size + max_size - 1)/max_size; + channel->xfer_size = (pkt_count << 19) | (pid << 29) | data.size; + + channel->cchar &= ~0x7FF; + channel->cchar |= max_size; + + channel->intmask = 0xFFFFFFFF; + channel->interrupt = 0; + + channel->cchar &= ~(1 << 15); + channel->cchar |= ((in ? 1 : 0) << 15); + + channel->cchar &= ~(1 << 30); + channel->cchar &= ~(1 << 31); + channel->cchar |= (1 << 31); + + if (!wait(&channel->interrupt, 1, true, 2000)){ + kprintf("[DWC2 error] Transfer timed out."); + return false; + } + + return true; +} + +bool DWC2Driver::request_sized_descriptor(uint8_t address, uint8_t endpoint, uint8_t rType, uint8_t request, uint8_t type, uint16_t descriptor_index, uint16_t wIndex, uint16_t descriptor_size, void *out_descriptor){ + + usb_setup_packet packet = { + .bmRequestType = rType, + .bRequest = request, + .wValue = (type << 8) | descriptor_index, + .wIndex = wIndex, + .wLength = descriptor_size + }; + + bool is_in = (rType & 0x80) != 0; + + dwc2_host_channel *channel = address == 0 ? get_channel(0) : get_channel(channel_map[address << 8 | endpoint]); + // kprintf("RT: %x R: %x V: %x I: %x L: %x",packet.bmRequestType,packet.bRequest,packet.wValue,packet.wIndex,packet.wLength); + + if (!make_transfer(channel, false, 0x3, (sizedptr){(uintptr_t)&packet, sizeof(uintptr_t)})){ + kprintf("[DWC2 error] Descriptor transfer failed setup stage"); + return false; + } + + if (descriptor_size > 0){ + if (!make_transfer(channel, is_in, 0x2, (sizedptr){(uintptr_t)out_descriptor, descriptor_size})){ + kprintf("[DWC2 error] Descriptor transfer failed data stage"); + return false; + } + } + + if (!make_transfer(channel, !is_in, 0x2, (sizedptr){0, 0})){ + kprintf("[DWC2 error] Descriptor transfer failed status stage"); + return false; + } + + return true; +} + +bool DWC2Driver::configure_endpoint(uint8_t address, usb_endpoint_descriptor *endpoint, uint8_t configuration_value, xhci_device_types type){ + + uint8_t ep_address = endpoint->bEndpointAddress; + uint8_t ep_num = ep_address & 0x0F; + uint8_t ep_dir = (ep_address & 0x80) >> 7; + + uint8_t ep_type = endpoint->bmAttributes & 0x03; // 0 = Control, 1 = Iso, 2 = Bulk, 3 = Interrupt + + kprintf("[DWC2] endpoint %i info. Direction %i type %i",ep_num, ep_dir, ep_type); + + //Configure endpoint + request_sized_descriptor(address, 0, 0x00, 0x09, 0, configuration_value, 0, 0, 0); + + uint8_t conf; + request_sized_descriptor(address, 0, 0x80, 0x08, 0, 0, 0, 1, &conf); + + if (!conf){ + kprintf("Failed to set configuration for device"); + return false; + } + + dwc2_host_channel *channel = get_channel(channel_map[address << 8]); + endpoint_channel = get_channel(assign_channel(address, ep_num, ep_type)); + if (channel->splt) + endpoint_channel->splt = channel->splt; + + endpoint_channel->cchar &= ~(1 << 15); + endpoint_channel->cchar |= (ep_dir << 15); + + endpoint_channel->cchar &= ~0x7FF; + endpoint_channel->cchar |= endpoint->wMaxPacketSize; + + endpoint_channel->xfer_size = (1 << 19) | (0x3 << 29) | endpoint->wMaxPacketSize; + + uint8_t mc = endpoint->bInterval & 0x3; + endpoint_channel->cchar &= ~(0b11 << 20); + endpoint_channel->cchar |= (mc << 20); + + usb_manager->register_endpoint(address, ep_num, type, endpoint->wMaxPacketSize); + + return true; +} + +bool DWC2Driver::poll(uint8_t address, uint8_t endpoint, void *out_buf, uint16_t size){ + dwc2_host_channel *endpoint_channel = get_channel(channel_map[(address << 8) | endpoint]); + if (endpoint_channel->cchar & 1) + return false; + + endpoint_channel->dma = (uintptr_t)out_buf; + + uint16_t max_size = endpoint_channel->cchar & 0x7FF; + uint32_t pkt_count = (size + max_size - 1)/max_size; + endpoint_channel->xfer_size = (pkt_count << 19) | (0x3 << 29) | size; + + endpoint_channel->intmask = 0xFFFFFFFF; + + endpoint_channel->interrupt = 0xFFFFFFFF; + + endpoint_channel->cchar &= ~(1 << 30); + endpoint_channel->cchar &= ~(1 << 31); + + endpoint_channel->cchar |= (1 << 31); + + if (!wait(&endpoint_channel->interrupt, 1, true, 10)){ + return false; + } + + endpoint_channel->interrupt = 0xFFFFFFFF; + endpoint_channel->cchar &= ~(1 << 31); + + return true; +} + +void DWC2Driver::handle_hub_routing(uint8_t hub, uint8_t port){ + dwc2_host_channel *dev_channel = get_channel(0); + dev_channel->splt = (1 << 31) | (1 << 16) | (hub << 7) | (port << 0); +} + +void DWC2Driver::handle_interrupt(){} \ No newline at end of file diff --git a/kernel/input/dwc2.hpp b/kernel/input/dwc2.hpp new file mode 100644 index 00000000..adabfe50 --- /dev/null +++ b/kernel/input/dwc2.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include "usb.hpp" +#include "std/indexmap.hpp" +#include "xhci_types.h" + +typedef struct { + uint32_t gotgctl; + uint32_t gotgint; + uint32_t gahbcfg; + uint32_t gusbcfg; + uint32_t grstctl; + uint32_t gintsts; + uint32_t gintmsk; + uint32_t grxstsr; + uint32_t grxstsp; + uint32_t grxfsiz; + uint32_t gnptxfsiz; + uint32_t gnptxsts; +} dwc2_regs; + +typedef struct { + uint32_t hstcfg; + uint32_t frminterval; + uint32_t frmnum; + uint32_t rsvd; + uint32_t ptx_fifo; + uint32_t allchan_int; + uint32_t allchan_int_mask; + uint32_t frmlst_base; + uint32_t rsvd2[8]; + uint32_t port; +} dwc2_host; + +typedef struct { + uint32_t cchar; + uint32_t splt; + uint32_t interrupt; + uint32_t intmask; + uint32_t xfer_size; + uint32_t dma; + uint32_t reserved[2]; + uint32_t buf; +} dwc2_host_channel; + +class DWC2Driver: public USBDriver { +public: + DWC2Driver() = default; + bool init() override; + bool request_sized_descriptor(uint8_t address, uint8_t endpoint, uint8_t rType, uint8_t request, uint8_t type, uint16_t descriptor_index, uint16_t wIndex, uint16_t descriptor_size, void *out_descriptor) override; + uint8_t address_device(uint8_t address) override; + bool configure_endpoint(uint8_t address, usb_endpoint_descriptor *endpoint, uint8_t configuration_value, xhci_device_types type) override; + void handle_hub_routing(uint8_t hub, uint8_t port) override; + bool poll(uint8_t address, uint8_t endpoint, void *out_buf, uint16_t size) override; + void handle_interrupt() override; + ~DWC2Driver() = default; + private: + dwc2_host_channel* get_channel(uint16_t channel); + uint8_t assign_channel(uint8_t device, uint8_t endpoint, uint8_t ep_type); + bool make_transfer(dwc2_host_channel *channel, bool in, uint8_t pid, sizedptr data); + bool port_reset(uint32_t *port); + uint16_t port_speed; + dwc2_regs *dwc2; + dwc2_host *host; + uint8_t next_channel; + uint8_t next_address; + dwc2_host_channel *endpoint_channel; + IndexMap channel_map; +}; \ No newline at end of file diff --git a/kernel/input/input_dispatch.c b/kernel/input/input_dispatch.cpp similarity index 83% rename from kernel/input/input_dispatch.c rename to kernel/input/input_dispatch.cpp index 850b5296..7f3993ec 100644 --- a/kernel/input/input_dispatch.c +++ b/kernel/input/input_dispatch.cpp @@ -1,6 +1,10 @@ #include "input_dispatch.h" #include "process/process.h" #include "process/scheduler.h" +#include "dwc2.hpp" +#include "xhci.hpp" +#include "hw/hw.h" +#include "std/std.hpp" process_t* focused_proc; @@ -16,8 +20,9 @@ uint16_t shortcut_count = 0; bool secure_mode = false; -void register_keypress(keypress kp) { +USBDriver *input_driver; +void register_keypress(keypress kp) { if (!secure_mode){ for (int i = 0; i < shortcut_count; i++){ if (shortcuts[i].pid != -1 && !is_new_keypress(&shortcuts[i].kp, &kp)){ @@ -83,6 +88,8 @@ bool is_new_keypress(keypress* current, keypress* previous) { } bool sys_read_input(int pid, keypress *out){ + if (BOARD_TYPE == 2) + input_driver->poll_inputs(); process_t *process = get_proc_by_pid(pid); if (process->input_buffer.read_index == process->input_buffer.write_index) return false; @@ -99,6 +106,20 @@ bool sys_shortcut_triggered(uint16_t pid, uint16_t sid){ if (shortcuts[sid].pid == pid && shortcuts[sid].triggered){ shortcuts[sid].triggered = false; return true; - } + } return false; +} + +bool input_init(){ + if (BOARD_TYPE == 2){ + input_driver = new DWC2Driver();//TODO: QEMU & 3 Only + return input_driver->init(); + } else { + input_driver = new XHCIDriver(); + return input_driver->init(); + } +} + +void handle_input_interrupt(){ + if (input_driver->use_interrupts) input_driver->handle_interrupt(); } \ No newline at end of file diff --git a/kernel/input/input_dispatch.h b/kernel/input/input_dispatch.h index ef8e27b9..9976c6ff 100644 --- a/kernel/input/input_dispatch.h +++ b/kernel/input/input_dispatch.h @@ -1,11 +1,12 @@ #pragma once -#include "xhci_bridge.h" #include "input_keycodes.h" +#include "keypress.h" #ifdef __cplusplus extern "C" { #endif + void register_keypress(keypress kp); uint16_t sys_subscribe_shortcut(uint16_t pid, keypress kp); uint16_t sys_subscribe_shortcut_current(keypress kp); @@ -24,6 +25,10 @@ bool sys_shortcut_triggered(uint16_t pid, uint16_t sid); bool is_new_keypress(keypress* current, keypress* previous); +bool input_init(); + +void handle_input_interrupt(); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/kernel/input/usb.cpp b/kernel/input/usb.cpp new file mode 100644 index 00000000..1c7d658f --- /dev/null +++ b/kernel/input/usb.cpp @@ -0,0 +1,206 @@ +#include "usb.hpp" +#include "console/kio.h" +#include "async.h" +#include "std/string.h" +#include "memory/page_allocator.h" +#include "xhci_types.h" + +uint16_t USBDriver::packet_size(uint16_t speed){ + switch (speed) { + case 2: return 8;//Low + case 1: + case 3: return 64;//High & full + case 4: + case 5: + default: return 512;//Super & Super Plus & Default + } +} + +bool USBDriver::setup_device(uint8_t address, uint16_t port){ + + address = address_device(address); + usb_device_descriptor* descriptor = (usb_device_descriptor*)allocate_in_page(mem_page, sizeof(usb_device_descriptor), ALIGN_64B, true, true); + + if (!request_descriptor(address, 0, 0x80, 6, USB_DEVICE_DESCRIPTOR, 0, 0, descriptor)){ + kprintf_raw("[USB error] failed to get device descriptor"); + return false; + } + + usb_string_language_descriptor* lang_desc = (usb_string_language_descriptor*)allocate_in_page(mem_page, sizeof(usb_string_language_descriptor), ALIGN_64B, true, true); + + bool use_lang_desc = true; + + if (!request_descriptor(address, 0, 0x80, 6, USB_STRING_DESCRIPTOR, 0, 0, lang_desc)){ + kprintf_raw("[USB warning] failed to get language descriptor"); + use_lang_desc = false; + } + + kprintf("[USB device] Vendor %x",descriptor->idVendor); + kprintf("[USB device] Product %x",descriptor->idProduct); + kprintf("[USB device] USB version %x",descriptor->bcdUSB); + kprintf("[USB device] EP0 Max Packet Size: %x", descriptor->bMaxPacketSize0); + kprintf("[USB device] Configurations: %x", descriptor->bNumConfigurations); + if (use_lang_desc){ + //TODO: we want to maintain the strings so we can have USB device information, and rework it to silece the alignment warning + uint16_t langid = lang_desc->lang_ids[0]; + usb_string_descriptor* prod_name = (usb_string_descriptor*)allocate_in_page(mem_page, sizeof(usb_string_descriptor), ALIGN_64B, true, true); + if (request_descriptor(address, 0, 0x80, 6, USB_STRING_DESCRIPTOR, descriptor->iProduct, langid, prod_name)){ + char name[128]; + if (utf16tochar(prod_name->unicode_string, name, sizeof(name))) { + kprintf("[USB device] Product name: %s", (uint64_t)name); + } + } + usb_string_descriptor* man_name = (usb_string_descriptor*)allocate_in_page(mem_page, sizeof(usb_string_descriptor), ALIGN_64B, true, true); + if (request_descriptor(address, 0, 0x80, 6, USB_STRING_DESCRIPTOR, descriptor->iManufacturer, langid, man_name)){ + char name[128]; + if (utf16tochar(man_name->unicode_string, name, sizeof(name))) { + kprintf("[USB device] Manufacturer name: %s", (uint64_t)name); + } + } + usb_string_descriptor* ser_name = (usb_string_descriptor*)allocate_in_page(mem_page, sizeof(usb_string_descriptor), ALIGN_64B, true, true); + if (request_descriptor(address, 0, 0x80, 6, USB_STRING_DESCRIPTOR, descriptor->iSerialNumber, langid, ser_name)){ + char name[128]; + if (utf16tochar(ser_name->unicode_string, name, sizeof(name))) { + kprintf("[USB device] Serial: %s", (uint64_t)name); + } + } + } + + return get_configuration(address); +} + +bool USBDriver::get_configuration(uint8_t address){ + + uint16_t ep_num = 0; + + usb_manager->register_device(address); + + usb_configuration_descriptor* config = (usb_configuration_descriptor*)allocate_in_page(mem_page, sizeof(usb_configuration_descriptor), ALIGN_64B, true, true); + if (!request_sized_descriptor(address, 0, 0x80, 6, USB_CONFIGURATION_DESCRIPTOR, 0, 0, 8, config)){ + kprintf("[USB error] could not get config descriptor header"); + return false; + } + + if (!request_sized_descriptor(address, 0, 0x80, 6, USB_CONFIGURATION_DESCRIPTOR, 0, 0, config->header.bLength, config)){ + kprintf("[USB error] could not get full config descriptor"); + return false; + } + + if (!request_sized_descriptor(address, 0, 0x80, 6, USB_CONFIGURATION_DESCRIPTOR, 0, 0, config->wTotalLength, config)){ + kprintf("[USB error] could not get full config descriptor"); + return false; + } + + uint16_t total_length = config->wTotalLength - config->header.bLength; + + kprintf("[USB] Config length %i (%i - %i)",total_length,config->wTotalLength,config->header.bLength); + + uint16_t interface_index = 0; + + bool need_new_endpoint = true; + + uint8_t* report_descriptor; + uint16_t report_length; + + xhci_device_types dev_type; + + for (uint16_t i = 0; i < total_length;){ + usb_descriptor_header* header = (usb_descriptor_header*)&config->data[i]; + if (header->bLength == 0){ + kprintf("[USB] Failed to get descriptor. Header size 0"); + return false; + } + if (need_new_endpoint){ + need_new_endpoint = false; + } + switch (header->bDescriptorType) + { + case 0x4: { //Interface + usb_interface_descriptor *interface = (usb_interface_descriptor *)&config->data[i]; + if (interface->bInterfaceClass == 0x9){ + kprintf("[USB] Hub detected %i", interface->bNumEndpoints); + hub_enumerate(address); + return true; + } else if (interface->bInterfaceClass != 0x3){ + kprintf("[USB implementation error] non-hid devices not supported yet %x",interface->bInterfaceClass); + return false; + } + kprintf("[USB] interface protocol %x",interface->bInterfaceProtocol); + switch (interface->bInterfaceProtocol) + { + case 0x1: + dev_type = KEYBOARD; + break; + + default: + break; + } + interface_index++; + break; + } + case 0x21: { //HID + usb_hid_descriptor *hid = (usb_hid_descriptor *)&config->data[i]; + for (uint8_t j = 0; j < hid->bNumDescriptors; j++){ + if (hid->descriptors[j].bDescriptorType == 0x22){//REPORT HID + report_length = hid->descriptors[j].wDescriptorLength; + report_descriptor = (uint8_t*)allocate_in_page(mem_page, report_length, ALIGN_64B, true, true); + request_descriptor(address, 0, 0x81, 6, 0x22, 0, interface_index-1, report_descriptor); + kprintf("[USB] retrieved report descriptor of length %i at %x", report_length, (uintptr_t)report_descriptor); + } + } + break; + } + case 0x5: {//Endpoint + usb_endpoint_descriptor *endpoint = (usb_endpoint_descriptor*)&config->data[i]; + + if (!configure_endpoint(address, endpoint, config->bConfigurationValue, dev_type)) return false; + + need_new_endpoint = true; + break; + } + default: { kprintf("[USB error] Unknown type %x", header->bDescriptorType); return false; } + } + i += header->bLength; + } + + return true; + +} + +bool USBDriver::request_descriptor(uint8_t address, uint8_t endpoint, uint8_t rType, uint8_t request, uint8_t type, uint16_t index, uint16_t wIndex, void *out_descriptor){ + if (!request_sized_descriptor(address, endpoint, rType, request, type, index, wIndex, sizeof(usb_descriptor_header), out_descriptor)){ + kprintf_raw("[USB error] Failed to get descriptor header. Size %i", sizeof(usb_descriptor_header)); + return false; + } + usb_descriptor_header* descriptor = (usb_descriptor_header*)out_descriptor; + if (descriptor->bLength == 0){ + kprintf_raw("[USB error] wrong descriptor size %i",descriptor->bLength); + return false; + } + return request_sized_descriptor(address, endpoint, rType, request, type, index, wIndex, descriptor->bLength, out_descriptor); +} + +void USBDriver::hub_enumerate(uint8_t address){ + //TODO: actually support multiple devices + uint8_t port = 1; + uint32_t port_status; + request_sized_descriptor(address, 0, 0xA3, 0, 0, 0, port, sizeof(uint32_t), (void*)&port_status); + if (port_status & 1){ + kprintf("Port %i status %b",port, port_status); + request_sized_descriptor(address, 0, 0x23, 3, 0, 4, port, 0, 0);//Port Reset + delay(50); + request_sized_descriptor(address, 0, 0x23, 1, 0, 4, port, 0, 0);//Port Reset Clear + delay(10); + request_sized_descriptor(address, 0, 0xA3, 0, 0, 0, port, sizeof(uint32_t), (void*)&port_status); + if (!(port_status & 0b11)){ + kprintf("Port not enabled or device not connected"); + return; + } + handle_hub_routing(address,port); + setup_device(0,1); + } +} + +void USBDriver::poll_inputs(){ + usb_manager->poll_inputs(this); +} \ No newline at end of file diff --git a/kernel/input/usb.hpp b/kernel/input/usb.hpp new file mode 100644 index 00000000..7fbf1c4b --- /dev/null +++ b/kernel/input/usb.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "types.h" +#include "keypress.h" +#include "xhci_types.h" +#include "USBManager.hpp" + +class USBDriver { +public: + USBDriver() = default; + virtual bool init() = 0; + bool request_descriptor(uint8_t address, uint8_t endpoint, uint8_t rType, uint8_t request, uint8_t type, uint16_t index, uint16_t wIndex, void *out_descriptor); + virtual bool request_sized_descriptor(uint8_t address, uint8_t endpoint, uint8_t rType, uint8_t request, uint8_t type, uint16_t descriptor_index, uint16_t wIndex, uint16_t descriptor_size, void *out_descriptor) = 0; + uint16_t packet_size(uint16_t speed); + bool get_configuration(uint8_t address); + void hub_enumerate(uint8_t address); + virtual bool setup_device(uint8_t address, uint16_t port); + virtual uint8_t address_device(uint8_t address) = 0; + virtual bool configure_endpoint(uint8_t address, usb_endpoint_descriptor *endpoint, uint8_t configuration_value, xhci_device_types type) = 0; + virtual void handle_hub_routing(uint8_t hub, uint8_t port) = 0; + virtual bool poll(uint8_t address, uint8_t endpoint, void *out_buf, uint16_t size) = 0; + void poll_inputs(); + virtual void handle_interrupt() = 0; + bool use_interrupts; + ~USBDriver() = default; +protected: + void *mem_page; + USBManager *usb_manager; + bool verbose = false; +}; \ No newline at end of file diff --git a/kernel/input/xHCIDevice.cpp b/kernel/input/xHCIDevice.cpp deleted file mode 100644 index 05c6c981..00000000 --- a/kernel/input/xHCIDevice.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "xHCIDevice.hpp" -#include "xHCIKeyboard.hpp" - -xHCIDevice::xHCIDevice(uint32_t capacity, xhci_usb_device *dev) : device(dev) { - endpoints = IndexMap(capacity); -}; - -void xHCIDevice::request_data(uint8_t endpoint_id){ - if (endpoint_id >= endpoints.max_size()) return;//TODO: check if it exists - endpoints[endpoint_id]->request_data(); -} - -void xHCIDevice::process_data(uint8_t endpoint_id){ - if (endpoint_id >= endpoints.max_size()) return;//TODO: check if it exists - endpoints[endpoint_id]->process_data(); -} - -void xHCIDevice::register_endpoint(xhci_usb_device_endpoint *endpoint){ - if (endpoint->poll_endpoint >= endpoints.max_size()) return; - xHCIEndpoint *newendpoint; - switch (endpoint->type){ - case KEYBOARD: - newendpoint = new xHCIKeyboard(device->slot_id, endpoint); - break; - default: return; - } - if (!newendpoint) return; - endpoints.add(endpoint->poll_endpoint,newendpoint); - request_data(endpoint->poll_endpoint); -} \ No newline at end of file diff --git a/kernel/input/xHCIDevice.hpp b/kernel/input/xHCIDevice.hpp deleted file mode 100644 index 4415e120..00000000 --- a/kernel/input/xHCIDevice.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include "types.h" -#include "xhci_types.h" -#include "std/std.hpp" - -class xHCIEndpoint { -public: - xHCIEndpoint(xhci_usb_device_endpoint *ep): endpoint(ep) {} - virtual void request_data() {}; - - virtual void process_data() {}; - - xhci_usb_device_endpoint *endpoint; -}; - -class xHCIDevice { -public: - xHCIDevice(uint32_t capacity, xhci_usb_device *dev); - void request_data(uint8_t endpoint_id); - - void process_data(uint8_t endpoint_id); - - void register_endpoint(xhci_usb_device_endpoint *endpoint); - - IndexMap endpoints; - xhci_usb_device *device; -}; \ No newline at end of file diff --git a/kernel/input/xHCIKeyboard.cpp b/kernel/input/xHCIKeyboard.cpp deleted file mode 100644 index f79e79b9..00000000 --- a/kernel/input/xHCIKeyboard.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "xHCIKeyboard.hpp" -#include "xhci.h" -#include "input_dispatch.h" -#include "console/kio.h" -#include "memory/page_allocator.h" - -void xHCIKeyboard::request_data(){ - requesting = true; - latest_ring = &endpoint->endpoint_transfer_ring[endpoint->endpoint_transfer_index++]; - - if (endpoint->input_buffer == 0x0){ - uint64_t buffer_addr = (uint64_t)alloc_page(endpoint->poll_packetSize, true, true, true); - endpoint->input_buffer = (uint8_t*)buffer_addr; - } - - latest_ring->parameter = (uintptr_t)endpoint->input_buffer; - latest_ring->status = endpoint->poll_packetSize; - latest_ring->control = (TRB_TYPE_NORMAL << 10) | (1 << 5) | endpoint->endpoint_transfer_cycle_bit; - - if (endpoint->endpoint_transfer_index == MAX_TRB_AMOUNT - 1){ - make_ring_link_control(endpoint->endpoint_transfer_ring, endpoint->endpoint_transfer_cycle_bit); - endpoint->endpoint_transfer_cycle_bit = !endpoint->endpoint_transfer_cycle_bit; - endpoint->endpoint_transfer_index = 0; - } - - ring_doorbell(slot_id, endpoint->poll_endpoint); -} - -void xHCIKeyboard::process_data(){ - if (!requesting){ - return; - } - - keypress kp; - if (!xhci_await_response((uintptr_t)latest_ring,TRB_TYPE_TRANSFER)) - xhci_sync_events();//TODO: we're just consuming the event without even looking to see if it's the right one, this is wrong, seriously, IRQ await would fix this - - keypress *rkp = (keypress*)endpoint->input_buffer; - if (is_new_keypress(rkp, &last_keypress) || repeated_keypresses > 3){ - if (is_new_keypress(rkp, &last_keypress)) - repeated_keypresses = 0; - kp.modifier = rkp->modifier; - // kprintf_raw("Mod: %i", kp.modifier); - for (int i = 0; i < 6; i++){ - kp.keys[i] = rkp->keys[i]; - // kprintf_raw("Key [%i]: %i", i, kp.keys[i]); - } - last_keypress = kp; - register_keypress(kp); - } else - repeated_keypresses++; - - request_data(); - -} \ No newline at end of file diff --git a/kernel/input/xHCIKeyboard.hpp b/kernel/input/xHCIKeyboard.hpp deleted file mode 100644 index d4cf9083..00000000 --- a/kernel/input/xHCIKeyboard.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "types.h" -#include "xHCIDevice.hpp" -#include "keypress.h" - -class xHCIKeyboard: public xHCIEndpoint { -public: - xHCIKeyboard(uint8_t new_slot_id, xhci_usb_device_endpoint *endpoint) : xHCIEndpoint(endpoint), slot_id(new_slot_id) {} - void request_data() override; - void process_data() override; -private: - trb* latest_ring; - bool requesting = false; - uint8_t slot_id; - - keypress last_keypress; - - int repeated_keypresses = 0; -}; \ No newline at end of file diff --git a/kernel/input/xHCIManager.cpp b/kernel/input/xHCIManager.cpp deleted file mode 100644 index 6c7b3e69..00000000 --- a/kernel/input/xHCIManager.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "xHCIManager.hpp" -#include "xHCIKeyboard.hpp" -#include "console/kio.h" - -xHCIManager::xHCIManager(uint32_t capacity){ - devices = IndexMap(capacity); -}; - -void xHCIManager::register_device(uint8_t slot_id, xhci_usb_device *device){ - if (slot_id >= devices.max_size()) return; - xHCIDevice *newdevice = new xHCIDevice(8,device); - if (!newdevice) return; - devices.add(slot_id,newdevice); -} - -void xHCIManager::register_endpoint(uint8_t slot_id, xhci_usb_device_endpoint *endpoint){ - if (slot_id >= devices.max_size()) return; - devices[slot_id]->register_endpoint(endpoint); -} - -void xHCIManager::request_data(uint8_t slot_id, uint8_t endpoint_id){ - if (slot_id >= devices.max_size()) return;//TODO: check if it exists - devices[slot_id]->request_data(endpoint_id); -} - -void xHCIManager::process_data(uint8_t slot_id, uint8_t endpoint_id){ - if (slot_id >= devices.max_size()) return;//TODO: check if it exists - devices[slot_id]->process_data(endpoint_id); -} diff --git a/kernel/input/xHCIManager.hpp b/kernel/input/xHCIManager.hpp deleted file mode 100644 index 6f600282..00000000 --- a/kernel/input/xHCIManager.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "types.h" -#include "xhci_types.h" -#include "std/std.hpp" -#include "xHCIDevice.hpp" - -class xHCIManager { -public: - xHCIManager(uint32_t capacity); - IndexMap devices; - xHCIDevice *default_device; - - void register_device(uint8_t slot_id, xhci_usb_device *device); - void register_endpoint(uint8_t slot_id, xhci_usb_device_endpoint *endpoint); - void request_data(uint8_t slot_id, uint8_t endpoint_id); - void process_data(uint8_t slot_id, uint8_t endpoint_id); -}; \ No newline at end of file diff --git a/kernel/input/xhci.c b/kernel/input/xhci.c deleted file mode 100644 index e56cff43..00000000 --- a/kernel/input/xhci.c +++ /dev/null @@ -1,725 +0,0 @@ -#include "xhci.h" -#include "console/kio.h" -#include "console/serial/uart.h" -#include "pci.h" -#include "memory/kalloc.h" -#include "memory/memory_access.h" -#include "memory/page_allocator.h" -#include "xhci_bridge.h" -#include "std/string.h" -#include "std/memfunctions.h" - -static xhci_device global_device; - -static bool xhci_verbose = false; - -void xhci_enable_verbose(){ - xhci_verbose = true; -} - -uint64_t awaited_addr; -uint32_t awaited_type; -#define AWAIT(addr, action, type) \ - ({ \ - awaited_addr = (uintptr_t)(addr); \ - awaited_type = (type); \ - action; \ - xhci_await_response((uintptr_t)(addr), (type)); \ - }) - -#define kprintfv(fmt, ...) \ - ({ \ - if (xhci_verbose){\ - uint64_t _args[] = { __VA_ARGS__ }; \ - kprintf_args_raw((fmt), _args, sizeof(_args) / sizeof(_args[0])); \ - }\ - }) - -static void* xhci_mem_page; - -bool xhci_check_fatal_error() { - uint32_t sts = global_device.op->usbsts; - if (sts & (XHCI_USBSTS_HSE | XHCI_USBSTS_CE)) { - kprintf_raw("[xHCI ERROR] Fatal condition: USBSTS = %x", sts); - return true; - } - return false; -} - -bool enable_xhci_events(){ - kprintfv("[xHCI] Allocating ERST"); - global_device.interrupter = (xhci_interrupter*)(uintptr_t)(global_device.rt_base + 0x20); - - uint64_t event_ring = (uintptr_t)allocate_in_page(xhci_mem_page, MAX_TRB_AMOUNT * sizeof(trb), ALIGN_64B, true, true); - uint64_t erst_addr = (uintptr_t)allocate_in_page(xhci_mem_page, MAX_ERST_AMOUNT * sizeof(erst_entry), ALIGN_64B, true, true); - erst_entry* erst = (erst_entry*)erst_addr; - - erst->ring_base = event_ring; - erst->ring_size = MAX_TRB_AMOUNT; - erst->reserved = 0; - kprintfv("[xHCI] ERST ring_base: %x", event_ring); - kprintfv("[xHCI] ERST ring_size: %x", erst[0].ring_size); - global_device.event_ring = (trb*)event_ring; - - kprintfv("[xHCI] Interrupter register @ %x", global_device.rt_base + 0x20); - - global_device.interrupter->erstsz = 1; - kprintfv("[xHCI] ERSTSZ set to: %x", global_device.interrupter->erstsz); - - global_device.interrupter->erdp = event_ring; - global_device.interrupter->erstba = erst_addr; - kprintfv("[xHCI] ERSTBA set to: %x", global_device.interrupter->erstba); - - kprintfv("[xHCI] ERDP set to: %x", global_device.interrupter->erdp); - - global_device.interrupter->iman |= 1 << 1;//Enable interrupt - - global_device.op->usbsts = 1 << 3;//Enable interrupts - global_device.interrupter->iman |= 1;//Clear pending interrupts - - return !xhci_check_fatal_error(); -} - -void make_ring_link_control(trb* ring, bool cycle){ - ring[MAX_TRB_AMOUNT-1].control = - (TRB_TYPE_LINK << 10) - | (1 << 1) // Toggle Cycle - | cycle; -} - -void make_ring_link(trb* ring, bool cycle){ - ring[MAX_TRB_AMOUNT-1].parameter = (uintptr_t)ring; - ring[MAX_TRB_AMOUNT-1].status = 0; - make_ring_link_control(ring, cycle); -} - -bool xhci_init(xhci_device *xhci, uint64_t pci_addr) { - kprintfv("[xHCI] init"); - if (!(read16(pci_addr + 0x06) & (1 << 4))){ - kprintfv("[xHCI] Wrong capabilities list"); - return false; - } - - pci_enable_device(pci_addr); - - if (!pci_setup_bar(pci_addr, 0, &xhci->mmio, &xhci->mmio_size)){ - kprintfv("[xHCI] BARs not set up"); - return false; - } - - pci_register(xhci->mmio, xhci->mmio_size); - - uint8_t interrupts_ok = pci_setup_interrupts(pci_addr, XHCI_IRQ, 1); - switch(interrupts_ok){ - case 0: - kprintf_raw("[xHCI] Failed to setup interrupts"); - return false; - case 1: - kprintf_raw("[xHCI] Interrupts setup with MSI-X %i",XHCI_IRQ); - break; - default: - kprintf_raw("[xHCI] Interrupts setup with MSI %i",XHCI_IRQ); - break; - } - - kprintfv("[xHCI] BARs set up @ %x (%x)",xhci->mmio,xhci->mmio_size); - - xhci->cap = (xhci_cap_regs*)(uintptr_t)xhci->mmio; - kprintfv("[xHCI] caplength %x",xhci->cap->caplength); - uint64_t op_base = xhci->mmio + xhci->cap->caplength; - xhci->op = (xhci_op_regs*)(uintptr_t)op_base; - xhci->ports = (xhci_port_regs*)((uintptr_t)op_base + 0x400); - xhci->db_base = xhci->mmio + (xhci->cap->dboff & ~0x1F); - xhci->rt_base = xhci->mmio + (xhci->cap->rtsoff & ~0x1F); - - kprintfv("[xHCI] Resetting controller"); - xhci->op->usbcmd &= ~1; - while (xhci->op->usbcmd & 1); - kprintfv("[xHCI] Clear complete"); - - xhci->op->usbcmd |= (1 << 1); - while (xhci->op->usbcmd & 1); - kprintfv("[xHCI] Reset complete"); - - while (xhci->op->usbsts & (1 << 11)); - kprintfv("[xHCI] Device ready"); - - if (xhci->op->usbcmd != 0){ - kprintf_raw("[xHCI Error] wrong usbcmd %x",xhci->op->usbcmd); - return false; - } else { - kprintfv("[xHCI] Correct usbcmd value"); - } - - if (xhci->op->dnctrl != 0){ - kprintf_raw("[xHCI Error] wrong dnctrl %x",xhci->op->dnctrl); - return false; - } else { - kprintfv("[xHCI] Correct dnctrl value"); - } - - if (xhci->op->crcr != 0){ - kprintf_raw("[xHCI Error] wrong crcr %x",xhci->op->crcr); - return false; - } else { - kprintfv("[xHCI] Correct crcr value"); - } - - if (xhci->op->dcbaap != 0){ - kprintf_raw("[xHCI Error] wrong dcbaap %x",xhci->op->dcbaap); - return false; - } else { - kprintfv("[xHCI] Correct dcbaap value"); - } - - if (xhci->op->config != 0){ - kprintf_raw("[xHCI Error] wrong config %x",xhci->op->config); - return false; - } else { - kprintfv("[xHCI] Correct config value"); - } - - xhci->command_cycle_bit = 1; - xhci->event_cycle_bit = 1; - - xhci->max_device_slots = xhci->cap->hcsparams1 & 0xFF; - xhci->max_ports = (xhci->cap->hcsparams1 >> 24) & 0xFF; - - xhci_initialize_manager(xhci->max_device_slots); - - uint16_t erst_max = ((xhci->cap->hcsparams2 >> 4) & 0xF); - - kprintfv("[xHCI] ERST Max: 2^%i",erst_max); - - xhci->op->dnctrl = 0xFFFF;//Enable device notifications - - xhci->op->config = xhci->max_device_slots; - kprintfv("[xHCI] %i device slots", xhci->max_device_slots); - - xhci_mem_page = alloc_page(0x1000, true, true, false); - - uintptr_t dcbaap_addr = (uintptr_t)allocate_in_page(xhci_mem_page, (xhci->max_device_slots + 1) * sizeof(uintptr_t), ALIGN_64B, true, true); - - xhci->op->dcbaap = dcbaap_addr; - - xhci->op->pagesize = 0b1;//4KB page size - - uint32_t scratchpad_count = ((xhci->cap->hcsparams2 >> 27) & 0x1F); - - xhci->dcbaa = (uint64_t *)dcbaap_addr; - - uint64_t* scratchpad_array = (uint64_t*)allocate_in_page(xhci_mem_page, (scratchpad_count == 0 ? 1 : scratchpad_count) * sizeof(uintptr_t), ALIGN_64B, true, true); - for (uint32_t i = 0; i < scratchpad_count; i++) - scratchpad_array[i] = (uint64_t)allocate_in_page(xhci_mem_page, 0x1000, ALIGN_64B, true, true); - xhci->dcbaa[0] = (uint64_t)scratchpad_array; - - kprintfv("[xHCI] dcbaap assigned at %x with %i scratchpads",dcbaap_addr,scratchpad_count); - - uint64_t command_ring = (uintptr_t)allocate_in_page(xhci_mem_page, MAX_TRB_AMOUNT * sizeof(trb), ALIGN_64B, true, true); - - xhci->cmd_ring = (trb*)command_ring; - xhci->cmd_index = 0; - xhci->op->crcr = command_ring | xhci->command_cycle_bit; - - make_ring_link(xhci->cmd_ring, xhci->command_cycle_bit); - - kprintfv("[xHCI] command ring allocated at %x. crcr now %x",command_ring, xhci->op->crcr); - - if (!enable_xhci_events()) - return false; - - kprintfv("[xHCI] event configuration finished"); - - xhci->op->usbcmd |= (1 << 2);//Interrupt enable - xhci->op->usbcmd |= 1;//Run - while ((xhci->op->usbsts & 0x1)); - - kprintfv("[xHCI] Init complete with usbcmd %x, usbsts %x",xhci->op->usbcmd, xhci->op->usbsts); - - return !xhci_check_fatal_error(); -} - - -void ring_doorbell(uint32_t slot, uint32_t endpoint) { - volatile uint32_t* db = (uint32_t*)(uintptr_t)(global_device.db_base + (slot << 2)); - kprintfv("[xHCI] Ringing doorbell at %x with value %x", global_device.db_base + (slot << 2),endpoint); - *db = endpoint; -} - -bool xhci_await_response(uint64_t command, uint32_t type){ - while (true){ - if (xhci_check_fatal_error()){ - kprintf_raw("[xHCI error] USBSTS value %x",global_device.op->usbsts); - awaited_type = 0; - return false; - } - for (; global_device.event_index < MAX_TRB_AMOUNT; global_device.event_index++){ - trb* ev = &global_device.event_ring[global_device.event_index]; - if (!((ev->control & 1) == global_device.event_cycle_bit)) //TODO: implement a timeout - break; - // kprintf_raw("[xHCI] A response at %i of type %x as a response to %x",global_device.event_index, (ev->control & TRB_TYPE_MASK) >> 10, ev->parameter); - if (global_device.event_index == MAX_TRB_AMOUNT - 1){ - global_device.event_index = 0; - global_device.event_cycle_bit = !global_device.event_cycle_bit; - } - if ((ev->control & TRB_TYPE_MASK) >> 10 == type && (command == 0 || ev->parameter == (command & 0xFFFFFFFFFFFFFFFF))){ - uint8_t completion_code = (ev->control >> 24) & 0xFF; - global_device.interrupter->erdp = (uintptr_t)ev | (1 << 3);//Inform of latest processed event - global_device.interrupter->iman |= 1;//Clear interrupts - global_device.op->usbsts |= 1 << 3;//Clear interrupts - awaited_type = 0; - return completion_code == 1; - } - } - awaited_type = 0; - return false; - } -} - -void xhci_sync_events(){ - for (; global_device.event_index < MAX_TRB_AMOUNT; global_device.event_index++){ - trb* ev = &global_device.event_ring[global_device.event_index]; - if (!((ev->control & 1) == global_device.event_cycle_bit)){ - global_device.interrupter->erdp = (uintptr_t)ev | (1 << 3); - global_device.interrupter->iman |= 1; - global_device.op->usbsts |= 1 << 3; - return; - } - global_device.interrupter->erdp = (uintptr_t)ev | (1 << 3); - global_device.interrupter->iman |= 1; - global_device.op->usbsts |= 1 << 3; - } -} - -bool issue_command(uint64_t param, uint32_t status, uint32_t control){ - trb* cmd = &global_device.cmd_ring[global_device.cmd_index++]; - cmd->parameter = param; - cmd->status = status; - cmd->control = control | global_device.command_cycle_bit; - - uint64_t cmd_addr = (uintptr_t)cmd; - kprintfv("[xHCI] issuing command with control: %x", cmd->control); - if (global_device.cmd_index == MAX_TRB_AMOUNT - 1){ - make_ring_link_control(global_device.cmd_ring, global_device.command_cycle_bit); - global_device.command_cycle_bit = !global_device.command_cycle_bit; - global_device.cmd_index = 0; - } - return AWAIT(cmd_addr, {ring_doorbell(0, 0);}, TRB_TYPE_COMMAND_COMPLETION); -} - -uint16_t packet_size(uint16_t port_speed){ - switch (port_speed) { - case 2: return 8;//Low - case 1: - case 3: return 64;//High & full - case 4: - case 5: - default: return 512;//Super & Super Plus & Default - } -} - -bool reset_port(uint16_t port){ - - xhci_port_regs* port_info = &global_device.ports[port]; - - if (port_info->portsc.pp == 0){ - port_info->portsc.pp = 1; - - //Read back after delay to ensure - // if (port_info->portsc.pp == 0){ - // kprintf_raw("[xHCI error] failed to power on port %i",port); - // return false; - // } - } - - port_info->portsc.csc = 1; - port_info->portsc.pec = 1; - port_info->portsc.prc = 1; - - //TODO: if usb3 - //portsc.wpr = 1; - //else - - return AWAIT(0, { - port_info->portsc.pr = 1; - },TRB_TYPE_PORT_STATUS_CHANGE); -} - -bool xhci_request_sized_descriptor(xhci_usb_device *device, bool interface, uint8_t type, uint16_t descriptor_index, uint16_t wIndex, uint16_t descriptor_size, void *out_descriptor){ - usb_setup_packet packet = { - .bmRequestType = 0x80 | interface, - .bRequest = 6, - .wValue = (type << 8) | descriptor_index, - .wIndex = wIndex, - .wLength = descriptor_size - }; - - trb* setup_trb = &device->transfer_ring[device->transfer_index++]; - memcpy(&setup_trb->parameter, &packet, sizeof(packet)); - setup_trb->status = sizeof(usb_setup_packet); - //bit 4 = chain. Bit 16 direction (3 = IN, 2 = OUT, 0 = NO DATA) - setup_trb->control = (3 << 16) | (TRB_TYPE_SETUP_STAGE << 10) | (1 << 6) | (1 << 4) | device->transfer_cycle_bit; - - trb* data = &device->transfer_ring[device->transfer_index++]; - data->parameter = (uintptr_t)out_descriptor; - data->status = packet.wLength; - //bit 16 = direction - data->control = (1 << 16) | (TRB_TYPE_DATA_STAGE << 10) | (0 << 4) | device->transfer_cycle_bit; - - trb* status_trb = &device->transfer_ring[device->transfer_index++]; - status_trb->parameter = 0; - status_trb->status = 0; - //bit 5 = interrupt-on-completion - status_trb->control = (TRB_TYPE_STATUS_STAGE << 10) | (1 << 5) | device->transfer_cycle_bit; - - if (device->transfer_index == MAX_TRB_AMOUNT - 1){ - make_ring_link_control(device->transfer_ring, device->transfer_cycle_bit); - device->transfer_cycle_bit = !device->transfer_cycle_bit; - device->transfer_index = 0; - } - - return AWAIT((uintptr_t)status_trb, {ring_doorbell(device->slot_id, 1);}, TRB_TYPE_TRANSFER); -} - -bool clear_halt(xhci_usb_device *device, uint16_t endpoint_num){ - kprintfv("Clearing halt"); - usb_setup_packet packet = { - .bmRequestType = 0x2, - .bRequest = 1, - .wValue = 0, - .wIndex = endpoint_num, - .wLength = 0 - }; - - trb* setup_trb = &device->transfer_ring[device->transfer_index++]; - memcpy(&setup_trb->parameter, &packet, sizeof(packet)); - setup_trb->status = sizeof(usb_setup_packet); - //Bit 16 direction (3 = IN, 2 = OUT, 0 = NO DATA) - setup_trb->control = (0 << 16) | (TRB_TYPE_SETUP_STAGE << 10) | (1 << 6) | device->transfer_cycle_bit; - - trb* status_trb = &device->transfer_ring[device->transfer_index++]; - status_trb->parameter = 0; - status_trb->status = 0; - //bit 16 = direction. 1 = handshake. bit 5 = interrupt-on-completion - status_trb->control = (1 << 16) | (TRB_TYPE_STATUS_STAGE << 10) | (1 << 5) | device->transfer_cycle_bit; - - if (device->transfer_index == MAX_TRB_AMOUNT - 1){ - make_ring_link_control(device->transfer_ring, device->transfer_cycle_bit); - device->transfer_cycle_bit = !device->transfer_cycle_bit; - device->transfer_index = 0; - } - - if (!AWAIT((uintptr_t)status_trb, {ring_doorbell(device->slot_id, 1);},TRB_TYPE_TRANSFER)){ - kprintf_raw("[xHCI error] could not clear stall"); - return false; - } - - return true; -} - -bool xhci_request_descriptor(xhci_usb_device *device, bool interface, uint8_t type, uint16_t index, uint16_t wIndex, void *out_descriptor){ - if (!xhci_request_sized_descriptor(device, interface, type, index, wIndex, sizeof(usb_descriptor_header), out_descriptor)){ - kprintf_raw("[xHCI error] Failed to get descriptor header. Size %i", sizeof(usb_descriptor_header)); - return false; - } - usb_descriptor_header* descriptor = (usb_descriptor_header*)out_descriptor; - if (descriptor->bLength == 0){ - kprintf_raw("[xHCI error] wrong descriptor size %i",descriptor->bLength); - return false; - } - return xhci_request_sized_descriptor(device, interface, type, index, wIndex, descriptor->bLength, out_descriptor); -} - -uint8_t get_ep_type(usb_endpoint_descriptor* descriptor) { - return (descriptor->bEndpointAddress & 0x80 ? 1 << 2 : 0) | (descriptor->bmAttributes & 0x3); -} - -bool xhci_get_configuration(usb_configuration_descriptor *config, xhci_usb_device *device){ - uint16_t total_length = config->wTotalLength - config->header.bLength; - - kprintfv("[xHCI] Config length %i (%i - %i)",total_length,config->wTotalLength,config->header.bLength); - - uint16_t interface_index = 0; - - bool need_new_endpoint = true; - - xhci_usb_device_endpoint *device_endpoint; - - xhci_configure_device(device->slot_id, device); - - for (uint16_t i = 0; i < total_length;){ - usb_descriptor_header* header = (usb_descriptor_header*)&config->data[i]; - if (header->bLength == 0){ - kprintf_raw("Failed to get descriptor. Header size 0"); - return false; - } - if (need_new_endpoint){ - need_new_endpoint = false; - device_endpoint = (xhci_usb_device_endpoint*)allocate_in_page(xhci_mem_page, sizeof(xhci_usb_device_endpoint), ALIGN_64B, true, true); - } - switch (header->bDescriptorType) - { - case 0x4: //Interface - usb_interface_descriptor *interface = (usb_interface_descriptor *)&config->data[i]; - if (interface->bInterfaceClass != 0x3){ - kprintf_raw("[xHCI implementation error] non-hid devices not supported yet"); - return false; - } - kprintfv("[xHCI] interface protocol %x",interface->bInterfaceProtocol); - switch (interface->bInterfaceProtocol) - { - case 0x1: - device_endpoint->type = KEYBOARD; - break; - - default: - break; - } - interface_index++; - break; - case 0x21://HID - usb_hid_descriptor *hid = (usb_hid_descriptor *)&config->data[i]; - for (uint8_t j = 0; j < hid->bNumDescriptors; j++){ - if (hid->descriptors[j].bDescriptorType == 0x22){//REPORT HID - device_endpoint->report_length = hid->descriptors[j].wDescriptorLength; - device_endpoint->report_descriptor = (uint8_t*)allocate_in_page(xhci_mem_page, device_endpoint->report_length, ALIGN_64B, true, true); - xhci_request_descriptor(device, true, 0x22, 0, interface_index-1, device_endpoint->report_descriptor); - kprintfv("[xHCI] retrieved report descriptor of length %i at %x", device_endpoint->report_length, (uintptr_t)device_endpoint->report_descriptor); - } - } - break; - case 0x5: //Endpoint - usb_endpoint_descriptor *endpoint = (usb_endpoint_descriptor*)&config->data[i]; - kprintfv("[xHCI] endpoint address %x",endpoint->bEndpointAddress); - uint8_t ep_address = endpoint->bEndpointAddress; - uint8_t ep_dir = (ep_address & 0x80) ? 1 : 0; // 1 IN, 0 OUT - uint8_t ep_num = ((ep_address & 0x0F) * 2) + ep_dir; - - uint8_t ep_type = endpoint->bmAttributes & 0x03; // 0 = Control, 1 = Iso, 2 = Bulk, 3 = Interrupt - kprintf_raw("[xHCI] endpoint %i info. Direction %i type %i",ep_num, ep_dir, ep_type); - - xhci_input_context* ctx = device->ctx; - - ctx->control_context.add_flags = (1 << 0) | (1 << ep_num); - ctx->device_context.slot_f0.context_entries = 2; // 2 entries: EP0 + EP1 - ctx->device_context.endpoints[ep_num-1].endpoint_f0.interval = endpoint->bInterval; - - ctx->device_context.endpoints[ep_num-1].endpoint_f0.endpoint_state = 0; - ctx->device_context.endpoints[ep_num-1].endpoint_f1.endpoint_type = get_ep_type(endpoint); - ctx->device_context.endpoints[ep_num-1].endpoint_f1.max_packet_size = endpoint->wMaxPacketSize; - ctx->device_context.endpoints[ep_num-1].endpoint_f4.max_esit_payload_lo = endpoint->wMaxPacketSize; - ctx->device_context.endpoints[ep_num-1].endpoint_f1.error_count = 3; - - device_endpoint->endpoint_transfer_ring = (trb*)allocate_in_page(xhci_mem_page, MAX_TRB_AMOUNT * sizeof(trb), ALIGN_64B, true, true); - device_endpoint->endpoint_transfer_cycle_bit = 1; - make_ring_link(device_endpoint->endpoint_transfer_ring, device_endpoint->endpoint_transfer_cycle_bit); - ctx->device_context.endpoints[ep_num-1].endpoint_f23.dcs = device_endpoint->endpoint_transfer_cycle_bit; - ctx->device_context.endpoints[ep_num-1].endpoint_f23.ring_ptr = ((uintptr_t)device_endpoint->endpoint_transfer_ring) >> 4; - ctx->device_context.endpoints[ep_num-1].endpoint_f4.average_trb_length = 8; - - device_endpoint->poll_endpoint = ep_num; - device_endpoint->poll_packetSize = endpoint->wMaxPacketSize; - - if (!issue_command((uintptr_t)ctx, 0, (device->slot_id << 24) | (TRB_TYPE_CONFIG_EP << 10))){ - kprintf_raw("[xHCI] Failed to configure endpoint %i",ep_num); - return false; - } - - kprintf_raw("[xHCI] Storing configuration for endpoint %i -> %i (%x)",ep_num,device_endpoint->poll_endpoint, (uintptr_t)device_endpoint); - - xhci_configure_endpoint(device->slot_id, device_endpoint); - - kprintf_raw("[xHCI] Returned from configuration for endpoint %i -> %i (%x)",ep_num,device_endpoint->poll_endpoint, (uintptr_t)device_endpoint); - - need_new_endpoint = true; - - break; - } - i += header->bLength; - } - - xhci_sync_events();//TODO: This is hacky af, we should have await use irqs entirely and we won't need to await anything anymore - - return true; - -} - -bool xhci_setup_device(uint16_t port){ - - kprintfv("[xHCI] detecting and activating the default device at %i port. Resetting port...",port); - reset_port(port); - kprintfv("[xHCI] Port speed %i", (uint32_t)global_device.ports[port].portsc.port_speed); - - if (!issue_command(0,0,TRB_TYPE_ENABLE_SLOT << 10)){ - kprintf_raw("[xHCI error] failed enable slot command"); - return false; - } - - xhci_usb_device *device = (xhci_usb_device*)allocate_in_page(xhci_mem_page, sizeof(xhci_usb_device), ALIGN_64B, true, true); - - device->slot_id = (global_device.event_ring[0].status >> 24) & 0xFF; - kprintfv("[xHCI] Slot id %x", device->slot_id); - - if (device->slot_id == 0){ - kprintf_raw("[xHCI error]: Wrong slot id 0"); - return false; - } - - device->transfer_cycle_bit = 1; - - xhci_input_context *ctx = (xhci_input_context*)allocate_in_page(xhci_mem_page, sizeof(xhci_input_context), ALIGN_64B, true, true); - device->ctx = ctx; - void* output_ctx = (void*)allocate_in_page(xhci_mem_page, 0x1000, ALIGN_64B, true, true); - kprintfv("[xHCI] Allocating output for context at %x", (uintptr_t)output_ctx); - - ctx->control_context.add_flags = 0b11; - - ctx->device_context.slot_f0.speed = global_device.ports[port].portsc.port_speed; - ctx->device_context.slot_f0.context_entries = 1; - ctx->device_context.slot_f1.root_hub_port_num = port + 1; - - ctx->device_context.endpoints[0].endpoint_f0.endpoint_state = 0;//Disabled - ctx->device_context.endpoints[0].endpoint_f1.endpoint_type = 4;//Type = control - ctx->device_context.endpoints[0].endpoint_f0.interval = 0; - ctx->device_context.endpoints[0].endpoint_f1.error_count = 3;//3 errors allowed - ctx->device_context.endpoints[0].endpoint_f1.max_packet_size = packet_size(ctx->device_context.slot_f0.speed);//Packet size. Guessed from port speed - - device->transfer_ring = (trb*)allocate_in_page(xhci_mem_page, MAX_TRB_AMOUNT * sizeof(trb), ALIGN_64B, true, true); - kprintfv("Transfer ring at %x",(uintptr_t)device->transfer_ring); - make_ring_link(device->transfer_ring, device->transfer_cycle_bit); - - ctx->device_context.endpoints[0].endpoint_f23.dcs = device->transfer_cycle_bit; - ctx->device_context.endpoints[0].endpoint_f23.ring_ptr = ((uintptr_t)device->transfer_ring) >> 4; - ctx->device_context.endpoints[0].endpoint_f4.average_trb_length = 8; - - ((uint64_t*)(uintptr_t)global_device.op->dcbaap)[device->slot_id] = (uintptr_t)output_ctx; - if (!issue_command((uintptr_t)device->ctx, 0, (device->slot_id << 24) | (TRB_TYPE_ADDRESS_DEV << 10))){ - kprintf_raw("[xHCI error] failed addressing device at slot %x",device->slot_id); - return false; - } - - xhci_device_context* context = (xhci_device_context*)(uintptr_t)(global_device.dcbaa[device->slot_id]); - - kprintfv("[xHCI] ADDRESS_DEVICE command issued. Received package size %i",context->endpoints[0].endpoint_f1.max_packet_size); - - usb_device_descriptor* descriptor = (usb_device_descriptor*)allocate_in_page(xhci_mem_page, sizeof(usb_device_descriptor), ALIGN_64B, true, true); - - if (!xhci_request_descriptor(device, false, USB_DEVICE_DESCRIPTOR, 0, 0, descriptor)){ - kprintf_raw("[xHCI error] failed to get device descriptor"); - return false; - } - - usb_string_language_descriptor* lang_desc = (usb_string_language_descriptor*)allocate_in_page(xhci_mem_page, sizeof(usb_string_language_descriptor), ALIGN_64B, true, true); - - bool use_lang_desc = true; - - if (!xhci_request_descriptor(device, false, USB_STRING_DESCRIPTOR, 0, 0, lang_desc)){ - kprintf_raw("[xHCI warning] failed to get language descriptor"); - use_lang_desc = false; - } - - kprintfv("[xHCI] Vendor %x",descriptor->idVendor); - kprintfv("[xHCI] Product %x",descriptor->idProduct); - kprintfv("[xHCI] USB version %x",descriptor->bcdUSB); - kprintfv("[xHCI] EP0 Max Packet Size: %x", descriptor->bMaxPacketSize0); - kprintfv("[xHCI] Configurations: %x", descriptor->bNumConfigurations); - if (use_lang_desc){ - //TODO: we want to maintain the strings so we can have USB device information, and rework it to silece the alignment warning - uint16_t langid = lang_desc->lang_ids[0]; - usb_string_descriptor* prod_name = (usb_string_descriptor*)allocate_in_page(xhci_mem_page, sizeof(usb_string_descriptor), ALIGN_64B, true, true); - if (xhci_request_descriptor(device, false, USB_STRING_DESCRIPTOR, descriptor->iProduct, langid, prod_name)){ - char name[128]; - if (utf16tochar(prod_name->unicode_string, name, sizeof(name))) { - kprintfv("[xHCI device] Product name: %s", (uint64_t)name); - } - } - usb_string_descriptor* man_name = (usb_string_descriptor*)allocate_in_page(xhci_mem_page, sizeof(usb_string_descriptor), ALIGN_64B, true, true); - if (xhci_request_descriptor(device, false, USB_STRING_DESCRIPTOR, descriptor->iManufacturer, langid, man_name)){ - char name[128]; - if (utf16tochar(man_name->unicode_string, name, sizeof(name))) { - kprintfv("[xHCI device] Manufacturer name: %s", (uint64_t)name); - } - } - usb_string_descriptor* ser_name = (usb_string_descriptor*)allocate_in_page(xhci_mem_page, sizeof(usb_string_descriptor), ALIGN_64B, true, true); - if (xhci_request_descriptor(device, false, USB_STRING_DESCRIPTOR, descriptor->iSerialNumber, langid, ser_name)){ - char name[128]; - if (utf16tochar(ser_name->unicode_string, name, sizeof(name))) { - kprintfv("[xHCI device] Serial: %s", (uint64_t)name); - } - } - } - - usb_configuration_descriptor* config = (usb_configuration_descriptor*)allocate_in_page(xhci_mem_page, sizeof(usb_configuration_descriptor), ALIGN_64B, true, true); - if (!xhci_request_sized_descriptor(device, false, USB_CONFIGURATION_DESCRIPTOR, 0, 0, 8, config)){ - kprintf_raw("[xHCI error] could not get config descriptor header"); - return false; - } - - if (!xhci_request_sized_descriptor(device, false, USB_CONFIGURATION_DESCRIPTOR, 0, 0, config->header.bLength, config)){ - kprintf_raw("[xHCI error] could not get full config descriptor"); - return false; - } - - if (!xhci_request_sized_descriptor(device, false, USB_CONFIGURATION_DESCRIPTOR, 0, 0, config->wTotalLength, config)){ - kprintf_raw("[xHCI error] could not get full config descriptor"); - return false; - } - - if (!xhci_get_configuration(config, device)){ - kprintf_raw("[xHCI error] failed to parse device configuration"); - return false; - } - - return true; -} - -bool xhci_input_init() { - uint64_t addr = find_pci_device(0x1B36, 0xD); - if (!addr){ - kprintf_raw("[PCI] xHCI device not found"); - return false; - } - - if (!xhci_init(&global_device, addr)){ - kprintf_raw("xHCI device initialization failed"); - return false; - } - - kprintfv("[xHCI] device initialized"); - - //TODO: we don't need this anymore, it's enough to handle port status changes - - for (uint16_t i = 0; i < global_device.max_ports; i++) - if (global_device.ports[i].portsc.ccs && global_device.ports[i].portsc.csc){ - if (!xhci_setup_device(i)){ - kprintf_raw("Failed to configure device at port %i",i); - return false; - } - break; - } - - return true; -} - -void xhci_handle_interrupt(){ - trb* ev = &global_device.event_ring[global_device.event_index]; - kprintfv("[xHCI] Interrupt with next event id %x. Awaited is %x", (ev->control & TRB_TYPE_MASK) >> 10, awaited_type); - uint32_t type = (ev->control & TRB_TYPE_MASK) >> 10; - uint64_t addr = ev->parameter; - if (type == awaited_type && (awaited_addr == 0 || (awaited_addr & 0xFFFFFFFFFFFFFFFF) == addr)) return;// Compatibility between our polling and interrupt, we'll need to get rid of this - kprintfv("[xHCI] Unhandled interrupt"); - switch (type){ - case TRB_TYPE_TRANSFER: - uint8_t slot_id = (ev->control & TRB_SLOT_MASK) >> 24; - uint8_t endpoint_id = (ev->control & TRB_ENDPOINT_MASK) >> 16; - kprintfv("Received input from slot %i endpoint %i",slot_id, endpoint_id); - xhci_process_input(slot_id, endpoint_id); - break; - case TRB_TYPE_PORT_STATUS_CHANGE: - kprintf_raw("[xHCI] Port status change. Ignored for now"); - global_device.interrupter->erdp = (uintptr_t)ev | (1 << 3);//Inform of latest processed event - global_device.interrupter->iman |= 1;//Clear interrupts - global_device.op->usbsts |= 1 << 3;//Clear interrupts - break; - } -} \ No newline at end of file diff --git a/kernel/input/xhci.cpp b/kernel/input/xhci.cpp new file mode 100644 index 00000000..a86d25d4 --- /dev/null +++ b/kernel/input/xhci.cpp @@ -0,0 +1,526 @@ +#include "xhci.hpp" +#include "USBManager.hpp" +#include "async.h" +#include "usb.hpp" +#include "pci.h" +#include "xhci_types.h" +#include "hw/hw.h" +#include "memory/memory_access.h" +#include "std/memfunctions.h" + +uint64_t awaited_addr; +uint32_t awaited_type; +#define AWAIT(addr, action, type) \ + ({ \ + awaited_addr = (uintptr_t)(addr); \ + awaited_type = (type); \ + interrupter->iman &= ~1; \ + action; \ + await_response((uintptr_t)(addr), (type)); \ + interrupter->iman |= 1; \ + }) + +#define kprintfv(fmt, ...) \ + ({ \ + if (verbose){\ + uint64_t _args[] = { __VA_ARGS__ }; \ + kprintf_args_raw((fmt), _args, sizeof(_args) / sizeof(_args[0])); \ + }\ + }) + +bool XHCIDriver::check_fatal_error() { + uint32_t sts = op->usbsts; + if (sts & (XHCI_USBSTS_HSE | XHCI_USBSTS_CE)) { + kprintf_raw("[xHCI ERROR] Fatal condition: USBSTS = %x", sts); + return true; + } + return false; +} + +#define CHECK_XHCI_FIELD(field) (op->field != 0 ? (kprintf_raw("[xHCI Error] wrong " #field " %x", op->field), false) : (kprintfv("[xHCI] Correct " #field " value"), true)) + +bool XHCIDriver::init(){ + uint64_t addr, mmio, mmio_size; + if (XHCI_BASE){ + addr = XHCI_BASE; + mmio = addr; + } else if (USE_PCI) { + addr = find_pci_device(0x1B36, 0xD); + } + if (!addr){ + kprintf_raw("[PCI] xHCI device not found"); + return false; + } + + kprintfv("[xHCI] init"); + if (USE_PCI){ + if (!(*(uint16_t*)(addr + 0x06) & (1 << 4))){ + kprintfv("[xHCI] Wrong capabilities list"); + return false; + } + + pci_enable_device(addr); + + if (!pci_setup_bar(addr, 0, &mmio, &mmio_size)){ + kprintfv("[xHCI] BARs not set up"); + return false; + } + + pci_register(mmio, mmio_size); + + uint8_t interrupts_ok = pci_setup_interrupts(addr, XHCI_IRQ, 1); + switch(interrupts_ok){ + case 0: + kprintf_raw("[xHCI] Failed to setup interrupts"); + return false; + case 1: + kprintf_raw("[xHCI] Interrupts setup with MSI-X %i",XHCI_IRQ); + break; + default: + kprintf_raw("[xHCI] Interrupts setup with MSI %i",XHCI_IRQ); + break; + } + + kprintfv("[xHCI] BARs set up @ %x (%x)",mmio,mmio_size); + } + + cap = (xhci_cap_regs*)(uintptr_t)mmio; + kprintfv("[xHCI] caplength %x",cap->caplength); + uint64_t op_base = mmio + cap->caplength; + op = (xhci_op_regs*)(uintptr_t)op_base; + ports = (xhci_port_regs*)((uintptr_t)op_base + 0x400); + db_base = mmio + (cap->dboff & ~0x1F); + rt_base = mmio + (cap->rtsoff & ~0x1F); + + kprintfv("[xHCI] Resetting controller"); + op->usbcmd &= ~1; + while (op->usbcmd & 1); + kprintfv("[xHCI] Clear complete"); + + op->usbcmd |= (1 << 1); + while (op->usbcmd & 1); + kprintfv("[xHCI] Reset complete"); + + while (op->usbsts & (1 << 11)); + kprintfv("[xHCI] Device ready"); + + if (!CHECK_XHCI_FIELD(usbcmd)) return false; + if (!CHECK_XHCI_FIELD(dnctrl)) return false; + if (!CHECK_XHCI_FIELD(crcr)) return false; + if (!CHECK_XHCI_FIELD(dcbaap)) return false; + if (!CHECK_XHCI_FIELD(config)) return false; + + command_ring.cycle_bit = 1; + + max_device_slots = cap->hcsparams1 & 0xFF; + max_ports = (cap->hcsparams1 >> 24) & 0xFF; + + usb_manager = new USBManager(max_device_slots); + + uint16_t erst_max = ((cap->hcsparams2 >> 4) & 0xF); + + kprintfv("[xHCI] ERST Max: 2^%i",erst_max); + + op->dnctrl = 0xFFFF;//Enable device notifications + + op->config = max_device_slots; + kprintfv("[xHCI] %i device slots", max_device_slots); + + mem_page = alloc_page(0x1000, true, true, false); + + uintptr_t dcbaap_addr = (uintptr_t)allocate_in_page(mem_page, (max_device_slots + 1) * sizeof(uintptr_t), ALIGN_64B, true, true); + + op->dcbaap = dcbaap_addr; + + op->pagesize = 0b1;//4KB page size + + uint32_t scratchpad_count = ((cap->hcsparams2 >> 27) & 0x1F); + + dcbaap = (uintptr_t*)dcbaap_addr; + + uint64_t* scratchpad_array = (uint64_t*)allocate_in_page(mem_page, (scratchpad_count == 0 ? 1 : scratchpad_count) * sizeof(uintptr_t), ALIGN_64B, true, true); + for (uint32_t i = 0; i < scratchpad_count; i++) + scratchpad_array[i] = (uint64_t)allocate_in_page(mem_page, 0x1000, ALIGN_64B, true, true); + dcbaap[0] = (uint64_t)scratchpad_array; + + kprintfv("[xHCI] dcbaap assigned at %x with %i scratchpads",dcbaap_addr,scratchpad_count); + + command_ring.ring = (trb*)allocate_in_page(mem_page, MAX_TRB_AMOUNT * sizeof(trb), ALIGN_64B, true, true); + + op->crcr = (uintptr_t)command_ring.ring | command_ring.cycle_bit; + + make_ring_link(command_ring.ring, command_ring.cycle_bit); + + kprintfv("[xHCI] command ring allocated at %x. crcr now %x",(uintptr_t)command_ring.ring, op->crcr); + + if (!enable_events()) + return false; + + kprintfv("[xHCI] event configuration finished"); + + op->usbcmd |= (1 << 2);//Interrupt enable + op->usbcmd |= 1;//Run + while ((op->usbsts & 0x1)); + + endpoint_map = IndexMap(255 * 5); + context_map = IndexMap(255 * 5); + + kprintfv("[xHCI] Init complete with usbcmd %x, usbsts %x",op->usbcmd, op->usbsts); + + if (check_fatal_error()) return false; + + for (uint16_t i = 0; i < max_ports; i++) + if (ports[i].portsc.ccs && ports[i].portsc.csc){ + if (!port_reset(i)){ + kprintf("[xHCI] Failed to reset port %i",i); + return false; + } + if (!setup_device(0,i)){ + kprintf_raw("[xHCI] Failed to configure device at port %i",i); + return false; + } + } + + return true; + +} + +bool XHCIDriver::port_reset(uint16_t port){ + + xhci_port_regs* port_info = &ports[port]; + + if (port_info->portsc.pp == 0){ + port_info->portsc.pp = 1; + + //Read back after delay to ensure + // if (port_info->portsc.pp == 0){ + // kprintf_raw("[xHCI error] failed to power on port %i",port); + // return false; + // } + } + + port_info->portsc.csc = 1; + port_info->portsc.pec = 1; + port_info->portsc.prc = 1; + + //TODO: if usb3 + //portsc.wpr = 1; + //else + + return AWAIT(0, { + port_info->portsc.pr = 1; + },TRB_TYPE_PORT_STATUS_CHANGE); +} + +bool XHCIDriver::enable_events(){ + kprintfv("[xHCI] Allocating ERST"); + interrupter = (xhci_interrupter*)(rt_base + 0x20); + + uint64_t ev_ring = (uintptr_t)allocate_in_page(mem_page, MAX_TRB_AMOUNT * sizeof(trb), ALIGN_64B, true, true); + uint64_t erst_addr = (uintptr_t)allocate_in_page(mem_page, MAX_ERST_AMOUNT * sizeof(erst_entry), ALIGN_64B, true, true); + erst_entry* erst = (erst_entry*)erst_addr; + + erst->ring_base = ev_ring; + erst->ring_size = MAX_TRB_AMOUNT; + + kprintfv("[xHCI] ERST ring_base: %x", ev_ring); + kprintfv("[xHCI] ERST ring_size: %x", erst[0].ring_size); + event_ring.ring = (trb*)ev_ring; + event_ring.cycle_bit = 1; + + kprintfv("[xHCI] Interrupter register @ %x", rt_base + 0x20); + + interrupter->erstsz = 1; + kprintfv("[xHCI] ERSTSZ set to: %x", interrupter->erstsz); + + interrupter->erdp = ev_ring; + interrupter->erstba = erst_addr; + kprintfv("[xHCI] ERSTBA set to: %x", interrupter->erstba); + + kprintfv("[xHCI] ERDP set to: %x", interrupter->erdp); + + interrupter->iman |= 1 << 1;//Enable interrupt + + op->usbsts = 1 << 3;//Enable interrupts + interrupter->iman |= 1;//Clear pending interrupts + + use_interrupts = true; + + return !check_fatal_error(); +} + +void XHCIDriver::make_ring_link_control(trb* ring, bool cycle){ + ring[MAX_TRB_AMOUNT-1].control = + (TRB_TYPE_LINK << 10) + | (1 << 1) // Toggle Cycle + | cycle; +} + +void XHCIDriver::make_ring_link(trb* ring, bool cycle){ + ring[MAX_TRB_AMOUNT-1].parameter = (uintptr_t)ring; + ring[MAX_TRB_AMOUNT-1].status = 0; + make_ring_link_control(ring, cycle); +} + +void XHCIDriver::ring_doorbell(uint32_t slot, uint32_t endpoint) { + volatile uint32_t* db = (uint32_t*)(uintptr_t)(db_base + (slot << 2)); + kprintfv("[xHCI] Ringing doorbell at %x with value %x", db_base + (slot << 2),endpoint); + *db = endpoint; +} + +bool XHCIDriver::await_response(uint64_t command, uint32_t type){ + while (1){ + if (check_fatal_error()){ + kprintf_raw("[xHCI error] USBSTS value %x",op->usbsts); + awaited_type = 0; + return false; + } + for (; event_ring.index < MAX_TRB_AMOUNT; event_ring.index++){ + last_event = &event_ring.ring[event_ring.index]; + if (!wait(&last_event->control, event_ring.cycle_bit, true, 2000)){ + awaited_type = 0; + return false; + } + // kprintf_raw("[xHCI] A response at %i of type %x as a response to %x",event_ring.index, (last_event->control & TRB_TYPE_MASK) >> 10, last_event->parameter); + // kprintf_raw("[xHCI] %x vs %x = %i and %x vs %x = %i", (ev->control & TRB_TYPE_MASK) >> 10, type, (ev->control & TRB_TYPE_MASK) >> 10 == type, ev->parameter, command, command == 0 || ev->parameter == command); + if (event_ring.index == MAX_TRB_AMOUNT - 1){ + event_ring.index = 0; + event_ring.cycle_bit = !event_ring.cycle_bit; + } + if ((((last_event->control & TRB_TYPE_MASK) >> 10) == type) && (command == 0 || last_event->parameter == command)){ + uint8_t completion_code = (last_event->status >> 24) & 0xFF; + if (completion_code != 1) + kprintf("[xHCI error] wrong status %i on command type %x", completion_code, ((last_event->control & TRB_TYPE_MASK) >> 10) ); + interrupter->erdp = (uintptr_t)&event_ring.ring[event_ring.index+1] | (1 << 3);//Inform of latest processed event + interrupter->iman |= 1;//Clear interrupts + op->usbsts |= 1 << 3;//Clear interrupts + awaited_type = 0; + event_ring.index++; + return completion_code == 1; + } + } + } + awaited_type = 0; + return false; +} + +bool XHCIDriver::issue_command(uint64_t param, uint32_t status, uint32_t control){ + trb* cmd = &command_ring.ring[command_ring.index++]; + cmd->parameter = param; + cmd->status = status; + cmd->control = control | command_ring.cycle_bit; + + uint64_t cmd_addr = (uintptr_t)cmd; + kprintfv("[xHCI] issuing command with control: %x from %x", cmd->control, cmd_addr); + if (command_ring.index == MAX_TRB_AMOUNT - 1){ + make_ring_link_control(command_ring.ring, command_ring.cycle_bit); + command_ring.cycle_bit = !command_ring.cycle_bit; + command_ring.index = 0; + } + return AWAIT(cmd_addr, {ring_doorbell(0, 0);}, TRB_TYPE_COMMAND_COMPLETION); +} + +bool XHCIDriver::setup_device(uint8_t address, uint16_t port){ + + if (!issue_command(0,0,TRB_TYPE_ENABLE_SLOT << 10)){ + kprintf_raw("[xHCI error] failed enable slot command"); + return false; + } + + address = (last_event->control >> 24) & 0xFF; + kprintfv("[xHCI] Slot id %x", address); + + if (address == 0){ + kprintf_raw("[xHCI error]: Wrong slot id 0"); + return false; + } + + xhci_ring *transfer_ring = &endpoint_map[address << 8]; + + transfer_ring->cycle_bit = 1; + + xhci_input_context *ctx = (xhci_input_context*)allocate_in_page(mem_page, sizeof(xhci_input_context), ALIGN_64B, true, true); + kprintfv("[xHCI] Allocating input context at %x", (uintptr_t)ctx); + context_map[address << 8] = ctx; + void* output_ctx = (void*)allocate_in_page(mem_page, 0x1000, ALIGN_64B, true, true); + kprintfv("[xHCI] Allocating output for context at %x", (uintptr_t)output_ctx); + + ctx->control_context.add_flags = 0b11; + + ctx->device_context.slot_f0.speed = ports[port].portsc.port_speed; + ctx->device_context.slot_f0.context_entries = 1; + ctx->device_context.slot_f1.root_hub_port_num = port + 1; + + ctx->device_context.endpoints[0].endpoint_f0.endpoint_state = 0;//Disabled + ctx->device_context.endpoints[0].endpoint_f1.endpoint_type = 4;//Type = control + ctx->device_context.endpoints[0].endpoint_f0.interval = 0; + ctx->device_context.endpoints[0].endpoint_f1.error_count = 3; + ctx->device_context.endpoints[0].endpoint_f1.max_packet_size = packet_size(ctx->device_context.slot_f0.speed);//Packet size. Guessed from port speed + + transfer_ring->ring = (trb*)allocate_in_page(mem_page, MAX_TRB_AMOUNT * sizeof(trb), ALIGN_64B, true, true); + kprintfv("Transfer ring at %x %i",(uintptr_t)transfer_ring->ring, address << 8); + make_ring_link(transfer_ring->ring, transfer_ring->cycle_bit); + + ctx->device_context.endpoints[0].endpoint_f23.dcs = transfer_ring->cycle_bit; + ctx->device_context.endpoints[0].endpoint_f23.ring_ptr = ((uintptr_t)transfer_ring->ring) >> 4; + ctx->device_context.endpoints[0].endpoint_f4.average_trb_length = sizeof(trb); + + dcbaap[address] = (uintptr_t)output_ctx; + + return USBDriver::setup_device(address, port); +} + +bool XHCIDriver::request_sized_descriptor(uint8_t address, uint8_t endpoint, uint8_t rType, uint8_t request, uint8_t type, uint16_t descriptor_index, uint16_t wIndex, uint16_t descriptor_size, void *out_descriptor){ + usb_setup_packet packet = { + .bmRequestType = rType, + .bRequest = request, + .wValue = (type << 8) | descriptor_index, + .wIndex = wIndex, + .wLength = descriptor_size + }; + + bool is_in = (rType & 0x80) != 0; + + xhci_ring *transfer_ring = &endpoint_map[address << 8 | endpoint]; + + trb* setup_trb = &transfer_ring->ring[transfer_ring->index++]; + memcpy(&setup_trb->parameter, &packet, sizeof(packet)); + setup_trb->status = sizeof(usb_setup_packet); + //bit 4 = chain. Bit 16 direction (3 = IN, 2 = OUT, 0 = NO DATA) + setup_trb->control = (3 << 16) | (TRB_TYPE_SETUP_STAGE << 10) | (1 << 6) | (1 << 4) | transfer_ring->cycle_bit; + + trb* data = &transfer_ring->ring[transfer_ring->index++]; + data->parameter = (uintptr_t)out_descriptor; + data->status = packet.wLength; + //bit 16 = direction + data->control = (1 << 16) | (TRB_TYPE_DATA_STAGE << 10) | (0 << 4) | transfer_ring->cycle_bit; + + trb* status_trb = &transfer_ring->ring[transfer_ring->index++]; + status_trb->parameter = 0; + status_trb->status = 0; + //bit 5 = interrupt-on-completion + status_trb->control = (TRB_TYPE_STATUS_STAGE << 10) | (1 << 5) | transfer_ring->cycle_bit; + + if (transfer_ring->index == MAX_TRB_AMOUNT - 1){ + make_ring_link_control(transfer_ring->ring, transfer_ring->cycle_bit); + transfer_ring->cycle_bit = !transfer_ring->cycle_bit; + transfer_ring->index = 0; + } + + return AWAIT((uintptr_t)status_trb, {ring_doorbell(address, 1);}, TRB_TYPE_TRANSFER); +} + +uint8_t XHCIDriver::address_device(uint8_t address){ + xhci_input_context* ctx = context_map[address << 8]; + kprintfv("Addressing device %i with context %x", address, (uintptr_t)ctx); + if (!issue_command((uintptr_t)ctx, 0, (address << 24) | (TRB_TYPE_ADDRESS_DEV << 10))){ + kprintf_raw("[xHCI error] failed addressing device at slot %x",address); + return 0; + } + xhci_device_context* context = (xhci_device_context*)dcbaap[address]; + + kprintfv("[xHCI] ADDRESS_DEVICE %i command issued. dcbaap %x Received packet size %i",address, (uintptr_t)dcbaap, context->endpoints[0].endpoint_f1.max_packet_size); + return address; +} + +uint8_t XHCIDriver::get_ep_type(usb_endpoint_descriptor* descriptor) { + return (descriptor->bEndpointAddress & 0x80 ? 1 << 2 : 0) | (descriptor->bmAttributes & 0x3); +} + +bool XHCIDriver::configure_endpoint(uint8_t address, usb_endpoint_descriptor *endpoint, uint8_t configuration_value, xhci_device_types type){ + kprintfv("[xHCI] endpoint address %x",endpoint->bEndpointAddress); + uint8_t ep_address = endpoint->bEndpointAddress; + uint8_t ep_dir = (ep_address & 0x80) ? 1 : 0; // 1 IN, 0 OUT + uint8_t ep_num = ((ep_address & 0x0F) * 2) + ep_dir; + + uint8_t ep_type = endpoint->bmAttributes & 0x03; // 0 = Control, 1 = Iso, 2 = Bulk, 3 = Interrupt + kprintf_raw("[xHCI] endpoint %i info. Direction %i type %i",ep_num, ep_dir, ep_type); + + xhci_input_context* ctx = context_map[address << 8]; + + + ctx->control_context.add_flags = (1 << 0) | (1 << ep_num); + ctx->device_context.slot_f0.context_entries = 2; //2 entries: EP0 + EP1 + ctx->device_context.endpoints[ep_num-1].endpoint_f0.interval = endpoint->bInterval; + + ctx->device_context.endpoints[ep_num-1].endpoint_f0.endpoint_state = 0; + ctx->device_context.endpoints[ep_num-1].endpoint_f1.endpoint_type = get_ep_type(endpoint); + ctx->device_context.endpoints[ep_num-1].endpoint_f1.max_packet_size = endpoint->wMaxPacketSize; + ctx->device_context.endpoints[ep_num-1].endpoint_f4.max_esit_payload_lo = endpoint->wMaxPacketSize; + ctx->device_context.endpoints[ep_num-1].endpoint_f1.error_count = 3; + + xhci_ring *ep_ring = &endpoint_map[address << 8 | ep_num]; + + ep_ring->ring = (trb*)allocate_in_page(mem_page, MAX_TRB_AMOUNT * sizeof(trb), ALIGN_64B, true, true); + ep_ring->cycle_bit = 1; + make_ring_link(ep_ring->ring, ep_ring->cycle_bit); + ctx->device_context.endpoints[ep_num-1].endpoint_f23.dcs = ep_ring->cycle_bit; + ctx->device_context.endpoints[ep_num-1].endpoint_f23.ring_ptr = ((uintptr_t)ep_ring->ring) >> 4; + ctx->device_context.endpoints[ep_num-1].endpoint_f4.average_trb_length = 8; + + if (!issue_command((uintptr_t)ctx, 0, (address << 24) | (TRB_TYPE_CONFIG_EP << 10))){ + kprintf_raw("[xHCI] Failed to configure endpoint %i for address %i",ep_num,address); + return false; + } + + usb_manager->register_endpoint(address, ep_num, type, endpoint->wMaxPacketSize); + usb_manager->request_data(address, ep_num, this); + + return true; +} + +void XHCIDriver::handle_hub_routing(uint8_t hub, uint8_t port){ + //TODO: hubs +} + +bool XHCIDriver::poll(uint8_t address, uint8_t endpoint, void *out_buf, uint16_t size){ + xhci_ring *ep_ring = &endpoint_map[address << 8 | endpoint]; + + trb* ev = &ep_ring->ring[ep_ring->index++]; + + ev->parameter = (uintptr_t)out_buf; + ev->status = size; + ev->control = (TRB_TYPE_NORMAL << 10) | (1 << 5) | ep_ring->cycle_bit; + + if (ep_ring->index == MAX_TRB_AMOUNT - 1){ + make_ring_link_control(ep_ring->ring, ep_ring->cycle_bit); + ep_ring->cycle_bit = !ep_ring->cycle_bit; + ep_ring->index = 0; + } + + ring_doorbell(address, endpoint); + + return true; +} + +void XHCIDriver::handle_interrupt(){ + trb* ev = &event_ring.ring[event_ring.index]; + if (!((ev->control & 1) == event_ring.cycle_bit)) return; + uint32_t type = (ev->control & TRB_TYPE_MASK) >> 10; + uint64_t addr = ev->parameter; + if (type == awaited_type && (awaited_addr == 0 || (awaited_addr & 0xFFFFFFFFFFFFFFFF) == addr)) + return; + kprintfv("[xHCI] >>> Unhandled interrupt %i %x",event_ring.index,type); + switch (type){ + case TRB_TYPE_TRANSFER: { + uint8_t slot_id = (ev->control & TRB_SLOT_MASK) >> 24; + uint8_t endpoint_id = (ev->control & TRB_ENDPOINT_MASK) >> 16; + kprintfv("Received input from slot %i endpoint %i",slot_id, endpoint_id); + + usb_manager->process_data(slot_id,endpoint_id, this); + break; + } + case TRB_TYPE_PORT_STATUS_CHANGE: { + kprintfv("[xHCI] Port status change. Ignored for now"); + break; + } + } + event_ring.index++; + if (event_ring.index == MAX_TRB_AMOUNT - 1){ + event_ring.index = 0; + event_ring.cycle_bit = !event_ring.cycle_bit; + } + interrupter->erdp = (uintptr_t)&event_ring.ring[event_ring.index] | (1 << 3);//Inform of latest processed event + interrupter->iman |= 1;//Clear interrupts + op->usbsts |= 1 << 3;//Clear interrupts +} \ No newline at end of file diff --git a/kernel/input/xhci.h b/kernel/input/xhci.h deleted file mode 100644 index 2b796c5f..00000000 --- a/kernel/input/xhci.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif -#include "types.h" -#include "xhci_types.h" - -void xhci_enable_verbose(); -bool xhci_input_init(); - -void make_ring_link_control(trb* ring, bool cycle); -void ring_doorbell(uint32_t slot, uint32_t endpoint); -bool xhci_await_response(uint64_t command, uint32_t type); - -void xhci_sync_events(); -void xhci_handle_interrupt(); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/kernel/input/xhci.hpp b/kernel/input/xhci.hpp new file mode 100644 index 00000000..234bb97a --- /dev/null +++ b/kernel/input/xhci.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include "usb.hpp" +#include "xhci_types.h" + +typedef struct xhci_ring { + trb* ring; + uint8_t cycle_bit; + uint32_t index; +} xhci_ring; + +class XHCIDriver : public USBDriver { +public: + XHCIDriver() = default; + bool init() override; + bool request_sized_descriptor(uint8_t address, uint8_t endpoint, uint8_t rType, uint8_t request, uint8_t type, uint16_t descriptor_index, uint16_t wIndex, uint16_t descriptor_size, void *out_descriptor) override; + uint8_t address_device(uint8_t address) override; + bool configure_endpoint(uint8_t address, usb_endpoint_descriptor *endpoint, uint8_t configuration_value, xhci_device_types type) override; + void handle_hub_routing(uint8_t hub, uint8_t port) override; + bool poll(uint8_t address, uint8_t endpoint, void *out_buf, uint16_t size) override; + bool setup_device(uint8_t address, uint16_t port) override; + void handle_interrupt() override; + ~XHCIDriver() = default; +private: + bool check_fatal_error(); + bool enable_events(); + + bool port_reset(uint16_t port); + + bool issue_command(uint64_t param, uint32_t status, uint32_t control); + void ring_doorbell(uint32_t slot, uint32_t endpoint); + bool await_response(uint64_t command, uint32_t type); + uint8_t get_ep_type(usb_endpoint_descriptor* descriptor); + + void make_ring_link_control(trb* ring, bool cycle); + void make_ring_link(trb* ring, bool cycle); + + xhci_cap_regs* cap; + xhci_op_regs* op; + xhci_port_regs* ports; + xhci_interrupter* interrupter; + uintptr_t db_base; + uintptr_t rt_base; + uintptr_t* dcbaap; + uint16_t max_device_slots; + uint16_t max_ports; + + xhci_ring command_ring; + xhci_ring event_ring; + + trb* last_event; + + IndexMap endpoint_map; + IndexMap context_map; +}; \ No newline at end of file diff --git a/kernel/input/xhci_bridge.cpp b/kernel/input/xhci_bridge.cpp deleted file mode 100644 index 4d192d84..00000000 --- a/kernel/input/xhci_bridge.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "xhci_bridge.h" -#include "memory/kalloc.h" -#include "input_dispatch.h" -#include "memory/page_allocator.h" -#include "xHCIManager.hpp" -#include "xHCIKeyboard.hpp" - -xHCIManager *xhci_manager; - -void xhci_bridge_request_data(uint8_t slot_id, uint8_t endpoint_id) { - xhci_manager->request_data(slot_id,endpoint_id); -} - -void xhci_process_input(uint8_t slot_id, uint8_t endpoint_id){ - xhci_manager->process_data(slot_id,endpoint_id); -} - -void xhci_initialize_manager(uint32_t capacity){ - xhci_manager = new xHCIManager(capacity); -} - -void xhci_configure_device(uint8_t slot_id, xhci_usb_device *device){ - xhci_manager->register_device(slot_id,device); -} - -void xhci_configure_endpoint(uint8_t slot_id, xhci_usb_device_endpoint *endpoint){ - xhci_manager->register_endpoint(slot_id,endpoint); -} \ No newline at end of file diff --git a/kernel/input/xhci_bridge.h b/kernel/input/xhci_bridge.h deleted file mode 100644 index dabb7f08..00000000 --- a/kernel/input/xhci_bridge.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include "xhci.h" -#include "xhci_types.h" - -#include "keypress.h" - -void xhci_bridge_request_data(uint8_t slot_id, uint8_t endpoint_id); -void xhci_process_input(uint8_t slot_id, uint8_t endpoint_id); - -void xhci_initialize_manager(uint32_t capacity); -void xhci_configure_device(uint8_t slot_id, xhci_usb_device *device); -void xhci_configure_endpoint(uint8_t slot_id, xhci_usb_device_endpoint *endpoint); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/kernel/input/xhci_types.h b/kernel/input/xhci_types.h index 5151afe5..34484fac 100644 --- a/kernel/input/xhci_types.h +++ b/kernel/input/xhci_types.h @@ -354,7 +354,6 @@ typedef struct { uint32_t transfer_index; trb* transfer_ring; uint32_t slot_id; - uint8_t interface_protocol;//TODO: support multiple xhci_input_context* ctx; } xhci_usb_device; diff --git a/kernel/kernel.c b/kernel/kernel.c index da6362a9..189e4ac1 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -1,6 +1,7 @@ #include "console/kio.h" #include "console/serial/uart.h" #include "graph/graphics.h" +#include "hw/hw.h" #include "pci.h" #include "kstring.h" #include "console/kconsole/kconsole.h" @@ -11,37 +12,43 @@ #include "process/scheduler.h" #include "filesystem/disk.h" #include "kernel_processes/boot/bootprocess.h" -#include "input/xhci_bridge.h" -#include "input/xhci.h" +#include "input/input_dispatch.h" #include "kernel_processes/monitor/monitor_processes.h" #include "networking/processes/net_proc.h" #include "memory/page_allocator.h" #include "networking/network.h" void kernel_main() { + + detect_hardware(); mmu_alloc(); // mmu_enable_verbose(); enable_uart(); - kprintf("UART output enabled"); + kprintf_l("UART output enabled"); // enable_talloc_verbose(); set_exception_vectors(); - kprintf("Exception vectors set"); + kprintf_l("Exception vectors set"); + + print_hardware(); page_allocator_init(); // page_alloc_enable_verbose(); - kprintf("Initializing kernel..."); + kprintf_l("Initializing kernel..."); init_main_process(); - kprintf("Preparing for draw"); + kprintf_l("Preparing for draw"); gpu_size screen_size = {1080,720}; irq_init(); kprintf("Interrupts initialized"); enable_interrupt(); + + kprintf_l("Initializing GPU"); + gpu_init(screen_size); kprintf("GPU initialized"); @@ -53,30 +60,26 @@ void kernel_main() { panic("Disk initialization failure"); // xhci_enable_verbose(); - if (!xhci_input_init()){ - panic("Input initialization failure"); - } + if (!input_init()) + panic("Input initialization error"); - if (!network_init()) - panic("Network initialization failure"); + bool network_available = network_init(); mmu_init(); - kprintf("MMU Mapped"); + kprintf_l("MMU Mapped"); if (!disk_init()) - panic("Disk read failure"); - - kprintf("Kernel initialization finished"); + panic("Disk read failure"); - kprintf("Starting processes"); + kprintf_l("Kernel initialization finished"); - // translate_enable_verbose(); + kprintf_l("Starting processes"); - launch_net_process(); + if (network_available) launch_net_process(); init_bootprocess(); - kprintf("Starting scheduler"); + kprintf_l("Starting scheduler"); disable_interrupt(); start_scheduler(); diff --git a/kernel/kernel_processes/boot/login_screen.c b/kernel/kernel_processes/boot/login_screen.c index d08315b8..45f842eb 100644 --- a/kernel/kernel_processes/boot/login_screen.c +++ b/kernel/kernel_processes/boot/login_screen.c @@ -69,7 +69,7 @@ void login_screen(){ char key = kp.keys[i]; if (hid_keycode_to_char[(uint8_t)key]){ if (key == KEY_ENTER){ - if (strcmp(buf,default_pwd) == 0){ + if (strcmp(buf,default_pwd, false) == 0){ free(s.data,s.mem_length); free(title.data,title.mem_length); free(subtitle.data,subtitle.mem_length); diff --git a/kernel/kernel_processes/kprocess_loader.c b/kernel/kernel_processes/kprocess_loader.c index 1868acad..47f57577 100644 --- a/kernel/kernel_processes/kprocess_loader.c +++ b/kernel/kernel_processes/kprocess_loader.c @@ -30,7 +30,7 @@ process_t *create_kernel_process(const char *name, void (*func)()){ proc->sp = proc->stack; proc->pc = (uintptr_t)func; - kprintf_raw("Kernel process allocated with address at %x, stack at %x, heap at %x",proc->pc, proc->sp, proc->heap); + kprintf_raw("Kernel process %s allocated with address at %x, stack at %x, heap at %x", (uintptr_t)name, proc->pc, proc->sp, proc->heap); proc->spsr = 0x205; proc->state = READY; diff --git a/kernel/kernel_processes/windows/desktop.cpp b/kernel/kernel_processes/windows/desktop.cpp index 11150a2b..85884f3b 100644 --- a/kernel/kernel_processes/windows/desktop.cpp +++ b/kernel/kernel_processes/windows/desktop.cpp @@ -28,16 +28,20 @@ uint16_t Desktop::find_extension(char *path){ Desktop::Desktop() { entries = Array(9); string_list *list = list_directory_contents("/redos/user/"); - char* reader = (char*)list->array; - for (uint32_t i = 0; i < list->count; i++){ - char *file = reader; - string fullpath = string_format("/redos/user/%s",(uintptr_t)file); - string name = string_ca_max(file,find_extension(file)); - string ext = string_l(file + find_extension(file)); - if (strcmp(ext.data,".elf") == 0) - add_entry(name.data, ext.data, fullpath.data); - while (*reader) reader++; - reader++; + if (list){ + char* reader = (char*)list->array; + for (uint32_t i = 0; i < list->count; i++){ + char *file = reader; + string fullpath = string_format("/redos/user/%s",(uintptr_t)file); + string name = string_ca_max(file,find_extension(file)); + string ext = string_l(file + find_extension(file)); + if (strcmp(ext.data,".elf", true) == 0){ + kprintf("Extension %s matches .elf", (uintptr_t)ext.data); + add_entry(name.data, ext.data, fullpath.data); + } + while (*reader) reader++; + reader++; + } } single_label = new Label(); @@ -55,6 +59,7 @@ void Desktop::draw_desktop(){ keypress kp; gpu_point old_selected = selected; while (sys_read_input_current(&kp)){ + //TODO: there's a crash when moving in the desktop with no processes loaded. Memcpy for (int i = 0; i < 6; i++){ char key = kp.keys[i]; if (key == KEY_ENTER){ @@ -112,12 +117,17 @@ void Desktop::activate_current(){ uint32_t index = (selected.y * MAX_COLS) + selected.x; if (index < entries.size()){ - if (strcmp(".elf",entries[index].ext) != 0){ + if (strcmp(".elf",entries[index].ext, true) != 0){ kprintf("Wrong executable format. Must be .elf"); return; } + kprintf("File path %s",(uintptr_t)entries[index].path); void *file = read_file(entries[index].path); active_proc = load_elf_file(entries[index].name, file); + if (!active_proc){ + kprintf("Failed to read ELF file"); + return; + } process_active = true; sys_set_focus(active_proc->id); } diff --git a/kernel/kstring.c b/kernel/kstring.c index aca1461b..3cfe197b 100644 --- a/kernel/kstring.c +++ b/kernel/kstring.c @@ -100,7 +100,7 @@ kstring kstring_from_bin(uint64_t value) { } bool kstring_equals(kstring a, kstring b) { - return strcmp(a.data,b.data) == 0; + return strcmp(a.data,b.data, false) == 0; } kstring kstring_format_args(const char *fmt, const uint64_t *args, uint32_t arg_count) { diff --git a/kernel/linker.ld b/kernel/linker.ld index db674661..543b8d78 100644 --- a/kernel/linker.ld +++ b/kernel/linker.ld @@ -1,14 +1,22 @@ ENTRY(_start) SECTIONS { - . = 0x41000000; + . = LOAD_ADDR; kernel_start = .; .boot . : { boot.o(.text) } .text : { *(EXCLUDE_FILE(shared/*.o) .text .text.[!p]*) } .data : { *(.data) } - .bss : { *(.bss COMMON) } + __bss_start = .; + .bss : + { + bss = .; + *(.bss) + } + . = ALIGN(4096); /* align to page size */ + __bss_end = .; + __bss_size = __bss_end - __bss_start; .vectors : { KEEP(*(.vectors)) } . = ALIGN(16); diff --git a/kernel/mailbox/mailbox.c b/kernel/mailbox/mailbox.c new file mode 100644 index 00000000..ac52f2e1 --- /dev/null +++ b/kernel/mailbox/mailbox.c @@ -0,0 +1,15 @@ +#include "mailbox.h" + +int mailbox_call(volatile uint32_t* mbox, uint8_t channel) { + uint32_t addr = ((uint32_t)(uintptr_t)mbox) & ~0xF; + + while (MBOX_STATUS & MBOX_FULL); + MBOX_WRITE = addr | (channel & 0xF); + + while (1) { + while (MBOX_STATUS & MBOX_EMPTY); + uint32_t resp = MBOX_READ; + if ((resp & 0xF) == channel && (resp & ~0xF) == addr) + return mbox[1] == 0x80000000; + } +} \ No newline at end of file diff --git a/kernel/mailbox/mailbox.h b/kernel/mailbox/mailbox.h new file mode 100644 index 00000000..bd28d6c7 --- /dev/null +++ b/kernel/mailbox/mailbox.h @@ -0,0 +1,21 @@ +#pragma once + +#include "types.h" +#include "hw/hw.h" + +#define MAILBOX_BASE (MMIO_BASE + 0xB880) + +#define MBOX_READ (*(volatile uint32_t*)(MAILBOX_BASE + 0x00)) +#define MBOX_STATUS (*(volatile uint32_t*)(MAILBOX_BASE + 0x18)) +#define MBOX_WRITE (*(volatile uint32_t*)(MAILBOX_BASE + 0x20)) + +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 + +#ifdef __cplusplus +extern "C" { +#endif +int mailbox_call(volatile uint32_t* mbox, uint8_t channel); +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/kernel/memory/kalloc.c b/kernel/memory/kalloc.c index 089f7ee0..3fd18caa 100644 --- a/kernel/memory/kalloc.c +++ b/kernel/memory/kalloc.c @@ -2,6 +2,7 @@ #include "types.h" #include "exceptions/exception_handler.h" #include "console/kio.h" +#include "hw/hw.h" #include "dtb.h" #include "console/serial/uart.h" #include "memory/memory_access.h" @@ -16,12 +17,12 @@ static uint64_t calculated_ram_end = 0; FreeBlock* temp_free_list = 0; -#define PCI_MMIO_BASE 0x10010000 -#define PCI_MMIO_LIMIT 0x1FFFFFFF +#define PCI_MMIO_LIMIT MMIO_BASE + 0xFFFFFFF -static uint64_t next_mmio_base = PCI_MMIO_BASE; +static uint64_t next_mmio_base; uint64_t alloc_mmio_region(uint64_t size) { + if (next_mmio_base == 0) next_mmio_base = MMIO_BASE; size = (size + 0xFFF) & ~0xFFF; if (next_mmio_base + size > PCI_MMIO_LIMIT){ panic_with_info("MMIO alloc overflow",next_mmio_base+size); @@ -33,7 +34,7 @@ uint64_t alloc_mmio_region(uint64_t size) { } bool is_mmio_allocated(uint64_t addr){ - return addr > PCI_MMIO_BASE && addr < next_mmio_base; + return addr > MMIO_BASE && addr < next_mmio_base; } extern uint64_t kernel_start; @@ -122,14 +123,14 @@ uint64_t mem_get_kmem_end(){ } int handle_mem_node(const char *propname, const void *prop, uint32_t len, dtb_match_t *match) { - if (strcmp(propname, "reg") == 0 && len >= 16) { + if (strcmp(propname, "reg", false) == 0 && len >= 16) { uint32_t *p = (uint32_t *)prop; match->reg_base = ((uint64_t)__builtin_bswap32(p[0]) << 32) | __builtin_bswap32(p[1]); match->reg_size = ((uint64_t)__builtin_bswap32(p[2]) << 32) | __builtin_bswap32(p[3]); return 1; } - if (strcmp(propname, "device_type") == 0 && strcmp(prop,"memory") == 0){ + if (strcmp(propname, "device_type", false) == 0 && strcmp(prop,"memory", false) == 0){ match->found = true; } return 0; @@ -147,14 +148,18 @@ int get_memory_region(uint64_t *out_base, uint64_t *out_size) { void calc_ram(){ if (get_memory_region(&total_ram_start, &total_ram_size)) { - calculated_ram_end = total_ram_start + total_ram_size; - calculated_ram_start = ((uint64_t)&kfull_end) + 0x1; - calculated_ram_start = ((calculated_ram_start) & ~((1ULL << 21) - 1)); - calculated_ram_end = ((calculated_ram_end) & ~((1ULL << 21) - 1)); - - calculated_ram_size = calculated_ram_end - calculated_ram_start; - kprintf("Device has %x memory starting at %x. %x for user starting at %x ",total_ram_size, total_ram_start, calculated_ram_size, calculated_ram_start); + calculated_ram_end = total_ram_start + total_ram_size; + calculated_ram_start = ((uint64_t)&kfull_end) + 0x1; + calculated_ram_start = ((calculated_ram_start) & ~((1ULL << 21) - 1)); + calculated_ram_end = ((calculated_ram_end) & ~((1ULL << 21) - 1)); + } else { + total_ram_start = RAM_START; + total_ram_size = RAM_SIZE; + calculated_ram_end = CRAM_END; + calculated_ram_start = CRAM_START; } + calculated_ram_size = calculated_ram_end - calculated_ram_start; + kprintf("Device has %x memory starting at %x. %x for user starting at %x ending at %x ",total_ram_size, total_ram_start, calculated_ram_size, calculated_ram_start, calculated_ram_end); } #define calcvar(var)\ diff --git a/kernel/memory/mmu.c b/kernel/memory/mmu.c index 69274b1e..046beb27 100644 --- a/kernel/memory/mmu.c +++ b/kernel/memory/mmu.c @@ -3,6 +3,7 @@ #include "memory/kalloc.h" #include "console/kio.h" #include "exceptions/irq.h" +#include "hw/hw.h" #include "dtb.h" #include "pci.h" #include "filesystem/disk.h" @@ -173,7 +174,7 @@ void mmu_alloc(){ } void mmu_init() { - + //TODO: Move these hardcoded mappings to their own file uint64_t kstart = mem_get_kmem_start(); uint64_t kend = mem_get_kmem_end(); for (uint64_t addr = kstart; addr <= kend; addr += GRANULE_2MB) @@ -182,7 +183,7 @@ void mmu_init() { for (uint64_t addr = get_uart_base(); addr <= get_uart_base(); addr += GRANULE_4KB) mmu_map_4kb(addr, addr, MAIR_IDX_DEVICE, 1); - for (uint64_t addr = GICD_BASE; addr <= GICD_BASE + 0x20040; addr += GRANULE_4KB) + for (uint64_t addr = GICD_BASE; addr <= GICC_BASE + 0x1000; addr += GRANULE_4KB) mmu_map_4kb(addr, addr, MAIR_IDX_DEVICE, 1); for (uint64_t addr = get_shared_start(); addr <= get_shared_end(); addr += GRANULE_4KB) @@ -190,9 +191,10 @@ void mmu_init() { uint64_t dstart; uint64_t dsize; - dtb_addresses(&dstart,&dsize); - for (uint64_t addr = dstart; addr <= dstart + dsize; addr += GRANULE_4KB) - mmu_map_4kb(addr, addr, MAIR_IDX_NORMAL, 1); + if (dtb_addresses(&dstart,&dsize)){ + for (uint64_t addr = dstart; addr <= dstart + dsize; addr += GRANULE_4KB) + mmu_map_4kb(addr, addr, MAIR_IDX_NORMAL, 1); + } uint64_t mair = (MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE * 8)) | (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL * 8)); asm volatile ("msr mair_el1, %0" :: "r"(mair)); diff --git a/kernel/memory/mmu.h b/kernel/memory/mmu.h index 7361bc9b..38ebcae5 100644 --- a/kernel/memory/mmu.h +++ b/kernel/memory/mmu.h @@ -7,9 +7,15 @@ void mmu_alloc(); void mmu_init(); +#ifdef __cplusplus +extern "C" { +#endif void register_device_memory(uint64_t va, uint64_t pa); void register_device_memory_2mb(uint64_t va, uint64_t pa); void register_proc_memory(uint64_t va, uint64_t pa, bool kernel); +#ifdef __cplusplus +} +#endif void debug_mmu_address(uint64_t va); void mmu_enable_verbose(); diff --git a/kernel/memory/page_allocator.c b/kernel/memory/page_allocator.c index 6a60103e..be8d3325 100644 --- a/kernel/memory/page_allocator.c +++ b/kernel/memory/page_allocator.c @@ -72,7 +72,7 @@ void* alloc_page(uint64_t size, bool kernel, bool device, bool full) { uintptr_t first_address = 0; for (uint64_t j = 0; j < page_count; j++){ - mem_bitmap[i] |= (1ULL << bit + j); + mem_bitmap[i] |= (1ULL << (bit + j)); uint64_t page_index = (i * 64) + (bit + j); uintptr_t address = page_index * PAGE_SIZE; if (!first_address) first_address = address; diff --git a/kernel/networking/processes/net_proc.c b/kernel/networking/processes/net_proc.c index 38e1ac94..84b7bfdc 100644 --- a/kernel/networking/processes/net_proc.c +++ b/kernel/networking/processes/net_proc.c @@ -45,7 +45,7 @@ bool find_server(){ unbind_port(7777); - return strcmp(content, "world") == 0; + return strcmp(content, "world", false) == 0; } void test_network(){ diff --git a/kernel/pci.c b/kernel/pci.c index 7eff280a..b2e0ba19 100644 --- a/kernel/pci.c +++ b/kernel/pci.c @@ -8,6 +8,7 @@ #include "exceptions/irq.h" #include "memory/mmu.h" #include "memory/memory_access.h" +#include "hw/hw.h" #define PCI_BUS_MAX 256 #define PCI_SLOT_MAX 32 @@ -213,6 +214,9 @@ uint64_t pci_setup_bar(uint64_t pci_addr, uint32_t bar_index, uint64_t *mmio_sta uint64_t find_pci_device(uint32_t vendor_id, uint32_t device_id) { + if (!USE_PCI) + return 0; + if (NINIT) find_pci(); diff --git a/kernel/process/loading/elf_file.c b/kernel/process/loading/elf_file.c index 6da1204f..2d46d350 100644 --- a/kernel/process/loading/elf_file.c +++ b/kernel/process/loading/elf_file.c @@ -39,6 +39,11 @@ typedef struct elf_program_header { process_t* load_elf_file(const char *name, void* file){ elf_header *header = (elf_header*)file; + if (header->magic[0] != 0x7f){ + kprintf("Failed to read header file"); + return 0; + } + kprintf("ELF FILE VERSION %x HEADER VERSION %x (%x)",header->elf_version,header->header_version,header->header_size); kprintf("FILE %i for %x",header->type, header->instruction_set); kprintf("ENTRY %x - %i",header->program_entry_offset); @@ -46,7 +51,7 @@ process_t* load_elf_file(const char *name, void* file){ elf_program_header* first_program_header = (elf_program_header*)((uint8_t *)file + header->program_header_offset); kprintf("program takes up %x, begins at %x, and is %b, %b",first_program_header->p_filez, first_program_header->p_offset, first_program_header->segment_type, first_program_header->flags); kprintf("SECTION %x - %i * %i",header->section_header_offset, header->section_entry_size,header->section_num_entries); - kprintf("First instruction %x", (uint64_t)*((uint8_t *)file + 0x1000)); + kprintf("First instruction %x", *(uint64_t*)(file + header->program_entry_offset)); return create_process(name, (void*)(file + first_program_header->p_offset), first_program_header->p_filez, header->program_entry_offset); } \ No newline at end of file diff --git a/kernel/process/loading/process_loader.c b/kernel/process/loading/process_loader.c index d1e3c9b3..7f8b42d6 100644 --- a/kernel/process/loading/process_loader.c +++ b/kernel/process/loading/process_loader.c @@ -259,7 +259,8 @@ process_t* create_process(char *name, void *content, uint64_t content_size, uint name_process(proc, name); - uint8_t* dest = (uint8_t*)alloc_page(content_size, false, false, false); + //TODO: keep track of code size so we can free up allocated code pages + uint8_t* dest = (uint8_t*)alloc_page(content_size, false, false, true); if (!dest) return 0; for (uint64_t i = 0; i < content_size; i++){ diff --git a/run_raspi b/run_raspi new file mode 100755 index 00000000..3b6c756e --- /dev/null +++ b/run_raspi @@ -0,0 +1,32 @@ +#/!bin/sh + +echo "Running raspi emulator" + +ARGS="" +if [ "$1" = "debug" ]; then + ARGS="-monitor unix:/tmp/qemu-monitor-socket,server,nowait -s -S" +fi + +OS_TYPE="$(uname)" + +if [[ "$OS_TYPE" == "Darwin" ]]; then + NETARG="vmnet-bridged,id=net0,ifname=en0" + PRIVILEGE="sudo" +elif [[ "$OS_TYPE" == "Linux" ]]; then + NETARG="user,id=net0" + PRIVILEGE="" +else + echo "Unknown OS: $OS_TYPE" >&2 + exit 1 +fi + +$PRIVILEGE qemu-system-aarch64 \ +-M raspi4b \ +-kernel kernel.img \ +-display sdl \ +-device sd-card,drive=sd -drive id=sd,format=raw,file=disk.img,if=none \ +-netdev $NETARG \ +-serial mon:stdio \ +-device usb-kbd \ +-d guest_errors \ +$ARGS diff --git a/run b/run_virt similarity index 86% rename from run rename to run_virt index 26e3bfd4..25663d9f 100755 --- a/run +++ b/run_virt @@ -1,6 +1,6 @@ -#!/bin/sh +#/!bin/sh -echo "Running emulator" +echo "Running virt emulator" ARGS="" if [ "$1" = "debug" ]; then @@ -19,24 +19,23 @@ OS_TYPE="$(uname)" if [[ "$OS_TYPE" == "Darwin" ]]; then NETARG="vmnet-bridged,id=net0,ifname=en0" - + PRIVILEGE="sudo" elif [[ "$OS_TYPE" == "Linux" ]]; then NETARG="user,id=net0" - + PRIVILEGE="" else echo "Unknown OS: $OS_TYPE" >&2 exit 1 fi - -qemu-system-aarch64 \ +$PRIVILEGE qemu-system-aarch64 \ -M virt \ -cpu cortex-a72 \ -m 512M \ -kernel kernel.elf \ -device virtio-gpu-pci \ -display sdl \ - -netdev ${NETARG} \ + -netdev $NETARG \ -device virtio-net-pci,netdev=net0 \ -serial mon:stdio \ -drive file=disk.img,if=none,format=raw,id=hd0 \ @@ -44,4 +43,4 @@ qemu-system-aarch64 \ -device qemu-xhci,${MSI_CAPABILITIES}id=usb \ -device usb-kbd,bus=usb.0 \ -d guest_errors \ - $ARGS + $ARGS \ No newline at end of file diff --git a/rundebug b/rundebug index 1b4a8888..c06603f9 100755 --- a/rundebug +++ b/rundebug @@ -1,10 +1,18 @@ #!/bin/bash -ARGS="$@" +MODE="rpi" +ARGS=() + +for arg in "$@"; do + case $arg in + MODE=*) MODE="${arg#MODE=}" ;; + *) ARGS+=("$arg") ;; + esac +done osascript <= 'A' && c <= 'Z') return c + 'a' - 'A'; + return c; +} + +int strcmp(char *a, char *b, bool case_insensitive) { while (*a && *b) { - if (*a != *b) return (unsigned char)*a - (unsigned char)*b; + char ca = *a; + char cb = *b; + + if (case_insensitive) { + ca = tolower((unsigned char)ca); + cb = tolower((unsigned char)cb); + } + + if (ca != cb) return ca - cb; + a++; b++; } - return (unsigned char)*a - (unsigned char)*b; + if (case_insensitive) return tolower(*a) - tolower(*b); + return *a - *b; } -int strstart(const char *a, const char *b) { +int strstart(char *a, char *b, bool case_insensitive) { + int index = 0; while (*a && *b) { - if (*a != *b) return (unsigned char)*a - (unsigned char)*b; - a++; b++; + char ca = *a; + char cb = *b; + + if (case_insensitive) { + ca = tolower(ca); + cb = tolower(cb); + } + + if (ca != cb) return index; + a++; b++; index++; } return 0; } -int strindex(const char *a, const char *b) { +int strindex( char *a, char *b) { for (int i = 0; a[i]; i++) { int j = 0; while (b[j] && a[i + j] == b[j]) j++; @@ -225,12 +249,20 @@ int strindex(const char *a, const char *b) { return -1; } -int strend(const char *a, const char *b) { +int strend(char *a, char *b, bool case_insensitive) { while (*a && *b) { - if (*a == *b) { - const char *pa = a, *pb = b; - while (*pa == *pb) { - if (!*pa) return 0; + char ca = case_insensitive ? tolower((unsigned char)*a) : *a; + char cb = case_insensitive ? tolower((unsigned char)*b) : *b; + + if (ca == cb) { + char *pa = a, *pb = b; + while (1) { + char cpa = case_insensitive ? tolower((unsigned char)*pa) : *pa; + char cpb = case_insensitive ? tolower((unsigned char)*pb) : *pb; + + if (!cpa) return 0; + if (cpa != cpb) break; + pa++; pb++; } } @@ -239,9 +271,9 @@ int strend(const char *a, const char *b) { return 1; } -bool strcont(const char *a, const char *b) { +bool strcont( char *a, char *b) { while (*a) { - const char *p = a, *q = b; + char *p = a, *q = b; while (*p && *q && *p == *q) { p++; q++; } @@ -251,14 +283,13 @@ bool strcont(const char *a, const char *b) { return 0; } -bool utf16tochar(const uint16_t* str_in, char* out_str, size_t max_len) { +bool utf16tochar( uint16_t* str_in, char* out_str, size_t max_len) { size_t out_i = 0; - while (str_in[out_i] != 0 && out_i + 1 < max_len) { - uint16_t wc = str_in[out_i]; - out_str[out_i] = (wc <= 0x7F) ? (char)wc : '?'; - out_i++; + for (int i = 0; i < max_len && str_in[i]; i++){ + uint16_t wc = str_in[i]; + out_str[out_i++] = (wc <= 0x7F) ? (char)(wc & 0xFF) : '?'; } - out_str[out_i] = '\0'; + out_str[out_i++] = '\0'; return true; } diff --git a/shared/std/string.h b/shared/std/string.h index bb61cfc2..165c83c2 100644 --- a/shared/std/string.h +++ b/shared/std/string.h @@ -3,6 +3,10 @@ #include "types.h" #include "args.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { char *data; uint32_t length; @@ -14,22 +18,27 @@ typedef struct string_list { char array[]; } string_list; -string string_l(const char *literal); -string string_ca_max(const char *array, uint32_t max_length); -string string_c(const char c); +string string_l( char *literal); +string string_ca_max( char *array, uint32_t max_length); +string string_c( char c); string string_from_hex(uint64_t value); bool string_equals(string a, string b); -string string_format(const char *fmt, ...); -string string_format_va(const char *fmt, va_list args); -string string_tail(const char *array, uint32_t max_length); +string string_format( char *fmt, ...); +string string_format_va( char *fmt, va_list args); +string string_tail( char *array, uint32_t max_length); string string_repeat(char symbol, uint32_t amount); -int strcmp(const char *a, const char *b); -bool strcont(const char *a, const char *b); -int strstart(const char *a, const char *b); -int strend(const char *a, const char *b); -int strindex(const char *a, const char *b); +char tolower(char c); +int strcmp( char *a, char *b, bool case_insensitive); +bool strcont( char *a, char *b); +int strstart(char *a, char *b, bool case_insensitive); +int strend( char *a, char *b, bool case_insensitive); +int strindex( char *a, char *b); uint64_t parse_hex_u64(char* str, size_t size); -bool utf16tochar(const uint16_t* str_in, char* out_str, size_t max_len); \ No newline at end of file +bool utf16tochar( uint16_t* str_in, char* out_str, size_t max_len); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/shared/ui/draw/draw.c b/shared/ui/draw/draw.c index 6b7c0d7a..eb0680b2 100644 --- a/shared/ui/draw/draw.c +++ b/shared/ui/draw/draw.c @@ -7,15 +7,70 @@ uint32_t stride = 0; uint32_t max_width, max_height; -void fb_clear(uint32_t* fb, uint32_t width, uint32_t height, uint32_t color) { - for (uint32_t i = 0; i < width * height; i++) { +gpu_rect dirty_rects[MAX_DIRTY_RECTS]; +uint32_t dirty_count = 0; +bool full_redraw = false; + +int try_merge(gpu_rect* a, gpu_rect* b) { + uint32_t ax2 = a->point.x + a->size.width; + uint32_t ay2 = a->point.y + a->size.height; + uint32_t bx2 = b->point.x + b->size.width; + uint32_t by2 = b->point.y + b->size.height; + + if (a->point.x > bx2 || b->point.x > ax2 || a->point.y > by2 || b->point.y > ay2) + return false; + + uint32_t min_x = a->point.x < b->point.x ? a->point.x : b->point.x; + uint32_t min_y = a->point.y < b->point.y ? a->point.y : b->point.y; + uint32_t max_x = ax2 > bx2 ? ax2 : bx2; + uint32_t max_y = ay2 > by2 ? ay2 : by2; + + a->point.x = min_x; + a->point.y = min_y; + a->size.width = max_x - min_x; + a->size.height = max_y - min_y; + + return true; +} + +void mark_dirty(uint32_t x, uint32_t y, uint32_t w, uint32_t h) { + if (full_redraw) return; + + if (x >= max_width || y >= max_height) + return; + + if (x + w > max_width) + w = max_width - x; + + if (y + h > max_height) + h = max_height - y; + + if (w == 0 || h == 0) + return; + + gpu_rect new_rect = { x, y, w, h }; + + for (uint32_t i = 0; i < dirty_count; i++) + if (try_merge(&dirty_rects[i], &new_rect)) + return; + + if (dirty_count < MAX_DIRTY_RECTS) + dirty_rects[dirty_count++] = new_rect; + else + full_redraw = true; +} + +void fb_clear(uint32_t* fb, uint32_t color) { + for (uint32_t i = 0; i < max_width * max_height; i++) { fb[i] = color; } + full_redraw = true; } void fb_draw_pixel(uint32_t* fb, uint32_t x, uint32_t y, color color){ - if (x > max_width || y > max_height) return; + if (x >= max_width || y >= max_height) return; fb[y * (stride / 4) + x] = color; + //TODO: for some reason, calling mark_dirty from here crashes. Calling it from just outside this function does not. Something to do with merge. Need to investigate. } void fb_fill_rect(uint32_t* fb, uint32_t x, uint32_t y, uint32_t width, uint32_t height, color color){ @@ -24,6 +79,7 @@ void fb_fill_rect(uint32_t* fb, uint32_t x, uint32_t y, uint32_t width, uint32_t fb_draw_pixel(fb, x + dx, y + dy, color); } } + mark_dirty(x,y,width,height); } gpu_rect fb_draw_line(uint32_t* fb, uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, color color){ @@ -46,6 +102,8 @@ gpu_rect fb_draw_line(uint32_t* fb, uint32_t x0, uint32_t y0, uint32_t x1, uint3 int max_x = (x0 > x1) ? x0 : x1; int max_y = (y0 > y1) ? y0 : y1; + mark_dirty(min_x,min_y,max_x - min_x + 1,max_y - min_y + 1); + return (gpu_rect) { {min_x, min_y}, {max_x - min_x + 1, max_y - min_y + 1}}; } @@ -59,6 +117,7 @@ void fb_draw_char(uint32_t* fb, uint32_t x, uint32_t y, char c, uint32_t scale, } } } + mark_dirty(x,y,8*scale,8*scale); } gpu_size fb_draw_string(uint32_t* fb, string s, uint32_t x0, uint32_t y0, uint32_t scale, uint32_t color){ @@ -87,6 +146,8 @@ gpu_size fb_draw_string(uint32_t* fb, string s, uint32_t x0, uint32_t y0, uint32 if (xRowSize > xSize) xSize = xRowSize; + mark_dirty(x0,y0,xSize,ySize); + return (gpu_size){xSize,ySize}; } diff --git a/shared/ui/draw/draw.h b/shared/ui/draw/draw.h index 94f295e7..0b949c8a 100644 --- a/shared/ui/draw/draw.h +++ b/shared/ui/draw/draw.h @@ -6,7 +6,12 @@ extern "C" { #include "ui/graphic_types.h" #include "std/string.h" -void fb_clear(uint32_t* fb, uint32_t width, uint32_t height, uint32_t color); +int try_merge(gpu_rect* a, gpu_rect* b); +void mark_dirty(uint32_t x, uint32_t y, uint32_t w, uint32_t h); + +//TODO: to make this a more robust drawing library available without syscall, unify dirty_rects, fb pointer, stride and size into a context structure + +void fb_clear(uint32_t* fb, uint32_t color); void fb_draw_pixel(uint32_t* fb, uint32_t x, uint32_t y, color color); void fb_fill_rect(uint32_t* fb, uint32_t x, uint32_t y, uint32_t width, uint32_t height, color color); gpu_rect fb_draw_line(uint32_t* fb, uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, color color); @@ -17,6 +22,12 @@ uint32_t fb_get_char_size(uint32_t scale); void fb_set_stride(uint32_t new_stride); void fb_set_bounds(uint32_t width, uint32_t height); +#define MAX_DIRTY_RECTS 64 + +extern gpu_rect dirty_rects[MAX_DIRTY_RECTS]; +extern uint32_t dirty_count; +extern bool full_redraw; + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/user/default_process.c b/user/default_process.c index 84dae5e0..4d9d644e 100644 --- a/user/default_process.c +++ b/user/default_process.c @@ -4,11 +4,6 @@ #include "input_keycodes.h" #include "std/string.h" -void var_test(char* s, ...){ - va_list args; - va_start(args, s); -} - void proc_func() { uint64_t j = 0; gpu_size* size = gpu_screen_size();