Squash commits for public release

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

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

@@ -0,0 +1,163 @@
#include "pl181.h"
#include <libboot/devtree/devtree.h>
#include <libboot/log/log.h>
// #define DEBUG_PL181
static sd_card_t sd_card;
static volatile pl181_registers_t* registers;
static inline int _pl181_map_itself(devtree_entry_t* dev)
{
registers = (pl181_registers_t*)(uint32_t)dev->region_base;
return 0;
}
static inline void _pl181_clear_flags()
{
registers->clear = 0x5FF;
}
static int _pl181_send_cmd(uint32_t cmd, uint32_t param)
{
_pl181_clear_flags();
registers->arg = param;
registers->cmd = cmd;
while (registers->status & MMC_STAT_CMD_ACTIVE_MASK) { }
if ((cmd & MMC_CMD_RESP_MASK) == MMC_CMD_RESP_MASK) {
while (((registers->status & MMC_STAT_CMD_RESP_END_MASK) != MMC_STAT_CMD_RESP_END_MASK) || (registers->status & MMC_STAT_CMD_ACTIVE_MASK)) {
if (registers->status & MMC_STAT_CMD_TIMEOUT_MASK) {
return -1;
}
}
} else {
while ((registers->status & MMC_STAT_CMD_SENT_MASK) != MMC_STAT_CMD_SENT_MASK) { }
}
return 0;
}
static int _pl181_send_app_cmd(uint32_t cmd, uint32_t param)
{
for (int i = 0; i < 5; i++) {
_pl181_send_cmd(CMD_APP_CMD | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, 0);
if (registers->response[0] & (1 << 5)) {
return _pl181_send_cmd(cmd, param);
}
}
log_error("Failed to send app command");
return -4;
}
inline static int _pl181_select_card(uint32_t rca)
{
return _pl181_send_cmd(CMD_SELECT | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, rca);
}
static int _pl181_read_block(uint32_t lba_like, void* read_data)
{
sd_card_t* sd_card_ptr = &sd_card;
uint32_t* read_data32 = (uint32_t*)read_data;
uint32_t bytes_read = 0;
registers->data_length = PL181_SECTOR_SIZE; // Set length of bytes to transfer
registers->data_control = 0b11; // Enable dpsm and set direction from card to host
if (sd_card_ptr->ishc) {
_pl181_send_cmd(CMD_READ_SINGLE_BLOCK | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, lba_like);
} else {
_pl181_send_cmd(CMD_READ_SINGLE_BLOCK | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, lba_like * PL181_SECTOR_SIZE);
}
while (registers->status & MMC_STAT_FIFO_DATA_AVAIL_TO_READ_MASK) {
*read_data32 = registers->fifo_data[0];
read_data32++;
bytes_read += 4;
}
return bytes_read;
}
static int _pl181_register_device(uint32_t rca, bool ishc, uint32_t capacity)
{
sd_card.rca = rca;
sd_card.ishc = ishc;
sd_card.capacity = capacity;
_pl181_select_card(rca);
_pl181_send_cmd(CMD_SET_SECTOR_SIZE | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, PL181_SECTOR_SIZE);
if (registers->response[0] != 0x900) {
log_error("PL181(pl181_add_new_device): Can't set sector size");
return -1;
}
return 0;
}
int pl181_init(drive_desc_t* drive_desc)
{
devtree_entry_t* dev = devtree_find_device("pl181");
if (!dev) {
return -1;
}
if (_pl181_map_itself(dev)) {
#ifdef DEBUG_PL181
log_error("PL181: Can't map itself!");
#endif
return -1;
}
#ifdef DEBUG_PL181
log("PL181: Turning on");
#endif
registers->clock = 0x1C6;
registers->power = 0x86;
// Send cmd 0 to set all cards into idle state
_pl181_send_cmd(CMD_GO_IDLE_STATE | MMC_CMD_ENABLE_MASK, 0x0);
// Voltage Check
_pl181_send_cmd(8 | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, 0x1AA);
if ((registers->response[0] & 0x1AA) != 0x1AA) {
#ifdef DEBUG_PL181
log_error("PL181: Can't set voltage!");
#endif
return -1;
}
if (_pl181_send_app_cmd(CMD_SD_SEND_OP_COND | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, 1 << 30 | 0x1AA)) {
#ifdef DEBUG_PL181
log_error("PL181: Can't send APP_CMD!");
#endif
return -1;
}
bool ishc = 0;
if (registers->response[0] & 1 << 30) {
ishc = 1;
#ifdef DEBUG_PL181
log("PL181: ishc = 1");
#endif
}
_pl181_send_cmd(CMD_ALL_SEND_CID | MMC_CMD_ENABLE_MASK | MMC_CMD_LONG_RESP_MASK, 0x0);
_pl181_send_cmd(CMD_SET_RELATIVE_ADDR | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, 0x0);
// Get the card RCA from the response it is the top 16 bits of the 32 bit response
uint32_t rca = (registers->response[0] & 0xFFFF0000);
_pl181_send_cmd(CMD_SEND_CSD | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK | MMC_CMD_LONG_RESP_MASK, rca);
uint32_t resp1 = registers->response[1];
uint32_t capacity = ((resp1 >> 8) & 0x3) << 10;
capacity |= (resp1 & 0xFF) << 2;
capacity = 256 * 1024 * (capacity + 1);
_pl181_register_device(rca, ishc, capacity);
drive_desc->read = _pl181_read_block;
return 0;
}

View File

@@ -0,0 +1,73 @@
#ifndef _BOOT_DRIVERS_PL181_H
#define _BOOT_DRIVERS_PL181_H
#include <libboot/abi/drivers.h>
#include <libboot/types.h>
#define PL181_SECTOR_SIZE 512
enum PL181CommandMasks {
MASKDEFINE(MMC_CMD_IDX, 0, 6),
MASKDEFINE(MMC_CMD_RESP, 6, 1),
MASKDEFINE(MMC_CMD_LONG_RESP, 7, 1),
MASKDEFINE(MMC_CMD_INTERRUPT, 8, 1),
MASKDEFINE(MMC_CMD_PENDING, 9, 1),
MASKDEFINE(MMC_CMD_ENABLE, 10, 1),
};
enum PL181StatusMasks {
MASKDEFINE(MMC_STAT_CRC_FAIL, 0, 1),
MASKDEFINE(MMC_STAT_CMD_TIMEOUT, 2, 1),
MASKDEFINE(MMC_STAT_CMD_RESP_END, 6, 1),
MASKDEFINE(MMC_STAT_CMD_SENT, 7, 1),
MASKDEFINE(MMC_STAT_CMD_ACTIVE, 11, 1),
MASKDEFINE(MMC_STAT_TRANSMIT_FIFO_EMPTY, 18, 1),
MASKDEFINE(MMC_STAT_FIFO_DATA_AVAIL_TO_READ, 21, 1),
};
enum PL181Commands {
CMD_GO_IDLE_STATE = 0,
CMD_ALL_SEND_CID = 2,
CMD_SET_RELATIVE_ADDR = 3,
CMD_SELECT = 7,
CMD_SEND_CSD = 9,
CMD_SEND_CID = 10,
CMD_SET_SECTOR_SIZE = 16,
CMD_READ_SINGLE_BLOCK = 17,
CMD_WRITE_SINGLE_BLOCK = 24,
CMD_SD_SEND_OP_COND = 41,
CMD_APP_CMD = 55,
};
struct pl181_registers {
uint32_t power;
uint32_t clock;
uint32_t arg;
uint32_t cmd;
uint32_t resp_cmd;
uint32_t response[4];
uint32_t data_timer;
uint32_t data_length;
uint32_t data_control;
uint32_t data_count;
uint32_t status;
uint32_t clear;
uint32_t interrupt_mask[2];
uint32_t interrupt_select;
uint32_t fifo_count;
char res[0x34];
uint32_t fifo_data[16];
// TO BE CONTINUED
};
typedef struct pl181_registers pl181_registers_t;
struct sd_card {
uint32_t rca;
uint32_t ishc;
uint32_t capacity;
};
typedef struct sd_card sd_card_t;
int pl181_init(drive_desc_t* drive_desc);
#endif // _BOOT_DRIVERS_PL181_H

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

@@ -0,0 +1,23 @@
#include "uart.h"
#include <libboot/devtree/devtree.h>
volatile uint32_t* output = NULL;
void uart_init()
{
devtree_entry_t* dev = devtree_find_device("uart");
if (!dev) {
while (1) { };
}
output = (uint32_t*)(uint32_t)dev->region_base;
}
int uart_write(uint8_t data)
{
if (!output) {
return 1;
}
*output = data;
return 0;
}

View File

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

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

@@ -0,0 +1,30 @@
.extern _start
.extern _start_secondary_cpu
.section ".xos_boot_text"
xos_loader:
ldr sp, =STACK_PHYZ_TOP
mrc p15, #0, r0, c0, c0, #5 // Read CPU ID register.
and r0, r0, #3
cmp r0, #0
bne secondary_cpu_loader
ldr r0, =_start
mov pc, r0
secondary_cpu_loader:
ldr sp, =STACK_SECONDARY_PHYZ_TOP
mov r9, #512
mrc p15, #0, r8, c0, c0, #5 // Read CPU ID register.
and r8, r8, #3
1:
sub r8, r8, #1
cmp r8, #0
beq secondary_cpu_loader_exit
add r9, r9, #512
b 1b
secondary_cpu_loader_exit:
subs sp, r9
ldr r0, =_start_secondary_cpu
mov pc, r0

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

@@ -0,0 +1,13 @@
#include "ram.h"
#include <libboot/devtree/devtree.h>
#include <libboot/log/log.h>
size_t hw_ram_get_size()
{
devtree_entry_t* dev = devtree_find_device("ram");
if (!dev) {
log("Can't find RAM in devtree");
while (1) { };
}
return dev->region_size;
}

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

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

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

@@ -0,0 +1,153 @@
#include "drivers/pl181.h"
#include "drivers/uart.h"
#include "vmm/vmm.h"
#include <libboot/crypto/sha256.h>
#include <libboot/crypto/signature.h>
#include <libboot/crypto/uint2048.h>
#include <libboot/crypto/validate.h>
#include <libboot/devtree/devtree.h>
#include <libboot/elf/elf_lite.h>
#include <libboot/fs/ext2_lite.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
// #define DEBUG_BOOT
#define KERNEL_PATH "/boot/kernel.bin"
#define LAUNCH_SERVER_PATH "/System/launch_server"
extern void jump_to_kernel(void*);
extern uint32_t _odt_phys[];
extern uint32_t _odt_phys_end[];
static void* bootdesc_ptr;
static size_t kernel_vaddr = 0;
static size_t kernel_paddr = 0;
static size_t kernel_size = 0;
static int sync = 0;
static int alloc_init()
{
devtree_entry_t* dev = devtree_find_device("ram");
if (!dev) {
log("Can't find RAM in devtree");
while (1) { };
}
extern int bootloader_start[];
size_t alloc_space = (size_t)bootloader_start - dev->region_base;
malloc_init((void*)(uint32_t)dev->region_base, alloc_space);
return 0;
}
static memory_boot_desc_t memory_boot_desc_init()
{
devtree_entry_t* dev = devtree_find_device("ram");
if (!dev) {
log("Can't find RAM in devtree");
while (1) { };
}
char dummy_data = 0x0;
memory_boot_desc_t res;
memory_layout_t* mem_layout_paddr = copy_after_kernel(kernel_paddr, &dummy_data, sizeof(dummy_data), &kernel_size, VMM_PAGE_SIZE);
// Init of trailing element.
mem_layout_paddr[0].flags = MEMORY_LAYOUT_FLAG_TERMINATE;
memory_layout_t* mem_layout_vaddr = paddr_to_vaddr(mem_layout_paddr, kernel_paddr, kernel_vaddr);
#ifdef DEBUG_BOOT
log("initing MEMLAYOUT %lx of %d elems", mem_layout_vaddr, memory_layout_size);
#endif
res.ram_base = dev->region_base;
res.ram_size = dev->region_size;
res.reserved_areas = mem_layout_vaddr;
return res;
}
static int prepare_boot_disk(drive_desc_t* drive_desc)
{
pl181_init(drive_desc);
return -1;
}
static int prepare_fs(drive_desc_t* drive_desc, fs_desc_t* fs_desc)
{
if (ext2_lite_init(drive_desc, fs_desc) == 0) {
return 0;
}
return -1;
}
static int validate_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc)
{
log("Validating Kernel...");
if (!validate_elf(KERNEL_PATH, drive_desc, fs_desc)) {
log("Can't validate kernel");
while (1) { }
}
if (!validate_elf(LAUNCH_SERVER_PATH, drive_desc, fs_desc)) {
log("Can't validate launch_server");
while (1) { }
}
return 0;
}
static void load_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc)
{
int res = elf_load_kernel(drive_desc, fs_desc, KERNEL_PATH, &kernel_vaddr, &kernel_paddr, &kernel_size);
kernel_size = align_size(kernel_size, VMM_PAGE_SIZE);
#ifdef DEBUG_BOOT
log("kernel %x %x %x", kernel_vaddr, kernel_paddr, kernel_size);
#endif
void* odt_ptr = paddr_to_vaddr(copy_after_kernel(kernel_paddr, devtree_start(), devtree_size(), &kernel_size, VMM_PAGE_SIZE), kernel_paddr, kernel_vaddr);
#ifdef DEBUG_BOOT
log("copying ODT %x -> %x of %d", devtree_start(), odt_ptr, devtree_size());
#endif
size_t kernel_data_size = kernel_size + align_size(sizeof(boot_args_t), VMM_PAGE_SIZE) + VMM_PAGE_SIZE;
boot_args_t boot_args;
boot_args.vaddr = kernel_vaddr;
boot_args.paddr = kernel_paddr;
boot_args.kernel_data_size = kernel_data_size;
boot_args.devtree = odt_ptr;
boot_args.mem_boot_desc = memory_boot_desc_init();
memcpy(boot_args.init_process, LAUNCH_SERVER_PATH, sizeof(LAUNCH_SERVER_PATH));
bootdesc_ptr = paddr_to_vaddr(copy_after_kernel(kernel_paddr, &boot_args, sizeof(boot_args), &kernel_size, VMM_PAGE_SIZE), kernel_paddr, kernel_vaddr);
#ifdef DEBUG_BOOT
log("copying BOOTDESC %x -> %x of %d", &boot_args, bootdesc_ptr, sizeof(boot_args));
#endif
}
void load_boot_cpu()
{
devtree_init((void*)_odt_phys, (uint32_t)_odt_phys_end - (uint32_t)_odt_phys);
uart_init();
log_init(uart_write);
alloc_init();
drive_desc_t drive_desc;
fs_desc_t fs_desc;
prepare_boot_disk(&drive_desc);
prepare_fs(&drive_desc, &fs_desc);
validate_kernel(&drive_desc, &fs_desc);
load_kernel(&drive_desc, &fs_desc);
vm_setup(kernel_vaddr, kernel_paddr, kernel_size);
__atomic_store_n(&sync, 1, __ATOMIC_RELEASE);
jump_to_kernel(bootdesc_ptr);
}
void load_secondary_cpu()
{
while (__atomic_load_n(&sync, __ATOMIC_ACQUIRE) == 0) {
continue;
}
vm_setup_secondary_cpu();
jump_to_kernel(bootdesc_ptr);
}

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

@@ -0,0 +1,25 @@
.extern load_boot_cpu
.extern load_secondary_cpu
.global _start
_start:
ldr r0, =load_boot_cpu
mov pc, r0
1:
b 1b
.size _start, . - _start
.global _start_secondary_cpu
_start_secondary_cpu:
ldr r0, =load_secondary_cpu
mov pc, r0
2:
b 2b
.global jump_to_kernel
jump_to_kernel:
isb
mov r5, #0xc0000000
mov pc, r5
3:
b 3b

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

@@ -0,0 +1,17 @@
#ifndef _BOOT_VMM_CONSTS_H
#define _BOOT_VMM_CONSTS_H
#define VMM_LV0_ENTITY_COUNT (256)
#define VMM_LV1_ENTITY_COUNT (4096)
#define VMM_PAGE_SIZE (4096)
#define VMM_OFFSET_IN_DIRECTORY(a) (((a) >> 20) & 0xfff)
#define VMM_OFFSET_IN_TABLE(a) (((a) >> 12) & 0xff)
#define VMM_OFFSET_IN_PAGE(a) ((a)&0xfff)
#define TABLE_START(vaddr) ((vaddr >> 20) << 20)
#define PAGE_START(vaddr) ((vaddr >> 12) << 12)
#define FRAME(addr) (addr / VMM_PAGE_SIZE)
#define PTABLE_TOP_KERNEL_OFFSET 3072
#endif //_BOOT_VMM_CONSTS_H

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

@@ -0,0 +1,147 @@
#include "vmm.h"
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
#include <libboot/types.h>
// #define DEBUG_VMM
#define VMM_OFFSET_IN_DIRECTORY(a) (((a) >> 20) & 0xfff)
#define VMM_OFFSET_IN_TABLE(a) (((a) >> 12) & 0xff)
#define VMM_OFFSET_IN_PAGE(a) ((a)&0xfff)
#define ALIGN_TO_TABLE(a) ((a)&0xfff00000)
static pdirectory_t* pdir = NULL;
static ptable_t* map_table(size_t tphyz, size_t tvirt);
static void mmu_enable();
static inline void write_ttbcr(uint32_t val)
{
asm volatile("mcr p15, 0, %0, c2, c0, 2"
:
: "r"(val)
: "memory");
asm volatile("dmb");
}
static inline void write_ttbr0(uint32_t val)
{
asm volatile("mcr p15, 0, %0, c2, c0, 0"
:
: "r"(val)
: "memory");
asm volatile("dmb");
}
static inline void write_dacr(uint32_t val)
{
asm volatile("mcr p15, 0, %0, c3, c0, 0"
:
: "r"(val));
asm volatile("dmb");
}
static void mmu_enable()
{
volatile uint32_t val;
asm volatile("mrc p15, 0, %0, c1, c0, 0"
: "=r"(val));
asm volatile("orr %0, %1, #0x1"
: "=r"(val)
: "r"(val));
asm volatile("mcr p15, 0, %0, c1, c0, 0" ::"r"(val)
: "memory");
asm volatile("isb");
}
static pdirectory_t* vm_alloc_pdir()
{
return (pdirectory_t*)malloc_aligned(sizeof(pdirectory_t), sizeof(pdirectory_t));
}
static ptable_t* vm_alloc_ptable()
{
return (ptable_t*)malloc_aligned(sizeof(ptable_t), sizeof(ptable_t));
}
static ptable_t* map_table(size_t tphyz, size_t tvirt)
{
ptable_t* table = vm_alloc_ptable();
for (size_t phyz = tphyz, virt = tvirt, i = 0; i < VMM_LV0_ENTITY_COUNT; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) {
page_desc_t new_page;
new_page.one = 1;
new_page.baddr = (phyz / VMM_PAGE_SIZE);
new_page.tex = 0b001;
new_page.c = 1;
new_page.b = 1;
new_page.ap1 = 0b11;
new_page.ap2 = 0b0;
new_page.s = 1;
table->entities[i] = new_page;
}
uint32_t table_int = (uint32_t)table;
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].valid = 1;
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].zero1 = 0;
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].zero2 = 0;
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].ns = 0;
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].zero3 = 0;
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].domain = 0b0011;
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].baddr = ((table_int / 1024));
return table;
}
static void vm_init()
{
pdir = vm_alloc_pdir();
for (int i = 0; i < VMM_LV1_ENTITY_COUNT; i++) {
pdir->entities[i].valid = 0;
}
}
static void vm_map_devices()
{
map_table(0x1c000000, 0x1c000000); // mapping uart
}
void vm_setup(size_t kernel_vaddr, size_t kernel_paddr, size_t kernel_size)
{
vm_init();
vm_map_devices();
extern int bootloader_start[];
size_t bootloader_start_aligned = ALIGN_TO_TABLE((size_t)bootloader_start);
map_table(bootloader_start_aligned, bootloader_start_aligned);
#ifdef DEBUG_VMM
log("map %x to %x", bootloader_start_aligned, bootloader_start_aligned);
#endif
size_t table_paddr = ALIGN_TO_TABLE(kernel_paddr);
size_t table_vaddr = ALIGN_TO_TABLE(kernel_vaddr);
const size_t bytes_per_table = VMM_LV0_ENTITY_COUNT * VMM_PAGE_SIZE;
const size_t tables_per_kernel = align_size((kernel_size + bytes_per_table - 1) / bytes_per_table, 4);
for (int i = 0; i < tables_per_kernel; i++) {
map_table(table_paddr, table_paddr);
map_table(table_paddr, table_vaddr);
#ifdef DEBUG_VMM
log("map %x to %x", table_paddr, table_paddr);
log("map %x to %x", table_paddr, table_vaddr);
#endif
table_paddr += bytes_per_table;
table_vaddr += bytes_per_table;
}
write_ttbr0((size_t)(pdir));
write_dacr(0x55555555);
mmu_enable();
}
void vm_setup_secondary_cpu()
{
write_ttbr0((uint32_t)(pdir));
write_dacr(0x55555555);
mmu_enable();
}

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

@@ -0,0 +1,54 @@
#ifndef _BOOT_VMM_VMM_H
#define _BOOT_VMM_VMM_H
#include "consts.h"
#include <libboot/types.h>
struct PACKED page_desc {
union {
struct {
unsigned int xn : 1; // Execute never. Stops execution of page.
unsigned int one : 1; // Always one for tables
unsigned int b : 1; // cacheable
unsigned int c : 1; // Cacheable
unsigned int ap1 : 2;
unsigned int tex : 3;
unsigned int ap2 : 1;
unsigned int s : 1;
unsigned int ng : 1;
unsigned int baddr : 20;
};
uint32_t data;
};
};
typedef struct page_desc page_desc_t;
struct PACKED table_desc {
union {
struct {
int valid : 1; /* Valid mapping */
int zero1 : 1;
int zero2 : 1;
int ns : 1;
int zero3 : 1;
int domain : 4;
int imp : 1;
int baddr : 22;
};
uint32_t data;
};
};
typedef struct table_desc table_desc_t;
typedef struct {
page_desc_t entities[VMM_LV0_ENTITY_COUNT];
} ptable_t;
typedef struct pdirectory {
table_desc_t entities[VMM_LV1_ENTITY_COUNT];
} pdirectory_t;
void vm_setup(size_t kernel_vaddr, size_t kernel_paddr, size_t kernel_size);
void vm_setup_secondary_cpu();
#endif // _BOOT_VMM_VMM_H

View File

@@ -0,0 +1,226 @@
#include "fb.h"
#include <libboot/devtree/devtree.h>
#include <libboot/types.h>
static char font8x8_basic[128][8];
static int _cursor_x = 0;
static int _cursor_y = 0;
static int _fbwidth = 0;
static int _fbheight = 0;
static int _fbpixels_per_row = 0;
static int _fbscale = 1;
static uint32_t _basecolor = 0x0;
volatile uint32_t* _fb = NULL;
static void system_cache_invalidate(void* addr, size_t size)
{
const size_t cache_line_size = 64;
size_t start = ROUND_FLOOR((size_t)addr, cache_line_size);
size_t end = ROUND_CEIL((size_t)addr + size, cache_line_size);
asm volatile("isb");
asm volatile("dsb sy");
for (size_t curaddr = start; curaddr < end; curaddr += cache_line_size) {
asm volatile("dc ivac, %0"
:
: "r"(curaddr));
}
asm volatile("dsb sy");
asm volatile("isb");
}
static void update_cursor_position(char c)
{
_cursor_x += 8 * _fbscale;
if (c == '\n' || (_cursor_x + 8 * _fbscale) > _fbwidth) {
_cursor_y += 8 * _fbscale;
_cursor_x = 0;
if ((_cursor_y + 8 * _fbscale + 2) > _fbheight) {
_cursor_y = 0;
}
}
}
static void draw_char_on_screen(char c)
{
for (int x = 0; x < (8 * _fbscale); x++) {
for (int y = 0; y < (8 * _fbscale); y++) {
uint32_t ind = (_cursor_x + x) + ((_cursor_y + y) * _fbpixels_per_row);
uint32_t clr = _basecolor;
if (font8x8_basic[c & 0x7f][y / _fbscale] & (1 << (x / _fbscale))) {
clr ^= 0xffffffff;
}
_fb[ind] = clr;
}
}
system_cache_invalidate((void*)&_fb[_cursor_y * _fbpixels_per_row], (1 + 8 * _fbscale) * _fbpixels_per_row * 4);
update_cursor_position(c);
}
int fb_init()
{
devtree_entry_t* dev = devtree_find_device("simplefb");
if (!dev) {
return -1;
}
_cursor_x = 0;
_cursor_y = 0;
_fb = (uint32_t*)dev->aux4;
_fbwidth = dev->aux1;
_fbheight = dev->aux2;
_fbpixels_per_row = dev->aux3;
_fbscale = 2;
return 0;
}
int fb_reinit_after_map(uintptr_t vaddr)
{
_fb = (uint32_t*)vaddr;
return 0;
}
int fb_put_char(uint8_t c)
{
if (!_fb) {
return -1;
}
draw_char_on_screen((char)c);
return 0;
}
static char font8x8_basic[128][8] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0000 (nul)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0001
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0002
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0003
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0004
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0005
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0006
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0007
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0008
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0009
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000A
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000B
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000C
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000D
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000E
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000F
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0010
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0011
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0012
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0013
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0014
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0015
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0016
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0017
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0018
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0019
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001A
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001B
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001C
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001D
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001E
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001F
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0020 (space)
{ 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00 }, // U+0021 (!)
{ 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0022 (")
{ 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00 }, // U+0023 (#)
{ 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00 }, // U+0024 ($)
{ 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00 }, // U+0025 (%)
{ 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00 }, // U+0026 (&)
{ 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0027 (')
{ 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00 }, // U+0028 (()
{ 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00 }, // U+0029 ())
{ 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00 }, // U+002A (*)
{ 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00 }, // U+002B (+)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06 }, // U+002C (,)
{ 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00 }, // U+002D (-)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00 }, // U+002E (.)
{ 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00 }, // U+002F (/)
{ 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00 }, // U+0030 (0)
{ 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00 }, // U+0031 (1)
{ 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00 }, // U+0032 (2)
{ 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00 }, // U+0033 (3)
{ 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00 }, // U+0034 (4)
{ 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00 }, // U+0035 (5)
{ 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00 }, // U+0036 (6)
{ 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00 }, // U+0037 (7)
{ 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00 }, // U+0038 (8)
{ 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00 }, // U+0039 (9)
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00 }, // U+003A (:)
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06 }, // U+003B (;)
{ 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00 }, // U+003C (<)
{ 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00 }, // U+003D (=)
{ 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00 }, // U+003E (>)
{ 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00 }, // U+003F (?)
{ 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00 }, // U+0040 (@)
{ 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00 }, // U+0041 (A)
{ 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00 }, // U+0042 (B)
{ 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00 }, // U+0043 (C)
{ 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00 }, // U+0044 (D)
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00 }, // U+0045 (E)
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00 }, // U+0046 (F)
{ 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00 }, // U+0047 (G)
{ 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00 }, // U+0048 (H)
{ 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00 }, // U+0049 (I)
{ 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00 }, // U+004A (J)
{ 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00 }, // U+004B (K)
{ 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00 }, // U+004C (L)
{ 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00 }, // U+004D (M)
{ 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00 }, // U+004E (N)
{ 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00 }, // U+004F (O)
{ 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00 }, // U+0050 (P)
{ 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00 }, // U+0051 (Q)
{ 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00 }, // U+0052 (R)
{ 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00 }, // U+0053 (S)
{ 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00 }, // U+0054 (T)
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00 }, // U+0055 (U)
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00 }, // U+0056 (V)
{ 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00 }, // U+0057 (W)
{ 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00 }, // U+0058 (X)
{ 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00 }, // U+0059 (Y)
{ 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00 }, // U+005A (Z)
{ 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00 }, // U+005B ([)
{ 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00 }, // U+005C (\)
{ 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00 }, // U+005D (])
{ 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00 }, // U+005E (^)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }, // U+005F (_)
{ 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0060 (`)
{ 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00 }, // U+0061 (a)
{ 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00 }, // U+0062 (b)
{ 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00 }, // U+0063 (c)
{ 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00 }, // U+0064 (d)
{ 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00 }, // U+0065 (e)
{ 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00 }, // U+0066 (f)
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F }, // U+0067 (g)
{ 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00 }, // U+0068 (h)
{ 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00 }, // U+0069 (i)
{ 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E }, // U+006A (j)
{ 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00 }, // U+006B (k)
{ 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00 }, // U+006C (l)
{ 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00 }, // U+006D (m)
{ 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00 }, // U+006E (n)
{ 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00 }, // U+006F (o)
{ 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F }, // U+0070 (p)
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78 }, // U+0071 (q)
{ 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00 }, // U+0072 (r)
{ 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00 }, // U+0073 (s)
{ 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00 }, // U+0074 (t)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00 }, // U+0075 (u)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00 }, // U+0076 (v)
{ 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00 }, // U+0077 (w)
{ 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00 }, // U+0078 (x)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F }, // U+0079 (y)
{ 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00 }, // U+007A (z)
{ 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00 }, // U+007B ({)
{ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00 }, // U+007C (|)
{ 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00 }, // U+007D (})
{ 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+007E (~)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // U+007F
};

View File

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

View File

@@ -0,0 +1,23 @@
#include "uart.h"
#include <libboot/devtree/devtree.h>
volatile uint32_t* output = NULL;
void uart_init()
{
devtree_entry_t* dev = devtree_find_device("uart");
if (!dev) {
return;
}
output = (uint32_t*)dev->region_base;
}
int uart_write(uint8_t data)
{
if (!output) {
return 1;
}
*output = data;
return 0;
}

View File

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

View File

@@ -0,0 +1,66 @@
.extern main
.section ".xos_boot_text"
prekernel_header:
nop // TODO(arm64): Add UEFI support
b prekernel_entry
prekernel_entry:
// Calculating location where of start address.
adr x20, .
adr x22, prekernel_header
adr x23, prekernel_entry
sub x21, x23, x22
sub x20, x20, x21
// Saving devtree
mov x21, x0
// Setting up prekernel stack.
ldr x30, =PREKERNEL_STACK_TOP_OFFSET
add x30, x20, x30
mov sp, x30
// Base of kernel
mov x0, x20
// Header location
ldr x1, =PREKERNEL_END_OFFSET
add x1, x20, x1
// Devtree location
mov x2, x21
ldr x3, =main
add x3, x3, x20
blr x3
entry_loop:
b entry_loop
.global jump_to_kernel
jump_to_kernel:
ic iallu
dsb sy
isb sy
blr x1
jump_loop:
b jump_loop
.global enable_mmu_el1
enable_mmu_el1:
dsb sy
msr mair_el1, x2
msr tcr_el1, x1
msr ttbr0_el1, x0
msr ttbr1_el1, x3
isb sy
tlbi vmalle1
isb sy
ic iallu
isb sy
mrs x3, sctlr_el1
orr x3, x3, #1
orr x3, x3, #4
and x3, x3, #(~2)
msr sctlr_el1, x3
ic iallu
dsb sy
isb sy
ret

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

@@ -0,0 +1,159 @@
#include "drivers/fb.h"
#include "drivers/uart.h"
#include "vm.h"
#include <libboot/abi/memory.h>
#include <libboot/abi/rawimage.h>
#include <libboot/devtree/devtree.h>
#include <libboot/elf/elf_lite.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
#define DEBUG_BOOT
#define EARLY_FB
extern void jump_to_kernel(void*, uintptr_t);
static void* bootdesc_paddr;
static void* bootdesc_vaddr;
static size_t kernel_vaddr = 0;
static size_t kernel_paddr = 0;
static size_t kernel_size = 0;
#define LAUNCH_SERVER_PATH "/System/launch_server"
static int alloc_init(uintptr_t base, rawimage_header_t* riheader)
{
devtree_entry_t* dev = devtree_find_device("ram");
if (!dev) {
#ifdef EARLY_FB
log("Can't find RAM in devtree");
#endif
while (1) { };
}
// Currenlty we setting the allocation after the raw image.
// Allocator is used to alloc paddrs for kernel, vm and other.
uintptr_t start_addr = ROUND_CEIL(base + riheader->rawimage_size, page_size());
size_t free_space = dev->region_size - (start_addr - dev->region_base);
malloc_init((void*)start_addr, free_space);
#if defined(DEBUG_BOOT) && defined(EARLY_FB)
log("malloc inited %llx %llx", start_addr, free_space);
#endif
return 0;
}
static size_t memory_layout_size()
{
return 0 + 1; // Including the trailing element.
}
static int preserve_alloc_init(size_t kernsize)
{
const size_t devtreesize = ROUND_CEIL(devtree_size(), page_size());
const size_t memmap = ROUND_CEIL(memory_layout_size() * sizeof(memory_layout_t), page_size());
const size_t bootargsstruct = ROUND_CEIL(sizeof(boot_args_t), page_size());
const size_t bootargssize = devtreesize + memmap + bootargsstruct;
// 32 tables should be enough for initial mappings.
const size_t prekernelvmsize = 32 * page_size();
const size_t total = ROUND_CEIL(kernsize + bootargssize + prekernelvmsize, page_size());
return palloc_init(total, 2 << 20);
}
static memory_boot_desc_t memory_boot_desc_init()
{
devtree_entry_t* dev = devtree_find_device("ram");
if (!dev) {
#ifdef EARLY_FB
log("Can't find RAM in devtree");
#endif
while (1) { };
}
memory_boot_desc_t res;
const size_t memlayout_size = memory_layout_size();
memory_layout_t* mem_layout_paddr = palloc_aligned(memlayout_size * sizeof(memory_layout_t), page_size());
// Init of trailing element.
mem_layout_paddr[memlayout_size - 1].flags = MEMORY_LAYOUT_FLAG_TERMINATE;
memory_layout_t* mem_layout_vaddr = paddr_to_vaddr(mem_layout_paddr, kernel_paddr, kernel_vaddr);
#if defined(DEBUG_BOOT) && defined(EARLY_FB)
log("initing MEMLAYOUT %lx of %d elems", mem_layout_vaddr, memlayout_size);
#endif
res.ram_base = dev->region_base;
res.ram_size = dev->region_size;
res.reserved_areas = mem_layout_vaddr;
return res;
}
static void load_kernel(void* kenrelstart)
{
kernel_size = elf_get_kernel_size(kenrelstart);
kernel_size = ROUND_CEIL(kernel_size, page_size());
int err = preserve_alloc_init(kernel_size);
if (err) {
#ifdef EARLY_FB
log("add assert");
#endif
while (1) { }
}
int res = elf_load_kernel(kenrelstart, kernel_size, &kernel_vaddr, &kernel_paddr);
#if defined(DEBUG_BOOT) && defined(EARLY_FB)
log("kernel %lx %lx %lx", kernel_vaddr, kernel_paddr, kernel_size);
#endif
void* odt_paddr = palloc_aligned(devtree_size(), page_size());
memcpy(odt_paddr, devtree_start(), devtree_size());
void* odt_vaddr = paddr_to_vaddr(odt_paddr, kernel_paddr, kernel_vaddr);
#if defined(DEBUG_BOOT) && defined(EARLY_FB)
log("copying ODT %lx -> %lx of %d", devtree_start(), odt_vaddr, devtree_size());
#endif
boot_args_t boot_args;
boot_args.vaddr = kernel_vaddr;
boot_args.paddr = kernel_paddr;
boot_args.kernel_data_size = 0x0; // Sets up later
boot_args.mem_boot_desc = memory_boot_desc_init();
boot_args.devtree = odt_vaddr;
boot_args.fb_boot_desc.vaddr = 0; // Marking fb as invalid.
memcpy(boot_args.init_process, LAUNCH_SERVER_PATH, sizeof(LAUNCH_SERVER_PATH));
bootdesc_paddr = palloc_aligned(sizeof(boot_args), page_size());
memcpy(bootdesc_paddr, &boot_args, sizeof(boot_args));
bootdesc_vaddr = paddr_to_vaddr(bootdesc_paddr, kernel_paddr, kernel_vaddr);
#if defined(DEBUG_BOOT) && defined(EARLY_FB)
log("copying BOOTDESC %lx -> %lx of %d", &boot_args, bootdesc_vaddr, sizeof(boot_args));
#endif
}
static int log_merged_output(uint8_t ch)
{
uart_write(ch);
fb_put_char(ch);
return 0;
}
int main(uintptr_t base, rawimage_header_t* riheader, void* devtree)
{
devtree_init((void*)(base + riheader->devtree_off), riheader->devtree_size);
uart_init();
fb_init();
log_init(log_merged_output);
alloc_init(base, riheader);
load_kernel((void*)(base + riheader->kern_off));
vm_setup(base, bootdesc_paddr, riheader);
#ifdef DEBUG_BOOT
log("Preboot done: booting to OS@%llx", ((boot_args_t*)bootdesc_vaddr)->vaddr);
#endif
((boot_args_t*)bootdesc_vaddr)->kernel_data_size = ROUND_CEIL(palloc_used_size(), page_size());
jump_to_kernel((void*)bootdesc_vaddr, ((boot_args_t*)bootdesc_vaddr)->vaddr);
return 0;
}

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

@@ -0,0 +1,168 @@
#include "vm.h"
#include "drivers/fb.h"
#include <libboot/abi/kernel.h>
#include <libboot/abi/rawimage.h>
#include <libboot/devtree/devtree.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
// #define DEBUG_VM
static uint64_t* global_page_table_0;
static uint64_t* global_page_table_1;
// This is setup for 4KB pages
static const int tg0 = 0b00;
static const int tg1 = 0b10;
static const int t0sz = 25;
static const int t1sz = 25;
static const uint64_t kernel_base = 0xffffffffffffffff - ((1ull << (64 - t1sz)) - 1);
static uint64_t* new_ptable(boot_args_t* args)
{
uint64_t* res = (uint64_t*)palloc_aligned(page_size(), page_size());
memset(res, 0, page_size());
#ifdef DEBUG_VM
log(" alloc ptable %llx %llx", (uint64_t)res, page_size());
#endif
return res;
}
// Huge page impl is not suitable for Apl, where we need percise mappings.
static void map4kb_1gb(boot_args_t* args, size_t phyz, size_t virt)
{
const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET);
const size_t page_mask = page_covers - 1;
if ((phyz & page_mask) != 0 || (virt & page_mask) != 0) {
return;
}
// Mapping from level2, as needed.
uint64_t* page_table = global_page_table_0;
if (virt >= kernel_base) {
page_table = global_page_table_1;
virt -= kernel_base;
}
uint64_t pdesc = 0x00000000000701;
pdesc |= (uintptr_t)phyz;
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)] = pdesc;
}
static void map4kb_2mb(boot_args_t* args, size_t phyz, size_t virt)
{
const size_t page_covers = (1ull << PTABLE_LV1_VADDR_OFFSET);
const size_t page_mask = page_covers - 1;
if ((phyz & page_mask) != 0 || (virt & page_mask) != 0) {
return;
}
// Mapping from level2, as needed.
uint64_t* page_table = global_page_table_0;
if (virt >= kernel_base) {
page_table = global_page_table_1;
virt -= kernel_base;
}
uint64_t ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)];
if (ptable_desc == 0) {
uint64_t* nptbl = new_ptable(args);
uint64_t pdesc = 0x00000000000003;
pdesc |= (uintptr_t)nptbl;
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)] = pdesc;
ptable_desc = pdesc;
}
page_table = (uint64_t*)(((ptable_desc >> 12) << 12) & 0xffffffffffff);
uint64_t pdesc = 0x00000000000701;
pdesc |= (uintptr_t)phyz;
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV1_VADDR_OFFSET, VMM_LV1_ENTITY_COUNT)] = pdesc;
}
static void map_uart(boot_args_t* args)
{
devtree_entry_t* dev = devtree_find_device("uart");
if (!dev) {
return;
}
uint64_t paddr = dev->region_base;
const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET);
paddr &= ~(page_covers - 1);
#ifdef DEBUG_VM
log("mapping %lx %lx", paddr, paddr);
#endif
map4kb_1gb(args, paddr, paddr);
}
static void map_fb(boot_args_t* args)
{
devtree_entry_t* dev = devtree_find_device("simplefb");
if (!dev) {
return;
}
uint64_t paddr = dev->region_base;
const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET);
paddr &= ~(page_covers - 1);
#ifdef DEBUG_VM
log("mapping %lx %lx", paddr, 0xfc0000000ULL);
#endif
map4kb_1gb(args, paddr, 0xfc0000000ULL);
args->fb_boot_desc.paddr = dev->region_base;
args->fb_boot_desc.vaddr = 0xfc0000000ULL + (args->fb_boot_desc.paddr - paddr);
args->fb_boot_desc.width = dev->aux1;
args->fb_boot_desc.height = dev->aux2;
args->fb_boot_desc.pixels_per_row = dev->aux3;
}
void vm_setup(uintptr_t base, boot_args_t* args, rawimage_header_t* riheader)
{
// This implementation is a stub, supporting only 4kb pages for now.
// We should support 16kb pages for sure on modern Apls.
global_page_table_0 = (uint64_t*)palloc_aligned(page_size(), page_size());
memset(global_page_table_0, 0, page_size());
global_page_table_1 = (uint64_t*)palloc_aligned(page_size(), page_size());
memset(global_page_table_1, 0, page_size());
const size_t map_range_2mb = (2 << 20);
const size_t map_range_1gb = (1 << 30);
// Mapping kernel vaddr to paddr
size_t kernel_size_to_map = palloc_total_size() + shadow_area_size();
size_t kernel_range_count_to_map = (kernel_size_to_map + (map_range_2mb - 1)) / map_range_2mb;
for (size_t i = 0; i < kernel_range_count_to_map; i++) {
#ifdef DEBUG_VM
log("mapping %lx %lx", args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb);
#endif
map4kb_2mb(args, args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb);
}
// Mapping RAM
size_t ram_base = ROUND_FLOOR(args->mem_boot_desc.ram_base, map_range_1gb);
size_t ram_size = args->mem_boot_desc.ram_size;
size_t ram_range_count_to_map = (ram_size + (map_range_1gb - 1)) / map_range_1gb;
for (size_t i = 0; i < ram_range_count_to_map; i++) {
#ifdef DEBUG_VM
log("mapping %lx %lx", ram_base + i * map_range_1gb, ram_base + i * map_range_1gb);
#endif
map4kb_1gb(args, ram_base + i * map_range_1gb, ram_base + i * map_range_1gb);
}
// The initial boot requires framebuffer and uart to be mapped.
// Checking this and mapping devices.
map_uart(args);
map_fb(args);
extern void enable_mmu_el1(uint64_t ttbr0, uint64_t tcr, uint64_t mair, uint64_t ttbr1);
enable_mmu_el1((uint64_t)global_page_table_0, 0x135003500 | (tg0 << 14) | (tg1 << 30) | (t1sz << 16) | t0sz, 0x04ff, (uint64_t)global_page_table_1);
fb_reinit_after_map(args->fb_boot_desc.vaddr);
}

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

@@ -0,0 +1,25 @@
#ifndef _BOOT_VM_H
#define _BOOT_VM_H
#include <libboot/abi/memory.h>
#include <libboot/abi/rawimage.h>
#include <libboot/types.h>
#define VMM_LV0_ENTITY_COUNT (512)
#define VMM_LV1_ENTITY_COUNT (512)
#define VMM_LV2_ENTITY_COUNT (512)
#define VMM_LV3_ENTITY_COUNT (512)
#define PTABLE_LV_TOP (2)
#define PTABLE_LV0_VADDR_OFFSET (12)
#define PTABLE_LV1_VADDR_OFFSET (21)
#define PTABLE_LV2_VADDR_OFFSET (30)
#define PTABLE_LV3_VADDR_OFFSET (39)
#define VM_VADDR_OFFSET_AT_LEVEL(vaddr, off, ent) ((vaddr >> off) % ent)
static size_t page_size() { return 0x1000; }
void vm_setup(uintptr_t base, boot_args_t* args, rawimage_header_t* riheader);
#endif // _BOOT_VM_H

View File

@@ -0,0 +1,29 @@
#ifndef _BOOT_LIBBOOT_ABI_DRIVERS_H
#define _BOOT_LIBBOOT_ABI_DRIVERS_H
#include <libboot/types.h>
#define MASKDEFINE(N, P, S) \
N##_POS = (P), \
N##_SIZE = (S), \
N##_MASK = ((~(~0 << (S))) << (P))
#define TOKEN_PASTE_IMPL(x, y) x##y
#define TOKEN_PASTE(x, y) TOKEN_PASTE_IMPL(x, y)
#define SKIP(x, y) char TOKEN_PASTE(prefix, __LINE__)[y - x - 8]
struct drive_desc {
void* init;
void* read;
void* write;
};
typedef struct drive_desc drive_desc_t;
struct fs_desc {
int (*get_inode)(drive_desc_t* drive_desc, const char* path, void* file_inode);
int (*read)(drive_desc_t* drive_desc, const char* path, uint8_t* buf, uint32_t from, uint32_t len);
int (*read_from_inode)(drive_desc_t* drive_desc, void* file_inode, uint8_t* buf, uint32_t from, uint32_t len);
};
typedef struct fs_desc fs_desc_t;
#endif // _BOOT_LIBBOOT_ABI_DRIVERS_H

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

@@ -0,0 +1,11 @@
#ifndef _BOOT_LIBBOOT_ABI_KERNEL_H
#define _BOOT_LIBBOOT_ABI_KERNEL_H
#include <libboot/types.h>
// Bootloaders and Kernel are tight together and share ABI in order
// to run kernel, see docs/boot.md for more information.
static size_t shadow_area_size() { return 4 << 20; }
#endif // _BOOT_LIBBOOT_ABI_KERNEL_H

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

@@ -0,0 +1,45 @@
#ifndef _BOOT_LIBBOOT_ABI_MEMORY_H
#define _BOOT_LIBBOOT_ABI_MEMORY_H
#include <libboot/types.h>
enum MEMORY_LAYOUT_FLAGS {
MEMORY_LAYOUT_FLAG_TERMINATE = (1 << 0),
};
struct memory_layout {
uint64_t base;
uint64_t size;
uint32_t flags;
};
typedef struct memory_layout memory_layout_t;
struct memory_boot_desc {
uint64_t ram_base;
uint64_t ram_size;
memory_layout_t* reserved_areas;
};
typedef struct memory_boot_desc memory_boot_desc_t;
struct fb_boot_desc {
uintptr_t vaddr;
uintptr_t paddr;
size_t width;
size_t height;
size_t pixels_per_row;
};
typedef struct fb_boot_desc fb_boot_desc_t;
struct boot_args {
size_t paddr;
size_t vaddr;
size_t kernel_data_size;
memory_boot_desc_t mem_boot_desc;
fb_boot_desc_t fb_boot_desc;
void* devtree;
char cmd_args[32];
char init_process[32];
};
typedef struct boot_args boot_args_t;
#endif // _BOOT_LIBBOOT_ABI_MEMORY_H

View File

@@ -0,0 +1,110 @@
#ifndef _BOOT_LIBBOOT_ABI_MULTIBOOT_H
#define _BOOT_LIBBOOT_ABI_MULTIBOOT_H
#include <libboot/types.h>
#define MULTIBOOT_INFO_MEMORY (0x1)
#define MULTIBOOT_INFO_BOOTDEV (0x2)
#define MULTIBOOT_INFO_CMDLINE (0x4)
#define MULTIBOOT_INFO_MODS (0x8)
#define MULTIBOOT_INFO_AOUT_SYMS (0x10)
#define MULTIBOOT_INFO_ELF_SHDR (0x20)
#define MULTIBOOT_INFO_MEM_MAP (0x40)
#define MULTIBOOT_INFO_DRIVE_INFO (0x80)
#define MULTIBOOT_INFO_CONFIG_TABLE (0x100)
#define MULTIBOOT_INFO_BOOT_LOADER_NAME (0x200)
#define MULTIBOOT_INFO_APM_TABLE (0x400)
#define MULTIBOOT_INFO_VBE_INFO (0x800)
#define MULTIBOOT_INFO_FRAMEBUFFER_INFO (0x1000)
struct multiboot_module_entry {
uint32_t start;
uint32_t end;
uint32_t string_addr;
uint32_t reserved;
};
typedef struct multiboot_module_entry multiboot_module_entry_t;
struct multiboot_aout_symbol_table {
uint32_t tabsize;
uint32_t strsize;
uint32_t addr;
uint32_t reserved;
};
typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
struct multiboot_elf_section_header_table {
uint32_t num;
uint32_t size;
uint32_t addr;
uint32_t shndx;
};
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
#define MULTIBOOT_MEMORY_NVS 4
#define MULTIBOOT_MEMORY_BADRAM 5
struct PACKED multiboot_mmap_entry {
uint32_t size;
uint64_t addr;
uint64_t len;
uint32_t type;
};
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
struct multiboot_info {
uint32_t flags;
uint32_t mem_lower;
uint32_t mem_upper;
uint32_t boot_device;
uint32_t cmdline;
uint32_t mods_count;
uint32_t mods_addr;
union {
multiboot_aout_symbol_table_t aout_sym;
multiboot_elf_section_header_table_t elf_sec;
} syms;
uint32_t mmap_length;
uint32_t mmap_addr;
uint32_t drives_length;
uint32_t drives_addr;
uint32_t config_table;
uint32_t boot_loader_name;
uint32_t apm_table;
uint32_t vbe_control_info;
uint32_t vbe_mode_info;
uint16_t vbe_mode;
uint16_t vbe_interface_seg;
uint16_t vbe_interface_off;
uint16_t vbe_interface_len;
uint64_t framebuffer_addr;
uint32_t framebuffer_pitch;
uint32_t framebuffer_width;
uint32_t framebuffer_height;
uint8_t framebuffer_bpp;
uint8_t framebuffer_type;
union {
struct
{
uint32_t framebuffer_palette_addr;
uint16_t framebuffer_palette_num_colors;
};
struct
{
uint8_t framebuffer_red_field_position;
uint8_t framebuffer_red_mask_size;
uint8_t framebuffer_green_field_position;
uint8_t framebuffer_green_mask_size;
uint8_t framebuffer_blue_field_position;
uint8_t framebuffer_blue_mask_size;
};
};
};
typedef struct multiboot_info multiboot_info_t;
#endif // _BOOT_LIBBOOT_ABI_MULTIBOOT_H

View File

@@ -0,0 +1,18 @@
#ifndef _BOOT_LIBBOOT_ABI_RAWIMAGE_H
#define _BOOT_LIBBOOT_ABI_RAWIMAGE_H
#include <libboot/types.h>
struct rawimage_header {
uint64_t kern_off;
uint64_t kern_size;
uint64_t devtree_off;
uint64_t devtree_size;
uint64_t ramdisk_off;
uint64_t ramdisk_size;
uint64_t rawimage_size;
uint64_t padding;
};
typedef struct rawimage_header rawimage_header_t;
#endif // _BOOT_LIBBOOT_ABI_RAWIMAGE_H

View File

@@ -0,0 +1,149 @@
#include "sha256.h"
#include <libboot/log/log.h>
#include <libboot/mem/mem.h>
const static sha256_word_t sha256_consts[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
const static sha256_word_t sha256_state_init[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
#define ROTLEFT(a, b) (((a) << (b)) | ((a) >> (32 - (b))))
#define ROTRIGHT(a, b) (((a) >> (b)) | ((a) << (32 - (b))))
#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define EP0(x) (ROTRIGHT(x, 2) ^ ROTRIGHT(x, 13) ^ ROTRIGHT(x, 22))
#define EP1(x) (ROTRIGHT(x, 6) ^ ROTRIGHT(x, 11) ^ ROTRIGHT(x, 25))
#define SIG0(x) (ROTRIGHT(x, 7) ^ ROTRIGHT(x, 18) ^ ((x) >> 3))
#define SIG1(x) (ROTRIGHT(x, 17) ^ ROTRIGHT(x, 19) ^ ((x) >> 10))
static void sha256_transform(sha256_ctx_t* ctx, const void* vdata)
{
sha256_byte_t* data = (sha256_byte_t*)vdata;
sha256_word_t m[64];
size_t i = 0;
for (sha256_word_t j = 0; i < 16; i++, j += 4) {
m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
}
for (; i < 64; i++) {
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
}
sha256_word_t a = ctx->state[0];
sha256_word_t b = ctx->state[1];
sha256_word_t c = ctx->state[2];
sha256_word_t d = ctx->state[3];
sha256_word_t e = ctx->state[4];
sha256_word_t f = ctx->state[5];
sha256_word_t g = ctx->state[6];
sha256_word_t h = ctx->state[7];
for (i = 0; i < 64; i++) {
sha256_word_t t1 = h + EP1(e) + CH(e, f, g) + sha256_consts[i] + m[i];
sha256_word_t t2 = EP0(a) + MAJ(a, b, c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
ctx->state[4] += e;
ctx->state[5] += f;
ctx->state[6] += g;
ctx->state[7] += h;
}
void sha256_init(sha256_ctx_t* ctx)
{
ctx->bufnxt = 0;
ctx->bits_count = 0;
memcpy(ctx->state, sha256_state_init, sizeof(sha256_state_init));
}
void sha256_update(sha256_ctx_t* ctx, const void* vdata, size_t len)
{
sha256_byte_t* data = (sha256_byte_t*)vdata;
for (size_t i = 0; i < len; i++) {
ctx->buf[ctx->bufnxt] = data[i];
ctx->bufnxt++;
if (ctx->bufnxt == 64) {
sha256_transform(ctx, ctx->buf);
ctx->bits_count += 512;
ctx->bufnxt = 0;
}
}
}
void sha256_hash(sha256_ctx_t* ctx, char* hash)
{
size_t i = ctx->bufnxt;
if (ctx->bufnxt < 56) {
ctx->buf[i++] = 0x80;
} else {
ctx->buf[i++] = 0x80;
while (i < 64) {
ctx->buf[i++] = 0x00;
}
sha256_transform(ctx, ctx->buf);
i = 0;
}
while (i < 56) {
ctx->buf[i++] = 0x00;
}
ctx->bits_count += ctx->bufnxt * 8;
ctx->buf[56] = ctx->bits_count >> 56;
ctx->buf[57] = ctx->bits_count >> 48;
ctx->buf[58] = ctx->bits_count >> 40;
ctx->buf[59] = ctx->bits_count >> 32;
ctx->buf[60] = ctx->bits_count >> 24;
ctx->buf[61] = ctx->bits_count >> 16;
ctx->buf[62] = ctx->bits_count >> 8;
ctx->buf[63] = ctx->bits_count >> 0;
sha256_transform(ctx, ctx->buf);
// Making hash big endian.
for (i = 0; i < 4; i++) {
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
}
}

View File

@@ -0,0 +1,22 @@
#ifndef _BOOT_LIBBOOT_CRYPTO_SHA256_H
#define _BOOT_LIBBOOT_CRYPTO_SHA256_H
#include <libboot/mem/mem.h>
#include <libboot/types.h>
typedef uint8_t sha256_byte_t;
typedef uint32_t sha256_word_t;
struct sha256_ctx {
uint64_t bits_count;
sha256_word_t state[8];
sha256_word_t bufnxt;
sha256_byte_t buf[64];
};
typedef struct sha256_ctx sha256_ctx_t;
void sha256_init(sha256_ctx_t* ctx);
void sha256_update(sha256_ctx_t* ctx, const void* data, size_t len);
void sha256_hash(sha256_ctx_t* ctx, char* hash);
#endif // #define _BOOT_LIBBOOT_CRYPTO_SHA256_H

View File

@@ -0,0 +1,136 @@
const char pub_xos_key_e[] = {
(char)0x1,
(char)0x0,
(char)0x1,
};
const char pub_xos_key_n[] = {
(char)0x1d,
(char)0x7e,
(char)0x51,
(char)0xed,
(char)0xdc,
(char)0x86,
(char)0x89,
(char)0x86,
(char)0xb1,
(char)0xa4,
(char)0x84,
(char)0x87,
(char)0xc9,
(char)0x35,
(char)0xe7,
(char)0x7f,
(char)0x8a,
(char)0xea,
(char)0xcb,
(char)0xda,
(char)0xdf,
(char)0xec,
(char)0x7a,
(char)0xa5,
(char)0x2a,
(char)0x60,
(char)0x15,
(char)0x91,
(char)0x14,
(char)0xd5,
(char)0x2c,
(char)0xbb,
(char)0x8f,
(char)0x8f,
(char)0xad,
(char)0x17,
(char)0x5b,
(char)0xd7,
(char)0xda,
(char)0x4d,
(char)0x4b,
(char)0xe3,
(char)0x3e,
(char)0x83,
(char)0xb5,
(char)0xb4,
(char)0x38,
(char)0x60,
(char)0x59,
(char)0x94,
(char)0xef,
(char)0xad,
(char)0x39,
(char)0x72,
(char)0x9d,
(char)0x7d,
(char)0xc6,
(char)0x1b,
(char)0xcf,
(char)0x4e,
(char)0x6f,
(char)0xee,
(char)0xf7,
(char)0xd3,
(char)0xbc,
(char)0xcf,
(char)0xe9,
(char)0xb9,
(char)0xf1,
(char)0x21,
(char)0xef,
(char)0x9a,
(char)0x6,
(char)0x75,
(char)0xc8,
(char)0xc2,
(char)0x6e,
(char)0x99,
(char)0x28,
(char)0xa6,
(char)0x3,
(char)0xe6,
(char)0xc6,
(char)0x4d,
(char)0x2,
(char)0x83,
(char)0xe4,
(char)0xe0,
(char)0x21,
(char)0xd9,
(char)0x19,
(char)0x11,
(char)0x29,
(char)0xe8,
(char)0xff,
(char)0x11,
(char)0x7,
(char)0x23,
(char)0x44,
(char)0x7f,
(char)0xfb,
(char)0x76,
(char)0xb1,
(char)0x7,
(char)0xe7,
(char)0xab,
(char)0x83,
(char)0x7e,
(char)0xa6,
(char)0xd9,
(char)0x7a,
(char)0x50,
(char)0x36,
(char)0xf,
(char)0xb3,
(char)0xc0,
(char)0xb7,
(char)0x4f,
(char)0x17,
(char)0xc7,
(char)0xb5,
(char)0x50,
(char)0xe8,
(char)0xe6,
(char)0xc1,
(char)0x3f,
(char)0x5f,
(char)0xa6,
};

View File

@@ -0,0 +1,10 @@
#ifndef _BOOT_LIBBOOT_CRYPTO_SIGNATURE_H
#define _BOOT_LIBBOOT_CRYPTO_SIGNATURE_H
#define pub_xos_key_e_len (3)
extern const char pub_xos_key_e[];
#define pub_xos_key_n_len (128)
extern const char pub_xos_key_n[];
#endif // _BOOT_LIBBOOT_CRYPTO_SIGNATURE_H

View File

@@ -0,0 +1,299 @@
#include "uint2048.h"
#include <libboot/log/log.h>
#include <libboot/mem/mem.h>
#define EOVERFLOW 75
int uint2048_init(uint2048_t* d, uint32_t n)
{
int i = 0;
d->bucket[i++] = n;
while (i < N_UINT2048) {
d->bucket[i++] = 0;
}
return 0;
}
int uint2048_init_bytes(uint2048_t* d, const char* f, size_t n)
{
if (n > sizeof(uint2048_t)) {
return -1;
}
memset(d->bucket, 0, sizeof(uint2048_t));
memcpy(d->bucket, f, n);
return 0;
}
static inline uint32_t char_to_u32_safe_convert(char x)
{
return x >= 0 ? x : 256 + x;
}
int uint2048_init_bytes_be(uint2048_t* d, const char* f, size_t n)
{
if (n > sizeof(uint2048_t)) {
return -1;
}
size_t i = 0;
uint32_t bytes4 = 0;
size_t dd = (n / 4) * 4;
size_t dr = n - dd;
for (int fi = n - 4; fi >= 0; fi -= 4) {
bytes4 = 0;
bytes4 |= char_to_u32_safe_convert(f[fi]) << 24;
bytes4 |= char_to_u32_safe_convert(f[fi + 1]) << 16;
bytes4 |= char_to_u32_safe_convert(f[fi + 2]) << 8;
bytes4 |= char_to_u32_safe_convert(f[fi + 3]) << 0;
d->bucket[i++] = bytes4;
}
bytes4 = 0;
for (int remi = dr - 1; remi >= 0; remi--) {
bytes4 |= char_to_u32_safe_convert(f[dd + remi]) << (remi * 8);
}
d->bucket[i++] = bytes4;
while (i < N_UINT2048) {
d->bucket[i++] = 0;
}
return 0;
}
int uint2048_copy(uint2048_t* dest, uint2048_t* src)
{
memcpy(dest, src, sizeof(uint2048_bucket_t) * N_UINT2048);
return 0;
}
int uint2048_add(uint2048_t* a, uint2048_t* b, uint2048_t* c)
{
uint64_t carry = 0;
uint64_t sum = 0;
for (int i = 0; i < N_UINT2048; i++) {
uint64_t ab = a->bucket[i];
uint64_t bb = b->bucket[i];
sum = ab + bb + carry;
if (sum >= BASE_UINT2048U) {
carry = 1;
sum -= BASE_UINT2048U;
} else {
carry = 0;
}
c->bucket[i] = (uint2048_bucket_t)sum;
}
return carry ? -EOVERFLOW : 0;
}
int uint2048_sub(uint2048_t* a, uint2048_t* b, uint2048_t* c)
{
uint32_t carry = 0;
uint64_t sum = 0;
for (int i = 0; i < N_UINT2048; i++) {
uint64_t ab = a->bucket[i];
uint64_t bb = b->bucket[i];
sum = carry + bb;
if (ab >= sum) {
ab = ab - (sum);
carry = 0;
} else {
ab = ab + BASE_UINT2048U - (sum);
carry = 1;
}
c->bucket[i] = (uint2048_bucket_t)ab;
}
if (carry) {
uint2048_init(c, 0);
}
return carry ? -EOVERFLOW : 0;
}
int uint2048_shl(uint2048_t* a, int n)
{
int i;
for (i = N_UINT2048 - 1; i >= n; i--) {
a->bucket[i] = a->bucket[i - n];
}
while (i >= 0) {
a->bucket[i--] = 0;
}
return 0;
}
int uint2048_shr(uint2048_t* a, int n)
{
int i;
for (i = 0; i < N_UINT2048 - n; i++) {
a->bucket[i] = a->bucket[i + n];
}
while (i < N_UINT2048) {
a->bucket[i++] = 0;
}
return 0;
}
int uint2048_mult_by_digit(uint2048_t* a, uint2048_t* b, uint2048_bucket_t un)
{
uint64_t carry = 0;
uint64_t tmp;
uint64_t n = (uint64_t)un;
for (int i = 0; i < N_UINT2048; i++) {
uint64_t ab = a->bucket[i];
tmp = n * ab + carry;
if (tmp >= BASE_UINT2048U) {
carry = tmp / BASE_UINT2048U;
tmp %= BASE_UINT2048U;
} else {
carry = 0;
}
b->bucket[i] = (uint2048_bucket_t)tmp;
}
return carry ? -EOVERFLOW : 0;
}
int uint2048_mult(uint2048_t* a, uint2048_t* b, uint2048_t* c)
{
uint2048_t p;
uint2048_init(c, 0);
for (int i = 0; i < N_UINT2048; i++) {
if (!a->bucket[i]) {
continue;
}
uint2048_mult_by_digit(b, &p, a->bucket[i]);
uint2048_shl(&p, i);
uint2048_add(c, &p, c);
}
return 0;
}
int uint2048_div(uint2048_t* a, uint2048_t* b, uint2048_t* dividend, uint2048_t* reminder)
{
uint2048_t tmp;
if (dividend) {
uint2048_init(dividend, 0);
}
uint2048_init(reminder, 0);
for (int i = N_UINT2048 - 1; i >= 0; i--) {
uint2048_shl(reminder, 1);
reminder->bucket[0] = a->bucket[i];
uint64_t l = 0, r = BASE_UINT2048U;
while (r - l > 1) {
uint64_t m = (l + r) / 2;
uint2048_mult_by_digit(b, &tmp, (uint2048_bucket_t)m);
if (uint2048_less_equal(&tmp, reminder)) {
l = m;
} else {
r = m;
}
}
if (dividend) {
dividend->bucket[i] = (uint2048_bucket_t)l;
}
uint2048_mult_by_digit(b, &tmp, (uint2048_bucket_t)l);
uint2048_sub(reminder, &tmp, reminder);
}
return 0;
}
int uint2048_pow(uint2048_t* ua, uint2048_t* up, uint2048_t* mod, uint2048_t* ans)
{
uint2048_t tmp1;
uint2048_t tmp2;
uint2048_t const2;
uint2048_t a;
uint2048_t p;
uint2048_copy(&a, ua);
uint2048_copy(&p, up);
uint2048_init(ans, 1);
uint2048_init(&const2, 2);
while (uint2048_is_not_zero(&p)) {
if (uint2048_is_odd(&p)) {
uint2048_mult(ans, &a, &tmp1);
uint2048_div(&tmp1, mod, NULL, &tmp2);
uint2048_copy(ans, &tmp2);
}
uint2048_mult(&a, &a, &tmp1);
uint2048_div(&tmp1, mod, NULL, &tmp2);
uint2048_copy(&a, &tmp2);
uint2048_div(&p, &const2, &tmp1, &tmp2);
uint2048_copy(&p, &tmp1);
}
return 0;
}
bool uint2048_less(uint2048_t* a, uint2048_t* b)
{
for (int i = N_UINT2048 - 1; i >= 0; i--) {
if (a->bucket[i] < b->bucket[i]) {
return true;
}
if (a->bucket[i] > b->bucket[i]) {
return false;
}
}
return false;
}
bool uint2048_less_equal(uint2048_t* a, uint2048_t* b)
{
for (int i = N_UINT2048 - 1; i >= 0; i--) {
if (a->bucket[i] < b->bucket[i]) {
return true;
}
if (a->bucket[i] > b->bucket[i]) {
return false;
}
}
return true;
}
bool uint2048_equal(uint2048_t* a, uint2048_t* b)
{
for (int i = 0; i < N_UINT2048; i++) {
if (a->bucket[i] != b->bucket[i]) {
return false;
}
}
return true;
}
bool uint2048_is_not_zero(uint2048_t* a)
{
for (int i = 0; i < N_UINT2048; i++) {
if (a->bucket[i] != 0) {
return true;
}
}
return false;
}
bool uint2048_is_odd(uint2048_t* a)
{
return (a->bucket[0] % 2) == 1;
}
int uint2048_dump(uint2048_t* a)
{
log("dumping");
for (int i = N_UINT2048 - 1; i >= 0; i--) {
log(" %x", a->bucket[i]);
}
return 0;
}

View File

@@ -0,0 +1,43 @@
#ifndef _BOOT_LIBBOOT_CRYPTO_UINT2048_H
#define _BOOT_LIBBOOT_CRYPTO_UINT2048_H
#include <libboot/mem/mem.h>
#include <libboot/types.h>
#define N_UINT2048 (64)
#define BITS_IN_BASE_UINT2048 (32)
#define BASE_UINT2048 ((uint64_t)((uint64_t)1 << BITS_IN_BASE_UINT2048))
#define BASE_UINT2048U ((uint64_t)((uint64_t)1 << (uint64_t)BITS_IN_BASE_UINT2048))
typedef uint32_t uint2048_bucket_t;
struct uint2048 {
uint2048_bucket_t bucket[N_UINT2048];
};
typedef struct uint2048 uint2048_t;
int uint2048_init(uint2048_t* d, uint32_t n);
int uint2048_init_bytes(uint2048_t* d, const char* f, size_t n);
int uint2048_init_bytes_be(uint2048_t* d, const char* f, size_t n);
int uint2048_copy(uint2048_t* dest, uint2048_t* src);
int uint2048_add(uint2048_t* a, uint2048_t* b, uint2048_t* c);
int uint2048_sub(uint2048_t* a, uint2048_t* b, uint2048_t* c);
int uint2048_shl(uint2048_t* a, int n);
int uint2048_shr(uint2048_t* a, int n);
int uint2048_mult_by_digit(uint2048_t* a, uint2048_t* b, uint2048_bucket_t un);
int uint2048_mult(uint2048_t* a, uint2048_t* b, uint2048_t* c);
int uint2048_div(uint2048_t* a, uint2048_t* b, uint2048_t* ans, uint2048_t* rem);
int uint2048_pow(uint2048_t* ua, uint2048_t* up, uint2048_t* mod, uint2048_t* ans);
bool uint2048_equal(uint2048_t* a, uint2048_t* b);
bool uint2048_less(uint2048_t* a, uint2048_t* b);
bool uint2048_less_equal(uint2048_t* a, uint2048_t* b);
bool uint2048_is_not_zero(uint2048_t* a);
bool uint2048_is_odd(uint2048_t* a);
int uint2048_dump(uint2048_t* a);
#endif // _BOOT_LIBBOOT_CRYPTO_UINT2048_H

View File

@@ -0,0 +1,103 @@
#include <libboot/crypto/sha256.h>
#include <libboot/crypto/signature.h>
#include <libboot/crypto/uint2048.h>
#include <libboot/crypto/validate.h>
#include <libboot/elf/elf_lite.h>
#include <libboot/fs/ext2_lite.h>
#include <libboot/log/log.h>
#define tmp_buf_size (4096)
char tmp_buf[tmp_buf_size];
static int get_elf_signature(elfctx_t* elfctx, void* signature_buffer)
{
elf_section_header_32_t shstrtab_section_header;
elf_read_section_header(elfctx, elfctx->header.e_shstrndx, &shstrtab_section_header);
uintptr_t shstrtab_offset = shstrtab_section_header.sh_offset;
for (uint32_t i = 0; i < elfctx->header.e_shnum; i++) {
elf_section_header_32_t section_header;
elf_read_section_header(elfctx, i, &section_header);
char tmp_name_buffer[32];
uintptr_t name_offset_abs = shstrtab_offset + section_header.sh_name;
elfctx->fs_desc->read_from_inode(elfctx->drive_desc, &elfctx->file_inode, (void*)tmp_name_buffer, name_offset_abs, 32);
size_t len = strnlen(tmp_name_buffer, 32);
if (len != sizeof("._signature") - 1) {
continue;
}
if (memcmp(tmp_name_buffer, "._signature", len)) {
continue;
}
elfctx->fs_desc->read_from_inode(elfctx->drive_desc, &elfctx->file_inode, signature_buffer, section_header.sh_offset, 128);
return 0;
}
return -1;
}
static int calc_elf_hash(elfctx_t* elfctx, char* hash)
{
sha256_ctx_t shactx;
sha256_init(&shactx);
for (uint32_t i = 0; i < elfctx->header.e_phnum; i++) {
elf_program_header_32_t program_header;
elf_read_program_header(elfctx, i, &program_header);
if (program_header.p_type != PT_LOAD) {
continue;
}
size_t from = program_header.p_offset;
size_t rem_to_read = program_header.p_filesz;
while (rem_to_read) {
size_t will_read = min(tmp_buf_size, rem_to_read);
int rd = elfctx->fs_desc->read_from_inode(elfctx->drive_desc, &elfctx->file_inode, (void*)tmp_buf, from, will_read);
from += will_read;
sha256_update(&shactx, tmp_buf, will_read);
rem_to_read -= will_read;
}
}
sha256_hash(&shactx, hash);
return 0;
}
bool validate_elf(const char* path, drive_desc_t* drive_desc, fs_desc_t* fs_desc)
{
elfctx_t elfctx;
char hash[32];
int err = elf_init_ctx(drive_desc, fs_desc, path, &elfctx);
if (err) {
return false;
}
err = get_elf_signature(&elfctx, tmp_buf);
if (err) {
return false;
}
uint2048_t signature;
uint2048_init_bytes(&signature, tmp_buf, 128);
err = calc_elf_hash(&elfctx, hash);
if (err) {
return false;
}
uint2048_t ihash;
uint2048_init_bytes_be(&ihash, hash, 32);
uint2048_t public_e;
uint2048_init_bytes(&public_e, pub_xos_key_e, pub_xos_key_e_len);
uint2048_t public_n;
uint2048_init_bytes(&public_n, pub_xos_key_n, pub_xos_key_n_len);
uint2048_t signed_ihash;
uint2048_pow(&signature, &public_e, &public_n, &signed_ihash);
return uint2048_equal(&signed_ihash, &ihash);
}

View File

@@ -0,0 +1,11 @@
#ifndef STAGE2_SECURITY_VALIDATE_H
#define STAGE2_SECURITY_VALIDATE_H
#include <libboot/abi/drivers.h>
#include <libboot/abi/memory.h>
#include <libboot/types.h>
bool validate_file(const char* path, const char* signature_path, drive_desc_t* drive_desc, fs_desc_t* fs_desc);
bool validate_elf(const char* path, drive_desc_t* drive_desc, fs_desc_t* fs_desc);
#endif // STAGE2_SECURITY_VALIDATE_H

View File

@@ -0,0 +1,52 @@
#include "devtree.h"
#include <libboot/log/log.h>
#include <libboot/mem/mem.h>
static size_t _devtree_size = 0;
static devtree_header_t* _devtree_header = NULL;
static devtree_entry_t* _devtree_body = NULL;
static char* _devtree_name_section = NULL;
void* devtree_start()
{
return (void*)_devtree_header;
}
size_t devtree_size()
{
return _devtree_size;
}
int devtree_init(void* devtree, size_t size)
{
if (!devtree) {
return 0;
}
devtree_header_t* dth = (devtree_header_t*)devtree;
_devtree_header = dth;
_devtree_body = (devtree_entry_t*)&dth[1];
_devtree_name_section = ((char*)dth + dth->name_list_offset);
_devtree_size = size;
return 0;
}
const char* devtree_name_of_entry(devtree_entry_t* en)
{
return &_devtree_name_section[en->rel_name_offset];
}
devtree_entry_t* devtree_find_device(const char* name)
{
if (!_devtree_body) {
return NULL;
}
for (int i = 0; i < _devtree_header->entries_count; i++) {
const char* curdev_name = devtree_name_of_entry(&_devtree_body[i]);
if (strcmp(curdev_name, name) == 0) {
return &_devtree_body[i];
}
}
return NULL;
}

View File

@@ -0,0 +1,50 @@
#ifndef _BOOT_LIBBOOT_DEVTREE_DEVTREE_H
#define _BOOT_LIBBOOT_DEVTREE_DEVTREE_H
#include <libboot/mem/mem.h>
#include <libboot/types.h>
#define DEVTREE_HEADER_SIGNATURE ("odtr3")
#define DEVTREE_HEADER_SIGNATURE_LEN (sizeof(DEVTREE_HEADER_SIGNATURE) - 1)
struct PACKED devtree_header {
char signature[8];
uint32_t revision;
uint32_t flags;
uint32_t entries_count;
uint32_t name_list_offset;
};
typedef struct devtree_header devtree_header_t;
#define DEVTREE_ENTRY_FLAGS_MMIO = (1 << 0)
#define DEVTREE_ENTRY_TYPE_IO (0)
#define DEVTREE_ENTRY_TYPE_FB (1)
#define DEVTREE_ENTRY_TYPE_UART (2)
#define DEVTREE_ENTRY_TYPE_RAM (3)
#define DEVTREE_ENTRY_TYPE_STORAGE (4)
#define DEVTREE_ENTRY_TYPE_BUS_CONTROLLER (5)
#define DEVTREE_ENTRY_TYPE_RTC (6)
struct PACKED devtree_entry {
uint32_t type;
uint32_t flags;
uint64_t region_base;
uint64_t region_size;
uint32_t irq_lane;
uint32_t irq_flags;
uint32_t irq_priority;
uint32_t rel_name_offset;
uint64_t aux1;
uint64_t aux2;
uint64_t aux3;
uint64_t aux4;
};
typedef struct devtree_entry devtree_entry_t;
int devtree_init(void* devtree, size_t size);
const char* devtree_name_of_entry(devtree_entry_t* en);
devtree_entry_t* devtree_find_device(const char* name);
void* devtree_start();
size_t devtree_size();
#endif // _BOOT_LIBBOOT_DEVTREE_DEVTREE_H

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

@@ -0,0 +1,144 @@
#include "elf_lite.h"
#include <libboot/crypto/sha256.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
// #define DEBUG_ELF
int elf_init_ctx(drive_desc_t* drive_desc, fs_desc_t* fs_desc, const char* path, elfctx_t* elfctx)
{
elfctx->drive_desc = drive_desc;
elfctx->fs_desc = fs_desc;
fs_desc->get_inode(drive_desc, path, &elfctx->file_inode);
fs_desc->read_from_inode(drive_desc, &elfctx->file_inode, (void*)&elfctx->header, 0, sizeof(elfctx->header));
if (elfctx->header.e_ident[EI_MAG0] != 0x7F || elfctx->header.e_ident[EI_MAG1] != 0x45 || elfctx->header.e_ident[EI_MAG2] != 0x4c || elfctx->header.e_ident[EI_MAG3] != 0x46) {
return -1;
}
return 0;
}
int elf_read_program_header(elfctx_t* elfctx, size_t id, elf_program_header_32_t* program_header)
{
uintptr_t offset = elfctx->header.e_phoff + id * elfctx->header.e_phentsize;
return elfctx->fs_desc->read_from_inode(elfctx->drive_desc, &elfctx->file_inode, (void*)program_header, offset, sizeof(*program_header));
}
int elf_read_section_header(elfctx_t* elfctx, uint32_t id, elf_section_header_32_t* section_header)
{
uintptr_t offset = elfctx->header.e_shoff + id * elfctx->header.e_shentsize;
return elfctx->fs_desc->read_from_inode(elfctx->drive_desc, &elfctx->file_inode, (void*)section_header, offset, sizeof(*section_header));
}
#ifdef BITS32
int elf_load_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc, const char* path, size_t* kernel_vaddr, size_t* kernel_paddr, size_t* kernel_size)
{
elfctx_t elfctx;
int err = elf_init_ctx(drive_desc, fs_desc, path, &elfctx);
if (err) {
return err;
}
size_t vaddr = -1;
size_t paddr = -1;
size_t vaddr_end = 0;
for (uint32_t i = 0; i < elfctx.header.e_phnum; i++) {
elf_program_header_32_t program_header;
elf_read_program_header(&elfctx, i, &program_header);
if (program_header.p_type == PT_LOAD) {
paddr = min(paddr, program_header.p_paddr);
vaddr = min(vaddr, program_header.p_vaddr);
fs_desc->read(drive_desc, path, (void*)program_header.p_paddr, program_header.p_offset, program_header.p_filesz);
}
}
for (uint32_t i = 0; i < elfctx.header.e_shnum; i++) {
elf_section_header_32_t section_header;
elf_read_section_header(&elfctx, i, &section_header);
if ((section_header.sh_flags & SHF_ALLOC) == SHF_ALLOC) {
vaddr_end = max(vaddr_end, section_header.sh_addr + section_header.sh_size);
}
}
*kernel_vaddr = vaddr;
*kernel_paddr = paddr;
*kernel_size = vaddr_end - vaddr;
return 0;
}
// #endif
#else
size_t elf_get_kernel_size(void* elffile)
{
elf_header_64_t* header = (elf_header_64_t*)elffile;
if (header->e_ident[EI_MAG0] != 0x7F || header->e_ident[EI_MAG1] != 0x45 || header->e_ident[EI_MAG2] != 0x4c || header->e_ident[EI_MAG3] != 0x46) {
return -1;
}
size_t vaddr = 0xffffffffffffffff;
size_t vaddr_end = 0;
for (size_t i = 0; i < header->e_phnum; i++) {
uintptr_t offset = header->e_phoff + i * header->e_phentsize;
elf_program_header_64_t* program_header = (elf_program_header_64_t*)((uintptr_t)elffile + offset);
if (program_header->p_type == PT_LOAD) {
vaddr = min(vaddr, program_header->p_vaddr);
}
}
for (size_t i = 0; i < header->e_shnum; i++) {
uintptr_t offset = header->e_shoff + i * header->e_shentsize;
elf_section_header_64_t* section_header = (elf_section_header_64_t*)((uintptr_t)elffile + offset);
if ((section_header->sh_flags & SHF_ALLOC) == SHF_ALLOC) {
vaddr_end = max(vaddr_end, section_header->sh_addr + section_header->sh_size);
}
}
return vaddr_end - vaddr;
}
int elf_load_kernel(void* elffile, size_t size, uintptr_t* kernel_vaddr, uintptr_t* kernel_paddr)
{
elf_header_64_t* header = (elf_header_64_t*)elffile;
if (header->e_ident[EI_MAG0] != 0x7F || header->e_ident[EI_MAG1] != 0x45 || header->e_ident[EI_MAG2] != 0x4c || header->e_ident[EI_MAG3] != 0x46) {
return -1;
}
size_t vaddr = 0xffffffffffffffff;
for (size_t i = 0; i < header->e_phnum; i++) {
uintptr_t offset = header->e_phoff + i * header->e_phentsize;
elf_program_header_64_t* program_header = (elf_program_header_64_t*)((uintptr_t)elffile + offset);
if (program_header->p_type == PT_LOAD) {
vaddr = min(vaddr, program_header->p_vaddr);
}
}
uintptr_t paddr = (uintptr_t)palloc(size);
if (!paddr) {
return -1;
}
for (size_t i = 0; i < header->e_phnum; i++) {
uintptr_t offset = header->e_phoff + i * header->e_phentsize;
elf_program_header_64_t* program_header = (elf_program_header_64_t*)((uintptr_t)elffile + offset);
if (program_header->p_type == PT_LOAD) {
uintptr_t data_paddr = (program_header->p_vaddr - vaddr) + paddr;
uintptr_t data_offset = (uintptr_t)elffile + program_header->p_offset;
#ifdef DEBUG_ELF
log("copying elf %lx %lx %lx", data_paddr, data_offset, program_header->p_filesz);
#endif
memcpy((void*)data_paddr, (void*)data_offset, program_header->p_filesz);
}
}
*kernel_vaddr = vaddr;
*kernel_paddr = paddr;
return 0;
}
#endif

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

@@ -0,0 +1,196 @@
#ifndef _BOOT_LIBBOOT_ELF_ELF_LITE
#define _BOOT_LIBBOOT_ELF_ELF_LITE
#include <libboot/abi/drivers.h>
#include <libboot/fs/ext2_lite.h>
#include <libboot/types.h>
enum E_IDENT_FIELDS {
EI_MAG0,
EI_MAG1,
EI_MAG2,
EI_MAG3,
EI_CLASS,
EI_DATA,
EI_VERSION,
EI_OSABI,
EI_ABIVERSION,
};
enum E_TYPE_FIELDS {
ET_NONE,
ET_REL,
ET_EXEC,
ET_DYN,
ET_CORE,
};
enum E_MACHINE_FIELDS {
EM_NONE,
EM_386 = 3,
EM_PPC = 20,
EM_PPC64 = 21,
EM_X86_64 = 62,
};
typedef struct {
uint8_t e_ident[16];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
uint32_t e_entry;
uint32_t e_phoff;
uint32_t e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
} elf_header_32_t;
typedef struct {
uint8_t e_ident[16];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
uint64_t e_entry;
uint64_t e_phoff;
uint64_t e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
} elf_header_64_t;
enum P_TYPE_FIELDS {
PT_NULL,
PT_LOAD,
PT_DYNAMIC,
PT_INTERP,
PT_NOTE,
PT_SHLIB,
PT_PHDR,
PT_TLS,
PT_LOOS = 0x60000000,
PT_HIOS = 0x6FFFFFFF,
PT_LOPROC = 0x70000000,
PT_HIPROC = 0x7FFFFFFF,
};
typedef struct {
uint32_t p_type;
uint32_t p_offset;
uint32_t p_vaddr;
uint32_t p_paddr;
uint32_t p_filesz;
uint16_t p_memsz;
uint16_t p_flags;
uint16_t p_align;
} elf_program_header_32_t;
typedef struct {
uint32_t p_type;
uint32_t p_flags;
uint64_t p_offset;
uint64_t p_vaddr;
uint64_t p_paddr;
uint64_t p_filesz;
uint64_t p_memsz;
uint64_t p_align;
} elf_program_header_64_t;
enum SH_TYPE_FIELDS {
SHT_NULL,
SHT_PROGBITS,
SHT_SYMTAB,
SHT_STRTAB,
SHT_RELA,
SHT_HASH,
SHT_DYNAMIC,
SHT_NOTE,
SHT_NOBITS,
SHT_REL,
SHT_SHLIB,
SHT_DYNSYM,
SHT_INIT_ARRAY,
SHT_FINI_ARRAY,
SHT_PREINIT_ARRAY,
SHT_GROUP,
SHT_SYMTAB_SHNDX,
SHT_LOOS = 1610612736,
SHT_HIOS = 1879048191,
SHT_LOPROC = 1879048192,
SHT_HIPROC = 2147483647,
SHT_LOUSER = 2147483648,
SHT_HIUSER = 4294967295,
};
enum SH_FLAGS_FIELDS {
SHF_WRITE = 0x1,
SHF_ALLOC = 0x2,
SHF_EXECINSTR = 0x4,
SHF_MERGE = 0x10,
SHF_STRINGS = 0x20,
SHF_INFO_LINK = 0x40,
SHF_LINK_ORDER = 0x80,
SHF_OS_NONCONFORMING = 0x100,
SHF_GROUP = 0x200,
SHF_TLS = 0x400,
SHF_COMPRESSED = 0x800,
SHF_MASKOS = 0x0ff00000,
SHF_MASKPROC = 0xf0000000
};
typedef struct {
uint32_t sh_name;
uint32_t sh_type;
uint32_t sh_flags;
uint32_t sh_addr;
uint32_t sh_offset;
uint32_t sh_size;
uint32_t sh_link;
uint32_t sh_info;
uint32_t sh_addralign;
uint32_t sh_entsize;
} elf_section_header_32_t;
typedef struct {
uint32_t sh_name;
uint32_t sh_type;
uint64_t sh_flags;
uint64_t sh_addr;
uint64_t sh_offset;
uint64_t sh_size;
uint32_t sh_link;
uint32_t sh_info;
uint64_t sh_addralign;
uint64_t sh_entsize;
} elf_section_header_64_t;
struct elfctx {
drive_desc_t* drive_desc;
fs_desc_t* fs_desc;
inode_t file_inode;
elf_header_32_t header;
};
typedef struct elfctx elfctx_t;
int elf_init_ctx(drive_desc_t* drive_desc, fs_desc_t* fs_desc, const char* path, elfctx_t* elfctx);
int elf_read_program_header(elfctx_t* elfctx, size_t id, elf_program_header_32_t* program_header);
int elf_read_section_header(elfctx_t* elfctx, uint32_t id, elf_section_header_32_t* section_header);
#ifdef BITS32
int elf_load_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc, const char* path, size_t* kernel_vaddr, size_t* kernel_paddr, size_t* kernel_size);
#else
size_t elf_get_kernel_size(void* elffile);
int elf_load_kernel(void* elffile, size_t size, uintptr_t* kernel_vaddr, uintptr_t* kernel_paddr);
#endif
#endif // _BOOT_LIBBOOT_ELF_ELF_LITE

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

@@ -0,0 +1,233 @@
#include <libboot/fs/ext2_lite.h>
#include <libboot/mem/mem.h>
#include <libboot/types.h>
superblock_t superblock;
drive_desc_t* active_drive_desc;
uint32_t _ext2_lite_get_block_len()
{
return (1 << (superblock.log_block_size + 10));
}
uint32_t _ext2_lite_get_offset_of_block(uint32_t block_index)
{
return SUPERBLOCK_START + (block_index - 1) * _ext2_lite_get_block_len();
}
static uint8_t tmp_read_buf[8192];
void _ext2_lite_read(uint8_t* buf, uint32_t start, uint32_t len)
{
void (*read)(uint32_t sector, uint8_t* read_to) = active_drive_desc->read;
int already_read = 0;
while (len != 0) {
uint32_t sector = start / 512;
uint32_t start_offset = start % 512;
read(sector, tmp_read_buf);
for (int i = 0; i < min(512 - start_offset, len); i++) {
buf[already_read++] = tmp_read_buf[start_offset + i];
}
len -= min(512 - start_offset, len);
start += min(512 - start_offset, len);
}
}
void _ext2_lite_read_group(uint32_t group_id, group_desc_t* group)
{
uint32_t group_start = SUPERBLOCK_START + _ext2_lite_get_block_len() + (group_id * GROUP_LEN);
_ext2_lite_read((uint8_t*)group, group_start, GROUP_LEN);
}
void _ext2_lite_read_inode(uint32_t inode_id, inode_t* inode)
{
uint32_t inodes_per_group = superblock.inodes_per_group;
uint32_t holder_group = (inode_id - 1) / inodes_per_group;
uint32_t pos_inside_group = (inode_id - 1) % inodes_per_group;
group_desc_t gr;
_ext2_lite_read_group(holder_group, &gr);
uint32_t inode_start = SUPERBLOCK_START + ((gr.inode_table - 1) * _ext2_lite_get_block_len()) + (pos_inside_group * INODE_LEN);
_ext2_lite_read((uint8_t*)inode, inode_start, INODE_LEN);
}
int ext2_lite_init(drive_desc_t* drive_desc, fs_desc_t* fs_desc)
{
active_drive_desc = drive_desc;
void (*read)(uint32_t sector, uint8_t* read_to) = drive_desc->read;
_ext2_lite_read((uint8_t*)&superblock, SUPERBLOCK_START, SUPERBLOCK_LEN);
if (superblock.magic != 0xEF53) {
return -1;
}
if (superblock.rev_level != 0) {
return -1;
}
// TODO currently support up to 8192 bytes a block.
if (superblock.log_block_size > 3) {
return -1;
}
fs_desc->get_inode = (void*)ext2_lite_get_inode;
fs_desc->read = ext2_lite_read;
fs_desc->read_from_inode = (void*)ext2_lite_read_inode;
return 0;
}
static uint8_t tmp_dir_buf[8192];
int ext2_lite_has_in_dir(uint32_t block_index, const char* path, uint32_t* found_inode_index)
{
if (block_index == 0) {
return -1;
}
if (_ext2_lite_get_block_len() != 1024) {
while (1) { }
return -1;
}
_ext2_lite_read(tmp_dir_buf, _ext2_lite_get_offset_of_block(block_index), _ext2_lite_get_block_len());
dir_entry_t* start_of_entry = (dir_entry_t*)tmp_dir_buf;
for (;;) {
if (start_of_entry->inode == 0) {
return -1;
}
// checking name of this entry
bool is_name_correct = true;
for (int i = 0; i < start_of_entry->name_len; i++) {
is_name_correct &= (path[i] == *((char*)start_of_entry + 8 + i));
}
is_name_correct &= (path[start_of_entry->name_len] == '\0' || path[start_of_entry->name_len] == '/');
if (is_name_correct) {
*found_inode_index = start_of_entry->inode;
return 0;
}
start_of_entry = (dir_entry_t*)((uint32_t)start_of_entry + start_of_entry->rec_len);
if ((uint32_t)start_of_entry >= (uint32_t)tmp_dir_buf + _ext2_lite_get_block_len()) {
return -1;
}
}
return -2;
}
int ext2_lite_scan_dir(inode_t inode, const char* path, inode_t* res_inode)
{
uint32_t nxt_inode_index;
uint32_t path_offset = 0;
new_inode:
for (int i = 0; i < 12; i++) {
if (inode.block[i] != 0) {
if (ext2_lite_has_in_dir(inode.block[i], &path[path_offset], &nxt_inode_index) == 0) {
while (path[path_offset] != '\0' && path[path_offset] != '/')
path_offset++;
for (; path[path_offset] != '/'; path_offset++) {
if (path[path_offset] == '\0') {
_ext2_lite_read_inode(nxt_inode_index, res_inode);
return 0;
}
}
path_offset++;
_ext2_lite_read_inode(nxt_inode_index, &inode);
goto new_inode;
}
}
}
return -1;
}
int ext2_lite_get_inode(drive_desc_t* drive_desc, const char* path, inode_t* file_inode)
{
active_drive_desc = drive_desc;
inode_t root_inode;
_ext2_lite_read_inode(2, &root_inode);
int res = -1;
if (path[0] == '/') {
res = ext2_lite_scan_dir(root_inode, &path[1], file_inode);
} else {
res = ext2_lite_scan_dir(root_inode, path, file_inode);
}
return res;
}
static uint8_t tmp_block_buf[8192];
uint32_t _ext2_lite_get_block_of_file_lev0(uint32_t cur_block, uint32_t file_block_index)
{
_ext2_lite_read(tmp_block_buf, _ext2_lite_get_offset_of_block(cur_block), _ext2_lite_get_block_len());
uint32_t* buf = (uint32_t*)tmp_block_buf;
return buf[file_block_index];
}
uint32_t _ext2_lite_get_block_of_file_lev1(uint32_t cur_block, uint32_t file_block_index)
{
_ext2_lite_read(tmp_block_buf, _ext2_lite_get_offset_of_block(cur_block), _ext2_lite_get_block_len());
uint32_t* buf = (uint32_t*)tmp_block_buf;
uint32_t lev_contain = _ext2_lite_get_block_len() / 4;
uint32_t offset = file_block_index / lev_contain;
uint32_t offset_inner = file_block_index % lev_contain;
return _ext2_lite_get_block_of_file_lev0(buf[offset], offset_inner);
}
uint32_t _ext2_lite_get_block_of_file_lev2(uint32_t cur_block, uint32_t file_block_index)
{
_ext2_lite_read(tmp_block_buf, _ext2_lite_get_offset_of_block(cur_block), _ext2_lite_get_block_len());
uint32_t* buf = (uint32_t*)tmp_block_buf;
uint32_t block_len = _ext2_lite_get_block_len() / 4;
uint32_t lev_contain = block_len * block_len;
uint32_t offset = file_block_index / lev_contain;
uint32_t offset_inner = file_block_index % lev_contain;
return _ext2_lite_get_block_of_file_lev1(buf[offset], offset_inner);
}
// TODO think of more effecient version
uint32_t _ext2_lite_get_block_of_file(inode_t* inode, uint32_t file_block_index)
{
uint32_t block_len = _ext2_lite_get_block_len() / 4;
if (file_block_index < 12) {
return inode->block[file_block_index];
} else if (file_block_index < 12 + block_len) { // single indirect
return _ext2_lite_get_block_of_file_lev0(inode->block[12], file_block_index - 12);
} else if (file_block_index < 12 + block_len + block_len * block_len) { // double indirect
return _ext2_lite_get_block_of_file_lev1(inode->block[13], file_block_index - 12 - block_len);
} else { // triple indirect
return _ext2_lite_get_block_of_file_lev2(inode->block[14], file_block_index - (12 + block_len + block_len * block_len));
}
}
// Note to save mem: the func reuses tmp_block_buf.
int ext2_lite_read_inode(drive_desc_t* drive_desc, inode_t* inode, uint8_t* buf, uint32_t from, uint32_t len)
{
active_drive_desc = drive_desc;
const uint32_t block_len = _ext2_lite_get_block_len();
uint32_t start_block_index = from / block_len;
uint32_t end_block_index = (from + len - 1) / block_len;
uint32_t read_offset = from % block_len;
uint32_t write_offset = 0;
for (uint32_t block_index = start_block_index; block_index <= end_block_index; block_index++) {
uint32_t data_block_index = _ext2_lite_get_block_of_file(inode, block_index);
_ext2_lite_read(tmp_block_buf, _ext2_lite_get_offset_of_block(data_block_index), _ext2_lite_get_block_len());
for (int i = 0; i < min(len, block_len - read_offset); i++) {
buf[write_offset++] = tmp_block_buf[read_offset + i];
}
len -= min(len, block_len - read_offset);
read_offset = 0;
}
return write_offset;
}
int ext2_lite_read(drive_desc_t* drive_desc, const char* path, uint8_t* buf, uint32_t from, uint32_t len)
{
active_drive_desc = drive_desc;
inode_t inode;
ext2_lite_get_inode(drive_desc, path, &inode);
return ext2_lite_read_inode(drive_desc, &inode, buf, from, len);
}

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

@@ -0,0 +1,124 @@
#ifndef _BOOT_LIBBOOT_FS_EXT2_LITE
#define _BOOT_LIBBOOT_FS_EXT2_LITE
#include <libboot/abi/drivers.h>
#include <libboot/types.h>
#define SUPERBLOCK_START 1024
#define SUPERBLOCK_LEN (sizeof(superblock_t))
typedef struct {
uint32_t inodes_count;
uint32_t blocks_count;
uint32_t r_blocks_count;
uint32_t free_blocks_count;
uint32_t free_inodes_count;
uint32_t first_data_block;
uint32_t log_block_size;
uint32_t log_frag_size;
uint32_t blocks_per_group;
uint32_t frags_per_group;
uint32_t inodes_per_group;
uint32_t mtime;
uint32_t wtime;
uint16_t mnt_count;
uint16_t max_mnt_count;
uint16_t magic;
uint16_t state;
uint16_t errors;
uint16_t minor_rev_level;
uint32_t lastcheck;
uint32_t checkinterval;
uint32_t creator_os;
uint32_t rev_level;
uint16_t def_resuid;
uint16_t def_resgid;
uint32_t first_ino;
uint16_t inode_size;
uint16_t block_group_nr;
uint32_t feature_compat;
uint32_t feature_incompat;
uint32_t feature_ro_compat;
uint8_t uuid[16];
uint8_t volume_name[16];
uint8_t last_mounted[64];
uint32_t algo_bitmap;
uint8_t prealloc_blocks;
uint8_t prealloc_dir_blocks;
// current jurnalling is unsupported
uint8_t unused[1024 - 206];
} superblock_t;
#define GROUP_LEN (sizeof(group_desc_t))
typedef struct {
uint32_t block_bitmap;
uint32_t inode_bitmap;
uint32_t inode_table;
uint16_t free_blocks_count;
uint16_t free_inodes_count;
uint16_t used_dirs_count;
uint16_t pad;
uint8_t reserved[12];
} group_desc_t;
#define S_IFSOCK 0xC000
#define S_IFLNK 0xA000
#define S_IFREG 0x8000
#define S_IFBLK 0x6000
#define S_IFDIR 0x4000
#define S_IFCHR 0x2000
#define S_IFIFO 0x1000
#define S_ISUID 0x0800
#define S_ISGID 0x0400
#define S_ISVTX 0x0200
#define S_IRUSR 0x0100
#define S_IWUSR 0x0080
#define S_IXUSR 0x0040
#define S_IRGRP 0x0020
#define S_IWGRP 0x0010
#define S_IXGRP 0x0008
#define S_IROTH 0x0004
#define S_IWOTH 0x0002
#define S_IXOTH 0x0001
#define INODE_LEN (sizeof(inode_t))
#define INODES_RESERVED 11
typedef struct {
uint16_t mode;
uint16_t uid;
uint32_t size;
uint32_t atime;
uint32_t ctime;
uint32_t mtime;
uint32_t dtime;
uint16_t gid;
uint16_t links_count;
uint32_t blocks;
uint32_t flags;
uint32_t osd1;
uint32_t block[15];
uint32_t generation;
uint32_t file_acl;
uint32_t dir_acl;
uint32_t faddr;
uint32_t osd2[3];
} inode_t;
typedef struct {
uint32_t inode;
uint16_t rec_len;
uint8_t name_len;
uint8_t file_type;
char* name; // may be a problematic for 64bit versions
} dir_entry_t;
int ext2_lite_init(drive_desc_t* drive_desc, fs_desc_t* fs_desc);
int ext2_lite_get_inode(drive_desc_t* drive_desc, const char* path, inode_t* file_inode);
int ext2_lite_read(drive_desc_t* drive_desc, const char* path, uint8_t* buf, uint32_t from, uint32_t len);
int ext2_lite_read_inode(drive_desc_t* drive_desc, inode_t* inode, uint8_t* buf, uint32_t from, uint32_t len);
#endif // _BOOT_LIBBOOT_FS_EXT2_LITE

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

@@ -0,0 +1,377 @@
#include <libboot/log/log.h>
#include <libboot/mem/mem.h>
typedef int (*_putch_callback)(char ch, char* buf_base, size_t* written, void* callback_params);
static uart_put_char_t uart_handler = NULL;
static const char HEX_alphabet[] = "0123456789ABCDEF";
static const char hex_alphabet[] = "0123456789abcdef";
static int putch_callback_stream(char c, char* buf_base, size_t* written, void* callback_params)
{
if (uart_handler) {
return uart_handler(c);
}
return 0;
}
static int _printf_hex32_impl(unsigned int value, const char* alph, char* base_buf, size_t* written, _putch_callback callback, void* callback_params)
{
int nxt = 0;
char tmp_buf[16];
while (value > 0) {
tmp_buf[nxt++] = alph[(value % 16)];
value /= 16;
}
callback('0', base_buf, written, callback_params);
callback('x', base_buf, written, callback_params);
if (nxt == 0) {
callback('0', base_buf, written, callback_params);
}
while (nxt) {
callback(tmp_buf[--nxt], base_buf, written, callback_params);
}
return 0;
}
static int _printf_hex64_impl(unsigned long value, const char* alph, char* base_buf, size_t* written, _putch_callback callback, void* callback_params)
{
int nxt = 0;
char tmp_buf[32];
while (value > 0) {
tmp_buf[nxt++] = alph[(value % 16)];
value /= 16;
}
callback('0', base_buf, written, callback_params);
callback('x', base_buf, written, callback_params);
if (nxt == 0) {
callback('0', base_buf, written, callback_params);
}
while (nxt) {
callback(tmp_buf[--nxt], base_buf, written, callback_params);
}
return 0;
}
static int _printf_hex32(unsigned int value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params)
{
return _printf_hex32_impl(value, hex_alphabet, base_buf, written, callback, callback_params);
}
static int _printf_HEX32(unsigned int value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params)
{
return _printf_hex32_impl(value, HEX_alphabet, base_buf, written, callback, callback_params);
}
static int _printf_hex64(unsigned long value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params)
{
return _printf_hex64_impl(value, hex_alphabet, base_buf, written, callback, callback_params);
}
static int _printf_HEX64(unsigned long value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params)
{
return _printf_hex64_impl(value, HEX_alphabet, base_buf, written, callback, callback_params);
}
static int _printf_u32(unsigned int value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params)
{
int nxt = 0;
char tmp_buf[16];
while (value > 0) {
tmp_buf[nxt++] = (value % 10) + '0';
value /= 10;
}
if (nxt == 0) {
callback('0', base_buf, written, callback_params);
}
while (nxt) {
callback(tmp_buf[--nxt], base_buf, written, callback_params);
}
return 0;
}
static int _printf_u64(unsigned long value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params)
{
int nxt = 0;
char tmp_buf[32];
while (value > 0) {
tmp_buf[nxt++] = (value % 10) + '0';
value /= 10;
}
if (nxt == 0) {
callback('0', base_buf, written, callback_params);
}
while (nxt) {
callback(tmp_buf[--nxt], base_buf, written, callback_params);
}
return 0;
}
static int _printf_i32(int value, char* buf, size_t* written, _putch_callback callback, void* callback_params)
{
if (value < 0) {
callback('-', buf, written, callback_params);
value = -value;
}
return _printf_u32(value, buf, written, callback, callback_params);
}
static int _printf_i64(long value, char* buf, size_t* written, _putch_callback callback, void* callback_params)
{
if (value < 0) {
callback('-', buf, written, callback_params);
value = -value;
}
return _printf_u64(value, buf, written, callback, callback_params);
}
static int _printf_string(const char* value, char* buf, size_t* written, _putch_callback callback, void* callback_params)
{
if (!value) {
return 0;
}
size_t len = strlen(value);
for (size_t i = 0; i < len; i++) {
callback(value[i], buf, written, callback_params);
}
return 0;
}
static ssize_t _printf_internal(char* buf, const char* format, _putch_callback callback, void* callback_params, va_list arg)
{
const char* p = format;
size_t written = 0;
while (*p) {
int l_arg = 0;
int h_arg = 0;
if (*p == '%' && *(p + 1)) {
// Reading arguments
parse_args:
p++;
switch (*p) {
case 'l':
l_arg++;
if (*(p + 1)) {
goto parse_args;
}
break;
case 'h':
h_arg++;
if (*(p + 1)) {
goto parse_args;
}
break;
default:
break;
}
// Reading conversion specifiers
switch (*p) {
case 'i':
case 'd':
if (l_arg) {
long value = va_arg(arg, long);
_printf_i64(value, buf, &written, callback, callback_params);
} else {
int value = va_arg(arg, int);
_printf_i32(value, buf, &written, callback, callback_params);
}
break;
case 'u':
if (l_arg) {
uint64_t value = va_arg(arg, uint64_t);
_printf_u64(value, buf, &written, callback, callback_params);
} else {
uint32_t value = va_arg(arg, uint32_t);
_printf_u32(value, buf, &written, callback, callback_params);
}
break;
case 'x':
if (l_arg) {
uint64_t value = va_arg(arg, uint64_t);
_printf_hex64(value, buf, &written, callback, callback_params);
} else {
uint32_t value = va_arg(arg, uint32_t);
_printf_hex32(value, buf, &written, callback, callback_params);
}
break;
case 'X':
if (l_arg) {
uint64_t value = va_arg(arg, uint64_t);
_printf_HEX64(value, buf, &written, callback, callback_params);
} else {
uint32_t value = va_arg(arg, uint32_t);
_printf_HEX32(value, buf, &written, callback, callback_params);
}
break;
case 'c': {
char value = (char)va_arg(arg, int);
callback(value, buf, &written, callback_params);
} break;
case '%': {
callback('%', buf, &written, callback_params);
} break;
case 's': {
const char* value = va_arg(arg, const char*);
_printf_string(value, buf, &written, callback, callback_params);
} break;
default:
break;
}
} else {
callback(*p, buf, &written, callback_params);
}
p++;
}
return written;
}
static int putch_callback_sized_buf(char ch, char* buf_base, size_t* written, void* callback_params)
{
if (!callback_params) {
return -1;
}
if (!written) {
return -1;
}
size_t n = *(size_t*)callback_params;
size_t vw = *written;
if (vw >= n) {
return -1;
}
buf_base[vw++] = ch;
*written = vw;
return 0;
}
int vsnprintf(char* s, size_t n, const char* format, va_list arg)
{
if (!s) {
return 0;
}
if (!n) {
return 0;
}
ssize_t wr = _printf_internal(s, format, putch_callback_sized_buf, &n, arg);
if (wr == n) {
s[n - 1] = '\0';
} else {
s[wr] = '\0';
}
return (int)wr;
}
int snprintf(char* s, size_t n, const char* format, ...)
{
va_list arg;
va_start(arg, format);
int res = vsnprintf(s, n, format, arg);
va_end(arg);
return res;
}
static int putch_callback_buf(char ch, char* buf_base, size_t* written, void* callback_params)
{
if (!written) {
return -1;
}
size_t vw = *written;
buf_base[vw++] = ch;
*written = vw;
return 0;
}
int vsprintf(char* s, const char* format, va_list arg)
{
if (!s) {
return 0;
}
ssize_t wr = _printf_internal(s, format, putch_callback_buf, NULL, arg);
s[wr] = '\0';
return (int)wr;
}
int sprintf(char* s, const char* format, ...)
{
va_list arg;
va_start(arg, format);
int res = vsprintf(s, format, arg);
va_end(arg);
return res;
}
static int vlog_unfmt(const char* format, va_list arg)
{
return _printf_internal(NULL, format, putch_callback_stream, NULL, arg);
}
static int vlog_fmt(const char* init_msg, const char* format, va_list arg)
{
vlog_unfmt(init_msg, arg);
vlog_unfmt(format, arg);
size_t formatlen = strlen(format);
if (format[formatlen - 1] != '\n') {
vlog_unfmt("\n", arg);
}
return 0;
}
int log(const char* format, ...)
{
va_list arg;
va_start(arg, format);
int ret = vlog_fmt("\033[1;37m[BOOT LOG]\033[0m ", format, arg);
va_end(arg);
return ret;
}
int log_warn(const char* format, ...)
{
va_list arg;
va_start(arg, format);
int ret = vlog_fmt("\033[1;33m[BOOT WARN]\033[0m ", format, arg);
va_end(arg);
return ret;
}
int log_error(const char* format, ...)
{
va_list arg;
va_start(arg, format);
int ret = vlog_fmt("\033[1;31m[BOOT ERR]\033[0m ", format, arg);
va_end(arg);
return ret;
}
int log_not_formatted(const char* format, ...)
{
va_list arg;
va_start(arg, format);
int ret = vlog_unfmt(format, arg);
va_end(arg);
return ret;
}
void log_init(uart_put_char_t ur)
{
uart_handler = ur;
}

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

@@ -0,0 +1,20 @@
#ifndef _BOOT_LIBBOOT_LOG_LOG_H
#define _BOOT_LIBBOOT_LOG_LOG_H
#include <libboot/types.h>
typedef int (*uart_put_char_t)(uint8_t ch);
void log_init(uart_put_char_t ur);
int vsnprintf(char* s, size_t n, const char* format, va_list arg);
int vsprintf(char* s, const char* format, va_list arg);
int snprintf(char* s, size_t n, const char* format, ...);
int sprintf(char* s, const char* format, ...);
int log(const char* format, ...);
int log_warn(const char* format, ...);
int log_error(const char* format, ...);
int log_not_formatted(const char* format, ...);
#endif // _BOOT_LIBBOOT_LOG_LOG_H

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

@@ -0,0 +1,96 @@
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
void* _malloc_next_addr = NULL;
void* _malloc_end_addr = NULL;
void* _palloc_start_addr = NULL;
void* _palloc_next_addr = NULL;
void* _palloc_end_addr = NULL;
int malloc_init(void* addr, size_t size)
{
_malloc_next_addr = addr;
_malloc_end_addr = _malloc_next_addr + size;
return 0;
}
// Current implementation is a simple linear allocator.
void* malloc(size_t size)
{
if (!_malloc_next_addr) {
return NULL;
}
if (_malloc_next_addr >= _malloc_end_addr) {
return NULL;
}
void* res = _malloc_next_addr;
size = ROUND_CEIL(size, 0x10);
_malloc_next_addr += size;
return res;
}
// Current implementation is a simple linear allocator.
void* malloc_aligned(size_t size, size_t alignment)
{
if ((size_t)_malloc_next_addr % alignment) {
malloc(alignment - ((size_t)_malloc_next_addr % alignment));
}
return malloc(size);
}
void free(void* ptr)
{
UNUSED(ptr);
}
// Preserve alloc
int palloc_init(size_t size, size_t alignment)
{
_palloc_start_addr = _palloc_next_addr = malloc_aligned(size, alignment);
if (!_palloc_next_addr) {
return -1;
}
_palloc_end_addr = (void*)((uintptr_t)_palloc_next_addr + size);
return 0;
}
void* palloc(size_t size)
{
if (!_palloc_next_addr) {
log("palloc not init");
while (1) { };
}
if (_palloc_next_addr >= _palloc_end_addr) {
log("palloc out of mem");
while (1) { };
}
void* res = _palloc_next_addr;
size = ROUND_CEIL(size, 0x10);
_palloc_next_addr += size;
return res;
}
void* palloc_aligned(size_t size, size_t alignment)
{
if ((size_t)_palloc_next_addr % alignment) {
palloc(alignment - ((size_t)_palloc_next_addr % alignment));
}
return palloc(size);
}
size_t palloc_total_size()
{
return (size_t)_palloc_end_addr - (size_t)_palloc_start_addr;
}
size_t palloc_used_size()
{
return (size_t)_palloc_next_addr - (size_t)_palloc_start_addr;
}

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

@@ -0,0 +1,17 @@
#ifndef _BOOT_LIBBOOT_MEM_MALLOC_H
#define _BOOT_LIBBOOT_MEM_MALLOC_H
#include <libboot/mem/mem.h>
int malloc_init(void* addr, size_t size);
void* malloc(size_t size);
void* malloc_aligned(size_t size, size_t alignment);
void free(void* ptr);
int palloc_init(size_t size, size_t alignment);
void* palloc(size_t size);
void* palloc_aligned(size_t size, size_t alignment);
size_t palloc_used_size();
size_t palloc_total_size();
#endif // _BOOT_LIBBOOT_MEM_MALLOC_H

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

@@ -0,0 +1,110 @@
#include <libboot/mem/mem.h>
int strcmp(const char* a, const char* b)
{
while (*a == *b && *a != 0 && *b != 0) {
a++;
b++;
}
if (*a < *b) {
return -1;
}
if (*a > *b) {
return 1;
}
return 0;
}
int strncmp(const char* a, const char* b, uint32_t num)
{
while (*a == *b && *a != 0 && *b != 0 && num) {
a++;
b++;
num--;
}
if (!num) {
return 0;
}
if (*a < *b) {
return -1;
}
if (*a > *b) {
return 1;
}
return 0;
}
size_t strlen(const char* s)
{
size_t i = 0;
while (s[i] != '\0')
++i;
return i;
}
size_t strnlen(const char* s, size_t maxlen)
{
size_t i = 0;
while (s[i] != '\0' && maxlen) {
i++;
maxlen--;
}
return i;
}
void* memset(void* dest, uint8_t fll, uint32_t nbytes)
{
for (int i = 0; i < nbytes; ++i) {
*((uint8_t*)dest + i) = fll;
}
return dest;
}
void* memcpy(void* dest, const void* src, uint32_t nbytes)
{
for (int i = 0; i < nbytes; ++i) {
*(char*)(dest + i) = *(char*)(src + i);
}
return dest;
}
void* memmove(void* dest, const void* src, uint32_t nbytes)
{
if (src > dest) {
for (int i = 0; i < nbytes; ++i) {
*((uint8_t*)dest + i) = *((uint8_t*)src + i);
}
} else {
for (int i = nbytes - 1; i >= 0; --i) {
*((uint8_t*)dest + i) = *((uint8_t*)src + i);
}
}
return dest;
}
void* memccpy(void* dest, const void* src, uint8_t stop, uint32_t nbytes)
{
for (int i = 0; i < nbytes; ++i) {
*((uint8_t*)dest + i) = *((uint8_t*)src + i);
if (*((uint8_t*)src + i) == stop) {
return ((uint8_t*)dest + i + 1);
}
}
return NULL;
}
int memcmp(const void* src1, const void* src2, uint32_t nbytes)
{
for (int i = 0; i < nbytes; ++i) {
if (*(uint8_t*)(src1 + i) < *((uint8_t*)src2 + i)) {
return -1;
}
if (*(uint8_t*)(src1 + i) > *(uint8_t*)(src2 + i)) {
return 1;
}
}
return 0;
}

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

@@ -0,0 +1,37 @@
#ifndef _BOOT_LIBBOOT_MEM_MEM_H
#define _BOOT_LIBBOOT_MEM_MEM_H
#include <libboot/types.h>
int strcmp(const char* a, const char* b);
int strncmp(const char* a, const char* b, uint32_t num);
size_t strlen(const char* s);
size_t strnlen(const char* s, size_t maxlen);
void* memset(void* dest, uint8_t fll, uint32_t nbytes);
void* memcpy(void* dest, const void* src, uint32_t nbytes);
void* memccpy(void* dest, const void* src, uint8_t stop, uint32_t nbytes);
void* memmove(void* dest, const void* src, uint32_t nbytes);
int memcmp(const void* src1, const void* src2, uint32_t nbytes);
static size_t align_size(size_t size, size_t align)
{
if (size % align) {
size += align - (size % align);
}
return size;
}
static inline void* copy_after_kernel(size_t kbase, void* from, size_t size, size_t* kernel_size, size_t align)
{
void* pp = (void*)(kbase + *kernel_size);
memcpy(pp, from, size);
*kernel_size += align_size(size, align);
return pp;
}
static inline void* paddr_to_vaddr(void* ptr, size_t pbase, size_t vbase)
{
return (void*)((size_t)ptr - pbase + vbase);
}
#endif // _BOOT_LIBBOOT_MEM_MEM_H

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

@@ -0,0 +1,89 @@
#ifndef _BOOT_LIBBOOT_TYPES_H
#define _BOOT_LIBBOOT_TYPES_H
typedef char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef long long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#ifdef __i386__
typedef int32_t intptr_t;
typedef uint32_t uintptr_t;
#if defined(__clang__)
typedef unsigned int size_t;
typedef int ssize_t;
#elif defined(__GNUC__) || defined(__GNUG__)
typedef unsigned long size_t;
typedef long ssize_t;
#endif
#define BITS32
#elif __x86_64__
typedef uint64_t size_t;
typedef int64_t ssize_t;
typedef int64_t intptr_t;
typedef uint64_t uintptr_t;
#define BITS64
#elif __arm__
typedef unsigned int size_t;
typedef int ssize_t;
typedef int32_t intptr_t;
typedef uint32_t uintptr_t;
#define BITS32
#elif __aarch64__
typedef uint64_t size_t;
typedef int64_t ssize_t;
typedef int64_t intptr_t;
typedef uint64_t uintptr_t;
#define BITS64
#elif defined(__riscv) && (__riscv_xlen == 64)
typedef uint64_t size_t;
typedef int64_t ssize_t;
typedef int64_t intptr_t;
typedef uint64_t uintptr_t;
#define BITS64
#endif
typedef _Bool bool;
typedef __builtin_va_list va_list;
#define va_start(v, l) __builtin_va_start(v, l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v, l) __builtin_va_arg(v, l)
#define true (1)
#define false (0)
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define NULL ((void*)0)
#define UNUSED(x) (void)(x)
#define ALIGNED(x) __attribute__((aligned(x)))
#define PACKED __attribute__((packed))
#ifndef max
#define max(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#endif /* max */
#ifndef min
#define min(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
#endif /* min */
#define ROUND_CEIL(a, b) (((a) + ((b)-1)) & ~((b)-1))
#define ROUND_FLOOR(a, b) ((a) & ~((b)-1))
#define TEST_FLAG(val, flag) (((val) & (flag)) == (flag))
#define TEST_BIT(val, bitnum) (((val) & (1 << bitnum)) == (1 << bitnum))
#endif // _BOOT_LIBBOOT_TYPES_H

View File

@@ -0,0 +1,24 @@
#include "uart.h"
volatile uint32_t* output = NULL;
#define UART 0x10000000
#define UART_THR (char*)(UART + 0x00) // THR:transmitter holding register
#define UART_LSR (char*)(UART + 0x05) // LSR:line status register
#define UART_LSR_EMPTY_MASK 0x40 // LSR Bit 6: Transmitter empty; both the THR and LSR are empty
void uart_init()
{
output = (uint32_t*)UART;
}
int uart_write(uint8_t data)
{
if (!output) {
return 1;
}
while ((*UART_LSR & UART_LSR_EMPTY_MASK) == 0) { }
*output = data;
return 0;
}

View File

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

View File

@@ -0,0 +1,100 @@
.extern main
.extern main_s_mode
.section ".xos_boot_text", "xa"
prekernel_header:
auipc a0, 0
la a1, PREKERNEL_STACK_TOP_OFFSET
mv sp, a1
j main
.global enable_mmu
enable_mmu:
fence rw, rw
csrw satp, a0
csrs sstatus, a1
sfence.vma
ret
.global jump_to_kernel
jump_to_kernel:
fence rw, rw
sfence.vma
jr a1
loop:
j loop
.align 4
timervec:
csrrw a0, mscratch, a0
sd a1, 0(a0)
sd a2, 8(a0)
sd a3, 16(a0)
ld a1, 24(a0)
ld a2, 32(a0)
ld a3, 0(a1)
add a3, a3, a2
sd a3, 0(a1)
li a1, 2
csrw sip, a1
ld a3, 16(a0)
ld a2, 8(a0)
ld a1, 0(a0)
csrrw a0, mscratch, a0
mret
.global setup_timer_m_mode
setup_timer_m_mode:
csrw mscratch, a0
la t0, timervec
csrw mtvec, t0
csrr t0, mstatus // Add flag MSTATUS_MIE | MSTATUS_SUM
li t1, (1 << 3) | (1 << 18)
or t0, t0, t1
csrw mstatus, t0
csrr t0, mie // Add flag MIE_MTIE
li t1, (1 << 7)
or t0, t0, t1
csrw mie, t0
ret
.global jump_to_s_mode
jump_to_s_mode:
csrr t0, mstatus
li t1, 3 << 11
and t0, t0, t1
li t1, 1 << 11
or t0, t0, t1
csrw mstatus, t0
la t1, sv_main
csrw mepc, t1
csrw satp, zero
li t1, 0xffff
csrw medeleg, t1
csrw mideleg, t1
li t1, (1 << 1) | (1 << 5) | (1 << 9)
csrr t0, sie
or t0, t0, t1
csrw sie, t0
li t1, 0x3fffffffffffff
csrw pmpaddr0, t1
li t1, 0xf
csrw pmpcfg0, t1
mret
sv_main:
j main_s_mode

View File

@@ -0,0 +1,185 @@
#include "drivers/uart.h"
#include "vm.h"
#include <libboot/abi/memory.h>
#include <libboot/devtree/devtree.h>
#include <libboot/elf/elf_lite.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
#define DEBUG_BOOT
#define EARLY_FB
extern uint32_t EMBED_DEVTREE_START[];
extern uint32_t EMBED_DEVTREE_END[];
extern void jump_to_s_mode(uintptr_t);
extern void jump_to_kernel(void*, uintptr_t);
static void* bootdesc_paddr;
static void* bootdesc_vaddr;
static size_t kernel_vaddr = 0;
static size_t kernel_paddr = 0;
static size_t kernel_size = 0;
#define LAUNCH_SERVER_PATH "/System/launch_server"
static int alloc_init()
{
devtree_entry_t* dev = devtree_find_device("ram");
if (!dev) {
log("Can't find RAM in devtree");
while (1) { };
}
extern uint32_t RAWIMAGE_END[];
uintptr_t start_addr = ROUND_CEIL((uint64_t)RAWIMAGE_END, page_size());
size_t free_space = dev->region_size - (start_addr - dev->region_base);
malloc_init((void*)start_addr, free_space);
#ifdef DEBUG_BOOT
log("malloc inited %llx %llx", start_addr, free_space);
#endif
return 0;
}
static size_t memory_layout_size()
{
return 0 + 1; // Including the trailing element.
}
static int preserve_alloc_init(size_t kernsize)
{
const size_t devtreesize = ROUND_CEIL(devtree_size(), page_size());
const size_t memmap = ROUND_CEIL(memory_layout_size() * sizeof(memory_layout_t), page_size());
const size_t bootargsstruct = ROUND_CEIL(sizeof(boot_args_t), page_size());
const size_t bootargssize = devtreesize + memmap + bootargsstruct;
// 32 tables should be enough for initial mappings.
const size_t prekernelvmsize = 32 * page_size();
const size_t total = ROUND_CEIL(kernsize + bootargssize + prekernelvmsize, page_size());
return palloc_init(total, 2 << 20);
}
static memory_boot_desc_t memory_boot_desc_init()
{
devtree_entry_t* dev = devtree_find_device("ram");
if (!dev) {
#ifdef EARLY_FB
log("Can't find RAM in devtree");
#endif
while (1) { };
}
memory_boot_desc_t res;
const size_t memlayout_size = memory_layout_size();
memory_layout_t* mem_layout_paddr = palloc_aligned(memlayout_size * sizeof(memory_layout_t), page_size());
// Init of trailing element.
mem_layout_paddr[memlayout_size - 1].flags = MEMORY_LAYOUT_FLAG_TERMINATE;
memory_layout_t* mem_layout_vaddr = paddr_to_vaddr(mem_layout_paddr, kernel_paddr, kernel_vaddr);
#if defined(DEBUG_BOOT) && defined(EARLY_FB)
log("initing MEMLAYOUT %lx of %d elems", mem_layout_vaddr, memlayout_size);
#endif
res.ram_base = dev->region_base;
res.ram_size = dev->region_size;
res.reserved_areas = mem_layout_vaddr;
return res;
}
static void load_kernel(void* kenrelstart)
{
kernel_size = elf_get_kernel_size(kenrelstart);
kernel_size = ROUND_CEIL(kernel_size, page_size());
int err = preserve_alloc_init(kernel_size);
if (err) {
#ifdef EARLY_FB
log("add assert");
#endif
while (1) { }
}
int res = elf_load_kernel(kenrelstart, kernel_size, &kernel_vaddr, &kernel_paddr);
#if defined(DEBUG_BOOT) && defined(EARLY_FB)
log("kernel %lx %lx %lx", kernel_vaddr, kernel_paddr, kernel_size);
#endif
void* odt_paddr = palloc_aligned(devtree_size(), page_size());
memcpy(odt_paddr, devtree_start(), devtree_size());
void* odt_vaddr = paddr_to_vaddr(odt_paddr, kernel_paddr, kernel_vaddr);
#if defined(DEBUG_BOOT) && defined(EARLY_FB)
log("copying ODT %lx -> %lx of %d", devtree_start(), odt_vaddr, devtree_size());
#endif
boot_args_t boot_args;
boot_args.vaddr = kernel_vaddr;
boot_args.paddr = kernel_paddr;
boot_args.kernel_data_size = 0x0; // Sets up later
boot_args.mem_boot_desc = memory_boot_desc_init();
boot_args.devtree = odt_vaddr;
boot_args.fb_boot_desc.vaddr = 0; // Marking fb as invalid.
memcpy(boot_args.init_process, LAUNCH_SERVER_PATH, sizeof(LAUNCH_SERVER_PATH));
bootdesc_paddr = palloc_aligned(sizeof(boot_args), page_size());
memcpy(bootdesc_paddr, &boot_args, sizeof(boot_args));
bootdesc_vaddr = paddr_to_vaddr(bootdesc_paddr, kernel_paddr, kernel_vaddr);
#if defined(DEBUG_BOOT) && defined(EARLY_FB)
log("copying BOOTDESC %lx -> %lx of %d", &boot_args, bootdesc_vaddr, sizeof(boot_args));
#endif
}
static int enable_timer()
{
devtree_entry_t* dev = devtree_find_device("rv64timer");
if (!dev) {
log("Can't find timer in devtree");
return 1;
}
struct timer_scratch_mem {
uint64_t entries[5];
};
struct timer_scratch_mem* scratch = palloc_aligned(sizeof(struct timer_scratch_mem), page_size());
size_t hartid = 0;
volatile uint64_t* mtime = (uint64_t*)(dev->region_base + 0xBFF8);
volatile uint64_t* mtimecmp = (uint64_t*)(dev->region_base + 0x4000 + 8 * hartid);
size_t interval = 10000000 / 125;
*mtimecmp = *mtime + interval;
scratch->entries[3] = (uint64_t)mtimecmp;
scratch->entries[4] = interval;
extern void setup_timer_m_mode(void*);
setup_timer_m_mode(scratch);
return 0;
}
void main(uintptr_t base)
{
devtree_init((void*)EMBED_DEVTREE_START, (uint64_t)EMBED_DEVTREE_END - (uint64_t)EMBED_DEVTREE_START);
uart_init();
log_init(uart_write);
alloc_init();
extern uint32_t EMBED_KERNEL_START[];
load_kernel((void*)(EMBED_KERNEL_START));
enable_timer();
jump_to_s_mode(base);
}
int main_s_mode(uintptr_t base)
{
vm_setup(base, bootdesc_paddr);
#ifdef DEBUG_BOOT
log("Preboot done: booting to OS@%llx", ((boot_args_t*)bootdesc_vaddr)->vaddr);
#endif
((boot_args_t*)bootdesc_vaddr)->kernel_data_size = ROUND_CEIL(palloc_used_size(), page_size());
jump_to_kernel((void*)bootdesc_vaddr, ((boot_args_t*)bootdesc_vaddr)->vaddr);
return 0;
}

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

@@ -0,0 +1,141 @@
#include "vm.h"
#include <libboot/abi/kernel.h>
#include <libboot/abi/rawimage.h>
#include <libboot/devtree/devtree.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
#define DEBUG_VM
static uint64_t* global_page_table;
static const uint64_t kernel_base = 0xffff800000000000;
static uint64_t* new_ptable(boot_args_t* args)
{
uint64_t* res = (uint64_t*)palloc_aligned(page_size(), page_size());
memset(res, 0, page_size());
#ifdef DEBUG_VM
log(" alloc ptable %llx %llx", (uint64_t)res, page_size());
#endif
return res;
}
static void map4kb_2mb(boot_args_t* args, size_t phyz, size_t virt)
{
const size_t page_covers = (1ull << PTABLE_LV1_VADDR_OFFSET);
const size_t page_mask = page_covers - 1;
if ((phyz & page_mask) != 0 || (virt & page_mask) != 0) {
return;
}
// Mapping from level3.
uint64_t* page_table = global_page_table;
uint64_t ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)];
if (ptable_desc == 0) {
uint64_t* nptbl = new_ptable(args);
uint64_t pdesc = 0x00000000000001; // v bit is set
pdesc |= ((uintptr_t)nptbl >> 2);
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)] = pdesc;
ptable_desc = pdesc;
}
// Level2
page_table = (uint64_t*)(((ptable_desc >> 10) << 12) & 0xffffffffffff);
ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)];
if (ptable_desc == 0) {
uint64_t* nptbl = new_ptable(args);
uint64_t pdesc = 0x00000000000001; // v bit is set
pdesc |= ((uintptr_t)nptbl >> 2);
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)] = pdesc;
ptable_desc = pdesc;
}
page_table = (uint64_t*)(((ptable_desc >> 10) << 12) & 0xffffffffffff);
uint64_t pdesc = 0x0000000000000f; // w + v + x + r bits are set.
pdesc |= ((uintptr_t)phyz >> 2);
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV1_VADDR_OFFSET, VMM_LV1_ENTITY_COUNT)] = pdesc;
}
static void map4kb_1gb(boot_args_t* args, size_t phyz, size_t virt)
{
const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET);
const size_t page_mask = page_covers - 1;
if ((phyz & page_mask) != 0 || (virt & page_mask) != 0) {
return;
}
// Mapping from level3.
uint64_t* page_table = global_page_table;
uint64_t ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)];
if (ptable_desc == 0) {
uint64_t* nptbl = new_ptable(args);
uint64_t pdesc = 0x00000000000001; // v bit is set
pdesc |= ((uintptr_t)nptbl >> 2);
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)] = pdesc;
ptable_desc = pdesc;
}
page_table = (uint64_t*)(((ptable_desc >> 10) << 12) & 0xffffffffffff);
uint64_t pdesc = 0x0000000000000f; // w + v + x + r bits are set.
pdesc |= ((uintptr_t)phyz >> 2);
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)] = pdesc;
}
static void map_uart(boot_args_t* args)
{
devtree_entry_t* dev = devtree_find_device("uart");
if (!dev) {
return;
}
uint64_t paddr = dev->region_base;
const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET);
paddr &= ~(page_covers - 1);
#ifdef DEBUG_VM
log("mapping %lx %lx", paddr, paddr);
#endif
map4kb_1gb(args, paddr, paddr);
}
void vm_setup(uintptr_t base, boot_args_t* args)
{
global_page_table = (uint64_t*)palloc_aligned(page_size(), page_size());
memset(global_page_table, 0, page_size());
const size_t map_range_2mb = (2 << 20);
const size_t map_range_1gb = (1 << 30);
// Mapping kernel vaddr to paddr
size_t kernel_size_to_map = palloc_total_size() + shadow_area_size();
size_t kernel_range_count_to_map = (kernel_size_to_map + (map_range_2mb - 1)) / map_range_2mb;
for (size_t i = 0; i < kernel_range_count_to_map; i++) {
#ifdef DEBUG_VM
log("mapping %lx %lx", args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb);
#endif
map4kb_2mb(args, args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb);
}
// Mapping RAM
size_t ram_base = ROUND_FLOOR(args->mem_boot_desc.ram_base, map_range_1gb);
size_t ram_size = args->mem_boot_desc.ram_size;
size_t ram_range_count_to_map = (ram_size + (map_range_1gb - 1)) / map_range_1gb;
for (size_t i = 0; i < ram_range_count_to_map; i++) {
#ifdef DEBUG_VM
log("mapping %lx %lx", ram_base + i * map_range_1gb, ram_base + i * map_range_1gb);
#endif
map4kb_1gb(args, ram_base + i * map_range_1gb, ram_base + i * map_range_1gb);
}
map_uart(args);
#ifdef DEBUG_VM
log("Complete tables setup");
#endif
extern void enable_mmu(uintptr_t, uintptr_t);
enable_mmu((uintptr_t)(9ull << 60) | (((uintptr_t)global_page_table >> 12) & 0xffffffffff), (1 << 18));
}

View File

@@ -0,0 +1,24 @@
#ifndef _BOOT_VM_H
#define _BOOT_VM_H
#include <libboot/abi/memory.h>
#include <libboot/types.h>
#define VMM_LV0_ENTITY_COUNT (512)
#define VMM_LV1_ENTITY_COUNT (512)
#define VMM_LV2_ENTITY_COUNT (512)
#define VMM_LV3_ENTITY_COUNT (512)
#define PTABLE_LV_TOP (3)
#define PTABLE_LV0_VADDR_OFFSET (12)
#define PTABLE_LV1_VADDR_OFFSET (21)
#define PTABLE_LV2_VADDR_OFFSET (30)
#define PTABLE_LV3_VADDR_OFFSET (39)
#define VM_VADDR_OFFSET_AT_LEVEL(vaddr, off, ent) ((vaddr >> off) % ent)
static size_t page_size() { return 0x1000; }
void vm_setup(uintptr_t base, boot_args_t* args);
#endif // _BOOT_VM_H

67
boot/x86/stage1/boot.s Normal file
View File

@@ -0,0 +1,67 @@
[org 0x7c00]
KERNEL_OFFSET equ 0x1000
KERNEL_SIZE equ 32 ; (KBytes) 32KB
MEMORY_MAP_REGION equ 0xA00
mov [BOOT_DISK], dl ; saving boot disk
mov bp, 0x8000 ; stack init in 16bits
mov sp, bp
mov bx, MSG_REAL_MODE
call print_string
mov eax, 0
mov es, ax
mov di, MEMORY_MAP_REGION
call bios_get_memory_map
call load_kernel
call switch_to_pm
jmp $
%include "boot/x86/stage1/utils16/print.s"
%include "boot/x86/stage1/utils16/smm.s"
%include "boot/x86/stage1/utils16/disk_load.s"
%include "boot/x86/stage1/utils16/switch_to_pm.s"
%include "boot/x86/stage1/utils32/print.s"
%include "boot/x86/stage1/utils32/gdt.s"
[bits 16]
load_kernel:
mov bx, MSG_KERNEL_LOAD
call print_string
mov bx, KERNEL_OFFSET
mov dh, 50
mov dl, [BOOT_DISK]
call disk_load
ret
[bits 32]
begin_pm:
mov ebx, MSG_PROT_MODE
call print_string_pm
mov eax, dword [memory_map_size]
push eax
mov eax, dword KERNEL_SIZE
push eax
push esp
call KERNEL_OFFSET
jmp $
MSG_REAL_MODE:
db 'Starting real mode', 0
MSG_PROT_MODE:
db 'Switched to prot mode', 0
MSG_KERNEL_LOAD:
db ' Loading kernel from drive', 0
BOOT_DISK: db 0
times (510-($-$$)) db 0
db 0x55
db 0xaa

View File

@@ -0,0 +1,23 @@
[bits 16]
disk_load:
push dx
mov ah, 0x02
mov al, dh
mov ch, 0x00
mov dh, 0x00
mov cl, 0x02
int 0x13
jc disk_error
pop dx
cmp al, dh
jne disk_error
ret
disk_error:
mov bx, MSG_DISK_ERROR
call print_string
jmp $
MSG_DISK_ERROR: db 'disk ERROR!', 0

View File

@@ -0,0 +1,15 @@
[bits 16]
print_string:
pusha
mov ah, 0x0e
print_string_cycle:
cmp [bx], BYTE 0
je print_string_end
mov al, [bx]
int 0x10
add bx, 1
jmp print_string_cycle
print_string_end:
popa
ret

View File

@@ -0,0 +1,55 @@
[bits 16]
memory_map_entry:
base_address:
dq 0x0
length:
dq 0x0
type:
dq 0x0
acpi_null:
dq 0x0
memory_map_entry_end:
memory_map_size: dw 0
bios_get_memory_map:
pushad
xor ebx, ebx
xor bp, bp
mov edx, 'PAMS'
mov eax, 0xe820
mov ecx, 24
int 0x15
jc memory_map_error
cmp eax, 'PAMS'
jne memory_map_error
test ebx, ebx
je memory_map_error
jmp memory_map_start
memory_map_next:
mov edx, 'PAMS'
mov ecx, 24
mov eax, 0xe820
int 0x15
memory_map_start:
jcxz memory_map_skip_entry
memory_map_common:
mov ecx, [es:di + 8]
test ecx, ecx
jne memory_map_good_entry
mov ecx, [es:di + 12]
jecxz memory_map_skip_entry
memory_map_good_entry:
inc bp
add di, 24
memory_map_skip_entry:
cmp ebx, 0
jne memory_map_next
jmp memory_map_done
memory_map_error:
stc
memory_map_done:
mov [memory_map_size], bp
popad
ret

View File

@@ -0,0 +1,22 @@
[bits 16]
switch_to_pm:
cli ; turn off interupts
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 0x1
mov cr0, eax
call CODE_SEG:init_pm
[bits 32]
init_pm:
mov ax, DATA_SEG
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000 ; stack's init
mov esp, ebp
call begin_pm

View File

@@ -0,0 +1,27 @@
gdt_begin:
gdt_null:
dd 0x00
dd 0x00
gdt_code:
dw 0xffff
dw 0x0000
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xffff
dw 0x0000
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_begin - 1
dd gdt_begin
CODE_SEG equ gdt_code - gdt_begin
DATA_SEG equ gdt_data - gdt_begin

View File

@@ -0,0 +1,22 @@
[bits 32]
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
print_string_pm:
pusha
mov edx, VIDEO_MEMORY
print_string_pm_cycle:
cmp [ebx], BYTE 0
je print_string_pm_end
mov ah, WHITE_ON_BLACK
mov al, [ebx]
mov [edx], ax
add ebx, 1
add edx, 2
jmp print_string_pm_cycle
print_string_pm_end:
popa
ret

24
boot/x86/stage2/config.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef STAGE2_CONFIG
#define STAGE2_CONFIG
#include <libboot/types.h>
#define KERNEL_BASE 0x100000
struct x86_memory_map {
uint32_t startLo;
uint32_t startHi;
uint32_t sizeLo;
uint32_t sizeHi;
uint32_t type;
uint32_t acpi_3_0;
};
typedef struct x86_memory_map x86_memory_map_t;
struct x86_mem_desc {
uint32_t memory_map_size;
uint32_t kernel_size;
};
typedef struct x86_mem_desc x86_mem_desc_t;
#endif // STAGE2_CONFIG

View File

@@ -0,0 +1,135 @@
/**
* Ata Stage2 driver. This is a lite version, since it can work with
* only one drive at time. The @active_ata_drive is a boot drive.
*/
#include "ata.h"
#include <libboot/log/log.h>
// #define DEBUG_ATA
ata_t active_ata_drive;
void init_ata(uint32_t port, char is_master)
{
active_ata_drive.is_master = is_master;
active_ata_drive.data_port = port;
active_ata_drive.error_port = port + 0x1;
active_ata_drive.sector_count_port = port + 0x2;
active_ata_drive.lba_lo_port = port + 0x3;
active_ata_drive.lba_mid_port = port + 0x4;
active_ata_drive.lba_hi_port = port + 0x5;
active_ata_drive.device_port = port + 0x6;
active_ata_drive.command_port = port + 0x7;
active_ata_drive.control_port = port + 0x206;
}
int indentify_ata_device(drive_desc_t* drive_desc)
{
port_write8(active_ata_drive.device_port, active_ata_drive.is_master ? 0xA0 : 0xB0);
port_write8(active_ata_drive.sector_count_port, 0);
port_write8(active_ata_drive.lba_lo_port, 0);
port_write8(active_ata_drive.lba_mid_port, 0);
port_write8(active_ata_drive.lba_hi_port, 0);
port_write8(active_ata_drive.command_port, 0xEC);
// check the acceptance of a command
uint8_t status = port_read8(active_ata_drive.command_port);
if (status == 0x00) {
// printf("Cmd isn't accepted");
return -1;
}
// waiting for processing
// while BSY is on
while ((status & 0x80) == 0x80) {
status = port_read8(active_ata_drive.command_port);
}
// check if drive isn't ready to transer DRQ
if ((status & 0x08) != 0x08) {
// printf("Don't ready for transport");
return -1;
}
// transfering 256 bytes of data
for (int i = 0; i < 256; i++) {
uint16_t data = port_read16(active_ata_drive.data_port);
char* text = " \0";
text[0] = (data >> 8) & 0xFF;
text[1] = data & 0xFF;
if (i == 1) {
#ifdef DEBUG_ATA
log("Logical cylindres %x", data);
#endif
}
if (i == 3) {
#ifdef DEBUG_ATA
log("Logical heads %x", data);
#endif
}
if (i == 6) {
#ifdef DEBUG_ATA
log("Logical sectors %x", data);
#endif
}
if (i == 49) {
if (((data >> 8) & 0x1) == 1) {
#ifdef DEBUG_ATA
log("Dma supported");
#endif
}
if (((data >> 9) & 0x1) == 1) {
#ifdef DEBUG_ATA
log("Lba supported");
#endif
}
}
}
drive_desc->read = ata_read;
return 0;
}
// Returning 2 head read bytes (used to get size of kernel)
int ata_read(uint32_t sector, uint8_t* read_to)
{
uint8_t dev_config = 0xA0;
// lba support
dev_config |= (1 << 6);
if (!active_ata_drive.is_master) {
dev_config |= (1 << 4);
}
port_write8(active_ata_drive.device_port, dev_config);
port_write8(active_ata_drive.sector_count_port, 1);
port_write8(active_ata_drive.lba_lo_port, sector & 0x000000FF);
port_write8(active_ata_drive.lba_mid_port, (sector & 0x0000FF00) >> 8);
port_write8(active_ata_drive.lba_hi_port, (sector & 0x00FF0000) >> 16);
port_write8(active_ata_drive.error_port, 0);
port_write8(active_ata_drive.command_port, 0x21);
// waiting for processing
// while BSY is on and no Errors
uint8_t status = port_read8(active_ata_drive.command_port);
while (((status >> 7) & 1) == 1 && ((status >> 0) & 1) != 1) {
status = port_read8(active_ata_drive.command_port);
}
// check if drive isn't ready to transer DRQ
if (((status >> 0) & 1) == 1) {
return -1;
}
if (((status >> 3) & 1) == 0) {
return -1;
}
for (int i = 0; i < 256; i++) {
uint16_t data = port_read16(active_ata_drive.data_port);
read_to[2 * i + 1] = (data >> 8) & 0xFF;
read_to[2 * i] = data & 0xFF;
}
return 0;
}

View File

@@ -0,0 +1,25 @@
#ifndef _BOOT_X86_STAGE2_DRIVERS_ATA_H
#define _BOOT_X86_STAGE2_DRIVERS_ATA_H
#include "port.h"
#include <libboot/abi/drivers.h>
#include <libboot/types.h>
typedef struct { // LBA28 | LBA48
uint32_t data_port; // 16bit | 16 bits
uint32_t error_port; // 8 bit | 16 bits
uint32_t sector_count_port; // 8 bit | 16 bits
uint32_t lba_lo_port; // 8 bit | 16 bits
uint32_t lba_mid_port; // 8 bit | 16 bits
uint32_t lba_hi_port; // 8 bit | 16 bits
uint32_t device_port; // 8 bit
uint32_t command_port; // 8 bit
uint32_t control_port; // 8 bit
char is_master;
} ata_t;
void init_ata(uint32_t port, char is_master);
int indentify_ata_device(drive_desc_t* drive_desc);
int ata_read(uint32_t sector, uint8_t* read_to);
#endif

View File

@@ -0,0 +1,56 @@
#include "port.h"
unsigned char port_read8(unsigned short port)
{
unsigned char result_data;
asm volatile("inb %%dx, %%al"
: "=a"(result_data)
: "d"(port));
return result_data;
}
void port_write8(unsigned short port, unsigned char data)
{
asm volatile("outb %%al, %%dx"
:
: "a"(data), "d"(port));
}
unsigned short port_read16(unsigned short port)
{
unsigned short result_data;
asm volatile("inw %%dx, %%ax"
: "=a"(result_data)
: "d"(port));
return result_data;
}
void port_write16(unsigned short port, unsigned short data)
{
asm volatile("outw %%ax, %%dx"
:
: "a"(data), "d"(port));
}
unsigned int port_read32(unsigned short port)
{
unsigned int result_data;
asm volatile("inl %%dx, %%eax"
: "=a"(result_data)
: "d"(port));
return result_data;
}
void port_write32(unsigned short port, unsigned int data)
{
asm volatile("outl %%eax, %%dx"
:
: "a"(data), "d"(port));
}
void port_wait_io()
{
asm volatile("out %%al, $0x80"
:
: "a"(0)); // writing to "unused" port
}

View File

@@ -0,0 +1,15 @@
#ifndef _BOOT_X86_STAGE2_DRIVERS_PORT_H
#define _BOOT_X86_STAGE2_DRIVERS_PORT_H
unsigned char port_read8(unsigned short port);
void port_write8(unsigned short port, unsigned char data);
unsigned short port_read16(unsigned short port);
void port_write16(unsigned short port, unsigned short data);
unsigned int port_read32(unsigned short port);
void port_write32(unsigned short port, unsigned int data);
void port_wait_io();
#endif // _BOOT_X86_STAGE2_DRIVERS_PORT_H

View File

@@ -0,0 +1,36 @@
#include "uart.h"
#include "port.h"
static int _uart_setup_impl(int port)
{
port_write8(port + 1, 0x00);
port_write8(port + 3, 0x80);
port_write8(port + 0, 0x03);
port_write8(port + 1, 0x00);
port_write8(port + 3, 0x03);
port_write8(port + 2, 0xC7);
port_write8(port + 4, 0x0B);
return 0;
}
void uart_init()
{
_uart_setup_impl(COM1);
}
static inline bool _uart_is_free_in(int port)
{
return port_read8(port + 5) & 0x01;
}
static inline bool _uart_is_free_out(int port)
{
return port_read8(port + 5) & 0x20;
}
int uart_write(uint8_t data)
{
while (!_uart_is_free_out(COM1)) { }
port_write8(COM1, data);
return 0;
}

View File

@@ -0,0 +1,14 @@
#ifndef _STAGE2_DRIVERS_X86_UART_H
#define _STAGE2_DRIVERS_X86_UART_H
#include <libboot/types.h>
#define COM1 0x3F8
#define COM2 0x2F8
#define COM3 0x3E8
#define COM4 0x2E8
void uart_init();
int uart_write(uint8_t data);
#endif //_STAGE2_DRIVERS_X86_UART_H

23
boot/x86/stage2/mem/pde.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef _BOOT_X86_STAGE2_MEM_PDE_H
#define _BOOT_X86_STAGE2_MEM_PDE_H
#include <libboot/types.h>
#define table_desc_t uint32_t
#define pde_t uint32_t
enum TABLE_DESC_PAGE_FLAGS {
TABLE_DESC_PRESENT = 0,
TABLE_DESC_WRITABLE,
TABLE_DESC_USER,
TABLE_DESC_PWT,
TABLE_DESC_PCD,
TABLE_DESC_ACCESSED,
TABLE_DESC_DIRTY,
TABLE_DESC_4MB,
TABLE_DESC_CPU_GLOBAL,
TABLE_DESC_LV4_GLOBAL,
TABLE_DESC_FRAME = 12
};
#endif //_BOOT_X86_STAGE2_MEM_PDE_H

23
boot/x86/stage2/mem/pte.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef _BOOT_X86_STAGE2_MEM_PTE_H
#define _BOOT_X86_STAGE2_MEM_PTE_H
#include <libboot/types.h>
#define page_desc_t uint32_t
#define pte_t uint32_t
enum PAGE_DESC_PAGE_FLAGS {
PAGE_DESC_PRESENT = 0,
PAGE_DESC_WRITABLE,
PAGE_DESC_USER,
PAGE_DESC_WRITETHOUGH,
PAGE_DESC_NOT_CACHEABLE,
PAGE_DESC_ACCESSED,
PAGE_DESC_DIRTY,
PAGE_DESC_PAT,
PAGE_DESC_CPU_GLOBAL,
PAGE_DESC_LV4_GLOBAL,
PAGE_DESC_FRAME = 12
};
#endif //_BOOT_X86_STAGE2_MEM_PTE_H

77
boot/x86/stage2/mem/vm.c Normal file
View File

@@ -0,0 +1,77 @@
#include "vm.h"
int vm_setup()
{
ptable_t* table_0mb = (ptable_t*)0x9A000;
ptable_t* table_0mbplus = (ptable_t*)0x98000;
ptable_t* table_3gb = (ptable_t*)0x9B000;
ptable_t* table_3gbplus = (ptable_t*)0x99000;
ptable_t* table_stack = (ptable_t*)0x9C000;
pdirectory_t* dir = (pdirectory_t*)0x9D000;
for (uint32_t phyz = 0, virt = 0, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) {
pte_t new_page = 0;
new_page |= 3;
new_page |= ((phyz / VMM_PAGE_SIZE) << 12);
table_0mb->entities[i] = new_page;
}
for (uint32_t phyz = 0x400000, virt = 0x400000, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) {
pte_t new_page = 0;
new_page |= 3;
new_page |= ((phyz / VMM_PAGE_SIZE) << 12);
table_0mbplus->entities[i] = new_page;
}
for (uint32_t phyz = 0x100000, virt = 0xc0000000, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) {
pte_t new_page = 0;
new_page |= 3;
new_page |= ((phyz / VMM_PAGE_SIZE) << 12);
table_3gb->entities[i] = new_page;
}
for (uint32_t phyz = 0x500000, virt = 0xc0400000, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) {
pte_t new_page = 0;
new_page |= 3;
new_page |= ((phyz / VMM_PAGE_SIZE) << 12);
table_3gbplus->entities[i] = new_page;
}
for (uint32_t phyz = 0x000000, virt = 0xffc00000, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) {
pte_t new_page = 0;
new_page |= 3;
new_page |= ((phyz / VMM_PAGE_SIZE) << 12);
table_stack->entities[i] = new_page;
}
uint8_t* dir_for_memset = (uint8_t*)dir;
for (int i = 0; i < 1024; i++) {
dir->entities[i] = 0;
}
uint32_t table_0mb_int = (uint32_t)table_0mb;
dir->entities[0] |= 3;
dir->entities[0] |= ((table_0mb_int / VMM_PAGE_SIZE) << 12);
table_0mb_int = (uint32_t)table_0mbplus;
dir->entities[1] |= 3;
dir->entities[1] |= ((table_0mb_int / VMM_PAGE_SIZE) << 12);
uint32_t table_3gb_int = (uint32_t)table_3gb;
dir->entities[768] |= 3;
dir->entities[768] |= ((table_3gb_int / VMM_PAGE_SIZE) << 12);
table_3gb_int = (uint32_t)table_3gbplus;
dir->entities[769] |= 3;
dir->entities[769] |= ((table_3gb_int / VMM_PAGE_SIZE) << 12);
uint32_t table_stack_int = (uint32_t)table_stack;
dir->entities[1023] |= 3;
dir->entities[1023] |= ((table_stack_int / VMM_PAGE_SIZE) << 12);
asm volatile("mov %%eax, %%cr3"
:
: "a"(dir));
return 0;
}

28
boot/x86/stage2/mem/vm.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef _BOOT_X86_STAGE2_MEM_VM_H
#define _BOOT_X86_STAGE2_MEM_VM_H
#include "pde.h"
#include "pte.h"
#include <libboot/types.h>
#define VMM_LV0_ENTITY_COUNT (1024)
#define VMM_LV1_ENTITY_COUNT (1024)
#define VMM_PAGE_SIZE (4096)
enum VMM_ERR_CODES {
VMM_ERR_PDIR,
VMM_ERR_NO_SPACE,
VMM_ERR_BAD_ADDR,
};
typedef struct {
page_desc_t entities[VMM_LV0_ENTITY_COUNT];
} ptable_t;
typedef struct pdirectory {
table_desc_t entities[VMM_LV1_ENTITY_COUNT];
} pdirectory_t;
int vm_setup();
#endif // _BOOT_X86_STAGE2_MEM_VM_H

156
boot/x86/stage2/stage2.c Normal file
View File

@@ -0,0 +1,156 @@
/**
* Stage2 is used to load main kernel.
*/
#include "config.h"
#include "drivers/ata.h"
#include "drivers/uart.h"
#include "mem/vm.h"
#include <libboot/abi/drivers.h>
#include <libboot/abi/memory.h>
#include <libboot/crypto/validate.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>
#include <libboot/types.h>
// #define DEBUG_BOOT
#define KERNEL_PATH "/boot/kernel.bin"
#define LAUNCH_SERVER_PATH "/System/launch_server"
static boot_args_t boot_args;
static size_t kernel_vaddr = 0;
static size_t kernel_paddr = 0;
static size_t kernel_size = 0;
static void alloc_init(x86_mem_desc_t* mem_desc)
{
// TODO: We use manual layouting in this bootloader. Thus
// all addresses are hardcoded, no need to use allocator at all.
}
static memory_boot_desc_t memory_boot_desc_init(x86_mem_desc_t* mem_desc)
{
char dummy_data = 0x0;
size_t ram_last_addr = 0x0;
size_t next_id = 0;
memory_layout_t* mem_layout_paddr = copy_after_kernel(kernel_paddr, &dummy_data, sizeof(dummy_data), &kernel_size, VMM_PAGE_SIZE);
x86_memory_map_t* memory_map = (x86_memory_map_t*)0xA00;
for (int i = 0; i < mem_desc->memory_map_size; i++) {
if (memory_map[i].type == 0x2) {
// The region is marked as reserved, removing it.
mem_layout_paddr[next_id].base = memory_map[i].startLo;
mem_layout_paddr[next_id].size = memory_map[i].sizeLo;
mem_layout_paddr[next_id].flags = 0;
next_id++;
} else {
ram_last_addr = max(ram_last_addr, memory_map[i].startLo + memory_map[i].sizeLo);
}
}
mem_layout_paddr[next_id].flags = MEMORY_LAYOUT_FLAG_TERMINATE;
memory_layout_t* mem_layout_vaddr = paddr_to_vaddr(mem_layout_paddr, kernel_paddr, kernel_vaddr);
memory_boot_desc_t res;
res.ram_base = 0x0;
res.ram_size = ram_last_addr;
res.reserved_areas = mem_layout_vaddr;
return res;
}
int prepare_boot_disk(drive_desc_t* drive_desc)
{
init_ata(0x1F0, 1);
if (indentify_ata_device(drive_desc) == 0) {
return 0;
}
return -1;
}
int prepare_fs(drive_desc_t* drive_desc, fs_desc_t* fs_desc)
{
if (ext2_lite_init(drive_desc, fs_desc) == 0) {
return 0;
}
return -1;
}
static int validate_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc)
{
log("Validating Kernel...");
if (!validate_elf(KERNEL_PATH, drive_desc, fs_desc)) {
log("Can't validate kernel");
while (1) { }
}
if (!validate_elf(LAUNCH_SERVER_PATH, drive_desc, fs_desc)) {
log("Can't validate launch_server");
while (1) { }
}
return 0;
}
void* bootdesc_ptr;
void load_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc, x86_mem_desc_t* mem_desc)
{
int res = elf_load_kernel(drive_desc, fs_desc, KERNEL_PATH, &kernel_vaddr, &kernel_paddr, &kernel_size);
kernel_size = align_size(kernel_size, VMM_PAGE_SIZE);
size_t kernel_data_size = kernel_size + align_size(sizeof(boot_args_t), VMM_PAGE_SIZE) + VMM_PAGE_SIZE;
boot_args_t boot_args;
boot_args.vaddr = kernel_vaddr;
boot_args.paddr = kernel_paddr;
boot_args.kernel_data_size = kernel_data_size;
boot_args.devtree = NULL;
boot_args.mem_boot_desc = memory_boot_desc_init(mem_desc);
memcpy(boot_args.init_process, LAUNCH_SERVER_PATH, sizeof(LAUNCH_SERVER_PATH));
bootdesc_ptr = paddr_to_vaddr(copy_after_kernel(kernel_paddr, &boot_args, sizeof(boot_args), &kernel_size, VMM_PAGE_SIZE), kernel_paddr, kernel_vaddr);
}
void stage2(x86_mem_desc_t* mem_desc)
{
uart_init();
log_init(uart_write);
alloc_init(mem_desc);
#ifdef DEBUG_BOOT
log("STAGE2");
#endif
drive_desc_t drive_desc;
fs_desc_t fs_desc;
if (prepare_boot_disk(&drive_desc) != 0) {
#ifdef DEBUG_BOOT
log("STAGE2");
#endif
while (1) { }
}
if (prepare_fs(&drive_desc, &fs_desc) != 0) {
#ifdef DEBUG_BOOT
log("STAGE2");
#endif
while (1) { }
}
validate_kernel(&drive_desc, &fs_desc);
load_kernel(&drive_desc, &fs_desc, mem_desc);
vm_setup();
// enabling paging
asm volatile("mov %cr0, %eax");
asm volatile("or $0x80000000, %eax");
asm volatile("mov %eax, %cr0");
asm volatile("push %0"
:
: "r"(bootdesc_ptr));
asm volatile("mov $0xc0000000, %eax");
asm volatile("call *%eax");
while (1) { }
}

View File

@@ -0,0 +1,12 @@
section .xos_boot_text
[bits 32]
extern stage2
extern STACK_PHYZ_TOP
global _start
_start:
mov eax, esp
mov esp, STACK_PHYZ_TOP
push dword [eax+4]
call stage2
jmp $

View File

@@ -0,0 +1,61 @@
#ifndef _BOOT_DRIVERS_PORT_H
#define _BOOT_DRIVERS_PORT_H
#include <libboot/types.h>
static inline uint8_t port_read8(uint16_t port)
{
uint8_t result_data;
asm volatile("inb %%dx, %%al"
: "=a"(result_data)
: "d"(port));
return result_data;
}
static inline void port_write8(uint16_t port, uint8_t data)
{
asm volatile("outb %%al, %%dx"
:
: "a"(data), "d"(port));
}
static inline uint16_t port_read16(uint16_t port)
{
uint16_t result_data;
asm volatile("inw %%dx, %%ax"
: "=a"(result_data)
: "d"(port));
return result_data;
}
static inline void port_write16(uint16_t port, uint16_t data)
{
asm volatile("outw %%ax, %%dx"
:
: "a"(data), "d"(port));
}
static inline uint32_t port_read32(uint16_t port)
{
uint32_t result_data;
asm volatile("inl %%dx, %%eax"
: "=a"(result_data)
: "d"(port));
return result_data;
}
static inline void port_write32(uint16_t port, uint32_t data)
{
asm volatile("outl %%eax, %%dx"
:
: "a"(data), "d"(port));
}
static inline void port_wait_io()
{
asm volatile("out %%al, $0x80"
:
: "a"(0));
}
#endif // _BOOT_DRIVERS_PORT_H

View File

@@ -0,0 +1,43 @@
#include "uart.h"
#include "port.h"
static int _uart_setup_impl(int port)
{
port_write8(port + 1, 0x00);
port_write8(port + 3, 0x80);
port_write8(port + 0, 0x03);
port_write8(port + 1, 0x00);
port_write8(port + 3, 0x03);
port_write8(port + 2, 0xC7);
port_write8(port + 4, 0x0B);
return 0;
}
void uart_init()
{
_uart_setup_impl(COM1);
}
static inline bool _uart_is_free_in(int port)
{
return port_read8(port + 5) & 0x01;
}
static inline bool _uart_is_free_out(int port)
{
return port_read8(port + 5) & 0x20;
}
int uart_write(uint8_t data)
{
while (!_uart_is_free_out(COM1)) { }
port_write8(COM1, data);
return 0;
}
int uart_read(uint8_t* data)
{
while (!_uart_is_free_out(COM1)) { }
*data = port_read8(COM1);
return 0;
}

View File

@@ -0,0 +1,15 @@
#ifndef _BOOT_DRIVERS_UART_H
#define _BOOT_DRIVERS_UART_H
#include <libboot/types.h>
#define COM1 0x3F8
#define COM2 0x2F8
#define COM3 0x3E8
#define COM4 0x2E8
void uart_init();
int uart_write(uint8_t data);
int uart_read(uint8_t* data);
#endif //_BOOT_DRIVERS_UART_H

View File

@@ -0,0 +1,153 @@
#include "drivers/uart.h"
#include "vm.h"
#include <libboot/abi/multiboot.h>
#include <libboot/elf/elf_lite.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/types.h>
// #define DEBUG_BOOT
extern void jump_to_kernel(void*, uintptr_t);
static void* bootdesc_paddr;
static void* bootdesc_vaddr;
static size_t kernel_vaddr = 0;
static size_t kernel_paddr = 0;
static size_t kernel_size = 0;
#define LAUNCH_SERVER_PATH "/System/launch_server"
static int alloc_init(uintptr_t base, multiboot_info_t* multiboot)
{
uintptr_t region_base = 0x0;
size_t region_size = 0x0;
multiboot_memory_map_t* memmap = (multiboot_memory_map_t*)(uint64_t)multiboot->mmap_addr;
size_t n = multiboot->mmap_length / sizeof(multiboot_memory_map_t);
// Looking for the zone of memory where we are linked
for (int i = 0; i < n; i++) {
if (memmap[i].type == MULTIBOOT_MEMORY_AVAILABLE) {
if (memmap[i].addr <= base && base < memmap[i].addr + memmap[i].len) {
region_base = memmap[i].addr;
region_size = memmap[i].len;
}
}
}
// We expect the current zone to be quite big, at least 128Mb.
if (region_size < (128 << 20)) {
log("Current space is less than required 128Mbs");
while (1) { }
}
extern uint32_t RAWIMAGE_END[];
uintptr_t start_addr = ROUND_CEIL((uint64_t)RAWIMAGE_END, page_size());
size_t free_space = region_size - (start_addr - region_base);
malloc_init((void*)start_addr, free_space);
#ifdef DEBUG_BOOT
log("malloc inited %llx %llx", start_addr, free_space);
#endif
return 0;
}
static size_t memory_layout_size(multiboot_info_t* multiboot)
{
size_t n = multiboot->mmap_length / sizeof(multiboot_memory_map_t);
return n + 1; // Including the trailing element.
}
static int preserve_alloc_init(size_t kernsize, multiboot_info_t* multiboot)
{
const size_t memmap = ROUND_CEIL(memory_layout_size(multiboot) * sizeof(memory_layout_t), page_size());
const size_t bootargsstruct = ROUND_CEIL(sizeof(boot_args_t), page_size());
const size_t bootargssize = memmap + bootargsstruct;
// 32 tables should be enough for initial mappings.
const size_t prekernelvmsize = 32 * page_size();
const size_t total = ROUND_CEIL(kernsize + bootargssize + prekernelvmsize, page_size());
return palloc_init(total, 2 << 20);
}
static memory_boot_desc_t memory_boot_desc_init(multiboot_info_t* multiboot)
{
size_t ram_last_addr = 0x0;
size_t next_id = 0;
memory_layout_t* mem_layout_paddr = palloc_aligned(memory_layout_size(multiboot) * sizeof(memory_layout_t), page_size());
multiboot_memory_map_t* memmap = (multiboot_memory_map_t*)(uint64_t)multiboot->mmap_addr;
size_t n = multiboot->mmap_length / sizeof(multiboot_memory_map_t);
for (int i = 0; i < n; i++) {
if (memmap[i].type != MULTIBOOT_MEMORY_AVAILABLE) {
// The region is marked as reserved, removing it.
mem_layout_paddr[next_id].base = memmap[i].addr;
mem_layout_paddr[next_id].size = memmap[i].len;
mem_layout_paddr[next_id].flags = 0;
next_id++;
} else {
ram_last_addr = max(ram_last_addr, memmap[i].addr + memmap[i].len);
}
}
mem_layout_paddr[next_id].flags = MEMORY_LAYOUT_FLAG_TERMINATE;
memory_layout_t* mem_layout_vaddr = paddr_to_vaddr(mem_layout_paddr, kernel_paddr, kernel_vaddr);
memory_boot_desc_t res;
res.ram_base = 0x0;
res.ram_size = ram_last_addr;
res.reserved_areas = mem_layout_vaddr;
return res;
}
static void load_kernel(void* kenrelstart, multiboot_info_t* multiboot)
{
kernel_size = elf_get_kernel_size(kenrelstart);
kernel_size = ROUND_CEIL(kernel_size, page_size());
int err = preserve_alloc_init(kernel_size, multiboot);
if (err) {
log("add assert");
while (1) { }
}
int res = elf_load_kernel(kenrelstart, kernel_size, &kernel_vaddr, &kernel_paddr);
#ifdef DEBUG_BOOT
log("kernel %lx %lx %lx", kernel_vaddr, kernel_paddr, kernel_size);
#endif
boot_args_t boot_args;
boot_args.vaddr = kernel_vaddr;
boot_args.paddr = kernel_paddr;
boot_args.kernel_data_size = 0x0; // Sets up later
boot_args.mem_boot_desc = memory_boot_desc_init(multiboot);
boot_args.devtree = NULL;
boot_args.fb_boot_desc.vaddr = 0; // Marking fb as invalid.
memcpy(boot_args.init_process, LAUNCH_SERVER_PATH, sizeof(LAUNCH_SERVER_PATH));
bootdesc_paddr = palloc_aligned(sizeof(boot_args), page_size());
memcpy(bootdesc_paddr, &boot_args, sizeof(boot_args));
bootdesc_vaddr = paddr_to_vaddr(bootdesc_paddr, kernel_paddr, kernel_vaddr);
#ifdef DEBUG_BOOT
log("copying BOOTDESC %lx -> %lx of %d", &boot_args, bootdesc_vaddr, sizeof(boot_args));
#endif
}
int main(uint64_t base, multiboot_info_t* multiboot)
{
uart_init();
log_init(uart_write);
alloc_init(base, multiboot);
extern uint32_t EMBED_KERNEL_START[];
load_kernel((void*)EMBED_KERNEL_START, multiboot);
vm_setup(base, bootdesc_paddr);
#ifdef DEBUG_BOOT
log("Preboot done: booting to OS@%llx", ((boot_args_t*)bootdesc_vaddr)->vaddr);
#endif
((boot_args_t*)bootdesc_vaddr)->kernel_data_size = ROUND_CEIL(palloc_used_size(), page_size());
jump_to_kernel((void*)bootdesc_vaddr, ((boot_args_t*)bootdesc_vaddr)->vaddr);
return 0;
}

View File

@@ -0,0 +1,299 @@
MBOOT_PAGE_ALIGN equ 1<<0
MBOOT_MEM_INFO equ 1<<1
MBOOT_HEADER_MAGIC equ 0x1badb002
MBOOT_HEADER_FLAGS equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO
MBOOT_CHECKSUM equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)
section .multiboot
dd MBOOT_HEADER_MAGIC
dd MBOOT_HEADER_FLAGS
dd MBOOT_CHECKSUM
dd 0x00000000; header_addr
dd 0x00000000; load_addr
dd 0x00000000; load_end_addr
dd 0x00000000; bss_end_addr
dd 0x00000000; entry_addr
dd 0x00000000; mode_type
dd 0x00000000; width
dd 0x00000000; height
dd 0x00000000; depth
[bits 32]
section .xos_boot_text
extern main
extern PREKERNEL_STACK_TOP
global _start
_start:
global prekernel_entry
prekernel_entry:
cli
cld
; Setting up the stack.
mov ebp, PREKERNEL_STACK_TOP
mov esp, ebp
; Save entry point to one of callee-saved regs.
mov esi, ecx
; PAE is required for x86_64
call check_for_pae
; Checking for long mode.
call check_for_long_mode
; x86_64 required paging enabled, thus 1GB of physical memmory is mapped
; for booting the kernel without any problems.
call setup_tables
; Enabling long mode with a 32-bit compatibility submode.
call enable_long_mode
; Just give control to jumper.
jmp jump_to_entry64
CPUID_FEATURE_PAE equ (1 << 6)
check_for_pae:
push ebp
mov ebp, esp
push ebx
mov eax, 0x1
cpuid
test edx, CPUID_FEATURE_PAE
jz pae_unsupported
pop ebx
pop ebp
ret
pae_unsupported:
push pae_unsupported_msg
call early_boot_print_string
hlt
CPUID_FEATURE_LONG_MODE equ (1 << 29)
check_for_long_mode:
push ebp
mov ebp, esp
push ebx
mov eax, 0x80000001
cpuid
test edx, CPUID_FEATURE_LONG_MODE
jz long_mode_unsupported
pop ebx
pop ebp
ret
long_mode_unsupported:
push long_mode_unsupported_msg
call early_boot_print_string
hlt
setup_tables:
push ebp
mov ebp, esp
push edi
mov edi, table0
xor eax, eax
mov ecx, 4096
rep stosb
mov edi, table1
xor eax, eax
mov ecx, 4096
rep stosb
mov edi, table2
xor eax, eax
mov ecx, 4096
rep stosb
mov eax, table1
add eax, 0x3
mov DWORD [table0], eax
mov eax, table2
add eax, 0x3
mov DWORD [table1], eax
mov edi, table2
mov eax, 0x83
mov ecx, 512
.table_fillup_last:
mov DWORD [edi], eax
add eax, 0x200000
add edi, 8
loop .table_fillup_last
pop edi
pop ebp
ret
enable_long_mode:
push ebp
mov ebp, esp
; Setting table
mov eax, table0
mov cr3, eax
; Enabling PAE
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
; Enabling Long Mode
mov ecx, 0xc0000080
rdmsr
or eax, 1 << 8
wrmsr
mov eax, cr0
or eax, 1 << 31
mov cr0, eax
pop ebp
ret
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
global early_boot_print_string
early_boot_print_string:
push ebp
mov ebp, esp
push esi
push ecx
mov esi, [ebp+8]
mov ecx, VIDEO_MEMORY
mov ah, WHITE_ON_BLACK
_print_string_loop:
lodsb; Load from esi to al then increment esi
test al, al
jz _print_string_end
mov [ecx], ax
add ecx, 2
jmp _print_string_loop
_print_string_end:
mov eax, esi
sub eax, [ebp+8]
pop ecx
pop esi
mov esp, ebp
pop ebp
ret
; Access bits
PRESENT equ 1 << 7
NOT_SYS equ 1 << 4
EXEC equ 1 << 3
DC equ 1 << 2
RW equ 1 << 1
ACCESSED equ 1 << 0
; Flags bits
GRAN_4K equ 1 << 7
SZ_32 equ 1 << 6
LONG_MODE equ 1 << 5
align 32
gdt_begin:
gdt_null:
dq 0x0
gdt_code:
dd 0xffff
db 0x0
db PRESENT | NOT_SYS | EXEC | RW
db GRAN_4K | LONG_MODE | 0xF
db 0x0
gdt_data:
dd 0xffff
db 0x0
db PRESENT | NOT_SYS | RW
db GRAN_4K | SZ_32 | 0xF
db 0x0
gdt_tss:
dd 0x00000068
dd 0x00cf8900
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_begin - 1
dd gdt_begin
dd 0x0
CODE_SEG equ gdt_code - gdt_begin
DATA_SEG equ gdt_data - gdt_begin
jump_to_entry64:
lgdt [gdt_descriptor]
jmp CODE_SEG:main_entry64
[bits 64]
main_entry64:
cli
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov edi, esi
mov esi, ebx
call main
hlt
global set_cr3
set_cr3:
mov cr3, rdi
ret
global jump_to_kernel
jump_to_kernel:
mov rax, cr3
mov cr3, rax
call rsi
jmp $
pae_unsupported_msg:
db "Required PAE Feature is unavailable, stopping...", 0
long_mode_unsupported_msg:
db "Required Long Mode Feature is unavailable, stopping...", 0
section .bss
table0:
align 4096
resb 4096
table1:
align 4096
resb 4096
table2:
align 4096
resb 4096

108
boot/x86_64/prekernel/vm.c Normal file
View File

@@ -0,0 +1,108 @@
#include "vm.h"
#include <libboot/abi/kernel.h>
#include <libboot/abi/rawimage.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 = 0x00000000000003;
pdesc |= (uintptr_t)nptbl;
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)] = pdesc;
ptable_desc = pdesc;
}
// Level2
page_table = (uint64_t*)(((ptable_desc >> 12) << 12) & 0xffffffffffff);
ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)];
if (ptable_desc == 0) {
uint64_t* nptbl = new_ptable(args);
uint64_t pdesc = 0x00000000000003;
pdesc |= (uintptr_t)nptbl;
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)] = pdesc;
ptable_desc = pdesc;
}
page_table = (uint64_t*)(((ptable_desc >> 12) << 12) & 0xffffffffffff);
uint64_t pdesc = 0x0000000000083;
pdesc |= (uintptr_t)phyz;
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV1_VADDR_OFFSET, VMM_LV1_ENTITY_COUNT)] = pdesc;
}
// 1Gb huge pages are available as a seperate feature, so use 2Mb pages.
static void map4kb_1gb(boot_args_t* args, size_t phyz, size_t virt)
{
const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET);
const size_t page_mask = page_covers - 1;
if ((phyz & page_mask) != 0 || (virt & page_mask) != 0) {
return;
}
for (int i = 0; i < 512; i++) {
map4kb_2mb(args, phyz, virt);
phyz += (2 << 20);
virt += (2 << 20);
}
}
void vm_setup(uintptr_t base, boot_args_t* args)
{
global_page_table = (uint64_t*)palloc_aligned(page_size(), page_size());
memset(global_page_table, 0, page_size());
const size_t map_range_2mb = (2 << 20);
const size_t map_range_1gb = (1 << 30);
// Mapping kernel vaddr to paddr
size_t kernel_size_to_map = palloc_total_size() + shadow_area_size();
size_t kernel_range_count_to_map = (kernel_size_to_map + (map_range_2mb - 1)) / map_range_2mb;
for (size_t i = 0; i < kernel_range_count_to_map; i++) {
#ifdef DEBUG_VM
log("mapping %lx %lx", args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb);
#endif
map4kb_2mb(args, args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb);
}
// Mapping RAM
size_t ram_base = ROUND_FLOOR(args->mem_boot_desc.ram_base, map_range_1gb);
size_t ram_size = args->mem_boot_desc.ram_size;
size_t ram_range_count_to_map = (ram_size + (map_range_1gb - 1)) / map_range_1gb;
for (size_t i = 0; i < ram_range_count_to_map; i++) {
#ifdef DEBUG_VM
log("mapping %lx %lx", ram_base + i * map_range_1gb, ram_base + i * map_range_1gb);
#endif
map4kb_1gb(args, ram_base + i * map_range_1gb, ram_base + i * map_range_1gb);
}
extern void set_cr3(void* cr);
set_cr3(global_page_table);
}

View File

@@ -0,0 +1,24 @@
#ifndef _BOOT_VM_H
#define _BOOT_VM_H
#include <libboot/abi/memory.h>
#include <libboot/types.h>
#define VMM_LV0_ENTITY_COUNT (512)
#define VMM_LV1_ENTITY_COUNT (512)
#define VMM_LV2_ENTITY_COUNT (512)
#define VMM_LV3_ENTITY_COUNT (512)
#define PTABLE_LV_TOP (3)
#define PTABLE_LV0_VADDR_OFFSET (12)
#define PTABLE_LV1_VADDR_OFFSET (21)
#define PTABLE_LV2_VADDR_OFFSET (30)
#define PTABLE_LV3_VADDR_OFFSET (39)
#define VM_VADDR_OFFSET_AT_LEVEL(vaddr, off, ent) ((vaddr >> off) % ent)
static size_t page_size() { return 0x1000; }
void vm_setup(uintptr_t base, boot_args_t* args);
#endif // _BOOT_VM_H