10 Commits

Author SHA1 Message Date
d3d316a994 Add: README.md 2025-04-08 07:02:54 +08:00
93bbddf364 Fix: lab3 on-board problems 2025-04-08 07:01:56 +08:00
2d572cea4d Fix: lab3 bug 2025-04-08 07:01:56 +08:00
fc91808c1b Fix: enable interrupt later 2025-04-08 07:01:56 +08:00
b7da380421 Feat: lab 3 2025-04-08 07:01:24 +08:00
e2ebb6cc34 Feat: lab 3 w/o adv 2 2025-04-08 07:01:24 +08:00
98327b148a Draft: lab 3 irq wtf 2025-04-08 07:01:24 +08:00
9d19b8b3b6 Draft: start lab 3 2025-04-08 06:59:50 +08:00
45ebb20cf2 Feat: lab 4 2025-04-08 06:59:50 +08:00
ed2ced5caf Feat: add memalloc command 2025-04-08 06:59:50 +08:00
63 changed files with 2224 additions and 508 deletions

3
.gitignore vendored
View File

@@ -2,3 +2,6 @@
**.img
**.elf
**.cpio
.gdb_history
userprog/userprog
rootfs/userprog

View File

@@ -1,19 +1,28 @@
MAKE := make
MAKEFLAGS += -j8
ARCH := aarch64
GNU := $(ARCH)-linux-gnu
GDB := $(GNU)-gdb
QEMU := qemu-system-$(ARCH)
QEMUFLAGS += -M raspi3b -display none -serial null -serial pty
QEMUFLAGS += -M raspi3b -display none -serial null
CC := $(GNU)-gcc
CCFLAGS += -Wall -Wextra -O0 \
-mcpu=cortex-a53+nofp+nosimd \
-nostdinc -nostdlib -nostartfiles -nodefaultlibs \
-Wno-unused-parameter -Wno-unused-value -Wno-main -g
LD := $(GNU)-ld
LDFLAGS += -g -nostdlib -no-pie
OBJCOPY := $(GNU)-objcopy
OBJDUMP := $(GNU)-objdump
MISC_DIR := misc
QEMUFLAGS += -dtb $(MISC_DIR)/bcm2710-rpi-3-b-plus.dtb
LIB_DIR := lib
INCLUDE := -Iinclude
#TARGET := kernel8
#TARGET_DIR := ./kernel
@@ -21,37 +30,40 @@ ELF := $(TARGET).elf
IMG := $(TARGET).img
LD_SCRIPT := $(TARGET_DIR)/linker.ld
INCLUDE += -Iinclude
LIB_DIR := ./lib
MISC_DIR := ./misc
QEMUFLAGS += -dtb $(MISC_DIR)/bcm2710-rpi-3-b-plus.dtb
INCLUDE += -I$(TARGET_DIR)/include
TARGET_LIB_DIR := $(TARGET_DIR)/lib
BOOTLOADER_DIR := ./bootloader
ROOTFS_DIR := ./rootfs
# initramfs
ROOTFS_DIR := ./rootfs
CPIO := initramfs.cpio
QEMUFLAGS += -initrd $(CPIO)
SRCS := $(shell find $(TARGET_DIR) -name '*.[cS]') \
$(shell find $(LIB_DIR) -name '*.c')
TARGET_SRCS := $(shell find $(TARGET_DIR) -maxdepth 1 -name '*.[cS]') \
$(shell find $(TARGET_LIB_DIR) -name '*.[cS]')
TARGET_OBJS := $(TARGET_SRCS:%=%.o)
SRCS := $(shell find $(LIB_DIR) -name '*.c')
OBJS := $(SRCS:%=%.o)
.PHONY: all build clean clean_target run kernel debug gdb
.PHONY: all build clean clean_target run \
kernel bootloader userprog debug gdb objdump
all: $(CPIO)
$(MAKE) build TARGET_DIR=./kernel TARGET=kernel8
$(MAKE) build TARGET_DIR=./bootloader TARGET=bootloader
$(MAKE) $(MAKEFLAGS) build TARGET_DIR=kernel TARGET=kernel8
$(MAKE) $(MAKEFLAGS) build TARGET_DIR=bootloader TARGET=bootloader
build: $(IMG)
$(CPIO): $(shell find $(ROOTFS_DIR))
$(CPIO): $(shell find $(ROOTFS_DIR)) userprog
cp userprog/userprog $(ROOTFS_DIR)/userprog
cd $(ROOTFS_DIR) && find . | cpio -o -H newc > ../$@
$(IMG): $(ELF)
$(OBJCOPY) -O binary $< $@
$(ELF): $(LD_SCRIPT) $(OBJS)
$(LD) -o $@ -T $^ $(LDFLAGS)
$(ELF): $(LD_SCRIPT) $(TARGET_OBJS) $(OBJS)
$(LD) -o $@ -T $(LD_SCRIPT) $(TARGET_OBJS) $(OBJS) $(LDFLAGS)
%.S.o: %.S
mkdir -p $(dir $@)
@@ -62,22 +74,35 @@ $(ELF): $(LD_SCRIPT) $(OBJS)
$(CC) -c $< -o $@ $(INCLUDE) $(CCFLAGS)
clean:
$(MAKE) clean_target TARGET_DIR=./kernel TARGET=kernel8
$(MAKE) clean_target TARGET_DIR=./bootloader TARGET=bootloader
-rm $(OBJS) $(CPIO) $(ROOTFS_DIR)/userprog
$(MAKE) $(MAKEFLAGS) -C userprog clean
$(MAKE) $(MAKEFLAGS) clean_target TARGET_DIR=kernel TARGET=kernel8
$(MAKE) $(MAKEFLAGS) clean_target TARGET_DIR=bootloader TARGET=bootloader
clean_target:
-rm $(OBJS) $(ELF) $(IMG) $(CPIO)
-rm $(TARGET_OBJS) $(ELF) $(IMG)
run: all $(CPIO)
$(QEMU) -kernel bootloader.img $(QEMUFLAGS)
$(QEMU) -kernel bootloader.img $(QEMUFLAGS) -serial pty
kernel: all $(CPIO)
-killall screen
$(QEMU) -kernel kernel8.img $(QEMUFLAGS)
kernel: $(CPIO)
$(MAKE) $(MAKEFLAGS) build TARGET_DIR=kernel TARGET=kernel8
$(QEMU) -kernel kernel8.img $(QEMUFLAGS) -serial stdio
debug: all $(CPIO)
-killall screen
$(QEMU) -kernel kernel8.img $(QEMUFLAGS) -S -s
bootloader: $(CPIO)
$(MAKE) $(MAKEFLAGS) build TARGET_DIR=bootloader TARGET=bootloader
$(QEMU) -kernel bootloader.img $(QEMUFLAGS) -serial stdio
userprog:
$(MAKE) $(MAKEFLAGS) -C userprog
debug: $(CPIO)
$(MAKE) $(MAKEFLAGS) build TARGET_DIR=kernel TARGET=kernel8
$(QEMU) -kernel kernel8.img $(QEMUFLAGS) -serial stdio -S -s
gdb:
$(GDB)
objdump:
$(MAKE) $(MAKEFLAGS) build TARGET_DIR=kernel TARGET=kernel8
$(OBJDUMP) -D kernel8.elf

1
README.md Normal file
View File

@@ -0,0 +1 @@
# osc2025/ytshih

12
bootloader/include/uart.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <stddef.h>
void uart_init();
void uart_send(uint32_t c);
uint8_t uart_getb();
char uart_getc();
void uart_puts(const char *s);
void uart_hex(uint64_t d);
extern int is_uart_inited;

133
bootloader/lib/uart.c Normal file
View File

@@ -0,0 +1,133 @@
#include <uart.h>
#include <gpio.h>
#include <stddef.h>
/* Auxilary mini UART registers */
#define AUX_ENABLE ((volatile unsigned int*)(MMIO_BASE + 0x00215004))
#define AUX_MU_IO ((volatile unsigned int*)(MMIO_BASE + 0x00215040))
#define AUX_MU_IER ((volatile unsigned int*)(MMIO_BASE + 0x00215044))
#define AUX_MU_IIR ((volatile unsigned int*)(MMIO_BASE + 0x00215048))
#define AUX_MU_LCR ((volatile unsigned int*)(MMIO_BASE + 0x0021504C))
#define AUX_MU_MCR ((volatile unsigned int*)(MMIO_BASE + 0x00215050))
#define AUX_MU_LSR ((volatile unsigned int*)(MMIO_BASE + 0x00215054))
#define AUX_MU_MSR ((volatile unsigned int*)(MMIO_BASE + 0x00215058))
#define AUX_MU_SCRATCH ((volatile unsigned int*)(MMIO_BASE + 0x0021505C))
#define AUX_MU_CNTL ((volatile unsigned int*)(MMIO_BASE + 0x00215060))
#define AUX_MU_STAT ((volatile unsigned int*)(MMIO_BASE + 0x00215064))
#define AUX_MU_BAUD ((volatile unsigned int*)(MMIO_BASE + 0x00215068))
int is_uart_inited = 0;
/**
* Set baud rate and characteristics (115200 8N1) and map to GPIO
*/
void uart_init()
{
register unsigned int r;
/* initialize UART */
*AUX_ENABLE |= 1; // enable UART1, AUX mini uart
*AUX_MU_CNTL = 0;
*AUX_MU_LCR = 3; // 8 bits
*AUX_MU_MCR = 0;
*AUX_MU_IER = 0;
*AUX_MU_IIR = 0xc6; // disable interrupts
*AUX_MU_BAUD = 270; // 115200 baud
/* map UART1 to GPIO pins */
r = *GPFSEL1;
r &= ~((7 << 12) | (7 << 15)); // gpio14, gpio15
r |= (2 << 12) | (2 << 15); // alt5
*GPFSEL1 = r;
*GPPUD = 0; // enable pins 14 and 15
r = 150; while (r--) { asm volatile("nop"); }
*GPPUDCLK0 = (1 << 14) | (1 << 15);
r = 150; while (r--) { asm volatile("nop"); }
*GPPUDCLK0 = 0; // flush GPIO setup
*AUX_MU_CNTL = 3; // enable Tx, Rx
is_uart_inited = 1;
}
/**
* Send a character
*/
void uart_send(unsigned int c)
{
/* wait until we can send */
do { asm volatile("nop"); } while (!(*AUX_MU_LSR & 0x20));
/* write the character to the buffer */
*AUX_MU_IO = c;
}
uint8_t uart_getb()
{
uint8_t r;
/* wait until something is in the buffer */
do { asm volatile("nop"); } while (!(*AUX_MU_LSR & 0x01));
/* read it and return */
r = (uint8_t)(*AUX_MU_IO);
return r;
}
/**
* Receive a character
*/
char uart_getc()
{
char r = (char)uart_getb();
/* convert carrige return to newline */
return r == '\r' ? '\n' : r;
}
/**
* Display a string
*/
void uart_puts(const char *s)
{
while (*s) {
/* convert newline to carrige return + newline */
if(*s == '\n')
uart_send('\r');
uart_send(*s++);
}
}
/**
* Display a binary value in hexadecimal
*/
void uart_hex(uint64_t d)
{
unsigned int n;
for (int c = 28; c >= 0; c -= 4) {
// get highest tetrad
n = (d >> c) & 0xF;
// 0-9 => '0'-'9', 10-15 => 'A'-'F'
n += n > 9 ? 0x37 : 0x30;
uart_send(n);
}
}
void uart_int(int d)
{
unsigned int buf[11];
int size = 0;
if (d == 0) {
uart_send((unsigned int)'0');
return;
}
int is_neg = (d < 0);
while (d != 0) {
buf[size++] = '0' + d % 10;
d /= 10;
}
if (is_neg)
uart_send((unsigned int)'-');
while (size--)
uart_send(buf[size]);
}

View File

@@ -1,16 +1,16 @@
ENTRY(_start)
MEMORY
{
NEWTEXT (rx) : ORIGIN = 0x10000, LENGTH = 64K
NEWRO (r) : ORIGIN = 0x20000, LENGTH = 16K
NEWDATA (rw) : ORIGIN = 0x24000, LENGTH = 16K
NEWBSS (rw) : ORIGIN = 0x28000, LENGTH = 16K
NEWTEXT (rx) : ORIGIN = 0x10000, LENGTH = 32K
NEWRO (r) : ORIGIN = 0x18000, LENGTH = 8K
NEWDATA (rw) : ORIGIN = 0x1a000, LENGTH = 8K
NEWBSS (rw) : ORIGIN = 0x1c000, LENGTH = 8K
TEXT (rx) : ORIGIN = 0x80000, LENGTH = 64K
RO (r) : ORIGIN = 0x90000, LENGTH = 16K
DATA (rw) : ORIGIN = 0x94000, LENGTH = 16K
BSS (rw) : ORIGIN = 0x98000, LENGTH = 16K
RAM (rw) : ORIGIN = 0x9c000, LENGTH = 4M
TEXT (rx) : ORIGIN = 0x80000, LENGTH = 32K
RO (r) : ORIGIN = 0x88000, LENGTH = 8K
DATA (rw) : ORIGIN = 0x8a000, LENGTH = 8K
BSS (rw) : ORIGIN = 0x8c000, LENGTH = 8K
RAM (rw) : ORIGIN = 0xa4000, LENGTH = 4M
}
SECTIONS

View File

@@ -1,5 +1,4 @@
#include <stddef.h>
#include <shell.h>
#include <uart.h>
// extern uint64_t __kernel;
@@ -22,7 +21,7 @@ void main(void *dtb)
kernel_header.buf[i] = uart_getb();
uart_puts("received kernel size: ");
uart_int(kernel_header.size);
uart_hex(kernel_header.size);
uart_puts(ENDL);
uart_puts("loaded addr: ");

8
include/ctype.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include <stddef.h>
int isdigit(int);
int isxdigit(int);
int isupper(int);
int isspace(int);

View File

@@ -1,6 +1,12 @@
#pragma once
#define ERR_NO_MEM 0x00000001
#define ERR_UNREACHABLE 0x00000002
#define ERR_CONVERSION 0x00000003
#define ERR_VECTOR_OOR 0x00000101
#define NO_ERROR 0x00000000
#define ERR_NO_MEM 0x00000001
#define ERR_UNREACHABLE 0x00000002
#define ERR_CONVERSION 0x00000003
#define ERR_OUT_OF_BOUND 0x00000004
#define ERR_INVALID_OP 0x00000005
#define ERR_INVALID_MEM 0x00000006
#define ERR_NOT_EXIST 0x00000007
#define ERR_IO_FAILED 0x00000008
#define ERR_ADMINKILL 0x00114514

View File

@@ -1,7 +0,0 @@
#pragma once
#include <stddef.h>
void *simple_alloc(size_t size);
void *kmalloc(size_t size);
void kfree(void *ptr);

114
include/logger.h Normal file
View File

@@ -0,0 +1,114 @@
#pragma once
#include <stddef.h>
#include <uart.h>
#ifndef LOGLEVEL
#define LOGLEVEL 3
#endif
#define LOGGER_BUFLEN 0x100
static inline char *_do_nothing(char *dest, const char *) { return dest; }
static inline char *_logger_string(char *dest, const char *src)
{
while (*src != '\0')
*dest++ = *src++;
*dest = '\0';
return dest;
}
static inline char *_logger_hex(char *dest, uint64_t x)
{
for (int n, c = 60; c >= 0; c -= 4) {
n = (x >> c) & 0xf;
n += (n > 9) ? 0x37 : 0x30;
*dest++ = (char)n;
}
*dest = '\0';
return dest;
}
static inline char *_logger_pointer(char *dest, void *x)
{
*dest++ = '0';
*dest++ = 'x';
return _logger_hex(dest, (uint64_t)x);
}
static inline
void _uart_puts_sync(const char *s)
{
while (*s != '\0')
uart_putb_sync((const uint8_t *)s++, 1);
}
#define _I_HATE_C_LANG(msg) \
logger_cur = _Generic((msg), \
char * : _do_nothing, \
const char *: _do_nothing, \
default : _logger_string \
)(logger_cur, #msg " = "); \
logger_cur = _Generic((msg), \
char * : _logger_string, \
const char *: _logger_string, \
uint64_t : _logger_hex, \
default : _logger_pointer \
)(logger_cur, msg)
#define LOG(val) { \
if (logger_cur != logger_buf) \
logger_cur = _logger_string(logger_cur, ", "); \
_I_HATE_C_LANG(val); \
}
#define FLUSH(prefix) { \
_uart_puts_sync(prefix); \
_uart_puts_sync(logger_buf); \
_uart_puts_sync(ENDL); \
logger_cur = logger_buf; \
}
#define CLEAN { \
logger_cur = logger_buf; \
}
#if LOGLEVEL >= 0
#define ERROR(val) { \
LOG(val); \
FLUSH("[ERROR]: "); \
}
#else
#define ERROR(val) CLEAN
#endif
#if LOGLEVEL >= 1
#define INFOR(val) { \
LOG(val); \
FLUSH("[INFOR]: "); \
}
#else
#define INFOR(val) CLEAN
#endif
#if LOGLEVEL >= 2
#define DEBUG(val) { \
LOG(val); \
FLUSH("[DEBUG]: "); \
}
#else // #if LOGLEVEL >= 2
#define DEBUG(val) CLEAN
#endif // #if LOGLEVEL >= 2
// #define DEBUG_DTB(val) DEBUG(val)
#define DEBUG_DTB(val) CLEAN
#define DEBUG_EXCEP(val) DEBUG(val)
// #define DEBUG_EXCEP(val) CLEAN
// #define DEBUG_MEM(val) DEBUG(val)
#define DEBUG_MEM(val) CLEAN
// #define DEBUG_INITRD(val) DEBUG(val)
#define DEBUG_INITRD(val) CLEAN
extern char logger_buf[LOGGER_BUFLEN];
extern char *logger_cur;

View File

@@ -1,14 +0,0 @@
#pragma once
#include <initrd.h>
#include <stddef.h>
void help(void);
void hello(void);
void hwinfo(void);
void ls(file_node_t *root);
void cat(file_node_t *root, const char *filename);
void reboot(void);
int // is continue
shell(file_node_t *);

View File

@@ -1,8 +1,10 @@
#pragma once
#define true 1
#define false 0
#define true 0x1
#define false 0x0
#define ENDL "\r\n"
#define NAME_MAX 255
#define PATH_MAX 4096

View File

@@ -5,6 +5,7 @@
int strcmp(const char *lhs, const char *rhs);
char *strcpy(char *destination, const char *source);
size_t strlen(const char *str);
char *strtok_r(char *str, const char *delimiters, char **saveptr);
void *memcpy(void *dest, const void *src, size_t count);
void *memzero(void *start, void *end);

View File

@@ -1,25 +0,0 @@
#pragma once
#include <stddef.h>
#define DEBUG(x) { \
uart_puts(#x " = "); \
uart_hex((unsigned int)(unsigned long)x); \
uart_puts(ENDL); \
}
#define DEBUG_s(x) { \
uart_puts(#x " = "); \
uart_puts(x); \
uart_puts(ENDL); \
}
void uart_init();
void uart_send(unsigned int c);
uint8_t uart_getb();
char uart_getc();
void uart_puts(const char *s);
void uart_hex(unsigned int d);
void uart_int(int d);
extern int is_uart_init;

View File

@@ -1,31 +0,0 @@
#pragma once
#include <stddef.h>
#include <uart.h>
uint32_t msb32(uint32_t);
uint32_t hton32(const uint32_t);
uint32_t ntoh32(const uint32_t);
uint64_t hton64(const uint64_t);
uint64_t ntoh64(const uint64_t);
int isdigit(int);
int isxdigit(int);
int isupper(int);
int isspace(int);
int32_t atoi32(const char *);
uint32_t atoh32(const char *);
void exit(int);
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) < (y)) ? (y) : (x))
#define ALIGN4(ptr) (void *)(((((uint64_t)(ptr) - 1) >> 2) + 1) << 2)
#define ALIGN8(ptr) (void *)(((((uint64_t)(ptr) - 1) >> 3) + 1) << 3)
#define BUMP(orig_type, bump_type, ptr) ( \
(ptr = (orig_type *)((bump_type *)ptr + 1)), \
((bump_type *)ptr - 1) \
)

View File

@@ -7,13 +7,16 @@ _start:
mrs x1, mpidr_el1
and x1, x1, #3
cbz x1, run
// cpu id > 0, stop
// cpu id > 0, fallback to wait
wait:
wfe
b wait
run: // cpu id == 0
mov x20, x0
bl el2_to_el1
adrp x0, __stack_end
mov sp, x0
@@ -25,3 +28,11 @@ run: // cpu id == 0
mov x0, x20
bl main
b wait
el2_to_el1:
mov x0, (1 << 31)
msr hcr_el2, x0
mov x0, 0x3c5
msr spsr_el2, x0
msr elr_el2, lr
eret

111
kernel/exception_table.S Normal file
View File

@@ -0,0 +1,111 @@
.section ".text.exception"
// save general registers to stack
.macro save_all
sub sp, sp, 34 * 8
stp x0, x1, [sp, 16 * 0]
stp x2, x3, [sp, 16 * 1]
stp x4, x5, [sp, 16 * 2]
stp x6, x7, [sp, 16 * 3]
stp x8, x9, [sp, 16 * 4]
stp x10, x11, [sp, 16 * 5]
stp x12, x13, [sp, 16 * 6]
stp x14, x15, [sp, 16 * 7]
stp x16, x17, [sp, 16 * 8]
stp x18, x19, [sp, 16 * 9]
stp x20, x21, [sp, 16 * 10]
stp x22, x23, [sp, 16 * 11]
stp x24, x25, [sp, 16 * 12]
stp x26, x27, [sp, 16 * 13]
stp x28, x29, [sp, 16 * 14]
mrs x0, spsr_el1
mrs x1, elr_el1
mrs x2, esr_el1
stp x0, x1, [sp, 16 * 15]
stp x2, lr, [sp, 16 * 16]
.endm
// load general registers from stack
.macro load_all
ldp x0, x1, [sp, 16 * 15]
ldp x2, lr, [sp, 16 * 16]
msr spsr_el1, x0
msr elr_el1, x1
msr esr_el1, x2
ldp x0, x1, [sp, 16 * 0]
ldp x2, x3, [sp, 16 * 1]
ldp x4, x5, [sp, 16 * 2]
ldp x6, x7, [sp, 16 * 3]
ldp x8, x9, [sp, 16 * 4]
ldp x10, x11, [sp, 16 * 5]
ldp x12, x13, [sp, 16 * 6]
ldp x14, x15, [sp, 16 * 7]
ldp x16, x17, [sp, 16 * 8]
ldp x18, x19, [sp, 16 * 9]
ldp x20, x21, [sp, 16 * 10]
ldp x22, x23, [sp, 16 * 11]
ldp x24, x25, [sp, 16 * 12]
ldp x26, x27, [sp, 16 * 13]
ldp x28, x29, [sp, 16 * 14]
add sp, sp, 34 * 8
.endm
_null_handler:
save_all
bl not_implemented_handler
load_all
eret
_synchronous_handler:
save_all
bl synchronous_handler
load_all
eret
_irq_handler:
save_all
bl irq_handler
load_all
eret
.align 11
.global exception_vector_table
exception_vector_table:
b _null_handler
.align 7
b _null_handler
.align 7
b _null_handler
.align 7
b _null_handler
.align 7
b _synchronous_handler
.align 7
b _irq_handler
.align 7
b _null_handler
.align 7
b _null_handler
.align 7
b _synchronous_handler
.align 7
b _irq_handler
.align 7
b _null_handler
.align 7
b _null_handler
.align 7
b _null_handler
.align 7
b _null_handler
.align 7
b _null_handler
.align 7
b _null_handler
.align 7

View File

@@ -40,13 +40,16 @@ typedef struct {
#define FDT_PATH_BUFFER_LEN 0x10
typedef void (*fdt_callback_func_t)(const vector_t *props);
typedef void (*fdt_callback_func_t)(const vector_t *);
typedef struct {
const char *name;
const fdt_callback_func_t func;
} fdt_callback_t;
void fdt_callback(const char *path, const vector_t *cbs, const vector_t *props);
void fdt_traverse(const vector_t *cbs);
void fdt_traverse(const vector_t *struct_cbs);
extern void *dtb_addr;
extern void *dtb_start;
extern void *dtb_end;
extern void *dtb_memory_start;
extern void *dtb_memory_end;
extern vector_t *dtb_reserved_entries;

View File

@@ -0,0 +1,5 @@
#pragma once
void init_exception(void);
void not_implemented_handler(void);
void synchronous_handler(void);

3
kernel/include/exec.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
void user_exec(void *text, void *sp);

View File

@@ -0,0 +1,25 @@
#pragma once
#include <stddef.h>
typedef void (*interrupt_callback_func_t)(uint64_t);
typedef struct interrupt {
struct interrupt *_l, *_r;
uint32_t _d;
uint64_t priority;
interrupt_callback_func_t func;
uint64_t param;
} interrupt_t;
void add_interrupt_task(uint64_t priority,
interrupt_callback_func_t func,
uint64_t param);
void init_interrupt(void);
void irq_handler(void);
void wfe(void);
extern interrupt_t *global_interrupt_pool;

27
kernel/include/kmalloc.h Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
#include <stddef.h>
#define KMALLOC_MAX_ALLOCATOR_SIZE 256
typedef struct kmalloc_header {
size_t unit;
size_t left;
void *begin;
struct kmalloc_header *page_prev, *page_next;
}__attribute__((packed)) kmalloc_header_t;
typedef struct {
size_t left;
kmalloc_header_t *page_begin;
} kmalloc_allocator_t;
void init_mman_kmalloc();
void *simple_alloc(size_t size);
void *mman_alloc(size_t size);
void mman_free(void *ptr);
extern void *(*kmalloc)(size_t size);
extern void (*kfree)(void *ptr);
extern kmalloc_allocator_t mman_kmalloc_pool[KMALLOC_MAX_ALLOCATOR_SIZE + 1];

37
kernel/include/mman.h Normal file
View File

@@ -0,0 +1,37 @@
#pragma once
#include <stddef.h>
#include <dtb.h>
#define MMAN_NO_PAGE 0xffffffffffffffff
#define PAGE_SIZE (1 << 12)
// PAGE_FREE => available
// PAGE_ALLOCATED => this range is allocated explicitly
// PAGE_DIVIDED => this range is divided into smaller range
// PAGE_RESERVED => this range is reserved explicitly
typedef enum :uint8_t {
PAGE_FREE = 0,
PAGE_ALLOCATED = 1,
PAGE_DIVIDED = 2,
PAGE_RESERVED = 3,
} page_state_t;
typedef struct {
page_state_t state;
uint64_t maxsz;
} page_header_t;
void mman_init();
void *allocate_page(size_t page_cnt);
void free_page(void *ptr);
void reserve_page(void *begin, void *end);
void mman_fdt_memory_cb_func(const vector_t *props);
extern fdt_callback_t mman_dtb_memory_cb;
extern void *mman_memory_start;
extern void *mman_memory_end;
extern size_t mman_page_cnt;
extern page_header_t *mman_frame_array;

29
kernel/include/queue.h Normal file
View File

@@ -0,0 +1,29 @@
#pragma once
#include <stddef.h>
typedef struct queue_node {
struct queue_node *prev, *next;
uint64_t value;
} queue_node_t;
typedef struct queue {
size_t size;
queue_node_t *begin, *end;
} queue_t;
queue_t *make_queue();
uint64_t queue_back(const queue_t *queue);
uint64_t queue_front(const queue_t *queue);
void queue_push_back(queue_t *queue, uint64_t val);
void queue_push_front(queue_t *queue, uint64_t val);
#define QUEUE_BACK(type, queue) ((type *)queue_back(queue))
#define QUEUE_FRONT(type, queue) ((type *)queue_front(queue))
#define QUEUE_PUSH_BACK(queue, val) \
queue_push_back(queue, (uint64_t)val)
#define QUEUE_PUSH_FRONT(queue, val) \
queue_push_front(queue, (uint64_t)val)

View File

@@ -0,0 +1,14 @@
#pragma once
#include <stddef.h>
typedef struct {
size_t size;
size_t cap;
uint8_t *data;
uint8_t *read, *write;
} ringbuffer_t;
ringbuffer_t *make_ringbuffer(size_t size);
int ringbuffer_push(ringbuffer_t *buf, uint8_t val);
uint8_t ringbuffer_bump(ringbuffer_t *buf);

7
kernel/include/shell.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#include <stddef.h>
#include <initrd.h>
int // is continue
shell(file_node_t *);

27
kernel/include/timer.h Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
#include <stddef.h>
typedef void (*task_callback_func_t)(uint64_t);
typedef struct {
uint64_t firing_tick;
uint64_t interval;
uint64_t repeat;
task_callback_func_t func;
uint64_t param;
} task_t;
typedef struct timer {
struct timer *_l, *_r;
uint32_t _d;
task_t data;
} timer_t;
void add_task(task_t task);
void timer_irq_handler(void);
extern timer_t *global_timer;

25
kernel/include/uart.h Normal file
View File

@@ -0,0 +1,25 @@
#pragma once
#include <stddef.h>
#include <ringbuffer.h>
#define UART_BUFLEN 0x800
void uart_init(void);
char uart_getc(void);
void uart_puts(const char *s);
void uart_hex(uint64_t d);
void uart_irq_handler(void);
size_t uart_putb_sync(const uint8_t *bytes, size_t len);
size_t uart_getb_sync(uint8_t *bytes, size_t len);
size_t uart_putb_async(const uint8_t *bytes, size_t len);
size_t uart_getb_async(uint8_t *bytes, size_t len);
extern size_t (*uart_putb)(const uint8_t *bytes, size_t len);
extern size_t (*uart_getb)(uint8_t *bytes, size_t len);
extern int is_uart_inited;
extern ringbuffer_t *uart_readbuf;

78
kernel/include/utils.h Normal file
View File

@@ -0,0 +1,78 @@
#pragma once
#include <stddef.h>
#include <uart.h>
uint32_t msb32(uint32_t);
uint64_t msb64(uint64_t);
uint32_t hton32(const uint32_t);
uint32_t ntoh32(const uint32_t);
uint64_t hton64(const uint64_t);
uint64_t ntoh64(const uint64_t);
int isdigit(int);
int isxdigit(int);
int isupper(int);
int isspace(int);
int32_t atoi32(const char *);
uint32_t atoh32(const char *);
void exit(int);
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) < (y)) ? (y) : (x))
#define ALIGN(ptr, cnt) (void *)((( \
((uint64_t)(ptr) - 1) >> (cnt)) + 1) << (cnt))
#define ALIGN4(ptr) ALIGN(ptr, 2)
#define ALIGN8(ptr) ALIGN(ptr, 3)
#define ALIGN4K(ptr) ALIGN(ptr, 12)
#define BUMP(orig_type, bump_type, ptr) ( \
(ptr = (orig_type*)((bump_type*)ptr + 1)), \
((bump_type*)ptr - 1) \
)
#define R_SYSREG(ret, reg) \
asm volatile( \
"mrs %[a], " #reg \
: [a] "=r" (ret) \
)
#define W_SYSREG(reg, val) \
asm volatile( \
"mov x0, %[a]" ENDL \
"msr " #reg ", x0" ENDL \
:: [a] "r" (val) \
: "x0" \
)
#define W_SYSREG_IMM(reg, val) \
asm volatile( \
"msr " #reg ", %[a]" \
:: [a] "i" (val) \
)
#define R_REG(ret, reg) \
asm volatile( \
"mov %[a], " #reg \
: [a] "=r" (ret) \
)
#define W_REG(reg, val) \
asm volatile( \
"mov " #reg ", %[a]" \
:: [a] "r" (val) \
)
#define MMIO_W_HELPER(name, reg, mask, offset) \
static inline void name(uint64_t state) \
{ *reg = (*reg & ~((mask) << (offset))) | ((state & (mask)) << (offset)); }
#define MMIO_R_HELPER(name, reg, mask, offset) \
static inline uint64_t name(void) \
{ return (*reg >> (offset)) & (mask); }

View File

@@ -12,7 +12,7 @@ typedef struct {
vector_t *make_vector(size_t size);
uint64_t vec_at(const vector_t *vec, size_t idx);
vector_t *vec_push(vector_t *vec, uint64_t val);
void vec_push(vector_t *vec, uint64_t val);
#define VEC_AT(type, vec, idx) ((type *)vec_at((vec), (idx)))
#define VEC_PUSH(vec, val) vec = vec_push(vec, (uint64_t)val)
#define VEC_PUSH(vec, val) vec_push(vec, (uint64_t)val)

View File

@@ -1,24 +1,43 @@
#include <logger.h>
#include <errcode.h>
#include <dtb.h>
#include <utils.h>
#include <string.h>
#include <uart.h>
#include <kmalloc.h>
#include <vector.h>
void *dtb_addr;
void *dtb_start;
void *dtb_end;
void *dtb_memory_start;
void *dtb_memory_end;
vector_t *dtb_reserved_entries;
void fdt_callback(const char *path, const vector_t *cbs, const vector_t *props)
fdt_reserve_entry_t *fdt_memory_cur;
uint32_t *fdt_struct_cur;
static inline
void _fdt_struct_callback(const char *path, const vector_t *cbs, const vector_t *props)
{
for (int i = 0; i < (int)cbs->size; ++i)
if (!strcmp(path, VEC_AT(fdt_callback_t, cbs, i)->name))
VEC_AT(fdt_callback_t, cbs, i)->func(props);
}
uint32_t *fdt_struct_cur;
static inline
void _memory_traverse()
{
dtb_reserved_entries = make_vector(0);
while (fdt_memory_cur->address != 0 || fdt_memory_cur->size != 0) {
DEBUG_DTB(ntoh64(fdt_memory_cur->address));
DEBUG_DTB(ntoh64(fdt_memory_cur->size));
VEC_PUSH(dtb_reserved_entries, fdt_memory_cur++);
}
}
#define nextnode(ptr) (void *)((((uint64_t)(ptr) >> 2) + 1) << 2)
void traverse(const char *path, const vector_t *cbs)
static inline
void _struct_traverse(const char *path, const vector_t *cbs)
{
vector_t *props = make_vector(0);
@@ -31,7 +50,7 @@ void traverse(const char *path, const vector_t *cbs)
switch (ntoh32(*fdt_struct_cur)) {
case FDT_BEGIN_NODE:
BUMP(uint32_t, uint32_t, fdt_struct_cur);
++fdt_struct_cur;
fdt_node_path = (void *)fdt_struct_cur;
do {
BUMP(uint32_t, char, fdt_struct_cur);
@@ -39,19 +58,19 @@ void traverse(const char *path, const vector_t *cbs)
BUMP(uint32_t, char, fdt_struct_cur); // '\0'
fdt_struct_cur = ALIGN4(fdt_struct_cur);
traverse(fdt_node_path, cbs);
_struct_traverse(fdt_node_path, cbs);
break;
case FDT_END_NODE:
fdt_struct_cur = nextnode(fdt_struct_cur);
goto traverse_callback;
goto traverse_struct_callback;
case FDT_PROP:
BUMP(uint32_t, uint32_t, fdt_struct_cur);
++fdt_struct_cur;
prop_header = BUMP(uint32_t, fdt_prop_header_t, fdt_struct_cur);
prop = kmalloc(sizeof(fdt_prop_t));
prop->len = ntoh32(prop_header->len);
prop->name = dtb_addr +
ntoh32(((fdt_header_t *)dtb_addr)->off_dt_strings) +
prop->name = dtb_start +
ntoh32(((fdt_header_t *)dtb_start)->off_dt_strings) +
ntoh32(prop_header->nameoff);
prop->value = (void *)fdt_struct_cur;
VEC_PUSH(props, prop);
@@ -69,13 +88,23 @@ void traverse(const char *path, const vector_t *cbs)
exit(ERR_UNREACHABLE);
}
}
traverse_callback:
fdt_callback(path, cbs, props);
traverse_struct_callback:
_fdt_struct_callback(path, cbs, props);
}
void fdt_traverse(const vector_t *cbs)
void fdt_traverse(const vector_t *struct_cbs)
{
fdt_struct_cur = dtb_addr + ntoh32(((fdt_header_t *)dtb_addr)->off_dt_struct);
fdt_memory_cur = dtb_start +
ntoh32(((fdt_header_t *)dtb_start)->off_mem_rsvmap);
fdt_struct_cur = dtb_start +
ntoh32(((fdt_header_t *)dtb_start)->off_dt_struct);
dtb_end = dtb_start +
ntoh32(((fdt_header_t *)dtb_start)->totalsize);
traverse("", cbs);
DEBUG_DTB(fdt_memory_cur);
DEBUG_DTB(fdt_struct_cur);
_memory_traverse();
DEBUG_DTB("memory traverse done");
_struct_traverse("", struct_cbs);
DEBUG_DTB("struct traverse done");
}

42
kernel/lib/exception.c Normal file
View File

@@ -0,0 +1,42 @@
#include <exception.h>
#include <errcode.h>
#include <stddef.h>
#include <logger.h>
#include <utils.h>
void init_exception()
{
asm volatile(
"adr x0, exception_vector_table" ENDL
"msr vbar_el1, x0" ENDL
::: "x0"
);
}
void not_implemented_handler()
{
DEBUG_EXCEP("not implemented caught");
}
void synchronous_handler()
{
static int poop = 0;
if (poop++ > 5)
exit(ERR_ADMINKILL);
DEBUG_EXCEP("synchronous caught");
uint64_t x0 = 0x0;
R_REG(x0, x0);
LOG(x0);
uint64_t spsr_el1 = 0x0;
R_SYSREG(spsr_el1, spsr_el1);
LOG(spsr_el1);
uint64_t elr_el1 = 0x0;
R_SYSREG(elr_el1, elr_el1);
LOG(elr_el1);
uint64_t esr_el1 = 0x0;
R_SYSREG(esr_el1, esr_el1);
DEBUG_EXCEP(esr_el1);
}

16
kernel/lib/exec.c Normal file
View File

@@ -0,0 +1,16 @@
#include <exec.h>
#include <utils.h>
void user_exec(void *text, void *sp)
{
// enable core timer
uint64_t cntkctl_el1 = 0x0;
R_SYSREG(cntkctl_el1, cntkctl_el1);
W_SYSREG(cntkctl_el1, cntkctl_el1 | 1);
W_SYSREG(cntp_ctl_el0, 1);
W_SYSREG(spsr_el1, 0);
W_SYSREG(elr_el1, text);
W_SYSREG(sp_el0, sp);
asm volatile("eret");
}

View File

@@ -29,14 +29,14 @@ void initrd_fdt_callback(const vector_t *props)
}
}
void _init_node(file_node_t *node) {
static inline void _init_node(file_node_t *node) {
node->l = nullnode;
node->r = nullnode;
node->rand = random();
node->node_size = 1;
}
void _pull_from(file_node_t *to, file_node_t *from)
static inline void _pull_from(file_node_t *to, file_node_t *from)
{
if (!from)
return;
@@ -44,14 +44,14 @@ void _pull_from(file_node_t *to, file_node_t *from)
to->node_size += from->node_size;
}
void _pull(file_node_t *node)
static inline void _pull(file_node_t *node)
{
node->node_size = 1;
_pull_from(node, node->l);
_pull_from(node, node->r);
}
file_node_t *_merge(file_node_t *a, file_node_t *b)
static inline file_node_t *_merge(file_node_t *a, file_node_t *b)
{
if (!a || !b)
return a ?: b;
@@ -66,7 +66,8 @@ file_node_t *_merge(file_node_t *a, file_node_t *b)
return b;
}
void _split(file_node_t *rt, const char *s, file_node_t **a, file_node_t **b)
static inline void _split(file_node_t *rt, const char *s,
file_node_t **a, file_node_t **b)
{
if (!rt) {
*a = *b = nullnode;
@@ -96,7 +97,7 @@ file_node_t *initrd_init(void)
file_node_t *root = nullnode, *ltr, *rtr;
for (;;) {
header = BUMP(cpio_newc_header_t, cpio_newc_header_t, initrd_cur);
header = initrd_cur++;
filename = (void *)initrd_cur;
if (!strcmp(filename, "TRAILER!!!"))
@@ -124,8 +125,6 @@ file_node_t *initrd_init(void)
newnode->filename = filename;
newnode->filecontent = filecontent;
DEBUG_s(filename);
_split(root, filename, &ltr, &rtr);
root = _merge(ltr, _merge(newnode, rtr));
}
@@ -133,7 +132,7 @@ file_node_t *initrd_init(void)
return root;
}
file_node_t *_node_bs(file_node_t *cur, const char *s)
static inline file_node_t *_node_bs(file_node_t *cur, const char *s)
{
if (!cur)
return nullnode;

118
kernel/lib/interrupt.c Normal file
View File

@@ -0,0 +1,118 @@
#include <interrupt.h>
#include <kmalloc.h>
#include <uart.h>
#include <timer.h>
#include <utils.h>
#include <logger.h>
#include <errcode.h>
#define CORE0_TIMER_IRQ_CTRL ((volatile uint32_t *)0x40000040)
#define CORE0_IRQ_SOURCE ((volatile uint32_t *)0x40000060)
interrupt_t *global_interrupt_pool = (interrupt_t *)0x0;
static inline
void _enable_interrupt(void)
{ W_SYSREG_IMM(DAIFClr, 0xf); }
static inline
void _disable_interrupt(void)
{ W_SYSREG_IMM(DAIFSet, 0xf); }
MMIO_W_HELPER(_enable_timer_irq, CORE0_TIMER_IRQ_CTRL, 0x1, 1);
MMIO_R_HELPER(_irq_source_timer, CORE0_IRQ_SOURCE, 0x1, 1);
MMIO_R_HELPER(_irq_source_uart, CORE0_IRQ_SOURCE, 0x1, 8);
static inline
uint32_t _d(interrupt_t *interrupt)
{ return interrupt ? interrupt->_d : 0; }
static inline
void _swap(interrupt_t **a, interrupt_t **b)
{
interrupt_t *tmp = *a;
*a = *b, *b = tmp;
}
static inline
interrupt_t *_merge(interrupt_t *a, interrupt_t *b)
{
if (!a || !b)
return a ?: b;
if (a->priority < b->priority)
_swap(&a, &b);
a->_r = _merge(a->_r, b);
if (_d(a->_l) < _d(a->_r))
_swap(&a->_l, &a->_r);
a->_d = _d(a->_r) + 1;
return a;
}
static inline
interrupt_t *_pop(interrupt_t *interrupt)
{
if (!interrupt || (!interrupt->_l && !interrupt->_r))
return (interrupt_t *)0x0;
return _merge(interrupt->_l, interrupt->_r);
}
void add_interrupt_task(uint64_t priority,
interrupt_callback_func_t func,
uint64_t param)
{
// DEBUG_EXCEP("add interrupt");
interrupt_t *newint = kmalloc(sizeof(interrupt_t));
*newint = (interrupt_t){
._l = (interrupt_t *)0x0,
._r = (interrupt_t *)0x0,
._d = 0,
.priority = priority,
.func = func,
.param = param
};
global_interrupt_pool = _merge(global_interrupt_pool, newint);
}
void init_interrupt(void)
{
uint64_t cntfrq_el0;
W_SYSREG(cntp_ctl_el0, 1);
R_SYSREG(cntfrq_el0, cntfrq_el0);
W_SYSREG(cntp_tval_el0, cntfrq_el0);
_enable_timer_irq(true);
_enable_interrupt();
}
void irq_handler(void)
{
// uint64_t core0_irq_source = *CORE0_IRQ_SOURCE;
// DEBUG_EXCEP(core0_irq_source);
if (_irq_source_timer())
timer_irq_handler();
if (_irq_source_uart())
uart_irq_handler();
}
void wfe(void)
{
if (!global_interrupt_pool) {
// asm volatile("wfe");
asm volatile("nop");
return;
}
interrupt_t *interrupt = global_interrupt_pool;
global_interrupt_pool = _merge(global_interrupt_pool->_l,
global_interrupt_pool->_r);
interrupt->func(interrupt->param);
}

114
kernel/lib/kmalloc.c Normal file
View File

@@ -0,0 +1,114 @@
#include <uart.h>
#include <errcode.h>
#include <utils.h>
#include <kmalloc.h>
#include <stddef.h>
#include <mman.h>
extern uint64_t __heap_start;
extern uint64_t __heap_end;
void *(*kmalloc)(size_t size) = simple_alloc;
void (*kfree)(void *ptr) = (void (*)(void *))0x0;
kmalloc_allocator_t mman_kmalloc_pool[KMALLOC_MAX_ALLOCATOR_SIZE + 1];
void *_heap_top = (void *)0x0;
void init_mman_kmalloc()
{
for (int i = 1; i <= KMALLOC_MAX_ALLOCATOR_SIZE; ++i)
mman_kmalloc_pool[i] = (kmalloc_allocator_t){
.left = 0,
.page_begin = (kmalloc_header_t *)0x0,
};
kmalloc = mman_alloc;
kfree = mman_free;
}
// simple 8-byte aligned linear allocation
void *simple_alloc(size_t size)
{
if (!_heap_top) {
_heap_top = (void *)&__heap_start;
}
size = (size_t)ALIGN8(size);
if ((uint64_t)_heap_top + size >= (uint64_t)&__heap_end)
exit(ERR_NO_MEM);
void *ret = _heap_top;
_heap_top = (void *)((uint64_t)_heap_top + size);
return ret;
}
#define PAGE_HEADER(ptr) ((kmalloc_header_t *)(((uint64_t)(ptr) >> 12) << 12))
void *mman_alloc(size_t unit)
{
unit = (size_t)ALIGN8(unit);
if (unit > (KMALLOC_MAX_ALLOCATOR_SIZE << 3))
return allocate_page(((unit - 1) >> 12) + 1);
kmalloc_allocator_t *pool = &mman_kmalloc_pool[unit >> 3];
if (!pool->left) {
void *page = allocate_page(1), *ptr = page + sizeof(kmalloc_header_t);
*(kmalloc_header_t *)page = (kmalloc_header_t){
.unit = unit,
.left = (PAGE_SIZE - sizeof(kmalloc_header_t)) / unit,
.begin = page + sizeof(kmalloc_header_t),
.page_prev = (kmalloc_header_t *)0x0,
.page_next = (kmalloc_header_t *)0x0,
};
*pool = (kmalloc_allocator_t){
.left = ((kmalloc_header_t *)page)->left,
.page_begin = (kmalloc_header_t *)page,
};
for (; ptr + unit <= page + PAGE_SIZE; ptr += unit)
*(void **)ptr = ptr + unit;
}
void *ret = pool->page_begin->begin;
pool->page_begin->begin = *(void **)pool->page_begin->begin;
--pool->left;
--pool->page_begin->left;
if (!pool->page_begin->left)
pool->page_begin = *(void **)pool->page_begin->page_next;
return ret;
}
void mman_free(void *ptr)
{
if (ptr == ALIGN4K(ptr)) {
free_page(ptr);
return;
}
size_t unit = PAGE_HEADER(ptr)->unit;
kmalloc_allocator_t *pool = &mman_kmalloc_pool[unit >> 3];
if (!PAGE_HEADER(ptr)->left) {
PAGE_HEADER(ptr)->page_next = pool->page_begin;
pool->page_begin->page_prev = PAGE_HEADER(ptr);
pool->page_begin = PAGE_HEADER(ptr);
}
*(void **)ptr = pool->page_begin->begin;
pool->page_begin->begin = ptr;
++pool->left;
++PAGE_HEADER(ptr)->left;
size_t cap = (PAGE_SIZE - sizeof(kmalloc_allocator_t)) / unit;
if (PAGE_HEADER(ptr)->left == cap && pool->left >= 2 * cap) {
if (PAGE_HEADER(ptr)->page_prev)
PAGE_HEADER(ptr)->page_prev->page_next = PAGE_HEADER(ptr)->page_next;
if (PAGE_HEADER(ptr)->page_next)
PAGE_HEADER(ptr)->page_next->page_prev = PAGE_HEADER(ptr)->page_prev;
free_page(PAGE_HEADER(ptr));
}
}

248
kernel/lib/mman.c Normal file
View File

@@ -0,0 +1,248 @@
#include <mman.h>
#include <logger.h>
#include <errcode.h>
#include <string.h>
#include <utils.h>
#include <kmalloc.h>
#include <dtb.h>
#include <initrd.h>
extern uint64_t __kernel_start;
extern uint64_t __kernel_end;
extern uint64_t __heap_start;
extern uint64_t __stack_end;
fdt_callback_t mman_dtb_memory_cb = {
.name = "memory@0",
.func = mman_fdt_memory_cb_func,
};
void *mman_memory_start = 0x0;
void *mman_memory_end = 0x0;
size_t mman_page_cnt = 0;
page_header_t *mman_frame_array = 0x0;
void mman_fdt_memory_cb_func(const vector_t *props)
{
for (int i = 0; i < (int)props->size; ++i) {
if (!strcmp(VEC_AT(fdt_prop_t, props, i)->name, "reg")) {
mman_memory_start = (void *)(uint64_t)ntoh32(
*((uint32_t *)VEC_AT(fdt_prop_t, props, i)->value));
mman_memory_end = (void *)(uint64_t)ntoh32(
*((uint32_t *)VEC_AT(fdt_prop_t, props, i)->value + 1));
}
}
}
// This is an array-like binary tree structure, where LCH (left-child) will
// always be the largest 2^k size block while RCH not empty.
#define CUR (&mman_frame_array[idx])
#define LIDX (((idx + 1) << 1) - 1)
#define LCH (&mman_frame_array[LIDX])
#define RIDX (((idx + 1) << 1 | 1) - 1)
#define RCH (&mman_frame_array[RIDX])
static inline
void _pull(int idx, size_t sz)
{
if (LCH->state == PAGE_FREE && RCH->state == PAGE_FREE) {
if (CUR->state != PAGE_FREE) {
LOG("node merged");
DEBUG_MEM((uint64_t)idx);
}
CUR->state = PAGE_FREE;
}
if (LCH->state != PAGE_FREE || RCH->state != PAGE_FREE)
CUR->state = PAGE_DIVIDED;
switch (CUR->state) {
case PAGE_FREE:
CUR->maxsz = sz;
break;
case PAGE_DIVIDED:
CUR->maxsz = MAX(LCH->maxsz, RCH->maxsz);
break;
case PAGE_ALLOCATED:
case PAGE_RESERVED:
CUR->maxsz = 0;
break;
default:
exit(ERR_UNREACHABLE);
}
}
void mman_init()
{
mman_memory_start = ALIGN4K(mman_memory_start);
mman_memory_end = ALIGN4K(mman_memory_end);
// 4KB per page
mman_page_cnt = (mman_memory_end - mman_memory_start) >> 12;
mman_frame_array = simple_alloc((mman_page_cnt << 1) * sizeof(page_header_t));
LOG(mman_memory_start);
LOG(mman_memory_end);
DEBUG_MEM((uint64_t)mman_page_cnt);
mman_frame_array[0] = (page_header_t){
.state = PAGE_FREE,
.maxsz = msb64(mman_page_cnt),
};
fdt_reserve_entry_t *entry = 0x0;
for (int i = 0; i < (int)dtb_reserved_entries->size; ++i) {
entry = VEC_AT(fdt_reserve_entry_t, dtb_reserved_entries, i);
LOG(ntoh64(entry->address));
DEBUG_MEM(ntoh64(entry->address) + ntoh64(entry->size));
reserve_page((void *)ntoh64(entry->address),
(void *)ntoh64(entry->address) + ntoh64(entry->size));
}
reserve_page(&__kernel_start, &__kernel_end);
reserve_page(&__heap_start, &__stack_end);
reserve_page(dtb_start, dtb_end);
reserve_page(initrd_start, initrd_end);
init_mman_kmalloc();
}
static inline
uint64_t _allocate_page(size_t req, int idx, uint64_t l, uint64_t r)
{
uint64_t sz = r - l;
if (req > sz || req > CUR->maxsz) {
return MMAN_NO_PAGE;
}
uint64_t m = l + ((msb64(sz) == sz) ? (sz >> 1) : msb64(sz));
switch (CUR->state) {
case PAGE_FREE:
if (req == sz) {
LOG("page allocated");
LOG(l);
DEBUG_MEM(r);
CUR->state = PAGE_ALLOCATED;
CUR->maxsz = 0;
return l;
}
LCH->state = RCH->state = PAGE_FREE;
LCH->maxsz = msb64(m - l);
RCH->maxsz = msb64(r - m);
break;
case PAGE_DIVIDED:
break;
case PAGE_ALLOCATED:
case PAGE_RESERVED:
return MMAN_NO_PAGE;
default:
exit(ERR_UNREACHABLE);
}
uint64_t ret = MMAN_NO_PAGE;
if (ret == MMAN_NO_PAGE && LCH->maxsz >= req)
ret = _allocate_page(req, LIDX, l, m);
if (ret == MMAN_NO_PAGE && RCH->maxsz >= req)
ret = _allocate_page(req, RIDX, m, r);
_pull(idx, sz);
return ret;
}
void *allocate_page(size_t page_cnt)
{
if (msb64(page_cnt) != page_cnt)
exit(ERR_INVALID_OP);
uint64_t offset = _allocate_page(page_cnt, 0, 0, mman_page_cnt);
if (offset == MMAN_NO_PAGE)
exit(ERR_NO_MEM);
// return (void *)0x0;
return mman_memory_start + offset * (1 << 12);
}
static inline
void _free_page(uint64_t req, int idx, uint64_t l, uint64_t r)
{
uint64_t sz = r - l;
switch (CUR->state) {
case PAGE_FREE:
return;
case PAGE_ALLOCATED:
if (req == l) {
LOG("page freed");
LOG(l);
DEBUG_MEM(r);
CUR->state = PAGE_FREE;
CUR->maxsz = sz;
return;
}
case PAGE_DIVIDED:
break;
case PAGE_RESERVED:
default:
exit(ERR_UNREACHABLE);
}
uint64_t m = l + ((msb64(sz) == sz) ? (sz >> 1) : msb64(sz));
if (l <= req && req < m)
_free_page(req, LIDX, l, m);
if (m <= req && req < r)
_free_page(req, RIDX, m, r);
_pull(idx, sz);
}
void free_page(void *page)
{
if (ALIGN4K(page) != page)
exit(ERR_INVALID_OP);
uint64_t start = ((uint64_t)page - (uint64_t)mman_memory_start) >> 12;
_free_page(start, 0, 0, mman_page_cnt);
}
static inline
void _reserve_page(uint64_t ql, uint64_t qr, int idx, uint64_t l, uint64_t r)
{
if (qr <= l || r <= ql)
return;
uint64_t sz = r - l;
if (ql <= l && r <= qr && msb64(sz) == sz) {
if (CUR->state == PAGE_RESERVED)
return;
if (CUR->state != PAGE_FREE)
exit(ERR_INVALID_MEM);
LOG("page reserved");
LOG(l);
DEBUG_MEM(r);
CUR->state = PAGE_RESERVED;
CUR->maxsz = 0;
return;
}
uint64_t m = l + ((msb64(sz) == sz) ? (sz >> 1) : msb64(sz));
if (CUR->state == PAGE_FREE) {
LCH->state = RCH->state = PAGE_FREE;
LCH->maxsz = msb64(m - l);
RCH->maxsz = msb64(r - m);
}
if (ql < m)
_reserve_page(ql, qr, LIDX, l, m);
if (m < qr)
_reserve_page(ql, qr, RIDX, m, r);
_pull(idx, sz);
}
void reserve_page(void *begin, void *end)
{
uint64_t ql = ((uint64_t)begin - (uint64_t)mman_memory_start) >> 12;
uint64_t qr = (((uint64_t)end - (uint64_t)mman_memory_start - 1) >> 12) + 1;
LOG("reserve page");
LOG(ql);
DEBUG_MEM(qr);
_reserve_page(ql, qr, 0, 0, mman_page_cnt);
}

57
kernel/lib/queue.c Normal file
View File

@@ -0,0 +1,57 @@
#include <queue.h>
#include <errcode.h>
#include <utils.h>
#include <kmalloc.h>
queue_t *make_queue()
{
queue_t *ret = kmalloc(sizeof(queue_t));
ret->size = 0;
ret->begin = kmalloc(sizeof(queue_node_t));
ret->end = kmalloc(sizeof(queue_node_t));
*ret->begin = *ret->end = (queue_node_t){
.prev = (queue_node_t *)ret->begin,
.next = (queue_node_t *)ret->end,
.value = 0,
};
return ret;
}
uint64_t queue_back(const queue_t *queue)
{
if (!queue->size)
exit(ERR_OUT_OF_BOUND);
return queue->end->prev->value;
}
uint64_t queue_front(const queue_t *queue)
{
if (!queue->size)
exit(ERR_OUT_OF_BOUND);
return queue->begin->next->value;
}
void queue_push_back(queue_t *queue, uint64_t val)
{
queue->end->value = val;
queue->end->next = kmalloc(sizeof(queue_node_t));
*queue->end->next = (queue_node_t){
.prev = queue->end,
.next = queue->end->next,
.value = 0,
};
queue->end = queue->end->next;
}
void queue_push_front(queue_t *queue, uint64_t val)
{
queue->begin->value = val;
queue->begin->prev = kmalloc(sizeof(queue_node_t));
*queue->begin->prev = (queue_node_t){
.prev = queue->begin->prev,
.next = queue->begin,
.value = 0,
};
queue->begin = queue->begin->prev;
}

55
kernel/lib/ringbuffer.c Normal file
View File

@@ -0,0 +1,55 @@
#include <ringbuffer.h>
#include <utils.h>
#include <errcode.h>
#include <stddef.h>
#include <kmalloc.h>
ringbuffer_t *make_ringbuffer(size_t size)
{
ringbuffer_t *ret = kmalloc(sizeof(ringbuffer_t));
uint8_t *data = kmalloc(size * sizeof(uint8_t));
*ret = (ringbuffer_t){
.size = 0,
.cap = size,
.data = data,
.read = data,
.write = data,
};
return ret;
}
int ringbuffer_push(ringbuffer_t *buf, uint8_t val)
{
if (buf->size == buf->cap)
return ERR_OUT_OF_BOUND;
*buf->write++ = val;
if (buf->write == buf->data + buf->cap)
buf->write = buf->data;
++buf->size;
return NO_ERROR;
}
uint8_t ringbuffer_bump(ringbuffer_t *buf)
{
if (buf->size == 0)
exit(ERR_INVALID_OP);
uint8_t ret = *buf->read++;
if (buf->read == buf->data + buf->cap)
buf->read = buf->data;
--buf->size;
return ret;
}
uint8_t ringbuffer_peek(ringbuffer_t *buf)
{
if (buf->size == 0)
exit(ERR_INVALID_OP);
return *buf->read;
}

231
kernel/lib/shell.c Normal file
View File

@@ -0,0 +1,231 @@
#include <stddef.h>
#include <logger.h>
#include <timer.h>
#include <errcode.h>
#include <kmalloc.h>
#include <utils.h>
#include <string.h>
#include <uart.h>
#include <mbox.h>
#include <shell.h>
#include <exec.h>
#include <mman.h>
#define INPUT_BUFLEN 1000
#define PM_PASSWORD 0x5a000000
#define PM_RSTC 0x3F10001c
#define PM_WDOG 0x3F100024
static inline
void _help (void)
{
uart_puts(
"help : print this help menu" ENDL
"hello : print Hello World!" ENDL
"hwinfo : print hardware info" ENDL
"memalloc <size> : alloate memory and print" ENDL
"ls : list directory contents" ENDL
"cat <file> : concatenate files and print" ENDL
"exec <file> : execute file in usermode" ENDL
"settimeout <sec> <message...>: pring message after a few seconds" ENDL
"reboot : reboot the device" ENDL
);
}
static inline
void _hello (void)
{
uart_puts("hello, world" ENDL);
}
static inline
void _hwinfo (void)
{
uart_puts(
"hwinfo: " ENDL
"board revision: "
);
uart_hex(get_board_revision());
uart_puts(
ENDL
"memory base addr: "
);
uart_hex(get_memory_base_addr());
uart_puts(
ENDL
"memory size: "
);
uart_hex(get_memory_size());
uart_puts(ENDL);
}
static inline
void _memalloc(size_t size)
{
void *addr = kmalloc(size);
uart_puts("size: ");
uart_hex(size);
uart_puts(ENDL);
uart_puts("addr: ");
uart_hex((uint64_t)addr);
uart_puts(ENDL);
}
static inline
void _ls_initrd_callback(file_node_t *tr)
{
uart_puts(tr->filename);
uart_puts(ENDL);
}
static inline
void _ls(file_node_t *root)
{
initrd_traverse(root, _ls_initrd_callback);
}
static inline
void _cat(file_node_t *root, const char *filename)
{
file_node_t *tr = initrd_get(root, filename);
if (tr) {
uart_puts((char *)tr->filecontent);
} else {
exit(ERR_NOT_EXIST);
}
}
static inline
void _exec(file_node_t *root, const char *filename)
{
file_node_t *tr = initrd_get(root, filename);
if (tr) {
void *userspace = allocate_page(1 << 6);
memcpy(userspace, tr->filecontent, tr->filesize);
user_exec(userspace, userspace + (1 << (12 + 6)) - 8);
kfree(userspace);
} else {
exit(ERR_NOT_EXIST);
}
}
static inline
void _settimeout_cb_func(uint64_t args)
{
vector_t *v = (void *)args;
for (int i = 2; i < (int)v->size; ++i) {
uart_puts(VEC_AT(char, v, i));
uart_puts(" ");
}
uart_puts(ENDL);
}
static inline
void _settimeout(int32_t sec, vector_t *args)
{
uint64_t cntpct_el0, cntfrq_el0;
R_SYSREG(cntpct_el0, cntpct_el0);
R_SYSREG(cntfrq_el0, cntfrq_el0);
task_t task = (task_t){
.firing_tick = cntpct_el0 + sec * cntfrq_el0,
.interval = sec * cntfrq_el0,
.repeat = 1,
.func = _settimeout_cb_func,
.param = (uint64_t)args,
};
add_task(task);
}
static inline
void _set(long addr, unsigned int value) {
volatile unsigned int* point = (unsigned int*)addr;
*point = value;
}
static inline
void _reset(int tick) { // reboot after watchdog timer expire
_set(PM_RSTC, PM_PASSWORD | 0x20); // full reset
_set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick
}
static inline
void _reboot(void)
{
_reset(1 << 16);
}
char *_shell_buf = (char *)0x0;
int _shell_sz = 0;
static inline
int _shell_operations(char ch)
{
switch (ch) {
case 0x7f:
if (_shell_sz > 0) {
--_shell_sz;
uart_puts("\b \b");
}
return true;
default:
}
return false;
}
int shell(file_node_t *initrd_root)
{
uart_puts("# ");
char ch;
_shell_buf = kmalloc(INPUT_BUFLEN * sizeof(char));
_shell_sz = 0;
while ((ch = uart_getc()) != '\n') {
if (_shell_operations(ch))
continue;
_shell_buf[_shell_sz++] = ch;
uart_putb((const uint8_t *)&ch, 1);
}
uart_puts(ENDL);
_shell_buf[_shell_sz] = ' ';
vector_t *args = make_vector(0);
for (char *saveptr = 0x0, *tok = strtok_r(_shell_buf, " ", &saveptr);
tok; tok = strtok_r((char *)0x0, " ", &saveptr)) {
VEC_PUSH(args, tok);
LOG(tok);
}
// DEBUG("ENDL");
CLEAN;
char *cmd = args->size ? VEC_AT(char, args, 0) : (char *)0x0;
if (!strcmp(cmd, "help")) {
_help();
} else if (!strcmp(cmd, "hello")) {
_hello();
} else if (!strcmp(cmd, "hwinfo")) {
_hwinfo();
} else if (!strcmp(cmd, "memalloc") && args->size >= 2){
char *p1 = VEC_AT(char, args, 1);
_memalloc((size_t)atoi32(p1));
} else if (!strcmp(cmd, "ls")) {
_ls(initrd_root);
} else if (!strcmp(cmd, "cat") && args->size >= 2) {
char *p1 = VEC_AT(char, args, 1);
_cat(initrd_root, p1);
} else if (!strcmp(cmd, "exec") && args->size >= 2) {
char *p1 = VEC_AT(char, args, 1);
_exec(initrd_root, p1);
} else if (!strcmp(cmd, "settimeout") && args->size >= 2) {
char *p1 = VEC_AT(char, args, 1);
_settimeout(atoi32(p1), args);
} else if (!strcmp(cmd, "reboot")) {
_reboot();
}
return true;
}

108
kernel/lib/timer.c Normal file
View File

@@ -0,0 +1,108 @@
#include <timer.h>
#include <interrupt.h>
#include <logger.h>
#include <utils.h>
#include <kmalloc.h>
#define CORE0_TIMER_IRQ_CTRL ((volatile uint32_t *)0x40000040)
timer_t *global_timer = (timer_t *)0x0;
MMIO_W_HELPER(_enable_timer_irq, CORE0_TIMER_IRQ_CTRL, 0x1, 1);
static inline
uint32_t _d(timer_t *t)
{ return t ? t->_d : 0; }
static inline
void _swap(timer_t **a, timer_t **b)
{
timer_t *tmp = *a;
*a = *b, *b = tmp;
}
static inline
timer_t *_merge(timer_t *a, timer_t *b)
{
if (!a || !b)
return a ?: b;
if (a->data.firing_tick > b->data.firing_tick)
_swap(&a, &b);
a->_r = _merge(a->_r, b);
if (_d(a->_l) < _d(a->_r))
_swap(&a->_l, &a->_r);
a->_d = _d(a->_r) + 1;
return a;
}
static inline
timer_t *_pop(timer_t *t)
{
if (!t || (!t->_l && !t->_r))
return (timer_t *)0x0;
return _merge(t->_l, t->_r);
}
static inline
void _set_timer_interrrupt()
{
if (global_timer) {
uint64_t cntpct_el0;
R_SYSREG(cntpct_el0, cntpct_el0);
DEBUG_EXCEP(cntpct_el0);
uint64_t firing_tick = MAX(global_timer->data.firing_tick, cntpct_el0);
W_SYSREG(cntp_cval_el0, firing_tick);
_enable_timer_irq(true);
}
}
static inline
void _traverse(timer_t *t)
{
if (!t) return;
DEBUG_EXCEP(t->data.firing_tick);
t->data.func(t->data.param);
_traverse(t->_l);
_traverse(t->_r);
}
void add_task(task_t task)
{
DEBUG_EXCEP("add task");
timer_t *newtimer = kmalloc(sizeof(timer_t));
*newtimer = (timer_t){
._l = (timer_t *)0x0,
._r = (timer_t *)0x0,
._d = 0,
.data = task,
};
global_timer = _merge(global_timer, newtimer);
_traverse(global_timer);
_set_timer_interrrupt();
}
void timer_irq_handler(void)
{
_enable_timer_irq(false);
LOG("timer irq");
uint64_t cntpct_el0;
R_SYSREG(cntpct_el0, cntpct_el0);
DEBUG_EXCEP(cntpct_el0);
if (global_timer) {
add_interrupt_task(20, global_timer->data.func, global_timer->data.param);
global_timer = _pop(global_timer);
}
_set_timer_interrrupt();
}

211
kernel/lib/uart.c Normal file
View File

@@ -0,0 +1,211 @@
#include <uart.h>
#include <kmalloc.h>
#include <interrupt.h>
#include <logger.h>
#include <errcode.h>
#include <utils.h>
#include <string.h>
#include <gpio.h>
#include <stddef.h>
#include <ringbuffer.h>
/* Auxilary mini UART registers */
#define AUX_ENABLE ((volatile uint32_t*)(MMIO_BASE + 0x00215004))
#define AUX_MU_IO ((volatile uint32_t*)(MMIO_BASE + 0x00215040))
#define AUX_MU_IER ((volatile uint32_t*)(MMIO_BASE + 0x00215044))
#define AUX_MU_IIR ((volatile uint32_t*)(MMIO_BASE + 0x00215048))
#define AUX_MU_LCR ((volatile uint32_t*)(MMIO_BASE + 0x0021504C))
#define AUX_MU_MCR ((volatile uint32_t*)(MMIO_BASE + 0x00215050))
#define AUX_MU_LSR ((volatile uint32_t*)(MMIO_BASE + 0x00215054))
#define AUX_MU_MSR ((volatile uint32_t*)(MMIO_BASE + 0x00215058))
#define AUX_MU_SCRATCH ((volatile uint32_t*)(MMIO_BASE + 0x0021505C))
#define AUX_MU_CNTL ((volatile uint32_t*)(MMIO_BASE + 0x00215060))
#define AUX_MU_STAT ((volatile uint32_t*)(MMIO_BASE + 0x00215064))
#define AUX_MU_BAUD ((volatile uint32_t*)(MMIO_BASE + 0x00215068))
#define ARMINT_En_IRQs1 ((volatile uint32_t*)(MMIO_BASE + 0x0000b210))
size_t (*uart_putb)(const uint8_t *bytes, size_t len) = uart_putb_sync;
size_t (*uart_getb)(uint8_t *bytes, size_t len) = uart_getb_sync;
int is_uart_inited = false;
ringbuffer_t *uart_readbuf;
ringbuffer_t *uart_writebuf;
MMIO_W_HELPER(_uart_enable_receive_interrupt, AUX_MU_IER, 0x1, 0);
MMIO_W_HELPER(_uart_enable_transmit_interrupt, AUX_MU_IER, 0x1, 1);
MMIO_W_HELPER(_uart_clear_receive_fifo, AUX_MU_IIR, 0x1, 1);
MMIO_W_HELPER(_uart_clear_transmit_fifo, AUX_MU_IIR, 0x1, 2);
MMIO_W_HELPER(_uart_write_data, AUX_MU_IO, 0xff, 0);
MMIO_W_HELPER(_uart_interrupt_controller, ARMINT_En_IRQs1, 0x1, 29);
MMIO_R_HELPER(_uart_interrupt_pending, AUX_MU_IIR, 0x1, 0);
MMIO_R_HELPER(_uart_transmit_interrupt, AUX_MU_IIR, 0x1, 1);
MMIO_R_HELPER(_uart_receive_interrupt, AUX_MU_IIR, 0x1, 2);
MMIO_R_HELPER(_uart_transmitter_idle, AUX_MU_LSR, 0x1, 5);
MMIO_R_HELPER(_uart_data_ready, AUX_MU_LSR, 0x1, 0);
MMIO_R_HELPER(_uart_read_data, AUX_MU_IO, 0xff, 0);
void uart_init(void)
{
register uint32_t r;
/* initialize UART */
*AUX_ENABLE |= 1; // enable UART1, AUX mini uart
*AUX_MU_CNTL = 0; // disable Tx, Rx
*AUX_MU_LCR = 3; // set 8 bits
*AUX_MU_MCR = 0;
*AUX_MU_IER = 0; // disable interrupt by default
*AUX_MU_IIR = 0x6; // clear tx, rx FIFO
*AUX_MU_BAUD = 270; // 115200 baud
/* map UART1 to GPIO pins */
r = *GPFSEL1;
r &= ~((7 << 12) | (7 << 15)); // gpio14, gpio15
r |= (2 << 12) | (2 << 15); // alt5
*GPFSEL1 = r;
*GPPUD = 0; // enable pins 14 and 15
r = 150; while (r--) { asm volatile("nop"); }
*GPPUDCLK0 = (1 << 14) | (1 << 15);
r = 150; while (r--) { asm volatile("nop"); }
*GPPUDCLK0 = 0; // flush GPIO setup
*AUX_MU_CNTL = 3; // enable Tx, Rx
_uart_interrupt_controller(true);
uart_readbuf = make_ringbuffer(UART_BUFLEN);
uart_writebuf = make_ringbuffer(UART_BUFLEN);
_uart_enable_receive_interrupt(true);
//uint64_t ier = *AUX_MU_IER;
uart_getb = uart_getb_async;
uart_putb = uart_putb_async;
is_uart_inited = true;
}
void uart_transmit_interrupt_handler()
{
if (uart_writebuf->size > 0)
_uart_write_data(ringbuffer_bump(uart_writebuf));
}
typedef struct {
ringbuffer_t *buf;
uint8_t val;
} uart_interrupt_callback_payload_t;
static inline
void uart_receive_interrupt_callback(uint64_t param)
{
uart_interrupt_callback_payload_t *payload = (void *)param;
ringbuffer_push(payload->buf, payload->val);
kfree(payload);
}
void uart_receive_interrupt_handler()
{
if (uart_readbuf->size < uart_readbuf->cap) {
uint8_t b = _uart_read_data();
uart_interrupt_callback_payload_t *param = kmalloc(
sizeof(uart_interrupt_callback_payload_t));
*param = (uart_interrupt_callback_payload_t){
.buf = uart_readbuf,
.val = b,
};
add_interrupt_task(10, uart_receive_interrupt_callback, (uint64_t)param);
}
}
void uart_irq_handler(void)
{
_uart_enable_receive_interrupt(false);
_uart_enable_transmit_interrupt(false);
if (_uart_receive_interrupt())
uart_receive_interrupt_handler();
if (_uart_transmit_interrupt())
uart_transmit_interrupt_handler();
_uart_enable_receive_interrupt(true);
if (uart_writebuf->size > 0)
_uart_enable_transmit_interrupt(true);
}
size_t uart_putb_async(const uint8_t *bytes, size_t len)
{
size_t sentlen = 0;
for (; sentlen < len; ++bytes, ++sentlen)
ringbuffer_push(uart_writebuf, *bytes);
if (uart_writebuf->size > 0)
_uart_enable_transmit_interrupt(true);
return sentlen;
}
size_t uart_putb_sync(const uint8_t *bytes, size_t len)
{
size_t sentlen = 0;
for (; sentlen < len; ++bytes, ++sentlen) {
do asm volatile("nop"); // busy waiting
while (!_uart_transmitter_idle());
_uart_write_data(*bytes);
}
return sentlen;
}
size_t uart_getb_async(uint8_t *bytes, size_t len)
{
size_t recvlen = 0;
for (; recvlen < len; ++bytes, ++recvlen) {
while (!uart_readbuf->size)
wfe(); // wait for interrupt
*bytes = ringbuffer_bump(uart_readbuf);
}
return recvlen;
}
size_t uart_getb_sync(uint8_t *bytes, size_t len)
{
size_t recvlen = 0;
for (; recvlen < len; ++bytes, ++recvlen) {
do asm volatile("nop");
while (!_uart_data_ready());
*bytes = _uart_read_data();
}
return recvlen;
}
char uart_getc(void)
{
char r;
uart_getb((uint8_t *)&r, 1);
return r == '\r' ? '\n' : r;
}
void uart_puts(const char *s)
{
size_t len = strlen(s);
size_t ret = uart_putb((const uint8_t *)s, len);
if (ret != len)
exit(ERR_IO_FAILED);
}
void uart_hex(uint64_t d)
{
char buf[0x11], *p = buf;
uint64_t n;
for (int c = 28; c >= 0; c -= 4) {
n = (d >> c) & 0xf;
n += n > 9 ? (char)'A' : (char)'0';
*p++ = n;
}
*p = '\0';
uart_puts(buf);
}

View File

@@ -4,18 +4,24 @@
uint32_t msb32(uint32_t x)
{
static const int msb[32] = {
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
};
uint32_t res = 0x0;
asm volatile(
"clz %[res], %[val]"
: [res] "=r" (res)
: [val] "r" (x)
);
return res == 32 ? 0 : (1 << (31 - res));
}
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return msb[(uint32_t)(x * 0x07c4acddu) >> 27];
uint64_t msb64(uint64_t x)
{
uint64_t res = 0x0;
asm volatile(
"clz %[res], %[val]"
: [res] "=r" (res)
: [val] "r" (x)
);
return res == 64 ? 0 : ((uint64_t)1 << (63 - res));
}
uint32_t hton32(const uint32_t h)

View File

@@ -21,12 +21,12 @@ vector_t *make_vector(size_t size)
uint64_t vec_at(const vector_t *vec, size_t idx)
{
if (idx >= vec->size)
exit(ERR_VECTOR_OOR);
exit(ERR_OUT_OF_BOUND);
return vec->data[idx];
}
vector_t *vec_push(vector_t *vec, uint64_t val)
void vec_push(vector_t *vec, uint64_t val)
{
if (vec->size == vec->cap) {
uint64_t *old = vec->data;
@@ -35,5 +35,4 @@ vector_t *vec_push(vector_t *vec, uint64_t val)
}
vec->data[vec->size++] = val;
return vec;
}

View File

@@ -25,9 +25,11 @@ SECTIONS
__bss_end = .;
} >DATA
__stack_end = ORIGIN(RAM) + LENGTH(RAM);
}
__heap_start = ORIGIN(RAM);
__heap_end = ORIGIN(RAM) + 32M;
__bss_size = (__bss_end - __bss_start)>>3;
PROVIDE(__kernel_start = ORIGIN(TEXT));
PROVIDE(__kernel_end = ORIGIN(DATA) + LENGTH(DATA));
PROVIDE(__heap_start = ORIGIN(RAM));
PROVIDE(__heap_end = ORIGIN(RAM) + 32M);
PROVIDE(__stack_end = ORIGIN(RAM) + LENGTH(RAM));
PROVIDE(__bss_size = (__bss_end - __bss_start)>>3);

View File

@@ -1,25 +1,117 @@
#include <logger.h>
#include <timer.h>
#include <kmalloc.h>
#include <uart.h>
#include <dtb.h>
#include <initrd.h>
#include <mman.h>
#include <shell.h>
#include <vector.h>
#include <utils.h>
#include <exception.h>
#include <interrupt.h>
void init(void *dtb, file_node_t **initrd_root)
{
init_exception();
// UART
uart_init();
// Device tree
DEBUG_DTB(dtb);
dtb_start = dtb;
vector_t *dtb_struct_cbs = make_vector(0);
VEC_PUSH(dtb_struct_cbs, &initrd_dtb_cb);
VEC_PUSH(dtb_struct_cbs, &mman_dtb_memory_cb);
fdt_traverse(dtb_struct_cbs);
DEBUG_DTB("device tree parse done");
// Initramfs
DEBUG_INITRD(initrd_start);
*initrd_root = initrd_init();
// Memory (Buddy system)
mman_init();
init_interrupt();
}
static inline
void _print_time(uint64_t)
{
uint64_t cntpct_el0, cntfrq_el0;
R_SYSREG(cntpct_el0, cntpct_el0);
R_SYSREG(cntfrq_el0, cntfrq_el0);
DEBUG_EXCEP(cntpct_el0 / cntfrq_el0);
task_t task = {
.firing_tick = cntpct_el0 + 2 * cntfrq_el0,
.interval = 2 * cntfrq_el0,
.repeat = 1,
.func = _print_time,
.param = 0x0,
};
add_task(task);
}
void main(void *dtb)
{
uart_init();
uart_getc();
DEBUG(dtb);
file_node_t *initrd_root = 0x0;
init(dtb, &initrd_root);
dtb_addr = dtb;
vector_t *dtb_cbs = make_vector(0);
VEC_PUSH(dtb_cbs, &initrd_dtb_cb);
fdt_traverse(dtb_cbs);
// LOG("system booting in");
// _print_time(0x0);
DEBUG(initrd_start);
DEBUG(initrd_end);
uint64_t el;
R_SYSREG(el, CurrentEL);
INFOR(el);
file_node_t *initrd_root = initrd_init();
void *page1 = allocate_page(1);
INFOR(page1);
void *page2 = allocate_page(2);
INFOR(page2);
void *page4 = allocate_page(4);
INFOR(page4);
void *page16 = allocate_page(16);
INFOR(page16);
free_page(page1);
free_page(page2);
free_page(page4);
free_page(page16);
void *page32 = allocate_page(32);
INFOR(page32);
page1 = allocate_page(1);
INFOR(page1);
free_page(page1);
void *kmalloc8 = kmalloc(8);
INFOR(kmalloc8);
kfree(kmalloc8);
kmalloc8 = kmalloc(8);
INFOR(kmalloc8);
kfree(kmalloc8);
void *kmalloc7k = kmalloc(7 * (1 << 10));
INFOR(kmalloc7k);
void *kmalloc8k = kmalloc(1 << 13);
INFOR(kmalloc8k);
kfree(kmalloc7k);
kfree(kmalloc8k);
page1 = allocate_page(1);
INFOR(page1);
int shell_cont = 1;
while (shell_cont) {

View File

@@ -1,40 +0,0 @@
#include <uart.h>
#include <errcode.h>
#include <utils.h>
#include <kmalloc.h>
#include <stddef.h>
extern uint64_t __heap_start;
extern uint64_t __heap_end;
void *_heap_top = (void *)0;
// simple 8-byte aligned linear allocation
void *simple_alloc(size_t size)
{
if (!_heap_top) {
_heap_top = (void *)&__heap_start;
}
if (size & 0xff)
size = (size & ~0xff) + 0x100;
if ((uint64_t)_heap_top + size >= (uint64_t)&__heap_end)
exit(ERR_NO_MEM);
void *ret = _heap_top;
_heap_top = (void *)((uint64_t)_heap_top + size);
return ret;
}
void *kmalloc(size_t size)
{
return simple_alloc(size);
}
void kfree(void *ptr)
{
// not implemented for now
return;
}

4
lib/logger.c Normal file
View File

@@ -0,0 +1,4 @@
#include <logger.h>
char logger_buf[LOGGER_BUFLEN];
char *logger_cur = logger_buf;

View File

@@ -1,130 +0,0 @@
#include <stddef.h>
#include <utils.h>
#include <string.h>
#include <uart.h>
#include <mbox.h>
#include <shell.h>
#define INPUT_BUFLEN 1000
#define PM_PASSWORD 0x5a000000
#define PM_RSTC 0x3F10001c
#define PM_WDOG 0x3F100024
void help (void)
{
uart_puts(
"help : print this help menu" ENDL
"hello : print Hello World!" ENDL
"hwinfo: print hardware info" ENDL
"ls : list directory contents" ENDL
"cat : concatenate files and print" ENDL
"reboot: reboot the device" ENDL
);
}
void hello (void)
{
uart_puts("hello, world" ENDL);
}
void hwinfo (void)
{
uart_puts(
"hwinfo: " ENDL
"board revision: "
);
uart_hex(get_board_revision());
uart_puts(
ENDL
"memory base addr: "
);
uart_hex(get_memory_base_addr());
uart_puts(
ENDL
"memory size: "
);
uart_hex(get_memory_size());
uart_puts(ENDL);
}
void ls_initrd_callback(file_node_t *tr)
{
uart_puts(tr->filename);
uart_puts(ENDL);
}
void ls(file_node_t *root)
{
initrd_traverse(root, ls_initrd_callback);
}
void cat(file_node_t *root, const char *filename)
{
file_node_t *tr = initrd_get(root, filename);
if (tr) {
uart_puts((char *)tr->filecontent);
} else {
uart_puts("FILE NOT EXIST!" ENDL);
}
}
void set(long addr, unsigned int value) {
volatile unsigned int* point = (unsigned int*)addr;
*point = value;
}
void reset(int tick) { // reboot after watchdog timer expire
set(PM_RSTC, PM_PASSWORD | 0x20); // full reset
set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick
}
void reboot(void)
{
reset(1 << 16);
}
int shell(file_node_t *initrd_root)
{
uart_puts("# ");
char buf[INPUT_BUFLEN], ch;
int sz = 0;
while ((ch = uart_getc()) != '\n') {
buf[sz++] = ch;
uart_send(ch);
}
uart_puts(ENDL);
buf[sz] = '\0';
const char *i = buf;
char bin[INPUT_BUFLEN], *j;
for (j = bin; *i != '\0' && !isspace(*i); ++i, ++j)
*j = *i;
*j = '\0';
for (; *i != '\0' && isspace(*i); ++i);
char param[INPUT_BUFLEN];
for (j = param; *i != '\0' && !isspace(*i); ++i, ++j)
*j = *i;
*j = '\0';
if (!strcmp(bin, "help")) {
help();
} else if (!strcmp(bin, "hello")) {
hello();
} else if (!strcmp(bin, "hwinfo")) {
hwinfo();
} else if (!strcmp(bin, "ls")) {
ls(initrd_root);
} else if (!strcmp(bin, "cat")) {
cat(initrd_root, param);
} else if (!strcmp(bin, "reboot")) {
reboot();
}
return true;
}

View File

@@ -35,6 +35,21 @@ size_t strlen(const char *str)
return ret;
}
char *strtok_r(char *restrict str, const char *restrict delimiters,
char **restrict saveptr)
{
if (str)
*saveptr = str;
for (char *ret = *saveptr; **saveptr != '\0'; ++(*saveptr)) {
for (int i = 0; delimiters[i] != '\0'; i++)
if (**saveptr == delimiters[i]) {
*(*saveptr)++ = '\0';
return ret;
}
}
return 0x0;
}
void *memcpy(void *dest, const void *src, size_t count)
{
void *ret = dest;

View File

@@ -1,131 +0,0 @@
#include <uart.h>
#include <gpio.h>
#include <stddef.h>
/* Auxilary mini UART registers */
#define AUX_ENABLE ((volatile unsigned int*)(MMIO_BASE+0x00215004))
#define AUX_MU_IO ((volatile unsigned int*)(MMIO_BASE+0x00215040))
#define AUX_MU_IER ((volatile unsigned int*)(MMIO_BASE+0x00215044))
#define AUX_MU_IIR ((volatile unsigned int*)(MMIO_BASE+0x00215048))
#define AUX_MU_LCR ((volatile unsigned int*)(MMIO_BASE+0x0021504C))
#define AUX_MU_MCR ((volatile unsigned int*)(MMIO_BASE+0x00215050))
#define AUX_MU_LSR ((volatile unsigned int*)(MMIO_BASE+0x00215054))
#define AUX_MU_MSR ((volatile unsigned int*)(MMIO_BASE+0x00215058))
#define AUX_MU_SCRATCH ((volatile unsigned int*)(MMIO_BASE+0x0021505C))
#define AUX_MU_CNTL ((volatile unsigned int*)(MMIO_BASE+0x00215060))
#define AUX_MU_STAT ((volatile unsigned int*)(MMIO_BASE+0x00215064))
#define AUX_MU_BAUD ((volatile unsigned int*)(MMIO_BASE+0x00215068))
int is_uart_init = 0;
/**
* Set baud rate and characteristics (115200 8N1) and map to GPIO
*/
void uart_init()
{
register unsigned int r;
/* initialize UART */
*AUX_ENABLE |=1; // enable UART1, AUX mini uart
*AUX_MU_IER = 0;
*AUX_MU_CNTL = 0;
*AUX_MU_LCR = 3; // 8 bits
*AUX_MU_MCR = 0;
*AUX_MU_IER = 0;
*AUX_MU_IIR = 0xc6; // disable interrupts
*AUX_MU_BAUD = 270; // 115200 baud
/* map UART1 to GPIO pins */
r=*GPFSEL1;
r&=~((7<<12)|(7<<15)); // gpio14, gpio15
r|=(2<<12)|(2<<15); // alt5
*GPFSEL1 = r;
*GPPUD = 0; // enable pins 14 and 15
r=150; while(r--) { asm volatile("nop"); }
*GPPUDCLK0 = (1<<14)|(1<<15);
r=150; while(r--) { asm volatile("nop"); }
*GPPUDCLK0 = 0; // flush GPIO setup
*AUX_MU_CNTL = 3; // enable Tx, Rx
is_uart_init = 1;
}
/**
* Send a character
*/
void uart_send(unsigned int c) {
/* wait until we can send */
do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20));
/* write the character to the buffer */
*AUX_MU_IO=c;
}
uint8_t uart_getb()
{
uint8_t r;
/* wait until something is in the buffer */
do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01));
/* read it and return */
r=(uint8_t)(*AUX_MU_IO);
return r;
}
/**
* Receive a character
*/
char uart_getc() {
char r = (char)uart_getb();
/* convert carrige return to newline */
return r=='\r'?'\n':r;
}
/**
* Display a string
*/
void uart_puts(const char *s) {
while(*s) {
/* convert newline to carrige return + newline */
if(*s=='\n')
uart_send('\r');
uart_send(*s++);
}
}
/**
* Display a binary value in hexadecimal
*/
void uart_hex(const unsigned int d) {
unsigned int n;
int c;
for(c=28;c>=0;c-=4) {
// get highest tetrad
n=(d>>c)&0xF;
// 0-9 => '0'-'9', 10-15 => 'A'-'F'
n+=n>9?0x37:0x30;
uart_send(n);
}
}
void uart_int(int d)
{
unsigned int buf[11];
int size = 0;
if (d == 0) {
uart_send((unsigned int)'0');
return;
}
int is_neg = (d < 0);
while (d != 0) {
buf[size++] = '0' + d % 10;
d /= 10;
}
if (is_neg)
uart_send((unsigned int)'-');
while (size--)
uart_send(buf[size]);
}

View File

@@ -1,15 +0,0 @@
from pwn import *
kernel = open("kernel8.img", "rb").read()
r = serialtube("/dev/ttyS5", convert_newlines=False)
input("@")
r.send(str(len(kernel))+"\n")
#print(r.recv())
#r.interactive()
print(r.recvuntil(b") : "))
r.send(kernel)
r.interactive()

13
test.py
View File

@@ -1,13 +0,0 @@
#!/usr/bin/env -S python3
from pwn import *
from struct import pack
print(sys.argv)
if len(sys.argv) < 2:
print("no args for serial device")
exit()
tube = serialtube(sys.argv[1], convert_newlines=False)
tube.interactive()

View File

@@ -26,6 +26,8 @@ while True:
r.send(kernel[len(kernel) // splitsize * splitsize:])
sleep(1)
r.send(b"\n")
r.interactive()
r.send(b"\nreboot\n")

39
userprog/Makefile Normal file
View File

@@ -0,0 +1,39 @@
MAKE := make
MAKEFLAGS += -j 8
ARCH := aarch64
GNU := $(ARCH)-linux-gnu
CC := $(GNU)-gcc
CCFLAGS += -Wall -Wextra -O0 \
-nostdinc -nostdlib -nostartfiles -nodefaultlibs \
-Wno-unused-parameter -Wno-unused-value -Wno-main -g
LD := $(GNU)-ld
LDFLAGS += -g -nostdlib -no-pie
OBJCOPY := $(GNU)-objcopy
LD_SCRIPT := linker.ld
SRCS := $(shell find . -name '*.[cS]')
OBJS := $(SRCS:%=%.o)
.PHONY: all
all: userprog
userprog: userprog.elf
$(OBJCOPY) -O binary $< $@
userprog.elf: $(LD_SCRIPT) $(OBJS)
$(LD) -o $@ -T $(LD_SCRIPT) $(OBJS) $(LDFLAGS)
%.S.o: %.S
mkdir -p $(dir $@)
$(CC) -c $< -o $@ $(CCFLAGS)
%.c.o: %.c
mkdir -p $(dir $@)
$(CC) -c $< -o $@ $(CCFLAGS)
clean:
-rm $(OBJS) userprog userprog.elf

11
userprog/Start.S Normal file
View File

@@ -0,0 +1,11 @@
.section ".text"
.global _start
_start:
mov x0, 0
loop:
add x0, x0, 1
svc 0
cmp x0, 5
blt loop
wait:
b wait

18
userprog/linker.ld Normal file
View File

@@ -0,0 +1,18 @@
ENTRY(_start)
SECTIONS
{
.text : {
*(.text.start)
*(.text)
}
.rodata : {
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}