rpi400: initial platform support
This commit is contained in:
parent
e90278b04b
commit
116ee0a803
|
@ -33,3 +33,5 @@
|
|||
/boot/mbr.sys
|
||||
/bootstub
|
||||
/.arch
|
||||
/kernel8.img
|
||||
/kernel8.img.elf
|
||||
|
|
|
@ -5,7 +5,7 @@ ARCH_KERNEL_CFLAGS = -z max-page-size=0x1000 -nostdlib -mgeneral-regs-only -mno-
|
|||
TARGET=aarch64-unknown-toaru
|
||||
|
||||
all: system
|
||||
system: misaka-kernel ramdisk.igz bootstub | $(BUILD_KRK)
|
||||
system: misaka-kernel ramdisk.igz bootstub kernel8.img | $(BUILD_KRK)
|
||||
|
||||
misaka-kernel: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o kernel/arch/aarch64/link.ld
|
||||
${CC} -g -T kernel/arch/${ARCH}/link.ld ${KERNEL_CFLAGS} -o $@ ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o
|
||||
|
@ -15,7 +15,17 @@ BOOTSTUB_OBJS += $(patsubst %.S,%.o,$(wildcard kernel/arch/aarch64/bootstub/*.S)
|
|||
BOOTSTUB_OBJS += kernel/misc/kprintf.o kernel/misc/string.o
|
||||
|
||||
bootstub: ${BOOTSTUB_OBJS} kernel/arch/aarch64/bootstub/link.ld
|
||||
${CC} -g -T kernel/arch/aarch64/bootstub/link.ld ${KERNEL_CFLAGS} -o $@ ${BOOTSTUB_OBJS} -lgcc
|
||||
${CC} -g -T kernel/arch/aarch64/bootstub/link.ld ${KERNEL_CFLAGS} -o $@ ${BOOTSTUB_OBJS}
|
||||
|
||||
|
||||
RPI400_OBJS = $(patsubst %.c,%.o,$(wildcard kernel/arch/aarch64/rpi400/*.c))
|
||||
RPI400_OBJS += $(patsubst %.S,%.o,$(wildcard kernel/arch/aarch64/rpi400/*.S))
|
||||
RPI400_OBJS += kernel/misc/kprintf.o kernel/misc/string.o
|
||||
|
||||
kernel/arch/aarch64/rpi400/start.o: misaka-kernel ramdisk.igz
|
||||
kernel8.img: ${RPI400_OBJS} kernel/arch/aarch64/rpi400/link.ld
|
||||
${CC} -g -T kernel/arch/aarch64/rpi400/link.ld ${KERNEL_CFLAGS} -o $@.elf ${RPI400_OBJS}
|
||||
${OC} $@.elf -O binary $@
|
||||
|
||||
QEMU = qemu-system-aarch64
|
||||
|
||||
|
|
|
@ -437,8 +437,8 @@ static void bootstub_start_kernel(Elf64_Header * header) {
|
|||
printf("bootstub: Jump to kernel entry point at %zx\n",
|
||||
header->e_entry);
|
||||
|
||||
void (*entry)(uintptr_t,uintptr_t) = (void(*)(uintptr_t,uintptr_t))header->e_entry;
|
||||
entry(QEMU_DTB_BASE, KERNEL_PHYS_BASE);
|
||||
void (*entry)(uintptr_t,uintptr_t,uintptr_t) = (void(*)(uintptr_t,uintptr_t,uintptr_t))header->e_entry;
|
||||
entry(QEMU_DTB_BASE, KERNEL_PHYS_BASE, 0);
|
||||
}
|
||||
|
||||
int kmain(void) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <kernel/misc.h>
|
||||
#include <kernel/ptrace.h>
|
||||
#include <kernel/ksym.h>
|
||||
#include <kernel/gzip.h>
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
|
@ -82,7 +83,7 @@ size_t arch_cpu_mhz(void) {
|
|||
static void arch_clock_initialize() {
|
||||
|
||||
/* QEMU RTC */
|
||||
void * clock_addr = mmu_map_from_physical(0x09010000);
|
||||
//void * clock_addr = mmu_map_from_physical(0x09010000);
|
||||
|
||||
/* Get frequency of system timer */
|
||||
uint64_t val;
|
||||
|
@ -90,7 +91,8 @@ static void arch_clock_initialize() {
|
|||
sys_timer_freq = val / 10000;
|
||||
|
||||
/* Get boot time from RTC */
|
||||
arch_boot_time = *(volatile uint32_t*)clock_addr;
|
||||
//arch_boot_time = *(volatile uint32_t*)clock_addr;
|
||||
arch_boot_time = 1644908027UL;
|
||||
|
||||
/* Get the "basis time" - the perf timestamp we got the wallclock time at */
|
||||
basis_time = arch_perf_timer() / sys_timer_freq;
|
||||
|
@ -143,9 +145,11 @@ void relative_time(unsigned long seconds, unsigned long subseconds, unsigned lon
|
|||
static void set_tick(void) {
|
||||
asm volatile (
|
||||
"mrs x0, CNTFRQ_EL0\n"
|
||||
"mov x1, 100\n"
|
||||
"mov x1, 100\n" // without this, one second
|
||||
"udiv x0, x0, x1\n"
|
||||
"msr CNTV_TVAL_EL0, x0\n"
|
||||
"mov x0, 1\n"
|
||||
"msr CNTV_CTL_EL0, x0\n"
|
||||
:::"x0","x1");
|
||||
}
|
||||
|
||||
|
@ -156,11 +160,6 @@ void timer_start(void) {
|
|||
/* Enable the local timer */
|
||||
set_tick();
|
||||
|
||||
asm volatile (
|
||||
"mov x0, 1\n"
|
||||
"msr CNTV_CTL_EL0, x0\n"
|
||||
:::"x0");
|
||||
|
||||
/* This is global, we only need to do this once... */
|
||||
gic_regs[0] = 1;
|
||||
|
||||
|
@ -253,15 +252,22 @@ static void dtb_locate_cmdline(void) {
|
|||
static void exception_handlers(void) {
|
||||
extern char _exception_vector[];
|
||||
|
||||
const uintptr_t gic_base = (uintptr_t)mmu_map_from_physical(0x08000000); /* TODO get this from dtb */
|
||||
gic_regs = (volatile uint32_t*)gic_base;
|
||||
|
||||
const uintptr_t gicc_base = (uintptr_t)mmu_map_from_physical(0x08010000);
|
||||
gicc_regs = (volatile uint32_t*)gicc_base;
|
||||
|
||||
asm volatile("msr VBAR_EL1, %0" :: "r"(&_exception_vector));
|
||||
}
|
||||
|
||||
#if 0
|
||||
#define GICD_BASE 0x08000000
|
||||
#define GICC_BASE 0x08010000
|
||||
#else
|
||||
#define GICD_BASE 0xff841000
|
||||
#define GICC_BASE 0xff842000
|
||||
#endif
|
||||
|
||||
static void gic_map_regs(void) {
|
||||
gic_regs = (volatile uint32_t*)mmu_map_mmio_region(GICD_BASE, 0x1000);
|
||||
gicc_regs = (volatile uint32_t*)mmu_map_mmio_region(GICC_BASE, 0x2000);
|
||||
}
|
||||
|
||||
void aarch64_sync_enter(struct regs * r) {
|
||||
uint64_t esr, far, elr, spsr;
|
||||
asm volatile ("mrs %0, ESR_EL1" : "=r"(esr));
|
||||
|
@ -269,6 +275,20 @@ void aarch64_sync_enter(struct regs * r) {
|
|||
asm volatile ("mrs %0, ELR_EL1" : "=r"(elr));
|
||||
asm volatile ("mrs %0, SPSR_EL1" : "=r"(spsr));
|
||||
|
||||
#if 0
|
||||
dprintf("EL0-EL1 sync: %d (%s) ESR: %#zx FAR: %#zx ELR: %#zx SPSR: %#zx\n",
|
||||
this_core ? (this_core->current_process ? this_core->current_process->id : -1) : -1,
|
||||
this_core ? (this_core->current_process ? this_core->current_process->name : "?") : "?",
|
||||
esr, far, elr, spsr);
|
||||
#endif
|
||||
|
||||
if (esr == 0x2000000) {
|
||||
dprintf("Unknown exception: ESR: %#zx FAR: %#zx ELR: %#zx SPSR: %#zx\n", esr, far, elr, spsr);
|
||||
dprintf("Instruction at ELR: 0x%08x\n", *(uint32_t*)elr);
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
if (this_core->current_process) {
|
||||
this_core->current_process->time_switch = arch_perf_timer();
|
||||
}
|
||||
|
@ -301,6 +321,8 @@ void aarch64_sync_enter(struct regs * r) {
|
|||
|
||||
/* System call */
|
||||
if ((esr >> 26) == 0x15) {
|
||||
//dprintf("pid %d syscall %zd elr=%#zx\n",
|
||||
// this_core->current_process->id, r->x0, elr);
|
||||
extern void syscall_handler(struct regs *);
|
||||
syscall_handler(r);
|
||||
return;
|
||||
|
@ -320,16 +342,20 @@ void aarch64_sync_enter(struct regs * r) {
|
|||
asm volatile ("mrs %0, TPIDR_EL0" : "=r"(tpidr_el0));
|
||||
dprintf(" TPIDR_EL0=%#zx\n", tpidr_el0);
|
||||
|
||||
while (1);
|
||||
|
||||
send_signal(this_core->current_process->id, SIGSEGV, 1);
|
||||
}
|
||||
|
||||
char _ret_from_preempt_source[1];
|
||||
|
||||
#define EOI(x) do { gicc_regs[4] = (x); } while (0)
|
||||
#define EOI(x) do { \
|
||||
gicc_regs[4] = (x); \
|
||||
} while (0)
|
||||
static void aarch64_interrupt_dispatch(int from_wfi) {
|
||||
uint32_t iar = gicc_regs[3];
|
||||
uint32_t irq = iar & 0x3FF;
|
||||
//uint32_t cpu = (iar >> 10) & 0x7;
|
||||
uint32_t cpu = (iar >> 10) & 0x7;
|
||||
|
||||
switch (irq) {
|
||||
case TIMER_IRQ:
|
||||
|
@ -400,7 +426,9 @@ void aarch64_fault_enter(struct regs * r) {
|
|||
asm volatile ("mrs %0, SPSR_EL1" : "=r"(spsr));
|
||||
|
||||
dprintf("EL1-EL1 fault handler, core %d\n", this_core->cpu_id);
|
||||
dprintf("In process %d (%s)\n", this_core->current_process->id, this_core->current_process->name);
|
||||
if (this_core && this_core->current_process) {
|
||||
dprintf("In process %d (%s)\n", this_core->current_process->id, this_core->current_process->name);
|
||||
}
|
||||
dprintf("ESR: %#zx FAR: %#zx ELR: %#zx SPSR: %#zx\n", esr, far, elr, spsr);
|
||||
aarch64_regs(r);
|
||||
|
||||
|
@ -414,6 +442,11 @@ void aarch64_fault_enter(struct regs * r) {
|
|||
while (1);
|
||||
}
|
||||
|
||||
void aarch64_sp0_fault_enter(struct regs * r) {
|
||||
dprintf("EL1-EL1 sp0 entry?\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable FPU and NEON (SIMD)
|
||||
*
|
||||
|
@ -437,6 +470,7 @@ void arch_pause(void) {
|
|||
* the interrupt function won't be called, so we'll need to change
|
||||
* it once we start getting actual hardware interrupts. */
|
||||
asm volatile ("wfi");
|
||||
|
||||
aarch64_interrupt_dispatch(1);
|
||||
}
|
||||
|
||||
|
@ -476,6 +510,17 @@ static void symbols_install(void) {
|
|||
}
|
||||
}
|
||||
|
||||
struct rpitag {
|
||||
uint32_t phys_addr;
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
uint32_t s;
|
||||
uint32_t b;
|
||||
uint32_t size;
|
||||
uint32_t ramdisk_start;
|
||||
uint32_t ramdisk_end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Main kernel C entrypoint for qemu's -machine virt
|
||||
*
|
||||
|
@ -485,10 +530,7 @@ static void symbols_install(void) {
|
|||
* at -2GiB, and there's some other mappings so that
|
||||
* a bit of RAM is 1:1.
|
||||
*/
|
||||
int kmain(uintptr_t dtb_base, uintptr_t phys_base) {
|
||||
early_log_initialize();
|
||||
|
||||
console_set_output(_early_log_write);
|
||||
int kmain(uintptr_t dtb_base, uintptr_t phys_base, uintptr_t rpi_tag) {
|
||||
|
||||
extern uintptr_t aarch64_kernel_phys_base;
|
||||
aarch64_kernel_phys_base = phys_base;
|
||||
|
@ -496,6 +538,29 @@ int kmain(uintptr_t dtb_base, uintptr_t phys_base) {
|
|||
extern uintptr_t aarch64_dtb_phys;
|
||||
aarch64_dtb_phys = dtb_base;
|
||||
|
||||
if (rpi_tag) {
|
||||
extern uint8_t * lfb_vid_memory;
|
||||
extern uint16_t lfb_resolution_x;
|
||||
extern uint16_t lfb_resolution_y;
|
||||
extern uint16_t lfb_resolution_b;
|
||||
extern uint32_t lfb_resolution_s;
|
||||
extern size_t lfb_memsize;
|
||||
|
||||
struct rpitag * tag = (struct rpitag*)rpi_tag;
|
||||
|
||||
lfb_vid_memory = mmu_map_from_physical(tag->phys_addr);
|
||||
lfb_resolution_x = tag->x;
|
||||
lfb_resolution_y = tag->y;
|
||||
lfb_resolution_s = tag->s;
|
||||
lfb_resolution_b = tag->b;
|
||||
lfb_memsize = tag->size;
|
||||
|
||||
fbterm_initialize();
|
||||
} else {
|
||||
early_log_initialize();
|
||||
console_set_output(_early_log_write);
|
||||
}
|
||||
|
||||
dprintf("%s %d.%d.%d-%s %s %s\n",
|
||||
__kernel_name,
|
||||
__kernel_version_major,
|
||||
|
@ -520,21 +585,61 @@ int kmain(uintptr_t dtb_base, uintptr_t phys_base) {
|
|||
/* Load ramdisk over fw-cfg. */
|
||||
uintptr_t ramdisk_phys_base = 0;
|
||||
size_t ramdisk_size = 0;
|
||||
fwcfg_load_initrd(&ramdisk_phys_base, &ramdisk_size);
|
||||
if (rpi_tag) {
|
||||
struct rpitag * tag = (struct rpitag*)rpi_tag;
|
||||
extern char end[];
|
||||
dprintf("rpi: compressed ramdisk is at %#x \n", tag->ramdisk_start);
|
||||
dprintf("rpi: end of ramdisk is at %#x \n", tag->ramdisk_end);
|
||||
dprintf("rpi: uncompress ramdisk to %#zx \n", (uintptr_t)&end);
|
||||
uint32_t size;
|
||||
memcpy(&size, (void*)(uintptr_t)(tag->ramdisk_end - sizeof(uint32_t)), sizeof(uint32_t));
|
||||
dprintf("rpi: size of uncompressed ramdisk is %#x\n", size);
|
||||
|
||||
/* Probe DTB for memory layout. */
|
||||
extern char end[];
|
||||
size_t memaddr, memsize;
|
||||
dtb_memory_size(&memaddr, &memsize);
|
||||
gzip_inputPtr = (uint8_t*)(uintptr_t)tag->ramdisk_start;
|
||||
gzip_outputPtr = (uint8_t*)&end;
|
||||
|
||||
/* Initialize the MMU based on the memory we got from dtb */
|
||||
mmu_init(
|
||||
memaddr, memsize,
|
||||
0x40100000 /* Should be end of DTB, but we're really just guessing */,
|
||||
(uintptr_t)&end + ramdisk_size - 0xffffffff80000000UL);
|
||||
if (gzip_decompress()) {
|
||||
dprintf("rpi: gzip failure, not mounting ramdisk\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
/* Find the cmdline */
|
||||
dtb_locate_cmdline();
|
||||
dprintf("rpi: ramdisk decompressed\n");
|
||||
|
||||
for (size_t i = 0; i < size; i += 64) {
|
||||
asm volatile ("dc cvac, %0\n" :: "r"((uintptr_t)&end + i) : "memory");
|
||||
}
|
||||
|
||||
ramdisk_phys_base = mmu_map_to_physical(NULL, (uintptr_t)&end);
|
||||
ramdisk_size = size;
|
||||
|
||||
dprintf("rpi: ramdisk_phys_base set to %#zx\n", ramdisk_phys_base);
|
||||
|
||||
mmu_init(0, 512 * 1024 * 1024,
|
||||
0x80000,
|
||||
(uintptr_t)&end + ramdisk_size - 0xffffffff80000000UL);
|
||||
|
||||
dprintf("rpi: mmu reinitialized\n");
|
||||
|
||||
_arch_args = "vid=preset start=live-session root=/dev/ram0";
|
||||
|
||||
} else {
|
||||
fwcfg_load_initrd(&ramdisk_phys_base, &ramdisk_size);
|
||||
/* Probe DTB for memory layout. */
|
||||
extern char end[];
|
||||
size_t memaddr, memsize;
|
||||
dtb_memory_size(&memaddr, &memsize);
|
||||
|
||||
/* Initialize the MMU based on the memory we got from dtb */
|
||||
mmu_init(
|
||||
memaddr, memsize,
|
||||
0x40100000 /* Should be end of DTB, but we're really just guessing */,
|
||||
(uintptr_t)&end + ramdisk_size - 0xffffffff80000000UL);
|
||||
|
||||
/* Find the cmdline */
|
||||
dtb_locate_cmdline();
|
||||
}
|
||||
|
||||
gic_map_regs();
|
||||
|
||||
/* Set up all the other arch-specific stuff here */
|
||||
fpu_enable();
|
||||
|
@ -545,7 +650,10 @@ int kmain(uintptr_t dtb_base, uintptr_t phys_base) {
|
|||
|
||||
/* Initialize the framebuffer and fbterm here */
|
||||
framebuffer_initialize();
|
||||
fbterm_initialize();
|
||||
|
||||
if (!rpi_tag) {
|
||||
fbterm_initialize();
|
||||
}
|
||||
|
||||
/* Ramdisk */
|
||||
ramdisk_mount(ramdisk_phys_base, ramdisk_size);
|
||||
|
@ -554,17 +662,20 @@ int kmain(uintptr_t dtb_base, uintptr_t phys_base) {
|
|||
aarch64_processor_data();
|
||||
|
||||
/* Start other cores here */
|
||||
aarch64_smp_start();
|
||||
//aarch64_smp_start();
|
||||
processor_count = 1;
|
||||
|
||||
/* Set up the system virtual timer to produce interrupts for userspace scheduling */
|
||||
timer_start();
|
||||
|
||||
#if 0
|
||||
/* Install drivers that may need to sleep here */
|
||||
virtio_input();
|
||||
|
||||
/* Set up serial input */
|
||||
extern void pl011_start(void);
|
||||
pl011_start();
|
||||
#endif
|
||||
|
||||
generic_main();
|
||||
|
||||
|
|
|
@ -0,0 +1,275 @@
|
|||
#include <stdint.h>
|
||||
#include <kernel/string.h>
|
||||
#include <kernel/printf.h>
|
||||
|
||||
static int fbterm_scroll = 0;
|
||||
static void (*write_char)(int, int, int, uint32_t) = NULL;
|
||||
static int (*get_width)(void) = NULL;
|
||||
static int (*get_height)(void) = NULL;
|
||||
static void (*scroll_terminal)(void) = NULL;
|
||||
|
||||
static int x = 0;
|
||||
static int y = 0;
|
||||
static int term_state = 0;
|
||||
static char term_buf[1024] = {0};
|
||||
static int term_buf_c = 0;
|
||||
|
||||
/* Is this in a header somewhere? */
|
||||
extern uint8_t * lfb_vid_memory;
|
||||
extern uint16_t lfb_resolution_x;
|
||||
extern uint16_t lfb_resolution_y;
|
||||
extern uint16_t lfb_resolution_b;
|
||||
extern uint32_t lfb_resolution_s;
|
||||
extern size_t lfb_memsize;
|
||||
|
||||
/* Bitmap font details */
|
||||
#include "../../../../apps/terminal-font.h"
|
||||
#define char_height LARGE_FONT_CELL_HEIGHT
|
||||
#define char_width LARGE_FONT_CELL_WIDTH
|
||||
|
||||
/* Default colors */
|
||||
#define BG_COLOR 0xFF000000 /* Background */
|
||||
#define FG_COLOR 0xFFCCCCCC /* Main text color */
|
||||
|
||||
static uint32_t fg_color = FG_COLOR;
|
||||
static uint32_t bg_color = BG_COLOR;
|
||||
|
||||
extern uint32_t lfb_resolution_s;
|
||||
|
||||
static inline void set_point(int x, int y, uint32_t value) {
|
||||
if (lfb_resolution_b == 32) {
|
||||
((uint32_t*)lfb_vid_memory)[y * (lfb_resolution_s/4) + x] = value;
|
||||
} else if (lfb_resolution_b == 24) {
|
||||
lfb_vid_memory[y * lfb_resolution_s + x * 3 + 0] = (value >> 0) & 0xFF;
|
||||
lfb_vid_memory[y * lfb_resolution_s + x * 3 + 1] = (value >> 8) & 0xFF;
|
||||
lfb_vid_memory[y * lfb_resolution_s + x * 3 + 2] = (value >> 16) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
static void fb_write_char(int _x, int _y, int val, uint32_t color) {
|
||||
if (val > 128) {
|
||||
val = 4;
|
||||
}
|
||||
|
||||
int x = 1 + _x * char_width;
|
||||
int y = _y * char_height;
|
||||
|
||||
uint16_t * c = large_font[val];
|
||||
for (uint8_t i = 0; i < char_height; ++i) {
|
||||
for (uint8_t j = 0; j < char_width; ++j) {
|
||||
if (c[i] & (1 << (LARGE_FONT_MASK-j))) {
|
||||
set_point(x+j,y+i,color);
|
||||
} else {
|
||||
set_point(x+j,y+i,bg_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic 16-color ANSI palette with Tango colors.
|
||||
*/
|
||||
static uint32_t term_colors[] = {
|
||||
0xFF000000,
|
||||
0xFFCC0000,
|
||||
0xFF4E9A06,
|
||||
0xFFC4A000,
|
||||
0xFF3465A4,
|
||||
0xFF75507B,
|
||||
0xFF06989A,
|
||||
0xFFD3D7CF,
|
||||
|
||||
0xFF555753,
|
||||
0xFFEF2929,
|
||||
0xFF8AE234,
|
||||
0xFFFCE94F,
|
||||
0xFF729FCF,
|
||||
0xFFAD7FA8,
|
||||
0xFF34E2E2,
|
||||
0xFFEEEEEC,
|
||||
};
|
||||
|
||||
static int fb_get_width(void) {
|
||||
return (lfb_resolution_x - 1) / char_width;
|
||||
}
|
||||
|
||||
static int fb_get_height(void) {
|
||||
return lfb_resolution_y / char_height;
|
||||
}
|
||||
|
||||
static void fb_scroll_terminal(void) {
|
||||
memmove(lfb_vid_memory, lfb_vid_memory + sizeof(uint32_t) * lfb_resolution_x * char_height, (lfb_resolution_y - char_height) * lfb_resolution_x * 4);
|
||||
memset(lfb_vid_memory + sizeof(uint32_t) * (lfb_resolution_y - char_height) * lfb_resolution_x, 0x00, char_height * lfb_resolution_x * 4);
|
||||
}
|
||||
|
||||
static void draw_square(int x, int y) {
|
||||
int center_x = lfb_resolution_x / 2;
|
||||
int center_y = lfb_resolution_y / 2;
|
||||
for (size_t _y = 0; _y < 7; ++_y) {
|
||||
uint32_t color = 0xFF00B2FF - (y * 8 + _y) * 0x200;
|
||||
for (size_t _x = 0; _x < 7; ++_x) {
|
||||
set_point(center_x - 32 + x * 8 + _x, center_y - 32 + y * 8 + _y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fbterm_draw_logo(void) {
|
||||
uint64_t logo_squares = 0x981818181818FFFFUL;
|
||||
for (size_t y = 0; y < 8; ++y) {
|
||||
for (size_t x = 0; x < 8; ++x) {
|
||||
if (logo_squares & (1 << x)) {
|
||||
draw_square(x,y);
|
||||
}
|
||||
}
|
||||
logo_squares >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void fbterm_init_framebuffer(void) {
|
||||
write_char = fb_write_char;
|
||||
get_width = fb_get_width;
|
||||
get_height = fb_get_height;
|
||||
scroll_terminal = fb_scroll_terminal;
|
||||
fbterm_draw_logo();
|
||||
}
|
||||
|
||||
static void cursor_update(void) {
|
||||
if (x >= get_width()) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
if (y >= get_height()) {
|
||||
if (fbterm_scroll) {
|
||||
y--;
|
||||
scroll_terminal();
|
||||
} else {
|
||||
y = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void process_char(char ch) {
|
||||
if (term_state == 1) {
|
||||
if (ch == '[') {
|
||||
term_buf_c = 0;
|
||||
term_buf[term_buf_c] = '\0';
|
||||
term_state = 2;
|
||||
} else {
|
||||
term_state = 0;
|
||||
process_char(ch);
|
||||
}
|
||||
return;
|
||||
} else if (term_state == 2) {
|
||||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
|
||||
/* do the thing */
|
||||
switch (ch) {
|
||||
case 'm': {
|
||||
char * arg = &term_buf[0];
|
||||
char * next;
|
||||
int argC = 0;
|
||||
int isBold = 0;
|
||||
do {
|
||||
next = strchr(arg, ';');
|
||||
if (next) { *next = '\0'; next++; }
|
||||
int asInt = atoi(arg);
|
||||
if (asInt == 0) {
|
||||
fg_color = FG_COLOR;
|
||||
bg_color = BG_COLOR;
|
||||
isBold = 0;
|
||||
} else if (asInt == 1) {
|
||||
isBold = 1;
|
||||
} else if (asInt == 22) {
|
||||
fg_color = FG_COLOR;
|
||||
isBold = 0;
|
||||
} else if (asInt >= 30 && asInt <= 37) {
|
||||
fg_color = term_colors[asInt-30 + (isBold ? 8 : 0)];
|
||||
} else if (asInt >= 90 && asInt <= 97) {
|
||||
fg_color = term_colors[asInt-90 + 8];
|
||||
} else if (asInt >= 40 && asInt <= 47) {
|
||||
bg_color = term_colors[asInt-40 + (isBold ? 8 : 0)];
|
||||
} else if (asInt >= 100 && asInt <= 107) {
|
||||
bg_color = term_colors[asInt-100 + 8];
|
||||
} else if (asInt == 38) {
|
||||
fg_color = FG_COLOR;
|
||||
} else if (asInt == 48) {
|
||||
bg_color = BG_COLOR;
|
||||
} else if (asInt == 7) {
|
||||
uint32_t tmp = fg_color;
|
||||
fg_color = bg_color;
|
||||
bg_color = tmp;
|
||||
}
|
||||
arg = next;
|
||||
argC++;
|
||||
} while (arg);
|
||||
break;
|
||||
}
|
||||
case 'G': {
|
||||
/* Set cursor column */
|
||||
x = atoi(term_buf) - 1;
|
||||
break;
|
||||
}
|
||||
case 'K': {
|
||||
if (atoi(term_buf) == 0) {
|
||||
for (int i = x; i < get_width(); ++i) {
|
||||
write_char(i,y,' ',bg_color);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
term_state = 0;
|
||||
} else {
|
||||
term_buf[term_buf_c++] = ch;
|
||||
term_buf[term_buf_c] = '\0';
|
||||
}
|
||||
return;
|
||||
} else if (ch == '\033') {
|
||||
term_state = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
write_char(x,y,' ',bg_color);
|
||||
switch (ch) {
|
||||
case '\n':
|
||||
x = 0;
|
||||
y++;
|
||||
break;
|
||||
case '\r':
|
||||
x = 0;
|
||||
break;
|
||||
case '\b':
|
||||
if (x) {
|
||||
x--;
|
||||
write_char(x,y,' ',fg_color);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ((unsigned int)ch > 127) return;
|
||||
write_char(x,y,ch,fg_color);
|
||||
x++;
|
||||
break;
|
||||
}
|
||||
cursor_update();
|
||||
}
|
||||
|
||||
static size_t (*previous_writer)(size_t,uint8_t*) = NULL;
|
||||
|
||||
size_t fbterm_write(size_t size, uint8_t *buffer) {
|
||||
if (!buffer) return 0;
|
||||
for (unsigned int i = 0; i < size; ++i) {
|
||||
process_char(buffer[i]);
|
||||
}
|
||||
if (previous_writer) previous_writer(size,buffer);
|
||||
return size;
|
||||
}
|
||||
|
||||
void fbterm_initialize(void) {
|
||||
if (!lfb_resolution_x) {
|
||||
return;
|
||||
}
|
||||
fbterm_init_framebuffer();
|
||||
previous_writer = printf_output;
|
||||
printf_output = fbterm_write;
|
||||
printf("fbterm: Generic framebuffer text output enabled.\n");
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
OUTPUT_FORMAT(elf64-littleaarch64)
|
||||
ENTRY(start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x80000;
|
||||
phys = .;
|
||||
|
||||
.text BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.bootstrap)
|
||||
code = .;
|
||||
*(.text)
|
||||
}
|
||||
|
||||
.rodata BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
.data BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
data = .;
|
||||
*(.data)
|
||||
*(.symbols)
|
||||
PROVIDE(kernel_symbols_start = .);
|
||||
PROVIDE(kernel_symbols_end = .);
|
||||
PROVIDE(bss_start = .);
|
||||
}
|
||||
|
||||
__bss_start = .;
|
||||
.bss BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
bss = .;
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
*(.stack)
|
||||
}
|
||||
__bss_end = .;
|
||||
__bss_size = __bss_end - __bss_start;
|
||||
|
||||
/* Some built-in stack space... */
|
||||
. = ALIGN(0x1000);
|
||||
. = . + 0x1000;
|
||||
__bootstrap_stack_top = .;
|
||||
|
||||
end = .;
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.comment)
|
||||
*(.eh_frame)
|
||||
*(.note.gnu.build-id)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,375 @@
|
|||
#include <stdint.h>
|
||||
#include <kernel/printf.h>
|
||||
#include <kernel/string.h>
|
||||
#include <kernel/elf.h>
|
||||
|
||||
#define MMIO_BASE 0xFE000000UL
|
||||
#define MBOX_BASE (MMIO_BASE + 0xB880)
|
||||
#define MBOX_READ (MBOX_BASE + 0x00)
|
||||
#define MBOX_STATUS (MBOX_BASE + 0x18)
|
||||
#define MBOX_WRITE (MBOX_BASE + 0x20)
|
||||
#define MBOX_FULL 0x80000000
|
||||
#define MBOX_EMPTY 0x40000000
|
||||
#define MBOX_RESPONSE 0x80000000
|
||||
#define MBOX_REQUEST 0
|
||||
|
||||
volatile uint32_t __attribute__((aligned(16))) mbox[36];
|
||||
|
||||
static uint32_t mmio_read32(uintptr_t addr) {
|
||||
uint32_t res = *((volatile uint32_t*)(addr));
|
||||
return res;
|
||||
}
|
||||
static void mmio_write32(uintptr_t addr, uint32_t val) {
|
||||
(*((volatile uint32_t*)(addr))) = val;
|
||||
}
|
||||
|
||||
uint32_t mbox_call(uint8_t ch) {
|
||||
uint32_t r = ((uint32_t)((uintptr_t)&mbox) & ~0xF) | (ch & 0xF);
|
||||
|
||||
while (mmio_read32(MBOX_STATUS) == MBOX_FULL); /* wait for mailbox to be ready */
|
||||
mmio_write32(MBOX_WRITE, r);
|
||||
|
||||
while (1) {
|
||||
while (mmio_read32(MBOX_STATUS) & MBOX_EMPTY);
|
||||
if (r == mmio_read32(MBOX_READ)) return mbox[1] == MBOX_RESPONSE;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t * lfb_vid_memory = 0;
|
||||
uint16_t lfb_resolution_x = 0;
|
||||
uint16_t lfb_resolution_y = 0;
|
||||
uint16_t lfb_resolution_b = 0;
|
||||
uint32_t lfb_resolution_s = 0;
|
||||
size_t lfb_memsize = 0;
|
||||
|
||||
void * malloc(size_t x) {
|
||||
while (1);
|
||||
}
|
||||
|
||||
int rpi_fb_init(void) {
|
||||
int i = 0;
|
||||
#define MB(j) mbox[i++] = j
|
||||
|
||||
MB(35 * 4);
|
||||
MB(MBOX_REQUEST);
|
||||
|
||||
MB(0x48003);
|
||||
MB(8);
|
||||
MB(0);
|
||||
int fb_width = i;
|
||||
MB(1920);
|
||||
int fb_height = i;
|
||||
MB(1080);
|
||||
|
||||
MB(0x48004);
|
||||
MB(8);
|
||||
MB(8);
|
||||
MB(1920);
|
||||
MB(1080);
|
||||
|
||||
MB(0x48009);
|
||||
MB(8);
|
||||
MB(8);
|
||||
MB(0);
|
||||
MB(0);
|
||||
|
||||
MB(0x48005);
|
||||
MB(4);
|
||||
MB(4);
|
||||
int fb_bpp = i;
|
||||
MB(32);
|
||||
|
||||
MB(0x48006);
|
||||
MB(4);
|
||||
MB(4);
|
||||
MB(1);
|
||||
|
||||
MB(0x40001);
|
||||
MB(8);
|
||||
MB(8);
|
||||
int fb_pointer = i;
|
||||
MB(4096);
|
||||
int fb_size = i;
|
||||
MB(0);
|
||||
|
||||
MB(0x40008);
|
||||
MB(4);
|
||||
MB(4);
|
||||
int fb_pitch = i;
|
||||
MB(0);
|
||||
|
||||
MB(0);
|
||||
|
||||
if (mbox_call(8) && mbox[fb_bpp] == 32 && mbox[fb_pointer] != 0) {
|
||||
lfb_vid_memory = (uint8_t*)(uintptr_t)(mbox[fb_pointer] & 0x3FFFFFFF);
|
||||
lfb_resolution_x = mbox[fb_width];
|
||||
lfb_resolution_y = mbox[fb_height];
|
||||
lfb_resolution_s = mbox[fb_pitch];
|
||||
lfb_resolution_b = mbox[fb_bpp];
|
||||
lfb_memsize = mbox[fb_size];
|
||||
|
||||
for (unsigned int y = 0; y < lfb_resolution_y; ++y) {
|
||||
for (unsigned int x = 0; x < lfb_resolution_x; ++x) {
|
||||
*(volatile uint32_t *)((uintptr_t)lfb_vid_memory + y * lfb_resolution_s + x * 4) = 0x3ea3f0;
|
||||
}
|
||||
}
|
||||
extern void fbterm_initialize(void);
|
||||
fbterm_initialize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern char _kernel_start[];
|
||||
extern char _kernel_end[];
|
||||
extern char _ramdisk_start[];
|
||||
extern char _ramdisk_end[];
|
||||
|
||||
static struct BaseTables {
|
||||
uintptr_t l0_base[512];
|
||||
uintptr_t l1_high_gbs[512];
|
||||
uintptr_t l1_low_gbs[512];
|
||||
uintptr_t l2_kernel[512];
|
||||
} _baseTables __attribute__((aligned(4096)));
|
||||
|
||||
#define PTE_VALID (1UL << 0)
|
||||
#define PTE_TABLE (1UL << 1)
|
||||
|
||||
/* Table attributes */
|
||||
#define PTE_NSTABLE (1UL << 63)
|
||||
#define PTE_APTABLE (3UL << 61) /* two bits */
|
||||
#define PTE_APTABLE_A (1UL << 62)
|
||||
#define PTE_APTABLE_B (1UL << 61)
|
||||
#define PTE_UXNTABLE (1UL << 60)
|
||||
#define PTE_PXNTABLE (1UL << 59)
|
||||
|
||||
/* Block attributes */
|
||||
#define PTE_UXN (1UL << 54)
|
||||
#define PTE_PXN (1UL << 53)
|
||||
#define PTE_CONTIGUOUS (1UL << 52)
|
||||
#define PTE_NG (1UL << 11)
|
||||
#define PTE_AF (1UL << 10)
|
||||
#define PTE_SH (3UL << 8) /* two bits */
|
||||
#define PTE_SH_A (1UL << 9)
|
||||
#define PTE_SH_B (1UL << 8)
|
||||
#define PTE_AP (3UL << 6) /* two bits */
|
||||
#define PTE_AP_A (1UL << 7)
|
||||
#define PTE_AP_B (1UL << 6)
|
||||
#define PTE_NS (1UL << 5)
|
||||
#define PTE_ATTRINDX (7UL << 2) /* three bits */
|
||||
#define PTE_ATTR_A (1UL << 4)
|
||||
#define PTE_ATTR_B (1UL << 3)
|
||||
#define PTE_ATTR_C (1UL << 2)
|
||||
|
||||
|
||||
#define KERNEL_PHYS_BASE 0x2000000UL
|
||||
|
||||
static void bootstub_mmu_init(void) {
|
||||
/* Map memory */
|
||||
_baseTables.l0_base[0] = (uintptr_t)&_baseTables.l1_low_gbs | PTE_VALID | PTE_TABLE | PTE_AF;
|
||||
|
||||
/* equivalent to high_base_pml */
|
||||
_baseTables.l0_base[511] = (uintptr_t)&_baseTables.l1_high_gbs | PTE_VALID | PTE_TABLE | PTE_AF;
|
||||
|
||||
/* Mapping for us */
|
||||
_baseTables.l1_low_gbs[0] = 0x00000000UL | PTE_VALID | PTE_AF | PTE_SH_A | (1 << 2);
|
||||
_baseTables.l1_low_gbs[1] = 0x40000000UL | PTE_VALID | PTE_AF | PTE_SH_A | (1 << 2);
|
||||
_baseTables.l1_low_gbs[2] = 0x80000000UL | PTE_VALID | PTE_AF | PTE_SH_A | (1 << 2);
|
||||
_baseTables.l1_low_gbs[3] = 0xc0000000UL | PTE_VALID | PTE_AF | PTE_SH_A | (1 << 2);
|
||||
|
||||
/* -512GB is a map of 64GB of memory */
|
||||
for (size_t i = 0; i < 64; ++i) {
|
||||
_baseTables.l1_high_gbs[i] = (i << 30) | PTE_VALID | PTE_AF | PTE_SH_A | (1 << 2);
|
||||
}
|
||||
|
||||
/* -2GiB, map kernel here */
|
||||
_baseTables.l1_high_gbs[510] = (uintptr_t)&_baseTables.l2_kernel | PTE_VALID | PTE_TABLE | PTE_AF;
|
||||
|
||||
for (size_t i = 0; i < 512; ++i) {
|
||||
_baseTables.l2_kernel[i] = (KERNEL_PHYS_BASE + (i << 21)) | PTE_VALID | PTE_AF | PTE_SH_A | (1 << 2);
|
||||
}
|
||||
|
||||
|
||||
uint64_t sctlr = 0
|
||||
| (1UL << 0) /* mmu enabled */
|
||||
| (1UL << 2) /* cachability */
|
||||
//| (1UL << 6)
|
||||
| (1UL << 12) /* instruction cachability */
|
||||
| (1UL << 23) /* SPAN */
|
||||
| (1UL << 28) /* nTLSMD */
|
||||
| (1UL << 29) /* LSMAOE */
|
||||
| (1UL << 20) /* TSCXT */
|
||||
| (1UL << 7) /* ITD */
|
||||
;
|
||||
|
||||
/* Translate control register */
|
||||
uint64_t tcr = 0
|
||||
| (3UL << 32) /* 36 bits? */
|
||||
| (2UL << 30) /* TG1 4KB granules in TTBR1 */
|
||||
| (16UL << 16) /* T1SZ 48-bit */
|
||||
| (3UL << 28) /* SH1 */
|
||||
| (1UL << 26) /* ORGN1 */
|
||||
| (1UL << 24) /* IRGN1 */
|
||||
| (0UL << 14) /* TG0 4KB granules in TTBR0 */
|
||||
| (16UL << 0) /* T0SZ 48-bit */
|
||||
| (3UL << 12) /* SH0 */
|
||||
| (1UL << 10) /* ORGN0 */
|
||||
| (1UL << 8) /* IRGN0 */
|
||||
;
|
||||
|
||||
/* MAIR setup? */
|
||||
uint64_t mair = (0x000000000044ff00);
|
||||
asm volatile ("msr MAIR_EL1,%0" :: "r"(mair));
|
||||
|
||||
/* Frob bits */
|
||||
printf("bootstub: setting base values\n");
|
||||
asm volatile ("msr TCR_EL1,%0" : : "r"(tcr));
|
||||
asm volatile ("msr TTBR0_EL1,%0" : : "r"(&_baseTables.l0_base));
|
||||
asm volatile ("msr TTBR1_EL1,%0" : : "r"(&_baseTables.l0_base));
|
||||
printf("bootstub: frobbing bits\n");
|
||||
asm volatile ("dsb ishst\ntlbi vmalle1is\ndsb ish\nisb" ::: "memory");
|
||||
printf("bootstub: enabling mmu\n");
|
||||
asm volatile ("msr SCTLR_EL1,%0" : : "r"(sctlr));
|
||||
asm volatile ("isb" ::: "memory");
|
||||
|
||||
printf("bootstub: MMU initialized\n");
|
||||
|
||||
}
|
||||
|
||||
static void bootstub_load_kernel(Elf64_Header * header) {
|
||||
/* Find load headers */
|
||||
for (int i = 0; i < header->e_phnum; ++i) {
|
||||
Elf64_Phdr * phdr = (void*)((uintptr_t)header + (header->e_phoff + header->e_phentsize * i));
|
||||
if (phdr->p_type == PT_LOAD) {
|
||||
printf("bootstub: Load %zu bytes @ %zx from off %zx\n", phdr->p_memsz, phdr->p_vaddr, phdr->p_offset);
|
||||
memset((void*)phdr->p_vaddr, 0, phdr->p_memsz);
|
||||
memcpy((void*)phdr->p_vaddr, (void*)((uintptr_t)header + phdr->p_offset), phdr->p_filesz);
|
||||
} else {
|
||||
printf("bootstub: Skip phdr %d\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct {
|
||||
uint32_t phys_addr;
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
uint32_t s;
|
||||
uint32_t b;
|
||||
uint32_t size;
|
||||
uint32_t ramdisk_start;
|
||||
uint32_t ramdisk_end;
|
||||
} tag_data = {0};
|
||||
|
||||
static void bootstub_start_kernel(uintptr_t dtb, Elf64_Header * header) {
|
||||
printf("bootstub: Jump to kernel entry point at %zx\n",
|
||||
header->e_entry);
|
||||
|
||||
void (*entry)(uintptr_t,uintptr_t,uintptr_t) = (void(*)(uintptr_t,uintptr_t,uintptr_t))header->e_entry;
|
||||
entry(dtb, KERNEL_PHYS_BASE, (uintptr_t)&tag_data);
|
||||
}
|
||||
|
||||
static void bootstub_exit_el2(void) {
|
||||
uint64_t spsr_el2, sctlr_el1;
|
||||
asm volatile ("mrs %0, SPSR_EL2\n" :"=r"(spsr_el2));
|
||||
printf("bootstub: SPSR_EL2=%#zx\n", spsr_el2);
|
||||
|
||||
asm volatile ("mrs %0, SCTLR_EL1\n" :"=r"(sctlr_el1));
|
||||
printf("bootstub: SCTLR_EL1=%#zx\n", sctlr_el1);
|
||||
|
||||
/* get us out of EL2 */
|
||||
|
||||
asm volatile (
|
||||
"ldr x0, =0x1004\n"
|
||||
"mrs x1, SCTLR_EL2\n"
|
||||
"orr x1, x1, x0\n"
|
||||
"msr SCTLR_EL2, x1\n"
|
||||
"ldr x0, =0x30d01804\n"
|
||||
"msr SCTLR_EL1, x0\n" ::: "x0", "x1");
|
||||
|
||||
printf("bootstub: sctlr_el1 set\n");
|
||||
|
||||
asm volatile (
|
||||
"ldr x0, =0x80000000\n"
|
||||
"msr HCR_EL2, x0\n" ::: "x0");
|
||||
|
||||
printf("bootstub: hcr set\n");
|
||||
|
||||
#if 0
|
||||
asm volatile (
|
||||
"ldr x0, =0x431\n"
|
||||
"msr SCR_EL3, x0\n" ::: "x0");
|
||||
printf("bootstub: SCR_EL3 set\n");
|
||||
#endif
|
||||
|
||||
asm volatile (
|
||||
"ldr x0, =0x3c5\n"
|
||||
"msr SPSR_EL2, x0\n" ::: "x0");
|
||||
|
||||
printf("bootstub: spsr_el2 set\n");
|
||||
|
||||
asm volatile (
|
||||
"mov x0, sp\n"
|
||||
"msr SP_EL1, x0\n"
|
||||
"adr x0, in_el1\n"
|
||||
"msr ELR_EL2, x0\n"
|
||||
"eret\n"
|
||||
"in_el1:\n"
|
||||
::: "x0", "memory", "cc"
|
||||
);
|
||||
|
||||
printf("bootstub: out of EL2?\n");
|
||||
|
||||
uint64_t CurrentEL;
|
||||
asm volatile ("mrs %0, CurrentEL" : "=r"(CurrentEL));
|
||||
printf("in el%zu\n", CurrentEL >> 2);
|
||||
}
|
||||
|
||||
void kmain(uint32_t dtb_address, uint32_t base_addr) {
|
||||
|
||||
if (rpi_fb_init()) {
|
||||
/* Panic */
|
||||
while (1);
|
||||
}
|
||||
|
||||
printf("rpi4 bootstub, kernel base address is %#x, dtb is at %#x\n", base_addr, dtb_address);
|
||||
|
||||
printf("framebuffer (%u x %u) @ %#zx\n",
|
||||
lfb_resolution_x,
|
||||
lfb_resolution_y,
|
||||
(uintptr_t)lfb_vid_memory);
|
||||
|
||||
uint64_t CurrentEL;
|
||||
asm volatile ("mrs %0, CurrentEL" : "=r"(CurrentEL));
|
||||
printf("in el%zu\n", CurrentEL >> 2);
|
||||
|
||||
printf("kernel @ %#zx (%zu bytes) ramdisk @ %#zx (%zu bytes)\n",
|
||||
(uintptr_t)&_kernel_start,
|
||||
(size_t)((uintptr_t)&_kernel_end - (uintptr_t)&_kernel_start),
|
||||
(uintptr_t)&_ramdisk_start,
|
||||
(size_t)((uintptr_t)&_ramdisk_end - (uintptr_t)&_ramdisk_start));
|
||||
|
||||
bootstub_exit_el2();
|
||||
|
||||
bootstub_mmu_init();
|
||||
|
||||
tag_data.phys_addr = lfb_vid_memory;
|
||||
tag_data.x = lfb_resolution_x;
|
||||
tag_data.y = lfb_resolution_y;
|
||||
tag_data.s = lfb_resolution_s;
|
||||
tag_data.b = lfb_resolution_b;
|
||||
tag_data.size = lfb_memsize;
|
||||
tag_data.ramdisk_start = (uintptr_t)&_ramdisk_start;
|
||||
tag_data.ramdisk_end = (uintptr_t)&_ramdisk_end;
|
||||
|
||||
Elf64_Header *header = (void*)&_kernel_start;
|
||||
bootstub_load_kernel(header);
|
||||
|
||||
/* Jump to kernel */
|
||||
bootstub_start_kernel(dtb_address, header);
|
||||
|
||||
while (1);
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
.extern __bootstrap_stack_top
|
||||
.extern __bss_start
|
||||
.extern __bss_size
|
||||
|
||||
.section ".bootstrap"
|
||||
.globl start
|
||||
start:
|
||||
ldr x30, =__bootstrap_stack_top
|
||||
mov x1, x4
|
||||
mov sp, x30
|
||||
ldr x5, =__bss_start
|
||||
ldr w6, =__bss_size
|
||||
3:
|
||||
cbz w6, 4f
|
||||
str xzr, [x5], #8
|
||||
sub w6, w6, #1
|
||||
cbnz w6, 3b
|
||||
4:
|
||||
bl kmain
|
||||
hang:
|
||||
b hang
|
||||
|
||||
.section ".rodata"
|
||||
.align 12
|
||||
.globl _kernel_start
|
||||
_kernel_start:
|
||||
.incbin "misaka-kernel"
|
||||
.globl _kernel_end
|
||||
_kernel_end:
|
||||
|
||||
.align 12
|
||||
.globl _ramdisk_start
|
||||
_ramdisk_start:
|
||||
.incbin "ramdisk.igz"
|
||||
.global _ramdisk_end
|
||||
_ramdisk_end:
|
|
@ -54,6 +54,7 @@ extern uint32_t lfb_resolution_s;
|
|||
static inline void set_point(int x, int y, uint32_t value) {
|
||||
if (lfb_resolution_b == 32) {
|
||||
((uint32_t*)lfb_vid_memory)[y * (lfb_resolution_s/4) + x] = value;
|
||||
asm volatile ("dc cvac, %0\n" :: "r"((uintptr_t)&((uint32_t*)lfb_vid_memory)[y * (lfb_resolution_s/4) + x]) : "memory");
|
||||
} else if (lfb_resolution_b == 24) {
|
||||
lfb_vid_memory[y * lfb_resolution_s + x * 3 + 0] = (value >> 0) & 0xFF;
|
||||
lfb_vid_memory[y * lfb_resolution_s + x * 3 + 1] = (value >> 8) & 0xFF;
|
||||
|
@ -295,6 +296,7 @@ size_t fbterm_write(size_t size, uint8_t *buffer) {
|
|||
for (unsigned int i = 0; i < size; ++i) {
|
||||
process_char(buffer[i]);
|
||||
}
|
||||
|
||||
if (previous_writer) previous_writer(size,buffer);
|
||||
return size;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue