diff --git a/.lock b/.lock new file mode 100644 index 0000000..e69de29 diff --git a/crates.js b/crates.js new file mode 100644 index 0000000..ae84c42 --- /dev/null +++ b/crates.js @@ -0,0 +1 @@ +window.ALL_CRATES = ["polyhal"]; \ No newline at end of file diff --git a/help.html b/help.html new file mode 100644 index 0000000..3ea2452 --- /dev/null +++ b/help.html @@ -0,0 +1 @@ +
#[repr(C)]pub struct PhysAddr(/* private fields */);
self
and other
) and is used by the <=
+operator. Read morepub struct PhysPage(/* private fields */);
self
and other
) and is used by the <=
+operator. Read morepub struct VirtAddr(/* private fields */);
self
and other
) and is used by the <=
+operator. Read morepub struct VirtPage(/* private fields */);
self
and other
) and is used by the <=
+operator. Read more#[arch_entry]
#[arch_interrupt]
pub const MULTI_CORE_AREA: usize = 0xFFFF_FFC2_0000_0000;
Every core has a unique area of memory. +Just using pagetable to map multi core area. +Area size: 0x100_0000 (16MBytes)
+First Area is 0xFFFF_FFC2_0000_0000 +Next Area is 0xFFFF_FFC2_0100_0000 +Others Same as This, so it will support 16 * 16 = 256 cores (Only auxiliary Harts).
+pub const MULTI_CORE_AREA_SIZE: usize = 0x100_0000;
pub const SIG_RETURN_ADDR: usize = 0xFFFF_FFC1_0000_0000;
pub const USER_VADDR_END: usize = PageTable::USER_VADDR_END; // 549_755_813_887usize
pub const VIRT_ADDR_START: usize = 0xffff_ffc0_0000_0000;
pub const STACK_SIZE: usize = 0x8_0000;
Boot Stack Size. +TODO: reduce the boot stack size. Map stack in boot step.
+pub const TRAPFRAME_SIZE: usize = _; // 288usize
The size of the trap frame(diffent in each architecture.).
+Redirecting to ../../../polyhal/constant.MULTI_CORE_AREA.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/consts/constant.MULTI_CORE_AREA_SIZE.html b/polyhal/currrent_arch/consts/constant.MULTI_CORE_AREA_SIZE.html new file mode 100644 index 0000000..a56cf91 --- /dev/null +++ b/polyhal/currrent_arch/consts/constant.MULTI_CORE_AREA_SIZE.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/constant.MULTI_CORE_AREA_SIZE.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/consts/constant.SIG_RETURN_ADDR.html b/polyhal/currrent_arch/consts/constant.SIG_RETURN_ADDR.html new file mode 100644 index 0000000..c2b19ca --- /dev/null +++ b/polyhal/currrent_arch/consts/constant.SIG_RETURN_ADDR.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/constant.SIG_RETURN_ADDR.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/consts/constant.VIRT_ADDR_START.html b/polyhal/currrent_arch/consts/constant.VIRT_ADDR_START.html new file mode 100644 index 0000000..d4d0b77 --- /dev/null +++ b/polyhal/currrent_arch/consts/constant.VIRT_ADDR_START.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/constant.VIRT_ADDR_START.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/context/struct.TrapFrame.html b/polyhal/currrent_arch/context/struct.TrapFrame.html new file mode 100644 index 0000000..b8e1efc --- /dev/null +++ b/polyhal/currrent_arch/context/struct.TrapFrame.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/struct.TrapFrame.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/entry/fn.kernel_page_table.html b/polyhal/currrent_arch/entry/fn.kernel_page_table.html new file mode 100644 index 0000000..4bccbc4 --- /dev/null +++ b/polyhal/currrent_arch/entry/fn.kernel_page_table.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/fn.kernel_page_table.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/entry/fn.switch_to_kernel_page_table.html b/polyhal/currrent_arch/entry/fn.switch_to_kernel_page_table.html new file mode 100644 index 0000000..d2d3964 --- /dev/null +++ b/polyhal/currrent_arch/entry/fn.switch_to_kernel_page_table.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/fn.switch_to_kernel_page_table.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/fn.arch_init.html b/polyhal/currrent_arch/fn.arch_init.html new file mode 100644 index 0000000..831aedc --- /dev/null +++ b/polyhal/currrent_arch/fn.arch_init.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../polyhal/fn.arch_init.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/fn.hart_id.html b/polyhal/currrent_arch/fn.hart_id.html new file mode 100644 index 0000000..ec890e1 --- /dev/null +++ b/polyhal/currrent_arch/fn.hart_id.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../polyhal/fn.hart_id.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/fn.wfi.html b/polyhal/currrent_arch/fn.wfi.html new file mode 100644 index 0000000..707f17f --- /dev/null +++ b/polyhal/currrent_arch/fn.wfi.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../polyhal/fn.wfi.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/interrupt/fn.disable_irq.html b/polyhal/currrent_arch/interrupt/fn.disable_irq.html new file mode 100644 index 0000000..984f84a --- /dev/null +++ b/polyhal/currrent_arch/interrupt/fn.disable_irq.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/fn.disable_irq.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/interrupt/fn.enable_external_irq.html b/polyhal/currrent_arch/interrupt/fn.enable_external_irq.html new file mode 100644 index 0000000..0be2c67 --- /dev/null +++ b/polyhal/currrent_arch/interrupt/fn.enable_external_irq.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/fn.enable_external_irq.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/interrupt/fn.enable_irq.html b/polyhal/currrent_arch/interrupt/fn.enable_irq.html new file mode 100644 index 0000000..c8ec189 --- /dev/null +++ b/polyhal/currrent_arch/interrupt/fn.enable_irq.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/fn.enable_irq.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/interrupt/fn.run_user_task.html b/polyhal/currrent_arch/interrupt/fn.run_user_task.html new file mode 100644 index 0000000..4c347a8 --- /dev/null +++ b/polyhal/currrent_arch/interrupt/fn.run_user_task.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/fn.run_user_task.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/interrupt/fn.run_user_task_forever.html b/polyhal/currrent_arch/interrupt/fn.run_user_task_forever.html new file mode 100644 index 0000000..7f25927 --- /dev/null +++ b/polyhal/currrent_arch/interrupt/fn.run_user_task_forever.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/fn.run_user_task_forever.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/kcontext/fn.context_switch.html b/polyhal/currrent_arch/kcontext/fn.context_switch.html new file mode 100644 index 0000000..1447ac8 --- /dev/null +++ b/polyhal/currrent_arch/kcontext/fn.context_switch.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/fn.context_switch.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/kcontext/fn.context_switch_pt.html b/polyhal/currrent_arch/kcontext/fn.context_switch_pt.html new file mode 100644 index 0000000..17ad13d --- /dev/null +++ b/polyhal/currrent_arch/kcontext/fn.context_switch_pt.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/fn.context_switch_pt.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/kcontext/fn.read_current_tp.html b/polyhal/currrent_arch/kcontext/fn.read_current_tp.html new file mode 100644 index 0000000..442ec41 --- /dev/null +++ b/polyhal/currrent_arch/kcontext/fn.read_current_tp.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/fn.read_current_tp.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/kcontext/struct.KContext.html b/polyhal/currrent_arch/kcontext/struct.KContext.html new file mode 100644 index 0000000..0d85e1c --- /dev/null +++ b/polyhal/currrent_arch/kcontext/struct.KContext.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/struct.KContext.html...
+ + + \ No newline at end of file diff --git a/polyhal/currrent_arch/sbi/fn.shutdown.html b/polyhal/currrent_arch/sbi/fn.shutdown.html new file mode 100644 index 0000000..c61bd41 --- /dev/null +++ b/polyhal/currrent_arch/sbi/fn.shutdown.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../../polyhal/fn.shutdown.html...
+ + + \ No newline at end of file diff --git a/polyhal/debug/index.html b/polyhal/debug/index.html new file mode 100644 index 0000000..abc2767 --- /dev/null +++ b/polyhal/debug/index.html @@ -0,0 +1,3 @@ +pub struct DebugConsole;
This is a console for debugging, +If you want to use this logging +You need to use like this:
+DebugConsole::putchar(b'3');
DebugConsole::getchar();
pub enum KContextArgs {
+ KSP,
+ KTP,
+ KPC,
+}
Kernel Context Arg Type.
+Using this by Index and IndexMut trait bound on KContext.
+Indexing operations for KContext
+Using it just like the Vector.
+#[derive(Debug)] +pub enum KContextArgs { +/// Kernel Stack Pointer +KSP, +/// Kernel Thread Pointer +KTP, +/// Kernel Program Counter +KPC +}
+etc. Get reg of the kernel stack:
+let ksp = KContextKContextArgs::KSP +let kpc = KContextKContextArgs::KPC +let ktp = KContextKContextArgs::KTP
+Indexing Mutable operations for KContext
+Using it just like the Vector.
+etc. Change the value of the kernel Context using IndexMut
+KContextKContextArgs::KSP = ksp; +KContextKContextArgs::KPC = kpc; +KContextKContextArgs::KTP = ktp;
+pub enum TrapFrameArgs {
+ SEPC,
+ RA,
+ SP,
+ RET,
+ ARG0,
+ ARG1,
+ ARG2,
+ TLS,
+ SYSCALL,
+}
Trap Frame Arg Type
+Using this by Index and IndexMut trait bound on TrapFrame
+pub enum TrapType {
+ Breakpoint,
+ UserEnvCall,
+ Time,
+ Unknown,
+ SupervisorExternal,
+ StorePageFault(usize),
+ LoadPageFault(usize),
+ InstructionPageFault(usize),
+ IllegalInstruction(usize),
+}
pub fn disable_irq()
pub fn enable_external_irq()
pub fn enable_irq()
pub fn get_cpu_num() -> usize
Get the number of cpus
+pub fn kernel_page_table() -> PageTable
pub extern "C" fn read_current_tp() -> usize
pub fn run_user_task_forever(context: &mut TrapFrame) -> !
pub fn switch_to_kernel_page_table()
This is a crate to help you supporting multiple platforms.
+If you want to use this crate, you should implement the following trait in your code.
+ +/// impl
+pub struct PageAllocImpl;
+
+impl PageAlloc for PageAllocImpl {
+ fn alloc(&self) -> PhysPage {
+ frame_alloc()
+ }
+
+ fn dealloc(&self, ppn: PhysPage) {
+ frame::frame_dealloc(ppn)
+ }
+}
+
+/// kernel interrupt
+#[polyhal::arch_interrupt]
+fn kernel_interrupt(ctx: &mut TrapFrame, trap_type: TrapType) {
+ // println!("trap_type @ {:x?} {:#x?}", trap_type, ctx);
+ match trap_type {
+ Breakpoint => return,
+ UserEnvCall => {
+ // jump to next instruction anyway
+ ctx.syscall_ok();
+ log::info!("Handle a syscall");
+ }
+ StorePageFault(_paddr) | LoadPageFault(_paddr) | InstructionPageFault(_paddr) => {
+ log::info!("page fault");
+ }
+ IllegalInstruction(_) => {
+ log::info!("illegal instruction");
+ }
+ Time => {
+ log::info!("Timer");
+ }
+ _ => {
+ log::warn!("unsuspended trap type: {:?}", trap_type);
+ }
+ }
+}
+
+#[polyhal::arch_entry]
+/// kernel main function, entry point.
+fn main(hartid: usize) {
+ if hartid != 0 {
+ return;
+ }
+
+ println!("[kernel] Hello, world!");
+ allocator::init_allocator();
+ logging::init(Some("trace"));
+ println!("init logging");
+
+ // Init page alloc for polyhal
+ polyhal::init(&PageAllocImpl);
+
+ polyhal::init_interrupt();
+
+ get_mem_areas().into_iter().for_each(|(start, size)| {
+ println!("init memory region {:#x} - {:#x}", start, start + size);
+ frame::add_frame_range(start, start + size);
+ });
+ panic!("end of rust_main!");
+}
+
The main(hardid: usize) is the entry point.
+You can find details in the example.
+In this crate you can find some interfaces to use. +These interfaces are classified into some structures.
+PhysPage: PhysicalPage And its associated functions.
+PhysAddr: PhysicalAddr And its associated functions.
+VirtPage: VirtualPage And its associated functions.
+VirtAddr: VirtualAddr And its associated functions.
+IRQ: Interrupt ReQuest management, includes enable and disable.
+Barrier: Memory barrier operations.
+MultiCore: MultiCore operations. Now only multicore::MultiCore::boot_all is available.
+PageTable: PageTable and its associated functions.
+MappingFlags: MappingFlags, This is an abstraction of pagetable flags.
+TLB: TLB operations.
+PageTableWrapper: PageTableWrapper. It will dealloc all pagetable leaf when it was dropping.
+Time: Time and its associated functions.
+Instruction: Some platform instruction.
+There also provides a debugging console(recommanded only for debugging).
+DebugConsole: A console for debugging.
+This crate provides a TrapFrame, you can operate it through index with TrapFrameArgs.
+If you are using kernel task. You should to enable feature kcontext
.
+Then you can use kernel task context structure KContext, and manipulate it with KContextArgs.
You can switch kcontext through context_switch_pt or context_switch
+There are also some consts.
+VIRT_ADDR_START: This is a higher half kernel offset address. +USER_VADDR_END: End of the user address range. +PAGE_SIZE: The size of the page.
+You can get some device information using the functions below. +get_mem_areas: Get the avaliable memorys. +get_fdt: Get the Fdt structure(fdt is a rust dtb operation crate). +get_cpu_num: Get the number of cpus.
+TIPS: You should have finished init before using get_mem_areas and get_fdt.
+pub use percpu;
pub struct Instruction;
Platform Instruction +Instruction::ebreak Intruction Breakpoint
+pub struct IRQ;
IRQ interface for exposing.
+TODO: Implement this interface.
+How to use this interface.
+ +// Init irq
+IRQ::init();
+
+// Enable irq 3
+IRQ::enable(3);
+
+// Disable irq 3
+IRQ::disable(3);
+
+// Check if irq is enabled
+// Return true if the irq is enabled.
+IRQ::enabled(3);
+
pub struct Barrier;
This is a barrier function.
+This struct has two functions.
+Barrier::complete_sync
: ensures the correct sequencing of instructions
+Barrier::ordering_sync
: ensures the visibility and consistency of memory operations
pub struct MultiCore;
This is a leader for the multicore operation
+You can use this function to use the multicore operation
+Boot other calls after the multicore +If you use this function call, you should call it after arch::init(..); +This function will allocate the stack and map it for itself.
+ +Multicore::boot_all();
Here will have more functionality about multicore in the future.
+pub struct LazyInit<T> { /* private fields */ }
Must be called after initialization.
+Must be called after initialization.
+pub enum MappingSize {
+ Page4KB,
+}
This structure indicates size of the page that will be mapped.
+TODO: Support More Page Size, 16KB or 32KB +Just support 4KB right now.
+pub struct MappingFlags(/* private fields */);
Mapping flags for page table.
+Get the underlying bits value.
+The returned value is exactly the bits set in this flags value.
+Convert from a bits value.
+This method will return None
if any unknown bits are set.
Convert from a bits value, unsetting any unknown bits.
+Convert from a bits value exactly.
+Get a flags value with the bits of a flag with the given name set.
+This method will return None
if name
is empty or doesn’t
+correspond to any named flag.
Whether any set bits in a source flags value are also set in a target flags value.
+Whether all set bits in a source flags value are also set in a target flags value.
+The intersection of a source flags value with the complement of a target flags value (&!
).
This method is not equivalent to self & !other
when other
has unknown bits set.
+remove
won’t truncate other
, but the !
operator will.
The bitwise exclusive-or (^
) of the bits in two flags values.
Call insert
when value
is true
or remove
when value
is false
.
The bitwise and (&
) of the bits in two flags values.
The bitwise or (|
) of the bits in two flags values.
The intersection of a source flags value with the complement of a target flags value (&!
).
This method is not equivalent to self & !other
when other
has unknown bits set.
+difference
won’t truncate other
, but the !
operator will.
The bitwise exclusive-or (^
) of the bits in two flags values.
The bitwise negation (!
) of the bits in a flags value, truncating the result.
Yield a set of contained flags values.
+Each yielded flags value will correspond to a defined named flag. Any unknown bits +will be yielded together as a final flags value.
+Yield a set of contained named flags values.
+This method is like iter
, except only yields bits in contained named flags.
+Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
The bitwise and (&
) of the bits in two flags values.
The bitwise or (|
) of the bits in two flags values.
|
operator.The bitwise or (|
) of the bits in two flags values.
The bitwise exclusive-or (^
) of the bits in two flags values.
source
. Read moreThe bitwise or (|
) of the bits in each flags value.
extend_one
)extend_one
)|
) of the bits in two flags values.&!
). Read more^
) of the bits in two flags values.Flags::insert
] when value
is true
or [Flags::remove
] when value
is false
.&
) of the bits in two flags values.&!
). Read more^
) of the bits in two flags values.!
) of the bits in a flags value, truncating the result.The bitwise or (|
) of the bits in each flags value.
self
and other
values to be equal, and is used
+by ==
.self
and other
) and is used by the <=
+operator. Read moreThe intersection of a source flags value with the complement of a target flags value (&!
).
This method is not equivalent to self & !other
when other
has unknown bits set.
+difference
won’t truncate other
, but the !
operator will.
-
operator.The intersection of a source flags value with the complement of a target flags value (&!
).
This method is not equivalent to self & !other
when other
has unknown bits set.
+difference
won’t truncate other
, but the !
operator will.
#[repr(C)]pub struct PageTable(/* private fields */);
Page Table
+This is just the page table defination. +The implementation of the page table in the specific architecture mod. +Such as: +x86_64/page_table.rs +riscv64/page_table/sv39.rs +aarch64/page_table.rs +loongarch64/page_table.rs
+Mapping a page to specific virtual page (user space address).
+Ensure that PageTable is which you want to map. +vpn: Virtual page will be mapped. +ppn: Physical page. +flags: Mapping flags, include Read, Write, Execute and so on. +size: MappingSize. Just support 4KB page currently.
+Mapping a page to specific address(kernel space address).
+TODO: This method is not implemented. +TIPS: If we mapped to kernel, the page will be shared between different pagetable.
+Ensure that PageTable is which you want to map. +vpn: Virtual page will be mapped. +ppn: Physical page. +flags: Mapping flags, include Read, Write, Execute and so on. +size: MappingSize. Just support 4KB page currently.
+How to implement shared.
+Unmap a page from specific virtual page (user space address).
+Ensure the virtual page is exists. +vpn: Virtual address.
+Translate a virtual adress to a physical address and mapping flags.
+Return None if the vaddr isn’t mapped. +vpn: The virtual address will be translated.
+Release the page table entry.
+The page table entry in the user space address will be released. +Page Table Wikipedia. +You don’t need to care about this if you just want to use.
+pub struct PageTableWrapper(pub PageTable);
Page Table Wrapper
+You can use this wrapper to packing PageTable. +If you release the PageTableWrapper, +the PageTable will release its page table entry.
+0: PageTable
Allocate a new PageTableWrapper with new page table root
+This operation will restore the page table.
+Mapping a page to specific virtual page (user space address).
+Ensure that PageTable is which you want to map. +vpn: Virtual page will be mapped. +ppn: Physical page. +flags: Mapping flags, include Read, Write, Execute and so on. +size: MappingSize. Just support 4KB page currently.
+Mapping a page to specific address(kernel space address).
+TODO: This method is not implemented. +TIPS: If we mapped to kernel, the page will be shared between different pagetable.
+Ensure that PageTable is which you want to map. +vpn: Virtual page will be mapped. +ppn: Physical page. +flags: Mapping flags, include Read, Write, Execute and so on. +size: MappingSize. Just support 4KB page currently.
+How to implement shared.
+Unmap a page from specific virtual page (user space address).
+Ensure the virtual page is exists. +vpn: Virtual address.
+Translate a virtual adress to a physical address and mapping flags.
+Return None if the vaddr isn’t mapped. +vpn: The virtual address will be translated.
+Release the page table entry.
+The page table entry in the user space address will be released. +Page Table Wikipedia. +You don’t need to care about this if you just want to use.
+pub struct TLB;
TLB Operation set. +Such as flush_vaddr, flush_all. +Just use it in the fn.
+there are some methods in the TLB implementation
+TLB::flush_vaddr(arg0); arg0 should be VirtAddr
TLB::flush_all();
#[repr(C)]pub struct KContext { /* private fields */ }
Kernel Context
+Kernel Context is used to switch context between kernel task.
+Indexing operations for KContext
+Using it just like the Vector.
+#[derive(Debug)] +pub enum KContextArgs { +/// Kernel Stack Pointer +KSP, +/// Kernel Thread Pointer +KTP, +/// Kernel Program Counter +KPC +}
+etc. Get reg of the kernel stack:
+let ksp = KContextKContextArgs::KSP +let kpc = KContextKContextArgs::KPC +let ktp = KContextKContextArgs::KTP
+Indexing Mutable operations for KContext
+Using it just like the Vector.
+etc. Change the value of the kernel Context using IndexMut
+KContextKContextArgs::KSP = ksp; +KContextKContextArgs::KPC = kpc; +KContextKContextArgs::KTP = ktp;
+#[repr(C)]pub struct TrapFrame {
+ pub x: [usize; 32],
+ pub sstatus: Sstatus,
+ pub sepc: usize,
+ pub fsx: [usize; 2],
+}
x: [usize; 32]
§sstatus: Sstatus
§sepc: usize
§fsx: [usize; 2]
pub struct Time(/* private fields */);
Time struct and its interface
+You can use this to get time from ticks
+Time::now();
Time::get_freq();
Time::now().to_nsec();
Time::now().to_usec();
Time::now().to_msec();
Time::now().raw();
Time::from_raw(Time::now().raw());
U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","","","","","","","","","","Return Some(()) if it was interrupt by syscall, otherwise …","","","调用 SBI_SHUTDOWN 来关闭操作系统(直接退出 …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","","","Returns the argument unchanged.","Returns the argument unchanged.","","","Returns the argument unchanged.","","","","","","","","","","","","","","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","","","","","","","","","Get n level page table index of the given virtual address","Get n level page table offset of the given virtual address","","","","","","","","","","","","","","","","","","","","","","","","","","","","Boot Stack Size. TODO: reduce the boot stack size. Map …","The size of the trap frame(diffent in each architecture.).","This is a console for debugging, If you want to use this …","","","Returns the argument unchanged.","","Calls U::from(self)
.","","","","","","Platform Instruction Instruction::ebreak Intruction …","","","","Returns the argument unchanged.","Calls U::from(self)
.","","","","IRQ interface for exposing.","","","Returns the argument unchanged.","Calls U::from(self)
.","","","","This is a barrier function.","","","","Returns the argument unchanged.","Calls U::from(self)
.","","","","","This is a leader for the multicore operation","Boot all application cores.","","","Returns the argument unchanged.","Calls U::from(self)
.","","","","","","","","","","","Returns the argument unchanged.","Safety","Safety","","Calls U::from(self)
.","","","","","","","Accessed Flag","Cache Flag, indicating that the page will be cached","Dirty Flag, indicating that the page was written","Device Flag, indicating that the page was used for device …","Global Flag","Mapping flags for page table.","This structure indicates size of the page that will be …","Persent","","Page Table","Page Table Wrapper","Readable Flag","Read | Write | Executeable Flags","TLB Operation set. Such as flush_vaddr, flush_all. Just …","User Accessable Flag","User | Read | Write Flags","User | Read | Write | Executeable Flags","User | Read | Executeable Flags","Writeable Flag","Executeable Flag","Get a flags value with all known bits set.","Alloc a new PageTableWrapper with new page table root This …","The bitwise and (&
) of the bits in two flags values.","The bitwise and (&
) of the bits in two flags values.","The bitwise or (|
) of the bits in two flags values.","The bitwise or (|
) of the bits in two flags values.","Get the underlying bits value.","","The bitwise exclusive-or (^
) of the bits in two flags …","The bitwise exclusive-or (^
) of the bits in two flags …","","","","","","","","","","","","","","","","","The bitwise negation (!
) of the bits in a flags value, …","Whether all set bits in a source flags value are also set …","","","The intersection of a source flags value with the …","","Get a flags value with all bits unset.","","The bitwise or (|
) of the bits in each flags value.","flush all tlb entry","flush the TLB entry by VirtualAddress just use it directly","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Convert from a bits value.","Convert from a bits value exactly.","","Convert from a bits value, unsetting any unknown bits.","The bitwise or (|
) of the bits in each flags value.","Get a flags value with the bits of a flag with the given …","","The bitwise or (|
) of the bits in two flags values.","The bitwise and (&
) of the bits in two flags values.","Whether any set bits in a source flags value are also set …","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","","Whether all known bits in this flags value are set.","Whether all bits in this flags value are unset.","Yield a set of contained flags values.","Yield a set of contained named flags values.","","Mapping a page to specific address(kernel space address).","Mapping a page to specific virtual page (user space …","The bitwise negation (!
) of the bits in a flags value, …","","Release the page table entry.","The intersection of a source flags value with the …","","Call insert
when value
is true
or remove
when value
is …","The intersection of a source flags value with the …","The intersection of a source flags value with the …","The bitwise exclusive-or (^
) of the bits in two flags …","","","The bitwise exclusive-or (^
) of the bits in two flags …","Translate a virtual adress to a physical address and …","","","","","","","","","","","","","","","","The bitwise or (|
) of the bits in two flags values.","Unmap a page from specific virtual page (user space …","Time struct and its interface","","","","","","Returns the argument unchanged.","","","Calls U::from(self)
.","","","","Converts hardware ticks to nanoseconds.","","","","",""],"i":[13,13,13,8,8,8,0,0,12,12,12,8,0,0,0,0,13,13,13,0,13,13,8,8,13,8,0,0,0,0,8,8,0,0,1,0,0,0,0,4,7,4,7,12,13,8,4,7,12,13,8,4,8,4,8,0,0,0,1,0,0,0,0,4,7,12,13,8,4,7,12,13,8,4,0,0,0,0,4,7,4,7,0,0,4,7,12,13,8,0,0,0,0,4,0,0,0,0,0,0,4,0,4,0,4,0,4,8,4,7,12,13,8,4,7,12,13,8,4,7,12,13,8,0,4,0,0,0,0,2,2,20,21,22,2,21,22,2,20,21,22,2,20,22,21,22,2,20,21,22,2,20,21,22,2,20,2,2,21,22,2,20,22,21,21,22,22,2,2,20,20,21,21,22,22,22,2,2,2,20,20,20,2,20,2,21,22,21,22,22,21,22,22,21,22,2,20,21,22,2,20,21,22,2,20,20,22,21,22,22,21,22,2,20,21,22,2,20,21,22,2,20,21,22,2,20,21,22,2,20,21,22,2,20,0,0,0,29,29,29,29,29,29,29,29,29,29,0,43,43,43,43,43,43,43,43,0,44,44,44,44,44,44,44,0,45,45,45,45,45,45,45,45,45,0,46,46,46,46,46,46,46,46,0,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,33,33,33,33,33,0,0,33,38,0,0,33,33,0,33,33,33,33,33,33,33,34,33,33,33,33,33,33,33,33,47,33,38,9,34,47,33,38,9,34,9,33,9,33,9,33,33,33,9,34,33,34,33,33,33,47,47,33,33,33,33,33,38,9,34,47,33,38,9,34,33,33,33,33,33,33,33,33,33,33,47,33,38,9,34,33,33,33,33,33,9,9,9,33,33,9,33,9,33,33,33,33,33,9,33,9,47,33,38,9,34,47,33,38,9,34,47,33,38,9,34,33,9,0,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42],"f":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[1,2],0,0,[[],3],0,[4,[[6,[5]]]],[[],7],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[4,4],[8,8],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],0,[[7,7],3],[[7,7,9],3],[[1,2],3],0,[[],3],[[],3],[[],3],[[4,10],11],[[7,10],11],[[12,10],11],[[13,10],11],[[8,10],11],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],0,[[],5],[[],[[15,[14]]]],[[],[[16,[[3,[5,5]]]]]],[[],5],[[4,13],-1,[]],[[7,12],-1,[]],[[4,13],-1,[]],[[7,12],-1,[]],[1,3],0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,[[],9],0,0,[[],4],0,0,0,[[],5],[4,[[15,[3]]]],[4,17],0,[[],17],0,[[],3],[4,3],0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,19,[]],[-1,19,[]],[-1,19,[]],[-1,19,[]],[-1,19,[]],[[],3],0,0,0,0,0,[[2,2],-1,[]],[[2,5],-1,[]],[[20,5],-1,[]],[21,5],[22,5],[2,5],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[22,22],[21,21],[22,22],[2,2],[20,20],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[21,21],23],[[22,22],23],[[2,2],23],[[20,20],23],[[2,2],3],[2,3],[[21,21],24],[[22,22],24],[[2,2],24],[[20,20],24],[22,22],[[21,10],11],[[21,10],11],[[22,10],11],[[22,10],11],[[2,10],11],[[2,10],11],[[20,10],11],[[20,10],11],[2,21],[-1,-1,[]],[20,22],[5,22],[-1,-1,[]],[-1,-1,[]],[5,2],[21,2],[-1,-1,[]],[22,20],[5,20],[5,2],[5,20],[2,[[26,[25]]]],[21,27],[22,27],[21],[22],[22,-1,[]],[21],[22],[22,-1,[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[5,21],[5,22],[5,2],[5,20],[[21,21],[[15,[23]]]],[[22,22],[[15,[23]]]],[[2,2],[[15,[23]]]],[[20,20],[[15,[23]]]],[[20,5],5],[[22,5],5],[[21,5],[[26,[-1]]],[]],[[22,5],[[26,[-1]]],[]],[22,[[26,[-1]]],[]],[[21,5],[[26,[-1]]],[]],[[22,5],[[26,[-1]]],[]],[2,5],[20,5],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,28,[]],[-1,28,[]],[-1,28,[]],[-1,28,[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,19,[]],[-1,19,[]],[-1,19,[]],[-1,19,[]],0,0,0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-1,[]],[[],[[15,[25]]]],[-1,-2,[],[]],[25,3],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,19,[]],[[29,30],11],0,[-1,-2,[],[]],[-1,-2,[],[]],[[],3],[-1,-1,[]],[-1,-2,[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,19,[]],0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-1,[]],[-1,-2,[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,19,[]],0,[-1,-2,[],[]],[-1,-2,[],[]],[[],3],[-1,-1,[]],[-1,-2,[],[]],[[],3],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,19,[]],0,[[],3],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-1,[]],[-1,-2,[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,19,[]],0,[-1,-2,[],[]],[-1,-2,[],[]],[[[31,[-1]]],-1,[]],[[[31,[-1]]],-1,[]],[[[31,[-1]]],3,[]],[[[31,[-1]],10],11,32],[-1,-1,[]],[[[31,[-1]]],-1,[]],[[[31,[-1]]],-1,[]],[[[31,[-1]],-1],3,[]],[-1,-2,[],[]],[[[31,[-1]]],24,[]],[[],[[31,[-1]]],[]],[-1,[[18,[-2]]],[],[]],[[[31,[-1]]],[[15,[-1]]],[]],[-1,[[18,[-2]]],[],[]],[-1,19,[]],0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[[],33],[[],34],[[33,33],33],[[33,33],3],[[33,33],33],[[33,33],3],[33,35],[33,35],[[33,33],33],[[33,33],3],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[9,3],[33,33],[9,9],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[33,33],23],[33,33],[[33,33],24],[[],9],[34,-1,[]],[[33,33],33],[34,3],[[],33],[[33,33],24],[[33,-1],3,[[37,[],[[36,[33]]]]]],[[],3],[22,3],[[33,10],11],[[33,10],11],[[33,10],11],[[33,10],11],[[33,10],11],[[38,10],11],[[9,10],11],[[34,10],11],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[35,[[15,[33]]]],[35,33],[35,33],[35,33],[-1,33,[[37,[],[[36,[33]]]]]],[30,[[15,[33]]]],[[33,-1],3,39],[[33,33],3],[[33,33],33],[[33,33],24],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[33,-1,[]],[33,24],[33,24],[33,[[40,[33]]]],[33,[[41,[33]]]],[9,21],[[9,20,2,33,38],3],[[9,20,2,33,38],3],[33,33],[[33,33],[[15,[23]]]],[9,3],[[33,33],3],[9,3],[[33,33,24],3],[[33,33],33],[[33,33],3],[[33,33],33],[-1,-2,[],[]],[-1,-2,[],[]],[[33,33],3],[[9,22],[[15,[[3,[21,33]]]]]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,19,[]],[-1,19,[]],[-1,19,[]],[-1,19,[]],[-1,19,[]],[[33,33],33],[[9,20],3],0,[-1,-2,[],[]],[-1,-2,[],[]],[42,42],[[-1,-2],3,[],[]],[[42,10],11],[-1,-1,[]],[5,42],[[],5],[-1,-2,[],[]],[[],42],[42,5],[42,5],[42,5],[-1,-2,[],[]],[42,5],[-1,[[18,[-2]]],[],[]],[-1,[[18,[-2]]],[],[]],[-1,19,[]]],"c":[],"p":[[10,"PageAlloc",0],[5,"PhysPage",125],[1,"tuple"],[5,"TrapFrame",0],[1,"usize"],[1,"array"],[5,"KContext",0],[6,"TrapType",0],[5,"PageTable",301],[5,"Formatter",443],[8,"Result",443],[6,"KContextArgs",0],[6,"TrapFrameArgs",0],[5,"Fdt",444],[6,"Option",445],[5,"Vec",446],[1,"never"],[6,"Result",447],[5,"TypeId",448],[5,"VirtPage",125],[5,"PhysAddr",125],[5,"VirtAddr",125],[6,"Ordering",449],[1,"bool"],[1,"u8"],[1,"slice"],[5,"CStr",450],[5,"String",451],[5,"DebugConsole",236],[1,"str"],[5,"LazyInit",283],[10,"Debug",443],[5,"MappingFlags",301],[5,"PageTableWrapper",301],[1,"u64"],[17,"Item"],[10,"IntoIterator",452],[6,"MappingSize",301],[10,"Hasher",453],[5,"Iter",454],[5,"IterNames",454],[5,"Time",424],[5,"Instruction",247],[5,"IRQ",256],[5,"Barrier",264],[5,"MultiCore",274],[5,"TLB",301]],"b":[[129,"impl-Add-for-PhysPage"],[130,"impl-Add%3Cusize%3E-for-PhysPage"],[163,"impl-Display-for-PhysAddr"],[164,"impl-Debug-for-PhysAddr"],[165,"impl-Debug-for-VirtAddr"],[166,"impl-Display-for-VirtAddr"],[167,"impl-Debug-for-PhysPage"],[168,"impl-Display-for-PhysPage"],[169,"impl-Display-for-VirtPage"],[170,"impl-Debug-for-VirtPage"],[173,"impl-From%3CVirtPage%3E-for-VirtAddr"],[174,"impl-From%3Cusize%3E-for-VirtAddr"],[177,"impl-From%3Cusize%3E-for-PhysPage"],[178,"impl-From%3CPhysAddr%3E-for-PhysPage"],[180,"impl-From%3CVirtAddr%3E-for-VirtPage"],[181,"impl-From%3Cusize%3E-for-VirtPage"],[327,"impl-MappingFlags"],[328,"impl-Flags-for-MappingFlags"],[358,"impl-Octal-for-MappingFlags"],[359,"impl-LowerHex-for-MappingFlags"],[360,"impl-UpperHex-for-MappingFlags"],[361,"impl-Debug-for-MappingFlags"],[362,"impl-Binary-for-MappingFlags"],[372,"impl-MappingFlags"],[373,"impl-Flags-for-MappingFlags"]]}\
+}');
+if (typeof window !== 'undefined' && window.initSearch) {window.initSearch(searchIndex)};
+if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
diff --git a/settings.html b/settings.html
new file mode 100644
index 0000000..b9f4de7
--- /dev/null
+++ b/settings.html
@@ -0,0 +1 @@
+1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +
use core::{
+ ffi::CStr,
+ fmt::{Debug, Display},
+ mem::size_of,
+ ops::Add,
+};
+
+use crate::{pagetable::PageTable, VIRT_ADDR_START};
+
+#[repr(C)]
+#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
+pub struct PhysAddr(pub(crate) usize);
+impl From<PhysPage> for PhysAddr {
+ fn from(value: PhysPage) -> Self {
+ Self(value.0 << 12)
+ }
+}
+
+impl PhysAddr {
+ #[inline]
+ pub fn addr(&self) -> usize {
+ self.0
+ }
+
+ #[inline]
+ pub fn get_ptr<T>(&self) -> *const T {
+ (self.0 | VIRT_ADDR_START) as *const T
+ }
+
+ #[inline]
+ pub const fn get_mut_ptr<T>(&self) -> *mut T {
+ (self.0 | VIRT_ADDR_START) as *mut T
+ }
+
+ #[inline]
+ pub fn slice_with_len<T>(&self, len: usize) -> &'static [T] {
+ unsafe { core::slice::from_raw_parts(self.get_ptr(), len) }
+ }
+
+ #[inline]
+ pub fn slice_mut_with_len<T>(&self, len: usize) -> &'static mut [T] {
+ unsafe { core::slice::from_raw_parts_mut(self.get_mut_ptr(), len) }
+ }
+
+ #[inline]
+ pub fn get_cstr(&self) -> &CStr {
+ unsafe { CStr::from_ptr(self.get_ptr::<i8>()) }
+ }
+}
+
+#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
+pub struct VirtAddr(pub(crate) usize);
+
+impl From<usize> for VirtAddr {
+ fn from(value: usize) -> Self {
+ Self(value)
+ }
+}
+
+impl From<VirtAddr> for usize {
+ fn from(value: VirtAddr) -> Self {
+ value.0
+ }
+}
+
+impl VirtAddr {
+ #[inline]
+ pub fn addr(&self) -> usize {
+ self.0
+ }
+
+ #[inline]
+ pub fn get_ptr<T>(&self) -> *const T {
+ self.0 as *const T
+ }
+
+ #[inline]
+ pub fn get_mut_ptr<T>(&self) -> *mut T {
+ self.0 as *mut T
+ }
+
+ #[inline]
+ pub fn get_ref<T>(&self) -> &'static T {
+ unsafe { &*(self.0 as *const T) }
+ }
+
+ #[inline]
+ pub fn get_mut_ref<T>(&self) -> &'static mut T {
+ unsafe { &mut *(self.0 as *mut T) }
+ }
+
+ #[inline]
+ pub fn slice_with_len<T>(&self, len: usize) -> &'static [T] {
+ unsafe { core::slice::from_raw_parts(self.get_ptr(), len) }
+ }
+
+ #[inline]
+ pub fn slice_mut_with_len<T>(&self, len: usize) -> &'static mut [T] {
+ unsafe { core::slice::from_raw_parts_mut(self.get_mut_ptr(), len) }
+ }
+
+ #[inline]
+ pub fn slice_until<T>(&self, is_valid: fn(T) -> bool) -> &'static mut [T] {
+ let ptr = self.addr() as *mut T;
+ unsafe {
+ let mut len = 0;
+ if !ptr.is_null() {
+ loop {
+ if !is_valid(ptr.add(len).read()) {
+ break;
+ }
+ len += 1;
+ }
+ }
+ core::slice::from_raw_parts_mut(ptr, len)
+ }
+ }
+
+ #[inline]
+ pub fn get_cstr(&self) -> &CStr {
+ unsafe { CStr::from_ptr(self.get_ptr::<i8>()) }
+ }
+
+ #[inline]
+ pub fn floor(&self) -> Self {
+ Self(self.0 / PageTable::PAGE_SIZE * PageTable::PAGE_SIZE)
+ }
+
+ #[inline]
+ pub fn ceil(&self) -> Self {
+ Self((self.0 + PageTable::PAGE_SIZE - 1) / PageTable::PAGE_SIZE * PageTable::PAGE_SIZE)
+ }
+}
+
+#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
+pub struct PhysPage(pub(crate) usize);
+
+impl From<usize> for PhysPage {
+ fn from(value: usize) -> Self {
+ Self(value)
+ }
+}
+
+impl From<PhysAddr> for PhysPage {
+ fn from(value: PhysAddr) -> Self {
+ Self(value.0 >> 12)
+ }
+}
+
+impl From<PhysPage> for usize {
+ fn from(value: PhysPage) -> Self {
+ value.0
+ }
+}
+
+impl Add<PhysPage> for PhysPage {
+ type Output = PhysPage;
+
+ fn add(self, rhs: PhysPage) -> Self::Output {
+ PhysPage(self.0 + rhs.0)
+ }
+}
+
+impl Add<usize> for PhysPage {
+ type Output = PhysPage;
+
+ fn add(self, rhs: usize) -> Self::Output {
+ PhysPage(self.0 + rhs)
+ }
+}
+
+#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
+pub struct VirtPage(pub(crate) usize);
+impl From<VirtAddr> for VirtPage {
+ fn from(value: VirtAddr) -> Self {
+ Self(value.0 >> 12)
+ }
+}
+impl From<usize> for VirtPage {
+ fn from(value: usize) -> Self {
+ Self(value)
+ }
+}
+
+impl PhysPage {
+ #[inline]
+ pub const fn new(ppn: usize) -> Self {
+ Self(ppn)
+ }
+
+ #[inline]
+ pub const fn from_addr(addr: usize) -> Self {
+ Self(addr >> 12)
+ }
+
+ #[inline]
+ pub const fn to_addr(&self) -> usize {
+ self.0 << 12
+ }
+
+ #[inline]
+ pub const fn get_buffer(&self) -> &'static mut [u8] {
+ unsafe {
+ core::slice::from_raw_parts_mut(
+ (self.0 << 12 | VIRT_ADDR_START) as *mut u8,
+ PageTable::PAGE_SIZE,
+ )
+ }
+ }
+
+ #[inline]
+ pub fn copy_value_from_another(&self, ppn: PhysPage) {
+ self.get_buffer().copy_from_slice(&ppn.get_buffer());
+ #[cfg(c906)]
+ unsafe {
+ asm!(".long 0x0010000b"); // dcache.all
+ asm!(".long 0x01b0000b"); // sync.is
+ }
+ #[cfg(board = "2k1000")]
+ unsafe {
+ core::arch::asm!("dbar 0;ibar 0;")
+ }
+ }
+
+ #[inline]
+ pub fn drop_clear(&self) {
+ // self.get_buffer().fill(0);
+ unsafe {
+ core::slice::from_raw_parts_mut(
+ (self.0 << 12 | VIRT_ADDR_START) as *mut usize,
+ PageTable::PAGE_SIZE / size_of::<usize>(),
+ )
+ .fill(0);
+ }
+ #[cfg(board = "2k1000")]
+ unsafe {
+ core::arch::asm!("dbar 0;ibar 0;")
+ }
+ #[cfg(c906)]
+ unsafe {
+ asm!(".long 0x0010000b"); // dcache.all
+ asm!(".long 0x01b0000b"); // sync.is
+ }
+ }
+
+ #[inline]
+ pub fn as_num(&self) -> usize {
+ self.0
+ }
+}
+
+impl Add<usize> for VirtPage {
+ type Output = VirtPage;
+
+ fn add(self, rhs: usize) -> Self::Output {
+ VirtPage(self.0 + rhs)
+ }
+}
+
+impl From<VirtPage> for VirtAddr {
+ fn from(value: VirtPage) -> Self {
+ Self(value.to_addr())
+ }
+}
+
+impl PhysAddr {
+ #[inline]
+ pub const fn new(addr: usize) -> Self {
+ Self(addr)
+ }
+}
+
+impl VirtPage {
+ #[inline]
+ pub const fn new(vpn: usize) -> Self {
+ Self(vpn)
+ }
+
+ #[inline]
+ pub const fn from_addr(addr: usize) -> Self {
+ Self(addr >> 12)
+ }
+ #[inline]
+ pub const fn to_addr(&self) -> usize {
+ self.0 << 12
+ }
+}
+
+impl VirtAddr {
+ #[inline]
+ pub const fn new(addr: usize) -> Self {
+ Self(addr)
+ }
+}
+
+impl Display for PhysPage {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.write_fmt(format_args!("{:#x}", self.0))
+ }
+}
+
+impl Display for PhysAddr {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.write_fmt(format_args!("{:#x}", self.0))
+ }
+}
+
+impl Display for VirtPage {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.write_fmt(format_args!("{:#x}", self.0))
+ }
+}
+
+impl Display for VirtAddr {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.write_fmt(format_args!("{:#x}", self.0))
+ }
+}
+
+impl Debug for PhysPage {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.write_fmt(format_args!("{:#x}", self.0))
+ }
+}
+
+impl Debug for PhysAddr {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.write_fmt(format_args!("{:#x}", self.0))
+ }
+}
+
+impl Debug for VirtPage {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.write_fmt(format_args!("{:#x}", self.0))
+ }
+}
+
+impl Debug for VirtAddr {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.write_fmt(format_args!("{:#x}", self.0))
+ }
+}
+
use crate::addr::PhysPage;
+use crate::{TrapFrame, TrapType, PAGE_ALLOC};
+
+extern "Rust" {
+ pub(crate) fn _main_for_arch(hartid: usize);
+ pub(crate) fn _interrupt_for_arch(ctx: &mut TrapFrame, trap_type: TrapType);
+}
+
+/// alloc a persistent memory page
+#[inline]
+pub(crate) fn frame_alloc() -> PhysPage {
+ PAGE_ALLOC.alloc()
+}
+
+/// release a frame
+#[inline]
+pub(crate) fn frame_dealloc(ppn: PhysPage) {
+ PAGE_ALLOC.dealloc(ppn)
+}
+
use core::mem::size_of;
+
+use crate::TrapFrame;
+
+/// Boot Stack Size.
+/// TODO: reduce the boot stack size. Map stack in boot step.
+pub const STACK_SIZE: usize = 0x8_0000;
+
+/// The size of the trap frame(diffent in each architecture.).
+pub const TRAPFRAME_SIZE: usize = size_of::<TrapFrame>();
+
+/// bit macro will generate the number through a shift value.
+///
+/// Here is an example.
+/// You can use bit!(0) instead of 1 << 0.
+/// bit!(39) instead of 1 << 39.
+macro_rules! bit {
+ ($x:expr) => {
+ 1 << $x
+ };
+}
+
use core::fmt::Write;
+
+/// This is a console for debugging,
+/// If you want to use this logging
+/// You need to use like this:
+///
+/// #### Put a char to output device(always uart)
+/// ```rust
+/// DebugConsole::putchar(b'3');
+/// ```
+///
+/// ### Get a char from input device(always uart)
+/// ```rust
+/// DebugConsole::getchar();
+/// ```
+pub struct DebugConsole;
+
+// Write string through DebugConsole
+impl Write for DebugConsole {
+ fn write_str(&mut self, s: &str) -> core::fmt::Result {
+ s.as_bytes().into_iter().for_each(|x| Self::putchar(*x));
+ Ok(())
+ }
+}
+
/// IRQ interface for exposing.
+///
+/// TODO: Implement this interface.
+///
+/// How to use this interface.
+/// ```rust
+/// // Init irq
+/// IRQ::init();
+///
+/// // Enable irq 3
+/// IRQ::enable(3);
+///
+/// // Disable irq 3
+/// IRQ::disable(3);
+///
+/// // Check if irq is enabled
+/// // Return true if the irq is enabled.
+/// IRQ::enabled(3);
+///
+/// ```
+pub struct IRQ;
+
+impl IRQ {}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +
#![no_std]
+#![no_main]
+#![feature(naked_functions)]
+#![feature(asm_const)]
+#![feature(stdsimd)]
+#![feature(const_mut_refs)]
+#![feature(const_slice_from_raw_parts_mut)]
+#![cfg_attr(target_arch = "riscv64", feature(riscv_ext_intrinsics))]
+#![cfg_attr(target_arch = "aarch64", feature(const_option))]
+
+//! This is a crate to help you supporting multiple platforms.
+//!
+//! If you want to use this crate, you should implement the following trait in your code.
+//!
+//! ```rust
+//! /// impl
+//! pub struct PageAllocImpl;
+//!
+//! impl PageAlloc for PageAllocImpl {
+//! fn alloc(&self) -> PhysPage {
+//! frame_alloc()
+//! }
+//!
+//! fn dealloc(&self, ppn: PhysPage) {
+//! frame::frame_dealloc(ppn)
+//! }
+//! }
+//!
+//! /// kernel interrupt
+//! #[polyhal::arch_interrupt]
+//! fn kernel_interrupt(ctx: &mut TrapFrame, trap_type: TrapType) {
+//! // println!("trap_type @ {:x?} {:#x?}", trap_type, ctx);
+//! match trap_type {
+//! Breakpoint => return,
+//! UserEnvCall => {
+//! // jump to next instruction anyway
+//! ctx.syscall_ok();
+//! log::info!("Handle a syscall");
+//! }
+//! StorePageFault(_paddr) | LoadPageFault(_paddr) | InstructionPageFault(_paddr) => {
+//! log::info!("page fault");
+//! }
+//! IllegalInstruction(_) => {
+//! log::info!("illegal instruction");
+//! }
+//! Time => {
+//! log::info!("Timer");
+//! }
+//! _ => {
+//! log::warn!("unsuspended trap type: {:?}", trap_type);
+//! }
+//! }
+//! }
+//!
+//! #[polyhal::arch_entry]
+//! /// kernel main function, entry point.
+//! fn main(hartid: usize) {
+//! if hartid != 0 {
+//! return;
+//! }
+//!
+//! println!("[kernel] Hello, world!");
+//! allocator::init_allocator();
+//! logging::init(Some("trace"));
+//! println!("init logging");
+//!
+//! // Init page alloc for polyhal
+//! polyhal::init(&PageAllocImpl);
+//!
+//! polyhal::init_interrupt();
+//!
+//! get_mem_areas().into_iter().for_each(|(start, size)| {
+//! println!("init memory region {:#x} - {:#x}", start, start + size);
+//! frame::add_frame_range(start, start + size);
+//! });
+//! panic!("end of rust_main!");
+//! }
+//!
+//! ```
+//!
+//! The main(hardid: usize) is the entry point.
+//!
+//! You can find details in the example.
+//!
+//! In this crate you can find some interfaces to use.
+//! These interfaces are classified into some structures.
+//!
+//! [PhysPage]: PhysicalPage And its associated functions.
+//!
+//! [PhysAddr](addr::PhysAddr): PhysicalAddr And its associated functions.
+//!
+//! [VirtPage](addr::VirtPage): VirtualPage And its associated functions.
+//!
+//! [VirtAddr](addr::VirtAddr): VirtualAddr And its associated functions.
+//!
+//! [IRQ](irq::IRQ): Interrupt ReQuest management, includes enable and disable.
+//!
+//! [Barrier](mem::Barrier): Memory barrier operations.
+//!
+//! [MultiCore](multicore::MultiCore): MultiCore operations. Now only [multicore::MultiCore::boot_all] is available.
+//!
+//! [PageTable]: PageTable and its associated functions.
+//!
+//! [MappingFlags](pagetable::MappingFlags): MappingFlags, This is an abstraction of pagetable flags.
+//!
+//! [TLB](pagetable::TLB): TLB operations.
+//!
+//! [PageTableWrapper](pagetable::PageTableWrapper): PageTableWrapper. It will dealloc all pagetable leaf when it was dropping.
+//!
+//! [Time](time::Time): Time and its associated functions.
+//!
+//! [Instruction](instruction::Instruction): Some platform instruction.
+//!
+//! There also provides a debugging console(recommanded only for debugging).
+//!
+//! [DebugConsole](debug::DebugConsole): A console for debugging.
+//!
+//! This crate provides a [TrapFrame], you can operate it through index with [TrapFrameArgs].
+//!
+//! If you are using kernel task. You should to enable feature `kcontext`.
+//! Then you can use kernel task context structure [KContext], and manipulate it with [KContextArgs].
+//!
+//! You can switch kcontext through [context_switch_pt] or [context_switch]
+//!
+//! There are also some consts.
+//!
+//! [VIRT_ADDR_START]: This is a higher half kernel offset address.
+//! [USER_VADDR_END]: End of the user address range.
+//! [PAGE_SIZE]: The size of the page.
+//!
+//! You can get some device information using the functions below.
+//! [get_mem_areas]: Get the avaliable memorys.
+//! [get_fdt]: Get the Fdt structure(fdt is a rust dtb operation crate).
+//! [get_cpu_num]: Get the number of cpus.
+//!
+//! TIPS: You should have finished [init] before using [get_mem_areas] and [get_fdt].
+
+extern crate alloc;
+
+#[macro_use]
+extern crate log;
+
+pub mod addr;
+pub mod api;
+#[macro_use]
+pub mod consts;
+pub mod debug;
+pub mod instruction;
+pub mod irq;
+pub mod mem;
+#[cfg(feature = "multicore")]
+pub mod multicore;
+pub mod once;
+pub mod pagetable;
+pub mod time;
+use core::mem::size_of;
+
+use addr::PhysPage;
+use alloc::vec::Vec;
+
+use consts::STACK_SIZE;
+use fdt::Fdt;
+use once::LazyInit;
+use pagetable::PageTable;
+pub use percpu;
+
+#[cfg_attr(target_arch = "riscv64", path = "riscv64/mod.rs")]
+#[cfg_attr(target_arch = "aarch64", path = "aarch64/mod.rs")]
+#[cfg_attr(target_arch = "x86_64", path = "x86_64/mod.rs")]
+#[cfg_attr(target_arch = "loongarch64", path = "loongarch64/mod.rs")]
+mod currrent_arch;
+
+/// Trap Frame
+pub use currrent_arch::TrapFrame;
+
+pub use currrent_arch::*;
+
+pub use polyhal_macro::{arch_entry, arch_interrupt};
+
+pub const PAGE_SIZE: usize = PageTable::PAGE_SIZE;
+pub const USER_VADDR_END: usize = PageTable::USER_VADDR_END;
+
+/// Kernel Context Arg Type.
+///
+/// Using this by Index and IndexMut trait bound on KContext.
+#[derive(Debug)]
+#[cfg(feature = "kcontext")]
+pub enum KContextArgs {
+ /// Kernel Stack Pointer
+ KSP,
+ /// Kernel Thread Pointer
+ KTP,
+ /// Kernel Program Counter
+ KPC,
+}
+
+/// Trap Frame Arg Type
+///
+/// Using this by Index and IndexMut trait bound on TrapFrame
+#[derive(Debug)]
+pub enum TrapFrameArgs {
+ SEPC,
+ RA,
+ SP,
+ RET,
+ ARG0,
+ ARG1,
+ ARG2,
+ TLS,
+ SYSCALL,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum TrapType {
+ Breakpoint,
+ UserEnvCall,
+ Time,
+ Unknown,
+ SupervisorExternal,
+ StorePageFault(usize),
+ LoadPageFault(usize),
+ InstructionPageFault(usize),
+ IllegalInstruction(usize),
+}
+
+#[link_section = ".bss.stack"]
+static mut BOOT_STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
+
+pub(crate) fn clear_bss() {
+ extern "C" {
+ fn _sbss();
+ fn _ebss();
+ }
+ unsafe {
+ core::slice::from_raw_parts_mut(
+ _sbss as usize as *mut u128,
+ (_ebss as usize - _sbss as usize) / size_of::<u128>(),
+ )
+ .fill(0);
+ }
+}
+
+pub trait PageAlloc: Sync {
+ fn alloc(&self) -> PhysPage;
+ fn dealloc(&self, ppn: PhysPage);
+}
+
+static PAGE_ALLOC: LazyInit<&dyn PageAlloc> = LazyInit::new();
+
+/// Init arch with page allocator, like log crate
+/// Please initialize the allocator before calling this function.
+pub fn init(page_alloc: &'static dyn PageAlloc) {
+ PAGE_ALLOC.init_by(page_alloc);
+
+ // Init current architecture
+ currrent_arch::arch_init();
+}
+
+/// Store the number of cpu, this will fill up by startup function.
+pub(crate) static CPU_NUM: LazyInit<usize> = LazyInit::new();
+
+/// Store the memory area, this will fill up by the arch_init() function in each architecture.
+pub(crate) static MEM_AREA: LazyInit<Vec<(usize, usize)>> = LazyInit::new();
+
+/// Store the DTB_area, this will fill up by the arch_init() function in each architecture
+static DTB_BIN: LazyInit<Vec<u8>> = LazyInit::new();
+
+/// Get the memory area, this function should be called after initialization
+pub fn get_mem_areas() -> Vec<(usize, usize)> {
+ MEM_AREA.clone()
+}
+
+/// Get the fdt
+pub fn get_fdt() -> Option<Fdt<'static>> {
+ Fdt::new(&DTB_BIN).ok()
+}
+
+/// Get the number of cpus
+pub fn get_cpu_num() -> usize {
+ *CPU_NUM
+}
+
/// This is a leader for the multicore operation
+///
+/// You can use this function to use the multicore operation
+///
+/// Boot other calls after the multicore
+/// If you use this function call, you should call it after arch::init(..);
+/// This function will allocate the stack and map it for itself.
+///
+/// ```rust
+/// Multicore::boot_all();
+/// ```
+///
+/// Here will have more functionality about multicore in the future.
+///
+pub struct MultiCore;
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +
use core::cell::UnsafeCell;
+use core::fmt;
+use core::mem::MaybeUninit;
+use core::ops::{Deref, DerefMut};
+use core::sync::atomic::{AtomicBool, Ordering};
+
+pub struct LazyInit<T> {
+ inited: AtomicBool,
+ data: UnsafeCell<MaybeUninit<T>>,
+}
+
+unsafe impl<T: Send + Sync> Sync for LazyInit<T> {}
+unsafe impl<T: Send> Send for LazyInit<T> {}
+
+impl<T> LazyInit<T> {
+ pub const fn new() -> Self {
+ Self {
+ inited: AtomicBool::new(false),
+ data: UnsafeCell::new(MaybeUninit::uninit()),
+ }
+ }
+
+ pub fn init_by(&self, data: T) {
+ assert!(!self.is_init());
+ unsafe { (*self.data.get()).as_mut_ptr().write(data) };
+ self.inited.store(true, Ordering::Release);
+ }
+
+ pub fn is_init(&self) -> bool {
+ self.inited.load(Ordering::Acquire)
+ }
+
+ pub fn try_get(&self) -> Option<&T> {
+ if self.is_init() {
+ unsafe { Some(&*(*self.data.get()).as_ptr()) }
+ } else {
+ None
+ }
+ }
+
+ fn check_init(&self) {
+ if !self.is_init() {
+ panic!(
+ "Use uninitialized value: {:?}",
+ core::any::type_name::<Self>()
+ )
+ }
+ }
+
+ #[inline]
+ fn get(&self) -> &T {
+ self.check_init();
+ unsafe { self.get_unchecked() }
+ }
+
+ #[inline]
+ fn get_mut(&mut self) -> &mut T {
+ self.check_init();
+ unsafe { self.get_mut_unchecked() }
+ }
+
+ /// # Safety
+ ///
+ /// Must be called after initialization.
+ #[inline]
+ pub unsafe fn get_unchecked(&self) -> &T {
+ &*(*self.data.get()).as_ptr()
+ }
+
+ /// # Safety
+ ///
+ /// Must be called after initialization.
+ #[inline]
+ pub unsafe fn get_mut_unchecked(&mut self) -> &mut T {
+ &mut *(*self.data.get()).as_mut_ptr()
+ }
+}
+
+impl<T: fmt::Debug> fmt::Debug for LazyInit<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.try_get() {
+ Some(s) => write!(f, "LazyInit {{ data: ")
+ .and_then(|()| s.fmt(f))
+ .and_then(|()| write!(f, "}}")),
+ None => write!(f, "LazyInit {{ <uninitialized> }}"),
+ }
+ }
+}
+
+impl<T> Deref for LazyInit<T> {
+ type Target = T;
+ #[inline]
+ fn deref(&self) -> &T {
+ self.get()
+ }
+}
+
+impl<T> DerefMut for LazyInit<T> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut T {
+ self.get_mut()
+ }
+}
+
+impl<T> Drop for LazyInit<T> {
+ fn drop(&mut self) {
+ if self.is_init() {
+ unsafe { core::ptr::drop_in_place((*self.data.get()).as_mut_ptr()) };
+ }
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +
use core::ops::Deref;
+
+use crate::addr::{PhysAddr, PhysPage, VirtAddr, VirtPage};
+use crate::api::{frame_alloc, frame_dealloc};
+
+bitflags::bitflags! {
+ /// Mapping flags for page table.
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ pub struct MappingFlags: u64 {
+ /// Persent
+ const P = bit!(0);
+ /// User Accessable Flag
+ const U = bit!(1);
+ /// Readable Flag
+ const R = bit!(2);
+ /// Writeable Flag
+ const W = bit!(3);
+ /// Executeable Flag
+ const X = bit!(4);
+ /// Accessed Flag
+ const A = bit!(5);
+ /// Dirty Flag, indicating that the page was written
+ const D = bit!(6);
+ /// Global Flag
+ const G = bit!(7);
+ /// Device Flag, indicating that the page was used for device memory
+ const Device = bit!(8);
+ /// Cache Flag, indicating that the page will be cached
+ const Cache = bit!(9);
+
+ /// Read | Write | Executeable Flags
+ const RWX = Self::R.bits() | Self::W.bits() | Self::X.bits();
+ /// User | Read | Write Flags
+ const URW = Self::U.bits() | Self::R.bits() | Self::W.bits();
+ /// User | Read | Executeable Flags
+ const URX = Self::U.bits() | Self::R.bits() | Self::X.bits();
+ /// User | Read | Write | Executeable Flags
+ const URWX = Self::URW.bits() | Self::X.bits();
+ }
+}
+
+/// This structure indicates size of the page that will be mapped.
+///
+/// TODO: Support More Page Size, 16KB or 32KB
+/// Just support 4KB right now.
+#[derive(Debug)]
+pub enum MappingSize {
+ Page4KB,
+ // Page2MB,
+ // Page1GB,
+}
+
+/// Page table entry structure
+///
+/// Just define here. Should implement functions in specific architectures.
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct PTE(pub usize);
+
+/// Page Table
+///
+/// This is just the page table defination.
+/// The implementation of the page table in the specific architecture mod.
+/// Such as:
+/// x86_64/page_table.rs
+/// riscv64/page_table/sv39.rs
+/// aarch64/page_table.rs
+/// loongarch64/page_table.rs
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+pub struct PageTable(pub(crate) PhysAddr);
+
+impl PageTable {
+ /// Get the page table list through the physical address
+ #[inline]
+ pub(crate) fn get_pte_list(paddr: PhysAddr) -> &'static mut [PTE] {
+ paddr.slice_mut_with_len::<PTE>(Self::PTE_NUM_IN_PAGE)
+ }
+
+ /// Mapping a page to specific virtual page (user space address).
+ ///
+ /// Ensure that PageTable is which you want to map.
+ /// vpn: Virtual page will be mapped.
+ /// ppn: Physical page.
+ /// flags: Mapping flags, include Read, Write, Execute and so on.
+ /// size: MappingSize. Just support 4KB page currently.
+ pub fn map_page(&self, vpn: VirtPage, ppn: PhysPage, flags: MappingFlags, _size: MappingSize) {
+ assert!(
+ vpn.to_addr() <= Self::USER_VADDR_END,
+ "You only should use the address limited by user"
+ );
+ assert!(Self::PAGE_LEVEL >= 3, "Just level >= 3 supported currently");
+ let mut pte_list = Self::get_pte_list(self.0);
+ if Self::PAGE_LEVEL == 4 {
+ let pte = &mut pte_list[vpn.pn_index(3)];
+ if !pte.is_valid() {
+ *pte = PTE::new_table(frame_alloc());
+ }
+ pte_list = Self::get_pte_list(pte.address());
+ }
+ // level 3
+ {
+ let pte = &mut pte_list[vpn.pn_index(2)];
+ if !pte.is_valid() {
+ *pte = PTE::new_table(frame_alloc());
+ }
+ pte_list = Self::get_pte_list(pte.address());
+ }
+ // level 2
+ {
+ let pte = &mut pte_list[vpn.pn_index(1)];
+ if !pte.is_valid() {
+ *pte = PTE::new_table(frame_alloc());
+ }
+ pte_list = Self::get_pte_list(pte.address());
+ }
+ // level 1, map page
+ pte_list[vpn.pn_index(0)] = PTE::new_page(ppn, flags.into());
+ TLB::flush_vaddr(vpn.into());
+ }
+
+ /// Mapping a page to specific address(kernel space address).
+ ///
+ /// TODO: This method is not implemented.
+ /// TIPS: If we mapped to kernel, the page will be shared between different pagetable.
+ ///
+ /// Ensure that PageTable is which you want to map.
+ /// vpn: Virtual page will be mapped.
+ /// ppn: Physical page.
+ /// flags: Mapping flags, include Read, Write, Execute and so on.
+ /// size: MappingSize. Just support 4KB page currently.
+ ///
+ /// How to implement shared.
+ pub fn map_kernel(
+ &self,
+ vpn: VirtPage,
+ ppn: PhysPage,
+ flags: MappingFlags,
+ _size: MappingSize,
+ ) {
+ assert!(
+ vpn.to_addr() >= Self::KERNEL_VADDR_START,
+ "Virt page should greater than Self::KERNEL_VADDR_START"
+ );
+ assert!(Self::PAGE_LEVEL >= 3, "Just level >= 3 supported currently");
+ let mut pte_list = Self::get_pte_list(self.0);
+ if Self::PAGE_LEVEL == 4 {
+ let pte = &mut pte_list[vpn.pn_index(3)];
+ if !pte.is_valid() {
+ *pte = PTE::new_table(frame_alloc());
+ }
+ pte_list = Self::get_pte_list(pte.address());
+ }
+ // level 3
+ {
+ let pte = &mut pte_list[vpn.pn_index(2)];
+ if !pte.is_valid() {
+ *pte = PTE::new_table(frame_alloc());
+ }
+ pte_list = Self::get_pte_list(pte.address());
+ }
+ // level 2
+ {
+ let pte = &mut pte_list[vpn.pn_index(1)];
+ if !pte.is_valid() {
+ *pte = PTE::new_table(frame_alloc());
+ }
+ pte_list = Self::get_pte_list(pte.address());
+ }
+ // level 1, map page
+ pte_list[vpn.pn_index(0)] = PTE::new_page(ppn, flags.into());
+ TLB::flush_vaddr(vpn.into());
+ }
+
+ /// Unmap a page from specific virtual page (user space address).
+ ///
+ /// Ensure the virtual page is exists.
+ /// vpn: Virtual address.
+ pub fn unmap_page(&self, vpn: VirtPage) {
+ let mut pte_list = Self::get_pte_list(self.0);
+ if Self::PAGE_LEVEL == 4 {
+ let pte = &mut pte_list[vpn.pn_index(3)];
+ if !pte.is_table() {
+ return;
+ };
+ pte_list = Self::get_pte_list(pte.address());
+ }
+ // level 3
+ {
+ let pte = &mut pte_list[vpn.pn_index(2)];
+ if !pte.is_table() {
+ return;
+ };
+ pte_list = Self::get_pte_list(pte.address());
+ }
+ // level 2
+ {
+ let pte = &mut pte_list[vpn.pn_index(1)];
+ if !pte.is_table() {
+ return;
+ };
+ pte_list = Self::get_pte_list(pte.address());
+ }
+ // level 1, map page
+ pte_list[vpn.pn_index(0)] = PTE(0);
+ TLB::flush_vaddr(vpn.into());
+ }
+
+ /// Translate a virtual adress to a physical address and mapping flags.
+ ///
+ /// Return None if the vaddr isn't mapped.
+ /// vpn: The virtual address will be translated.
+ pub fn translate(&self, vaddr: VirtAddr) -> Option<(PhysAddr, MappingFlags)> {
+ let vpn: VirtPage = vaddr.into();
+ let mut pte_list = Self::get_pte_list(self.0);
+ if Self::PAGE_LEVEL == 4 {
+ let pte = &mut pte_list[vpn.pn_index(3)];
+ if !pte.is_table() {
+ return None;
+ }
+ pte_list = Self::get_pte_list(pte.address());
+ }
+ // level 3
+ {
+ let pte = &mut pte_list[vpn.pn_index(2)];
+ if !pte.is_table() {
+ return None;
+ }
+ pte_list = Self::get_pte_list(pte.address());
+ }
+ // level 2
+ {
+ let pte = &mut pte_list[vpn.pn_index(1)];
+ if !pte.is_table() {
+ return None;
+ }
+ pte_list = Self::get_pte_list(pte.address());
+ }
+ // level 1, map page
+ let pte = pte_list[vpn.pn_index(0)];
+ Some((
+ PhysAddr(pte.address().0 + vaddr.pn_offest(0)),
+ pte.flags().into(),
+ ))
+ }
+
+ /// Release the page table entry.
+ ///
+ /// The page table entry in the user space address will be released.
+ /// [Page Table Wikipedia](https://en.wikipedia.org/wiki/Page_table).
+ /// You don't need to care about this if you just want to use.
+ pub fn release(&self) {
+ let drop_l2 = |pte_list: &[PTE]| {
+ pte_list.iter().for_each(|x| {
+ if x.is_table() {
+ frame_dealloc(x.address().into());
+ }
+ });
+ };
+ let drop_l3 = |pte_list: &[PTE]| {
+ pte_list.iter().for_each(|x| {
+ if x.is_table() {
+ drop_l2(Self::get_pte_list(x.address()));
+ frame_dealloc(x.address().into());
+ }
+ });
+ };
+ let drop_l4 = |pte_list: &[PTE]| {
+ pte_list.iter().for_each(|x| {
+ if x.is_table() {
+ drop_l3(Self::get_pte_list(x.address()));
+ frame_dealloc(x.address().into());
+ }
+ });
+ };
+
+ // Drop all sub page table entry and clear root page.
+ let pte_list = &mut Self::get_pte_list(self.0)[..Self::GLOBAL_ROOT_PTE_RANGE];
+ if Self::PAGE_LEVEL == 4 {
+ drop_l4(pte_list);
+ } else {
+ drop_l3(pte_list);
+ }
+ pte_list.fill(PTE(0));
+ }
+}
+
+/// TLB Operation set.
+/// Such as flush_vaddr, flush_all.
+/// Just use it in the fn.
+///
+/// there are some methods in the TLB implementation
+///
+/// ### Flush the tlb entry through the specific virtual address
+///
+/// ```rust
+/// TLB::flush_vaddr(arg0); arg0 should be VirtAddr
+/// ```
+/// ### Flush all tlb entries
+/// ```rust
+/// TLB::flush_all();
+/// ```
+pub struct TLB;
+
+/// Page Table Wrapper
+///
+/// You can use this wrapper to packing PageTable.
+/// If you release the PageTableWrapper,
+/// the PageTable will release its page table entry.
+#[derive(Debug)]
+pub struct PageTableWrapper(pub PageTable);
+
+impl Deref for PageTableWrapper {
+ type Target = PageTable;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+/// Allocate a new PageTableWrapper with new page table root
+///
+/// This operation will restore the page table.
+impl PageTableWrapper {
+ /// Alloc a new PageTableWrapper with new page table root
+ /// This operation will copy kernel page table space from booting page table.
+ #[inline]
+ pub fn alloc() -> Self {
+ let pt = PageTable(frame_alloc().into());
+ pt.restore();
+ Self(pt)
+ }
+}
+
+/// Page Table Release.
+///
+/// You must implement this trait to release page table.
+/// Include the page table entry and root page.
+impl Drop for PageTableWrapper {
+ fn drop(&mut self) {
+ self.0.release();
+ frame_dealloc(self.0 .0.into());
+ }
+}
+
+#[cfg(test)]
+/// TODO: use #![feature(custom_test_frameworks)] to
+/// Test this crate.
+mod tests {
+ use core::mem::size_of;
+
+ use crate::pagetable::PageTableWrapper;
+
+ #[test]
+ fn exploration() {
+ assert_eq!(
+ size_of::<PageTableWrapper>(),
+ size_of::<usize>(),
+ "ensure the size of the page table wrapper equas the size of the usize"
+ );
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +
cfg_if::cfg_if! {
+ if #[cfg(board = "k210")] {
+ mod k210;
+ pub use k210::*;
+ } else if #[cfg(board = "qemu")] {
+ mod qemu;
+ pub use qemu::*;
+ } else if #[cfg(board = "cv1811h")] {
+ mod cv1811h;
+ pub use cv1811h::*;
+ } else if #[cfg(board = "visionfive2")] {
+ use riscv::register::sstatus;
+ pub const CLOCK_FREQ: usize = 12500000;
+ static DEVICE_TREE: &[u8] = include_bytes!("jh7110-visionfive-v2.dtb");
+ pub fn init_device(hartid: usize, _device_tree: usize) -> (usize, usize) {
+ unsafe {
+ sstatus::set_sum();
+ }
+ (hartid, DEVICE_TREE.as_ptr() as usize)
+ }
+ } else {
+ // compile_error!("not support this board");
+ pub const CLOCK_FREQ: usize = 12500000;
+
+ pub fn init_device(hartid: usize, device_tree: usize) -> (usize, usize) {
+ // warn!("use default board config");
+ (hartid, device_tree)
+ }
+ }
+}
+
pub const VIRT_ADDR_START: usize = 0xffff_ffc0_0000_0000;
+pub const SIG_RETURN_ADDR: usize = 0xFFFF_FFC1_0000_0000;
+
+/// Every core has a unique area of memory.
+/// Just using pagetable to map multi core area.
+/// Area size: 0x100_0000 (16MBytes)
+///
+/// First Area is 0xFFFF_FFC2_0000_0000
+/// Next Area is 0xFFFF_FFC2_0100_0000
+/// Others Same as This, so it will support 16 * 16 = 256 cores (Only auxiliary Harts).
+pub const MULTI_CORE_AREA: usize = 0xFFFF_FFC2_0000_0000;
+pub const MULTI_CORE_AREA_SIZE: usize = 0x100_0000;
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +
use core::{
+ fmt::Debug,
+ ops::{Index, IndexMut},
+};
+
+use riscv::register::sstatus::{self, Sstatus};
+
+use crate::TrapFrameArgs;
+
+#[repr(C)]
+#[derive(Clone)]
+// 上下文
+pub struct TrapFrame {
+ pub x: [usize; 32], // 32 个通用寄存器
+ pub sstatus: Sstatus,
+ pub sepc: usize,
+ pub fsx: [usize; 2],
+}
+
+impl Debug for TrapFrame {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.debug_struct("Context")
+ .field("ra", &self.x[1])
+ .field("sp", &self.x[2])
+ .field("gp", &self.x[3])
+ .field("tp", &self.x[4])
+ .field("t0", &self.x[5])
+ .field("t1", &self.x[6])
+ .field("t2", &self.x[7])
+ .field("s0", &self.x[8])
+ .field("s1", &self.x[9])
+ .field("a0", &self.x[10])
+ .field("a1", &self.x[11])
+ .field("a2", &self.x[12])
+ .field("a3", &self.x[13])
+ .field("a4", &self.x[14])
+ .field("a5", &self.x[15])
+ .field("a6", &self.x[16])
+ .field("a7", &self.x[17])
+ .field("s2", &self.x[18])
+ .field("s3", &self.x[19])
+ .field("s4", &self.x[20])
+ .field("s5", &self.x[21])
+ .field("s6", &self.x[22])
+ .field("s7", &self.x[23])
+ .field("s8", &self.x[24])
+ .field("s9", &self.x[25])
+ .field("s10", &self.x[26])
+ .field("s11", &self.x[27])
+ .field("t3", &self.x[28])
+ .field("t4", &self.x[29])
+ .field("t5", &self.x[30])
+ .field("t6", &self.x[31])
+ .field("sstatus", &self.sstatus)
+ .field("sepc", &self.sepc)
+ .field("fsx", &self.fsx)
+ .finish()
+ }
+}
+
+impl TrapFrame {
+ // 创建上下文信息
+ #[inline]
+ pub fn new() -> Self {
+ TrapFrame {
+ x: [0usize; 32],
+ sstatus: sstatus::read(),
+ sepc: 0,
+ fsx: [0; 2],
+ }
+ }
+
+ #[inline]
+ pub fn args(&self) -> [usize; 6] {
+ self.x[10..16].try_into().expect("args slice force convert")
+ }
+
+ #[inline]
+ pub fn syscall_ok(&mut self) {
+ self.sepc += 4;
+ }
+}
+
+impl Index<TrapFrameArgs> for TrapFrame {
+ type Output = usize;
+
+ fn index(&self, index: TrapFrameArgs) -> &Self::Output {
+ match index {
+ TrapFrameArgs::SEPC => &self.sepc,
+ TrapFrameArgs::RA => &self.x[1],
+ TrapFrameArgs::SP => &self.x[2],
+ TrapFrameArgs::RET => &self.x[10],
+ TrapFrameArgs::ARG0 => &self.x[10],
+ TrapFrameArgs::ARG1 => &self.x[11],
+ TrapFrameArgs::ARG2 => &self.x[12],
+ TrapFrameArgs::TLS => &self.x[4],
+ TrapFrameArgs::SYSCALL => &self.x[17],
+ }
+ }
+}
+
+impl IndexMut<TrapFrameArgs> for TrapFrame {
+ fn index_mut(&mut self, index: TrapFrameArgs) -> &mut Self::Output {
+ match index {
+ TrapFrameArgs::SEPC => &mut self.sepc,
+ TrapFrameArgs::RA => &mut self.x[1],
+ TrapFrameArgs::SP => &mut self.x[2],
+ TrapFrameArgs::RET => &mut self.x[10],
+ TrapFrameArgs::ARG0 => &mut self.x[10],
+ TrapFrameArgs::ARG1 => &mut self.x[11],
+ TrapFrameArgs::ARG2 => &mut self.x[12],
+ TrapFrameArgs::TLS => &mut self.x[4],
+ TrapFrameArgs::SYSCALL => &mut self.x[17],
+ }
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +
use core::arch::riscv64::sfence_vma_all;
+
+use crate::pagetable::{PageTable, PTE};
+use crate::VIRT_ADDR_START;
+
+use super::page_table::PTEFlags;
+
+#[link_section = ".data.prepage.entry"]
+pub(crate) static mut PAGE_TABLE: [PTE; PageTable::PTE_NUM_IN_PAGE] = {
+ let mut arr: [PTE; PageTable::PTE_NUM_IN_PAGE] = [PTE(0); PageTable::PTE_NUM_IN_PAGE];
+ // 初始化页表信息
+ // 0x00000000_80000000 -> 0x80000000 (1G)
+ // 高半核
+ // 0xffffffc0_00000000 -> 0x00000000 (1G)
+ // 0xffffffc0_80000000 -> 0x80000000 (1G)
+
+ // arr[0] = PTE::from_addr(0x0000_0000, PTEFlags::VRWX);
+ // arr[1] = PTE::from_addr(0x4000_0000, PTEFlags::VRWX);
+ arr[2] = PTE::from_addr(0x8000_0000, PTEFlags::ADVRWX);
+ arr[0x100] = PTE::from_addr(0x0000_0000, PTEFlags::ADGVRWX);
+ arr[0x101] = PTE::from_addr(0x4000_0000, PTEFlags::ADGVRWX);
+ arr[0x102] = PTE::from_addr(0x8000_0000, PTEFlags::ADGVRWX);
+ arr[0x103] = PTE::from_addr(0xc000_0000, PTEFlags::ADGVRWX);
+ arr[0x104] = PTE::from_addr(0x1_0000_0000, PTEFlags::ADGVRWX);
+ arr[0x105] = PTE::from_addr(0x1_4000_0000, PTEFlags::ADGVRWX);
+ arr[0x106] = PTE::from_addr(0x8000_0000, PTEFlags::ADVRWX);
+ arr
+};
+
+/// 汇编入口函数
+///
+/// 分配栈 初始化页表信息 并调到rust入口函数
+#[naked]
+#[no_mangle]
+#[link_section = ".text.entry"]
+unsafe extern "C" fn _start() -> ! {
+ core::arch::asm!(
+ // Chcek boot core
+ "
+ beqz a0, 2f
+ ",
+ // Ensure that boot core is 0
+ "1:
+ // li a7, 0x48534D
+ // li a6, 0
+ // li a0, 0
+ // mv a2, a1
+ // la a1, _start
+ // ecall
+ // li a7, 0x48534D
+ // li a6, 1 // 0: START, 1: STOP, 2: STATUS
+ // li a0, 0
+ // mv a2, a1
+ // la a1, _start
+ // ecall
+ // wfi
+ // la ra, 1b
+ // ret
+ ",
+ // 1. 设置栈信息
+ // sp = bootstack + (hartid + 1) * 0x10000
+ "2:
+ la sp, {boot_stack}
+ li t0, {stack_size}
+ add sp, sp, t0 // set boot stack
+
+ li s0, {virt_addr_start} // add virtual address
+ or sp, sp, s0
+ ",
+ // 2. 开启分页模式
+ // satp = (8 << 60) | PPN(page_table)
+ "
+ la t0, {page_table}
+ srli t0, t0, 12
+ li t1, 8 << 60
+ or t0, t0, t1
+ csrw satp, t0
+ sfence.vma
+ ",
+ // 3. 跳到 rust_main 函数,绝对路径
+ "
+ la a2, {entry}
+ or a2, a2, s0
+ jalr a2 // call rust_main
+ ",
+ stack_size = const crate::STACK_SIZE,
+ boot_stack = sym crate::BOOT_STACK,
+ page_table = sym PAGE_TABLE,
+ entry = sym super::rust_main,
+ virt_addr_start = const VIRT_ADDR_START,
+ options(noreturn),
+ )
+}
+
+/// 汇编函数入口
+///
+/// 初始化也表信息 并调到 rust_secondary_main 入口函数
+#[naked]
+#[no_mangle]
+pub(crate) unsafe extern "C" fn secondary_start() -> ! {
+ core::arch::asm!(
+ // 1. 设置栈信息
+ // sp = bootstack + (hartid + 1) * 0x10000
+ "
+ mv s6, a0
+ mv sp, a1
+
+ li s0, {virt_addr_start} // add virtual address
+ or sp, sp, s0
+ ",
+ // 2. 开启分页模式
+ // satp = (8 << 60) | PPN(page_table)
+ "
+ la t0, {page_table}
+ srli t0, t0, 12
+ li t1, 8 << 60
+ or t0, t0, t1
+ csrw satp, t0
+ sfence.vma
+ ",
+ // 3. 跳到 secondary_entry
+ "
+ la a2, {entry}
+ or a2, a2, s0
+ mv a0, s6
+ jalr a2 // call rust_main
+ ",
+ page_table = sym PAGE_TABLE,
+ entry = sym super::rust_secondary_main,
+ virt_addr_start = const VIRT_ADDR_START,
+ options(noreturn)
+ );
+}
+
+pub fn switch_to_kernel_page_table() {
+ unsafe {
+ riscv::register::satp::set(
+ riscv::register::satp::Mode::Sv39,
+ 0,
+ (PAGE_TABLE.as_ptr() as usize & !VIRT_ADDR_START) >> 12,
+ );
+ sfence_vma_all();
+ }
+}
+
+pub fn kernel_page_table() -> PageTable {
+ PageTable(crate::addr::PhysAddr(unsafe {
+ PAGE_TABLE.as_ptr() as usize & !VIRT_ADDR_START
+ }))
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +
use core::arch::{asm, global_asm};
+
+use riscv::register::{
+ scause::{self, Exception, Interrupt, Trap},
+ sie, stval, stvec,
+};
+
+use crate::{instruction::Instruction, TrapFrame, TrapType, VIRT_ADDR_START};
+
+use super::timer;
+
+global_asm!(
+ r"
+ .altmacro
+ .macro LOAD reg, offset
+ ld \reg, \offset*8(sp)
+ .endm
+
+ .macro SAVE reg, offset
+ sd \reg, \offset*8(sp)
+ .endm
+
+ .macro LOAD_N n
+ ld x\n, \n*8(sp)
+ .endm
+
+ .macro SAVE_N n
+ sd x\n, \n*8(sp)
+ .endm
+
+ .macro SAVE_GENERAL_REGS
+ SAVE x1, 1
+ csrr x1, sscratch
+ SAVE x1, 2
+ .set n, 3
+ .rept 29
+ SAVE_N %n
+ .set n, n + 1
+ .endr
+
+ csrr t0, sstatus
+ csrr t1, sepc
+ SAVE t0, 32
+ SAVE t1, 33
+ .endm
+
+ .macro LOAD_GENERAL_REGS
+ LOAD t0, 32
+ LOAD t1, 33
+ csrw sstatus, t0
+ csrw sepc, t1
+
+ LOAD x1, 1
+ .set n, 3
+ .rept 29
+ LOAD_N %n
+ .set n, n + 1
+ .endr
+ LOAD x2, 2
+ .endm
+
+ .macro LOAD_PERCPU dst, sym
+ lui \dst, %hi(__PERCPU_\sym)
+ add \dst, \dst, gp
+ ld \dst, %lo(__PERCPU_\sym)(\dst)
+ .endm
+
+ .macro SAVE_PERCPU sym, temp, src
+ lui \temp, %hi(__PERCPU_\sym)
+ add \temp, \temp, gp
+ sd \src, %lo(__PERCPU_\sym)(\temp)
+ .endm
+"
+);
+
+#[no_mangle]
+#[percpu::def_percpu]
+static KERNEL_RSP: usize = 0;
+
+#[no_mangle]
+#[percpu::def_percpu]
+static USER_RSP: usize = 0;
+
+// 设置中断
+pub(crate) fn init_interrupt() {
+ crate::currrent_arch::page_table::sigtrx::init();
+ // 输出内核信息
+
+ unsafe {
+ stvec::write(kernelvec as usize, stvec::TrapMode::Direct);
+ // asm!("csrw stvec, a0", in("a0") kernelvec as usize);
+ }
+
+ // 初始化定时器
+ timer::init();
+}
+
+// 内核中断回调
+#[no_mangle]
+fn kernel_callback(context: &mut TrapFrame) -> TrapType {
+ let scause = scause::read();
+ let stval = stval::read();
+ // debug!(
+ // "int occurs: {:#x} {:?} stval {:#x} sepc: {:#x}",
+ // scause.bits(),
+ // scause.cause(),
+ // stval,
+ // context.sepc
+ // );
+ let trap_type = match scause.cause() {
+ // 中断异常
+ Trap::Exception(Exception::Breakpoint) => {
+ context.sepc += 2;
+ TrapType::Breakpoint
+ }
+ Trap::Exception(Exception::LoadFault) => {
+ if stval > VIRT_ADDR_START {
+ panic!("kernel error: {:#x}", stval);
+ }
+ TrapType::Unknown
+ }
+ Trap::Exception(Exception::UserEnvCall) => TrapType::UserEnvCall,
+ // 时钟中断
+ Trap::Interrupt(Interrupt::SupervisorTimer) => {
+ timer::set_next_timeout();
+ TrapType::Time
+ }
+ Trap::Exception(Exception::StorePageFault) => TrapType::StorePageFault(stval),
+ Trap::Exception(Exception::InstructionPageFault) => TrapType::InstructionPageFault(stval),
+ Trap::Exception(Exception::IllegalInstruction) => TrapType::IllegalInstruction(stval),
+ Trap::Exception(Exception::LoadPageFault) => TrapType::LoadPageFault(stval),
+ Trap::Interrupt(Interrupt::SupervisorExternal) => TrapType::SupervisorExternal,
+ _ => {
+ error!(
+ "内核态中断发生: {:#x} {:?} stval {:#x} sepc: {:#x}",
+ scause.bits(),
+ scause.cause(),
+ stval,
+ context.sepc
+ );
+ panic!("未知中断: {:#x?}", context);
+ }
+ };
+ unsafe { crate::api::_interrupt_for_arch(context, trap_type) };
+ trap_type
+}
+
+#[naked]
+pub unsafe extern "C" fn kernelvec() {
+ asm!(
+ // 宏定义
+ r"
+ .align 4
+ .altmacro
+
+ csrrw sp, sscratch, sp
+ bnez sp, uservec
+ csrr sp, sscratch
+
+ addi sp, sp, -{cx_size}
+
+ SAVE_GENERAL_REGS
+ csrw sscratch, x0
+
+ mv a0, sp
+
+ call kernel_callback
+
+ LOAD_GENERAL_REGS
+ sret
+ ",
+ cx_size = const crate::consts::TRAPFRAME_SIZE,
+ options(noreturn)
+ )
+}
+
+#[naked]
+#[no_mangle]
+extern "C" fn user_restore(context: *mut TrapFrame) {
+ unsafe {
+ asm!(
+ r"
+ .align 4
+ .altmacro
+ ",
+ // 在内核态栈中开一个空间来存储内核态信息
+ // 下次发生中断必然会进入中断入口然后恢复这个上下文.
+ // 仅保存 Callee-saved regs、gp、tp、ra.
+ " addi sp, sp, -18*8
+
+ sd sp, 8*1(sp)
+ sd gp, 8*2(sp)
+ sd tp, 8*3(sp)
+ sd s0, 8*4(sp)
+ sd s1, 8*5(sp)
+ sd s2, 8*6(sp)
+ sd s3, 8*7(sp)
+ sd s4, 8*8(sp)
+ sd s5, 8*9(sp)
+ sd s6, 8*10(sp)
+ sd s7, 8*11(sp)
+ sd s8, 8*12(sp)
+ sd s9, 8*13(sp)
+ sd s10, 8*14(sp)
+ sd s11, 8*15(sp)
+ sd a0, 8*16(sp)
+ sd ra, 8*17(sp)
+ ",
+ // 将栈信息保存到用户栈.
+ // a0 是传入的Context, 然后下面会再次恢复 sp 地址.
+ " sd sp, 8*0(a0)
+ csrw sscratch, a0
+ mv sp, a0
+
+ .short 0x2452 # fld fs0, 272(sp)
+ .short 0x24f2 # fld fs1, 280(sp)
+
+ LOAD_GENERAL_REGS
+ sret
+ ",
+ options(noreturn)
+ )
+ }
+}
+
+#[naked]
+#[no_mangle]
+#[allow(named_asm_labels)]
+pub unsafe extern "C" fn uservec() {
+ asm!(
+ r"
+ .altmacro
+ ",
+ // 保存 general registers, 除了 sp
+ "
+ SAVE_GENERAL_REGS
+ csrw sscratch, x0
+
+ .word 0x10813827 # fsd fs0, 272(sp)
+ .word 0x10913c27 # fsd fs1, 280(sp)
+
+ mv a0, sp
+ ld sp, 0*8(a0)
+ sd x0, 0*8(a0)
+ ",
+ // 恢复内核上下文信息, 仅恢复 callee-saved 寄存器和 ra、gp、tp
+ "
+ ld gp, 8*2(sp)
+ ld tp, 8*3(sp)
+ ld s0, 8*4(sp)
+ ld s1, 8*5(sp)
+ ld s2, 8*6(sp)
+ ld s3, 8*7(sp)
+ ld s4, 8*8(sp)
+ ld s5, 8*9(sp)
+ ld s6, 8*10(sp)
+ ld s7, 8*11(sp)
+ ld s8, 8*12(sp)
+ ld s9, 8*13(sp)
+ ld s10, 8*14(sp)
+ ld s11, 8*15(sp)
+ ld ra, 8*17(sp)
+
+ ld sp, 8(sp)
+ ",
+ // 回收栈
+ " addi sp, sp, 18*8
+ ret
+ ",
+ options(noreturn)
+ );
+}
+
+/// Return Some(()) if it was interrupt by syscall, otherwise None.
+pub fn run_user_task(context: &mut TrapFrame) -> Option<()> {
+ user_restore(context);
+ match kernel_callback(context) {
+ TrapType::UserEnvCall => Some(()),
+ _ => None,
+ }
+}
+
+pub fn run_user_task_forever(context: &mut TrapFrame) -> ! {
+ loop {
+ user_restore(context);
+ kernel_callback(context);
+ }
+}
+
+#[allow(dead_code)]
+#[inline(always)]
+pub fn enable_irq() {
+ unsafe {
+ sie::set_sext();
+ sie::set_ssoft();
+ }
+}
+
+#[inline(always)]
+pub fn disable_irq() {
+ unsafe {
+ sie::clear_sext();
+ sie::clear_ssoft();
+ }
+}
+
+#[inline(always)]
+pub fn enable_external_irq() {
+ unsafe {
+ sie::set_sext();
+ }
+}
+
+impl Instruction {
+ #[inline]
+ pub fn ebreak() {
+ unsafe {
+ riscv::asm::ebreak();
+ }
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +
use core::{
+ arch::asm,
+ ops::{Index, IndexMut},
+};
+
+use crate::{KContextArgs, PageTable};
+
+/// Kernel Context
+///
+/// Kernel Context is used to switch context between kernel task.
+#[derive(Debug)]
+#[repr(C)]
+pub struct KContext {
+ /// Kernel Stack Pointer
+ ksp: usize,
+ /// Kernel Thread Pointer
+ ktp: usize,
+ /// Kernel S regs, s0 - s11, just callee-saved registers
+ /// just used in the context_switch function.
+ _sregs: [usize; 12],
+ /// Kernel Program Counter, Will return to this address.
+ kpc: usize,
+}
+
+impl KContext {
+ /// Create a new blank Kernel Context.
+ pub fn blank() -> Self {
+ Self {
+ ksp: 0,
+ ktp: 0,
+ _sregs: [0; 12],
+ kpc: 0,
+ }
+ }
+}
+
+/// Indexing operations for KContext
+///
+/// Using it just like the Vector.
+///
+/// #[derive(Debug)]
+/// pub enum KContextArgs {
+/// /// Kernel Stack Pointer
+/// KSP,
+/// /// Kernel Thread Pointer
+/// KTP,
+/// /// Kernel Program Counter
+/// KPC
+/// }
+///
+/// etc. Get reg of the kernel stack:
+///
+/// let ksp = KContext[KContextArgs::KSP]
+/// let kpc = KContext[KContextArgs::KPC]
+/// let ktp = KContext[KContextArgs::KTP]
+///
+impl Index<KContextArgs> for KContext {
+ type Output = usize;
+
+ fn index(&self, index: KContextArgs) -> &Self::Output {
+ match index {
+ KContextArgs::KSP => &self.ksp,
+ KContextArgs::KTP => &self.ktp,
+ KContextArgs::KPC => &self.kpc,
+ }
+ }
+}
+
+/// Indexing Mutable operations for KContext
+///
+/// Using it just like the Vector.
+///
+/// etc. Change the value of the kernel Context using IndexMut
+///
+/// KContext[KContextArgs::KSP] = ksp;
+/// KContext[KContextArgs::KPC] = kpc;
+/// KContext[KContextArgs::KTP] = ktp;
+///
+impl IndexMut<KContextArgs> for KContext {
+ fn index_mut(&mut self, index: KContextArgs) -> &mut Self::Output {
+ match index {
+ KContextArgs::KSP => &mut self.ksp,
+ KContextArgs::KTP => &mut self.ktp,
+ KContextArgs::KPC => &mut self.kpc,
+ }
+ }
+}
+
+/// Context Switch
+///
+/// Save the context of current task and switch to new task.
+#[naked]
+pub unsafe extern "C" fn context_switch(from: *mut KContext, to: *const KContext) {
+ core::arch::asm!(
+ // Save Kernel Context.
+ "
+ sd sp, 0*8(a0)
+ sd tp, 1*8(a0)
+ sd s0, 2*8(a0)
+ sd s1, 3*8(a0)
+ sd s2, 4*8(a0)
+ sd s3, 5*8(a0)
+ sd s4, 6*8(a0)
+ sd s5, 7*8(a0)
+ sd s6, 8*8(a0)
+ sd s7, 9*8(a0)
+ sd s8, 10*8(a0)
+ sd s9, 11*8(a0)
+ sd s10, 12*8(a0)
+ sd s11, 13*8(a0)
+ sd ra, 14*8(a0)
+ ",
+ // Restore Kernel Context.
+ "
+ ld sp, 0*8(a1)
+ ld tp, 1*8(a1)
+ ld s0, 2*8(a1)
+ ld s1, 3*8(a1)
+ ld s2, 4*8(a1)
+ ld s3, 5*8(a1)
+ ld s4, 6*8(a1)
+ ld s5, 7*8(a1)
+ ld s6, 8*8(a1)
+ ld s7, 9*8(a1)
+ ld s8, 10*8(a1)
+ ld s9, 11*8(a1)
+ ld s10, 12*8(a1)
+ ld s11, 13*8(a1)
+ ld ra, 14*8(a1)
+ ret
+ ",
+ options(noreturn)
+ )
+}
+
+/// Context Switch With Page Table
+///
+/// Save the context of current task and switch to new task.
+#[naked]
+pub unsafe extern "C" fn context_switch_pt(
+ from: *mut KContext,
+ to: *const KContext,
+ pt_token: PageTable,
+) {
+ core::arch::asm!(
+ // Save Kernel Context.
+ "
+ sd sp, 0*8(a0)
+ sd tp, 1*8(a0)
+ sd s0, 2*8(a0)
+ sd s1, 3*8(a0)
+ sd s2, 4*8(a0)
+ sd s3, 5*8(a0)
+ sd s4, 6*8(a0)
+ sd s5, 7*8(a0)
+ sd s6, 8*8(a0)
+ sd s7, 9*8(a0)
+ sd s8, 10*8(a0)
+ sd s9, 11*8(a0)
+ sd s10, 12*8(a0)
+ sd s11, 13*8(a0)
+ sd ra, 14*8(a0)
+ ",
+ // Switch to new page table.
+ "
+ srli a2, a2, 12
+ li a3, 8 << 60
+ or a2, a2, a3
+ csrw satp, a2
+ sfence.vma
+ ",
+ // Restore Kernel Context.
+ "
+ ld sp, 0*8(a1)
+ ld tp, 1*8(a1)
+ ld s0, 2*8(a1)
+ ld s1, 3*8(a1)
+ ld s2, 4*8(a1)
+ ld s3, 5*8(a1)
+ ld s4, 6*8(a1)
+ ld s5, 7*8(a1)
+ ld s6, 8*8(a1)
+ ld s7, 9*8(a1)
+ ld s8, 10*8(a1)
+ ld s9, 11*8(a1)
+ ld s10, 12*8(a1)
+ ld s11, 13*8(a1)
+ ld ra, 14*8(a1)
+ ret
+ ",
+ options(noreturn)
+ )
+}
+
+#[naked]
+pub extern "C" fn read_current_tp() -> usize {
+ unsafe {
+ asm!(
+ "
+ mv a0, tp
+ ret
+ ",
+ options(noreturn)
+ )
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +
mod barrier;
+mod boards;
+mod consts;
+mod context;
+mod entry;
+mod interrupt;
+#[cfg(feature = "kcontext")]
+mod kcontext;
+mod page_table;
+mod sbi;
+mod timer;
+
+use core::slice;
+
+use alloc::vec::Vec;
+pub use consts::*;
+pub use context::TrapFrame;
+pub use entry::{kernel_page_table, switch_to_kernel_page_table};
+use fdt::Fdt;
+pub use interrupt::{
+ disable_irq, enable_external_irq, enable_irq, run_user_task, run_user_task_forever,
+};
+use sbi::*;
+
+pub use sbi::shutdown;
+
+#[cfg(feature = "kcontext")]
+pub use kcontext::{context_switch, context_switch_pt, read_current_tp, KContext};
+
+use riscv::register::sstatus;
+
+use crate::{api::frame_alloc, multicore::MultiCore, once::LazyInit, CPU_NUM, DTB_BIN, MEM_AREA};
+
+#[percpu::def_percpu]
+static CPU_ID: usize = 0;
+
+static DTB_PTR: LazyInit<usize> = LazyInit::new();
+
+pub(crate) fn rust_main(hartid: usize, device_tree: usize) {
+ crate::clear_bss();
+ // Init allocator
+ percpu::init(4);
+ percpu::set_local_thread_pointer(hartid);
+ CPU_ID.write_current(hartid);
+
+ interrupt::init_interrupt();
+
+ let (_hartid, device_tree) = boards::init_device(hartid, device_tree | VIRT_ADDR_START);
+
+ // 开启 SUM
+ unsafe {
+ // 开启浮点运算
+ sstatus::set_fs(sstatus::FS::Dirty);
+ }
+
+ CPU_NUM.init_by(match unsafe { Fdt::from_ptr(device_tree as *const u8) } {
+ Ok(fdt) => fdt.cpus().count(),
+ Err(_) => 1,
+ });
+
+ DTB_PTR.init_by(device_tree);
+
+ unsafe { crate::api::_main_for_arch(hartid) };
+ shutdown();
+}
+
+pub(crate) extern "C" fn rust_secondary_main(hartid: usize) {
+ percpu::set_local_thread_pointer(hartid);
+ CPU_ID.write_current(hartid);
+
+ interrupt::init_interrupt();
+
+ let (hartid, _device_tree) = boards::init_device(hartid, 0);
+
+ unsafe {
+ // 开启浮点运算
+ sstatus::set_fs(sstatus::FS::Dirty);
+ }
+
+ info!("secondary hart {} started", hartid);
+ unsafe { crate::api::_main_for_arch(hartid) };
+ shutdown();
+}
+
+#[inline]
+pub fn wfi() {
+ unsafe {
+ riscv::register::sstatus::clear_sie();
+ riscv::asm::wfi();
+ riscv::register::sstatus::set_sie();
+ }
+}
+
+pub fn hart_id() -> usize {
+ CPU_ID.read_current()
+}
+
+pub fn arch_init() {
+ let mut buffer = Vec::new();
+ if let Ok(fdt) = unsafe { Fdt::from_ptr(*DTB_PTR as *const u8) } {
+ unsafe {
+ buffer.extend_from_slice(slice::from_raw_parts(
+ *DTB_PTR as *const u8,
+ fdt.total_size(),
+ ));
+ }
+ }
+ DTB_BIN.init_by(buffer);
+ let mut mem_area = Vec::new();
+ if let Ok(fdt) = Fdt::new(&DTB_BIN) {
+ info!("There has {} CPU(s)", fdt.cpus().count());
+ fdt.memory().regions().for_each(|x| {
+ info!(
+ "memory region {:#X} - {:#X}",
+ x.starting_address as usize,
+ x.starting_address as usize + x.size.unwrap()
+ );
+ mem_area.push((
+ x.starting_address as usize | VIRT_ADDR_START,
+ x.size.unwrap_or(0),
+ ));
+ });
+ } else {
+ mem_area.push((0x8000_0000 | VIRT_ADDR_START, 0x1000_0000));
+ }
+ MEM_AREA.init_by(mem_area);
+}
+
+#[cfg(feature = "multicore")]
+/// Implement the function for multicore
+impl MultiCore {
+ /// Boot all application cores.
+ pub fn boot_all() {
+ use self::entry::secondary_start;
+ use crate::{
+ addr::VirtPage,
+ pagetable::{MappingFlags, MappingSize, PageTable},
+ };
+
+ let page_table = PageTable::current();
+
+ (0..*CPU_NUM).into_iter().for_each(|cpu| {
+ if cpu == CPU_ID.read_current() {
+ return;
+ };
+
+ // PERCPU DATA ADDRESS RANGE END
+ let cpu_addr_end = MULTI_CORE_AREA + (cpu + 1) * MULTI_CORE_AREA_SIZE;
+ let aux_core_func = (secondary_start as usize) & (!VIRT_ADDR_START);
+
+ // Ready to build multi core area.
+ // default stack size is 512K
+ for i in 0..128 {
+ page_table.map_kernel(
+ VirtPage::from_addr(cpu_addr_end - i * PageTable::PAGE_SIZE - 1),
+ frame_alloc(),
+ MappingFlags::RWX | MappingFlags::G,
+ MappingSize::Page4KB,
+ )
+ }
+
+ info!("secondary addr: {:#x}", secondary_start as usize);
+ let ret = sbi_rt::hart_start(cpu, aux_core_func, cpu_addr_end);
+ if ret.is_ok() {
+ info!("hart {} Startting successfully", cpu);
+ } else {
+ warn!("hart {} Startting failed", cpu)
+ }
+ });
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +
pub mod sigtrx;
+mod sv39;
+
+use core::arch::riscv64::sfence_vma;
+
+pub use sv39::*;
+
+use crate::addr::VirtAddr;
+use crate::pagetable::TLB;
+
+/// TLB operations
+impl TLB {
+ /// flush the TLB entry by VirtualAddress
+ /// just use it directly
+ ///
+ /// TLB::flush_vaddr(arg0); // arg0 is the virtual address(VirtAddr)
+ #[inline]
+ pub fn flush_vaddr(vaddr: VirtAddr) {
+ unsafe {
+ sfence_vma(vaddr.0, 0);
+ }
+ }
+
+ /// flush all tlb entry
+ ///
+ /// how to use ?
+ /// just
+ /// TLB::flush_all();
+ #[inline]
+ pub fn flush_all() {
+ riscv::asm::sfence_vma_all();
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +
use crate::{
+ pagetable::{PageTable, PTE},
+ VIRT_ADDR_START,
+};
+
+use super::PTEFlags;
+
+/// 汇编入口函数
+///
+/// 分配栈 初始化页表信息 并调到rust入口函数
+#[naked]
+#[no_mangle]
+#[link_section = ".sigtrx.sigreturn"]
+unsafe extern "C" fn _sigreturn() -> ! {
+ core::arch::asm!(
+ // 1. 设置栈信息
+ // sp = bootstack + (hartid + 1) * 0x10000
+ "
+ li a7, 139
+ ecall
+ ",
+ options(noreturn)
+ )
+}
+
+#[link_section = ".data.prepage.trx1"]
+static mut TRX_STEP1: [PTE; PageTable::PTE_NUM_IN_PAGE] = [PTE(0); PageTable::PTE_NUM_IN_PAGE];
+
+#[link_section = ".data.prepage.trx2"]
+static mut TRX_STEP2: [PTE; PageTable::PTE_NUM_IN_PAGE] = [PTE(0); PageTable::PTE_NUM_IN_PAGE];
+
+pub fn init() {
+ unsafe {
+ TRX_STEP1[0] = PTE::from_addr(
+ _sigreturn as usize & !VIRT_ADDR_START,
+ PTEFlags::ADUVRX.union(PTEFlags::G),
+ );
+ TRX_STEP2[0] = PTE::from_addr(TRX_STEP1.as_ptr() as usize & !VIRT_ADDR_START, PTEFlags::V);
+ }
+}
+
+pub fn get_trx_mapping() -> usize {
+ unsafe { TRX_STEP2.as_ptr() as usize & !VIRT_ADDR_START }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +
use bitflags::bitflags;
+use riscv::register::satp;
+
+use crate::addr::{PhysAddr, PhysPage, VirtAddr, VirtPage};
+use crate::kernel_page_table;
+use crate::pagetable::MappingFlags;
+use crate::pagetable::{PageTable, PTE, TLB};
+
+use super::sigtrx::get_trx_mapping;
+
+impl PTE {
+ #[inline]
+ pub const fn from_ppn(ppn: usize, flags: PTEFlags) -> Self {
+ // let flags = flags.union(PTEFlags::D);
+ let mut flags = flags;
+ if flags.contains(PTEFlags::R) | flags.contains(PTEFlags::X) {
+ flags = flags.union(PTEFlags::A)
+ }
+ if flags.contains(PTEFlags::W) {
+ flags = flags.union(PTEFlags::D)
+ }
+ // TIPS: This is prepare for the extend bits of T-HEAD C906
+ #[cfg(c906)]
+ if flags.contains(PTEFlags::G) && ppn == 0x8_0000 {
+ Self(
+ ppn << 10
+ | flags
+ .union(PTEFlags::C)
+ .union(PTEFlags::B)
+ .union(PTEFlags::K)
+ .bits() as usize,
+ )
+ } else if flags.contains(PTEFlags::G) && ppn == 0 {
+ Self(ppn << 10 | flags.union(PTEFlags::SE).union(PTEFlags::SO).bits() as usize)
+ } else {
+ Self(ppn << 10 | flags.union(PTEFlags::C).bits() as usize)
+ }
+
+ #[cfg(not(c906))]
+ Self(ppn << 10 | flags.bits() as usize)
+ }
+
+ #[inline]
+ pub const fn from_addr(addr: usize, flags: PTEFlags) -> Self {
+ Self::from_ppn(addr >> 12, flags)
+ }
+
+ #[inline]
+ pub const fn flags(&self) -> PTEFlags {
+ PTEFlags::from_bits_truncate((self.0 & 0xff) as u64)
+ }
+
+ #[inline]
+ pub const fn is_valid(&self) -> bool {
+ self.flags().contains(PTEFlags::V) && self.0 > u8::MAX as usize
+ }
+
+ /// 判断是否是大页
+ ///
+ /// 大页判断条件 V 位为 1, R/W/X 位至少有一个不为 0
+ /// PTE 页表范围 1G(0x4000_0000) 2M(0x20_0000) 4K(0x1000)
+ #[inline]
+ pub fn is_huge(&self) -> bool {
+ return self.flags().contains(PTEFlags::V)
+ && (self.flags().contains(PTEFlags::R)
+ || self.flags().contains(PTEFlags::W)
+ || self.flags().contains(PTEFlags::X));
+ }
+
+ #[inline]
+ pub(crate) fn is_table(&self) -> bool {
+ return self.flags().contains(PTEFlags::V)
+ && !(self.flags().contains(PTEFlags::R)
+ || self.flags().contains(PTEFlags::W)
+ || self.flags().contains(PTEFlags::X));
+ }
+
+ #[inline]
+ pub(crate) fn new_table(ppn: PhysPage) -> Self {
+ Self((ppn.0 << 10) | (PTEFlags::V).bits() as usize)
+ }
+
+ #[inline]
+ pub(crate) fn new_page(ppn: PhysPage, flags: PTEFlags) -> Self {
+ Self((ppn.0 << 10) | flags.bits() as usize)
+ }
+
+ #[inline]
+ pub(crate) fn address(&self) -> PhysAddr {
+ PhysAddr((self.0 << 2) & 0xFFFF_FFFF_F000)
+ }
+}
+
+bitflags! {
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ pub struct PTEFlags: u64 {
+ const V = bit!(0);
+ const R = bit!(1);
+ const W = bit!(2);
+ const X = bit!(3);
+ const U = bit!(4);
+ const G = bit!(5);
+ const A = bit!(6);
+ const D = bit!(7);
+
+ #[cfg(c906)]
+ const SO = bit!(63);
+ #[cfg(c906)]
+ const C = bit!(62);
+ #[cfg(c906)]
+ const B = bit!(61);
+ #[cfg(c906)]
+ const K = bit!(60);
+ #[cfg(c906)]
+ const SE = bit!(59);
+
+ const VRWX = Self::V.bits() | Self::R.bits() | Self::W.bits() | Self::X.bits();
+ const ADUVRX = Self::A.bits() | Self::D.bits() | Self::U.bits() | Self::V.bits() | Self::R.bits() | Self::X.bits();
+ const ADVRWX = Self::A.bits() | Self::D.bits() | Self::VRWX.bits();
+ const ADGVRWX = Self::G.bits() | Self::ADVRWX.bits();
+ }
+}
+
+impl From<MappingFlags> for PTEFlags {
+ fn from(flags: MappingFlags) -> Self {
+ if flags.is_empty() {
+ Self::empty()
+ } else {
+ let mut res = Self::V;
+ if flags.contains(MappingFlags::R) {
+ res |= PTEFlags::R | PTEFlags::A;
+ }
+ if flags.contains(MappingFlags::W) {
+ res |= PTEFlags::W | PTEFlags::D;
+ }
+ if flags.contains(MappingFlags::X) {
+ res |= PTEFlags::X;
+ }
+ if flags.contains(MappingFlags::U) {
+ res |= PTEFlags::U;
+ }
+ res
+ }
+ }
+}
+
+impl From<PTEFlags> for MappingFlags {
+ fn from(value: PTEFlags) -> Self {
+ let mut mapping_flags = MappingFlags::empty();
+ if value.contains(PTEFlags::V) {
+ mapping_flags |= MappingFlags::P;
+ }
+ if value.contains(PTEFlags::R) {
+ mapping_flags |= MappingFlags::R;
+ }
+ if value.contains(PTEFlags::W) {
+ mapping_flags |= MappingFlags::W;
+ }
+ if value.contains(PTEFlags::X) {
+ mapping_flags |= MappingFlags::X;
+ }
+ if value.contains(PTEFlags::U) {
+ mapping_flags |= MappingFlags::U;
+ }
+ if value.contains(PTEFlags::A) {
+ mapping_flags |= MappingFlags::A;
+ }
+ if value.contains(PTEFlags::D) {
+ mapping_flags |= MappingFlags::D;
+ }
+
+ mapping_flags
+ }
+}
+
+impl PageTable {
+ /// The size of the page for this platform.
+ pub(crate) const PAGE_SIZE: usize = 0x1000;
+ pub(crate) const PAGE_LEVEL: usize = 3;
+ pub(crate) const PTE_NUM_IN_PAGE: usize = 0x200;
+ pub(crate) const GLOBAL_ROOT_PTE_RANGE: usize = 0x100;
+ pub(crate) const VADDR_BITS: usize = 39;
+ pub(crate) const USER_VADDR_END: usize = (1 << Self::VADDR_BITS) - 1;
+ pub(crate) const KERNEL_VADDR_START: usize = !Self::USER_VADDR_END;
+
+ #[inline]
+ pub fn current() -> Self {
+ Self(PhysAddr(satp::read().ppn() << 12))
+ }
+
+ #[inline]
+ pub fn kernel_pte_entry(&self) -> PhysAddr {
+ self.0
+ }
+
+ #[inline]
+ pub fn restore(&self) {
+ self.release();
+ let kernel_arr = Self::get_pte_list(kernel_page_table().0);
+ let arr = Self::get_pte_list(self.0);
+ arr[0x100..].copy_from_slice(&kernel_arr[0x100..]);
+ // TODO: using map kernel in the boot instead of map here manually
+ arr[0x104] = PTE::from_addr(get_trx_mapping(), PTEFlags::V);
+ arr[0..0x100].fill(PTE(0));
+ }
+
+ #[inline]
+ pub fn change(&self) {
+ // Write page table entry for
+ satp::write((8 << 60) | (self.0 .0 >> 12));
+ TLB::flush_all();
+ }
+}
+
+impl VirtPage {
+ /// Get n level page table index of the given virtual address
+ #[inline]
+ pub fn pn_index(&self, n: usize) -> usize {
+ (self.0 >> 9 * n) & 0x1ff
+ }
+}
+
+impl VirtAddr {
+ /// Get n level page table offset of the given virtual address
+ #[inline]
+ pub fn pn_offest(&self, n: usize) -> usize {
+ self.0 % (1 << (12 + 9 * n))
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +
//! 调用 Machine 层的操作
+// 目前还不会用到全部的 SBI 调用,暂时允许未使用的变量或函数
+#![allow(unused)]
+
+use core::arch::asm;
+
+use sbi_rt::{NoReason, Shutdown};
+
+use crate::debug::DebugConsole;
+
+const SBI_SET_TIMER: usize = 0;
+const SBI_CONSOLE_PUT_CHAR: usize = 1;
+const SBI_CONSOLE_GET_CHAR: usize = 2;
+const SBI_CLEAR_IPI: usize = 3;
+const SBI_SEND_IPI: usize = 4;
+const SBI_REMOTE_FENCE_I: usize = 5;
+const SBI_REMOTE_SFENCE_VMA: usize = 6;
+const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7;
+const SBI_SHUTDOWN: usize = 8;
+
+// SBI 调用
+fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize {
+ let mut ret;
+ unsafe {
+ asm!("ecall",
+ in("a7") which,
+ inlateout("a0") arg0 => ret,
+ in("a1") arg1,
+ in("a2") arg2);
+ }
+ ret
+}
+
+/// 设置定时器
+#[inline]
+pub fn set_timer(time: usize) {
+ sbi_rt::set_timer(time as _);
+}
+
+impl DebugConsole {
+ #[inline]
+ #[allow(deprecated)]
+ pub fn putchar(ch: u8) {
+ sbi_rt::legacy::console_putchar(ch as _);
+ }
+
+ #[inline]
+ #[allow(deprecated)]
+ pub fn getchar() -> Option<u8> {
+ let c = sbi_rt::legacy::console_getchar() as u8;
+ match c == u8::MAX {
+ true => None,
+ _ => Some(c),
+ }
+ }
+}
+
+/// 调用 SBI_SHUTDOWN 来关闭操作系统(直接退出 QEMU)
+#[inline]
+pub fn shutdown() -> ! {
+ // sbi_rt::legacy::shutdown();
+ sbi_rt::system_reset(Shutdown, NoReason);
+ unreachable!()
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +
use crate::currrent_arch::boards::CLOCK_FREQ;
+use crate::time::Time;
+use riscv::register::{sie, time};
+
+use super::set_timer;
+
+impl Time {
+ #[inline]
+ pub fn get_freq() -> usize {
+ CLOCK_FREQ
+ }
+
+ #[inline]
+ pub fn now() -> Self {
+ Self(time::read())
+ }
+}
+
+// 设置下一次时钟中断触发时间
+#[inline]
+pub fn set_next_timeout() {
+ // 调用sbi设置定时器
+ set_timer(time::read() + CLOCK_FREQ / 100);
+}
+
+pub fn init() {
+ unsafe {
+ sie::set_stimer();
+ }
+ set_next_timeout();
+ info!("initialize timer interrupt");
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +
/// Time struct and its interface
+///
+/// You can use this to get time from ticks
+///
+/// ### get current time
+/// ```rust
+/// Time::now();
+/// ```
+///
+/// ### get current cpu's frequency
+/// ```rust
+/// Time::get_freq();
+/// ```
+///
+/// ### get how many nanoseconds have passed.
+/// ```rust
+/// Time::now().to_nsec();
+/// ```
+///
+/// ### get how many microseconds have passed.
+/// ```rust
+/// Time::now().to_usec();
+/// ```
+///
+/// ### get how many millisecond have passed.
+/// ```rust
+/// Time::now().to_msec();
+/// ```
+///
+/// ### get how may ticks have passed
+/// ```rust
+/// Time::now().raw();
+/// ```
+///
+/// ### convert ticks to time
+/// ```rust
+/// Time::from_raw(Time::now().raw());
+/// ```
+///
+
+#[derive(Clone, Copy, Debug)]
+pub struct Time(pub(crate) usize);
+
+impl Time {
+ #[inline]
+ pub fn to_msec(&self) -> usize {
+ self.0 * 1_000 / Self::get_freq()
+ }
+
+ #[inline]
+ pub fn to_usec(&self) -> usize {
+ self.0 * 1000_000 / Self::get_freq()
+ }
+
+ /// Converts hardware ticks to nanoseconds.
+ #[inline]
+ pub fn to_nsec(&self) -> usize {
+ self.0 * 1000_000_000 / Self::get_freq()
+ }
+
+ #[inline]
+ pub fn raw(&self) -> usize {
+ self.0
+ }
+
+ #[inline]
+ pub fn from_raw(raw: usize) -> Self {
+ Self(raw)
+ }
+}
+
fn:
) to \
+ restrict the search to a given item kind.","Accepted kinds are: fn
, mod
, struct
, \
+ enum
, trait
, type
, macro
, \
+ and const
.","Search functions by type signature (e.g., vec -> usize
or \
+ -> vec
or String, enum:Cow -> bool
)","You can look for items with an exact name by putting double quotes around \
+ your request: \"string\"
","Look for functions that accept or return \
+ slices and \
+ arrays by writing \
+ square brackets (e.g., -> [u8]
or [] -> Option
)","Look for items inside another one by searching for a path: vec::Vec
",].map(x=>""+x+"
").join("");const div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="${value.replaceAll(" ", " ")}
`}else{error[index]=value}});output+=`