2021 pre-release
This commit is contained in:
parent
11059d5b6f
commit
a94708b3b5
42 changed files with 278 additions and 227 deletions
|
@ -1,3 +1,6 @@
|
|||
#ifndef __AMDEV_H__
|
||||
#define __AMDEV_H__
|
||||
|
||||
// **MAY SUBJECT TO CHANGE IN THE FUTURE**
|
||||
|
||||
#define AM_DEVREG(id, reg, perm, ...) \
|
||||
|
@ -67,3 +70,5 @@ struct gpu_canvas {
|
|||
struct gpu_texturedesc texture;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
#include <sys/time.h>
|
||||
#include <string.h>
|
||||
#include "platform.h"
|
||||
|
||||
#define TIMER_HZ 100
|
||||
|
||||
#define YIELD_INSTR "0xff,0x14,0x25,0x08,0x00,0x10,0x00" // callq *0x100008
|
||||
#define YIELD_INSTR_LEN ((sizeof(YIELD_INSTR)) / 5) // sizeof() counts the '\0' byte
|
||||
#define SYSCALL_INSTR_LEN YIELD_INSTR_LEN
|
||||
|
||||
static_assert(SYSCALL_INSTR_LEN == 7);
|
||||
#define SYSCALL_INSTR_LEN 7
|
||||
|
||||
static Context* (*user_handler)(Event, Context*) = NULL;
|
||||
|
||||
|
@ -23,13 +19,20 @@ static void irq_handle(Context *c) {
|
|||
c->vm_head = thiscpu->vm_head;
|
||||
c->ksp = thiscpu->ksp;
|
||||
|
||||
if (thiscpu->ev.event == EVENT_ERROR) {
|
||||
uintptr_t rip = c->uc.uc_mcontext.gregs[REG_RIP];
|
||||
printf("Unhandle signal '%s' at rip = %p, badaddr = %p, cause = 0x%x\n",
|
||||
thiscpu->ev.msg, rip, thiscpu->ev.ref, thiscpu->ev.cause);
|
||||
assert(0);
|
||||
}
|
||||
c = user_handler(thiscpu->ev, c);
|
||||
assert(c != NULL);
|
||||
|
||||
__am_switch(c);
|
||||
|
||||
// magic call to restore context
|
||||
asm volatile("call *0x100010" : : "a" (c));
|
||||
void (*p)(Context *c) = (void *)(uintptr_t)0x100008;
|
||||
p(c);
|
||||
__am_panic_on_return();
|
||||
}
|
||||
|
||||
|
@ -55,9 +58,8 @@ static void setup_stack(uintptr_t event, ucontext_t *uc) {
|
|||
|
||||
if (trap_from_user) __am_pmem_unprotect();
|
||||
|
||||
// skip the instructions causing SIGSEGV for syscall and yield
|
||||
// skip the instructions causing SIGSEGV for syscall
|
||||
if (event == EVENT_SYSCALL) { rip += SYSCALL_INSTR_LEN; }
|
||||
else if (event == EVENT_YIELD) { rip += YIELD_INSTR_LEN; }
|
||||
uc->uc_mcontext.gregs[REG_RIP] = (uintptr_t)rip;
|
||||
|
||||
// switch to kernel stack if we were previously in user space
|
||||
|
@ -80,7 +82,7 @@ static void setup_stack(uintptr_t event, ucontext_t *uc) {
|
|||
}
|
||||
|
||||
static void iret(ucontext_t *uc) {
|
||||
Context *c = (void *)uc->uc_mcontext.gregs[REG_RAX];
|
||||
Context *c = (void *)uc->uc_mcontext.gregs[REG_RDI];
|
||||
// restore the context
|
||||
*uc = c->uc;
|
||||
thiscpu->ksp = c->ksp;
|
||||
|
@ -92,13 +94,13 @@ static void sig_handler(int sig, siginfo_t *info, void *ucontext) {
|
|||
thiscpu->ev.event = EVENT_ERROR;
|
||||
switch (sig) {
|
||||
case SIGUSR1: thiscpu->ev.event = EVENT_IRQ_IODEV; break;
|
||||
case SIGUSR2: thiscpu->ev.event = EVENT_YIELD; break;
|
||||
case SIGVTALRM: thiscpu->ev.event = EVENT_IRQ_TIMER; break;
|
||||
case SIGSEGV:
|
||||
if (info->si_code == SEGV_ACCERR) {
|
||||
switch ((uintptr_t)info->si_addr) {
|
||||
case 0x100000: thiscpu->ev.event = EVENT_SYSCALL; break;
|
||||
case 0x100008: thiscpu->ev.event = EVENT_YIELD; break;
|
||||
case 0x100010: iret(ucontext); return;
|
||||
case 0x100008: iret(ucontext); return;
|
||||
}
|
||||
}
|
||||
if (__am_in_userspace(info->si_addr)) {
|
||||
|
@ -112,15 +114,14 @@ static void sig_handler(int sig, siginfo_t *info, void *ucontext) {
|
|||
}
|
||||
thiscpu->ev.ref = (uintptr_t)info->si_addr;
|
||||
}
|
||||
|
||||
if (thiscpu->ev.event == EVENT_ERROR) {
|
||||
uintptr_t rip = ((ucontext_t *)ucontext)->uc_mcontext.gregs[REG_RIP];
|
||||
printf("Unhandle SIGSEGV at rip = %p, badaddr = %p\n", rip, info->si_addr);
|
||||
}
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
assert(thiscpu->ev.event != EVENT_ERROR);
|
||||
|
||||
if (thiscpu->ev.event == EVENT_ERROR) {
|
||||
thiscpu->ev.ref = (uintptr_t)info->si_addr;
|
||||
thiscpu->ev.cause = (uintptr_t)info->si_code;
|
||||
thiscpu->ev.msg = strsignal(sig);
|
||||
}
|
||||
setup_stack(thiscpu->ev.event, ucontext);
|
||||
}
|
||||
|
||||
|
@ -136,6 +137,8 @@ static void install_signal_handler() {
|
|||
assert(ret == 0);
|
||||
ret = sigaction(SIGUSR1, &s, NULL);
|
||||
assert(ret == 0);
|
||||
ret = sigaction(SIGUSR2, &s, NULL);
|
||||
assert(ret == 0);
|
||||
ret = sigaction(SIGSEGV, &s, NULL);
|
||||
assert(ret == 0);
|
||||
}
|
||||
|
@ -178,7 +181,7 @@ Context* kcontext(Area kstack, void (*entry)(void *), void *arg) {
|
|||
}
|
||||
|
||||
void yield() {
|
||||
asm volatile (".byte " YIELD_INSTR);
|
||||
raise(SIGUSR2);
|
||||
}
|
||||
|
||||
bool ienabled() {
|
||||
|
|
|
@ -7,6 +7,7 @@ static bool ioe_init_done = false;
|
|||
void __am_timer_init();
|
||||
void __am_gpu_init();
|
||||
void __am_input_init();
|
||||
void __am_audio_init();
|
||||
void __am_input_config(AM_INPUT_CONFIG_T *);
|
||||
void __am_timer_config(AM_TIMER_CONFIG_T *);
|
||||
void __am_timer_rtc(AM_TIMER_RTC_T *);
|
||||
|
@ -57,6 +58,7 @@ void __am_ioe_init() {
|
|||
__am_timer_init();
|
||||
__am_gpu_init();
|
||||
__am_input_init();
|
||||
__am_audio_init();
|
||||
ioe_init_done = true;
|
||||
}
|
||||
|
||||
|
|
72
am/src/native/ioe/audio.c
Normal file
72
am/src/native/ioe/audio.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <klib.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
static int rfd = -1, wfd = -1;
|
||||
static volatile int count = 0;
|
||||
|
||||
void __am_audio_init() {
|
||||
int fds[2];
|
||||
int ret = pipe2(fds, O_NONBLOCK);
|
||||
assert(ret == 0);
|
||||
rfd = fds[0];
|
||||
wfd = fds[1];
|
||||
}
|
||||
|
||||
static void audio_play(void *userdata, uint8_t *stream, int len) {
|
||||
int nread = len;
|
||||
if (count < len) nread = count;
|
||||
int b = 0;
|
||||
while (b < nread) {
|
||||
int n = read(rfd, stream, nread);
|
||||
if (n > 0) b += n;
|
||||
}
|
||||
|
||||
count -= nread;
|
||||
if (len > nread) {
|
||||
memset(stream + nread, 0, len - nread);
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_write(uint8_t *buf, int len) {
|
||||
int nwrite = 0;
|
||||
while (nwrite < len) {
|
||||
int n = write(wfd, buf, len);
|
||||
if (n == -1) n = 0;
|
||||
count += n;
|
||||
nwrite += n;
|
||||
}
|
||||
}
|
||||
|
||||
void __am_audio_ctrl(AM_AUDIO_CTRL_T *ctrl) {
|
||||
SDL_AudioSpec s = {};
|
||||
s.freq = ctrl->freq;
|
||||
s.format = AUDIO_S16SYS;
|
||||
s.channels = ctrl->channels;
|
||||
s.samples = ctrl->samples;
|
||||
s.callback = audio_play;
|
||||
s.userdata = NULL;
|
||||
|
||||
count = 0;
|
||||
int ret = SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
if (ret == 0) {
|
||||
SDL_OpenAudio(&s, NULL);
|
||||
SDL_PauseAudio(0);
|
||||
}
|
||||
}
|
||||
|
||||
void __am_audio_status(AM_AUDIO_STATUS_T *stat) {
|
||||
stat->count = count;
|
||||
}
|
||||
|
||||
void __am_audio_play(AM_AUDIO_PLAY_T *ctl) {
|
||||
int len = ctl->buf.end - ctl->buf.start;
|
||||
audio_write(ctl->buf.start, len);
|
||||
}
|
||||
|
||||
void __am_audio_config(AM_AUDIO_CONFIG_T *cfg) {
|
||||
cfg->present = true;
|
||||
cfg->bufsize = fcntl(rfd, F_GETPIPE_SZ);
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#include <am.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <fenv.h>
|
||||
|
||||
//#define MODE_800x600
|
||||
#ifdef MODE_800x600
|
||||
|
@ -12,35 +13,32 @@
|
|||
|
||||
#define FPS 60
|
||||
|
||||
#define RMASK 0x00ff0000
|
||||
#define GMASK 0x0000ff00
|
||||
#define BMASK 0x000000ff
|
||||
#define AMASK 0x00000000
|
||||
|
||||
static SDL_Window *window = NULL;
|
||||
static SDL_Renderer *renderer = NULL;
|
||||
|
||||
static SDL_Texture *texture = NULL;
|
||||
static uint32_t fb[W * H] = {};
|
||||
|
||||
static inline int min(int x, int y) { return (x < y) ? x : y; }
|
||||
static SDL_Surface *surface = NULL;
|
||||
|
||||
static Uint32 texture_sync(Uint32 interval, void *param) {
|
||||
SDL_UpdateTexture(texture, NULL, fb, W * sizeof(Uint32));
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||
SDL_RenderPresent(renderer);
|
||||
SDL_BlitScaled(surface, NULL, SDL_GetWindowSurface(window), NULL);
|
||||
SDL_UpdateWindowSurface(window);
|
||||
return interval;
|
||||
}
|
||||
|
||||
void __am_gpu_init() {
|
||||
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
|
||||
SDL_CreateWindowAndRenderer(
|
||||
window = SDL_CreateWindow("Native Application",
|
||||
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||
#ifdef MODE_800x600
|
||||
W, H,
|
||||
#else
|
||||
W * 2, H * 2,
|
||||
#endif
|
||||
0, &window, &renderer);
|
||||
SDL_SetWindowTitle(window, "Native Application");
|
||||
texture = SDL_CreateTexture(renderer,
|
||||
SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, W, H);
|
||||
memset(fb, 0, W * H * sizeof(uint32_t));
|
||||
SDL_WINDOW_SHOWN);
|
||||
surface = SDL_CreateRGBSurface(SDL_SWSURFACE, W, H, 32,
|
||||
RMASK, GMASK, BMASK, AMASK);
|
||||
SDL_AddTimer(1000 / FPS, texture_sync, NULL);
|
||||
}
|
||||
|
||||
|
@ -58,10 +56,11 @@ void __am_gpu_status(AM_GPU_STATUS_T *stat) {
|
|||
|
||||
void __am_gpu_fbdraw(AM_GPU_FBDRAW_T *ctl) {
|
||||
int x = ctl->x, y = ctl->y, w = ctl->w, h = ctl->h;
|
||||
uint32_t *pixels = ctl->pixels;
|
||||
int cp_bytes = sizeof(uint32_t) * min(w, W - x);
|
||||
for (int j = 0; j < h && y + j < H; j ++) {
|
||||
memcpy(&fb[(y + j) * W + x], pixels, cp_bytes);
|
||||
pixels += w;
|
||||
}
|
||||
if (w == 0 || h == 0) return;
|
||||
feclearexcept(-1);
|
||||
SDL_Surface *s = SDL_CreateRGBSurfaceFrom(ctl->pixels, w, h, 32, w * sizeof(uint32_t),
|
||||
RMASK, GMASK, BMASK, AMASK);
|
||||
SDL_Rect rect = { .x = x, .y = y };
|
||||
SDL_BlitSurface(s, NULL, surface, &rect);
|
||||
SDL_FreeSurface(s);
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
#include <am.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include "platform.h"
|
||||
|
||||
#define KEYDOWN_MASK 0x8000
|
||||
|
||||
|
@ -31,7 +30,8 @@ static int event_thread(void *args) {
|
|||
key_queue[key_r] = am_code;
|
||||
key_r = (key_r + 1) % KEY_QUEUE_LEN;
|
||||
SDL_UnlockMutex(key_queue_lock);
|
||||
kill(getpid(), SIGUSR1);
|
||||
void __am_send_kbd_intr();
|
||||
__am_send_kbd_intr();
|
||||
}
|
||||
break;
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
#include <am.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static struct timeval boot_time = {};
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
#include <klib.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#define SBUF_SIZE_MAX 65536
|
||||
static uint8_t sbuf [SBUF_SIZE_MAX] = {};
|
||||
static int head = 0, tail = 0;
|
||||
static volatile int count = 0;
|
||||
|
||||
static void audio_play(void *userdata, uint8_t *stream, int len) {
|
||||
int nread = len;
|
||||
if (count < len) nread = count;
|
||||
|
||||
if (nread + tail < SBUF_SIZE_MAX) {
|
||||
memcpy(stream, sbuf + tail, nread);
|
||||
tail += nread;
|
||||
} else {
|
||||
int first_cpy_len = SBUF_SIZE_MAX - tail;
|
||||
memcpy(stream, sbuf + tail, first_cpy_len);
|
||||
memcpy(stream + first_cpy_len, sbuf, nread - first_cpy_len);
|
||||
tail = nread - first_cpy_len;
|
||||
}
|
||||
count -= nread;
|
||||
if (len > nread) memset(stream + nread, 0, len - nread);
|
||||
}
|
||||
|
||||
static int audio_write(uint8_t *buf, int len) {
|
||||
int free = SBUF_SIZE_MAX - count;
|
||||
int nwrite = len;
|
||||
if (free < len) nwrite = free;
|
||||
|
||||
if (nwrite + head < SBUF_SIZE_MAX) {
|
||||
memcpy(sbuf + head, buf, nwrite);
|
||||
head += nwrite;
|
||||
} else {
|
||||
int first_cpy_len = SBUF_SIZE_MAX - head;
|
||||
memcpy(sbuf + head, buf, first_cpy_len);
|
||||
memcpy(sbuf, buf + first_cpy_len, nwrite - first_cpy_len);
|
||||
head = nwrite - first_cpy_len;
|
||||
}
|
||||
count += nwrite;
|
||||
return nwrite;
|
||||
}
|
||||
|
||||
void __am_audio_ctrl(AM_AUDIO_CTRL_T *ctrl) {
|
||||
SDL_AudioSpec s = {};
|
||||
s.freq = ctrl->freq;
|
||||
s.format = AUDIO_S16SYS;
|
||||
s.channels = ctrl->channels;
|
||||
s.samples = ctrl->samples;
|
||||
s.callback = audio_play;
|
||||
s.userdata = NULL;
|
||||
|
||||
head = tail = 0;
|
||||
count = 0;
|
||||
int ret = SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
if (ret == 0) {
|
||||
SDL_OpenAudio(&s, NULL);
|
||||
SDL_PauseAudio(0);
|
||||
}
|
||||
}
|
||||
|
||||
void __am_audio_status(AM_AUDIO_STATUS_T *stat) {
|
||||
stat->count = count;
|
||||
}
|
||||
|
||||
void __am_audio_play(AM_AUDIO_PLAY_T *ctl) {
|
||||
int len = ctl->buf.end - ctl->buf.start;
|
||||
assert(len <= SBUF_SIZE_MAX);
|
||||
while (SBUF_SIZE_MAX - count < len);
|
||||
audio_write(ctl->buf.start, len);
|
||||
}
|
||||
|
||||
void __am_audio_config(AM_AUDIO_CONFIG_T *cfg) {
|
||||
cfg->present = true;
|
||||
cfg->bufsize = SBUF_SIZE_MAX;
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <sys/mman.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <dlfcn.h>
|
||||
#include <elf.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
@ -9,18 +10,19 @@
|
|||
#define MAX_CPU 16
|
||||
#define TRAP_PAGE_START (void *)0x100000
|
||||
#define PMEM_START (void *)0x1000000 // for nanos-lite with vme disabled
|
||||
#define PMEM_SIZE (128 * 1024 * 1024)
|
||||
#define PMEM_SIZE (128 * 1024 * 1024) // 128MB
|
||||
static int pmem_fd = 0;
|
||||
static void *pmem = NULL;
|
||||
static ucontext_t uc_example = {};
|
||||
static int sys_pgsz;
|
||||
static void *(*memcpy_libc)(void *, const void *, size_t) = NULL;
|
||||
sigset_t __am_intr_sigmask = {};
|
||||
__am_cpu_t *__am_cpu_struct = NULL;
|
||||
int __am_ncpu = 0;
|
||||
int __am_pgsize;
|
||||
|
||||
static void save_context_handler(int sig, siginfo_t *info, void *ucontext) {
|
||||
memcpy(&uc_example, ucontext, sizeof(uc_example));
|
||||
memcpy_libc(&uc_example, ucontext, sizeof(uc_example));
|
||||
}
|
||||
|
||||
static void save_example_context() {
|
||||
|
@ -30,7 +32,8 @@ static void save_example_context() {
|
|||
// registers. So we save the example context during signal handling
|
||||
// to get a context with everything valid.
|
||||
struct sigaction s;
|
||||
memset(&s, 0, sizeof(s));
|
||||
void *(*memset_libc)(void *, int, size_t) = dlsym(RTLD_NEXT, "memset");
|
||||
memset_libc(&s, 0, sizeof(s));
|
||||
s.sa_sigaction = save_context_handler;
|
||||
s.sa_flags = SA_SIGINFO;
|
||||
int ret = sigaction(SIGUSR1, &s, NULL);
|
||||
|
@ -79,6 +82,10 @@ static void init_platform() {
|
|||
MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
assert(ret != (void *)-1);
|
||||
|
||||
// save the address of memcpy() in glibc, since it may be linked with klib
|
||||
memcpy_libc = dlsym(RTLD_NEXT, "memcpy");
|
||||
assert(memcpy_libc != NULL);
|
||||
|
||||
// remap writable sections as MAP_SHARED
|
||||
Elf64_Phdr *phdr = (void *)getauxval(AT_PHDR);
|
||||
int phnum = (int)getauxval(AT_PHNUM);
|
||||
|
@ -96,12 +103,15 @@ static void init_platform() {
|
|||
assert(temp_mem != (void *)-1);
|
||||
|
||||
// save data and bss sections
|
||||
memcpy(temp_mem, vaddr_align, size);
|
||||
memcpy_libc(temp_mem, vaddr_align, size);
|
||||
|
||||
// save the addresses of library functions which will be used after munamp()
|
||||
// save the address of mmap() which will be used after munamp(),
|
||||
// since calling the library functions requires accessing GOT, which will be unmapped
|
||||
void *(*volatile mmap_libc)(void *, size_t, int, int, int, off_t) = &mmap;
|
||||
void *(*volatile memcpy_libc)(void *, const void *, size_t) = &memcpy;
|
||||
void *(*mmap_libc)(void *, size_t, int, int, int, off_t) = dlsym(RTLD_NEXT, "mmap");
|
||||
assert(mmap_libc != NULL);
|
||||
// load the address of memcpy() on stack, which can still be accessed
|
||||
// after the data section is unmapped
|
||||
void *(*volatile memcpy_libc_temp)(void *, const void *, size_t) = memcpy_libc;
|
||||
|
||||
// unmap the data and bss sections
|
||||
ret2 = munmap(vaddr_align, size);
|
||||
|
@ -113,7 +123,7 @@ static void init_platform() {
|
|||
assert(ret == vaddr_align);
|
||||
|
||||
// restore the data in the sections
|
||||
memcpy_libc(vaddr_align, temp_mem, size);
|
||||
memcpy_libc_temp(vaddr_align, temp_mem, size);
|
||||
|
||||
// unmap the temporary memory
|
||||
ret2 = munmap(temp_mem, size);
|
||||
|
@ -185,17 +195,21 @@ void __am_pmem_unmap(void *va) {
|
|||
}
|
||||
|
||||
void __am_get_example_uc(Context *r) {
|
||||
memcpy(&r->uc, &uc_example, sizeof(uc_example));
|
||||
memcpy_libc(&r->uc, &uc_example, sizeof(uc_example));
|
||||
}
|
||||
|
||||
void __am_get_intr_sigmask(sigset_t *s) {
|
||||
memcpy(s, &__am_intr_sigmask, sizeof(__am_intr_sigmask));
|
||||
memcpy_libc(s, &__am_intr_sigmask, sizeof(__am_intr_sigmask));
|
||||
}
|
||||
|
||||
int __am_is_sigmask_sti(sigset_t *s) {
|
||||
return !sigismember(s, SIGVTALRM);
|
||||
}
|
||||
|
||||
void __am_send_kbd_intr() {
|
||||
kill(getpid(), SIGUSR1);
|
||||
}
|
||||
|
||||
void __am_pmem_protect() {
|
||||
// int ret = mprotect(PMEM_START, PMEM_SIZE, PROT_NONE);
|
||||
// assert(ret == 0);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <search.h>
|
||||
#include "platform.h"
|
||||
|
||||
#define USER_SPACE RANGE(0x40000000, 0xc0000000)
|
||||
|
@ -8,10 +10,17 @@ typedef struct PageMap {
|
|||
struct PageMap *next;
|
||||
int prot;
|
||||
int is_mapped;
|
||||
char key[32]; // used for hsearch_r()
|
||||
} PageMap;
|
||||
|
||||
typedef struct VMHead {
|
||||
PageMap *head;
|
||||
struct hsearch_data hash;
|
||||
int nr_page;
|
||||
} VMHead;
|
||||
|
||||
#define list_foreach(p, head) \
|
||||
for (p = ((PageMap *)(head))->next; p != NULL; p = p->next)
|
||||
for (p = (PageMap *)(head); p != NULL; p = p->next)
|
||||
|
||||
extern int __am_pgsize;
|
||||
static int vme_enable = 0;
|
||||
|
@ -27,7 +36,14 @@ bool vme_init(void* (*pgalloc_f)(int), void (*pgfree_f)(void*)) {
|
|||
|
||||
void protect(AddrSpace *as) {
|
||||
assert(as != NULL);
|
||||
as->ptr = pgalloc(__am_pgsize); // used as head of the list
|
||||
VMHead *h = pgalloc(__am_pgsize); // used as head of the list
|
||||
assert(h != NULL);
|
||||
memset(h, 0, sizeof(*h));
|
||||
int max_pg = (USER_SPACE.end - USER_SPACE.start) / __am_pgsize;
|
||||
int ret = hcreate_r(max_pg, &h->hash);
|
||||
assert(ret != 0);
|
||||
|
||||
as->ptr = h;
|
||||
as->pgsize = __am_pgsize;
|
||||
as->area = USER_SPACE;
|
||||
}
|
||||
|
@ -38,13 +54,14 @@ void unprotect(AddrSpace *as) {
|
|||
void __am_switch(Context *c) {
|
||||
if (!vme_enable) return;
|
||||
|
||||
PageMap *head = c->vm_head;
|
||||
if (head == thiscpu->vm_head) return;
|
||||
VMHead *head = c->vm_head;
|
||||
VMHead *now_head = thiscpu->vm_head;
|
||||
if (head == now_head) goto end;
|
||||
|
||||
PageMap *pp;
|
||||
if (thiscpu->vm_head != NULL) {
|
||||
if (now_head != NULL) {
|
||||
// munmap all mappings
|
||||
list_foreach(pp, thiscpu->vm_head) {
|
||||
list_foreach(pp, now_head->head) {
|
||||
if (pp->is_mapped) {
|
||||
__am_pmem_unmap(pp->va);
|
||||
pp->is_mapped = false;
|
||||
|
@ -54,13 +71,14 @@ void __am_switch(Context *c) {
|
|||
|
||||
if (head != NULL) {
|
||||
// mmap all mappings
|
||||
list_foreach(pp, head) {
|
||||
list_foreach(pp, head->head) {
|
||||
assert(IN_RANGE(pp->va, USER_SPACE));
|
||||
__am_pmem_map(pp->va, pp->pa, pp->prot);
|
||||
pp->is_mapped = true;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
thiscpu->vm_head = head;
|
||||
}
|
||||
|
||||
|
@ -70,23 +88,30 @@ void map(AddrSpace *as, void *va, void *pa, int prot) {
|
|||
assert((uintptr_t)pa % __am_pgsize == 0);
|
||||
assert(as != NULL);
|
||||
PageMap *pp = NULL;
|
||||
PageMap *vm_head = as->ptr;
|
||||
VMHead *vm_head = as->ptr;
|
||||
assert(vm_head != NULL);
|
||||
list_foreach(pp, vm_head) {
|
||||
if (pp->va == va) break;
|
||||
}
|
||||
|
||||
if (pp == NULL) {
|
||||
char buf[32];
|
||||
snprintf(buf, 32, "%x", va);
|
||||
ENTRY item = { .key = buf };
|
||||
ENTRY *item_find;
|
||||
hsearch_r(item, FIND, &item_find, &vm_head->hash);
|
||||
if (item_find == NULL) {
|
||||
pp = pgalloc(__am_pgsize); // this will waste memory, any better idea?
|
||||
snprintf(pp->key, 32, "%x", va);
|
||||
item.key = pp->key;
|
||||
item.data = pp;
|
||||
int ret = hsearch_r(item, ENTER, &item_find, &vm_head->hash);
|
||||
assert(ret != 0);
|
||||
vm_head->nr_page ++;
|
||||
} else {
|
||||
pp = item_find->data;
|
||||
}
|
||||
pp->va = va;
|
||||
pp->pa = pa;
|
||||
pp->prot = prot;
|
||||
pp->is_mapped = false;
|
||||
// add after to vm_head to keep vm_head unchanged,
|
||||
// since vm_head is a key to describe an address space
|
||||
pp->next = vm_head->next;
|
||||
vm_head->next = pp;
|
||||
pp->next = vm_head->head;
|
||||
vm_head->head = pp;
|
||||
|
||||
if (vm_head == thiscpu->vm_head) {
|
||||
// enforce the map immediately
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
_pmem_start = 0x80000000;
|
||||
|
||||
/* at $(AM_HOME)/am/src/nemu/scripts/section.ld */
|
||||
INCLUDE "section.ld"
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
static Context* (*user_handler)(Event, Context*) = NULL;
|
||||
|
||||
static inline bool get_CU0(Context *c) { return (c->status >> 28) & 0x1; }
|
||||
|
||||
Context* __am_irq_handle(Context *c) {
|
||||
if (user_handler) {
|
||||
Event ev = {0};
|
||||
|
|
|
@ -26,12 +26,12 @@ f(30) f(31)
|
|||
.set noat
|
||||
.globl __am_asm_trap
|
||||
__am_asm_trap:
|
||||
move $k0, $sp
|
||||
move $k1, $sp
|
||||
addiu $sp, $sp, -CONTEXT_SIZE
|
||||
|
||||
MAP(REGS, PUSH)
|
||||
|
||||
sw $k0, OFFSET_SP($sp)
|
||||
sw $k1, OFFSET_SP($sp)
|
||||
|
||||
mflo $t0
|
||||
mfhi $t1
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
_pmem_start = 0x80000000;
|
||||
|
||||
/* at $(AM_HOME)/am/src/nemu/scripts/section.ld */
|
||||
INCLUDE "section.ld"
|
|
@ -1,4 +0,0 @@
|
|||
_pmem_start = 0x80000000;
|
||||
|
||||
/* at $(AM_HOME)/am/src/nemu/scripts/section.ld */
|
||||
INCLUDE "section.ld"
|
|
@ -1,4 +0,0 @@
|
|||
_pmem_start = 0x0;
|
||||
|
||||
/* at $(AM_HOME)/am/src/nemu/scripts/section.ld */
|
||||
INCLUDE "section.ld"
|
|
@ -1,7 +1,10 @@
|
|||
#include <am.h>
|
||||
#include <stdatomic.h>
|
||||
#include <klib-macros.h>
|
||||
|
||||
bool mpe_init(void (*entry)()) {
|
||||
return false;
|
||||
entry();
|
||||
panic("MPE entry returns");
|
||||
}
|
||||
|
||||
int cpu_count() {
|
||||
|
@ -13,5 +16,5 @@ int cpu_current() {
|
|||
}
|
||||
|
||||
int atomic_xchg(int *addr, int newval) {
|
||||
return 0;
|
||||
return atomic_exchange(addr, newval);
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
ENTRY(_start)
|
||||
|
||||
SECTIONS {
|
||||
. = _pmem_start + 0x100000;
|
||||
.text : {
|
||||
*(entry)
|
||||
*(.text*)
|
||||
}
|
||||
etext = .;
|
||||
_etext = .;
|
||||
.rodata : {
|
||||
*(.rodata*)
|
||||
}
|
||||
.data : {
|
||||
*(.data)
|
||||
}
|
||||
edata = .;
|
||||
_data = .;
|
||||
.bss : {
|
||||
_bss_start = .;
|
||||
*(.bss*)
|
||||
*(.sbss*)
|
||||
*(.scommon)
|
||||
}
|
||||
_stack_top = ALIGN(0x1000);
|
||||
. = _stack_top + 0x8000;
|
||||
_stack_pointer = .;
|
||||
end = .;
|
||||
_end = .;
|
||||
_heap_start = ALIGN(0x1000);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
SRCS := start.S main.c
|
||||
bootblock.o: $(SRCS) Makefile
|
||||
@echo + CC $(SRCS)
|
||||
@gcc -m32 -Os -nostdlib -Ttext 0x7c00 -I$(AM_HOME)/am/src -o bootblock.o $(SRCS)
|
||||
@$(CROSS_COMPILE)gcc -static -m32 -fno-pic -Os -nostdlib -Ttext 0x7c00 -I$(AM_HOME)/am/src -o bootblock.o $(SRCS)
|
||||
@python3 genboot.py bootblock.o
|
||||
|
||||
clean:
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import sys, pathlib, subprocess
|
||||
import os, sys, pathlib, subprocess
|
||||
|
||||
f = pathlib.Path(sys.argv[1])
|
||||
try:
|
||||
objcopy = os.getenv('CROSS_COMPILE', '') + 'objcopy'
|
||||
data = subprocess.run(
|
||||
['objcopy', '-S', '-O', 'binary', '-j', '.text', f, '/dev/stdout'],
|
||||
[objcopy, '-S', '-O', 'binary', '-j', '.text', f, '/dev/stdout'],
|
||||
capture_output=True).stdout
|
||||
assert len(data) <= 510
|
||||
data += b'\0' * (510 - len(data)) + b'\x55\xaa'
|
||||
|
|
|
@ -14,7 +14,7 @@ static GateDesc32 idt[NR_IRQ];
|
|||
|
||||
IRQS(IRQHANDLE_DECL)
|
||||
void __am_irqall();
|
||||
void __amkcontext_start();
|
||||
void __am_kcontext_start();
|
||||
|
||||
void __am_irq_handle(struct trap_frame *tf) {
|
||||
Context *saved_ctx = &tf->saved_context;
|
||||
|
@ -141,13 +141,13 @@ Context* kcontext(Area kstack, void (*entry)(void *), void *arg) {
|
|||
|
||||
#if __x86_64__
|
||||
ctx->cs = KSEL(SEG_KCODE);
|
||||
ctx->rip = (uintptr_t)__amkcontext_start;
|
||||
ctx->rip = (uintptr_t)__am_kcontext_start;
|
||||
ctx->rflags = FL_IF;
|
||||
ctx->rsp = (uintptr_t)kstack.end;
|
||||
#else
|
||||
ctx->ds = KSEL(SEG_KDATA);
|
||||
ctx->cs = KSEL(SEG_KCODE);
|
||||
ctx->eip = (uintptr_t)__amkcontext_start;
|
||||
ctx->eip = (uintptr_t)__am_kcontext_start;
|
||||
ctx->eflags = FL_IF;
|
||||
ctx->esp = (uintptr_t)kstack.end;
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "x86-qemu.h"
|
||||
|
||||
.globl __amkcontext_start
|
||||
__amkcontext_start:
|
||||
.globl __am_kcontext_start
|
||||
__am_kcontext_start:
|
||||
// eax = arg, ebx = entry
|
||||
pushl %eax
|
||||
pushl $__am_panic_on_return
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "x86-qemu.h"
|
||||
|
||||
.globl __amkcontext_start
|
||||
__amkcontext_start:
|
||||
.globl __am_kcontext_start
|
||||
__am_kcontext_start:
|
||||
// rdi = arg, rsi = entry
|
||||
pushq $__am_panic_on_return
|
||||
jmpq *%rsi
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
#include "x86-qemu.h"
|
||||
|
||||
Area heap = {};
|
||||
volatile uint32_t *__am_lapic;
|
||||
int __am_ncpu = 0;
|
||||
struct cpu_local __am_cpuinfo[MAX_CPU];
|
||||
|
||||
int main(const char *args);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue