Feat: lab 4
This commit is contained in:
55
kernel/include/dtb.h
Normal file
55
kernel/include/dtb.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <vector.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t totalsize;
|
||||
uint32_t off_dt_struct;
|
||||
uint32_t off_dt_strings;
|
||||
uint32_t off_mem_rsvmap;
|
||||
uint32_t version;
|
||||
uint32_t last_comp_version;
|
||||
uint32_t boot_cpuid_phys;
|
||||
uint32_t size_dt_strings;
|
||||
uint32_t size_dt_struct;
|
||||
}__attribute__((packed)) fdt_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t address;
|
||||
uint64_t size;
|
||||
}__attribute__((packed)) fdt_reserve_entry_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t len;
|
||||
uint32_t nameoff;
|
||||
}__attribute__((packed)) fdt_prop_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t len;
|
||||
const char *name;
|
||||
void *value;
|
||||
} fdt_prop_t;
|
||||
|
||||
#define FDT_BEGIN_NODE 0x00000001
|
||||
#define FDT_END_NODE 0x00000002
|
||||
#define FDT_PROP 0x00000003
|
||||
#define FDT_NOP 0x00000004
|
||||
#define FDT_END 0x00000009
|
||||
|
||||
#define FDT_PATH_BUFFER_LEN 0x10
|
||||
|
||||
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_traverse(const vector_t *struct_cbs);
|
||||
|
||||
extern void *dtb_start;
|
||||
extern void *dtb_end;
|
||||
extern void *dtb_memory_start;
|
||||
extern void *dtb_memory_end;
|
||||
extern vector_t *dtb_reserved_entries;
|
||||
55
kernel/include/initrd.h
Normal file
55
kernel/include/initrd.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <dtb.h>
|
||||
#include <vector.h>
|
||||
|
||||
typedef struct {
|
||||
char c_magic[6];
|
||||
char c_ino[8];
|
||||
char c_mode[8];
|
||||
char c_uid[8];
|
||||
char c_gid[8];
|
||||
char c_nlink[8];
|
||||
char c_mtime[8];
|
||||
char c_filesize[8];
|
||||
char c_devmajor[8];
|
||||
char c_devminor[8];
|
||||
char c_rdevmajor[8];
|
||||
char c_rdevminor[8];
|
||||
char c_namesize[8];
|
||||
char c_check[8];
|
||||
}__attribute__((packed)) cpio_newc_header_t;
|
||||
|
||||
typedef struct file_node {
|
||||
struct file_node *l, *r;
|
||||
int rand;
|
||||
int node_size;
|
||||
|
||||
int ino;
|
||||
int mode;
|
||||
int uid;
|
||||
int gid;
|
||||
int nlink;
|
||||
int mtime;
|
||||
int filesize;
|
||||
int devmajor;
|
||||
int devminor;
|
||||
int rdevmajor;
|
||||
int rdevminor;
|
||||
int namesize;
|
||||
|
||||
char *filename;
|
||||
uint8_t *filecontent;
|
||||
} file_node_t;
|
||||
|
||||
typedef void (*initrd_callback_func_t)(file_node_t *);
|
||||
|
||||
file_node_t *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);
|
||||
|
||||
extern fdt_callback_t initrd_dtb_cb;
|
||||
extern void *initrd_start;
|
||||
extern void *initrd_end;
|
||||
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];
|
||||
51
kernel/include/mbox.h
Normal file
51
kernel/include/mbox.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2018 bzt (bztsrc@github)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/* a properly aligned buffer */
|
||||
extern volatile unsigned int mbox[36];
|
||||
|
||||
#define MBOX_REQUEST 0
|
||||
|
||||
/* channels */
|
||||
#define MBOX_CH_POWER 0
|
||||
#define MBOX_CH_FB 1
|
||||
#define MBOX_CH_VUART 2
|
||||
#define MBOX_CH_VCHIQ 3
|
||||
#define MBOX_CH_LEDS 4
|
||||
#define MBOX_CH_BTNS 5
|
||||
#define MBOX_CH_TOUCH 6
|
||||
#define MBOX_CH_COUNT 7
|
||||
#define MBOX_CH_PROP 8
|
||||
|
||||
/* tags */
|
||||
#define MBOX_TAG_LAST 0
|
||||
#define MBOX_TAG_BOARD_REVISION 0x00010002
|
||||
#define MBOX_TAG_GETSERIAL 0x00010004
|
||||
#define MBOX_TAG_ARM_MEMORY 0x00010005
|
||||
|
||||
int mbox_call(unsigned char ch);
|
||||
unsigned int get_board_revision(void);
|
||||
unsigned int get_memory_base_addr(void);
|
||||
unsigned int get_memory_size(void);
|
||||
37
kernel/include/mman.h
Normal file
37
kernel/include/mman.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <dtb.h>
|
||||
|
||||
#define MMAN_NO_PAGE 0xffffffffffffffff
|
||||
#define PAGE_SIZE (1 << 12)
|
||||
|
||||
// PAGE_FREE => available
|
||||
// PAGE_ALLOCATED => this range is allocated explicitly
|
||||
// PAGE_DIVIDED => this range is divided into smaller range
|
||||
// PAGE_RESERVED => this range is reserved explicitly
|
||||
typedef enum :uint8_t {
|
||||
PAGE_FREE = 0,
|
||||
PAGE_ALLOCATED = 1,
|
||||
PAGE_DIVIDED = 2,
|
||||
PAGE_RESERVED = 3,
|
||||
} page_state_t;
|
||||
|
||||
typedef struct {
|
||||
page_state_t state;
|
||||
uint64_t maxsz;
|
||||
} page_header_t;
|
||||
|
||||
void mman_init();
|
||||
|
||||
void *allocate_page(size_t page_cnt);
|
||||
void free_page(void *ptr);
|
||||
void reserve_page(void *begin, void *end);
|
||||
|
||||
void mman_fdt_memory_cb_func(const vector_t *props);
|
||||
|
||||
extern fdt_callback_t mman_dtb_memory_cb;
|
||||
extern void *mman_memory_start;
|
||||
extern void *mman_memory_end;
|
||||
extern size_t mman_page_cnt;
|
||||
extern page_header_t *mman_frame_array;
|
||||
29
kernel/include/queue.h
Normal file
29
kernel/include/queue.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct queue_node {
|
||||
struct queue_node *prev, *next;
|
||||
uint64_t value;
|
||||
} queue_node_t;
|
||||
|
||||
typedef struct queue {
|
||||
size_t size;
|
||||
|
||||
queue_node_t *begin, *end;
|
||||
} queue_t;
|
||||
|
||||
queue_t *make_queue();
|
||||
|
||||
uint64_t queue_back(const queue_t *queue);
|
||||
uint64_t queue_front(const queue_t *queue);
|
||||
|
||||
void queue_push_back(queue_t *queue, uint64_t val);
|
||||
void queue_push_front(queue_t *queue, uint64_t val);
|
||||
|
||||
#define QUEUE_BACK(type, queue) ((type *)queue_back(queue))
|
||||
#define QUEUE_FRONT(type, queue) ((type *)queue_front(queue))
|
||||
#define QUEUE_PUSH_BACK(queue, val) \
|
||||
queue_push_back(queue, (uint64_t)val)
|
||||
#define QUEUE_PUSH_FRONT(queue, val) \
|
||||
queue_push_front(queue, (uint64_t)val)
|
||||
8
kernel/include/random.h
Normal file
8
kernel/include/random.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
extern const int _random_a;
|
||||
extern const int _random_c;
|
||||
extern const int _random_m;
|
||||
extern int seed;
|
||||
|
||||
int random(void);
|
||||
15
kernel/include/shell.h
Normal file
15
kernel/include/shell.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <initrd.h>
|
||||
#include <stddef.h>
|
||||
|
||||
void help(void);
|
||||
void hello(void);
|
||||
void hwinfo(void);
|
||||
void memalloc(size_t size);
|
||||
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 *);
|
||||
38
kernel/include/utils.h
Normal file
38
kernel/include/utils.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <uart.h>
|
||||
|
||||
uint32_t msb32(uint32_t);
|
||||
uint64_t msb64(uint64_t);
|
||||
|
||||
uint32_t hton32(const uint32_t);
|
||||
uint32_t ntoh32(const uint32_t);
|
||||
|
||||
uint64_t hton64(const uint64_t);
|
||||
uint64_t ntoh64(const uint64_t);
|
||||
|
||||
int isdigit(int);
|
||||
int isxdigit(int);
|
||||
int isupper(int);
|
||||
int isspace(int);
|
||||
|
||||
int32_t atoi32(const char *);
|
||||
uint32_t atoh32(const char *);
|
||||
|
||||
void exit(int);
|
||||
|
||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
#define MAX(x, y) (((x) < (y)) ? (y) : (x))
|
||||
|
||||
#define ALIGN(ptr, cnt) (void *)((( \
|
||||
((uint64_t)(ptr) - 1) >> (cnt)) + 1) << (cnt))
|
||||
|
||||
#define ALIGN4(ptr) ALIGN(ptr, 2)
|
||||
#define ALIGN8(ptr) ALIGN(ptr, 3)
|
||||
#define ALIGN4K(ptr) ALIGN(ptr, 12)
|
||||
|
||||
#define BUMP(orig_type, bump_type, ptr) ( \
|
||||
(ptr = (orig_type*)((bump_type*)ptr + 1)), \
|
||||
((bump_type*)ptr - 1) \
|
||||
)
|
||||
18
kernel/include/vector.h
Normal file
18
kernel/include/vector.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
size_t cap;
|
||||
|
||||
uint64_t *data;
|
||||
} vector_t;
|
||||
|
||||
vector_t *make_vector(size_t size);
|
||||
|
||||
uint64_t vec_at(const vector_t *vec, size_t idx);
|
||||
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_push(vec, (uint64_t)val)
|
||||
110
kernel/lib/dtb.c
Normal file
110
kernel/lib/dtb.c
Normal file
@@ -0,0 +1,110 @@
|
||||
#include <logger.h>
|
||||
#include <errcode.h>
|
||||
#include <dtb.h>
|
||||
#include <utils.h>
|
||||
#include <string.h>
|
||||
#include <kmalloc.h>
|
||||
#include <vector.h>
|
||||
|
||||
void *dtb_start;
|
||||
void *dtb_end;
|
||||
void *dtb_memory_start;
|
||||
void *dtb_memory_end;
|
||||
vector_t *dtb_reserved_entries;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static inline
|
||||
void _memory_traverse()
|
||||
{
|
||||
dtb_reserved_entries = make_vector(0);
|
||||
while (fdt_memory_cur->address != 0 || fdt_memory_cur->size != 0) {
|
||||
DEBUG(ntoh64(fdt_memory_cur->address));
|
||||
DEBUG(ntoh64(fdt_memory_cur->size));
|
||||
|
||||
VEC_PUSH(dtb_reserved_entries, fdt_memory_cur++);
|
||||
}
|
||||
}
|
||||
|
||||
#define nextnode(ptr) (void *)((((uint64_t)(ptr) >> 2) + 1) << 2)
|
||||
static inline
|
||||
void _struct_traverse(const char *path, const vector_t *cbs)
|
||||
{
|
||||
vector_t *props = make_vector(0);
|
||||
|
||||
fdt_prop_t *prop;
|
||||
const fdt_prop_header_t *prop_header;
|
||||
const char *fdt_node_path = 0x0;
|
||||
|
||||
for (;;) {
|
||||
fdt_struct_cur = ALIGN4(fdt_struct_cur);
|
||||
|
||||
switch (ntoh32(*fdt_struct_cur)) {
|
||||
case FDT_BEGIN_NODE:
|
||||
++fdt_struct_cur;
|
||||
fdt_node_path = (void *)fdt_struct_cur;
|
||||
do {
|
||||
BUMP(uint32_t, char, fdt_struct_cur);
|
||||
} while (*(char *)fdt_struct_cur != '\0');
|
||||
BUMP(uint32_t, char, fdt_struct_cur); // '\0'
|
||||
|
||||
fdt_struct_cur = ALIGN4(fdt_struct_cur);
|
||||
_struct_traverse(fdt_node_path, cbs);
|
||||
break;
|
||||
case FDT_END_NODE:
|
||||
fdt_struct_cur = nextnode(fdt_struct_cur);
|
||||
goto traverse_struct_callback;
|
||||
case FDT_PROP:
|
||||
++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_start +
|
||||
ntoh32(((fdt_header_t *)dtb_start)->off_dt_strings) +
|
||||
ntoh32(prop_header->nameoff);
|
||||
prop->value = (void *)fdt_struct_cur;
|
||||
VEC_PUSH(props, prop);
|
||||
|
||||
fdt_struct_cur = (void *)((uint64_t)fdt_struct_cur +
|
||||
ntoh32(prop_header->len));
|
||||
fdt_struct_cur = ALIGN4(fdt_struct_cur);
|
||||
break;
|
||||
case FDT_NOP:
|
||||
fdt_struct_cur = nextnode(fdt_struct_cur);
|
||||
break;
|
||||
case FDT_END:
|
||||
return;
|
||||
default:
|
||||
exit(ERR_UNREACHABLE);
|
||||
}
|
||||
}
|
||||
traverse_struct_callback:
|
||||
_fdt_struct_callback(path, cbs, props);
|
||||
}
|
||||
|
||||
void fdt_traverse(const vector_t *struct_cbs)
|
||||
{
|
||||
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);
|
||||
|
||||
DEBUG(fdt_memory_cur);
|
||||
DEBUG(fdt_struct_cur);
|
||||
_memory_traverse();
|
||||
DEBUG_DTB("memory traverse done");
|
||||
_struct_traverse("", struct_cbs);
|
||||
DEBUG_DTB("struct traverse done");
|
||||
}
|
||||
161
kernel/lib/initrd.c
Normal file
161
kernel/lib/initrd.c
Normal file
@@ -0,0 +1,161 @@
|
||||
#include <initrd.h>
|
||||
#include <utils.h>
|
||||
#include <stddef.h>
|
||||
#include <dtb.h>
|
||||
#include <kmalloc.h>
|
||||
#include <random.h>
|
||||
#include <string.h>
|
||||
#include <uart.h>
|
||||
|
||||
#define nullnode ((file_node_t *)0)
|
||||
|
||||
fdt_callback_t initrd_dtb_cb = {
|
||||
.name = "chosen",
|
||||
.func = initrd_fdt_callback,
|
||||
};
|
||||
|
||||
void *initrd_start = 0x0;
|
||||
void *initrd_end = 0x0;
|
||||
|
||||
void initrd_fdt_callback(const vector_t *props)
|
||||
{
|
||||
for (int i = 0; i < (int)props->size; ++i) {
|
||||
if (!strcmp(VEC_AT(fdt_prop_t, props, i)->name, "linux,initrd-start"))
|
||||
initrd_start = (void *)(uint64_t)ntoh32(
|
||||
*(uint32_t *)VEC_AT(fdt_prop_t, props, i)->value);
|
||||
if (!strcmp(VEC_AT(fdt_prop_t, props, i)->name, "linux,initrd-end"))
|
||||
initrd_end = (void *)(uint64_t)ntoh32(
|
||||
*(uint32_t *)VEC_AT(fdt_prop_t, props, i)->value);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _init_node(file_node_t *node) {
|
||||
node->l = nullnode;
|
||||
node->r = nullnode;
|
||||
node->rand = random();
|
||||
node->node_size = 1;
|
||||
}
|
||||
|
||||
static inline void _pull_from(file_node_t *to, file_node_t *from)
|
||||
{
|
||||
if (!from)
|
||||
return;
|
||||
|
||||
to->node_size += from->node_size;
|
||||
}
|
||||
|
||||
static inline void _pull(file_node_t *node)
|
||||
{
|
||||
node->node_size = 1;
|
||||
_pull_from(node, node->l);
|
||||
_pull_from(node, node->r);
|
||||
}
|
||||
|
||||
static inline file_node_t *_merge(file_node_t *a, file_node_t *b)
|
||||
{
|
||||
if (!a || !b)
|
||||
return a ?: b;
|
||||
|
||||
if (a->rand < b->rand) {
|
||||
a->r = _merge(a->r, b);
|
||||
_pull(a);
|
||||
return a;
|
||||
}
|
||||
b->l = _merge(a, b->l);
|
||||
_pull(b);
|
||||
return 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;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(rt->filename, s) < 0) {
|
||||
*a = rt;
|
||||
_split((*a)->r, s, &(*a)->r, b);
|
||||
_pull(*a);
|
||||
} else {
|
||||
*b = rt;
|
||||
_split((*b)->l, s, a, &(*b)->l);
|
||||
_pull(*b);
|
||||
}
|
||||
}
|
||||
|
||||
cpio_newc_header_t *initrd_cur;
|
||||
|
||||
file_node_t *initrd_init(void)
|
||||
{
|
||||
cpio_newc_header_t *header;
|
||||
char *filename;
|
||||
uint8_t *filecontent;
|
||||
|
||||
initrd_cur = (void *)initrd_start;
|
||||
|
||||
file_node_t *root = nullnode, *ltr, *rtr;
|
||||
for (;;) {
|
||||
header = initrd_cur++;
|
||||
|
||||
filename = (void *)initrd_cur;
|
||||
if (!strcmp(filename, "TRAILER!!!"))
|
||||
break;
|
||||
initrd_cur = ALIGN4((uint64_t)initrd_cur + atoh32(header->c_namesize));
|
||||
|
||||
filecontent = (void *)initrd_cur;
|
||||
initrd_cur = ALIGN4((uint64_t)initrd_cur + atoh32(header->c_filesize));
|
||||
|
||||
file_node_t *newnode = kmalloc(sizeof(file_node_t));
|
||||
_init_node(newnode);
|
||||
newnode->ino = atoh32(header->c_ino);
|
||||
newnode->mode = atoh32(header->c_mode);
|
||||
newnode->uid = atoh32(header->c_uid);
|
||||
newnode->gid = atoh32(header->c_gid);
|
||||
newnode->nlink = atoh32(header->c_nlink);
|
||||
newnode->mtime = atoh32(header->c_mtime);
|
||||
newnode->filesize = atoh32(header->c_filesize);
|
||||
newnode->devmajor = atoh32(header->c_devmajor);
|
||||
newnode->devminor = atoh32(header->c_devminor);
|
||||
newnode->rdevmajor = atoh32(header->c_rdevmajor);
|
||||
newnode->rdevminor = atoh32(header->c_rdevminor);
|
||||
newnode->namesize = atoh32(header->c_namesize);
|
||||
|
||||
newnode->filename = filename;
|
||||
newnode->filecontent = filecontent;
|
||||
|
||||
_split(root, filename, <r, &rtr);
|
||||
root = _merge(ltr, _merge(newnode, rtr));
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
static inline file_node_t *_node_bs(file_node_t *cur, const char *s)
|
||||
{
|
||||
if (!cur)
|
||||
return nullnode;
|
||||
|
||||
int cmp = strcmp(cur->filename, s);
|
||||
if (cmp < 0)
|
||||
return _node_bs(cur->r, s);
|
||||
if (cmp > 0)
|
||||
return _node_bs(cur->l, s);
|
||||
return cur; // cmp == 0
|
||||
}
|
||||
|
||||
file_node_t *initrd_get(file_node_t *tr, const char *filename)
|
||||
{
|
||||
return _node_bs(tr, filename);
|
||||
}
|
||||
|
||||
void initrd_traverse(file_node_t *tr, initrd_callback_func_t func)
|
||||
{
|
||||
if (!tr)
|
||||
return;
|
||||
|
||||
initrd_traverse(tr->l, func);
|
||||
func(tr);
|
||||
initrd_traverse(tr->r, func);
|
||||
}
|
||||
114
kernel/lib/kmalloc.c
Normal file
114
kernel/lib/kmalloc.c
Normal file
@@ -0,0 +1,114 @@
|
||||
#include <uart.h>
|
||||
#include <errcode.h>
|
||||
#include <utils.h>
|
||||
#include <kmalloc.h>
|
||||
#include <stddef.h>
|
||||
#include <mman.h>
|
||||
|
||||
extern uint64_t __heap_start;
|
||||
extern uint64_t __heap_end;
|
||||
|
||||
void *(*kmalloc)(size_t size) = simple_alloc;
|
||||
void (*kfree)(void *ptr) = (void (*)(void *))0x0;
|
||||
|
||||
kmalloc_allocator_t mman_kmalloc_pool[KMALLOC_MAX_ALLOCATOR_SIZE + 1];
|
||||
|
||||
void *_heap_top = (void *)0x0;
|
||||
|
||||
void init_mman_kmalloc()
|
||||
{
|
||||
for (int i = 1; i <= KMALLOC_MAX_ALLOCATOR_SIZE; ++i)
|
||||
mman_kmalloc_pool[i] = (kmalloc_allocator_t){
|
||||
.left = 0,
|
||||
.page_begin = (kmalloc_header_t *)0x0,
|
||||
};
|
||||
|
||||
kmalloc = mman_alloc;
|
||||
kfree = mman_free;
|
||||
}
|
||||
|
||||
// simple 8-byte aligned linear allocation
|
||||
void *simple_alloc(size_t size)
|
||||
{
|
||||
if (!_heap_top) {
|
||||
_heap_top = (void *)&__heap_start;
|
||||
}
|
||||
|
||||
size = (size_t)ALIGN8(size);
|
||||
|
||||
if ((uint64_t)_heap_top + size >= (uint64_t)&__heap_end)
|
||||
exit(ERR_NO_MEM);
|
||||
|
||||
void *ret = _heap_top;
|
||||
_heap_top = (void *)((uint64_t)_heap_top + size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define PAGE_HEADER(ptr) ((kmalloc_header_t *)(((uint64_t)(ptr) >> 12) << 12))
|
||||
|
||||
void *mman_alloc(size_t unit)
|
||||
{
|
||||
unit = (size_t)ALIGN8(unit);
|
||||
if (unit > (KMALLOC_MAX_ALLOCATOR_SIZE << 3))
|
||||
return allocate_page(((unit - 1) >> 12) + 1);
|
||||
|
||||
kmalloc_allocator_t *pool = &mman_kmalloc_pool[unit >> 3];
|
||||
if (!pool->left) {
|
||||
void *page = allocate_page(1), *ptr = page + sizeof(kmalloc_header_t);
|
||||
*(kmalloc_header_t *)page = (kmalloc_header_t){
|
||||
.unit = unit,
|
||||
.left = (PAGE_SIZE - sizeof(kmalloc_header_t)) / unit,
|
||||
.begin = page + sizeof(kmalloc_header_t),
|
||||
.page_prev = (kmalloc_header_t *)0x0,
|
||||
.page_next = (kmalloc_header_t *)0x0,
|
||||
};
|
||||
*pool = (kmalloc_allocator_t){
|
||||
.left = ((kmalloc_header_t *)page)->left,
|
||||
.page_begin = (kmalloc_header_t *)page,
|
||||
};
|
||||
|
||||
for (; ptr + unit <= page + PAGE_SIZE; ptr += unit)
|
||||
*(void **)ptr = ptr + unit;
|
||||
}
|
||||
|
||||
void *ret = pool->page_begin->begin;
|
||||
pool->page_begin->begin = *(void **)pool->page_begin->begin;
|
||||
|
||||
--pool->left;
|
||||
--pool->page_begin->left;
|
||||
if (!pool->page_begin->left)
|
||||
pool->page_begin = *(void **)pool->page_begin->page_next;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mman_free(void *ptr)
|
||||
{
|
||||
if (ptr == ALIGN4K(ptr)) {
|
||||
free_page(ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t unit = PAGE_HEADER(ptr)->unit;
|
||||
kmalloc_allocator_t *pool = &mman_kmalloc_pool[unit >> 3];
|
||||
if (!PAGE_HEADER(ptr)->left) {
|
||||
PAGE_HEADER(ptr)->page_next = pool->page_begin;
|
||||
pool->page_begin->page_prev = PAGE_HEADER(ptr);
|
||||
pool->page_begin = PAGE_HEADER(ptr);
|
||||
}
|
||||
|
||||
*(void **)ptr = pool->page_begin->begin;
|
||||
pool->page_begin->begin = ptr;
|
||||
|
||||
++pool->left;
|
||||
++PAGE_HEADER(ptr)->left;
|
||||
size_t cap = (PAGE_SIZE - sizeof(kmalloc_allocator_t)) / unit;
|
||||
if (PAGE_HEADER(ptr)->left == cap && pool->left >= 2 * cap) {
|
||||
if (PAGE_HEADER(ptr)->page_prev)
|
||||
PAGE_HEADER(ptr)->page_prev->page_next = PAGE_HEADER(ptr)->page_next;
|
||||
if (PAGE_HEADER(ptr)->page_next)
|
||||
PAGE_HEADER(ptr)->page_next->page_prev = PAGE_HEADER(ptr)->page_prev;
|
||||
free_page(PAGE_HEADER(ptr));
|
||||
}
|
||||
}
|
||||
125
kernel/lib/mbox.c
Normal file
125
kernel/lib/mbox.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2018 bzt (bztsrc@github)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gpio.h>
|
||||
#include <mbox.h>
|
||||
|
||||
/* mailbox message buffer */
|
||||
volatile unsigned int __attribute__((aligned(16))) mbox[36];
|
||||
|
||||
#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880)
|
||||
#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0))
|
||||
#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10))
|
||||
#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14))
|
||||
#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18))
|
||||
#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C))
|
||||
#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20))
|
||||
#define MBOX_RESPONSE 0x80000000
|
||||
#define MBOX_FULL 0x80000000
|
||||
#define MBOX_EMPTY 0x40000000
|
||||
|
||||
#define MAILBOX_BASE MMIO_BASE + 0xb880
|
||||
|
||||
#define REQUEST_SUCCEED 0x80000000
|
||||
#define REQUEST_FAILED 0x80000001
|
||||
#define TAG_MBOX_REQUEST 0x00000000
|
||||
|
||||
/**
|
||||
* Make a mailbox call. Returns 0 on failure, non-zero on success
|
||||
*/
|
||||
int mbox_call(unsigned char ch)
|
||||
{
|
||||
unsigned int r = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF));
|
||||
/* wait until we can write to the mailbox */
|
||||
do{asm volatile("nop");}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) {
|
||||
/* is there a response? */
|
||||
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY);
|
||||
/* is it a response to our message? */
|
||||
if(r == *MBOX_READ)
|
||||
/* is it a valid successful response? */
|
||||
return mbox[1]==MBOX_RESPONSE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int get_board_revision(void)
|
||||
{
|
||||
mbox[0] = 36 * 4;
|
||||
mbox[1] = MBOX_REQUEST;
|
||||
|
||||
// tags
|
||||
mbox[2] = MBOX_TAG_BOARD_REVISION;
|
||||
mbox[3] = 4;
|
||||
mbox[4] = TAG_MBOX_REQUEST;
|
||||
mbox[5] = 0; // value buffer
|
||||
|
||||
mbox[6] = MBOX_TAG_LAST;
|
||||
|
||||
mbox_call(MBOX_CH_PROP);
|
||||
|
||||
return mbox[5];
|
||||
}
|
||||
|
||||
unsigned int get_memory_base_addr(void)
|
||||
{
|
||||
mbox[0] = 36 * 4;
|
||||
mbox[1] = MBOX_REQUEST;
|
||||
|
||||
// tags
|
||||
mbox[2] = MBOX_TAG_ARM_MEMORY;
|
||||
mbox[3] = 8;
|
||||
mbox[4] = 8;
|
||||
mbox[5] = 0;
|
||||
mbox[6] = 0;
|
||||
|
||||
mbox[7] = MBOX_TAG_LAST;
|
||||
|
||||
mbox_call(MBOX_CH_PROP);
|
||||
|
||||
return mbox[5];
|
||||
}
|
||||
|
||||
unsigned int get_memory_size(void)
|
||||
{
|
||||
mbox[0] = 36 * 4;
|
||||
mbox[1] = MBOX_REQUEST;
|
||||
|
||||
// tags
|
||||
mbox[2] = MBOX_TAG_ARM_MEMORY;
|
||||
mbox[3] = 8;
|
||||
mbox[4] = 8;
|
||||
mbox[5] = 0;
|
||||
mbox[6] = 0;
|
||||
|
||||
mbox[7] = MBOX_TAG_LAST;
|
||||
|
||||
mbox_call(MBOX_CH_PROP);
|
||||
|
||||
return mbox[6];
|
||||
}
|
||||
248
kernel/lib/mman.c
Normal file
248
kernel/lib/mman.c
Normal file
@@ -0,0 +1,248 @@
|
||||
#include <mman.h>
|
||||
#include <logger.h>
|
||||
#include <errcode.h>
|
||||
#include <string.h>
|
||||
#include <utils.h>
|
||||
#include <kmalloc.h>
|
||||
#include <dtb.h>
|
||||
#include <initrd.h>
|
||||
|
||||
extern uint64_t __kernel_start;
|
||||
extern uint64_t __kernel_end;
|
||||
extern uint64_t __heap_start;
|
||||
extern uint64_t __stack_end;
|
||||
|
||||
fdt_callback_t mman_dtb_memory_cb = {
|
||||
.name = "memory@0",
|
||||
.func = mman_fdt_memory_cb_func,
|
||||
};
|
||||
|
||||
void *mman_memory_start = 0x0;
|
||||
void *mman_memory_end = 0x0;
|
||||
size_t mman_page_cnt = 0;
|
||||
page_header_t *mman_frame_array = 0x0;
|
||||
|
||||
void mman_fdt_memory_cb_func(const vector_t *props)
|
||||
{
|
||||
for (int i = 0; i < (int)props->size; ++i) {
|
||||
if (!strcmp(VEC_AT(fdt_prop_t, props, i)->name, "reg")) {
|
||||
mman_memory_start = (void *)(uint64_t)ntoh32(
|
||||
*((uint32_t *)VEC_AT(fdt_prop_t, props, i)->value));
|
||||
mman_memory_end = (void *)(uint64_t)ntoh32(
|
||||
*((uint32_t *)VEC_AT(fdt_prop_t, props, i)->value + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is an array-like binary tree structure, where LCH (left-child) will
|
||||
// always be the largest 2^k size block while RCH not empty.
|
||||
#define CUR (&mman_frame_array[idx])
|
||||
#define LIDX (((idx + 1) << 1) - 1)
|
||||
#define LCH (&mman_frame_array[LIDX])
|
||||
#define RIDX (((idx + 1) << 1 | 1) - 1)
|
||||
#define RCH (&mman_frame_array[RIDX])
|
||||
|
||||
static inline
|
||||
void _pull(int idx, size_t sz)
|
||||
{
|
||||
if (LCH->state == PAGE_FREE && RCH->state == PAGE_FREE) {
|
||||
if (CUR->state != PAGE_FREE) {
|
||||
LOG("node merged");
|
||||
DEBUG_MEM((uint64_t)idx);
|
||||
}
|
||||
CUR->state = PAGE_FREE;
|
||||
}
|
||||
if (LCH->state != PAGE_FREE || RCH->state != PAGE_FREE)
|
||||
CUR->state = PAGE_DIVIDED;
|
||||
switch (CUR->state) {
|
||||
case PAGE_FREE:
|
||||
CUR->maxsz = sz;
|
||||
break;
|
||||
case PAGE_DIVIDED:
|
||||
CUR->maxsz = MAX(LCH->maxsz, RCH->maxsz);
|
||||
break;
|
||||
case PAGE_ALLOCATED:
|
||||
case PAGE_RESERVED:
|
||||
CUR->maxsz = 0;
|
||||
break;
|
||||
default:
|
||||
exit(ERR_UNREACHABLE);
|
||||
}
|
||||
}
|
||||
|
||||
void mman_init()
|
||||
{
|
||||
mman_memory_start = ALIGN4K(mman_memory_start);
|
||||
mman_memory_end = ALIGN4K(mman_memory_end);
|
||||
|
||||
// 4KB per page
|
||||
mman_page_cnt = (mman_memory_end - mman_memory_start) >> 12;
|
||||
mman_frame_array = simple_alloc((mman_page_cnt << 1) * sizeof(page_header_t));
|
||||
|
||||
LOG(mman_memory_start);
|
||||
LOG(mman_memory_end);
|
||||
DEBUG_MEM((uint64_t)mman_page_cnt);
|
||||
|
||||
mman_frame_array[0] = (page_header_t){
|
||||
.state = PAGE_FREE,
|
||||
.maxsz = msb64(mman_page_cnt),
|
||||
};
|
||||
|
||||
fdt_reserve_entry_t *entry = 0x0;
|
||||
for (int i = 0; i < (int)dtb_reserved_entries->size; ++i) {
|
||||
entry = VEC_AT(fdt_reserve_entry_t, dtb_reserved_entries, i);
|
||||
LOG(ntoh64(entry->address));
|
||||
DEBUG_MEM(ntoh64(entry->address) + ntoh64(entry->size));
|
||||
reserve_page((void *)ntoh64(entry->address),
|
||||
(void *)ntoh64(entry->address) + ntoh64(entry->size));
|
||||
}
|
||||
|
||||
reserve_page(&__kernel_start, &__kernel_end);
|
||||
reserve_page(&__heap_start, &__stack_end);
|
||||
reserve_page(dtb_start, dtb_end);
|
||||
reserve_page(initrd_start, initrd_end);
|
||||
|
||||
init_mman_kmalloc();
|
||||
}
|
||||
|
||||
static inline
|
||||
uint64_t _allocate_page(size_t req, int idx, uint64_t l, uint64_t r)
|
||||
{
|
||||
uint64_t sz = r - l;
|
||||
if (req > sz || req > CUR->maxsz) {
|
||||
return MMAN_NO_PAGE;
|
||||
}
|
||||
|
||||
uint64_t m = l + ((msb64(sz) == sz) ? (sz >> 1) : msb64(sz));
|
||||
switch (CUR->state) {
|
||||
case PAGE_FREE:
|
||||
if (req == sz) {
|
||||
LOG("page allocated");
|
||||
LOG(l);
|
||||
DEBUG_MEM(r);
|
||||
CUR->state = PAGE_ALLOCATED;
|
||||
CUR->maxsz = 0;
|
||||
return l;
|
||||
}
|
||||
LCH->state = RCH->state = PAGE_FREE;
|
||||
LCH->maxsz = msb64(m - l);
|
||||
RCH->maxsz = msb64(r - m);
|
||||
break;
|
||||
case PAGE_DIVIDED:
|
||||
break;
|
||||
case PAGE_ALLOCATED:
|
||||
case PAGE_RESERVED:
|
||||
return MMAN_NO_PAGE;
|
||||
default:
|
||||
exit(ERR_UNREACHABLE);
|
||||
}
|
||||
|
||||
uint64_t ret = MMAN_NO_PAGE;
|
||||
if (ret == MMAN_NO_PAGE && LCH->maxsz >= req)
|
||||
ret = _allocate_page(req, LIDX, l, m);
|
||||
if (ret == MMAN_NO_PAGE && RCH->maxsz >= req)
|
||||
ret = _allocate_page(req, RIDX, m, r);
|
||||
_pull(idx, sz);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *allocate_page(size_t page_cnt)
|
||||
{
|
||||
if (msb64(page_cnt) != page_cnt)
|
||||
exit(ERR_INVALID_OP);
|
||||
|
||||
uint64_t offset = _allocate_page(page_cnt, 0, 0, mman_page_cnt);
|
||||
|
||||
if (offset == MMAN_NO_PAGE)
|
||||
exit(ERR_NO_MEM);
|
||||
// return (void *)0x0;
|
||||
|
||||
return mman_memory_start + offset * (1 << 12);
|
||||
}
|
||||
|
||||
static inline
|
||||
void _free_page(uint64_t req, int idx, uint64_t l, uint64_t r)
|
||||
{
|
||||
uint64_t sz = r - l;
|
||||
|
||||
switch (CUR->state) {
|
||||
case PAGE_FREE:
|
||||
return;
|
||||
case PAGE_ALLOCATED:
|
||||
if (req == l) {
|
||||
LOG("page freed");
|
||||
LOG(l);
|
||||
DEBUG_MEM(r);
|
||||
CUR->state = PAGE_FREE;
|
||||
CUR->maxsz = sz;
|
||||
return;
|
||||
}
|
||||
case PAGE_DIVIDED:
|
||||
break;
|
||||
case PAGE_RESERVED:
|
||||
default:
|
||||
exit(ERR_UNREACHABLE);
|
||||
}
|
||||
|
||||
uint64_t m = l + ((msb64(sz) == sz) ? (sz >> 1) : msb64(sz));
|
||||
if (l <= req && req < m)
|
||||
_free_page(req, LIDX, l, m);
|
||||
if (m <= req && req < r)
|
||||
_free_page(req, RIDX, m, r);
|
||||
_pull(idx, sz);
|
||||
}
|
||||
|
||||
void free_page(void *page)
|
||||
{
|
||||
if (ALIGN4K(page) != page)
|
||||
exit(ERR_INVALID_OP);
|
||||
|
||||
uint64_t start = ((uint64_t)page - (uint64_t)mman_memory_start) >> 12;
|
||||
_free_page(start, 0, 0, mman_page_cnt);
|
||||
}
|
||||
|
||||
static inline
|
||||
void _reserve_page(uint64_t ql, uint64_t qr, int idx, uint64_t l, uint64_t r)
|
||||
{
|
||||
if (qr <= l || r <= ql)
|
||||
return;
|
||||
|
||||
uint64_t sz = r - l;
|
||||
if (ql <= l && r <= qr && msb64(sz) == sz) {
|
||||
if (CUR->state == PAGE_RESERVED)
|
||||
return;
|
||||
if (CUR->state != PAGE_FREE)
|
||||
exit(ERR_INVALID_MEM);
|
||||
|
||||
LOG("page reserved");
|
||||
LOG(l);
|
||||
DEBUG_MEM(r);
|
||||
CUR->state = PAGE_RESERVED;
|
||||
CUR->maxsz = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t m = l + ((msb64(sz) == sz) ? (sz >> 1) : msb64(sz));
|
||||
if (CUR->state == PAGE_FREE) {
|
||||
LCH->state = RCH->state = PAGE_FREE;
|
||||
LCH->maxsz = msb64(m - l);
|
||||
RCH->maxsz = msb64(r - m);
|
||||
}
|
||||
|
||||
if (ql < m)
|
||||
_reserve_page(ql, qr, LIDX, l, m);
|
||||
if (m < qr)
|
||||
_reserve_page(ql, qr, RIDX, m, r);
|
||||
_pull(idx, sz);
|
||||
}
|
||||
|
||||
void reserve_page(void *begin, void *end)
|
||||
{
|
||||
uint64_t ql = ((uint64_t)begin - (uint64_t)mman_memory_start) >> 12;
|
||||
uint64_t qr = (((uint64_t)end - (uint64_t)mman_memory_start - 1) >> 12) + 1;
|
||||
|
||||
LOG("reserve page");
|
||||
LOG(ql);
|
||||
DEBUG_MEM(qr);
|
||||
_reserve_page(ql, qr, 0, 0, mman_page_cnt);
|
||||
}
|
||||
57
kernel/lib/queue.c
Normal file
57
kernel/lib/queue.c
Normal file
@@ -0,0 +1,57 @@
|
||||
#include <queue.h>
|
||||
#include <errcode.h>
|
||||
#include <utils.h>
|
||||
#include <kmalloc.h>
|
||||
|
||||
queue_t *make_queue()
|
||||
{
|
||||
queue_t *ret = kmalloc(sizeof(queue_t));
|
||||
ret->size = 0;
|
||||
ret->begin = kmalloc(sizeof(queue_node_t));
|
||||
ret->end = kmalloc(sizeof(queue_node_t));
|
||||
*ret->begin = *ret->end = (queue_node_t){
|
||||
.prev = (queue_node_t *)ret->begin,
|
||||
.next = (queue_node_t *)ret->end,
|
||||
.value = 0,
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t queue_back(const queue_t *queue)
|
||||
{
|
||||
if (!queue->size)
|
||||
exit(ERR_OUT_OF_BOUND);
|
||||
return queue->end->prev->value;
|
||||
}
|
||||
|
||||
uint64_t queue_front(const queue_t *queue)
|
||||
{
|
||||
if (!queue->size)
|
||||
exit(ERR_OUT_OF_BOUND);
|
||||
return queue->begin->next->value;
|
||||
}
|
||||
|
||||
void queue_push_back(queue_t *queue, uint64_t val)
|
||||
{
|
||||
queue->end->value = val;
|
||||
queue->end->next = kmalloc(sizeof(queue_node_t));
|
||||
*queue->end->next = (queue_node_t){
|
||||
.prev = queue->end,
|
||||
.next = queue->end->next,
|
||||
.value = 0,
|
||||
};
|
||||
queue->end = queue->end->next;
|
||||
}
|
||||
|
||||
void queue_push_front(queue_t *queue, uint64_t val)
|
||||
{
|
||||
queue->begin->value = val;
|
||||
queue->begin->prev = kmalloc(sizeof(queue_node_t));
|
||||
*queue->begin->prev = (queue_node_t){
|
||||
.prev = queue->begin->prev,
|
||||
.next = queue->begin,
|
||||
.value = 0,
|
||||
};
|
||||
queue->begin = queue->begin->prev;
|
||||
}
|
||||
12
kernel/lib/random.c
Normal file
12
kernel/lib/random.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <random.h>
|
||||
|
||||
const int _random_a = 100003;
|
||||
const int _random_c = 114514 + 33;
|
||||
const int _random_m = 1000000007;
|
||||
int seed = 0;
|
||||
|
||||
int random(void)
|
||||
{
|
||||
seed = _random_a * (seed + _random_c) % _random_m;
|
||||
return seed;
|
||||
}
|
||||
146
kernel/lib/shell.c
Normal file
146
kernel/lib/shell.c
Normal file
@@ -0,0 +1,146 @@
|
||||
#include <stddef.h>
|
||||
#include <kmalloc.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
|
||||
"memalloc : alloate memory and print" 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 memalloc(size_t size)
|
||||
{
|
||||
void *addr = kmalloc(size);
|
||||
uart_puts("size: ");
|
||||
uart_hex(size);
|
||||
uart_puts(ENDL);
|
||||
|
||||
uart_puts("addr: ");
|
||||
uart_hex((uint64_t)addr);
|
||||
uart_puts(ENDL);
|
||||
}
|
||||
|
||||
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, "memalloc")){
|
||||
memalloc((size_t)atoi32(param));
|
||||
} 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;
|
||||
}
|
||||
138
kernel/lib/utils.c
Normal file
138
kernel/lib/utils.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#include <utils.h>
|
||||
#include <errcode.h>
|
||||
#include <uart.h>
|
||||
|
||||
uint32_t msb32(uint32_t x)
|
||||
{
|
||||
uint32_t res = 0x0;
|
||||
asm volatile(
|
||||
"clz %[res], %[val]"
|
||||
: [res] "=r" (res)
|
||||
: [val] "r" (x)
|
||||
);
|
||||
return res == 32 ? 0 : (1 << (31 - res));
|
||||
}
|
||||
|
||||
uint64_t msb64(uint64_t x)
|
||||
{
|
||||
uint64_t res = 0x0;
|
||||
asm volatile(
|
||||
"clz %[res], %[val]"
|
||||
: [res] "=r" (res)
|
||||
: [val] "r" (x)
|
||||
);
|
||||
return res == 64 ? 0 : ((uint64_t)1 << (63 - res));
|
||||
}
|
||||
|
||||
uint32_t hton32(const uint32_t h)
|
||||
{
|
||||
const uint8_t *p = (const void *)&h;
|
||||
|
||||
return (uint32_t)p[0] << 24 |
|
||||
(uint32_t)p[1] << 16 |
|
||||
(uint32_t)p[2] << 8 |
|
||||
(uint32_t)p[3];
|
||||
}
|
||||
|
||||
uint32_t ntoh32(const uint32_t h)
|
||||
{
|
||||
return hton32(h);
|
||||
}
|
||||
|
||||
uint64_t hton64(const uint64_t h)
|
||||
{
|
||||
return (uint64_t)hton32(h & 0xffffffff) << 32 |
|
||||
(uint64_t)hton32(h >> 32);
|
||||
}
|
||||
|
||||
uint64_t ntoh64(const uint64_t h)
|
||||
{
|
||||
return hton64(h);
|
||||
}
|
||||
|
||||
int isspace(int c)
|
||||
{
|
||||
switch (c) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\v':
|
||||
case '\f':
|
||||
case '\r':
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int isdigit(int c)
|
||||
{
|
||||
return ('0' <= c && c <= '9');
|
||||
}
|
||||
|
||||
int isxdigit(int c)
|
||||
{
|
||||
return ('0' <= c && c <= '9') ||
|
||||
('a' <= c && c <= 'f') ||
|
||||
('A' <= c && c <= 'F');
|
||||
}
|
||||
|
||||
int isupper(int c)
|
||||
{
|
||||
return ('A' <= c && c <= 'F');
|
||||
}
|
||||
|
||||
int32_t atoi32(const char *s)
|
||||
{
|
||||
if (!s)
|
||||
exit(ERR_CONVERSION);
|
||||
|
||||
int is_neg = 0;
|
||||
if (*s != '\0' && *s == '-')
|
||||
is_neg = 1, s++;
|
||||
|
||||
int32_t ret = 0;
|
||||
for (; *s != '\0'; ++s) {
|
||||
if (!isdigit(*s))
|
||||
exit(ERR_CONVERSION);
|
||||
ret *= 10, ret += *s - '0';
|
||||
}
|
||||
|
||||
return is_neg ? -ret : ret;
|
||||
}
|
||||
|
||||
uint32_t atoh32(const char *s)
|
||||
{
|
||||
if (!s)
|
||||
exit(ERR_CONVERSION);
|
||||
|
||||
uint32_t ret = 0;
|
||||
for (int i = 8; i--; ++s) {
|
||||
if (!isxdigit(*s))
|
||||
exit(ERR_CONVERSION);
|
||||
ret <<= 4, ret |= (isdigit(*s) ? *s - '0' :
|
||||
(isupper(*s) ? *s - 'A' + 10 :
|
||||
*s - 'a' + 10));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void exit(int exit_code)
|
||||
{
|
||||
static int print = 0;
|
||||
if (!print) {
|
||||
uart_puts(
|
||||
"OOPS! YOUR KERNEL DEAD" ENDL
|
||||
"ERROR CODE: "
|
||||
);
|
||||
uart_hex(exit_code);
|
||||
uart_puts(ENDL);
|
||||
print = 1;
|
||||
}
|
||||
|
||||
asm volatile(
|
||||
"wfe\n"
|
||||
"b exit"
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
38
kernel/lib/vector.c
Normal file
38
kernel/lib/vector.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <errcode.h>
|
||||
#include <uart.h>
|
||||
#include <vector.h>
|
||||
#include <utils.h>
|
||||
#include <kmalloc.h>
|
||||
#include <string.h>
|
||||
|
||||
vector_t *make_vector(size_t size)
|
||||
{
|
||||
vector_t *ret = kmalloc(sizeof(vector_t));
|
||||
ret->size = size;
|
||||
uint32_t msb = msb32(size);
|
||||
ret->cap = (msb == size) ? size : (msb << 1);
|
||||
ret->cap = MAX(ret->cap, 4);
|
||||
ret->data = kmalloc(ret->cap * sizeof(uint64_t));
|
||||
memzero(ret->data, ret->data + ret->cap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t vec_at(const vector_t *vec, size_t idx)
|
||||
{
|
||||
if (idx >= vec->size)
|
||||
exit(ERR_OUT_OF_BOUND);
|
||||
|
||||
return vec->data[idx];
|
||||
}
|
||||
|
||||
void vec_push(vector_t *vec, uint64_t val)
|
||||
{
|
||||
if (vec->size == vec->cap) {
|
||||
uint64_t *old = vec->data;
|
||||
vec->data = kmalloc((vec->cap <<= 1) * sizeof(uint64_t));
|
||||
memcpy(vec->data, old, vec->size * sizeof(uint64_t));
|
||||
}
|
||||
|
||||
vec->data[vec->size++] = val;
|
||||
}
|
||||
@@ -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,25 +1,82 @@
|
||||
#include <logger.h>
|
||||
#include <kmalloc.h>
|
||||
#include <uart.h>
|
||||
#include <dtb.h>
|
||||
#include <initrd.h>
|
||||
#include <mman.h>
|
||||
#include <shell.h>
|
||||
#include <vector.h>
|
||||
|
||||
void init(void *dtb, file_node_t **initrd_root)
|
||||
{
|
||||
// UART
|
||||
uart_init();
|
||||
|
||||
// Device tree
|
||||
INFOR(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("device tree parse done");
|
||||
|
||||
// Initramfs
|
||||
INFOR(initrd_start);
|
||||
*initrd_root = initrd_init();
|
||||
|
||||
// Memory (Buddy system)
|
||||
mman_init();
|
||||
}
|
||||
|
||||
void main(void *dtb)
|
||||
{
|
||||
uart_init();
|
||||
uart_getc();
|
||||
|
||||
DEBUG(dtb);
|
||||
file_node_t *initrd_root = 0x0;
|
||||
init(dtb, &initrd_root);
|
||||
|
||||
dtb_addr = dtb;
|
||||
vector_t *dtb_cbs = make_vector(0);
|
||||
VEC_PUSH(dtb_cbs, &initrd_dtb_cb);
|
||||
fdt_traverse(dtb_cbs);
|
||||
void *page1 = allocate_page(1);
|
||||
INFOR(page1);
|
||||
|
||||
DEBUG(initrd_start);
|
||||
DEBUG(initrd_end);
|
||||
void *page2 = allocate_page(2);
|
||||
INFOR(page2);
|
||||
|
||||
file_node_t *initrd_root = initrd_init();
|
||||
void *page4 = allocate_page(4);
|
||||
INFOR(page4);
|
||||
|
||||
void *page16 = allocate_page(16);
|
||||
INFOR(page16);
|
||||
|
||||
free_page(page1);
|
||||
free_page(page2);
|
||||
free_page(page4);
|
||||
free_page(page16);
|
||||
|
||||
void *page32 = allocate_page(32);
|
||||
INFOR(page32);
|
||||
page1 = allocate_page(1);
|
||||
INFOR(page1);
|
||||
|
||||
free_page(page1);
|
||||
|
||||
void *kmalloc8 = kmalloc(8);
|
||||
INFOR(kmalloc8);
|
||||
kfree(kmalloc8);
|
||||
|
||||
kmalloc8 = kmalloc(8);
|
||||
INFOR(kmalloc8);
|
||||
kfree(kmalloc8);
|
||||
|
||||
void *kmalloc7k = kmalloc(7 * (1 << 10));
|
||||
INFOR(kmalloc7k);
|
||||
|
||||
void *kmalloc8k = kmalloc(1 << 13);
|
||||
INFOR(kmalloc8k);
|
||||
|
||||
kfree(kmalloc7k);
|
||||
kfree(kmalloc8k);
|
||||
|
||||
page1 = allocate_page(1);
|
||||
INFOR(page1);
|
||||
|
||||
int shell_cont = 1;
|
||||
while (shell_cont) {
|
||||
|
||||
Reference in New Issue
Block a user