ctx switch and kenter/kexit

This commit is contained in:
quackerd 2024-11-19 14:00:13 -05:00
parent a1bf1cd7b4
commit db8c734f4e
22 changed files with 378 additions and 76 deletions

View File

@ -61,6 +61,7 @@ src_arm64 = [
"arm64/paging.c", "arm64/paging.c",
"arm64/mrt/init.c", "arm64/mrt/init.c",
"arm64/mrt/paging.c", "arm64/mrt/paging.c",
"arm64/mrt/priv.c"
] ]
src_common = [ src_common = [

View File

@ -11,8 +11,6 @@
#define DECL_MRT(name) void MCODE name(void) #define DECL_MRT(name) void MCODE name(void)
#endif #endif
#define MGREG_MSTK (MCREG_MG16)
#if defined(IMPL_MRT) #if defined(IMPL_MRT)
#undef IMPL_MRT #undef IMPL_MRT
#define IMPL_MRT(name) int MCODE _ ## name ## _impl(void); \ #define IMPL_MRT(name) int MCODE _ ## name ## _impl(void); \
@ -21,38 +19,22 @@
".globl " METAL_STR(name) ";" \ ".globl " METAL_STR(name) ";" \
".balign 16;" \ ".balign 16;" \
METAL_STR(name) ":;" \ METAL_STR(name) ":;" \
METAL_STR(RMCR_GAS(MGREG_MSTK, REG_X0)) ";" \
"mov x1, sp;" \
"str x1, [x0, #-16]!;" \
"mov sp, x0;" \
"mov x0, xzr;" \ "mov x0, xzr;" \
"ldr x0,=_" METAL_STR(name) "_impl;" \ "ldr x0,=_" METAL_STR(name) "_impl;" \
"blr x0;" \ "blr x0;" \
"ldr x1, [sp], #16;" \
"mov sp, x1;" \
METAL_STR(WMR_GAS(MREG_MR0, REG_X0)) ";" \ METAL_STR(WMR_GAS(MREG_MR0, REG_X0)) ";" \
METAL_STR(MEXIT_GAS(MREG_MR0)) ";" \ METAL_STR(MEXIT_GAS(MREG_MR0)) ";" \
); \ ); \
int MCODE _ ## name ## _impl(void) int MCODE _ ## name ## _impl(void)
#endif #endif
#define IMPL_SHORT_MRT(name) int MCODE _ ## name ## _impl(void); \
__asm__ ( \
".section \"mcode\";" \
".globl " METAL_STR(name) ";" \
".balign 16;" \
METAL_STR(name) ":;" \
"mov x0, xzr;" \
"ldr x0,=_" METAL_STR(name) "_impl;" \
"blr x0;" \
METAL_STR(WMR_GAS(MREG_MR0, REG_X0)) ";" \
METAL_STR(MEXIT_GAS(MREG_MR0)) ";" \
); \
int MCODE _ ## name ## _impl(void)
#define DECL_MVAR(type, name) type MDATA name #define DECL_MVAR(type, name) type MDATA name
#define DECL_MVAR_ALIGNED(type, name, align) type ALIGNED(align) MDATA name #define DECL_MVAR_ALIGNED(type, name, align) type ALIGNED(align) MDATA name
#define MGREG_MPTB_DMAP (MCREG_MG19) #define MGREG_MPTB_DMAP (MCREG_MG19)
#define MGREG_MPTB_XMEM (MCREG_MG18) #define MGREG_MPTB_XMEM (MCREG_MG18)
#define MGREG_MPTB_USER (MCREG_MG17) #define MGREG_MPTB_USER (MCREG_MG17)
#define MGREG_MCPL (MCREG_MG20)
#define MGREG_TMPRET (MCREG_MG21)
#define MCPL_KERNEL (0)
#define MCPL_USER (1)

View File

@ -121,6 +121,7 @@
#define MCREG_MEB (MCREG_MG3) #define MCREG_MEB (MCREG_MG3)
#define MCREG_MTP (MCREG_MG4) #define MCREG_MTP (MCREG_MG4)
#define MCREG_MAR (MCREG_MG5) #define MCREG_MAR (MCREG_MG5)
#define MCREG_MSTK (MCREG_MG6)
#define _METAL_STR(x) #x #define _METAL_STR(x) #x
#define METAL_STR(x) _METAL_STR(x) #define METAL_STR(x) _METAL_STR(x)

View File

@ -17,12 +17,15 @@ void MP_CrossCallTrap();
int MP_CrossCall(CrossCallCB cb, void *arg); int MP_CrossCall(CrossCallCB cb, void *arg);
struct CPUState { struct CPUState {
vaddr_t kstack;
unsigned int id; unsigned int id;
uint32_t mpid; uint32_t mpid;
uint32_t gic_redist_id; uint32_t gic_redist_id;
volatile int state; volatile int state;
}; };
_Static_assert(offsetof(struct CPUState, kstack) == 0);
register uint64_t _cpu __asm__("x18"); register uint64_t _cpu __asm__("x18");
static inline unsigned int CPU(void) static inline unsigned int CPU(void)
{ {

View File

@ -38,6 +38,12 @@ DECL_MRT(mrt_set_mtp);
DECL_MRT(mrt_wfi); DECL_MRT(mrt_wfi);
#define MRT_WFI_IDX (6) #define MRT_WFI_IDX (6)
DECL_MRT(mrt_kenter);
#define MRT_KENTER_IDX (7)
DECL_MRT(mrt_kexit);
#define MRT_KEXIT_IDX (8)
extern DECL_MVAR(struct mroutine_table, mtl_mrt_tbl); extern DECL_MVAR(struct mroutine_table, mtl_mrt_tbl);
extern DECL_MVAR(struct exc_intercept_table, mtl_exc_tbl); extern DECL_MVAR(struct exc_intercept_table, mtl_exc_tbl);

View File

@ -6,11 +6,25 @@
#include <machine/cpuop.h> #include <machine/cpuop.h>
typedef struct ThreadArchStackFrame { typedef struct ThreadArchStackFrame {
uint64_t r0;
uint64_t _r0;
uint64_t r19;
uint64_t r20;
uint64_t r21;
uint64_t r22;
uint64_t r23;
uint64_t r24;
uint64_t r25;
uint64_t r26;
uint64_t r27;
uint64_t r28;
uint64_t fp;
uint64_t lr;
} ThreadArchStackFrame; } ThreadArchStackFrame;
_Static_assert(sizeof(ThreadArchStackFrame) % 16 == 0);
typedef struct ThreadArch { typedef struct ThreadArch {
bool useFP; uint64_t sp;
uint64_t rsp;
} ThreadArch; } ThreadArch;
#endif /* __MACHINE_THREAD_H__ */ #endif /* __MACHINE_THREAD_H__ */

View File

@ -114,7 +114,12 @@ typedef struct TrapFrame
uint64_t r29; uint64_t r29;
uint64_t r30; uint64_t r30;
uint64_t r31; uint64_t r31;
uint64_t pcpl;
uint64_t psp;
} TrapFrame; } TrapFrame;
void Trap_Pop(struct TrapFrame * tf);
#endif /* __TRAP_H__ */ #endif /* __TRAP_H__ */

View File

@ -71,7 +71,7 @@ Machine_EarlyInit()
static void static void
Machine_IdleThread(UNUSED void *test) Machine_IdleThread(UNUSED void *test)
{ {
while (1) { enable_interrupts(); hlt(); } while (1) { kprintf("Idle Thread!\n"); enable_interrupts(); hlt(); }
} }
/** /**
@ -138,12 +138,6 @@ void Machine_Init()
Panic("No boot disk!"); Panic("No boot disk!");
VFS_MountRoot(root); VFS_MountRoot(root);
Critical_Exit();
while(1){
hlt();
}
/* /*
* Create the idle thread * Create the idle thread
*/ */
@ -153,6 +147,12 @@ void Machine_Init()
} }
Sched_SetRunnable(thr); Sched_SetRunnable(thr);
Critical_Exit();
while(1) {
kprintf("Main thread!\n");
hlt();
}
/* /*
* Load the init processor * Load the init processor
*/ */

View File

@ -2,6 +2,9 @@
#include <string.h> #include <string.h>
#include <machine/pmap.h> #include <machine/pmap.h>
#define METAL_BOOTSTACK_SZ (4096)
DECL_MVAR_ALIGNED(static char, mtl_bootstack[METAL_BOOTSTACK_SZ], METAL_BOOTSTACK_SZ);
// early metal init // early metal init
void mtl_init(void) void mtl_init(void)
{ {
@ -10,6 +13,10 @@ void mtl_init(void)
mtl_mrt_tbl.entries[MRT_INIT_IDX] = MRT_ENTRY_MAKE(mrt_init, 1); mtl_mrt_tbl.entries[MRT_INIT_IDX] = MRT_ENTRY_MAKE(mrt_init, 1);
// load metal stack for the boot core
const regval_t mstk = (regval_t)(mtl_bootstack + METAL_BOOTSTACK_SZ);
WMCR(MCREG_MSTK, mstk);
// load mroutine table // load mroutine table
WMCR(MCREG_MBR, &mtl_mrt_tbl); WMCR(MCREG_MBR, &mtl_mrt_tbl);

View File

@ -6,15 +6,13 @@
DECL_MVAR(struct mroutine_table, mtl_mrt_tbl); DECL_MVAR(struct mroutine_table, mtl_mrt_tbl);
DECL_MVAR(struct exc_intercept_table, mtl_exc_tbl); DECL_MVAR(struct exc_intercept_table, mtl_exc_tbl);
DECL_MVAR(struct inst_intercept_table, mtl_inst_tbl); DECL_MVAR(struct inst_intercept_table, mtl_inst_tbl);
#define METAL_BOOTSTACK_SZ (4096)
DECL_MVAR_ALIGNED(static char, mtl_bootstack[METAL_BOOTSTACK_SZ], METAL_BOOTSTACK_SZ);
IMPL_SHORT_MRT(mrt_dummy) IMPL_MRT(mrt_dummy)
{ {
return 0; return 0;
} }
IMPL_SHORT_MRT(mrt_wfi) IMPL_MRT(mrt_wfi)
{ {
unsigned int times; unsigned int times;
MRT_GETARG(0, times); MRT_GETARG(0, times);
@ -30,7 +28,7 @@ IMPL_SHORT_MRT(mrt_wfi)
return 0; return 0;
} }
IMPL_SHORT_MRT(mrt_init) IMPL_MRT(mrt_init)
{ {
memset(&mtl_mrt_tbl, 0, sizeof(mtl_mrt_tbl)); memset(&mtl_mrt_tbl, 0, sizeof(mtl_mrt_tbl));
memset(&mtl_exc_tbl, 0, sizeof(mtl_exc_tbl)); memset(&mtl_exc_tbl, 0, sizeof(mtl_exc_tbl));
@ -44,6 +42,8 @@ IMPL_SHORT_MRT(mrt_init)
mtl_mrt_tbl.entries[MRT_SET_MPTB_IDX] = MRT_ENTRY_MAKE(mrt_set_mptb, 1); mtl_mrt_tbl.entries[MRT_SET_MPTB_IDX] = MRT_ENTRY_MAKE(mrt_set_mptb, 1);
mtl_mrt_tbl.entries[MRT_SET_MTP_IDX] = MRT_ENTRY_MAKE(mrt_set_mtp, 1); mtl_mrt_tbl.entries[MRT_SET_MTP_IDX] = MRT_ENTRY_MAKE(mrt_set_mtp, 1);
mtl_mrt_tbl.entries[MRT_WFI_IDX] = MRT_ENTRY_MAKE(mrt_wfi, 1); mtl_mrt_tbl.entries[MRT_WFI_IDX] = MRT_ENTRY_MAKE(mrt_wfi, 1);
mtl_mrt_tbl.entries[MRT_KENTER_IDX] = MRT_ENTRY_MAKE(mrt_kenter, 1);
mtl_mrt_tbl.entries[MRT_KEXIT_IDX] = MRT_ENTRY_MAKE(mrt_kexit, 1);
mtl_exc_tbl.entries[0].esrbits = (0b100100 << 26) | (0b00100); // data abort, lv0 translation mtl_exc_tbl.entries[0].esrbits = (0b100100 << 26) | (0b00100); // data abort, lv0 translation
mtl_exc_tbl.entries[0].esrmask = (0b111111 << 26) | (0b11111); mtl_exc_tbl.entries[0].esrmask = (0b111111 << 26) | (0b11111);
@ -111,9 +111,9 @@ IMPL_SHORT_MRT(mrt_init)
msr |= (1ull << 60); msr |= (1ull << 60);
WMCR(MCREG_MSR, msr); WMCR(MCREG_MSR, msr);
// temporary metal stack // set cpl = 0
regval_t mstk = (regval_t)&mtl_bootstack[METAL_BOOTSTACK_SZ]; regval_t zero = 0;
WMCR(MGREG_MSTK, mstk); WMCR(MGREG_MCPL, zero);
return 0; return 0;
} }

72
sys/arm64/mrt/priv.c Normal file
View File

@ -0,0 +1,72 @@
#include <machine/metal.h>
#include <machine/mrt.h>
#include <machine/paging.h>
#include <machine/mp.h>
#include <sys/thread.h>
extern Thread *curProc[MAX_CPUS];
IMPL_MRT(mrt_kenter)
{
regval_t pcpl;
RMCR(MGREG_MCPL, pcpl);
regval_t kstack_top, psp;
psp = SYSREG_GET(sp_el1);
if (pcpl == MCPL_USER) {
// switch MTP
const regval_t kmtp = MTP_KERNEL;
WMCR(MCREG_MTP, kmtp);
// switch to kernel stack
struct CPUState * state = (struct CPUState *)SYSREG_GET(tpidr_el1);
const uint32_t id = state->id;
kstack_top = curProc[id]->kstack + PGSIZE;
const regval_t kcpl = MCPL_KERNEL;
WMCR(MGREG_MCPL, kcpl);
} else {
// we already in kernel mode
kstack_top = SYSREG_GET(sp_el1);
}
// store var onto the current kstack
// [kstack top] = pcpl
// [kstack top] + 8 = psp
kstack_top = kstack_top - 2 * sizeof(regval_t);
*(regval_t *)kstack_top = pcpl;
*(regval_t *)(kstack_top + sizeof(regval_t)) = psp;
SYSREG_SET(sp_el1, kstack_top);
return 0;
}
IMPL_MRT(mrt_kexit)
{
regval_t cpl;
RMCR(MGREG_MCPL, cpl);
ASSERT(cpl == MCPL_KERNEL);
// [kstack top] = pcpl
// [kstack top] + 8 = psp
regval_t kstack_top = SYSREG_GET(sp_el1);
const regval_t psp = *(regval_t *)(kstack_top + sizeof(regval_t));
const regval_t pcpl = *(regval_t *)(kstack_top);
kstack_top += 2 * sizeof(regval_t);
if (pcpl == MCPL_USER) {
// we are going back to usermode
// switch MTP to user
const regval_t kmtp = MTP_USER;
WMCR(MCREG_MTP, kmtp);
const regval_t kcpl = MCPL_USER;
WMCR(MGREG_MCPL, kcpl);
}
// restore previous stack ptr
SYSREG_SET(sp_el1, psp);
return 0;
}

View File

@ -74,6 +74,9 @@ void vm_early_paging_init()
SYSREG_SET(ttbr0_el1, zero); SYSREG_SET(ttbr0_el1, zero);
SYSREG_SET(ttbr1_el1, zero); SYSREG_SET(ttbr1_el1, zero);
// set MCPL to 0
// reset page tables // reset page tables
flushtlb(); flushtlb();
} }

View File

@ -124,6 +124,26 @@ PMap_NewAS()
return as; return as;
} }
static void
pmap_destroy_vmpt(struct vmpt * const pt)
{
for (size_t i = 0; i < VM_PTBUCKETS; i++) {
paddr_t curp = pt->entries[i].first;
while(curp != 0) {
struct vmpd * const cur = (struct vmpd *)DMPA2VA(curp);
const paddr_t pnext = cur->next;
pdcache_free(cur);
curp = pnext;
}
}
// release vmpt
PAlloc_Release(pt);
}
/** /**
* PMap_DestroyAS -- * PMap_DestroyAS --
* *
@ -135,13 +155,10 @@ void
PMap_DestroyAS(AS *space) PMap_DestroyAS(AS *space)
{ {
// free usertables // free usertables
UNUSED struct vmpt * pt = space->user_tbl; pmap_destroy_vmpt(space->user_tbl);
// release space itself // release space itself
PAlloc_Release(space); PAlloc_Release(space);
// XXX: release all pdcaches
NOT_IMPLEMENTED();
} }
/** /**
@ -205,7 +222,7 @@ PMap_LoadAS(AS *space)
} }
static void static void
PMap_MapPage(uint64_t phys, uint64_t virt, uint64_t pages, uint32_t pgshift, struct vmpt * tbl, uint64_t flags) PMap_MapPage(paddr_t phys, vaddr_t virt, size_t pages, uint32_t pgshift, struct vmpt * tbl, uint64_t flags)
{ {
unsigned int i = 0; unsigned int i = 0;
while (i < pages) { while (i < pages) {
@ -229,6 +246,59 @@ PMap_MapPage(uint64_t phys, uint64_t virt, uint64_t pages, uint32_t pgshift, str
} }
} }
static bool
PMap_FindVmpd(struct vmpte * pte, vaddr_t virt, uint32_t pgshift, struct vmpd ** curout, struct vmpd ** prevout)
{
paddr_t curp = pte->first;
struct vmpd * prev = NULL;
while (curp != 0) {
struct vmpd * const cur = (struct vmpd *)DMPA2VA(curp);
if (vm_get_pfn(cur->vaddr, pgshift) == vm_get_pfn(virt, pgshift)) {
if (prevout != NULL) {
*prevout = prev;
}
if (curout != NULL) {
*curout = cur;
}
return true;
}
prev = cur;
curp = cur->next;
}
return false;
}
static void
PMap_UnmapPage(vaddr_t virt, size_t pages, uint32_t pgshift, struct vmpt * tbl)
{
ASSERT((virt & ((1ull << pgshift) - 1)) == 0);
for (uint64_t i = 0; i < pages; i++) {
const vaddr_t va = virt + i * (1ull << pgshift);
const uint64_t pfn = vm_get_pfn(va, pgshift);
const uint64_t hash = vm_vahash(pfn);
ASSERT(hash < VM_PTBUCKETS);
struct vmpte * const pte = &tbl->entries[hash];
struct vmpd *found, *prev;
if (!PMap_FindVmpd(pte, virt, pgshift, &found, &prev)) {
Panic("Unmapping an unmapped vaddr.\n");
}
// detach the node
if (prev == NULL) {
// first node
pte->first = found->next;
} else {
prev->next = found->next;
}
// free the unmapped pd
pdcache_free(found);
}
}
/** /**
* PMap_Translate -- * PMap_Translate --
@ -239,12 +309,39 @@ PMap_MapPage(uint64_t phys, uint64_t virt, uint64_t pages, uint32_t pgshift, str
* @param [in] va Virtual address we wish to translate. * @param [in] va Virtual address we wish to translate.
*/ */
uintptr_t uintptr_t
PMap_Translate(UNUSED AS *space, UNUSED uintptr_t va) PMap_Translate(AS *space, uintptr_t va)
{ {
NOT_IMPLEMENTED(); struct vmpt * tbl;
uint32_t pgshift;
if (va >= MEM_USERSPACE_BASE && va < MEM_USERSPACE_TOP) {
tbl = space->user_tbl;
pgshift = PGSHIFT;
} else if (va >= MEM_DIRECTMAP_BASE && va < MEM_DIRECTMAP_TOP) {
tbl = space->dmap_tbl;
pgshift = LARGE_PGSHIFT;
} else if (va >= MEM_XMAP_BASE && va < MEM_XMAP_TOP) {
tbl = space->xmem_tbl;
pgshift = PGSHIFT;
} else {
kprintf("Trying to translate non-canonical vaddr 0x%lx.\n", va);
return 0; return 0;
} }
const uint64_t pfn = vm_get_pfn(va, pgshift);
const uint64_t hash = vm_vahash(pfn);
ASSERT(hash < VM_PTBUCKETS);
struct vmpte * const pte = &tbl->entries[hash];
const vaddr_t base = va & ~((1ull << pgshift) - 1);
struct vmpd * found;
if (!PMap_FindVmpd(pte, base, pgshift, &found, NULL)) {
kprintf("Trying to translate unmapped vaddr 0x%lx.\n", va);
return 0;
}
return found->paddr + (va - base);
}
/** /**
* PMap_Map -- * PMap_Map --
* *
@ -285,9 +382,14 @@ PMap_Map(AS *as, uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags)
* @retval false On failure * @retval false On failure
*/ */
bool bool
PMap_Unmap(UNUSED AS *as, UNUSED uint64_t va, UNUSED uint64_t pages) PMap_Unmap(AS *as, uint64_t va, uint64_t pages)
{ {
NOT_IMPLEMENTED(); // virt address must be within the usermap region
if (va < MEM_USERSPACE_BASE || va + pages * PGSIZE > MEM_USERSPACE_TOP) {
return false;
}
PMap_UnmapPage(va, pages, PGSHIFT, as->user_tbl);
return true; return true;
} }
@ -306,9 +408,25 @@ PMap_Unmap(UNUSED AS *as, UNUSED uint64_t va, UNUSED uint64_t pages)
* @retval false On failure * @retval false On failure
*/ */
bool bool
PMap_AllocMap(UNUSED AS *as, UNUSED uint64_t virt, UNUSED uint64_t len, UNUSED uint64_t flags) PMap_AllocMap(AS *as, uint64_t virt, uint64_t len, uint64_t flags)
{ {
NOT_IMPLEMENTED(); ASSERT((virt & PGMASK) == 0);
if (virt + len > MEM_USERSPACE_TOP || virt < MEM_USERSPACE_BASE) {
// not in userspace
return false;
}
const size_t pages = ROUNDUP(len, PGSIZE) / PGSIZE;
const uint64_t padattr = PMapProtToPdattr(flags, false);
for (unsigned int i = 0; i < pages; i++) {
const vaddr_t va = virt + PGSIZE * i;
const void *pg = PAlloc_AllocPage();
PMap_MapPage(DMVA2PA(pg), va, 1, PGSHIFT, as->user_tbl, padattr);
}
return true; return true;
} }
@ -387,12 +505,18 @@ PMap_SystemMap(uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags)
* We do not currently use this! * We do not currently use this!
*/ */
bool bool
PMap_SystemUnmap(UNUSED uint64_t virt, UNUSED uint64_t pages) PMap_SystemUnmap(uint64_t virt, uint64_t pages)
{ {
NOT_IMPLEMENTED(); // virt address must be within the xmem region
if (virt < MEM_XMAP_BASE || virt + pages * PGSIZE > MEM_XMAP_TOP) {
return false; return false;
} }
PMap_UnmapPage(virt, pages, PGSHIFT, systemAS.xmem_tbl);
return true;
}
void void
PMap_Dump(UNUSED AS *space) PMap_Dump(UNUSED AS *space)
{ {

View File

@ -7,13 +7,30 @@
.text .text
# switch(uint64_t *oldsp, uint64_t newsp) # switch(uint64_t *oldsp, uint64_t newsp)
# %rdi: oldsp # %x0: oldsp
# %rsi: newsp # %x1: newsp
FUNC_BEGIN(switchstack) FUNC_BEGIN(switchstack)
# Save callee saved registers of old thread # Save callee saved registers of old thread
stp fp, lr, [sp, #-16]!
stp x27, x28, [sp, #-16]!
stp x25, x26, [sp, #-16]!
stp x23, x24, [sp, #-16]!
stp x21, x22, [sp, #-16]!
stp x19, x20, [sp, #-16]!
stp x0, x0, [sp, #-16]!
# Switch stack from old to new thread # Switch stack from old to new thread
mov x9, sp
str x9, [x0]
mov sp, x1
# Restore callee saved registers of new thread # Restore callee saved registers of new thread
ldp x0, x0, [sp], #16
ldp x19, x20, [sp], #16
ldp x21, x22, [sp], #16
ldp x23, x24, [sp], #16
ldp x25, x26, [sp], #16
ldp x27, x28, [sp], #16
ldp fp, lr, [sp], #16
FUNC_END(switchstack) FUNC_END(switchstack)

View File

@ -13,19 +13,29 @@
#include <machine/cpuop.h> #include <machine/cpuop.h>
#include <machine/trap.h> #include <machine/trap.h>
#include <machine/pmap.h> #include <machine/pmap.h>
#include <machine/metal.h>
extern void ThreadKThreadEntry(TrapFrame *tf); extern void switchstack(uint64_t *oldsp, uint64_t sp);
extern void switchstack(uint64_t *oldrsp, uint64_t rsp); extern Spinlock schedLock;
void void
Thread_InitArch(Thread *thr) Thread_InitArch(Thread *thr)
{ {
thr->arch.useFP = true;
} }
void void
Thread_SetupKThread(Thread *thr, UNUSED void (*f)(void *), ThreadKThreadEntry(TrapFrame *tf) __NO_LOCK_ANALYSIS
UNUSED uintptr_t arg1, UNUSED uintptr_t arg2, UNUSED uintptr_t arg3) {
Spinlock_Unlock(&schedLock);
kprintf("tf in entry = 0x%p, elr = 0x%lx\n", tf, tf->elr);
Trap_Pop(tf);
}
#define SPSR_EL1H_DAIF0 (0b101)
void
Thread_SetupKThread(Thread *thr, kthread_entry f,
uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
{ {
// Initialize stack // Initialize stack
uint64_t stacktop = thr->kstack + PGSIZE; uint64_t stacktop = thr->kstack + PGSIZE;
@ -34,35 +44,54 @@ Thread_SetupKThread(Thread *thr, UNUSED void (*f)(void *),
tf = (TrapFrame *)(stacktop - sizeof(*tf)); tf = (TrapFrame *)(stacktop - sizeof(*tf));
sf = (ThreadArchStackFrame *)(stacktop - sizeof(*tf) - sizeof(*sf)); sf = (ThreadArchStackFrame *)(stacktop - sizeof(*tf) - sizeof(*sf));
thr->arch.sp = (uint64_t)sf;
memset(tf, 0, sizeof(*tf)); memset(tf, 0, sizeof(*tf));
memset(sf, 0, sizeof(*sf)); memset(sf, 0, sizeof(*sf));
// Setup thread exit function on stack // Setup thread exit function on stack
sf->lr = (uint64_t)&ThreadKThreadEntry;
sf->r0 = (uint64_t)tf;
sf->_r0 = (uint64_t)tf;
kprintf("tf before entry = 0x%p\n", tf);
// interrupt enable
tf->spsr = SPSR_EL1H_DAIF0; // el1h, enable interrupts
tf->elr = (regval_t)f;
tf->pcpl = MCPL_KERNEL;
tf->psp = stacktop;
tf->r0 = (regval_t)arg1;
tf->r1 = (regval_t)arg2;
tf->r2 = (regval_t)arg3;
} }
static void static void
ThreadEnterUserLevelCB(UNUSED void * unused) ThreadEnterUserLevelCB(vaddr_t entry, vaddr_t ustack, vaddr_t args)
{ {
TrapFrame tf; TrapFrame tf;
memset(&tf, 0, sizeof(tf)); memset(&tf, 0, sizeof(tf));
tf.elr = entry;
tf.r0 = args;
tf.psp = ustack + MEM_USERSPACE_STKLEN - PGSIZE;
tf.spsr = SPSR_EL1H_DAIF0;
tf.pcpl = MCPL_USER;
//Trap_Pop(&tf); Trap_Pop(&tf);
} }
void void
Thread_SetupUThread(Thread *thr, uintptr_t rip, uintptr_t arg) Thread_SetupUThread(Thread *thr, uintptr_t rip, uintptr_t arg)
{ {
Thread_SetupKThread(thr, ThreadEnterUserLevelCB, rip, Thread_SetupKThread(thr, (kthread_entry)ThreadEnterUserLevelCB, rip,
thr->ustack, arg); thr->ustack, arg);
} }
void void
Thread_SwitchArch(Thread *oldthr, Thread *newthr) Thread_SwitchArch(Thread *oldthr, Thread *newthr)
{ {
kprintf("switch stack! oldthr sp = 0x%lx, newthr sp = 0x%lx\n", oldthr->arch.sp, newthr->arch.sp);
// Jump to trapframe // Jump to trapframe
switchstack(&oldthr->arch.rsp, newthr->arch.rsp); switchstack(&oldthr->arch.sp, newthr->arch.sp);
} }

View File

@ -18,6 +18,8 @@
// hardcode to 2024/03/14 12:34:56 AM EST // hardcode to 2024/03/14 12:34:56 AM EST
#define KTIMER_EPOCH (1710390896ull) #define KTIMER_EPOCH (1710390896ull)
extern void Sched_Scheduler(void);
static struct IRQHandler _irqh; static struct IRQHandler _irqh;
static inline void static inline void
@ -34,8 +36,9 @@ PTimer_Tick(UNUSED void * arg)
gic_send_eoi(KTIMER_IRQ); gic_send_eoi(KTIMER_IRQ);
KTimer_Process(); KTimer_Process();
kprintf("Hardware timer tick, epoch = %lu, tsc = %lu, CVAL = %lu.\n", KTime_GetEpoch(), Time_GetTSC(), SYSREG_GET(CNTP_CVAL_EL0)); kprintf("Hardware timer tick, epoch = %lu, tsc = %lu, CVAL = %lu.\n", KTime_GetEpoch(), Time_GetTSC(), SYSREG_GET(CNTP_CVAL_EL0));
Sched_Scheduler();
} }
void void

View File

@ -102,6 +102,7 @@ extern void copystr_unsafe_fault(void);
void void
trap_entry(TrapFrame * tf) trap_entry(TrapFrame * tf)
{ {
// kprintf("Trap: psp = 0x%lx, pcpl = %lu\n", tf->psp, tf->pcpl);
if (tf->type == T_TYPE_EXC) { if (tf->type == T_TYPE_EXC) {
Panic("Unexpected exception: Type = 0x%lx, IntID = 0x%lx, ESR = 0x%lx, FAR = 0x%lx, ELR = 0x%lx, SPSR = 0x%lx.\n", tf->type, tf->intid, tf->esr, tf->far, tf->elr, tf->spsr); Panic("Unexpected exception: Type = 0x%lx, IntID = 0x%lx, ESR = 0x%lx, FAR = 0x%lx, ELR = 0x%lx, SPSR = 0x%lx.\n", tf->type, tf->intid, tf->esr, tf->far, tf->elr, tf->spsr);
} else { } else {

View File

@ -1,4 +1,8 @@
#include <machine/metalasm.h> #include <machine/metalasm.h>
#define MRT_KENTER_IDX (7)
#define MRT_KEXIT_IDX (8)
/* /*
* Trap Handlers * Trap Handlers
*/ */
@ -191,21 +195,36 @@
// daif bits are stored in PSTATE and are automatically re-enabled by eret // daif bits are stored in PSTATE and are automatically re-enabled by eret
.endm .endm
.global Trap_Pop
.text
Trap_Pop:
mov sp, x0
trapframe_restore_common
MENTER_GAS(MRT_KEXIT_IDX)
eret
.extern trap_entry .extern trap_entry
.text .text
interrupt_locore_entry: interrupt_locore_entry:
MENTER_GAS(MRT_KENTER_IDX)
trapframe_save_common 1 trapframe_save_common 1
mov x0, sp mov x0, sp
// pcpu for this core
mrs x18, tpidr_el1
bl trap_entry bl trap_entry
trapframe_restore_common trapframe_restore_common
MENTER_GAS(MRT_KEXIT_IDX)
eret eret
exception_locore_entry: exception_locore_entry:
MENTER_GAS(MRT_KENTER_IDX)
trapframe_save_common 0 trapframe_save_common 0
mov x0, sp mov x0, sp
// pcpu for this core
mrs x18, tpidr_el1
bl trap_entry bl trap_entry
trapframe_restore_common trapframe_restore_common
MENTER_GAS(MRT_KEXIT_IDX)
eret eret
.global _evt .global _evt

View File

@ -92,6 +92,8 @@ typedef struct Process {
HandleQueue handles[PROCESS_HANDLE_SLOTS]; HandleQueue handles[PROCESS_HANDLE_SLOTS];
} Process; } Process;
typedef void (*kthread_entry)(void *);
// General // General
void Thread_Init(); void Thread_Init();
void Thread_InitAP(); void Thread_InitAP();
@ -107,7 +109,7 @@ uint64_t Process_Wait(Process *proc, uint64_t pid);
// Thread functions // Thread functions
Thread *Thread_Create(Process *proc); Thread *Thread_Create(Process *proc);
Thread *Thread_KThreadCreate(void (*f)(void*), void *arg); Thread *Thread_KThreadCreate(kthread_entry f, void *arg);
Thread *Thread_UThreadCreate(Thread *oldThr, uint64_t rip, uint64_t arg); Thread *Thread_UThreadCreate(Thread *oldThr, uint64_t rip, uint64_t arg);
Thread *Thread_Lookup(Process *proc, uint64_t tid); Thread *Thread_Lookup(Process *proc, uint64_t tid);
void Thread_Retain(Thread *thr); void Thread_Retain(Thread *thr);
@ -127,7 +129,7 @@ void Thread_Dump(Thread *thr);
// Platform functions // Platform functions
void Thread_InitArch(Thread *thr); void Thread_InitArch(Thread *thr);
void Thread_SetupKThread(Thread *thr, void (*f)(void *), void Thread_SetupKThread(Thread *thr, kthread_entry f,
uintptr_t arg1, uintptr_t arg2, uintptr_t arg3); uintptr_t arg1, uintptr_t arg2, uintptr_t arg3);
void Thread_SetupUThread(Thread *thr, uint64_t rip, uint64_t arg); void Thread_SetupUThread(Thread *thr, uint64_t rip, uint64_t arg);
void Thread_SwitchArch(Thread *oldthr, Thread *newthr); void Thread_SwitchArch(Thread *oldthr, Thread *newthr);

View File

@ -238,7 +238,6 @@ Loader_LoadInit()
*/ */
PMap_LoadAS(thr->space); // Reload CR3 PMap_LoadAS(thr->space); // Reload CR3
#if defined(__x86_64__)
/* /*
* Pass in zero arguments with null pointers to init * Pass in zero arguments with null pointers to init
*/ */
@ -246,8 +245,9 @@ Loader_LoadInit()
ap[0] = 0; ap[0] = 0;
ap[1] = 0; ap[1] = 0;
ap[2] = 0xDEADBEEF; ap[2] = 0xDEADBEEF;
uintptr_t rsp = MEM_USERSPACE_STKTOP - PGSIZE;
#if defined(__x86_64__)
uintptr_t rsp = MEM_USERSPACE_STKTOP - PGSIZE;
Copy_Out(&ap[0], rsp, sizeof(uintptr_t)*3); Copy_Out(&ap[0], rsp, sizeof(uintptr_t)*3);
/* /*
@ -265,7 +265,19 @@ Loader_LoadInit()
tf.rdi = rsp; tf.rdi = rsp;
Trap_Pop(&tf); Trap_Pop(&tf);
#elif defined(__aarch64__) #elif defined(__aarch64__)
NOT_IMPLEMENTED(); /*
* Pass in zero arguments with null pointers to init
*/
const vaddr_t sp = MEM_USERSPACE_STKTOP - PGSIZE;
Copy_Out(&ap[0], sp, sizeof(uintptr_t)*3);
TrapFrame tf;
memset(&tf, 0, sizeof(tf));
tf.elr = thr->proc->entrypoint;
tf.r0 = sp;
//Trap_Pop(&tf);
#endif #endif
/* /*

View File

@ -214,6 +214,7 @@ Sched_Scheduler()
curProc[CPU()] = next; curProc[CPU()] = next;
next->schedState = SCHED_STATE_RUNNING; next->schedState = SCHED_STATE_RUNNING;
next->ctxSwitches++; next->ctxSwitches++;
kprintf("sched: cur = %lu next = %lu\n", prev->tid, next->tid);
if (prev->schedState == SCHED_STATE_RUNNING) { if (prev->schedState == SCHED_STATE_RUNNING) {
prev->schedState = SCHED_STATE_RUNNABLE; prev->schedState = SCHED_STATE_RUNNABLE;

View File

@ -141,7 +141,7 @@ Thread_Create(Process *proc)
} }
Thread * Thread *
Thread_KThreadCreate(void (*f)(void *), void *arg) Thread_KThreadCreate(kthread_entry f, void *arg)
{ {
Thread *thr = Thread_Create(kernelProcess); Thread *thr = Thread_Create(kernelProcess);
if (!thr) if (!thr)