Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
7c054743ce
|
|||
|
d31f5e02fe
|
|||
|
8d1045f20d
|
|||
|
e73f90395d
|
|||
|
981cae803b
|
|||
|
02b2a87fed
|
|||
|
8ea82f927b
|
|||
|
75edf55dd3
|
|||
|
3c03c9d383
|
|||
|
c4a44542ef
|
|||
|
89ff8a018d
|
|||
|
f25758031a
|
|||
|
d3d316a994
|
|||
|
93bbddf364
|
|||
|
2d572cea4d
|
|||
|
fc91808c1b
|
|||
|
b7da380421
|
|||
|
e2ebb6cc34
|
|||
|
98327b148a
|
|||
|
9d19b8b3b6
|
|||
|
45ebb20cf2
|
|||
|
ed2ced5caf
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,3 +2,6 @@
|
||||
**.img
|
||||
**.elf
|
||||
**.cpio
|
||||
.gdb_history
|
||||
userprog/userprog
|
||||
rootfs/userprog
|
||||
|
||||
73
Makefile
73
Makefile
@@ -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 gtk -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
|
||||
|
||||
12
bootloader/include/uart.h
Normal file
12
bootloader/include/uart.h
Normal 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
133
bootloader/lib/uart.c
Normal 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]);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
8
include/ctype.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
int isdigit(int);
|
||||
int isxdigit(int);
|
||||
int isupper(int);
|
||||
int isspace(int);
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void *simple_alloc(size_t size);
|
||||
void *kmalloc(size_t size);
|
||||
void kfree(void *ptr);
|
||||
170
include/logger.h
Normal file
170
include/logger.h
Normal file
@@ -0,0 +1,170 @@
|
||||
#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)
|
||||
{
|
||||
*dest++ = '0';
|
||||
*dest++ = '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_int(char *dest, int x)
|
||||
{
|
||||
char arr[12], *c = &arr[11];
|
||||
arr[11] = '\0';
|
||||
|
||||
if (x < 0)
|
||||
*dest++ = '-', x = -x;
|
||||
if (x == 0)
|
||||
*dest++ = '0';
|
||||
|
||||
while (x > 0)
|
||||
*--c = x % 10 + '0', x /= 10;
|
||||
|
||||
for (int i = 0; c[i] != '\0'; ++i)
|
||||
*dest++ = c[i];
|
||||
*dest = '\0';
|
||||
return dest;
|
||||
}
|
||||
static inline char *_logger_uint(char *dest, size_t x)
|
||||
{
|
||||
char arr[12], *c = &arr[11];
|
||||
arr[11] = '\0';
|
||||
|
||||
if (x == 0)
|
||||
*dest++ = '0';
|
||||
|
||||
while (x > 0)
|
||||
*--c = x % 10 + '0', x /= 10;
|
||||
|
||||
for (int i = 0; c[i] != '\0'; ++i)
|
||||
*dest++ = c[i];
|
||||
*dest = '\0';
|
||||
return dest;
|
||||
}
|
||||
static inline char *_logger_pointer(char *dest, void *x)
|
||||
{
|
||||
*dest++ = '*';
|
||||
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, \
|
||||
int32_t : _logger_int, \
|
||||
size_t : _logger_uint, \
|
||||
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); \
|
||||
}
|
||||
|
||||
static inline
|
||||
uint64_t _r_sp()
|
||||
{
|
||||
uint64_t ret;
|
||||
asm volatile("mov %[a], sp" : [a] "=r" (ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define FLUSH(prefix) { \
|
||||
_logger_hex(sp_cur, _r_sp()); \
|
||||
_uart_puts_sync(sp_buf); \
|
||||
_uart_puts_sync(" | "); \
|
||||
_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
|
||||
|
||||
// #define DEBUG_THREAD(val) DEBUG(val)
|
||||
#define DEBUG_THREAD(val) CLEAN
|
||||
|
||||
#define DEBUG_SIGNAL(val) DEBUG(val)
|
||||
// #define DEBUG_SIGNAL(val) CLEAN
|
||||
|
||||
extern char logger_buf[LOGGER_BUFLEN];
|
||||
extern char *logger_cur;
|
||||
extern char sp_buf[LOGGER_BUFLEN];
|
||||
extern char *sp_cur;
|
||||
@@ -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 *);
|
||||
@@ -1,8 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#define true 1
|
||||
#define false 0
|
||||
#define bool _Bool
|
||||
#define true 0x1
|
||||
#define false 0x0
|
||||
#define __bool_true_false_are_defined 0x1
|
||||
|
||||
#define ENDL "\r\n"
|
||||
|
||||
#define NAME_MAX 255
|
||||
#define PATH_MAX 4096
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
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 *memset(void *dest, int ch, size_t count);
|
||||
void *memzero(void *start, void *end);
|
||||
|
||||
@@ -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;
|
||||
@@ -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) \
|
||||
)
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
10
kernel/include/exception.h
Normal file
10
kernel/include/exception.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <process.h>
|
||||
|
||||
void exception_vector_table(void);
|
||||
|
||||
void exception_init(void);
|
||||
void not_implemented_handler(void);
|
||||
void synchronous_handler(trapframe_t *regs);
|
||||
5
kernel/include/exec.h
Normal file
5
kernel/include/exec.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <process.h>
|
||||
|
||||
void user_exec(trapframe_t *regs);
|
||||
@@ -45,7 +45,7 @@ typedef struct file_node {
|
||||
|
||||
typedef void (*initrd_callback_func_t)(file_node_t *);
|
||||
|
||||
file_node_t *initrd_init(void);
|
||||
void initrd_init(void);
|
||||
void initrd_fdt_callback(const vector_t *props);
|
||||
file_node_t *initrd_get(file_node_t *root, const char *filename);
|
||||
void initrd_traverse(file_node_t *tr, initrd_callback_func_t func);
|
||||
@@ -53,3 +53,4 @@ void initrd_traverse(file_node_t *tr, initrd_callback_func_t func);
|
||||
extern fdt_callback_t initrd_dtb_cb;
|
||||
extern void *initrd_start;
|
||||
extern void *initrd_end;
|
||||
extern file_node_t *initrd_root;
|
||||
29
kernel/include/interrupt.h
Normal file
29
kernel/include/interrupt.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#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;
|
||||
|
||||
int is_start;
|
||||
} interrupt_t;
|
||||
|
||||
void enable_interrupt(void);
|
||||
void disable_interrupt(void);
|
||||
|
||||
void add_interrupt_task(uint64_t priority,
|
||||
interrupt_callback_func_t func,
|
||||
uint64_t param);
|
||||
|
||||
void irq_handler(void);
|
||||
|
||||
void wfe(void);
|
||||
|
||||
extern interrupt_t *global_interrupt_pool;
|
||||
27
kernel/include/kmalloc.h
Normal file
27
kernel/include/kmalloc.h
Normal 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];
|
||||
@@ -24,7 +24,7 @@
|
||||
*/
|
||||
|
||||
/* a properly aligned buffer */
|
||||
extern volatile unsigned int mbox[36];
|
||||
// extern volatile unsigned int mbox[36];
|
||||
|
||||
#define MBOX_REQUEST 0
|
||||
|
||||
@@ -45,7 +45,7 @@ extern volatile unsigned int mbox[36];
|
||||
#define MBOX_TAG_GETSERIAL 0x00010004
|
||||
#define MBOX_TAG_ARM_MEMORY 0x00010005
|
||||
|
||||
int mbox_call(unsigned char ch);
|
||||
int mbox_call(unsigned char ch, unsigned int *mbox);
|
||||
unsigned int get_board_revision(void);
|
||||
unsigned int get_memory_base_addr(void);
|
||||
unsigned int get_memory_size(void);
|
||||
41
kernel/include/mman.h
Normal file
41
kernel/include/mman.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#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;
|
||||
|
||||
// when state == PAGE_ALLOCATED or PAGE_RESERVED, size = 0
|
||||
// when state == PAGE_FREE, size = r - l
|
||||
// when state == PAGE_DIVIDED, size = LCH->size | RCH->size
|
||||
uint64_t size;
|
||||
} 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;
|
||||
63
kernel/include/process.h
Normal file
63
kernel/include/process.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <vector.h>
|
||||
#include <signal.h>
|
||||
|
||||
typedef struct {
|
||||
uint64_t x0, x1;
|
||||
uint64_t x2, x3;
|
||||
uint64_t x4, x5;
|
||||
uint64_t x6, x7;
|
||||
uint64_t x8, x9;
|
||||
uint64_t x10, x11;
|
||||
uint64_t x12, x13;
|
||||
uint64_t x14, x15;
|
||||
uint64_t x16, x17;
|
||||
uint64_t x18, x19;
|
||||
uint64_t x20, x21;
|
||||
uint64_t x22, x23;
|
||||
uint64_t x24, x25;
|
||||
uint64_t x26, x27;
|
||||
uint64_t x28, fp;
|
||||
uint64_t lr, spsr_el1;
|
||||
uint64_t elr_el1;
|
||||
uint64_t esr_el1;
|
||||
uint64_t sp_el0;
|
||||
} trapframe_t;
|
||||
|
||||
struct thread;
|
||||
|
||||
typedef struct process {
|
||||
int32_t pid;
|
||||
struct thread *th;
|
||||
|
||||
int32_t exitcode;
|
||||
|
||||
void *stack;
|
||||
size_t stack_size;
|
||||
|
||||
void *mem;
|
||||
size_t mem_size;
|
||||
|
||||
void *sigstack;
|
||||
size_t sigstack_size;
|
||||
|
||||
bool sigstate[SIGNAL_NUM];
|
||||
int32_t current_signal;
|
||||
signal_handler_t sighandlers[SIGNAL_NUM];
|
||||
|
||||
trapframe_t *regs, *retregs;
|
||||
} process_t;
|
||||
|
||||
// thread_func_t, cast from
|
||||
// void run_process_by_name(const char *filename)
|
||||
int32_t run_process_by_name(uint64_t filename);
|
||||
|
||||
// void run_process(process_t *)
|
||||
int32_t run_process(uint64_t process);
|
||||
|
||||
process_t *fork_process(const process_t *from);
|
||||
|
||||
extern int32_t global_pid_counter;
|
||||
extern vector_t *global_processes;
|
||||
34
kernel/include/queue.h
Normal file
34
kernel/include/queue.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#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);
|
||||
|
||||
uint64_t queue_pop_back(queue_t *queue);
|
||||
uint64_t queue_pop_front(queue_t *queue);
|
||||
|
||||
#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)
|
||||
|
||||
#define QUEUE_POP_BACK(type, queue) ((type *)queue_pop_back(queue))
|
||||
#define QUEUE_POP_FRONT(type, queue) ((type *)queue_pop_front(queue))
|
||||
14
kernel/include/ringbuffer.h
Normal file
14
kernel/include/ringbuffer.h
Normal 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);
|
||||
12
kernel/include/signal.h
Normal file
12
kernel/include/signal.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define SIGNAL_NUM 32
|
||||
|
||||
#define SIGKILL 9
|
||||
|
||||
typedef void (*signal_handler_t)();
|
||||
|
||||
void run_signal(int32_t SIGNAL);
|
||||
void end_signal(void);
|
||||
19
kernel/include/syscall.h
Normal file
19
kernel/include/syscall.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <process.h>
|
||||
#include <signal.h>
|
||||
|
||||
void syscall_handler(trapframe_t *regs);
|
||||
|
||||
int32_t sys_getpid(void);
|
||||
size_t sys_uart_read(char buf[], size_t size);
|
||||
size_t sys_uart_write(const char buf[], size_t size);
|
||||
int32_t sys_exec(const char *name, char *const argv[]);
|
||||
int32_t sys_fork(void);
|
||||
void sys_exit(int32_t status);
|
||||
int32_t sys_mbox_call(uint8_t ch, uint32_t *mbox);
|
||||
void sys_kill_by_id(int32_t pid);
|
||||
void sys_signal(int32_t SIGNAL, signal_handler_t handler);
|
||||
void sys_kill(int32_t pid, int32_t SIGNAL);
|
||||
void sys_sigreturn(void);
|
||||
54
kernel/include/thread.h
Normal file
54
kernel/include/thread.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <queue.h>
|
||||
#include <process.h>
|
||||
|
||||
typedef int32_t (*thread_func_t)(uint64_t);
|
||||
|
||||
typedef enum: uint32_t {
|
||||
THREAD_STATUS_RUNABLE = 0,
|
||||
THREAD_STATUS_WAIT = 1,
|
||||
THREAD_STATUS_EXIT = 2,
|
||||
THREAD_STATUS_ZOMBIE = 3,
|
||||
} thread_status_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t x19, x20;
|
||||
uint64_t x21, x22;
|
||||
uint64_t x23, x24;
|
||||
uint64_t x25, x26;
|
||||
uint64_t x27, x28;
|
||||
uint64_t fp, lr;
|
||||
uint64_t sp;
|
||||
} cpu_state_t;
|
||||
|
||||
typedef struct thread {
|
||||
thread_func_t func;
|
||||
uint64_t param;
|
||||
|
||||
thread_status_t status;
|
||||
int32_t retcode;
|
||||
|
||||
void *stack;
|
||||
size_t stack_size;
|
||||
|
||||
cpu_state_t *regs;
|
||||
|
||||
process_t *process;
|
||||
} thread_t;
|
||||
|
||||
// thread.S
|
||||
void context_switch(void *from, void *to, thread_t *th);
|
||||
|
||||
// thread.c
|
||||
void thread_init(void);
|
||||
void run_thread(thread_func_t func, uint64_t param);
|
||||
void schedule(void);
|
||||
#define yield schedule
|
||||
|
||||
thread_t *get_current(void);
|
||||
|
||||
extern queue_t *global_run_queue;
|
||||
extern queue_t *global_wait_queue;
|
||||
extern queue_t *global_gc_queue;
|
||||
29
kernel/include/timer.h
Normal file
29
kernel/include/timer.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef void (*task_callback_func_t)(uint64_t);
|
||||
|
||||
typedef struct {
|
||||
uint64_t firing_tick;
|
||||
uint64_t interval;
|
||||
|
||||
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 timer_init(void);
|
||||
|
||||
void add_timer_task(task_t task);
|
||||
void sleep(uint64_t ms);
|
||||
|
||||
void timer_irq_handler(void);
|
||||
|
||||
extern timer_t *global_timer;
|
||||
25
kernel/include/uart.h
Normal file
25
kernel/include/uart.h
Normal 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;
|
||||
81
kernel/include/utils.h
Normal file
81
kernel/include/utils.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <uart.h>
|
||||
|
||||
uint32_t msb32(uint32_t);
|
||||
uint64_t msb64(uint64_t);
|
||||
|
||||
uint64_t lsb64(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 panic(int errno);
|
||||
|
||||
#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 ALIGN16(ptr) ALIGN(ptr, 4)
|
||||
#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); }
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
@@ -66,16 +85,26 @@ void traverse(const char *path, const vector_t *cbs)
|
||||
case FDT_END:
|
||||
return;
|
||||
default:
|
||||
exit(ERR_UNREACHABLE);
|
||||
panic(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");
|
||||
}
|
||||
116
kernel/lib/exception.S
Normal file
116
kernel/lib/exception.S
Normal file
@@ -0,0 +1,116 @@
|
||||
.section ".text.exception"
|
||||
|
||||
// save general registers to stack
|
||||
.macro save_all
|
||||
sub sp, sp, 36 * 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, fp, [sp, 16 * 14]
|
||||
|
||||
mrs x0, spsr_el1
|
||||
mrs x1, elr_el1
|
||||
mrs x2, esr_el1
|
||||
mrs x3, sp_el0
|
||||
stp lr, x0, [sp, 16 * 15]
|
||||
stp x1, x2, [sp, 16 * 16]
|
||||
str x3, [sp, 16 * 17]
|
||||
.endm
|
||||
|
||||
// load general registers from stack
|
||||
.macro load_all
|
||||
ldp lr, x0, [sp, 16 * 15]
|
||||
ldp x1, x2, [sp, 16 * 16]
|
||||
ldr x3, [sp, 16 * 17]
|
||||
msr spsr_el1, x0
|
||||
msr elr_el1, x1
|
||||
msr esr_el1, x2
|
||||
msr sp_el0, x3
|
||||
|
||||
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, fp, [sp, 16 * 14]
|
||||
|
||||
add sp, sp, 36 * 8
|
||||
.endm
|
||||
|
||||
_null_handler:
|
||||
save_all
|
||||
bl not_implemented_handler
|
||||
load_all
|
||||
eret
|
||||
|
||||
_synchronous_handler:
|
||||
save_all
|
||||
mov x0, sp
|
||||
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
|
||||
48
kernel/lib/exception.c
Normal file
48
kernel/lib/exception.c
Normal file
@@ -0,0 +1,48 @@
|
||||
#include <exception.h>
|
||||
#include <errcode.h>
|
||||
#include <stddef.h>
|
||||
#include <logger.h>
|
||||
#include <utils.h>
|
||||
#include <syscall.h>
|
||||
#include <interrupt.h>
|
||||
|
||||
void exception_init()
|
||||
{
|
||||
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(trapframe_t *regs)
|
||||
{
|
||||
disable_interrupt();
|
||||
|
||||
DEBUG_EXCEP("synchronous caught");
|
||||
uint64_t x0 = 0x0;
|
||||
R_REG(x0, x0);
|
||||
|
||||
uint64_t spsr_el1 = 0x0;
|
||||
R_SYSREG(spsr_el1, spsr_el1);
|
||||
|
||||
uint64_t elr_el1 = 0x0;
|
||||
R_SYSREG(elr_el1, elr_el1);
|
||||
|
||||
uint64_t esr_el1 = 0x0;
|
||||
R_SYSREG(esr_el1, esr_el1);
|
||||
|
||||
LOG(x0); LOG(spsr_el1); LOG(elr_el1); DEBUG_EXCEP(esr_el1)
|
||||
|
||||
switch ((esr_el1 >> 26) & 0x7f) {
|
||||
case 0b010101:
|
||||
syscall_handler(regs);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
36
kernel/lib/exec.S
Normal file
36
kernel/lib/exec.S
Normal file
@@ -0,0 +1,36 @@
|
||||
.global user_exec
|
||||
user_exec:
|
||||
|
||||
sub sp, sp, 36 * 8
|
||||
mov x1, x0
|
||||
mov x0, sp
|
||||
mov x2, 36 * 8
|
||||
bl memcpy
|
||||
|
||||
ldp lr, x0, [sp, 16 * 15]
|
||||
ldp x1, x2, [sp, 16 * 16]
|
||||
ldr x3, [sp, 16 * 17]
|
||||
msr spsr_el1, x0
|
||||
msr elr_el1, x1
|
||||
msr esr_el1, x2
|
||||
msr sp_el0, x3
|
||||
|
||||
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, fp, [sp, 16 * 14]
|
||||
|
||||
add sp, sp, 36 * 8
|
||||
|
||||
eret
|
||||
@@ -17,6 +17,8 @@ fdt_callback_t initrd_dtb_cb = {
|
||||
void *initrd_start = 0x0;
|
||||
void *initrd_end = 0x0;
|
||||
|
||||
file_node_t *initrd_root = 0x0;
|
||||
|
||||
void initrd_fdt_callback(const vector_t *props)
|
||||
{
|
||||
for (int i = 0; i < (int)props->size; ++i) {
|
||||
@@ -29,14 +31,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 +46,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 +68,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;
|
||||
@@ -86,7 +89,7 @@ void _split(file_node_t *rt, const char *s, file_node_t **a, file_node_t **b)
|
||||
|
||||
cpio_newc_header_t *initrd_cur;
|
||||
|
||||
file_node_t *initrd_init(void)
|
||||
void initrd_init(void)
|
||||
{
|
||||
cpio_newc_header_t *header;
|
||||
char *filename;
|
||||
@@ -96,7 +99,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,16 +127,14 @@ file_node_t *initrd_init(void)
|
||||
newnode->filename = filename;
|
||||
newnode->filecontent = filecontent;
|
||||
|
||||
DEBUG_s(filename);
|
||||
|
||||
_split(root, filename, <r, &rtr);
|
||||
root = _merge(ltr, _merge(newnode, rtr));
|
||||
}
|
||||
|
||||
return root;
|
||||
|
||||
initrd_root = 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;
|
||||
121
kernel/lib/interrupt.c
Normal file
121
kernel/lib/interrupt.c
Normal file
@@ -0,0 +1,121 @@
|
||||
#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;
|
||||
|
||||
void enable_interrupt(void)
|
||||
{ W_SYSREG_IMM(DAIFClr, 0xf); }
|
||||
|
||||
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");
|
||||
uint64_t last_priority = 0xfff;
|
||||
if (global_interrupt_pool)
|
||||
last_priority = global_interrupt_pool->priority;
|
||||
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,
|
||||
|
||||
.is_start = false,
|
||||
};
|
||||
|
||||
global_interrupt_pool = _merge(global_interrupt_pool, newint);
|
||||
|
||||
while (global_interrupt_pool) {
|
||||
// LOG("check interrupt"); DEBUG_EXCEP(global_interrupt_pool->priority);
|
||||
if (global_interrupt_pool->is_start && global_interrupt_pool->priority < last_priority)
|
||||
return;
|
||||
global_interrupt_pool->is_start = true;
|
||||
global_interrupt_pool->func(global_interrupt_pool->param);
|
||||
global_interrupt_pool = _pop(global_interrupt_pool);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return; // do nothing for now
|
||||
|
||||
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);
|
||||
}
|
||||
133
kernel/lib/kmalloc.c
Normal file
133
kernel/lib/kmalloc.c
Normal file
@@ -0,0 +1,133 @@
|
||||
#include <logger.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)
|
||||
panic(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)
|
||||
{
|
||||
LOG("mman_alloc called"); DEBUG_MEM(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->page_begin || !pool->left) {
|
||||
void *page = allocate_page(1);
|
||||
|
||||
*(kmalloc_header_t *)page = (kmalloc_header_t){
|
||||
.unit = unit,
|
||||
.left = (PAGE_SIZE - sizeof(kmalloc_header_t)) / unit,
|
||||
.begin = (void *)((uint64_t)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,
|
||||
};
|
||||
LOG(page); LOG(sizeof(kmalloc_header_t)); DEBUG_MEM(pool->page_begin->begin);
|
||||
|
||||
uint64_t ptr = (uint64_t)page + sizeof(kmalloc_header_t);
|
||||
for (; ptr + unit <= (uint64_t)page + PAGE_SIZE; ptr += unit)
|
||||
*(uint64_t *)ptr = ptr + unit;
|
||||
}
|
||||
|
||||
void *ret = pool->page_begin->begin;
|
||||
LOG(pool); LOG(pool->page_begin); DEBUG_MEM(pool->left);
|
||||
LOG(pool->page_begin->left); DEBUG_MEM(pool->page_begin->begin);
|
||||
pool->page_begin->begin = *(void **)pool->page_begin->begin;
|
||||
|
||||
pool->left--;
|
||||
pool->page_begin->left--;
|
||||
if (!pool->left)
|
||||
pool->page_begin = 0x0;
|
||||
while (pool->page_begin && !pool->page_begin->left) {
|
||||
pool->page_begin = pool->page_begin->page_next;
|
||||
if (pool->page_begin)
|
||||
pool->page_begin->page_prev = 0x0;
|
||||
}
|
||||
|
||||
LOG("mman_alloc"); LOG((uint64_t)unit); DEBUG_MEM(ret);
|
||||
LOG(pool->page_begin); LOG(pool->page_begin->left);
|
||||
DEBUG_MEM(pool->page_begin->begin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mman_free(void *ptr)
|
||||
{
|
||||
if (ptr == ALIGN4K(ptr)) {
|
||||
free_page(ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
return; // early return for debugging
|
||||
|
||||
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;
|
||||
|
||||
LOG("mman_free"); LOG((uint64_t)unit); DEBUG_MEM(ptr);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,14 @@
|
||||
|
||||
#include <gpio.h>
|
||||
#include <mbox.h>
|
||||
#include <string.h>
|
||||
#include <kmalloc.h>
|
||||
#include <thread.h>
|
||||
#include <logger.h>
|
||||
#include <utils.h>
|
||||
|
||||
/* mailbox message buffer */
|
||||
volatile unsigned int __attribute__((aligned(16))) mbox[36];
|
||||
// volatile unsigned int __attribute__((aligned(16))) mbox[36];
|
||||
|
||||
#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880)
|
||||
#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0))
|
||||
@@ -49,27 +54,37 @@ volatile unsigned int __attribute__((aligned(16))) mbox[36];
|
||||
/**
|
||||
* Make a mailbox call. Returns 0 on failure, non-zero on success
|
||||
*/
|
||||
int mbox_call(unsigned char ch)
|
||||
int mbox_call(unsigned char ch, unsigned int *input)
|
||||
{
|
||||
unsigned int r = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF));
|
||||
unsigned int *_mbox = kmalloc((size_t)input[0] + 0xf), *mbox = ALIGN16(_mbox);
|
||||
LOG(_mbox); LOG(mbox); DEBUG_THREAD((size_t)input[0]);
|
||||
memcpy(mbox, input, (size_t)input[0]);
|
||||
unsigned int r = (unsigned long)mbox | (unsigned int)(ch&0xf);
|
||||
/* wait until we can write to the mailbox */
|
||||
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL);
|
||||
do yield();
|
||||
while(*MBOX_STATUS & MBOX_FULL);
|
||||
/* write the address of our message to the mailbox with channel identifier */
|
||||
*MBOX_WRITE = r;
|
||||
/* now wait for the response */
|
||||
while(1) {
|
||||
for (;;) {
|
||||
/* is there a response? */
|
||||
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY);
|
||||
do yield();
|
||||
while(*MBOX_STATUS & MBOX_EMPTY);
|
||||
/* is it a response to our message? */
|
||||
if(r == *MBOX_READ)
|
||||
if(r == *MBOX_READ) {
|
||||
/* is it a valid successful response? */
|
||||
return mbox[1]==MBOX_RESPONSE;
|
||||
if (mbox[1] == MBOX_RESPONSE)
|
||||
memcpy(input, mbox, (size_t)input[0]);
|
||||
kfree(_mbox);
|
||||
return mbox[1] == MBOX_RESPONSE;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int get_board_revision(void)
|
||||
{
|
||||
unsigned int __attribute__((aligned(16))) mbox[36];
|
||||
mbox[0] = 36 * 4;
|
||||
mbox[1] = MBOX_REQUEST;
|
||||
|
||||
@@ -81,13 +96,14 @@ unsigned int get_board_revision(void)
|
||||
|
||||
mbox[6] = MBOX_TAG_LAST;
|
||||
|
||||
mbox_call(MBOX_CH_PROP);
|
||||
mbox_call(MBOX_CH_PROP, mbox);
|
||||
|
||||
return mbox[5];
|
||||
}
|
||||
|
||||
unsigned int get_memory_base_addr(void)
|
||||
{
|
||||
unsigned int __attribute__((aligned(16))) mbox[36];
|
||||
mbox[0] = 36 * 4;
|
||||
mbox[1] = MBOX_REQUEST;
|
||||
|
||||
@@ -100,13 +116,14 @@ unsigned int get_memory_base_addr(void)
|
||||
|
||||
mbox[7] = MBOX_TAG_LAST;
|
||||
|
||||
mbox_call(MBOX_CH_PROP);
|
||||
mbox_call(MBOX_CH_PROP, mbox);
|
||||
|
||||
return mbox[5];
|
||||
}
|
||||
|
||||
unsigned int get_memory_size(void)
|
||||
{
|
||||
unsigned int __attribute__((aligned(16))) mbox[36];
|
||||
mbox[0] = 36 * 4;
|
||||
mbox[1] = MBOX_REQUEST;
|
||||
|
||||
@@ -119,7 +136,7 @@ unsigned int get_memory_size(void)
|
||||
|
||||
mbox[7] = MBOX_TAG_LAST;
|
||||
|
||||
mbox_call(MBOX_CH_PROP);
|
||||
mbox_call(MBOX_CH_PROP, mbox);
|
||||
|
||||
return mbox[6];
|
||||
}
|
||||
258
kernel/lib/mman.c
Normal file
258
kernel/lib/mman.c
Normal file
@@ -0,0 +1,258 @@
|
||||
#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("free page merged"); DEBUG_MEM((uint64_t)idx);
|
||||
}
|
||||
CUR->state = PAGE_FREE;
|
||||
CUR->size = sz;
|
||||
}
|
||||
if (LCH->state != PAGE_FREE || RCH->state != PAGE_FREE)
|
||||
CUR->state = PAGE_DIVIDED;
|
||||
switch (CUR->state) {
|
||||
case PAGE_FREE:
|
||||
CUR->size = sz;
|
||||
break;
|
||||
case PAGE_DIVIDED:
|
||||
CUR->size = LCH->size | RCH->size;
|
||||
break;
|
||||
case PAGE_ALLOCATED:
|
||||
case PAGE_RESERVED:
|
||||
CUR->size = 0;
|
||||
break;
|
||||
default:
|
||||
panic(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,
|
||||
.size = 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((void *)0x00000000, (void *)0x00001000);
|
||||
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->size) {
|
||||
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->size = 0;
|
||||
return l;
|
||||
}
|
||||
LOG("page divided"); LOG(l); DEBUG_MEM(r);
|
||||
LCH->state = RCH->state = PAGE_FREE;
|
||||
LCH->size = m - l;
|
||||
RCH->size = r - m;
|
||||
break;
|
||||
case PAGE_DIVIDED:
|
||||
break;
|
||||
case PAGE_ALLOCATED:
|
||||
case PAGE_RESERVED:
|
||||
return MMAN_NO_PAGE;
|
||||
default:
|
||||
panic(ERR_UNREACHABLE);
|
||||
}
|
||||
|
||||
uint64_t ret = MMAN_NO_PAGE;
|
||||
|
||||
// Goto child where size >= req
|
||||
// If both children can handle, choose the one that has the least significant
|
||||
// bit that can handle.
|
||||
// It both children are the same, choose the left one
|
||||
int is_lch_valid = (LCH->size >= req);
|
||||
int is_rch_valid = (RCH->size >= req);
|
||||
if (is_lch_valid && is_rch_valid) {
|
||||
if (lsb64(LCH->size & ~(req - 1)) <= lsb64(RCH->size & ~(req - 1)))
|
||||
ret = _allocate_page(req, LIDX, l, m);
|
||||
else
|
||||
ret = _allocate_page(req, RIDX, m, r);
|
||||
}
|
||||
|
||||
if (ret == MMAN_NO_PAGE && LCH->size >= req)
|
||||
ret = _allocate_page(req, LIDX, l, m);
|
||||
if (ret == MMAN_NO_PAGE && RCH->size >= 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)
|
||||
panic(ERR_INVALID_OP);
|
||||
|
||||
uint64_t offset = _allocate_page(page_cnt, 0, 0, mman_page_cnt);
|
||||
|
||||
if (offset == MMAN_NO_PAGE)
|
||||
panic(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->size = sz;
|
||||
return;
|
||||
}
|
||||
case PAGE_DIVIDED:
|
||||
break;
|
||||
case PAGE_RESERVED:
|
||||
default:
|
||||
panic(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)
|
||||
panic(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)
|
||||
panic(ERR_INVALID_MEM);
|
||||
|
||||
LOG("page reserved"); LOG(l); DEBUG_MEM(r);
|
||||
CUR->state = PAGE_RESERVED;
|
||||
CUR->size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t m = l + ((msb64(sz) == sz) ? (sz >> 1) : msb64(sz));
|
||||
if (CUR->state == PAGE_FREE) {
|
||||
LOG("page divided"); LOG(l); DEBUG_MEM(r);
|
||||
CUR->state = PAGE_DIVIDED;
|
||||
LCH->state = RCH->state = PAGE_FREE;
|
||||
LCH->size = m - l;
|
||||
RCH->size = 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);
|
||||
}
|
||||
122
kernel/lib/process.c
Normal file
122
kernel/lib/process.c
Normal file
@@ -0,0 +1,122 @@
|
||||
#include <process.h>
|
||||
#include <utils.h>
|
||||
#include <errcode.h>
|
||||
#include <logger.h>
|
||||
#include <thread.h>
|
||||
#include <kmalloc.h>
|
||||
#include <mman.h>
|
||||
#include <exec.h>
|
||||
#include <initrd.h>
|
||||
#include <string.h>
|
||||
#include <interrupt.h>
|
||||
|
||||
int32_t global_pid_counter = 0;
|
||||
vector_t *global_processes = 0x0;
|
||||
|
||||
static inline
|
||||
process_t *_make_process()
|
||||
{
|
||||
process_t *ret = kmalloc(sizeof(process_t));
|
||||
|
||||
if (!global_processes)
|
||||
global_processes = make_vector(0);
|
||||
VEC_PUSH(global_processes, ret);
|
||||
|
||||
*ret = (process_t){
|
||||
.pid = global_pid_counter++,
|
||||
.th = 0x0,
|
||||
|
||||
.exitcode = 0,
|
||||
|
||||
.stack = allocate_page(256),
|
||||
.stack_size = 256 << 12,
|
||||
|
||||
.mem = allocate_page(256),
|
||||
.mem_size = 256 << 12,
|
||||
|
||||
.sigstack = allocate_page(256),
|
||||
.sigstack_size = 256 << 12,
|
||||
|
||||
.current_signal = 0,
|
||||
|
||||
.regs = kmalloc(sizeof(trapframe_t)),
|
||||
};
|
||||
|
||||
memset(ret->sigstate, 0x0, SIGNAL_NUM * sizeof(bool));
|
||||
memset(ret->sighandlers, 0x0, SIGNAL_NUM * sizeof(signal_handler_t));
|
||||
memset(ret->regs, 0x0, sizeof(trapframe_t));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline
|
||||
void _init_process(process_t *process, const char *filename)
|
||||
{
|
||||
file_node_t *file = initrd_get(initrd_root, filename);
|
||||
if (file == 0x0)
|
||||
panic(ERR_NOT_EXIST);
|
||||
|
||||
memcpy(process->mem, file->filecontent, file->filesize);
|
||||
*process->regs = (trapframe_t){
|
||||
.spsr_el1 = 0x0, // enable all interrupt
|
||||
.elr_el1 = (uint64_t)process->mem,
|
||||
.sp_el0 = ((uint64_t)process->stack + process->stack_size - 64),
|
||||
};
|
||||
}
|
||||
|
||||
// void run_process_by_name(const char *filename)
|
||||
int32_t run_process_by_name(uint64_t param)
|
||||
{
|
||||
const char *filename = (void *)param;
|
||||
thread_t *th = get_current();
|
||||
|
||||
if (!th->process)
|
||||
th->process = _make_process();
|
||||
_init_process(th->process, filename);
|
||||
|
||||
th->process->th = th;
|
||||
LOG("Run process by name"); DEBUG_THREAD(filename);
|
||||
LOG(th->process->stack); DEBUG_THREAD(th->process->regs->sp_el0);
|
||||
LOG(th->process->mem); DEBUG_THREAD(th->process->regs->elr_el1);
|
||||
|
||||
disable_interrupt();
|
||||
user_exec(th->process->regs);
|
||||
|
||||
__builtin_unreachable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// void run_process(process_t *)
|
||||
int32_t run_process(uint64_t param)
|
||||
{
|
||||
process_t *process = (void *)param;
|
||||
thread_t *th = get_current();
|
||||
|
||||
th->process = process;
|
||||
th->process->th = th;
|
||||
LOG("Run process"); DEBUG_THREAD(process->pid);
|
||||
|
||||
disable_interrupt();
|
||||
user_exec(th->process->regs);
|
||||
|
||||
__builtin_unreachable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
process_t *fork_process(const process_t *from)
|
||||
{
|
||||
process_t *ret = _make_process();
|
||||
memcpy(ret->stack, from->stack, from->stack_size);
|
||||
memcpy(ret->mem, from->mem, from->mem_size);
|
||||
memcpy(ret->sigstack, from->sigstack, from->sigstack_size);
|
||||
memcpy(ret->sighandlers, from->sighandlers, sizeof(from->sighandlers));
|
||||
*ret->regs = (trapframe_t){
|
||||
.x0 = 0, // fork return value
|
||||
.fp = from->regs->fp - (uint64_t)from->stack + (uint64_t)ret->stack,
|
||||
.lr = from->regs->lr - (uint64_t)from->mem + (uint64_t)ret->mem,
|
||||
.sp_el0 = from->regs->sp_el0 - (uint64_t)from->stack + (uint64_t)ret->stack,
|
||||
.elr_el1 = from->regs->elr_el1 - (uint64_t)from->mem + (uint64_t)ret->mem,
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
87
kernel/lib/queue.c
Normal file
87
kernel/lib/queue.c
Normal file
@@ -0,0 +1,87 @@
|
||||
#include <queue.h>
|
||||
#include <errcode.h>
|
||||
#include <utils.h>
|
||||
#include <kmalloc.h>
|
||||
|
||||
queue_t *make_queue()
|
||||
{
|
||||
queue_t *ret = kmalloc(sizeof(queue_t));
|
||||
*ret = (queue_t){
|
||||
.size = 0,
|
||||
.begin = kmalloc(sizeof(queue_node_t)),
|
||||
.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)
|
||||
panic(ERR_OUT_OF_BOUND);
|
||||
return queue->end->prev->value;
|
||||
}
|
||||
|
||||
uint64_t queue_front(const queue_t *queue)
|
||||
{
|
||||
if (!queue->size)
|
||||
panic(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;
|
||||
++queue->size;
|
||||
}
|
||||
|
||||
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;
|
||||
++queue->size;
|
||||
}
|
||||
|
||||
uint64_t queue_pop_back(queue_t *queue)
|
||||
{
|
||||
if (!queue->size)
|
||||
panic(ERR_OUT_OF_BOUND);
|
||||
|
||||
uint64_t ret = queue->end->prev->value;
|
||||
queue->end->prev = queue->end->prev->prev;
|
||||
queue->end->prev->next = queue->end;
|
||||
|
||||
--queue->size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t queue_pop_front(queue_t *queue)
|
||||
{
|
||||
if (!queue->size)
|
||||
panic(ERR_OUT_OF_BOUND);
|
||||
|
||||
uint64_t ret = queue->begin->next->value;
|
||||
queue->begin->next = queue->begin->next->next;
|
||||
queue->begin->next->prev = queue->begin;
|
||||
|
||||
--queue->size;
|
||||
return ret;
|
||||
}
|
||||
55
kernel/lib/ringbuffer.c
Normal file
55
kernel/lib/ringbuffer.c
Normal 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)
|
||||
panic(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)
|
||||
panic(ERR_INVALID_OP);
|
||||
|
||||
return *buf->read;
|
||||
}
|
||||
76
kernel/lib/signal.c
Normal file
76
kernel/lib/signal.c
Normal file
@@ -0,0 +1,76 @@
|
||||
#include <signal.h>
|
||||
#include <logger.h>
|
||||
#include <string.h>
|
||||
#include <process.h>
|
||||
#include <thread.h>
|
||||
#include <kmalloc.h>
|
||||
#include <interrupt.h>
|
||||
#include <exec.h>
|
||||
|
||||
static inline
|
||||
void _sighandler_wrapper(signal_handler_t handler)
|
||||
{
|
||||
handler();
|
||||
asm volatile(
|
||||
"mov x8, #10" ENDL
|
||||
"svc 0"
|
||||
::: "x8"
|
||||
);
|
||||
}
|
||||
|
||||
static inline
|
||||
void _sigkill_default_handler()
|
||||
{
|
||||
thread_t *th = get_current();
|
||||
th->status = THREAD_STATUS_ZOMBIE;
|
||||
}
|
||||
|
||||
void run_signal(int32_t SIGNAL)
|
||||
{
|
||||
process_t *process = get_current()->process;
|
||||
process->current_signal = SIGNAL;
|
||||
LOG("run_signal"); LOG(process->sighandlers[SIGNAL]); DEBUG_SIGNAL(SIGNAL);
|
||||
|
||||
if (!process->sighandlers[SIGNAL]) {
|
||||
switch (SIGNAL) {
|
||||
case SIGKILL:
|
||||
_sigkill_default_handler();
|
||||
break;
|
||||
default:
|
||||
LOG("No default handler for this signal"); DEBUG_SIGNAL(SIGNAL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_SIGNAL(process->sighandlers[SIGNAL]);
|
||||
|
||||
process->retregs = process->regs;
|
||||
process->regs = kmalloc(sizeof(trapframe_t));
|
||||
memcpy(process->regs, process->retregs, sizeof(trapframe_t));
|
||||
*process->regs = (trapframe_t){
|
||||
.x0 = (uint64_t)process->sighandlers[SIGNAL],
|
||||
.elr_el1 = (uint64_t)_sighandler_wrapper,
|
||||
.sp_el0 = ((uint64_t)process->sigstack + process->sigstack_size - 64),
|
||||
};
|
||||
|
||||
disable_interrupt();
|
||||
process->current_signal = SIGNAL;
|
||||
process->sigstate[SIGNAL] = false;
|
||||
user_exec(process->regs);
|
||||
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void end_signal()
|
||||
{
|
||||
DEBUG_SIGNAL("end_signal");
|
||||
process_t *process = get_current()->process;
|
||||
|
||||
disable_interrupt();
|
||||
process->current_signal = 0x0;
|
||||
kfree(process->regs);
|
||||
process->regs = process->retregs;
|
||||
user_exec(process->regs);
|
||||
|
||||
__builtin_unreachable();
|
||||
}
|
||||
114
kernel/lib/syscall.c
Normal file
114
kernel/lib/syscall.c
Normal file
@@ -0,0 +1,114 @@
|
||||
#include <syscall.h>
|
||||
#include <logger.h>
|
||||
#include <uart.h>
|
||||
#include <thread.h>
|
||||
#include <process.h>
|
||||
#include <mbox.h>
|
||||
#include <exec.h>
|
||||
#include <signal.h>
|
||||
|
||||
void syscall_handler(trapframe_t *regs)
|
||||
{
|
||||
thread_t *th = get_current();
|
||||
th->process->regs = regs;
|
||||
|
||||
switch (regs->x8) {
|
||||
case 0: // int32_t getpid(void)
|
||||
regs->x0 = sys_getpid();
|
||||
break;
|
||||
case 1: // size_t uart_read(char buf[], size_t size)
|
||||
regs->x0 = sys_uart_read((char *)regs->x0, (size_t)regs->x1);
|
||||
break;
|
||||
case 2: // size_t uart_write(const char buf[], size_t size)
|
||||
regs->x0 = sys_uart_write((const char *)regs->x0, (size_t)regs->x1);
|
||||
break;
|
||||
case 3: // int32_t exec(const char *name, char *const argv[])
|
||||
regs->x0 = sys_exec((const char *)regs->x0, (char *const *)regs->x1);
|
||||
break;
|
||||
case 4: // int32_t fork(void)
|
||||
regs->x0 = sys_fork();
|
||||
break;
|
||||
case 5: // void exit(int32_t status)
|
||||
sys_exit((int32_t)regs->x0);
|
||||
break;
|
||||
case 6: // int32_t mbox_call(uint8_t ch, uint32_t *mbox)
|
||||
regs->x0 = sys_mbox_call((uint8_t)regs->x0, (uint32_t *)regs->x1);
|
||||
break;
|
||||
case 7: // void kill_by_id(int32_t pid)
|
||||
sys_kill_by_id((int32_t)regs->x0);
|
||||
break;
|
||||
case 8: // void signal(int32_t SIGNAL, signal_handler_t handler)
|
||||
sys_signal((int32_t)regs->x0, (signal_handler_t)regs->x1);
|
||||
break;
|
||||
case 9: // void kill(int32_t pid, int32_t SIGNAL)
|
||||
sys_kill((int32_t)regs->x0, (int32_t)regs->x1);
|
||||
break;
|
||||
case 10: // void sigreturn(void)
|
||||
sys_sigreturn();
|
||||
break;
|
||||
default:
|
||||
LOG("unsupported syscall"); ERROR(regs->x8);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t sys_getpid(void)
|
||||
{
|
||||
thread_t *th = get_current();
|
||||
if (th->process == 0x0)
|
||||
return -1;
|
||||
return th->process->pid;
|
||||
}
|
||||
|
||||
size_t sys_uart_read(char buf[], size_t size)
|
||||
{ return uart_getb((uint8_t *)buf, size); }
|
||||
|
||||
size_t sys_uart_write(const char buf[], size_t size)
|
||||
{ return uart_putb((const uint8_t *)buf, size); }
|
||||
|
||||
int32_t sys_exec(const char *name, char *const argv[])
|
||||
{ return run_process_by_name((uint64_t)name); /* ignore argv for now */ }
|
||||
|
||||
int32_t sys_fork(void)
|
||||
{
|
||||
thread_t *cur = get_current();
|
||||
process_t *newproc = fork_process(cur->process);
|
||||
run_thread(run_process, (uint64_t)newproc);
|
||||
return newproc->pid;
|
||||
}
|
||||
|
||||
void sys_exit(int32_t status)
|
||||
{
|
||||
thread_t *th = get_current();
|
||||
th->status = THREAD_STATUS_ZOMBIE;
|
||||
}
|
||||
|
||||
int32_t sys_mbox_call(uint8_t ch, uint32_t *mbox)
|
||||
{ return mbox_call(ch, mbox); }
|
||||
|
||||
void sys_kill_by_id(int32_t pid)
|
||||
{
|
||||
if (!global_processes || global_processes->size <= (size_t)pid) {
|
||||
LOG("Process not exist"); INFOR(pid);
|
||||
return;
|
||||
}
|
||||
|
||||
process_t *process = VEC_AT(process_t, global_processes, pid);
|
||||
process->th->status = THREAD_STATUS_ZOMBIE;
|
||||
LOG("Process killed"); INFOR(pid);
|
||||
}
|
||||
|
||||
void sys_signal(int32_t SIGNAL, signal_handler_t handler)
|
||||
{
|
||||
thread_t *th = get_current();
|
||||
th->process->sighandlers[SIGNAL] = handler;
|
||||
LOG(handler); LOG(SIGNAL); DEBUG_SIGNAL("registered");
|
||||
}
|
||||
|
||||
void sys_kill(int32_t pid, int32_t SIGNAL)
|
||||
{
|
||||
process_t *process = VEC_AT(process_t, global_processes, pid);
|
||||
process->sigstate[SIGNAL] = true;
|
||||
}
|
||||
|
||||
void sys_sigreturn(void)
|
||||
{ end_signal(); }
|
||||
21
kernel/lib/thread.S
Normal file
21
kernel/lib/thread.S
Normal file
@@ -0,0 +1,21 @@
|
||||
.global context_switch
|
||||
context_switch:
|
||||
stp x19, x20, [x0, 16 * 0]
|
||||
stp x21, x22, [x0, 16 * 1]
|
||||
stp x23, x24, [x0, 16 * 2]
|
||||
stp x25, x26, [x0, 16 * 3]
|
||||
stp x27, x28, [x0, 16 * 4]
|
||||
stp fp, lr, [x0, 16 * 5]
|
||||
mov x9, sp
|
||||
str x9, [x0, 16 * 6]
|
||||
|
||||
ldp x19, x20, [x1, 16 * 0]
|
||||
ldp x21, x22, [x1, 16 * 1]
|
||||
ldp x23, x24, [x1, 16 * 2]
|
||||
ldp x25, x26, [x1, 16 * 3]
|
||||
ldp x27, x28, [x1, 16 * 4]
|
||||
ldp fp, lr, [x1, 16 * 5]
|
||||
ldr x9, [x1, 16 * 6]
|
||||
mov sp, x9
|
||||
msr tpidr_el1, x2
|
||||
ret
|
||||
118
kernel/lib/thread.c
Normal file
118
kernel/lib/thread.c
Normal file
@@ -0,0 +1,118 @@
|
||||
#include <thread.h>
|
||||
#include <logger.h>
|
||||
#include <utils.h>
|
||||
#include <kmalloc.h>
|
||||
#include <mman.h>
|
||||
#include <queue.h>
|
||||
#include <interrupt.h>
|
||||
#include <string.h>
|
||||
#include <timer.h>
|
||||
|
||||
queue_t *global_run_queue = 0x0;
|
||||
queue_t *global_wait_queue = 0x0;
|
||||
queue_t *global_gc_queue = 0x0;
|
||||
|
||||
thread_t *get_current(void)
|
||||
{
|
||||
uint64_t tpidr_el1;
|
||||
R_SYSREG(tpidr_el1, tpidr_el1);
|
||||
return (thread_t *)tpidr_el1;
|
||||
}
|
||||
|
||||
static inline
|
||||
void _thread_wrapper()
|
||||
{
|
||||
enable_interrupt();
|
||||
|
||||
thread_t *cur = get_current();
|
||||
|
||||
LOG("Running thread wrapper"); DEBUG_THREAD(cur->func);
|
||||
cur->func(cur->param);
|
||||
|
||||
cur->status = THREAD_STATUS_ZOMBIE;
|
||||
|
||||
schedule();
|
||||
}
|
||||
|
||||
static inline
|
||||
thread_t *_make_thread(thread_func_t func, uint64_t param)
|
||||
{
|
||||
thread_t *ret = (thread_t *)kmalloc(sizeof(thread_t));
|
||||
|
||||
*ret = (thread_t){
|
||||
.func = func,
|
||||
.param = param,
|
||||
|
||||
.status = THREAD_STATUS_RUNABLE,
|
||||
.retcode = 0,
|
||||
|
||||
.stack = allocate_page(256),
|
||||
.stack_size = 256 << 12,
|
||||
|
||||
.regs = kmalloc(sizeof(cpu_state_t)),
|
||||
|
||||
.process = 0x0,
|
||||
};
|
||||
memset(ret->regs, 0, sizeof(cpu_state_t));
|
||||
ret->regs->sp = (uint64_t)ret->stack + ret->stack_size - 64;
|
||||
ret->regs->lr = (uint64_t)_thread_wrapper;
|
||||
ret->regs->fp = ret->regs->sp;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void run_thread(thread_func_t func, uint64_t param)
|
||||
{
|
||||
// Runs before enable interrupt
|
||||
QUEUE_PUSH_BACK(global_run_queue, _make_thread(func, param));
|
||||
}
|
||||
|
||||
static inline
|
||||
int32_t _idle(uint64_t)
|
||||
{
|
||||
DEBUG_THREAD("enter idle thread");
|
||||
|
||||
for (;;) {
|
||||
enable_interrupt();
|
||||
schedule();
|
||||
DEBUG_THREAD(global_gc_queue->size);
|
||||
// DEBUG_THREAD("back to idle thread");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void thread_init(void)
|
||||
{
|
||||
global_run_queue = make_queue();
|
||||
global_wait_queue = make_queue();
|
||||
global_gc_queue = make_queue();
|
||||
|
||||
thread_t *th = kmalloc(sizeof(thread_t));
|
||||
W_SYSREG(tpidr_el1, th);
|
||||
|
||||
run_thread(_idle, 0x0);
|
||||
}
|
||||
|
||||
void schedule(void)
|
||||
{
|
||||
disable_interrupt();
|
||||
|
||||
thread_t *th = get_current(), *next = 0x0;
|
||||
LOG("Run thread"); LOG(global_run_queue->size); DEBUG_THREAD(th);
|
||||
LOG(th->stack); DEBUG_THREAD(th->regs->sp);
|
||||
|
||||
while (global_run_queue->size > 0 && !next) {
|
||||
next = QUEUE_POP_FRONT(thread_t, global_run_queue);
|
||||
if (next->status == THREAD_STATUS_ZOMBIE) {
|
||||
QUEUE_PUSH_BACK(global_gc_queue, next);
|
||||
next = 0x0;
|
||||
} else
|
||||
QUEUE_PUSH_BACK(global_run_queue, next);
|
||||
}
|
||||
|
||||
if (next && th != next)
|
||||
context_switch(th->regs, next->regs, next);
|
||||
|
||||
enable_interrupt();
|
||||
}
|
||||
51
kernel/lib/timer.c
Normal file
51
kernel/lib/timer.c
Normal file
@@ -0,0 +1,51 @@
|
||||
#include <timer.h>
|
||||
#include <interrupt.h>
|
||||
#include <logger.h>
|
||||
#include <utils.h>
|
||||
#include <kmalloc.h>
|
||||
#include <thread.h>
|
||||
|
||||
#define CORE0_TIMER_IRQ_CTRL ((volatile uint32_t *)0x40000040)
|
||||
|
||||
MMIO_W_HELPER(_enable_timer_irq, CORE0_TIMER_IRQ_CTRL, 0x1, 1);
|
||||
|
||||
void timer_init()
|
||||
{
|
||||
uint64_t cntkctl_el1, cntfrq_el0;
|
||||
R_SYSREG(cntkctl_el1, cntkctl_el1);
|
||||
W_SYSREG(cntkctl_el1, cntkctl_el1 | 1);
|
||||
W_SYSREG(cntp_ctl_el0, 1);
|
||||
_enable_timer_irq(true);
|
||||
|
||||
R_SYSREG(cntfrq_el0, cntfrq_el0);
|
||||
W_SYSREG(cntp_tval_el0, cntfrq_el0 >> 5);
|
||||
}
|
||||
|
||||
void sleep(uint64_t ms)
|
||||
{
|
||||
uint64_t cntpct_el0, cntfrq_el0;
|
||||
R_SYSREG(cntpct_el0, cntpct_el0);
|
||||
R_SYSREG(cntfrq_el0, cntfrq_el0);
|
||||
|
||||
uint64_t wake = cntpct_el0 + cntfrq_el0 * ms / 1000000;
|
||||
for (;;) {
|
||||
R_SYSREG(cntpct_el0, cntpct_el0);
|
||||
if (cntpct_el0 >= wake)
|
||||
break;
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
void timer_irq_handler(void)
|
||||
{
|
||||
uint64_t cntfrq_el0;
|
||||
R_SYSREG(cntfrq_el0, cntfrq_el0);
|
||||
W_SYSREG(cntp_tval_el0, cntfrq_el0 >> 5);
|
||||
|
||||
thread_t *th = get_current();
|
||||
for (int32_t i = 0; i < SIGNAL_NUM; ++i) {
|
||||
if (th->process->sigstate[i])
|
||||
run_signal(i);
|
||||
}
|
||||
schedule();
|
||||
}
|
||||
223
kernel/lib/uart.c
Normal file
223
kernel/lib/uart.c
Normal file
@@ -0,0 +1,223 @@
|
||||
#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>
|
||||
#include <thread.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;
|
||||
|
||||
int is_uart_in_interrupt_queue = 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);
|
||||
_uart_enable_receive_interrupt(false);
|
||||
_uart_enable_transmit_interrupt(false);
|
||||
// uint64_t ier = *AUX_MU_IER;
|
||||
|
||||
uart_getb = uart_getb_async;
|
||||
uart_putb = uart_putb_async;
|
||||
|
||||
is_uart_inited = true;
|
||||
}
|
||||
|
||||
static inline
|
||||
void _enable_uart_interrupt()
|
||||
{
|
||||
_uart_enable_receive_interrupt(true);
|
||||
if (uart_writebuf->size > 0)
|
||||
_uart_enable_transmit_interrupt(true);
|
||||
}
|
||||
|
||||
static inline
|
||||
void _uart_transmit_interrupt_callback(uint64_t)
|
||||
{
|
||||
_uart_write_data(ringbuffer_bump(uart_writebuf));
|
||||
|
||||
is_uart_in_interrupt_queue = false;
|
||||
_enable_uart_interrupt();
|
||||
}
|
||||
|
||||
static inline
|
||||
void _uart_transmit_interrupt_handler()
|
||||
{
|
||||
if (uart_writebuf->size > 0) {
|
||||
is_uart_in_interrupt_queue = true;
|
||||
add_interrupt_task(11, _uart_transmit_interrupt_callback, 0x0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline
|
||||
void _uart_receive_interrupt_callback(uint64_t)
|
||||
{
|
||||
ringbuffer_push(uart_readbuf, _uart_read_data());
|
||||
|
||||
is_uart_in_interrupt_queue = false;
|
||||
_enable_uart_interrupt();
|
||||
}
|
||||
|
||||
static inline
|
||||
void _uart_receive_interrupt_handler()
|
||||
{
|
||||
if (uart_readbuf->size < uart_readbuf->cap) {
|
||||
is_uart_in_interrupt_queue = true;
|
||||
add_interrupt_task(12, _uart_receive_interrupt_callback, 0x0);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
size_t uart_putb_async(const uint8_t *bytes, size_t len)
|
||||
{
|
||||
size_t sentlen = 0;
|
||||
for (; sentlen < len; ++bytes, ++sentlen) {
|
||||
while(!_uart_transmitter_idle())
|
||||
yield();
|
||||
|
||||
_uart_write_data(*bytes);
|
||||
}
|
||||
|
||||
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_data_ready())
|
||||
yield();
|
||||
|
||||
*bytes = _uart_read_data();
|
||||
}
|
||||
|
||||
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)
|
||||
panic(ERR_IO_FAILED);
|
||||
}
|
||||
|
||||
void uart_hex(uint64_t d)
|
||||
{
|
||||
char buf[0x11], *p = buf;
|
||||
for (int c = 28, n; c >= 0; c -= 4) {
|
||||
n = (d >> c) & 0xf;
|
||||
n += (n > 9) ? 0x37 : 0x30;
|
||||
*p++ = (char)n;
|
||||
}
|
||||
*p = '\0';
|
||||
uart_puts(buf);
|
||||
}
|
||||
@@ -4,18 +4,37 @@
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
uint64_t lsb64(uint64_t x)
|
||||
{
|
||||
uint64_t res = 0x0;
|
||||
asm volatile(
|
||||
"rbit x0, %[val]" ENDL
|
||||
"clz %[res], x0"
|
||||
: [res] "=r" (res)
|
||||
: [val] "r" (x)
|
||||
: "x0"
|
||||
);
|
||||
return res == 64 ? 0 : ((uint64_t)1 << res);
|
||||
}
|
||||
|
||||
uint32_t hton32(const uint32_t h)
|
||||
@@ -78,7 +97,7 @@ int isupper(int c)
|
||||
int32_t atoi32(const char *s)
|
||||
{
|
||||
if (!s)
|
||||
exit(ERR_CONVERSION);
|
||||
panic(ERR_CONVERSION);
|
||||
|
||||
int is_neg = 0;
|
||||
if (*s != '\0' && *s == '-')
|
||||
@@ -87,7 +106,7 @@ int32_t atoi32(const char *s)
|
||||
int32_t ret = 0;
|
||||
for (; *s != '\0'; ++s) {
|
||||
if (!isdigit(*s))
|
||||
exit(ERR_CONVERSION);
|
||||
panic(ERR_CONVERSION);
|
||||
ret *= 10, ret += *s - '0';
|
||||
}
|
||||
|
||||
@@ -97,12 +116,12 @@ int32_t atoi32(const char *s)
|
||||
uint32_t atoh32(const char *s)
|
||||
{
|
||||
if (!s)
|
||||
exit(ERR_CONVERSION);
|
||||
panic(ERR_CONVERSION);
|
||||
|
||||
uint32_t ret = 0;
|
||||
for (int i = 8; i--; ++s) {
|
||||
for (int i = 8; i-- && *s != '\0'; ++s) {
|
||||
if (!isxdigit(*s))
|
||||
exit(ERR_CONVERSION);
|
||||
panic(ERR_CONVERSION);
|
||||
ret <<= 4, ret |= (isdigit(*s) ? *s - '0' :
|
||||
(isupper(*s) ? *s - 'A' + 10 :
|
||||
*s - 'a' + 10));
|
||||
@@ -111,7 +130,7 @@ uint32_t atoh32(const char *s)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void exit(int exit_code)
|
||||
void panic(int exitcode)
|
||||
{
|
||||
static int print = 0;
|
||||
if (!print) {
|
||||
@@ -119,14 +138,14 @@ void exit(int exit_code)
|
||||
"OOPS! YOUR KERNEL DEAD" ENDL
|
||||
"ERROR CODE: "
|
||||
);
|
||||
uart_hex(exit_code);
|
||||
uart_hex(exitcode);
|
||||
uart_puts(ENDL);
|
||||
print = 1;
|
||||
}
|
||||
|
||||
asm volatile(
|
||||
"wfe\n"
|
||||
"b exit"
|
||||
"b panic"
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -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);
|
||||
panic(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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -1,28 +1,53 @@
|
||||
#include <logger.h>
|
||||
#include <process.h>
|
||||
#include <thread.h>
|
||||
#include <kmalloc.h>
|
||||
#include <uart.h>
|
||||
#include <dtb.h>
|
||||
#include <initrd.h>
|
||||
#include <shell.h>
|
||||
#include <mman.h>
|
||||
#include <vector.h>
|
||||
#include <utils.h>
|
||||
#include <timer.h>
|
||||
#include <exception.h>
|
||||
#include <interrupt.h>
|
||||
#include <mbox.h>
|
||||
|
||||
static inline
|
||||
void _init(void *dtb)
|
||||
{
|
||||
exception_init();
|
||||
|
||||
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");
|
||||
|
||||
initrd_init();
|
||||
|
||||
mman_init();
|
||||
|
||||
thread_init();
|
||||
|
||||
timer_init();
|
||||
|
||||
enable_interrupt();
|
||||
}
|
||||
|
||||
void main(void *dtb)
|
||||
{
|
||||
uart_init();
|
||||
uart_getc();
|
||||
|
||||
DEBUG(dtb);
|
||||
INFOR("kernel running");
|
||||
|
||||
dtb_addr = dtb;
|
||||
vector_t *dtb_cbs = make_vector(0);
|
||||
VEC_PUSH(dtb_cbs, &initrd_dtb_cb);
|
||||
fdt_traverse(dtb_cbs);
|
||||
_init(dtb);
|
||||
|
||||
DEBUG(initrd_start);
|
||||
DEBUG(initrd_end);
|
||||
INFOR("Run user process syscall.img");
|
||||
run_thread(run_process_by_name, (uint64_t)&"syscall.img");
|
||||
|
||||
file_node_t *initrd_root = initrd_init();
|
||||
|
||||
int shell_cont = 1;
|
||||
while (shell_cont) {
|
||||
shell_cont = shell(initrd_root);
|
||||
}
|
||||
schedule();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
6
lib/logger.c
Normal file
6
lib/logger.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <logger.h>
|
||||
|
||||
char logger_buf[LOGGER_BUFLEN];
|
||||
char *logger_cur = logger_buf;
|
||||
char sp_buf[LOGGER_BUFLEN];
|
||||
char *sp_cur = sp_buf;
|
||||
130
lib/shell.c
130
lib/shell.c
@@ -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;
|
||||
}
|
||||
24
lib/string.c
24
lib/string.c
@@ -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;
|
||||
@@ -44,6 +59,15 @@ void *memcpy(void *dest, const void *src, size_t count)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *memset(void *dest, int ch, size_t count)
|
||||
{
|
||||
void *ret = dest;
|
||||
for (; count > 0; --count, ++dest)
|
||||
*(uint8_t *)dest = ch & 0xff;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *memzero(void *start, void *end)
|
||||
{
|
||||
void *ret = start;
|
||||
|
||||
131
lib/uart.c
131
lib/uart.c
@@ -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]);
|
||||
}
|
||||
@@ -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
13
test.py
@@ -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()
|
||||
32
upload.py
32
upload.py
@@ -9,24 +9,22 @@ if len(sys.argv) < 2:
|
||||
print("no args for serial device")
|
||||
exit()
|
||||
|
||||
while True:
|
||||
kernel = open("kernel8.img", "rb").read()
|
||||
r = serialtube(sys.argv[1], convert_newlines=False)
|
||||
kernel = open("kernel8.img", "rb").read()
|
||||
r = serialtube(sys.argv[1], convert_newlines=False)
|
||||
|
||||
# send size
|
||||
sz = len(kernel)
|
||||
print("size:", sz)
|
||||
r.send(pack("<I", sz))
|
||||
print(r.recvuntil(b"$").decode())
|
||||
# send size
|
||||
sz = len(kernel)
|
||||
print("size:", sz)
|
||||
r.send(pack("<I", sz))
|
||||
print(r.recvuntil(b"$").decode())
|
||||
|
||||
# send kernel
|
||||
splitsize = 1000
|
||||
for i in tqdm(range(len(kernel) // splitsize), unit="KB"):
|
||||
r.send(kernel[i * splitsize : (i + 1) * splitsize])
|
||||
# send kernel
|
||||
splitsize = 1000
|
||||
for i in tqdm(range(len(kernel) // splitsize), unit="KB"):
|
||||
r.send(kernel[i * splitsize : (i + 1) * splitsize])
|
||||
|
||||
r.send(kernel[len(kernel) // splitsize * splitsize:])
|
||||
r.send(kernel[len(kernel) // splitsize * splitsize:])
|
||||
|
||||
r.interactive()
|
||||
|
||||
r.send(b"\nreboot\n")
|
||||
sleep(10)
|
||||
sleep(1)
|
||||
r.send(b"\n")
|
||||
r.interactive()
|
||||
|
||||
41
userprog/Makefile
Normal file
41
userprog/Makefile
Normal file
@@ -0,0 +1,41 @@
|
||||
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
|
||||
|
||||
INCLUDE := -I../include -Iinclude
|
||||
|
||||
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 $@ $(INCLUDE) $(CCFLAGS)
|
||||
|
||||
%.c.o: %.c
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) -c $< -o $@ $(INCLUDE) $(CCFLAGS)
|
||||
|
||||
clean:
|
||||
-rm $(OBJS) userprog userprog.elf
|
||||
11
userprog/Start.S
Normal file
11
userprog/Start.S
Normal 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
|
||||
14
userprog/include/syscall.h
Normal file
14
userprog/include/syscall.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
uint64_t syscall(int32_t num, ...);
|
||||
|
||||
int32_t getpid(void);
|
||||
size_t uart_read(char buf[], size_t size);
|
||||
size_t uart_write(const char buf[], size_t size);
|
||||
int32_t exec(const char *name, char *const argv[]);
|
||||
int32_t fork(void);
|
||||
void exit(int32_t status);
|
||||
int32_t mbox_call(uint8_t ch, uint32_t *mbox);
|
||||
void kill(int32_t pid);
|
||||
13
userprog/lib/syscall.S
Normal file
13
userprog/lib/syscall.S
Normal file
@@ -0,0 +1,13 @@
|
||||
.global syscall
|
||||
syscall:
|
||||
mov x8, x0
|
||||
mov x0, x1
|
||||
mov x1, x2
|
||||
mov x2, x3
|
||||
mov x3, x4
|
||||
mov x4, x5
|
||||
mov x5, x6
|
||||
mov x6, x7
|
||||
|
||||
svc 0
|
||||
ret
|
||||
25
userprog/lib/syscall.c
Normal file
25
userprog/lib/syscall.c
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <syscall.h>
|
||||
|
||||
int32_t getpid()
|
||||
{ return (int32_t)syscall(0); }
|
||||
|
||||
size_t uart_read(char buf[], size_t size)
|
||||
{ return (size_t)syscall(1, buf, size); }
|
||||
|
||||
size_t uart_write(const char buf[], size_t size)
|
||||
{ return (size_t)syscall(2, buf, size); }
|
||||
|
||||
int32_t exec(const char *name, char *const argv[])
|
||||
{ return (int32_t)syscall(3, name, argv); }
|
||||
|
||||
int32_t fork(void)
|
||||
{ return (int32_t)syscall(4); }
|
||||
|
||||
void exit(int32_t status)
|
||||
{ syscall(5); __builtin_unreachable(); }
|
||||
|
||||
int32_t mbox_call(uint8_t ch, uint32_t *mbox)
|
||||
{ return (int32_t)syscall(6, ch, mbox); }
|
||||
|
||||
void kill(int32_t pid)
|
||||
{ syscall(7, pid); }
|
||||
18
userprog/linker.ld
Normal file
18
userprog/linker.ld
Normal file
@@ -0,0 +1,18 @@
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text : {
|
||||
*(.text.start)
|
||||
*(.text)
|
||||
}
|
||||
.rodata : {
|
||||
*(.rodata)
|
||||
}
|
||||
.data : {
|
||||
*(.data)
|
||||
}
|
||||
.bss : {
|
||||
*(.bss)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user