riscv64/smp: Implement multi-processor support

* Working under qemu smp 1,2+
* Working on SiFive Unmatched
* x86_64 efi not broken by smp_boot_other_cpus change

Change-Id: I32ebc17913e46ed082be9ade8f56448bbf12f16e
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4705
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Alex von Gluck IV <[email protected]>
This commit is contained in:
X512
2021-12-12 15:35:24 +00:00
committed by Alex von Gluck IV
parent 0cdb323800
commit 8ca0f03d0c
31 changed files with 1350 additions and 506 deletions
+10 -10
View File
@@ -12,20 +12,20 @@
struct fdt_bus; struct fdt_bus;
struct fdt_device; struct fdt_device;
struct fdt_bus_module_info { typedef struct fdt_bus_module_info {
driver_module_info info; driver_module_info info;
device_node* (*node_by_phandle)(fdt_bus* bus, int phandle); device_node* (*node_by_phandle)(struct fdt_bus* bus, int phandle);
}; } fdt_bus_module_info;
struct fdt_device_module_info{ typedef struct fdt_device_module_info {
driver_module_info info; driver_module_info info;
device_node* (*get_bus)(fdt_device* dev); device_node* (*get_bus)(struct fdt_device* dev);
const char* (*get_name)(fdt_device* dev); const char* (*get_name)(struct fdt_device* dev);
const void* (*get_prop)(fdt_device* dev, const char* name, int* len); const void* (*get_prop)(struct fdt_device* dev, const char* name, int* len);
bool (*get_reg)(fdt_device* dev, uint32 ord, uint64* regs, uint64* len); bool (*get_reg)(struct fdt_device* dev, uint32 ord, uint64* regs, uint64* len);
bool (*get_interrupt)(fdt_device* dev, uint32 ord, bool (*get_interrupt)(struct fdt_device* dev, uint32 ord,
device_node** interruptController, uint64* interrupt); device_node** interruptController, uint64* interrupt);
}; } fdt_device_module_info;
#endif // _DRIVERS_BUS_FDT_H #endif // _DRIVERS_BUS_FDT_H
@@ -45,7 +45,7 @@ clear_ac()
typedef struct arch_cpu_info { typedef struct arch_cpu_info {
int null; uint64 hartId;
} arch_cpu_info; } arch_cpu_info;
@@ -10,6 +10,7 @@
struct kernel_args; struct kernel_args;
struct iframe;
struct arch_debug_registers { struct arch_debug_registers {
}; };
@@ -17,7 +18,7 @@ struct arch_debug_registers {
void WritePC(addr_t pc); void WritePC(addr_t pc);
void DoStackTrace(addr_t fp, addr_t pc); void DoStackTrace(addr_t fp, addr_t pc);
void WriteTrapInfo(); void WriteTrapInfo(iframe* frame);
status_t arch_debug_init_early(kernel_args *args); status_t arch_debug_init_early(kernel_args *args);
@@ -15,6 +15,8 @@
#define NUM_IO_VECTORS 256 #define NUM_IO_VECTORS 256
#ifdef __cplusplus
static inline void static inline void
arch_int_enable_interrupts_inline(void) arch_int_enable_interrupts_inline(void)
{ {
@@ -69,5 +71,7 @@ enum {
extern "C" status_t MSyscall(uint64 op, ...); extern "C" status_t MSyscall(uint64 op, ...);
#endif
#endif /* _KERNEL_ARCH_RISCV64_INT_H */ #endif /* _KERNEL_ARCH_RISCV64_INT_H */
@@ -38,7 +38,6 @@ typedef struct {
// MNative hooks, or SBI // MNative hooks, or SBI
uint32 machine_platform; uint32 machine_platform;
uint bootHart;
uint64 timerFrequency; // in Hz uint64 timerFrequency; // in Hz
// All following address are virtual // All following address are virtual
@@ -50,6 +49,9 @@ typedef struct {
addr_range clint; addr_range clint;
uart_info uart; uart_info uart;
uint32 hartIds[SMP_MAX_CPUS];
uint32 plicContexts[SMP_MAX_CPUS];
} _PACKED arch_kernel_args; } _PACKED arch_kernel_args;
#endif /* KERNEL_ARCH_RISCV64_KERNEL_ARGS_H */ #endif /* KERNEL_ARCH_RISCV64_KERNEL_ARGS_H */
@@ -14,6 +14,11 @@ namespace BKernel {
struct iframe { struct iframe {
uint64 status;
uint64 cause;
uint64 tval;
uint64 align1; // structure need to be 16 byte aligned
uint64 ra; uint64 ra;
uint64 t6; uint64 t6;
uint64 sp; uint64 sp;
@@ -48,6 +53,7 @@ struct iframe {
uint64 epc; uint64 epc;
}; };
struct arch_context { struct arch_context {
uint64 ra; // 0 uint64 ra; // 0
uint64 s[12]; // 12 uint64 s[12]; // 12
@@ -60,12 +66,15 @@ struct fpu_context {
uint64 fcsr; uint64 fcsr;
}; };
struct __attribute__((aligned(16))) arch_stack {
BKernel::Thread* thread;
};
struct arch_thread { struct arch_thread {
BKernel::Thread* thread;
arch_context context; arch_context context;
fpu_context fpuContext; fpu_context fpuContext;
iframe* userFrame; iframe* userFrame;
uint64 oldA0;
}; };
struct arch_team { struct arch_team {
@@ -84,13 +93,12 @@ struct arch_fork_arg {
extern "C" { extern "C" {
#endif #endif
int arch_setjmp(arch_context* ctx); void arch_context_switch(arch_context* from, arch_context* to);
void arch_longjmp(arch_context* ctx, int val);
void save_fpu(fpu_context* ctx); void save_fpu(fpu_context* ctx);
void restore_fpu(fpu_context* ctx); void restore_fpu(fpu_context* ctx);
void arch_thread_entry(); void arch_thread_entry();
void arch_enter_userspace(void *arg1, void *arg2, addr_t sp); void arch_load_user_iframe(arch_stack* stackHeader, iframe* frame)
void arch_longjmp_iframe(iframe* frame); __attribute__ ((noreturn));
#ifdef __cplusplus #ifdef __cplusplus
} }
@@ -9,79 +9,79 @@
# NOTE: this macro don't save SP, it should be saved manually # NOTE: this macro don't save SP, it should be saved manually
.macro PushTrapFrame .macro PushTrapFrame extSize
addi sp, sp, -256 addi sp, sp, -(\extSize + 256)
sd ra, 0*8(sp) sd ra, \extSize + 0*8(sp)
sd t6, 1*8(sp) sd t6, \extSize + 1*8(sp)
# sd sp, 2*8(sp) # sp # sd sp, \extSize + 2*8(sp) # sp
sd gp, 3*8(sp) sd gp, \extSize + 3*8(sp)
sd tp, 4*8(sp) sd tp, \extSize + 4*8(sp)
sd t0, 5*8(sp) sd t0, \extSize + 5*8(sp)
sd t1, 6*8(sp) sd t1, \extSize + 6*8(sp)
sd t2, 7*8(sp) sd t2, \extSize + 7*8(sp)
sd t5, 8*8(sp) sd t5, \extSize + 8*8(sp)
sd s1, 9*8(sp) sd s1, \extSize + 9*8(sp)
sd a0, 10*8(sp) sd a0, \extSize + 10*8(sp)
sd a1, 11*8(sp) sd a1, \extSize + 11*8(sp)
sd a2, 12*8(sp) sd a2, \extSize + 12*8(sp)
sd a3, 13*8(sp) sd a3, \extSize + 13*8(sp)
sd a4, 14*8(sp) sd a4, \extSize + 14*8(sp)
sd a5, 15*8(sp) sd a5, \extSize + 15*8(sp)
sd a6, 16*8(sp) sd a6, \extSize + 16*8(sp)
sd a7, 17*8(sp) sd a7, \extSize + 17*8(sp)
sd s2, 18*8(sp) sd s2, \extSize + 18*8(sp)
sd s3, 19*8(sp) sd s3, \extSize + 19*8(sp)
sd s4, 20*8(sp) sd s4, \extSize + 20*8(sp)
sd s5, 21*8(sp) sd s5, \extSize + 21*8(sp)
sd s6, 22*8(sp) sd s6, \extSize + 22*8(sp)
sd s7, 23*8(sp) sd s7, \extSize + 23*8(sp)
sd s8, 24*8(sp) sd s8, \extSize + 24*8(sp)
sd s9, 25*8(sp) sd s9, \extSize + 25*8(sp)
sd s10, 26*8(sp) sd s10, \extSize + 26*8(sp)
sd s11, 27*8(sp) sd s11, \extSize + 27*8(sp)
sd t3, 28*8(sp) sd t3, \extSize + 28*8(sp)
sd t4, 29*8(sp) sd t4, \extSize + 29*8(sp)
sd fp, 30*8(sp) sd fp, \extSize + 30*8(sp)
addi fp, sp, 256 addi fp, sp, \extSize + 256
.endm .endm
.macro PopTrapFrame .macro PopTrapFrame extSize
ld ra, 0*8(sp) ld ra, \extSize + 0*8(sp)
ld t6, 1*8(sp) ld t6, \extSize + 1*8(sp)
# ld sp, 2*8(sp) restore later # ld sp, \extSize + 2*8(sp) restore later
ld gp, 3*8(sp) ld gp, \extSize + 3*8(sp)
# ld tp, 4*8(sp) # ld tp, \extSize + 4*8(sp)
ld t0, 5*8(sp) ld t0, \extSize + 5*8(sp)
ld t1, 6*8(sp) ld t1, \extSize + 6*8(sp)
ld t2, 7*8(sp) ld t2, \extSize + 7*8(sp)
ld t5, 8*8(sp) ld t5, \extSize + 8*8(sp)
ld s1, 9*8(sp) ld s1, \extSize + 9*8(sp)
ld a0, 10*8(sp) ld a0, \extSize + 10*8(sp)
ld a1, 11*8(sp) ld a1, \extSize + 11*8(sp)
ld a2, 12*8(sp) ld a2, \extSize + 12*8(sp)
ld a3, 13*8(sp) ld a3, \extSize + 13*8(sp)
ld a4, 14*8(sp) ld a4, \extSize + 14*8(sp)
ld a5, 15*8(sp) ld a5, \extSize + 15*8(sp)
ld a6, 16*8(sp) ld a6, \extSize + 16*8(sp)
ld a7, 17*8(sp) ld a7, \extSize + 17*8(sp)
ld s2, 18*8(sp) ld s2, \extSize + 18*8(sp)
ld s3, 19*8(sp) ld s3, \extSize + 19*8(sp)
ld s4, 20*8(sp) ld s4, \extSize + 20*8(sp)
ld s5, 21*8(sp) ld s5, \extSize + 21*8(sp)
ld s6, 22*8(sp) ld s6, \extSize + 22*8(sp)
ld s7, 23*8(sp) ld s7, \extSize + 23*8(sp)
ld s8, 24*8(sp) ld s8, \extSize + 24*8(sp)
ld s9, 25*8(sp) ld s9, \extSize + 25*8(sp)
ld s10, 26*8(sp) ld s10, \extSize + 26*8(sp)
ld s11, 27*8(sp) ld s11, \extSize + 27*8(sp)
ld t3, 28*8(sp) ld t3, \extSize + 28*8(sp)
ld t4, 29*8(sp) ld t4, \extSize + 29*8(sp)
ld fp, 30*8(sp) ld fp, \extSize + 30*8(sp)
ld sp, 2*8(sp) ld sp, \extSize + 2*8(sp)
.endm .endm
@@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2019 Haiku, Inc. All rights reserved. * Copyright 2013-2021 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef KERNEL_BOOT_PLATFORM_EFI_ARCH_SMP_H #ifndef KERNEL_BOOT_PLATFORM_EFI_ARCH_SMP_H
@@ -13,9 +13,17 @@
// These platforms take inventory of cpu cores from fdt // These platforms take inventory of cpu cores from fdt
struct platform_cpu_info { struct platform_cpu_info {
uint32 id; uint32 id; // hart id on riscv
#if defined(__riscv)
uint32 phandle;
uint32 plicContext;
#endif
}; };
#if defined(__riscv)
extern uint32 gBootHart;
#endif
void arch_smp_register_cpu(platform_cpu_info** cpu); void arch_smp_register_cpu(platform_cpu_info** cpu);
#endif #endif
@@ -23,6 +31,7 @@ void arch_smp_register_cpu(platform_cpu_info** cpu);
int arch_smp_get_current_cpu(void); int arch_smp_get_current_cpu(void);
void arch_smp_init_other_cpus(void); void arch_smp_init_other_cpus(void);
#ifdef __riscv #ifdef __riscv
platform_cpu_info* arch_smp_find_cpu(uint32 phandle);
void arch_smp_boot_other_cpus(uint64 satp, uint64 kernel_entry); void arch_smp_boot_other_cpus(uint64 satp, uint64 kernel_entry);
#else #else
void arch_smp_boot_other_cpus(uint32 pml4, uint64 kernel_entry); void arch_smp_boot_other_cpus(uint32 pml4, uint64 kernel_entry);
+1 -1
View File
@@ -376,7 +376,7 @@ vm_page::IncrementWiredCount()
inline void inline void
vm_page::DecrementWiredCount() vm_page::DecrementWiredCount()
{ {
ASSERT(fWiredCount > 0); ASSERT_PRINT(fWiredCount > 0, "page: %#" B_PRIx64, physical_page_number * B_PAGE_SIZE);
if (--fWiredCount == 0) if (--fWiredCount == 0)
cache_ref->cache->DecrementWiredPagesCount(); cache_ref->cache->DecrementWiredPagesCount();
+9 -11
View File
@@ -230,10 +230,9 @@ vm_page_debug_access_start(vm_page* page)
thread_id previousThread = atomic_test_and_set(&page->accessing_thread, thread_id previousThread = atomic_test_and_set(&page->accessing_thread,
threadID, -1); threadID, -1);
if (previousThread != -1) { if (previousThread != -1) {
panic("Invalid concurrent access to page %p (start), currently " panic("Invalid concurrent access to page 0x%" B_PRIXPHYSADDR " (start), currently "
"accessed by: %" B_PRId32 "accessed by: %" B_PRId32 "@! page -m %p; sc %" B_PRId32 "; cache _cache",
"@! page -m %p; sc %" B_PRId32 "; cache _cache", page, page->physical_page_number * B_PAGE_SIZE, previousThread, page, previousThread);
previousThread, page, previousThread);
} }
} }
@@ -245,9 +244,9 @@ vm_page_debug_access_end(vm_page* page)
thread_id previousThread = atomic_test_and_set(&page->accessing_thread, -1, thread_id previousThread = atomic_test_and_set(&page->accessing_thread, -1,
threadID); threadID);
if (previousThread != threadID) { if (previousThread != threadID) {
panic("Invalid concurrent access to page %p (end) by current thread, " panic("Invalid concurrent access to page 0x%" B_PRIXPHYSADDR " (end) by "
"current accessor is: %" B_PRId32 "current thread, current accessor is: %" B_PRId32 "@! page -m %p; "
"@! page -m %p; sc %" B_PRId32 "; cache _cache", page, "sc %" B_PRId32 "; cache _cache", page->physical_page_number * B_PAGE_SIZE,
previousThread, page, previousThread); previousThread, page, previousThread);
} }
} }
@@ -258,10 +257,9 @@ vm_page_debug_access_check(vm_page* page)
{ {
thread_id thread = page->accessing_thread; thread_id thread = page->accessing_thread;
if (thread != thread_get_current_thread_id()) { if (thread != thread_get_current_thread_id()) {
panic("Invalid concurrent access to page %p (check), currently " panic("Invalid concurrent access to page 0x%" B_PRIXPHYSADDR " (check), currently "
"accessed by: %" B_PRId32 "accessed by: %" B_PRId32 "@! page -m %p; sc %" B_PRId32 "; cache _cache",
"@! page -m %p; sc %" B_PRId32 "; cache _cache", page, thread, page, page->physical_page_number * B_PAGE_SIZE, thread, page, thread);
thread);
} }
} }
@@ -11,6 +11,8 @@
#define B_ALWAYS_INLINE __attribute__((always_inline)) inline #define B_ALWAYS_INLINE __attribute__((always_inline)) inline
#ifdef __cplusplus
enum { enum {
modeU = 0, modeU = 0,
modeS = 1, modeS = 1,
@@ -327,6 +329,10 @@ static B_ALWAYS_INLINE void FlushTlbAllAsid(uint64 asid) {
static B_ALWAYS_INLINE void FlushTlbPageAsid(uint64 page, uint64 asid) { static B_ALWAYS_INLINE void FlushTlbPageAsid(uint64 page, uint64 asid) {
asm volatile("sfence.vma %0, %0" : : "r" (page), "r" (asid) : "memory");} asm volatile("sfence.vma %0, %0" : : "r" (page), "r" (asid) : "memory");}
// flush instruction cache
static B_ALWAYS_INLINE void FenceI() {
asm volatile("fence.i" : : : "memory");}
static B_ALWAYS_INLINE uint64 Sp() { static B_ALWAYS_INLINE uint64 Sp() {
uint64 x; asm volatile("mv %0, sp" : "=r" (x)); return x;} uint64 x; asm volatile("mv %0, sp" : "=r" (x)); return x;}
static B_ALWAYS_INLINE void SetSp(uint64 x) { static B_ALWAYS_INLINE void SetSp(uint64 x) {
@@ -352,6 +358,8 @@ static B_ALWAYS_INLINE void Wfi() {asm volatile("wfi");}
static B_ALWAYS_INLINE void Mret() {asm volatile("mret");} static B_ALWAYS_INLINE void Mret() {asm volatile("mret");}
static B_ALWAYS_INLINE void Sret() {asm volatile("sret");} static B_ALWAYS_INLINE void Sret() {asm volatile("sret");}
#endif // __cplusplus
#define SPINLOCK_PAUSE() do {} while (false) #define SPINLOCK_PAUSE() do {} while (false)
@@ -63,7 +63,8 @@ WritePteFlags(uint32 flags)
static void static void
DumpPageWrite(uint64_t virtAdr, uint64_t physAdr, size_t size, uint64 flags, uint64& firstVirt, uint64& firstPhys, uint64& firstFlags, uint64& len) DumpPageWrite(uint64_t virtAdr, uint64_t physAdr, size_t size, uint64 flags, uint64& firstVirt,
uint64& firstPhys, uint64& firstFlags, uint64& len)
{ {
if (virtAdr == firstVirt + len && physAdr == firstPhys + len && flags == firstFlags) { if (virtAdr == firstVirt + len && physAdr == firstPhys + len && flags == firstFlags) {
len += size; len += size;
@@ -71,7 +72,8 @@ DumpPageWrite(uint64_t virtAdr, uint64_t physAdr, size_t size, uint64 flags, uin
if (len != 0) { if (len != 0) {
dprintf(" 0x%08" B_PRIxADDR " - 0x%08" B_PRIxADDR, dprintf(" 0x%08" B_PRIxADDR " - 0x%08" B_PRIxADDR,
firstVirt, firstVirt + (len - 1)); firstVirt, firstVirt + (len - 1));
dprintf(": 0x%08" B_PRIxADDR " - 0x%08" B_PRIxADDR ", %#" B_PRIxADDR ", ", firstPhys, firstPhys + (len - 1), len); dprintf(": 0x%08" B_PRIxADDR " - 0x%08" B_PRIxADDR ", %#" B_PRIxADDR ", ",
firstPhys, firstPhys + (len - 1), len);
WritePteFlags(firstFlags); dprintf("\n"); WritePteFlags(firstFlags); dprintf("\n");
} }
firstVirt = virtAdr; firstVirt = virtAdr;
@@ -83,7 +85,8 @@ DumpPageWrite(uint64_t virtAdr, uint64_t physAdr, size_t size, uint64 flags, uin
static void static void
DumpPageTableInt(Pte* pte, uint64_t virtAdr, uint32_t level, uint64& firstVirt, uint64& firstPhys, uint64& firstFlags, uint64& len) DumpPageTableInt(Pte* pte, uint64_t virtAdr, uint32_t level, uint64& firstVirt, uint64& firstPhys,
uint64& firstFlags, uint64& len)
{ {
for (uint32 i = 0; i < pteCount; i++) { for (uint32 i = 0; i < pteCount; i++) {
if (((1 << pteValid) & pte[i].flags) != 0) { if (((1 << pteValid) & pte[i].flags) != 0) {
@@ -6,6 +6,7 @@
#include "arch_smp.h" #include "arch_smp.h"
#include <algorithm>
#include <string.h> #include <string.h>
#include <KernelExport.h> #include <KernelExport.h>
@@ -28,13 +29,14 @@
#endif #endif
extern "C" void arch_enter_kernel(uint64 satp, struct kernel_args *kernelArgs, typedef status_t (*KernelEntry) (kernel_args *bootKernelArgs, int currentCPU);
addr_t kernelEntry, addr_t kernelStackTop);
struct CpuEntryInfo { struct CpuEntryInfo {
uint64 satp; uint64 satp; // 0
uint64 kernelEntry; uint64 stackBase; // 8
uint64 stackSize; // 16
KernelEntry kernelEntry;// 24
}; };
@@ -43,11 +45,85 @@ uint32 sCpuCount = 0;
static void static void
CpuEntry(int hartId, CpuEntryInfo* info) arch_cpu_dump_hart_status(uint64 status)
{ {
arch_enter_kernel(info->satp, &gKernelArgs, info->kernelEntry, switch (status) {
gKernelArgs.cpu_kstack[hartId].start case SBI_HART_STATE_STARTED:
+ gKernelArgs.cpu_kstack[hartId].size); dprintf("started");
break;
case SBI_HART_STATE_STOPPED:
dprintf("stopped");
break;
case SBI_HART_STATE_START_PENDING:
dprintf("startPending");
break;
case SBI_HART_STATE_STOP_PENDING:
dprintf("stopPending");
break;
case SBI_HART_STATE_SUSPENDED:
dprintf("suspended");
break;
case SBI_HART_STATE_SUSPEND_PENDING:
dprintf("suspendPending");
break;
case SBI_HART_STATE_RESUME_PENDING:
dprintf("resumePending");
break;
default:
dprintf("?(%" B_PRIu64 ")", status);
}
}
static void
arch_cpu_dump_hart()
{
dprintf(" hart status:\n");
for (uint32 i = 0; i < sCpuCount; i++) {
dprintf(" hart %" B_PRIu32 ": ", i);
sbiret res = sbi_hart_get_status(sCpus[i].id);
if (res.error < 0)
dprintf("error: %" B_PRIu64 , res.error);
else {
arch_cpu_dump_hart_status(res.value);
}
dprintf("\n");
}
}
static void __attribute__((naked))
arch_cpu_entry(int hartId, CpuEntryInfo* info)
{
// enable MMU
asm("ld t0, 0(a1)"); // CpuEntryInfo::satp
asm("csrw satp, t0");
asm("sfence.vma");
// setup stack
asm("ld sp, 8(a1)"); // CpuEntryInfo::stackBase
asm("ld t0, 16(a1)"); // CpuEntryInfo::stackSize
asm("add sp, sp, t0");
asm("li fp, 0");
asm("tail arch_cpu_entry2");
}
extern "C" void
arch_cpu_entry2(int hartId, CpuEntryInfo* info)
{
dprintf("%s(%d)\n", __func__, hartId);
uint32 cpu = 0;
while (cpu < sCpuCount && !(sCpus[cpu].id == (uint32)hartId))
cpu++;
if (!(cpu < sCpuCount))
panic("CPU for hart id %d not found\n", hartId);
info->kernelEntry(&gKernelArgs, cpu);
for (;;) {}
} }
@@ -65,6 +141,17 @@ arch_smp_register_cpu(platform_cpu_info** cpu)
} }
platform_cpu_info*
arch_smp_find_cpu(uint32 phandle)
{
for (uint32 i = 0; i < sCpuCount; i++) {
if (sCpus[i].phandle == phandle)
return &sCpus[i];
}
return NULL;
}
int int
arch_smp_get_current_cpu(void) arch_smp_get_current_cpu(void)
{ {
@@ -75,9 +162,18 @@ arch_smp_get_current_cpu(void)
void void
arch_smp_init_other_cpus(void) arch_smp_init_other_cpus(void)
{ {
// TODO: SMP code disabled for now gKernelArgs.num_cpus = sCpuCount;
gKernelArgs.num_cpus = 1;
return; // make boot CPU first as expected by kernel
for (uint32 i = 1; i < sCpuCount; i++) {
if (sCpus[i].id == gBootHart)
std::swap(sCpus[i], sCpus[0]);
}
for (uint32 i = 0; i < sCpuCount; i++) {
gKernelArgs.arch_args.hartIds[i] = sCpus[i].id;
gKernelArgs.arch_args.plicContexts[i] = sCpus[i].plicContext;
}
if (get_safemode_boolean(B_SAFEMODE_DISABLE_SMP, false)) { if (get_safemode_boolean(B_SAFEMODE_DISABLE_SMP, false)) {
// SMP has been disabled! // SMP has been disabled!
@@ -85,8 +181,6 @@ arch_smp_init_other_cpus(void)
gKernelArgs.num_cpus = 1; gKernelArgs.num_cpus = 1;
} }
gKernelArgs.num_cpus = sCpuCount;
if (gKernelArgs.num_cpus < 2) if (gKernelArgs.num_cpus < 2)
return; return;
@@ -108,35 +202,34 @@ arch_smp_init_other_cpus(void)
void void
arch_smp_boot_other_cpus(uint64 satp, uint64 kernel_entry) arch_smp_boot_other_cpus(uint64 satp, uint64 kernel_entry)
{ {
// TODO: SMP code disabled for now dprintf("arch_smp_boot_other_cpus(%p, %p)\n", (void*)satp, (void*)kernel_entry);
return;
dprintf("arch_smp_boot_other_cpus()\n"); arch_cpu_dump_hart();
for (uint32 i = 0; i < sCpuCount; i++) { for (uint32 i = 0; i < sCpuCount; i++) {
// TODO: mhartid 0 may not exist, or it may not be a core if (sCpus[i].id != gBootHart) {
// you're interested in (FU540/FU740 hart 0 is mgmt core.)
if (0 != sCpus[i].id) {
sbiret res; sbiret res;
dprintf("starting CPU %" B_PRIu32 "\n", sCpus[i].id); dprintf(" starting CPU %" B_PRIu32 "\n", sCpus[i].id);
res = sbi_hart_get_status(sCpus[i].id); dprintf(" stack: %#" B_PRIx64 " - %#" B_PRIx64 "\n",
dprintf("[PRE] sbi_hart_get_status() -> (%ld, %ld)\n", gKernelArgs.cpu_kstack[i].start, gKernelArgs.cpu_kstack[i].start
res.error, res.value); + gKernelArgs.cpu_kstack[i].size - 1);
CpuEntryInfo info = {.satp = satp, .kernelEntry = kernel_entry}; CpuEntryInfo* info = new(std::nothrow) CpuEntryInfo{
res = sbi_hart_start(sCpus[i].id, (addr_t)&CpuEntry, (addr_t)&info); .satp = satp,
dprintf("sbi_hart_start() -> (%ld, %ld)\n", res.error, res.value); .stackBase = gKernelArgs.cpu_kstack[i].start,
.stackSize = gKernelArgs.cpu_kstack[i].size,
.kernelEntry = (KernelEntry)kernel_entry
};
res = sbi_hart_start(sCpus[i].id, (addr_t)&arch_cpu_entry, (addr_t)info);
for (;;) { for (;;) {
res = sbi_hart_get_status(sCpus[i].id); res = sbi_hart_get_status(sCpus[i].id);
if (res.error < 0 || res.value == SBI_HART_STATE_STARTED) if (res.error < 0 || res.value == SBI_HART_STATE_STARTED)
break; break;
} }
dprintf("[POST] sbi_hart_get_status() -> (%ld, %ld)\n",
res.error, res.value);
} }
} }
arch_cpu_dump_hart();
} }
+34 -5
View File
@@ -9,6 +9,7 @@
// TODO: split arch-depending code to per-arch source // TODO: split arch-depending code to per-arch source
#include <arch_cpu_defs.h>
#include <arch_smp.h> #include <arch_smp.h>
#include <arch/generic/debug_uart_8250.h> #include <arch/generic/debug_uart_8250.h>
#if defined(__riscv) #if defined(__riscv)
@@ -40,7 +41,8 @@ extern "C" {
static void* sDtbTable = NULL; static void* sDtbTable = NULL;
static uint32 sDtbSize = 0; static uint32 sDtbSize = 0;
static uint32 sBootHart = 0; // TODO: gBootHart is riscy, move
uint32 gBootHart = 0;
static uint64 sTimerFrequency = 10000000; static uint64 sTimerFrequency = 10000000;
static addr_range sPlic = {0}; static addr_range sPlic = {0};
@@ -422,7 +424,7 @@ HandleFdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells)
const char* name = fdt_get_name(fdt, node, NULL); const char* name = fdt_get_name(fdt, node, NULL);
if (strcmp(name, "chosen") == 0) { if (strcmp(name, "chosen") == 0) {
if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "boot-hartid", NULL)) if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "boot-hartid", NULL))
sBootHart = fdt32_to_cpu(*prop); gBootHart = fdt32_to_cpu(*prop);
} else if (strcmp(name, "cpus") == 0) { } else if (strcmp(name, "cpus") == 0) {
if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "timebase-frequency", NULL)) if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "timebase-frequency", NULL))
sTimerFrequency = fdt32_to_cpu(*prop); sTimerFrequency = fdt32_to_cpu(*prop);
@@ -433,6 +435,9 @@ HandleFdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells)
if (deviceType != NULL) { if (deviceType != NULL) {
if (strcmp(deviceType, "cpu") == 0) { if (strcmp(deviceType, "cpu") == 0) {
// TODO: improve incompatible CPU detection
if (!(fdt_getprop(fdt, node, "mmu-type", NULL) != NULL))
return;
platform_cpu_info* info; platform_cpu_info* info;
arch_smp_register_cpu(&info); arch_smp_register_cpu(&info);
if (info == NULL) if (info == NULL)
@@ -441,6 +446,14 @@ HandleFdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells)
"reg", NULL)); "reg", NULL));
dprintf("cpu\n"); dprintf("cpu\n");
dprintf(" id: %" B_PRIu32 "\n", info->id); dprintf(" id: %" B_PRIu32 "\n", info->id);
int subNode = fdt_subnode_offset(fdt, node, "interrupt-controller");
if (subNode < 0) {
dprintf(" [!] no interrupt controller\n");
} else {
info->phandle = fdt_get_phandle(fdt, subNode);
dprintf(" phandle: %" B_PRIu32 "\n", info->phandle);
}
} }
} }
@@ -459,6 +472,24 @@ HandleFdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells)
if (HasFdtString(compatible, compatibleLen, "riscv,plic0") if (HasFdtString(compatible, compatibleLen, "riscv,plic0")
|| HasFdtString(compatible, compatibleLen, "sifive,plic-1.0.0")) { || HasFdtString(compatible, compatibleLen, "sifive,plic-1.0.0")) {
GetReg(fdt, node, addressCells, sizeCells, 0, sPlic); GetReg(fdt, node, addressCells, sizeCells, 0, sPlic);
int propSize;
if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts-extended", &propSize)) {
dprintf("PLIC contexts\n");
uint32 contextId = 0;
for (uint32 *it = prop; (uint8_t*)it - (uint8_t*)prop < propSize; it += 2) {
uint32 phandle = fdt32_to_cpu(*it);
uint32 interrupt = fdt32_to_cpu(*(it + 1));
if (interrupt == sExternInt) {
platform_cpu_info* cpuInfo = arch_smp_find_cpu(phandle);
dprintf(" context %" B_PRIu32 ": %" B_PRIu32 "\n", contextId, phandle);
if (cpuInfo != NULL) {
cpuInfo->plicContext = contextId;
dprintf(" cpu id: %" B_PRIu32 "\n", cpuInfo->id);
}
}
contextId++;
}
}
return; return;
} }
@@ -556,7 +587,6 @@ dtb_set_kernel_args()
// pack into proper location if the architecture cares // pack into proper location if the architecture cares
if (sDtbTable != NULL) { if (sDtbTable != NULL) {
#if defined(__ARM__) || defined(__riscv) #if defined(__ARM__) || defined(__riscv)
// libfdt requires 8-byte alignment // libfdt requires 8-byte alignment
gKernelArgs.arch_args.fdt = (void*)(addr_t)kernel_args_malloc(sDtbSize, 8); gKernelArgs.arch_args.fdt = (void*)(addr_t)kernel_args_malloc(sDtbSize, 8);
@@ -568,8 +598,7 @@ dtb_set_kernel_args()
} }
#ifdef __riscv #ifdef __riscv
dprintf("bootHart: %" B_PRIu32 "\n", sBootHart); dprintf("bootHart: %" B_PRIu32 "\n", gBootHart);
gKernelArgs.arch_args.bootHart = sBootHart;
dprintf("timerFrequency: %" B_PRIu64 "\n", sTimerFrequency); dprintf("timerFrequency: %" B_PRIu64 "\n", sTimerFrequency);
gKernelArgs.arch_args.timerFrequency = sTimerFrequency; gKernelArgs.arch_args.timerFrequency = sTimerFrequency;
+2 -2
View File
@@ -48,12 +48,12 @@ smp_init_other_cpus(void)
void void
smp_boot_other_cpus(uint32 pml4, uint64 kernel_entry) smp_boot_other_cpus(addr_t pageTable, addr_t kernelEntry)
{ {
if (gKernelArgs.num_cpus < 2) if (gKernelArgs.num_cpus < 2)
return; return;
arch_smp_boot_other_cpus(pml4, kernel_entry); arch_smp_boot_other_cpus(pageTable, kernelEntry);
} }
+1 -1
View File
@@ -19,7 +19,7 @@ extern "C" {
extern void smp_init(void); extern void smp_init(void);
extern void smp_init_other_cpus(void); extern void smp_init_other_cpus(void);
extern void smp_boot_other_cpus(uint32 pml4, uint64 kernel_entry); extern void smp_boot_other_cpus(addr_t pageTable, addr_t kernelEntry);
extern int smp_get_current_cpu(void); extern int smp_get_current_cpu(void);
#ifdef __cplusplus #ifdef __cplusplus
+2
View File
@@ -35,3 +35,5 @@ KernelMergeObject kernel_arch_riscv64.o :
$(TARGET_KERNEL_PIC_CCFLAGS) -Wno-unused $(TARGET_KERNEL_PIC_CCFLAGS) -Wno-unused
: :
; ;
CreateAsmStructOffsetsHeader asm_offsets.h : asm_offsets.cpp : $(TARGET_KERNEL_ARCH) ;
@@ -15,13 +15,12 @@
#include <vm/VMAddressSpace.h> #include <vm/VMAddressSpace.h>
#include <vm/VMCache.h> #include <vm/VMCache.h>
#include <slab/Slab.h> #include <slab/Slab.h>
#include <platform/sbi/sbi_syscalls.h>
#include <util/AutoLock.h> #include <util/AutoLock.h>
#include <util/ThreadAutoLock.h> #include <util/ThreadAutoLock.h>
//#define DISABLE_MODIFIED_FLAGS 1
//#define DO_TRACE //#define DO_TRACE
#ifdef DO_TRACE #ifdef DO_TRACE
# define TRACE(x...) dprintf(x) # define TRACE(x...) dprintf(x)
@@ -32,6 +31,84 @@
#define NOT_IMPLEMENTED_PANIC() \ #define NOT_IMPLEMENTED_PANIC() \
panic("not implemented: %s\n", __PRETTY_FUNCTION__) panic("not implemented: %s\n", __PRETTY_FUNCTION__)
extern uint32 gPlatform;
static void
WriteVmPage(vm_page* page)
{
dprintf("0x%08" B_PRIxADDR " ",
(addr_t)(page->physical_page_number * B_PAGE_SIZE));
switch (page->State()) {
case PAGE_STATE_ACTIVE:
dprintf("A");
break;
case PAGE_STATE_INACTIVE:
dprintf("I");
break;
case PAGE_STATE_MODIFIED:
dprintf("M");
break;
case PAGE_STATE_CACHED:
dprintf("C");
break;
case PAGE_STATE_FREE:
dprintf("F");
break;
case PAGE_STATE_CLEAR:
dprintf("L");
break;
case PAGE_STATE_WIRED:
dprintf("W");
break;
case PAGE_STATE_UNUSED:
dprintf("-");
break;
}
dprintf(" ");
if (page->busy)
dprintf("B");
else
dprintf("-");
if (page->busy_writing)
dprintf("W");
else
dprintf("-");
if (page->accessed)
dprintf("A");
else
dprintf("-");
if (page->modified)
dprintf("M");
else
dprintf("-");
if (page->unused)
dprintf("U");
else
dprintf("-");
dprintf(" usage:%3u", page->usage_count);
dprintf(" wired:%5u", page->WiredCount());
bool first = true;
vm_page_mappings::Iterator iterator = page->mappings.GetIterator();
vm_page_mapping* mapping;
while ((mapping = iterator.Next()) != NULL) {
if (first) {
dprintf(": ");
first = false;
} else
dprintf(", ");
dprintf("%" B_PRId32 " (%s)", mapping->area->id, mapping->area->name);
mapping = mapping->page_link.next;
}
}
static void static void
FreePageTable(page_num_t ppn, bool isKernel, uint32 level = 2) FreePageTable(page_num_t ppn, bool isKernel, uint32 level = 2)
@@ -50,6 +127,7 @@ FreePageTable(page_num_t ppn, bool isKernel, uint32 level = 2)
} }
} }
vm_page* page = vm_lookup_page(ppn); vm_page* page = vm_lookup_page(ppn);
DEBUG_PAGE_ACCESS_START(page);
vm_page_set_state(page, PAGE_STATE_FREE); vm_page_set_state(page, PAGE_STATE_FREE);
} }
@@ -94,6 +172,7 @@ RISCV64VMTranslationMap::LookupPte(addr_t virtAdr, bool alloc,
fPageTable = page->physical_page_number * B_PAGE_SIZE; fPageTable = page->physical_page_number * B_PAGE_SIZE;
if (fPageTable == 0) if (fPageTable == 0)
return NULL; return NULL;
DEBUG_PAGE_ACCESS_END(page);
fPageTableSize++; fPageTableSize++;
if (!fIsKernel) { if (!fIsKernel) {
// Map kernel address space into user address space. Preallocated // Map kernel address space into user address space. Preallocated
@@ -121,6 +200,7 @@ RISCV64VMTranslationMap::LookupPte(addr_t virtAdr, bool alloc,
pte->ppn = page->physical_page_number; pte->ppn = page->physical_page_number;
if (pte->ppn == 0) if (pte->ppn == 0)
return NULL; return NULL;
DEBUG_PAGE_ACCESS_END(page);
fPageTableSize++; fPageTableSize++;
pte->flags |= (1 << pteValid); pte->flags |= (1 << pteValid);
} }
@@ -147,7 +227,9 @@ RISCV64VMTranslationMap::RISCV64VMTranslationMap(bool kernel,
phys_addr_t pageTable): phys_addr_t pageTable):
fIsKernel(kernel), fIsKernel(kernel),
fPageTable(pageTable), fPageTable(pageTable),
fPageTableSize(GetPageTableSize(pageTable / B_PAGE_SIZE, kernel)) fPageTableSize(GetPageTableSize(pageTable / B_PAGE_SIZE, kernel)),
fInvalidPagesCount(0),
fInvalidCode(false)
{ {
TRACE("+RISCV64VMTranslationMap(%p, %d, 0x%" B_PRIxADDR ")\n", this, TRACE("+RISCV64VMTranslationMap(%p, %d, 0x%" B_PRIxADDR ")\n", this,
kernel, pageTable); kernel, pageTable);
@@ -235,32 +317,33 @@ RISCV64VMTranslationMap::Map(addr_t virtualAddress, phys_addr_t physicalAddress,
if (pte == NULL) if (pte == NULL)
panic("can't allocate page table"); panic("can't allocate page table");
pte->ppn = physicalAddress / B_PAGE_SIZE; Pte newPte;
pte->flags = 0; newPte.ppn = physicalAddress / B_PAGE_SIZE;
newPte.flags = (1 << pteValid);
if ((attributes & B_USER_PROTECTION) != 0) { if ((attributes & B_USER_PROTECTION) != 0) {
pte->flags |= (1 << pteUser); newPte.flags |= (1 << pteUser);
if ((attributes & B_READ_AREA) != 0) if ((attributes & B_READ_AREA) != 0)
pte->flags |= (1 << pteRead); newPte.flags |= (1 << pteRead);
if ((attributes & B_WRITE_AREA) != 0) if ((attributes & B_WRITE_AREA) != 0)
pte->flags |= (1 << pteWrite); newPte.flags |= (1 << pteWrite);
if ((attributes & B_EXECUTE_AREA) != 0) if ((attributes & B_EXECUTE_AREA) != 0)
pte->flags |= (1 << pteExec); newPte.flags |= (1 << pteExec);
} else { } else {
if ((attributes & B_KERNEL_READ_AREA) != 0) if ((attributes & B_KERNEL_READ_AREA) != 0)
pte->flags |= (1 << pteRead); newPte.flags |= (1 << pteRead);
if ((attributes & B_KERNEL_WRITE_AREA) != 0) if ((attributes & B_KERNEL_WRITE_AREA) != 0)
pte->flags |= (1 << pteWrite); newPte.flags |= (1 << pteWrite);
if ((attributes & B_KERNEL_EXECUTE_AREA) != 0) if ((attributes & B_KERNEL_EXECUTE_AREA) != 0) {
pte->flags |= (1 << pteExec); newPte.flags |= (1 << pteExec);
fInvalidCode = true;
}
} }
pte->flags |= (1 << pteValid) *pte = newPte;
#ifdef DISABLE_MODIFIED_FLAGS
| (1 << pteAccessed) | (1 << pteDirty)
#endif
;
FlushTlbPage(virtualAddress); // Note: We don't need to invalidate the TLB for this address, as previously
// the entry was not present and the TLB doesn't cache those entries.
fMapCount++; fMapCount++;
@@ -280,9 +363,9 @@ RISCV64VMTranslationMap::Unmap(addr_t start, addr_t end)
Pte* pte = LookupPte(page, false, NULL); Pte* pte = LookupPte(page, false, NULL);
if (pte != NULL) { if (pte != NULL) {
fMapCount--; fMapCount--;
pte->flags = 0; Pte oldPte((uint64)atomic_get_and_set64((int64*)&pte->val, 0));
pte->ppn = 0; if ((oldPte.flags & (1 << pteAccessed)) != 0)
FlushTlbPage(page); InvalidatePage(page);
} }
} }
return B_OK; return B_OK;
@@ -327,13 +410,15 @@ RISCV64VMTranslationMap::UnmapPage(VMArea* area, addr_t address,
RecursiveLocker locker(fLock); RecursiveLocker locker(fLock);
Pte oldPte = *pte; Pte oldPte((uint64)atomic_get_and_set64((int64*)&pte->val, 0));
pte->flags = 0;
pte->ppn = 0;
fMapCount--; fMapCount--;
FlushTlbPage(address);
pinner.Unlock(); pinner.Unlock();
if ((oldPte.flags & (1 << pteAccessed)) != 0)
InvalidatePage(address);
Flush();
locker.Detach(); // PageUnmapped takes ownership locker.Detach(); // PageUnmapped takes ownership
PageUnmapped(area, oldPte.ppn, ((1 << pteAccessed) & oldPte.flags) != 0, PageUnmapped(area, oldPte.ppn, ((1 << pteAccessed) & oldPte.flags) != 0,
((1 << pteDirty) & oldPte.flags) != 0, updatePageQueue); ((1 << pteDirty) & oldPte.flags) != 0, updatePageQueue);
@@ -349,8 +434,98 @@ RISCV64VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size,
B_PRIxADDR ", 0x%" B_PRIxSIZE ", %d)\n", (addr_t)area, B_PRIxADDR ", 0x%" B_PRIxSIZE ", %d)\n", (addr_t)area,
area->name, base, size, updatePageQueue); area->name, base, size, updatePageQueue);
for (addr_t end = base + size; base < end; base += B_PAGE_SIZE) if (size == 0)
UnmapPage(area, base, updatePageQueue); return;
addr_t end = base + size - 1;
VMAreaMappings queue;
RecursiveLocker locker(fLock);
ThreadCPUPinner pinner(thread_get_current_thread());
for (addr_t start = base; start < end; start += B_PAGE_SIZE) {
Pte* pte = LookupPte(start, false, NULL);
if (pte == NULL)
continue;
Pte oldPte((uint64)atomic_get_and_set64((int64*)&pte->val, 0));
if ((oldPte.flags & (1 << pteValid)) == 0)
continue;
fMapCount--;
if ((oldPte.flags & (1 << pteAccessed)) != 0)
InvalidatePage(start);
if (area->cache_type != CACHE_TYPE_DEVICE) {
// get the page
vm_page* page = vm_lookup_page(oldPte.ppn);
ASSERT(page != NULL);
if (false) {
WriteVmPage(page); dprintf("\n");
}
DEBUG_PAGE_ACCESS_START(page);
// transfer the accessed/dirty flags to the page
if ((oldPte.flags & (1 << pteAccessed)) != 0)
page->accessed = true;
if ((oldPte.flags & (1 << pteDirty)) != 0)
page->modified = true;
// remove the mapping object/decrement the wired_count of the
// page
if (area->wiring == B_NO_LOCK) {
vm_page_mapping* mapping = NULL;
vm_page_mappings::Iterator iterator
= page->mappings.GetIterator();
while ((mapping = iterator.Next()) != NULL) {
if (mapping->area == area)
break;
}
ASSERT(mapping != NULL);
area->mappings.Remove(mapping);
page->mappings.Remove(mapping);
queue.Add(mapping);
} else
page->DecrementWiredCount();
if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1);
if (updatePageQueue) {
if (page->Cache()->temporary)
vm_page_set_state(page, PAGE_STATE_INACTIVE);
else if (page->modified)
vm_page_set_state(page, PAGE_STATE_MODIFIED);
else
vm_page_set_state(page, PAGE_STATE_CACHED);
}
}
DEBUG_PAGE_ACCESS_END(page);
}
// flush explicitly, since we directly use the lock
Flush();
}
// TODO: As in UnmapPage() we can lose page dirty flags here. ATM it's not
// really critical here, as in all cases this method is used, the unmapped
// area range is unmapped for good (resized/cut) and the pages will likely
// be freed.
locker.Unlock();
// free removed mappings
bool isKernelSpace = area->address_space == VMAddressSpace::Kernel();
uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY
| (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0);
while (vm_page_mapping* mapping = queue.RemoveHead())
object_cache_free(gPageMappingsObjectCache, mapping, freeFlags);
} }
@@ -404,9 +579,7 @@ RISCV64VMTranslationMap::UnmapArea(VMArea* area, bool deletingAddressSpace,
continue; continue;
} }
Pte oldPte = *pte; Pte oldPte((uint64)atomic_get_and_set64((int64*)&pte->val, 0));
pte->flags = 0;
pte->ppn = 0;
// transfer the accessed/dirty flags to the page and // transfer the accessed/dirty flags to the page and
// invalidate the mapping, if necessary // invalidate the mapping, if necessary
@@ -414,13 +587,15 @@ RISCV64VMTranslationMap::UnmapArea(VMArea* area, bool deletingAddressSpace,
page->accessed = true; page->accessed = true;
if (!deletingAddressSpace) if (!deletingAddressSpace)
FlushTlbPage(address); InvalidatePage(address);
} }
if (((1 << pteDirty) & oldPte.flags) != 0) if (((1 << pteDirty) & oldPte.flags) != 0)
page->modified = true; page->modified = true;
if (pageFullyUnmapped) { if (pageFullyUnmapped) {
DEBUG_PAGE_ACCESS_START(page);
if (cache->temporary) { if (cache->temporary) {
vm_page_set_state(page, vm_page_set_state(page,
PAGE_STATE_INACTIVE); PAGE_STATE_INACTIVE);
@@ -431,6 +606,8 @@ RISCV64VMTranslationMap::UnmapArea(VMArea* area, bool deletingAddressSpace,
vm_page_set_state(page, vm_page_set_state(page,
PAGE_STATE_CACHED); PAGE_STATE_CACHED);
} }
DEBUG_PAGE_ACCESS_END(page);
} }
} }
@@ -467,29 +644,28 @@ RISCV64VMTranslationMap::Query(addr_t virtualAddress,
if (pte == 0) if (pte == 0)
return B_OK; return B_OK;
*_physicalAddress = pte->ppn * B_PAGE_SIZE; Pte pteVal = *pte;
*_physicalAddress = pteVal.ppn * B_PAGE_SIZE;
if (((1 << pteValid) & pte->flags) != 0) if (((1 << pteValid) & pteVal.flags) != 0)
*_flags |= PAGE_PRESENT; *_flags |= PAGE_PRESENT;
#ifndef DISABLE_MODIFIED_FLAGS if (((1 << pteDirty) & pteVal.flags) != 0)
if (((1 << pteDirty) & pte->flags) != 0)
*_flags |= PAGE_MODIFIED; *_flags |= PAGE_MODIFIED;
if (((1 << pteAccessed) & pte->flags) != 0) if (((1 << pteAccessed) & pteVal.flags) != 0)
*_flags |= PAGE_ACCESSED; *_flags |= PAGE_ACCESSED;
#endif if (((1 << pteUser) & pteVal.flags) != 0) {
if (((1 << pteUser) & pte->flags) != 0) { if (((1 << pteRead) & pteVal.flags) != 0)
if (((1 << pteRead) & pte->flags) != 0)
*_flags |= B_READ_AREA; *_flags |= B_READ_AREA;
if (((1 << pteWrite) & pte->flags) != 0) if (((1 << pteWrite) & pteVal.flags) != 0)
*_flags |= B_WRITE_AREA; *_flags |= B_WRITE_AREA;
if (((1 << pteExec) & pte->flags) != 0) if (((1 << pteExec) & pteVal.flags) != 0)
*_flags |= B_EXECUTE_AREA; *_flags |= B_EXECUTE_AREA;
} else { } else {
if (((1 << pteRead) & pte->flags) != 0) if (((1 << pteRead) & pteVal.flags) != 0)
*_flags |= B_KERNEL_READ_AREA; *_flags |= B_KERNEL_READ_AREA;
if (((1 << pteWrite) & pte->flags) != 0) if (((1 << pteWrite) & pteVal.flags) != 0)
*_flags |= B_KERNEL_WRITE_AREA; *_flags |= B_KERNEL_WRITE_AREA;
if (((1 << pteExec) & pte->flags) != 0) if (((1 << pteExec) & pteVal.flags) != 0)
*_flags |= B_KERNEL_EXECUTE_AREA; *_flags |= B_KERNEL_EXECUTE_AREA;
} }
@@ -522,7 +698,8 @@ status_t RISCV64VMTranslationMap::Protect(addr_t base, addr_t top,
continue; continue;
} }
Pte newPte = *pte; Pte oldPte = *pte;
Pte newPte = oldPte;
newPte.flags &= (1 << pteValid) newPte.flags &= (1 << pteValid)
| (1 << pteAccessed) | (1 << pteDirty); | (1 << pteAccessed) | (1 << pteDirty);
@@ -532,19 +709,24 @@ status_t RISCV64VMTranslationMap::Protect(addr_t base, addr_t top,
newPte.flags |= (1 << pteRead); newPte.flags |= (1 << pteRead);
if ((attributes & B_WRITE_AREA) != 0) if ((attributes & B_WRITE_AREA) != 0)
newPte.flags |= (1 << pteWrite); newPte.flags |= (1 << pteWrite);
if ((attributes & B_EXECUTE_AREA) != 0) if ((attributes & B_EXECUTE_AREA) != 0) {
newPte.flags |= (1 << pteExec); newPte.flags |= (1 << pteExec);
fInvalidCode = true;
}
} else { } else {
if ((attributes & B_KERNEL_READ_AREA) != 0) if ((attributes & B_KERNEL_READ_AREA) != 0)
newPte.flags |= (1 << pteRead); newPte.flags |= (1 << pteRead);
if ((attributes & B_KERNEL_WRITE_AREA) != 0) if ((attributes & B_KERNEL_WRITE_AREA) != 0)
newPte.flags |= (1 << pteWrite); newPte.flags |= (1 << pteWrite);
if ((attributes & B_KERNEL_EXECUTE_AREA) != 0) if ((attributes & B_KERNEL_EXECUTE_AREA) != 0) {
newPte.flags |= (1 << pteExec); newPte.flags |= (1 << pteExec);
fInvalidCode = true;
}
} }
*pte = newPte; *pte = newPte;
FlushTlbPage(page); if ((oldPte.flags & (1 << pteAccessed)) != 0)
InvalidatePage(page);
} }
return B_OK; return B_OK;
@@ -583,9 +765,7 @@ RISCV64VMTranslationMap::SetFlags(addr_t address, uint32 flags)
Pte* pte = LookupPte(address, false, NULL); Pte* pte = LookupPte(address, false, NULL);
if (pte == NULL || ((1 << pteValid) & pte->flags) == 0) if (pte == NULL || ((1 << pteValid) & pte->flags) == 0)
return B_OK; return B_OK;
#ifndef DISABLE_MODIFIED_FLAGS
pte->flags |= ConvertAccessedFlags(flags); pte->flags |= ConvertAccessedFlags(flags);
#endif
FlushTlbPage(address); FlushTlbPage(address);
return B_OK; return B_OK;
} }
@@ -600,11 +780,8 @@ RISCV64VMTranslationMap::ClearFlags(addr_t address, uint32 flags)
if (pte == NULL || ((1 << pteValid) & pte->flags) == 0) if (pte == NULL || ((1 << pteValid) & pte->flags) == 0)
return B_OK; return B_OK;
#ifndef DISABLE_MODIFIED_FLAGS
pte->flags &= ~ConvertAccessedFlags(flags); pte->flags &= ~ConvertAccessedFlags(flags);
#endif InvalidatePage(address);
FlushTlbPage(address);
return B_OK; return B_OK;
} }
@@ -624,25 +801,32 @@ RISCV64VMTranslationMap::ClearAccessedAndModified(VMArea* area, addr_t address,
if (pte == NULL || ((1 << pteValid) & pte->flags) == 0) if (pte == NULL || ((1 << pteValid) & pte->flags) == 0)
return false; return false;
Pte oldPte = *pte; Pte oldPte;
#ifndef DISABLE_MODIFIED_FLAGS
if (unmapIfUnaccessed) { if (unmapIfUnaccessed) {
if (((1 << pteAccessed) & pte->flags) != 0) { for (;;) {
pte->flags &= ~((1 << pteAccessed) | (1 << pteDirty)); oldPte = *pte;
} else { if (((1 << pteValid) & oldPte.flags) == 0)
pte->flags = 0; return false;
pte->ppn = 0;
if (((1 << pteAccessed) & oldPte.flags) != 0) {
oldPte.val = atomic_and64((int64*)&pte->val,
~((1 << pteAccessed) | (1 << pteDirty)));
break;
}
if (atomic_test_and_set64((int64*)&pte->val, 0, oldPte.val)
== (int64)oldPte.val) {
break;
}
} }
} else { } else {
pte->flags &= ~((1 << pteAccessed) | (1 << pteDirty)); oldPte.val = atomic_and64((int64*)&pte->val,
~((1 << pteAccessed) | (1 << pteDirty)));
} }
#endif
pinner.Unlock(); pinner.Unlock();
_modified = ((1 << pteDirty) & oldPte.flags) != 0; _modified = ((1 << pteDirty) & oldPte.flags) != 0;
if (((1 << pteAccessed) & oldPte.flags) != 0) { if (((1 << pteAccessed) & oldPte.flags) != 0) {
FlushTlbPage(address); InvalidatePage(address);
Flush(); Flush();
return true; return true;
} }
@@ -661,7 +845,104 @@ RISCV64VMTranslationMap::ClearAccessedAndModified(VMArea* area, addr_t address,
void void
RISCV64VMTranslationMap::Flush() RISCV64VMTranslationMap::Flush()
{ {
//NOT_IMPLEMENTED_PANIC(); // copy of X86VMTranslationMap::Flush
// TODO: move to common VMTranslationMap class
if (fInvalidPagesCount <= 0)
return;
/*
dprintf("+Flush(%p)\n", this);
struct ScopeExit {
~ScopeExit()
{
dprintf("-Flush(%p)\n", this);
}
} scopeExit;
*/
ThreadCPUPinner pinner(thread_get_current_thread());
if (fInvalidPagesCount > PAGE_INVALIDATE_CACHE_SIZE) {
// invalidate all pages
TRACE("flush_tmap: %d pages to invalidate, invalidate all\n",
fInvalidPagesCount);
if (fIsKernel) {
arch_cpu_global_TLB_invalidate();
// dprintf("+smp_send_broadcast_ici\n");
smp_send_broadcast_ici(SMP_MSG_GLOBAL_INVALIDATE_PAGES, 0, 0, 0,
NULL, SMP_MSG_FLAG_SYNC);
// dprintf("-smp_send_broadcast_ici\n");
} else {
cpu_status state = disable_interrupts();
arch_cpu_user_TLB_invalidate();
restore_interrupts(state);
int cpu = smp_get_current_cpu();
CPUSet cpuMask = fActiveOnCpus;
cpuMask.ClearBit(cpu);
if (!cpuMask.IsEmpty()) {
// dprintf("+smp_send_multicast_ici\n");
smp_send_multicast_ici(cpuMask, SMP_MSG_USER_INVALIDATE_PAGES,
0, 0, 0, NULL, SMP_MSG_FLAG_SYNC);
// dprintf("-smp_send_multicast_ici\n");
}
}
} else {
TRACE("flush_tmap: %d pages to invalidate, invalidate list\n",
fInvalidPagesCount);
arch_cpu_invalidate_TLB_list(fInvalidPages, fInvalidPagesCount);
if (fIsKernel) {
// dprintf("+smp_send_broadcast_ici\n");
smp_send_broadcast_ici(SMP_MSG_INVALIDATE_PAGE_LIST,
(addr_t)fInvalidPages, fInvalidPagesCount, 0, NULL,
SMP_MSG_FLAG_SYNC);
// dprintf("-smp_send_broadcast_ici\n");
} else {
int cpu = smp_get_current_cpu();
CPUSet cpuMask = fActiveOnCpus;
cpuMask.ClearBit(cpu);
if (!cpuMask.IsEmpty()) {
// dprintf("+smp_send_multicast_ici\n");
smp_send_multicast_ici(cpuMask, SMP_MSG_INVALIDATE_PAGE_LIST,
(addr_t)fInvalidPages, fInvalidPagesCount, 0, NULL,
SMP_MSG_FLAG_SYNC);
// dprintf("-smp_send_multicast_ici\n");
}
}
}
fInvalidPagesCount = 0;
if (fInvalidCode) {
FenceI();
int cpu = smp_get_current_cpu();
CPUSet cpuMask = fActiveOnCpus;
cpuMask.ClearBit(cpu);
if (!cpuMask.IsEmpty()) {
switch (gPlatform) {
case kPlatformSbi: {
uint64 hartMask = 0;
int32 cpuCount = smp_get_num_cpus();
for (int32 i = 0; i < cpuCount; i++) {
if (cpuMask.GetBit(i))
hartMask |= (uint64)1 << gCPU[i].arch.hartId;
}
// TODO: handle hart ID >= 64
memory_full_barrier();
sbi_remote_fence_i(hartMask, 0);
break;
}
}
}
fInvalidCode = false;
}
} }
@@ -883,11 +1164,7 @@ RISCV64VMPhysicalPageMapper::MemsetPhysical(phys_addr_t address, int value,
{ {
TRACE("RISCV64VMPhysicalPageMapper::MemsetPhysical(0x%" B_PRIxADDR TRACE("RISCV64VMPhysicalPageMapper::MemsetPhysical(0x%" B_PRIxADDR
", 0x%x, 0x%" B_PRIxADDR ")\n", address, value, length); ", 0x%x, 0x%" B_PRIxADDR ")\n", address, value, length);
set_ac(); return user_memset(VirtFromPhys(address), value, length);
memset(VirtFromPhys(address), value, length);
clear_ac();
return B_OK;
} }
@@ -898,12 +1175,7 @@ RISCV64VMPhysicalPageMapper::MemcpyFromPhysical(void* to, phys_addr_t from,
TRACE("RISCV64VMPhysicalPageMapper::MemcpyFromPhysical(0x%" B_PRIxADDR TRACE("RISCV64VMPhysicalPageMapper::MemcpyFromPhysical(0x%" B_PRIxADDR
", 0x%" B_PRIxADDR ", %" B_PRIuSIZE ")\n", (addr_t)to, ", 0x%" B_PRIxADDR ", %" B_PRIuSIZE ")\n", (addr_t)to,
from, length); from, length);
return user_memcpy(to, VirtFromPhys(from), length);
set_ac();
memcpy(to, VirtFromPhys(from), length);
clear_ac();
return B_OK;
} }
@@ -914,12 +1186,7 @@ RISCV64VMPhysicalPageMapper::MemcpyToPhysical(phys_addr_t to, const void* from,
TRACE("RISCV64VMPhysicalPageMapper::MemcpyToPhysical(0x%" B_PRIxADDR TRACE("RISCV64VMPhysicalPageMapper::MemcpyToPhysical(0x%" B_PRIxADDR
", 0x%" B_PRIxADDR ", %" B_PRIuSIZE ")\n", to, (addr_t)from, ", 0x%" B_PRIxADDR ", %" B_PRIuSIZE ")\n", to, (addr_t)from,
length); length);
return user_memcpy(VirtFromPhys(to), from, length);
set_ac();
memcpy(VirtFromPhys(to), from, length);
clear_ac();
return B_OK;
} }
@@ -929,8 +1196,5 @@ RISCV64VMPhysicalPageMapper::MemcpyPhysicalPage(phys_addr_t to,
{ {
TRACE("RISCV64VMPhysicalPageMapper::MemcpyPhysicalPage(0x%" B_PRIxADDR TRACE("RISCV64VMPhysicalPageMapper::MemcpyPhysicalPage(0x%" B_PRIxADDR
", 0x%" B_PRIxADDR ")\n", to, from); ", 0x%" B_PRIxADDR ")\n", to, from);
user_memcpy(VirtFromPhys(to), VirtFromPhys(from), B_PAGE_SIZE);
set_ac();
memcpy(VirtFromPhys(to), VirtFromPhys(from), B_PAGE_SIZE);
clear_ac();
} }
@@ -11,6 +11,12 @@
#include <vm/VMTranslationMap.h> #include <vm/VMTranslationMap.h>
#include <arch_cpu_defs.h> #include <arch_cpu_defs.h>
#include <kernel/smp.h>
enum {
PAGE_INVALIDATE_CACHE_SIZE = 64
};
struct RISCV64VMTranslationMap: public VMTranslationMap { struct RISCV64VMTranslationMap: public VMTranslationMap {
@@ -87,6 +93,9 @@ struct RISCV64VMTranslationMap: public VMTranslationMap {
ssize_t StrlcpyToMap(addr_t to, const char *from, ssize_t StrlcpyToMap(addr_t to, const char *from,
size_t size); size_t size);
inline CPUSet& ActiveOnCpus();
inline void InvalidatePage(addr_t address);
private: private:
Pte* LookupPte(addr_t virtAdr, bool alloc, Pte* LookupPte(addr_t virtAdr, bool alloc,
vm_page_reservation* reservation); vm_page_reservation* reservation);
@@ -94,16 +103,23 @@ private:
bool fIsKernel; bool fIsKernel;
phys_addr_t fPageTable; phys_addr_t fPageTable;
uint64_t fPageTableSize; // in page units uint64 fPageTableSize; // in page units
CPUSet fActiveOnCpus;
int fInvalidPagesCount;
addr_t fInvalidPages[PAGE_INVALIDATE_CACHE_SIZE];
bool fInvalidCode;
}; };
inline phys_addr_t RISCV64VMTranslationMap::PageTable() inline phys_addr_t
RISCV64VMTranslationMap::PageTable()
{ {
return fPageTable; return fPageTable;
} }
inline uint64 RISCV64VMTranslationMap::Satp()
inline uint64
RISCV64VMTranslationMap::Satp()
{ {
SatpReg satp; SatpReg satp;
satp.ppn = fPageTable / B_PAGE_SIZE; satp.ppn = fPageTable / B_PAGE_SIZE;
@@ -113,6 +129,23 @@ inline uint64 RISCV64VMTranslationMap::Satp()
} }
CPUSet&
RISCV64VMTranslationMap::ActiveOnCpus()
{
return fActiveOnCpus;
}
void
RISCV64VMTranslationMap::InvalidatePage(addr_t address)
{
if (fInvalidPagesCount < PAGE_INVALIDATE_CACHE_SIZE)
fInvalidPages[fInvalidPagesCount] = address;
fInvalidPagesCount++;
}
struct RISCV64VMPhysicalPageMapper: public VMPhysicalPageMapper { struct RISCV64VMPhysicalPageMapper: public VMPhysicalPageMapper {
RISCV64VMPhysicalPageMapper(); RISCV64VMPhysicalPageMapper();
virtual ~RISCV64VMPhysicalPageMapper(); virtual ~RISCV64VMPhysicalPageMapper();
+25 -36
View File
@@ -17,7 +17,8 @@ FUNCTION(MSyscall):
FUNCTION_END(MSyscall) FUNCTION_END(MSyscall)
FUNCTION(arch_setjmp): FUNCTION(arch_context_switch):
# save `from` context
sd ra, 0*8(a0) sd ra, 0*8(a0)
sd s0, 1*8(a0) sd s0, 1*8(a0)
sd s1, 2*8(a0) sd s1, 2*8(a0)
@@ -35,34 +36,27 @@ FUNCTION(arch_setjmp):
csrr t0, satp csrr t0, satp
sd t0, 14*8(a0) sd t0, 14*8(a0)
li a0, 0 # load `to` context
ret ld ra, 0*8(a1)
FUNCTION_END(arch_setjmp) ld s0, 1*8(a1)
ld s1, 2*8(a1)
ld s2, 3*8(a1)
FUNCTION(arch_longjmp): ld s3, 4*8(a1)
ld ra, 0*8(a0) ld s4, 5*8(a1)
ld s0, 1*8(a0) ld s5, 6*8(a1)
ld s1, 2*8(a0) ld s6, 7*8(a1)
ld s2, 3*8(a0) ld s7, 8*8(a1)
ld s3, 4*8(a0) ld s8, 9*8(a1)
ld s4, 5*8(a0) ld s9, 10*8(a1)
ld s5, 6*8(a0) ld s10, 11*8(a1)
ld s6, 7*8(a0) ld s11, 12*8(a1)
ld s7, 8*8(a0) ld sp, 13*8(a1)
ld s8, 9*8(a0) ld t0, 14*8(a1)
ld s9, 10*8(a0)
ld s10, 11*8(a0)
ld s11, 12*8(a0)
ld sp, 13*8(a0)
ld t0, 14*8(a0)
csrw satp, t0 csrw satp, t0
sfence.vma sfence.vma
seqz a0, a1
add a0, a0, a1 # a0 = (a1 == 0) ? 1 : a1
ret ret
FUNCTION_END(arch_longjmp) FUNCTION_END(arch_context_switch)
FUNCTION(save_fpu): FUNCTION(save_fpu):
@@ -147,20 +141,15 @@ FUNCTION_END(restore_fpu)
FUNCTION(arch_thread_entry): FUNCTION(arch_thread_entry):
mv a0, s2 mv a0, s2
jalr s1 jr s1
FUNCTION_END(arch_thread_entry) FUNCTION_END(arch_thread_entry)
FUNCTION(arch_enter_userspace): FUNCTION(arch_load_user_iframe):
mv sp, a2 mv fp, a0
sret mv sp, a1
FUNCTION_END(arch_enter_userspace) tail SVecURet
FUNCTION_END(arch_load_user_iframe)
FUNCTION(arch_longjmp_iframe):
mv sp, a0
call SVecURet
FUNCTION_END(arch_longjmp_iframe)
FUNCTION(arch_user_thread_exit): FUNCTION(arch_user_thread_exit):
+33 -3
View File
@@ -15,12 +15,15 @@
#include <platform/sbi/sbi_syscalls.h> #include <platform/sbi/sbi_syscalls.h>
extern "C" void SVec();
extern uint32 gPlatform; extern uint32 gPlatform;
status_t status_t
arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu) arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu)
{ {
// dprintf("arch_cpu_preboot_init_percpu(%" B_PRId32 ")\n", curr_cpu);
return B_OK; return B_OK;
} }
@@ -28,16 +31,34 @@ arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu)
status_t status_t
arch_cpu_init_percpu(kernel_args *args, int curr_cpu) arch_cpu_init_percpu(kernel_args *args, int curr_cpu)
{ {
//detect_cpu(curr_cpu); SetStvec((uint64)SVec);
SstatusReg sstatus(Sstatus());
sstatus.ie = 0;
sstatus.fs = extStatusInitial; // enable FPU
sstatus.xs = extStatusOff;
SetSstatus(sstatus.val);
SetSie(Sie() | (1 << sTimerInt) | (1 << sSoftInt) | (1 << sExternInt));
// we only support one anyway... return B_OK;
return 0;
} }
status_t status_t
arch_cpu_init(kernel_args *args) arch_cpu_init(kernel_args *args)
{ {
for (uint32 curCpu = 0; curCpu < args->num_cpus; curCpu++) {
cpu_ent* cpu = &gCPU[curCpu];
cpu->arch.hartId = args->arch_args.hartIds[curCpu];
cpu->topology_id[CPU_TOPOLOGY_PACKAGE] = 0;
cpu->topology_id[CPU_TOPOLOGY_CORE] = curCpu;
cpu->topology_id[CPU_TOPOLOGY_SMT] = 0;
for (unsigned int i = 0; i < CPU_MAX_CACHE_LEVEL; i++)
cpu->cache_id[i] = -1;
}
/* /*
uint64 conversionFactor uint64 conversionFactor
= (1LL << 32) * 1000000LL / args->arch_args.timerFrequency; = (1LL << 32) * 1000000LL / args->arch_args.timerFrequency;
@@ -88,24 +109,33 @@ arch_cpu_memory_write_barrier(void)
void void
arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
{ {
int32 numPages = end / B_PAGE_SIZE - start / B_PAGE_SIZE;
while (numPages-- >= 0) {
FlushTlbPage(start);
start += B_PAGE_SIZE;
}
} }
void void
arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
{ {
for (int i = 0; i < num_pages; i++)
FlushTlbPage(pages[i]);
} }
void void
arch_cpu_global_TLB_invalidate(void) arch_cpu_global_TLB_invalidate(void)
{ {
FlushTlbAll();
} }
void void
arch_cpu_user_TLB_invalidate(void) arch_cpu_user_TLB_invalidate(void)
{ {
FlushTlbAll();
} }
+69 -17
View File
@@ -20,6 +20,12 @@ kernel_args *sKernelArgs;
bool sInitCalled = false; bool sInitCalled = false;
extern "C" void SVecRet();
extern "C" void SVecURet();
void WriteRegisters(iframe* frame);
static void static void
WriteImage(preloaded_image* _image) WriteImage(preloaded_image* _image)
{ {
@@ -120,6 +126,19 @@ FindArea(addr_t adr)
} }
static VMArea*
FindAreaEx(Thread* thread, addr_t adr)
{
if (IS_KERNEL_ADDRESS(adr)) {
return VMAddressSpace::Kernel()->LookupArea(adr);
}
if (IS_USER_ADDRESS(adr)) {
return thread->team->address_space->LookupArea(adr);
}
return NULL;
}
static status_t static status_t
lookup_symbol(Thread* thread, addr_t address, addr_t* _baseAddress, lookup_symbol(Thread* thread, addr_t address, addr_t* _baseAddress,
const char** _symbolName, const char** _imageName, bool* _exactMatch) const char** _symbolName, const char** _imageName, bool* _exactMatch)
@@ -172,8 +191,8 @@ WritePCBoot(addr_t pc)
} }
void static void
WritePC(addr_t pc) WritePCEx(Thread* thread, addr_t pc)
{ {
dprintf("0x%" B_PRIxADDR " ", pc); dprintf("0x%" B_PRIxADDR " ", pc);
if (!sInitCalled) { if (!sInitCalled) {
@@ -184,7 +203,7 @@ WritePC(addr_t pc)
const char* symbolName; const char* symbolName;
const char* imageName; const char* imageName;
bool exactMatch; bool exactMatch;
if (lookup_symbol(thread_get_current_thread(), pc, &baseAddress, if (lookup_symbol(thread, pc, &baseAddress,
&symbolName, &imageName, &exactMatch) >= B_OK) { &symbolName, &imageName, &exactMatch) >= B_OK) {
if (symbolName != NULL) { if (symbolName != NULL) {
dprintf("<%s> %s + %" B_PRIdSSIZE, imageName, symbolName, dprintf("<%s> %s + %" B_PRIdSSIZE, imageName, symbolName,
@@ -195,7 +214,7 @@ WritePC(addr_t pc)
return; return;
} }
VMArea* area = FindArea(pc); VMArea* area = FindAreaEx(thread, pc);
if (area != NULL) { if (area != NULL) {
dprintf("<%s> 0x%" B_PRIxADDR, area->name, pc - area->Base()); dprintf("<%s> 0x%" B_PRIxADDR, area->name, pc - area->Base());
return; return;
@@ -205,14 +224,30 @@ WritePC(addr_t pc)
} }
void WritePC(addr_t pc)
{
WritePCEx(thread_get_current_thread(), pc);
}
static status_t
arch_debug_memcpy(void* dst, const void* src, size_t size)
{
if (debug_debugger_running())
return debug_memcpy(B_CURRENT_TEAM, dst, src, size);
return user_memcpy(dst, src, size);
}
static void static void
DumpMemory(uint64* adr, size_t len) DumpMemory(uint64* adr, size_t len)
{ {
while (len > 0) { while (len > 0) {
if ((addr_t)adr % 0x10 == 0) if ((addr_t)adr % 0x10 == 0)
dprintf("%08" B_PRIxADDR " ", (addr_t)adr); dprintf(" %08" B_PRIxADDR " ", (addr_t)adr);
uint64 val; uint64 val;
if (user_memcpy(&val, adr++, sizeof(val)) < B_OK) { if (arch_debug_memcpy(&val, adr++, sizeof(val)) < B_OK) {
dprintf(" ????????????????"); dprintf(" ????????????????");
} else { } else {
dprintf(" %016" B_PRIx64, val); dprintf(" %016" B_PRIx64, val);
@@ -226,40 +261,56 @@ DumpMemory(uint64* adr, size_t len)
} }
void static void
DoStackTrace(addr_t fp, addr_t pc) DoStackTraceEx(Thread* thread, addr_t fp, addr_t pc)
{ {
dprintf("Stack:\n"); dprintf("Stack:\n");
dprintf("FP: 0x%" B_PRIxADDR, fp); dprintf("FP: 0x%" B_PRIxADDR, fp);
if (pc != 0) { if (pc != 0) {
dprintf(", PC: "); WritePC(pc); dprintf(", PC: "); WritePCEx(thread, pc);
} }
dprintf("\n"); dprintf("\n");
addr_t oldFp = fp; addr_t oldFp = fp;
while (fp != 0) { int i = 0;
while (fp != 0 && i < 1000) {
if ((pc >= (addr_t)&strcpy && pc < (addr_t)&strcpy + 32) if ((pc >= (addr_t)&strcpy && pc < (addr_t)&strcpy + 32)
|| (pc >= (addr_t)&memset && pc < (addr_t)&memset + 34)) { || (pc >= (addr_t)&memset && pc < (addr_t)&memset + 34)
if (user_memcpy(&fp, (uint64*)fp - 1, sizeof(pc)) < B_OK) || (pc >= (addr_t)&memcpy && pc < (addr_t)&memcpy + 186)) {
if (arch_debug_memcpy(&fp, (uint64*)fp - 1, sizeof(pc)) < B_OK)
break; break;
pc = 0; pc = 0;
} else { } else {
if (user_memcpy(&pc, (uint64*)fp - 1, sizeof(pc)) < B_OK) if (arch_debug_memcpy(&pc, (uint64*)fp - 1, sizeof(pc)) < B_OK)
break; break;
if (user_memcpy(&fp, (uint64*)fp - 2, sizeof(pc)) < B_OK) if (arch_debug_memcpy(&fp, (uint64*)fp - 2, sizeof(pc)) < B_OK)
break; break;
} }
dprintf("FP: 0x%" B_PRIxADDR, fp); dprintf("FP: 0x%" B_PRIxADDR, fp);
dprintf(", PC: "); WritePC((pc == 0) ? 0 : pc - 1); dprintf(", PC: "); WritePCEx(thread, pc);
dprintf("\n"); dprintf("\n");
if (pc == (addr_t)&SVecRet || pc == (addr_t)&SVecURet) {
WriteTrapInfo((iframe*)fp - 1);
}
/* /*
if (IS_KERNEL_ADDRESS(oldFp) && IS_KERNEL_ADDRESS(fp)) if (IS_KERNEL_ADDRESS(oldFp) != IS_KERNEL_ADDRESS(fp))
oldFp = fp;
else if (fp != 0)
DumpMemory((uint64*)oldFp, (addr_t)fp - (addr_t)oldFp); DumpMemory((uint64*)oldFp, (addr_t)fp - (addr_t)oldFp);
*/ */
oldFp = fp; oldFp = fp;
i++;
} }
} }
void
DoStackTrace(addr_t fp, addr_t pc)
{
DoStackTraceEx(thread_get_current_thread(), fp, pc);
}
static int static int
stack_trace(int argc, char **argv) stack_trace(int argc, char **argv)
{ {
@@ -272,7 +323,8 @@ stack_trace(int argc, char **argv)
} }
uint64 oldSatp = Satp(); uint64 oldSatp = Satp();
SetSatp(thread->arch_info.context.satp); SetSatp(thread->arch_info.context.satp);
DoStackTrace(thread->arch_info.context.s[0], thread->arch_info.context.ra); DebuggedThreadSetter threadSetter(thread);
DoStackTraceEx(thread, thread->arch_info.context.s[0], thread->arch_info.context.ra);
SetSatp(oldSatp); SetSatp(oldSatp);
return 0; return 0;
} }
+224 -85
View File
@@ -26,17 +26,12 @@
#include <algorithm> #include <algorithm>
static uint32 sBootHartId = 0; static uint32 sPlicContexts[SMP_MAX_CPUS];
static int32 sPlicContextOfs = 0;
extern "C" void SVec();
extern "C" void SVecU();
//#pragma mark debug output //#pragma mark debug output
void static void
WriteMode(int mode) WriteMode(int mode)
{ {
switch (mode) { switch (mode) {
@@ -48,7 +43,7 @@ WriteMode(int mode)
} }
void static void
WriteModeSet(uint32_t val) WriteModeSet(uint32_t val)
{ {
bool first = true; bool first = true;
@@ -63,21 +58,20 @@ WriteModeSet(uint32_t val)
} }
void static void
WriteMstatus(uint64_t val) WriteExt(uint64_t val)
{ {
MstatusReg status(val); switch (val) {
dprintf("("); case 0: dprintf("off"); break;
dprintf("ie: "); WriteModeSet(status.ie); case 1: dprintf("initial"); break;
dprintf(", pie: "); WriteModeSet(status.pie); case 2: dprintf("clean"); break;
dprintf(", spp: "); WriteMode(status.spp); case 3: dprintf("dirty"); break;
dprintf(", mpp: "); WriteMode(status.mpp); default: dprintf("%" B_PRId64, val);
dprintf(", sum: %d", (int)status.sum); }
dprintf(")");
} }
void static void
WriteSstatus(uint64_t val) WriteSstatus(uint64_t val)
{ {
SstatusReg status(val); SstatusReg status(val);
@@ -85,12 +79,17 @@ WriteSstatus(uint64_t val)
dprintf("ie: "); WriteModeSet(status.ie); dprintf("ie: "); WriteModeSet(status.ie);
dprintf(", pie: "); WriteModeSet(status.pie); dprintf(", pie: "); WriteModeSet(status.pie);
dprintf(", spp: "); WriteMode(status.spp); dprintf(", spp: "); WriteMode(status.spp);
dprintf(", fs: "); WriteExt(status.fs);
dprintf(", xs: "); WriteExt(status.xs);
dprintf(", sum: %d", (int)status.sum); dprintf(", sum: %d", (int)status.sum);
dprintf(", mxr: %d", (int)status.mxr);
dprintf(", uxl: %d", (int)status.uxl);
dprintf(", sd: %d", (int)status.sd);
dprintf(")"); dprintf(")");
} }
void static void
WriteInterrupt(uint64_t val) WriteInterrupt(uint64_t val)
{ {
switch (val) { switch (val) {
@@ -108,7 +107,7 @@ WriteInterrupt(uint64_t val)
} }
void static void
WriteInterruptSet(uint64_t val) WriteInterruptSet(uint64_t val)
{ {
bool first = true; bool first = true;
@@ -123,7 +122,7 @@ WriteInterruptSet(uint64_t val)
} }
void static void
WriteCause(uint64_t cause) WriteCause(uint64_t cause)
{ {
if ((cause & causeInterrupt) == 0) { if ((cause & causeInterrupt) == 0) {
@@ -151,18 +150,99 @@ WriteCause(uint64_t cause)
} }
const static char* registerNames[] = {
" ra", " t6", " sp", " gp",
" tp", " t0", " t1", " t2",
" t5", " s1", " a0", " a1",
" a2", " a3", " a4", " a5",
" a6", " a7", " s2", " s3",
" s4", " s5", " s6", " s7",
" s8", " s9", "s10", "s11",
" t3", " t4", " fp", "epc"
};
static void WriteRegisters(iframe* frame)
{
uint64* regs = &frame->ra;
for (int i = 0; i < 32; i += 4) {
dprintf(
" %s: 0x%016" B_PRIx64
" %s: 0x%016" B_PRIx64
" %s: 0x%016" B_PRIx64
" %s: 0x%016" B_PRIx64 "\n",
registerNames[i + 0], regs[i + 0],
registerNames[i + 1], regs[i + 1],
registerNames[i + 2], regs[i + 2],
registerNames[i + 3], regs[i + 3]
);
}
}
static void
DumpMemory(uint64* adr, size_t len)
{
while (len > 0) {
if ((addr_t)adr % 0x10 == 0)
dprintf("%08" B_PRIxADDR " ", (addr_t)adr);
uint64 val;
if (user_memcpy(&val, adr++, sizeof(val)) < B_OK) {
dprintf(" ????????????????");
} else {
dprintf(" %016" B_PRIx64, val);
}
if ((addr_t)adr % 0x10 == 0)
dprintf("\n");
len -= 8;
}
if ((addr_t)adr % 0x10 != 0)
dprintf("\n");
dprintf("%08" B_PRIxADDR "\n\n", (addr_t)adr);
}
void void
WriteTrapInfo() WriteTrapInfo(iframe* frame)
{ {
InterruptsLocker locker; InterruptsLocker locker;
dprintf("STrap("); WriteCause(Scause()); dprintf(")\n"); dprintf("STrap("); WriteCause(frame->cause); dprintf(")\n");
dprintf(" sstatus: "); WriteSstatus(Sstatus()); dprintf("\n"); dprintf(" sstatus: "); WriteSstatus(frame->status); dprintf("\n");
dprintf(" sie: "); WriteInterruptSet(Sie()); dprintf("\n"); // dprintf(" sie: "); WriteInterruptSet(Sie()); dprintf("\n");
dprintf(" sip: "); WriteInterruptSet(Sip()); dprintf("\n"); // dprintf(" sip: "); WriteInterruptSet(Sip()); dprintf("\n");
//dprintf(" stval: "); WritePC(Stval()); dprintf("\n"); //dprintf(" stval: "); WritePC(Stval()); dprintf("\n");
dprintf(" stval: 0x%" B_PRIx64 "\n", Stval()); dprintf(" stval: 0x%" B_PRIx64 "\n", frame->tval);
dprintf(" tp: 0x%" B_PRIxADDR "(%s)\n", Tp(), // dprintf(" tp: 0x%" B_PRIxADDR "(%s)\n", Tp(),
thread_get_current_thread()->name); // thread_get_current_thread()->name);
WriteRegisters(frame);
#if 0
dprintf(" kernel stack: %#" B_PRIxADDR " - %#" B_PRIxADDR "\n",
thread_get_current_thread()->kernel_stack_base,
thread_get_current_thread()->kernel_stack_top - 1
);
dprintf(" user stack: %#" B_PRIxADDR " - %#" B_PRIxADDR "\n",
thread_get_current_thread()->user_stack_base,
thread_get_current_thread()->user_stack_base +
thread_get_current_thread()->user_stack_size - 1
);
if (thread_get_current_thread()->arch_info.userFrame != NULL) {
WriteRegisters(thread_get_current_thread()->arch_info.userFrame);
dprintf("Stack memory dump:\n");
DumpMemory(
(uint64*)thread_get_current_thread()->arch_info.userFrame->sp,
thread_get_current_thread()->user_stack_base +
thread_get_current_thread()->user_stack_size -
thread_get_current_thread()->arch_info.userFrame->sp
);
// if (true) {
// } else {
// DumpMemory((uint64*)frame->sp, thread_get_current_thread()->kernel_stack_top - frame->sp);
// }
}
#endif
} }
@@ -176,7 +256,6 @@ SendSignal(debug_exception_type type, uint32 signalNumber, int32 signalCode,
struct sigaction action; struct sigaction action;
Thread* thread = thread_get_current_thread(); Thread* thread = thread_get_current_thread();
WriteTrapInfo();
DoStackTrace(Fp(), 0); DoStackTrace(Fp(), 0);
enable_interrupts(); enable_interrupts();
@@ -193,7 +272,6 @@ SendSignal(debug_exception_type type, uint32 signalNumber, int32 signalCode,
send_signal_to_thread(thread, signal, 0); send_signal_to_thread(thread, signal, 0);
} }
} else { } else {
WriteTrapInfo();
panic("Unexpected exception occurred in kernel mode!"); panic("Unexpected exception occurred in kernel mode!");
} }
} }
@@ -244,6 +322,10 @@ SetAccessedFlags(addr_t addr, bool isWrite)
phys_addr_t physAdr; phys_addr_t physAdr;
uint32 pageFlags; uint32 pageFlags;
map->QueryInterrupt(addr, &physAdr, &pageFlags); map->QueryInterrupt(addr, &physAdr, &pageFlags);
if ((PAGE_PRESENT & pageFlags) == 0)
return false;
if (isWrite) { if (isWrite) {
if ( if (
((B_WRITE_AREA | B_KERNEL_WRITE_AREA) & pageFlags) != 0 ((B_WRITE_AREA | B_KERNEL_WRITE_AREA) & pageFlags) != 0
@@ -272,23 +354,6 @@ SetAccessedFlags(addr_t addr, bool isWrite)
} }
static void
WriteProtection(uint32 flags)
{
dprintf("kernel: {");
if (B_KERNEL_READ_AREA & flags) dprintf("R");
if (B_KERNEL_WRITE_AREA & flags) dprintf("W");
if (B_KERNEL_EXECUTE_AREA & flags) dprintf("X");
if (B_KERNEL_STACK_AREA & flags) dprintf("S");
dprintf("}, user: {");
if (B_READ_AREA & flags) dprintf("R");
if (B_WRITE_AREA & flags) dprintf("W");
if (B_EXECUTE_AREA & flags) dprintf("X");
if (B_STACK_AREA & flags) dprintf("S");
dprintf("}");
}
// TODO: needs moved into an arch-agnostic location? // TODO: needs moved into an arch-agnostic location?
template<typename F> template<typename F>
@@ -328,29 +393,45 @@ STrap(iframe* frame)
{ {
// dprintf("STrap("); WriteCause(Scause()); dprintf(")\n"); // dprintf("STrap("); WriteCause(Scause()); dprintf(")\n");
SstatusReg status(Sstatus()); /*
uint64 cause = Scause(); iframe oldFrame = *frame;
const auto& frameChangeChecker = MakeScopeExit([&]() {
InterruptsLocker locker;
bool first = true;
for (int i = 0; i < 32; i++) {
uint64 oldVal = ((int64*)&oldFrame)[i];
uint64 newVal = ((int64*)frame)[i];
if (oldVal != newVal) {
if (first) {
dprintf("FrameChangeChecker, thread: %" B_PRId32 "(%s)\n", thread_get_current_thread()->id, thread_get_current_thread()->name);
first = false;
}
dprintf(" %s: %#" B_PRIxADDR " -> %#" B_PRIxADDR "\n", registerNames[i], oldVal, newVal);
}
}
const auto& statusRestorer = MakeScopeExit([&]() { if (frame->epc == 0)
SetSstatus(status.val); panic("FrameChangeChecker: EPC = 0");
}); });
*/
switch (cause) { switch (frame->cause) {
case causeExecPageFault: case causeExecPageFault:
case causeLoadPageFault: case causeLoadPageFault:
case causeStorePageFault: { case causeStorePageFault: {
if (SetAccessedFlags(Stval(), cause == causeStorePageFault)) if (SetAccessedFlags(Stval(), frame->cause == causeStorePageFault))
return; return;
} }
} }
if (status.spp == modeU) { if (SstatusReg(frame->status).spp == modeU) {
thread_get_current_thread()->arch_info.userFrame = frame; thread_get_current_thread()->arch_info.userFrame = frame;
thread_get_current_thread()->arch_info.oldA0 = frame->a0;
thread_at_kernel_entry(system_time()); thread_at_kernel_entry(system_time());
} }
const auto& kernelExit = MakeScopeExit([&]() { const auto& kernelExit = MakeScopeExit([&]() {
if (status.spp == modeU) { if (SstatusReg(frame->status).spp == modeU) {
disable_interrupts(); disable_interrupts();
atomic_and(&thread_get_current_thread()->flags, ~THREAD_FLAGS_SYSCALL_RESTARTED);
if ((thread_get_current_thread()->flags if ((thread_get_current_thread()->flags
& (THREAD_FLAGS_SIGNALS_PENDING & (THREAD_FLAGS_SIGNALS_PENDING
| THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_DEBUG_THREAD
@@ -360,11 +441,18 @@ STrap(iframe* frame)
} else { } else {
thread_at_kernel_exit_no_signals(); thread_at_kernel_exit_no_signals();
} }
if ((THREAD_FLAGS_RESTART_SYSCALL & thread_get_current_thread()->flags) != 0) {
atomic_and(&thread_get_current_thread()->flags, ~THREAD_FLAGS_RESTART_SYSCALL);
atomic_or(&thread_get_current_thread()->flags, THREAD_FLAGS_SYSCALL_RESTARTED);
frame->a0 = thread_get_current_thread()->arch_info.oldA0;
frame->epc -= 4;
}
thread_get_current_thread()->arch_info.userFrame = NULL; thread_get_current_thread()->arch_info.userFrame = NULL;
} }
}); });
switch (cause) { switch (frame->cause) {
case causeIllegalInst: { case causeIllegalInst: {
return SendSignal(B_INVALID_OPCODE_EXCEPTION, SIGILL, ILL_ILLOPC, return SendSignal(B_INVALID_OPCODE_EXCEPTION, SIGILL, ILL_ILLOPC,
frame->epc); frame->epc);
@@ -393,7 +481,7 @@ STrap(iframe* frame)
cpu_ent* cpu = &gCPU[smp_get_current_cpu()]; cpu_ent* cpu = &gCPU[smp_get_current_cpu()];
if (cpu->fault_handler != 0) { if (cpu->fault_handler != 0) {
debug_set_page_fault_info(stval, frame->epc, debug_set_page_fault_info(stval, frame->epc,
(cause == causeStorePageFault) (frame->cause == causeStorePageFault)
? DEBUG_PAGE_FAULT_WRITE : 0); ? DEBUG_PAGE_FAULT_WRITE : 0);
frame->epc = cpu->fault_handler; frame->epc = cpu->fault_handler;
frame->sp = cpu->fault_handler_stack_pointer; frame->sp = cpu->fault_handler_stack_pointer;
@@ -404,7 +492,7 @@ STrap(iframe* frame)
kprintf("ERROR: thread::fault_handler used in kernel " kprintf("ERROR: thread::fault_handler used in kernel "
"debugger!\n"); "debugger!\n");
debug_set_page_fault_info(stval, frame->epc, debug_set_page_fault_info(stval, frame->epc,
cause == causeStorePageFault frame->cause == causeStorePageFault
? DEBUG_PAGE_FAULT_WRITE : 0); ? DEBUG_PAGE_FAULT_WRITE : 0);
frame->epc = (addr_t)thread->fault_handler; frame->epc = (addr_t)thread->fault_handler;
return; return;
@@ -416,32 +504,49 @@ STrap(iframe* frame)
return; return;
} }
if (status.pie == 0) { if (SstatusReg(frame->status).pie == 0) {
WriteTrapInfo(); // user_memcpy() failure
Thread* thread = thread_get_current_thread();
if (thread != NULL && thread->fault_handler != 0) {
addr_t handler = (addr_t)(thread->fault_handler);
if (frame->epc != handler) {
frame->epc = handler;
return;
}
}
panic("page fault with interrupts disabled@!dump_virt_page %#" B_PRIx64, stval); panic("page fault with interrupts disabled@!dump_virt_page %#" B_PRIx64, stval);
} }
addr_t newIP = 0; addr_t newIP = 0;
enable_interrupts(); enable_interrupts();
vm_page_fault(stval, frame->epc, cause == causeStorePageFault,
cause == causeExecPageFault, status.spp == modeU, &newIP); vm_page_fault(stval, frame->epc, frame->cause == causeStorePageFault,
frame->cause == causeExecPageFault,
SstatusReg(frame->status).spp == modeU, &newIP);
if (newIP != 0) if (newIP != 0)
frame->epc = newIP; frame->epc = newIP;
return; return;
} }
case causeInterrupt + sSoftInt: {
SetSip(Sip() & ~(1 << sSoftInt));
// dprintf("sSoftInt(%" B_PRId32 ")\n", smp_get_current_cpu());
smp_intercpu_int_handler(smp_get_current_cpu());
AfterInterrupt();
return;
}
case causeInterrupt + sTimerInt: { case causeInterrupt + sTimerInt: {
// SetSie(Sie() & ~(1 << sTimerInt));
// dprintf("sTimerInt(%" B_PRId32 ")\n", smp_get_current_cpu());
timer_interrupt(); timer_interrupt();
AfterInterrupt(); AfterInterrupt();
return; return;
} }
case causeInterrupt + sExternInt: { case causeInterrupt + sExternInt: {
// TODO: get PLIC context ID mapping for HARD ID from FDT? uint64 irq = gPlicRegs->contexts[sPlicContexts[smp_get_current_cpu()]].claimAndComplete;
uint64 irq = gPlicRegs->contexts[modeS + 2 * sBootHartId
+ sPlicContextOfs].claimAndComplete;
int_io_interrupt_handler(irq, true); int_io_interrupt_handler(irq, true);
gPlicRegs->contexts[modeS + 2*sBootHartId gPlicRegs->contexts[sPlicContexts[smp_get_current_cpu()]].claimAndComplete = irq;
+ sPlicContextOfs].claimAndComplete = irq;
AfterInterrupt(); AfterInterrupt();
return; return;
} }
@@ -467,12 +572,12 @@ STrap(iframe* frame)
switch (syscall) { switch (syscall) {
case SYSCALL_READ_PORT_ETC: case SYSCALL_READ_PORT_ETC:
case SYSCALL_WRITE_PORT_ETC: case SYSCALL_WRITE_PORT_ETC:
WriteTrapInfo();
DoStackTrace(Fp(), 0); DoStackTrace(Fp(), 0);
break; break;
} }
*/ */
// dprintf("syscall: %s\n", kExtendedSyscallInfos[syscall].name); // dprintf("syscall: %s\n", kExtendedSyscallInfos[syscall].name);
enable_interrupts(); enable_interrupts();
uint64 returnValue = 0; uint64 returnValue = 0;
syscall_dispatcher(syscall, (void*)args, &returnValue); syscall_dispatcher(syscall, (void*)args, &returnValue);
@@ -480,7 +585,6 @@ STrap(iframe* frame)
return; return;
} }
} }
WriteTrapInfo();
panic("unhandled STrap"); panic("unhandled STrap");
} }
@@ -490,22 +594,23 @@ STrap(iframe* frame)
status_t status_t
arch_int_init(kernel_args* args) arch_int_init(kernel_args* args)
{ {
sBootHartId = args->arch_args.bootHart; dprintf("arch_int_init()\n");
sPlicContextOfs = (sBootHartId == 0) ? 0 : -1;
// TODO: Kernel mode FPU handling needs improved? for (uint32 i = 0; i < args->num_cpus; i++) {
SetStvec((uint64)SVec); dprintf(" CPU %" B_PRIu32 ":\n", i);
SstatusReg sstatus(Sstatus()); dprintf(" hartId: %" B_PRIu32 "\n", args->arch_args.hartIds[i]);
sstatus.ie = 0; dprintf(" plicContext: %" B_PRIu32 "\n", args->arch_args.plicContexts[i]);
sstatus.fs = extStatusInitial; // enable FPU }
sstatus.xs = extStatusOff;
SetSstatus(sstatus.val); for (uint32 i = 0; i < args->num_cpus; i++)
SetSie(Sie() | (1 << sTimerInt) | (1 << sExternInt)); sPlicContexts[i] = args->arch_args.plicContexts[i];
// TODO: read from FDT // TODO: read from FDT
reserve_io_interrupt_vectors(128, 0, INTERRUPT_TYPE_IRQ); reserve_io_interrupt_vectors(128, 0, INTERRUPT_TYPE_IRQ);
gPlicRegs->contexts[modeS + 2*sBootHartId + sPlicContextOfs].priorityThreshold = 0; for (uint32 i = 0; i < args->num_cpus; i++)
gPlicRegs->contexts[sPlicContexts[i]].priorityThreshold = 0;
return B_OK; return B_OK;
} }
@@ -536,7 +641,7 @@ arch_int_enable_io_interrupt(int irq)
{ {
dprintf("arch_int_enable_io_interrupt(%d)\n", irq); dprintf("arch_int_enable_io_interrupt(%d)\n", irq);
gPlicRegs->priority[irq] = 1; gPlicRegs->priority[irq] = 1;
gPlicRegs->enable[modeS + 2*sBootHartId + sPlicContextOfs][irq / 32] |= 1 << (irq % 32); gPlicRegs->enable[sPlicContexts[0]][irq / 32] |= 1 << (irq % 32);
} }
@@ -545,7 +650,7 @@ arch_int_disable_io_interrupt(int irq)
{ {
dprintf("arch_int_disable_io_interrupt(%d)\n", irq); dprintf("arch_int_disable_io_interrupt(%d)\n", irq);
gPlicRegs->priority[irq] = 0; gPlicRegs->priority[irq] = 0;
gPlicRegs->enable[modeS + 2*sBootHartId + sPlicContextOfs][irq / 32] &= ~(1 << (irq % 32)); gPlicRegs->enable[sPlicContexts[0]][irq / 32] &= ~(1 << (irq % 32));
} }
@@ -555,3 +660,37 @@ arch_int_assign_to_cpu(int32 irq, int32 cpu)
// Not yet supported. // Not yet supported.
return 0; return 0;
} }
#undef arch_int_enable_interrupts
#undef arch_int_disable_interrupts
#undef arch_int_restore_interrupts
#undef arch_int_are_interrupts_enabled
extern "C" void
arch_int_enable_interrupts()
{
arch_int_enable_interrupts_inline();
}
extern "C" int
arch_int_disable_interrupts()
{
return arch_int_disable_interrupts_inline();
}
extern "C" void
arch_int_restore_interrupts(int oldState)
{
arch_int_restore_interrupts_inline(oldState);
}
extern "C" bool
arch_int_are_interrupts_enabled()
{
return arch_int_are_interrupts_enabled_inline();
}
+42 -5
View File
@@ -17,16 +17,23 @@
#include <debug.h> #include <debug.h>
#include <int.h> #include <int.h>
#include <cpu.h>
#include <platform/sbi/sbi_syscalls.h>
extern uint32 gPlatform;
status_t status_t
arch_smp_init(kernel_args *args) arch_smp_init(kernel_args *args)
{ {
dprintf("arch_smp_init()\n");
return B_OK; return B_OK;
} }
status_t status_t
arch_smp_per_cpu_init(kernel_args *args, int32 cpu) arch_smp_per_cpu_init(kernel_args *args, int32 cpuId)
{ {
return B_OK; return B_OK;
} }
@@ -35,6 +42,22 @@ arch_smp_per_cpu_init(kernel_args *args, int32 cpu)
void void
arch_smp_send_multicast_ici(CPUSet& cpuSet) arch_smp_send_multicast_ici(CPUSet& cpuSet)
{ {
switch (gPlatform) {
case kPlatformSbi: {
uint64 hartMask = 0;
int32 cpuCount = smp_get_num_cpus();
for (int32 i = 0; i < cpuCount; i++) {
if (cpuSet.GetBit(i) && i != smp_get_current_cpu())
hartMask |= (uint64)1 << gCPU[i].arch.hartId;
}
// TODO: handle hart ID >= 64
sbi_send_ipi(hartMask, 0);
break;
}
case kPlatformMNative:
default:
dprintf("arch_smp_send_multicast_ici: not implemented\n");
}
#if KDEBUG #if KDEBUG
if (are_interrupts_enabled()) if (are_interrupts_enabled())
panic("arch_smp_send_multicast_ici: called with interrupts enabled"); panic("arch_smp_send_multicast_ici: called with interrupts enabled");
@@ -45,14 +68,28 @@ arch_smp_send_multicast_ici(CPUSet& cpuSet)
void void
arch_smp_send_ici(int32 target_cpu) arch_smp_send_ici(int32 target_cpu)
{ {
panic("called arch_smp_send_ici!\n"); switch (gPlatform) {
case kPlatformSbi:
// dprintf("arch_smp_send_ici(%" B_PRId32 ")\n", target_cpu);
sbi_send_ipi((uint64)1 << gCPU[target_cpu].arch.hartId, 0);
break;
case kPlatformMNative:
default:
dprintf("arch_smp_send_ici: not implemented\n");
}
} }
void void
arch_smp_send_broadcast_ici() arch_smp_send_broadcast_ici()
{ {
panic("called arch_smp_send_broadcast_ici\n"); switch (gPlatform) {
case kPlatformSbi:
// dprintf("arch_smp_send_broadcast_ici()\n");
sbi_send_ipi(0, -1);
break;
case kPlatformMNative:
default:
dprintf("arch_smp_send_broadcast_ici: not implemented\n");
}
} }
+44 -28
View File
@@ -22,12 +22,6 @@
extern "C" void SVecU(); extern "C" void SVecU();
extern "C" void RestoreUserRegs()
{
SetSscratch((addr_t)&thread_get_current_thread()->arch_info);
SetTp(thread_get_current_thread()->user_local_storage);
}
status_t status_t
arch_thread_init(struct kernel_args *args) arch_thread_init(struct kernel_args *args)
@@ -50,7 +44,6 @@ arch_team_init_team_struct(Team *team, bool kernel)
status_t status_t
arch_thread_init_thread_struct(Thread *thread) arch_thread_init_thread_struct(Thread *thread)
{ {
thread->arch_info.thread = thread;
return B_OK; return B_OK;
} }
@@ -70,15 +63,17 @@ void
arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop, arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop,
void (*function)(void*), const void* data) void (*function)(void*), const void* data)
{ {
// dprintf("arch_thread_init_kthread_stack(%p(%s))\n", thread, thread->name);
memset(&thread->arch_info.context, 0, sizeof(arch_context)); memset(&thread->arch_info.context, 0, sizeof(arch_context));
thread->arch_info.context.sp = (addr_t)_stackTop; thread->arch_info.context.sp = (addr_t)_stackTop;
thread->arch_info.context.s[0] = 0; // fp thread->arch_info.context.s[0] = 0; // fp
thread->arch_info.context.s[1] = (addr_t)function; thread->arch_info.context.s[1] = (addr_t)function;
thread->arch_info.context.s[2] = (addr_t)data; thread->arch_info.context.s[2] = (addr_t)data;
thread->arch_info.context.ra = (addr_t)arch_thread_entry; thread->arch_info.context.ra = (addr_t)arch_thread_entry;
VMTranslationMap* map = GetThreadAddressSpace(thread)->TranslationMap(); RISCV64VMTranslationMap* map = (RISCV64VMTranslationMap*)
thread->arch_info.context.satp = ((RISCV64VMTranslationMap*)map)->Satp(); thread->team->address_space->TranslationMap();
thread->arch_info.context.satp = map->Satp();
memset(&thread->arch_info.fpuContext, 0, sizeof(fpu_context));
} }
@@ -107,13 +102,22 @@ arch_thread_context_switch(Thread *from, Thread *to)
dprintf("arch_thread_context_switch(%p(%s), %p(%s))\n", from, from->name, dprintf("arch_thread_context_switch(%p(%s), %p(%s))\n", from, from->name,
to, to->name); to, to->name);
*/ */
RISCV64VMTranslationMap* fromMap = (RISCV64VMTranslationMap*)from->team
->address_space->TranslationMap();
RISCV64VMTranslationMap* toMap = (RISCV64VMTranslationMap*)to->team
->address_space->TranslationMap();
int cpu = to->cpu->cpu_num;
toMap->ActiveOnCpus().SetBitAtomic(cpu);
fromMap->ActiveOnCpus().ClearBitAtomic(cpu);
// TODO: save/restore FPU only if needed // TODO: save/restore FPU only if needed
save_fpu(&from->arch_info.fpuContext); save_fpu(&from->arch_info.fpuContext);
if (arch_setjmp(&from->arch_info.context) == 0) { restore_fpu(&to->arch_info.fpuContext);
arch_longjmp(&to->arch_info.context, 1);
} else { arch_context_switch(&from->arch_info.context, &to->arch_info.context);
restore_fpu(&from->arch_info.fpuContext);
}
} }
@@ -138,14 +142,17 @@ arch_thread_enter_userspace(Thread *thread, addr_t entry, void *arg1,
disable_interrupts(); disable_interrupts();
arch_stack* stackHeader = (arch_stack*)thread->kernel_stack_top - 1;
stackHeader->thread = thread;
iframe frame; iframe frame;
memset(&frame, 0, sizeof(frame)); memset(&frame, 0, sizeof(frame));
SstatusReg status(Sstatus()); SstatusReg status(Sstatus());
status.pie = (1 << modeS); // enable interrupts when enter userspace status.pie = (1 << modeS); // enable interrupts when enter userspace
status.spp = modeU; status.spp = modeU;
SetSstatus(status.val);
frame.status = status.val;
frame.epc = entry; frame.epc = entry;
frame.a0 = (addr_t)arg1; frame.a0 = (addr_t)arg1;
frame.a1 = (addr_t)arg2; frame.a1 = (addr_t)arg2;
@@ -153,7 +160,7 @@ arch_thread_enter_userspace(Thread *thread, addr_t entry, void *arg1,
frame.sp = thread->user_stack_base + thread->user_stack_size; frame.sp = thread->user_stack_base + thread->user_stack_size;
frame.tp = thread->user_local_storage; frame.tp = thread->user_local_storage;
arch_longjmp_iframe(&frame); arch_load_user_iframe(stackHeader, &frame);
// never return // never return
return B_ERROR; return B_ERROR;
@@ -199,7 +206,7 @@ status_t
arch_setup_signal_frame(Thread *thread, struct sigaction *sa, arch_setup_signal_frame(Thread *thread, struct sigaction *sa,
struct signal_frame_data *signalFrameData) struct signal_frame_data *signalFrameData)
{ {
// dprintf("arch_setup_signal_frame()\n"); // dprintf("%s(%" B_PRId32 "(%s))\n", __func__, thread->id, thread->name);
iframe* frame = thread->arch_info.userFrame; iframe* frame = thread->arch_info.userFrame;
// fill signal context // fill signal context
@@ -250,6 +257,8 @@ arch_setup_signal_frame(Thread *thread, struct sigaction *sa,
); );
} }
*/ */
signalFrameData->syscall_restart_return_value = thread->arch_info.oldA0;
uint8* userStack = get_signal_stack(thread, frame, sa, uint8* userStack = get_signal_stack(thread, frame, sa,
sizeof(*signalFrameData)); sizeof(*signalFrameData));
// dprintf(" user stack: 0x%" B_PRIxADDR "\n", (addr_t)userStack); // dprintf(" user stack: 0x%" B_PRIxADDR "\n", (addr_t)userStack);
@@ -283,6 +292,9 @@ arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
// dprintf("arch_restore_signal_frame()\n"); // dprintf("arch_restore_signal_frame()\n");
iframe* frame = thread_get_current_thread()->arch_info.userFrame; iframe* frame = thread_get_current_thread()->arch_info.userFrame;
thread_get_current_thread()->arch_info.oldA0
= signalFrameData->syscall_restart_return_value;
frame->ra = signalFrameData->context.uc_mcontext.x[ 0]; frame->ra = signalFrameData->context.uc_mcontext.x[ 0];
frame->sp = signalFrameData->context.uc_mcontext.x[ 1]; frame->sp = signalFrameData->context.uc_mcontext.x[ 1];
frame->gp = signalFrameData->context.uc_mcontext.x[ 2]; frame->gp = signalFrameData->context.uc_mcontext.x[ 2];
@@ -359,15 +371,19 @@ arch_store_fork_frame(struct arch_fork_arg *arg)
void void
arch_restore_fork_frame(struct arch_fork_arg *arg) arch_restore_fork_frame(struct arch_fork_arg *arg)
{ {
// dprintf("arch_restore_fork_frame(%p)\n", arg); //dprintf("arch_restore_fork_frame(%p)\n", arg);
//dprintf(" thread: %" B_PRId32 "(%s))\n", thread_get_current_thread()->id,
// thread_get_current_thread()->name);
//dprintf(" kernel SP: %#" B_PRIxADDR "\n", thread_get_current_thread()->kernel_stack_top);
//dprintf(" user PC: "); WritePC(arg->frame.epc); dprintf("\n");
disable_interrupts(); disable_interrupts();
if (arch_setjmp(&thread_get_current_thread()->arch_info.context) == 0) {
SstatusReg status(Sstatus()); arch_stack* stackHeader = (arch_stack*)thread_get_current_thread()->kernel_stack_top - 1;
status.pie = (1 << modeS); // enable interrupts when enter userspace stackHeader->thread = thread_get_current_thread();
status.spp = modeU; SstatusReg status(Sstatus());
SetSstatus(status.val); status.pie = (1 << modeS); // enable interrupts when enter userspace
arch_longjmp_iframe(&arg->frame); status.spp = modeU;
} else { arg->frame.status = status.val;
panic("return from userspace"); arch_load_user_iframe(stackHeader, &arg->frame);
}
} }
@@ -17,6 +17,8 @@
#include <timer.h> #include <timer.h>
#include <Clint.h> #include <Clint.h>
#include <smp.h>
extern uint32 gPlatform; extern uint32 gPlatform;
@@ -24,6 +26,8 @@ extern uint32 gPlatform;
void void
arch_timer_set_hardware_timer(bigtime_t timeout) arch_timer_set_hardware_timer(bigtime_t timeout)
{ {
// dprintf("arch_timer_set_hardware_timer(%" B_PRIu64 "), cpu: %" B_PRId32 "\n", timeout, smp_get_current_cpu());
// TODO: Read timer frequency from FDT // TODO: Read timer frequency from FDT
switch (gPlatform) { switch (gPlatform) {
case kPlatformMNative: case kPlatformMNative:
@@ -37,12 +41,16 @@ arch_timer_set_hardware_timer(bigtime_t timeout)
default: default:
; ;
} }
// SetSie(Sie() | (1 << sTimerInt));
} }
void void
arch_timer_clear_hardware_timer() arch_timer_clear_hardware_timer()
{ {
// SetSie(Sie() & ~(1 << sTimerInt));
switch (gPlatform) { switch (gPlatform) {
case kPlatformMNative: case kPlatformMNative:
MSyscall(kMSyscallSetTimer, false); MSyscall(kMSyscallSetTimer, false);
+45 -31
View File
@@ -4,43 +4,58 @@
*/ */
#include <asm_defs.h>
#include "arch_traps.h" #include "arch_traps.h"
#include "asm_offsets.h"
.globl SVec
.type SVec, @function
.align 4 .align 4
SVec: FUNCTION(SVec):
PushTrapFrame PushTrapFrame IFRAME_ra
sd fp, 2*8(sp) sd fp, IFRAME_sp(sp)
csrr t0, sepc csrr t0, sepc
sd t0, 31*8(sp) sd t0, IFRAME_epc(sp)
csrr t0, sstatus
sd t0, IFRAME_status(sp)
csrr t0, scause
sd t0, IFRAME_cause(sp)
csrr t0, stval
sd t0, IFRAME_tval(sp)
mv a0, sp mv a0, sp
call STrap call STrap
ld t0, 31*8(sp) FUNCTION(SVecRet):
ld t0, IFRAME_status(sp)
csrw sstatus, t0
ld t0, IFRAME_epc(sp)
csrw sepc, t0 csrw sepc, t0
PopTrapFrame PopTrapFrame IFRAME_ra
sret sret
.size SVec, .-SVec FUNCTION_END(SVec)
.globl SVecU
.type SVecU, @function
.align 4 .align 4
SVecU: FUNCTION(SVecU):
csrrw t0, sscratch, t0 # t0: &arch_thread # switch to kernel stack, SSCRATCH will hold user SP
ld tp, 0*8(t0) # tp = arch_thread.thread csrrw sp, sscratch, sp
ld t0, (1 + 13)*8(t0) # t0 = arch_thread.context.sp
sd sp, 2*8 - 256(t0) # save user SP
mv sp, t0 # switch to kernel stack
csrr t0, sscratch
PushTrapFrame
PushTrapFrame IFRAME_ra
csrr t0, sscratch
sd t0, IFRAME_sp(sp)
csrr t0, sepc csrr t0, sepc
sd t0, 31*8(sp) sd t0, IFRAME_epc(sp)
csrr t0, sstatus
sd t0, IFRAME_status(sp)
csrr t0, scause
sd t0, IFRAME_cause(sp)
csrr t0, stval
sd t0, IFRAME_tval(sp)
ld tp, ARCH_STACK_thread(fp)
la t0, SVec la t0, SVec
csrw stvec, t0 csrw stvec, t0
@@ -48,19 +63,18 @@ SVecU:
mv a0, sp mv a0, sp
call STrap call STrap
.globl SVecURet FUNCTION(SVecURet):
.type SVecURet, @function csrw sscratch, fp # save kernel SP
SVecURet:
call RestoreUserRegs
csrr t0, sscratch
sd fp, (1 + 13)*8(t0) # arch_thread.context.sp = fp
la t0, SVecU la t0, SVecU
csrw stvec, t0 csrw stvec, t0
ld t0, 31*8(sp) ld t0, IFRAME_status(sp)
csrw sstatus, t0
ld tp, IFRAME_tp(sp)
ld t0, IFRAME_epc(sp)
csrw sepc, t0 csrw sepc, t0
PopTrapFrame PopTrapFrame IFRAME_ra
sret sret
.size SVecU, .-SVecU FUNCTION_END(SVecU)
+117 -69
View File
@@ -94,91 +94,143 @@ WritePteFlags(uint32 flags)
} }
static void class PageTableDumper
DumpPageWrite(uint64_t virtAdr, uint64_t physAdr, size_t size, uint64 flags,
uint64& firstVirt, uint64& firstPhys, uint64& firstFlags, uint64& len)
{ {
if (virtAdr == firstVirt + len && physAdr == firstPhys + len private:
&& flags == firstFlags) { uint64 firstVirt;
len += size; uint64 firstPhys;
} else { uint64 firstFlags;
if (len != 0) { uint64 len;
dprintf(" 0x%08" B_PRIxADDR " - 0x%08" B_PRIxADDR,
firstVirt, firstVirt + (len - 1)); public:
dprintf(": 0x%08" B_PRIxADDR " - 0x%08" B_PRIxADDR ",%#" PageTableDumper()
B_PRIxADDR ", ", firstPhys, :
firstPhys + (len - 1), len); firstVirt(0),
WritePteFlags(firstFlags); dprintf("\n"); firstPhys(0),
} firstFlags(0),
firstVirt = virtAdr; len(0)
firstPhys = physAdr; {}
firstFlags = flags;
len = size; ~PageTableDumper()
{
Write(0, 0, 0, 0);
} }
}
void Write(uint64_t virtAdr, uint64_t physAdr, size_t size, uint64 flags) {
if (virtAdr == firstVirt + len && physAdr == firstPhys + len && flags == firstFlags) {
len += size;
} else {
if (len != 0) {
dprintf(" 0x%08" B_PRIxADDR " - 0x%08" B_PRIxADDR,
firstVirt, firstVirt + (len - 1));
dprintf(": 0x%08" B_PRIxADDR " - 0x%08" B_PRIxADDR ", %#" B_PRIxADDR ", ",
firstPhys, firstPhys + (len - 1), len);
WritePteFlags(firstFlags); dprintf("\n");
}
firstVirt = virtAdr;
firstPhys = physAdr;
firstFlags = flags;
len = size;
}
}
};
static void static void
DumpPageTableInt(Pte* pte, uint64_t virtAdr, uint32_t level, uint64& firstVirt, DumpPageTableInt(Pte* pte, uint64_t virtAdr, uint32_t level, PageTableDumper& dumper)
uint64& firstPhys, uint64& firstFlags, uint64& len)
{ {
for (uint32 i = 0; i < pteCount; i++) { for (uint32 i = 0; i < pteCount; i++) {
if (((1 << pteValid) & pte[i].flags) != 0) { if (((1 << pteValid) & pte[i].flags) != 0) {
if ((((1 << pteRead) | (1 << pteWrite) if ((((1 << pteRead) | (1 << pteWrite)
| (1 << pteExec)) & pte[i].flags) == 0) { | (1 << pteExec)) & pte[i].flags) == 0) {
if (level == 0) { if (level == 0)
kprintf(" internal page table on " kprintf(" internal page table on level 0\n");
"level 0\n");
}
DumpPageTableInt( DumpPageTableInt((Pte*)VirtFromPhys(pageSize*pte[i].ppn),
(Pte*)VirtFromPhys(pageSize*pte[i].ppn), virtAdr + ((uint64_t)i << (pageBits + pteIdxBits * level)),
virtAdr + ((uint64_t)i level - 1, dumper);
<< (pageBits + pteIdxBits
* level)),
level - 1, firstVirt, firstPhys,
firstFlags, len);
} else { } else {
DumpPageWrite(SignExtendVirtAdr(virtAdr dumper.Write(SignExtendVirtAdr(virtAdr
+ ((uint64_t)i << (pageBits + ((uint64_t)i << (pageBits + pteIdxBits*level))),
+ pteIdxBits*level))), pte[i].ppn * B_PAGE_SIZE, 1 << (pageBits + pteIdxBits * level),
pte[i].ppn * B_PAGE_SIZE, pte[i].flags);
1 << (pageBits + pteIdxBits*level),
pte[i].flags, firstVirt, firstPhys,
firstFlags, len);
} }
} }
} }
} }
static VMArea* LookupArea(area_id id)
{
VMAreaHash::ReadLock();
VMArea* area = VMAreaHash::LookupLocked(id);
VMAreaHash::ReadUnlock();
return area;
}
static int static int
DumpPageTable(int argc, char** argv) DumpPageTable(int argc, char** argv)
{ {
int curArg = 1;
SatpReg satp; SatpReg satp;
if (argc >= 2) { bool isArea = false;
team_id id = strtoul(argv[1], NULL, 0); addr_t base = 0;
VMAddressSpace* addrSpace = VMAddressSpace::DebugGet(id); size_t size = 0;
if (addrSpace == NULL) {
kprintf("could not find team %" B_PRId32 "\n", id); satp.val = Satp();
while (curArg < argc && argv[curArg][0] == '-') {
if (strcmp(argv[curArg], "-team") == 0) {
curArg++;
team_id id = strtoul(argv[curArg++], NULL, 0);
VMAddressSpace* addrSpace = VMAddressSpace::DebugGet(id);
if (addrSpace == NULL) {
kprintf("could not find team %" B_PRId32 "\n", id);
return 0;
}
satp.val = ((RISCV64VMTranslationMap*)
addrSpace->TranslationMap())->Satp();
isArea = false;
} else if (strcmp(argv[curArg], "-area") == 0) {
curArg++;
uint64 areaId;
if (!evaluate_debug_expression(argv[curArg++], &areaId, false))
return 0;
VMArea* area = LookupArea((area_id)areaId);
if (area == NULL) {
kprintf("could not find area %" B_PRId32 "\n", (area_id)areaId);
return 0;
}
satp.val = ((RISCV64VMTranslationMap*)
area->address_space->TranslationMap())->Satp();
base = area->Base();
size = area->Size();
kprintf("area %" B_PRId32 "(%s)\n", area->id, area->name);
isArea = true;
} else {
kprintf("unknown flag \"%s\"\n", argv[curArg]);
return 0; return 0;
} }
satp.val = ((RISCV64VMTranslationMap*)
addrSpace->TranslationMap())->Satp();
dprintf("page table for team %" B_PRId32 "\n", id);
} else {
satp.val = Satp();
dprintf("current page table:\n");
} }
Pte* root = (Pte*)VirtFromPhys(satp.ppn * B_PAGE_SIZE);
uint64 firstVirt = 0; kprintf("satp: %#" B_PRIx64 "\n", satp.val);
uint64 firstPhys = 0;
uint64 firstFlags = 0; PageTableDumper dumper;
uint64 len = 0;
DumpPageTableInt(root, 0, 2, firstVirt, firstPhys, firstFlags, len); if (!isArea) {
DumpPageWrite(0, 0, 0, 0, firstVirt, firstPhys, firstFlags, len); Pte* root = (Pte*)VirtFromPhys(satp.ppn * B_PAGE_SIZE);
DumpPageTableInt(root, 0, 2, dumper);
} else {
for (; size > 0; base += B_PAGE_SIZE, size -= B_PAGE_SIZE) {
Pte* pte = LookupPte(satp.ppn * B_PAGE_SIZE, base);
if (pte == NULL || (pte->flags & (1 << pteValid)) == 0)
continue;
dumper.Write(base, pte->ppn * B_PAGE_SIZE, B_PAGE_SIZE, pte->flags);
}
}
return 0; return 0;
} }
@@ -191,7 +243,7 @@ DumpVirtPage(int argc, char** argv)
SatpReg satp; SatpReg satp;
satp.val = Satp(); satp.val = Satp();
while (argv[curArg][0] == '-') { while (curArg < argc && argv[curArg][0] == '-') {
if (strcmp(argv[curArg], "-team") == 0) { if (strcmp(argv[curArg], "-team") == 0) {
curArg++; curArg++;
team_id id = strtoul(argv[curArg++], NULL, 0); team_id id = strtoul(argv[curArg++], NULL, 0);
@@ -210,24 +262,20 @@ DumpVirtPage(int argc, char** argv)
kprintf("satp: %#" B_PRIx64 "\n", satp.val); kprintf("satp: %#" B_PRIx64 "\n", satp.val);
uint64 firstVirt = 0; uint64 virt = 0;
uint64 firstPhys = 0; if (!evaluate_debug_expression(argv[curArg++], &virt, false))
uint64 firstFlags = 0;
uint64 len = B_PAGE_SIZE;
if (!evaluate_debug_expression(argv[curArg++], &firstVirt, false))
return 0; return 0;
firstVirt = ROUNDDOWN(firstVirt, B_PAGE_SIZE); virt = ROUNDDOWN(virt, B_PAGE_SIZE);
Pte* pte = LookupPte(satp.ppn * B_PAGE_SIZE, firstVirt); Pte* pte = LookupPte(satp.ppn * B_PAGE_SIZE, virt);
if (pte == NULL) { if (pte == NULL) {
dprintf("not mapped\n"); dprintf("not mapped\n");
return 0; return 0;
} }
firstPhys = pte->ppn * B_PAGE_SIZE;
firstFlags = pte->flags;
DumpPageWrite(0, 0, 0, 0, firstVirt, firstPhys, firstFlags, len); PageTableDumper dumper;
dumper.Write(virt, pte->ppn * B_PAGE_SIZE, B_PAGE_SIZE, pte->flags);
return 0; return 0;
} }
@@ -0,0 +1,52 @@
/*
* Copyright 2007-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
// This file is used to get C structure offsets into assembly code.
// The build system assembles the file and processes the output to create
// a header file with macro definitions, that can be included from assembly
// code.
#include <computed_asm_macros.h>
#include <arch_cpu.h>
#include <cpu.h>
#include <ksignal.h>
#include <ksyscalls.h>
#include <thread_types.h>
#define DEFINE_MACRO(macro, value) DEFINE_COMPUTED_ASM_MACRO(macro, value)
#define DEFINE_OFFSET_MACRO(prefix, structure, member) \
DEFINE_MACRO(prefix##_##member, offsetof(struct structure, member));
#define DEFINE_SIZEOF_MACRO(prefix, structure) \
DEFINE_MACRO(prefix##_sizeof, sizeof(struct structure));
void
dummy()
{
// struct Thread
DEFINE_OFFSET_MACRO(THREAD, Thread, arch_info);
// struct arch_thread
DEFINE_OFFSET_MACRO(ARCH_THREAD, arch_thread, context);
DEFINE_OFFSET_MACRO(ARCH_THREAD, arch_thread, fpuContext);
DEFINE_OFFSET_MACRO(ARCH_CONTEXT, arch_context, sp);
DEFINE_OFFSET_MACRO(ARCH_STACK, arch_stack, thread);
DEFINE_SIZEOF_MACRO(IFRAME, iframe);
DEFINE_OFFSET_MACRO(IFRAME, iframe, status);
DEFINE_OFFSET_MACRO(IFRAME, iframe, cause);
DEFINE_OFFSET_MACRO(IFRAME, iframe, tval);
DEFINE_OFFSET_MACRO(IFRAME, iframe, ra);
DEFINE_OFFSET_MACRO(IFRAME, iframe, sp);
DEFINE_OFFSET_MACRO(IFRAME, iframe, tp);
DEFINE_OFFSET_MACRO(IFRAME, iframe, epc);
}
+5
View File
@@ -411,6 +411,11 @@ restore_interrupts(cpu_status status)
static static
uint32 assign_cpu(void) uint32 assign_cpu(void)
{ {
// arch_int_assign_to_cpu is not yet implemented for riscv
#ifdef __riscv
return 0;
#endif
const cpu_topology_node* node; const cpu_topology_node* node;
do { do {
int32 nextID = atomic_add(&sLastCPU, 1); int32 nextID = atomic_add(&sLastCPU, 1);
+2 -2
View File
@@ -4421,8 +4421,8 @@ vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite, bool isExecute,
if (status < B_OK) { if (status < B_OK) {
dprintf("vm_page_fault: vm_soft_fault returned error '%s' on fault at " dprintf("vm_page_fault: vm_soft_fault returned error '%s' on fault at "
"0x%lx, ip 0x%lx, write %d, user %d, thread 0x%" B_PRIx32 "\n", "0x%lx, ip 0x%lx, write %d, user %d, exec %d, thread 0x%" B_PRIx32 "\n",
strerror(status), address, faultAddress, isWrite, isUser, strerror(status), address, faultAddress, isWrite, isUser, isExecute,
thread_get_current_thread_id()); thread_get_current_thread_id());
if (!isUser) { if (!isUser) {
Thread* thread = thread_get_current_thread(); Thread* thread = thread_get_current_thread();