Squash commits for public release
This commit is contained in:
163
boot/arm32/drivers/pl181.c
Normal file
163
boot/arm32/drivers/pl181.c
Normal file
@@ -0,0 +1,163 @@
|
||||
#include "pl181.h"
|
||||
#include <libboot/devtree/devtree.h>
|
||||
#include <libboot/log/log.h>
|
||||
|
||||
// #define DEBUG_PL181
|
||||
|
||||
static sd_card_t sd_card;
|
||||
static volatile pl181_registers_t* registers;
|
||||
|
||||
static inline int _pl181_map_itself(devtree_entry_t* dev)
|
||||
{
|
||||
registers = (pl181_registers_t*)(uint32_t)dev->region_base;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void _pl181_clear_flags()
|
||||
{
|
||||
registers->clear = 0x5FF;
|
||||
}
|
||||
|
||||
static int _pl181_send_cmd(uint32_t cmd, uint32_t param)
|
||||
{
|
||||
_pl181_clear_flags();
|
||||
|
||||
registers->arg = param;
|
||||
registers->cmd = cmd;
|
||||
|
||||
while (registers->status & MMC_STAT_CMD_ACTIVE_MASK) { }
|
||||
|
||||
if ((cmd & MMC_CMD_RESP_MASK) == MMC_CMD_RESP_MASK) {
|
||||
while (((registers->status & MMC_STAT_CMD_RESP_END_MASK) != MMC_STAT_CMD_RESP_END_MASK) || (registers->status & MMC_STAT_CMD_ACTIVE_MASK)) {
|
||||
if (registers->status & MMC_STAT_CMD_TIMEOUT_MASK) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while ((registers->status & MMC_STAT_CMD_SENT_MASK) != MMC_STAT_CMD_SENT_MASK) { }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _pl181_send_app_cmd(uint32_t cmd, uint32_t param)
|
||||
{
|
||||
for (int i = 0; i < 5; i++) {
|
||||
_pl181_send_cmd(CMD_APP_CMD | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, 0);
|
||||
if (registers->response[0] & (1 << 5)) {
|
||||
return _pl181_send_cmd(cmd, param);
|
||||
}
|
||||
}
|
||||
|
||||
log_error("Failed to send app command");
|
||||
return -4;
|
||||
}
|
||||
|
||||
inline static int _pl181_select_card(uint32_t rca)
|
||||
{
|
||||
return _pl181_send_cmd(CMD_SELECT | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, rca);
|
||||
}
|
||||
|
||||
static int _pl181_read_block(uint32_t lba_like, void* read_data)
|
||||
{
|
||||
sd_card_t* sd_card_ptr = &sd_card;
|
||||
uint32_t* read_data32 = (uint32_t*)read_data;
|
||||
uint32_t bytes_read = 0;
|
||||
|
||||
registers->data_length = PL181_SECTOR_SIZE; // Set length of bytes to transfer
|
||||
registers->data_control = 0b11; // Enable dpsm and set direction from card to host
|
||||
|
||||
if (sd_card_ptr->ishc) {
|
||||
_pl181_send_cmd(CMD_READ_SINGLE_BLOCK | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, lba_like);
|
||||
} else {
|
||||
_pl181_send_cmd(CMD_READ_SINGLE_BLOCK | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, lba_like * PL181_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
while (registers->status & MMC_STAT_FIFO_DATA_AVAIL_TO_READ_MASK) {
|
||||
*read_data32 = registers->fifo_data[0];
|
||||
read_data32++;
|
||||
bytes_read += 4;
|
||||
}
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static int _pl181_register_device(uint32_t rca, bool ishc, uint32_t capacity)
|
||||
{
|
||||
sd_card.rca = rca;
|
||||
sd_card.ishc = ishc;
|
||||
sd_card.capacity = capacity;
|
||||
_pl181_select_card(rca);
|
||||
_pl181_send_cmd(CMD_SET_SECTOR_SIZE | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, PL181_SECTOR_SIZE);
|
||||
if (registers->response[0] != 0x900) {
|
||||
log_error("PL181(pl181_add_new_device): Can't set sector size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pl181_init(drive_desc_t* drive_desc)
|
||||
{
|
||||
devtree_entry_t* dev = devtree_find_device("pl181");
|
||||
if (!dev) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_pl181_map_itself(dev)) {
|
||||
#ifdef DEBUG_PL181
|
||||
log_error("PL181: Can't map itself!");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PL181
|
||||
log("PL181: Turning on");
|
||||
#endif
|
||||
|
||||
registers->clock = 0x1C6;
|
||||
registers->power = 0x86;
|
||||
|
||||
// Send cmd 0 to set all cards into idle state
|
||||
_pl181_send_cmd(CMD_GO_IDLE_STATE | MMC_CMD_ENABLE_MASK, 0x0);
|
||||
|
||||
// Voltage Check
|
||||
_pl181_send_cmd(8 | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, 0x1AA);
|
||||
if ((registers->response[0] & 0x1AA) != 0x1AA) {
|
||||
#ifdef DEBUG_PL181
|
||||
log_error("PL181: Can't set voltage!");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_pl181_send_app_cmd(CMD_SD_SEND_OP_COND | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, 1 << 30 | 0x1AA)) {
|
||||
#ifdef DEBUG_PL181
|
||||
log_error("PL181: Can't send APP_CMD!");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ishc = 0;
|
||||
|
||||
if (registers->response[0] & 1 << 30) {
|
||||
ishc = 1;
|
||||
#ifdef DEBUG_PL181
|
||||
log("PL181: ishc = 1");
|
||||
#endif
|
||||
}
|
||||
|
||||
_pl181_send_cmd(CMD_ALL_SEND_CID | MMC_CMD_ENABLE_MASK | MMC_CMD_LONG_RESP_MASK, 0x0);
|
||||
_pl181_send_cmd(CMD_SET_RELATIVE_ADDR | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK, 0x0);
|
||||
|
||||
// Get the card RCA from the response it is the top 16 bits of the 32 bit response
|
||||
uint32_t rca = (registers->response[0] & 0xFFFF0000);
|
||||
|
||||
_pl181_send_cmd(CMD_SEND_CSD | MMC_CMD_ENABLE_MASK | MMC_CMD_RESP_MASK | MMC_CMD_LONG_RESP_MASK, rca);
|
||||
uint32_t resp1 = registers->response[1];
|
||||
uint32_t capacity = ((resp1 >> 8) & 0x3) << 10;
|
||||
capacity |= (resp1 & 0xFF) << 2;
|
||||
capacity = 256 * 1024 * (capacity + 1);
|
||||
|
||||
_pl181_register_device(rca, ishc, capacity);
|
||||
|
||||
drive_desc->read = _pl181_read_block;
|
||||
return 0;
|
||||
}
|
||||
73
boot/arm32/drivers/pl181.h
Normal file
73
boot/arm32/drivers/pl181.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#ifndef _BOOT_DRIVERS_PL181_H
|
||||
#define _BOOT_DRIVERS_PL181_H
|
||||
|
||||
#include <libboot/abi/drivers.h>
|
||||
#include <libboot/types.h>
|
||||
|
||||
#define PL181_SECTOR_SIZE 512
|
||||
|
||||
enum PL181CommandMasks {
|
||||
MASKDEFINE(MMC_CMD_IDX, 0, 6),
|
||||
MASKDEFINE(MMC_CMD_RESP, 6, 1),
|
||||
MASKDEFINE(MMC_CMD_LONG_RESP, 7, 1),
|
||||
MASKDEFINE(MMC_CMD_INTERRUPT, 8, 1),
|
||||
MASKDEFINE(MMC_CMD_PENDING, 9, 1),
|
||||
MASKDEFINE(MMC_CMD_ENABLE, 10, 1),
|
||||
};
|
||||
|
||||
enum PL181StatusMasks {
|
||||
MASKDEFINE(MMC_STAT_CRC_FAIL, 0, 1),
|
||||
MASKDEFINE(MMC_STAT_CMD_TIMEOUT, 2, 1),
|
||||
MASKDEFINE(MMC_STAT_CMD_RESP_END, 6, 1),
|
||||
MASKDEFINE(MMC_STAT_CMD_SENT, 7, 1),
|
||||
MASKDEFINE(MMC_STAT_CMD_ACTIVE, 11, 1),
|
||||
MASKDEFINE(MMC_STAT_TRANSMIT_FIFO_EMPTY, 18, 1),
|
||||
MASKDEFINE(MMC_STAT_FIFO_DATA_AVAIL_TO_READ, 21, 1),
|
||||
};
|
||||
|
||||
enum PL181Commands {
|
||||
CMD_GO_IDLE_STATE = 0,
|
||||
CMD_ALL_SEND_CID = 2,
|
||||
CMD_SET_RELATIVE_ADDR = 3,
|
||||
CMD_SELECT = 7,
|
||||
CMD_SEND_CSD = 9,
|
||||
CMD_SEND_CID = 10,
|
||||
CMD_SET_SECTOR_SIZE = 16,
|
||||
CMD_READ_SINGLE_BLOCK = 17,
|
||||
CMD_WRITE_SINGLE_BLOCK = 24,
|
||||
CMD_SD_SEND_OP_COND = 41,
|
||||
CMD_APP_CMD = 55,
|
||||
};
|
||||
|
||||
struct pl181_registers {
|
||||
uint32_t power;
|
||||
uint32_t clock;
|
||||
uint32_t arg;
|
||||
uint32_t cmd;
|
||||
uint32_t resp_cmd;
|
||||
uint32_t response[4];
|
||||
uint32_t data_timer;
|
||||
uint32_t data_length;
|
||||
uint32_t data_control;
|
||||
uint32_t data_count;
|
||||
uint32_t status;
|
||||
uint32_t clear;
|
||||
uint32_t interrupt_mask[2];
|
||||
uint32_t interrupt_select;
|
||||
uint32_t fifo_count;
|
||||
char res[0x34];
|
||||
uint32_t fifo_data[16];
|
||||
// TO BE CONTINUED
|
||||
};
|
||||
typedef struct pl181_registers pl181_registers_t;
|
||||
|
||||
struct sd_card {
|
||||
uint32_t rca;
|
||||
uint32_t ishc;
|
||||
uint32_t capacity;
|
||||
};
|
||||
typedef struct sd_card sd_card_t;
|
||||
|
||||
int pl181_init(drive_desc_t* drive_desc);
|
||||
|
||||
#endif // _BOOT_DRIVERS_PL181_H
|
||||
23
boot/arm32/drivers/uart.c
Normal file
23
boot/arm32/drivers/uart.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "uart.h"
|
||||
#include <libboot/devtree/devtree.h>
|
||||
|
||||
volatile uint32_t* output = NULL;
|
||||
|
||||
void uart_init()
|
||||
{
|
||||
devtree_entry_t* dev = devtree_find_device("uart");
|
||||
if (!dev) {
|
||||
while (1) { };
|
||||
}
|
||||
output = (uint32_t*)(uint32_t)dev->region_base;
|
||||
}
|
||||
|
||||
int uart_write(uint8_t data)
|
||||
{
|
||||
if (!output) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
*output = data;
|
||||
return 0;
|
||||
}
|
||||
9
boot/arm32/drivers/uart.h
Normal file
9
boot/arm32/drivers/uart.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef _BOOT_DRIVERS_UART_H
|
||||
#define _BOOT_DRIVERS_UART_H
|
||||
|
||||
#include <libboot/types.h>
|
||||
|
||||
void uart_init();
|
||||
int uart_write(uint8_t data);
|
||||
|
||||
#endif // _BOOT_DRIVERS_UART_H
|
||||
30
boot/arm32/entry.s
Normal file
30
boot/arm32/entry.s
Normal file
@@ -0,0 +1,30 @@
|
||||
.extern _start
|
||||
.extern _start_secondary_cpu
|
||||
|
||||
.section ".xos_boot_text"
|
||||
xos_loader:
|
||||
ldr sp, =STACK_PHYZ_TOP
|
||||
|
||||
mrc p15, #0, r0, c0, c0, #5 // Read CPU ID register.
|
||||
and r0, r0, #3
|
||||
cmp r0, #0
|
||||
bne secondary_cpu_loader
|
||||
|
||||
ldr r0, =_start
|
||||
mov pc, r0
|
||||
|
||||
secondary_cpu_loader:
|
||||
ldr sp, =STACK_SECONDARY_PHYZ_TOP
|
||||
mov r9, #512
|
||||
mrc p15, #0, r8, c0, c0, #5 // Read CPU ID register.
|
||||
and r8, r8, #3
|
||||
1:
|
||||
sub r8, r8, #1
|
||||
cmp r8, #0
|
||||
beq secondary_cpu_loader_exit
|
||||
add r9, r9, #512
|
||||
b 1b
|
||||
secondary_cpu_loader_exit:
|
||||
subs sp, r9
|
||||
ldr r0, =_start_secondary_cpu
|
||||
mov pc, r0
|
||||
13
boot/arm32/hw/ram.c
Normal file
13
boot/arm32/hw/ram.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "ram.h"
|
||||
#include <libboot/devtree/devtree.h>
|
||||
#include <libboot/log/log.h>
|
||||
|
||||
size_t hw_ram_get_size()
|
||||
{
|
||||
devtree_entry_t* dev = devtree_find_device("ram");
|
||||
if (!dev) {
|
||||
log("Can't find RAM in devtree");
|
||||
while (1) { };
|
||||
}
|
||||
return dev->region_size;
|
||||
}
|
||||
8
boot/arm32/hw/ram.h
Normal file
8
boot/arm32/hw/ram.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef _BOOT_HW_RAM_H
|
||||
#define _BOOT_HW_RAM_H
|
||||
|
||||
#include <libboot/types.h>
|
||||
|
||||
size_t hw_ram_get_size();
|
||||
|
||||
#endif //_BOOT_HW_RAM_H
|
||||
153
boot/arm32/main.c
Normal file
153
boot/arm32/main.c
Normal file
@@ -0,0 +1,153 @@
|
||||
#include "drivers/pl181.h"
|
||||
#include "drivers/uart.h"
|
||||
#include "vmm/vmm.h"
|
||||
#include <libboot/crypto/sha256.h>
|
||||
#include <libboot/crypto/signature.h>
|
||||
#include <libboot/crypto/uint2048.h>
|
||||
#include <libboot/crypto/validate.h>
|
||||
#include <libboot/devtree/devtree.h>
|
||||
#include <libboot/elf/elf_lite.h>
|
||||
#include <libboot/fs/ext2_lite.h>
|
||||
#include <libboot/log/log.h>
|
||||
#include <libboot/mem/alloc.h>
|
||||
#include <libboot/mem/mem.h>
|
||||
|
||||
// #define DEBUG_BOOT
|
||||
#define KERNEL_PATH "/boot/kernel.bin"
|
||||
#define LAUNCH_SERVER_PATH "/System/launch_server"
|
||||
|
||||
extern void jump_to_kernel(void*);
|
||||
extern uint32_t _odt_phys[];
|
||||
extern uint32_t _odt_phys_end[];
|
||||
|
||||
static void* bootdesc_ptr;
|
||||
static size_t kernel_vaddr = 0;
|
||||
static size_t kernel_paddr = 0;
|
||||
static size_t kernel_size = 0;
|
||||
static int sync = 0;
|
||||
|
||||
static int alloc_init()
|
||||
{
|
||||
devtree_entry_t* dev = devtree_find_device("ram");
|
||||
if (!dev) {
|
||||
log("Can't find RAM in devtree");
|
||||
while (1) { };
|
||||
}
|
||||
|
||||
extern int bootloader_start[];
|
||||
size_t alloc_space = (size_t)bootloader_start - dev->region_base;
|
||||
malloc_init((void*)(uint32_t)dev->region_base, alloc_space);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static memory_boot_desc_t memory_boot_desc_init()
|
||||
{
|
||||
devtree_entry_t* dev = devtree_find_device("ram");
|
||||
if (!dev) {
|
||||
log("Can't find RAM in devtree");
|
||||
while (1) { };
|
||||
}
|
||||
|
||||
char dummy_data = 0x0;
|
||||
memory_boot_desc_t res;
|
||||
memory_layout_t* mem_layout_paddr = copy_after_kernel(kernel_paddr, &dummy_data, sizeof(dummy_data), &kernel_size, VMM_PAGE_SIZE);
|
||||
|
||||
// Init of trailing element.
|
||||
mem_layout_paddr[0].flags = MEMORY_LAYOUT_FLAG_TERMINATE;
|
||||
memory_layout_t* mem_layout_vaddr = paddr_to_vaddr(mem_layout_paddr, kernel_paddr, kernel_vaddr);
|
||||
#ifdef DEBUG_BOOT
|
||||
log("initing MEMLAYOUT %lx of %d elems", mem_layout_vaddr, memory_layout_size);
|
||||
#endif
|
||||
|
||||
res.ram_base = dev->region_base;
|
||||
res.ram_size = dev->region_size;
|
||||
res.reserved_areas = mem_layout_vaddr;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int prepare_boot_disk(drive_desc_t* drive_desc)
|
||||
{
|
||||
pl181_init(drive_desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int prepare_fs(drive_desc_t* drive_desc, fs_desc_t* fs_desc)
|
||||
{
|
||||
if (ext2_lite_init(drive_desc, fs_desc) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int validate_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc)
|
||||
{
|
||||
log("Validating Kernel...");
|
||||
if (!validate_elf(KERNEL_PATH, drive_desc, fs_desc)) {
|
||||
log("Can't validate kernel");
|
||||
while (1) { }
|
||||
}
|
||||
|
||||
if (!validate_elf(LAUNCH_SERVER_PATH, drive_desc, fs_desc)) {
|
||||
log("Can't validate launch_server");
|
||||
while (1) { }
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void load_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc)
|
||||
{
|
||||
int res = elf_load_kernel(drive_desc, fs_desc, KERNEL_PATH, &kernel_vaddr, &kernel_paddr, &kernel_size);
|
||||
kernel_size = align_size(kernel_size, VMM_PAGE_SIZE);
|
||||
#ifdef DEBUG_BOOT
|
||||
log("kernel %x %x %x", kernel_vaddr, kernel_paddr, kernel_size);
|
||||
#endif
|
||||
|
||||
void* odt_ptr = paddr_to_vaddr(copy_after_kernel(kernel_paddr, devtree_start(), devtree_size(), &kernel_size, VMM_PAGE_SIZE), kernel_paddr, kernel_vaddr);
|
||||
#ifdef DEBUG_BOOT
|
||||
log("copying ODT %x -> %x of %d", devtree_start(), odt_ptr, devtree_size());
|
||||
#endif
|
||||
|
||||
size_t kernel_data_size = kernel_size + align_size(sizeof(boot_args_t), VMM_PAGE_SIZE) + VMM_PAGE_SIZE;
|
||||
|
||||
boot_args_t boot_args;
|
||||
boot_args.vaddr = kernel_vaddr;
|
||||
boot_args.paddr = kernel_paddr;
|
||||
boot_args.kernel_data_size = kernel_data_size;
|
||||
boot_args.devtree = odt_ptr;
|
||||
boot_args.mem_boot_desc = memory_boot_desc_init();
|
||||
memcpy(boot_args.init_process, LAUNCH_SERVER_PATH, sizeof(LAUNCH_SERVER_PATH));
|
||||
|
||||
bootdesc_ptr = paddr_to_vaddr(copy_after_kernel(kernel_paddr, &boot_args, sizeof(boot_args), &kernel_size, VMM_PAGE_SIZE), kernel_paddr, kernel_vaddr);
|
||||
#ifdef DEBUG_BOOT
|
||||
log("copying BOOTDESC %x -> %x of %d", &boot_args, bootdesc_ptr, sizeof(boot_args));
|
||||
#endif
|
||||
}
|
||||
|
||||
void load_boot_cpu()
|
||||
{
|
||||
devtree_init((void*)_odt_phys, (uint32_t)_odt_phys_end - (uint32_t)_odt_phys);
|
||||
uart_init();
|
||||
log_init(uart_write);
|
||||
alloc_init();
|
||||
|
||||
drive_desc_t drive_desc;
|
||||
fs_desc_t fs_desc;
|
||||
prepare_boot_disk(&drive_desc);
|
||||
prepare_fs(&drive_desc, &fs_desc);
|
||||
validate_kernel(&drive_desc, &fs_desc);
|
||||
load_kernel(&drive_desc, &fs_desc);
|
||||
vm_setup(kernel_vaddr, kernel_paddr, kernel_size);
|
||||
|
||||
__atomic_store_n(&sync, 1, __ATOMIC_RELEASE);
|
||||
jump_to_kernel(bootdesc_ptr);
|
||||
}
|
||||
|
||||
void load_secondary_cpu()
|
||||
{
|
||||
while (__atomic_load_n(&sync, __ATOMIC_ACQUIRE) == 0) {
|
||||
continue;
|
||||
}
|
||||
vm_setup_secondary_cpu();
|
||||
jump_to_kernel(bootdesc_ptr);
|
||||
}
|
||||
25
boot/arm32/start_kernel.s
Normal file
25
boot/arm32/start_kernel.s
Normal file
@@ -0,0 +1,25 @@
|
||||
.extern load_boot_cpu
|
||||
.extern load_secondary_cpu
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
ldr r0, =load_boot_cpu
|
||||
mov pc, r0
|
||||
1:
|
||||
b 1b
|
||||
.size _start, . - _start
|
||||
|
||||
.global _start_secondary_cpu
|
||||
_start_secondary_cpu:
|
||||
ldr r0, =load_secondary_cpu
|
||||
mov pc, r0
|
||||
2:
|
||||
b 2b
|
||||
|
||||
.global jump_to_kernel
|
||||
jump_to_kernel:
|
||||
isb
|
||||
mov r5, #0xc0000000
|
||||
mov pc, r5
|
||||
3:
|
||||
b 3b
|
||||
17
boot/arm32/vmm/consts.h
Normal file
17
boot/arm32/vmm/consts.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef _BOOT_VMM_CONSTS_H
|
||||
#define _BOOT_VMM_CONSTS_H
|
||||
|
||||
#define VMM_LV0_ENTITY_COUNT (256)
|
||||
#define VMM_LV1_ENTITY_COUNT (4096)
|
||||
#define VMM_PAGE_SIZE (4096)
|
||||
|
||||
#define VMM_OFFSET_IN_DIRECTORY(a) (((a) >> 20) & 0xfff)
|
||||
#define VMM_OFFSET_IN_TABLE(a) (((a) >> 12) & 0xff)
|
||||
#define VMM_OFFSET_IN_PAGE(a) ((a)&0xfff)
|
||||
#define TABLE_START(vaddr) ((vaddr >> 20) << 20)
|
||||
#define PAGE_START(vaddr) ((vaddr >> 12) << 12)
|
||||
#define FRAME(addr) (addr / VMM_PAGE_SIZE)
|
||||
|
||||
#define PTABLE_TOP_KERNEL_OFFSET 3072
|
||||
|
||||
#endif //_BOOT_VMM_CONSTS_H
|
||||
147
boot/arm32/vmm/vmm.c
Normal file
147
boot/arm32/vmm/vmm.c
Normal file
@@ -0,0 +1,147 @@
|
||||
#include "vmm.h"
|
||||
#include <libboot/log/log.h>
|
||||
#include <libboot/mem/alloc.h>
|
||||
#include <libboot/mem/mem.h>
|
||||
#include <libboot/types.h>
|
||||
|
||||
// #define DEBUG_VMM
|
||||
|
||||
#define VMM_OFFSET_IN_DIRECTORY(a) (((a) >> 20) & 0xfff)
|
||||
#define VMM_OFFSET_IN_TABLE(a) (((a) >> 12) & 0xff)
|
||||
#define VMM_OFFSET_IN_PAGE(a) ((a)&0xfff)
|
||||
#define ALIGN_TO_TABLE(a) ((a)&0xfff00000)
|
||||
|
||||
static pdirectory_t* pdir = NULL;
|
||||
|
||||
static ptable_t* map_table(size_t tphyz, size_t tvirt);
|
||||
static void mmu_enable();
|
||||
|
||||
static inline void write_ttbcr(uint32_t val)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c2, c0, 2"
|
||||
:
|
||||
: "r"(val)
|
||||
: "memory");
|
||||
asm volatile("dmb");
|
||||
}
|
||||
|
||||
static inline void write_ttbr0(uint32_t val)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c2, c0, 0"
|
||||
:
|
||||
: "r"(val)
|
||||
: "memory");
|
||||
asm volatile("dmb");
|
||||
}
|
||||
|
||||
static inline void write_dacr(uint32_t val)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c3, c0, 0"
|
||||
:
|
||||
: "r"(val));
|
||||
asm volatile("dmb");
|
||||
}
|
||||
|
||||
static void mmu_enable()
|
||||
{
|
||||
volatile uint32_t val;
|
||||
asm volatile("mrc p15, 0, %0, c1, c0, 0"
|
||||
: "=r"(val));
|
||||
asm volatile("orr %0, %1, #0x1"
|
||||
: "=r"(val)
|
||||
: "r"(val));
|
||||
asm volatile("mcr p15, 0, %0, c1, c0, 0" ::"r"(val)
|
||||
: "memory");
|
||||
asm volatile("isb");
|
||||
}
|
||||
|
||||
static pdirectory_t* vm_alloc_pdir()
|
||||
{
|
||||
return (pdirectory_t*)malloc_aligned(sizeof(pdirectory_t), sizeof(pdirectory_t));
|
||||
}
|
||||
|
||||
static ptable_t* vm_alloc_ptable()
|
||||
{
|
||||
return (ptable_t*)malloc_aligned(sizeof(ptable_t), sizeof(ptable_t));
|
||||
}
|
||||
|
||||
static ptable_t* map_table(size_t tphyz, size_t tvirt)
|
||||
{
|
||||
ptable_t* table = vm_alloc_ptable();
|
||||
for (size_t phyz = tphyz, virt = tvirt, i = 0; i < VMM_LV0_ENTITY_COUNT; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) {
|
||||
page_desc_t new_page;
|
||||
new_page.one = 1;
|
||||
new_page.baddr = (phyz / VMM_PAGE_SIZE);
|
||||
new_page.tex = 0b001;
|
||||
new_page.c = 1;
|
||||
new_page.b = 1;
|
||||
new_page.ap1 = 0b11;
|
||||
new_page.ap2 = 0b0;
|
||||
new_page.s = 1;
|
||||
table->entities[i] = new_page;
|
||||
}
|
||||
|
||||
uint32_t table_int = (uint32_t)table;
|
||||
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].valid = 1;
|
||||
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].zero1 = 0;
|
||||
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].zero2 = 0;
|
||||
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].ns = 0;
|
||||
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].zero3 = 0;
|
||||
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].domain = 0b0011;
|
||||
pdir->entities[VMM_OFFSET_IN_DIRECTORY(tvirt)].baddr = ((table_int / 1024));
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
static void vm_init()
|
||||
{
|
||||
pdir = vm_alloc_pdir();
|
||||
|
||||
for (int i = 0; i < VMM_LV1_ENTITY_COUNT; i++) {
|
||||
pdir->entities[i].valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void vm_map_devices()
|
||||
{
|
||||
map_table(0x1c000000, 0x1c000000); // mapping uart
|
||||
}
|
||||
|
||||
void vm_setup(size_t kernel_vaddr, size_t kernel_paddr, size_t kernel_size)
|
||||
{
|
||||
vm_init();
|
||||
vm_map_devices();
|
||||
|
||||
extern int bootloader_start[];
|
||||
size_t bootloader_start_aligned = ALIGN_TO_TABLE((size_t)bootloader_start);
|
||||
map_table(bootloader_start_aligned, bootloader_start_aligned);
|
||||
#ifdef DEBUG_VMM
|
||||
log("map %x to %x", bootloader_start_aligned, bootloader_start_aligned);
|
||||
#endif
|
||||
|
||||
size_t table_paddr = ALIGN_TO_TABLE(kernel_paddr);
|
||||
size_t table_vaddr = ALIGN_TO_TABLE(kernel_vaddr);
|
||||
const size_t bytes_per_table = VMM_LV0_ENTITY_COUNT * VMM_PAGE_SIZE;
|
||||
const size_t tables_per_kernel = align_size((kernel_size + bytes_per_table - 1) / bytes_per_table, 4);
|
||||
for (int i = 0; i < tables_per_kernel; i++) {
|
||||
map_table(table_paddr, table_paddr);
|
||||
map_table(table_paddr, table_vaddr);
|
||||
#ifdef DEBUG_VMM
|
||||
log("map %x to %x", table_paddr, table_paddr);
|
||||
log("map %x to %x", table_paddr, table_vaddr);
|
||||
#endif
|
||||
table_paddr += bytes_per_table;
|
||||
table_vaddr += bytes_per_table;
|
||||
}
|
||||
|
||||
write_ttbr0((size_t)(pdir));
|
||||
write_dacr(0x55555555);
|
||||
mmu_enable();
|
||||
}
|
||||
|
||||
void vm_setup_secondary_cpu()
|
||||
{
|
||||
write_ttbr0((uint32_t)(pdir));
|
||||
write_dacr(0x55555555);
|
||||
mmu_enable();
|
||||
}
|
||||
54
boot/arm32/vmm/vmm.h
Normal file
54
boot/arm32/vmm/vmm.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef _BOOT_VMM_VMM_H
|
||||
#define _BOOT_VMM_VMM_H
|
||||
|
||||
#include "consts.h"
|
||||
#include <libboot/types.h>
|
||||
|
||||
struct PACKED page_desc {
|
||||
union {
|
||||
struct {
|
||||
unsigned int xn : 1; // Execute never. Stops execution of page.
|
||||
unsigned int one : 1; // Always one for tables
|
||||
unsigned int b : 1; // cacheable
|
||||
unsigned int c : 1; // Cacheable
|
||||
unsigned int ap1 : 2;
|
||||
unsigned int tex : 3;
|
||||
unsigned int ap2 : 1;
|
||||
unsigned int s : 1;
|
||||
unsigned int ng : 1;
|
||||
unsigned int baddr : 20;
|
||||
};
|
||||
uint32_t data;
|
||||
};
|
||||
};
|
||||
typedef struct page_desc page_desc_t;
|
||||
|
||||
struct PACKED table_desc {
|
||||
union {
|
||||
struct {
|
||||
int valid : 1; /* Valid mapping */
|
||||
int zero1 : 1;
|
||||
int zero2 : 1;
|
||||
int ns : 1;
|
||||
int zero3 : 1;
|
||||
int domain : 4;
|
||||
int imp : 1;
|
||||
int baddr : 22;
|
||||
};
|
||||
uint32_t data;
|
||||
};
|
||||
};
|
||||
typedef struct table_desc table_desc_t;
|
||||
|
||||
typedef struct {
|
||||
page_desc_t entities[VMM_LV0_ENTITY_COUNT];
|
||||
} ptable_t;
|
||||
|
||||
typedef struct pdirectory {
|
||||
table_desc_t entities[VMM_LV1_ENTITY_COUNT];
|
||||
} pdirectory_t;
|
||||
|
||||
void vm_setup(size_t kernel_vaddr, size_t kernel_paddr, size_t kernel_size);
|
||||
void vm_setup_secondary_cpu();
|
||||
|
||||
#endif // _BOOT_VMM_VMM_H
|
||||
Reference in New Issue
Block a user