From da74c628ec15d73153efb6e57f7dc3d1dd104c18 Mon Sep 17 00:00:00 2001 From: cfgbd Date: Sun, 14 Oct 2018 11:13:36 +0800 Subject: [PATCH 01/26] ignore eclipse files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 637c5b18..f0bf97ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ build target /kernel/src/arch/x86_64/interrupt/vector.asm + +# for eclipse +.project \ No newline at end of file From 70abc9ec2ed52ddcdb59e38be4ac062bbbaaac95 Mon Sep 17 00:00:00 2001 From: equation314 Date: Fri, 26 Oct 2018 11:10:11 +0800 Subject: [PATCH 02/26] ignore .DS_Store --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f0bf97ba..47d3bb28 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,7 @@ build target /kernel/src/arch/x86_64/interrupt/vector.asm +.DS_Store + # for eclipse -.project \ No newline at end of file +.project From 1140d32aaa16081c0a97b8876e5ecec9ba0bf553 Mon Sep 17 00:00:00 2001 From: equation314 Date: Fri, 26 Oct 2018 11:20:03 +0800 Subject: [PATCH 03/26] add arch=aarch64 & board=raspi3 to Makefile --- kernel/Cargo.toml | 2 + kernel/Makefile | 93 +++++++++++++++++++++---------------- kernel/aarch64-blog_os.json | 29 ++++++++++++ 3 files changed, 85 insertions(+), 39 deletions(-) create mode 100644 kernel/aarch64-blog_os.json diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 0afa030f..7bde15d5 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -8,6 +8,8 @@ use_apic = [] link_user_program = [] no_bbl = [] +board_raspi3 = [] + [profile.dev] # MUST >= 1 : Enable RVO to avoid stack overflow # MUST <= 1 : Avoid double fault at -O2 T_T diff --git a/kernel/Makefile b/kernel/Makefile index 00531848..9f54a192 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -8,13 +8,16 @@ # make clean Clean # # Options: -# arch = x86_64 | riscv32 +# arch = x86_64 | riscv32 | aarch64 # d = int | in_asm | ... QEMU debug info # mode = debug | release # LOG = off | error | warn | info | debug | trace -# board Only available on riscv32, build without bbl, run on board +# board = fpga Only available on riscv32, build without bbl, run on board +# | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+ -arch ?= riscv32 +arch ?= aarch64 +board ?= raspi3 +prefix ?= $(arch)-none-elf mode ?= debug LOG ?= debug @@ -27,21 +30,41 @@ user_bin_path := ../user/target/$(arch)-ucore/debug user_bins := $(patsubst $(user_bin_path)/%.d, $(user_bin_path)/%, $(wildcard $(user_bin_path)/*.d)) user_obj := build/$(arch)/user.o SFSIMG := ../user/ucore32.img + +### qemu options ### ifeq ($(arch), x86_64) qemu_opts := \ -drive format=raw,file=$(bootimage) \ -drive format=raw,file=$(SFSIMG),media=disk,cache=writeback \ -smp 4 \ -serial mon:stdio \ - -device isa-debug-exit -endif -ifeq ($(arch), riscv32) -qemu_opts := -machine virt -kernel $(bin) -nographic + -device isa-debug-exit \ + -nographic +else ifeq ($(arch), riscv32) +qemu_opts := \ + -machine virt \ + -nographic \ + -kernel $(bin) +else ifeq ($(arch), aarch64) +qemu_opts := \ + -machine $(board) \ + -serial null -serial mon:stdio \ + -nographic \ + -kernel $(bin) endif -ifdef board +ifdef d +qemu_opts := $(qemu_opts) -d $(d) +endif + + + +### build args ### +ifeq ($(arch), riscv32) +ifeq ($(board), fpga) features := $(features) no_bbl endif +endif # Link user binaries at ../user ifdef link_user @@ -49,37 +72,25 @@ features := $(features) link_user_program assembly_object_files := $(assembly_object_files) $(user_obj) endif -ifdef d -qemu_opts := $(qemu_opts) -d $(d) -endif - +features := $(features) board_$(board) build_args := --target $(target).json --features "$(features)" ifeq ($(mode), release) build_args := $(build_args) --release endif -ifeq ($(OS),Windows_NT) -uname := Win32 -else -uname := $(shell uname) -endif -ifeq ($(uname), Darwin) -prefix := x86_64-elf- -endif -ifeq ($(arch), riscv32) -prefix := riscv64-unknown-elf- -endif -ld := $(prefix)ld -objdump := $(prefix)objdump -cc := $(prefix)gcc -as := $(prefix)as +### prefix ### +ld := $(prefix)-ld +objdump := $(prefix)-objdump +objcopy := $(prefix)-objcopy +cc := $(prefix)-gcc +as := $(prefix)-as .PHONY: all clean run build asm doc justrun kernel -all: $(kernel) +all: kernel clean: @cargo clean @@ -108,20 +119,24 @@ elf-h: @$(objdump) -h $(kernel) $(bin): kernel -ifdef board +ifeq ($(arch), riscv32) +ifeq ($(board), fpga) @cp $(kernel) $@ else @cd ../riscv-pk && \ - mkdir -p build && \ - cd build && \ - ../configure \ - --enable-32bit \ - --enable-logo \ - --disable-fp-emulation \ - --host=riscv64-unknown-elf \ - --with-payload=$(abspath $(kernel)) && \ - make && \ - cp bbl ../../kernel/$@ + mkdir -p build && \ + cd build && \ + ../configure \ + --enable-32bit \ + --enable-logo \ + --disable-fp-emulation \ + --host=riscv64-unknown-elf \ + --with-payload=$(abspath $(kernel)) && \ + make && \ + cp bbl ../../kernel/$@ +endif +else ifeq ($(arch), aarch64) + $(objcopy) $(kernel) -O binary $@ endif kernel: diff --git a/kernel/aarch64-blog_os.json b/kernel/aarch64-blog_os.json new file mode 100644 index 00000000..048db110 --- /dev/null +++ b/kernel/aarch64-blog_os.json @@ -0,0 +1,29 @@ +{ + "abi-blacklist": [ + "stdcall", + "fastcall", + "vectorcall", + "thiscall", + "win64", + "sysv64" + ], + "arch": "aarch64", + "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + "executables": true, + "linker": "aarch64-none-elf-ld", + "linker-flavor": "ld", + "linker-is-gnu": true, + "llvm-target": "aarch64-unknown-none", + "no-compiler-rt": true, + "features": "+a53,+strict-align", + "max-atomic-width": 128, + "os": "none", + "panic": "abort", + "panic-strategy": "abort", + "position-independent-executables": true, + "target-c-int-width": "32", + "target-endian": "little", + "target-pointer-width": "64", + "target-family": "unix", + "disable-redzone": true +} From 174e0da3b6d41db589e5606253582d351c5b848b Mon Sep 17 00:00:00 2001 From: equation314 Date: Fri, 26 Oct 2018 11:21:43 +0800 Subject: [PATCH 04/26] aarch64: basic framework --- kernel/src/arch/aarch64/board/raspi3/mod.rs | 5 + kernel/src/arch/aarch64/context.rs | 62 ++++++ kernel/src/arch/aarch64/interrupt.rs | 42 +++++ kernel/src/arch/aarch64/io.rs | 13 ++ kernel/src/arch/aarch64/memory.rs | 8 + kernel/src/arch/aarch64/mod.rs | 34 ++++ kernel/src/arch/aarch64/paging.rs | 199 ++++++++++++++++++++ kernel/src/consts.rs | 19 +- kernel/src/fs.rs | 6 + kernel/src/lib.rs | 4 + kernel/src/memory.rs | 4 + 11 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 kernel/src/arch/aarch64/board/raspi3/mod.rs create mode 100644 kernel/src/arch/aarch64/context.rs create mode 100644 kernel/src/arch/aarch64/interrupt.rs create mode 100644 kernel/src/arch/aarch64/io.rs create mode 100644 kernel/src/arch/aarch64/memory.rs create mode 100644 kernel/src/arch/aarch64/mod.rs create mode 100644 kernel/src/arch/aarch64/paging.rs diff --git a/kernel/src/arch/aarch64/board/raspi3/mod.rs b/kernel/src/arch/aarch64/board/raspi3/mod.rs new file mode 100644 index 00000000..db63357f --- /dev/null +++ b/kernel/src/arch/aarch64/board/raspi3/mod.rs @@ -0,0 +1,5 @@ +//! Raspberry PI 3 Model B/B+ + +pub fn init() { + // TODO +} diff --git a/kernel/src/arch/aarch64/context.rs b/kernel/src/arch/aarch64/context.rs new file mode 100644 index 00000000..4ca8b569 --- /dev/null +++ b/kernel/src/arch/aarch64/context.rs @@ -0,0 +1,62 @@ +//! Trapframe and context definitions for aarch64. + +/// TODO +#[repr(C)] +#[derive(Debug)] +pub struct TrapFrame { + // TODO +} + +///TODO +#[derive(Debug)] +pub struct Context { + // TODO +} + +impl Context { + /// TODO + #[inline(never)] + pub unsafe extern fn switch(&mut self, target: &mut Self) { + unimplemented!() + } + + /// TODO + pub unsafe fn null() -> Self { + unimplemented!() + } + + /// TODO + pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, cr3: usize) -> Self { + unimplemented!() + } + + /// TODO + pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, is32: bool, cr3: usize) -> Self { + unimplemented!() + } + + /// TODO + pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, cr3: usize) -> Self { + unimplemented!() + } +} + +#[inline(always)] +pub unsafe fn enable() { + unimplemented!() +} + +#[inline(always)] +pub unsafe fn disable() { + unimplemented!() +} + +#[inline(always)] +pub unsafe fn disable_and_store() -> usize { + unimplemented!() +} + +#[inline(always)] +pub unsafe fn restore(flags: usize) { + unimplemented!() +} diff --git a/kernel/src/arch/aarch64/interrupt.rs b/kernel/src/arch/aarch64/interrupt.rs new file mode 100644 index 00000000..1566afde --- /dev/null +++ b/kernel/src/arch/aarch64/interrupt.rs @@ -0,0 +1,42 @@ +//! Interrupt handler implementation on raspi3. + +pub use self::context::*; + +#[path = "context.rs"] +mod context; + +/// Initialize the trap to enable the interrupt. +pub fn init() { + // TODO + // info!("interrupt: init end"); +} + +/// Enable the interrupt. +#[inline(always)] +pub unsafe fn enable() { + // TODO +} + +/// Disable the interrupt. +#[inline(always)] +pub unsafe fn disable() { + // TODO +} + +/// Disable the interrupt and store the status. +/// +/// return: status(usize) +#[inline(always)] +pub unsafe fn disable_and_store() -> usize { + // TODO + 0 +} + +/// Use the original status to restore the process +/// +/// Arguments: +/// * flags: original status(usize) +#[inline(always)] +pub unsafe fn restore(flags: usize) { + // TODO +} diff --git a/kernel/src/arch/aarch64/io.rs b/kernel/src/arch/aarch64/io.rs new file mode 100644 index 00000000..70f40350 --- /dev/null +++ b/kernel/src/arch/aarch64/io.rs @@ -0,0 +1,13 @@ +//! Serial driver for aarch64. + +use core::fmt::{Arguments}; + +/// TODO +pub fn getchar() -> char { + unimplemented!() +} + +/// TODO +pub fn putfmt(fmt: Arguments<'_>) { + unimplemented!() +} diff --git a/kernel/src/arch/aarch64/memory.rs b/kernel/src/arch/aarch64/memory.rs new file mode 100644 index 00000000..05fff9de --- /dev/null +++ b/kernel/src/arch/aarch64/memory.rs @@ -0,0 +1,8 @@ +//! Memory initialization for aarch64. + +use ucore_memory::PAGE_SIZE; + +/// Memory initialization. +pub fn init() { + // TODO +} diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs new file mode 100644 index 00000000..c19cd975 --- /dev/null +++ b/kernel/src/arch/aarch64/mod.rs @@ -0,0 +1,34 @@ +//! Entrance and initialization for aarch64. + +pub mod io; +pub mod paging; +pub mod memory; +pub mod interrupt; + +#[cfg(feature = "board_raspi3")] +#[path = "board/raspi3/mod.rs"] +pub mod board; + +/// TODO +/// The entry point of kernel +#[no_mangle] // don't mangle the name of this function +pub extern fn rust_main() -> ! { + println!("Hello ARM64!"); + + // First init log mod, so that we can print log info. + // ::logging::init(); + // Init trap handling. + // interrupt::init(); + // Init physical memory management and heap. + // memory::init(); + // Now heap is available + // timer::init(); + + // Init board. + board::init(); + ::kmain(); +} + +// global_asm!(include_str!("boot/boot.asm")); +// global_asm!(include_str!("boot/entry.asm")); +// global_asm!(include_str!("boot/trap.asm")); diff --git a/kernel/src/arch/aarch64/paging.rs b/kernel/src/arch/aarch64/paging.rs new file mode 100644 index 00000000..6c218396 --- /dev/null +++ b/kernel/src/arch/aarch64/paging.rs @@ -0,0 +1,199 @@ +//! Page table implementations for aarch64. + +use ucore_memory::memory_set::*; +use ucore_memory::paging::*; + +type VirtAddr = usize; +type PhysAddr = usize; + +/// TODO +pub struct ActivePageTable { + // TODO +} + +impl ActivePageTable { + /// TODO + pub unsafe fn new() -> Self { + unimplemented!() + } +} + +impl PageTable for ActivePageTable { + type Entry = PageEntry; + + fn map(&mut self, addr: VirtAddr, target: PhysAddr) -> &mut Self::Entry { + unimplemented!() + } + fn unmap(&mut self, addr: VirtAddr) { + unimplemented!() + } + + fn get_entry(&mut self, addr: VirtAddr) -> &mut Self::Entry { + unimplemented!() + } + + // For testing with mock + fn get_page_slice_mut<'a,'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8] { + unimplemented!() + } + + fn read(&mut self, addr: VirtAddr) -> u8 { + unimplemented!() + } + + fn write(&mut self, addr: VirtAddr, data: u8) { + unimplemented!() + } +} + +/// TODO +pub struct PageEntry { + // TODO +} + +impl Entry for PageEntry { + /// IMPORTANT! + /// This must be called after any change to ensure it become effective. + /// Usually this will make a flush to TLB/MMU. + fn update(&mut self) { + unimplemented!() + } + + /// Will be set when accessed + fn accessed(&self) -> bool { + unimplemented!() + } + + /// Will be set when written + fn dirty(&self) -> bool { + unimplemented!() + } + + /// Will PageFault when try to write page where writable=0 + fn writable(&self) -> bool { + unimplemented!() + } + + /// Will PageFault when try to access page where present=0 + fn present(&self) -> bool { + unimplemented!() + } + + + fn clear_accessed(&mut self) { + unimplemented!() + } + + fn clear_dirty(&mut self) { + unimplemented!() + } + + fn set_writable(&mut self, value: bool) { + unimplemented!() + } + + fn set_present(&mut self, value: bool) { + unimplemented!() + } + + + fn target(&self) -> PhysAddr { + unimplemented!() + } + + fn set_target(&mut self, target: PhysAddr) { + unimplemented!() + } + + + // For Copy-on-write extension + fn writable_shared(&self) -> bool { + unimplemented!() + } + + fn readonly_shared(&self) -> bool { + unimplemented!() + } + + fn set_shared(&mut self, writable: bool) { + unimplemented!() + } + + fn clear_shared(&mut self) { + unimplemented!() + } + + + // For Swap extension + fn swapped(&self) -> bool { + unimplemented!() + } + + fn set_swapped(&mut self, value: bool) { + unimplemented!() + } + + + fn user(&self) -> bool { + unimplemented!() + } + + fn set_user(&mut self, value: bool) { + unimplemented!() + } + + fn execute(&self) -> bool { + unimplemented!() + } + + fn set_execute(&mut self, value: bool) { + unimplemented!() + } + +} + +/// TODO +pub struct InactivePageTable0 { + // TODO +} + +/// TODO +impl InactivePageTable for InactivePageTable0 { + type Active = ActivePageTable; + + fn new() -> Self { + unimplemented!() + } + + fn new_bare() -> Self { + unimplemented!() + } + + fn edit(&mut self, f: impl FnOnce(&mut Self::Active)) { + unimplemented!() + } + + unsafe fn activate(&self) { + unimplemented!() + } + + unsafe fn with(&self, f: impl FnOnce()) { + unimplemented!() + } + + fn token(&self) -> usize { + unimplemented!() + } + + fn alloc_frame() -> Option { + unimplemented!() + } + + fn dealloc_frame(target: PhysAddr) { + unimplemented!() + } + + fn alloc_stack() -> Stack { + unimplemented!() + } +} diff --git a/kernel/src/consts.rs b/kernel/src/consts.rs index 4dddae09..b2cdefef 100644 --- a/kernel/src/consts.rs +++ b/kernel/src/consts.rs @@ -4,6 +4,8 @@ pub use self::riscv::*; #[cfg(target_arch = "x86_64")] pub use self::x86_64::*; +#[cfg(target_arch = "aarch64")] +pub use self::aarch64::*; pub const MAX_CPU_NUM: usize = 8; pub const MAX_PROCESS_NUM: usize = 48; @@ -125,4 +127,19 @@ mod x86_64 { /// Offset for usage in other temporary pages pub const USER_TMP_MISC_OFFSET: usize = USER_TMP_TLS_OFFSET + PML4_SIZE; pub const USER_TMP_MISC_PML4: usize = (USER_TMP_MISC_OFFSET & PML4_MASK) / PML4_SIZE; -} \ No newline at end of file +} + +#[cfg(target_arch = "aarch64")] +mod aarch64 { + //! TODO: replace unmiplemented consts with real value + const UNIMPLEMENTED: usize = 0; + pub const KERNEL_OFFSET: usize = UNIMPLEMENTED; + pub const KERNEL_PML4: usize = UNIMPLEMENTED; + pub const KERNEL_HEAP_OFFSET: usize = UNIMPLEMENTED; + pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024; + pub const MEMORY_OFFSET: usize = UNIMPLEMENTED; + pub const MEMORY_END: usize = UNIMPLEMENTED; + pub const USER_STACK_OFFSET: usize = UNIMPLEMENTED; + pub const USER_STACK_SIZE: usize = UNIMPLEMENTED; + pub const USER32_STACK_OFFSET: usize = UNIMPLEMENTED; +} diff --git a/kernel/src/fs.rs b/kernel/src/fs.rs index fe20c6c7..4dcaa141 100644 --- a/kernel/src/fs.rs +++ b/kernel/src/fs.rs @@ -23,8 +23,14 @@ pub fn shell() { } Box::new(unsafe { MemBuf::new(_binary_user_riscv_img_start, _binary_user_riscv_img_end) }) }; + #[cfg(target_arch = "x86_64")] let device = Box::new(&ide::DISK1); + + #[cfg(target_arch = "aarch64")] + // TODO + let device: Box = unimplemented!(); + let sfs = SimpleFileSystem::open(device).expect("failed to open SFS"); let root = sfs.root_inode(); let files = root.borrow().list().unwrap(); diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 4a23294a..8305a771 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -60,6 +60,10 @@ pub mod arch; #[path = "arch/riscv32/mod.rs"] pub mod arch; +#[cfg(target_arch = "aarch64")] +#[path = "arch/aarch64/mod.rs"] +pub mod arch; + pub fn kmain() -> ! { process::init(); unsafe { arch::interrupt::enable(); } diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index 0f203f37..bbe78dbb 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -17,6 +17,10 @@ pub type FrameAlloc = BitAlloc64K; #[cfg(target_arch = "riscv32")] pub type FrameAlloc = BitAlloc4K; +// Raspberry Pi 3 has 1G memory +#[cfg(target_arch = "aarch64")] +pub type FrameAlloc = BitAlloc64K; + lazy_static! { pub static ref FRAME_ALLOCATOR: Mutex = Mutex::new(FrameAlloc::default()); } From cc936ded35960875a93e67031f16048aaf377655 Mon Sep 17 00:00:00 2001 From: equation314 Date: Fri, 26 Oct 2018 22:02:24 +0800 Subject: [PATCH 05/26] aarch64: bootable in qemu --- kernel/Makefile | 7 +- kernel/aarch64-blog_os.json | 6 ++ kernel/src/arch/aarch64/boot/boot.S | 99 ++++++++++++++++++++++++++ kernel/src/arch/aarch64/boot/linker.ld | 39 ++++++++++ kernel/src/arch/aarch64/mod.rs | 4 +- tools/gdbinit | 3 + 6 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 kernel/src/arch/aarch64/boot/boot.S create mode 100644 kernel/src/arch/aarch64/boot/linker.ld create mode 100644 tools/gdbinit diff --git a/kernel/Makefile b/kernel/Makefile index 9f54a192..62dde62c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -87,6 +87,7 @@ objdump := $(prefix)-objdump objcopy := $(prefix)-objcopy cc := $(prefix)-gcc as := $(prefix)-as +gdb := $(prefix)-gdb .PHONY: all clean run build asm doc justrun kernel @@ -103,8 +104,10 @@ run: build justrun justrun: @qemu-system-$(arch) $(qemu_opts) || [ $$? -eq 11 ] # run qemu and assert it exit 11 -debug: $(bin) +debug: $(kernel) $(bin) @qemu-system-$(arch) $(qemu_opts) -s -S & + @sleep 1 + @$(gdb) $(kernel) -x ../tools/gdbinit ifeq ($(arch), x86_64) build: kernel @@ -136,7 +139,7 @@ else cp bbl ../../kernel/$@ endif else ifeq ($(arch), aarch64) - $(objcopy) $(kernel) -O binary $@ + $(objcopy) $(kernel) --strip-all -O binary $@ endif kernel: diff --git a/kernel/aarch64-blog_os.json b/kernel/aarch64-blog_os.json index 048db110..8c9ab023 100644 --- a/kernel/aarch64-blog_os.json +++ b/kernel/aarch64-blog_os.json @@ -13,6 +13,11 @@ "linker": "aarch64-none-elf-ld", "linker-flavor": "ld", "linker-is-gnu": true, + "pre-link-args": { + "ld": [ + "-Tsrc/arch/aarch64/boot/linker.ld" + ] + }, "llvm-target": "aarch64-unknown-none", "no-compiler-rt": true, "features": "+a53,+strict-align", @@ -20,6 +25,7 @@ "os": "none", "panic": "abort", "panic-strategy": "abort", + "relocation-model": "static", "position-independent-executables": true, "target-c-int-width": "32", "target-endian": "little", diff --git a/kernel/src/arch/aarch64/boot/boot.S b/kernel/src/arch/aarch64/boot/boot.S new file mode 100644 index 00000000..ab0601cc --- /dev/null +++ b/kernel/src/arch/aarch64/boot/boot.S @@ -0,0 +1,99 @@ +# TODO rewrite in Rust, use crate cortex-a + +.section .text.boot + +.global _start +_start: + # read cpu affinity, start core 0, halt rest + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, setup + +halt: + # core affinity != 0, halt it + wfe + b halt + +setup: + # store the desired EL1 stack pointer in x1 + adr x1, _start + + # read the current exception level into x0 (ref: C5.2.1) + mrs x0, CurrentEL + and x0, x0, #0b1100 + lsr x0, x0, #2 + +switch_to_el2: + # switch to EL2 if we're in EL3. otherwise switch to EL1 + cmp x0, #2 + beq switch_to_el1 + + # set-up SCR_EL3 (bits 0, 4, 5, 7, 8, 10) (A53: 4.3.42) + mov x0, #0x5b1 + msr scr_el3, x0 + + # set-up SPSR_EL3 (bits 0, 3, 6, 7, 8, 9) (ref: C5.2.20) + mov x0, #0x3c9 + msr spsr_el3, x0 + + # switch + adr x0, switch_to_el1 + msr elr_el3, x0 + + eret + +switch_to_el1: + # switch to EL1 if we're not already in EL1. otherwise continue with start + cmp x0, #1 + beq set_stack + + # set the stack-pointer for EL1 + msr sp_el1, x1 + + # set-up HCR_EL2, enable AArch64 in EL1 (bits 1, 31) (ref: D10.2.45) + mov x0, #0x0002 + movk x0, #0x8000, lsl #16 + msr hcr_el2, x0 + + # Set SCTLR to known state (RES1: 11, 20, 22, 23, 28, 29) (ref: D10.2.100) + mov x0, #0x0800 + movk x0, #0x30d0, lsl #16 + msr sctlr_el1, x0 + + # set-up SPSR_EL2 (bits 0, 2, 6, 7, 8, 9) (ref: C5.2.19) + mov x0, #0x3c5 + msr spsr_el2, x0 + + # enable CNTP for EL1/EL0 (ref: D7.5.2, D7.5.13) + # NOTE: This doesn't actually enable the counter stream. + mrs x0, cnthctl_el2 + orr x0, x0, #3 + msr cnthctl_el2, x0 + msr cntvoff_el2, xzr + + # switch + adr x0, set_stack + msr elr_el2, x0 + + eret + +set_stack: + # set the current stack pointer + mov sp, x1 + +zero_bss: + # load the start address and number of bytes in BSS section + ldr x1, =__bss_start + ldr x2, =__bss_length + +zero_bss_loop: + # zero out the BSS section, 64-bits at a time + cbz x2, go_kmain + str xzr, [x1], #8 + sub x2, x2, #8 + cbnz x2, zero_bss_loop + +go_kmain: + # jump to rust_main, which shouldn't return. halt if it does + bl rust_main + b halt diff --git a/kernel/src/arch/aarch64/boot/linker.ld b/kernel/src/arch/aarch64/boot/linker.ld new file mode 100644 index 00000000..ce4c0c2a --- /dev/null +++ b/kernel/src/arch/aarch64/boot/linker.ld @@ -0,0 +1,39 @@ +ENTRY(_start) + +SECTIONS { + . = 0x80000; /* Raspbery Pi 3 Aarch64 (kernel8.img) load address */ + + /* start of the binary */ + _start = .; + + .text : { + KEEP(*(.text.boot)) /* from boot.S */ + *(.text .text.* .gnu.linkonce.t*) + } + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r*) + } + + .data : { + *(.data .data.* .gnu.linkonce.d*) + } + + .bss (NOLOAD) : { + . = ALIGN(32); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + . = ALIGN(8); + __bss_end = .; + } + + /* end of the binary */ + _end = ALIGN(8); + + /* number of bytes in BSS section and complete binary */ + __bss_length = (__bss_end - __bss_start); + __binary_length = (_end - _start); + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index c19cd975..137941c8 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -29,6 +29,4 @@ pub extern fn rust_main() -> ! { ::kmain(); } -// global_asm!(include_str!("boot/boot.asm")); -// global_asm!(include_str!("boot/entry.asm")); -// global_asm!(include_str!("boot/trap.asm")); +global_asm!(include_str!("boot/boot.S")); diff --git a/tools/gdbinit b/tools/gdbinit new file mode 100644 index 00000000..5041b6e7 --- /dev/null +++ b/tools/gdbinit @@ -0,0 +1,3 @@ +target remote :1234 +break rust_main +continue From addf49ffdb2816049f8a42de637152bdde34b18b Mon Sep 17 00:00:00 2001 From: equation314 Date: Sat, 27 Oct 2018 02:45:47 +0800 Subject: [PATCH 06/26] aarch64: add crate bcm2837, implement GPIO --- crate/bcm2837/Cargo.toml | 7 + crate/bcm2837/src/asm.rs | 10 ++ crate/bcm2837/src/gpio.rs | 159 ++++++++++++++++++++ crate/bcm2837/src/lib.rs | 11 ++ crate/bcm2837/src/mini_uart.rs | 1 + kernel/Cargo.lock | 14 +- kernel/Cargo.toml | 5 +- kernel/src/arch/aarch64/board/raspi3/mod.rs | 4 + kernel/src/arch/aarch64/mod.rs | 9 +- 9 files changed, 212 insertions(+), 8 deletions(-) create mode 100644 crate/bcm2837/Cargo.toml create mode 100644 crate/bcm2837/src/asm.rs create mode 100644 crate/bcm2837/src/gpio.rs create mode 100644 crate/bcm2837/src/lib.rs create mode 100644 crate/bcm2837/src/mini_uart.rs diff --git a/crate/bcm2837/Cargo.toml b/crate/bcm2837/Cargo.toml new file mode 100644 index 00000000..969c995f --- /dev/null +++ b/crate/bcm2837/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "bcm2837" +version = "0.1.0" +authors = ["equation314 "] + +[dependencies] +volatile = "0.2.4" diff --git a/crate/bcm2837/src/asm.rs b/crate/bcm2837/src/asm.rs new file mode 100644 index 00000000..72f4c739 --- /dev/null +++ b/crate/bcm2837/src/asm.rs @@ -0,0 +1,10 @@ +//! utility assembly instructions + +/// delay for some clocks +#[inline] +pub unsafe fn delay(clock: u32) { + #[cfg(target_arch = "aarch64")] + asm!("1: subs x0, x0, #1; bne 1b;" + :: "{x0}"(clock) + :: "volatile"); +} diff --git a/crate/bcm2837/src/gpio.rs b/crate/bcm2837/src/gpio.rs new file mode 100644 index 00000000..aa2f9efe --- /dev/null +++ b/crate/bcm2837/src/gpio.rs @@ -0,0 +1,159 @@ +use super::IO_BASE; +use super::asm::delay; +use core::marker::PhantomData; +use volatile::{ReadOnly, Volatile, WriteOnly}; + +/// The base address of the `GPIO` registers. +const GPIO_BASE: usize = IO_BASE + 0x200000; + +/// An alternative GPIO function. +#[repr(u8)] +pub enum Function { + Input = 0b000, + Output = 0b001, + Alt0 = 0b100, + Alt1 = 0b101, + Alt2 = 0b110, + Alt3 = 0b111, + Alt4 = 0b011, + Alt5 = 0b010, +} + +#[repr(C)] +#[allow(non_snake_case)] +struct Registers { + FSEL: [Volatile; 6], + __reserved0: u32, + SET: [WriteOnly; 2], + __reserved1: u32, + CLR: [WriteOnly; 2], + __reserved2: u32, + LEV: [ReadOnly; 2], + __reserved3: u32, + EDS: [Volatile; 2], + __reserved4: u32, + REN: [Volatile; 2], + __reserved5: u32, + FEN: [Volatile; 2], + __reserved6: u32, + HEN: [Volatile; 2], + __reserved7: u32, + LEN: [Volatile; 2], + __reserved8: u32, + AREN: [Volatile; 2], + __reserved9: u32, + AFEN: [Volatile; 2], + __reserved10: u32, + PUD: Volatile, + PUDCLK: [Volatile; 2], +} + +/// Possible states for a GPIO pin. +pub enum Uninitialized {} +pub enum Input {} +pub enum Output {} +pub enum Alt {} + +/// A GPIO pin in state `State`. +/// +/// The `State` generic always corresponds to an uninstantiatable type that is +/// use solely to mark and track the state of a given GPIO pin. A `Gpio` +/// structure starts in the `Uninitialized` state and must be transitions into +/// one of `Input`, `Output`, or `Alt` via the `into_input`, `into_output`, and +/// `into_alt` methods before it can be used. +pub struct Gpio { + pin: u8, + registers: &'static mut Registers, + _state: PhantomData, +} + +impl Gpio { + /// Transitions `self` to state `S`, consuming `self` and returning a new + /// `Gpio` instance in state `S`. This method should _never_ be exposed to + /// the public! + #[inline(always)] + fn transition(self) -> Gpio { + Gpio { + pin: self.pin, + registers: self.registers, + _state: PhantomData, + } + } + + /// Set the Gpio pull-up/pull-down state for values in `pin_value` + pub fn set_gpio_pd(&mut self, pud_value: u8) { + unsafe { + let index = if self.pin >= 32 { 1 } else { 0 }; + + self.registers.PUD.write(pud_value as u32); + delay(150); + self.registers.PUDCLK[index as usize].write((1 << self.pin) as u32); + delay(150); + self.registers.PUD.write(0); + self.registers.PUDCLK[index as usize].write(0); + } + } +} + +impl Gpio { + /// Returns a new `GPIO` structure for pin number `pin`. + /// + /// # Panics + /// + /// Panics if `pin` > `53`. + pub fn new(pin: u8) -> Gpio { + if pin > 53 { + panic!("Gpio::new(): pin {} exceeds maximum of 53", pin); + } + + Gpio { + registers: unsafe { &mut *(GPIO_BASE as *mut Registers) }, + pin: pin, + _state: PhantomData, + } + } + + /// Enables the alternative function `function` for `self`. Consumes self + /// and returns a `Gpio` structure in the `Alt` state. + pub fn into_alt(self, function: Function) -> Gpio { + self.registers.FSEL[(self.pin / 10) as usize] + .write((function as u32) << (3 * (self.pin % 10))); + self.transition() + } + + /// Sets this pin to be an _output_ pin. Consumes self and returns a `Gpio` + /// structure in the `Output` state. + pub fn into_output(self) -> Gpio { + self.into_alt(Function::Output).transition() + } + + /// Sets this pin to be an _input_ pin. Consumes self and returns a `Gpio` + /// structure in the `Input` state. + pub fn into_input(self) -> Gpio { + self.into_alt(Function::Input).transition() + } +} + +impl Gpio { + /// Sets (turns on) the pin. + pub fn set(&mut self) { + let index = if self.pin >= 32 { 1 } else { 0 }; + self.registers.SET[index as usize].write(1 << (self.pin - index * 32)); + } + + /// Clears (turns off) the pin. + pub fn clear(&mut self) { + let index = if self.pin >= 32 { 1 } else { 0 }; + self.registers.CLR[index as usize].write(1 << (self.pin - index * 32)); + } +} + +impl Gpio { + /// Reads the pin's value. Returns `true` if the level is high and `false` + /// if the level is low. + pub fn level(&mut self) -> bool { + let index = if self.pin >= 32 { 1 } else { 0 }; + let high = 1 << (self.pin - index * 32); + (self.registers.LEV[index as usize].read() & high) == high + } +} diff --git a/crate/bcm2837/src/lib.rs b/crate/bcm2837/src/lib.rs new file mode 100644 index 00000000..b2611e33 --- /dev/null +++ b/crate/bcm2837/src/lib.rs @@ -0,0 +1,11 @@ +#![no_std] +#![feature(asm)] + +extern crate volatile; + +mod asm; + +pub mod gpio; +pub mod mini_uart; + +pub const IO_BASE: usize = 0x3F000000; diff --git a/crate/bcm2837/src/mini_uart.rs b/crate/bcm2837/src/mini_uart.rs new file mode 100644 index 00000000..db28245b --- /dev/null +++ b/crate/bcm2837/src/mini_uart.rs @@ -0,0 +1 @@ +use super::IO_BASE; diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index d8de26e6..3886b0cc 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -7,6 +7,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "bbl" version = "0.1.0" +[[package]] +name = "bcm2837" +version = "0.1.0" +dependencies = [ + "volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bit-allocator" version = "0.1.0" @@ -211,6 +218,7 @@ name = "ucore" version = "0.1.0" dependencies = [ "bbl 0.1.0", + "bcm2837 0.1.0", "bit-allocator 0.1.0", "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -227,7 +235,7 @@ dependencies = [ "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ucore-memory 0.1.0", "ucore-process 0.1.0", - "volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -265,7 +273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "volatile" -version = "0.1.0" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -344,7 +352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" "checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41" "checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" -"checksum volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37c5d76c0f40ba4f8ac10ec4717d4e98ce3e58c5607eea36e9464226fc5e0a95" +"checksum volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "54d4343a2df2d65144a874f95950754ee7b7e8594f6027aae8c7d0f4858a3fe8" "checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 7bde15d5..fe193773 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -25,7 +25,7 @@ once = "0.3.3" xmas-elf = "0.6" bitflags = "1.0" bit_field = "0.9.0" -volatile = "0.1.0" +volatile = "0.2.4" linked_list_allocator = "0.6" lazy_static = { version = "1.0.0", features = ["spin_no_std"] } bit-allocator = { path = "../crate/bit-allocator" } @@ -43,6 +43,9 @@ uart_16550 = "0.1" riscv = { path = "../crate/riscv" } bbl = { path = "../crate/bbl" } +[target.'cfg(target_arch = "aarch64")'.dependencies] +bcm2837 = { path = "../crate/bcm2837" } + [package.metadata.bootimage] default-target = "x86_64-blog_os.json" output = "target/x86_64-blog_os/bootimage.bin" diff --git a/kernel/src/arch/aarch64/board/raspi3/mod.rs b/kernel/src/arch/aarch64/board/raspi3/mod.rs index db63357f..c8cff9fa 100644 --- a/kernel/src/arch/aarch64/board/raspi3/mod.rs +++ b/kernel/src/arch/aarch64/board/raspi3/mod.rs @@ -1,5 +1,9 @@ //! Raspberry PI 3 Model B/B+ +extern crate bcm2837; + pub fn init() { // TODO + bcm2837::gpio::Gpio::new(14).set_gpio_pd(0); + bcm2837::gpio::Gpio::new(15).set_gpio_pd(0); } diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index 137941c8..0f66365e 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -11,8 +11,11 @@ pub mod board; /// TODO /// The entry point of kernel -#[no_mangle] // don't mangle the name of this function -pub extern fn rust_main() -> ! { +#[no_mangle] // don't mangle the name of this function +pub extern "C" fn rust_main() -> ! { + // Init board. + board::init(); + println!("Hello ARM64!"); // First init log mod, so that we can print log info. @@ -24,8 +27,6 @@ pub extern fn rust_main() -> ! { // Now heap is available // timer::init(); - // Init board. - board::init(); ::kmain(); } From faa5f01f31e7087d585c8f437157e555cae0fe20 Mon Sep 17 00:00:00 2001 From: equation314 Date: Sat, 27 Oct 2018 02:55:10 +0800 Subject: [PATCH 07/26] aarch64: fix a bug of bcm2837::asm::dealy() --- crate/bcm2837/src/asm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crate/bcm2837/src/asm.rs b/crate/bcm2837/src/asm.rs index 72f4c739..1c2b4492 100644 --- a/crate/bcm2837/src/asm.rs +++ b/crate/bcm2837/src/asm.rs @@ -4,7 +4,7 @@ #[inline] pub unsafe fn delay(clock: u32) { #[cfg(target_arch = "aarch64")] - asm!("1: subs x0, x0, #1; bne 1b;" + asm!("mov x1, x0; 1: subs x1, x1, #1; bne 1b;" :: "{x0}"(clock) :: "volatile"); } From 517a78d1144b9342ec93bde821a30a29abeee8cc Mon Sep 17 00:00:00 2001 From: equation314 Date: Mon, 29 Oct 2018 13:25:29 +0800 Subject: [PATCH 08/26] aarch64: implement mini UART for bcm2837 --- crate/bcm2837/src/asm.rs | 4 +- crate/bcm2837/src/mini_uart.rs | 116 +++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 2 deletions(-) diff --git a/crate/bcm2837/src/asm.rs b/crate/bcm2837/src/asm.rs index 1c2b4492..a496d92f 100644 --- a/crate/bcm2837/src/asm.rs +++ b/crate/bcm2837/src/asm.rs @@ -2,9 +2,9 @@ /// delay for some clocks #[inline] -pub unsafe fn delay(clock: u32) { +pub unsafe fn delay(_clock: u32) { #[cfg(target_arch = "aarch64")] asm!("mov x1, x0; 1: subs x1, x1, #1; bne 1b;" - :: "{x0}"(clock) + :: "{x0}"(_clock) :: "volatile"); } diff --git a/crate/bcm2837/src/mini_uart.rs b/crate/bcm2837/src/mini_uart.rs index db28245b..d4dcf357 100644 --- a/crate/bcm2837/src/mini_uart.rs +++ b/crate/bcm2837/src/mini_uart.rs @@ -1 +1,117 @@ use super::IO_BASE; +use gpio::{Function, Gpio}; +use volatile::{ReadOnly, Volatile}; + +/// The base address for the `MU` registers. +const MU_REG_BASE: usize = IO_BASE + 0x215040; + +/// The `AUXENB` register from page 9 of the BCM2837 documentation. +const AUX_ENABLES: *mut Volatile = (IO_BASE + 0x215004) as *mut Volatile; + +/// Enum representing bit fields of the `AUX_MU_LSR_REG` register. +#[repr(u8)] +enum LsrStatus { + DataReady = 1, + TxAvailable = 1 << 5, +} + +#[repr(C)] +#[allow(non_snake_case)] +struct Registers { + AUX_MU_IO_REG: Volatile, + __r0: [u8; 3], + AUX_MU_IER_REG: Volatile, + __r1: [u8; 3], + AUX_MU_IIR_REG: Volatile, + __r2: [u8; 3], + AUX_MU_LCR_REG: Volatile, + __r3: [u8; 3], + AUX_MU_MCR_REG: Volatile, + __r4: [u8; 3], + AUX_MU_LSR_REG: ReadOnly, + __r5: [u8; 3], + AUX_MU_MSR_REG: ReadOnly, + __r6: [u8; 3], + AUX_MU_SCRATCH: Volatile, + __r7: [u8; 3], + AUX_MU_CNTL_REG: Volatile, + __r8: [u8; 3], + AUX_MU_STAT_REG: ReadOnly, + AUX_MU_BAUD_REG: Volatile, +} + +/// The Raspberry Pi's "mini UART". +pub struct MiniUart { + registers: &'static mut Registers, + timeout: Option, +} + +impl MiniUart { + /// Initializes the mini UART by enabling it as an auxiliary peripheral, + /// setting the data size to 8 bits, setting the BAUD rate to ~115200 (baud + /// divider of 270), setting GPIO pins 14 and 15 to alternative function 5 + /// (TXD1/RDXD1), and finally enabling the UART transmitter and receiver. + /// + /// By default, reads will never time out. To set a read timeout, use + /// `set_read_timeout()`. + pub fn new() -> MiniUart { + let registers = unsafe { + // Enable the mini UART as an auxiliary device. + (*AUX_ENABLES).write(1); + &mut *(MU_REG_BASE as *mut Registers) + }; + + Gpio::new(14).into_alt(Function::Alt5).set_gpio_pd(0); + Gpio::new(15).into_alt(Function::Alt5).set_gpio_pd(0); + + registers.AUX_MU_CNTL_REG.write(0); // Disable auto flow control and disable receiver and transmitter (for now) + registers.AUX_MU_IER_REG.write(0); // Disable receive and transmit interrupts + registers.AUX_MU_LCR_REG.write(3); // Enable 8 bit mode + registers.AUX_MU_MCR_REG.write(0); // Set RTS line to be always high + registers.AUX_MU_BAUD_REG.write(270); // Set baud rate to 115200 + + registers.AUX_MU_CNTL_REG.write(3); // Finally, enable transmitter and receiver + + MiniUart { + registers: registers, + timeout: None, + } + } + + /// Set the read timeout to `milliseconds` milliseconds. + pub fn set_read_timeout(&mut self, milliseconds: u32) { + self.timeout = Some(milliseconds) + } + + /// Write the byte `byte`. This method blocks until there is space available + /// in the output FIFO. + pub fn write_byte(&mut self, byte: u8) { + while self.registers.AUX_MU_LSR_REG.read() & (LsrStatus::TxAvailable as u8) == 0 {} + self.registers.AUX_MU_IO_REG.write(byte); + } + + /// Returns `true` if there is at least one byte ready to be read. If this + /// method returns `true`, a subsequent call to `read_byte` is guaranteed to + /// return immediately. This method does not block. + pub fn has_byte(&self) -> bool { + self.registers.AUX_MU_LSR_REG.read() & (LsrStatus::DataReady as u8) != 0 + } + + /// Blocks until there is a byte ready to read. If a read timeout is set, + /// this method blocks for at most that amount of time. Otherwise, this + /// method blocks indefinitely until there is a byte to read. + /// + /// Returns `Ok(())` if a byte is ready to read. Returns `Err(())` if the + /// timeout expired while waiting for a byte to be ready. If this method + /// returns `Ok(())`, a subsequent call to `read_byte` is guaranteed to + /// return immediately. + pub fn wait_for_byte(&self) -> Result<(), ()> { + unimplemented!() + } + + /// Reads a byte. Blocks indefinitely until a byte is ready to be read. + pub fn read_byte(&mut self) -> u8 { + while !self.has_byte() {} + self.registers.AUX_MU_IO_REG.read() + } +} From abf3418d2471ff79087580bc928d1eb6668670e9 Mon Sep 17 00:00:00 2001 From: equation314 Date: Mon, 29 Oct 2018 13:38:27 +0800 Subject: [PATCH 09/26] aarch64: implement I/O by serial port --- kernel/src/arch/aarch64/board/raspi3/mod.rs | 10 ++- .../src/arch/aarch64/board/raspi3/serial.rs | 73 +++++++++++++++++++ kernel/src/arch/aarch64/boot/boot.S | 9 +++ kernel/src/arch/aarch64/io.rs | 11 ++- kernel/src/arch/aarch64/mod.rs | 34 ++++++--- 5 files changed, 117 insertions(+), 20 deletions(-) create mode 100644 kernel/src/arch/aarch64/board/raspi3/serial.rs diff --git a/kernel/src/arch/aarch64/board/raspi3/mod.rs b/kernel/src/arch/aarch64/board/raspi3/mod.rs index c8cff9fa..bdd0b21f 100644 --- a/kernel/src/arch/aarch64/board/raspi3/mod.rs +++ b/kernel/src/arch/aarch64/board/raspi3/mod.rs @@ -2,8 +2,12 @@ extern crate bcm2837; +pub mod serial; + pub fn init() { - // TODO - bcm2837::gpio::Gpio::new(14).set_gpio_pd(0); - bcm2837::gpio::Gpio::new(15).set_gpio_pd(0); + assert_has_not_been_called!("board::init must be called only once"); + + serial::SERIAL_PORT.lock().init(); + + println!("Hello Raspberry Pi!"); } diff --git a/kernel/src/arch/aarch64/board/raspi3/serial.rs b/kernel/src/arch/aarch64/board/raspi3/serial.rs new file mode 100644 index 00000000..b6c29f74 --- /dev/null +++ b/kernel/src/arch/aarch64/board/raspi3/serial.rs @@ -0,0 +1,73 @@ +use super::bcm2837::mini_uart::MiniUart; + +use core::fmt; +use spin::Mutex; + +/// Struct to get a global SerialPort interface +pub struct SerialPort { + mu: Option, +} + +pub trait SerialRead { + fn receive(&mut self) -> u8; +} + +impl SerialPort { + /// Creates a new instance of `SerialPort`. + const fn new() -> SerialPort { + SerialPort { mu: None } + } + + /// Init a newly created SerialPort, can only be called once. + pub fn init(&mut self) { + assert_has_not_been_called!("SerialPort::init must be called only once"); + self.mu = Some(MiniUart::new()); + } + + /// Writes the byte `byte` to the UART device. + pub fn write_byte(&mut self, byte: u8) { + match &mut self.mu { + Some(mu) => mu.write_byte(byte), + None => panic!("SerialPort is not initialized"), + } + } + + /// Reads a byte from the UART device, blocking until a byte is available. + pub fn read_byte(&mut self) -> u8 { + match &mut self.mu { + Some(mu) => return mu.read_byte(), + None => panic!("SerialPort is not initialized"), + } + } +} + +impl SerialRead for SerialPort { + fn receive(&mut self) -> u8 { + self.read_byte() + } +} + +impl fmt::Write for SerialPort { + fn write_str(&mut self, s: &str) -> fmt::Result { + for byte in s.bytes() { + match byte { + // Backspace + b'\x7f' => { + self.write_byte(b'\x08'); + self.write_byte(b' '); + self.write_byte(b'\x08'); + } + // Return + b'\n' => { + self.write_byte(b'\r'); + self.write_byte(b'\n'); + } + // Others + _ => self.write_byte(byte), + } + } + Ok(()) + } +} + +pub static SERIAL_PORT: Mutex = Mutex::new(SerialPort::new()); diff --git a/kernel/src/arch/aarch64/boot/boot.S b/kernel/src/arch/aarch64/boot/boot.S index ab0601cc..974d6ed5 100644 --- a/kernel/src/arch/aarch64/boot/boot.S +++ b/kernel/src/arch/aarch64/boot/boot.S @@ -55,6 +55,15 @@ switch_to_el1: movk x0, #0x8000, lsl #16 msr hcr_el2, x0 + + # don't trap accessing SVE registers (ref: D10.2.30) + msr cptr_el2, xzr + + # enable floating point and SVE (SIMD) (bits 20, 21) (ref: D10.2.29) + mrs x0, cpacr_el1 + orr x0, x0, #(0x3 << 20) + msr cpacr_el1, x0 + # Set SCTLR to known state (RES1: 11, 20, 22, 23, 28, 29) (ref: D10.2.100) mov x0, #0x0800 movk x0, #0x30d0, lsl #16 diff --git a/kernel/src/arch/aarch64/io.rs b/kernel/src/arch/aarch64/io.rs index 70f40350..5e5a6452 100644 --- a/kernel/src/arch/aarch64/io.rs +++ b/kernel/src/arch/aarch64/io.rs @@ -1,13 +1,12 @@ //! Serial driver for aarch64. -use core::fmt::{Arguments}; +use core::fmt::{Arguments, Write}; +use super::board::serial::{SerialRead, SERIAL_PORT}; -/// TODO pub fn getchar() -> char { - unimplemented!() + SERIAL_PORT.lock().receive() as char } -/// TODO -pub fn putfmt(fmt: Arguments<'_>) { - unimplemented!() +pub fn putfmt(fmt: Arguments) { + SERIAL_PORT.lock().write_fmt(fmt).unwrap() } diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index 0f66365e..0dfddc32 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -13,21 +13,33 @@ pub mod board; /// The entry point of kernel #[no_mangle] // don't mangle the name of this function pub extern "C" fn rust_main() -> ! { - // Init board. + // Init board to enable serial port. board::init(); - println!("Hello ARM64!"); - // First init log mod, so that we can print log info. - // ::logging::init(); - // Init trap handling. - // interrupt::init(); - // Init physical memory management and heap. - // memory::init(); - // Now heap is available - // timer::init(); + ::logging::init(); - ::kmain(); + loop { + print!(">> "); + loop { + let c = io::getchar(); + match c { + '\u{7f}' => { + print!("\u{7f}"); + } + ' '...'\u{7e}' => { + print!("{}", c); + } + '\n' | '\r' => { + print!("\n"); + break; + } + _ => {} + } + } + } + + // ::kmain(); } global_asm!(include_str!("boot/boot.S")); From 2e094d08bc2f3f14def1e792589ba5bea0b3a87a Mon Sep 17 00:00:00 2001 From: equation314 Date: Mon, 29 Oct 2018 13:41:25 +0800 Subject: [PATCH 10/26] common: add a logo --- kernel/src/arch/aarch64/mod.rs | 2 ++ kernel/src/fs.rs | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index 0dfddc32..ac14adb9 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -19,6 +19,8 @@ pub extern "C" fn rust_main() -> ! { // First init log mod, so that we can print log info. ::logging::init(); + super::fs::show_logo(); + loop { print!(">> "); loop { diff --git a/kernel/src/fs.rs b/kernel/src/fs.rs index 4dcaa141..d6822365 100644 --- a/kernel/src/fs.rs +++ b/kernel/src/fs.rs @@ -14,7 +14,21 @@ _binary_user_riscv_img_start: _binary_user_riscv_img_end: "#); +const LOGO: &str = r#" + ____ __ ____ _____ + / __ \ __ __ _____ / /_ / __ \/ ___/ + / /_/ // / / // ___// __// / / /\__ \ + / _, _// /_/ /(__ )/ /_ / /_/ /___/ / +/_/ |_| \__,_//____/ \__/ \____//____/ +"#; + +pub fn show_logo() { + println!("{}", LOGO); +} + pub fn shell() { + show_logo(); + #[cfg(target_arch = "riscv32")] let device = { extern { @@ -97,4 +111,4 @@ impl BlockedDevice for &'static ide::DISK1 { let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) }; self.0.lock().write(block_id as u64, 1, buf).is_ok() } -} \ No newline at end of file +} From 632baedabdbed36af669f5b007573c6a16321d5f Mon Sep 17 00:00:00 2001 From: equation314 Date: Mon, 29 Oct 2018 18:53:14 +0800 Subject: [PATCH 11/26] aarch64: can run on the real raspi3 --- crate/bcm2837/src/gpio.rs | 8 ++++++-- kernel/src/arch/aarch64/board/raspi3/mod.rs | 7 +++++-- kernel/src/arch/aarch64/board/raspi3/serial.rs | 8 ++++++-- kernel/src/arch/aarch64/io.rs | 10 ++++++++-- kernel/src/arch/aarch64/mod.rs | 3 ++- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/crate/bcm2837/src/gpio.rs b/crate/bcm2837/src/gpio.rs index aa2f9efe..44653033 100644 --- a/crate/bcm2837/src/gpio.rs +++ b/crate/bcm2837/src/gpio.rs @@ -116,8 +116,12 @@ impl Gpio { /// Enables the alternative function `function` for `self`. Consumes self /// and returns a `Gpio` structure in the `Alt` state. pub fn into_alt(self, function: Function) -> Gpio { - self.registers.FSEL[(self.pin / 10) as usize] - .write((function as u32) << (3 * (self.pin % 10))); + let select = (self.pin / 10) as usize; + let offset = 3 * (self.pin % 10) as usize; + let mut value = self.registers.FSEL[select].read(); + value &= !(0b111 << offset); + value |= (function as u32) << offset; + self.registers.FSEL[select].write(value); self.transition() } diff --git a/kernel/src/arch/aarch64/board/raspi3/mod.rs b/kernel/src/arch/aarch64/board/raspi3/mod.rs index bdd0b21f..3ff2324c 100644 --- a/kernel/src/arch/aarch64/board/raspi3/mod.rs +++ b/kernel/src/arch/aarch64/board/raspi3/mod.rs @@ -5,9 +5,12 @@ extern crate bcm2837; pub mod serial; pub fn init() { - assert_has_not_been_called!("board::init must be called only once"); + // FIXME + // assert_has_not_been_called!("board::init must be called only once"); - serial::SERIAL_PORT.lock().init(); + unsafe { + serial::SERIAL_PORT.init(); + } println!("Hello Raspberry Pi!"); } diff --git a/kernel/src/arch/aarch64/board/raspi3/serial.rs b/kernel/src/arch/aarch64/board/raspi3/serial.rs index b6c29f74..5434071f 100644 --- a/kernel/src/arch/aarch64/board/raspi3/serial.rs +++ b/kernel/src/arch/aarch64/board/raspi3/serial.rs @@ -20,7 +20,8 @@ impl SerialPort { /// Init a newly created SerialPort, can only be called once. pub fn init(&mut self) { - assert_has_not_been_called!("SerialPort::init must be called only once"); + // FIXME + // assert_has_not_been_called!("SerialPort::init must be called only once"); self.mu = Some(MiniUart::new()); } @@ -70,4 +71,7 @@ impl fmt::Write for SerialPort { } } -pub static SERIAL_PORT: Mutex = Mutex::new(SerialPort::new()); +// FIXME +// pub static SERIAL_PORT: Mutex = Mutex::new(SerialPort::new()); +pub static mut SERIAL_PORT: SerialPort = SerialPort::new(); + diff --git a/kernel/src/arch/aarch64/io.rs b/kernel/src/arch/aarch64/io.rs index 5e5a6452..deda39c3 100644 --- a/kernel/src/arch/aarch64/io.rs +++ b/kernel/src/arch/aarch64/io.rs @@ -4,9 +4,15 @@ use core::fmt::{Arguments, Write}; use super::board::serial::{SerialRead, SERIAL_PORT}; pub fn getchar() -> char { - SERIAL_PORT.lock().receive() as char + // FIXME + unsafe { + SERIAL_PORT.receive() as char + } } pub fn putfmt(fmt: Arguments) { - SERIAL_PORT.lock().write_fmt(fmt).unwrap() + // FIXME + unsafe { + SERIAL_PORT.write_fmt(fmt).unwrap() + } } diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index ac14adb9..f668a256 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -17,7 +17,8 @@ pub extern "C" fn rust_main() -> ! { board::init(); // First init log mod, so that we can print log info. - ::logging::init(); + // FIXME + // ::logging::init(); super::fs::show_logo(); From 77464858614f8e8929a1e2449ad5f7453ed4675e Mon Sep 17 00:00:00 2001 From: equation314 Date: Mon, 29 Oct 2018 19:14:54 +0800 Subject: [PATCH 12/26] aarch64: add target 'install' to Makefile --- kernel/Makefile | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/kernel/Makefile b/kernel/Makefile index 62dde62c..de0ab82a 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -153,3 +153,24 @@ endif $(user_obj): $(user_bins) @cd $(user_bin_path) && \ $(ld) -o $(abspath $@) $(patsubst %, -b binary %, $(notdir $(user_bins))) + + + +### install ### +ifeq ($(board), raspi3) +sd_card ?= + +ifeq ($(shell uname), Darwin) +sd_card := /Volumes/boot +else ifeq ($(shell uname), Linux) +sd_card := /media/$(shell whoami)/boot +endif + +ifdef sd_card +.PHONY: +install: $(bin) + cp $(bin) $(sd_card)/kernel8.img + sudo umount $(sd_card) +endif + +endif From ae5260db5c745a33a44d5037496f0dc43bcf4517 Mon Sep 17 00:00:00 2001 From: equation314 Date: Mon, 29 Oct 2018 21:34:29 +0800 Subject: [PATCH 13/26] aarch64: change linker to rust-lld --- kernel/aarch64-blog_os.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/aarch64-blog_os.json b/kernel/aarch64-blog_os.json index 8c9ab023..e3f80a06 100644 --- a/kernel/aarch64-blog_os.json +++ b/kernel/aarch64-blog_os.json @@ -10,11 +10,11 @@ "arch": "aarch64", "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", "executables": true, - "linker": "aarch64-none-elf-ld", - "linker-flavor": "ld", + "linker": "rust-lld", + "linker-flavor": "ld.lld", "linker-is-gnu": true, "pre-link-args": { - "ld": [ + "ld.lld": [ "-Tsrc/arch/aarch64/boot/linker.ld" ] }, From 001254fd64234a64d030860b59f56ab4687b25a0 Mon Sep 17 00:00:00 2001 From: equation314 Date: Mon, 29 Oct 2018 21:37:57 +0800 Subject: [PATCH 14/26] riscv32: change linker to rust-lld --- kernel/riscv32-blog_os.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/riscv32-blog_os.json b/kernel/riscv32-blog_os.json index ab160b8d..6e704549 100644 --- a/kernel/riscv32-blog_os.json +++ b/kernel/riscv32-blog_os.json @@ -9,10 +9,10 @@ "cpu": "generic-rv32", "features": "", "max-atomic-width": "32", - "linker": "riscv64-unknown-elf-ld", - "linker-flavor": "ld", + "linker": "rust-lld", + "linker-flavor": "ld.lld", "pre-link-args": { - "ld": [ + "ld.lld": [ "-Tsrc/arch/riscv32/boot/linker.ld", "-melf32lriscv" ] @@ -33,4 +33,4 @@ "msp430-interrupt", "x86-interrupt" ] -} \ No newline at end of file +} From 3386a793a5c92c33c904a598343bff3db8f8abf3 Mon Sep 17 00:00:00 2001 From: equation314 Date: Mon, 29 Oct 2018 23:05:16 +0800 Subject: [PATCH 15/26] aarch64: disable NEON --- kernel/aarch64-blog_os.json | 2 +- kernel/src/arch/aarch64/boot/boot.S | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/aarch64-blog_os.json b/kernel/aarch64-blog_os.json index e3f80a06..b0c24dc8 100644 --- a/kernel/aarch64-blog_os.json +++ b/kernel/aarch64-blog_os.json @@ -20,7 +20,7 @@ }, "llvm-target": "aarch64-unknown-none", "no-compiler-rt": true, - "features": "+a53,+strict-align", + "features": "+a53,+strict-align,-neon", "max-atomic-width": 128, "os": "none", "panic": "abort", diff --git a/kernel/src/arch/aarch64/boot/boot.S b/kernel/src/arch/aarch64/boot/boot.S index 974d6ed5..1740a202 100644 --- a/kernel/src/arch/aarch64/boot/boot.S +++ b/kernel/src/arch/aarch64/boot/boot.S @@ -55,7 +55,6 @@ switch_to_el1: movk x0, #0x8000, lsl #16 msr hcr_el2, x0 - # don't trap accessing SVE registers (ref: D10.2.30) msr cptr_el2, xzr From 8c1949911233335cba03dffc35c73d95ccc00c44 Mon Sep 17 00:00:00 2001 From: equation314 Date: Tue, 30 Oct 2018 20:44:54 +0800 Subject: [PATCH 16/26] aarch64: implement exception interface & synchronous exception handler --- kernel/src/arch/aarch64/context.rs | 62 ---------- kernel/src/arch/aarch64/interrupt/context.rs | 60 ++++++++++ kernel/src/arch/aarch64/interrupt/handler.rs | 67 +++++++++++ .../{interrupt.rs => interrupt/mod.rs} | 20 ++-- kernel/src/arch/aarch64/interrupt/syndrome.rs | 108 ++++++++++++++++++ kernel/src/arch/aarch64/interrupt/trap.S | 103 +++++++++++++++++ kernel/src/arch/aarch64/interrupt/vector.S | 29 +++++ kernel/src/arch/aarch64/mod.rs | 9 ++ 8 files changed, 389 insertions(+), 69 deletions(-) delete mode 100644 kernel/src/arch/aarch64/context.rs create mode 100644 kernel/src/arch/aarch64/interrupt/context.rs create mode 100644 kernel/src/arch/aarch64/interrupt/handler.rs rename kernel/src/arch/aarch64/{interrupt.rs => interrupt/mod.rs} (70%) create mode 100644 kernel/src/arch/aarch64/interrupt/syndrome.rs create mode 100644 kernel/src/arch/aarch64/interrupt/trap.S create mode 100644 kernel/src/arch/aarch64/interrupt/vector.S diff --git a/kernel/src/arch/aarch64/context.rs b/kernel/src/arch/aarch64/context.rs deleted file mode 100644 index 4ca8b569..00000000 --- a/kernel/src/arch/aarch64/context.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! Trapframe and context definitions for aarch64. - -/// TODO -#[repr(C)] -#[derive(Debug)] -pub struct TrapFrame { - // TODO -} - -///TODO -#[derive(Debug)] -pub struct Context { - // TODO -} - -impl Context { - /// TODO - #[inline(never)] - pub unsafe extern fn switch(&mut self, target: &mut Self) { - unimplemented!() - } - - /// TODO - pub unsafe fn null() -> Self { - unimplemented!() - } - - /// TODO - pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, cr3: usize) -> Self { - unimplemented!() - } - - /// TODO - pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, is32: bool, cr3: usize) -> Self { - unimplemented!() - } - - /// TODO - pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, cr3: usize) -> Self { - unimplemented!() - } -} - -#[inline(always)] -pub unsafe fn enable() { - unimplemented!() -} - -#[inline(always)] -pub unsafe fn disable() { - unimplemented!() -} - -#[inline(always)] -pub unsafe fn disable_and_store() -> usize { - unimplemented!() -} - -#[inline(always)] -pub unsafe fn restore(flags: usize) { - unimplemented!() -} diff --git a/kernel/src/arch/aarch64/interrupt/context.rs b/kernel/src/arch/aarch64/interrupt/context.rs new file mode 100644 index 00000000..06a9bd5c --- /dev/null +++ b/kernel/src/arch/aarch64/interrupt/context.rs @@ -0,0 +1,60 @@ +//! TrapFrame and context definitions for aarch64. + +#[repr(C)] +#[derive(Default, Debug, Copy, Clone)] +pub struct TrapFrame { + pub elr: u64, + pub spsr: u64, + pub sp: u64, + pub tpidr: u64, + // pub q0to31: [u128; 32], // disable SIMD/FP registers + pub x1to29: [u64; 29], + pub __reserved: u64, + pub x30: u64, // lr + pub x0: u64, +} + +///TODO +#[derive(Debug)] +pub struct Context { + // TODO +} + +impl Context { + /// TODO + #[inline(never)] + pub unsafe extern "C" fn switch(&mut self, target: &mut Self) { + unimplemented!() + } + + /// TODO + pub unsafe fn null() -> Self { + unimplemented!() + } + + /// TODO + pub unsafe fn new_kernel_thread( + entry: extern "C" fn(usize) -> !, + arg: usize, + kstack_top: usize, + cr3: usize, + ) -> Self { + unimplemented!() + } + + /// TODO + pub unsafe fn new_user_thread( + entry_addr: usize, + ustack_top: usize, + kstack_top: usize, + is32: bool, + cr3: usize, + ) -> Self { + unimplemented!() + } + + /// TODO + pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, cr3: usize) -> Self { + unimplemented!() + } +} diff --git a/kernel/src/arch/aarch64/interrupt/handler.rs b/kernel/src/arch/aarch64/interrupt/handler.rs new file mode 100644 index 00000000..371d4d1e --- /dev/null +++ b/kernel/src/arch/aarch64/interrupt/handler.rs @@ -0,0 +1,67 @@ +//! Trap handler + +use super::context::TrapFrame; +use super::syndrome::Syndrome; + +global_asm!(include_str!("trap.S")); +global_asm!(include_str!("vector.S")); + +#[repr(u16)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum Kind { + Synchronous = 0, + Irq = 1, + Fiq = 2, + SError = 3, +} + +#[repr(u16)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum Source { + CurrentSpEl0 = 0, + CurrentSpElx = 1, + LowerAArch64 = 2, + LowerAArch32 = 3, +} + +#[repr(C)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub struct Info { + source: Source, + kind: Kind, +} + +/// This function is called when an exception occurs. The `info` parameter +/// specifies the source and kind of exception that has occurred. The `esr` is +/// the value of the exception syndrome register. Finally, `tf` is a pointer to +/// the trap frame for the exception. +#[no_mangle] +pub extern "C" fn rust_trap(info: Info, esr: u32, tf: &mut TrapFrame) { + let syndrome = Syndrome::from(esr); + trace!("Interrupt: {:?} from: {:?}", syndrome, info); + match info.kind { + Kind::Synchronous => { + // syndrome is only valid with sync + match syndrome { + Syndrome::Brk(brk) => handle_break(brk, tf), + Syndrome::Svc(syscall) => handle_syscall(syscall, tf), + _ => ::trap::error(tf), + } + } + Kind::Irq => { + // TODO + } + _ => ::trap::error(tf), + } + ::trap::before_return(); + trace!("Interrupt end"); +} + +fn handle_break(num: u16, tf: &mut TrapFrame) { + tf.elr += 4; // Skip the current brk instruction +} + +fn handle_syscall(num: u16, tf: &mut TrapFrame) { + // svc instruction has been skipped in syscall + println!("syscall {}", num); +} diff --git a/kernel/src/arch/aarch64/interrupt.rs b/kernel/src/arch/aarch64/interrupt/mod.rs similarity index 70% rename from kernel/src/arch/aarch64/interrupt.rs rename to kernel/src/arch/aarch64/interrupt/mod.rs index 1566afde..5181cb53 100644 --- a/kernel/src/arch/aarch64/interrupt.rs +++ b/kernel/src/arch/aarch64/interrupt/mod.rs @@ -1,14 +1,20 @@ -//! Interrupt handler implementation on raspi3. +//! Interrupt and exception for aarch64. + +mod handler; +mod context; +mod syndrome; pub use self::context::*; +pub use self::handler::*; -#[path = "context.rs"] -mod context; - -/// Initialize the trap to enable the interrupt. +/// Set the exception vector address pub fn init() { - // TODO - // info!("interrupt: init end"); + unsafe { + asm!( + "adr x0, __vectors; + msr vbar_el1, x0" + ); + } } /// Enable the interrupt. diff --git a/kernel/src/arch/aarch64/interrupt/syndrome.rs b/kernel/src/arch/aarch64/interrupt/syndrome.rs new file mode 100644 index 00000000..d466a5d2 --- /dev/null +++ b/kernel/src/arch/aarch64/interrupt/syndrome.rs @@ -0,0 +1,108 @@ +//! Exception syndrome from ESR + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum Fault { + AddressSize, + Translation, + AccessFlag, + Permission, + Alignment, + TlbConflict, + Other(u8), +} + +impl From for Fault { + fn from(val: u32) -> Fault { + use self::Fault::*; + + // IFSC or DFSC bits (ref: D10.2.39, Page 2457~2464). + match val & 0b111100 { + 0b000000 => AddressSize, + 0b000100 => Translation, + 0b001000 => AccessFlag, + 0b001100 => Permission, + 0b100000 => Alignment, + 0b110000 => TlbConflict, + _ => Other((val & 0b111111) as u8), + } + } +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum Syndrome { + Unknown, + WfiWfe, + McrMrc, + McrrMrrc, + LdcStc, + SimdFp, + Vmrs, + Mrrc, + IllegalExecutionState, + Svc(u16), + Hvc(u16), + Smc(u16), + MsrMrsSystem, + InstructionAbort { kind: Fault, level: u8 }, + PCAlignmentFault, + DataAbort { kind: Fault, level: u8 }, + SpAlignmentFault, + TrappedFpu, + SError, + Breakpoint, + Step, + Watchpoint, + Brk(u16), + Other(u32), +} + +/// Converts a raw syndrome value (ESR) into a `Syndrome` (ref: D1.10.4, D10.2.39). +impl From for Syndrome { + fn from(esr: u32) -> Syndrome { + use self::Syndrome::*; + + let ec = esr >> 26; + let iss = esr & 0xFFFFFF; + + match ec { + 0b000000 => Unknown, + 0b000001 => WfiWfe, + 0b000011 => McrMrc, + 0b000100 => McrrMrrc, + 0b000101 => McrMrc, + 0b000110 => LdcStc, + 0b000111 => SimdFp, + 0b001000 => Vmrs, + 0b001100 => Mrrc, + 0b001110 => IllegalExecutionState, + 0b010001 => Svc((iss & 0xFFFF) as u16), + 0b010010 => Hvc((iss & 0xFFFF) as u16), + 0b010011 => Smc((iss & 0xFFFF) as u16), + 0b010101 => Svc((iss & 0xFFFF) as u16), + 0b010110 => Hvc((iss & 0xFFFF) as u16), + 0b010111 => Smc((iss & 0xFFFF) as u16), + 0b011000 => MsrMrsSystem, + 0b100000 | 0b100001 => InstructionAbort { + kind: Fault::from(iss), + level: (iss & 0b11) as u8, + }, + 0b100010 => PCAlignmentFault, + 0b100100 | 0b100101 => DataAbort { + kind: Fault::from(iss), + level: (iss & 0b11) as u8, + }, + 0b100110 => SpAlignmentFault, + 0b101000 => TrappedFpu, + 0b101100 => TrappedFpu, + 0b101111 => SError, + 0b110000 => Breakpoint, + 0b110001 => Breakpoint, + 0b110010 => Step, + 0b110011 => Step, + 0b110100 => Watchpoint, + 0b110101 => Watchpoint, + 0b111100 => Brk((iss & 0xFFFF) as u16), + other => Other(other), + } + } +} diff --git a/kernel/src/arch/aarch64/interrupt/trap.S b/kernel/src/arch/aarch64/interrupt/trap.S new file mode 100644 index 00000000..fb511108 --- /dev/null +++ b/kernel/src/arch/aarch64/interrupt/trap.S @@ -0,0 +1,103 @@ +.section .text + +.macro SAVE_ALL + # lr, x0 is saved in HANDLER + str x29, [sp, #-16]! + stp x27, x28, [sp, #-16]! + stp x25, x26, [sp, #-16]! + stp x23, x24, [sp, #-16]! + stp x21, x22, [sp, #-16]! + stp x19, x20, [sp, #-16]! + stp x17, x18, [sp, #-16]! + stp x15, x16, [sp, #-16]! + stp x13, x14, [sp, #-16]! + stp x11, x12, [sp, #-16]! + stp x9, x10, [sp, #-16]! + stp x7, x8, [sp, #-16]! + stp x5, x6, [sp, #-16]! + stp x3, x4, [sp, #-16]! + stp x1, x2, [sp, #-16]! + + # stp q30, q31, [sp, #-32]! + # stp q28, q29, [sp, #-32]! + # stp q26, q27, [sp, #-32]! + # stp q24, q25, [sp, #-32]! + # stp q22, q23, [sp, #-32]! + # stp q20, q21, [sp, #-32]! + # stp q18, q19, [sp, #-32]! + # stp q16, q17, [sp, #-32]! + # stp q14, q15, [sp, #-32]! + # stp q12, q13, [sp, #-32]! + # stp q10, q11, [sp, #-32]! + # stp q8, q9, [sp, #-32]! + # stp q6, q7, [sp, #-32]! + # stp q4, q5, [sp, #-32]! + # stp q2, q3, [sp, #-32]! + # stp q0, q1, [sp, #-32]! + + mrs x2, tpidr_el0 + mrs x1, sp_el0 + stp x1, x2, [sp, #-16]! + + mrs x2, spsr_el1 + mrs x1, elr_el1 + stp x1, x2, [sp, #-16]! +.endm + +.macro RESTORE_ALL + ldp x1, x2, [sp], #16 + msr elr_el1, x1 + msr spsr_el1, x2 + + ldp x1, x2, [sp], #16 + msr sp_el0, x1 + msr tpidr_el0, x2 + + # ldp q0, q1, [sp], #32 + # ldp q2, q3, [sp], #32 + # ldp q4, q5, [sp], #32 + # ldp q6, q7, [sp], #32 + # ldp q8, q9, [sp], #32 + # ldp q10, q11, [sp], #32 + # ldp q12, q13, [sp], #32 + # ldp q14, q15, [sp], #32 + # ldp q16, q17, [sp], #32 + # ldp q18, q19, [sp], #32 + # ldp q20, q21, [sp], #32 + # ldp q22, q23, [sp], #32 + # ldp q24, q25, [sp], #32 + # ldp q26, q27, [sp], #32 + # ldp q28, q29, [sp], #32 + # ldp q30, q31, [sp], #32 + + ldp x1, x2, [sp], #16 + ldp x3, x4, [sp], #16 + ldp x5, x6, [sp], #16 + ldp x7, x8, [sp], #16 + ldp x9, x10, [sp], #16 + ldp x11, x12, [sp], #16 + ldp x13, x14, [sp], #16 + ldp x15, x16, [sp], #16 + ldp x17, x18, [sp], #16 + ldp x19, x20, [sp], #16 + ldp x21, x22, [sp], #16 + ldp x23, x24, [sp], #16 + ldp x25, x26, [sp], #16 + ldp x27, x28, [sp], #16 + ldr x29, [sp], #16 + ldp lr, x0, [sp], #16 +.endm + +.global __alltraps +__alltraps: + SAVE_ALL + + # x0 is set in HANDLER + mrs x1, esr_el1 + mov x2, sp + bl rust_trap + +.global trap_ret +trap_ret: + RESTORE_ALL + eret diff --git a/kernel/src/arch/aarch64/interrupt/vector.S b/kernel/src/arch/aarch64/interrupt/vector.S new file mode 100644 index 00000000..3a749f94 --- /dev/null +++ b/kernel/src/arch/aarch64/interrupt/vector.S @@ -0,0 +1,29 @@ +.section .text + +.macro HANDLER source kind + .align 7 + stp lr, x0, [sp, #-16]! + mov x0, #\source + movk x0, #\kind, lsl #16 + b __alltraps +.endm + +.global __vectors +.align 11 +__vectors: + HANDLER 0 0 + HANDLER 0 1 + HANDLER 0 2 + HANDLER 0 3 + HANDLER 1 0 + HANDLER 1 1 + HANDLER 1 2 + HANDLER 1 3 + HANDLER 2 0 + HANDLER 2 1 + HANDLER 2 2 + HANDLER 2 3 + HANDLER 3 0 + HANDLER 3 1 + HANDLER 3 2 + HANDLER 3 3 diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index f668a256..83533248 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -19,6 +19,7 @@ pub extern "C" fn rust_main() -> ! { // First init log mod, so that we can print log info. // FIXME // ::logging::init(); + interrupt::init(); super::fs::show_logo(); @@ -30,6 +31,14 @@ pub extern "C" fn rust_main() -> ! { '\u{7f}' => { print!("\u{7f}"); } + 'b' => unsafe { + println!("brk 233"); + asm!("brk 233"); + }, + 'c' => unsafe { + println!("svc 666"); + asm!("svc 666"); + }, ' '...'\u{7e}' => { print!("{}", c); } From 430bf508e29d528f82211f7722e1abb540d4e4a5 Mon Sep 17 00:00:00 2001 From: equation314 Date: Tue, 30 Oct 2018 23:18:15 +0800 Subject: [PATCH 17/26] aarch64: add some comments to crate bcm2837 --- crate/bcm2837/src/gpio.rs | 12 +++++++----- crate/bcm2837/src/mini_uart.rs | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/crate/bcm2837/src/gpio.rs b/crate/bcm2837/src/gpio.rs index 44653033..1b340c77 100644 --- a/crate/bcm2837/src/gpio.rs +++ b/crate/bcm2837/src/gpio.rs @@ -6,7 +6,7 @@ use volatile::{ReadOnly, Volatile, WriteOnly}; /// The base address of the `GPIO` registers. const GPIO_BASE: usize = IO_BASE + 0x200000; -/// An alternative GPIO function. +/// An alternative GPIO function. (ref: peripherals 6.1, page 92) #[repr(u8)] pub enum Function { Input = 0b000, @@ -19,6 +19,7 @@ pub enum Function { Alt5 = 0b010, } +/// GPIO registers starting from `GPIO_BASE` (ref: peripherals 6.1, page 90) #[repr(C)] #[allow(non_snake_case)] struct Registers { @@ -81,6 +82,7 @@ impl Gpio { } /// Set the Gpio pull-up/pull-down state for values in `pin_value` + /// (ref: peripherals 6.1, page 101) pub fn set_gpio_pd(&mut self, pud_value: u8) { unsafe { let index = if self.pin >= 32 { 1 } else { 0 }; @@ -118,10 +120,10 @@ impl Gpio { pub fn into_alt(self, function: Function) -> Gpio { let select = (self.pin / 10) as usize; let offset = 3 * (self.pin % 10) as usize; - let mut value = self.registers.FSEL[select].read(); - value &= !(0b111 << offset); - value |= (function as u32) << offset; - self.registers.FSEL[select].write(value); + self.registers.FSEL[select].update(|value| { + *value &= !(0b111 << offset); + *value |= (function as u32) << offset; + }); self.transition() } diff --git a/crate/bcm2837/src/mini_uart.rs b/crate/bcm2837/src/mini_uart.rs index d4dcf357..58160177 100644 --- a/crate/bcm2837/src/mini_uart.rs +++ b/crate/bcm2837/src/mini_uart.rs @@ -15,6 +15,7 @@ enum LsrStatus { TxAvailable = 1 << 5, } +/// MU registers starting from `AUX_ENABLES` (ref: peripherals 2.1, page 8) #[repr(C)] #[allow(non_snake_case)] struct Registers { From 07aa9a0686fb2dd597315ec0795c8fd654ed1b40 Mon Sep 17 00:00:00 2001 From: equation314 Date: Wed, 31 Oct 2018 16:10:22 +0800 Subject: [PATCH 18/26] aarch64: implement IRQ & system timer, but don't work in qemu --- crate/bcm2837/src/interrupt.rs | 61 +++++++++++++++++ crate/bcm2837/src/lib.rs | 2 + crate/bcm2837/src/timer.rs | 68 +++++++++++++++++++ kernel/src/arch/aarch64/board/raspi3/irq.rs | 10 +++ kernel/src/arch/aarch64/board/raspi3/mod.rs | 2 + kernel/src/arch/aarch64/board/raspi3/timer.rs | 16 +++++ kernel/src/arch/aarch64/interrupt/handler.rs | 5 +- kernel/src/arch/aarch64/interrupt/mod.rs | 4 +- kernel/src/arch/aarch64/mod.rs | 8 +++ 9 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 crate/bcm2837/src/interrupt.rs create mode 100644 crate/bcm2837/src/timer.rs create mode 100644 kernel/src/arch/aarch64/board/raspi3/irq.rs create mode 100644 kernel/src/arch/aarch64/board/raspi3/timer.rs diff --git a/crate/bcm2837/src/interrupt.rs b/crate/bcm2837/src/interrupt.rs new file mode 100644 index 00000000..cf340ee7 --- /dev/null +++ b/crate/bcm2837/src/interrupt.rs @@ -0,0 +1,61 @@ +use super::IO_BASE; +use volatile::{ReadOnly, Volatile}; + +const INT_BASE: usize = IO_BASE + 0xB000 + 0x200; + +/// Allowed interrupts (ref: peripherals 7.5, page 113) +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum Interrupt { + Timer1 = 1, + Timer3 = 3, + Usb = 9, + Aux = 29, + Gpio0 = 49, + Gpio1 = 50, + Gpio2 = 51, + Gpio3 = 52, + Uart = 57, +} + +/// Interrupts registers starting from `INT_BASE` (ref: peripherals 7.5, page 112) +#[repr(C)] +#[allow(non_snake_case)] +struct Registers { + IRQBasicPending: ReadOnly, + IRQPending: [ReadOnly; 2], + FIQControl: Volatile, + EnableIRQ: [Volatile; 2], + EnableBasicIRQ: Volatile, + DisableIRQ: [Volatile; 2], + DisableBasicIRQ: Volatile, +} + +/// An interrupt controller. Used to enable and disable interrupts as well as to +/// check if an interrupt is pending. +pub struct Controller { + registers: &'static mut Registers, +} + +impl Controller { + /// Returns a new handle to the interrupt controller. + pub fn new() -> Controller { + Controller { + registers: unsafe { &mut *(INT_BASE as *mut Registers) }, + } + } + + /// Enables the interrupt `int`. + pub fn enable(&mut self, int: Interrupt) { + self.registers.EnableIRQ[int as usize / 32].write(1 << (int as usize) % 32); + } + + /// Disables the interrupt `int`. + pub fn disable(&mut self, int: Interrupt) { + self.registers.DisableIRQ[int as usize / 32].write(1 << (int as usize) % 32); + } + + /// Returns `true` if `int` is pending. Otherwise, returns `false`. + pub fn is_pending(&self, int: Interrupt) -> bool { + self.registers.IRQPending[int as usize / 32].read() & (1 << (int as usize) % 32) != 0 + } +} diff --git a/crate/bcm2837/src/lib.rs b/crate/bcm2837/src/lib.rs index b2611e33..13da9ffa 100644 --- a/crate/bcm2837/src/lib.rs +++ b/crate/bcm2837/src/lib.rs @@ -6,6 +6,8 @@ extern crate volatile; mod asm; pub mod gpio; +pub mod timer; pub mod mini_uart; +pub mod interrupt; pub const IO_BASE: usize = 0x3F000000; diff --git a/crate/bcm2837/src/timer.rs b/crate/bcm2837/src/timer.rs new file mode 100644 index 00000000..3e485b84 --- /dev/null +++ b/crate/bcm2837/src/timer.rs @@ -0,0 +1,68 @@ +use super::IO_BASE; +use volatile::{ReadOnly, Volatile}; + +/// The base address for the ARM system timer registers. +const TIMER_REG_BASE: usize = IO_BASE + 0x3000; + +/// System timer registers (ref: peripherals 12.1, page 172) +#[repr(C)] +#[allow(non_snake_case)] +struct Registers { + CS: Volatile, + CLO: ReadOnly, + CHI: ReadOnly, + COMPARE: [Volatile; 4], +} + +#[repr(u8)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum SystemTimer { + Timer0 = 0, + Timer1 = 1, + Timer2 = 2, + Timer3 = 3, +} + +/// The Raspberry Pi ARM system timer. +pub struct Timer { + registers: &'static mut Registers, +} + +impl Timer { + /// Returns a new instance of `Timer`. + pub fn new() -> Timer { + Timer { + registers: unsafe { &mut *(TIMER_REG_BASE as *mut Registers) }, + } + } + + /// Reads the system timer's counter and returns the 64-bit counter value. + /// The returned value is the number of elapsed microseconds. + pub fn read(&self) -> u64 { + let low = self.registers.CLO.read(); + let high = self.registers.CHI.read(); + ((high as u64) << 32) | (low as u64) + } + + /// Sets up a match in timer 1 to occur `us` microseconds from now. If + /// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer + /// interrupt will be issued in `us` microseconds. + pub fn tick_in(&mut self, st: SystemTimer, us: u32) { + let current_low = self.registers.CLO.read(); + let compare = current_low.wrapping_add(us); + self.registers.COMPARE[st as usize].write(compare); + self.registers.CS.write(1 << (st as usize)); // unmask + } +} + +/// Returns the current time in microseconds. +pub fn current_time() -> u64 { + Timer::new().read() +} + +/// Sets up a match in timer 1 to occur `us` microseconds from now. If +/// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer +/// interrupt will be issued in `us` microseconds. +pub fn tick_in(st: SystemTimer, us: u32) { + Timer::new().tick_in(st, us) +} diff --git a/kernel/src/arch/aarch64/board/raspi3/irq.rs b/kernel/src/arch/aarch64/board/raspi3/irq.rs new file mode 100644 index 00000000..5f1fb0d9 --- /dev/null +++ b/kernel/src/arch/aarch64/board/raspi3/irq.rs @@ -0,0 +1,10 @@ +use super::bcm2837::interrupt::{Controller, Interrupt}; + +pub fn handle_irq() { + let controller = Controller::new(); + if controller.is_pending(Interrupt::Timer1) { + println!("Timer tick..."); + super::timer::set_next(); + // ::trap::timer(); + } +} diff --git a/kernel/src/arch/aarch64/board/raspi3/mod.rs b/kernel/src/arch/aarch64/board/raspi3/mod.rs index 3ff2324c..2b32a108 100644 --- a/kernel/src/arch/aarch64/board/raspi3/mod.rs +++ b/kernel/src/arch/aarch64/board/raspi3/mod.rs @@ -2,6 +2,8 @@ extern crate bcm2837; +pub mod irq; +pub mod timer; pub mod serial; pub fn init() { diff --git a/kernel/src/arch/aarch64/board/raspi3/timer.rs b/kernel/src/arch/aarch64/board/raspi3/timer.rs new file mode 100644 index 00000000..b1a08869 --- /dev/null +++ b/kernel/src/arch/aarch64/board/raspi3/timer.rs @@ -0,0 +1,16 @@ +use super::bcm2837::timer; +use super::bcm2837::interrupt::{Controller, Interrupt}; + +pub fn init() { + Controller::new().enable(Interrupt::Timer1); + set_next(); +} + +pub fn get_cycle() -> u64 { + timer::current_time() +} + +pub fn set_next() { + // 1000 ms + timer::tick_in(timer::SystemTimer::Timer1, 1000 * 1000); +} diff --git a/kernel/src/arch/aarch64/interrupt/handler.rs b/kernel/src/arch/aarch64/interrupt/handler.rs index 371d4d1e..6a3a9054 100644 --- a/kernel/src/arch/aarch64/interrupt/handler.rs +++ b/kernel/src/arch/aarch64/interrupt/handler.rs @@ -1,5 +1,6 @@ //! Trap handler +use arch::board::irq::handle_irq; use super::context::TrapFrame; use super::syndrome::Syndrome; @@ -48,9 +49,7 @@ pub extern "C" fn rust_trap(info: Info, esr: u32, tf: &mut TrapFrame) { _ => ::trap::error(tf), } } - Kind::Irq => { - // TODO - } + Kind::Irq => handle_irq(), _ => ::trap::error(tf), } ::trap::before_return(); diff --git a/kernel/src/arch/aarch64/interrupt/mod.rs b/kernel/src/arch/aarch64/interrupt/mod.rs index 5181cb53..9f6fb0f5 100644 --- a/kernel/src/arch/aarch64/interrupt/mod.rs +++ b/kernel/src/arch/aarch64/interrupt/mod.rs @@ -20,13 +20,13 @@ pub fn init() { /// Enable the interrupt. #[inline(always)] pub unsafe fn enable() { - // TODO + asm!("msr daifclr, #2"); } /// Disable the interrupt. #[inline(always)] pub unsafe fn disable() { - // TODO + asm!("msr daifset, #2"); } /// Disable the interrupt and store the status. diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index 83533248..8548417a 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -9,6 +9,8 @@ pub mod interrupt; #[path = "board/raspi3/mod.rs"] pub mod board; +pub use self::board::timer; + /// TODO /// The entry point of kernel #[no_mangle] // don't mangle the name of this function @@ -20,6 +22,9 @@ pub extern "C" fn rust_main() -> ! { // FIXME // ::logging::init(); interrupt::init(); + timer::init(); + + unsafe { interrupt::enable(); } super::fs::show_logo(); @@ -39,6 +44,9 @@ pub extern "C" fn rust_main() -> ! { println!("svc 666"); asm!("svc 666"); }, + 't' => unsafe { + println!("{}", timer::get_cycle()); + }, ' '...'\u{7e}' => { print!("{}", c); } From 3e1d8c5827676e01586e84a938a49cb5a6228dd7 Mon Sep 17 00:00:00 2001 From: equation314 Date: Sun, 4 Nov 2018 18:15:14 +0800 Subject: [PATCH 19/26] aarch64: implement ARM generic timer, can work in qemu --- crate/bcm2837/Cargo.toml | 4 + crate/bcm2837/src/timer/generic_timer.rs | 83 +++++++++++++++++++ crate/bcm2837/src/timer/mod.rs | 26 ++++++ .../src/{timer.rs => timer/system_timer.rs} | 37 +++++---- kernel/Cargo.lock | 25 ++++++ kernel/Cargo.toml | 2 +- kernel/src/arch/aarch64/board/raspi3/irq.rs | 7 +- kernel/src/arch/aarch64/board/raspi3/timer.rs | 5 +- 8 files changed, 165 insertions(+), 24 deletions(-) create mode 100644 crate/bcm2837/src/timer/generic_timer.rs create mode 100644 crate/bcm2837/src/timer/mod.rs rename crate/bcm2837/src/{timer.rs => timer/system_timer.rs} (67%) diff --git a/crate/bcm2837/Cargo.toml b/crate/bcm2837/Cargo.toml index 969c995f..3fb3e2e9 100644 --- a/crate/bcm2837/Cargo.toml +++ b/crate/bcm2837/Cargo.toml @@ -3,5 +3,9 @@ name = "bcm2837" version = "0.1.0" authors = ["equation314 "] +[features] +use_generic_timer = [] + [dependencies] volatile = "0.2.4" +cortex-a = "2.2.2" diff --git a/crate/bcm2837/src/timer/generic_timer.rs b/crate/bcm2837/src/timer/generic_timer.rs new file mode 100644 index 00000000..6c3c0c8a --- /dev/null +++ b/crate/bcm2837/src/timer/generic_timer.rs @@ -0,0 +1,83 @@ +extern crate cortex_a; + +use self::cortex_a::regs::*; +use volatile::*; + +/// The base address for the ARM generic timer, IRQs, mailboxes +const GEN_TIMER_REG_BASE: usize = 0x40000000; + +/// Core interrupt sources (ref: QA7 4.10, page 16) +#[repr(u8)] +#[allow(dead_code)] +#[allow(non_snake_case)] +#[derive(Copy, Clone, PartialEq, Debug)] +enum CoreInterrupt { + CNTPSIRQ = 0, + CNTPNSIRQ = 1, + CNTHPIRQ = 2, + CNTVIRQ = 3, + Mailbox0 = 4, + Mailbox1 = 5, + Mailbox2 = 6, + Mailbox3 = 7, + Gpu = 8, + Pmu = 9, + AxiOutstanding = 10, + LocalTimer = 11, +} + +/// Timer, IRQs, mailboxes registers (ref: QA7 chapter 4, page 7) +#[allow(non_snake_case)] +#[repr(C)] +struct Registers { + CONTROL: Volatile, + _unused1: [Volatile; 8], + LOCAL_IRQ: Volatile, + _unused2: [Volatile; 3], + LOCAL_TIMER_CTL: Volatile, + LOCAL_TIMER_FLAGS: Volatile, + _unused3: Volatile, + CORE_TIMER_IRQCNTL: [Volatile; 4], + CORE_MAILBOX_IRQCNTL: [Volatile; 4], + CORE_IRQ_SRC: [Volatile; 4], +} + +/// The ARM generic timer. +pub struct Timer { + registers: &'static mut Registers, +} + +impl Timer { + /// Returns a new instance of `Timer`. + pub fn new() -> Timer { + Timer { + registers: unsafe { &mut *(GEN_TIMER_REG_BASE as *mut Registers) }, + } + } + + /// Reads the generic timer's counter and returns the 64-bit counter value. + /// The returned value is the number of elapsed microseconds. + pub fn read(&self) -> u64 { + let cntfrq = CNTFRQ_EL0.get(); + (CNTPCT_EL0.get() * 1000000 / (cntfrq as u64)) as u64 + } + + /// Sets up a match in timer 1 to occur `us` microseconds from now. If + /// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer + /// interrupt will be issued in `us` microseconds. + pub fn tick_in(&mut self, us: u32) { + let cntfrq = CNTFRQ_EL0.get(); + CNTP_TVAL_EL0.set(((cntfrq as f64) * (us as f64) / 1000000.0) as u32); + } + + /// Initialization timer + pub fn init(&mut self) { + self.registers.CORE_TIMER_IRQCNTL[0].write(1 << (CoreInterrupt::CNTPNSIRQ as u8)); + CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET); + } + + /// Returns `true` if timer interruption is pending. Otherwise, returns `false`. + pub fn is_pending(&self) -> bool { + self.registers.CORE_IRQ_SRC[0].read() & (1 << (CoreInterrupt::CNTPNSIRQ as u8)) != 0 + } +} diff --git a/crate/bcm2837/src/timer/mod.rs b/crate/bcm2837/src/timer/mod.rs new file mode 100644 index 00000000..da501cbd --- /dev/null +++ b/crate/bcm2837/src/timer/mod.rs @@ -0,0 +1,26 @@ +#[cfg(feature = "use_generic_timer")] +mod generic_timer; +#[cfg(feature = "use_generic_timer")] +pub use self::generic_timer::Timer; + +#[cfg(not(feature = "use_generic_timer"))] +mod system_timer; +#[cfg(not(feature = "use_generic_timer"))] +pub use self::system_timer::Timer; + +/// Initialization timer +pub fn init() { + Timer::new().init(); +} + +/// Returns the current time in microseconds. +pub fn current_time() -> u64 { + Timer::new().read() +} + +/// Sets up a match in timer 1 to occur `us` microseconds from now. If +/// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer +/// interrupt will be issued in `us` microseconds. +pub fn tick_in(us: u32) { + Timer::new().tick_in(us); +} diff --git a/crate/bcm2837/src/timer.rs b/crate/bcm2837/src/timer/system_timer.rs similarity index 67% rename from crate/bcm2837/src/timer.rs rename to crate/bcm2837/src/timer/system_timer.rs index 3e485b84..cad2af46 100644 --- a/crate/bcm2837/src/timer.rs +++ b/crate/bcm2837/src/timer/system_timer.rs @@ -1,5 +1,6 @@ -use super::IO_BASE; +use ::IO_BASE; use volatile::{ReadOnly, Volatile}; +use interrupt::{Controller, Interrupt}; /// The base address for the ARM system timer registers. const TIMER_REG_BASE: usize = IO_BASE + 0x3000; @@ -15,8 +16,9 @@ struct Registers { } #[repr(u8)] -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum SystemTimer { +#[allow(dead_code)] +#[derive(Copy, Clone, PartialEq, Debug)] +enum SystemTimer { Timer0 = 0, Timer1 = 1, Timer2 = 2, @@ -47,22 +49,21 @@ impl Timer { /// Sets up a match in timer 1 to occur `us` microseconds from now. If /// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer /// interrupt will be issued in `us` microseconds. - pub fn tick_in(&mut self, st: SystemTimer, us: u32) { + pub fn tick_in(&mut self, us: u32) { let current_low = self.registers.CLO.read(); let compare = current_low.wrapping_add(us); - self.registers.COMPARE[st as usize].write(compare); - self.registers.CS.write(1 << (st as usize)); // unmask + self.registers.COMPARE[SystemTimer::Timer1 as usize].write(compare); + self.registers.CS.write(1 << (SystemTimer::Timer1 as usize)); // unmask + } + + /// Initialization timer + pub fn init(&mut self) { + Controller::new().enable(Interrupt::Timer1); + } + + /// Returns `true` if timer interruption is pending. Otherwise, returns `false`. + pub fn is_pending(&self) -> bool { + let controller = Controller::new(); + controller.is_pending(Interrupt::Timer1) } } - -/// Returns the current time in microseconds. -pub fn current_time() -> u64 { - Timer::new().read() -} - -/// Sets up a match in timer 1 to occur `us` microseconds from now. If -/// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer -/// interrupt will be issued in `us` microseconds. -pub fn tick_in(st: SystemTimer, us: u32) { - Timer::new().tick_in(st, us) -} diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 3886b0cc..3d0ffa66 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -11,6 +11,7 @@ version = "0.1.0" name = "bcm2837" version = "0.1.0" dependencies = [ + "cortex-a 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -57,6 +58,14 @@ name = "cfg-if" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cortex-a" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fixedvec" version = "0.2.3" @@ -150,6 +159,14 @@ name = "redox_syscall" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "register" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tock-registers 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "remove_dir_all" version = "0.5.1" @@ -204,6 +221,11 @@ dependencies = [ "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tock-registers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "uart_16550" version = "0.1.0" @@ -328,6 +350,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bootloader 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f1721ced9efc102309bc218c7934d642f60567858faf8d5dd90c0cc6722d97b9" "checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" +"checksum cortex-a 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b187d0d728b4a99ba1d79f9671b976bcdd71a8a2c719585218fd2dc14a4d08c" "checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" @@ -341,12 +364,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" +"checksum register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e10f31b6d2299e5620986ad9fcdd66463e125ad72af4f403f9aedf7592d5ccdb" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum simple-filesystem 0.0.1 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust)" = "" "checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c" "checksum spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "37b5646825922b96b5d7d676b5bb3458a54498e96ed7b0ce09dc43a07038fea4" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +"checksum tock-registers 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a385d94f3f62e60445a0adb9ff8d9621faa272234530d4c0f848ec98f88e316" "checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index fe193773..476d0c5d 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -44,7 +44,7 @@ riscv = { path = "../crate/riscv" } bbl = { path = "../crate/bbl" } [target.'cfg(target_arch = "aarch64")'.dependencies] -bcm2837 = { path = "../crate/bcm2837" } +bcm2837 = { path = "../crate/bcm2837", features = ["use_generic_timer"] } [package.metadata.bootimage] default-target = "x86_64-blog_os.json" diff --git a/kernel/src/arch/aarch64/board/raspi3/irq.rs b/kernel/src/arch/aarch64/board/raspi3/irq.rs index 5f1fb0d9..3c3e0b55 100644 --- a/kernel/src/arch/aarch64/board/raspi3/irq.rs +++ b/kernel/src/arch/aarch64/board/raspi3/irq.rs @@ -1,9 +1,10 @@ +use super::bcm2837::timer::Timer; use super::bcm2837::interrupt::{Controller, Interrupt}; pub fn handle_irq() { - let controller = Controller::new(); - if controller.is_pending(Interrupt::Timer1) { - println!("Timer tick..."); + let controller = Timer::new(); + if controller.is_pending() { + println!("Timer tick {}...", super::timer::get_cycle()); super::timer::set_next(); // ::trap::timer(); } diff --git a/kernel/src/arch/aarch64/board/raspi3/timer.rs b/kernel/src/arch/aarch64/board/raspi3/timer.rs index b1a08869..2e54fb36 100644 --- a/kernel/src/arch/aarch64/board/raspi3/timer.rs +++ b/kernel/src/arch/aarch64/board/raspi3/timer.rs @@ -2,8 +2,9 @@ use super::bcm2837::timer; use super::bcm2837::interrupt::{Controller, Interrupt}; pub fn init() { - Controller::new().enable(Interrupt::Timer1); + timer::init(); set_next(); + info!("timer: init end"); } pub fn get_cycle() -> u64 { @@ -12,5 +13,5 @@ pub fn get_cycle() -> u64 { pub fn set_next() { // 1000 ms - timer::tick_in(timer::SystemTimer::Timer1, 1000 * 1000); + timer::tick_in(1000 * 1000); } From 7b6173a7bdba3ccfd06c543e0d35bc5ab5c0d46c Mon Sep 17 00:00:00 2001 From: equation314 Date: Sun, 4 Nov 2018 18:27:21 +0800 Subject: [PATCH 20/26] aarch64: move function delay() into mod timer in crate bcm2837 --- crate/bcm2837/src/asm.rs | 10 ---------- crate/bcm2837/src/gpio.rs | 20 +++++++++----------- crate/bcm2837/src/interrupt.rs | 2 +- crate/bcm2837/src/lib.rs | 2 -- crate/bcm2837/src/mini_uart.rs | 2 +- crate/bcm2837/src/timer/mod.rs | 8 ++++++++ 6 files changed, 19 insertions(+), 25 deletions(-) delete mode 100644 crate/bcm2837/src/asm.rs diff --git a/crate/bcm2837/src/asm.rs b/crate/bcm2837/src/asm.rs deleted file mode 100644 index a496d92f..00000000 --- a/crate/bcm2837/src/asm.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! utility assembly instructions - -/// delay for some clocks -#[inline] -pub unsafe fn delay(_clock: u32) { - #[cfg(target_arch = "aarch64")] - asm!("mov x1, x0; 1: subs x1, x1, #1; bne 1b;" - :: "{x0}"(_clock) - :: "volatile"); -} diff --git a/crate/bcm2837/src/gpio.rs b/crate/bcm2837/src/gpio.rs index 1b340c77..1fb7fecb 100644 --- a/crate/bcm2837/src/gpio.rs +++ b/crate/bcm2837/src/gpio.rs @@ -1,5 +1,5 @@ -use super::IO_BASE; -use super::asm::delay; +use IO_BASE; +use timer::delay; use core::marker::PhantomData; use volatile::{ReadOnly, Volatile, WriteOnly}; @@ -84,16 +84,14 @@ impl Gpio { /// Set the Gpio pull-up/pull-down state for values in `pin_value` /// (ref: peripherals 6.1, page 101) pub fn set_gpio_pd(&mut self, pud_value: u8) { - unsafe { - let index = if self.pin >= 32 { 1 } else { 0 }; + let index = if self.pin >= 32 { 1 } else { 0 }; - self.registers.PUD.write(pud_value as u32); - delay(150); - self.registers.PUDCLK[index as usize].write((1 << self.pin) as u32); - delay(150); - self.registers.PUD.write(0); - self.registers.PUDCLK[index as usize].write(0); - } + self.registers.PUD.write(pud_value as u32); + delay(150); + self.registers.PUDCLK[index as usize].write((1 << self.pin) as u32); + delay(150); + self.registers.PUD.write(0); + self.registers.PUDCLK[index as usize].write(0); } } diff --git a/crate/bcm2837/src/interrupt.rs b/crate/bcm2837/src/interrupt.rs index cf340ee7..7324085a 100644 --- a/crate/bcm2837/src/interrupt.rs +++ b/crate/bcm2837/src/interrupt.rs @@ -1,4 +1,4 @@ -use super::IO_BASE; +use IO_BASE; use volatile::{ReadOnly, Volatile}; const INT_BASE: usize = IO_BASE + 0xB000 + 0x200; diff --git a/crate/bcm2837/src/lib.rs b/crate/bcm2837/src/lib.rs index 13da9ffa..9635fdce 100644 --- a/crate/bcm2837/src/lib.rs +++ b/crate/bcm2837/src/lib.rs @@ -3,8 +3,6 @@ extern crate volatile; -mod asm; - pub mod gpio; pub mod timer; pub mod mini_uart; diff --git a/crate/bcm2837/src/mini_uart.rs b/crate/bcm2837/src/mini_uart.rs index 58160177..28e2c13f 100644 --- a/crate/bcm2837/src/mini_uart.rs +++ b/crate/bcm2837/src/mini_uart.rs @@ -1,4 +1,4 @@ -use super::IO_BASE; +use IO_BASE; use gpio::{Function, Gpio}; use volatile::{ReadOnly, Volatile}; diff --git a/crate/bcm2837/src/timer/mod.rs b/crate/bcm2837/src/timer/mod.rs index da501cbd..f88b33d1 100644 --- a/crate/bcm2837/src/timer/mod.rs +++ b/crate/bcm2837/src/timer/mod.rs @@ -24,3 +24,11 @@ pub fn current_time() -> u64 { pub fn tick_in(us: u32) { Timer::new().tick_in(us); } + +/// wait for `cycle` CPU cycles +#[inline(always)] +pub fn delay(cycle: u32) { + for _ in 0..cycle { + unsafe { asm!("nop") } + } +} From a91534e34d7dfe471495d5a20293e9c7118a907f Mon Sep 17 00:00:00 2001 From: equation314 Date: Tue, 6 Nov 2018 21:44:12 +0800 Subject: [PATCH 21/26] aarch64: implement context switch, but not tested --- kernel/src/arch/aarch64/board/raspi3/irq.rs | 3 +- kernel/src/arch/aarch64/interrupt/context.rs | 151 +++++++++++++++---- kernel/src/arch/aarch64/interrupt/handler.rs | 2 +- kernel/src/arch/aarch64/interrupt/mod.rs | 4 +- kernel/src/arch/aarch64/interrupt/trap.S | 4 +- kernel/src/arch/aarch64/mod.rs | 2 + kernel/src/process/mod.rs | 18 ++- 7 files changed, 143 insertions(+), 41 deletions(-) diff --git a/kernel/src/arch/aarch64/board/raspi3/irq.rs b/kernel/src/arch/aarch64/board/raspi3/irq.rs index 3c3e0b55..d7d43b27 100644 --- a/kernel/src/arch/aarch64/board/raspi3/irq.rs +++ b/kernel/src/arch/aarch64/board/raspi3/irq.rs @@ -1,7 +1,8 @@ +use arch::interrupt::TrapFrame; use super::bcm2837::timer::Timer; use super::bcm2837::interrupt::{Controller, Interrupt}; -pub fn handle_irq() { +pub fn handle_irq(tf: &mut TrapFrame) { let controller = Timer::new(); if controller.is_pending() { println!("Timer tick {}...", super::timer::get_cycle()); diff --git a/kernel/src/arch/aarch64/interrupt/context.rs b/kernel/src/arch/aarch64/interrupt/context.rs index 06a9bd5c..df08d0a4 100644 --- a/kernel/src/arch/aarch64/interrupt/context.rs +++ b/kernel/src/arch/aarch64/interrupt/context.rs @@ -14,47 +14,136 @@ pub struct TrapFrame { pub x0: u64, } -///TODO -#[derive(Debug)] -pub struct Context { - // TODO +/// 用于在内核栈中构造新线程的中断帧 +impl TrapFrame { + fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, sp: usize) -> Self { + use core::mem::zeroed; + let mut tf: Self = unsafe { zeroed() }; + tf.x0 = arg as u64; + tf.sp = sp as u64; + tf.elr = entry as u64; + tf.spsr = 0b1101_00_0101; // To EL 1, enable IRQ + tf + } + fn new_user_thread(entry_addr: usize, sp: usize) -> Self { + use core::mem::zeroed; + let mut tf: Self = unsafe { zeroed() }; + tf.sp = sp as u64; + tf.elr = entry_addr as u64; + tf.spsr = 0b1101_00_0000; // To EL 0, enable IRQ + tf + } + pub fn is_user(&self) -> bool { + unimplemented!() + } } +/// 新线程的内核栈初始内容 +#[derive(Debug)] +#[repr(C)] +pub struct InitStack { + context: ContextData, + tf: TrapFrame, +} + +impl InitStack { + unsafe fn push_at(self, stack_top: usize) -> Context { + let ptr = (stack_top as *mut Self).offset(-1); + *ptr = self; + Context(ptr as usize) + } +} + +extern { + fn __trapret(); +} + +#[derive(Debug, Default)] +#[repr(C)] +struct ContextData { + x19to29: [usize; 11], + lr: usize, + ttbr0: usize, +} + +impl ContextData { + fn new(ttbr0: usize) -> Self { + ContextData { lr: __trapret as usize, ttbr0, ..ContextData::default() } + } +} + + +#[derive(Debug)] +pub struct Context(usize); + impl Context { - /// TODO + /// Switch to another kernel thread. + /// + /// Defined in `trap.S`. + /// + /// Push all callee-saved registers at the current kernel stack. + /// Store current sp, switch to target. + /// Pop all callee-saved registers, then return to the target. + #[naked] #[inline(never)] - pub unsafe extern "C" fn switch(&mut self, target: &mut Self) { - unimplemented!() + pub unsafe extern fn switch(&mut self, target: &mut Self) { + asm!( + " + mov x10, #-(13 * 8) + add x8, sp, x10 + str x8, [x0] + stp x19, x20, [x8], #16 // store callee-saved registers + stp x21, x22, [x8], #16 + stp x23, x24, [x8], #16 + stp x25, x26, [x8], #16 + stp x27, x28, [x8], #16 + stp x29, lr, [x8], #16 + mrs x9, ttbr0_el1 + str x9, [x8], #8 + + ldr x8, [x1] + ldp x19, x20, [x8], #16 // restore callee-saved registers + ldp x21, x22, [x8], #16 + ldp x23, x24, [x8], #16 + ldp x25, x26, [x8], #16 + ldp x27, x28, [x8], #16 + ldp x29, lr, [x8], #16 + ldr x9, [x8], #8 + mov sp, x8 + + msr ttbr0_el1, x9 // set new page directory + dsb ishst // ensure write has completed + tlbi vmalle1is // invalidate the TLB entry for the entry that changes + dsb ish // ensure TLB invalidation is complete + isb // synchronize context on this processor + ret" + : : : : "volatile" ); } - /// TODO pub unsafe fn null() -> Self { - unimplemented!() + Context(0) } - /// TODO - pub unsafe fn new_kernel_thread( - entry: extern "C" fn(usize) -> !, - arg: usize, - kstack_top: usize, - cr3: usize, - ) -> Self { - unimplemented!() + pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, ttbr0: usize) -> Self { + InitStack { + context: ContextData::new(ttbr0), + tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top), + }.push_at(kstack_top) } - - /// TODO - pub unsafe fn new_user_thread( - entry_addr: usize, - ustack_top: usize, - kstack_top: usize, - is32: bool, - cr3: usize, - ) -> Self { - unimplemented!() + pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, is32: bool, ttbr0: usize) -> Self { + InitStack { + context: ContextData::new(ttbr0), + tf: TrapFrame::new_user_thread(entry_addr, ustack_top), + }.push_at(kstack_top) } - - /// TODO - pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, cr3: usize) -> Self { - unimplemented!() + pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, ttbr0: usize) -> Self { + InitStack { + context: ContextData::new(ttbr0), + tf: { + let mut tf = tf.clone(); + tf.x0 = 0; + tf + }, + }.push_at(kstack_top) } } diff --git a/kernel/src/arch/aarch64/interrupt/handler.rs b/kernel/src/arch/aarch64/interrupt/handler.rs index 6a3a9054..7253e4d3 100644 --- a/kernel/src/arch/aarch64/interrupt/handler.rs +++ b/kernel/src/arch/aarch64/interrupt/handler.rs @@ -49,7 +49,7 @@ pub extern "C" fn rust_trap(info: Info, esr: u32, tf: &mut TrapFrame) { _ => ::trap::error(tf), } } - Kind::Irq => handle_irq(), + Kind::Irq => handle_irq(tf), _ => ::trap::error(tf), } ::trap::before_return(); diff --git a/kernel/src/arch/aarch64/interrupt/mod.rs b/kernel/src/arch/aarch64/interrupt/mod.rs index 9f6fb0f5..2ced2839 100644 --- a/kernel/src/arch/aarch64/interrupt/mod.rs +++ b/kernel/src/arch/aarch64/interrupt/mod.rs @@ -17,13 +17,13 @@ pub fn init() { } } -/// Enable the interrupt. +/// Enable the interrupt (only IRQ). #[inline(always)] pub unsafe fn enable() { asm!("msr daifclr, #2"); } -/// Disable the interrupt. +/// Disable the interrupt (only IRQ). #[inline(always)] pub unsafe fn disable() { asm!("msr daifset, #2"); diff --git a/kernel/src/arch/aarch64/interrupt/trap.S b/kernel/src/arch/aarch64/interrupt/trap.S index fb511108..331ba41a 100644 --- a/kernel/src/arch/aarch64/interrupt/trap.S +++ b/kernel/src/arch/aarch64/interrupt/trap.S @@ -97,7 +97,7 @@ __alltraps: mov x2, sp bl rust_trap -.global trap_ret -trap_ret: +.global __trapret +__trapret: RESTORE_ALL eret diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index 8548417a..f5461a69 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -24,6 +24,8 @@ pub extern "C" fn rust_main() -> ! { interrupt::init(); timer::init(); + // ::process::init(); + unsafe { interrupt::enable(); } super::fs::show_logo(); diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 569f3d2a..09636cdf 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -5,6 +5,8 @@ pub use ucore_process::processor::{*, Context as _whatever}; pub use ucore_process::scheduler::*; pub use ucore_process::thread::*; +use arch::timer; + mod context; type Processor = Processor_; @@ -17,10 +19,18 @@ pub fn init() { // NOTE: max_time_slice <= 5 to ensure 'priority' test pass StrideScheduler::new(5), ); - extern fn idle(arg: usize) -> ! { - loop {} + extern fn idle1(arg: usize) -> ! { + loop { + println!("idle 1 {}", timer::get_cycle()); + } } - processor.add(Context::new_kernel(idle, 0)); + extern fn idle2(arg: usize) -> ! { + loop { + println!("idle 2 {}", timer::get_cycle()); + } + } + processor.add(Context::new_kernel(idle1, 0)); + processor.add(Context::new_kernel(idle2, 0)); processor }) ); @@ -50,4 +60,4 @@ impl ThreadSupport for ThreadSupportImpl { fn processor() -> Self::ProcessorGuard { processor() } -} \ No newline at end of file +} From 9fc13c8ebbb326d9b6dd0c1a36638c3b4ce2d03c Mon Sep 17 00:00:00 2001 From: equation314 Date: Wed, 7 Nov 2018 01:05:43 +0800 Subject: [PATCH 22/26] aarch64: implement syscall --- kernel/src/arch/aarch64/interrupt/context.rs | 26 ++++++++--------- kernel/src/arch/aarch64/interrupt/handler.rs | 23 +++++++++++---- kernel/src/arch/aarch64/mod.rs | 8 ++++-- user/aarch64-ucore.json | 30 ++++++++++++++++++++ user/ucore-ulib/src/syscall.rs | 10 +++++-- 5 files changed, 75 insertions(+), 22 deletions(-) create mode 100644 user/aarch64-ucore.json diff --git a/kernel/src/arch/aarch64/interrupt/context.rs b/kernel/src/arch/aarch64/interrupt/context.rs index df08d0a4..9bc2e778 100644 --- a/kernel/src/arch/aarch64/interrupt/context.rs +++ b/kernel/src/arch/aarch64/interrupt/context.rs @@ -3,15 +3,15 @@ #[repr(C)] #[derive(Default, Debug, Copy, Clone)] pub struct TrapFrame { - pub elr: u64, - pub spsr: u64, - pub sp: u64, - pub tpidr: u64, + pub elr: usize, + pub spsr: usize, + pub sp: usize, + pub tpidr: usize, // pub q0to31: [u128; 32], // disable SIMD/FP registers - pub x1to29: [u64; 29], - pub __reserved: u64, - pub x30: u64, // lr - pub x0: u64, + pub x1to29: [usize; 29], + pub __reserved: usize, + pub x30: usize, // lr + pub x0: usize, } /// 用于在内核栈中构造新线程的中断帧 @@ -19,17 +19,17 @@ impl TrapFrame { fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, sp: usize) -> Self { use core::mem::zeroed; let mut tf: Self = unsafe { zeroed() }; - tf.x0 = arg as u64; - tf.sp = sp as u64; - tf.elr = entry as u64; + tf.x0 = arg; + tf.sp = sp; + tf.elr = entry as usize; tf.spsr = 0b1101_00_0101; // To EL 1, enable IRQ tf } fn new_user_thread(entry_addr: usize, sp: usize) -> Self { use core::mem::zeroed; let mut tf: Self = unsafe { zeroed() }; - tf.sp = sp as u64; - tf.elr = entry_addr as u64; + tf.sp = sp; + tf.elr = entry_addr; tf.spsr = 0b1101_00_0000; // To EL 0, enable IRQ tf } diff --git a/kernel/src/arch/aarch64/interrupt/handler.rs b/kernel/src/arch/aarch64/interrupt/handler.rs index 7253e4d3..85d1faf7 100644 --- a/kernel/src/arch/aarch64/interrupt/handler.rs +++ b/kernel/src/arch/aarch64/interrupt/handler.rs @@ -45,7 +45,7 @@ pub extern "C" fn rust_trap(info: Info, esr: u32, tf: &mut TrapFrame) { // syndrome is only valid with sync match syndrome { Syndrome::Brk(brk) => handle_break(brk, tf), - Syndrome::Svc(syscall) => handle_syscall(syscall, tf), + Syndrome::Svc(_) => handle_syscall(tf), _ => ::trap::error(tf), } } @@ -57,10 +57,23 @@ pub extern "C" fn rust_trap(info: Info, esr: u32, tf: &mut TrapFrame) { } fn handle_break(num: u16, tf: &mut TrapFrame) { - tf.elr += 4; // Skip the current brk instruction + // Skip the current brk instruction (ref: J1.1.2, page 6147) + tf.elr += 4; } -fn handle_syscall(num: u16, tf: &mut TrapFrame) { - // svc instruction has been skipped in syscall - println!("syscall {}", num); +fn handle_syscall(tf: &mut TrapFrame) { + // svc instruction has been skipped in syscall (ref: J1.1.2, page 6152) + let ret = ::syscall::syscall( + tf.x1to29[7] as usize, + [ + tf.x0, + tf.x1to29[0], + tf.x1to29[1], + tf.x1to29[2], + tf.x1to29[3], + tf.x1to29[4], + ], + tf, + ); + tf.x0 = ret as usize; } diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index f5461a69..01f4d4e0 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -43,8 +43,12 @@ pub extern "C" fn rust_main() -> ! { asm!("brk 233"); }, 'c' => unsafe { - println!("svc 666"); - asm!("svc 666"); + println!("sys_putc"); + asm!( + "mov x8, #30 + mov x0, #65 + svc 0" + ); }, 't' => unsafe { println!("{}", timer::get_cycle()); diff --git a/user/aarch64-ucore.json b/user/aarch64-ucore.json new file mode 100644 index 00000000..357c2e3c --- /dev/null +++ b/user/aarch64-ucore.json @@ -0,0 +1,30 @@ +{ + "abi-blacklist": [ + "stdcall", + "fastcall", + "vectorcall", + "thiscall", + "win64", + "sysv64" + ], + "arch": "aarch64", + "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + "executables": true, + "linker": "rust-lld", + "linker-flavor": "ld.lld", + "linker-is-gnu": true, + "llvm-target": "aarch64-unknown-none", + "no-compiler-rt": true, + "features": "+a53,+strict-align,-neon", + "max-atomic-width": 128, + "os": "none", + "panic": "abort", + "panic-strategy": "abort", + "relocation-model": "static", + "position-independent-executables": true, + "target-c-int-width": "32", + "target-endian": "little", + "target-pointer-width": "64", + "target-family": "unix", + "disable-redzone": true +} diff --git a/user/ucore-ulib/src/syscall.rs b/user/ucore-ulib/src/syscall.rs index 5d8765b1..f7071429 100644 --- a/user/ucore-ulib/src/syscall.rs +++ b/user/ucore-ulib/src/syscall.rs @@ -44,6 +44,12 @@ fn sys_call(id: usize, arg0: usize, arg1: usize, arg2: usize, arg3: usize, arg4: : "{rax}" (id), "{rdi}" (arg0), "{rsi}" (arg1), "{rdx}" (arg2), "{rcx}" (arg3), "{r8}" (arg4), "{r9}" (arg5) : "memory" : "intel" "volatile"); + #[cfg(target_arch = "aarch64")] + asm!("svc 0" + : "={x0}" (ret) + : "{x8}" (id), "{x0}" (arg0), "{x1}" (arg1), "{x2}" (arg2), "{x3}" (arg3), "{x4}" (arg4), "{x5}" (arg5) + : "memory" + : "volatile"); } ret } @@ -68,7 +74,7 @@ pub fn sys_open(path: &str, flags: usize) -> i32 { } pub fn sys_close(fd: usize) -> i32 { - sys_call(SYS_CLOSE, fd, 0 , 0, 0, 0, 0) + sys_call(SYS_CLOSE, fd, 0, 0, 0, 0, 0) } /// Fork the current process. Return the child's PID. @@ -137,4 +143,4 @@ const SYS_FSYNC: usize = 111; const SYS_GETCWD: usize = 121; const SYS_GETDIRENTRY: usize = 128; const SYS_DUP: usize = 130; -const SYS_LAB6_SET_PRIORITY: usize = 255; \ No newline at end of file +const SYS_LAB6_SET_PRIORITY: usize = 255; From a13f39149b22100f22c10b6519a840f56b22002a Mon Sep 17 00:00:00 2001 From: koumingyang <1761674434@qq.com> Date: Wed, 7 Nov 2018 10:44:24 +0800 Subject: [PATCH 23/26] add basic alloc --- crate/atags/Cargo.lock | 14 +++++++ crate/atags/Cargo.toml | 6 +++ crate/atags/src/atag.rs | 67 +++++++++++++++++++++++++++++++ crate/atags/src/atags.rs | 37 +++++++++++++++++ crate/atags/src/lib.rs | 6 +++ crate/atags/src/raw.rs | 67 +++++++++++++++++++++++++++++++ kernel/Cargo.lock | 6 +++ kernel/Cargo.toml | 2 + kernel/src/arch/aarch64/memory.rs | 28 ++++++++++++- kernel/src/arch/aarch64/mod.rs | 14 +++++++ 10 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 crate/atags/Cargo.lock create mode 100644 crate/atags/Cargo.toml create mode 100644 crate/atags/src/atag.rs create mode 100644 crate/atags/src/atags.rs create mode 100644 crate/atags/src/lib.rs create mode 100644 crate/atags/src/raw.rs diff --git a/crate/atags/Cargo.lock b/crate/atags/Cargo.lock new file mode 100644 index 00000000..42d11ebd --- /dev/null +++ b/crate/atags/Cargo.lock @@ -0,0 +1,14 @@ +[[package]] +name = "atags" +version = "0.1.0" +dependencies = [ + "volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "volatile" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ca391c55768e479d5c2f8beb40c136df09257292a809ea514e82cfdfc15d00" diff --git a/crate/atags/Cargo.toml b/crate/atags/Cargo.toml new file mode 100644 index 00000000..3c095bfa --- /dev/null +++ b/crate/atags/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "atags" +version = "0.1.0" +authors = ["koumingyang <1761674434@qq.com>"] + +[dependencies] \ No newline at end of file diff --git a/crate/atags/src/atag.rs b/crate/atags/src/atag.rs new file mode 100644 index 00000000..77f729a7 --- /dev/null +++ b/crate/atags/src/atag.rs @@ -0,0 +1,67 @@ +use raw; +use core::slice; +use core::str; + +pub use raw::{Core, Mem}; + +/// An ATAG. +#[derive(Debug, Copy, Clone)] +pub enum Atag { + Core(raw::Core), + Mem(raw::Mem), + Cmd(&'static str), + Unknown(u32), + None +} + +impl Atag { + /// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`. + pub fn core(self) -> Option { + match self { + Atag::Core(x) => Some(x), + _ => None, + } + } + + /// Returns `Some` if this is a `Mem` ATAG. Otherwise returns `None`. + pub fn mem(self) -> Option { + match self { + Atag::Mem(x) => Some(x), + _ => None, + } + } + + /// Returns `Some` with the command line string if this is a `Cmd` ATAG. + /// Otherwise returns `None`. + pub fn cmd(self) -> Option<&'static str> { + match self { + Atag::Cmd(x) => Some(x), + _ => None, + } + } +} + +// Convert between raw::* types and Atag wrapper. +impl<'a> From<&'a raw::Atag> for Atag { + fn from(atag: &raw::Atag) -> Atag { + unsafe { + match (atag.tag, &atag.kind) { + (raw::Atag::CORE, &raw::Kind { core }) => Atag::Core(core), + (raw::Atag::MEM, &raw::Kind { mem }) => Atag::Mem(mem), + (raw::Atag::CMDLINE, &raw::Kind { ref cmd }) => { + let mut cmd_ptr: *const u8 = &cmd.cmd as *const u8; + let mut len: usize = 0; + + while *cmd_ptr.add(len) != 0 { + len += 1; + } + + let cmd_slice = slice::from_raw_parts(cmd_ptr, len); + Atag::Cmd(str::from_utf8_unchecked(cmd_slice)) + }, + (raw::Atag::NONE, _) => Atag::None, + (id, _) => Atag::Unknown(id), + } + } + } +} diff --git a/crate/atags/src/atags.rs b/crate/atags/src/atags.rs new file mode 100644 index 00000000..98b7522a --- /dev/null +++ b/crate/atags/src/atags.rs @@ -0,0 +1,37 @@ +pub use atag::*; +use raw; + +/// The address at which the firmware loads the ATAGS. +const ATAG_BASE: usize = 0x100; + +/// An iterator over the ATAGS on this system. +pub struct Atags { + ptr: &'static raw::Atag, +} + +impl Atags { + /// Returns an instance of `Atags`, an iterator over ATAGS on this system. + pub fn get() -> Atags { + Atags { + ptr: unsafe { &*(ATAG_BASE as *const raw::Atag) } + } + } +} + +impl Iterator for Atags { + type Item = Atag; + + /// Iterate over Atags. Returns a valid Atag until the iterator hits the + /// Atag::None. + fn next(&mut self) -> Option { + let cur = self.ptr; + match cur.next() { + Some(next) => { + let result = Some(Atag::from(cur)); + self.ptr = next; + result + }, + None => None, + } + } +} diff --git a/crate/atags/src/lib.rs b/crate/atags/src/lib.rs new file mode 100644 index 00000000..33c76c26 --- /dev/null +++ b/crate/atags/src/lib.rs @@ -0,0 +1,6 @@ +#![no_std] + +mod raw; +mod atag; + +pub mod atags; diff --git a/crate/atags/src/raw.rs b/crate/atags/src/raw.rs new file mode 100644 index 00000000..abfd1669 --- /dev/null +++ b/crate/atags/src/raw.rs @@ -0,0 +1,67 @@ +/// A raw `ATAG` as laid out in memory. +#[repr(C)] +pub struct Atag { + pub dwords: u32, + pub tag: u32, + pub kind: Kind +} + +impl Atag { + pub const NONE: u32 = 0x00000000; + pub const CORE: u32 = 0x54410001; + pub const MEM: u32 = 0x54410002; + pub const VIDEOTEXT: u32 = 0x54410003; + pub const RAMDISK: u32 = 0x54410004; + pub const INITRD2: u32 = 0x54420005; + pub const SERIAL: u32 = 0x54410006; + pub const REVISION: u32 = 0x54410007; + pub const VIDEOLFB: u32 = 0x54410008; + pub const CMDLINE: u32 = 0x54410009; + + /// Returns the ATAG following `self`, if there is one. + pub fn next(&self) -> Option<&Atag> { + if self.tag == Atag::NONE { + None + } else { + let current = self as *const Atag as *const u32; + let next: &Atag = unsafe { + &*(current.add(self.dwords as usize) as *const Atag) + }; + + Some(next) + } + } +} + +/// The possible variant of an ATAG. +#[repr(C)] +pub union Kind { + pub core: Core, + pub mem: Mem, + pub cmd: Cmd +} + +/// A `CORE` ATAG. +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Core { + pub flags: u32, + pub page_size: u32, + pub root_dev: u32 +} + +/// A `MEM` ATAG. +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Mem { + pub size: u32, + pub start: u32 +} + +/// A `CMDLINE` ATAG. +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Cmd { + /// The first byte of the command line string. + pub cmd: u8 +} diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 3d0ffa66..e1b7d050 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -1,3 +1,7 @@ +[[package]] +name = "atags" +version = "0.1.0" + [[package]] name = "bare-metal" version = "0.2.3" @@ -239,6 +243,7 @@ dependencies = [ name = "ucore" version = "0.1.0" dependencies = [ + "atags 0.1.0", "bbl 0.1.0", "bcm2837 0.1.0", "bit-allocator 0.1.0", @@ -246,6 +251,7 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bootloader 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-a 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 476d0c5d..e2bba971 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -44,6 +44,8 @@ riscv = { path = "../crate/riscv" } bbl = { path = "../crate/bbl" } [target.'cfg(target_arch = "aarch64")'.dependencies] +cortex-a = "2.2.1" +atags = { path = "../crate/atags" } bcm2837 = { path = "../crate/bcm2837", features = ["use_generic_timer"] } [package.metadata.bootimage] diff --git a/kernel/src/arch/aarch64/memory.rs b/kernel/src/arch/aarch64/memory.rs index 05fff9de..085ab365 100644 --- a/kernel/src/arch/aarch64/memory.rs +++ b/kernel/src/arch/aarch64/memory.rs @@ -1,8 +1,34 @@ //! Memory initialization for aarch64. use ucore_memory::PAGE_SIZE; +use super::atags::atags::Atags; +use super::super::HEAP_ALLOCATOR; /// Memory initialization. pub fn init() { - // TODO + let (start, end) = memory_map().expect("failed to find memory map"); + unsafe { + HEAP_ALLOCATOR.lock().init(start, end - start); + } +} + +extern "C" { + static _end: u8; +} + +/// Returns the (start address, end address) of the available memory on this +/// system if it can be determined. If it cannot, `None` is returned. +/// +/// This function is expected to return `Some` under all normal cirumstances. +pub fn memory_map() -> Option<(usize, usize)> { + let binary_end = unsafe { (&_end as *const u8) as u32 }; + + let mut atags: Atags = Atags::get(); + while let Some(atag) = atags.next() { + if let Some(mem) = atag.mem() { + return Some((binary_end as usize, (mem.start + mem.size) as usize)); + } + } + + None } diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index 01f4d4e0..826078da 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -1,5 +1,7 @@ //! Entrance and initialization for aarch64. +extern crate atags; + pub mod io; pub mod paging; pub mod memory; @@ -18,6 +20,18 @@ pub extern "C" fn rust_main() -> ! { // Init board to enable serial port. board::init(); + let (start, end) = memory::memory_map().expect("failed to find memory map"); + println!("The value of start is: {}, end is {}", start, end); + + memory::init(); + println!("memory init over"); + + let mut v = vec![]; + for i in 0..1000 { + v.push(i); + println!("{:?}", v); + } + // First init log mod, so that we can print log info. // FIXME // ::logging::init(); From a0b948fb532358c1efd6ab4f67865dc79dab3e42 Mon Sep 17 00:00:00 2001 From: koumingyang <1761674434@qq.com> Date: Wed, 7 Nov 2018 12:00:57 +0800 Subject: [PATCH 24/26] add basic alloc --- kernel/Cargo.lock | 2 ++ kernel/Cargo.toml | 5 ++++ kernel/src/arch/aarch64/mod.rs | 17 ++++++----- kernel/src/arch/aarch64/paging.rs | 49 ++++++++++++++++++++++++------- kernel/src/lib.rs | 2 ++ 5 files changed, 57 insertions(+), 18 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index e1b7d050..4e27780c 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -263,6 +263,8 @@ dependencies = [ "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ucore-memory 0.1.0", "ucore-process 0.1.0", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index e2bba971..21080d59 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -33,6 +33,10 @@ ucore-memory = { path = "../crate/memory" } ucore-process = { path = "../crate/process" } simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-Rust" } +[dependencies.ux] +default-features = false +version = "0.1.0" + [target.'cfg(target_arch = "x86_64")'.dependencies] bootloader = "0.3" x86_64 = "0.2.11" @@ -45,6 +49,7 @@ bbl = { path = "../crate/bbl" } [target.'cfg(target_arch = "aarch64")'.dependencies] cortex-a = "2.2.1" +usize_conversions = "0.2.0" atags = { path = "../crate/atags" } bcm2837 = { path = "../crate/bcm2837", features = ["use_generic_timer"] } diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index 826078da..d3d0e6db 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -1,6 +1,9 @@ //! Entrance and initialization for aarch64. extern crate atags; +extern crate bitflags; +extern crate usize_conversions; +pub extern crate ux; pub mod io; pub mod paging; @@ -26,19 +29,19 @@ pub extern "C" fn rust_main() -> ! { memory::init(); println!("memory init over"); - let mut v = vec![]; - for i in 0..1000 { - v.push(i); - println!("{:?}", v); - } + //let mut v = vec![]; + //for i in 0..1000 { + // v.push(i); + // println!("{:?}", v); + //} // First init log mod, so that we can print log info. // FIXME - // ::logging::init(); + ::logging::init(); interrupt::init(); timer::init(); - // ::process::init(); + ::process::init(); unsafe { interrupt::enable(); } diff --git a/kernel/src/arch/aarch64/paging.rs b/kernel/src/arch/aarch64/paging.rs index 6c218396..76c395c0 100644 --- a/kernel/src/arch/aarch64/paging.rs +++ b/kernel/src/arch/aarch64/paging.rs @@ -3,8 +3,11 @@ use ucore_memory::memory_set::*; use ucore_memory::paging::*; -type VirtAddr = usize; -type PhysAddr = usize; +type VirtAddr=usize; +type PhysAddr=usize; + +use alloc::alloc::{alloc, Layout}; +use memory::alloc_stack; /// TODO pub struct ActivePageTable { @@ -152,21 +155,45 @@ impl Entry for PageEntry { } +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct MockFrame(PhysAddr); + +impl MockFrame { + pub fn of_addr(addr: PhysAddr) -> Self { + MockFrame(addr) + } + pub fn start_address(&self) -> PhysAddr { + unimplemented!() + } + pub fn p2_index(&self) -> usize { + unimplemented!() + } + pub fn p1_index(&self) -> usize { + unimplemented!() + } + pub fn number(&self) -> usize { + unimplemented!() + } +} + /// TODO pub struct InactivePageTable0 { - // TODO + p4_frame: MockFrame, } /// TODO impl InactivePageTable for InactivePageTable0 { type Active = ActivePageTable; - fn new() -> Self { - unimplemented!() + fn new() -> Self { + unsafe {let layout = Layout::new::(); + let ptr = alloc(layout); + let frame = MockFrame::of_addr(*ptr as usize); + InactivePageTable0 { p4_frame: frame }} } fn new_bare() -> Self { - unimplemented!() + Self::new() } fn edit(&mut self, f: impl FnOnce(&mut Self::Active)) { @@ -174,15 +201,15 @@ impl InactivePageTable for InactivePageTable0 { } unsafe fn activate(&self) { - unimplemented!() + } unsafe fn with(&self, f: impl FnOnce()) { - unimplemented!() + } fn token(&self) -> usize { - unimplemented!() + 0 } fn alloc_frame() -> Option { @@ -190,10 +217,10 @@ impl InactivePageTable for InactivePageTable0 { } fn dealloc_frame(target: PhysAddr) { - unimplemented!() + } fn alloc_stack() -> Stack { - unimplemented!() + alloc_stack() } } diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 8305a771..9d876162 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -9,6 +9,7 @@ #![feature(panic_info_message)] #![feature(global_asm)] #![feature(compiler_builtins_lib)] +#![feature(try_from)] #![no_std] @@ -33,6 +34,7 @@ extern crate volatile; #[cfg(target_arch = "x86_64")] extern crate x86_64; extern crate xmas_elf; +extern crate usize_conversions; use linked_list_allocator::LockedHeap; From 67b920cc16cbbb83b2fe79ff2c0042f1f06f097b Mon Sep 17 00:00:00 2001 From: equation314 Date: Wed, 7 Nov 2018 13:09:50 +0800 Subject: [PATCH 25/26] aarch64: format paging.rs --- kernel/Cargo.lock | 2 -- kernel/Cargo.toml | 5 ----- kernel/src/arch/aarch64/memory.rs | 1 + kernel/src/arch/aarch64/mod.rs | 20 ++++++++---------- kernel/src/arch/aarch64/paging.rs | 34 ++++++++++++++----------------- kernel/src/lib.rs | 2 -- 6 files changed, 24 insertions(+), 40 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 4e27780c..e1b7d050 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -263,8 +263,6 @@ dependencies = [ "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ucore-memory 0.1.0", "ucore-process 0.1.0", - "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 21080d59..e2bba971 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -33,10 +33,6 @@ ucore-memory = { path = "../crate/memory" } ucore-process = { path = "../crate/process" } simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-Rust" } -[dependencies.ux] -default-features = false -version = "0.1.0" - [target.'cfg(target_arch = "x86_64")'.dependencies] bootloader = "0.3" x86_64 = "0.2.11" @@ -49,7 +45,6 @@ bbl = { path = "../crate/bbl" } [target.'cfg(target_arch = "aarch64")'.dependencies] cortex-a = "2.2.1" -usize_conversions = "0.2.0" atags = { path = "../crate/atags" } bcm2837 = { path = "../crate/bcm2837", features = ["use_generic_timer"] } diff --git a/kernel/src/arch/aarch64/memory.rs b/kernel/src/arch/aarch64/memory.rs index 085ab365..bf553546 100644 --- a/kernel/src/arch/aarch64/memory.rs +++ b/kernel/src/arch/aarch64/memory.rs @@ -10,6 +10,7 @@ pub fn init() { unsafe { HEAP_ALLOCATOR.lock().init(start, end - start); } + info!("memory: init end"); } extern "C" { diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index d3d0e6db..8c9585d1 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -1,9 +1,6 @@ //! Entrance and initialization for aarch64. extern crate atags; -extern crate bitflags; -extern crate usize_conversions; -pub extern crate ux; pub mod io; pub mod paging; @@ -23,23 +20,22 @@ pub extern "C" fn rust_main() -> ! { // Init board to enable serial port. board::init(); - let (start, end) = memory::memory_map().expect("failed to find memory map"); - println!("The value of start is: {}, end is {}", start, end); + // First init log mod, so that we can print log info. + // FIXME + ::logging::init(); + let (start, end) = memory::memory_map().expect("failed to find memory map"); + println!("The value of start is: {:#x?}, end is {:#x?}", start, end); + + interrupt::init(); memory::init(); - println!("memory init over"); + timer::init(); //let mut v = vec![]; //for i in 0..1000 { // v.push(i); // println!("{:?}", v); //} - - // First init log mod, so that we can print log info. - // FIXME - ::logging::init(); - interrupt::init(); - timer::init(); ::process::init(); diff --git a/kernel/src/arch/aarch64/paging.rs b/kernel/src/arch/aarch64/paging.rs index 76c395c0..e9cc43e8 100644 --- a/kernel/src/arch/aarch64/paging.rs +++ b/kernel/src/arch/aarch64/paging.rs @@ -3,11 +3,11 @@ use ucore_memory::memory_set::*; use ucore_memory::paging::*; -type VirtAddr=usize; -type PhysAddr=usize; +type VirtAddr = usize; +type PhysAddr = usize; use alloc::alloc::{alloc, Layout}; -use memory::alloc_stack; +use memory::{active_table, alloc_frame, alloc_stack, dealloc_frame}; /// TODO pub struct ActivePageTable { @@ -36,7 +36,7 @@ impl PageTable for ActivePageTable { } // For testing with mock - fn get_page_slice_mut<'a,'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8] { + fn get_page_slice_mut<'a, 'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8] { unimplemented!() } @@ -82,7 +82,6 @@ impl Entry for PageEntry { unimplemented!() } - fn clear_accessed(&mut self) { unimplemented!() } @@ -99,7 +98,6 @@ impl Entry for PageEntry { unimplemented!() } - fn target(&self) -> PhysAddr { unimplemented!() } @@ -108,7 +106,6 @@ impl Entry for PageEntry { unimplemented!() } - // For Copy-on-write extension fn writable_shared(&self) -> bool { unimplemented!() @@ -126,7 +123,6 @@ impl Entry for PageEntry { unimplemented!() } - // For Swap extension fn swapped(&self) -> bool { unimplemented!() @@ -136,7 +132,6 @@ impl Entry for PageEntry { unimplemented!() } - fn user(&self) -> bool { unimplemented!() } @@ -152,7 +147,6 @@ impl Entry for PageEntry { fn set_execute(&mut self, value: bool) { unimplemented!() } - } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] @@ -186,14 +180,16 @@ impl InactivePageTable for InactivePageTable0 { type Active = ActivePageTable; fn new() -> Self { - unsafe {let layout = Layout::new::(); - let ptr = alloc(layout); - let frame = MockFrame::of_addr(*ptr as usize); - InactivePageTable0 { p4_frame: frame }} + unsafe { + let layout = Layout::new::(); + let ptr = alloc(layout); + let frame = MockFrame::of_addr(*ptr as usize); + InactivePageTable0 { p4_frame: frame } + } } fn new_bare() -> Self { - Self::new() + unimplemented!() } fn edit(&mut self, f: impl FnOnce(&mut Self::Active)) { @@ -201,11 +197,11 @@ impl InactivePageTable for InactivePageTable0 { } unsafe fn activate(&self) { - + unimplemented!() } unsafe fn with(&self, f: impl FnOnce()) { - + unimplemented!() } fn token(&self) -> usize { @@ -213,11 +209,11 @@ impl InactivePageTable for InactivePageTable0 { } fn alloc_frame() -> Option { - unimplemented!() + alloc_frame() } fn dealloc_frame(target: PhysAddr) { - + dealloc_frame(target) } fn alloc_stack() -> Stack { diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 9d876162..8305a771 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -9,7 +9,6 @@ #![feature(panic_info_message)] #![feature(global_asm)] #![feature(compiler_builtins_lib)] -#![feature(try_from)] #![no_std] @@ -34,7 +33,6 @@ extern crate volatile; #[cfg(target_arch = "x86_64")] extern crate x86_64; extern crate xmas_elf; -extern crate usize_conversions; use linked_list_allocator::LockedHeap; From 5610d0bdb0e4261a28f646167fcf9aef88e64866 Mon Sep 17 00:00:00 2001 From: equation314 Date: Wed, 7 Nov 2018 22:07:48 +0800 Subject: [PATCH 26/26] aarch64: context switch is runnable! --- kernel/src/arch/aarch64/board/raspi3/irq.rs | 3 +- kernel/src/arch/aarch64/board/raspi3/timer.rs | 4 +- kernel/src/arch/aarch64/boot/boot.S | 3 + kernel/src/arch/aarch64/interrupt/context.rs | 2 + kernel/src/arch/aarch64/interrupt/mod.rs | 8 ++- kernel/src/arch/aarch64/mod.rs | 61 +------------------ kernel/src/fs.rs | 56 +++++++++++++++++ kernel/src/lib.rs | 16 ++++- kernel/src/process/context.rs | 11 +++- kernel/src/process/mod.rs | 21 +++---- kernel/src/sync/mutex.rs | 6 +- 11 files changed, 109 insertions(+), 82 deletions(-) diff --git a/kernel/src/arch/aarch64/board/raspi3/irq.rs b/kernel/src/arch/aarch64/board/raspi3/irq.rs index d7d43b27..e01a2c30 100644 --- a/kernel/src/arch/aarch64/board/raspi3/irq.rs +++ b/kernel/src/arch/aarch64/board/raspi3/irq.rs @@ -5,8 +5,7 @@ use super::bcm2837::interrupt::{Controller, Interrupt}; pub fn handle_irq(tf: &mut TrapFrame) { let controller = Timer::new(); if controller.is_pending() { - println!("Timer tick {}...", super::timer::get_cycle()); super::timer::set_next(); - // ::trap::timer(); + ::trap::timer(); } } diff --git a/kernel/src/arch/aarch64/board/raspi3/timer.rs b/kernel/src/arch/aarch64/board/raspi3/timer.rs index 2e54fb36..4cc0be0d 100644 --- a/kernel/src/arch/aarch64/board/raspi3/timer.rs +++ b/kernel/src/arch/aarch64/board/raspi3/timer.rs @@ -12,6 +12,6 @@ pub fn get_cycle() -> u64 { } pub fn set_next() { - // 1000 ms - timer::tick_in(1000 * 1000); + // 10 ms + timer::tick_in(10 * 1000); } diff --git a/kernel/src/arch/aarch64/boot/boot.S b/kernel/src/arch/aarch64/boot/boot.S index 1740a202..b8a142e9 100644 --- a/kernel/src/arch/aarch64/boot/boot.S +++ b/kernel/src/arch/aarch64/boot/boot.S @@ -18,6 +18,9 @@ setup: # store the desired EL1 stack pointer in x1 adr x1, _start + # use SP_ELx for Exception level ELx + msr SPsel, #1 + # read the current exception level into x0 (ref: C5.2.1) mrs x0, CurrentEL and x0, x0, #0b1100 diff --git a/kernel/src/arch/aarch64/interrupt/context.rs b/kernel/src/arch/aarch64/interrupt/context.rs index 9bc2e778..df2b5b34 100644 --- a/kernel/src/arch/aarch64/interrupt/context.rs +++ b/kernel/src/arch/aarch64/interrupt/context.rs @@ -116,6 +116,8 @@ impl Context { tlbi vmalle1is // invalidate the TLB entry for the entry that changes dsb ish // ensure TLB invalidation is complete isb // synchronize context on this processor + + str xzr, [x1] ret" : : : : "volatile" ); } diff --git a/kernel/src/arch/aarch64/interrupt/mod.rs b/kernel/src/arch/aarch64/interrupt/mod.rs index 2ced2839..140e9b85 100644 --- a/kernel/src/arch/aarch64/interrupt/mod.rs +++ b/kernel/src/arch/aarch64/interrupt/mod.rs @@ -4,6 +4,7 @@ mod handler; mod context; mod syndrome; +use super::cortex_a::regs::*; pub use self::context::*; pub use self::handler::*; @@ -34,8 +35,9 @@ pub unsafe fn disable() { /// return: status(usize) #[inline(always)] pub unsafe fn disable_and_store() -> usize { - // TODO - 0 + let daif = DAIF.get() as usize; + disable(); + daif } /// Use the original status to restore the process @@ -44,5 +46,5 @@ pub unsafe fn disable_and_store() -> usize { /// * flags: original status(usize) #[inline(always)] pub unsafe fn restore(flags: usize) { - // TODO + DAIF.set(flags as u32); } diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index 8c9585d1..35613abd 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -1,6 +1,7 @@ //! Entrance and initialization for aarch64. extern crate atags; +extern crate cortex_a; pub mod io; pub mod paging; @@ -13,72 +14,16 @@ pub mod board; pub use self::board::timer; -/// TODO /// The entry point of kernel #[no_mangle] // don't mangle the name of this function pub extern "C" fn rust_main() -> ! { // Init board to enable serial port. board::init(); - - // First init log mod, so that we can print log info. - // FIXME - ::logging::init(); - - let (start, end) = memory::memory_map().expect("failed to find memory map"); - println!("The value of start is: {:#x?}, end is {:#x?}", start, end); - + ::logging::init(); // FIXME interrupt::init(); memory::init(); timer::init(); - - //let mut v = vec![]; - //for i in 0..1000 { - // v.push(i); - // println!("{:?}", v); - //} - - ::process::init(); - - unsafe { interrupt::enable(); } - - super::fs::show_logo(); - - loop { - print!(">> "); - loop { - let c = io::getchar(); - match c { - '\u{7f}' => { - print!("\u{7f}"); - } - 'b' => unsafe { - println!("brk 233"); - asm!("brk 233"); - }, - 'c' => unsafe { - println!("sys_putc"); - asm!( - "mov x8, #30 - mov x0, #65 - svc 0" - ); - }, - 't' => unsafe { - println!("{}", timer::get_cycle()); - }, - ' '...'\u{7e}' => { - print!("{}", c); - } - '\n' | '\r' => { - print!("\n"); - break; - } - _ => {} - } - } - } - - // ::kmain(); + ::kmain(); } global_asm!(include_str!("boot/boot.S")); diff --git a/kernel/src/fs.rs b/kernel/src/fs.rs index d6822365..6e4e0a3d 100644 --- a/kernel/src/fs.rs +++ b/kernel/src/fs.rs @@ -26,6 +26,62 @@ pub fn show_logo() { println!("{}", LOGO); } +#[inline(always)] +fn sys_call(id: usize, arg0: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> i32 { + let ret: i32; + unsafe { + #[cfg(target_arch = "riscv32")] + asm!("ecall" + : "={x10}" (ret) + : "{x10}" (id), "{x11}" (arg0), "{x12}" (arg1), "{x13}" (arg2), "{x14}" (arg3), "{x15}" (arg4), "{x16}" (arg5) + : "memory" + : "volatile"); + #[cfg(target_arch = "x86_64")] + asm!("int 0x40" + : "={rax}" (ret) + : "{rax}" (id), "{rdi}" (arg0), "{rsi}" (arg1), "{rdx}" (arg2), "{rcx}" (arg3), "{r8}" (arg4), "{r9}" (arg5) + : "memory" + : "intel" "volatile"); + #[cfg(target_arch = "aarch64")] + asm!("svc 0" + : "={x0}" (ret) + : "{x8}" (id), "{x0}" (arg0), "{x1}" (arg1), "{x2}" (arg2), "{x3}" (arg3), "{x4}" (arg4), "{x5}" (arg5) + : "memory" + : "volatile"); + } + ret +} + +pub fn test_shell(prefix: &str) -> ! { + show_logo(); + loop { + print!("{}", prefix); + loop { + let c = super::arch::io::getchar(); + match c { + '\u{7f}' => { + print!("\u{7f}"); + } + 'c' => unsafe { + print!("sys_putc: "); + sys_call(30, 'A' as usize, 0, 0, 0, 0, 0); + }, + 't' => unsafe { + println!("sys_get_time: {}", sys_call(17, 0, 0, 0, 0, 0, 0)); + }, + ' '...'\u{7e}' => { + print!("{}", c); + } + '\n' | '\r' => { + print!("\n"); + break; + } + _ => {} + } + } + } +} + pub fn shell() { show_logo(); diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 8305a771..4474c9c8 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -66,9 +66,14 @@ pub mod arch; pub fn kmain() -> ! { process::init(); + + use process::*; + processor().add(Context::new_kernel(kernel_proc2, 2333)); + processor().add(Context::new_user_test(kernel_proc3)); + unsafe { arch::interrupt::enable(); } - fs::shell(); + // fs::shell(); // thread::test::local_key(); // thread::test::unpack(); @@ -86,3 +91,12 @@ pub fn kmain() -> ! { /// It should be defined in memory mod, but in Rust `global_allocator` must be in root mod. #[global_allocator] static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty(); + + +pub extern "C" fn kernel_proc2(arg: usize) -> ! { + fs::test_shell(&format!("proc2-{}>> ", arg)); +} + +pub extern "C" fn kernel_proc3(arg: usize) -> ! { + fs::test_shell(&format!("proc3-{}$ ", arg)); +} diff --git a/kernel/src/process/context.rs b/kernel/src/process/context.rs index d4ebd96a..f20d2099 100644 --- a/kernel/src/process/context.rs +++ b/kernel/src/process/context.rs @@ -33,6 +33,15 @@ impl Context { } } + pub fn new_user_test(entry: extern fn(usize) -> !) -> Self { + let ms = MemorySet::new(); + let user_stack = ::memory::alloc_stack(); + Context { + arch: unsafe { ArchContext::new_user_thread(entry as usize, user_stack.top - 8, ms.kstack_top(), false, ms.token()) }, + memory_set: ms, + } + } + /// Make a new user thread from ELF data pub fn new_user(data: &[u8]) -> Self { // Parse elf @@ -143,4 +152,4 @@ fn memory_attr_from(elf_flags: Flags) -> MemoryAttr { // TODO: handle readonly if elf_flags.is_execute() { flags = flags.execute(); } flags -} \ No newline at end of file +} diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 09636cdf..5ee8cd25 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -1,39 +1,32 @@ use spin::Once; -use sync::{SpinNoIrqLock, Mutex, MutexGuard, SpinNoIrq}; +use sync::{Mutex, MutexGuard, SpinNoIrq, SpinNoIrqLock}; pub use self::context::Context; pub use ucore_process::processor::{*, Context as _whatever}; pub use ucore_process::scheduler::*; pub use ucore_process::thread::*; -use arch::timer; - mod context; type Processor = Processor_; pub fn init() { - PROCESSOR.call_once(|| + PROCESSOR.call_once(|| { SpinNoIrqLock::new({ let mut processor = Processor::new( unsafe { Context::new_init() }, // NOTE: max_time_slice <= 5 to ensure 'priority' test pass StrideScheduler::new(5), ); - extern fn idle1(arg: usize) -> ! { + extern "C" fn idle(arg: usize) -> ! { loop { - println!("idle 1 {}", timer::get_cycle()); + #[cfg(target_arch = "aarch64")] + unsafe { asm!("wfi" :::: "volatile") } } } - extern fn idle2(arg: usize) -> ! { - loop { - println!("idle 2 {}", timer::get_cycle()); - } - } - processor.add(Context::new_kernel(idle1, 0)); - processor.add(Context::new_kernel(idle2, 0)); + processor.add(Context::new_kernel(idle, 0)); processor }) - ); + }); info!("process init end"); } diff --git a/kernel/src/sync/mutex.rs b/kernel/src/sync/mutex.rs index c8e62ea4..6e4a24c0 100644 --- a/kernel/src/sync/mutex.rs +++ b/kernel/src/sync/mutex.rs @@ -217,6 +217,8 @@ impl MutexSupport for Spin { asm!("pause" :::: "volatile"); #[cfg(target_arch = "riscv32")] asm!("nop" :::: "volatile"); + #[cfg(target_arch = "aarch64")] + asm!("yield" :::: "volatile"); } } fn before_lock() -> Self::GuardData {} @@ -247,6 +249,8 @@ impl MutexSupport for SpinNoIrq { asm!("pause" :::: "volatile"); #[cfg(target_arch = "riscv32")] asm!("nop" :::: "volatile"); + #[cfg(target_arch = "aarch64")] + asm!("yield" :::: "volatile"); } } fn before_lock() -> Self::GuardData { @@ -267,4 +271,4 @@ impl MutexSupport for Condvar { fn after_unlock(&self) { self.notify_one(); } -} \ No newline at end of file +}