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:
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user