commit 7118adc51448dfb769cd8a0b4df04a773ca94d25 Author: Ayaan Tunio Date: Wed Feb 12 09:54:05 2025 -0500 Squash commits for public release diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..a74183d --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +--- +BasedOnStyle: WebKit \ No newline at end of file diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..fbbc11c --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,2 @@ +Checks: '-*,clang-diagnostic-*,llvm-*,clang-analyzer*,cert-*-c,-cert-dcl37-c,-llvm-header-guard,-clang-diagnostic-incompatible-library-redeclaration,-clang-diagnostic-typedef-redefinition,-clang-analyzer-deadcode.DeadStores' +HeaderFilterRegex: '.*' \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5edcab9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +*.log +*.map +*.img +products/ +*.o +*.a +*DS_Store +*.pyc +.DS_Store/ +base/boot/ +base/bin/ +mountpoint/ +out/ +third_party/*/src +third_party/*/bin_x86/ +third_party/*/bin_x86_64/ +third_party/*/bin_arm32/ +third_party/*/bin_arm64/ +third_party/*/bin_riscv64/ +third_party/*/patches/.applied_* +__pycache__/ +libs/libfreetype/include/ +utils/.cached/* diff --git a/.gn b/.gn new file mode 100644 index 0000000..2711aa4 --- /dev/null +++ b/.gn @@ -0,0 +1,6 @@ +buildconfig = "//build/config/BUILDCONFIG.gn" +script_executable = "python3" + +default_args = { + # Set in buildconfig +} diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 0000000..daf495e --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,25 @@ +group("build") { + deps = [ + ":env", + "//build/boot:boot", + "//build/kernel:kernel", + + "//build/libs:libs", + "//build/third_party:third_party", + "//build/userland:userland", + ] + if (compile_tests) { + deps += [ "//build/test:test" ] + } +} + +group("env") { + deps = [ + ":scripts", + "//build/tools:prepare_env", + ] +} + +group("scripts") { + deps = [ "//build/tools:build_scripts" ] +} diff --git a/Images/sysarch.svg b/Images/sysarch.svg new file mode 100644 index 0000000..765112c --- /dev/null +++ b/Images/sysarch.svg @@ -0,0 +1,67 @@ +

USERLAND (Unprivileged)

SYSCALL / TRAP BOUNDARY

PRIVILEGED KERNEL SPACE

Platform Layer

I/O & Storage

Process & Scheduling

Memory Management

return to
userspace

syscall
invocation

CR3/TTBR0
(Page Tables)

restore
registers

MMIO /
Port I/O

notify

powers

loads &
jumps to

page
allocation

I/O wait
blocking

page cache
& mmap

mmap/
brk

fork/
exec

read/
write

sysret/
iret

trap into
kernel

Syscall Interface

Trapframe
(Register Save/Restore)

Syscall Dispatch
(Table Lookup)

Firmware & Boot Chain

Stage 1 → Prekernel (PIC)
Device Tree Parse → ELF Load + Signature Verify
Page Table Setup → Kernel Entry

Legend

═══ Solid Arrow: Control Flow / Data Path

----- Dotted Arrow: Dependency / Interaction

CPU • MMU • RAM • Interrupt Controller • Storage • Peripherals

Physical Memory
Manager (PMM)

Virtual Memory
Manager (VMM)

Per-Process
Address Spaces

Page Fault Handler

Thread Management

Preemptive Scheduler
(Priority Queues)

Context Switch
(Arch-Specific)

Virtual File System
(VFS)

Driver Framework

IPC Layer
• Local Sockets
• Signals
• Shared Memory

(int 0x80 / ecall / svc)
Ring 3→0 (x86) | EL0→EL1 (ARM) | U-Mode→S-Mode (RISC-V)

POSIX LibC / C++ Runtime
System Servers: Window Server, Launch Server
Applications & Shell

\ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..68eace0 --- /dev/null +++ b/README.md @@ -0,0 +1,131 @@ +# xOS +**A multi-architecture operating system built from scratch targeting x86, ARM, and RISC-V** + +![System Overview][system_overview] + +--- + +## What This Is + +An operating system implemented entirely from scratch (no existing kernel), spanning kernel development, driver architecture, filesystems, userland applications, and UI frameworks. + +### Technical Scope + +- **Multi-architecture kernel**: x86/x86-64, ARMv7, Arm64, RISC-V support with unified codebase +- **Custom bootloaders** for each architecture with ELF validation and secure boot integration +- **Full userspace stack**: C/C++ standard libraries, Objective-C runtime, UI framework, window server +- **Production OS features**: Ext2 filesystem, virtual filesystem layer, process management, POSIX signals, TTY subsystem + +--- + +## Core Technical Implementation + +### Kernel Architecture + +**Preemptive Multitasking & Scheduling** +- Priority-based round-robin scheduler with 12 priority levels +- Per-CPU runqueues for SMP support (multi-core) +- Conditional kernel preemption (`PREEMPT_KERNEL` flag for real-time responsiveness) +- Interrupt depth counter preventing race conditions during context switches +- Idle threads for zero-allocation interrupt handling + +**Memory Management** +- Virtual memory manager with per-process address spaces +- Demand paging and swap support +- Kernel/userspace memory isolation with access validation +- Shared buffers for zero-copy IPC + +**System Call Interface** +- 60+ system calls following POSIX conventions (`fork`, `exec`, `read`, `write`, `mmap`, etc.) +- Architecture-specific syscall dispatch (software interrupts on x86, `svc` on ARM) +- Kernel-mode syscalls (`ksys1`-`ksys4`) for internal operations + +### Boot Process & Security + +**Custom Bootloader Chain** +- **Stage 1** (x86): Real-mode to protected-mode transition, memory map collection +- **Stage 2/Prekernel**: ELF loader, device tree initialization, MMU setup +- **Kernel validation**: SHA256 + RSA signature verification before execution +- Passes boot arguments (`boot_args_t`) with memory layout, framebuffer, device tree + +### Filesystem & Device Management + +- **Ext2 filesystem** with full read/write support +- **Virtual filesystem (VFS)** layer abstracting file operations +- `/dev` (device nodes) and `/proc` (process/system introspection) filesystems +- Device tree parsing for ARM/RISC-V hardware discovery +- Device driver framework with pluggable driver registration + +### Userland & UI + +**Window Server** (compositing manager) +- Client-server architecture using IPC +- Desktop and mobile window management modes +- Hardware-accelerated rendering via LibG +- Menu bar, dock, popup system + +**Libraries** +- **LibC/LibCxx**: POSIX-compliant C library and C++ STL +- **LibObjC**: Objective-C runtime (message dispatch, ARC) +- **LibFoundation**: Event loop, shared buffers, collections (Cocoa-inspired) +- **LibG**: 2D graphics (pixel buffers, fonts, PNG/BMP loaders) +- **LibUI**: High-level UI widgets (buttons, text fields, windows) + +--- + +## Key Engineering Decisions + +**1. Multi-Architecture Support** +Abstracted platform-specific code (`kernel/platform/{x86,arm32,arm64,riscv}`) with common interfaces for MMU, interrupts, context switching. Enables same kernel codebase across all targets. + +**2. Build System** +GN (Generate Ninja) meta-build system for fast incremental builds. Compiles for multiple architectures from single source tree. + +**3. Bootloader Security** +Validates kernel ELF binary cryptographically before loading—prevents tampered kernel execution (verified boot). + +**4. Preemptive vs Cooperative** +Kernel preemption is compile-time optional (`-DPREEMPT_KERNEL`). Enables low-latency scheduling when enabled, or simpler non-preemptive model for easier debugging. + +**5. Window Server Architecture** +Separates compositing from applications—crash in user app doesn't take down entire UI. Similar to X11/Wayland model. + +--- + +## Features + +### Kernel + +* x86/x86-64, ARMv7 and Arm64 kernel with pre-emptive multi-threading +* Ext2 filesystem +* /dev and /proc filesystems +* Local sockets +* POSIX signals +* TTY +* [learn more](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/docs/kernel.md) + +### Libraries + +* Runtime & support: LibC, LibCxx, LibObjC +* Rich functionality: LibFoundation +* UI functionality & rendering: LibG, LibUI +* [learn more](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/docs/libs.md) + +### Userland + +* Composing windows manager for desktop and mobile +* Simple UI apps +* Terminal + +### Boot + +* Custom bootloaders +* Kernel validation during the boot proccess +* Custom device tree +* [learn more](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/docs/boot.md) + +## How to build and run xOS? + +See the [build instructions](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/docs/build.md) + +[system_overview]: /Images/sysarch.svg "System Architecture Diagram" \ No newline at end of file diff --git a/base/System/launch_server_config.json b/base/System/launch_server_config.json new file mode 100644 index 0000000..46a6726 --- /dev/null +++ b/base/System/launch_server_config.json @@ -0,0 +1,5 @@ +{ + "launch": [ + "/System/window_server" + ] +} \ No newline at end of file diff --git a/base/etc/passwd b/base/etc/passwd new file mode 100644 index 0000000..ada1d5a --- /dev/null +++ b/base/etc/passwd @@ -0,0 +1,2 @@ +root::0:0:root:/root:/bin/xsh +user::10:10:user:/user:/bin/xsh \ No newline at end of file diff --git a/base/etc/shadow b/base/etc/shadow new file mode 100644 index 0000000..598de06 --- /dev/null +++ b/base/etc/shadow @@ -0,0 +1,2 @@ +root:root:18727:::::: +user:password:18727:0:99999:::: diff --git a/base/home/root/rootfile.txt b/base/home/root/rootfile.txt new file mode 100644 index 0000000..54c1165 --- /dev/null +++ b/base/home/root/rootfile.txt @@ -0,0 +1 @@ +Root file \ No newline at end of file diff --git a/base/home/user/userfile.txt b/base/home/user/userfile.txt new file mode 100644 index 0000000..f795012 --- /dev/null +++ b/base/home/user/userfile.txt @@ -0,0 +1 @@ +User file \ No newline at end of file diff --git a/base/open_docs b/base/open_docs new file mode 100644 index 0000000..c59268e --- /dev/null +++ b/base/open_docs @@ -0,0 +1,37 @@ +The open() system call opens the file specified by pathname. If the +specified file does not exist, it may optionally (if O_CREAT is +specified in flags) be created by open(). + +The return value of open() is a file descriptor, a small, nonnegative +integer that is used in subsequent system calls (read(2), write(2), +lseek(2), fcntl(2), etc.) to refer to the open file. The file +descriptor returned by a successful call will be the lowest-numbered +file descriptor not currently open for the process. + +By default, the new file descriptor is set to remain open across an +execve(2) (i.e., the FD_CLOEXEC file descriptor flag described in +fcntl(2) is initially disabled); the O_CLOEXEC flag, described below, +can be used to change this default. The file offset is set to the +beginning of the file (see lseek(2)). + +A call to open() creates a new open file description, an entry in the +system-wide table of open files. The open file description records +the file offset and the file status flags (see below). A file +descriptor is a reference to an open file description; this reference +is unaffected if pathname is subsequently removed or modified to +refer to a different file. For further details on open file +descriptions, see NOTES. + +The argument flags must include one of the following access modes: +O_RDONLY, O_WRONLY, or O_RDWR. These request opening the file read- +only, write-only, or read/write, respectively. + +In addition, zero or more file creation flags and file status flags +can be bitwise-or'd in flags. The file creation flags are O_CLOEXEC, +O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TMPFILE, and +O_TRUNC. The file status flags are all of the remaining flags listed +below. The distinction between these two groups of flags is that the +file creation flags affect the semantics of the open operation +itself, while the file status flags affect the semantics of +subsequent I/O operations. The file status flags can be retrieved +and (in some cases) modified; see fcntl(2) for details. \ No newline at end of file diff --git a/base/res/fonts/Liza.font/10/bold.font b/base/res/fonts/Liza.font/10/bold.font new file mode 100644 index 0000000..3efd580 Binary files /dev/null and b/base/res/fonts/Liza.font/10/bold.font differ diff --git a/base/res/fonts/Liza.font/10/regular.font b/base/res/fonts/Liza.font/10/regular.font new file mode 100644 index 0000000..c89a53a Binary files /dev/null and b/base/res/fonts/Liza.font/10/regular.font differ diff --git a/base/res/fonts/system.font/10/bold.font b/base/res/fonts/system.font/10/bold.font new file mode 100644 index 0000000..973ad9f Binary files /dev/null and b/base/res/fonts/system.font/10/bold.font differ diff --git a/base/res/fonts/system.font/10/regular.font b/base/res/fonts/system.font/10/regular.font new file mode 100644 index 0000000..28dfc21 Binary files /dev/null and b/base/res/fonts/system.font/10/regular.font differ diff --git a/base/res/fonts/system.font/12/bold.font b/base/res/fonts/system.font/12/bold.font new file mode 100644 index 0000000..7d30bff Binary files /dev/null and b/base/res/fonts/system.font/12/bold.font differ diff --git a/base/res/fonts/system.font/12/regular.font b/base/res/fonts/system.font/12/regular.font new file mode 100644 index 0000000..1da2d78 Binary files /dev/null and b/base/res/fonts/system.font/12/regular.font differ diff --git a/base/res/fonts/system.font/24/bold.font b/base/res/fonts/system.font/24/bold.font new file mode 100644 index 0000000..766128a Binary files /dev/null and b/base/res/fonts/system.font/24/bold.font differ diff --git a/base/res/fonts/system.font/24/regular.font b/base/res/fonts/system.font/24/regular.font new file mode 100644 index 0000000..72c20f0 Binary files /dev/null and b/base/res/fonts/system.font/24/regular.font differ diff --git a/base/res/fonts/system.font/36/bold.font b/base/res/fonts/system.font/36/bold.font new file mode 100644 index 0000000..164d57a Binary files /dev/null and b/base/res/fonts/system.font/36/bold.font differ diff --git a/base/res/fonts/system.font/36/regular.font b/base/res/fonts/system.font/36/regular.font new file mode 100644 index 0000000..92fd18e Binary files /dev/null and b/base/res/fonts/system.font/36/regular.font differ diff --git a/base/res/fonts/system.font/truetype/bold.ttf b/base/res/fonts/system.font/truetype/bold.ttf new file mode 100644 index 0000000..065c154 Binary files /dev/null and b/base/res/fonts/system.font/truetype/bold.ttf differ diff --git a/base/res/fonts/system.font/truetype/regular.ttf b/base/res/fonts/system.font/truetype/regular.ttf new file mode 100644 index 0000000..e017417 Binary files /dev/null and b/base/res/fonts/system.font/truetype/regular.ttf differ diff --git a/base/res/icons/apps/about.icon/32x32.png b/base/res/icons/apps/about.icon/32x32.png new file mode 100644 index 0000000..5e72437 Binary files /dev/null and b/base/res/icons/apps/about.icon/32x32.png differ diff --git a/base/res/icons/apps/about.icon/48x48.png b/base/res/icons/apps/about.icon/48x48.png new file mode 100644 index 0000000..008da0f Binary files /dev/null and b/base/res/icons/apps/about.icon/48x48.png differ diff --git a/base/res/icons/apps/activity_monitor.icon/32x32.png b/base/res/icons/apps/activity_monitor.icon/32x32.png new file mode 100644 index 0000000..b198901 Binary files /dev/null and b/base/res/icons/apps/activity_monitor.icon/32x32.png differ diff --git a/base/res/icons/apps/activity_monitor.icon/48x48.png b/base/res/icons/apps/activity_monitor.icon/48x48.png new file mode 100644 index 0000000..026aed4 Binary files /dev/null and b/base/res/icons/apps/activity_monitor.icon/48x48.png differ diff --git a/base/res/icons/apps/calculator.icon/32x32.png b/base/res/icons/apps/calculator.icon/32x32.png new file mode 100644 index 0000000..642987a Binary files /dev/null and b/base/res/icons/apps/calculator.icon/32x32.png differ diff --git a/base/res/icons/apps/calculator.icon/48x48.png b/base/res/icons/apps/calculator.icon/48x48.png new file mode 100644 index 0000000..5048f88 Binary files /dev/null and b/base/res/icons/apps/calculator.icon/48x48.png differ diff --git a/base/res/icons/apps/missing.icon/12x12.png b/base/res/icons/apps/missing.icon/12x12.png new file mode 100644 index 0000000..975bb26 Binary files /dev/null and b/base/res/icons/apps/missing.icon/12x12.png differ diff --git a/base/res/icons/apps/missing.icon/32x32.png b/base/res/icons/apps/missing.icon/32x32.png new file mode 100644 index 0000000..d1852cc Binary files /dev/null and b/base/res/icons/apps/missing.icon/32x32.png differ diff --git a/base/res/icons/apps/missing.icon/48x48.png b/base/res/icons/apps/missing.icon/48x48.png new file mode 100644 index 0000000..ea7ffa9 Binary files /dev/null and b/base/res/icons/apps/missing.icon/48x48.png differ diff --git a/base/res/icons/apps/terminal.icon/32x32.png b/base/res/icons/apps/terminal.icon/32x32.png new file mode 100644 index 0000000..9509fea Binary files /dev/null and b/base/res/icons/apps/terminal.icon/32x32.png differ diff --git a/base/res/icons/apps/terminal.icon/48x48.png b/base/res/icons/apps/terminal.icon/48x48.png new file mode 100644 index 0000000..f04f041 Binary files /dev/null and b/base/res/icons/apps/terminal.icon/48x48.png differ diff --git a/base/res/system/app_list_32.png b/base/res/system/app_list_32.png new file mode 100644 index 0000000..27294ea Binary files /dev/null and b/base/res/system/app_list_32.png differ diff --git a/base/res/system/arrow.png b/base/res/system/arrow.png new file mode 100644 index 0000000..6a173da Binary files /dev/null and b/base/res/system/arrow.png differ diff --git a/base/res/system/contol_center.png b/base/res/system/contol_center.png new file mode 100644 index 0000000..de77e14 Binary files /dev/null and b/base/res/system/contol_center.png differ diff --git a/base/res/system/logo_dark_128.png b/base/res/system/logo_dark_128.png new file mode 100644 index 0000000..5309ab3 Binary files /dev/null and b/base/res/system/logo_dark_128.png differ diff --git a/base/res/system/logo_dark_256.png b/base/res/system/logo_dark_256.png new file mode 100644 index 0000000..7c0b970 Binary files /dev/null and b/base/res/system/logo_dark_256.png differ diff --git a/base/res/system/logo_opac_128.png b/base/res/system/logo_opac_128.png new file mode 100644 index 0000000..9adeee9 Binary files /dev/null and b/base/res/system/logo_opac_128.png differ diff --git a/base/res/system/mobile/control.png b/base/res/system/mobile/control.png new file mode 100644 index 0000000..7a41eb3 Binary files /dev/null and b/base/res/system/mobile/control.png differ diff --git a/base/res/system/mobile/cursor.png b/base/res/system/mobile/cursor.png new file mode 100644 index 0000000..1666dd0 Binary files /dev/null and b/base/res/system/mobile/cursor.png differ diff --git a/base/res/wallpapers/abstract.png b/base/res/wallpapers/abstract.png new file mode 100644 index 0000000..01572be Binary files /dev/null and b/base/res/wallpapers/abstract.png differ diff --git a/base/res/wallpapers/island.png b/base/res/wallpapers/island.png new file mode 100644 index 0000000..722e322 Binary files /dev/null and b/base/res/wallpapers/island.png differ diff --git a/base/res/wallpapers/new_year.png b/base/res/wallpapers/new_year.png new file mode 100644 index 0000000..c03f3a5 Binary files /dev/null and b/base/res/wallpapers/new_year.png differ diff --git a/base/res/wallpapers/pink_sand.png b/base/res/wallpapers/pink_sand.png new file mode 100644 index 0000000..7c3227b Binary files /dev/null and b/base/res/wallpapers/pink_sand.png differ diff --git a/boot/arm32/drivers/pl181.c b/boot/arm32/drivers/pl181.c new file mode 100644 index 0000000..95aa1ce --- /dev/null +++ b/boot/arm32/drivers/pl181.c @@ -0,0 +1,163 @@ +#include "pl181.h" +#include +#include + +// #define DEBUG_PL181 + +static sd_card_t sd_card; +static volatile pl181_registers_t* registers; + +static inline int _pl181_map_itself(devtree_entry_t* dev) +{ + registers = (pl181_registers_t*)(uint32_t)dev->region_base; + return 0; +} + +static inline void _pl181_clear_flags() +{ + registers->clear = 0x5FF; +} + +static int _pl181_send_cmd(uint32_t cmd, uint32_t param) +{ + _pl181_clear_flags(); + + registers->arg = param; + registers->cmd = cmd; + + while (registers->status & MMC_STAT_CMD_ACTIVE_MASK) { } + + if ((cmd & MMC_CMD_RESP_MASK) == MMC_CMD_RESP_MASK) { + while (((registers->status & MMC_STAT_CMD_RESP_END_MASK) != MMC_STAT_CMD_RESP_END_MASK) || (registers->status & MMC_STAT_CMD_ACTIVE_MASK)) { + if (registers->status & MMC_STAT_CMD_TIMEOUT_MASK) { + return -1; + } + } + } else { + while ((registers->status & MMC_STAT_CMD_SENT_MASK) != MMC_STAT_CMD_SENT_MASK) { } + } + return 0; +} + +static int _pl181_send_app_cmd(uint32_t cmd, uint32_t param) +{ + for (int i = 0; i < 5; i++) { + _pl181_send_cmd(CMD_APP_CMD | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, 0); + if (registers->response[0] & (1 << 5)) { + return _pl181_send_cmd(cmd, param); + } + } + + log_error("Failed to send app command"); + return -4; +} + +inline static int _pl181_select_card(uint32_t rca) +{ + return _pl181_send_cmd(CMD_SELECT | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, rca); +} + +static int _pl181_read_block(uint32_t lba_like, void* read_data) +{ + sd_card_t* sd_card_ptr = &sd_card; + uint32_t* read_data32 = (uint32_t*)read_data; + uint32_t bytes_read = 0; + + registers->data_length = PL181_SECTOR_SIZE; // Set length of bytes to transfer + registers->data_control = 0b11; // Enable dpsm and set direction from card to host + + if (sd_card_ptr->ishc) { + _pl181_send_cmd(CMD_READ_SINGLE_BLOCK | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, lba_like); + } else { + _pl181_send_cmd(CMD_READ_SINGLE_BLOCK | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, lba_like * PL181_SECTOR_SIZE); + } + + while (registers->status & MMC_STAT_FIFO_DATA_AVAIL_TO_READ_MASK) { + *read_data32 = registers->fifo_data[0]; + read_data32++; + bytes_read += 4; + } + return bytes_read; +} + +static int _pl181_register_device(uint32_t rca, bool ishc, uint32_t capacity) +{ + sd_card.rca = rca; + sd_card.ishc = ishc; + sd_card.capacity = capacity; + _pl181_select_card(rca); + _pl181_send_cmd(CMD_SET_SECTOR_SIZE | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, PL181_SECTOR_SIZE); + if (registers->response[0] != 0x900) { + log_error("PL181(pl181_add_new_device): Can't set sector size"); + return -1; + } + + return 0; +} + +int pl181_init(drive_desc_t* drive_desc) +{ + devtree_entry_t* dev = devtree_find_device("pl181"); + if (!dev) { + return -1; + } + + if (_pl181_map_itself(dev)) { +#ifdef DEBUG_PL181 + log_error("PL181: Can't map itself!"); +#endif + return -1; + } + +#ifdef DEBUG_PL181 + log("PL181: Turning on"); +#endif + + registers->clock = 0x1C6; + registers->power = 0x86; + + // Send cmd 0 to set all cards into idle state + _pl181_send_cmd(CMD_GO_IDLE_STATE | MMC_CMD_ENABLE_MASK, 0x0); + + // Voltage Check + _pl181_send_cmd(8 | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, 0x1AA); + if ((registers->response[0] & 0x1AA) != 0x1AA) { +#ifdef DEBUG_PL181 + log_error("PL181: Can't set voltage!"); +#endif + return -1; + } + + if (_pl181_send_app_cmd(CMD_SD_SEND_OP_COND | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, 1 << 30 | 0x1AA)) { +#ifdef DEBUG_PL181 + log_error("PL181: Can't send APP_CMD!"); +#endif + return -1; + } + + bool ishc = 0; + + if (registers->response[0] & 1 << 30) { + ishc = 1; +#ifdef DEBUG_PL181 + log("PL181: ishc = 1"); +#endif + } + + _pl181_send_cmd(CMD_ALL_SEND_CID | MMC_CMD_ENABLE_MASK | MMC_CMD_LONG_RESP_MASK, 0x0); + _pl181_send_cmd(CMD_SET_RELATIVE_ADDR | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, 0x0); + + // Get the card RCA from the response it is the top 16 bits of the 32 bit response + uint32_t rca = (registers->response[0] & 0xFFFF0000); + + _pl181_send_cmd(CMD_SEND_CSD | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK | MMC_CMD_LONG_RESP_MASK, rca); + uint32_t resp1 = registers->response[1]; + uint32_t capacity = ((resp1 >> 8) & 0x3) << 10; + capacity |= (resp1 & 0xFF) << 2; + capacity = 256 * 1024 * (capacity + 1); + + _pl181_register_device(rca, ishc, capacity); + + drive_desc->read = _pl181_read_block; + return 0; +} \ No newline at end of file diff --git a/boot/arm32/drivers/pl181.h b/boot/arm32/drivers/pl181.h new file mode 100644 index 0000000..47f8af2 --- /dev/null +++ b/boot/arm32/drivers/pl181.h @@ -0,0 +1,73 @@ +#ifndef _BOOT_DRIVERS_PL181_H +#define _BOOT_DRIVERS_PL181_H + +#include +#include + +#define PL181_SECTOR_SIZE 512 + +enum PL181CommandMasks { + MASKDEFINE(MMC_CMD_IDX, 0, 6), + MASKDEFINE(MMC_CMD_RESP, 6, 1), + MASKDEFINE(MMC_CMD_LONG_RESP, 7, 1), + MASKDEFINE(MMC_CMD_INTERRUPT, 8, 1), + MASKDEFINE(MMC_CMD_PENDING, 9, 1), + MASKDEFINE(MMC_CMD_ENABLE, 10, 1), +}; + +enum PL181StatusMasks { + MASKDEFINE(MMC_STAT_CRC_FAIL, 0, 1), + MASKDEFINE(MMC_STAT_CMD_TIMEOUT, 2, 1), + MASKDEFINE(MMC_STAT_CMD_RESP_END, 6, 1), + MASKDEFINE(MMC_STAT_CMD_SENT, 7, 1), + MASKDEFINE(MMC_STAT_CMD_ACTIVE, 11, 1), + MASKDEFINE(MMC_STAT_TRANSMIT_FIFO_EMPTY, 18, 1), + MASKDEFINE(MMC_STAT_FIFO_DATA_AVAIL_TO_READ, 21, 1), +}; + +enum PL181Commands { + CMD_GO_IDLE_STATE = 0, + CMD_ALL_SEND_CID = 2, + CMD_SET_RELATIVE_ADDR = 3, + CMD_SELECT = 7, + CMD_SEND_CSD = 9, + CMD_SEND_CID = 10, + CMD_SET_SECTOR_SIZE = 16, + CMD_READ_SINGLE_BLOCK = 17, + CMD_WRITE_SINGLE_BLOCK = 24, + CMD_SD_SEND_OP_COND = 41, + CMD_APP_CMD = 55, +}; + +struct pl181_registers { + uint32_t power; + uint32_t clock; + uint32_t arg; + uint32_t cmd; + uint32_t resp_cmd; + uint32_t response[4]; + uint32_t data_timer; + uint32_t data_length; + uint32_t data_control; + uint32_t data_count; + uint32_t status; + uint32_t clear; + uint32_t interrupt_mask[2]; + uint32_t interrupt_select; + uint32_t fifo_count; + char res[0x34]; + uint32_t fifo_data[16]; + // TO BE CONTINUED +}; +typedef struct pl181_registers pl181_registers_t; + +struct sd_card { + uint32_t rca; + uint32_t ishc; + uint32_t capacity; +}; +typedef struct sd_card sd_card_t; + +int pl181_init(drive_desc_t* drive_desc); + +#endif // _BOOT_DRIVERS_PL181_H \ No newline at end of file diff --git a/boot/arm32/drivers/uart.c b/boot/arm32/drivers/uart.c new file mode 100644 index 0000000..2cd3925 --- /dev/null +++ b/boot/arm32/drivers/uart.c @@ -0,0 +1,23 @@ +#include "uart.h" +#include + +volatile uint32_t* output = NULL; + +void uart_init() +{ + devtree_entry_t* dev = devtree_find_device("uart"); + if (!dev) { + while (1) { }; + } + output = (uint32_t*)(uint32_t)dev->region_base; +} + +int uart_write(uint8_t data) +{ + if (!output) { + return 1; + } + + *output = data; + return 0; +} \ No newline at end of file diff --git a/boot/arm32/drivers/uart.h b/boot/arm32/drivers/uart.h new file mode 100644 index 0000000..13554e7 --- /dev/null +++ b/boot/arm32/drivers/uart.h @@ -0,0 +1,9 @@ +#ifndef _BOOT_DRIVERS_UART_H +#define _BOOT_DRIVERS_UART_H + +#include + +void uart_init(); +int uart_write(uint8_t data); + +#endif // _BOOT_DRIVERS_UART_H \ No newline at end of file diff --git a/boot/arm32/entry.s b/boot/arm32/entry.s new file mode 100644 index 0000000..10a9e73 --- /dev/null +++ b/boot/arm32/entry.s @@ -0,0 +1,30 @@ +.extern _start +.extern _start_secondary_cpu + +.section ".xos_boot_text" +xos_loader: + ldr sp, =STACK_PHYZ_TOP + + mrc p15, #0, r0, c0, c0, #5 // Read CPU ID register. + and r0, r0, #3 + cmp r0, #0 + bne secondary_cpu_loader + + ldr r0, =_start + mov pc, r0 + +secondary_cpu_loader: + ldr sp, =STACK_SECONDARY_PHYZ_TOP + mov r9, #512 + mrc p15, #0, r8, c0, c0, #5 // Read CPU ID register. + and r8, r8, #3 +1: + sub r8, r8, #1 + cmp r8, #0 + beq secondary_cpu_loader_exit + add r9, r9, #512 + b 1b +secondary_cpu_loader_exit: + subs sp, r9 + ldr r0, =_start_secondary_cpu + mov pc, r0 diff --git a/boot/arm32/hw/ram.c b/boot/arm32/hw/ram.c new file mode 100644 index 0000000..e3ad7d1 --- /dev/null +++ b/boot/arm32/hw/ram.c @@ -0,0 +1,13 @@ +#include "ram.h" +#include +#include + +size_t hw_ram_get_size() +{ + devtree_entry_t* dev = devtree_find_device("ram"); + if (!dev) { + log("Can't find RAM in devtree"); + while (1) { }; + } + return dev->region_size; +} \ No newline at end of file diff --git a/boot/arm32/hw/ram.h b/boot/arm32/hw/ram.h new file mode 100644 index 0000000..0f944a0 --- /dev/null +++ b/boot/arm32/hw/ram.h @@ -0,0 +1,8 @@ +#ifndef _BOOT_HW_RAM_H +#define _BOOT_HW_RAM_H + +#include + +size_t hw_ram_get_size(); + +#endif //_BOOT_HW_RAM_H diff --git a/boot/arm32/main.c b/boot/arm32/main.c new file mode 100644 index 0000000..fbd16f6 --- /dev/null +++ b/boot/arm32/main.c @@ -0,0 +1,153 @@ +#include "drivers/pl181.h" +#include "drivers/uart.h" +#include "vmm/vmm.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// #define DEBUG_BOOT +#define KERNEL_PATH "/boot/kernel.bin" +#define LAUNCH_SERVER_PATH "/System/launch_server" + +extern void jump_to_kernel(void*); +extern uint32_t _odt_phys[]; +extern uint32_t _odt_phys_end[]; + +static void* bootdesc_ptr; +static size_t kernel_vaddr = 0; +static size_t kernel_paddr = 0; +static size_t kernel_size = 0; +static int sync = 0; + +static int alloc_init() +{ + devtree_entry_t* dev = devtree_find_device("ram"); + if (!dev) { + log("Can't find RAM in devtree"); + while (1) { }; + } + + extern int bootloader_start[]; + size_t alloc_space = (size_t)bootloader_start - dev->region_base; + malloc_init((void*)(uint32_t)dev->region_base, alloc_space); + return 0; +} + +static memory_boot_desc_t memory_boot_desc_init() +{ + devtree_entry_t* dev = devtree_find_device("ram"); + if (!dev) { + log("Can't find RAM in devtree"); + while (1) { }; + } + + char dummy_data = 0x0; + memory_boot_desc_t res; + memory_layout_t* mem_layout_paddr = copy_after_kernel(kernel_paddr, &dummy_data, sizeof(dummy_data), &kernel_size, VMM_PAGE_SIZE); + + // Init of trailing element. + mem_layout_paddr[0].flags = MEMORY_LAYOUT_FLAG_TERMINATE; + memory_layout_t* mem_layout_vaddr = paddr_to_vaddr(mem_layout_paddr, kernel_paddr, kernel_vaddr); +#ifdef DEBUG_BOOT + log("initing MEMLAYOUT %lx of %d elems", mem_layout_vaddr, memory_layout_size); +#endif + + res.ram_base = dev->region_base; + res.ram_size = dev->region_size; + res.reserved_areas = mem_layout_vaddr; + return res; +} + +static int prepare_boot_disk(drive_desc_t* drive_desc) +{ + pl181_init(drive_desc); + return -1; +} + +static int prepare_fs(drive_desc_t* drive_desc, fs_desc_t* fs_desc) +{ + if (ext2_lite_init(drive_desc, fs_desc) == 0) { + return 0; + } + return -1; +} + +static int validate_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc) +{ + log("Validating Kernel..."); + if (!validate_elf(KERNEL_PATH, drive_desc, fs_desc)) { + log("Can't validate kernel"); + while (1) { } + } + + if (!validate_elf(LAUNCH_SERVER_PATH, drive_desc, fs_desc)) { + log("Can't validate launch_server"); + while (1) { } + } + + return 0; +} + +static void load_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc) +{ + int res = elf_load_kernel(drive_desc, fs_desc, KERNEL_PATH, &kernel_vaddr, &kernel_paddr, &kernel_size); + kernel_size = align_size(kernel_size, VMM_PAGE_SIZE); +#ifdef DEBUG_BOOT + log("kernel %x %x %x", kernel_vaddr, kernel_paddr, kernel_size); +#endif + + void* odt_ptr = paddr_to_vaddr(copy_after_kernel(kernel_paddr, devtree_start(), devtree_size(), &kernel_size, VMM_PAGE_SIZE), kernel_paddr, kernel_vaddr); +#ifdef DEBUG_BOOT + log("copying ODT %x -> %x of %d", devtree_start(), odt_ptr, devtree_size()); +#endif + + size_t kernel_data_size = kernel_size + align_size(sizeof(boot_args_t), VMM_PAGE_SIZE) + VMM_PAGE_SIZE; + + boot_args_t boot_args; + boot_args.vaddr = kernel_vaddr; + boot_args.paddr = kernel_paddr; + boot_args.kernel_data_size = kernel_data_size; + boot_args.devtree = odt_ptr; + boot_args.mem_boot_desc = memory_boot_desc_init(); + memcpy(boot_args.init_process, LAUNCH_SERVER_PATH, sizeof(LAUNCH_SERVER_PATH)); + + bootdesc_ptr = paddr_to_vaddr(copy_after_kernel(kernel_paddr, &boot_args, sizeof(boot_args), &kernel_size, VMM_PAGE_SIZE), kernel_paddr, kernel_vaddr); +#ifdef DEBUG_BOOT + log("copying BOOTDESC %x -> %x of %d", &boot_args, bootdesc_ptr, sizeof(boot_args)); +#endif +} + +void load_boot_cpu() +{ + devtree_init((void*)_odt_phys, (uint32_t)_odt_phys_end - (uint32_t)_odt_phys); + uart_init(); + log_init(uart_write); + alloc_init(); + + drive_desc_t drive_desc; + fs_desc_t fs_desc; + prepare_boot_disk(&drive_desc); + prepare_fs(&drive_desc, &fs_desc); + validate_kernel(&drive_desc, &fs_desc); + load_kernel(&drive_desc, &fs_desc); + vm_setup(kernel_vaddr, kernel_paddr, kernel_size); + + __atomic_store_n(&sync, 1, __ATOMIC_RELEASE); + jump_to_kernel(bootdesc_ptr); +} + +void load_secondary_cpu() +{ + while (__atomic_load_n(&sync, __ATOMIC_ACQUIRE) == 0) { + continue; + } + vm_setup_secondary_cpu(); + jump_to_kernel(bootdesc_ptr); +} \ No newline at end of file diff --git a/boot/arm32/start_kernel.s b/boot/arm32/start_kernel.s new file mode 100644 index 0000000..30c7f98 --- /dev/null +++ b/boot/arm32/start_kernel.s @@ -0,0 +1,25 @@ +.extern load_boot_cpu +.extern load_secondary_cpu + +.global _start +_start: + ldr r0, =load_boot_cpu + mov pc, r0 +1: + b 1b +.size _start, . - _start + +.global _start_secondary_cpu +_start_secondary_cpu: + ldr r0, =load_secondary_cpu + mov pc, r0 +2: + b 2b + +.global jump_to_kernel +jump_to_kernel: + isb + mov r5, #0xc0000000 + mov pc, r5 +3: + b 3b diff --git a/boot/arm32/vmm/consts.h b/boot/arm32/vmm/consts.h new file mode 100644 index 0000000..34cafc7 --- /dev/null +++ b/boot/arm32/vmm/consts.h @@ -0,0 +1,17 @@ +#ifndef _BOOT_VMM_CONSTS_H +#define _BOOT_VMM_CONSTS_H + +#define VMM_LV0_ENTITY_COUNT (256) +#define VMM_LV1_ENTITY_COUNT (4096) +#define VMM_PAGE_SIZE (4096) + +#define VMM_OFFSET_IN_DIRECTORY(a) (((a) >> 20) & 0xfff) +#define VMM_OFFSET_IN_TABLE(a) (((a) >> 12) & 0xff) +#define VMM_OFFSET_IN_PAGE(a) ((a)&0xfff) +#define TABLE_START(vaddr) ((vaddr >> 20) << 20) +#define PAGE_START(vaddr) ((vaddr >> 12) << 12) +#define FRAME(addr) (addr / VMM_PAGE_SIZE) + +#define PTABLE_TOP_KERNEL_OFFSET 3072 + +#endif //_BOOT_VMM_CONSTS_H diff --git a/boot/arm32/vmm/vmm.c b/boot/arm32/vmm/vmm.c new file mode 100644 index 0000000..de4b0f3 --- /dev/null +++ b/boot/arm32/vmm/vmm.c @@ -0,0 +1,147 @@ +#include "vmm.h" +#include +#include +#include +#include + +// #define DEBUG_VMM + +#define VMM_OFFSET_IN_DIRECTORY(a) (((a) >> 20) & 0xfff) +#define VMM_OFFSET_IN_TABLE(a) (((a) >> 12) & 0xff) +#define VMM_OFFSET_IN_PAGE(a) ((a)&0xfff) +#define ALIGN_TO_TABLE(a) ((a)&0xfff00000) + +static pdirectory_t* pdir = NULL; + +static ptable_t* map_table(size_t tphyz, size_t tvirt); +static void mmu_enable(); + +static inline void write_ttbcr(uint32_t val) +{ + asm volatile("mcr p15, 0, %0, c2, c0, 2" + : + : "r"(val) + : "memory"); + asm volatile("dmb"); +} + +static inline void write_ttbr0(uint32_t val) +{ + asm volatile("mcr p15, 0, %0, c2, c0, 0" + : + : "r"(val) + : "memory"); + asm volatile("dmb"); +} + +static inline void write_dacr(uint32_t val) +{ + asm volatile("mcr p15, 0, %0, c3, c0, 0" + : + : "r"(val)); + asm volatile("dmb"); +} + +static void mmu_enable() +{ + volatile uint32_t val; + asm volatile("mrc p15, 0, %0, c1, c0, 0" + : "=r"(val)); + asm volatile("orr %0, %1, #0x1" + : "=r"(val) + : "r"(val)); + asm volatile("mcr p15, 0, %0, c1, c0, 0" ::"r"(val) + : "memory"); + asm volatile("isb"); +} + +static pdirectory_t* vm_alloc_pdir() +{ + return (pdirectory_t*)malloc_aligned(sizeof(pdirectory_t), sizeof(pdirectory_t)); +} + +static ptable_t* vm_alloc_ptable() +{ + return (ptable_t*)malloc_aligned(sizeof(ptable_t), sizeof(ptable_t)); +} + +static ptable_t* map_table(size_t tphyz, size_t tvirt) +{ + ptable_t* table = vm_alloc_ptable(); + for (size_t phyz = tphyz, virt = tvirt, i = 0; i < VMM_LV0_ENTITY_COUNT; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) { + page_desc_t new_page; + new_page.one = 1; + new_page.baddr = (phyz / VMM_PAGE_SIZE); + new_page.tex = 0b001; + new_page.c = 1; + new_page.b = 1; + new_page.ap1 = 0b11; + new_page.ap2 = 0b0; + new_page.s = 1; + table->entities[i] = new_page; + } + + uint32_t table_int = (uint32_t)table; + pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].valid = 1; + pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].zero1 = 0; + pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].zero2 = 0; + pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].ns = 0; + pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].zero3 = 0; + pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].domain = 0b0011; + pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].baddr = ((table_int / 1024)); + + return table; +} + +static void vm_init() +{ + pdir = vm_alloc_pdir(); + + for (int i = 0; i < VMM_LV1_ENTITY_COUNT; i++) { + pdir->entities[i].valid = 0; + } +} + +static void vm_map_devices() +{ + map_table(0x1c000000, 0x1c000000); // mapping uart +} + +void vm_setup(size_t kernel_vaddr, size_t kernel_paddr, size_t kernel_size) +{ + vm_init(); + vm_map_devices(); + + extern int bootloader_start[]; + size_t bootloader_start_aligned = ALIGN_TO_TABLE((size_t)bootloader_start); + map_table(bootloader_start_aligned, bootloader_start_aligned); +#ifdef DEBUG_VMM + log("map %x to %x", bootloader_start_aligned, bootloader_start_aligned); +#endif + + size_t table_paddr = ALIGN_TO_TABLE(kernel_paddr); + size_t table_vaddr = ALIGN_TO_TABLE(kernel_vaddr); + const size_t bytes_per_table = VMM_LV0_ENTITY_COUNT * VMM_PAGE_SIZE; + const size_t tables_per_kernel = align_size((kernel_size + bytes_per_table - 1) / bytes_per_table, 4); + for (int i = 0; i < tables_per_kernel; i++) { + map_table(table_paddr, table_paddr); + map_table(table_paddr, table_vaddr); +#ifdef DEBUG_VMM + log("map %x to %x", table_paddr, table_paddr); + log("map %x to %x", table_paddr, table_vaddr); +#endif + table_paddr += bytes_per_table; + table_vaddr += bytes_per_table; + } + + write_ttbr0((size_t)(pdir)); + write_dacr(0x55555555); + mmu_enable(); +} + +void vm_setup_secondary_cpu() +{ + write_ttbr0((uint32_t)(pdir)); + write_dacr(0x55555555); + mmu_enable(); +} \ No newline at end of file diff --git a/boot/arm32/vmm/vmm.h b/boot/arm32/vmm/vmm.h new file mode 100644 index 0000000..f24cddf --- /dev/null +++ b/boot/arm32/vmm/vmm.h @@ -0,0 +1,54 @@ +#ifndef _BOOT_VMM_VMM_H +#define _BOOT_VMM_VMM_H + +#include "consts.h" +#include + +struct PACKED page_desc { + union { + struct { + unsigned int xn : 1; // Execute never. Stops execution of page. + unsigned int one : 1; // Always one for tables + unsigned int b : 1; // cacheable + unsigned int c : 1; // Cacheable + unsigned int ap1 : 2; + unsigned int tex : 3; + unsigned int ap2 : 1; + unsigned int s : 1; + unsigned int ng : 1; + unsigned int baddr : 20; + }; + uint32_t data; + }; +}; +typedef struct page_desc page_desc_t; + +struct PACKED table_desc { + union { + struct { + int valid : 1; /* Valid mapping */ + int zero1 : 1; + int zero2 : 1; + int ns : 1; + int zero3 : 1; + int domain : 4; + int imp : 1; + int baddr : 22; + }; + uint32_t data; + }; +}; +typedef struct table_desc table_desc_t; + +typedef struct { + page_desc_t entities[VMM_LV0_ENTITY_COUNT]; +} ptable_t; + +typedef struct pdirectory { + table_desc_t entities[VMM_LV1_ENTITY_COUNT]; +} pdirectory_t; + +void vm_setup(size_t kernel_vaddr, size_t kernel_paddr, size_t kernel_size); +void vm_setup_secondary_cpu(); + +#endif // _BOOT_VMM_VMM_H \ No newline at end of file diff --git a/boot/arm64/prekernel/drivers/fb.c b/boot/arm64/prekernel/drivers/fb.c new file mode 100644 index 0000000..093fb0c --- /dev/null +++ b/boot/arm64/prekernel/drivers/fb.c @@ -0,0 +1,226 @@ +#include "fb.h" +#include +#include + +static char font8x8_basic[128][8]; + +static int _cursor_x = 0; +static int _cursor_y = 0; +static int _fbwidth = 0; +static int _fbheight = 0; +static int _fbpixels_per_row = 0; +static int _fbscale = 1; +static uint32_t _basecolor = 0x0; +volatile uint32_t* _fb = NULL; + +static void system_cache_invalidate(void* addr, size_t size) +{ + const size_t cache_line_size = 64; + size_t start = ROUND_FLOOR((size_t)addr, cache_line_size); + size_t end = ROUND_CEIL((size_t)addr + size, cache_line_size); + + asm volatile("isb"); + asm volatile("dsb sy"); + for (size_t curaddr = start; curaddr < end; curaddr += cache_line_size) { + asm volatile("dc ivac, %0" + : + : "r"(curaddr)); + } + asm volatile("dsb sy"); + asm volatile("isb"); +} + +static void update_cursor_position(char c) +{ + _cursor_x += 8 * _fbscale; + + if (c == '\n' || (_cursor_x + 8 * _fbscale) > _fbwidth) { + _cursor_y += 8 * _fbscale; + _cursor_x = 0; + + if ((_cursor_y + 8 * _fbscale + 2) > _fbheight) { + _cursor_y = 0; + } + } +} + +static void draw_char_on_screen(char c) +{ + for (int x = 0; x < (8 * _fbscale); x++) { + for (int y = 0; y < (8 * _fbscale); y++) { + uint32_t ind = (_cursor_x + x) + ((_cursor_y + y) * _fbpixels_per_row); + uint32_t clr = _basecolor; + if (font8x8_basic[c & 0x7f][y / _fbscale] & (1 << (x / _fbscale))) { + clr ^= 0xffffffff; + } + _fb[ind] = clr; + } + } + system_cache_invalidate((void*)&_fb[_cursor_y * _fbpixels_per_row], (1 + 8 * _fbscale) * _fbpixels_per_row * 4); + update_cursor_position(c); +} + +int fb_init() +{ + devtree_entry_t* dev = devtree_find_device("simplefb"); + if (!dev) { + return -1; + } + + _cursor_x = 0; + _cursor_y = 0; + _fb = (uint32_t*)dev->aux4; + _fbwidth = dev->aux1; + _fbheight = dev->aux2; + _fbpixels_per_row = dev->aux3; + _fbscale = 2; + + return 0; +} + +int fb_reinit_after_map(uintptr_t vaddr) +{ + _fb = (uint32_t*)vaddr; + return 0; +} + +int fb_put_char(uint8_t c) +{ + if (!_fb) { + return -1; + } + + draw_char_on_screen((char)c); + return 0; +} + +static char font8x8_basic[128][8] = { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0000 (nul) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0001 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0002 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0003 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0004 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0005 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0006 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0007 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0008 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0009 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0010 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0011 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0012 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0013 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0014 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0015 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0016 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0017 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0018 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0019 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0020 (space) + { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00 }, // U+0021 (!) + { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0022 (") + { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00 }, // U+0023 (#) + { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00 }, // U+0024 ($) + { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00 }, // U+0025 (%) + { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00 }, // U+0026 (&) + { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0027 (') + { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00 }, // U+0028 (() + { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00 }, // U+0029 ()) + { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00 }, // U+002A (*) + { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00 }, // U+002B (+) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06 }, // U+002C (,) + { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00 }, // U+002D (-) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00 }, // U+002E (.) + { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00 }, // U+002F (/) + { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00 }, // U+0030 (0) + { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00 }, // U+0031 (1) + { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00 }, // U+0032 (2) + { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00 }, // U+0033 (3) + { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00 }, // U+0034 (4) + { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00 }, // U+0035 (5) + { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00 }, // U+0036 (6) + { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00 }, // U+0037 (7) + { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00 }, // U+0038 (8) + { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00 }, // U+0039 (9) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00 }, // U+003A (:) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06 }, // U+003B (;) + { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00 }, // U+003C (<) + { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00 }, // U+003D (=) + { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00 }, // U+003E (>) + { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00 }, // U+003F (?) + { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00 }, // U+0040 (@) + { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00 }, // U+0041 (A) + { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00 }, // U+0042 (B) + { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00 }, // U+0043 (C) + { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00 }, // U+0044 (D) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00 }, // U+0045 (E) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00 }, // U+0046 (F) + { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00 }, // U+0047 (G) + { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00 }, // U+0048 (H) + { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00 }, // U+0049 (I) + { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00 }, // U+004A (J) + { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00 }, // U+004B (K) + { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00 }, // U+004C (L) + { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00 }, // U+004D (M) + { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00 }, // U+004E (N) + { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00 }, // U+004F (O) + { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00 }, // U+0050 (P) + { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00 }, // U+0051 (Q) + { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00 }, // U+0052 (R) + { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00 }, // U+0053 (S) + { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00 }, // U+0054 (T) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00 }, // U+0055 (U) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00 }, // U+0056 (V) + { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00 }, // U+0057 (W) + { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00 }, // U+0058 (X) + { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00 }, // U+0059 (Y) + { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00 }, // U+005A (Z) + { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00 }, // U+005B ([) + { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00 }, // U+005C (\) + { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00 }, // U+005D (]) + { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00 }, // U+005E (^) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }, // U+005F (_) + { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0060 (`) + { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00 }, // U+0061 (a) + { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00 }, // U+0062 (b) + { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00 }, // U+0063 (c) + { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00 }, // U+0064 (d) + { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00 }, // U+0065 (e) + { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00 }, // U+0066 (f) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F }, // U+0067 (g) + { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00 }, // U+0068 (h) + { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00 }, // U+0069 (i) + { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E }, // U+006A (j) + { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00 }, // U+006B (k) + { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00 }, // U+006C (l) + { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00 }, // U+006D (m) + { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00 }, // U+006E (n) + { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00 }, // U+006F (o) + { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F }, // U+0070 (p) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78 }, // U+0071 (q) + { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00 }, // U+0072 (r) + { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00 }, // U+0073 (s) + { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00 }, // U+0074 (t) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00 }, // U+0075 (u) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00 }, // U+0076 (v) + { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00 }, // U+0077 (w) + { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00 }, // U+0078 (x) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F }, // U+0079 (y) + { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00 }, // U+007A (z) + { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00 }, // U+007B ({) + { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00 }, // U+007C (|) + { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00 }, // U+007D (}) + { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+007E (~) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // U+007F +}; diff --git a/boot/arm64/prekernel/drivers/fb.h b/boot/arm64/prekernel/drivers/fb.h new file mode 100644 index 0000000..00b86e2 --- /dev/null +++ b/boot/arm64/prekernel/drivers/fb.h @@ -0,0 +1,11 @@ +#ifndef _BOOT_DRIVERS_SCREEN_H +#define _BOOT_DRIVERS_SCREEN_H + +#include +#include + +int fb_init(); +int fb_reinit_after_map(uintptr_t vaddr); +int fb_put_char(uint8_t c); + +#endif // _BOOT_DRIVERS_SCREEN_H \ No newline at end of file diff --git a/boot/arm64/prekernel/drivers/uart.c b/boot/arm64/prekernel/drivers/uart.c new file mode 100644 index 0000000..d3f4275 --- /dev/null +++ b/boot/arm64/prekernel/drivers/uart.c @@ -0,0 +1,23 @@ +#include "uart.h" +#include + +volatile uint32_t* output = NULL; + +void uart_init() +{ + devtree_entry_t* dev = devtree_find_device("uart"); + if (!dev) { + return; + } + output = (uint32_t*)dev->region_base; +} + +int uart_write(uint8_t data) +{ + if (!output) { + return 1; + } + + *output = data; + return 0; +} \ No newline at end of file diff --git a/boot/arm64/prekernel/drivers/uart.h b/boot/arm64/prekernel/drivers/uart.h new file mode 100644 index 0000000..13554e7 --- /dev/null +++ b/boot/arm64/prekernel/drivers/uart.h @@ -0,0 +1,9 @@ +#ifndef _BOOT_DRIVERS_UART_H +#define _BOOT_DRIVERS_UART_H + +#include + +void uart_init(); +int uart_write(uint8_t data); + +#endif // _BOOT_DRIVERS_UART_H \ No newline at end of file diff --git a/boot/arm64/prekernel/entry.S b/boot/arm64/prekernel/entry.S new file mode 100644 index 0000000..276d777 --- /dev/null +++ b/boot/arm64/prekernel/entry.S @@ -0,0 +1,66 @@ +.extern main + +.section ".xos_boot_text" +prekernel_header: + nop // TODO(arm64): Add UEFI support + b prekernel_entry + +prekernel_entry: + // Calculating location where of start address. + adr x20, . + adr x22, prekernel_header + adr x23, prekernel_entry + sub x21, x23, x22 + sub x20, x20, x21 + + // Saving devtree + mov x21, x0 + + // Setting up prekernel stack. + ldr x30, =PREKERNEL_STACK_TOP_OFFSET + add x30, x20, x30 + mov sp, x30 + + // Base of kernel + mov x0, x20 + // Header location + ldr x1, =PREKERNEL_END_OFFSET + add x1, x20, x1 + // Devtree location + mov x2, x21 + ldr x3, =main + add x3, x3, x20 + blr x3 +entry_loop: + b entry_loop + +.global jump_to_kernel +jump_to_kernel: + ic iallu + dsb sy + isb sy + blr x1 +jump_loop: + b jump_loop + +.global enable_mmu_el1 +enable_mmu_el1: + dsb sy + msr mair_el1, x2 + msr tcr_el1, x1 + msr ttbr0_el1, x0 + msr ttbr1_el1, x3 + isb sy + tlbi vmalle1 + isb sy + ic iallu + isb sy + mrs x3, sctlr_el1 + orr x3, x3, #1 + orr x3, x3, #4 + and x3, x3, #(~2) + msr sctlr_el1, x3 + ic iallu + dsb sy + isb sy + ret \ No newline at end of file diff --git a/boot/arm64/prekernel/main.c b/boot/arm64/prekernel/main.c new file mode 100644 index 0000000..3b5bb24 --- /dev/null +++ b/boot/arm64/prekernel/main.c @@ -0,0 +1,159 @@ +#include "drivers/fb.h" +#include "drivers/uart.h" +#include "vm.h" +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_BOOT +#define EARLY_FB + +extern void jump_to_kernel(void*, uintptr_t); +static void* bootdesc_paddr; +static void* bootdesc_vaddr; +static size_t kernel_vaddr = 0; +static size_t kernel_paddr = 0; +static size_t kernel_size = 0; + +#define LAUNCH_SERVER_PATH "/System/launch_server" + +static int alloc_init(uintptr_t base, rawimage_header_t* riheader) +{ + devtree_entry_t* dev = devtree_find_device("ram"); + if (!dev) { +#ifdef EARLY_FB + log("Can't find RAM in devtree"); +#endif + while (1) { }; + } + + // Currenlty we setting the allocation after the raw image. + // Allocator is used to alloc paddrs for kernel, vm and other. + uintptr_t start_addr = ROUND_CEIL(base + riheader->rawimage_size, page_size()); + size_t free_space = dev->region_size - (start_addr - dev->region_base); + malloc_init((void*)start_addr, free_space); + +#if defined(DEBUG_BOOT) && defined(EARLY_FB) + log("malloc inited %llx %llx", start_addr, free_space); +#endif + return 0; +} + +static size_t memory_layout_size() +{ + return 0 + 1; // Including the trailing element. +} + +static int preserve_alloc_init(size_t kernsize) +{ + const size_t devtreesize = ROUND_CEIL(devtree_size(), page_size()); + const size_t memmap = ROUND_CEIL(memory_layout_size() * sizeof(memory_layout_t), page_size()); + const size_t bootargsstruct = ROUND_CEIL(sizeof(boot_args_t), page_size()); + const size_t bootargssize = devtreesize + memmap + bootargsstruct; + + // 32 tables should be enough for initial mappings. + const size_t prekernelvmsize = 32 * page_size(); + const size_t total = ROUND_CEIL(kernsize + bootargssize + prekernelvmsize, page_size()); + + return palloc_init(total, 2 << 20); +} + +static memory_boot_desc_t memory_boot_desc_init() +{ + devtree_entry_t* dev = devtree_find_device("ram"); + if (!dev) { +#ifdef EARLY_FB + log("Can't find RAM in devtree"); +#endif + while (1) { }; + } + + memory_boot_desc_t res; + const size_t memlayout_size = memory_layout_size(); + memory_layout_t* mem_layout_paddr = palloc_aligned(memlayout_size * sizeof(memory_layout_t), page_size()); + + // Init of trailing element. + mem_layout_paddr[memlayout_size - 1].flags = MEMORY_LAYOUT_FLAG_TERMINATE; + memory_layout_t* mem_layout_vaddr = paddr_to_vaddr(mem_layout_paddr, kernel_paddr, kernel_vaddr); +#if defined(DEBUG_BOOT) && defined(EARLY_FB) + log("initing MEMLAYOUT %lx of %d elems", mem_layout_vaddr, memlayout_size); +#endif + + res.ram_base = dev->region_base; + res.ram_size = dev->region_size; + res.reserved_areas = mem_layout_vaddr; + return res; +} + +static void load_kernel(void* kenrelstart) +{ + kernel_size = elf_get_kernel_size(kenrelstart); + kernel_size = ROUND_CEIL(kernel_size, page_size()); + + int err = preserve_alloc_init(kernel_size); + if (err) { +#ifdef EARLY_FB + log("add assert"); +#endif + while (1) { } + } + + int res = elf_load_kernel(kenrelstart, kernel_size, &kernel_vaddr, &kernel_paddr); +#if defined(DEBUG_BOOT) && defined(EARLY_FB) + log("kernel %lx %lx %lx", kernel_vaddr, kernel_paddr, kernel_size); +#endif + + void* odt_paddr = palloc_aligned(devtree_size(), page_size()); + memcpy(odt_paddr, devtree_start(), devtree_size()); + void* odt_vaddr = paddr_to_vaddr(odt_paddr, kernel_paddr, kernel_vaddr); +#if defined(DEBUG_BOOT) && defined(EARLY_FB) + log("copying ODT %lx -> %lx of %d", devtree_start(), odt_vaddr, devtree_size()); +#endif + + boot_args_t boot_args; + boot_args.vaddr = kernel_vaddr; + boot_args.paddr = kernel_paddr; + boot_args.kernel_data_size = 0x0; // Sets up later + boot_args.mem_boot_desc = memory_boot_desc_init(); + boot_args.devtree = odt_vaddr; + boot_args.fb_boot_desc.vaddr = 0; // Marking fb as invalid. + memcpy(boot_args.init_process, LAUNCH_SERVER_PATH, sizeof(LAUNCH_SERVER_PATH)); + + bootdesc_paddr = palloc_aligned(sizeof(boot_args), page_size()); + memcpy(bootdesc_paddr, &boot_args, sizeof(boot_args)); + bootdesc_vaddr = paddr_to_vaddr(bootdesc_paddr, kernel_paddr, kernel_vaddr); +#if defined(DEBUG_BOOT) && defined(EARLY_FB) + log("copying BOOTDESC %lx -> %lx of %d", &boot_args, bootdesc_vaddr, sizeof(boot_args)); +#endif +} + +static int log_merged_output(uint8_t ch) +{ + uart_write(ch); + fb_put_char(ch); + return 0; +} + +int main(uintptr_t base, rawimage_header_t* riheader, void* devtree) +{ + devtree_init((void*)(base + riheader->devtree_off), riheader->devtree_size); + uart_init(); + fb_init(); + log_init(log_merged_output); + alloc_init(base, riheader); + + load_kernel((void*)(base + riheader->kern_off)); + vm_setup(base, bootdesc_paddr, riheader); + +#ifdef DEBUG_BOOT + log("Preboot done: booting to OS@%llx", ((boot_args_t*)bootdesc_vaddr)->vaddr); +#endif + + ((boot_args_t*)bootdesc_vaddr)->kernel_data_size = ROUND_CEIL(palloc_used_size(), page_size()); + jump_to_kernel((void*)bootdesc_vaddr, ((boot_args_t*)bootdesc_vaddr)->vaddr); + return 0; +} \ No newline at end of file diff --git a/boot/arm64/prekernel/vm.c b/boot/arm64/prekernel/vm.c new file mode 100644 index 0000000..e96a4f1 --- /dev/null +++ b/boot/arm64/prekernel/vm.c @@ -0,0 +1,168 @@ +#include "vm.h" +#include "drivers/fb.h" +#include +#include +#include +#include +#include +#include + +// #define DEBUG_VM + +static uint64_t* global_page_table_0; +static uint64_t* global_page_table_1; + +// This is setup for 4KB pages +static const int tg0 = 0b00; +static const int tg1 = 0b10; +static const int t0sz = 25; +static const int t1sz = 25; +static const uint64_t kernel_base = 0xffffffffffffffff - ((1ull << (64 - t1sz)) - 1); + +static uint64_t* new_ptable(boot_args_t* args) +{ + uint64_t* res = (uint64_t*)palloc_aligned(page_size(), page_size()); + memset(res, 0, page_size()); +#ifdef DEBUG_VM + log(" alloc ptable %llx %llx", (uint64_t)res, page_size()); +#endif + return res; +} + +// Huge page impl is not suitable for Apl, where we need percise mappings. +static void map4kb_1gb(boot_args_t* args, size_t phyz, size_t virt) +{ + const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET); + const size_t page_mask = page_covers - 1; + + if ((phyz & page_mask) != 0 || (virt & page_mask) != 0) { + return; + } + + // Mapping from level2, as needed. + uint64_t* page_table = global_page_table_0; + if (virt >= kernel_base) { + page_table = global_page_table_1; + virt -= kernel_base; + } + + uint64_t pdesc = 0x00000000000701; + pdesc |= (uintptr_t)phyz; + page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)] = pdesc; +} + +static void map4kb_2mb(boot_args_t* args, size_t phyz, size_t virt) +{ + const size_t page_covers = (1ull << PTABLE_LV1_VADDR_OFFSET); + const size_t page_mask = page_covers - 1; + + if ((phyz & page_mask) != 0 || (virt & page_mask) != 0) { + return; + } + + // Mapping from level2, as needed. + uint64_t* page_table = global_page_table_0; + if (virt >= kernel_base) { + page_table = global_page_table_1; + virt -= kernel_base; + } + + uint64_t ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)]; + if (ptable_desc == 0) { + uint64_t* nptbl = new_ptable(args); + uint64_t pdesc = 0x00000000000003; + pdesc |= (uintptr_t)nptbl; + page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)] = pdesc; + ptable_desc = pdesc; + } + + page_table = (uint64_t*)(((ptable_desc >> 12) << 12) & 0xffffffffffff); + uint64_t pdesc = 0x00000000000701; + pdesc |= (uintptr_t)phyz; + page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV1_VADDR_OFFSET, VMM_LV1_ENTITY_COUNT)] = pdesc; +} + +static void map_uart(boot_args_t* args) +{ + devtree_entry_t* dev = devtree_find_device("uart"); + if (!dev) { + return; + } + + uint64_t paddr = dev->region_base; + const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET); + paddr &= ~(page_covers - 1); + +#ifdef DEBUG_VM + log("mapping %lx %lx", paddr, paddr); +#endif + map4kb_1gb(args, paddr, paddr); +} + +static void map_fb(boot_args_t* args) +{ + devtree_entry_t* dev = devtree_find_device("simplefb"); + if (!dev) { + return; + } + + uint64_t paddr = dev->region_base; + const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET); + paddr &= ~(page_covers - 1); + +#ifdef DEBUG_VM + log("mapping %lx %lx", paddr, 0xfc0000000ULL); +#endif + map4kb_1gb(args, paddr, 0xfc0000000ULL); + + args->fb_boot_desc.paddr = dev->region_base; + args->fb_boot_desc.vaddr = 0xfc0000000ULL + (args->fb_boot_desc.paddr - paddr); + args->fb_boot_desc.width = dev->aux1; + args->fb_boot_desc.height = dev->aux2; + args->fb_boot_desc.pixels_per_row = dev->aux3; +} + +void vm_setup(uintptr_t base, boot_args_t* args, rawimage_header_t* riheader) +{ + // This implementation is a stub, supporting only 4kb pages for now. + // We should support 16kb pages for sure on modern Apls. + global_page_table_0 = (uint64_t*)palloc_aligned(page_size(), page_size()); + memset(global_page_table_0, 0, page_size()); + + global_page_table_1 = (uint64_t*)palloc_aligned(page_size(), page_size()); + memset(global_page_table_1, 0, page_size()); + + const size_t map_range_2mb = (2 << 20); + const size_t map_range_1gb = (1 << 30); + + // Mapping kernel vaddr to paddr + size_t kernel_size_to_map = palloc_total_size() + shadow_area_size(); + size_t kernel_range_count_to_map = (kernel_size_to_map + (map_range_2mb - 1)) / map_range_2mb; + for (size_t i = 0; i < kernel_range_count_to_map; i++) { +#ifdef DEBUG_VM + log("mapping %lx %lx", args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb); +#endif + map4kb_2mb(args, args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb); + } + + // Mapping RAM + size_t ram_base = ROUND_FLOOR(args->mem_boot_desc.ram_base, map_range_1gb); + size_t ram_size = args->mem_boot_desc.ram_size; + size_t ram_range_count_to_map = (ram_size + (map_range_1gb - 1)) / map_range_1gb; + for (size_t i = 0; i < ram_range_count_to_map; i++) { +#ifdef DEBUG_VM + log("mapping %lx %lx", ram_base + i * map_range_1gb, ram_base + i * map_range_1gb); +#endif + map4kb_1gb(args, ram_base + i * map_range_1gb, ram_base + i * map_range_1gb); + } + + // The initial boot requires framebuffer and uart to be mapped. + // Checking this and mapping devices. + map_uart(args); + map_fb(args); + + extern void enable_mmu_el1(uint64_t ttbr0, uint64_t tcr, uint64_t mair, uint64_t ttbr1); + enable_mmu_el1((uint64_t)global_page_table_0, 0x135003500 | (tg0 << 14) | (tg1 << 30) | (t1sz << 16) | t0sz, 0x04ff, (uint64_t)global_page_table_1); + + fb_reinit_after_map(args->fb_boot_desc.vaddr); +} diff --git a/boot/arm64/prekernel/vm.h b/boot/arm64/prekernel/vm.h new file mode 100644 index 0000000..a661e30 --- /dev/null +++ b/boot/arm64/prekernel/vm.h @@ -0,0 +1,25 @@ +#ifndef _BOOT_VM_H +#define _BOOT_VM_H + +#include +#include +#include + +#define VMM_LV0_ENTITY_COUNT (512) +#define VMM_LV1_ENTITY_COUNT (512) +#define VMM_LV2_ENTITY_COUNT (512) +#define VMM_LV3_ENTITY_COUNT (512) + +#define PTABLE_LV_TOP (2) +#define PTABLE_LV0_VADDR_OFFSET (12) +#define PTABLE_LV1_VADDR_OFFSET (21) +#define PTABLE_LV2_VADDR_OFFSET (30) +#define PTABLE_LV3_VADDR_OFFSET (39) + +#define VM_VADDR_OFFSET_AT_LEVEL(vaddr, off, ent) ((vaddr >> off) % ent) + +static size_t page_size() { return 0x1000; } + +void vm_setup(uintptr_t base, boot_args_t* args, rawimage_header_t* riheader); + +#endif // _BOOT_VM_H \ No newline at end of file diff --git a/boot/libboot/abi/drivers.h b/boot/libboot/abi/drivers.h new file mode 100644 index 0000000..de362d8 --- /dev/null +++ b/boot/libboot/abi/drivers.h @@ -0,0 +1,29 @@ +#ifndef _BOOT_LIBBOOT_ABI_DRIVERS_H +#define _BOOT_LIBBOOT_ABI_DRIVERS_H + +#include + +#define MASKDEFINE(N, P, S) \ + N##_POS = (P), \ + N##_SIZE = (S), \ + N##_MASK = ((~(~0 << (S))) << (P)) + +#define TOKEN_PASTE_IMPL(x, y) x##y +#define TOKEN_PASTE(x, y) TOKEN_PASTE_IMPL(x, y) +#define SKIP(x, y) char TOKEN_PASTE(prefix, __LINE__)[y - x - 8] + +struct drive_desc { + void* init; + void* read; + void* write; +}; +typedef struct drive_desc drive_desc_t; + +struct fs_desc { + int (*get_inode)(drive_desc_t* drive_desc, const char* path, void* file_inode); + int (*read)(drive_desc_t* drive_desc, const char* path, uint8_t* buf, uint32_t from, uint32_t len); + int (*read_from_inode)(drive_desc_t* drive_desc, void* file_inode, uint8_t* buf, uint32_t from, uint32_t len); +}; +typedef struct fs_desc fs_desc_t; + +#endif // _BOOT_LIBBOOT_ABI_DRIVERS_H \ No newline at end of file diff --git a/boot/libboot/abi/kernel.h b/boot/libboot/abi/kernel.h new file mode 100644 index 0000000..c453616 --- /dev/null +++ b/boot/libboot/abi/kernel.h @@ -0,0 +1,11 @@ +#ifndef _BOOT_LIBBOOT_ABI_KERNEL_H +#define _BOOT_LIBBOOT_ABI_KERNEL_H + +#include + +// Bootloaders and Kernel are tight together and share ABI in order +// to run kernel, see docs/boot.md for more information. + +static size_t shadow_area_size() { return 4 << 20; } + +#endif // _BOOT_LIBBOOT_ABI_KERNEL_H \ No newline at end of file diff --git a/boot/libboot/abi/memory.h b/boot/libboot/abi/memory.h new file mode 100644 index 0000000..c09739f --- /dev/null +++ b/boot/libboot/abi/memory.h @@ -0,0 +1,45 @@ +#ifndef _BOOT_LIBBOOT_ABI_MEMORY_H +#define _BOOT_LIBBOOT_ABI_MEMORY_H + +#include + +enum MEMORY_LAYOUT_FLAGS { + MEMORY_LAYOUT_FLAG_TERMINATE = (1 << 0), +}; + +struct memory_layout { + uint64_t base; + uint64_t size; + uint32_t flags; +}; +typedef struct memory_layout memory_layout_t; + +struct memory_boot_desc { + uint64_t ram_base; + uint64_t ram_size; + memory_layout_t* reserved_areas; +}; +typedef struct memory_boot_desc memory_boot_desc_t; + +struct fb_boot_desc { + uintptr_t vaddr; + uintptr_t paddr; + size_t width; + size_t height; + size_t pixels_per_row; +}; +typedef struct fb_boot_desc fb_boot_desc_t; + +struct boot_args { + size_t paddr; + size_t vaddr; + size_t kernel_data_size; + memory_boot_desc_t mem_boot_desc; + fb_boot_desc_t fb_boot_desc; + void* devtree; + char cmd_args[32]; + char init_process[32]; +}; +typedef struct boot_args boot_args_t; + +#endif // _BOOT_LIBBOOT_ABI_MEMORY_H \ No newline at end of file diff --git a/boot/libboot/abi/multiboot.h b/boot/libboot/abi/multiboot.h new file mode 100644 index 0000000..a962745 --- /dev/null +++ b/boot/libboot/abi/multiboot.h @@ -0,0 +1,110 @@ +#ifndef _BOOT_LIBBOOT_ABI_MULTIBOOT_H +#define _BOOT_LIBBOOT_ABI_MULTIBOOT_H + +#include + +#define MULTIBOOT_INFO_MEMORY (0x1) +#define MULTIBOOT_INFO_BOOTDEV (0x2) +#define MULTIBOOT_INFO_CMDLINE (0x4) +#define MULTIBOOT_INFO_MODS (0x8) +#define MULTIBOOT_INFO_AOUT_SYMS (0x10) +#define MULTIBOOT_INFO_ELF_SHDR (0x20) +#define MULTIBOOT_INFO_MEM_MAP (0x40) +#define MULTIBOOT_INFO_DRIVE_INFO (0x80) +#define MULTIBOOT_INFO_CONFIG_TABLE (0x100) +#define MULTIBOOT_INFO_BOOT_LOADER_NAME (0x200) +#define MULTIBOOT_INFO_APM_TABLE (0x400) +#define MULTIBOOT_INFO_VBE_INFO (0x800) +#define MULTIBOOT_INFO_FRAMEBUFFER_INFO (0x1000) + +struct multiboot_module_entry { + uint32_t start; + uint32_t end; + uint32_t string_addr; + uint32_t reserved; +}; +typedef struct multiboot_module_entry multiboot_module_entry_t; + +struct multiboot_aout_symbol_table { + uint32_t tabsize; + uint32_t strsize; + uint32_t addr; + uint32_t reserved; +}; +typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; + +struct multiboot_elf_section_header_table { + uint32_t num; + uint32_t size; + uint32_t addr; + uint32_t shndx; +}; +typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; + +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 +struct PACKED multiboot_mmap_entry { + uint32_t size; + uint64_t addr; + uint64_t len; + uint32_t type; +}; +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 +struct multiboot_info { + uint32_t flags; + uint32_t mem_lower; + uint32_t mem_upper; + uint32_t boot_device; + uint32_t cmdline; + uint32_t mods_count; + uint32_t mods_addr; + union { + multiboot_aout_symbol_table_t aout_sym; + multiboot_elf_section_header_table_t elf_sec; + } syms; + uint32_t mmap_length; + uint32_t mmap_addr; + uint32_t drives_length; + uint32_t drives_addr; + uint32_t config_table; + uint32_t boot_loader_name; + uint32_t apm_table; + uint32_t vbe_control_info; + uint32_t vbe_mode_info; + uint16_t vbe_mode; + uint16_t vbe_interface_seg; + uint16_t vbe_interface_off; + uint16_t vbe_interface_len; + uint64_t framebuffer_addr; + uint32_t framebuffer_pitch; + uint32_t framebuffer_width; + uint32_t framebuffer_height; + uint8_t framebuffer_bpp; + uint8_t framebuffer_type; + union { + struct + { + uint32_t framebuffer_palette_addr; + uint16_t framebuffer_palette_num_colors; + }; + struct + { + uint8_t framebuffer_red_field_position; + uint8_t framebuffer_red_mask_size; + uint8_t framebuffer_green_field_position; + uint8_t framebuffer_green_mask_size; + uint8_t framebuffer_blue_field_position; + uint8_t framebuffer_blue_mask_size; + }; + }; +}; +typedef struct multiboot_info multiboot_info_t; + +#endif // _BOOT_LIBBOOT_ABI_MULTIBOOT_H \ No newline at end of file diff --git a/boot/libboot/abi/rawimage.h b/boot/libboot/abi/rawimage.h new file mode 100644 index 0000000..25665e9 --- /dev/null +++ b/boot/libboot/abi/rawimage.h @@ -0,0 +1,18 @@ +#ifndef _BOOT_LIBBOOT_ABI_RAWIMAGE_H +#define _BOOT_LIBBOOT_ABI_RAWIMAGE_H + +#include + +struct rawimage_header { + uint64_t kern_off; + uint64_t kern_size; + uint64_t devtree_off; + uint64_t devtree_size; + uint64_t ramdisk_off; + uint64_t ramdisk_size; + uint64_t rawimage_size; + uint64_t padding; +}; +typedef struct rawimage_header rawimage_header_t; + +#endif // _BOOT_LIBBOOT_ABI_RAWIMAGE_H \ No newline at end of file diff --git a/boot/libboot/crypto/sha256.c b/boot/libboot/crypto/sha256.c new file mode 100644 index 0000000..26acfb1 --- /dev/null +++ b/boot/libboot/crypto/sha256.c @@ -0,0 +1,149 @@ +#include "sha256.h" +#include +#include + +const static sha256_word_t sha256_consts[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +const static sha256_word_t sha256_state_init[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +#define ROTLEFT(a, b) (((a) << (b)) | ((a) >> (32 - (b)))) +#define ROTRIGHT(a, b) (((a) >> (b)) | ((a) << (32 - (b)))) + +#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z))) +#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EP0(x) (ROTRIGHT(x, 2) ^ ROTRIGHT(x, 13) ^ ROTRIGHT(x, 22)) +#define EP1(x) (ROTRIGHT(x, 6) ^ ROTRIGHT(x, 11) ^ ROTRIGHT(x, 25)) +#define SIG0(x) (ROTRIGHT(x, 7) ^ ROTRIGHT(x, 18) ^ ((x) >> 3)) +#define SIG1(x) (ROTRIGHT(x, 17) ^ ROTRIGHT(x, 19) ^ ((x) >> 10)) + +static void sha256_transform(sha256_ctx_t* ctx, const void* vdata) +{ + sha256_byte_t* data = (sha256_byte_t*)vdata; + sha256_word_t m[64]; + + size_t i = 0; + for (sha256_word_t j = 0; i < 16; i++, j += 4) { + m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); + } + + for (; i < 64; i++) { + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + } + + sha256_word_t a = ctx->state[0]; + sha256_word_t b = ctx->state[1]; + sha256_word_t c = ctx->state[2]; + sha256_word_t d = ctx->state[3]; + sha256_word_t e = ctx->state[4]; + sha256_word_t f = ctx->state[5]; + sha256_word_t g = ctx->state[6]; + sha256_word_t h = ctx->state[7]; + + for (i = 0; i < 64; i++) { + sha256_word_t t1 = h + EP1(e) + CH(e, f, g) + sha256_consts[i] + m[i]; + sha256_word_t t2 = EP0(a) + MAJ(a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + +void sha256_init(sha256_ctx_t* ctx) +{ + ctx->bufnxt = 0; + ctx->bits_count = 0; + memcpy(ctx->state, sha256_state_init, sizeof(sha256_state_init)); +} + +void sha256_update(sha256_ctx_t* ctx, const void* vdata, size_t len) +{ + sha256_byte_t* data = (sha256_byte_t*)vdata; + + for (size_t i = 0; i < len; i++) { + ctx->buf[ctx->bufnxt] = data[i]; + ctx->bufnxt++; + if (ctx->bufnxt == 64) { + sha256_transform(ctx, ctx->buf); + ctx->bits_count += 512; + ctx->bufnxt = 0; + } + } +} + +void sha256_hash(sha256_ctx_t* ctx, char* hash) +{ + size_t i = ctx->bufnxt; + + if (ctx->bufnxt < 56) { + ctx->buf[i++] = 0x80; + } else { + ctx->buf[i++] = 0x80; + while (i < 64) { + ctx->buf[i++] = 0x00; + } + sha256_transform(ctx, ctx->buf); + i = 0; + } + + while (i < 56) { + ctx->buf[i++] = 0x00; + } + + ctx->bits_count += ctx->bufnxt * 8; + ctx->buf[56] = ctx->bits_count >> 56; + ctx->buf[57] = ctx->bits_count >> 48; + ctx->buf[58] = ctx->bits_count >> 40; + ctx->buf[59] = ctx->bits_count >> 32; + ctx->buf[60] = ctx->bits_count >> 24; + ctx->buf[61] = ctx->bits_count >> 16; + ctx->buf[62] = ctx->bits_count >> 8; + ctx->buf[63] = ctx->bits_count >> 0; + + sha256_transform(ctx, ctx->buf); + + // Making hash big endian. + for (i = 0; i < 4; i++) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; + } +} \ No newline at end of file diff --git a/boot/libboot/crypto/sha256.h b/boot/libboot/crypto/sha256.h new file mode 100644 index 0000000..127f563 --- /dev/null +++ b/boot/libboot/crypto/sha256.h @@ -0,0 +1,22 @@ +#ifndef _BOOT_LIBBOOT_CRYPTO_SHA256_H +#define _BOOT_LIBBOOT_CRYPTO_SHA256_H + +#include +#include + +typedef uint8_t sha256_byte_t; +typedef uint32_t sha256_word_t; + +struct sha256_ctx { + uint64_t bits_count; + sha256_word_t state[8]; + sha256_word_t bufnxt; + sha256_byte_t buf[64]; +}; +typedef struct sha256_ctx sha256_ctx_t; + +void sha256_init(sha256_ctx_t* ctx); +void sha256_update(sha256_ctx_t* ctx, const void* data, size_t len); +void sha256_hash(sha256_ctx_t* ctx, char* hash); + +#endif // #define _BOOT_LIBBOOT_CRYPTO_SHA256_H \ No newline at end of file diff --git a/boot/libboot/crypto/signature.c b/boot/libboot/crypto/signature.c new file mode 100644 index 0000000..3380ba4 --- /dev/null +++ b/boot/libboot/crypto/signature.c @@ -0,0 +1,136 @@ +const char pub_xos_key_e[] = { + (char)0x1, + (char)0x0, + (char)0x1, +}; + +const char pub_xos_key_n[] = { + (char)0x1d, + (char)0x7e, + (char)0x51, + (char)0xed, + (char)0xdc, + (char)0x86, + (char)0x89, + (char)0x86, + (char)0xb1, + (char)0xa4, + (char)0x84, + (char)0x87, + (char)0xc9, + (char)0x35, + (char)0xe7, + (char)0x7f, + (char)0x8a, + (char)0xea, + (char)0xcb, + (char)0xda, + (char)0xdf, + (char)0xec, + (char)0x7a, + (char)0xa5, + (char)0x2a, + (char)0x60, + (char)0x15, + (char)0x91, + (char)0x14, + (char)0xd5, + (char)0x2c, + (char)0xbb, + (char)0x8f, + (char)0x8f, + (char)0xad, + (char)0x17, + (char)0x5b, + (char)0xd7, + (char)0xda, + (char)0x4d, + (char)0x4b, + (char)0xe3, + (char)0x3e, + (char)0x83, + (char)0xb5, + (char)0xb4, + (char)0x38, + (char)0x60, + (char)0x59, + (char)0x94, + (char)0xef, + (char)0xad, + (char)0x39, + (char)0x72, + (char)0x9d, + (char)0x7d, + (char)0xc6, + (char)0x1b, + (char)0xcf, + (char)0x4e, + (char)0x6f, + (char)0xee, + (char)0xf7, + (char)0xd3, + (char)0xbc, + (char)0xcf, + (char)0xe9, + (char)0xb9, + (char)0xf1, + (char)0x21, + (char)0xef, + (char)0x9a, + (char)0x6, + (char)0x75, + (char)0xc8, + (char)0xc2, + (char)0x6e, + (char)0x99, + (char)0x28, + (char)0xa6, + (char)0x3, + (char)0xe6, + (char)0xc6, + (char)0x4d, + (char)0x2, + (char)0x83, + (char)0xe4, + (char)0xe0, + (char)0x21, + (char)0xd9, + (char)0x19, + (char)0x11, + (char)0x29, + (char)0xe8, + (char)0xff, + (char)0x11, + (char)0x7, + (char)0x23, + (char)0x44, + (char)0x7f, + (char)0xfb, + (char)0x76, + (char)0xb1, + (char)0x7, + (char)0xe7, + (char)0xab, + (char)0x83, + (char)0x7e, + (char)0xa6, + (char)0xd9, + (char)0x7a, + (char)0x50, + (char)0x36, + (char)0xf, + (char)0xb3, + (char)0xc0, + (char)0xb7, + (char)0x4f, + (char)0x17, + (char)0xc7, + (char)0xb5, + (char)0x50, + (char)0xe8, + (char)0xe6, + (char)0xc1, + (char)0x3f, + (char)0x5f, + (char)0xa6, +}; \ No newline at end of file diff --git a/boot/libboot/crypto/signature.h b/boot/libboot/crypto/signature.h new file mode 100644 index 0000000..7e2673c --- /dev/null +++ b/boot/libboot/crypto/signature.h @@ -0,0 +1,10 @@ +#ifndef _BOOT_LIBBOOT_CRYPTO_SIGNATURE_H +#define _BOOT_LIBBOOT_CRYPTO_SIGNATURE_H + +#define pub_xos_key_e_len (3) +extern const char pub_xos_key_e[]; + +#define pub_xos_key_n_len (128) +extern const char pub_xos_key_n[]; + +#endif // _BOOT_LIBBOOT_CRYPTO_SIGNATURE_H diff --git a/boot/libboot/crypto/uint2048.c b/boot/libboot/crypto/uint2048.c new file mode 100644 index 0000000..540013f --- /dev/null +++ b/boot/libboot/crypto/uint2048.c @@ -0,0 +1,299 @@ +#include "uint2048.h" +#include +#include + +#define EOVERFLOW 75 + +int uint2048_init(uint2048_t* d, uint32_t n) +{ + int i = 0; + d->bucket[i++] = n; + while (i < N_UINT2048) { + d->bucket[i++] = 0; + } + return 0; +} + +int uint2048_init_bytes(uint2048_t* d, const char* f, size_t n) +{ + if (n > sizeof(uint2048_t)) { + return -1; + } + memset(d->bucket, 0, sizeof(uint2048_t)); + memcpy(d->bucket, f, n); + return 0; +} + +static inline uint32_t char_to_u32_safe_convert(char x) +{ + return x >= 0 ? x : 256 + x; +} + +int uint2048_init_bytes_be(uint2048_t* d, const char* f, size_t n) +{ + if (n > sizeof(uint2048_t)) { + return -1; + } + + size_t i = 0; + uint32_t bytes4 = 0; + size_t dd = (n / 4) * 4; + size_t dr = n - dd; + for (int fi = n - 4; fi >= 0; fi -= 4) { + bytes4 = 0; + bytes4 |= char_to_u32_safe_convert(f[fi]) << 24; + bytes4 |= char_to_u32_safe_convert(f[fi + 1]) << 16; + bytes4 |= char_to_u32_safe_convert(f[fi + 2]) << 8; + bytes4 |= char_to_u32_safe_convert(f[fi + 3]) << 0; + d->bucket[i++] = bytes4; + } + + bytes4 = 0; + for (int remi = dr - 1; remi >= 0; remi--) { + bytes4 |= char_to_u32_safe_convert(f[dd + remi]) << (remi * 8); + } + d->bucket[i++] = bytes4; + + while (i < N_UINT2048) { + d->bucket[i++] = 0; + } + + return 0; +} + +int uint2048_copy(uint2048_t* dest, uint2048_t* src) +{ + memcpy(dest, src, sizeof(uint2048_bucket_t) * N_UINT2048); + return 0; +} + +int uint2048_add(uint2048_t* a, uint2048_t* b, uint2048_t* c) +{ + uint64_t carry = 0; + uint64_t sum = 0; + for (int i = 0; i < N_UINT2048; i++) { + uint64_t ab = a->bucket[i]; + uint64_t bb = b->bucket[i]; + sum = ab + bb + carry; + if (sum >= BASE_UINT2048U) { + carry = 1; + sum -= BASE_UINT2048U; + } else { + carry = 0; + } + c->bucket[i] = (uint2048_bucket_t)sum; + } + + return carry ? -EOVERFLOW : 0; +} + +int uint2048_sub(uint2048_t* a, uint2048_t* b, uint2048_t* c) +{ + uint32_t carry = 0; + uint64_t sum = 0; + for (int i = 0; i < N_UINT2048; i++) { + uint64_t ab = a->bucket[i]; + uint64_t bb = b->bucket[i]; + sum = carry + bb; + if (ab >= sum) { + ab = ab - (sum); + carry = 0; + } else { + ab = ab + BASE_UINT2048U - (sum); + carry = 1; + } + c->bucket[i] = (uint2048_bucket_t)ab; + } + + if (carry) { + uint2048_init(c, 0); + } + return carry ? -EOVERFLOW : 0; +} + +int uint2048_shl(uint2048_t* a, int n) +{ + int i; + for (i = N_UINT2048 - 1; i >= n; i--) { + a->bucket[i] = a->bucket[i - n]; + } + + while (i >= 0) { + a->bucket[i--] = 0; + } + + return 0; +} + +int uint2048_shr(uint2048_t* a, int n) +{ + int i; + for (i = 0; i < N_UINT2048 - n; i++) { + a->bucket[i] = a->bucket[i + n]; + } + while (i < N_UINT2048) { + a->bucket[i++] = 0; + } + + return 0; +} + +int uint2048_mult_by_digit(uint2048_t* a, uint2048_t* b, uint2048_bucket_t un) +{ + uint64_t carry = 0; + uint64_t tmp; + uint64_t n = (uint64_t)un; + for (int i = 0; i < N_UINT2048; i++) { + uint64_t ab = a->bucket[i]; + tmp = n * ab + carry; + if (tmp >= BASE_UINT2048U) { + carry = tmp / BASE_UINT2048U; + tmp %= BASE_UINT2048U; + } else { + carry = 0; + } + + b->bucket[i] = (uint2048_bucket_t)tmp; + } + + return carry ? -EOVERFLOW : 0; +} + +int uint2048_mult(uint2048_t* a, uint2048_t* b, uint2048_t* c) +{ + uint2048_t p; + + uint2048_init(c, 0); + for (int i = 0; i < N_UINT2048; i++) { + if (!a->bucket[i]) { + continue; + } + uint2048_mult_by_digit(b, &p, a->bucket[i]); + uint2048_shl(&p, i); + uint2048_add(c, &p, c); + } + + return 0; +} + +int uint2048_div(uint2048_t* a, uint2048_t* b, uint2048_t* dividend, uint2048_t* reminder) +{ + uint2048_t tmp; + + if (dividend) { + uint2048_init(dividend, 0); + } + uint2048_init(reminder, 0); + for (int i = N_UINT2048 - 1; i >= 0; i--) { + uint2048_shl(reminder, 1); + reminder->bucket[0] = a->bucket[i]; + uint64_t l = 0, r = BASE_UINT2048U; + while (r - l > 1) { + uint64_t m = (l + r) / 2; + uint2048_mult_by_digit(b, &tmp, (uint2048_bucket_t)m); + if (uint2048_less_equal(&tmp, reminder)) { + l = m; + } else { + r = m; + } + } + + if (dividend) { + dividend->bucket[i] = (uint2048_bucket_t)l; + } + uint2048_mult_by_digit(b, &tmp, (uint2048_bucket_t)l); + uint2048_sub(reminder, &tmp, reminder); + } + + return 0; +} + +int uint2048_pow(uint2048_t* ua, uint2048_t* up, uint2048_t* mod, uint2048_t* ans) +{ + uint2048_t tmp1; + uint2048_t tmp2; + uint2048_t const2; + uint2048_t a; + uint2048_t p; + + uint2048_copy(&a, ua); + uint2048_copy(&p, up); + + uint2048_init(ans, 1); + uint2048_init(&const2, 2); + while (uint2048_is_not_zero(&p)) { + if (uint2048_is_odd(&p)) { + uint2048_mult(ans, &a, &tmp1); + uint2048_div(&tmp1, mod, NULL, &tmp2); + uint2048_copy(ans, &tmp2); + } + uint2048_mult(&a, &a, &tmp1); + uint2048_div(&tmp1, mod, NULL, &tmp2); + uint2048_copy(&a, &tmp2); + + uint2048_div(&p, &const2, &tmp1, &tmp2); + uint2048_copy(&p, &tmp1); + } + + return 0; +} + +bool uint2048_less(uint2048_t* a, uint2048_t* b) +{ + for (int i = N_UINT2048 - 1; i >= 0; i--) { + if (a->bucket[i] < b->bucket[i]) { + return true; + } + if (a->bucket[i] > b->bucket[i]) { + return false; + } + } + return false; +} + +bool uint2048_less_equal(uint2048_t* a, uint2048_t* b) +{ + for (int i = N_UINT2048 - 1; i >= 0; i--) { + if (a->bucket[i] < b->bucket[i]) { + return true; + } + if (a->bucket[i] > b->bucket[i]) { + return false; + } + } + return true; +} + +bool uint2048_equal(uint2048_t* a, uint2048_t* b) +{ + for (int i = 0; i < N_UINT2048; i++) { + if (a->bucket[i] != b->bucket[i]) { + return false; + } + } + return true; +} + +bool uint2048_is_not_zero(uint2048_t* a) +{ + for (int i = 0; i < N_UINT2048; i++) { + if (a->bucket[i] != 0) { + return true; + } + } + return false; +} + +bool uint2048_is_odd(uint2048_t* a) +{ + return (a->bucket[0] % 2) == 1; +} + +int uint2048_dump(uint2048_t* a) +{ + log("dumping"); + for (int i = N_UINT2048 - 1; i >= 0; i--) { + log(" %x", a->bucket[i]); + } + return 0; +} diff --git a/boot/libboot/crypto/uint2048.h b/boot/libboot/crypto/uint2048.h new file mode 100644 index 0000000..3cad61a --- /dev/null +++ b/boot/libboot/crypto/uint2048.h @@ -0,0 +1,43 @@ +#ifndef _BOOT_LIBBOOT_CRYPTO_UINT2048_H +#define _BOOT_LIBBOOT_CRYPTO_UINT2048_H + +#include +#include + +#define N_UINT2048 (64) +#define BITS_IN_BASE_UINT2048 (32) +#define BASE_UINT2048 ((uint64_t)((uint64_t)1 << BITS_IN_BASE_UINT2048)) +#define BASE_UINT2048U ((uint64_t)((uint64_t)1 << (uint64_t)BITS_IN_BASE_UINT2048)) +typedef uint32_t uint2048_bucket_t; +struct uint2048 { + uint2048_bucket_t bucket[N_UINT2048]; +}; +typedef struct uint2048 uint2048_t; + +int uint2048_init(uint2048_t* d, uint32_t n); +int uint2048_init_bytes(uint2048_t* d, const char* f, size_t n); +int uint2048_init_bytes_be(uint2048_t* d, const char* f, size_t n); +int uint2048_copy(uint2048_t* dest, uint2048_t* src); + +int uint2048_add(uint2048_t* a, uint2048_t* b, uint2048_t* c); +int uint2048_sub(uint2048_t* a, uint2048_t* b, uint2048_t* c); + +int uint2048_shl(uint2048_t* a, int n); +int uint2048_shr(uint2048_t* a, int n); + +int uint2048_mult_by_digit(uint2048_t* a, uint2048_t* b, uint2048_bucket_t un); +int uint2048_mult(uint2048_t* a, uint2048_t* b, uint2048_t* c); + +int uint2048_div(uint2048_t* a, uint2048_t* b, uint2048_t* ans, uint2048_t* rem); +int uint2048_pow(uint2048_t* ua, uint2048_t* up, uint2048_t* mod, uint2048_t* ans); + +bool uint2048_equal(uint2048_t* a, uint2048_t* b); +bool uint2048_less(uint2048_t* a, uint2048_t* b); +bool uint2048_less_equal(uint2048_t* a, uint2048_t* b); + +bool uint2048_is_not_zero(uint2048_t* a); +bool uint2048_is_odd(uint2048_t* a); + +int uint2048_dump(uint2048_t* a); + +#endif // _BOOT_LIBBOOT_CRYPTO_UINT2048_H diff --git a/boot/libboot/crypto/validate.c b/boot/libboot/crypto/validate.c new file mode 100644 index 0000000..10b7e8d --- /dev/null +++ b/boot/libboot/crypto/validate.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include +#include + +#define tmp_buf_size (4096) +char tmp_buf[tmp_buf_size]; + +static int get_elf_signature(elfctx_t* elfctx, void* signature_buffer) +{ + elf_section_header_32_t shstrtab_section_header; + elf_read_section_header(elfctx, elfctx->header.e_shstrndx, &shstrtab_section_header); + uintptr_t shstrtab_offset = shstrtab_section_header.sh_offset; + + for (uint32_t i = 0; i < elfctx->header.e_shnum; i++) { + elf_section_header_32_t section_header; + elf_read_section_header(elfctx, i, §ion_header); + + char tmp_name_buffer[32]; + uintptr_t name_offset_abs = shstrtab_offset + section_header.sh_name; + elfctx->fs_desc->read_from_inode(elfctx->drive_desc, &elfctx->file_inode, (void*)tmp_name_buffer, name_offset_abs, 32); + size_t len = strnlen(tmp_name_buffer, 32); + if (len != sizeof("._signature") - 1) { + continue; + } + if (memcmp(tmp_name_buffer, "._signature", len)) { + continue; + } + + elfctx->fs_desc->read_from_inode(elfctx->drive_desc, &elfctx->file_inode, signature_buffer, section_header.sh_offset, 128); + return 0; + } + + return -1; +} + +static int calc_elf_hash(elfctx_t* elfctx, char* hash) +{ + sha256_ctx_t shactx; + sha256_init(&shactx); + + for (uint32_t i = 0; i < elfctx->header.e_phnum; i++) { + elf_program_header_32_t program_header; + elf_read_program_header(elfctx, i, &program_header); + + if (program_header.p_type != PT_LOAD) { + continue; + } + + size_t from = program_header.p_offset; + size_t rem_to_read = program_header.p_filesz; + + while (rem_to_read) { + size_t will_read = min(tmp_buf_size, rem_to_read); + int rd = elfctx->fs_desc->read_from_inode(elfctx->drive_desc, &elfctx->file_inode, (void*)tmp_buf, from, will_read); + from += will_read; + sha256_update(&shactx, tmp_buf, will_read); + + rem_to_read -= will_read; + } + } + + sha256_hash(&shactx, hash); + return 0; +} + +bool validate_elf(const char* path, drive_desc_t* drive_desc, fs_desc_t* fs_desc) +{ + elfctx_t elfctx; + char hash[32]; + + int err = elf_init_ctx(drive_desc, fs_desc, path, &elfctx); + if (err) { + return false; + } + + err = get_elf_signature(&elfctx, tmp_buf); + if (err) { + return false; + } + uint2048_t signature; + uint2048_init_bytes(&signature, tmp_buf, 128); + + err = calc_elf_hash(&elfctx, hash); + if (err) { + return false; + } + + uint2048_t ihash; + uint2048_init_bytes_be(&ihash, hash, 32); + + uint2048_t public_e; + uint2048_init_bytes(&public_e, pub_xos_key_e, pub_xos_key_e_len); + uint2048_t public_n; + uint2048_init_bytes(&public_n, pub_xos_key_n, pub_xos_key_n_len); + uint2048_t signed_ihash; + uint2048_pow(&signature, &public_e, &public_n, &signed_ihash); + + return uint2048_equal(&signed_ihash, &ihash); +} \ No newline at end of file diff --git a/boot/libboot/crypto/validate.h b/boot/libboot/crypto/validate.h new file mode 100644 index 0000000..5c75f5f --- /dev/null +++ b/boot/libboot/crypto/validate.h @@ -0,0 +1,11 @@ +#ifndef STAGE2_SECURITY_VALIDATE_H +#define STAGE2_SECURITY_VALIDATE_H + +#include +#include +#include + +bool validate_file(const char* path, const char* signature_path, drive_desc_t* drive_desc, fs_desc_t* fs_desc); +bool validate_elf(const char* path, drive_desc_t* drive_desc, fs_desc_t* fs_desc); + +#endif // STAGE2_SECURITY_VALIDATE_H \ No newline at end of file diff --git a/boot/libboot/devtree/devtree.c b/boot/libboot/devtree/devtree.c new file mode 100644 index 0000000..b2b7204 --- /dev/null +++ b/boot/libboot/devtree/devtree.c @@ -0,0 +1,52 @@ +#include "devtree.h" +#include +#include + +static size_t _devtree_size = 0; +static devtree_header_t* _devtree_header = NULL; +static devtree_entry_t* _devtree_body = NULL; +static char* _devtree_name_section = NULL; + +void* devtree_start() +{ + return (void*)_devtree_header; +} + +size_t devtree_size() +{ + return _devtree_size; +} + +int devtree_init(void* devtree, size_t size) +{ + if (!devtree) { + return 0; + } + + devtree_header_t* dth = (devtree_header_t*)devtree; + _devtree_header = dth; + _devtree_body = (devtree_entry_t*)&dth[1]; + _devtree_name_section = ((char*)dth + dth->name_list_offset); + _devtree_size = size; + return 0; +} + +const char* devtree_name_of_entry(devtree_entry_t* en) +{ + return &_devtree_name_section[en->rel_name_offset]; +} + +devtree_entry_t* devtree_find_device(const char* name) +{ + if (!_devtree_body) { + return NULL; + } + + for (int i = 0; i < _devtree_header->entries_count; i++) { + const char* curdev_name = devtree_name_of_entry(&_devtree_body[i]); + if (strcmp(curdev_name, name) == 0) { + return &_devtree_body[i]; + } + } + return NULL; +} diff --git a/boot/libboot/devtree/devtree.h b/boot/libboot/devtree/devtree.h new file mode 100644 index 0000000..7385d7d --- /dev/null +++ b/boot/libboot/devtree/devtree.h @@ -0,0 +1,50 @@ +#ifndef _BOOT_LIBBOOT_DEVTREE_DEVTREE_H +#define _BOOT_LIBBOOT_DEVTREE_DEVTREE_H + +#include +#include + +#define DEVTREE_HEADER_SIGNATURE ("odtr3") +#define DEVTREE_HEADER_SIGNATURE_LEN (sizeof(DEVTREE_HEADER_SIGNATURE) - 1) + +struct PACKED devtree_header { + char signature[8]; + uint32_t revision; + uint32_t flags; + uint32_t entries_count; + uint32_t name_list_offset; +}; +typedef struct devtree_header devtree_header_t; + +#define DEVTREE_ENTRY_FLAGS_MMIO = (1 << 0) +#define DEVTREE_ENTRY_TYPE_IO (0) +#define DEVTREE_ENTRY_TYPE_FB (1) +#define DEVTREE_ENTRY_TYPE_UART (2) +#define DEVTREE_ENTRY_TYPE_RAM (3) +#define DEVTREE_ENTRY_TYPE_STORAGE (4) +#define DEVTREE_ENTRY_TYPE_BUS_CONTROLLER (5) +#define DEVTREE_ENTRY_TYPE_RTC (6) + +struct PACKED devtree_entry { + uint32_t type; + uint32_t flags; + uint64_t region_base; + uint64_t region_size; + uint32_t irq_lane; + uint32_t irq_flags; + uint32_t irq_priority; + uint32_t rel_name_offset; + uint64_t aux1; + uint64_t aux2; + uint64_t aux3; + uint64_t aux4; +}; +typedef struct devtree_entry devtree_entry_t; + +int devtree_init(void* devtree, size_t size); +const char* devtree_name_of_entry(devtree_entry_t* en); +devtree_entry_t* devtree_find_device(const char* name); +void* devtree_start(); +size_t devtree_size(); + +#endif // _BOOT_LIBBOOT_DEVTREE_DEVTREE_H diff --git a/boot/libboot/elf/elf_lite.c b/boot/libboot/elf/elf_lite.c new file mode 100644 index 0000000..7ea853d --- /dev/null +++ b/boot/libboot/elf/elf_lite.c @@ -0,0 +1,144 @@ +#include "elf_lite.h" +#include +#include +#include +#include + +// #define DEBUG_ELF + +int elf_init_ctx(drive_desc_t* drive_desc, fs_desc_t* fs_desc, const char* path, elfctx_t* elfctx) +{ + elfctx->drive_desc = drive_desc; + elfctx->fs_desc = fs_desc; + fs_desc->get_inode(drive_desc, path, &elfctx->file_inode); + fs_desc->read_from_inode(drive_desc, &elfctx->file_inode, (void*)&elfctx->header, 0, sizeof(elfctx->header)); + + if (elfctx->header.e_ident[EI_MAG0] != 0x7F || elfctx->header.e_ident[EI_MAG1] != 0x45 || elfctx->header.e_ident[EI_MAG2] != 0x4c || elfctx->header.e_ident[EI_MAG3] != 0x46) { + return -1; + } + + return 0; +} + +int elf_read_program_header(elfctx_t* elfctx, size_t id, elf_program_header_32_t* program_header) +{ + uintptr_t offset = elfctx->header.e_phoff + id * elfctx->header.e_phentsize; + return elfctx->fs_desc->read_from_inode(elfctx->drive_desc, &elfctx->file_inode, (void*)program_header, offset, sizeof(*program_header)); +} + +int elf_read_section_header(elfctx_t* elfctx, uint32_t id, elf_section_header_32_t* section_header) +{ + uintptr_t offset = elfctx->header.e_shoff + id * elfctx->header.e_shentsize; + return elfctx->fs_desc->read_from_inode(elfctx->drive_desc, &elfctx->file_inode, (void*)section_header, offset, sizeof(*section_header)); +} + +#ifdef BITS32 +int elf_load_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc, const char* path, size_t* kernel_vaddr, size_t* kernel_paddr, size_t* kernel_size) +{ + elfctx_t elfctx; + int err = elf_init_ctx(drive_desc, fs_desc, path, &elfctx); + if (err) { + return err; + } + + size_t vaddr = -1; + size_t paddr = -1; + size_t vaddr_end = 0; + + for (uint32_t i = 0; i < elfctx.header.e_phnum; i++) { + elf_program_header_32_t program_header; + elf_read_program_header(&elfctx, i, &program_header); + + if (program_header.p_type == PT_LOAD) { + paddr = min(paddr, program_header.p_paddr); + vaddr = min(vaddr, program_header.p_vaddr); + fs_desc->read(drive_desc, path, (void*)program_header.p_paddr, program_header.p_offset, program_header.p_filesz); + } + } + + for (uint32_t i = 0; i < elfctx.header.e_shnum; i++) { + elf_section_header_32_t section_header; + elf_read_section_header(&elfctx, i, §ion_header); + + if ((section_header.sh_flags & SHF_ALLOC) == SHF_ALLOC) { + vaddr_end = max(vaddr_end, section_header.sh_addr + section_header.sh_size); + } + } + + *kernel_vaddr = vaddr; + *kernel_paddr = paddr; + *kernel_size = vaddr_end - vaddr; + return 0; +} +// #endif +#else +size_t elf_get_kernel_size(void* elffile) +{ + elf_header_64_t* header = (elf_header_64_t*)elffile; + if (header->e_ident[EI_MAG0] != 0x7F || header->e_ident[EI_MAG1] != 0x45 || header->e_ident[EI_MAG2] != 0x4c || header->e_ident[EI_MAG3] != 0x46) { + return -1; + } + + size_t vaddr = 0xffffffffffffffff; + size_t vaddr_end = 0; + + for (size_t i = 0; i < header->e_phnum; i++) { + uintptr_t offset = header->e_phoff + i * header->e_phentsize; + elf_program_header_64_t* program_header = (elf_program_header_64_t*)((uintptr_t)elffile + offset); + if (program_header->p_type == PT_LOAD) { + vaddr = min(vaddr, program_header->p_vaddr); + } + } + + for (size_t i = 0; i < header->e_shnum; i++) { + uintptr_t offset = header->e_shoff + i * header->e_shentsize; + elf_section_header_64_t* section_header = (elf_section_header_64_t*)((uintptr_t)elffile + offset); + + if ((section_header->sh_flags & SHF_ALLOC) == SHF_ALLOC) { + vaddr_end = max(vaddr_end, section_header->sh_addr + section_header->sh_size); + } + } + + return vaddr_end - vaddr; +} + +int elf_load_kernel(void* elffile, size_t size, uintptr_t* kernel_vaddr, uintptr_t* kernel_paddr) +{ + elf_header_64_t* header = (elf_header_64_t*)elffile; + if (header->e_ident[EI_MAG0] != 0x7F || header->e_ident[EI_MAG1] != 0x45 || header->e_ident[EI_MAG2] != 0x4c || header->e_ident[EI_MAG3] != 0x46) { + return -1; + } + + size_t vaddr = 0xffffffffffffffff; + for (size_t i = 0; i < header->e_phnum; i++) { + uintptr_t offset = header->e_phoff + i * header->e_phentsize; + elf_program_header_64_t* program_header = (elf_program_header_64_t*)((uintptr_t)elffile + offset); + if (program_header->p_type == PT_LOAD) { + vaddr = min(vaddr, program_header->p_vaddr); + } + } + + uintptr_t paddr = (uintptr_t)palloc(size); + if (!paddr) { + return -1; + } + + for (size_t i = 0; i < header->e_phnum; i++) { + uintptr_t offset = header->e_phoff + i * header->e_phentsize; + elf_program_header_64_t* program_header = (elf_program_header_64_t*)((uintptr_t)elffile + offset); + if (program_header->p_type == PT_LOAD) { + uintptr_t data_paddr = (program_header->p_vaddr - vaddr) + paddr; + uintptr_t data_offset = (uintptr_t)elffile + program_header->p_offset; + +#ifdef DEBUG_ELF + log("copying elf %lx %lx %lx", data_paddr, data_offset, program_header->p_filesz); +#endif + memcpy((void*)data_paddr, (void*)data_offset, program_header->p_filesz); + } + } + + *kernel_vaddr = vaddr; + *kernel_paddr = paddr; + return 0; +} +#endif \ No newline at end of file diff --git a/boot/libboot/elf/elf_lite.h b/boot/libboot/elf/elf_lite.h new file mode 100644 index 0000000..8f1c2cf --- /dev/null +++ b/boot/libboot/elf/elf_lite.h @@ -0,0 +1,196 @@ +#ifndef _BOOT_LIBBOOT_ELF_ELF_LITE +#define _BOOT_LIBBOOT_ELF_ELF_LITE + +#include +#include +#include + +enum E_IDENT_FIELDS { + EI_MAG0, + EI_MAG1, + EI_MAG2, + EI_MAG3, + EI_CLASS, + EI_DATA, + EI_VERSION, + EI_OSABI, + EI_ABIVERSION, +}; + +enum E_TYPE_FIELDS { + ET_NONE, + ET_REL, + ET_EXEC, + ET_DYN, + ET_CORE, +}; + +enum E_MACHINE_FIELDS { + EM_NONE, + EM_386 = 3, + EM_PPC = 20, + EM_PPC64 = 21, + EM_X86_64 = 62, +}; + +typedef struct { + uint8_t e_ident[16]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +} elf_header_32_t; + +typedef struct { + uint8_t e_ident[16]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint64_t e_entry; + uint64_t e_phoff; + uint64_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +} elf_header_64_t; + +enum P_TYPE_FIELDS { + PT_NULL, + PT_LOAD, + PT_DYNAMIC, + PT_INTERP, + PT_NOTE, + PT_SHLIB, + PT_PHDR, + PT_TLS, + PT_LOOS = 0x60000000, + PT_HIOS = 0x6FFFFFFF, + PT_LOPROC = 0x70000000, + PT_HIPROC = 0x7FFFFFFF, +}; + +typedef struct { + uint32_t p_type; + uint32_t p_offset; + uint32_t p_vaddr; + uint32_t p_paddr; + uint32_t p_filesz; + uint16_t p_memsz; + uint16_t p_flags; + uint16_t p_align; +} elf_program_header_32_t; + +typedef struct { + uint32_t p_type; + uint32_t p_flags; + uint64_t p_offset; + uint64_t p_vaddr; + uint64_t p_paddr; + uint64_t p_filesz; + uint64_t p_memsz; + uint64_t p_align; +} elf_program_header_64_t; + +enum SH_TYPE_FIELDS { + SHT_NULL, + SHT_PROGBITS, + SHT_SYMTAB, + SHT_STRTAB, + SHT_RELA, + SHT_HASH, + SHT_DYNAMIC, + SHT_NOTE, + SHT_NOBITS, + SHT_REL, + SHT_SHLIB, + SHT_DYNSYM, + SHT_INIT_ARRAY, + SHT_FINI_ARRAY, + SHT_PREINIT_ARRAY, + SHT_GROUP, + SHT_SYMTAB_SHNDX, + + SHT_LOOS = 1610612736, + SHT_HIOS = 1879048191, + SHT_LOPROC = 1879048192, + SHT_HIPROC = 2147483647, + SHT_LOUSER = 2147483648, + SHT_HIUSER = 4294967295, +}; + +enum SH_FLAGS_FIELDS { + SHF_WRITE = 0x1, + SHF_ALLOC = 0x2, + SHF_EXECINSTR = 0x4, + SHF_MERGE = 0x10, + SHF_STRINGS = 0x20, + + SHF_INFO_LINK = 0x40, + SHF_LINK_ORDER = 0x80, + SHF_OS_NONCONFORMING = 0x100, + SHF_GROUP = 0x200, + SHF_TLS = 0x400, + SHF_COMPRESSED = 0x800, + SHF_MASKOS = 0x0ff00000, + SHF_MASKPROC = 0xf0000000 +}; + +typedef struct { + uint32_t sh_name; + uint32_t sh_type; + uint32_t sh_flags; + uint32_t sh_addr; + uint32_t sh_offset; + uint32_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint32_t sh_addralign; + uint32_t sh_entsize; +} elf_section_header_32_t; + +typedef struct { + uint32_t sh_name; + uint32_t sh_type; + uint64_t sh_flags; + uint64_t sh_addr; + uint64_t sh_offset; + uint64_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint64_t sh_addralign; + uint64_t sh_entsize; +} elf_section_header_64_t; + +struct elfctx { + drive_desc_t* drive_desc; + fs_desc_t* fs_desc; + inode_t file_inode; + elf_header_32_t header; +}; +typedef struct elfctx elfctx_t; + +int elf_init_ctx(drive_desc_t* drive_desc, fs_desc_t* fs_desc, const char* path, elfctx_t* elfctx); +int elf_read_program_header(elfctx_t* elfctx, size_t id, elf_program_header_32_t* program_header); +int elf_read_section_header(elfctx_t* elfctx, uint32_t id, elf_section_header_32_t* section_header); + +#ifdef BITS32 +int elf_load_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc, const char* path, size_t* kernel_vaddr, size_t* kernel_paddr, size_t* kernel_size); +#else +size_t elf_get_kernel_size(void* elffile); +int elf_load_kernel(void* elffile, size_t size, uintptr_t* kernel_vaddr, uintptr_t* kernel_paddr); +#endif + +#endif // _BOOT_LIBBOOT_ELF_ELF_LITE \ No newline at end of file diff --git a/boot/libboot/fs/ext2_lite.c b/boot/libboot/fs/ext2_lite.c new file mode 100644 index 0000000..308e948 --- /dev/null +++ b/boot/libboot/fs/ext2_lite.c @@ -0,0 +1,233 @@ +#include +#include +#include + +superblock_t superblock; +drive_desc_t* active_drive_desc; + +uint32_t _ext2_lite_get_block_len() +{ + return (1 << (superblock.log_block_size + 10)); +} + +uint32_t _ext2_lite_get_offset_of_block(uint32_t block_index) +{ + return SUPERBLOCK_START + (block_index - 1) * _ext2_lite_get_block_len(); +} + +static uint8_t tmp_read_buf[8192]; +void _ext2_lite_read(uint8_t* buf, uint32_t start, uint32_t len) +{ + void (*read)(uint32_t sector, uint8_t* read_to) = active_drive_desc->read; + int already_read = 0; + while (len != 0) { + uint32_t sector = start / 512; + uint32_t start_offset = start % 512; + read(sector, tmp_read_buf); + for (int i = 0; i < min(512 - start_offset, len); i++) { + buf[already_read++] = tmp_read_buf[start_offset + i]; + } + len -= min(512 - start_offset, len); + start += min(512 - start_offset, len); + } +} + +void _ext2_lite_read_group(uint32_t group_id, group_desc_t* group) +{ + uint32_t group_start = SUPERBLOCK_START + _ext2_lite_get_block_len() + (group_id * GROUP_LEN); + _ext2_lite_read((uint8_t*)group, group_start, GROUP_LEN); +} + +void _ext2_lite_read_inode(uint32_t inode_id, inode_t* inode) +{ + uint32_t inodes_per_group = superblock.inodes_per_group; + uint32_t holder_group = (inode_id - 1) / inodes_per_group; + uint32_t pos_inside_group = (inode_id - 1) % inodes_per_group; + + group_desc_t gr; + _ext2_lite_read_group(holder_group, &gr); + + uint32_t inode_start = SUPERBLOCK_START + ((gr.inode_table - 1) * _ext2_lite_get_block_len()) + (pos_inside_group * INODE_LEN); + _ext2_lite_read((uint8_t*)inode, inode_start, INODE_LEN); +} + +int ext2_lite_init(drive_desc_t* drive_desc, fs_desc_t* fs_desc) +{ + active_drive_desc = drive_desc; + void (*read)(uint32_t sector, uint8_t* read_to) = drive_desc->read; + _ext2_lite_read((uint8_t*)&superblock, SUPERBLOCK_START, SUPERBLOCK_LEN); + + if (superblock.magic != 0xEF53) { + return -1; + } + if (superblock.rev_level != 0) { + return -1; + } + + // TODO currently support up to 8192 bytes a block. + if (superblock.log_block_size > 3) { + return -1; + } + + fs_desc->get_inode = (void*)ext2_lite_get_inode; + fs_desc->read = ext2_lite_read; + fs_desc->read_from_inode = (void*)ext2_lite_read_inode; + return 0; +} + +static uint8_t tmp_dir_buf[8192]; +int ext2_lite_has_in_dir(uint32_t block_index, const char* path, uint32_t* found_inode_index) +{ + if (block_index == 0) { + return -1; + } + if (_ext2_lite_get_block_len() != 1024) { + while (1) { } + return -1; + } + + _ext2_lite_read(tmp_dir_buf, _ext2_lite_get_offset_of_block(block_index), _ext2_lite_get_block_len()); + dir_entry_t* start_of_entry = (dir_entry_t*)tmp_dir_buf; + for (;;) { + if (start_of_entry->inode == 0) { + return -1; + } + // checking name of this entry + bool is_name_correct = true; + for (int i = 0; i < start_of_entry->name_len; i++) { + is_name_correct &= (path[i] == *((char*)start_of_entry + 8 + i)); + } + is_name_correct &= (path[start_of_entry->name_len] == '\0' || path[start_of_entry->name_len] == '/'); + + if (is_name_correct) { + *found_inode_index = start_of_entry->inode; + return 0; + } + + start_of_entry = (dir_entry_t*)((uint32_t)start_of_entry + start_of_entry->rec_len); + if ((uint32_t)start_of_entry >= (uint32_t)tmp_dir_buf + _ext2_lite_get_block_len()) { + return -1; + } + } + return -2; +} + +int ext2_lite_scan_dir(inode_t inode, const char* path, inode_t* res_inode) +{ + uint32_t nxt_inode_index; + uint32_t path_offset = 0; +new_inode: + for (int i = 0; i < 12; i++) { + if (inode.block[i] != 0) { + if (ext2_lite_has_in_dir(inode.block[i], &path[path_offset], &nxt_inode_index) == 0) { + while (path[path_offset] != '\0' && path[path_offset] != '/') + path_offset++; + for (; path[path_offset] != '/'; path_offset++) { + if (path[path_offset] == '\0') { + _ext2_lite_read_inode(nxt_inode_index, res_inode); + return 0; + } + } + path_offset++; + _ext2_lite_read_inode(nxt_inode_index, &inode); + goto new_inode; + } + } + } + return -1; +} + +int ext2_lite_get_inode(drive_desc_t* drive_desc, const char* path, inode_t* file_inode) +{ + active_drive_desc = drive_desc; + inode_t root_inode; + _ext2_lite_read_inode(2, &root_inode); + + int res = -1; + if (path[0] == '/') { + res = ext2_lite_scan_dir(root_inode, &path[1], file_inode); + } else { + res = ext2_lite_scan_dir(root_inode, path, file_inode); + } + + return res; +} + +static uint8_t tmp_block_buf[8192]; +uint32_t _ext2_lite_get_block_of_file_lev0(uint32_t cur_block, uint32_t file_block_index) +{ + _ext2_lite_read(tmp_block_buf, _ext2_lite_get_offset_of_block(cur_block), _ext2_lite_get_block_len()); + uint32_t* buf = (uint32_t*)tmp_block_buf; + return buf[file_block_index]; +} + +uint32_t _ext2_lite_get_block_of_file_lev1(uint32_t cur_block, uint32_t file_block_index) +{ + _ext2_lite_read(tmp_block_buf, _ext2_lite_get_offset_of_block(cur_block), _ext2_lite_get_block_len()); + uint32_t* buf = (uint32_t*)tmp_block_buf; + + uint32_t lev_contain = _ext2_lite_get_block_len() / 4; + uint32_t offset = file_block_index / lev_contain; + uint32_t offset_inner = file_block_index % lev_contain; + + return _ext2_lite_get_block_of_file_lev0(buf[offset], offset_inner); +} + +uint32_t _ext2_lite_get_block_of_file_lev2(uint32_t cur_block, uint32_t file_block_index) +{ + _ext2_lite_read(tmp_block_buf, _ext2_lite_get_offset_of_block(cur_block), _ext2_lite_get_block_len()); + uint32_t* buf = (uint32_t*)tmp_block_buf; + + uint32_t block_len = _ext2_lite_get_block_len() / 4; + uint32_t lev_contain = block_len * block_len; + uint32_t offset = file_block_index / lev_contain; + uint32_t offset_inner = file_block_index % lev_contain; + + return _ext2_lite_get_block_of_file_lev1(buf[offset], offset_inner); +} + +// TODO think of more effecient version +uint32_t _ext2_lite_get_block_of_file(inode_t* inode, uint32_t file_block_index) +{ + uint32_t block_len = _ext2_lite_get_block_len() / 4; + if (file_block_index < 12) { + return inode->block[file_block_index]; + } else if (file_block_index < 12 + block_len) { // single indirect + return _ext2_lite_get_block_of_file_lev0(inode->block[12], file_block_index - 12); + } else if (file_block_index < 12 + block_len + block_len * block_len) { // double indirect + return _ext2_lite_get_block_of_file_lev1(inode->block[13], file_block_index - 12 - block_len); + } else { // triple indirect + return _ext2_lite_get_block_of_file_lev2(inode->block[14], file_block_index - (12 + block_len + block_len * block_len)); + } +} + +// Note to save mem: the func reuses tmp_block_buf. +int ext2_lite_read_inode(drive_desc_t* drive_desc, inode_t* inode, uint8_t* buf, uint32_t from, uint32_t len) +{ + active_drive_desc = drive_desc; + + const uint32_t block_len = _ext2_lite_get_block_len(); + uint32_t start_block_index = from / block_len; + uint32_t end_block_index = (from + len - 1) / block_len; + uint32_t read_offset = from % block_len; + uint32_t write_offset = 0; + + for (uint32_t block_index = start_block_index; block_index <= end_block_index; block_index++) { + uint32_t data_block_index = _ext2_lite_get_block_of_file(inode, block_index); + _ext2_lite_read(tmp_block_buf, _ext2_lite_get_offset_of_block(data_block_index), _ext2_lite_get_block_len()); + for (int i = 0; i < min(len, block_len - read_offset); i++) { + buf[write_offset++] = tmp_block_buf[read_offset + i]; + } + len -= min(len, block_len - read_offset); + read_offset = 0; + } + return write_offset; +} + +int ext2_lite_read(drive_desc_t* drive_desc, const char* path, uint8_t* buf, uint32_t from, uint32_t len) +{ + active_drive_desc = drive_desc; + inode_t inode; + ext2_lite_get_inode(drive_desc, path, &inode); + return ext2_lite_read_inode(drive_desc, &inode, buf, from, len); +} \ No newline at end of file diff --git a/boot/libboot/fs/ext2_lite.h b/boot/libboot/fs/ext2_lite.h new file mode 100644 index 0000000..efc2c06 --- /dev/null +++ b/boot/libboot/fs/ext2_lite.h @@ -0,0 +1,124 @@ +#ifndef _BOOT_LIBBOOT_FS_EXT2_LITE +#define _BOOT_LIBBOOT_FS_EXT2_LITE + +#include +#include + +#define SUPERBLOCK_START 1024 +#define SUPERBLOCK_LEN (sizeof(superblock_t)) +typedef struct { + uint32_t inodes_count; + uint32_t blocks_count; + uint32_t r_blocks_count; + uint32_t free_blocks_count; + uint32_t free_inodes_count; + uint32_t first_data_block; + uint32_t log_block_size; + uint32_t log_frag_size; + uint32_t blocks_per_group; + uint32_t frags_per_group; + uint32_t inodes_per_group; + uint32_t mtime; + uint32_t wtime; + uint16_t mnt_count; + uint16_t max_mnt_count; + uint16_t magic; + uint16_t state; + uint16_t errors; + uint16_t minor_rev_level; + uint32_t lastcheck; + uint32_t checkinterval; + uint32_t creator_os; + uint32_t rev_level; + uint16_t def_resuid; + uint16_t def_resgid; + + uint32_t first_ino; + uint16_t inode_size; + uint16_t block_group_nr; + uint32_t feature_compat; + uint32_t feature_incompat; + uint32_t feature_ro_compat; + uint8_t uuid[16]; + uint8_t volume_name[16]; + uint8_t last_mounted[64]; + uint32_t algo_bitmap; + + uint8_t prealloc_blocks; + uint8_t prealloc_dir_blocks; + + // current jurnalling is unsupported + uint8_t unused[1024 - 206]; +} superblock_t; + +#define GROUP_LEN (sizeof(group_desc_t)) +typedef struct { + uint32_t block_bitmap; + uint32_t inode_bitmap; + uint32_t inode_table; + uint16_t free_blocks_count; + uint16_t free_inodes_count; + uint16_t used_dirs_count; + uint16_t pad; + uint8_t reserved[12]; +} group_desc_t; + +#define S_IFSOCK 0xC000 +#define S_IFLNK 0xA000 +#define S_IFREG 0x8000 +#define S_IFBLK 0x6000 +#define S_IFDIR 0x4000 +#define S_IFCHR 0x2000 +#define S_IFIFO 0x1000 + +#define S_ISUID 0x0800 +#define S_ISGID 0x0400 +#define S_ISVTX 0x0200 + +#define S_IRUSR 0x0100 +#define S_IWUSR 0x0080 +#define S_IXUSR 0x0040 +#define S_IRGRP 0x0020 +#define S_IWGRP 0x0010 +#define S_IXGRP 0x0008 +#define S_IROTH 0x0004 +#define S_IWOTH 0x0002 +#define S_IXOTH 0x0001 + +#define INODE_LEN (sizeof(inode_t)) +#define INODES_RESERVED 11 +typedef struct { + uint16_t mode; + uint16_t uid; + uint32_t size; + uint32_t atime; + uint32_t ctime; + uint32_t mtime; + uint32_t dtime; + uint16_t gid; + uint16_t links_count; + uint32_t blocks; + uint32_t flags; + uint32_t osd1; + uint32_t block[15]; + uint32_t generation; + uint32_t file_acl; + uint32_t dir_acl; + uint32_t faddr; + uint32_t osd2[3]; +} inode_t; + +typedef struct { + uint32_t inode; + uint16_t rec_len; + uint8_t name_len; + uint8_t file_type; + char* name; // may be a problematic for 64bit versions +} dir_entry_t; + +int ext2_lite_init(drive_desc_t* drive_desc, fs_desc_t* fs_desc); +int ext2_lite_get_inode(drive_desc_t* drive_desc, const char* path, inode_t* file_inode); +int ext2_lite_read(drive_desc_t* drive_desc, const char* path, uint8_t* buf, uint32_t from, uint32_t len); +int ext2_lite_read_inode(drive_desc_t* drive_desc, inode_t* inode, uint8_t* buf, uint32_t from, uint32_t len); + +#endif // _BOOT_LIBBOOT_FS_EXT2_LITE \ No newline at end of file diff --git a/boot/libboot/log/log.c b/boot/libboot/log/log.c new file mode 100644 index 0000000..d051d05 --- /dev/null +++ b/boot/libboot/log/log.c @@ -0,0 +1,377 @@ +#include +#include + +typedef int (*_putch_callback)(char ch, char* buf_base, size_t* written, void* callback_params); + +static uart_put_char_t uart_handler = NULL; +static const char HEX_alphabet[] = "0123456789ABCDEF"; +static const char hex_alphabet[] = "0123456789abcdef"; + +static int putch_callback_stream(char c, char* buf_base, size_t* written, void* callback_params) +{ + if (uart_handler) { + return uart_handler(c); + } + return 0; +} + +static int _printf_hex32_impl(unsigned int value, const char* alph, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) +{ + int nxt = 0; + char tmp_buf[16]; + + while (value > 0) { + tmp_buf[nxt++] = alph[(value % 16)]; + value /= 16; + } + + callback('0', base_buf, written, callback_params); + callback('x', base_buf, written, callback_params); + if (nxt == 0) { + callback('0', base_buf, written, callback_params); + } + + while (nxt) { + callback(tmp_buf[--nxt], base_buf, written, callback_params); + } + return 0; +} + +static int _printf_hex64_impl(unsigned long value, const char* alph, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) +{ + int nxt = 0; + char tmp_buf[32]; + + while (value > 0) { + tmp_buf[nxt++] = alph[(value % 16)]; + value /= 16; + } + + callback('0', base_buf, written, callback_params); + callback('x', base_buf, written, callback_params); + if (nxt == 0) { + callback('0', base_buf, written, callback_params); + } + + while (nxt) { + callback(tmp_buf[--nxt], base_buf, written, callback_params); + } + return 0; +} + +static int _printf_hex32(unsigned int value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) +{ + return _printf_hex32_impl(value, hex_alphabet, base_buf, written, callback, callback_params); +} + +static int _printf_HEX32(unsigned int value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) +{ + return _printf_hex32_impl(value, HEX_alphabet, base_buf, written, callback, callback_params); +} + +static int _printf_hex64(unsigned long value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) +{ + return _printf_hex64_impl(value, hex_alphabet, base_buf, written, callback, callback_params); +} + +static int _printf_HEX64(unsigned long value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) +{ + return _printf_hex64_impl(value, HEX_alphabet, base_buf, written, callback, callback_params); +} + +static int _printf_u32(unsigned int value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) +{ + int nxt = 0; + char tmp_buf[16]; + + while (value > 0) { + tmp_buf[nxt++] = (value % 10) + '0'; + value /= 10; + } + + if (nxt == 0) { + callback('0', base_buf, written, callback_params); + } + + while (nxt) { + callback(tmp_buf[--nxt], base_buf, written, callback_params); + } + return 0; +} + +static int _printf_u64(unsigned long value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) +{ + int nxt = 0; + char tmp_buf[32]; + + while (value > 0) { + tmp_buf[nxt++] = (value % 10) + '0'; + value /= 10; + } + + if (nxt == 0) { + callback('0', base_buf, written, callback_params); + } + + while (nxt) { + callback(tmp_buf[--nxt], base_buf, written, callback_params); + } + return 0; +} + +static int _printf_i32(int value, char* buf, size_t* written, _putch_callback callback, void* callback_params) +{ + if (value < 0) { + callback('-', buf, written, callback_params); + value = -value; + } + return _printf_u32(value, buf, written, callback, callback_params); +} + +static int _printf_i64(long value, char* buf, size_t* written, _putch_callback callback, void* callback_params) +{ + if (value < 0) { + callback('-', buf, written, callback_params); + value = -value; + } + return _printf_u64(value, buf, written, callback, callback_params); +} + +static int _printf_string(const char* value, char* buf, size_t* written, _putch_callback callback, void* callback_params) +{ + if (!value) { + return 0; + } + + size_t len = strlen(value); + for (size_t i = 0; i < len; i++) { + callback(value[i], buf, written, callback_params); + } + return 0; +} + +static ssize_t _printf_internal(char* buf, const char* format, _putch_callback callback, void* callback_params, va_list arg) +{ + const char* p = format; + size_t written = 0; + while (*p) { + int l_arg = 0; + int h_arg = 0; + if (*p == '%' && *(p + 1)) { + // Reading arguments + parse_args: + p++; + switch (*p) { + case 'l': + l_arg++; + if (*(p + 1)) { + goto parse_args; + } + break; + case 'h': + h_arg++; + if (*(p + 1)) { + goto parse_args; + } + break; + default: + break; + } + + // Reading conversion specifiers + switch (*p) { + case 'i': + case 'd': + if (l_arg) { + long value = va_arg(arg, long); + _printf_i64(value, buf, &written, callback, callback_params); + } else { + int value = va_arg(arg, int); + _printf_i32(value, buf, &written, callback, callback_params); + } + break; + case 'u': + if (l_arg) { + uint64_t value = va_arg(arg, uint64_t); + _printf_u64(value, buf, &written, callback, callback_params); + } else { + uint32_t value = va_arg(arg, uint32_t); + _printf_u32(value, buf, &written, callback, callback_params); + } + break; + case 'x': + if (l_arg) { + uint64_t value = va_arg(arg, uint64_t); + _printf_hex64(value, buf, &written, callback, callback_params); + } else { + uint32_t value = va_arg(arg, uint32_t); + _printf_hex32(value, buf, &written, callback, callback_params); + } + break; + case 'X': + if (l_arg) { + uint64_t value = va_arg(arg, uint64_t); + _printf_HEX64(value, buf, &written, callback, callback_params); + } else { + uint32_t value = va_arg(arg, uint32_t); + _printf_HEX32(value, buf, &written, callback, callback_params); + } + break; + case 'c': { + char value = (char)va_arg(arg, int); + callback(value, buf, &written, callback_params); + } break; + case '%': { + callback('%', buf, &written, callback_params); + } break; + case 's': { + const char* value = va_arg(arg, const char*); + _printf_string(value, buf, &written, callback, callback_params); + } break; + default: + break; + } + } else { + callback(*p, buf, &written, callback_params); + } + p++; + } + return written; +} + +static int putch_callback_sized_buf(char ch, char* buf_base, size_t* written, void* callback_params) +{ + if (!callback_params) { + return -1; + } + + if (!written) { + return -1; + } + + size_t n = *(size_t*)callback_params; + size_t vw = *written; + if (vw >= n) { + return -1; + } + buf_base[vw++] = ch; + *written = vw; + return 0; +} + +int vsnprintf(char* s, size_t n, const char* format, va_list arg) +{ + if (!s) { + return 0; + } + + if (!n) { + return 0; + } + + ssize_t wr = _printf_internal(s, format, putch_callback_sized_buf, &n, arg); + if (wr == n) { + s[n - 1] = '\0'; + } else { + s[wr] = '\0'; + } + return (int)wr; +} + +int snprintf(char* s, size_t n, const char* format, ...) +{ + va_list arg; + va_start(arg, format); + int res = vsnprintf(s, n, format, arg); + va_end(arg); + return res; +} + +static int putch_callback_buf(char ch, char* buf_base, size_t* written, void* callback_params) +{ + if (!written) { + return -1; + } + + size_t vw = *written; + buf_base[vw++] = ch; + *written = vw; + return 0; +} + +int vsprintf(char* s, const char* format, va_list arg) +{ + if (!s) { + return 0; + } + ssize_t wr = _printf_internal(s, format, putch_callback_buf, NULL, arg); + s[wr] = '\0'; + return (int)wr; +} + +int sprintf(char* s, const char* format, ...) +{ + va_list arg; + va_start(arg, format); + int res = vsprintf(s, format, arg); + va_end(arg); + return res; +} + +static int vlog_unfmt(const char* format, va_list arg) +{ + return _printf_internal(NULL, format, putch_callback_stream, NULL, arg); +} + +static int vlog_fmt(const char* init_msg, const char* format, va_list arg) +{ + vlog_unfmt(init_msg, arg); + vlog_unfmt(format, arg); + + size_t formatlen = strlen(format); + if (format[formatlen - 1] != '\n') { + vlog_unfmt("\n", arg); + } + return 0; +} + +int log(const char* format, ...) +{ + va_list arg; + va_start(arg, format); + int ret = vlog_fmt("\033[1;37m[BOOT LOG]\033[0m ", format, arg); + va_end(arg); + return ret; +} + +int log_warn(const char* format, ...) +{ + va_list arg; + va_start(arg, format); + int ret = vlog_fmt("\033[1;33m[BOOT WARN]\033[0m ", format, arg); + va_end(arg); + return ret; +} + +int log_error(const char* format, ...) +{ + va_list arg; + va_start(arg, format); + int ret = vlog_fmt("\033[1;31m[BOOT ERR]\033[0m ", format, arg); + va_end(arg); + return ret; +} + +int log_not_formatted(const char* format, ...) +{ + va_list arg; + va_start(arg, format); + int ret = vlog_unfmt(format, arg); + va_end(arg); + return ret; +} + +void log_init(uart_put_char_t ur) +{ + uart_handler = ur; +} \ No newline at end of file diff --git a/boot/libboot/log/log.h b/boot/libboot/log/log.h new file mode 100644 index 0000000..34e4b92 --- /dev/null +++ b/boot/libboot/log/log.h @@ -0,0 +1,20 @@ +#ifndef _BOOT_LIBBOOT_LOG_LOG_H +#define _BOOT_LIBBOOT_LOG_LOG_H + +#include + +typedef int (*uart_put_char_t)(uint8_t ch); + +void log_init(uart_put_char_t ur); + +int vsnprintf(char* s, size_t n, const char* format, va_list arg); +int vsprintf(char* s, const char* format, va_list arg); +int snprintf(char* s, size_t n, const char* format, ...); +int sprintf(char* s, const char* format, ...); + +int log(const char* format, ...); +int log_warn(const char* format, ...); +int log_error(const char* format, ...); +int log_not_formatted(const char* format, ...); + +#endif // _BOOT_LIBBOOT_LOG_LOG_H \ No newline at end of file diff --git a/boot/libboot/mem/alloc.c b/boot/libboot/mem/alloc.c new file mode 100644 index 0000000..d33063f --- /dev/null +++ b/boot/libboot/mem/alloc.c @@ -0,0 +1,96 @@ +#include +#include + +void* _malloc_next_addr = NULL; +void* _malloc_end_addr = NULL; + +void* _palloc_start_addr = NULL; +void* _palloc_next_addr = NULL; +void* _palloc_end_addr = NULL; + +int malloc_init(void* addr, size_t size) +{ + _malloc_next_addr = addr; + _malloc_end_addr = _malloc_next_addr + size; + return 0; +} + +// Current implementation is a simple linear allocator. +void* malloc(size_t size) +{ + if (!_malloc_next_addr) { + return NULL; + } + if (_malloc_next_addr >= _malloc_end_addr) { + return NULL; + } + + void* res = _malloc_next_addr; + + size = ROUND_CEIL(size, 0x10); + _malloc_next_addr += size; + return res; +} + +// Current implementation is a simple linear allocator. +void* malloc_aligned(size_t size, size_t alignment) +{ + if ((size_t)_malloc_next_addr % alignment) { + malloc(alignment - ((size_t)_malloc_next_addr % alignment)); + } + return malloc(size); +} + +void free(void* ptr) +{ + UNUSED(ptr); +} + +// Preserve alloc + +int palloc_init(size_t size, size_t alignment) +{ + _palloc_start_addr = _palloc_next_addr = malloc_aligned(size, alignment); + if (!_palloc_next_addr) { + return -1; + } + + _palloc_end_addr = (void*)((uintptr_t)_palloc_next_addr + size); + return 0; +} + +void* palloc(size_t size) +{ + if (!_palloc_next_addr) { + log("palloc not init"); + while (1) { }; + } + if (_palloc_next_addr >= _palloc_end_addr) { + log("palloc out of mem"); + while (1) { }; + } + + void* res = _palloc_next_addr; + + size = ROUND_CEIL(size, 0x10); + _palloc_next_addr += size; + return res; +} + +void* palloc_aligned(size_t size, size_t alignment) +{ + if ((size_t)_palloc_next_addr % alignment) { + palloc(alignment - ((size_t)_palloc_next_addr % alignment)); + } + return palloc(size); +} + +size_t palloc_total_size() +{ + return (size_t)_palloc_end_addr - (size_t)_palloc_start_addr; +} + +size_t palloc_used_size() +{ + return (size_t)_palloc_next_addr - (size_t)_palloc_start_addr; +} diff --git a/boot/libboot/mem/alloc.h b/boot/libboot/mem/alloc.h new file mode 100644 index 0000000..36808ad --- /dev/null +++ b/boot/libboot/mem/alloc.h @@ -0,0 +1,17 @@ +#ifndef _BOOT_LIBBOOT_MEM_MALLOC_H +#define _BOOT_LIBBOOT_MEM_MALLOC_H + +#include + +int malloc_init(void* addr, size_t size); +void* malloc(size_t size); +void* malloc_aligned(size_t size, size_t alignment); +void free(void* ptr); + +int palloc_init(size_t size, size_t alignment); +void* palloc(size_t size); +void* palloc_aligned(size_t size, size_t alignment); +size_t palloc_used_size(); +size_t palloc_total_size(); + +#endif // _BOOT_LIBBOOT_MEM_MALLOC_H \ No newline at end of file diff --git a/boot/libboot/mem/mem.c b/boot/libboot/mem/mem.c new file mode 100644 index 0000000..5833503 --- /dev/null +++ b/boot/libboot/mem/mem.c @@ -0,0 +1,110 @@ +#include + +int strcmp(const char* a, const char* b) +{ + while (*a == *b && *a != 0 && *b != 0) { + a++; + b++; + } + + if (*a < *b) { + return -1; + } + if (*a > *b) { + return 1; + } + return 0; +} + +int strncmp(const char* a, const char* b, uint32_t num) +{ + while (*a == *b && *a != 0 && *b != 0 && num) { + a++; + b++; + num--; + } + + if (!num) { + return 0; + } + + if (*a < *b) { + return -1; + } + if (*a > *b) { + return 1; + } + return 0; +} + +size_t strlen(const char* s) +{ + size_t i = 0; + while (s[i] != '\0') + ++i; + return i; +} + +size_t strnlen(const char* s, size_t maxlen) +{ + size_t i = 0; + while (s[i] != '\0' && maxlen) { + i++; + maxlen--; + } + return i; +} + +void* memset(void* dest, uint8_t fll, uint32_t nbytes) +{ + for (int i = 0; i < nbytes; ++i) { + *((uint8_t*)dest + i) = fll; + } + return dest; +} + +void* memcpy(void* dest, const void* src, uint32_t nbytes) +{ + for (int i = 0; i < nbytes; ++i) { + *(char*)(dest + i) = *(char*)(src + i); + } + return dest; +} + +void* memmove(void* dest, const void* src, uint32_t nbytes) +{ + if (src > dest) { + for (int i = 0; i < nbytes; ++i) { + *((uint8_t*)dest + i) = *((uint8_t*)src + i); + } + } else { + for (int i = nbytes - 1; i >= 0; --i) { + *((uint8_t*)dest + i) = *((uint8_t*)src + i); + } + } + return dest; +} + +void* memccpy(void* dest, const void* src, uint8_t stop, uint32_t nbytes) +{ + for (int i = 0; i < nbytes; ++i) { + *((uint8_t*)dest + i) = *((uint8_t*)src + i); + if (*((uint8_t*)src + i) == stop) { + return ((uint8_t*)dest + i + 1); + } + } + return NULL; +} + +int memcmp(const void* src1, const void* src2, uint32_t nbytes) +{ + for (int i = 0; i < nbytes; ++i) { + if (*(uint8_t*)(src1 + i) < *((uint8_t*)src2 + i)) { + return -1; + } + if (*(uint8_t*)(src1 + i) > *(uint8_t*)(src2 + i)) { + return 1; + } + } + return 0; +} \ No newline at end of file diff --git a/boot/libboot/mem/mem.h b/boot/libboot/mem/mem.h new file mode 100644 index 0000000..91cac11 --- /dev/null +++ b/boot/libboot/mem/mem.h @@ -0,0 +1,37 @@ +#ifndef _BOOT_LIBBOOT_MEM_MEM_H +#define _BOOT_LIBBOOT_MEM_MEM_H + +#include + +int strcmp(const char* a, const char* b); +int strncmp(const char* a, const char* b, uint32_t num); +size_t strlen(const char* s); +size_t strnlen(const char* s, size_t maxlen); +void* memset(void* dest, uint8_t fll, uint32_t nbytes); +void* memcpy(void* dest, const void* src, uint32_t nbytes); +void* memccpy(void* dest, const void* src, uint8_t stop, uint32_t nbytes); +void* memmove(void* dest, const void* src, uint32_t nbytes); +int memcmp(const void* src1, const void* src2, uint32_t nbytes); + +static size_t align_size(size_t size, size_t align) +{ + if (size % align) { + size += align - (size % align); + } + return size; +} + +static inline void* copy_after_kernel(size_t kbase, void* from, size_t size, size_t* kernel_size, size_t align) +{ + void* pp = (void*)(kbase + *kernel_size); + memcpy(pp, from, size); + *kernel_size += align_size(size, align); + return pp; +} + +static inline void* paddr_to_vaddr(void* ptr, size_t pbase, size_t vbase) +{ + return (void*)((size_t)ptr - pbase + vbase); +} + +#endif // _BOOT_LIBBOOT_MEM_MEM_H \ No newline at end of file diff --git a/boot/libboot/types.h b/boot/libboot/types.h new file mode 100644 index 0000000..debc8b6 --- /dev/null +++ b/boot/libboot/types.h @@ -0,0 +1,89 @@ +#ifndef _BOOT_LIBBOOT_TYPES_H +#define _BOOT_LIBBOOT_TYPES_H + +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +#ifdef __i386__ +typedef int32_t intptr_t; +typedef uint32_t uintptr_t; +#if defined(__clang__) +typedef unsigned int size_t; +typedef int ssize_t; +#elif defined(__GNUC__) || defined(__GNUG__) +typedef unsigned long size_t; +typedef long ssize_t; +#endif +#define BITS32 +#elif __x86_64__ +typedef uint64_t size_t; +typedef int64_t ssize_t; +typedef int64_t intptr_t; +typedef uint64_t uintptr_t; +#define BITS64 +#elif __arm__ +typedef unsigned int size_t; +typedef int ssize_t; +typedef int32_t intptr_t; +typedef uint32_t uintptr_t; +#define BITS32 +#elif __aarch64__ +typedef uint64_t size_t; +typedef int64_t ssize_t; +typedef int64_t intptr_t; +typedef uint64_t uintptr_t; +#define BITS64 +#elif defined(__riscv) && (__riscv_xlen == 64) +typedef uint64_t size_t; +typedef int64_t ssize_t; +typedef int64_t intptr_t; +typedef uint64_t uintptr_t; +#define BITS64 +#endif + +typedef _Bool bool; + +typedef __builtin_va_list va_list; +#define va_start(v, l) __builtin_va_start(v, l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v, l) __builtin_va_arg(v, l) + +#define true (1) +#define false (0) + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#define NULL ((void*)0) + +#define UNUSED(x) (void)(x) +#define ALIGNED(x) __attribute__((aligned(x))) +#define PACKED __attribute__((packed)) + +#ifndef max +#define max(a, b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) +#endif /* max */ + +#ifndef min +#define min(a, b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) +#endif /* min */ + +#define ROUND_CEIL(a, b) (((a) + ((b)-1)) & ~((b)-1)) +#define ROUND_FLOOR(a, b) ((a) & ~((b)-1)) + +#define TEST_FLAG(val, flag) (((val) & (flag)) == (flag)) +#define TEST_BIT(val, bitnum) (((val) & (1 << bitnum)) == (1 << bitnum)) + +#endif // _BOOT_LIBBOOT_TYPES_H \ No newline at end of file diff --git a/boot/riscv64/prekernel/drivers/uart.c b/boot/riscv64/prekernel/drivers/uart.c new file mode 100644 index 0000000..d999a58 --- /dev/null +++ b/boot/riscv64/prekernel/drivers/uart.c @@ -0,0 +1,24 @@ +#include "uart.h" + +volatile uint32_t* output = NULL; + +#define UART 0x10000000 +#define UART_THR (char*)(UART + 0x00) // THR:transmitter holding register +#define UART_LSR (char*)(UART + 0x05) // LSR:line status register +#define UART_LSR_EMPTY_MASK 0x40 // LSR Bit 6: Transmitter empty; both the THR and LSR are empty + +void uart_init() +{ + output = (uint32_t*)UART; +} + +int uart_write(uint8_t data) +{ + if (!output) { + return 1; + } + + while ((*UART_LSR & UART_LSR_EMPTY_MASK) == 0) { } + *output = data; + return 0; +} \ No newline at end of file diff --git a/boot/riscv64/prekernel/drivers/uart.h b/boot/riscv64/prekernel/drivers/uart.h new file mode 100644 index 0000000..13554e7 --- /dev/null +++ b/boot/riscv64/prekernel/drivers/uart.h @@ -0,0 +1,9 @@ +#ifndef _BOOT_DRIVERS_UART_H +#define _BOOT_DRIVERS_UART_H + +#include + +void uart_init(); +int uart_write(uint8_t data); + +#endif // _BOOT_DRIVERS_UART_H \ No newline at end of file diff --git a/boot/riscv64/prekernel/entry.S b/boot/riscv64/prekernel/entry.S new file mode 100644 index 0000000..02c9498 --- /dev/null +++ b/boot/riscv64/prekernel/entry.S @@ -0,0 +1,100 @@ +.extern main +.extern main_s_mode + +.section ".xos_boot_text", "xa" +prekernel_header: + auipc a0, 0 + la a1, PREKERNEL_STACK_TOP_OFFSET + mv sp, a1 + j main + +.global enable_mmu +enable_mmu: + fence rw, rw + csrw satp, a0 + csrs sstatus, a1 + sfence.vma + ret + +.global jump_to_kernel +jump_to_kernel: + fence rw, rw + sfence.vma + jr a1 +loop: + j loop + +.align 4 +timervec: + csrrw a0, mscratch, a0 + sd a1, 0(a0) + sd a2, 8(a0) + sd a3, 16(a0) + + ld a1, 24(a0) + ld a2, 32(a0) + ld a3, 0(a1) + add a3, a3, a2 + sd a3, 0(a1) + + li a1, 2 + csrw sip, a1 + + ld a3, 16(a0) + ld a2, 8(a0) + ld a1, 0(a0) + csrrw a0, mscratch, a0 + + mret + +.global setup_timer_m_mode +setup_timer_m_mode: + csrw mscratch, a0 + la t0, timervec + csrw mtvec, t0 + + csrr t0, mstatus // Add flag MSTATUS_MIE | MSTATUS_SUM + li t1, (1 << 3) | (1 << 18) + or t0, t0, t1 + csrw mstatus, t0 + + csrr t0, mie // Add flag MIE_MTIE + li t1, (1 << 7) + or t0, t0, t1 + csrw mie, t0 + + ret + +.global jump_to_s_mode +jump_to_s_mode: + csrr t0, mstatus + li t1, 3 << 11 + and t0, t0, t1 + li t1, 1 << 11 + or t0, t0, t1 + csrw mstatus, t0 + + la t1, sv_main + csrw mepc, t1 + + csrw satp, zero + + li t1, 0xffff + csrw medeleg, t1 + csrw mideleg, t1 + + li t1, (1 << 1) | (1 << 5) | (1 << 9) + csrr t0, sie + or t0, t0, t1 + csrw sie, t0 + + li t1, 0x3fffffffffffff + csrw pmpaddr0, t1 + + li t1, 0xf + csrw pmpcfg0, t1 + + mret + +sv_main: + j main_s_mode \ No newline at end of file diff --git a/boot/riscv64/prekernel/main.c b/boot/riscv64/prekernel/main.c new file mode 100644 index 0000000..5950773 --- /dev/null +++ b/boot/riscv64/prekernel/main.c @@ -0,0 +1,185 @@ +#include "drivers/uart.h" +#include "vm.h" +#include +#include +#include +#include +#include +#include + +#define DEBUG_BOOT +#define EARLY_FB + +extern uint32_t EMBED_DEVTREE_START[]; +extern uint32_t EMBED_DEVTREE_END[]; + +extern void jump_to_s_mode(uintptr_t); +extern void jump_to_kernel(void*, uintptr_t); +static void* bootdesc_paddr; +static void* bootdesc_vaddr; +static size_t kernel_vaddr = 0; +static size_t kernel_paddr = 0; +static size_t kernel_size = 0; + +#define LAUNCH_SERVER_PATH "/System/launch_server" + +static int alloc_init() +{ + devtree_entry_t* dev = devtree_find_device("ram"); + if (!dev) { + log("Can't find RAM in devtree"); + while (1) { }; + } + + extern uint32_t RAWIMAGE_END[]; + uintptr_t start_addr = ROUND_CEIL((uint64_t)RAWIMAGE_END, page_size()); + size_t free_space = dev->region_size - (start_addr - dev->region_base); + malloc_init((void*)start_addr, free_space); + +#ifdef DEBUG_BOOT + log("malloc inited %llx %llx", start_addr, free_space); +#endif + return 0; +} + +static size_t memory_layout_size() +{ + return 0 + 1; // Including the trailing element. +} + +static int preserve_alloc_init(size_t kernsize) +{ + const size_t devtreesize = ROUND_CEIL(devtree_size(), page_size()); + const size_t memmap = ROUND_CEIL(memory_layout_size() * sizeof(memory_layout_t), page_size()); + const size_t bootargsstruct = ROUND_CEIL(sizeof(boot_args_t), page_size()); + const size_t bootargssize = devtreesize + memmap + bootargsstruct; + + // 32 tables should be enough for initial mappings. + const size_t prekernelvmsize = 32 * page_size(); + const size_t total = ROUND_CEIL(kernsize + bootargssize + prekernelvmsize, page_size()); + + return palloc_init(total, 2 << 20); +} + +static memory_boot_desc_t memory_boot_desc_init() +{ + devtree_entry_t* dev = devtree_find_device("ram"); + if (!dev) { +#ifdef EARLY_FB + log("Can't find RAM in devtree"); +#endif + while (1) { }; + } + + memory_boot_desc_t res; + const size_t memlayout_size = memory_layout_size(); + memory_layout_t* mem_layout_paddr = palloc_aligned(memlayout_size * sizeof(memory_layout_t), page_size()); + + // Init of trailing element. + mem_layout_paddr[memlayout_size - 1].flags = MEMORY_LAYOUT_FLAG_TERMINATE; + memory_layout_t* mem_layout_vaddr = paddr_to_vaddr(mem_layout_paddr, kernel_paddr, kernel_vaddr); +#if defined(DEBUG_BOOT) && defined(EARLY_FB) + log("initing MEMLAYOUT %lx of %d elems", mem_layout_vaddr, memlayout_size); +#endif + + res.ram_base = dev->region_base; + res.ram_size = dev->region_size; + res.reserved_areas = mem_layout_vaddr; + return res; +} + +static void load_kernel(void* kenrelstart) +{ + kernel_size = elf_get_kernel_size(kenrelstart); + kernel_size = ROUND_CEIL(kernel_size, page_size()); + + int err = preserve_alloc_init(kernel_size); + if (err) { +#ifdef EARLY_FB + log("add assert"); +#endif + while (1) { } + } + + int res = elf_load_kernel(kenrelstart, kernel_size, &kernel_vaddr, &kernel_paddr); +#if defined(DEBUG_BOOT) && defined(EARLY_FB) + log("kernel %lx %lx %lx", kernel_vaddr, kernel_paddr, kernel_size); +#endif + + void* odt_paddr = palloc_aligned(devtree_size(), page_size()); + memcpy(odt_paddr, devtree_start(), devtree_size()); + void* odt_vaddr = paddr_to_vaddr(odt_paddr, kernel_paddr, kernel_vaddr); +#if defined(DEBUG_BOOT) && defined(EARLY_FB) + log("copying ODT %lx -> %lx of %d", devtree_start(), odt_vaddr, devtree_size()); +#endif + + boot_args_t boot_args; + boot_args.vaddr = kernel_vaddr; + boot_args.paddr = kernel_paddr; + boot_args.kernel_data_size = 0x0; // Sets up later + boot_args.mem_boot_desc = memory_boot_desc_init(); + boot_args.devtree = odt_vaddr; + boot_args.fb_boot_desc.vaddr = 0; // Marking fb as invalid. + memcpy(boot_args.init_process, LAUNCH_SERVER_PATH, sizeof(LAUNCH_SERVER_PATH)); + + bootdesc_paddr = palloc_aligned(sizeof(boot_args), page_size()); + memcpy(bootdesc_paddr, &boot_args, sizeof(boot_args)); + bootdesc_vaddr = paddr_to_vaddr(bootdesc_paddr, kernel_paddr, kernel_vaddr); +#if defined(DEBUG_BOOT) && defined(EARLY_FB) + log("copying BOOTDESC %lx -> %lx of %d", &boot_args, bootdesc_vaddr, sizeof(boot_args)); +#endif +} + +static int enable_timer() +{ + devtree_entry_t* dev = devtree_find_device("rv64timer"); + if (!dev) { + log("Can't find timer in devtree"); + return 1; + } + + struct timer_scratch_mem { + uint64_t entries[5]; + }; + struct timer_scratch_mem* scratch = palloc_aligned(sizeof(struct timer_scratch_mem), page_size()); + + size_t hartid = 0; + volatile uint64_t* mtime = (uint64_t*)(dev->region_base + 0xBFF8); + volatile uint64_t* mtimecmp = (uint64_t*)(dev->region_base + 0x4000 + 8 * hartid); + + size_t interval = 10000000 / 125; + *mtimecmp = *mtime + interval; + scratch->entries[3] = (uint64_t)mtimecmp; + scratch->entries[4] = interval; + + extern void setup_timer_m_mode(void*); + setup_timer_m_mode(scratch); + return 0; +} + +void main(uintptr_t base) +{ + devtree_init((void*)EMBED_DEVTREE_START, (uint64_t)EMBED_DEVTREE_END - (uint64_t)EMBED_DEVTREE_START); + uart_init(); + log_init(uart_write); + alloc_init(); + + extern uint32_t EMBED_KERNEL_START[]; + load_kernel((void*)(EMBED_KERNEL_START)); + + enable_timer(); + jump_to_s_mode(base); +} + +int main_s_mode(uintptr_t base) +{ + vm_setup(base, bootdesc_paddr); + +#ifdef DEBUG_BOOT + log("Preboot done: booting to OS@%llx", ((boot_args_t*)bootdesc_vaddr)->vaddr); +#endif + + ((boot_args_t*)bootdesc_vaddr)->kernel_data_size = ROUND_CEIL(palloc_used_size(), page_size()); + jump_to_kernel((void*)bootdesc_vaddr, ((boot_args_t*)bootdesc_vaddr)->vaddr); + return 0; +} diff --git a/boot/riscv64/prekernel/vm.c b/boot/riscv64/prekernel/vm.c new file mode 100644 index 0000000..e17c88b --- /dev/null +++ b/boot/riscv64/prekernel/vm.c @@ -0,0 +1,141 @@ +#include "vm.h" +#include +#include +#include +#include +#include +#include + +#define DEBUG_VM + +static uint64_t* global_page_table; +static const uint64_t kernel_base = 0xffff800000000000; + +static uint64_t* new_ptable(boot_args_t* args) +{ + uint64_t* res = (uint64_t*)palloc_aligned(page_size(), page_size()); + memset(res, 0, page_size()); +#ifdef DEBUG_VM + log(" alloc ptable %llx %llx", (uint64_t)res, page_size()); +#endif + return res; +} + +static void map4kb_2mb(boot_args_t* args, size_t phyz, size_t virt) +{ + const size_t page_covers = (1ull << PTABLE_LV1_VADDR_OFFSET); + const size_t page_mask = page_covers - 1; + + if ((phyz & page_mask) != 0 || (virt & page_mask) != 0) { + return; + } + + // Mapping from level3. + uint64_t* page_table = global_page_table; + uint64_t ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)]; + if (ptable_desc == 0) { + uint64_t* nptbl = new_ptable(args); + uint64_t pdesc = 0x00000000000001; // v bit is set + pdesc |= ((uintptr_t)nptbl >> 2); + page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)] = pdesc; + ptable_desc = pdesc; + } + + // Level2 + page_table = (uint64_t*)(((ptable_desc >> 10) << 12) & 0xffffffffffff); + ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)]; + if (ptable_desc == 0) { + uint64_t* nptbl = new_ptable(args); + uint64_t pdesc = 0x00000000000001; // v bit is set + pdesc |= ((uintptr_t)nptbl >> 2); + page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)] = pdesc; + ptable_desc = pdesc; + } + + page_table = (uint64_t*)(((ptable_desc >> 10) << 12) & 0xffffffffffff); + uint64_t pdesc = 0x0000000000000f; // w + v + x + r bits are set. + pdesc |= ((uintptr_t)phyz >> 2); + page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV1_VADDR_OFFSET, VMM_LV1_ENTITY_COUNT)] = pdesc; +} + +static void map4kb_1gb(boot_args_t* args, size_t phyz, size_t virt) +{ + const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET); + const size_t page_mask = page_covers - 1; + + if ((phyz & page_mask) != 0 || (virt & page_mask) != 0) { + return; + } + + // Mapping from level3. + uint64_t* page_table = global_page_table; + uint64_t ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)]; + if (ptable_desc == 0) { + uint64_t* nptbl = new_ptable(args); + uint64_t pdesc = 0x00000000000001; // v bit is set + pdesc |= ((uintptr_t)nptbl >> 2); + page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)] = pdesc; + ptable_desc = pdesc; + } + + page_table = (uint64_t*)(((ptable_desc >> 10) << 12) & 0xffffffffffff); + uint64_t pdesc = 0x0000000000000f; // w + v + x + r bits are set. + pdesc |= ((uintptr_t)phyz >> 2); + page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)] = pdesc; +} + +static void map_uart(boot_args_t* args) +{ + devtree_entry_t* dev = devtree_find_device("uart"); + if (!dev) { + return; + } + + uint64_t paddr = dev->region_base; + const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET); + paddr &= ~(page_covers - 1); + +#ifdef DEBUG_VM + log("mapping %lx %lx", paddr, paddr); +#endif + map4kb_1gb(args, paddr, paddr); +} + +void vm_setup(uintptr_t base, boot_args_t* args) +{ + global_page_table = (uint64_t*)palloc_aligned(page_size(), page_size()); + memset(global_page_table, 0, page_size()); + + const size_t map_range_2mb = (2 << 20); + const size_t map_range_1gb = (1 << 30); + + // Mapping kernel vaddr to paddr + size_t kernel_size_to_map = palloc_total_size() + shadow_area_size(); + size_t kernel_range_count_to_map = (kernel_size_to_map + (map_range_2mb - 1)) / map_range_2mb; + for (size_t i = 0; i < kernel_range_count_to_map; i++) { +#ifdef DEBUG_VM + log("mapping %lx %lx", args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb); +#endif + map4kb_2mb(args, args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb); + } + + // Mapping RAM + size_t ram_base = ROUND_FLOOR(args->mem_boot_desc.ram_base, map_range_1gb); + size_t ram_size = args->mem_boot_desc.ram_size; + size_t ram_range_count_to_map = (ram_size + (map_range_1gb - 1)) / map_range_1gb; + for (size_t i = 0; i < ram_range_count_to_map; i++) { +#ifdef DEBUG_VM + log("mapping %lx %lx", ram_base + i * map_range_1gb, ram_base + i * map_range_1gb); +#endif + map4kb_1gb(args, ram_base + i * map_range_1gb, ram_base + i * map_range_1gb); + } + + map_uart(args); + +#ifdef DEBUG_VM + log("Complete tables setup"); +#endif + + extern void enable_mmu(uintptr_t, uintptr_t); + enable_mmu((uintptr_t)(9ull << 60) | (((uintptr_t)global_page_table >> 12) & 0xffffffffff), (1 << 18)); +} diff --git a/boot/riscv64/prekernel/vm.h b/boot/riscv64/prekernel/vm.h new file mode 100644 index 0000000..a948d5f --- /dev/null +++ b/boot/riscv64/prekernel/vm.h @@ -0,0 +1,24 @@ +#ifndef _BOOT_VM_H +#define _BOOT_VM_H + +#include +#include + +#define VMM_LV0_ENTITY_COUNT (512) +#define VMM_LV1_ENTITY_COUNT (512) +#define VMM_LV2_ENTITY_COUNT (512) +#define VMM_LV3_ENTITY_COUNT (512) + +#define PTABLE_LV_TOP (3) +#define PTABLE_LV0_VADDR_OFFSET (12) +#define PTABLE_LV1_VADDR_OFFSET (21) +#define PTABLE_LV2_VADDR_OFFSET (30) +#define PTABLE_LV3_VADDR_OFFSET (39) + +#define VM_VADDR_OFFSET_AT_LEVEL(vaddr, off, ent) ((vaddr >> off) % ent) + +static size_t page_size() { return 0x1000; } + +void vm_setup(uintptr_t base, boot_args_t* args); + +#endif // _BOOT_VM_H \ No newline at end of file diff --git a/boot/x86/stage1/boot.s b/boot/x86/stage1/boot.s new file mode 100644 index 0000000..814a845 --- /dev/null +++ b/boot/x86/stage1/boot.s @@ -0,0 +1,67 @@ +[org 0x7c00] + +KERNEL_OFFSET equ 0x1000 +KERNEL_SIZE equ 32 ; (KBytes) 32KB +MEMORY_MAP_REGION equ 0xA00 + +mov [BOOT_DISK], dl ; saving boot disk + +mov bp, 0x8000 ; stack init in 16bits +mov sp, bp + +mov bx, MSG_REAL_MODE +call print_string + +mov eax, 0 +mov es, ax +mov di, MEMORY_MAP_REGION +call bios_get_memory_map + +call load_kernel +call switch_to_pm +jmp $ + +%include "boot/x86/stage1/utils16/print.s" +%include "boot/x86/stage1/utils16/smm.s" +%include "boot/x86/stage1/utils16/disk_load.s" +%include "boot/x86/stage1/utils16/switch_to_pm.s" + +%include "boot/x86/stage1/utils32/print.s" +%include "boot/x86/stage1/utils32/gdt.s" + + +[bits 16] +load_kernel: + mov bx, MSG_KERNEL_LOAD + call print_string + + mov bx, KERNEL_OFFSET + mov dh, 50 + mov dl, [BOOT_DISK] + call disk_load + ret + +[bits 32] +begin_pm: + mov ebx, MSG_PROT_MODE + call print_string_pm + mov eax, dword [memory_map_size] + push eax + mov eax, dword KERNEL_SIZE + push eax + push esp + call KERNEL_OFFSET + jmp $ + +MSG_REAL_MODE: + db 'Starting real mode', 0 +MSG_PROT_MODE: + db 'Switched to prot mode', 0 +MSG_KERNEL_LOAD: + db ' Loading kernel from drive', 0 + +BOOT_DISK: db 0 + +times (510-($-$$)) db 0 +db 0x55 +db 0xaa \ No newline at end of file diff --git a/boot/x86/stage1/utils16/disk_load.s b/boot/x86/stage1/utils16/disk_load.s new file mode 100644 index 0000000..c001d9f --- /dev/null +++ b/boot/x86/stage1/utils16/disk_load.s @@ -0,0 +1,23 @@ +[bits 16] + +disk_load: + push dx + mov ah, 0x02 + mov al, dh + mov ch, 0x00 + mov dh, 0x00 + mov cl, 0x02 + + int 0x13 + + jc disk_error + + pop dx + cmp al, dh + jne disk_error + ret +disk_error: + mov bx, MSG_DISK_ERROR + call print_string + jmp $ +MSG_DISK_ERROR: db 'disk ERROR!', 0 \ No newline at end of file diff --git a/boot/x86/stage1/utils16/print.s b/boot/x86/stage1/utils16/print.s new file mode 100644 index 0000000..ce87674 --- /dev/null +++ b/boot/x86/stage1/utils16/print.s @@ -0,0 +1,15 @@ +[bits 16] + +print_string: + pusha + mov ah, 0x0e +print_string_cycle: + cmp [bx], BYTE 0 + je print_string_end + mov al, [bx] + int 0x10 + add bx, 1 + jmp print_string_cycle +print_string_end: + popa + ret \ No newline at end of file diff --git a/boot/x86/stage1/utils16/smm.s b/boot/x86/stage1/utils16/smm.s new file mode 100644 index 0000000..5f04a6b --- /dev/null +++ b/boot/x86/stage1/utils16/smm.s @@ -0,0 +1,55 @@ +[bits 16] + +memory_map_entry: +base_address: + dq 0x0 +length: + dq 0x0 +type: + dq 0x0 +acpi_null: + dq 0x0 +memory_map_entry_end: + +memory_map_size: dw 0 + +bios_get_memory_map: + pushad + xor ebx, ebx + xor bp, bp + mov edx, 'PAMS' + mov eax, 0xe820 + mov ecx, 24 + int 0x15 + jc memory_map_error + cmp eax, 'PAMS' + jne memory_map_error + test ebx, ebx + je memory_map_error + jmp memory_map_start +memory_map_next: + mov edx, 'PAMS' + mov ecx, 24 + mov eax, 0xe820 + int 0x15 +memory_map_start: + jcxz memory_map_skip_entry +memory_map_common: + mov ecx, [es:di + 8] + test ecx, ecx + jne memory_map_good_entry + mov ecx, [es:di + 12] + jecxz memory_map_skip_entry +memory_map_good_entry: + inc bp + add di, 24 +memory_map_skip_entry: + cmp ebx, 0 + jne memory_map_next + jmp memory_map_done +memory_map_error: + stc +memory_map_done: + mov [memory_map_size], bp + popad + ret \ No newline at end of file diff --git a/boot/x86/stage1/utils16/switch_to_pm.s b/boot/x86/stage1/utils16/switch_to_pm.s new file mode 100644 index 0000000..a45e852 --- /dev/null +++ b/boot/x86/stage1/utils16/switch_to_pm.s @@ -0,0 +1,22 @@ +[bits 16] +switch_to_pm: + cli ; turn off interupts + lgdt [gdt_descriptor] + mov eax, cr0 + or eax, 0x1 + mov cr0, eax + call CODE_SEG:init_pm + +[bits 32] +init_pm: + mov ax, DATA_SEG + mov ds, ax + mov ss, ax + mov es, ax + mov fs, ax + mov gs, ax + + mov ebp, 0x90000 ; stack's init + mov esp, ebp + + call begin_pm \ No newline at end of file diff --git a/boot/x86/stage1/utils32/gdt.s b/boot/x86/stage1/utils32/gdt.s new file mode 100644 index 0000000..6b3561e --- /dev/null +++ b/boot/x86/stage1/utils32/gdt.s @@ -0,0 +1,27 @@ +gdt_begin: + +gdt_null: + dd 0x00 + dd 0x00 +gdt_code: + dw 0xffff + dw 0x0000 + db 0x0 + db 10011010b + db 11001111b + db 0x0 +gdt_data: + dw 0xffff + dw 0x0000 + db 0x0 + db 10010010b + db 11001111b + db 0x0 +gdt_end: + +gdt_descriptor: + dw gdt_end - gdt_begin - 1 + dd gdt_begin + +CODE_SEG equ gdt_code - gdt_begin +DATA_SEG equ gdt_data - gdt_begin \ No newline at end of file diff --git a/boot/x86/stage1/utils32/print.s b/boot/x86/stage1/utils32/print.s new file mode 100644 index 0000000..3536e38 --- /dev/null +++ b/boot/x86/stage1/utils32/print.s @@ -0,0 +1,22 @@ +[bits 32] + +VIDEO_MEMORY equ 0xb8000 +WHITE_ON_BLACK equ 0x0f + +print_string_pm: + pusha + mov edx, VIDEO_MEMORY +print_string_pm_cycle: + cmp [ebx], BYTE 0 + je print_string_pm_end + mov ah, WHITE_ON_BLACK + mov al, [ebx] + mov [edx], ax + + add ebx, 1 + add edx, 2 + + jmp print_string_pm_cycle +print_string_pm_end: + popa + ret \ No newline at end of file diff --git a/boot/x86/stage2/config.h b/boot/x86/stage2/config.h new file mode 100644 index 0000000..7d7abf4 --- /dev/null +++ b/boot/x86/stage2/config.h @@ -0,0 +1,24 @@ +#ifndef STAGE2_CONFIG +#define STAGE2_CONFIG + +#include + +#define KERNEL_BASE 0x100000 + +struct x86_memory_map { + uint32_t startLo; + uint32_t startHi; + uint32_t sizeLo; + uint32_t sizeHi; + uint32_t type; + uint32_t acpi_3_0; +}; +typedef struct x86_memory_map x86_memory_map_t; + +struct x86_mem_desc { + uint32_t memory_map_size; + uint32_t kernel_size; +}; +typedef struct x86_mem_desc x86_mem_desc_t; + +#endif // STAGE2_CONFIG \ No newline at end of file diff --git a/boot/x86/stage2/drivers/ata.c b/boot/x86/stage2/drivers/ata.c new file mode 100644 index 0000000..2e14d68 --- /dev/null +++ b/boot/x86/stage2/drivers/ata.c @@ -0,0 +1,135 @@ +/** + * Ata Stage2 driver. This is a lite version, since it can work with + * only one drive at time. The @active_ata_drive is a boot drive. + */ + +#include "ata.h" +#include + +// #define DEBUG_ATA + +ata_t active_ata_drive; + +void init_ata(uint32_t port, char is_master) +{ + active_ata_drive.is_master = is_master; + active_ata_drive.data_port = port; + active_ata_drive.error_port = port + 0x1; + active_ata_drive.sector_count_port = port + 0x2; + active_ata_drive.lba_lo_port = port + 0x3; + active_ata_drive.lba_mid_port = port + 0x4; + active_ata_drive.lba_hi_port = port + 0x5; + active_ata_drive.device_port = port + 0x6; + active_ata_drive.command_port = port + 0x7; + active_ata_drive.control_port = port + 0x206; +} + +int indentify_ata_device(drive_desc_t* drive_desc) +{ + port_write8(active_ata_drive.device_port, active_ata_drive.is_master ? 0xA0 : 0xB0); + port_write8(active_ata_drive.sector_count_port, 0); + port_write8(active_ata_drive.lba_lo_port, 0); + port_write8(active_ata_drive.lba_mid_port, 0); + port_write8(active_ata_drive.lba_hi_port, 0); + port_write8(active_ata_drive.command_port, 0xEC); + + // check the acceptance of a command + uint8_t status = port_read8(active_ata_drive.command_port); + if (status == 0x00) { + // printf("Cmd isn't accepted"); + return -1; + } + + // waiting for processing + // while BSY is on + while ((status & 0x80) == 0x80) { + status = port_read8(active_ata_drive.command_port); + } + + // check if drive isn't ready to transer DRQ + if ((status & 0x08) != 0x08) { + // printf("Don't ready for transport"); + return -1; + } + + // transfering 256 bytes of data + for (int i = 0; i < 256; i++) { + uint16_t data = port_read16(active_ata_drive.data_port); + char* text = " \0"; + text[0] = (data >> 8) & 0xFF; + text[1] = data & 0xFF; + if (i == 1) { +#ifdef DEBUG_ATA + log("Logical cylindres %x", data); +#endif + } + if (i == 3) { +#ifdef DEBUG_ATA + log("Logical heads %x", data); +#endif + } + if (i == 6) { +#ifdef DEBUG_ATA + log("Logical sectors %x", data); +#endif + } + if (i == 49) { + if (((data >> 8) & 0x1) == 1) { +#ifdef DEBUG_ATA + log("Dma supported"); +#endif + } + if (((data >> 9) & 0x1) == 1) { +#ifdef DEBUG_ATA + log("Lba supported"); +#endif + } + } + } + + drive_desc->read = ata_read; + return 0; +} + +// Returning 2 head read bytes (used to get size of kernel) +int ata_read(uint32_t sector, uint8_t* read_to) +{ + uint8_t dev_config = 0xA0; + // lba support + dev_config |= (1 << 6); + if (!active_ata_drive.is_master) { + dev_config |= (1 << 4); + } + + port_write8(active_ata_drive.device_port, dev_config); + port_write8(active_ata_drive.sector_count_port, 1); + port_write8(active_ata_drive.lba_lo_port, sector & 0x000000FF); + port_write8(active_ata_drive.lba_mid_port, (sector & 0x0000FF00) >> 8); + port_write8(active_ata_drive.lba_hi_port, (sector & 0x00FF0000) >> 16); + port_write8(active_ata_drive.error_port, 0); + port_write8(active_ata_drive.command_port, 0x21); + + // waiting for processing + // while BSY is on and no Errors + uint8_t status = port_read8(active_ata_drive.command_port); + while (((status >> 7) & 1) == 1 && ((status >> 0) & 1) != 1) { + status = port_read8(active_ata_drive.command_port); + } + + // check if drive isn't ready to transer DRQ + if (((status >> 0) & 1) == 1) { + return -1; + } + + if (((status >> 3) & 1) == 0) { + return -1; + } + + for (int i = 0; i < 256; i++) { + uint16_t data = port_read16(active_ata_drive.data_port); + read_to[2 * i + 1] = (data >> 8) & 0xFF; + read_to[2 * i] = data & 0xFF; + } + + return 0; +} \ No newline at end of file diff --git a/boot/x86/stage2/drivers/ata.h b/boot/x86/stage2/drivers/ata.h new file mode 100644 index 0000000..1a5be85 --- /dev/null +++ b/boot/x86/stage2/drivers/ata.h @@ -0,0 +1,25 @@ +#ifndef _BOOT_X86_STAGE2_DRIVERS_ATA_H +#define _BOOT_X86_STAGE2_DRIVERS_ATA_H + +#include "port.h" +#include +#include + +typedef struct { // LBA28 | LBA48 + uint32_t data_port; // 16bit | 16 bits + uint32_t error_port; // 8 bit | 16 bits + uint32_t sector_count_port; // 8 bit | 16 bits + uint32_t lba_lo_port; // 8 bit | 16 bits + uint32_t lba_mid_port; // 8 bit | 16 bits + uint32_t lba_hi_port; // 8 bit | 16 bits + uint32_t device_port; // 8 bit + uint32_t command_port; // 8 bit + uint32_t control_port; // 8 bit + char is_master; +} ata_t; + +void init_ata(uint32_t port, char is_master); +int indentify_ata_device(drive_desc_t* drive_desc); +int ata_read(uint32_t sector, uint8_t* read_to); + +#endif \ No newline at end of file diff --git a/boot/x86/stage2/drivers/port.c b/boot/x86/stage2/drivers/port.c new file mode 100644 index 0000000..e7ea270 --- /dev/null +++ b/boot/x86/stage2/drivers/port.c @@ -0,0 +1,56 @@ +#include "port.h" + +unsigned char port_read8(unsigned short port) +{ + unsigned char result_data; + asm volatile("inb %%dx, %%al" + : "=a"(result_data) + : "d"(port)); + return result_data; +} + +void port_write8(unsigned short port, unsigned char data) +{ + asm volatile("outb %%al, %%dx" + : + : "a"(data), "d"(port)); +} + +unsigned short port_read16(unsigned short port) +{ + unsigned short result_data; + asm volatile("inw %%dx, %%ax" + : "=a"(result_data) + : "d"(port)); + return result_data; +} + +void port_write16(unsigned short port, unsigned short data) +{ + asm volatile("outw %%ax, %%dx" + : + : "a"(data), "d"(port)); +} + +unsigned int port_read32(unsigned short port) +{ + unsigned int result_data; + asm volatile("inl %%dx, %%eax" + : "=a"(result_data) + : "d"(port)); + return result_data; +} + +void port_write32(unsigned short port, unsigned int data) +{ + asm volatile("outl %%eax, %%dx" + : + : "a"(data), "d"(port)); +} + +void port_wait_io() +{ + asm volatile("out %%al, $0x80" + : + : "a"(0)); // writing to "unused" port +} \ No newline at end of file diff --git a/boot/x86/stage2/drivers/port.h b/boot/x86/stage2/drivers/port.h new file mode 100644 index 0000000..55dedcd --- /dev/null +++ b/boot/x86/stage2/drivers/port.h @@ -0,0 +1,15 @@ +#ifndef _BOOT_X86_STAGE2_DRIVERS_PORT_H +#define _BOOT_X86_STAGE2_DRIVERS_PORT_H + +unsigned char port_read8(unsigned short port); +void port_write8(unsigned short port, unsigned char data); + +unsigned short port_read16(unsigned short port); +void port_write16(unsigned short port, unsigned short data); + +unsigned int port_read32(unsigned short port); +void port_write32(unsigned short port, unsigned int data); + +void port_wait_io(); + +#endif // _BOOT_X86_STAGE2_DRIVERS_PORT_H \ No newline at end of file diff --git a/boot/x86/stage2/drivers/uart.c b/boot/x86/stage2/drivers/uart.c new file mode 100644 index 0000000..76f61c5 --- /dev/null +++ b/boot/x86/stage2/drivers/uart.c @@ -0,0 +1,36 @@ +#include "uart.h" +#include "port.h" + +static int _uart_setup_impl(int port) +{ + port_write8(port + 1, 0x00); + port_write8(port + 3, 0x80); + port_write8(port + 0, 0x03); + port_write8(port + 1, 0x00); + port_write8(port + 3, 0x03); + port_write8(port + 2, 0xC7); + port_write8(port + 4, 0x0B); + return 0; +} + +void uart_init() +{ + _uart_setup_impl(COM1); +} + +static inline bool _uart_is_free_in(int port) +{ + return port_read8(port + 5) & 0x01; +} + +static inline bool _uart_is_free_out(int port) +{ + return port_read8(port + 5) & 0x20; +} + +int uart_write(uint8_t data) +{ + while (!_uart_is_free_out(COM1)) { } + port_write8(COM1, data); + return 0; +} diff --git a/boot/x86/stage2/drivers/uart.h b/boot/x86/stage2/drivers/uart.h new file mode 100644 index 0000000..4671d4f --- /dev/null +++ b/boot/x86/stage2/drivers/uart.h @@ -0,0 +1,14 @@ +#ifndef _STAGE2_DRIVERS_X86_UART_H +#define _STAGE2_DRIVERS_X86_UART_H + +#include + +#define COM1 0x3F8 +#define COM2 0x2F8 +#define COM3 0x3E8 +#define COM4 0x2E8 + +void uart_init(); +int uart_write(uint8_t data); + +#endif //_STAGE2_DRIVERS_X86_UART_H \ No newline at end of file diff --git a/boot/x86/stage2/mem/pde.h b/boot/x86/stage2/mem/pde.h new file mode 100644 index 0000000..80ec193 --- /dev/null +++ b/boot/x86/stage2/mem/pde.h @@ -0,0 +1,23 @@ +#ifndef _BOOT_X86_STAGE2_MEM_PDE_H +#define _BOOT_X86_STAGE2_MEM_PDE_H + +#include + +#define table_desc_t uint32_t +#define pde_t uint32_t + +enum TABLE_DESC_PAGE_FLAGS { + TABLE_DESC_PRESENT = 0, + TABLE_DESC_WRITABLE, + TABLE_DESC_USER, + TABLE_DESC_PWT, + TABLE_DESC_PCD, + TABLE_DESC_ACCESSED, + TABLE_DESC_DIRTY, + TABLE_DESC_4MB, + TABLE_DESC_CPU_GLOBAL, + TABLE_DESC_LV4_GLOBAL, + TABLE_DESC_FRAME = 12 +}; + +#endif //_BOOT_X86_STAGE2_MEM_PDE_H diff --git a/boot/x86/stage2/mem/pte.h b/boot/x86/stage2/mem/pte.h new file mode 100644 index 0000000..c44f539 --- /dev/null +++ b/boot/x86/stage2/mem/pte.h @@ -0,0 +1,23 @@ +#ifndef _BOOT_X86_STAGE2_MEM_PTE_H +#define _BOOT_X86_STAGE2_MEM_PTE_H + +#include + +#define page_desc_t uint32_t +#define pte_t uint32_t + +enum PAGE_DESC_PAGE_FLAGS { + PAGE_DESC_PRESENT = 0, + PAGE_DESC_WRITABLE, + PAGE_DESC_USER, + PAGE_DESC_WRITETHOUGH, + PAGE_DESC_NOT_CACHEABLE, + PAGE_DESC_ACCESSED, + PAGE_DESC_DIRTY, + PAGE_DESC_PAT, + PAGE_DESC_CPU_GLOBAL, + PAGE_DESC_LV4_GLOBAL, + PAGE_DESC_FRAME = 12 +}; + +#endif //_BOOT_X86_STAGE2_MEM_PTE_H diff --git a/boot/x86/stage2/mem/vm.c b/boot/x86/stage2/mem/vm.c new file mode 100644 index 0000000..1112bf5 --- /dev/null +++ b/boot/x86/stage2/mem/vm.c @@ -0,0 +1,77 @@ +#include "vm.h" + +int vm_setup() +{ + ptable_t* table_0mb = (ptable_t*)0x9A000; + ptable_t* table_0mbplus = (ptable_t*)0x98000; + ptable_t* table_3gb = (ptable_t*)0x9B000; + ptable_t* table_3gbplus = (ptable_t*)0x99000; + ptable_t* table_stack = (ptable_t*)0x9C000; + pdirectory_t* dir = (pdirectory_t*)0x9D000; + + for (uint32_t phyz = 0, virt = 0, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) { + pte_t new_page = 0; + new_page |= 3; + new_page |= ((phyz / VMM_PAGE_SIZE) << 12); + table_0mb->entities[i] = new_page; + } + + for (uint32_t phyz = 0x400000, virt = 0x400000, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) { + pte_t new_page = 0; + new_page |= 3; + new_page |= ((phyz / VMM_PAGE_SIZE) << 12); + table_0mbplus->entities[i] = new_page; + } + + for (uint32_t phyz = 0x100000, virt = 0xc0000000, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) { + pte_t new_page = 0; + new_page |= 3; + new_page |= ((phyz / VMM_PAGE_SIZE) << 12); + table_3gb->entities[i] = new_page; + } + + for (uint32_t phyz = 0x500000, virt = 0xc0400000, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) { + pte_t new_page = 0; + new_page |= 3; + new_page |= ((phyz / VMM_PAGE_SIZE) << 12); + table_3gbplus->entities[i] = new_page; + } + + for (uint32_t phyz = 0x000000, virt = 0xffc00000, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) { + pte_t new_page = 0; + new_page |= 3; + new_page |= ((phyz / VMM_PAGE_SIZE) << 12); + table_stack->entities[i] = new_page; + } + + uint8_t* dir_for_memset = (uint8_t*)dir; + for (int i = 0; i < 1024; i++) { + dir->entities[i] = 0; + } + + uint32_t table_0mb_int = (uint32_t)table_0mb; + dir->entities[0] |= 3; + dir->entities[0] |= ((table_0mb_int / VMM_PAGE_SIZE) << 12); + + table_0mb_int = (uint32_t)table_0mbplus; + dir->entities[1] |= 3; + dir->entities[1] |= ((table_0mb_int / VMM_PAGE_SIZE) << 12); + + uint32_t table_3gb_int = (uint32_t)table_3gb; + dir->entities[768] |= 3; + dir->entities[768] |= ((table_3gb_int / VMM_PAGE_SIZE) << 12); + + table_3gb_int = (uint32_t)table_3gbplus; + dir->entities[769] |= 3; + dir->entities[769] |= ((table_3gb_int / VMM_PAGE_SIZE) << 12); + + uint32_t table_stack_int = (uint32_t)table_stack; + dir->entities[1023] |= 3; + dir->entities[1023] |= ((table_stack_int / VMM_PAGE_SIZE) << 12); + + asm volatile("mov %%eax, %%cr3" + : + : "a"(dir)); + + return 0; +} \ No newline at end of file diff --git a/boot/x86/stage2/mem/vm.h b/boot/x86/stage2/mem/vm.h new file mode 100644 index 0000000..1b2d247 --- /dev/null +++ b/boot/x86/stage2/mem/vm.h @@ -0,0 +1,28 @@ +#ifndef _BOOT_X86_STAGE2_MEM_VM_H +#define _BOOT_X86_STAGE2_MEM_VM_H + +#include "pde.h" +#include "pte.h" +#include + +#define VMM_LV0_ENTITY_COUNT (1024) +#define VMM_LV1_ENTITY_COUNT (1024) +#define VMM_PAGE_SIZE (4096) + +enum VMM_ERR_CODES { + VMM_ERR_PDIR, + VMM_ERR_NO_SPACE, + VMM_ERR_BAD_ADDR, +}; + +typedef struct { + page_desc_t entities[VMM_LV0_ENTITY_COUNT]; +} ptable_t; + +typedef struct pdirectory { + table_desc_t entities[VMM_LV1_ENTITY_COUNT]; +} pdirectory_t; + +int vm_setup(); + +#endif // _BOOT_X86_STAGE2_MEM_VM_H diff --git a/boot/x86/stage2/stage2.c b/boot/x86/stage2/stage2.c new file mode 100644 index 0000000..7c119e9 --- /dev/null +++ b/boot/x86/stage2/stage2.c @@ -0,0 +1,156 @@ +/** + * Stage2 is used to load main kernel. + */ + +#include "config.h" +#include "drivers/ata.h" +#include "drivers/uart.h" +#include "mem/vm.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// #define DEBUG_BOOT +#define KERNEL_PATH "/boot/kernel.bin" +#define LAUNCH_SERVER_PATH "/System/launch_server" + +static boot_args_t boot_args; +static size_t kernel_vaddr = 0; +static size_t kernel_paddr = 0; +static size_t kernel_size = 0; + +static void alloc_init(x86_mem_desc_t* mem_desc) +{ + // TODO: We use manual layouting in this bootloader. Thus + // all addresses are hardcoded, no need to use allocator at all. +} + +static memory_boot_desc_t memory_boot_desc_init(x86_mem_desc_t* mem_desc) +{ + char dummy_data = 0x0; + size_t ram_last_addr = 0x0; + size_t next_id = 0; + memory_layout_t* mem_layout_paddr = copy_after_kernel(kernel_paddr, &dummy_data, sizeof(dummy_data), &kernel_size, VMM_PAGE_SIZE); + x86_memory_map_t* memory_map = (x86_memory_map_t*)0xA00; + + for (int i = 0; i < mem_desc->memory_map_size; i++) { + if (memory_map[i].type == 0x2) { + // The region is marked as reserved, removing it. + mem_layout_paddr[next_id].base = memory_map[i].startLo; + mem_layout_paddr[next_id].size = memory_map[i].sizeLo; + mem_layout_paddr[next_id].flags = 0; + next_id++; + } else { + ram_last_addr = max(ram_last_addr, memory_map[i].startLo + memory_map[i].sizeLo); + } + } + mem_layout_paddr[next_id].flags = MEMORY_LAYOUT_FLAG_TERMINATE; + memory_layout_t* mem_layout_vaddr = paddr_to_vaddr(mem_layout_paddr, kernel_paddr, kernel_vaddr); + + memory_boot_desc_t res; + res.ram_base = 0x0; + res.ram_size = ram_last_addr; + res.reserved_areas = mem_layout_vaddr; + return res; +} + +int prepare_boot_disk(drive_desc_t* drive_desc) +{ + init_ata(0x1F0, 1); + if (indentify_ata_device(drive_desc) == 0) { + return 0; + } + return -1; +} + +int prepare_fs(drive_desc_t* drive_desc, fs_desc_t* fs_desc) +{ + if (ext2_lite_init(drive_desc, fs_desc) == 0) { + return 0; + } + return -1; +} + +static int validate_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc) +{ + log("Validating Kernel..."); + if (!validate_elf(KERNEL_PATH, drive_desc, fs_desc)) { + log("Can't validate kernel"); + while (1) { } + } + + if (!validate_elf(LAUNCH_SERVER_PATH, drive_desc, fs_desc)) { + log("Can't validate launch_server"); + while (1) { } + } + + return 0; +} + +void* bootdesc_ptr; +void load_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc, x86_mem_desc_t* mem_desc) +{ + int res = elf_load_kernel(drive_desc, fs_desc, KERNEL_PATH, &kernel_vaddr, &kernel_paddr, &kernel_size); + kernel_size = align_size(kernel_size, VMM_PAGE_SIZE); + + size_t kernel_data_size = kernel_size + align_size(sizeof(boot_args_t), VMM_PAGE_SIZE) + VMM_PAGE_SIZE; + + boot_args_t boot_args; + boot_args.vaddr = kernel_vaddr; + boot_args.paddr = kernel_paddr; + boot_args.kernel_data_size = kernel_data_size; + boot_args.devtree = NULL; + boot_args.mem_boot_desc = memory_boot_desc_init(mem_desc); + memcpy(boot_args.init_process, LAUNCH_SERVER_PATH, sizeof(LAUNCH_SERVER_PATH)); + + bootdesc_ptr = paddr_to_vaddr(copy_after_kernel(kernel_paddr, &boot_args, sizeof(boot_args), &kernel_size, VMM_PAGE_SIZE), kernel_paddr, kernel_vaddr); +} + +void stage2(x86_mem_desc_t* mem_desc) +{ + uart_init(); + log_init(uart_write); + alloc_init(mem_desc); + +#ifdef DEBUG_BOOT + log("STAGE2"); +#endif + drive_desc_t drive_desc; + fs_desc_t fs_desc; + + if (prepare_boot_disk(&drive_desc) != 0) { +#ifdef DEBUG_BOOT + log("STAGE2"); +#endif + while (1) { } + } + + if (prepare_fs(&drive_desc, &fs_desc) != 0) { +#ifdef DEBUG_BOOT + log("STAGE2"); +#endif + while (1) { } + } + + validate_kernel(&drive_desc, &fs_desc); + load_kernel(&drive_desc, &fs_desc, mem_desc); + vm_setup(); + + // enabling paging + asm volatile("mov %cr0, %eax"); + asm volatile("or $0x80000000, %eax"); + asm volatile("mov %eax, %cr0"); + + asm volatile("push %0" + : + : "r"(bootdesc_ptr)); + asm volatile("mov $0xc0000000, %eax"); + asm volatile("call *%eax"); + while (1) { } +} diff --git a/boot/x86/stage2/stage2_entry.s b/boot/x86/stage2/stage2_entry.s new file mode 100644 index 0000000..346c069 --- /dev/null +++ b/boot/x86/stage2/stage2_entry.s @@ -0,0 +1,12 @@ +section .xos_boot_text + +[bits 32] +extern stage2 +extern STACK_PHYZ_TOP +global _start +_start: + mov eax, esp + mov esp, STACK_PHYZ_TOP + push dword [eax+4] + call stage2 + jmp $ \ No newline at end of file diff --git a/boot/x86_64/prekernel/drivers/port.h b/boot/x86_64/prekernel/drivers/port.h new file mode 100644 index 0000000..6d7e4de --- /dev/null +++ b/boot/x86_64/prekernel/drivers/port.h @@ -0,0 +1,61 @@ +#ifndef _BOOT_DRIVERS_PORT_H +#define _BOOT_DRIVERS_PORT_H + +#include + +static inline uint8_t port_read8(uint16_t port) +{ + uint8_t result_data; + asm volatile("inb %%dx, %%al" + : "=a"(result_data) + : "d"(port)); + return result_data; +} + +static inline void port_write8(uint16_t port, uint8_t data) +{ + asm volatile("outb %%al, %%dx" + : + : "a"(data), "d"(port)); +} + +static inline uint16_t port_read16(uint16_t port) +{ + uint16_t result_data; + asm volatile("inw %%dx, %%ax" + : "=a"(result_data) + : "d"(port)); + return result_data; +} + +static inline void port_write16(uint16_t port, uint16_t data) +{ + asm volatile("outw %%ax, %%dx" + : + : "a"(data), "d"(port)); +} + +static inline uint32_t port_read32(uint16_t port) +{ + uint32_t result_data; + asm volatile("inl %%dx, %%eax" + : "=a"(result_data) + : "d"(port)); + return result_data; +} + +static inline void port_write32(uint16_t port, uint32_t data) +{ + asm volatile("outl %%eax, %%dx" + : + : "a"(data), "d"(port)); +} + +static inline void port_wait_io() +{ + asm volatile("out %%al, $0x80" + : + : "a"(0)); +} + +#endif // _BOOT_DRIVERS_PORT_H \ No newline at end of file diff --git a/boot/x86_64/prekernel/drivers/uart.c b/boot/x86_64/prekernel/drivers/uart.c new file mode 100644 index 0000000..1d6d4a1 --- /dev/null +++ b/boot/x86_64/prekernel/drivers/uart.c @@ -0,0 +1,43 @@ +#include "uart.h" +#include "port.h" + +static int _uart_setup_impl(int port) +{ + port_write8(port + 1, 0x00); + port_write8(port + 3, 0x80); + port_write8(port + 0, 0x03); + port_write8(port + 1, 0x00); + port_write8(port + 3, 0x03); + port_write8(port + 2, 0xC7); + port_write8(port + 4, 0x0B); + return 0; +} + +void uart_init() +{ + _uart_setup_impl(COM1); +} + +static inline bool _uart_is_free_in(int port) +{ + return port_read8(port + 5) & 0x01; +} + +static inline bool _uart_is_free_out(int port) +{ + return port_read8(port + 5) & 0x20; +} + +int uart_write(uint8_t data) +{ + while (!_uart_is_free_out(COM1)) { } + port_write8(COM1, data); + return 0; +} + +int uart_read(uint8_t* data) +{ + while (!_uart_is_free_out(COM1)) { } + *data = port_read8(COM1); + return 0; +} \ No newline at end of file diff --git a/boot/x86_64/prekernel/drivers/uart.h b/boot/x86_64/prekernel/drivers/uart.h new file mode 100644 index 0000000..52717d9 --- /dev/null +++ b/boot/x86_64/prekernel/drivers/uart.h @@ -0,0 +1,15 @@ +#ifndef _BOOT_DRIVERS_UART_H +#define _BOOT_DRIVERS_UART_H + +#include + +#define COM1 0x3F8 +#define COM2 0x2F8 +#define COM3 0x3E8 +#define COM4 0x2E8 + +void uart_init(); +int uart_write(uint8_t data); +int uart_read(uint8_t* data); + +#endif //_BOOT_DRIVERS_UART_H \ No newline at end of file diff --git a/boot/x86_64/prekernel/main.c b/boot/x86_64/prekernel/main.c new file mode 100644 index 0000000..58adef7 --- /dev/null +++ b/boot/x86_64/prekernel/main.c @@ -0,0 +1,153 @@ +#include "drivers/uart.h" +#include "vm.h" +#include +#include +#include +#include +#include + +// #define DEBUG_BOOT + +extern void jump_to_kernel(void*, uintptr_t); +static void* bootdesc_paddr; +static void* bootdesc_vaddr; +static size_t kernel_vaddr = 0; +static size_t kernel_paddr = 0; +static size_t kernel_size = 0; + +#define LAUNCH_SERVER_PATH "/System/launch_server" + +static int alloc_init(uintptr_t base, multiboot_info_t* multiboot) +{ + uintptr_t region_base = 0x0; + size_t region_size = 0x0; + + multiboot_memory_map_t* memmap = (multiboot_memory_map_t*)(uint64_t)multiboot->mmap_addr; + size_t n = multiboot->mmap_length / sizeof(multiboot_memory_map_t); + + // Looking for the zone of memory where we are linked + for (int i = 0; i < n; i++) { + if (memmap[i].type == MULTIBOOT_MEMORY_AVAILABLE) { + if (memmap[i].addr <= base && base < memmap[i].addr + memmap[i].len) { + region_base = memmap[i].addr; + region_size = memmap[i].len; + } + } + } + + // We expect the current zone to be quite big, at least 128Mb. + if (region_size < (128 << 20)) { + log("Current space is less than required 128Mbs"); + while (1) { } + } + + extern uint32_t RAWIMAGE_END[]; + uintptr_t start_addr = ROUND_CEIL((uint64_t)RAWIMAGE_END, page_size()); + size_t free_space = region_size - (start_addr - region_base); + malloc_init((void*)start_addr, free_space); + +#ifdef DEBUG_BOOT + log("malloc inited %llx %llx", start_addr, free_space); +#endif + return 0; +} + +static size_t memory_layout_size(multiboot_info_t* multiboot) +{ + size_t n = multiboot->mmap_length / sizeof(multiboot_memory_map_t); + return n + 1; // Including the trailing element. +} + +static int preserve_alloc_init(size_t kernsize, multiboot_info_t* multiboot) +{ + const size_t memmap = ROUND_CEIL(memory_layout_size(multiboot) * sizeof(memory_layout_t), page_size()); + const size_t bootargsstruct = ROUND_CEIL(sizeof(boot_args_t), page_size()); + const size_t bootargssize = memmap + bootargsstruct; + + // 32 tables should be enough for initial mappings. + const size_t prekernelvmsize = 32 * page_size(); + const size_t total = ROUND_CEIL(kernsize + bootargssize + prekernelvmsize, page_size()); + + return palloc_init(total, 2 << 20); +} + +static memory_boot_desc_t memory_boot_desc_init(multiboot_info_t* multiboot) +{ + size_t ram_last_addr = 0x0; + size_t next_id = 0; + memory_layout_t* mem_layout_paddr = palloc_aligned(memory_layout_size(multiboot) * sizeof(memory_layout_t), page_size()); + multiboot_memory_map_t* memmap = (multiboot_memory_map_t*)(uint64_t)multiboot->mmap_addr; + size_t n = multiboot->mmap_length / sizeof(multiboot_memory_map_t); + + for (int i = 0; i < n; i++) { + if (memmap[i].type != MULTIBOOT_MEMORY_AVAILABLE) { + // The region is marked as reserved, removing it. + mem_layout_paddr[next_id].base = memmap[i].addr; + mem_layout_paddr[next_id].size = memmap[i].len; + mem_layout_paddr[next_id].flags = 0; + next_id++; + } else { + ram_last_addr = max(ram_last_addr, memmap[i].addr + memmap[i].len); + } + } + mem_layout_paddr[next_id].flags = MEMORY_LAYOUT_FLAG_TERMINATE; + memory_layout_t* mem_layout_vaddr = paddr_to_vaddr(mem_layout_paddr, kernel_paddr, kernel_vaddr); + + memory_boot_desc_t res; + res.ram_base = 0x0; + res.ram_size = ram_last_addr; + res.reserved_areas = mem_layout_vaddr; + return res; +} + +static void load_kernel(void* kenrelstart, multiboot_info_t* multiboot) +{ + kernel_size = elf_get_kernel_size(kenrelstart); + kernel_size = ROUND_CEIL(kernel_size, page_size()); + + int err = preserve_alloc_init(kernel_size, multiboot); + if (err) { + log("add assert"); + while (1) { } + } + + int res = elf_load_kernel(kenrelstart, kernel_size, &kernel_vaddr, &kernel_paddr); +#ifdef DEBUG_BOOT + log("kernel %lx %lx %lx", kernel_vaddr, kernel_paddr, kernel_size); +#endif + + boot_args_t boot_args; + boot_args.vaddr = kernel_vaddr; + boot_args.paddr = kernel_paddr; + boot_args.kernel_data_size = 0x0; // Sets up later + boot_args.mem_boot_desc = memory_boot_desc_init(multiboot); + boot_args.devtree = NULL; + boot_args.fb_boot_desc.vaddr = 0; // Marking fb as invalid. + memcpy(boot_args.init_process, LAUNCH_SERVER_PATH, sizeof(LAUNCH_SERVER_PATH)); + + bootdesc_paddr = palloc_aligned(sizeof(boot_args), page_size()); + memcpy(bootdesc_paddr, &boot_args, sizeof(boot_args)); + bootdesc_vaddr = paddr_to_vaddr(bootdesc_paddr, kernel_paddr, kernel_vaddr); +#ifdef DEBUG_BOOT + log("copying BOOTDESC %lx -> %lx of %d", &boot_args, bootdesc_vaddr, sizeof(boot_args)); +#endif +} + +int main(uint64_t base, multiboot_info_t* multiboot) +{ + uart_init(); + log_init(uart_write); + alloc_init(base, multiboot); + + extern uint32_t EMBED_KERNEL_START[]; + load_kernel((void*)EMBED_KERNEL_START, multiboot); + vm_setup(base, bootdesc_paddr); + +#ifdef DEBUG_BOOT + log("Preboot done: booting to OS@%llx", ((boot_args_t*)bootdesc_vaddr)->vaddr); +#endif + + ((boot_args_t*)bootdesc_vaddr)->kernel_data_size = ROUND_CEIL(palloc_used_size(), page_size()); + jump_to_kernel((void*)bootdesc_vaddr, ((boot_args_t*)bootdesc_vaddr)->vaddr); + return 0; +} \ No newline at end of file diff --git a/boot/x86_64/prekernel/mboot1.S b/boot/x86_64/prekernel/mboot1.S new file mode 100644 index 0000000..4b6793c --- /dev/null +++ b/boot/x86_64/prekernel/mboot1.S @@ -0,0 +1,299 @@ +MBOOT_PAGE_ALIGN equ 1<<0 +MBOOT_MEM_INFO equ 1<<1 +MBOOT_HEADER_MAGIC equ 0x1badb002 +MBOOT_HEADER_FLAGS equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO +MBOOT_CHECKSUM equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS) + +section .multiboot +dd MBOOT_HEADER_MAGIC +dd MBOOT_HEADER_FLAGS +dd MBOOT_CHECKSUM +dd 0x00000000; header_addr +dd 0x00000000; load_addr +dd 0x00000000; load_end_addr +dd 0x00000000; bss_end_addr +dd 0x00000000; entry_addr +dd 0x00000000; mode_type +dd 0x00000000; width +dd 0x00000000; height +dd 0x00000000; depth + +[bits 32] +section .xos_boot_text + +extern main +extern PREKERNEL_STACK_TOP + +global _start +_start: +global prekernel_entry +prekernel_entry: + cli + cld + + ; Setting up the stack. + mov ebp, PREKERNEL_STACK_TOP + mov esp, ebp + + ; Save entry point to one of callee-saved regs. + mov esi, ecx + + ; PAE is required for x86_64 + call check_for_pae + + ; Checking for long mode. + call check_for_long_mode + + ; x86_64 required paging enabled, thus 1GB of physical memmory is mapped + ; for booting the kernel without any problems. + call setup_tables + + ; Enabling long mode with a 32-bit compatibility submode. + call enable_long_mode + + ; Just give control to jumper. + jmp jump_to_entry64 + +CPUID_FEATURE_PAE equ (1 << 6) +check_for_pae: + push ebp + mov ebp, esp + push ebx + + mov eax, 0x1 + cpuid + test edx, CPUID_FEATURE_PAE + jz pae_unsupported + + pop ebx + pop ebp + ret + +pae_unsupported: + push pae_unsupported_msg + call early_boot_print_string + hlt + +CPUID_FEATURE_LONG_MODE equ (1 << 29) +check_for_long_mode: + push ebp + mov ebp, esp + push ebx + + mov eax, 0x80000001 + cpuid + test edx, CPUID_FEATURE_LONG_MODE + jz long_mode_unsupported + + pop ebx + pop ebp + ret + +long_mode_unsupported: + push long_mode_unsupported_msg + call early_boot_print_string + hlt + + +setup_tables: + push ebp + mov ebp, esp + push edi + + mov edi, table0 + xor eax, eax + mov ecx, 4096 + rep stosb + + mov edi, table1 + xor eax, eax + mov ecx, 4096 + rep stosb + + mov edi, table2 + xor eax, eax + mov ecx, 4096 + rep stosb + + mov eax, table1 + add eax, 0x3 + mov DWORD [table0], eax + + mov eax, table2 + add eax, 0x3 + mov DWORD [table1], eax + + mov edi, table2 + mov eax, 0x83 + mov ecx, 512 +.table_fillup_last: + mov DWORD [edi], eax + add eax, 0x200000 + add edi, 8 + loop .table_fillup_last + + pop edi + pop ebp + ret + + +enable_long_mode: + push ebp + mov ebp, esp + + ; Setting table + mov eax, table0 + mov cr3, eax + + ; Enabling PAE + mov eax, cr4 + or eax, 1 << 5 + mov cr4, eax + + ; Enabling Long Mode + mov ecx, 0xc0000080 + rdmsr + or eax, 1 << 8 + wrmsr + + mov eax, cr0 + or eax, 1 << 31 + mov cr0, eax + + pop ebp + ret + + +VIDEO_MEMORY equ 0xb8000 +WHITE_ON_BLACK equ 0x0f + +global early_boot_print_string +early_boot_print_string: + push ebp + mov ebp, esp + + push esi + push ecx + + mov esi, [ebp+8] + mov ecx, VIDEO_MEMORY + mov ah, WHITE_ON_BLACK + +_print_string_loop: + lodsb; Load from esi to al then increment esi + + test al, al + jz _print_string_end + + mov [ecx], ax + add ecx, 2 + + jmp _print_string_loop + +_print_string_end: + mov eax, esi + sub eax, [ebp+8] + + pop ecx + pop esi + + mov esp, ebp + pop ebp + ret + + +; Access bits +PRESENT equ 1 << 7 +NOT_SYS equ 1 << 4 +EXEC equ 1 << 3 +DC equ 1 << 2 +RW equ 1 << 1 +ACCESSED equ 1 << 0 + +; Flags bits +GRAN_4K equ 1 << 7 +SZ_32 equ 1 << 6 +LONG_MODE equ 1 << 5 + +align 32 +gdt_begin: +gdt_null: + dq 0x0 +gdt_code: + dd 0xffff + db 0x0 + db PRESENT | NOT_SYS | EXEC | RW + db GRAN_4K | LONG_MODE | 0xF + db 0x0 +gdt_data: + dd 0xffff + db 0x0 + db PRESENT | NOT_SYS | RW + db GRAN_4K | SZ_32 | 0xF + db 0x0 +gdt_tss: + dd 0x00000068 + dd 0x00cf8900 +gdt_end: + +gdt_descriptor: + dw gdt_end - gdt_begin - 1 + dd gdt_begin + dd 0x0 + +CODE_SEG equ gdt_code - gdt_begin +DATA_SEG equ gdt_data - gdt_begin + +jump_to_entry64: + lgdt [gdt_descriptor] + jmp CODE_SEG:main_entry64 + +[bits 64] +main_entry64: + cli + mov ax, DATA_SEG + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + mov edi, esi + mov esi, ebx + call main + hlt + + +global set_cr3 +set_cr3: + mov cr3, rdi + ret + + +global jump_to_kernel +jump_to_kernel: + mov rax, cr3 + mov cr3, rax + call rsi + jmp $ + + +pae_unsupported_msg: + db "Required PAE Feature is unavailable, stopping...", 0 + +long_mode_unsupported_msg: + db "Required Long Mode Feature is unavailable, stopping...", 0 + +section .bss + +table0: + align 4096 + resb 4096 + +table1: + align 4096 + resb 4096 + +table2: + align 4096 + resb 4096 diff --git a/boot/x86_64/prekernel/vm.c b/boot/x86_64/prekernel/vm.c new file mode 100644 index 0000000..2fda8de --- /dev/null +++ b/boot/x86_64/prekernel/vm.c @@ -0,0 +1,108 @@ +#include "vm.h" +#include +#include +#include +#include +#include + +// #define DEBUG_VM + +static uint64_t* global_page_table; +static const uint64_t kernel_base = 0xffff800000000000; + +static uint64_t* new_ptable(boot_args_t* args) +{ + uint64_t* res = (uint64_t*)palloc_aligned(page_size(), page_size()); + memset(res, 0, page_size()); +#ifdef DEBUG_VM + log(" alloc ptable %llx %llx", (uint64_t)res, page_size()); +#endif + return res; +} + +static void map4kb_2mb(boot_args_t* args, size_t phyz, size_t virt) +{ + const size_t page_covers = (1ull << PTABLE_LV1_VADDR_OFFSET); + const size_t page_mask = page_covers - 1; + + if ((phyz & page_mask) != 0 || (virt & page_mask) != 0) { + return; + } + + // Mapping from level3. + uint64_t* page_table = global_page_table; + uint64_t ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)]; + if (ptable_desc == 0) { + uint64_t* nptbl = new_ptable(args); + uint64_t pdesc = 0x00000000000003; + pdesc |= (uintptr_t)nptbl; + page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)] = pdesc; + ptable_desc = pdesc; + } + + // Level2 + page_table = (uint64_t*)(((ptable_desc >> 12) << 12) & 0xffffffffffff); + ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)]; + if (ptable_desc == 0) { + uint64_t* nptbl = new_ptable(args); + uint64_t pdesc = 0x00000000000003; + pdesc |= (uintptr_t)nptbl; + page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)] = pdesc; + ptable_desc = pdesc; + } + + page_table = (uint64_t*)(((ptable_desc >> 12) << 12) & 0xffffffffffff); + uint64_t pdesc = 0x0000000000083; + pdesc |= (uintptr_t)phyz; + page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV1_VADDR_OFFSET, VMM_LV1_ENTITY_COUNT)] = pdesc; +} + +// 1Gb huge pages are available as a seperate feature, so use 2Mb pages. +static void map4kb_1gb(boot_args_t* args, size_t phyz, size_t virt) +{ + const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET); + const size_t page_mask = page_covers - 1; + + if ((phyz & page_mask) != 0 || (virt & page_mask) != 0) { + return; + } + + for (int i = 0; i < 512; i++) { + map4kb_2mb(args, phyz, virt); + phyz += (2 << 20); + virt += (2 << 20); + } +} + +void vm_setup(uintptr_t base, boot_args_t* args) +{ + global_page_table = (uint64_t*)palloc_aligned(page_size(), page_size()); + memset(global_page_table, 0, page_size()); + + const size_t map_range_2mb = (2 << 20); + const size_t map_range_1gb = (1 << 30); + + // Mapping kernel vaddr to paddr + size_t kernel_size_to_map = palloc_total_size() + shadow_area_size(); + size_t kernel_range_count_to_map = (kernel_size_to_map + (map_range_2mb - 1)) / map_range_2mb; + for (size_t i = 0; i < kernel_range_count_to_map; i++) { +#ifdef DEBUG_VM + log("mapping %lx %lx", args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb); +#endif + map4kb_2mb(args, args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb); + } + + // Mapping RAM + size_t ram_base = ROUND_FLOOR(args->mem_boot_desc.ram_base, map_range_1gb); + size_t ram_size = args->mem_boot_desc.ram_size; + size_t ram_range_count_to_map = (ram_size + (map_range_1gb - 1)) / map_range_1gb; + for (size_t i = 0; i < ram_range_count_to_map; i++) { +#ifdef DEBUG_VM + log("mapping %lx %lx", ram_base + i * map_range_1gb, ram_base + i * map_range_1gb); +#endif + map4kb_1gb(args, ram_base + i * map_range_1gb, ram_base + i * map_range_1gb); + } + + extern void set_cr3(void* cr); + set_cr3(global_page_table); +} diff --git a/boot/x86_64/prekernel/vm.h b/boot/x86_64/prekernel/vm.h new file mode 100644 index 0000000..a948d5f --- /dev/null +++ b/boot/x86_64/prekernel/vm.h @@ -0,0 +1,24 @@ +#ifndef _BOOT_VM_H +#define _BOOT_VM_H + +#include +#include + +#define VMM_LV0_ENTITY_COUNT (512) +#define VMM_LV1_ENTITY_COUNT (512) +#define VMM_LV2_ENTITY_COUNT (512) +#define VMM_LV3_ENTITY_COUNT (512) + +#define PTABLE_LV_TOP (3) +#define PTABLE_LV0_VADDR_OFFSET (12) +#define PTABLE_LV1_VADDR_OFFSET (21) +#define PTABLE_LV2_VADDR_OFFSET (30) +#define PTABLE_LV3_VADDR_OFFSET (39) + +#define VM_VADDR_OFFSET_AT_LEVEL(vaddr, off, ent) ((vaddr >> off) % ent) + +static size_t page_size() { return 0x1000; } + +void vm_setup(uintptr_t base, boot_args_t* args); + +#endif // _BOOT_VM_H \ No newline at end of file diff --git a/build/boot/BUILD.gn b/build/boot/BUILD.gn new file mode 100644 index 0000000..81f71c5 --- /dev/null +++ b/build/boot/BUILD.gn @@ -0,0 +1,13 @@ +group("boot") { + if (target_arch == "x86") { + deps = [ "x86:bootx86" ] + } else if (target_arch == "x86_64") { + deps = [ "x86_64:bootx86_64" ] + } else if (target_arch == "arm32") { + deps = [ "arm32:bootarm" ] + } else if (target_arch == "arm64") { + deps = [ "arm64:bootarm64" ] + } else if (target_arch == "riscv64") { + deps = [ "riscv64:bootriscv64" ] + } +} diff --git a/build/boot/arm32/BUILD.gn b/build/boot/arm32/BUILD.gn new file mode 100644 index 0000000..2a4b87e --- /dev/null +++ b/build/boot/arm32/BUILD.gn @@ -0,0 +1,111 @@ +boot_c_flags = [ + "-ffreestanding", + "-Werror", + "-Wno-address-of-packed-member", +] +boot_asm_flags = [] +boot_ld_flags = [] + +if (kernel_symbols) { + boot_c_flags += [ "-ggdb" ] +} + +boot_c_flags += [ + "-fno-builtin", + "-march=armv7-a", + "-mfpu=neon-vfpv4", + "-mfloat-abi=soft", + "-fno-pie", +] +boot_asm_flags += [ + "-march=armv7-a", + "-mfpu=neon-vfpv4", + "-mfloat-abi=softfp", + "-mcpu=cortex-a15", +] +boot_ld_flags += [ "-nostdlib" ] + +if (host == "gnu") { + boot_ld_flags += [ + "-nostdinc", + "-nodefaultlibs", + "-nostartfiles", + "-lgcc", + ] +} + +if (host == "llvm") { + boot_ld_flags += [ + "--oformat", + "elf32-littlearm", + "/usr/lib/llvm-18/lib/clang/18/lib/linux/libclang_rt.builtins-arm.a", + ] +} + +config("boot_flags") { + cflags = boot_c_flags + asmflags = boot_asm_flags + ldflags = boot_ld_flags + defines = [ "xOS_kernel" ] +} + +linker_script = + rebase_path("//build/boot/$target_arch/boot_link.ld", root_build_dir) + +# Use a strange __EMPTY_PATH_, empty string can't be passed as an arg. +path_to_bins = "__EMPTY_PATH_" +if (host == "llvm") { + path_to_bins = llvm_bin_path +} + +devtree_compile_script_args = [ + rebase_path("//firmware/$target_arch/$target_board.odt", root_build_dir), + rebase_path("$root_out_dir/firmware/$target_board.obt", root_build_dir), + "$target_arch", + "$target_board", + "$host", + "$path_to_bins", +] + +action("devtree_compile") { + script = "//build/kernel/devtree_compile.py" + inputs = [ "//firmware/$target_arch/$target_board.odt" ] + outputs = [ + "$root_out_dir/firmware/$target_board.obt", + "$root_out_dir/firmware/$target_board.obto", + ] + args = devtree_compile_script_args +} + +executable("bootarm") { + deps = [ ":devtree_compile" ] + output_name = "bootarm.bin" + sources = [ + "//boot/arm32/drivers/pl181.c", + "//boot/arm32/drivers/uart.c", + "//boot/arm32/entry.s", + "//boot/arm32/hw/ram.c", + "//boot/arm32/main.c", + "//boot/arm32/start_kernel.s", + "//boot/arm32/vmm/vmm.c", + "//boot/libboot/crypto/sha256.c", + "//boot/libboot/crypto/signature.c", + "//boot/libboot/crypto/uint2048.c", + "//boot/libboot/crypto/validate.c", + "//boot/libboot/devtree/devtree.c", + "//boot/libboot/elf/elf_lite.c", + "//boot/libboot/fs/ext2_lite.c", + "//boot/libboot/log/log.c", + "//boot/libboot/mem/alloc.c", + "//boot/libboot/mem/mem.c", + ] + + include_dirs = [ "//boot" ] + + configs = [ ":boot_flags" ] + + ldflags = [ + rebase_path("$root_out_dir/firmware/$target_board.obto", root_build_dir), + "-T$linker_script", + ] +} diff --git a/build/boot/arm32/boot_link.ld b/build/boot/arm32/boot_link.ld new file mode 100644 index 0000000..eccfbeb --- /dev/null +++ b/build/boot/arm32/boot_link.ld @@ -0,0 +1,55 @@ +_pa_base = 0x80010000; + +ENTRY(_pa_base) + +SECTIONS +{ + . = _pa_base; + bootloader_start = .; + + .text ALIGN(4K) : + { + *(.xos_boot_text) + *(.text) + *(.text.*) + } + + .rodata ALIGN(4K) : + { + *(.rodata) + *(.rodata.*) + } + + .rodata.odt ALIGN(4K) : + { + _odt_phys = .; + *(.odt) + _odt_phys_end = .; + } + + .data ALIGN(4K) : + { + *(.data) + *(.data.*) + } + + .bss ALIGN(4K) : + { + *(.bss) + *(.bss.*) + *(COMMON) + } + + .stack ALIGN(4K) : + { + STACK_SECONDARY_PHYZ_BASE = .; + . += 0x1000; + STACK_SECONDARY_PHYZ_TOP = .; + + STACK_PHYZ_BASE = .; + . += 0x1000; + STACK_PHYZ_TOP = .; + } + + .ARM.exidx : { *(.ARM.exidx) } +} \ No newline at end of file diff --git a/build/boot/arm64/BUILD.gn b/build/boot/arm64/BUILD.gn new file mode 100644 index 0000000..43851e4 --- /dev/null +++ b/build/boot/arm64/BUILD.gn @@ -0,0 +1,31 @@ +# Use a strange __EMPTY_PATH_, empty string can't be passed as an arg. +path_to_bins = "__EMPTY_PATH_" +if (host == "llvm") { + path_to_bins = llvm_bin_path +} + +devtree_compile_script_args = [ + rebase_path("//firmware/$target_arch/$target_board.odt", root_build_dir), + rebase_path("$root_out_dir/firmware/$target_board.obt", root_build_dir), + "$target_arch", + "$target_board", + "$host", + "$path_to_bins", +] + +action("devtree_compile") { + script = "//build/kernel/devtree_compile.py" + inputs = [ "//firmware/$target_arch/$target_board.odt" ] + outputs = [ + "$root_out_dir/firmware/$target_board.obt", + "$root_out_dir/firmware/$target_board.obto", + ] + args = devtree_compile_script_args +} + +group("bootarm64") { + deps = [ + ":devtree_compile", + "rawImage:rawImage", + ] +} diff --git a/build/boot/arm64/prekernel/BUILD.gn b/build/boot/arm64/prekernel/BUILD.gn new file mode 100644 index 0000000..083a1e0 --- /dev/null +++ b/build/boot/arm64/prekernel/BUILD.gn @@ -0,0 +1,63 @@ +prekernel_c_flags = [ + "-ffreestanding", + "-Werror", + "-Wno-address-of-packed-member", + "-fno-builtin", + "-mcpu=cortex-a53+nofp+nosimd+nocrypto+nocrc", + "-fpie", +] +prekernel_asm_flags = [ "-mcpu=cortex-a53+nofp+nosimd+nocrypto+nocrc" ] +prekernel_ld_flags = [ "-nostdlib" ] + +if (kernel_symbols) { + prekernel_c_flags += [ "-ggdb" ] +} + +if (host == "gnu") { + prekernel_ld_flags += [ + "-nostdinc", + "-nodefaultlibs", + "-nostartfiles", + "-lgcc", + ] +} + +if (host == "llvm") { + prekernel_ld_flags += [ + "--oformat", + "binary", + ] +} + +config("prekernel_flags") { + cflags = prekernel_c_flags + asmflags = prekernel_asm_flags + ldflags = prekernel_ld_flags + defines = [ "xOS_prekernel" ] +} + +linker_script = + rebase_path("//build/boot/$target_arch/prekernel/prekernel_link.ld", + root_build_dir) + +executable("prekernelarm64") { + output_name = "prekernelarm64.bin" + sources = [ + "//boot/arm64/prekernel/drivers/fb.c", + "//boot/arm64/prekernel/drivers/uart.c", + "//boot/arm64/prekernel/entry.S", + "//boot/arm64/prekernel/main.c", + "//boot/arm64/prekernel/vm.c", + "//boot/libboot/devtree/devtree.c", + "//boot/libboot/elf/elf_lite.c", + "//boot/libboot/log/log.c", + "//boot/libboot/mem/alloc.c", + "//boot/libboot/mem/mem.c", + ] + + include_dirs = [ "//boot" ] + + configs = [ ":prekernel_flags" ] + + ldflags = [ "-T$linker_script" ] +} diff --git a/build/boot/arm64/prekernel/prekernel_link.ld b/build/boot/arm64/prekernel/prekernel_link.ld new file mode 100644 index 0000000..28afa4d --- /dev/null +++ b/build/boot/arm64/prekernel/prekernel_link.ld @@ -0,0 +1,45 @@ +/* PIC */ +_pa_base = 0x0; + +ENTRY(_pa_base) + +SECTIONS +{ + . = _pa_base; + PREKERNEL_START_OFFSET = .; + + .text : + { + *(.xos_boot_text) + *(.text) + *(.text.*) + } + + .rodata : + { + *(.rodata) + *(.rodata.*) + } + + .data : + { + *(.data) + *(.data.*) + } + + .bss : + { + *(.bss) + *(.bss.*) + *(COMMON) + } + + .stack ALIGN(4K) : + { + PREKERNEL_STACK_BASE_OFFSET = .; + . += 0x1000; + PREKERNEL_STACK_TOP_OFFSET = .; + } + + PREKERNEL_END_OFFSET = .; +} \ No newline at end of file diff --git a/build/boot/arm64/rawImage/BUILD.gn b/build/boot/arm64/rawImage/BUILD.gn new file mode 100644 index 0000000..7795d78 --- /dev/null +++ b/build/boot/arm64/rawImage/BUILD.gn @@ -0,0 +1,22 @@ +if (target_arch == "arm64") { + action("rawImage") { + script = "make_raw_image.py" + sources = [ + "$root_build_dir/base/boot/kernel.bin", + "$root_build_dir/prekernelarm64.bin", + ] + outputs = [ "$root_build_dir/rawImage.bin" ] + args = [ + rebase_path("$root_build_dir/prekernelarm64.bin", root_build_dir), + rebase_path("$root_build_dir/base/boot/kernel.bin", root_build_dir), + rebase_path("$root_out_dir/firmware/$target_board.obt", root_build_dir), + rebase_path("$root_build_dir/rawImage.bin", root_build_dir), + ] + + deps = [ + "//build/boot/arm64:devtree_compile", + "//build/boot/arm64/prekernel:prekernelarm64", + "//build/kernel:kernel_build", + ] + } +} diff --git a/build/boot/arm64/rawImage/make_raw_image.py b/build/boot/arm64/rawImage/make_raw_image.py new file mode 100644 index 0000000..7d54f4c --- /dev/null +++ b/build/boot/arm64/rawImage/make_raw_image.py @@ -0,0 +1,77 @@ +import sys +import os +import subprocess +from construct import * +from elftools.elf.elffile import ELFFile +from elftools.elf.constants import SH_FLAGS + +prekernel_path = sys.argv[1] +kernel_path = sys.argv[2] +devtree_path = sys.argv[3] +out_path = sys.argv[4] +build_dir_path = os.path.dirname(os.path.abspath(sys.argv[4])) +tmp_dir_path = build_dir_path + "/tmp" +rawimage_header_path = tmp_dir_path + "/rawimage_header.bin" + +# GNU-LD can't convert ELF object format to Binary on the fly. +# Checking if output is an ELF and convertining it to binary. +prekernel_header = [] +with open(prekernel_path, "rb") as f: + prekernel_header = f.read(4) + +if prekernel_header == b'\x7fELF': + kernel_vaddr = 0 + kernel_vaddr_end = 0 + + with open(prekernel_path, 'rb') as elffile: + signature_section = None + for section in ELFFile(elffile).iter_sections(): + if (section['sh_flags'] & SH_FLAGS.SHF_ALLOC) == SH_FLAGS.SHF_ALLOC: + kernel_vaddr_end = max( + kernel_vaddr_end, section['sh_addr'] + section['sh_size']) + + output = subprocess.check_output( + "aarch64-elf-objcopy -O binary {0} {0}".format(prekernel_path), shell=True) + binary_blob_size = os.path.getsize(prekernel_path) + assert(binary_blob_size <= kernel_vaddr_end) + + need_to_append = kernel_vaddr_end - binary_blob_size + with open(prekernel_path, 'r+b') as file: + _ = file.read() + padding = [0x0 for _ in range(need_to_append)] + file.write(bytearray(padding)) + + +prekernel_size = os.path.getsize(prekernel_path) +rawimage_header_size = 8 * 8 +kernel_size = os.path.getsize(kernel_path) +devtree_size = os.path.getsize(devtree_path) +ramdisk_size = 0 + +result = { + "kern_off": rawimage_header_size + prekernel_size, + "kern_size": kernel_size, + "devtree_off": rawimage_header_size + prekernel_size + kernel_size, + "devtree_size": devtree_size, + "ramdisk_off": 0, + "ramdisk_size": 0, + "rawimage_size": rawimage_header_size + prekernel_size + kernel_size + devtree_size + ramdisk_size, + "padding": 0, +} + +rawimage_header = Struct( + "kern_off" / Int64ul, + "kern_size" / Int64ul, + "devtree_off" / Int64ul, + "devtree_size" / Int64ul, + "ramdisk_off" / Int64ul, + "ramdisk_size" / Int64ul, + "rawimage_size" / Int64ul, + "padding" / Int64ul, +).build(result) + +with open(rawimage_header_path, "wb") as binfile: + binfile.write(bytes(rawimage_header)) + +output = subprocess.check_output("cat {0} {1} {2} {3} > {4}".format( + prekernel_path, rawimage_header_path, kernel_path, devtree_path, out_path), shell=True) diff --git a/build/boot/riscv64/BUILD.gn b/build/boot/riscv64/BUILD.gn new file mode 100644 index 0000000..d521731 --- /dev/null +++ b/build/boot/riscv64/BUILD.gn @@ -0,0 +1,5 @@ +group("bootriscv64") { + deps = [ + "prekernel:prekernelriscv64", + ] +} diff --git a/build/boot/riscv64/prekernel/BUILD.gn b/build/boot/riscv64/prekernel/BUILD.gn new file mode 100644 index 0000000..56f99f3 --- /dev/null +++ b/build/boot/riscv64/prekernel/BUILD.gn @@ -0,0 +1,125 @@ +prekernel_c_flags = [ + "-ffreestanding", + "-Werror", + "-Wno-address-of-packed-member", + "-fno-builtin", + "-march=rv64ima", + "-mabi=lp64", + "-fpie", + "-mcmodel=medany", +] +prekernel_asm_flags = [ + "-mcmodel=medany", + "-march=rv64ima", + "-mabi=lp64", +] +prekernel_ld_flags = [ "-nostdlib" ] + +if (kernel_symbols) { + prekernel_c_flags += [ "-ggdb" ] +} + +if (host == "gnu") { + prekernel_ld_flags += [ + # "-mno-relax", + "-nostdinc", + "-nodefaultlibs", + "-nostartfiles", + "-lgcc", + ] +} + +if (host == "llvm") { + prekernel_ld_flags += [ + "--oformat", + "elf64", + ] +} + +config("prekernel_flags") { + cflags = prekernel_c_flags + asmflags = prekernel_asm_flags + ldflags = prekernel_ld_flags + defines = [ "xOS_prekernel" ] +} + +linker_script = + rebase_path("//build/boot/$target_arch/prekernel/prekernel_link.ld", + root_build_dir) + +# Use a strange __EMPTY_PATH_, empty string can't be passed as an arg. +path_to_bins = "__EMPTY_PATH_" +if (host == "llvm") { + path_to_bins = llvm_bin_path +} + +devtree_compile_script_args = [ + rebase_path("//firmware/$target_arch/$target_board.odt", root_build_dir), + rebase_path("$root_out_dir/firmware/$target_board.obt", root_build_dir), + "$target_arch", + "$target_board", + "$host", + "$path_to_bins", +] + +action("devtree_compile") { + script = "//build/kernel/devtree_compile.py" + inputs = [ "//firmware/$target_arch/$target_board.odt" ] + outputs = [ + "$root_out_dir/firmware/$target_board.obt", + "$root_out_dir/firmware/$target_board.obto", + ] + args = devtree_compile_script_args +} + +embed_kernel_script_args = [ + rebase_path("$root_build_dir/base/boot/kernel.bin", root_build_dir), + rebase_path("$root_build_dir/tmp/boot/kernel.o", root_build_dir), + "$target_arch", + "$target_board", + "$host", + "$path_to_bins", +] + +action("embed_kernel") { + script = "embed_kernel.py" + sources = [ "$root_build_dir/base/boot/kernel.bin" ] + outputs = [ "$root_build_dir/tmp/boot/kernel.o" ] + args = embed_kernel_script_args + deps = [ "//build/kernel:kernel_build" ] +} + +executable("prekernelriscv64") { + output_name = "prekernelriscv64.bin" + sources = [ + "//boot/libboot/devtree/devtree.c", + "//boot/libboot/elf/elf_lite.c", + "//boot/libboot/log/log.c", + "//boot/libboot/mem/alloc.c", + "//boot/libboot/mem/mem.c", + "//boot/riscv64/prekernel/drivers/uart.c", + "//boot/riscv64/prekernel/entry.S", + "//boot/riscv64/prekernel/main.c", + "//boot/riscv64/prekernel/vm.c", + ] + + include_dirs = [ "//boot" ] + + inputs = [ + "$root_out_dir/firmware/$target_board.obto", + "$root_out_dir/tmp/boot/kernel.o", + ] + deps = [ + ":devtree_compile", + ":embed_kernel", + ] + + configs = [ ":prekernel_flags" ] + + ldflags = [ + # Embeding kernel elf file into rawimage. + rebase_path("$root_out_dir/firmware/$target_board.obto", ""), + rebase_path("$root_out_dir/tmp/boot/kernel.o", ""), + "-T$linker_script", + ] +} diff --git a/build/boot/riscv64/prekernel/embed_kernel.py b/build/boot/riscv64/prekernel/embed_kernel.py new file mode 100644 index 0000000..ebf18d1 --- /dev/null +++ b/build/boot/riscv64/prekernel/embed_kernel.py @@ -0,0 +1,30 @@ +import sys +import os +import subprocess + +prekernel_path = sys.argv[1] +out_path = sys.argv[2] +arch = sys.argv[3] +board = sys.argv[4] +host = sys.argv[5] +path_to_bins = sys.argv[6] + +if path_to_bins == "__EMPTY_PATH_": + path_to_bins = "" +if len(path_to_bins) != 0: + if path_to_bins[-1] != '/': + path_to_bins += "/" + +if host == "gnu": + OBJCOPY_TOOL = "{0}riscv64-unknown-elf-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-littleriscv" +elif host == "llvm": + OBJCOPY_TOOL = "{0}llvm-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-littleriscv" +else: + print("Unsupported host {0}".format(host)) + exit(0) + +cmd = "{0} -I binary -O {1} --rename-section .data=.kernelelf {2} {3}".format( + OBJCOPY_TOOL, OBJCOPY_TARGET, prekernel_path, out_path) +output = subprocess.check_output(cmd, shell=True) diff --git a/build/boot/riscv64/prekernel/prekernel_link.ld b/build/boot/riscv64/prekernel/prekernel_link.ld new file mode 100644 index 0000000..353c955 --- /dev/null +++ b/build/boot/riscv64/prekernel/prekernel_link.ld @@ -0,0 +1,72 @@ +_pa_base = 0x80000000; + +ENTRY(_pa_base) + +SECTIONS +{ + . = _pa_base; + PREKERNEL_START_OFFSET = .; + + .text : + { + *(.xos_boot_text) + *(.text) + *(.text.*) + } + + .rodata : + { + *(.rodata) + *(.rodata.*) + } + + .data : + { + *(.data) + *(.data.*) + } + + .bss : + { + *(.bss) + *(.bss.*) + *(COMMON) + } + + .rela.text : + { + *(.rela.text) + } + + .rela.bss : + { + *(.rela.bss) + } + + .stack ALIGN(4K) : + { + PREKERNEL_STACK_BASE_OFFSET = .; + . += 0x1000; + PREKERNEL_STACK_TOP_OFFSET = .; + } + + PREKERNEL_END_OFFSET = .; + + .devtree ALIGN(4K) : + { + EMBED_DEVTREE_START = .; + *(.odt) + EMBED_DEVTREE_END = .; + } + + DEVTREE_END = .; + + .kernelelf ALIGN(4K) : + { + EMBED_KERNEL_START = .; + *(.kernelelf) + EMBED_KERNEL_END = .; + } + + RAWIMAGE_END = .; +} \ No newline at end of file diff --git a/build/boot/x86/BUILD.gn b/build/boot/x86/BUILD.gn new file mode 100644 index 0000000..a61cb82 --- /dev/null +++ b/build/boot/x86/BUILD.gn @@ -0,0 +1,20 @@ +if (target_arch == "x86") { + action("bootx86") { + script = "make_boot_drive.py" + sources = [ + "$root_build_dir/stage1.bin", + "$root_build_dir/stage2.bin", + ] + outputs = [ "$root_build_dir/os-image.bin" ] + args = [ + rebase_path("$root_build_dir/stage1.bin", root_build_dir), + rebase_path("$root_build_dir/stage2.bin", root_build_dir), + rebase_path("$root_build_dir/os-image.bin", root_build_dir), + ] + + deps = [ + "stage1:stage1", + "stage2:stage2", + ] + } +} \ No newline at end of file diff --git a/build/boot/x86/boot_link.ld b/build/boot/x86/boot_link.ld new file mode 100644 index 0000000..a04f949 --- /dev/null +++ b/build/boot/x86/boot_link.ld @@ -0,0 +1,42 @@ +_pa_base = 0x1000; + +ENTRY(_pa_base) + +SECTIONS +{ + . = _pa_base; + bootloader_start = .; + + .text ALIGN(4K) : + { + *(.xos_boot_text) + *(.text) + *(.text.*) + } + + .rodata : + { + *(.rodata) + *(.rodata.*) + } + + .data : + { + *(.data) + *(.data.*) + } + + .bss : + { + *(.bss) + *(.bss.*) + *(COMMON) + } + + .stack ALIGN(4K) : + { + STACK_PHYZ_BASE = .; + . += 0x1000; + STACK_PHYZ_TOP = .; + } +} \ No newline at end of file diff --git a/build/boot/x86/make_boot_drive.py b/build/boot/x86/make_boot_drive.py new file mode 100644 index 0000000..e8495d4 --- /dev/null +++ b/build/boot/x86/make_boot_drive.py @@ -0,0 +1,7 @@ +import sys +inf = sys.argv[1] +outf = sys.argv[2] +reli = sys.argv[3] + +import subprocess +output = subprocess.check_output("cat {0} {1} > {2}".format(inf, outf, reli), shell=True) \ No newline at end of file diff --git a/build/boot/x86/stage1/BUILD.gn b/build/boot/x86/stage1/BUILD.gn new file mode 100644 index 0000000..8b5936f --- /dev/null +++ b/build/boot/x86/stage1/BUILD.gn @@ -0,0 +1,21 @@ +action("stage1") { + script = "compile_stage1.py" + sources = [ "//boot/x86/stage1/boot.s" ] + outputs = [ "$root_build_dir/stage1.bin" ] + + inputs = [ + "//boot/x86/stage1/boot.s", + "//boot/x86/stage1/utils16/disk_load.s", + "//boot/x86/stage1/utils16/print.s", + "//boot/x86/stage1/utils16/smm.s", + "//boot/x86/stage1/utils16/switch_to_pm.s", + "//boot/x86/stage1/utils32/gdt.s", + "//boot/x86/stage1/utils32/print.s", + ] + + args = [ + rebase_path("//boot/x86/stage1/boot.s", root_build_dir), + rebase_path(root_build_dir, root_build_dir), + rebase_path("//", root_build_dir), + ] +} diff --git a/build/boot/x86/stage1/compile_stage1.py b/build/boot/x86/stage1/compile_stage1.py new file mode 100644 index 0000000..8487934 --- /dev/null +++ b/build/boot/x86/stage1/compile_stage1.py @@ -0,0 +1,7 @@ +import sys +inf = sys.argv[1] +outf = sys.argv[2] +reli = sys.argv[3] + +import subprocess +output = subprocess.check_output("nasm {0} -f bin -i {2} -o {1}/stage1.bin".format(inf, outf, reli), shell=True) \ No newline at end of file diff --git a/build/boot/x86/stage2/BUILD.gn b/build/boot/x86/stage2/BUILD.gn new file mode 100644 index 0000000..3524557 --- /dev/null +++ b/build/boot/x86/stage2/BUILD.gn @@ -0,0 +1,48 @@ +linker_script = + rebase_path("//build/boot/$target_arch/boot_link.ld", root_build_dir) + +executable("stage2") { + output_name = "stage2.bin" + sources = [ + "//boot/libboot/crypto/sha256.c", + "//boot/libboot/crypto/signature.c", + "//boot/libboot/crypto/uint2048.c", + "//boot/libboot/crypto/validate.c", + "//boot/libboot/devtree/devtree.c", + "//boot/libboot/elf/elf_lite.c", + "//boot/libboot/fs/ext2_lite.c", + "//boot/libboot/log/log.c", + "//boot/libboot/mem/alloc.c", + "//boot/libboot/mem/mem.c", + "//boot/x86/stage2/drivers/ata.c", + "//boot/x86/stage2/drivers/port.c", + "//boot/x86/stage2/drivers/uart.c", + "//boot/x86/stage2/mem/vm.c", + "//boot/x86/stage2/stage2.c", + "//boot/x86/stage2/stage2_entry.s", + ] + + include_dirs = [ "//boot" ] + + ldflags = [ + "-T$linker_script", + "--oformat", + "binary", + "-Map=stage2.map", + ] + + cflags = [ + "-ffreestanding", + "-Werror", + "-Wno-address-of-packed-member", + "-mno-80387", + "-mno-mmx", + "-mno-sse", + "-mno-sse2", + ] + + asmflags = [ + "-f", + "elf", + ] +} diff --git a/build/boot/x86_64/BUILD.gn b/build/boot/x86_64/BUILD.gn new file mode 100644 index 0000000..5eb566d --- /dev/null +++ b/build/boot/x86_64/BUILD.gn @@ -0,0 +1,5 @@ +group("bootx86_64") { + deps = [ + "rawImage:rawImage", + ] +} diff --git a/build/boot/x86_64/prekernel/BUILD.gn b/build/boot/x86_64/prekernel/BUILD.gn new file mode 100644 index 0000000..3e7a1d3 --- /dev/null +++ b/build/boot/x86_64/prekernel/BUILD.gn @@ -0,0 +1,92 @@ +prekernel_c_flags = [ + "-ffreestanding", + "-Werror", + "-Wno-address-of-packed-member", + "-fno-builtin", + "-mno-80387", + "-mno-mmx", + "-mno-sse", + "-mno-sse2", + "-fpie", + "-mno-red-zone", + "-fno-omit-frame-pointer", +] +prekernel_asm_flags = [ + "-w+all", + "-Werror", + "-f", + "elf64", +] +prekernel_ld_flags = [ "-nostdlib" ] + +if (kernel_symbols) { + prekernel_c_flags += [ "-ggdb" ] +} + +if (host == "llvm") { + prekernel_ld_flags += [ + "--oformat", + "elf64", + ] +} + +config("prekernel_flags") { + cflags = prekernel_c_flags + asmflags = prekernel_asm_flags + ldflags = prekernel_ld_flags + defines = [ "xOS_prekernel" ] +} + +linker_script = + rebase_path("//build/boot/$target_arch/prekernel/prekernel_link.ld", + root_build_dir) + +# Use a strange __EMPTY_PATH_, empty string can't be passed as an arg. +path_to_bins = "__EMPTY_PATH_" +if (host == "llvm") { + path_to_bins = llvm_bin_path +} + +embed_kernel_script_args = [ + rebase_path("$root_build_dir/base/boot/kernel.bin", root_build_dir), + rebase_path("$root_build_dir/tmp/boot/kernel.o", root_build_dir), + "$target_arch", + "$target_board", + "$host", + "$path_to_bins", +] + +action("embed_kernel") { + script = "embed_kernel.py" + sources = [ "$root_build_dir/base/boot/kernel.bin" ] + outputs = [ "$root_build_dir/tmp/boot/kernel.o" ] + args = embed_kernel_script_args + deps = [ "//build/kernel:kernel_build" ] +} + +executable("prekernelx86_64") { + output_name = "prekernelx86_64.bin" + inputs = [ "$root_build_dir/tmp/boot/kernel.o" ] + sources = [ + "//boot/libboot/elf/elf_lite.c", + "//boot/libboot/log/log.c", + "//boot/libboot/mem/alloc.c", + "//boot/libboot/mem/mem.c", + "//boot/x86_64/prekernel/drivers/uart.c", + "//boot/x86_64/prekernel/main.c", + "//boot/x86_64/prekernel/mboot1.S", + "//boot/x86_64/prekernel/vm.c", + ] + + deps = [ ":embed_kernel" ] + + include_dirs = [ "//boot" ] + + configs = [ ":prekernel_flags" ] + + ldflags = [ + # Embeding kernel elf file into rawimage. + rebase_path("$root_out_dir/tmp/boot/kernel.o", ""), + "-T$linker_script", + ] +} diff --git a/build/boot/x86_64/prekernel/embed_kernel.py b/build/boot/x86_64/prekernel/embed_kernel.py new file mode 100644 index 0000000..547f98b --- /dev/null +++ b/build/boot/x86_64/prekernel/embed_kernel.py @@ -0,0 +1,30 @@ +import sys +import os +import subprocess + +prekernel_path = sys.argv[1] +out_path = sys.argv[2] +arch = sys.argv[3] +board = sys.argv[4] +host = sys.argv[5] +path_to_bins = sys.argv[6] + +if path_to_bins == "__EMPTY_PATH_": + path_to_bins = "" +if len(path_to_bins) != 0: + if path_to_bins[-1] != '/': + path_to_bins += "/" + +if host == "gnu": + OBJCOPY_TOOL = "{0}x86_64-elf-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-x86-64" +elif host == "llvm": + OBJCOPY_TOOL = "{0}llvm-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-x86-64" +else: + print("Unsupported host {0}".format(host)) + exit(0) + +cmd = "{0} -I binary -O {1} --rename-section .data=.kernelelf {2} {3}".format( + OBJCOPY_TOOL, OBJCOPY_TARGET, prekernel_path, out_path) +output = subprocess.check_output(cmd, shell=True) diff --git a/build/boot/x86_64/prekernel/prekernel_link.ld b/build/boot/x86_64/prekernel/prekernel_link.ld new file mode 100644 index 0000000..17fc89b --- /dev/null +++ b/build/boot/x86_64/prekernel/prekernel_link.ld @@ -0,0 +1,59 @@ +/* PIC */ +_pa_base = 1M; + +/* ENTRY(_pa_base) */ + +SECTIONS +{ + . = _pa_base; + PREKERNEL_START = .; + + .multiboot : + { + *(.multiboot) + } + + .text : + { + *(.xos_boot_text) + *(.text) + *(.text.*) + } + + .rodata : + { + *(.rodata) + *(.rodata.*) + } + + .data : + { + *(.data) + *(.data.*) + } + + .bss : + { + *(.bss) + *(.bss.*) + *(COMMON) + } + + .stack ALIGN(4K) : + { + PREKERNEL_STACK_BASE = .; + . += 0x1000; + PREKERNEL_STACK_TOP = .; + } + + PREKERNEL_END = .; + + .kernelelf ALIGN(4K) : + { + EMBED_KERNEL_START = .; + *(.kernelelf) + EMBED_KERNEL_END = .; + } + + RAWIMAGE_END = .; +} \ No newline at end of file diff --git a/build/boot/x86_64/rawImage/BUILD.gn b/build/boot/x86_64/rawImage/BUILD.gn new file mode 100644 index 0000000..ff794a9 --- /dev/null +++ b/build/boot/x86_64/rawImage/BUILD.gn @@ -0,0 +1,23 @@ +if (target_arch == "x86_64") { + path_to_bins = "__EMPTY_PATH_" + if (host == "llvm") { + path_to_bins = llvm_bin_path + } + + make_raw_image_script_args = [ + rebase_path("$root_build_dir/prekernelx86_64.bin", root_build_dir), + rebase_path("$root_build_dir/rawImage.elf", root_build_dir), + "$target_arch", + "$target_board", + "$host", + "$path_to_bins", + ] + + action("rawImage") { + script = "make_raw_image.py" + sources = [ "$root_build_dir/prekernelx86_64.bin" ] + outputs = [ "$root_build_dir/rawImage.elf" ] + args = make_raw_image_script_args + deps = [ "//build/boot/x86_64/prekernel:prekernelx86_64" ] + } +} diff --git a/build/boot/x86_64/rawImage/make_raw_image.py b/build/boot/x86_64/rawImage/make_raw_image.py new file mode 100644 index 0000000..61b4d47 --- /dev/null +++ b/build/boot/x86_64/rawImage/make_raw_image.py @@ -0,0 +1,30 @@ +import sys +import os +import subprocess + +prekernel_path = sys.argv[1] +out_path = sys.argv[2] +arch = sys.argv[3] +board = sys.argv[4] +host = sys.argv[5] +path_to_bins = sys.argv[6] + +if path_to_bins == "__EMPTY_PATH_": + path_to_bins = "" +if len(path_to_bins) != 0: + if path_to_bins[-1] != '/': + path_to_bins += "/" + +if host == "gnu": + OBJCOPY_TOOL = "{0}x86_64-elf-objcopy".format(path_to_bins) +elif host == "llvm": + OBJCOPY_TOOL = "{0}llvm-objcopy".format(path_to_bins) +else: + print("Unsupported host {0}".format(host)) + exit(0) + +# rawImage for x86 is a multiboot-capable elf file. Since qemu does not +# implement support for multiboot2 specs, which could load elf64, we have +# to change the type of the elf file to elf32-i686. +output = subprocess.check_output( + "{0} -O elf32-i386 {1} {2}".format(OBJCOPY_TOOL, prekernel_path, out_path), shell=True) diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn new file mode 100644 index 0000000..530be35 --- /dev/null +++ b/build/config/BUILDCONFIG.gn @@ -0,0 +1,70 @@ +declare_args() { + # Common + debug_build = true + optimize = true + host = "gnu" + llvm_bin_path = "" + device_type = "desktop" + target_arch = "" + target_board = "" + + # Kernel Flags + kernel_symbols = true + kernel_preempt = true + + # Userland + userland_symbols = true + compile_tests = true + objc_support = false + test_method = "none" +} + +if (target_arch == "") { + # target_cpu is deprecated, but not fully deleted. + if (target_cpu != "") { + target_arch = target_cpu + } else { + target_arch = "x86" + } +} +if (target_arch == "arm") { + target_arch = "arm32" +} +if (target_arch == "aarch64") { + target_arch = "arm64" +} +if (device_type == "m") { + device_type = "mobile" +} +if (device_type == "d") { + device_type = "desktop" +} + +if (target_arch == "x86") { + target_board = "i386" +} +if (target_arch == "x86_64") { + target_board = "x86_64" +} +if (target_arch == "arm32") { + # Currently we support only vexpress-a15. + target_board = "vexpress-a15" +} +if (target_arch == "arm64") { + if (target_board == "") { + target_board = "qemu_virt" + } +} +if (target_arch == "riscv64") { + target_board = "riscv64" +} + +if (host == "gnu") { + set_default_toolchain("//toolchains:gnu-cross-compiler") +} + +if (host == "llvm") { + objc_support = true + llvm_bin_path = getenv("LLVM_BIN_PATH") + set_default_toolchain("//toolchains:llvm-cross-compiler") +} diff --git a/build/kernel/BUILD.gn b/build/kernel/BUILD.gn new file mode 100644 index 0000000..30a04f0 --- /dev/null +++ b/build/kernel/BUILD.gn @@ -0,0 +1,257 @@ +import("//build/security/SIGN_TEMPLATE.gni") + +kernel_out_path = "base/boot" + +kernel_c_flags = [ + "-std=gnu11", + "-ffreestanding", + "-Werror", + "-Wno-address-of-packed-member", + "-fpie", +] +kernel_asm_flags = [] +kernel_ld_flags = [] + +if (debug_build) { + kernel_c_flags += [ "-DDEBUG_KERNEL" ] +} + +if (kernel_symbols) { + kernel_c_flags += [ "-ggdb" ] +} + +if (optimize) { + kernel_c_flags += [ "-Os" ] + if (host == "llvm") { + kernel_c_flags += [ "-flto" ] + + if (target_arch == "x86_64") { + kernel_c_flags += [ + "-mllvm", + "-code-model=large", + ] + } + } +} + +if (target_arch == "x86" && kernel_preempt) { + kernel_c_flags += [ "-DPREEMPT_KERNEL" ] +} + +if (device_type == "desktop") { + kernel_c_flags += [ "-DTARGET_DESKTOP" ] +} +if (device_type == "mobile") { + kernel_c_flags += [ "-DTARGET_MOBILE" ] +} + +if (target_arch == "x86") { + kernel_c_flags += [ + "-mno-80387", + "-mno-mmx", + "-mno-sse", + "-mno-sse2", + ] + kernel_asm_flags += [ + "-w+all", + "-Werror", + "-f", + "elf", + ] + kernel_ld_flags += [ + "--oformat", + "elf32-i386", + ] +} + +if (target_arch == "x86_64") { + kernel_c_flags += [ + "-mno-80387", + "-mno-mmx", + "-mno-sse", + "-mno-sse2", + "-mno-red-zone", + "-fno-omit-frame-pointer", + "-mcmodel=large", + ] + kernel_asm_flags += [ + "-w+all", + "-Werror", + "-f", + "elf64", + ] + if (host == "llvm") { + kernel_ld_flags += [ + "--oformat", + "elf64", + ] + } +} + +if (target_arch == "arm32") { + kernel_c_flags += [ + "-fno-builtin", + "-march=armv7-a", + "-mfpu=neon-vfpv4", + "-mfloat-abi=soft", + ] + kernel_asm_flags += [ + "-march=armv7-a", + "-mfpu=neon-vfpv4", + "-mfloat-abi=softfp", + "-mcpu=cortex-a15", + ] + kernel_ld_flags += [ "-nostdlib" ] + + if (host == "gnu") { + kernel_ld_flags += [ + "-nostdinc", + "-nodefaultlibs", + "-nostartfiles", + "-lgcc", + ] + } + + if (host == "llvm") { + kernel_ld_flags += [ + "--oformat", + "elf32-littlearm", + rebase_path("//toolchains/llvm_runtime/11.1.0/libclang_rt.builtins-arm.a", + root_build_dir), + ] + } +} + +if (target_arch == "arm64") { + kernel_c_flags += [ + "-fno-builtin", + "-mcpu=cortex-a53+nofp+nosimd+nocrypto+nocrc", + ] + kernel_asm_flags += [ "-mcpu=cortex-a53+nofp+nosimd+nocrypto+nocrc" ] + kernel_ld_flags += [ "-nostdlib" ] + + if (host == "gnu") { + kernel_ld_flags += [ + "-nostdinc", + "-nodefaultlibs", + "-nostartfiles", + "-lgcc", + ] + } + + if (host == "llvm") { + kernel_ld_flags += [ + "--oformat", + "elf64-littlearm", + ] + } + + # Qemu virt is used as a test platform. + if (target_board == "qemu_virt") { + kernel_c_flags += [ "-DTARGET_QEMU_VIRT" ] + kernel_asm_flags += [ "-DTARGET_QEMU_VIRT" ] + } + if (target_board == "apl") { + kernel_c_flags += [ "-DTARGET_APL" ] + kernel_asm_flags += [ "-DTARGET_APL" ] + } + + # Enabling KASAN only for GCC builds as LLVM has fixed KASAN shadow bases + # which are incompatible with xOS layout. + if (debug_build && host == "gnu") { + kernel_c_flags += [ + "-fsanitize=kernel-address", + "-DKASAN_ENABLED", + ] + } +} + +if (target_arch == "riscv64") { + kernel_c_flags += [ + "-fno-builtin", + "-march=rv64ima", + "-mabi=lp64", + "-mcmodel=medany", + ] + kernel_asm_flags += [ + "-mcmodel=medany", + "-march=rv64ima", + "-mabi=lp64", + ] + kernel_ld_flags += [ "-nostdlib" ] + + if (host == "gnu") { + kernel_ld_flags += [ + "-nostdinc", + "-nodefaultlibs", + "-nostartfiles", + rebase_path("//toolchains/gcc_runtime/10.2.1/riscv64-libgcc.a", + root_build_dir), + ] + } + + if (host == "llvm") { + kernel_ld_flags += [ + "--oformat", + "elf64", + rebase_path("//toolchains/gcc_runtime/10.2.1/riscv64-libgcc.a", + root_build_dir), + ] + } +} + +config("kernel_flags") { + cflags = kernel_c_flags + asmflags = kernel_asm_flags + ldflags = kernel_ld_flags + defines = [ "xOS_kernel" ] +} + +kernel_src = exec_script("get_kernel_files.py", + [ + rebase_path("//src", root_build_dir), + target_arch, + ], + "list lines") + +linker_script = + rebase_path("//build/kernel/$target_arch/kernel_link.ld", root_build_dir) + +action("kernel_config") { + script = "//build/kernel/gen_config.py" + outputs = [ "$root_out_dir/base/boot/kernel.config" ] + args = [ + rebase_path("$root_out_dir/base/boot/kernel.config", root_build_dir), + "$target_arch", + "$host", + ] +} + +executable("kernel_build") { + deps = [ ":kernel_config" ] + + output_name = "$kernel_out_path/kernel.bin" + sources = kernel_src + + include_dirs = [ "//kernel/include" ] + + configs = [ ":kernel_flags" ] + + ldflags = [ + # See comment at EXEC_TEMPLATE.gni about elfsign_section.o. + # It is required to sign a binary. + rebase_path("$root_out_dir/tmp/elfsign_section.o", ""), + "-T$linker_script", + ] +} + +xOS_signexec("kernel") { + binpath = "boot/kernel.bin" +} + +group("kernel") { + deps = [ + ":kernel_build", + ":sign_kernel", + ] +} diff --git a/build/kernel/arm32/kernel_link.ld b/build/kernel/arm32/kernel_link.ld new file mode 100644 index 0000000..1dddcb3 --- /dev/null +++ b/build/kernel/arm32/kernel_link.ld @@ -0,0 +1,83 @@ +_pa_base = 0x80100000; +_va_base = 0xc0000000; + +ENTRY(_va_base) + +SECTIONS +{ + . = _va_base; + + __text_start = .; + .text ALIGN(4K) : AT (ADDR(.text) - _va_base + _pa_base) + { + *(.interrupt_vector_table) + *(.text) + *(.text.*) + } + __text_end = .; + + __rodata_start = .; + .rodata ALIGN(4K) : AT (ADDR(.rodata) - _va_base + _pa_base) + { + *(.rodata) + *(.rodata.*) + } + + .rodata.driver_init ALIGN(4K) : AT (ADDR(.rodata.driver_init) - _va_base + _pa_base) + { + _drivers_init_start = .; + *(SORT_BY_NAME(.driver_init_sections.*)) + _drivers_init_end = .; + } + __rodata_end = .; + + __data_start = .; + .data ALIGN(4K) : AT (ADDR(.data) - _va_base + _pa_base) + { + *(.data) + *(.data.*) + } + __data_end = .; + + __bss_start = .; + .bss ALIGN(4K) : AT (ADDR(.bss) - _va_base + _pa_base) + { + *(.bss) + *(.bss.*) + *(COMMON) + } + __bss_end = .; + + __stack_start = .; + .stack ALIGN(4K) : AT (ADDR(.stack) - _va_base + _pa_base) + { + STACK_SECONDARY_BASE = .; + . += 0x1000; + STACK_SECONDARY_TOP = .; + + STACK_BASE = .; + . += 0x1000; + STACK_TOP = .; + + STACK_SVC_BASE = .; + . += 0x1000; + STACK_SVC_TOP = .; + + STACK_IRQ_BASE = .; + . += 0x1000; + STACK_IRQ_TOP = .; + + STACK_ABORT_BASE = .; + . += 0x1000; + STACK_ABORT_TOP = .; + + STACK_UNDEFINED_BASE = .; + . += 0x1000; + STACK_UNDEFINED_TOP = .; + } + __stack_end = .; + + .ARM.exidx : { *(.ARM.exidx) } + + __end = .; +} \ No newline at end of file diff --git a/build/kernel/arm64/kernel_link.ld b/build/kernel/arm64/kernel_link.ld new file mode 100644 index 0000000..a189b68 --- /dev/null +++ b/build/kernel/arm64/kernel_link.ld @@ -0,0 +1,67 @@ +_pa_base = 0x0; +_va_base = 0xffffff8000000000; + +ENTRY(_va_base) + +SECTIONS +{ + . = _va_base; + + __text_start = .; + .text ALIGN(4K) : AT (ADDR(.text) - _va_base + _pa_base) + { + *(.xos_kernel_boot) + *(.text) + *(.text.*) + } + __text_end = .; + + __rodata_start = .; + .rodata ALIGN(4K) : AT (ADDR(.rodata) - _va_base + _pa_base) + { + *(.rodata) + *(.rodata.*) + } + + .rodata.driver_init ALIGN(4K) : AT (ADDR(.rodata.driver_init) - _va_base + _pa_base) + { + _drivers_init_start = .; + *(SORT_BY_NAME(.driver_init_sections.*)) + _drivers_init_end = .; + } + __rodata_end = .; + + __data_start = .; + .data ALIGN(4K) : AT (ADDR(.data) - _va_base + _pa_base) + { + *(.data) + *(.data.*) + } + __data_end = .; + + __bss_start = .; + .bss ALIGN(4K) : AT (ADDR(.bss) - _va_base + _pa_base) + { + *(.bss) + *(.bss.*) + *(COMMON) + } + __bss_end = .; + + __stack_start = .; + .stack ALIGN(4K) : AT (ADDR(.stack) - _va_base + _pa_base) + { + STACK_SECONDARY_BASE = .; + . += 0x1000; + STACK_SECONDARY_TOP = .; + + STACK_BASE = .; + . += 0x1000; + STACK_TOP = .; + } + __stack_end = .; + + .ARM.exidx : { *(.ARM.exidx) } + + __end = .; +} \ No newline at end of file diff --git a/build/kernel/devtree_compile.py b/build/kernel/devtree_compile.py new file mode 100644 index 0000000..9d86d49 --- /dev/null +++ b/build/kernel/devtree_compile.py @@ -0,0 +1,61 @@ +import os +import glob +import sys +import json +import subprocess +from datetime import datetime + +OBJCOPY_TOOL = "" +OBJCOPY_TARGET = "" + + +def shell(cmd, cwd=None): + return subprocess.check_output(cmd, shell=True, cwd=cwd).decode("ascii") + + +inpath = sys.argv[1] +outpath = sys.argv[2] +arch = sys.argv[3] +board = sys.argv[4] +host = sys.argv[5] +path_to_bins = sys.argv[6] + +if path_to_bins == "__EMPTY_PATH_": + path_to_bins = "" +if len(path_to_bins) != 0: + if path_to_bins[-1] != '/': + path_to_bins += "/" + +if (arch == "arm32"): + if host == "gnu": + OBJCOPY_TOOL = "{0}arm-none-eabi-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf32-littlearm" + elif host == "llvm": + OBJCOPY_TOOL = "{0}llvm-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf32-littlearm" +elif (arch == "arm64"): + if host == "gnu": + OBJCOPY_TOOL = "{0}aarch64-elf-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-littleaarch64" + elif host == "llvm": + OBJCOPY_TOOL = "{0}llvm-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-littleaarch64" +elif (arch == "riscv64"): + if host == "gnu": + OBJCOPY_TOOL = "{0}riscv64-unknown-elf-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-littleriscv" + elif host == "llvm": + OBJCOPY_TOOL = "{0}llvm-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-littleriscv" +else: + print("Unsupported arch {0}".format(arch)) + exit(1) + +run_from = os.getcwd() + '/../utils/compilers/DevTreeCompiler' +inpath_abs = os.getcwd() + '/' + inpath +outpath_abs = os.getcwd() + '/' + outpath +obj_outpath_abs = outpath_abs + "o" + +shell("python3 . {0} {1}".format(inpath_abs, outpath_abs), run_from) +shell("{0} -I binary -O {1} --rename-section .data=.odt {2} {3}".format( + OBJCOPY_TOOL, OBJCOPY_TARGET, outpath_abs, obj_outpath_abs)) diff --git a/build/kernel/gen_config.py b/build/kernel/gen_config.py new file mode 100644 index 0000000..78470ce --- /dev/null +++ b/build/kernel/gen_config.py @@ -0,0 +1,42 @@ +import os +import glob +import sys +import json +import subprocess +from datetime import datetime + +def shell(cmd): + return subprocess.check_output(cmd, shell=True).decode("ascii") + +outpath = sys.argv[1] +arch = sys.argv[2] +host = sys.argv[3] +branch = "{0}@{1}".format(shell("git rev-parse --short HEAD")[:-1], shell("git rev-parse --abbrev-ref HEAD")[:-1]) + + +config = {} +config['arch'] = arch +config['host'] = host +config['branch'] = branch +config['time'] = datetime.today().strftime('%Y-%m-%d %H:%M:%S') + + +# Printing to the file +def print_header(config_file): + config_file.write( + """# +# Automatically generated file; DO NOT EDIT. +# xOS Kernel Configuration +# + +""") + + +def print_json(config_file, rdict): + json.dump(rdict, config_file, indent = 4) + + +config_file = open(outpath, "w") +print_header(config_file) +print_json(config_file, config) +config_file.close() diff --git a/build/kernel/get_kernel_files.py b/build/kernel/get_kernel_files.py new file mode 100644 index 0000000..ee2aa52 --- /dev/null +++ b/build/kernel/get_kernel_files.py @@ -0,0 +1,77 @@ +import os +import glob +import sys +# sys.argv[2] Target to generate for +target = sys.argv[2] + +platforms = ['x86', 'i386', 'x86_64', 'arm', + 'arm32', 'arm64', 'aarch32', 'aarch64', + 'riscv', 'riscv64'] +bits = ['bits32', 'bits64'] + +platform_to_bits = { + "x86": "bits32", + "x86_64": "bits64", + "arm32": "bits32", + "arm64": "bits64", + "riscv64": "bits64", +} + +allowed_paths = { + "x86": ["x86", "i386"], + "x86_64": ["x86", "x86_64"], + "arm32": ["aarch32", "arm32", "arm"], + "arm64": ["aarch64", "arm64", "arm"], + "riscv64": ["riscv64", "riscv"] +} + +ignore_platforms = [] +ignore_bits = [] + +allowed_paths_for_target = allowed_paths.get(target, None) +if allowed_paths_for_target is None: + print("Unknown platform {0}".format(target)) + exit(1) + +for platform in platforms: + if not (platform in allowed_paths_for_target): + ignore_platforms.append(platform) + +for bit in bits: + if platform_to_bits[target] != bit: + ignore_bits.append(bit) + + +def is_file_type(name, ending): + if len(name) <= len(ending): + return False + return (name[-len(ending)-1::] == '.'+ending) + + +def is_file_blocked(name): + global ignore_platforms + for platform in ignore_platforms: + if (name.find(platform) != -1): + return True + for bit in ignore_bits: + if (name.find(bit) != -1): + return True + return False + + +for path, subdirs, files in os.walk("../kernel/kernel"): + for name in files: + # It runs from out dir, at least it should + file = "//" + path[3:] + "/" + name + if not is_file_type(file, 'c') and not is_file_type(file, 's') and not is_file_type(file, 'S'): + continue + if is_file_blocked(file): + continue + print(file) + + +def special_paths(platform): + pass + + +special_paths(target) diff --git a/build/kernel/riscv64/kernel_link.ld b/build/kernel/riscv64/kernel_link.ld new file mode 100644 index 0000000..0446da3 --- /dev/null +++ b/build/kernel/riscv64/kernel_link.ld @@ -0,0 +1,60 @@ +_pa_base = 0x0; +_va_base = 0xffff800000000000; + +ENTRY(_va_base) + +SECTIONS +{ + . = _va_base; + + __text_start = .; + .text ALIGN(4K) : + { + *(.xos_kernel_boot) + *(.text) + *(.text.*) + } + __text_end = .; + + __rodata_start = .; + .rodata ALIGN(4K) : + { + *(.rodata) + *(.rodata.*) + } + + .rodata.driver_init ALIGN(4K) : + { + _drivers_init_start = .; + *(SORT_BY_NAME(.driver_init_sections.*)) + _drivers_init_end = .; + } + __rodata_end = .; + + __data_start = .; + .data ALIGN(4K) : + { + *(.data) + *(.data.*) + } + __data_end = .; + + __bss_start = .; + .bss ALIGN(4K) : + { + *(.bss) + *(.bss.*) + *(COMMON) + } + __bss_end = .; + + __stack_start = .; + .stack ALIGN(4K) : + { + STACK_BASE = .; + . += 0x1000; + STACK_TOP = .; + } + __stack_end = .; + __end = .; +} \ No newline at end of file diff --git a/build/kernel/x86/kernel_link.ld b/build/kernel/x86/kernel_link.ld new file mode 100644 index 0000000..a1cece3 --- /dev/null +++ b/build/kernel/x86/kernel_link.ld @@ -0,0 +1,60 @@ +_pa_base = 1M; +_va_base = 0xc0000000; + +ENTRY(_va_base) + +SECTIONS +{ + . = _va_base; + + __text_start = .; + .text ALIGN(4K) : AT (ADDR(.text) - _va_base + _pa_base) + { + *(.xos_kernel_boot) + *(.text) + *(.text.*) + } + __text_end = .; + + __rodata_start = .; + .rodata ALIGN(4K) : AT (ADDR(.rodata) - _va_base + _pa_base) + { + *(.rodata) + *(.rodata.*) + } + + .rodata.driver_init ALIGN(4K) : AT (ADDR(.rodata.driver_init) - _va_base + _pa_base) + { + _drivers_init_start = .; + *(SORT_BY_NAME(.driver_init_sections.*)) + _drivers_init_end = .; + } + __rodata_end = .; + + __data_start = .; + .data ALIGN(4K) : AT (ADDR(.data) - _va_base + _pa_base) + { + *(.data) + *(.data.*) + } + __data_end = .; + + __bss_start = .; + .bss ALIGN(4K) : AT (ADDR(.bss) - _va_base + _pa_base) + { + *(.bss) + *(.bss.*) + *(COMMON) + } + __bss_end = .; + + __stack_start = .; + .stack ALIGN(4K) : AT (ADDR(.stack) - _va_base + _pa_base) + { + STACK_BASE = .; + . += 0x1000; + STACK_TOP = .; + } + __stack_end = .; + __end = .; +} \ No newline at end of file diff --git a/build/kernel/x86_64/kernel_link.ld b/build/kernel/x86_64/kernel_link.ld new file mode 100644 index 0000000..0446da3 --- /dev/null +++ b/build/kernel/x86_64/kernel_link.ld @@ -0,0 +1,60 @@ +_pa_base = 0x0; +_va_base = 0xffff800000000000; + +ENTRY(_va_base) + +SECTIONS +{ + . = _va_base; + + __text_start = .; + .text ALIGN(4K) : + { + *(.xos_kernel_boot) + *(.text) + *(.text.*) + } + __text_end = .; + + __rodata_start = .; + .rodata ALIGN(4K) : + { + *(.rodata) + *(.rodata.*) + } + + .rodata.driver_init ALIGN(4K) : + { + _drivers_init_start = .; + *(SORT_BY_NAME(.driver_init_sections.*)) + _drivers_init_end = .; + } + __rodata_end = .; + + __data_start = .; + .data ALIGN(4K) : + { + *(.data) + *(.data.*) + } + __data_end = .; + + __bss_start = .; + .bss ALIGN(4K) : + { + *(.bss) + *(.bss.*) + *(COMMON) + } + __bss_end = .; + + __stack_start = .; + .stack ALIGN(4K) : + { + STACK_BASE = .; + . += 0x1000; + STACK_TOP = .; + } + __stack_end = .; + __end = .; +} \ No newline at end of file diff --git a/build/libs/BUILD.gn b/build/libs/BUILD.gn new file mode 100644 index 0000000..140b06d --- /dev/null +++ b/build/libs/BUILD.gn @@ -0,0 +1,123 @@ +lib_c_flags = [ + "-ffreestanding", + "-Werror", + "-Wno-address-of-packed-member", +] + +if (userland_symbols) { + lib_c_flags += [ "-ggdb" ] +} + +if (optimize) { + lib_c_flags += [ "-Os" ] +} + +lib_cc_flags = [ + "-std=c++2a", + "-fno-sized-deallocation", + "-fno-exceptions", + "-D_LIBCXX_BUILD_XOS_EXTENSIONS", +] + +lib_objcc_flags = lib_cc_flags + [ + "-Wno-nullability-completeness", + "-Wno-deprecated-objc-isa-usage", + "-Wno-objc-root-class", + "-Wno-cast-of-sel-type", + "-fno-objc-exceptions", + "-fno-objc-arc", + "-fno-unwind-tables", + ] + +lib_asm_flags = [] + +if (device_type == "desktop") { + lib_c_flags += [ "-DTARGET_DESKTOP" ] +} +if (device_type == "mobile") { + lib_c_flags += [ "-DTARGET_MOBILE" ] +} + +if (target_arch == "x86") { + lib_asm_flags += [ + "-f", + "elf", + ] +} + +if (target_arch == "x86_64") { + lib_asm_flags += [ + "-f", + "elf64", + ] +} + +if (target_arch == "arm32") { + lib_c_flags += [ + "-fno-builtin", + "-march=armv7-a", + "-mfpu=neon-vfpv4", + "-mfloat-abi=softfp", + "-fno-pie", + ] + lib_asm_flags += [ + "-march=armv7-a", + "-mfpu=neon-vfpv4", + "-mfloat-abi=softfp", + "-mcpu=cortex-a15", + ] +} + +if (target_arch == "arm64") { + lib_c_flags += [ + "-fno-builtin", + "-mcpu=cortex-a53+nocrypto+nocrc", + "-fno-pie", + ] + lib_asm_flags += [ "-mcpu=cortex-a53+nocrypto+nocrc" ] +} + +if (target_arch == "riscv64") { + lib_c_flags += [ + "-fno-builtin", + "-march=rv64ima", + "-mabi=lp64", + "-fno-pie", + ] + lib_asm_flags += [ + "-march=rv64ima", + "-mabi=lp64", + ] +} + +config("lib_flags") { + cflags = lib_c_flags + asmflags = lib_asm_flags +} + +config("libobjcc_flags") { + cflags = lib_c_flags + cflags_objcc = lib_objcc_flags + cflags_cc = lib_cc_flags + asmflags = lib_asm_flags +} + +config("libcxx_flags") { + cflags = lib_c_flags + asmflags = lib_asm_flags + cflags_cc = lib_cc_flags +} + +group("libs") { + deps = [ + "//libs/libc:libc", + "//libs/libcxx:libcxx", + "//libs/libfoundation:libfoundation", + "//libs/libg:libg", + "//libs/libui:libui", + ] + + if (objc_support) { + deps += [ "//libs/libobjc:libobjc" ] + } +} diff --git a/build/libs/TEMPLATE.gni b/build/libs/TEMPLATE.gni new file mode 100644 index 0000000..bb2e560 --- /dev/null +++ b/build/libs/TEMPLATE.gni @@ -0,0 +1,102 @@ +template("xOS_static_library") { + assert(defined(invoker.sources), + "Need sources in $target_name to build static library") + + lib_name = target_name + lib_build_name = lib_name + "_build" + lib_include_config_name = lib_name + "_include_config" + compiled_lib_output_name_base = "$root_out_dir/tmp/libs/" + compiled_lib_output_name = compiled_lib_output_name_base + lib_name + final_lib_output_name = "$root_out_dir/base/libs/" + lib_name + ".a" + building_deplib_bulders_list = [] + linking_deplib_bulders_list = [] + linking_deplib_list = [] + includes = [] + + if (defined(invoker.include_dirs)) { + includes = invoker.include_dirs + } + + if (defined(invoker.deplibs)) { + foreach(i, invoker.deplibs) { + fullname = "//libs/" + i + ":" + i + + # To speed up compilation we have separate deps for builing and linking stages. + # The only library which is required to be a dependancy for building stage is libfreetype, + # since its header files might not be available initially (they are archived). + if (i == "libfreetype") { + building_deplib_bulders_list += [ fullname + "_build" ] + } + + linking_deplib_bulders_list += [ fullname + "_build" ] + linking_deplib_list += [ compiled_lib_output_name_base + + get_label_info(fullname, "name") + ".a" ] + includes += [ "//libs/" + i + "/include" ] + + # Also adding libc includes. + # Note to add libc after libcxx. + if (i == "libcxx") { + includes += [ "//libs/libc/include" ] + } + + # LibAPI is a lightweight library to use shared headers with API between libs and apps. + if (i == "libui") { + includes += [ "//libs/libapi/include" ] + } + } + } + includes += [ "//libs/" + lib_name + "/include" ] + + # The output library is passed at the end. + linking_deplib_list += [ compiled_lib_output_name + ".a" ] + linking_deplib_bulders_list += [ "//libs/" + lib_name + ":" + lib_build_name ] + + # Use a strange __EMPTY_PATH_, empty string can't be passed as an arg. + path_to_bins = "__EMPTY_PATH_" + if (host == "llvm") { + path_to_bins = llvm_bin_path + } + + script_args = [ + "$target_arch", + "$host", + "$path_to_bins", + rebase_path("$final_lib_output_name", root_build_dir), + ] + + foreach(i, linking_deplib_list) { + script_args += [ rebase_path(i, root_build_dir) ] + } + + config(lib_include_config_name) { + include_dirs = includes + } + + # Create a build rule to compile only a lib with unresolved references from other libs + static_library(lib_build_name) { + output_name = "tmp/libs/" + lib_name + sources = invoker.sources + include_dirs = includes + deps = building_deplib_bulders_list + forward_variables_from(invoker, + [ + "configs", + "cflags", + "cflags_c", + "cflags_cc", + "cflags_objc", + "cflags_objcc", + "asmflags", + "deps", + "public_deps", + ]) + } + + action(lib_name) { + script = "//build/libs/merge_libs.py" + inputs = linking_deplib_list + outputs = [ "$final_lib_output_name" ] + deps = linking_deplib_bulders_list + args = script_args + } +} diff --git a/build/libs/merge_libs.py b/build/libs/merge_libs.py new file mode 100644 index 0000000..ebf6b9c --- /dev/null +++ b/build/libs/merge_libs.py @@ -0,0 +1,83 @@ +import sys +import subprocess +import random +AR_TOOL = "" + +arch = sys.argv[1] +host = sys.argv[2] +path_to_bins = sys.argv[3] +target_lib = sys.argv[4] +srcs_lib = list(sys.argv[5:]) + +if path_to_bins == "__EMPTY_PATH_": + path_to_bins = "" +if len(path_to_bins) != 0: + if path_to_bins[-1] != '/': + path_to_bins += "/" + +if (arch == "arm32"): + if host == "gnu": + AR_TOOL = "{0}arm-none-eabi-ar".format(path_to_bins) + srcs_lib.append( + "../toolchains/gcc_runtime/10.2.1/arm-none-eabi-libgcc.a") + elif host == "llvm": + AR_TOOL = "{0}llvm-ar".format(path_to_bins) + srcs_lib.append( + "/usr/lib/llvm-18/lib/clang/18/lib/linux/libclang_rt.builtins-arm.a") +elif (arch == "x86"): + if host == "gnu": + AR_TOOL = "{0}i686-elf-ar".format(path_to_bins) + elif host == "llvm": + AR_TOOL = "{0}llvm-ar".format(path_to_bins) + srcs_lib.append( + "/usr/lib/llvm-18/lib/clang/18/lib/linux/libclang_rt.builtins-i386.a") +elif (arch == "x86_64"): + if host == "gnu": + AR_TOOL = "{0}x86_64-elf-ar".format(path_to_bins) + srcs_lib.append( + "../toolchains/gcc_runtime/10.2.1/x86_64-libgcc.a") + elif host == "llvm": + AR_TOOL = "{0}llvm-ar".format(path_to_bins) +elif (arch == "arm64"): + if host == "gnu": + AR_TOOL = "{0}aarch64-elf-ar".format(path_to_bins) + srcs_lib.append( + "../toolchains/gcc_runtime/10.2.1/aarch64-libgcc.a") + elif host == "llvm": + AR_TOOL = "{0}llvm-ar".format(path_to_bins) + else: + print("Unsupported host for arch {0}".format(host, arch)) + exit(1) +elif (arch == "riscv64"): + if host == "gnu": + AR_TOOL = "{0}riscv64-unknown-elf-ar".format(path_to_bins) + srcs_lib.append( + "../toolchains/gcc_runtime/10.2.1/riscv64-libgcc.a") + elif host == "llvm": + AR_TOOL = "{0}llvm-ar".format(path_to_bins) + srcs_lib.append( + "../toolchains/gcc_runtime/10.2.1/riscv64-libgcc.a") + else: + print("Unsupported host for arch {0}".format(host, arch)) + exit(1) +else: + print("Unsupported arch {0}".format(arch)) + exit(1) + +if (len(srcs_lib) == 1): + output = subprocess.check_output( + "cp {1} {0}".format(target_lib, srcs_lib[0]), shell=True) +else: + filename = "libmerger{0}.mri".format(random.randint(10000, 100000)) + + ffile = open(filename, "w") + ffile.write("CREATE {0}\n".format(target_lib)) + for i in srcs_lib: + ffile.write("ADDLIB {0}\n".format(i)) + ffile.write("SAVE\n") + ffile.write("END") + ffile.close() + + output = subprocess.check_output( + "{0} -M <{1}".format(AR_TOOL, filename), shell=True) + output = subprocess.check_output("rm {0}".format(filename), shell=True) diff --git a/build/makefile.configs b/build/makefile.configs new file mode 100644 index 0000000..ad7afd3 --- /dev/null +++ b/build/makefile.configs @@ -0,0 +1,11 @@ +# Sync config +# SET YOUR PATHS HERE +FUSE_EXT2 = fuse-ext2 +MKFS_LINUX = mkfs +MKFS_MAC = /usr/local/opt/e2fsprogs/sbin/mkfs.ext2 +MKFS = ${MKFS_MAC} +MOUNT_EXT2 = ${FUSE_EXT2} + +# xOS boot config +DISK = one.img +BASE_DIR = base \ No newline at end of file diff --git a/build/security/SIGN_TEMPLATE.gni b/build/security/SIGN_TEMPLATE.gni new file mode 100644 index 0000000..08163ca --- /dev/null +++ b/build/security/SIGN_TEMPLATE.gni @@ -0,0 +1,16 @@ +template("xOS_signexec") { + app_name = target_name + assert(defined(invoker.binpath), "Install path must be provided") + + binpath = invoker.binpath + action("sign_$app_name") { + script = "//build/security/sign_executable.py" + inputs = [ "$root_out_dir/base/$binpath" ] + outputs = [ "$root_out_dir/tmp/$binpath.signed" ] + deps = [ ":$app_name" + "_build" ] + args = [ + rebase_path("$root_out_dir/base/$binpath", root_build_dir), + rebase_path("$root_out_dir/tmp/$binpath.signed", ""), + ] + } +} diff --git a/build/security/sign_executable.py b/build/security/sign_executable.py new file mode 100644 index 0000000..21e3955 --- /dev/null +++ b/build/security/sign_executable.py @@ -0,0 +1,18 @@ +import sys +import os +import subprocess +from pathlib import Path + + +def shell(cmd, cwd=None): + return subprocess.check_output(cmd, shell=True, cwd=cwd).decode("ascii") + + +elffile_path = sys.argv[1] +stampfile_path = sys.argv[2] + +run_from = os.getcwd() + '/../utils/crypto/' +elffile_path_abs = os.getcwd() + '/' + elffile_path + +shell("python3 elfsign.py {0} --overwrite".format(elffile_path_abs), run_from) +Path(stampfile_path).touch() diff --git a/build/test/BUILD.gn b/build/test/BUILD.gn new file mode 100644 index 0000000..a8ea55d --- /dev/null +++ b/build/test/BUILD.gn @@ -0,0 +1,16 @@ +group("test") { + deps = [] + + # If we run test, let's include the entry point. + if (test_method == "tests") { + deps += [ + "//test/kernel:test_kernel", + "//test/libc:test_libc", + "//test/runner:launch_server", + ] + } + + if (test_method == "bench") { + deps += [ "//test/bench:launch_server" ] + } +} diff --git a/build/test/TEMPLATE.gni b/build/test/TEMPLATE.gni new file mode 100644 index 0000000..a7ae345 --- /dev/null +++ b/build/test/TEMPLATE.gni @@ -0,0 +1,36 @@ +import("//build/userland/EXEC_TEMPLATE.gni") + +template("xOS_test") { + app_name = string_replace(invoker.test_bundle, "/", "\$") + xOS_executable_template(app_name) { + install_path = "test_bin/" + forward_variables_from(invoker, + [ + "sources", + "configs", + "deplibs", + "cflags", + "cflags_c", + "cflags_cc", + "cflags_objc", + "cflags_objcc", + "asmflags", + "ldflags", + "public_deps", + ]) + if (defined(invoker.cflags)) { + cflags = invoker.cflags + } else { + cflags = [] + } + + cflags += [ + "-DTestMsg(x)=printf(\"[MSG] %s\n\", x);fflush(stdout);", + "-DTestErr(x)=printf(\"[MSG] %s\n\", x);fflush(stdout);exit(1)", + ] + } + + group(target_name) { + deps = [ ":$app_name" + "_build" ] + } +} diff --git a/build/third_party/BUILD.gn b/build/third_party/BUILD.gn new file mode 100644 index 0000000..0923180 --- /dev/null +++ b/build/third_party/BUILD.gn @@ -0,0 +1,3 @@ +group("third_party") { + deps = [ "//build/third_party/tinysh:tinysh" ] +} diff --git a/build/third_party/PY_BRIDGE.gni b/build/third_party/PY_BRIDGE.gni new file mode 100644 index 0000000..a3f7d6a --- /dev/null +++ b/build/third_party/PY_BRIDGE.gni @@ -0,0 +1,27 @@ +import("//build/userland/USERLAND_FLAGS.gni") +import("//toolchains/COMPILERS.gni") + +if (uland_ld_flags == []) { + port_ld_flags = [ "__EMPTY__" ] +} else { + port_ld_flags = uland_ld_flags +} + +py_bridging_args = [ + # outpath here is inserted + rebase_path("//", root_build_dir), # rootdir + "$target_arch", # target cpu + "$host", # host compiler + string_join(" ", + [ + toolchain_ar, + toolchain_cc, + toolchain_cxx, + toolchain_ld, + toolchain_asm, + toolchain_target, + ]), # compiler_toolchain + string_join(" ", uland_c_flags), # c_flags + string_join(" ", uland_cc_flags), # cc_flags + string_join(" ", port_ld_flags), # ld_flags +] diff --git a/build/third_party/PortingTools.py b/build/third_party/PortingTools.py new file mode 100644 index 0000000..ad53339 --- /dev/null +++ b/build/third_party/PortingTools.py @@ -0,0 +1,109 @@ +import os +import subprocess +import sys +from pathlib import Path +from git import Repo + + +class PortTools: + def __init__(self): + pass + + @staticmethod + def set_env(name, val): + os.environ[name] = str(val) + + @staticmethod + def run_command_impl(cmd, cwd="."): + result = subprocess.run( + cmd, stdout=subprocess.PIPE, shell=True, cwd=cwd) + return (result.stdout.decode("ascii"), result.returncode) + + @staticmethod + def run_command(cmd, cwd="."): + return PortTools.run_command_impl(cmd, cwd) + + @staticmethod + def apply_patch(location, patch_name): + src_dir = location+"/src" + if not os.path.exists(src_dir): + return ("", -1) + + patch_path = location+"/patches/"+patch_name + if not os.path.exists(patch_path): + return ("", -1) + + applied_patch_path = location+"/patches/.applied_"+patch_name + if os.path.exists(applied_patch_path): + return ("", 0) + + cmd = ["patch"] + myinput = open(patch_path) + result = subprocess.run( + cmd, stdin=myinput, stdout=subprocess.PIPE, cwd=src_dir) + if result.returncode == 0: + Path(applied_patch_path).touch() + return (result.stdout.decode("ascii"), result.returncode) + + @staticmethod + def clone_git(location, url): + src_dir = location+"/src" + if os.path.exists(src_dir): + return + Repo.clone_from(url, src_dir) + + +class StaticBuiler: + def check_libs_present(self, lib_name): + lib_desc = StaticBuiler.libs.get(lib_name, None) + if lib_desc is None: + return False + + if not os.path.exists(lib_desc["bin"]): + return False + + return True + + def __init__(self, rootdir, srcdir, libs): + self.rootdir = rootdir + self.srcdir = srcdir + self.target_libs = libs + self.libs = { + "libc": { + "include": self.rootdir + "/libs/libc/include", + "bin": self.rootdir + "/out/base/libs/", + } + } + + def libs_include_flags(self): + flags = "" + for lib_name in self.target_libs: + lib_desc = self.libs.get(lib_name, None) + assert(lib_desc is not None) + + flags += "-I" + flags += lib_desc["include"] + " " + return flags + + def libs_link_flags(self): + flags = " " + for lib_name in self.target_libs: + lib_desc = self.libs.get(lib_name, None) + assert(lib_desc is not None) + + flags += "-L" + flags += lib_desc["bin"] + " " + flags += "-l" + lib_name[3:] + " " + return flags + + def run_command(self, cmd_str): + return PortTools.run_command(cmd_str, self.srcdir) + + def move_exec(self, execname, targetdir): + if not os.path.exists(targetdir): + os.makedirs(targetdir) + return self.run_command("mv {0} {1}".format(execname, targetdir)) + + +if __name__ == '__main__': + pass diff --git a/build/third_party/PyBridgingTools.py b/build/third_party/PyBridgingTools.py new file mode 100644 index 0000000..5dfe5de --- /dev/null +++ b/build/third_party/PyBridgingTools.py @@ -0,0 +1,34 @@ +import os +import subprocess +import sys +from pathlib import Path + + +class PyBridgingTools: + def __init__(self): + pass + + @staticmethod + def build_descriptor(): + # Fixup for runtime libs. + ldflags = sys.argv[8] + " " if sys.argv[8] != "__EMPTY__" else "" + ldflags = ldflags.replace("../toolchains/", "../../../toolchains/") + + desc = { + "outpath": os.path.abspath(sys.argv[1]), + "rootdir": os.path.abspath(sys.argv[2]), + "target_arch": sys.argv[3], + "host": sys.argv[4], + "toolchain": { + "ar": sys.argv[5].split(" ")[0], + "cc": sys.argv[5].split(" ")[1], + "cxx": sys.argv[5].split(" ")[2], + "ld": sys.argv[5].split(" ")[3], + "asm": sys.argv[5].split(" ")[4], + "target": sys.argv[5].split(" ")[5], + }, + "c_flags": sys.argv[6] + " " if sys.argv[6] != "__EMPTY__" else "", + "cc_flags": sys.argv[7] + " " if sys.argv[7] != "__EMPTY__" else "", + "ld_flags": ldflags, + } + return desc diff --git a/build/third_party/tinysh/BUILD.gn b/build/third_party/tinysh/BUILD.gn new file mode 100644 index 0000000..9938744 --- /dev/null +++ b/build/third_party/tinysh/BUILD.gn @@ -0,0 +1,11 @@ +import("//build/third_party/PY_BRIDGE.gni") + +gnstate = [ rebase_path("$root_out_dir/base/bin/tinysh", root_build_dir) ] + + py_bridging_args + +action("tinysh") { + script = "//build/third_party/tinysh/package.py" + outputs = [ "$root_out_dir/base/bin/tinysh" ] + args = gnstate + deps = [ "//libs/libc:libc" ] +} diff --git a/build/third_party/tinysh/package.py b/build/third_party/tinysh/package.py new file mode 100644 index 0000000..7bdcc64 --- /dev/null +++ b/build/third_party/tinysh/package.py @@ -0,0 +1,97 @@ +# fmt: off +import sys +from os import path +sys.path.append(path.dirname(path.dirname(path.abspath(__file__)))) +from PortingTools import * +from PyBridgingTools import * +# fmt: on + +state = PyBridgingTools.build_descriptor() + + +class TinyshPackage: + version = "1.0" + name = "tinysh" + exec_name = "simple-c-shell" + rootdir = state["rootdir"] + target_dir = state["rootdir"] + "/third_party/tinysh" + url = "https://github.com/jmreyes/simple-c-shell.git" + + def __init__(self): + pass + + def clean(self): + src_dir = self.target_dir + "/src" + PortTools.run_command("rm -rf {0}".format(src_dir)) + + def has_build(self): + cache_location = self.target_dir + \ + "/bin_{0}/".format(state['target_arch']) + file_in_cache = cache_location + TinyshPackage.exec_name + return os.path.exists(file_in_cache) + + def download(self): + PortTools.clone_git(self.target_dir, self.url) + + def apply_patches(self): + txt, err = PortTools.apply_patch( + self.target_dir, "0001-llvm_support.patch") + if err: + print(txt) + exit(1) + txt, err = PortTools.apply_patch( + self.target_dir, "0002-disable_unsupported.patch") + if err: + print(txt) + exit(1) + + def build(self): + cache_location = self.target_dir + \ + "/bin_{0}/".format(state['target_arch']) + file_in_cache = cache_location + TinyshPackage.exec_name + if self.has_build(): + return + + src_dir = self.target_dir + "/src" + + builder = StaticBuiler(state["rootdir"], src_dir, libs=["libc"]) + PortTools.set_env("CC", state["toolchain"]["cc"]) + PortTools.set_env("LD", state["toolchain"]["ld"]) + + cflags = "" + ldflags = "" + if state["host"] == "llvm": + cflags += "-target " + state["toolchain"]["target"] + " " + + cflags += state["c_flags"] + cflags += builder.libs_include_flags() + PortTools.set_env("CFLAGS", cflags) + + ldflags += state["ld_flags"] + ldflags += builder.libs_link_flags() + PortTools.set_env("LDFLAGS", ldflags) + + _, err = builder.run_command( + "make CC=\"$CC\" LD=\"$LD\" CFLAGS=\"$CFLAGS\" LDFLAGS=\"$LDFLAGS\"") + if err: + exit(1) + + exepath = src_dir + "/" + TinyshPackage.exec_name + builder.move_exec(exepath, cache_location) + builder.run_command("make clean") + + def bin_is_ready(self): + cache_location = self.target_dir + \ + "/bin_{0}/".format(state['target_arch']) + file_in_cache = cache_location + TinyshPackage.exec_name + if os.path.exists(state["outpath"]): + return + os.symlink(file_in_cache, state["outpath"]) + + +package = TinyshPackage() +if not package.has_build(): + package.download() + package.apply_patches() + package.build() +package.bin_is_ready() diff --git a/build/tools/BUILD.gn b/build/tools/BUILD.gn new file mode 100644 index 0000000..119a7cb --- /dev/null +++ b/build/tools/BUILD.gn @@ -0,0 +1,36 @@ +action("build_scripts") { + script = "build_scripts.py" + outputs = [ + "$root_build_dir/build.sh", + "$root_build_dir/run.sh", + "$root_build_dir/sync.sh", + "$root_build_dir/all.sh", + ] + + args = [ + target_arch, + target_board, + rebase_path("//", root_build_dir), + rebase_path("$root_build_dir", root_build_dir), + ] +} + +# Use a strange __EMPTY_PATH_, empty string can't be passed as an arg. +path_to_bins = "__EMPTY_PATH_" +if (host == "llvm") { + path_to_bins = llvm_bin_path +} + +prepare_env_script_args = [ + rebase_path("$root_out_dir/tmp/elfsign_section.o", root_build_dir), + "$target_arch", + "$target_board", + "$host", + "$path_to_bins", +] + +action("prepare_env") { + script = "prepare_env.py" + outputs = [ "$root_build_dir/tmp/elfsign_section.o" ] + args = prepare_env_script_args +} diff --git a/build/tools/build_scripts.py b/build/tools/build_scripts.py new file mode 100644 index 0000000..162ae4c --- /dev/null +++ b/build/tools/build_scripts.py @@ -0,0 +1,190 @@ +import sys +import os +QEMU_PATH_VAR = "qemu_exec" +QEMU_PATH_ENV_VAR = "" +QEMU_SMP_VAR = "qemu_smp" +QEMU_SMP_ENV_VAR = "XOS_QEMU_SMP" +QEMU_STD_PATH = "" +qemu_run_cmd = "" +arch = sys.argv[1] +target_board = sys.argv[2] +base = sys.argv[3] +out = sys.argv[4] + +if arch == "x86": + QEMU_PATH_ENV_VAR = "XOS_QEMU_X86" + QEMU_STD_PATH = "qemu-system-i386" + qemu_run_cmd = "${2} -m 256M --drive file={1}/os-image.bin,format=raw,index=0,if=floppy -device piix3-ide,id=ide -drive id=disk,format=raw,file={1}/one.img,if=none -device ide-hd,drive=disk,bus=ide.0 -serial mon:stdio -rtc base=utc -vga std -qmp unix:./qmp-sock,server,nowait".format( + base, out, QEMU_PATH_VAR) +if arch == "x86_64": + QEMU_PATH_ENV_VAR = "XOS_QEMU_X86_64" + QEMU_STD_PATH = "qemu-system-x86_64" + qemu_run_cmd = "${2} -m 1G -kernel {1}/rawImage.elf -cpu phenom -device piix3-ide,id=ide -drive id=disk,format=raw,file={1}/one.img,if=none -device ide-hd,drive=disk,bus=ide.0 -serial mon:stdio -rtc base=utc -vga std".format( + base, out, QEMU_PATH_VAR) +if arch == "arm32": + QEMU_PATH_ENV_VAR = "XOS_QEMU_ARM" + QEMU_STD_PATH = "qemu-system-arm" + qemu_run_cmd = "${2} -m 256M -M vexpress-a15 -cpu cortex-a15 -kernel {1}/bootarm.bin -smp ${3} -serial mon:stdio -vga std -drive id=disk,if=sd,format=raw,file={1}/one.img".format( + base, out, QEMU_PATH_VAR, QEMU_SMP_VAR) +if arch == "arm64": + QEMU_PATH_ENV_VAR = "XOS_QEMU_AA64" + QEMU_STD_PATH = "echo Please provide path to custom QEMU with $XOS_QEMU_AA64, see https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/docs/getting_qemu.md" + qemu_run_cmd = "${2} -machine virt,secure=off,virtualization=off,gic-version=2 -cpu cortex-a53 -m 1G -kernel {1}/rawImage.bin -smp ${3} -serial mon:stdio -drive id=disk,if=sd,format=raw,file={1}/one.img".format( + base, out, QEMU_PATH_VAR, QEMU_SMP_VAR) + if target_board == "apl": + qemu_run_cmd = "python3 {0}/utils/codeassistant/pongo_startup.py".format(base) +if arch == "riscv64": + QEMU_PATH_ENV_VAR = "XOS_QEMU_RV64" + QEMU_STD_PATH = "qemu-system-riscv64" + qemu_run_cmd = "${2} -machine virt -m 1G -bios none -kernel {1}/prekernelriscv64.bin -serial mon:stdio -drive if=none,format=raw,file={1}/one.img,id=drv -device virtio-blk-device,drive=drv -device virtio-rng-device -device virtio-gpu-device -device virtio-keyboard-device -device virtio-mouse-device".format( + base, out, QEMU_PATH_VAR, QEMU_SMP_VAR) + +if base[-1] == '/': + base = base[:-1] + +if out[-1] == '/': + out = out[:-1] + +env_var_checker = """ +{2}="{3}" +{4}=1 +[[ -z "${1}" ]] && {2}='{3}' || {2}="${1}" +[[ -z "${5}" ]] && {4}=1 || {4}="${5}" +""".format("", QEMU_PATH_ENV_VAR, QEMU_PATH_VAR, QEMU_STD_PATH, QEMU_SMP_VAR, QEMU_SMP_ENV_VAR) + +sync = open("{0}/sync.sh".format(out), "w") +sync.write( + """#!/bin/bash +GREEN='\\033[0;32m' +RED='\\033[0;31m' +NC='\\033[0m' +ERROR="${{RED}}[ERROR]${{NC}}" +SUCCESS="${{GREEN}}[SUCCESS]${{NC}}" + +mkdir -p {1}/mountpoint +sudo fuse-ext2 {1}/one.img {1}/mountpoint -o rw+ +if [ $? -ne 0 ]; then echo -e "${{ERROR}} Can't mount one.img to {1}/mountpoint" && exit 1; fi +sudo mkdir -p {1}/mountpoint/boot +sudo mkdir -p {1}/mountpoint/proc +sudo mkdir -p {1}/mountpoint/var +sudo mkdir -p {1}/mountpoint/dev +sudo mkdir -p {1}/mountpoint/tmp +sudo cp -r {0}/base/* {1}/mountpoint/ +sudo cp -r {1}/base/* {1}/mountpoint/ + +sudo chmod -R 644 {1}/mountpoint/proc +sudo chmod -R 644 {1}/mountpoint/dev +sudo chmod -R 666 {1}/mountpoint/tmp +sudo chmod -R 666 {1}/mountpoint/var +sudo chmod -R 755 {1}/mountpoint/bin +sudo chmod -R 700 {1}/mountpoint/home +sudo chmod 777 {1}/mountpoint/home +sudo chmod -R 755 {1}/mountpoint/System +sudo chmod -R 755 {1}/mountpoint/Applications + +sudo chown -R 0 {1}/mountpoint/home/root +sudo chown -R 0 {1}/mountpoint/bin/sudo +sudo chmod 4755 {1}/mountpoint/bin/sudo + +sudo chown -R 10 {1}/mountpoint/home/user + +sudo umount {1}/mountpoint +if [ $? -ne 0 ]; then echo -e "${{ERROR}} Can't umount {1}/mountpoint" && exit 1; fi +echo -e "${{SUCCESS}} Sync" +""".format(base, out)) +sync.close() + + +build = open("{0}/build.sh".format(out), "w") +build.write( + """#!/bin/bash +GREEN='\\033[0;32m' +RED='\\033[0;31m' +NC='\\033[0m' +ERROR="${{RED}}[ERROR]${{NC}}" +SUCCESS="${{GREEN}}[SUCCESS]${{NC}}" + +ninja +if [ $? -ne 0 ]; then echo -e "${{ERROR}} Can't build for arch: {0}" && exit 1; fi +echo -e "${{SUCCESS}} Build for arch: {0}" +""".format(arch)) +build.close() + +run = open("{0}/run.sh".format(out), "w") +run.write( + """#!/bin/bash +{1} +{0} +if [ $? -ne 0 ]; then echo -e "${{ERROR}} Run command failed" && exit 1; fi""".format(qemu_run_cmd, env_var_checker) +) +run.close() + +debug = open("{0}/debug.sh".format(out), "w") +debug.write( + """#!/bin/bash +{1} +{0} -s -S +if [ $? -ne 0 ]; then echo -e "${{ERROR}} Debug Run command failed" && exit 1; fi""".format(qemu_run_cmd, env_var_checker) +) +debug.close() + +allf = open("{0}/all.sh".format(out), "w") +allf.write( + """#!/bin/bash +GREEN='\\033[0;32m' +RED='\\033[0;31m' +NC='\\033[0m' +ERROR="${RED}[ERROR]${NC}" +SUCCESS="${GREEN}[SUCCESS]${NC}" + +./build.sh +if [ $? -ne 0 ]; then echo -e "${ERROR} All command failed" && exit 1; fi +./sync.sh +if [ $? -ne 0 ]; then echo -e "${ERROR} All command failed" && exit 1; fi +./run.sh +if [ $? -ne 0 ]; then echo -e "${ERROR} All command failed" && exit 1; fi +""") +allf.close() + +allf = open("{0}/run_tester.sh".format(out), "w") +allf.write( + """#!/bin/bash +GREEN='\\033[0;32m' +RED='\\033[0;31m' +NC='\\033[0m' +ERROR="${{RED}}[ERROR]${{NC}}" +SUCCESS="${{GREEN}}[SUCCESS]${{NC}}" + +./build.sh +if [ $? -ne 0 ]; then echo -e "${{ERROR}} All command failed" && exit 1; fi +./sync.sh +if [ $? -ne 0 ]; then echo -e "${{ERROR}} All command failed" && exit 1; fi +{1} +{0} --nographic +if [ $? -ne 0 ]; then echo -e "${{ERROR}} All command failed" && exit 1; fi +""".format(qemu_run_cmd, env_var_checker)) +allf.close() + +allf = open("{0}/dll.sh".format(out), "w") +allf.write( + """#!/bin/bash +GREEN='\\033[0;32m' +RED='\\033[0;31m' +NC='\\033[0m' +ERROR="${RED}[ERROR]${NC}" +SUCCESS="${GREEN}[SUCCESS]${NC}" + +./build.sh +if [ $? -ne 0 ]; then echo -e "${ERROR} Debug All command failed" && exit 1; fi +./sync.sh +if [ $? -ne 0 ]; then echo -e "${ERROR} Debug All command failed" && exit 1; fi +./debug.sh +if [ $? -ne 0 ]; then echo -e "${ERROR} Debug All command failed" && exit 1; fi +""") +allf.close() + +gdbinit = open("{0}/.gdbinit".format(out), "w") +gdbinit.write( + """file {0}/base/boot/kernel.bin +target remote :1234""".format(out)) +gdbinit.close() diff --git a/build/tools/prepare_env.py b/build/tools/prepare_env.py new file mode 100644 index 0000000..38fd1ba --- /dev/null +++ b/build/tools/prepare_env.py @@ -0,0 +1,78 @@ +import sys +import os +import subprocess + +OBJCOPY_TOOL = "" +OBJCOPY_TARGET = "" + + +def shell(cmd, cwd=None): + return subprocess.check_output(cmd, shell=True, cwd=cwd).decode("ascii") + + +outpath = sys.argv[1] +arch = sys.argv[2] +board = sys.argv[3] +host = sys.argv[4] +path_to_bins = sys.argv[5] + +if path_to_bins == "__EMPTY_PATH_": + path_to_bins = "" +if len(path_to_bins) != 0: + if path_to_bins[-1] != '/': + path_to_bins += "/" + +if (arch == "arm32"): + if host == "gnu": + OBJCOPY_TOOL = "{0}arm-none-eabi-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf32-littlearm" + elif host == "llvm": + OBJCOPY_TOOL = "{0}llvm-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf32-littlearm" +elif (arch == "x86"): + if host == "gnu": + OBJCOPY_TOOL = "{0}i686-elf-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf32-i386" + elif host == "llvm": + OBJCOPY_TOOL = "{0}llvm-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf32-i386" +elif (arch == "x86_64"): + if host == "gnu": + OBJCOPY_TOOL = "{0}x86_64-elf-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-x86-64" + elif host == "llvm": + OBJCOPY_TOOL = "{0}llvm-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-x86-64" +elif (arch == "arm64"): + if host == "gnu": + OBJCOPY_TOOL = "{0}aarch64-elf-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-littleaarch64" + elif host == "llvm": + OBJCOPY_TOOL = "{0}llvm-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-littleaarch64" +elif (arch == "riscv64"): + if host == "gnu": + OBJCOPY_TOOL = "{0}riscv64-unknown-elf-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-littleriscv" + elif host == "llvm": + OBJCOPY_TOOL = "{0}llvm-objcopy".format(path_to_bins) + OBJCOPY_TARGET = "elf64-littleriscv" +else: + print("Unsupported arch {0}".format(arch)) + exit(0) + +outpath_abs = os.getcwd() + '/' + outpath + +codesign_section_len = 1024 + +tmp_empty_bin_name = 'elfsign_section.bin' +f = open(tmp_empty_bin_name, "wb") +f.seek(codesign_section_len-1) +f.write(b"\0") +f.close() + + +shell("{0} -I binary -O {1} --rename-section .data=._signature {2} {3}".format( + OBJCOPY_TOOL, OBJCOPY_TARGET, tmp_empty_bin_name, outpath_abs)) +shell("{0} --set-section-flags ._signature=noload,readonly {1} {2}".format( + OBJCOPY_TOOL, outpath_abs, outpath_abs)) diff --git a/build/userland/BUILD.gn b/build/userland/BUILD.gn new file mode 100644 index 0000000..17c83a5 --- /dev/null +++ b/build/userland/BUILD.gn @@ -0,0 +1,73 @@ +import("//build/userland/USERLAND_FLAGS.gni") + +config("userland_flags") { + cflags = uland_c_flags + cflags_cc = uland_cc_flags + cflags_objcc = uland_objcc_flags + asmflags = uland_asm_flags + ldflags = uland_ld_flags + defines = [ "xOS" ] +} + +group("applications") { + deps = [ + "//userland/applications/about:about", + "//userland/applications/activity_monitor:activity_monitor", + "//userland/applications/calculator:calculator", + "//userland/applications/terminal:terminal", + ] +} + +group("system") { + deps = [ + "//userland/system/applist:applist", + "//userland/system/dock:dock", + "//userland/system/homescreen:homescreen", + ] +} + +group("servers") { + deps = [ "//userland/servers/window_server:window_server" ] +} + +group("utilities") { + deps = [ + "//userland/utilities/cat:cat", + "//userland/utilities/kill:kill", + "//userland/utilities/ls:ls", + "//userland/utilities/mkdir:mkdir", + "//userland/utilities/rm:rm", + "//userland/utilities/rmdir:rmdir", + "//userland/utilities/sudo:sudo", + "//userland/utilities/touch:touch", + "//userland/utilities/uname:uname", + "//userland/utilities/whoami:whoami", + ] +} + +group("userland") { + deps = [ + "//build/userland:applications", + "//build/userland:servers", + "//build/userland:system", + "//build/userland:utilities", + "//userland/shell/xsh:xsh", + ] + + # Make sure that we don't run any tests/benchmarks, since + # tests/benchmarks use thier own entry point. + if (test_method == "none") { + deps += [ "//userland/servers/launch_server:launch_server" ] + } + + if (compile_tests) { + deps += [ + "//userland/tests/testlibcxx:testlibcxx", + "//userland/tests/utester:utester", + ] + + if (objc_support) { + deps += [ "//userland/tests/testobjc:testobjc" ] + } + } +} diff --git a/build/userland/EXEC_TEMPLATE.gni b/build/userland/EXEC_TEMPLATE.gni new file mode 100644 index 0000000..853d005 --- /dev/null +++ b/build/userland/EXEC_TEMPLATE.gni @@ -0,0 +1,77 @@ +template("xOS_executable_template") { + assert(defined(invoker.sources), + "Need sources in $target_name to build xOS App") + + app_name = target_name + app_build_name = app_name + "_build" + + deplibs = [] + depbuilders = [] + includes = [] + confs = [] + if (defined(invoker.libs)) { + deplibs = invoker.libs + } + if (defined(invoker.deps)) { + depbuilders = invoker.deps + } + if (defined(invoker.include_dirs)) { + includes = invoker.include_dirs + } + if (defined(invoker.configs)) { + confs = invoker.configs + } + if (defined(invoker.deplibs)) { + foreach(i, invoker.deplibs) { + deplibs += [ "$root_out_dir/base/libs/" + i + ".a" ] + depbuilders += [ "//libs/" + i + ":" + i ] + includes += [ "//libs/" + i + "/include" ] + confs += [ "//libs/" + i + ":" + i + "_include_config" ] + + # Also adding libc includes. + # Note to add libc after libcxx. + if (i == "libcxx") { + includes += [ "//libs/libc/include" ] + } + + if (i == "libui") { + includes += [ "//libs/libapi/include" ] + } + } + } + + linkflags = [] + if (defined(invoker.need_sign_section) && invoker.need_sign_section == true) { + # Adding empty section for a signature. + # HACK: Since ldflags follow inputs for linker we put this + # section as a first flag, but it will be treated as input. + linkflags += [ rebase_path("$root_out_dir/tmp/elfsign_section.o", "") ] + } + if (defined(invoker.ldflags)) { + linkflags += invoker.ldflags + } + + executable(app_build_name) { + if (defined(invoker.install_path)) { + output_name = "base/" + invoker.install_path + app_name + } else { + output_name = "base/bin/" + app_name + } + sources = invoker.sources + libs = deplibs + deps = depbuilders + include_dirs = includes + configs = confs + ldflags = linkflags + forward_variables_from(invoker, + [ + "cflags", + "cflags_c", + "cflags_cc", + "cflags_objc", + "cflags_objcc", + "asmflags", + "public_deps", + ]) + } +} diff --git a/build/userland/TEMPLATE.gni b/build/userland/TEMPLATE.gni new file mode 100644 index 0000000..77b54a8 --- /dev/null +++ b/build/userland/TEMPLATE.gni @@ -0,0 +1,94 @@ +import("//build/security/SIGN_TEMPLATE.gni") +import("//build/userland/EXEC_TEMPLATE.gni") + +template("xOS_executable") { + app_name = target_name + + assert(defined(invoker.install_path), "Install path must be provided") + + signexec = false + if (defined(invoker.signexec)) { + signexec = invoker.signexec + } + + if (signexec) { + xOS_signexec(app_name) { + binpath = invoker.install_path + app_name + } + } + + xOS_executable_template(app_name) { + need_sign_section = signexec + forward_variables_from(invoker, + [ + "install_path", + "sources", + "configs", + "deplibs", + "cflags", + "cflags_c", + "cflags_cc", + "cflags_objc", + "cflags_objcc", + "asmflags", + "ldflags", + "public_deps", + "include_dirs", + ]) + } + + group(app_name) { + deps = [ ":$app_name" + "_build" ] + if (signexec) { + deps += [ ":sign_" + "$app_name" ] + } + } +} + +template("xOS_application") { + app_name = target_name + root = "Applications/$app_name.app" + exec_file = "$root/Content/" + + action("prepare_$app_name") { + script = "//build/userland/prepare_app.py" + outputs = [ "$root_out_dir/base/Applications/$app_name.app/Content" ] + args = [ + app_name, + invoker.display_name, + rebase_path("$root_out_dir/base/Applications/$app_name.app/Content", + root_build_dir), + rebase_path("//userland/applications/$app_name", root_build_dir), + ] + } + + xOS_signexec(app_name) { + binpath = exec_file + app_name + } + + xOS_executable_template(app_name) { + install_path = "$exec_file" + need_sign_section = true + forward_variables_from(invoker, + [ + "sources", + "configs", + "deplibs", + "cflags", + "cflags_c", + "cflags_cc", + "asmflags", + "ldflags", + "public_deps", + "include_dirs", + ]) + } + + group(app_name) { + deps = [ + ":$app_name" + "_build", + ":prepare_$app_name", + ":sign_" + "$app_name", + ] + } +} diff --git a/build/userland/USERLAND_FLAGS.gni b/build/userland/USERLAND_FLAGS.gni new file mode 100644 index 0000000..25b08d3 --- /dev/null +++ b/build/userland/USERLAND_FLAGS.gni @@ -0,0 +1,140 @@ +uland_c_flags = [ + "-Werror", + "-Wno-address-of-packed-member", +] + +if (userland_symbols) { + uland_c_flags += [ "-ggdb" ] +} + +if (optimize) { + uland_c_flags += [ "-Os" ] +} + +uland_cc_flags = [ + "-std=c++2a", + "-fno-sized-deallocation", + "-fno-exceptions", + "-D_LIBCXX_BUILD_XOS_EXTENSIONS", +] + +uland_objcc_flags = uland_cc_flags + [ + "-fno-objc-exceptions", + "-fno-objc-arc", + ] + +uland_asm_flags = [] +uland_ld_flags = [] + +if (device_type == "desktop") { + uland_c_flags += [ "-DTARGET_DESKTOP" ] +} +if (device_type == "mobile") { + uland_c_flags += [ "-DTARGET_MOBILE" ] +} + +if (target_arch == "x86") { + uland_asm_flags += [ + "-f", + "elf", + ] +} + +if (target_arch == "x86_64") { + uland_asm_flags += [ + "-f", + "elf64", + ] +} + +if (target_arch == "arm32") { + uland_c_flags += [ + "-fno-builtin", + "-march=armv7-a", + "-mfpu=neon-vfpv4", + "-mfloat-abi=softfp", + "-fno-pie", + ] + uland_asm_flags += [ + "-march=armv7-a", + "-mfpu=neon-vfpv4", + "-mfloat-abi=softfp", + "-mcpu=cortex-a15", + ] + uland_ld_flags += [ "-nostdlib" ] + + if (host == "gnu") { + uland_ld_flags += [ + "-nostdinc", + "-nodefaultlibs", + "-nostartfiles", + "-lgcc", + ] + } + + if (host == "llvm") { + uland_ld_flags += [ + "--oformat", + "elf32-littlearm", + "/usr/lib/llvm-18/lib/clang/18/lib/linux/libclang_rt.builtins-arm.a", + ] + } +} + +if (target_arch == "arm64") { + uland_c_flags += [ + "-fno-builtin", + "-mcpu=cortex-a53+nocrypto+nocrc", + "-fno-pie", + ] + uland_asm_flags += [ "-mcpu=cortex-a53+nocrypto+nocrc" ] + uland_ld_flags += [ "-nostdlib" ] + + if (host == "gnu") { + uland_ld_flags += [ + "-nostdinc", + "-nodefaultlibs", + "-nostartfiles", + "-lgcc", + ] + } + + if (host == "llvm") { + uland_ld_flags += [ + "--oformat", + "elf64-littlearm", + ] + } +} + +if (target_arch == "riscv64") { + uland_c_flags += [ + "-fno-builtin", + "-march=rv64ima", + "-mabi=lp64", + ] + uland_asm_flags += [ + "-march=rv64ima", + "-mabi=lp64", + ] + uland_ld_flags += [ "-nostdlib" ] + + if (host == "gnu") { + uland_ld_flags += [ + "-nostdinc", + "-nodefaultlibs", + "-nostartfiles", + rebase_path("//toolchains/gcc_runtime/10.2.1/riscv64-libgcc.a", + root_build_dir), + ] + } + + if (host == "llvm") { + uland_ld_flags += [ + "--oformat", + "elf64", + rebase_path("//toolchains/gcc_runtime/10.2.1/riscv64-libgcc.a", + root_build_dir), + ] + } +} \ No newline at end of file diff --git a/build/userland/prepare_app.py b/build/userland/prepare_app.py new file mode 100644 index 0000000..7b3fc8a --- /dev/null +++ b/build/userland/prepare_app.py @@ -0,0 +1,44 @@ +import sys +import os +import json +import subprocess + +fs_app_name = sys.argv[1] +app_name = sys.argv[2] +outpath = sys.argv[3] +src_dir = sys.argv[4] + + +def print_json(config_file, rdict): + json.dump(rdict, config_file, indent=4) + + +def read_config(path): + with open(path) as json_file: + data = json.load(json_file) + return data + return {} + + +def write_config(config, outpath): + config_file = open(outpath+"/info.json", "w") + + config['name'] = app_name + config['exec_rel_path'] = fs_app_name + config['icon_path'] = "/res/icons/apps/" + fs_app_name + ".icon" + config['bundle_id'] = "com.x.{0}".format(fs_app_name) + + print_json(config_file, config) + config_file.close() + + +if not os.path.exists(outpath): + os.makedirs(outpath) + +config = {} +for fname in os.listdir(src_dir): + if fname == "info.json": + config = read_config(src_dir + "/info.json") + break + +write_config(config, outpath) diff --git a/docs/boot.md b/docs/boot.md new file mode 100644 index 0000000..82af49e --- /dev/null +++ b/docs/boot.md @@ -0,0 +1,30 @@ +# Bootloaders + +The boot process of XKernel could be divided into 2 parts: bootloader(prekernel) and kernel. These parts are tight together and share the same ABI to prepare the required environment for the kernel. + +### Kernel boot requirements + +* VM is on. +* Filled *boot args*. +* All *kernel data* required for a kernel bootup (e.g. the kernel itself, boot args and vm translation tables) should be a continuous region of memory (both physical and virtual). This region is described with `boot_args->vaddr`, `boot_args->paddr` and `boot_args->kernel_data_size`. +* After *kernel data* **4mb** should be mapped for a successful kernel boot process. This part is used for kernel structs (e.g physical allocation table) which are required before the kernel can set up its own vm translation tables. +* Initial debug devices should be mapped (UART and/or framebuffer). +* For 64-bit kernels all RAM should be mapped to itself. + +### Prekernel + +The kernel is an ELF file but there are some use cases when it is needed a raw binary image or an UEFI-capable image. In order to prepare the required environment for a kernel bootup there is a part called *prekernel*. It is a position independent raw binary which contains code to boot the kernel. + +Raw image consists of prekernel, kernel and devtree. + +### Bootloaders + +An alternative to *prekernel* part is a standalone bootloader which could prepare the required environment for the kernel. + +## Dirs + +* [arm32](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/boot/arm32) Arm32 bootloader. +* [arm64](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/boot/arm64) Arm64 bootloader. +* [libboot](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/boot/libboot) Bootloader library. +* [x86](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/boot/x86) x86 bootloader. +* [x86_64](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/boot/x86_64) x86_64 bootloader. diff --git a/docs/build.md b/docs/build.md new file mode 100644 index 0000000..40915c3 --- /dev/null +++ b/docs/build.md @@ -0,0 +1,320 @@ +# Building OS + +## Prerequisites + +The project uses GN Build System, please ensure that you have `gn` binary. If your system doesn't have the build system, please visit [instructions how to get a GN binary](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/docs/getting_gn.md) + +### Getting QEMU + +The project uses QEMU as a primary build and test target. Please follow [instructions how to get a QEMU binary](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/docs/getting_qemu.md). + +### Tools for MacOS + +```bash +brew install --cask osxfuse + +brew install coreutils qemu e2fsprogs nasm m4 autoconf libtool automake bash gcc@10 ninja + +# install fuse-ext2 +``` + +`fuse-ext2` is not available as homebrew formula, download [sources](https://github.com/alperakcan/fuse-ext2) and compile it following [instructions](https://apple.stackexchange.com/questions/226981/how-do-i-install-fuse-ext2-to-use-with-osxfuse). + +*Notes*: + +* Make sure you have `xcode-tools` installed. + +
+ +### Tools for Linux (Ubuntu) + +```bash +apt install build-essential curl libmpfr-dev libmpc-dev libgmp-dev e2fsprogs qemu-system-i386 qemu-utils nasm fuseext2 ninja +``` + +
+ + + +### Tools for Windows (WSL2) + +**Setting up WSL2** + +1. **Enable WSL2** (requires Windows 10 version 2004+ or Windows 11): + + ```powershell + + # Run in PowerShell as Administrator + + wsl --install + + ``` + + This installs WSL2 with Ubuntu by default. Reboot when prompted. + + + +2. **Install Ubuntu from Microsoft Store** (if not auto-installed): + + - Open Microsoft Store + + - Search for "Ubuntu" (recommend Ubuntu 22.04 LTS) + + - Click "Get" and install + + + +3. **Set WSL2 as default version** (if needed): + + ```powershell + + wsl --set-default-version 2 + + ``` + + + +4. **Launch Ubuntu** from Start Menu and create a user account. + + + +**Installing Development Tools in WSL2** + + + +Once inside your WSL2 Ubuntu terminal: + + + +```bash + +# Update package lists + +sudo apt update && sudo apt upgrade -y + + + +# Install build tools + +sudo apt install build-essential curl libmpfr-dev libmpc-dev libgmp-dev \ + + e2fsprogs qemu-system-x86 qemu-system-arm qemu-system-misc \ + + qemu-utils nasm ninja-build git python3 python3-pip -y +``` +**WSL2-Specific Notes**: + + + +* **File Performance**: Keep your project files within the WSL2 filesystem rather than Windows filesystem (`/mnt/c/... `) for much better I/O performance. + +* **GUI Applications**: WSL2 supports GUI apps natively on Windows 11. On Windows 10, you may need an X server like VcXsrv for QEMU's graphical output. + +* **Memory Limits**: WSL2 defaults to 50% of host RAM. Create `%USERPROFILE%\.wslconfig` to adjust: + + ```ini + + [wsl2] + + memory=8GB + + processors=4 + + ``` + +* **Accessing WSL files from Windows**: Navigate to `\\wsl$\Ubuntu\home\\` in File Explorer. + +* **Restarting WSL**: If you encounter issues, restart WSL with `wsl --shutdown` in PowerShell, then relaunch. + + + +
+ +## Cross-compiler + +xOS could be compiled both with GNU and LLVM toochains. + +*Note* that in GNU world, every host/target combination has its own set of binaries, headers, libraries, etc. So, choose GNU Toolchain based on target architecture you want to compile the OS to. + +### GNU Toolchain for MacOS + +***x86*** + +```bash +brew install i686-elf-gcc +``` + +***x86-64*** + +```bash +brew install x86_64-elf-gcc +``` + +***Arm64*** + +```bash +brew install aarch64-elf-gcc +``` + +
+ +### LLVM Toolchain for MacOS + +```bash +brew install llvm +``` + +
+ +### GNU Toolchain for Linux (Ubuntu) and WSL2 + +***x86*** + +```bash +./toolchains/scripts/i686-elf-tools.sh +``` + +***Arm32*** + +```bash +./toolchains/scripts/arm-none-eabi-tools.sh +``` + +
+ +### LLVM Toolchain for Linux (Ubuntu) and WSL2 +```bash +wget https://apt.llvm.org/llvm.sh +chmod +x llvm.sh +sudo ./llvm.sh 18 +``` + +Learn more on + +### Python Dependencies + +It's recommended to use a virtual environment to avoid conflicts with system packages. + +**Create and activate a virtual environment:** + +```bash +# Create virtual environment +python3 -m venv venv + +# Activate on Linux/macOS/WSL2 +source venv/bin/activate +``` + +**Install dependencies:** + +```bash +pip install -r utils/python_requirements.txt +``` + +**Note**: Remember to activate the virtual environment each time you work on the project. To deactivate, simply run `deactivate`. + + + + +## Building OS + +Now we are ready to build the OS :) + +### Generating Ninja + +To generate ninja just run `./gn_gen.sh`. This command creates build directory `out/` and disk image for the OS. + +***Note*** you can set some environment variables before running `./gn_gen.sh` to change some parameters, visit [Environment varibles](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/docs/build.md#environment-variables) to learn more. + +#### **Options of ./gn_gen.sh** + +* --target_arch|--target_cpu(deprecated) *value* + * Sets target arch. + * Possible values: + * x86 *(default)* + * x86_64 + * arm32 / arm + * arm64 / aarch64 +* --host *value* + * Sets toolchain to build the OS. + * Possible values: + * gnu *(default)* + * llvm +* --device_type *value* + * Configures OS parts to work in either desktop or mobile mode. + * Possible values: + * d / desktop *(default)* + * m / mobile +* --test_method *value* + * Possible values: + * none *(default)* + * tests + * bench +* --target_board *value* + * See "Available targets" table below. +* --dir *value* + * Creates the build directory with the given name. +* -y|--yes + * Force yes all operations. +* -h|--help + * Prints all options of ./gn_gen.sh. + +So to build xOS for Arm with LLVM you have to generate Ninja files with `./gn_gen.sh --target_arch arm32 --host llvm` + +#### **Environment variables** + +Another option how to configure the project is environment variables. + +* `XOS_QEMU_SMP` + * CPU cores count in the system. +* `XOS_QEMU_X86` + * Path to *qemu-system-i386* executable +* `XOS_QEMU_X86_64` + * Path to *qemu-system-x86_64* executable +* `XOS_QEMU_ARM` + * Path to *qemu-system-arm* executable +* `XOS_QEMU_AA64` + * Path to *qemu-system-aarch64* executable +* `LLVM_BIN_PATH` *(Only with --host llvm)* + * ***Must be set before `./gn_gen.sh`*** + * Path to LLVM bins. + +
+ +### Building + +Move to `out/` directory where the OS will be built. There are several scripts: + +* `build.sh` - builds OS +* `sync.sh` - synchronise files with the disk image +* `run.sh` - launches QEMU or a real device + +The right sequence to run the OS is to build, sync, launch or use `all.sh` which combine these 3 scripts. + +**WSL2 Note**: QEMU graphical output works on Windows 11 by default. On Windows 10, you may need to set `DISPLAY` environment variable if using an X server: +```bash +export DISPLAY=:0 +``` + +### Debugging + +There are several scripts which might help you to debug the OS: + +* `debug.sh` - launches QEMU in debug mode. Debug analog of `run.sh` (available only when run.sh uses QEMU) +* `dll.sh` - Debug analog of `all.sh`. + +Also you can run `gdb` or `lldb` from the `out/` directory, which will automatically load kernel symbols and connect to QEMU in debug mode. + +### Available boards + +***x86*** + +* `i386` - regular x86 (i386). (default) + +***x86_64*** + +* `x86_64` - regular x86_64. (default) + +***Arm32*** + +* `vexpress-a15` - QEMU's vexpress-a15 target. (default) diff --git a/docs/getting_gn.md b/docs/getting_gn.md new file mode 100644 index 0000000..dd66856 --- /dev/null +++ b/docs/getting_gn.md @@ -0,0 +1,26 @@ +# Getting GN + +GN is a meta-build system that generates build files for Ninja. + +## Getting a binary + +You can download the latest version of GN binary for Linux and macOS from Google's build infrastructure + +| MacOS | Linux | +| ------------- | ------------- | +| [amd64](https://chrome-infra-packages.appspot.com/dl/gn/gn/mac-amd64/+/latest)
[arm64](https://chrome-infra-packages.appspot.com/dl/gn/gn/mac-arm64/+/latest) | [amd64](https://chrome-infra-packages.appspot.com/dl/gn/gn/linux-amd64/+/latest)
[arm64](https://chrome-infra-packages.appspot.com/dl/gn/gn/linux-arm64/+/latest) | + +Alternatively, you can build GN from source with a C++17 compiler: + +```bash +git clone https://gn.googlesource.com/gn +cd gn +python build/gen.py +ninja -C out +# To run tests: +out/gn_unittests +``` + +*Note:* On Linux and Mac, the default compiler is clang++, a recent version is expected to be found in PATH. This can be overridden by setting CC, CXX, and AR. + +For more inforamtion, please visit: https://gn.googlesource.com/gn/ \ No newline at end of file diff --git a/docs/getting_qemu.md b/docs/getting_qemu.md new file mode 100644 index 0000000..da35309 --- /dev/null +++ b/docs/getting_qemu.md @@ -0,0 +1,15 @@ +# Getting QEMU + +QEMU is an emulator used for running and debugging xOS. + +### QEMU for MacOS + +```bash +brew install qemu +``` + +### Tools for Linux (Ubuntu) + +```bash +apt install qemu-utils qemu-system-i386 qemu-system-x86_64 qemu-system-arm +``` diff --git a/docs/kernel.md b/docs/kernel.md new file mode 100644 index 0000000..b15af89 --- /dev/null +++ b/docs/kernel.md @@ -0,0 +1,16 @@ +# XKernel + +The XKernel is a unix-like kernel of xOS, supporting x86/x86-64, arm32 and arm64 architectures. + +## Dirs + +* [algo](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/kernel/kernel/algo) contains implementation of algorithms and data structures which are used inside the kernel. +* [drivers](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/kernel/kernel/drivers) contains implementation of drivers for supported platforms. +* [fs](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/kernel/kernel/fs) contains implementation of VFS and file systems which are supported. +* [io](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/kernel/kernel/io) contains implementation of communication parts. +* [libkern](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/kernel/kernel/libkern) is a support library for kernel. +* [mem](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/kernel/kernel/mem) contains implementation of memory managers (both virtual and physical). +* [platform](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/kernel/kernel/platform) contains platform specific code. +* [syscalls](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/kernel/kernel/syscalls) contains implementation of syscalls. +* [tasking](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/kernel/kernel/tasking) contains implementation of tasking-control mechanisms. +* [time](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/kernel/kernel/time) contains implementation of a time manager. \ No newline at end of file diff --git a/docs/libs.md b/docs/libs.md new file mode 100644 index 0000000..13fd542 --- /dev/null +++ b/docs/libs.md @@ -0,0 +1,12 @@ +# Libraries + +The userland of xOS contains several custom libraries + +* [LibC](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/libs/libc) - the standard library for C. +* [LibCxx](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/libs/libcxx) - the standard library for C++, targeting C++17 and above. +* [LibObjC](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/libs/libobjc) - the Objective-C runtime library. +* [LibAPI](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/libs/libapi) the standard API library. +* [LibFoundation](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/libs/libfoundation) - provides a base layer of functionality for apps and libraries which are implemented in C++ and Objective-C. +* [LibIPC](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/libs/libipc) - manages inter-prcess communication for C++. +* [LibG](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/libs/libg) - provides low-level 2D rendering. +* [LibUI](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/libs/libui) - provides the required tools to build UI applications. diff --git a/docs/target_apl.md b/docs/target_apl.md new file mode 100644 index 0000000..bd6af40 --- /dev/null +++ b/docs/target_apl.md @@ -0,0 +1,25 @@ +# Target Apl + +## Introduction + +xOS gets support for `apl` target allowing to run the OS on a real i-device. + +## How to boot + +* Step 1: The process of compiling the OS is similar to other targets. You have to provide `apl` as a `target_board` to GN Build System. More information you can find [on this page](https://code.ayaantunio.me/ayaan/Custom-Operating-System/src/branch/master/docs/build.md). + +* Step 2: To get access to the bootloader you have to jailbreak your i-device. The checkra1n environment is used. You can get the binary at [http://checkra.in/](http://checkra.in/). + +* Step 3: After configuring GN you have to provide path to the checkra1n binary with a $CHECKRAIN env variable. + +* Step 4: Run `./all.sh` from `out/` dir. This will compile the OS, prepare ramdisk and compile a custom version of pongoOS which is used as a bootloader. + + +Note: to turn off xOS, [force reset](https://support.apple.com/en-gb/guide/iphone/iph8903c3ee6/15.0/ios/15.0) your device. + +## Limitations + +Support for `apl` target at a early stage of development. Currently only devices with A7-A9x are supported. We have also plans to get support for AIC and touchscreen. + + +***NOTE: Please ensure you have a backup of your device before applying the jailbreak. While the data loss is unlikely, we are not responsible if something goes wrong. Use it on your own risk.*** \ No newline at end of file diff --git a/firmware/arm32/vexpress-a15.odt b/firmware/arm32/vexpress-a15.odt new file mode 100644 index 0000000..f6be81e --- /dev/null +++ b/firmware/arm32/vexpress-a15.odt @@ -0,0 +1,84 @@ +{ + "name": "vexpress-a15", + "devices": [{ + "name": "ram", + "type": "RAM", + "mem": { + "base": "0x80000000", + "size": "0x10000000" + } + }, + { + "name": "gicv2", + "type": "IC", + "aux1": "0x1000", + "aux2": "0x2000" + }, + { + "name": "pl031", + "type": "RTC", + "flags": "MMIO", + "mem": { + "base": "0x1c170000" + } + }, + { + "name": "pl050k", + "type": "IO", + "flags": "MMIO", + "mem": { + "base": "0x1c060000" + }, + "irq": { + "lane": "44" + } + }, + { + "name": "pl050m", + "type": "IO", + "flags": "MMIO", + "mem": { + "base": "0x1c070000" + }, + "irq": { + "lane": "45" + } + }, + { + "name": "pl111", + "type": "FB", + "flags": "MMIO", + "mem": { + "base": "0x1c1f0000" + } + }, + { + "name": "pl181", + "type": "BUS_CONTROLLER", + "flags": "MMIO", + "mem": { + "base": "0x1c050000" + } + }, + { + "name": "uart", + "type": "UART", + "flags": "MMIO", + "mem": { + "base": "0x1c090000" + } + }, + { + "name": "sp804", + "type": "TIMER", + "flags": "MMIO", + "mem": { + "base": "0x1c110000" + }, + "irq": { + "lane": "34", + "flags": "EDGE_TRIGGER" + } + } + ] +} \ No newline at end of file diff --git a/firmware/arm64/apl.odt b/firmware/arm64/apl.odt new file mode 100644 index 0000000..f29718e --- /dev/null +++ b/firmware/arm64/apl.odt @@ -0,0 +1,35 @@ +{ + "name": "apl_a7", + "devices": [{ + "name": "ram", + "type": "RAM", + "mem": { + "base": "0x0", + "size": "0x0" + } + }, + { + "name": "aa64timer", + "type": "TIMER", + "flags": "MMIO" + }, + { + "name": "ramdisk", + "type": "STORAGE", + "flags": "MMIO", + "mem": { + "base": "0x0", + "size": "0x0" + } + }, + { + "name": "simplefb", + "type": "FB", + "flags": "MMIO", + "mem": { + "base": "0x0", + "size": "0x0" + } + } + ] +} \ No newline at end of file diff --git a/firmware/arm64/qemu_virt.odt b/firmware/arm64/qemu_virt.odt new file mode 100644 index 0000000..7a8c48f --- /dev/null +++ b/firmware/arm64/qemu_virt.odt @@ -0,0 +1,81 @@ +{ + "name": "oemu-virt", + "devices": [{ + "name": "ram", + "type": "RAM", + "mem": { + "base": "0x40000000", + "size": "0x40000000" + } + }, + { + "name": "gicv2", + "type": "IC", + "aux1": "0x0", + "aux2": "0x10000" + }, + { + "name": "pl031", + "type": "RTC", + "flags": "MMIO", + "mem": { + "base": "0x09010000" + } + }, + { + "name": "pl111", + "type": "FB", + "flags": "MMIO", + "mem": { + "base": "0x0b010000" + } + }, + { + "name": "pl181", + "type": "BUS_CONTROLLER", + "flags": "MMIO", + "mem": { + "base": "0x0b020000" + } + }, + { + "name": "uart", + "type": "UART", + "flags": "MMIO", + "mem": { + "base": "0x09000000" + } + }, + { + "name": "aa64timer", + "type": "TIMER", + "flags": "MMIO", + "irq": { + "lane": "30", + "flags": "EDGE_TRIGGER" + } + }, + { + "name": "pl050k", + "type": "IO", + "flags": "MMIO", + "mem": { + "base": "0x0b030000" + }, + "irq": { + "lane": "42" + } + }, + { + "name": "pl050m", + "type": "IO", + "flags": "MMIO", + "mem": { + "base": "0x0b040000" + }, + "irq": { + "lane": "43" + } + } + ] +} \ No newline at end of file diff --git a/firmware/riscv64/riscv64.odt b/firmware/riscv64/riscv64.odt new file mode 100644 index 0000000..1be44af --- /dev/null +++ b/firmware/riscv64/riscv64.odt @@ -0,0 +1,43 @@ +{ + "name": "qemu-virt", + "devices": [{ + "name": "ram", + "type": "RAM", + "mem": { + "base": "0x80000000", + "size": "0x40000000" + } + }, + { + "name": "uart", + "type": "UART", + "flags": "MMIO", + "mem": { + "base": "0x10000000" + } + }, + { + "name": "rv64timer", + "type": "TIMER", + "flags": "MMIO", + "mem": { + "base": "0x2000000" + } + }, + { + "name": "plic", + "type": "IC", + "mem": { + "base": "0x0c000000" + } + }, + { + "name": "virtio", + "type": "BUS", + "mem": { + "base": "0x10001000", + "size": "0x8000" + } + } + ] +} \ No newline at end of file diff --git a/gn_gen.sh b/gn_gen.sh new file mode 100644 index 0000000..491f175 --- /dev/null +++ b/gn_gen.sh @@ -0,0 +1,126 @@ +#!/bin/bash -e + +GREEN='\033[0;32m' +RED='\033[0;31m' +NC='\033[0m' +ERROR="${RED}[ERROR]${NC}" +SUCCESS="${GREEN}[SUCCESS]${NC}" +OUTDIR="out" +FORCEY="NO" +GNARGS="" + +function main() { + while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + print_help + ;; + -y|--yes) + FORCEY="YES" + shift + ;; + --dir) + OUTDIR="$2" + shift + shift + ;; + # All other flags are passed to GN. + --*) + GNARGS+="${1:2}=" + shift + ;; + *) + GNARGS+="\"$1\"" + shift + ;; + esac + done + + if [ -d "$OUTDIR" ]; then + if [[ $FORCEY != "YES" ]]; then + read -p "Are you sure you want to overwrite all files in ${OUTDIR} (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + rm -rf $OUTDIR + else + echo "Exiting..." + exit + fi + fi + fi + + gn gen $OUTDIR --args=$GNARGS + if [ $? -ne 0 ]; then echo -e "${ERROR} Can't do gn gen" && exit 1; fi + ninja -C $OUTDIR scripts + if [ $? -ne 0 ]; then echo -e "${ERROR} Can't do ninja -C ${OUTDIR} scripts" && exit 1; fi + chmod +x $OUTDIR/build.sh + chmod +x $OUTDIR/run.sh + chmod +x $OUTDIR/sync.sh + chmod +x $OUTDIR/all.sh + chmod +x $OUTDIR/run_tester.sh + chmod +x $OUTDIR/debug.sh + chmod +x $OUTDIR/dll.sh + + #building one.img + IMAGE_SIZE=128M + qemu-img create -f raw $OUTDIR/one.img $IMAGE_SIZE + if [ $? -ne 0 ]; then echo -e "${ERROR} Can't create an one.img" && exit 1; fi + MKFS="" # Provide path here + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + MKFS=mkfs + elif [[ "$OSTYPE" == "darwin"* ]]; then + MKFS=/usr/local/opt/e2fsprogs/sbin/mkfs.ext2 + else + echo "Please provide path to MKFS in MKFSBIN env variable" + fi + $MKFS -t ext2 -r 0 -b 1024 $OUTDIR/one.img + if [ $? -ne 0 ]; then echo -e "${ERROR} Can't create an one.img" && exit 1; fi + echo -e "${SUCCESS} Generated files with args: $*" + +} + +function print_help() { + echo "--target_arch {arch} + Sets target arch. + Possible values: + x86 (default) + x86_64 + arm32 / arm + arm64 / aarch64 + riscv64 + +--host {host} + Sets toolchain to build the OS. + Possible values: + gnu (default) + llvm + +--device_type {type} + Configueres OS parts to work in either desktop or mobile mode. + Possible values: + d / desktop (default) + m / mobile + +--test_method {method} + Possible values: + none (default) + tests + bench + +--target_board {board} + Possible values (arm64): + qemu-virt (default) + apl + +--dir {name} + Creates the build directory with the given {name}. + +-y|--yes + Force yes all operations. + +-h|--help + Prints all options of ./gn_gen.sh" + exit +} + +main "$@"; exit \ No newline at end of file diff --git a/kernel/include/algo/bitmap.h b/kernel/include/algo/bitmap.h new file mode 100644 index 0000000..1f2932a --- /dev/null +++ b/kernel/include/algo/bitmap.h @@ -0,0 +1,20 @@ +#ifndef _KERNEL_ALGO_BITMAP_H +#define _KERNEL_ALGO_BITMAP_H + +#include + +struct bitmap { + uint8_t* data; + size_t len; +}; +typedef struct bitmap bitmap_t; + +bitmap_t bitmap_wrap(uint8_t* data, size_t len); +bitmap_t bitmap_allocate(size_t len); +int bitmap_find_space(bitmap_t bitmap, int req); +int bitmap_find_space_aligned(bitmap_t bitmap, int req, int alignment); +int bitmap_set(bitmap_t bitmap, int where); +int bitmap_unset(bitmap_t bitmap, int where); +int bitmap_set_range(bitmap_t bitmap, int start, int len); +int bitmap_unset_range(bitmap_t bitmap, int start, int len); +#endif //_KERNEL_ALGO_BITMAP_H \ No newline at end of file diff --git a/kernel/include/algo/dynamic_array.h b/kernel/include/algo/dynamic_array.h new file mode 100644 index 0000000..2d5d424 --- /dev/null +++ b/kernel/include/algo/dynamic_array.h @@ -0,0 +1,34 @@ +#ifndef _KERNEL_ALGO_DYNAMIC_ARRAY_H +#define _KERNEL_ALGO_DYNAMIC_ARRAY_H + +#include + +// TODO: Speed up bucket search using binary jumps. +struct dynamic_array_bucket { + void* data; + struct dynamic_array_bucket* next; + size_t capacity; + size_t size; +}; +typedef struct dynamic_array_bucket dynamic_array_bucket_t; + +struct dynamic_array { + dynamic_array_bucket_t* head; + dynamic_array_bucket_t* tail; + size_t size; /* number of elements in vector */ + size_t element_size; /* size of elements in bytes */ +}; +typedef struct dynamic_array dynamic_array_t; + +#define dynarr_init(type, v) dynarr_init_of_size_impl(v, sizeof(type), 8) +#define dynarr_init_of_size(type, v, cap) dynarr_init_of_size_impl(v, sizeof(type), cap) + +int dynarr_init_of_size_impl(dynamic_array_t* v, size_t element_size, size_t capacity); +int dynarr_free(dynamic_array_t* v); + +void* dynarr_get(dynamic_array_t* v, int index); +void* dynarr_push(dynamic_array_t* v, void* element); +int dynarr_pop(dynamic_array_t* v); +int dynarr_clear(dynamic_array_t* v); + +#endif // _KERNEL_ALGO_DYNAMIC_ARRAY_H \ No newline at end of file diff --git a/kernel/include/algo/hash.h b/kernel/include/algo/hash.h new file mode 100644 index 0000000..019ea45 --- /dev/null +++ b/kernel/include/algo/hash.h @@ -0,0 +1,11 @@ +#ifndef _KERNEL_ALGO_HASH_H +#define _KERNEL_ALGO_HASH_H + +#include + +#define hashint(hfunc, val) (hfunc((uint8_t*)&val, sizeof(val))) + +uint32_t hash_crc32(uint8_t* data, size_t len); +uint32_t hashstr_crc32(char* data); + +#endif // _KERNEL_ALGO_HASH_H \ No newline at end of file diff --git a/kernel/include/algo/ringbuffer.h b/kernel/include/algo/ringbuffer.h new file mode 100644 index 0000000..d8293cf --- /dev/null +++ b/kernel/include/algo/ringbuffer.h @@ -0,0 +1,39 @@ +#ifndef _KERNEL_ALGO_RINGBUFFER_H +#define _KERNEL_ALGO_RINGBUFFER_H + +#include +#include +#include + +#define RINGBUFFER_STD_SIZE (16 * KB) + +struct __ringbuffer { + kmemzone_t zone; + size_t start; + size_t end; +}; +typedef struct __ringbuffer ringbuffer_t; + +ringbuffer_t ringbuffer_create(size_t size); +static ALWAYS_INLINE ringbuffer_t ringbuffer_create_std() { return ringbuffer_create(RINGBUFFER_STD_SIZE); } +void ringbuffer_free(ringbuffer_t* rbuf); + +ssize_t ringbuffer_space_to_read_from(ringbuffer_t* rbuf, size_t start); +ssize_t ringbuffer_space_to_read(ringbuffer_t* rbuf); +ssize_t ringbuffer_space_to_write(ringbuffer_t* rbuf); + +size_t ringbuffer_read_from(ringbuffer_t* rbuf, size_t ustart, uint8_t __user* buf, size_t siz); +size_t ringbuffer_read_user_from(ringbuffer_t* rbuf, size_t ustart, uint8_t __user* buf, size_t siz); +size_t ringbuffer_read(ringbuffer_t* rbuf, uint8_t*, size_t); +size_t ringbuffer_read_user(ringbuffer_t* rbuf, uint8_t __user* buf, size_t siz); + +size_t ringbuffer_write(ringbuffer_t* rbuf, const uint8_t*, size_t); +size_t ringbuffer_write_user(ringbuffer_t* rbuf, const uint8_t __user* buf, size_t siz); +size_t ringbuffer_write_ignore_bounds(ringbuffer_t* rbuf, const uint8_t* buf, size_t siz); +size_t ringbuffer_write_user_ignore_bounds(ringbuffer_t* rbuf, const uint8_t* __user buf, size_t siz); + +size_t ringbuffer_read_one(ringbuffer_t* rbuf, uint8_t* data); +size_t ringbuffer_write_one(ringbuffer_t* rbuf, uint8_t data); +void ringbuffer_clear(ringbuffer_t* rbuf); + +#endif //_KERNEL_ALGO_RINGBUFFER_H \ No newline at end of file diff --git a/kernel/include/algo/sync_ringbuffer.h b/kernel/include/algo/sync_ringbuffer.h new file mode 100644 index 0000000..81cd9ef --- /dev/null +++ b/kernel/include/algo/sync_ringbuffer.h @@ -0,0 +1,131 @@ +#ifndef _KERNEL_ALGO_SYNC_RINGBUFFER_H +#define _KERNEL_ALGO_SYNC_RINGBUFFER_H + +#include +#include +#include +#include + +struct __sync_ringbuffer { + ringbuffer_t ringbuffer; + spinlock_t lock; +}; +typedef struct __sync_ringbuffer sync_ringbuffer_t; + +static ALWAYS_INLINE sync_ringbuffer_t sync_ringbuffer_create(size_t size) +{ + sync_ringbuffer_t res; + res.ringbuffer = ringbuffer_create(size); + spinlock_init(&res.lock); + return res; +} + +#define sync_ringbuffer_create_std() sync_ringbuffer_create(RINGBUFFER_STD_SIZE) +static ALWAYS_INLINE void sync_ringbuffer_free(sync_ringbuffer_t* buf) +{ + spinlock_acquire(&buf->lock); + ringbuffer_free(&buf->ringbuffer); + spinlock_release(&buf->lock); +} + +static ALWAYS_INLINE ssize_t sync_ringbuffer_space_to_read(sync_ringbuffer_t* buf) +{ + spinlock_acquire(&buf->lock); + ssize_t res = ringbuffer_space_to_read(&buf->ringbuffer); + spinlock_release(&buf->lock); + return res; +} + +static ALWAYS_INLINE ssize_t sync_ringbuffer_space_to_read_from(sync_ringbuffer_t* buf, size_t start) +{ + spinlock_acquire(&buf->lock); + ssize_t res = ringbuffer_space_to_read_from(&buf->ringbuffer, start); + spinlock_release(&buf->lock); + return res; +} +static ALWAYS_INLINE ssize_t sync_ringbuffer_space_to_write(sync_ringbuffer_t* buf) +{ + spinlock_acquire(&buf->lock); + ssize_t res = ringbuffer_space_to_write(&buf->ringbuffer); + spinlock_release(&buf->lock); + return res; +} +static ALWAYS_INLINE size_t sync_ringbuffer_read_from(sync_ringbuffer_t* buf, size_t start, uint8_t* holder, size_t siz) +{ + spinlock_acquire(&buf->lock); + size_t res = ringbuffer_read_from(&buf->ringbuffer, start, holder, siz); + spinlock_release(&buf->lock); + return res; +} +static ALWAYS_INLINE size_t sync_ringbuffer_read_user_from(sync_ringbuffer_t* buf, size_t start, uint8_t __user* holder, size_t siz) +{ + spinlock_acquire(&buf->lock); + size_t res = ringbuffer_read_user_from(&buf->ringbuffer, start, holder, siz); + spinlock_release(&buf->lock); + return res; +} +static ALWAYS_INLINE size_t sync_ringbuffer_read(sync_ringbuffer_t* buf, uint8_t* v, size_t a) +{ + spinlock_acquire(&buf->lock); + size_t res = ringbuffer_read(&buf->ringbuffer, v, a); + spinlock_release(&buf->lock); + return res; +} +static ALWAYS_INLINE size_t sync_ringbuffer_read_user(sync_ringbuffer_t* buf, uint8_t __user* v, size_t a) +{ + spinlock_acquire(&buf->lock); + size_t res = ringbuffer_read_user(&buf->ringbuffer, v, a); + spinlock_release(&buf->lock); + return res; +} +static ALWAYS_INLINE size_t sync_ringbuffer_write(sync_ringbuffer_t* buf, const uint8_t* v, size_t a) +{ + spinlock_acquire(&buf->lock); + size_t res = ringbuffer_write(&buf->ringbuffer, v, a); + spinlock_release(&buf->lock); + return res; +} +static ALWAYS_INLINE size_t sync_ringbuffer_write_user(sync_ringbuffer_t* buf, const uint8_t __user* v, size_t a) +{ + spinlock_acquire(&buf->lock); + size_t res = ringbuffer_write_user(&buf->ringbuffer, v, a); + spinlock_release(&buf->lock); + return res; +} +static ALWAYS_INLINE size_t sync_ringbuffer_write_ignore_bounds(sync_ringbuffer_t* buf, const uint8_t* holder, size_t siz) +{ + spinlock_acquire(&buf->lock); + size_t res = ringbuffer_write_ignore_bounds(&buf->ringbuffer, holder, siz); + spinlock_release(&buf->lock); + return res; +} +static ALWAYS_INLINE size_t sync_ringbuffer_write_user_ignore_bounds(sync_ringbuffer_t* buf, const uint8_t __user* holder, size_t siz) +{ + spinlock_acquire(&buf->lock); + size_t res = ringbuffer_write_user_ignore_bounds(&buf->ringbuffer, holder, siz); + spinlock_release(&buf->lock); + return res; +} +static ALWAYS_INLINE size_t sync_ringbuffer_read_one(sync_ringbuffer_t* buf, uint8_t* data) +{ + spinlock_acquire(&buf->lock); + size_t res = ringbuffer_read_one(&buf->ringbuffer, data); + spinlock_release(&buf->lock); + return res; +} +static ALWAYS_INLINE size_t sync_ringbuffer_write_one(sync_ringbuffer_t* buf, uint8_t data) +{ + spinlock_acquire(&buf->lock); + size_t res = ringbuffer_write_one(&buf->ringbuffer, data); + spinlock_release(&buf->lock); + return res; +} + +static ALWAYS_INLINE void sync_ringbuffer_clear(sync_ringbuffer_t* buf) +{ + spinlock_acquire(&buf->lock); + ringbuffer_clear(&buf->ringbuffer); + spinlock_release(&buf->lock); +} + +#endif //_KERNEL_ALGO_SYNC_RINGBUFFER_H \ No newline at end of file diff --git a/kernel/include/drivers/bits/device.h b/kernel/include/drivers/bits/device.h new file mode 100644 index 0000000..5b347c0 --- /dev/null +++ b/kernel/include/drivers/bits/device.h @@ -0,0 +1,68 @@ +#ifndef _KERNEL_DRIVERS_BITS_DEVICE_H +#define _KERNEL_DRIVERS_BITS_DEVICE_H + +#include +#include + +enum DEVICES_TYPE { + DEVICE_STORAGE = (1 << 0), + DEVICE_SOUND = (1 << 1), + DEVICE_INPUT_SYSTEMS = (1 << 2), + DEVICE_NETWORK = (1 << 3), + DEVICE_DISPLAY = (1 << 4), + DEVICE_BUS_CONTROLLER = (1 << 5), + DEVICE_BRIDGE = (1 << 6), + DEVICE_CHAR = (1 << 7), + DEVICE_RTC = (1 << 8), + DEVICE_UNKNOWN = (1 << 9), +}; + +enum DEVICE_DESC_TYPE { + DEVICE_DESC_PCI, + DEVICE_DESC_DEVTREE, +}; + +struct device_desc_pci { + uint8_t bus; + uint8_t device; + uint8_t function; + uint16_t vendor_id; + uint16_t device_id; + uint8_t class_id; + uint8_t subclass_id; + uint8_t interface_id; + uint8_t revision_id; + uint32_t interrupt; + uint32_t port_base; +}; +typedef struct device_desc_pci device_desc_pci_t; + +struct devtree_entry; +struct device_desc_devtree { + struct devtree_entry* entry; +}; +typedef struct device_desc_devtree device_desc_devtree_t; + +struct device_desc { + int type; + union { + device_desc_pci_t pci; + device_desc_devtree_t devtree; + }; + uint32_t args[4]; +}; +typedef struct device_desc device_desc_t; + +#define DRIVER_ID_EMPTY (0xff) +struct device { + int id; + int type; + bool is_virtual; + int driver_id; + + spinlock_t lock; + device_desc_t device_desc; +}; +typedef struct device device_t; + +#endif // _KERNEL_DRIVERS_BITS_DEVICE_H \ No newline at end of file diff --git a/kernel/include/drivers/bits/driver.h b/kernel/include/drivers/bits/driver.h new file mode 100644 index 0000000..8f63923 --- /dev/null +++ b/kernel/include/drivers/bits/driver.h @@ -0,0 +1,123 @@ +#ifndef _KERNEL_DRIVERS_BITS_DRIVER_H +#define _KERNEL_DRIVERS_BITS_DRIVER_H + +#include + +#define MAX_DRIVER_FUNCTION_COUNT 32 + +// Supported driver's types +enum DRIVERS_TYPE { + DRIVER_STORAGE_DEVICE = (1 << 0), + DRIVER_VIDEO_DEVICE = (1 << 1), + DRIVER_SOUND_DEVICE = (1 << 2), + DRIVER_INPUT_SYSTEMS_DEVICE = (1 << 3), + DRIVER_NETWORK_DEVICE = (1 << 4), + DRIVER_BUS_CONTROLLER = (1 << 5), + DRIVER_CHAR_DEVICE = (1 << 6), + DRIVER_VIRTUAL_FILE_SYSTEM = (1 << 7), + DRIVER_FILE_SYSTEM = (1 << 8), + DRIVER_TIMER = (1 << 9), + DRIVER_RTC = (1 << 10), + DRIVER_TIME_MANAGER = (1 << 11), + DRIVER_VIRTUAL = (1 << 12), +}; + +// Api function of DRIVER_STORAGE type +enum DRIVER_VIDEO_OPERTAION { + DRIVER_VIDEO_INIT = 0x1, // function called when a device is found + DRIVER_VIDEO_SET_RESOLUTION, +}; + +// Api function of DRIVER_STORAGE type +enum DRIVER_STORAGE_OPERTAION { + DRIVER_STORAGE_ADD_DEVICE = 0x1, // function called when a device is found + DRIVER_STORAGE_READ, + DRIVER_STORAGE_WRITE, + DRIVER_STORAGE_FLUSH, + DRIVER_STORAGE_CAPACITY, +}; + +// Api function of DRIVER_INPUT_SYSTEMS type +enum DRIVER_INPUT_SYSTEMS_OPERTAION { + DRIVER_INPUT_SYSTEMS_ADD_DEVICE = 0x1, // function called when a device is found + DRIVER_INPUT_SYSTEMS_GET_LAST_KEY, + DRIVER_INPUT_SYSTEMS_DISCARD_LAST_KEY +}; + +// Api function of DRIVER_CONTROLLER type +enum DRIVER_BUS_CONTROLLER_OPERTAION { + DRIVER_BUS_CONTROLLER_FIND_DEVICE = 0x1, // function called when a device is found +}; + +// Api function of DRIVER_VIRTUAL_FILE_SYSTEM type +enum DRIVER_VIRTUAL_FILE_SYSTEM_OPERTAION { + DRIVER_VIRTUAL_FILE_SYSTEM_ADD_DRIVER = 0x1, + DRIVER_VIRTUAL_FILE_SYSTEM_ADD_DEVICE, + DRIVER_VIRTUAL_FILE_SYSTEM_EJECT_DEVICE, +}; + +// Api function of DRIVER_FILE_SYSTEM type +enum DRIVER_FILE_SYSTEM_OPERTAION { + DRIVER_FILE_SYSTEM_RECOGNIZE = 0x1, + DRIVER_FILE_SYSTEM_PREPARE_FS, + DRIVER_FILE_SYSTEM_EJECT_DEVICE, + + DRIVER_FILE_SYSTEM_OPEN, + DRIVER_FILE_SYSTEM_CAN_READ, + DRIVER_FILE_SYSTEM_CAN_WRITE, + DRIVER_FILE_SYSTEM_READ, + DRIVER_FILE_SYSTEM_WRITE, + DRIVER_FILE_SYSTEM_TRUNCATE, + DRIVER_FILE_SYSTEM_MKDIR, + DRIVER_FILE_SYSTEM_RMDIR, + + DRIVER_FILE_SYSTEM_READ_INODE, + DRIVER_FILE_SYSTEM_WRITE_INODE, + DRIVER_FILE_SYSTEM_FREE_INODE, + DRIVER_FILE_SYSTEM_LOOKUP, + DRIVER_FILE_SYSTEM_GETDENTS, + DRIVER_FILE_SYSTEM_CREATE, + DRIVER_FILE_SYSTEM_UNLINK, + + DRIVER_FILE_SYSTEM_FSTAT, + DRIVER_FILE_SYSTEM_FCHMOD, + DRIVER_FILE_SYSTEM_IOCTL, + DRIVER_FILE_SYSTEM_MMAP, +}; + +enum DRIVER_RTC_OPERTAION { + DRIVER_RTC_GET_TIME, +}; + +struct driver; +struct device; +typedef struct { + void (*recieve_notification)(uintptr_t key, uintptr_t val); + int (*on_start)(); + int (*on_stop)(); + int (*init_with_dev)(struct device* device); +} driver_system_funcs_t; + +enum DRIVER_DESC_FLAGS { + DRIVER_DESC_FLAG_START = (1 << 0), +}; + +struct driver_desc { + int type; + uint32_t flags; + uint32_t listened_device_mask; + uint32_t listened_driver_mask; + void* functions[MAX_DRIVER_FUNCTION_COUNT]; + driver_system_funcs_t system_funcs; +}; +typedef struct driver_desc driver_desc_t; + +struct driver { + int id; + int status; + driver_desc_t desc; + const char* name; +}; +typedef struct driver driver_t; + +#endif // _KERNEL_DRIVERS_BITS_DRIVER_H \ No newline at end of file diff --git a/kernel/include/drivers/bus/x86/ide.h b/kernel/include/drivers/bus/x86/ide.h new file mode 100644 index 0000000..07cfc9e --- /dev/null +++ b/kernel/include/drivers/bus/x86/ide.h @@ -0,0 +1,10 @@ +#ifndef _KERNEL_DRIVERS_BUS_X86_IDE_H +#define _KERNEL_DRIVERS_BUS_X86_IDE_H + +#include +#include + +void ide_install(); +int ide_init_with_dev(device_t* dev); + +#endif // _KERNEL_DRIVERS_BUS_X86_IDE_H diff --git a/kernel/include/drivers/bus/x86/pci.h b/kernel/include/drivers/bus/x86/pci.h new file mode 100644 index 0000000..aa94569 --- /dev/null +++ b/kernel/include/drivers/bus/x86/pci.h @@ -0,0 +1,46 @@ +#ifndef _KERNEL_DRIVERS_BUS_X86_PCI_H +#define _KERNEL_DRIVERS_BUS_X86_PCI_H + +#include +#include +#include +#include + +struct PACKED pcidd { + uint8_t bus; + uint8_t device; + uint8_t function; + + uint16_t vendor_id; + uint16_t device_id; + + uint8_t class_id; + uint8_t subclass_id; + uint8_t interface_id; + uint8_t revision_id; + + uint32_t interrupt; + uint32_t port_base; +}; +typedef struct pcidd pcidd_t; + +enum bar_type { + MEMORY_MAPPED = 0, + INPUT_OUTPUT = 1 +}; + +typedef struct { + char prefetchable; + uint32_t address; + uint8_t type; +} bar_t; + +void pci_install(); +uint32_t pci_read(uint16_t bus, uint16_t device, uint16_t function, uint32_t offset); +void pci_write(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t data); +char pci_has_device_functions(uint8_t bus, uint8_t device); +int pci_find_devices(); +device_desc_t pci_get_device_desriptor(uint8_t bus, uint8_t device, uint8_t function); +uint32_t pci_read_bar(device_t* dev, int bar_id); + +#endif /* _KERNEL_DRIVERS_BUS_X86_PCI_H */ diff --git a/kernel/include/drivers/clock/arm/pl031.h b/kernel/include/drivers/clock/arm/pl031.h new file mode 100644 index 0000000..572ad43 --- /dev/null +++ b/kernel/include/drivers/clock/arm/pl031.h @@ -0,0 +1,21 @@ +#ifndef _KERNEL_DRIVERS_CLOCK_ARM_PL031_H +#define _KERNEL_DRIVERS_CLOCK_ARM_PL031_H + +#include +#include +#include +#include +#include + +struct pl031_registers { + uint32_t data; + uint32_t match; + uint32_t load; + uint32_t control; + // TO BE CONTINUED +}; +typedef struct pl031_registers pl031_registers_t; + +uint32_t pl031_read_rtc(); + +#endif // _KERNEL_DRIVERS_CLOCK_ARM_PL031_H \ No newline at end of file diff --git a/kernel/include/drivers/clock/x86/rtc.h b/kernel/include/drivers/clock/x86/rtc.h new file mode 100644 index 0000000..017b34e --- /dev/null +++ b/kernel/include/drivers/clock/x86/rtc.h @@ -0,0 +1,8 @@ +#ifndef _KERNEL_DRIVERS_CLOCK_X86_RTC_H +#define _KERNEL_DRIVERS_CLOCK_X86_RTC_H + +#include + +uint32_t rtc_load_time(); + +#endif /* _KERNEL_DRIVERS_CLOCK_X86_RTC_H */ \ No newline at end of file diff --git a/kernel/include/drivers/debug/screen.h b/kernel/include/drivers/debug/screen.h new file mode 100644 index 0000000..9bc25c9 --- /dev/null +++ b/kernel/include/drivers/debug/screen.h @@ -0,0 +1,10 @@ +#ifndef _KERNEL_DRIVERS_DEBUG_SCREEN_H +#define _KERNEL_DRIVERS_DEBUG_SCREEN_H + +#include + +struct boot_args; +int screen_setup(struct boot_args* boot_args); +int screen_put_char(char c); + +#endif //_KERNEL_DRIVERS_DEBUG_SCREEN_H \ No newline at end of file diff --git a/kernel/include/drivers/devtree.h b/kernel/include/drivers/devtree.h new file mode 100644 index 0000000..b9aacb9 --- /dev/null +++ b/kernel/include/drivers/devtree.h @@ -0,0 +1,51 @@ +#ifndef _KERNEL_DRIVERS_DEVTREE_H +#define _KERNEL_DRIVERS_DEVTREE_H + +#include +#include +#include + +#define DEVTREE_HEADER_SIGNATURE ("odtr3") +#define DEVTREE_HEADER_SIGNATURE_LEN (sizeof(DEVTREE_HEADER_SIGNATURE) - 1) + +struct PACKED devtree_header { + char signature[8]; + uint32_t revision; + uint32_t flags; + uint32_t entries_count; + uint32_t name_list_offset; +}; +typedef struct devtree_header devtree_header_t; + +#define DEVTREE_ENTRY_FLAGS_MMIO = (1 << 0) +#define DEVTREE_ENTRY_TYPE_IO (0) +#define DEVTREE_ENTRY_TYPE_FB (1) +#define DEVTREE_ENTRY_TYPE_UART (2) +#define DEVTREE_ENTRY_TYPE_RAM (3) +#define DEVTREE_ENTRY_TYPE_STORAGE (4) +#define DEVTREE_ENTRY_TYPE_BUS_CONTROLLER (5) +#define DEVTREE_ENTRY_TYPE_RTC (6) + +struct PACKED devtree_entry { + uint32_t type; + uint32_t flags; + uint64_t region_base; + uint64_t region_size; + uint32_t irq_lane; + uint32_t irq_flags; + uint32_t irq_priority; + uint32_t rel_name_offset; + uint64_t aux1; + uint64_t aux2; + uint64_t aux3; + uint64_t aux4; +}; +typedef struct devtree_entry devtree_entry_t; + +int devtree_init(boot_args_t* boot_args); +devtree_entry_t* devtree_find_device(const char* name); +const char* devtree_name_of_entry(devtree_entry_t* en); +devtree_entry_t* devtree_new_entry(const devtree_entry_t* from); +uint32_t devtree_new_entry_name(const char* ptr); + +#endif // _KERNEL_DRIVERS_DEVTREE_H diff --git a/kernel/include/drivers/driver_manager.h b/kernel/include/drivers/driver_manager.h new file mode 100644 index 0000000..00af44a --- /dev/null +++ b/kernel/include/drivers/driver_manager.h @@ -0,0 +1,57 @@ +#ifndef _KERNEL_DRIVERS_DRIVER_MANAGER_H +#define _KERNEL_DRIVERS_DRIVER_MANAGER_H + +#include +#include +#include +#include + +#define MAX_DRIVERS_COUNT 256 +#define MAX_DEVICES_COUNT 64 + +#define DEVMAN_FUNC_NOTIFY 0x0 +#define DEVMAN_FUNC_DEVICE_START 0x1 +#define DEVMAN_FUNC_DRIVER_START 0x1 +#define DEVMAN_FUNC_DRIVER_EMIT_DRIVER 0x1 +#define DEVMAN_FUNC_DRIVER_EMIT_DEVICE 0x2 + +#define DEFAULT_DRIVER_PRIV (100) + +typedef void (*driver_installation_func_t)(); +#define devman_register_driver_installation_order(func, N) \ + static driver_installation_func_t registered_driver_##func \ + __attribute__((used)) __attribute__((section(".driver_init_sections." #N))) \ + = func + +#define devman_register_driver_installation(func) devman_register_driver_installation_order(func, DEFAULT_DRIVER_PRIV) + +enum DEVMAN_NOTIFICATIONS { + DEVMAN_NOTIFICATION_DEVFS_READY = 0, + DEVMAN_NOTIFICATION_NEW_DRIVER = 1, + DEVMAN_NOTIFICATION_NEW_DEVICE = 2, + DEVMAN_NOTIFICATION_STOP, +}; + +extern driver_t drivers[MAX_DRIVERS_COUNT]; +extern device_t devices[MAX_DEVICES_COUNT]; + +int devman_init(); +int devman_install_drivers(); +void devman_run(); +int devman_register_driver(driver_desc_t driver_info, const char* name); +int devman_register_device(device_desc_t device_info, int type); +device_t* new_virtual_device(int type); +int devman_get_driver_id_by_name(const char* name); +void devman_send_notification(uintptr_t msg, uintptr_t param); + +static inline void* devman_driver_function(int driver_id, int function_id) +{ + return drivers[driver_id].desc.functions[function_id]; +} + +static inline void* devman_function_handler(device_t* dev, int function_id) +{ + return devman_driver_function(dev->driver_id, function_id); +} + +#endif // _KERNEL_DRIVERS_DRIVER_MANAGER_H diff --git a/kernel/include/drivers/graphics/arm/pl111.h b/kernel/include/drivers/graphics/arm/pl111.h new file mode 100644 index 0000000..4bb65d6 --- /dev/null +++ b/kernel/include/drivers/graphics/arm/pl111.h @@ -0,0 +1,49 @@ +#ifndef _KERNEL_DRIVERS_GRAPHICS_ARM_PL111_H +#define _KERNEL_DRIVERS_GRAPHICS_ARM_PL111_H + +#include +#include +#include + +enum PL111RegisterMasks { + MASKDEFINE(PIXELS_PER_LINE, 2, 6), + MASKDEFINE(LINES_PER_PANEL, 0, 10), + + MASKDEFINE(LCD_POWER, 11, 1), + MASKDEFINE(LCD_ENDIAN, 9, 2), + MASKDEFINE(LCD_BGR, 8, 1), + MASKDEFINE(LCD_DUAL, 7, 1), + MASKDEFINE(LCD_TFT, 5, 1), + MASKDEFINE(LCD_BW, 4, 1), + MASKDEFINE(LCD_BPP, 1, 3), + MASKDEFINE(LCD_EN, 0, 1), +}; + +enum PL111Consts { + NUM_TIMINGS = 4, + NUM_PALETTE_WORDS = 0x378, + LCD_16_BPP = 4, // Register constant for 16 bits per pixel + LCD_24_BPP = 5, // Register constant for 24 bits per pixel +}; + +struct pl111_registers { + uint32_t lcd_timing_0; + uint32_t lcd_timing_1; + uint32_t lcd_timing_2; + uint32_t lcd_timing_3; + uint32_t lcd_upbase; + uint32_t lcd_lpbase; + uint32_t lcd_control; + uint32_t lcd_imsc; + uint32_t lcd_ris; + uint32_t lcd_mis; + uint32_t lcd_icr; + uint32_t lcd_upcurr; + uint32_t lcd_lpcurr; + // TO BE CONTINUED +}; +typedef struct pl111_registers pl111_registers_t; + +void pl111_install(); + +#endif //_KERNEL_DRIVERS_GRAPHICS_ARM_PL111_H diff --git a/kernel/include/drivers/graphics/virtio_gpu.h b/kernel/include/drivers/graphics/virtio_gpu.h new file mode 100644 index 0000000..e262ce9 --- /dev/null +++ b/kernel/include/drivers/graphics/virtio_gpu.h @@ -0,0 +1,182 @@ +#ifndef _KERNEL_DRIVERS_GRAPHICS_VIRTIO_GPU_H +#define _KERNEL_DRIVERS_GRAPHICS_VIRTIO_GPU_H + +#include +#include +#include +#include + +enum CtrlType { + // 2d commands + CmdGetDisplayInfo = 0x0100, + CmdResourceCreate2d, + CmdResourceUref, + CmdSetScanout, + CmdResourceFlush, + CmdTransferToHost2d, + CmdResourceAttachBacking, + CmdResourceDetachBacking, + CmdGetCapsetInfo, + CmdGetCapset, + CmdGetEdid, + // cursor commands + CmdUpdateCursor = 0x0300, + CmdMoveCursor, + // success responses + RespOkNoData = 0x1100, + RespOkDisplayInfo, + RespOkCapsetInfo, + RespOkCapset, + RespOkEdid, + // error responses + RespErrUnspec = 0x1200, + RespErrOutOfMemory, + RespErrInvalidScanoutId, + RespErrInvalidResourceId, + RespErrInvalidContextId, + RespErrInvalidParameter, +}; + +struct gpu_dev { + virtio_queue_desc_t queue_desc; + volatile virtio_mmio_registers_t* registers; + uint32_t idx; + uint32_t ack_used_idx; + virtio_buffer_desc_t fb_desc; + size_t width; + size_t height; + int current_fb; +}; +typedef struct gpu_dev gpu_dev_t; + +struct gpu_ctrl_header { + uint32_t ctrl_type; + uint32_t flags; + uint64_t fence_id; + uint32_t ctx_id; + uint32_t padding; +}; +typedef struct gpu_ctrl_header gpu_ctrl_header_t; + +struct gpu_rect { + uint32_t x; + uint32_t y; + uint32_t width; + uint32_t height; +}; +typedef struct gpu_rect gpu_rect_t; + +struct gpu_display_one { + gpu_rect_t r; + uint32_t enabled; + uint32_t flags; +}; +typedef struct gpu_display_one gpu_display_one_t; + +#define MAX_SCANOUTS (16) +typedef struct gpu_resp_display_info { + gpu_ctrl_header_t hdr; + gpu_display_one_t pmodes[MAX_SCANOUTS]; +} gpu_resp_display_info_t; + +typedef struct gpu_get_edid { + gpu_ctrl_header_t hdr; + uint32_t scanout; + uint32_t padding; +} gpu_get_edid_t; + +typedef struct gpu_resp_edid { + gpu_ctrl_header_t hdr; + uint32_t size; + uint32_t padding; + uint8_t edid[1024]; +} gpu_resp_edid_t; + +typedef enum gpu_formats { + GPU_FORMAT_B8G8R8A8Unorm = 1, + GPU_FORMAT_B8G8R8X8Unorm = 2, + GPU_FORMAT_A8R8G8B8Unorm = 3, + GPU_FORMAT_X8R8G8B8Unorm = 4, + GPU_FORMAT_R8G8B8A8Unorm = 67, + GPU_FORMAT_X8B8G8R8Unorm = 68, + GPU_FORMAT_A8B8G8R8Unorm = 121, + GPU_FORMAT_R8G8B8X8Unorm = 134, +} gpu_formats_t; + +typedef struct gpu_resource_create_2d { + gpu_ctrl_header_t hdr; + uint32_t resource_id; + gpu_formats_t format; + uint32_t width; + uint32_t height; +} gpu_resource_create_2d_t; + +typedef struct gpu_resource_unref { + gpu_ctrl_header_t hdr; + uint32_t resource_id; + uint32_t padding; +} gpu_resource_unref_t; + +typedef struct gpu_set_scanout { + gpu_ctrl_header_t hdr; + gpu_rect_t r; + uint32_t scanout_id; + uint32_t resource_id; +} gpu_set_scanout_t; + +typedef struct gpu_resource_flush { + gpu_ctrl_header_t hdr; + gpu_rect_t r; + uint32_t resource_id; + uint32_t padding; +} gpu_resource_flush_t; + +typedef struct gpu_transfer_to_host_2d { + gpu_ctrl_header_t hdr; + gpu_rect_t r; + uint64_t offset; + uint32_t resource_id; + uint32_t padding; +} gpu_transfer_to_host_2d_t; + +typedef struct gpu_attach_backing { + gpu_ctrl_header_t hdr; + uint32_t resource_id; + uint32_t nr_entries; +} gpu_attach_backing_t; + +typedef struct gpu_mem_entry { + uint64_t addr; + uint32_t length; + uint32_t padding; +} gpu_mem_entry_t; + +typedef struct gpu_detach_backing { + gpu_ctrl_header_t hdr; + uint32_t resource_id; + uint32_t padding; +} gpu_detach_backing_t; + +typedef struct gpu_cursor_pos { + uint32_t scanout_id; + uint32_t x; + uint32_t y; + uint32_t padding; +} gpu_cursor_pos_t; + +typedef struct gpu_update_cursor { + gpu_ctrl_header_t hdr; + gpu_cursor_pos_t pos; + uint32_t resource_id; + uint32_t hot_x; + uint32_t hot_y; + uint32_t padding; +} gpu_update_cursor_t; + +typedef struct gpu_request { + void* request; + void* response; + void* alloc_start; +} gpu_request_t; + +#endif //_KERNEL_DRIVERS_GRAPHICS_VIRTIO_GPU_H \ No newline at end of file diff --git a/kernel/include/drivers/graphics/x86/bga.h b/kernel/include/drivers/graphics/x86/bga.h new file mode 100644 index 0000000..e208c72 --- /dev/null +++ b/kernel/include/drivers/graphics/x86/bga.h @@ -0,0 +1,12 @@ +#ifndef _KERNEL_DRIVERS_GRAPHICS_X86_BGA_H +#define _KERNEL_DRIVERS_GRAPHICS_X86_BGA_H + +#include +#include +#include +#include + +void bga_install(); +int bga_init_with_dev(device_t* dev); + +#endif //_KERNEL_DRIVERS_GRAPHICS_X86_BGA_H diff --git a/kernel/include/drivers/io/arm/pl050.h b/kernel/include/drivers/io/arm/pl050.h new file mode 100644 index 0000000..a3c0552 --- /dev/null +++ b/kernel/include/drivers/io/arm/pl050.h @@ -0,0 +1,20 @@ +#ifndef _KERNEL_DRIVERS_IO_ARM_PL050_H +#define _KERNEL_DRIVERS_IO_ARM_PL050_H + +#include +#include +#include + +struct pl050_registers { + uint32_t cr; // control register (rw) + uint32_t stat; // status register (r) + uint32_t data; // data register (rw) + uint32_t clk; // clock divisor register (rw) + uint32_t ir; +}; +typedef struct pl050_registers pl050_registers_t; + +void pl050_keyboard_install(); +void pl050_mouse_install(); + +#endif //_KERNEL_DRIVERS_IO_ARM_PL050_H diff --git a/kernel/include/drivers/io/keyboard.h b/kernel/include/drivers/io/keyboard.h new file mode 100644 index 0000000..054a689 --- /dev/null +++ b/kernel/include/drivers/io/keyboard.h @@ -0,0 +1,186 @@ +#ifndef _KERNEL_DRIVERS_IO_KEYBOARD_H +#define _KERNEL_DRIVERS_IO_KEYBOARD_H + +#include + +enum KEYCODE { + + // Alphanumeric keys //////////////// + KEY_CTRLC = '\003', + + KEY_SPACE = ' ', + KEY_0 = '0', + KEY_1 = '1', + KEY_2 = '2', + KEY_3 = '3', + KEY_4 = '4', + KEY_5 = '5', + KEY_6 = '6', + KEY_7 = '7', + KEY_8 = '8', + KEY_9 = '9', + + KEY_A = 'a', + KEY_B = 'b', + KEY_C = 'c', + KEY_D = 'd', + KEY_E = 'e', + KEY_F = 'f', + KEY_G = 'g', + KEY_H = 'h', + KEY_I = 'i', + KEY_J = 'j', + KEY_K = 'k', + KEY_L = 'l', + KEY_M = 'm', + KEY_N = 'n', + KEY_O = 'o', + KEY_P = 'p', + KEY_Q = 'q', + KEY_R = 'r', + KEY_S = 's', + KEY_T = 't', + KEY_U = 'u', + KEY_V = 'v', + KEY_W = 'w', + KEY_X = 'x', + KEY_Y = 'y', + KEY_Z = 'z', + + KEY_RETURN = '\r', + KEY_ESCAPE = 0x1001, + KEY_BACKSPACE = '\b', + + // Arrow keys //////////////////////// + + KEY_UP = 0x1100, + KEY_DOWN = 0x1101, + KEY_LEFT = 0x1102, + KEY_RIGHT = 0x1103, + + // Function keys ///////////////////// + + KEY_F1 = 0x1201, + KEY_F2 = 0x1202, + KEY_F3 = 0x1203, + KEY_F4 = 0x1204, + KEY_F5 = 0x1205, + KEY_F6 = 0x1206, + KEY_F7 = 0x1207, + KEY_F8 = 0x1208, + KEY_F9 = 0x1209, + KEY_F10 = 0x120a, + KEY_F11 = 0x120b, + KEY_F12 = 0x120b, + KEY_F13 = 0x120c, + KEY_F14 = 0x120d, + KEY_F15 = 0x120e, + + KEY_DOT = '.', + KEY_COMMA = ',', + KEY_COLON = ':', + KEY_SEMICOLON = ';', + KEY_SLASH = '/', + KEY_BACKSLASH = '\\', + KEY_PLUS = '+', + KEY_MINUS = '-', + KEY_ASTERISK = '*', + KEY_EXCLAMATION = '!', + KEY_QUESTION = '?', + KEY_QUOTEDOUBLE = '\"', + KEY_QUOTE = '\'', + KEY_EQUAL = '=', + KEY_HASH = '#', + KEY_PERCENT = '%', + KEY_AMPERSAND = '&', + KEY_UNDERSCORE = '_', + KEY_LEFTPARENTHESIS = '(', + KEY_RIGHTPARENTHESIS = ')', + KEY_LEFTBRACKET = '[', + KEY_RIGHTBRACKET = ']', + KEY_LEFTCURL = '{', + KEY_RIGHTCURL = '}', + KEY_DOLLAR = '$', + KEY_POUND = 0, + KEY_EURO = '$', + KEY_LESS = '<', + KEY_GREATER = '>', + KEY_BAR = '|', + KEY_GRAVE = '`', + KEY_TILDE = '~', + KEY_AT = '@', + KEY_CARRET = '^', + + // Numeric keypad ////////////////////// + + KEY_KP_0 = '0', + KEY_KP_1 = '1', + KEY_KP_2 = '2', + KEY_KP_3 = '3', + KEY_KP_4 = '4', + KEY_KP_5 = '5', + KEY_KP_6 = '6', + KEY_KP_7 = '7', + KEY_KP_8 = '8', + KEY_KP_9 = '9', + KEY_KP_PLUS = '+', + KEY_KP_MINUS = '-', + KEY_KP_DECIMAL = '.', + KEY_KP_DIVIDE = '/', + KEY_KP_ASTERISK = '*', + KEY_KP_NUMLOCK = 0x300f, + KEY_KP_ENTER = 0x3010, + + KEY_TAB = 0x4000, + KEY_CAPSLOCK = 0x4001, + + // Modify keys //////////////////////////// + + KEY_LSHIFT = 0x4002, + KEY_LCTRL = 0x4003, + KEY_LALT = 0x4004, + KEY_LWIN = 0x4005, + KEY_RSHIFT = 0x4006, + KEY_RCTRL = 0x4007, + KEY_RALT = 0x4008, + KEY_RWIN = 0x4009, + + KEY_INSERT = 0x400a, + KEY_DELETE = 0x400b, + KEY_HOME = 0x400c, + KEY_END = 0x400d, + KEY_PAGEUP = 0x400e, + KEY_PAGEDOWN = 0x400f, + KEY_SCROLLLOCK = 0x4010, + KEY_PAUSE = 0x4011, + + // Multimedia keys //////////////////////// + + KEY_PREV_TRACK = 0x5001, + KEY_NEXT_TRACK = 0x5002, + KEY_MUTE = 0x5003, + KEY_CALC = 0x5004, + KEY_PLAY = 0x5005, + KEY_STOP = 0x5006, + KEY_VOL_DOWN = 0x5007, + KEY_VOL_UP = 0x5008, + + KEY_WWW_HOME = 0x500a, + + KEY_UNKNOWN, + KEY_NUMKEYCODES +}; + +typedef uint32_t key_t; + +/* The keyboard packet should be aligned to 4 bytes */ +struct kbd_packet { + key_t key; +}; +typedef struct kbd_packet kbd_packet_t; + +int generic_keyboard_create_devfs(); +void generic_keyboard_init(); +void generic_emit_key_set1(uint32_t scancode); + +#endif //_KERNEL_DRIVERS_IO_KEYBOARD_H \ No newline at end of file diff --git a/kernel/include/drivers/io/keyboard_mappings/scancode_set1.h b/kernel/include/drivers/io/keyboard_mappings/scancode_set1.h new file mode 100644 index 0000000..025ebd3 --- /dev/null +++ b/kernel/include/drivers/io/keyboard_mappings/scancode_set1.h @@ -0,0 +1,180 @@ +#include + +static key_t _scancode_set1[] = { + KEY_UNKNOWN, // 0 + KEY_ESCAPE, // 1 + KEY_1, // 2 + KEY_2, // 3 + KEY_3, // 4 + KEY_4, // 5 + KEY_5, // 6 + KEY_6, // 7 + KEY_7, // 8 + KEY_8, // 9 + KEY_9, // 0xa + KEY_0, // 0xb + KEY_MINUS, // 0xc + KEY_EQUAL, // 0xd + KEY_BACKSPACE, // 0xe + KEY_TAB, // 0xf + KEY_Q, // 0x10 + KEY_W, // 0x11 + KEY_E, // 0x12 + KEY_R, // 0x13 + KEY_T, // 0x14 + KEY_Y, // 0x15 + KEY_U, // 0x16 + KEY_I, // 0x17 + KEY_O, // 0x18 + KEY_P, // 0x19 + KEY_LEFTBRACKET, // 0x1a + KEY_RIGHTBRACKET, // 0x1b + KEY_RETURN, // 0x1c + KEY_LCTRL, // 0x1d + KEY_A, // 0x1e + KEY_S, // 0x1f + KEY_D, // 0x20 + KEY_F, // 0x21 + KEY_G, // 0x22 + KEY_H, // 0x23 + KEY_J, // 0x24 + KEY_K, // 0x25 + KEY_L, // 0x26 + KEY_SEMICOLON, // 0x27 + KEY_QUOTE, // 0x28 + KEY_GRAVE, // 0x29 + KEY_LSHIFT, // 0x2a + KEY_BACKSLASH, // 0x2b + KEY_Z, // 0x2c + KEY_X, // 0x2d + KEY_C, // 0x2e + KEY_V, // 0x2f + KEY_B, // 0x30 + KEY_N, // 0x31 + KEY_M, // 0x32 + KEY_COMMA, // 0x33 + KEY_DOT, // 0x34 + KEY_SLASH, // 0x35 + KEY_RSHIFT, // 0x36 + KEY_KP_ASTERISK, // 0x37 + KEY_RALT, // 0x38 + KEY_SPACE, // 0x39 + KEY_CAPSLOCK, // 0x3a + KEY_F1, // 0x3b + KEY_F2, // 0x3c + KEY_F3, // 0x3d + KEY_F4, // 0x3e + KEY_F5, // 0x3f + KEY_F6, // 0x40 + KEY_F7, // 0x41 + KEY_F8, // 0x42 + KEY_F9, // 0x43 + KEY_F10, // 0x44 + KEY_KP_NUMLOCK, // 0x45 + KEY_SCROLLLOCK, // 0x46 + KEY_HOME, // 0x47 + KEY_KP_8, // 0x48 //keypad up arrow + KEY_PAGEUP, // 0x49 + KEY_KP_2, // 0x50 //keypad down arrow + KEY_KP_3, // 0x51 //keypad page down + KEY_KP_0, // 0x52 //keypad insert key + KEY_KP_DECIMAL, // 0x53 //keypad delete key + KEY_UNKNOWN, // 0x54 + KEY_UNKNOWN, // 0x55 + KEY_UNKNOWN, // 0x56 + KEY_F11, // 0x57 + KEY_F12 // 0x58 +}; + +static key_t _scancode_set1_upper[] = { + KEY_UNKNOWN, // 0 + KEY_UNKNOWN, // 1 + KEY_UNKNOWN, // 2 + KEY_UNKNOWN, // 3 + KEY_UNKNOWN, // 4 + KEY_UNKNOWN, // 5 + KEY_UNKNOWN, // 6 + KEY_UNKNOWN, // 7 + KEY_UNKNOWN, // 8 + KEY_UNKNOWN, // 9 + KEY_UNKNOWN, // 0xa + KEY_UNKNOWN, // 0xb + KEY_UNKNOWN, // 0xc + KEY_UNKNOWN, // 0xd + KEY_UNKNOWN, // 0xe + KEY_UNKNOWN, // 0xf + KEY_PREV_TRACK, // 0x10 + KEY_UNKNOWN, // 0x11 + KEY_UNKNOWN, // 0x12 + KEY_UNKNOWN, // 0x13 + KEY_UNKNOWN, // 0x14 + KEY_UNKNOWN, // 0x15 + KEY_UNKNOWN, // 0x16 + KEY_UNKNOWN, // 0x17 + KEY_UNKNOWN, // 0x18 + KEY_NEXT_TRACK, // 0x19 + KEY_UNKNOWN, // 0x1a + KEY_UNKNOWN, // 0x1b + KEY_KP_ENTER, // 0x1c + KEY_RCTRL, // 0x1d + KEY_UNKNOWN, // 0x1e + KEY_UNKNOWN, // 0x1f + KEY_MUTE, // 0x20 + KEY_CALC, // 0x21 + KEY_PLAY, // 0x22 + KEY_UNKNOWN, // 0x23 + KEY_STOP, // 0x24 + KEY_UNKNOWN, // 0x25 + KEY_UNKNOWN, // 0x26 + KEY_UNKNOWN, // 0x27 + KEY_UNKNOWN, // 0x28 + KEY_UNKNOWN, // 0x29 + KEY_UNKNOWN, // 0x2a + KEY_UNKNOWN, // 0x2b + KEY_UNKNOWN, // 0x2c + KEY_UNKNOWN, // 0x2d + KEY_VOL_DOWN, // 0x2e + KEY_UNKNOWN, // 0x2f + KEY_VOL_UP, // 0x30 + KEY_UNKNOWN, // 0x31 + KEY_WWW_HOME, // 0x32 + KEY_UNKNOWN, // 0x33 + KEY_UNKNOWN, // 0x34 + KEY_NUMKEYCODES, // 0x35 + KEY_UNKNOWN, // 0x36 + KEY_UNKNOWN, // 0x37 + KEY_RALT, // 0x38 + KEY_UNKNOWN, // 0x39 + KEY_UNKNOWN, // 0x3a + KEY_UNKNOWN, // 0x3b + KEY_UNKNOWN, // 0x3c + KEY_UNKNOWN, // 0x3d + KEY_UNKNOWN, // 0x3e + KEY_UNKNOWN, // 0x3f + KEY_UNKNOWN, // 0x40 + KEY_UNKNOWN, // 0x41 + KEY_UNKNOWN, // 0x42 + KEY_UNKNOWN, // 0x43 + KEY_UNKNOWN, // 0x44 + KEY_UNKNOWN, // 0x45 + KEY_UNKNOWN, // 0x46 + KEY_HOME, // 0x47 + KEY_UP, // 0x48 + KEY_PAGEUP, // 0x49 + KEY_UNKNOWN, // 0x4a + KEY_LEFT, // 0x4b + KEY_UNKNOWN, // 0x4c + KEY_RIGHT, // 0x4d + KEY_UNKNOWN, // 0x4e + KEY_END, // 0x4f + KEY_DOWN, // 0x50 + KEY_PAGEDOWN, // 0x51 + KEY_INSERT, // 0x52 + KEY_DELETE // 0x53 +}; + +static inline key_t generic_keyboard_get_keycode_set1(uint32_t scancode) +{ + key_t* lookup_table[] = { _scancode_set1, _scancode_set1_upper }; + return lookup_table[(scancode >> 8) & 1][scancode & ~((uint32_t)0x100)]; +} \ No newline at end of file diff --git a/kernel/include/drivers/io/mouse.h b/kernel/include/drivers/io/mouse.h new file mode 100644 index 0000000..b3c0cd8 --- /dev/null +++ b/kernel/include/drivers/io/mouse.h @@ -0,0 +1,19 @@ +#ifndef _KERNEL_DRIVERS_IO_MOUSE_H +#define _KERNEL_DRIVERS_IO_MOUSE_H + +#include + +/* The mouse packet should be aligned to 4 bytes */ +struct mouse_packet { + int16_t x_offset; + int16_t y_offset; + uint16_t button_states; + int16_t wheel_data; +}; +typedef struct mouse_packet mouse_packet_t; + +int generic_mouse_create_devfs(); +void generic_mouse_init(); +void generic_mouse_send_packet(mouse_packet_t* packet); + +#endif //_KERNEL_DRIVERS_IO_MOUSE_H \ No newline at end of file diff --git a/kernel/include/drivers/io/virtio_input.h b/kernel/include/drivers/io/virtio_input.h new file mode 100644 index 0000000..86aa317 --- /dev/null +++ b/kernel/include/drivers/io/virtio_input.h @@ -0,0 +1,28 @@ +#ifndef _KERNEL_DRIVERS_STORAGE_VIRTIO_INPUT_H +#define _KERNEL_DRIVERS_STORAGE_VIRTIO_INPUT_H + +#include +#include +#include +#include +#include + +struct virtio_input_event { + int16_t event_type; + int16_t code; + int32_t value; +}; +typedef struct virtio_input_event virtio_input_event_t; + +struct virtio_input_dev { + virtio_queue_desc_t event_queue_desc; + virtio_queue_desc_t status_queue_desc; + uint32_t status_ack_used_idx; + uint32_t event_idx; + uint32_t event_ack_used_idx; + virtio_buffer_desc_t event_buffer_desc; + irq_line_t irq_line; +}; +typedef struct virtio_input_dev virtio_input_dev_t; + +#endif //_KERNEL_DRIVERS_STORAGE_VIRTIO_INPUT_H \ No newline at end of file diff --git a/kernel/include/drivers/io/x86/keyboard.h b/kernel/include/drivers/io/x86/keyboard.h new file mode 100644 index 0000000..c312a95 --- /dev/null +++ b/kernel/include/drivers/io/x86/keyboard.h @@ -0,0 +1,13 @@ +#ifndef _KERNEL_DRIVERS_IO_X86_KEYBOARD_H +#define _KERNEL_DRIVERS_IO_X86_KEYBOARD_H + +#include +#include + +void kbdriver_install(); +int kbdriver_run(); + +uint32_t kbdriver_get_last_key(); +void kbdriver_discard_last_key(); + +#endif diff --git a/kernel/include/drivers/io/x86/mouse.h b/kernel/include/drivers/io/x86/mouse.h new file mode 100644 index 0000000..540e1b2 --- /dev/null +++ b/kernel/include/drivers/io/x86/mouse.h @@ -0,0 +1,9 @@ +#ifndef _KERNEL_DRIVERS_IO_X86_MOUSE_H +#define _KERNEL_DRIVERS_IO_X86_MOUSE_H + +#include +#include + +void mouse_install(); + +#endif // _KERNEL_DRIVERS_IO_X86_MOUSE_H diff --git a/kernel/include/drivers/irq/arm/gicv2.h b/kernel/include/drivers/irq/arm/gicv2.h new file mode 100644 index 0000000..d7ebdf8 --- /dev/null +++ b/kernel/include/drivers/irq/arm/gicv2.h @@ -0,0 +1,69 @@ +#ifndef _KERNEL_DRIVERS_IRQ_ARM_GICV2_H +#define _KERNEL_DRIVERS_IRQ_ARM_GICV2_H + +#include +#include +#include +#include + +enum GICDControlMasks { + MASKDEFINE(GICD_ENABLE, 0, 1), +}; + +enum GICCControlMasks { + MASKDEFINE(GICC_ENABLE_GR1, 0, 1), + MASKDEFINE(GICC_FIQ_BYP_DIS_GR1, 5, 1), + MASKDEFINE(GICC_IRQ_BYP_DIS_GR1, 6, 1), + MASKDEFINE(GICC_EO_IMODE_NS, 9, 1), +}; + +struct gicv2_distributor_registers { + uint32_t control; + uint32_t typer; + uint32_t iidr; + SKIP(0x008 + 0x4, 0x080); + uint32_t igroup[8]; + SKIP(0x09C + 0x4, 0x100); + uint32_t isenabler[8]; + SKIP(0x11C + 0x4, 0x180); + uint32_t icenabler[8]; + SKIP(0x19C + 0x4, 0x200); + uint32_t ispendr[8]; + SKIP(0x21C + 0x4, 0x280); + uint32_t icpendr[8]; + SKIP(0x29C + 0x4, 0x300); + uint32_t isactiver[8]; + SKIP(0x31C + 0x4, 0x380); + uint32_t icactiver[8]; + SKIP(0x39C + 0x4, 0x400); + uint32_t ipriorityr[64]; + SKIP(0x4FC + 0x4, 0x800); + uint32_t itargetsr[64]; + SKIP(0x8FC + 0x4, 0xC00); + uint32_t icfgr[16]; + // TO BE CONTINUED +}; +typedef struct gicv2_distributor_registers gicv2_distributor_registers_t; + +struct gicv2_cpu_interface_registers { + uint32_t control; + uint32_t pmr; + uint32_t bpr; + uint32_t iar; + uint32_t eoir; + uint32_t hppir; + uint32_t abpr; + uint32_t aiar; + uint32_t aeoir; + uint32_t ahppir; + // TO BE CONTINUED +}; +typedef struct gicv2_cpu_interface_registers gicv2_cpu_interface_registers_t; + +void gicv2_enable_irq(irq_line_t id, irq_priority_t prior, irq_flags_t flags, int cpu_mask); +void gicv2_install(); +void gicv2_install_secondary_cpu(); +uint32_t gicv2_interrupt_descriptor(); +void gicv2_end(uint32_t int_disc); + +#endif //_KERNEL_DRIVERS_IRQ_ARM_GICV2_H diff --git a/kernel/include/drivers/irq/irq_api.h b/kernel/include/drivers/irq/irq_api.h new file mode 100644 index 0000000..d615f5b --- /dev/null +++ b/kernel/include/drivers/irq/irq_api.h @@ -0,0 +1,35 @@ +#ifndef _KERNEL_DRIVERS_IRQ_IRQ_API_H +#define _KERNEL_DRIVERS_IRQ_IRQ_API_H + +#include + +// This value shows the maximum number of irqs OS supports. It is irqdev independent, +// thus irqdev implementations should double check the irqlines. +#define IRQ_HANDLERS_MAX 256 + +#define ALL_CPU_MASK 0xff +#define BOOT_CPU_MASK 0x01 + +typedef int irq_flags_t; +typedef int irq_line_t; +typedef uint8_t irq_priority_t; +typedef void (*irq_handler_t)(irq_line_t line); + +// Currently flags maps to devtree irq_flags. +// Later we might need to enhance irq_flags_from_devtree() to use as translator. +#define IRQ_FLAG_EDGE_TRIGGERED (1 << 0) + +struct irqdev_descritptor { + uint32_t (*interrupt_descriptor)(); + void (*end_interrupt)(uint32_t int_desc); + void (*enable_irq)(irq_line_t line, irq_priority_t prior, irq_flags_t type, int cpu_mask); +}; +typedef struct irqdev_descritptor irqdev_descritptor_t; + +static inline irq_flags_t irq_flags_from_devtree(uint32_t devtree_irq_flags) { return (irq_flags_t)devtree_irq_flags; } + +void irq_register_handler(irq_line_t line, irq_priority_t prior, irq_flags_t flags, irq_handler_t func, int cpu_mask); +void irq_set_dev(irqdev_descritptor_t irqdev_desc); +irq_line_t irqline_from_id(int id); + +#endif \ No newline at end of file diff --git a/kernel/include/drivers/irq/riscv/plic.h b/kernel/include/drivers/irq/riscv/plic.h new file mode 100644 index 0000000..8dde63b --- /dev/null +++ b/kernel/include/drivers/irq/riscv/plic.h @@ -0,0 +1,12 @@ +#ifndef _KERNEL_DRIVERS_IRQ_RISCV_PLIC_H +#define _KERNEL_DRIVERS_IRQ_RISCV_PLIC_H + +#include +#include + +void plic_install(); +void plic_enable_irq(irq_line_t id, irq_priority_t prior, irq_flags_t flags, int cpu_mask); +uint32_t plic_interrupt_descriptor(); +void plic_end(uint32_t id); + +#endif //_KERNEL_DRIVERS_IRQ_RISCV_PLIC_H \ No newline at end of file diff --git a/kernel/include/drivers/irq/x86/pic.h b/kernel/include/drivers/irq/x86/pic.h new file mode 100644 index 0000000..8546c05 --- /dev/null +++ b/kernel/include/drivers/irq/x86/pic.h @@ -0,0 +1,14 @@ +#ifndef _KERNEL_DRIVERS_IRQ_X86_PIC_H +#define _KERNEL_DRIVERS_IRQ_X86_PIC_H + +#include + +#define MASTER_PIC_CMD 0x0020 +#define MASTER_PIC_DATA 0x0021 +#define SLAVE_PIC_CMD 0x00A0 +#define SLAVE_PIC_DATA 0x00A1 +#define ICW4_8086 0x01 + +void pic_remap(unsigned int offset1, unsigned int offset2); + +#endif \ No newline at end of file diff --git a/kernel/include/drivers/serial/arm/uart.h b/kernel/include/drivers/serial/arm/uart.h new file mode 100644 index 0000000..b994fc2 --- /dev/null +++ b/kernel/include/drivers/serial/arm/uart.h @@ -0,0 +1,9 @@ +#ifndef _KERNEL_DRIVERS_SERIAL_ARM_UART_H +#define _KERNEL_DRIVERS_SERIAL_ARM_UART_H + +#include +#include + +void uart_remap(); + +#endif /* _KERNEL_DRIVERS_SERIAL_ARM_UART_H */ \ No newline at end of file diff --git a/kernel/include/drivers/serial/riscv/uart.h b/kernel/include/drivers/serial/riscv/uart.h new file mode 100644 index 0000000..b2276d7 --- /dev/null +++ b/kernel/include/drivers/serial/riscv/uart.h @@ -0,0 +1,9 @@ +#ifndef _KERNEL_DRIVERS_SERIAL_RISCV_UART_H +#define _KERNEL_DRIVERS_SERIAL_RISCV_UART_H + +#include +#include + +void uart_remap(); + +#endif /* _KERNEL_DRIVERS_SERIAL_RISCV_UART_H */ \ No newline at end of file diff --git a/kernel/include/drivers/serial/uart_api.h b/kernel/include/drivers/serial/uart_api.h new file mode 100644 index 0000000..1666454 --- /dev/null +++ b/kernel/include/drivers/serial/uart_api.h @@ -0,0 +1,11 @@ +#ifndef _KERNEL_DRIVERS_SERIAL_UART_API_H +#define _KERNEL_DRIVERS_SERIAL_UART_API_H + +#include + +struct boot_args; +void uart_setup(struct boot_args* boot_args); +int uart_write(uint8_t data); +int uart_read(uint8_t* data); + +#endif //_KERNEL_DRIVERS_SERIAL_UART_API_H \ No newline at end of file diff --git a/kernel/include/drivers/serial/x86/uart.h b/kernel/include/drivers/serial/x86/uart.h new file mode 100644 index 0000000..bc248c3 --- /dev/null +++ b/kernel/include/drivers/serial/x86/uart.h @@ -0,0 +1,12 @@ +#ifndef _KERNEL_DRIVERS_SERIAL_X86_UART_H +#define _KERNEL_DRIVERS_SERIAL_X86_UART_H + +#include +#include + +#define COM1 0x3F8 +#define COM2 0x2F8 +#define COM3 0x3E8 +#define COM4 0x2E8 + +#endif //_KERNEL_DRIVERS_SERIAL_X86_UART_H \ No newline at end of file diff --git a/kernel/include/drivers/storage/arm/pl181.h b/kernel/include/drivers/storage/arm/pl181.h new file mode 100644 index 0000000..848cc08 --- /dev/null +++ b/kernel/include/drivers/storage/arm/pl181.h @@ -0,0 +1,74 @@ +#ifndef _KERNEL_DRIVERS_STORAGE_ARM_PL181_H +#define _KERNEL_DRIVERS_STORAGE_ARM_PL181_H + +#include +#include +#include + +#define PL181_SECTOR_SIZE 512 + +enum PL181CommandMasks { + MASKDEFINE(MMC_CMD_IDX, 0, 6), + MASKDEFINE(MMC_CMD_RESP, 6, 1), + MASKDEFINE(MMC_CMD_LONG_RESP, 7, 1), + MASKDEFINE(MMC_CMD_INTERRUPT, 8, 1), + MASKDEFINE(MMC_CMD_PENDING, 9, 1), + MASKDEFINE(MMC_CMD_ENABLE, 10, 1), +}; + +enum PL181StatusMasks { + MASKDEFINE(MMC_STAT_CRC_FAIL, 0, 1), + MASKDEFINE(MMC_STAT_CMD_TIMEOUT, 2, 1), + MASKDEFINE(MMC_STAT_CMD_RESP_END, 6, 1), + MASKDEFINE(MMC_STAT_CMD_SENT, 7, 1), + MASKDEFINE(MMC_STAT_CMD_ACTIVE, 11, 1), + MASKDEFINE(MMC_STAT_TRANSMIT_FIFO_EMPTY, 18, 1), + MASKDEFINE(MMC_STAT_FIFO_DATA_AVAIL_TO_READ, 21, 1), +}; + +enum PL181Commands { + CMD_GO_IDLE_STATE = 0, + CMD_ALL_SEND_CID = 2, + CMD_SET_RELATIVE_ADDR = 3, + CMD_SELECT = 7, + CMD_SEND_CSD = 9, + CMD_SEND_CID = 10, + CMD_SET_SECTOR_SIZE = 16, + CMD_READ_SINGLE_BLOCK = 17, + CMD_WRITE_SINGLE_BLOCK = 24, + CMD_SD_SEND_OP_COND = 41, + CMD_APP_CMD = 55, +}; + +struct pl181_registers { + uint32_t power; + uint32_t clock; + uint32_t arg; + uint32_t cmd; + uint32_t resp_cmd; + uint32_t response[4]; + uint32_t data_timer; + uint32_t data_length; + uint32_t data_control; + uint32_t data_count; + uint32_t status; + uint32_t clear; + uint32_t interrupt_mask[2]; + uint32_t interrupt_select; + uint32_t fifo_count; + char res[0x34]; + uint32_t fifo_data[16]; + // TO BE CONTINUED +}; +typedef struct pl181_registers pl181_registers_t; + +struct sd_card { + uint32_t rca; + uint32_t ishc; + uint32_t capacity; +}; +typedef struct sd_card sd_card_t; + +void pl181_install(); + +#endif //_KERNEL_DRIVERS_STORAGE_ARM_PL181_H diff --git a/kernel/include/drivers/storage/ramdisk.h b/kernel/include/drivers/storage/ramdisk.h new file mode 100644 index 0000000..2844aad --- /dev/null +++ b/kernel/include/drivers/storage/ramdisk.h @@ -0,0 +1,9 @@ +#ifndef _KERNEL_DRIVERS_STORAGE_RAMDISK_H +#define _KERNEL_DRIVERS_STORAGE_RAMDISK_H + +#include +#include + +void ramdisk_install(); + +#endif //_KERNEL_DRIVERS_STORAGE_RAMDISK_H \ No newline at end of file diff --git a/kernel/include/drivers/storage/virtio_block.h b/kernel/include/drivers/storage/virtio_block.h new file mode 100644 index 0000000..e73bbc7 --- /dev/null +++ b/kernel/include/drivers/storage/virtio_block.h @@ -0,0 +1,58 @@ +#ifndef _KERNEL_DRIVERS_STORAGE_VIRTIO_BLOCK_H +#define _KERNEL_DRIVERS_STORAGE_VIRTIO_BLOCK_H + +#include +#include +#include +#include + +#define VIRTIO_BLK_T_IN (0) +#define VIRTIO_BLK_T_OUT (1) +#define VIRTIO_BLK_T_FLUSH (4) +#define VIRTIO_BLK_T_DISCARD (11) +#define VIRTIO_BLK_T_WRITE_ZEROES (13) + +// Status values +#define VIRTIO_BLK_S_OK (0) +#define VIRTIO_BLK_S_IOERR (1) +#define VIRTIO_BLK_S_UNSUPP (2) + +// Feature bits +#define VIRTIO_BLK_F_SIZE_MAX (1) +#define VIRTIO_BLK_F_SEG_MAX (2) +#define VIRTIO_BLK_F_GEOMETRY (4) +#define VIRTIO_BLK_F_RO (5) +#define VIRTIO_BLK_F_BLK_SIZE (6) +#define VIRTIO_BLK_F_FLUSH (9) +#define VIRTIO_BLK_F_TOPOLOGY (10) +#define VIRTIO_BLK_F_CONFIG_WCE (11) +#define VIRTIO_BLK_F_DISCARD (13) +#define VIRTIO_BLK_F_WRITE_ZEROES (14) + +struct block_dev { + virtio_queue_desc_t queue_desc; + void* ptr; + uint32_t idx; + uint32_t ack_used_idx; + virtio_buffer_desc_t buffer_desc; +}; +typedef struct block_dev block_dev_t; + +typedef struct { + uint32_t blktype; + uint32_t reserved; + uint64_t sector; +} block_header_t; + +typedef struct { + uint8_t status; +} block_status_t; + +typedef struct { + block_header_t header; + block_status_t status; + uint16_t head; + uint16_t watcher; +} block_request_t; + +#endif //_KERNEL_DRIVERS_STORAGE_VIRTIO_BLOCK_H \ No newline at end of file diff --git a/kernel/include/drivers/storage/x86/ata.h b/kernel/include/drivers/storage/x86/ata.h new file mode 100644 index 0000000..71b9990 --- /dev/null +++ b/kernel/include/drivers/storage/x86/ata.h @@ -0,0 +1,40 @@ +#ifndef _KERNEL_DRIVERS_STORAGE_X86_ATA_H +#define _KERNEL_DRIVERS_STORAGE_X86_ATA_H + +#include +#include +#include +#include + +typedef struct { // LBA28 | LBA48 + uint32_t data; // 16bit | 16 bits + uint32_t error; // 8 bit | 16 bits + uint32_t sector_count; // 8 bit | 16 bits + uint32_t lba_lo; // 8 bit | 16 bits + uint32_t lba_mid; // 8 bit | 16 bits + uint32_t lba_hi; // 8 bit | 16 bits + uint32_t device; // 8 bit + uint32_t command; // 8 bit + uint32_t control; +} ata_ports_t; + +typedef struct { + ata_ports_t port; + bool is_master; + uint16_t cylindres; + uint16_t heads; + uint16_t sectors; + bool dma; + bool lba; + uint32_t capacity; // in sectors +} ata_t; + +extern ata_t _ata_drives[MAX_DEVICES_COUNT]; + +int ata_init_with_dev(device_t* dev); + +void ata_install(); +void ata_init(ata_t* ata, uint32_t port, bool is_master); +bool ata_indentify(ata_t* ata); + +#endif //_KERNEL_DRIVERS_STORAGE_X86_ATA_H diff --git a/kernel/include/drivers/timer/arm/arm64/timer.h b/kernel/include/drivers/timer/arm/arm64/timer.h new file mode 100644 index 0000000..e8f7f0c --- /dev/null +++ b/kernel/include/drivers/timer/arm/arm64/timer.h @@ -0,0 +1,10 @@ +#ifndef _KERNEL_DRIVERS_TIMER_ARM_ARM64_TIMER_H +#define _KERNEL_DRIVERS_TIMER_ARM_ARM64_TIMER_H + +#include +#include