Squash commits for public release

This commit is contained in:
2025-02-12 09:54:05 -05:00
commit 7118adc514
1108 changed files with 80873 additions and 0 deletions

2
.clang-format Normal file
View File

@@ -0,0 +1,2 @@
---
BasedOnStyle: WebKit

2
.clang-tidy Normal file
View File

@@ -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: '.*'

23
.gitignore vendored Normal file
View File

@@ -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/*

6
.gn Normal file
View File

@@ -0,0 +1,6 @@
buildconfig = "//build/config/BUILDCONFIG.gn"
script_executable = "python3"
default_args = {
# Set in buildconfig
}

25
BUILD.gn Normal file
View File

@@ -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" ]
}

67
Images/sysarch.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 546 KiB

131
README.md Normal file
View File

@@ -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"

View File

@@ -0,0 +1,5 @@
{
"launch": [
"/System/window_server"
]
}

2
base/etc/passwd Normal file
View File

@@ -0,0 +1,2 @@
root::0:0:root:/root:/bin/xsh
user::10:10:user:/user:/bin/xsh

2
base/etc/shadow Normal file
View File

@@ -0,0 +1,2 @@
root:root:18727::::::
user:password:18727:0:99999::::

View File

@@ -0,0 +1 @@
Root file

View File

@@ -0,0 +1 @@
User file

37
base/open_docs Normal file
View File

@@ -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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 950 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
base/res/system/arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 700 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

163
boot/arm32/drivers/pl181.c Normal file
View File

@@ -0,0 +1,163 @@
#include "pl181.h"
#include <libboot/devtree/devtree.h>
#include <libboot/log/log.h>
// #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;
}

View File

@@ -0,0 +1,73 @@
#ifndef _BOOT_DRIVERS_PL181_H
#define _BOOT_DRIVERS_PL181_H
#include <libboot/abi/drivers.h>
#include <libboot/types.h>
#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

23
boot/arm32/drivers/uart.c Normal file
View File

@@ -0,0 +1,23 @@
#include "uart.h"
#include <libboot/devtree/devtree.h>
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;
}

View File

@@ -0,0 +1,9 @@
#ifndef _BOOT_DRIVERS_UART_H
#define _BOOT_DRIVERS_UART_H
#include <libboot/types.h>
void uart_init();
int uart_write(uint8_t data);
#endif // _BOOT_DRIVERS_UART_H

30
boot/arm32/entry.s Normal file
View File

@@ -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

13
boot/arm32/hw/ram.c Normal file
View File

@@ -0,0 +1,13 @@
#include "ram.h"
#include <libboot/devtree/devtree.h>
#include <libboot/log/log.h>
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;
}

8
boot/arm32/hw/ram.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef _BOOT_HW_RAM_H
#define _BOOT_HW_RAM_H
#include <libboot/types.h>
size_t hw_ram_get_size();
#endif //_BOOT_HW_RAM_H

153
boot/arm32/main.c Normal file
View File

@@ -0,0 +1,153 @@
#include "drivers/pl181.h"
#include "drivers/uart.h"
#include "vmm/vmm.h"
#include <libboot/crypto/sha256.h>
#include <libboot/crypto/signature.h>
#include <libboot/crypto/uint2048.h>
#include <libboot/crypto/validate.h>
#include <libboot/devtree/devtree.h>
#include <libboot/elf/elf_lite.h>
#include <libboot/fs/ext2_lite.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
// #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);
}

25
boot/arm32/start_kernel.s Normal file
View File

@@ -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

17
boot/arm32/vmm/consts.h Normal file
View File

@@ -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

147
boot/arm32/vmm/vmm.c Normal file
View File

@@ -0,0 +1,147 @@
#include "vmm.h"
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
#include <libboot/types.h>
// #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();
}

54
boot/arm32/vmm/vmm.h Normal file
View File

@@ -0,0 +1,54 @@
#ifndef _BOOT_VMM_VMM_H
#define _BOOT_VMM_VMM_H
#include "consts.h"
#include <libboot/types.h>
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

View File

@@ -0,0 +1,226 @@
#include "fb.h"
#include <libboot/devtree/devtree.h>
#include <libboot/types.h>
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
};

View File

@@ -0,0 +1,11 @@
#ifndef _BOOT_DRIVERS_SCREEN_H
#define _BOOT_DRIVERS_SCREEN_H
#include <libboot/abi/memory.h>
#include <libboot/types.h>
int fb_init();
int fb_reinit_after_map(uintptr_t vaddr);
int fb_put_char(uint8_t c);
#endif // _BOOT_DRIVERS_SCREEN_H

View File

@@ -0,0 +1,23 @@
#include "uart.h"
#include <libboot/devtree/devtree.h>
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;
}

View File

@@ -0,0 +1,9 @@
#ifndef _BOOT_DRIVERS_UART_H
#define _BOOT_DRIVERS_UART_H
#include <libboot/types.h>
void uart_init();
int uart_write(uint8_t data);
#endif // _BOOT_DRIVERS_UART_H

View File

@@ -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

159
boot/arm64/prekernel/main.c Normal file
View File

@@ -0,0 +1,159 @@
#include "drivers/fb.h"
#include "drivers/uart.h"
#include "vm.h"
#include <libboot/abi/memory.h>
#include <libboot/abi/rawimage.h>
#include <libboot/devtree/devtree.h>
#include <libboot/elf/elf_lite.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
#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;
}

168
boot/arm64/prekernel/vm.c Normal file
View File

@@ -0,0 +1,168 @@
#include "vm.h"
#include "drivers/fb.h"
#include <libboot/abi/kernel.h>
#include <libboot/abi/rawimage.h>
#include <libboot/devtree/devtree.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
// #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);
}

25
boot/arm64/prekernel/vm.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef _BOOT_VM_H
#define _BOOT_VM_H
#include <libboot/abi/memory.h>
#include <libboot/abi/rawimage.h>
#include <libboot/types.h>
#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

View File

@@ -0,0 +1,29 @@
#ifndef _BOOT_LIBBOOT_ABI_DRIVERS_H
#define _BOOT_LIBBOOT_ABI_DRIVERS_H
#include <libboot/types.h>
#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

11
boot/libboot/abi/kernel.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef _BOOT_LIBBOOT_ABI_KERNEL_H
#define _BOOT_LIBBOOT_ABI_KERNEL_H
#include <libboot/types.h>
// 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

45
boot/libboot/abi/memory.h Normal file
View File

@@ -0,0 +1,45 @@
#ifndef _BOOT_LIBBOOT_ABI_MEMORY_H
#define _BOOT_LIBBOOT_ABI_MEMORY_H
#include <libboot/types.h>
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

View File

@@ -0,0 +1,110 @@
#ifndef _BOOT_LIBBOOT_ABI_MULTIBOOT_H
#define _BOOT_LIBBOOT_ABI_MULTIBOOT_H
#include <libboot/types.h>
#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

View File

@@ -0,0 +1,18 @@
#ifndef _BOOT_LIBBOOT_ABI_RAWIMAGE_H
#define _BOOT_LIBBOOT_ABI_RAWIMAGE_H
#include <libboot/types.h>
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

View File

@@ -0,0 +1,149 @@
#include "sha256.h"
#include <libboot/log/log.h>
#include <libboot/mem/mem.h>
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;
}
}

View File

@@ -0,0 +1,22 @@
#ifndef _BOOT_LIBBOOT_CRYPTO_SHA256_H
#define _BOOT_LIBBOOT_CRYPTO_SHA256_H
#include <libboot/mem/mem.h>
#include <libboot/types.h>
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

View File

@@ -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,
};

View File

@@ -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

View File

@@ -0,0 +1,299 @@
#include "uint2048.h"
#include <libboot/log/log.h>
#include <libboot/mem/mem.h>
#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;
}

View File

@@ -0,0 +1,43 @@
#ifndef _BOOT_LIBBOOT_CRYPTO_UINT2048_H
#define _BOOT_LIBBOOT_CRYPTO_UINT2048_H
#include <libboot/mem/mem.h>
#include <libboot/types.h>
#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

View File

@@ -0,0 +1,103 @@
#include <libboot/crypto/sha256.h>
#include <libboot/crypto/signature.h>
#include <libboot/crypto/uint2048.h>
#include <libboot/crypto/validate.h>
#include <libboot/elf/elf_lite.h>
#include <libboot/fs/ext2_lite.h>
#include <libboot/log/log.h>
#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, &section_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);
}

View File

@@ -0,0 +1,11 @@
#ifndef STAGE2_SECURITY_VALIDATE_H
#define STAGE2_SECURITY_VALIDATE_H
#include <libboot/abi/drivers.h>
#include <libboot/abi/memory.h>
#include <libboot/types.h>
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

View File

@@ -0,0 +1,52 @@
#include "devtree.h"
#include <libboot/log/log.h>
#include <libboot/mem/mem.h>
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;
}

View File

@@ -0,0 +1,50 @@
#ifndef _BOOT_LIBBOOT_DEVTREE_DEVTREE_H
#define _BOOT_LIBBOOT_DEVTREE_DEVTREE_H
#include <libboot/mem/mem.h>
#include <libboot/types.h>
#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

144
boot/libboot/elf/elf_lite.c Normal file
View File

@@ -0,0 +1,144 @@
#include "elf_lite.h"
#include <libboot/crypto/sha256.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
// #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, &section_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

196
boot/libboot/elf/elf_lite.h Normal file
View File

@@ -0,0 +1,196 @@
#ifndef _BOOT_LIBBOOT_ELF_ELF_LITE
#define _BOOT_LIBBOOT_ELF_ELF_LITE
#include <libboot/abi/drivers.h>
#include <libboot/fs/ext2_lite.h>
#include <libboot/types.h>
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

233
boot/libboot/fs/ext2_lite.c Normal file
View File

@@ -0,0 +1,233 @@
#include <libboot/fs/ext2_lite.h>
#include <libboot/mem/mem.h>
#include <libboot/types.h>
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);
}

124
boot/libboot/fs/ext2_lite.h Normal file
View File

@@ -0,0 +1,124 @@
#ifndef _BOOT_LIBBOOT_FS_EXT2_LITE
#define _BOOT_LIBBOOT_FS_EXT2_LITE
#include <libboot/abi/drivers.h>
#include <libboot/types.h>
#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

377
boot/libboot/log/log.c Normal file
View File

@@ -0,0 +1,377 @@
#include <libboot/log/log.h>
#include <libboot/mem/mem.h>
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;
}

20
boot/libboot/log/log.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef _BOOT_LIBBOOT_LOG_LOG_H
#define _BOOT_LIBBOOT_LOG_LOG_H
#include <libboot/types.h>
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

96
boot/libboot/mem/alloc.c Normal file
View File

@@ -0,0 +1,96 @@
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
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;
}

17
boot/libboot/mem/alloc.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef _BOOT_LIBBOOT_MEM_MALLOC_H
#define _BOOT_LIBBOOT_MEM_MALLOC_H
#include <libboot/mem/mem.h>
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

110
boot/libboot/mem/mem.c Normal file
View File

@@ -0,0 +1,110 @@
#include <libboot/mem/mem.h>
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;
}

37
boot/libboot/mem/mem.h Normal file
View File

@@ -0,0 +1,37 @@
#ifndef _BOOT_LIBBOOT_MEM_MEM_H
#define _BOOT_LIBBOOT_MEM_MEM_H
#include <libboot/types.h>
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

89
boot/libboot/types.h Normal file
View File

@@ -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

View File

@@ -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;
}

View File

@@ -0,0 +1,9 @@
#ifndef _BOOT_DRIVERS_UART_H
#define _BOOT_DRIVERS_UART_H
#include <libboot/types.h>
void uart_init();
int uart_write(uint8_t data);
#endif // _BOOT_DRIVERS_UART_H

View File

@@ -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

View File

@@ -0,0 +1,185 @@
#include "drivers/uart.h"
#include "vm.h"
#include <libboot/abi/memory.h>
#include <libboot/devtree/devtree.h>
#include <libboot/elf/elf_lite.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
#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;
}

141
boot/riscv64/prekernel/vm.c Normal file
View File

@@ -0,0 +1,141 @@
#include "vm.h"
#include <libboot/abi/kernel.h>
#include <libboot/abi/rawimage.h>
#include <libboot/devtree/devtree.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
#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));
}

View File

@@ -0,0 +1,24 @@
#ifndef _BOOT_VM_H
#define _BOOT_VM_H
#include <libboot/abi/memory.h>
#include <libboot/types.h>
#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

Some files were not shown because too many files have changed in this diff Show More