[platform][vax] first working context switch
Timers aren't firing yet so the system locks up as soon as any timeout is involved. Enough to run the command line for a bit.
This commit is contained in:
@@ -6,26 +6,65 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <lk/trace.h>
|
||||
#include <lk/compiler.h>
|
||||
#include <lk/debug.h>
|
||||
#include <lk/trace.h>
|
||||
#include <stdint.h>
|
||||
#include <arch/ops.h>
|
||||
#include <arch/vax.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
extern uint8_t irq_stack[1024];
|
||||
// initial boot stack that start.S leaves us on
|
||||
extern uint8_t boot_stack[1024];
|
||||
|
||||
uint32_t SCB[scb_max_index] __ALIGNED(512);
|
||||
|
||||
struct vax_pcb pcb;
|
||||
|
||||
extern void vax_undefined_exception(void);
|
||||
extern void vax_exception_table(void);
|
||||
|
||||
static void dump_pr(const char *name, int reg) {
|
||||
printf("%s\t%#x\n", name, mfpr(reg));
|
||||
}
|
||||
#define dump_pr_byname(name) \
|
||||
dump_pr(#name, PR_##name)
|
||||
|
||||
static void dump_regs(void) {
|
||||
dump_pr_byname(SID);
|
||||
|
||||
dump_pr_byname(KSP); // Kernel Stack Pointer
|
||||
dump_pr_byname(ESP); // Executive Stack Pointer
|
||||
dump_pr_byname(SSP); // Supervisor Stack Pointer
|
||||
dump_pr_byname(USP); // User Stack Pointer
|
||||
dump_pr_byname(ISP); // Interrupt Stack Pointer
|
||||
|
||||
dump_pr_byname(P0BR); // P0 Base Register
|
||||
dump_pr_byname(P0LR); // P0 Length Register
|
||||
dump_pr_byname(P1BR); // P1 Base Register
|
||||
dump_pr_byname(P1LR); // P1 Length Register
|
||||
dump_pr_byname(SBR); // System Base Register
|
||||
dump_pr_byname(SLR); // System Limit Register
|
||||
|
||||
dump_pr_byname(PCBB); // Process Control Block Base
|
||||
dump_pr_byname(SCBB); // System Control Block Base
|
||||
dump_pr_byname(IPL); // Interrupt Priority Level
|
||||
|
||||
dump_pr_byname(MAPEN); // Memory Management Enable
|
||||
}
|
||||
|
||||
void arch_early_init(void) {
|
||||
// set the top level exception handler
|
||||
//riscv_csr_write(mtvec, (uintptr_t)&riscv_exception_entry);
|
||||
|
||||
// mask all exceptions, just in case
|
||||
//riscv_csr_clear(mstatus, RISCV_STATUS_MIE);
|
||||
//riscv_csr_clear(mie, RISCV_MIE_MTIE | RISCV_MIE_MSIE | RISCV_MIE_SEIE | RISCV_MIE_MEIE);
|
||||
// initialize the SCB
|
||||
for (int i = 0; i < scb_max_index; i++) {
|
||||
SCB[i] = ((uint32_t)&vax_exception_table + (i * 16)) | SCB_FLAG_KERNEL_STACK;
|
||||
|
||||
// enable cycle counter (disabled for now, unimplemented on sifive-e)
|
||||
//riscv_csr_set(mcounteren, 1);
|
||||
}
|
||||
mtpr((uint32_t)SCB, PR_SCBB);
|
||||
mtpr((uint32_t)&pcb, PR_PCBB);
|
||||
|
||||
dump_regs();
|
||||
}
|
||||
|
||||
void arch_init(void) {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/asm.h>
|
||||
|
||||
// void vax_context_switch(struct vax_pcb *newpcb);
|
||||
FUNCTION(vax_context_switch)
|
||||
.word 0 // nothing saved
|
||||
|
||||
// on the old stack save the current PSL and the PC to the exit of this function,
|
||||
// to be popped by the svpctx instruction
|
||||
movpsl -(%sp)
|
||||
moval .Lreturn, -(%sp)
|
||||
|
||||
// load the new pcb into r0
|
||||
movl 4(%ap),%r0
|
||||
|
||||
// save the full state of the cpu, switching to interrupt stack
|
||||
svpctx
|
||||
|
||||
mtpr %r0,$0x10 // load the new PCBB
|
||||
|
||||
// load new process context, leaves the new PSL and PC on the stack
|
||||
ldpctx
|
||||
|
||||
// return to the new thread
|
||||
rei
|
||||
|
||||
.Lreturn:
|
||||
// when an old thread is switch back to, arrange for the return address to be here
|
||||
ret
|
||||
|
||||
// trampoline when initially starting a thread to get from a fake saved process
|
||||
// context to the C world, which requires a calls instruction.
|
||||
.globl vax_initial_thread_func
|
||||
vax_initial_thread_func:
|
||||
calls $0,initial_thread_func
|
||||
halt
|
||||
|
||||
|
||||
33
arch/vax/exceptions.S
Normal file
33
arch/vax/exceptions.S
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/asm.h>
|
||||
|
||||
.text
|
||||
|
||||
// first level exception vectors must be 4 byte aligned
|
||||
.balign 4
|
||||
.globl vax_undefined_exception
|
||||
vax_undefined_exception:
|
||||
halt
|
||||
|
||||
.balign 16
|
||||
.globl vax_exception_table
|
||||
vax_exception_table:
|
||||
.set i, 0
|
||||
.rept (0x600/4)
|
||||
|
||||
pushl $i
|
||||
jbr interrupt_common
|
||||
.balign 16
|
||||
|
||||
.set i, i + 1
|
||||
.endr
|
||||
|
||||
FUNCTION(interrupt_common)
|
||||
halt
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
|
||||
static inline void arch_enable_ints(void) {
|
||||
// set the IPL to 0
|
||||
mtpr(PR_IPL, 0);
|
||||
mtpr(0, PR_IPL);
|
||||
}
|
||||
|
||||
static inline void arch_disable_ints(void) {
|
||||
// set the IPL to 31
|
||||
mtpr(PR_IPL, 31);
|
||||
mtpr(31, PR_IPL);
|
||||
}
|
||||
|
||||
static inline bool arch_ints_disabled(void) {
|
||||
|
||||
@@ -8,36 +8,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <arch/vax.h>
|
||||
|
||||
#if 0
|
||||
struct riscv32_context_switch_frame {
|
||||
uint32_t ra; // return address (x1)
|
||||
uint32_t sp; // stack pointer (x2)
|
||||
uint32_t tp; // thread pointer (x4)
|
||||
|
||||
uint32_t s0; // x8-x9
|
||||
uint32_t s1;
|
||||
|
||||
uint32_t s2; // x18-x27
|
||||
uint32_t s3;
|
||||
uint32_t s4;
|
||||
uint32_t s5;
|
||||
uint32_t s6;
|
||||
uint32_t s7;
|
||||
uint32_t s8;
|
||||
uint32_t s9;
|
||||
uint32_t s10;
|
||||
uint32_t s11;
|
||||
};
|
||||
|
||||
struct arch_thread {
|
||||
struct riscv32_context_switch_frame cs_frame;
|
||||
};
|
||||
|
||||
void riscv32_context_switch(struct riscv32_context_switch_frame *oldcs,
|
||||
struct riscv32_context_switch_frame *newcs);
|
||||
#endif
|
||||
void vax_context_switch(struct vax_pcb *newpcb);
|
||||
|
||||
struct arch_thread {
|
||||
// main process control block
|
||||
struct vax_pcb pcb;
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
typedef unsigned int spin_lock_t;
|
||||
|
||||
typedef unsigned long spin_lock_saved_state_t;
|
||||
typedef unsigned int spin_lock_saved_state_t;
|
||||
typedef unsigned int spin_lock_save_flags_t;
|
||||
|
||||
static inline void arch_spin_lock(spin_lock_t *lock) {
|
||||
@@ -46,13 +46,12 @@ static inline bool arch_spin_lock_held(spin_lock_t *lock) {
|
||||
|
||||
static inline void
|
||||
arch_interrupt_save(spin_lock_saved_state_t *statep, spin_lock_save_flags_t flags) {
|
||||
/* disable interrupts by clearing the MIE bit while atomically saving the old state */
|
||||
//*statep = riscv_csr_read_clear(mstatus, RISCV_STATUS_MIE) & RISCV_STATUS_MIE;
|
||||
*statep = mfpr(PR_IPL);
|
||||
mtpr(31, PR_IPL);
|
||||
}
|
||||
|
||||
static inline void
|
||||
arch_interrupt_restore(spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags) {
|
||||
/* drop the old MIE flag into the status register */
|
||||
//riscv_csr_set(mstatus, old_state);
|
||||
mtpr(old_state, PR_IPL);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,4 +7,36 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <arch/vax/mtpr.h>
|
||||
|
||||
// Indexes (in units of a long word) into the SCB for various vectors
|
||||
// that we care about. Many are not used yet, so dont fill all of them.
|
||||
enum vax_scb_index {
|
||||
foo = 0,
|
||||
|
||||
scb_adaptor_base_index = 0x100/4,
|
||||
|
||||
scb_device_base_index = 0x200/4,
|
||||
scb_max_index = 0x600/4
|
||||
};
|
||||
|
||||
#define SCB_FLAG_KERNEL_STACK (0b00)
|
||||
#define SCB_FLAG_INT_STACK (0b01)
|
||||
|
||||
struct vax_pcb {
|
||||
uint32_t ksp;
|
||||
uint32_t esp;
|
||||
uint32_t ssp;
|
||||
uint32_t usp;
|
||||
uint32_t r[14];
|
||||
uint32_t pc;
|
||||
uint32_t psl;
|
||||
uint32_t p0br;
|
||||
uint32_t p0lr;
|
||||
uint32_t p1br;
|
||||
uint32_t p1lr;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct vax_pcb) == 96);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ MODULE := $(LOCAL_DIR)
|
||||
MODULE_SRCS += $(LOCAL_DIR)/start.S
|
||||
MODULE_SRCS += $(LOCAL_DIR)/arch.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/asm.S
|
||||
MODULE_SRCS += $(LOCAL_DIR)/exceptions.S
|
||||
MODULE_SRCS += $(LOCAL_DIR)/thread.c
|
||||
|
||||
GLOBAL_DEFINES += \
|
||||
|
||||
@@ -37,13 +37,23 @@ _start:
|
||||
sobgtr %r2,1b
|
||||
|
||||
// branch to our new spot
|
||||
// TODO: use a REI to make sure the cpu dumps the pipeline
|
||||
movl $relocated, %r0
|
||||
jmp (%r0)
|
||||
// use a REI to make sure the cpu dumps the pipeline
|
||||
moval boot_stack_end,%sp // set the stack temporarily in the current memory spot
|
||||
movpsl -(%sp)
|
||||
movl $relocated, -(%sp)
|
||||
rei
|
||||
|
||||
relocated:
|
||||
// set the stack to the end of us
|
||||
moval irq_stack_end,%sp
|
||||
// switch to kernel stack
|
||||
moval boot_stack_end,%sp // set the interrupt stack in the relocated spot
|
||||
movpsl -(%sp) // push the psl on the stack
|
||||
bicl2 $(1<<26),(%sp) // clear bit 26 (IS)
|
||||
moval 1f,-(%sp) // push the address of the end of this routine
|
||||
rei // rei to it, loading the new PSL
|
||||
1:
|
||||
|
||||
// now we should be using the kernel stack pointer, so re-set it
|
||||
moval boot_stack_end,%sp
|
||||
|
||||
// branch into main and we're done
|
||||
calls $0, lk_main
|
||||
@@ -52,14 +62,14 @@ relocated:
|
||||
.section .data
|
||||
// declare bootargs here to make sure it goes in the data segment, since it's
|
||||
// saved before the bss is zeroed out.
|
||||
.align 4
|
||||
.balign 4
|
||||
.globl bootargs
|
||||
bootargs:
|
||||
.skip 13*4
|
||||
bootargs_end:
|
||||
|
||||
.section .bss
|
||||
.align 4
|
||||
irq_stack:
|
||||
.balign 4
|
||||
boot_stack:
|
||||
.skip 1024
|
||||
irq_stack_end:
|
||||
boot_stack_end:
|
||||
|
||||
@@ -14,12 +14,14 @@
|
||||
#include <kernel/thread.h>
|
||||
#include <arch/vax.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
#define LOCAL_TRACE 1
|
||||
|
||||
struct thread *_current_thread;
|
||||
|
||||
static void initial_thread_func(void) __NO_RETURN;
|
||||
static void initial_thread_func(void) {
|
||||
extern void vax_initial_thread_func(void);
|
||||
|
||||
void initial_thread_func(void) __NO_RETURN;
|
||||
void initial_thread_func(void) {
|
||||
DEBUG_ASSERT(arch_ints_disabled());
|
||||
|
||||
thread_t *ct = get_current_thread();
|
||||
@@ -29,7 +31,7 @@ static void initial_thread_func(void) {
|
||||
dump_thread(ct);
|
||||
#endif
|
||||
|
||||
/* release the thread lock that was implicitly held across the reschedule */
|
||||
// release the thread lock that was implicitly held across the reschedule
|
||||
spin_unlock(&thread_lock);
|
||||
arch_enable_ints();
|
||||
|
||||
@@ -43,26 +45,37 @@ static void initial_thread_func(void) {
|
||||
void arch_thread_initialize(thread_t *t) {
|
||||
LTRACEF("t %p (%s)\n", t, t->name);
|
||||
|
||||
/* zero out the thread context */
|
||||
// zero out the arch thread context, including the PCB
|
||||
memset(&t->arch, 0, sizeof(t->arch));
|
||||
|
||||
//t->arch.cs_frame.sp = (vaddr_t)t->stack + t->stack_size;
|
||||
//t->arch.cs_frame.ra = (vaddr_t)&initial_thread_func;
|
||||
// initialize the top of the stack
|
||||
uint32_t *stack_top = (uint32_t *)((uintptr_t)t->stack + t->stack_size);
|
||||
t->arch.pcb.ksp = (uint32_t)stack_top;
|
||||
|
||||
// set the initial address to the initial_thread_func
|
||||
t->arch.pcb.pc = (uint32_t)&vax_initial_thread_func;
|
||||
t->arch.pcb.psl = (31 << 16); // IPL 31
|
||||
t->arch.pcb.p0lr = (4 << 24); // ASTLVL 4
|
||||
}
|
||||
|
||||
void arch_context_switch(thread_t *oldthread, thread_t *newthread) {
|
||||
DEBUG_ASSERT(arch_ints_disabled());
|
||||
|
||||
LTRACEF("old %p (%s), new %p (%s)\n", oldthread, oldthread->name, newthread, newthread->name);
|
||||
LTRACEF("old %p (%s) pcb %p, new %p (%s) pcb %p\n",
|
||||
oldthread, oldthread->name, &oldthread->arch.pcb,
|
||||
newthread, newthread->name, &newthread->arch.pcb);
|
||||
|
||||
PANIC_UNIMPLEMENTED;
|
||||
//riscv32_context_switch(&oldthread->arch.cs_frame, &newthread->arch.cs_frame);
|
||||
if (LOCAL_TRACE) {
|
||||
hexdump(&newthread->arch.pcb, sizeof(struct vax_pcb));
|
||||
}
|
||||
|
||||
vax_context_switch(&newthread->arch.pcb);
|
||||
}
|
||||
|
||||
void arch_dump_thread(thread_t *t) {
|
||||
if (t->state != THREAD_RUNNING) {
|
||||
dprintf(INFO, "\tarch: ");
|
||||
//dprintf(INFO, "sp 0x%x\n", t->arch.cs_frame.sp);
|
||||
dprintf(INFO, "pcb %p, sp %#x\n", &t->arch.pcb, t->arch.pcb.ksp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,14 @@
|
||||
|
||||
#include "platform_p.h"
|
||||
|
||||
#define DEFAULT_PUTCHAR_ROUTINE putchar_mtfr
|
||||
#define DEFAULT_GETCHAR_ROUTINE getchar_mtfr
|
||||
|
||||
// Console io via rom routine
|
||||
unsigned int rom_putchar_addr;
|
||||
unsigned int rom_putchar_addr = 0x20040068;
|
||||
extern void rom_putchar(int c);
|
||||
//unsigned int rom_getchar_addr = 0x20040068;
|
||||
//extern void rom_getchar(int c);
|
||||
|
||||
// PR version
|
||||
void putchar_mtfr(int c) {
|
||||
@@ -25,8 +30,16 @@ void putchar_mtfr(int c) {
|
||||
mtpr((char)c, PR_TXDB);
|
||||
}
|
||||
|
||||
int getchar_mtfr(void) {
|
||||
if (mfpr(PR_RXCS) & (1<<7)) {
|
||||
return mfpr(PR_RXDB) & 0xff;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// select the above routine
|
||||
void (*putchar_func)(int c);
|
||||
void (*putchar_func)(int c) = &DEFAULT_PUTCHAR_ROUTINE;
|
||||
int (*getchar_func)(void) = &DEFAULT_GETCHAR_ROUTINE;
|
||||
|
||||
void platform_dputc(char c) {
|
||||
if (c == '\n')
|
||||
@@ -35,6 +48,11 @@ void platform_dputc(char c) {
|
||||
}
|
||||
|
||||
int platform_dgetc(char *c, bool wait) {
|
||||
int ret = getchar_func();
|
||||
if (ret > 0) {
|
||||
*c = ret & 0xff;
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -55,10 +73,12 @@ void platform_early_console_init(void) {
|
||||
case 0x14000004: // Microvax 3100/40
|
||||
rom_putchar_addr = 0x20040068;
|
||||
putchar_func = &rom_putchar;
|
||||
//getchar_func = &rom_getchar;
|
||||
break;
|
||||
default:
|
||||
// default is to use the pr routines
|
||||
putchar_func = &putchar_mtfr;
|
||||
getchar_func = &getchar_mtfr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user