[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:
Travis Geiselbrecht
2019-10-20 22:03:27 -07:00
parent d5ec654f9a
commit 23ebd514c1
11 changed files with 232 additions and 66 deletions

View File

@@ -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) {

View File

@@ -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
View 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

View File

@@ -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) {

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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 += \

View File

@@ -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:

View File

@@ -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);
}
}

View File

@@ -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;
}
}