Squash commits for public release
2
.clang-format
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
BasedOnStyle: WebKit
|
||||
2
.clang-tidy
Normal 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
@@ -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
@@ -0,0 +1,6 @@
|
||||
buildconfig = "//build/config/BUILDCONFIG.gn"
|
||||
script_executable = "python3"
|
||||
|
||||
default_args = {
|
||||
# Set in buildconfig
|
||||
}
|
||||
25
BUILD.gn
Normal 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
|
After Width: | Height: | Size: 546 KiB |
131
README.md
Normal 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"
|
||||
5
base/System/launch_server_config.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"launch": [
|
||||
"/System/window_server"
|
||||
]
|
||||
}
|
||||
2
base/etc/passwd
Normal 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
@@ -0,0 +1,2 @@
|
||||
root:root:18727::::::
|
||||
user:password:18727:0:99999::::
|
||||
1
base/home/root/rootfile.txt
Normal file
@@ -0,0 +1 @@
|
||||
Root file
|
||||
1
base/home/user/userfile.txt
Normal file
@@ -0,0 +1 @@
|
||||
User file
|
||||
37
base/open_docs
Normal 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.
|
||||
BIN
base/res/fonts/Liza.font/10/bold.font
Normal file
BIN
base/res/fonts/Liza.font/10/regular.font
Normal file
BIN
base/res/fonts/system.font/10/bold.font
Normal file
BIN
base/res/fonts/system.font/10/regular.font
Normal file
BIN
base/res/fonts/system.font/12/bold.font
Normal file
BIN
base/res/fonts/system.font/12/regular.font
Normal file
BIN
base/res/fonts/system.font/24/bold.font
Normal file
BIN
base/res/fonts/system.font/24/regular.font
Normal file
BIN
base/res/fonts/system.font/36/bold.font
Normal file
BIN
base/res/fonts/system.font/36/regular.font
Normal file
BIN
base/res/fonts/system.font/truetype/bold.ttf
Normal file
BIN
base/res/fonts/system.font/truetype/regular.ttf
Normal file
BIN
base/res/icons/apps/about.icon/32x32.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
base/res/icons/apps/about.icon/48x48.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
base/res/icons/apps/activity_monitor.icon/32x32.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
base/res/icons/apps/activity_monitor.icon/48x48.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
base/res/icons/apps/calculator.icon/32x32.png
Normal file
|
After Width: | Height: | Size: 950 B |
BIN
base/res/icons/apps/calculator.icon/48x48.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
base/res/icons/apps/missing.icon/12x12.png
Normal file
|
After Width: | Height: | Size: 373 B |
BIN
base/res/icons/apps/missing.icon/32x32.png
Normal file
|
After Width: | Height: | Size: 716 B |
BIN
base/res/icons/apps/missing.icon/48x48.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
base/res/icons/apps/terminal.icon/32x32.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
base/res/icons/apps/terminal.icon/48x48.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
base/res/system/app_list_32.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
base/res/system/arrow.png
Normal file
|
After Width: | Height: | Size: 430 B |
BIN
base/res/system/contol_center.png
Normal file
|
After Width: | Height: | Size: 666 B |
BIN
base/res/system/logo_dark_128.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
base/res/system/logo_dark_256.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
base/res/system/logo_opac_128.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
base/res/system/mobile/control.png
Normal file
|
After Width: | Height: | Size: 393 B |
BIN
base/res/system/mobile/cursor.png
Normal file
|
After Width: | Height: | Size: 410 B |
BIN
base/res/wallpapers/abstract.png
Normal file
|
After Width: | Height: | Size: 4.3 MiB |
BIN
base/res/wallpapers/island.png
Normal file
|
After Width: | Height: | Size: 755 KiB |
BIN
base/res/wallpapers/new_year.png
Normal file
|
After Width: | Height: | Size: 700 KiB |
BIN
base/res/wallpapers/pink_sand.png
Normal file
|
After Width: | Height: | Size: 246 KiB |
163
boot/arm32/drivers/pl181.c
Normal 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;
|
||||
}
|
||||
73
boot/arm32/drivers/pl181.h
Normal 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
@@ -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;
|
||||
}
|
||||
9
boot/arm32/drivers/uart.h
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
226
boot/arm64/prekernel/drivers/fb.c
Normal 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
|
||||
};
|
||||
11
boot/arm64/prekernel/drivers/fb.h
Normal 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
|
||||
23
boot/arm64/prekernel/drivers/uart.c
Normal 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;
|
||||
}
|
||||
9
boot/arm64/prekernel/drivers/uart.h
Normal 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
|
||||
66
boot/arm64/prekernel/entry.S
Normal 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
@@ -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
@@ -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
@@ -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
|
||||
29
boot/libboot/abi/drivers.h
Normal 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
@@ -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
@@ -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
|
||||
110
boot/libboot/abi/multiboot.h
Normal 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
|
||||
18
boot/libboot/abi/rawimage.h
Normal 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
|
||||
149
boot/libboot/crypto/sha256.c
Normal 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;
|
||||
}
|
||||
}
|
||||
22
boot/libboot/crypto/sha256.h
Normal 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
|
||||
136
boot/libboot/crypto/signature.c
Normal 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,
|
||||
};
|
||||
10
boot/libboot/crypto/signature.h
Normal 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
|
||||
299
boot/libboot/crypto/uint2048.c
Normal 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;
|
||||
}
|
||||
43
boot/libboot/crypto/uint2048.h
Normal 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
|
||||
103
boot/libboot/crypto/validate.c
Normal 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, §ion_header);
|
||||
|
||||
char tmp_name_buffer[32];
|
||||
uintptr_t name_offset_abs = shstrtab_offset + section_header.sh_name;
|
||||
elfctx->fs_desc->read_from_inode(elfctx->drive_desc, &elfctx->file_inode, (void*)tmp_name_buffer, name_offset_abs, 32);
|
||||
size_t len = strnlen(tmp_name_buffer, 32);
|
||||
if (len != sizeof("._signature") - 1) {
|
||||
continue;
|
||||
}
|
||||
if (memcmp(tmp_name_buffer, "._signature", len)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
elfctx->fs_desc->read_from_inode(elfctx->drive_desc, &elfctx->file_inode, signature_buffer, section_header.sh_offset, 128);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int calc_elf_hash(elfctx_t* elfctx, char* hash)
|
||||
{
|
||||
sha256_ctx_t shactx;
|
||||
sha256_init(&shactx);
|
||||
|
||||
for (uint32_t i = 0; i < elfctx->header.e_phnum; i++) {
|
||||
elf_program_header_32_t program_header;
|
||||
elf_read_program_header(elfctx, i, &program_header);
|
||||
|
||||
if (program_header.p_type != PT_LOAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t from = program_header.p_offset;
|
||||
size_t rem_to_read = program_header.p_filesz;
|
||||
|
||||
while (rem_to_read) {
|
||||
size_t will_read = min(tmp_buf_size, rem_to_read);
|
||||
int rd = elfctx->fs_desc->read_from_inode(elfctx->drive_desc, &elfctx->file_inode, (void*)tmp_buf, from, will_read);
|
||||
from += will_read;
|
||||
sha256_update(&shactx, tmp_buf, will_read);
|
||||
|
||||
rem_to_read -= will_read;
|
||||
}
|
||||
}
|
||||
|
||||
sha256_hash(&shactx, hash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool validate_elf(const char* path, drive_desc_t* drive_desc, fs_desc_t* fs_desc)
|
||||
{
|
||||
elfctx_t elfctx;
|
||||
char hash[32];
|
||||
|
||||
int err = elf_init_ctx(drive_desc, fs_desc, path, &elfctx);
|
||||
if (err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
err = get_elf_signature(&elfctx, tmp_buf);
|
||||
if (err) {
|
||||
return false;
|
||||
}
|
||||
uint2048_t signature;
|
||||
uint2048_init_bytes(&signature, tmp_buf, 128);
|
||||
|
||||
err = calc_elf_hash(&elfctx, hash);
|
||||
if (err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint2048_t ihash;
|
||||
uint2048_init_bytes_be(&ihash, hash, 32);
|
||||
|
||||
uint2048_t public_e;
|
||||
uint2048_init_bytes(&public_e, pub_xos_key_e, pub_xos_key_e_len);
|
||||
uint2048_t public_n;
|
||||
uint2048_init_bytes(&public_n, pub_xos_key_n, pub_xos_key_n_len);
|
||||
uint2048_t signed_ihash;
|
||||
uint2048_pow(&signature, &public_e, &public_n, &signed_ihash);
|
||||
|
||||
return uint2048_equal(&signed_ihash, &ihash);
|
||||
}
|
||||
11
boot/libboot/crypto/validate.h
Normal 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
|
||||
52
boot/libboot/devtree/devtree.c
Normal 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;
|
||||
}
|
||||
50
boot/libboot/devtree/devtree.h
Normal 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
@@ -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, §ion_header);
|
||||
|
||||
if ((section_header.sh_flags & SHF_ALLOC) == SHF_ALLOC) {
|
||||
vaddr_end = max(vaddr_end, section_header.sh_addr + section_header.sh_size);
|
||||
}
|
||||
}
|
||||
|
||||
*kernel_vaddr = vaddr;
|
||||
*kernel_paddr = paddr;
|
||||
*kernel_size = vaddr_end - vaddr;
|
||||
return 0;
|
||||
}
|
||||
// #endif
|
||||
#else
|
||||
size_t elf_get_kernel_size(void* elffile)
|
||||
{
|
||||
elf_header_64_t* header = (elf_header_64_t*)elffile;
|
||||
if (header->e_ident[EI_MAG0] != 0x7F || header->e_ident[EI_MAG1] != 0x45 || header->e_ident[EI_MAG2] != 0x4c || header->e_ident[EI_MAG3] != 0x46) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t vaddr = 0xffffffffffffffff;
|
||||
size_t vaddr_end = 0;
|
||||
|
||||
for (size_t i = 0; i < header->e_phnum; i++) {
|
||||
uintptr_t offset = header->e_phoff + i * header->e_phentsize;
|
||||
elf_program_header_64_t* program_header = (elf_program_header_64_t*)((uintptr_t)elffile + offset);
|
||||
if (program_header->p_type == PT_LOAD) {
|
||||
vaddr = min(vaddr, program_header->p_vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < header->e_shnum; i++) {
|
||||
uintptr_t offset = header->e_shoff + i * header->e_shentsize;
|
||||
elf_section_header_64_t* section_header = (elf_section_header_64_t*)((uintptr_t)elffile + offset);
|
||||
|
||||
if ((section_header->sh_flags & SHF_ALLOC) == SHF_ALLOC) {
|
||||
vaddr_end = max(vaddr_end, section_header->sh_addr + section_header->sh_size);
|
||||
}
|
||||
}
|
||||
|
||||
return vaddr_end - vaddr;
|
||||
}
|
||||
|
||||
int elf_load_kernel(void* elffile, size_t size, uintptr_t* kernel_vaddr, uintptr_t* kernel_paddr)
|
||||
{
|
||||
elf_header_64_t* header = (elf_header_64_t*)elffile;
|
||||
if (header->e_ident[EI_MAG0] != 0x7F || header->e_ident[EI_MAG1] != 0x45 || header->e_ident[EI_MAG2] != 0x4c || header->e_ident[EI_MAG3] != 0x46) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t vaddr = 0xffffffffffffffff;
|
||||
for (size_t i = 0; i < header->e_phnum; i++) {
|
||||
uintptr_t offset = header->e_phoff + i * header->e_phentsize;
|
||||
elf_program_header_64_t* program_header = (elf_program_header_64_t*)((uintptr_t)elffile + offset);
|
||||
if (program_header->p_type == PT_LOAD) {
|
||||
vaddr = min(vaddr, program_header->p_vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t paddr = (uintptr_t)palloc(size);
|
||||
if (!paddr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < header->e_phnum; i++) {
|
||||
uintptr_t offset = header->e_phoff + i * header->e_phentsize;
|
||||
elf_program_header_64_t* program_header = (elf_program_header_64_t*)((uintptr_t)elffile + offset);
|
||||
if (program_header->p_type == PT_LOAD) {
|
||||
uintptr_t data_paddr = (program_header->p_vaddr - vaddr) + paddr;
|
||||
uintptr_t data_offset = (uintptr_t)elffile + program_header->p_offset;
|
||||
|
||||
#ifdef DEBUG_ELF
|
||||
log("copying elf %lx %lx %lx", data_paddr, data_offset, program_header->p_filesz);
|
||||
#endif
|
||||
memcpy((void*)data_paddr, (void*)data_offset, program_header->p_filesz);
|
||||
}
|
||||
}
|
||||
|
||||
*kernel_vaddr = vaddr;
|
||||
*kernel_paddr = paddr;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
196
boot/libboot/elf/elf_lite.h
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
24
boot/riscv64/prekernel/drivers/uart.c
Normal 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;
|
||||
}
|
||||
9
boot/riscv64/prekernel/drivers/uart.h
Normal 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
|
||||
100
boot/riscv64/prekernel/entry.S
Normal 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
|
||||
185
boot/riscv64/prekernel/main.c
Normal 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
@@ -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));
|
||||
}
|
||||
24
boot/riscv64/prekernel/vm.h
Normal 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
|
||||