From 58223f289bd393f884da6ca8e9bf731318081925 Mon Sep 17 00:00:00 2001 From: Godones <1925466036@qq.com> Date: Mon, 8 Jan 2024 20:43:26 +0800 Subject: [PATCH 1/5] refactor: partition the kernel subsystem We need to divide the kernel into a hierarchical structure to minimize the dependencies of each subsystem. --- .gitignore | 9 +- Cargo.lock | 229 ++++++++++++++++-- Cargo.toml | 6 +- apps/egui/src/main.rs | 3 +- apps/ls/src/main.rs | 2 +- apps/memory-game/src/main.rs | 10 +- apps/printdemo/src/main.rs | 10 +- apps/slint/src/main.rs | 6 +- apps/sysinfo/src/main.rs | 11 +- apps/todo/src/main.rs | 8 +- boot/Cargo.toml | 2 + boot/src/main.rs | 8 +- kernel/Cargo.toml | 13 +- kernel/src/arch/riscv.rs | 45 ---- kernel/src/board/common.rs | 1 - kernel/src/board/cv1811.rs | 49 ---- kernel/src/board/mod.rs | 5 +- kernel/src/board/qemu.rs | 20 +- kernel/src/device/block.rs | 6 +- kernel/src/device/input.rs | 4 +- kernel/src/device/mod.rs | 26 +- kernel/src/device/net.rs | 12 +- kernel/src/device/rtc.rs | 6 +- kernel/src/device/uart.rs | 4 +- kernel/src/driver/block_device.rs | 6 +- kernel/src/driver/gpu.rs | 4 +- kernel/src/driver/input.rs | 2 +- kernel/src/driver/net.rs | 6 +- kernel/src/driver/uart.rs | 2 +- kernel/src/error.rs | 7 - kernel/src/fs/basic.rs | 10 +- kernel/src/fs/control.rs | 6 +- kernel/src/fs/dev/mod.rs | 22 +- kernel/src/fs/ext.rs | 6 +- kernel/src/fs/file.rs | 20 +- kernel/src/fs/link.rs | 10 +- kernel/src/fs/mod.rs | 8 +- kernel/src/fs/poll.rs | 6 +- kernel/src/fs/proc/filesystem.rs | 8 +- kernel/src/fs/proc/interrupt.rs | 2 +- kernel/src/fs/proc/mem.rs | 2 +- kernel/src/fs/proc/mod.rs | 4 +- kernel/src/fs/proc/mounts.rs | 94 +++---- kernel/src/fs/proc/process.rs | 6 +- kernel/src/fs/ram/mod.rs | 3 +- kernel/src/fs/select.rs | 8 +- kernel/src/fs/stdio.rs | 2 +- kernel/src/fs/sys/info.rs | 174 ++++++------- kernel/src/fs/sys/mod.rs | 2 +- kernel/src/interrupt/ext_interrupt.rs | 2 +- kernel/src/interrupt/mod.rs | 4 +- kernel/src/interrupt/record.rs | 4 +- kernel/src/ipc/futex.rs | 4 +- kernel/src/ipc/mod.rs | 8 +- kernel/src/ipc/pipe.rs | 12 +- kernel/src/ipc/shm.rs | 6 +- kernel/src/ipc/signal.rs | 6 +- kernel/src/lib.rs | 12 - kernel/src/memory/elf.rs | 15 ++ kernel/src/memory/frame.rs | 2 +- kernel/src/memory/map.rs | 19 +- kernel/src/memory/mod.rs | 24 +- kernel/src/memory/vmm.rs | 28 ++- kernel/src/net/addr.rs | 6 +- kernel/src/net/mod.rs | 8 +- kernel/src/net/port.rs | 4 +- kernel/src/net/socket.rs | 18 +- kernel/src/net/unix.rs | 4 +- kernel/src/panic.rs | 11 +- kernel/src/print/console.rs | 9 +- kernel/src/task/cpu.rs | 18 +- kernel/src/task/mod.rs | 2 +- kernel/src/task/schedule.rs | 2 +- kernel/src/task/stack.rs | 2 +- kernel/src/task/task.rs | 29 ++- kernel/src/timer/mod.rs | 22 +- kernel/src/trap/context.rs | 20 +- kernel/src/trap/exception.rs | 6 +- kernel/src/trap/mod.rs | 32 ++- rust-toolchain.toml | 2 +- subsystems/arch/Cargo.toml | 13 + subsystems/arch/src/lib.rs | 5 + .../arch => subsystems/arch/src/riscv}/mod.rs | 44 ++-- subsystems/arch/src/riscv/regs.rs | 39 +++ subsystems/config/Cargo.toml | 16 ++ subsystems/config/src/lib.rs | 118 +++++++++ subsystems/constants/Cargo.toml | 9 + subsystems/constants/src/lib.rs | 36 +++ subsystems/device_interface/Cargo.toml | 9 + subsystems/device_interface/src/lib.rs | 48 ++++ subsystems/interrupt/Cargo.toml | 22 ++ subsystems/interrupt/src/ext_interrupt.rs | 17 ++ subsystems/interrupt/src/lib.rs | 58 +++++ subsystems/interrupt/src/record.rs | 33 +++ subsystems/ksync/Cargo.toml | 11 + .../ksync.rs => subsystems/ksync/src/lib.rs | 169 ++++++------- subsystems/mem/Cargo.toml | 34 +++ subsystems/mem/src/frame.rs | 63 +++++ subsystems/mem/src/heap.rs | 71 ++++++ subsystems/mem/src/lib.rs | 45 ++++ subsystems/mem/src/vmm.rs | 18 ++ subsystems/platform/Cargo.toml | 21 ++ subsystems/platform/src/common_riscv/boot.rs | 45 ++++ subsystems/platform/src/common_riscv/mod.rs | 2 + subsystems/platform/src/common_riscv/sbi.rs | 123 ++++++++++ subsystems/platform/src/console.rs | 42 ++++ subsystems/platform/src/hifive_riscv/mod.rs | 37 +++ subsystems/platform/src/lib.rs | 50 ++++ subsystems/platform/src/logger.rs | 41 ++++ subsystems/platform/src/qemu_riscv/mod.rs | 29 +++ .../platform/src/starfive2_riscv/mod.rs | 37 +++ 111 files changed, 1880 insertions(+), 681 deletions(-) delete mode 100644 kernel/src/arch/riscv.rs delete mode 100644 kernel/src/board/cv1811.rs delete mode 100644 kernel/src/error.rs create mode 100644 subsystems/arch/Cargo.toml create mode 100644 subsystems/arch/src/lib.rs rename {kernel/src/arch => subsystems/arch/src/riscv}/mod.rs (53%) create mode 100644 subsystems/arch/src/riscv/regs.rs create mode 100644 subsystems/config/Cargo.toml create mode 100644 subsystems/config/src/lib.rs create mode 100644 subsystems/constants/Cargo.toml create mode 100644 subsystems/constants/src/lib.rs create mode 100644 subsystems/device_interface/Cargo.toml create mode 100644 subsystems/device_interface/src/lib.rs create mode 100644 subsystems/interrupt/Cargo.toml create mode 100644 subsystems/interrupt/src/ext_interrupt.rs create mode 100644 subsystems/interrupt/src/lib.rs create mode 100644 subsystems/interrupt/src/record.rs create mode 100644 subsystems/ksync/Cargo.toml rename kernel/src/ksync.rs => subsystems/ksync/src/lib.rs (83%) create mode 100644 subsystems/mem/Cargo.toml create mode 100644 subsystems/mem/src/frame.rs create mode 100644 subsystems/mem/src/heap.rs create mode 100644 subsystems/mem/src/lib.rs create mode 100644 subsystems/mem/src/vmm.rs create mode 100644 subsystems/platform/Cargo.toml create mode 100644 subsystems/platform/src/common_riscv/boot.rs create mode 100644 subsystems/platform/src/common_riscv/mod.rs create mode 100644 subsystems/platform/src/common_riscv/sbi.rs create mode 100644 subsystems/platform/src/console.rs create mode 100644 subsystems/platform/src/hifive_riscv/mod.rs create mode 100644 subsystems/platform/src/lib.rs create mode 100644 subsystems/platform/src/logger.rs create mode 100644 subsystems/platform/src/qemu_riscv/mod.rs create mode 100644 subsystems/platform/src/starfive2_riscv/mod.rs diff --git a/.gitignore b/.gitignore index c6561507..f2f0c937 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,11 @@ tools/redis-3.2.9 tools/sqlite-amalgamation-3410100 alien-* alien.bin -rust \ No newline at end of file +rust + +tests/testsuits-for-oskernel + +subsystems/devices +subsystems/drivers +subsystems/vfs +subsystems/timer \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 7f256a51..b4f5e9a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,15 @@ dependencies = [ "talc 2.1.0", ] +[[package]] +name = "aarch64-cpu" +version = "9.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac42a04a61c19fc8196dd728022a784baecc5d63d7e256c01ad1b3fbfab26287" +dependencies = [ + "tock-registers", +] + [[package]] name = "adler" version = "1.0.2" @@ -64,6 +73,14 @@ dependencies = [ "nom 4.2.3", ] +[[package]] +name = "arch" +version = "0.1.0" +dependencies = [ + "config", + "riscv", +] + [[package]] name = "arrayref" version = "0.3.7" @@ -94,15 +111,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "atomic-polyfill" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" -dependencies = [ - "critical-section", -] - [[package]] name = "atomic-polyfill" version = "1.0.3" @@ -146,7 +154,7 @@ checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" name = "basemachine" version = "0.1.0" dependencies = [ - "fdt", + "fdt 0.1.5", ] [[package]] @@ -206,6 +214,7 @@ dependencies = [ name = "boot" version = "0.1.0" dependencies = [ + "arch", "basemachine", "cfg-if", "kernel", @@ -379,6 +388,10 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "config" +version = "0.1.0" + [[package]] name = "const-field-offset" version = "0.1.3" @@ -400,6 +413,13 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "constants" +version = "0.1.0" +dependencies = [ + "pconst", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -638,6 +658,32 @@ dependencies = [ "vfscore", ] +[[package]] +name = "device_interface" +version = "0.1.0" +dependencies = [ + "constants", +] + +[[package]] +name = "devices" +version = "0.1.0" +dependencies = [ + "config", + "constants", + "device_interface", + "drivers", + "fdt 0.2.0-alpha1", + "ksync", + "log", + "netcore", + "platform", + "smoltcp", + "spin", + "vfscore", + "virtio-drivers 0.5.0 (git+https://github.com/rcore-os/virtio-drivers?rev=de1c3b1)", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -668,6 +714,27 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "drivers" +version = "0.1.0" +dependencies = [ + "config", + "constants", + "device_interface", + "ksync", + "log", + "loopback", + "lru", + "mem", + "netcore", + "rtc", + "timer", + "uart16550", + "uart8250", + "virtio-drivers 0.5.0 (git+https://github.com/rcore-os/virtio-drivers?rev=de1c3b1)", + "virtio-net", +] + [[package]] name = "drm" version = "0.9.0" @@ -856,6 +923,11 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67" +[[package]] +name = "fdt" +version = "0.2.0-alpha1" +source = "git+https://github.com/repnop/fdt#6fc87b53da0b46166f7bc5029982568e344cc338" + [[package]] name = "field-offset" version = "0.3.6" @@ -1111,11 +1183,11 @@ dependencies = [ [[package]] name = "heapless" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" dependencies = [ - "atomic-polyfill 0.1.11", + "atomic-polyfill", "hash32 0.2.1", "rustc_version", "spin", @@ -1354,6 +1426,18 @@ dependencies = [ "num-traits", ] +[[package]] +name = "interrupt" +version = "0.1.0" +dependencies = [ + "arch", + "config", + "device_interface", + "ksync", + "plic", + "spin", +] + [[package]] name = "inventory" version = "0.3.12" @@ -1416,25 +1500,26 @@ dependencies = [ name = "kernel" version = "0.1.0" dependencies = [ + "arch", "basemachine", "bit_field", "bitflags 1.3.2", "buddy_system_allocator", "cfg-if", + "constants", "devfs", "downcast-rs", "dynfs", "fat-vfs", - "fdt", + "fdt 0.1.5", "gmanager", - "kernel-sync", + "ksync", "log", "loopback", "lru", "netcore", "page-table", "pager", - "pconst", "plic", "preprint", "ramfs", @@ -1465,6 +1550,15 @@ dependencies = [ "lock_api", ] +[[package]] +name = "ksync" +version = "0.1.0" +dependencies = [ + "arch", + "config", + "kernel-sync", +] + [[package]] name = "kurbo" version = "0.9.5" @@ -1639,6 +1733,25 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" +[[package]] +name = "mem" +version = "0.1.0" +dependencies = [ + "arch", + "buddy_system_allocator", + "config", + "ksync", + "log", + "memory_addr", + "page-table", + "page_table", + "pager", + "platform", + "rslab", + "spin", + "talc 1.0.0", +] + [[package]] name = "memchr" version = "2.3.4" @@ -1703,6 +1816,11 @@ dependencies = [ "virt2slint", ] +[[package]] +name = "memory_addr" +version = "0.1.0" +source = "git+https://github.com/rcore-os/arceos?rev=7eeebc5#7eeebc5581f3d1d6e8b03c6177c6cb34543ae50f" + [[package]] name = "micromath" version = "1.1.1" @@ -1983,7 +2101,7 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" dependencies = [ - "atomic-polyfill 1.0.3", + "atomic-polyfill", "critical-section", ] @@ -2012,6 +2130,27 @@ dependencies = [ "log", ] +[[package]] +name = "page_table" +version = "0.1.0" +source = "git+https://github.com/rcore-os/arceos?rev=7eeebc5#7eeebc5581f3d1d6e8b03c6177c6cb34543ae50f" +dependencies = [ + "log", + "memory_addr", + "page_table_entry", +] + +[[package]] +name = "page_table_entry" +version = "0.1.0" +source = "git+https://github.com/rcore-os/arceos?rev=7eeebc5#7eeebc5581f3d1d6e8b03c6177c6cb34543ae50f" +dependencies = [ + "aarch64-cpu", + "bitflags 2.4.0", + "memory_addr", + "x86_64", +] + [[package]] name = "pager" version = "0.1.0" @@ -2094,6 +2233,16 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "platform" +version = "0.1.0" +dependencies = [ + "arch", + "config", + "ksync", + "log", +] + [[package]] name = "plic" version = "0.1.0" @@ -2623,7 +2772,7 @@ dependencies = [ "byteorder", "cfg-if", "defmt", - "heapless 0.7.16", + "heapless 0.7.17", "log", "managed", ] @@ -2895,6 +3044,14 @@ dependencies = [ "time-core", ] +[[package]] +name = "timer" +version = "0.1.0" +dependencies = [ + "arch", + "config", +] + [[package]] name = "tiny-skia" version = "0.10.0" @@ -2958,6 +3115,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tock-registers" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" + [[package]] name = "todo" version = "0.1.0" @@ -3222,6 +3385,24 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "vfs" +version = "0.1.0" +dependencies = [ + "arch", + "constants", + "devfs", + "dynfs", + "fat-vfs", + "interrupt", + "ksync", + "log", + "platform", + "ramfs", + "spin", + "vfscore", +] + [[package]] name = "vfscore" version = "0.1.0" @@ -3697,6 +3878,18 @@ dependencies = [ "nix", ] +[[package]] +name = "x86_64" +version = "0.14.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b835097a84e4457323331ec5d6eb23d096066cbfb215d54096dcb4b2e85f500" +dependencies = [ + "bit_field", + "bitflags 2.4.0", + "rustversion", + "volatile", +] + [[package]] name = "xmas-elf" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 46501212..c26eb0ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,11 @@ members = [ "apps/memory-game", "apps/print", "apps/final_test", -] + "subsystems/arch", + "subsystems/config", + "subsystems/ksync", + "subsystems/constants" +, "subsystems/mem", "subsystems/vfs", "subsystems/devices", "subsystems/drivers", "subsystems/interrupt", "subsystems/device_interface", "subsystems/timer"] [profile.release] diff --git a/apps/egui/src/main.rs b/apps/egui/src/main.rs index 43707663..74cba48f 100644 --- a/apps/egui/src/main.rs +++ b/apps/egui/src/main.rs @@ -23,7 +23,7 @@ impl GpuDevice { } } -impl GPUDevice for GpuDevice{ +impl GPUDevice for GpuDevice { fn flush(&self) { flush_frame_buffer(); } @@ -38,7 +38,6 @@ impl GPUDevice for GpuDevice{ } } - #[no_mangle] fn main() { println!("embedded graphics demo"); diff --git a/apps/ls/src/main.rs b/apps/ls/src/main.rs index 2b4b8e4a..1bcf9c86 100644 --- a/apps/ls/src/main.rs +++ b/apps/ls/src/main.rs @@ -20,7 +20,7 @@ fn main(_: usize, argv: Vec) -> isize { } 0 } -const BUF_SIZE:usize = 512; +const BUF_SIZE: usize = 512; fn parse_args(path: &str) { let fd = open(path, OpenFlags::O_RDONLY); assert!(fd >= 0, "open failed"); diff --git a/apps/memory-game/src/main.rs b/apps/memory-game/src/main.rs index 2aaea6a7..31efdf7b 100644 --- a/apps/memory-game/src/main.rs +++ b/apps/memory-game/src/main.rs @@ -13,8 +13,8 @@ use rand::prelude::{SliceRandom, SmallRng}; use rand::SeedableRng; use slint::platform::WindowEvent; use slint::{Model, VecModel}; -use virt2slint::Converter; use slint_helper::{MyPlatform, SwapBuffer}; +use virt2slint::Converter; use Mstd::io::{keyboard_or_mouse_event, VIRTGPU_XRES, VIRTGPU_YRES}; use Mstd::time::get_time_ms; @@ -86,7 +86,7 @@ fn main() { loop { // Let Slint run the timer hooks and update animations. slint::platform::update_timers_and_animations(); - let events = checkout_event(&mut converter,&mut x, &mut y); + let events = checkout_event(&mut converter, &mut x, &mut y); events.iter().for_each(|event| { window.dispatch_event(event.clone()); }); @@ -99,7 +99,7 @@ fn main() { }); } } -fn checkout_event(converter: &mut Converter,x: &mut isize, y: &mut isize) -> Vec { +fn checkout_event(converter: &mut Converter, x: &mut isize, y: &mut isize) -> Vec { let mut events = [0; 100]; let event_num = keyboard_or_mouse_event(&mut events); let mut res = Vec::new(); @@ -107,9 +107,9 @@ fn checkout_event(converter: &mut Converter,x: &mut isize, y: &mut isize) -> Vec let event = events[i]; // let window_event = input2event(event, x, y); let window_event = converter.convert(event, x, y); - window_event.map(|e|{ + window_event.map(|e| { res.push(e); }); } res -} \ No newline at end of file +} diff --git a/apps/printdemo/src/main.rs b/apps/printdemo/src/main.rs index 4f24bce1..663f7ee6 100644 --- a/apps/printdemo/src/main.rs +++ b/apps/printdemo/src/main.rs @@ -11,8 +11,8 @@ use alloc::vec::Vec; use slint::platform::WindowEvent; use slint::Model; -use virt2slint::Converter; use slint_helper::{MyPlatform, SwapBuffer}; +use virt2slint::Converter; use Mstd::io::{keyboard_or_mouse_event, VIRTGPU_XRES, VIRTGPU_YRES}; #[no_mangle] @@ -142,7 +142,7 @@ fn main() -> ! { loop { // Let Slint run the timer hooks and update animations. slint::platform::update_timers_and_animations(); - let events = checkout_event(&mut converter,&mut x, &mut y); + let events = checkout_event(&mut converter, &mut x, &mut y); events.iter().for_each(|event| { window.dispatch_event(event.clone()); }); @@ -156,7 +156,7 @@ fn main() -> ! { } } -fn checkout_event(converter: &mut Converter,x: &mut isize, y: &mut isize) -> Vec { +fn checkout_event(converter: &mut Converter, x: &mut isize, y: &mut isize) -> Vec { let mut events = [0; 100]; let event_num = keyboard_or_mouse_event(&mut events); let mut res = Vec::new(); @@ -164,9 +164,9 @@ fn checkout_event(converter: &mut Converter,x: &mut isize, y: &mut isize) -> Vec let event = events[i]; // let window_event = input2event(event, x, y); let window_event = converter.convert(event, x, y); - window_event.map(|e|{ + window_event.map(|e| { res.push(e); }); } res -} \ No newline at end of file +} diff --git a/apps/slint/src/main.rs b/apps/slint/src/main.rs index 0312d923..10f0d3e7 100644 --- a/apps/slint/src/main.rs +++ b/apps/slint/src/main.rs @@ -41,7 +41,7 @@ fn main() { loop { // Let Slint run the timer hooks and update animations. slint::platform::update_timers_and_animations(); - let events = checkout_event(&mut converter,&mut x, &mut y); + let events = checkout_event(&mut converter, &mut x, &mut y); events.iter().for_each(|event| { window.dispatch_event(event.clone()); }); @@ -55,7 +55,7 @@ fn main() { } } -fn checkout_event(converter: &mut Converter,x: &mut isize, y: &mut isize) -> Vec { +fn checkout_event(converter: &mut Converter, x: &mut isize, y: &mut isize) -> Vec { let mut events = [0; 100]; let event_num = keyboard_or_mouse_event(&mut events); let mut res = Vec::new(); @@ -63,7 +63,7 @@ fn checkout_event(converter: &mut Converter,x: &mut isize, y: &mut isize) -> Vec let event = events[i]; // let window_event = input2event(event, x, y); let window_event = converter.convert(event, x, y); - window_event.map(|e|{ + window_event.map(|e| { res.push(e); }); } diff --git a/apps/sysinfo/src/main.rs b/apps/sysinfo/src/main.rs index 00c2e9b3..f1b92563 100644 --- a/apps/sysinfo/src/main.rs +++ b/apps/sysinfo/src/main.rs @@ -11,8 +11,8 @@ use alloc::vec::Vec; use slint::platform::WindowEvent; use slint::SharedString; -use virt2slint::Converter; use slint_helper::{MyPlatform, SwapBuffer}; +use virt2slint::Converter; use Mstd::io::{keyboard_or_mouse_event, VIRTGPU_XRES, VIRTGPU_YRES}; slint::include_modules!(); @@ -62,7 +62,7 @@ fn main() { loop { // Let Slint run the timer hooks and update animations. slint::platform::update_timers_and_animations(); - let events = checkout_event(&mut converter,&mut x, &mut y); + let events = checkout_event(&mut converter, &mut x, &mut y); events.iter().for_each(|event| { window.dispatch_event(event.clone()); }); @@ -76,8 +76,7 @@ fn main() { } } - -fn checkout_event(converter: &mut Converter,x: &mut isize, y: &mut isize) -> Vec { +fn checkout_event(converter: &mut Converter, x: &mut isize, y: &mut isize) -> Vec { let mut events = [0; 100]; let event_num = keyboard_or_mouse_event(&mut events); let mut res = Vec::new(); @@ -85,9 +84,9 @@ fn checkout_event(converter: &mut Converter,x: &mut isize, y: &mut isize) -> Vec let event = events[i]; // let window_event = input2event(event, x, y); let window_event = converter.convert(event, x, y); - window_event.map(|e|{ + window_event.map(|e| { res.push(e); }); } res -} \ No newline at end of file +} diff --git a/apps/todo/src/main.rs b/apps/todo/src/main.rs index 31722e53..2cf3e9b6 100644 --- a/apps/todo/src/main.rs +++ b/apps/todo/src/main.rs @@ -12,8 +12,8 @@ use core::default::Default; use core::iter::Iterator; use slint::platform::WindowEvent; use slint::{FilterModel, Model, SortModel}; -use virt2slint::Converter; use slint_helper::{MyPlatform, SwapBuffer}; +use virt2slint::Converter; use Mstd::io::{keyboard_or_mouse_event, VIRTGPU_XRES, VIRTGPU_YRES}; slint::include_modules!(); @@ -147,7 +147,7 @@ fn main() { loop { // Let Slint run the timer hooks and update animations. slint::platform::update_timers_and_animations(); - let events = checkout_event(&mut converter,&mut x, &mut y); + let events = checkout_event(&mut converter, &mut x, &mut y); events.iter().for_each(|event| { window.dispatch_event(event.clone()); }); @@ -161,7 +161,7 @@ fn main() { } } -fn checkout_event(converter: &mut Converter,x: &mut isize, y: &mut isize) -> Vec { +fn checkout_event(converter: &mut Converter, x: &mut isize, y: &mut isize) -> Vec { let mut events = [0; 100]; let event_num = keyboard_or_mouse_event(&mut events); let mut res = Vec::new(); @@ -169,7 +169,7 @@ fn checkout_event(converter: &mut Converter,x: &mut isize, y: &mut isize) -> Vec let event = events[i]; // let window_event = input2event(event, x, y); let window_event = converter.convert(event, x, y); - window_event.map(|e|{ + window_event.map(|e| { res.push(e); }); } diff --git a/boot/Cargo.toml b/boot/Cargo.toml index 410ca4e2..9781b1b3 100644 --- a/boot/Cargo.toml +++ b/boot/Cargo.toml @@ -13,6 +13,8 @@ basemachine = { path = "../dep/basemachine" } kernel = { version = "0.1.0", path = "../kernel" } +arch = { path = "../subsystems/arch" } + [features] default = [] vf2 = ["kernel/vf2"] diff --git a/boot/src/main.rs b/boot/src/main.rs index 5c75d044..dfe8f47a 100644 --- a/boot/src/main.rs +++ b/boot/src/main.rs @@ -25,8 +25,8 @@ use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use cfg_if::cfg_if; use kernel::init_init_array; +use arch::hart_id; use basemachine::machine_info_from_dtb; -use kernel::arch::hart_id; #[cfg(not(feature = "qemu"))] use kernel::board; #[cfg(any( @@ -43,7 +43,7 @@ use kernel::interrupt::init_plic; use kernel::memory::{init_memory_system, kernel_info}; use kernel::print::init_print; use kernel::sbi::hart_start; -use kernel::{config, init_machine_info, println, task, thread_local_init, timer, trap}; +use kernel::{config, init_machine_info, println, task, timer, trap}; mod entry; @@ -92,7 +92,7 @@ pub fn main(_: usize, _: usize) -> ! { init_machine_info(machine_info.clone()); kernel_info(machine_info.memory.end); init_memory_system(machine_info.memory.end, true); - thread_local_init(); + arch::allow_access_user_memory(); // init device tree #[cfg(feature = "qemu")] init_dtb(Some(device_tree_addr)); @@ -114,7 +114,7 @@ pub fn main(_: usize, _: usize) -> ! { while !STARTED.load(Ordering::Relaxed) { spin_loop(); } - thread_local_init(); + arch::allow_access_user_memory(); println!("hart {:#x} start", hart_id()); init_memory_system(0, false); trap::init_trap_subsystem(); diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index a4e8a836..5ef36955 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -7,7 +7,7 @@ authors = ["chen linfeng"] [dependencies] log = "0.4.14" spin = "0.9.2" -riscv = "0.10.0" +riscv = "0.10" bit_field = "0.10.1" xmas-elf = "0.9.0" bitflags = "1.3.2" @@ -27,10 +27,6 @@ rslab = { version = "0.2.1", optional = true } syscall-table = { git = "https://github.com/os-module/syscall-table.git" } plic = { git = "https://github.com/os-module/plic" } pager = { git = "https://github.com/os-module/pager", default-features = false, optional = true } -kernel-sync = { git = "https://github.com/os-module/kernel-sync.git"} -pconst = { git = "https://github.com/os-module/pconst.git", features = [ - "trick", -] } gmanager = { path = "../dep/gmanager" } basemachine = { path = "../dep/basemachine" } uart16550 = { version = "0.0.1", optional = true } @@ -48,10 +44,17 @@ devfs = { git = "https://github.com/os-module/rvfs.git" } dynfs = { git = "https://github.com/os-module/rvfs.git" } ramfs = { git = "https://github.com/os-module/rvfs.git" } fat-vfs = { git = "https://github.com/os-module/rvfs.git" } + + loopback = {git = "https://github.com/os-module/simple-net",optional = true} virtio-net = {git = "https://github.com/os-module/simple-net"} netcore = {git = "https://github.com/os-module/simple-net"} +arch = { path = "../subsystems/arch"} +ksync = {path = "../subsystems/ksync"} +constants = {path = "../subsystems/constants" } + + [dependencies.smoltcp] git = "https://github.com/rcore-os/smoltcp.git" rev = "2ade274" diff --git a/kernel/src/arch/riscv.rs b/kernel/src/arch/riscv.rs deleted file mode 100644 index eee8ab02..00000000 --- a/kernel/src/arch/riscv.rs +++ /dev/null @@ -1,45 +0,0 @@ -pub use riscv::*; - -pub mod sstatus { - use core::arch::asm; - - use bit_field::BitField; - pub use riscv::register::sstatus::*; - - #[derive(Copy, Clone, Debug, Default)] - pub struct Sstatus(pub usize); - - impl Sstatus { - pub fn set_value(&mut self, val: usize) { - self.0 = val; - } - pub fn set_spp(&mut self, spp: SPP) { - self.0.set_bit(8, spp as usize != 0); - } - pub fn spp(&self) -> SPP { - let v = self.0.get_bit(8); - if v { - SPP::Supervisor - } else { - SPP::User - } - } - pub fn set_spie(&mut self) { - self.0.set_bit(5, true); - } - pub fn sie(&self) -> bool { - self.0.get_bit(1) - } - pub fn set_sie(&mut self, value: bool) { - self.0.set_bit(1, value); - } - } - - pub fn read() -> Sstatus { - let val: usize; - unsafe { - asm!("csrr {},sstatus", out(reg)val); - } - Sstatus(val) - } -} diff --git a/kernel/src/board/common.rs b/kernel/src/board/common.rs index 9b26c8d6..59dd7e55 100644 --- a/kernel/src/board/common.rs +++ b/kernel/src/board/common.rs @@ -1,7 +1,6 @@ use fdt::node::FdtNode; use fdt::Fdt; -#[allow(unused)] pub fn get_device_info(fdt: &Fdt, device_name: &str) -> Option<(usize, usize)> { let res = fdt .all_nodes() diff --git a/kernel/src/board/cv1811.rs b/kernel/src/board/cv1811.rs deleted file mode 100644 index 664416d8..00000000 --- a/kernel/src/board/cv1811.rs +++ /dev/null @@ -1,49 +0,0 @@ -use fdt::Fdt; -use spin::Once; - -use crate::board::common::get_device_info; - -#[repr(align(4))] -struct _Wrapper(T); - -pub const FDT: &[u8] = &_Wrapper(*include_bytes!("../../../tools/cv1811h.dtb")).0; - -pub static DTB: Once = Once::new(); - -pub fn init_dtb(dtb: Option) { - let fdt = if dtb.is_some() { - unsafe { Fdt::from_ptr(dtb as *const u8).unwrap() } - } else { - unsafe { Fdt::from_ptr(FDT.as_ptr()).unwrap() } - }; - DTB.call_once(|| fdt); -} - -/// Get the base address and irq number of the uart device from the device tree. -pub fn probe_devices_from_dtb() { - if let Some(rtc) = probe_rtc() { - BOARD_DEVICES.lock().insert(DeviceType::Rtc, rtc); - } - if let Some(uart) = probe_uart() { - BOARD_DEVICES.lock().insert(DeviceType::Uart, uart); - } -} - -/// Get the base address and irq number of the uart device from the device tree. -pub fn probe_rtc() -> Option { - let fdt = DTB.get().unwrap(); - let res = get_device_info(fdt, "rtc"); - if res.is_none() { - return None; - } - let (base_addr, irq) = res.unwrap(); - Some(DeviceInfo::new(base_addr, irq)) -} - -pub fn probe_uart() -> Option { - let fdt = DTB.get().unwrap(); - if let Some((base_addr, irq)) = get_device_info(fdt, "serial0") { - return Some(DeviceInfo::new(base_addr, irq)); - } - None -} diff --git a/kernel/src/board/mod.rs b/kernel/src/board/mod.rs index 562684f8..399a874b 100644 --- a/kernel/src/board/mod.rs +++ b/kernel/src/board/mod.rs @@ -2,7 +2,7 @@ use alloc::collections::BTreeMap; use cfg_if::cfg_if; -use crate::ksync::Mutex; +use ksync::Mutex; use crate::device::{DeviceInfo, DeviceType}; @@ -63,9 +63,6 @@ cfg_if! { if #[cfg(feature="qemu")]{ mod qemu; pub use qemu::*; - }else if #[cfg(feature="cv1811")]{ - mod cv1811; - pub use cv1811::*; }else if #[cfg(feature="hifive")]{ mod unmatched; pub use unmatched::*; diff --git a/kernel/src/board/qemu.rs b/kernel/src/board/qemu.rs index 3f31ec60..0d21b187 100644 --- a/kernel/src/board/qemu.rs +++ b/kernel/src/board/qemu.rs @@ -38,11 +38,7 @@ pub fn probe_devices_from_dtb() { pub fn probe_rtc() -> Option { let fdt = DTB.get().unwrap(); let res = get_device_info(fdt, "rtc"); - if res.is_none() { - return None; - } - let (base_addr, irq) = res.unwrap(); - Some(DeviceInfo::new(base_addr, irq)) + res.map(|(base_addr, irq)| DeviceInfo::new(base_addr, irq)) } /// Get the base address and irq number of the uart device from the device tree. @@ -100,7 +96,7 @@ fn virtio_probe(node: &FdtNode) -> Option<(DeviceType, DeviceInfo)> { transport.read_device_features(), ); info!("Probe virtio device: {:?}", transport.device_type()); - match transport.device_type() { + return match transport.device_type() { VirtDeviceType::Input => { let device_info = DeviceInfo::new(paddr, irq); let res = if paddr == VIRTIO5 { @@ -110,22 +106,22 @@ fn virtio_probe(node: &FdtNode) -> Option<(DeviceType, DeviceInfo)> { } else { None }; - return res; + res } VirtDeviceType::Block => { let device_info = DeviceInfo::new(paddr, irq); - return Some((DeviceType::Block, device_info)); + Some((DeviceType::Block, device_info)) } VirtDeviceType::GPU => { let device_info = DeviceInfo::new(paddr, irq); - return Some((DeviceType::GPU, device_info)); + Some((DeviceType::GPU, device_info)) } VirtDeviceType::Network => { let device_info = DeviceInfo::new(paddr, irq); - return Some((DeviceType::Network, device_info)); + Some((DeviceType::Network, device_info)) } - _ => return None, - } + _ => None, + }; } } } diff --git a/kernel/src/device/block.rs b/kernel/src/device/block.rs index e52b3c82..d3a99d84 100644 --- a/kernel/src/device/block.rs +++ b/kernel/src/device/block.rs @@ -1,8 +1,8 @@ use alloc::sync::Arc; use crate::driver::GenericBlockDevice; -use crate::error::AlienResult; use crate::fs::dev::DeviceId; +use constants::AlienResult; use spin::Once; use vfscore::error::VfsError; use vfscore::file::VfsFile; @@ -52,10 +52,10 @@ impl VfsFile for BLKDevice { .map_err(|_| VfsError::IoError) } fn poll(&self, _event: VfsPollEvents) -> VfsResult { - todo!() + unimplemented!() } fn ioctl(&self, _cmd: u32, _arg: usize) -> VfsResult { - todo!() + unimplemented!() } fn flush(&self) -> VfsResult<()> { Ok(()) diff --git a/kernel/src/device/input.rs b/kernel/src/device/input.rs index 3da763a0..918097c7 100644 --- a/kernel/src/device/input.rs +++ b/kernel/src/device/input.rs @@ -42,7 +42,7 @@ impl INPUTDevice { impl VfsFile for INPUTDevice { fn read_at(&self, _offset: u64, buf: &mut [u8]) -> VfsResult { - if buf.len() != 8{ + if buf.len() != 8 { return Err(VfsError::Invalid); } let buf = unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u64, 1) }; @@ -85,12 +85,10 @@ impl VfsInode for INPUTDevice { pub static KEYBOARD_INPUT_DEVICE: Once> = Once::new(); pub static MOUSE_INPUT_DEVICE: Once> = Once::new(); - pub fn init_keyboard_input_device(input_device: Arc) { KEYBOARD_INPUT_DEVICE.call_once(|| input_device); } - pub fn init_mouse_input_device(input_device: Arc) { MOUSE_INPUT_DEVICE.call_once(|| input_device); } diff --git a/kernel/src/device/mod.rs b/kernel/src/device/mod.rs index 89738ebd..f165fd55 100644 --- a/kernel/src/device/mod.rs +++ b/kernel/src/device/mod.rs @@ -9,11 +9,11 @@ use alloc::boxed::Box; use alloc::sync::Arc; pub use block::{BLKDevice, BlockDevice, BLOCK_DEVICE}; use core::sync::atomic::Ordering; -use smoltcp::wire::IpAddress; pub use gpu::{GPUDevice, GpuDevice, GPU_DEVICE}; pub use input::{ sys_event_get, INPUTDevice, InputDevice, KEYBOARD_INPUT_DEVICE, MOUSE_INPUT_DEVICE, }; +use smoltcp::wire::IpAddress; mod block; mod gpu; @@ -67,11 +67,11 @@ fn init_rtc() { #[cfg(feature = "qemu")] { use crate::driver::rtc::GoldFishRtc; - use ::rtc::{LowRtcDeviceExt}; + use ::rtc::LowRtcDeviceExt; let rtc = Arc::new(GoldFishRtc::new(base_addr)); let current_time = rtc.read_time_fmt(); rtc::init_rtc(rtc.clone()); - register_device_to_plic(irq, rtc.clone()); + register_device_to_plic(irq, rtc); println!("Init rtc success, current time: {:?}", current_time); } #[cfg(feature = "vf2")] @@ -150,7 +150,6 @@ fn init_fake_disk() { block::init_block_device(device.clone()); } - fn init_gpu() { let res = crate::board::get_gpu_info(); if res.is_none() { @@ -237,15 +236,15 @@ fn init_net() { use crate::device::net::NetNeedFunc; use crate::driver::net::make_virtio_net_device; let virtio_net = make_virtio_net_device(base_addr); - use core::str::FromStr; use crate::config::{QEMU_GATEWAY, QEMU_IP}; + use core::str::FromStr; let device = Box::new(virtio_net); netcore::init_net( device, Arc::new(NetNeedFunc), IpAddress::from_str(QEMU_IP).unwrap(), - IpAddress::from_str(QEMU_GATEWAY).unwrap(), - true + IpAddress::from_str(QEMU_GATEWAY).unwrap(), + true, ); println!("Init net device success"); #[cfg(feature = "net_test")] @@ -261,16 +260,9 @@ fn init_loop_device() { use crate::device::net::NetNeedFunc; use loopback::LoopbackDev; // use default ip and gateway for qemu - let ip = IpAddress::v4(127,0,0,1); - let gate_way = IpAddress::v4(127,0,0,1); + let ip = IpAddress::v4(127, 0, 0, 1); + let gate_way = IpAddress::v4(127, 0, 0, 1); let loopback = Box::new(LoopbackDev::new()); - netcore::init_net( - loopback, - Arc::new(NetNeedFunc), - ip, - gate_way, - false, - ); + netcore::init_net(loopback, Arc::new(NetNeedFunc), ip, gate_way, false); println!("Init net device success"); } - diff --git a/kernel/src/device/net.rs b/kernel/src/device/net.rs index befb6bdc..2d2a6af7 100644 --- a/kernel/src/device/net.rs +++ b/kernel/src/device/net.rs @@ -8,11 +8,11 @@ pub trait NetDevice: DeviceBase {} #[cfg(feature = "net_test")] pub mod nettest { + use crate::net::port::neterror2alien; use alloc::vec::Vec; + use constants::AlienResult; use core::net::{IpAddr, SocketAddr}; use netcore::tcp::TcpSocket; - use crate::error::{AlienResult}; - use crate::net::port::neterror2alien; /// A TCP stream between a local and a remote socket. pub struct TcpStream(TcpSocket); @@ -68,16 +68,12 @@ pub mod nettest { if n == 0 { return Ok(()); } - stream - .write_all(reverse(&buf[..n]).as_slice()).unwrap(); + stream.write_all(reverse(&buf[..n]).as_slice()).unwrap(); } } pub fn accept_loop() { - let local_addr = SocketAddr::new( - IpAddr::V4(LOCAL_IP.parse().unwrap()), - LOCAL_PORT, - ); + let local_addr = SocketAddr::new(IpAddr::V4(LOCAL_IP.parse().unwrap()), LOCAL_PORT); let listener = TcpListener::bind(local_addr).unwrap(); println!("listen on: {}", listener.local_addr().unwrap()); let mut i = 0; diff --git a/kernel/src/device/rtc.rs b/kernel/src/device/rtc.rs index 485be920..44d488b8 100644 --- a/kernel/src/device/rtc.rs +++ b/kernel/src/device/rtc.rs @@ -1,7 +1,7 @@ use alloc::format; use alloc::sync::Arc; +use constants::io::TeletypeCommand; use core::cmp::min; -use pconst::io::TeletypeCommand; use rtc::RtcTime; use crate::fs::dev::DeviceId; @@ -62,7 +62,7 @@ impl VfsFile for RTCDevice { match cmd { TeletypeCommand::RTC_RD_TIME => { let time = self.device.read_time_fmt(); - let c_rtc_time = pconst::io::RtcTime{ + let c_rtc_time = constants::io::RtcTime { sec: time.second as u32, min: time.minute as u32, hour: time.hour as u32, @@ -73,7 +73,7 @@ impl VfsFile for RTCDevice { yday: 0, isdst: 0, }; - task_inner.copy_to_user(&c_rtc_time, arg as *mut pconst::io::RtcTime); + task_inner.copy_to_user(&c_rtc_time, arg as *mut constants::io::RtcTime); } _ => return Err(VfsError::Invalid), } diff --git a/kernel/src/device/uart.rs b/kernel/src/device/uart.rs index 5a8c552d..9b511b1f 100644 --- a/kernel/src/device/uart.rs +++ b/kernel/src/device/uart.rs @@ -1,6 +1,6 @@ use crate::fs::dev::DeviceId; use alloc::sync::Arc; -use pconst::io::{LocalModes, TeletypeCommand, Termios, WinSize}; +use constants::io::{LocalModes, TeletypeCommand, Termios, WinSize}; use spin::Once; use vfscore::error::VfsError; use vfscore::file::VfsFile; @@ -10,8 +10,8 @@ use vfscore::utils::{VfsFileStat, VfsNodeType, VfsPollEvents}; use vfscore::VfsResult; use crate::interrupt::DeviceBase; -use crate::ksync::Mutex; use crate::task::current_task; +use ksync::Mutex; pub trait UartDevice: Send + Sync + DeviceBase { fn put(&self, c: u8); diff --git a/kernel/src/driver/block_device.rs b/kernel/src/driver/block_device.rs index 8c525dc7..0c0c6f0c 100644 --- a/kernel/src/driver/block_device.rs +++ b/kernel/src/driver/block_device.rs @@ -1,17 +1,17 @@ use alloc::boxed::Box; use alloc::vec::Vec; +use constants::LinuxErrno; use core::cmp::min; use core::fmt::{Debug, Formatter}; use core::num::NonZeroUsize; use core::ptr::NonNull; -use pconst::LinuxErrno; use lru::LruCache; use virtio_drivers::device::blk::VirtIOBlk; use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; -use crate::error::AlienResult; -use crate::ksync::Mutex; +use constants::AlienResult; +use ksync::Mutex; use crate::config::BLOCK_CACHE_FRAMES; use crate::config::FRAME_SIZE; diff --git a/kernel/src/driver/gpu.rs b/kernel/src/driver/gpu.rs index b678d98d..61dbb485 100644 --- a/kernel/src/driver/gpu.rs +++ b/kernel/src/driver/gpu.rs @@ -2,7 +2,7 @@ use core::ptr::NonNull; use virtio_drivers::device::gpu::VirtIOGpu; use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; -use crate::ksync::Mutex; +use ksync::Mutex; use crate::device::GpuDevice; use crate::driver::hal::HalImpl; @@ -35,7 +35,7 @@ impl VirtIOGpuWrapper { Self { gpu: Mutex::new(gpu), fb, - resolution + resolution, } } } diff --git a/kernel/src/driver/input.rs b/kernel/src/driver/input.rs index a556a896..5f1d8d15 100644 --- a/kernel/src/driver/input.rs +++ b/kernel/src/driver/input.rs @@ -5,7 +5,7 @@ use core::ptr::NonNull; use virtio_drivers::device::input::VirtIOInput; use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; -use crate::ksync::Mutex; +use ksync::Mutex; use smpscheduler::FifoTask; use crate::device::InputDevice; diff --git a/kernel/src/driver/net.rs b/kernel/src/driver/net.rs index e10c93bd..a776a543 100644 --- a/kernel/src/driver/net.rs +++ b/kernel/src/driver/net.rs @@ -8,9 +8,11 @@ use crate::driver::hal::HalImpl; pub const NET_BUFFER_LEN: usize = 4096; pub const NET_QUEUE_SIZE: usize = 128; -pub fn make_virtio_net_device(addr:usize) -> VirtIONetDeviceWrapper { +pub fn make_virtio_net_device( + addr: usize, +) -> VirtIONetDeviceWrapper { let header = NonNull::new(addr as *mut VirtIOHeader).unwrap(); let transport = unsafe { MmioTransport::new(header) }.unwrap(); let device = VirtIONetDeviceWrapper::new(transport, NET_BUFFER_LEN); device -} \ No newline at end of file +} diff --git a/kernel/src/driver/uart.rs b/kernel/src/driver/uart.rs index 61971ef0..a1e7cc38 100644 --- a/kernel/src/driver/uart.rs +++ b/kernel/src/driver/uart.rs @@ -1,7 +1,7 @@ -use crate::ksync::Mutex; use alloc::boxed::Box; use alloc::collections::VecDeque; use alloc::sync::Arc; +use ksync::Mutex; use smpscheduler::FifoTask; #[cfg(not(feature = "vf2"))] diff --git a/kernel/src/error.rs b/kernel/src/error.rs deleted file mode 100644 index b656d979..00000000 --- a/kernel/src/error.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! alien os中error定义 -//! -//! 后续需要将其与linux的error等价转换 -use pconst::LinuxErrno; - -pub type AlienError = LinuxErrno; -pub type AlienResult = Result; diff --git a/kernel/src/fs/basic.rs b/kernel/src/fs/basic.rs index 417e53a3..9d88776d 100644 --- a/kernel/src/fs/basic.rs +++ b/kernel/src/fs/basic.rs @@ -1,18 +1,18 @@ use super::im2vim; use crate::config::AT_FDCWD; -use crate::error::AlienResult; use crate::fs::file::KernelFile; use crate::fs::{syscontext_for_vfs, user_path_at, FS, SYSTEM_ROOT_FS}; use crate::task::current_task; use alloc::sync::Arc; use alloc::vec; +use constants::io::{ + FileStat, FsStat, InodeMode, IoVec, MountFlags, OpenFlags, Renameat2Flags, SeekFrom, StatFlags, +}; +use constants::AlienResult; +use constants::LinuxErrno; use core::cmp::min; use core::ops::Index; use gmanager::ManagerError; -use pconst::io::{ - FileStat, FsStat, InodeMode, IoVec, MountFlags, OpenFlags, Renameat2Flags, SeekFrom, StatFlags, -}; -use pconst::LinuxErrno; use syscall_table::syscall_func; use vfscore::path::VfsPath; use vfscore::utils::{VfsFileStat, VfsFsStat, VfsNodeType, VfsRenameFlag}; diff --git a/kernel/src/fs/control.rs b/kernel/src/fs/control.rs index db28c4db..337a55fb 100644 --- a/kernel/src/fs/control.rs +++ b/kernel/src/fs/control.rs @@ -1,10 +1,10 @@ use crate::config::AT_FDCWD; -use crate::error::AlienResult; use crate::fs::user_path_at; use crate::task::current_task; use crate::timer::TimeSpec; -use pconst::io::{FaccessatFlags, FaccessatMode, Fcntl64Cmd, OpenFlags, TeletypeCommand}; -use pconst::LinuxErrno; +use constants::io::{FaccessatFlags, FaccessatMode, Fcntl64Cmd, OpenFlags, TeletypeCommand}; +use constants::AlienResult; +use constants::LinuxErrno; use syscall_table::syscall_func; use vfscore::utils::*; diff --git a/kernel/src/fs/dev/mod.rs b/kernel/src/fs/dev/mod.rs index 4a3b88af..2da04bea 100644 --- a/kernel/src/fs/dev/mod.rs +++ b/kernel/src/fs/dev/mod.rs @@ -4,10 +4,10 @@ use crate::device::{ }; use crate::fs::dev::null::NullDevice; use crate::fs::dev::random::RandomDevice; -use crate::ksync::Mutex; use alloc::collections::BTreeMap; use alloc::sync::Arc; use devfs::DevKernelProvider; +use ksync::Mutex; use spin::Lazy; use vfscore::dentry::VfsDentry; use vfscore::fstype::VfsFsType; @@ -186,7 +186,10 @@ pub fn init_devfs(devfs: Arc) -> Arc { fn scan_system_devices(root: Arc) { BLOCK_DEVICE.get().map(|blk| { - let block_device = Arc::new(BLKDevice::new(alloc_device_id(VfsNodeType::BlockDevice), blk.clone())); + let block_device = Arc::new(BLKDevice::new( + alloc_device_id(VfsNodeType::BlockDevice), + blk.clone(), + )); root.create( "sda", VfsNodeType::BlockDevice, @@ -197,7 +200,10 @@ fn scan_system_devices(root: Arc) { register_device(block_device); }); GPU_DEVICE.get().map(|gpu| { - let gpu_device = Arc::new(GPUDevice::new(alloc_device_id(VfsNodeType::CharDevice), gpu.clone())); + let gpu_device = Arc::new(GPUDevice::new( + alloc_device_id(VfsNodeType::CharDevice), + gpu.clone(), + )); root.create( "gpu", VfsNodeType::BlockDevice, @@ -238,7 +244,10 @@ fn scan_system_devices(root: Arc) { register_device(input_device); }); RTC_DEVICE.get().map(|rtc| { - let rtc_device = Arc::new(RTCDevice::new(alloc_device_id(VfsNodeType::CharDevice), rtc.clone())); + let rtc_device = Arc::new(RTCDevice::new( + alloc_device_id(VfsNodeType::CharDevice), + rtc.clone(), + )); root.create( "rtc", VfsNodeType::BlockDevice, @@ -249,7 +258,10 @@ fn scan_system_devices(root: Arc) { register_device(rtc_device); }); UART_DEVICE.get().map(|uart| { - let uart_device = Arc::new(UARTDevice::new(alloc_device_id(VfsNodeType::CharDevice), uart.clone())); + let uart_device = Arc::new(UARTDevice::new( + alloc_device_id(VfsNodeType::CharDevice), + uart.clone(), + )); root.create( "tty", VfsNodeType::BlockDevice, diff --git a/kernel/src/fs/ext.rs b/kernel/src/fs/ext.rs index a3ba61e9..a1219ce8 100644 --- a/kernel/src/fs/ext.rs +++ b/kernel/src/fs/ext.rs @@ -1,9 +1,9 @@ +use constants::LinuxErrno; use core::cmp::min; -use pconst::LinuxErrno; use vfscore::path::VfsPath; -use crate::{config::AT_FDCWD, error::AlienResult, fs::user_path_at, task::current_task}; - +use crate::{config::AT_FDCWD, fs::user_path_at, task::current_task}; +use constants::AlienResult; /// 一个系统调用,用于设置文件的 扩展属性(xattrs, Extended Attributes)。 /// /// 扩展属性(xattrs)提供了一个机制用来将一个(键, 值)对永久地关联到文件,让现有的文件系统得以支持在原始设计中未提供的功能。扩展属性是文件系统不可知论者, diff --git a/kernel/src/fs/file.rs b/kernel/src/fs/file.rs index 340ac3e7..f6f01bbe 100644 --- a/kernel/src/fs/file.rs +++ b/kernel/src/fs/file.rs @@ -1,16 +1,16 @@ +use constants::io::DirentType; pub use kernel_file::{File, KernelFile}; -use pconst::io::DirentType; use vfscore::utils::VfsNodeType; mod kernel_file { use super::vfsnodetype2dirent64; - use crate::error::AlienResult; - use crate::ksync::Mutex; use alloc::sync::Arc; + use constants::io::{Dirent64, OpenFlags, PollEvents, SeekFrom}; + use constants::AlienResult; + use constants::LinuxErrno; use core::fmt::{Debug, Formatter}; use downcast_rs::{impl_downcast, DowncastSync}; - use pconst::io::{Dirent64, OpenFlags, PollEvents, SeekFrom}; - use pconst::LinuxErrno; + use ksync::Mutex; use vfscore::dentry::VfsDentry; use vfscore::error::VfsError; use vfscore::inode::VfsInode; @@ -117,7 +117,7 @@ mod kernel_file { return Ok(0); } let open_flag = self.open_flag.lock(); - if !open_flag.contains(OpenFlags::O_RDONLY)&& !open_flag.contains(OpenFlags::O_RDWR) { + if !open_flag.contains(OpenFlags::O_RDONLY) && !open_flag.contains(OpenFlags::O_RDWR) { return Err(LinuxErrno::EPERM); } drop(open_flag); @@ -151,7 +151,7 @@ mod kernel_file { fn fsync(&self) -> AlienResult<()> { let open_flag = self.open_flag.lock(); - if !open_flag.contains(OpenFlags::O_WRONLY)&& !open_flag.contains(OpenFlags::O_RDWR) { + if !open_flag.contains(OpenFlags::O_WRONLY) && !open_flag.contains(OpenFlags::O_RDWR) { return Err(LinuxErrno::EPERM); } let inode = self.dentry.inode()?; @@ -213,7 +213,7 @@ mod kernel_file { if count + dirent64.len() <= buf.len() { let dirent_ptr = unsafe { &mut *(ptr as *mut Dirent64) }; *dirent_ptr = dirent64; - let name_ptr = dirent_ptr.name.as_mut_ptr(); + let name_ptr = dirent_ptr.name.as_mut_ptr(); unsafe { let mut name = d.name.clone(); name.push('\0'); @@ -236,9 +236,7 @@ mod kernel_file { } fn truncate(&self, len: u64) -> AlienResult<()> { let open_flag = self.open_flag.lock(); - if !open_flag - .contains(OpenFlags::O_WRONLY) & !open_flag.contains(OpenFlags::O_RDWR) - { + if !open_flag.contains(OpenFlags::O_WRONLY) & !open_flag.contains(OpenFlags::O_RDWR) { return Err(LinuxErrno::EINVAL); } let dt = self.dentry(); diff --git a/kernel/src/fs/link.rs b/kernel/src/fs/link.rs index 882c72bc..0e71bb61 100644 --- a/kernel/src/fs/link.rs +++ b/kernel/src/fs/link.rs @@ -1,9 +1,9 @@ use alloc::vec; -use pconst::io::{LinkFlags, UnlinkatFlags}; +use constants::io::{LinkFlags, UnlinkatFlags}; use syscall_table::syscall_func; -use crate::{error::AlienResult, fs::user_path_at, task::current_task}; - +use crate::{fs::user_path_at, task::current_task}; +use constants::AlienResult; /// 一个系统调用,用于创建相对于一个目录某位置处的一个文件的(硬)链接。 /// /// 当传入的 `old_name` 是一个相对地址时,那么 `old_name` 会被解析成基于文件描述符 `old_fd` @@ -85,9 +85,9 @@ pub fn sys_unlinkat(fd: isize, path: *const u8, flag: usize) -> AlienResult String { let mut res = String::new(); let fs = FS.lock(); - for (_,fs) in fs.iter() { + for (_, fs) in fs.iter() { let flag = fs.fs_flag(); if !flag.contains(FileSystemFlags::REQUIRES_DEV) { res.push_str("nodev ") @@ -36,7 +36,7 @@ impl SystemSupportFS { impl VfsFile for SystemSupportFS { fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { let info = self.serialize(); - let min_len = min(buf.len(), info.as_bytes().len()-offset as usize); + let min_len = min(buf.len(), info.as_bytes().len() - offset as usize); buf[..min_len].copy_from_slice(&info.as_bytes()[..min_len]); Ok(min_len) } diff --git a/kernel/src/fs/proc/interrupt.rs b/kernel/src/fs/proc/interrupt.rs index 5d5ce8dc..83332a7a 100644 --- a/kernel/src/fs/proc/interrupt.rs +++ b/kernel/src/fs/proc/interrupt.rs @@ -13,7 +13,7 @@ pub struct InterruptRecord; impl VfsFile for InterruptRecord { fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { let info = interrupts_info(); - let min_len = min(buf.len(), info.as_bytes().len()-offset as usize); + let min_len = min(buf.len(), info.as_bytes().len() - offset as usize); buf[..min_len].copy_from_slice(&info.as_bytes()[..min_len]); Ok(min_len) } diff --git a/kernel/src/fs/proc/mem.rs b/kernel/src/fs/proc/mem.rs index c66539e4..4a777ee6 100644 --- a/kernel/src/fs/proc/mem.rs +++ b/kernel/src/fs/proc/mem.rs @@ -12,7 +12,7 @@ pub struct MemInfo; impl VfsFile for MemInfo { fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { - let min_len = min(buf.len(), MEMINFO.as_bytes().len()-offset as usize); + let min_len = min(buf.len(), MEMINFO.as_bytes().len() - offset as usize); buf[..min_len].copy_from_slice(&MEMINFO.as_bytes()[..min_len]); Ok(min_len) } diff --git a/kernel/src/fs/proc/mod.rs b/kernel/src/fs/proc/mod.rs index b14c16a9..55b83f28 100644 --- a/kernel/src/fs/proc/mod.rs +++ b/kernel/src/fs/proc/mod.rs @@ -7,10 +7,10 @@ mod process; use crate::fs::proc::filesystem::SystemSupportFS; use crate::fs::proc::interrupt::InterruptRecord; use crate::fs::proc::mounts::MountInfo; -use crate::fs::{CommonFsProviderImpl}; -use crate::ksync::Mutex; +use crate::fs::CommonFsProviderImpl; use alloc::sync::Arc; use dynfs::DynFsDirInode; +use ksync::Mutex; use mem::MemInfo; use vfscore::dentry::VfsDentry; use vfscore::error::VfsError; diff --git a/kernel/src/fs/proc/mounts.rs b/kernel/src/fs/proc/mounts.rs index a266101e..ac0d76fe 100644 --- a/kernel/src/fs/proc/mounts.rs +++ b/kernel/src/fs/proc/mounts.rs @@ -1,47 +1,47 @@ -use alloc::sync::Arc; -use core::cmp::min; -use vfscore::error::VfsError; -use vfscore::file::VfsFile; -use vfscore::inode::{InodeAttr, VfsInode}; -use vfscore::superblock::VfsSuperBlock; -use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; -use vfscore::VfsResult; - -// todo!(dynamic mount info) -const MOUNT_INFO: &str = r" - rootfs / rootfs rw 0 0 - devfs /dev devfs rw 0 0 - fat32 / fat rw 0 0 -"; -pub struct MountInfo; - -impl VfsFile for MountInfo { - fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { - let min_len = min(buf.len(), MOUNT_INFO.as_bytes().len()-offset as usize); - buf[..min_len].copy_from_slice(&MOUNT_INFO.as_bytes()[..min_len]); - Ok(min_len) - } -} - -impl VfsInode for MountInfo { - fn get_super_block(&self) -> VfsResult> { - Err(VfsError::NoSys) - } - fn node_perm(&self) -> VfsNodePerm { - VfsNodePerm::empty() - } - fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { - Ok(()) - } - - fn get_attr(&self) -> VfsResult { - Ok(VfsFileStat { - st_size: MOUNT_INFO.as_bytes().len() as u64, - ..Default::default() - }) - } - - fn inode_type(&self) -> VfsNodeType { - VfsNodeType::File - } -} +use alloc::sync::Arc; +use core::cmp::min; +use vfscore::error::VfsError; +use vfscore::file::VfsFile; +use vfscore::inode::{InodeAttr, VfsInode}; +use vfscore::superblock::VfsSuperBlock; +use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; +use vfscore::VfsResult; + +// todo!(dynamic mount info) +const MOUNT_INFO: &str = r" + rootfs / rootfs rw 0 0 + devfs /dev devfs rw 0 0 + fat32 / fat rw 0 0 +"; +pub struct MountInfo; + +impl VfsFile for MountInfo { + fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { + let min_len = min(buf.len(), MOUNT_INFO.as_bytes().len() - offset as usize); + buf[..min_len].copy_from_slice(&MOUNT_INFO.as_bytes()[..min_len]); + Ok(min_len) + } +} + +impl VfsInode for MountInfo { + fn get_super_block(&self) -> VfsResult> { + Err(VfsError::NoSys) + } + fn node_perm(&self) -> VfsNodePerm { + VfsNodePerm::empty() + } + fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { + Ok(()) + } + + fn get_attr(&self) -> VfsResult { + Ok(VfsFileStat { + st_size: MOUNT_INFO.as_bytes().len() as u64, + ..Default::default() + }) + } + + fn inode_type(&self) -> VfsNodeType { + VfsNodeType::File + } +} diff --git a/kernel/src/fs/proc/process.rs b/kernel/src/fs/proc/process.rs index 43e2033c..36259558 100644 --- a/kernel/src/fs/proc/process.rs +++ b/kernel/src/fs/proc/process.rs @@ -1,8 +1,8 @@ -use crate::error::AlienResult; use crate::task::current_task; use crate::timer::TimeFromFreq; -use pconst::sys::{Rusage, RusageFlag, TimeVal}; -use pconst::LinuxErrno; +use constants::sys::{Rusage, RusageFlag, TimeVal}; +use constants::AlienResult; +use constants::LinuxErrno; /// (待完善)一个系统调用,用于获取对系统资源的使用量信息。获取的信息将保存到`usage`所指向的[`Rusage`]结构中。 /// diff --git a/kernel/src/fs/ram/mod.rs b/kernel/src/fs/ram/mod.rs index b466db95..b1b71834 100644 --- a/kernel/src/fs/ram/mod.rs +++ b/kernel/src/fs/ram/mod.rs @@ -73,7 +73,8 @@ pub fn init_ramfs(ramfs: Arc) -> Arc { .create("tmp", VfsNodeType::Dir, "rwxrwxrwx".into(), None) .unwrap(); - let _bashrc = root.create(".bashrc", VfsNodeType::File, "rwxrwxrwx".into(), None) + let _bashrc = root + .create(".bashrc", VfsNodeType::File, "rwxrwxrwx".into(), None) .unwrap(); println!("ramfs init success"); diff --git a/kernel/src/fs/select.rs b/kernel/src/fs/select.rs index 4aff56a5..bd30ee51 100644 --- a/kernel/src/fs/select.rs +++ b/kernel/src/fs/select.rs @@ -1,13 +1,13 @@ use crate::config::MAX_FD_NUM; -use crate::error::AlienResult; use crate::task::{current_task, do_suspend}; use crate::timer::TimeSpec; use alloc::vec::Vec; use bit_field::BitField; +use constants::io::PollEvents; +use constants::signal::{SignalNumber, SimpleBitSet}; +use constants::AlienResult; +use constants::LinuxErrno; use core::cmp::min; -use pconst::io::PollEvents; -use pconst::signal::{SignalNumber, SimpleBitSet}; -use pconst::LinuxErrno; use syscall_table::syscall_func; /// 一个系统调用,实现 IO 端口的复用。一般用于用户程序的一段循环体中, diff --git a/kernel/src/fs/stdio.rs b/kernel/src/fs/stdio.rs index aa2a7ce0..4e90fc3a 100644 --- a/kernel/src/fs/stdio.rs +++ b/kernel/src/fs/stdio.rs @@ -1,7 +1,7 @@ use crate::fs::file::KernelFile; use crate::fs::SYSTEM_ROOT_FS; use alloc::sync::Arc; -use pconst::io::OpenFlags; +use constants::io::OpenFlags; use spin::Lazy; use vfscore::path::VfsPath; diff --git a/kernel/src/fs/sys/info.rs b/kernel/src/fs/sys/info.rs index 40acfcec..277b80a9 100644 --- a/kernel/src/fs/sys/info.rs +++ b/kernel/src/fs/sys/info.rs @@ -1,87 +1,87 @@ -use crate::task::current_task; -use crate::timer::get_time_ms; -use crate::MACHINE_INFO; -use core::cmp::min; -use pconst::sys::{Sysinfo, SyslogAction}; -use pconst::LinuxErrno; - -const LOG_BUF_LEN: usize = 4096; -const LOG: &str = r" -[ 0.000000] Linux version 5.10.0-7-riscv64 (debian-kernel@lists.debian.org) (gcc-10 (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2) #1 SMP Debian 5.10.40-1 (2021-05-28) -"; - -/// (待完善)一个系统调用函数,用于对内核消息环状缓冲区进行操作。 -/// -/// + `log_type`: 指明操作的类型,具体值可见[`SyslogAction`]; -/// + `buf`: 指明读取消息时,消息要保存到的位置; -/// + `len`: 指明具体操作时,对于消息读取的长度限制。真正的读取消息的长度将取决于就传入的`len`和`LOG_BUF_LEN`的最小值。 -/// -/// 当`log_type`为`READ`、`ReadAll`、`ReadClear`三种flag,正确执行后返回读取消息的长度; -/// 当`log_type`为`Unknown`时,会返回`EINVAL`;当`log_type`为`OPEN`或`CLOSE`时,函数不进行任何操作后返回0。 -/// 目前Alien仅支持上述`log_type`值,其余值都将不进行任何操作后返回0。 -/// -/// Reference: [syslog](https://man7.org/linux/man-pages/man2/syslog.2.html) -#[syscall_func(116)] -pub fn syslog(log_type: u32, buf: usize, len: usize) -> isize { - let log_type = SyslogAction::try_from(log_type); - if log_type.is_err() { - return LinuxErrno::EINVAL as isize; - } - match log_type.unwrap() { - SyslogAction::OPEN | SyslogAction::CLOSE => 0, - SyslogAction::READ | SyslogAction::ReadAll | SyslogAction::ReadClear => { - let min_len = min(len, LOG_BUF_LEN); - let task = current_task().unwrap(); - // the buf may be not valid, so we need to check it -- > sbrk heap - let mut buf = task.transfer_buffer(buf as *mut u8, min_len); - let log = LOG.as_bytes(); - let mut offset = 0; - buf.iter_mut().for_each(|buf| { - let copy_len = min(log.len() - offset, buf.len()); - buf[..copy_len].copy_from_slice(&log[offset..offset + copy_len]); - offset += copy_len; - }); - offset as isize - } - SyslogAction::Unknown => LinuxErrno::EINVAL as isize, - _ => 0, - } -} - -extern "C" { - fn ekernel(); -} - -/// 一个系统调用函数,用于获取系统相关信息。信息包括系统的自启动经过的时间、对于内存的使用情况、共享存储区的大小、 -/// 缓冲区与交换区的大小、当前进程数目等,具体可见[`Sysinfo`]。获取到的信息将保存到`dst_info`所指向的[`Sysinfo`]结构处。 -/// -/// 目前功能还有待完善。正确执行后返回0。 -#[syscall_func(179)] -pub fn sys_info(dst_info: usize) -> isize { - const LINUX_SYSINFO_LOADS_SCALE: usize = 65536; - let task = current_task().unwrap(); - // calculate the task number - let task_number = 10; // fake task number - let memory_info = MACHINE_INFO.get().as_ref().unwrap().memory.clone(); - let info = Sysinfo { - uptime: (get_time_ms() / 1000) as usize, - loads: [ - task_number * LINUX_SYSINFO_LOADS_SCALE / 60, - task_number * LINUX_SYSINFO_LOADS_SCALE / 300, - task_number * LINUX_SYSINFO_LOADS_SCALE / 900, - ], - totalram: memory_info.end - memory_info.start, - freeram: memory_info.end - ekernel as usize, - sharedram: 0, - bufferram: 0, - totalswap: 0, - freeswap: 0, - procs: task_number as u16, - totalhigh: 0, - freehigh: 0, - mem_unit: 1, - }; - task.access_inner() - .copy_to_user(&info, dst_info as *mut Sysinfo); - 0 -} +use crate::task::current_task; +use crate::timer::get_time_ms; +use crate::MACHINE_INFO; +use constants::sys::{Sysinfo, SyslogAction}; +use constants::LinuxErrno; +use core::cmp::min; + +const LOG_BUF_LEN: usize = 4096; +const LOG: &str = r" +[ 0.000000] Linux version 5.10.0-7-riscv64 (debian-kernel@lists.debian.org) (gcc-10 (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2) #1 SMP Debian 5.10.40-1 (2021-05-28) +"; + +/// (待完善)一个系统调用函数,用于对内核消息环状缓冲区进行操作。 +/// +/// + `log_type`: 指明操作的类型,具体值可见[`SyslogAction`]; +/// + `buf`: 指明读取消息时,消息要保存到的位置; +/// + `len`: 指明具体操作时,对于消息读取的长度限制。真正的读取消息的长度将取决于就传入的`len`和`LOG_BUF_LEN`的最小值。 +/// +/// 当`log_type`为`READ`、`ReadAll`、`ReadClear`三种flag,正确执行后返回读取消息的长度; +/// 当`log_type`为`Unknown`时,会返回`EINVAL`;当`log_type`为`OPEN`或`CLOSE`时,函数不进行任何操作后返回0。 +/// 目前Alien仅支持上述`log_type`值,其余值都将不进行任何操作后返回0。 +/// +/// Reference: [syslog](https://man7.org/linux/man-pages/man2/syslog.2.html) +#[syscall_func(116)] +pub fn syslog(log_type: u32, buf: usize, len: usize) -> isize { + let log_type = SyslogAction::try_from(log_type); + if log_type.is_err() { + return LinuxErrno::EINVAL as isize; + } + match log_type.unwrap() { + SyslogAction::OPEN | SyslogAction::CLOSE => 0, + SyslogAction::READ | SyslogAction::ReadAll | SyslogAction::ReadClear => { + let min_len = min(len, LOG_BUF_LEN); + let task = current_task().unwrap(); + // the buf may be not valid, so we need to check it -- > sbrk heap + let mut buf = task.transfer_buffer(buf as *mut u8, min_len); + let log = LOG.as_bytes(); + let mut offset = 0; + buf.iter_mut().for_each(|buf| { + let copy_len = min(log.len() - offset, buf.len()); + buf[..copy_len].copy_from_slice(&log[offset..offset + copy_len]); + offset += copy_len; + }); + offset as isize + } + SyslogAction::Unknown => LinuxErrno::EINVAL as isize, + _ => 0, + } +} + +extern "C" { + fn ekernel(); +} + +/// 一个系统调用函数,用于获取系统相关信息。信息包括系统的自启动经过的时间、对于内存的使用情况、共享存储区的大小、 +/// 缓冲区与交换区的大小、当前进程数目等,具体可见[`Sysinfo`]。获取到的信息将保存到`dst_info`所指向的[`Sysinfo`]结构处。 +/// +/// 目前功能还有待完善。正确执行后返回0。 +#[syscall_func(179)] +pub fn sys_info(dst_info: usize) -> isize { + const LINUX_SYSINFO_LOADS_SCALE: usize = 65536; + let task = current_task().unwrap(); + // calculate the task number + let task_number = 10; // fake task number + let memory_info = MACHINE_INFO.get().as_ref().unwrap().memory.clone(); + let info = Sysinfo { + uptime: (get_time_ms() / 1000) as usize, + loads: [ + task_number * LINUX_SYSINFO_LOADS_SCALE / 60, + task_number * LINUX_SYSINFO_LOADS_SCALE / 300, + task_number * LINUX_SYSINFO_LOADS_SCALE / 900, + ], + totalram: memory_info.end - memory_info.start, + freeram: memory_info.end - ekernel as usize, + sharedram: 0, + bufferram: 0, + totalswap: 0, + freeswap: 0, + procs: task_number as u16, + totalhigh: 0, + freehigh: 0, + mem_unit: 1, + }; + task.access_inner() + .copy_to_user(&info, dst_info as *mut Sysinfo); + 0 +} diff --git a/kernel/src/fs/sys/mod.rs b/kernel/src/fs/sys/mod.rs index de12de20..5cd608a1 100644 --- a/kernel/src/fs/sys/mod.rs +++ b/kernel/src/fs/sys/mod.rs @@ -1,7 +1,7 @@ use crate::fs::CommonFsProviderImpl; -use crate::ksync::Mutex; use alloc::sync::Arc; use dynfs::DynFsDirInode; +use ksync::Mutex; use vfscore::dentry::VfsDentry; use vfscore::fstype::VfsFsType; diff --git a/kernel/src/interrupt/ext_interrupt.rs b/kernel/src/interrupt/ext_interrupt.rs index 7433e486..7e0d06ef 100644 --- a/kernel/src/interrupt/ext_interrupt.rs +++ b/kernel/src/interrupt/ext_interrupt.rs @@ -1,7 +1,7 @@ use plic::Mode; -use crate::arch::hart_id; use crate::interrupt::{DEVICE_TABLE, PLIC}; +use arch::hart_id; pub fn external_interrupt_handler() { let plic = PLIC.get().unwrap(); diff --git a/kernel/src/interrupt/mod.rs b/kernel/src/interrupt/mod.rs index e5f58411..93e1240c 100644 --- a/kernel/src/interrupt/mod.rs +++ b/kernel/src/interrupt/mod.rs @@ -3,13 +3,13 @@ use alloc::sync::Arc; use cfg_if::cfg_if; use spin::Once; -use crate::ksync::Mutex; pub use ext_interrupt::external_interrupt_handler; +use ksync::Mutex; use plic::{Mode, PLIC}; -use crate::arch::hart_id; use crate::config::CPU_NUM; use crate::MACHINE_INFO; +use arch::hart_id; mod ext_interrupt; pub mod record; diff --git a/kernel/src/interrupt/record.rs b/kernel/src/interrupt/record.rs index 4f2e89b2..5d576b92 100644 --- a/kernel/src/interrupt/record.rs +++ b/kernel/src/interrupt/record.rs @@ -1,8 +1,8 @@ use alloc::collections::BTreeMap; use alloc::format; use alloc::string::String; -use spin::{Lazy}; -use crate::ksync::Mutex; +use ksync::Mutex; +use spin::Lazy; /// Record the number of interrupts pub static INTERRUPT_RECORD: Lazy>> = Lazy::new(|| { diff --git a/kernel/src/ipc/futex.rs b/kernel/src/ipc/futex.rs index 095be7ac..184b2a34 100644 --- a/kernel/src/ipc/futex.rs +++ b/kernel/src/ipc/futex.rs @@ -18,12 +18,12 @@ use alloc::vec; use alloc::vec::Vec; use core::cmp::min; -use crate::ksync::Mutex; +use ksync::Mutex; use smpscheduler::FifoTask; -use crate::error::{AlienError, AlienResult}; use crate::task::{Task, GLOBAL_TASK_MANAGER}; use crate::timer::read_timer; +use constants::{AlienError, AlienResult}; /// 用于记录一个进程等待一个 futex 的相关信息 pub struct FutexWaiter { diff --git a/kernel/src/ipc/mod.rs b/kernel/src/ipc/mod.rs index 31b9409f..c4ac1946 100644 --- a/kernel/src/ipc/mod.rs +++ b/kernel/src/ipc/mod.rs @@ -9,10 +9,10 @@ use alloc::sync::Arc; use core::sync::atomic::{AtomicI32, Ordering}; use spin::Lazy; -use crate::error::AlienResult; -use crate::ksync::Mutex; -use pconst::ipc::{FutexOp, RobustList}; -use pconst::LinuxErrno; +use constants::ipc::{FutexOp, RobustList}; +use constants::AlienResult; +use constants::LinuxErrno; +use ksync::Mutex; pub use pipe::*; pub use shm::*; pub use signal::*; diff --git a/kernel/src/ipc/pipe.rs b/kernel/src/ipc/pipe.rs index 54db94f8..75784b1a 100644 --- a/kernel/src/ipc/pipe.rs +++ b/kernel/src/ipc/pipe.rs @@ -11,19 +11,19 @@ //! 符表中。 use crate::config::PIPE_BUF; -use crate::error::AlienResult; use crate::fs::file::File; use crate::fs::CommonFsProviderImpl; -use crate::ksync::Mutex; use crate::task::{current_task, do_suspend}; use alloc::string::{String, ToString}; use alloc::sync::{Arc, Weak}; use alloc::vec::Vec; +use constants::io::{MountFlags, OpenFlags, PollEvents, SeekFrom}; +use constants::AlienResult; +use constants::LinuxErrno; use core::fmt::{Debug, Formatter}; use core::sync::atomic::AtomicUsize; use dynfs::DynFsDirInode; -use pconst::io::{MountFlags, OpenFlags, PollEvents, SeekFrom}; -use pconst::LinuxErrno; +use ksync::Mutex; use spin::Once; use vfscore::dentry::VfsDentry; use vfscore::error::VfsError; @@ -105,13 +105,13 @@ pub fn make_pipe_file() -> VfsResult<(Arc, Arc)> { impl File for PipeFile { fn read(&self, buf: &mut [u8]) -> AlienResult { if buf.len() == 0 { - return Ok(0) + return Ok(0); } self.dentry.inode()?.read_at(0, buf).map_err(|e| e.into()) } fn write(&self, buf: &[u8]) -> AlienResult { if buf.len() == 0 { - return Ok(0) + return Ok(0); } self.dentry.inode()?.write_at(0, buf).map_err(|e| e.into()) } diff --git a/kernel/src/ipc/shm.rs b/kernel/src/ipc/shm.rs index 319a067c..3baca29c 100644 --- a/kernel/src/ipc/shm.rs +++ b/kernel/src/ipc/shm.rs @@ -11,9 +11,9 @@ use alloc::vec::Vec; use page_table::addr::{align_down_4k, PhysAddr, VirtAddr}; use page_table::table::PageSize; -use crate::ksync::{Mutex, MutexGuard}; -use pconst::ipc::{ShmAtFlags, ShmCtlCmd, ShmGetFlags, IPC_PRIVATE}; -use pconst::LinuxErrno; +use constants::ipc::{ShmAtFlags, ShmCtlCmd, ShmGetFlags, IPC_PRIVATE}; +use constants::LinuxErrno; +use ksync::{Mutex, MutexGuard}; use syscall_table::syscall_func; use crate::config::FRAME_SIZE; diff --git a/kernel/src/ipc/signal.rs b/kernel/src/ipc/signal.rs index 6478d87d..6769a6e7 100644 --- a/kernel/src/ipc/signal.rs +++ b/kernel/src/ipc/signal.rs @@ -7,12 +7,12 @@ use alloc::sync::Arc; use alloc::vec::Vec; use core::mem::size_of; -use crate::ksync::Mutex; -use pconst::signal::{ +use constants::signal::{ SigAction, SigActionDefault, SigActionFlags, SigInfo, SigProcMaskHow, SignalNumber, SignalReceivers, SignalUserContext, SimpleBitSet, }; -use pconst::LinuxErrno; +use constants::LinuxErrno; +use ksync::Mutex; use syscall_table::syscall_func; use crate::task::{current_task, do_exit, do_suspend}; diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 116435c1..523a8f7b 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -13,24 +13,20 @@ extern crate alloc; #[macro_use] extern crate log; - use spin::Once; use basemachine::MachineInfo; #[macro_use] pub mod print; -pub mod arch; pub mod board; pub mod config; pub mod device; pub mod driver; -pub mod error; pub mod fs; pub mod gui; pub mod interrupt; pub mod ipc; -pub mod ksync; pub mod memory; pub mod net; pub mod panic; @@ -55,11 +51,3 @@ pub static MACHINE_INFO: Once = Once::new(); pub fn init_machine_info(machine_info: MachineInfo) { MACHINE_INFO.call_once(|| machine_info); } - -/// 允许内核读写用户态内存。 -/// 取决于 CPU 的 RISC-V 规范版本就行处理 -pub fn thread_local_init() { - unsafe { - riscv::register::sstatus::set_sum(); - } -} diff --git a/kernel/src/memory/elf.rs b/kernel/src/memory/elf.rs index eb430b00..0f14e224 100644 --- a/kernel/src/memory/elf.rs +++ b/kernel/src/memory/elf.rs @@ -133,3 +133,18 @@ impl ELFReader for ElfFile<'_> { Ok(res) } } +// /* RISC-V relocations. */ +// #define R_RISCV_NONE 0 +// #define R_RISCV_32 1 +// #define R_RISCV_64 2 +// #define R_RISCV_RELATIVE 3 +// #define R_RISCV_COPY 4 +// #define R_RISCV_JUMP_SLOT 5 +// #define R_RISCV_TLS_DTPMOD32 6 +// #define R_RISCV_TLS_DTPMOD64 7 +// #define R_RISCV_TLS_DTPREL32 8 +// #define R_RISCV_TLS_DTPREL64 9 +// #define R_RISCV_TLS_TPREL32 10 +// #define R_RISCV_TLS_TPREL64 11 +// #define R_RISCV_BRANCH 16 +// #define R_RISCV_JAL 17 diff --git a/kernel/src/memory/frame.rs b/kernel/src/memory/frame.rs index f4b180c2..aad1d187 100644 --- a/kernel/src/memory/frame.rs +++ b/kernel/src/memory/frame.rs @@ -1,9 +1,9 @@ use super::manager::FrameRefManager; use crate::config::{FRAME_BITS, FRAME_SIZE}; -use crate::ksync::Mutex; use alloc::format; use alloc::vec::Vec; use core::ops::{Deref, DerefMut}; +use ksync::Mutex; use pager::{PageAllocator, PageAllocatorExt}; use spin::Lazy; diff --git a/kernel/src/memory/map.rs b/kernel/src/memory/map.rs index 05197109..11fa4d1a 100644 --- a/kernel/src/memory/map.rs +++ b/kernel/src/memory/map.rs @@ -6,14 +6,14 @@ use bitflags::bitflags; use page_table::addr::{align_up_4k, VirtAddr}; use page_table::pte::MappingFlags; -use pconst::io::MapFlags; -use pconst::LinuxErrno; +use constants::io::MapFlags; +use constants::LinuxErrno; use syscall_table::syscall_func; use crate::config::{FRAME_SIZE, PROCESS_HEAP_MAX}; -use crate::error::AlienResult; use crate::fs::file::File; use crate::task::current_task; +use constants::AlienResult; bitflags! { pub struct ProtFlags: u32 { @@ -183,7 +183,14 @@ pub fn do_munmap(start: usize, len: usize) -> isize { /// 函数成功执行后将返回所创建的内存映射区的首地址;否则返回错误类型。 /// Reference: [do_mmap](https://man7.org/linux/man-pages/man2/mmap.2.html) #[syscall_func(222)] -pub fn do_mmap(start: usize, len: usize, prot: u32, flags: u32, fd: usize, offset: usize) -> AlienResult { +pub fn do_mmap( + start: usize, + len: usize, + prot: u32, + flags: u32, + fd: usize, + offset: usize, +) -> AlienResult { let process = current_task().unwrap(); let mut process_inner = process.access_inner(); let prot = ProtFlags::from_bits_truncate(prot); @@ -192,7 +199,9 @@ pub fn do_mmap(start: usize, len: usize, prot: u32, flags: u32, fd: usize, offse "mmap: start: {:#x}, len: {:#x}, prot: {:?}, flags: {:?}, fd: {}, offset: {:#x}", start, len, prot, flags, fd, offset ); - process_inner.add_mmap(start, len, prot, flags, fd, offset).map(|addr| addr as isize) + process_inner + .add_mmap(start, len, prot, flags, fd, offset) + .map(|addr| addr as isize) } /// 一个系统调用,用于修改内存映射的保护位,从而修改对内存映射的访问权限。 diff --git a/kernel/src/memory/mod.rs b/kernel/src/memory/mod.rs index 13240c92..5da7e00d 100644 --- a/kernel/src/memory/mod.rs +++ b/kernel/src/memory/mod.rs @@ -3,21 +3,19 @@ use core::alloc::GlobalAlloc; #[cfg(feature = "buddy")] use buddy_system_allocator::LockedHeap; use cfg_if::cfg_if; -use riscv::asm::sfence_vma_all; -use riscv::register::satp; #[cfg(feature = "talloc")] use talc::{Talc, Talck}; -use crate::ksync::Mutex; pub use frame::*; +use ksync::Mutex; pub use map::*; use syscall_table::syscall_func; pub use vmm::*; -use crate::arch::hart_id; use crate::config::FRAME_SIZE; #[cfg(any(feature = "talloc", feature = "buddy"))] use crate::config::KERNEL_HEAP_SIZE; +use arch::{activate_paging_mode, hart_id}; mod elf; mod frame; @@ -49,24 +47,10 @@ pub fn init_memory_system(memory_end: usize, is_first_cpu: bool) { } build_kernel_address_space(memory_end); println!("build kernel address space success"); - activate_paging_mode(); + activate_paging_mode(kernel_space_root_ppn()); println!("activate paging mode success"); } else { - activate_paging_mode(); - } -} - -/// 激活页表模式 -pub fn activate_paging_mode() { - // let ppn = KERNEL_SPACE.read().root_ppn().unwrap().0; - unsafe { - sfence_vma_all(); - satp::set( - satp::Mode::Sv39, - 0, - KERNEL_SPACE.read().root_paddr().as_usize() >> 12, - ); - sfence_vma_all(); + activate_paging_mode(kernel_space_root_ppn()); } } diff --git a/kernel/src/memory/vmm.rs b/kernel/src/memory/vmm.rs index bb4c9b2b..2f2d2a01 100644 --- a/kernel/src/memory/vmm.rs +++ b/kernel/src/memory/vmm.rs @@ -1,7 +1,6 @@ use crate::config::*; use crate::fs; use crate::ipc::ShmInfo; -use crate::ksync::RwLock; use crate::memory::elf::{ELFError, ELFInfo, ELFReader}; use crate::memory::frame::{addr_to_frame, frame_alloc}; use crate::memory::{frame_alloc_contiguous, FRAME_REF_MANAGER}; @@ -14,6 +13,7 @@ use alloc::vec::Vec; use core::cmp::min; use core::fmt::Debug; use core::mem::forget; +use ksync::RwLock; use page_table::addr::{align_up_4k, PhysAddr, VirtAddr}; use page_table::pte::MappingFlags; use page_table::table::{PagingIf, Sv39PageTable}; @@ -26,6 +26,10 @@ pub static KERNEL_SPACE: Lazy>>> = Lazy: )) }); +pub fn kernel_space_root_ppn() -> usize { + KERNEL_SPACE.read().root_paddr().as_usize() >> FRAME_BITS +} + #[allow(unused)] extern "C" { fn stext(); @@ -381,8 +385,6 @@ pub fn build_elf_address_space( .for_each(|ph| { let start_addr = ph.virtual_addr() as usize + bias; let end_addr = start_addr + ph.mem_size() as usize; - // 记录程序地址空间的最大地址 - break_addr = end_addr; let mut permission: MappingFlags = "UVAD".into(); let ph_flags = ph.flags(); if ph_flags.is_read() { @@ -396,6 +398,8 @@ pub fn build_elf_address_space( } let vaddr = VirtAddr::from(start_addr).align_down_4k(); let end_vaddr = VirtAddr::from(end_addr).align_up_4k(); + // 记录程序地址空间的最大地址 + break_addr = end_addr; let len = end_vaddr.as_usize() - vaddr.as_usize(); warn!( "load segment: {:#x} - {:#x} -> {:#x}-{:#x}, permission: {:?}", @@ -412,24 +416,30 @@ pub fn build_elf_address_space( .unwrap(); // copy data let mut page_offset = start_addr & (FRAME_SIZE - 1); + let mut count = 0; map_info .into_iter() - .for_each(|(vir, phy, page_size)| unsafe { - trace!("{:#x} {:#x} {:#x?}", vir, phy, page_size); + .for_each(|(_vir, phy, page_size)| unsafe { let size: usize = page_size.into(); let min = min(size - page_offset, data.len()); let dst = (phy.as_usize() + page_offset) as *mut u8; core::ptr::copy(data.as_ptr(), dst, min); data = &data[min..]; - page_offset = (page_offset + min) & (FRAME_SIZE - 1); + count += min; + page_offset = 0; }); + assert_eq!(count, ph.file_size() as usize); }); // 地址向上取整对齐4 - let ceil_addr = align_up_4k(break_addr+FRAME_SIZE); + let ceil_addr = align_up_4k(break_addr + FRAME_SIZE); // 留出一个用户栈的位置+隔离页 let top = ceil_addr + USER_STACK_SIZE + FRAME_SIZE; - warn!("user stack: {:#x} - {:#x}", top - USER_STACK_SIZE - FRAME_SIZE, top-FRAME_SIZE); + warn!( + "user stack: {:#x} - {:#x}", + top - USER_STACK_SIZE - FRAME_SIZE, + top - FRAME_SIZE + ); // map user stack address_space .map_region_no_target( @@ -442,7 +452,7 @@ pub fn build_elf_address_space( .unwrap(); // 初始化一个有效页 address_space - .validate(VirtAddr::from(top - FRAME_SIZE * 2 ), "RWUVAD".into()) + .validate(VirtAddr::from(top - FRAME_SIZE * 2), "RWUVAD".into()) .unwrap(); let heap_bottom = top; // align to 4k diff --git a/kernel/src/net/addr.rs b/kernel/src/net/addr.rs index cde85cbb..db9deb7e 100644 --- a/kernel/src/net/addr.rs +++ b/kernel/src/net/addr.rs @@ -15,10 +15,10 @@ use alloc::vec; use core::fmt::Debug; use core::net::{IpAddr, Ipv4Addr, SocketAddr}; -use crate::error::AlienResult; use crate::task::current_task; -use pconst::net::Domain; -use pconst::LinuxErrno; +use constants::net::Domain; +use constants::AlienResult; +use constants::LinuxErrno; /// 用于存储套接字通信地址的结构,分为本地路径地址和网络套接字地址。 #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] diff --git a/kernel/src/net/mod.rs b/kernel/src/net/mod.rs index a49f96a8..992d1a26 100644 --- a/kernel/src/net/mod.rs +++ b/kernel/src/net/mod.rs @@ -5,7 +5,6 @@ //! [`socket`] 子模块指明了Alien 内核中使用的套接字。 //! [`unix`] 子模块指明了有关 Unix 协议族下的套接字结构。(目前有关的功能有待支持) //! -use crate::error::AlienResult; use crate::fs::file::File; use crate::net::addr::{socket_addr_resolution, RawIpV4Addr}; use crate::net::socket::{SocketData, SocketFile, SocketFileExt}; @@ -13,9 +12,10 @@ use crate::task::{current_task, do_suspend}; use alloc::sync::Arc; use alloc::vec; use alloc::vec::Vec; -use pconst::io::OpenFlags; -use pconst::net::*; -use pconst::LinuxErrno; +use constants::io::OpenFlags; +use constants::net::*; +use constants::AlienResult; +use constants::LinuxErrno; use syscall_table::syscall_func; pub mod addr; diff --git a/kernel/src/net/port.rs b/kernel/src/net/port.rs index aeab125b..3183d585 100644 --- a/kernel/src/net/port.rs +++ b/kernel/src/net/port.rs @@ -1,7 +1,7 @@ //! 现为将网络异常类型 [`NetError`] 转为 系统异常类型 [`LinuxErrno`]的模块。原为定义端口全局变量和操作的模块。 -use crate::error::AlienError; -use pconst::LinuxErrno; +use constants::AlienError; +use constants::LinuxErrno; use netcore::common::NetError; /// 现为将网络异常类型 [`NetError`] 转为 系统异常类型 [`LinuxErrno`]。 diff --git a/kernel/src/net/socket.rs b/kernel/src/net/socket.rs index 74be92ce..5518bdd6 100644 --- a/kernel/src/net/socket.rs +++ b/kernel/src/net/socket.rs @@ -8,20 +8,20 @@ //! [`socket_ready_to_read`]、[`socket_ready_to_write`] 几个操作函数,即可快速的创建套接字文件,并将其放入进程的文件描述 //! 符表中,具体有关套接字文件的创建,可见 [`SocketData::new`] 的实现。 use super::ShutdownFlag; -use crate::error::AlienResult; use crate::fs::file::File; -use crate::ksync::{Mutex, MutexGuard}; use crate::net::addr::SocketAddrExt; use crate::net::port::neterror2alien; use crate::net::unix::UnixSocket; +use constants::AlienResult; +use ksync::{Mutex, MutexGuard}; // use crate::task::do_suspend; use alloc::boxed::Box; use alloc::sync::Arc; +use constants::io::{OpenFlags, PollEvents, SeekFrom}; +use constants::net::{Domain, SocketType}; +use constants::LinuxErrno; use core::fmt::{Debug, Formatter}; use core::net::SocketAddr; -use pconst::io::{OpenFlags, PollEvents, SeekFrom}; -use pconst::net::{Domain, SocketType}; -use pconst::LinuxErrno; use netcore::tcp::TcpSocket; use netcore::udp::UdpSocket; use vfscore::dentry::VfsDentry; @@ -69,8 +69,8 @@ impl SocketFileExt for SocketFile { impl File for SocketFile { fn read(&self, buf: &mut [u8]) -> AlienResult { - if buf.len()==0{ - return Ok(0) + if buf.len() == 0 { + return Ok(0); } netcore::poll_interfaces(); let socket = self.get_socketdata().unwrap(); @@ -83,8 +83,8 @@ impl File for SocketFile { } fn write(&self, buf: &[u8]) -> AlienResult { - if buf.len()==0{ - return Ok(0) + if buf.len() == 0 { + return Ok(0); } info!("socket_file_write: buf_len:{:?}", buf.len()); netcore::poll_interfaces(); diff --git a/kernel/src/net/unix.rs b/kernel/src/net/unix.rs index e1188c33..5ff469d9 100644 --- a/kernel/src/net/unix.rs +++ b/kernel/src/net/unix.rs @@ -1,10 +1,10 @@ //! 有关 Unix 协议族下的套接字结构。(目前有关的功能有待支持) use alloc::string::String; use alloc::sync::Arc; -use pconst::LinuxErrno; +use constants::LinuxErrno; use crate::fs::file::File; -use crate::ksync::Mutex; +use ksync::Mutex; /// Unix 协议族下的套接字结构 #[allow(unused)] diff --git a/kernel/src/panic.rs b/kernel/src/panic.rs index 3d6d2601..e2c2a26b 100644 --- a/kernel/src/panic.rs +++ b/kernel/src/panic.rs @@ -1,15 +1,15 @@ //! panic 处理 -use crate::sbi::{system_shutdown}; +use crate::sbi::system_shutdown; use crate::trace::find_symbol_with_addr; use core::panic::PanicInfo; use core::sync::atomic::AtomicBool; -use tracer::{Tracer, TracerProvider}; #[cfg(all(not(feature = "debug-eh-frame"), not(feature = "debug-frame-point")))] use tracer::CompilerTracer; -#[cfg(feature = "debug-frame-point")] -use tracer::FramePointTracer; #[cfg(feature = "debug-eh-frame")] use tracer::DwarfTracer; +#[cfg(feature = "debug-frame-point")] +use tracer::FramePointTracer; +use tracer::{Tracer, TracerProvider}; /// 递归标志 static RECURSION: AtomicBool = AtomicBool::new(false); @@ -45,7 +45,6 @@ impl TracerProvider for TracerProviderImpl { } } - #[cfg(feature = "debug-eh-frame")] extern "C" { fn kernel_eh_frame(); @@ -84,7 +83,7 @@ fn back_trace() { #[cfg(feature = "debug-frame-point")] let tracer = FramePointTracer::new(TracerProviderImpl); #[cfg(feature = "debug-eh-frame")] - let tracer = DwarfTracer::new(DwarfProviderImpl,TracerProviderImpl); + let tracer = DwarfTracer::new(DwarfProviderImpl, TracerProviderImpl); for x in tracer.trace() { println!("[{:#x}] (+{:0>4x}) {}", x.func_addr, x.bias, x.func_name); } diff --git a/kernel/src/print/console.rs b/kernel/src/print/console.rs index 1960beea..91272e0d 100644 --- a/kernel/src/print/console.rs +++ b/kernel/src/print/console.rs @@ -3,7 +3,7 @@ use core::sync::atomic::{AtomicBool, Ordering}; use preprint::Print; -use crate::ksync::Mutex; +use ksync::Mutex; use crate::device::UART_DEVICE; use crate::sbi::console_putchar; @@ -11,7 +11,7 @@ use crate::sbi::console_putchar; #[macro_export] macro_rules! print { ($($arg:tt)*) => { - let hard_id = $crate::arch::hart_id(); + let hard_id = arch::hart_id(); // [hart_id] xxx $crate::print::console::__print(format_args!("[{}] {}", hard_id, format_args!($($arg)*))) }; @@ -77,7 +77,7 @@ impl Write for Stdout { } struct MStdout; -impl Write for MStdout{ +impl Write for MStdout { fn write_str(&mut self, s: &str) -> Result { s.as_bytes().iter().for_each(|x| { console_putchar(*x); @@ -93,7 +93,7 @@ pub fn __mprint(args: Arguments) { #[macro_export] macro_rules! mprint { ($($arg:tt)*) => { - let hard_id = $crate::arch::hart_id(); + let hard_id = arch::hart_id(); // [hart_id] xxx $crate::print::console::__mprint(format_args!("[{}] {}", hard_id, format_args!($($arg)*))) }; @@ -107,7 +107,6 @@ macro_rules! mprintln { concat!($fmt, "\n"), $($arg)*)); } - /// 输出函数 /// 对参数进行输出 主要使用在输出相关的宏中 如println pub fn __print(args: Arguments) { diff --git a/kernel/src/task/cpu.rs b/kernel/src/task/cpu.rs index 8108e9ab..bd84d41a 100644 --- a/kernel/src/task/cpu.rs +++ b/kernel/src/task/cpu.rs @@ -2,20 +2,20 @@ use alloc::string::{String, ToString}; use alloc::sync::Arc; use alloc::vec::Vec; -use core::cell::{UnsafeCell}; +use core::cell::UnsafeCell; use smpscheduler::{FifoSmpScheduler, FifoTask, ScheduleHart}; use spin::Lazy; -use crate::error::{AlienError, AlienResult}; -use crate::ksync::Mutex; -use pconst::ipc::FutexOp; -use pconst::signal::SignalNumber; -use pconst::task::{CloneFlags, WaitOptions}; -use pconst::{PrLimit, PrLimitRes}; +use constants::ipc::FutexOp; +use constants::signal::SignalNumber; +use constants::task::{CloneFlags, WaitOptions}; +use constants::{AlienError, AlienResult}; +use constants::{PrLimit, PrLimitRes}; +use ksync::Mutex; use syscall_table::syscall_func; -use crate::arch::hart_id; use crate::config::CPU_NUM; +use crate::fs; use crate::ipc::{futex, global_logoff_signals}; use crate::sbi::system_shutdown; use crate::task::context::Context; @@ -23,7 +23,7 @@ use crate::task::schedule::schedule; use crate::task::task::{Task, TaskState}; use crate::task::INIT_PROCESS; use crate::trap::{check_task_timer_expired, TrapFrame}; -use crate::{arch, fs}; +use arch::hart_id; /// 记录当前 CPU 上正在执行的线程 和 线程上下文 #[derive(Debug, Clone)] diff --git a/kernel/src/task/mod.rs b/kernel/src/task/mod.rs index 77e5e576..37b2f6c7 100644 --- a/kernel/src/task/mod.rs +++ b/kernel/src/task/mod.rs @@ -30,7 +30,7 @@ pub static INIT_PROCESS: Lazy> = Lazy::new(|| { let mut data = Vec::new(); read_all("/bin/init", &mut data); // let data = INIT; - assert!(data.len()>0); + assert!(data.len() > 0); let task = Task::from_elf("/bin/init", data.as_slice()).unwrap(); Arc::new(task) }); diff --git a/kernel/src/task/schedule.rs b/kernel/src/task/schedule.rs index 0bc67b99..bead11fe 100644 --- a/kernel/src/task/schedule.rs +++ b/kernel/src/task/schedule.rs @@ -3,7 +3,7 @@ use alloc::sync::Arc; use core::arch::asm; use smpscheduler::FifoTask; -use pconst::signal::SignalNumber; +use constants::signal::SignalNumber; use crate::ipc::send_signal; use crate::task::context::switch; diff --git a/kernel/src/task/stack.rs b/kernel/src/task/stack.rs index 1ce8dee2..c5c8b676 100644 --- a/kernel/src/task/stack.rs +++ b/kernel/src/task/stack.rs @@ -1,7 +1,7 @@ //! 进程内核栈空间 use alloc::vec::Vec; -use crate::ksync::Mutex; +use ksync::Mutex; use crate::config::FRAME_BITS; use crate::memory::{frame_alloc_contiguous, FrameTracker}; diff --git a/kernel/src/task/task.rs b/kernel/src/task/task.rs index 3bb53a91..2c8d5473 100644 --- a/kernel/src/task/task.rs +++ b/kernel/src/task/task.rs @@ -4,11 +4,9 @@ //! 使用 `clone` 创建新的进程(线程)时,会根据 flag 指明父子进程之间资源共享的程度。 //! tid 是标识不同任务的唯一标识。 use crate::config::*; -use crate::error::{AlienError, AlienResult}; use crate::fs::file::File; use crate::fs::{STDIN, STDOUT, SYSTEM_ROOT_FS}; use crate::ipc::{global_register_signals, ShmInfo}; -use crate::ksync::{Mutex, MutexGuard}; use crate::memory::*; use crate::task::context::Context; use crate::task::heap::HeapInfo; @@ -21,20 +19,22 @@ use alloc::sync::{Arc, Weak}; use alloc::vec::Vec; use alloc::{format, vec}; use bit_field::BitField; +use constants::aux::*; +use constants::io::MapFlags; +use constants::ipc::RobustList; +use constants::signal::{SignalHandlers, SignalNumber, SignalReceivers, SignalUserContext}; +use constants::sys::TimeVal; +use constants::task::CloneFlags; +use constants::time::TimerType; +use constants::{AlienError, AlienResult}; +use constants::{LinuxErrno, PrLimit, PrLimitRes}; use core::fmt::{Debug, Formatter}; use core::ops::Range; use gmanager::MinimalManager; +use ksync::{Mutex, MutexGuard}; use page_table::addr::{align_down_4k, align_up_4k, VirtAddr}; use page_table::pte::MappingFlags; use page_table::table::Sv39PageTable; -use pconst::aux::*; -use pconst::io::MapFlags; -use pconst::ipc::RobustList; -use pconst::signal::{SignalHandlers, SignalNumber, SignalReceivers, SignalUserContext}; -use pconst::sys::TimeVal; -use pconst::task::CloneFlags; -use pconst::time::TimerType; -use pconst::{LinuxErrno, PrLimit, PrLimitRes}; use spin::Lazy; use vfscore::dentry::VfsDentry; @@ -1085,7 +1085,10 @@ impl TaskInner { let fd = if flags.contains(MapFlags::MAP_ANONYMOUS) { None } else { - let file = self.fd_table.lock().get(fd) + let file = self + .fd_table + .lock() + .get(fd) .map_err(|_| LinuxErrno::EBADF)? .ok_or(LinuxErrno::EBADF)?; // EBADF Some(file) @@ -1512,7 +1515,7 @@ impl Task { let argc_ptr = user_stack.push(0).unwrap(); let trap_frame = process.trap_frame(); - *trap_frame = TrapFrame::from_app_info( + *trap_frame = TrapFrame::init_for_task( elf_info.entry, argc_ptr, kernel_satp(), @@ -1850,7 +1853,7 @@ impl Task { .query(VirtAddr::from(TRAP_CONTEXT_BASE)) .unwrap(); let trap_frame = TrapFrame::from_raw_ptr(physical.as_usize() as *mut TrapFrame); - *trap_frame = TrapFrame::from_app_info( + *trap_frame = TrapFrame::init_for_task( elf_info.entry, user_sp, kernel_satp(), diff --git a/kernel/src/timer/mod.rs b/kernel/src/timer/mod.rs index 0c5b05da..1e2fcdc6 100644 --- a/kernel/src/timer/mod.rs +++ b/kernel/src/timer/mod.rs @@ -14,19 +14,17 @@ use alloc::collections::BinaryHeap; use alloc::sync::Arc; use core::cmp::Ordering; -use crate::ksync::Mutex; -use pconst::sys::TimeVal; -use pconst::time::{ClockId, TimerType}; -use pconst::LinuxErrno; +use crate::config::CLOCK_FREQ; +use crate::task::{current_task, do_suspend, StatisticalData, Task, GLOBAL_TASK_MANAGER}; +use constants::sys::TimeVal; +use constants::time::{ClockId, TimerType}; +use constants::LinuxErrno; +use ksync::Mutex; use smpscheduler::FifoTask; use spin::Lazy; use syscall_table::syscall_func; use vfscore::utils::VfsTimeSpec; -use crate::arch; -use crate::config::CLOCK_FREQ; -use crate::task::{current_task, do_suspend, StatisticalData, Task, GLOBAL_TASK_MANAGER}; - /// 每秒包含的 时间片 数,每隔一个时间片,就会产生一个时钟中断 const TICKS_PER_SEC: usize = 10; // const TICKS_PER_SEC_IN_KERNEL: usize = 1000; @@ -376,7 +374,7 @@ pub fn getitimer(_which: usize, current_value: usize) -> isize { pub fn setitimer(which: usize, current_value: usize, old_value: usize) -> isize { let which = TimerType::try_from(which).unwrap(); assert_ne!(which, TimerType::NONE); - warn!( + info!( "setitimer: which {:?} ,curret_value {:#x}, old_value {:#x}", which, current_value, old_value ); @@ -394,7 +392,7 @@ pub fn setitimer(which: usize, current_value: usize, old_value: usize) -> isize let mut itimer = ITimerVal::default(); task.access_inner() .copy_from_user(current_value as *const ITimerVal, &mut itimer); - error!("setitimer: itimer {:x?}", itimer); + info!("setitimer: itimer {:x?}", itimer); task.access_inner().set_timer(itimer, which); 0 } @@ -406,7 +404,7 @@ pub fn setitimer(which: usize, current_value: usize, old_value: usize) -> isize #[syscall_func(114)] pub fn clock_getres(id: usize, res: usize) -> isize { let id = ClockId::from_raw(id).unwrap(); - warn!("clock_getres: id {:?} ,res {:#x}", id, res); + info!("clock_getres: id {:?} ,res {:#x}", id, res); let task = current_task().unwrap(); let time_res = match id { ClockId::Monotonic => { @@ -434,7 +432,7 @@ pub fn clock_getres(id: usize, res: usize) -> isize { pub fn clock_nanosleep(clock_id: usize, flags: usize, req: usize, remain: usize) -> isize { const TIMER_ABSTIME: usize = 1; let id = ClockId::from_raw(clock_id).unwrap(); - warn!( + info!( "clock_nanosleep: id {:?} ,flags {:#x}, req {:#x}, remain {:#x}", id, flags, req, remain ); diff --git a/kernel/src/trap/context.rs b/kernel/src/trap/context.rs index b56b2089..b8534fb2 100644 --- a/kernel/src/trap/context.rs +++ b/kernel/src/trap/context.rs @@ -1,7 +1,6 @@ //! Trap 上下文 (Trap帧) 的定义和相关操作 -use bit_field::BitField; - -use crate::arch::riscv::sstatus::{self, Sstatus, SPP}; +use arch::ExtSstatus; +use riscv::register::sstatus::SPP; #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -19,7 +18,7 @@ pub struct TrapFrame { /// 记录所在的核 hart_id: usize, /// 给出 Trap 发生之前 CPU 处在哪个特权级等信息 - sstatus: Sstatus, + sstatus: ExtSstatus, fg: [usize; 2], } @@ -32,13 +31,13 @@ impl TrapFrame { k_sp: 0, trap_handler: 0, hart_id: 0, - sstatus: Sstatus::default(), + sstatus: ExtSstatus::default(), fg: [0; 2], } } /// 获取当前的 Trap 帧下的 sstatus 寄存器的值 - pub fn get_status(&self) -> Sstatus { + pub fn get_status(&self) -> ExtSstatus { self.sstatus } @@ -47,9 +46,8 @@ impl TrapFrame { self.sepc += 4; } - /// pub fn from_raw_ptr(ptr: *mut TrapFrame) -> &'static mut Self { - unsafe { &mut *(ptr as *mut Self) } + unsafe { &mut *(ptr) } } /// 更新 Trap 帧中的内核栈地址 @@ -68,16 +66,16 @@ impl TrapFrame { } /// 用一个从文件系统中读取到的相关app数据,初始化一个 Trap 帧,使通过其创建的进程在初次进入用户态时能正常运行 - pub fn from_app_info( + pub fn init_for_task( entry: usize, sp: usize, k_satp: usize, k_sp: usize, trap_handler: usize, ) -> Self { - let mut sstatus = sstatus::read(); + let mut sstatus = ExtSstatus::read(); sstatus.set_spie(); - assert!(sstatus.0.get_bit(5)); //spie == 1 + // assert!(sstatus.0.get_bit(5)); //spie == 1 sstatus.set_spp(SPP::User); sstatus.set_sie(false); let mut res = Self { diff --git a/kernel/src/trap/exception.rs b/kernel/src/trap/exception.rs index 03d7448f..6f768f58 100644 --- a/kernel/src/trap/exception.rs +++ b/kernel/src/trap/exception.rs @@ -3,11 +3,11 @@ //! 目前包括系统调用异常处理 [`syscall_exception_handler`]、页错误异常处理 [`page_exception_handler`] (包括 //! 指令页错误异常处理 [`instruction_page_fault_exception_handler`]、 加载页错误异常处理[`load_page_fault_exception_handler`]、 //! 储存页错误异常处理 [`store_page_fault_exception_handler`]) 和 文件读入异常处理 [`trap_common_read_file`]。 -use crate::arch::{interrupt_enable}; -use crate::error::{AlienError, AlienResult}; use crate::fs::file::File; use crate::task::{current_task, current_trap_frame}; use alloc::sync::Arc; +use arch::interrupt_enable; +use constants::{AlienError, AlienResult}; use riscv::register::scause::{Exception, Trap}; /// 系统调用异常处理 @@ -19,7 +19,7 @@ pub fn syscall_exception_handler() { cx.update_sepc(); // get system call return value let parameters = cx.parameters(); - let syscall_name = pconst::syscall_name(parameters[0]); + let syscall_name = constants::syscall_name(parameters[0]); let p_name = current_task().unwrap().get_name(); let tid = current_task().unwrap().get_tid(); diff --git a/kernel/src/trap/mod.rs b/kernel/src/trap/mod.rs index a4c27151..ae42a8c4 100644 --- a/kernel/src/trap/mod.rs +++ b/kernel/src/trap/mod.rs @@ -3,30 +3,28 @@ use core::arch::{asm, global_asm}; use bit_field::BitField; use page_table::addr::VirtAddr; use riscv::register::sstatus::SPP; -use riscv::register::{sepc, sscratch, stval}; +use riscv::register::{sepc, sscratch, sstatus, stval, stvec}; +use constants::signal::SignalNumber; +use constants::signal::SIGNAL_RETURN_TRAP; +use constants::time::TimerType; pub use context::TrapFrame; pub use exception::trap_common_read_file; -use pconst::signal::SignalNumber; -use pconst::signal::SIGNAL_RETURN_TRAP; -use pconst::time::TimerType; -use crate::arch::riscv::register::scause::{Exception, Interrupt, Trap}; -use crate::arch::riscv::register::stvec; -use crate::arch::riscv::register::stvec::TrapMode; -use crate::arch::riscv::sstatus; -use crate::arch::{ - external_interrupt_enable, hart_id, interrupt_disable, interrupt_enable, is_interrupt_enable, - timer_interrupt_enable, -}; use crate::config::TRAMPOLINE; -use crate::error::AlienError; use crate::interrupt::external_interrupt_handler; use crate::interrupt::record::write_irq_info; use crate::ipc::{send_signal, signal_handler, signal_return, solve_futex_wait}; use crate::memory::KERNEL_SPACE; use crate::task::{current_task, current_trap_frame, current_user_token, do_exit, do_suspend}; use crate::timer::{check_timer_queue, set_next_trigger, set_next_trigger_in_kernel}; +use arch::{ + external_interrupt_enable, hart_id, interrupt_disable, interrupt_enable, is_interrupt_enable, + timer_interrupt_enable, +}; +use constants::AlienError; +use riscv::register::scause::{Exception, Interrupt, Trap}; +use riscv::register::stvec::TrapMode; mod context; mod exception; @@ -102,7 +100,7 @@ pub fn init_trap_subsystem() { pub trait TrapHandler { fn do_user_handle(&self); - fn do_kernel_handle(&self,sp:usize); + fn do_kernel_handle(&self, sp: usize); } impl TrapHandler for Trap { @@ -193,7 +191,7 @@ impl TrapHandler for Trap { } /// 内核态下的 trap 例程 - fn do_kernel_handle(&self,sp:usize) { + fn do_kernel_handle(&self, sp: usize) { let stval = stval::read(); let sepc = sepc::read(); match self { @@ -219,7 +217,7 @@ impl TrapHandler for Trap { Trap::Exception(_) => { panic!( "unhandled trap: {:?}, stval: {:#x?}, sepc: {:#x}, sp: {:#x}", - self, stval, sepc,sp + self, stval, sepc, sp ) } Trap::Interrupt(Interrupt::SupervisorExternal) => { @@ -305,7 +303,7 @@ pub fn check_task_timer_expired() { /// 只有在内核态下才能进入这个函数 /// 避免嵌套中断发生这里不会再开启中断 #[no_mangle] -pub fn kernel_trap_vector(sp:usize) { +pub fn kernel_trap_vector(sp: usize) { let sstatus = sstatus::read(); let spp = sstatus.spp(); if spp == SPP::User { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index f22d9b34..34757309 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2023-11-02" +channel = "nightly-2023-11-05" components = ["rust-src", "llvm-tools-preview", "rustfmt", "clippy"] targets = ["riscv64gc-unknown-none-elf"] diff --git a/subsystems/arch/Cargo.toml b/subsystems/arch/Cargo.toml new file mode 100644 index 00000000..717d3789 --- /dev/null +++ b/subsystems/arch/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "arch" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +config = { path = "../config" } + + +#[target.'cfg(target_arch = "riscv64")'.dependencies] +riscv = { version = "0.10" } \ No newline at end of file diff --git a/subsystems/arch/src/lib.rs b/subsystems/arch/src/lib.rs new file mode 100644 index 00000000..a4c2b0c8 --- /dev/null +++ b/subsystems/arch/src/lib.rs @@ -0,0 +1,5 @@ +#![no_std] + +mod riscv; + +pub use riscv::*; diff --git a/kernel/src/arch/mod.rs b/subsystems/arch/src/riscv/mod.rs similarity index 53% rename from kernel/src/arch/mod.rs rename to subsystems/arch/src/riscv/mod.rs index 5f2a2506..d91145d8 100644 --- a/kernel/src/arch/mod.rs +++ b/subsystems/arch/src/riscv/mod.rs @@ -1,9 +1,10 @@ -use core::arch::asm; +mod regs; -use self::riscv::register::sie; -use self::riscv::sstatus; +pub use regs::*; -pub mod riscv; +use core::arch::asm; +use riscv::asm::sfence_vma_all; +use riscv::register::satp; /// 获取当前的 hart id pub fn hart_id() -> usize { @@ -18,48 +19,48 @@ pub fn hart_id() -> usize { /// 检查全局中断是否开启 pub fn is_interrupt_enable() -> bool { - sstatus::read().sie() + riscv::register::sstatus::read().sie() } /// 关闭全局中断 pub fn interrupt_disable() { unsafe { - sstatus::clear_sie(); + riscv::register::sstatus::clear_sie(); } } /// 开启全局中断 pub fn interrupt_enable() { unsafe { - sstatus::set_sie(); + riscv::register::sstatus::set_sie(); } } /// 开启外部中断 pub fn external_interrupt_enable() { unsafe { - sie::set_sext(); + riscv::register::sie::set_sext(); } } /// 开启软件中断 pub fn software_interrupt_enable() { unsafe { - sie::set_ssoft(); + riscv::register::sie::set_ssoft(); } } /// 关闭外部中断 pub fn external_interrupt_disable() { unsafe { - sie::clear_sext(); + riscv::register::sie::clear_sext(); } } /// 开启时钟中断 pub fn timer_interrupt_enable() { unsafe { - sie::set_stimer(); + riscv::register::sie::set_stimer(); } } @@ -68,11 +69,18 @@ pub fn read_timer() -> usize { riscv::register::time::read() } -#[macro_export] -macro_rules! write_csr { - ($csr:ident, $val:expr) => { - unsafe { - asm!(concat!("csrw ", stringify!($csr), ", {}"), in(reg) $val); - } - }; +/// 激活页表模式 +pub fn activate_paging_mode(root_ppn: usize) { + unsafe { + sfence_vma_all(); + satp::set(satp::Mode::Sv39, 0, root_ppn); + sfence_vma_all(); + } +} + +/// Permit Supervisor User Memory access +pub fn allow_access_user_memory() { + unsafe { + riscv::register::sstatus::set_sum(); + } } diff --git a/subsystems/arch/src/riscv/regs.rs b/subsystems/arch/src/riscv/regs.rs new file mode 100644 index 00000000..ab3d9dc5 --- /dev/null +++ b/subsystems/arch/src/riscv/regs.rs @@ -0,0 +1,39 @@ +use core::arch::asm; +use riscv::register::sstatus::SPP; + +#[derive(Debug, Default, Copy, Clone)] +pub struct ExtSstatus(pub usize); + +impl ExtSstatus { + pub fn read() -> Self { + let val: usize; + unsafe { + asm!("csrr {},sstatus", out(reg)val); + } + ExtSstatus(val) + } + pub fn set_value(&mut self, val: usize) { + self.0 = val; + } + pub fn set_spp(&mut self, spp: SPP) { + // self.0.set_bit(8, spp as usize != 0); + self.0 = self.0 & !(1 << 8) | ((spp as usize) << 8); + } + pub fn spp(&self) -> SPP { + let v = (self.0 >> 8) & 1; + if v == 1 { + SPP::Supervisor + } else { + SPP::User + } + } + pub fn set_spie(&mut self) { + self.0 |= 1 << 5; + } + pub fn sie(&self) -> bool { + (self.0 & (1 << 1)) != 0 + } + pub fn set_sie(&mut self, value: bool) { + self.0 = self.0 & !(1 << 1) | ((value as usize) << 1); + } +} diff --git a/subsystems/config/Cargo.toml b/subsystems/config/Cargo.toml new file mode 100644 index 00000000..c1c81a8a --- /dev/null +++ b/subsystems/config/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "config" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + + +[features] +default = ["qemu"] +vf2 = [] +cv1811h = [] +hifive = [] +qemu = [] \ No newline at end of file diff --git a/subsystems/config/src/lib.rs b/subsystems/config/src/lib.rs new file mode 100644 index 00000000..91891f10 --- /dev/null +++ b/subsystems/config/src/lib.rs @@ -0,0 +1,118 @@ +#![no_std] +//! 配置文件 + +/// Alien os的标志 +pub const FLAG: &str = r" + _ _ _ + / \ | | (_) ___ _ __ + / _ \ | | | | / _ \ | '_ \ + / ___ \ | | | | | __/ | | | | + /_/ \_\ |_| |_| \___| |_| |_| +"; + +/// qemu时钟频率 +#[cfg(feature = "qemu")] +pub const CLOCK_FREQ: usize = 1250_0000; +/// vf2时钟频率 +#[cfg(feature = "vf2")] +pub const CLOCK_FREQ: usize = 400_0000; + +/// unmatched时钟频率 +#[cfg(feature = "hifive")] +pub const CLOCK_FREQ: usize = 100_0000; + +/// cv1811h时钟频率 +#[cfg(feature = "cv1811h")] +pub const CLOCK_FREQ: usize = 0x17d7840; + +/// 物理页大小 +pub const FRAME_SIZE: usize = 0x1000; +/// 物理页大小的位数 +pub const FRAME_BITS: usize = 12; +/// 内核启动栈大小 +pub const STACK_SIZE: usize = 1024 * 64; +/// 内核启动栈大小的位数 +pub const STACK_SIZE_BITS: usize = 16; + +/// equal to CLOCK_FREQ +pub const TIMER_FREQ: usize = CLOCK_FREQ; +/// 可配置的启动cpu数量 +pub const CPU_NUM: usize = 1; + +pub const AT_FDCWD: isize = -100isize; + +///qemu的设备地址空间 +#[cfg(feature = "qemu")] +pub const MMIO: &[(usize, usize)] = &[ + (0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine + (0x2000000, 0x10000), + (0xc00_0000, 0x21_0000), // VIRT_PLIC in virt machine + (0x1000_0000, 0x9000), // VIRT_UART0 with GPU in virt machine + (0x3000_0000, 0x1000_0000), +]; + +/// vf2的设备地址空间 +#[cfg(feature = "vf2")] +pub const MMIO: &[(usize, usize)] = &[ + (0x17040000, 0x10000), // RTC + (0xc000000, 0x4000000), //PLIC + (0x00_1000_0000, 0x10000), // UART +]; + +/// hifive的设备地址空间 +#[cfg(feature = "hifive")] +pub const MMIO: &[(usize, usize)] = &[ + (0xc000000, 0x4000000), //PLIC +]; + +// todo!(if the app linker script changed, this should be changed too) +/// 进程的堆空间上限 +pub const PROCESS_HEAP_MAX: usize = u32::MAX as usize + 1; +/// 跳板页的虚拟地址 +pub const TRAMPOLINE: usize = usize::MAX - 2 * FRAME_SIZE + 1; +/// trap context的虚拟地址 +pub const TRAP_CONTEXT_BASE: usize = TRAMPOLINE - FRAME_SIZE; + +/// app内核栈大小 +pub const USER_KERNEL_STACK_SIZE: usize = 0x1000 * 2; +/// app用户栈大小 +pub const USER_STACK_SIZE: usize = 0x50_000; + +/// vf2/unmatched 的块缓存大小 +#[cfg(any(feature = "vf2", feature = "hifive"))] +pub const BLOCK_CACHE_FRAMES: usize = 1024 * 4 * 4; + +/// qemu 的块缓存大小 +#[cfg(feature = "qemu")] +pub const BLOCK_CACHE_FRAMES: usize = 1024 * 4 * 4; + +/// vf2/unmatched 的堆空间大小 +#[cfg(any(feature = "vf2", feature = "hifive"))] +pub const HEAP_SIZE: usize = 0x40_00000; + +/// qemu 的堆空间大小 +#[cfg(feature = "qemu")] +pub const HEAP_SIZE: usize = 0x26_00000; // (32+6)MB + +/// equal to HEAP_SIZe +pub const KERNEL_HEAP_SIZE: usize = HEAP_SIZE; + +/// pipe缓冲区大小 +pub const PIPE_BUF: usize = 65536; + +/// 线程数量大小限制 +pub const MAX_THREAD_NUM: usize = 65536; +/// 描述符数量大小限制 +pub const MAX_FD_NUM: usize = 4096; + +/// 最大的输入事件数量 +pub const MAX_INPUT_EVENT_NUM: usize = 1024; + +/// 如果 elf 的 phdr 指示 base 是 0(如 libc-test 的 libc.so),则需要找一个非0的位置放置 +/// 我们将其从 0x4000_0000 开始放置。主要用于动态链接库使用 +pub const ELF_BASE_RELOCATE: usize = 0x400_0000; + +// QEMU user networking default IP +pub const QEMU_IP: &str = "10.0.2.15"; +// QEMU user networking gateway +pub const QEMU_GATEWAY: &str = "10.0.2.2"; diff --git a/subsystems/constants/Cargo.toml b/subsystems/constants/Cargo.toml new file mode 100644 index 00000000..6d53e5ad --- /dev/null +++ b/subsystems/constants/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "constants" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +pconst = { git = "https://github.com/os-module/pconst.git", features = ["trick"] } \ No newline at end of file diff --git a/subsystems/constants/src/lib.rs b/subsystems/constants/src/lib.rs new file mode 100644 index 00000000..2d3efe92 --- /dev/null +++ b/subsystems/constants/src/lib.rs @@ -0,0 +1,36 @@ +#![no_std] +//! 导出 `pconst` 中的常量和数据结构, 定义Alien OS的错误类型 + +pub use pconst::*; +pub type AlienError = LinuxErrno; +pub type AlienResult = Result; + +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq, Hash, Ord)] +pub struct DeviceId { + major: u32, + minor: u32, +} + +impl DeviceId { + pub fn new(major: u32, minor: u32) -> Self { + Self { major, minor } + } + pub fn major(&self) -> u32 { + self.major + } + pub fn minor(&self) -> u32 { + self.minor + } + pub fn id(&self) -> u64 { + ((self.major as u64) << 32) | (self.minor as u64) + } +} + +impl From for DeviceId { + fn from(id: u64) -> Self { + Self { + major: (id >> 32) as u32, + minor: (id & 0xffffffff) as u32, + } + } +} diff --git a/subsystems/device_interface/Cargo.toml b/subsystems/device_interface/Cargo.toml new file mode 100644 index 00000000..50e61212 --- /dev/null +++ b/subsystems/device_interface/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "device_interface" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +constants = { path = "../constants" } \ No newline at end of file diff --git a/subsystems/device_interface/src/lib.rs b/subsystems/device_interface/src/lib.rs new file mode 100644 index 00000000..1ee339fd --- /dev/null +++ b/subsystems/device_interface/src/lib.rs @@ -0,0 +1,48 @@ +#![no_std] + +use constants::io::RtcTime; +use constants::AlienResult; +use core::any::Any; + +pub trait DeviceBase: Sync + Send { + fn hand_irq(&self); +} + +pub trait BlockDevice: Send + Sync + DeviceBase { + fn read(&self, buf: &mut [u8], offset: usize) -> AlienResult; + fn write(&self, buf: &[u8], offset: usize) -> AlienResult; + fn size(&self) -> usize; + fn flush(&self) -> AlienResult<()>; +} +pub trait LowBlockDevice { + fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> AlienResult<()>; + fn write_block(&mut self, block_id: usize, buf: &[u8]) -> AlienResult<()>; + fn capacity(&self) -> usize; + fn flush(&mut self) {} +} + +pub trait GpuDevice: Send + Sync + Any + DeviceBase { + fn update_cursor(&self); + fn get_framebuffer(&self) -> &mut [u8]; + fn flush(&self); +} + +pub trait InputDevice: Send + Sync + DeviceBase { + fn is_empty(&self) -> bool; + fn read_event_with_block(&self) -> u64; + fn read_event_without_block(&self) -> Option; +} + +pub trait RtcDevice: Send + Sync + DeviceBase { + fn read_time(&self) -> RtcTime; +} + +pub trait UartDevice: Send + Sync + DeviceBase { + fn put(&self, c: u8); + fn get(&self) -> Option; + fn put_bytes(&self, bytes: &[u8]); + fn have_data_to_get(&self) -> bool; + fn have_space_to_put(&self) -> bool; +} + +pub trait NetDevice: DeviceBase {} diff --git a/subsystems/interrupt/Cargo.toml b/subsystems/interrupt/Cargo.toml new file mode 100644 index 00000000..0010297f --- /dev/null +++ b/subsystems/interrupt/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "interrupt" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +plic = { git = "https://github.com/os-module/plic" } +spin = "0" +ksync = { path = "../ksync" } +arch = { path = "../arch" } +config = { path = "../config" } +device_interface = { path = "../device_interface" } + + +[features] +default = [ "qemu" ] + +vf2 = [] +hifive = [] +qemu = [] diff --git a/subsystems/interrupt/src/ext_interrupt.rs b/subsystems/interrupt/src/ext_interrupt.rs new file mode 100644 index 00000000..44541293 --- /dev/null +++ b/subsystems/interrupt/src/ext_interrupt.rs @@ -0,0 +1,17 @@ +use plic::Mode; + +use crate::{DEVICE_TABLE, PLIC}; +use arch::hart_id; + +pub fn external_interrupt_handler() { + let plic = PLIC.get().unwrap(); + let hart_id = hart_id(); + let irq = plic.claim(hart_id as u32, Mode::Supervisor); + let table = DEVICE_TABLE.lock(); + let device = table + .get(&(irq as usize)) + .or_else(|| panic!("no device for irq {}", irq)) + .unwrap(); + device.hand_irq(); + plic.complete(hart_id as u32, Mode::Supervisor, irq); +} diff --git a/subsystems/interrupt/src/lib.rs b/subsystems/interrupt/src/lib.rs new file mode 100644 index 00000000..1498f198 --- /dev/null +++ b/subsystems/interrupt/src/lib.rs @@ -0,0 +1,58 @@ +#![no_std] +extern crate alloc; + +use alloc::collections::BTreeMap; +use alloc::sync::Arc; +use spin::Once; + +pub use ext_interrupt::external_interrupt_handler; +use ksync::Mutex; +use plic::{Mode, PLIC}; + +use arch::hart_id; +use config::CPU_NUM; +use device_interface::DeviceBase; + +mod ext_interrupt; +pub mod record; + +pub static PLIC: Once> = Once::new(); + +pub static DEVICE_TABLE: Mutex>> = Mutex::new(BTreeMap::new()); + +pub fn init_plic(addr: usize) { + #[cfg(feature = "qemu")] + { + let privileges = [2; CPU_NUM]; + let plic = PLIC::new(addr, privileges); + PLIC.call_once(|| plic); + println!("Init qemu plic success"); + } + #[cfg(any(feature = "vf2", feature = "hifive"))] + { + let mut privileges = [2; CPU_NUM]; + // core 0 don't have S mode + privileges[0] = 1; + println!("PLIC context: {:?}", privileges); + let plic = PLIC::new(addr, privileges); + PLIC.call_once(|| plic); + println!("Init hifive or vf2 plic success"); + } +} + +/// Register a device to PLIC. +pub fn register_device_to_plic(irq: usize, device: Arc) { + let mut table = DEVICE_TABLE.lock(); + table.insert(irq, device); + let hard_id = hart_id(); + println!( + "plic enable irq {} for hart {}, priority {}", + irq, hard_id, 1 + ); + let plic = PLIC.get().unwrap(); + plic.set_threshold(hard_id as u32, Mode::Machine, 1); + plic.set_threshold(hard_id as u32, Mode::Supervisor, 0); + plic.complete(hard_id as u32, Mode::Supervisor, irq as u32); + plic.set_priority(irq as u32, 1); + plic.enable(hard_id as u32, Mode::Supervisor, irq as u32); +} diff --git a/subsystems/interrupt/src/record.rs b/subsystems/interrupt/src/record.rs new file mode 100644 index 00000000..5d576b92 --- /dev/null +++ b/subsystems/interrupt/src/record.rs @@ -0,0 +1,33 @@ +use alloc::collections::BTreeMap; +use alloc::format; +use alloc::string::String; +use ksync::Mutex; +use spin::Lazy; + +/// Record the number of interrupts +pub static INTERRUPT_RECORD: Lazy>> = Lazy::new(|| { + let mut tree = BTreeMap::new(); + tree.insert(1, 0); // timer + tree.insert(10, 0); // uart + Mutex::new(tree) +}); + +/// Increase the number of interrupts +pub fn write_irq_info(irq: usize) { + let mut interrupts = INTERRUPT_RECORD.lock(); + let value = interrupts.get_mut(&irq).unwrap().clone(); + interrupts.insert(irq, value + 1); +} + +/// Serializes the number of interrupts +/// +/// # Return +/// irq{}: number +pub fn interrupts_info() -> String { + let interrupts = INTERRUPT_RECORD.lock(); + let mut res = String::new(); + interrupts.iter().for_each(|(irq, value)| { + res.push_str(&format!("{}: {}\r\n", irq, value)); + }); + res +} diff --git a/subsystems/ksync/Cargo.toml b/subsystems/ksync/Cargo.toml new file mode 100644 index 00000000..6a9a9f08 --- /dev/null +++ b/subsystems/ksync/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "ksync" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +config = { path = "../config" } +arch = { path = "../arch" } +kernel-sync = { git = "https://github.com/os-module/kernel-sync.git" } diff --git a/kernel/src/ksync.rs b/subsystems/ksync/src/lib.rs similarity index 83% rename from kernel/src/ksync.rs rename to subsystems/ksync/src/lib.rs index 8583dd43..464839b7 100644 --- a/kernel/src/ksync.rs +++ b/subsystems/ksync/src/lib.rs @@ -1,84 +1,85 @@ -use kernel_sync::{LockAction, ticket::TicketMutexGuard}; -use core::cell::{RefCell, RefMut}; -use crate::arch::{hart_id, interrupt_disable, interrupt_enable, is_interrupt_enable}; -use crate::config::CPU_NUM; - - -pub type SpinMutex = kernel_sync::spin::SpinMutex; -pub type TicketMutex = kernel_sync::ticket::TicketMutex; -pub type RwLock = kernel_sync::RwLock; -pub type Mutex = TicketMutex; -pub type MutexGuard<'a, T> = TicketMutexGuard<'a, T, KernelLockAction>; - -#[derive(Debug, Default, Clone, Copy)] -#[repr(align(64))] -pub struct Cpu { - pub noff: i32, // Depth of push_off() nesting. - pub interrupt_enable: bool, // Were interrupts enabled before push_off()? -} - -impl Cpu { - const fn new() -> Self { - Self { - noff: 0, - interrupt_enable: false, - } - } -} - -pub struct SafeRefCell(RefCell); - -/// # Safety: Only the corresponding cpu will access it. -unsafe impl Sync for SafeRefCell {} - -impl SafeRefCell { - const fn new(t: T) -> Self { - Self(RefCell::new(t)) - } -} - -#[allow(clippy::declare_interior_mutable_const)] -const DEFAULT_CPU: SafeRefCell = SafeRefCell::new(Cpu::new()); - -static CPUS: [SafeRefCell; CPU_NUM] = [DEFAULT_CPU; CPU_NUM]; - -pub fn mycpu() -> RefMut<'static, Cpu> { - CPUS[hart_id()].0.borrow_mut() -} - -// push_off/pop_off are like intr_off()/intr_on() except that they are matched: -// it takes two pop_off()s to undo two push_off()s. Also, if interrupts -// are initially off, then push_off, pop_off leaves them off. -pub(crate) fn push_off() { - let old = is_interrupt_enable(); - interrupt_disable(); - let mut cpu = mycpu(); - if cpu.noff == 0 { - cpu.interrupt_enable = old; - } - cpu.noff += 1; -} - -pub(crate) fn pop_off() { - let mut cpu = mycpu(); - if is_interrupt_enable() || cpu.noff < 1 { - panic!("pop_off"); - } - cpu.noff -= 1; - let should_enable = cpu.noff == 0 && cpu.interrupt_enable; - drop(cpu); - // NOTICE: intr_on() may lead to an immediate inerrupt, so we *MUST* drop(cpu) in advance. - if should_enable { - interrupt_enable(); - } -} - -pub struct KernelLockAction; -impl LockAction for KernelLockAction { - fn before_lock() { - push_off(); - } - fn after_lock() { - pop_off(); - } -} +#![no_std] + +use arch::{hart_id, interrupt_disable, interrupt_enable, is_interrupt_enable}; +use config::CPU_NUM; +use core::cell::{RefCell, RefMut}; +use kernel_sync::{ticket::TicketMutexGuard, LockAction}; + +pub type SpinMutex = kernel_sync::spin::SpinMutex; +pub type TicketMutex = kernel_sync::ticket::TicketMutex; +pub type RwLock = kernel_sync::RwLock; +pub type Mutex = TicketMutex; +pub type MutexGuard<'a, T> = TicketMutexGuard<'a, T, KernelLockAction>; + +#[derive(Debug, Default, Clone, Copy)] +#[repr(align(64))] +pub struct Cpu { + pub noff: i32, // Depth of push_off() nesting. + pub interrupt_enable: bool, // Were interrupts enabled before push_off()? +} + +impl Cpu { + const fn new() -> Self { + Self { + noff: 0, + interrupt_enable: false, + } + } +} + +pub struct SafeRefCell(RefCell); + +/// # Safety: Only the corresponding cpu will access it. +unsafe impl Sync for SafeRefCell {} + +impl SafeRefCell { + const fn new(t: T) -> Self { + Self(RefCell::new(t)) + } +} + +#[allow(clippy::declare_interior_mutable_const)] +const DEFAULT_CPU: SafeRefCell = SafeRefCell::new(Cpu::new()); + +static CPUS: [SafeRefCell; CPU_NUM] = [DEFAULT_CPU; CPU_NUM]; + +pub fn mycpu() -> RefMut<'static, Cpu> { + CPUS[hart_id()].0.borrow_mut() +} + +// push_off/pop_off are like intr_off()/intr_on() except that they are matched: +// it takes two pop_off()s to undo two push_off()s. Also, if interrupts +// are initially off, then push_off, pop_off leaves them off. +pub(crate) fn push_off() { + let old = is_interrupt_enable(); + interrupt_disable(); + let mut cpu = mycpu(); + if cpu.noff == 0 { + cpu.interrupt_enable = old; + } + cpu.noff += 1; +} + +pub(crate) fn pop_off() { + let mut cpu = mycpu(); + if is_interrupt_enable() || cpu.noff < 1 { + panic!("pop_off"); + } + cpu.noff -= 1; + let should_enable = cpu.noff == 0 && cpu.interrupt_enable; + drop(cpu); + // NOTICE: intr_on() may lead to an immediate inerrupt, so we *MUST* drop(cpu) in advance. + if should_enable { + interrupt_enable(); + } +} + +pub struct KernelLockAction; +impl LockAction for KernelLockAction { + fn before_lock() { + push_off(); + } + fn after_lock() { + pop_off(); + } +} diff --git a/subsystems/mem/Cargo.toml b/subsystems/mem/Cargo.toml new file mode 100644 index 00000000..fe5ff36e --- /dev/null +++ b/subsystems/mem/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "mem" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +config = {path = "../config" } +arch = {path = "../arch" } +ksync = { path = "../ksync" } +pager = { git = "https://github.com/os-module/pager", default-features = false, optional = true } +platform = { path = "../platform" } +log = "0" +talc = { version = "1.0", optional = true } +buddy_system_allocator = { version = "0.9.0", optional = true } +rslab = { version = "0.2.1", optional = true } + +spin = "0" + +page-table = { git = "https://github.com/os-module/page-table.git", branch = "dev" } + +page_table = { git = "https://github.com/rcore-os/arceos",rev = "7eeebc5" } +memory_addr = { git = "https://github.com/rcore-os/arceos",rev = "7eeebc5" } + + + +[features] +default = ["pager_buddy","talloc"] +pager_buddy = ["pager/buddy"] +pager_bitmap = ["pager/bitmap"] +slab = ["rslab"] +talloc = ["talc"] +buddy = ["buddy_system_allocator"] \ No newline at end of file diff --git a/subsystems/mem/src/frame.rs b/subsystems/mem/src/frame.rs new file mode 100644 index 00000000..58576bc7 --- /dev/null +++ b/subsystems/mem/src/frame.rs @@ -0,0 +1,63 @@ +use alloc::format; +use config::{FRAME_BITS, FRAME_SIZE}; +use ksync::Mutex; +use page_table::PagingIf; +use pager::{PageAllocator, PageAllocatorExt}; +use platform::println; + +#[cfg(feature = "pager_bitmap")] +pub static FRAME_ALLOCATOR: Mutex> = Mutex::new(pager::Bitmap::new()); +#[cfg(feature = "pager_buddy")] +pub static FRAME_ALLOCATOR: Mutex> = Mutex::new(pager::Zone::new()); + +pub fn init_frame_allocator(start: usize, end: usize) { + let page_start = start / FRAME_SIZE; + let page_end = end / FRAME_SIZE; + let page_count = page_end - page_start; + println!( + "Page start:{:#x},end:{:#x},count:{:#x}", + page_start, page_end, page_count + ); + FRAME_ALLOCATOR + .lock() + .init(start..end) + .expect("init frame allocator failed"); +} + +#[no_mangle] +pub fn alloc_frames(num: usize) -> *mut u8 { + assert_eq!(num.next_power_of_two(), num); + let start_page = FRAME_ALLOCATOR + .lock() + .alloc_pages(num, FRAME_SIZE) + .expect(format!("alloc {} frame failed", num).as_str()); + let start_addr = start_page << FRAME_BITS; + start_addr as *mut u8 +} + +#[no_mangle] +pub fn free_frames(addr: *mut u8, num: usize) { + assert_eq!(num.next_power_of_two(), num); + let start = addr as usize >> FRAME_BITS; + FRAME_ALLOCATOR + .lock() + .free_pages(start, num) + .expect(format!("free frame start:{:#x},num:{} failed", start, num).as_str()); +} + +pub struct VmmPageAllocator; + +impl PagingIf for VmmPageAllocator { + fn alloc_frame() -> Option { + let start_addr = alloc_frames(1); + Some(memory_addr::PhysAddr::from(start_addr as usize)) + } + + fn dealloc_frame(paddr: memory_addr::PhysAddr) { + free_frames(paddr.as_usize() as *mut u8, 1); + } + + fn phys_to_virt(paddr: memory_addr::PhysAddr) -> memory_addr::VirtAddr { + memory_addr::VirtAddr::from(paddr.as_usize()) + } +} diff --git a/subsystems/mem/src/heap.rs b/subsystems/mem/src/heap.rs new file mode 100644 index 00000000..8aa2c719 --- /dev/null +++ b/subsystems/mem/src/heap.rs @@ -0,0 +1,71 @@ +use crate::frame::{alloc_frames, free_frames}; +#[cfg(feature = "buddy")] +use buddy_system_allocator::LockedHeap; +use config::FRAME_SIZE; +use core::alloc::GlobalAlloc; +use ksync::Mutex; +use log::trace; +#[cfg(feature = "rslab")] +use rslab::{init_slab_system, SlabAllocator}; +#[cfg(feature = "talloc")] +use talc::{Talc, Talck}; + +pub struct HeapAllocator { + #[cfg(feature = "talloc")] + allocator: Mutex, + #[cfg(feature = "buddy")] + allocator: Mutex>, + #[cfg(feature = "slab")] + allocator: Mutex, +} + +unsafe impl GlobalAlloc for HeapAllocator { + unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { + if layout.size() >= 5 * 1024 * 1024 { + let need_page = (layout.size() + FRAME_SIZE - 1) / FRAME_SIZE; + trace!("alloc big page: {:#x}", layout.size()); + alloc_frames(need_page) + } else { + self.allocator.lock().alloc(layout) + } + } + unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { + if layout.size() >= 5 * 1024 * 1024 { + let need_page = (layout.size() + FRAME_SIZE - 1) / FRAME_SIZE; + trace!("free big page: {:#x}", layout.size()); + free_frames(ptr, need_page); + } else { + self.allocator.lock().dealloc(ptr, layout); + } + } +} + +impl HeapAllocator { + pub const fn new() -> Self { + Self { + #[cfg(feature = "talloc")] + allocator: Mutex::new(Talc::new().spin_lock()), + #[cfg(feature = "buddy")] + allocator: Mutex::new(LockedHeap::<32>::new()), + #[cfg(feature = "slab")] + allocator: Mutex::new(SlabAllocator), + } + } + pub fn init(&self, heap: &mut [u8]) { + #[cfg(feature = "talloc")] + unsafe { + self.allocator.lock().talc().init(heap.into()) + } + #[cfg(feature = "buddy")] + unsafe { + self.allocator + .lock() + .lock() + .init(heap.as_mut_ptr() as usize, heap.len()) + } + #[cfg(feature = "slab")] + unsafe { + init_slab_system(FRAME_SIZE, 64); + } + } +} diff --git a/subsystems/mem/src/lib.rs b/subsystems/mem/src/lib.rs new file mode 100644 index 00000000..2ce23641 --- /dev/null +++ b/subsystems/mem/src/lib.rs @@ -0,0 +1,45 @@ +#![no_std] + +extern crate alloc; + +use arch::activate_paging_mode; +use config::{FRAME_BITS, KERNEL_HEAP_SIZE}; +use heap::HeapAllocator; + +mod frame; +mod heap; +mod vmm; + +pub use frame::{alloc_frames, free_frames}; + +#[global_allocator] +static HEAP_ALLOCATOR: HeapAllocator = HeapAllocator::new(); + +#[cfg(any(feature = "talloc", feature = "buddy"))] +static mut KERNEL_HEAP: [u8; KERNEL_HEAP_SIZE] = [0; KERNEL_HEAP_SIZE]; + +pub fn init_memory_system(memory_start: usize, memory_end: usize, is_first_cpu: bool) { + if is_first_cpu { + frame::init_frame_allocator(memory_start, memory_end); + println!("Frame allocator init success"); + HEAP_ALLOCATOR.init(unsafe { &mut KERNEL_HEAP }); + #[cfg(feature = "talloc")] + { + println!("Talloc allocator init success"); + } + #[cfg(feature = "slab")] + { + println!("Slab allocator init success"); + } + #[cfg(feature = "buddy")] + { + println!("Buddy allocator init success"); + } + vmm::build_kernel_address_space(memory_end); + println!("Build kernel address space success"); + activate_paging_mode(vmm::kernel_pgd() >> FRAME_BITS); + println!("Activate paging mode success"); + } else { + activate_paging_mode(vmm::kernel_pgd() >> FRAME_BITS); + } +} diff --git a/subsystems/mem/src/vmm.rs b/subsystems/mem/src/vmm.rs new file mode 100644 index 00000000..42cf671f --- /dev/null +++ b/subsystems/mem/src/vmm.rs @@ -0,0 +1,18 @@ +#[allow(unused)] +extern "C" { + fn stext(); + fn srodata(); + fn sdata(); + fn sbss(); + fn ekernel(); + fn strampoline(); + fn sinit(); + fn einit(); + + // fn kernel_eh_frame(); + // fn kernel_eh_frame_end(); + // fn kernel_eh_frame_hdr(); + // fn kernel_eh_frame_hdr_end(); +} + +pub fn build_kernel_address_space(memory_end: usize) {} diff --git a/subsystems/platform/Cargo.toml b/subsystems/platform/Cargo.toml new file mode 100644 index 00000000..e0ff57b5 --- /dev/null +++ b/subsystems/platform/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "platform" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log = "0" +arch = { path = "../arch" } +config = { path = "../config" } +ksync = { path = "../ksync" } + + + +[features] +default = ["qemu_riscv"] + +qemu_riscv = [] +starfive2_riscv = [] +hifive_riscv = [] \ No newline at end of file diff --git a/subsystems/platform/src/common_riscv/boot.rs b/subsystems/platform/src/common_riscv/boot.rs new file mode 100644 index 00000000..86f2ab50 --- /dev/null +++ b/subsystems/platform/src/common_riscv/boot.rs @@ -0,0 +1,45 @@ +use config::{CPU_NUM, STACK_SIZE}; +use core::arch::asm; + +#[link_section = ".bss.stack"] +static mut STACK: [u8; STACK_SIZE * CPU_NUM] = [0; STACK_SIZE * CPU_NUM]; + +/// 内核入口 +/// +/// 用于初始化内核的栈空间,并关闭中断 +#[naked] +#[no_mangle] +#[link_section = ".text.entry"] +extern "C" fn _start() { + unsafe { + asm!("\ + mv tp, a0 + mv gp, a1 + add t0, a0, 1 + slli t0, t0, 16 + la sp, {boot_stack} + add sp, sp, t0 + call clear_bss + mv a0, tp + mv a1, gp + call main + ", + boot_stack = sym STACK, + options(noreturn) + ); + } +} + +extern "C" { + fn sbss(); + fn ebss(); +} + +/// 清空.bss段 +#[no_mangle] +fn clear_bss() { + unsafe { + core::slice::from_raw_parts_mut(sbss as usize as *mut u8, ebss as usize - sbss as usize) + .fill(0); + } +} diff --git a/subsystems/platform/src/common_riscv/mod.rs b/subsystems/platform/src/common_riscv/mod.rs new file mode 100644 index 00000000..6823140c --- /dev/null +++ b/subsystems/platform/src/common_riscv/mod.rs @@ -0,0 +1,2 @@ +pub mod boot; +pub mod sbi; diff --git a/subsystems/platform/src/common_riscv/sbi.rs b/subsystems/platform/src/common_riscv/sbi.rs new file mode 100644 index 00000000..39458c76 --- /dev/null +++ b/subsystems/platform/src/common_riscv/sbi.rs @@ -0,0 +1,123 @@ +//! SBI 调用接口 +use core::arch::asm; + +/// 设置定时器 +const SBI_SET_TIMER: usize = 0; +/// 控制台输出 +const SBI_CONSOLE_PUT_CHAR: usize = 1; +/// 控制台输入 +const SBI_CONSOLE_GET_CHAR: usize = 2; +// const SBI_CLEAR_IPI: usize = 3; +/// 发送 IPI +const SBI_SEND_IPI: usize = 4; +// const SBI_REMOTE_FENCE_I: usize = 5; +// const SBI_REMOTE_SFENCE_VMA: usize = 6; +// const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7; +/// 关闭机器 +const SBI_SHUTDOWN: usize = 8; + +/// SBI 调用 +/// +/// sbi规范定义了调用的参数传递方法 +fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> i32 { + let mut ret; + unsafe { + asm!("ecall", + in("a7") which, + inlateout("a0") arg0 as i32 => ret, + in("a1") arg1, + in("a2") arg2); + } + ret +} + +/// 设置定时器 +pub fn set_timer(time: usize) { + sbi_call(SBI_SET_TIMER, time, 0, 0); +} + +pub fn system_shutdown() -> ! { + sbi_call(SBI_SHUTDOWN, 0, 0, 0); + loop {} +} + +/// Warp sbi SBI_CONSOLE_PUT_CHAR call +pub fn console_putchar(ch: u8) { + sbi_call(SBI_CONSOLE_PUT_CHAR, ch as usize, 0, 0); +} + +/// Warp sbi SBI_CONSOLE_GET_CHAR call +#[allow(unused)] +pub fn console_getchar() -> char { + sbi_call(SBI_CONSOLE_GET_CHAR, 0, 0, 0) as u8 as char +} + +/// sbi调用返回值 +#[repr(C)] +#[derive(Debug)] +pub struct SbiRet { + /// Error number + pub error: isize, + /// Result value + pub value: isize, +} + +/// SBI 基本扩展 +pub const EXTENSION_BASE: usize = 0x10; +/// SBI 时钟扩展 +pub const EXTENSION_TIMER: usize = 0x54494D45; +// pub const EXTENSION_IPI: usize = 0x735049; +// pub const EXTENSION_RFENCE: usize = 0x52464E43; +/// SBI HSM 扩展 +pub const EXTENSION_HSM: usize = 0x48534D; +// pub const EXTENSION_SRST: usize = 0x53525354; + +/// SBI HSM扩展的启动cpu功能 +const FUNCTION_HSM_HART_START: usize = 0x0; +// const FUNCTION_HSM_HART_STOP: usize = 0x1; +// const FUNCTION_HSM_HART_GET_STATUS: usize = 0x2; +const FUNCTION_HSM_HART_SUSPEND: usize = 0x3; + +/// 第三种类型的SBI调用 +/// +/// 可以传递更多参数 +#[inline(always)] +fn sbi_call_3(extension: usize, function: usize, arg0: usize, arg1: usize, arg2: usize) -> SbiRet { + let (error, value); + unsafe { + asm!( + "ecall", + in("a0") arg0, in("a1") arg1, in("a2") arg2, + in("a6") function, in("a7") extension, + lateout("a0") error, lateout("a1") value, + ) + } + SbiRet { error, value } +} + +pub fn hart_suspend(suspend_type: u32, resume_addr: usize, opaque: usize) -> SbiRet { + sbi_call_3( + EXTENSION_HSM, + FUNCTION_HSM_HART_SUSPEND, + suspend_type as usize, + resume_addr, + opaque, + ) +} + +/// wrap sbi FUNCTION_HSM_HART_START call +pub fn hart_start(hart_id: usize, start_addr: usize, opaque: usize) -> SbiRet { + sbi_call_3( + EXTENSION_HSM, + FUNCTION_HSM_HART_START, + hart_id, + start_addr, + opaque, + ) +} + +/// wrap sbi SBI_SEND_IPI call +#[allow(unused)] +pub fn send_ipi(ptr: usize) { + sbi_call(SBI_SEND_IPI, ptr, 0, 0); +} diff --git a/subsystems/platform/src/console.rs b/subsystems/platform/src/console.rs new file mode 100644 index 00000000..7161e341 --- /dev/null +++ b/subsystems/platform/src/console.rs @@ -0,0 +1,42 @@ +use core::fmt::{Arguments, Result, Write}; +#[macro_export] +macro_rules! xprint { + ($($arg:tt)*) => { + let hard_id = arch::hart_id(); + $crate::console::__print(format_args!("[{}] {}", hard_id, format_args!($($arg)*))) + }; +} + +#[macro_export] +macro_rules! xprintln { + () => ($crate::print!("\n")); + ($fmt:expr) => ($crate::print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => ($crate::print!( + concat!($fmt, "\n"), $($arg)*)); +} + +pub struct Stdout; + +/// 对`Stdout`实现输出的Trait +impl Write for Stdout { + fn write_str(&mut self, s: &str) -> Result { + s.as_bytes().iter().for_each(|x| { + crate::console_putchar(*x); + }); + Ok(()) + } +} + +/// 输出函数 +/// 对参数进行输出 主要使用在输出相关的宏中 如println +#[doc(hidden)] +pub fn __print(args: Arguments) { + Stdout.write_fmt(args).unwrap(); +} + +/// 系统启动初期使用的输出函数 +/// +/// 在riscv平台上,由于没有实现串口驱动,所以在系统启动初期使用SBI进行输出 +pub fn early_console_write(s: &str) { + Stdout.write_str(s).unwrap(); +} diff --git a/subsystems/platform/src/hifive_riscv/mod.rs b/subsystems/platform/src/hifive_riscv/mod.rs new file mode 100644 index 00000000..5493eea0 --- /dev/null +++ b/subsystems/platform/src/hifive_riscv/mod.rs @@ -0,0 +1,37 @@ +use core::iter::Once; + +#[repr(align(4))] +struct Wrapper(T); + +const FDT: &[u8] = &Wrapper(*include_bytes!( + "../../../../tools/hifive-unmatched-a00.dtb" +)) +.0; + +pub static DTB: Once = Once::new(); + +pub fn init_dtb(dtb: Option) { + let dtb_ptr = dtb.unwrap_or(FDT.as_ptr() as usize); + DTB.call_once(|| dtb_ptr); +} + +/// 设置定时器 +pub fn set_timer(time: usize) { + crate::common_riscv::sbi::set_timer(time); +} + +pub fn system_shutdown() -> ! { + crate::common_riscv::sbi::system_shutdown(); + loop {} +} + +/// Warp sbi SBI_CONSOLE_PUT_CHAR call +pub fn console_putchar(ch: u8) { + crate::common_riscv::sbi::console_putchar(ch); +} + +/// Warp sbi SBI_CONSOLE_GET_CHAR call +#[allow(unused)] +pub fn console_getchar() -> char { + crate::common_riscv::sbi::console_getchar() +} diff --git a/subsystems/platform/src/lib.rs b/subsystems/platform/src/lib.rs new file mode 100644 index 00000000..a1cfe7a5 --- /dev/null +++ b/subsystems/platform/src/lib.rs @@ -0,0 +1,50 @@ +#![no_std] +#![feature(naked_functions)] + +extern crate alloc; + +#[macro_use] +pub mod console; +mod common_riscv; +#[cfg(feature = "hifive_riscv")] +mod hifive_riscv; +mod logger; +#[cfg(feature = "qemu_riscv")] +mod qemu_riscv; +#[cfg(feature = "starfive2_riscv")] +mod starfive2_riscv; + +#[cfg(feature = "qemu_riscv")] +use qemu_riscv::console_putchar; +#[cfg(feature = "qemu_riscv")] +pub use qemu_riscv::system_shutdown; + +#[cfg(feature = "starfive2_riscv")] +use starfive2_riscv::console_putchar; +#[cfg(feature = "starfive2_riscv")] +pub use starfive2_riscv::system_shutdown; + +#[cfg(feature = "hifive_riscv")] +pub use hifive_riscv::system_shutdown; + +#[cfg(feature = "hifive_riscv")] +pub use hifive_riscv::console_putchar; + +pub fn platform_init(dtb: Option) { + #[cfg(feature = "hifive_riscv")] + hifive_riscv::init_dtb(dtb); + #[cfg(feature = "starfive2_riscv")] + starfive2_riscv::init_dtb(dtb); + #[cfg(feature = "qemu_riscv")] + qemu_riscv::init_dtb(dtb); + logger::init_logger(); +} + +pub fn platform_dtb_ptr() -> usize { + #[cfg(feature = "hifive_riscv")] + return hifive_riscv::DTB.get().unwrap(); + #[cfg(feature = "starfive2_riscv")] + return starfive2_riscv::DTB.get().unwrap(); + #[cfg(feature = "qemu_riscv")] + return qemu_riscv::DTB.get().unwrap(); +} diff --git a/subsystems/platform/src/logger.rs b/subsystems/platform/src/logger.rs new file mode 100644 index 00000000..5be30879 --- /dev/null +++ b/subsystems/platform/src/logger.rs @@ -0,0 +1,41 @@ +use crate::xprintln; +use log::{self, Level, LevelFilter, Log, Metadata, Record}; +struct SimpleLogger; + +impl Log for SimpleLogger { + fn enabled(&self, _metadata: &Metadata) -> bool { + true + } + fn log(&self, record: &Record) { + if !self.enabled(record.metadata()) { + return; + } + let color = match record.level() { + Level::Error => 31, // Red + Level::Warn => 93, // BrightYellow + Level::Info => 35, // Blue + Level::Debug => 32, // Green + Level::Trace => 90, // BrightBlack + }; + xprintln!( + "\u{1B}[{}m[{:>1}] {}\u{1B}[0m", + color, + record.level(), + record.args(), + ); + } + fn flush(&self) {} +} + +pub fn init_logger() { + xprintln!("Init logger {:?}", option_env!("LOG")); + log::set_logger(&SimpleLogger).unwrap(); + log::set_max_level(match option_env!("LOG") { + Some("ERROR") => LevelFilter::Error, + Some("WARN") => LevelFilter::Warn, + Some("INFO") => LevelFilter::Info, + Some("DEBUG") => LevelFilter::Debug, + Some("TRACE") => LevelFilter::Trace, + _ => LevelFilter::Off, + }); +} diff --git a/subsystems/platform/src/qemu_riscv/mod.rs b/subsystems/platform/src/qemu_riscv/mod.rs new file mode 100644 index 00000000..7ba465c1 --- /dev/null +++ b/subsystems/platform/src/qemu_riscv/mod.rs @@ -0,0 +1,29 @@ +use core::iter::Once; + +pub static DTB: Once = Once::new(); + +pub fn init_dtb(dtb: Option) { + let dtb_ptr = dtb.expect("No dtb found"); + DTB.call_once(|| dtb_ptr); +} + +/// 设置定时器 +pub fn set_timer(time: usize) { + crate::common_riscv::sbi::set_timer(time); +} + +pub fn system_shutdown() -> ! { + crate::common_riscv::sbi::system_shutdown(); + loop {} +} + +/// Warp sbi SBI_CONSOLE_PUT_CHAR call +pub fn console_putchar(ch: u8) { + crate::common_riscv::sbi::console_putchar(ch); +} + +/// Warp sbi SBI_CONSOLE_GET_CHAR call +#[allow(unused)] +pub fn console_getchar() -> char { + crate::common_riscv::sbi::console_getchar() +} diff --git a/subsystems/platform/src/starfive2_riscv/mod.rs b/subsystems/platform/src/starfive2_riscv/mod.rs new file mode 100644 index 00000000..f0fab6c2 --- /dev/null +++ b/subsystems/platform/src/starfive2_riscv/mod.rs @@ -0,0 +1,37 @@ +use core::iter::Once; + +#[repr(align(4))] +struct Wrapper(T); + +pub const FDT: &[u8] = &Wrapper(*include_bytes!( + "../../../../tools/jh7110-visionfive-v2.dtb" +)) +.0; + +pub static DTB: Once = Once::new(); + +pub fn init_dtb(dtb: Option) { + let dtb_ptr = dtb.unwrap_or(FDT.as_ptr() as usize); + DTB.call_once(|| dtb_ptr); +} + +/// 设置定时器 +pub fn set_timer(time: usize) { + crate::common_riscv::sbi::set_timer(time); +} + +pub fn system_shutdown() -> ! { + crate::common_riscv::sbi::system_shutdown(); + loop {} +} + +/// Warp sbi SBI_CONSOLE_PUT_CHAR call +pub fn console_putchar(ch: u8) { + crate::common_riscv::sbi::console_putchar(ch); +} + +/// Warp sbi SBI_CONSOLE_GET_CHAR call +#[allow(unused)] +pub fn console_getchar() -> char { + crate::common_riscv::sbi::console_getchar() +} From 5b9e9471f040a887907d845227e984d84762cfa9 Mon Sep 17 00:00:00 2001 From: Godones <1925466036@qq.com> Date: Mon, 15 Jan 2024 23:48:42 +0800 Subject: [PATCH 2/5] feat: New subsystem division --- .gitignore | 8 +- Cargo.lock | 109 +- Cargo.toml | 17 +- Makefile | 10 +- boot/src/main.rs | 4 +- dep/basemachine/src/lib.rs | 66 +- docs/assert/boot.drawio.png | Bin 0 -> 22636 bytes docs/subsystem.md | 98 + kernel/Cargo.toml | 8 +- kernel/src/device/rtc.rs | 1 - kernel/src/ipc/shm.rs | 4 - kernel/src/memory/vmm.rs | 2 +- kernel/src/net/socket.rs | 4 - kernel/src/task/task.rs | 53 - kernel/src/timer/mod.rs | 2 +- kkernel/Cargo.toml | 56 + kkernel/build.rs | 32 + kkernel/src/fs/basic.rs | 714 ++ kkernel/src/fs/control.rs | 263 + kkernel/src/fs/ext.rs | 231 + kkernel/src/fs/file.rs | 278 + kkernel/src/fs/link.rs | 142 + kkernel/src/fs/mod.rs | 96 + kkernel/src/fs/poll.rs | 93 + kkernel/src/fs/select.rs | 220 + kkernel/src/fs/stdio.rs | 27 + kkernel/src/gui.rs | 34 + kkernel/src/ipc/futex.rs | 178 + kkernel/src/ipc/mod.rs | 262 + kkernel/src/ipc/pipe.rs | 387 + kkernel/src/ipc/shm.rs | 283 + kkernel/src/ipc/signal.rs | 404 + kkernel/src/main.rs | 71 + kkernel/src/mm/elf.rs | 150 + kkernel/src/mm/loader.rs | 395 + kkernel/src/mm/map.rs | 254 + kkernel/src/mm/mod.rs | 20 + kkernel/src/net/addr.rs | 125 + kkernel/src/net/mod.rs | 475 + kkernel/src/net/port.rs | 24 + kkernel/src/net/socket.rs | 469 + kkernel/src/net/unix.rs | 31 + kkernel/src/system.rs | 218 + kkernel/src/task/context.rs | 46 + kkernel/src/task/cpu.rs | 496 + kkernel/src/task/heap.rs | 59 + kkernel/src/task/mod.rs | 96 + kkernel/src/task/schedule.rs | 85 + kkernel/src/task/stack.rs | 33 + kkernel/src/task/switch.asm | 34 + kkernel/src/task/task.rs | 1813 +++ kkernel/src/time.rs | 269 + kkernel/src/trap/context.rs | 102 + kkernel/src/trap/exception.rs | 158 + kkernel/src/trap/interrupt.rs | 16 + kkernel/src/trap/kernel_v.asm | 47 + kkernel/src/trap/mod.rs | 309 + kkernel/src/trap/trampoline.asm | 83 + subsystems/arch/Cargo.toml | 4 - subsystems/config/Cargo.toml | 6 - subsystems/config/build.rs | 21 + subsystems/config/src/lib.rs | 62 - subsystems/constants/Cargo.toml | 2 +- subsystems/constants/src/lib.rs | 2 + subsystems/device_interface/src/lib.rs | 1 + subsystems/devices/Cargo.toml | 45 + subsystems/devices/src/block.rs | 72 + subsystems/devices/src/gpu.rs | 68 + subsystems/devices/src/input.rs | 84 + subsystems/devices/src/lib.rs | 408 + subsystems/devices/src/net.rs | 1 + subsystems/devices/src/prob.rs | 90 + subsystems/devices/src/rtc.rs | 121 + subsystems/devices/src/uart.rs | 167 + subsystems/drivers/Cargo.toml | 36 + subsystems/drivers/src/block_device.rs | 263 + subsystems/drivers/src/gpu.rs | 61 + subsystems/drivers/src/hal.rs | 28 + subsystems/drivers/src/input.rs | 108 + subsystems/drivers/src/lib.rs | 39 + subsystems/drivers/src/net.rs | 68 + subsystems/drivers/src/rtc.rs | 59 + subsystems/drivers/src/uart.rs | 176 + subsystems/interrupt/Cargo.toml | 1 + subsystems/interrupt/src/lib.rs | 9 +- subsystems/mem/Cargo.toml | 6 +- subsystems/mem/src/frame.rs | 92 +- subsystems/mem/src/heap.rs | 2 + subsystems/mem/src/lib.rs | 24 +- subsystems/mem/src/manager.rs | 54 + subsystems/mem/src/vmm.rs | 153 +- subsystems/platform/Cargo.toml | 9 +- subsystems/platform/src/common_riscv/boot.rs | 29 +- subsystems/platform/src/common_riscv/sbi.rs | 1 + subsystems/platform/src/console.rs | 30 +- .../platform/src/hifive_riscv/config.rs | 8 + subsystems/platform/src/hifive_riscv/mod.rs | 11 +- subsystems/platform/src/lib.rs | 100 +- .../platform/src/{logger.rs => logging.rs} | 83 +- subsystems/platform/src/qemu_riscv/config.rs | 14 + subsystems/platform/src/qemu_riscv/mod.rs | 5 +- .../platform/src/starfive2_riscv/config.rs | 11 + .../platform/src/starfive2_riscv/mod.rs | 11 +- subsystems/timer/Cargo.toml | 15 + subsystems/timer/src/lib.rs | 131 + subsystems/unwinder/Cargo.toml | 15 + subsystems/unwinder/build.rs | 22 + subsystems/unwinder/src/kernel_symbol.S | 9977 +++++++++++++++++ subsystems/unwinder/src/lib.rs | 4 + subsystems/unwinder/src/panic.rs | 93 + subsystems/unwinder/src/symbol.rs | 53 + subsystems/vfs/Cargo.toml | 27 + subsystems/vfs/src/dev/mod.rs | 253 + subsystems/vfs/src/dev/null.rs | 55 + subsystems/vfs/src/dev/random.rs | 59 + subsystems/vfs/src/lib.rs | 133 + subsystems/vfs/src/pipefs.rs | 20 + subsystems/vfs/src/proc/filesystem.rs | 68 + subsystems/vfs/src/proc/interrupt.rs | 47 + subsystems/vfs/src/proc/mem.rs | 87 + subsystems/vfs/src/proc/mod.rs | 52 + subsystems/vfs/src/proc/mounts.rs | 47 + subsystems/vfs/src/ram/mod.rs | 112 + subsystems/vfs/src/sys/mod.rs | 18 + 124 files changed, 23512 insertions(+), 385 deletions(-) create mode 100644 docs/assert/boot.drawio.png create mode 100644 docs/subsystem.md create mode 100644 kkernel/Cargo.toml create mode 100644 kkernel/build.rs create mode 100644 kkernel/src/fs/basic.rs create mode 100644 kkernel/src/fs/control.rs create mode 100644 kkernel/src/fs/ext.rs create mode 100644 kkernel/src/fs/file.rs create mode 100644 kkernel/src/fs/link.rs create mode 100644 kkernel/src/fs/mod.rs create mode 100644 kkernel/src/fs/poll.rs create mode 100644 kkernel/src/fs/select.rs create mode 100644 kkernel/src/fs/stdio.rs create mode 100644 kkernel/src/gui.rs create mode 100644 kkernel/src/ipc/futex.rs create mode 100644 kkernel/src/ipc/mod.rs create mode 100644 kkernel/src/ipc/pipe.rs create mode 100644 kkernel/src/ipc/shm.rs create mode 100644 kkernel/src/ipc/signal.rs create mode 100644 kkernel/src/main.rs create mode 100644 kkernel/src/mm/elf.rs create mode 100644 kkernel/src/mm/loader.rs create mode 100644 kkernel/src/mm/map.rs create mode 100644 kkernel/src/mm/mod.rs create mode 100644 kkernel/src/net/addr.rs create mode 100644 kkernel/src/net/mod.rs create mode 100644 kkernel/src/net/port.rs create mode 100644 kkernel/src/net/socket.rs create mode 100644 kkernel/src/net/unix.rs create mode 100644 kkernel/src/system.rs create mode 100644 kkernel/src/task/context.rs create mode 100644 kkernel/src/task/cpu.rs create mode 100644 kkernel/src/task/heap.rs create mode 100644 kkernel/src/task/mod.rs create mode 100644 kkernel/src/task/schedule.rs create mode 100644 kkernel/src/task/stack.rs create mode 100644 kkernel/src/task/switch.asm create mode 100644 kkernel/src/task/task.rs create mode 100644 kkernel/src/time.rs create mode 100644 kkernel/src/trap/context.rs create mode 100644 kkernel/src/trap/exception.rs create mode 100644 kkernel/src/trap/interrupt.rs create mode 100644 kkernel/src/trap/kernel_v.asm create mode 100644 kkernel/src/trap/mod.rs create mode 100644 kkernel/src/trap/trampoline.asm create mode 100644 subsystems/config/build.rs create mode 100644 subsystems/devices/Cargo.toml create mode 100644 subsystems/devices/src/block.rs create mode 100644 subsystems/devices/src/gpu.rs create mode 100644 subsystems/devices/src/input.rs create mode 100644 subsystems/devices/src/lib.rs create mode 100644 subsystems/devices/src/net.rs create mode 100644 subsystems/devices/src/prob.rs create mode 100644 subsystems/devices/src/rtc.rs create mode 100644 subsystems/devices/src/uart.rs create mode 100644 subsystems/drivers/Cargo.toml create mode 100644 subsystems/drivers/src/block_device.rs create mode 100644 subsystems/drivers/src/gpu.rs create mode 100644 subsystems/drivers/src/hal.rs create mode 100644 subsystems/drivers/src/input.rs create mode 100644 subsystems/drivers/src/lib.rs create mode 100644 subsystems/drivers/src/net.rs create mode 100644 subsystems/drivers/src/rtc.rs create mode 100644 subsystems/drivers/src/uart.rs create mode 100644 subsystems/mem/src/manager.rs create mode 100644 subsystems/platform/src/hifive_riscv/config.rs rename subsystems/platform/src/{logger.rs => logging.rs} (89%) create mode 100644 subsystems/platform/src/qemu_riscv/config.rs create mode 100644 subsystems/platform/src/starfive2_riscv/config.rs create mode 100644 subsystems/timer/Cargo.toml create mode 100644 subsystems/timer/src/lib.rs create mode 100644 subsystems/unwinder/Cargo.toml create mode 100644 subsystems/unwinder/build.rs create mode 100644 subsystems/unwinder/src/kernel_symbol.S create mode 100644 subsystems/unwinder/src/lib.rs create mode 100644 subsystems/unwinder/src/panic.rs create mode 100644 subsystems/unwinder/src/symbol.rs create mode 100644 subsystems/vfs/Cargo.toml create mode 100644 subsystems/vfs/src/dev/mod.rs create mode 100644 subsystems/vfs/src/dev/null.rs create mode 100644 subsystems/vfs/src/dev/random.rs create mode 100644 subsystems/vfs/src/lib.rs create mode 100644 subsystems/vfs/src/pipefs.rs create mode 100644 subsystems/vfs/src/proc/filesystem.rs create mode 100644 subsystems/vfs/src/proc/interrupt.rs create mode 100644 subsystems/vfs/src/proc/mem.rs create mode 100644 subsystems/vfs/src/proc/mod.rs create mode 100644 subsystems/vfs/src/proc/mounts.rs create mode 100644 subsystems/vfs/src/ram/mod.rs create mode 100644 subsystems/vfs/src/sys/mod.rs diff --git a/.gitignore b/.gitignore index f2f0c937..b45e9406 100644 --- a/.gitignore +++ b/.gitignore @@ -40,7 +40,7 @@ rust tests/testsuits-for-oskernel -subsystems/devices -subsystems/drivers -subsystems/vfs -subsystems/timer \ No newline at end of file +#subsystems/devices +#subsystems/drivers +#subsystems/vfs +#subsystems/timer \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index b4f5e9a1..f01a1655 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,15 +13,6 @@ dependencies = [ "talc 2.1.0", ] -[[package]] -name = "aarch64-cpu" -version = "9.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac42a04a61c19fc8196dd728022a784baecc5d63d7e256c01ad1b3fbfab26287" -dependencies = [ - "tock-registers", -] - [[package]] name = "adler" version = "1.0.2" @@ -77,7 +68,6 @@ dependencies = [ name = "arch" version = "0.1.0" dependencies = [ - "config", "riscv", ] @@ -669,11 +659,13 @@ dependencies = [ name = "devices" version = "0.1.0" dependencies = [ + "arch", "config", "constants", "device_interface", "drivers", "fdt 0.2.0-alpha1", + "interrupt", "ksync", "log", "netcore", @@ -721,13 +713,16 @@ dependencies = [ "config", "constants", "device_interface", + "downcast-rs", "ksync", "log", "loopback", "lru", "mem", "netcore", + "platform", "rtc", + "spin", "timer", "uart16550", "uart8250", @@ -1434,6 +1429,7 @@ dependencies = [ "config", "device_interface", "ksync", + "platform", "plic", "spin", ] @@ -1550,6 +1546,37 @@ dependencies = [ "lock_api", ] +[[package]] +name = "kkernel" +version = "0.1.0" +dependencies = [ + "arch", + "bit_field", + "bitflags 1.3.2", + "config", + "constants", + "devices", + "downcast-rs", + "drivers", + "gmanager", + "interrupt", + "ksync", + "log", + "mem", + "netcore", + "page-table", + "platform", + "riscv", + "smpscheduler", + "spin", + "syscall-table", + "timer", + "unwinder", + "vfs", + "vfscore", + "xmas-elf", +] + [[package]] name = "ksync" version = "0.1.0" @@ -1742,9 +1769,7 @@ dependencies = [ "config", "ksync", "log", - "memory_addr", "page-table", - "page_table", "pager", "platform", "rslab", @@ -1816,11 +1841,6 @@ dependencies = [ "virt2slint", ] -[[package]] -name = "memory_addr" -version = "0.1.0" -source = "git+https://github.com/rcore-os/arceos?rev=7eeebc5#7eeebc5581f3d1d6e8b03c6177c6cb34543ae50f" - [[package]] name = "micromath" version = "1.1.1" @@ -2130,27 +2150,6 @@ dependencies = [ "log", ] -[[package]] -name = "page_table" -version = "0.1.0" -source = "git+https://github.com/rcore-os/arceos?rev=7eeebc5#7eeebc5581f3d1d6e8b03c6177c6cb34543ae50f" -dependencies = [ - "log", - "memory_addr", - "page_table_entry", -] - -[[package]] -name = "page_table_entry" -version = "0.1.0" -source = "git+https://github.com/rcore-os/arceos?rev=7eeebc5#7eeebc5581f3d1d6e8b03c6177c6cb34543ae50f" -dependencies = [ - "aarch64-cpu", - "bitflags 2.4.0", - "memory_addr", - "x86_64", -] - [[package]] name = "pager" version = "0.1.0" @@ -2238,9 +2237,12 @@ name = "platform" version = "0.1.0" dependencies = [ "arch", + "basemachine", "config", "ksync", "log", + "preprint", + "spin", ] [[package]] @@ -3050,6 +3052,9 @@ version = "0.1.0" dependencies = [ "arch", "config", + "constants", + "platform", + "vfscore", ] [[package]] @@ -3115,12 +3120,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" -[[package]] -name = "tock-registers" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" - [[package]] name = "todo" version = "0.1.0" @@ -3295,6 +3294,15 @@ dependencies = [ "vfscore", ] +[[package]] +name = "unwinder" +version = "0.1.0" +dependencies = [ + "arch", + "platform", + "tracer", +] + [[package]] name = "url" version = "2.4.1" @@ -3392,6 +3400,7 @@ dependencies = [ "arch", "constants", "devfs", + "devices", "dynfs", "fat-vfs", "interrupt", @@ -3878,18 +3887,6 @@ dependencies = [ "nix", ] -[[package]] -name = "x86_64" -version = "0.14.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b835097a84e4457323331ec5d6eb23d096066cbfb215d54096dcb4b2e85f500" -dependencies = [ - "bit_field", - "bitflags 2.4.0", - "rustversion", - "volatile", -] - [[package]] name = "xmas-elf" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index c26eb0ae..4032dfb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,10 +29,23 @@ members = [ "subsystems/arch", "subsystems/config", "subsystems/ksync", - "subsystems/constants" -, "subsystems/mem", "subsystems/vfs", "subsystems/devices", "subsystems/drivers", "subsystems/interrupt", "subsystems/device_interface", "subsystems/timer"] + "subsystems/constants", + "subsystems/mem", + "subsystems/vfs", + "subsystems/devices", + "subsystems/drivers", + "subsystems/interrupt", + "subsystems/device_interface", + "subsystems/timer", + "kkernel" + , "subsystems/unwinder",] [profile.release] #lto = true #codegen-units = 1 + + + +[workspace.dependencies] +spin = "0" diff --git a/Makefile b/Makefile index 7f6582a2..0c910f33 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ TRACE_EXE := trace_exe TARGET := riscv64gc-unknown-none-elf -OUTPUT := target/$(TARGET)/release/ +OUTPUT := target/$(TARGET)/release KERNEL_FILE := $(OUTPUT)/boot DEBUG_FILE ?= $(KERNEL_FILE) KERNEL_ENTRY_PA := 0x80200000 @@ -90,7 +90,7 @@ else endif -build:install compile +build:install compile2 #compile compile: @@ -101,6 +101,12 @@ compile: @#$(OBJCOPY) $(KERNEL_FILE) --strip-all -O binary $(KERNEL_BIN) @cp $(KERNEL_FILE) ./kernel-qemu +compile2: + cargo build --release -p kkernel --target $(TARGET) --features $(FEATURES) + @(nm -n ${KERNEL_FILE} | $(TRACE_EXE) > subsystems/unwinder/src/kernel_symbol.S) + cargo build --release -p boot --target $(TARGET) --features $(FEATURES) + @cp $(OUTPUT)/kkernel ./kernel-qemu + trace_info: @(nm -n ${KERNEL_FILE} | $(TRACE_EXE) > kernel/src/trace/kernel_symbol.S) diff --git a/boot/src/main.rs b/boot/src/main.rs index dfe8f47a..66793715 100644 --- a/boot/src/main.rs +++ b/boot/src/main.rs @@ -105,11 +105,11 @@ pub fn main(_: usize, _: usize) -> ! { trap::init_trap_subsystem(); init_filesystem().expect("Init filesystem failed"); task::init_process(); + // register all syscall + init_init_array!(); CPUS.fetch_add(1, Ordering::Release); STARTED.store(true, Ordering::Relaxed); init_other_hart(hart_id()); - // register all syscall - init_init_array!(); } else { while !STARTED.load(Ordering::Relaxed) { spin_loop(); diff --git a/dep/basemachine/src/lib.rs b/dep/basemachine/src/lib.rs index b46f2173..8557b29e 100644 --- a/dep/basemachine/src/lib.rs +++ b/dep/basemachine/src/lib.rs @@ -14,11 +14,8 @@ use core::ops::Range; use fdt::Fdt; const MEMORY: &str = "memory"; -const SERIAL: &str = "serial"; -const UART: &str = "uart"; const PLIC: &str = "plic"; const CLINT: &str = "clint"; -const RTC: &str = "rtc"; /// Machine basic information #[derive(Clone)] @@ -29,16 +26,10 @@ pub struct MachineInfo { pub smp: usize, /// Memory range pub memory: Range, - /// UART information - pub uart: [UartInfo; 8], /// PLIC information pub plic: Range, /// CLINT information pub clint: Range, - /// RTC information - pub rtc: RtcInfo, - /// Number of UARTs - pub uart_count: usize, } impl Debug for MachineInfo { @@ -47,7 +38,7 @@ impl Debug for MachineInfo { let model = core::str::from_utf8(&self.model[..index]).unwrap(); write!( f, - "This is a devicetree representation of a {} machine\n", + "This is a device tree representation of a {} machine\n", model ) .unwrap(); @@ -64,24 +55,6 @@ impl Debug for MachineInfo { } } -/// RTC information -#[derive(Debug, Default, Clone)] -pub struct RtcInfo { - /// mmio virtual address - pub range: Range, - /// interrupt number - pub irq: usize, -} - -/// UART information -#[derive(Debug, Default, Copy, Clone)] -#[allow(unused)] -pub struct UartInfo { - /// mmio virtual address - base: usize, - /// interrupt number - irq: usize, -} /// Get machine information from a device-tree pub fn machine_info_from_dtb(ptr: usize) -> MachineInfo { @@ -95,11 +68,8 @@ fn walk_dt(fdt: Fdt) -> MachineInfo { model: [0; 32], smp: 0, memory: 0..0, - uart: [UartInfo::default(); 8], plic: 0..0, clint: 0..0, - rtc: RtcInfo::default(), - uart_count: 0, }; let x = fdt.root(); machine.smp = fdt.cpus().count(); @@ -107,8 +77,6 @@ fn walk_dt(fdt: Fdt) -> MachineInfo { let len = min(model.len(), machine.model.len()); machine.model[0..len].copy_from_slice(&model[..len]); - let mut uart_count = 0; - for node in fdt.all_nodes() { if node.name.starts_with(MEMORY) { let reg = node.reg().unwrap(); @@ -118,26 +86,6 @@ fn walk_dt(fdt: Fdt) -> MachineInfo { end: x.starting_address as usize + x.size.unwrap(), } }) - } else if node.name.starts_with(SERIAL) || node.name.starts_with(UART) { - let reg = node.reg(); - if reg.is_none() { - continue; - } - let irq = node.property("interrupts").unwrap().value; - let irq = u32::from_be_bytes(irq.try_into().unwrap()); - - let reg = reg.unwrap(); - // let val = node.interrupts().unwrap().next().unwrap(); - let mut base = 0; - // let irq = val as u32; - reg.for_each(|x| { - base = x.starting_address as usize; - }); - machine.uart[uart_count] = UartInfo { - base, - irq: irq as usize, - }; - uart_count += 1; } else if node.name.starts_with(PLIC) { let reg = node.reg().unwrap(); reg.for_each(|x| { @@ -154,19 +102,7 @@ fn walk_dt(fdt: Fdt) -> MachineInfo { end: x.starting_address as usize + x.size.unwrap(), } }) - } else if node.name.starts_with(RTC) { - let reg = node.reg().unwrap(); - let irq = 0xc; - let mut range = 0..0; - reg.for_each(|x| { - range = Range { - start: x.starting_address as usize, - end: x.starting_address as usize + x.size.unwrap(), - } - }); - machine.rtc = RtcInfo { range, irq } } } - machine.uart_count = uart_count; machine } diff --git a/docs/assert/boot.drawio.png b/docs/assert/boot.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..fa6edb72d24be7de26f3f02122dd6070e360b42d GIT binary patch literal 22636 zcmeHv2{_bi`@f{JgrZWGh>&F8Ns=vN%{JLavKwZY8Ecl%u26`qErt-2tYZyXB9wh! zvSpWj8Rq{ThU&b_d9UB^y?+1qocCO(tLA%upYQ!V_xjw==YFnpUt3d!nv#){goK1z z^|GQ42?;5Jgk%pb`F?;>>B++Y{IdtCqjHHPy`FiDgoN`3O6e-f(cRk4!HR@aL}B|E zr?8+c9Esu-QREaBHg|I3x3n|2L6|!t`C(QlfCRjEgj?EK+gVv|j}aCW7UdHZ;u8|n z6B6MRkr$Q({t}Vm7ZnpV+8%FiV+A8J)PQ^1IXIYe3M-583j(apfbC$Ga5p6IQ&SK4 zOGpqPi(CSJ0WZWww|}~ei}C;zc_$|aE3nmdH9KG(%3>lC{37B2`Hb3SJq>kEVFlo~ zgB{cg_(#Rc0tzR5qF{@FI|3ACAz^?q;Xi<=Yi@0hu=|MxK_)Adxy`mbFf$P|H4SSA zm>@#^vZ08EHZbG19IjRfq#Yba6kC{Ih+jx@`why&$!eQyY2|8X0n8}ODWb$FC=YNZ z{1H(gY7uy_BkD~-Oy?3(R0OVQ&ZlPSX=J5|a`D*a1~UiNyrq9_Ky`dVzvZ^W)6rc8 zVeVwB0k^br02o`kZ+|2tBq_1Y$kJn*A}J=iO|U`i%)Z4`Sdc)_weuuSCj=~(pbQ%q zJ4-7hk=r&21&2GJ?3{ijTEJm2D+{7&i5$%l2!cJgmQN&E!ySk+6A4a$Sig)Q5Ogif z9sZUIwzEXpZjTia5hSjUF#NKWosBJVYEf}XB4qmy3%7y8%pH_| zP%k0iE-=fj^gxK^A7j+va3{bLLIBa;3Wf3@I-a=;3J#ELQH~D8w}6ZYkE_4~;rp!z zL&5{U*v_LO!PR$PDiYkB@U-o!garZw;Nf4@8gU#F?t%bfck9!?s|=!9QRWC6AQ%4Q zaa;WUxhMVbClxCoMFH{xK83JyFh|+B{xvrV)8DMg7BY5zIal=>T^{TD|zF$4T=WCN!Db!R8o`tSWA#MB=r zvWepV6xohe|2;ts6c*dD@W&78oeJ)!RQz8Y)mzajEcm-oE%N7#YNGf*MYSCaWraW> zT%3p}xu4wR&$?raO8t3)o0z75vfBSeaJ$=~2(>t&kh21Q|5S{-0XF zZw30lkPxvZ(9HW0Sq9# z`*Hr?dfEX1wmpncfo!+Qh~fILwP%2n=KKHZSnUys^S)sR@bfne|A)VYf8!gq%)WZaH&Z7AKVMs zdiTo}oS(~wt+zXuezso_KOkJU+P)PMctMnvgoKSmRZ(8g9WoU|5q7KsTLRsGkj?h^ zHSO!y6&D1)oZ%Ph%^Nr=#RTX#cYM{mrts?(B^P8AzG)oYdLyEFdL{3Mf0GdEAn8<>SB8C6dK&fOBDL>pOxO1+3I?1P z?4h}iEEz_pf(0tfTJ(hf2tFZUvSsxfE2LvyNjftX5`LLM`*Kf0%_(m+{qphy;lAD$ zqclDFUK!pDEg7aBrxdiK+5I%SQd$x_7gMZj4@{({^i5uUInIB)Z#lh!Cx%pk@nR;$Vmj~dSYHkS( z6|jc8z#2B2vHh%&)xp3l-Dt=ODujd{O|Q#<#GUM~&MBy_9!zR#ANr)XM```{(Z0=n z#ywxd`Q|>>P56TwTL$98!sJ}|SMGv0SJX;ssfweUqu(QNUv3!6RX#rl;HCt0%aY6`fJZTe4EhNUX%`KvTi!1Y-Cw36|J?(64J?uU2(Sx;No)Pc@{r*a_hBWZ0kg*XbUx zareZsr)QqxlILG9>zD(9o>HZUg~hw%;L3UBydS$dmh<|@pxhqh)!&IE!%kA!)bjEe z^5^}vn17#U&UUhavr|BI@j_;%a*LiV8M;;0%eJL&ZjbYtZM>8AeZOkIo-;K*a=)o% z!>tc<=h2BoAK^L5v0hJ88wGX$n6{dGQMtq6ucgpoP=;>F(Q{))p(&wDG0ix>N6=ci zw!$axd{?zFuW#q_>otw`-~`&#H{8N$^-`c*kFGd&Wrx!|`zXx>IXpy3j)=AwPws+6 zrKK0TDh3V+KwY`cjC6pK@%BLx81BM1Q@%PAs-Jo7YM(6#;0AOl*^~3xsS(c>QqXJ> zVR9FOpo4`^$JiLU{oXl)<3$@IL0mJqw|qM4(exQRwTbDogT5~ z+J|g@QiD!WxVtpYFz@>;wdm_OZ*y3NuIt1{eLMOi$WWb>M>_T~I`-C^Yu+@7Qf|GE zaTA?0%j-U{RR&X^E7Q7Zn_t{~=X<>IJte8wrqSt<=+s`t#qj6gE4l}KXTp64kgenT z`s2N3=W5a{zH?}ad(>0byYQ`MuMTQ8hX!9j`)n4(r*ej?={5TrVMCQ|ZBXyH zCb?qS4bbOQ>)ezx{@rrDcoof{M`BFKvWKz4Ip2p~v8IhA9PANpjkjG4_CYajqL?mt z?Bh=M*}FdC|03Nu*VS~I9XB%J`|-9Y%l-n^M$>)VI(+HHg3xCHadV@ZYePqEaAXzC z31LxbVfJV|1uwet?%voLdCj|-uVravI;L*Iq$KjE`}8+vxdRY*Gd!8**!P8s)i?9? zH5)z7+|1F)hPHUJq9^R%Yf5lz5i=1>T=C z^Y>3c<6Y%_R}K~)Oix{lI?jy2tFMc|I`d54QpqK@_)5$?^+>^^H;{v?v!Tzy6)Zz# z425iwEMF$>S!)Td&h4A27F*;Ib+6+0D(k+QX_tE~(pOEIna0#-;n3C4w~;NNWd8Vu zY_TKXthLgaabq_JRaR!<%VwTo)2lNP8^zyWCdp;&=g#1*3ewKii0(PwIw$Kq_T8|X z8r05fXWY9I!8%mNdLdfI=C*>qn$JFYeo3(Sa$ns(Z2#VO#qBw$xG)%q(S>4t^bxo& zqh4+_YsgG@G_8MclIuvnLjLHb7d~|8a-;r;&4PEDEKKmXWD*y=eERs!F;U&=FY`DU zV!TBC68%j!`TAz3x<{s~hwo<3epJJoUj2Y$ke8)KsKyyjTqxmX_>^JV=MirrwNiEA z0QT+Px+yFW6C4}YzOM;2Q;Tq?-j*vc-8XG5Se`8U7Z)m z(%5iQGq1~J<90c%8Os0>%YBQZeZ{xRP+YmO{1so{b6Y02FP91a^qZ7_)#SkH0{xvt zSjsIk7fQ(CdzpL0gI3R1KZ{v2L^q!RC9jR_=X=1`)|~X|?fF$VCH3ydwbw#KzJlo4 z@5o_WeNKK`;4tu3fvE_QVf()*L~3l_7Au$M=fNa!>%eh=Ohc!Ajxr9FX|aiZn`Ob` zNE&;I(XZ?r7FSmO<=#<#8l?sy-> zphWh9su1o`91fmFH>4=9>06+NZ#=b;)>26VR+rbr)0EHVQtl1*ui7A!daU9cSU9J} zIOJcYqu~wBmMVGaAG4qNLf@ljqRK_zYbFW+VtMiUkWZEMiplXpK};}wd^xzHN0PpZ z(`odyZ7nax==!sgQE0DW==!4Znwlq{>0nksu&g$=EAFl@EtG#!Y@X?KRH{hEsNKWI zH^F35K;X?(qca{GMsw^D+N(Hv2K`jLs&-TcVTfeAzj*pvc$O(p`PsjyzboJ%*5c#8 zIS{@Fb=K+`h@Zz-ZFt4A*^ZW-l*LU3e1%Dn>TVk zfc@HBjZ2|Fq}zO&LFX_RJkY^|bKjj`Y9<#_V2ewbO@_u@B)$H?30X#OK9^Gs)L_?s zt--kakIHLO#!LG%(|`O(LH+2>R$_Miz{>acnjT%UX`>jhaMd-aK)7wjzO_6RAR zmKwM(=wWOL6h?$I!CYqjQ=o=T5@<}Pp9RXR+gdDcLr!d_q!cl;5BYCWrC*7ur?v(P zMTF+QSJa%qWcA-@j*eZUxW~i(kwWX%$1Zkbh^il%5JYOA5gofeppr0{fEMUn)XfRFi_J1r;7=~+EoX1 zt5~F%FGpM?+?7H^@)eY%uL6p?jQBl8O;-CH&?Co!{% zk%fHkhQp5>|F!ZatUa_WDM$t(8N%;Jrs=NC@P1$08O_oC1Pw?f`G2`XH+wdgO#(U= znF42ZS(R6|6O0rgi}ReCPPsCwE+;v4XZEb)*Rgt_(j7bdT?1bdDzQvbiG^+_KNT^}eXMWfB zMS|74-);&`l~_+pDp0bn?%2}VrlOVCUw_-q?H?YCoG(Gp^g|2maCfijda7WS&it&b za8zBhl;$;XkLF@KFO?jN@8*=FL-s#B9yXB`fdr~GJiTV!YGjz5v}WS=)+A6R)jN{b z_7=j+@1(UvXq@*QpfisBhet$Fc}yb}!ZRcH+zBcC&37jQJXzWcVo~3lv8w&yVzs$= z@20+EkQ>vE;I8RI7>Ajg*j3XxQ2tpU!Vo3(oWOa>+bn^FYf?X7UQ@uc^XmX|$qu~K zqf0wcVwT$2szcK(b?IW?Nyzslg_h`CUtDyCw{;wULW!CEh zyflEb7kWs4Os;I=Xi*#*I^QGNd1w1I@PbT=nK%}Bh@)ex_Q-e6qTWMJ{DvGM39unPoaek4GLIUx zW!mL`Xvk@oH@Q3LCfn#(DpQQ#hYw*_wGKt*9DfUB@vW!YIi;IGzSPWZY}O+5*axn4#w=Lu)7{0WfRv8 zjQV#AKIt3+MTgl_s}QD-qk9bog?o0&Y|Y;OGR!_Hth0sr!4q=jhBIi*TO0(1Xi>b; z2E~50o7vKCKTrcllhf>!yM&w3 zfO%lkRHnPW>35lw40~De$PW`q05W!WGvxd4y3AwXqsRBo{P0g0AR`tlfZF%}Lox5~ zv$-h@2cHG0ElX$U+fC3f*|(%8xKsq%%A_b0W?Y`0pD))swYES@FHi`D zq)>l|Jczk|QEl}Q07J5u0ejsImkVom!Ao9`>tk}j1_3|@-@zbRGct7V!c3*7P16_f zE6$zSCm5 zXO%jYq9BG;h^9DZad=;j>He6`OuP@86Rjf-WWndf#hS9~tpTi#y~W>)GrUJk#x5IE zVoW;jyL;!2hoi&@<&Sl2DzL*u1A82(lb2T>RxdKhI@SH6>sb-a`Rt-2WG*nemH8XB zP-u?VLi4N$?6_@#LgBljy(1%TA9=@8W`Rv=LplQ3tCs=HC^8J3d_cTN0^uWMXejV>|H^{G7&z_nB`ulmn62MUZ1?f)Ep6a_w~Muf&4H~CW3bT~A4!pE9> z>}B$Nz)6&lyS3B**k{G3^i$+v$t_%Y)SYgHa~y!w>(ty$o) z{W~z^fs*S9&t;ciy8jA7O8gTLvI&A_9J1zT$z1Dx#XrMudd|h?@YT7_9;kAhi0tA< z1#iiDo-AXaW?cX9OHtLC08ZYI{TLp=w4Yh-QoiQ+d5+osz|0l^c~z9M^3r#=VouiG z3xJoDdkCoKZiNU9g(#V#+|HsqdC;z^(a>ZXAq{Pm+riN5$KHVo&)$0Kn@xZc310o9 zf&(T43RIVIc8bU&B8Yd|d$2^45LN&HW4stR#%b5tMoubwah zR{z4eH2mk{`LA(*T)ja3)&^-Wq(j!?BU;2lD_`eKb%K_;!M{a0{eu>>+Y=&h3!X`& z@2&OqRPrwATW&E|VNSH}y`bPCmvH0M>%uqLK#^}?fa9%1KD7*XT#eX=5pQwOk$||p zVwCo@eS_408Y?;$KE~#jqcdI-wO%z49eIOp=rs4eH!XlK25Tf1c7}SlX^zLwABZX8 zE_Ziv@Q0{M9l7mmSZoWD$WP8E+o&xBlVL~dLNo&myBlIXwK+6ugn*jt?fOWY6dHOJ5DvVKC@{W+cncw z0F37Tctt@uHP@gR&7Y5ZSy|v!>gD-qWD}Rrq@@EOv6Hx1+0g4F*uf(3ZIjDc^Z+I+ zE=^~0t>k;!V9OAcYxEAIxOL>(fY$!0ks$(xYWZI6Gw)cAWv`rfDT}W2BTt`>c~Ct3 ztTOnuNA9N$?)WE9x>s!$Q&PHn`un*h59}{?{q`BMaeY$&S+(v|`~(IZudO;$r@C?^ z;^O_e$*p2*7-gyIE#yvkD8YCavQg6uzS2nz@U@0{Ig@WuF3`3LPY_qnOxC!%rQ`$A#+*miyH&vN7CBb8f0kE)T{TXNHJAnm3~4PA?*hx$D<-=0QeCN@o5N@(*f zb3M(b%K+QWu!golj(T3N#vftwlKea^wv1mC%Iy&~HuabyAKmNw;ym2~s1tN$g`wCM z_NF6py+66(_S)Xm&4PXtH0$Wyc!R>#H8aE>ffcqF4e(N|4rTlBwzUV4hE9)Urf*pw zStZLghs{(*dxW(XOR{`51N)Dn0o=N)2Nsn#`7l8u6!MG)k&m}W>qRs$y!#mryxeMw z=E7@Up6ydeXMDr;FzR)B-r9q1Rlb#k!(=)AWDHL=*1RWqEqdc{LbTK3^Ae zUS#RUK7)Q9wEBaN4~&J2DW5mUagE%Cne{Tf471tL&Y}^2lNZPpz4*6aog>ed1>^v1 z%J@RUELP_L7C`VF3aKKpRkA47BkV9no>`2W1x_JUCBY~278Wgn^o*goBd`R^;i?4i z6?x5)8CQdYPA>6%;Z!s|>G8^%0FY@B5n!TL3OXRQ(S8c|O3v?&Ko)BuKDgVW1!r7V zVz#u-RU-Ogv>@?oXHVt9lWJt~_vTqED%%5_X;w`>ogSTUOqIMCbwiPr2I1K~J9w}E z3OHufZd7py~Sy?g z*OXH+PIDBGg4s{I4f*%C(S5@Oy2WUy4jvD^uH5~2z9v<2G9b`Co@)JdZm(Ct_fT6T z|Kyljg|nynMC2`?wO8IXABFPc+b87>JJ{y}9Sbt?NkjR7C+L<0njp6u)JoT#OGDE} z>J3-53jHTu7oTFsLh{G2_?U4OJ;>((p9$@M=DP(4?swi`!S>%a<1PKE|qhWK%UD#%JNEkFTV=3O{b2poTbaaH%@PY5pOQp9l-*Z!!z| zG82XIa>fTlNzb;Cw+Vp%s8sM}Vq5Uvs9H#q_Z|4g=EBqa z<3%aUdKJC~Lr)KFw%V^S`IjnzeXpF7^cXJT*7=sJTb}!@yw6(WW5(4cAn-7IW{Mu{ z)svZR-y2>K^#rs|LP8fxxC`LDSCDzAtWUIg&<6JFTTDDpY5Lg=G>H^Ehh7I?20AF57oML+^eMEoQ$#S8Wp*Qg-e zjcwqKQx{9{Ox=%6U+h;7`)=xHuEci8H70-)wSu-#!@JdsGKi(z))^Z02hUVU zF*pN@;CwBh8)dfAMw)!i)Fj%-ngAazm|fdHv6Zm0??tmk$TKOZ3G-N=N|;SKWVG1= z6g;4m_6?3|RSlju>Fq^lA3pVM;c9@AN#U3JI)XGF7*?}O4II5xTSBNxRDZ?c92)^V zD@@wuF`4><6HqIp%RKe=r>ozbO!A)slR5!1*OH|+&f)ahH7 z4}LDgfx17D|73BBTf?R-a6aTW<#mZW)UH>cDZ9L+kXpI)?1pV8-=Kcyho*LBHl*0o>ARFQ5x2Eo2NEVS;_ z!aIhL#Hgxb4M$S|Ts#rz3_Mw?F$!rS;gVe%ynsfdgPGe`q0usK-&(N_Gl-T9Z!izj zxDMCz65%3eXm(1++`t_-30!u7{p%Tt;u#h-T^I*Ky6}PGke;6aaB?E#C?=O;;PMR& zxO~H|fqAnZOHw_=eaGZV3P|f5pPl#h=+-Hay_*AQBccW*k#u!JI%_J=bG_b?dXc&S z@*2~(Saz#;%vUB`d&yn@Ovb{5_W}q+@yqooWG6%l=$|;f4j_UxY@uX~7j9^)aNWaJ2jC&~FfwdpzvRIk0LuaZdxWmg4PEyi6x>0d z9v)_^u257B38V-r-({#wV95Cw!@qP0;Fx~xWc3E1o}{pRBc4SlTJO-1&-1W+eIA$l zI`(#xUjn~f^fx)|D6V#U+fOAGudUn2Pg|h%Vs%oYb;cFYdJ_%)-3;M6j?CjtV+Q01 zO*m~G5u_AW>o-C-TcVpG@du$_<;Ppv5YkX-q7}`Z!_O!CLZhn)bfKegs{i0QUR||zw|Li7 zH;29sZLk@>ilty2|Mpt**!&X{HhF&4{D;IIfZ)Yz-`)&+tEn-b-1H3IkeKeX>f;}_ zn$q_$Jg}ETM3IgxMFMuEMa;OllRCN$W0IX?;jK`pKh{eBj?&z4kVQlX+JsJ2aV?cPnF zn6=?K?-@q-r7Nb?)E@<(QgoLrw75Ve98QWZk2l4MwouB~A5pC&s`~h8!O2#uf;*;O z2;P%PjJNDPUYois+Lvw!OvWG=?aTy!Gn`#pXujhC2Q6Q`SEU5rj9WoL_#p>b+-6gs zy+OLsjg9WdNdlr@=;Z6klq!i3_VLqBEt8|iVqLw018HZ9&5}#aPt@!oWo?izc%XL ze0+s8lOatTsS*b}9dP2r=~pp^$F{o!?SIZ4)rPkknu$XbfVrMgY@*UT-kZ;nN=XLdk5GK=j3}o?XzI`=%9K&m- zpA_R06eTosQol7h({oI#VKm6ltVol^yPIM>UsXiE%XRAE+Z-Ws`TG4XBe%BmN`fL= ztvt-4&U5kGUc4Mbl07t8CVxaf9N`cTu9Q zx7IqQ0ul0`ms$N|W@IkoiN-iaenc&Vs!zYkt!Jdq(_+w6(%TJI|L~)IS#yW|VoJ&M zl3Q`DLdd-Lfic!?-DxMtYxZ5aFT~l9dS4^dgVoN#NaBmY8AV}ZQ zSNqANSlu4Q5&LSFNDV0v>r;4iH^Yeqmb`+IhEF}FHwIfGn%8I2>ocq zetknHv&U6Z$*_sTJcp%~PHfwsgp}tnU@1HG0r>NvSW$(drJ6u2Jk4k9=3ZoS$s;V>#PgW^nsG*YTHc%t_nMx%+IMI`EWs+`GGU>L6{M6A%5>&5{`h-y0f>Whcrti#vy! zf7vc0-&adD)Qv4v6qR)0KfPLl)>#;oqe59V_xYAxBDuB92EIk|Hj3&3Ml(YY>K*BI|~ z? AlienResult; + fn write(&self, buf: &[u8], offset: usize) -> AlienResult; + fn size(&self) -> usize; + fn flush(&self) -> AlienResult<()>; +} +``` + +在设备管理子系统中,扫描程序会使用驱动程序实例化一个设备,并再次使用其提供的接口功能实现文件系统相关的接口。 + +因此,如果需要将其作为一个隔离域,这个隔离域向外暴露的功能就应该与其接口类似,而对于依赖,根据不同的设备,我们可能会传递一个`MmioTransport` 结构体或者 `SDIo`结构体。 + + + +串口设备驱动`Uart`: + +1. 其依赖由几个寄存器构成的设备地址空间 + +向上,其使用一个接口暴露功能: + +```rust +pub trait UartDevice: Send + Sync + DeviceBase { + fn put(&self, c: u8); + fn get(&self) -> Option; + fn put_bytes(&self, bytes: &[u8]); + fn have_data_to_get(&self) -> bool; + fn have_space_to_put(&self) -> bool; +} +``` + +如果将其作为一个隔离域,其可能的形式应该如下: + +```rust +pub struct Registers { + pub thr_rbr_dll: RwReg, + pub ier_dlh: RwReg, + pub iir_fcr: RwReg, + pub lcr: RwReg, + pub mcr: RwReg, + pub lsr: RoReg, + pub msr: RoReg, + pub scratch: RwReg, +} + +fn main(regs:Box)->Box{ + // +} + +pub trait UartDomain{ + fn put(&self, c: u8); + fn get(&self,[u8]) -> RpcResult<[u8]>; + fn put_bytes(&self, [u8;128]); + fn have_data_to_get(&self) -> RpcResult<()>; + fn have_space_to_put(&self) -> RpcResult<()>; +} +``` + diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 5ef36955..113131b9 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -5,11 +5,11 @@ edition = "2021" authors = ["chen linfeng"] [dependencies] -log = "0.4.14" -spin = "0.9.2" +log = "0.4" +spin = "0.9" riscv = "0.10" -bit_field = "0.10.1" -xmas-elf = "0.9.0" +bit_field = "0.10" +xmas-elf = "0.9" bitflags = "1.3.2" virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers",rev = "de1c3b1"} fdt = "0.1.3" diff --git a/kernel/src/device/rtc.rs b/kernel/src/device/rtc.rs index 44d488b8..eb3664a2 100644 --- a/kernel/src/device/rtc.rs +++ b/kernel/src/device/rtc.rs @@ -22,7 +22,6 @@ pub fn get_rtc_time() -> Option { RTC_DEVICE.get().map(|rtc| rtc.read_time_fmt()) } -#[allow(unused)] pub fn init_rtc(rtc: Arc) { RTC_DEVICE.call_once(|| rtc); } diff --git a/kernel/src/ipc/shm.rs b/kernel/src/ipc/shm.rs index 3baca29c..ff5a3eef 100644 --- a/kernel/src/ipc/shm.rs +++ b/kernel/src/ipc/shm.rs @@ -96,10 +96,6 @@ impl ShmMemory { self.access_inner().state == ShmMemoryState::Deleted } - /// 引用计数器减一 - pub fn dec_ref(&self) { - self.access_inner().ref_count -= 1; - } } /// 记录共享内存当前状态的结构 diff --git a/kernel/src/memory/vmm.rs b/kernel/src/memory/vmm.rs index 2f2d2a01..306bcefe 100644 --- a/kernel/src/memory/vmm.rs +++ b/kernel/src/memory/vmm.rs @@ -302,7 +302,7 @@ pub fn build_cow_address_space( if target { for i in 0..usize::from(page_size) / FRAME_SIZE { let page_number = (phy + FRAME_SIZE * i).as_usize() >> FRAME_BITS; - FRAME_REF_MANAGER.lock().get_ref(page_number); + // FRAME_REF_MANAGER.lock().get_ref(page_number); FRAME_REF_MANAGER.lock().add_ref(page_number); } address_space.get_record_mut().insert(v_addr, true); diff --git a/kernel/src/net/socket.rs b/kernel/src/net/socket.rs index 5518bdd6..433b2b72 100644 --- a/kernel/src/net/socket.rs +++ b/kernel/src/net/socket.rs @@ -193,10 +193,6 @@ impl Debug for Socket { } impl SocketData { - pub fn from_ptr(ptr: *const u8) -> &'static mut Self { - unsafe { &mut *(ptr as *mut Self) } - } - /// 用于创建一个新的套接字数据 `SocketData` 结构,返回创建的文件描述符。一般被系统调用 [`socket`] 所调用。 /// /// 执行过程中会创建一个对应的套接字文件,打开后将对应的文件描述符放入进程的文件描述符表中, diff --git a/kernel/src/task/task.rs b/kernel/src/task/task.rs index 2c8d5473..64c22295 100644 --- a/kernel/src/task/task.rs +++ b/kernel/src/task/task.rs @@ -367,15 +367,6 @@ impl Task { &inner.context as *const Context } - pub fn get_context(&self) -> Context { - let inner = self.inner.lock(); - inner.context.clone() - } - - pub fn kstack_top(&self) -> usize { - self.kernel_stack.top() - } - /// 获取任务上下文的可变指针 pub fn get_context_mut_raw_ptr(&self) -> *mut Context { let mut inner = self.inner.lock(); @@ -449,25 +440,6 @@ impl Task { inner.exit_code } - /// 用于判断一个文件是否存在在该进程的文件描述符表中,如果存在返回该文件描述符 - pub fn file_existed(&self, file: Arc) -> Option> { - let inner = self.inner.lock(); - let fd_table = inner.fd_table.lock(); - let fds = fd_table.data(); - fds.iter().find_map(|f| { - if f.is_some() { - let f = f.as_ref().unwrap(); - if Arc::ptr_eq(f, &file) { - Some(f.clone()) - } else { - None - } - } else { - None - } - }) - } - /// 用于获取文件描述符id号为 fd 的 文件描述符 pub fn get_file(&self, fd: usize) -> Option> { let inner = self.inner.lock(); @@ -717,31 +689,6 @@ impl TaskInner { res } - /// 将虚拟地址空间中的一段缓冲区的首地址 `ptr` 和 缓冲区的长度 `len` 转换为 实地址下的一组页 - pub fn transfer_raw_buffer(&self, ptr: *const u8, len: usize) -> Vec<&'static mut [u8]> { - let address_space = &self.address_space.lock(); - let mut start = ptr as usize; - let end = start + len; - let mut v = Vec::new(); - while start < end { - let (start_phy, flag, _) = address_space.query(VirtAddr::from(start)).unwrap(); - assert!(flag.contains(MappingFlags::V)); - // start_phy向上取整到FRAME_SIZE - let bound = (start & !(FRAME_SIZE - 1)) + FRAME_SIZE; - let len = if bound > end { - end - start - } else { - bound - start - }; - unsafe { - let buf = core::slice::from_raw_parts_mut(start_phy.as_usize() as *mut u8, len); - v.push(buf); - } - start = bound; - } - v - } - /// 从物理地址的 `src` 处取一个长度为 `len` 类型为 T 的缓冲区 赋到 用户虚拟地址空间下的 `dst` 处 pub fn copy_to_user_buffer( &mut self, diff --git a/kernel/src/timer/mod.rs b/kernel/src/timer/mod.rs index 1e2fcdc6..d353fe38 100644 --- a/kernel/src/timer/mod.rs +++ b/kernel/src/timer/mod.rs @@ -154,6 +154,7 @@ impl Into for TimeSpec { VfsTimeSpec::new(self.tv_sec as u64, self.tv_nsec as u64) } } + /// [`getitimer`] / [`setitimer`] 指定的类型,用户执行系统调用时获取和输入的计时器 #[repr(C)] #[derive(Debug, Copy, Clone, Default)] @@ -189,7 +190,6 @@ pub fn set_next_trigger_in_kernel() { } /// 获取当前时间,以 ms 为单位 -// #[syscall_func(169)] pub fn get_time_ms() -> isize { (read_timer() / (CLOCK_FREQ / MSEC_PER_SEC)) as isize } diff --git a/kkernel/Cargo.toml b/kkernel/Cargo.toml new file mode 100644 index 00000000..19eb13ad --- /dev/null +++ b/kkernel/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "kkernel" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +arch = { path = "../subsystems/arch" } +platform = { path = "../subsystems/platform" } +mem = { path = "../subsystems/mem" } +interrupt = { path = "../subsystems/interrupt" } +devices = { path = "../subsystems/devices" } +drivers = { path = "../subsystems/drivers" } +unwinder = { path = "../subsystems/unwinder" } +constants = { path = "../subsystems/constants" } +config = { path = "../subsystems/config" } +vfs = { path = "../subsystems/vfs" } +timer = { path = "../subsystems/timer" } +ksync = { path = "../subsystems/ksync" } + +gmanager = { path = "../dep/gmanager" } + + + + +riscv = "0.10" +bit_field = "0.10" +xmas-elf = "0.9" +bitflags = "1.3.2" +spin = "0" +log = "0" +vfscore = { git = "https://github.com/os-module/rvfs.git", features = [ + "linux_error", +] } +syscall-table = { git = "https://github.com/os-module/syscall-table.git" } +smpscheduler = { git = "https://github.com/os-module/smpscheduler.git" } +page-table = { git = "https://github.com/os-module/page-table.git", branch = "dev" } +downcast-rs = { version = "1.2.0", default-features = false } +netcore = {git = "https://github.com/os-module/simple-net"} + + +[features] +default = ["qemu","smp"] +qemu = ["platform/qemu_riscv","interrupt/qemu"] +vf2 = ["platform/vf2","interrupt/vf2"] +hifive = ["platform/hifive","interrupt/hifive"] +smp = ["platform/smp"] + + +slab = [] +talloc = [] +buddy = [] + +pager_buddy = [] +pager_bitmap = [] \ No newline at end of file diff --git a/kkernel/build.rs b/kkernel/build.rs new file mode 100644 index 00000000..615bef3e --- /dev/null +++ b/kkernel/build.rs @@ -0,0 +1,32 @@ +use std::fs::File; +use std::io::Write; +use std::path::Path; +use std::{env, fs}; + +fn main() { + // 指定target + let outdir = env::var("OUT_DIR").unwrap(); + let link_script = Path::new(&outdir).join("link.lds"); + let mut script = File::create(&link_script).unwrap(); + + let ld_path = Path::new("../tools/link.ld"); + let ld = fs::read_to_string(ld_path).unwrap(); + + #[cfg(not(feature = "vf2"))] + let base_addr = 0x80200000usize; + #[cfg(feature = "vf2")] + let base_addr: usize = 0x40200000; + let base_addr = format!("BASE_ADDRESS = {};", base_addr); + let mut new_config = String::new(); + for line in ld.lines() { + if line.starts_with("BASE_ADDRESS = ") { + new_config.push_str(base_addr.as_str()); + } else { + new_config.push_str(line); + new_config.push_str("\n"); + } + } + + script.write_all(new_config.as_bytes()).unwrap(); + println!("cargo:rustc-link-arg=-T{}", &link_script.display()); +} diff --git a/kkernel/src/fs/basic.rs b/kkernel/src/fs/basic.rs new file mode 100644 index 00000000..d463ed16 --- /dev/null +++ b/kkernel/src/fs/basic.rs @@ -0,0 +1,714 @@ +use super::im2vim; +use crate::fs::file::KernelFile; +use crate::fs::{syscontext_for_vfs, user_path_at}; +use crate::task::current_task; +use alloc::sync::Arc; +use alloc::vec; +use constants::io::{ + FileStat, FsStat, InodeMode, IoVec, MountFlags, OpenFlags, Renameat2Flags, SeekFrom, StatFlags, +}; +use constants::{AlienResult, AT_FDCWD}; +use constants::LinuxErrno; +use core::cmp::min; +use core::ops::Index; +use log::{info, warn}; +use gmanager::ManagerError; +use syscall_table::syscall_func; +use vfscore::path::VfsPath; +use vfscore::utils::{VfsFileStat, VfsFsStat, VfsNodeType, VfsRenameFlag}; +use vfs::{FS, SYSTEM_ROOT_FS}; + +/// 用于将一个设备(通常是存储设备)挂载到一个已经存在的目录上,可以挂载文件系统。 +#[syscall_func(40)] +pub fn sys_mount( + source: *const u8, + dir: *const u8, + fs_type: *const u8, + flags: usize, + data: *const u8, +) -> AlienResult { + let process = current_task().unwrap(); + let source = process.transfer_str(source); + let dir = process.transfer_str(dir); + let fs_type = process.transfer_str(fs_type); + assert!(data.is_null()); + let flags = MountFlags::from_bits(flags as u32).unwrap(); + info!( + "mount special:{:?},dir:{:?},fs_type:{:?},flags:{:?},data:{:?}", + source, dir, fs_type, flags, data + ); + let find = FS + .lock() + .iter() + .find(|(name, _)| name.eq(&&fs_type)) + .map(|(_, fs)| fs.clone()) + .ok_or(LinuxErrno::EINVAL)?; + let path = VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()); + let fs_root = match find.fs_name() { + name @ ("tmpfs" | "ramfs" | "fat32") => { + let fs = FS.lock().index(name).clone(); + let dev = if name.eq("fat32") { + let dev = path.join(source)?.open(None)?; + Some(dev.inode()?) + } else { + None + }; + let new_fs = fs.i_mount(0, &dir, dev, &[])?; + new_fs + } + _ => return Err(LinuxErrno::EINVAL), + }; + path.join(dir)?.mount(fs_root, flags.bits())?; + Ok(0) +} + +/// 用于取消一个目录上的文件挂载(卸载一个文件系统)。 +#[syscall_func(39)] +pub fn sys_umount(dir: *const u8) -> AlienResult { + let process = current_task().unwrap(); + let dir = process.transfer_str(dir); + info!("umount dir:{:?}", dir); + let path = VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()); + path.join(dir)?.umount()?; + Ok(0) +} + +#[syscall_func(56)] +pub fn sys_openat(dirfd: isize, path: *const u8, flag: usize, mode: u32) -> AlienResult { + if path.is_null() { + return Err(LinuxErrno::EFAULT); + } + let flag = OpenFlags::from_bits_truncate(flag); + let file_mode = if flag.contains(OpenFlags::O_CREAT) { + Some(InodeMode::from_bits_truncate(mode)) + } else { + None + } + .map(|x| im2vim(x)); + let process = current_task().unwrap(); + + let _path = process.transfer_str(path); + let path = user_path_at(dirfd, &_path)?; + warn!( + "open file: dirfd:[{}], {:?},flag:{:?}, mode:{:?}", + dirfd, path, flag, file_mode + ); + + let dentry = path.open(file_mode)?; + let file = KernelFile::new(dentry, flag); + + let fd = process.add_file(Arc::new(file)); + warn!("openat fd: {:?}", fd); + if fd.is_err() { + let error = ManagerError::from((fd.unwrap_err()) as usize); + info!("[vfs] openat error: {:?}", error); + match error { + ManagerError::NoSpace => Err(LinuxErrno::EMFILE), + _ => Err(LinuxErrno::ENOMEM), + } + } else { + Ok(fd.unwrap() as isize) + } +} + +/// 一个系统调用,用于关闭一个文件描述符,以便回收该文件描述符。 +/// +/// 传入的文件描述符`fd`指向要关闭的文件。如果`fd`所指向的文件已经被`unlink`, +/// 那么在关闭文件描述符后,还将继续执行`unlink`,删除该文件链接,并回收相应的存储空间。 +/// +/// 如果`sys_close`成功关闭文件描述符,将返回0,否则-1或返回错误的类型。 +/// +/// Reference: [close](https://man7.org/linux/man-pages/man2/close.2.html) +#[syscall_func(57)] +pub fn sys_close(fd: usize) -> AlienResult { + let process = current_task().unwrap(); + let _file = process.remove_file(fd).map_err(|_| LinuxErrno::EBADF)?; + Ok(0) +} + +/// 一个系统调用,用于读取文件的目录项信息。 +/// +/// 参数: +/// + `fd`: 用于指明操作文件的文件描述符。 +/// + `buf`: 用于指明一块缓冲区,保存获取到的目录项信息。 +/// + `len`: 用于指明缓冲区的长度。 +/// +/// 若获取文件的目录项信息成功,则返回获取信息的长度(字节数);否则返回 -1 表示获取相关信息失败。 +/// +/// Reference: [sys_getdents](https://man7.org/linux/man-pages/man2/getdents.2.html) +#[syscall_func(61)] +pub fn sys_getdents(fd: usize, buf: *mut u8, len: usize) -> AlienResult { + info!("[getdents] fd: {}, buf size: {}", fd, len); + let process = current_task().unwrap(); + let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let user_bufs = process.transfer_buffer(buf, len); + let mut buf = vec![0u8; len]; + let len = file.readdir(buf.as_mut_slice())?; + info!("[getdents]: read len: {:?}", len); + let mut offset = 0; + // copy dirent_buf to user space + for user_buf in user_bufs { + let copy_len = user_buf.len(); // user_bufs len is equal to buf len + user_buf.copy_from_slice(&buf[offset..offset + copy_len]); + offset += copy_len; + if offset >= len { + break; + } + } + Ok(len as _) +} + +/// 一个系统调用,用于将一个文件的大小截断到一个指定长度。与 [`sys_ftruncate`] 功能类似。 +/// +/// `path` 用于指明要截断文件的路径,`len` 用于指明要截断到的长度。 +/// 当文件长度小于 `len` 时,多余的部分填充为'/0';当文件长度大于 `len` 时,多余的数据将会被直接舍弃。 +/// +/// 需保证该 `path` 所指出的文件必须是可写的。此外,该调用对于文件的偏移量 offset 将不会改变。 +/// +/// 当截断成功时,返回 0;否则返回 -1 表示截断出现错误。 +/// Reference: https://man7.org/linux/man-pages/man2/truncate64.2.html +#[syscall_func(45)] +pub fn sys_truncate(path: usize, len: usize) -> AlienResult { + let process = current_task().unwrap(); + let path = process.transfer_str(path as *const u8); + let path = user_path_at(AT_FDCWD, &path)?; + path.truncate(len as u64)?; + Ok(0) +} + +/// 一个系统调用,用于将一个文件的大小截断到一个指定长度。与 [`sys_truncate`] 功能类似。 +/// +/// `fd` 用于指明要截断文件的文件描述符,`len` 用于指明要截断到的长度。 +/// 当文件长度小于 `len` 时,多余的部分填充为'/0';当文件长度大于 `len` 时,多余的数据将会被直接舍弃。 +/// +/// 需保证该 `fd` 所指出的文件必须是打开的。此外,该调用对于文件的偏移量 offset 将不会改变。 +/// +/// 当截断成功时,返回 0;否则返回 -1 表示截断出现错误。 +/// Reference: https://man7.org/linux/man-pages/man2/truncate64.2.html +#[syscall_func(46)] +pub fn sys_ftruncate(fd: usize, len: usize) -> AlienResult { + let process = current_task().unwrap(); + let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + file.truncate(len as u64)?; + Ok(0) +} + +/// 一个系统调用,用于从一个打开的文件描述符中读取文件内容。对于每个打开的文件描述符都具有一个偏移量,读取将从该偏移位置开始。 +/// +/// `fd` 指明了要读取并且已经打开的文件的文件描述符,`buf` 指明了读取内容后所要保存的位置, +/// `len` 指明了缓冲区 `buf` 的大小(即最多读取的内容长度) +/// +/// 读取完成后,将返回读取内容的长度(字节数);如果发生错误,将返回错误类型。 +#[syscall_func(63)] +pub fn sys_read(fd: usize, buf: *mut u8, len: usize) -> AlienResult { + let process = current_task().unwrap(); + let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + info!("read file: {:?}, len:{:?}", fd, len); + let mut buf = process.transfer_buffer(buf, len); + + let mut count = 0; + for b in buf.iter_mut() { + let r = file.read(b)?; + count += r; + if r != b.len() { + break; + } + } + + Ok(count as _) +} + +/// 一个系统调用,用于向一个打开的文件描述符中写入内容。对于每个打开的文件描述符都具有一个偏移量,写入将从该偏移位置开始。 +/// +/// `fd` 指明了要写入并且已经打开的文件的文件描述符,`buf` 指明了要写入的内容在内存中保存的位置, +/// `len` 指明了缓冲区 `buf` 的大小(即所要写入的内容长度) +/// +/// 写入完成后,将返回写入内容的长度(字节数);如果发生错误,将返回错误类型。 +#[syscall_func(64)] +pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> AlienResult { + let process = current_task().unwrap(); + let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let mut buf = process.transfer_buffer(buf, len); + let mut count = 0; + for b in buf.iter_mut() { + let w = file.write(b)?; + count += w; + if w != b.len() { + break; + } + } + Ok(count as _) +} + +/// 一个系统调用,用于获取当前工作目录。 +/// 获取的工作目录将直接保存在 `buf` 所指向的缓冲区中,`len` 用于指明 `buf` 的长度。 +/// +/// 获取当前目录成功后,返回 `buf` 的首地址。当 `buf` 为空指针时,会导致函数 panic。 +#[syscall_func(17)] +pub fn sys_getcwd(buf: *mut u8, len: usize) -> isize { + info!("getcwd: {:?}, len: {:?}", buf, len); + assert!(!buf.is_null()); + let task = current_task().unwrap(); + let cwd = task.access_inner().cwd(); + + let mut buf = task.transfer_buffer(buf, len); + let mut count = 0; + let path = cwd.cwd.path(); + let mut cwd = path.as_bytes(); + buf.iter_mut().for_each(|buf| { + // fill buf + if !cwd.is_empty() { + let min = min(cwd.len(), buf.len()); + buf[..min].copy_from_slice(&cwd[..min]); + count += min; + cwd = &cwd[min..]; + } + }); + buf[0].as_ptr() as isize +} + +/// 一个系统调用,用于切换当前工作目录。`path` 指出要切换到的工作目录。 +/// +/// 切换工作目录成功后,将返回 0;当输入的 path 不是一个合法的目录项时,会返回 -1 表示切换目录错误。 +#[syscall_func(49)] +pub fn sys_chdir(path: *const u8) -> AlienResult { + let process = current_task().unwrap(); + let path = process.transfer_str(path); + let dt = user_path_at(AT_FDCWD, &path)?.open(None)?; + + if dt.inode()?.inode_type() != VfsNodeType::Dir { + return Err(LinuxErrno::ENOTDIR); + } + let fs = dt.inode()?.get_super_block()?.fs_type(); + info!( + "chdir: {:?} fs: {}, parent:{:?}", + dt.name(), + fs.fs_name(), + dt.parent().is_some() + ); + process.access_inner().fs_info.cwd = dt; + Ok(0) +} + +/// Like [`sys_chdir`], but uses a file descriptor instead of a path. +#[syscall_func(50)] +pub fn sys_fchdir(fd: usize) -> AlienResult { + let process = current_task().unwrap(); + let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let dt = file.dentry(); + if dt.inode()?.inode_type() != VfsNodeType::Dir { + return Err(LinuxErrno::ENOTDIR); + } + info!("fchdir: {:?}", dt.path()); + process.access_inner().fs_info.cwd = dt; + Ok(0) +} + +/// 一个系统调用,用于在 相对于一个目录某位置处 路径下创建一个空的目录。功能与 [`sys_mkdir`] 相似。 +/// +/// 有关对 `dirfd` 和 `mode` 的解析规则以及 flag 的相关设置可见 [`sys_openat`]。成功创建目录则返回 0;否则返回错误码。 +/// +/// Reference: [mkdirat](https://man7.org/linux/man-pages/man2/mkdirat.2.html) +#[syscall_func(34)] +pub fn sys_mkdirat(dirfd: isize, path: *const u8, mode: u32) -> AlienResult { + let process = current_task().unwrap(); + let path = process.transfer_str(path); + let mut mode = InodeMode::from_bits_truncate(mode); + warn!("mkdirat path: {}, mode: {:?}", path, mode); + let path = user_path_at(dirfd, &path)?; + mode |= InodeMode::DIR; + assert_eq!(mode & InodeMode::TYPE_MASK, InodeMode::DIR); + let _ = path.open(Some(im2vim(mode)))?; + Ok(0) +} + +/// 一个系统调用,用于调整一个已经打开的文件描述符的偏移量。文件描述符的偏移量用于确定读写文件时操作的位置。 +/// +/// 参数: +/// + `fd`: 指明要操作的文件描述符; +/// + `offset`: 指明要调整的偏移量,实际要调整到的位置和 `whence` 的取值有关。 +/// + `whence`: 用于定义参数 offset 偏移量对应的参考值,可以取的值及其含义如下:(详情可见 [`SeekFrom`]) +/// + `SEEK_SET`: 读写偏移量将指向 offset 字节位置处(从文件头部开始算); +/// + `SEEK_CUR`: 读写偏移量将指向当前位置偏移量 + offset 字节位置处, offset 可以为正、也可以为负,如果是正数表示往后偏移,如果是负数则表示往前偏移; +/// + `SEEK_END`: 读写偏移量将指向文件末尾 + offset 字节位置处,同样 offset 可以为正、也可以为负,如果是正数表示往后偏移、如果是负数则表示往前偏移。 +/// +/// 调整成功后,将返回从文件头部开始算起的位置偏移量(字节为单位),也就是当前的读写位置;发生错误将返回错误码, +#[syscall_func(62)] +pub fn sys_lseek(fd: usize, offset: isize, whence: usize) -> AlienResult { + let process = current_task().unwrap(); + let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let seek = SeekFrom::try_from((whence, offset as usize)).unwrap(); + let r = file.seek(seek).map(|x| x as isize)?; + Ok(r) +} + +/// 一个系统调用,用于向一个打开的文件描述符中写入内容,写入的内容将用一组缓冲区给出。 +/// 对于每个打开的文件描述符都具有一个偏移量,写入将从该偏移位置开始。 +/// +/// `fd` 指明了要执行写入操作并且已经打开的文件的文件描述符,`iovec` 指明了该组缓冲区向量的首地址, +/// `iovcnt` 指明了缓冲区向量的长度,即在这组缓冲区向量包含了多少个缓冲区。(每个缓冲区的大小,通过调用 IoVec::len() 来获取) +/// +/// 写入完成后,将返回写入内容的长度(字节数);如果发生错误,将返回错误类型。 +#[syscall_func(66)] +pub fn sys_writev(fd: usize, iovec: usize, iovcnt: usize) -> AlienResult { + let process = current_task().unwrap(); + let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let mut count = 0; + for i in 0..iovcnt { + let mut iov = IoVec::empty(); + let ptr = unsafe { (iovec as *mut IoVec).add(i) }; + process.access_inner().copy_from_user(ptr, &mut iov); + let base = iov.base; + if base as usize == 0 { + // busybox 可能会给stdout两个io_vec,第二个是空地址 + continue; + } + let len = iov.len; + let buf = process.transfer_buffer(base, len); + for b in buf.iter() { + let r = file.write(b)?; + count += r; + } + } + Ok(count as isize) +} + +/// 一个系统调用,用于从一个打开的文件描述符中读取文件内容,将读取到的文件内容保存到一组缓冲区中。 +/// 对于每个打开的文件描述符都具有一个偏移量,读取将从该偏移位置开始。 +/// +/// `fd` 指明了要读取并且已经打开的文件的文件描述符,`iovec` 指明了该组缓冲区向量的首地址, +/// `iovcnt` 指明了缓冲区向量的长度,即在这组缓冲区向量包含了多少个缓冲区。(每个缓冲区的大小,通过调用 IoVec::len() 来获取) +/// +/// 读取完成后,将返回所有被读取内容的总长度(字节数)。 +#[syscall_func(65)] +pub fn sys_readv(fd: usize, iovec: usize, iovcnt: usize) -> AlienResult { + let task = current_task().unwrap(); + let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let mut count = 0; + for i in 0..iovcnt { + let ptr = unsafe { (iovec as *mut IoVec).add(i) }; + let iov = task.transfer_raw_ptr(ptr); + let base = iov.base; + if base as usize == 0 || iov.len == 0 { + continue; + } + let len = iov.len; + let mut buf = task.transfer_buffer(base, len); + for b in buf.iter_mut() { + info!("read file: {:?}, len:{:?}", fd, b.len()); + let r = file.read(b)?; + count += r; + } + } + Ok(count as isize) +} + +/// 一个系统调用,用于从一个打开的文件描述符中读取文件内容。与 [`sys_read`] 不同,该调用将指定一个偏移量 `offset`,读取将从该偏移位置开始。 +/// +/// `fd` 指明了要读取并且已经打开的文件的文件描述符,`buf` 指明了读取内容后所要保存的位置, +/// `len` 指明了缓冲区 `buf` 的大小(即最多读取的内容长度),`offset` 指明开始读取位置的偏移量。 +/// +/// 读取完成后,将返回读取内容的长度(字节数)。 +#[syscall_func(67)] +pub fn sys_pread(fd: usize, buf: usize, count: usize, offset: u64) -> AlienResult { + let task = current_task().unwrap(); + let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let mut buf = task.transfer_buffer(buf as *mut u8, count); + let mut offset = offset; + let mut count = 0; + for b in buf.iter_mut() { + let r = file.read_at(offset, b)?; + count += r; + offset += r as u64; + } + Ok(count as isize) +} + +/// 一个系统调用,用于向一个打开的文件描述符中写入内容。与 [`sys_write`] 不同,该调用将指定一个偏移量 `offset`,写入将从该偏移位置开始。 +/// +/// `fd` 指明了要写入并且已经打开的文件的文件描述符,`buf` 指明了要写入的内容在内存中保存的位置, +/// `count` 指明了缓冲区 `buf` 的大小(即所要写入的内容长度) +/// +/// 写入完成后,将返回写入内容的长度(字节数);如果发生错误(如输入的 fd 不合法等),将返回 -1。 +#[syscall_func(68)] +pub fn sys_pwrite(fd: usize, buf: usize, count: usize, offset: u64) -> AlienResult { + let task = current_task().unwrap(); + let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let buf = task.transfer_buffer(buf as *mut u8, count); + let mut offset = offset; + let mut count = 0; + for b in buf.iter() { + let r = file.write_at(offset, b)?; + count += r; + offset += r as u64; + } + + Ok(count as isize) +} + +/// 一个系统调用,用于获取文件的相关信息。功能与 [`sys_fstat`] 类似。 +/// +/// `sys_fstateat` 中要获取信息的文件 由 `dir_fd` 和 `path` 解析得出。Alien 中有关 `fd` 和 `path` 的路径解析可见 [`user_path_at`]。 +/// 获取的信息会保存在 `stat` 指向的 [`FileStat`] 结构中,`flag` 是一组标志位,用于定义相关的操作类型,具体可见 [`StatFlags`]。 +/// +/// 获取相关信息成功后,函数返回 0;否则函数会返回 -1 表示获取信息出错。 +/// 如果输入的 `stat` 为空指针,那么会导致函数 panic。 +/// +/// Reference: https://man7.org/linux/man-pages/man2/newfstatat.2.html +#[syscall_func(79)] +pub fn sys_fstateat( + dir_fd: isize, + path: *const u8, + stat: *mut u8, + flag: usize, +) -> AlienResult { + let process = current_task().unwrap(); + let path = process.transfer_str(path); + let flag = StatFlags::from_bits_truncate(flag as u32); + warn!("sys_fstateat: path: {:?}, flag: {:?}", path, flag); + let path = user_path_at(dir_fd, &path)?; + + let dt = path.open(None)?; + let attr = dt.inode()?.get_attr()?; + + let mut file_stat = FileStat::default(); + unsafe { + (&mut file_stat as *mut FileStat as *mut usize as *mut VfsFileStat).write(attr); + } + warn!("sys_fstateat: res: {:?}", file_stat); + process + .access_inner() + .copy_to_user(&file_stat, stat as *mut FileStat); + Ok(0) +} + +/// 一个系统调用,用于获取文件的相关信息。获取的信息会保存在 `stat` 指向的 [`FileStat`] 结构中。 +/// `fd` 用于指明要获取信息的文件的文件描述符。 +/// +/// 获取相关信息成功后,函数返回 0;否则函数会返回 -1 表示获取信息出错。 +/// 如果输入的 `stat` 为空指针,那么会导致函数 panic。 +#[syscall_func(80)] +pub fn sys_fstat(fd: usize, stat: *mut u8) -> AlienResult { + assert!(!stat.is_null()); + let process = current_task().unwrap(); + let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let attr = file.get_attr()?; + let mut file_stat = FileStat::default(); + unsafe { + (&mut file_stat as *mut FileStat as *mut usize as *mut VfsFileStat).write(attr); + } + warn!("sys_fstat: {:?}, res: {:?}", fd, file_stat); + process + .access_inner() + .copy_to_user(&file_stat, stat as *mut FileStat); + Ok(0) +} + +/// 一个系统调用,用于获取一个已挂载的文件系统的使用情况。与 [`sys_statfs`] 的功能类似。 +/// 获取到的相关信息将会保存在 `statfs` 所指向的 [`FsStat`] 结构中,`fd` 可以是该已挂载的文件系统下的任意一个文件的文件描述符。 +/// +/// 如果获取成功,函数会返回 0;否则返回 -1 表示获取信息异常。 +/// Reference: https://man7.org/linux/man-pages/man2/fstatfs64.2.html +#[syscall_func(44)] +pub fn sys_fstatfs(fd: isize, buf: *mut u8) -> AlienResult { + let process = current_task().unwrap(); + let buf = process.transfer_raw_ptr(buf as *mut FsStat); + let file = process.get_file(fd as usize).ok_or(LinuxErrno::EBADF)?; + let fs_stat = file.inode().get_super_block()?.stat_fs()?; + unsafe { + (&mut *buf as *mut FsStat as *mut usize as *mut VfsFsStat).write(fs_stat); + } + warn!("sys_fstatfs: res: {:#x?}", fs_stat); + Ok(0) +} + +/// 一个系统调用,用于获取一个已挂载的文件系统的使用情况。 +/// 获取到的相关信息将会保存在 `statfs` 所指向的 [`FsStat`] 结构中,`path` 可以是该已挂载的文件系统下的任意一个文件的路径。 +/// +/// 如果获取成功,函数会返回 0;否则返回 -1 表示获取信息异常。 +/// +/// In libc, [[deprecated]] +#[syscall_func(43)] +pub fn sys_statfs(path: *const u8, statfs: *const u8) -> AlienResult { + let process = current_task().unwrap(); + let buf = process.transfer_raw_ptr(statfs as *mut FsStat); + let path = process.transfer_str(path); + + let path = user_path_at(AT_FDCWD, &path)?; + let dt = path.open(None)?; + let fs_stat = dt.inode()?.get_super_block()?.stat_fs()?; + + unsafe { + (&mut *buf as *mut FsStat as *mut usize as *mut VfsFsStat).write(fs_stat); + } + + warn!("sys_statfs: [{:?}] res: {:#x?}", path, fs_stat); + Ok(0) +} + +/// Like [`sys_renameat2`]. +#[syscall_func(38)] +pub fn sys_renameat( + old_dirfd: isize, + old_path: *const u8, + new_dirfd: isize, + new_path: *const u8, +) -> AlienResult { + let process = current_task().unwrap(); + let old_path = process.transfer_str(old_path); + let new_path = process.transfer_str(new_path); + + info!( + "renameat2: {:?} {:?} {:?} {:?}", + old_dirfd, old_path, new_dirfd, new_path + ); + let old_path = user_path_at(old_dirfd, &old_path)?; + let new_path = user_path_at(new_dirfd, &new_path)?; + old_path.rename_to( + syscontext_for_vfs(process.access_inner().cwd()), + new_path, + VfsRenameFlag::empty(), + )?; + Ok(0) +} + +/// 一个系统调用,用于更改文件所在的路径名。文件的新/旧路径 将分别使用 new_dirfd/old_dirfd 和 new_path/old_path 解析获得。有关解析的相关设计请查看 [`user_path_at`]。 +/// +/// 更改文件路径名成功后,函数会返回 0;否则函数返回-1(即当新路径或旧路径中存在不合法的路径 或 在文件系统中修改路径出错时)。 +/// +/// Reference: https://man7.org/linux/man-pages/man2/renameat.2.html +#[syscall_func(276)] +pub fn sys_renameat2( + old_dirfd: isize, + old_path: *const u8, + new_dirfd: isize, + new_path: *const u8, + flag: u32, +) -> AlienResult { + let process = current_task().unwrap(); + let old_path = process.transfer_str(old_path); + let new_path = process.transfer_str(new_path); + let flag = Renameat2Flags::from_bits_truncate(flag); + info!( + "renameat2: {:?} {:?} {:?} {:?}, flag: {:?}", + old_dirfd, old_path, new_dirfd, new_path, flag + ); + let old_path = user_path_at(old_dirfd, &old_path)?; + let new_path = user_path_at(new_dirfd, &new_path)?; + + if flag.contains(Renameat2Flags::RENAME_EXCHANGE) + && (flag.contains(Renameat2Flags::RENAME_NOREPLACE) + || flag.contains(Renameat2Flags::RENAME_WHITEOUT)) + { + return Err(LinuxErrno::EINVAL); + } + + old_path.rename_to( + syscontext_for_vfs(process.access_inner().cwd()), + new_path, + VfsRenameFlag::from_bits_truncate(flag.bits()), + )?; + Ok(0) +} + +/// 一个系统调用,用于在文件描述符之间传递数据。 +/// +/// 从 `in_fd` 读取最多 `count` 个字符,存到 `out_fd` 中。 +/// - 如果 `offset != 0`,则其指定了 `in_fd` 中文件的偏移,此时完成后会修改 `offset` 为读取后的位置,但不更新文件内部的 `offset` +/// - 否则,正常更新文件内部的 `offset` +/// +/// Reference: [send_file](https://man7.org/linux/man-pages/man2/sendfile64.2.html) +#[syscall_func(71)] +pub fn send_file( + out_fd: usize, + in_fd: usize, + offset_ptr: usize, + count: usize, +) -> AlienResult { + warn!( + "send_file: in_fd: {:?}, out_fd: {:?}, offset_ptr: {:?}, count: {:?}", + in_fd, out_fd, offset_ptr, count + ); + let task = current_task().unwrap(); + let in_file = task.get_file(in_fd).ok_or(LinuxErrno::EINVAL)?; + let out_file = task.get_file(out_fd).ok_or(LinuxErrno::EINVAL)?; + + if !(in_file.is_readable() && out_file.is_writable()) { + return Err(LinuxErrno::EBADF); + } + + let mut buf = vec![0u8; count]; + + let nbytes = match offset_ptr { + // offset 为零则要求更新实际文件 + 0 => in_file.read(&mut buf)?, + _ => { + // offset 非零则要求不更新实际文件,更新这个用户给的值 + let offset_ptr = task.transfer_raw_ptr(offset_ptr as *mut u64); + let nbytes = in_file.read_at(*offset_ptr, &mut buf)?; + *offset_ptr += nbytes as u64; + nbytes + } + }; + info!("sys_sendfile: read {} bytes from in_file", nbytes); + let w = out_file.write(&buf[0..nbytes as usize])?; + Ok(w as _) +} + +/// 一个系统调用函数,用于包把含更新文件的所有内核缓冲区(包含数据块、指针块、元数据等)都flush到磁盘上。 +#[syscall_func(81)] +pub fn sync() -> isize { + 0 +} + +/// 用于把打开的文件描述符fd相关的所有缓冲元数据和数据都刷新到磁盘上。 +#[syscall_func(82)] +pub fn fsync(fd: usize) -> AlienResult { + let task = current_task().unwrap(); + let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let fs = file.inode().get_super_block()?; + fs.sync_fs(false)?; + Ok(0) +} + +#[syscall_func(285)] +pub fn copy_file_range( + fd_in: isize, + off_in_ptr: usize, + fd_out: isize, + off_out_ptr: usize, + len: usize, + _flag: usize, +) -> AlienResult { + info!( + "copy_file_range: {:?} {:?} {:?} {:?} {:?}", + fd_in, off_in_ptr, fd_out, off_out_ptr, len + ); + let task = current_task().unwrap(); + let in_file = task.get_file(fd_in as usize).ok_or(LinuxErrno::EBADF)?; + let out_file = task.get_file(fd_out as usize).ok_or(LinuxErrno::EBADF)?; + if !(in_file.is_readable() && out_file.is_writable()) { + return Err(LinuxErrno::EBADF); + } + let mut buf = vec![0u8; len]; + let r = if off_in_ptr == 0 { + in_file.read(&mut buf)? + } else { + // offset 非零则要求不更新实际文件,更新这个用户给的值 + let off_in_ptr = task.transfer_raw_ptr(off_in_ptr as *mut u64); + let nr = in_file.read_at(*off_in_ptr, &mut buf)?; + *off_in_ptr += nr as u64; + nr + }; + info!("sys_copy_file_range: read {} bytes from in_file", r); + let w = if off_out_ptr == 0 { + out_file.write(&buf[..r])? + } else { + let off_out_ptr = task.transfer_raw_ptr(off_out_ptr as *mut u64); + let wr = out_file.write_at(*off_out_ptr, &buf[..r])?; + *off_out_ptr += wr as u64; + wr + }; + info!("sys_copy_file_range: write {} bytes to out_file", w); + Ok(w as _) +} diff --git a/kkernel/src/fs/control.rs b/kkernel/src/fs/control.rs new file mode 100644 index 00000000..9998c438 --- /dev/null +++ b/kkernel/src/fs/control.rs @@ -0,0 +1,263 @@ +use log::{info, warn}; +use crate::fs::user_path_at; +use crate::task::current_task; +use constants::io::{FaccessatFlags, FaccessatMode, Fcntl64Cmd, OpenFlags, TeletypeCommand}; +use constants::{AlienResult, AT_FDCWD}; +use constants::LinuxErrno; +use syscall_table::syscall_func; +use vfscore::utils::*; +use timer::TimeSpec; + +const FD_CLOEXEC: usize = 1; + +/// 一个系统调用,用于对一个文件提供控制。 +/// +/// `fd` 指明要操作的文件的描述符;`cmd` 指明控制操作的类型;`arg` 指明操作的参数。 +/// +/// 目前 Alien 中 fcntl 支持的 `cmd` 类型有:(更多可见 [`Fcntl64Cmd`] ) +/// + F_DUPFD: 复制一个现有的文件描述符,此时返回新的文件描述符 new_fd; +/// + F_DUPFD_CLOEXEC: 复制一个现有的文件描述符,同时修改文件的 flags,使得 `O_CLOSEEXEC`位 为1,返回新的文件描述符 new_fd; +/// + F_GETFD: 返回 fd 所指向的文件的 flags 中的 `O_CLOSEEXEC`位。 +/// + F_SETFD: 设置 fd 所指向的文件的 flags 的 `O_CLOSEEXEC`位,由参数arg的 `FD_CLOEXEC` 位决定。 设置成功返回 0。 +/// + F_GETFL: 返回 fd 所指向的文件的 flags。 +/// + F_SETFL: 根据 arg 设置 fd 的 flags,可以采用的 arg 可见 [`OpenFlags`]。 +/// + 其它操作类型均会使得函数返回 EINVAL。 +/// +/// Reference: [fcntl](https:///man7.org/linux/man-pages/man2/fcntl.2.html) +#[syscall_func(25)] +pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> AlienResult { + let task = current_task().unwrap(); + let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let cmd = Fcntl64Cmd::try_from(cmd).map_err(|_| LinuxErrno::EINVAL)?; + info!("fcntl:{:?} {:?} ", cmd, arg); + match cmd { + Fcntl64Cmd::F_DUPFD => { + let fd = task.add_file(file.clone()).unwrap(); + return Ok(fd as isize); + } + Fcntl64Cmd::F_DUPFD_CLOEXEC => { + let new_file = file.clone(); + new_file.set_open_flag(new_file.get_open_flag() | OpenFlags::O_CLOEXEC); + let new_fd = task.add_file(new_file).unwrap(); + return Ok(new_fd as isize); + } + Fcntl64Cmd::F_GETFD => { + return if file.get_open_flag().contains(OpenFlags::O_CLOEXEC) { + Ok(1) + } else { + Ok(0) + }; + } + Fcntl64Cmd::F_SETFD => { + info!("fcntl: F_SETFD :{:?}", arg & FD_CLOEXEC); + let open_flag = file.get_open_flag(); + if arg & FD_CLOEXEC == 0 { + file.set_open_flag(open_flag & !OpenFlags::O_CLOEXEC); + } else { + file.set_open_flag(open_flag | OpenFlags::O_CLOEXEC); + } + } + Fcntl64Cmd::F_GETFL => { + return Ok(file.get_open_flag().bits() as isize); + } + Fcntl64Cmd::F_SETFL => { + let flag = OpenFlags::from_bits_truncate(arg); + info!("fcntl: F_SETFL :{:?}", flag,); + file.set_open_flag(flag); + } + Fcntl64Cmd::GETLK | Fcntl64Cmd::SETLK | Fcntl64Cmd::SETLKW => { + info!("fcntl: GETLK SETLK SETLKW now ignored"); + } + _ => { + return Err(LinuxErrno::EINVAL.into()); + } + } + Ok(0) +} + +/// 一个系统调用,用于管理 IO 设备。一个字符设备驱动通常会实现设备打开、关闭、读、写等功能, +/// 在一些需要细分的情境下,如果需要扩展新的功能,通常以增设 ioctl() 命令的方式实现。 +/// +/// `fd` 指明要操作的设备的文件描述符;`cmd` 指明控制操作的类型, +/// 目前 Alien 支持的 ioctl 操作可见 [`TeletypeCommand`] 和 `rvfs` 中有关 `ioctl` 的支持; +/// `arg` 指明操作的参数。 +/// +/// 根据不同的 ioctl 命令,将有不同的返回值。 +/// +/// Reference: [ioctl](https:///man7.org/linux/man-pages/man2/ioctl.2.html) +#[syscall_func(29)] +pub fn ioctl(fd: usize, cmd: usize, arg: usize) -> AlienResult { + let process = current_task().unwrap(); + let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let cmd = TeletypeCommand::try_from(cmd as u32).map_err(|_| LinuxErrno::EINVAL)?; + info!("ioctl: {:?} {:?} {:?}", fd, cmd, arg); + let res = file.ioctl(cmd as u32, arg)?; + Ok(res as isize) +} + +const UTIME_NOW: usize = 0x3fffffff; +/// ignore +#[allow(dead_code)] +const UTIME_OMIT: usize = 0x3ffffffe; + +/// 一个系统调用,用于获取 相对于一个目录某位置处 的一个文件上一次的访问时间和修改时间。 +/// +/// 当传入的 `path` 是一个相对地址时,那么 `path` 会被解析成基于文件描述符 `fd` 所指向的目录地址的一个地址;当传入的 `path` 是一个相对地址并且 +/// `fd` 被特殊的设置为 `AT_FDCWD` 时,`path` 会被解析成基于调用该系统调用的进程当前工作目录的一个地址; +/// 当传入的 `path` 是一个绝对地址时,`fd`将被直接忽略。 +/// +/// `times` 指向了一个 `TimeSpec[2]` 的一个数组,其中 TimeSpec[0] 将保存文件上一次访问时间,TimeSpec[1] 将保存文件上一次修改时间。 +/// 用户可从传入的两个 `TimeSpec` 结构中修改 `tv_nsec` 字段值来使得查询到的访问时间变为 上一次的操作时间(`UTIME_OMT`)、当前时间(`UTIME_NOW`)或 0。 +/// +/// `flag` 的值目前还未用到。 +#[syscall_func(88)] +pub fn utimensat( + fd: usize, + path: *const u8, + times: *const u8, + _flags: usize, +) -> AlienResult { + if fd as isize != AT_FDCWD && (fd as isize) < 0 { + return Err(LinuxErrno::EBADF.into()); + } + let task = current_task().unwrap(); + + let dt = if fd as isize > 0 { + let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; + file.dentry() + } else { + let path = task.transfer_str(path); + let path = user_path_at(fd as isize, &path)?; + let dt = path.open(None)?; + dt + }; + + let mut inner = task.access_inner(); + if times.is_null() { + warn!( + "utimensat: {:?} {:?} {:?} {:?}", + fd as isize, + path, + TimeSpec::now(), + TimeSpec::now() + ); + dt.inode()?.update_time( + VfsTime::AccessTime(TimeSpec::now().into()), + TimeSpec::now().into(), + )?; + dt.inode()?.update_time( + VfsTime::AccessTime(TimeSpec::now().into()), + TimeSpec::now().into(), + )?; + } else { + let mut atime = TimeSpec::new(0, 0); + let mut mtime = TimeSpec::new(0, 0); + inner.copy_from_user(times as *const TimeSpec, &mut atime); + unsafe { + inner.copy_from_user((times as *const TimeSpec).add(1), &mut mtime); + } + warn!( + "utimensat: {:?} {:?} {:?} {:?}", + fd as isize, path, atime, mtime + ); + if atime.tv_nsec == UTIME_NOW { + dt.inode()?.update_time( + VfsTime::AccessTime(TimeSpec::now().into()), + TimeSpec::now().into(), + )?; + } else if atime.tv_nsec == UTIME_OMIT { + // do nothing + } else { + dt.inode()? + .update_time(VfsTime::AccessTime(atime.into()), TimeSpec::now().into())?; + }; + if mtime.tv_nsec == UTIME_NOW { + dt.inode()?.update_time( + VfsTime::ModifiedTime(TimeSpec::now().into()), + TimeSpec::now().into(), + )?; + } else if mtime.tv_nsec == UTIME_OMIT { + // do nothing + } else { + dt.inode()? + .update_time(VfsTime::ModifiedTime(mtime.into()), TimeSpec::now().into())?; + }; + }; + + Ok(0) +} + +/// 一个系统调用,用于检测当前进程是否有权限访问一个文件。 +/// +/// 文件的路径由 `dirfd` 和 `path` 解析得到。解析相关信息可见 [`user_path_at`]。 +/// 目前 `mode` 和 `flag` 都未使用。仅检测当前进程是否有打开对应路径下文件的权限。 +/// +/// 如果有打开的权限,则返回 0;否则返回 -1。 +#[syscall_func(48)] +pub fn faccessat(dirfd: isize, path: usize, mode: usize, flag: usize) -> AlienResult { + let task = current_task().unwrap(); + let path = task.transfer_str(path as *const u8); + let mode = FaccessatMode::from_bits_truncate(mode as u32); + let flag = FaccessatFlags::from_bits_truncate(flag as u32); + info!( + "faccessat file: {:?},flag:{:?}, mode:{:?}", + path, flag, mode + ); + // todo! check the AT_SYMLINK_NOFOLLOW flag + let _path = user_path_at(dirfd, &path)?.open(None)?; + Ok(0) +} + +/// 一个系统调用函数,用于修改文件或目录的权限。(待实现) +/// +/// 在Alien系统中,每个文件或目录都有一个权限位, +/// 用于控制该文件或目录的访问权限。sys_chmod函数可以用于修改这些权限位。 +/// +/// sys_chmod函数需要传入两个参数:第一个参数是需要要修改的文件的文件描述符, +/// 第二个参数是新的权限值。 +/// +/// Reference: [chmod](https:///man7.org/linux/man-pages/man2/chmod.2.html) +#[syscall_func(52)] +pub fn chmod(_fd: usize, _mode: usize) -> isize { + 0 +} + +/// (待实现)一个系统调用函数,用于修改相对于某目录某位置处文件或目录的权限。 +/// +/// 当传入的`path`是一个相对地址时,那么`path`会被解析成基于文件描述符`dirfd` +/// 所指向的目录地址的一个地址;当传入的`path`是一个相对地址并且 +/// `dirfd`被特殊的设置为`AT_FDCWD`时,`path`会 +/// 被解析成基于调用该系统调用的进程当前工作目录的一个地址; +/// 当传入的`path`是一个绝对地址时,`dirfd`将被直接忽略。 +/// +/// 当解析出的地址指向的文件是一个软链接时,将根据传入的`flag`的值进行以下的内容: +/// + 若`flag`为0,则将对软链接进行解析,修改软链接的目标文件的权限 +/// + 若`flag`为AT_SYMLINK_NOFOLLOW,则将不对软链接进行解析,直接修改该文件的权限 +/// +/// `flag`处可以传入的值及其含义包括: +/// + AT_SYMLINK_NOFOLLOW: 0x200,如果`path`解析之后指向的文件是一个软链接时,不对软链接进行解析,直接修改该文件的权限 +/// +/// `flag`可以置为AT_SYMLINK_NOFOLLOW或者为0。 +/// +/// Reference: [chmod](https:///man7.org/linux/man-pages/man2/chmod.2.html) +#[syscall_func(53)] +pub fn chmodat(_dirfd: usize, _path: usize, _mode: usize, _flags: usize) -> isize { + 0 +} + +/// 一个系统调用,用于获取并设置当前进程的 `unmask`。在一个进程中,unmask 用于定义新建文件或目录的默认权限。 +/// 每次新建一个文件时,文件的默认权限是由 unmask 的值决定的。如果 unmask 值的某位被设置,在新建文件或目录时将禁用对应的权限。 +/// +/// 函数执行成功后,将会把当前进程的 unmask 值置为传入的 `unmask`,同时返回原来的 unmask 值。 +#[syscall_func(55)] +pub fn fchown() -> isize { + 0 +} + +#[syscall_func(166)] +pub fn unmask(unmask: usize) -> isize { + let task = current_task().unwrap(); + let old_unmask = task.access_inner().unmask; + task.access_inner().unmask = unmask; + old_unmask as isize +} diff --git a/kkernel/src/fs/ext.rs b/kkernel/src/fs/ext.rs new file mode 100644 index 00000000..c1d902be --- /dev/null +++ b/kkernel/src/fs/ext.rs @@ -0,0 +1,231 @@ +use constants::{AT_FDCWD, LinuxErrno}; +use core::cmp::min; +use syscall_table::syscall_func; +use vfscore::path::VfsPath; +use constants::AlienResult; +use crate::fs::user_path_at; +use crate::task::current_task; + +/// 一个系统调用,用于设置文件的 扩展属性(xattrs, Extended Attributes)。 +/// +/// 扩展属性(xattrs)提供了一个机制用来将一个(键, 值)对永久地关联到文件,让现有的文件系统得以支持在原始设计中未提供的功能。扩展属性是文件系统不可知论者, +/// 应用程序可以通过一个标准的接口来操纵他们,此接口不因文件系统而异。每个扩展属性可以通过唯一的键来区分,键的内容必须是有效的UTF-8,格式为namespace.attribute, +/// 每个键采用完全限定的形式。 +/// +/// 参数: +/// + `path`: 用于指明要操作文件的路径; +/// + `name`: 用于指明要设置的扩展属性的 `key` 名称,是一个字符串的首地址; +/// + `value`: 用于指明要设置的扩展属性值 `value`,是一段缓冲区的首地址; +/// + `size`: 用于指明缓冲区的长度。请注意该长度最好不要超过一个帧的大小 (4K); +/// + `flag`: 用于调整操作的类型。目前 Alien 中默认未使用该值,请保证该值为0,否则会导致函数 panic。 +/// +/// 返回值: 当设置扩展属性成功时,返回 0;否则返回 -1 表示设置失败。 +/// Reference: https://man7.org/linux/man-pages/man2/setxattr.2.html +#[syscall_func(5)] +pub fn sys_setxattr( + path: *const u8, + name: *const u8, + value: *const u8, + size: usize, + flag: usize, +) -> AlienResult { + // we ignore flag + assert_eq!(flag, 0); + let process = current_task().unwrap(); + let path = process.transfer_str(path); + let name = process.transfer_str(name); + let value = process.transfer_buffer(value, size); + let path = user_path_at(AT_FDCWD, &path)?; + path.set_xattr(&name, value[0])?; + Ok(0) +} + +/// 一个系统调用,用于设置文件的 扩展属性(xattrs, Extended Attributes)。在功能上与 [`sys_setxattr`] 相似。 +/// 唯一的不同点是 `sys_lsetxattr` 不允许设置软链接文件。 +/// +/// 目前的实现为直接调用 [`sys_setxattr`]。 +#[syscall_func(6)] +pub fn sys_lsetxattr( + path: *const u8, + name: *const u8, + value: *const u8, + size: usize, + flag: usize, +) -> AlienResult { + sys_setxattr(path, name, value, size, flag) +} + +/// 一个系统调用,用于设置文件的 扩展属性(xattrs, Extended Attributes)。在功能和实现上与 [`sys_setxattr`] 相似。 +/// 唯一的不同点是 `sys_fsetxattr` 采用文件描述符 `fd` 查找文件,而非文件路径 `path`。 +/// +/// 有关其它参数和 扩展属性 的相关信息可见 [`sys_setxattr`]。 +#[syscall_func(7)] +pub fn sys_fsetxattr( + fd: usize, + name: *const u8, + value: *const u8, + size: usize, + flag: usize, +) -> AlienResult { + // we ignore flag + assert_eq!(flag, 0); + let process = current_task().unwrap(); + let name = process.transfer_str(name); + let value = process.transfer_buffer(value, size); + let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let path = VfsPath::new(file.dentry()); + path.set_xattr(&name, value[0])?; + Ok(0) +} + +/// 一个系统调用,用于获取文件的扩展属性值。有关 扩展属性 的相关信息可见 [`sys_setxattr`]。 +/// +/// 参数: +/// + `path`: 用于指明要操作文件的路径; +/// + `name`: 用于指明要获取的扩展属性的 `key` 名称,是一个字符串的首地址; +/// + `value`: 用于指明要获取的扩展属性值 `value` 保存的位置,是一段缓冲区的首地址; +/// + `size`: 用于指明缓冲区的长度。请注意该长度最好不要超过一个帧的大小 (4K)。 +/// +/// 如果获取扩展属性值成功,返回获取到的扩展属性值的长度;否则返回 -1 表示获取扩展属性值失败。 +/// +/// Reference: https://man7.org/linux/man-pages/man2/getxattr.2.html +#[syscall_func(8)] +pub fn sys_getxattr( + path: *const u8, + name: *const u8, + value: *const u8, + size: usize, +) -> AlienResult { + let process = current_task().unwrap(); + let path = process.transfer_str(path); + let name = process.transfer_str(name); + let mut value = process.transfer_buffer(value, size); + let path = user_path_at(AT_FDCWD, &path)?; + let res = path.get_xattr(&name)?; + let mut copy = 0; + value.iter_mut().for_each(|x| { + let min_copy = min(x.len(), res.len() - copy); + x.copy_from_slice(&res[copy..copy + min_copy]); + copy += min_copy; + }); + Ok(copy as _) +} + +/// 一个系统调用,用于获取文件的 扩展属性。在功能上与 [`sys_getxattr`] 相似。 +/// 唯一的不同点是 `sys_lgetxattr` 不允许获取软链接文件的 扩展属性。 +/// +/// 目前的实现为直接调用 [`sys_getxattr`]。 +#[syscall_func(9)] +pub fn sys_lgetxattr( + path: *const u8, + name: *const u8, + value: *const u8, + size: usize, +) -> AlienResult { + sys_getxattr(path, name, value, size) +} + +/// 一个系统调用,用于获取文件的 扩展属性。在功能上与 [`sys_getxattr`] 相似。 +/// 唯一的不同点是 `sys_fgetxattr` 采用文件描述符 `fd` 查找文件,而非文件路径 `path`。 +/// +/// 有关其它参数和 扩展属性 的相关信息可见 [`sys_getxattr`] 和 [`sys_setxattr`]。 +#[syscall_func(10)] +pub fn sys_fgetxattr( + fd: usize, + name: *const u8, + value: *const u8, + size: usize, +) -> AlienResult { + let process = current_task().unwrap(); + let name = process.transfer_str(name); + let mut value = process.transfer_buffer(value, size); + let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let path = VfsPath::new(file.dentry()); + let res = path.get_xattr(&name)?; + let mut copy = 0; + value.iter_mut().for_each(|x| { + let min_copy = min(x.len(), res.len() - copy); + x.copy_from_slice(&res[copy..copy + min_copy]); + copy += min_copy; + }); + Ok(copy as _) +} + +/// 一个系统调用,用于获取一个文件的所有扩展属性类型 。有关 扩展属性 的相关信息可见 [`sys_setxattr`]。 +/// +/// 参数: +/// + `path`: 用于指明要操作文件的路径; +/// + `list`: 用于指明要获取的所有扩展属性类型保存的位置,是一段缓冲区的首地址; +/// + `size`: 用于指明缓冲区的长度。请注意该长度最好不要超过一个帧的大小 (4K)。 +/// +/// 如果获取扩展属性类型成功,返回获取到的扩展属性类型的长度(总字节数);否则返回 -1 表示获取扩展属性类型失败。 +/// +/// Note: 获取到的拓展属性类型类似于 `user.name1/0system.name1/0user.name2/0`,每个拓展属性类型后都会使用 `/0` 表示该种拓展属性类型结束。 +/// +/// Reference: https://man7.org/linux/man-pages/man2/listxattr.2.html +#[syscall_func(11)] +pub fn sys_listxattr(path: *const u8, list: *const u8, size: usize) -> AlienResult { + let process = current_task().unwrap(); + let _path = process.transfer_str(path); + let _list = process.transfer_buffer(list, size); + unimplemented!(); +} + +/// 一个系统调用,用于获取一个文件的所有扩展属性类型。在功能上与 [`sys_listxattr`] 相似。 +/// 唯一的不同点是 `sys_llistxattr` 不允许获取软链接文件的所有扩展属性类型。 +/// +/// 目前的实现为直接调用 [`sys_listxattr`]。 +#[syscall_func(12)] +pub fn sys_llistxattr(path: *const u8, list: *const u8, size: usize) -> AlienResult { + sys_listxattr(path, list, size) +} + +/// 一个系统调用,用于获取一个文件的所有扩展属性类型。在功能上与 [`sys_listxattr`] 相似。 +/// 唯一的不同点是 `sys_flistxattr` 采用文件描述符 `fd` 查找文件,而非文件路径 `path`。 +/// +/// 有关其它参数和 扩展属性 的相关信息可见 [`sys_listxattr`] 和 [`sys_setxattr`]。 +#[syscall_func(13)] +pub fn sys_flistxattr(fd: usize, list: *const u8, size: usize) -> AlienResult { + let process = current_task().unwrap(); + let _list = process.transfer_buffer(list, size); + let _file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + unimplemented!(); +} + +/// 一个系统调用,用于删除文件的某个扩展属性值。有关 扩展属性 的相关信息可见 [`sys_setxattr`]。 +/// +/// 参数: +/// + `path`: 用于指明要操作文件的路径; +/// + `name`: 用于指明要删除的扩展属性的 `key` 名称,是一个字符串的首地址。 +/// +/// 如果删除扩展属性值成功,返回0;否则返回 -1 表示删除扩展属性值失败。 +/// +/// Reference: https://man7.org/linux/man-pages/man2/removexattr.2.html +#[syscall_func(14)] +pub fn sys_removexattr(path: *const u8, name: *const u8) -> AlienResult { + let process = current_task().unwrap(); + let _path = process.transfer_str(path); + let _name = process.transfer_str(name); + unimplemented!(); +} + +/// 一个系统调用,用于删除文件的某个扩展属性值。在功能上与 [`sys_removexattr`] 相似。 +/// 唯一的不同点是 `sys_lremovexattr` 不允许删除软链接文件的扩展属性值。 +/// +/// 目前的实现为直接调用 [`sys_removexattr`]。 +#[syscall_func(15)] +pub fn sys_lremovexattr(path: *const u8, name: *const u8) -> AlienResult { + sys_removexattr(path, name) +} + +/// 一个系统调用,用于删除文件的某个扩展属性值型。在功能上与 [`sys_removexattr`] 相似。 +/// 唯一的不同点是 `sys_fremovexattr` 采用文件描述符 `fd` 查找文件,而非文件路径 `path`。 +/// +/// 有关其它参数和 扩展属性 的相关信息可见 [`sys_removexattr`] 和 [`sys_setxattr`]。 +#[syscall_func(16)] +pub fn sys_fremovexattr(fd: usize, name: *const u8) -> AlienResult { + let process = current_task().unwrap(); + let _name = process.transfer_str(name); + let _file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + unimplemented!(); +} diff --git a/kkernel/src/fs/file.rs b/kkernel/src/fs/file.rs new file mode 100644 index 00000000..f6f01bbe --- /dev/null +++ b/kkernel/src/fs/file.rs @@ -0,0 +1,278 @@ +use constants::io::DirentType; +pub use kernel_file::{File, KernelFile}; +use vfscore::utils::VfsNodeType; + +mod kernel_file { + use super::vfsnodetype2dirent64; + use alloc::sync::Arc; + use constants::io::{Dirent64, OpenFlags, PollEvents, SeekFrom}; + use constants::AlienResult; + use constants::LinuxErrno; + use core::fmt::{Debug, Formatter}; + use downcast_rs::{impl_downcast, DowncastSync}; + use ksync::Mutex; + use vfscore::dentry::VfsDentry; + use vfscore::error::VfsError; + use vfscore::inode::VfsInode; + use vfscore::path::VfsPath; + use vfscore::utils::{VfsFileStat, VfsPollEvents}; + pub struct KernelFile { + pos: Mutex, + open_flag: Mutex, + dentry: Arc, + } + + impl Debug for KernelFile { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("KernelFile") + .field("pos", &self.pos) + .field("open_flag", &self.open_flag) + .field("name", &self.dentry.name()) + .finish() + } + } + + impl KernelFile { + pub fn new(dentry: Arc, open_flag: OpenFlags) -> Self { + let pos = if open_flag.contains(OpenFlags::O_APPEND) { + dentry.inode().unwrap().get_attr().unwrap().st_size + } else { + 0 + }; + Self { + pos: Mutex::new(pos), + open_flag: Mutex::new(open_flag), + dentry, + } + } + } + + pub trait File: DowncastSync + Debug { + fn read(&self, buf: &mut [u8]) -> AlienResult; + fn write(&self, buf: &[u8]) -> AlienResult; + fn read_at(&self, _offset: u64, _buf: &mut [u8]) -> AlienResult { + Err(LinuxErrno::ENOSYS) + } + fn write_at(&self, _offset: u64, _buf: &[u8]) -> AlienResult { + Err(LinuxErrno::ENOSYS) + } + fn flush(&self) -> AlienResult<()> { + Ok(()) + } + fn fsync(&self) -> AlienResult<()> { + Ok(()) + } + fn seek(&self, pos: SeekFrom) -> AlienResult; + /// Gets the file attributes. + fn get_attr(&self) -> AlienResult; + fn ioctl(&self, _cmd: u32, _arg: usize) -> AlienResult { + Err(LinuxErrno::ENOSYS) + } + fn set_open_flag(&self, _flag: OpenFlags) {} + fn get_open_flag(&self) -> OpenFlags { + OpenFlags::O_RDONLY + } + fn dentry(&self) -> Arc; + fn inode(&self) -> Arc; + fn readdir(&self, _buf: &mut [u8]) -> AlienResult { + Err(LinuxErrno::ENOSYS) + } + fn truncate(&self, _len: u64) -> AlienResult<()> { + Err(LinuxErrno::ENOSYS) + } + fn is_readable(&self) -> bool; + fn is_writable(&self) -> bool; + fn is_append(&self) -> bool; + fn poll(&self, _event: PollEvents) -> AlienResult { + Err(LinuxErrno::ENOSYS) + } + } + + impl_downcast!(sync File); + + // todo! permission check + impl File for KernelFile { + fn read(&self, buf: &mut [u8]) -> AlienResult { + if buf.len() == 0 { + return Ok(0); + } + // warn!("[read] is_interrupt_enable:{}",is_interrupt_enable()); + let pos = *self.pos.lock(); + // warn!("[read] is_interrupt_enable:{}",is_interrupt_enable()); + let read = self.read_at(pos, buf)?; + *self.pos.lock() += read as u64; + Ok(read) + } + fn write(&self, buf: &[u8]) -> AlienResult { + if buf.len() == 0 { + return Ok(0); + } + let mut pos = self.pos.lock(); + let write = self.write_at(*pos, buf)?; + *pos += write as u64; + Ok(write) + } + fn read_at(&self, offset: u64, buf: &mut [u8]) -> AlienResult { + if buf.len() == 0 { + return Ok(0); + } + let open_flag = self.open_flag.lock(); + if !open_flag.contains(OpenFlags::O_RDONLY) && !open_flag.contains(OpenFlags::O_RDWR) { + return Err(LinuxErrno::EPERM); + } + drop(open_flag); + let inode = self.dentry.inode()?; + let read = inode.read_at(offset, buf)?; + Ok(read) + } + + fn write_at(&self, _offset: u64, buf: &[u8]) -> AlienResult { + if buf.len() == 0 { + return Ok(0); + } + let open_flag = self.open_flag.lock(); + if !open_flag.contains(OpenFlags::O_WRONLY) && !open_flag.contains(OpenFlags::O_RDWR) { + return Err(LinuxErrno::EPERM); + } + let inode = self.dentry.inode()?; + let write = inode.write_at(_offset, buf)?; + Ok(write) + } + + fn flush(&self) -> AlienResult<()> { + let open_flag = self.open_flag.lock(); + if !open_flag.contains(OpenFlags::O_WRONLY) & !open_flag.contains(OpenFlags::O_RDWR) { + return Err(LinuxErrno::EPERM); + } + let inode = self.dentry.inode()?; + inode.flush()?; + Ok(()) + } + + fn fsync(&self) -> AlienResult<()> { + let open_flag = self.open_flag.lock(); + if !open_flag.contains(OpenFlags::O_WRONLY) && !open_flag.contains(OpenFlags::O_RDWR) { + return Err(LinuxErrno::EPERM); + } + let inode = self.dentry.inode()?; + inode.fsync()?; + Ok(()) + } + + // check for special file + fn seek(&self, pos: SeekFrom) -> AlienResult { + let mut spos = self.pos.lock(); + let size = self.get_attr()?.st_size; + let new_offset = match pos { + SeekFrom::Start(pos) => Some(pos), + SeekFrom::Current(off) => spos.checked_add_signed(off), + SeekFrom::End(off) => size.checked_add_signed(off), + } + .ok_or_else(|| VfsError::Invalid)?; + *spos = new_offset; + Ok(new_offset) + } + + /// Gets the file attributes. + fn get_attr(&self) -> AlienResult { + self.dentry.inode()?.get_attr().map_err(Into::into) + } + + fn ioctl(&self, _cmd: u32, _arg: usize) -> AlienResult { + let inode = self.dentry.inode().unwrap(); + inode.ioctl(_cmd, _arg).map_err(Into::into) + } + + fn set_open_flag(&self, flag: OpenFlags) { + *self.open_flag.lock() = flag; + } + + fn get_open_flag(&self) -> OpenFlags { + *self.open_flag.lock() + } + fn dentry(&self) -> Arc { + self.dentry.clone() + } + fn inode(&self) -> Arc { + self.dentry.inode().unwrap() + } + fn readdir(&self, buf: &mut [u8]) -> AlienResult { + let inode = self.inode(); + let mut pos = self.pos.lock(); + let mut count = 0; + let mut ptr = buf.as_mut_ptr(); + loop { + let dirent = inode.readdir(*pos as usize).map_err(|e| { + *pos = 0; + e + })?; + match dirent { + Some(d) => { + let dirent64 = + Dirent64::new(&d.name, d.ino, *pos as i64, vfsnodetype2dirent64(d.ty)); + if count + dirent64.len() <= buf.len() { + let dirent_ptr = unsafe { &mut *(ptr as *mut Dirent64) }; + *dirent_ptr = dirent64; + let name_ptr = dirent_ptr.name.as_mut_ptr(); + unsafe { + let mut name = d.name.clone(); + name.push('\0'); + let len = name.len(); + name_ptr.copy_from(name.as_ptr(), len); + ptr = ptr.add(dirent_ptr.len()); + } + count += dirent_ptr.len(); + } else { + break; + } // Buf is small + } + None => { + break; + } // EOF + } + *pos += 1; + } + Ok(count) + } + fn truncate(&self, len: u64) -> AlienResult<()> { + let open_flag = self.open_flag.lock(); + if !open_flag.contains(OpenFlags::O_WRONLY) & !open_flag.contains(OpenFlags::O_RDWR) { + return Err(LinuxErrno::EINVAL); + } + let dt = self.dentry(); + VfsPath::new(dt).truncate(len).map_err(Into::into) + } + fn is_readable(&self) -> bool { + let open_flag = self.open_flag.lock(); + open_flag.contains(OpenFlags::O_RDONLY) | open_flag.contains(OpenFlags::O_RDWR) + } + fn is_writable(&self) -> bool { + let open_flag = self.open_flag.lock(); + open_flag.contains(OpenFlags::O_WRONLY) | open_flag.contains(OpenFlags::O_RDWR) + } + + fn is_append(&self) -> bool { + let open_flag = self.open_flag.lock(); + open_flag.contains(OpenFlags::O_APPEND) + } + + fn poll(&self, _event: PollEvents) -> AlienResult { + let inode = self.dentry.inode()?; + let res = inode + .poll(VfsPollEvents::from_bits_truncate(_event.bits())) + .map(|e| PollEvents::from_bits_truncate(e.bits())); + res.map_err(Into::into) + } + } +} + +fn vfsnodetype2dirent64(ty: VfsNodeType) -> DirentType { + DirentType::from_u8(ty as u8) +} + +impl Drop for KernelFile { + fn drop(&mut self) { + let _ = self.flush(); + let _ = self.fsync(); + } +} diff --git a/kkernel/src/fs/link.rs b/kkernel/src/fs/link.rs new file mode 100644 index 00000000..b7805ac3 --- /dev/null +++ b/kkernel/src/fs/link.rs @@ -0,0 +1,142 @@ +use alloc::vec; +use log::{info, warn}; +use constants::io::{LinkFlags, UnlinkatFlags}; +use syscall_table::syscall_func; + +use crate::{fs::user_path_at, task::current_task}; +use constants::AlienResult; +/// 一个系统调用,用于创建相对于一个目录某位置处的一个文件的(硬)链接。 +/// +/// 当传入的 `old_name` 是一个相对地址时,那么 `old_name` 会被解析成基于文件描述符 `old_fd` +/// 所指向的目录地址的一个地址;当传入的 `old_name` 是一个相对地址并且 +/// `old_fd` 被特殊的设置为 `AT_FDCWD` 时,`old_name` 会 +/// 被解析成基于调用该系统调用的进程当前工作目录的一个地址; +/// 当传入的 `old_name` 是一个绝对地址时,`old_fd` 将被直接忽略。 +/// 对于 `new_name` 同理,将根据 'new_fd' 进行解析。 +/// +/// `flag` 处可以传入的值及其含义包括: +/// + AT_SYMLINK_FOLLOW: 0x400,允许软链接(Follow symbolic links.)。 +/// + AT_EMPTY_PATH: 0x1000,允许 old_name 和 new_name 为空字符串(Allow empty relative pathname.). +/// +/// `flag` 可以为包括上述值 `OR` 运算的结果。 +/// +/// 如果成功创建文件链接,`sys_linkat` 将返回0;否则返回-1或错误类型。 +/// 出错的情况大致包括:当 `old_name` 或 `new_name` 是一个相对地址,`old_fd` 或 `new_fd` 所指向的文件不是一个目录文件; +/// `old_fd` 或 `new_fd` 不是一个有效的文件描述符等。 +/// +/// Reference: [link](https://man7.org/linux/man-pages/man2/link.2.html) +#[syscall_func(37)] +pub fn sys_linkat( + old_fd: isize, + old_name: *const u8, + new_fd: isize, + new_name: *const u8, + flag: usize, +) -> AlienResult { + let flag = LinkFlags::from_bits_truncate(flag as u32); + let process = current_task().unwrap(); + let old_name = process.transfer_str(old_name); + let old_path = user_path_at(old_fd, &old_name)?; + let new_name = process.transfer_str(new_name); + let new_path = user_path_at(new_fd, &new_name)?; + + warn!( + "old_path: {},new_path: {}, flag:{:?}", + old_name, new_name, flag + ); + + let old_dt = old_path.open(None)?; + + new_path.link(old_dt)?; + Ok(0) +} + +/// 一个系统调用,用于删除相对于一个目录某位置处的一个文件的链接。 +/// +/// `unlinkat`执行的操作将根据`flag`参数是否设置为`AT_REMOVEDIR`而执行`unlink`或`rmdir`操作。 +/// 不同情况下,`unlinkat`删除文件链接成功的结果包括: +/// + 如果要删除的链接是软链接,直接删除链接; +/// + 如果要删除的链接是硬连接,并且不是指向该文件的最后一个链接,那么直接删除链接; +/// + 如果要删除的链接是硬连接,并且是指向该文件的最后一个链接 +/// + 如果该文件在某进程中处于打开状态,该文件会一直存活到进程关闭其文件描述符,而后被删除。 +/// + 如果该文件没有任何进程目前正在打开,该文件会被删除,并回收其所占的存储空间。 +/// +/// 当传入的`path`是一个相对地址时,那么`path`会被解析成基于文件描述符`fd` +/// 所指向的目录地址的一个地址;当传入的`path`是一个相对地址并且 +/// `fd`被特殊的设置为`AT_FDCWD`时,`path`会 +/// 被解析成基于调用该系统调用的进程当前工作目录的一个地址; +/// 当传入的`path`是一个绝对地址时,`fd`将被直接忽略。 +/// +/// +/// `flag`处可以传入的值及其含义包括: +/// + AT_REMOVEDIR: 0x200,`sys_linkat`将执行`rmdir`操作。(`rmdir`要求要删除的目录必须为空) +/// +/// `flag`可以置为AT_REMOVEDIR或者为0。 +/// +/// 如果成功删除文件链接,`sys_linkat`将返回0;否则返回-1或错误类型。 +/// +/// Reference: +/// + [unlink](https://man7.org/linux/man-pages/man2/unlink.2.html) +/// + [rmdir](https://man7.org/linux/man-pages/man2/rmdir.2.html) +/// +#[syscall_func(35)] +pub fn sys_unlinkat(fd: isize, path: *const u8, flag: usize) -> AlienResult { + let task = current_task().unwrap(); + let path = task.transfer_str(path); + let flag = UnlinkatFlags::from_bits_truncate(flag as u32); + info!("unlinkat path: {:?}, flag: {:?}", path, flag); + let path = user_path_at(fd, &path)?; + if flag.contains(UnlinkatFlags::AT_REMOVEDIR) { + path.rmdir()?; + } else { + path.unlink()?; + } + Ok(0) +} + +/// 一个系统调用,用于创建一个指向 `oldname` 的新目录项. +/// +/// `old_name` 指明 要链接到的目录位置;新目录项的位置将由 `new_fd` 和 `new_name` 一起解析出,有关解析的相关信息可见 [`user_path_at`]。 +/// +/// 若创建链接成功,则返回 0;否则返回 -1。 +#[syscall_func(36)] +pub fn sys_symlinkat( + old_name: *const u8, + new_fd: isize, + new_name: *const u8, +) -> AlienResult { + let process = current_task().unwrap(); + let old_name = process.transfer_str(old_name); + let new_name = process.transfer_str(new_name); + let new_path = user_path_at(new_fd, &new_name)?; + new_path.symlink(&old_name)?; + Ok(0) +} + +/// 一个系统调用,从相对于 一个目录某位置处 的一个软链接文件处读取文件的软链接内容(即链接到文件的路径)。 +/// +/// 要读取的文件的路径由 `fd` 和 `path` 解析得出。Alien 中有关 `fd` 和 `path` 的路径解析可见 [`user_path_at`] (解析出的文件需是一个软链接文件,否则函数将返回 `ENOENT`)。 +/// `buf` 指明了读取内容要保存到的缓冲区首地址,`size` 指明了缓冲区的大小,即所能保存的内容的最大值。 +/// +/// 若读取成功,则返回读取内容的长度(即链接到文件的路径的长度);否则返回错误码。 +#[syscall_func(78)] +pub fn sys_readlinkat(fd: isize, path: *const u8, buf: *mut u8, size: usize) -> AlienResult { + let process = current_task().unwrap(); + let path = process.transfer_str(path); + info!("readlink path: {}", path); + let path = user_path_at(fd, &path)?; + let dt = path.open(None)?; + let mut empty_buf = vec![0u8; size]; + let r = dt.inode()?.readlink(empty_buf.as_mut_slice())?; + let buf = process.transfer_buffer(buf, size); + let mut w = 0; + for buf in buf { + let len = buf.len(); + buf.copy_from_slice(&empty_buf[w..w + len]); + w += len; + if w >= r { + break; + } + } + Ok(r as isize) +} diff --git a/kkernel/src/fs/mod.rs b/kkernel/src/fs/mod.rs new file mode 100644 index 00000000..c4cf8510 --- /dev/null +++ b/kkernel/src/fs/mod.rs @@ -0,0 +1,96 @@ +pub mod stdio; +pub mod basic; +pub mod control; +pub mod ext; +pub mod file; +pub mod link; +pub mod poll; +pub mod select; + + +use alloc::vec::Vec; +use log::info; +use vfscore::path::{SysContext, VfsPath}; +use vfscore::utils::{VfsInodeMode, VfsNodeType}; +use constants::{AlienResult, AT_FDCWD, LinuxErrno}; +use constants::io::InodeMode; +use vfs::SYSTEM_ROOT_FS; +use crate::task::{current_task, FsContext}; + +/// 地址解析函数,通过 `fd` 所指向的一个目录文件 和 相对于该目录文件的路径或绝对路径 `path` 解析出某目标文件的绝对路径。 +/// +/// 当传入的`path`是一个相对地址时,那么`path`会被解析成基于文件描述符`fd`所指向的目录地址的一个地址;当传入的`path`是一个相对地址并且 +/// `fd`被特殊的设置为`AT_FDCWD`时,`path`会被解析成基于调用该系统调用的进程当前工作目录的一个地址;当传入的`path`是一个绝对地址时,`fd`将被直接忽略。 +/// +/// 在`Alien`使用的`rvfs`中,对一个文件路径`path`是相对路径还是绝对路径的的判断条件如下: +/// + 绝对路径:以`/`开头,如`/file1.txt`,表示根目录下的`file1.txt`文件; +/// + 相对路径: 以`./`或者`../`或者其它开头,如`./file1.txt`,表示`dirfd`所指向的目录下的`file1.txt`文件。 +fn user_path_at(fd: isize, path: &str) -> AlienResult { + info!("user_path_at fd: {},path:{}", fd, path); + let process = current_task().unwrap(); + let res = if !path.starts_with("/") { + if fd == AT_FDCWD { + let fs_context = process.access_inner().fs_info.clone(); + VfsPath::new(fs_context.cwd).join(path) + } else { + let fd = fd as usize; + let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; + VfsPath::new(file.dentry()).join(path) + } + } else { + VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()).join(path) + }; + res.map_err(|e| e.into()) +} + +pub fn read_all(file_name: &str, buf: &mut Vec) -> bool { + let task = current_task(); + // let cwd = if task.is_some() { + // task.unwrap().access_inner().cwd().cwd + // } else { + // SYSTEM_ROOT_FS.get().unwrap().clone() + // }; + let path = if task.is_none() { + VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()) + .join(file_name) + .unwrap() + } else { + user_path_at(AT_FDCWD, file_name).unwrap() + }; + + let dentry = path.open(None); + if dentry.is_err() { + info!("open file {} failed, err:{:?}", file_name, dentry.err()); + return false; + } + let dentry = dentry.unwrap(); + if dentry.inode().unwrap().inode_type() != VfsNodeType::File { + info!("{} is not a file", file_name); + return false; + } + let size = dentry.inode().unwrap().get_attr().unwrap().st_size; + let mut offset = 0; + while offset < size { + let mut tmp = [0;512]; + let res = dentry.inode().unwrap().read_at(offset, &mut tmp).unwrap(); + offset += res as u64; + buf.extend_from_slice(&tmp); + } + assert_eq!(offset, size); + true +} + +/// [InodeMode](InodeMode)转换为[VfsInodeMode](VfsInodeMode) +fn im2vim(mode: InodeMode) -> VfsInodeMode { + VfsInodeMode::from_bits_truncate(mode.bits()) +} + +fn syscontext_for_vfs(fs_info: FsContext) -> SysContext { + SysContext { + pid: 0, + uid: 0, + gid: 0, + cwd: fs_info.cwd.clone(), + root: fs_info.root.clone(), + } +} diff --git a/kkernel/src/fs/poll.rs b/kkernel/src/fs/poll.rs new file mode 100644 index 00000000..eebde6bb --- /dev/null +++ b/kkernel/src/fs/poll.rs @@ -0,0 +1,93 @@ +use crate::task::{current_task, do_suspend}; +use alloc::vec::Vec; +use log::{info, warn}; +use constants::io::{PollEvents, PollFd}; +use constants::AlienResult; +use constants::LinuxErrno; +use syscall_table::syscall_func; +use timer::TimeSpec; + +/// 一个系统调用,用于在一些文件描述符上等待事件。作用与 [`pselect6`] 相似。 +/// +/// 与 'pselect6' 不同,`ppoll` 并不按照等待事件的类型将所有要等待的文件描述符分成`readfds`、`writefds`、`exceptfds`, +/// 而是按照需要等待的文件描述符,将其加入 `fds_ptr`,再对每一个文件描述符进行等待事件的约束。其中 `fds_ptr` 指向的是一个 +/// [`PollFd'] 向量,每个 Pollfd 结构中都保存了文件描述符、等待事件类型和获取到的事件类型三方面信息。因此对于 `ppoll`, +/// 会周期性检测 `fds_ptr` 中是否有文件描述符发生了所要等待的事件,如果有,那么就把事件的类型记录在 Pollfd 结构的 revents +/// 字段下,并使得计数器自增。在 `fds_ptr` 指向的向量中所有的文件描述符都被遍历一遍后,如果有需要处理的事件,那么此时 `ppoll` +/// 会返回需要处理的事件个数。如果没有,和 'pselect6' 相同,`ppoll` 也会让渡 CPU 后循环查询,直到发生超时事件,此时会返回 0, +/// 表示没有收到需要处理的事件。 +/// +/// 参数: +/// + `fds_ptr`: 用于指明需要等待的文件描述符和等待的事件类型。具体可见 [`PollFd`] 结构 和 [`PollEvents`]结构。 +/// + `nfds`: 用于指明需要等待的文件描述符中的最大值 + 1,用于作为 `fds` 中查询文件描述符是否含有事件需要处理的迭代过程的边界条件。 +/// + `time`: 指明超时的时间限制,是一个 [`TimeSpec`] 结构的指针。根据不同取值,不同的效果如下:(目前需要为0,否则会导致 panic) +/// - 如果该值为空,那么select会一直等待需要处理的IO事件,永远不会超时; +/// - 如果该值不为空,但内部的时间被设为0时,表示即使没有发现需要处理的IO事件,也直接返回。 +/// - 否则按照正常的超时时间计算。 +/// + `mask`: 用于屏蔽某些信号。目前在 Alien 中未使用。(并且需要为0,否则会导致 panic) +/// +/// 当因为检测到需要处理的IO事件返回时,ppoll 会返回接收到的需要处理的IO事件的总数; +/// 当因为超时而返回时,ppoll 会返回0; +/// 当因为接收到信号而返回时, ppoll 会返回 EINTR; +/// 当其他情况导致的函数执行异常,ppoll 将直接返回错误码。 +/// +/// Reference: [ppoll](https://man7.org/linux/man-pages/man2/ppoll.2.html) +#[syscall_func(73)] +pub fn ppoll(fds_ptr: usize, nfds: usize, time: usize, _mask: usize) -> AlienResult { + let task = current_task().unwrap(); + let mut fds = Vec::::with_capacity(nfds); + unsafe { + fds.set_len(nfds); + } + task.access_inner() + .copy_from_user_buffer(fds_ptr as *const PollFd, fds.as_mut_ptr(), nfds); + + info!("fds: {:?}", fds); + let wait_time = if time != 0 { + let time_spec = task.transfer_raw_ptr(time as *mut TimeSpec); + Some(time_spec.to_clock() + TimeSpec::now().to_clock()) + } else { + None + }; // wait forever + let mut res = 0; + let task = current_task().unwrap(); + loop { + for pfd in fds.iter_mut() { + if let Some(file) = task.get_file(pfd.fd as usize) { + let event = file.poll(pfd.events)?; + if !event.is_empty() { + res += 1; + } + info!("[ppoll]: event: {:?}", event); + pfd.revents = event; + } else { + // todo: error + pfd.events = PollEvents::INVAL; + } + } + + if res > 0 { + // copy to user + task.access_inner() + .copy_to_user_buffer(fds.as_ptr(), fds_ptr as *mut PollFd, nfds); + info!("ppoll return {:?}", fds); + return Ok(res as isize); + } + if let Some(wait_time) = wait_time { + if wait_time <= TimeSpec::now().to_clock() { + warn!("ppoll timeout"); + return Ok(0); + } + } + info!("[poll] suspend"); + // suspend + do_suspend(); + // interrupt by signal + // let task = current_task().unwrap(); + let task_inner = task.access_inner(); + let receiver = task_inner.signal_receivers.lock(); + if receiver.have_signal() { + return Err(LinuxErrno::EINTR.into()); + } + } +} diff --git a/kkernel/src/fs/select.rs b/kkernel/src/fs/select.rs new file mode 100644 index 00000000..9df2276d --- /dev/null +++ b/kkernel/src/fs/select.rs @@ -0,0 +1,220 @@ +use config::MAX_FD_NUM; +use crate::task::{current_task, do_suspend}; +use alloc::vec::Vec; +use bit_field::BitField; +use constants::io::PollEvents; +use constants::signal::{SignalNumber, SimpleBitSet}; +use constants::AlienResult; +use constants::LinuxErrno; +use core::cmp::min; +use log::{info, trace}; +use syscall_table::syscall_func; +use timer::TimeSpec; + +/// 一个系统调用,实现 IO 端口的复用。一般用于用户程序的一段循环体中, +/// 用于周期性检测一组关注的文件描述符集里是否有需要进行处理的IO事件发生。 +/// +/// 具体的,pselect6 会周期性检测在 `readfds`、`writefds`、`exceptfds`中的文件描述符, +/// 是否符合可读、可写、发生异常。如果有这样的文件描述符,那么就会记录下来,并使得计数器 +/// 自增。如果在一次循环后,发现有需要处理的IO事件,那么 pselect6 会直接返回计数器的值(即 +/// 事件个数),如果一直没有需要处理的IO事件,pselect6 也会在 `timeout` 所指明的一段时间后 +/// 返回 0,表示在该段时间内没有接收到需要处理的IO事件。pselect6 还可能因为 `SIGKILL` 而被 +/// 打断返回。 +/// +/// 参数有: +/// + `nfds`: 用于指明需要检测的文件描述符中的最大值 + 1,用于作为下面三个 `fds` 中查询 +/// 文件描述符是否符合条件的迭代过程的边界条件。目前在 Aien 中,即使传入的 nfds 大于 64,也会被调整为64。 +/// + `readfds`: 指向一个64位的位图(u64),用于记录哪些文件描述符需要被查询可读状态。在执行操作后,该位图被重用为记录哪些文件描述符有事件需要处理。 +/// + `writefds`: 指向一个64位的位图(u64),用于记录哪些文件描述符需要被查询可写状态。在执行操作后,该位图被重用为记录哪些文件描述符有事件需要处理。 +/// + `exceptfds`: 指向一个64位的位图(u64),用于记录哪些文件描述符需要被查询异常状态。在执行操作后,该位图被重用为记录哪些文件描述符有事件需要处理。 +/// + `timeout`: 指明超时的时间限制,是一个 [`TimeSpec`] 结构的指针。根据不同取值,不同的效果如下: +/// - 如果该值为空,那么select会一直等待需要处理的IO事件,永远不会超时; +/// - 如果该值不为空,但内部的时间被设为0时,表示即使没有发现需要处理的IO事件,也直接返回。 +/// - 否则按照正常的超时时间计算。 +/// + `sigmask`: 用于屏蔽某些信号。目前在 Alien 中未使用。 +/// +/// 有关位图的设计,以 `readfds` 为例:当要检测 fd 为 i 的文件描述符是否已经准备好读时,需要则将位值置为1,否则将该位值置为0。 +/// 在执行操作后,该位图被重用为记录哪些文件描述符有事件需要处理,当有事件需要处理时,该位值置为1,否则置为0。`writefds` 和 `exceptfds` 同理。 +/// +/// 当因为检测到需要处理的IO事件返回时,pselect6 会返回接收到的需要处理的IO事件的总数; +/// 当因为超时而返回时,pselect6 会返回0; +/// 当因为接收到信号而返回时, pselect6 会返回 EINTR; +/// 当其他情况导致的函数执行异常,pselect6 将直接返回错误码。 +/// +/// Reference: [pselect](https://www.man7.org/linux/man-pages/man2/select.2.html) +#[syscall_func(72)] +pub fn pselect6( + nfds: usize, + readfds: usize, + writefds: usize, + exceptfds: usize, + timeout: usize, // pselect 不会更新 timeout 的值,而 select 会 + sigmask: usize, +) -> AlienResult { + if nfds >= MAX_FD_NUM { + return Err(LinuxErrno::EINVAL); + } + info!("pselect6: nfds = {}, readfds = {:#x}, writefds = {:#x}, exceptfds = {:#x}, timeout = {:#x}, sigmask = {:#x}", + nfds, readfds, writefds, exceptfds, timeout, sigmask); + + // 注意 pselect 不会修改用户空间中的 timeout,所以需要内核自己记录 + let task = current_task().unwrap(); + + if sigmask != 0 { + let mask = task.access_inner().transfer_raw_ptr(sigmask as *mut usize); + let mask_num: Vec = SimpleBitSet(*mask).into(); + info!("pselect6: sigmask = {} ---> {:?}, ", *mask, mask_num); + } + + let (wait_time, time_spec) = if timeout != 0 { + let time_spec = task.transfer_raw_ptr(timeout as *mut TimeSpec); + info!("pselect6: timeout = {:#x} ---> {:?}", timeout, time_spec); + ( + Some(time_spec.to_clock() + TimeSpec::now().to_clock()), + Some(time_spec.clone()), + ) + } else { + (Some(usize::MAX), None) + }; + // assert!(nfds <= 64); + let nfds = min(nfds, 64); + + // 这里暂时不考虑 sigmask 的问题 + let ori_readfds = if readfds != 0 { + let readfds = task.transfer_raw_ptr(readfds as *mut u64); + *readfds + } else { + 0 + }; + let ori_writefds = if writefds != 0 { + let writefds = task.transfer_raw_ptr(writefds as *mut u64); + *writefds + } else { + 0 + }; + let ori_exceptfds = if exceptfds != 0 { + let exceptfds = task.transfer_raw_ptr(exceptfds as *mut u64); + *exceptfds + } else { + 0 + }; + + // at iperf test, if readfds hav one fd is ok, but writefds is empty, + // it still return 1 and cause recursion error + do_suspend(); + + loop { + let mut set = 0; + // 如果设置了监视是否可读的 fd + if readfds != 0 { + let readfds = task.transfer_raw_ptr(readfds as *mut u64); + trace!( + "[tid:{}]pselect6: readfds = {:#b}", + task.get_tid(), + ori_readfds + ); + for i in 0..nfds { + if ori_readfds.get_bit(i) { + if let Some(fd) = task.get_file(i) { + let event = fd.poll(PollEvents::IN).expect("poll error"); + if event.contains(PollEvents::IN) { + info!("pselect6: fd {} ready to read", i); + readfds.set_bit(i, true); + set += 1; + } else { + readfds.set_bit(i, false); + } + } else { + return Err(LinuxErrno::EBADF.into()); + } + } + } + } + // 如果设置了监视是否可写的 fd + if writefds != 0 { + let writefds = task.transfer_raw_ptr(writefds as *mut u64); + trace!( + "[tid:{}]pselect6: writefds = {:#b}", + task.get_tid(), + ori_writefds + ); + for i in 0..nfds { + if ori_writefds.get_bit(i) { + if let Some(fd) = task.get_file(i) { + let event = fd.poll(PollEvents::OUT).expect("poll error"); + if event.contains(PollEvents::OUT) { + info!("pselect6: fd {} ready to write", i); + writefds.set_bit(i, true); + set += 1; + } else { + writefds.set_bit(i, false); + } + } else { + return Err(LinuxErrno::EBADF.into()); + } + } + } + } + // 如果设置了监视是否异常的 fd + if exceptfds != 0 { + let exceptfds = task.transfer_raw_ptr(exceptfds as *mut u64); + trace!( + "[tid:{}]pselect6: exceptfds = {:#b}", + task.get_tid(), + ori_exceptfds + ); + for i in 0..nfds { + if ori_exceptfds.get_bit(i) { + if let Some(fd) = task.get_file(i) { + let event = fd.poll(PollEvents::ERR).expect("poll error"); + if event.contains(PollEvents::ERR) { + info!("pselect6: fd {} in exceptional conditions", i); + exceptfds.set_bit(i, true); + set += 1; + } else { + exceptfds.set_bit(i, false); + } + } else { + return Err(LinuxErrno::EBADF.into()); + } + } + } + } + + if set > 0 { + // let readfds = task.transfer_raw_ptr(readfds as *mut u64); + // error!("pselect6: readfds = {:#b}", *readfds); + // 如果找到满足条件的 fd,则返回找到的 fd 数量 + return Ok(set as isize); + } + + if let Some(time_spec) = time_spec { + if time_spec == TimeSpec::new(0, 0) { + // 不阻塞 + return Ok(0); + } + } + + // 否则暂时 block 住 + do_suspend(); + + if let Some(wait_time) = wait_time { + if wait_time <= TimeSpec::now().to_clock() { + info!( + "select timeout, wait_time = {:#x}, now = {:#x}", + wait_time, + TimeSpec::now().to_clock() + ); + return Ok(0); + } + } + + // interrupt by signal + let task_inner = task.access_inner(); + let receiver = task_inner.signal_receivers.lock(); + let res = receiver.have_signal_with_number(); + if res.is_some() && res.unwrap() == SignalNumber::SIGKILL as usize { + return Err(LinuxErrno::EINTR.into()); + } + } +} diff --git a/kkernel/src/fs/stdio.rs b/kkernel/src/fs/stdio.rs new file mode 100644 index 00000000..064eaa44 --- /dev/null +++ b/kkernel/src/fs/stdio.rs @@ -0,0 +1,27 @@ +use crate::fs::file::KernelFile; +use alloc::sync::Arc; +use constants::io::OpenFlags; +use spin::Lazy; +use vfscore::path::VfsPath; +use vfs::SYSTEM_ROOT_FS; + +type Stdin = KernelFile; +type Stdout = KernelFile; + +pub static STDIN: Lazy> = Lazy::new(|| { + let path = VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()) + .join("dev/tty") + .unwrap(); + let dentry = path.open(None).unwrap(); + let file = KernelFile::new(dentry, OpenFlags::O_RDONLY); + Arc::new(file) +}); + +pub static STDOUT: Lazy> = Lazy::new(|| { + let path = VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()) + .join("dev/tty") + .unwrap(); + let dentry = path.open(None).unwrap(); + let file = KernelFile::new(dentry, OpenFlags::O_WRONLY); + Arc::new(file) +}); diff --git a/kkernel/src/gui.rs b/kkernel/src/gui.rs new file mode 100644 index 00000000..69061884 --- /dev/null +++ b/kkernel/src/gui.rs @@ -0,0 +1,34 @@ +//! GUI 相关的系统调用 +use page_table::addr::{align_up_4k, PhysAddr, VirtAddr}; +use crate::task::current_task; + + +use devices::GPU_DEVICE; + +const FB_VADDR: usize = 0x1000_0000; + +/// 一个系统调用,用于获取一段帧缓存。执行成功后返回帧缓存的首地址,Alien 中默认该地址为 FB_VADDR (0x1000_0000) +#[syscall_func(2000)] +pub fn sys_framebuffer() -> isize { + let fb = GPU_DEVICE.get().unwrap().get_framebuffer(); + let len = fb.len(); + // println!("[kernel] FrameBuffer: addr 0x{:X}, len {}", fb.as_ptr() as usize , len); + let phy_addr = PhysAddr::from(fb.as_ptr() as usize); + assert!(phy_addr.is_aligned_4k()); + let virt_addr = VirtAddr::from(FB_VADDR); + let current_process = current_task().unwrap(); + let inner = current_process.access_inner(); + inner + .address_space + .lock() + .map_region(virt_addr, phy_addr, align_up_4k(len), "RWUVAD".into(), true) + .unwrap(); + FB_VADDR as isize +} + +/// 一个系统调用,用于刷新帧缓存。执行成功后返回 0。 +#[syscall_func(2001)] +pub fn sys_framebuffer_flush() -> isize { + GPU_DEVICE.get().unwrap().flush(); + 0 +} diff --git a/kkernel/src/ipc/futex.rs b/kkernel/src/ipc/futex.rs new file mode 100644 index 00000000..751b9feb --- /dev/null +++ b/kkernel/src/ipc/futex.rs @@ -0,0 +1,178 @@ +//! Futex按英文翻译过来就是快速用户空间互斥体(Fast Userspace Mutex)。在传统的Unix系统中,System V IPC(inter process communication), +//! 如 semaphores, msgqueues, sockets还有文件锁机制(flock())等进程间同步机制都是对一个内核对象操作来完成的,这 +//! 个内核对象对要同步的进程都是可见的,其提供了共享的状态信息和原子操作。当进程间要同步的时候必须要通过系统调用 +//! (如semop())在内核中完成。可是经研究发现,很多同步是无竞争的,即某个进程进入互斥区,到再从某个互斥区出来这段 +//! 时间,常常是没有进程也要进这个互斥区或者请求同一同步变量的。但是在这种情况下,这个进程也要陷入内核去查询是否发生竞争 +//! 退出的时侯还要陷入内核去查询是否有进程等待在同一同步变量上。这些不必要的系统调用(或者说内核陷入)造 +//! 成了大量的性能开销。为了解决这个问题,设计了Futex这一结构。Futex是一种用户态和内核态混合的同步机制。首先,同步的进 +//! 程间通过mmap共享一段内存,futex变量就位于这段共享的内存中且操作是原子的,当进程尝试进入互斥区或者退出互斥区的 +//! 时候,先去查看共享内存中的futex变量,如果没有竞争发生,则只修改futex, 而不用再执行系统调用了。当通过访问futex +//! 变量告诉进程有竞争发生,则还是得执行系统调用去完成相应的处理(wait 或者 wake up)。简单的说,futex就是通过在用户 +//! 态的检查,(motivation)如果了解到没有竞争就不用陷入内核了,大大提高了low-contention时候的效率。Linux从2.5.7开始支持Futex。 +//! +//! Reference: https://cloud.tencent.com/developer/article/1176832 +//! +use alloc::collections::BTreeMap; +use alloc::sync::Arc; +use alloc::vec; +use alloc::vec::Vec; +use core::cmp::min; + +use ksync::Mutex; +use smpscheduler::FifoTask; + +use crate::task::{Task, GLOBAL_TASK_MANAGER}; +use timer::read_timer; +use constants::{AlienError, AlienResult}; + +/// 用于记录一个进程等待一个 futex 的相关信息 +pub struct FutexWaiter { + /// 进程的控制块 + task: Option>, + /// 进程等待 futex 的等待时间 + wait_time: Option, + /// 超时事件的标志位,标识该进程对于 futex 等待是否超时 + timeout_flag: Arc>, +} + +/// 用于管理 futex 等待队列的数据结构 +/// +/// 包含一个 futex id -> futexWait Vec 的 map +pub struct FutexWaitManager { + map: BTreeMap>, +} + +impl FutexWaiter { + /// 创建一个新的 `FutexWaiter` 保存等待在某 futex 上的一个进程 有关等待的相关信息 + pub fn new(task: Arc, wait_time: Option, timeout_flag: Arc>) -> Self { + Self { + task: Some(task), + wait_time, + timeout_flag, + } + } + + /// 唤醒该进程,返回该进程的控制块 + pub fn wake(&mut self) -> Arc { + self.task.take().unwrap() + } +} + +impl FutexWaitManager { + /// 创建一个新的 futex 管理器,保存 futex 和在其上等待队列的映射关系 + pub fn new() -> Self { + Self { + map: BTreeMap::new(), + } + } + + /// 在某等待队列中加入等待进程 + pub fn add_waiter(&mut self, futex: usize, waiter: FutexWaiter) { + self.map.entry(futex).or_insert(Vec::new()).push(waiter); + } + + ///由于信号引发的唤醒操作 + pub fn wake_for_signal(&mut self) { + for (_, waiters) in self.map.iter_mut() { + let mut record = vec![]; + for (index, waiter) in waiters.iter_mut().enumerate() { + let task = waiter.task.as_ref().unwrap(); + let task_inner = task.access_inner(); + let receiver = task_inner.signal_receivers.lock(); + if receiver.have_signal() { + drop(receiver); + drop(task_inner); + let task = waiter.wake(); + GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); + record.push(index); + } + } + record.iter().for_each(|index| { + waiters.remove(*index); + }) + } + self.delete_empty_waiters(); + } + + /// 由于超时引发的唤醒操作 + pub fn wake_for_timeout(&mut self) { + let now = read_timer(); + for (_, waiters) in self.map.iter_mut() { + let mut record = vec![]; + for (index, waiter) in waiters.iter_mut().enumerate() { + if let Some(wait_time) = waiter.wait_time { + if wait_time <= now { + *waiter.timeout_flag.lock() = true; + let task = waiter.wake(); + GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); + record.push(index); + } + } + } + record.iter().for_each(|index| { + waiters.remove(*index); + }) + } + // delete empty waiters + self.delete_empty_waiters(); + } + + /// 清空所有空的等待队列 + fn delete_empty_waiters(&mut self) { + let mut record = vec![]; + for (futex, waiters) in self.map.iter() { + if waiters.is_empty() { + record.push(*futex); + } + } + record.iter().for_each(|futex| { + self.map.remove(futex); + }) + } + + /// 唤醒 futex 上的至多 num 个等待的进程 + pub fn wake(&mut self, futex: usize, num: usize) -> AlienResult { + if let Some(waiters) = self.map.get_mut(&futex) { + error!("there are {} waiters, wake {}", waiters.len(), num); + let min_index = min(num, waiters.len()); + for i in 0..min_index { + let task = waiters[i].wake(); + GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); + } + // delete waiters + waiters.drain(0..min_index); + warn!("wake {} tasks", min_index); + Ok(min_index) + } else { + error!("futex {} not found", futex); + Err(AlienError::EINVAL) + } + } + + /// 将原来等待在 old_futex 上至多 num 个进程转移到 requeue_futex 上等待,返回转移的进程数 + pub fn requeue( + &mut self, + requeue_futex: usize, + num: usize, + old_futex: usize, + ) -> AlienResult { + if num == 0 { + return Ok(0); + } + // move waiters + let mut waiters = self.map.remove(&old_futex).unwrap(); + // create new waiters + let new_waiters = self.map.entry(requeue_futex).or_insert(Vec::new()); + let min_index = min(num, waiters.len()); + error!("requeue {} waiters", min_index); + for _ in 0..min_index { + let waiter = waiters.pop().unwrap(); + new_waiters.push(waiter); + } + // insert old waiters + if !waiters.is_empty() { + self.map.insert(old_futex, waiters); + } + Ok(min_index) + } +} diff --git a/kkernel/src/ipc/mod.rs b/kkernel/src/ipc/mod.rs new file mode 100644 index 00000000..afc46034 --- /dev/null +++ b/kkernel/src/ipc/mod.rs @@ -0,0 +1,262 @@ +//! IPC 进程间通信,目前 Alien 支持管道、共享内存、信号以及futex'等进程间的通信机制。 +//! +//! [`futex`] 子模块指明了 Alien 中的 futex (快速用户空间互斥体)结构。 +//! [`pipe`] 子模块指明了 Alien 中管道结构。 +//! [`shm`] 子模块指明了 Alien 中的共享内存结构。 +//! [`signal`] 子模块指明了 Alien 中使用的信号机制。 + +use alloc::sync::Arc; +use core::sync::atomic::{AtomicI32, Ordering}; +use spin::Lazy; + +use constants::ipc::{FutexOp, RobustList}; +use constants::AlienResult; +use constants::LinuxErrno; +use ksync::Mutex; +pub use pipe::*; +pub use shm::*; +pub use signal::*; +use crate::ipc::futex::{FutexWaitManager, FutexWaiter}; +use crate::task::schedule::schedule; +use crate::task::{current_task, TaskState}; +use timer::TimeSpec; +use crate::fs::basic::sys_close; + +pub mod futex; +mod pipe; +pub mod shm; +pub mod signal; + +/// 一个全局变量,用于记录和管理 futex 的等待队列 +pub static FUTEX_WAITER: Lazy> = + Lazy::new(|| Mutex::new(FutexWaitManager::new())); + +/// 一对文件描述符。用于创建管道时,返回管道两个端口的文件描述符。 +#[repr(C)] +#[derive(Debug, Copy, Clone)] +struct FdPair { + fd: [u32; 2], +} + +/// 一个系统调用,用于创建管道。管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。 +/// 调用 `sys_pipe` 系统函数即可创建一个管道。 `Alien` 中有关管道的设计可见[`Pipe`]。 +/// +/// `sys_pipe` 按照传入的 `pipe` 解析出对应的 [`FdPair`] 结构在用户内存中的位置, +/// 并将创建成功的管道的读端赋值给 `fd_pair.fd[0]` ,将管道的写端赋值给 `fd_pair.fd[1]` 。 +/// 目前的 `flag` 未发挥作用。 +/// +/// 若创建管道成功,则会返回 0;若发生创建管道错误,或 `pipe == 0` 会导致函数返回 -1。 +#[syscall_func(59)] +pub fn sys_pipe(pipe: *mut u32, _flag: u32) -> AlienResult { + if pipe.is_null() { + return Err(LinuxErrno::EINVAL); + } + let process = current_task().unwrap(); + let fd_pair = process.transfer_raw_ptr(pipe as *mut FdPair); + let (read, write) = make_pipe_file()?; + let read_fd = process.add_file(read).map_err(|_| LinuxErrno::EMFILE)?; + let write_fd = process.add_file(write).map_err(|_| LinuxErrno::EMFILE)?; + fd_pair.fd[0] = read_fd as u32; + fd_pair.fd[1] = write_fd as u32; + Ok(0) +} + +/// 一个系统调用,将进程中一个已经打开的文件复制一份并分配到一个新的文件描述符中。可以用于IO重定向。 +/// `old_fd` 指明进程中一个已经打开的文件的文件描述符。 +/// +/// 如果传入的 `old_fd` 并不对应一个合法的已打开文件,将会返回 -1; +/// 如果创建新的文件描述符失败,那么会返回 `EMFILE`; +/// 否则创建新的文件描述符成功,返回能够访问已打开文件的新文件描述符。(同时文件描述符分配器会保证新文件描述符是当时情况下所能分配的描述符中最小的) +/// +/// Reference: https://man7.org/linux/man-pages/man2/dup.2.html +#[syscall_func(23)] +pub fn sys_dup(old_fd: usize) -> AlienResult { + let process = current_task().unwrap(); + let file = process.get_file(old_fd).ok_or(LinuxErrno::EBADF)?; + let new_fd = process + .add_file(file.clone()) + .map_err(|_| LinuxErrno::EMFILE)?; + Ok(new_fd as isize) +} + +/// 一个系统调用,将进程中一个已经打开的文件复制一份并分配到一个新的文件描述符中。功能上与 `sys_dup` 大致相同。 +/// +/// `old_fd` 指明进程中一个已经打开的文件的文件描述符,`new_fd` 指明新的文件描述符。 +/// 如果 `new_fd` 已经分配给一个文件,那么将自动关闭 `new_fd` 原来对应的那个文件后,再将复制的文件分配到 `new_fd`。 +/// +/// 如果传入的 `old_fd` 并不对应一个合法的已打开文件或者创建新的文件描述符失败,都将会返回 -1; +/// 如果 `new_fd` 与 `old_fd` 相等, 那么调用将什么也不进行,直接返回 `new_fd`。 +/// 否则创建新的文件描述符成功,返回 `new_fd`。 +/// +/// Reference: https://man7.org/linux/man-pages/man2/dup.2.html +#[syscall_func(24)] +pub fn sys_dup2(old_fd: usize, new_fd: usize, _flag: usize) -> AlienResult { + let process = current_task().unwrap(); + let file = process.get_file(old_fd).ok_or(LinuxErrno::EBADF)?; + let new_file = process.get_file(new_fd); + if new_file.is_some() { + let _ = sys_close(new_fd); + } + process + .add_file_with_fd(file.clone(), new_fd) + .map_err(|_| LinuxErrno::EMFILE)?; + Ok(new_fd as isize) +} + +static FCOUNT: Mutex = Mutex::new(0); + +/// 一个系统调用,对 futex 进行操作。 有关 `futex` 的相关信息请见 [`futex`]。 +/// +/// 参数: +/// + `uaddr`: 用户态下共享内存的地址,里面存放的是一个对齐的整型计数器,指向一个 futex。 +/// + `futex_op`: 指明操作的类型。具体操作类型可见 [`FutexOp`]。目前 Alien 识别的 futex_op 包括: +/// + FutexOp::FutexWaitPrivate | FutexOp::FutexWait: 先比较 uaddr 上计数器的值和 val 是否相等,如果不相等则将直接返回 `EAGAIN`;否则 +/// 该进程将等待在 uaddr 上,并根据 val2 的值确定等待的逻辑。若 val2 值为0,则表示进程一直等待;若 val2 是一个正数,则表示进程将在等待 val2 时间后因超时被唤醒 +/// + FutexOp::FutexCmpRequeuePiPrivate: 先比较 uaddr 上计数器的值和 val3 是否相等,如果不相等则将直接返回 `EAGAIN`;否则 +/// 唤醒至多 val 个在 uaddr 上等待的进程后,将原来等待在 uaddr 上至多 val2 个进程转移到 uaddr2 上等待,最后返回 唤醒的进程数 + 转移的进程数 +/// + FutexOp::FutexRequeuePrivate: 唤醒至多 val 个在 uaddr 上等待的进程后,将原来等待在 uaddr 上至多 val2 个进程转移到 uaddr2 上等待 +/// 最后返回 唤醒的进程数 + 转移的进程数 +/// + FutexOp::FutexWakePrivate | FutexOp::FutexWake: 唤醒至多 val 个在 uaddr 上等待的进程。最后返回 唤醒的进程数。 +/// + `val`: 传入的参数1,将根据 futex_op 发挥不同的作用。 +/// + `val2`: 传入的参数2,将根据 futex_op 发挥不同的作用。 +/// + `uaddr2`: 传入的地址2,将根据 futex_op 发挥不同的作用。 +/// + `val3`: 传入的参数3,将根据 futex_op 发挥不同的作用。 +/// +/// 在此过程中,如果出现异常,会返回异常类型。 +/// +/// Reference: [futex](https://man7.org/linux/man-pages/man2/futex.2.html) +#[syscall_func(98)] +pub fn futex( + uaddr: usize, + futex_op: u32, + val: u32, + val2: usize, + uaddr2: usize, + val3: u32, +) -> isize { + *FCOUNT.lock() += 1; + let futex_op = FutexOp::try_from(futex_op).unwrap(); + let task = current_task().unwrap(); + let task_inner = task.access_inner(); + warn!( + "futex: {:?} {:?} {:?} {:?} {:?} {:?}", + uaddr, futex_op, val, val2, uaddr2, val3 + ); + match futex_op { + FutexOp::FutexWaitPrivate | FutexOp::FutexWait => { + let uaddr_ref = task_inner.transfer_raw_ptr_mut(uaddr as *mut i32); + let uaddr_atomic = AtomicI32::from_mut(uaddr_ref); + + if uaddr_atomic.load(Ordering::SeqCst) != val as i32 { + error!("FutexWait: uaddr_ref != val"); + return LinuxErrno::EAGAIN as isize; + } + // we checkout the timeout + let wait_time = if val2 != 0 { + let time_spec = task_inner.transfer_raw_ptr(val2 as *const TimeSpec); + Some(time_spec.to_clock() + TimeSpec::now().to_clock()) + } else { + // wait forever + None + }; + // add to wait queue + drop(task_inner); + warn!("Futex wait time: {:?}", wait_time); + let timeout_flag = Arc::new(Mutex::new(false)); + let waiter = FutexWaiter::new(task.clone(), wait_time, timeout_flag.clone()); + FUTEX_WAITER.lock().add_waiter(uaddr, waiter); + // switch to other task + task.update_state(TaskState::Waiting); + warn!("Because of futex, we switch to other task"); + schedule(); + // checkout the timeout flag + let timeout_flag = timeout_flag.lock(); + if *timeout_flag { + return 0; + } + } + FutexOp::FutexCmpRequeuePiPrivate => { + let uaddr_ref = task_inner.transfer_raw_ptr(uaddr as *const u32); + if *uaddr_ref != val3 { + error!("FutexRequeuePrivate: uaddr_ref != val"); + return LinuxErrno::EAGAIN as isize; + } + // wake val tasks + let res = FUTEX_WAITER.lock().wake(uaddr, val as usize); + if res.is_err() { + return LinuxErrno::EINVAL as isize; + } + // requeue val2 tasks to uaddr2 + let res2 = FUTEX_WAITER.lock().requeue(uaddr2, val2, uaddr); + if res2.is_err() { + return LinuxErrno::EINVAL as isize; + } + return res2.unwrap() as isize + res.unwrap() as isize; + } + FutexOp::FutexRequeuePrivate => { + // wake val tasks + let res = FUTEX_WAITER.lock().wake(uaddr, val as usize); + if res.is_err() { + return LinuxErrno::EINVAL as isize; + } + // requeue val2 tasks to uaddr2 + let res2 = FUTEX_WAITER.lock().requeue(uaddr2, val2, uaddr); + if res2.is_err() { + return LinuxErrno::EINVAL as isize; + } + return res2.unwrap() as isize + res.unwrap() as isize; + } + FutexOp::FutexWakePrivate | FutexOp::FutexWake => { + let res = FUTEX_WAITER.lock().wake(uaddr, val as usize); + if res.is_err() { + return LinuxErrno::EINVAL as isize; + } + return res.unwrap() as isize; + } + _ => { + panic!("futex: unimplemented futex_op: {:?}", futex_op); + // return LinuxErrno::EINVAL as isize; + } + } + 0 +} + +/// 一个系统调用,用于设置当前进程的 robust 锁的列表头。robust 锁主要是解决当一个持有互斥锁的线程退出之后这个锁成为不可用状态的问题。 +/// +/// 当传入的 `len` 不等于 `HEAD_SIZE` 时,将会返回 `EINVAL`,否则函数将把 `head` 赋值给 tcb 的 robust 的 head 字段,然后返回 0。 +#[syscall_func(99)] +pub fn set_robust_list(head: usize, len: usize) -> isize { + if len != RobustList::HEAD_SIZE { + return LinuxErrno::EINVAL as isize; + } + let task = current_task().unwrap(); + let mut task_inner = task.access_inner(); + task_inner.robust.head = head; + 0 +} + +/// 一个系统调用,用于获取某进程的 robust 锁的列表头。robust 锁主要是解决当一个持有互斥锁的线程退出之后这个锁成为不可用状态的问题。 +/// +/// `pid` 指明了要获取相关信息的进程号;`head_ptr` 指明了获取信息后保存的位置;`len_ptr` 指明了获取列表长度信息后保存的位置。 +/// +/// 当 `pid` 的值为 0 时,将会导致函数 panic;当函数正确执行时,返回 0。 +#[syscall_func(100)] +pub fn get_robust_list(pid: usize, head_ptr: usize, len_ptr: usize) -> isize { + assert_eq!(pid, 0); + let task = current_task().unwrap(); + let task_inner = task.access_inner(); + let head = task_inner.robust.head; + let len = RobustList::HEAD_SIZE; + let head_ref = task_inner.transfer_raw_ptr_mut(head_ptr as *mut usize); + let len_ref = task_inner.transfer_raw_ptr_mut(len_ptr as *mut usize); + *head_ref = head; + *len_ref = len; + 0 +} + +/// 唤醒所有当前正在等待 futex 但因为超时或者信号而需要被唤醒的进程 +pub fn solve_futex_wait() { + let mut futex_waiter = FUTEX_WAITER.lock(); + futex_waiter.wake_for_timeout(); + futex_waiter.wake_for_signal(); +} diff --git a/kkernel/src/ipc/pipe.rs b/kkernel/src/ipc/pipe.rs new file mode 100644 index 00000000..011e2f10 --- /dev/null +++ b/kkernel/src/ipc/pipe.rs @@ -0,0 +1,387 @@ +//! 管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。 +//! +//! `Alien` 中对于管道的设计参考了`rCore`的相关设计。创建管道时会同时创建一个环形缓冲区, +//! 管道的两个端口抽象成文件,对两个端口直接的相关的文件操作(读操作或者写操作)都被设计 +//! 成对缓冲区进行数据处理(向缓冲区中传入数据或接收数据)。 +//! +//! 管道文件创建时,依据 Alien 所使用的 rvfs 中对文件 `File` 的规定,我们只需为管道文件规定好 +//! [`pipe_release`]、[`pipe_write`]、[`pipe_read`]、[`pipe_exec`]、[`pipe_llseek`]、 +//! [`pipe_read_is_hang_up`]、[`pipe_write_is_hang_up`]、[`pipe_ready_to_read`] +//! 、[`pipe_ready_to_write`] 几个操作函数,即可快速的创建管道文件,并将其放入进程的文件描述 +//! 符表中。 + +use config::PIPE_BUF; +use crate::fs::file::File; +use crate::task::{current_task, do_suspend}; +use alloc::string::{String, ToString}; +use alloc::sync::{Arc, Weak}; +use alloc::vec::Vec; +use constants::io::{OpenFlags, PollEvents, SeekFrom}; +use constants::AlienResult; +use constants::LinuxErrno; +use core::fmt::{Debug, Formatter}; +use core::sync::atomic::AtomicUsize; +use ksync::Mutex; +use vfscore::dentry::VfsDentry; +use vfscore::error::VfsError; +use vfscore::file::VfsFile; +use vfscore::impl_common_inode_default; +use vfscore::inode::{InodeAttr, VfsInode}; +use vfscore::superblock::VfsSuperBlock; +use vfscore::utils::VfsPollEvents; +use vfscore::utils::*; +use vfscore::VfsResult; +use vfs::pipefs::{PIPE_FS_ROOT, PipeFsDirInodeImpl}; + +static PIPE: AtomicUsize = AtomicUsize::new(0); + +/// 管道文件 +pub struct PipeFile { + open_flag: Mutex, + dentry: Arc, + inode_copy: Arc, +} + +impl Debug for PipeFile { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("PipeFile") + .field("open_flag", &self.open_flag) + .field("name", &self.dentry.name()) + .finish() + } +} + +impl PipeFile { + pub fn new( + dentry: Arc, + open_flag: OpenFlags, + inode_copy: Arc, + ) -> Self { + Self { + open_flag: Mutex::new(open_flag), + dentry, + inode_copy, + } + } +} + +/// create a pipe file +pub fn make_pipe_file() -> VfsResult<(Arc, Arc)> { + let root = PIPE_FS_ROOT.get().unwrap(); + let root_inode = root + .inode()? + .downcast_arc::() + .map_err(|_| VfsError::Invalid) + .unwrap(); + let inode = Arc::new(PipeInode::new()); + let num_str = PIPE.fetch_add(1, core::sync::atomic::Ordering::AcqRel); + let same_inode = + root_inode.add_file_manually(&num_str.to_string(), inode.clone(), "rw-rw-rw-".into())?; + let dt = root.i_insert(&num_str.to_string(), same_inode)?; + let reader = Arc::new(PipeFile::new( + dt.clone(), + OpenFlags::O_RDONLY, + inode.clone(), + )); + let sender = Arc::new(PipeFile::new(dt, OpenFlags::O_WRONLY, inode.clone())); + inode.set_reader(&reader); + inode.set_sender(&sender); + Ok((reader, sender)) +} + +impl File for PipeFile { + fn read(&self, buf: &mut [u8]) -> AlienResult { + if buf.len() == 0 { + return Ok(0); + } + self.dentry.inode()?.read_at(0, buf).map_err(|e| e.into()) + } + fn write(&self, buf: &[u8]) -> AlienResult { + if buf.len() == 0 { + return Ok(0); + } + self.dentry.inode()?.write_at(0, buf).map_err(|e| e.into()) + } + fn seek(&self, _pos: SeekFrom) -> AlienResult { + Err(LinuxErrno::ESPIPE) + } + fn get_attr(&self) -> AlienResult { + Err(LinuxErrno::ENOSYS) + } + fn dentry(&self) -> Arc { + self.dentry.clone() + } + fn inode(&self) -> Arc { + self.dentry.inode().unwrap() + } + fn is_readable(&self) -> bool { + let open_flag = self.open_flag.lock(); + open_flag.contains(OpenFlags::O_RDONLY | OpenFlags::O_RDWR) + } + + fn is_writable(&self) -> bool { + let open_flag = self.open_flag.lock(); + open_flag.contains(OpenFlags::O_WRONLY | OpenFlags::O_RDWR) + } + fn is_append(&self) -> bool { + false + } + fn poll(&self, _event: PollEvents) -> AlienResult { + let inode = self.dentry.inode()?; + let res = inode + .poll(VfsPollEvents::from_bits_truncate(_event.bits())) + .map(|e| PollEvents::from_bits_truncate(e.bits())); + res.map_err(Into::into) + } +} + +/// 环形缓冲区,用于在内存中维护管道的相关信息。 +pub struct PipeInode { + data: Mutex, +} + +struct PipeInodeData { + /// 缓冲区的数据部分 + pub buf: [u8; PIPE_BUF], + /// 缓冲区头部,用于指明当前的读位置 + pub head: usize, + /// 缓冲区尾部,用于指明当前的写位置 + pub tail: usize, + /// 记录 在 读端 进行等待的进程 + pub read_wait: Option>, + /// 记录 在 写端 进行等待的进程 + pub write_wait: Option>, +} + +impl PipeInodeData { + /// 用于返回当前的缓冲区是否为空 + pub fn is_empty(&self) -> bool { + self.head == self.tail + } + + /// 用于返回当前的缓冲区是否为满 + pub fn is_full(&self) -> bool { + (self.tail + 1) % PIPE_BUF == self.head + } + + /// 返回当前缓冲区中能够被读的字节数 + pub fn available_read(&self) -> usize { + if self.head <= self.tail { + self.tail - self.head + } else { + PIPE_BUF - self.head + self.tail + } + } + /// 返回当前缓冲区中还能够写入的字节数 + pub fn available_write(&self) -> usize { + if self.head <= self.tail { + PIPE_BUF - self.tail + self.head - 1 + } else { + self.head - self.tail - 1 + } + } + + /// 向缓冲区中写入数据,返回写入的字节数 + pub fn write(&mut self, buf: &[u8]) -> usize { + let mut count = 0; + while !self.is_full() && count < buf.len() { + self.buf[self.tail] = buf[count]; + self.tail = (self.tail + 1) % PIPE_BUF; + count += 1; + } + count + } + + /// 从缓冲区中读取数据,返回读取的字节数 + pub fn read(&mut self, buf: &mut [u8]) -> usize { + let mut count = 0; + while !self.is_empty() && count < buf.len() { + buf[count] = self.buf[self.head]; + self.head = (self.head + 1) % PIPE_BUF; + count += 1; + } + count + } + + /// 返回是否有进程在 写端等待 + pub fn is_write_wait(&self) -> bool { + self.write_wait.is_some() && self.write_wait.as_ref().unwrap().upgrade().is_some() + } + + /// 返回是否有进程在 读端等待 + pub fn is_read_wait(&self) -> bool { + self.read_wait.is_some() && self.read_wait.as_ref().unwrap().upgrade().is_some() + } +} + +impl PipeInode { + /// 创建一片新的管道缓冲区,在 `Pipe::new` 中被调用 + pub fn new() -> PipeInode { + PipeInode { + data: Mutex::new(PipeInodeData { + buf: [0; PIPE_BUF], + head: 0, + tail: 0, + read_wait: None, + write_wait: None, + }), + } + } + + pub fn set_reader(&self, reader: &Arc) { + let mut data = self.data.lock(); + data.read_wait = Some(Arc::downgrade(reader)) + } + pub fn set_sender(&self, sender: &Arc) { + let mut data = self.data.lock(); + data.write_wait = Some(Arc::downgrade(sender)) + } +} + +impl VfsFile for PipeInode { + fn read_at(&self, _offset: u64, user_buf: &mut [u8]) -> VfsResult { + info!("pipe_read: user_buf's len {:?}", user_buf.len()); + let mut count = 0; + loop { + let mut buf = self.data.lock(); + let available = buf.available_read(); + info!("pipe_read: available:{}", available); + if available == 0 { + if !buf.is_write_wait() { + // if there is no process waiting for writing, we should return + break; + } else { + // wait for writing + drop(buf); + do_suspend(); + warn!("pipe_read: suspend"); + // check signal + let task = current_task().unwrap(); + // interrupt by signal + let task_inner = task.access_inner(); + let receiver = task_inner.signal_receivers.lock(); + if receiver.have_signal() { + error!("pipe_write: have signal"); + return Err(VfsError::EINTR); + } + } + } else { + let min = core::cmp::min(available, user_buf.len() - count); + count += buf.read(&mut user_buf[count..count + min]); + break; + } + } + info!("pipe_read: return count:{}", count); + Ok(count) + } + fn write_at(&self, _offset: u64, user_buf: &[u8]) -> VfsResult { + info!("pipe_write: {:?}", user_buf.len()); + let mut count = 0; + loop { + let mut buf = self.data.lock(); + let available = buf.available_write(); + if available == 0 { + if !buf.is_read_wait() { + // if there is no process waiting for reading, we should return + break; + } + // release lock + drop(buf); + // wait for reading + do_suspend(); + let task = current_task().unwrap(); + let task_inner = task.access_inner(); + let receiver = task_inner.signal_receivers.lock(); + if receiver.have_signal() { + error!("pipe_write: have signal"); + return Err(VfsError::EINTR); + } + } else { + let min = core::cmp::min(available, user_buf.len() - count); + info!("pipe_write: min:{}, count:{}", min, count); + count += buf.write(&user_buf[count..count + min]); + break; + } + } + info!("pipe_write: count:{}", count); + Ok(count) + } + fn poll(&self, event: VfsPollEvents) -> VfsResult { + let data = self.data.lock(); + let mut res = VfsPollEvents::empty(); + if event.contains(VfsPollEvents::IN) { + if data.available_read() > 0 { + res |= VfsPollEvents::IN; + } + } + if event.contains(VfsPollEvents::OUT) { + if data.available_write() > 0 { + res |= VfsPollEvents::OUT + } + } + let is_reader = data.is_read_wait(); + let is_sender = data.is_write_wait(); + if is_reader && !is_sender { + res |= VfsPollEvents::HUP; + } + if !is_reader && is_sender { + res |= VfsPollEvents::ERR; + } + Ok(res) + } +} + +impl VfsInode for PipeInode { + impl_common_inode_default!(); + + fn get_super_block(&self) -> VfsResult> { + Err(VfsError::NoSys) + } + + fn node_perm(&self) -> VfsNodePerm { + VfsNodePerm::empty() + } + + fn readlink(&self, _buf: &mut [u8]) -> VfsResult { + Err(VfsError::NoSys) + } + + fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { + Err(VfsError::NoSys) + } + + fn get_attr(&self) -> VfsResult { + Err(VfsError::NoSys) + } + + fn list_xattr(&self) -> VfsResult> { + Err(VfsError::NoSys) + } + + fn inode_type(&self) -> VfsNodeType { + VfsNodeType::Fifo + } + fn update_time(&self, _: VfsTime, _: VfsTimeSpec) -> VfsResult<()> { + Err(VfsError::NoSys) + } +} + +impl Drop for PipeFile { + fn drop(&mut self) { + let data = self.inode_copy.data.lock(); + let is_reader = data.is_read_wait(); + let is_sender = data.is_write_wait(); + if !is_reader && !is_sender { + let name = self.dentry.name(); + let root = PIPE_FS_ROOT.get().unwrap(); + let root_inode = root + .inode() + .unwrap() + .downcast_arc::() + .map_err(|_| VfsError::Invalid) + .unwrap(); + root.remove(&name).unwrap(); + root_inode.remove_manually(&name).unwrap(); + } + } +} diff --git a/kkernel/src/ipc/shm.rs b/kkernel/src/ipc/shm.rs new file mode 100644 index 00000000..1944282f --- /dev/null +++ b/kkernel/src/ipc/shm.rs @@ -0,0 +1,283 @@ +//! 共享内存是一种最为高效的进程间通信方式。因为进程可以直接读写内存,不需要任何数据的拷贝。 +//! 为了在多个进程间交换信息,内核专门留出了一块内存区。这段内存区可以由需要访问的进程将其映射到自己的私有地址空间。 +//! 因此,进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高了效率。 +//! +//! Alien 中的共享内存同时提供了同步机制,也就是说,所有的 [`ShmMemoryInner`] 结构被包裹在一个 Mutex 中, +//! 最后封装成 [`ShmMemory`] 结构。 +//! +use alloc::collections::btree_map::BTreeMap; +use page_table::addr::{align_down_4k, PhysAddr, VirtAddr}; +use constants::ipc::{ShmAtFlags, ShmCtlCmd, ShmGetFlags, IPC_PRIVATE}; +use constants::{AlienResult, LinuxErrno}; +use ksync::{Mutex, MutexGuard}; +use syscall_table::syscall_func; + +use config::FRAME_SIZE; +use mem::{alloc_frame_trackers, FrameTracker}; +use crate::task::current_task; + +/// 共享内存被 Mutex 封装后的结构 +#[derive(Debug)] +pub struct ShmMemory { + /// 封装后的共享内存 + inner: Mutex, +} + +/// 未加入同步机制前的 共享内存 +#[derive(Debug)] +pub struct ShmMemoryInner { + /// 引用计数器 + ref_count: usize, + /// 共享内存数据部分 + pub frames: FrameTracker, + /// 共享内存的状态 + state: ShmMemoryState, +} + +/// 共享内存的信息,在创建一块共享内存时,需要将对应的信息加入到进程控制块中的 `shm` 字段下 +#[derive(Debug, Clone)] +pub struct ShmInfo { + /// 共享内存的虚拟地址首地址 + pub start_va: usize, + /// 共享内存的虚拟地址尾地址 + pub end_va: usize, +} + +impl ShmInfo { + /// 创建新的共享内存信息 + pub fn new(start_va: usize, end_va: usize) -> Self { + Self { start_va, end_va } + } +} + +impl ShmMemory { + /// 创建新的共享内存 + pub fn new(frames: FrameTracker) -> Self { + Self { + inner: Mutex::new(ShmMemoryInner { + ref_count: 0, + frames, + state: ShmMemoryState::Init, + }), + } + } + + /// 同步获取内部的共享内存信息 + pub fn access_inner(&self) -> MutexGuard { + self.inner.lock() + } + + /// 返回共享内存数据区的长度(字节数) + pub fn len(&self) -> usize { + self.access_inner().frames.len() + } + + /// 引用计数器加一 + pub fn add_ref(&self) { + self.access_inner().ref_count += 1; + } + + /// 获取当前共享内存的引用数 + pub fn get_ref(&self) -> usize { + self.access_inner().ref_count + } + + /// 删除当前的共享内存 + pub fn delete(&self) { + self.access_inner().state = ShmMemoryState::Deleted; + } + + /// 查询当前的共享内存是否被删除 + pub fn is_deleted(&self) -> bool { + self.access_inner().state == ShmMemoryState::Deleted + } + +} + +/// 记录共享内存当前状态的结构 +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +pub enum ShmMemoryState { + Init, + Used, + Deleted, +} + +/// 用于记录共享内存分配情况的全局变量,可使用其获取已经被创建的一块共享内存 +pub static SHM_MEMORY: Mutex> = Mutex::new(BTreeMap::new()); + +/// 一个系统调用,用于创建一块共享内存,方便进程间通信。 +/// +/// 参数: +/// + `key`: 指明共享内存的键值,多个进程可以通过它来访问同一个共享内存。当其值为 `IPC_PRIVATE` 时,用于创建当前进程的私有共享内存,多用于父子进程间。 +/// + `size`: 用于指明创建共享内存区大小。在函数执行过程中,内核将自动将该值与帧大小(4K)对齐。 +/// + `shmflg`: 用于指明操作的类型。当包含 `IPC_CREAT` 时,将创建一块共享内存,目前 Alien 中仅对 `IPC_CREAT` 有所识别。其它 flag 具体可见 [`ShmGetFlags`]。 +/// +/// 如果已经有共享内存使用了键值 `key`,那么将直接返回 `key` 的值,不会进行创建共享内存操作。 +/// +/// 返回值:如果创建共享内存成功或已经有共享内存使用了键值 `key`,则返回 `key` 值;否则返回 `ENOENT`。 +/// +/// Reference: [shmget](https://man7.org/linux/man-pages/man2/shmget.2.html) +#[syscall_func(194)] +pub fn shmget(key: usize, size: usize, shmflg: u32) -> isize { + info!( + "shmget key:{},size:{},shmflg:{:?}", + key, + size, + ShmGetFlags::from_bits_truncate(shmflg as i32) + ); + let key = if key == IPC_PRIVATE { + // we must create a key + *SHM_MEMORY.lock().keys().max().unwrap_or(&0) + 1 + } else { + key + }; + let mut shm_memory = SHM_MEMORY.lock(); + let shm = shm_memory.get(&key); + // now we ignore flag + if shm.is_some() { + return key as isize; + } + let flag = ShmGetFlags::from_bits_truncate(shmflg as i32); + if flag.contains(ShmGetFlags::IPC_CREAT) { + info!("create new share memory {}", key); + // alloc frames + let frames = alloc_frame_trackers(align_down_4k(size) / FRAME_SIZE); + // if frames.is_none() { + // return LinuxErrno::ENOMEM as isize; + // } + // let frames = frames.unwrap(); + let share_mem = ShmMemory::new(frames); + shm_memory.insert(key, share_mem); + return key as isize; + } + LinuxErrno::ENOENT as isize +} + +/// 一个系统调用,用于将一块共享内存映射到进程的虚拟空间中。通常与 [`shmget`] 一起使用。 +/// +/// 参数: +/// + `shmid`: 用于指明要映射的共享内存的键值 `key`, 一般为 [`shmget`] 的返回值。 +/// + `shmaddr`: 用于指明共享内存要映射到的虚存地址。一般有以下几种情况(目前Alien只能处理情况1,其余情况会导致 panic 退出) +/// 1. 如果 `shmaddr` 是NULL,系统将自动选择一个合适的地址 +/// 2. 如果 `shmaddr` 不是NULL 并且没有指定 SHM_RND,则此段连接到addr所指定的地址上 +/// 3. 如果 `shmaddr` 不是NULL 并且指定了 SHM_RND,则此段连接到 shmaddr -(shmaddr mod SHMLAB)所表示的地址上 +/// + `shmflg`: 一组标志位,通常为0。详细可见 [`ShmAtFlags`]。 +/// +/// 函数正常执行且映射成功时,则会返回虚拟空间中映射的首地址;当 `shmid` 不合法时,会返回 `EINVAL`。 +/// +/// Reference: [shmat](https://www.man7.org/linux/man-pages/man3/shmat.3p.html) +#[syscall_func(196)] +pub fn shmat(shmid: usize, shmaddr: usize, shmflg: u32) -> AlienResult { + warn!( + "shmat shmid:{},shmaddr:{:#x},shmflg:{:?}", + shmid, + shmaddr, + ShmAtFlags::from_bits_truncate(shmflg as i32) + ); + let shm_memory = SHM_MEMORY.lock(); + let shm = shm_memory.get(&shmid).ok_or(LinuxErrno::EINVAL)?; + + let flag = ShmAtFlags::from_bits_truncate(shmflg as i32); + assert!(flag.is_empty()); + if flag.contains(ShmAtFlags::SHM_RDONLY) { + info!("read only"); + } + assert_eq!(shmaddr, 0); + // we must find a place to map + let task = current_task().unwrap(); + let free_map = task.access_inner().mmap.alloc(shm.len()); + // map to va + error!("shm map range:{:#x?}", free_map); + shm.access_inner().state = ShmMemoryState::Used; + let mut task_inner = task.access_inner(); + let mut address_space = task_inner.address_space.lock(); + // let shm_inner = shm.access_inner(); + // let mut virt_start = free_map.start; + // shm.access_inner().frames.iter().for_each(|x| { + // let phy_start = x.start(); + // address_space + // .map( + // VirtAddr::from(virt_start), + // PhysAddr::from(phy_start), + // PageSize::Size4K, + // "UVRWAD".into(), + // ) + // .unwrap(); + // error!("map {:#x} to {:#x}", phy_start, virt_start); + // virt_start += FRAME_SIZE; + // }); + + let size = shm.len(); + let start_phy = shm.access_inner().frames.start(); + address_space.map_region( + VirtAddr::from(free_map.start), + PhysAddr::from(start_phy), + size, + "UVRWAD".into(), + false, + ).unwrap(); + + info!("shm map range:{:#x?}", free_map); + + drop(address_space); + task_inner + .shm + .insert(shmid, ShmInfo::new(free_map.start, free_map.end)); + shm.add_ref(); + Ok(free_map.start as isize) +} + +/// 一个系统调用,用于控制共享内存。 +/// +/// 参数: +/// + `shmid`: 用于指明要操作的共享内存的键值 `key`, 一般为 [`shmget`] 的返回值。 +/// + `cmd`: 指明要采取的操作。具体可见 [`ShmCtlCmd`],目前Alien仅支持 `IpcRmid`,即删除共享内存操作。 +/// + `_buf`: 指向一个存储共享内存模式和访问权限的结构,目前未用到。 +/// +/// 当接受的 `cmd` 为 `IpcRmid` 且 成功执行后,将返回 0;否则会因为还未支持相关操作类型而 panic。 +/// +/// Reference: [shmctl](https://man7.org/linux/man-pages/man2/shmctl.2.html) +#[syscall_func(195)] +pub fn shmctl(shmid: usize, cmd: usize, _buf: usize) -> AlienResult { + let cmd = ShmCtlCmd::try_from(cmd as u32) + .map_err(|_| LinuxErrno::EINVAL)?; + match cmd { + ShmCtlCmd::IpcRmid => { + //delete + let shm_memory = SHM_MEMORY.lock(); + let shm = shm_memory.get(&shmid) + .ok_or(LinuxErrno::EINVAL)?; + shm.delete(); + let task = current_task().unwrap(); + let task_inner = task.access_inner(); + let have_detach = task_inner.shm.get(&shmid).clone(); + if have_detach.is_some() { + // task_inner.shm.remove(&shmid); + // unmap + // let mut address_space = task_inner.address_space.lock(); + // let mut virt_start = shm.access_inner().start_va; + // let virt_end = shm.access_inner().end_va; + // error!("shm unmap rang: {:#x}-{:#x}",virt_start,virt_end); + // while virt_start < virt_end { + // let (phy, flag, _) = address_space.query( + // VirtAddr::from(virt_start) + // ).unwrap(); + // error!("query {:#x} to {:#x} {:?}",virt_start,phy,flag); + // address_space.unmap(VirtAddr::from(virt_start)).unwrap(); + // virt_start += FRAME_SIZE; + // } + } + let mut flag = false; + if shm.get_ref() == 0 && shm.is_deleted() { + flag = true; + } + if flag { + // shm_memory.remove(&shmid); + } + } + _ => { + panic!("not support") + } + } + Ok(0) +} diff --git a/kkernel/src/ipc/signal.rs b/kkernel/src/ipc/signal.rs new file mode 100644 index 00000000..822bbadd --- /dev/null +++ b/kkernel/src/ipc/signal.rs @@ -0,0 +1,404 @@ +//! 信号是进程间通信机制中唯一的异步通信机制,进程之间可以互相通过系统调用 kill 发送软中断信号。 +//! 内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。 +//! +//! 有关 Alien 中信号的具体处理流程可见 [`signal_handler`]。 +use alloc::collections::BTreeMap; +use alloc::sync::Arc; +use alloc::vec::Vec; +use core::mem::size_of; + +use constants::signal::{ + SigAction, SigActionDefault, SigActionFlags, SigInfo, SigProcMaskHow, SignalNumber, + SignalReceivers, SignalUserContext, SimpleBitSet, +}; +use constants::LinuxErrno; +use ksync::Mutex; +use syscall_table::syscall_func; + +use crate::task::{current_task, do_exit, do_suspend}; +use timer::{read_timer, TimeSpec}; + +/// 记录每个线程的信号量,从 tid 获取信号相关信息 +static TID2SIGNALS: Mutex>>> = + Mutex::new(BTreeMap::new()); + +/// 所有线程初始化时均需要加入表 +pub fn global_register_signals(tid: usize, signals: Arc>) { + TID2SIGNALS.lock().insert(tid, signals).take(); +} + +/// 所有线程退出时均需要从表中删除 +pub fn global_logoff_signals(tid: usize) { + TID2SIGNALS.lock().remove(&tid).take(); +} + +/// 获取信号量。这个函数会复制一个 Arc,不会影响表中的信号本身 +pub fn get_signals_from_tid(tid: usize) -> Option>> { + TID2SIGNALS.lock().get(&tid).map(|s| s.clone()) +} + +/// 发送一个信号给进程 tid +pub fn send_signal(tid: usize, signum: usize) { + if let Some(signals) = get_signals_from_tid(tid) { + // 获取目标线程(可以是自己)的 signals 数组 + warn!("send signal {:?} to {}", SignalNumber::from(signum), tid); + signals.lock().try_add_bit(signum); + } +} + +/// 一个系统调用,用于获取或修改与指定信号相关联的处理动作。 +/// +/// 一个进程,对于每种信号,在不进行特殊设置的情况下,都有其默认的处理方式。有关信号的处理流程具体可见 [`signal_handler`] 与 [`SigActionDefault`]。 +/// 用户可以通过 `sigaction` 获取或修改进程在接收到某信号时的处理动作。 +/// +/// 参数: +/// + `sig`: 指出要修改的处理动作所捕获的信号类型。有关详情可见 [`SignalNumber`]。 +/// + `action`: 指定新的信号处理方式的指针。详情可见 [`SigAction`]。当该值为空指针时,`sigaction` 将不会修改信号的处理动作。 +/// + `old_action`: 指出原信号处理方式要保存到的位置。详情可见 [`SigAction`]。当该值为空指针时,`sigaction` 将不会保存信号的原处理动作。 +/// +/// 函数执行成功后返回 0;若输入的 `sig` 是 `SIGSTOP`, `SIGKILL`, `ERR`中的一个时,将导致函数返回 `EINVAL`。 +#[syscall_func(134)] +pub fn sigaction(sig: usize, action: usize, old_action: usize) -> isize { + let action = action as *const SigAction; + let old_action = old_action as *mut SigAction; + // check whether sig is valid + let signum = SignalNumber::from(sig); + if signum == SignalNumber::SIGSTOP + || signum == SignalNumber::SIGKILL + || signum == SignalNumber::ERR + { + return LinuxErrno::EINVAL as isize; + } + let task = current_task().unwrap(); + let mut task_inner = task.access_inner(); + let signal_handler = task_inner.signal_handlers.clone(); + let mut signal_handler = signal_handler.lock(); + if !old_action.is_null() { + let mut tmp = SigAction::empty(); + signal_handler.get_action(sig, &mut tmp); + task_inner.copy_to_user(&tmp, old_action); + } + if !action.is_null() { + let mut tmp_action = SigAction::empty(); + task_inner.copy_from_user(action, &mut tmp_action); + warn!("sig {:?} action is {:?}", signum, tmp_action); + signal_handler.set_action(sig, &tmp_action); + } + 0 +} + +/// 一个系统调用,用于使得一个进程在一段时间限制内等待一个信号,并保存信号的相关信息。 +/// +/// 参数: +/// + `set`: 用于指明等待的信号集,当进程接收到 `set` 中的任一一种信号时,都会返回。 +/// + `info`: 用于指明保存信号相关信息的位置。 当该值为空时,将不执行保存信号信息的操作。具体可见 [`SigInfo`] 结构。 +/// + `time`: 指明等待的时间。具体可见 [`TimeSpec`] 结构。 +/// +/// 当函数在规定的时间内成功接收到 `set` 中包含的某个信号时,将会返回该信号的序号; +/// 当函数在规定的时间内未接收到 `set` 中包含的某个信号时,将返回 `EAGAIN` 表示超时; +/// 如果 `time` 所指明的时间为 0,那么函数将直接返回-1。 +/// +/// Reference: [sigtimedwait](https://linux.die.net/man/2/sigtimedwait) +#[syscall_func(137)] +pub fn sigtimewait(set: usize, info: usize, time: usize) -> isize { + warn!( + "sigtimewait: set: {:x}, info: {:x}, time: {:x}", + set, info, time + ); + + let mut flag = false; + let mut target_time = 0; + + let task = current_task().unwrap().clone(); + let mut time_spec = TimeSpec::new(0, 0); + task.access_inner() + .copy_from_user(time as *const TimeSpec, &mut time_spec); + loop { + let mut task_inner = task.access_inner(); + let mut signal_receivers = task_inner.signal_receivers.lock(); + for i in 1..64 { + if set & (1 << i) != 0 { + if signal_receivers.check_signal(i) { + if info != 0 { + let mut tmp_info = SigInfo::default(); + tmp_info.si_signo = i as i32; + tmp_info.si_code = 0; + drop(signal_receivers); + task_inner.copy_to_user(&tmp_info, info as *mut SigInfo); + } + return i as isize; + } + } + } + + // wait time + if time_spec.tv_sec == 0 && time_spec.tv_nsec == 0 { + return -1; + } + drop(signal_receivers); + drop(task_inner); + if !flag { + warn!("sigtimewait: sleep for {:?}", time_spec); + let t_time = read_timer() + time_spec.to_clock(); + target_time = t_time; + flag = true; + } + let now = read_timer(); + if now >= target_time { + warn!("sigtimewait: timeout"); + break; + } + do_suspend(); + + // interrupt by signal + let task_inner = task.access_inner(); + let receiver = task_inner.signal_receivers.lock(); + if receiver.have_signal() { + let sig = receiver.have_signal_with_number().unwrap(); + return sig as isize; + } + } + LinuxErrno::EAGAIN.into() +} + +/// 一个系统调用,用于获取和设置信号的屏蔽位。通过 `sigprocmask`,进程可以方便的屏蔽某些信号。 +/// +/// 参数: +/// + `how`: 指明将采取何种逻辑修改信号屏蔽位。大致包括:屏蔽 `set` 中指明的所有信号,将 `set` 中指明的所有信号解除屏蔽或者直接使用 `set` 作为屏蔽码。具体可见 [`SigProcMaskHow`]。 +/// + `set`: 用于指明将要修改的信号屏蔽位。具体可见 [`SimpleBitSet`]。当该值为 null 时,将不修改信号的屏蔽位。 +/// + `oldset`: 用于获取当前对信号的屏蔽位。具体可见 [`SimpleBitSet`]。当该值为 null 时,将不保存信号的旧屏蔽位。 +/// + `_sig_set_size`: 用于指示 `set` 和 `oldset` 所指向的信号屏蔽位的长度,目前在 Alien 中未使用。 +/// +/// 函数正常执行后,返回 0。 +/// +/// Reference: [sigprocmask](https://www.man7.org/linux/man-pages/man2/sigprocmask.2.html) +#[syscall_func(135)] +pub fn sigprocmask(how: usize, set: usize, oldset: usize, _sig_set_size: usize) -> isize { + let task = current_task().unwrap(); + let task_inner = task.access_inner(); + let mut signal_receivers = task_inner.signal_receivers.lock(); + if oldset != 0 { + let set_mut = task_inner.transfer_raw_ptr_mut(oldset as *mut usize); + *set_mut = signal_receivers.mask.bits(); + } + let how = SigProcMaskHow::from(how); + warn!("sigprocmask: how: {:?}, set: {:x}", how, set); + if set != 0 { + let set = task_inner.transfer_raw_ptr(set as *const usize); + match how { + SigProcMaskHow::SigBlock => { + signal_receivers.mask += SimpleBitSet::from(*set); + } + SigProcMaskHow::SigUnblock => { + signal_receivers.mask -= SimpleBitSet::from(*set); + } + SigProcMaskHow::SigSetMask => { + signal_receivers.mask = SimpleBitSet::from(*set); + } + SigProcMaskHow::Unknown => { + return LinuxErrno::EINVAL as isize; + } + } + } + let mask: Vec = signal_receivers.mask.into(); + trace!("after sigprocmask: {:?}", mask); + 0 +} + +/// 一个系统调用函数,向 `pid` 指定的进程发送信号。 +/// 如果进程中有多个线程,则会发送给任意一个未阻塞的线程。 +/// +/// pid 有如下情况 +/// 1. pid > 0,则发送给指定进程 +/// 2. pid = 0,则发送给所有同组进程 +/// 3. pid = -1,则发送给除了初始进程(pid=1)外的所有当前进程有权限的进程 +/// 4. pid < -2,则发送给组内 pid 为参数相反数的进程 +/// +/// 目前 2/3/4 未实现。对于 1,仿照 zCore 的设置,认为**当前进程自己或其直接子进程** 是"有权限"或者"同组"的进程。 +/// +/// 目前如果函数成功执行后会返回0;否则返回错误类型。 +/// +/// Reference: [kill](https://man7.org/linux/man-pages/man2/kill.2.html) +#[syscall_func(129)] +pub fn kill(pid: usize, sig: usize) -> isize { + warn!("kill pid {}, signal id {:?}", pid, SignalNumber::from(sig)); + if pid > 0 { + //println!("kill pid {}, signal id {}", pid, signal_id); + if sig > 0 { + send_signal(pid, sig); + } + 0 + } else if pid == 0 { + LinuxErrno::ESRCH as isize + } else { + // 如果 signal_id == 0,则仅为了检查是否存在对应进程,此时应该返回参数错误。是的,用户库是会刻意触发这个错误的 + LinuxErrno::EINVAL as isize + } +} + +/// 一个系统调用函数,向 `tid` 指定的线程发送信号。在`Alien`中`tid`是task的唯一标识,故 `tid` 只会指向一个线程。 +/// +/// 函数正常执行后会返回0;否则返回错误类型。 +/// +/// Reference: [tkill](https://man7.org/linux/man-pages/man2/tkill.2.html) +#[syscall_func(130)] +pub fn tkill(tid: usize, sig: usize) -> isize { + warn!("tkill tid {}, signal id {:?}", tid, SignalNumber::from(sig)); + if tid > 0 && sig > 0 { + //println!("kill pid {}, signal id {}", pid, signal_id); + send_signal(tid, sig); + 0 + } else { + // 如果 signal_id == 0,则仅为了检查是否存在对应进程,此时应该返回参数错误。是的,用户库是会刻意触发这个错误的 + LinuxErrno::EINVAL as isize + } +} + +/// 一个系统调用函数,用于在用户态执行完信号处理函数后重新装回原 trap 上下文,一般不会被用户态程序调用。函数返回原 trap 上下文的 a0。 +#[syscall_func(139)] +pub fn signal_return() -> isize { + let task = current_task().unwrap(); + let mut task_inner = task.access_inner(); + let a0 = task_inner.load_trap_frame(); + a0 +} + +/// 信号处理函数。该函数在进程即将从内核态回到用户态时被调用,用于处理当前进程所接收到的信号。 +/// +/// 进行信号处理的前提: +/// 1. 有要处理的信号; +/// 2. 该信号目前没有被该进程屏蔽; +/// 3. 该信号没有被当前正在处理的信号屏蔽。 +/// +/// 当进入 `signal_handler` 后,对于该进程 `signal_receivers` 下所有信号种类开始遍历: +/// 先检查此种信号是否满足上面所有的前提,如果有一项以上不满足,直接continue; +/// 否则需要根据该信号是否已经设置非默认的处理函数进行接下来的操作。 +/// +/// + 对于一些固定采用采用默认信号处理方式的信号,或由于未设置其它信号处理函数的信号,仍然使用默认信号处理方式,Alien 中采用 [`SigActionDefault`] 对该信号进行判定: +/// + 如果属于 `Terminate` 类型,将导致进程终止。 +/// + 如果属于 `Ignore` 类型,进程将直接忽略该信号。 +/// + 如果进程已经设置过信号处理函数,由于信号处理函数的位置位于用户虚拟内存空间,需要回到用户态下进行信号处理函数的执行, +/// 但由于原来在用户态下我们还保存有一个 trap 上下文,因此我们需要记录这个 trap 上下文,同时将设计好的新的执行信号处理函数的上下文转移至原trap上下文的位置, +/// 以便其执行用户态下的信号处理函数。 +/// +/// 待用户态下的信号处理函数执行完毕后进程将重新陷入内核态,调用 [`signal_return`] 重新装载回原 trap 上下文。 +/// 至此,一个信号被处理完毕。 +pub fn signal_handler() { + let task = current_task().unwrap(); + let mut task_inner = task.access_inner(); + let receiver = task_inner.signal_receivers.clone(); + let mut receiver = receiver.lock(); + let handler = task_inner.signal_handlers.clone(); + let handler = handler.lock(); + if let Some(signum) = receiver.get_one_signal() { + let sig = SignalNumber::from(signum); + error!("task {:?} receive signal {:?}", task.tid, sig); + match sig { + SignalNumber::SIGSEGV | SignalNumber::SIGBUS => { + // we need exit the process + drop(task_inner); + drop(handler); + drop(receiver); + warn!("task {:?} exit by signal {:?}", task.tid, sig); + do_exit(-1); + } + _ => { + if let Some(action) = handler.get_action_ref(signum) { + // we find the handler + if action.is_ignore() { + return; + } + warn!("find handler for signal {:?}", sig); + if !task_inner.save_trap_frame() { + // we are in signal handler,don't nest + return; + } + // save the trap context + let trap_contex = task_inner.trap_frame(); + // modify trap context + // set ra to save user's stack + trap_contex.regs()[1] = action.get_restorer(); + // + let old_pc = trap_contex.sepc(); + trap_contex.set_sepc(action.handler); + // a0 ==signum + trap_contex.regs()[10] = signum; + assert_eq!(trap_contex.regs()[10], signum); + + warn!( + "task {:?} handle signal {:?} at {:#x}, old pc: {:#x}, old_sp: {:#x}", + task.tid, + sig, + trap_contex.sepc(), + old_pc, + trap_contex.regs()[2] + ); + let mut sp = trap_contex.regs()[2] - 0x200; // 128 + if action.flags.contains(SigActionFlags::SA_SIGINFO) { + task_inner.signal_set_siginfo = true; + // 如果带 SIGINFO,则需要在用户栈上放额外的信息 + sp = (sp - size_of::()) & !0xf; + info!("add siginfo at {:x}", sp); + let mut info = SigInfo::default(); + info.si_signo = signum as i32; + unsafe { + let phy_sp = task_inner.transfer_raw(sp); + *(phy_sp as *mut SigInfo) = info; + } + // a1 = &siginfo + trap_contex.regs()[11] = sp; + sp = (sp - size_of::()) & !0xf; + info!("add ucontext at {:x}", sp); + unsafe { + let phy_sp = task_inner.transfer_raw(sp); + *(phy_sp as *mut SignalUserContext) = + SignalUserContext::init(receiver.mask.bits() as u64, old_pc); + } + // a2 = &ucontext + trap_contex.regs()[12] = sp; + } + // set sp + trap_contex.regs()[2] = sp; + warn!( + "task {:?} handle signal {:?}, pc:{:#x}, sp:{:#x}", + task.tid, + sig, + trap_contex.sepc(), + trap_contex.regs()[2] + ); + } else { + // find the default handler + // 否则,查找默认处理方式 + match SigActionDefault::of_signal(sig) { + SigActionDefault::Terminate => { + // 这里不需要 drop(task),因为当前函数没有用到 task_inner,在 task.save_trap... 内部用过后已经 drop 了 + drop(task_inner); + drop(handler); + drop(receiver); + do_exit(-1); + } + SigActionDefault::Ignore => { + // 忽略信号时,要将已保存的上下文删除 + warn!("ignore signal {:?}", sig); + } + } + } + } + } + } +} + +/// 一个系统调用函数,用于阻塞当前进程,等待其他进程传入信号打断阻塞。当进程接收到某种信号时,终止阻塞,函数返回 `EINTR`。 +#[syscall_func(133)] +pub fn sigsuspend() -> isize { + loop { + do_suspend(); + let task = current_task().unwrap(); + // interrupt by signal + let task_inner = task.access_inner(); + let receiver = task_inner.signal_receivers.lock(); + if receiver.have_signal() { + return LinuxErrno::EINTR.into(); + } + } +} diff --git a/kkernel/src/main.rs b/kkernel/src/main.rs new file mode 100644 index 00000000..6007b615 --- /dev/null +++ b/kkernel/src/main.rs @@ -0,0 +1,71 @@ +#![feature(atomic_from_mut)] +#![feature(ip_in_core)] +#![no_std] +#![no_main] + +#[macro_use] +extern crate log; +#[macro_use] +extern crate syscall_table; +#[macro_use] +extern crate platform; +extern crate alloc; + +use alloc::boxed::Box; +pub use syscall_table::*; +mod fs; +mod task; +mod time; +mod trap; +mod ipc; +mod mm; +mod net; +mod gui; +mod system; + +use core::hint::spin_loop; +use core::panic::PanicInfo; +use core::sync::atomic::{AtomicBool, Ordering}; +use platform::{platform_machine_info, system_shutdown}; +use crate::task::DriverTaskImpl; + +/// 多核启动标志 +static STARTED: AtomicBool = AtomicBool::new(false); + + +#[no_mangle] +fn main(hart_id:usize){ + if STARTED.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed).is_ok() { + println!("Boot hart {}", hart_id); + let machine_info = platform_machine_info(); + println!("{:#?}", machine_info); + mem::init_memory_system(machine_info.memory.end, true); + interrupt::init_plic(machine_info.plic.start); + drivers::register_task_func(Box::new(DriverTaskImpl)); + devices::init_device(Box::new(DriverTaskImpl)); + vfs::init_filesystem().expect("init filesystem failed"); + trap::init_trap_subsystem(); + arch::allow_access_user_memory(); + task::init_process(); + // register all syscall + syscall_table::init_init_array!(); + STARTED.store(false, Ordering::Relaxed); + }else { + while STARTED.load(Ordering::Relaxed) { + spin_loop(); + } + mem::init_memory_system(0, false); + arch::allow_access_user_memory(); + trap::init_trap_subsystem(); + println!("hart {} start", arch::hart_id()); + } + time::set_next_trigger(); + println!("Begin run task..."); + task::schedule::run_task(); +} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + println!("{}", info); + system_shutdown(); +} \ No newline at end of file diff --git a/kkernel/src/mm/elf.rs b/kkernel/src/mm/elf.rs new file mode 100644 index 00000000..a88aaca9 --- /dev/null +++ b/kkernel/src/mm/elf.rs @@ -0,0 +1,150 @@ +use alloc::string::String; +use alloc::vec; +use alloc::vec::Vec; +use core::fmt::{Debug, Formatter}; + +use page_table::table::Sv39PageTable; +use xmas_elf::sections::SectionData; +use xmas_elf::symbol_table::Entry; +use xmas_elf::ElfFile; +use mem::VmmPageAllocator; + +#[allow(unused)] +#[derive(Debug)] +pub enum ELFError { + NotELF, + FileBreak, + NotSupported, + NoLoadableSegment, + NoStackSegment, + NoEntrySegment, + RelocationError, + DynsymNotFind, +} + +impl Debug for ELFInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!( + "ELFInfo {{ address_space: {:#x?}, entry: {:#x}, stack_top: {:#x} }}", + self.address_space.root_paddr().as_usize() >> 12, + self.entry, + self.stack_top + )) + } +} + +pub struct ELFInfo { + pub address_space: Sv39PageTable, + pub entry: usize, + pub stack_top: usize, + pub heap_bottom: usize, + pub ph_num: usize, + pub ph_entry_size: usize, + pub ph_drift: usize, + pub tls: usize, + pub bias: usize, + pub name: String, +} + +pub trait ELFReader { + fn build_elf(&mut self) -> Result; + fn relocate(&self, bias: usize) -> Result, ELFError>; +} + +impl ELFReader for ElfFile<'_> { + fn build_elf(&mut self) -> Result { + Err(ELFError::NotSupported) + } + fn relocate(&self, bias: usize) -> Result, ELFError> { + let mut res = vec![]; + let data = self + .find_section_by_name(".rela.dyn") + .ok_or(ELFError::RelocationError)? + .get_data(self) + .map_err(|_| ELFError::RelocationError)?; + let entries = match data { + SectionData::Rela64(entries) => entries, + _ => return Err(ELFError::RelocationError), + }; + let dynsym = match self + .find_section_by_name(".dynsym") + .ok_or(ELFError::DynsymNotFind)? + .get_data(self) + .map_err(|_| ELFError::DynsymNotFind)? + { + SectionData::DynSymbolTable64(dsym) => Ok(dsym), + _ => Err(ELFError::DynsymNotFind), + }?; + for entry in entries.iter() { + const REL_GOT: u32 = 6; + const REL_PLT: u32 = 7; + const REL_RELATIVE: u32 = 8; + const R_RISCV_64: u32 = 2; + const R_RISCV_RELATIVE: u32 = 3; + match entry.get_type() { + REL_GOT | REL_PLT | R_RISCV_64 => { + let dynsym = &dynsym[entry.get_symbol_table_index() as usize]; + let symval = if dynsym.shndx() == 0 { + let name = dynsym.get_name(self).map_err(|_| ELFError::DynsymNotFind)?; + panic!("need to find symbol: {:?}", name); + } else { + bias + dynsym.value() as usize + }; + let value = symval + entry.get_addend() as usize; + let addr = bias + entry.get_offset() as usize; + res.push((addr, value)) + } + REL_RELATIVE | R_RISCV_RELATIVE => { + let value = bias + entry.get_addend() as usize; + let addr = bias + entry.get_offset() as usize; + res.push((addr, value)) + } + t => unimplemented!("unknown type: {}", t), + } + } + + // + let data = self + .find_section_by_name(".rela.plt") + .ok_or(ELFError::RelocationError)? + .get_data(self) + .map_err(|_| ELFError::RelocationError)?; + let entries = match data { + SectionData::Rela64(entries) => entries, + _ => return Err(ELFError::RelocationError), + }; + for entry in entries.iter() { + match entry.get_type() { + 5 => { + let dynsym = &dynsym[entry.get_symbol_table_index() as usize]; + let symval = if dynsym.shndx() == 0 { + let name = dynsym.get_name(self).map_err(|_| ELFError::DynsymNotFind)?; + panic!("symbol not found: {:?}", name); + } else { + dynsym.value() as usize + }; + let value = bias + symval; + let addr = bias + entry.get_offset() as usize; + res.push((addr, value)) + } + t => panic!("[kernel] unknown entry, type = {}", t), + } + } + Ok(res) + } +} +// /* RISC-V relocations. */ +// #define R_RISCV_NONE 0 +// #define R_RISCV_32 1 +// #define R_RISCV_64 2 +// #define R_RISCV_RELATIVE 3 +// #define R_RISCV_COPY 4 +// #define R_RISCV_JUMP_SLOT 5 +// #define R_RISCV_TLS_DTPMOD32 6 +// #define R_RISCV_TLS_DTPMOD64 7 +// #define R_RISCV_TLS_DTPREL32 8 +// #define R_RISCV_TLS_DTPREL64 9 +// #define R_RISCV_TLS_TPREL32 10 +// #define R_RISCV_TLS_TPREL64 11 +// #define R_RISCV_BRANCH 16 +// #define R_RISCV_JAL 17 diff --git a/kkernel/src/mm/loader.rs b/kkernel/src/mm/loader.rs new file mode 100644 index 00000000..0279b796 --- /dev/null +++ b/kkernel/src/mm/loader.rs @@ -0,0 +1,395 @@ +use config::*; +use crate::fs; +use crate::ipc::ShmInfo; +use crate::mm::elf::{ELFError, ELFInfo, ELFReader}; +use crate::trap::TrapFrame; +use alloc::collections::BTreeMap; +use alloc::string::{String, ToString}; +use alloc::vec; +use alloc::vec::Vec; +use core::cmp::min; +use core::fmt::Debug; +use page_table::addr::{align_up_4k, PhysAddr, VirtAddr}; +use page_table::pte::MappingFlags; +use page_table::table::{Sv39PageTable}; +use xmas_elf::program::{SegmentData, Type}; +use mem::{FRAME_REF_MANAGER, VmmPageAllocator}; + +extern "C" { + fn strampoline(); +} +#[derive(Debug)] +pub struct UserStack { + pub virt_stack_top: usize, + pub stack_top: usize, + pub stack_bottom: usize, +} + +impl UserStack { + pub fn new(phy_stack_top: usize, virt_stack_top: usize) -> Self { + Self { + virt_stack_top, + stack_top: phy_stack_top, + stack_bottom: phy_stack_top - FRAME_SIZE, + } + } + + pub fn push(&mut self, data: usize) -> Result { + if self.stack_top - 8 < self.stack_bottom { + return Err("Stack Overflow"); + } + unsafe { + self.stack_top -= 8; + *(self.stack_top as *mut usize) = data; + } + trace!( + "stack top: {:#x}, data:{:#x?}", + self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom)), + data + ); + Ok(self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom))) + } + + pub fn push_str(&mut self, data: &str) -> Result { + self.push_bytes(data.as_bytes()) + } + + pub fn push_bytes(&mut self, data: &[u8]) -> Result { + let len = data.len(); + // align 8 + let start = self.stack_top - len; + let start = start & !7; + if start < self.stack_bottom { + return Err("Stack Overflow"); + } + unsafe { + self.stack_top = start; + let ptr = self.stack_top as *mut u8; + ptr.copy_from_nonoverlapping(data.as_ptr(), len); + } + trace!( + "stack top: {:#x}", + self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom)) + ); + Ok(self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom))) + } + + pub fn align_to(&mut self, align: usize) -> Result { + let start = self.stack_top & !(align - 1); + if start < self.stack_bottom { + return Err("Stack Overflow"); + } + self.stack_top = start; + Ok(self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom))) + } +} + +pub fn build_thread_address_space( + table: &mut Sv39PageTable, + thread_num_within: usize, +) -> &'static mut TrapFrame { + let address = TRAP_CONTEXT_BASE - FRAME_SIZE * thread_num_within; + let (_virt_dst, phy_dst, _) = table + .map_region_no_target( + VirtAddr::from(address), + FRAME_SIZE, + "RWVAD".into(), + true, + false, + ) + .unwrap() + .next() + .unwrap(); + // copy data + // find the + let (phy, _flag, page_size) = table.query(VirtAddr::from(TRAP_CONTEXT_BASE)).unwrap(); + assert_eq!(usize::from(page_size), FRAME_SIZE); + // copy data + let src_ptr = phy.as_usize() as *const u8; + let dst_ptr = phy_dst.as_usize() as *mut u8; + unsafe { + core::ptr::copy(src_ptr, dst_ptr, usize::from(page_size)); + } + TrapFrame::from_raw_ptr(dst_ptr as *mut TrapFrame) +} + +pub fn build_cow_address_space( + p_table: &mut Sv39PageTable, + shm: BTreeMap, +) -> Sv39PageTable { + let mut address_space = Sv39PageTable::::try_new().unwrap(); + for (v_addr, target) in p_table.get_record().into_iter() { + trace!("v_addr: {:?}, target: {}", v_addr, target); + let (phy, flag, page_size) = p_table.query(v_addr).unwrap(); + + // shm should remap, we can't use cow for it + let is_in_segs = |addr: usize| -> bool { + for (_id, shminfo) in shm.iter() { + if addr >= shminfo.start_va && addr < shminfo.end_va { + return true; + } + } + false + }; + + if v_addr.as_usize() == TRAP_CONTEXT_BASE { + // for Trap_context, we remap it + assert_eq!(usize::from(page_size), TRAMPOLINE - TRAP_CONTEXT_BASE); + let dst = address_space + .map_no_target(v_addr, page_size, flag, false) + .unwrap(); + // copy data + let src_ptr = phy.as_usize() as *const u8; + let dst_ptr = dst.as_usize() as *mut u8; + unsafe { + core::ptr::copy(src_ptr, dst_ptr, usize::from(page_size)); + } + } else if is_in_segs(v_addr.as_usize()) { + // for shm, we now skip it + address_space.map(v_addr, phy, page_size, flag).unwrap(); + } else { + // cow + // checkout whether pte flags has `W` flag + let mut flags = flag.clone(); + if !flag.contains(MappingFlags::V) { + // if flags is not valid, we just map it + address_space.map(v_addr, phy, page_size, flags).unwrap(); + if target { + address_space.get_record_mut().insert(v_addr, true); + } + continue; + } + if flag.contains(MappingFlags::W) { + flags -= MappingFlags::W; + flags |= MappingFlags::RSD; // we use the RSD flag to indicate that this page is a cow page + // update parent's flag and clear dirty + p_table.modify_pte_flags(v_addr, flags, false).unwrap(); + } + address_space.map(v_addr, phy, page_size, flags).unwrap(); + // add ref for alloc page + if target { + for i in 0..usize::from(page_size) / FRAME_SIZE { + let page_number = (phy + FRAME_SIZE * i).as_usize() >> FRAME_BITS; + // FRAME_REF_MANAGER.lock().get_ref(page_number); + FRAME_REF_MANAGER.lock().add_ref(page_number); + } + address_space.get_record_mut().insert(v_addr, true); + } + } + } + address_space +} + +pub fn build_elf_address_space( + elf: &[u8], + args: &mut Vec, + name: &str, +) -> Result { + let mut address_space = Sv39PageTable::::try_new().unwrap(); + const ELF_MAGIC: [u8; 4] = [0x7f, b'E', b'L', b'F']; + if elf[0..4] != ELF_MAGIC { + return Err(ELFError::NotELF); + } + let elf = xmas_elf::ElfFile::new(elf).map_err(|_| ELFError::NotELF)?; + // check whether it's a dynamic linked elf + if let Some(inter) = elf + .program_iter() + .find(|ph| ph.get_type().unwrap() == Type::Interp) + { + let data = match inter.get_data(&elf).unwrap() { + SegmentData::Undefined(data) => data, + _ => return Err(ELFError::NoEntrySegment), + }; + let path = core::str::from_utf8(data).unwrap(); + assert!(path.starts_with("/lib/ld-musl-riscv64-sf.so.1")); + let mut new_args = vec!["/libc.so\0".to_string()]; + new_args.extend(args.clone()); + *args = new_args; + // load interpreter + let mut data = vec![]; + warn!("load interpreter: {}, new_args:{:?}", path, args); + if fs::read_all("libc.so", &mut data) { + return build_elf_address_space(&data, args, "libc.so"); + } else { + error!("[map_elf] Found interpreter path: {}", path); + panic!("load interpreter failed"); + } + } + + // calculate bias for dynamic linked elf + // if elf is static linked, bias is 0 + let bias = match elf.header.pt2.type_().as_type() { + // static + xmas_elf::header::Type::Executable => 0, + xmas_elf::header::Type::SharedObject => { + match elf + .program_iter() + .filter(|ph| ph.get_type().unwrap() == Type::Interp) + .count() + { + // It's a loader! + 0 => ELF_BASE_RELOCATE, + // It's a dynamically linked ELF. + 1 => 0, + // Emmm, It has multiple interpreters. + _ => return Err(ELFError::NotSupported), + } + } + _ => return Err(ELFError::NotSupported), + }; + trace!("bias: {:#x}", bias); + + let tls = elf + .program_iter() + .find(|x| x.get_type().unwrap() == Type::Tls) + .map(|ph| ph.virtual_addr()) + .unwrap_or(0); + + warn!("ELF tls: {:#x}", tls); + + let mut break_addr = 0usize; + elf.program_iter() + .filter(|ph| ph.get_type() == Ok(Type::Load)) + .for_each(|ph| { + let start_addr = ph.virtual_addr() as usize + bias; + let end_addr = start_addr + ph.mem_size() as usize; + let mut permission: MappingFlags = "UVAD".into(); + let ph_flags = ph.flags(); + if ph_flags.is_read() { + permission |= MappingFlags::R; + } + if ph_flags.is_write() { + permission |= MappingFlags::W; + } + if ph_flags.is_execute() { + permission |= MappingFlags::X; + } + let vaddr = VirtAddr::from(start_addr).align_down_4k(); + let end_vaddr = VirtAddr::from(end_addr).align_up_4k(); + // 记录程序地址空间的最大地址 + break_addr = end_addr; + let len = end_vaddr.as_usize() - vaddr.as_usize(); + warn!( + "load segment: {:#x} - {:#x} -> {:#x}-{:#x}, permission: {:?}", + start_addr, + end_addr, + vaddr.as_usize(), + end_vaddr.as_usize(), + permission + ); + let mut data = + &elf.input[ph.offset() as usize..(ph.offset() + ph.file_size()) as usize]; + let map_info = address_space + .map_region_no_target(vaddr, len, permission, false, false) + .unwrap(); + // copy data + let mut page_offset = start_addr & (FRAME_SIZE - 1); + let mut count = 0; + map_info + .into_iter() + .for_each(|(_vir, phy, page_size)| unsafe { + let size: usize = page_size.into(); + let min = min(size - page_offset, data.len()); + let dst = (phy.as_usize() + page_offset) as *mut u8; + core::ptr::copy(data.as_ptr(), dst, min); + data = &data[min..]; + count += min; + page_offset = 0; + }); + assert_eq!(count, ph.file_size() as usize); + }); + + // 地址向上取整对齐4 + let ceil_addr = align_up_4k(break_addr + FRAME_SIZE); + // 留出一个用户栈的位置+隔离页 + let top = ceil_addr + USER_STACK_SIZE + FRAME_SIZE; + warn!( + "user stack: {:#x} - {:#x}", + top - USER_STACK_SIZE - FRAME_SIZE, + top - FRAME_SIZE + ); + // map user stack + address_space + .map_region_no_target( + VirtAddr::from(top - USER_STACK_SIZE - FRAME_SIZE), + USER_STACK_SIZE, + "RWUAD".into(), + false, + true, + ) + .unwrap(); + // 初始化一个有效页 + address_space + .validate(VirtAddr::from(top - FRAME_SIZE * 2), "RWUVAD".into()) + .unwrap(); + let heap_bottom = top; + // align to 4k + warn!("trap context: {:#x} - {:#x}", TRAP_CONTEXT_BASE, TRAMPOLINE); + address_space + .map_region_no_target( + VirtAddr::from(TRAP_CONTEXT_BASE), + TRAMPOLINE - TRAP_CONTEXT_BASE, + "RWVAD".into(), + true, + false, + ) + .unwrap(); + warn!( + "TRAMPOLINE: {:#x} - {:#x}", + TRAMPOLINE, + TRAMPOLINE + FRAME_SIZE + ); + address_space + .map_region( + VirtAddr::from(TRAMPOLINE), + PhysAddr::from(strampoline as usize), + FRAME_SIZE, + "RXVAD".into(), + true, + ) + .unwrap(); + + let res = if let Some(phdr) = elf + .program_iter() + .find(|ph| ph.get_type() == Ok(Type::Phdr)) + { + // if phdr exists in program header, use it + Ok(phdr.virtual_addr()) + } else if let Some(elf_addr) = elf + .program_iter() + .find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0) + { + // otherwise, check if elf is loaded from the beginning, then phdr can be inferred. + // Ok(elf_addr.virtual_addr()) + Ok(elf_addr.virtual_addr() + elf.header.pt2.ph_offset()) + } else { + warn!("elf: no phdr found, tls might not work"); + Err(ELFError::NoEntrySegment) + } + .unwrap_or(0); + warn!( + "entry: {:#x}, phdr:{:#x}", + elf.header.pt2.entry_point() + bias as u64, + res + bias as u64 + ); + // relocate if elf is dynamically linked + if let Ok(kvs) = elf.relocate(bias) { + kvs.into_iter().for_each(|kv| { + trace!("relocate: {:#x} -> {:#x}", kv.0, kv.1); + let (addr, ..) = address_space.query(VirtAddr::from(kv.0)).unwrap(); + unsafe { (addr.as_usize() as *mut usize).write(kv.1) } + }) + } + Ok(ELFInfo { + address_space, + entry: elf.header.pt2.entry_point() as usize + bias, + stack_top: top - FRAME_SIZE, + heap_bottom, + ph_num: elf.header.pt2.ph_count() as usize, + ph_entry_size: elf.header.pt2.ph_entry_size() as usize, + ph_drift: res as usize + bias, + tls: tls as usize, + bias, + name: name.to_string(), + }) +} diff --git a/kkernel/src/mm/map.rs b/kkernel/src/mm/map.rs new file mode 100644 index 00000000..85b77fa0 --- /dev/null +++ b/kkernel/src/mm/map.rs @@ -0,0 +1,254 @@ +use alloc::sync::Arc; +use alloc::vec::Vec; +use core::ops::Range; + +use bitflags::bitflags; +use page_table::addr::{align_up_4k, VirtAddr}; +use page_table::pte::MappingFlags; + +use constants::io::MapFlags; +use constants::LinuxErrno; +use syscall_table::syscall_func; + +use config::{FRAME_SIZE, PROCESS_HEAP_MAX}; +use crate::fs::file::File; +use crate::task::current_task; +use constants::AlienResult; + +bitflags! { + pub struct ProtFlags: u32 { + const PROT_NONE = 0x0; + const PROT_READ = 0x1; + const PROT_WRITE = 0x2; + const PROT_EXEC = 0x4; + } +} + +impl Into for ProtFlags { + fn into(self) -> MappingFlags { + let mut perm = MappingFlags::empty(); + if self.contains(ProtFlags::PROT_READ) { + perm |= MappingFlags::R; + } + if self.contains(ProtFlags::PROT_WRITE) { + perm |= MappingFlags::W; + } + if self.contains(ProtFlags::PROT_EXEC) { + perm |= MappingFlags::X; + } + perm |= MappingFlags::U; + perm + } +} + +#[derive(Debug, Clone)] +/// The Process should manage the mmap info +pub struct MMapInfo { + /// The start address of the mmap, it is a constant + map_start: usize, + /// The regions of the mmap + regions: Vec, +} + +#[derive(Debug, Clone)] +pub struct MMapRegion { + /// The start address of the mapping + pub start: usize, + /// The length of the mapping + pub len: usize, + pub map_len: usize, + /// The protection flags of the mapping + pub prot: ProtFlags, + /// The flags of the mapping + pub flags: MapFlags, + /// The file descriptor to map + pub fd: Option>, + /// The offset in the file to start from + pub offset: usize, +} + +impl MMapInfo { + pub fn new() -> Self { + Self { + map_start: PROCESS_HEAP_MAX, + regions: Vec::new(), + } + } + + pub fn alloc(&mut self, len: usize) -> Range { + let addr = self.map_start; + self.map_start += len; + // align to Frame size + self.map_start = (self.map_start + FRAME_SIZE - 1) & !(FRAME_SIZE - 1); + addr..self.map_start + } + + pub fn add_region(&mut self, region: MMapRegion) { + self.regions.push(region); + } + + pub fn get_region(&self, addr: usize) -> Option<&MMapRegion> { + for region in self.regions.iter() { + if region.start <= addr && addr < region.start + region.len { + return Some(region); + } + } + None + } + + pub fn get_region_mut(&mut self, addr: usize) -> Option<&mut MMapRegion> { + for region in self.regions.iter_mut() { + if region.start <= addr && addr < region.start + region.len { + return Some(region); + } + } + None + } + + pub fn remove_region(&mut self, addr: usize) { + let mut index = 0; + for region in self.regions.iter() { + if region.start <= addr && addr < region.start + region.len { + break; + } + index += 1; + } + self.regions.remove(index); + } +} + +impl MMapRegion { + pub fn new( + start: usize, + len: usize, + map_len: usize, + prot: ProtFlags, + flags: MapFlags, + fd: Option>, + offset: usize, + ) -> Self { + Self { + start, + len, + map_len, + prot, + flags, + fd, + offset, + } + } + // [a-b] + // [a-c] [c-b] + pub fn split(&self, addr: usize) -> (Self, Self) { + let mut region1 = self.clone(); + let mut region2 = self.clone(); + region1.len = addr - self.start; + region1.map_len = align_up_4k(region1.len); + region2.start = addr; + region2.len = self.start + self.len - addr; + region2.map_len = align_up_4k(region2.len); + region2.offset += region1.len; + (region1, region2) + } + + pub fn set_prot(&mut self, prot: ProtFlags) { + self.prot = prot; + } + pub fn set_flags(&mut self, flags: MapFlags) { + self.flags = flags; + } +} + +/// 一个函数调用,用于消除内存映射。 +/// 注意:传入的`start`必须是某段内存映射的首地址,`len`必须是该段内存映射的长度,否则将导致函数返回`EINVAL`。函数正常执行将返回0。 +#[syscall_func(215)] +pub fn do_munmap(start: usize, len: usize) -> isize { + let task = current_task().unwrap(); + let res = task.access_inner().unmap(start, len); + if res.is_err() { + return res.err().unwrap(); + } + 0 +} + +/// 一个系统调用,用于将文件或设备映射到内存中。将一个普通文件映射到内存中,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能。 +/// +/// + `start`: 所要创建的映射区的起始地址。当该值为0时,内核将自动为其分配一段内存空间创建内存映射。该值在函数运行过程中将被调整为与4K对齐。 +/// + `len`: 指明所要创建的映射区的长度。该值在函数运行过程中将被调整为与4K对齐。 +/// + `prot`: 指明创建内存映射区的初始保护位。具体可见[`ProtFlags`]。 +/// + `flags`: 指明mmap操作的相关设置。具体可见[`MapFlags`]。 +/// + `fd`: 指明要创建内存映射的文件的文件描述符。 +/// + `offset`: 将从文件中偏移量为`offset`处开始映射。该值需要和4K对齐。 +/// +/// 函数成功执行后将返回所创建的内存映射区的首地址;否则返回错误类型。 +/// Reference: [do_mmap](https://man7.org/linux/man-pages/man2/mmap.2.html) +#[syscall_func(222)] +pub fn do_mmap( + start: usize, + len: usize, + prot: u32, + flags: u32, + fd: usize, + offset: usize, +) -> AlienResult { + let process = current_task().unwrap(); + let mut process_inner = process.access_inner(); + let prot = ProtFlags::from_bits_truncate(prot); + let flags = MapFlags::from_bits_truncate(flags); + warn!( + "mmap: start: {:#x}, len: {:#x}, prot: {:?}, flags: {:?}, fd: {}, offset: {:#x}", + start, len, prot, flags, fd, offset + ); + process_inner + .add_mmap(start, len, prot, flags, fd, offset) + .map(|addr| addr as isize) +} + +/// 一个系统调用,用于修改内存映射的保护位,从而修改对内存映射的访问权限。 +/// 函数会检查传入的`start`和`len`所指示的内存映射区是否已经处于被映射状态,如果是,则将对应内存映射区的保护位与`prot`做或运算。 +/// +/// 如果函数正常执行,则返回0;如果`start`和`len`所指示的内存映射区未已经处于被映射状态,函数将返回-1。 +#[syscall_func(226)] +pub fn map_protect(start: usize, len: usize, prot: u32) -> AlienResult { + let process = current_task().unwrap(); + let mut process_inner = process.access_inner(); + let prot = ProtFlags::from_bits_truncate(prot); + warn!( + "mprotect: start: {:#x}, len: {:#x}, prot: {:?}", + start, len, prot + ); + process_inner.map_protect(start, len, prot)?; + Ok(0) +} + +/// (待实现)一个系统调用,用于同步文件在内存映射中的修改。一个文件通过[`do_mmap`]映射到内存中,可以在内存中对其进行快速的读写。 +/// 当我们对文件的映射进行修改后,如果不调用`msync`系统调用,那么在调用[`do_munmap`]之前内存中的相应内容都不会写回磁盘文件,有可能导致不一致性问题。 +/// 目前函数仅会检查所传入的`addr`是否已经被映射,如果没有被映射,则会返回`EFAULT`;否则直接返回0。 +/// +/// Reference: [madvise](https://man7.org/linux/man-pages/man2/madvise.2.html) +#[syscall_func(227)] +pub fn msync(addr: usize, len: usize, flags: usize) -> isize { + warn!( + "msync: addr: {:#x}, len: {:#x}, flags: {:#x}", + addr, len, flags + ); + let task = current_task().unwrap(); + let address_space = &task.access_inner().address_space; + let res = address_space.lock().query(VirtAddr::from(addr)); + if res.is_err() { + return LinuxErrno::EFAULT as isize; + } + 0 +} + +/// (待实现)一个系统调用,用于向内核提供使用内存的建议。目前直接返回0。 +/// +/// Reference: [madvise](https://man7.org/linux/man-pages/man2/madvise.2.html) +#[syscall_func(233)] +pub fn madvise(addr: usize, len: usize, advice: usize) -> isize { + warn!( + "madvise: addr: {:#x}, len: {:#x}, advice: {:#x}", + addr, len, advice + ); + 0 +} diff --git a/kkernel/src/mm/mod.rs b/kkernel/src/mm/mod.rs new file mode 100644 index 00000000..27020c21 --- /dev/null +++ b/kkernel/src/mm/mod.rs @@ -0,0 +1,20 @@ +use arch::hart_id; + +pub mod map; +pub mod elf; +pub mod loader; + + +/// This function will be call in slab allocator +#[no_mangle] +fn current_cpu_id() -> usize { + hart_id() +} + +/// (待实现)在一组线程中,设置内存屏障,控制多核系统中的内存访问次序。目前直接返回0。 +/// +/// +#[syscall_func(283)] +pub fn membarrier() -> isize { + 0 +} diff --git a/kkernel/src/net/addr.rs b/kkernel/src/net/addr.rs new file mode 100644 index 00000000..91afe025 --- /dev/null +++ b/kkernel/src/net/addr.rs @@ -0,0 +1,125 @@ +//! 在 Alien 内核中使用的 socket 套接字地址结构。 +//! +//! Alien 中目前能够接收的套接字地址种类包括本地路径地址和网络套接字地址。 +//! 对于从用户端传来的套接字地址,类似于 `linux` 中 `socket.h` 的套接字地址。 +//! 大致结构如下: +//! + 2字节表明该套接字使用的地址协议族 +//! + 2字节表明该套接字的端口 +//! + 12字节的地址数据 +//! +//! Alien 将会首先对传入的套接字的协议族进行解析,然后根据不同的地址协议族将其解析成 [`SocketAddrExt`] 结构, +//! 向下层的具体套接字中传递相应地址时,传递的也是 [`SocketAddrExt`] 结构。 +//! +use alloc::string::{String, ToString}; +use alloc::vec; +use core::fmt::Debug; +use core::net::{IpAddr, Ipv4Addr, SocketAddr}; + +use crate::task::current_task; +use constants::net::Domain; +use constants::{AlienResult,LinuxErrno}; + +/// 用于存储套接字通信地址的结构,分为本地路径地址和网络套接字地址。 +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +pub enum SocketAddrExt { + LocalPath(String), + SocketAddr(SocketAddr), +} + +/// 用于存储一个Ipv4套接字相关信息的结构。对应 `linux` 中 `socket.h` 的 `sockaddr_in` 结构。 +/// +/// 在 socket 相关系统调用中,一般都先分析出套接字采用的地址协议族,如果是 `IPV4` 则会将传入的套接字相关信息解析成 `RawIpV4Addr`。 +/// 且 `Alien` 目前默认使用网络套接字时,即采用 `IPV4` 协议。 +#[repr(C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct RawIpV4Addr { + /// 地址协议族 + pub family: u16, + /// Ipv4 的端口 + pub port: u16, + /// Ipv4 的地址 + pub addr: u32, + /// 零位,用于后续扩展 + pub zero: [u8; 8], +} + +impl SocketAddrExt { + /// 获取网络套接字地址。当本结构中存储的是本地路径地址时,将导致 panic。 + pub fn get_socketaddr(&self) -> SocketAddr { + match self { + SocketAddrExt::LocalPath(_) => { + panic!("Can't get socketaddr from local path") + } + SocketAddrExt::SocketAddr(addr) => *addr, + } + } + + /// 获取本地路径地址。当本结构中存储的是网络套接字地址时,将导致 panic。 + pub fn get_local_path(&self) -> String { + match self { + SocketAddrExt::LocalPath(path) => path.clone(), + SocketAddrExt::SocketAddr(_) => { + panic!("Can't get local path from socketaddr") + } + } + } +} + +impl From for RawIpV4Addr { + /// 用一个 [`SocketAddr`] 结构 初始化 `RawIpV4Addr ` + fn from(addr: SocketAddr) -> Self { + let ip = addr.ip(); + let port = addr.port(); + let ip = match ip { + IpAddr::V4(ip) => ip, + IpAddr::V6(_) => { + panic!("ipv6 is not supported") + } + }; + let ip = ip.octets(); + let ip = u32::from_le_bytes(ip); + Self { + family: Domain::AF_INET as u16, + port: port.to_be(), + addr: ip, + zero: [0u8; 8], + } + } +} + +/// 地址解析,将根据`family_user_addr`的[`Domain`]类型分类进行解析。 +/// +/// 对于`AF_INET`将解析成SocketAddrExt::SocketAddr(SocketAddr), +/// 对于`AF_UNIX`将解析成ocketAddrExt::LocalPath(String),详情可见[`SocketAddrExt`]。 +pub fn socket_addr_resolution(family_user_addr: usize, len: usize) -> AlienResult { + let task = current_task().unwrap(); + let family = task + .access_inner() + .transfer_raw_ptr(family_user_addr as *const u16); + let domain = Domain::try_from(*family as usize).map_err(|_| LinuxErrno::EINVAL)?; + match domain { + Domain::AF_INET => { + let mut ip_addr = RawIpV4Addr::default(); + task.access_inner() + .copy_from_user(family_user_addr as *const RawIpV4Addr, &mut ip_addr); + let ip = u32::from_be_bytes(ip_addr.addr.to_le_bytes()); + let ipv4_addr = IpAddr::V4(Ipv4Addr::from(ip)); + let port = u16::from_be(ip_addr.port); + Ok(SocketAddrExt::SocketAddr(SocketAddr::new( + ipv4_addr.into(), + port, + ))) + } + Domain::AF_UNIX => { + // local path + let mut buf = vec![0u8; len]; + task.access_inner().copy_from_user_buffer( + family_user_addr as *const u8, + buf.as_mut_ptr(), + len, + ); + let path = String::from_utf8_lossy(&buf[2..len - 2]).to_string(); + Ok(SocketAddrExt::LocalPath(path)) + } + } +} diff --git a/kkernel/src/net/mod.rs b/kkernel/src/net/mod.rs new file mode 100644 index 00000000..afbd60f8 --- /dev/null +++ b/kkernel/src/net/mod.rs @@ -0,0 +1,475 @@ +//! Alien 内核部分的的网络模块,向下调用 `simple_net` 模块实现 tcp 和 udp 套接字的系统调用。 +//! +//! [`addr`] 子模块指明了在 Alien 内核中使用的 socket 套接字地址结构。 +//! [`port`] 子模块现为将网络异常类型 [`NetError`] 转为 系统异常类型 [`LinuxErrno`]的模块。 +//! [`socket`] 子模块指明了Alien 内核中使用的套接字。 +//! [`unix`] 子模块指明了有关 Unix 协议族下的套接字结构。(目前有关的功能有待支持) +//! +use crate::fs::file::File; +use crate::net::addr::{socket_addr_resolution, RawIpV4Addr}; +use crate::net::socket::{SocketData, SocketFile, SocketFileExt}; +use crate::task::{current_task, do_suspend}; +use alloc::sync::Arc; +use alloc::vec; +use alloc::vec::Vec; +use constants::io::OpenFlags; +use constants::net::*; +use constants::{AlienResult,LinuxErrno}; + +pub mod addr; +pub mod port; +pub mod socket; +mod unix; + +/// 一个系统调用,用于创建一个未绑定的socket套接字。 +/// +/// + `domain`: 指明套接字被创建的协议簇(包括文件路径协议簇和网络地址协议簇,具体可见[`Domain`]); +/// + `s_type`: 指明被创建的socket的类型,具体可见[`SocketType`]; +/// + `protocol`: 指明该socket应用于某一个特定的协议上。当确定了套接字使用的协议簇和类型,该参数可以取为0。 +/// +/// 如果创建套接字成功则返回一个能在之后使用的文件描述符,否则返回错误信息。 +#[syscall_func(198)] +pub fn socket(domain: usize, s_type: usize, protocol: usize) -> AlienResult { + let domain = Domain::try_from(domain).map_err(|_| LinuxErrno::EAFNOSUPPORT)?; + let socket_type = + SocketType::try_from(s_type & SOCKET_TYPE_MASK as usize).map_err(|_| LinuxErrno::EINVAL)?; + let task = current_task().unwrap(); + let file = SocketData::new(domain, socket_type, protocol)?; + info!("socket domain: {:?}, type: {:?}", domain, socket_type); + if s_type & SocketType::SOCK_NONBLOCK as usize != 0 { + let socket = file.get_socketdata()?; + file.set_open_flag(file.get_open_flag() | OpenFlags::O_NONBLOCK); + socket.set_socket_nonblock(true); + info!("socket with nonblock"); + } + if s_type & SocketType::SOCK_CLOEXEC as usize != 0 { + file.set_close_on_exec(); + info!("socket with cloexec"); + } + let fd = task.add_file(file).map_err(|_| LinuxErrno::EMFILE)?; + Ok(fd as isize) +} + +/// 一个系统调用,用于绑定socket的地址和端口。 +/// +/// + `socketfd`: 指明要操作socket的文件描述符fd; +/// + `sockaddr`: 指明存储有关绑定信息([`RawIpV4Addr`])的地址; +/// + `len`: `address`([`RawIpV4Addr`])的长度。 +/// +/// 执行成功则返回0,否则返回错误信息。 +#[syscall_func(200)] +pub fn bind(socketfd: usize, sockaddr: usize, len: usize) -> AlienResult { + let socket_fd = common_socket_syscall(socketfd)?; + let socket_addr = socket_addr_resolution(sockaddr, len)?; + let socket = socket_fd.get_socketdata()?; + match socket.bind(socket_addr.clone()) { + Ok(()) => { + let local_addr = socket.local_addr(); + info!( + "[{:?}] {:?} connect to ip: {:?}", + socket.s_type, local_addr, socket_addr + ); + Ok(0) + } + Err(e) => Err(e.into()), + } +} + +/// 一个系统调用,用于等待client提交连接请求,一般用于bind之后,accept之前 +/// +/// + `socketfd`: 指明要操作socket的文件描述符fd; +/// + `backlog`: 指明套接字侦听队列中正在处于半连接状态(等待accept)的请求数最大值。如果该值小于等于0,则自动调为0,同时也有最大值上限。 +/// +/// 执行成功则返回0,否则返回错误信息。 +#[syscall_func(201)] +pub fn listening(socketfd: usize, backlog: usize) -> AlienResult { + let socket_fd = common_socket_syscall(socketfd)?; + let socket = socket_fd.get_socketdata()?; + match socket.listening(backlog) { + Ok(_) => { + info!("socket {:?} listening", socket.local_addr()); + Ok(0) + } + Err(e) => Err(e), + } +} + +/// 一个系统调用,用于取出套接字listen队列中的第一个连接,创建一个与指定套接字具有相同套接字类型的地址族的新套接字。 +/// 新套接字用于传递数据,原套接字继续处理侦听队列中的连接请求。如果侦听队列中无请求,accept()将阻塞。 +/// +/// + `socketfd`: 指明要操作socket的文件描述符fd,需经过bind()和listen()处理; +/// + `socket_addr`: 要么为空,要么指明保存accept成功的客户端相关信息([`RawIpV4Addr`])的地址; +/// + `addr_len`: 保存连接的client相关信息`address`长度的地址。 +/// +/// 执行成功则返回新的套接字的文件描述符,否则返回错误信息. +#[syscall_func(202)] +pub fn accept(socketfd: usize, socket_addr: usize, addr_len: usize) -> AlienResult { + let socket_fd = common_socket_syscall(socketfd)?; + let socket = socket_fd.get_socketdata()?; + match socket.accept() { + Ok(file) => { + let task = current_task().unwrap(); + // get peer addr + if socket_addr != 0 { + let socket = file.get_socketdata()?; + let peer_addr = socket.peer_addr().unwrap(); + info!("accept peer addr: {:?}", peer_addr); + let raw_ip_addr = RawIpV4Addr::from(peer_addr); + let addr_len_ref = task + .access_inner() + .transfer_raw_ptr_mut(addr_len as *mut u32); + *addr_len_ref = core::mem::size_of::() as u32; + task.access_inner() + .copy_to_user(&raw_ip_addr, socket_addr as *mut RawIpV4Addr); + } + let fd = task.add_file(file).map_err(|_| LinuxErrno::EMFILE)?; + Ok(fd as isize) + } + Err(e) => Err(e), + } +} + +/// 一个系统调用,用于client请求在一个套接字上建立连接。 +/// +/// + `socketfd`: 指明要操作socket的文件描述符fd; +/// + `socket_addr`: 指明保存服务器地址和端口号的数据结构([`RawIpV4Addr`])的地址; +/// + `len`: `socket_addr`长度的地址。 +/// +/// 执行成功则返回0,否则返回错误信息。 +/// +/// Note: For netperf_test, the server may be run after client, so we nedd allow +/// client retry once +#[syscall_func(203)] +pub fn connect(socketfd: usize, socket_addr: usize, len: usize) -> AlienResult { + let socket_addr = socket_addr_resolution(socket_addr, len)?; + let socket_fd = common_socket_syscall(socketfd)?; + let socket = socket_fd.get_socketdata()?; + let mut retry = 1; + while retry >= 0 { + match socket.connect(socket_addr.clone()) { + Ok(_) => { + let local_addr = socket.local_addr(); + info!( + "[{:?}] {:?} connect to ip: {:?}", + socket.s_type, local_addr, socket_addr + ); + return Ok(0); + } + Err(e) => { + if retry == 0 { + return Err(e.into()); + } + if e == LinuxErrno::EAGAIN { + return Err(LinuxErrno::EINPROGRESS.into()); + } + retry -= 1; + do_suspend(); + } + } + } + Ok(0) +} + +/// 一个系统调用,查询一个套接字本地bind()的相关信息。 +/// +/// + `socketfd`: 指明要操作socket的文件描述符fd; +/// + `socket_addr`: 指明相关信息([`RawIpV4Addr`])将要保存的地址; +/// + `len`: 保存`address`长度的地址。 +/// +/// 执行成功则返回0,否则返回错误信息。 +#[syscall_func(204)] +pub fn getsockname(socketfd: usize, socket_addr: usize, len: usize) -> AlienResult { + let socket_fd = common_socket_syscall(socketfd)?; + let socket = socket_fd.get_socketdata()?; + let local_addr = socket.local_addr().ok_or(LinuxErrno::EINVAL)?; + info!("getsockname: {:?}", local_addr); + let raw_ip_addr = RawIpV4Addr::from(local_addr); + let task = current_task().unwrap(); + task.access_inner() + .copy_to_user(&raw_ip_addr, socket_addr as *mut RawIpV4Addr); + let len_ref = task.access_inner().transfer_raw_ptr_mut(len as *mut u32); + *len_ref = core::mem::size_of::() as u32; + Ok(0) +} + +/// 一个系统调用,用于获取一个本地套接字所连接的远程服务器的信息。 +/// +/// + `socketfd`: 指明要操作socket的文件描述符fd; +/// + `socket_addr`: 指明连接的客户端相关信息([`RawIpV4Addr`])将要保存的地址; +/// + `len`: 保存`address`长度的地址。 +/// +/// 执行成功则返回0,否则返回错误信息。 +#[syscall_func(205)] +pub fn get_peer_name(socketfd: usize, sockaddr: usize, len: usize) -> AlienResult { + let socket_fd = common_socket_syscall(socketfd)?; + let socket = socket_fd.get_socketdata()?; + let socket_addr = socket.peer_addr().ok_or(LinuxErrno::EINVAL)?; + info!("get_peer_name: {:?}", socket_addr); + let raw_ip_addr = RawIpV4Addr::from(socket_addr); + let task = current_task().unwrap(); + task.access_inner() + .copy_to_user(&raw_ip_addr, sockaddr as *mut RawIpV4Addr); + let len_ref = task.access_inner().transfer_raw_ptr_mut(len as *mut u32); + *len_ref = core::mem::size_of::() as u32; + Ok(0) +} + +/// 一个系统调用,用于发送消息。当面向连接时,dest_addr被忽略;当非面向连接时,消息发送给dest_addr。 +/// +/// + `socketfd`: 指明要操作socket的文件描述符fd; +/// + `message`: 指明要发送的消息的首地址; +/// + `length`: 指明`message`的长度; +/// + `flags`: 指明发送操作的类型; +/// + `dest_addr`: 指明保存目的地的相关信息([`RawIpV4Addr`])的地址; +/// + `dest_len`: 指明`dest_addr`([`RawIpV4Addr`])的大小。 +/// +/// 如果发送成功,返回发送的字节数;否则返回错误信息. +#[syscall_func(206)] +pub fn sendto( + socketfd: usize, + message: *const u8, + length: usize, + flags: usize, + dest_addr: usize, + dest_len: usize, +) -> AlienResult { + assert_eq!(flags, 0); + let socket_fd = common_socket_syscall(socketfd)?; + let task = current_task().unwrap(); + let message = task.transfer_buffer(message, length); + // to vec + // todo!(don't need) + let message = message + .iter() + .map(|buf| buf.to_vec()) + .flatten() + .collect::>(); + let socket = socket_fd.get_socketdata()?; + match socket.socket_type() { + SocketType::SOCK_STREAM | SocketType::SOCK_SEQPACKET => { + if dest_addr != 0 { + return Err(LinuxErrno::EISCONN.into()); + } + } + _ => {} + } + let socket_addr = if dest_addr != 0 { + let res = socket_addr_resolution(dest_addr, dest_len)?; + Some(res) + } else { + None + }; + info!( + "sendto: {:?}, local_addr: {:?}, message len: {}", + socket_addr, + socket.local_addr(), + message.len() + ); + let send = socket.send_to(message.as_slice(), flags, socket_addr)?; + do_suspend(); + Ok(send as isize) +} + +/// 一个系统调用,用于接收消息。消息源地址的相关信息将会保存在src_addr所指向的位置处。 +/// +/// + `socketfd`: 指明要操作socket的文件描述符fd; +/// + `buffer`: 指明接收消息的缓冲区的首地址; +/// + `length`: 指明缓冲区的长度(能接收消息的最大长度); +/// + `flags`: 指明接收操作的类型; +/// + `src_addr`: 指明消息源地址的相关信息([`RawIpV4Addr`])的保存地址。当该值为空时,不进行相关信息的保存; +/// + `addr_len`: 指明`src_addr`([`RawIpV4Addr`])大小的保存地址。 +/// +/// 如果接收成功,返回接收message的字节数;否则返回错误信息。 +#[syscall_func(207)] +pub fn recvfrom( + socketfd: usize, + buffer: *mut u8, + length: usize, + flags: usize, + src_addr: usize, + addr_len: usize, +) -> AlienResult { + assert_eq!(flags, 0); + let socket_fd = common_socket_syscall(socketfd)?; + let socket = socket_fd.get_socketdata()?; + info!( + "recvfrom: {:?}, local_addr: {:?}", + socket.peer_addr(), + socket.local_addr() + ); + let mut tmp_buffer = vec![0u8; length]; + let recv_info = socket.recvfrom(tmp_buffer.as_mut_slice(), flags)?; + let task = current_task().unwrap(); + task.access_inner() + .copy_to_user_buffer(tmp_buffer.as_ptr(), buffer, recv_info.0); + if src_addr != 0 { + let raw_ip_addr = RawIpV4Addr::from(recv_info.1); + task.access_inner() + .copy_to_user(&raw_ip_addr, src_addr as *mut RawIpV4Addr); + let addr_len_ref = task + .access_inner() + .transfer_raw_ptr_mut(addr_len as *mut u32); + *addr_len_ref = core::mem::size_of::() as u32; + } + Ok(recv_info.0 as isize) +} + +/// (待完成)一个系统调用函数,用于设置套接字的选项。 +/// +/// + `socketfd`: 指明要操作socket的文件描述符fd; +/// + `level`: 定义选项的级别,包括`Ip`,`Socket`,`TCP`等,详情可见[`SocketLevel`]; +/// + `opt_name`: 在对应level下,为其设置值的套接字选项,详情可见[`SocketOption`]; +/// + `_opt_value`: 存储选项值位置的指针; +/// + `_opt_len`: 选项值长度; +/// +/// 如果函数执行成功,则返回0;否则返回错误信息。 +#[syscall_func(208)] +pub fn setsockopt( + socketfd: usize, + level: usize, + opt_name: usize, + _opt_value: usize, + _opt_len: u32, +) -> AlienResult { + let socket_fd = common_socket_syscall(socketfd)?; + let _socket = socket_fd.get_socketdata()?; + let level = SocketLevel::try_from(level).map_err(|_| LinuxErrno::EINVAL)?; + match level { + SocketLevel::Ip => {} + SocketLevel::Socket => { + let opt_name = SocketOption::try_from(opt_name).map_err(|_| LinuxErrno::EINVAL)?; + info!("[setsockopt] level: {:?}, opt_name: {:?}", level, opt_name); + } + SocketLevel::Tcp => { + let opt_name = TcpSocketOption::try_from(opt_name).map_err(|_| LinuxErrno::EINVAL)?; + info!("[setsockopt] level: {:?}, opt_name: {:?}", level, opt_name); + } + } + Ok(0) +} + +/// 一个系统调用函数,用于获取套接字的选项。 +/// +/// + `socketfd`: 指明要操作socket的文件描述符fd; +/// + `level`: 定义选项的级别,包括`Ip`,`Socket`,`TCP`等,详情可见[`SocketLevel`]; +/// + `opt_name`: 在对应level下,要为其检索值的套接字选项,详情可见[`SocketOption`]; +/// + `opt_value`: 一个指向将要保存请求选项值的缓冲区的指针; +/// + `_opt_len`: 指向保存选项值长度的指针; +/// +/// 如果函数执行成功,则返回0;否则返回错误信息。 +#[syscall_func(209)] +pub fn getsockopt( + socketfd: usize, + level: usize, + opt_name: usize, + opt_value: usize, + opt_len: usize, +) -> AlienResult { + let socket_fd = common_socket_syscall(socketfd)?; + let _socket = socket_fd.get_socketdata()?; + let level = SocketLevel::try_from(level).map_err(|_| LinuxErrno::EINVAL)?; + match level { + SocketLevel::Ip => {} + SocketLevel::Socket => { + let opt_name = SocketOption::try_from(opt_name).map_err(|_| LinuxErrno::EINVAL)?; + info!("[getsockopt] level: {:?}, opt_name: {:?}", level, opt_name); + match opt_name { + SocketOption::SO_RCVBUF => { + let opt_value_ref = current_task() + .unwrap() + .transfer_raw_ptr(opt_value as *mut u32); + *opt_value_ref = netcore::common::SOCKET_RECV_BUFFER_SIZE as u32; + } + SocketOption::SO_SNDBUF => { + let opt_value_ref = current_task() + .unwrap() + .transfer_raw_ptr(opt_value as *mut u32); + *opt_value_ref = netcore::common::SOCKET_SEND_BUFFER_SIZE as u32; + } + SocketOption::SO_ERROR => { + let opt_value_ref = current_task() + .unwrap() + .transfer_raw_ptr(opt_value as *mut u32); + *opt_value_ref = 0; + } + _ => {} + } + let opt_len_ref = current_task() + .unwrap() + .transfer_raw_ptr(opt_len as *mut u32); + *opt_len_ref = core::mem::size_of::() as u32; + } + SocketLevel::Tcp => { + let opt_name = TcpSocketOption::try_from(opt_name).map_err(|_| LinuxErrno::EINVAL)?; + info!("[getsockopt] level: {:?}, opt_name: {:?}", level, opt_name); + match opt_name { + TcpSocketOption::TCP_MAXSEG => { + let opt_value_ref = current_task() + .unwrap() + .transfer_raw_ptr(opt_value as *mut u32); + *opt_value_ref = netcore::common::MAX_SEGMENT_SIZE as u32; + } + TcpSocketOption::TCP_NODELAY => { + let opt_value_ref = current_task() + .unwrap() + .transfer_raw_ptr(opt_value as *mut u32); + *opt_value_ref = 0; + } + _ => {} + } + } + } + Ok(0) +} + +/// 一个系统调用,用于关闭一个socket的发送操作或接收操作。 +/// +/// + `socketfd`: 指明要操作socket的文件描述符fd; +/// + `how`: 指明要关闭的操作:包括只关闭Read,只关闭Write,RW都关闭,相关Flag值可见[`ShutdownFlag`]。 +/// +/// 执行成功则返回0,否则返回错误信息。 +#[syscall_func(210)] +pub fn shutdown(socketfd: usize, how: usize) -> AlienResult<()> { + let flag = ShutdownFlag::try_from(how).map_err(|_| LinuxErrno::EINVAL)?; + let socket_fd = common_socket_syscall(socketfd)?; + let socket = socket_fd.get_socketdata()?; + info!( + "shutdown: {:?}, local_addr: {:?}", + flag, + socket.local_addr() + ); + socket.shutdown(flag) +} + +/// (待实现)一个系统调用,创建一对未绑定的socket套接字,该对套接字可以用于全双工通信,或者用于父子进程之间的通信。 +/// +/// 如果向其中的一个socket写入后,再从该socket读时,就会发生阻塞。只能在另一个套接字中读。往往和shutdown()配合使用 +/// +/// + `domain`: 指明套接字被创建的协议簇(包括文件路径协议簇和网络地址协议簇,具体可见[`Domain`]); +/// + `type`: 指明被创建的socket的类型,具体可见[`SocketType`]; +/// + `protocol`: 指明该socket应用于某一个特定的协议上。当确定了套接字使用的协议簇和类型,该参数可以取为0。 +/// + `sv[2]`: 用于存放一对套接字的文件描述符。 +/// +/// 如果创建成功则返回0,否则返回错误信息。 +#[syscall_func(199)] +pub fn socket_pair(domain: usize, c_type: usize, proto: usize, sv: usize) -> AlienResult { + let domain = Domain::try_from(domain).map_err(|_| LinuxErrno::EINVAL)?; + let c_type = SocketType::try_from(c_type).map_err(|_| LinuxErrno::EINVAL)?; + info!( + "socketpair: {:?}, {:?}, {:?}, {:?}", + domain, c_type, proto, sv + ); + // panic!("socketpair"); + Err(LinuxErrno::EAFNOSUPPORT.into()) +} + +/// 通过socket文件描述符fd获取对应的文件 +fn common_socket_syscall(socket_fd: usize) -> AlienResult> { + let task = current_task().unwrap(); + let socket_fd = task.get_file(socket_fd).ok_or(LinuxErrno::EBADF)?; + let socket_file = socket_fd + .downcast_arc::() + .map_err(|_| LinuxErrno::EINVAL) + .expect("socket_fd is not a socket file"); + Ok(socket_file) +} diff --git a/kkernel/src/net/port.rs b/kkernel/src/net/port.rs new file mode 100644 index 00000000..3183d585 --- /dev/null +++ b/kkernel/src/net/port.rs @@ -0,0 +1,24 @@ +//! 现为将网络异常类型 [`NetError`] 转为 系统异常类型 [`LinuxErrno`]的模块。原为定义端口全局变量和操作的模块。 + +use constants::AlienError; +use constants::LinuxErrno; +use netcore::common::NetError; + +/// 现为将网络异常类型 [`NetError`] 转为 系统异常类型 [`LinuxErrno`]。 +pub fn neterror2alien(error: NetError) -> AlienError { + match error { + NetError::AddrInUse => LinuxErrno::EADDRINUSE, + NetError::InvalidInput => LinuxErrno::EINVAL, + NetError::WouldBlock => LinuxErrno::EAGAIN, + NetError::NotConnected => LinuxErrno::ENOTCONN, + NetError::BadState => LinuxErrno::EBADF, + NetError::Unaddressable => LinuxErrno::EADDRNOTAVAIL, + NetError::AlreadyExists => LinuxErrno::EEXIST, + NetError::ConnectionRefused => LinuxErrno::ECONNREFUSED, + NetError::ConnectionReset => LinuxErrno::ECONNRESET, + NetError::Interrupted => LinuxErrno::EINTR, + NetError::DeviceError => LinuxErrno::EIO, + NetError::Again => LinuxErrno::EAGAIN, + } + .into() +} diff --git a/kkernel/src/net/socket.rs b/kkernel/src/net/socket.rs new file mode 100644 index 00000000..f0951bf8 --- /dev/null +++ b/kkernel/src/net/socket.rs @@ -0,0 +1,469 @@ +//! Alien 内核中使用的套接字结构。 +//! +//! Alien 目前采用 [`SocketData`] 存储每一个套接字的相关信息,其字段 socket (结构为 [`Socket`]) 存储套接字的具体信息, +//! 对于套接字的操作最终都会归结于对 [`SocketData`] 的操作。 +//! +//! 套接字的创建时,需要返回一个创建的套接字文件描述符用于获取和操作该套接字。依据 Alien 所使用的 rvfs 中对文件 `File` +//! 的规定,我们只需为套接字文件规定好 [`socket_file_release`]、[`socket_file_write`]、[`socket_file_read`]、 +//! [`socket_ready_to_read`]、[`socket_ready_to_write`] 几个操作函数,即可快速的创建套接字文件,并将其放入进程的文件描述 +//! 符表中,具体有关套接字文件的创建,可见 [`SocketData::new`] 的实现。 +use super::ShutdownFlag; +use crate::fs::file::File; +use crate::net::addr::SocketAddrExt; +use crate::net::port::neterror2alien; +use crate::net::unix::UnixSocket; +use constants::AlienResult; +use ksync::{Mutex, MutexGuard}; +// use crate::task::do_suspend; +use alloc::boxed::Box; +use alloc::sync::Arc; +use constants::io::{OpenFlags, PollEvents, SeekFrom}; +use constants::net::{Domain, SocketType}; +use constants::LinuxErrno; +use core::fmt::{Debug, Formatter}; +use core::net::SocketAddr; +use netcore::tcp::TcpSocket; +use netcore::udp::UdpSocket; +use vfscore::dentry::VfsDentry; +use vfscore::inode::VfsInode; +use vfscore::utils::VfsFileStat; + +pub trait SocketFileExt { + fn get_socketdata(&self) -> AlienResult>>; +} + +pub struct SocketFile { + open_flag: Mutex, + node: Mutex>, +} + +impl Debug for SocketFile { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("SocketFile") + .field("open_flag", &self.open_flag) + .field("node", &self.node) + .finish() + } +} + +impl SocketFile { + pub fn new(socket_data: SocketData) -> Self { + Self { + open_flag: Mutex::new(OpenFlags::O_RDWR), + node: Mutex::new(Box::new(socket_data)), + } + } + + pub fn set_close_on_exec(&self) { + *self.open_flag.lock() |= OpenFlags::O_CLOEXEC; + } +} + +impl SocketFileExt for SocketFile { + fn get_socketdata(&self) -> AlienResult>> { + let r = self.node.lock(); + Ok(r) + } +} + +impl File for SocketFile { + fn read(&self, buf: &mut [u8]) -> AlienResult { + if buf.len() == 0 { + return Ok(0); + } + netcore::poll_interfaces(); + let socket = self.get_socketdata().unwrap(); + let res = socket.recvfrom(buf, 0).map(|x| x.0).map_err(|x| { + info!("socket_file_read: {:?}", x); + x + }); + info!("socket_file_read: {:?}, indeed {:?}", buf.len(), res); + res + } + + fn write(&self, buf: &[u8]) -> AlienResult { + if buf.len() == 0 { + return Ok(0); + } + info!("socket_file_write: buf_len:{:?}", buf.len()); + netcore::poll_interfaces(); + let socket = self.get_socketdata().unwrap(); + let res = socket.send_to(buf, 0, None).map_err(|x| { + info!("socket_file_write: {:?}", x); + x + }); + // do_suspend(); + res + } + + fn seek(&self, _pos: SeekFrom) -> AlienResult { + Err(LinuxErrno::ESPIPE) + } + + fn get_attr(&self) -> AlienResult { + Err(LinuxErrno::ENOSYS) + } + + fn set_open_flag(&self, flag: OpenFlags) { + *self.open_flag.lock() = flag; + } + + fn get_open_flag(&self) -> OpenFlags { + *self.open_flag.lock() + } + + fn dentry(&self) -> Arc { + panic!("dentry in socket file is not supported") + } + + fn inode(&self) -> Arc { + panic!("inode in socket file is not supported") + } + + fn is_readable(&self) -> bool { + true + } + + fn is_writable(&self) -> bool { + true + } + fn is_append(&self) -> bool { + false + } + fn poll(&self, _event: PollEvents) -> AlienResult { + let mut res = PollEvents::empty(); + netcore::poll_interfaces(); + let socket = self.get_socketdata().unwrap(); + if _event.contains(PollEvents::IN) { + if socket.ready_read() { + res |= PollEvents::IN; + } + } + if _event.contains(PollEvents::OUT) { + if socket.ready_write() { + res |= PollEvents::OUT; + } + } + Ok(res) + } +} + +/// Alien 内核中对于每一个套接字所存储的相关信息。所有系统调用最后都要归到该结构的操作。 +#[derive(Debug)] +pub struct SocketData { + /// socket 通信域 + pub domain: Domain, + /// 连接类型 + pub s_type: SocketType, + /// 具体的通信协议 + pub protocol: usize, + /// 具体的套接字数据,具体可见 [`Socket`] + pub socket: Socket, +} + +/// 用于记录一个套接字的具体数据。 +/// +/// 针对套接字类型,`Tcp` 和 `Udp` 类型中存储的具体数据是 `simple_net` 中的 [`TcpSocket`] 和 [`UdpSocket`] 类型; +/// `Unix` 类型中存储的数据是 [`UnixSocket`]。 +pub enum Socket { + Tcp(TcpSocket), + Udp(UdpSocket), + Unix(UnixSocket), + None, +} + +impl Debug for Socket { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + match self { + Socket::Tcp(_) => { + write!(f, "Tcp") + } + Socket::Udp(_) => { + write!(f, "Udp") + } + Socket::None => { + write!(f, "None") + } + Socket::Unix(_) => { + write!(f, "Unix") + } + } + } +} + +impl SocketData { + /// 用于创建一个新的套接字数据 `SocketData` 结构,返回创建的文件描述符。一般被系统调用 [`socket`] 所调用。 + /// + /// 执行过程中会创建一个对应的套接字文件,打开后将对应的文件描述符放入进程的文件描述符表中, + /// 对于 `Alien` 中对文件的相关定义可见 `rvfs` 模块中的 `File` 结构。这里对套接字文件的相关 + /// 操作函数可见 [`socket_file_release`]、[`socket_file_write`]、[`socket_file_read`]、 + /// [`socket_ready_to_read`]、[`socket_ready_to_write`]。 + pub fn new( + domain: Domain, + s_type: SocketType, + protocol: usize, + ) -> AlienResult> { + let raw_socket = match domain { + Domain::AF_UNIX => { + error!("AF_UNIX is not supported"); + Socket::Unix(UnixSocket::new()) + } + Domain::AF_INET => match s_type { + SocketType::SOCK_STREAM => Socket::Tcp(TcpSocket::new()), + SocketType::SOCK_DGRAM => Socket::Udp(UdpSocket::new()), + _ => { + error!("unsupported socket type: {:?}", s_type); + return Err(LinuxErrno::EPROTONOSUPPORT.into()); + } + }, + }; + let socket_data = Self { + domain, + s_type, + protocol, + socket: raw_socket, + }; + Ok(Arc::new(SocketFile::new(socket_data))) + } + /// 用于对一个已经存在的 tcp_socket 创建对应的套接字文件。一般在 accept 成功接受一个 client 后被调用。 + fn new_connected(&self, tcp_socket: TcpSocket) -> Arc { + let socket_data = Self { + domain: self.domain, + s_type: self.s_type, + protocol: self.protocol, + socket: Socket::Tcp(tcp_socket), + }; + Arc::new(SocketFile::new(socket_data)) + } + + /// 返回套接字的类型 + pub fn socket_type(&self) -> SocketType { + self.s_type + } + + /// 设置套接字的阻塞状态。用于传入 SOCK_NONBLOCK 标志位的套接字创建过程中。 + pub fn set_socket_nonblock(&self, blocking: bool) { + match &self.socket { + Socket::Tcp(tcp) => { + tcp.set_nonblocking(blocking); + } + Socket::Udp(udp) => { + udp.set_nonblocking(blocking); + } + _ => { + panic!("set_socket_nonblock is not supported") + } + } + } + + /// 用于绑定套接字端口,tcp 和 udp 可用。被系统调用 [`bind`] 调用。 + pub fn bind(&self, socket_addr: SocketAddrExt) -> AlienResult<()> { + match &self.socket { + Socket::Tcp(tcp) => { + tcp.bind(socket_addr.get_socketaddr()) + .map_err(neterror2alien)?; + } + Socket::Udp(udp) => { + udp.bind(socket_addr.get_socketaddr()) + .map_err(neterror2alien)?; + } + _ => { + panic!("bind is not supported") + } + } + Ok(()) + } + + /// 用于处理一个 client 的连接请求,仅限于 Tcp 套接字。被系统调用 [`accept`] 调用。 + /// + /// 如果该套接字不是 Tcp 套接字,将直接返回 Err。 + pub fn accept(&self) -> AlienResult> { + match &self.socket { + Socket::Tcp(tcp) => tcp + .accept() + .map(|socket| Ok(self.new_connected(socket))) + .map_err(neterror2alien)?, + _ => Err(LinuxErrno::EOPNOTSUPP.into()), + } + } + + /// 用于监听一个端口,仅限于 Tcp 套接字。被系统调用 [`listening`] 调用。 + /// + /// 如果该套接字不是 Tcp 套接字,将直接返回 Err。 + pub fn listening(&self, _back_log: usize) -> AlienResult<()> { + match &self.socket { + Socket::Tcp(tcp) => tcp.listen().map_err(neterror2alien), + _ => Err(LinuxErrno::EOPNOTSUPP.into()), + } + } + + /// 用于连接一个套接字。被系统调用 [`connect`] 调用。 + pub fn connect(&self, ip: SocketAddrExt) -> AlienResult<()> { + match &self.socket { + Socket::Tcp(tcp) => { + tcp.connect(ip.get_socketaddr()).map_err(neterror2alien)?; + } + Socket::Udp(udp) => { + udp.connect(ip.get_socketaddr()).map_err(neterror2alien)?; + } + Socket::Unix(unix) => unix.connect(ip.get_local_path())?, + _ => { + panic!("bind is not supported") + } + } + Ok(()) + } + + /// 用于向一个套接字中发送消息。发送成功则返回发送的消息长度。被系统调用 [`sendto`] 调用。 + pub fn send_to( + &self, + message: &[u8], + _flags: usize, + dest_addr: Option, + ) -> AlienResult { + match &self.socket { + Socket::Tcp(tcp) => tcp.send(message).map_err(|x| neterror2alien(x)), + Socket::Udp(udp) => { + if let Some(dest_addr) = dest_addr { + udp.send_to(message, dest_addr.get_socketaddr()) + .map_err(neterror2alien) + } else { + udp.send(message).map_err(neterror2alien) + } + } + _ => { + panic!("bind is not supported") + } + } + } + + /// 用于从一个套接字中接收消息,接收成功则返回接受的消息长度。被系统调用 [`recvfrom`] 调用。 + pub fn recvfrom(&self, message: &mut [u8], _flags: usize) -> AlienResult<(usize, SocketAddr)> { + match &self.socket { + Socket::Tcp(tcp) => { + let recv = tcp.recv(message).map_err(neterror2alien)?; + let peer_addr = tcp.peer_addr().map_err(neterror2alien)?; + Ok((recv, peer_addr)) + } + Socket::Udp(udp) => { + let recv = udp.recv_from(message).map_err(neterror2alien)?; + // let peer_addr = udp.peer_addr().map_err(neterror2linux)?; + Ok((recv.0, recv.1)) + } + _ => { + panic!("bind is not supported") + } + } + } + + /// 用于关闭套接字的读功能或写功能。被系统调用 [`shutdown`] 调用。 + pub fn shutdown(&self, _sdflag: ShutdownFlag) -> AlienResult<()> { + match &self.socket { + Socket::Tcp(tcp) => tcp.shutdown().map_err(neterror2alien), + Socket::Udp(udp) => udp.shutdown().map_err(neterror2alien), + _ => { + panic!("bind is not supported") + } + } + } + + /// 用于获取当前套接字绑定的本地套接字地址信息。 + pub fn local_addr(&self) -> Option { + match &self.socket { + Socket::Tcp(tcp) => { + let local_addr = tcp.local_addr(); + if let Ok(addr) = local_addr { + Some(addr) + } else { + None + } + } + Socket::Udp(udp) => { + let local_addr = udp.local_addr(); + if let Ok(addr) = local_addr { + Some(addr) + } else { + None + } + } + _ => None, + } + } + + /// 用于获取当前套接字连接的远程服务器的套接字地址信息。 + pub fn peer_addr(&self) -> Option { + match &self.socket { + Socket::Tcp(tcp) => { + let peer_addr = tcp.peer_addr(); + if let Ok(addr) = peer_addr { + Some(addr) + } else { + None + } + } + Socket::Udp(udp) => { + let peer_addr = udp.peer_addr(); + if let Ok(addr) = peer_addr { + Some(addr) + } else { + None + } + } + _ => { + panic!("bind is not supported") + } + } + } + + /// 用于获取当前套接字是否有消息需要接收。 + pub fn ready_read(&self) -> bool { + match &self.socket { + Socket::Tcp(tcp) => { + let res = tcp.poll(); + info!("Tcp ready_read: {:?}", res); + if let Ok(res) = res { + res.readable + } else { + false + } + } + Socket::Udp(udp) => { + let res = udp.poll(); + info!("Udp ready_read: {:?}", res); + if let Ok(res) = res { + res.readable + } else { + false + } + } + _ => { + panic!("bind is not supported") + } + } + } + + ///用于获取当前套接字是否有消息需要发送。 + pub fn ready_write(&self) -> bool { + match &self.socket { + Socket::Tcp(tcp) => { + let res = tcp.poll(); + if let Ok(res) = res { + res.writable + } else { + false + } + } + Socket::Udp(udp) => { + let res = udp.poll(); + if let Ok(res) = res { + res.writable + } else { + false + } + } + _ => { + panic!("bind is not supported") + } + } + } +} diff --git a/kkernel/src/net/unix.rs b/kkernel/src/net/unix.rs new file mode 100644 index 00000000..5ff469d9 --- /dev/null +++ b/kkernel/src/net/unix.rs @@ -0,0 +1,31 @@ +//! 有关 Unix 协议族下的套接字结构。(目前有关的功能有待支持) +use alloc::string::String; +use alloc::sync::Arc; +use constants::LinuxErrno; + +use crate::fs::file::File; +use ksync::Mutex; + +/// Unix 协议族下的套接字结构 +#[allow(unused)] +pub struct UnixSocket { + /// 文件路径,即套接字地址 + file_path: Mutex>, + /// 套接字数据 + file: Mutex>>, +} + +impl UnixSocket { + /// 创建一个新的 Unix 协议族下的套接字结构 + pub fn new() -> Self { + Self { + file_path: Mutex::new(None), + file: Mutex::new(None), + } + } + + /// UnixSocket 的 connect 操作 + pub fn connect(&self, _file_path: String) -> Result<(), LinuxErrno> { + Err(LinuxErrno::ENOENT) + } +} diff --git a/kkernel/src/system.rs b/kkernel/src/system.rs new file mode 100644 index 00000000..9443f5b2 --- /dev/null +++ b/kkernel/src/system.rs @@ -0,0 +1,218 @@ +//! uname系统调用实现 +use syscall_table::syscall_func; +use constants::sys::{Rusage, RusageFlag, Sysinfo, SyslogAction, TimeVal}; +use constants::{AlienResult, LinuxErrno}; +use core::cmp::min; +use timer::{get_time_ms, TimeFromFreq}; + +use crate::task::current_task; + +/// 记录系统信息的结构,包括操作系统名、在网络中的用户名、操作系统release和version版本、硬件类型、域名等信息。 +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Utsname { + /// 操作系统名 + sysname: [u8; 65], + /// Name within communications network to which the node is attached + nodename: [u8; 65], + /// 系统发行版 + release: [u8; 65], + /// 系统版本 + version: [u8; 65], + /// 硬件类型 + machine: [u8; 65], + /// 域名 + domainname: [u8; 65], +} + +/// 返回系统信息,信息保存在[`Utsname`]结构中。 +fn system_info() -> Utsname { + const SYSNAME: &str = "Linux"; + const NODENAME: &str = "Alien"; + const RELEASE: &str = "5.1"; + const VERSION: &str = "5.1"; + const MACHINE: &str = "riscv64"; + const DOMAINNAME: &str = "RustOS"; + let mut name = Utsname { + sysname: [0; 65], + nodename: [0; 65], + release: [0; 65], + version: [0; 65], + machine: [0; 65], + domainname: [0; 65], + }; + name.sysname[..SYSNAME.len()].copy_from_slice(SYSNAME.as_bytes()); + name.nodename[..NODENAME.len()].copy_from_slice(NODENAME.as_bytes()); + name.release[..RELEASE.len()].copy_from_slice(RELEASE.as_bytes()); + name.version[..VERSION.len()].copy_from_slice(VERSION.as_bytes()); + name.machine[..MACHINE.len()].copy_from_slice(MACHINE.as_bytes()); + name.domainname[..DOMAINNAME.len()].copy_from_slice(DOMAINNAME.as_bytes()); + name +} + +/// 一个系统调用,返回系统信息。信息包括操作系统名、在网络中的用户名、操作系统release和version版本、硬件类型、域名等信息,详情可见[`Utsname`]。 +/// +/// 函数成功执行后返回0。 +#[syscall_func(160)] +pub fn uname(utsname: *const u8) -> isize { + let task = current_task().unwrap(); + task.access_inner() + .copy_to_user(&system_info(), utsname as *mut Utsname); + 0 +} + + +const LOG_BUF_LEN: usize = 4096; +const LOG: &str = r" +[ 0.000000] Linux version 5.10.0-7-riscv64 (debian-kernel@lists.debian.org) (gcc-10 (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2) #1 SMP Debian 5.10.40-1 (2021-05-28) +"; + +/// (待完善)一个系统调用函数,用于对内核消息环状缓冲区进行操作。 +/// +/// + `log_type`: 指明操作的类型,具体值可见[`SyslogAction`]; +/// + `buf`: 指明读取消息时,消息要保存到的位置; +/// + `len`: 指明具体操作时,对于消息读取的长度限制。真正的读取消息的长度将取决于就传入的`len`和`LOG_BUF_LEN`的最小值。 +/// +/// 当`log_type`为`READ`、`ReadAll`、`ReadClear`三种flag,正确执行后返回读取消息的长度; +/// 当`log_type`为`Unknown`时,会返回`EINVAL`;当`log_type`为`OPEN`或`CLOSE`时,函数不进行任何操作后返回0。 +/// 目前Alien仅支持上述`log_type`值,其余值都将不进行任何操作后返回0。 +/// +/// Reference: [syslog](https://man7.org/linux/man-pages/man2/syslog.2.html) +#[syscall_func(116)] +pub fn syslog(log_type: u32, buf: usize, len: usize) -> isize { + let log_type = SyslogAction::try_from(log_type); + if log_type.is_err() { + return LinuxErrno::EINVAL as isize; + } + match log_type.unwrap() { + SyslogAction::OPEN | SyslogAction::CLOSE => 0, + SyslogAction::READ | SyslogAction::ReadAll | SyslogAction::ReadClear => { + let min_len = min(len, LOG_BUF_LEN); + let task = current_task().unwrap(); + // the buf may be not valid, so we need to check it -- > sbrk heap + let mut buf = task.transfer_buffer(buf as *mut u8, min_len); + let log = LOG.as_bytes(); + let mut offset = 0; + buf.iter_mut().for_each(|buf| { + let copy_len = min(log.len() - offset, buf.len()); + buf[..copy_len].copy_from_slice(&log[offset..offset + copy_len]); + offset += copy_len; + }); + offset as isize + } + SyslogAction::Unknown => LinuxErrno::EINVAL as isize, + _ => 0, + } +} + +extern "C" { + fn ekernel(); +} + +/// 一个系统调用函数,用于获取系统相关信息。信息包括系统的自启动经过的时间、对于内存的使用情况、共享存储区的大小、 +/// 缓冲区与交换区的大小、当前进程数目等,具体可见[`Sysinfo`]。获取到的信息将保存到`dst_info`所指向的[`Sysinfo`]结构处。 +/// +/// 目前功能还有待完善。正确执行后返回0。 +#[syscall_func(179)] +pub fn sys_info(dst_info: usize) -> isize { + const LINUX_SYSINFO_LOADS_SCALE: usize = 65536; + let task = current_task().unwrap(); + // calculate the task number + let task_number = 10; // fake task number + let machine_info = platform::platform_machine_info(); + let memory_info = machine_info.memory.clone(); + let info = Sysinfo { + uptime: (get_time_ms() / 1000) as usize, + loads: [ + task_number * LINUX_SYSINFO_LOADS_SCALE / 60, + task_number * LINUX_SYSINFO_LOADS_SCALE / 300, + task_number * LINUX_SYSINFO_LOADS_SCALE / 900, + ], + totalram: memory_info.end - memory_info.start, + freeram: memory_info.end - ekernel as usize, + sharedram: 0, + bufferram: 0, + totalswap: 0, + freeswap: 0, + procs: task_number as u16, + totalhigh: 0, + freehigh: 0, + mem_unit: 1, + }; + task.access_inner() + .copy_to_user(&info, dst_info as *mut Sysinfo); + 0 +} + +/// (待实现)一个系统调用,设置进程调度的参数。目前直接返回0。 +#[syscall_func(118)] +pub fn sched_setparam() -> isize { + 0 +} + +/// (待实现)一个系统调用,获取进程调度的参数。目前直接返回0。 +#[syscall_func(121)] +pub fn sched_getparam() -> isize { + 0 +} + +/// (待实现)一个系统调用,设置进程CPU亲和力(位掩码),使进程绑定在某一个或几个CPU上运行,避免在CPU之间来回切换,从而提高该进程的实时性能。目前直接返回0。 +#[syscall_func(122)] +pub fn sched_setaffinity() -> isize { + 0 +} + +/// (待完善)一个系统调用,获取某进程对CPU的亲和力(位掩码)。当前进程的cpu亲和力将保存到`mask`所指向的位置。函数执行成功后返回8。 +#[syscall_func(123)] +pub fn sched_getaffinity(pid: usize, size: usize, mask: usize) -> isize { + warn!( + "sched_getaffinity: pid: {}, size: {}, mask: {}", + pid, size, mask + ); + assert_eq!(pid, 0); + let task = current_task().unwrap(); + let res = task.access_inner().cpu_affinity; + let mask = task.access_inner().transfer_raw_ptr_mut(mask as *mut usize); + *mask = res; + 8 +} + +/// (待实现)一个系统调用,用于获取当前CPU的调度策略。目前直接返回0。 +#[syscall_func(120)] +pub fn sched_getscheduler(pid: usize) -> isize { + assert_eq!(pid, 0); + // let task = current_task().unwrap(); + 0 +} + +/// (待实现)一个系统调用,用于设置当前CPU的调度策略。目前直接返回0。 +#[syscall_func(119)] +pub fn sched_setscheduler(_pid: usize, _policy: usize, _param: usize) -> isize { + 0 +} + + + +/// (待完善)一个系统调用,用于获取对系统资源的使用量信息。获取的信息将保存到`usage`所指向的[`Rusage`]结构中。 +/// +/// 可以通过`who`修改获取信息的对象,包括: +/// + `RUSAGE_SELF`: 返回调用该函数进程的资源用量统计,会返回该进程下所有线程的资源用量之和; +/// + `RUSAGE_CHILDREN`: 返回调用该函数进程所有已终止且被回收子进程的资源用量统计. +/// + `RUSAGE_THREAD`: 返回调用该函数线程的资源用量统计。 +/// +/// 在Alien中,目前仅支持`RUSAGE_SELF`。且返回的信息目前仅有[`Rusage`]下的`ru_utime`和`ru_stime`字段。 +/// +/// 正确执行后返回0。 +#[syscall_func(165)] +pub fn getrusage(who: isize, usage: usize) -> AlienResult { + let who = RusageFlag::try_from(who).map_err(|_| LinuxErrno::EINVAL)?; + info!("getrusage: who: {:?}, usage: {}", who, usage); + let task = current_task().unwrap(); + let static_info = task.access_inner().statistical_data().clone(); + let mut task_usage = Rusage::new(); + task_usage.ru_utime = TimeVal::from_freq(static_info.tms_utime); + task_usage.ru_stime = TimeVal::from_freq(static_info.tms_stime); + task.access_inner() + .copy_to_user(&task_usage, usage as *mut Rusage); + Ok(0) +} \ No newline at end of file diff --git a/kkernel/src/task/context.rs b/kkernel/src/task/context.rs new file mode 100644 index 00000000..01a60b56 --- /dev/null +++ b/kkernel/src/task/context.rs @@ -0,0 +1,46 @@ +//! 线程切换的上下文结构 +use core::arch::global_asm; + +/// 线程切换需要保存的上下文 +/// +/// 线程切换由__switch()完成,这个汇编函数不会由编译器完成寄存器保存,因此需要手动保存 +#[derive(Debug, Clone)] +#[repr(C)] +pub struct Context { + /// ra 寄存器 + ra: usize, + /// sp 寄存器值 + sp: usize, + /// s0 ~ s11 + s: [usize; 12], +} + +impl Context { + /// 创建一个新的上下文,默认 s0 ~ s11 的值为 0 + pub fn new(ra: usize, sp: usize) -> Self { + Self { ra, sp, s: [0; 12] } + } + + /// 创建一个全为 0 的上下文 + pub const fn empty() -> Self { + Self { + ra: 0, + sp: 0, + s: [0; 12], + } + } +} + +global_asm!(include_str!("switch.asm")); + +extern "C" { + pub fn __switch(current_task_cx_ptr: *mut Context, next_task_cx_ptr: *const Context); +} + +/// 交换前后两个线程的上下文,调用 `switch.asm` 中的 `__switch` +#[inline(always)] +pub fn switch(current_task_cx_ptr: *mut Context, next_task_cx_ptr: *const Context) { + unsafe { + __switch(current_task_cx_ptr, next_task_cx_ptr); + } +} diff --git a/kkernel/src/task/cpu.rs b/kkernel/src/task/cpu.rs new file mode 100644 index 00000000..6a5d3744 --- /dev/null +++ b/kkernel/src/task/cpu.rs @@ -0,0 +1,496 @@ +//! Alien 中有关进程的系统调用 和 多核的相关支持。 +use alloc::string::{String, ToString}; +use alloc::sync::Arc; +use alloc::vec::Vec; +use core::cell::UnsafeCell; +use log::{error, info, warn}; +use smpscheduler::{FifoSmpScheduler, FifoTask, ScheduleHart}; +use spin::Lazy; + +use constants::ipc::FutexOp; +use constants::signal::SignalNumber; +use constants::task::{CloneFlags, WaitOptions}; +use constants::{AlienError, AlienResult}; +use constants::{PrLimit, PrLimitRes}; +use ksync::Mutex; +use syscall_table::syscall_func; + +use config::CPU_NUM; +use crate::fs; +use crate::ipc::{futex, global_logoff_signals}; +use platform::system_shutdown; +use crate::task::context::Context; +use crate::task::schedule::schedule; +use crate::task::task::{Task, TaskState}; +use crate::task::INIT_PROCESS; +use crate::trap::{check_task_timer_expired, TrapFrame}; +use arch::hart_id; + +/// 记录当前 CPU 上正在执行的线程 和 线程上下文 +#[derive(Debug, Clone)] +pub struct CPU { + /// 正在该 CPU 上运行的线程的控制块 + pub task: Option>, + /// 当前线程的上下文 + pub context: Context, +} + +impl CPU { + /// 获取一个空的 CPU + const fn empty() -> Self { + Self { + task: None, + context: Context::empty(), + } + } + + /// 获取线程上下文的一个 不可变引用 的指针 + pub fn get_context_raw_ptr(&self) -> *const Context { + &self.context as *const Context + } + + /// 获取线程上下文的一个 可变引用 的指针 + pub fn get_context_mut_raw_ptr(&mut self) -> *mut Context { + &mut self.context as *mut Context + } +} +pub struct SafeRefCell(UnsafeCell); +impl SafeRefCell { + const fn new(t: T) -> Self { + Self(UnsafeCell::new(t)) + } +} +/// #Safety: Only the corresponding cpu will access it. +unsafe impl Sync for SafeRefCell {} + +const DEFAULT_CPU: SafeRefCell = SafeRefCell::new(CPU::empty()); +/// 保存每个核的信息 +static CPU_MANAGER: [SafeRefCell; CPU_NUM] = [DEFAULT_CPU; CPU_NUM]; +#[derive(Debug)] +pub struct ScheduleHartImpl; + +impl ScheduleHart for ScheduleHartImpl { + fn hart_id() -> usize { + hart_id() + } +} +/// 多核调度器 +pub static GLOBAL_TASK_MANAGER: Lazy< + FifoSmpScheduler, Mutex<()>, ScheduleHartImpl>, +> = Lazy::new(|| FifoSmpScheduler::new()); + +/// 获取当前 cpu 的信息 +pub fn current_cpu() -> &'static mut CPU { + let hart_id = arch::hart_id(); + unsafe { &mut (*(CPU_MANAGER[hart_id].0.get())) } +} + +/// 获取当前 CPU 上的线程 +pub fn current_task() -> Option<&'static Arc> { + let cpu = current_cpu(); + cpu.task.as_ref() +} + +/// 获取当前进程的虚拟页表的 token (root ppn) +pub fn current_user_token() -> usize { + let task = current_task().unwrap(); + task.token() +} + +/// 获取当前进程的 trap 帧(上下文) +pub fn current_trap_frame() -> &'static mut TrapFrame { + let task = current_task().unwrap(); + task.trap_frame() +} + +/// 一个系统调用,用于终止进程。 +/// +/// 运行成功后,调用该函数的进程将转变为Zombie状态,同时回收部分资源,并让渡CPU执行其他的进程。 +/// 等待父进程得知其终止退出后,将回收该进程的其余资源。 +/// `exit_code`中的值,将会在其父进程调用[`wait4`]时,作为信息传递给父进程。 +/// 当一个具有子进程的进程终止时,其所有子进程将转交至init进程,由init进程完成其子进程相关资源的回收。 +/// 当`clear_child_tid`不为0时,会将`clear_child_tid`该处的值置为0,同时内核唤醒当前正在等待的futex。 +/// +/// 当调用该函数的进程为`pid==0`的init进程时,将直接调用`system_shutdown`使得内核终止。 +#[syscall_func(93)] +pub fn do_exit(exit_code: i32) -> isize { + let task = current_task().unwrap(); + let exit_code = (exit_code & 0xff) << 8; + if task.get_pid() == 0 { + println!("Init process exit with code {}", exit_code); + system_shutdown(); + } + { + let init = INIT_PROCESS.clone(); + task.take_children().into_iter().for_each(|child| { + child.update_parent(init.clone()); + init.insert_child(child); + }); + } + task.update_state(TaskState::Zombie); + task.update_exit_code(exit_code); + global_logoff_signals(task.get_tid() as usize); + // clear_child_tid 的值不为 0,则将这个用户地址处的值写为0 + let addr = task.access_inner().clear_child_tid; + if addr != 0 { + // 确认这个地址在用户地址空间中。如果没有也不需要报错,因为线程马上就退出了 + let addr = task.transfer_raw_ptr(addr as *mut i32); + *addr = 0; + } + + // 回收一些物理页,不然等到wait系统调用真正进行回收时,可能会出现OOM + // 可回收物理页包括trap页以及内核栈页 + // 在这里还不能回收内核栈页,因为还需要用到内核栈页来执行下面的代码 + // 所以只回收trap页 + // 在wait系统调用中,会回收内核栈页 + task.pre_recycle(); + info!("pre recycle done"); + let clear_child_tid = task.futex_wake(); + if clear_child_tid != 0 { + let phy_addr = task.transfer_raw_ptr(clear_child_tid as *mut usize); + *phy_addr = 0; + error!("exit wake futex on {:#x}", clear_child_tid); + futex(clear_child_tid, FutexOp::FutexWake as u32, 1, 0, 0, 0); + } else { + error!("exit clear_child_tid is 0"); + } + schedule(); + 0 +} + +/// 一个系统调用,退出当前进程(进程组)下的所有线程(进程)。 +/// +/// 目前该系统调用直接调用[`do_exit`],有关进程组的相关功能有待实现。 +#[syscall_func(94)] +pub fn exit_group(exit_code: i32) -> isize { + do_exit(exit_code) +} + +/// 一个系统调用,用于使当前正在运行的进程让渡CPU。 +#[syscall_func(124)] +pub fn do_suspend() -> isize { + let task = current_task().unwrap(); + task.access_inner().update_timer(); + check_task_timer_expired(); + task.update_state(TaskState::Ready); + schedule(); + 0 +} + +/// (待实现)设置进程组的id。目前直接返回0。 +#[syscall_func(154)] +pub fn set_pgid() -> isize { + 0 +} + +/// (待实现)获取进程组的id。目前直接返回0。 +#[syscall_func(155)] +pub fn get_pgid() -> isize { + 0 +} + +/// 创建一个新的session,并使得使用系统调用的当前task成为新session的leader,同时也是新进程组的leader(待实现) +#[syscall_func(157)] +pub fn set_sid() -> isize { + 0 +} + +/// 获取当前正在运行task的pid号。在Alien中pid作为线程组的标识符,位于同一线程组中的线程的pid相同。 +#[syscall_func(172)] +pub fn get_pid() -> isize { + let process = current_task().unwrap(); + process.get_pid() +} + +/// 获取当前正在运行task的ppid号,即父task的pid号。 +#[syscall_func(173)] +pub fn get_ppid() -> isize { + let process = current_task().unwrap(); + let parent = process.access_inner().parent.clone(); + if parent.is_none() { + return 0; + } else { + parent.unwrap().upgrade().unwrap().get_pid() + } +} + +/// (待实现)获取用户 id。在实现多用户权限前默认为最高权限。目前直接返回0。 +#[syscall_func(174)] +pub fn getuid() -> isize { + 0 +} + +/// (待实现)获取有效用户 id,即相当于哪个用户的权限。在实现多用户权限前默认为最高权限。目前直接返回0。 +#[syscall_func(175)] +pub fn geteuid() -> isize { + 0 +} + +/// (待实现)获取用户组 id。在实现多用户权限前默认为最高权限。目前直接返回0。 +#[syscall_func(176)] +pub fn getgid() -> isize { + 0 +} + +/// (待实现)获取有效用户组 id,即相当于哪个用户组的权限。在实现多用户组权限前默认为最高权限。目前直接返回0。 +#[syscall_func(177)] +pub fn getegid() -> isize { + 0 +} + +/// 获取当前正在运行task的tid号。在Alien中tid作为task的唯一标识符。 +#[syscall_func(178)] +pub fn get_tid() -> isize { + let process = current_task().unwrap(); + process.get_tid() +} + +/// 一个系统调用,用于创建一个子进程。 +/// +/// 与传统的`fork()`的功能大致相同,创建一个子进程,并将其放入任务队列中等待cpu进行调度。 +/// 但与`fork()`的功能相比,`Alien`中`clone`系统调用提供了更多详细的控制, +/// 管理父进程和子进程之间的共享资源,例如调用者可以控制父子进程之间是否共享虚拟内存空间、文件描述符表、 +/// 信号处理程序等。 +/// +/// `flag`用于控制父子进程之间资源的共享程度,有关flag值及其相关含义设置可见[`CloneFlags`]和[`SignalNumber`]。 +/// `stack`用于控制子进程的用户栈。由于clone产生的子进程有可能和父进程共享内存,所以它不能使用父进程的栈。 +/// `ptid`是一个在父进程地址空间中的地址,用于在创建子进程成功后向该位置写入子进程的tid号。在flag包含`CLONE_PARENT_SETTID`时才会发挥效果。 +/// `tls`用于为子进程创建新的TLS(thread-local storage)值,在flag包含`CLONE_SETTLS`时才会实际产生效果。 +/// `ctid`用于给子进程中的[`set_child_tid`]和[`clear_child_tid`]赋值(分别在flag中包含`CLONE_CHILD_SETTID`和`CLONE_CHILD_CLEARTID`时产生效果)。 +/// +/// 成功创建子进程后父进程会返回子进程的tid号,子进程的返回值将被设置为0;否则返回-1。 +/// +/// Reference: [clone](https://www.man7.org/linux/man-pages/man2/clone.2.html) +#[syscall_func(220)] +pub fn clone(flag: usize, stack: usize, ptid: usize, tls: usize, ctid: usize) -> isize { + let clone_flag = CloneFlags::from_bits_truncate(flag as u32); + // check whether flag include signal + let sig = flag & 0xff; + let sig = SignalNumber::from(sig); + let task = current_task().unwrap(); + + let child_num = task.access_inner().children.len(); + if child_num >= 10 { + do_suspend(); + } + let new_task = task.t_clone(clone_flag, stack, sig, ptid, tls, ctid); + if new_task.is_none() { + return -1; + } + let new_task = new_task.unwrap(); + // update return value + let trap_frame = new_task.trap_frame(); + trap_frame.update_res(0); + let tid = new_task.get_tid(); + GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(new_task))); + // do_suspend(); + tid +} + +/// 一个系统调用,用于执行一个文件。 +/// +/// `path`用于指明要执行的文件的绝对路径。 +/// `args_ptr`用于指明保存启动可执行文件时要传入的参数的地址。 +/// `env`用于指明保存相关环境变量的地址。 +/// +/// 成功执行文件后会返回0;否则会返回-1或错误类型。 +#[syscall_func(221)] +pub fn do_exec(path: *const u8, args_ptr: usize, env: usize) -> AlienResult { + let task = current_task().unwrap(); + let mut path_str = task.transfer_str(path); + // get the args and push them into the new process stack + let (mut args, envs) = parse_user_arg_env(args_ptr, env); + warn!("exec path: {}", path_str); + warn!("exec args: {:?} ,env: {:?}", args, envs); + if path_str.ends_with(".sh") { + if args.is_empty() { + let mut new_path = path_str.clone(); + new_path.push('\0'); + args.insert(0, new_path); + } + path_str = "./busybox".to_string(); + args.insert(0, "sh\0".to_string()); + } + let mut data = Vec::new(); + if path_str.contains("libc-bench") { + path_str = "libc-bench2".to_string(); + } + if fs::read_all(&path_str, &mut data) { + let res = task.exec(&path_str, data.as_slice(), args, envs); + if res.is_err() { + return Err(AlienError::ENOEXEC); + } + Ok(0) + } else { + info!("exec {} failed", path_str); + Err(AlienError::ENOENT) + } +} + +/// 一个系统调用,用于父进程等待某子进程退出。 +/// +/// `pid`用于指明等待的子进程pid号。`pid == -1`表示父进程等待任意子进程返回。 +/// 当`exit_code`非空时,将会把退出的子程序的退出值赋给`exit_code`所指向的位置。 +/// `options`主要用于控制`wait4`的执行逻辑,例如当`wait_options`包含`WNOHANG`时,即使未发现子程序返回,函数也将直接返回0。 +/// +/// 一般`wait4`会使得父进程阻塞,直到子进程退出,返回退出的子进程pid。但当`wait_options`包含`WNOHANG`时,即使未发现子程序返回,函数也将直接返回0。 +/// 当父进程的所有子进程中不包含进程号为pid的子进程,将返回-1。 +/// +/// Reference:[wait](https://man7.org/linux/man-pages/man2/wait.2.html) +#[syscall_func(260)] +pub fn wait4(pid: isize, exit_code: *mut i32, options: u32, _rusage: *const u8) -> isize { + loop { + let task = current_task().unwrap(); + if task + .children() + .iter() + .find(|child| child.get_pid() == pid || pid == -1) + .is_none() + { + return -1; + } + let res = task.check_child(pid); + if let Some(index) = res { + let child = task.remove_child(index); + assert_eq!( + Arc::strong_count(&child), + 1, + "Father is [{}-{}], wait task is [{}-{}]", + task.get_pid(), + task.get_tid(), + child.get_pid(), + child.get_tid() + ); + if !exit_code.is_null() { + let exit_code_ref = task.transfer_raw_ptr(exit_code); + *exit_code_ref = child.exit_code(); + } + return child.get_tid(); + } else { + let wait_options = WaitOptions::from_bits(options).unwrap(); + if wait_options.contains(WaitOptions::WNOHANG) { + return 0; + } else { + do_suspend(); + } + } + } +} + +/// 一个系统调用,用于改变堆区的大小(目前仅可以增加堆区大小) +/// +/// `addr`用于指明扩充堆区后,堆区的末尾位置。 +/// 当`addr`所标识的位置在当前堆起始位置的前方,或者堆当前已使用的末尾位置的前方时,将会导致增加堆区大小失败。 +/// +/// 成功增加堆区大小时,函数返回堆当前已使用的末尾位置;否则返回-1。 +#[syscall_func(214)] +pub fn do_brk(addr: usize) -> isize { + let process = current_task().unwrap(); + let mut inner = process.access_inner(); + let heap_info = inner.heap_info(); + if addr == 0 { + return heap_info.current as isize; + } + if addr < heap_info.start || addr < heap_info.current { + // panic!("heap can't be shrinked"); + return -1; + } + let res = inner.extend_heap(addr); + if res.is_err() { + return -1; + } + res.unwrap() as isize +} + +/// 一个系统调用,用于修改进程clear_child_tid的值,同时返回进程的tid。 +#[syscall_func(96)] +pub fn set_tid_address(tidptr: usize) -> isize { + let task = current_task().unwrap(); + task.set_tid_address(tidptr); + task.get_tid() +} + +/// 一个系统调用,用于修改进程的资源限制。 +/// +/// 进程对其拥有的资源,包括用户栈大小、可以打开的文件描述符数、用户地址空间大小等都有所上限。 +/// +/// `prlimit64`则可以根据资源的种类对不同的资源进行大小的限制。针对每一具体限制都包括软上限和硬上限,具体可见[`PrLimit`]。 +/// `pid`用于指明需要修改资源限制的进程的pid号。 +/// `resource`用于指明需要修改的资源类型,可选的值包括`RLIMIT_STACK`、`RLIMIT_NOFILE`、`RLIMIT_AS`等,详情可见[`PrLimitRes`]。 +/// `new_limit`用于指明新限制的指针,如果为空指针则不进行新限制的赋值。 +/// `old_limit`用于指明存放旧限制的指针,如果为空则不进行旧限制的保存。 +/// +/// 正确执行后会返回0;如果输入的pid为0或者为当前正在运行的进程号,则会直接终止。 +#[syscall_func(261)] +pub fn prlimit64(pid: usize, resource: usize, new_limit: *const u8, old_limit: *mut u8) -> isize { + assert!(pid == 0 || pid == current_task().unwrap().get_pid() as usize); + let task = current_task().unwrap(); + let mut inner = task.access_inner(); + if let Ok(resource) = PrLimitRes::try_from(resource) { + if !old_limit.is_null() { + let limit = inner.get_prlimit(resource); + warn!("get rlimit nofile to {:?}", limit); + inner.copy_to_user(&limit, old_limit as *mut PrLimit); + } + match resource { + PrLimitRes::RlimitStack => {} + PrLimitRes::RlimitNofile => { + if !new_limit.is_null() { + let mut limit = PrLimit::new(0, 0); + inner.copy_from_user(new_limit as *const PrLimit, &mut limit); + warn!("set rlimit nofile to {:?}", limit); + inner.set_prlimit(resource, limit); + } + } + PrLimitRes::RlimitAs => {} + } + } + 0 +} + +/// 用于exec可执行文件时,分别在args_ptr和env_ptr所指向的地址处取出参数和环境变量 +fn parse_user_arg_env(args_ptr: usize, env_ptr: usize) -> (Vec, Vec) { + let task = current_task().unwrap(); + let mut args = Vec::new(); + + if args_ptr != 0 { + let mut start = args_ptr as *mut usize; + loop { + let arg = task.transfer_raw_ptr(start); + if *arg == 0 { + break; + } + args.push(*arg); + start = unsafe { start.add(1) }; + } + } + let args = args + .into_iter() + .map(|arg| { + let mut arg = task.transfer_str(arg as *const u8); + arg.push('\0'); + arg + }) + .collect::>(); + let mut envs = Vec::new(); + if env_ptr != 0 { + let mut start = env_ptr as *mut usize; + loop { + let env = task.transfer_raw_ptr(start); + if *env == 0 { + break; + } + envs.push(*env); + start = unsafe { start.add(1) }; + } + } + let envs = envs + .into_iter() + .map(|env| { + let mut env = task.transfer_str(env as *const u8); + env.push('\0'); + env + }) + .collect::>(); + (args, envs) +} diff --git a/kkernel/src/task/heap.rs b/kkernel/src/task/heap.rs new file mode 100644 index 00000000..cbe663ae --- /dev/null +++ b/kkernel/src/task/heap.rs @@ -0,0 +1,59 @@ +//! 记录进程的堆空间的相关信息 + +/// 记录进程的堆空间的相关信息 +#[derive(Debug, Clone)] +pub struct HeapInfo { + /// 堆使用到的位置 + pub current: usize, + /// 堆空间的起始位置 + pub start: usize, + /// 堆空间的末尾位置 + pub end: usize, +} + +impl HeapInfo { + /// 新建一个 HeapInfo + pub fn new(start: usize, end: usize) -> Self { + HeapInfo { + current: start, + start, + end, + } + } + + /// 返回堆的大小 + #[allow(unused)] + pub fn size(&self) -> usize { + self.end - self.start + } + + /// 返回堆是否包括某地址 + #[allow(unused)] + pub fn contains(&self, addr: usize) -> bool { + addr >= self.start && addr < self.end + } + + #[allow(unused)] + /// 堆大小增加 size 个单位 + pub fn increase(&mut self, size: usize) { + self.end += size; + } + + /// 重新设置堆空间的头 + #[allow(unused)] + pub fn set_start(&mut self, start: usize) { + self.start = start; + } + + #[allow(unused)] + /// 重新设置堆空间的尾 + pub fn set_end(&mut self, end: usize) { + self.end = end; + } + + /// 返回堆空间是否为空 + #[allow(unused)] + pub fn is_empty(&self) -> bool { + self.start == self.end + } +} diff --git a/kkernel/src/task/mod.rs b/kkernel/src/task/mod.rs new file mode 100644 index 00000000..1376dd20 --- /dev/null +++ b/kkernel/src/task/mod.rs @@ -0,0 +1,96 @@ +//! Alien 中有关进程管理的相关数据结构 +//! +//! [`context`] 子模块定义了 Alien 中线程上下文的相关结构. +//! [`cpu`] 子模块中指明了 Alien 中有关进程的系统调用 和 多核的相关支持。 +//! [`heap`] 子模块定义了 Alien 记录进程堆空间的相关信息的结构。 +//! [`schedule`] 子模块指明了 Alien 中有关 CPU 调度的相关机制 +//! [`stack`] 子模块定义了 Alien 中有关内核栈的相关结构。 +//! [`task`] 子模块定义了 Alien 中有关进程控制块的定义。 +use alloc::sync::Arc; +use alloc::vec::Vec; +use smpscheduler::FifoTask; +use spin::Lazy; +pub use cpu::*; +use devices::DeviceWithTask; +use drivers::{DriverTask, DriverWithTask}; +pub use task::{StatisticalData, Task, TaskState}; +use vfs::SYSTEM_ROOT_FS; + +use crate::fs::{read_all}; +use crate::task::schedule::schedule; +pub use crate::task::task::FsContext; + +mod context; +mod cpu; +mod heap; +pub mod schedule; +mod stack; +mod task; + +/// 初始进程(0号进程) +pub static INIT_PROCESS: Lazy> = Lazy::new(|| { + let mut data = Vec::new(); + read_all("/bin/init", &mut data); + // let data = INIT; + assert!(data.len() > 0); + let task = Task::from_elf("/bin/init", data.as_slice()).unwrap(); + Arc::new(task) +}); + +/// 将初始进程加入进程池中进行调度 +pub fn init_process() { + let task = INIT_PROCESS.clone(); + let cwd = SYSTEM_ROOT_FS.get().unwrap().clone(); + let root = cwd.clone(); + task.access_inner().fs_info = FsContext::new(root, cwd); + GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); + println!("Init process success"); +} + + +impl DriverTask for Task { + fn to_wait(&self) { + self.update_state(TaskState::Waiting) + } + + fn to_wakeup(&self) { + self.update_state(TaskState::Ready) + } + + fn have_signal(&self) -> bool { + self.access_inner().signal_receivers.lock().have_signal() + } +} +pub struct DriverTaskImpl; +impl DriverWithTask for DriverTaskImpl{ + fn get_task(&self) -> Arc { + let task = current_task().unwrap(); + task.clone() + } + + fn put_task(&self, task: Arc) { + let task = task.downcast_arc::().map_err(|_| ()).unwrap(); + GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); + } + + fn suspend(&self) { + do_suspend(); + } +} + + +impl DeviceWithTask for DriverTaskImpl { + fn transfer_ptr_raw(&self, ptr: usize) -> usize { + let task = current_task().unwrap(); + task.transfer_raw(ptr) + } + + fn transfer_buf_raw(&self, src: usize, size:usize) -> Vec<&mut [u8]> { + let task = current_task().unwrap(); + task.transfer_buffer(src as * const u8,size) + } +} + + +// online test has no sort.src +// pub static SORT_SRC: &[u8] = include_bytes!("../../../sdcard/sort.src"); diff --git a/kkernel/src/task/schedule.rs b/kkernel/src/task/schedule.rs new file mode 100644 index 00000000..4f9f72fe --- /dev/null +++ b/kkernel/src/task/schedule.rs @@ -0,0 +1,85 @@ +//! CPU 调度 +use alloc::sync::Arc; +use core::arch::asm; +use smpscheduler::FifoTask; + +use constants::signal::SignalNumber; + +use crate::ipc::send_signal; +use crate::task::context::switch; +use crate::task::cpu::current_cpu; +use crate::task::task::TaskState; +use crate::task::GLOBAL_TASK_MANAGER; +use crate::trap::check_timer_interrupt_pending; + +/// 在 CPU 启动并初始化完毕后初次进入用户态时,或者在一个任务将要让渡 CPU 时 将会执行该函数。 +/// +/// 如果当前 CPU 上有任务正在执行,那么将根据该任务当前的状态进行操作。 +/// - 如果该任务处于睡眠或等待状态,将会把其任务的控制块取出丢弃掉。 +/// - 如果该任务处于僵尸状态,将会向其父进程发送信号,令其回收该任务的控制块。 +/// - 如果该任务处于其他状态,我们将其放入线程池中等待下一次分配。 +/// +/// 之后如果在线程池中有任务需要调度,那么就把该任务的上下文切换到 CPU 上来运行; +/// 否则该 CPU 将进入等待状态,等待其它核的中断信号。 +pub fn run_task() -> ! { + loop { + { + let cpu = current_cpu(); + if cpu.task.is_some() { + let task = cpu.task.take().unwrap(); + match task.state() { + TaskState::Sleeping | TaskState::Waiting => { + // drop(task); + } + TaskState::Zombie => { + // 退出时向父进程发送信号,其中选项可被 sys_clone 控制 + if task.send_sigchld_when_exit || task.pid == task.tid.0 { + let parent = task + .access_inner() + .parent + .clone() + .unwrap() + .upgrade() + .unwrap(); + send_signal(parent.pid, SignalNumber::SIGCHLD as usize); + } + // 通知全局表将 signals 删除 + task.terminate(); + } + _ => { + GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); + } + } + } + } + let cpu = current_cpu(); + if let Some(task) = GLOBAL_TASK_MANAGER.pick_next_task() { + // if process.get_tid() >= 1 { + // warn!("switch to task {}", task.get_tid()); + // } + // update state to running + task.inner().update_state(TaskState::Running); + // get the process context + let context = task.inner().get_context_raw_ptr(); + cpu.task = Some(task.inner().clone()); + // switch to the process context + let cpu_context = cpu.get_context_mut_raw_ptr(); + // warn!("switch to task {}", process.get_tid()); + drop(task); + switch(cpu_context, context); + } else { + unsafe { asm!("wfi") } + } + } +} + +/// 切换线程上下文,调度当前在 CPU 上执行的线程 让渡出 CPU +pub fn schedule() { + check_timer_interrupt_pending(); + let cpu = current_cpu(); + let task = cpu.task.clone().unwrap(); + let cpu_context = cpu.get_context_raw_ptr(); + let context = task.get_context_mut_raw_ptr(); + drop(task); + switch(context, cpu_context); +} diff --git a/kkernel/src/task/stack.rs b/kkernel/src/task/stack.rs new file mode 100644 index 00000000..31a575de --- /dev/null +++ b/kkernel/src/task/stack.rs @@ -0,0 +1,33 @@ +//! 进程内核栈空间 + +use config::{ FRAME_SIZE}; +use mem::{alloc_frames, free_frames}; + +/// 记录进程内核栈空间 +#[derive(Debug)] +pub struct Stack { + /// 栈帧 + start_ptr: usize, + pages: usize, +} + +impl Stack { + /// 通过帧的个数创建一块新的 内核栈 + pub fn new(pages: usize) -> Option { + let frames = alloc_frames(pages); + Some(Stack { + start_ptr:frames as usize, + pages + }) + } + + /// 获取帧顶指针 + pub fn top(&self) -> usize { + self.start_ptr + self.pages * FRAME_SIZE + } + + /// 回收内核栈空间。 + pub fn release(&self) { + free_frames(self.start_ptr as _, self.pages) + } +} diff --git a/kkernel/src/task/switch.asm b/kkernel/src/task/switch.asm new file mode 100644 index 00000000..3f985d24 --- /dev/null +++ b/kkernel/src/task/switch.asm @@ -0,0 +1,34 @@ +.altmacro +.macro SAVE_SN n + sd s\n, (\n+2)*8(a0) +.endm +.macro LOAD_SN n + ld s\n, (\n+2)*8(a1) +.endm + .section .text + .globl __switch +__switch: + # __switch( + # current_task_cx_ptr: *mut TaskContext, + # next_task_cx_ptr: *const TaskContext + # ) + # save kernel stack of current task + sd sp, 8(a0) + # save ra & s0~s11 of current execution + sd ra, 0(a0) + .set n, 0 + .rept 12 + SAVE_SN %n + .set n, n + 1 + .endr + # restore ra & s0~s11 of next execution + ld ra, 0(a1) + .set n, 0 + .rept 12 + LOAD_SN %n + .set n, n + 1 + .endr + # restore kernel stack of next task + ld sp, 8(a1) + ret + diff --git a/kkernel/src/task/task.rs b/kkernel/src/task/task.rs new file mode 100644 index 00000000..b127bbef --- /dev/null +++ b/kkernel/src/task/task.rs @@ -0,0 +1,1813 @@ +//! Alien 中任务控制块的相关定义。 +//! +//! Alien 中对于进程\线程的相关概念的设计与 Linux 类似,进程和线程共用一个控制块结构。 +//! 使用 `clone` 创建新的进程(线程)时,会根据 flag 指明父子进程之间资源共享的程度。 +//! tid 是标识不同任务的唯一标识。 +use config::*; +use crate::fs::file::File; +use crate::ipc::{global_register_signals, ShmInfo}; +use crate::task::context::Context; +use crate::task::heap::HeapInfo; +use crate::task::stack::Stack; +use timer::{read_timer, ITimerVal, TimeNow, ToClock}; +use crate::trap::{trap_common_read_file, trap_return, user_trap_vector, TrapFrame}; +use alloc::collections::BTreeMap; +use alloc::string::{String, ToString}; +use alloc::sync::{Arc, Weak}; +use alloc::vec::Vec; +use alloc::{format, vec}; +use constants::aux::*; +use constants::io::MapFlags; +use constants::ipc::RobustList; +use constants::signal::{SignalHandlers, SignalNumber, SignalReceivers, SignalUserContext}; +use constants::sys::TimeVal; +use constants::task::CloneFlags; +use constants::time::TimerType; +use constants::{AlienError, AlienResult}; +use constants::{LinuxErrno, PrLimit, PrLimitRes}; +use core::fmt::{Debug, Formatter}; +use core::ops::Range; +use bit_field::BitField; +use gmanager::MinimalManager; +use ksync::{Mutex, MutexGuard}; +use page_table::addr::{align_down_4k, align_up_4k, VirtAddr}; +use page_table::pte::MappingFlags; +use page_table::table::Sv39PageTable; +use spin::Lazy; +use vfscore::dentry::VfsDentry; +use mem::{FRAME_REF_MANAGER, kernel_satp, VmmPageAllocator}; +use vfs::SYSTEM_ROOT_FS; +use crate::fs::stdio::{STDIN, STDOUT}; +use crate::mm::loader::{build_cow_address_space, build_elf_address_space, build_thread_address_space, UserStack}; +use crate::mm::map::{MMapInfo, MMapRegion, ProtFlags}; + +type FdManager = MinimalManager>; + +/// 这里把MinimalManager复用为tid分配器,通常,MinimalManager会将数据插入到最小可用位置并返回位置, +/// 但tid的分配并不需要实际存储信息,因此可以插入任意的数据,这里为了节省空间,将数据定义为u8 +pub static TID_MANAGER: Lazy>> = + Lazy::new(|| Mutex::new(MinimalManager::new(MAX_THREAD_NUM))); + +/// 用于存储线程的tid +#[derive(Debug)] +pub struct TidHandle(pub usize); + +impl TidHandle { + /// 获取一个新的线程 tid (来自于 `TID_MANAGER` 分配) + pub fn new() -> Option { + let tid = TID_MANAGER.lock().insert(0); + if tid.is_err() { + return None; + } + Some(Self(tid.unwrap())) + } +} + +impl Drop for TidHandle { + fn drop(&mut self) { + TID_MANAGER.lock().remove(self.0).unwrap(); + } +} + +#[derive(Debug)] +pub struct Task { + /// 任务的唯一标识 + pub tid: TidHandle, + /// 作为进程时,pid == tid;作为线程时,pid 为其线程组 leader (父进程)的 tid 号。 + pub pid: usize, + /// 当退出时是否向父进程发送信号 SIGCHLD。 + /// 如果创建时带 CLONE_THREAD 选项,则不发送信号,除非它是线程组(即拥有相同pid的所有线程)中最后一个退出的线程; + /// 否则发送信号 + pub send_sigchld_when_exit: bool, + /// 内核栈 + pub kernel_stack: Stack, + /// 更详细的信息 + inner: Mutex, +} + +#[derive(Debug)] +pub struct TaskInner { + /// 任务名,一般为其文件路径加文件名 + pub name: String, + /// 线程计数器,用于分配同一个线程组中的线程序号 + pub threads: MinimalManager<()>, + /// 用于记录当前线程组中的线程个数 + pub thread_number: usize, + /// 地址空间 + pub address_space: Arc>>, + /// 线程状态 + pub state: TaskState, + /// 父亲任务控制块 + pub parent: Option>, + /// 孩子任务控制块的集合 + pub children: Vec>, + /// 文件描述符表 + pub fd_table: Arc>, + /// 任务上下文 + pub context: Context, + /// 文件系统的信息 + pub fs_info: FsContext, + /// 有关任务执行情况的统计信息 + pub statistical_data: StatisticalData, + /// 任务计时器 + pub timer: TaskTimer, + /// 返回值 + pub exit_code: i32, + /// 堆空间 + pub heap: Arc>, + /// 地址空间中的映射信息 + pub mmap: MMapInfo, + /// 信号量对应的一组处理函数。 + /// 因为发送信号是通过 pid/tid 查找的,因此放在 inner 中一起调用时更容易导致死锁 + pub signal_handlers: Arc>, + /// 接收信号的结构。每个线程中一定是独特的,而上面的 handler 可能是共享的 + pub signal_receivers: Arc>, + /// 子线程初始化时,存放 tid 的地址。当且仅当创建时包含 CLONE_CHILD_SETTID 才非0 + pub set_child_tid: usize, + /// 子线程初始化时,将这个地址清空;子线程退出时,触发这里的 futex。 + /// 在创建时包含 CLONE_CHILD_SETTID 时才非0,但可以被 sys_set_tid_address 修改 + pub clear_child_tid: usize, + /// 处理信号时,保存的之前的用户线程的上下文信息 + trap_cx_before_signal: Option, + /// 保存信息时,处理函数是否设置了 SIGINFO 选项 + /// 如果设置了,说明信号触发前的上下文信息通过 ucontext 传递给了用户, + /// 此时用户可能修改其中的 pc 信息(如musl-libc 的 pthread_cancel 函数)。 + /// 在这种情况下,需要手动在 sigreturn 时更新已保存的上下文信息 + pub signal_set_siginfo: bool, + /// robust 锁的列表 + pub robust: RobustList, + /// 共享内存 + pub shm: BTreeMap, + /// cpu 亲和力,用于 cpu 调度时 倾向于将该任务调度给 哪个 CPU + pub cpu_affinity: usize, + /// 进程创建文件时,文件权限的默认掩码 + pub unmask: usize, + /// 栈空间的信息 + pub stack: Range, + /// 是否需要等待 + pub need_wait: u8, +} + +#[derive(Debug, Copy, Clone)] +pub struct TaskTimer { + /// 计时器类型 + pub timer_type: TimerType, + /// 设置下一次触发计时器的区间 + /// + /// 当 timer_remained 归零时,如果 timer_interval 非零,则将其重置为 timer_interval 的值; + /// 否则,则这个计时器不再触发 + pub timer_interval: TimeVal, + /// 当前计时器还剩下多少时间。 + /// + /// 根据 timer_type 的规则不断减少,当归零时触发信号 + pub timer_remained: usize, + /// 上一次计时的开始时间 + pub start: usize, + /// 该计时器是否已经超时 + pub expired: bool, +} + +impl TaskTimer { + /// 清除当前的计数器信息,将 timer_remained 置为 0 + pub fn clear(&mut self) { + self.timer_type = TimerType::NONE; + self.timer_interval = TimeVal::new(); + self.timer_remained = 0; + self.expired = false; + } +} + +impl Default for TaskTimer { + /// 默认的任务计数器 + fn default() -> Self { + Self { + timer_type: TimerType::NONE, + timer_interval: TimeVal::new(), + timer_remained: 0, + start: 0, + expired: false, + } + } +} + +/// statistics of a process +#[derive(Debug, Clone)] +pub struct StatisticalData { + /// The number of times the process was scheduled in user mode. --ticks + pub tms_utime: usize, + /// The number of times the process was scheduled in kernel mode. --ticks + pub tms_stime: usize, + /// The last time the process was scheduled in user mode. --ticks + pub last_utime: usize, + /// The last time the process was scheduled in kernel mode. --ticks + pub last_stime: usize, + + pub tms_cutime: usize, + pub tms_cstime: usize, +} + +impl StatisticalData { + /// 用于创建一个新的 `StatisticalData` 结构 + pub fn new() -> Self { + let now = read_timer(); + StatisticalData { + tms_utime: 0, + tms_stime: 0, + last_utime: now, + last_stime: now, + tms_cutime: 0, + tms_cstime: 0, + } + } + /// 清除当前 `StatisticalData` 结构中储存的数据,并将 `last_utime` 和 `last_stime` 的值置为 当前的时间 + pub fn clear(&mut self) { + let now = read_timer(); + self.tms_utime = 0; + self.tms_stime = 0; + self.last_utime = now; + self.last_stime = now; + self.tms_cutime = 0; + self.tms_cstime = 0; + } +} + +#[derive(Clone)] +pub struct FsContext { + /// 当前工作目录 + pub cwd: Arc, + /// 根目录 + pub root: Arc, +} + +impl Debug for FsContext { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + let cwd = self.cwd.path(); + let root = self.root.path(); + f.debug_struct("FsContext") + .field("cwd", &cwd) + .field("root", &root) + .finish() + } +} + +impl FsContext { + /// 创建一个新的 `FsContext` 结构 + pub fn new(root: Arc, cwd: Arc) -> Self { + FsContext { cwd, root } + } +} + +#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)] +pub enum TaskState { + /// 就绪态 + Ready, + /// 运行态 + Running, + /// 等待一段时间 + Sleeping, + /// 等待一个事件 + Waiting, + /// 僵尸态,等待父进程回收资源 + Zombie, + /// 终止态 + Terminated, +} + +impl Task { + /// 终止进程,回收内核栈等资源,同时将该任务的状态修改为 `Terminated` + pub fn terminate(self: Arc) { + // recycle kernel stack + self.kernel_stack.release(); + if self.access_inner().thread_number != 0 { + let parent = self.inner.lock().parent.clone(); + if let Some(parent) = parent { + let parent = parent.upgrade(); + if let Some(parent) = parent { + parent.remove_child_by_tid(self.get_tid()); + assert_eq!(Arc::strong_count(&self), 1); + } + } + } else { + // if it is a thread, we should not remove it from parent's children + // if self.access_inner().children.len() == 0 { + // self.access_inner().address_space.lock().release(); + // } + } + self.access_inner().state = TaskState::Terminated; + } + + /// 获取进程的 pid 号 + #[inline] + pub fn get_pid(&self) -> isize { + self.pid as isize + } + + /// 获取进程的 tid 号 + #[inline] + pub fn get_tid(&self) -> isize { + self.tid.0 as isize + } + + /// 设置 `clear_child_tid` 字段的 值 + pub fn set_tid_address(&self, tidptr: usize) { + let mut inner = self.inner.lock(); + inner.clear_child_tid = tidptr; + } + + /// 获取文件的名称 + pub fn get_name(&self) -> String { + let inner = self.inner.lock(); + inner.name.clone() + } + + /// 尝试获取 TaskInner + pub fn access_inner(&self) -> MutexGuard { + self.inner.lock() + } + + /// 获取进程页表的root ppn + pub fn token(&self) -> usize { + let inner = self.inner.lock(); + let paddr = inner.address_space.lock().root_paddr(); + (8usize << 60) | (paddr.as_usize() >> 12) + } + + /// 获取 trap 帧的可变引用 + pub fn trap_frame(&self) -> &'static mut TrapFrame { + self.inner.lock().trap_frame() + } + + /// 获取 trap 帧的指针 + pub fn trap_frame_ptr(&self) -> *mut TrapFrame { + self.inner.lock().trap_frame_ptr() + } + + /// 将进程的状态修改为 state + pub fn update_state(&self, state: TaskState) { + let mut inner = self.inner.lock(); + inner.state = state; + } + + /// 返回进程的状态 + pub fn state(&self) -> TaskState { + let inner = self.inner.lock(); + inner.state + } + + /// 更新进程的返回码 + pub fn update_exit_code(&self, code: i32) { + let mut inner = self.inner.lock(); + inner.exit_code = code; + } + + /// 获取任务上下文的指针 + pub fn get_context_raw_ptr(&self) -> *const Context { + let inner = self.inner.lock(); + &inner.context as *const Context + } + + /// 获取任务上下文的可变指针 + pub fn get_context_mut_raw_ptr(&self) -> *mut Context { + let mut inner = self.inner.lock(); + &mut inner.context as *mut Context + } + + /// 获取该进程的子进程的控制块列表 + pub fn children(&self) -> Vec> { + let inner = self.inner.lock(); + inner.children.clone() + } + + /// 查找进程号为pid的子进程是否已经退出。当pid为-1时,任意子进程退出都将返回子进程的pid号。 + pub fn check_child(&self, pid: isize) -> Option { + let res = self + .inner + .lock() + .children + .iter() + .enumerate() + .find(|(_, child)| { + child.state() == TaskState::Terminated && (child.get_pid() == pid || pid == -1) + }) + .map(|(index, _)| index); + res + } + + /// 取走当前进程的子进程控制块列表的所有权 + pub fn take_children(&self) -> Vec> { + let children = self.children(); + self.access_inner().children = Vec::new(); + children + } + + /// 将任务号为 `tid` 的进程 从子进程列表中移除 + pub fn remove_child_by_tid(&self, tid: isize) -> Option> { + let mut inner = self.inner.lock(); + let index = inner + .children + .iter() + .position(|child| child.get_tid() == tid); + if let Some(index) = index { + Some(inner.children.remove(index)) + } else { + None + } + } + + /// 将子进程列表中第 `index` 个进程 从子进程列表中移除 + pub fn remove_child(&self, index: usize) -> Arc { + let mut inner = self.inner.lock(); + assert!(index < inner.children.len()); + inner.children.remove(index) + } + + /// 将进程的父进程更新为 `parent` + pub fn update_parent(&self, parent: Arc) { + let mut inner = self.inner.lock(); + inner.parent = Some(Arc::downgrade(&parent)); + } + + /// 向子进程列表中插入一个新的子进程 + pub fn insert_child(&self, child: Arc) { + let mut inner = self.inner.lock(); + inner.children.push(child); + } + + /// 获取进程当前的返回码 + pub fn exit_code(&self) -> i32 { + let inner = self.inner.lock(); + inner.exit_code + } + + /// 用于获取文件描述符id号为 fd 的 文件描述符 + pub fn get_file(&self, fd: usize) -> Option> { + let inner = self.inner.lock(); + let file = inner.fd_table.lock().get(fd); + return if file.is_err() { None } else { file.unwrap() }; + } + + /// 在进程的文件描述符表中加入 file 文件 + pub fn add_file(&self, file: Arc) -> Result { + self.access_inner() + .fd_table + .lock() + .insert(file) + .map_err(|x| x as isize) + } + + /// 指定文件描述符表中的一个id,在该处加入一个 file 文件 + pub fn add_file_with_fd(&self, file: Arc, fd: usize) -> Result<(), ()> { + let inner = self.access_inner(); + let mut fd_table = inner.fd_table.lock(); + fd_table.insert_with_index(fd, file).map_err(|_| {}) + } + + /// 指明文件描述符表中的一个id,删除并返回该处的 file 文件 + pub fn remove_file(&self, fd: usize) -> Result, ()> { + let inner = self.inner.lock(); + let file = inner.fd_table.lock().get(fd); + if file.is_err() { + return Err(()); + } + let file = file.unwrap(); + if file.is_none() { + return Err(()); + } + let file = file.unwrap(); + inner.fd_table.lock().remove(fd).map_err(|_| {})?; + Ok(file) + } + + /// 获取一个虚拟地址 `ptr` 的实际物理地址 + pub fn transfer_raw(&self, ptr: usize) -> usize { + self.access_inner().transfer_raw(ptr) + } + + /// 获取一个虚拟地址 `ptr` 对应的 T 类型数据 的 可变引用 + pub fn transfer_raw_ptr(&self, ptr: *mut T) -> &'static mut T { + self.access_inner().transfer_raw_ptr_mut(ptr) + } + + /// 通过用户地址空间中一个字符串的首指针 `ptr`,获取一个字符串。 + pub fn transfer_str(&self, ptr: *const u8) -> String { + // we need check the ptr and len before transfer indeed + let mut start = ptr as usize; + let end = start + 128; //todo! string len is unknown + let address_space = self.access_inner().address_space.clone(); + while start < end { + let (_phy, flag, _) = address_space + .lock() + .query(VirtAddr::from(start)) + .expect(format!("transfer_buffer: {:x} failed", start).as_str()); + if !flag.contains(MappingFlags::V) { + error!("transfer_str flag: {:?}, addr:{:#x}", flag, start); + let res = self + .access_inner() + .invalid_page_solver(align_down_4k(start)) + .unwrap(); + if res.is_some() { + let (file, buf, offset) = res.unwrap(); + if file.is_some() { + trap_common_read_file(file.unwrap(), buf, offset); + } + } + } + start += FRAME_SIZE; + } + self.access_inner().transfer_str(ptr) + } + + /// 通过用户地址空间中一个缓冲区的指针 `ptr` 和 缓冲区的长度 `len`,得到一组对用户地址空间中缓冲区的可变引用,每一组引用的长度为 4K + pub fn transfer_buffer(&self, ptr: *const T, len: usize) -> Vec<&'static mut [T]> { + // we need check the ptr and len before transfer indeed + let mut start = ptr as usize; + let end = start + len; + let address_space = self.access_inner().address_space.clone(); + start = align_down_4k(start); + while start < end { + let (_phy, flag, _) = address_space + .lock() + .query(VirtAddr::from(start)) + .expect(format!("transfer_buffer: {:x} failed", start).as_str()); + if !flag.contains(MappingFlags::V) { + error!("transfer_buffer flag: {:?}, addr:{:#x}", flag, start); + let res = self + .access_inner() + .invalid_page_solver(align_down_4k(start)) + .unwrap(); + if res.is_some() { + let (file, buf, offset) = res.unwrap(); + if file.is_some() { + trap_common_read_file(file.unwrap(), buf, offset); + } + } + } + start += FRAME_SIZE; + } + self.access_inner().transfer_buffer(ptr, len) + } +} + +impl TaskInner { + /// 获取进程的文件系统信息 + pub fn cwd(&self) -> FsContext { + self.fs_info.clone() + } + + /// 获取进程的计时器 + pub fn get_timer(&self) -> TaskTimer { + self.timer.clone() + } + + /// 获取当前进程对于资源的限制 + pub fn get_prlimit(&self, resource: PrLimitRes) -> PrLimit { + match resource { + PrLimitRes::RlimitStack => PrLimit::new(USER_STACK_SIZE as u64, USER_STACK_SIZE as u64), + PrLimitRes::RlimitNofile => { + let max_fd = self.fd_table.lock().max(); + PrLimit::new(max_fd as u64, max_fd as u64) + } + PrLimitRes::RlimitAs => PrLimit::new(u64::MAX, u64::MAX), + } + } + + /// 设置当前进程对于资源的限制 + pub fn set_prlimit(&mut self, resource: PrLimitRes, value: PrLimit) { + match resource { + PrLimitRes::RlimitStack => {} + PrLimitRes::RlimitNofile => { + let new_max_fd = value.rlim_cur; + self.fd_table.lock().set_max(new_max_fd as usize); + } + PrLimitRes::RlimitAs => {} + } + } + + /// 返回 trap 上下文的一个可变指针 + pub fn trap_frame_ptr(&self) -> *mut TrapFrame { + let trap_context_base = if self.thread_number != 0 { + let base = TRAP_CONTEXT_BASE - self.thread_number * FRAME_SIZE; + base + } else { + TRAP_CONTEXT_BASE + }; + trap_context_base as *mut TrapFrame + } + + /// 返回 trap 上下文的一个可变引用 + pub fn trap_frame(&self) -> &'static mut TrapFrame { + let trap_context_base = if self.thread_number != 0 { + let base = TRAP_CONTEXT_BASE - self.thread_number * FRAME_SIZE; + base + } else { + TRAP_CONTEXT_BASE + }; + let (physical, _, _) = self + .address_space + .lock() + .query(VirtAddr::from(trap_context_base)) + .unwrap(); + TrapFrame::from_raw_ptr(physical.as_usize() as *mut TrapFrame) + } + + /// 在信号处理需要执行用户态信号处理函数时,保存原 trap 上下文。 + pub fn save_trap_frame(&mut self) -> bool { + let trap_frame = self.trap_frame(); + if self.trap_cx_before_signal.is_some() { + return false; + } + self.trap_cx_before_signal = Some(*trap_frame); + self.signal_set_siginfo = false; + true + } + + /// 待用户态信号处理函数执行完毕后,需要重新加载原 trap 上下文。 + pub fn load_trap_frame(&mut self) -> isize { + if let Some(old_trap_frame) = self.trap_cx_before_signal.take() { + let trap_frame = self.trap_frame(); + // 这里假定是 sigreturn 触发的,即用户的信号处理函数 return 了(cancel_handler) + // 也就是说信号触发时的 sp 就是现在的 sp + let sp = trap_frame.regs()[2]; + // 获取可能被修改的 pc + let phy_sp = self.transfer_raw(sp); + + let pc = unsafe { (*(phy_sp as *const SignalUserContext)).get_pc() }; + *trap_frame = old_trap_frame; + if self.signal_set_siginfo { + // 更新用户修改的 pc + trap_frame.set_sepc(pc); + warn!("sig return sp = {:x} pc = {:x}", sp, pc); + } + trap_frame.regs()[10] as isize // old arg0 + } else { + -1 + } + } + + /// 获取一个虚拟地址 `ptr` 的实际物理地址 + pub fn transfer_raw(&mut self, ptr: usize) -> usize { + let (phy, flag, _) = self + .address_space + .lock() + .query(VirtAddr::from(ptr)) + .unwrap(); + if !flag.contains(MappingFlags::V) { + error!("[transfer_raw] invalid page {:?}, ptr:{:#x}", flag, ptr); + self.invalid_page_solver(ptr).unwrap(); + let (phy, flag, _) = self + .address_space + .lock() + .query(VirtAddr::from(ptr)) + .unwrap(); + assert!(flag.contains(MappingFlags::V)); + return phy.as_usize(); + } + phy.as_usize() + } + + /// 获取 虚拟地址空间中的以 `ptr` 为起始地址,以 '\0' 结尾的字符串 + pub fn transfer_str(&self, ptr: *const u8) -> String { + let mut res = String::new(); + let physical = self + .address_space + .lock() + .query(VirtAddr::from(ptr as usize)); + if physical.is_err() { + return res; + } + let (physical, _, _) = physical.unwrap(); + let mut physical = physical.as_usize(); + loop { + let c = unsafe { &*(physical as *const u8) }; + if *c == 0 { + break; + } + res.push(*c as char); + physical += 1; + } + res + } + + /// 从物理地址的 `src` 处取一个长度为 `len` 类型为 T 的缓冲区 赋到 用户虚拟地址空间下的 `dst` 处 + pub fn copy_to_user_buffer( + &mut self, + src: *const T, + dst: *mut T, + len: usize, + ) { + let size = core::mem::size_of::() * len; + if VirtAddr::from(dst as usize).align_down_4k() + == VirtAddr::from(dst as usize + size - 1).align_down_4k() + { + // the src and dst are in same page + let dst = self.transfer_raw(dst as usize); + unsafe { + core::ptr::copy_nonoverlapping(src as *const u8, dst as *mut u8, size); + } + } else { + let bufs = self.transfer_buffer(dst as *const u8, size); + let src = unsafe { core::slice::from_raw_parts(src as *const u8, size) }; + let mut start = 0; + let src_len = src.len(); + for buffer in bufs { + let len = if start + buffer.len() > src_len { + src_len - start + } else { + buffer.len() + }; + unsafe { + core::ptr::copy_nonoverlapping( + src.as_ptr().add(start), + buffer.as_mut_ptr(), + len, + ); + } + start += len; + } + } + } + + /// 从用户虚拟地址空间的 `src` 处取一个长度为 `len` 类型为 T 的缓冲区 赋到 物理地址下的 `dst` 处 + pub fn copy_from_user_buffer( + &mut self, + src: *const T, + dst: *mut T, + len: usize, + ) { + let size = core::mem::size_of::() * len; + if VirtAddr::from(src as usize).align_down_4k() + == VirtAddr::from(src as usize + size - 1).align_down_4k() + { + // the src and dst are in same page + let src = self.transfer_raw(src as usize); + unsafe { + core::ptr::copy_nonoverlapping(src as *const u8, dst as *mut u8, size); + } + } else { + let mut bufs = self.transfer_buffer(src as *const u8, size); + let dst = unsafe { core::slice::from_raw_parts_mut(dst as *mut u8, size) }; + let mut start = 0; + let dst_len = dst.len(); + for buffer in bufs.iter_mut() { + let len = if start + buffer.len() > dst_len { + dst_len - start + } else { + buffer.len() + }; + unsafe { + core::ptr::copy_nonoverlapping( + buffer.as_ptr(), + dst.as_mut_ptr().add(start), + len, + ); + } + start += len; + } + } + } + + /// 从物理空间下的 `src` 处取一个 T 类型的数据 赋给 虚拟地址空间下的 `dst` 处 + pub fn copy_to_user(&mut self, src: *const T, dst: *mut T) { + // self.copy_to_user_buffer(src, dst, 1); + let size = core::mem::size_of::(); + if VirtAddr::from(dst as usize).align_down_4k() + == VirtAddr::from(dst as usize + size - 1).align_down_4k() + { + // the src and dst are in same page + let dst = self.transfer_raw(dst as usize); + unsafe { + core::ptr::copy_nonoverlapping(src as *const u8, dst as *mut u8, size); + } + } else { + let bufs = self.transfer_buffer(dst as *const u8, size); + let src = unsafe { core::slice::from_raw_parts(src as *const u8, size) }; + let mut start = 0; + let src_len = src.len(); + for buffer in bufs { + let len = if start + buffer.len() > src_len { + src_len - start + } else { + buffer.len() + }; + unsafe { + core::ptr::copy_nonoverlapping( + src.as_ptr().add(start), + buffer.as_mut_ptr(), + len, + ); + } + start += len; + } + } + } + + /// 从用户虚拟地址空间的 `src` 处取一个 T 类型的数据 赋给 物理地址下的 `dst` 处 + pub fn copy_from_user(&mut self, src: *const T, dst: *mut T) { + // self.copy_from_user_buffer(src, dst, 1); + let size = core::mem::size_of::(); + if VirtAddr::from(src as usize).align_down_4k() + == VirtAddr::from(src as usize + size - 1).align_down_4k() + { + // the src and dst are in same page + let src = self.transfer_raw(src as usize); + unsafe { + core::ptr::copy_nonoverlapping(src as *const u8, dst as *mut u8, size); + } + } else { + let mut bufs = self.transfer_buffer(src as *const u8, size); + let dst = unsafe { core::slice::from_raw_parts_mut(dst as *mut u8, size) }; + let mut start = 0; + let dst_len = dst.len(); + for buffer in bufs.iter_mut() { + let len = if start + buffer.len() > dst_len { + dst_len - start + } else { + buffer.len() + }; + unsafe { + core::ptr::copy_nonoverlapping( + buffer.as_ptr(), + dst.as_mut_ptr().add(start), + len, + ); + } + start += len; + } + } + } + + /// 将在进程的虚拟空间中的一段缓冲区的首地址 `ptr` 和 长度 `len` 转换为 实地址下的一组页 + pub fn transfer_buffer( + &mut self, + ptr: *const T, + len: usize, + ) -> Vec<&'static mut [T]> { + let mut start = ptr as usize; + let end = start + len; + let mut v = Vec::new(); + while start < end { + let (start_phy, flag, _) = self + .address_space + .lock() + .query(VirtAddr::from(start)) + .expect(format!("transfer_buffer: {:x} failed", start).as_str()); + if !flag.contains(MappingFlags::V) { + panic!("transfer_buffer: {:x} not mapped", start); + } + // start_phy向上取整到FRAME_SIZE + let bound = (start & !(FRAME_SIZE - 1)) + FRAME_SIZE; + let len = if bound > end { + end - start + } else { + bound - start + }; + unsafe { + let buf = core::slice::from_raw_parts_mut(start_phy.as_usize() as *mut T, len); + v.push(buf); + } + start = bound; + } + v + } + + /// 将一个在进程的虚拟空间中的虚地址 转换为一个实地址的可变引用 + pub fn transfer_raw_ptr_mut(&self, ptr: *mut T) -> &'static mut T { + let (physical, flag, _) = self + .address_space + .lock() + .query(VirtAddr::from(ptr as usize)) + .unwrap(); + assert!(flag.contains(MappingFlags::V)); + unsafe { &mut *(physical.as_usize() as *mut T) } + } + + /// 将一个在进程的虚拟空间中的虚地址 转换为一个实地址的不可变引用 + pub fn transfer_raw_ptr(&self, ptr: *const T) -> &'static T { + let (physical, flag, _) = self + .address_space + .lock() + .query(VirtAddr::from(ptr as usize)) + .unwrap(); + assert!(flag.contains(MappingFlags::V)); + unsafe { &*(physical.as_usize() as *const T) } + } + + /// 当进程回到用户态时,需要更新进程在内核态下的运行时间 + /// WARNING: If the cause of the process returning to the kernel is a timer interrupt, + /// We should not call this function. + pub fn update_kernel_mode_time(&mut self) { + let now = read_timer(); // current cpu clocks + let time = now - self.statistical_data.last_stime; + self.update_timer(); + self.statistical_data.tms_stime += time; + self.statistical_data.last_utime = now; + } + + /// 当进程进入内核态时,需要更新进程在用户态下的运行时间 + pub fn update_user_mode_time(&mut self) { + let now = read_timer(); // current cpu clocks + let time = now - self.statistical_data.last_utime; + self.update_timer(); + self.statistical_data.tms_utime += time; + self.statistical_data.last_stime = now; + } + + /// 设置计时器 + pub fn set_timer(&mut self, itimer: ITimerVal, timer_type: TimerType) { + self.timer.timer_remained = itimer.it_value.to_clock(); + self.timer.timer_interval = itimer.it_interval; + self.timer.timer_type = timer_type; + self.timer.start = TimeVal::now().to_clock(); + } + + /// 更新计时器 + /// + /// 如果没有计时器则直接返回;如果有计时器但时辰未到也直接返回; + /// 如果有计时器且计时器到时间了,根据是否为one-shot计时器,确定重置计时器或者置`timer`的`timer_remained`为0。 + pub fn update_timer(&mut self) { + let now = read_timer(); + let delta = now - self.timer.start; + if self.timer.timer_remained == 0 { + // 等于0说明没有计时器,或者 one-shot 计时器已结束 + return; + } + if self.timer.timer_remained > delta { + // 时辰未到 + return; + } + // 到此说明计时器已经到时间了,更新计时器 + // 如果是 one-shot 计时器,则 timer_interval_us == 0,这样赋值也恰好是符合语义的 + self.timer.timer_remained = if self.timer.timer_interval == TimeVal::new() { + 0 + } else { + self.timer.start = now; + self.timer.timer_interval.to_clock() + }; + self.timer.expired = true; + } + + /// 在调用 `update_user_mode_time` 和 `update_kernel_mode_time` 后,我们需要检查一下计时器是否已经超时 + pub fn check_timer_expired(&mut self) -> Option { + if self.timer.expired { + self.timer.expired = false; + Some(self.timer.timer_type) + } else { + None + } + } + + /// 返回进程的统计信息 + pub fn statistical_data(&self) -> &StatisticalData { + &self.statistical_data + } + + /// 返回堆信息 + pub fn heap_info(&self) -> HeapInfo { + self.heap.lock().clone() + } + + #[allow(unused)] + /// (待实现)缩减堆空间 + pub fn shrink_heap(_addr: usize) -> Result { + todo!() + } + + /// 拓展堆空间 + pub fn extend_heap(&mut self, addr: usize) -> Result { + let mut heap = self.heap.lock(); + heap.current = addr; + if addr < heap.end { + return Ok(heap.current); + } + let addition = addr - heap.end; + // increase heap size + let end = heap.end; + // align addition to PAGE_SIZE + let addition = (addition + FRAME_SIZE - 1) & !(FRAME_SIZE - 1); + trace!("extend heap: {:#x} -- {:#x}", end, addition); + self.address_space + .lock() + .map_region_no_target( + VirtAddr::from(end), + addition, + "RWUAD".into(), // no V flag + false, + true, + ) + .unwrap(); + let new_end = end + addition; + heap.end = new_end; + Ok(heap.current) + } + + /// 在虚拟空间中创建内存映射。 + /// + `start`: 所要创建的映射区的起始地址。当该值为0时,内核将自动为其分配一段内存空间创建内存映射。该值在函数运行过程中将被调整为与4K对齐。 + /// + `len`: 指明所要创建的映射区的长度。该值在函数运行过程中将被调整为与4K对齐。 + /// + `prot`: 指明创建内存映射区的初始保护位。具体可见[`ProtFlags`]。 + /// + `flags`: 指明mmap操作的相关设置。具体可见[`MapFlags`]。 + /// + `fd`: 指明要创建内存映射的文件的文件描述符。 + /// + `offset`: 将从文件中偏移量为`offset`处开始映射。该值需要和4K对齐。 + /// + /// 函数成功执行后将返回所创建的内存映射区的首地址;否则返回错误类型。 + pub fn add_mmap( + &mut self, + start: usize, + len: usize, + prot: ProtFlags, + flags: MapFlags, + fd: usize, + offset: usize, + ) -> AlienResult { + // start == 0 表明需要OS为其找一段内存,而 MAP_FIXED 表明必须 mmap 在固定位置。两者是冲突的 + if start == 0 && flags.contains(MapFlags::MAP_FIXED) { + return Err(LinuxErrno::EINVAL); + } + + // if the map in heap, now we ignore it + if self.heap.lock().contains(start) && self.heap.lock().contains(start + len) { + return Ok(start); + } + + // not map to file + let fd = if flags.contains(MapFlags::MAP_ANONYMOUS) { + None + } else { + let file = self + .fd_table + .lock() + .get(fd) + .map_err(|_| LinuxErrno::EBADF)? + .ok_or(LinuxErrno::EBADF)?; // EBADF + Some(file) + }; + // todo! + // for dynamic link, the linker will map the elf file to the same address + // we must satisfy this requirement + let mut start = align_down_4k(start); + let v_range = if prot.contains(ProtFlags::PROT_EXEC) { + let len = align_up_4k(len); + if start > self.heap.lock().start { + // the mmap region is in heap + return Err(LinuxErrno::EINVAL); + } + if let Some(_region) = self.mmap.get_region(start) { + return Err(LinuxErrno::EINVAL); + } + if start == 0 { + start = 0x1000; + } + start..start + len + } else if flags.contains(MapFlags::MAP_FIXED) { + let len = align_up_4k(len); + if start > self.heap.lock().start { + error!("mmap fixed address conflict with heap"); + return Err(LinuxErrno::EINVAL); + } + // check if the region is already mapped + if let Some(region) = self.mmap.get_region(start) { + // split the region + let (left, mut right) = region.split(start); + // delete the old region + self.mmap.remove_region(region.start); + // add the left region + self.mmap.add_region(left); + if start + len < right.start + right.map_len { + // slice the right region + trace!( + "again slice the right region:{:#x?}, len:{:#x}", + right.start, + right.len + ); + let (mut left, right) = right.split(start + len); + // add the right region + self.mmap.add_region(right); + // update prot and flags + left.set_prot(prot); + left.set_flags(flags); + left.offset = offset; + left.fd = fd; + self.mmap.add_region(left); + } else { + trace!( + "directly add the right region:{:#x?}, len:{:#x}", + right.start, + right.len + ); + // update prot and flags + right.set_prot(prot); + right.set_flags(flags); + right.offset = offset; + right.fd = fd; + self.mmap.add_region(right); + } + return Ok(start); + } + start..start + len + } else { + let v_range = self.mmap.alloc(len); + v_range + }; + + let region = MMapRegion::new( + v_range.start, + len, + v_range.end - v_range.start, + prot, + flags, + fd, + offset, + ); + // warn!("add mmap region:{:#x?}",region); + self.mmap.add_region(region); + let start = v_range.start; + let mut map_flags:MappingFlags = prot.into(); // no V flag + map_flags |= "AD".into(); + self.address_space + .lock() + .map_region_no_target( + VirtAddr::from(start), + v_range.end - start, + map_flags, + false, + true, + ) + .unwrap(); + Ok(start) + } + + /// 用于在进程的虚拟内存空间中消除一段内存映射。传入的`start`需要是某段内存映射的首地址,`len`需要是该段内存映射的长度。 + pub fn unmap(&mut self, start: usize, len: usize) -> Result<(), isize> { + // check whether the start is in mmap + let x = self.mmap.get_region(start); + if x.is_none() { + return Err(LinuxErrno::EINVAL.into()); + } + // now we need make sure the start is equal to the start of the region, and the len is equal to the len of the region + let region = x.unwrap(); + if region.start != start || len != region.len { + return Err(LinuxErrno::EINVAL.into()); + } + self.address_space + .lock() + .unmap_region(VirtAddr::from(start), region.map_len) + .unwrap(); + self.mmap.remove_region(start); + Ok(()) + } + + /// 设置内存映射的保护位,函数会检查传入的`start`和`len`所指示的内存映射区是否已经处于被映射状态,如果是,则将对应内存映射区的保护位与`prot`做或运算。 + pub fn map_protect(&mut self, start: usize, len: usize, prot: ProtFlags) -> AlienResult<()> { + // check whether the start is in mmap + let x = self.mmap.get_region_mut(start); + if x.is_none() { + let res = self.address_space.lock().query(VirtAddr::from(start)); + return if res.is_err() { + Err(LinuxErrno::EINVAL) + } else { + Ok(()) + }; + } + // now we need make sure the start is equal to the start of the region, and the len is equal to the len of the region + let region = x.unwrap(); + if start + len > region.start + region.len { + error!("start+len > region.start + region.len"); + return Err(LinuxErrno::EINVAL); + } + region.prot |= prot; + Ok(()) + } + + /// 用于处理装入页异常 + pub fn do_load_page_fault( + &mut self, + addr: usize, + ) -> AlienResult>, &'static mut [u8], u64)>> { + // check whether the addr is in mmap + let addr = align_down_4k(addr); + let (_phy, flags, page_size) = self + .address_space + .lock() + .query(VirtAddr::from(addr)) + .expect(format!("addr:{:#x}", addr).as_str()); + trace!( + "do load page fault:{:#x}, flags:{:?}, page_size:{:?}", + addr, + flags, + page_size + ); + if !flags.contains(MappingFlags::V) { + return self.invalid_page_solver(addr); + } + assert!(!flags.contains(MappingFlags::RSD)); + + let region = self.mmap.get_region(addr).ok_or(AlienError::EINVAL)?; + // now we need make sure the start is equal to the start of the region, and the len is equal to the len of the region + // update page table + let mut map_flags:MappingFlags = region.prot.into(); + map_flags |= "V".into(); + + let mut address_space = self.address_space.lock(); + + let (_, flags, _) = address_space.query(VirtAddr::from(addr)).unwrap(); + assert!(!flags.contains(MappingFlags::V)); + address_space + .validate(VirtAddr::from(addr), map_flags) + .unwrap(); + let (phy, _, size) = address_space.query(VirtAddr::from(addr)).unwrap(); + let buf = + unsafe { core::slice::from_raw_parts_mut(phy.as_usize() as *mut u8, size.into()) }; + let file = ®ion.fd; + + let read_offset = region.offset + (addr - region.start); + Ok(Some((file.clone(), buf, read_offset as u64))) + } + + /// 用于处理无效页错误 + fn invalid_page_solver( + &mut self, + addr: usize, + ) -> AlienResult>, &'static mut [u8], u64)>> { + trace!("invalid page fault at {:#x}", addr); + let is_mmap = self.mmap.get_region(addr); + let is_heap = self.heap.lock().contains(addr); + + let is_stack = self.stack.contains(&addr); + + if is_mmap.is_none() && !is_heap && !is_stack { + warn!("invalid page fault at {:#x}", addr); + return Err(AlienError::EINVAL); + } + if is_heap { + trace!("invalid page fault in heap"); + let map_flags = "RWUVAD".into(); + self.address_space + .lock() + .validate(VirtAddr::from(addr), map_flags) + .unwrap(); + } else if is_mmap.is_some() { + let region = is_mmap.unwrap(); + // assert_eq!(addr % FRAME_SIZE, 0); + // update page table + let mut map_flags:MappingFlags = region.prot.into(); + map_flags |= "VAD".into(); + warn!( + "invalid page fault at {:#x}, flag is :{:?}", + addr, map_flags + ); + self.address_space + .lock() + .validate(VirtAddr::from(addr).align_down_4k(), map_flags) + .unwrap(); + let (phy, flag, size) = self + .address_space + .lock() + .query(VirtAddr::from(addr)) + .unwrap(); + assert!(flag.contains(MappingFlags::V)); + let buf = + unsafe { core::slice::from_raw_parts_mut(phy.as_usize() as *mut u8, size.into()) }; + let file = ®ion.fd; + let read_offset = region.offset + (addr - region.start); + return Ok(Some((file.clone(), buf, read_offset as u64))); + } else { + warn!("invalid page fault in stack, addr: {:#x}", addr); + let map_flags = "RWUVAD".into(); + self.address_space + .lock() + .validate(VirtAddr::from(addr), map_flags) + .unwrap(); + } + Ok(None) + } + + /// 用于处理指令页异常 + pub fn do_instruction_page_fault( + &mut self, + addr: usize, + ) -> AlienResult>, &'static mut [u8], u64)>> { + let addr = align_down_4k(addr); + let (_phy, flags, page_size) = self + .address_space + .lock() + .query(VirtAddr::from(addr)) + .map_err(|_| AlienError::EINVAL)?; + // + trace!( + "do store page fault:{:#x}, flags:{:?}, page_size:{:?}", + addr, + flags, + page_size + ); + if !flags.contains(MappingFlags::V) { + return self.invalid_page_solver(addr); + } + panic!("instruction page fault"); + } + + /// 用于处理数据页异常 + pub fn do_store_page_fault( + &mut self, + o_addr: usize, + ) -> AlienResult>, &'static mut [u8], u64)>> { + let addr = align_down_4k(o_addr); + let (phy, flags, page_size) = self + .address_space + .lock() + .query(VirtAddr::from(addr)) + .map_err(|_x| { + if self.need_wait < 5 { + self.need_wait += 1; + AlienError::EAGAIN + } else { + error!("do_store_page_fault panic :{:#x}", o_addr); + AlienError::ETMP + } + })?; + // .expect(format!("addr:{:#x}", addr).as_str()); + trace!( + "do store page fault:{:#x}, flags:{:?}, page_size:{:?}", + addr, + flags, + page_size + ); + if !flags.contains(MappingFlags::V) { + return self.invalid_page_solver(addr); + } + // if !flags.contains(MappingFlags::RSD) { + // return Ok(None); + // } + assert!( + flags.contains(MappingFlags::RSD), + "addr:{:#x} flags:{:?}", + o_addr, + flags + ); + // decrease the reference count + let mut flags = flags | "W".into(); + flags -= MappingFlags::RSD; + let new_phy = self + .address_space + .lock() + .modify_pte_flags(VirtAddr::from(addr), flags, true) + .unwrap(); + assert!(new_phy.is_some()); + // copy data + let src_ptr = phy.as_usize() as *const u8; + let dst_ptr = new_phy.unwrap().as_usize() as *mut u8; + unsafe { + core::ptr::copy(src_ptr, dst_ptr, usize::from(page_size)); + } + let mut frame_ref_manager = FRAME_REF_MANAGER.lock(); + for i in 0..usize::from(page_size) / FRAME_SIZE { + let t_phy = phy + i * FRAME_SIZE; + frame_ref_manager.dec_ref(t_phy.as_usize() >> FRAME_BITS); + } + Ok(None) + } +} + +impl Task { + /// 对进程的资源进行预回收,将会回收 trap 帧、子进程控制块列表、文件描述符表等资源。 + pub fn pre_recycle(&self) { + // recycle trap page + let trap_frame_ptr = self.trap_frame_ptr() as usize; + self.access_inner() + .address_space + .lock() + .unmap_region(VirtAddr::from(trap_frame_ptr), FRAME_SIZE) + .unwrap(); + let mut inner = self.inner.lock(); + // delete child process + inner.children.clear(); + let thread_number = inner.thread_number; + if thread_number == 0 { + let _ = inner.fd_table.lock().clear(); + drop(inner); + } + } + + /// 获取进程的 `clear_child_tid` 字段 + pub fn futex_wake(&self) -> usize { + self.access_inner().clear_child_tid + } + + /// 从 elf 文件中创建一个新的进程控制块,只会调用一次(即读取 init 进程的相关信息) + pub fn from_elf(name: &str, elf: &[u8]) -> Option { + let tid = TidHandle::new()?; + let pid = tid.0; + // 创建进程地址空间 + let mut args = vec![]; + let elf_info = build_elf_address_space(elf, &mut args, "/bin/init"); + if elf_info.is_err() { + return None; + } + let elf_info = elf_info.unwrap(); + let address_space = elf_info.address_space; + let k_stack = Stack::new(USER_KERNEL_STACK_SIZE / FRAME_SIZE)?; + let k_stack_top = k_stack.top(); + let stack_info = elf_info.stack_top - USER_STACK_SIZE..elf_info.stack_top; + let cwd = SYSTEM_ROOT_FS.get().unwrap().clone(); + + let process = Task { + tid, + kernel_stack: k_stack, + pid, + inner: Mutex::new(TaskInner { + name: name.to_string(), + threads: MinimalManager::new(MAX_THREAD_NUM), + thread_number: 0, + address_space: Arc::new(Mutex::new(address_space)), + state: TaskState::Ready, + parent: None, + children: Vec::new(), + fd_table: { + let mut fd_table = FdManager::new(MAX_FD_NUM); + fd_table.insert(STDIN.clone()).unwrap(); + fd_table.insert(STDOUT.clone()).unwrap(); + fd_table.insert(STDOUT.clone()).unwrap(); + Arc::new(Mutex::new(fd_table)) + }, + context: Context::new(trap_return as usize, k_stack_top), + fs_info: FsContext::new(cwd.clone(), cwd), + statistical_data: StatisticalData::new(), + timer: TaskTimer::default(), + exit_code: 0, + heap: Arc::new(Mutex::new(HeapInfo::new( + elf_info.heap_bottom, + elf_info.heap_bottom, + ))), + mmap: MMapInfo::new(), + signal_handlers: Arc::new(Mutex::new(SignalHandlers::new())), + signal_receivers: Arc::new(Mutex::new(SignalReceivers::new())), + set_child_tid: 0, + clear_child_tid: 0, + trap_cx_before_signal: None, + signal_set_siginfo: false, + robust: RobustList::default(), + shm: BTreeMap::new(), + cpu_affinity: { + let mut affinity = 0; + affinity.set_bits(0..CPU_NUM, 1 << CPU_NUM - 1); + affinity + }, + unmask: 0o022, + stack: stack_info, + need_wait: 0, + }), + send_sigchld_when_exit: false, + }; + let phy_button = process.transfer_raw(elf_info.stack_top - FRAME_SIZE); + let mut user_stack = UserStack::new(phy_button + FRAME_SIZE, elf_info.stack_top); + user_stack.push(0).unwrap(); + let argc_ptr = user_stack.push(0).unwrap(); + + let trap_frame = process.trap_frame(); + *trap_frame = TrapFrame::init_for_task( + elf_info.entry, + argc_ptr, + kernel_satp(), + process.kernel_stack.top(), + user_trap_vector as usize, + ); + trap_frame.regs()[4] = elf_info.tls; // tp --> tls + let res = Some(process); + res + } + + /// 产生一个新的子进程。 + /// + /// `flag`用于控制父子进程之间资源的共享程度,有关flag值及其相关含义设置可见[`CloneFlags`]。 + /// `stack`用于控制子进程的用户栈。由于clone产生的子进程有可能和父进程共享内存,所以它不能使用父进程的栈。 + /// `sig`用于控制子进程退出时传递给父进程的相关信号。目前Alien中的设计为当其值为`SIGCHLD`时,在子进程退出时会向父程序发送`SIGCHLD`信号。会其它有关值的设置可见[`SignalNumber`]。 + /// `ptid`是一个在父进程地址空间中的地址,用于在创建子进程成功后向该位置写入子进程的tid号。在flag包含`CLONE_PARENT_SETTID`时才会发挥效果。 + /// `tls`用于为子进程创建新的TLS(thread-local storage)值,在flag包含`CLONE_SETTLS`时才会实际产生效果。 + /// `ctid`用于给子进程中的[`set_child_tid`]和[`clear_child_tid`]赋值(分别在flag中包含`CLONE_CHILD_SETTID`和`CLONE_CHILD_CLEARTID`时产生效果)。 + /// + /// 成功创建子进程后父进程会返回子进程的TCB。 + /// + /// Note: 当传入的ptid未在父进程地址空间中被分配时,会引发panic。 + pub fn t_clone( + self: &Arc, + flag: CloneFlags, + stack: usize, + sig: SignalNumber, + ptid: usize, + tls: usize, + ctid: usize, + ) -> Option> { + warn!( + "clone: flag:{:?}, sig:{:?}, stack:{:#x}, ptid:{:#x}, tls:{:#x}, ctid:{:#x}", + flag, sig, stack, ptid, tls, ctid + ); + let tid = TidHandle::new()?; + let mut inner = self.inner.lock(); + let address_space = if flag.contains(CloneFlags::CLONE_VM) { + // to create thread + inner.address_space.clone() + } else { + // to create process + let address_space = + build_cow_address_space(&mut inner.address_space.lock(), inner.shm.clone()); + Arc::new(Mutex::new(address_space)) + }; + + let fd_table = if flag.contains(CloneFlags::CLONE_FILES) { + inner.fd_table.clone() + } else { + Arc::new(Mutex::new(inner.fd_table.lock().clone())) + }; + + let signal_handlers = if flag.contains(CloneFlags::CLONE_SIGHAND) { + inner.signal_handlers.clone() + } else { + Arc::new(Mutex::new(inner.signal_handlers.lock().clone())) + }; + + let parent = if flag.contains(CloneFlags::CLONE_PARENT) { + inner.parent.clone() + } else { + Some(Arc::downgrade(self)) + }; + + let k_stack = Stack::new(USER_KERNEL_STACK_SIZE / FRAME_SIZE)?; + let k_stack_top = k_stack.top(); + let pid = if flag.contains(CloneFlags::CLONE_THREAD) { + self.pid + } else { + tid.0 + }; + let signal_receivers = Arc::new(Mutex::new(SignalReceivers::new())); + // 注册线程-信号对应关系 + global_register_signals(tid.0, signal_receivers.clone()); + // map the thread trap_context if clone_vm + let (trap_context, thread_num) = if flag.contains(CloneFlags::CLONE_VM) { + let thread_num = inner.threads.insert(()).unwrap() + 1; + warn!("thread_num: {}", thread_num); + // calculate the address for thread context + let trap_context = build_thread_address_space(&mut address_space.lock(), thread_num); + (trap_context, thread_num) + } else { + let (physical, _, _) = address_space + .lock() + .query(VirtAddr::from(TRAP_CONTEXT_BASE)) + .unwrap(); + let trap_frame = TrapFrame::from_raw_ptr(physical.as_usize() as *mut TrapFrame); + (trap_frame, 0) + }; + + let heap = if flag.contains(CloneFlags::CLONE_VM) { + inner.heap.clone() + } else { + Arc::new(Mutex::new(inner.heap.lock().clone())) + }; + + // 设置内核栈地址 + trap_context.update_kernel_sp(k_stack_top); + + // 检查是否需要设置 tls + if flag.contains(CloneFlags::CLONE_SETTLS) { + trap_context.update_tp(tls); + } + + // 检查是否在父任务地址中写入 tid + if flag.contains(CloneFlags::CLONE_PARENT_SETTID) { + // 有可能这个地址是 lazy alloc 的,需要先检查 + let res = inner.address_space.lock().query(VirtAddr::from(ptid)); + if res.is_ok() { + let (physical, _, _) = res.unwrap(); + unsafe { + *(physical.as_usize() as *mut i32) = tid.0 as i32; + } + } else { + panic!("clone: ptid is not mapped") + } + } + + let ctid_value = if flag.contains(CloneFlags::CLONE_CHILD_SETTID) + || flag.contains(CloneFlags::CLONE_CHILD_CLEARTID) + { + tid.0 + } else { + 0 + }; + + if flag.contains(CloneFlags::CLONE_CHILD_SETTID) + || flag.contains(CloneFlags::CLONE_CHILD_CLEARTID) + { + // TODO!(may be not map when cow fork) + let (phy, ..) = address_space.lock().query(VirtAddr::from(ctid)).unwrap(); + unsafe { + *(phy.as_usize() as *mut i32) = ctid_value as i32; + } + } + if stack != 0 { + assert!(flag.contains(CloneFlags::CLONE_VM)); + // set the sp of the new process + trap_context.regs()[2] = stack; + } + + warn!("create task pid:{}, tid:{}", pid, tid.0); + let task = Task { + tid, + kernel_stack: k_stack, + pid, + inner: Mutex::new(TaskInner { + name: inner.name.clone(), + threads: MinimalManager::new(MAX_THREAD_NUM), + thread_number: thread_num, + address_space, + state: TaskState::Ready, + parent, + children: Vec::new(), + fd_table, + context: Context::new(trap_return as usize, k_stack_top), + fs_info: inner.fs_info.clone(), + statistical_data: StatisticalData::new(), + timer: TaskTimer::default(), + exit_code: 0, + heap, + mmap: inner.mmap.clone(), + signal_handlers, + signal_receivers, + set_child_tid: if flag.contains(CloneFlags::CLONE_CHILD_SETTID) { + ctid + } else { + 0 + }, + clear_child_tid: if flag.contains(CloneFlags::CLONE_CHILD_CLEARTID) { + ctid + } else { + 0 + }, + trap_cx_before_signal: None, + signal_set_siginfo: false, + robust: RobustList::default(), + shm: inner.shm.clone(), + cpu_affinity: { + let mut affinity = 0; + affinity.set_bits(0..CPU_NUM, 1 << CPU_NUM - 1); + affinity + }, + unmask: 0o022, + stack: inner.stack.clone(), + need_wait: 0, + }), + send_sigchld_when_exit: sig == SignalNumber::SIGCHLD, + }; + let task = Arc::new(task); + if !flag.contains(CloneFlags::CLONE_PARENT) { + inner.children.push(task.clone()); + } + error!("create a task success"); + Some(task) + } + + /// 用于执行一个可执行文件,供sys_exec调用。 + /// + /// `name`用于传入文件的路径和文件名。 + /// `elf_data`用于传入从对应文件处读入的文件数据,用于构造elf_info。 + /// `args`用于指明启动可执行文件时要传入的参数。 + /// `env`用于指明相关环境变量。 + /// + /// 成功执行则返回OK(());否则返回错误码(isize)。 + pub fn exec( + &self, + name: &str, + elf_data: &[u8], + args: Vec, + env: Vec, + ) -> Result<(), isize> { + let mut args = args; + let elf_info = build_elf_address_space(elf_data, &mut args, name); + if elf_info.is_err() { + return Err(-1); + } + let elf_info = elf_info.unwrap(); + let mut inner = self.inner.lock(); + assert_eq!(inner.thread_number, 0); + let name = elf_info.name; + let address_space = elf_info.address_space; + // reset the address space + inner.address_space = Arc::new(Mutex::new(address_space)); + // reset the heap + inner.heap = Arc::new(Mutex::new(HeapInfo::new( + elf_info.heap_bottom, + elf_info.heap_bottom, + ))); + // reset the mmap + inner.mmap = MMapInfo::new(); + // set the name of the process + inner.name = name.to_string(); + // reset time record + inner.statistical_data.clear(); + // close file which contains FD_CLOEXEC flag + // now we delete all fd + // inner.fd_table = + // reset signal handler + inner.signal_handlers.lock().clear(); + inner.signal_receivers.lock().clear(); + inner.timer.clear(); + inner.stack = elf_info.stack_top - USER_STACK_SIZE..elf_info.stack_top; + let env = if env.is_empty() { + let envp = vec![ + "LD_LIBRARY_PATH=/", + "PS1=\x1b[1m\x1b[32mAlien\x1b[0m:\x1b[1m\x1b[34m\\w\x1b[0m\\$ \0", + "PATH=/bin:/usr/bin", + "UB_BINDIR=./", + ] + .iter() + .map(|x| x.to_string()) + .collect::>(); + envp + } else { + env + }; + // we need make sure the args and env size is less than 4KB + let phy_button = inner.transfer_raw(elf_info.stack_top - FRAME_SIZE); + let mut user_stack = UserStack::new(phy_button + FRAME_SIZE, elf_info.stack_top); + // push env to the top of stack of the process + // we have push '\0' into the env string,so we don't need to push it again + let envv = env + .iter() + .rev() + .map(|env| user_stack.push_str(env).unwrap()) + .collect::>(); + // push the args to the top of stack of the process + // we have push '\0' into the arg string,so we don't need to push it again + let argcv = args + .iter() + .rev() + .map(|arg| user_stack.push_str(arg).unwrap()) + .collect::>(); + // push padding to the top of stack of the process + user_stack.align_to(8).unwrap(); + let random_ptr = user_stack.push_bytes(&[0u8; 16]).unwrap(); + // padding + user_stack.push_bytes(&[0u8; 8]).unwrap(); + // push aux + let platform = user_stack.push_str("riscv").unwrap(); + + let ex_path = user_stack.push_str(&name).unwrap(); + user_stack.push(0).unwrap(); + user_stack.push(platform).unwrap(); + user_stack.push(AT_PLATFORM).unwrap(); + user_stack.push(ex_path).unwrap(); + user_stack.push(AT_EXECFN).unwrap(); + user_stack.push(elf_info.ph_num).unwrap(); + user_stack.push(AT_PHNUM).unwrap(); + user_stack.push(FRAME_SIZE).unwrap(); + user_stack.push(AT_PAGESZ).unwrap(); + + user_stack.push(elf_info.bias).unwrap(); + user_stack.push(AT_BASE).unwrap(); + user_stack.push(elf_info.entry).unwrap(); + user_stack.push(AT_ENTRY).unwrap(); + user_stack.push(elf_info.ph_entry_size).unwrap(); + user_stack.push(AT_PHENT).unwrap(); + user_stack.push(elf_info.ph_drift).unwrap(); + user_stack.push(AT_PHDR).unwrap(); + user_stack.push(0).unwrap(); + user_stack.push(AT_GID).unwrap(); + user_stack.push(0).unwrap(); + user_stack.push(AT_EGID).unwrap(); + user_stack.push(0).unwrap(); + user_stack.push(AT_UID).unwrap(); + user_stack.push(0).unwrap(); + user_stack.push(AT_EUID).unwrap(); + user_stack.push(0).unwrap(); + user_stack.push(AT_SECURE).unwrap(); + user_stack.push(random_ptr).unwrap(); + user_stack.push(AT_RANDOM).unwrap(); + + user_stack.push(0).unwrap(); + // push the env addr to the top of stack of the process + envv.iter().for_each(|env| { + user_stack.push(*env).unwrap(); + }); + user_stack.push(0).unwrap(); + // push the args addr to the top of stack of the process + argcv.iter().enumerate().for_each(|(_i, arg)| { + user_stack.push(*arg).unwrap(); + }); + // push the argc to the top of stack of the process + let argc = args.len(); + let argc_ptr = user_stack.push(argc).unwrap(); + let user_sp = argc_ptr; + warn!("args:{:?}, env:{:?}, user_sp: {:#x}", args, env, user_sp); + let (physical, _, _) = inner + .address_space + .lock() + .query(VirtAddr::from(TRAP_CONTEXT_BASE)) + .unwrap(); + let trap_frame = TrapFrame::from_raw_ptr(physical.as_usize() as *mut TrapFrame); + *trap_frame = TrapFrame::init_for_task( + elf_info.entry, + user_sp, + kernel_satp(), + self.kernel_stack.top(), + user_trap_vector as usize, + ); + trap_frame.regs()[4] = elf_info.tls; // tp --> tls + Ok(()) + } +} diff --git a/kkernel/src/time.rs b/kkernel/src/time.rs new file mode 100644 index 00000000..cc343bdd --- /dev/null +++ b/kkernel/src/time.rs @@ -0,0 +1,269 @@ +//! Alien 中的有关时钟、计时器的结构 以及 一些计时器的系统调用。 +//! +//! 在对系统时间的记录上,Alien 中使用 [`TimeVal`] 记录 (秒,微秒) 的时间,使用 [`TimeSpec`] 记录 更精细的 (秒,纳秒) 的时间; +//! 在对进程的运行时间的记录上,使用 [`Times`] 结构记录进程运行的时间,记录的信息包括程序在用户态、内核态下分别运行的时间, +//! 其子进程运行的总时间等,在任务控制块中记录相应数据的结构为 [`StatisticalData`]。 +//! +//! 计时器方面, [`Timer`] 结构为实际放入计时器队列 [`TIMER_QUEUE`] 中的计时器结构。 +//! 当发生时钟中断时,会检查所有计时器队列中的计时器是否超时,具体可见 [`check_timer_queue`]。 +//! [`ITimerVal`] 结构为系统调用 [`getitimer`] / [`setitimer`] 指定的类型,用户执行系统调用时获取和输入时需要为该种类型的计时器, +//! 在任务控制块中记录相应数据的字段为 `timer`(结构为 `TaskTimer` )。 +//! +//! 对于时间片 (每次引发时钟中断的时间间隔) 大小的设计:目前 Alien 中用户态和内核态下采用相同的时间片间隔,1s 内触发 10 次时钟中断。 +use log::{info, warn}; +use crate::task::{current_task, do_suspend, StatisticalData}; +use constants::sys::TimeVal; +use constants::time::{ClockId, TimerType}; +use constants::LinuxErrno; +use syscall_table::syscall_func; +use platform::config::CLOCK_FREQ; +use platform::set_timer; +use timer::{ITimerVal, read_timer, TimeNow, Times, TimeSpec}; + +/// 每秒包含的 时间片 数,每隔一个时间片,就会产生一个时钟中断 +const TICKS_PER_SEC: usize = 10; +// const TICKS_PER_SEC_IN_KERNEL: usize = 1000; + + +/// 设置下一次时钟的中断 +#[inline] +pub fn set_next_trigger() { + let next = read_timer() + CLOCK_FREQ / TICKS_PER_SEC; + assert!(next > read_timer()); + set_timer(next); +} + +/// 设置内核态中下一次时钟的中断 +/// +/// 原设计为内核态下的时间片设置的更短一些,以免一个进程在进入内核态前后占用过多的时间片。但目前修改为 内核态和用户态下的时间片大小相同。 +#[inline] +pub fn set_next_trigger_in_kernel() { + let next = read_timer() + CLOCK_FREQ / TICKS_PER_SEC; + assert!(next > read_timer()); + set_timer(next); +} + + +/// 一个系统调用函数,获取当前的时间,获取的时间将存储在`tv`所指向的[`TimeVal`]结构处。 +/// 执行成功则返回0。 +/// +/// Reference: [get_time_of_day](https://man7.org/linux/man-pages/man2/gettimeofday.2.html) +#[syscall_func(169)] +pub fn get_time_of_day(tv: *mut u8) -> isize { + let time = TimeVal::now(); + let process = current_task().unwrap(); + let tv = process.transfer_raw_ptr(tv as *mut TimeVal); + *tv = time; + 0 +} + +/// 一个系统调用函数,获取当前进程在用户态/内核态下运行的时间、最后一次运行在用户态/内核态下的时间等, +/// 获取的信息将保存在`tms`所指向的[`Times`]结构处。执行成功返回0。 +/// +/// Reference: [times](https://man7.org/linux/man-pages/man2/times.2.html) +#[syscall_func(153)] +pub fn times(tms: *mut u8) -> isize { + let mut task = current_task().unwrap().access_inner(); + let statistic_data = task.statistical_data(); + let time = times_from_process_data(statistic_data); + task.copy_to_user(&time, tms as *mut Times); + 0 +} + + + +/// 从一个 [`StatisticalData`] 结构 (一般为 task 的 statistical_data 字段) 得到一个 `Times` 变量 +pub fn times_from_process_data(data: &StatisticalData) -> Times { + Times { + tms_stime: data.tms_stime, + tms_utime: data.tms_utime, + tms_cstime: data.tms_cstime, + tms_cutime: data.tms_cutime, + } +} + +/// 一个系统调用函数,暂停本进程直到一段时间后结束,要暂停的时间将保存在`req`所指向的[`TimeSpec`]结构处。 +/// 但在`nanosleep`执行过程中,本进程有可能被其他信号唤醒。 +/// 函数若正常停止`req`时间则返回0;如果由于因为其他信号而被唤醒,此时函数返回-1(EINTR)。 +/// +/// Reference: [nanosleep](https://man7.org/linux/man-pages/man2/nanosleep.2.html) +#[syscall_func(101)] +pub fn nanosleep(req: *mut u8, _: *mut u8) -> isize { + let task = current_task().unwrap().clone(); + let mut time = TimeSpec::new(0, 0); + task.access_inner() + .copy_from_user(req as *const TimeSpec, &mut time); + warn!("nanosleep: {:?}", time); + let end_time = read_timer() + time.to_clock(); + loop { + if read_timer() >= end_time { + break; + } + do_suspend(); + // interrupt by signal + let task_inner = task.access_inner(); + let receiver = task_inner.signal_receivers.lock(); + if receiver.have_signal() { + return LinuxErrno::EINTR as isize; + } + } + 0 +} + +/// 一个系统调用函数,可以根据输入的时钟类型`clock_id`来获取当前的时间,获取的时间将存储在`tp`所指向的[`TimeSpec`]结构处。 +/// +/// 目前仅支持`Monotonic`、`Realtime`和`ProcessCputimeId`三种时钟类型,均会返回当前的系统时间。 +/// 执行成功则返回0;当所输入的`clock_id`不在`Monotonic`、`Realtime`和`ProcessCputimeId`中时,进程将会被panic。 +/// +/// Reference: [clock_get_time](https://www.man7.org/linux/man-pages/man3/clock_gettime.3.html) +#[syscall_func(113)] +pub fn clock_get_time(clock_id: usize, tp: *mut u8) -> isize { + let id = ClockId::from_raw(clock_id).unwrap(); + let task = current_task().unwrap(); + match id { + ClockId::Monotonic | ClockId::Realtime | ClockId::ProcessCputimeId => { + let time = TimeSpec::now(); + task.access_inner().copy_to_user(&time, tp as *mut TimeSpec) + } + _ => { + panic!("clock_get_time: clock_id {:?} not supported", id); + } + } + 0 +} + + + + + + + + + +/// 当发生时钟中断时,`trap_handler` 会调用该函数检查所有计时器队列中的计时器,并唤醒等待在这些计时器上的进程 +/// +/// 遍历所有计时器队列 [`TIMER_QUEUE`] 中的计时器,若计时器的超时时间在当前时间之前(即已超时),那么将该等待的进程加入 +/// 线程池的首位,马上对其进行调度。 +pub fn check_timer_queue() {} + +/// 一个系统调用函数,用于获取当前进程的计时器,保存在`current_value`指向的[`ITimerVal`]结构处。 +/// 由于Alien目前每个进程只支持一个计时器,原定于分辨计时器种类的`_which`在此处并没有派上用场。 +/// 函数执行成功则返回0。 +/// Reference: [getitimer](https://man7.org/linux/man-pages/man2/setitimer.2.html) +#[syscall_func(102)] +pub fn getitimer(_which: usize, current_value: usize) -> isize { + let task = current_task().unwrap(); + let timer = &task.access_inner().timer; + let itimer = ITimerVal { + it_interval: timer.timer_interval, + it_value: timer.timer_remained.into(), + }; + task.access_inner() + .copy_to_user(&itimer, current_value as *mut ITimerVal); + 0 +} + +/// 一个系统调用函数,用于将当前进程的定时器设置为`current_value`指向的[`ITimerVal`]结构处, +/// 同时将旧计时器的信息保存在`old_value`指向的[`ITimerVal`]结构处。 +/// +/// `which`参数需为目前支持的[`TimerType`]类型且不为`NONE`,否则会导致进程被panic。 +/// 如果`current_value`为空,则会导致进程被panic。 +/// 如果`old_value`为空,则不进行保存旧计时器信息操作。 +/// +/// 函数执行正确则返回0。 +/// Reference: [setitimer](https://man7.org/linux/man-pages/man2/setitimer.2.html) +#[syscall_func(103)] +pub fn setitimer(which: usize, current_value: usize, old_value: usize) -> isize { + let which = TimerType::try_from(which).unwrap(); + assert_ne!(which, TimerType::NONE); + info!( + "setitimer: which {:?} ,curret_value {:#x}, old_value {:#x}", + which, current_value, old_value + ); + let task = current_task().unwrap(); + if old_value != 0 { + let timer = task.access_inner().get_timer(); + let itimer = ITimerVal { + it_interval: timer.timer_interval.into(), + it_value: timer.timer_remained.into(), + }; + task.access_inner() + .copy_to_user(&itimer, old_value as *mut ITimerVal); + } + assert_ne!(current_value, 0); + let mut itimer = ITimerVal::default(); + task.access_inner() + .copy_from_user(current_value as *const ITimerVal, &mut itimer); + info!("setitimer: itimer {:x?}", itimer); + task.access_inner().set_timer(itimer, which); + 0 +} + +/// 一个系统调用函数,可以根据输入的时钟类型`clock_id`来获取该时钟分辨率(精度),获取的精度将存储在`res`所指向的[`TimeSpec`]结构处。 +/// 时钟的分辨率取决于实现方式,无法由特定进程配置。目前Alien仅支持`Monotonic`一种时钟类型。 +/// +/// Reference: [clock_getres](https://www.man7.org/linux/man-pages/man3/clock_getres.3.html) +#[syscall_func(114)] +pub fn clock_getres(id: usize, res: usize) -> isize { + let id = ClockId::from_raw(id).unwrap(); + info!("clock_getres: id {:?} ,res {:#x}", id, res); + let task = current_task().unwrap(); + let time_res = match id { + ClockId::Monotonic => { + let time = TimeSpec::new(0, 1); + time + } + _ => { + panic!("clock_get_time: clock_id {:?} not supported", id); + } + }; + task.access_inner() + .copy_to_user(&time_res, res as *mut TimeSpec); + 0 +} + +/// 一个系统调用函数,如`nanosleep`一样,暂停本进程直到一段时间后结束,但`clock_nanosleep`可以根据传入的`clock_id`来指定使用的时钟类型。 +/// +/// 要暂停的时间将保存在`req`所指向的[`TimeSpec`]结构处。目前仅支持`Monotonic`,输入其它时钟类型将会返回使得进程panic。 +/// 如`nanosleep`一样,在`clock_nanosleep`执行过程中,本进程也有可能被其他信号唤醒。 +/// +/// 函数若正常停止`req`时间则返回0;如果由于因为其他信号而被唤醒,此时函数返回-1(EINTR)。 +/// +/// Reference: [times](https://man7.org/linux/man-pages/man2/times.2.html) +#[syscall_func(115)] +pub fn clock_nanosleep(clock_id: usize, flags: usize, req: usize, remain: usize) -> isize { + const TIMER_ABSTIME: usize = 1; + let id = ClockId::from_raw(clock_id).unwrap(); + info!( + "clock_nanosleep: id {:?} ,flags {:#x}, req {:#x}, remain {:#x}", + id, flags, req, remain + ); + match id { + ClockId::Monotonic => { + assert_eq!(flags, TIMER_ABSTIME); + let mut target_time = TimeSpec::new(0, 0); + let task = current_task().unwrap().clone(); + task.access_inner() + .copy_from_user(req as *const TimeSpec, &mut target_time); + let end_time = target_time.to_clock(); + + loop { + let now = read_timer(); + if now >= end_time { + break; + } + do_suspend(); + // check signal + let task_inner = task.access_inner(); + let receiver = task_inner.signal_receivers.lock(); + if receiver.have_signal() { + return LinuxErrno::EINTR.into(); + } + } + } + _ => { + panic!("clock_nanotime: clock_id {:?} not supported", id); + } + } + 0 +} diff --git a/kkernel/src/trap/context.rs b/kkernel/src/trap/context.rs new file mode 100644 index 00000000..5cf2bb4d --- /dev/null +++ b/kkernel/src/trap/context.rs @@ -0,0 +1,102 @@ +//! Trap 上下文 (Trap帧) 的定义和相关操作 +use arch::ExtSstatus; +use riscv::register::sstatus::SPP; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct TrapFrame { + /// 整数寄存器组 + x: [usize; 32], + /// sepc 记录陷入地址 + sepc: usize, + /// k_satp 记录内核根页表地址 + k_satp: usize, + /// k_sp记录task内核栈地址 + k_sp: usize, + /// 记录trap处理的地址 + trap_handler: usize, + /// 记录所在的核 + hart_id: usize, + /// 给出 Trap 发生之前 CPU 处在哪个特权级等信息 + sstatus: ExtSstatus, + fg: [usize; 2], +} + +impl TrapFrame { + /// 获取当前的 Trap 帧下的 sstatus 寄存器的值 + pub fn get_status(&self) -> ExtSstatus { + self.sstatus + } + + /// 用于在收到外部中断时,需要将程序计数器 pc + 4 (下一条指令位置加4个字节) + pub fn update_sepc(&mut self) { + self.sepc += 4; + } + + pub fn from_raw_ptr(ptr: *mut TrapFrame) -> &'static mut Self { + unsafe { &mut *(ptr) } + } + + /// 更新 Trap 帧中的内核栈地址 + pub fn update_kernel_sp(&mut self, val: usize) { + self.k_sp = val; + } + + /// 返回 Trap 帧中的 sepc + pub fn sepc(&self) -> usize { + self.sepc + } + + /// 设置 Trap 帧中的 sepc + pub fn set_sepc(&mut self, val: usize) { + self.sepc = val; + } + + /// 用一个从文件系统中读取到的相关app数据,初始化一个 Trap 帧,使通过其创建的进程在初次进入用户态时能正常运行 + pub fn init_for_task( + entry: usize, + sp: usize, + k_satp: usize, + k_sp: usize, + trap_handler: usize, + ) -> Self { + let mut sstatus = ExtSstatus::read(); + sstatus.set_spie(); + // assert!(sstatus.0.get_bit(5)); //spie == 1 + sstatus.set_spp(SPP::User); + sstatus.set_sie(false); + let mut res = Self { + x: [0; 32], + sepc: entry, + k_satp, + k_sp, + trap_handler, + hart_id: 0, + sstatus, + fg: [0; 2], + }; + res.x[2] = sp; + res + } + + /// 更新 Trap 帧中 x[10] (即函数返回值) 的值 + pub fn update_res(&mut self, val: usize) { + self.x[10] = val; + } + + /// 更新 Trap 帧中 x[4] (tp) 的值 + pub fn update_tp(&mut self, val: usize) { + self.x[4] = val; + } + + /// 获取系统调用的参数,一般用于发生 trap 的原因是系统调用时 + pub fn parameters(&self) -> [usize; 7] { + [ + self.x[17], self.x[10], self.x[11], self.x[12], self.x[13], self.x[14], self.x[15], + ] + } + /// 获取整数寄存器组的可变引用 + pub fn regs(&mut self) -> &mut [usize] { + &mut self.x + } +} diff --git a/kkernel/src/trap/exception.rs b/kkernel/src/trap/exception.rs new file mode 100644 index 00000000..bda11334 --- /dev/null +++ b/kkernel/src/trap/exception.rs @@ -0,0 +1,158 @@ +//! Alien 中对于内部异常的处理 +//! +//! 目前包括系统调用异常处理 [`syscall_exception_handler`]、页错误异常处理 [`page_exception_handler`] (包括 +//! 指令页错误异常处理 [`instruction_page_fault_exception_handler`]、 加载页错误异常处理[`load_page_fault_exception_handler`]、 +//! 储存页错误异常处理 [`store_page_fault_exception_handler`]) 和 文件读入异常处理 [`trap_common_read_file`]。 +use crate::fs::file::File; +use crate::task::{current_task, current_trap_frame}; +use alloc::sync::Arc; +use arch::interrupt_enable; +use constants::{AlienError, AlienResult}; +use riscv::register::scause::{Exception, Trap}; + +/// 系统调用异常处理 +pub fn syscall_exception_handler() { + // enable interrupt + interrupt_enable(); + // jump to next instruction anyway + let mut cx = current_trap_frame(); + cx.update_sepc(); + // get system call return value + let parameters = cx.parameters(); + let syscall_name = constants::syscall_name(parameters[0]); + + let task = current_task().unwrap(); + let p_name = task.get_name(); + let tid = task.get_tid(); + let pid = task.get_pid(); + if !p_name.contains("shell") && !p_name.contains("init") && !p_name.contains("ls") { + // ignore shell and init + info!( + "[pid:{}, tid: {}][p_name: {}] syscall: [{}] {}({:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x})", + pid, + tid, + p_name, + parameters[0], + syscall_name, + parameters[1], + parameters[2], + parameters[3], + parameters[4], + parameters[5], + parameters[6] + ); + } + + let result = invoke_call_id!( + parameters[0], + parameters[1], + parameters[2], + parameters[3], + parameters[4], + parameters[5], + parameters[6] + ); + let result = Some(result); + // cx is changed during sys_exec, so we have to call it again + cx = current_trap_frame(); + + if !p_name.contains("shell") && !p_name.contains("init") && !p_name.contains("ls") { + info!( + "[pid:{}, tid: {}] syscall: [{}] result: {:?}, tp: {:#x}", + pid, + tid, + syscall_name, + result, + cx.regs()[4] + ); + } + cx.update_res(result.unwrap() as usize); +} + +/// 页异常处理,会根据不同的异常类型,分发至指令页错误异常处理 [`instruction_page_fault_exception_handler`]、 +/// 加载页错误异常处理 [`load_page_fault_exception_handler`]、 +/// 储存页错误异常处理 [`store_page_fault_exception_handler`] 等处理方案中。 +pub fn page_exception_handler(trap: Trap, addr: usize) -> AlienResult<()> { + trace!( + "[pid: {}] page fault addr:{:#x} trap:{:?}", + current_task().unwrap().get_pid(), + addr, + trap + ); + match trap { + Trap::Exception(Exception::LoadPageFault) => load_page_fault_exception_handler(addr)?, + Trap::Exception(Exception::StorePageFault) => store_page_fault_exception_handler(addr)?, + Trap::Exception(Exception::InstructionPageFault) => { + instruction_page_fault_exception_handler(addr)? + } + _ => { + return Err(AlienError::ENOSYS); + } + } + Ok(()) +} + +/// 指令页错误异常处理 +pub fn instruction_page_fault_exception_handler(addr: usize) -> AlienResult<()> { + let task = current_task().unwrap(); + trace!( + "[tid: {}] do instruction_page_fault addr:{:#x}", + task.get_tid(), + addr + ); + let res = task.access_inner().do_instruction_page_fault(addr)?; + if res.is_some() { + let (file, buf, offset) = res.unwrap(); + if file.is_some() { + trap_common_read_file(file.unwrap(), buf, offset); + } + } + Ok(()) +} + +/// 加载页错误异常处理 +pub fn load_page_fault_exception_handler(addr: usize) -> AlienResult<()> { + let info = { + let process = current_task().unwrap(); + process.access_inner().do_load_page_fault(addr)? + }; + if info.is_some() { + let (file, buf, offset) = info.unwrap(); + if file.is_some() { + trap_common_read_file(file.unwrap(), buf, offset); + } + } + Ok(()) +} + +/// 储存页错误异常处理 +pub fn store_page_fault_exception_handler(addr: usize) -> AlienResult<()> { + let process = current_task().unwrap(); + trace!( + "[tid: {}] do store page fault addr:{:#x}", + process.get_tid(), + addr + ); + let res = process.access_inner().do_store_page_fault(addr)?; + if res.is_some() { + let (file, buf, offset) = res.unwrap(); + if file.is_some() { + trap_common_read_file(file.unwrap(), buf, offset); + } + } + Ok(()) +} + +/// 文件读入异常处理 +pub fn trap_common_read_file(file: Arc, buf: &mut [u8], offset: u64) { + info!( + "trap_common_read_file buf.len: {}, offset:{:#x}", + buf.len(), + offset + ); + // let r = vfs_read_file::(file.get_file(), buf, offset); + let r = file.read_at(offset, buf); + if r.is_err() { + info!("page fault: read file error"); + } +} diff --git a/kkernel/src/trap/interrupt.rs b/kkernel/src/trap/interrupt.rs new file mode 100644 index 00000000..82934756 --- /dev/null +++ b/kkernel/src/trap/interrupt.rs @@ -0,0 +1,16 @@ +//! Alien 的外部中断处理 +//! +//! 目前仅有时钟中断处理函数。 +use interrupt::record::write_irq_info; +use crate::ipc::solve_futex_wait; +use crate::task::do_suspend; +use crate::time::{check_timer_queue, set_next_trigger}; + +/// 时钟中断处理函数 +pub fn timer_interrupt_handler() { + write_irq_info(1); + check_timer_queue(); + solve_futex_wait(); + set_next_trigger(); + do_suspend(); +} diff --git a/kkernel/src/trap/kernel_v.asm b/kkernel/src/trap/kernel_v.asm new file mode 100644 index 00000000..b334e184 --- /dev/null +++ b/kkernel/src/trap/kernel_v.asm @@ -0,0 +1,47 @@ +.attribute arch, "rv64gc" +.altmacro +.macro KSAVE_GP n + sd x\n, \n*8(sp) +.endm +.macro KLOAD_GP n + ld x\n, \n*8(sp) +.endm + + +.section .text +.globl kernel_v +.align 3 +kernel_v: + addi sp, sp, -34*8 + sd x1, 1*8(sp) + sd x3, 3*8(sp) + sd x4, 4*8(sp) + .set n, 5 + .rept 27 + KSAVE_GP %n + .set n, n+1 + .endr + csrr t0, sstatus + csrr t1, sepc + sd t0, 32*8(sp) + sd t1, 33*8(sp) + mv a0, sp + # call the C trap handler in trap.c + csrr t2, sscratch + jalr t2 + + + ld t0, 32*8(sp) + ld t1, 33*8(sp) + csrw sstatus, t0 + csrw sepc, t1 + ld x1, 1*8(sp) + ld x3, 3*8(sp) + ld x4, 4*8(sp) + .set n, 5 + .rept 27 + KLOAD_GP %n + .set n, n+1 + .endr + addi sp, sp, 34*8 + sret diff --git a/kkernel/src/trap/mod.rs b/kkernel/src/trap/mod.rs new file mode 100644 index 00000000..5a350300 --- /dev/null +++ b/kkernel/src/trap/mod.rs @@ -0,0 +1,309 @@ +use core::arch::{asm, global_asm}; +use bit_field::BitField; +use riscv::register::sstatus::SPP; +use riscv::register::{sepc, sscratch, sstatus, stval, stvec}; + +use constants::signal::SignalNumber; +use constants::signal::SIGNAL_RETURN_TRAP; +use constants::time::TimerType; +pub use context::TrapFrame; +pub use exception::trap_common_read_file; + +use config::TRAMPOLINE; +use ::interrupt::external_interrupt_handler; +use ::interrupt::record::write_irq_info; +use crate::ipc::{send_signal, signal_handler, signal_return, solve_futex_wait}; +use crate::task::{current_task, current_trap_frame, current_user_token, do_exit, do_suspend}; +use crate::time::{check_timer_queue, set_next_trigger, set_next_trigger_in_kernel}; +use arch::{ + external_interrupt_enable, interrupt_disable, interrupt_enable, is_interrupt_enable, + timer_interrupt_enable, +}; +use constants::AlienError; +use riscv::register::scause::{Exception, Interrupt, Trap}; +use riscv::register::stvec::TrapMode; + +mod context; +mod exception; +mod interrupt; + +global_asm!(include_str!("./kernel_v.asm")); +global_asm!(include_str!("./trampoline.asm")); + +extern "C" { + fn kernel_v(); + fn user_v(); + fn user_r(); +} + +#[no_mangle] +/// set the new addr of __restore asm function in TRAMPOLINE page, +/// set the reg a0 = trap_cx_ptr, reg a1 = phy addr of usr page table, +/// finally, jump to new addr of __restore asm function +pub fn trap_return() -> ! { + check_timer_interrupt_pending(); + signal_handler(); + interrupt_disable(); + set_user_trap_entry(); + let trap_frame = current_trap_frame(); + let sstatues = trap_frame.get_status(); + let enable = sstatues.0.get_bit(5); + let sie = sstatues.0.get_bit(1); + assert!(enable); + assert!(!sie); + + let trap_cx_ptr = current_task().unwrap().trap_frame_ptr(); + let user_satp = current_user_token(); + let restore_va = user_r as usize - user_v as usize + TRAMPOLINE; + unsafe { + asm!( + "fence.i", + "jr {restore_va}", + restore_va = in(reg) restore_va, + in("a0") trap_cx_ptr, + in("a1") user_satp, + options(noreturn) + ) + } +} + +/// 设置用户态 trap 处理例程的入口点 +#[inline] +fn set_user_trap_entry() { + unsafe { + stvec::write(TRAMPOLINE, TrapMode::Direct); + } +} + +/// 设置内核态 trap 处理例程的入口点 +#[inline] +pub fn set_kernel_trap_entry() { + unsafe { + sscratch::write(kernel_trap_vector as usize); + stvec::write(kernel_v as usize, TrapMode::Direct); + } +} + +/// 开启中断/异常 +pub fn init_trap_subsystem() { + println!("++++ setup interrupt ++++"); + set_kernel_trap_entry(); + external_interrupt_enable(); + timer_interrupt_enable(); + interrupt_enable(); + let enable = is_interrupt_enable(); + println!("++++ setup interrupt done, enable:{:?} ++++", enable); +} + +pub trait TrapHandler { + fn do_user_handle(&self); + fn do_kernel_handle(&self, sp: usize); +} + +impl TrapHandler for Trap { + /// 用户态下的 trap 例程 + fn do_user_handle(&self) { + let stval = stval::read(); + let sepc = sepc::read(); + trace!("trap :{:?}", self); + match self { + Trap::Exception(Exception::UserEnvCall) => { + exception::syscall_exception_handler(); + } + Trap::Exception(Exception::StoreFault) + | Trap::Exception(Exception::LoadFault) + | Trap::Exception(Exception::InstructionFault) + | Trap::Exception(Exception::IllegalInstruction) => { + error!( + "[User] {:?} in application,stval:{:#x?} sepc:{:#x?}", + self, stval, sepc + ); + let task = current_task().unwrap(); + send_signal(task.get_tid() as usize, SignalNumber::SIGSEGV as usize) + } + Trap::Exception(Exception::StorePageFault) + | Trap::Exception(Exception::LoadPageFault) => { + let task = current_task().unwrap(); + let tid = task.get_tid(); + warn!( + "[User][tid:{}] {:?} in application,stval:{:#x?} sepc:{:#x?}", + tid, self, stval, sepc + ); + let res = exception::page_exception_handler(self.clone(), stval); + if res.is_err() { + error!( + "[User] {:?} in application,stval:{:#x?} sepc:{:#x?}", + self, stval, sepc + ); + let err = res.err().unwrap(); + if err == AlienError::EAGAIN { + // println!("thread need wait"); + do_suspend(); + } else if err == AlienError::ETMP { + do_exit(-1); + } else { + send_signal(tid as usize, SignalNumber::SIGSEGV as usize) + } + } + } + Trap::Exception(Exception::InstructionPageFault) => { + trace!( + "[User] {:?} in application,stval:{:#x?} sepc:{:#x?}", + self, + stval, + sepc + ); + if stval == SIGNAL_RETURN_TRAP { + // 当作调用了 sigreturn 一样 + let cx = current_trap_frame(); + cx.regs()[10] = signal_return() as usize; + return; + } + + let res = exception::page_exception_handler(self.clone(), stval); + if res.is_err() { + error!( + "[User] {:?} in application,stval:{:#x?} sepc:{:#x?}", + self, stval, sepc + ); + let task = current_task().unwrap(); + send_signal(task.get_tid() as usize, SignalNumber::SIGSEGV as usize) + } + } + Trap::Interrupt(Interrupt::SupervisorTimer) => { + trace!("[User] timer interrupt"); + interrupt::timer_interrupt_handler(); + } + Trap::Interrupt(Interrupt::SupervisorExternal) => { + trace!("external interrupt"); + external_interrupt_handler(); + } + _ => { + panic!( + "unhandled trap: {:?}, stval: {:?}, sepc: {:x}", + self, stval, sepc + ); + } + } + } + + /// 内核态下的 trap 例程 + fn do_kernel_handle(&self, sp: usize) { + let stval = stval::read(); + let sepc = sepc::read(); + match self { + Trap::Interrupt(Interrupt::SupervisorTimer) => { + trace!("[kernel] timer interrupt"); + write_irq_info(1); + check_timer_queue(); + solve_futex_wait(); + // set_next_trigger(); + set_next_trigger_in_kernel(); + } + Trap::Exception(Exception::StorePageFault) => { + debug!( + "[kernel] {:?} in kernel, stval:{:#x?} sepc:{:#x?}", + self, stval, sepc + ); + { + // let kernel_space = KERNEL_SPACE.read(); + // let phy = kernel_space.query(VirtAddr::from(stval)); + let phy = mem::query_kernel_space(stval); + debug!("physical address: {:#x?}", phy); + } + } + Trap::Exception(_) => { + panic!( + "unhandled trap: {:?}, stval: {:#x?}, sepc: {:#x}, sp: {:#x}", + self, stval, sepc, sp + ) + } + Trap::Interrupt(Interrupt::SupervisorExternal) => { + external_interrupt_handler(); + } + _ => { + panic!( + "unhandled trap: {:?}, stval: {:?}, sepc: {:x}", + self, stval, sepc + ) + } + } + // check timer interrupt + check_timer_interrupt_pending(); + } +} + +/// 检查时钟中断是否被屏蔽 +pub fn check_timer_interrupt_pending() { + let sip = riscv::register::sip::read(); + if sip.stimer() { + debug!("timer interrupt pending"); + set_next_trigger(); + } + let sie = riscv::register::sie::read(); + if !sie.stimer() { + panic!("[check_timer_interrupt_pending] timer interrupt not enable"); + } +} + +/// 用户态陷入处理 +#[no_mangle] +pub fn user_trap_vector() { + let sstatus = sstatus::read(); + let spp = sstatus.spp(); + if spp == SPP::Supervisor { + panic!("user_trap_vector: spp == SPP::Supervisor"); + } + { + let task = current_task().expect("user_trap_vector: current_task is none"); + // update process statistics + task.access_inner().update_user_mode_time(); + check_task_timer_expired(); + } + set_kernel_trap_entry(); + let cause = riscv::register::scause::read(); + let cause = cause.cause(); + cause.do_user_handle(); + let task = current_task().unwrap(); + if cause != Trap::Interrupt(Interrupt::SupervisorTimer) { + // update process statistics + task.access_inner().update_kernel_mode_time(); + } + task.access_inner().update_timer(); + check_task_timer_expired(); + trap_return(); +} + +/// 用于检查进程的计时器是否超时。如果超时则会重置计时器,并按照计时器类型向进程发送信号。 +pub fn check_task_timer_expired() { + let task = current_task().unwrap(); + let timer_expired = task.access_inner().check_timer_expired(); + let tid = task.get_tid() as usize; + if timer_expired.is_some() { + error!("timer expired: {:?}", timer_expired); + let timer_type = timer_expired.unwrap(); + match timer_type { + TimerType::REAL => send_signal(tid, SignalNumber::SIGALRM as usize), + TimerType::VIRTUAL => send_signal(tid, SignalNumber::SIGVTALRM as usize), + TimerType::PROF => send_signal(tid, SignalNumber::SIGPROF as usize), + _ => { + panic!("timer type error"); + } + }; + } +} + +/// 只有在内核态下才能进入这个函数 +/// 避免嵌套中断发生这里不会再开启中断 +#[no_mangle] +pub fn kernel_trap_vector(sp: usize) { + let sstatus = sstatus::read(); + let spp = sstatus.spp(); + if spp == SPP::User { + panic!("kernel_trap_vector: spp == SPP::User"); + } + let enable = is_interrupt_enable(); + assert!(!enable); + let cause = riscv::register::scause::read().cause(); + cause.do_kernel_handle(sp) +} diff --git a/kkernel/src/trap/trampoline.asm b/kkernel/src/trap/trampoline.asm new file mode 100644 index 00000000..00bf2c28 --- /dev/null +++ b/kkernel/src/trap/trampoline.asm @@ -0,0 +1,83 @@ +.attribute arch, "rv64gc" +.altmacro +.macro SAVE_GP n + sd x\n, \n*8(sp) +.endm +.macro LOAD_GP n + ld x\n, \n*8(sp) +.endm + .section .text.trampoline + .globl user_v + .globl user_r + .align 3 +user_v: + csrrw sp, sscratch, sp + # now sp->*TrapContext in user space, sscratch->user stack + # save other general purpose registers + sd x1, 1*8(sp) + # skip sp(x2), we will save it later + # save x3~x31 + .set n, 3 + .rept 29 + SAVE_GP %n + .set n, n+1 + .endr + # we can use t0/t1/t2 freely, because they have been saved in TrapContext + csrr t0, sstatus + csrr t1, sepc + sd t1, 32*8(sp) + sd t0, 37*8(sp) + fsd fs0, 38*8(sp) + fsd fs1, 39*8(sp) + # read user stack from sscratch and save it in TrapContext + csrr t2, sscratch + sd t2, 2*8(sp) + # load kernel_satp into t0 + ld t0, 33*8(sp) + # load trap_handler into t1 + ld t1, 35*8(sp) + # load tp + ld tp,36*8(sp) + # move to kernel_sp + ld sp, 34*8(sp) + + # load hartid into tp(x4) + # ld tp, 36*8(tp) + # 保证用户态缓存全部刷新到内存 + sfence.vma + # switch to kernel space + csrw satp, t0 + sfence.vma + # jump to trap_handler + jr t1 + +user_r: + # a0: *TrapContext in user space(Constant); a1: user space token + # switch to user space + sfence.vma + csrw satp, a1 + sfence.vma + csrw sscratch, a0 + mv sp, a0 + # now sp points to TrapContext in user space, start restoring based on it + # restore sstatus/sepc + ld t1, 32*8(sp) + ld t0, 37*8(sp) + # save cpu_id + sd tp, 36*8(sp) + + csrw sepc, t1 + csrw sstatus, t0 + # restore general purpose registers except x0/sp + ld x1, 1*8(sp) + .set n, 3 + .rept 29 + LOAD_GP %n + .set n, n+1 + .endr + fld fs0, 38*8(sp) + fld fs1, 39*8(sp) + + # back to user stack + ld sp, 2*8(sp) + sret \ No newline at end of file diff --git a/subsystems/arch/Cargo.toml b/subsystems/arch/Cargo.toml index 717d3789..23804066 100644 --- a/subsystems/arch/Cargo.toml +++ b/subsystems/arch/Cargo.toml @@ -6,8 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -config = { path = "../config" } - - -#[target.'cfg(target_arch = "riscv64")'.dependencies] riscv = { version = "0.10" } \ No newline at end of file diff --git a/subsystems/config/Cargo.toml b/subsystems/config/Cargo.toml index c1c81a8a..691bb071 100644 --- a/subsystems/config/Cargo.toml +++ b/subsystems/config/Cargo.toml @@ -8,9 +8,3 @@ edition = "2021" [dependencies] -[features] -default = ["qemu"] -vf2 = [] -cv1811h = [] -hifive = [] -qemu = [] \ No newline at end of file diff --git a/subsystems/config/build.rs b/subsystems/config/build.rs new file mode 100644 index 00000000..2fdeee20 --- /dev/null +++ b/subsystems/config/build.rs @@ -0,0 +1,21 @@ +use std::fs; +use std::path::Path; + +fn main(){ + println!("cargo:rerun-if-changed={}", "src/lib.rs"); + let cpus = option_env!("SMP").unwrap_or("1"); + let cpus = cpus.parse::().unwrap(); + let config_file = Path::new("src/lib.rs"); + let config = fs::read_to_string(config_file).unwrap(); + let cpus = format!("pub const CPU_NUM: usize = {};\n", cpus); + let mut new_config = String::new(); + for line in config.lines() { + if line.starts_with("pub const CPU_NUM: usize = ") { + new_config.push_str(cpus.as_str()); + } else { + new_config.push_str(line); + new_config.push_str("\n"); + } + } + fs::write(config_file, new_config).unwrap(); +} \ No newline at end of file diff --git a/subsystems/config/src/lib.rs b/subsystems/config/src/lib.rs index 91891f10..560b48b1 100644 --- a/subsystems/config/src/lib.rs +++ b/subsystems/config/src/lib.rs @@ -10,21 +10,6 @@ pub const FLAG: &str = r" /_/ \_\ |_| |_| \___| |_| |_| "; -/// qemu时钟频率 -#[cfg(feature = "qemu")] -pub const CLOCK_FREQ: usize = 1250_0000; -/// vf2时钟频率 -#[cfg(feature = "vf2")] -pub const CLOCK_FREQ: usize = 400_0000; - -/// unmatched时钟频率 -#[cfg(feature = "hifive")] -pub const CLOCK_FREQ: usize = 100_0000; - -/// cv1811h时钟频率 -#[cfg(feature = "cv1811h")] -pub const CLOCK_FREQ: usize = 0x17d7840; - /// 物理页大小 pub const FRAME_SIZE: usize = 0x1000; /// 物理页大小的位数 @@ -34,37 +19,9 @@ pub const STACK_SIZE: usize = 1024 * 64; /// 内核启动栈大小的位数 pub const STACK_SIZE_BITS: usize = 16; -/// equal to CLOCK_FREQ -pub const TIMER_FREQ: usize = CLOCK_FREQ; /// 可配置的启动cpu数量 pub const CPU_NUM: usize = 1; -pub const AT_FDCWD: isize = -100isize; - -///qemu的设备地址空间 -#[cfg(feature = "qemu")] -pub const MMIO: &[(usize, usize)] = &[ - (0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine - (0x2000000, 0x10000), - (0xc00_0000, 0x21_0000), // VIRT_PLIC in virt machine - (0x1000_0000, 0x9000), // VIRT_UART0 with GPU in virt machine - (0x3000_0000, 0x1000_0000), -]; - -/// vf2的设备地址空间 -#[cfg(feature = "vf2")] -pub const MMIO: &[(usize, usize)] = &[ - (0x17040000, 0x10000), // RTC - (0xc000000, 0x4000000), //PLIC - (0x00_1000_0000, 0x10000), // UART -]; - -/// hifive的设备地址空间 -#[cfg(feature = "hifive")] -pub const MMIO: &[(usize, usize)] = &[ - (0xc000000, 0x4000000), //PLIC -]; - // todo!(if the app linker script changed, this should be changed too) /// 进程的堆空间上限 pub const PROCESS_HEAP_MAX: usize = u32::MAX as usize + 1; @@ -78,25 +35,6 @@ pub const USER_KERNEL_STACK_SIZE: usize = 0x1000 * 2; /// app用户栈大小 pub const USER_STACK_SIZE: usize = 0x50_000; -/// vf2/unmatched 的块缓存大小 -#[cfg(any(feature = "vf2", feature = "hifive"))] -pub const BLOCK_CACHE_FRAMES: usize = 1024 * 4 * 4; - -/// qemu 的块缓存大小 -#[cfg(feature = "qemu")] -pub const BLOCK_CACHE_FRAMES: usize = 1024 * 4 * 4; - -/// vf2/unmatched 的堆空间大小 -#[cfg(any(feature = "vf2", feature = "hifive"))] -pub const HEAP_SIZE: usize = 0x40_00000; - -/// qemu 的堆空间大小 -#[cfg(feature = "qemu")] -pub const HEAP_SIZE: usize = 0x26_00000; // (32+6)MB - -/// equal to HEAP_SIZe -pub const KERNEL_HEAP_SIZE: usize = HEAP_SIZE; - /// pipe缓冲区大小 pub const PIPE_BUF: usize = 65536; diff --git a/subsystems/constants/Cargo.toml b/subsystems/constants/Cargo.toml index 6d53e5ad..1cd1d88b 100644 --- a/subsystems/constants/Cargo.toml +++ b/subsystems/constants/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -pconst = { git = "https://github.com/os-module/pconst.git", features = ["trick"] } \ No newline at end of file +pconst = { git = "https://github.com/os-module/pconst.git", features = ["trick"] } diff --git a/subsystems/constants/src/lib.rs b/subsystems/constants/src/lib.rs index 2d3efe92..95463953 100644 --- a/subsystems/constants/src/lib.rs +++ b/subsystems/constants/src/lib.rs @@ -34,3 +34,5 @@ impl From for DeviceId { } } } + +pub const AT_FDCWD: isize = -100isize; \ No newline at end of file diff --git a/subsystems/device_interface/src/lib.rs b/subsystems/device_interface/src/lib.rs index 1ee339fd..aa50cced 100644 --- a/subsystems/device_interface/src/lib.rs +++ b/subsystems/device_interface/src/lib.rs @@ -25,6 +25,7 @@ pub trait GpuDevice: Send + Sync + Any + DeviceBase { fn update_cursor(&self); fn get_framebuffer(&self) -> &mut [u8]; fn flush(&self); + fn resolution(&self) -> (u32, u32); } pub trait InputDevice: Send + Sync + DeviceBase { diff --git a/subsystems/devices/Cargo.toml b/subsystems/devices/Cargo.toml new file mode 100644 index 00000000..f29154d4 --- /dev/null +++ b/subsystems/devices/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "devices" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +arch = { path = "../arch" } +config = { path = "../config" } +platform = { path = "../platform" } +constants = { path = "../constants" } +ksync = { path = "../ksync" } +interrupt = { path = "../interrupt" } +drivers = { path = "../drivers" } +device_interface = { path = "../device_interface" } + +spin = "0" +fdt = { git = "https://github.com/repnop/fdt" } +log = "0" +vfscore = { git = "https://github.com/os-module/rvfs.git", features = [ + "linux_error", +] } + +virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers",rev = "de1c3b1"} +netcore = {git = "https://github.com/os-module/simple-net"} + + + +[dependencies.smoltcp] +git = "https://github.com/rcore-os/smoltcp.git" +rev = "2ade274" +default-features = false +features = [ + "alloc", + "log", # no std + "medium-ethernet", +] + + + +[features] +default = ["test"] +memblk = [] +test = [] \ No newline at end of file diff --git a/subsystems/devices/src/block.rs b/subsystems/devices/src/block.rs new file mode 100644 index 00000000..9bd70ec1 --- /dev/null +++ b/subsystems/devices/src/block.rs @@ -0,0 +1,72 @@ +use alloc::sync::Arc; +use constants::DeviceId; +use device_interface::BlockDevice; +use spin::Once; +use vfscore::error::VfsError; +use vfscore::file::VfsFile; +use vfscore::inode::{InodeAttr, VfsInode}; +use vfscore::utils::{VfsFileStat, VfsNodeType, VfsPollEvents}; +use vfscore::VfsResult; + +use drivers::block_device::GenericBlockDevice; +pub static BLOCK_DEVICE: Once> = Once::new(); + +pub fn init_block_device(block_device: Arc) { + // BLOCK_DEVICE.lock().push(block_device); + BLOCK_DEVICE.call_once(|| block_device); +} + +pub struct BLKDevice { + device_id: DeviceId, + device: Arc, +} + +impl BLKDevice { + pub fn new(device_id: DeviceId, device: Arc) -> Self { + Self { device_id, device } + } + pub fn device_id(&self) -> DeviceId { + self.device_id + } +} + +impl VfsFile for BLKDevice { + fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { + self.device + .read(buf, offset as usize) + .map_err(|_| VfsError::IoError) + } + fn write_at(&self, offset: u64, buf: &[u8]) -> VfsResult { + self.device + .write(buf, offset as usize) + .map_err(|_| VfsError::IoError) + } + fn poll(&self, _event: VfsPollEvents) -> VfsResult { + unimplemented!() + } + fn ioctl(&self, _cmd: u32, _arg: usize) -> VfsResult { + unimplemented!() + } + fn flush(&self) -> VfsResult<()> { + Ok(()) + } + fn fsync(&self) -> VfsResult<()> { + Ok(()) + } +} + +impl VfsInode for BLKDevice { + fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { + Ok(()) + } + fn get_attr(&self) -> VfsResult { + Ok(VfsFileStat { + st_rdev: self.device_id.id(), + st_size: self.device.size() as u64, + ..Default::default() + }) + } + fn inode_type(&self) -> VfsNodeType { + VfsNodeType::BlockDevice + } +} diff --git a/subsystems/devices/src/gpu.rs b/subsystems/devices/src/gpu.rs new file mode 100644 index 00000000..d806486c --- /dev/null +++ b/subsystems/devices/src/gpu.rs @@ -0,0 +1,68 @@ +use alloc::sync::Arc; +use constants::DeviceId; +use spin::Once; +use vfscore::error::VfsError; +use vfscore::file::VfsFile; +use vfscore::inode::{InodeAttr, VfsInode}; +use vfscore::utils::{VfsFileStat, VfsNodeType}; +use vfscore::VfsResult; + +use device_interface::GpuDevice; + +pub static GPU_DEVICE: Once> = Once::new(); + +pub fn init_gpu(gpu: Arc) { + GPU_DEVICE.call_once(|| gpu); +} + +pub struct GPUDevice { + device_id: DeviceId, + device: Arc, +} + +impl GPUDevice { + pub fn new(device_id: DeviceId, device: Arc) -> Self { + Self { device_id, device } + } + pub fn device_id(&self) -> DeviceId { + self.device_id + } +} + +impl VfsFile for GPUDevice { + fn read_at(&self, _offset: u64, _buf: &mut [u8]) -> VfsResult { + Err(VfsError::Invalid) + } + fn write_at(&self, offset: u64, buf: &[u8]) -> VfsResult { + let gbuf = self.device.get_framebuffer(); + let offset = offset as usize; + let gbuf_len = gbuf.len(); + let min_len = (gbuf_len - offset).min(buf.len()); + gbuf[offset..offset + min_len].copy_from_slice(&buf[..min_len]); + Ok(min_len) + } + fn flush(&self) -> VfsResult<()> { + self.device.flush(); + Ok(()) + } + fn fsync(&self) -> VfsResult<()> { + self.flush() + } +} + +impl VfsInode for GPUDevice { + fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { + Ok(()) + } + + fn get_attr(&self) -> VfsResult { + Ok(VfsFileStat { + st_rdev: self.device_id.id(), + ..Default::default() + }) + } + + fn inode_type(&self) -> VfsNodeType { + VfsNodeType::CharDevice + } +} diff --git a/subsystems/devices/src/input.rs b/subsystems/devices/src/input.rs new file mode 100644 index 00000000..27c43d4a --- /dev/null +++ b/subsystems/devices/src/input.rs @@ -0,0 +1,84 @@ +use alloc::sync::Arc; + +use constants::DeviceId; +use device_interface::InputDevice; +use spin::Once; +use vfscore::error::VfsError; +use vfscore::file::VfsFile; +use vfscore::inode::{InodeAttr, VfsInode}; +use vfscore::superblock::VfsSuperBlock; +use vfscore::utils::{VfsFileStat, VfsNodeType, VfsPollEvents}; +use vfscore::VfsResult; + +pub struct INPUTDevice { + device_id: DeviceId, + device: Arc, + #[allow(unused)] + is_keyboard: bool, +} + +impl INPUTDevice { + pub fn new(device_id: DeviceId, device: Arc, is_keyboard: bool) -> Self { + Self { + device_id, + device, + is_keyboard, + } + } + pub fn device_id(&self) -> DeviceId { + self.device_id + } +} + +impl VfsFile for INPUTDevice { + fn read_at(&self, _offset: u64, buf: &mut [u8]) -> VfsResult { + if buf.len() != 8 { + return Err(VfsError::Invalid); + } + let buf = unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u64, 1) }; + let event = self.device.read_event_with_block(); + buf[0] = event; + Ok(1) + } + fn write_at(&self, _offset: u64, _buf: &[u8]) -> VfsResult { + Err(VfsError::Invalid) + } + fn poll(&self, event: VfsPollEvents) -> VfsResult { + let mut res = VfsPollEvents::empty(); + if event.contains(VfsPollEvents::IN) { + if self.device.is_empty() { + res |= VfsPollEvents::IN; + } + } + Ok(res) + } +} + +impl VfsInode for INPUTDevice { + fn get_super_block(&self) -> VfsResult> { + Err(VfsError::NoSys) + } + fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { + Ok(()) + } + fn get_attr(&self) -> VfsResult { + Ok(VfsFileStat { + st_rdev: self.device_id.id(), + ..Default::default() + }) + } + fn inode_type(&self) -> VfsNodeType { + VfsNodeType::CharDevice + } +} + +pub static KEYBOARD_INPUT_DEVICE: Once> = Once::new(); +pub static MOUSE_INPUT_DEVICE: Once> = Once::new(); + +pub fn init_keyboard_input_device(input_device: Arc) { + KEYBOARD_INPUT_DEVICE.call_once(|| input_device); +} + +pub fn init_mouse_input_device(input_device: Arc) { + MOUSE_INPUT_DEVICE.call_once(|| input_device); +} diff --git a/subsystems/devices/src/lib.rs b/subsystems/devices/src/lib.rs new file mode 100644 index 00000000..dc641708 --- /dev/null +++ b/subsystems/devices/src/lib.rs @@ -0,0 +1,408 @@ +#![no_std] + +mod block; +mod gpu; +mod input; +mod net; +mod prob; +mod rtc; +mod uart; + +extern crate alloc; + +use alloc::boxed::Box; +use alloc::sync::Arc; + +use crate::prob::Probe; +use alloc::vec::Vec; +use config::MAX_INPUT_EVENT_NUM; +use core::ptr::NonNull; +use device_interface::{DeviceBase, GpuDevice, LowBlockDevice}; +use drivers::rtc::GoldFishRtc; +use drivers::uart::{Uart, Uart16550, Uart8250}; +use fdt::Fdt; +use ksync::Mutex; +use log::info; +use platform::println; +use spin::{Lazy, Once}; +use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; +use virtio_drivers::transport::{DeviceType, Transport}; + +pub use block::{BLKDevice,BLOCK_DEVICE}; +pub use gpu::{GPUDevice,GPU_DEVICE}; +pub use input::{INPUTDevice,KEYBOARD_INPUT_DEVICE,MOUSE_INPUT_DEVICE}; +use interrupt::register_device_to_plic; +pub use rtc::{RTC_DEVICE,RTCDevice}; +pub use uart::{UARTDevice,UART_DEVICE}; + + + +pub struct DeviceInfo { + pub device: Arc, + pub irq: usize, + pub need_register: bool, +} + +pub static INITIALIZED_DEVICES: Lazy>> = Lazy::new(|| Mutex::new(Vec::new())); + +static TASK_FUNC: Once> = Once::new(); + +pub trait DeviceWithTask:Send+Sync{ + fn transfer_ptr_raw(&self, ptr: usize) -> usize; + fn transfer_buf_raw(&self, src: usize, size:usize) -> Vec<&mut [u8]>; +} + +impl dyn DeviceWithTask{ + fn copy_data_to_task(&self,src: *const T, dst: *mut T){ + let size = core::mem::size_of::(); + let bufs = self.transfer_buf_raw(dst as usize,size); + let src = unsafe { core::slice::from_raw_parts(src as *const u8, size) }; + let mut start = 0; + for buffer in bufs { + let len = if start + buffer.len() > size { + size - start + } else { + buffer.len() + }; + unsafe { + core::ptr::copy_nonoverlapping( + src.as_ptr().add(start), + buffer.as_mut_ptr(), + len, + ); + } + start += len; + } + } + fn copy_data_from_task(&self,src: *const T, dst: *mut T){ + let size = core::mem::size_of::(); + let bufs = self.transfer_buf_raw(src as usize,size); + let dst = unsafe { core::slice::from_raw_parts_mut(dst as *mut u8, size) }; + let mut start = 0; + for buffer in bufs { + let len = if start + buffer.len() > size { + size - start + } else { + buffer.len() + }; + unsafe { + core::ptr::copy_nonoverlapping( + buffer.as_ptr(), + dst.as_mut_ptr().add(start), + len, + ); + } + start += len; + } + } + fn transfer_ptr_mut(&self, ptr: *mut T) -> &'static mut T{ + let ptr = ptr as usize; + let ptr = self.transfer_ptr_raw(ptr); + unsafe { &mut *(ptr as *mut T) } + } + fn transfer_ptr(&self, ptr: *const T) -> &'static T{ + let ptr = ptr as usize; + let ptr = self.transfer_ptr_raw(ptr); + unsafe { &*(ptr as *const T) } + } +} + + +/// Probe all devices from device tree and init them. +/// # Warning +/// Before init device, we should init platform first. +/// +/// todo!(The task_func should be replaced) +pub fn init_device(task_func:Box) { + + TASK_FUNC.call_once(|| task_func); + + let dtb_ptr = platform::platform_dtb_ptr(); + + let dtb = unsafe { Fdt::from_ptr(dtb_ptr as *const u8).unwrap() }; + match dtb.probe_rtc() { + Some(rtc) => init_rtc(rtc), + None => { println!("There is no rtc device"); }, + } + + match dtb.probe_uart() { + Some(uart) => init_uart(uart), + None => { println!("There is no uart device"); }, + } + + match dtb.probe_virtio() { + Some(virtio_mmio_devices) => init_virtio_mmio(virtio_mmio_devices), + None => { println!("There is no virtio-mmio device"); }, + } +} + +fn init_rtc(rtc: prob::DeviceInfo) { + let info = rtc; + println!( + "Init rtc, base_addr:{:#x}, irq:{}", + info.base_addr, + info.irq + ); + match info.compatible.as_str() { + "google,goldfish-rtc" => { + let rtc = Arc::new(GoldFishRtc::new(info.base_addr)); + let current_time = rtc.read_time_string(); + rtc::init_rtc(rtc.clone()); + register_device_to_plic(info.irq, rtc); + // INITIALIZED_DEVICES.lock().push(DeviceInfo { + // device: rtc, + // irq: info.irq, + // need_register: true, + // }); + println!("Init rtc success, current time: {:?}", current_time); + } + name => { + println!("Don't support rtc: {}", name); + } + } +} + +fn init_uart(uart: prob::DeviceInfo) { + let (base_addr, irq) = (uart.base_addr, uart.irq); + println!("Init uart, base_addr:{:#x},irq:{}", base_addr, irq); + match uart.compatible.as_str() { + "ns16550a" => { + // qemu + let uart = Uart16550::new(base_addr); + let uart = Arc::new(Uart::new(Box::new(uart))); + uart::init_uart(uart.clone()); + register_device_to_plic(irq, uart); + // INITIALIZED_DEVICES.lock().push(DeviceInfo { + // device: uart, + // irq, + // need_register: true, + // }); + } + "snps,dw-apb-uart" => { + // vf2 + let uart = Uart8250::new(base_addr); + let uart = Arc::new(Uart::new(Box::new(uart))); + uart::init_uart(uart.clone()); + register_device_to_plic(irq, uart); + // INITIALIZED_DEVICES.lock().push(DeviceInfo { + // device: uart, + // irq, + // need_register: true, + // }); + } + name => { + println!("Don't support uart: {}", name); + return; + } + } + println!("Init uart success"); +} + +// keyboard +const VIRTIO5: usize = 0x10005000; +// mouse +const VIRTIO6: usize = 0x10006000; + +pub fn init_virtio_mmio(devices: Vec) { + for device in devices { + let paddr = device.base_addr; + let header = NonNull::new(paddr as *mut VirtIOHeader).unwrap(); + match unsafe { MmioTransport::new(header) } { + Err(_) => {} + Ok(mut transport) => { + info!( + "Detected virtio MMIO device with vendor id {:#X}, device type {:?}, version {:?}, features:{:?}", + transport.vendor_id(), + transport.device_type(), + transport.version(), + transport.read_device_features(), + ); + info!("Probe virtio device: {:?}", transport.device_type()); + match transport.device_type() { + DeviceType::Input => { + if paddr == VIRTIO5 { + init_input_device(device, "keyboard"); + } else if paddr == VIRTIO6 { + init_input_device(device, "mouse"); + } + } + DeviceType::Block => init_block_device(device,Some(transport)), + DeviceType::GPU => init_gpu(device), + DeviceType::Network => { init_net(device) }, + _ => {}, + } + } + } + } +} + +#[cfg(feature = "memblk")] +core::arch::global_asm!( + r#" + .section .data + .global img_start + .global img_end + .align 12 + img_start: + .incbin "./tools/sdcard.img" + img_end: + "# +); + +#[cfg(feature = "memblk")] +extern "C" { + pub fn img_start(); + pub fn img_end(); +} +#[cfg(feature = "memblk")] +pub fn checkout_fs_img() { + let img_start = img_start as usize; + let img_end = img_end as usize; + let img_size = img_end - img_start; + println!( + "img_start: {:#x}, img_end: {:#x}, img_size: {:#x}", + img_start, + img_end, + img_size + ); +} + +fn init_block_device(blk: prob::DeviceInfo, mmio_transport: Option) { + use drivers::block_device::{GenericBlockDevice, VirtIOBlkWrapper}; + match blk.compatible.as_str() { + "virtio,mmio" => { + // qemu + // let mut block_device = VirtIOBlkWrapper::new(blk.base_addr); + let block_device = VirtIOBlkWrapper::from_mmio(mmio_transport.unwrap()); + let (base_addr, irq) = (blk.base_addr, blk.irq); + println!("Init block device, base_addr:{:#x},irq:{}", base_addr, irq); + let size = block_device.capacity(); + println!("Block device size is {}MB", size * 512 / 1024 / 1024); + let block_device = Arc::new(GenericBlockDevice::new(Box::new(block_device))); + block::init_block_device(block_device); + // register_device_to_plic(irq, block_device); + println!("Init block device success"); + } + name => { + println!("Don't support block device: {}", name); + #[cfg(feature = "memblk")] + { + use drivers::block_device::MemoryFat32Img; + checkout_fs_img(); + let data = unsafe { + core::slice::from_raw_parts_mut( + img_start as *mut u8, + img_end as usize - img_start as usize, + ) + }; + let device = GenericBlockDevice::new(Box::new(MemoryFat32Img::new(data))); + let device = Arc::new(device); + println!("Init fake block device success"); + } + #[cfg(not(feature = "memblk"))] + panic!("System need block device, but there is no block device"); + } + } +} + +fn init_gpu(gpu: prob::DeviceInfo) { + let (base_addr, irq) = (gpu.base_addr, gpu.irq); + println!("Init gpu, base_addr:{:#x},irq:{}", base_addr, irq); + match gpu.compatible.as_str() { + "virtio,mmio" => { + // qemu + use drivers::gpu::VirtIOGpuWrapper; + let gpu = VirtIOGpuWrapper::new(base_addr); + let resolution = gpu.resolution(); + println!("GPU resolution: {:?}", resolution); + let gpu = Arc::new(gpu); + gpu::init_gpu(gpu.clone()); + // let _ = register_device_to_plic(irq, gpu); + println!("Init gpu success"); + } + name => { + println!("Don't support gpu: {}", name); + } + } +} + +fn init_input_device(input: prob::DeviceInfo, name: &str) { + let (base_addr, irq) = (input.base_addr, input.irq); + println!( + "Init {} input device, base_addr:{:#x},irq:{}", + name, + base_addr, + irq + ); + match input.compatible.as_str() { + "virtio,mmio" => { + // qemu + use drivers::input::VirtIOInputDriver; + let input = VirtIOInputDriver::from_addr(base_addr, MAX_INPUT_EVENT_NUM as u32); + let input = Arc::new(input); + match name { + "mouse" => input::init_mouse_input_device(input.clone()), + "keyboard" => input::init_keyboard_input_device(input.clone()), + _ => panic!("Don't support {} input device", name), + } + let _ = register_device_to_plic(irq, input); + // INITIALIZED_DEVICES.lock().push(DeviceInfo { + // device: input, + // irq, + // need_register: true, + // }); + println!("Init keyboard input device success"); + } + name => { + println!("Don't support keyboard input device: {}", name); + } + } +} + +fn init_net(nic: prob::DeviceInfo) { + // If we need run test, we should only init loop device because no we can't route packet + #[cfg(feature = "test")] + { + init_loop_device(); + } + #[cfg(not(feature = "test"))] + { + let (base_addr, irq) = (nic.base_addr, nic.irq); + println!("Init net device, base_addr:{:#x},irq:{}", base_addr, irq); + + match nic.compatible.as_str() { + "virtio,mmio" => { + use config::{QEMU_GATEWAY, QEMU_IP}; + use core::str::FromStr; + use drivers::net::{NetNeedFunc, VirtIONetDriver}; + use smoltcp::wire::IpAddress; + let virtio_net = VirtIONetDriver::from_mmio(base_addr); + let device = Box::new(virtio_net); + netcore::init_net( + device, + Arc::new(NetNeedFunc), + IpAddress::from_str(QEMU_IP).unwrap(), + IpAddress::from_str(QEMU_GATEWAY).unwrap(), + true, + ); + println!("Init net device success"); + } + name => { + println!("Don't support net device: {}", name); + return; + } + } + } +} + +#[cfg(feature = "test")] +fn init_loop_device() { + use drivers::net::{LoopbackDev, NetNeedFunc}; + use smoltcp::wire::IpAddress; + // use default ip and gateway for qemu + let ip = IpAddress::v4(127, 0, 0, 1); + let gate_way = IpAddress::v4(127, 0, 0, 1); + let loopback = Box::new(LoopbackDev::new()); + netcore::init_net(loopback, Arc::new(NetNeedFunc), ip, gate_way, false); + println!("Init net device success"); +} diff --git a/subsystems/devices/src/net.rs b/subsystems/devices/src/net.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/subsystems/devices/src/net.rs @@ -0,0 +1 @@ + diff --git a/subsystems/devices/src/prob.rs b/subsystems/devices/src/prob.rs new file mode 100644 index 00000000..76a163fe --- /dev/null +++ b/subsystems/devices/src/prob.rs @@ -0,0 +1,90 @@ +use alloc::string::{String, ToString}; + +use alloc::vec::Vec; +use core::ops::Range; +use fdt::standard_nodes::Compatible; +use fdt::Fdt; + +#[derive(Debug, Clone)] +pub struct DeviceInfo { + pub name: String, + pub base_addr: usize, + pub irq: usize, + pub compatible: String, +} + +impl DeviceInfo { + pub fn new(name: String, base_addr: usize, irq: usize, compatible: String) -> Self { + Self { + name, + base_addr, + irq, + compatible, + } + } +} + +pub trait Probe { + /// Get the base address and irq number of the uart device from the device tree. + fn probe_uart(&self) -> Option; + /// Get the base address and irq number of the rtc device from the device tree. + fn probe_rtc(&self) -> Option; + /// Get the base address and irq number of the virtio devices from the device tree. + fn probe_virtio(&self) -> Option>; + fn probe_common(&self, device_name: &str) -> Option; +} + +impl Probe for Fdt<'_> { + fn probe_uart(&self) -> Option { + match self.probe_common("uart") { + Some(device_info) => Some(device_info), + None => self.probe_common("serial"), + } + } + + fn probe_rtc(&self) -> Option { + self.probe_common("rtc") + } + + fn probe_virtio(&self) -> Option> { + let mut virtio_devices = Vec::new(); + for node in self.all_nodes() { + if node.name.starts_with("virtio_mmio") { + let reg = node.reg()?.next()?; + let paddr = reg.starting_address as usize; + let irq = node.property("interrupts")?.value; + let irq = u32::from_be_bytes(irq[0..4].try_into().ok()?); + + let compatible = node.compatible().map(Compatible::first).unwrap(); + + virtio_devices.push(DeviceInfo::new( + String::from("virtio_mmio"), + paddr, + irq as usize, + compatible.to_string(), + )); + } + } + Some(virtio_devices) + } + + fn probe_common(&self, device_name: &str) -> Option { + let node = self + .all_nodes() + .find(|node| node.name.starts_with(device_name))?; + let reg = node.reg()?.next()?; + let range = Range { + start: reg.starting_address as usize, + end: reg.starting_address as usize + reg.size.unwrap(), + }; + let irq = node.property("interrupts").unwrap().value; + let irq = u32::from_be_bytes(irq[0..4].try_into().unwrap()); + let compatible = node.compatible().map(Compatible::first).unwrap(); + Some(DeviceInfo::new( + device_name.to_string(), + range.start, + irq as usize, + compatible.to_string(), + )) + } +} diff --git a/subsystems/devices/src/rtc.rs b/subsystems/devices/src/rtc.rs new file mode 100644 index 00000000..b2dd7d30 --- /dev/null +++ b/subsystems/devices/src/rtc.rs @@ -0,0 +1,121 @@ +use alloc::format; +use alloc::sync::Arc; +use constants::io::{RtcTime, TeletypeCommand}; +use constants::DeviceId; +use core::cmp::min; +use device_interface::RtcDevice; +use spin::Once; +use vfscore::error::VfsError; +use vfscore::file::VfsFile; +use vfscore::inode::{InodeAttr, VfsInode}; +use vfscore::superblock::VfsSuperBlock; +use vfscore::utils::{VfsFileStat, VfsNodeType}; +use vfscore::VfsResult; +use crate::TASK_FUNC; + +pub static RTC_DEVICE: Once> = Once::new(); + +#[allow(unused)] +pub fn get_rtc_time() -> Option { + RTC_DEVICE.get().map(|rtc| rtc.read_time()) +} + +pub fn init_rtc(rtc: Arc) { + RTC_DEVICE.call_once(|| rtc); +} + +pub struct RTCDevice { + device_id: DeviceId, + device: Arc, +} + +impl RTCDevice { + pub fn new(device_id: DeviceId, device: Arc) -> Self { + Self { device_id, device } + } + pub fn device_id(&self) -> DeviceId { + self.device_id + } +} + +impl VfsFile for RTCDevice { + fn read_at(&self, _offset: u64, buf: &mut [u8]) -> VfsResult { + let time = self.device.read_time(); + let str = format!("{:?}", time); + let bytes = str.as_bytes(); + let min_len = min(buf.len(), bytes.len()); + buf[..min_len].copy_from_slice(&bytes[..min_len]); + Ok(min_len) + } + fn write_at(&self, _offset: u64, _buf: &[u8]) -> VfsResult { + todo!() + } + fn ioctl(&self, cmd: u32, arg: usize) -> VfsResult { + // let task = current_task().unwrap(); + // let mut task_inner = task.access_inner(); + let cmd = TeletypeCommand::try_from(cmd).map_err(|_| VfsError::Invalid)?; + match cmd { + TeletypeCommand::RTC_RD_TIME => { + let time = self.device.read_time(); + TASK_FUNC.get().unwrap().copy_data_to_task(&time, arg as *mut RtcTime); + } + _ => return Err(VfsError::Invalid), + } + Ok(0) + } + fn flush(&self) -> VfsResult<()> { + Ok(()) + } + fn fsync(&self) -> VfsResult<()> { + Ok(()) + } +} + +impl VfsInode for RTCDevice { + fn get_super_block(&self) -> VfsResult> { + Err(VfsError::NoSys) + } + + fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { + Ok(()) + } + + fn get_attr(&self) -> VfsResult { + Ok(VfsFileStat { + st_rdev: self.device_id.id(), + ..Default::default() + }) + } + + fn inode_type(&self) -> VfsNodeType { + VfsNodeType::CharDevice + } +} + +#[allow(dead_code)] +fn example() { + // let rtc = RTC_DEVICE.get().unwrap(); + // let time = rtc.read_time(); + // let alarm = rtc.read_alarm(); + // println!("time: {:#x}, alarm: {:#x}", time, alarm); + // rtc.clear_irq(); + // rtc.enable_irq(); + // println!("set alarm"); + // rtc.set_alarm(time + 1_000_000_000 * 5); // wait 5s + // let alarm = rtc.read_alarm_fmt(); + // let status = rtc.alarm_status(); + // let is_enable = rtc.is_irq_enabled(); + // println!( + // "At {:?}, rtc will interrupt, status: {} enable: {}", + // alarm, status, is_enable + // ); + // loop { + // let time = rtc.read_time(); + // let alarm = rtc.read_alarm(); + // if time == alarm { + // let status = rtc.alarm_status(); + // let enable = rtc.is_irq_enabled(); + // println!("time == alarm, status: {}, enable: {}", status, enable); + // } + // } +} diff --git a/subsystems/devices/src/uart.rs b/subsystems/devices/src/uart.rs new file mode 100644 index 00000000..a91ccb63 --- /dev/null +++ b/subsystems/devices/src/uart.rs @@ -0,0 +1,167 @@ +use alloc::sync::Arc; +use constants::io::{LocalModes, TeletypeCommand, Termios, WinSize}; +use constants::DeviceId; +use device_interface::UartDevice; +use ksync::Mutex; +use spin::Once; +use vfscore::error::VfsError; +use vfscore::file::VfsFile; +use vfscore::inode::{InodeAttr, VfsInode}; +use vfscore::superblock::VfsSuperBlock; +use vfscore::utils::{VfsFileStat, VfsNodeType, VfsPollEvents}; +use vfscore::VfsResult; +use crate::TASK_FUNC; + +pub static UART_DEVICE: Once> = Once::new(); + +pub fn init_uart(uart: Arc) { + UART_DEVICE.call_once(|| uart); +} + +#[derive(Debug, Default)] +pub struct IoData { + foreground_pgid: u32, + winsize: WinSize, + termios: Termios, +} + +pub struct UARTDevice { + device_id: DeviceId, + device: Arc, + io: Mutex, +} + +impl UARTDevice { + pub fn new(device_id: DeviceId, device: Arc) -> Self { + Self { + device_id, + device, + io: Mutex::new(IoData::default()), + } + } + pub fn device_id(&self) -> DeviceId { + self.device_id + } +} + +impl VfsFile for UARTDevice { + fn read_at(&self, _offset: u64, buf: &mut [u8]) -> VfsResult { + // read util \r and transform to \n + let mut read_count = 0; + loop { + let ch = self.device.get(); + assert!(ch.is_some()); + let ch = ch.unwrap(); + buf[read_count] = ch; + read_count += 1; + if ch == b'\r' { + buf[read_count - 1] = b'\n'; + if LocalModes::from_bits_truncate(self.io.lock().termios.lflag) + .contains(LocalModes::ECHO) + { + self.device.put(b'\n'); + } + break; + } + if LocalModes::from_bits_truncate(self.io.lock().termios.lflag) + .contains(LocalModes::ECHO) + { + self.device.put(ch); + } + if read_count >= buf.len() { + break; + } + } + Ok(read_count) + } + fn write_at(&self, _offset: u64, buf: &[u8]) -> VfsResult { + self.device.put_bytes(buf); + Ok(buf.len()) + } + fn poll(&self, event: VfsPollEvents) -> VfsResult { + let mut res = VfsPollEvents::empty(); + if event.contains(VfsPollEvents::IN) { + if self.device.have_data_to_get() { + res |= VfsPollEvents::IN; + } + } + if event.contains(VfsPollEvents::OUT) { + if self.device.have_space_to_put() { + res |= VfsPollEvents::OUT + } + } + Ok(res) + } + fn ioctl(&self, cmd: u32, arg: usize) -> VfsResult { + let mut io = self.io.lock(); + let cmd = TeletypeCommand::try_from(cmd).unwrap(); + + // let task = current_task().unwrap(); + // let mut task_inner = task.access_inner(); + + return match cmd { + TeletypeCommand::TCGETS | TeletypeCommand::TCGETA => { + // task_inner.copy_to_user(&io.termios, arg as *mut Termios); + TASK_FUNC.get().unwrap().copy_data_to_task(&io.termios, arg as *mut Termios); + Ok(0) + } + TeletypeCommand::TCSETS | TeletypeCommand::TCSETSW | TeletypeCommand::TCSETSF => { + // task_inner.copy_from_user(arg as *const Termios, &mut io.termios); + TASK_FUNC.get().unwrap().copy_data_from_task(arg as *const Termios, &mut io.termios); + Ok(0) + } + TeletypeCommand::TIOCGPGRP => { + // let word = task_inner.transfer_raw_ptr_mut(arg as *mut u32); + let word = TASK_FUNC.get().unwrap().transfer_ptr_mut(arg as *mut u32); + *word = io.foreground_pgid; + Ok(0) + } + TeletypeCommand::TIOCSPGRP => { + // let word = task_inner.transfer_raw_ptr(arg as *const u32); + let word = TASK_FUNC.get().unwrap().transfer_ptr(arg as *const u32); + io.foreground_pgid = *word; + Ok(0) + } + TeletypeCommand::TIOCGWINSZ => { + // task_inner.copy_to_user(&io.winsize, arg as *mut WinSize); + TASK_FUNC.get().unwrap().copy_data_to_task(&io.winsize, arg as *mut WinSize); + Ok(0) + } + TeletypeCommand::TIOCSWINSZ => { + // task_inner.copy_from_user(arg as *const WinSize, &mut io.winsize); + TASK_FUNC.get().unwrap().copy_data_from_task(arg as *const WinSize, &mut io.winsize); + Ok(0) + } + _ => { + unimplemented!("ioctl cmd: {:?}", cmd) + } + }; + } + fn flush(&self) -> VfsResult<()> { + Ok(()) + } + fn fsync(&self) -> VfsResult<()> { + Ok(()) + } +} + +impl VfsInode for UARTDevice { + fn get_super_block(&self) -> VfsResult> { + Err(VfsError::NoSys) + } + + fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { + Ok(()) + } + + fn get_attr(&self) -> VfsResult { + Ok(VfsFileStat { + st_rdev: self.device_id.id(), + ..Default::default() + }) + } + + fn inode_type(&self) -> VfsNodeType { + VfsNodeType::CharDevice + } +} diff --git a/subsystems/drivers/Cargo.toml b/subsystems/drivers/Cargo.toml new file mode 100644 index 00000000..02fbf061 --- /dev/null +++ b/subsystems/drivers/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "drivers" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +constants = { path = "../constants" } +ksync = { path = "../ksync" } +config = { path = "../config" } +device_interface = { path = "../device_interface" } +mem = { path = "../mem" } +log = "0" +timer = { path = "../timer" } +platform = { path = "../platform" } + + +spin = "0" + +virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers",rev = "de1c3b1"} +rtc = { git = "https://github.com/os-module/rtc.git" } +lru = "0.10.0" + +# uart +uart16550 = { version = "0.0.1"} +uart8250 = { git = "https://github.com/os-module/uart-rs.git"} + + +# net +loopback = {git = "https://github.com/os-module/simple-net"} +virtio-net = {git = "https://github.com/os-module/simple-net"} +netcore = {git = "https://github.com/os-module/simple-net"} + + +downcast-rs = { version = "1.2.0", default-features = false } \ No newline at end of file diff --git a/subsystems/drivers/src/block_device.rs b/subsystems/drivers/src/block_device.rs new file mode 100644 index 00000000..9a64881d --- /dev/null +++ b/subsystems/drivers/src/block_device.rs @@ -0,0 +1,263 @@ +use alloc::boxed::Box; +use alloc::vec::Vec; +use constants::LinuxErrno; +use core::cmp::min; +use core::fmt::{Debug, Formatter}; +use core::num::NonZeroUsize; +use core::ops::{Deref, DerefMut}; +use core::ptr::NonNull; +use lru::LruCache; +use virtio_drivers::device::blk::VirtIOBlk; +use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; + +use constants::AlienResult; +use ksync::Mutex; + +use crate::hal::HalImpl; +use config::{FRAME_SIZE}; +use device_interface::{BlockDevice, DeviceBase, LowBlockDevice}; +use mem::{alloc_frames, free_frames}; +use platform::config::BLOCK_CACHE_FRAMES; + + +const PAGE_CACHE_SIZE: usize = FRAME_SIZE; + +pub struct GenericBlockDevice { + pub device: Mutex>, + cache: Mutex>, + dirty: Mutex>, +} + +#[derive(Debug)] +struct FrameTracker { + ptr: usize, +} + +impl FrameTracker { + pub fn new(ptr: usize) -> Self { + Self { ptr } + } +} + +impl Deref for FrameTracker { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + unsafe { core::slice::from_raw_parts(self.ptr as *const u8, FRAME_SIZE) } + } +} + +impl DerefMut for FrameTracker { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { core::slice::from_raw_parts_mut(self.ptr as *mut u8, FRAME_SIZE) } + } +} + +impl Drop for FrameTracker { + fn drop(&mut self) { + free_frames(self.ptr as *mut u8, 1); + } +} + +unsafe impl Send for GenericBlockDevice {} + +unsafe impl Sync for GenericBlockDevice {} + +impl GenericBlockDevice { + pub fn new(device: Box) -> Self { + Self { + device: Mutex::new(device), + cache: Mutex::new(LruCache::new( + NonZeroUsize::new(BLOCK_CACHE_FRAMES).unwrap(), + )), // 4MB cache + dirty: Mutex::new(Vec::new()), + } + } +} + +impl DeviceBase for GenericBlockDevice { + fn hand_irq(&self) { + unimplemented!() + } +} + +impl Debug for GenericBlockDevice { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("QemuBlockDevice").finish() + } +} + +impl BlockDevice for GenericBlockDevice { + fn read(&self, buf: &mut [u8], offset: usize) -> AlienResult { + let mut page_id = offset / PAGE_CACHE_SIZE; + let mut offset = offset % PAGE_CACHE_SIZE; + + let mut cache_lock = self.cache.lock(); + let len = buf.len(); + let mut count = 0; + + while count < len { + if !cache_lock.contains(&page_id) { + let mut device = self.device.lock(); + let cache = alloc_frames(1); + let mut cache = FrameTracker::new(cache as usize); + let start_block = page_id * PAGE_CACHE_SIZE / 512; + let end_block = start_block + PAGE_CACHE_SIZE / 512; + for i in start_block..end_block { + let target_buf = + &mut cache[(i - start_block) * 512..(i - start_block + 1) * 512]; + device.read_block(i, target_buf).unwrap(); + } + let old_cache = cache_lock.push(page_id, cache); + if let Some((id, old_cache)) = old_cache { + let start_block = id * PAGE_CACHE_SIZE / 512; + let end_block = start_block + PAGE_CACHE_SIZE / 512; + for i in start_block..end_block { + let target_buf = + &old_cache[(i - start_block) * 512..(i - start_block + 1) * 512]; + device.write_block(i, target_buf).unwrap(); + self.dirty.lock().retain(|&x| x != id); + } + } + } + let cache = cache_lock.get(&page_id).unwrap(); + let copy_len = min(PAGE_CACHE_SIZE - offset, len - count); + buf[count..count + copy_len].copy_from_slice(&cache[offset..offset + copy_len]); + count += copy_len; + offset = 0; + page_id += 1; + } + Ok(buf.len()) + } + fn write(&self, buf: &[u8], offset: usize) -> AlienResult { + let mut page_id = offset / PAGE_CACHE_SIZE; + let mut offset = offset % PAGE_CACHE_SIZE; + + let mut cache_lock = self.cache.lock(); + let len = buf.len(); + let mut count = 0; + while count < len { + if !cache_lock.contains(&page_id) { + let mut device = self.device.lock(); + let cache = alloc_frames(1); + let mut cache = FrameTracker::new(cache as usize); + let start_block = page_id * PAGE_CACHE_SIZE / 512; + let end_block = start_block + PAGE_CACHE_SIZE / 512; + for i in start_block..end_block { + let target_buf = + &mut cache[(i - start_block) * 512..(i - start_block + 1) * 512]; + device.read_block(i, target_buf).unwrap(); + } + let old_cache = cache_lock.push(page_id, cache); + if let Some((id, old_cache)) = old_cache { + let start_block = id * PAGE_CACHE_SIZE / 512; + let end_block = start_block + PAGE_CACHE_SIZE / 512; + for i in start_block..end_block { + let target_buf = + &old_cache[(i - start_block) * 512..(i - start_block + 1) * 512]; + device.write_block(i, target_buf).unwrap(); + self.dirty.lock().retain(|&x| x != id); + } + } + } + let cache = cache_lock.get_mut(&page_id).unwrap(); + if cache.as_ptr() as usize == 0x9000_0000 { + panic!("cache is null"); + } + // self.dirty.lock().push(page_id); + let copy_len = min(PAGE_CACHE_SIZE - offset, len - count); + cache[offset..offset + copy_len].copy_from_slice(&buf[count..count + copy_len]); + count += copy_len; + offset = (offset + copy_len) % PAGE_CACHE_SIZE; + page_id += 1; + } + Ok(buf.len()) + } + fn size(&self) -> usize { + self.device.lock().capacity() * 512 + } + fn flush(&self) -> AlienResult<()> { + // let mut device = self.device.lock(); + // let mut lru = self.cache.lock(); + // self.dirty.lock().iter().for_each(|id|{ + // let start = id * PAGE_CACHE_SIZE; + // let start_block = start / 512; + // let end_block = (start + PAGE_CACHE_SIZE) / 512; + // let cache = lru.get(id).unwrap(); + // for i in start_block..end_block { + // let target_buf = &cache[(i - start_block) * 512..(i - start_block + 1) * 512]; + // device.write_block(i, target_buf).unwrap(); + // } + // }); + // self.dirty.lock().clear(); + Ok(()) + } +} + +pub struct VirtIOBlkWrapper { + device: VirtIOBlk, +} + +impl VirtIOBlkWrapper { + pub fn new(addr: usize) -> Self { + let header = NonNull::new(addr as *mut VirtIOHeader).unwrap(); + let transport = unsafe { MmioTransport::new(header) }.unwrap(); + let blk = VirtIOBlk::::new(transport) + .expect("failed to create blk driver"); + Self { device: blk } + } + + pub fn from_mmio(mmio_transport: MmioTransport)->Self{ + let blk = VirtIOBlk::::new(mmio_transport) + .expect("failed to create blk driver"); + Self { device: blk } + } +} + +impl LowBlockDevice for VirtIOBlkWrapper { + fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> AlienResult<()> { + let res = self + .device + .read_block(block_id, buf) + .map_err(|_| LinuxErrno::EIO.into()); + res + } + fn write_block(&mut self, block_id: usize, buf: &[u8]) -> AlienResult<()> { + self.device + .write_block(block_id, buf) + .map_err(|_| LinuxErrno::EIO.into()) + } + + fn capacity(&self) -> usize { + self.device.capacity() as usize + } +} + +pub struct MemoryFat32Img { + data: &'static mut [u8], +} + +impl LowBlockDevice for MemoryFat32Img { + fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> AlienResult<()> { + let start = block_id * 512; + let end = start + 512; + buf.copy_from_slice(&self.data[start..end]); + Ok(()) + } + fn write_block(&mut self, block_id: usize, buf: &[u8]) -> AlienResult<()> { + let start = block_id * 512; + let end = start + 512; + self.data[start..end].copy_from_slice(buf); + Ok(()) + } + + fn capacity(&self) -> usize { + self.data.len() / 512 + } +} + +impl MemoryFat32Img { + pub fn new(data: &'static mut [u8]) -> Self { + Self { data } + } +} diff --git a/subsystems/drivers/src/gpu.rs b/subsystems/drivers/src/gpu.rs new file mode 100644 index 00000000..008916cc --- /dev/null +++ b/subsystems/drivers/src/gpu.rs @@ -0,0 +1,61 @@ +use core::ptr::NonNull; +use device_interface::{DeviceBase, GpuDevice}; +use virtio_drivers::device::gpu::VirtIOGpu; +use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; + +use crate::hal::HalImpl; +use ksync::Mutex; + +pub struct VirtIOGpuWrapper { + gpu: Mutex>, + fb: &'static [u8], + #[allow(unused)] + resolution: (u32, u32), +} + +unsafe impl Sync for VirtIOGpuWrapper {} + +unsafe impl Send for VirtIOGpuWrapper {} + +impl VirtIOGpuWrapper { + pub fn new(addr: usize) -> Self { + let header = NonNull::new(addr as *mut VirtIOHeader).unwrap(); + let mmio = unsafe { MmioTransport::new(header) }.unwrap(); + let mut gpu = VirtIOGpu::new(mmio).unwrap(); + let resolution = gpu.resolution().unwrap(); + unsafe { + let fbuffer = gpu.setup_framebuffer().unwrap(); + let len = fbuffer.len(); + let ptr = fbuffer.as_mut_ptr(); + let fb = core::slice::from_raw_parts_mut(ptr, len); + gpu.move_cursor(50, 50).unwrap(); + Self { + gpu: Mutex::new(gpu), + fb, + resolution, + } + } + } +} + +impl DeviceBase for VirtIOGpuWrapper { + fn hand_irq(&self) { + self.gpu.lock().ack_interrupt(); + } +} + +impl GpuDevice for VirtIOGpuWrapper { + fn update_cursor(&self) {} + fn get_framebuffer(&self) -> &mut [u8] { + unsafe { + let ptr = self.fb.as_ptr() as *const _ as *mut u8; + core::slice::from_raw_parts_mut(ptr, self.fb.len()) + } + } + fn flush(&self) { + self.gpu.lock().flush().unwrap(); + } + fn resolution(&self) -> (u32, u32) { + self.resolution + } +} diff --git a/subsystems/drivers/src/hal.rs b/subsystems/drivers/src/hal.rs new file mode 100644 index 00000000..d203d96b --- /dev/null +++ b/subsystems/drivers/src/hal.rs @@ -0,0 +1,28 @@ +use core::ptr::NonNull; +use mem::{alloc_frames, free_frames}; +use virtio_drivers::{BufferDirection, Hal, PhysAddr}; + +pub struct HalImpl; + +unsafe impl Hal for HalImpl { + fn dma_alloc(pages: usize, _direction: BufferDirection) -> (PhysAddr, NonNull) { + let start = alloc_frames(pages); + (start as usize, NonNull::new(start).unwrap()) + } + + unsafe fn dma_dealloc(paddr: PhysAddr, _vaddr: NonNull, pages: usize) -> i32 { + free_frames(paddr as *mut u8, pages); + 0 + } + + unsafe fn mmio_phys_to_virt(paddr: PhysAddr, _size: usize) -> NonNull { + NonNull::new(paddr as *mut u8).unwrap() + } + + unsafe fn share(buffer: NonNull<[u8]>, _direction: BufferDirection) -> PhysAddr { + let vaddr = buffer.as_ptr() as *mut u8 as usize; + vaddr + } + + unsafe fn unshare(_paddr: PhysAddr, _buffer: NonNull<[u8]>, _direction: BufferDirection) {} +} diff --git a/subsystems/drivers/src/input.rs b/subsystems/drivers/src/input.rs new file mode 100644 index 00000000..dda4ac8b --- /dev/null +++ b/subsystems/drivers/src/input.rs @@ -0,0 +1,108 @@ +use alloc::collections::VecDeque; +use alloc::sync::Arc; +use core::ptr::NonNull; +use log::info; + +use device_interface::{DeviceBase, InputDevice}; +use virtio_drivers::device::input::VirtIOInput; +use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; + +use crate::hal::HalImpl; +use ksync::Mutex; +use crate::{DRIVER_TASK, DriverTask}; + +pub struct VirtIOInputDriver { + inner: Mutex, +} + +unsafe impl Send for VirtIOInputDriver {} + +unsafe impl Sync for VirtIOInputDriver {} + +struct InputDriverInner { + max_events: u32, + driver: VirtIOInput, + events: VecDeque, + wait_queue: VecDeque>, +} + +impl VirtIOInputDriver { + fn new(driver: VirtIOInput, max_events: u32) -> Self { + let driver = VirtIOInputDriver { + inner: Mutex::new(InputDriverInner { + max_events, + driver, + events: VecDeque::with_capacity(max_events as usize), + wait_queue: VecDeque::new(), + }), + }; + driver + } + + pub fn from_addr(addr: usize, max_events: u32) -> Self { + let header = NonNull::new(addr as *mut VirtIOHeader).unwrap(); + let transport = unsafe { MmioTransport::new(header) }.unwrap(); + let input = VirtIOInput::::new(transport) + .expect("failed to create input driver"); + Self::new(input, max_events) + } +} + +impl InputDevice for VirtIOInputDriver { + fn is_empty(&self) -> bool { + let inner = self.inner.lock(); + inner.events.is_empty() + } + + fn read_event_with_block(&self) -> u64 { + loop { + { + let mut inner = self.inner.lock(); + if let Some(event) = inner.events.pop_front() { + return event; + } + // let process = current_task().unwrap(); + // process.update_state(TaskState::Waiting); + // inner.wait_queue.push_back(process.clone()); + let task = DRIVER_TASK.get().unwrap().get_task(); + task.to_wait(); + inner.wait_queue.push_back(task); + } // drop the lock + // schedule(); + DRIVER_TASK.get().unwrap().suspend(); + } + } + + fn read_event_without_block(&self) -> Option { + let mut inner = self.inner.lock(); + inner.events.pop_front() + } +} + +impl DeviceBase for VirtIOInputDriver { + fn hand_irq(&self) { + let mut inner = self.inner.lock(); + inner.driver.ack_interrupt(); + let mut count = 0; + while let Some(event) = inner.driver.pop_pending_event() { + let result = + (event.event_type as u64) << 48 | (event.code as u64) << 32 | (event.value) as u64; + info!("event: {:?}", event); + if inner.events.len() >= inner.max_events as usize { + // remove the first event + inner.events.pop_front(); + } + inner.events.push_back(result); + count += 1; + } + while !inner.wait_queue.is_empty() && count > 0 { + let task = inner.wait_queue.pop_front().unwrap(); + // process.update_state(TaskState::Ready); + // GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(process))); + task.to_wakeup(); + DRIVER_TASK.get().unwrap().put_task(task); + count -= 1; + } + info!("read {} events", count); + } +} diff --git a/subsystems/drivers/src/lib.rs b/subsystems/drivers/src/lib.rs new file mode 100644 index 00000000..ad3092e1 --- /dev/null +++ b/subsystems/drivers/src/lib.rs @@ -0,0 +1,39 @@ +#![no_std] +extern crate alloc; + +use alloc::boxed::Box; +use alloc::sync::Arc; +use downcast_rs::{DowncastSync, impl_downcast}; +use spin::Once; + +pub mod block_device; +pub mod gpu; +pub mod hal; +pub mod input; +pub mod net; +pub mod rtc; +pub mod uart; + + + + +pub trait DriverTask:Send+Sync+DowncastSync{ + fn to_wait(&self); + fn to_wakeup(&self); + fn have_signal(&self) -> bool; +} + +impl_downcast!(sync DriverTask); + +pub trait DriverWithTask:Send+Sync{ + fn get_task(&self) -> Arc; + fn put_task(&self,task:Arc); + fn suspend(&self); +} + + +static DRIVER_TASK:Once> = Once::new(); + +pub fn register_task_func(task_func:Box){ + DRIVER_TASK.call_once(||task_func); +} \ No newline at end of file diff --git a/subsystems/drivers/src/net.rs b/subsystems/drivers/src/net.rs new file mode 100644 index 00000000..36f8af7e --- /dev/null +++ b/subsystems/drivers/src/net.rs @@ -0,0 +1,68 @@ +use core::ptr::NonNull; + +use crate::hal::HalImpl; +use netcore::{KernelNetFunc, NetInstant}; +use timer::TimeSpec; +use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; +use virtio_net::VirtIONetDeviceWrapper; + +pub use loopback::LoopbackDev; +use crate::DRIVER_TASK; + +pub const NET_BUFFER_LEN: usize = 4096; +pub const NET_QUEUE_SIZE: usize = 128; + +pub struct VirtIONetDriver; + +impl VirtIONetDriver { + pub fn from_mmio( + addr: usize, + ) -> VirtIONetDeviceWrapper { + let header = NonNull::new(addr as *mut VirtIOHeader).unwrap(); + let transport = unsafe { MmioTransport::new(header) }.unwrap(); + let device = VirtIONetDeviceWrapper::new(transport, NET_BUFFER_LEN); + device + } +} + +#[derive(Debug, Default)] +pub struct NetNeedFunc; +#[derive(Debug, Default)] +pub struct NetNeedFuncEmpty; + +impl KernelNetFunc for NetNeedFuncEmpty { + fn now(&self) -> NetInstant { + let time_spec = TimeSpec::now(); + NetInstant { + micros: time_spec.tv_sec as i64 * 1000_000 + time_spec.tv_nsec as i64 / 1000, + } + } + + fn yield_now(&self) -> bool { + false + } +} + +impl KernelNetFunc for NetNeedFunc { + fn now(&self) -> NetInstant { + let time_spec = TimeSpec::now(); + NetInstant { + micros: time_spec.tv_sec as i64 * 1000_000 + time_spec.tv_nsec as i64 / 1000, + } + } + fn yield_now(&self) -> bool { + // use crate::task::current_task; + // use crate::task::do_suspend; + // do_suspend(); + DRIVER_TASK.get().unwrap().suspend(); + // interrupt by signal + // let task = current_task().unwrap(); + // let task_inner = task.access_inner(); + // let receiver = task_inner.signal_receivers.lock(); + // if receiver.have_signal() { + // return true; + // } + let task = DRIVER_TASK.get().unwrap().get_task(); + task.have_signal() + } +} diff --git a/subsystems/drivers/src/rtc.rs b/subsystems/drivers/src/rtc.rs new file mode 100644 index 00000000..d200e5c6 --- /dev/null +++ b/subsystems/drivers/src/rtc.rs @@ -0,0 +1,59 @@ +use alloc::format; +use alloc::string::String; +use log::trace; +use constants::io::RtcTime; +use device_interface::{DeviceBase, RtcDevice}; +use rtc::{LowRtcDevice, LowRtcDeviceExt}; + +type GFish = rtc::goldfish::GoldFishRtc; +pub struct GoldFishRtc { + gold_fish_rtc: GFish, +} + +impl GoldFishRtc{ + pub fn read_time_u64(&self) -> u64 { + self.gold_fish_rtc.read_time() + } + pub fn read_time_string(&self) -> String { + let time = self.gold_fish_rtc.read_time_fmt(); + format!( + "{:04}-{:02}-{:02} {:02}:{:02}:{:02}", + time.year, time.month, time.day, time.hour, time.minute, time.second + ) + } +} + +impl DeviceBase for GoldFishRtc { + fn hand_irq(&self) { + let alarm = self.gold_fish_rtc.read_alarm_fmt(); + let time = self.gold_fish_rtc.read_time_fmt(); + trace!("rtc interrupt, time: {:?}, alarm: {:?}", time, alarm); + self.gold_fish_rtc.clear_irq(); + self.gold_fish_rtc + .set_alarm(self.read_time_u64() + 1_000_000_000 * 5); + } +} + +impl RtcDevice for GoldFishRtc { + fn read_time(&self) -> RtcTime { + let time = self.gold_fish_rtc.read_time_fmt(); + RtcTime { + year: time.year, + wday: 0, + yday: 0, + mon: time.month as u32, + mday: time.day as u32, + hour: time.hour as u32, + min: time.minute as u32, + sec: time.second as u32, + isdst: 0, + } + } +} + +impl GoldFishRtc { + pub fn new(base_addr: usize) -> Self { + let gold_fish_rtc = GFish::new(base_addr); + Self { gold_fish_rtc } + } +} diff --git a/subsystems/drivers/src/uart.rs b/subsystems/drivers/src/uart.rs new file mode 100644 index 00000000..550a9e3d --- /dev/null +++ b/subsystems/drivers/src/uart.rs @@ -0,0 +1,176 @@ +pub use self::uart16550::Uart16550; +pub use self::uart8250::Uart8250; +use alloc::boxed::Box; +use alloc::collections::VecDeque; +use alloc::sync::Arc; +use device_interface::{DeviceBase, UartDevice}; +use ksync::Mutex; +use crate::{DRIVER_TASK, DriverTask}; + +pub trait LowUartDriver: Send + Sync { + fn _init(&mut self); + fn _put(&mut self, c: u8); + fn _read(&mut self) -> Option; +} + +mod uart8250 { + use crate::uart::LowUartDriver; + + pub struct Uart8250 { + uart_raw: uart8250::MmioUart8250<'static, u32>, + } + + unsafe impl Send for Uart8250 {} + + unsafe impl Sync for Uart8250 {} + + impl Uart8250 { + pub fn new(base_addr: usize) -> Self { + let uart_raw = unsafe { uart8250::MmioUart8250::::new(base_addr) }; + Uart8250 { uart_raw } + } + } + + impl LowUartDriver for Uart8250 { + fn _init(&mut self) { + self.uart_raw.enable_received_data_available_interrupt(); + } + + fn _put(&mut self, c: u8) { + loop { + if self.uart_raw.write_byte(c).is_ok() { + break; + } + } + } + + fn _read(&mut self) -> Option { + self.uart_raw.read_byte() + } + } +} + +mod uart16550 { + use crate::uart::LowUartDriver; + + pub struct Uart16550 { + uart_raw: &'static mut uart16550::Uart16550, + } + + unsafe impl Send for Uart16550 {} + + unsafe impl Sync for Uart16550 {} + + impl Uart16550 { + pub fn new(base_addr: usize) -> Self { + let uart_raw = unsafe { &mut *(base_addr as *mut uart16550::Uart16550) }; + Uart16550 { uart_raw } + } + } + + impl LowUartDriver for Uart16550 { + fn _init(&mut self) { + use uart16550::InterruptTypes; + let ier = self.uart_raw.ier(); + let inter = InterruptTypes::ZERO; + ier.write(inter.enable_rda()); + } + + fn _put(&mut self, c: u8) { + self.uart_raw.write(&[c]); + } + + fn _read(&mut self) -> Option { + let mut buf = [0]; + let r = self.uart_raw.read(&mut buf); + if r == 0 { + None + } else { + Some(buf[0]) + } + } + } +} + +pub struct Uart { + inner: Mutex<(Box, UartInner)>, +} + +struct UartInner { + rx_buf: VecDeque, + wait_queue: VecDeque>, +} + +impl Uart { + pub fn new(uart_raw: Box) -> Self { + let mut uart_raw = uart_raw; + uart_raw._init(); + let inner = UartInner { + rx_buf: VecDeque::new(), + wait_queue: VecDeque::new(), + }; + Uart { + inner: Mutex::new((uart_raw, inner)), + } + } +} + +impl UartDevice for Uart { + fn put(&self, c: u8) { + let mut inner = self.inner.lock(); + inner.0._put(c); + } + fn get(&self) -> Option { + loop { + let mut inner = self.inner.lock(); + if inner.1.rx_buf.is_empty() { + // let current_process = current_task().unwrap(); + // current_process.update_state(TaskState::Waiting); + let task = DRIVER_TASK.get().unwrap().get_task(); + task.to_wait(); + inner.1.wait_queue.push_back(task); + drop(inner); + DRIVER_TASK.get().unwrap().suspend(); + } else { + return inner.1.rx_buf.pop_front(); + } + } + } + + fn put_bytes(&self, bytes: &[u8]) { + for &c in bytes { + if c == b'\n' { + self.put(b'\r'); + } + self.put(c); + } + } + + fn have_data_to_get(&self) -> bool { + !self.inner.lock().1.rx_buf.is_empty() + } + + fn have_space_to_put(&self) -> bool { + true + } +} + +impl DeviceBase for Uart { + fn hand_irq(&self) { + loop { + let mut inner = self.inner.lock(); + if let Some(c) = inner.0._read() { + inner.1.rx_buf.push_back(c); + if !inner.1.wait_queue.is_empty() { + let task = inner.1.wait_queue.pop_front().unwrap(); + // task.update_state(TaskState::Ready); + // GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); + task.to_wakeup(); + DRIVER_TASK.get().unwrap().put_task(task); + } + } else { + break; + } + } + } +} diff --git a/subsystems/interrupt/Cargo.toml b/subsystems/interrupt/Cargo.toml index 0010297f..dfbebdfa 100644 --- a/subsystems/interrupt/Cargo.toml +++ b/subsystems/interrupt/Cargo.toml @@ -12,6 +12,7 @@ ksync = { path = "../ksync" } arch = { path = "../arch" } config = { path = "../config" } device_interface = { path = "../device_interface" } +platform = { path = "../platform"} [features] diff --git a/subsystems/interrupt/src/lib.rs b/subsystems/interrupt/src/lib.rs index 1498f198..dec7457d 100644 --- a/subsystems/interrupt/src/lib.rs +++ b/subsystems/interrupt/src/lib.rs @@ -12,6 +12,7 @@ use plic::{Mode, PLIC}; use arch::hart_id; use config::CPU_NUM; use device_interface::DeviceBase; +use platform::println; mod ext_interrupt; pub mod record; @@ -20,11 +21,11 @@ pub static PLIC: Once> = Once::new(); pub static DEVICE_TABLE: Mutex>> = Mutex::new(BTreeMap::new()); -pub fn init_plic(addr: usize) { +pub fn init_plic(plic_addr: usize) { #[cfg(feature = "qemu")] { let privileges = [2; CPU_NUM]; - let plic = PLIC::new(addr, privileges); + let plic = PLIC::new(plic_addr, privileges); PLIC.call_once(|| plic); println!("Init qemu plic success"); } @@ -34,7 +35,7 @@ pub fn init_plic(addr: usize) { // core 0 don't have S mode privileges[0] = 1; println!("PLIC context: {:?}", privileges); - let plic = PLIC::new(addr, privileges); + let plic = PLIC::new(plic_addr, privileges); PLIC.call_once(|| plic); println!("Init hifive or vf2 plic success"); } @@ -46,7 +47,7 @@ pub fn register_device_to_plic(irq: usize, device: Arc) { table.insert(irq, device); let hard_id = hart_id(); println!( - "plic enable irq {} for hart {}, priority {}", + "PLIC enable irq {} for hart {}, priority {}", irq, hard_id, 1 ); let plic = PLIC.get().unwrap(); diff --git a/subsystems/mem/Cargo.toml b/subsystems/mem/Cargo.toml index fe5ff36e..207e1a37 100644 --- a/subsystems/mem/Cargo.toml +++ b/subsystems/mem/Cargo.toml @@ -20,13 +20,13 @@ spin = "0" page-table = { git = "https://github.com/os-module/page-table.git", branch = "dev" } -page_table = { git = "https://github.com/rcore-os/arceos",rev = "7eeebc5" } -memory_addr = { git = "https://github.com/rcore-os/arceos",rev = "7eeebc5" } +#page_table = { git = "https://github.com/rcore-os/arceos",rev = "7eeebc5" } +#memory_addr = { git = "https://github.com/rcore-os/arceos",rev = "7eeebc5" } [features] -default = ["pager_buddy","talloc"] +default = ["pager_bitmap","talloc"] pager_buddy = ["pager/buddy"] pager_bitmap = ["pager/bitmap"] slab = ["rslab"] diff --git a/subsystems/mem/src/frame.rs b/subsystems/mem/src/frame.rs index 58576bc7..fdc24f3f 100644 --- a/subsystems/mem/src/frame.rs +++ b/subsystems/mem/src/frame.rs @@ -1,9 +1,14 @@ use alloc::format; +use core::mem::forget; +use core::ops::{Deref, DerefMut}; +use log::trace; +use page_table::addr::{PhysAddr, VirtAddr}; use config::{FRAME_BITS, FRAME_SIZE}; use ksync::Mutex; -use page_table::PagingIf; +use page_table::table::PagingIf; use pager::{PageAllocator, PageAllocatorExt}; use platform::println; +use crate::manager::FRAME_REF_MANAGER; #[cfg(feature = "pager_bitmap")] pub static FRAME_ALLOCATOR: Mutex> = Mutex::new(pager::Bitmap::new()); @@ -45,19 +50,90 @@ pub fn free_frames(addr: *mut u8, num: usize) { .expect(format!("free frame start:{:#x},num:{} failed", start, num).as_str()); } + +#[derive(Debug)] +pub struct FrameTracker { + start: usize, + size: usize, +} + +impl FrameTracker { + pub fn new(start: usize, size:usize) -> Self { + Self { start ,size} + } + pub fn from_addr(addr: usize,size:usize) -> Self { + assert_eq!(addr % FRAME_SIZE, 0); + Self::new(addr >> FRAME_BITS,size) + } + pub fn start(&self) -> usize { + self.start << FRAME_BITS + } + pub fn end(&self) -> usize { + self.start() + FRAME_SIZE * self.size + } + pub fn as_ptr(&self) -> *mut u8 { + self.start() as *mut u8 + } +} + +impl Drop for FrameTracker { + fn drop(&mut self) { + trace!("drop frame tracker: {:#x?}", self); + let mut manager = FRAME_REF_MANAGER.lock(); + for i in 0..self.size { + let _id = manager.dec_ref(self.start + i); + } + } +} + +impl Deref for FrameTracker { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + unsafe { core::slice::from_raw_parts(self.start() as *const u8, FRAME_SIZE*self.size) } + } +} +impl DerefMut for FrameTracker { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { core::slice::from_raw_parts_mut(self.start() as *mut u8, FRAME_SIZE*self.size) } + } +} + + +pub fn alloc_frame_trackers(count: usize) -> FrameTracker { + let frame = FRAME_ALLOCATOR.lock().alloc_pages(count, FRAME_SIZE) + .expect(format!("alloc {} frame failed", count).as_str()); + trace!("alloc frame [{}] start page: {:#x}", count, frame); + for i in 0..count { + let refs = FRAME_REF_MANAGER.lock().add_ref(frame + i); + assert_eq!(refs, 1) + } + FrameTracker::new(frame,count) +} + + pub struct VmmPageAllocator; impl PagingIf for VmmPageAllocator { - fn alloc_frame() -> Option { - let start_addr = alloc_frames(1); - Some(memory_addr::PhysAddr::from(start_addr as usize)) + fn alloc_frame() -> Option { + let frame = alloc_frame_trackers(1); + let start_addr = frame.start(); + forget(frame); + Some(PhysAddr::from(start_addr)) + } + + fn dealloc_frame(paddr: PhysAddr) { + FrameTracker::from_addr(paddr.as_usize(),1); } - fn dealloc_frame(paddr: memory_addr::PhysAddr) { - free_frames(paddr.as_usize() as *mut u8, 1); + fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { + VirtAddr::from(paddr.as_usize()) } - fn phys_to_virt(paddr: memory_addr::PhysAddr) -> memory_addr::VirtAddr { - memory_addr::VirtAddr::from(paddr.as_usize()) + fn alloc_contiguous_frames(size: usize) -> Option { + let frames = alloc_frame_trackers(size); + let start_addr = frames.start(); + forget(frames); + Some(PhysAddr::from(start_addr)) } } diff --git a/subsystems/mem/src/heap.rs b/subsystems/mem/src/heap.rs index 8aa2c719..648f52d3 100644 --- a/subsystems/mem/src/heap.rs +++ b/subsystems/mem/src/heap.rs @@ -67,5 +67,7 @@ impl HeapAllocator { unsafe { init_slab_system(FRAME_SIZE, 64); } + #[cfg(any(feature = "talc",feature = "buddy"))] + println!("Kernel Heap size: {:#x}MB", heap.len() / 1024 / 1024); } } diff --git a/subsystems/mem/src/lib.rs b/subsystems/mem/src/lib.rs index 2ce23641..bfb338bf 100644 --- a/subsystems/mem/src/lib.rs +++ b/subsystems/mem/src/lib.rs @@ -1,27 +1,37 @@ #![no_std] extern crate alloc; - +#[macro_use] +extern crate platform; use arch::activate_paging_mode; -use config::{FRAME_BITS, KERNEL_HEAP_SIZE}; +use config::{FRAME_BITS}; use heap::HeapAllocator; - +use platform::config::HEAP_SIZE; mod frame; mod heap; mod vmm; +mod manager; + +pub use frame::{alloc_frames, free_frames,FrameTracker,VmmPageAllocator,alloc_frame_trackers}; -pub use frame::{alloc_frames, free_frames}; +pub use vmm::{map_region_to_kernel,query_kernel_space,kernel_pgd,kernel_satp}; +pub use manager::FRAME_REF_MANAGER; #[global_allocator] static HEAP_ALLOCATOR: HeapAllocator = HeapAllocator::new(); #[cfg(any(feature = "talloc", feature = "buddy"))] -static mut KERNEL_HEAP: [u8; KERNEL_HEAP_SIZE] = [0; KERNEL_HEAP_SIZE]; +static mut KERNEL_HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE]; + +extern "C"{ + fn ekernel(); +} -pub fn init_memory_system(memory_start: usize, memory_end: usize, is_first_cpu: bool) { +pub fn init_memory_system( memory_end: usize, is_first_cpu: bool) { if is_first_cpu { - frame::init_frame_allocator(memory_start, memory_end); + frame::init_frame_allocator(ekernel as usize, memory_end); println!("Frame allocator init success"); + #[cfg(any(feature = "talloc", feature = "buddy"))] HEAP_ALLOCATOR.init(unsafe { &mut KERNEL_HEAP }); #[cfg(feature = "talloc")] { diff --git a/subsystems/mem/src/manager.rs b/subsystems/mem/src/manager.rs new file mode 100644 index 00000000..b27250b1 --- /dev/null +++ b/subsystems/mem/src/manager.rs @@ -0,0 +1,54 @@ +use alloc::collections::BTreeMap; +use log::trace; +use pager::PageAllocator; +use spin::Lazy; +use ksync::Mutex; +use crate::frame::FRAME_ALLOCATOR; + + +pub static FRAME_REF_MANAGER: Lazy> = + Lazy::new(|| Mutex::new(FrameRefManager::new())); + + +#[derive(Debug)] +pub struct FrameRefManager { + record: BTreeMap, +} + +impl FrameRefManager { + pub fn new() -> Self { + Self { + record: BTreeMap::new(), + } + } + pub fn add_ref(&mut self, id: usize) -> usize { + if let Some(count) = self.record.get_mut(&id) { + *count += 1; + *count + } else { + self.record.insert(id, 1); + 1 + } + } + pub fn dec_ref(&mut self, id: usize) -> Option { + if let Some(count) = self.record.get_mut(&id) { + *count -= 1; + let now_count = *count; + if *count == 0 { + self.record.remove(&id); + trace!("free frame:{:#x}", id); + FRAME_ALLOCATOR.lock().free(id, 0).unwrap(); + } + return Some(now_count); + } else { + panic!("dec page {:#x?} ref error", id); + } + } + pub fn get_ref(&self, id: usize) -> usize { + if let Some(count) = self.record.get(&id) { + *count + } else { + panic!("get {} ref error", id); + } + } +} diff --git a/subsystems/mem/src/vmm.rs b/subsystems/mem/src/vmm.rs index 42cf671f..21a65be5 100644 --- a/subsystems/mem/src/vmm.rs +++ b/subsystems/mem/src/vmm.rs @@ -1,3 +1,14 @@ +use alloc::sync::Arc; +use core::sync::atomic::AtomicUsize; +use page_table::addr::{PhysAddr, VirtAddr}; +use page_table::pte::MappingFlags; +use page_table::table::Sv39PageTable; +use spin::Lazy; +use config::{FRAME_BITS, FRAME_SIZE, TRAMPOLINE}; +use ksync::RwLock; +use platform::config::MMIO; +use crate::frame::VmmPageAllocator; + #[allow(unused)] extern "C" { fn stext(); @@ -8,11 +19,149 @@ extern "C" { fn strampoline(); fn sinit(); fn einit(); - // fn kernel_eh_frame(); // fn kernel_eh_frame_end(); // fn kernel_eh_frame_hdr(); // fn kernel_eh_frame_hdr_end(); } -pub fn build_kernel_address_space(memory_end: usize) {} +fn kernel_info(memory_end: usize) { + println!( + "kernel text: {:#x}-{:#x}", + stext as usize, srodata as usize + ); + println!( + "kernel rodata: {:#x}-{:#x}", + srodata as usize, sdata as usize + ); + println!( + "kernel init_array: {:#x}-{:#x}", + sinit as usize, einit as usize + ); + println!( + "kernel data: {:#x}-{:#x}", + sdata as usize, sbss as usize + ); + println!( + "kernel bss: {:#x}-{:#x}", + sbss as usize, ekernel as usize + ); + // println!("kernel eh_frame: {:#x}-{:#x}", kernel_eh_frame as usize, kernel_eh_frame_end as usize); + // println!("kernel eh_frame_hdr: {:#x}-{:#x}", kernel_eh_frame_hdr as usize, kernel_eh_frame_hdr_end as usize); + println!( + "kernel heap: {:#x}-{:#x}", + ekernel as usize, memory_end + ); +} + + +pub static KERNEL_SPACE: Lazy>>> = Lazy::new(|| { + Arc::new(RwLock::new( + Sv39PageTable::::try_new().unwrap(), + )) +}); + +pub fn build_kernel_address_space(memory_end: usize) { + kernel_info(memory_end); + let mut kernel_space = KERNEL_SPACE.write(); + kernel_space + .map_region( + VirtAddr::from(stext as usize), + PhysAddr::from(stext as usize), + srodata as usize - stext as usize, + "RXVAD".into(), + true, + ) + .unwrap(); + kernel_space + .map_region( + VirtAddr::from(srodata as usize), + PhysAddr::from(srodata as usize), + sdata as usize - srodata as usize, + "RVAD".into(), + true, + ) + .unwrap(); + kernel_space + .map_region( + VirtAddr::from(sdata as usize), + PhysAddr::from(sdata as usize), + sbss as usize - sdata as usize, + "RWVAD".into(), + true, + ) + .unwrap(); + kernel_space + .map_region( + VirtAddr::from(sbss as usize), + PhysAddr::from(sbss as usize), + ekernel as usize - sbss as usize, + "RWVAD".into(), + true, + ) + .unwrap(); + kernel_space + .map_region( + VirtAddr::from(ekernel as usize), + PhysAddr::from(ekernel as usize), + memory_end - ekernel as usize, + "RWVAD".into(), + true, + ) + .unwrap(); + kernel_space + .map_region( + VirtAddr::from(TRAMPOLINE), + PhysAddr::from(strampoline as usize), + FRAME_SIZE, + "RXVAD".into(), + true, + ) + .unwrap(); + for pair in MMIO { + kernel_space + .map_region( + VirtAddr::from(pair.0), + PhysAddr::from(pair.0), + pair.1, + "RWVAD".into(), + true, + ) + .unwrap(); + println!("map mmio: {:#x?}-{:#x?}", pair.0, pair.0 + pair.1); + } +} + +static KERNEL_MAP_MAX: AtomicUsize = AtomicUsize::new(0); +pub fn kernel_pgd() -> usize { + KERNEL_SPACE.read().root_paddr().as_usize() +} + +pub fn kernel_satp() -> usize { + 8usize << 60 | (KERNEL_SPACE.read().root_paddr().as_usize() >> FRAME_BITS) +} + +pub fn alloc_kernel_free_region(size: usize) -> usize { + assert!(size > 0 && size % FRAME_SIZE == 0); + KERNEL_MAP_MAX.fetch_add(size, core::sync::atomic::Ordering::SeqCst) +} + +pub fn map_region_to_kernel(addr: usize, size: usize, flags: MappingFlags){ + let mut kernel_space = KERNEL_SPACE.write(); + kernel_space + .map_region( + VirtAddr::from(addr), + PhysAddr::from(addr), + size, + flags, + true, + ) + .unwrap(); +} +pub fn query_kernel_space(addr: usize) -> Option { + let kernel_space = KERNEL_SPACE.read(); + kernel_space + .query(VirtAddr::from(addr)) + .ok() + .map(|(x, _, _)| x.as_usize()) +} diff --git a/subsystems/platform/Cargo.toml b/subsystems/platform/Cargo.toml index e0ff57b5..d7e4543a 100644 --- a/subsystems/platform/Cargo.toml +++ b/subsystems/platform/Cargo.toml @@ -10,12 +10,17 @@ log = "0" arch = { path = "../arch" } config = { path = "../config" } ksync = { path = "../ksync" } +spin = "0" +preprint = "0.1.0" +basemachine = { path = "../../dep/basemachine" } [features] default = ["qemu_riscv"] qemu_riscv = [] -starfive2_riscv = [] -hifive_riscv = [] \ No newline at end of file +vf2 = [] +hifive = [] + +smp = [] \ No newline at end of file diff --git a/subsystems/platform/src/common_riscv/boot.rs b/subsystems/platform/src/common_riscv/boot.rs index 86f2ab50..e5675c71 100644 --- a/subsystems/platform/src/common_riscv/boot.rs +++ b/subsystems/platform/src/common_riscv/boot.rs @@ -1,4 +1,4 @@ -use config::{CPU_NUM, STACK_SIZE}; +use config::{CPU_NUM, STACK_SIZE, STACK_SIZE_BITS}; use core::arch::asm; #[link_section = ".bss.stack"] @@ -16,20 +16,45 @@ extern "C" fn _start() { mv tp, a0 mv gp, a1 add t0, a0, 1 - slli t0, t0, 16 + slli t0, t0, {stack_size_bits} la sp, {boot_stack} add sp, sp, t0 call clear_bss mv a0, tp mv a1, gp + call {platform_init} + ", + stack_size_bits = const STACK_SIZE_BITS, + boot_stack = sym STACK, + platform_init = sym crate::platform_init, + options(noreturn) + ); + } +} + +#[naked] +#[no_mangle] +extern "C" fn _start_secondary() { + unsafe { + asm!("\ + mv tp, a0 + mv gp, a1 + add t0, a0, 1 + slli t0, t0, {stack_size_bits} + la sp, {boot_stack} + add sp, sp, t0 + mv a0, tp + mv a1, gp call main ", + stack_size_bits = const STACK_SIZE_BITS, boot_stack = sym STACK, options(noreturn) ); } } + extern "C" { fn sbss(); fn ebss(); diff --git a/subsystems/platform/src/common_riscv/sbi.rs b/subsystems/platform/src/common_riscv/sbi.rs index 39458c76..2712cca6 100644 --- a/subsystems/platform/src/common_riscv/sbi.rs +++ b/subsystems/platform/src/common_riscv/sbi.rs @@ -1,3 +1,4 @@ +#![allow(unused)] //! SBI 调用接口 use core::arch::asm; diff --git a/subsystems/platform/src/console.rs b/subsystems/platform/src/console.rs index 7161e341..5bce7a7c 100644 --- a/subsystems/platform/src/console.rs +++ b/subsystems/platform/src/console.rs @@ -1,14 +1,18 @@ use core::fmt::{Arguments, Result, Write}; +use preprint::Print; +use ksync::Mutex; +/// 系统启动初期使用的输出函数 #[macro_export] -macro_rules! xprint { +macro_rules! print { ($($arg:tt)*) => { let hard_id = arch::hart_id(); $crate::console::__print(format_args!("[{}] {}", hard_id, format_args!($($arg)*))) }; } +/// 系统启动初期使用的输出函数 #[macro_export] -macro_rules! xprintln { +macro_rules! println { () => ($crate::print!("\n")); ($fmt:expr) => ($crate::print!(concat!($fmt, "\n"))); ($fmt:expr, $($arg:tt)*) => ($crate::print!( @@ -27,16 +31,34 @@ impl Write for Stdout { } } +static STDOUT: Mutex = Mutex::new(Stdout); + /// 输出函数 /// 对参数进行输出 主要使用在输出相关的宏中 如println #[doc(hidden)] pub fn __print(args: Arguments) { - Stdout.write_fmt(args).unwrap(); + STDOUT.lock().write_fmt(args).unwrap(); } /// 系统启动初期使用的输出函数 /// /// 在riscv平台上,由于没有实现串口驱动,所以在系统启动初期使用SBI进行输出 -pub fn early_console_write(s: &str) { +pub fn console_write(s: &str) { Stdout.write_str(s).unwrap(); } + + +pub struct PrePrint; + +impl Print for PrePrint { + fn print(&self, args: Arguments) { + print!("{}", args); + } +} + +impl Write for PrePrint { + fn write_str(&mut self, s: &str) -> Result { + print!("{}", s); + Ok(()) + } +} \ No newline at end of file diff --git a/subsystems/platform/src/hifive_riscv/config.rs b/subsystems/platform/src/hifive_riscv/config.rs new file mode 100644 index 00000000..c3ae7ac9 --- /dev/null +++ b/subsystems/platform/src/hifive_riscv/config.rs @@ -0,0 +1,8 @@ +pub const CLOCK_FREQ: usize = 100_0000; +pub const BLOCK_CACHE_FRAMES: usize = 1024 * 4 * 4; +pub const HEAP_SIZE: usize = 0x40_00000; //64M + + +pub const MMIO: &[(usize, usize)] = &[ + (0xc000000, 0x4000000), //PLIC +]; \ No newline at end of file diff --git a/subsystems/platform/src/hifive_riscv/mod.rs b/subsystems/platform/src/hifive_riscv/mod.rs index 5493eea0..54676c64 100644 --- a/subsystems/platform/src/hifive_riscv/mod.rs +++ b/subsystems/platform/src/hifive_riscv/mod.rs @@ -1,12 +1,10 @@ -use core::iter::Once; +pub mod config; -#[repr(align(4))] -struct Wrapper(T); +use spin::Once; -const FDT: &[u8] = &Wrapper(*include_bytes!( +const FDT: &[u8] = include_bytes!( "../../../../tools/hifive-unmatched-a00.dtb" -)) -.0; +); pub static DTB: Once = Once::new(); @@ -22,7 +20,6 @@ pub fn set_timer(time: usize) { pub fn system_shutdown() -> ! { crate::common_riscv::sbi::system_shutdown(); - loop {} } /// Warp sbi SBI_CONSOLE_PUT_CHAR call diff --git a/subsystems/platform/src/lib.rs b/subsystems/platform/src/lib.rs index a1cfe7a5..6201052a 100644 --- a/subsystems/platform/src/lib.rs +++ b/subsystems/platform/src/lib.rs @@ -1,50 +1,102 @@ #![no_std] #![feature(naked_functions)] - +#![feature(asm_const)] extern crate alloc; #[macro_use] pub mod console; mod common_riscv; -#[cfg(feature = "hifive_riscv")] +#[cfg(feature = "hifive")] mod hifive_riscv; -mod logger; + + +use spin::Once; +pub use basemachine::MachineInfo as PlatformInfo; +use ::config::CPU_NUM; + #[cfg(feature = "qemu_riscv")] mod qemu_riscv; -#[cfg(feature = "starfive2_riscv")] +#[cfg(feature = "vf2")] mod starfive2_riscv; +pub mod logging; #[cfg(feature = "qemu_riscv")] use qemu_riscv::console_putchar; #[cfg(feature = "qemu_riscv")] -pub use qemu_riscv::system_shutdown; +pub use qemu_riscv::{config, set_timer, system_shutdown}; -#[cfg(feature = "starfive2_riscv")] +#[cfg(feature = "vf2")] use starfive2_riscv::console_putchar; -#[cfg(feature = "starfive2_riscv")] -pub use starfive2_riscv::system_shutdown; +#[cfg(feature = "vf2")] +pub use starfive2_riscv::{config, set_timer, system_shutdown}; -#[cfg(feature = "hifive_riscv")] -pub use hifive_riscv::system_shutdown; +#[cfg(feature = "hifive")] +use hifive_riscv::console_putchar; -#[cfg(feature = "hifive_riscv")] -pub use hifive_riscv::console_putchar; +#[cfg(feature = "hifive")] +pub use hifive_riscv::{config, set_timer, system_shutdown}; +use crate::common_riscv::sbi::hart_start; +use crate::console::PrePrint; -pub fn platform_init(dtb: Option) { - #[cfg(feature = "hifive_riscv")] - hifive_riscv::init_dtb(dtb); - #[cfg(feature = "starfive2_riscv")] - starfive2_riscv::init_dtb(dtb); + + +#[no_mangle] +pub fn platform_init(hart_id:usize,dtb: usize) { + println!("{}",::config::FLAG); + #[cfg(feature = "hifive")] + hifive_riscv::init_dtb(Some(dtb)); + #[cfg(feature = "vf2")] + starfive2_riscv::init_dtb(Some(dtb)); #[cfg(feature = "qemu_riscv")] - qemu_riscv::init_dtb(dtb); - logger::init_logger(); + qemu_riscv::init_dtb(Some(dtb)); + let machine_info = basemachine::machine_info_from_dtb(platform_dtb_ptr()); + MACHINE_INFO.call_once(|| machine_info); + logging::init_logger(); + preprint::init_print(&PrePrint); + #[cfg(feature = "smp")] + init_other_hart(hart_id); + unsafe{ + main(hart_id) + } +} + + +/// 唤醒其它核 +/// +/// 对于qemu来说,只需要工具所有的核都是一样的,因此从严号核开始唤醒。 +/// 对于visionfive2/unmatched 来说,0号核只有M态,因此不进行唤醒 +fn init_other_hart(hart_id: usize) { + let start_hart = if cfg!(any(feature = "vf2", feature = "hifive")){ + 1 + } else { + 0 + }; + for i in start_hart..CPU_NUM { + if i != hart_id { + let res = hart_start(i, _start_secondary as usize, 0); + assert_eq!(res.error, 0); + } + } +} + + +extern "C" { + fn main(hart_id: usize); + fn _start_secondary(); } + pub fn platform_dtb_ptr() -> usize { - #[cfg(feature = "hifive_riscv")] - return hifive_riscv::DTB.get().unwrap(); - #[cfg(feature = "starfive2_riscv")] - return starfive2_riscv::DTB.get().unwrap(); + #[cfg(feature = "hifive")] + return *hifive_riscv::DTB.get().unwrap(); + #[cfg(feature = "vf2")] + return *starfive2_riscv::DTB.get().unwrap(); #[cfg(feature = "qemu_riscv")] - return qemu_riscv::DTB.get().unwrap(); + return *qemu_riscv::DTB.get().unwrap(); +} + +static MACHINE_INFO: Once = Once::new(); + +pub fn platform_machine_info()->PlatformInfo{ + MACHINE_INFO.get().unwrap().clone() } diff --git a/subsystems/platform/src/logger.rs b/subsystems/platform/src/logging.rs similarity index 89% rename from subsystems/platform/src/logger.rs rename to subsystems/platform/src/logging.rs index 5be30879..f69ec6ac 100644 --- a/subsystems/platform/src/logger.rs +++ b/subsystems/platform/src/logging.rs @@ -1,41 +1,42 @@ -use crate::xprintln; -use log::{self, Level, LevelFilter, Log, Metadata, Record}; -struct SimpleLogger; - -impl Log for SimpleLogger { - fn enabled(&self, _metadata: &Metadata) -> bool { - true - } - fn log(&self, record: &Record) { - if !self.enabled(record.metadata()) { - return; - } - let color = match record.level() { - Level::Error => 31, // Red - Level::Warn => 93, // BrightYellow - Level::Info => 35, // Blue - Level::Debug => 32, // Green - Level::Trace => 90, // BrightBlack - }; - xprintln!( - "\u{1B}[{}m[{:>1}] {}\u{1B}[0m", - color, - record.level(), - record.args(), - ); - } - fn flush(&self) {} -} - -pub fn init_logger() { - xprintln!("Init logger {:?}", option_env!("LOG")); - log::set_logger(&SimpleLogger).unwrap(); - log::set_max_level(match option_env!("LOG") { - Some("ERROR") => LevelFilter::Error, - Some("WARN") => LevelFilter::Warn, - Some("INFO") => LevelFilter::Info, - Some("DEBUG") => LevelFilter::Debug, - Some("TRACE") => LevelFilter::Trace, - _ => LevelFilter::Off, - }); -} +use log::{self, Level, LevelFilter, Log, Metadata, Record}; + + +struct SimpleLogger; + +impl Log for SimpleLogger { + fn enabled(&self, _metadata: &Metadata) -> bool { + true + } + fn log(&self, record: &Record) { + if !self.enabled(record.metadata()) { + return; + } + let color = match record.level() { + Level::Error => 31, // Red + Level::Warn => 93, // BrightYellow + Level::Info => 35, // Blue + Level::Debug => 32, // Green + Level::Trace => 90, // BrightBlack + }; + println!( + "\u{1B}[{}m[{:>1}] {}\u{1B}[0m", + color, + record.level(), + record.args(), + ); + } + fn flush(&self) {} +} + +pub fn init_logger() { + println!("Init logger {:?}", option_env!("LOG")); + log::set_logger(&SimpleLogger).unwrap(); + log::set_max_level(match option_env!("LOG") { + Some("ERROR") => LevelFilter::Error, + Some("WARN") => LevelFilter::Warn, + Some("INFO") => LevelFilter::Info, + Some("DEBUG") => LevelFilter::Debug, + Some("TRACE") => LevelFilter::Trace, + _ => LevelFilter::Off, + }); +} diff --git a/subsystems/platform/src/qemu_riscv/config.rs b/subsystems/platform/src/qemu_riscv/config.rs new file mode 100644 index 00000000..c0981e95 --- /dev/null +++ b/subsystems/platform/src/qemu_riscv/config.rs @@ -0,0 +1,14 @@ +pub const CLOCK_FREQ: usize = 1250_0000; +pub const BLOCK_CACHE_FRAMES: usize = 1024 * 4 * 4; +pub const HEAP_SIZE: usize = 0x26_00000; // (32+6)MB + + + +/// qemu的设备地址空间 +pub const MMIO: &[(usize, usize)] = &[ + (0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine + (0x2000000, 0x10000), + (0xc00_0000, 0x21_0000), // VIRT_PLIC in virt machine + (0x1000_0000, 0x9000), // VIRT_UART0 with GPU in virt machine + (0x3000_0000, 0x1000_0000), +]; diff --git a/subsystems/platform/src/qemu_riscv/mod.rs b/subsystems/platform/src/qemu_riscv/mod.rs index 7ba465c1..3777ff4b 100644 --- a/subsystems/platform/src/qemu_riscv/mod.rs +++ b/subsystems/platform/src/qemu_riscv/mod.rs @@ -1,4 +1,6 @@ -use core::iter::Once; +pub mod config; + +use spin::Once; pub static DTB: Once = Once::new(); @@ -14,7 +16,6 @@ pub fn set_timer(time: usize) { pub fn system_shutdown() -> ! { crate::common_riscv::sbi::system_shutdown(); - loop {} } /// Warp sbi SBI_CONSOLE_PUT_CHAR call diff --git a/subsystems/platform/src/starfive2_riscv/config.rs b/subsystems/platform/src/starfive2_riscv/config.rs new file mode 100644 index 00000000..f4422f16 --- /dev/null +++ b/subsystems/platform/src/starfive2_riscv/config.rs @@ -0,0 +1,11 @@ +pub const CLOCK_FREQ: usize = 400_0000; +pub const BLOCK_CACHE_FRAMES: usize = 1024 * 4 * 4; +pub const HEAP_SIZE: usize = 0x40_00000; + +/// vf2的设备地址空间 + +pub const MMIO: &[(usize, usize)] = &[ + (0x17040000, 0x10000), // RTC + (0xc000000, 0x4000000), //PLIC + (0x00_1000_0000, 0x10000), // UART +]; diff --git a/subsystems/platform/src/starfive2_riscv/mod.rs b/subsystems/platform/src/starfive2_riscv/mod.rs index f0fab6c2..1e3f62a4 100644 --- a/subsystems/platform/src/starfive2_riscv/mod.rs +++ b/subsystems/platform/src/starfive2_riscv/mod.rs @@ -1,12 +1,10 @@ -use core::iter::Once; +pub mod config; -#[repr(align(4))] -struct Wrapper(T); +use spin::Once; -pub const FDT: &[u8] = &Wrapper(*include_bytes!( +pub const FDT: &[u8] = include_bytes!( "../../../../tools/jh7110-visionfive-v2.dtb" -)) -.0; +); pub static DTB: Once = Once::new(); @@ -22,7 +20,6 @@ pub fn set_timer(time: usize) { pub fn system_shutdown() -> ! { crate::common_riscv::sbi::system_shutdown(); - loop {} } /// Warp sbi SBI_CONSOLE_PUT_CHAR call diff --git a/subsystems/timer/Cargo.toml b/subsystems/timer/Cargo.toml new file mode 100644 index 00000000..c220d29b --- /dev/null +++ b/subsystems/timer/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "timer" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +arch = { path = "../arch" } +config = { path = "../config" } +platform = { path = "../platform" } +constants = { path = "../constants" } +vfscore = { git = "https://github.com/os-module/rvfs.git", features = [ + "linux_error", +] } \ No newline at end of file diff --git a/subsystems/timer/src/lib.rs b/subsystems/timer/src/lib.rs new file mode 100644 index 00000000..ecb19824 --- /dev/null +++ b/subsystems/timer/src/lib.rs @@ -0,0 +1,131 @@ +#![no_std] + +use vfscore::utils::VfsTimeSpec; +use constants::sys::TimeVal; +use platform::config::CLOCK_FREQ; +/// 每秒包含的毫秒数 +const MSEC_PER_SEC: usize = 1000; +/// 程序运行时间 +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Times { + /// the ticks of user mode + pub tms_utime: usize, + /// the ticks of kernel mode + pub tms_stime: usize, + /// the ticks of user mode of child process + pub tms_cutime: usize, + /// the ticks of kernel mode of child process + pub tms_cstime: usize, +} + +impl Times { + pub fn new() -> Self { + Self { + tms_utime: 0, + tms_stime: 0, + tms_cutime: 0, + tms_cstime: 0, + } + } +} + + +/// 实现 `TimeNow` 特征的时钟结构,能够通过调用 `now` 方法得出 表示当前的 cpu 时间的一个本类型时钟 +pub trait TimeNow { + fn now() -> Self; +} + +/// 实现 `ToClock` 特征的时钟结构,能够将所表示的时间间隔,转换为 cpu 时钟 +pub trait ToClock { + fn to_clock(&self) -> usize; +} + +/// 实现 `TimeFromFreq` 特征的时钟结构,能够实现从 cpu时钟跳变的次数 初始化一个本类型的时钟 +pub trait TimeFromFreq { + fn from_freq(freq: usize) -> Self; +} + +impl TimeNow for TimeVal { + fn now() -> Self { + let time = read_timer(); + Self { + tv_sec: time / CLOCK_FREQ, + tv_usec: (time % CLOCK_FREQ) * 1000000 / CLOCK_FREQ, + } + } +} +impl ToClock for TimeVal { + fn to_clock(&self) -> usize { + self.tv_sec * CLOCK_FREQ + self.tv_usec * CLOCK_FREQ / 1000_000 + } +} + +impl TimeFromFreq for TimeVal { + fn from_freq(freq: usize) -> Self { + Self { + tv_sec: freq / CLOCK_FREQ, + tv_usec: (freq % CLOCK_FREQ) * 1000000 / CLOCK_FREQ, + } + } +} + + +/// 更精细的时间,秒(s)+纳秒(ns) +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct TimeSpec { + pub tv_sec: usize, + pub tv_nsec: usize, //0~999999999 +} + +impl TimeSpec { + /// 创建一个新的 [`TimeSpec`] 时钟 + pub fn new(sec: usize, ns: usize) -> Self { + Self { + tv_sec: sec, + tv_nsec: ns, + } + } + + /// 获取一个可以表示当前 cpu 时间的一个 [`TimeSpec`] 时钟 + pub fn now() -> Self { + let time = arch::read_timer(); + Self { + tv_sec: time / CLOCK_FREQ, + tv_nsec: (time % CLOCK_FREQ) * 1000000000 / CLOCK_FREQ, + } + } + + /// 将本时钟所表示的时间间隔转化为 cpu 上时钟的跳变数 + pub fn to_clock(&self) -> usize { + self.tv_sec * CLOCK_FREQ + self.tv_nsec * CLOCK_FREQ / 1000_000_000 + } +} + +impl Into for TimeSpec { + fn into(self) -> VfsTimeSpec { + VfsTimeSpec::new(self.tv_sec as u64, self.tv_nsec as u64) + } +} + +/// [`getitimer`] / [`setitimer`] 指定的类型,用户执行系统调用时获取和输入的计时器 +#[repr(C)] +#[derive(Debug, Copy, Clone, Default)] +pub struct ITimerVal { + /// 计时器超时间隔 + pub it_interval: TimeVal, + /// 计时器当前所剩时间 + pub it_value: TimeVal, +} + +/// 获取当前计时器的值 +#[inline] +pub fn read_timer() -> usize { + arch::read_timer() +} + +/// 获取当前时间,以 ms 为单位 +pub fn get_time_ms() -> isize { + (read_timer() / (CLOCK_FREQ / MSEC_PER_SEC)) as isize +} \ No newline at end of file diff --git a/subsystems/unwinder/Cargo.toml b/subsystems/unwinder/Cargo.toml new file mode 100644 index 00000000..cc6f21ec --- /dev/null +++ b/subsystems/unwinder/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "unwinder" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tracer = { git = "https://github.com/os-module/tracer" } +platform = { path = "../platform" } +arch = { path = "../arch" } + +[features] +debug-eh-frame = [] +debug-frame-pointer = [] \ No newline at end of file diff --git a/subsystems/unwinder/build.rs b/subsystems/unwinder/build.rs new file mode 100644 index 00000000..6565a7ea --- /dev/null +++ b/subsystems/unwinder/build.rs @@ -0,0 +1,22 @@ +use std::fs::File; +use std::path::Path; +use std::io::Write; + +fn main(){ + println!("cargo:rerun-if-changed={}", "src/"); + let path = Path::new("src/kernel_symbol.S"); + if !path.exists() { + let mut file = File::create(path).unwrap(); + write!(file, ".section .rodata\n").unwrap(); + write!(file, ".align 3\n").unwrap(); + write!(file, ".global symbol_num\n").unwrap(); + write!(file, ".global symbol_address\n").unwrap(); + write!(file, ".global symbol_index\n").unwrap(); + write!(file, ".global symbol_name\n").unwrap(); + write!(file, "symbol_num:\n").unwrap(); + write!(file, ".quad {}\n", 0).unwrap(); + write!(file, "symbol_address:\n").unwrap(); + write!(file, "symbol_index:\n").unwrap(); + write!(file, "symbol_name:\n").unwrap(); + } +} \ No newline at end of file diff --git a/subsystems/unwinder/src/kernel_symbol.S b/subsystems/unwinder/src/kernel_symbol.S new file mode 100644 index 00000000..6eeb99eb --- /dev/null +++ b/subsystems/unwinder/src/kernel_symbol.S @@ -0,0 +1,9977 @@ +.align 3 +.section .rodata +.globl symbol_num +symbol_num: + .quad 3322 +.globl symbol_address +symbol_address: + .quad 2149580800 + .quad 2149580800 + .quad 2149584896 + .quad 2149584896 + .quad 2149585004 + .quad 2149588992 + .quad 2149588992 + .quad 2149589008 + .quad 2149589024 + .quad 2149589040 + .quad 2149589056 + .quad 2149589072 + .quad 2149589088 + .quad 2149589104 + .quad 2149589120 + .quad 2149589136 + .quad 2149589152 + .quad 2149589168 + .quad 2149589184 + .quad 2149589200 + .quad 2149589216 + .quad 2149589232 + .quad 2149589248 + .quad 2149589264 + .quad 2149589280 + .quad 2149589296 + .quad 2149589312 + .quad 2149589328 + .quad 2149589344 + .quad 2149589360 + .quad 2149589376 + .quad 2149589392 + .quad 2149589408 + .quad 2149589424 + .quad 2149589440 + .quad 2149589456 + .quad 2149589472 + .quad 2149589488 + .quad 2149589504 + .quad 2149589520 + .quad 2149589536 + .quad 2149589552 + .quad 2149589568 + .quad 2149589584 + .quad 2149589600 + .quad 2149589616 + .quad 2149589632 + .quad 2149589648 + .quad 2149589664 + .quad 2149589680 + .quad 2149589696 + .quad 2149589712 + .quad 2149589728 + .quad 2149589744 + .quad 2149589760 + .quad 2149589776 + .quad 2149589792 + .quad 2149589808 + .quad 2149589824 + .quad 2149589840 + .quad 2149589856 + .quad 2149589872 + .quad 2149589888 + .quad 2149589904 + .quad 2149589920 + .quad 2149589936 + .quad 2149589952 + .quad 2149589968 + .quad 2149589984 + .quad 2149590000 + .quad 2149590016 + .quad 2149590032 + .quad 2149590048 + .quad 2149590064 + .quad 2149590080 + .quad 2149590096 + .quad 2149590112 + .quad 2149590128 + .quad 2149590144 + .quad 2149590160 + .quad 2149590176 + .quad 2149590192 + .quad 2149590208 + .quad 2149590224 + .quad 2149590240 + .quad 2149590256 + .quad 2149590272 + .quad 2149590288 + .quad 2149590304 + .quad 2149590320 + .quad 2149590336 + .quad 2149590352 + .quad 2149590368 + .quad 2149590384 + .quad 2149590400 + .quad 2149590416 + .quad 2149590432 + .quad 2149590448 + .quad 2149590464 + .quad 2149590480 + .quad 2149590496 + .quad 2149590512 + .quad 2149590528 + .quad 2149590544 + .quad 2149590560 + .quad 2149590576 + .quad 2149590592 + .quad 2149590608 + .quad 2149590624 + .quad 2149590640 + .quad 2149590656 + .quad 2149590672 + .quad 2149590688 + .quad 2149590704 + .quad 2149590720 + .quad 2149590736 + .quad 2149590752 + .quad 2149590768 + .quad 2149590784 + .quad 2149590800 + .quad 2149590816 + .quad 2149590832 + .quad 2149590848 + .quad 2149590864 + .quad 2149590880 + .quad 2149590896 + .quad 2149590912 + .quad 2149590928 + .quad 2149590944 + .quad 2149590960 + .quad 2149590976 + .quad 2149590992 + .quad 2149591008 + .quad 2149591024 + .quad 2149591040 + .quad 2149591056 + .quad 2149591072 + .quad 2149591114 + .quad 2149591134 + .quad 2149591136 + .quad 2149591186 + .quad 2149592186 + .quad 2149592200 + .quad 2149592360 + .quad 2149592378 + .quad 2149592396 + .quad 2149592414 + .quad 2149592432 + .quad 2149592450 + .quad 2149592468 + .quad 2149592486 + .quad 2149592504 + .quad 2149593104 + .quad 2149593112 + .quad 2149593122 + .quad 2149593132 + .quad 2149593142 + .quad 2149593152 + .quad 2149593162 + .quad 2149593172 + .quad 2149593182 + .quad 2149593192 + .quad 2149593202 + .quad 2149593212 + .quad 2149593222 + .quad 2149593232 + .quad 2149593242 + .quad 2149593242 + .quad 2149593252 + .quad 2149593262 + .quad 2149593272 + .quad 2149593282 + .quad 2149593292 + .quad 2149593302 + .quad 2149593312 + .quad 2149593322 + .quad 2149593332 + .quad 2149593342 + .quad 2149593352 + .quad 2149593362 + .quad 2149593372 + .quad 2149593382 + .quad 2149593392 + .quad 2149593402 + .quad 2149593412 + .quad 2149593422 + .quad 2149593432 + .quad 2149593442 + .quad 2149593452 + .quad 2149593462 + .quad 2149593472 + .quad 2149593482 + .quad 2149593492 + .quad 2149593502 + .quad 2149593512 + .quad 2149593552 + .quad 2149593582 + .quad 2149593602 + .quad 2149593746 + .quad 2149594018 + .quad 2149594292 + .quad 2149594454 + .quad 2149594636 + .quad 2149594760 + .quad 2149594770 + .quad 2149594946 + .quad 2149595048 + .quad 2149595050 + .quad 2149595052 + .quad 2149595052 + .quad 2149595546 + .quad 2149596262 + .quad 2149596392 + .quad 2149597494 + .quad 2149597498 + .quad 2149597510 + .quad 2149598134 + .quad 2149599972 + .quad 2149599976 + .quad 2149599988 + .quad 2149600656 + .quad 2149601440 + .quad 2149602754 + .quad 2149603660 + .quad 2149603668 + .quad 2149603672 + .quad 2149603684 + .quad 2149603696 + .quad 2149603712 + .quad 2149603724 + .quad 2149603824 + .quad 2149603910 + .quad 2149603996 + .quad 2149604114 + .quad 2149604240 + .quad 2149604366 + .quad 2149604562 + .quad 2149604634 + .quad 2149604688 + .quad 2149604934 + .quad 2149604962 + .quad 2149605046 + .quad 2149605092 + .quad 2149605104 + .quad 2149605662 + .quad 2149605786 + .quad 2149605868 + .quad 2149605948 + .quad 2149605952 + .quad 2149605956 + .quad 2149605970 + .quad 2149606102 + .quad 2149606192 + .quad 2149606246 + .quad 2149606256 + .quad 2149607954 + .quad 2149610430 + .quad 2149610440 + .quad 2149610454 + .quad 2149610632 + .quad 2149610644 + .quad 2149610648 + .quad 2149610652 + .quad 2149610736 + .quad 2149611612 + .quad 2149611836 + .quad 2149612064 + .quad 2149612398 + .quad 2149612416 + .quad 2149612420 + .quad 2149612510 + .quad 2149612516 + .quad 2149612530 + .quad 2149612544 + .quad 2149612796 + .quad 2149612808 + .quad 2149613030 + .quad 2149613076 + .quad 2149613208 + .quad 2149613338 + .quad 2149613410 + .quad 2149614254 + .quad 2149614262 + .quad 2149615462 + .quad 2149615480 + .quad 2149617198 + .quad 2149617344 + .quad 2149618394 + .quad 2149618632 + .quad 2149618740 + .quad 2149619032 + .quad 2149619174 + .quad 2149619256 + .quad 2149619394 + .quad 2149619462 + .quad 2149619466 + .quad 2149619472 + .quad 2149619946 + .quad 2149620202 + .quad 2149620290 + .quad 2149620582 + .quad 2149620882 + .quad 2149621112 + .quad 2149621866 + .quad 2149622276 + .quad 2149622464 + .quad 2149622658 + .quad 2149624730 + .quad 2149624740 + .quad 2149624750 + .quad 2149624760 + .quad 2149624770 + .quad 2149624810 + .quad 2149624840 + .quad 2149624840 + .quad 2149624842 + .quad 2149624842 + .quad 2149624842 + .quad 2149624844 + .quad 2149624914 + .quad 2149625152 + .quad 2149625938 + .quad 2149626020 + .quad 2149626118 + .quad 2149626208 + .quad 2149626440 + .quad 2149626774 + .quad 2149627170 + .quad 2149627404 + .quad 2149627612 + .quad 2149627826 + .quad 2149628298 + .quad 2149628678 + .quad 2149628678 + .quad 2149628678 + .quad 2149629058 + .quad 2149629438 + .quad 2149629818 + .quad 2149630760 + .quad 2149632182 + .quad 2149633128 + .quad 2149633422 + .quad 2149633684 + .quad 2149633892 + .quad 2149634724 + .quad 2149635102 + .quad 2149635666 + .quad 2149635666 + .quad 2149635968 + .quad 2149636270 + .quad 2149636572 + .quad 2149636874 + .quad 2149637176 + .quad 2149637478 + .quad 2149637936 + .quad 2149640020 + .quad 2149640468 + .quad 2149640808 + .quad 2149642196 + .quad 2149644210 + .quad 2149644674 + .quad 2149645772 + .quad 2149646354 + .quad 2149654758 + .quad 2149659138 + .quad 2149670896 + .quad 2149670940 + .quad 2149671800 + .quad 2149672958 + .quad 2149674106 + .quad 2149674726 + .quad 2149675444 + .quad 2149676448 + .quad 2149677862 + .quad 2149678392 + .quad 2149678402 + .quad 2149678462 + .quad 2149678644 + .quad 2149678696 + .quad 2149678872 + .quad 2149679040 + .quad 2149679166 + .quad 2149679246 + .quad 2149679248 + .quad 2149679480 + .quad 2149679666 + .quad 2149679898 + .quad 2149680084 + .quad 2149682186 + .quad 2149683802 + .quad 2149685374 + .quad 2149687020 + .quad 2149688642 + .quad 2149688770 + .quad 2149691494 + .quad 2149692638 + .quad 2149693550 + .quad 2149694486 + .quad 2149694776 + .quad 2149695298 + .quad 2149695782 + .quad 2149695956 + .quad 2149696614 + .quad 2149697800 + .quad 2149699826 + .quad 2149700424 + .quad 2149700804 + .quad 2149700972 + .quad 2149702662 + .quad 2149702836 + .quad 2149702998 + .quad 2149703450 + .quad 2149705586 + .quad 2149706546 + .quad 2149706796 + .quad 2149707882 + .quad 2149709408 + .quad 2149709986 + .quad 2149710288 + .quad 2149710288 + .quad 2149710520 + .quad 2149710744 + .quad 2149710970 + .quad 2149711206 + .quad 2149711426 + .quad 2149711658 + .quad 2149711930 + .quad 2149712146 + .quad 2149712164 + .quad 2149712182 + .quad 2149712200 + .quad 2149712218 + .quad 2149712286 + .quad 2149712296 + .quad 2149712306 + .quad 2149712316 + .quad 2149712326 + .quad 2149712326 + .quad 2149712336 + .quad 2149712346 + .quad 2149712356 + .quad 2149712366 + .quad 2149712376 + .quad 2149712386 + .quad 2149712396 + .quad 2149712406 + .quad 2149712416 + .quad 2149712426 + .quad 2149712436 + .quad 2149712446 + .quad 2149712476 + .quad 2149712620 + .quad 2149712892 + .quad 2149712946 + .quad 2149713126 + .quad 2149713128 + .quad 2149713130 + .quad 2149713130 + .quad 2149713130 + .quad 2149713318 + .quad 2149713630 + .quad 2149714076 + .quad 2149714348 + .quad 2149714730 + .quad 2149715034 + .quad 2149715306 + .quad 2149715598 + .quad 2149715848 + .quad 2149716096 + .quad 2149716344 + .quad 2149716790 + .quad 2149717138 + .quad 2149717584 + .quad 2149717838 + .quad 2149718094 + .quad 2149718342 + .quad 2149718590 + .quad 2149718876 + .quad 2149719222 + .quad 2149719472 + .quad 2149719724 + .quad 2149719918 + .quad 2149720288 + .quad 2149720836 + .quad 2149721554 + .quad 2149721554 + .quad 2149721638 + .quad 2149723226 + .quad 2149723292 + .quad 2149723364 + .quad 2149723432 + .quad 2149723504 + .quad 2149723576 + .quad 2149723644 + .quad 2149723712 + .quad 2149723780 + .quad 2149723852 + .quad 2149723946 + .quad 2149723954 + .quad 2149723966 + .quad 2149723978 + .quad 2149723994 + .quad 2149724006 + .quad 2149724198 + .quad 2149724434 + .quad 2149724488 + .quad 2149724542 + .quad 2149724588 + .quad 2149724634 + .quad 2149724890 + .quad 2149726018 + .quad 2149726736 + .quad 2149726952 + .quad 2149727092 + .quad 2149727446 + .quad 2149727640 + .quad 2149727984 + .quad 2149728076 + .quad 2149728172 + .quad 2149729234 + .quad 2149729370 + .quad 2149729812 + .quad 2149729818 + .quad 2149729832 + .quad 2149729838 + .quad 2149729852 + .quad 2149729866 + .quad 2149729880 + .quad 2149729892 + .quad 2149729898 + .quad 2149729902 + .quad 2149730032 + .quad 2149730104 + .quad 2149730158 + .quad 2149730166 + .quad 2149731182 + .quad 2149731730 + .quad 2149732238 + .quad 2149732470 + .quad 2149732482 + .quad 2149732486 + .quad 2149732490 + .quad 2149734312 + .quad 2149734316 + .quad 2149734320 + .quad 2149734992 + .quad 2149735652 + .quad 2149735980 + .quad 2149736256 + .quad 2149736628 + .quad 2149737014 + .quad 2149737336 + .quad 2149737722 + .quad 2149738118 + .quad 2149738386 + .quad 2149738540 + .quad 2149738600 + .quad 2149738660 + .quad 2149738688 + .quad 2149738716 + .quad 2149738884 + .quad 2149738928 + .quad 2149740836 + .quad 2149742532 + .quad 2149744288 + .quad 2149746112 + .quad 2149747812 + .quad 2149749490 + .quad 2149749490 + .quad 2149749490 + .quad 2149751434 + .quad 2149753574 + .quad 2149753574 + .quad 2149755330 + .quad 2149756996 + .quad 2149756996 + .quad 2149758662 + .quad 2149760540 + .quad 2149760996 + .quad 2149761512 + .quad 2149761980 + .quad 2149762500 + .quad 2149763028 + .quad 2149763484 + .quad 2149763962 + .quad 2149764466 + .quad 2149764978 + .quad 2149765542 + .quad 2149766046 + .quad 2149766610 + .quad 2149767138 + .quad 2149767696 + .quad 2149768224 + .quad 2149768758 + .quad 2149769306 + .quad 2149769824 + .quad 2149770368 + .quad 2149770870 + .quad 2149771372 + .quad 2149771840 + .quad 2149772320 + .quad 2149772756 + .quad 2149773192 + .quad 2149773660 + .quad 2149774102 + .quad 2149774560 + .quad 2149775210 + .quad 2149775896 + .quad 2149776584 + .quad 2149777278 + .quad 2149777958 + .quad 2149778608 + .quad 2149779252 + .quad 2149779466 + .quad 2149779714 + .quad 2149779904 + .quad 2149779904 + .quad 2149780094 + .quad 2149780294 + .quad 2149780554 + .quad 2149780796 + .quad 2149781018 + .quad 2149781018 + .quad 2149781240 + .quad 2149781462 + .quad 2149781680 + .quad 2149781898 + .quad 2149781898 + .quad 2149782120 + .quad 2149782982 + .quad 2149783780 + .quad 2149783996 + .quad 2149785232 + .quad 2149785572 + .quad 2149786374 + .quad 2149786750 + .quad 2149786984 + .quad 2149787200 + .quad 2149787346 + .quad 2149787492 + .quad 2149787502 + .quad 2149787542 + .quad 2149787836 + .quad 2149787838 + .quad 2149787840 + .quad 2149787844 + .quad 2149787962 + .quad 2149788092 + .quad 2149788222 + .quad 2149788466 + .quad 2149788928 + .quad 2149789440 + .quad 2149789656 + .quad 2149790612 + .quad 2149791462 + .quad 2149791794 + .quad 2149792752 + .quad 2149793440 + .quad 2149794552 + .quad 2149795598 + .quad 2149796100 + .quad 2149797804 + .quad 2149803254 + .quad 2149804172 + .quad 2149804456 + .quad 2149804768 + .quad 2149806636 + .quad 2149807854 + .quad 2149807876 + .quad 2149807900 + .quad 2149808006 + .quad 2149808064 + .quad 2149808064 + .quad 2149808066 + .quad 2149808068 + .quad 2149808070 + .quad 2149808316 + .quad 2149808380 + .quad 2149808380 + .quad 2149808380 + .quad 2149808380 + .quad 2149808380 + .quad 2149808380 + .quad 2149808380 + .quad 2149808380 + .quad 2149808380 + .quad 2149808380 + .quad 2149808380 + .quad 2149808504 + .quad 2149808504 + .quad 2149808666 + .quad 2149808900 + .quad 2149808900 + .quad 2149808954 + .quad 2149809008 + .quad 2149809218 + .quad 2149809398 + .quad 2149809580 + .quad 2149809634 + .quad 2149809860 + .quad 2149809860 + .quad 2149809968 + .quad 2149810130 + .quad 2149810130 + .quad 2149810362 + .quad 2149810468 + .quad 2149810468 + .quad 2149810520 + .quad 2149810720 + .quad 2149810908 + .quad 2149811014 + .quad 2149811132 + .quad 2149811312 + .quad 2149811368 + .quad 2149811572 + .quad 2149811770 + .quad 2149812108 + .quad 2149812352 + .quad 2149812996 + .quad 2149813104 + .quad 2149813190 + .quad 2149813370 + .quad 2149813694 + .quad 2149814430 + .quad 2149814494 + .quad 2149814522 + .quad 2149814888 + .quad 2149815132 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815420 + .quad 2149815440 + .quad 2149817706 + .quad 2149818244 + .quad 2149818248 + .quad 2149818530 + .quad 2149818532 + .quad 2149818746 + .quad 2149821524 + .quad 2149821612 + .quad 2149821700 + .quad 2149821788 + .quad 2149821876 + .quad 2149821964 + .quad 2149822052 + .quad 2149822140 + .quad 2149822228 + .quad 2149822316 + .quad 2149822404 + .quad 2149822492 + .quad 2149822580 + .quad 2149822668 + .quad 2149822756 + .quad 2149822844 + .quad 2149822932 + .quad 2149823020 + .quad 2149823108 + .quad 2149823196 + .quad 2149823284 + .quad 2149823372 + .quad 2149823460 + .quad 2149823548 + .quad 2149823636 + .quad 2149823724 + .quad 2149823812 + .quad 2149823900 + .quad 2149823988 + .quad 2149824094 + .quad 2149824182 + .quad 2149824594 + .quad 2149824724 + .quad 2149825026 + .quad 2149825046 + .quad 2149825140 + .quad 2149825284 + .quad 2149825504 + .quad 2149825924 + .quad 2149825924 + .quad 2149825924 + .quad 2149825924 + .quad 2149825924 + .quad 2149825924 + .quad 2149825924 + .quad 2149825924 + .quad 2149825924 + .quad 2149825924 + .quad 2149825924 + .quad 2149825924 + .quad 2149825924 + .quad 2149825928 + .quad 2149826160 + .quad 2149826228 + .quad 2149826348 + .quad 2149826442 + .quad 2149826534 + .quad 2149826626 + .quad 2149826732 + .quad 2149826884 + .quad 2149826968 + .quad 2149827062 + .quad 2149827154 + .quad 2149827512 + .quad 2149827632 + .quad 2149827726 + .quad 2149827836 + .quad 2149827912 + .quad 2149828212 + .quad 2149828356 + .quad 2149828444 + .quad 2149828750 + .quad 2149828834 + .quad 2149828916 + .quad 2149829108 + .quad 2149829108 + .quad 2149829288 + .quad 2149829524 + .quad 2149829608 + .quad 2149829700 + .quad 2149830000 + .quad 2149830094 + .quad 2149830186 + .quad 2149830366 + .quad 2149830492 + .quad 2149830580 + .quad 2149830672 + .quad 2149830760 + .quad 2149830924 + .quad 2149831088 + .quad 2149831330 + .quad 2149831476 + .quad 2149831568 + .quad 2149831712 + .quad 2149831824 + .quad 2149831920 + .quad 2149832000 + .quad 2149832080 + .quad 2149832172 + .quad 2149832382 + .quad 2149832470 + .quad 2149832620 + .quad 2149832714 + .quad 2149832722 + .quad 2149832798 + .quad 2149832866 + .quad 2149833146 + .quad 2149833238 + .quad 2149833458 + .quad 2149833618 + .quad 2149833838 + .quad 2149833944 + .quad 2149834154 + .quad 2149834246 + .quad 2149834334 + .quad 2149834634 + .quad 2149834642 + .quad 2149834774 + .quad 2149834938 + .quad 2149834938 + .quad 2149835028 + .quad 2149835462 + .quad 2149835714 + .quad 2149835834 + .quad 2149835926 + .quad 2149836018 + .quad 2149836328 + .quad 2149836420 + .quad 2149836512 + .quad 2149836732 + .quad 2149836930 + .quad 2149837086 + .quad 2149837086 + .quad 2149837182 + .quad 2149837274 + .quad 2149837368 + .quad 2149837716 + .quad 2149837808 + .quad 2149837894 + .quad 2149838116 + .quad 2149838400 + .quad 2149838620 + .quad 2149839028 + .quad 2149839248 + .quad 2149839502 + .quad 2149839658 + .quad 2149839746 + .quad 2149839926 + .quad 2149840150 + .quad 2149840330 + .quad 2149840420 + .quad 2149840442 + .quad 2149840746 + .quad 2149840838 + .quad 2149841246 + .quad 2149841654 + .quad 2149841834 + .quad 2149841924 + .quad 2149842080 + .quad 2149842096 + .quad 2149842228 + .quad 2149842450 + .quad 2149842450 + .quad 2149842450 + .quad 2149842450 + .quad 2149842450 + .quad 2149842450 + .quad 2149842450 + .quad 2149842450 + .quad 2149842450 + .quad 2149842450 + .quad 2149842450 + .quad 2149842450 + .quad 2149842450 + .quad 2149842454 + .quad 2149842454 + .quad 2149842660 + .quad 2149842754 + .quad 2149842838 + .quad 2149842950 + .quad 2149843044 + .quad 2149843164 + .quad 2149843258 + .quad 2149843350 + .quad 2149843446 + .quad 2149843532 + .quad 2149843540 + .quad 2149843548 + .quad 2149843564 + .quad 2149843716 + .quad 2149843724 + .quad 2149843732 + .quad 2149843888 + .quad 2149843896 + .quad 2149843912 + .quad 2149843920 + .quad 2149844012 + .quad 2149844020 + .quad 2149844088 + .quad 2149844096 + .quad 2149844252 + .quad 2149844344 + .quad 2149844432 + .quad 2149844578 + .quad 2149844670 + .quad 2149844678 + .quad 2149844798 + .quad 2149844886 + .quad 2149845186 + .quad 2149845278 + .quad 2149845286 + .quad 2149845286 + .quad 2149845382 + .quad 2149845390 + .quad 2149845548 + .quad 2149845556 + .quad 2149845556 + .quad 2149845646 + .quad 2149845802 + .quad 2149845922 + .quad 2149846006 + .quad 2149846028 + .quad 2149846138 + .quad 2149846230 + .quad 2149846320 + .quad 2149846408 + .quad 2149846430 + .quad 2149846438 + .quad 2149846530 + .quad 2149846622 + .quad 2149846630 + .quad 2149846722 + .quad 2149846810 + .quad 2149846818 + .quad 2149846826 + .quad 2149846846 + .quad 2149846922 + .quad 2149846930 + .quad 2149847056 + .quad 2149847132 + .quad 2149847312 + .quad 2149847402 + .quad 2149847706 + .quad 2149847886 + .quad 2149847978 + .quad 2149848072 + .quad 2149848080 + .quad 2149848160 + .quad 2149848244 + .quad 2149848312 + .quad 2149848400 + .quad 2149848492 + .quad 2149848636 + .quad 2149848816 + .quad 2149848966 + .quad 2149849058 + .quad 2149849158 + .quad 2149849246 + .quad 2149849254 + .quad 2149849534 + .quad 2149849834 + .quad 2149849952 + .quad 2149850046 + .quad 2149850054 + .quad 2149850148 + .quad 2149850156 + .quad 2149850316 + .quad 2149850410 + .quad 2149850502 + .quad 2149850622 + .quad 2149850630 + .quad 2149850722 + .quad 2149850914 + .quad 2149850996 + .quad 2149851004 + .quad 2149851096 + .quad 2149851104 + .quad 2149851248 + .quad 2149851340 + .quad 2149851420 + .quad 2149851428 + .quad 2149851436 + .quad 2149851566 + .quad 2149851650 + .quad 2149851830 + .quad 2149851922 + .quad 2149852152 + .quad 2149852272 + .quad 2149852390 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852534 + .quad 2149852536 + .quad 2149852562 + .quad 2149852582 + .quad 2149852782 + .quad 2149852992 + .quad 2149853302 + .quad 2149853574 + .quad 2149853884 + .quad 2149854156 + .quad 2149854538 + .quad 2149854882 + .quad 2149855272 + .quad 2149856808 + .quad 2149857572 + .quad 2149858320 + .quad 2149858330 + .quad 2149858340 + .quad 2149858350 + .quad 2149858360 + .quad 2149858370 + .quad 2149858380 + .quad 2149858390 + .quad 2149858400 + .quad 2149858410 + .quad 2149858420 + .quad 2149858430 + .quad 2149858440 + .quad 2149858450 + .quad 2149858460 + .quad 2149858470 + .quad 2149858480 + .quad 2149858490 + .quad 2149858500 + .quad 2149858510 + .quad 2149858520 + .quad 2149858530 + .quad 2149858540 + .quad 2149858550 + .quad 2149858560 + .quad 2149858570 + .quad 2149858580 + .quad 2149858590 + .quad 2149858600 + .quad 2149858618 + .quad 2149858636 + .quad 2149858638 + .quad 2149858638 + .quad 2149858638 + .quad 2149858640 + .quad 2149858910 + .quad 2149858912 + .quad 2149859224 + .quad 2149859254 + .quad 2149859284 + .quad 2149859314 + .quad 2149859316 + .quad 2149859346 + .quad 2149859376 + .quad 2149859964 + .quad 2149860620 + .quad 2149860846 + .quad 2149860846 + .quad 2149860928 + .quad 2149860928 + .quad 2149861158 + .quad 2149861362 + .quad 2149861362 + .quad 2149861616 + .quad 2149861616 + .quad 2149861616 + .quad 2149861848 + .quad 2149862078 + .quad 2149862308 + .quad 2149862492 + .quad 2149862492 + .quad 2149862746 + .quad 2149862990 + .quad 2149863214 + .quad 2149863476 + .quad 2149863706 + .quad 2149863706 + .quad 2149863936 + .quad 2149864140 + .quad 2149864394 + .quad 2149864656 + .quad 2149864918 + .quad 2149864926 + .quad 2149864930 + .quad 2149864934 + .quad 2149864938 + .quad 2149864946 + .quad 2149864954 + .quad 2149864958 + .quad 2149864970 + .quad 2149864982 + .quad 2149864998 + .quad 2149865014 + .quad 2149865030 + .quad 2149865044 + .quad 2149865058 + .quad 2149865072 + .quad 2149865078 + .quad 2149865084 + .quad 2149865090 + .quad 2149865096 + .quad 2149865102 + .quad 2149865108 + .quad 2149865122 + .quad 2149865136 + .quad 2149865150 + .quad 2149865164 + .quad 2149865178 + .quad 2149865192 + .quad 2149865206 + .quad 2149865220 + .quad 2149865234 + .quad 2149865246 + .quad 2149865258 + .quad 2149865270 + .quad 2149865276 + .quad 2149865282 + .quad 2149865288 + .quad 2149865292 + .quad 2149865296 + .quad 2149865644 + .quad 2149865992 + .quad 2149865996 + .quad 2149866008 + .quad 2149866012 + .quad 2149866074 + .quad 2149866078 + .quad 2149866090 + .quad 2149866152 + .quad 2149866226 + .quad 2149866230 + .quad 2149866244 + .quad 2149866248 + .quad 2149866262 + .quad 2149866266 + .quad 2149866328 + .quad 2149866332 + .quad 2149871770 + .quad 2149871772 + .quad 2149871778 + .quad 2149871780 + .quad 2149871788 + .quad 2149871792 + .quad 2149871800 + .quad 2149871814 + .quad 2149871818 + .quad 2149871822 + .quad 2149871884 + .quad 2149871888 + .quad 2149872150 + .quad 2149872482 + .quad 2149872730 + .quad 2149876354 + .quad 2149876442 + .quad 2149876530 + .quad 2149876618 + .quad 2149876706 + .quad 2149876794 + .quad 2149876882 + .quad 2149876970 + .quad 2149877058 + .quad 2149877146 + .quad 2149877234 + .quad 2149877322 + .quad 2149877410 + .quad 2149877498 + .quad 2149877586 + .quad 2149877674 + .quad 2149877762 + .quad 2149878460 + .quad 2149879958 + .quad 2149880634 + .quad 2149880722 + .quad 2149880810 + .quad 2149880898 + .quad 2149880986 + .quad 2149881074 + .quad 2149881162 + .quad 2149881250 + .quad 2149881338 + .quad 2149881426 + .quad 2149881514 + .quad 2149881602 + .quad 2149881690 + .quad 2149881778 + .quad 2149881866 + .quad 2149881972 + .quad 2149882184 + .quad 2149882376 + .quad 2149882566 + .quad 2149882584 + .quad 2149882594 + .quad 2149882604 + .quad 2149882614 + .quad 2149882624 + .quad 2149882634 + .quad 2149882674 + .quad 2149883212 + .quad 2149883478 + .quad 2149884018 + .quad 2149884040 + .quad 2149884070 + .quad 2149884212 + .quad 2149884212 + .quad 2149884212 + .quad 2149884212 + .quad 2149884214 + .quad 2149884216 + .quad 2149884226 + .quad 2149884308 + .quad 2149884672 + .quad 2149884824 + .quad 2149885462 + .quad 2149885858 + .quad 2149885870 + .quad 2149885882 + .quad 2149885886 + .quad 2149885898 + .quad 2149885910 + .quad 2149885916 + .quad 2149886020 + .quad 2149886396 + .quad 2149886754 + .quad 2149886764 + .quad 2149886776 + .quad 2149886852 + .quad 2149886930 + .quad 2149886980 + .quad 2149887030 + .quad 2149887034 + .quad 2149887038 + .quad 2149887284 + .quad 2149887428 + .quad 2149888030 + .quad 2149888572 + .quad 2149888838 + .quad 2149889408 + .quad 2149889772 + .quad 2149890052 + .quad 2149890172 + .quad 2149890464 + .quad 2149890802 + .quad 2149891456 + .quad 2149891942 + .quad 2149892030 + .quad 2149892118 + .quad 2149895106 + .quad 2149895194 + .quad 2149895282 + .quad 2149895370 + .quad 2149895458 + .quad 2149896304 + .quad 2149896970 + .quad 2149897508 + .quad 2149898770 + .quad 2149899544 + .quad 2149900586 + .quad 2149901680 + .quad 2149902612 + .quad 2149904290 + .quad 2149904770 + .quad 2149904858 + .quad 2149906062 + .quad 2149906512 + .quad 2149906722 + .quad 2149906810 + .quad 2149906898 + .quad 2149906986 + .quad 2149907074 + .quad 2149907156 + .quad 2149907238 + .quad 2149908078 + .quad 2149908572 + .quad 2149909036 + .quad 2149910622 + .quad 2149911222 + .quad 2149912338 + .quad 2149912630 + .quad 2149912640 + .quad 2149912650 + .quad 2149912670 + .quad 2149912860 + .quad 2149913146 + .quad 2149913168 + .quad 2149913190 + .quad 2149913212 + .quad 2149913212 + .quad 2149913212 + .quad 2149913212 + .quad 2149913212 + .quad 2149913212 + .quad 2149913212 + .quad 2149913212 + .quad 2149913212 + .quad 2149913212 + .quad 2149913212 + .quad 2149913214 + .quad 2149913214 + .quad 2149913214 + .quad 2149913216 + .quad 2149913242 + .quad 2149913244 + .quad 2149913338 + .quad 2149913358 + .quad 2149913440 + .quad 2149913534 + .quad 2149913534 + .quad 2149913824 + .quad 2149914078 + .quad 2149914420 + .quad 2149914508 + .quad 2149914594 + .quad 2149914686 + .quad 2149914938 + .quad 2149915130 + .quad 2149915418 + .quad 2149915702 + .quad 2149916042 + .quad 2149916276 + .quad 2149916620 + .quad 2149916932 + .quad 2149917402 + .quad 2149918074 + .quad 2149918204 + .quad 2149918234 + .quad 2149918310 + .quad 2149918438 + .quad 2149918528 + .quad 2149918670 + .quad 2149919134 + .quad 2149919438 + .quad 2149919976 + .quad 2149920354 + .quad 2149920832 + .quad 2149921012 + .quad 2149921278 + .quad 2149921710 + .quad 2149921728 + .quad 2149921746 + .quad 2149921788 + .quad 2149921798 + .quad 2149921808 + .quad 2149921818 + .quad 2149921838 + .quad 2149921848 + .quad 2149921870 + .quad 2149921912 + .quad 2149922030 + .quad 2149922050 + .quad 2149922092 + .quad 2149922134 + .quad 2149922144 + .quad 2149922154 + .quad 2149922196 + .quad 2149922206 + .quad 2149922216 + .quad 2149922258 + .quad 2149922268 + .quad 2149922278 + .quad 2149922288 + .quad 2149922298 + .quad 2149922308 + .quad 2149922318 + .quad 2149922328 + .quad 2149922348 + .quad 2149922388 + .quad 2149922428 + .quad 2149922468 + .quad 2149922486 + .quad 2149922504 + .quad 2149922506 + .quad 2149922508 + .quad 2149922606 + .quad 2149923236 + .quad 2149923236 + .quad 2149923236 + .quad 2149923246 + .quad 2149923334 + .quad 2149923712 + .quad 2149923732 + .quad 2149923752 + .quad 2149923954 + .quad 2149924008 + .quad 2149924062 + .quad 2149924108 + .quad 2149924154 + .quad 2149924530 + .quad 2149924580 + .quad 2149924674 + .quad 2149925854 + .quad 2149925882 + .quad 2149925894 + .quad 2149925906 + .quad 2149925918 + .quad 2149925920 + .quad 2149925924 + .quad 2149925936 + .quad 2149925942 + .quad 2149925952 + .quad 2149925964 + .quad 2149925968 + .quad 2149926206 + .quad 2149927506 + .quad 2149927720 + .quad 2149929488 + .quad 2149930618 + .quad 2149930960 + .quad 2149932028 + .quad 2149932436 + .quad 2149934932 + .quad 2149935462 + .quad 2149935692 + .quad 2149935948 + .quad 2149936162 + .quad 2149936736 + .quad 2149938926 + .quad 2149939168 + .quad 2149940662 + .quad 2149940978 + .quad 2149941344 + .quad 2149941914 + .quad 2149943686 + .quad 2149945196 + .quad 2149945468 + .quad 2149946538 + .quad 2149946858 + .quad 2149948052 + .quad 2149950950 + .quad 2149950960 + .quad 2149951038 + .quad 2149951040 + .quad 2149951042 + .quad 2149951246 + .quad 2149951376 + .quad 2149951376 + .quad 2149951376 + .quad 2149951376 + .quad 2149951376 + .quad 2149951508 + .quad 2149951508 + .quad 2149951508 + .quad 2149951508 + .quad 2149951508 + .quad 2149951508 + .quad 2149951508 + .quad 2149951640 + .quad 2149951640 + .quad 2149951772 + .quad 2149951772 + .quad 2149951910 + .quad 2149952060 + .quad 2149952200 + .quad 2149952342 + .quad 2149952482 + .quad 2149952616 + .quad 2149952616 + .quad 2149952750 + .quad 2149952892 + .quad 2149952900 + .quad 2149953274 + .quad 2149953518 + .quad 2149955830 + .quad 2149958200 + .quad 2149958552 + .quad 2149958718 + .quad 2149958884 + .quad 2149959098 + .quad 2149959950 + .quad 2149961084 + .quad 2149961172 + .quad 2149961260 + .quad 2149961348 + .quad 2149961436 + .quad 2149961524 + .quad 2149961612 + .quad 2149961700 + .quad 2149961788 + .quad 2149961876 + .quad 2149961964 + .quad 2149962052 + .quad 2149962140 + .quad 2149962228 + .quad 2149962316 + .quad 2149962404 + .quad 2149962492 + .quad 2149962580 + .quad 2149962668 + .quad 2149962756 + .quad 2149962844 + .quad 2149962932 + .quad 2149963020 + .quad 2149963108 + .quad 2149963196 + .quad 2149963284 + .quad 2149963372 + .quad 2149963460 + .quad 2149963548 + .quad 2149963636 + .quad 2149963724 + .quad 2149963802 + .quad 2149963890 + .quad 2149963978 + .quad 2149964066 + .quad 2149964672 + .quad 2149964760 + .quad 2149964848 + .quad 2149964936 + .quad 2149965024 + .quad 2149965112 + .quad 2149965200 + .quad 2149965288 + .quad 2149965376 + .quad 2149965464 + .quad 2149965482 + .quad 2149965500 + .quad 2149965518 + .quad 2149965536 + .quad 2149965554 + .quad 2149965572 + .quad 2149965582 + .quad 2149965592 + .quad 2149965602 + .quad 2149965612 + .quad 2149965622 + .quad 2149965632 + .quad 2149965642 + .quad 2149965652 + .quad 2149965662 + .quad 2149965672 + .quad 2149965682 + .quad 2149965692 + .quad 2149965702 + .quad 2149965712 + .quad 2149965722 + .quad 2149965732 + .quad 2149965742 + .quad 2149965752 + .quad 2149965762 + .quad 2149965772 + .quad 2149965782 + .quad 2149965792 + .quad 2149965802 + .quad 2149965812 + .quad 2149965822 + .quad 2149965832 + .quad 2149965842 + .quad 2149965852 + .quad 2149965862 + .quad 2149965872 + .quad 2149965882 + .quad 2149965892 + .quad 2149965902 + .quad 2149965912 + .quad 2149965922 + .quad 2149965932 + .quad 2149965942 + .quad 2149965952 + .quad 2149965962 + .quad 2149965972 + .quad 2149965982 + .quad 2149965992 + .quad 2149966002 + .quad 2149966042 + .quad 2149966328 + .quad 2149966350 + .quad 2149966368 + .quad 2149966370 + .quad 2149966400 + .quad 2149966436 + .quad 2149966560 + .quad 2149966570 + .quad 2149966750 + .quad 2149966752 + .quad 2149966778 + .quad 2149966854 + .quad 2149966856 + .quad 2149967000 + .quad 2149967060 + .quad 2149967080 + .quad 2149967342 + .quad 2149967424 + .quad 2149968562 + .quad 2149970460 + .quad 2149970826 + .quad 2149971228 + .quad 2149971354 + .quad 2149972354 + .quad 2149972358 + .quad 2149972366 + .quad 2149972374 + .quad 2149973254 + .quad 2149973262 + .quad 2149973274 + .quad 2149973278 + .quad 2149973290 + .quad 2149973298 + .quad 2149973306 + .quad 2149973310 + .quad 2149973314 + .quad 2149973326 + .quad 2149973338 + .quad 2149973350 + .quad 2149973366 + .quad 2149973382 + .quad 2149973394 + .quad 2149973406 + .quad 2149973420 + .quad 2149973426 + .quad 2149973480 + .quad 2149973486 + .quad 2149973500 + .quad 2149973514 + .quad 2149973528 + .quad 2149973540 + .quad 2149973546 + .quad 2149973592 + .quad 2149973596 + .quad 2149973608 + .quad 2149973612 + .quad 2149973616 + .quad 2149973626 + .quad 2149973644 + .quad 2149973660 + .quad 2149973852 + .quad 2149974118 + .quad 2149974334 + .quad 2149974492 + .quad 2149974762 + .quad 2149975050 + .quad 2149975286 + .quad 2149975522 + .quad 2149975730 + .quad 2149975892 + .quad 2149976086 + .quad 2149976172 + .quad 2149976254 + .quad 2149976342 + .quad 2149977354 + .quad 2149977582 + .quad 2149977662 + .quad 2149977750 + .quad 2149977838 + .quad 2149978352 + .quad 2149978480 + .quad 2149978580 + .quad 2149978590 + .quad 2149978604 + .quad 2149978608 + .quad 2149978612 + .quad 2149978676 + .quad 2149978680 + .quad 2149978744 + .quad 2149980090 + .quad 2149986980 + .quad 2149987110 + .quad 2149988338 + .quad 2149990004 + .quad 2149990166 + .quad 2149990370 + .quad 2149991854 + .quad 2149992036 + .quad 2149992218 + .quad 2149992218 + .quad 2149992240 + .quad 2149992328 + .quad 2149992416 + .quad 2149992506 + .quad 2149992506 + .quad 2149992672 + .quad 2149993846 + .quad 2149994966 + .quad 2149995344 + .quad 2149995358 + .quad 2149995362 + .quad 2149995374 + .quad 2149995380 + .quad 2149995392 + .quad 2149995406 + .quad 2149995410 + .quad 2149995416 + .quad 2149996320 + .quad 2149996550 + .quad 2149996588 + .quad 2149996676 + .quad 2149996764 + .quad 2149996852 + .quad 2149996940 + .quad 2149997028 + .quad 2149997116 + .quad 2149997204 + .quad 2149997292 + .quad 2149998996 + .quad 2149999084 + .quad 2149999098 + .quad 2149999152 + .quad 2149999166 + .quad 2149999180 + .quad 2149999186 + .quad 2149999192 + .quad 2149999238 + .quad 2149999326 + .quad 2149999414 + .quad 2149999502 + .quad 2149999590 + .quad 2149999678 + .quad 2149999766 + .quad 2149999854 + .quad 2149999942 + .quad 2150000030 + .quad 2150000118 + .quad 2150001460 + .quad 2150001478 + .quad 2150001496 + .quad 2150001514 + .quad 2150001532 + .quad 2150001540 + .quad 2150001550 + .quad 2150001560 + .quad 2150001570 + .quad 2150001580 + .quad 2150001590 + .quad 2150001600 + .quad 2150001610 + .quad 2150001620 + .quad 2150001642 + .quad 2150001682 + .quad 2150001722 + .quad 2150001728 + .quad 2150001872 + .quad 2150001874 + .quad 2150001944 + .quad 2150001964 + .quad 2150001984 + .quad 2150002466 + .quad 2150002466 + .quad 2150002600 + .quad 2150002610 + .quad 2150002898 + .quad 2150002898 + .quad 2150003040 + .quad 2150003094 + .quad 2150003094 + .quad 2150003148 + .quad 2150003148 + .quad 2150003194 + .quad 2150003240 + .quad 2150003244 + .quad 2150003248 + .quad 2150003380 + .quad 2150003576 + .quad 2150003666 + .quad 2150003720 + .quad 2150004028 + .quad 2150004156 + .quad 2150004264 + .quad 2150004348 + .quad 2150004394 + .quad 2150004536 + .quad 2150004566 + .quad 2150004596 + .quad 2150004688 + .quad 2150004780 + .quad 2150005846 + .quad 2150008012 + .quad 2150008618 + .quad 2150009516 + .quad 2150010258 + .quad 2150010596 + .quad 2150010784 + .quad 2150011226 + .quad 2150011558 + .quad 2150012166 + .quad 2150013246 + .quad 2150013874 + .quad 2150014436 + .quad 2150014700 + .quad 2150015482 + .quad 2150016060 + .quad 2150016408 + .quad 2150016756 + .quad 2150017894 + .quad 2150018526 + .quad 2150019116 + .quad 2150020040 + .quad 2150020872 + .quad 2150021814 + .quad 2150022632 + .quad 2150023026 + .quad 2150024046 + .quad 2150024610 + .quad 2150025184 + .quad 2150025946 + .quad 2150026716 + .quad 2150026894 + .quad 2150027068 + .quad 2150027796 + .quad 2150028282 + .quad 2150028696 + .quad 2150029658 + .quad 2150029856 + .quad 2150029874 + .quad 2150029892 + .quad 2150029910 + .quad 2150029928 + .quad 2150029946 + .quad 2150029964 + .quad 2150029982 + .quad 2150029992 + .quad 2150030002 + .quad 2150030012 + .quad 2150030022 + .quad 2150030032 + .quad 2150030042 + .quad 2150030052 + .quad 2150030062 + .quad 2150030072 + .quad 2150030082 + .quad 2150030092 + .quad 2150030102 + .quad 2150030112 + .quad 2150030122 + .quad 2150030132 + .quad 2150030142 + .quad 2150030152 + .quad 2150030162 + .quad 2150030180 + .quad 2150030248 + .quad 2150030392 + .quad 2150030572 + .quad 2150030678 + .quad 2150030680 + .quad 2150030682 + .quad 2150030944 + .quad 2150031026 + .quad 2150031060 + .quad 2150031094 + .quad 2150031128 + .quad 2150031162 + .quad 2150031196 + .quad 2150031230 + .quad 2150031264 + .quad 2150031298 + .quad 2150032386 + .quad 2150032866 + .quad 2150033726 + .quad 2150034262 + .quad 2150034648 + .quad 2150036642 + .quad 2150037078 + .quad 2150038918 + .quad 2150039552 + .quad 2150039744 + .quad 2150039936 + .quad 2150040128 + .quad 2150040220 + .quad 2150040310 + .quad 2150040906 + .quad 2150041192 + .quad 2150041474 + .quad 2150041740 + .quad 2150041812 + .quad 2150041890 + .quad 2150041962 + .quad 2150042040 + .quad 2150042518 + .quad 2150043402 + .quad 2150044360 + .quad 2150045458 + .quad 2150045732 + .quad 2150045740 + .quad 2150045744 + .quad 2150045756 + .quad 2150045768 + .quad 2150045784 + .quad 2150045796 + .quad 2150045850 + .quad 2150045904 + .quad 2150045958 + .quad 2150046004 + .quad 2150046050 + .quad 2150046096 + .quad 2150046350 + .quad 2150046368 + .quad 2150046372 + .quad 2150046386 + .quad 2150046516 + .quad 2150046588 + .quad 2150046642 + .quad 2150046648 + .quad 2150046662 + .quad 2150046680 + .quad 2150046694 + .quad 2150046932 + .quad 2150046944 + .quad 2150046948 + .quad 2150046952 + .quad 2150046952 + .quad 2150047036 + .quad 2150047082 + .quad 2150047168 + .quad 2150047254 + .quad 2150047340 + .quad 2150047422 + .quad 2150047508 + .quad 2150047594 + .quad 2150048628 + .quad 2150048632 + .quad 2150048720 + .quad 2150048792 + .quad 2150048806 + .quad 2150049166 + .quad 2150049178 + .quad 2150049182 + .quad 2150049186 + .quad 2150049214 + .quad 2150049430 + .quad 2150049732 + .quad 2150049864 + .quad 2150050060 + .quad 2150050150 + .quad 2150050204 + .quad 2150050512 + .quad 2150050620 + .quad 2150050820 + .quad 2150050866 + .quad 2150050936 + .quad 2150050974 + .quad 2150051132 + .quad 2150051160 + .quad 2150051612 + .quad 2150052582 + .quad 2150052670 + .quad 2150052822 + .quad 2150053188 + .quad 2150053272 + .quad 2150053668 + .quad 2150053806 + .quad 2150054722 + .quad 2150054810 + .quad 2150055178 + .quad 2150055394 + .quad 2150055476 + .quad 2150056006 + .quad 2150056134 + .quad 2150056234 + .quad 2150056490 + .quad 2150056884 + .quad 2150057418 + .quad 2150057630 + .quad 2150058166 + .quad 2150058858 + .quad 2150059234 + .quad 2150059770 + .quad 2150060608 + .quad 2150061096 + .quad 2150061500 + .quad 2150061554 + .quad 2150061556 + .quad 2150062502 + .quad 2150062804 + .quad 2150062822 + .quad 2150062844 + .quad 2150062946 + .quad 2150062988 + .quad 2150062992 + .quad 2150062998 + .quad 2150063002 + .quad 2150063044 + .quad 2150063046 + .quad 2150063218 + .quad 2150063238 + .quad 2150063280 + .quad 2150063280 + .quad 2150063280 + .quad 2150063280 + .quad 2150063280 + .quad 2150063280 + .quad 2150063282 + .quad 2150063316 + .quad 2150063564 + .quad 2150063744 + .quad 2150064082 + .quad 2150064318 + .quad 2150064328 + .quad 2150064330 + .quad 2150064728 + .quad 2150066768 + .quad 2150066988 + .quad 2150067476 + .quad 2150067896 + .quad 2150067982 + .quad 2150068246 + .quad 2150068284 + .quad 2150068790 + .quad 2150068964 + .quad 2150069470 + .quad 2150069632 + .quad 2150069656 + .quad 2150069658 + .quad 2150069838 + .quad 2150071310 + .quad 2150072200 + .quad 2150072642 + .quad 2150072682 + .quad 2150072750 + .quad 2150072818 + .quad 2150072822 + .quad 2150072826 + .quad 2150072826 + .quad 2150072912 + .quad 2150072912 + .quad 2150072998 + .quad 2150073238 + .quad 2150073238 + .quad 2150073922 + .quad 2150073964 + .quad 2150074036 + .quad 2150074094 + .quad 2150074128 + .quad 2150074130 + .quad 2150074198 + .quad 2150074234 + .quad 2150074302 + .quad 2150074444 + .quad 2150074770 + .quad 2150074934 + .quad 2150075290 + .quad 2150075944 + .quad 2150076278 + .quad 2150076320 + .quad 2150076682 + .quad 2150076748 + .quad 2150077300 + .quad 2150077820 + .quad 2150078268 + .quad 2150078896 + .quad 2150078978 + .quad 2150079020 + .quad 2150079062 + .quad 2150079104 + .quad 2150079114 + .quad 2150079124 + .quad 2150079126 + .quad 2150079388 + .quad 2150079550 + .quad 2150079692 + .quad 2150079814 + .quad 2150079948 + .quad 2150080232 + .quad 2150080350 + .quad 2150080670 + .quad 2150080720 + .quad 2150080796 + .quad 2150080922 + .quad 2150080974 + .quad 2150081014 + .quad 2150081196 + .quad 2150081354 + .quad 2150081394 + .quad 2150081434 + .quad 2150081474 + .quad 2150081476 + .quad 2150081478 + .quad 2150081480 + .quad 2150081482 + .quad 2150081802 + .quad 2150081838 + .quad 2150081900 + .quad 2150081982 + .quad 2150082678 + .quad 2150082842 + .quad 2150083398 + .quad 2150083580 + .quad 2150083656 + .quad 2150083770 + .quad 2150083772 + .quad 2150083842 + .quad 2150083848 + .quad 2150083880 + .quad 2150083902 + .quad 2150083920 + .quad 2150083932 + .quad 2150083942 + .quad 2150083948 + .quad 2150083962 + .quad 2150084186 + .quad 2150084262 + .quad 2150084296 + .quad 2150084310 + .quad 2150084318 + .quad 2150084364 + .quad 2150084468 + .quad 2150084588 + .quad 2150084590 + .quad 2150084634 + .quad 2150085488 + .quad 2150086140 + .quad 2150086790 + .quad 2150086832 + .quad 2150086874 + .quad 2150086916 + .quad 2150086926 + .quad 2150086966 + .quad 2150086968 + .quad 2150086970 + .quad 2150087074 + .quad 2150087372 + .quad 2150087492 + .quad 2150087532 + .quad 2150087572 + .quad 2150087574 + .quad 2150087576 + .quad 2150087620 + .quad 2150087664 + .quad 2150087826 + .quad 2150087952 + .quad 2150088094 + .quad 2150088214 + .quad 2150088224 + .quad 2150088264 + .quad 2150088266 + .quad 2150088300 + .quad 2150088374 + .quad 2150088458 + .quad 2150088502 + .quad 2150088886 + .quad 2150088928 + .quad 2150088946 + .quad 2150088964 + .quad 2150089100 + .quad 2150089222 + .quad 2150089362 + .quad 2150089380 + .quad 2150089426 + .quad 2150089634 + .quad 2150089792 + .quad 2150089924 + .quad 2150089932 + .quad 2150089936 + .quad 2150089950 + .quad 2150089962 + .quad 2150089970 + .quad 2150089978 + .quad 2150089986 + .quad 2150090000 + .quad 2150090012 + .quad 2150090020 + .quad 2150090032 + .quad 2150090044 + .quad 2150090150 + .quad 2150090244 + .quad 2150090284 + .quad 2150090286 + .quad 2150090440 + .quad 2150091082 + .quad 2150091574 + .quad 2150091834 + .quad 2150091854 + .quad 2150091864 + .quad 2150091884 + .quad 2150091962 + .quad 2150092362 + .quad 2150092372 + .quad 2150092394 + .quad 2150092414 + .quad 2150092462 + .quad 2150092502 + .quad 2150094032 + .quad 2150094458 + .quad 2150094868 + .quad 2150095754 + .quad 2150096308 + .quad 2150096880 + .quad 2150097452 + .quad 2150097836 + .quad 2150098070 + .quad 2150098168 + .quad 2150098550 + .quad 2150098552 + .quad 2150098776 + .quad 2150099124 + .quad 2150099456 + .quad 2150099878 + .quad 2150100128 + .quad 2150100404 + .quad 2150100890 + .quad 2150101232 + .quad 2150101690 + .quad 2150101892 + .quad 2150102350 + .quad 2150102918 + .quad 2150103240 + .quad 2150103766 + .quad 2150104416 + .quad 2150104824 + .quad 2150104826 + .quad 2150105160 + .quad 2150105846 + .quad 2150106442 + .quad 2150106960 + .quad 2150107594 + .quad 2150108132 + .quad 2150109146 + .quad 2150109616 + .quad 2150109900 + .quad 2150112868 + .quad 2150113102 + .quad 2150114326 + .quad 2150114560 + .quad 2150114794 + .quad 2150115968 + .quad 2150117434 + .quad 2150117684 + .quad 2150117948 + .quad 2150118038 + .quad 2150118172 + .quad 2150118810 + .quad 2150119060 + .quad 2150119628 + .quad 2150120020 + .quad 2150120154 + .quad 2150120344 + .quad 2150120486 + .quad 2150121144 + .quad 2150121376 + .quad 2150121620 + .quad 2150121620 + .quad 2150121694 + .quad 2150122092 + .quad 2150122328 + .quad 2150122772 + .quad 2150123410 + .quad 2150124194 + .quad 2150124424 + .quad 2150124658 + .quad 2150124912 + .quad 2150125262 + .quad 2150125264 + .quad 2150126250 + .quad 2150127032 + .quad 2150128646 + .quad 2150128654 + .quad 2150128664 + .quad 2150128706 + .quad 2150128726 + .quad 2150128728 + .quad 2150128730 + .quad 2150128846 + .quad 2150129768 + .quad 2150130174 + .quad 2150130216 + .quad 2150130298 + .quad 2150130700 + .quad 2150130764 + .quad 2150131518 + .quad 2150131774 + .quad 2150131992 + .quad 2150132226 + .quad 2150132348 + .quad 2150132480 + .quad 2150132622 + .quad 2150132632 + .quad 2150133124 + .quad 2150133430 + .quad 2150133936 + .quad 2150133946 + .quad 2150133948 + .quad 2150133982 + .quad 2150134016 + .quad 2150134146 + .quad 2150134434 + .quad 2150134456 + .quad 2150135716 + .quad 2150135842 + .quad 2150135874 + .quad 2150135876 + .quad 2150135944 + .quad 2150135946 + .quad 2150136036 + .quad 2150136038 + .quad 2150136438 + .quad 2150136452 + .quad 2150136456 + .quad 2150136460 + .quad 2150136462 + .quad 2150136464 + .quad 2150136510 + .quad 2150136530 + .quad 2150136542 + .quad 2150136604 + .quad 2150136622 + .quad 2150136780 + .quad 2150137542 + .quad 2150137936 + .quad 2150138188 + .quad 2150139508 + .quad 2150139752 + .quad 2150140162 + .quad 2150140780 + .quad 2150141090 + .quad 2150141574 + .quad 2150142568 + .quad 2150143184 + .quad 2150143816 + .quad 2150146778 + .quad 2150146806 + .quad 2150146834 + .quad 2150146942 + .quad 2150147330 + .quad 2150147546 + .quad 2150147698 + .quad 2150150770 + .quad 2150150810 + .quad 2150150850 + .quad 2150150890 + .quad 2150150892 + .quad 2150150894 + .quad 2150151082 + .quad 2150151184 + .quad 2150152848 + .quad 2150152890 + .quad 2150153072 + .quad 2150153114 + .quad 2150153236 + .quad 2150153278 + .quad 2150153320 + .quad 2150153340 + .quad 2150153344 + .quad 2150153362 + .quad 2150153486 + .quad 2150153626 + .quad 2150154194 + .quad 2150154238 + .quad 2150154238 + .quad 2150154240 + .quad 2150154270 + .quad 2150154352 + .quad 2150154356 + .quad 2150154374 + .quad 2150154408 + .quad 2150154408 + .quad 2150154408 + .quad 2150154524 + .quad 2150154562 + .quad 2150154596 + .quad 2150154638 + .quad 2150154648 + .quad 2150154688 + .quad 2150154728 + .quad 2150154768 + .quad 2150154770 + .quad 2150154772 + .quad 2150154774 + .quad 2150155388 + .quad 2150155810 + .quad 2150156052 + .quad 2150156470 + .quad 2150156582 + .quad 2150156886 + .quad 2150157108 + .quad 2150157268 + .quad 2150157502 + .quad 2150157834 + .quad 2150159376 + .quad 2150161546 + .quad 2150163210 + .quad 2150163506 + .quad 2150163810 + .quad 2150163850 + .quad 2150163852 + .quad 2150165220 + .quad 2150165258 + .quad 2150165260 + .quad 2150166202 + .quad 2150166284 + .quad 2150166326 + .quad 2150166368 + .quad 2150166408 + .quad 2150166408 + .quad 2150166408 + .quad 2150166408 + .quad 2150166408 + .quad 2150166410 + .quad 2150166492 + .quad 2150166534 + .quad 2150168306 + .quad 2150168346 + .quad 2150168348 + .quad 2150168450 + .quad 2150168588 + .quad 2150168604 + .quad 2150168738 + .quad 2150169370 + .quad 2150169412 + .quad 2150169456 + .quad 2150169458 + .quad 2150169724 + .quad 2150169792 + .quad 2150169862 + .quad 2150169930 + .quad 2150170006 + .quad 2150170022 + .quad 2150170076 + .quad 2150170208 + .quad 2150170672 + .quad 2150171162 + .quad 2150171524 + .quad 2150171570 + .quad 2150171762 + .quad 2150171802 + .quad 2150171868 + .quad 2150171910 + .quad 2150172004 + .quad 2150172046 + .quad 2150172086 + .quad 2150172172 + .quad 2150172212 + .quad 2150172252 + .quad 2150172582 + .quad 2150172646 + .quad 2150172784 + .quad 2150173082 + .quad 2150173388 + .quad 2150173760 + .quad 2150173818 + .quad 2150173960 + .quad 2150174084 + .quad 2150174280 + .quad 2150174820 + .quad 2150174982 + .quad 2150181542 + .quad 2150181860 + .quad 2150181948 + .quad 2150182002 + .quad 2150182044 + .quad 2150182084 + .quad 2150182096 + .quad 2150184320 + .quad 2150184764 + .quad 2150184996 + .quad 2150185006 + .quad 2150185008 + .quad 2150185256 + .quad 2150185318 + .quad 2150185378 + .quad 2150185438 + .quad 2150185496 + .quad 2150186104 + .quad 2150186918 + .quad 2150188100 + .quad 2150188182 + .quad 2150189222 + .quad 2150189724 + .quad 2150189768 + .quad 2150190962 + .quad 2150193606 + .quad 2150194512 + .quad 2150194512 + .quad 2150194534 + .quad 2150194692 + .quad 2150194888 + .quad 2150195150 + .quad 2150195880 + .quad 2150196084 + .quad 2150196472 + .quad 2150196478 + .quad 2150196576 + .quad 2150196620 + .quad 2150196620 + .quad 2150196620 + .quad 2150196620 + .quad 2150196620 + .quad 2150196620 + .quad 2150196620 + .quad 2150196620 + .quad 2150196620 + .quad 2150196620 + .quad 2150196620 + .quad 2150196620 + .quad 2150196622 + .quad 2150197428 + .quad 2150198082 + .quad 2150198146 + .quad 2150199458 + .quad 2150199680 + .quad 2150199904 + .quad 2150200210 + .quad 2150200300 + .quad 2150200302 + .quad 2150200586 + .quad 2150200972 + .quad 2150201012 + .quad 2150201062 + .quad 2150201448 + .quad 2150201538 + .quad 2150201582 + .quad 2150201656 + .quad 2150201790 + .quad 2150201892 + .quad 2150201992 + .quad 2150202014 + .quad 2150202058 + .quad 2150202102 + .quad 2150202448 + .quad 2150202928 + .quad 2150203434 + .quad 2150203950 + .quad 2150204282 + .quad 2150204516 + .quad 2150204864 + .quad 2150205184 + .quad 2150205554 + .quad 2150205598 + .quad 2150205642 + .quad 2150205724 + .quad 2150205726 + .quad 2150205728 + .quad 2150205784 + .quad 2150205900 + .quad 2150206272 + .quad 2150206756 + .quad 2150206820 + .quad 2150206864 + .quad 2150206906 + .quad 2150207028 + .quad 2150207116 + .quad 2150207158 + .quad 2150207244 + .quad 2150207286 + .quad 2150207538 + .quad 2150207558 + .quad 2150207724 + .quad 2150208300 + .quad 2150208372 + .quad 2150208624 + .quad 2150208806 + .quad 2150209114 + .quad 2150209386 + .quad 2150209700 + .quad 2150209842 + .quad 2150209882 + .quad 2150209884 + .quad 2150209886 + .quad 2150209888 + .quad 2150209936 + .quad 2150210166 + .quad 2150210360 + .quad 2150210736 + .quad 2150210830 + .quad 2150210986 + .quad 2150211100 + .quad 2150211110 + .quad 2150211298 + .quad 2150211610 + .quad 2150212142 + .quad 2150212498 + .quad 2150213128 + .quad 2150213186 + .quad 2150213566 + .quad 2150213794 + .quad 2150213794 + .quad 2150213816 + .quad 2150214238 + .quad 2150214334 + .quad 2150214494 + .quad 2150214550 + .quad 2150214594 + .quad 2150214638 + .quad 2150214640 + .quad 2150214712 + .quad 2150214714 + .quad 2150214716 + .quad 2150214738 + .quad 2150214758 + .quad 2150214760 + .quad 2150214762 + .quad 2150214764 + .quad 2150215794 + .quad 2150218216 + .quad 2150218656 + .quad 2150218980 + .quad 2150219218 + .quad 2150219710 + .quad 2150220478 + .quad 2150221660 + .quad 2150222456 + .quad 2150222916 + .quad 2150222964 + .quad 2150223668 + .quad 2150224188 + .quad 2150224570 + .quad 2150224666 + .quad 2150224918 + .quad 2150225810 + .quad 2150225974 + .quad 2150226162 + .quad 2150226204 + .quad 2150226600 + .quad 2150226954 + .quad 2150227064 + .quad 2150227106 + .quad 2150227108 + .quad 2150227142 + .quad 2150227168 + .quad 2150227206 + .quad 2150227266 + .quad 2150227442 + .quad 2150227484 + .quad 2150227536 + .quad 2150227544 + .quad 2150227650 + .quad 2150227756 + .quad 2150227862 + .quad 2150227968 + .quad 2150228074 + .quad 2150228096 + .quad 2150228118 + .quad 2150228120 + .quad 2150228122 + .quad 2150228152 + .quad 2150228156 + .quad 2150228158 + .quad 2150228160 + .quad 2150228258 + .quad 2150228446 + .quad 2150228490 + .quad 2150228512 + .quad 2150228514 + .quad 2150228532 + .quad 2150228672 + .quad 2150228810 + .quad 2150228934 + .quad 2150228986 + .quad 2150229006 + .quad 2150229136 + .quad 2150229364 + .quad 2150229806 + .quad 2150230064 + .quad 2150230180 + .quad 2150230262 + .quad 2150230282 + .quad 2150230348 + .quad 2150230352 + .quad 2150230354 + .quad 2150230356 + .quad 2150230780 + .quad 2150230880 + .quad 2150230898 + .quad 2150230898 + .quad 2150230898 + .quad 2150230960 + .quad 2150230978 + .quad 2150230996 + .quad 2150231052 + .quad 2150231108 + .quad 2150231878 + .quad 2150231946 + .quad 2150232014 + .quad 2150232082 + .quad 2150232150 + .quad 2150232458 + .quad 2150234156 + .quad 2150234182 + .quad 2150234208 + .quad 2150234484 + .quad 2150234954 + .quad 2150235012 + .quad 2150235058 + .quad 2150235106 + .quad 2150235150 + .quad 2150235214 + .quad 2150235258 + .quad 2150235484 + .quad 2150235560 + .quad 2150236036 + .quad 2150236132 + .quad 2150236510 + .quad 2150236602 + .quad 2150236850 + .quad 2150236984 + .quad 2150237242 + .quad 2150237242 + .quad 2150237268 + .quad 2150237298 + .quad 2150237534 + .quad 2150237770 + .quad 2150238006 + .quad 2150238242 + .quad 2150238264 + .quad 2150238286 + .quad 2150238308 + .quad 2150238330 + .quad 2150238352 + .quad 2150238370 + .quad 2150238752 + .quad 2150239276 + .quad 2150239362 + .quad 2150239920 + .quad 2150239920 + .quad 2150239928 + .quad 2150239928 + .quad 2150239948 + .quad 2150239994 + .quad 2150240140 + .quad 2150240328 + .quad 2150240554 + .quad 2150240814 + .quad 2150241108 + .quad 2150241302 + .quad 2150241362 + .quad 2150241524 + .quad 2150241714 + .quad 2150241766 + .quad 2150241810 + .quad 2150242556 + .quad 2150242572 + .quad 2150242864 + .quad 2150243060 + .quad 2150243246 + .quad 2150243446 + .quad 2150243722 + .quad 2150243786 + .quad 2150243850 + .quad 2150243914 + .quad 2150243980 + .quad 2150244510 + .quad 2150244910 + .quad 2150245024 + .quad 2150245956 + .quad 2150246488 + .quad 2150246502 + .quad 2150247212 + .quad 2150247480 + .quad 2150247778 + .quad 2150247786 + .quad 2150247786 + .quad 2150247904 + .quad 2150247904 + .quad 2150248022 + .quad 2150248022 + .quad 2150248140 + .quad 2150248140 + .quad 2150248258 + .quad 2150248258 + .quad 2150248356 + .quad 2150248356 + .quad 2150248472 + .quad 2150248472 + .quad 2150248588 + .quad 2150248588 + .quad 2150248588 + .quad 2150248588 + .quad 2150248686 + .quad 2150248686 + .quad 2150248686 + .quad 2150248686 + .quad 2150248800 + .quad 2150248800 + .quad 2150248800 + .quad 2150248800 + .quad 2150248914 + .quad 2150249162 + .quad 2150249400 + .quad 2150249756 + .quad 2150249772 + .quad 2150249788 + .quad 2150249828 + .quad 2150249844 + .quad 2150249844 + .quad 2150249878 + .quad 2150249878 + .quad 2150249892 + .quad 2150249910 + .quad 2150249920 + .quad 2150250118 + .quad 2150250128 + .quad 2150250136 + .quad 2150250146 + .quad 2150250162 + .quad 2150250172 + .quad 2150250292 + .quad 2150250472 + .quad 2150250754 + .quad 2150250930 + .quad 2150251322 + .quad 2150251424 + .quad 2150251456 + .quad 2150251464 + .quad 2150251570 + .quad 2150253002 + .quad 2150253010 + .quad 2150253018 + .quad 2150256640 + .quad 2150256640 + .quad 2150272128 + .quad 2150272136 + .quad 2150298712 + .quad 2150325288 + .quad 2150577808 + .quad 2150587552 + .quad 2150587648 + .quad 2150588800 + .quad 2150601968 + .quad 2150644944 + .quad 2150654240 + .quad 2150660392 + .quad 2150660524 + .quad 2150662144 + .quad 2150666240 + .quad 2150666240 + .quad 2150666240 + .quad 2150666248 + .quad 2150666256 + .quad 2150666264 + .quad 2150666272 + .quad 2150666280 + .quad 2150666288 + .quad 2150666296 + .quad 2150666304 + .quad 2150666312 + .quad 2150666320 + .quad 2150666328 + .quad 2150666336 + .quad 2150666344 + .quad 2150666352 + .quad 2150666360 + .quad 2150666368 + .quad 2150666376 + .quad 2150666384 + .quad 2150666392 + .quad 2150666400 + .quad 2150666408 + .quad 2150666416 + .quad 2150666424 + .quad 2150666432 + .quad 2150666440 + .quad 2150666448 + .quad 2150666456 + .quad 2150666464 + .quad 2150666472 + .quad 2150666480 + .quad 2150666488 + .quad 2150666496 + .quad 2150666504 + .quad 2150666512 + .quad 2150666520 + .quad 2150666528 + .quad 2150666536 + .quad 2150666544 + .quad 2150666552 + .quad 2150666560 + .quad 2150666568 + .quad 2150666576 + .quad 2150666584 + .quad 2150666592 + .quad 2150666600 + .quad 2150666608 + .quad 2150666616 + .quad 2150666624 + .quad 2150666632 + .quad 2150666640 + .quad 2150666648 + .quad 2150666656 + .quad 2150666664 + .quad 2150666672 + .quad 2150666680 + .quad 2150666688 + .quad 2150666696 + .quad 2150666704 + .quad 2150666712 + .quad 2150666720 + .quad 2150666728 + .quad 2150666736 + .quad 2150666744 + .quad 2150666752 + .quad 2150666760 + .quad 2150666768 + .quad 2150666776 + .quad 2150666784 + .quad 2150666792 + .quad 2150666800 + .quad 2150666808 + .quad 2150666816 + .quad 2150666824 + .quad 2150666832 + .quad 2150666840 + .quad 2150666848 + .quad 2150666856 + .quad 2150666864 + .quad 2150666872 + .quad 2150666880 + .quad 2150666888 + .quad 2150666896 + .quad 2150666904 + .quad 2150666912 + .quad 2150666920 + .quad 2150666928 + .quad 2150666936 + .quad 2150666944 + .quad 2150666952 + .quad 2150666960 + .quad 2150666968 + .quad 2150666976 + .quad 2150666984 + .quad 2150666992 + .quad 2150667000 + .quad 2150667008 + .quad 2150667016 + .quad 2150667024 + .quad 2150667032 + .quad 2150667040 + .quad 2150667048 + .quad 2150667056 + .quad 2150667064 + .quad 2150667072 + .quad 2150667080 + .quad 2150667088 + .quad 2150667096 + .quad 2150667104 + .quad 2150667112 + .quad 2150667120 + .quad 2150667128 + .quad 2150667136 + .quad 2150667144 + .quad 2150667152 + .quad 2150667160 + .quad 2150667168 + .quad 2150667176 + .quad 2150667184 + .quad 2150667192 + .quad 2150667200 + .quad 2150667208 + .quad 2150667216 + .quad 2150667224 + .quad 2150667232 + .quad 2150667240 + .quad 2150667248 + .quad 2150667256 + .quad 2150667264 + .quad 2150667272 + .quad 2150667280 + .quad 2150667280 + .quad 2150667352 + .quad 2150667376 + .quad 2150668488 + .quad 2150668512 + .quad 2150668536 + .quad 2150668560 + .quad 2150668584 + .quad 2150668608 + .quad 2150668632 + .quad 2150668656 + .quad 2150668680 + .quad 2150668704 + .quad 2150668728 + .quad 2150668752 + .quad 2150668776 + .quad 2150668800 + .quad 2150668824 + .quad 2150668848 + .quad 2150668872 + .quad 2150668896 + .quad 2150668920 + .quad 2150668944 + .quad 2150668968 + .quad 2150668992 + .quad 2150669016 + .quad 2150669040 + .quad 2150669064 + .quad 2150669088 + .quad 2150669112 + .quad 2150669136 + .quad 2150669160 + .quad 2150669216 + .quad 2150669272 + .quad 2150669296 + .quad 2150669320 + .quad 2150669344 + .quad 2150669368 + .quad 2150669392 + .quad 2150669416 + .quad 2150669440 + .quad 2150669464 + .quad 2150669488 + .quad 2150669512 + .quad 2150669536 + .quad 2150669560 + .quad 2150669584 + .quad 2150669608 + .quad 2150669632 + .quad 2150669656 + .quad 2150669680 + .quad 2150669704 + .quad 2150669728 + .quad 2150669752 + .quad 2150669776 + .quad 2150669800 + .quad 2150669824 + .quad 2150669848 + .quad 2150669872 + .quad 2150669896 + .quad 2150669920 + .quad 2150669944 + .quad 2150669968 + .quad 2150669992 + .quad 2150670048 + .quad 2150670072 + .quad 2150670096 + .quad 2150670120 + .quad 2150670144 + .quad 2150670168 + .quad 2150670192 + .quad 2150670216 + .quad 2150670240 + .quad 2150670264 + .quad 2150670288 + .quad 2150670312 + .quad 2150670336 + .quad 2150670360 + .quad 2150670384 + .quad 2150670440 + .quad 2150670480 + .quad 2150670504 + .quad 2150670528 + .quad 2150670552 + .quad 2150670576 + .quad 2150670600 + .quad 2150670624 + .quad 2150670648 + .quad 2150670672 + .quad 2150670696 + .quad 2150670720 + .quad 2150670744 + .quad 2150670768 + .quad 2150670792 + .quad 2150670816 + .quad 2150670840 + .quad 2150670864 + .quad 2150670888 + .quad 2150670912 + .quad 2150670936 + .quad 2150670960 + .quad 2150670984 + .quad 2150671008 + .quad 2150671032 + .quad 2150671056 + .quad 2150671080 + .quad 2150671104 + .quad 2150671128 + .quad 2150671152 + .quad 2150671176 + .quad 2150671200 + .quad 2150671224 + .quad 2150671248 + .quad 2150671272 + .quad 2150671296 + .quad 2150671320 + .quad 2150671344 + .quad 2150671368 + .quad 2150671392 + .quad 2150671416 + .quad 2150671440 + .quad 2150671464 + .quad 2150671488 + .quad 2150671512 + .quad 2150671536 + .quad 2150671560 + .quad 2150671584 + .quad 2150671608 + .quad 2150671632 + .quad 2150671656 + .quad 2150671680 + .quad 2150671704 + .quad 2150671728 + .quad 2150671752 + .quad 2150671776 + .quad 2150671800 + .quad 2150671824 + .quad 2150671848 + .quad 2150671872 + .quad 2150671896 + .quad 2150671920 + .quad 2150671944 + .quad 2150672000 + .quad 2150672056 + .quad 2150672112 + .quad 2150672136 + .quad 2150672160 + .quad 2150672216 + .quad 2150672248 + .quad 2150674168 + .quad 2150674176 + .quad 2150678528 + .quad 2150678528 + .quad 2150744064 + .quad 2150744064 + .quad 2150744128 + .quad 2150744168 + .quad 2150744184 + .quad 2190590072 + .quad 2190590112 + .quad 2190590152 + .quad 2190590176 + .quad 2190590296 + .quad 2190590320 + .quad 2190590344 + .quad 2190590384 + .quad 2190590408 + .quad 2190590432 + .quad 2190590528 + .quad 2190590552 + .quad 2190590608 + .quad 2190590632 + .quad 2190590656 + .quad 2190590680 + .quad 2190590704 + .quad 2190591104 + .quad 2190591232 + .quad 2190591240 + .quad 2190591248 + .quad 2190591249 + .quad 2190591250 + .quad 2190591251 + .quad 2190591256 + .quad 2190591264 + .quad 2190591272 + .quad 2190591280 + .quad 2190594048 + .quad 2190594048 +.globl symbol_index +symbol_index: + .quad 0 + .quad 8 + .quad 14 + .quad 26 + .quad 33 + .quad 40 + .quad 84 + .quad 96 + .quad 140 + .quad 184 + .quad 228 + .quad 272 + .quad 310 + .quad 348 + .quad 386 + .quad 432 + .quad 478 + .quad 515 + .quad 558 + .quad 597 + .quad 644 + .quad 696 + .quad 738 + .quad 779 + .quad 819 + .quad 859 + .quad 899 + .quad 944 + .quad 989 + .quad 1034 + .quad 1077 + .quad 1120 + .quad 1163 + .quad 1206 + .quad 1255 + .quad 1295 + .quad 1339 + .quad 1383 + .quad 1426 + .quad 1464 + .quad 1502 + .quad 1540 + .quad 1578 + .quad 1616 + .quad 1654 + .quad 1700 + .quad 1737 + .quad 1783 + .quad 1829 + .quad 1868 + .quad 1916 + .quad 1963 + .quad 2010 + .quad 2057 + .quad 2101 + .quad 2143 + .quad 2184 + .quad 2225 + .quad 2270 + .quad 2313 + .quad 2356 + .quad 2399 + .quad 2442 + .quad 2485 + .quad 2528 + .quad 2571 + .quad 2615 + .quad 2659 + .quad 2698 + .quad 2736 + .quad 2782 + .quad 2828 + .quad 2871 + .quad 2919 + .quad 2964 + .quad 3007 + .quad 3047 + .quad 3087 + .quad 3127 + .quad 3171 + .quad 3215 + .quad 3259 + .quad 3303 + .quad 3346 + .quad 3387 + .quad 3425 + .quad 3463 + .quad 3501 + .quad 3542 + .quad 3588 + .quad 3626 + .quad 3663 + .quad 3709 + .quad 3755 + .quad 3801 + .quad 3844 + .quad 3891 + .quad 3938 + .quad 3980 + .quad 4021 + .quad 4062 + .quad 4103 + .quad 4143 + .quad 4183 + .quad 4229 + .quad 4272 + .quad 4315 + .quad 4358 + .quad 4401 + .quad 4444 + .quad 4487 + .quad 4530 + .quad 4573 + .quad 4616 + .quad 4659 + .quad 4702 + .quad 4745 + .quad 4788 + .quad 4828 + .quad 4868 + .quad 4908 + .quad 4948 + .quad 4992 + .quad 5036 + .quad 5080 + .quad 5117 + .quad 5154 + .quad 5200 + .quad 5242 + .quad 5284 + .quad 5325 + .quad 5370 + .quad 5415 + .quad 5459 + .quad 5502 + .quad 5546 + .quad 5589 + .quad 5619 + .quad 5651 + .quad 5684 + .quad 5715 + .quad 5720 + .quad 5747 + .quad 5756 + .quad 5787 + .quad 5818 + .quad 5849 + .quad 5880 + .quad 5911 + .quad 5942 + .quad 5973 + .quad 6004 + .quad 6034 + .quad 6066 + .quad 6107 + .quad 6148 + .quad 6189 + .quad 6230 + .quad 6271 + .quad 6312 + .quad 6353 + .quad 6394 + .quad 6435 + .quad 6476 + .quad 6518 + .quad 6560 + .quad 6602 + .quad 6644 + .quad 6691 + .quad 6733 + .quad 6775 + .quad 6817 + .quad 6859 + .quad 6901 + .quad 6943 + .quad 6980 + .quad 7017 + .quad 7054 + .quad 7091 + .quad 7128 + .quad 7165 + .quad 7202 + .quad 7239 + .quad 7276 + .quad 7313 + .quad 7352 + .quad 7391 + .quad 7430 + .quad 7469 + .quad 7508 + .quad 7547 + .quad 7586 + .quad 7625 + .quad 7664 + .quad 7703 + .quad 7756 + .quad 7857 + .quad 7976 + .quad 8087 + .quad 8202 + .quad 8319 + .quad 8442 + .quad 8567 + .quad 8701 + .quad 8841 + .quad 8995 + .quad 9151 + .quad 9191 + .quad 9242 + .quad 9269 + .quad 9296 + .quad 9335 + .quad 9375 + .quad 9432 + .quad 9491 + .quad 9550 + .quad 9609 + .quad 9672 + .quad 9737 + .quad 9802 + .quad 9867 + .quad 9912 + .quad 9963 + .quad 10008 + .quad 10037 + .quad 10067 + .quad 10097 + .quad 10129 + .quad 10161 + .quad 10194 + .quad 10259 + .quad 10325 + .quad 10391 + .quad 10457 + .quad 10525 + .quad 10594 + .quad 10668 + .quad 10746 + .quad 10813 + .quad 10884 + .quad 10955 + .quad 11027 + .quad 11099 + .quad 11172 + .quad 11247 + .quad 11325 + .quad 11400 + .quad 11475 + .quad 11550 + .quad 11630 + .quad 11710 + .quad 11791 + .quad 11876 + .quad 11950 + .quad 12025 + .quad 12101 + .quad 12177 + .quad 12253 + .quad 12330 + .quad 12408 + .quad 12486 + .quad 12564 + .quad 12642 + .quad 12721 + .quad 12800 + .quad 12875 + .quad 12952 + .quad 13030 + .quad 13105 + .quad 13187 + .quad 13274 + .quad 13351 + .quad 13429 + .quad 13507 + .quad 13587 + .quad 13667 + .quad 13747 + .quad 13828 + .quad 13908 + .quad 13989 + .quad 14074 + .quad 14148 + .quad 14223 + .quad 14299 + .quad 14375 + .quad 14451 + .quad 14536 + .quad 14613 + .quad 14691 + .quad 14769 + .quad 14848 + .quad 14932 + .quad 15013 + .quad 15094 + .quad 15175 + .quad 15263 + .quad 15349 + .quad 15388 + .quad 15416 + .quad 15460 + .quad 15472 + .quad 15506 + .quad 15550 + .quad 15567 + .quad 15606 + .quad 15625 + .quad 15655 + .quad 15699 + .quad 15740 + .quad 15782 + .quad 15819 + .quad 15858 + .quad 15913 + .quad 15952 + .quad 16067 + .quad 16099 + .quad 16130 + .quad 16179 + .quad 16236 + .quad 16304 + .quad 16367 + .quad 16403 + .quad 16442 + .quad 16479 + .quad 16520 + .quad 16555 + .quad 16593 + .quad 16633 + .quad 16673 + .quad 16708 + .quad 16743 + .quad 16781 + .quad 16824 + .quad 16867 + .quad 16910 + .quad 16953 + .quad 16996 + .quad 17039 + .quad 17078 + .quad 17120 + .quad 17162 + .quad 17205 + .quad 17247 + .quad 17294 + .quad 17338 + .quad 17382 + .quad 17429 + .quad 17481 + .quad 17533 + .quad 17585 + .quad 17633 + .quad 17681 + .quad 17729 + .quad 17777 + .quad 17820 + .quad 17860 + .quad 17897 + .quad 17940 + .quad 17990 + .quad 18041 + .quad 18098 + .quad 18149 + .quad 18187 + .quad 18222 + .quad 18256 + .quad 18287 + .quad 18344 + .quad 18431 + .quad 18490 + .quad 18549 + .quad 18592 + .quad 18635 + .quad 18678 + .quad 18721 + .quad 18769 + .quad 18799 + .quad 18840 + .quad 18881 + .quad 18922 + .quad 18963 + .quad 19000 + .quad 19131 + .quad 19273 + .quad 19327 + .quad 19355 + .quad 19383 + .quad 19411 + .quad 19439 + .quad 19478 + .quad 19517 + .quad 19557 + .quad 19597 + .quad 19641 + .quad 19686 + .quad 19721 + .quad 19756 + .quad 19793 + .quad 19831 + .quad 19859 + .quad 19891 + .quad 19925 + .quad 19972 + .quad 19996 + .quad 20040 + .quad 20080 + .quad 20125 + .quad 20171 + .quad 20220 + .quad 20301 + .quad 20346 + .quad 20389 + .quad 20422 + .quad 20458 + .quad 20476 + .quad 20513 + .quad 20544 + .quad 20577 + .quad 20610 + .quad 20642 + .quad 20734 + .quad 20826 + .quad 20918 + .quad 21010 + .quad 21102 + .quad 21194 + .quad 21289 + .quad 21387 + .quad 21499 + .quad 21530 + .quad 21561 + .quad 21592 + .quad 21623 + .quad 21653 + .quad 21694 + .quad 21735 + .quad 21776 + .quad 21817 + .quad 21859 + .quad 21906 + .quad 21948 + .quad 21990 + .quad 22032 + .quad 22069 + .quad 22106 + .quad 22143 + .quad 22180 + .quad 22219 + .quad 22258 + .quad 22297 + .quad 22336 + .quad 22437 + .quad 22548 + .quad 22663 + .quad 22812 + .quad 22961 + .quad 22994 + .quad 23053 + .quad 23106 + .quad 23159 + .quad 23212 + .quad 23268 + .quad 23324 + .quad 23380 + .quad 23436 + .quad 23492 + .quad 23548 + .quad 23604 + .quad 23660 + .quad 23716 + .quad 23772 + .quad 23828 + .quad 23884 + .quad 23940 + .quad 23996 + .quad 24052 + .quad 24108 + .quad 24164 + .quad 24220 + .quad 24276 + .quad 24332 + .quad 24388 + .quad 24451 + .quad 24514 + .quad 24555 + .quad 24597 + .quad 24641 + .quad 24713 + .quad 24757 + .quad 24808 + .quad 24859 + .quad 24910 + .quad 24961 + .quad 25012 + .quad 25063 + .quad 25114 + .quad 25165 + .quad 25216 + .quad 25277 + .quad 25306 + .quad 25336 + .quad 25368 + .quad 25400 + .quad 25433 + .quad 25462 + .quad 25491 + .quad 25522 + .quad 25553 + .quad 25589 + .quad 25625 + .quad 25668 + .quad 25701 + .quad 25769 + .quad 25843 + .quad 25918 + .quad 25996 + .quad 26077 + .quad 26145 + .quad 26213 + .quad 26282 + .quad 26352 + .quad 26422 + .quad 26492 + .quad 26565 + .quad 26638 + .quad 26706 + .quad 26775 + .quad 26844 + .quad 26914 + .quad 26985 + .quad 27056 + .quad 27129 + .quad 27203 + .quad 27281 + .quad 27348 + .quad 27416 + .quad 27485 + .quad 27554 + .quad 27623 + .quad 27694 + .quad 27765 + .quad 27836 + .quad 27907 + .quad 27979 + .quad 28057 + .quad 28132 + .quad 28226 + .quad 28320 + .quad 28401 + .quad 28482 + .quad 28563 + .quad 28644 + .quad 28725 + .quad 28806 + .quad 28887 + .quad 28968 + .quad 28994 + .quad 29064 + .quad 29135 + .quad 29202 + .quad 29270 + .quad 29343 + .quad 29414 + .quad 29656 + .quad 29898 + .quad 30140 + .quad 30382 + .quad 30624 + .quad 30866 + .quad 31108 + .quad 31350 + .quad 31592 + .quad 31834 + .quad 32076 + .quad 32318 + .quad 32560 + .quad 32802 + .quad 33044 + .quad 33286 + .quad 33358 + .quad 33430 + .quad 33502 + .quad 33574 + .quad 33646 + .quad 33718 + .quad 33790 + .quad 33863 + .quad 33936 + .quad 34009 + .quad 34082 + .quad 34155 + .quad 34228 + .quad 34301 + .quad 34383 + .quad 34465 + .quad 34547 + .quad 34629 + .quad 34711 + .quad 34793 + .quad 34875 + .quad 34940 + .quad 35005 + .quad 35070 + .quad 35135 + .quad 35200 + .quad 35265 + .quad 35330 + .quad 35610 + .quad 35890 + .quad 36170 + .quad 36450 + .quad 36730 + .quad 37010 + .quad 37290 + .quad 37584 + .quad 37878 + .quad 38172 + .quad 38466 + .quad 38760 + .quad 39054 + .quad 39348 + .quad 39642 + .quad 39941 + .quad 40240 + .quad 40539 + .quad 40838 + .quad 41137 + .quad 41436 + .quad 41735 + .quad 42034 + .quad 42116 + .quad 42177 + .quad 42239 + .quad 42302 + .quad 42369 + .quad 42440 + .quad 42514 + .quad 42568 + .quad 42626 + .quad 42662 + .quad 42699 + .quad 42729 + .quad 42784 + .quad 42823 + .quad 42880 + .quad 42951 + .quad 42969 + .quad 43020 + .quad 43071 + .quad 43122 + .quad 43194 + .quad 43293 + .quad 43354 + .quad 43403 + .quad 43457 + .quad 43512 + .quad 43571 + .quad 43614 + .quad 43660 + .quad 43693 + .quad 43741 + .quad 43789 + .quad 43834 + .quad 43879 + .quad 43914 + .quad 43989 + .quad 44066 + .quad 44143 + .quad 44222 + .quad 44235 + .quad 44250 + .quad 44265 + .quad 44285 + .quad 44331 + .quad 44394 + .quad 44445 + .quad 44501 + .quad 44555 + .quad 44608 + .quad 44641 + .quad 44674 + .quad 44707 + .quad 44740 + .quad 44773 + .quad 44806 + .quad 44839 + .quad 44872 + .quad 44905 + .quad 44938 + .quad 44971 + .quad 45004 + .quad 45037 + .quad 45070 + .quad 45103 + .quad 45136 + .quad 45169 + .quad 45202 + .quad 45235 + .quad 45268 + .quad 45301 + .quad 45334 + .quad 45367 + .quad 45400 + .quad 45433 + .quad 45466 + .quad 45499 + .quad 45532 + .quad 45565 + .quad 45598 + .quad 45631 + .quad 45664 + .quad 45697 + .quad 45730 + .quad 45763 + .quad 45796 + .quad 45829 + .quad 45862 + .quad 45895 + .quad 45928 + .quad 45961 + .quad 45994 + .quad 46027 + .quad 46060 + .quad 46093 + .quad 46126 + .quad 46197 + .quad 46246 + .quad 46311 + .quad 46376 + .quad 46441 + .quad 46517 + .quad 46593 + .quad 46669 + .quad 46745 + .quad 46821 + .quad 46897 + .quad 46973 + .quad 47049 + .quad 47125 + .quad 47201 + .quad 47277 + .quad 47353 + .quad 47429 + .quad 47505 + .quad 47581 + .quad 47657 + .quad 47733 + .quad 47809 + .quad 47885 + .quad 47961 + .quad 48037 + .quad 48113 + .quad 48189 + .quad 48265 + .quad 48341 + .quad 48417 + .quad 48493 + .quad 48569 + .quad 48645 + .quad 48721 + .quad 48797 + .quad 48873 + .quad 48949 + .quad 49025 + .quad 49101 + .quad 49147 + .quad 49204 + .quad 49264 + .quad 49320 + .quad 49378 + .quad 49414 + .quad 49442 + .quad 49458 + .quad 49473 + .quad 49485 + .quad 49499 + .quad 49514 + .quad 49522 + .quad 49530 + .quad 49540 + .quad 49556 + .quad 49571 + .quad 49587 + .quad 49603 + .quad 49620 + .quad 49632 + .quad 49649 + .quad 49667 + .quad 49675 + .quad 49693 + .quad 49705 + .quad 49715 + .quad 49727 + .quad 49737 + .quad 49748 + .quad 49761 + .quad 49772 + .quad 49781 + .quad 49791 + .quad 49799 + .quad 49845 + .quad 49891 + .quad 49937 + .quad 49983 + .quad 50029 + .quad 50075 + .quad 50121 + .quad 50167 + .quad 50213 + .quad 50259 + .quad 50305 + .quad 50351 + .quad 50397 + .quad 50443 + .quad 50489 + .quad 50535 + .quad 50581 + .quad 50627 + .quad 50673 + .quad 50719 + .quad 50765 + .quad 50811 + .quad 50857 + .quad 50903 + .quad 50949 + .quad 50995 + .quad 51041 + .quad 51087 + .quad 51133 + .quad 51179 + .quad 51225 + .quad 51271 + .quad 51317 + .quad 51363 + .quad 51409 + .quad 51455 + .quad 51501 + .quad 51547 + .quad 51593 + .quad 51639 + .quad 51685 + .quad 51731 + .quad 51777 + .quad 51823 + .quad 51869 + .quad 51915 + .quad 51961 + .quad 52007 + .quad 52053 + .quad 52099 + .quad 52145 + .quad 52191 + .quad 52237 + .quad 52283 + .quad 52329 + .quad 52375 + .quad 52421 + .quad 52467 + .quad 52513 + .quad 52559 + .quad 52605 + .quad 52651 + .quad 52697 + .quad 52743 + .quad 52789 + .quad 52835 + .quad 52881 + .quad 52927 + .quad 52973 + .quad 53019 + .quad 53065 + .quad 53111 + .quad 53157 + .quad 53203 + .quad 53249 + .quad 53295 + .quad 53341 + .quad 53387 + .quad 53433 + .quad 53479 + .quad 53525 + .quad 53571 + .quad 53617 + .quad 53663 + .quad 53709 + .quad 53755 + .quad 53801 + .quad 53847 + .quad 53893 + .quad 53939 + .quad 53985 + .quad 54031 + .quad 54077 + .quad 54123 + .quad 54169 + .quad 54215 + .quad 54261 + .quad 54307 + .quad 54353 + .quad 54399 + .quad 54445 + .quad 54491 + .quad 54537 + .quad 54583 + .quad 54629 + .quad 54675 + .quad 54721 + .quad 54767 + .quad 54813 + .quad 54859 + .quad 54905 + .quad 54951 + .quad 54997 + .quad 55043 + .quad 55089 + .quad 55135 + .quad 55181 + .quad 55227 + .quad 55273 + .quad 55319 + .quad 55365 + .quad 55411 + .quad 55457 + .quad 55503 + .quad 55549 + .quad 55595 + .quad 55641 + .quad 55687 + .quad 55733 + .quad 55779 + .quad 55816 + .quad 55866 + .quad 55916 + .quad 55966 + .quad 56016 + .quad 56066 + .quad 56116 + .quad 56166 + .quad 56216 + .quad 56266 + .quad 56316 + .quad 56366 + .quad 56416 + .quad 56466 + .quad 56516 + .quad 56566 + .quad 56616 + .quad 56666 + .quad 56716 + .quad 56766 + .quad 56816 + .quad 56866 + .quad 56916 + .quad 56966 + .quad 57016 + .quad 57066 + .quad 57116 + .quad 57166 + .quad 57216 + .quad 57266 + .quad 57316 + .quad 57366 + .quad 57416 + .quad 57466 + .quad 57516 + .quad 57566 + .quad 57616 + .quad 57666 + .quad 57716 + .quad 57766 + .quad 57816 + .quad 57866 + .quad 57916 + .quad 57966 + .quad 58016 + .quad 58066 + .quad 58116 + .quad 58166 + .quad 58216 + .quad 58266 + .quad 58316 + .quad 58366 + .quad 58416 + .quad 58466 + .quad 58516 + .quad 58566 + .quad 58616 + .quad 58666 + .quad 58716 + .quad 58766 + .quad 58816 + .quad 58866 + .quad 58916 + .quad 58966 + .quad 59016 + .quad 59066 + .quad 59116 + .quad 59166 + .quad 59216 + .quad 59266 + .quad 59316 + .quad 59366 + .quad 59416 + .quad 59466 + .quad 59516 + .quad 59566 + .quad 59616 + .quad 59666 + .quad 59716 + .quad 59766 + .quad 59816 + .quad 59866 + .quad 59916 + .quad 59966 + .quad 60016 + .quad 60066 + .quad 60116 + .quad 60166 + .quad 60216 + .quad 60266 + .quad 60316 + .quad 60366 + .quad 60416 + .quad 60466 + .quad 60516 + .quad 60566 + .quad 60616 + .quad 60666 + .quad 60716 + .quad 60766 + .quad 60816 + .quad 60866 + .quad 60916 + .quad 60966 + .quad 61016 + .quad 61066 + .quad 61116 + .quad 61166 + .quad 61216 + .quad 61266 + .quad 61316 + .quad 61366 + .quad 61416 + .quad 61466 + .quad 61516 + .quad 61566 + .quad 61616 + .quad 61666 + .quad 61716 + .quad 61766 + .quad 61816 + .quad 61866 + .quad 61916 + .quad 61966 + .quad 62016 + .quad 62066 + .quad 62116 + .quad 62166 + .quad 62216 + .quad 62266 + .quad 62316 + .quad 62422 + .quad 62530 + .quad 62638 + .quad 62747 + .quad 62856 + .quad 62965 + .quad 63074 + .quad 63183 + .quad 63292 + .quad 63402 + .quad 63512 + .quad 63622 + .quad 63732 + .quad 63843 + .quad 63954 + .quad 64066 + .quad 64180 + .quad 64293 + .quad 64407 + .quad 64524 + .quad 64641 + .quad 64757 + .quad 64873 + .quad 64992 + .quad 65111 + .quad 65229 + .quad 65340 + .quad 65459 + .quad 65579 + .quad 65701 + .quad 65821 + .quad 65941 + .quad 66055 + .quad 66176 + .quad 66298 + .quad 66419 + .quad 66542 + .quad 66664 + .quad 66788 + .quad 66912 + .quad 67036 + .quad 67162 + .quad 67283 + .quad 67412 + .quad 67539 + .quad 67667 + .quad 67795 + .quad 67920 + .quad 68050 + .quad 68175 + .quad 68307 + .quad 68429 + .quad 68563 + .quad 68693 + .quad 68826 + .quad 68962 + .quad 69101 + .quad 69241 + .quad 69379 + .quad 69515 + .quad 69650 + .quad 69790 + .quad 69948 + .quad 70110 + .quad 70275 + .quad 70441 + .quad 70608 + .quad 70769 + .quad 70935 + .quad 71103 + .quad 71271 + .quad 71440 + .quad 71610 + .quad 71775 + .quad 71949 + .quad 72124 + .quad 72297 + .quad 72467 + .quad 72642 + .quad 72817 + .quad 72992 + .quad 73163 + .quad 73340 + .quad 73517 + .quad 73696 + .quad 73869 + .quad 74047 + .quad 74226 + .quad 74401 + .quad 74579 + .quad 74758 + .quad 74939 + .quad 75121 + .quad 75304 + .quad 75482 + .quad 75662 + .quad 75844 + .quad 76023 + .quad 76208 + .quad 76389 + .quad 76570 + .quad 76754 + .quad 76936 + .quad 77119 + .quad 77303 + .quad 77483 + .quad 77669 + .quad 77852 + .quad 78036 + .quad 78227 + .quad 78414 + .quad 78609 + .quad 78797 + .quad 78985 + .quad 79175 + .quad 79365 + .quad 79566 + .quad 79758 + .quad 79951 + .quad 80144 + .quad 80337 + .quad 80531 + .quad 80728 + .quad 80927 + .quad 81126 + .quad 81322 + .quad 81519 + .quad 81721 + .quad 81924 + .quad 82129 + .quad 82177 + .quad 82226 + .quad 82272 + .quad 82318 + .quad 82367 + .quad 82416 + .quad 82465 + .quad 82514 + .quad 82566 + .quad 82618 + .quad 82680 + .quad 82743 + .quad 82792 + .quad 82843 + .quad 82884 + .quad 82925 + .quad 82966 + .quad 83007 + .quad 83048 + .quad 83089 + .quad 83130 + .quad 83172 + .quad 83214 + .quad 83256 + .quad 83298 + .quad 83340 + .quad 83382 + .quad 83424 + .quad 83461 + .quad 83498 + .quad 83535 + .quad 83572 + .quad 83609 + .quad 83646 + .quad 83683 + .quad 83722 + .quad 83761 + .quad 83800 + .quad 83839 + .quad 83878 + .quad 83917 + .quad 83956 + .quad 83995 + .quad 84034 + .quad 84064 + .quad 84096 + .quad 84127 + .quad 84187 + .quad 84235 + .quad 84286 + .quad 84339 + .quad 84396 + .quad 84453 + .quad 84512 + .quad 84571 + .quad 84630 + .quad 84691 + .quad 84755 + .quad 84822 + .quad 84895 + .quad 84932 + .quad 84969 + .quad 85011 + .quad 85053 + .quad 85095 + .quad 85137 + .quad 85179 + .quad 85221 + .quad 85263 + .quad 85305 + .quad 85347 + .quad 85389 + .quad 85431 + .quad 85473 + .quad 85515 + .quad 85557 + .quad 85599 + .quad 85641 + .quad 85683 + .quad 85725 + .quad 85767 + .quad 85809 + .quad 85851 + .quad 85893 + .quad 85935 + .quad 85997 + .quad 86060 + .quad 86124 + .quad 86193 + .quad 86222 + .quad 86251 + .quad 86281 + .quad 86311 + .quad 86341 + .quad 86373 + .quad 86405 + .quad 86437 + .quad 86474 + .quad 86511 + .quad 86548 + .quad 86586 + .quad 86624 + .quad 86662 + .quad 86694 + .quad 86726 + .quad 86758 + .quad 86791 + .quad 86824 + .quad 86857 + .quad 86890 + .quad 86923 + .quad 86956 + .quad 86990 + .quad 87024 + .quad 87058 + .quad 87093 + .quad 87128 + .quad 87163 + .quad 87198 + .quad 87233 + .quad 87268 + .quad 87304 + .quad 87340 + .quad 87424 + .quad 87508 + .quad 87583 + .quad 87651 + .quad 87722 + .quad 87793 + .quad 87866 + .quad 87939 + .quad 88014 + .quad 88080 + .quad 88146 + .quad 88224 + .quad 88292 + .quad 88372 + .quad 88445 + .quad 88518 + .quad 88593 + .quad 88621 + .quad 88673 + .quad 88780 + .quad 88869 + .quad 88960 + .quad 89044 + .quad 89116 + .quad 89197 + .quad 89272 + .quad 89346 + .quad 89420 + .quad 89496 + .quad 89529 + .quad 89562 + .quad 89640 + .quad 89668 + .quad 89680 + .quad 89692 + .quad 89706 + .quad 89718 + .quad 89730 + .quad 89743 + .quad 89751 + .quad 89768 + .quad 89787 + .quad 89802 + .quad 89813 + .quad 89830 + .quad 89850 + .quad 89871 + .quad 89882 + .quad 89906 + .quad 89931 + .quad 89955 + .quad 89980 + .quad 89994 + .quad 90002 + .quad 90013 + .quad 90023 + .quad 90032 + .quad 90039 + .quad 90053 + .quad 90062 + .quad 90073 + .quad 90086 + .quad 90099 + .quad 90107 + .quad 90117 + .quad 90129 + .quad 90138 + .quad 90187 + .quad 90236 + .quad 90285 + .quad 90316 + .quad 90346 + .quad 90387 + .quad 90429 + .quad 90466 + .quad 90505 + .quad 90560 + .quad 90599 + .quad 90638 + .quad 90677 + .quad 90716 + .quad 90817 + .quad 90952 + .quad 90984 + .quad 91038 + .quad 91093 + .quad 91151 + .quad 91202 + .quad 91260 + .quad 91294 + .quad 91339 + .quad 91384 + .quad 91431 + .quad 91481 + .quad 91526 + .quad 91572 + .quad 91615 + .quad 91658 + .quad 91703 + .quad 91749 + .quad 91808 + .quad 91887 + .quad 91967 + .quad 92046 + .quad 92129 + .quad 92217 + .quad 92305 + .quad 92386 + .quad 92466 + .quad 92552 + .quad 92636 + .quad 92715 + .quad 92770 + .quad 92807 + .quad 92845 + .quad 92885 + .quad 92926 + .quad 92967 + .quad 93009 + .quad 93051 + .quad 93095 + .quad 93130 + .quad 93157 + .quad 93190 + .quad 93198 + .quad 93210 + .quad 93239 + .quad 93248 + .quad 93257 + .quad 93264 + .quad 93278 + .quad 93298 + .quad 93316 + .quad 93339 + .quad 93359 + .quad 93380 + .quad 93405 + .quad 93432 + .quad 93452 + .quad 93474 + .quad 93498 + .quad 93511 + .quad 93535 + .quad 93557 + .quad 93582 + .quad 93600 + .quad 93609 + .quad 93618 + .quad 93636 + .quad 93687 + .quad 93739 + .quad 93764 + .quad 93794 + .quad 93819 + .quad 93844 + .quad 93872 + .quad 93903 + .quad 93995 + .quad 94025 + .quad 94055 + .quad 94085 + .quad 94114 + .quad 94143 + .quad 94171 + .quad 94199 + .quad 94227 + .quad 94334 + .quad 94366 + .quad 94396 + .quad 94427 + .quad 94460 + .quad 94506 + .quad 94559 + .quad 94622 + .quad 94674 + .quad 94738 + .quad 94808 + .quad 94851 + .quad 94908 + .quad 94966 + .quad 95014 + .quad 95063 + .quad 95097 + .quad 95153 + .quad 95208 + .quad 95237 + .quad 95354 + .quad 95471 + .quad 95499 + .quad 95543 + .quad 95591 + .quad 95639 + .quad 95687 + .quad 95739 + .quad 95802 + .quad 95879 + .quad 95926 + .quad 95961 + .quad 95997 + .quad 96078 + .quad 96159 + .quad 96240 + .quad 96321 + .quad 96385 + .quad 96450 + .quad 96482 + .quad 96543 + .quad 96585 + .quad 96624 + .quad 96653 + .quad 96711 + .quad 96740 + .quad 96773 + .quad 96800 + .quad 96829 + .quad 96919 + .quad 96968 + .quad 96999 + .quad 97030 + .quad 97060 + .quad 97090 + .quad 97120 + .quad 97150 + .quad 97180 + .quad 97210 + .quad 97240 + .quad 97270 + .quad 97300 + .quad 97330 + .quad 97360 + .quad 97390 + .quad 97420 + .quad 97450 + .quad 97480 + .quad 97510 + .quad 97540 + .quad 97570 + .quad 97611 + .quad 97653 + .quad 97690 + .quad 97729 + .quad 97761 + .quad 97793 + .quad 97825 + .quad 97857 + .quad 97910 + .quad 97965 + .quad 98020 + .quad 98059 + .quad 98098 + .quad 98128 + .quad 98160 + .quad 98214 + .quad 98255 + .quad 98289 + .quad 98325 + .quad 98361 + .quad 98394 + .quad 98449 + .quad 98498 + .quad 98549 + .quad 98605 + .quad 98636 + .quad 98667 + .quad 98703 + .quad 98739 + .quad 98809 + .quad 98880 + .quad 98947 + .quad 99015 + .quad 99090 + .quad 99135 + .quad 99181 + .quad 99224 + .quad 99275 + .quad 99326 + .quad 99371 + .quad 99417 + .quad 99492 + .quad 99571 + .quad 99651 + .quad 99689 + .quad 99705 + .quad 99738 + .quad 99789 + .quad 99837 + .quad 99884 + .quad 99911 + .quad 99938 + .quad 99969 + .quad 100000 + .quad 100028 + .quad 100050 + .quad 100071 + .quad 100093 + .quad 100112 + .quad 100141 + .quad 100168 + .quad 100198 + .quad 100226 + .quad 100251 + .quad 100278 + .quad 100303 + .quad 100329 + .quad 100358 + .quad 100425 + .quad 100478 + .quad 100514 + .quad 100544 + .quad 100574 + .quad 100622 + .quad 100691 + .quad 100719 + .quad 100760 + .quad 100806 + .quad 100852 + .quad 100898 + .quad 100944 + .quad 100990 + .quad 101036 + .quad 101082 + .quad 101128 + .quad 101174 + .quad 101220 + .quad 101266 + .quad 101312 + .quad 101358 + .quad 101404 + .quad 101450 + .quad 101496 + .quad 101542 + .quad 101588 + .quad 101634 + .quad 101694 + .quad 101754 + .quad 101814 + .quad 101874 + .quad 101934 + .quad 101984 + .quad 102038 + .quad 102092 + .quad 102187 + .quad 102283 + .quad 102335 + .quad 102444 + .quad 102554 + .quad 102583 + .quad 102626 + .quad 102668 + .quad 102681 + .quad 102694 + .quad 102706 + .quad 102721 + .quad 102732 + .quad 102744 + .quad 102757 + .quad 102770 + .quad 102782 + .quad 102795 + .quad 102808 + .quad 102823 + .quad 102830 + .quad 102839 + .quad 102854 + .quad 102870 + .quad 102887 + .quad 102905 + .quad 102924 + .quad 102940 + .quad 102960 + .quad 102981 + .quad 102990 + .quad 103004 + .quad 103020 + .quad 103033 + .quad 103044 + .quad 103062 + .quad 103070 + .quad 103083 + .quad 103143 + .quad 103152 + .quad 103168 + .quad 103182 + .quad 103204 + .quad 103212 + .quad 103222 + .quad 103232 + .quad 103242 + .quad 103253 + .quad 103263 + .quad 103281 + .quad 103298 + .quad 103313 + .quad 103344 + .quad 103375 + .quad 103406 + .quad 103437 + .quad 103468 + .quad 103499 + .quad 103529 + .quad 103559 + .quad 103589 + .quad 103630 + .quad 103671 + .quad 103712 + .quad 103753 + .quad 103794 + .quad 103835 + .quad 103876 + .quad 103917 + .quad 103958 + .quad 103999 + .quad 104040 + .quad 104082 + .quad 104124 + .quad 104166 + .quad 104208 + .quad 104250 + .quad 104292 + .quad 104334 + .quad 104376 + .quad 104418 + .quad 104460 + .quad 104502 + .quad 104539 + .quad 104576 + .quad 104613 + .quad 104650 + .quad 104687 + .quad 104724 + .quad 104761 + .quad 104798 + .quad 104835 + .quad 104872 + .quad 104909 + .quad 104948 + .quad 104987 + .quad 105026 + .quad 105065 + .quad 105104 + .quad 105143 + .quad 105182 + .quad 105237 + .quad 105266 + .quad 105294 + .quad 105333 + .quad 105439 + .quad 105540 + .quad 105674 + .quad 105808 + .quad 105948 + .quad 106095 + .quad 106138 + .quad 106186 + .quad 106235 + .quad 106286 + .quad 106341 + .quad 106409 + .quad 106458 + .quad 106514 + .quad 106569 + .quad 106613 + .quad 106654 + .quad 106717 + .quad 106781 + .quad 106846 + .quad 106903 + .quad 106962 + .quad 107021 + .quad 107080 + .quad 107137 + .quad 107196 + .quad 107255 + .quad 107320 + .quad 107385 + .quad 107414 + .quad 107443 + .quad 107473 + .quad 107503 + .quad 107533 + .quad 107563 + .quad 107595 + .quad 107627 + .quad 107659 + .quad 107692 + .quad 107725 + .quad 107762 + .quad 107800 + .quad 107831 + .quad 107863 + .quad 107896 + .quad 107929 + .quad 107963 + .quad 107998 + .quad 108033 + .quad 108069 + .quad 108142 + .quad 108213 + .quad 108284 + .quad 108355 + .quad 108446 + .quad 108536 + .quad 108627 + .quad 108696 + .quad 108743 + .quad 108832 + .quad 108922 + .quad 109014 + .quad 109107 + .quad 109197 + .quad 109287 + .quad 109376 + .quad 109469 + .quad 109559 + .quad 109657 + .quad 109755 + .quad 109845 + .quad 109937 + .quad 110030 + .quad 110126 + .quad 110222 + .quad 110316 + .quad 110373 + .quad 110456 + .quad 110542 + .quad 110625 + .quad 110703 + .quad 110775 + .quad 110846 + .quad 110917 + .quad 110990 + .quad 111066 + .quad 111096 + .quad 111124 + .quad 111179 + .quad 111204 + .quad 111225 + .quad 111280 + .quad 111311 + .quad 111345 + .quad 111420 + .quad 111496 + .quad 111573 + .quad 111664 + .quad 111740 + .quad 111822 + .quad 111904 + .quad 111979 + .quad 112068 + .quad 112134 + .quad 112201 + .quad 112264 + .quad 112340 + .quad 112410 + .quad 112479 + .quad 112548 + .quad 112617 + .quad 112688 + .quad 112759 + .quad 112831 + .quad 112892 + .quad 112941 + .quad 112967 + .quad 112983 + .quad 112999 + .quad 113011 + .quad 113029 + .quad 113041 + .quad 113050 + .quad 113066 + .quad 113079 + .quad 113103 + .quad 113111 + .quad 113178 + .quad 113243 + .quad 113311 + .quad 113378 + .quad 113444 + .quad 113513 + .quad 113583 + .quad 113595 + .quad 113605 + .quad 113613 + .quad 113624 + .quad 113634 + .quad 113646 + .quad 113654 + .quad 113666 + .quad 113678 + .quad 113696 + .quad 113790 + .quad 113821 + .quad 113852 + .quad 113883 + .quad 113914 + .quad 113946 + .quad 113987 + .quad 114028 + .quad 114070 + .quad 114112 + .quad 114149 + .quad 114186 + .quad 114225 + .quad 114264 + .quad 114294 + .quad 114349 + .quad 114404 + .quad 114443 + .quad 114554 + .quad 114583 + .quad 114651 + .quad 114700 + .quad 114751 + .quad 114796 + .quad 114843 + .quad 114890 + .quad 114949 + .quad 114999 + .quad 115049 + .quad 115099 + .quad 115130 + .quad 115161 + .quad 115192 + .quad 115228 + .quad 115264 + .quad 115300 + .quad 115378 + .quad 115453 + .quad 115541 + .quad 115630 + .quad 115723 + .quad 115805 + .quad 115891 + .quad 115977 + .quad 116063 + .quad 116150 + .quad 116237 + .quad 116306 + .quad 116372 + .quad 116438 + .quad 116506 + .quad 116579 + .quad 116643 + .quad 116672 + .quad 116702 + .quad 116732 + .quad 116764 + .quad 116796 + .quad 116829 + .quad 116857 + .quad 116886 + .quad 116916 + .quad 116945 + .quad 116975 + .quad 117006 + .quad 117035 + .quad 117065 + .quad 117094 + .quad 117123 + .quad 117153 + .quad 117185 + .quad 117214 + .quad 117245 + .quad 117275 + .quad 117307 + .quad 117340 + .quad 117369 + .quad 117394 + .quad 117429 + .quad 117459 + .quad 117490 + .quad 117520 + .quad 117551 + .quad 117583 + .quad 117617 + .quad 117646 + .quad 117677 + .quad 117709 + .quad 117742 + .quad 117793 + .quad 117824 + .quad 117855 + .quad 117886 + .quad 117917 + .quad 117948 + .quad 117979 + .quad 118010 + .quad 118040 + .quad 118070 + .quad 118100 + .quad 118130 + .quad 118160 + .quad 118190 + .quad 118231 + .quad 118272 + .quad 118313 + .quad 118355 + .quad 118397 + .quad 118439 + .quad 118476 + .quad 118513 + .quad 118550 + .quad 118589 + .quad 118628 + .quad 118667 + .quad 118706 + .quad 118745 + .quad 118856 + .quad 119003 + .quad 119152 + .quad 119200 + .quad 119269 + .quad 119322 + .quad 119375 + .quad 119406 + .quad 119437 + .quad 119468 + .quad 119499 + .quad 119530 + .quad 119561 + .quad 119592 + .quad 119623 + .quad 119668 + .quad 119716 + .quad 119764 + .quad 119813 + .quad 119866 + .quad 119904 + .quad 119944 + .quad 119987 + .quad 120031 + .quad 120059 + .quad 120087 + .quad 120115 + .quad 120163 + .quad 120201 + .quad 120240 + .quad 120290 + .quad 120343 + .quad 120396 + .quad 120449 + .quad 120502 + .quad 120555 + .quad 120608 + .quad 120663 + .quad 120719 + .quad 120775 + .quad 120833 + .quad 120893 + .quad 120922 + .quad 120952 + .quad 120982 + .quad 121014 + .quad 121046 + .quad 121079 + .quad 121110 + .quad 121141 + .quad 121172 + .quad 121208 + .quad 121244 + .quad 121280 + .quad 121342 + .quad 121410 + .quad 121483 + .quad 121556 + .quad 121630 + .quad 121708 + .quad 121775 + .quad 121843 + .quad 121912 + .quad 121981 + .quad 122051 + .quad 122122 + .quad 122193 + .quad 122264 + .quad 122335 + .quad 122407 + .quad 122488 + .quad 122560 + .quad 122627 + .quad 122695 + .quad 122763 + .quad 122831 + .quad 122901 + .quad 122972 + .quad 123038 + .quad 123113 + .quad 123189 + .quad 123269 + .quad 123340 + .quad 123413 + .quad 123486 + .quad 123559 + .quad 123634 + .quad 123708 + .quad 123785 + .quad 123863 + .quad 123945 + .quad 124028 + .quad 124115 + .quad 124191 + .quad 124271 + .quad 124351 + .quad 124431 + .quad 124512 + .quad 124584 + .quad 124653 + .quad 124721 + .quad 124790 + .quad 124856 + .quad 124899 + .quad 124982 + .quad 125063 + .quad 125115 + .quad 125206 + .quad 125310 + .quad 125417 + .quad 125503 + .quad 125573 + .quad 125643 + .quad 125719 + .quad 125802 + .quad 125874 + .quad 125956 + .quad 126041 + .quad 126083 + .quad 126126 + .quad 126170 + .quad 126239 + .quad 126252 + .quad 126264 + .quad 126299 + .quad 126335 + .quad 126381 + .quad 126431 + .quad 126468 + .quad 126531 + .quad 126562 + .quad 126603 + .quad 126633 + .quad 126660 + .quad 126691 + .quad 126750 + .quad 126780 + .quad 126812 + .quad 126850 + .quad 126876 + .quad 126906 + .quad 126939 + .quad 126991 + .quad 127021 + .quad 127051 + .quad 127083 + .quad 127134 + .quad 127188 + .quad 127243 + .quad 127298 + .quad 127361 + .quad 127392 + .quad 127415 + .quad 127444 + .quad 127478 + .quad 127518 + .quad 127548 + .quad 127579 + .quad 127620 + .quad 127664 + .quad 127708 + .quad 127762 + .quad 127802 + .quad 127883 + .quad 127926 + .quad 127969 + .quad 128014 + .quad 128059 + .quad 128104 + .quad 128149 + .quad 128229 + .quad 128259 + .quad 128274 + .quad 128293 + .quad 128310 + .quad 128327 + .quad 128352 + .quad 128416 + .quad 128482 + .quad 128494 + .quad 128505 + .quad 128559 + .quad 128616 + .quad 128670 + .quad 128727 + .quad 128794 + .quad 128851 + .quad 128911 + .quad 128969 + .quad 129024 + .quad 129085 + .quad 129135 + .quad 129186 + .quad 129242 + .quad 129298 + .quad 129352 + .quad 129406 + .quad 129429 + .quad 129454 + .quad 129492 + .quad 129529 + .quad 129574 + .quad 129611 + .quad 129693 + .quad 129780 + .quad 129816 + .quad 129869 + .quad 129914 + .quad 129955 + .quad 129985 + .quad 130015 + .quad 130045 + .quad 130075 + .quad 130105 + .quad 130135 + .quad 130165 + .quad 130218 + .quad 130271 + .quad 130324 + .quad 130352 + .quad 130412 + .quad 130454 + .quad 130504 + .quad 130540 + .quad 130597 + .quad 130655 + .quad 130710 + .quad 130770 + .quad 130838 + .quad 130868 + .quad 130898 + .quad 130950 + .quad 131003 + .quad 131056 + .quad 131085 + .quad 131115 + .quad 131145 + .quad 131206 + .quad 131239 + .quad 131277 + .quad 131317 + .quad 131361 + .quad 131412 + .quad 131459 + .quad 131519 + .quad 131581 + .quad 131639 + .quad 131699 + .quad 131801 + .quad 131853 + .quad 131911 + .quad 132013 + .quad 132124 + .quad 132236 + .quad 132341 + .quad 132438 + .quad 132539 + .quad 132649 + .quad 132749 + .quad 132851 + .quad 132952 + .quad 133056 + .quad 133136 + .quad 133208 + .quad 133278 + .quad 133308 + .quad 133403 + .quad 133470 + .quad 133498 + .quad 133526 + .quad 133554 + .quad 133584 + .quad 133614 + .quad 133644 + .quad 133677 + .quad 133730 + .quad 133760 + .quad 133792 + .quad 133861 + .quad 133910 + .quad 133940 + .quad 133993 + .quad 134046 + .quad 134076 + .quad 134106 + .quad 134171 + .quad 134235 + .quad 134302 + .quad 134363 + .quad 134435 + .quad 134465 + .quad 134495 + .quad 134550 + .quad 134580 + .quad 134611 + .quad 134651 + .quad 134740 + .quad 134807 + .quad 134885 + .quad 134950 + .quad 134981 + .quad 135024 + .quad 135075 + .quad 135103 + .quad 135149 + .quad 135211 + .quad 135279 + .quad 135338 + .quad 135396 + .quad 135462 + .quad 135515 + .quad 135568 + .quad 135629 + .quad 135689 + .quad 135751 + .quad 135814 + .quad 135875 + .quad 135937 + .quad 135998 + .quad 136061 + .quad 136125 + .quad 136191 + .quad 136231 + .quad 136315 + .quad 136368 + .quad 136398 + .quad 136470 + .quad 136518 + .quad 136562 + .quad 136590 + .quad 136620 + .quad 136650 + .quad 136682 + .quad 136732 + .quad 136798 + .quad 136844 + .quad 136888 + .quad 136908 + .quad 136948 + .quad 137000 + .quad 137033 + .quad 137063 + .quad 137095 + .quad 137127 + .quad 137161 + .quad 137191 + .quad 137221 + .quad 137251 + .quad 137289 + .quad 137346 + .quad 137379 + .quad 137443 + .quad 137527 + .quad 137580 + .quad 137630 + .quad 137680 + .quad 137730 + .quad 137780 + .quad 137834 + .quad 137888 + .quad 137942 + .quad 137996 + .quad 138050 + .quad 138104 + .quad 138158 + .quad 138212 + .quad 138266 + .quad 138311 + .quad 138363 + .quad 138432 + .quad 138496 + .quad 138563 + .quad 138627 + .quad 138691 + .quad 138755 + .quad 138815 + .quad 138849 + .quad 138887 + .quad 138926 + .quad 138989 + .quad 139052 + .quad 139115 + .quad 139178 + .quad 139241 + .quad 139304 + .quad 139376 + .quad 139405 + .quad 139441 + .quad 139476 + .quad 139506 + .quad 139539 + .quad 139574 + .quad 139607 + .quad 139637 + .quad 139671 + .quad 139701 + .quad 139736 + .quad 139793 + .quad 139900 + .quad 139972 + .quad 140012 + .quad 140055 + .quad 140100 + .quad 140147 + .quad 140190 + .quad 140246 + .quad 140288 + .quad 140330 + .quad 140372 + .quad 140414 + .quad 140464 + .quad 140519 + .quad 140562 + .quad 140601 + .quad 140633 + .quad 140663 + .quad 140693 + .quad 140725 + .quad 140756 + .quad 140788 + .quad 140821 + .quad 140853 + .quad 140886 + .quad 140939 + .quad 140996 + .quad 141095 + .quad 141158 + .quad 141193 + .quad 141234 + .quad 141277 + .quad 141320 + .quad 141348 + .quad 141394 + .quad 141440 + .quad 141476 + .quad 141507 + .quad 141538 + .quad 141596 + .quad 141626 + .quad 141657 + .quad 141688 + .quad 141719 + .quad 141770 + .quad 141822 + .quad 141864 + .quad 141882 + .quad 141907 + .quad 142004 + .quad 142047 + .quad 142096 + .quad 142147 + .quad 142199 + .quad 142253 + .quad 142298 + .quad 142330 + .quad 142357 + .quad 142384 + .quad 142412 + .quad 142440 + .quad 142470 + .quad 142521 + .quad 142586 + .quad 142636 + .quad 142664 + .quad 142693 + .quad 142724 + .quad 142759 + .quad 142790 + .quad 142821 + .quad 142854 + .quad 142884 + .quad 142915 + .quad 142948 + .quad 142980 + .quad 143009 + .quad 143039 + .quad 143070 + .quad 143104 + .quad 143138 + .quad 143172 + .quad 143207 + .quad 143236 + .quad 143268 + .quad 143298 + .quad 143327 + .quad 143380 + .quad 143433 + .quad 143488 + .quad 143518 + .quad 143548 + .quad 143613 + .quad 143648 + .quad 143704 + .quad 143759 + .quad 143812 + .quad 143842 + .quad 143872 + .quad 143902 + .quad 143932 + .quad 143964 + .quad 143990 + .quad 144018 + .quad 144046 + .quad 144106 + .quad 144160 + .quad 144212 + .quad 144243 + .quad 144276 + .quad 144329 + .quad 144382 + .quad 144408 + .quad 144436 + .quad 144467 + .quad 144500 + .quad 144533 + .quad 144566 + .quad 144609 + .quad 144715 + .quad 144757 + .quad 144787 + .quad 144840 + .quad 144893 + .quad 144946 + .quad 144976 + .quad 145006 + .quad 145036 + .quad 145086 + .quad 145134 + .quad 145182 + .quad 145232 + .quad 145278 + .quad 145331 + .quad 145385 + .quad 145438 + .quad 145487 + .quad 145542 + .quad 145591 + .quad 145641 + .quad 145690 + .quad 145739 + .quad 145793 + .quad 145846 + .quad 145876 + .quad 145905 + .quad 145977 + .quad 146064 + .quad 146118 + .quad 146169 + .quad 146199 + .quad 146229 + .quad 146284 + .quad 146314 + .quad 146345 + .quad 146378 + .quad 146411 + .quad 146494 + .quad 146542 + .quad 146593 + .quad 146645 + .quad 146700 + .quad 146732 + .quad 146760 + .quad 146806 + .quad 146881 + .quad 146942 + .quad 147008 + .quad 147072 + .quad 147102 + .quad 147191 + .quad 147229 + .quad 147272 + .quad 147319 + .quad 147362 + .quad 147410 + .quad 147455 + .quad 147512 + .quad 147627 + .quad 147675 + .quad 147727 + .quad 147778 + .quad 147833 + .quad 147892 + .quad 147953 + .quad 148013 + .quad 148074 + .quad 148138 + .quad 148205 + .quad 148254 + .quad 148305 + .quad 148358 + .quad 148411 + .quad 148468 + .quad 148527 + .quad 148571 + .quad 148621 + .quad 148657 + .quad 148693 + .quad 148734 + .quad 148775 + .quad 148815 + .quad 148855 + .quad 148895 + .quad 148933 + .quad 148971 + .quad 149017 + .quad 149063 + .quad 149110 + .quad 149165 + .quad 149218 + .quad 149260 + .quad 149298 + .quad 149329 + .quad 149361 + .quad 149393 + .quad 149423 + .quad 149503 + .quad 149562 + .quad 149631 + .quad 149700 + .quad 149762 + .quad 149799 + .quad 149835 + .quad 149867 + .quad 149904 + .quad 149935 + .quad 149989 + .quad 150046 + .quad 150150 + .quad 150246 + .quad 150342 + .quad 150404 + .quad 150471 + .quad 150529 + .quad 150583 + .quad 150639 + .quad 150694 + .quad 150743 + .quad 150799 + .quad 150854 + .quad 150894 + .quad 150962 + .quad 151065 + .quad 151175 + .quad 151205 + .quad 151252 + .quad 151306 + .quad 151362 + .quad 151424 + .quad 151487 + .quad 151556 + .quad 151615 + .quad 151695 + .quad 151774 + .quad 151809 + .quad 151843 + .quad 151906 + .quad 151944 + .quad 151984 + .quad 152025 + .quad 152063 + .quad 152095 + .quad 152125 + .quad 152179 + .quad 152217 + .quad 152255 + .quad 152311 + .quad 152368 + .quad 152424 + .quad 152453 + .quad 152510 + .quad 152573 + .quad 152623 + .quad 152683 + .quad 152748 + .quad 152802 + .quad 152853 + .quad 152903 + .quad 152961 + .quad 153019 + .quad 153077 + .quad 153135 + .quad 153198 + .quad 153258 + .quad 153318 + .quad 153382 + .quad 153430 + .quad 153460 + .quad 153490 + .quad 153522 + .quad 153576 + .quad 153617 + .quad 153675 + .quad 153708 + .quad 153740 + .quad 153803 + .quad 153859 + .quad 153889 + .quad 153919 + .quad 153949 + .quad 153979 + .quad 154009 + .quad 154039 + .quad 154071 + .quad 154103 + .quad 154156 + .quad 154188 + .quad 154233 + .quad 154295 + .quad 154347 + .quad 154386 + .quad 154425 + .quad 154459 + .quad 154489 + .quad 154542 + .quad 154635 + .quad 154665 + .quad 154695 + .quad 154732 + .quad 154768 + .quad 154803 + .quad 154837 + .quad 154891 + .quad 154943 + .quad 154997 + .quad 155029 + .quad 155094 + .quad 155162 + .quad 155206 + .quad 155253 + .quad 155284 + .quad 155354 + .quad 155402 + .quad 155448 + .quad 155493 + .quad 155542 + .quad 155580 + .quad 155646 + .quad 155711 + .quad 155745 + .quad 155775 + .quad 155805 + .quad 155836 + .quad 155893 + .quad 155939 + .quad 155987 + .quad 156013 + .quad 156045 + .quad 156085 + .quad 156128 + .quad 156182 + .quad 156234 + .quad 156269 + .quad 156309 + .quad 156333 + .quad 156364 + .quad 156395 + .quad 156426 + .quad 156447 + .quad 156476 + .quad 156507 + .quad 156533 + .quad 156623 + .quad 156642 + .quad 156657 + .quad 156672 + .quad 156692 + .quad 156715 + .quad 156735 + .quad 156759 + .quad 156800 + .quad 156833 + .quad 156871 + .quad 156910 + .quad 156940 + .quad 156970 + .quad 157001 + .quad 157025 + .quad 157052 + .quad 157079 + .quad 157106 + .quad 157134 + .quad 157166 + .quad 157197 + .quad 157238 + .quad 157277 + .quad 157316 + .quad 157357 + .quad 157396 + .quad 157424 + .quad 157454 + .quad 157485 + .quad 157526 + .quad 157566 + .quad 157604 + .quad 157638 + .quad 157674 + .quad 157690 + .quad 157714 + .quad 157761 + .quad 157789 + .quad 157832 + .quad 157880 + .quad 157940 + .quad 157986 + .quad 158014 + .quad 158048 + .quad 158081 + .quad 158091 + .quad 158124 + .quad 158163 + .quad 158191 + .quad 158244 + .quad 158299 + .quad 158355 + .quad 158399 + .quad 158438 + .quad 158531 + .quad 158574 + .quad 158600 + .quad 158656 + .quad 158687 + .quad 158771 + .quad 158817 + .quad 158882 + .quad 158933 + .quad 158987 + .quad 159022 + .quad 159065 + .quad 159116 + .quad 159193 + .quad 159270 + .quad 159347 + .quad 159424 + .quad 159482 + .quad 159540 + .quad 159604 + .quad 159666 + .quad 159732 + .quad 159798 + .quad 159826 + .quad 159853 + .quad 159889 + .quad 159912 + .quad 159948 + .quad 159979 + .quad 160016 + .quad 160044 + .quad 160109 + .quad 160175 + .quad 160215 + .quad 160256 + .quad 160295 + .quad 160335 + .quad 160374 + .quad 160411 + .quad 160449 + .quad 160488 + .quad 160517 + .quad 160546 + .quad 160575 + .quad 160604 + .quad 160632 + .quad 160660 + .quad 160688 + .quad 160716 + .quad 160744 + .quad 160794 + .quad 160811 + .quad 160846 + .quad 160895 + .quad 160921 + .quad 160953 + .quad 161007 + .quad 161039 + .quad 161093 + .quad 161128 + .quad 161177 + .quad 161226 + .quad 161275 + .quad 161324 + .quad 161373 + .quad 161422 + .quad 161456 + .quad 161504 + .quad 161552 + .quad 161585 + .quad 161619 + .quad 161650 + .quad 161683 + .quad 161715 + .quad 161749 + .quad 161778 + .quad 161814 + .quad 161843 + .quad 161890 + .quad 161935 + .quad 161978 + .quad 162038 + .quad 162069 + .quad 162102 + .quad 162159 + .quad 162196 + .quad 162275 + .quad 162303 + .quad 162334 + .quad 162366 + .quad 162405 + .quad 162443 + .quad 162498 + .quad 162553 + .quad 162608 + .quad 162663 + .quad 162719 + .quad 162775 + .quad 162831 + .quad 162887 + .quad 162941 + .quad 162995 + .quad 163051 + .quad 163107 + .quad 163163 + .quad 163219 + .quad 163273 + .quad 163327 + .quad 163383 + .quad 163439 + .quad 163495 + .quad 163551 + .quad 163609 + .quad 163667 + .quad 163723 + .quad 163779 + .quad 163837 + .quad 163895 + .quad 163947 + .quad 164000 + .quad 164029 + .quad 164088 + .quad 164148 + .quad 164208 + .quad 164268 + .quad 164328 + .quad 164390 + .quad 164450 + .quad 164512 + .quad 164556 + .quad 164586 + .quad 164616 + .quad 164646 + .quad 164676 + .quad 164708 + .quad 164740 + .quad 164772 + .quad 164805 + .quad 164860 + .quad 164913 + .quad 164944 + .quad 164976 + .quad 165007 + .quad 165038 + .quad 165045 + .quad 165054 + .quad 165112 + .quad 165119 + .quad 165127 + .quad 165134 + .quad 165140 + .quad 165148 + .quad 165159 + .quad 165174 + .quad 165187 + .quad 165199 + .quad 165231 + .quad 165237 + .quad 165243 + .quad 165249 + .quad 165280 + .quad 165312 + .quad 165333 + .quad 165397 + .quad 165451 + .quad 165459 + .quad 165503 + .quad 165509 + .quad 165515 + .quad 165559 + .quad 165603 + .quad 165647 + .quad 165691 + .quad 165729 + .quad 165767 + .quad 165805 + .quad 165851 + .quad 165897 + .quad 165934 + .quad 165977 + .quad 166016 + .quad 166063 + .quad 166115 + .quad 166157 + .quad 166198 + .quad 166238 + .quad 166278 + .quad 166318 + .quad 166363 + .quad 166408 + .quad 166453 + .quad 166496 + .quad 166539 + .quad 166582 + .quad 166625 + .quad 166674 + .quad 166714 + .quad 166758 + .quad 166802 + .quad 166845 + .quad 166883 + .quad 166921 + .quad 166959 + .quad 166997 + .quad 167035 + .quad 167073 + .quad 167119 + .quad 167156 + .quad 167202 + .quad 167248 + .quad 167287 + .quad 167335 + .quad 167382 + .quad 167429 + .quad 167476 + .quad 167520 + .quad 167562 + .quad 167603 + .quad 167644 + .quad 167689 + .quad 167732 + .quad 167775 + .quad 167818 + .quad 167861 + .quad 167904 + .quad 167947 + .quad 167990 + .quad 168034 + .quad 168078 + .quad 168117 + .quad 168155 + .quad 168201 + .quad 168247 + .quad 168290 + .quad 168338 + .quad 168383 + .quad 168426 + .quad 168466 + .quad 168506 + .quad 168546 + .quad 168590 + .quad 168634 + .quad 168678 + .quad 168722 + .quad 168765 + .quad 168806 + .quad 168844 + .quad 168882 + .quad 168920 + .quad 168961 + .quad 169007 + .quad 169045 + .quad 169082 + .quad 169128 + .quad 169174 + .quad 169220 + .quad 169263 + .quad 169310 + .quad 169357 + .quad 169399 + .quad 169440 + .quad 169481 + .quad 169522 + .quad 169562 + .quad 169602 + .quad 169648 + .quad 169691 + .quad 169734 + .quad 169777 + .quad 169820 + .quad 169863 + .quad 169906 + .quad 169949 + .quad 169992 + .quad 170035 + .quad 170078 + .quad 170121 + .quad 170164 + .quad 170207 + .quad 170247 + .quad 170287 + .quad 170327 + .quad 170367 + .quad 170411 + .quad 170455 + .quad 170499 + .quad 170536 + .quad 170573 + .quad 170619 + .quad 170661 + .quad 170703 + .quad 170744 + .quad 170789 + .quad 170834 + .quad 170878 + .quad 170921 + .quad 170965 + .quad 171008 + .quad 171040 + .quad 171046 + .quad 171080 + .quad 171111 + .quad 171160 + .quad 171209 + .quad 171258 + .quad 171307 + .quad 171356 + .quad 171399 + .quad 171442 + .quad 171485 + .quad 171536 + .quad 171587 + .quad 171629 + .quad 171677 + .quad 171721 + .quad 171773 + .quad 171830 + .quad 171877 + .quad 171923 + .quad 171968 + .quad 172013 + .quad 172058 + .quad 172108 + .quad 172158 + .quad 172208 + .quad 172256 + .quad 172304 + .quad 172352 + .quad 172400 + .quad 172454 + .quad 172479 + .quad 172514 + .quad 172559 + .quad 172608 + .quad 172657 + .quad 172705 + .quad 172748 + .quad 172791 + .quad 172834 + .quad 172877 + .quad 172920 + .quad 172963 + .quad 173014 + .quad 173056 + .quad 173107 + .quad 173158 + .quad 173202 + .quad 173255 + .quad 173307 + .quad 173359 + .quad 173411 + .quad 173460 + .quad 173507 + .quad 173553 + .quad 173599 + .quad 173649 + .quad 173697 + .quad 173745 + .quad 173793 + .quad 173841 + .quad 173889 + .quad 173937 + .quad 173964 + .quad 174012 + .quad 174061 + .quad 174110 + .quad 174154 + .quad 174197 + .quad 174248 + .quad 174299 + .quad 174347 + .quad 174400 + .quad 174450 + .quad 174498 + .quad 174523 + .quad 174549 + .quad 174576 + .quad 174602 + .quad 174641 + .quad 174686 + .quad 174731 + .quad 174776 + .quad 174825 + .quad 174874 + .quad 174923 + .quad 174972 + .quad 175020 + .quad 175066 + .quad 175109 + .quad 175152 + .quad 175195 + .quad 175241 + .quad 175292 + .quad 175335 + .quad 175377 + .quad 175428 + .quad 175479 + .quad 175530 + .quad 175578 + .quad 175630 + .quad 175682 + .quad 175729 + .quad 175775 + .quad 175821 + .quad 175867 + .quad 175912 + .quad 175957 + .quad 176008 + .quad 176056 + .quad 176104 + .quad 176152 + .quad 176200 + .quad 176248 + .quad 176296 + .quad 176344 + .quad 176392 + .quad 176440 + .quad 176488 + .quad 176536 + .quad 176584 + .quad 176632 + .quad 176677 + .quad 176722 + .quad 176767 + .quad 176812 + .quad 176861 + .quad 176910 + .quad 176959 + .quad 177001 + .quad 177043 + .quad 177094 + .quad 177141 + .quad 177188 + .quad 177234 + .quad 177284 + .quad 177334 + .quad 177383 + .quad 177431 + .quad 177480 + .quad 177528 + .quad 177543 + .quad 177587 + .quad 177628 + .quad 177667 + .quad 177706 + .quad 177726 + .quad 177751 + .quad 177767 + .quad 177781 + .quad 177795 + .quad 177814 + .quad 177820 + .quad 177845 + .quad 177850 + .quad 177883 + .quad 177919 + .quad 177947 + .quad 177976 + .quad 178005 + .quad 178025 + .quad 178056 + .quad 178090 + .quad 178114 + .quad 178146 + .quad 178178 + .quad 178205 + .quad 178226 + .quad 178258 + .quad 178297 + .quad 178342 + .quad 178384 + .quad 178416 + .quad 178441 + .quad 178464 + .quad 178476 + .quad 178492 + .quad 178503 + .quad 178543 + .quad 178576 + .quad 178601 + .quad 178635 + .quad 178659 + .quad 178733 + .quad 178744 + .quad 178770 + .quad 178775 +.globl symbol_name +symbol_name: + .asciz "skernel" + .asciz "stext" + .asciz "strampoline" + .asciz "user_v" + .asciz "user_r" + .asciz "kernel::task::cpu::__syscall_260::_::__ctor" + .asciz "etrampoline" + .asciz "kernel::task::cpu::__syscall_177::_::__ctor" + .asciz "kernel::task::cpu::__syscall_174::_::__ctor" + .asciz "kernel::task::cpu::__syscall_155::_::__ctor" + .asciz "kernel::task::cpu::__syscall_124::_::__ctor" + .asciz "kernel::net::__syscall_210::_::__ctor" + .asciz "kernel::net::__syscall_203::_::__ctor" + .asciz "kernel::net::__syscall_201::_::__ctor" + .asciz "kernel::memory::map::__syscall_233::_::__ctor" + .asciz "kernel::memory::map::__syscall_215::_::__ctor" + .asciz "kernel::ipc::__syscall_99::_::__ctor" + .asciz "kernel::ipc::shm::__syscall_196::_::__ctor" + .asciz "kernel::gui::__syscall_2000::_::__ctor" + .asciz "kernel::fs::sys::cpu::__syscall_121::_::__ctor" + .asciz "kernel::fs::proc::process::__syscall_165::_::__ctor" + .asciz "kernel::fs::link::__syscall_78::_::__ctor" + .asciz "kernel::fs::ext::__syscall_10::_::__ctor" + .asciz "kernel::fs::ext::__syscall_9::_::__ctor" + .asciz "kernel::fs::ext::__syscall_8::_::__ctor" + .asciz "kernel::fs::ext::__syscall_6::_::__ctor" + .asciz "kernel::fs::control::__syscall_53::_::__ctor" + .asciz "kernel::fs::control::__syscall_29::_::__ctor" + .asciz "kernel::fs::control::__syscall_25::_::__ctor" + .asciz "kernel::fs::basic::__syscall_38::_::__ctor" + .asciz "kernel::fs::basic::__syscall_44::_::__ctor" + .asciz "kernel::fs::basic::__syscall_67::_::__ctor" + .asciz "kernel::fs::basic::__syscall_45::_::__ctor" + .asciz "kernel::device::input::__syscall_2002::_::__ctor" + .asciz "kernel::timer::__syscall_103::_::__ctor" + .asciz "kernel::task::cpu::__syscall_221::_::__ctor" + .asciz "kernel::task::cpu::__syscall_220::_::__ctor" + .asciz "kernel::task::cpu::__syscall_94::_::__ctor" + .asciz "kernel::net::__syscall_209::_::__ctor" + .asciz "kernel::net::__syscall_207::_::__ctor" + .asciz "kernel::net::__syscall_206::_::__ctor" + .asciz "kernel::net::__syscall_204::_::__ctor" + .asciz "kernel::net::__syscall_200::_::__ctor" + .asciz "kernel::net::__syscall_198::_::__ctor" + .asciz "kernel::memory::map::__syscall_222::_::__ctor" + .asciz "kernel::ipc::__syscall_59::_::__ctor" + .asciz "kernel::ipc::signal::__syscall_130::_::__ctor" + .asciz "kernel::ipc::signal::__syscall_137::_::__ctor" + .asciz "kernel::gui::__syscall_2001::_::__ctor" + .asciz "kernel::fs::sys::info::__syscall_179::_::__ctor" + .asciz "kernel::fs::sys::cpu::__syscall_120::_::__ctor" + .asciz "kernel::fs::sys::cpu::__syscall_123::_::__ctor" + .asciz "kernel::fs::sys::cpu::__syscall_118::_::__ctor" + .asciz "kernel::fs::select::__syscall_72::_::__ctor" + .asciz "kernel::fs::link::__syscall_35::_::__ctor" + .asciz "kernel::fs::ext::__syscall_15::_::__ctor" + .asciz "kernel::fs::ext::__syscall_13::_::__ctor" + .asciz "kernel::fs::control::__syscall_52::_::__ctor" + .asciz "kernel::fs::basic::__syscall_43::_::__ctor" + .asciz "kernel::fs::basic::__syscall_80::_::__ctor" + .asciz "kernel::fs::basic::__syscall_65::_::__ctor" + .asciz "kernel::fs::basic::__syscall_34::_::__ctor" + .asciz "kernel::fs::basic::__syscall_49::_::__ctor" + .asciz "kernel::fs::basic::__syscall_40::_::__ctor" + .asciz "kernel::task::cpu::__syscall_96::_::__ctor" + .asciz "kernel::task::cpu::__syscall_214::_::__ctor" + .asciz "kernel::task::cpu::__syscall_176::_::__ctor" + .asciz "kernel::sbi::__syscall_2003::_::__ctor" + .asciz "kernel::net::__syscall_208::_::__ctor" + .asciz "kernel::memory::map::__syscall_226::_::__ctor" + .asciz "kernel::ipc::signal::__syscall_129::_::__ctor" + .asciz "kernel::ipc::shm::__syscall_194::_::__ctor" + .asciz "kernel::fs::sys::info::__syscall_116::_::__ctor" + .asciz "kernel::fs::control::__syscall_88::_::__ctor" + .asciz "kernel::fs::basic::__syscall_82::_::__ctor" + .asciz "kernel::timer::__syscall_114::_::__ctor" + .asciz "kernel::timer::__syscall_113::_::__ctor" + .asciz "kernel::timer::__syscall_169::_::__ctor" + .asciz "kernel::task::cpu::__syscall_175::_::__ctor" + .asciz "kernel::task::cpu::__syscall_173::_::__ctor" + .asciz "kernel::task::cpu::__syscall_172::_::__ctor" + .asciz "kernel::task::cpu::__syscall_157::_::__ctor" + .asciz "kernel::task::cpu::__syscall_93::_::__ctor" + .asciz "kernel::system::__syscall_160::_::__ctor" + .asciz "kernel::net::__syscall_199::_::__ctor" + .asciz "kernel::net::__syscall_205::_::__ctor" + .asciz "kernel::net::__syscall_202::_::__ctor" + .asciz "kernel::memory::__syscall_283::_::__ctor" + .asciz "kernel::memory::map::__syscall_227::_::__ctor" + .asciz "kernel::ipc::__syscall_100::_::__ctor" + .asciz "kernel::ipc::__syscall_24::_::__ctor" + .asciz "kernel::ipc::signal::__syscall_133::_::__ctor" + .asciz "kernel::ipc::signal::__syscall_139::_::__ctor" + .asciz "kernel::ipc::signal::__syscall_135::_::__ctor" + .asciz "kernel::ipc::shm::__syscall_195::_::__ctor" + .asciz "kernel::fs::sys::cpu::__syscall_119::_::__ctor" + .asciz "kernel::fs::sys::cpu::__syscall_122::_::__ctor" + .asciz "kernel::fs::link::__syscall_36::_::__ctor" + .asciz "kernel::fs::ext::__syscall_16::_::__ctor" + .asciz "kernel::fs::ext::__syscall_14::_::__ctor" + .asciz "kernel::fs::ext::__syscall_12::_::__ctor" + .asciz "kernel::fs::ext::__syscall_7::_::__ctor" + .asciz "kernel::fs::ext::__syscall_5::_::__ctor" + .asciz "kernel::fs::control::__syscall_166::_::__ctor" + .asciz "kernel::fs::basic::__syscall_81::_::__ctor" + .asciz "kernel::fs::basic::__syscall_79::_::__ctor" + .asciz "kernel::fs::basic::__syscall_68::_::__ctor" + .asciz "kernel::fs::basic::__syscall_66::_::__ctor" + .asciz "kernel::fs::basic::__syscall_62::_::__ctor" + .asciz "kernel::fs::basic::__syscall_50::_::__ctor" + .asciz "kernel::fs::basic::__syscall_17::_::__ctor" + .asciz "kernel::fs::basic::__syscall_64::_::__ctor" + .asciz "kernel::fs::basic::__syscall_63::_::__ctor" + .asciz "kernel::fs::basic::__syscall_61::_::__ctor" + .asciz "kernel::fs::basic::__syscall_57::_::__ctor" + .asciz "kernel::fs::basic::__syscall_56::_::__ctor" + .asciz "kernel::fs::basic::__syscall_39::_::__ctor" + .asciz "kernel::timer::__syscall_115::_::__ctor" + .asciz "kernel::timer::__syscall_102::_::__ctor" + .asciz "kernel::timer::__syscall_101::_::__ctor" + .asciz "kernel::timer::__syscall_153::_::__ctor" + .asciz "kernel::task::cpu::__syscall_261::_::__ctor" + .asciz "kernel::task::cpu::__syscall_178::_::__ctor" + .asciz "kernel::task::cpu::__syscall_154::_::__ctor" + .asciz "kernel::ipc::__syscall_98::_::__ctor" + .asciz "kernel::ipc::__syscall_23::_::__ctor" + .asciz "kernel::ipc::signal::__syscall_134::_::__ctor" + .asciz "kernel::fs::poll::__syscall_73::_::__ctor" + .asciz "kernel::fs::link::__syscall_37::_::__ctor" + .asciz "kernel::fs::ext::__syscall_11::_::__ctor" + .asciz "kernel::fs::control::__syscall_55::_::__ctor" + .asciz "kernel::fs::control::__syscall_48::_::__ctor" + .asciz "kernel::fs::basic::__syscall_285::_::__ctor" + .asciz "kernel::fs::basic::__syscall_71::_::__ctor" + .asciz "kernel::fs::basic::__syscall_276::_::__ctor" + .asciz "kernel::fs::basic::__syscall_46::_::__ctor" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::ptr::drop_in_place<&isize>" + .asciz "core::panicking::assert_failed" + .asciz "main" + .asciz "__rust_alloc_error_handler" + .asciz "kernel_v" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "fdt::node::all_nodes::closure" + .asciz "::fmt" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_arc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place<&fatfs::error::Error<()>>" + .asciz "unifs::UniFs::kill_sb" + .asciz "unifs::UniFs::kill_sb" + .asciz "unifs::UniFsSuperBlock::root_dentry" + .asciz "unifs::UniFsSuperBlock::remove_inode" + .asciz " as vfscore::fstype::VfsFsType>::mount" + .asciz " as vfscore::fstype::VfsFsType>::fs_flag" + .asciz " as vfscore::fstype::VfsFsType>::fs_name" + .asciz " as vfscore::fstype::VfsFsType>::kill_sb" + .asciz " as vfscore::fstype::VfsFsType>::mount" + .asciz " as vfscore::fstype::VfsFsType>::fs_flag" + .asciz " as vfscore::fstype::VfsFsType>::fs_name" + .asciz " as vfscore::fstype::VfsFsType>::kill_sb" + .asciz "fat_vfs::fs::FatFsSuperBlock::root_dentry" + .asciz "fat_vfs::inode::dir::FatFsDirInode::delete_file" + .asciz "fat_vfs::inode::file::FatFsFileInode::new" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::flush" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::read_at" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::write_at" + .asciz " as vfscore::file::VfsFile>::poll" + .asciz " as vfscore::file::VfsFile>::flush" + .asciz " as vfscore::file::VfsFile>::fsync" + .asciz " as vfscore::file::VfsFile>::ioctl" + .asciz " as vfscore::file::VfsFile>::read_at" + .asciz " as vfscore::file::VfsFile>::write_at" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::file::VfsFile>::ioctl" + .asciz " as vfscore::file::VfsFile>::readdir" + .asciz " as vfscore::superblock::VfsSuperBlock>::root_inode" + .asciz " as vfscore::superblock::VfsSuperBlock>::fs_type" + .asciz " as vfscore::superblock::VfsSuperBlock>::stat_fs" + .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::rmdir" + .asciz " as vfscore::inode::VfsInode>::create" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::unlink" + .asciz " as vfscore::inode::VfsInode>::symlink" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::file::VfsFile>::flush" + .asciz " as vfscore::file::VfsFile>::read_at" + .asciz " as vfscore::file::VfsFile>::write_at" + .asciz " as vfscore::file::VfsFile>::readdir" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::rmdir" + .asciz " as vfscore::inode::VfsInode>::create" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::rmdir" + .asciz " as vfscore::inode::VfsInode>::create" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::unlink" + .asciz " as vfscore::inode::VfsInode>::unlink::closure" + .asciz " as vfscore::inode::VfsInode>::symlink" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::superblock::VfsSuperBlock>::root_inode" + .asciz " as vfscore::superblock::VfsSuperBlock>::fs_type" + .asciz " as vfscore::superblock::VfsSuperBlock>::stat_fs" + .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz "kernel::board::common::get_device_info" + .asciz "kernel::fs::sys::init_sysfs" + .asciz "kernel::task::task::TaskInner::update_timer" + .asciz "trap_return" + .asciz "kernel::trap::init_trap_subsystem" + .asciz "kernel::trap::check_timer_interrupt_pending" + .asciz "user_trap_vector" + .asciz "kernel::trap::check_task_timer_expired" + .asciz "kernel_trap_vector" + .asciz "kernel::board::qemu::init_dtb" + .asciz "kernel::board::qemu::probe_devices_from_dtb" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::into_any" + .asciz "core::fmt::num::::fmt" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place<&kernel_sync::ticket::TicketMutex>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "::drop" + .asciz "kernel::task::task::Task::terminate" + .asciz "kernel::task::task::Task::access_inner" + .asciz "kernel::task::task::Task::trap_frame" + .asciz "kernel::task::task::Task::trap_frame_ptr" + .asciz "kernel::task::task::Task::children" + .asciz "kernel::task::task::Task::check_child" + .asciz "kernel::task::task::Task::take_children" + .asciz "kernel::task::task::Task::update_parent" + .asciz "kernel::task::task::Task::get_file" + .asciz "kernel::task::task::Task::add_file" + .asciz "kernel::task::task::Task::remove_file" + .asciz "kernel::task::task::Task::transfer_raw_ptr" + .asciz "kernel::task::task::Task::transfer_raw_ptr" + .asciz "kernel::task::task::Task::transfer_raw_ptr" + .asciz "kernel::task::task::Task::transfer_raw_ptr" + .asciz "kernel::task::task::Task::transfer_raw_ptr" + .asciz "kernel::task::task::Task::transfer_raw_ptr" + .asciz "kernel::task::task::Task::transfer_str" + .asciz "kernel::task::task::Task::transfer_buffer" + .asciz "kernel::task::task::Task::transfer_buffer" + .asciz "kernel::task::task::TaskInner::set_prlimit" + .asciz "kernel::task::task::TaskInner::trap_frame" + .asciz "kernel::task::task::TaskInner::load_trap_frame" + .asciz "kernel::task::task::TaskInner::transfer_raw" + .asciz "kernel::task::task::TaskInner::transfer_str" + .asciz "kernel::task::task::TaskInner::transfer_buffer" + .asciz "kernel::task::task::TaskInner::transfer_raw_ptr_mut" + .asciz "kernel::task::task::TaskInner::transfer_raw_ptr_mut" + .asciz "kernel::task::task::TaskInner::transfer_raw_ptr_mut" + .asciz "kernel::task::task::TaskInner::transfer_raw_ptr" + .asciz "kernel::task::task::TaskInner::transfer_raw_ptr" + .asciz "kernel::task::task::TaskInner::transfer_raw_ptr" + .asciz "kernel::task::task::TaskInner::transfer_raw_ptr" + .asciz "kernel::task::task::TaskInner::extend_heap" + .asciz "kernel::task::task::TaskInner::add_mmap" + .asciz "kernel::task::task::TaskInner::unmap" + .asciz "kernel::task::task::TaskInner::map_protect" + .asciz "kernel::task::task::TaskInner::do_load_page_fault" + .asciz "kernel::task::task::TaskInner::invalid_page_solver" + .asciz "kernel::task::task::TaskInner::do_instruction_page_fault" + .asciz "kernel::task::task::TaskInner::do_store_page_fault" + .asciz "kernel::task::task::Task::pre_recycle" + .asciz "kernel::task::task::Task::from_elf" + .asciz "kernel::task::task::Task::t_clone" + .asciz "kernel::task::task::Task::exec" + .asciz "::fmt" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz "virtio_drivers::queue::VirtQueue::add_notify_wait_pop" + .asciz "virtio_drivers::queue::VirtQueue::add_notify_wait_pop" + .asciz "virtio_drivers::queue::VirtQueue::add" + .asciz "virtio_drivers::queue::VirtQueue::new" + .asciz "virtio_drivers::queue::VirtQueue::new" + .asciz "virtio_drivers::queue::VirtQueue::new" + .asciz "virtio_drivers::queue::VirtQueue::pop_used" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "::read_u16_le" + .asciz "::read_u16_le" + .asciz "::read_u32_le" + .asciz "::read_u32_le" + .asciz "::read_u8" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place" + .asciz "fatfs::io::Read::read_exact" + .asciz "fatfs::io::Read::read_exact" + .asciz "fatfs::io::Write::write_all" + .asciz "fatfs::io::Write::write_all" + .asciz "fatfs::dir::Dir::create_dir" + .asciz "fatfs::dir::Dir::find_entry" + .asciz "fatfs::dir::Dir::create_file" + .asciz "fatfs::dir::Dir::write_entry" + .asciz "fatfs::dir::Dir::rename_internal" + .asciz "fatfs::dir::Dir::create_sfn_entry" + .asciz "fatfs::dir::Dir::remove" + .asciz "fatfs::dir::Dir::rename" + .asciz "fatfs::dir::Dir::open_dir" + .asciz "fatfs::dir::Dir::open_file" + .asciz "fatfs::table::alloc_cluster" + .asciz "fatfs::table::find_free_cluster" + .asciz "fatfs::table::count_free_clusters" + .asciz "fatfs::table::ClusterIterator::truncate" + .asciz "fatfs::table::write_fat" + .asciz "fatfs::dir_entry::DirEntryData::deserialize" + .asciz "fatfs::dir_entry::DirEntryEditor::flush" + .asciz "fatfs::dir_entry::DirLfnEntryData::serialize" + .asciz "fatfs::dir_entry::DirFileEntryData::serialize" + .asciz "fatfs::dir_entry::DirEntry::file_name" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz "kernel::ipc::signal::global_register_signals" + .asciz "kernel::ipc::signal::global_logoff_signals" + .asciz "kernel::ipc::signal::send_signal" + .asciz "kernel::ipc::signal::signal_handler" + .asciz "rust_begin_unwind" + .asciz "kernel::trace::find_symbol_with_addr" + .asciz "kernel::ipc::signal::sigaction" + .asciz "kernel::ipc::signal::sigtimewait" + .asciz "kernel::ipc::signal::sigprocmask" + .asciz "kernel::ipc::signal::sigsuspend" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::double_ended::DoubleEndedIterator>::next_back" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_arc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place<&isize>" + .asciz "core::ptr::drop_in_place" + .asciz "alloc::collections::btree::map::BTreeMap::get" + .asciz "alloc::collections::btree::map::BTreeMap::get" + .asciz "alloc::collections::btree::map::BTreeMap::get" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::remove" + .asciz "alloc::collections::btree::map::BTreeMap::remove" + .asciz "alloc::collections::btree::map::BTreeMap::remove" + .asciz "alloc::collections::btree::map::BTreeMap::remove" + .asciz "alloc::collections::btree::map::BTreeMap::remove" + .asciz "alloc::collections::btree::map::BTreeMap::remove" + .asciz "alloc::collections::btree::map::BTreeMap::remove" + .asciz "alloc::collections::btree::map::entry::Entry::or_insert" + .asciz "alloc::collections::btree::map::entry::Entry::or_insert" + .asciz "unifs::inode::UniFsDirInode::lookup" + .asciz "unifs::inode::UniFsDirInode::readdir" + .asciz "unifs::inode::UniFsDirInode::node_perm" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz "unifs::inode::UniFsDirInode::rename_to" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::ops::drop::Drop>::drop" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::read_at" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::write_at" + .asciz "vfscore::path::VfsPath::join" + .asciz "vfscore::path::VfsPath::join" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "vfscore::dentry::VfsDentry::is_mount_point" + .asciz "vfscore::dentry::VfsDentry::path" + .asciz " as vfscore::file::VfsFile>::readdir" + .asciz " as vfscore::dentry::VfsDentry>::set_parent" + .asciz " as vfscore::dentry::VfsDentry>::mount_point" + .asciz " as vfscore::dentry::VfsDentry>::to_mount_point" + .asciz " as vfscore::dentry::VfsDentry>::clear_mount_point" + .asciz " as vfscore::dentry::VfsDentry>::find" + .asciz " as vfscore::dentry::VfsDentry>::name" + .asciz " as vfscore::dentry::VfsDentry>::inode" + .asciz " as vfscore::dentry::VfsDentry>::insert" + .asciz " as vfscore::dentry::VfsDentry>::parent" + .asciz " as vfscore::dentry::VfsDentry>::remove" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::rmdir" + .asciz " as vfscore::inode::VfsInode>::create" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::symlink" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::rmdir" + .asciz " as vfscore::inode::VfsInode>::create" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::unlink" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::superblock::VfsSuperBlock>::super_type" + .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" + .asciz " as core::clone::Clone>::clone::clone_subtree" + .asciz " as core::clone::Clone>::clone::clone_subtree" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz "kernel::print::init_print" + .asciz "::read_at" + .asciz "::write_at" + .asciz "::poll" + .asciz "::ioctl" + .asciz "::get_attr" + .asciz "::read_at" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz " as core::ops::drop::Drop>::drop" + .asciz "page_table::table::bits64::PageTable64::map_region" + .asciz "page_table::table::bits64::PageTable64::alloc_table" + .asciz "page_table::table::bits64::PageTable64::unmap_region" + .asciz "page_table::table::bits64::PageTable64::modify_pte_flags" + .asciz "page_table::table::bits64::PageTable64::map_region_no_target" + .asciz "page_table::table::bits64::PageTable64::get_entry_mut_or_create" + .asciz "page_table::table::bits64::PageTable64::map" + .asciz "page_table::table::bits64::PageTable64::try_new" + .asciz "rtc::LowRtcDeviceExt::read_time_fmt" + .asciz "rtc::LowRtcDeviceExt::read_alarm_fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "talc::alloc_error" + .asciz "alloc::collections::vec_deque::VecDeque::grow" + .asciz "alloc::collections::vec_deque::VecDeque::grow" + .asciz "alloc::collections::vec_deque::VecDeque::grow" + .asciz "::yield_now" + .asciz "kernel::driver::rtc::::hand_irq" + .asciz "kernel::interrupt::ext_interrupt::external_interrupt_handler" + .asciz "kernel::ipc::futex::FutexWaitManager::add_waiter" + .asciz "kernel::ipc::futex::FutexWaitManager::wake_for_signal" + .asciz "kernel::ipc::futex::FutexWaitManager::wake_for_timeout" + .asciz "kernel::ipc::futex::FutexWaitManager::delete_empty_waiters" + .asciz "kernel::ipc::futex::FutexWaitManager::wake" + .asciz "kernel::ipc::futex::FutexWaitManager::requeue" + .asciz "kernel::memory::vmm::kernel_info" + .asciz "kernel::memory::vmm::build_kernel_address_space" + .asciz "kernel::memory::vmm::build_thread_address_space" + .asciz "kernel::memory::vmm::build_cow_address_space" + .asciz "kernel::memory::vmm::build_elf_address_space" + .asciz "kernel::memory::init_memory_system" + .asciz "::alloc" + .asciz "::dealloc" + .asciz "::do_user_handle" + .asciz "::do_kernel_handle" + .asciz "__rust_alloc" + .asciz "__rust_dealloc" + .asciz "__rust_realloc" + .asciz "__rust_alloc_zeroed" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "alloc::collections::binary_heap::BinaryHeap::pop" + .asciz "alloc::sync::Arc::downgrade::panic_cold_display" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Weak::upgrade::checked_increment::panic_cold_display" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz "hashbrown::raw::RawTable::reserve_rehash" + .asciz "hashbrown::raw::RawTableInner::fallible_with_capacity" + .asciz "::enabled" + .asciz "::log" + .asciz "::flush" + .asciz "kernel::print::logging::init_logger" + .asciz "kernel::fs::ram::init_ramfs" + .asciz "__sys_event_get" + .asciz "__sys_truncate" + .asciz "__sys_pread" + .asciz "__sys_fstatfs" + .asciz "__sys_renameat" + .asciz "__fcntl" + .asciz "__ioctl" + .asciz "__chmodat" + .asciz "__sys_lsetxattr" + .asciz "__sys_getxattr" + .asciz "__sys_lgetxattr" + .asciz "__sys_fgetxattr" + .asciz "__sys_readlinkat" + .asciz "__getrusage" + .asciz "__sched_getparam" + .asciz "__sys_framebuffer" + .asciz "__shmat" + .asciz "__set_robust_list" + .asciz "__do_munmap" + .asciz "__madvise" + .asciz "__listening" + .asciz "__connect" + .asciz "__shutdown" + .asciz "__do_suspend" + .asciz "__get_pgid" + .asciz "__getuid" + .asciz "__getegid" + .asciz "__wait4" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "syscall_table::Service::from_handler::closure" + .asciz "::submit" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "<(P0,P1,P2) as syscall_table::FromArgs>::from" + .asciz "<(P0,P1,P2) as syscall_table::FromArgs>::from" + .asciz "<(P0,P1,P2,P3) as syscall_table::FromArgs>::from" + .asciz "<(P0,P1,P2,P3) as syscall_table::FromArgs>::from" + .asciz "<(P0,P1,P2,P3) as syscall_table::FromArgs>::from" + .asciz "<(P0,P1,P2,P3) as syscall_table::FromArgs>::from" + .asciz "<(P0,P1,P2,P3,P4) as syscall_table::FromArgs>::from" + .asciz "<(P0,P1,P2,P3,P4) as syscall_table::FromArgs>::from" + .asciz "virtio_drivers::device::gpu::VirtIOGpu::get_display_info" + .asciz "virtio_drivers::device::gpu::VirtIOGpu::setup_framebuffer" + .asciz "virtio_drivers::device::gpu::VirtIOGpu::new" + .asciz "virtio_drivers::device::gpu::VirtIOGpu::flush" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place<&str>" + .asciz "core::ptr::drop_in_place<&kernel::ipc::shm::ShmMemoryState>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "spin::once::Once::try_call_once" + .asciz "spin::once::Once::try_call_once" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "::can_receive" + .asciz "::can_transmit" + .asciz "::rx_queue_size" + .asciz "::recycle_tx_buffers" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::flush" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::inode::VfsInode::list_xattr" + .asciz "vfscore::inode::VfsInode::list_xattr" + .asciz "vfscore::inode::VfsInode::list_xattr" + .asciz "vfscore::inode::VfsInode::update_time" + .asciz "vfscore::inode::VfsInode::update_time" + .asciz "vfscore::inode::VfsInode::update_time" + .asciz "vfscore::inode::VfsInode::rmdir" + .asciz "vfscore::inode::VfsInode::rmdir" + .asciz "vfscore::inode::VfsInode::rmdir" + .asciz "vfscore::inode::VfsInode::create" + .asciz "vfscore::inode::VfsInode::create" + .asciz "vfscore::inode::VfsInode::create" + .asciz "vfscore::inode::VfsInode::lookup" + .asciz "vfscore::inode::VfsInode::lookup" + .asciz "vfscore::inode::VfsInode::lookup" + .asciz "vfscore::inode::VfsInode::symlink" + .asciz "vfscore::inode::VfsInode::symlink" + .asciz "vfscore::inode::VfsInode::symlink" + .asciz "vfscore::inode::VfsInode::readlink" + .asciz "vfscore::inode::VfsInode::readlink" + .asciz "vfscore::inode::VfsInode::readlink" + .asciz "vfscore::inode::VfsInode::truncate" + .asciz "vfscore::inode::VfsInode::truncate" + .asciz "vfscore::inode::VfsInode::truncate" + .asciz "vfscore::inode::VfsInode::node_perm" + .asciz "vfscore::inode::VfsInode::node_perm" + .asciz " as core::iter::traits::iterator::Iterator>::fold" + .asciz " as core::iter::traits::iterator::Iterator>::fold" + .asciz "::inode_type" + .asciz "::read_at" + .asciz "::set_attr" + .asciz "::get_attr" + .asciz "::inode_type" + .asciz "::write_at" + .asciz "::get_attr" + .asciz "::now" + .asciz "::flush" + .asciz "::get_super_block" + .asciz "::flush" + .asciz "::get_super_block" + .asciz "::set_attr" + .asciz "::get_attr" + .asciz "::inode_type" + .asciz "kernel::device::init_device" + .asciz "kernel::driver::block_device::LowBlockDriver::flush" + .asciz "::capacity" + .asciz "::update_cursor" + .asciz "::get_framebuffer" + .asciz "::have_space_to_put" + .asciz "::write_at" + .asciz "::get_super_block" + .asciz "::node_perm" + .asciz "::set_attr" + .asciz "::get_attr" + .asciz "::inode_type" + .asciz "kernel::fs::dev::register_device" + .asciz "kernel::fs::dev::alloc_device_id" + .asciz "::rdev2device" + .asciz "kernel::fs::dev::init_devfs" + .asciz "__sys_mount" + .asciz "__sys_chdir" + .asciz "__sys_mkdirat" + .asciz "__sys_readv" + .asciz "__sys_fstat" + .asciz "__sys_statfs" + .asciz "__chmod" + .asciz "__sys_flistxattr" + .asciz "__sys_lremovexattr" + .asciz "__sys_unlinkat" + .asciz "__pselect6" + .asciz "__sched_setparam" + .asciz "__sched_getaffinity" + .asciz "__sched_getscheduler" + .asciz "__sys_info" + .asciz "__sys_framebuffer_flush" + .asciz "kernel::ipc::shm::shmget" + .asciz "kernel::ipc::shm::shmat" + .asciz "kernel::ipc::shm::shmctl" + .asciz "__sigtimewait" + .asciz "__tkill" + .asciz "__sys_pipe" + .asciz "__do_mmap" + .asciz "__socket" + .asciz "__bind" + .asciz "__getsockname" + .asciz "__sendto" + .asciz "__recvfrom" + .asciz "__getsockopt" + .asciz "__exit_group" + .asciz "__clone" + .asciz "__do_exec" + .asciz "__setitimer" + .asciz "__switch" + .asciz "virtio_drivers::transport::Transport::begin_init" + .asciz "virtio_drivers::transport::Transport::begin_init" + .asciz "virtio_drivers::transport::Transport::begin_init" + .asciz "::type_id" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::into_any" + .asciz "core::fmt::num::::fmt" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place,ksync::KernelLockAction>>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place<&kernel::net::socket::Socket>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "<&mut T as core::fmt::Debug>::fmt" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz "kernel::fs::file::kernel_file::File::read_at" + .asciz "kernel::fs::file::kernel_file::File::write_at" + .asciz "kernel::fs::file::kernel_file::File::flush" + .asciz "kernel::fs::file::kernel_file::File::ioctl" + .asciz "kernel::fs::file::kernel_file::File::readdir" + .asciz "kernel::fs::file::kernel_file::File::truncate" + .asciz "::fmt" + .asciz "::read" + .asciz "::write" + .asciz "::seek" + .asciz "::get_attr" + .asciz "::set_open_flag" + .asciz "::get_open_flag" + .asciz "::dentry" + .asciz "::inode" + .asciz "::is_readable" + .asciz "::is_append" + .asciz "::poll" + .asciz "::fmt" + .asciz "kernel::net::socket::SocketData::new" + .asciz "kernel::net::socket::SocketData::bind" + .asciz "kernel::net::socket::SocketData::accept" + .asciz "kernel::net::socket::SocketData::connect" + .asciz "kernel::net::socket::SocketData::send_to" + .asciz "kernel::net::socket::SocketData::recvfrom" + .asciz "kernel::net::socket::SocketData::shutdown" + .asciz "kernel::net::socket::SocketData::ready_read" + .asciz "kernel::net::common_socket_syscall" + .asciz "kernel::task::init_process" + .asciz "kernel::timer::check_timer_queue" + .asciz "__fsync" + .asciz "__utimensat" + .asciz "kernel::fs::select::pselect6" + .asciz "__syslog" + .asciz "__shmget" + .asciz "__kill" + .asciz "__map_protect" + .asciz "kernel::net::socket" + .asciz "kernel::net::bind" + .asciz "kernel::net::listening" + .asciz "kernel::net::accept" + .asciz "kernel::net::connect" + .asciz "kernel::net::getsockname" + .asciz "kernel::net::get_peer_name" + .asciz "kernel::net::sendto" + .asciz "kernel::net::recvfrom" + .asciz "kernel::net::setsockopt" + .asciz "__setsockopt" + .asciz "kernel::net::getsockopt" + .asciz "kernel::net::shutdown" + .asciz "kernel::net::socket_pair" + .asciz "__system_shutdown" + .asciz "__getgid" + .asciz "__do_brk" + .asciz "__set_tid_address" + .asciz "::fmt" + .asciz "::fmt" + .asciz "kernel::timer::nanosleep" + .asciz "kernel::timer::clock_get_time" + .asciz "kernel::timer::getitimer" + .asciz "kernel::timer::setitimer" + .asciz "kernel::timer::clock_getres" + .asciz "kernel::timer::clock_nanosleep" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::fmt::Write::write_char" + .asciz "core::fmt::Write::write_char" + .asciz "core::fmt::Write::write_fmt" + .asciz "core::fmt::Write::write_fmt" + .asciz "core::fmt::Write::write_fmt" + .asciz "core::ptr::drop_in_place<&core::option::Option>>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz "core::ptr::drop_in_place<&u32>" + .asciz "core::ptr::drop_in_place<&usize>" + .asciz "core::ptr::drop_in_place<&pconst::io::PollFd>" + .asciz "core::ptr::drop_in_place<&kernel::ipc::shm::ShmInfo>" + .asciz "core::ptr::drop_in_place<&kernel::memory::frame::FrameTracker>" + .asciz "core::ptr::drop_in_place<&core::option::Option<()>>" + .asciz "core::ptr::drop_in_place<&pconst::signal::number::SignalNumber>" + .asciz "core::ptr::drop_in_place<&alloc::sync::Arc>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "<&mut T as core::fmt::Debug>::fmt" + .asciz "::write_char" + .asciz "::write_str" + .asciz "alloc::vec::Vec::remove" + .asciz "alloc::vec::in_place_collect:: for alloc::vec::Vec>::from_iter" + .asciz "alloc::vec::in_place_collect:: for alloc::vec::Vec>::from_iter" + .asciz "alloc::string::String::push" + .asciz "pager::bitmap::Bitmap<_>::alloc_pages_inner" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::clone::Clone>::clone" + .asciz " as core::ops::drop::Drop>::drop" + .asciz ">::extend" + .asciz "gmanager::MinimalManager::insert_with_index" + .asciz "gmanager::MinimalManager::clear" + .asciz "gmanager::MinimalManager::insert" + .asciz " as alloc::vec::spec_from_iter::SpecFromIter>::from_iter" + .asciz " as alloc::vec::spec_from_iter::SpecFromIter>::from_iter" + .asciz " as alloc::vec::spec_from_iter::SpecFromIter>::from_iter" + .asciz " as alloc::vec::spec_from_iter::SpecFromIter>::from_iter" + .asciz "::write_str" + .asciz "::write_str" + .asciz "kernel::print::console::__print" + .asciz "::print" + .asciz "kernel::memory::map::MMapInfo::add_region" + .asciz "kernel::memory::map::MMapRegion::split" + .asciz "kernel::gui::sys_framebuffer" + .asciz "::fmt" + .asciz "kernel::memory::map::do_mmap" + .asciz "kernel::memory::map::map_protect" + .asciz "kernel::memory::map::msync" + .asciz "kernel::memory::map::madvise" + .asciz " as core::iter::traits::iterator::Iterator>::fold" + .asciz "virtio_drivers::device::blk::VirtIOBlk::new" + .asciz "::type_id" + .asciz "::type_id" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::into_any" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::str::pattern::TwoWaySearcher::next" + .asciz "<*mut T as core::fmt::Debug>::fmt" + .asciz "<*const T as core::fmt::Debug>::fmt" + .asciz "<*mut T as core::fmt::Pointer>::fmt" + .asciz "<(U,T) as core::fmt::Debug>::fmt" + .asciz "<&str as core::str::pattern::Pattern>::is_contained_in" + .asciz "::fmt" + .asciz "::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "::read_at" + .asciz "::write_at" + .asciz "::poll" + .asciz "::ioctl" + .asciz "::read_at" + .asciz "kernel::fs::file::kernel_file::File::read_at" + .asciz "kernel::fs::file::kernel_file::File::write_at" + .asciz "kernel::fs::file::kernel_file::File::ioctl" + .asciz "kernel::fs::file::kernel_file::File::set_open_flag" + .asciz "kernel::fs::file::kernel_file::File::get_open_flag" + .asciz "kernel::fs::file::kernel_file::File::readdir" + .asciz "kernel::fs::file::kernel_file::File::truncate" + .asciz "::seek" + .asciz "::get_attr" + .asciz "::is_append" + .asciz "kernel::task::cpu::current_user_token" + .asciz "first_into_user" + .asciz "kernel::task::schedule::schedule" + .asciz "kernel::trap::exception::syscall_exception_handler" + .asciz "kernel::trap::exception::page_exception_handler" + .asciz "kernel::trap::exception::trap_common_read_file" + .asciz "kernel::fs::control::fcntl" + .asciz "kernel::fs::control::ioctl" + .asciz "kernel::fs::control::utimensat" + .asciz "kernel::fs::control::faccessat" + .asciz "kernel::fs::control::unmask" + .asciz "kernel::ipc::sys_pipe" + .asciz "kernel::ipc::sys_dup" + .asciz "kernel::ipc::sys_dup2" + .asciz "kernel::ipc::futex" + .asciz "kernel::ipc::get_robust_list" + .asciz "kernel::task::cpu::do_exit" + .asciz "kernel::task::cpu::do_suspend" + .asciz "kernel::task::cpu::get_ppid" + .asciz "kernel::task::cpu::clone" + .asciz "kernel::task::cpu::do_exec" + .asciz "kernel::task::cpu::wait4" + .asciz "kernel::task::cpu::do_brk" + .asciz "kernel::task::cpu::prlimit64" + .asciz "virtio_drivers::device::input::VirtIOInput::pop_pending_event" + .asciz "virtio_drivers::device::input::VirtIOInput::new" + .asciz "lru::LruCache::capturing_put" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::allocate_in" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::ops::drop::Drop>::drop" + .asciz "kernel::driver::block_device::GenericBlockDevice::new" + .asciz "::read" + .asciz "::write" + .asciz "kernel::driver::block_device::VirtIOBlkWrapper::new" + .asciz "::read_block" + .asciz "::write_block" + .asciz "kernel::interrupt::init_plic" + .asciz "kernel::interrupt::register_device_to_plic" + .asciz "kernel::net::addr::socket_addr_resolution" + .asciz "__sys_umount" + .asciz "__sys_openat" + .asciz "__sys_close" + .asciz "__sys_getdents" + .asciz "__sys_read" + .asciz "__sys_write" + .asciz "__sys_getcwd" + .asciz "__sys_fchdir" + .asciz "__sys_lseek" + .asciz "__sys_writev" + .asciz "__sys_pwrite" + .asciz "__sys_fstateat" + .asciz "__sync" + .asciz "__unmask" + .asciz "__sys_setxattr" + .asciz "__sys_fsetxattr" + .asciz "__sys_llistxattr" + .asciz "__sys_removexattr" + .asciz "__sys_fremovexattr" + .asciz "__sys_symlinkat" + .asciz "__sched_setaffinity" + .asciz "__sched_setscheduler" + .asciz "__shmctl" + .asciz "__sigprocmask" + .asciz "__signal_return" + .asciz "__sigsuspend" + .asciz "__sys_dup2" + .asciz "__get_robust_list" + .asciz "__msync" + .asciz "__membarrier" + .asciz "::fmt" + .asciz "__accept" + .asciz "__get_peer_name" + .asciz "__socket_pair" + .asciz "kernel::system::uname" + .asciz "__uname" + .asciz "__do_exit" + .asciz "__set_sid" + .asciz "__get_pid" + .asciz "__get_ppid" + .asciz "__geteuid" + .asciz "__get_time_of_day" + .asciz "__clock_get_time" + .asciz "__clock_getres" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::Write::write_char" + .asciz "core::fmt::Write::write_fmt" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place>" + .asciz "::fmt" + .asciz "::write_char" + .asciz "::write_str" + .asciz "fatfs::boot_sector::BootSector::deserialize" + .asciz "fatfs::boot_sector::BootSector::validate" + .asciz "fatfs::boot_sector::BiosParameterBlock::validate_total_sectors" + .asciz "fatfs::boot_sector::BiosParameterBlock::validate_total_clusters" + .asciz "fatfs::boot_sector::BiosParameterBlock::validate_sectors_per_fat" + .asciz " as vfscore::fstype::VfsFsType>::mount" + .asciz " as vfscore::fstype::VfsFsType>::fs_flag" + .asciz " as vfscore::fstype::VfsFsType>::fs_name" + .asciz " as vfscore::fstype::VfsFsType>::kill_sb" + .asciz " as vfscore::fstype::VfsFsType>::mount" + .asciz " as vfscore::fstype::VfsFsType>::kill_sb" + .asciz " as vfscore::fstype::VfsFsType>::fs_name" + .asciz " as vfscore::fstype::VfsFsType>::fs_flag" + .asciz " as vfscore::fstype::VfsFsType>::fs_name" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::flush" + .asciz "vfscore::file::VfsFile::flush" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::read_at" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::write_at" + .asciz "vfscore::file::VfsFile::write_at" + .asciz "vfscore::inode::VfsInode::list_xattr" + .asciz "vfscore::inode::VfsInode::update_time" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::rmdir" + .asciz "vfscore::inode::VfsInode::create" + .asciz "vfscore::inode::VfsInode::lookup" + .asciz "vfscore::inode::VfsInode::symlink" + .asciz "vfscore::inode::VfsInode::readlink" + .asciz "vfscore::inode::VfsInode::truncate" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz "::_init" + .asciz "::_put" + .asciz "::_read" + .asciz "::fmt" + .asciz "kernel::fs::file::kernel_file::KernelFile::new" + .asciz "::read" + .asciz "::write" + .asciz "::read_at" + .asciz "::write_at" + .asciz "::flush" + .asciz "::fsync" + .asciz "::seek" + .asciz "::get_attr" + .asciz "::ioctl" + .asciz "::set_open_flag" + .asciz "::get_open_flag" + .asciz "::inode" + .asciz "::readdir" + .asciz "::truncate" + .asciz "::is_readable" + .asciz "::is_writable" + .asciz "::is_append" + .asciz "kernel::fs::proc::filesystem::SystemSupportFS::serialize" + .asciz "::read_at" + .asciz "::get_attr" + .asciz "::write_at" + .asciz "::get_super_block" + .asciz "::node_perm" + .asciz "::set_attr" + .asciz "::get_attr" + .asciz "::inode_type" + .asciz "::get_attr" + .asciz "kernel::fs::proc::init_procfs" + .asciz "kernel::fs::init_filesystem" + .asciz "::write_str" + .asciz "kernel::fs::user_path_at" + .asciz "kernel::fs::read_all" + .asciz "::fmt" + .asciz "kernel::ipc::pipe::init_pipefs" + .asciz "kernel::ipc::pipe::make_pipe_file" + .asciz "::read" + .asciz "::write" + .asciz "::dentry" + .asciz "::dentry" + .asciz "::inode" + .asciz "::is_readable" + .asciz "::is_writable" + .asciz "::poll" + .asciz "::poll" + .asciz "::read_at" + .asciz "::write_at" + .asciz "::poll" + .asciz "::get_super_block" + .asciz "::node_perm" + .asciz "::readlink" + .asciz "::set_attr" + .asciz "::get_attr" + .asciz "::list_xattr" + .asciz "::inode_type" + .asciz "::update_time" + .asciz "::drop" + .asciz "kernel::trap::interrupt::timer_interrupt_handler" + .asciz "kernel::init_machine_info" + .asciz "__sys_ftruncate" + .asciz "__sys_renameat2" + .asciz "__send_file" + .asciz "__copy_file_range" + .asciz "__faccessat" + .asciz "__fchown" + .asciz "__sys_listxattr" + .asciz "__sys_linkat" + .asciz "kernel::fs::poll::ppoll" + .asciz "__ppoll" + .asciz "::create" + .asciz "::link" + .asciz "::symlink" + .asciz "::lookup" + .asciz "::rmdir" + .asciz "::truncate" + .asciz "::rename_to" + .asciz "__sigaction" + .asciz "__sys_dup" + .asciz "__futex" + .asciz "__set_pgid" + .asciz "__get_tid" + .asciz "__prlimit64" + .asciz "__times" + .asciz "__nanosleep" + .asciz "__getitimer" + .asciz "__clock_nanosleep" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::fmt" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "<() as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place<()>" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "::fmt" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz " as core::fmt::Debug>::fmt" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz " as vfscore::superblock::VfsSuperBlock>::super_type" + .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz "::write_at" + .asciz "::flush" + .asciz "::fsync" + .asciz "::read_at" + .asciz "::read_at" + .asciz "::relocate" + .asciz "kernel::fs::basic::sys_mount" + .asciz "kernel::fs::basic::sys_umount" + .asciz "kernel::fs::basic::sys_openat" + .asciz "kernel::fs::basic::sys_getdents" + .asciz "kernel::fs::basic::sys_truncate" + .asciz "kernel::fs::basic::sys_ftruncate" + .asciz "kernel::fs::basic::sys_read" + .asciz "kernel::fs::basic::sys_write" + .asciz "kernel::fs::basic::sys_getcwd" + .asciz "kernel::fs::basic::sys_chdir" + .asciz "kernel::fs::basic::sys_fchdir" + .asciz "kernel::fs::basic::sys_mkdirat" + .asciz "kernel::fs::basic::sys_lseek" + .asciz "kernel::fs::basic::sys_writev" + .asciz "kernel::fs::basic::sys_readv" + .asciz "kernel::fs::basic::sys_pread" + .asciz "kernel::fs::basic::sys_pwrite" + .asciz "kernel::fs::basic::sys_fstateat" + .asciz "kernel::fs::basic::sys_fstat" + .asciz "kernel::fs::basic::sys_fstatfs" + .asciz "kernel::fs::basic::sys_statfs" + .asciz "kernel::fs::basic::sys_renameat" + .asciz "kernel::fs::basic::sys_renameat2" + .asciz "kernel::fs::basic::send_file" + .asciz "kernel::fs::basic::fsync" + .asciz "kernel::fs::basic::copy_file_range" + .asciz "kernel::fs::ext::sys_setxattr" + .asciz "kernel::fs::ext::sys_fsetxattr" + .asciz "kernel::fs::ext::sys_getxattr" + .asciz "kernel::fs::ext::sys_fgetxattr" + .asciz "kernel::fs::ext::sys_flistxattr" + .asciz "kernel::fs::ext::sys_fremovexattr" + .asciz "kernel::fs::link::sys_linkat" + .asciz "kernel::fs::link::sys_unlinkat" + .asciz "kernel::fs::link::sys_symlinkat" + .asciz "kernel::fs::link::sys_readlinkat" + .asciz "smpscheduler::fifo::FifoSmpScheduler<_,T,L,H>::new" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::array::::fmt" + .asciz "core::array::::fmt" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed" + .asciz "dynfs::dir::DynFsDirInode::add_manually" + .asciz "dynfs::dir::DynFsDirInode::remove_manually" + .asciz "fatfs::fs::FileSystem::alloc_cluster" + .asciz "fatfs::fs::FileSystem::set_dirty_flag" + .asciz "fatfs::fs::FileSystem::free_cluster_chain" + .asciz "fatfs::fs::FileSystem::new" + .asciz "fatfs::fs::FileSystem::stats" + .asciz "fatfs::fs::FileSystem::root_dir" + .asciz "fatfs::fs::FileSystem::fat_slice" + .asciz "fatfs::io::Read::read_exact" + .asciz "fatfs::io::Write::write_all" + .asciz "fatfs::io::Write::write_all" + .asciz "fatfs::file::File::set_first_cluster" + .asciz "fatfs::file::File::abs_pos" + .asciz "fatfs::file::File::truncate" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as fatfs::io::Read>::read" + .asciz " as fatfs::io::Seek>::seek" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as fatfs::io::Write>::write" + .asciz " as fatfs::io::Read>::read" + .asciz " as fatfs::io::Seek>::seek" + .asciz " as fatfs::io::Write>::write" + .asciz " as core::clone::Clone>::clone" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::flush" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::read_at" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::write_at" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as vfscore::file::VfsFile>::readdir" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::rmdir" + .asciz " as vfscore::inode::VfsInode>::create" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::symlink" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::file::VfsFile>::poll" + .asciz " as vfscore::file::VfsFile>::flush" + .asciz " as vfscore::file::VfsFile>::fsync" + .asciz " as vfscore::file::VfsFile>::ioctl" + .asciz " as vfscore::file::VfsFile>::read_at" + .asciz " as vfscore::file::VfsFile>::write_at" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" + .asciz " as vfscore::file::VfsFile>::poll" + .asciz " as vfscore::file::VfsFile>::read_at" + .asciz " as vfscore::file::VfsFile>::write_at" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz "::read_at" + .asciz "::poll" + .asciz "::read_at" + .asciz "::write_at" + .asciz "::ioctl" + .asciz "kernel::driver::gpu::VirtIOGpuWrapper::new" + .asciz "::hand_irq" + .asciz "::flush" + .asciz "kernel::driver::input::VirtIOInputDriver::from_addr" + .asciz "::is_empty" + .asciz "::read_event_with_block" + .asciz "::read_event_without_block" + .asciz "::hand_irq" + .asciz "::put" + .asciz "::get" + .asciz "::put_bytes" + .asciz "::have_data_to_get" + .asciz "::hand_irq" + .asciz "::read_at" + .asciz "::get_attr" + .asciz "kernel::interrupt::record::write_irq_info" + .asciz "kernel::interrupt::record::interrupts_info" + .asciz "kernel::memory::frame::init_frame_allocator" + .asciz "::drop" + .asciz "alloc_frames" + .asciz "free_frames" + .asciz "kernel::memory::frame::frame_alloc" + .asciz "kernel::memory::frame::frames_alloc" + .asciz "kernel::memory::frame::frame_alloc_contiguous" + .asciz "kernel::memory::manager::FrameRefManager::dec_ref" + .asciz "kernel::device::input::sys_event_get" + .asciz "::fmt" + .asciz "core::ptr::drop_in_place<&u32>" + .asciz "tracer::compiler::InstructionSp::try_new" + .asciz "tracer::compiler::check_sd_ra" + .asciz "tracer::compiler::is_caddi" + .asciz "tracer::compiler::is_caddi16sp" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "tracer::utils::read_instruction" + .asciz "tracer::utils::read_instruction_short" + .asciz "tracer::utils::read_value" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&usize>" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&&str>" + .asciz "core::ptr::drop_in_place<&xmas_elf::program::Type>" + .asciz "core::ptr::drop_in_place<&xmas_elf::sections::ShType>" + .asciz "core::ptr::drop_in_place<&xmas_elf::dynamic::Tag>" + .asciz "core::ptr::drop_in_place<&xmas_elf::dynamic::Tag>" + .asciz "core::ptr::drop_in_place<&xmas_elf::sections::CompressionType>" + .asciz "core::panicking::assert_failed" + .asciz "xmas_elf::ElfFile::new" + .asciz "xmas_elf::ElfFile::get_shstr" + .asciz "xmas_elf::ElfFile::get_dyn_string" + .asciz "xmas_elf::ElfFile::find_section_by_name" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&str>" + .asciz "xmas_elf::sections::parse_section_header" + .asciz "xmas_elf::sections::SectionHeader::get_data" + .asciz "xmas_elf::sections::SectionHeader::raw_data" + .asciz "::fmt" + .asciz "xmas_elf::program::parse_program_header" + .asciz "::next" + .asciz "xmas_elf::program::ProgramHeader::get_type" + .asciz "xmas_elf::program::ProgramHeader::get_data" + .asciz "xmas_elf::program::ProgramHeader32::get_data" + .asciz "xmas_elf::program::ProgramHeader32::raw_data" + .asciz "xmas_elf::program::ProgramHeader64::get_data" + .asciz "xmas_elf::program::ProgramHeader64::raw_data" + .asciz "::get_name" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz "zero::read_str" + .asciz "talc::Talc::malloc" + .asciz "talc::Talc::free" + .asciz "talc::Talc::init" + .asciz "talc::talck::Talck::talc" + .asciz "::alloc" + .asciz "::dealloc" + .asciz "plic::write" + .asciz "plic::read" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz ">::from" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz ">::from" + .asciz "::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "::write" + .asciz "::flush" + .asciz "::read" + .asciz "::seek" + .asciz "fatfs::dir::split_path" + .asciz "fatfs::dir::lfn_checksum" + .asciz "fatfs::dir::LongNameBuilder::into_buf" + .asciz "fatfs::dir::LongNameBuilder::process" + .asciz "fatfs::dir::LongNameBuilder::validate_chksum" + .asciz "fatfs::dir::LfnEntriesGenerator::new" + .asciz "::next" + .asciz "::size_hint" + .asciz "fatfs::dir::ShortNameGenerator::new" + .asciz "fatfs::dir::ShortNameGenerator::copy_short_name_part" + .asciz "fatfs::dir::ShortNameGenerator::add_existing" + .asciz "fatfs::dir::ShortNameGenerator::generate" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::array::::fmt" + .asciz "core::array::::fmt" + .asciz "core::array::::fmt" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz "fatfs::fs::FsInfoSector::validate_and_fix" + .asciz "::fmt" + .asciz "core::str::::trim_matches" + .asciz "fatfs::boot_sector::BiosParameterBlock::root_dir_sectors" + .asciz "fatfs::boot_sector::BiosParameterBlock::first_data_sector" + .asciz "fatfs::boot_sector::BiosParameterBlock::total_clusters" + .asciz "fatfs::boot_sector::BiosParameterBlock::clusters_from_bytes" + .asciz "::default" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "fatfs::dir_entry::ShortName::new" + .asciz "fatfs::dir_entry::ShortName::as_bytes" + .asciz "fatfs::dir_entry::DirFileEntryData::new" + .asciz "fatfs::dir_entry::DirFileEntryData::renamed" + .asciz "fatfs::dir_entry::DirFileEntryData::lowercase_name" + .asciz "fatfs::dir_entry::DirEntryEditor::set_modified" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "core::ptr::drop_in_place>" + .asciz "virtio_drivers::transport::mmio::MmioTransport::new" + .asciz "virtio_drivers::transport::mmio::MmioTransport::vendor_id" + .asciz "::device_type" + .asciz "::read_device_features" + .asciz "::write_driver_features" + .asciz "::max_queue_size" + .asciz "::notify" + .asciz "::set_status" + .asciz "::set_guest_page_size" + .asciz "::queue_set" + .asciz "::queue_unset" + .asciz "::queue_used" + .asciz "::ack_interrupt" + .asciz "::drop" + .asciz "::fmt" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place>>" + .asciz "::fmt" + .asciz "bitflags::parser::to_writer" + .asciz "bitflags::parser::to_writer" + .asciz "bitflags::parser::to_writer" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::LowerHex>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz "core::panicking::assert_failed" + .asciz "virtio_drivers::queue::queue_part_sizes" + .asciz "::next" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::type_id" + .asciz "core::ptr::drop_in_place" + .asciz "alloc::collections::vec_deque::VecDeque::grow" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "::mac_address" + .asciz "::recycle_rx_buffer" + .asciz "::transmit" + .asciz "::receive" + .asciz "::alloc_tx_buffer" + .asciz "::packet_mut" + .asciz "::packet_len" + .asciz "::read_time" + .asciz "::set_time" + .asciz "::enable_irq" + .asciz "::disable_irq" + .asciz "::clear_irq" + .asciz "::read_alarm" + .asciz "::set_alarm" + .asciz "::clear_alarm" + .asciz "::alarm_status" + .asciz "::is_irq_enabled" + .asciz "::fmt" + .asciz ">::from" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "time::date_time::DateTime::checked_to_offset" + .asciz "time::date::Date::from_julian_day_unchecked" + .asciz "time::date::Date::month_day" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "time::offset_date_time::OffsetDateTime::to_offset" + .asciz "time::offset_date_time::OffsetDateTime::from_unix_timestamp_nanos" + .asciz "time::offset_date_time::OffsetDateTime::month" + .asciz "time::offset_date_time::OffsetDateTime::day" + .asciz "time::expect_failed" + .asciz "time::expect_failed::panic_cold_display" + .asciz "core::fmt::num::::fmt" + .asciz "netcore::tcp::TcpSocket::connect" + .asciz "netcore::tcp::TcpSocket::bind" + .asciz "netcore::tcp::TcpSocket::listen" + .asciz "netcore::tcp::TcpSocket::accept" + .asciz "netcore::tcp::TcpSocket::shutdown" + .asciz "netcore::tcp::TcpSocket::recv" + .asciz "netcore::tcp::TcpSocket::send" + .asciz "netcore::tcp::TcpSocket::poll" + .asciz "netcore::tcp::TcpSocket::poll_connect" + .asciz "::drop" + .asciz "netcore::tcp::get_ephemeral_port" + .asciz "core::ptr::drop_in_place" + .asciz "::poll" + .asciz "netcore::interface::SocketSetWrapper::new_udp_socket" + .asciz "netcore::interface::SocketSetWrapper::with_socket" + .asciz "netcore::interface::SocketSetWrapper::with_socket" + .asciz "netcore::interface::SocketSetWrapper::with_socket" + .asciz "netcore::interface::SocketSetWrapper::with_socket" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::remove" + .asciz "core::ptr::drop_in_place" + .asciz "::receive" + .asciz "::consume" + .asciz "::preprocess" + .asciz "::consume" + .asciz "::consume" + .asciz "::consume" + .asciz "netcore::device::NetDeviceWrapper::bench_transmit_bandwidth" + .asciz "smoltcp::socket::tcp::Socket::new" + .asciz "smoltcp::socket::tcp::Socket::connect" + .asciz "smoltcp::socket::tcp::Socket::dispatch" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "core::ptr::drop_in_place>" + .asciz "netcore::udp::UdpSocket::new" + .asciz "netcore::udp::UdpSocket::local_addr" + .asciz "netcore::udp::UdpSocket::peer_addr" + .asciz "netcore::udp::UdpSocket::bind" + .asciz "netcore::udp::UdpSocket::send_to" + .asciz "netcore::udp::UdpSocket::recv_from" + .asciz "netcore::udp::UdpSocket::connect" + .asciz "netcore::udp::UdpSocket::send" + .asciz "netcore::udp::UdpSocket::shutdown" + .asciz "netcore::udp::UdpSocket::poll" + .asciz "netcore::udp::UdpSocket::send_impl" + .asciz "::drop" + .asciz "core::ptr::drop_in_place>>" + .asciz "::default" + .asciz "netcore::listen_table::ListenTable::new" + .asciz "netcore::listen_table::ListenTable::listen" + .asciz "netcore::listen_table::ListenTable::unlisten" + .asciz "netcore::listen_table::ListenTable::can_accept" + .asciz "netcore::listen_table::ListenTable::accept" + .asciz "netcore::listen_table::ListenTable::incoming_tcp_packet" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "core::ptr::drop_in_place" + .asciz "smoltcp::iface::interface::InterfaceInner::dispatch_ip" + .asciz "smoltcp::iface::interface::Interface::poll" + .asciz "smoltcp::socket::dns::Socket::dispatch" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place<&bool>" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "smoltcp::wire::ipv4::Repr::emit" + .asciz "smoltcp::wire::ipv4::Repr::parse" + .asciz "::fmt" + .asciz "::fmt" + .asciz " as core::iter::traits::iterator::Iterator>::try_fold" + .asciz ">::from" + .asciz "smoltcp::wire::icmpv4::Repr::parse" + .asciz "smoltcp::socket::udp::Socket::send_slice" + .asciz "smoltcp::iface::socket_set::SocketSet::add" + .asciz "smoltcp::iface::socket_set::SocketSet::add" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "<&mut T as core::fmt::Display>::fmt" + .asciz "smoltcp::wire::arp::Repr::emit" + .asciz "smoltcp::wire::dns::Repr::emit" + .asciz "smoltcp::storage::packet_buffer::PacketBuffer::enqueue" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&u16>" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed" + .asciz "alloc::collections::vec_deque::VecDeque::grow" + .asciz "smoltcp::iface::socket_meta::Meta::egress_permitted" + .asciz "netcore::interface::SocketSetWrapper::new" + .asciz "netcore::init_net" + .asciz "netcore::poll_interfaces" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::str::iter::SplitInternal

::next_back" + .asciz "core::error::Error::description" + .asciz "core::error::Error::source" + .asciz "core::error::Error::source" + .asciz "core::error::Error::provide" + .asciz "core::error::Error::provide" + .asciz "alloc::alloc::exchange_malloc" + .asciz "::fmt" + .asciz "::description" + .asciz "::fmt" + .asciz "vfscore::path::VfsPath::new" + .asciz "vfscore::path::VfsPath::open" + .asciz "vfscore::path::VfsPath::create" + .asciz "vfscore::path::VfsPath::get_parent" + .asciz "vfscore::path::VfsPath::parent" + .asciz "vfscore::path::VfsPath::exists" + .asciz "vfscore::path::VfsPath::filename" + .asciz "vfscore::path::VfsPath::mount" + .asciz "vfscore::path::VfsPath::umount" + .asciz "vfscore::path::VfsPath::truncate" + .asciz "vfscore::path::VfsPath::symlink" + .asciz "vfscore::path::VfsPath::link" + .asciz "vfscore::path::VfsPath::rmdir" + .asciz "vfscore::path::VfsPath::unlink" + .asciz "vfscore::path::VfsPath::rename_to" + .asciz "vfscore::path::VfsPath::set_xattr" + .asciz "vfscore::path::VfsPath::get_xattr" + .asciz "vfscore::path::checkout_write_perm" + .asciz "vfscore::path::check_same_fs" + .asciz "vfscore::path::real_dentry_down" + .asciz "vfscore::path::real_dentry_up" + .asciz "vfscore::path::print_fs_tree" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz ">::from" + .asciz "vfscore::utils::VfsInodeMode::from" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::error::Error::cause" + .asciz "core::error::Error::type_id" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz "::fmt" + .asciz "::fmt" + .asciz "core::ptr::drop_in_place<&i32>" + .asciz "core::ptr::drop_in_place<&isize>" + .asciz "core::ptr::drop_in_place" + .asciz "core::array::::fmt" + .asciz "core::error::Error::cause" + .asciz "core::error::Error::type_id" + .asciz "core::panicking::assert_failed" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "::i_insert" + .asciz "vfscore::error:: for pconst::consts::LinuxErrno>::from" + .asciz "::i_mount" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "pconst::consts::syscall_name" + .asciz ">::try_from" + .asciz "pconst::consts:: for isize>::from" + .asciz "::fmt" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz "core::ptr::drop_in_place<&i32>" + .asciz "core::ptr::drop_in_place<&isize>" + .asciz "core::ptr::drop_in_place<&usize>" + .asciz "core::ptr::drop_in_place<&core::option::Option>" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz ">::from" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&[core::option::Option; 64]>" + .asciz "pconst::signal::SignalHandlers::clear" + .asciz "pconst::signal::SignalHandlers::get_action" + .asciz "pconst::signal::SignalHandlers::get_action_ref" + .asciz "pconst::signal::SignalHandlers::set_action" + .asciz "pconst::signal::SignalReceivers::get_one_signal" + .asciz "pconst::signal::SignalReceivers::have_signal" + .asciz "pconst::signal::SignalReceivers::have_signal_with_number" + .asciz ">>::into" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "::fmt" + .asciz "smoltcp::socket::tcp::RttEstimator::retransmission_timeout" + .asciz "smoltcp::socket::tcp::RttEstimator::on_send" + .asciz "smoltcp::socket::tcp::RttEstimator::on_retransmit" + .asciz "smoltcp::socket::tcp::Socket::reset" + .asciz "smoltcp::socket::tcp::Socket::close" + .asciz "smoltcp::socket::tcp::Socket::send_slice" + .asciz "smoltcp::socket::tcp::Socket::recv_slice" + .asciz "smoltcp::socket::tcp::Socket::set_state" + .asciz "smoltcp::socket::tcp::Socket::rst_reply" + .asciz "smoltcp::socket::tcp::Socket::ack_reply" + .asciz "smoltcp::socket::tcp::Socket::accepts" + .asciz "smoltcp::socket::tcp::Socket::process" + .asciz "smoltcp::socket::tcp::Socket::seq_to_transmit" + .asciz "smoltcp::socket::tcp::Socket::ack_to_transmit" + .asciz "smoltcp::socket::tcp::Socket::window_to_update" + .asciz "::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "smoltcp::socket::dns::DnsQuery::set_state" + .asciz "smoltcp::socket::dns::Socket::process" + .asciz "smoltcp::socket::dns::eq_names" + .asciz "smoltcp::socket::dns::copy_name" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz " as core::iter::traits::iterator::Iterator>::fold" + .asciz "::fmt" + .asciz ">::add" + .asciz ">::sub" + .asciz "::sub" + .asciz "smoltcp::wire::tcp::TcpOption::parse" + .asciz "smoltcp::wire::tcp::TcpOption::emit" + .asciz "smoltcp::wire::tcp::Repr::parse" + .asciz "smoltcp::wire::tcp::Repr::buffer_len" + .asciz "smoltcp::wire::tcp::Repr::emit" + .asciz "::fmt" + .asciz "::fmt" + .asciz "smoltcp::iface::interface::ethernet::::process_ethernet" + .asciz "smoltcp::iface::interface::ipv4::::process_ipv4" + .asciz "smoltcp::iface::interface::ipv4::::icmpv4_reply" + .asciz "smoltcp::iface::interface::InterfaceInner::get_source_address" + .asciz "smoltcp::iface::interface::InterfaceInner::get_source_address_ipv4" + .asciz "smoltcp::iface::interface::InterfaceInner::check_ip_addrs" + .asciz "smoltcp::iface::interface::InterfaceInner::process_ip" + .asciz "smoltcp::iface::interface::InterfaceInner::is_broadcast" + .asciz "smoltcp::iface::interface::InterfaceInner::process_udp" + .asciz "smoltcp::iface::interface::InterfaceInner::route" + .asciz "smoltcp::iface::interface::InterfaceInner::has_neighbor" + .asciz "smoltcp::iface::interface::InterfaceInner::flush_cache" + .asciz "smoltcp::wire::udp::Packet<&T>::payload" + .asciz "::fmt" + .asciz "core::ptr::drop_in_place<&smoltcp::storage::packet_buffer::PacketMetadata>" + .asciz "core::ptr::drop_in_place<&smoltcp::storage::packet_buffer::PacketMetadata>" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz "core::ptr::drop_in_place<&alloc::vec::Vec>" + .asciz "core::ptr::drop_in_place<&smoltcp::wire::ip::Address>" + .asciz "core::ptr::drop_in_place<&smoltcp::iface::route::Route>" + .asciz "core::ptr::drop_in_place<&smoltcp::iface::neighbor::Neighbor>" + .asciz "core::ptr::drop_in_place<&smoltcp::storage::assembler::Contig>" + .asciz "core::ptr::drop_in_place<&smoltcp::iface::socket_set::SocketStorage>" + .asciz "core::ptr::drop_in_place<&core::option::Option<(u32,u32)>>" + .asciz "core::ptr::drop_in_place<&core::option::Option>" + .asciz "core::ptr::drop_in_place<&smoltcp::storage::packet_buffer::PacketMetadata<()>>" + .asciz "smoltcp::wire::icmpv4::Repr::parse" + .asciz "smoltcp::wire::icmpv4::Repr::emit" + .asciz ">::from" + .asciz "smoltcp::iface::neighbor::Cache::fill" + .asciz "smoltcp::iface::neighbor::Cache::lookup" + .asciz "smoltcp::socket::udp::Socket::recv_slice" + .asciz "smoltcp::socket::udp::Socket::process" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "smoltcp::iface::route::Routes::add_default_ipv4_route" + .asciz "smoltcp::iface::route::Routes::lookup" + .asciz "smoltcp::wire::ip::Version::of_packet" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "smoltcp::wire::ip::Cidr::new" + .asciz "::fmt" + .asciz "::fmt" + .asciz "smoltcp::wire::HardwareAddress::ethernet_or_panic" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "smoltcp::iface::ip_packet::IpPacket::emit_payload" + .asciz "smoltcp::storage::packet_buffer::PacketBuffer::enqueue" + .asciz "smoltcp::storage::packet_buffer::PacketBuffer::enqueue" + .asciz "smoltcp::storage::packet_buffer::PacketBuffer::enqueue" + .asciz "smoltcp::storage::packet_buffer::PacketBuffer::dequeue" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::enqueue_slice" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_slice" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::write_unallocated" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "smoltcp::wire::ipv4::Address::from_bytes" + .asciz "::fmt" + .asciz "smoltcp::wire::ipv4::Repr::parse" + .asciz "smoltcp::wire::ipv4::Repr::emit" + .asciz ">::from" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "::fmt" + .asciz "smoltcp::wire::arp::Repr::parse" + .asciz "smoltcp::wire::ethernet::Address::from_bytes" + .asciz "::fmt" + .asciz "smoltcp::iface::socket_meta::Meta::neighbor_missing" + .asciz "smoltcp::socket::icmp::Socket::accepts" + .asciz "smoltcp::socket::icmp::Socket::process" + .asciz "smoltcp::wire::ip::checksum::data" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place<&&mut alloc::collections::vec_deque::VecDeque>>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "smoltcp::wire::dns::Packet::rcode" + .asciz "smoltcp::wire::dns::Question::parse" + .asciz "smoltcp::wire::dns::Question::emit" + .asciz "smoltcp::wire::dns::Record::parse" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "smoltcp::storage::assembler::Assembler::add" + .asciz "smoltcp::wire::udp::Packet::verify_checksum" + .asciz "smoltcp::wire::udp::Repr::emit" + .asciz "::fmt" + .asciz "smoltcp::iface::socket_set::SocketSet::add::put" + .asciz "smoltcp::iface::socket_set::SocketSet::remove" + .asciz "smoltcp::iface::socket_set::SocketSet::items" + .asciz "smoltcp::iface::socket_set::SocketSet::items_mut" + .asciz "smoltcp::socket::raw::Socket::process" + .asciz "::before_lock" + .asciz "::after_lock" + .asciz "arch::riscv::activate_paging_mode" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&u32>" + .asciz "::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "::print" + .asciz "preprint::__private_print" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "basemachine::machine_info_from_dtb" + .asciz "core::str::iter::SplitInternal

::next" + .asciz "fdt::node::FdtNode::reg" + .asciz "fdt::node::FdtNode::compatible" + .asciz "fdt::node::FdtNode::cell_sizes" + .asciz "fdt::node::FdtNode::interrupts" + .asciz "fdt::node::find_node" + .asciz "fdt::node::skip_current_node" + .asciz "fdt::node::NodeProperty::parse" + .asciz "fdt::node::skip_4_aligned" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz "fdt::Fdt::from_ptr" + .asciz "fdt::Fdt::cpus" + .asciz "fdt::Fdt::root" + .asciz "fdt::Fdt::find_node" + .asciz "fdt::Fdt::find_phandle" + .asciz "fdt::Fdt::all_nodes" + .asciz "fdt::Fdt::str_at_offset" + .asciz "::fmt" + .asciz "fdt::standard_nodes::Root::model" + .asciz "fdt::standard_nodes::Aliases::resolve" + .asciz "fdt::standard_nodes::Compatible::first" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz "core::panicking::assert_failed" + .asciz "fdt::parsing::CStr::new" + .asciz "fdt::parsing::CStr::as_str" + .asciz "fdt::parsing::FdtData::u32" + .asciz "fdt::parsing::FdtData::u64" + .asciz "fdt::parsing::FdtData::skip" + .asciz "fdt::parsing::FdtData::peek_u32" + .asciz "syscall_table::Service::handle" + .asciz "::from" + .asciz "::from" + .asciz "::from" + .asciz "::from" + .asciz "::from" + .asciz "inventory::Registry::submit" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&u32>" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "::enabled" + .asciz "::log" + .asciz "::flush" + .asciz "log::set_logger" + .asciz "log::__private_api::log" + .asciz "::fmt" + .asciz "core::fmt::Write::write_fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::capacity_overflow" + .asciz "alloc::alloc::handle_alloc_error" + .asciz "__rdl_oom" + .asciz "alloc::fmt::format::format_inner" + .asciz "alloc::string::String::from_utf8_lossy" + .asciz "alloc::string::String::push" + .asciz "::clone" + .asciz "::write_str" + .asciz "::write_char" + .asciz "alloc::vec::Vec::remove::assert_failed" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place<&core::iter::adapters::copied::Copied>>" + .asciz "core::ptr::drop_in_place" + .asciz "core::num::from_str_radix" + .asciz " as core::fmt::Debug>::fmt" + .asciz "::type_id" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "core::cell::panic_already_borrowed" + .asciz "core::cell::panic_already_mutably_borrowed" + .asciz "core::char::methods::::escape_debug_ext" + .asciz " as core::fmt::Write>::write_str" + .asciz " as core::fmt::Write>::write_str" + .asciz " as core::fmt::Write>::write_str" + .asciz " as core::fmt::Write>::write_str" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "core::option::expect_failed" + .asciz "core::panicking::panic_fmt" + .asciz "core::panicking::panic_nounwind_fmt" + .asciz "core::panicking::panic" + .asciz "core::panicking::panic_bounds_check" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed_inner" + .asciz "core::result::unwrap_failed" + .asciz "::write_str" + .asciz "::write_char" + .asciz "core::fmt::builders::DebugStruct::field" + .asciz "core::fmt::builders::DebugStruct::finish" + .asciz "core::fmt::builders::DebugTuple::field" + .asciz "core::fmt::builders::DebugTuple::finish" + .asciz "core::fmt::builders::DebugInner::entry" + .asciz "core::fmt::builders::DebugSet::entry" + .asciz "core::fmt::builders::DebugList::entry" + .asciz "core::fmt::builders::DebugList::finish" + .asciz "core::fmt::Write::write_char" + .asciz "core::fmt::Write::write_char" + .asciz "core::fmt::Write::write_char" + .asciz "core::fmt::Write::write_char" + .asciz "core::fmt::Write::write_fmt" + .asciz "core::fmt::Write::write_fmt" + .asciz "core::fmt::Write::write_fmt" + .asciz "core::fmt::Write::write_fmt" + .asciz "core::fmt::Write::write_fmt" + .asciz "::fmt" + .asciz "core::fmt::write" + .asciz "core::fmt::Formatter::pad_integral" + .asciz "core::fmt::Formatter::pad_integral::write_prefix" + .asciz "core::fmt::Formatter::pad" + .asciz "core::fmt::Formatter::write_str" + .asciz "::write_str" + .asciz "core::fmt::Formatter::write_fmt" + .asciz "::write_fmt" + .asciz "core::fmt::Formatter::debug_struct" + .asciz "core::fmt::Formatter::debug_struct_field1_finish" + .asciz "core::fmt::Formatter::debug_struct_field2_finish" + .asciz "core::fmt::Formatter::debug_struct_field3_finish" + .asciz "core::fmt::Formatter::debug_struct_field4_finish" + .asciz "core::fmt::Formatter::debug_struct_field5_finish" + .asciz "core::fmt::Formatter::debug_struct_fields_finish" + .asciz "core::fmt::Formatter::debug_tuple" + .asciz "core::fmt::Formatter::debug_tuple_field1_finish" + .asciz "core::fmt::Formatter::debug_tuple_field2_finish" + .asciz "core::fmt::Formatter::debug_list" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "core::fmt::pointer_fmt_inner" + .asciz "core::slice::memchr::memchr_aligned" + .asciz "core::slice::memchr::memrchr" + .asciz "core::slice::index::slice_start_index_len_fail" + .asciz "core::slice::index::slice_end_index_len_fail" + .asciz "core::slice::index::slice_index_order_fail" + .asciz "core::slice::::copy_from_slice::len_mismatch_fail" + .asciz "core::str::converts::from_utf8" + .asciz "core::str::count::do_count_chars" + .asciz "::fmt" + .asciz "core::str::pattern::StrSearcher::new" + .asciz "::next" + .asciz "core::str::slice_error_fail" + .asciz "core::str::slice_error_fail_rt" + .asciz "core::unicode::printable::check" + .asciz "core::unicode::printable::is_printable" + .asciz "core::num::::from_str_radix" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::imp::fmt_u64" + .asciz "core::fmt::num::imp::::fmt" + .asciz "core::fmt::num::imp::::fmt" + .asciz "core::fmt::num::imp::::fmt" + .asciz "core::fmt::num::imp::::fmt" + .asciz "core::fmt::num::imp::::fmt" + .asciz "core::fmt::num::imp::::fmt" + .asciz "core::fmt::num::imp::::fmt" + .asciz "core::fmt::num::imp::::fmt" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "<&T as core::fmt::LowerHex>::fmt" + .asciz "::fmt" + .asciz "core::unicode::unicode_data::grapheme_extend::lookup" + .asciz "compiler_builtins::mem::memcpy" + .asciz "compiler_builtins::mem::memmove" + .asciz "compiler_builtins::mem::memset" + .asciz "compiler_builtins::mem::memcmp" + .asciz "memset" + .asciz "__divti3" + .asciz "compiler_builtins::int::specialized_div_rem::u128_div_rem" + .asciz "memcmp" + .asciz "memmove" + .asciz "memcpy" + .asciz "etext" + .asciz "srodata" + .asciz "symbol_num" + .asciz "symbol_address" + .asciz "symbol_index" + .asciz "symbol_name" + .asciz "str.1.llvm.17000698678205763346" + .asciz "str.0" + .asciz "str.1" + .asciz "str.0" + .asciz "str.0.llvm.9032329141667060801" + .asciz "str.0.llvm.12830073343055868386" + .asciz "log::LOG_LEVEL_NAMES" + .asciz "core::unicode::unicode_data::grapheme_extend::SHORT_OFFSET_RUNS" + .asciz "core::unicode::unicode_data::grapheme_extend::OFFSETS" + .asciz "erodata" + .asciz "kernel::task::cpu::__syscall_260::_::__CTOR" + .asciz "sdata" + .asciz "sinit" + .asciz "kernel::task::cpu::__syscall_177::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_174::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_155::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_124::_::__CTOR" + .asciz "kernel::net::__syscall_210::_::__CTOR" + .asciz "kernel::net::__syscall_203::_::__CTOR" + .asciz "kernel::net::__syscall_201::_::__CTOR" + .asciz "kernel::memory::map::__syscall_233::_::__CTOR" + .asciz "kernel::memory::map::__syscall_215::_::__CTOR" + .asciz "kernel::ipc::__syscall_99::_::__CTOR" + .asciz "kernel::ipc::shm::__syscall_196::_::__CTOR" + .asciz "kernel::gui::__syscall_2000::_::__CTOR" + .asciz "kernel::fs::sys::cpu::__syscall_121::_::__CTOR" + .asciz "kernel::fs::proc::process::__syscall_165::_::__CTOR" + .asciz "kernel::fs::link::__syscall_78::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_10::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_9::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_8::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_6::_::__CTOR" + .asciz "kernel::fs::control::__syscall_53::_::__CTOR" + .asciz "kernel::fs::control::__syscall_29::_::__CTOR" + .asciz "kernel::fs::control::__syscall_25::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_38::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_44::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_67::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_45::_::__CTOR" + .asciz "kernel::device::input::__syscall_2002::_::__CTOR" + .asciz "kernel::timer::__syscall_103::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_221::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_220::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_94::_::__CTOR" + .asciz "kernel::net::__syscall_209::_::__CTOR" + .asciz "kernel::net::__syscall_207::_::__CTOR" + .asciz "kernel::net::__syscall_206::_::__CTOR" + .asciz "kernel::net::__syscall_204::_::__CTOR" + .asciz "kernel::net::__syscall_200::_::__CTOR" + .asciz "kernel::net::__syscall_198::_::__CTOR" + .asciz "kernel::memory::map::__syscall_222::_::__CTOR" + .asciz "kernel::ipc::__syscall_59::_::__CTOR" + .asciz "kernel::ipc::signal::__syscall_130::_::__CTOR" + .asciz "kernel::ipc::signal::__syscall_137::_::__CTOR" + .asciz "kernel::gui::__syscall_2001::_::__CTOR" + .asciz "kernel::fs::sys::info::__syscall_179::_::__CTOR" + .asciz "kernel::fs::sys::cpu::__syscall_120::_::__CTOR" + .asciz "kernel::fs::sys::cpu::__syscall_123::_::__CTOR" + .asciz "kernel::fs::sys::cpu::__syscall_118::_::__CTOR" + .asciz "kernel::fs::select::__syscall_72::_::__CTOR" + .asciz "kernel::fs::link::__syscall_35::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_15::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_13::_::__CTOR" + .asciz "kernel::fs::control::__syscall_52::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_43::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_80::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_65::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_34::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_49::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_40::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_96::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_214::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_176::_::__CTOR" + .asciz "kernel::sbi::__syscall_2003::_::__CTOR" + .asciz "kernel::net::__syscall_208::_::__CTOR" + .asciz "kernel::memory::map::__syscall_226::_::__CTOR" + .asciz "kernel::ipc::signal::__syscall_129::_::__CTOR" + .asciz "kernel::ipc::shm::__syscall_194::_::__CTOR" + .asciz "kernel::fs::sys::info::__syscall_116::_::__CTOR" + .asciz "kernel::fs::control::__syscall_88::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_82::_::__CTOR" + .asciz "kernel::timer::__syscall_114::_::__CTOR" + .asciz "kernel::timer::__syscall_113::_::__CTOR" + .asciz "kernel::timer::__syscall_169::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_175::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_173::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_172::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_157::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_93::_::__CTOR" + .asciz "kernel::system::__syscall_160::_::__CTOR" + .asciz "kernel::net::__syscall_199::_::__CTOR" + .asciz "kernel::net::__syscall_205::_::__CTOR" + .asciz "kernel::net::__syscall_202::_::__CTOR" + .asciz "kernel::memory::__syscall_283::_::__CTOR" + .asciz "kernel::memory::map::__syscall_227::_::__CTOR" + .asciz "kernel::ipc::__syscall_100::_::__CTOR" + .asciz "kernel::ipc::__syscall_24::_::__CTOR" + .asciz "kernel::ipc::signal::__syscall_133::_::__CTOR" + .asciz "kernel::ipc::signal::__syscall_139::_::__CTOR" + .asciz "kernel::ipc::signal::__syscall_135::_::__CTOR" + .asciz "kernel::ipc::shm::__syscall_195::_::__CTOR" + .asciz "kernel::fs::sys::cpu::__syscall_119::_::__CTOR" + .asciz "kernel::fs::sys::cpu::__syscall_122::_::__CTOR" + .asciz "kernel::fs::link::__syscall_36::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_16::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_14::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_12::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_7::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_5::_::__CTOR" + .asciz "kernel::fs::control::__syscall_166::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_81::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_79::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_68::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_66::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_62::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_50::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_17::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_64::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_63::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_61::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_57::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_56::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_39::_::__CTOR" + .asciz "kernel::timer::__syscall_115::_::__CTOR" + .asciz "kernel::timer::__syscall_102::_::__CTOR" + .asciz "kernel::timer::__syscall_101::_::__CTOR" + .asciz "kernel::timer::__syscall_153::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_261::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_178::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_154::_::__CTOR" + .asciz "kernel::ipc::__syscall_98::_::__CTOR" + .asciz "kernel::ipc::__syscall_23::_::__CTOR" + .asciz "kernel::ipc::signal::__syscall_134::_::__CTOR" + .asciz "kernel::fs::poll::__syscall_73::_::__CTOR" + .asciz "kernel::fs::link::__syscall_37::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_11::_::__CTOR" + .asciz "kernel::fs::control::__syscall_55::_::__CTOR" + .asciz "kernel::fs::control::__syscall_48::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_285::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_71::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_276::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_46::_::__CTOR" + .asciz "kernel::task::task::TID_MANAGER" + .asciz "einit" + .asciz "kernel::memory::vmm::KERNEL_SPACE" + .asciz "kernel::memory::HEAP_ALLOCATOR" + .asciz "kernel::task::cpu::__syscall_260::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_177::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_174::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_155::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_124::_::__INVENTORY" + .asciz "kernel::net::__syscall_210::_::__INVENTORY" + .asciz "kernel::net::__syscall_203::_::__INVENTORY" + .asciz "kernel::net::__syscall_201::_::__INVENTORY" + .asciz "kernel::memory::map::__syscall_233::_::__INVENTORY" + .asciz "kernel::memory::map::__syscall_215::_::__INVENTORY" + .asciz "kernel::ipc::__syscall_99::_::__INVENTORY" + .asciz "kernel::ipc::shm::__syscall_196::_::__INVENTORY" + .asciz "kernel::gui::__syscall_2000::_::__INVENTORY" + .asciz "kernel::fs::sys::cpu::__syscall_121::_::__INVENTORY" + .asciz "kernel::fs::proc::process::__syscall_165::_::__INVENTORY" + .asciz "kernel::fs::link::__syscall_78::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_10::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_9::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_8::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_6::_::__INVENTORY" + .asciz "kernel::fs::control::__syscall_53::_::__INVENTORY" + .asciz "kernel::fs::control::__syscall_29::_::__INVENTORY" + .asciz "kernel::fs::control::__syscall_25::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_38::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_44::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_67::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_45::_::__INVENTORY" + .asciz "kernel::device::input::__syscall_2002::_::__INVENTORY" + .asciz "kernel::fs::dev::DEVICES" + .asciz "kernel::fs::dev::DEVICE_ID_MANAGER" + .asciz "kernel::timer::__syscall_103::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_221::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_220::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_94::_::__INVENTORY" + .asciz "kernel::net::__syscall_209::_::__INVENTORY" + .asciz "kernel::net::__syscall_207::_::__INVENTORY" + .asciz "kernel::net::__syscall_206::_::__INVENTORY" + .asciz "kernel::net::__syscall_204::_::__INVENTORY" + .asciz "kernel::net::__syscall_200::_::__INVENTORY" + .asciz "kernel::net::__syscall_198::_::__INVENTORY" + .asciz "kernel::memory::map::__syscall_222::_::__INVENTORY" + .asciz "kernel::ipc::__syscall_59::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_130::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_137::_::__INVENTORY" + .asciz "kernel::gui::__syscall_2001::_::__INVENTORY" + .asciz "kernel::fs::sys::info::__syscall_179::_::__INVENTORY" + .asciz "kernel::fs::sys::cpu::__syscall_120::_::__INVENTORY" + .asciz "kernel::fs::sys::cpu::__syscall_123::_::__INVENTORY" + .asciz "kernel::fs::sys::cpu::__syscall_118::_::__INVENTORY" + .asciz "kernel::fs::select::__syscall_72::_::__INVENTORY" + .asciz "kernel::fs::link::__syscall_35::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_15::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_13::_::__INVENTORY" + .asciz "kernel::fs::control::__syscall_52::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_43::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_80::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_65::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_34::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_49::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_40::_::__INVENTORY" + .asciz "kernel::timer::TIMER_QUEUE" + .asciz "kernel::task::cpu::__syscall_96::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_214::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_176::_::__INVENTORY" + .asciz "kernel::sbi::__syscall_2003::_::__INVENTORY" + .asciz "kernel::net::__syscall_208::_::__INVENTORY" + .asciz "kernel::memory::map::__syscall_226::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_129::_::__INVENTORY" + .asciz "kernel::ipc::shm::__syscall_194::_::__INVENTORY" + .asciz "kernel::fs::sys::info::__syscall_116::_::__INVENTORY" + .asciz "kernel::fs::control::__syscall_88::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_82::_::__INVENTORY" + .asciz "kernel::fs::stdio::STDIN" + .asciz "kernel::fs::stdio::STDOUT" + .asciz "kernel::task::INIT_PROCESS" + .asciz "kernel::ipc::FUTEX_WAITER" + .asciz "kernel::task::cpu::GLOBAL_TASK_MANAGER" + .asciz "kernel::timer::__syscall_114::_::__INVENTORY" + .asciz "kernel::timer::__syscall_113::_::__INVENTORY" + .asciz "kernel::timer::__syscall_169::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_175::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_173::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_172::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_157::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_93::_::__INVENTORY" + .asciz "kernel::system::__syscall_160::_::__INVENTORY" + .asciz "kernel::net::__syscall_199::_::__INVENTORY" + .asciz "kernel::net::__syscall_205::_::__INVENTORY" + .asciz "kernel::net::__syscall_202::_::__INVENTORY" + .asciz "kernel::memory::__syscall_283::_::__INVENTORY" + .asciz "kernel::memory::map::__syscall_227::_::__INVENTORY" + .asciz "kernel::ipc::__syscall_100::_::__INVENTORY" + .asciz "kernel::ipc::__syscall_24::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_133::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_139::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_135::_::__INVENTORY" + .asciz "kernel::ipc::shm::__syscall_195::_::__INVENTORY" + .asciz "kernel::fs::sys::cpu::__syscall_119::_::__INVENTORY" + .asciz "kernel::fs::sys::cpu::__syscall_122::_::__INVENTORY" + .asciz "kernel::fs::link::__syscall_36::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_16::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_14::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_12::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_7::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_5::_::__INVENTORY" + .asciz "kernel::fs::control::__syscall_166::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_81::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_79::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_68::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_66::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_62::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_50::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_17::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_64::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_63::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_61::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_57::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_56::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_39::_::__INVENTORY" + .asciz "kernel::timer::__syscall_115::_::__INVENTORY" + .asciz "kernel::timer::__syscall_102::_::__INVENTORY" + .asciz "kernel::timer::__syscall_101::_::__INVENTORY" + .asciz "kernel::timer::__syscall_153::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_261::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_178::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_154::_::__INVENTORY" + .asciz "kernel::ipc::__syscall_98::_::__INVENTORY" + .asciz "kernel::ipc::__syscall_23::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_134::_::__INVENTORY" + .asciz "kernel::fs::poll::__syscall_73::_::__INVENTORY" + .asciz "kernel::fs::link::__syscall_37::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_11::_::__INVENTORY" + .asciz "kernel::fs::control::__syscall_55::_::__INVENTORY" + .asciz "kernel::fs::control::__syscall_48::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_285::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_71::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_276::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_46::_::__INVENTORY" + .asciz "kernel::fs::FS" + .asciz "kernel::interrupt::record::INTERRUPT_RECORD" + .asciz "kernel::memory::frame::FRAME_REF_MANAGER" + .asciz "netcore::tcp::get_ephemeral_port::CURR" + .asciz "netcore::udp::get_ephemeral_port::CURR" + .asciz "netcore::SOCKET_SET" + .asciz "netcore::LISTENING_TABLE" + .asciz "preprint::PRINT" + .asciz "log::LOGGER.0" + .asciz "log::LOGGER.1" + .asciz "boot::entry::STACK" + .asciz "edata" + .asciz "kernel::board::qemu::DTB" + .asciz "sbss" + .asciz "kernel::ipc::signal::TID2SIGNALS" + .asciz "kernel::device::block::BLOCK_DEVICE" + .asciz "kernel::memory::KERNEL_HEAP" + .asciz "kernel::board::BOARD_DEVICES" + .asciz "kernel::ipc::shm::SHM_MEMORY" + .asciz "kernel::ipc::FCOUNT" + .asciz "kernel::task::cpu::CPU_MANAGER" + .asciz "kernel::device::uart::UART_DEVICE" + .asciz "kernel::interrupt::PLIC" + .asciz "kernel::interrupt::DEVICE_TABLE" + .asciz "kernel::ipc::pipe::PIPE_FS_ROOT" + .asciz "kernel::fs::SYSTEM_ROOT_FS" + .asciz "kernel::MACHINE_INFO" + .asciz "kernel::device::gpu::GPU_DEVICE" + .asciz "kernel::memory::frame::FRAME_ALLOCATOR" + .asciz "kernel::device::input::KEYBOARD_INPUT_DEVICE" + .asciz "kernel::device::input::MOUSE_INPUT_DEVICE" + .asciz "kernel::device::rtc::RTC_DEVICE" + .asciz "netcore::KERNEL_NET_FUNC" + .asciz "netcore::NET_INTERFACE" + .asciz "ksync::CPUS" + .asciz "boot::STARTED.0" + .asciz "boot::CPUS" + .asciz "__rust_alloc_error_handler_should_panic" + .asciz "__rust_no_alloc_shim_is_unstable" + .asciz "kernel::panic::RECURSION" + .asciz "kernel::print::console::UART_FLAG" + .asciz "kernel::ipc::pipe::PIPE" + .asciz "::registry::REGISTRY" + .asciz "log::STATE" + .asciz "log::MAX_LOG_LEVEL_FILTER" + .asciz "ebss" + .asciz "ekernel" diff --git a/subsystems/unwinder/src/lib.rs b/subsystems/unwinder/src/lib.rs new file mode 100644 index 00000000..a2dc7e03 --- /dev/null +++ b/subsystems/unwinder/src/lib.rs @@ -0,0 +1,4 @@ +#![no_std] +#![feature(panic_info_message)] +mod panic; +mod symbol; \ No newline at end of file diff --git a/subsystems/unwinder/src/panic.rs b/subsystems/unwinder/src/panic.rs new file mode 100644 index 00000000..e3d471c4 --- /dev/null +++ b/subsystems/unwinder/src/panic.rs @@ -0,0 +1,93 @@ +//! panic 处理 + + +use core::panic::PanicInfo; +use core::sync::atomic::AtomicBool; +#[cfg(all(not(feature = "debug-eh-frame"), not(feature = "debug-frame-point")))] +use tracer::CompilerTracer; +#[cfg(feature = "debug-eh-frame")] +use tracer::DwarfTracer; +#[cfg(feature = "debug-frame-point")] +use tracer::FramePointTracer; +use tracer::{Tracer, TracerProvider}; +use platform::{system_shutdown, println}; +use crate::symbol::find_symbol_with_addr; + +/// 递归标志 +static RECURSION: AtomicBool = AtomicBool::new(false); + +/// 错误处理 +/// +/// 发生 panic 是进行结果处理.目前我们会读取符号表信息,进行堆栈回溯 +#[panic_handler] +fn panic_handler(info: &PanicInfo) -> ! { + if let Some(p) = info.location() { + println!( + "line {}, file {}: {}", + p.line(), + p.file(), + info.message().unwrap() + ); + } else { + println!("no location information available"); + } + if !RECURSION.swap(true, core::sync::atomic::Ordering::SeqCst) { + back_trace(); + } + println!("!TEST FINISH!"); + system_shutdown(); +} + +#[derive(Clone)] +struct TracerProviderImpl; +impl TracerProvider for TracerProviderImpl { + fn address2symbol(&self, addr: usize) -> Option<(usize, &'static str)> { + find_symbol_with_addr(addr) + } +} + +#[cfg(feature = "debug-eh-frame")] +extern "C" { + fn kernel_eh_frame(); + fn kernel_eh_frame_end(); + fn kernel_eh_frame_hdr(); + fn kernel_eh_frame_hdr_end(); +} + +#[cfg(feature = "debug-eh-frame")] +struct DwarfProviderImpl; + +#[cfg(feature = "debug-eh-frame")] +impl DwarfProvider for DwarfProviderImpl { + fn kernel_eh_frame_hdr(&self) -> usize { + kernel_eh_frame_hdr as usize + } + + fn kernel_eh_frame(&self) -> usize { + kernel_eh_frame as usize + } + + fn kernel_eh_frame_hdr_end(&self) -> usize { + kernel_eh_frame_hdr_end as usize + } + + fn kernel_eh_frame_end(&self) -> usize { + kernel_eh_frame_end as usize + } +} + +/// 打印堆栈回溯信息 +fn back_trace() { + println!("---START BACKTRACE---"); + #[cfg(all(not(feature = "debug-eh-frame"), not(feature = "debug-frame-point")))] + let tracer = CompilerTracer::new(TracerProviderImpl); + #[cfg(feature = "debug-frame-point")] + let tracer = FramePointTracer::new(TracerProviderImpl); + #[cfg(feature = "debug-eh-frame")] + let tracer = DwarfTracer::new(DwarfProviderImpl, TracerProviderImpl); + for x in tracer.trace() { + println!("[{:#x}] (+{:0>4x}) {}", x.func_addr, x.bias, x.func_name); + } + println!("---END BACKTRACE---"); +} + diff --git a/subsystems/unwinder/src/symbol.rs b/subsystems/unwinder/src/symbol.rs new file mode 100644 index 00000000..966b48f4 --- /dev/null +++ b/subsystems/unwinder/src/symbol.rs @@ -0,0 +1,53 @@ +use core::arch::global_asm; + +extern "C" { + fn symbol_num(); + fn symbol_address(); + fn symbol_index(); + fn symbol_name(); +} + +global_asm!(include_str!("kernel_symbol.S")); + +pub fn find_symbol_with_addr(addr: usize) -> Option<(usize, &'static str)> { + let symbol_num_addr = symbol_num as usize as *const usize; + let symbol_num = unsafe { symbol_num_addr.read_volatile() }; + if symbol_num == 0 { + return None; + } + let symbol_addr = symbol_address as usize as *const usize; // 符号地址存储区域 + let addr_data = unsafe { core::slice::from_raw_parts(symbol_addr, symbol_num) }; + // find the symbol with the nearest address + let mut index = -1isize; + for i in 0..symbol_num - 1 { + if addr >= addr_data[i] && addr < addr_data[i + 1] { + index = i as isize; + break; + } + } + if addr == addr_data[symbol_num - 1] { + index = (symbol_num - 1) as isize; + } + if index == -1 { + return None; + } + let index = index as usize; + let symbol_index = symbol_index as usize as *const usize; // 符号字符串的起始位置 + let index_data = unsafe { core::slice::from_raw_parts(symbol_index, symbol_num) }; + let symbol_name = symbol_name as usize as *const u8; // 符号字符串 + let mut last = 0; + unsafe { + for i in index_data[index].. { + let c = symbol_name.add(i); + if *c == 0 { + last = i; + break; + } + } + } + let name = unsafe { + core::slice::from_raw_parts(symbol_name.add(index_data[index]), last - index_data[index]) + }; + let name = core::str::from_utf8(name).unwrap(); + Some((addr_data[index], name)) +} diff --git a/subsystems/vfs/Cargo.toml b/subsystems/vfs/Cargo.toml new file mode 100644 index 00000000..9e7208b8 --- /dev/null +++ b/subsystems/vfs/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "vfs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +spin = "0" +log = "0" +ksync = { path = "../ksync" } +arch = { path = "../arch" } +constants = { path = "../constants" } +interrupt = { path = "../interrupt" } +platform = { path = "../platform" } + + +vfscore = { git = "https://github.com/os-module/rvfs.git", features = [ + "linux_error", +] } +devfs = { git = "https://github.com/os-module/rvfs.git" } +dynfs = { git = "https://github.com/os-module/rvfs.git" } +ramfs = { git = "https://github.com/os-module/rvfs.git" } +fat-vfs = { git = "https://github.com/os-module/rvfs.git" } + + +devices = { path = "../devices" } diff --git a/subsystems/vfs/src/dev/mod.rs b/subsystems/vfs/src/dev/mod.rs new file mode 100644 index 00000000..8c833014 --- /dev/null +++ b/subsystems/vfs/src/dev/mod.rs @@ -0,0 +1,253 @@ +use devices::{ + BLKDevice, GPUDevice, INPUTDevice, RTCDevice, UARTDevice, BLOCK_DEVICE, GPU_DEVICE, + KEYBOARD_INPUT_DEVICE, MOUSE_INPUT_DEVICE, RTC_DEVICE, UART_DEVICE, +}; +use alloc::collections::BTreeMap; +use alloc::sync::Arc; +use constants::DeviceId; +use devfs::DevKernelProvider; +use log::info; +use ksync::Mutex; +use null::NullDevice; +use random::RandomDevice; +use spin::Lazy; +use vfscore::dentry::VfsDentry; +use vfscore::fstype::VfsFsType; +use vfscore::inode::VfsInode; +use vfscore::utils::{VfsNodeType, VfsTimeSpec}; + +mod null; +mod random; + +pub static DEVICES: Lazy>>> = + Lazy::new(|| Mutex::new(BTreeMap::new())); + +pub static DEVICE_ID_MANAGER: Lazy> = + Lazy::new(|| Mutex::new(DeviceIdManager::new())); + +pub fn register_device(inode: Arc) { + let rdev = inode.get_attr().unwrap().st_rdev; + let device_id = DeviceId::from(rdev); + DEVICES.lock().insert(device_id, inode); +} + +pub fn unregister_device(rdev: DeviceId) { + DEVICES.lock().remove(&rdev); +} + +pub fn alloc_device_id(inode_type: VfsNodeType) -> DeviceId { + DEVICE_ID_MANAGER.lock().alloc(inode_type) +} + +pub trait InodeType2u32 { + fn to_u32(&self) -> u32; +} + +impl InodeType2u32 for VfsNodeType { + fn to_u32(&self) -> u32 { + match self { + VfsNodeType::CharDevice => 2, + VfsNodeType::BlockDevice => 3, + _ => 0, + } + } +} + +pub struct DeviceIdManager { + map: BTreeMap, +} + +impl DeviceIdManager { + pub fn new() -> Self { + Self { + map: BTreeMap::new(), + } + } + pub fn alloc(&mut self, inode_type: VfsNodeType) -> DeviceId { + assert!(matches!( + inode_type, + VfsNodeType::CharDevice | VfsNodeType::BlockDevice + )); + let id = self.map.entry(inode_type.to_u32()).or_insert(0); + *id += 1; + DeviceId::new(inode_type.to_u32(), *id) + } +} + +#[derive(Clone)] +pub struct DevFsProviderImpl; +impl DevKernelProvider for DevFsProviderImpl { + fn current_time(&self) -> VfsTimeSpec { + VfsTimeSpec::new(0, 0) + } + fn rdev2device(&self, rdev: u64) -> Option> { + let device_id = DeviceId::from(rdev); + DEVICES.lock().get(&device_id).cloned() + } +} + +///```bash +/// | +/// |-- null +/// |-- zero +/// |-- random +/// |-- urandom +/// |-- tty +/// |-- shm (a ramfs will be mounted here) +/// |-- misc +/// |-- rtc +/// ``` +pub fn init_devfs(devfs: Arc) -> Arc { + let root = devfs.i_mount(0, "/dev", None, &[]).unwrap(); + let root_inode = root.inode().unwrap(); + + let null_device = Arc::new(NullDevice::new(alloc_device_id(VfsNodeType::CharDevice))); + let zero_device = Arc::new(NullDevice::new(alloc_device_id(VfsNodeType::CharDevice))); + let random_device = Arc::new(RandomDevice::new(alloc_device_id(VfsNodeType::CharDevice))); + let urandom_device = Arc::new(RandomDevice::new(alloc_device_id(VfsNodeType::CharDevice))); + + root_inode + .create( + "null", + 'c'.into(), + "rw-rw-rw-".into(), + Some(null_device.device_id().id()), + ) + .unwrap(); + root_inode + .create( + "zero", + 'c'.into(), + "rw-rw-rw-".into(), + Some(zero_device.device_id().id()), + ) + .unwrap(); + root_inode + .create( + "random", + 'c'.into(), + "rw-rw-rw-".into(), + Some(random_device.device_id().id()), + ) + .unwrap(); + root_inode + .create( + "urandom", + 'c'.into(), + "rw-rw-rw-".into(), + Some(urandom_device.device_id().id()), + ) + .unwrap(); + + register_device(null_device); + register_device(zero_device); + register_device(random_device); + register_device(urandom_device); + + root_inode + .create("shm", VfsNodeType::Dir, "rwxrwxrwx".into(), None) + .unwrap(); + root_inode + .create("misc", VfsNodeType::Dir, "rwxrwxrwx".into(), None) + .unwrap(); + + scan_system_devices(root_inode); + // todo!(tty,shm,misc) + println!("devfs init success"); + root +} + +fn scan_system_devices(root: Arc) { + BLOCK_DEVICE.get().map(|blk| { + let block_device = Arc::new(BLKDevice::new( + alloc_device_id(VfsNodeType::BlockDevice), + blk.clone(), + )); + root.create( + "sda", + VfsNodeType::BlockDevice, + "rw-rw----".into(), + Some(block_device.device_id().id()), + ) + .unwrap(); + info!("block device id: {}", block_device.device_id().id()); + register_device(block_device); + }); + GPU_DEVICE.get().map(|gpu| { + let gpu_device = Arc::new(GPUDevice::new( + alloc_device_id(VfsNodeType::CharDevice), + gpu.clone(), + )); + root.create( + "gpu", + VfsNodeType::BlockDevice, + "rw-rw----".into(), + Some(gpu_device.device_id().id()), + ) + .unwrap(); + info!("gpu device id: {}", gpu_device.device_id().id()); + register_device(gpu_device); + }); + KEYBOARD_INPUT_DEVICE.get().map(|input| { + let input_device = Arc::new(INPUTDevice::new( + alloc_device_id(VfsNodeType::CharDevice), + input.clone(), + false, + )); + root.create( + "keyboard", + VfsNodeType::BlockDevice, + "rw-rw----".into(), + Some(input_device.device_id().id()), + ) + .unwrap(); + info!("keyboard device id: {}", input_device.device_id().id()); + register_device(input_device); + }); + MOUSE_INPUT_DEVICE.get().map(|input| { + let input_device = Arc::new(INPUTDevice::new( + alloc_device_id(VfsNodeType::CharDevice), + input.clone(), + true, + )); + root.create( + "mouse", + VfsNodeType::BlockDevice, + "rw-rw----".into(), + Some(input_device.device_id().id()), + ) + .unwrap(); + info!("mouse device id: {}", input_device.device_id().id()); + register_device(input_device); + }); + RTC_DEVICE.get().map(|rtc| { + let rtc_device = Arc::new(RTCDevice::new( + alloc_device_id(VfsNodeType::CharDevice), + rtc.clone(), + )); + root.create( + "rtc", + VfsNodeType::BlockDevice, + "rw-rw----".into(), + Some(rtc_device.device_id().id()), + ) + .unwrap(); + info!("rtc device id: {}", rtc_device.device_id().id()); + register_device(rtc_device); + }); + UART_DEVICE.get().map(|uart| { + let uart_device = Arc::new(UARTDevice::new( + alloc_device_id(VfsNodeType::CharDevice), + uart.clone(), + )); + root.create( + "tty", + VfsNodeType::BlockDevice, + "rw-rw----".into(), + Some(uart_device.device_id().id()), + ) + .unwrap(); + info!("uart device id: {}", uart_device.device_id().id()); + register_device(uart_device); + }); +} diff --git a/subsystems/vfs/src/dev/null.rs b/subsystems/vfs/src/dev/null.rs new file mode 100644 index 00000000..44a731f8 --- /dev/null +++ b/subsystems/vfs/src/dev/null.rs @@ -0,0 +1,55 @@ +use crate::dev::DeviceId; +use alloc::sync::Arc; +use vfscore::error::VfsError; +use vfscore::file::VfsFile; +use vfscore::inode::{InodeAttr, VfsInode}; +use vfscore::superblock::VfsSuperBlock; +use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; +use vfscore::VfsResult; + +pub struct NullDevice { + device_id: DeviceId, +} + +impl NullDevice { + pub fn new(device_id: DeviceId) -> Self { + Self { device_id } + } + pub fn device_id(&self) -> DeviceId { + self.device_id + } +} + +impl VfsFile for NullDevice { + fn read_at(&self, _offset: u64, buf: &mut [u8]) -> VfsResult { + buf.fill(0); + Ok(buf.len()) + } + fn write_at(&self, _offset: u64, buf: &[u8]) -> VfsResult { + Ok(buf.len()) + } +} + +impl VfsInode for NullDevice { + fn get_super_block(&self) -> VfsResult> { + Err(VfsError::NoSys) + } + + fn node_perm(&self) -> VfsNodePerm { + VfsNodePerm::empty() + } + + fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { + Ok(()) + } + + fn get_attr(&self) -> VfsResult { + Ok(VfsFileStat { + st_rdev: self.device_id.id(), + ..Default::default() + }) + } + fn inode_type(&self) -> VfsNodeType { + VfsNodeType::CharDevice + } +} diff --git a/subsystems/vfs/src/dev/random.rs b/subsystems/vfs/src/dev/random.rs new file mode 100644 index 00000000..16362f62 --- /dev/null +++ b/subsystems/vfs/src/dev/random.rs @@ -0,0 +1,59 @@ +use crate::dev::DeviceId; +use alloc::sync::Arc; +use arch::read_timer; +use vfscore::error::VfsError; +use vfscore::file::VfsFile; +use vfscore::inode::{InodeAttr, VfsInode}; +use vfscore::superblock::VfsSuperBlock; +use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; +use vfscore::VfsResult; +pub struct RandomDevice { + device_id: DeviceId, +} +impl RandomDevice { + pub fn new(device_id: DeviceId) -> Self { + Self { device_id } + } + pub fn device_id(&self) -> DeviceId { + self.device_id + } +} + +impl VfsFile for RandomDevice { + fn read_at(&self, _offset: u64, buf: &mut [u8]) -> VfsResult { + let mut current_time = read_timer(); + buf.iter_mut().for_each(|x| { + *x = current_time as u8; + current_time = current_time.wrapping_sub(1); + }); + Ok(buf.len()) + } + fn write_at(&self, _offset: u64, buf: &[u8]) -> VfsResult { + Ok(buf.len()) + } +} + +impl VfsInode for RandomDevice { + fn get_super_block(&self) -> VfsResult> { + Err(VfsError::NoSys) + } + + fn node_perm(&self) -> VfsNodePerm { + VfsNodePerm::empty() + } + + fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { + Ok(()) + } + + fn get_attr(&self) -> VfsResult { + Ok(VfsFileStat { + st_rdev: self.device_id.id(), + ..Default::default() + }) + } + + fn inode_type(&self) -> VfsNodeType { + VfsNodeType::CharDevice + } +} diff --git a/subsystems/vfs/src/lib.rs b/subsystems/vfs/src/lib.rs new file mode 100644 index 00000000..35604a15 --- /dev/null +++ b/subsystems/vfs/src/lib.rs @@ -0,0 +1,133 @@ +#![no_std] + +extern crate alloc; +#[macro_use] +extern crate platform; +use crate::dev::DevFsProviderImpl; +use alloc::collections::BTreeMap; +use alloc::string::{String, ToString}; +use alloc::sync::Arc; +use constants::AlienResult; +use core::ops::Index; +use dynfs::DynFsKernelProvider; +use fat_vfs::FatFsProvider; +use ksync::Mutex; +use spin::{Lazy, Once}; +use vfscore::dentry::VfsDentry; +use vfscore::fstype::VfsFsType; +use vfscore::path::VfsPath; +use vfscore::utils::{VfsTimeSpec}; + +pub mod dev; +pub mod proc; +pub mod ram; +pub mod sys; +pub mod pipefs; + +pub static FS: Lazy>>> = + Lazy::new(|| Mutex::new(BTreeMap::new())); + +pub static SYSTEM_ROOT_FS: Once> = Once::new(); + +type SysFs = dynfs::DynFs>; +type ProcFs = dynfs::DynFs>; +type RamFs = ramfs::RamFs>; +type DevFs = devfs::DevFs>; +type TmpFs = ramfs::RamFs>; +type PipeFs = dynfs::DynFs>; +type FatFs = fat_vfs::FatFs>; + +#[derive(Clone)] +pub struct CommonFsProviderImpl; + +impl DynFsKernelProvider for CommonFsProviderImpl { + fn current_time(&self) -> VfsTimeSpec { + VfsTimeSpec::new(0, 0) + } +} + +impl ramfs::RamFsProvider for CommonFsProviderImpl { + fn current_time(&self) -> VfsTimeSpec { + DynFsKernelProvider::current_time(self) + } +} + +impl FatFsProvider for CommonFsProviderImpl { + fn current_time(&self) -> VfsTimeSpec { + DynFsKernelProvider::current_time(self) + } +} + +fn register_all_fs() { + let procfs = Arc::new(ProcFs::new(CommonFsProviderImpl, "procfs")); + let sysfs = Arc::new(SysFs::new(CommonFsProviderImpl, "sysfs")); + let ramfs = Arc::new(RamFs::new(CommonFsProviderImpl)); + let devfs = Arc::new(DevFs::new(DevFsProviderImpl)); + let tmpfs = Arc::new(TmpFs::new(CommonFsProviderImpl)); + let pipefs = Arc::new(PipeFs::new(CommonFsProviderImpl, "pipefs")); + + let fatfs = Arc::new(FatFs::new(CommonFsProviderImpl)); + + FS.lock().insert("procfs".to_string(), procfs); + FS.lock().insert("sysfs".to_string(), sysfs); + FS.lock().insert("ramfs".to_string(), ramfs); + FS.lock().insert("devfs".to_string(), devfs); + FS.lock().insert("tmpfs".to_string(), tmpfs); + FS.lock().insert("pipefs".to_string(), pipefs); + FS.lock().insert("fatfs".to_string(), fatfs); + + println!("register fs success"); +} + +/// Init the filesystem +pub fn init_filesystem() -> AlienResult<()> { + register_all_fs(); + let ramfs_root = ram::init_ramfs(FS.lock().index("ramfs").clone()); + let procfs_root = proc::init_procfs(FS.lock().index("procfs").clone()); + let devfs_root = dev::init_devfs(FS.lock().index("devfs").clone()); + let sysfs_root = sys::init_sysfs(FS.lock().index("sysfs").clone()); + let tmpfs_root = FS + .lock() + .index("tmpfs") + .clone() + .i_mount(0, "/tmp", None, &[])?; + + pipefs::init_pipefs(FS.lock().index("pipefs").clone()); + + let path = VfsPath::new(ramfs_root.clone()); + path.join("proc")?.mount(procfs_root, 0)?; + path.join("sys")?.mount(sysfs_root, 0)?; + path.join("dev")?.mount(devfs_root, 0)?; + path.join("tmp")?.mount(tmpfs_root.clone(), 0)?; + + let shm_ramfs = FS + .lock() + .index("ramfs") + .clone() + .i_mount(0, "/dev/shm", None, &[])?; + path.join("dev/shm")?.mount(shm_ramfs, 0)?; + + let fatfs = FS.lock().index("fatfs").clone(); + let blk_inode = path + .join("/dev/sda")? + .open(None) + .expect("open /dev/sda failed") + .inode()?; + let fat32_root = fatfs.i_mount(0, "/bin", Some(blk_inode), &[])?; + path.join("bin")?.mount(fat32_root, 0)?; + + vfscore::path::print_fs_tree(&mut VfsOutPut, ramfs_root.clone(), "".to_string(), false) + .unwrap(); + SYSTEM_ROOT_FS.call_once(|| ramfs_root); + println!("Init filesystem success"); + Ok(()) +} + +struct VfsOutPut; +impl core::fmt::Write for VfsOutPut { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + platform::console::console_write(s); + Ok(()) + } +} + diff --git a/subsystems/vfs/src/pipefs.rs b/subsystems/vfs/src/pipefs.rs new file mode 100644 index 00000000..cb1fe1d5 --- /dev/null +++ b/subsystems/vfs/src/pipefs.rs @@ -0,0 +1,20 @@ +use alloc::sync::Arc; +use dynfs::DynFsDirInode; +use spin::Once; +use vfscore::dentry::VfsDentry; +use vfscore::fstype::VfsFsType; +use constants::io::MountFlags; + +use ksync::Mutex; +use crate::CommonFsProviderImpl; + +pub type PipeFsDirInodeImpl = DynFsDirInode>; +pub static PIPE_FS_ROOT: Once> = Once::new(); + +pub fn init_pipefs(fs: Arc) { + let root = fs + .i_mount(MountFlags::empty().bits(), "", None, &[]) + .unwrap(); + PIPE_FS_ROOT.call_once(|| root); + println!("pipefs init success"); +} \ No newline at end of file diff --git a/subsystems/vfs/src/proc/filesystem.rs b/subsystems/vfs/src/proc/filesystem.rs new file mode 100644 index 00000000..651a3a89 --- /dev/null +++ b/subsystems/vfs/src/proc/filesystem.rs @@ -0,0 +1,68 @@ +use crate::FS; +use alloc::string::String; +use alloc::sync::Arc; +use core::cmp::min; +use vfscore::error::VfsError; +use vfscore::file::VfsFile; +use vfscore::fstype::FileSystemFlags; +use vfscore::inode::{InodeAttr, VfsInode}; +use vfscore::superblock::VfsSuperBlock; +use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; +use vfscore::VfsResult; + +pub struct SystemSupportFS; + +impl SystemSupportFS { + pub fn new() -> Self { + Self + } + pub fn serialize(&self) -> String { + let mut res = String::new(); + let fs = FS.lock(); + for (_, fs) in fs.iter() { + let flag = fs.fs_flag(); + if !flag.contains(FileSystemFlags::REQUIRES_DEV) { + res.push_str("nodev ") + } else { + res.push_str(" "); + } + res.push_str(fs.fs_name()); + res.push_str("\n"); + } + res + } +} + +impl VfsFile for SystemSupportFS { + fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { + let info = self.serialize(); + let min_len = min(buf.len(), info.as_bytes().len() - offset as usize); + buf[..min_len].copy_from_slice(&info.as_bytes()[..min_len]); + Ok(min_len) + } +} + +impl VfsInode for SystemSupportFS { + fn get_super_block(&self) -> VfsResult> { + Err(VfsError::NoSys) + } + + fn node_perm(&self) -> VfsNodePerm { + VfsNodePerm::empty() + } + + fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { + Ok(()) + } + + fn get_attr(&self) -> VfsResult { + Ok(VfsFileStat { + st_size: self.serialize().as_bytes().len() as u64, + ..Default::default() + }) + } + + fn inode_type(&self) -> VfsNodeType { + VfsNodeType::File + } +} diff --git a/subsystems/vfs/src/proc/interrupt.rs b/subsystems/vfs/src/proc/interrupt.rs new file mode 100644 index 00000000..9c9c61b9 --- /dev/null +++ b/subsystems/vfs/src/proc/interrupt.rs @@ -0,0 +1,47 @@ +use alloc::sync::Arc; +use core::cmp::min; +use interrupt::record::interrupts_info; +use vfscore::error::VfsError; +use vfscore::file::VfsFile; +use vfscore::inode::{InodeAttr, VfsInode}; +use vfscore::superblock::VfsSuperBlock; +use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; +use vfscore::VfsResult; + +pub struct InterruptRecord; + +impl VfsFile for InterruptRecord { + fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { + let info = interrupts_info(); + let min_len = min(buf.len(), info.as_bytes().len() - offset as usize); + buf[..min_len].copy_from_slice(&info.as_bytes()[..min_len]); + Ok(min_len) + } + fn write_at(&self, _offset: u64, _buf: &[u8]) -> VfsResult { + Err(VfsError::PermissionDenied) + } +} + +impl VfsInode for InterruptRecord { + fn get_super_block(&self) -> VfsResult> { + Err(VfsError::NoSys) + } + fn node_perm(&self) -> VfsNodePerm { + VfsNodePerm::empty() + } + fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { + Ok(()) + } + + fn get_attr(&self) -> VfsResult { + let info = interrupts_info(); + Ok(VfsFileStat { + st_size: info.as_bytes().len() as u64, + ..Default::default() + }) + } + + fn inode_type(&self) -> VfsNodeType { + VfsNodeType::File + } +} diff --git a/subsystems/vfs/src/proc/mem.rs b/subsystems/vfs/src/proc/mem.rs new file mode 100644 index 00000000..ff8af076 --- /dev/null +++ b/subsystems/vfs/src/proc/mem.rs @@ -0,0 +1,87 @@ +use alloc::sync::Arc; +use core::cmp::min; +use vfscore::error::VfsError; +use vfscore::file::VfsFile; +use vfscore::inode::{InodeAttr, VfsInode}; +use vfscore::superblock::VfsSuperBlock; +use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; +use vfscore::VfsResult; + +pub struct MemInfo; + +impl VfsFile for MemInfo { + fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { + let min_len = min(buf.len(), MEMINFO.as_bytes().len() - offset as usize); + buf[..min_len].copy_from_slice(&MEMINFO.as_bytes()[..min_len]); + Ok(min_len) + } +} + +impl VfsInode for MemInfo { + fn get_super_block(&self) -> VfsResult> { + Err(VfsError::NoSys) + } + fn node_perm(&self) -> VfsNodePerm { + VfsNodePerm::empty() + } + fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { + Ok(()) + } + + fn get_attr(&self) -> VfsResult { + Ok(VfsFileStat { + st_size: MEMINFO.as_bytes().len() as u64, + ..Default::default() + }) + } + + fn inode_type(&self) -> VfsNodeType { + VfsNodeType::File + } +} + +/// meminfo文件中保存的内容 +const MEMINFO: &str = r" +MemTotal: 944564 kB +MemFree: 835248 kB +MemAvailable: 873464 kB +Buffers: 6848 kB +Cached: 36684 kB +SwapCached: 0 kB +Active: 19032 kB +Inactive: 32676 kB +Active(anon): 128 kB +Inactive(anon): 8260 kB +Active(file): 18904 kB +Inactive(file): 24416 kB +Unevictable: 0 kB +Mlocked: 0 kB +SwapTotal: 0 kB +SwapFree: 0 kB +Dirty: 0 kB +Writeback: 0 kB +AnonPages: 8172 kB +Mapped: 16376 kB +Shmem: 216 kB +KReclaimable: 9960 kB +Slab: 17868 kB +SReclaimable: 9960 kB +SUnreclaim: 7908 kB +KernelStack: 1072 kB +PageTables: 600 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 472280 kB +Committed_AS: 64684 kB +VmallocTotal: 67108863 kB +VmallocUsed: 15740 kB +VmallocChunk: 0 kB +Percpu: 496 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +Hugetlb: 0 kB +"; diff --git a/subsystems/vfs/src/proc/mod.rs b/subsystems/vfs/src/proc/mod.rs new file mode 100644 index 00000000..082a6afb --- /dev/null +++ b/subsystems/vfs/src/proc/mod.rs @@ -0,0 +1,52 @@ +mod filesystem; +mod interrupt; +mod mem; +mod mounts; + +use crate::CommonFsProviderImpl; +use alloc::sync::Arc; +use dynfs::DynFsDirInode; +use filesystem::SystemSupportFS; +use interrupt::InterruptRecord; +use ksync::Mutex; +use mem::MemInfo; +use mounts::MountInfo; +use vfscore::dentry::VfsDentry; +use vfscore::error::VfsError; +use vfscore::fstype::VfsFsType; + +pub type ProcFsDirInodeImpl = DynFsDirInode>; + +/// +/// ```bash +/// | +/// |-- meminfo +/// |-- interrupts +/// |-- mounts +/// |-- filesystems +/// ``` +pub fn init_procfs(procfs: Arc) -> Arc { + let root_dt = procfs.i_mount(0, "/proc", None, &[]).unwrap(); + let root_inode = root_dt.inode().unwrap(); + let root_inode = root_inode + .downcast_arc::() + .map_err(|_| VfsError::Invalid) + .unwrap(); + root_inode + .add_file_manually("meminfo", Arc::new(MemInfo), "r--r--r--".into()) + .unwrap(); + root_inode + .add_file_manually("interrupts", Arc::new(InterruptRecord), "r--r--r--".into()) + .unwrap(); + root_inode + .add_file_manually("mounts", Arc::new(MountInfo), "r--r--r--".into()) + .unwrap(); + let support_fs = SystemSupportFS::new(); + root_inode + .add_file_manually("filesystems", Arc::new(support_fs), "r--r--r--".into()) + .unwrap(); + + println!("procfs init success"); + + root_dt +} diff --git a/subsystems/vfs/src/proc/mounts.rs b/subsystems/vfs/src/proc/mounts.rs new file mode 100644 index 00000000..ac0d76fe --- /dev/null +++ b/subsystems/vfs/src/proc/mounts.rs @@ -0,0 +1,47 @@ +use alloc::sync::Arc; +use core::cmp::min; +use vfscore::error::VfsError; +use vfscore::file::VfsFile; +use vfscore::inode::{InodeAttr, VfsInode}; +use vfscore::superblock::VfsSuperBlock; +use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; +use vfscore::VfsResult; + +// todo!(dynamic mount info) +const MOUNT_INFO: &str = r" + rootfs / rootfs rw 0 0 + devfs /dev devfs rw 0 0 + fat32 / fat rw 0 0 +"; +pub struct MountInfo; + +impl VfsFile for MountInfo { + fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { + let min_len = min(buf.len(), MOUNT_INFO.as_bytes().len() - offset as usize); + buf[..min_len].copy_from_slice(&MOUNT_INFO.as_bytes()[..min_len]); + Ok(min_len) + } +} + +impl VfsInode for MountInfo { + fn get_super_block(&self) -> VfsResult> { + Err(VfsError::NoSys) + } + fn node_perm(&self) -> VfsNodePerm { + VfsNodePerm::empty() + } + fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { + Ok(()) + } + + fn get_attr(&self) -> VfsResult { + Ok(VfsFileStat { + st_size: MOUNT_INFO.as_bytes().len() as u64, + ..Default::default() + }) + } + + fn inode_type(&self) -> VfsNodeType { + VfsNodeType::File + } +} diff --git a/subsystems/vfs/src/ram/mod.rs b/subsystems/vfs/src/ram/mod.rs new file mode 100644 index 00000000..8f688408 --- /dev/null +++ b/subsystems/vfs/src/ram/mod.rs @@ -0,0 +1,112 @@ +use alloc::sync::Arc; +use vfscore::dentry::VfsDentry; +use vfscore::fstype::VfsFsType; +use vfscore::utils::VfsNodeType; + + +/// +/// ```bash +/// | +/// |-- root +/// |-- .bashrc +/// |--var +/// |-- log +/// |-- tmp(ramfs) +/// |-- run +/// |-- etc +/// |-- passwd +/// |--localtime +/// |--adjtime +/// |-- dev (devfs) +/// |-- proc (procfs) +/// |-- sys (sysfs) +/// |-- bin (fat32) +/// |-- tmp (ramfs) +/// ``` +pub fn init_ramfs(ramfs: Arc) -> Arc { + let root_dt = ramfs.i_mount(0, "/", None, &[]).unwrap(); + let root_inode = root_dt.inode().unwrap(); + let root = root_inode + .create("root", VfsNodeType::Dir, "rwxr-xr-x".into(), None) + .unwrap(); + let var = root_inode + .create("var", VfsNodeType::Dir, "rwxr-xr-x".into(), None) + .unwrap(); + var.create("log", VfsNodeType::Dir, "rwxrwxr-x".into(), None) + .unwrap(); + var.create("tmp", VfsNodeType::Dir, "rwxrwxrwx".into(), None) + .unwrap(); + var.create("run", VfsNodeType::Dir, "rwxrwxrwx".into(), None) + .unwrap(); + let etc = root_inode + .create("etc", VfsNodeType::Dir, "rwxr-xr-x".into(), None) + .unwrap(); + let passwd = etc + .create("passwd", VfsNodeType::File, "rw-r--r--".into(), None) + .unwrap(); + let localtime = etc + .create("localtime", VfsNodeType::File, "rw-r--r--".into(), None) + .unwrap(); + let adjtime = etc + .create("adjtime", VfsNodeType::File, "rw-r--r--".into(), None) + .unwrap(); + + passwd + .write_at(0, b"root:x:0:0:root:/root:/bin/bash\n") + .unwrap(); + localtime.write_at(0, UTC).unwrap(); + adjtime.write_at(0, RTC_TIME.as_bytes()).unwrap(); + + root_inode + .create("dev", VfsNodeType::Dir, "rwxr-xr-x".into(), None) + .unwrap(); + root_inode + .create("proc", VfsNodeType::Dir, "rwxr-xr-x".into(), None) + .unwrap(); + root_inode + .create("sys", VfsNodeType::Dir, "rwxr-xr-x".into(), None) + .unwrap(); + root_inode + .create("bin", VfsNodeType::Dir, "rwxr-xr-x".into(), None) + .unwrap(); + root_inode + .create("tmp", VfsNodeType::Dir, "rwxrwxrwx".into(), None) + .unwrap(); + + let _bashrc = root + .create(".bashrc", VfsNodeType::File, "rwxrwxrwx".into(), None) + .unwrap(); + + println!("ramfs init success"); + root_dt +} + +/// localtime文件中保存的内容 +pub const UTC: &[u8] = &[ + b'T', b'Z', b'i', b'f', b'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, + 0, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, b'U', b'T', b'C', + 0, 0, 0, b'T', b'Z', b'i', b'f', b'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, b'U', + b'T', b'C', 0, 0, 0, 0x0a, 0x55, 0x54, 0x43, 0x30, 0x0a, +]; + +/// rtc文件中保存的内容 +pub const RTC_TIME: &str = r" +rtc_time : 03:01:50 +rtc_date : 2023-07-11 +alrm_time : 13:03:24 +alrm_date : 2023-07-11 +alarm_IRQ : no +alrm_pending : no +update IRQ enabled : no +periodic IRQ enabled : no +periodic IRQ frequency : 1024 +max user IRQ frequency : 64 +24hr : yes +periodic_IRQ : no +update_IRQ : no +HPET_emulated : no +BCD : yes +DST_enable : no +periodic_freq : 1024 +batt_status : okay"; diff --git a/subsystems/vfs/src/sys/mod.rs b/subsystems/vfs/src/sys/mod.rs new file mode 100644 index 00000000..3bfa5a5a --- /dev/null +++ b/subsystems/vfs/src/sys/mod.rs @@ -0,0 +1,18 @@ +use crate::CommonFsProviderImpl; +use alloc::sync::Arc; +use dynfs::DynFsDirInode; +use ksync::Mutex; +use vfscore::dentry::VfsDentry; +use vfscore::fstype::VfsFsType; + +pub type SysFsDirInodeImpl = DynFsDirInode>; + +pub fn init_sysfs(sysfs: Arc) -> Arc { + let root_dt = sysfs.i_mount(0, "/sys", None, &[]).unwrap(); + // let root_inode = root_dt.inode().unwrap(); + // let root_inode = root_inode + // .downcast_arc::() + // .map_err(|_| VfsError::Invalid).unwrap(); + println!("sysfs init success"); + root_dt +} From f20ae0f45e77a52db9c6894d026e136425ceb5a1 Mon Sep 17 00:00:00 2001 From: Godones <1925466036@qq.com> Date: Tue, 16 Jan 2024 22:38:47 +0800 Subject: [PATCH 3/5] feat: Migrate old system to new system delete old kernel code --- Cargo.lock | 86 +- Cargo.toml | 9 +- Makefile | 37 +- boot/Cargo.toml | 29 - boot/build.rs | 32 - boot/src/entry.rs | 45 - boot/src/main.rs | 164 - dep/basemachine/Cargo.toml | 9 - ...73\347\273\237\346\236\266\346\236\204.md" | 2 +- kernel/.gitignore | 2 - kernel/Cargo.toml | 109 +- kernel/build.rs | 51 +- kernel/src/board/common.rs | 37 - kernel/src/board/mod.rs | 100 - kernel/src/board/qemu.rs | 129 - kernel/src/board/unmatched.rs | 50 - kernel/src/board/vf2.rs | 68 - kernel/src/config.rs | 194 - kernel/src/device/block.rs | 82 - kernel/src/device/gpu.rs | 76 - kernel/src/device/input.rs | 137 - kernel/src/device/mod.rs | 268 - kernel/src/device/net.rs | 128 - kernel/src/device/rtc.rs | 136 - kernel/src/device/uart.rs | 168 - kernel/src/driver/block_device.rs | 233 - kernel/src/driver/gpu.rs | 61 - kernel/src/driver/hal.rs | 31 - kernel/src/driver/input.rs | 105 - kernel/src/driver/mod.rs | 9 - kernel/src/driver/net.rs | 18 - kernel/src/driver/rtc.rs | 17 - kernel/src/driver/uart.rs | 181 - kernel/src/fs/basic.rs | 22 +- kernel/src/fs/control.rs | 6 +- kernel/src/fs/dev/mod.rs | 275 - kernel/src/fs/dev/null.rs | 55 - kernel/src/fs/dev/random.rs | 60 - kernel/src/fs/ext.rs | 8 +- kernel/src/fs/file.rs | 278 - kernel/src/fs/link.rs | 1 + kernel/src/fs/mod.rs | 162 +- kernel/src/fs/poll.rs | 15 +- kernel/src/fs/proc/filesystem.rs | 68 - kernel/src/fs/proc/interrupt.rs | 47 - kernel/src/fs/proc/mem.rs | 42 - kernel/src/fs/proc/mod.rs | 52 - kernel/src/fs/proc/mounts.rs | 47 - kernel/src/fs/proc/process.rs | 29 - kernel/src/fs/ram/mod.rs | 82 - kernel/src/fs/select.rs | 5 +- kernel/src/fs/stdio.rs | 11 +- kernel/src/fs/sys/cpu.rs | 48 - kernel/src/fs/sys/info.rs | 87 - kernel/src/fs/sys/mod.rs | 20 - kernel/src/gui.rs | 50 +- kernel/src/interrupt/ext_interrupt.rs | 17 - kernel/src/interrupt/mod.rs | 63 - kernel/src/interrupt/record.rs | 33 - kernel/src/interrupt/timer.rs | 1 - kernel/src/ipc/futex.rs | 2 +- kernel/src/ipc/mod.rs | 12 +- kernel/src/ipc/pipe.rs | 22 +- kernel/src/ipc/shm.rs | 105 +- kernel/src/ipc/signal.rs | 2 +- kernel/src/lib.rs | 53 - {kkernel => kernel}/src/main.rs | 24 +- kernel/src/memory/elf.rs | 150 - kernel/src/memory/frame.rs | 147 - kernel/src/memory/manager.rs | 47 - kernel/src/memory/map.rs | 254 - kernel/src/memory/mod.rs | 151 - kernel/src/memory/vmm.rs | 557 - {kkernel => kernel}/src/mm/elf.rs | 2 +- {kkernel => kernel}/src/mm/loader.rs | 789 +- {kkernel => kernel}/src/mm/map.rs | 9 +- {kkernel => kernel}/src/mm/mod.rs | 39 +- kernel/src/net/addr.rs | 90 +- kernel/src/net/mod.rs | 14 +- kernel/src/net/socket.rs | 470 - kernel/src/net/unix.rs | 31 - kernel/src/panic.rs | 91 - kernel/src/print/console.rs | 133 - kernel/src/print/logging.rs | 41 - kernel/src/print/mod.rs | 12 - kernel/src/sbi.rs | 128 - kernel/src/system.rs | 170 + kernel/src/task/cpu.rs | 10 +- kernel/src/task/heap.rs | 2 + kernel/src/task/mod.rs | 57 +- kernel/src/task/schedule.rs | 7 +- kernel/src/task/stack.rs | 25 +- kernel/src/task/task.rs | 31 +- {kkernel => kernel}/src/time.rs | 526 +- kernel/src/timer/mod.rs | 467 - kernel/src/trace/mod.rs | 57 - kernel/src/trap/context.rs | 13 - kernel/src/trap/exception.rs | 14 +- kernel/src/trap/interrupt.rs | 4 +- kernel/src/trap/mod.rs | 32 +- kkernel/Cargo.toml | 56 - kkernel/build.rs | 32 - kkernel/src/fs/basic.rs | 714 - kkernel/src/fs/control.rs | 263 - kkernel/src/fs/ext.rs | 231 - kkernel/src/fs/file.rs | 278 - kkernel/src/fs/link.rs | 142 - kkernel/src/fs/mod.rs | 96 - kkernel/src/fs/poll.rs | 93 - kkernel/src/fs/select.rs | 220 - kkernel/src/fs/stdio.rs | 27 - kkernel/src/gui.rs | 34 - kkernel/src/ipc/futex.rs | 178 - kkernel/src/ipc/mod.rs | 262 - kkernel/src/ipc/pipe.rs | 387 - kkernel/src/ipc/shm.rs | 283 - kkernel/src/ipc/signal.rs | 404 - kkernel/src/net/mod.rs | 475 - kkernel/src/net/port.rs | 24 - kkernel/src/system.rs | 218 - kkernel/src/task/context.rs | 46 - kkernel/src/task/cpu.rs | 496 - kkernel/src/task/heap.rs | 59 - kkernel/src/task/mod.rs | 96 - kkernel/src/task/schedule.rs | 85 - kkernel/src/task/stack.rs | 33 - kkernel/src/task/switch.asm | 34 - kkernel/src/task/task.rs | 1813 -- kkernel/src/trap/context.rs | 102 - kkernel/src/trap/exception.rs | 158 - kkernel/src/trap/interrupt.rs | 16 - kkernel/src/trap/kernel_v.asm | 47 - kkernel/src/trap/mod.rs | 309 - kkernel/src/trap/trampoline.asm | 83 - subsystems/config/build.rs | 42 +- subsystems/constants/src/lib.rs | 2 +- subsystems/devices/Cargo.toml | 5 +- subsystems/devices/src/lib.rs | 156 +- subsystems/devices/src/net.rs | 90 + subsystems/devices/src/prob.rs | 4 + subsystems/devices/src/rtc.rs | 7 +- subsystems/devices/src/uart.rs | 22 +- subsystems/drivers/Cargo.toml | 5 +- subsystems/drivers/src/block_device.rs | 40 +- subsystems/drivers/src/input.rs | 4 +- subsystems/drivers/src/lib.rs | 20 +- subsystems/drivers/src/net.rs | 2 +- subsystems/drivers/src/rtc.rs | 4 +- subsystems/drivers/src/uart.rs | 2 +- {dep => subsystems}/gmanager/Cargo.toml | 3 - {dep => subsystems}/gmanager/src/lib.rs | 16 +- subsystems/knet/Cargo.toml | 17 + .../src/net => subsystems/knet/src}/addr.rs | 47 +- subsystems/knet/src/lib.rs | 11 + .../src/net => subsystems/knet/src}/port.rs | 0 .../src/net => subsystems/knet/src}/socket.rs | 16 +- .../src/net => subsystems/knet/src}/unix.rs | 3 +- subsystems/mem/src/frame.rs | 29 +- subsystems/mem/src/heap.rs | 146 +- subsystems/mem/src/lib.rs | 12 +- subsystems/mem/src/manager.rs | 106 +- subsystems/mem/src/vmm.rs | 23 +- subsystems/platform/Cargo.toml | 6 +- .../platform/src/basic.rs | 212 +- subsystems/platform/src/common_riscv/boot.rs | 139 +- subsystems/platform/src/console.rs | 5 +- .../platform/src/hifive_riscv/config.rs | 15 +- subsystems/platform/src/hifive_riscv/mod.rs | 4 +- subsystems/platform/src/lib.rs | 31 +- subsystems/platform/src/logging.rs | 1 - subsystems/platform/src/qemu_riscv/config.rs | 26 +- .../platform/src/starfive2_riscv/mod.rs | 4 +- subsystems/timer/src/lib.rs | 6 +- subsystems/unwinder/build.rs | 44 +- subsystems/unwinder/src/kernel_symbol.S | 18255 ++++++++-------- subsystems/unwinder/src/lib.rs | 2 +- subsystems/unwinder/src/panic.rs | 184 +- subsystems/vfs/Cargo.toml | 2 +- subsystems/vfs/src/dev/mod.rs | 10 +- subsystems/vfs/src/kfile.rs | 272 + subsystems/vfs/src/lib.rs | 24 +- subsystems/vfs/src/pipefs.rs | 40 +- subsystems/vfs/src/ram/mod.rs | 1 - 183 files changed, 11863 insertions(+), 25225 deletions(-) delete mode 100644 boot/Cargo.toml delete mode 100644 boot/build.rs delete mode 100644 boot/src/entry.rs delete mode 100644 boot/src/main.rs delete mode 100644 dep/basemachine/Cargo.toml delete mode 100644 kernel/.gitignore delete mode 100644 kernel/src/board/common.rs delete mode 100644 kernel/src/board/mod.rs delete mode 100644 kernel/src/board/qemu.rs delete mode 100644 kernel/src/board/unmatched.rs delete mode 100644 kernel/src/board/vf2.rs delete mode 100644 kernel/src/config.rs delete mode 100644 kernel/src/device/block.rs delete mode 100644 kernel/src/device/gpu.rs delete mode 100644 kernel/src/device/input.rs delete mode 100644 kernel/src/device/mod.rs delete mode 100644 kernel/src/device/net.rs delete mode 100644 kernel/src/device/rtc.rs delete mode 100644 kernel/src/device/uart.rs delete mode 100644 kernel/src/driver/block_device.rs delete mode 100644 kernel/src/driver/gpu.rs delete mode 100644 kernel/src/driver/hal.rs delete mode 100644 kernel/src/driver/input.rs delete mode 100644 kernel/src/driver/mod.rs delete mode 100644 kernel/src/driver/net.rs delete mode 100644 kernel/src/driver/rtc.rs delete mode 100644 kernel/src/driver/uart.rs delete mode 100644 kernel/src/fs/dev/mod.rs delete mode 100644 kernel/src/fs/dev/null.rs delete mode 100644 kernel/src/fs/dev/random.rs delete mode 100644 kernel/src/fs/file.rs delete mode 100644 kernel/src/fs/proc/filesystem.rs delete mode 100644 kernel/src/fs/proc/interrupt.rs delete mode 100644 kernel/src/fs/proc/mem.rs delete mode 100644 kernel/src/fs/proc/mod.rs delete mode 100644 kernel/src/fs/proc/mounts.rs delete mode 100644 kernel/src/fs/proc/process.rs delete mode 100644 kernel/src/fs/ram/mod.rs delete mode 100644 kernel/src/fs/sys/cpu.rs delete mode 100644 kernel/src/fs/sys/info.rs delete mode 100644 kernel/src/fs/sys/mod.rs delete mode 100644 kernel/src/interrupt/ext_interrupt.rs delete mode 100644 kernel/src/interrupt/mod.rs delete mode 100644 kernel/src/interrupt/record.rs delete mode 100644 kernel/src/interrupt/timer.rs delete mode 100644 kernel/src/lib.rs rename {kkernel => kernel}/src/main.rs (90%) delete mode 100644 kernel/src/memory/elf.rs delete mode 100644 kernel/src/memory/frame.rs delete mode 100644 kernel/src/memory/manager.rs delete mode 100644 kernel/src/memory/map.rs delete mode 100644 kernel/src/memory/mod.rs delete mode 100644 kernel/src/memory/vmm.rs rename {kkernel => kernel}/src/mm/elf.rs (100%) rename {kkernel => kernel}/src/mm/loader.rs (96%) rename {kkernel => kernel}/src/mm/map.rs (99%) rename {kkernel => kernel}/src/mm/mod.rs (92%) delete mode 100644 kernel/src/net/socket.rs delete mode 100644 kernel/src/net/unix.rs delete mode 100644 kernel/src/panic.rs delete mode 100644 kernel/src/print/console.rs delete mode 100644 kernel/src/print/logging.rs delete mode 100644 kernel/src/print/mod.rs delete mode 100644 kernel/src/sbi.rs rename {kkernel => kernel}/src/time.rs (97%) delete mode 100644 kernel/src/timer/mod.rs delete mode 100644 kernel/src/trace/mod.rs delete mode 100644 kkernel/Cargo.toml delete mode 100644 kkernel/build.rs delete mode 100644 kkernel/src/fs/basic.rs delete mode 100644 kkernel/src/fs/control.rs delete mode 100644 kkernel/src/fs/ext.rs delete mode 100644 kkernel/src/fs/file.rs delete mode 100644 kkernel/src/fs/link.rs delete mode 100644 kkernel/src/fs/mod.rs delete mode 100644 kkernel/src/fs/poll.rs delete mode 100644 kkernel/src/fs/select.rs delete mode 100644 kkernel/src/fs/stdio.rs delete mode 100644 kkernel/src/gui.rs delete mode 100644 kkernel/src/ipc/futex.rs delete mode 100644 kkernel/src/ipc/mod.rs delete mode 100644 kkernel/src/ipc/pipe.rs delete mode 100644 kkernel/src/ipc/shm.rs delete mode 100644 kkernel/src/ipc/signal.rs delete mode 100644 kkernel/src/net/mod.rs delete mode 100644 kkernel/src/net/port.rs delete mode 100644 kkernel/src/system.rs delete mode 100644 kkernel/src/task/context.rs delete mode 100644 kkernel/src/task/cpu.rs delete mode 100644 kkernel/src/task/heap.rs delete mode 100644 kkernel/src/task/mod.rs delete mode 100644 kkernel/src/task/schedule.rs delete mode 100644 kkernel/src/task/stack.rs delete mode 100644 kkernel/src/task/switch.asm delete mode 100644 kkernel/src/task/task.rs delete mode 100644 kkernel/src/trap/context.rs delete mode 100644 kkernel/src/trap/exception.rs delete mode 100644 kkernel/src/trap/interrupt.rs delete mode 100644 kkernel/src/trap/kernel_v.asm delete mode 100644 kkernel/src/trap/mod.rs delete mode 100644 kkernel/src/trap/trampoline.asm rename {dep => subsystems}/gmanager/Cargo.toml (93%) rename {dep => subsystems}/gmanager/src/lib.rs (91%) create mode 100644 subsystems/knet/Cargo.toml rename {kkernel/src/net => subsystems/knet/src}/addr.rs (63%) create mode 100644 subsystems/knet/src/lib.rs rename {kernel/src/net => subsystems/knet/src}/port.rs (100%) rename {kkernel/src/net => subsystems/knet/src}/socket.rs (98%) rename {kkernel/src/net => subsystems/knet/src}/unix.rs (96%) rename dep/basemachine/src/lib.rs => subsystems/platform/src/basic.rs (95%) create mode 100644 subsystems/vfs/src/kfile.rs diff --git a/Cargo.lock b/Cargo.lock index f01a1655..44607fa7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -140,13 +140,6 @@ version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" -[[package]] -name = "basemachine" -version = "0.1.0" -dependencies = [ - "fdt 0.1.5", -] - [[package]] name = "bit-struct" version = "0.3.2" @@ -200,18 +193,6 @@ dependencies = [ "objc2-encode", ] -[[package]] -name = "boot" -version = "0.1.0" -dependencies = [ - "arch", - "basemachine", - "cfg-if", - "kernel", - "preprint", - "riscv", -] - [[package]] name = "buddy_system_allocator" version = "0.9.0" @@ -664,7 +645,7 @@ dependencies = [ "constants", "device_interface", "drivers", - "fdt 0.2.0-alpha1", + "fdt", "interrupt", "ksync", "log", @@ -728,6 +709,7 @@ dependencies = [ "uart8250", "virtio-drivers 0.5.0 (git+https://github.com/rcore-os/virtio-drivers?rev=de1c3b1)", "virtio-net", + "visionfive2-sd", ] [[package]] @@ -912,12 +894,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "fdt" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67" - [[package]] name = "fdt" version = "0.2.0-alpha1" @@ -1497,43 +1473,29 @@ name = "kernel" version = "0.1.0" dependencies = [ "arch", - "basemachine", "bit_field", "bitflags 1.3.2", - "buddy_system_allocator", - "cfg-if", + "config", "constants", - "devfs", - "downcast-rs", - "dynfs", - "fat-vfs", - "fdt 0.1.5", + "devices", + "drivers", "gmanager", + "interrupt", + "knet", "ksync", "log", - "loopback", - "lru", + "mem", "netcore", "page-table", - "pager", - "plic", - "preprint", - "ramfs", + "platform", "riscv", - "rslab", - "rtc", - "smoltcp", "smpscheduler", "spin", "syscall-table", - "talc 1.0.0", - "tracer", - "uart16550", - "uart8250", + "timer", + "unwinder", + "vfs", "vfscore", - "virtio-drivers 0.5.0 (git+https://github.com/rcore-os/virtio-drivers?rev=de1c3b1)", - "virtio-net", - "visionfive2-sd", "xmas-elf", ] @@ -1547,34 +1509,15 @@ dependencies = [ ] [[package]] -name = "kkernel" +name = "knet" version = "0.1.0" dependencies = [ - "arch", - "bit_field", - "bitflags 1.3.2", - "config", "constants", - "devices", - "downcast-rs", - "drivers", - "gmanager", - "interrupt", "ksync", "log", - "mem", "netcore", - "page-table", - "platform", - "riscv", - "smpscheduler", - "spin", - "syscall-table", - "timer", - "unwinder", "vfs", "vfscore", - "xmas-elf", ] [[package]] @@ -2237,8 +2180,8 @@ name = "platform" version = "0.1.0" dependencies = [ "arch", - "basemachine", "config", + "fdt", "ksync", "log", "preprint", @@ -3401,6 +3344,7 @@ dependencies = [ "constants", "devfs", "devices", + "downcast-rs", "dynfs", "fat-vfs", "interrupt", diff --git a/Cargo.toml b/Cargo.toml index 4032dfb6..40d769f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,7 @@ resolver = "2" members = [ "kernel", "userlib", - "boot", - "dep/gmanager", - "dep/basemachine", + "subsystems/gmanager", "apps/slint-helper", "apps/cat", "apps/sleep", @@ -37,8 +35,9 @@ members = [ "subsystems/interrupt", "subsystems/device_interface", "subsystems/timer", - "kkernel" - , "subsystems/unwinder",] + "kernel", + "subsystems/unwinder", + "subsystems/knet",] [profile.release] diff --git a/Makefile b/Makefile index 0c910f33..4d6793a3 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ TRACE_EXE := trace_exe TARGET := riscv64gc-unknown-none-elf OUTPUT := target/$(TARGET)/release -KERNEL_FILE := $(OUTPUT)/boot +KERNEL_FILE := $(OUTPUT)/kernel DEBUG_FILE ?= $(KERNEL_FILE) KERNEL_ENTRY_PA := 0x80200000 OBJDUMP := rust-objdump --arch-name=riscv64 @@ -17,7 +17,7 @@ NET ?=y APPS_NAME := $(shell cd apps && ls -d */ | cut -d '/' -f 1) VF2 ?=n -CV1811h ?=n +UNMATCHED ?=n FEATURES := QEMU_ARGS := MEMORY_SIZE := 1024M @@ -30,8 +30,6 @@ comma:= , empty:= space:= $(empty) $(empty) -CARGO_FLAGS := -Zbuild-std=core,compiler_builtins,alloc \ - -Zbuild-std-features=compiler-builtins-mem ifeq ($(GUI),y) QEMU_ARGS += -device virtio-gpu-device \ @@ -44,10 +42,8 @@ endif ifeq ($(VF2),y) FEATURES += vf2 -else ifeq ($(CV1811h),y) -FEATURES += cv1811h else ifeq ($(UNMATCHED),y) -FEATURES += hifive +FEATURES += hifive ramdisk else FEATURES += qemu endif @@ -90,22 +86,15 @@ else endif -build:install compile2 #compile - +build:install compile compile: - cargo build --release -p boot --target $(TARGET) --features $(FEATURES) - @(nm -n ${KERNEL_FILE} | $(TRACE_EXE) > kernel/src/trace/kernel_symbol.S) + cargo build --release -p kernel --target $(TARGET) --features $(FEATURES) + (nm -n ${KERNEL_FILE} | $(TRACE_EXE) > subsystems/unwinder/src/kernel_symbol.S) @#call trace_info - cargo build --release -p boot --target $(TARGET) --features $(FEATURES) + cargo build --release -p kernel --target $(TARGET) --features $(FEATURES) @#$(OBJCOPY) $(KERNEL_FILE) --strip-all -O binary $(KERNEL_BIN) - @cp $(KERNEL_FILE) ./kernel-qemu - -compile2: - cargo build --release -p kkernel --target $(TARGET) --features $(FEATURES) - @(nm -n ${KERNEL_FILE} | $(TRACE_EXE) > subsystems/unwinder/src/kernel_symbol.S) - cargo build --release -p boot --target $(TARGET) --features $(FEATURES) - @cp $(OUTPUT)/kkernel ./kernel-qemu + cp $(KERNEL_FILE) ./kernel-qemu trace_info: @(nm -n ${KERNEL_FILE} | $(TRACE_EXE) > kernel/src/trace/kernel_symbol.S) @@ -142,11 +131,6 @@ vf2:board @cp ./alien-vf2.itb /home/godones/projects/tftpboot/ -cv1811h:board - @mkimage -f ./tools/cv1811h.its ./alien-cv1811h.itb - @rm ./kernel-qemu - @cp ./alien-cv1811h.itb /home/godones/projects/tftpboot/ - unmatched:board @mkimage -f ./tools/fu740.its ./alien-unmatched.itb @rm ./kernel-qemu @@ -227,9 +211,8 @@ docs: cargo doc --open -p kernel --target riscv64gc-unknown-none-elf --features $(FEATURES) clean: @cargo clean - @rm riscv.* - @rm kernel-qemu - @rm alien-* + @-rm kernel-qemu + @-rm alien-* check: diff --git a/boot/Cargo.toml b/boot/Cargo.toml deleted file mode 100644 index 9781b1b3..00000000 --- a/boot/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "boot" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -cfg-if = "1.0.0" -riscv = "0.10.0" -preprint = "0.1.0" -basemachine = { path = "../dep/basemachine" } -kernel = { version = "0.1.0", path = "../kernel" } - - -arch = { path = "../subsystems/arch" } - -[features] -default = [] -vf2 = ["kernel/vf2"] -cv1811h = ["kernel/cv1811h"] -qemu = ["kernel/qemu"] -hifive = ["kernel/hifive"] - -slab = ["kernel/slab"] -talloc = ["kernel/talloc"] -buddy = ["kernel/buddy"] - -[build-dependencies] diff --git a/boot/build.rs b/boot/build.rs deleted file mode 100644 index 63c386fe..00000000 --- a/boot/build.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::fs::File; -use std::io::Write; -use std::path::Path; -use std::{env, fs}; - -fn main() { - // 指定target - let outdir = env::var("OUT_DIR").unwrap(); - let link_script = Path::new(&outdir).join("link.lds"); - let mut script = File::create(&link_script).unwrap(); - - let ld_path = Path::new("../tools/link.ld"); - let ld = fs::read_to_string(ld_path).unwrap(); - - #[cfg(not(feature = "vf2"))] - let base_addr = 0x80200000usize; - #[cfg(feature = "vf2")] - let base_addr: usize = 0x40200000; - let base_addr = format!("BASE_ADDRESS = {};", base_addr); - let mut new_config = String::new(); - for line in ld.lines() { - if line.starts_with("BASE_ADDRESS = ") { - new_config.push_str(base_addr.as_str()); - } else { - new_config.push_str(line); - new_config.push_str("\n"); - } - } - - script.write_all(new_config.as_bytes()).unwrap(); - println!("cargo:rustc-link-arg=-T{}", &link_script.display()); -} diff --git a/boot/src/entry.rs b/boot/src/entry.rs deleted file mode 100644 index 0e25fa1e..00000000 --- a/boot/src/entry.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! 内核汇编入口 -use core::arch::asm; - -use kernel::config::{CPU_NUM, STACK_SIZE}; - -#[link_section = ".bss.stack"] -pub static mut STACK: [u8; STACK_SIZE * CPU_NUM] = [0; STACK_SIZE * CPU_NUM]; - -/// 内核入口 -/// -/// 用于初始化内核的栈空间,并关闭中断 -#[naked] -#[no_mangle] -#[link_section = ".text.entry"] -extern "C" fn _start() { - unsafe { - asm!("\ - mv tp, a0 - csrw sscratch, a1 - add t0, a0, 1 - slli t0, t0, 16 - la sp, {boot_stack} - add sp, sp, t0 - call main - ", - boot_stack = sym STACK, - options(noreturn) - ); - } -} - -/// 获取设备树地址 -/// 在开始阶段,内核会将设备树的地址保存在sscratch寄存器中 -#[allow(unused)] -#[inline] -pub fn device_tree_addr() -> usize { - let mut res: usize; - unsafe { - asm!( - " csrr {}, sscratch", - out(reg) res, - ) - } - res -} diff --git a/boot/src/main.rs b/boot/src/main.rs deleted file mode 100644 index 66793715..00000000 --- a/boot/src/main.rs +++ /dev/null @@ -1,164 +0,0 @@ -//! 内核启动模块 -//! -//! 该模块主要完成以下功能: -//! 1. 初始化内核的栈空间 -//! 2. 清空.bss段 -//! 3. 从设备树中获取基本的信息 -//! 4. 初始化内存子系统 -//! 5. 初始化中断子系统 -//! 6. 初始化系统调用 -//! 7. 初始化进程子系统 -//! 8. 初始化文件系统 -//! 9. 初始化设备子系统 -//! 10. 主核唤醒其它核 - -#![no_std] -#![no_main] -#![feature(naked_functions)] -#![feature(asm_const)] -#![feature(stmt_expr_attributes)] -#![deny(missing_docs)] - -use core::hint::spin_loop; -use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; - -use cfg_if::cfg_if; -use kernel::init_init_array; - -use arch::hart_id; -use basemachine::machine_info_from_dtb; -#[cfg(not(feature = "qemu"))] -use kernel::board; -#[cfg(any( - feature = "vf2", - feature = "qemu", - feature = "hifive", - feature = "cv1811h" -))] -use kernel::board::init_dtb; -use kernel::config::CPU_NUM; -use kernel::device::init_device; -use kernel::fs::init_filesystem; -use kernel::interrupt::init_plic; -use kernel::memory::{init_memory_system, kernel_info}; -use kernel::print::init_print; -use kernel::sbi::hart_start; -use kernel::{config, init_machine_info, println, task, timer, trap}; - -mod entry; - -/// 多核启动标志 -static STARTED: AtomicBool = AtomicBool::new(false); -/// cpu启动计数 -static CPUS: AtomicUsize = AtomicUsize::new(0); - -extern "C" { - fn _start(); - fn sbss(); - fn ebss(); -} - -/// 清空.bss段 -#[inline] -fn clear_bss() { - unsafe { - core::slice::from_raw_parts_mut(sbss as usize as *mut u8, ebss as usize - sbss as usize) - .fill(0); - } -} - -/// 内核位于高级语言的入口 -#[no_mangle] -pub fn main(_: usize, _: usize) -> ! { - if !STARTED.load(Ordering::Relaxed) { - clear_bss(); - println!("{}", config::FLAG); - cfg_if! { - if #[cfg(not(feature = "qemu"))] { - let device_tree_addr = board::FDT.as_ptr() as usize; - }else{ - use crate::entry::device_tree_addr; - let device_tree_addr = device_tree_addr(); - } - } - init_print(); - println!( - "boot hart id: {}, device tree addr: {:#x}", - hart_id(), - device_tree_addr - ); - let machine_info = machine_info_from_dtb(device_tree_addr); - println!("{:#x?}", machine_info); - init_machine_info(machine_info.clone()); - kernel_info(machine_info.memory.end); - init_memory_system(machine_info.memory.end, true); - arch::allow_access_user_memory(); - // init device tree - #[cfg(feature = "qemu")] - init_dtb(Some(device_tree_addr)); - #[cfg(feature = "vf2")] - init_dtb(None); - // init plic associate board - init_plic(); - // init all device - init_device(); - trap::init_trap_subsystem(); - init_filesystem().expect("Init filesystem failed"); - task::init_process(); - // register all syscall - init_init_array!(); - CPUS.fetch_add(1, Ordering::Release); - STARTED.store(true, Ordering::Relaxed); - init_other_hart(hart_id()); - } else { - while !STARTED.load(Ordering::Relaxed) { - spin_loop(); - } - arch::allow_access_user_memory(); - println!("hart {:#x} start", hart_id()); - init_memory_system(0, false); - trap::init_trap_subsystem(); - CPUS.fetch_add(1, Ordering::Release); - } - timer::set_next_trigger(); - println!("Begin run task..."); - task::schedule::first_into_user(); -} - -/// 唤醒其它核 -/// -/// 对于qemu来说,只需要工具所有的核都是一样的,因此从严号核开始唤醒。 -/// 对于visionfive2/unmatched 来说,0号核只有M态,因此不进行唤醒 -fn init_other_hart(hart_id: usize) { - cfg_if! { - if #[cfg(any(feature="vf2",feature = "hifive"))]{ - let start_hart = 1; - }else { - let start_hart = 0; - } - } - for i in start_hart..CPU_NUM { - if i != hart_id { - let res = hart_start(i, _start as usize, 0); - assert_eq!(res.error, 0); - } - } - wait_all_cpu_start(); -} - -/// 等待其它cpu核启动 -/// -/// 对于visionfive2/unmatched 来说,我们使用make SMP=2 来进行单核启动,这里针对这个情况做了处理 -fn wait_all_cpu_start() { - cfg_if! { - if #[cfg(any(feature="vf2",feature = "hifive"))]{ - let cpu_num = CPU_NUM - 1; - }else { - let cpu_num = CPU_NUM; - } - } - while CPUS.load(Ordering::Acquire) < cpu_num { - spin_loop() - } - println!("All cpu start"); -} diff --git a/dep/basemachine/Cargo.toml b/dep/basemachine/Cargo.toml deleted file mode 100644 index ce04ac4b..00000000 --- a/dep/basemachine/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "basemachine" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -fdt = "0.1.5" \ No newline at end of file diff --git "a/docs/doc/\347\263\273\347\273\237\346\236\266\346\236\204.md" "b/docs/doc/\347\263\273\347\273\237\346\236\266\346\236\204.md" index 619320f9..9d47c085 100644 --- "a/docs/doc/\347\263\273\347\273\237\346\236\266\346\236\204.md" +++ "b/docs/doc/\347\263\273\347\273\237\346\236\266\346\236\204.md" @@ -50,7 +50,7 @@ - [Godones/doubly-linked-list](https://github.com/Godones/doubly-linked-list) **侵入式双向链表** - [Godones/dbfs2](https://github.com/Godones/dbfs2) **高性能数据库文件系统** - [module/basemachine](../../dep/basemachine) **设备树机器基本信息** -- [module/gmanager](../../dep/gmanager) **最小索引分配管理** +- [module/gmanager](../../subsystems/gmanager) **最小索引分配管理** - [module/Input2event](../../dep/input2event) **virtio输入事件转换** - [module/pager](../modules/pager) **物理页管理** - [module/plic](../modules/plic) **riscv平台控制器驱动** diff --git a/kernel/.gitignore b/kernel/.gitignore deleted file mode 100644 index c7256db4..00000000 --- a/kernel/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.idea -src/trace/kernel_symbol.S \ No newline at end of file diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 113131b9..ce3684a5 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -2,91 +2,58 @@ name = "kernel" version = "0.1.0" edition = "2021" -authors = ["chen linfeng"] -[dependencies] -log = "0.4" -spin = "0.9" -riscv = "0.10" -bit_field = "0.10" -xmas-elf = "0.9" -bitflags = "1.3.2" -virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers",rev = "de1c3b1"} -fdt = "0.1.3" -rtc = { git = "https://github.com/os-module/rtc.git" } -lru = "0.10.0" +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -cfg-if = "1.0.0" -page-table = { git = "https://github.com/os-module/page-table.git", branch = "dev" } +[dependencies] +arch = { path = "../subsystems/arch" } +platform = { path = "../subsystems/platform" } +mem = { path = "../subsystems/mem" } +interrupt = { path = "../subsystems/interrupt" } +devices = { path = "../subsystems/devices" } +drivers = { path = "../subsystems/drivers" } +unwinder = { path = "../subsystems/unwinder" } +constants = { path = "../subsystems/constants" } +config = { path = "../subsystems/config" } +vfs = { path = "../subsystems/vfs" } +timer = { path = "../subsystems/timer" } +ksync = { path = "../subsystems/ksync" } +knet = { path = "../subsystems/knet" } +gmanager = { path = "../subsystems/gmanager" } -visionfive2-sd = { git = "https://github.com/os-module/visionfive2-sd.git", optional = true } -tracer = { git = "https://github.com/os-module/tracer" } -preprint = "0.1.0" -rslab = { version = "0.2.1", optional = true } -syscall-table = { git = "https://github.com/os-module/syscall-table.git" } -plic = { git = "https://github.com/os-module/plic" } -pager = { git = "https://github.com/os-module/pager", default-features = false, optional = true } -gmanager = { path = "../dep/gmanager" } -basemachine = { path = "../dep/basemachine" } -uart16550 = { version = "0.0.1", optional = true } -uart8250 = { git = "https://github.com/os-module/uart-rs.git", optional = true } -smpscheduler = { git = "https://github.com/os-module/smpscheduler.git" } -talc = { version = "1.0", optional = true } -buddy_system_allocator = { version = "0.9.0", optional = true } -downcast-rs = { version = "1.2.0", default-features = false } +riscv = "0.10" +bit_field = "0.10" +xmas-elf = "0.9" +bitflags = "1.3" +spin = "0" +log = "0" vfscore = { git = "https://github.com/os-module/rvfs.git", features = [ "linux_error", ] } -devfs = { git = "https://github.com/os-module/rvfs.git" } -dynfs = { git = "https://github.com/os-module/rvfs.git" } -ramfs = { git = "https://github.com/os-module/rvfs.git" } -fat-vfs = { git = "https://github.com/os-module/rvfs.git" } - - -loopback = {git = "https://github.com/os-module/simple-net",optional = true} -virtio-net = {git = "https://github.com/os-module/simple-net"} +syscall-table = { git = "https://github.com/os-module/syscall-table.git" } +smpscheduler = { git = "https://github.com/os-module/smpscheduler.git" } +page-table = { git = "https://github.com/os-module/page-table.git", branch = "dev" } netcore = {git = "https://github.com/os-module/simple-net"} -arch = { path = "../subsystems/arch"} -ksync = {path = "../subsystems/ksync"} -constants = {path = "../subsystems/constants" } - - -[dependencies.smoltcp] -git = "https://github.com/rcore-os/smoltcp.git" -rev = "2ade274" -default-features = false -features = [ - "alloc", - "log", # no std - "medium-ethernet", - "proto-ipv4", - "socket-raw", - "socket-icmp", - "socket-udp", - "socket-tcp", - "socket-dns", -] [features] -default = ["pager_bitmap","test"] -vf2 = ["visionfive2-sd", "uart8250"] -cv1811h = [] -hifive = ["uart16550"] -qemu = ["uart16550"] -net_test = [] +default = ["smp","test"] +qemu = ["platform/qemu_riscv","interrupt/qemu"] +vf2 = ["platform/vf2","interrupt/vf2", "devices/vf2"] +hifive = ["platform/hifive","interrupt/hifive"] +smp = ["platform/smp"] + -slab = ["rslab"] -talloc = ["talc"] -buddy = ["buddy_system_allocator"] +slab = [] +talloc = [] +buddy = [] -pager_buddy = ["pager/buddy"] -pager_bitmap = ["pager/bitmap"] +pager_buddy = ["mem/pager_buddy"] +pager_bitmap = ["mem/pager_bitmap"] -test = ["loopback"] -debug-eh-frame = [] -debug-frame-pointer = [] +ramdisk = ["devices/ramdisk"] +test = ["devices/test"] \ No newline at end of file diff --git a/kernel/build.rs b/kernel/build.rs index 0449bc84..63c386fe 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -1,45 +1,32 @@ use std::fs::File; use std::io::Write; use std::path::Path; -use std::string::String; -use std::{format, fs}; +use std::{env, fs}; fn main() { - println!("cargo:rerun-if-changed={}", "src/"); - let path = Path::new("src/trace/kernel_symbol.S"); - if !path.exists() { - let mut file = File::create(path).unwrap(); - write!(file, ".section .rodata\n").unwrap(); - write!(file, ".align 3\n").unwrap(); - write!(file, ".global symbol_num\n").unwrap(); - write!(file, ".global symbol_address\n").unwrap(); - write!(file, ".global symbol_index\n").unwrap(); - write!(file, ".global symbol_name\n").unwrap(); - write!(file, "symbol_num:\n").unwrap(); - write!(file, ".quad {}\n", 0).unwrap(); - write!(file, "symbol_address:\n").unwrap(); - write!(file, "symbol_index:\n").unwrap(); - write!(file, "symbol_name:\n").unwrap(); - } - rewrite_config(); -} + // 指定target + let outdir = env::var("OUT_DIR").unwrap(); + let link_script = Path::new(&outdir).join("link.lds"); + let mut script = File::create(&link_script).unwrap(); -pub fn rewrite_config() { - let cpus = option_env!("SMP").unwrap_or("1"); - let cpus = cpus.parse::().unwrap(); - let config_file = Path::new("src/config.rs"); - let config = fs::read_to_string(config_file).unwrap(); - let cpus = format!("pub const CPU_NUM: usize = {};\n", cpus); - // let regex = regex::Regex::new(r"pub const CPU_NUM: usize = \d+;").unwrap(); - // config = regex.replace_all(&config, cpus.as_str()).to_string(); + let ld_path = Path::new("../tools/link.ld"); + let ld = fs::read_to_string(ld_path).unwrap(); + + #[cfg(not(feature = "vf2"))] + let base_addr = 0x80200000usize; + #[cfg(feature = "vf2")] + let base_addr: usize = 0x40200000; + let base_addr = format!("BASE_ADDRESS = {};", base_addr); let mut new_config = String::new(); - for line in config.lines() { - if line.starts_with("pub const CPU_NUM: usize = ") { - new_config.push_str(cpus.as_str()); + for line in ld.lines() { + if line.starts_with("BASE_ADDRESS = ") { + new_config.push_str(base_addr.as_str()); } else { new_config.push_str(line); new_config.push_str("\n"); } } - fs::write(config_file, new_config).unwrap(); + + script.write_all(new_config.as_bytes()).unwrap(); + println!("cargo:rustc-link-arg=-T{}", &link_script.display()); } diff --git a/kernel/src/board/common.rs b/kernel/src/board/common.rs deleted file mode 100644 index 59dd7e55..00000000 --- a/kernel/src/board/common.rs +++ /dev/null @@ -1,37 +0,0 @@ -use fdt::node::FdtNode; -use fdt::Fdt; - -pub fn get_device_info(fdt: &Fdt, device_name: &str) -> Option<(usize, usize)> { - let res = fdt - .all_nodes() - .find(|node| node.name.starts_with(device_name)); - let res = res.and_then(|node| { - if let Some(reg) = node.reg().and_then(|mut reg| reg.next()) { - let addr = reg.starting_address as usize; - if let Some(mut interrupts) = node.interrupts() { - let irq = interrupts.next().unwrap(); - return Some((addr, irq)); - } else { - None - } - } else { - None - } - }); - res -} - -#[allow(unused)] -pub fn get_device_info_from_node(node: &FdtNode) -> Option<(usize, usize)> { - if let Some(reg) = node.reg().and_then(|mut reg| reg.next()) { - let addr = reg.starting_address as usize; - if let Some(mut interrupts) = node.interrupts() { - let irq = interrupts.next().unwrap(); - Some((addr, irq)) - } else { - None - } - } else { - None - } -} diff --git a/kernel/src/board/mod.rs b/kernel/src/board/mod.rs deleted file mode 100644 index 399a874b..00000000 --- a/kernel/src/board/mod.rs +++ /dev/null @@ -1,100 +0,0 @@ -use alloc::collections::BTreeMap; - -use cfg_if::cfg_if; - -use ksync::Mutex; - -use crate::device::{DeviceInfo, DeviceType}; - -mod common; - -pub static BOARD_DEVICES: Mutex> = Mutex::new(BTreeMap::new()); - -pub fn get_rtc_info() -> Option<(usize, usize)> { - if let Some(rtc) = BOARD_DEVICES.lock().get(&DeviceType::Rtc) { - return Some((rtc.base_addr, rtc.irq)); - } - None -} - -pub fn get_uart_info() -> Option<(usize, usize)> { - if let Some(uart) = BOARD_DEVICES.lock().get(&DeviceType::Uart) { - return Some((uart.base_addr, uart.irq)); - } - None -} - -pub fn get_gpu_info() -> Option<(usize, usize)> { - if let Some(gpu) = BOARD_DEVICES.lock().get(&DeviceType::GPU) { - return Some((gpu.base_addr, gpu.irq)); - } - None -} - -pub fn get_keyboard_info() -> Option<(usize, usize)> { - if let Some(keyboard) = BOARD_DEVICES.lock().get(&DeviceType::KeyBoardInput) { - return Some((keyboard.base_addr, keyboard.irq)); - } - None -} - -pub fn get_mouse_info() -> Option<(usize, usize)> { - if let Some(mouse) = BOARD_DEVICES.lock().get(&DeviceType::MouseInput) { - return Some((mouse.base_addr, mouse.irq)); - } - None -} - -pub fn get_block_device_info() -> Option<(usize, usize)> { - if let Some(block) = BOARD_DEVICES.lock().get(&DeviceType::Block) { - return Some((block.base_addr, block.irq)); - } - None -} - -pub fn get_net_device_info() -> Option<(usize, usize)> { - if let Some(net) = BOARD_DEVICES.lock().get(&DeviceType::Network) { - return Some((net.base_addr, net.irq)); - } - None -} - -cfg_if! { - if #[cfg(feature="qemu")]{ - mod qemu; - pub use qemu::*; - }else if #[cfg(feature="hifive")]{ - mod unmatched; - pub use unmatched::*; - }else if #[cfg(feature="vf2")]{ - mod vf2; - pub use vf2::*; - } -} - -cfg_if! { - if #[cfg(any(feature = "vf2", feature = "hifive"))]{ - core::arch::global_asm!(r#" - .section .data - .global img_start - .global img_end - .align 12 - img_start: - .incbin "./tools/sdcard.img" - img_end: - "#); - extern "C" { - pub fn img_start(); - pub fn img_end(); - } - pub fn checkout_fs_img() { - let img_start = img_start as usize; - let img_end = img_end as usize; - let img_size = img_end - img_start; - println!( - "img_start: {:#x}, img_end: {:#x}, img_size: {:#x}", - img_start, img_end, img_size - ); - } - } -} diff --git a/kernel/src/board/qemu.rs b/kernel/src/board/qemu.rs deleted file mode 100644 index 0d21b187..00000000 --- a/kernel/src/board/qemu.rs +++ /dev/null @@ -1,129 +0,0 @@ -use core::ptr::NonNull; - -use fdt::node::FdtNode; -use fdt::standard_nodes::Compatible; -use fdt::Fdt; -use spin::Once; -use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; -use virtio_drivers::transport::{DeviceType as VirtDeviceType, Transport}; - -use crate::board::common::get_device_info; -use crate::board::BOARD_DEVICES; -use crate::device::DeviceInfo; -use crate::device::DeviceType; - -pub static DTB: Once = Once::new(); - -pub fn init_dtb(dtb: Option) { - let fdt = if dtb.is_some() { - unsafe { Fdt::from_ptr(dtb.unwrap() as *const u8).unwrap() } - } else { - panic!("No dtb found") - }; - DTB.call_once(|| fdt); -} - -/// Get the base address and irq number of the uart device from the device tree. -pub fn probe_devices_from_dtb() { - if let Some(rtc) = probe_rtc() { - BOARD_DEVICES.lock().insert(DeviceType::Rtc, rtc); - } - if let Some(uart) = probe_uart() { - BOARD_DEVICES.lock().insert(DeviceType::Uart, uart); - } - find_virtio_device(DTB.get().unwrap()); -} - -/// Get the base address and irq number of the uart device from the device tree. -pub fn probe_rtc() -> Option { - let fdt = DTB.get().unwrap(); - let res = get_device_info(fdt, "rtc"); - res.map(|(base_addr, irq)| DeviceInfo::new(base_addr, irq)) -} - -/// Get the base address and irq number of the uart device from the device tree. -pub fn probe_uart() -> Option { - let fdt = DTB.get().unwrap(); - if let Some((base_addr, irq)) = get_device_info(fdt, "uart") { - return Some(DeviceInfo::new(base_addr, irq)); - } - None -} - -fn find_virtio_device(fdt: &Fdt) -> Option<(usize, usize)> { - for node in fdt.all_nodes() { - if node.name.starts_with("virtio_mmio") { - if let Some((device_type, info)) = virtio_probe(&node) { - BOARD_DEVICES.lock().insert(device_type, info); - } - } - } - None -} - -// keyboard -const VIRTIO5: usize = 0x10005000; -// mouse -const VIRTIO6: usize = 0x10006000; - -fn virtio_probe(node: &FdtNode) -> Option<(DeviceType, DeviceInfo)> { - if let Some(reg) = node.reg().and_then(|mut reg| reg.next()) { - let paddr = reg.starting_address as usize; - let size = reg.size.unwrap(); - let vaddr = paddr; - info!("walk dt addr={:#x}, size={:#x}", paddr, size); - info!( - "Device tree node {}: {:?}", - node.name, - node.compatible().map(Compatible::first), - ); - let irq = if let Some(mut interrupts) = node.interrupts() { - let irq = interrupts.next().unwrap(); - irq - } else { - 0 - }; - - let header = NonNull::new(vaddr as *mut VirtIOHeader).unwrap(); - match unsafe { MmioTransport::new(header) } { - Err(_) => {} - Ok(mut transport) => { - info!( - "Detected virtio MMIO device with vendor id {:#X}, device type {:?}, version {:?}, features:{:?}", - transport.vendor_id(), - transport.device_type(), - transport.version(), - transport.read_device_features(), - ); - info!("Probe virtio device: {:?}", transport.device_type()); - return match transport.device_type() { - VirtDeviceType::Input => { - let device_info = DeviceInfo::new(paddr, irq); - let res = if paddr == VIRTIO5 { - Some((DeviceType::KeyBoardInput, device_info)) - } else if paddr == VIRTIO6 { - Some((DeviceType::MouseInput, device_info)) - } else { - None - }; - res - } - VirtDeviceType::Block => { - let device_info = DeviceInfo::new(paddr, irq); - Some((DeviceType::Block, device_info)) - } - VirtDeviceType::GPU => { - let device_info = DeviceInfo::new(paddr, irq); - Some((DeviceType::GPU, device_info)) - } - VirtDeviceType::Network => { - let device_info = DeviceInfo::new(paddr, irq); - Some((DeviceType::Network, device_info)) - } - _ => None, - }; - } - } - } - None -} diff --git a/kernel/src/board/unmatched.rs b/kernel/src/board/unmatched.rs deleted file mode 100644 index c387ccb6..00000000 --- a/kernel/src/board/unmatched.rs +++ /dev/null @@ -1,50 +0,0 @@ -use alloc::vec::Vec; -use fdt::Fdt; -use spin::Once; - -use crate::board::common::get_device_info; - -#[repr(align(4))] -struct _Wrapper(T); - -pub const FDT: &[u8] = &_Wrapper(*include_bytes!("../../../tools/hifive-unmatched-a00.dtb")).0; - -pub static DTB: Once = Once::new(); - -pub fn init_dtb(dtb: Option) { - let fdt = if dtb.is_some() { - unsafe { Fdt::from_ptr(dtb as *const u8).unwrap() } - } else { - unsafe { Fdt::from_ptr(FDT.as_ptr()).unwrap() } - }; - DTB.call_once(|| fdt); -} - -/// Get the base address and irq number of the uart device from the device tree. -pub fn probe_devices_from_dtb() { - if let Some(rtc) = probe_rtc() { - BOARD_DEVICES.lock().insert(DeviceType::Rtc, rtc); - } - if let Some(uart) = probe_uart() { - BOARD_DEVICES.lock().insert(DeviceType::Uart, uart); - } -} - -/// Get the base address and irq number of the uart device from the device tree. -pub fn probe_rtc() -> Option { - let fdt = DTB.get().unwrap(); - let res = get_device_info(fdt, "rtc"); - if res.is_none() { - return None; - } - let (base_addr, irq) = res.unwrap(); - Some(DeviceInfo::new(base_addr, irq)) -} - -pub fn probe_uart() -> Option { - let fdt = DTB.get().unwrap(); - if let Some((base_addr, irq)) = get_device_info(fdt, "serial") { - return Some(DeviceInfo::new(base_addr, irq)); - } - None -} diff --git a/kernel/src/board/vf2.rs b/kernel/src/board/vf2.rs deleted file mode 100644 index 670334ce..00000000 --- a/kernel/src/board/vf2.rs +++ /dev/null @@ -1,68 +0,0 @@ -use core::ops::Range; - -use fdt::Fdt; -use spin::Once; - -use crate::board::BOARD_DEVICES; -use crate::device::{DeviceInfo, DeviceType}; - -#[repr(align(4))] -struct _Wrapper(T); - -pub const FDT: &[u8] = &_Wrapper(*include_bytes!("../../../tools/jh7110-visionfive-v2.dtb")).0; - -pub static DTB: Once = Once::new(); - -pub fn init_dtb(dtb: Option) { - let fdt = if dtb.is_some() { - assert_eq!(dtb.unwrap(), FDT.as_ptr() as usize); - unsafe { Fdt::from_ptr(dtb.unwrap() as *const u8).unwrap() } - } else { - unsafe { Fdt::from_ptr(FDT.as_ptr()).unwrap() } - }; - DTB.call_once(|| fdt); -} - -/// Get the base address and irq number of the uart device from the device tree. -pub fn probe_devices_from_dtb() { - if let Some(rtc) = probe_rtc() { - BOARD_DEVICES.lock().insert(DeviceType::Rtc, rtc); - } - if let Some(uart) = probe_uart() { - BOARD_DEVICES.lock().insert(DeviceType::Uart, uart); - } -} - -/// Get the base address and irq number of the uart device from the device tree. -pub fn probe_rtc() -> Option { - let fdt = DTB.get().unwrap(); - let node = fdt.all_nodes().find(|node| node.name.starts_with("rtc")); - assert!(node.is_some()); - let node = node.unwrap(); - let reg = node.reg().unwrap().next().unwrap(); - let range = Range { - start: reg.starting_address as usize, - end: reg.starting_address as usize + reg.size.unwrap(), - }; - // let irq = node.property("interrupts").unwrap().value; - // let irq = u32::from_be_bytes(irq.try_into().unwrap()); - let irq = 0xa; - Some(DeviceInfo::new(range.start, irq as usize)) -} - -/// Get the base address and irq number of the uart device from the device tree. -/// -/// Return: -/// (base addr, irq) -pub fn probe_uart() -> Option { - let fdt = DTB.get().unwrap(); - // get_device_info(fdt, "serial") - let node = fdt.all_nodes().find(|node| node.name.starts_with("serial")); - assert!(node.is_some()); - let node = node.unwrap(); - let mut reg = node.reg().unwrap(); - let irq = node.property("interrupts").unwrap().value; - let irq = u32::from_be_bytes(irq.try_into().unwrap()); - let base_addr = reg.next().unwrap().starting_address as usize; - Some(DeviceInfo::new(base_addr, irq as usize)) -} diff --git a/kernel/src/config.rs b/kernel/src/config.rs deleted file mode 100644 index 8acd8202..00000000 --- a/kernel/src/config.rs +++ /dev/null @@ -1,194 +0,0 @@ -//! 配置文件 - -/// Alien os的标志 -pub const FLAG: &str = r" - _ _ _ - / \ | | (_) ___ _ __ - / _ \ | | | | / _ \ | '_ \ - / ___ \ | | | | | __/ | | | | - /_/ \_\ |_| |_| \___| |_| |_| -"; - -/// qemu时钟频率 -#[cfg(feature = "qemu")] -pub const CLOCK_FREQ: usize = 1250_0000; -/// vf2时钟频率 -#[cfg(feature = "vf2")] -pub const CLOCK_FREQ: usize = 400_0000; - -/// unmatched时钟频率 -#[cfg(feature = "hifive")] -pub const CLOCK_FREQ: usize = 100_0000; - -/// cv1811h时钟频率 -#[cfg(feature = "cv1811h")] -pub const CLOCK_FREQ: usize = 0x17d7840; - -/// 物理页大小 -pub const FRAME_SIZE: usize = 0x1000; -/// 物理页大小的位数 -pub const FRAME_BITS: usize = 12; -/// 内核启动栈大小 -pub const STACK_SIZE: usize = 1024 * 64; -/// 内核启动栈大小的位数 -pub const STACK_SIZE_BITS: usize = 16; - -/// equal to CLOCK_FREQ -pub const TIMER_FREQ: usize = CLOCK_FREQ; -/// 可配置的启动cpu数量 -pub const CPU_NUM: usize = 1; - -pub const AT_FDCWD: isize = -100isize; - -///qemu的设备地址空间 -#[cfg(feature = "qemu")] -pub const MMIO: &[(usize, usize)] = &[ - (0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine - (0x2000000, 0x10000), - (0xc00_0000, 0x21_0000), // VIRT_PLIC in virt machine - (0x1000_0000, 0x9000), // VIRT_UART0 with GPU in virt machine - (0x3000_0000, 0x1000_0000), -]; - -/// vf2的设备地址空间 -#[cfg(feature = "vf2")] -pub const MMIO: &[(usize, usize)] = &[ - (0x17040000, 0x10000), // RTC - (0xc000000, 0x4000000), //PLIC - (0x00_1000_0000, 0x10000), // UART -]; - -/// hifive的设备地址空间 -#[cfg(feature = "hifive")] -pub const MMIO: &[(usize, usize)] = &[ - (0xc000000, 0x4000000), //PLIC -]; - -// todo!(if the app linker script changed, this should be changed too) -/// 进程的堆空间上限 -pub const PROCESS_HEAP_MAX: usize = u32::MAX as usize + 1; -/// 跳板页的虚拟地址 -pub const TRAMPOLINE: usize = usize::MAX - 2 * FRAME_SIZE + 1; -/// trap context的虚拟地址 -pub const TRAP_CONTEXT_BASE: usize = TRAMPOLINE - FRAME_SIZE; - -/// app内核栈大小 -pub const USER_KERNEL_STACK_SIZE: usize = 0x1000 * 2; -/// app用户栈大小 -pub const USER_STACK_SIZE: usize = 0x50_000; - -/// vf2/unmatched 的块缓存大小 -#[cfg(any(feature = "vf2", feature = "hifive"))] -pub const BLOCK_CACHE_FRAMES: usize = 1024 * 4 * 4; - -/// qemu 的块缓存大小 -#[cfg(feature = "qemu")] -pub const BLOCK_CACHE_FRAMES: usize = 1024 * 4 * 4; - -/// vf2/unmatched 的堆空间大小 -#[cfg(any(feature = "vf2", feature = "hifive"))] -pub const HEAP_SIZE: usize = 0x40_00000; - -/// qemu 的堆空间大小 -#[cfg(feature = "qemu")] -pub const HEAP_SIZE: usize = 0x26_00000; // (32+6)MB - -/// equal to HEAP_SIZe -#[cfg(any(feature = "talloc", feature = "buddy"))] -pub const KERNEL_HEAP_SIZE: usize = HEAP_SIZE; - -/// pipe缓冲区大小 -pub const PIPE_BUF: usize = 65536; - -/// 线程数量大小限制 -pub const MAX_THREAD_NUM: usize = 65536; -/// 描述符数量大小限制 -pub const MAX_FD_NUM: usize = 4096; - -/// 最大的输入事件数量 -pub const MAX_INPUT_EVENT_NUM: usize = 1024; - -/// 如果 elf 的 phdr 指示 base 是 0(如 libc-test 的 libc.so),则需要找一个非0的位置放置 -/// 我们将其从 0x4000_0000 开始放置。主要用于动态链接库使用 -pub const ELF_BASE_RELOCATE: usize = 0x400_0000; - -/// localtime文件中保存的内容 -pub const UTC: &[u8] = &[ - b'T', b'Z', b'i', b'f', b'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, - 0, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, b'U', b'T', b'C', - 0, 0, 0, b'T', b'Z', b'i', b'f', b'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, b'U', - b'T', b'C', 0, 0, 0, 0x0a, 0x55, 0x54, 0x43, 0x30, 0x0a, -]; - -/// rtc文件中保存的内容 -pub const RTC_TIME: &str = r" -rtc_time : 03:01:50 -rtc_date : 2023-07-11 -alrm_time : 13:03:24 -alrm_date : 2023-07-11 -alarm_IRQ : no -alrm_pending : no -update IRQ enabled : no -periodic IRQ enabled : no -periodic IRQ frequency : 1024 -max user IRQ frequency : 64 -24hr : yes -periodic_IRQ : no -update_IRQ : no -HPET_emulated : no -BCD : yes -DST_enable : no -periodic_freq : 1024 -batt_status : okay"; - -/// meminfo文件中保存的内容 -pub const MEMINFO: &str = r" -MemTotal: 944564 kB -MemFree: 835248 kB -MemAvailable: 873464 kB -Buffers: 6848 kB -Cached: 36684 kB -SwapCached: 0 kB -Active: 19032 kB -Inactive: 32676 kB -Active(anon): 128 kB -Inactive(anon): 8260 kB -Active(file): 18904 kB -Inactive(file): 24416 kB -Unevictable: 0 kB -Mlocked: 0 kB -SwapTotal: 0 kB -SwapFree: 0 kB -Dirty: 0 kB -Writeback: 0 kB -AnonPages: 8172 kB -Mapped: 16376 kB -Shmem: 216 kB -KReclaimable: 9960 kB -Slab: 17868 kB -SReclaimable: 9960 kB -SUnreclaim: 7908 kB -KernelStack: 1072 kB -PageTables: 600 kB -NFS_Unstable: 0 kB -Bounce: 0 kB -WritebackTmp: 0 kB -CommitLimit: 472280 kB -Committed_AS: 64684 kB -VmallocTotal: 67108863 kB -VmallocUsed: 15740 kB -VmallocChunk: 0 kB -Percpu: 496 kB -HugePages_Total: 0 -HugePages_Free: 0 -HugePages_Rsvd: 0 -HugePages_Surp: 0 -Hugepagesize: 2048 kB -Hugetlb: 0 kB -"; - -// QEMU user networking default IP -pub const QEMU_IP: &str = "10.0.2.15"; -// QEMU user networking gateway -pub const QEMU_GATEWAY: &str = "10.0.2.2"; diff --git a/kernel/src/device/block.rs b/kernel/src/device/block.rs deleted file mode 100644 index d3a99d84..00000000 --- a/kernel/src/device/block.rs +++ /dev/null @@ -1,82 +0,0 @@ -use alloc::sync::Arc; - -use crate::driver::GenericBlockDevice; -use crate::fs::dev::DeviceId; -use constants::AlienResult; -use spin::Once; -use vfscore::error::VfsError; -use vfscore::file::VfsFile; -use vfscore::inode::{InodeAttr, VfsInode}; -use vfscore::utils::{VfsFileStat, VfsNodeType, VfsPollEvents}; -use vfscore::VfsResult; - -use crate::interrupt::DeviceBase; - -pub static BLOCK_DEVICE: Once> = Once::new(); - -pub fn init_block_device(block_device: Arc) { - // BLOCK_DEVICE.lock().push(block_device); - BLOCK_DEVICE.call_once(|| block_device); -} - -pub trait BlockDevice: Send + Sync + DeviceBase { - fn read(&self, buf: &mut [u8], offset: usize) -> AlienResult; - fn write(&self, buf: &[u8], offset: usize) -> AlienResult; - fn size(&self) -> usize; - fn flush(&self) -> AlienResult<()>; -} - -pub struct BLKDevice { - device_id: DeviceId, - device: Arc, -} - -impl BLKDevice { - pub fn new(device_id: DeviceId, device: Arc) -> Self { - Self { device_id, device } - } - pub fn device_id(&self) -> DeviceId { - self.device_id - } -} - -impl VfsFile for BLKDevice { - fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { - self.device - .read(buf, offset as usize) - .map_err(|_| VfsError::IoError) - } - fn write_at(&self, offset: u64, buf: &[u8]) -> VfsResult { - self.device - .write(buf, offset as usize) - .map_err(|_| VfsError::IoError) - } - fn poll(&self, _event: VfsPollEvents) -> VfsResult { - unimplemented!() - } - fn ioctl(&self, _cmd: u32, _arg: usize) -> VfsResult { - unimplemented!() - } - fn flush(&self) -> VfsResult<()> { - Ok(()) - } - fn fsync(&self) -> VfsResult<()> { - Ok(()) - } -} - -impl VfsInode for BLKDevice { - fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { - Ok(()) - } - fn get_attr(&self) -> VfsResult { - Ok(VfsFileStat { - st_rdev: self.device_id.id(), - st_size: self.device.size() as u64, - ..Default::default() - }) - } - fn inode_type(&self) -> VfsNodeType { - VfsNodeType::BlockDevice - } -} diff --git a/kernel/src/device/gpu.rs b/kernel/src/device/gpu.rs deleted file mode 100644 index 0d6a944c..00000000 --- a/kernel/src/device/gpu.rs +++ /dev/null @@ -1,76 +0,0 @@ -use alloc::sync::Arc; -use core::any::Any; - -use crate::fs::dev::DeviceId; -use spin::Once; -use vfscore::error::VfsError; -use vfscore::file::VfsFile; -use vfscore::inode::{InodeAttr, VfsInode}; -use vfscore::utils::{VfsFileStat, VfsNodeType}; -use vfscore::VfsResult; - -use crate::interrupt::DeviceBase; - -pub trait GpuDevice: Send + Sync + Any + DeviceBase { - fn update_cursor(&self); - fn get_framebuffer(&self) -> &mut [u8]; - fn flush(&self); -} - -pub static GPU_DEVICE: Once> = Once::new(); - -pub fn init_gpu(gpu: Arc) { - GPU_DEVICE.call_once(|| gpu); -} - -pub struct GPUDevice { - device_id: DeviceId, - device: Arc, -} - -impl GPUDevice { - pub fn new(device_id: DeviceId, device: Arc) -> Self { - Self { device_id, device } - } - pub fn device_id(&self) -> DeviceId { - self.device_id - } -} - -impl VfsFile for GPUDevice { - fn read_at(&self, _offset: u64, _buf: &mut [u8]) -> VfsResult { - Err(VfsError::Invalid) - } - fn write_at(&self, offset: u64, buf: &[u8]) -> VfsResult { - let gbuf = self.device.get_framebuffer(); - let offset = offset as usize; - let gbuf_len = gbuf.len(); - let min_len = (gbuf_len - offset).min(buf.len()); - gbuf[offset..offset + min_len].copy_from_slice(&buf[..min_len]); - Ok(min_len) - } - fn flush(&self) -> VfsResult<()> { - self.device.flush(); - Ok(()) - } - fn fsync(&self) -> VfsResult<()> { - self.flush() - } -} - -impl VfsInode for GPUDevice { - fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { - Ok(()) - } - - fn get_attr(&self) -> VfsResult { - Ok(VfsFileStat { - st_rdev: self.device_id.id(), - ..Default::default() - }) - } - - fn inode_type(&self) -> VfsNodeType { - VfsNodeType::CharDevice - } -} diff --git a/kernel/src/device/input.rs b/kernel/src/device/input.rs deleted file mode 100644 index 918097c7..00000000 --- a/kernel/src/device/input.rs +++ /dev/null @@ -1,137 +0,0 @@ -use alloc::sync::Arc; - -use spin::Once; - -use crate::fs::dev::DeviceId; -use syscall_table::syscall_func; -use vfscore::error::VfsError; -use vfscore::file::VfsFile; -use vfscore::inode::{InodeAttr, VfsInode}; -use vfscore::superblock::VfsSuperBlock; -use vfscore::utils::{VfsFileStat, VfsNodeType, VfsPollEvents}; -use vfscore::VfsResult; - -use crate::interrupt::DeviceBase; -use crate::task::current_task; - -pub trait InputDevice: Send + Sync + DeviceBase { - fn is_empty(&self) -> bool; - fn read_event_with_block(&self) -> u64; - fn read_event_without_block(&self) -> Option; -} - -pub struct INPUTDevice { - device_id: DeviceId, - device: Arc, - #[allow(unused)] - is_keyboard: bool, -} - -impl INPUTDevice { - pub fn new(device_id: DeviceId, device: Arc, is_keyboard: bool) -> Self { - Self { - device_id, - device, - is_keyboard, - } - } - pub fn device_id(&self) -> DeviceId { - self.device_id - } -} - -impl VfsFile for INPUTDevice { - fn read_at(&self, _offset: u64, buf: &mut [u8]) -> VfsResult { - if buf.len() != 8 { - return Err(VfsError::Invalid); - } - let buf = unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u64, 1) }; - let event = self.device.read_event_with_block(); - buf[0] = event; - Ok(1) - } - fn write_at(&self, _offset: u64, _buf: &[u8]) -> VfsResult { - Err(VfsError::Invalid) - } - fn poll(&self, event: VfsPollEvents) -> VfsResult { - let mut res = VfsPollEvents::empty(); - if event.contains(VfsPollEvents::IN) { - if self.device.is_empty() { - res |= VfsPollEvents::IN; - } - } - Ok(res) - } -} - -impl VfsInode for INPUTDevice { - fn get_super_block(&self) -> VfsResult> { - Err(VfsError::NoSys) - } - fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { - Ok(()) - } - fn get_attr(&self) -> VfsResult { - Ok(VfsFileStat { - st_rdev: self.device_id.id(), - ..Default::default() - }) - } - fn inode_type(&self) -> VfsNodeType { - VfsNodeType::CharDevice - } -} - -pub static KEYBOARD_INPUT_DEVICE: Once> = Once::new(); -pub static MOUSE_INPUT_DEVICE: Once> = Once::new(); - -pub fn init_keyboard_input_device(input_device: Arc) { - KEYBOARD_INPUT_DEVICE.call_once(|| input_device); -} - -pub fn init_mouse_input_device(input_device: Arc) { - MOUSE_INPUT_DEVICE.call_once(|| input_device); -} - -/// 一个系统调用函数,用于获取鼠标和键盘事件。 -/// -/// `sys_event_get`会将获取到的事件将保存在event_buf所指向的内存位置处, -/// 此次允许获取到的事件的最大值(即event_buf)的大小由len指出。 -/// -/// 函数将返回成功获取到的事件个数。 -/// -#[syscall_func(2002)] -pub fn sys_event_get(event_buf: *mut u64, len: usize) -> isize { - let process = current_task().unwrap(); - let user_buffer = process.transfer_buffer(event_buf, len); - let mut count = 0; - for buf in user_buffer { - let mut index = 0; - let len = buf.len(); - while index < len { - let event = read_event(); - if event == 0 { - break; - } - buf[index] = event; - index += 1; - count += 1; - } - } - count -} - -fn read_event() -> u64 { - let (keyboard, mouse) = { - let kb = KEYBOARD_INPUT_DEVICE.get().unwrap(); - let mouse = MOUSE_INPUT_DEVICE.get().unwrap(); - (kb, mouse) - }; - if !keyboard.is_empty() { - keyboard.read_event_with_block() - } else if !mouse.is_empty() { - mouse.read_event_with_block() - } else { - 0 - } -} diff --git a/kernel/src/device/mod.rs b/kernel/src/device/mod.rs deleted file mode 100644 index f165fd55..00000000 --- a/kernel/src/device/mod.rs +++ /dev/null @@ -1,268 +0,0 @@ -pub use self::rtc::{get_rtc_time, RTCDevice, RtcDevice, RTC_DEVICE}; -pub use self::uart::{UARTDevice, UartDevice, UART_DEVICE}; -use crate::board::{get_rtc_info, probe_devices_from_dtb}; -use crate::driver::uart::Uart; -use crate::driver::GenericBlockDevice; -use crate::interrupt::register_device_to_plic; -use crate::print::console::UART_FLAG; -use alloc::boxed::Box; -use alloc::sync::Arc; -pub use block::{BLKDevice, BlockDevice, BLOCK_DEVICE}; -use core::sync::atomic::Ordering; -pub use gpu::{GPUDevice, GpuDevice, GPU_DEVICE}; -pub use input::{ - sys_event_get, INPUTDevice, InputDevice, KEYBOARD_INPUT_DEVICE, MOUSE_INPUT_DEVICE, -}; -use smoltcp::wire::IpAddress; - -mod block; -mod gpu; -mod input; -mod net; -mod rtc; -mod uart; - -#[derive(Debug, Clone, Copy, PartialOrd, PartialEq, Hash, Ord, Eq)] -pub enum DeviceType { - Block, - GPU, - KeyBoardInput, - MouseInput, - Network, - Uart, - Rtc, -} - -pub struct DeviceInfo { - pub base_addr: usize, - pub irq: usize, -} - -impl DeviceInfo { - pub fn new(base_addr: usize, irq: usize) -> Self { - Self { base_addr, irq } - } -} - -pub fn init_device() { - probe_devices_from_dtb(); - init_uart(); - init_gpu(); - init_keyboard_input_device(); - init_mouse_input_device(); - init_rtc(); - init_net(); - init_block_device(); - // init_pci(); -} - -fn init_rtc() { - let res = get_rtc_info(); - if res.is_none() { - println!("There is no rtc device"); - return; - } - let (base_addr, irq) = res.unwrap(); - println!("Init rtc, base_addr:{:#x},irq:{}", base_addr, irq); - #[cfg(feature = "qemu")] - { - use crate::driver::rtc::GoldFishRtc; - use ::rtc::LowRtcDeviceExt; - let rtc = Arc::new(GoldFishRtc::new(base_addr)); - let current_time = rtc.read_time_fmt(); - rtc::init_rtc(rtc.clone()); - register_device_to_plic(irq, rtc); - println!("Init rtc success, current time: {:?}", current_time); - } - #[cfg(feature = "vf2")] - { - // rtc = todo!(); - println!("Don't support rtc on vf2"); - } -} - -fn init_uart() { - let res = crate::board::get_uart_info(); - if res.is_none() { - println!("There is no uart device"); - return; - } - let (base_addr, irq) = res.unwrap(); - println!("Init uart, base_addr:{:#x},irq:{}", base_addr, irq); - #[cfg(feature = "qemu")] - { - use crate::driver::uart::Uart16550; - let uart = Uart16550::new(base_addr); - let uart = Uart::new(Box::new(uart)); - let uart = Arc::new(uart); - uart::init_uart(uart.clone()); - register_device_to_plic(irq, uart); - } - #[cfg(feature = "vf2")] - { - use crate::driver::uart::Uart8250; - let uart = Uart8250::new(base_addr); - let uart = Uart::new(Box::new(uart)); - let uart = Arc::new(uart); - uart::init_uart(uart.clone()); - register_device_to_plic(irq, uart); - } - UART_FLAG.store(true, Ordering::Relaxed); - println!("Init uart success"); -} - -fn init_block_device() { - #[cfg(feature = "qemu")] - { - use crate::driver::VirtIOBlkWrapper; - let res = crate::board::get_block_device_info(); - if res.is_none() { - println!("There is no block device"); - return; - } - let (base_addr, irq) = res.unwrap(); - println!("Init block device, base_addr:{:#x},irq:{}", base_addr, irq); - let block_device = VirtIOBlkWrapper::new(base_addr); - let block_device = GenericBlockDevice::new(Box::new(block_device)); - let block_device = Arc::new(block_device); - block::init_block_device(block_device); - // register_device_to_plic(irq, block_device); - println!("Init block device success"); - } - #[cfg(any(feature = "vf2", feature = "hifive"))] - { - use crate::board::checkout_fs_img; - checkout_fs_img(); - init_fake_disk(); - println!("Init fake disk success"); - } -} - -#[cfg(any(feature = "vf2", feature = "hifive"))] -fn init_fake_disk() { - use crate::board::{img_end, img_start}; - use crate::driver::MemoryFat32Img; - let data = unsafe { - core::slice::from_raw_parts_mut(img_start as *mut u8, img_end as usize - img_start as usize) - }; - let device = GenericBlockDevice::new(Box::new(MemoryFat32Img::new(data))); - let device = Arc::new(device); - block::init_block_device(device.clone()); -} - -fn init_gpu() { - let res = crate::board::get_gpu_info(); - if res.is_none() { - println!("There is no gpu device"); - return; - } - let (base_addr, irq) = res.unwrap(); - println!("Init gpu, base_addr:{:#x},irq:{}", base_addr, irq); - #[cfg(feature = "qemu")] - { - use crate::driver::gpu::VirtIOGpuWrapper; - let gpu = VirtIOGpuWrapper::new(base_addr); - let gpu = Arc::new(gpu); - gpu::init_gpu(gpu.clone()); - // let _ = register_device_to_plic(irq, gpu); - println!("Init gpu success"); - } -} - -fn init_keyboard_input_device() { - let res = crate::board::get_keyboard_info(); - if res.is_none() { - println!("There is no keyboard device"); - return; - } - let (base_addr, irq) = res.unwrap(); - println!( - "Init keyboard input device, base_addr:{:#x},irq:{}", - base_addr, irq - ); - #[cfg(feature = "qemu")] - { - use crate::config::MAX_INPUT_EVENT_NUM; - use crate::driver::input::VirtIOInputDriver; - let input_device = VirtIOInputDriver::from_addr(base_addr, MAX_INPUT_EVENT_NUM as u32); - let input_device = Arc::new(input_device); - input::init_keyboard_input_device(input_device.clone()); - let _ = register_device_to_plic(irq, input_device); - println!("Init keyboard input device success"); - } -} - -fn init_mouse_input_device() { - let res = crate::board::get_mouse_info(); - if res.is_none() { - println!("There is no mouse device"); - return; - } - let (base_addr, irq) = res.unwrap(); - println!( - "Init mouse input device, base_addr:{:#x},irq:{}", - base_addr, irq - ); - #[cfg(feature = "qemu")] - { - use crate::config::MAX_INPUT_EVENT_NUM; - use crate::driver::input::VirtIOInputDriver; - let input_device = VirtIOInputDriver::from_addr(base_addr, MAX_INPUT_EVENT_NUM as u32); - let input_device = Arc::new(input_device); - input::init_mouse_input_device(input_device.clone()); - let _ = register_device_to_plic(irq, input_device); - println!("Init mouse input device success"); - } -} - -fn init_net() { - // If we need run test, we should only init loop device because no we can't route packet - #[cfg(feature = "test")] - { - init_loop_device(); - } - #[cfg(not(feature = "test"))] - { - let res = crate::board::get_net_device_info(); - if res.is_none() { - println!("There is no net device"); - return; - } - let (base_addr, irq) = res.unwrap(); - println!("Init net device, base_addr:{:#x},irq:{}", base_addr, irq); - - #[cfg(feature = "qemu")] - { - use crate::device::net::NetNeedFunc; - use crate::driver::net::make_virtio_net_device; - let virtio_net = make_virtio_net_device(base_addr); - use crate::config::{QEMU_GATEWAY, QEMU_IP}; - use core::str::FromStr; - let device = Box::new(virtio_net); - netcore::init_net( - device, - Arc::new(NetNeedFunc), - IpAddress::from_str(QEMU_IP).unwrap(), - IpAddress::from_str(QEMU_GATEWAY).unwrap(), - true, - ); - println!("Init net device success"); - #[cfg(feature = "net_test")] - { - println!("test echo-server"); - net::nettest::accept_loop(); - } - } - } -} -#[cfg(feature = "test")] -fn init_loop_device() { - use crate::device::net::NetNeedFunc; - use loopback::LoopbackDev; - // use default ip and gateway for qemu - let ip = IpAddress::v4(127, 0, 0, 1); - let gate_way = IpAddress::v4(127, 0, 0, 1); - let loopback = Box::new(LoopbackDev::new()); - netcore::init_net(loopback, Arc::new(NetNeedFunc), ip, gate_way, false); - println!("Init net device success"); -} diff --git a/kernel/src/device/net.rs b/kernel/src/device/net.rs deleted file mode 100644 index 2d2a6af7..00000000 --- a/kernel/src/device/net.rs +++ /dev/null @@ -1,128 +0,0 @@ -use netcore::{KernelNetFunc, NetInstant}; - -use crate::interrupt::DeviceBase; - -use crate::timer::TimeSpec; - -pub trait NetDevice: DeviceBase {} - -#[cfg(feature = "net_test")] -pub mod nettest { - use crate::net::port::neterror2alien; - use alloc::vec::Vec; - use constants::AlienResult; - use core::net::{IpAddr, SocketAddr}; - use netcore::tcp::TcpSocket; - - /// A TCP stream between a local and a remote socket. - pub struct TcpStream(TcpSocket); - - /// A TCP socket server, listening for connections. - pub struct TcpListener(TcpSocket); - - impl TcpStream { - pub fn read(&mut self, buf: &mut [u8]) -> AlienResult { - self.0.recv(buf).map_err(neterror2alien) - } - pub fn write_all(&mut self, buf: &[u8]) -> AlienResult { - self.0.send(buf).map_err(neterror2alien) - } - } - - impl TcpListener { - pub fn bind(addr: SocketAddr) -> AlienResult { - let socket = TcpSocket::new(); - socket.bind(addr).map_err(neterror2alien)?; - socket.listen().map_err(neterror2alien)?; - Ok(TcpListener(socket)) - } - pub fn local_addr(&self) -> AlienResult { - self.0.local_addr().map_err(neterror2alien) - } - - pub fn accept(&self) -> AlienResult<(TcpStream, SocketAddr)> { - let socket = self.0.accept().map_err(neterror2alien)?; - let addr = socket.peer_addr().map_err(neterror2alien)?; - Ok((TcpStream(socket), addr)) - } - } - - const LOCAL_IP: &str = "0.0.0.0"; - const LOCAL_PORT: u16 = 5555; - - fn reverse(buf: &[u8]) -> Vec { - let mut lines = buf - .split(|&b| b == b'\n') - .map(Vec::from) - .collect::>(); - for line in lines.iter_mut() { - line.reverse(); - } - lines.join(&b'\n') - } - - fn echo_server(mut stream: TcpStream) -> AlienResult<()> { - let mut buf = [0u8; 1024]; - loop { - let n = stream.read(&mut buf).unwrap(); - if n == 0 { - return Ok(()); - } - stream.write_all(reverse(&buf[..n]).as_slice()).unwrap(); - } - } - - pub fn accept_loop() { - let local_addr = SocketAddr::new(IpAddr::V4(LOCAL_IP.parse().unwrap()), LOCAL_PORT); - let listener = TcpListener::bind(local_addr).unwrap(); - println!("listen on: {}", listener.local_addr().unwrap()); - let mut i = 0; - loop { - match listener.accept() { - Ok((stream, addr)) => { - println!("new client {}: {}", i, addr); - match echo_server(stream) { - Err(e) => { - println!("client connection error: {:?}", e); - } - Ok(()) => { - println!("client {} closed successfully", i); - } - } - } - Err(e) => panic!("couldn't get client: {:?}", e), - } - i += 1; - } - } -} - -#[derive(Debug, Default)] -pub struct NetNeedFunc; - -impl KernelNetFunc for NetNeedFunc { - fn now(&self) -> NetInstant { - let time_spec = TimeSpec::now(); - NetInstant { - micros: time_spec.tv_sec as i64 * 1000_000 + time_spec.tv_nsec as i64 / 1000, - } - } - #[cfg(feature = "net_test")] - fn yield_now(&self) { - // do_suspend(); - } - #[cfg(not(feature = "net_test"))] - fn yield_now(&self) -> bool { - use crate::task::current_task; - use crate::task::do_suspend; - do_suspend(); - // interrupt by signal - let task = current_task().unwrap(); - let task_inner = task.access_inner(); - let receiver = task_inner.signal_receivers.lock(); - if receiver.have_signal() { - return true; - } - false - } -} diff --git a/kernel/src/device/rtc.rs b/kernel/src/device/rtc.rs deleted file mode 100644 index eb3664a2..00000000 --- a/kernel/src/device/rtc.rs +++ /dev/null @@ -1,136 +0,0 @@ -use alloc::format; -use alloc::sync::Arc; -use constants::io::TeletypeCommand; -use core::cmp::min; -use rtc::RtcTime; - -use crate::fs::dev::DeviceId; -use spin::Once; -use vfscore::error::VfsError; -use vfscore::file::VfsFile; -use vfscore::inode::{InodeAttr, VfsInode}; -use vfscore::superblock::VfsSuperBlock; -use vfscore::utils::{VfsFileStat, VfsNodeType}; -use vfscore::VfsResult; - -use crate::interrupt::DeviceBase; -use crate::task::current_task; - -pub static RTC_DEVICE: Once> = Once::new(); - -pub fn get_rtc_time() -> Option { - RTC_DEVICE.get().map(|rtc| rtc.read_time_fmt()) -} - -pub fn init_rtc(rtc: Arc) { - RTC_DEVICE.call_once(|| rtc); -} - -pub trait RtcDevice: Send + Sync + DeviceBase + rtc::LowRtcDevice + rtc::LowRtcDeviceExt {} - -pub struct RTCDevice { - device_id: DeviceId, - device: Arc, -} - -impl RTCDevice { - pub fn new(device_id: DeviceId, device: Arc) -> Self { - Self { device_id, device } - } - pub fn device_id(&self) -> DeviceId { - self.device_id - } -} - -impl VfsFile for RTCDevice { - fn read_at(&self, _offset: u64, buf: &mut [u8]) -> VfsResult { - let time = self.device.read_time_fmt(); - let str = format!("{:?}", time); - let bytes = str.as_bytes(); - let min_len = min(buf.len(), bytes.len()); - buf[..min_len].copy_from_slice(&bytes[..min_len]); - Ok(min_len) - } - fn write_at(&self, _offset: u64, _buf: &[u8]) -> VfsResult { - todo!() - } - fn ioctl(&self, cmd: u32, arg: usize) -> VfsResult { - let task = current_task().unwrap(); - let mut task_inner = task.access_inner(); - let cmd = TeletypeCommand::try_from(cmd).map_err(|_| VfsError::Invalid)?; - match cmd { - TeletypeCommand::RTC_RD_TIME => { - let time = self.device.read_time_fmt(); - let c_rtc_time = constants::io::RtcTime { - sec: time.second as u32, - min: time.minute as u32, - hour: time.hour as u32, - mday: time.day as u32, - mon: time.month as u32, - year: time.year, - wday: 0, - yday: 0, - isdst: 0, - }; - task_inner.copy_to_user(&c_rtc_time, arg as *mut constants::io::RtcTime); - } - _ => return Err(VfsError::Invalid), - } - Ok(0) - } - fn flush(&self) -> VfsResult<()> { - Ok(()) - } - fn fsync(&self) -> VfsResult<()> { - Ok(()) - } -} - -impl VfsInode for RTCDevice { - fn get_super_block(&self) -> VfsResult> { - Err(VfsError::NoSys) - } - - fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { - Ok(()) - } - - fn get_attr(&self) -> VfsResult { - Ok(VfsFileStat { - st_rdev: self.device_id.id(), - ..Default::default() - }) - } - - fn inode_type(&self) -> VfsNodeType { - VfsNodeType::CharDevice - } -} - -#[allow(dead_code)] -fn example() { - // let rtc = RTC_DEVICE.get().unwrap(); - // let time = rtc.read_time(); - // let alarm = rtc.read_alarm(); - // println!("time: {:#x}, alarm: {:#x}", time, alarm); - // rtc.clear_irq(); - // rtc.enable_irq(); - // println!("set alarm"); - // rtc.set_alarm(time + 1_000_000_000 * 5); // wait 5s - // let alarm = rtc.read_alarm_fmt(); - // let status = rtc.alarm_status(); - // let is_enable = rtc.is_irq_enabled(); - // println!( - // "At {:?}, rtc will interrupt, status: {} enable: {}", - // alarm, status, is_enable - // ); - // loop { - // let time = rtc.read_time(); - // let alarm = rtc.read_alarm(); - // if time == alarm { - // let status = rtc.alarm_status(); - // let enable = rtc.is_irq_enabled(); - // println!("time == alarm, status: {}, enable: {}", status, enable); - // } - // } -} diff --git a/kernel/src/device/uart.rs b/kernel/src/device/uart.rs deleted file mode 100644 index 9b511b1f..00000000 --- a/kernel/src/device/uart.rs +++ /dev/null @@ -1,168 +0,0 @@ -use crate::fs::dev::DeviceId; -use alloc::sync::Arc; -use constants::io::{LocalModes, TeletypeCommand, Termios, WinSize}; -use spin::Once; -use vfscore::error::VfsError; -use vfscore::file::VfsFile; -use vfscore::inode::{InodeAttr, VfsInode}; -use vfscore::superblock::VfsSuperBlock; -use vfscore::utils::{VfsFileStat, VfsNodeType, VfsPollEvents}; -use vfscore::VfsResult; - -use crate::interrupt::DeviceBase; -use crate::task::current_task; -use ksync::Mutex; - -pub trait UartDevice: Send + Sync + DeviceBase { - fn put(&self, c: u8); - fn get(&self) -> Option; - fn put_bytes(&self, bytes: &[u8]); - fn have_data_to_get(&self) -> bool; - fn have_space_to_put(&self) -> bool; -} - -pub static UART_DEVICE: Once> = Once::new(); - -pub fn init_uart(uart: Arc) { - UART_DEVICE.call_once(|| uart); -} - -#[derive(Debug, Default)] -pub struct IoData { - foreground_pgid: u32, - winsize: WinSize, - termios: Termios, -} - -pub struct UARTDevice { - device_id: DeviceId, - device: Arc, - io: Mutex, -} - -impl UARTDevice { - pub fn new(device_id: DeviceId, device: Arc) -> Self { - Self { - device_id, - device, - io: Mutex::new(IoData::default()), - } - } - pub fn device_id(&self) -> DeviceId { - self.device_id - } -} - -impl VfsFile for UARTDevice { - fn read_at(&self, _offset: u64, buf: &mut [u8]) -> VfsResult { - // read util \r and transform to \n - let mut read_count = 0; - loop { - let ch = self.device.get(); - assert!(ch.is_some()); - let ch = ch.unwrap(); - buf[read_count] = ch; - read_count += 1; - if ch == b'\r' { - buf[read_count - 1] = b'\n'; - if LocalModes::from_bits_truncate(self.io.lock().termios.lflag) - .contains(LocalModes::ECHO) - { - self.device.put(b'\n'); - } - break; - } - if LocalModes::from_bits_truncate(self.io.lock().termios.lflag) - .contains(LocalModes::ECHO) - { - self.device.put(ch); - } - if read_count >= buf.len() { - break; - } - } - Ok(read_count) - } - fn write_at(&self, _offset: u64, buf: &[u8]) -> VfsResult { - self.device.put_bytes(buf); - Ok(buf.len()) - } - fn poll(&self, event: VfsPollEvents) -> VfsResult { - let mut res = VfsPollEvents::empty(); - if event.contains(VfsPollEvents::IN) { - if self.device.have_data_to_get() { - res |= VfsPollEvents::IN; - } - } - if event.contains(VfsPollEvents::OUT) { - if self.device.have_space_to_put() { - res |= VfsPollEvents::OUT - } - } - Ok(res) - } - fn ioctl(&self, cmd: u32, arg: usize) -> VfsResult { - let mut io = self.io.lock(); - let cmd = TeletypeCommand::try_from(cmd).unwrap(); - let task = current_task().unwrap(); - let mut task_inner = task.access_inner(); - return match cmd { - TeletypeCommand::TCGETS | TeletypeCommand::TCGETA => { - task_inner.copy_to_user(&io.termios, arg as *mut Termios); - Ok(0) - } - TeletypeCommand::TCSETS | TeletypeCommand::TCSETSW | TeletypeCommand::TCSETSF => { - task_inner.copy_from_user(arg as *const Termios, &mut io.termios); - Ok(0) - } - TeletypeCommand::TIOCGPGRP => { - let word = task_inner.transfer_raw_ptr_mut(arg as *mut u32); - *word = io.foreground_pgid; - Ok(0) - } - TeletypeCommand::TIOCSPGRP => { - let word = task_inner.transfer_raw_ptr(arg as *const u32); - io.foreground_pgid = *word; - Ok(0) - } - TeletypeCommand::TIOCGWINSZ => { - task_inner.copy_to_user(&io.winsize, arg as *mut WinSize); - Ok(0) - } - TeletypeCommand::TIOCSWINSZ => { - task_inner.copy_from_user(arg as *const WinSize, &mut io.winsize); - Ok(0) - } - _ => { - unimplemented!("ioctl cmd: {:?}", cmd) - } - }; - } - fn flush(&self) -> VfsResult<()> { - Ok(()) - } - fn fsync(&self) -> VfsResult<()> { - Ok(()) - } -} - -impl VfsInode for UARTDevice { - fn get_super_block(&self) -> VfsResult> { - Err(VfsError::NoSys) - } - - fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { - Ok(()) - } - - fn get_attr(&self) -> VfsResult { - Ok(VfsFileStat { - st_rdev: self.device_id.id(), - ..Default::default() - }) - } - - fn inode_type(&self) -> VfsNodeType { - VfsNodeType::CharDevice - } -} diff --git a/kernel/src/driver/block_device.rs b/kernel/src/driver/block_device.rs deleted file mode 100644 index 0c0c6f0c..00000000 --- a/kernel/src/driver/block_device.rs +++ /dev/null @@ -1,233 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use constants::LinuxErrno; -use core::cmp::min; -use core::fmt::{Debug, Formatter}; -use core::num::NonZeroUsize; -use core::ptr::NonNull; - -use lru::LruCache; -use virtio_drivers::device::blk::VirtIOBlk; -use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; - -use constants::AlienResult; -use ksync::Mutex; - -use crate::config::BLOCK_CACHE_FRAMES; -use crate::config::FRAME_SIZE; -use crate::device::BlockDevice; -use crate::driver::hal::HalImpl; -use crate::interrupt::DeviceBase; -use crate::memory::{frame_alloc, FrameTracker}; - -const PAGE_CACHE_SIZE: usize = FRAME_SIZE; - -pub struct GenericBlockDevice { - pub device: Mutex>, - cache: Mutex>, - dirty: Mutex>, -} - -unsafe impl Send for GenericBlockDevice {} - -unsafe impl Sync for GenericBlockDevice {} - -impl GenericBlockDevice { - pub fn new(device: Box) -> Self { - Self { - device: Mutex::new(device), - cache: Mutex::new(LruCache::new( - NonZeroUsize::new(BLOCK_CACHE_FRAMES).unwrap(), - )), // 4MB cache - dirty: Mutex::new(Vec::new()), - } - } -} - -impl DeviceBase for GenericBlockDevice { - fn hand_irq(&self) { - unimplemented!() - } -} - -impl Debug for GenericBlockDevice { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("QemuBlockDevice").finish() - } -} - -impl BlockDevice for GenericBlockDevice { - fn read(&self, buf: &mut [u8], offset: usize) -> AlienResult { - let mut page_id = offset / PAGE_CACHE_SIZE; - let mut offset = offset % PAGE_CACHE_SIZE; - - let mut cache_lock = self.cache.lock(); - let len = buf.len(); - let mut count = 0; - - while count < len { - if !cache_lock.contains(&page_id) { - let mut device = self.device.lock(); - let mut cache = frame_alloc().unwrap(); - let start_block = page_id * PAGE_CACHE_SIZE / 512; - let end_block = start_block + PAGE_CACHE_SIZE / 512; - for i in start_block..end_block { - let target_buf = - &mut cache[(i - start_block) * 512..(i - start_block + 1) * 512]; - device.read_block(i, target_buf).unwrap(); - } - let old_cache = cache_lock.push(page_id, cache); - if let Some((id, old_cache)) = old_cache { - let start_block = id * PAGE_CACHE_SIZE / 512; - let end_block = start_block + PAGE_CACHE_SIZE / 512; - for i in start_block..end_block { - let target_buf = - &old_cache[(i - start_block) * 512..(i - start_block + 1) * 512]; - device.write_block(i, target_buf).unwrap(); - self.dirty.lock().retain(|&x| x != id); - } - } - } - let cache = cache_lock.get(&page_id).unwrap(); - let copy_len = min(PAGE_CACHE_SIZE - offset, len - count); - buf[count..count + copy_len].copy_from_slice(&cache[offset..offset + copy_len]); - count += copy_len; - offset = 0; - page_id += 1; - } - Ok(buf.len()) - } - fn write(&self, buf: &[u8], offset: usize) -> AlienResult { - let mut page_id = offset / PAGE_CACHE_SIZE; - let mut offset = offset % PAGE_CACHE_SIZE; - - let mut cache_lock = self.cache.lock(); - let len = buf.len(); - let mut count = 0; - while count < len { - if !cache_lock.contains(&page_id) { - let mut device = self.device.lock(); - let mut cache = frame_alloc().unwrap(); - let start_block = page_id * PAGE_CACHE_SIZE / 512; - let end_block = start_block + PAGE_CACHE_SIZE / 512; - for i in start_block..end_block { - let target_buf = - &mut cache[(i - start_block) * 512..(i - start_block + 1) * 512]; - device.read_block(i, target_buf).unwrap(); - } - let old_cache = cache_lock.push(page_id, cache); - if let Some((id, old_cache)) = old_cache { - let start_block = id * PAGE_CACHE_SIZE / 512; - let end_block = start_block + PAGE_CACHE_SIZE / 512; - for i in start_block..end_block { - let target_buf = - &old_cache[(i - start_block) * 512..(i - start_block + 1) * 512]; - device.write_block(i, target_buf).unwrap(); - self.dirty.lock().retain(|&x| x != id); - } - } - } - let cache = cache_lock.get_mut(&page_id).unwrap(); - if cache.as_ptr() as usize == 0x9000_0000 { - panic!("cache is null"); - } - // self.dirty.lock().push(page_id); - let copy_len = min(PAGE_CACHE_SIZE - offset, len - count); - cache[offset..offset + copy_len].copy_from_slice(&buf[count..count + copy_len]); - count += copy_len; - offset = (offset + copy_len) % PAGE_CACHE_SIZE; - page_id += 1; - } - Ok(buf.len()) - } - fn size(&self) -> usize { - self.device.lock().capacity() * 512 - } - fn flush(&self) -> AlienResult<()> { - // let mut device = self.device.lock(); - // let mut lru = self.cache.lock(); - // self.dirty.lock().iter().for_each(|id|{ - // let start = id * PAGE_CACHE_SIZE; - // let start_block = start / 512; - // let end_block = (start + PAGE_CACHE_SIZE) / 512; - // let cache = lru.get(id).unwrap(); - // for i in start_block..end_block { - // let target_buf = &cache[(i - start_block) * 512..(i - start_block + 1) * 512]; - // device.write_block(i, target_buf).unwrap(); - // } - // }); - // self.dirty.lock().clear(); - Ok(()) - } -} - -pub trait LowBlockDriver { - fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> AlienResult<()>; - fn write_block(&mut self, block_id: usize, buf: &[u8]) -> AlienResult<()>; - fn capacity(&self) -> usize; - fn flush(&mut self) {} -} - -pub struct VirtIOBlkWrapper { - device: VirtIOBlk, -} - -impl VirtIOBlkWrapper { - pub fn new(addr: usize) -> Self { - let header = NonNull::new(addr as *mut VirtIOHeader).unwrap(); - let transport = unsafe { MmioTransport::new(header) }.unwrap(); - let blk = VirtIOBlk::::new(transport) - .expect("failed to create blk driver"); - let size = blk.capacity(); - println!("blk device size is {}MB", size * 512 / 1024 / 1024); - Self { device: blk } - } -} - -impl LowBlockDriver for VirtIOBlkWrapper { - fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> AlienResult<()> { - let res = self - .device - .read_block(block_id, buf) - .map_err(|_| LinuxErrno::EIO.into()); - res - } - fn write_block(&mut self, block_id: usize, buf: &[u8]) -> AlienResult<()> { - self.device - .write_block(block_id, buf) - .map_err(|_| LinuxErrno::EIO.into()) - } - - fn capacity(&self) -> usize { - self.device.capacity() as usize - } -} - -pub struct MemoryFat32Img { - data: &'static mut [u8], -} - -impl LowBlockDriver for MemoryFat32Img { - fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> AlienResult<()> { - let start = block_id * 512; - let end = start + 512; - buf.copy_from_slice(&self.data[start..end]); - Ok(()) - } - fn write_block(&mut self, block_id: usize, buf: &[u8]) -> AlienResult<()> { - let start = block_id * 512; - let end = start + 512; - self.data[start..end].copy_from_slice(buf); - Ok(()) - } - - fn capacity(&self) -> usize { - self.data.len() / 512 - } -} - -impl MemoryFat32Img { - pub fn new(data: &'static mut [u8]) -> Self { - Self { data } - } -} diff --git a/kernel/src/driver/gpu.rs b/kernel/src/driver/gpu.rs deleted file mode 100644 index 61dbb485..00000000 --- a/kernel/src/driver/gpu.rs +++ /dev/null @@ -1,61 +0,0 @@ -use core::ptr::NonNull; -use virtio_drivers::device::gpu::VirtIOGpu; -use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; - -use ksync::Mutex; - -use crate::device::GpuDevice; -use crate::driver::hal::HalImpl; -use crate::interrupt::DeviceBase; - -pub struct VirtIOGpuWrapper { - gpu: Mutex>, - fb: &'static [u8], - #[allow(unused)] - resolution: (u32, u32), -} - -unsafe impl Sync for VirtIOGpuWrapper {} - -unsafe impl Send for VirtIOGpuWrapper {} - -impl VirtIOGpuWrapper { - pub fn new(addr: usize) -> Self { - let header = NonNull::new(addr as *mut VirtIOHeader).unwrap(); - let mmio = unsafe { MmioTransport::new(header) }.unwrap(); - let mut gpu = VirtIOGpu::new(mmio).unwrap(); - let resolution = gpu.resolution().unwrap(); - println!("GPU resolution: {:?}", resolution); - unsafe { - let fbuffer = gpu.setup_framebuffer().unwrap(); - let len = fbuffer.len(); - let ptr = fbuffer.as_mut_ptr(); - let fb = core::slice::from_raw_parts_mut(ptr, len); - gpu.move_cursor(50, 50).unwrap(); - Self { - gpu: Mutex::new(gpu), - fb, - resolution, - } - } - } -} - -impl DeviceBase for VirtIOGpuWrapper { - fn hand_irq(&self) { - self.gpu.lock().ack_interrupt(); - } -} - -impl GpuDevice for VirtIOGpuWrapper { - fn update_cursor(&self) {} - fn get_framebuffer(&self) -> &mut [u8] { - unsafe { - let ptr = self.fb.as_ptr() as *const _ as *mut u8; - core::slice::from_raw_parts_mut(ptr, self.fb.len()) - } - } - fn flush(&self) { - self.gpu.lock().flush().unwrap(); - } -} diff --git a/kernel/src/driver/hal.rs b/kernel/src/driver/hal.rs deleted file mode 100644 index 46a9147c..00000000 --- a/kernel/src/driver/hal.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::memory::{addr_to_frame, frame_alloc_contiguous}; -use core::ptr::NonNull; -use virtio_drivers::{BufferDirection, Hal, PhysAddr, PAGE_SIZE}; - -pub struct HalImpl; - -unsafe impl Hal for HalImpl { - fn dma_alloc(pages: usize, _direction: BufferDirection) -> (PhysAddr, NonNull) { - let start = frame_alloc_contiguous(pages); - (start as usize, NonNull::new(start).unwrap()) - } - - unsafe fn dma_dealloc(paddr: PhysAddr, _vaddr: NonNull, pages: usize) -> i32 { - for i in 0..pages { - let frame_tracker = addr_to_frame(paddr + i * PAGE_SIZE); - drop(frame_tracker); - } - 0 - } - - unsafe fn mmio_phys_to_virt(paddr: PhysAddr, _size: usize) -> NonNull { - NonNull::new(paddr as *mut u8).unwrap() - } - - unsafe fn share(buffer: NonNull<[u8]>, _direction: BufferDirection) -> PhysAddr { - let vaddr = buffer.as_ptr() as *mut u8 as usize; - vaddr - } - - unsafe fn unshare(_paddr: PhysAddr, _buffer: NonNull<[u8]>, _direction: BufferDirection) {} -} diff --git a/kernel/src/driver/input.rs b/kernel/src/driver/input.rs deleted file mode 100644 index 5f1d8d15..00000000 --- a/kernel/src/driver/input.rs +++ /dev/null @@ -1,105 +0,0 @@ -use alloc::collections::VecDeque; -use alloc::sync::Arc; -use core::ptr::NonNull; - -use virtio_drivers::device::input::VirtIOInput; -use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; - -use ksync::Mutex; -use smpscheduler::FifoTask; - -use crate::device::InputDevice; -use crate::driver::hal::HalImpl; -use crate::interrupt::DeviceBase; -use crate::task::schedule::schedule; -use crate::task::{current_task, Task, TaskState, GLOBAL_TASK_MANAGER}; - -pub struct VirtIOInputDriver { - inner: Mutex, -} - -unsafe impl Send for VirtIOInputDriver {} - -unsafe impl Sync for VirtIOInputDriver {} - -struct InputDriverInner { - max_events: u32, - driver: VirtIOInput, - events: VecDeque, - wait_queue: VecDeque>, -} - -impl VirtIOInputDriver { - fn new(driver: VirtIOInput, max_events: u32) -> Self { - let driver = VirtIOInputDriver { - inner: Mutex::new(InputDriverInner { - max_events, - driver, - events: VecDeque::with_capacity(max_events as usize), - wait_queue: VecDeque::new(), - }), - }; - driver - } - - pub fn from_addr(addr: usize, max_events: u32) -> Self { - let header = NonNull::new(addr as *mut VirtIOHeader).unwrap(); - let transport = unsafe { MmioTransport::new(header) }.unwrap(); - let input = VirtIOInput::::new(transport) - .expect("failed to create input driver"); - Self::new(input, max_events) - } -} - -impl InputDevice for VirtIOInputDriver { - fn is_empty(&self) -> bool { - let inner = self.inner.lock(); - inner.events.is_empty() - } - - fn read_event_with_block(&self) -> u64 { - loop { - { - let mut inner = self.inner.lock(); - if let Some(event) = inner.events.pop_front() { - return event; - } - let process = current_task().unwrap(); - process.update_state(TaskState::Waiting); - inner.wait_queue.push_back(process.clone()); - } // drop the lock - schedule(); - } - } - - fn read_event_without_block(&self) -> Option { - let mut inner = self.inner.lock(); - inner.events.pop_front() - } -} - -impl DeviceBase for VirtIOInputDriver { - fn hand_irq(&self) { - let mut inner = self.inner.lock(); - inner.driver.ack_interrupt(); - let mut count = 0; - while let Some(event) = inner.driver.pop_pending_event() { - let result = - (event.event_type as u64) << 48 | (event.code as u64) << 32 | (event.value) as u64; - info!("event: {:?}", event); - if inner.events.len() >= inner.max_events as usize { - // remove the first event - inner.events.pop_front(); - } - inner.events.push_back(result); - count += 1; - } - while !inner.wait_queue.is_empty() && count > 0 { - let process = inner.wait_queue.pop_front().unwrap(); - process.update_state(TaskState::Ready); - GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(process))); - count -= 1; - } - info!("read {} events", count); - } -} diff --git a/kernel/src/driver/mod.rs b/kernel/src/driver/mod.rs deleted file mode 100644 index 5dc3e4d8..00000000 --- a/kernel/src/driver/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub use block_device::*; -mod block_device; -pub mod hal; - -pub mod gpu; -pub mod input; -pub mod net; -pub mod rtc; -pub mod uart; diff --git a/kernel/src/driver/net.rs b/kernel/src/driver/net.rs deleted file mode 100644 index a776a543..00000000 --- a/kernel/src/driver/net.rs +++ /dev/null @@ -1,18 +0,0 @@ -use core::ptr::NonNull; - -use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; -use virtio_net::VirtIONetDeviceWrapper; - -use crate::driver::hal::HalImpl; - -pub const NET_BUFFER_LEN: usize = 4096; -pub const NET_QUEUE_SIZE: usize = 128; - -pub fn make_virtio_net_device( - addr: usize, -) -> VirtIONetDeviceWrapper { - let header = NonNull::new(addr as *mut VirtIOHeader).unwrap(); - let transport = unsafe { MmioTransport::new(header) }.unwrap(); - let device = VirtIONetDeviceWrapper::new(transport, NET_BUFFER_LEN); - device -} diff --git a/kernel/src/driver/rtc.rs b/kernel/src/driver/rtc.rs deleted file mode 100644 index 788480f6..00000000 --- a/kernel/src/driver/rtc.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub use rtc::goldfish::GoldFishRtc; -use rtc::{LowRtcDevice, LowRtcDeviceExt}; - -use crate::device::RtcDevice; -use crate::interrupt::DeviceBase; - -impl DeviceBase for GoldFishRtc { - fn hand_irq(&self) { - let alarm = self.read_alarm_fmt(); - let time = self.read_time_fmt(); - println!("rtc interrupt, time: {:?}, alarm: {:?}", time, alarm); - self.clear_irq(); - self.set_alarm(self.read_time() + 1_000_000_000 * 5); - } -} - -impl RtcDevice for GoldFishRtc {} diff --git a/kernel/src/driver/uart.rs b/kernel/src/driver/uart.rs deleted file mode 100644 index a1e7cc38..00000000 --- a/kernel/src/driver/uart.rs +++ /dev/null @@ -1,181 +0,0 @@ -use alloc::boxed::Box; -use alloc::collections::VecDeque; -use alloc::sync::Arc; -use ksync::Mutex; -use smpscheduler::FifoTask; - -#[cfg(not(feature = "vf2"))] -pub use self::uart16550::Uart16550; -use crate::device::UartDevice; -use crate::interrupt::DeviceBase; -use crate::task::schedule::schedule; -use crate::task::{current_task, Task, TaskState, GLOBAL_TASK_MANAGER}; - -#[cfg(feature = "vf2")] -pub use self::uart8250::Uart8250; - -pub trait LowUartDriver: Send + Sync { - fn _init(&mut self); - fn _put(&mut self, c: u8); - fn _read(&mut self) -> Option; -} - -#[cfg(feature = "vf2")] -mod uart8250 { - use crate::driver::uart::LowUartDriver; - - pub struct Uart8250 { - uart_raw: uart8250::MmioUart8250<'static, u32>, - } - - unsafe impl Send for Uart8250 {} - - unsafe impl Sync for Uart8250 {} - - impl Uart8250 { - pub fn new(base_addr: usize) -> Self { - let uart_raw = unsafe { uart8250::MmioUart8250::::new(base_addr) }; - Uart8250 { uart_raw } - } - } - - impl LowUartDriver for Uart8250 { - fn _init(&mut self) { - self.uart_raw.enable_received_data_available_interrupt(); - } - - fn _put(&mut self, c: u8) { - loop { - if self.uart_raw.write_byte(c).is_ok() { - break; - } - } - } - - fn _read(&mut self) -> Option { - self.uart_raw.read_byte() - } - } -} - -#[cfg(not(feature = "vf2"))] -mod uart16550 { - use crate::driver::uart::LowUartDriver; - - pub struct Uart16550 { - uart_raw: &'static mut uart16550::Uart16550, - } - - unsafe impl Send for Uart16550 {} - - unsafe impl Sync for Uart16550 {} - - impl Uart16550 { - pub fn new(base_addr: usize) -> Self { - let uart_raw = unsafe { &mut *(base_addr as *mut uart16550::Uart16550) }; - Uart16550 { uart_raw } - } - } - - impl LowUartDriver for Uart16550 { - fn _init(&mut self) { - use uart16550::InterruptTypes; - let ier = self.uart_raw.ier(); - let inter = InterruptTypes::ZERO; - ier.write(inter.enable_rda()); - } - - fn _put(&mut self, c: u8) { - self.uart_raw.write(&[c]); - } - - fn _read(&mut self) -> Option { - let mut buf = [0]; - let r = self.uart_raw.read(&mut buf); - if r == 0 { - None - } else { - Some(buf[0]) - } - } - } -} - -pub struct Uart { - inner: Mutex<(Box, UartInner)>, -} - -struct UartInner { - rx_buf: VecDeque, - wait_queue: VecDeque>, -} - -impl Uart { - pub fn new(uart_raw: Box) -> Self { - let mut uart_raw = uart_raw; - uart_raw._init(); - let inner = UartInner { - rx_buf: VecDeque::new(), - wait_queue: VecDeque::new(), - }; - Uart { - inner: Mutex::new((uart_raw, inner)), - } - } -} - -impl UartDevice for Uart { - fn put(&self, c: u8) { - let mut inner = self.inner.lock(); - inner.0._put(c); - } - fn get(&self) -> Option { - loop { - let mut inner = self.inner.lock(); - if inner.1.rx_buf.is_empty() { - let current_process = current_task().unwrap(); - current_process.update_state(TaskState::Waiting); - inner.1.wait_queue.push_back(current_process.clone()); - drop(inner); - schedule(); - } else { - return inner.1.rx_buf.pop_front(); - } - } - } - - fn put_bytes(&self, bytes: &[u8]) { - for &c in bytes { - if c == b'\n' { - self.put(b'\r'); - } - self.put(c); - } - } - - fn have_data_to_get(&self) -> bool { - !self.inner.lock().1.rx_buf.is_empty() - } - - fn have_space_to_put(&self) -> bool { - true - } -} - -impl DeviceBase for Uart { - fn hand_irq(&self) { - loop { - let mut inner = self.inner.lock(); - if let Some(c) = inner.0._read() { - inner.1.rx_buf.push_back(c); - if !inner.1.wait_queue.is_empty() { - let task = inner.1.wait_queue.pop_front().unwrap(); - task.update_state(TaskState::Ready); - GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); - } - } else { - break; - } - } - } -} diff --git a/kernel/src/fs/basic.rs b/kernel/src/fs/basic.rs index 9d88776d..4f176597 100644 --- a/kernel/src/fs/basic.rs +++ b/kernel/src/fs/basic.rs @@ -1,19 +1,18 @@ use super::im2vim; -use crate::config::AT_FDCWD; -use crate::fs::file::KernelFile; -use crate::fs::{syscontext_for_vfs, user_path_at, FS, SYSTEM_ROOT_FS}; +use crate::fs::{syscontext_for_vfs, user_path_at}; use crate::task::current_task; use alloc::sync::Arc; use alloc::vec; use constants::io::{ FileStat, FsStat, InodeMode, IoVec, MountFlags, OpenFlags, Renameat2Flags, SeekFrom, StatFlags, }; -use constants::AlienResult; use constants::LinuxErrno; +use constants::{AlienResult, AT_FDCWD}; use core::cmp::min; -use core::ops::Index; use gmanager::ManagerError; +use log::{info, warn}; use syscall_table::syscall_func; +use vfs::kfile::KernelFile; use vfscore::path::VfsPath; use vfscore::utils::{VfsFileStat, VfsFsStat, VfsNodeType, VfsRenameFlag}; @@ -36,16 +35,11 @@ pub fn sys_mount( "mount special:{:?},dir:{:?},fs_type:{:?},flags:{:?},data:{:?}", source, dir, fs_type, flags, data ); - let find = FS - .lock() - .iter() - .find(|(name, _)| name.eq(&&fs_type)) - .map(|(_, fs)| fs.clone()) - .ok_or(LinuxErrno::EINVAL)?; - let path = VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()); + let find = vfs::system_support_fs(&fs_type).ok_or(LinuxErrno::EINVAL)?; + let path = VfsPath::new(vfs::system_root_fs()); let fs_root = match find.fs_name() { name @ ("tmpfs" | "ramfs" | "fat32") => { - let fs = FS.lock().index(name).clone(); + let fs = vfs::system_support_fs(name).unwrap(); let dev = if name.eq("fat32") { let dev = path.join(source)?.open(None)?; Some(dev.inode()?) @@ -67,7 +61,7 @@ pub fn sys_umount(dir: *const u8) -> AlienResult { let process = current_task().unwrap(); let dir = process.transfer_str(dir); info!("umount dir:{:?}", dir); - let path = VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()); + let path = VfsPath::new(vfs::system_root_fs()); path.join(dir)?.umount()?; Ok(0) } diff --git a/kernel/src/fs/control.rs b/kernel/src/fs/control.rs index 337a55fb..85ab8bbf 100644 --- a/kernel/src/fs/control.rs +++ b/kernel/src/fs/control.rs @@ -1,11 +1,11 @@ -use crate::config::AT_FDCWD; use crate::fs::user_path_at; use crate::task::current_task; -use crate::timer::TimeSpec; use constants::io::{FaccessatFlags, FaccessatMode, Fcntl64Cmd, OpenFlags, TeletypeCommand}; -use constants::AlienResult; use constants::LinuxErrno; +use constants::{AlienResult, AT_FDCWD}; +use log::{info, warn}; use syscall_table::syscall_func; +use timer::TimeSpec; use vfscore::utils::*; const FD_CLOEXEC: usize = 1; diff --git a/kernel/src/fs/dev/mod.rs b/kernel/src/fs/dev/mod.rs deleted file mode 100644 index 2da04bea..00000000 --- a/kernel/src/fs/dev/mod.rs +++ /dev/null @@ -1,275 +0,0 @@ -use crate::device::{ - BLKDevice, GPUDevice, INPUTDevice, RTCDevice, UARTDevice, BLOCK_DEVICE, GPU_DEVICE, - KEYBOARD_INPUT_DEVICE, MOUSE_INPUT_DEVICE, RTC_DEVICE, UART_DEVICE, -}; -use crate::fs::dev::null::NullDevice; -use crate::fs::dev::random::RandomDevice; -use alloc::collections::BTreeMap; -use alloc::sync::Arc; -use devfs::DevKernelProvider; -use ksync::Mutex; -use spin::Lazy; -use vfscore::dentry::VfsDentry; -use vfscore::fstype::VfsFsType; -use vfscore::inode::VfsInode; -use vfscore::utils::{VfsNodeType, VfsTimeSpec}; - -mod null; -mod random; - -pub static DEVICES: Lazy>>> = - Lazy::new(|| Mutex::new(BTreeMap::new())); - -pub static DEVICE_ID_MANAGER: Lazy> = - Lazy::new(|| Mutex::new(DeviceIdManager::new())); - -pub fn register_device(inode: Arc) { - let rdev = inode.get_attr().unwrap().st_rdev; - let device_id = DeviceId::from(rdev); - DEVICES.lock().insert(device_id, inode); -} - -pub fn unregister_device(rdev: DeviceId) { - DEVICES.lock().remove(&rdev); -} - -pub fn alloc_device_id(inode_type: VfsNodeType) -> DeviceId { - DEVICE_ID_MANAGER.lock().alloc(inode_type) -} - -#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq, Hash, Ord)] -pub struct DeviceId { - major: u32, - minor: u32, -} - -impl DeviceId { - pub fn new(major: u32, minor: u32) -> Self { - Self { major, minor } - } - pub fn major(&self) -> u32 { - self.major - } - pub fn minor(&self) -> u32 { - self.minor - } - pub fn id(&self) -> u64 { - ((self.major as u64) << 32) | (self.minor as u64) - } -} - -impl From for DeviceId { - fn from(id: u64) -> Self { - Self { - major: (id >> 32) as u32, - minor: (id & 0xffffffff) as u32, - } - } -} - -pub trait InodeType2u32 { - fn to_u32(&self) -> u32; -} - -impl InodeType2u32 for VfsNodeType { - fn to_u32(&self) -> u32 { - match self { - VfsNodeType::CharDevice => 2, - VfsNodeType::BlockDevice => 3, - _ => 0, - } - } -} - -pub struct DeviceIdManager { - map: BTreeMap, -} - -impl DeviceIdManager { - pub fn new() -> Self { - Self { - map: BTreeMap::new(), - } - } - pub fn alloc(&mut self, inode_type: VfsNodeType) -> DeviceId { - assert!(matches!( - inode_type, - VfsNodeType::CharDevice | VfsNodeType::BlockDevice - )); - let id = self.map.entry(inode_type.to_u32()).or_insert(0); - *id += 1; - DeviceId::new(inode_type.to_u32(), *id) - } -} - -#[derive(Clone)] -pub struct DevFsProviderImpl; -impl DevKernelProvider for DevFsProviderImpl { - fn current_time(&self) -> VfsTimeSpec { - VfsTimeSpec::new(0, 0) - } - fn rdev2device(&self, rdev: u64) -> Option> { - let device_id = DeviceId::from(rdev); - DEVICES.lock().get(&device_id).cloned() - } -} -///```bash -/// | -/// |-- null -/// |-- zero -/// |-- random -/// |-- urandom -/// |-- tty -/// |-- shm (a ramfs will be mounted here) -/// |-- misc -/// |-- rtc -/// ``` -pub fn init_devfs(devfs: Arc) -> Arc { - let root = devfs.i_mount(0, "/dev", None, &[]).unwrap(); - let root_inode = root.inode().unwrap(); - - let null_device = Arc::new(NullDevice::new(alloc_device_id(VfsNodeType::CharDevice))); - let zero_device = Arc::new(NullDevice::new(alloc_device_id(VfsNodeType::CharDevice))); - let random_device = Arc::new(RandomDevice::new(alloc_device_id(VfsNodeType::CharDevice))); - let urandom_device = Arc::new(RandomDevice::new(alloc_device_id(VfsNodeType::CharDevice))); - - root_inode - .create( - "null", - 'c'.into(), - "rw-rw-rw-".into(), - Some(null_device.device_id().id()), - ) - .unwrap(); - root_inode - .create( - "zero", - 'c'.into(), - "rw-rw-rw-".into(), - Some(zero_device.device_id().id()), - ) - .unwrap(); - root_inode - .create( - "random", - 'c'.into(), - "rw-rw-rw-".into(), - Some(random_device.device_id().id()), - ) - .unwrap(); - root_inode - .create( - "urandom", - 'c'.into(), - "rw-rw-rw-".into(), - Some(urandom_device.device_id().id()), - ) - .unwrap(); - - register_device(null_device); - register_device(zero_device); - register_device(random_device); - register_device(urandom_device); - - root_inode - .create("shm", VfsNodeType::Dir, "rwxrwxrwx".into(), None) - .unwrap(); - root_inode - .create("misc", VfsNodeType::Dir, "rwxrwxrwx".into(), None) - .unwrap(); - - scan_system_devices(root_inode); - // todo!(tty,shm,misc) - println!("devfs init success"); - root -} - -fn scan_system_devices(root: Arc) { - BLOCK_DEVICE.get().map(|blk| { - let block_device = Arc::new(BLKDevice::new( - alloc_device_id(VfsNodeType::BlockDevice), - blk.clone(), - )); - root.create( - "sda", - VfsNodeType::BlockDevice, - "rw-rw----".into(), - Some(block_device.device_id().id()), - ) - .unwrap(); - register_device(block_device); - }); - GPU_DEVICE.get().map(|gpu| { - let gpu_device = Arc::new(GPUDevice::new( - alloc_device_id(VfsNodeType::CharDevice), - gpu.clone(), - )); - root.create( - "gpu", - VfsNodeType::BlockDevice, - "rw-rw----".into(), - Some(gpu_device.device_id().id()), - ) - .unwrap(); - register_device(gpu_device); - }); - KEYBOARD_INPUT_DEVICE.get().map(|input| { - let input_device = Arc::new(INPUTDevice::new( - alloc_device_id(VfsNodeType::CharDevice), - input.clone(), - false, - )); - root.create( - "keyboard", - VfsNodeType::BlockDevice, - "rw-rw----".into(), - Some(input_device.device_id().id()), - ) - .unwrap(); - register_device(input_device); - }); - MOUSE_INPUT_DEVICE.get().map(|input| { - let input_device = Arc::new(INPUTDevice::new( - alloc_device_id(VfsNodeType::CharDevice), - input.clone(), - true, - )); - root.create( - "mouse", - VfsNodeType::BlockDevice, - "rw-rw----".into(), - Some(input_device.device_id().id()), - ) - .unwrap(); - register_device(input_device); - }); - RTC_DEVICE.get().map(|rtc| { - let rtc_device = Arc::new(RTCDevice::new( - alloc_device_id(VfsNodeType::CharDevice), - rtc.clone(), - )); - root.create( - "rtc", - VfsNodeType::BlockDevice, - "rw-rw----".into(), - Some(rtc_device.device_id().id()), - ) - .unwrap(); - register_device(rtc_device); - }); - UART_DEVICE.get().map(|uart| { - let uart_device = Arc::new(UARTDevice::new( - alloc_device_id(VfsNodeType::CharDevice), - uart.clone(), - )); - root.create( - "tty", - VfsNodeType::BlockDevice, - "rw-rw----".into(), - Some(uart_device.device_id().id()), - ) - .unwrap(); - info!("uart device id: {}", uart_device.device_id().id()); - register_device(uart_device); - }); -} diff --git a/kernel/src/fs/dev/null.rs b/kernel/src/fs/dev/null.rs deleted file mode 100644 index fbe37bc6..00000000 --- a/kernel/src/fs/dev/null.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::fs::dev::DeviceId; -use alloc::sync::Arc; -use vfscore::error::VfsError; -use vfscore::file::VfsFile; -use vfscore::inode::{InodeAttr, VfsInode}; -use vfscore::superblock::VfsSuperBlock; -use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; -use vfscore::VfsResult; - -pub struct NullDevice { - device_id: DeviceId, -} - -impl NullDevice { - pub fn new(device_id: DeviceId) -> Self { - Self { device_id } - } - pub fn device_id(&self) -> DeviceId { - self.device_id - } -} - -impl VfsFile for NullDevice { - fn read_at(&self, _offset: u64, buf: &mut [u8]) -> VfsResult { - buf.fill(0); - Ok(buf.len()) - } - fn write_at(&self, _offset: u64, buf: &[u8]) -> VfsResult { - Ok(buf.len()) - } -} - -impl VfsInode for NullDevice { - fn get_super_block(&self) -> VfsResult> { - Err(VfsError::NoSys) - } - - fn node_perm(&self) -> VfsNodePerm { - VfsNodePerm::empty() - } - - fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { - Ok(()) - } - - fn get_attr(&self) -> VfsResult { - Ok(VfsFileStat { - st_rdev: self.device_id.id(), - ..Default::default() - }) - } - fn inode_type(&self) -> VfsNodeType { - VfsNodeType::CharDevice - } -} diff --git a/kernel/src/fs/dev/random.rs b/kernel/src/fs/dev/random.rs deleted file mode 100644 index 97ba584f..00000000 --- a/kernel/src/fs/dev/random.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::fs::dev::DeviceId; -use crate::timer::read_timer; -use alloc::sync::Arc; -use vfscore::error::VfsError; -use vfscore::file::VfsFile; -use vfscore::inode::{InodeAttr, VfsInode}; -use vfscore::superblock::VfsSuperBlock; -use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; -use vfscore::VfsResult; - -pub struct RandomDevice { - device_id: DeviceId, -} -impl RandomDevice { - pub fn new(device_id: DeviceId) -> Self { - Self { device_id } - } - pub fn device_id(&self) -> DeviceId { - self.device_id - } -} - -impl VfsFile for RandomDevice { - fn read_at(&self, _offset: u64, buf: &mut [u8]) -> VfsResult { - let mut current_time = read_timer(); - buf.iter_mut().for_each(|x| { - *x = current_time as u8; - current_time = current_time.wrapping_sub(1); - }); - Ok(buf.len()) - } - fn write_at(&self, _offset: u64, buf: &[u8]) -> VfsResult { - Ok(buf.len()) - } -} - -impl VfsInode for RandomDevice { - fn get_super_block(&self) -> VfsResult> { - Err(VfsError::NoSys) - } - - fn node_perm(&self) -> VfsNodePerm { - VfsNodePerm::empty() - } - - fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { - Ok(()) - } - - fn get_attr(&self) -> VfsResult { - Ok(VfsFileStat { - st_rdev: self.device_id.id(), - ..Default::default() - }) - } - - fn inode_type(&self) -> VfsNodeType { - VfsNodeType::CharDevice - } -} diff --git a/kernel/src/fs/ext.rs b/kernel/src/fs/ext.rs index a1219ce8..601c1de6 100644 --- a/kernel/src/fs/ext.rs +++ b/kernel/src/fs/ext.rs @@ -1,9 +1,11 @@ -use constants::LinuxErrno; +use crate::fs::user_path_at; +use crate::task::current_task; +use constants::AlienResult; +use constants::{LinuxErrno, AT_FDCWD}; use core::cmp::min; +use syscall_table::syscall_func; use vfscore::path::VfsPath; -use crate::{config::AT_FDCWD, fs::user_path_at, task::current_task}; -use constants::AlienResult; /// 一个系统调用,用于设置文件的 扩展属性(xattrs, Extended Attributes)。 /// /// 扩展属性(xattrs)提供了一个机制用来将一个(键, 值)对永久地关联到文件,让现有的文件系统得以支持在原始设计中未提供的功能。扩展属性是文件系统不可知论者, diff --git a/kernel/src/fs/file.rs b/kernel/src/fs/file.rs deleted file mode 100644 index f6f01bbe..00000000 --- a/kernel/src/fs/file.rs +++ /dev/null @@ -1,278 +0,0 @@ -use constants::io::DirentType; -pub use kernel_file::{File, KernelFile}; -use vfscore::utils::VfsNodeType; - -mod kernel_file { - use super::vfsnodetype2dirent64; - use alloc::sync::Arc; - use constants::io::{Dirent64, OpenFlags, PollEvents, SeekFrom}; - use constants::AlienResult; - use constants::LinuxErrno; - use core::fmt::{Debug, Formatter}; - use downcast_rs::{impl_downcast, DowncastSync}; - use ksync::Mutex; - use vfscore::dentry::VfsDentry; - use vfscore::error::VfsError; - use vfscore::inode::VfsInode; - use vfscore::path::VfsPath; - use vfscore::utils::{VfsFileStat, VfsPollEvents}; - pub struct KernelFile { - pos: Mutex, - open_flag: Mutex, - dentry: Arc, - } - - impl Debug for KernelFile { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("KernelFile") - .field("pos", &self.pos) - .field("open_flag", &self.open_flag) - .field("name", &self.dentry.name()) - .finish() - } - } - - impl KernelFile { - pub fn new(dentry: Arc, open_flag: OpenFlags) -> Self { - let pos = if open_flag.contains(OpenFlags::O_APPEND) { - dentry.inode().unwrap().get_attr().unwrap().st_size - } else { - 0 - }; - Self { - pos: Mutex::new(pos), - open_flag: Mutex::new(open_flag), - dentry, - } - } - } - - pub trait File: DowncastSync + Debug { - fn read(&self, buf: &mut [u8]) -> AlienResult; - fn write(&self, buf: &[u8]) -> AlienResult; - fn read_at(&self, _offset: u64, _buf: &mut [u8]) -> AlienResult { - Err(LinuxErrno::ENOSYS) - } - fn write_at(&self, _offset: u64, _buf: &[u8]) -> AlienResult { - Err(LinuxErrno::ENOSYS) - } - fn flush(&self) -> AlienResult<()> { - Ok(()) - } - fn fsync(&self) -> AlienResult<()> { - Ok(()) - } - fn seek(&self, pos: SeekFrom) -> AlienResult; - /// Gets the file attributes. - fn get_attr(&self) -> AlienResult; - fn ioctl(&self, _cmd: u32, _arg: usize) -> AlienResult { - Err(LinuxErrno::ENOSYS) - } - fn set_open_flag(&self, _flag: OpenFlags) {} - fn get_open_flag(&self) -> OpenFlags { - OpenFlags::O_RDONLY - } - fn dentry(&self) -> Arc; - fn inode(&self) -> Arc; - fn readdir(&self, _buf: &mut [u8]) -> AlienResult { - Err(LinuxErrno::ENOSYS) - } - fn truncate(&self, _len: u64) -> AlienResult<()> { - Err(LinuxErrno::ENOSYS) - } - fn is_readable(&self) -> bool; - fn is_writable(&self) -> bool; - fn is_append(&self) -> bool; - fn poll(&self, _event: PollEvents) -> AlienResult { - Err(LinuxErrno::ENOSYS) - } - } - - impl_downcast!(sync File); - - // todo! permission check - impl File for KernelFile { - fn read(&self, buf: &mut [u8]) -> AlienResult { - if buf.len() == 0 { - return Ok(0); - } - // warn!("[read] is_interrupt_enable:{}",is_interrupt_enable()); - let pos = *self.pos.lock(); - // warn!("[read] is_interrupt_enable:{}",is_interrupt_enable()); - let read = self.read_at(pos, buf)?; - *self.pos.lock() += read as u64; - Ok(read) - } - fn write(&self, buf: &[u8]) -> AlienResult { - if buf.len() == 0 { - return Ok(0); - } - let mut pos = self.pos.lock(); - let write = self.write_at(*pos, buf)?; - *pos += write as u64; - Ok(write) - } - fn read_at(&self, offset: u64, buf: &mut [u8]) -> AlienResult { - if buf.len() == 0 { - return Ok(0); - } - let open_flag = self.open_flag.lock(); - if !open_flag.contains(OpenFlags::O_RDONLY) && !open_flag.contains(OpenFlags::O_RDWR) { - return Err(LinuxErrno::EPERM); - } - drop(open_flag); - let inode = self.dentry.inode()?; - let read = inode.read_at(offset, buf)?; - Ok(read) - } - - fn write_at(&self, _offset: u64, buf: &[u8]) -> AlienResult { - if buf.len() == 0 { - return Ok(0); - } - let open_flag = self.open_flag.lock(); - if !open_flag.contains(OpenFlags::O_WRONLY) && !open_flag.contains(OpenFlags::O_RDWR) { - return Err(LinuxErrno::EPERM); - } - let inode = self.dentry.inode()?; - let write = inode.write_at(_offset, buf)?; - Ok(write) - } - - fn flush(&self) -> AlienResult<()> { - let open_flag = self.open_flag.lock(); - if !open_flag.contains(OpenFlags::O_WRONLY) & !open_flag.contains(OpenFlags::O_RDWR) { - return Err(LinuxErrno::EPERM); - } - let inode = self.dentry.inode()?; - inode.flush()?; - Ok(()) - } - - fn fsync(&self) -> AlienResult<()> { - let open_flag = self.open_flag.lock(); - if !open_flag.contains(OpenFlags::O_WRONLY) && !open_flag.contains(OpenFlags::O_RDWR) { - return Err(LinuxErrno::EPERM); - } - let inode = self.dentry.inode()?; - inode.fsync()?; - Ok(()) - } - - // check for special file - fn seek(&self, pos: SeekFrom) -> AlienResult { - let mut spos = self.pos.lock(); - let size = self.get_attr()?.st_size; - let new_offset = match pos { - SeekFrom::Start(pos) => Some(pos), - SeekFrom::Current(off) => spos.checked_add_signed(off), - SeekFrom::End(off) => size.checked_add_signed(off), - } - .ok_or_else(|| VfsError::Invalid)?; - *spos = new_offset; - Ok(new_offset) - } - - /// Gets the file attributes. - fn get_attr(&self) -> AlienResult { - self.dentry.inode()?.get_attr().map_err(Into::into) - } - - fn ioctl(&self, _cmd: u32, _arg: usize) -> AlienResult { - let inode = self.dentry.inode().unwrap(); - inode.ioctl(_cmd, _arg).map_err(Into::into) - } - - fn set_open_flag(&self, flag: OpenFlags) { - *self.open_flag.lock() = flag; - } - - fn get_open_flag(&self) -> OpenFlags { - *self.open_flag.lock() - } - fn dentry(&self) -> Arc { - self.dentry.clone() - } - fn inode(&self) -> Arc { - self.dentry.inode().unwrap() - } - fn readdir(&self, buf: &mut [u8]) -> AlienResult { - let inode = self.inode(); - let mut pos = self.pos.lock(); - let mut count = 0; - let mut ptr = buf.as_mut_ptr(); - loop { - let dirent = inode.readdir(*pos as usize).map_err(|e| { - *pos = 0; - e - })?; - match dirent { - Some(d) => { - let dirent64 = - Dirent64::new(&d.name, d.ino, *pos as i64, vfsnodetype2dirent64(d.ty)); - if count + dirent64.len() <= buf.len() { - let dirent_ptr = unsafe { &mut *(ptr as *mut Dirent64) }; - *dirent_ptr = dirent64; - let name_ptr = dirent_ptr.name.as_mut_ptr(); - unsafe { - let mut name = d.name.clone(); - name.push('\0'); - let len = name.len(); - name_ptr.copy_from(name.as_ptr(), len); - ptr = ptr.add(dirent_ptr.len()); - } - count += dirent_ptr.len(); - } else { - break; - } // Buf is small - } - None => { - break; - } // EOF - } - *pos += 1; - } - Ok(count) - } - fn truncate(&self, len: u64) -> AlienResult<()> { - let open_flag = self.open_flag.lock(); - if !open_flag.contains(OpenFlags::O_WRONLY) & !open_flag.contains(OpenFlags::O_RDWR) { - return Err(LinuxErrno::EINVAL); - } - let dt = self.dentry(); - VfsPath::new(dt).truncate(len).map_err(Into::into) - } - fn is_readable(&self) -> bool { - let open_flag = self.open_flag.lock(); - open_flag.contains(OpenFlags::O_RDONLY) | open_flag.contains(OpenFlags::O_RDWR) - } - fn is_writable(&self) -> bool { - let open_flag = self.open_flag.lock(); - open_flag.contains(OpenFlags::O_WRONLY) | open_flag.contains(OpenFlags::O_RDWR) - } - - fn is_append(&self) -> bool { - let open_flag = self.open_flag.lock(); - open_flag.contains(OpenFlags::O_APPEND) - } - - fn poll(&self, _event: PollEvents) -> AlienResult { - let inode = self.dentry.inode()?; - let res = inode - .poll(VfsPollEvents::from_bits_truncate(_event.bits())) - .map(|e| PollEvents::from_bits_truncate(e.bits())); - res.map_err(Into::into) - } - } -} - -fn vfsnodetype2dirent64(ty: VfsNodeType) -> DirentType { - DirentType::from_u8(ty as u8) -} - -impl Drop for KernelFile { - fn drop(&mut self) { - let _ = self.flush(); - let _ = self.fsync(); - } -} diff --git a/kernel/src/fs/link.rs b/kernel/src/fs/link.rs index 0e71bb61..7f45274e 100644 --- a/kernel/src/fs/link.rs +++ b/kernel/src/fs/link.rs @@ -1,5 +1,6 @@ use alloc::vec; use constants::io::{LinkFlags, UnlinkatFlags}; +use log::{info, warn}; use syscall_table::syscall_func; use crate::{fs::user_path_at, task::current_task}; diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs index aad62d1e..fdb5b8d4 100644 --- a/kernel/src/fs/mod.rs +++ b/kernel/src/fs/mod.rs @@ -1,154 +1,18 @@ -use crate::config::AT_FDCWD; -use crate::fs::dev::{init_devfs, DevFsProviderImpl}; -use crate::fs::proc::init_procfs; -use crate::fs::ram::init_ramfs; -use crate::fs::sys::init_sysfs; -use crate::ipc::init_pipefs; -use crate::print::console::Stdout; -use crate::task::{current_task, FsContext}; -use alloc::collections::BTreeMap; -use alloc::string::{String, ToString}; -use alloc::sync::Arc; -use alloc::vec; -use alloc::vec::Vec; -pub use basic::*; -use constants::io::InodeMode; -use constants::AlienResult; -use constants::LinuxErrno; -pub use control::*; -use core::ops::Index; -use dynfs::DynFsKernelProvider; -use fat_vfs::FatFsProvider; -use ksync::Mutex; -pub use poll::*; -use riscv::register::sstatus::FS; -pub use select::*; -use spin::{Lazy, Once}; -pub use stdio::*; -use vfscore::dentry::VfsDentry; -use vfscore::fstype::VfsFsType; -use vfscore::path::{SysContext, VfsPath}; -use vfscore::utils::{VfsInodeMode, VfsNodeType, VfsTimeSpec}; - -pub mod stdio; - pub mod basic; pub mod control; -pub mod dev; pub mod ext; -pub mod file; pub mod link; pub mod poll; -pub mod proc; -pub mod ram; pub mod select; -pub mod sys; - -pub static FS: Lazy>>> = - Lazy::new(|| Mutex::new(BTreeMap::new())); - -pub static SYSTEM_ROOT_FS: Once> = Once::new(); - -type SysFs = dynfs::DynFs>; -type ProcFs = dynfs::DynFs>; -type RamFs = ramfs::RamFs>; -type DevFs = devfs::DevFs>; -type TmpFs = ramfs::RamFs>; -type PipeFs = dynfs::DynFs>; -type FatFs = fat_vfs::FatFs>; - -#[derive(Clone)] -pub struct CommonFsProviderImpl; - -impl DynFsKernelProvider for CommonFsProviderImpl { - fn current_time(&self) -> VfsTimeSpec { - VfsTimeSpec::new(0, 0) - } -} - -impl ramfs::RamFsProvider for CommonFsProviderImpl { - fn current_time(&self) -> VfsTimeSpec { - DynFsKernelProvider::current_time(self) - } -} - -impl FatFsProvider for CommonFsProviderImpl { - fn current_time(&self) -> VfsTimeSpec { - DynFsKernelProvider::current_time(self) - } -} - -fn register_all_fs() { - let procfs = Arc::new(ProcFs::new(CommonFsProviderImpl, "procfs")); - let sysfs = Arc::new(SysFs::new(CommonFsProviderImpl, "sysfs")); - let ramfs = Arc::new(RamFs::new(CommonFsProviderImpl)); - let devfs = Arc::new(DevFs::new(DevFsProviderImpl)); - let tmpfs = Arc::new(TmpFs::new(CommonFsProviderImpl)); - let pipefs = Arc::new(PipeFs::new(CommonFsProviderImpl, "pipefs")); - - let fatfs = Arc::new(FatFs::new(CommonFsProviderImpl)); - - FS.lock().insert("procfs".to_string(), procfs); - FS.lock().insert("sysfs".to_string(), sysfs); - FS.lock().insert("ramfs".to_string(), ramfs); - FS.lock().insert("devfs".to_string(), devfs); - FS.lock().insert("tmpfs".to_string(), tmpfs); - FS.lock().insert("pipefs".to_string(), pipefs); - FS.lock().insert("fatfs".to_string(), fatfs); - println!("register fs success"); -} - -/// Init the filesystem -pub fn init_filesystem() -> AlienResult<()> { - register_all_fs(); - let ramfs_root = init_ramfs(FS.lock().index("ramfs").clone()); - let procfs_root = init_procfs(FS.lock().index("procfs").clone()); - let devfs_root = init_devfs(FS.lock().index("devfs").clone()); - let sysfs_root = init_sysfs(FS.lock().index("sysfs").clone()); - let tmpfs_root = FS - .lock() - .index("tmpfs") - .clone() - .i_mount(0, "/tmp", None, &[])?; - - init_pipefs(FS.lock().index("pipefs").clone()); - - let path = VfsPath::new(ramfs_root.clone()); - path.join("proc")?.mount(procfs_root, 0)?; - path.join("sys")?.mount(sysfs_root, 0)?; - path.join("dev")?.mount(devfs_root, 0)?; - path.join("tmp")?.mount(tmpfs_root.clone(), 0)?; - - let shm_ramfs = FS - .lock() - .index("ramfs") - .clone() - .i_mount(0, "/dev/shm", None, &[])?; - path.join("dev/shm")?.mount(shm_ramfs, 0)?; - - let fatfs = FS.lock().index("fatfs").clone(); - let blk_inode = path - .join("/dev/sda")? - .open(None) - .expect("open /dev/sda failed") - .inode()?; - let fat32_root = fatfs.i_mount(0, "/bin", Some(blk_inode), &[])?; - path.join("bin")?.mount(fat32_root, 0)?; - - vfscore::path::print_fs_tree(&mut VfsOutPut, ramfs_root.clone(), "".to_string(), false) - .unwrap(); - SYSTEM_ROOT_FS.call_once(|| ramfs_root); - println!("Init filesystem success"); - Ok(()) -} +pub mod stdio; -struct VfsOutPut; -impl core::fmt::Write for VfsOutPut { - fn write_str(&mut self, s: &str) -> core::fmt::Result { - Stdout.write_str(s).unwrap(); - Ok(()) - } -} +use crate::task::{current_task, FsContext}; +use alloc::vec::Vec; +use constants::io::InodeMode; +use constants::{AlienResult, LinuxErrno, AT_FDCWD}; +use log::info; +use vfscore::path::{SysContext, VfsPath}; +use vfscore::utils::{VfsInodeMode, VfsNodeType}; /// 地址解析函数,通过 `fd` 所指向的一个目录文件 和 相对于该目录文件的路径或绝对路径 `path` 解析出某目标文件的绝对路径。 /// @@ -171,7 +35,7 @@ fn user_path_at(fd: isize, path: &str) -> AlienResult { VfsPath::new(file.dentry()).join(path) } } else { - VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()).join(path) + VfsPath::new(vfs::system_root_fs()).join(path) }; res.map_err(|e| e.into()) } @@ -181,12 +45,10 @@ pub fn read_all(file_name: &str, buf: &mut Vec) -> bool { // let cwd = if task.is_some() { // task.unwrap().access_inner().cwd().cwd // } else { - // SYSTEM_ROOT_FS.get().unwrap().clone() + // vfs::system_root_fs() // }; let path = if task.is_none() { - VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()) - .join(file_name) - .unwrap() + VfsPath::new(vfs::system_root_fs()).join(file_name).unwrap() } else { user_path_at(AT_FDCWD, file_name).unwrap() }; @@ -204,7 +66,7 @@ pub fn read_all(file_name: &str, buf: &mut Vec) -> bool { let size = dentry.inode().unwrap().get_attr().unwrap().st_size; let mut offset = 0; while offset < size { - let mut tmp = vec![0; 512usize]; + let mut tmp = [0; 512]; let res = dentry.inode().unwrap().read_at(offset, &mut tmp).unwrap(); offset += res as u64; buf.extend_from_slice(&tmp); diff --git a/kernel/src/fs/poll.rs b/kernel/src/fs/poll.rs index db526523..3be2987d 100644 --- a/kernel/src/fs/poll.rs +++ b/kernel/src/fs/poll.rs @@ -1,10 +1,11 @@ use crate::task::{current_task, do_suspend}; -use crate::timer::TimeSpec; use alloc::vec::Vec; use constants::io::{PollEvents, PollFd}; use constants::AlienResult; use constants::LinuxErrno; +use log::{info, warn}; use syscall_table::syscall_func; +use timer::TimeSpec; /// 一个系统调用,用于在一些文件描述符上等待事件。作用与 [`pselect6`] 相似。 /// @@ -54,18 +55,6 @@ pub fn ppoll(fds_ptr: usize, nfds: usize, time: usize, _mask: usize) -> AlienRes for pfd in fds.iter_mut() { if let Some(file) = task.get_file(pfd.fd as usize) { let event = file.poll(pfd.events)?; - // if file.in_exceptional_conditions() { - // event |= PollEvents::ERR; - // } - // if file.is_hang_up() { - // event |= PollEvents::HUP; - // } - // if pfd.events.contains(PollEvents::IN) && file.ready_to_read() { - // event |= PollEvents::IN; - // } - // if pfd.events.contains(PollEvents::OUT) && file.ready_to_write() { - // event |= PollEvents::OUT; - // } if !event.is_empty() { res += 1; } diff --git a/kernel/src/fs/proc/filesystem.rs b/kernel/src/fs/proc/filesystem.rs deleted file mode 100644 index 44662d32..00000000 --- a/kernel/src/fs/proc/filesystem.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::fs::FS; -use alloc::string::String; -use alloc::sync::Arc; -use core::cmp::min; -use vfscore::error::VfsError; -use vfscore::file::VfsFile; -use vfscore::fstype::FileSystemFlags; -use vfscore::inode::{InodeAttr, VfsInode}; -use vfscore::superblock::VfsSuperBlock; -use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; -use vfscore::VfsResult; - -pub struct SystemSupportFS; - -impl SystemSupportFS { - pub fn new() -> Self { - Self - } - pub fn serialize(&self) -> String { - let mut res = String::new(); - let fs = FS.lock(); - for (_, fs) in fs.iter() { - let flag = fs.fs_flag(); - if !flag.contains(FileSystemFlags::REQUIRES_DEV) { - res.push_str("nodev ") - } else { - res.push_str(" "); - } - res.push_str(fs.fs_name()); - res.push_str("\n"); - } - res - } -} - -impl VfsFile for SystemSupportFS { - fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { - let info = self.serialize(); - let min_len = min(buf.len(), info.as_bytes().len() - offset as usize); - buf[..min_len].copy_from_slice(&info.as_bytes()[..min_len]); - Ok(min_len) - } -} - -impl VfsInode for SystemSupportFS { - fn get_super_block(&self) -> VfsResult> { - Err(VfsError::NoSys) - } - - fn node_perm(&self) -> VfsNodePerm { - VfsNodePerm::empty() - } - - fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { - Ok(()) - } - - fn get_attr(&self) -> VfsResult { - Ok(VfsFileStat { - st_size: self.serialize().as_bytes().len() as u64, - ..Default::default() - }) - } - - fn inode_type(&self) -> VfsNodeType { - VfsNodeType::File - } -} diff --git a/kernel/src/fs/proc/interrupt.rs b/kernel/src/fs/proc/interrupt.rs deleted file mode 100644 index 83332a7a..00000000 --- a/kernel/src/fs/proc/interrupt.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::interrupt::record::interrupts_info; -use alloc::sync::Arc; -use core::cmp::min; -use vfscore::error::VfsError; -use vfscore::file::VfsFile; -use vfscore::inode::{InodeAttr, VfsInode}; -use vfscore::superblock::VfsSuperBlock; -use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; -use vfscore::VfsResult; - -pub struct InterruptRecord; - -impl VfsFile for InterruptRecord { - fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { - let info = interrupts_info(); - let min_len = min(buf.len(), info.as_bytes().len() - offset as usize); - buf[..min_len].copy_from_slice(&info.as_bytes()[..min_len]); - Ok(min_len) - } - fn write_at(&self, _offset: u64, _buf: &[u8]) -> VfsResult { - Err(VfsError::PermissionDenied) - } -} - -impl VfsInode for InterruptRecord { - fn get_super_block(&self) -> VfsResult> { - Err(VfsError::NoSys) - } - fn node_perm(&self) -> VfsNodePerm { - VfsNodePerm::empty() - } - fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { - Ok(()) - } - - fn get_attr(&self) -> VfsResult { - let info = interrupts_info(); - Ok(VfsFileStat { - st_size: info.as_bytes().len() as u64, - ..Default::default() - }) - } - - fn inode_type(&self) -> VfsNodeType { - VfsNodeType::File - } -} diff --git a/kernel/src/fs/proc/mem.rs b/kernel/src/fs/proc/mem.rs deleted file mode 100644 index 4a777ee6..00000000 --- a/kernel/src/fs/proc/mem.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::config::MEMINFO; -use alloc::sync::Arc; -use core::cmp::min; -use vfscore::error::VfsError; -use vfscore::file::VfsFile; -use vfscore::inode::{InodeAttr, VfsInode}; -use vfscore::superblock::VfsSuperBlock; -use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; -use vfscore::VfsResult; - -pub struct MemInfo; - -impl VfsFile for MemInfo { - fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { - let min_len = min(buf.len(), MEMINFO.as_bytes().len() - offset as usize); - buf[..min_len].copy_from_slice(&MEMINFO.as_bytes()[..min_len]); - Ok(min_len) - } -} - -impl VfsInode for MemInfo { - fn get_super_block(&self) -> VfsResult> { - Err(VfsError::NoSys) - } - fn node_perm(&self) -> VfsNodePerm { - VfsNodePerm::empty() - } - fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { - Ok(()) - } - - fn get_attr(&self) -> VfsResult { - Ok(VfsFileStat { - st_size: MEMINFO.as_bytes().len() as u64, - ..Default::default() - }) - } - - fn inode_type(&self) -> VfsNodeType { - VfsNodeType::File - } -} diff --git a/kernel/src/fs/proc/mod.rs b/kernel/src/fs/proc/mod.rs deleted file mode 100644 index 55b83f28..00000000 --- a/kernel/src/fs/proc/mod.rs +++ /dev/null @@ -1,52 +0,0 @@ -mod filesystem; -mod interrupt; -mod mem; -mod mounts; -mod process; - -use crate::fs::proc::filesystem::SystemSupportFS; -use crate::fs::proc::interrupt::InterruptRecord; -use crate::fs::proc::mounts::MountInfo; -use crate::fs::CommonFsProviderImpl; -use alloc::sync::Arc; -use dynfs::DynFsDirInode; -use ksync::Mutex; -use mem::MemInfo; -use vfscore::dentry::VfsDentry; -use vfscore::error::VfsError; -use vfscore::fstype::VfsFsType; - -pub type ProcFsDirInodeImpl = DynFsDirInode>; - -/// -/// ```bash -/// | -/// |-- meminfo -/// |-- interrupts -/// |-- mounts -/// |-- filesystems -/// ``` -pub fn init_procfs(procfs: Arc) -> Arc { - let root_dt = procfs.i_mount(0, "/proc", None, &[]).unwrap(); - let root_inode = root_dt.inode().unwrap(); - let root_inode = root_inode - .downcast_arc::() - .map_err(|_| VfsError::Invalid) - .unwrap(); - root_inode - .add_file_manually("meminfo", Arc::new(MemInfo), "r--r--r--".into()) - .unwrap(); - root_inode - .add_file_manually("interrupts", Arc::new(InterruptRecord), "r--r--r--".into()) - .unwrap(); - root_inode - .add_file_manually("mounts", Arc::new(MountInfo), "r--r--r--".into()) - .unwrap(); - let support_fs = SystemSupportFS::new(); - root_inode - .add_file_manually("filesystems", Arc::new(support_fs), "r--r--r--".into()) - .unwrap(); - println!("procfs init success"); - - root_dt -} diff --git a/kernel/src/fs/proc/mounts.rs b/kernel/src/fs/proc/mounts.rs deleted file mode 100644 index ac0d76fe..00000000 --- a/kernel/src/fs/proc/mounts.rs +++ /dev/null @@ -1,47 +0,0 @@ -use alloc::sync::Arc; -use core::cmp::min; -use vfscore::error::VfsError; -use vfscore::file::VfsFile; -use vfscore::inode::{InodeAttr, VfsInode}; -use vfscore::superblock::VfsSuperBlock; -use vfscore::utils::{VfsFileStat, VfsNodePerm, VfsNodeType}; -use vfscore::VfsResult; - -// todo!(dynamic mount info) -const MOUNT_INFO: &str = r" - rootfs / rootfs rw 0 0 - devfs /dev devfs rw 0 0 - fat32 / fat rw 0 0 -"; -pub struct MountInfo; - -impl VfsFile for MountInfo { - fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { - let min_len = min(buf.len(), MOUNT_INFO.as_bytes().len() - offset as usize); - buf[..min_len].copy_from_slice(&MOUNT_INFO.as_bytes()[..min_len]); - Ok(min_len) - } -} - -impl VfsInode for MountInfo { - fn get_super_block(&self) -> VfsResult> { - Err(VfsError::NoSys) - } - fn node_perm(&self) -> VfsNodePerm { - VfsNodePerm::empty() - } - fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { - Ok(()) - } - - fn get_attr(&self) -> VfsResult { - Ok(VfsFileStat { - st_size: MOUNT_INFO.as_bytes().len() as u64, - ..Default::default() - }) - } - - fn inode_type(&self) -> VfsNodeType { - VfsNodeType::File - } -} diff --git a/kernel/src/fs/proc/process.rs b/kernel/src/fs/proc/process.rs deleted file mode 100644 index 36259558..00000000 --- a/kernel/src/fs/proc/process.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::task::current_task; -use crate::timer::TimeFromFreq; -use constants::sys::{Rusage, RusageFlag, TimeVal}; -use constants::AlienResult; -use constants::LinuxErrno; - -/// (待完善)一个系统调用,用于获取对系统资源的使用量信息。获取的信息将保存到`usage`所指向的[`Rusage`]结构中。 -/// -/// 可以通过`who`修改获取信息的对象,包括: -/// + `RUSAGE_SELF`: 返回调用该函数进程的资源用量统计,会返回该进程下所有线程的资源用量之和; -/// + `RUSAGE_CHILDREN`: 返回调用该函数进程所有已终止且被回收子进程的资源用量统计. -/// + `RUSAGE_THREAD`: 返回调用该函数线程的资源用量统计。 -/// -/// 在Alien中,目前仅支持`RUSAGE_SELF`。且返回的信息目前仅有[`Rusage`]下的`ru_utime`和`ru_stime`字段。 -/// -/// 正确执行后返回0。 -#[syscall_func(165)] -pub fn getrusage(who: isize, usage: usize) -> AlienResult { - let who = RusageFlag::try_from(who).map_err(|_| LinuxErrno::EINVAL)?; - info!("getrusage: who: {:?}, usage: {}", who, usage); - let task = current_task().unwrap(); - let static_info = task.access_inner().statistical_data().clone(); - let mut task_usage = Rusage::new(); - task_usage.ru_utime = TimeVal::from_freq(static_info.tms_utime); - task_usage.ru_stime = TimeVal::from_freq(static_info.tms_stime); - task.access_inner() - .copy_to_user(&task_usage, usage as *mut Rusage); - Ok(0) -} diff --git a/kernel/src/fs/ram/mod.rs b/kernel/src/fs/ram/mod.rs deleted file mode 100644 index b1b71834..00000000 --- a/kernel/src/fs/ram/mod.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::config::{RTC_TIME, UTC}; -use alloc::sync::Arc; -use vfscore::dentry::VfsDentry; -use vfscore::fstype::VfsFsType; -use vfscore::utils::VfsNodeType; - -/// -/// ```bash -/// | -/// |-- root -/// |-- .bashrc -/// |--var -/// |-- log -/// |-- tmp(ramfs) -/// |-- run -/// |-- etc -/// |-- passwd -/// |--localtime -/// |--adjtime -/// |-- dev (devfs) -/// |-- proc (procfs) -/// |-- sys (sysfs) -/// |-- bin (fat32) -/// |-- tmp (ramfs) -/// ``` -pub fn init_ramfs(ramfs: Arc) -> Arc { - let root_dt = ramfs.i_mount(0, "/", None, &[]).unwrap(); - let root_inode = root_dt.inode().unwrap(); - let root = root_inode - .create("root", VfsNodeType::Dir, "rwxr-xr-x".into(), None) - .unwrap(); - let var = root_inode - .create("var", VfsNodeType::Dir, "rwxr-xr-x".into(), None) - .unwrap(); - var.create("log", VfsNodeType::Dir, "rwxrwxr-x".into(), None) - .unwrap(); - var.create("tmp", VfsNodeType::Dir, "rwxrwxrwx".into(), None) - .unwrap(); - var.create("run", VfsNodeType::Dir, "rwxrwxrwx".into(), None) - .unwrap(); - let etc = root_inode - .create("etc", VfsNodeType::Dir, "rwxr-xr-x".into(), None) - .unwrap(); - let passwd = etc - .create("passwd", VfsNodeType::File, "rw-r--r--".into(), None) - .unwrap(); - let localtime = etc - .create("localtime", VfsNodeType::File, "rw-r--r--".into(), None) - .unwrap(); - let adjtime = etc - .create("adjtime", VfsNodeType::File, "rw-r--r--".into(), None) - .unwrap(); - - passwd - .write_at(0, b"root:x:0:0:root:/root:/bin/bash\n") - .unwrap(); - localtime.write_at(0, UTC).unwrap(); - adjtime.write_at(0, RTC_TIME.as_bytes()).unwrap(); - - root_inode - .create("dev", VfsNodeType::Dir, "rwxr-xr-x".into(), None) - .unwrap(); - root_inode - .create("proc", VfsNodeType::Dir, "rwxr-xr-x".into(), None) - .unwrap(); - root_inode - .create("sys", VfsNodeType::Dir, "rwxr-xr-x".into(), None) - .unwrap(); - root_inode - .create("bin", VfsNodeType::Dir, "rwxr-xr-x".into(), None) - .unwrap(); - root_inode - .create("tmp", VfsNodeType::Dir, "rwxrwxrwx".into(), None) - .unwrap(); - - let _bashrc = root - .create(".bashrc", VfsNodeType::File, "rwxrwxrwx".into(), None) - .unwrap(); - - println!("ramfs init success"); - root_dt -} diff --git a/kernel/src/fs/select.rs b/kernel/src/fs/select.rs index bd30ee51..e2813a7d 100644 --- a/kernel/src/fs/select.rs +++ b/kernel/src/fs/select.rs @@ -1,14 +1,15 @@ -use crate::config::MAX_FD_NUM; use crate::task::{current_task, do_suspend}; -use crate::timer::TimeSpec; use alloc::vec::Vec; use bit_field::BitField; +use config::MAX_FD_NUM; use constants::io::PollEvents; use constants::signal::{SignalNumber, SimpleBitSet}; use constants::AlienResult; use constants::LinuxErrno; use core::cmp::min; +use log::{info, trace}; use syscall_table::syscall_func; +use timer::TimeSpec; /// 一个系统调用,实现 IO 端口的复用。一般用于用户程序的一段循环体中, /// 用于周期性检测一组关注的文件描述符集里是否有需要进行处理的IO事件发生。 diff --git a/kernel/src/fs/stdio.rs b/kernel/src/fs/stdio.rs index 4e90fc3a..ef4f1f9f 100644 --- a/kernel/src/fs/stdio.rs +++ b/kernel/src/fs/stdio.rs @@ -1,26 +1,21 @@ -use crate::fs::file::KernelFile; -use crate::fs::SYSTEM_ROOT_FS; use alloc::sync::Arc; use constants::io::OpenFlags; use spin::Lazy; +use vfs::kfile::KernelFile; use vfscore::path::VfsPath; type Stdin = KernelFile; type Stdout = KernelFile; pub static STDIN: Lazy> = Lazy::new(|| { - let path = VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()) - .join("dev/tty") - .unwrap(); + let path = VfsPath::new(vfs::system_root_fs()).join("dev/tty").unwrap(); let dentry = path.open(None).unwrap(); let file = KernelFile::new(dentry, OpenFlags::O_RDONLY); Arc::new(file) }); pub static STDOUT: Lazy> = Lazy::new(|| { - let path = VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()) - .join("dev/tty") - .unwrap(); + let path = VfsPath::new(vfs::system_root_fs()).join("dev/tty").unwrap(); let dentry = path.open(None).unwrap(); let file = KernelFile::new(dentry, OpenFlags::O_WRONLY); Arc::new(file) diff --git a/kernel/src/fs/sys/cpu.rs b/kernel/src/fs/sys/cpu.rs deleted file mode 100644 index 2ab92f03..00000000 --- a/kernel/src/fs/sys/cpu.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::task::current_task; - -/// (待实现)一个系统调用,设置进程调度的参数。目前直接返回0。 -#[syscall_func(118)] -pub fn sched_setparam() -> isize { - 0 -} - -/// (待实现)一个系统调用,获取进程调度的参数。目前直接返回0。 -#[syscall_func(121)] -pub fn sched_getparam() -> isize { - 0 -} - -/// (待实现)一个系统调用,设置进程CPU亲和力(位掩码),使进程绑定在某一个或几个CPU上运行,避免在CPU之间来回切换,从而提高该进程的实时性能。目前直接返回0。 -#[syscall_func(122)] -pub fn sched_setaffinity() -> isize { - 0 -} - -/// (待完善)一个系统调用,获取某进程对CPU的亲和力(位掩码)。当前进程的cpu亲和力将保存到`mask`所指向的位置。函数执行成功后返回8。 -#[syscall_func(123)] -pub fn sched_getaffinity(pid: usize, size: usize, mask: usize) -> isize { - warn!( - "sched_getaffinity: pid: {}, size: {}, mask: {}", - pid, size, mask - ); - assert_eq!(pid, 0); - let task = current_task().unwrap(); - let res = task.access_inner().cpu_affinity; - let mask = task.access_inner().transfer_raw_ptr_mut(mask as *mut usize); - *mask = res; - 8 -} - -/// (待实现)一个系统调用,用于获取当前CPU的调度策略。目前直接返回0。 -#[syscall_func(120)] -pub fn sched_getscheduler(pid: usize) -> isize { - assert_eq!(pid, 0); - // let task = current_task().unwrap(); - 0 -} - -/// (待实现)一个系统调用,用于设置当前CPU的调度策略。目前直接返回0。 -#[syscall_func(119)] -pub fn sched_setscheduler(_pid: usize, _policy: usize, _param: usize) -> isize { - 0 -} diff --git a/kernel/src/fs/sys/info.rs b/kernel/src/fs/sys/info.rs deleted file mode 100644 index 277b80a9..00000000 --- a/kernel/src/fs/sys/info.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::task::current_task; -use crate::timer::get_time_ms; -use crate::MACHINE_INFO; -use constants::sys::{Sysinfo, SyslogAction}; -use constants::LinuxErrno; -use core::cmp::min; - -const LOG_BUF_LEN: usize = 4096; -const LOG: &str = r" -[ 0.000000] Linux version 5.10.0-7-riscv64 (debian-kernel@lists.debian.org) (gcc-10 (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2) #1 SMP Debian 5.10.40-1 (2021-05-28) -"; - -/// (待完善)一个系统调用函数,用于对内核消息环状缓冲区进行操作。 -/// -/// + `log_type`: 指明操作的类型,具体值可见[`SyslogAction`]; -/// + `buf`: 指明读取消息时,消息要保存到的位置; -/// + `len`: 指明具体操作时,对于消息读取的长度限制。真正的读取消息的长度将取决于就传入的`len`和`LOG_BUF_LEN`的最小值。 -/// -/// 当`log_type`为`READ`、`ReadAll`、`ReadClear`三种flag,正确执行后返回读取消息的长度; -/// 当`log_type`为`Unknown`时,会返回`EINVAL`;当`log_type`为`OPEN`或`CLOSE`时,函数不进行任何操作后返回0。 -/// 目前Alien仅支持上述`log_type`值,其余值都将不进行任何操作后返回0。 -/// -/// Reference: [syslog](https://man7.org/linux/man-pages/man2/syslog.2.html) -#[syscall_func(116)] -pub fn syslog(log_type: u32, buf: usize, len: usize) -> isize { - let log_type = SyslogAction::try_from(log_type); - if log_type.is_err() { - return LinuxErrno::EINVAL as isize; - } - match log_type.unwrap() { - SyslogAction::OPEN | SyslogAction::CLOSE => 0, - SyslogAction::READ | SyslogAction::ReadAll | SyslogAction::ReadClear => { - let min_len = min(len, LOG_BUF_LEN); - let task = current_task().unwrap(); - // the buf may be not valid, so we need to check it -- > sbrk heap - let mut buf = task.transfer_buffer(buf as *mut u8, min_len); - let log = LOG.as_bytes(); - let mut offset = 0; - buf.iter_mut().for_each(|buf| { - let copy_len = min(log.len() - offset, buf.len()); - buf[..copy_len].copy_from_slice(&log[offset..offset + copy_len]); - offset += copy_len; - }); - offset as isize - } - SyslogAction::Unknown => LinuxErrno::EINVAL as isize, - _ => 0, - } -} - -extern "C" { - fn ekernel(); -} - -/// 一个系统调用函数,用于获取系统相关信息。信息包括系统的自启动经过的时间、对于内存的使用情况、共享存储区的大小、 -/// 缓冲区与交换区的大小、当前进程数目等,具体可见[`Sysinfo`]。获取到的信息将保存到`dst_info`所指向的[`Sysinfo`]结构处。 -/// -/// 目前功能还有待完善。正确执行后返回0。 -#[syscall_func(179)] -pub fn sys_info(dst_info: usize) -> isize { - const LINUX_SYSINFO_LOADS_SCALE: usize = 65536; - let task = current_task().unwrap(); - // calculate the task number - let task_number = 10; // fake task number - let memory_info = MACHINE_INFO.get().as_ref().unwrap().memory.clone(); - let info = Sysinfo { - uptime: (get_time_ms() / 1000) as usize, - loads: [ - task_number * LINUX_SYSINFO_LOADS_SCALE / 60, - task_number * LINUX_SYSINFO_LOADS_SCALE / 300, - task_number * LINUX_SYSINFO_LOADS_SCALE / 900, - ], - totalram: memory_info.end - memory_info.start, - freeram: memory_info.end - ekernel as usize, - sharedram: 0, - bufferram: 0, - totalswap: 0, - freeswap: 0, - procs: task_number as u16, - totalhigh: 0, - freehigh: 0, - mem_unit: 1, - }; - task.access_inner() - .copy_to_user(&info, dst_info as *mut Sysinfo); - 0 -} diff --git a/kernel/src/fs/sys/mod.rs b/kernel/src/fs/sys/mod.rs deleted file mode 100644 index 5cd608a1..00000000 --- a/kernel/src/fs/sys/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::fs::CommonFsProviderImpl; -use alloc::sync::Arc; -use dynfs::DynFsDirInode; -use ksync::Mutex; -use vfscore::dentry::VfsDentry; -use vfscore::fstype::VfsFsType; - -mod cpu; -mod info; -pub type SysFsDirInodeImpl = DynFsDirInode>; - -pub fn init_sysfs(sysfs: Arc) -> Arc { - let root_dt = sysfs.i_mount(0, "/sys", None, &[]).unwrap(); - // let root_inode = root_dt.inode().unwrap(); - // let root_inode = root_inode - // .downcast_arc::() - // .map_err(|_| VfsError::Invalid).unwrap(); - println!("sysfs init success"); - root_dt -} diff --git a/kernel/src/gui.rs b/kernel/src/gui.rs index aa3e3b21..1ec22685 100644 --- a/kernel/src/gui.rs +++ b/kernel/src/gui.rs @@ -1,10 +1,8 @@ //! GUI 相关的系统调用 +use crate::task::current_task; use page_table::addr::{align_up_4k, PhysAddr, VirtAddr}; -use syscall_table::syscall_func; - -use crate::device::GPU_DEVICE; -use crate::task::current_task; +use devices::{GPU_DEVICE, KEYBOARD_INPUT_DEVICE, MOUSE_INPUT_DEVICE}; const FB_VADDR: usize = 0x1000_0000; @@ -33,3 +31,47 @@ pub fn sys_framebuffer_flush() -> isize { GPU_DEVICE.get().unwrap().flush(); 0 } + + +/// 一个系统调用函数,用于获取鼠标和键盘事件。 +/// +/// `sys_event_get`会将获取到的事件将保存在event_buf所指向的内存位置处, +/// 此次允许获取到的事件的最大值(即event_buf)的大小由len指出。 +/// +/// 函数将返回成功获取到的事件个数。 +/// +#[syscall_func(2002)] +pub fn sys_event_get(event_buf: *mut u64, len: usize) -> isize { + let task = current_task().unwrap(); + let user_buffer = task.transfer_buffer(event_buf, len); + let mut count = 0; + for buf in user_buffer { + let mut index = 0; + let len = buf.len(); + while index < len { + let event = read_event(); + if event == 0 { + break; + } + buf[index] = event; + index += 1; + count += 1; + } + } + count +} + +fn read_event() -> u64 { + let (keyboard, mouse) = { + let kb = KEYBOARD_INPUT_DEVICE.get().unwrap(); + let mouse = MOUSE_INPUT_DEVICE.get().unwrap(); + (kb, mouse) + }; + if !keyboard.is_empty() { + keyboard.read_event_with_block() + } else if !mouse.is_empty() { + mouse.read_event_with_block() + } else { + 0 + } +} diff --git a/kernel/src/interrupt/ext_interrupt.rs b/kernel/src/interrupt/ext_interrupt.rs deleted file mode 100644 index 7e0d06ef..00000000 --- a/kernel/src/interrupt/ext_interrupt.rs +++ /dev/null @@ -1,17 +0,0 @@ -use plic::Mode; - -use crate::interrupt::{DEVICE_TABLE, PLIC}; -use arch::hart_id; - -pub fn external_interrupt_handler() { - let plic = PLIC.get().unwrap(); - let hart_id = hart_id(); - let irq = plic.claim(hart_id as u32, Mode::Supervisor); - let table = DEVICE_TABLE.lock(); - let device = table - .get(&(irq as usize)) - .or_else(|| panic!("no device for irq {}", irq)) - .unwrap(); - device.hand_irq(); - plic.complete(hart_id as u32, Mode::Supervisor, irq); -} diff --git a/kernel/src/interrupt/mod.rs b/kernel/src/interrupt/mod.rs deleted file mode 100644 index 93e1240c..00000000 --- a/kernel/src/interrupt/mod.rs +++ /dev/null @@ -1,63 +0,0 @@ -use alloc::collections::BTreeMap; -use alloc::sync::Arc; -use cfg_if::cfg_if; -use spin::Once; - -pub use ext_interrupt::external_interrupt_handler; -use ksync::Mutex; -use plic::{Mode, PLIC}; - -use crate::config::CPU_NUM; -use crate::MACHINE_INFO; -use arch::hart_id; - -mod ext_interrupt; -pub mod record; -mod timer; - -pub static PLIC: Once> = Once::new(); - -pub static DEVICE_TABLE: Mutex>> = Mutex::new(BTreeMap::new()); - -pub trait DeviceBase: Sync + Send { - fn hand_irq(&self); -} - -pub fn init_plic() { - let machine = MACHINE_INFO.get().unwrap(); - let addr = machine.plic.start; - - cfg_if! { - if #[cfg(feature = "qemu")]{ - let privileges = [2;CPU_NUM]; - let plic = PLIC::new(addr, privileges); - PLIC.call_once(|| plic); - println!("Init qemu plic success"); - }else if #[cfg(any(feature = "vf2", feature = "hifive"))]{ - let mut privileges = [2u8;CPU_NUM]; - // core 0 don't have S mode - privileges[0] = 1; - println!("PLIC context: {:?}",privileges); - let plic = PLIC::new(addr, privileges); - PLIC.call_once(|| plic); - println!("Init hifive or vf2 plic success"); - } - } -} - -/// Register a device to PLIC. -pub fn register_device_to_plic(irq: usize, device: Arc) { - let mut table = DEVICE_TABLE.lock(); - table.insert(irq, device); - let hard_id = hart_id(); - println!( - "plic enable irq {} for hart {}, priority {}", - irq, hard_id, 1 - ); - let plic = PLIC.get().unwrap(); - plic.set_threshold(hard_id as u32, Mode::Machine, 1); - plic.set_threshold(hard_id as u32, Mode::Supervisor, 0); - plic.complete(hard_id as u32, Mode::Supervisor, irq as u32); - plic.set_priority(irq as u32, 1); - plic.enable(hard_id as u32, Mode::Supervisor, irq as u32); -} diff --git a/kernel/src/interrupt/record.rs b/kernel/src/interrupt/record.rs deleted file mode 100644 index 5d576b92..00000000 --- a/kernel/src/interrupt/record.rs +++ /dev/null @@ -1,33 +0,0 @@ -use alloc::collections::BTreeMap; -use alloc::format; -use alloc::string::String; -use ksync::Mutex; -use spin::Lazy; - -/// Record the number of interrupts -pub static INTERRUPT_RECORD: Lazy>> = Lazy::new(|| { - let mut tree = BTreeMap::new(); - tree.insert(1, 0); // timer - tree.insert(10, 0); // uart - Mutex::new(tree) -}); - -/// Increase the number of interrupts -pub fn write_irq_info(irq: usize) { - let mut interrupts = INTERRUPT_RECORD.lock(); - let value = interrupts.get_mut(&irq).unwrap().clone(); - interrupts.insert(irq, value + 1); -} - -/// Serializes the number of interrupts -/// -/// # Return -/// irq{}: number -pub fn interrupts_info() -> String { - let interrupts = INTERRUPT_RECORD.lock(); - let mut res = String::new(); - interrupts.iter().for_each(|(irq, value)| { - res.push_str(&format!("{}: {}\r\n", irq, value)); - }); - res -} diff --git a/kernel/src/interrupt/timer.rs b/kernel/src/interrupt/timer.rs deleted file mode 100644 index 8b137891..00000000 --- a/kernel/src/interrupt/timer.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/kernel/src/ipc/futex.rs b/kernel/src/ipc/futex.rs index 184b2a34..9b4c2b95 100644 --- a/kernel/src/ipc/futex.rs +++ b/kernel/src/ipc/futex.rs @@ -22,8 +22,8 @@ use ksync::Mutex; use smpscheduler::FifoTask; use crate::task::{Task, GLOBAL_TASK_MANAGER}; -use crate::timer::read_timer; use constants::{AlienError, AlienResult}; +use timer::read_timer; /// 用于记录一个进程等待一个 futex 的相关信息 pub struct FutexWaiter { diff --git a/kernel/src/ipc/mod.rs b/kernel/src/ipc/mod.rs index c4ac1946..b46b73f4 100644 --- a/kernel/src/ipc/mod.rs +++ b/kernel/src/ipc/mod.rs @@ -9,6 +9,10 @@ use alloc::sync::Arc; use core::sync::atomic::{AtomicI32, Ordering}; use spin::Lazy; +use crate::fs::basic::sys_close; +use crate::ipc::futex::{FutexWaitManager, FutexWaiter}; +use crate::task::schedule::schedule; +use crate::task::{current_task, TaskState}; use constants::ipc::{FutexOp, RobustList}; use constants::AlienResult; use constants::LinuxErrno; @@ -16,13 +20,7 @@ use ksync::Mutex; pub use pipe::*; pub use shm::*; pub use signal::*; -use syscall_table::syscall_func; - -use crate::fs::sys_close; -use crate::ipc::futex::{FutexWaitManager, FutexWaiter}; -use crate::task::schedule::schedule; -use crate::task::{current_task, TaskState}; -use crate::timer::TimeSpec; +use timer::TimeSpec; pub mod futex; mod pipe; diff --git a/kernel/src/ipc/pipe.rs b/kernel/src/ipc/pipe.rs index 75784b1a..9a43b809 100644 --- a/kernel/src/ipc/pipe.rs +++ b/kernel/src/ipc/pipe.rs @@ -9,26 +9,22 @@ //! [`pipe_read_is_hang_up`]、[`pipe_write_is_hang_up`]、[`pipe_ready_to_read`] //! 、[`pipe_ready_to_write`] 几个操作函数,即可快速的创建管道文件,并将其放入进程的文件描述 //! 符表中。 - -use crate::config::PIPE_BUF; -use crate::fs::file::File; -use crate::fs::CommonFsProviderImpl; use crate::task::{current_task, do_suspend}; use alloc::string::{String, ToString}; use alloc::sync::{Arc, Weak}; use alloc::vec::Vec; -use constants::io::{MountFlags, OpenFlags, PollEvents, SeekFrom}; +use config::PIPE_BUF; +use constants::io::{OpenFlags, PollEvents, SeekFrom}; use constants::AlienResult; use constants::LinuxErrno; use core::fmt::{Debug, Formatter}; use core::sync::atomic::AtomicUsize; -use dynfs::DynFsDirInode; use ksync::Mutex; -use spin::Once; +use vfs::kfile::File; +use vfs::pipefs::{PipeFsDirInodeImpl, PIPE_FS_ROOT}; use vfscore::dentry::VfsDentry; use vfscore::error::VfsError; use vfscore::file::VfsFile; -use vfscore::fstype::VfsFsType; use vfscore::impl_common_inode_default; use vfscore::inode::{InodeAttr, VfsInode}; use vfscore::superblock::VfsSuperBlock; @@ -36,9 +32,6 @@ use vfscore::utils::VfsPollEvents; use vfscore::utils::*; use vfscore::VfsResult; -type PipeFsDirInodeImpl = DynFsDirInode>; -static PIPE_FS_ROOT: Once> = Once::new(); - static PIPE: AtomicUsize = AtomicUsize::new(0); /// 管道文件 @@ -71,13 +64,6 @@ impl PipeFile { } } -pub fn init_pipefs(fs: Arc) { - let root = fs - .i_mount(MountFlags::empty().bits(), "", None, &[]) - .unwrap(); - PIPE_FS_ROOT.call_once(|| root); -} - /// create a pipe file pub fn make_pipe_file() -> VfsResult<(Arc, Arc)> { let root = PIPE_FS_ROOT.get().unwrap(); diff --git a/kernel/src/ipc/shm.rs b/kernel/src/ipc/shm.rs index ff5a3eef..af61c1e0 100644 --- a/kernel/src/ipc/shm.rs +++ b/kernel/src/ipc/shm.rs @@ -6,19 +6,15 @@ //! 最后封装成 [`ShmMemory`] 结构。 //! use alloc::collections::btree_map::BTreeMap; -use alloc::vec::Vec; - -use page_table::addr::{align_down_4k, PhysAddr, VirtAddr}; -use page_table::table::PageSize; - use constants::ipc::{ShmAtFlags, ShmCtlCmd, ShmGetFlags, IPC_PRIVATE}; -use constants::LinuxErrno; +use constants::{AlienResult, LinuxErrno}; use ksync::{Mutex, MutexGuard}; +use page_table::addr::{align_down_4k, PhysAddr, VirtAddr}; use syscall_table::syscall_func; -use crate::config::FRAME_SIZE; -use crate::memory::{frames_alloc, FrameTracker}; use crate::task::current_task; +use config::FRAME_SIZE; +use mem::{alloc_frame_trackers, FrameTracker}; /// 共享内存被 Mutex 封装后的结构 #[derive(Debug)] @@ -33,7 +29,7 @@ pub struct ShmMemoryInner { /// 引用计数器 ref_count: usize, /// 共享内存数据部分 - pub frames: Vec, + pub frames: FrameTracker, /// 共享内存的状态 state: ShmMemoryState, } @@ -56,7 +52,7 @@ impl ShmInfo { impl ShmMemory { /// 创建新的共享内存 - pub fn new(frames: Vec) -> Self { + pub fn new(frames: FrameTracker) -> Self { Self { inner: Mutex::new(ShmMemoryInner { ref_count: 0, @@ -73,7 +69,7 @@ impl ShmMemory { /// 返回共享内存数据区的长度(字节数) pub fn len(&self) -> usize { - self.access_inner().frames.len() * FRAME_SIZE + self.access_inner().frames.len() } /// 引用计数器加一 @@ -95,7 +91,6 @@ impl ShmMemory { pub fn is_deleted(&self) -> bool { self.access_inner().state == ShmMemoryState::Deleted } - } /// 记录共享内存当前状态的结构 @@ -123,7 +118,7 @@ pub static SHM_MEMORY: Mutex> = Mutex::new(BTreeMap:: /// Reference: [shmget](https://man7.org/linux/man-pages/man2/shmget.2.html) #[syscall_func(194)] pub fn shmget(key: usize, size: usize, shmflg: u32) -> isize { - warn!( + info!( "shmget key:{},size:{},shmflg:{:?}", key, size, @@ -143,13 +138,13 @@ pub fn shmget(key: usize, size: usize, shmflg: u32) -> isize { } let flag = ShmGetFlags::from_bits_truncate(shmflg as i32); if flag.contains(ShmGetFlags::IPC_CREAT) { - warn!("create new share memory {}", key); + info!("create new share memory {}", key); // alloc frames - let frames = frames_alloc(align_down_4k(size) / FRAME_SIZE); - if frames.is_none() { - return LinuxErrno::ENOMEM as isize; - } - let frames = frames.unwrap(); + let frames = alloc_frame_trackers(align_down_4k(size) / FRAME_SIZE); + // if frames.is_none() { + // return LinuxErrno::ENOMEM as isize; + // } + // let frames = frames.unwrap(); let share_mem = ShmMemory::new(frames); shm_memory.insert(key, share_mem); return key as isize; @@ -171,7 +166,7 @@ pub fn shmget(key: usize, size: usize, shmflg: u32) -> isize { /// /// Reference: [shmat](https://www.man7.org/linux/man-pages/man3/shmat.3p.html) #[syscall_func(196)] -pub fn shmat(shmid: usize, shmaddr: usize, shmflg: u32) -> isize { +pub fn shmat(shmid: usize, shmaddr: usize, shmflg: u32) -> AlienResult { warn!( "shmat shmid:{},shmaddr:{:#x},shmflg:{:?}", shmid, @@ -179,15 +174,12 @@ pub fn shmat(shmid: usize, shmaddr: usize, shmflg: u32) -> isize { ShmAtFlags::from_bits_truncate(shmflg as i32) ); let shm_memory = SHM_MEMORY.lock(); - let shm = shm_memory.get(&shmid); - if shm.is_none() { - return LinuxErrno::EINVAL as isize; - } - let shm = shm.unwrap(); + let shm = shm_memory.get(&shmid).ok_or(LinuxErrno::EINVAL)?; + let flag = ShmAtFlags::from_bits_truncate(shmflg as i32); assert!(flag.is_empty()); if flag.contains(ShmAtFlags::SHM_RDONLY) { - warn!("read only"); + info!("read only"); } assert_eq!(shmaddr, 0); // we must find a place to map @@ -199,26 +191,41 @@ pub fn shmat(shmid: usize, shmaddr: usize, shmflg: u32) -> isize { let mut task_inner = task.access_inner(); let mut address_space = task_inner.address_space.lock(); // let shm_inner = shm.access_inner(); - let mut virt_start = free_map.start; - shm.access_inner().frames.iter().for_each(|x| { - let phy_start = x.start(); - address_space - .map( - VirtAddr::from(virt_start), - PhysAddr::from(phy_start), - PageSize::Size4K, - "UVRWAD".into(), - ) - .unwrap(); - error!("map {:#x} to {:#x}", phy_start, virt_start); - virt_start += FRAME_SIZE; - }); + // let mut virt_start = free_map.start; + // shm.access_inner().frames.iter().for_each(|x| { + // let phy_start = x.start(); + // address_space + // .map( + // VirtAddr::from(virt_start), + // PhysAddr::from(phy_start), + // PageSize::Size4K, + // "UVRWAD".into(), + // ) + // .unwrap(); + // error!("map {:#x} to {:#x}", phy_start, virt_start); + // virt_start += FRAME_SIZE; + // }); + + let size = shm.len(); + let start_phy = shm.access_inner().frames.start(); + address_space + .map_region( + VirtAddr::from(free_map.start), + PhysAddr::from(start_phy), + size, + "UVRWAD".into(), + false, + ) + .unwrap(); + + info!("shm map range:{:#x?}", free_map); + drop(address_space); task_inner .shm .insert(shmid, ShmInfo::new(free_map.start, free_map.end)); shm.add_ref(); - free_map.start as isize + Ok(free_map.start as isize) } /// 一个系统调用,用于控制共享内存。 @@ -232,21 +239,13 @@ pub fn shmat(shmid: usize, shmaddr: usize, shmflg: u32) -> isize { /// /// Reference: [shmctl](https://man7.org/linux/man-pages/man2/shmctl.2.html) #[syscall_func(195)] -pub fn shmctl(shmid: usize, cmd: usize, _buf: usize) -> isize { - let cmd = ShmCtlCmd::try_from(cmd as u32); - if cmd.is_err() { - return LinuxErrno::EINVAL as isize; - } - let cmd = cmd.unwrap(); +pub fn shmctl(shmid: usize, cmd: usize, _buf: usize) -> AlienResult { + let cmd = ShmCtlCmd::try_from(cmd as u32).map_err(|_| LinuxErrno::EINVAL)?; match cmd { ShmCtlCmd::IpcRmid => { //delete let shm_memory = SHM_MEMORY.lock(); - let shm = shm_memory.get(&shmid); - if shm.is_none() { - return LinuxErrno::EINVAL as isize; - } - let shm = shm.unwrap(); + let shm = shm_memory.get(&shmid).ok_or(LinuxErrno::EINVAL)?; shm.delete(); let task = current_task().unwrap(); let task_inner = task.access_inner(); @@ -279,5 +278,5 @@ pub fn shmctl(shmid: usize, cmd: usize, _buf: usize) -> isize { panic!("not support") } } - 0 + Ok(0) } diff --git a/kernel/src/ipc/signal.rs b/kernel/src/ipc/signal.rs index 6769a6e7..822bbadd 100644 --- a/kernel/src/ipc/signal.rs +++ b/kernel/src/ipc/signal.rs @@ -16,7 +16,7 @@ use ksync::Mutex; use syscall_table::syscall_func; use crate::task::{current_task, do_exit, do_suspend}; -use crate::timer::{read_timer, TimeSpec}; +use timer::{read_timer, TimeSpec}; /// 记录每个线程的信号量,从 tid 获取信号相关信息 static TID2SIGNALS: Mutex>>> = diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs deleted file mode 100644 index 523a8f7b..00000000 --- a/kernel/src/lib.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! 内核的主要代码,包含各个子模块的实现。 -//! -//! 通过导出子模块,boot模块可以调用内核的各个子模块完成初始化工作 - -#![no_std] -#![feature(error_in_core)] -#![feature(panic_info_message)] -#![feature(atomic_from_mut)] -#![feature(ip_in_core)] -// #![deny(missing_docs)] - -extern crate alloc; -#[macro_use] -extern crate log; - -use spin::Once; - -use basemachine::MachineInfo; - -#[macro_use] -pub mod print; -pub mod board; -pub mod config; -pub mod device; -pub mod driver; -pub mod fs; -pub mod gui; -pub mod interrupt; -pub mod ipc; -pub mod memory; -pub mod net; -pub mod panic; -pub mod sbi; -pub mod system; -pub mod task; -pub mod timer; -pub mod trace; -pub mod trap; - -#[macro_use] -extern crate syscall_table; - -pub use syscall_table::*; - -/// 设备基本信息 -pub static MACHINE_INFO: Once = Once::new(); - -/// 初始化设备基本信息 -/// -/// 在后续的代码中,可以通过调用`MACHINE_INFO.get()`来获取设备基本信息 -pub fn init_machine_info(machine_info: MachineInfo) { - MACHINE_INFO.call_once(|| machine_info); -} diff --git a/kkernel/src/main.rs b/kernel/src/main.rs similarity index 90% rename from kkernel/src/main.rs rename to kernel/src/main.rs index 6007b615..feedf595 100644 --- a/kkernel/src/main.rs +++ b/kernel/src/main.rs @@ -14,28 +14,30 @@ extern crate alloc; use alloc::boxed::Box; pub use syscall_table::*; mod fs; -mod task; -mod time; -mod trap; +mod gui; mod ipc; mod mm; mod net; -mod gui; mod system; +mod task; +mod time; +mod trap; +use crate::task::DriverTaskImpl; use core::hint::spin_loop; use core::panic::PanicInfo; use core::sync::atomic::{AtomicBool, Ordering}; use platform::{platform_machine_info, system_shutdown}; -use crate::task::DriverTaskImpl; /// 多核启动标志 static STARTED: AtomicBool = AtomicBool::new(false); - #[no_mangle] -fn main(hart_id:usize){ - if STARTED.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed).is_ok() { +fn main(hart_id: usize) { + if STARTED + .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) + .is_ok() + { println!("Boot hart {}", hart_id); let machine_info = platform_machine_info(); println!("{:#?}", machine_info); @@ -50,7 +52,7 @@ fn main(hart_id:usize){ // register all syscall syscall_table::init_init_array!(); STARTED.store(false, Ordering::Relaxed); - }else { + } else { while STARTED.load(Ordering::Relaxed) { spin_loop(); } @@ -67,5 +69,5 @@ fn main(hart_id:usize){ #[panic_handler] fn panic(info: &PanicInfo) -> ! { println!("{}", info); - system_shutdown(); -} \ No newline at end of file + system_shutdown() +} diff --git a/kernel/src/memory/elf.rs b/kernel/src/memory/elf.rs deleted file mode 100644 index 0f14e224..00000000 --- a/kernel/src/memory/elf.rs +++ /dev/null @@ -1,150 +0,0 @@ -use alloc::string::String; -use alloc::vec; -use alloc::vec::Vec; -use core::fmt::{Debug, Formatter}; - -use page_table::table::Sv39PageTable; -use xmas_elf::sections::SectionData; -use xmas_elf::symbol_table::Entry; -use xmas_elf::ElfFile; - -use crate::memory::PageAllocator; - -#[derive(Debug)] -pub enum ELFError { - NotELF, - FileBreak, - NotSupported, - NoLoadableSegment, - NoStackSegment, - NoEntrySegment, - RelocationError, - DynsymNotFind, -} - -impl Debug for ELFInfo { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.write_fmt(format_args!( - "ELFInfo {{ address_space: {:#x?}, entry: {:#x}, stack_top: {:#x} }}", - self.address_space.root_paddr().as_usize() >> 12, - self.entry, - self.stack_top - )) - } -} - -pub struct ELFInfo { - pub address_space: Sv39PageTable, - pub entry: usize, - pub stack_top: usize, - pub heap_bottom: usize, - pub ph_num: usize, - pub ph_entry_size: usize, - pub ph_drift: usize, - pub tls: usize, - pub bias: usize, - pub name: String, -} - -pub trait ELFReader { - fn build_elf(&mut self) -> Result; - fn relocate(&self, bias: usize) -> Result, ELFError>; -} - -impl ELFReader for ElfFile<'_> { - fn build_elf(&mut self) -> Result { - Err(ELFError::NotSupported) - } - fn relocate(&self, bias: usize) -> Result, ELFError> { - let mut res = vec![]; - let data = self - .find_section_by_name(".rela.dyn") - .ok_or(ELFError::RelocationError)? - .get_data(self) - .map_err(|_| ELFError::RelocationError)?; - let entries = match data { - SectionData::Rela64(entries) => entries, - _ => return Err(ELFError::RelocationError), - }; - let dynsym = match self - .find_section_by_name(".dynsym") - .ok_or(ELFError::DynsymNotFind)? - .get_data(self) - .map_err(|_| ELFError::DynsymNotFind)? - { - SectionData::DynSymbolTable64(dsym) => Ok(dsym), - _ => Err(ELFError::DynsymNotFind), - }?; - for entry in entries.iter() { - const REL_GOT: u32 = 6; - const REL_PLT: u32 = 7; - const REL_RELATIVE: u32 = 8; - const R_RISCV_64: u32 = 2; - const R_RISCV_RELATIVE: u32 = 3; - match entry.get_type() { - REL_GOT | REL_PLT | R_RISCV_64 => { - let dynsym = &dynsym[entry.get_symbol_table_index() as usize]; - let symval = if dynsym.shndx() == 0 { - let name = dynsym.get_name(self).map_err(|_| ELFError::DynsymNotFind)?; - panic!("need to find symbol: {:?}", name); - } else { - bias + dynsym.value() as usize - }; - let value = symval + entry.get_addend() as usize; - let addr = bias + entry.get_offset() as usize; - res.push((addr, value)) - } - REL_RELATIVE | R_RISCV_RELATIVE => { - let value = bias + entry.get_addend() as usize; - let addr = bias + entry.get_offset() as usize; - res.push((addr, value)) - } - t => unimplemented!("unknown type: {}", t), - } - } - - // - let data = self - .find_section_by_name(".rela.plt") - .ok_or(ELFError::RelocationError)? - .get_data(self) - .map_err(|_| ELFError::RelocationError)?; - let entries = match data { - SectionData::Rela64(entries) => entries, - _ => return Err(ELFError::RelocationError), - }; - for entry in entries.iter() { - match entry.get_type() { - 5 => { - let dynsym = &dynsym[entry.get_symbol_table_index() as usize]; - let symval = if dynsym.shndx() == 0 { - let name = dynsym.get_name(self).map_err(|_| ELFError::DynsymNotFind)?; - panic!("symbol not found: {:?}", name); - } else { - dynsym.value() as usize - }; - let value = bias + symval; - let addr = bias + entry.get_offset() as usize; - res.push((addr, value)) - } - t => panic!("[kernel] unknown entry, type = {}", t), - } - } - Ok(res) - } -} -// /* RISC-V relocations. */ -// #define R_RISCV_NONE 0 -// #define R_RISCV_32 1 -// #define R_RISCV_64 2 -// #define R_RISCV_RELATIVE 3 -// #define R_RISCV_COPY 4 -// #define R_RISCV_JUMP_SLOT 5 -// #define R_RISCV_TLS_DTPMOD32 6 -// #define R_RISCV_TLS_DTPMOD64 7 -// #define R_RISCV_TLS_DTPREL32 8 -// #define R_RISCV_TLS_DTPREL64 9 -// #define R_RISCV_TLS_TPREL32 10 -// #define R_RISCV_TLS_TPREL64 11 -// #define R_RISCV_BRANCH 16 -// #define R_RISCV_JAL 17 diff --git a/kernel/src/memory/frame.rs b/kernel/src/memory/frame.rs deleted file mode 100644 index aad1d187..00000000 --- a/kernel/src/memory/frame.rs +++ /dev/null @@ -1,147 +0,0 @@ -use super::manager::FrameRefManager; -use crate::config::{FRAME_BITS, FRAME_SIZE}; -use alloc::format; -use alloc::vec::Vec; -use core::ops::{Deref, DerefMut}; -use ksync::Mutex; -use pager::{PageAllocator, PageAllocatorExt}; -use spin::Lazy; - -#[cfg(feature = "pager_bitmap")] -pub static FRAME_ALLOCATOR: Mutex> = Mutex::new(pager::Bitmap::new()); -#[cfg(feature = "pager_buddy")] -pub static FRAME_ALLOCATOR: Mutex> = Mutex::new(pager::Zone::new()); - -pub static FRAME_REF_MANAGER: Lazy> = - Lazy::new(|| Mutex::new(FrameRefManager::new())); -extern "C" { - fn ekernel(); -} - -pub fn init_frame_allocator(memory_end: usize) { - let start = ekernel as usize; - let end = memory_end; - let page_start = start / FRAME_SIZE; - let page_end = end / FRAME_SIZE; - let page_count = page_end - page_start; - println!( - "page start:{:#x},end:{:#x},count:{:#x}", - page_start, page_end, page_count - ); - FRAME_ALLOCATOR.lock().init(start..end).unwrap(); -} - -#[derive(Debug)] -pub struct FrameTracker { - id: usize, -} - -pub fn addr_to_frame(addr: usize) -> FrameTracker { - assert_eq!(addr % FRAME_SIZE, 0); - FrameTracker::new(addr >> FRAME_BITS) -} - -impl FrameTracker { - pub fn new(id: usize) -> Self { - Self { id } - } - pub fn start(&self) -> usize { - self.id << FRAME_BITS - } - pub fn end(&self) -> usize { - self.start() + FRAME_SIZE - } - pub fn id(&self) -> usize { - self.id - } -} - -impl Drop for FrameTracker { - fn drop(&mut self) { - trace!("drop frame:{}", self.id); - let _id = FRAME_REF_MANAGER.lock().dec_ref(self.id); - } -} - -impl Deref for FrameTracker { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - unsafe { core::slice::from_raw_parts(self.start() as *const u8, FRAME_SIZE) } - } -} - -impl DerefMut for FrameTracker { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { core::slice::from_raw_parts_mut(self.start() as *mut u8, FRAME_SIZE) } - } -} - -/// 提供给slab分配器的接口 -/// 这些页面需要保持连续 -#[no_mangle] -pub fn alloc_frames(num: usize) -> *mut u8 { - assert_eq!(num.next_power_of_two(), num); - let start_page = FRAME_ALLOCATOR.lock().alloc_pages(num, FRAME_SIZE); - if start_page.is_err() { - panic!("alloc {} frame failed", num); - } - let start_page = start_page.unwrap(); - let start_addr = start_page << FRAME_BITS; - trace!("slab alloc frame {} start:{:#x}", num, start_addr); - start_addr as *mut u8 -} - -/// 提供给slab分配器的接口 -#[no_mangle] -pub fn free_frames(addr: *mut u8, num: usize) { - assert_eq!(num.next_power_of_two(), num); - let start = addr as usize >> FRAME_BITS; - trace!("slab free frame {} start:{:#x}", num, addr as usize); - // make sure the num is 2^n - // assert_eq!(num.count_ones(), 1); - FRAME_ALLOCATOR - .lock() - .free_pages(start, num) - .expect(format!("frame start:{:#x},num:{}", start, num).as_str()); -} - -pub fn frame_alloc() -> Option { - let frame = FRAME_ALLOCATOR.lock().alloc(0); - if frame.is_err() { - return None; - } - let frame = frame.unwrap(); - FRAME_REF_MANAGER.lock().add_ref(frame); - Some(FrameTracker::new(frame)) -} - -pub fn frames_alloc(count: usize) -> Option> { - let mut ans = Vec::new(); - for _ in 0..count { - let id = FRAME_ALLOCATOR.lock().alloc(0); - if id.is_err() { - return None; - } - let id = id.unwrap(); - FRAME_REF_MANAGER.lock().add_ref(id); - ans.push(FrameTracker::new(id)); - } - Some(ans) -} - -pub fn frame_alloc_contiguous(count: usize) -> *mut u8 { - let count = count.next_power_of_two(); - assert_ne!(count, 0); - let frame = FRAME_ALLOCATOR.lock().alloc_pages(count, FRAME_SIZE); - if frame.is_err() { - panic!("alloc {} frame failed, oom", count); - } - let frame = frame.unwrap(); - trace!("alloc frame {} start:{:#x}", count, frame); - for i in 0..count { - let refs = FRAME_REF_MANAGER.lock().add_ref(frame + i); - assert_eq!(refs, 1) - } - (frame << FRAME_BITS as u64) as *mut u8 -} diff --git a/kernel/src/memory/manager.rs b/kernel/src/memory/manager.rs deleted file mode 100644 index 779c091a..00000000 --- a/kernel/src/memory/manager.rs +++ /dev/null @@ -1,47 +0,0 @@ -use alloc::collections::BTreeMap; -use pager::PageAllocator; - -use crate::memory::FRAME_ALLOCATOR; - -#[derive(Debug)] -pub struct FrameRefManager { - record: BTreeMap, -} - -impl FrameRefManager { - pub fn new() -> Self { - Self { - record: BTreeMap::new(), - } - } - pub fn add_ref(&mut self, id: usize) -> usize { - if let Some(count) = self.record.get_mut(&id) { - *count += 1; - *count - } else { - self.record.insert(id, 1); - 1 - } - } - pub fn dec_ref(&mut self, id: usize) -> Option { - if let Some(count) = self.record.get_mut(&id) { - *count -= 1; - let now_count = *count; - if *count == 0 { - self.record.remove(&id); - trace!("free frame:{:#x}", id); - FRAME_ALLOCATOR.lock().free(id, 0).unwrap(); - } - return Some(now_count); - } else { - panic!("dec {} ref error", id); - } - } - pub fn get_ref(&self, id: usize) -> usize { - if let Some(count) = self.record.get(&id) { - *count - } else { - panic!("get {} ref error", id); - } - } -} diff --git a/kernel/src/memory/map.rs b/kernel/src/memory/map.rs deleted file mode 100644 index 11fa4d1a..00000000 --- a/kernel/src/memory/map.rs +++ /dev/null @@ -1,254 +0,0 @@ -use alloc::sync::Arc; -use alloc::vec::Vec; -use core::ops::Range; - -use bitflags::bitflags; -use page_table::addr::{align_up_4k, VirtAddr}; -use page_table::pte::MappingFlags; - -use constants::io::MapFlags; -use constants::LinuxErrno; -use syscall_table::syscall_func; - -use crate::config::{FRAME_SIZE, PROCESS_HEAP_MAX}; -use crate::fs::file::File; -use crate::task::current_task; -use constants::AlienResult; - -bitflags! { - pub struct ProtFlags: u32 { - const PROT_NONE = 0x0; - const PROT_READ = 0x1; - const PROT_WRITE = 0x2; - const PROT_EXEC = 0x4; - } -} - -impl Into for ProtFlags { - fn into(self) -> MappingFlags { - let mut perm = MappingFlags::empty(); - if self.contains(ProtFlags::PROT_READ) { - perm |= MappingFlags::R; - } - if self.contains(ProtFlags::PROT_WRITE) { - perm |= MappingFlags::W; - } - if self.contains(ProtFlags::PROT_EXEC) { - perm |= MappingFlags::X; - } - perm |= MappingFlags::U; - perm - } -} - -#[derive(Debug, Clone)] -/// The Process should manage the mmap info -pub struct MMapInfo { - /// The start address of the mmap, it is a constant - map_start: usize, - /// The regions of the mmap - regions: Vec, -} - -#[derive(Debug, Clone)] -pub struct MMapRegion { - /// The start address of the mapping - pub start: usize, - /// The length of the mapping - pub len: usize, - pub map_len: usize, - /// The protection flags of the mapping - pub prot: ProtFlags, - /// The flags of the mapping - pub flags: MapFlags, - /// The file descriptor to map - pub fd: Option>, - /// The offset in the file to start from - pub offset: usize, -} - -impl MMapInfo { - pub fn new() -> Self { - Self { - map_start: PROCESS_HEAP_MAX, - regions: Vec::new(), - } - } - - pub fn alloc(&mut self, len: usize) -> Range { - let addr = self.map_start; - self.map_start += len; - // align to Frame size - self.map_start = (self.map_start + FRAME_SIZE - 1) & !(FRAME_SIZE - 1); - addr..self.map_start - } - - pub fn add_region(&mut self, region: MMapRegion) { - self.regions.push(region); - } - - pub fn get_region(&self, addr: usize) -> Option<&MMapRegion> { - for region in self.regions.iter() { - if region.start <= addr && addr < region.start + region.len { - return Some(region); - } - } - None - } - - pub fn get_region_mut(&mut self, addr: usize) -> Option<&mut MMapRegion> { - for region in self.regions.iter_mut() { - if region.start <= addr && addr < region.start + region.len { - return Some(region); - } - } - None - } - - pub fn remove_region(&mut self, addr: usize) { - let mut index = 0; - for region in self.regions.iter() { - if region.start <= addr && addr < region.start + region.len { - break; - } - index += 1; - } - self.regions.remove(index); - } -} - -impl MMapRegion { - pub fn new( - start: usize, - len: usize, - map_len: usize, - prot: ProtFlags, - flags: MapFlags, - fd: Option>, - offset: usize, - ) -> Self { - Self { - start, - len, - map_len, - prot, - flags, - fd, - offset, - } - } - // [a-b] - // [a-c] [c-b] - pub fn split(&self, addr: usize) -> (Self, Self) { - let mut region1 = self.clone(); - let mut region2 = self.clone(); - region1.len = addr - self.start; - region1.map_len = align_up_4k(region1.len); - region2.start = addr; - region2.len = self.start + self.len - addr; - region2.map_len = align_up_4k(region2.len); - region2.offset += region1.len; - (region1, region2) - } - - pub fn set_prot(&mut self, prot: ProtFlags) { - self.prot = prot; - } - pub fn set_flags(&mut self, flags: MapFlags) { - self.flags = flags; - } -} - -/// 一个函数调用,用于消除内存映射。 -/// 注意:传入的`start`必须是某段内存映射的首地址,`len`必须是该段内存映射的长度,否则将导致函数返回`EINVAL`。函数正常执行将返回0。 -#[syscall_func(215)] -pub fn do_munmap(start: usize, len: usize) -> isize { - let task = current_task().unwrap(); - let res = task.access_inner().unmap(start, len); - if res.is_err() { - return res.err().unwrap(); - } - 0 -} - -/// 一个系统调用,用于将文件或设备映射到内存中。将一个普通文件映射到内存中,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能。 -/// -/// + `start`: 所要创建的映射区的起始地址。当该值为0时,内核将自动为其分配一段内存空间创建内存映射。该值在函数运行过程中将被调整为与4K对齐。 -/// + `len`: 指明所要创建的映射区的长度。该值在函数运行过程中将被调整为与4K对齐。 -/// + `prot`: 指明创建内存映射区的初始保护位。具体可见[`ProtFlags`]。 -/// + `flags`: 指明mmap操作的相关设置。具体可见[`MapFlags`]。 -/// + `fd`: 指明要创建内存映射的文件的文件描述符。 -/// + `offset`: 将从文件中偏移量为`offset`处开始映射。该值需要和4K对齐。 -/// -/// 函数成功执行后将返回所创建的内存映射区的首地址;否则返回错误类型。 -/// Reference: [do_mmap](https://man7.org/linux/man-pages/man2/mmap.2.html) -#[syscall_func(222)] -pub fn do_mmap( - start: usize, - len: usize, - prot: u32, - flags: u32, - fd: usize, - offset: usize, -) -> AlienResult { - let process = current_task().unwrap(); - let mut process_inner = process.access_inner(); - let prot = ProtFlags::from_bits_truncate(prot); - let flags = MapFlags::from_bits_truncate(flags); - warn!( - "mmap: start: {:#x}, len: {:#x}, prot: {:?}, flags: {:?}, fd: {}, offset: {:#x}", - start, len, prot, flags, fd, offset - ); - process_inner - .add_mmap(start, len, prot, flags, fd, offset) - .map(|addr| addr as isize) -} - -/// 一个系统调用,用于修改内存映射的保护位,从而修改对内存映射的访问权限。 -/// 函数会检查传入的`start`和`len`所指示的内存映射区是否已经处于被映射状态,如果是,则将对应内存映射区的保护位与`prot`做或运算。 -/// -/// 如果函数正常执行,则返回0;如果`start`和`len`所指示的内存映射区未已经处于被映射状态,函数将返回-1。 -#[syscall_func(226)] -pub fn map_protect(start: usize, len: usize, prot: u32) -> AlienResult { - let process = current_task().unwrap(); - let mut process_inner = process.access_inner(); - let prot = ProtFlags::from_bits_truncate(prot); - warn!( - "mprotect: start: {:#x}, len: {:#x}, prot: {:?}", - start, len, prot - ); - process_inner.map_protect(start, len, prot)?; - Ok(0) -} - -/// (待实现)一个系统调用,用于同步文件在内存映射中的修改。一个文件通过[`do_mmap`]映射到内存中,可以在内存中对其进行快速的读写。 -/// 当我们对文件的映射进行修改后,如果不调用`msync`系统调用,那么在调用[`do_munmap`]之前内存中的相应内容都不会写回磁盘文件,有可能导致不一致性问题。 -/// 目前函数仅会检查所传入的`addr`是否已经被映射,如果没有被映射,则会返回`EFAULT`;否则直接返回0。 -/// -/// Reference: [madvise](https://man7.org/linux/man-pages/man2/madvise.2.html) -#[syscall_func(227)] -pub fn msync(addr: usize, len: usize, flags: usize) -> isize { - warn!( - "msync: addr: {:#x}, len: {:#x}, flags: {:#x}", - addr, len, flags - ); - let task = current_task().unwrap(); - let address_space = &task.access_inner().address_space; - let res = address_space.lock().query(VirtAddr::from(addr)); - if res.is_err() { - return LinuxErrno::EFAULT as isize; - } - 0 -} - -/// (待实现)一个系统调用,用于向内核提供使用内存的建议。目前直接返回0。 -/// -/// Reference: [madvise](https://man7.org/linux/man-pages/man2/madvise.2.html) -#[syscall_func(233)] -pub fn madvise(addr: usize, len: usize, advice: usize) -> isize { - warn!( - "madvise: addr: {:#x}, len: {:#x}, advice: {:#x}", - addr, len, advice - ); - 0 -} diff --git a/kernel/src/memory/mod.rs b/kernel/src/memory/mod.rs deleted file mode 100644 index 5da7e00d..00000000 --- a/kernel/src/memory/mod.rs +++ /dev/null @@ -1,151 +0,0 @@ -use core::alloc::GlobalAlloc; - -#[cfg(feature = "buddy")] -use buddy_system_allocator::LockedHeap; -use cfg_if::cfg_if; -#[cfg(feature = "talloc")] -use talc::{Talc, Talck}; - -pub use frame::*; -use ksync::Mutex; -pub use map::*; -use syscall_table::syscall_func; -pub use vmm::*; - -use crate::config::FRAME_SIZE; -#[cfg(any(feature = "talloc", feature = "buddy"))] -use crate::config::KERNEL_HEAP_SIZE; -use arch::{activate_paging_mode, hart_id}; - -mod elf; -mod frame; -mod manager; -mod map; -mod vmm; - -#[global_allocator] -static HEAP_ALLOCATOR: HeapAllocator = HeapAllocator::new(); - -#[cfg(any(feature = "talloc", feature = "buddy"))] -static mut KERNEL_HEAP: [u8; KERNEL_HEAP_SIZE] = [0; KERNEL_HEAP_SIZE]; - -pub fn init_memory_system(memory_end: usize, is_first_cpu: bool) { - if is_first_cpu { - init_frame_allocator(memory_end); - println!("Frame allocator init success"); - cfg_if! { - if #[cfg(feature = "talloc")] { - init_talloc_system(); - println!("talloc allocator init success"); - } else if #[cfg(feature = "buddy")] { - init_buddy_system(); - println!("buddy allocator init success"); - } else if #[cfg(feature = "slab")] { - init_slab_system(FRAME_SIZE, 32); - println!("slab allocator init success"); - } - } - build_kernel_address_space(memory_end); - println!("build kernel address space success"); - activate_paging_mode(kernel_space_root_ppn()); - println!("activate paging mode success"); - } else { - activate_paging_mode(kernel_space_root_ppn()); - } -} - -struct HeapAllocator { - #[cfg(feature = "talloc")] - allocator: Mutex, - #[cfg(feature = "buddy")] - allocator: Mutex>, - #[cfg(feature = "slab")] - allocator: Mutex, -} - -unsafe impl GlobalAlloc for HeapAllocator { - unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { - let need_page = if layout.size() % FRAME_SIZE == 0 { - layout.size() / FRAME_SIZE - } else { - layout.size() / FRAME_SIZE + 1 - }; - if layout.size() >= 5 * 1024 * 1024 { - trace!("alloc big page: {:#x}", layout.size()); - let frame = alloc_frames(need_page); - frame - } else { - let ptr = self.allocator.lock().alloc(layout); - assert!(!ptr.is_null()); - ptr - } - } - unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { - let need_page = if layout.size() % FRAME_SIZE == 0 { - layout.size() / FRAME_SIZE - } else { - layout.size() / FRAME_SIZE + 1 - }; - if layout.size() >= 5 * 1024 * 1024 { - trace!("free big page: {:#x}", layout.size()); - free_frames(ptr, need_page); - } else { - assert_eq!(ptr.is_null(), false); - self.allocator.lock().dealloc(ptr, layout); - } - } -} - -impl HeapAllocator { - pub const fn new() -> Self { - Self { - #[cfg(feature = "talloc")] - allocator: Mutex::new(Talc::new().spin_lock()), - #[cfg(feature = "buddy")] - allocator: Mutex::new(LockedHeap::<32>::new()), - #[cfg(feature = "slab")] - allocator: Mutex::new(SlabAllocator), - } - } -} - -pub fn kernel_satp() -> usize { - 8usize << 60 | (KERNEL_SPACE.read().root_paddr().as_usize() >> 12) -} - -/// This function will be call in slab allocator -#[no_mangle] -fn current_cpu_id() -> usize { - hart_id() -} - -/// (待实现)在一组线程中,设置内存屏障,控制多核系统中的内存访问次序。目前直接返回0。 -/// -/// -#[syscall_func(283)] -pub fn membarrier() -> isize { - 0 -} - -#[cfg(feature = "talloc")] -fn init_talloc_system() { - unsafe { - HEAP_ALLOCATOR - .allocator - .lock() - .talc() - .init(KERNEL_HEAP.as_mut_slice().into()) - } -} - -#[cfg(feature = "buddy")] -fn init_buddy_system() { - unsafe { - HEAP_ALLOCATOR - .allocator - .lock() - .lock() - .init(KERNEL_HEAP.as_ptr() as usize, KERNEL_HEAP_SIZE); - println!("heap start: {:#x}", KERNEL_HEAP.as_ptr() as usize); - } -} diff --git a/kernel/src/memory/vmm.rs b/kernel/src/memory/vmm.rs deleted file mode 100644 index 306bcefe..00000000 --- a/kernel/src/memory/vmm.rs +++ /dev/null @@ -1,557 +0,0 @@ -use crate::config::*; -use crate::fs; -use crate::ipc::ShmInfo; -use crate::memory::elf::{ELFError, ELFInfo, ELFReader}; -use crate::memory::frame::{addr_to_frame, frame_alloc}; -use crate::memory::{frame_alloc_contiguous, FRAME_REF_MANAGER}; -use crate::trap::TrapFrame; -use alloc::collections::BTreeMap; -use alloc::string::{String, ToString}; -use alloc::sync::Arc; -use alloc::vec; -use alloc::vec::Vec; -use core::cmp::min; -use core::fmt::Debug; -use core::mem::forget; -use ksync::RwLock; -use page_table::addr::{align_up_4k, PhysAddr, VirtAddr}; -use page_table::pte::MappingFlags; -use page_table::table::{PagingIf, Sv39PageTable}; -use spin::Lazy; -use xmas_elf::program::{SegmentData, Type}; - -pub static KERNEL_SPACE: Lazy>>> = Lazy::new(|| { - Arc::new(RwLock::new( - Sv39PageTable::::try_new().unwrap(), - )) -}); - -pub fn kernel_space_root_ppn() -> usize { - KERNEL_SPACE.read().root_paddr().as_usize() >> FRAME_BITS -} - -#[allow(unused)] -extern "C" { - fn stext(); - fn srodata(); - fn sdata(); - fn sbss(); - fn ekernel(); - fn strampoline(); - fn sinit(); - fn einit(); - - // fn kernel_eh_frame(); - // fn kernel_eh_frame_end(); - // fn kernel_eh_frame_hdr(); - // fn kernel_eh_frame_hdr_end(); -} - -pub fn kernel_info(memory_end: usize) { - println!( - "kernel text: {:#x}-{:#x}", - stext as usize, srodata as usize - ); - println!( - "kernel rodata: {:#x}-{:#x}", - srodata as usize, sdata as usize - ); - println!( - "kernel init_array: {:#x}-{:#x}", - sinit as usize, einit as usize - ); - println!( - "kernel data: {:#x}-{:#x}", - sdata as usize, sbss as usize - ); - println!( - "kernel bss: {:#x}-{:#x}", - sbss as usize, ekernel as usize - ); - // println!("kernel eh_frame: {:#x}-{:#x}", kernel_eh_frame as usize, kernel_eh_frame_end as usize); - // println!("kernel eh_frame_hdr: {:#x}-{:#x}", kernel_eh_frame_hdr as usize, kernel_eh_frame_hdr_end as usize); - println!( - "kernel heap: {:#x}-{:#x}", - ekernel as usize, memory_end - ); -} - -/// 建立内核页表 -pub fn build_kernel_address_space(memory_end: usize) { - let mut kernel_space = KERNEL_SPACE.write(); - kernel_space - .map_region( - VirtAddr::from(stext as usize), - PhysAddr::from(stext as usize), - srodata as usize - stext as usize, - "RXVAD".into(), - true, - ) - .unwrap(); - kernel_space - .map_region( - VirtAddr::from(srodata as usize), - PhysAddr::from(srodata as usize), - sdata as usize - srodata as usize, - "RVAD".into(), - true, - ) - .unwrap(); - kernel_space - .map_region( - VirtAddr::from(sdata as usize), - PhysAddr::from(sdata as usize), - sbss as usize - sdata as usize, - "RWVAD".into(), - true, - ) - .unwrap(); - kernel_space - .map_region( - VirtAddr::from(sbss as usize), - PhysAddr::from(sbss as usize), - ekernel as usize - sbss as usize, - "RWVAD".into(), - true, - ) - .unwrap(); - kernel_space - .map_region( - VirtAddr::from(ekernel as usize), - PhysAddr::from(ekernel as usize), - memory_end - ekernel as usize, - "RWVAD".into(), - true, - ) - .unwrap(); - kernel_space - .map_region( - VirtAddr::from(TRAMPOLINE), - PhysAddr::from(strampoline as usize), - FRAME_SIZE, - "RXVAD".into(), - true, - ) - .unwrap(); - for pair in MMIO { - kernel_space - .map_region( - VirtAddr::from(pair.0), - PhysAddr::from(pair.0), - pair.1, - "RWVAD".into(), - true, - ) - .unwrap(); - } -} - -#[derive(Debug)] -pub struct UserStack { - pub virt_stack_top: usize, - pub stack_top: usize, - pub stack_bottom: usize, -} - -impl UserStack { - pub fn new(phy_stack_top: usize, virt_stack_top: usize) -> Self { - Self { - virt_stack_top, - stack_top: phy_stack_top, - stack_bottom: phy_stack_top - FRAME_SIZE, - } - } - - pub fn get_stack_top(&self) -> usize { - self.stack_top - } - - pub fn push(&mut self, data: usize) -> Result { - if self.stack_top - 8 < self.stack_bottom { - return Err("Stack Overflow"); - } - unsafe { - self.stack_top -= 8; - *(self.stack_top as *mut usize) = data; - } - trace!( - "stack top: {:#x}, data:{:#x?}", - self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom)), - data - ); - Ok(self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom))) - } - - pub fn push_str(&mut self, data: &str) -> Result { - self.push_bytes(data.as_bytes()) - } - - pub fn push_bytes(&mut self, data: &[u8]) -> Result { - let len = data.len(); - // align 8 - let start = self.stack_top - len; - let start = start & !7; - if start < self.stack_bottom { - return Err("Stack Overflow"); - } - unsafe { - self.stack_top = start; - let ptr = self.stack_top as *mut u8; - ptr.copy_from_nonoverlapping(data.as_ptr(), len); - } - trace!( - "stack top: {:#x}", - self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom)) - ); - Ok(self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom))) - } - - pub fn align_to(&mut self, align: usize) -> Result { - let start = self.stack_top & !(align - 1); - if start < self.stack_bottom { - return Err("Stack Overflow"); - } - self.stack_top = start; - Ok(self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom))) - } -} - -pub fn build_thread_address_space( - table: &mut Sv39PageTable, - thread_num_within: usize, -) -> &'static mut TrapFrame { - let address = TRAP_CONTEXT_BASE - FRAME_SIZE * thread_num_within; - let (_virt_dst, phy_dst, _) = table - .map_region_no_target( - VirtAddr::from(address), - FRAME_SIZE, - "RWVAD".into(), - true, - false, - ) - .unwrap() - .next() - .unwrap(); - // copy data - // find the - let (phy, _flag, page_size) = table.query(VirtAddr::from(TRAP_CONTEXT_BASE)).unwrap(); - assert_eq!(usize::from(page_size), FRAME_SIZE); - // copy data - let src_ptr = phy.as_usize() as *const u8; - let dst_ptr = phy_dst.as_usize() as *mut u8; - unsafe { - core::ptr::copy(src_ptr, dst_ptr, usize::from(page_size)); - } - TrapFrame::from_raw_ptr(dst_ptr as *mut TrapFrame) -} - -pub fn build_cow_address_space( - p_table: &mut Sv39PageTable, - shm: BTreeMap, -) -> Sv39PageTable { - let mut address_space = Sv39PageTable::::try_new().unwrap(); - for (v_addr, target) in p_table.get_record().into_iter() { - trace!("v_addr: {:?}, target: {}", v_addr, target); - let (phy, flag, page_size) = p_table.query(v_addr).unwrap(); - - // shm should remap, we can't use cow for it - let is_in_segs = |addr: usize| -> bool { - for (_id, shminfo) in shm.iter() { - if addr >= shminfo.start_va && addr < shminfo.end_va { - return true; - } - } - false - }; - - if v_addr.as_usize() == TRAP_CONTEXT_BASE { - // for Trap_context, we remap it - assert_eq!(usize::from(page_size), TRAMPOLINE - TRAP_CONTEXT_BASE); - let dst = address_space - .map_no_target(v_addr, page_size, flag, false) - .unwrap(); - // copy data - let src_ptr = phy.as_usize() as *const u8; - let dst_ptr = dst.as_usize() as *mut u8; - unsafe { - core::ptr::copy(src_ptr, dst_ptr, usize::from(page_size)); - } - } else if is_in_segs(v_addr.as_usize()) { - // for shm, we now skip it - address_space.map(v_addr, phy, page_size, flag).unwrap(); - } else { - // cow - // checkout whether pte flags has `W` flag - let mut flags = flag.clone(); - if !flag.contains(MappingFlags::V) { - // if flags is not valid, we just map it - address_space.map(v_addr, phy, page_size, flags).unwrap(); - if target { - address_space.get_record_mut().insert(v_addr, true); - } - continue; - } - if flag.contains(MappingFlags::W) { - flags -= MappingFlags::W; - flags |= MappingFlags::RSD; // we use the RSD flag to indicate that this page is a cow page - // update parent's flag and clear dirty - p_table.modify_pte_flags(v_addr, flags, false).unwrap(); - } - address_space.map(v_addr, phy, page_size, flags).unwrap(); - // add ref for alloc page - if target { - for i in 0..usize::from(page_size) / FRAME_SIZE { - let page_number = (phy + FRAME_SIZE * i).as_usize() >> FRAME_BITS; - // FRAME_REF_MANAGER.lock().get_ref(page_number); - FRAME_REF_MANAGER.lock().add_ref(page_number); - } - address_space.get_record_mut().insert(v_addr, true); - } - } - } - address_space -} - -pub fn build_elf_address_space( - elf: &[u8], - args: &mut Vec, - name: &str, -) -> Result { - let mut address_space = Sv39PageTable::::try_new().unwrap(); - const ELF_MAGIC: [u8; 4] = [0x7f, b'E', b'L', b'F']; - if elf[0..4] != ELF_MAGIC { - return Err(ELFError::NotELF); - } - let elf = xmas_elf::ElfFile::new(elf).map_err(|_| ELFError::NotELF)?; - // check whether it's a dynamic linked elf - if let Some(inter) = elf - .program_iter() - .find(|ph| ph.get_type().unwrap() == Type::Interp) - { - let data = match inter.get_data(&elf).unwrap() { - SegmentData::Undefined(data) => data, - _ => return Err(ELFError::NoEntrySegment), - }; - let path = core::str::from_utf8(data).unwrap(); - assert!(path.starts_with("/lib/ld-musl-riscv64-sf.so.1")); - let mut new_args = vec!["/libc.so\0".to_string()]; - new_args.extend(args.clone()); - *args = new_args; - // load interpreter - let mut data = vec![]; - warn!("load interpreter: {}, new_args:{:?}", path, args); - if fs::read_all("libc.so", &mut data) { - return build_elf_address_space(&data, args, "libc.so"); - } else { - error!("[map_elf] Found interpreter path: {}", path); - panic!("load interpreter failed"); - } - } - - // calculate bias for dynamic linked elf - // if elf is static linked, bias is 0 - let bias = match elf.header.pt2.type_().as_type() { - // static - xmas_elf::header::Type::Executable => 0, - xmas_elf::header::Type::SharedObject => { - match elf - .program_iter() - .filter(|ph| ph.get_type().unwrap() == Type::Interp) - .count() - { - // It's a loader! - 0 => ELF_BASE_RELOCATE, - // It's a dynamically linked ELF. - 1 => 0, - // Emmm, It has multiple interpreters. - _ => return Err(ELFError::NotSupported), - } - } - _ => return Err(ELFError::NotSupported), - }; - trace!("bias: {:#x}", bias); - - let tls = elf - .program_iter() - .find(|x| x.get_type().unwrap() == Type::Tls) - .map(|ph| ph.virtual_addr()) - .unwrap_or(0); - - warn!("ELF tls: {:#x}", tls); - - let mut break_addr = 0usize; - elf.program_iter() - .filter(|ph| ph.get_type() == Ok(Type::Load)) - .for_each(|ph| { - let start_addr = ph.virtual_addr() as usize + bias; - let end_addr = start_addr + ph.mem_size() as usize; - let mut permission: MappingFlags = "UVAD".into(); - let ph_flags = ph.flags(); - if ph_flags.is_read() { - permission |= MappingFlags::R; - } - if ph_flags.is_write() { - permission |= MappingFlags::W; - } - if ph_flags.is_execute() { - permission |= MappingFlags::X; - } - let vaddr = VirtAddr::from(start_addr).align_down_4k(); - let end_vaddr = VirtAddr::from(end_addr).align_up_4k(); - // 记录程序地址空间的最大地址 - break_addr = end_addr; - let len = end_vaddr.as_usize() - vaddr.as_usize(); - warn!( - "load segment: {:#x} - {:#x} -> {:#x}-{:#x}, permission: {:?}", - start_addr, - end_addr, - vaddr.as_usize(), - end_vaddr.as_usize(), - permission - ); - let mut data = - &elf.input[ph.offset() as usize..(ph.offset() + ph.file_size()) as usize]; - let map_info = address_space - .map_region_no_target(vaddr, len, permission, false, false) - .unwrap(); - // copy data - let mut page_offset = start_addr & (FRAME_SIZE - 1); - let mut count = 0; - map_info - .into_iter() - .for_each(|(_vir, phy, page_size)| unsafe { - let size: usize = page_size.into(); - let min = min(size - page_offset, data.len()); - let dst = (phy.as_usize() + page_offset) as *mut u8; - core::ptr::copy(data.as_ptr(), dst, min); - data = &data[min..]; - count += min; - page_offset = 0; - }); - assert_eq!(count, ph.file_size() as usize); - }); - - // 地址向上取整对齐4 - let ceil_addr = align_up_4k(break_addr + FRAME_SIZE); - // 留出一个用户栈的位置+隔离页 - let top = ceil_addr + USER_STACK_SIZE + FRAME_SIZE; - warn!( - "user stack: {:#x} - {:#x}", - top - USER_STACK_SIZE - FRAME_SIZE, - top - FRAME_SIZE - ); - // map user stack - address_space - .map_region_no_target( - VirtAddr::from(top - USER_STACK_SIZE - FRAME_SIZE), - USER_STACK_SIZE, - "RWUAD".into(), - false, - true, - ) - .unwrap(); - // 初始化一个有效页 - address_space - .validate(VirtAddr::from(top - FRAME_SIZE * 2), "RWUVAD".into()) - .unwrap(); - let heap_bottom = top; - // align to 4k - warn!("trap context: {:#x} - {:#x}", TRAP_CONTEXT_BASE, TRAMPOLINE); - address_space - .map_region_no_target( - VirtAddr::from(TRAP_CONTEXT_BASE), - TRAMPOLINE - TRAP_CONTEXT_BASE, - "RWVAD".into(), - true, - false, - ) - .unwrap(); - warn!( - "TRAMPOLINE: {:#x} - {:#x}", - TRAMPOLINE, - TRAMPOLINE + FRAME_SIZE - ); - address_space - .map_region( - VirtAddr::from(TRAMPOLINE), - PhysAddr::from(strampoline as usize), - FRAME_SIZE, - "RXVAD".into(), - true, - ) - .unwrap(); - - let res = if let Some(phdr) = elf - .program_iter() - .find(|ph| ph.get_type() == Ok(Type::Phdr)) - { - // if phdr exists in program header, use it - Ok(phdr.virtual_addr()) - } else if let Some(elf_addr) = elf - .program_iter() - .find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0) - { - // otherwise, check if elf is loaded from the beginning, then phdr can be inferred. - // Ok(elf_addr.virtual_addr()) - Ok(elf_addr.virtual_addr() + elf.header.pt2.ph_offset()) - } else { - warn!("elf: no phdr found, tls might not work"); - Err(ELFError::NoEntrySegment) - } - .unwrap_or(0); - warn!( - "entry: {:#x}, phdr:{:#x}", - elf.header.pt2.entry_point() + bias as u64, - res + bias as u64 - ); - // relocate if elf is dynamically linked - if let Ok(kvs) = elf.relocate(bias) { - kvs.into_iter().for_each(|kv| { - trace!("relocate: {:#x} -> {:#x}", kv.0, kv.1); - let (addr, ..) = address_space.query(VirtAddr::from(kv.0)).unwrap(); - unsafe { (addr.as_usize() as *mut usize).write(kv.1) } - }) - } - Ok(ELFInfo { - address_space, - entry: elf.header.pt2.entry_point() as usize + bias, - stack_top: top - FRAME_SIZE, - heap_bottom, - ph_num: elf.header.pt2.ph_count() as usize, - ph_entry_size: elf.header.pt2.ph_entry_size() as usize, - ph_drift: res as usize + bias, - tls: tls as usize, - bias, - name: name.to_string(), - }) -} - -pub struct PageAllocator; - -impl PagingIf for PageAllocator { - fn alloc_frame() -> Option { - frame_alloc().map(|frame| { - let start = frame.start(); - trace!("PageAllocator alloc frame{:?} start:{:#x}", frame, start); - forget(frame); - PhysAddr::from(start) - }) - } - - fn dealloc_frame(paddr: PhysAddr) { - let frame = addr_to_frame(paddr.as_usize()); - trace!("PageAllocator dealloc frame {:?}", frame); - } - - fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { - VirtAddr::from(paddr.as_usize()) - } - - fn alloc_contiguous_frames(size: usize) -> Option { - let ptr = frame_alloc_contiguous(size); - if ptr.is_null() { - return None; - } - Some(PhysAddr::from(ptr as usize)) - } -} diff --git a/kkernel/src/mm/elf.rs b/kernel/src/mm/elf.rs similarity index 100% rename from kkernel/src/mm/elf.rs rename to kernel/src/mm/elf.rs index a88aaca9..b2d0b522 100644 --- a/kkernel/src/mm/elf.rs +++ b/kernel/src/mm/elf.rs @@ -3,11 +3,11 @@ use alloc::vec; use alloc::vec::Vec; use core::fmt::{Debug, Formatter}; +use mem::VmmPageAllocator; use page_table::table::Sv39PageTable; use xmas_elf::sections::SectionData; use xmas_elf::symbol_table::Entry; use xmas_elf::ElfFile; -use mem::VmmPageAllocator; #[allow(unused)] #[derive(Debug)] diff --git a/kkernel/src/mm/loader.rs b/kernel/src/mm/loader.rs similarity index 96% rename from kkernel/src/mm/loader.rs rename to kernel/src/mm/loader.rs index 0279b796..4da73547 100644 --- a/kkernel/src/mm/loader.rs +++ b/kernel/src/mm/loader.rs @@ -1,395 +1,394 @@ -use config::*; -use crate::fs; -use crate::ipc::ShmInfo; -use crate::mm::elf::{ELFError, ELFInfo, ELFReader}; -use crate::trap::TrapFrame; -use alloc::collections::BTreeMap; -use alloc::string::{String, ToString}; -use alloc::vec; -use alloc::vec::Vec; -use core::cmp::min; -use core::fmt::Debug; -use page_table::addr::{align_up_4k, PhysAddr, VirtAddr}; -use page_table::pte::MappingFlags; -use page_table::table::{Sv39PageTable}; -use xmas_elf::program::{SegmentData, Type}; -use mem::{FRAME_REF_MANAGER, VmmPageAllocator}; - -extern "C" { - fn strampoline(); -} -#[derive(Debug)] -pub struct UserStack { - pub virt_stack_top: usize, - pub stack_top: usize, - pub stack_bottom: usize, -} - -impl UserStack { - pub fn new(phy_stack_top: usize, virt_stack_top: usize) -> Self { - Self { - virt_stack_top, - stack_top: phy_stack_top, - stack_bottom: phy_stack_top - FRAME_SIZE, - } - } - - pub fn push(&mut self, data: usize) -> Result { - if self.stack_top - 8 < self.stack_bottom { - return Err("Stack Overflow"); - } - unsafe { - self.stack_top -= 8; - *(self.stack_top as *mut usize) = data; - } - trace!( - "stack top: {:#x}, data:{:#x?}", - self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom)), - data - ); - Ok(self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom))) - } - - pub fn push_str(&mut self, data: &str) -> Result { - self.push_bytes(data.as_bytes()) - } - - pub fn push_bytes(&mut self, data: &[u8]) -> Result { - let len = data.len(); - // align 8 - let start = self.stack_top - len; - let start = start & !7; - if start < self.stack_bottom { - return Err("Stack Overflow"); - } - unsafe { - self.stack_top = start; - let ptr = self.stack_top as *mut u8; - ptr.copy_from_nonoverlapping(data.as_ptr(), len); - } - trace!( - "stack top: {:#x}", - self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom)) - ); - Ok(self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom))) - } - - pub fn align_to(&mut self, align: usize) -> Result { - let start = self.stack_top & !(align - 1); - if start < self.stack_bottom { - return Err("Stack Overflow"); - } - self.stack_top = start; - Ok(self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom))) - } -} - -pub fn build_thread_address_space( - table: &mut Sv39PageTable, - thread_num_within: usize, -) -> &'static mut TrapFrame { - let address = TRAP_CONTEXT_BASE - FRAME_SIZE * thread_num_within; - let (_virt_dst, phy_dst, _) = table - .map_region_no_target( - VirtAddr::from(address), - FRAME_SIZE, - "RWVAD".into(), - true, - false, - ) - .unwrap() - .next() - .unwrap(); - // copy data - // find the - let (phy, _flag, page_size) = table.query(VirtAddr::from(TRAP_CONTEXT_BASE)).unwrap(); - assert_eq!(usize::from(page_size), FRAME_SIZE); - // copy data - let src_ptr = phy.as_usize() as *const u8; - let dst_ptr = phy_dst.as_usize() as *mut u8; - unsafe { - core::ptr::copy(src_ptr, dst_ptr, usize::from(page_size)); - } - TrapFrame::from_raw_ptr(dst_ptr as *mut TrapFrame) -} - -pub fn build_cow_address_space( - p_table: &mut Sv39PageTable, - shm: BTreeMap, -) -> Sv39PageTable { - let mut address_space = Sv39PageTable::::try_new().unwrap(); - for (v_addr, target) in p_table.get_record().into_iter() { - trace!("v_addr: {:?}, target: {}", v_addr, target); - let (phy, flag, page_size) = p_table.query(v_addr).unwrap(); - - // shm should remap, we can't use cow for it - let is_in_segs = |addr: usize| -> bool { - for (_id, shminfo) in shm.iter() { - if addr >= shminfo.start_va && addr < shminfo.end_va { - return true; - } - } - false - }; - - if v_addr.as_usize() == TRAP_CONTEXT_BASE { - // for Trap_context, we remap it - assert_eq!(usize::from(page_size), TRAMPOLINE - TRAP_CONTEXT_BASE); - let dst = address_space - .map_no_target(v_addr, page_size, flag, false) - .unwrap(); - // copy data - let src_ptr = phy.as_usize() as *const u8; - let dst_ptr = dst.as_usize() as *mut u8; - unsafe { - core::ptr::copy(src_ptr, dst_ptr, usize::from(page_size)); - } - } else if is_in_segs(v_addr.as_usize()) { - // for shm, we now skip it - address_space.map(v_addr, phy, page_size, flag).unwrap(); - } else { - // cow - // checkout whether pte flags has `W` flag - let mut flags = flag.clone(); - if !flag.contains(MappingFlags::V) { - // if flags is not valid, we just map it - address_space.map(v_addr, phy, page_size, flags).unwrap(); - if target { - address_space.get_record_mut().insert(v_addr, true); - } - continue; - } - if flag.contains(MappingFlags::W) { - flags -= MappingFlags::W; - flags |= MappingFlags::RSD; // we use the RSD flag to indicate that this page is a cow page - // update parent's flag and clear dirty - p_table.modify_pte_flags(v_addr, flags, false).unwrap(); - } - address_space.map(v_addr, phy, page_size, flags).unwrap(); - // add ref for alloc page - if target { - for i in 0..usize::from(page_size) / FRAME_SIZE { - let page_number = (phy + FRAME_SIZE * i).as_usize() >> FRAME_BITS; - // FRAME_REF_MANAGER.lock().get_ref(page_number); - FRAME_REF_MANAGER.lock().add_ref(page_number); - } - address_space.get_record_mut().insert(v_addr, true); - } - } - } - address_space -} - -pub fn build_elf_address_space( - elf: &[u8], - args: &mut Vec, - name: &str, -) -> Result { - let mut address_space = Sv39PageTable::::try_new().unwrap(); - const ELF_MAGIC: [u8; 4] = [0x7f, b'E', b'L', b'F']; - if elf[0..4] != ELF_MAGIC { - return Err(ELFError::NotELF); - } - let elf = xmas_elf::ElfFile::new(elf).map_err(|_| ELFError::NotELF)?; - // check whether it's a dynamic linked elf - if let Some(inter) = elf - .program_iter() - .find(|ph| ph.get_type().unwrap() == Type::Interp) - { - let data = match inter.get_data(&elf).unwrap() { - SegmentData::Undefined(data) => data, - _ => return Err(ELFError::NoEntrySegment), - }; - let path = core::str::from_utf8(data).unwrap(); - assert!(path.starts_with("/lib/ld-musl-riscv64-sf.so.1")); - let mut new_args = vec!["/libc.so\0".to_string()]; - new_args.extend(args.clone()); - *args = new_args; - // load interpreter - let mut data = vec![]; - warn!("load interpreter: {}, new_args:{:?}", path, args); - if fs::read_all("libc.so", &mut data) { - return build_elf_address_space(&data, args, "libc.so"); - } else { - error!("[map_elf] Found interpreter path: {}", path); - panic!("load interpreter failed"); - } - } - - // calculate bias for dynamic linked elf - // if elf is static linked, bias is 0 - let bias = match elf.header.pt2.type_().as_type() { - // static - xmas_elf::header::Type::Executable => 0, - xmas_elf::header::Type::SharedObject => { - match elf - .program_iter() - .filter(|ph| ph.get_type().unwrap() == Type::Interp) - .count() - { - // It's a loader! - 0 => ELF_BASE_RELOCATE, - // It's a dynamically linked ELF. - 1 => 0, - // Emmm, It has multiple interpreters. - _ => return Err(ELFError::NotSupported), - } - } - _ => return Err(ELFError::NotSupported), - }; - trace!("bias: {:#x}", bias); - - let tls = elf - .program_iter() - .find(|x| x.get_type().unwrap() == Type::Tls) - .map(|ph| ph.virtual_addr()) - .unwrap_or(0); - - warn!("ELF tls: {:#x}", tls); - - let mut break_addr = 0usize; - elf.program_iter() - .filter(|ph| ph.get_type() == Ok(Type::Load)) - .for_each(|ph| { - let start_addr = ph.virtual_addr() as usize + bias; - let end_addr = start_addr + ph.mem_size() as usize; - let mut permission: MappingFlags = "UVAD".into(); - let ph_flags = ph.flags(); - if ph_flags.is_read() { - permission |= MappingFlags::R; - } - if ph_flags.is_write() { - permission |= MappingFlags::W; - } - if ph_flags.is_execute() { - permission |= MappingFlags::X; - } - let vaddr = VirtAddr::from(start_addr).align_down_4k(); - let end_vaddr = VirtAddr::from(end_addr).align_up_4k(); - // 记录程序地址空间的最大地址 - break_addr = end_addr; - let len = end_vaddr.as_usize() - vaddr.as_usize(); - warn!( - "load segment: {:#x} - {:#x} -> {:#x}-{:#x}, permission: {:?}", - start_addr, - end_addr, - vaddr.as_usize(), - end_vaddr.as_usize(), - permission - ); - let mut data = - &elf.input[ph.offset() as usize..(ph.offset() + ph.file_size()) as usize]; - let map_info = address_space - .map_region_no_target(vaddr, len, permission, false, false) - .unwrap(); - // copy data - let mut page_offset = start_addr & (FRAME_SIZE - 1); - let mut count = 0; - map_info - .into_iter() - .for_each(|(_vir, phy, page_size)| unsafe { - let size: usize = page_size.into(); - let min = min(size - page_offset, data.len()); - let dst = (phy.as_usize() + page_offset) as *mut u8; - core::ptr::copy(data.as_ptr(), dst, min); - data = &data[min..]; - count += min; - page_offset = 0; - }); - assert_eq!(count, ph.file_size() as usize); - }); - - // 地址向上取整对齐4 - let ceil_addr = align_up_4k(break_addr + FRAME_SIZE); - // 留出一个用户栈的位置+隔离页 - let top = ceil_addr + USER_STACK_SIZE + FRAME_SIZE; - warn!( - "user stack: {:#x} - {:#x}", - top - USER_STACK_SIZE - FRAME_SIZE, - top - FRAME_SIZE - ); - // map user stack - address_space - .map_region_no_target( - VirtAddr::from(top - USER_STACK_SIZE - FRAME_SIZE), - USER_STACK_SIZE, - "RWUAD".into(), - false, - true, - ) - .unwrap(); - // 初始化一个有效页 - address_space - .validate(VirtAddr::from(top - FRAME_SIZE * 2), "RWUVAD".into()) - .unwrap(); - let heap_bottom = top; - // align to 4k - warn!("trap context: {:#x} - {:#x}", TRAP_CONTEXT_BASE, TRAMPOLINE); - address_space - .map_region_no_target( - VirtAddr::from(TRAP_CONTEXT_BASE), - TRAMPOLINE - TRAP_CONTEXT_BASE, - "RWVAD".into(), - true, - false, - ) - .unwrap(); - warn!( - "TRAMPOLINE: {:#x} - {:#x}", - TRAMPOLINE, - TRAMPOLINE + FRAME_SIZE - ); - address_space - .map_region( - VirtAddr::from(TRAMPOLINE), - PhysAddr::from(strampoline as usize), - FRAME_SIZE, - "RXVAD".into(), - true, - ) - .unwrap(); - - let res = if let Some(phdr) = elf - .program_iter() - .find(|ph| ph.get_type() == Ok(Type::Phdr)) - { - // if phdr exists in program header, use it - Ok(phdr.virtual_addr()) - } else if let Some(elf_addr) = elf - .program_iter() - .find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0) - { - // otherwise, check if elf is loaded from the beginning, then phdr can be inferred. - // Ok(elf_addr.virtual_addr()) - Ok(elf_addr.virtual_addr() + elf.header.pt2.ph_offset()) - } else { - warn!("elf: no phdr found, tls might not work"); - Err(ELFError::NoEntrySegment) - } - .unwrap_or(0); - warn!( - "entry: {:#x}, phdr:{:#x}", - elf.header.pt2.entry_point() + bias as u64, - res + bias as u64 - ); - // relocate if elf is dynamically linked - if let Ok(kvs) = elf.relocate(bias) { - kvs.into_iter().for_each(|kv| { - trace!("relocate: {:#x} -> {:#x}", kv.0, kv.1); - let (addr, ..) = address_space.query(VirtAddr::from(kv.0)).unwrap(); - unsafe { (addr.as_usize() as *mut usize).write(kv.1) } - }) - } - Ok(ELFInfo { - address_space, - entry: elf.header.pt2.entry_point() as usize + bias, - stack_top: top - FRAME_SIZE, - heap_bottom, - ph_num: elf.header.pt2.ph_count() as usize, - ph_entry_size: elf.header.pt2.ph_entry_size() as usize, - ph_drift: res as usize + bias, - tls: tls as usize, - bias, - name: name.to_string(), - }) -} +use crate::fs; +use crate::ipc::ShmInfo; +use crate::mm::elf::{ELFError, ELFInfo, ELFReader}; +use crate::trap::TrapFrame; +use alloc::collections::BTreeMap; +use alloc::string::{String, ToString}; +use alloc::vec; +use alloc::vec::Vec; +use config::*; +use core::cmp::min; +use core::fmt::Debug; +use mem::{VmmPageAllocator, FRAME_REF_MANAGER}; +use page_table::addr::{align_up_4k, PhysAddr, VirtAddr}; +use page_table::pte::MappingFlags; +use page_table::table::Sv39PageTable; +use xmas_elf::program::{SegmentData, Type}; + +extern "C" { + fn strampoline(); +} +#[derive(Debug)] +pub struct UserStack { + pub virt_stack_top: usize, + pub stack_top: usize, + pub stack_bottom: usize, +} + +impl UserStack { + pub fn new(phy_stack_top: usize, virt_stack_top: usize) -> Self { + Self { + virt_stack_top, + stack_top: phy_stack_top, + stack_bottom: phy_stack_top - FRAME_SIZE, + } + } + pub fn push(&mut self, data: usize) -> Result { + if self.stack_top - 8 < self.stack_bottom { + return Err("Stack Overflow"); + } + unsafe { + self.stack_top -= 8; + *(self.stack_top as *mut usize) = data; + } + trace!( + "stack top: {:#x}, data:{:#x?}", + self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom)), + data + ); + Ok(self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom))) + } + + pub fn push_str(&mut self, data: &str) -> Result { + self.push_bytes(data.as_bytes()) + } + + pub fn push_bytes(&mut self, data: &[u8]) -> Result { + let len = data.len(); + // align 8 + let start = self.stack_top - len; + let start = start & !7; + if start < self.stack_bottom { + return Err("Stack Overflow"); + } + unsafe { + self.stack_top = start; + let ptr = self.stack_top as *mut u8; + ptr.copy_from_nonoverlapping(data.as_ptr(), len); + } + trace!( + "stack top: {:#x}", + self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom)) + ); + Ok(self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom))) + } + + pub fn align_to(&mut self, align: usize) -> Result { + let start = self.stack_top & !(align - 1); + if start < self.stack_bottom { + return Err("Stack Overflow"); + } + self.stack_top = start; + Ok(self.virt_stack_top - (FRAME_SIZE - (self.stack_top - self.stack_bottom))) + } +} + +pub fn build_thread_address_space( + table: &mut Sv39PageTable, + thread_num_within: usize, +) -> &'static mut TrapFrame { + let address = TRAP_CONTEXT_BASE - FRAME_SIZE * thread_num_within; + let (_virt_dst, phy_dst, _) = table + .map_region_no_target( + VirtAddr::from(address), + FRAME_SIZE, + "RWVAD".into(), + true, + false, + ) + .unwrap() + .next() + .unwrap(); + // copy data + // find the + let (phy, _flag, page_size) = table.query(VirtAddr::from(TRAP_CONTEXT_BASE)).unwrap(); + assert_eq!(usize::from(page_size), FRAME_SIZE); + // copy data + let src_ptr = phy.as_usize() as *const u8; + let dst_ptr = phy_dst.as_usize() as *mut u8; + unsafe { + core::ptr::copy(src_ptr, dst_ptr, usize::from(page_size)); + } + TrapFrame::from_raw_ptr(dst_ptr as *mut TrapFrame) +} + +pub fn build_cow_address_space( + p_table: &mut Sv39PageTable, + shm: BTreeMap, +) -> Sv39PageTable { + let mut address_space = Sv39PageTable::::try_new().unwrap(); + for (v_addr, target) in p_table.get_record().into_iter() { + trace!("v_addr: {:?}, target: {}", v_addr, target); + let (phy, flag, page_size) = p_table.query(v_addr).unwrap(); + + // shm should remap, we can't use cow for it + let is_in_segs = |addr: usize| -> bool { + for (_id, shminfo) in shm.iter() { + if addr >= shminfo.start_va && addr < shminfo.end_va { + return true; + } + } + false + }; + + if v_addr.as_usize() == TRAP_CONTEXT_BASE { + // for Trap_context, we remap it + assert_eq!(usize::from(page_size), TRAMPOLINE - TRAP_CONTEXT_BASE); + let dst = address_space + .map_no_target(v_addr, page_size, flag, false) + .unwrap(); + // copy data + let src_ptr = phy.as_usize() as *const u8; + let dst_ptr = dst.as_usize() as *mut u8; + unsafe { + core::ptr::copy(src_ptr, dst_ptr, usize::from(page_size)); + } + } else if is_in_segs(v_addr.as_usize()) { + // for shm, we now skip it + address_space.map(v_addr, phy, page_size, flag).unwrap(); + } else { + // cow + // checkout whether pte flags has `W` flag + let mut flags = flag.clone(); + if !flag.contains(MappingFlags::V) { + // if flags is not valid, we just map it + address_space.map(v_addr, phy, page_size, flags).unwrap(); + if target { + address_space.get_record_mut().insert(v_addr, true); + } + continue; + } + if flag.contains(MappingFlags::W) { + flags -= MappingFlags::W; + flags |= MappingFlags::RSD; // we use the RSD flag to indicate that this page is a cow page + // update parent's flag and clear dirty + p_table.modify_pte_flags(v_addr, flags, false).unwrap(); + } + address_space.map(v_addr, phy, page_size, flags).unwrap(); + // add ref for alloc page + if target { + for i in 0..usize::from(page_size) / FRAME_SIZE { + let page_number = (phy + FRAME_SIZE * i).as_usize() >> FRAME_BITS; + // FRAME_REF_MANAGER.lock().get_ref(page_number); + FRAME_REF_MANAGER.lock().add_ref(page_number); + } + address_space.get_record_mut().insert(v_addr, true); + } + } + } + address_space +} + +pub fn build_elf_address_space( + elf: &[u8], + args: &mut Vec, + name: &str, +) -> Result { + let mut address_space = Sv39PageTable::::try_new().unwrap(); + const ELF_MAGIC: [u8; 4] = [0x7f, b'E', b'L', b'F']; + if elf[0..4] != ELF_MAGIC { + return Err(ELFError::NotELF); + } + let elf = xmas_elf::ElfFile::new(elf).map_err(|_| ELFError::NotELF)?; + // check whether it's a dynamic linked elf + if let Some(inter) = elf + .program_iter() + .find(|ph| ph.get_type().unwrap() == Type::Interp) + { + let data = match inter.get_data(&elf).unwrap() { + SegmentData::Undefined(data) => data, + _ => return Err(ELFError::NoEntrySegment), + }; + let path = core::str::from_utf8(data).unwrap(); + assert!(path.starts_with("/lib/ld-musl-riscv64-sf.so.1")); + let mut new_args = vec!["/libc.so\0".to_string()]; + new_args.extend(args.clone()); + *args = new_args; + // load interpreter + let mut data = vec![]; + warn!("load interpreter: {}, new_args:{:?}", path, args); + if fs::read_all("libc.so", &mut data) { + return build_elf_address_space(&data, args, "libc.so"); + } else { + error!("[map_elf] Found interpreter path: {}", path); + panic!("load interpreter failed"); + } + } + + // calculate bias for dynamic linked elf + // if elf is static linked, bias is 0 + let bias = match elf.header.pt2.type_().as_type() { + // static + xmas_elf::header::Type::Executable => 0, + xmas_elf::header::Type::SharedObject => { + match elf + .program_iter() + .filter(|ph| ph.get_type().unwrap() == Type::Interp) + .count() + { + // It's a loader! + 0 => ELF_BASE_RELOCATE, + // It's a dynamically linked ELF. + 1 => 0, + // Emmm, It has multiple interpreters. + _ => return Err(ELFError::NotSupported), + } + } + _ => return Err(ELFError::NotSupported), + }; + trace!("bias: {:#x}", bias); + + let tls = elf + .program_iter() + .find(|x| x.get_type().unwrap() == Type::Tls) + .map(|ph| ph.virtual_addr()) + .unwrap_or(0); + + warn!("ELF tls: {:#x}", tls); + + let mut break_addr = 0usize; + elf.program_iter() + .filter(|ph| ph.get_type() == Ok(Type::Load)) + .for_each(|ph| { + let start_addr = ph.virtual_addr() as usize + bias; + let end_addr = start_addr + ph.mem_size() as usize; + let mut permission: MappingFlags = "UVAD".into(); + let ph_flags = ph.flags(); + if ph_flags.is_read() { + permission |= MappingFlags::R; + } + if ph_flags.is_write() { + permission |= MappingFlags::W; + } + if ph_flags.is_execute() { + permission |= MappingFlags::X; + } + let vaddr = VirtAddr::from(start_addr).align_down_4k(); + let end_vaddr = VirtAddr::from(end_addr).align_up_4k(); + // 记录程序地址空间的最大地址 + break_addr = end_addr; + let len = end_vaddr.as_usize() - vaddr.as_usize(); + warn!( + "load segment: {:#x} - {:#x} -> {:#x}-{:#x}, permission: {:?}", + start_addr, + end_addr, + vaddr.as_usize(), + end_vaddr.as_usize(), + permission + ); + let mut data = + &elf.input[ph.offset() as usize..(ph.offset() + ph.file_size()) as usize]; + let map_info = address_space + .map_region_no_target(vaddr, len, permission, false, false) + .unwrap(); + // copy data + let mut page_offset = start_addr & (FRAME_SIZE - 1); + let mut count = 0; + map_info + .into_iter() + .for_each(|(_vir, phy, page_size)| unsafe { + let size: usize = page_size.into(); + let min = min(size - page_offset, data.len()); + let dst = (phy.as_usize() + page_offset) as *mut u8; + core::ptr::copy(data.as_ptr(), dst, min); + data = &data[min..]; + count += min; + page_offset = 0; + }); + assert_eq!(count, ph.file_size() as usize); + }); + + // 地址向上取整对齐4 + let ceil_addr = align_up_4k(break_addr + FRAME_SIZE); + // 留出一个用户栈的位置+隔离页 + let top = ceil_addr + USER_STACK_SIZE + FRAME_SIZE; + warn!( + "user stack: {:#x} - {:#x}", + top - USER_STACK_SIZE - FRAME_SIZE, + top - FRAME_SIZE + ); + // map user stack + address_space + .map_region_no_target( + VirtAddr::from(top - USER_STACK_SIZE - FRAME_SIZE), + USER_STACK_SIZE, + "RWUAD".into(), + false, + true, + ) + .unwrap(); + // 初始化一个有效页 + address_space + .validate(VirtAddr::from(top - FRAME_SIZE * 2), "RWUVAD".into()) + .unwrap(); + let heap_bottom = top; + // align to 4k + warn!("trap context: {:#x} - {:#x}", TRAP_CONTEXT_BASE, TRAMPOLINE); + address_space + .map_region_no_target( + VirtAddr::from(TRAP_CONTEXT_BASE), + TRAMPOLINE - TRAP_CONTEXT_BASE, + "RWVAD".into(), + true, + false, + ) + .unwrap(); + warn!( + "TRAMPOLINE: {:#x} - {:#x}", + TRAMPOLINE, + TRAMPOLINE + FRAME_SIZE + ); + address_space + .map_region( + VirtAddr::from(TRAMPOLINE), + PhysAddr::from(strampoline as usize), + FRAME_SIZE, + "RXVAD".into(), + true, + ) + .unwrap(); + + let res = if let Some(phdr) = elf + .program_iter() + .find(|ph| ph.get_type() == Ok(Type::Phdr)) + { + // if phdr exists in program header, use it + Ok(phdr.virtual_addr()) + } else if let Some(elf_addr) = elf + .program_iter() + .find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0) + { + // otherwise, check if elf is loaded from the beginning, then phdr can be inferred. + // Ok(elf_addr.virtual_addr()) + Ok(elf_addr.virtual_addr() + elf.header.pt2.ph_offset()) + } else { + warn!("elf: no phdr found, tls might not work"); + Err(ELFError::NoEntrySegment) + } + .unwrap_or(0); + warn!( + "entry: {:#x}, phdr:{:#x}", + elf.header.pt2.entry_point() + bias as u64, + res + bias as u64 + ); + // relocate if elf is dynamically linked + if let Ok(kvs) = elf.relocate(bias) { + kvs.into_iter().for_each(|kv| { + trace!("relocate: {:#x} -> {:#x}", kv.0, kv.1); + let (addr, ..) = address_space.query(VirtAddr::from(kv.0)).unwrap(); + unsafe { (addr.as_usize() as *mut usize).write(kv.1) } + }) + } + Ok(ELFInfo { + address_space, + entry: elf.header.pt2.entry_point() as usize + bias, + stack_top: top - FRAME_SIZE, + heap_bottom, + ph_num: elf.header.pt2.ph_count() as usize, + ph_entry_size: elf.header.pt2.ph_entry_size() as usize, + ph_drift: res as usize + bias, + tls: tls as usize, + bias, + name: name.to_string(), + }) +} diff --git a/kkernel/src/mm/map.rs b/kernel/src/mm/map.rs similarity index 99% rename from kkernel/src/mm/map.rs rename to kernel/src/mm/map.rs index 85b77fa0..c79ffe91 100644 --- a/kkernel/src/mm/map.rs +++ b/kernel/src/mm/map.rs @@ -6,14 +6,13 @@ use bitflags::bitflags; use page_table::addr::{align_up_4k, VirtAddr}; use page_table::pte::MappingFlags; +use crate::task::current_task; +use config::{FRAME_SIZE, PROCESS_HEAP_MAX}; use constants::io::MapFlags; +use constants::AlienResult; use constants::LinuxErrno; use syscall_table::syscall_func; - -use config::{FRAME_SIZE, PROCESS_HEAP_MAX}; -use crate::fs::file::File; -use crate::task::current_task; -use constants::AlienResult; +use vfs::kfile::File; bitflags! { pub struct ProtFlags: u32 { diff --git a/kkernel/src/mm/mod.rs b/kernel/src/mm/mod.rs similarity index 92% rename from kkernel/src/mm/mod.rs rename to kernel/src/mm/mod.rs index 27020c21..660a1c28 100644 --- a/kkernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -1,20 +1,19 @@ -use arch::hart_id; - -pub mod map; -pub mod elf; -pub mod loader; - - -/// This function will be call in slab allocator -#[no_mangle] -fn current_cpu_id() -> usize { - hart_id() -} - -/// (待实现)在一组线程中,设置内存屏障,控制多核系统中的内存访问次序。目前直接返回0。 -/// -/// -#[syscall_func(283)] -pub fn membarrier() -> isize { - 0 -} +use arch::hart_id; + +pub mod elf; +pub mod loader; +pub mod map; + +/// This function will be call in slab allocator +#[no_mangle] +fn current_cpu_id() -> usize { + hart_id() +} + +/// (待实现)在一组线程中,设置内存屏障,控制多核系统中的内存访问次序。目前直接返回0。 +/// +/// +#[syscall_func(283)] +pub fn membarrier() -> isize { + 0 +} diff --git a/kernel/src/net/addr.rs b/kernel/src/net/addr.rs index db9deb7e..421670ed 100644 --- a/kernel/src/net/addr.rs +++ b/kernel/src/net/addr.rs @@ -1,92 +1,10 @@ -//! 在 Alien 内核中使用的 socket 套接字地址结构。 -//! -//! Alien 中目前能够接收的套接字地址种类包括本地路径地址和网络套接字地址。 -//! 对于从用户端传来的套接字地址,类似于 `linux` 中 `socket.h` 的套接字地址。 -//! 大致结构如下: -//! + 2字节表明该套接字使用的地址协议族 -//! + 2字节表明该套接字的端口 -//! + 12字节的地址数据 -//! -//! Alien 将会首先对传入的套接字的协议族进行解析,然后根据不同的地址协议族将其解析成 [`SocketAddrExt`] 结构, -//! 向下层的具体套接字中传递相应地址时,传递的也是 [`SocketAddrExt`] 结构。 -//! +use crate::task::current_task; use alloc::string::{String, ToString}; use alloc::vec; -use core::fmt::Debug; -use core::net::{IpAddr, Ipv4Addr, SocketAddr}; - -use crate::task::current_task; use constants::net::Domain; -use constants::AlienResult; -use constants::LinuxErrno; - -/// 用于存储套接字通信地址的结构,分为本地路径地址和网络套接字地址。 -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -pub enum SocketAddrExt { - LocalPath(String), - SocketAddr(SocketAddr), -} - -/// 用于存储一个Ipv4套接字相关信息的结构。对应 `linux` 中 `socket.h` 的 `sockaddr_in` 结构。 -/// -/// 在 socket 相关系统调用中,一般都先分析出套接字采用的地址协议族,如果是 `IPV4` 则会将传入的套接字相关信息解析成 `RawIpV4Addr`。 -/// 且 `Alien` 目前默认使用网络套接字时,即采用 `IPV4` 协议。 -#[repr(C)] -#[derive(Debug, Clone, Copy, Default)] -pub struct RawIpV4Addr { - /// 地址协议族 - pub family: u16, - /// Ipv4 的端口 - pub port: u16, - /// Ipv4 的地址 - pub addr: u32, - /// 零位,用于后续扩展 - pub zero: [u8; 8], -} - -impl SocketAddrExt { - /// 获取网络套接字地址。当本结构中存储的是本地路径地址时,将导致 panic。 - pub fn get_socketaddr(&self) -> SocketAddr { - match self { - SocketAddrExt::LocalPath(_) => { - panic!("Can't get socketaddr from local path") - } - SocketAddrExt::SocketAddr(addr) => *addr, - } - } - - /// 获取本地路径地址。当本结构中存储的是网络套接字地址时,将导致 panic。 - pub fn get_local_path(&self) -> String { - match self { - SocketAddrExt::LocalPath(path) => path.clone(), - SocketAddrExt::SocketAddr(_) => { - panic!("Can't get local path from socketaddr") - } - } - } -} - -impl From for RawIpV4Addr { - /// 用一个 [`SocketAddr`] 结构 初始化 `RawIpV4Addr ` - fn from(addr: SocketAddr) -> Self { - let ip = addr.ip(); - let port = addr.port(); - let ip = match ip { - IpAddr::V4(ip) => ip, - IpAddr::V6(_) => { - panic!("ipv6 is not supported") - } - }; - let ip = ip.octets(); - let ip = u32::from_le_bytes(ip); - Self { - family: Domain::AF_INET as u16, - port: port.to_be(), - addr: ip, - zero: [0u8; 8], - } - } -} +use constants::{AlienResult, LinuxErrno}; +use core::net::{IpAddr, Ipv4Addr, SocketAddr}; +use knet::addr::{RawIpV4Addr, SocketAddrExt}; /// 地址解析,将根据`family_user_addr`的[`Domain`]类型分类进行解析。 /// diff --git a/kernel/src/net/mod.rs b/kernel/src/net/mod.rs index 992d1a26..a4de7c2c 100644 --- a/kernel/src/net/mod.rs +++ b/kernel/src/net/mod.rs @@ -5,23 +5,19 @@ //! [`socket`] 子模块指明了Alien 内核中使用的套接字。 //! [`unix`] 子模块指明了有关 Unix 协议族下的套接字结构。(目前有关的功能有待支持) //! -use crate::fs::file::File; -use crate::net::addr::{socket_addr_resolution, RawIpV4Addr}; -use crate::net::socket::{SocketData, SocketFile, SocketFileExt}; +use crate::net::addr::socket_addr_resolution; use crate::task::{current_task, do_suspend}; use alloc::sync::Arc; use alloc::vec; use alloc::vec::Vec; use constants::io::OpenFlags; use constants::net::*; -use constants::AlienResult; -use constants::LinuxErrno; -use syscall_table::syscall_func; +use constants::{AlienResult, LinuxErrno}; +use knet::addr::RawIpV4Addr; +use knet::socket::{SocketData, SocketFile, SocketFileExt}; +use vfs::kfile::File; pub mod addr; -pub mod port; -pub mod socket; -mod unix; /// 一个系统调用,用于创建一个未绑定的socket套接字。 /// diff --git a/kernel/src/net/socket.rs b/kernel/src/net/socket.rs deleted file mode 100644 index 433b2b72..00000000 --- a/kernel/src/net/socket.rs +++ /dev/null @@ -1,470 +0,0 @@ -//! Alien 内核中使用的套接字结构。 -//! -//! Alien 目前采用 [`SocketData`] 存储每一个套接字的相关信息,其字段 socket (结构为 [`Socket`]) 存储套接字的具体信息, -//! 对于套接字的操作最终都会归结于对 [`SocketData`] 的操作。 -//! -//! 套接字的创建时,需要返回一个创建的套接字文件描述符用于获取和操作该套接字。依据 Alien 所使用的 rvfs 中对文件 `File` -//! 的规定,我们只需为套接字文件规定好 [`socket_file_release`]、[`socket_file_write`]、[`socket_file_read`]、 -//! [`socket_ready_to_read`]、[`socket_ready_to_write`] 几个操作函数,即可快速的创建套接字文件,并将其放入进程的文件描述 -//! 符表中,具体有关套接字文件的创建,可见 [`SocketData::new`] 的实现。 -use super::ShutdownFlag; -use crate::fs::file::File; -use crate::net::addr::SocketAddrExt; -use crate::net::port::neterror2alien; -use crate::net::unix::UnixSocket; -use constants::AlienResult; -use ksync::{Mutex, MutexGuard}; -// use crate::task::do_suspend; -use alloc::boxed::Box; -use alloc::sync::Arc; -use constants::io::{OpenFlags, PollEvents, SeekFrom}; -use constants::net::{Domain, SocketType}; -use constants::LinuxErrno; -use core::fmt::{Debug, Formatter}; -use core::net::SocketAddr; -use netcore::tcp::TcpSocket; -use netcore::udp::UdpSocket; -use vfscore::dentry::VfsDentry; -use vfscore::inode::VfsInode; -use vfscore::utils::VfsFileStat; - -// Only for simplify the modification of the old code -pub trait SocketFileExt { - fn get_socketdata(&self) -> AlienResult>>; -} - -pub struct SocketFile { - open_flag: Mutex, - node: Mutex>, -} - -impl Debug for SocketFile { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("SocketFile") - .field("open_flag", &self.open_flag) - .field("node", &self.node) - .finish() - } -} - -impl SocketFile { - pub fn new(socket_data: SocketData) -> Self { - Self { - open_flag: Mutex::new(OpenFlags::O_RDWR), - node: Mutex::new(Box::new(socket_data)), - } - } - - pub fn set_close_on_exec(&self) { - *self.open_flag.lock() |= OpenFlags::O_CLOEXEC; - } -} - -impl SocketFileExt for SocketFile { - fn get_socketdata(&self) -> AlienResult>> { - let r = self.node.lock(); - Ok(r) - } -} - -impl File for SocketFile { - fn read(&self, buf: &mut [u8]) -> AlienResult { - if buf.len() == 0 { - return Ok(0); - } - netcore::poll_interfaces(); - let socket = self.get_socketdata().unwrap(); - let res = socket.recvfrom(buf, 0).map(|x| x.0).map_err(|x| { - info!("socket_file_read: {:?}", x); - x - }); - info!("socket_file_read: {:?}, indeed {:?}", buf.len(), res); - res - } - - fn write(&self, buf: &[u8]) -> AlienResult { - if buf.len() == 0 { - return Ok(0); - } - info!("socket_file_write: buf_len:{:?}", buf.len()); - netcore::poll_interfaces(); - let socket = self.get_socketdata().unwrap(); - let res = socket.send_to(buf, 0, None).map_err(|x| { - info!("socket_file_write: {:?}", x); - x - }); - // do_suspend(); - res - } - - fn seek(&self, _pos: SeekFrom) -> AlienResult { - Err(LinuxErrno::ESPIPE) - } - - fn get_attr(&self) -> AlienResult { - Err(LinuxErrno::ENOSYS) - } - - fn set_open_flag(&self, flag: OpenFlags) { - *self.open_flag.lock() = flag; - } - - fn get_open_flag(&self) -> OpenFlags { - *self.open_flag.lock() - } - - fn dentry(&self) -> Arc { - panic!("dentry in socket file is not supported") - } - - fn inode(&self) -> Arc { - panic!("inode in socket file is not supported") - } - - fn is_readable(&self) -> bool { - true - } - - fn is_writable(&self) -> bool { - true - } - fn is_append(&self) -> bool { - false - } - fn poll(&self, _event: PollEvents) -> AlienResult { - let mut res = PollEvents::empty(); - netcore::poll_interfaces(); - let socket = self.get_socketdata().unwrap(); - if _event.contains(PollEvents::IN) { - if socket.ready_read() { - res |= PollEvents::IN; - } - } - if _event.contains(PollEvents::OUT) { - if socket.ready_write() { - res |= PollEvents::OUT; - } - } - Ok(res) - } -} - -/// Alien 内核中对于每一个套接字所存储的相关信息。所有系统调用最后都要归到该结构的操作。 -#[derive(Debug)] -pub struct SocketData { - /// socket 通信域 - pub domain: Domain, - /// 连接类型 - pub s_type: SocketType, - /// 具体的通信协议 - pub protocol: usize, - /// 具体的套接字数据,具体可见 [`Socket`] - pub socket: Socket, -} - -/// 用于记录一个套接字的具体数据。 -/// -/// 针对套接字类型,`Tcp` 和 `Udp` 类型中存储的具体数据是 `simple_net` 中的 [`TcpSocket`] 和 [`UdpSocket`] 类型; -/// `Unix` 类型中存储的数据是 [`UnixSocket`]。 -pub enum Socket { - Tcp(TcpSocket), - Udp(UdpSocket), - Unix(UnixSocket), - None, -} - -impl Debug for Socket { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - match self { - Socket::Tcp(_) => { - write!(f, "Tcp") - } - Socket::Udp(_) => { - write!(f, "Udp") - } - Socket::None => { - write!(f, "None") - } - Socket::Unix(_) => { - write!(f, "Unix") - } - } - } -} - -impl SocketData { - /// 用于创建一个新的套接字数据 `SocketData` 结构,返回创建的文件描述符。一般被系统调用 [`socket`] 所调用。 - /// - /// 执行过程中会创建一个对应的套接字文件,打开后将对应的文件描述符放入进程的文件描述符表中, - /// 对于 `Alien` 中对文件的相关定义可见 `rvfs` 模块中的 `File` 结构。这里对套接字文件的相关 - /// 操作函数可见 [`socket_file_release`]、[`socket_file_write`]、[`socket_file_read`]、 - /// [`socket_ready_to_read`]、[`socket_ready_to_write`]。 - pub fn new( - domain: Domain, - s_type: SocketType, - protocol: usize, - ) -> AlienResult> { - let raw_socket = match domain { - Domain::AF_UNIX => { - error!("AF_UNIX is not supported"); - Socket::Unix(UnixSocket::new()) - } - Domain::AF_INET => match s_type { - SocketType::SOCK_STREAM => Socket::Tcp(TcpSocket::new()), - SocketType::SOCK_DGRAM => Socket::Udp(UdpSocket::new()), - _ => { - error!("unsupported socket type: {:?}", s_type); - return Err(LinuxErrno::EPROTONOSUPPORT.into()); - } - }, - }; - let socket_data = Self { - domain, - s_type, - protocol, - socket: raw_socket, - }; - Ok(Arc::new(SocketFile::new(socket_data))) - } - /// 用于对一个已经存在的 tcp_socket 创建对应的套接字文件。一般在 accept 成功接受一个 client 后被调用。 - fn new_connected(&self, tcp_socket: TcpSocket) -> Arc { - let socket_data = Self { - domain: self.domain, - s_type: self.s_type, - protocol: self.protocol, - socket: Socket::Tcp(tcp_socket), - }; - Arc::new(SocketFile::new(socket_data)) - } - - /// 返回套接字的类型 - pub fn socket_type(&self) -> SocketType { - self.s_type - } - - /// 设置套接字的阻塞状态。用于传入 SOCK_NONBLOCK 标志位的套接字创建过程中。 - pub fn set_socket_nonblock(&self, blocking: bool) { - match &self.socket { - Socket::Tcp(tcp) => { - tcp.set_nonblocking(blocking); - } - Socket::Udp(udp) => { - udp.set_nonblocking(blocking); - } - _ => { - panic!("set_socket_nonblock is not supported") - } - } - } - - /// 用于绑定套接字端口,tcp 和 udp 可用。被系统调用 [`bind`] 调用。 - pub fn bind(&self, socket_addr: SocketAddrExt) -> AlienResult<()> { - match &self.socket { - Socket::Tcp(tcp) => { - tcp.bind(socket_addr.get_socketaddr()) - .map_err(neterror2alien)?; - } - Socket::Udp(udp) => { - udp.bind(socket_addr.get_socketaddr()) - .map_err(neterror2alien)?; - } - _ => { - panic!("bind is not supported") - } - } - Ok(()) - } - - /// 用于处理一个 client 的连接请求,仅限于 Tcp 套接字。被系统调用 [`accept`] 调用。 - /// - /// 如果该套接字不是 Tcp 套接字,将直接返回 Err。 - pub fn accept(&self) -> AlienResult> { - match &self.socket { - Socket::Tcp(tcp) => tcp - .accept() - .map(|socket| Ok(self.new_connected(socket))) - .map_err(neterror2alien)?, - _ => Err(LinuxErrno::EOPNOTSUPP.into()), - } - } - - /// 用于监听一个端口,仅限于 Tcp 套接字。被系统调用 [`listening`] 调用。 - /// - /// 如果该套接字不是 Tcp 套接字,将直接返回 Err。 - pub fn listening(&self, _back_log: usize) -> AlienResult<()> { - match &self.socket { - Socket::Tcp(tcp) => tcp.listen().map_err(neterror2alien), - _ => Err(LinuxErrno::EOPNOTSUPP.into()), - } - } - - /// 用于连接一个套接字。被系统调用 [`connect`] 调用。 - pub fn connect(&self, ip: SocketAddrExt) -> AlienResult<()> { - match &self.socket { - Socket::Tcp(tcp) => { - tcp.connect(ip.get_socketaddr()).map_err(neterror2alien)?; - } - Socket::Udp(udp) => { - udp.connect(ip.get_socketaddr()).map_err(neterror2alien)?; - } - Socket::Unix(unix) => unix.connect(ip.get_local_path())?, - _ => { - panic!("bind is not supported") - } - } - Ok(()) - } - - /// 用于向一个套接字中发送消息。发送成功则返回发送的消息长度。被系统调用 [`sendto`] 调用。 - pub fn send_to( - &self, - message: &[u8], - _flags: usize, - dest_addr: Option, - ) -> AlienResult { - match &self.socket { - Socket::Tcp(tcp) => tcp.send(message).map_err(|x| neterror2alien(x)), - Socket::Udp(udp) => { - if let Some(dest_addr) = dest_addr { - udp.send_to(message, dest_addr.get_socketaddr()) - .map_err(neterror2alien) - } else { - udp.send(message).map_err(neterror2alien) - } - } - _ => { - panic!("bind is not supported") - } - } - } - - /// 用于从一个套接字中接收消息,接收成功则返回接受的消息长度。被系统调用 [`recvfrom`] 调用。 - pub fn recvfrom(&self, message: &mut [u8], _flags: usize) -> AlienResult<(usize, SocketAddr)> { - match &self.socket { - Socket::Tcp(tcp) => { - let recv = tcp.recv(message).map_err(neterror2alien)?; - let peer_addr = tcp.peer_addr().map_err(neterror2alien)?; - Ok((recv, peer_addr)) - } - Socket::Udp(udp) => { - let recv = udp.recv_from(message).map_err(neterror2alien)?; - // let peer_addr = udp.peer_addr().map_err(neterror2linux)?; - Ok((recv.0, recv.1)) - } - _ => { - panic!("bind is not supported") - } - } - } - - /// 用于关闭套接字的读功能或写功能。被系统调用 [`shutdown`] 调用。 - pub fn shutdown(&self, _sdflag: ShutdownFlag) -> AlienResult<()> { - match &self.socket { - Socket::Tcp(tcp) => tcp.shutdown().map_err(neterror2alien), - Socket::Udp(udp) => udp.shutdown().map_err(neterror2alien), - _ => { - panic!("bind is not supported") - } - } - } - - /// 用于获取当前套接字绑定的本地套接字地址信息。 - pub fn local_addr(&self) -> Option { - match &self.socket { - Socket::Tcp(tcp) => { - let local_addr = tcp.local_addr(); - if let Ok(addr) = local_addr { - Some(addr) - } else { - None - } - } - Socket::Udp(udp) => { - let local_addr = udp.local_addr(); - if let Ok(addr) = local_addr { - Some(addr) - } else { - None - } - } - _ => None, - } - } - - /// 用于获取当前套接字连接的远程服务器的套接字地址信息。 - pub fn peer_addr(&self) -> Option { - match &self.socket { - Socket::Tcp(tcp) => { - let peer_addr = tcp.peer_addr(); - if let Ok(addr) = peer_addr { - Some(addr) - } else { - None - } - } - Socket::Udp(udp) => { - let peer_addr = udp.peer_addr(); - if let Ok(addr) = peer_addr { - Some(addr) - } else { - None - } - } - _ => { - panic!("bind is not supported") - } - } - } - - /// 用于获取当前套接字是否有消息需要接收。 - pub fn ready_read(&self) -> bool { - match &self.socket { - Socket::Tcp(tcp) => { - let res = tcp.poll(); - info!("Tcp ready_read: {:?}", res); - if let Ok(res) = res { - res.readable - } else { - false - } - } - Socket::Udp(udp) => { - let res = udp.poll(); - info!("Udp ready_read: {:?}", res); - if let Ok(res) = res { - res.readable - } else { - false - } - } - _ => { - panic!("bind is not supported") - } - } - } - - ///用于获取当前套接字是否有消息需要发送。 - pub fn ready_write(&self) -> bool { - match &self.socket { - Socket::Tcp(tcp) => { - let res = tcp.poll(); - if let Ok(res) = res { - res.writable - } else { - false - } - } - Socket::Udp(udp) => { - let res = udp.poll(); - if let Ok(res) = res { - res.writable - } else { - false - } - } - _ => { - panic!("bind is not supported") - } - } - } -} diff --git a/kernel/src/net/unix.rs b/kernel/src/net/unix.rs deleted file mode 100644 index 5ff469d9..00000000 --- a/kernel/src/net/unix.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! 有关 Unix 协议族下的套接字结构。(目前有关的功能有待支持) -use alloc::string::String; -use alloc::sync::Arc; -use constants::LinuxErrno; - -use crate::fs::file::File; -use ksync::Mutex; - -/// Unix 协议族下的套接字结构 -#[allow(unused)] -pub struct UnixSocket { - /// 文件路径,即套接字地址 - file_path: Mutex>, - /// 套接字数据 - file: Mutex>>, -} - -impl UnixSocket { - /// 创建一个新的 Unix 协议族下的套接字结构 - pub fn new() -> Self { - Self { - file_path: Mutex::new(None), - file: Mutex::new(None), - } - } - - /// UnixSocket 的 connect 操作 - pub fn connect(&self, _file_path: String) -> Result<(), LinuxErrno> { - Err(LinuxErrno::ENOENT) - } -} diff --git a/kernel/src/panic.rs b/kernel/src/panic.rs deleted file mode 100644 index e2c2a26b..00000000 --- a/kernel/src/panic.rs +++ /dev/null @@ -1,91 +0,0 @@ -//! panic 处理 -use crate::sbi::system_shutdown; -use crate::trace::find_symbol_with_addr; -use core::panic::PanicInfo; -use core::sync::atomic::AtomicBool; -#[cfg(all(not(feature = "debug-eh-frame"), not(feature = "debug-frame-point")))] -use tracer::CompilerTracer; -#[cfg(feature = "debug-eh-frame")] -use tracer::DwarfTracer; -#[cfg(feature = "debug-frame-point")] -use tracer::FramePointTracer; -use tracer::{Tracer, TracerProvider}; -/// 递归标志 -static RECURSION: AtomicBool = AtomicBool::new(false); - -/// 错误处理 -/// -/// 发生 panic 是进行结果处理.目前我们会读取符号表信息,进行堆栈回溯 -#[panic_handler] -fn panic_handler(info: &PanicInfo) -> ! { - if let Some(p) = info.location() { - mprintln!( - "line {}, file {}: {}", - p.line(), - p.file(), - info.message().unwrap() - ); - } else { - mprintln!("no location information available"); - } - if !RECURSION.swap(true, core::sync::atomic::Ordering::SeqCst) { - back_trace(); - } - mprintln!("!TEST FINISH!"); - system_shutdown(); - loop {} -} - -#[derive(Clone)] -struct TracerProviderImpl; -impl TracerProvider for TracerProviderImpl { - fn address2symbol(&self, addr: usize) -> Option<(usize, &'static str)> { - warn!("address2symbol: {:#x}", addr); - find_symbol_with_addr(addr) - } -} - -#[cfg(feature = "debug-eh-frame")] -extern "C" { - fn kernel_eh_frame(); - fn kernel_eh_frame_end(); - fn kernel_eh_frame_hdr(); - fn kernel_eh_frame_hdr_end(); -} - -#[cfg(feature = "debug-eh-frame")] -struct DwarfProviderImpl; - -#[cfg(feature = "debug-eh-frame")] -impl DwarfProvider for DwarfProviderImpl { - fn kernel_eh_frame_hdr(&self) -> usize { - kernel_eh_frame_hdr as usize - } - - fn kernel_eh_frame(&self) -> usize { - kernel_eh_frame as usize - } - - fn kernel_eh_frame_hdr_end(&self) -> usize { - kernel_eh_frame_hdr_end as usize - } - - fn kernel_eh_frame_end(&self) -> usize { - kernel_eh_frame_end as usize - } -} - -/// 打印堆栈回溯信息 -fn back_trace() { - println!("---START BACKTRACE---"); - #[cfg(all(not(feature = "debug-eh-frame"), not(feature = "debug-frame-point")))] - let tracer = CompilerTracer::new(TracerProviderImpl); - #[cfg(feature = "debug-frame-point")] - let tracer = FramePointTracer::new(TracerProviderImpl); - #[cfg(feature = "debug-eh-frame")] - let tracer = DwarfTracer::new(DwarfProviderImpl, TracerProviderImpl); - for x in tracer.trace() { - println!("[{:#x}] (+{:0>4x}) {}", x.func_addr, x.bias, x.func_name); - } - println!("---END BACKTRACE---"); -} diff --git a/kernel/src/print/console.rs b/kernel/src/print/console.rs deleted file mode 100644 index 91272e0d..00000000 --- a/kernel/src/print/console.rs +++ /dev/null @@ -1,133 +0,0 @@ -use core::fmt::{Arguments, Result, Write}; -use core::sync::atomic::{AtomicBool, Ordering}; - -use preprint::Print; - -use ksync::Mutex; - -use crate::device::UART_DEVICE; -use crate::sbi::console_putchar; - -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => { - let hard_id = arch::hart_id(); - // [hart_id] xxx - $crate::print::console::__print(format_args!("[{}] {}", hard_id, format_args!($($arg)*))) - }; -} - -#[macro_export] -macro_rules! println { - () => ($crate::print!("\n")); - ($fmt:expr) => ($crate::print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => ($crate::print!( - concat!($fmt, "\n"), $($arg)*)); -} - -#[macro_export] -macro_rules! eprint { - ($($arg:tt)*) => { - $crate::print::console::__print(format_args!("{}", format_args!($($arg)*))) - }; -} - -#[macro_export] -macro_rules! eprintln { - () => ($crate::eprint!("\n")); - ($fmt:expr) => ($crate::eprint!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => ($crate::eprint!( - concat!($fmt, "\n"), $($arg)*)); -} - -#[macro_export] -macro_rules! uprint { - ($($arg:tt)*) => { - $crate::print::console::__uprint(format_args!($($arg)*)) - }; -} - -#[macro_export] -macro_rules! uprintln { - () => ($crate::uprint!("\n")); - ($fmt:expr) => ($crate::uprint!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => ($crate::uprint!( - concat!($fmt, "\n"), $($arg)*)); -} - -pub struct Stdout; - -pub static STDOUT: Mutex = Mutex::new(Stdout); - -pub static UART_FLAG: AtomicBool = AtomicBool::new(false); - -/// 对`Stdout`实现输出的Trait -impl Write for Stdout { - fn write_str(&mut self, s: &str) -> Result { - if UART_FLAG.load(Ordering::Relaxed) { - let uart = UART_DEVICE.get().unwrap(); - uart.put_bytes(s.as_bytes()); - } else { - s.as_bytes().iter().for_each(|x| { - console_putchar(*x); - }); - } - Ok(()) - } -} - -struct MStdout; -impl Write for MStdout { - fn write_str(&mut self, s: &str) -> Result { - s.as_bytes().iter().for_each(|x| { - console_putchar(*x); - }); - Ok(()) - } -} - -pub fn __mprint(args: Arguments) { - MStdout.write_fmt(args).unwrap(); -} - -#[macro_export] -macro_rules! mprint { - ($($arg:tt)*) => { - let hard_id = arch::hart_id(); - // [hart_id] xxx - $crate::print::console::__mprint(format_args!("[{}] {}", hard_id, format_args!($($arg)*))) - }; -} - -#[macro_export] -macro_rules! mprintln { - () => ($crate::mprint!("\n")); - ($fmt:expr) => ($crate::mprint!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => ($crate::mprint!( - concat!($fmt, "\n"), $($arg)*)); -} - -/// 输出函数 -/// 对参数进行输出 主要使用在输出相关的宏中 如println -pub fn __print(args: Arguments) { - Stdout.write_fmt(args).unwrap(); -} - -pub fn __uprint(args: Arguments) { - Stdout.write_fmt(args).unwrap(); -} - -pub struct PrePrint; - -impl Print for PrePrint { - fn print(&self, args: Arguments) { - print!("{}", args); - } -} - -impl Write for PrePrint { - fn write_str(&mut self, s: &str) -> Result { - print!("{}", s); - Ok(()) - } -} diff --git a/kernel/src/print/logging.rs b/kernel/src/print/logging.rs deleted file mode 100644 index 1c03d400..00000000 --- a/kernel/src/print/logging.rs +++ /dev/null @@ -1,41 +0,0 @@ -use log::{self, Level, LevelFilter, Log, Metadata, Record}; - -struct SimpleLogger; - -impl Log for SimpleLogger { - fn enabled(&self, _metadata: &Metadata) -> bool { - true - } - fn log(&self, record: &Record) { - if !self.enabled(record.metadata()) { - return; - } - let color = match record.level() { - Level::Error => 31, // Red - Level::Warn => 93, // BrightYellow - Level::Info => 35, // Blue - Level::Debug => 32, // Green - Level::Trace => 90, // BrightBlack - }; - println!( - "\u{1B}[{}m[{:>1}] {}\u{1B}[0m", - color, - record.level(), - record.args(), - ); - } - fn flush(&self) {} -} - -pub fn init_logger() { - println!("Init logger {:?}", option_env!("LOG")); - log::set_logger(&SimpleLogger).unwrap(); - log::set_max_level(match option_env!("LOG") { - Some("ERROR") => LevelFilter::Error, - Some("WARN") => LevelFilter::Warn, - Some("INFO") => LevelFilter::Info, - Some("DEBUG") => LevelFilter::Debug, - Some("TRACE") => LevelFilter::Trace, - _ => LevelFilter::Off, - }); -} diff --git a/kernel/src/print/mod.rs b/kernel/src/print/mod.rs deleted file mode 100644 index 7b25d2c0..00000000 --- a/kernel/src/print/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -use console::PrePrint; -use logging::init_logger; - -#[macro_use] -pub mod console; -mod logging; - -pub fn init_print() { - init_logger(); - preprint::init_print(&PrePrint); - println!("Print init success"); -} diff --git a/kernel/src/sbi.rs b/kernel/src/sbi.rs deleted file mode 100644 index 58a3d3cd..00000000 --- a/kernel/src/sbi.rs +++ /dev/null @@ -1,128 +0,0 @@ -//! SBI 调用接口 -use core::arch::asm; - -use syscall_table::syscall_func; - -/// 设置定时器 -const SBI_SET_TIMER: usize = 0; -/// 控制台输出 -const SBI_CONSOLE_PUT_CHAR: usize = 1; -/// 控制台输入 -const SBI_CONSOLE_GET_CHAR: usize = 2; -// const SBI_CLEAR_IPI: usize = 3; -/// 发送 IPI -const SBI_SEND_IPI: usize = 4; -// const SBI_REMOTE_FENCE_I: usize = 5; -// const SBI_REMOTE_SFENCE_VMA: usize = 6; -// const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7; -/// 关闭机器 -const SBI_SHUTDOWN: usize = 8; - -/// SBI 调用 -/// -/// sbi规范定义了调用的参数传递方法 -fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> i32 { - let mut ret; - unsafe { - asm!("ecall", - in("a7") which, - inlateout("a0") arg0 as i32 => ret, - in("a1") arg1, - in("a2") arg2); - } - ret -} - -/// 设置定时器 -pub fn set_timer(time: usize) { - sbi_call(SBI_SET_TIMER, time, 0, 0); -} - -/// 一个系统调用,通过调用 SBI_SHUTDOWN 来关闭操作系统(直接退出 QEMU) -#[syscall_func(2003)] -pub fn system_shutdown() -> isize { - mprintln!("shutdown..."); - sbi_call(SBI_SHUTDOWN, 0, 0, 0); - 0 -} - -/// Warp sbi SBI_CONSOLE_PUT_CHAR call -pub fn console_putchar(ch: u8) { - sbi_call(SBI_CONSOLE_PUT_CHAR, ch as usize, 0, 0); -} - -/// Warp sbi SBI_CONSOLE_GET_CHAR call -#[allow(unused)] -pub fn console_getchar() -> char { - sbi_call(SBI_CONSOLE_GET_CHAR, 0, 0, 0) as u8 as char -} - -/// sbi调用返回值 -#[repr(C)] -#[derive(Debug)] -pub struct SbiRet { - /// Error number - pub error: isize, - /// Result value - pub value: isize, -} - -/// SBI 基本扩展 -pub const EXTENSION_BASE: usize = 0x10; -/// SBI 时钟扩展 -pub const EXTENSION_TIMER: usize = 0x54494D45; -// pub const EXTENSION_IPI: usize = 0x735049; -// pub const EXTENSION_RFENCE: usize = 0x52464E43; -/// SBI HSM 扩展 -pub const EXTENSION_HSM: usize = 0x48534D; -// pub const EXTENSION_SRST: usize = 0x53525354; - -/// SBI HSM扩展的启动cpu功能 -const FUNCTION_HSM_HART_START: usize = 0x0; -// const FUNCTION_HSM_HART_STOP: usize = 0x1; -// const FUNCTION_HSM_HART_GET_STATUS: usize = 0x2; -// const FUNCTION_HSM_HART_SUSPEND: usize = 0x3; - -/// 第三种类型的SBI调用 -/// -/// 可以传递更多参数 -#[inline(always)] -fn sbi_call_3(extension: usize, function: usize, arg0: usize, arg1: usize, arg2: usize) -> SbiRet { - let (error, value); - unsafe { - asm!( - "ecall", - in("a0") arg0, in("a1") arg1, in("a2") arg2, - in("a6") function, in("a7") extension, - lateout("a0") error, lateout("a1") value, - ) - } - SbiRet { error, value } -} - -// pub fn hart_suspend(suspend_type: u32, resume_addr: usize, opaque: usize) -> SbiRet { -// sbi_call_3( -// EXTENSION_HSM, -// FUNCTION_HSM_HART_SUSPEND, -// suspend_type as usize, -// resume_addr, -// opaque, -// ) -// } - -/// wrap sbi FUNCTION_HSM_HART_START call -pub fn hart_start(hart_id: usize, start_addr: usize, opaque: usize) -> SbiRet { - sbi_call_3( - EXTENSION_HSM, - FUNCTION_HSM_HART_START, - hart_id, - start_addr, - opaque, - ) -} - -/// wrap sbi SBI_SEND_IPI call -#[allow(unused)] -pub fn send_ipi(ptr: usize) { - sbi_call(SBI_SEND_IPI, ptr, 0, 0); -} diff --git a/kernel/src/system.rs b/kernel/src/system.rs index 0de05c6b..77871740 100644 --- a/kernel/src/system.rs +++ b/kernel/src/system.rs @@ -1,5 +1,9 @@ //! uname系统调用实现 +use constants::sys::{Rusage, RusageFlag, Sysinfo, SyslogAction, TimeVal}; +use constants::{AlienResult, LinuxErrno}; +use core::cmp::min; use syscall_table::syscall_func; +use timer::{get_time_ms, TimeFromFreq}; use crate::task::current_task; @@ -56,3 +60,169 @@ pub fn uname(utsname: *const u8) -> isize { .copy_to_user(&system_info(), utsname as *mut Utsname); 0 } + +const LOG_BUF_LEN: usize = 4096; +const LOG: &str = r" +[ 0.000000] Linux version 5.10.0-7-riscv64 (debian-kernel@lists.debian.org) (gcc-10 (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2) #1 SMP Debian 5.10.40-1 (2021-05-28) +"; + +/// (待完善)一个系统调用函数,用于对内核消息环状缓冲区进行操作。 +/// +/// + `log_type`: 指明操作的类型,具体值可见[`SyslogAction`]; +/// + `buf`: 指明读取消息时,消息要保存到的位置; +/// + `len`: 指明具体操作时,对于消息读取的长度限制。真正的读取消息的长度将取决于就传入的`len`和`LOG_BUF_LEN`的最小值。 +/// +/// 当`log_type`为`READ`、`ReadAll`、`ReadClear`三种flag,正确执行后返回读取消息的长度; +/// 当`log_type`为`Unknown`时,会返回`EINVAL`;当`log_type`为`OPEN`或`CLOSE`时,函数不进行任何操作后返回0。 +/// 目前Alien仅支持上述`log_type`值,其余值都将不进行任何操作后返回0。 +/// +/// Reference: [syslog](https://man7.org/linux/man-pages/man2/syslog.2.html) +#[syscall_func(116)] +pub fn syslog(log_type: u32, buf: usize, len: usize) -> isize { + let log_type = SyslogAction::try_from(log_type); + if log_type.is_err() { + return LinuxErrno::EINVAL as isize; + } + match log_type.unwrap() { + SyslogAction::OPEN | SyslogAction::CLOSE => 0, + SyslogAction::READ | SyslogAction::ReadAll | SyslogAction::ReadClear => { + let min_len = min(len, LOG_BUF_LEN); + let task = current_task().unwrap(); + // the buf may be not valid, so we need to check it -- > sbrk heap + let mut buf = task.transfer_buffer(buf as *mut u8, min_len); + let log = LOG.as_bytes(); + let mut offset = 0; + buf.iter_mut().for_each(|buf| { + let copy_len = min(log.len() - offset, buf.len()); + buf[..copy_len].copy_from_slice(&log[offset..offset + copy_len]); + offset += copy_len; + }); + offset as isize + } + SyslogAction::Unknown => LinuxErrno::EINVAL as isize, + _ => 0, + } +} + +extern "C" { + fn ekernel(); +} + +/// 一个系统调用函数,用于获取系统相关信息。信息包括系统的自启动经过的时间、对于内存的使用情况、共享存储区的大小、 +/// 缓冲区与交换区的大小、当前进程数目等,具体可见[`Sysinfo`]。获取到的信息将保存到`dst_info`所指向的[`Sysinfo`]结构处。 +/// +/// 目前功能还有待完善。正确执行后返回0。 +#[syscall_func(179)] +pub fn sys_info(dst_info: usize) -> isize { + const LINUX_SYSINFO_LOADS_SCALE: usize = 65536; + let task = current_task().unwrap(); + // calculate the task number + let task_number = 10; // fake task number + let machine_info = platform::platform_machine_info(); + let memory_info = machine_info.memory.clone(); + let info = Sysinfo { + uptime: (get_time_ms() / 1000) as usize, + loads: [ + task_number * LINUX_SYSINFO_LOADS_SCALE / 60, + task_number * LINUX_SYSINFO_LOADS_SCALE / 300, + task_number * LINUX_SYSINFO_LOADS_SCALE / 900, + ], + totalram: memory_info.end - memory_info.start, + freeram: memory_info.end - ekernel as usize, + sharedram: 0, + bufferram: 0, + totalswap: 0, + freeswap: 0, + procs: task_number as u16, + totalhigh: 0, + freehigh: 0, + mem_unit: 1, + }; + task.access_inner() + .copy_to_user(&info, dst_info as *mut Sysinfo); + 0 +} + +/// (待实现)一个系统调用,设置进程调度的参数。目前直接返回0。 +#[syscall_func(118)] +pub fn sched_setparam() -> isize { + 0 +} + +/// (待实现)一个系统调用,获取进程调度的参数。目前直接返回0。 +#[syscall_func(121)] +pub fn sched_getparam() -> isize { + 0 +} + +/// (待实现)一个系统调用,设置进程CPU亲和力(位掩码),使进程绑定在某一个或几个CPU上运行,避免在CPU之间来回切换,从而提高该进程的实时性能。目前直接返回0。 +#[syscall_func(122)] +pub fn sched_setaffinity() -> isize { + 0 +} + +/// (待完善)一个系统调用,获取某进程对CPU的亲和力(位掩码)。当前进程的cpu亲和力将保存到`mask`所指向的位置。函数执行成功后返回8。 +#[syscall_func(123)] +pub fn sched_getaffinity(pid: usize, size: usize, mask: usize) -> isize { + warn!( + "sched_getaffinity: pid: {}, size: {}, mask: {}", + pid, size, mask + ); + assert_eq!(pid, 0); + let task = current_task().unwrap(); + let res = task.access_inner().cpu_affinity; + let mask = task.access_inner().transfer_raw_ptr_mut(mask as *mut usize); + *mask = res; + 8 +} + +/// (待实现)一个系统调用,用于获取当前CPU的调度策略。目前直接返回0。 +#[syscall_func(120)] +pub fn sched_getscheduler(pid: usize) -> isize { + assert_eq!(pid, 0); + // let task = current_task().unwrap(); + 0 +} + +/// (待实现)一个系统调用,用于设置当前CPU的调度策略。目前直接返回0。 +#[syscall_func(119)] +pub fn sched_setscheduler(_pid: usize, _policy: usize, _param: usize) -> isize { + 0 +} + +/// (待完善)一个系统调用,用于获取对系统资源的使用量信息。获取的信息将保存到`usage`所指向的[`Rusage`]结构中。 +/// +/// 可以通过`who`修改获取信息的对象,包括: +/// + `RUSAGE_SELF`: 返回调用该函数进程的资源用量统计,会返回该进程下所有线程的资源用量之和; +/// + `RUSAGE_CHILDREN`: 返回调用该函数进程所有已终止且被回收子进程的资源用量统计. +/// + `RUSAGE_THREAD`: 返回调用该函数线程的资源用量统计。 +/// +/// 在Alien中,目前仅支持`RUSAGE_SELF`。且返回的信息目前仅有[`Rusage`]下的`ru_utime`和`ru_stime`字段。 +/// +/// 正确执行后返回0。 +#[syscall_func(165)] +pub fn getrusage(who: isize, usage: usize) -> AlienResult { + let who = RusageFlag::try_from(who).map_err(|_| LinuxErrno::EINVAL)?; + info!("getrusage: who: {:?}, usage: {}", who, usage); + let task = current_task().unwrap(); + let static_info = task.access_inner().statistical_data().clone(); + let mut task_usage = Rusage::new(); + task_usage.ru_utime = TimeVal::from_freq(static_info.tms_utime); + task_usage.ru_stime = TimeVal::from_freq(static_info.tms_stime); + task.access_inner() + .copy_to_user(&task_usage, usage as *mut Rusage); + Ok(0) +} + + + + + + + +/// 一个系统调用,通过调用 SBI_SHUTDOWN 来关闭操作系统(直接退出 QEMU) +#[syscall_func(2003)] +pub fn system_shutdown() -> AlienResult { + println!("shutdown..."); + platform::system_shutdown(); +} \ No newline at end of file diff --git a/kernel/src/task/cpu.rs b/kernel/src/task/cpu.rs index bd84d41a..0ea880f1 100644 --- a/kernel/src/task/cpu.rs +++ b/kernel/src/task/cpu.rs @@ -3,6 +3,7 @@ use alloc::string::{String, ToString}; use alloc::sync::Arc; use alloc::vec::Vec; use core::cell::UnsafeCell; +use log::{error, info, warn}; use smpscheduler::{FifoSmpScheduler, FifoTask, ScheduleHart}; use spin::Lazy; @@ -14,16 +15,16 @@ use constants::{PrLimit, PrLimitRes}; use ksync::Mutex; use syscall_table::syscall_func; -use crate::config::CPU_NUM; use crate::fs; use crate::ipc::{futex, global_logoff_signals}; -use crate::sbi::system_shutdown; use crate::task::context::Context; use crate::task::schedule::schedule; use crate::task::task::{Task, TaskState}; use crate::task::INIT_PROCESS; use crate::trap::{check_task_timer_expired, TrapFrame}; use arch::hart_id; +use config::CPU_NUM; +use platform::system_shutdown; /// 记录当前 CPU 上正在执行的线程 和 线程上下文 #[derive(Debug, Clone)] @@ -43,11 +44,6 @@ impl CPU { } } - /// 获取 cpu 上的线程任务控制块(会直接获取该任务控制块的所有权) - pub fn take_process(&mut self) -> Option> { - self.task.take() - } - /// 获取线程上下文的一个 不可变引用 的指针 pub fn get_context_raw_ptr(&self) -> *const Context { &self.context as *const Context diff --git a/kernel/src/task/heap.rs b/kernel/src/task/heap.rs index 9243bc09..cbe663ae 100644 --- a/kernel/src/task/heap.rs +++ b/kernel/src/task/heap.rs @@ -33,6 +33,7 @@ impl HeapInfo { addr >= self.start && addr < self.end } + #[allow(unused)] /// 堆大小增加 size 个单位 pub fn increase(&mut self, size: usize) { self.end += size; @@ -44,6 +45,7 @@ impl HeapInfo { self.start = start; } + #[allow(unused)] /// 重新设置堆空间的尾 pub fn set_end(&mut self, end: usize) { self.end = end; diff --git a/kernel/src/task/mod.rs b/kernel/src/task/mod.rs index 37b2f6c7..dff74938 100644 --- a/kernel/src/task/mod.rs +++ b/kernel/src/task/mod.rs @@ -6,18 +6,17 @@ //! [`schedule`] 子模块指明了 Alien 中有关 CPU 调度的相关机制 //! [`stack`] 子模块定义了 Alien 中有关内核栈的相关结构。 //! [`task`] 子模块定义了 Alien 中有关进程控制块的定义。 +use crate::fs::read_all; +pub use crate::task::task::FsContext; use alloc::sync::Arc; use alloc::vec::Vec; +pub use cpu::*; +use devices::DeviceWithTask; +use drivers::{DriverTask, DriverWithTask}; use smpscheduler::FifoTask; - use spin::Lazy; - -pub use cpu::*; pub use task::{StatisticalData, Task, TaskState}; -use crate::fs::{read_all, SYSTEM_ROOT_FS}; -pub use crate::task::task::FsContext; - mod context; mod cpu; mod heap; @@ -29,7 +28,6 @@ mod task; pub static INIT_PROCESS: Lazy> = Lazy::new(|| { let mut data = Vec::new(); read_all("/bin/init", &mut data); - // let data = INIT; assert!(data.len() > 0); let task = Task::from_elf("/bin/init", data.as_slice()).unwrap(); Arc::new(task) @@ -38,11 +36,54 @@ pub static INIT_PROCESS: Lazy> = Lazy::new(|| { /// 将初始进程加入进程池中进行调度 pub fn init_process() { let task = INIT_PROCESS.clone(); - let cwd = SYSTEM_ROOT_FS.get().unwrap().clone(); + let cwd = vfs::system_root_fs(); let root = cwd.clone(); task.access_inner().fs_info = FsContext::new(root, cwd); GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); println!("Init process success"); } + +impl DriverTask for Task { + fn to_wait(&self) { + self.update_state(TaskState::Waiting) + } + + fn to_wakeup(&self) { + self.update_state(TaskState::Ready) + } + + fn have_signal(&self) -> bool { + self.access_inner().signal_receivers.lock().have_signal() + } +} +pub struct DriverTaskImpl; +impl DriverWithTask for DriverTaskImpl { + fn get_task(&self) -> Arc { + let task = current_task().unwrap(); + task.clone() + } + + fn put_task(&self, task: Arc) { + let task = task.downcast_arc::().map_err(|_| ()).unwrap(); + GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); + } + + fn suspend(&self) { + do_suspend(); + } +} + +impl DeviceWithTask for DriverTaskImpl { + fn transfer_ptr_raw(&self, ptr: usize) -> usize { + let task = current_task().unwrap(); + task.transfer_raw(ptr) + } + + fn transfer_buf_raw(&self, src: usize, size: usize) -> Vec<&mut [u8]> { + let task = current_task().unwrap(); + task.transfer_buffer(src as *const u8, size) + } +} + // online test has no sort.src // pub static SORT_SRC: &[u8] = include_bytes!("../../../sdcard/sort.src"); diff --git a/kernel/src/task/schedule.rs b/kernel/src/task/schedule.rs index bead11fe..f35e0e38 100644 --- a/kernel/src/task/schedule.rs +++ b/kernel/src/task/schedule.rs @@ -21,15 +21,14 @@ use crate::trap::check_timer_interrupt_pending; /// /// 之后如果在线程池中有任务需要调度,那么就把该任务的上下文切换到 CPU 上来运行; /// 否则该 CPU 将进入等待状态,等待其它核的中断信号。 -#[no_mangle] -pub fn first_into_user() -> ! { +pub fn run_task() -> ! { loop { { let cpu = current_cpu(); if cpu.task.is_some() { let task = cpu.task.take().unwrap(); match task.state() { - TaskState::Sleeping | TaskState::Waiting => { + TaskState::Waiting => { // drop(task); } TaskState::Zombie => { @@ -56,7 +55,7 @@ pub fn first_into_user() -> ! { let cpu = current_cpu(); if let Some(task) = GLOBAL_TASK_MANAGER.pick_next_task() { // if process.get_tid() >= 1 { - // warn!("switch to task {}", process.get_tid()); + // warn!("switch to task {}", task.get_tid()); // } // update state to running task.inner().update_state(TaskState::Running); diff --git a/kernel/src/task/stack.rs b/kernel/src/task/stack.rs index c5c8b676..494ce871 100644 --- a/kernel/src/task/stack.rs +++ b/kernel/src/task/stack.rs @@ -1,40 +1,33 @@ //! 进程内核栈空间 -use alloc::vec::Vec; -use ksync::Mutex; - -use crate::config::FRAME_BITS; -use crate::memory::{frame_alloc_contiguous, FrameTracker}; +use config::FRAME_SIZE; +use mem::{alloc_frames, free_frames}; /// 记录进程内核栈空间 #[derive(Debug)] pub struct Stack { /// 栈帧 - frames: Mutex>, + start_ptr: usize, + pages: usize, } impl Stack { /// 通过帧的个数创建一块新的 内核栈 pub fn new(pages: usize) -> Option { - let frames = frame_alloc_contiguous(pages) as usize >> FRAME_BITS; - let frames = (0..pages) - .into_iter() - .map(|i| FrameTracker::new(i + frames)) - .collect::>(); + let frames = alloc_frames(pages); Some(Stack { - frames: Mutex::new(frames), + start_ptr: frames as usize, + pages, }) } /// 获取帧顶指针 pub fn top(&self) -> usize { - let first = self.frames.lock().last().map(|frame| frame.end()); - first.unwrap() + self.start_ptr + self.pages * FRAME_SIZE } /// 回收内核栈空间。 pub fn release(&self) { - let mut frames = self.frames.lock(); - *frames = Vec::new(); + free_frames(self.start_ptr as _, self.pages) } } diff --git a/kernel/src/task/task.rs b/kernel/src/task/task.rs index 64c22295..4ddd5a0f 100644 --- a/kernel/src/task/task.rs +++ b/kernel/src/task/task.rs @@ -3,15 +3,15 @@ //! Alien 中对于进程\线程的相关概念的设计与 Linux 类似,进程和线程共用一个控制块结构。 //! 使用 `clone` 创建新的进程(线程)时,会根据 flag 指明父子进程之间资源共享的程度。 //! tid 是标识不同任务的唯一标识。 -use crate::config::*; -use crate::fs::file::File; -use crate::fs::{STDIN, STDOUT, SYSTEM_ROOT_FS}; +use crate::fs::stdio::{STDIN, STDOUT}; use crate::ipc::{global_register_signals, ShmInfo}; -use crate::memory::*; +use crate::mm::loader::{ + build_cow_address_space, build_elf_address_space, build_thread_address_space, UserStack, +}; +use crate::mm::map::{MMapInfo, MMapRegion, ProtFlags}; use crate::task::context::Context; use crate::task::heap::HeapInfo; use crate::task::stack::Stack; -use crate::timer::{read_timer, ITimerVal, TimeNow, ToClock}; use crate::trap::{trap_common_read_file, trap_return, user_trap_vector, TrapFrame}; use alloc::collections::BTreeMap; use alloc::string::{String, ToString}; @@ -19,6 +19,7 @@ use alloc::sync::{Arc, Weak}; use alloc::vec::Vec; use alloc::{format, vec}; use bit_field::BitField; +use config::*; use constants::aux::*; use constants::io::MapFlags; use constants::ipc::RobustList; @@ -32,10 +33,13 @@ use core::fmt::{Debug, Formatter}; use core::ops::Range; use gmanager::MinimalManager; use ksync::{Mutex, MutexGuard}; +use mem::{kernel_satp, VmmPageAllocator, FRAME_REF_MANAGER}; use page_table::addr::{align_down_4k, align_up_4k, VirtAddr}; use page_table::pte::MappingFlags; use page_table::table::Sv39PageTable; use spin::Lazy; +use timer::{read_timer, ITimerVal, TimeNow, ToClock}; +use vfs::kfile::File; use vfscore::dentry::VfsDentry; type FdManager = MinimalManager>; @@ -91,7 +95,7 @@ pub struct TaskInner { /// 用于记录当前线程组中的线程个数 pub thread_number: usize, /// 地址空间 - pub address_space: Arc>>, + pub address_space: Arc>>, /// 线程状态 pub state: TaskState, /// 父亲任务控制块 @@ -165,10 +169,6 @@ pub struct TaskTimer { } impl TaskTimer { - /// 创建一个新的任务计数器 - pub fn new() -> Self { - Self::default() - } /// 清除当前的计数器信息,将 timer_remained 置为 0 pub fn clear(&mut self) { self.timer_type = TimerType::NONE; @@ -265,7 +265,7 @@ pub enum TaskState { /// 运行态 Running, /// 等待一段时间 - Sleeping, + // Sleeping, /// 等待一个事件 Waiting, /// 僵尸态,等待父进程回收资源 @@ -967,6 +967,7 @@ impl TaskInner { self.heap.lock().clone() } + #[allow(unused)] /// (待实现)缩减堆空间 pub fn shrink_heap(_addr: usize) -> Result { todo!() @@ -1120,7 +1121,7 @@ impl TaskInner { // warn!("add mmap region:{:#x?}",region); self.mmap.add_region(region); let start = v_range.start; - let mut map_flags = prot.into(); // no V flag + let mut map_flags: MappingFlags = prot.into(); // no V flag map_flags |= "AD".into(); self.address_space .lock() @@ -1203,7 +1204,7 @@ impl TaskInner { let region = self.mmap.get_region(addr).ok_or(AlienError::EINVAL)?; // now we need make sure the start is equal to the start of the region, and the len is equal to the len of the region // update page table - let mut map_flags = region.prot.into(); + let mut map_flags: MappingFlags = region.prot.into(); map_flags |= "V".into(); let mut address_space = self.address_space.lock(); @@ -1248,7 +1249,7 @@ impl TaskInner { let region = is_mmap.unwrap(); // assert_eq!(addr % FRAME_SIZE, 0); // update page table - let mut map_flags = region.prot.into(); + let mut map_flags: MappingFlags = region.prot.into(); map_flags |= "VAD".into(); warn!( "invalid page fault at {:#x}, flag is :{:?}", @@ -1406,7 +1407,7 @@ impl Task { let k_stack = Stack::new(USER_KERNEL_STACK_SIZE / FRAME_SIZE)?; let k_stack_top = k_stack.top(); let stack_info = elf_info.stack_top - USER_STACK_SIZE..elf_info.stack_top; - let cwd = SYSTEM_ROOT_FS.get().unwrap().clone(); + let cwd = vfs::system_root_fs(); let process = Task { tid, diff --git a/kkernel/src/time.rs b/kernel/src/time.rs similarity index 97% rename from kkernel/src/time.rs rename to kernel/src/time.rs index cc343bdd..3c5098fe 100644 --- a/kkernel/src/time.rs +++ b/kernel/src/time.rs @@ -1,269 +1,257 @@ -//! Alien 中的有关时钟、计时器的结构 以及 一些计时器的系统调用。 -//! -//! 在对系统时间的记录上,Alien 中使用 [`TimeVal`] 记录 (秒,微秒) 的时间,使用 [`TimeSpec`] 记录 更精细的 (秒,纳秒) 的时间; -//! 在对进程的运行时间的记录上,使用 [`Times`] 结构记录进程运行的时间,记录的信息包括程序在用户态、内核态下分别运行的时间, -//! 其子进程运行的总时间等,在任务控制块中记录相应数据的结构为 [`StatisticalData`]。 -//! -//! 计时器方面, [`Timer`] 结构为实际放入计时器队列 [`TIMER_QUEUE`] 中的计时器结构。 -//! 当发生时钟中断时,会检查所有计时器队列中的计时器是否超时,具体可见 [`check_timer_queue`]。 -//! [`ITimerVal`] 结构为系统调用 [`getitimer`] / [`setitimer`] 指定的类型,用户执行系统调用时获取和输入时需要为该种类型的计时器, -//! 在任务控制块中记录相应数据的字段为 `timer`(结构为 `TaskTimer` )。 -//! -//! 对于时间片 (每次引发时钟中断的时间间隔) 大小的设计:目前 Alien 中用户态和内核态下采用相同的时间片间隔,1s 内触发 10 次时钟中断。 -use log::{info, warn}; -use crate::task::{current_task, do_suspend, StatisticalData}; -use constants::sys::TimeVal; -use constants::time::{ClockId, TimerType}; -use constants::LinuxErrno; -use syscall_table::syscall_func; -use platform::config::CLOCK_FREQ; -use platform::set_timer; -use timer::{ITimerVal, read_timer, TimeNow, Times, TimeSpec}; - -/// 每秒包含的 时间片 数,每隔一个时间片,就会产生一个时钟中断 -const TICKS_PER_SEC: usize = 10; -// const TICKS_PER_SEC_IN_KERNEL: usize = 1000; - - -/// 设置下一次时钟的中断 -#[inline] -pub fn set_next_trigger() { - let next = read_timer() + CLOCK_FREQ / TICKS_PER_SEC; - assert!(next > read_timer()); - set_timer(next); -} - -/// 设置内核态中下一次时钟的中断 -/// -/// 原设计为内核态下的时间片设置的更短一些,以免一个进程在进入内核态前后占用过多的时间片。但目前修改为 内核态和用户态下的时间片大小相同。 -#[inline] -pub fn set_next_trigger_in_kernel() { - let next = read_timer() + CLOCK_FREQ / TICKS_PER_SEC; - assert!(next > read_timer()); - set_timer(next); -} - - -/// 一个系统调用函数,获取当前的时间,获取的时间将存储在`tv`所指向的[`TimeVal`]结构处。 -/// 执行成功则返回0。 -/// -/// Reference: [get_time_of_day](https://man7.org/linux/man-pages/man2/gettimeofday.2.html) -#[syscall_func(169)] -pub fn get_time_of_day(tv: *mut u8) -> isize { - let time = TimeVal::now(); - let process = current_task().unwrap(); - let tv = process.transfer_raw_ptr(tv as *mut TimeVal); - *tv = time; - 0 -} - -/// 一个系统调用函数,获取当前进程在用户态/内核态下运行的时间、最后一次运行在用户态/内核态下的时间等, -/// 获取的信息将保存在`tms`所指向的[`Times`]结构处。执行成功返回0。 -/// -/// Reference: [times](https://man7.org/linux/man-pages/man2/times.2.html) -#[syscall_func(153)] -pub fn times(tms: *mut u8) -> isize { - let mut task = current_task().unwrap().access_inner(); - let statistic_data = task.statistical_data(); - let time = times_from_process_data(statistic_data); - task.copy_to_user(&time, tms as *mut Times); - 0 -} - - - -/// 从一个 [`StatisticalData`] 结构 (一般为 task 的 statistical_data 字段) 得到一个 `Times` 变量 -pub fn times_from_process_data(data: &StatisticalData) -> Times { - Times { - tms_stime: data.tms_stime, - tms_utime: data.tms_utime, - tms_cstime: data.tms_cstime, - tms_cutime: data.tms_cutime, - } -} - -/// 一个系统调用函数,暂停本进程直到一段时间后结束,要暂停的时间将保存在`req`所指向的[`TimeSpec`]结构处。 -/// 但在`nanosleep`执行过程中,本进程有可能被其他信号唤醒。 -/// 函数若正常停止`req`时间则返回0;如果由于因为其他信号而被唤醒,此时函数返回-1(EINTR)。 -/// -/// Reference: [nanosleep](https://man7.org/linux/man-pages/man2/nanosleep.2.html) -#[syscall_func(101)] -pub fn nanosleep(req: *mut u8, _: *mut u8) -> isize { - let task = current_task().unwrap().clone(); - let mut time = TimeSpec::new(0, 0); - task.access_inner() - .copy_from_user(req as *const TimeSpec, &mut time); - warn!("nanosleep: {:?}", time); - let end_time = read_timer() + time.to_clock(); - loop { - if read_timer() >= end_time { - break; - } - do_suspend(); - // interrupt by signal - let task_inner = task.access_inner(); - let receiver = task_inner.signal_receivers.lock(); - if receiver.have_signal() { - return LinuxErrno::EINTR as isize; - } - } - 0 -} - -/// 一个系统调用函数,可以根据输入的时钟类型`clock_id`来获取当前的时间,获取的时间将存储在`tp`所指向的[`TimeSpec`]结构处。 -/// -/// 目前仅支持`Monotonic`、`Realtime`和`ProcessCputimeId`三种时钟类型,均会返回当前的系统时间。 -/// 执行成功则返回0;当所输入的`clock_id`不在`Monotonic`、`Realtime`和`ProcessCputimeId`中时,进程将会被panic。 -/// -/// Reference: [clock_get_time](https://www.man7.org/linux/man-pages/man3/clock_gettime.3.html) -#[syscall_func(113)] -pub fn clock_get_time(clock_id: usize, tp: *mut u8) -> isize { - let id = ClockId::from_raw(clock_id).unwrap(); - let task = current_task().unwrap(); - match id { - ClockId::Monotonic | ClockId::Realtime | ClockId::ProcessCputimeId => { - let time = TimeSpec::now(); - task.access_inner().copy_to_user(&time, tp as *mut TimeSpec) - } - _ => { - panic!("clock_get_time: clock_id {:?} not supported", id); - } - } - 0 -} - - - - - - - - - -/// 当发生时钟中断时,`trap_handler` 会调用该函数检查所有计时器队列中的计时器,并唤醒等待在这些计时器上的进程 -/// -/// 遍历所有计时器队列 [`TIMER_QUEUE`] 中的计时器,若计时器的超时时间在当前时间之前(即已超时),那么将该等待的进程加入 -/// 线程池的首位,马上对其进行调度。 -pub fn check_timer_queue() {} - -/// 一个系统调用函数,用于获取当前进程的计时器,保存在`current_value`指向的[`ITimerVal`]结构处。 -/// 由于Alien目前每个进程只支持一个计时器,原定于分辨计时器种类的`_which`在此处并没有派上用场。 -/// 函数执行成功则返回0。 -/// Reference: [getitimer](https://man7.org/linux/man-pages/man2/setitimer.2.html) -#[syscall_func(102)] -pub fn getitimer(_which: usize, current_value: usize) -> isize { - let task = current_task().unwrap(); - let timer = &task.access_inner().timer; - let itimer = ITimerVal { - it_interval: timer.timer_interval, - it_value: timer.timer_remained.into(), - }; - task.access_inner() - .copy_to_user(&itimer, current_value as *mut ITimerVal); - 0 -} - -/// 一个系统调用函数,用于将当前进程的定时器设置为`current_value`指向的[`ITimerVal`]结构处, -/// 同时将旧计时器的信息保存在`old_value`指向的[`ITimerVal`]结构处。 -/// -/// `which`参数需为目前支持的[`TimerType`]类型且不为`NONE`,否则会导致进程被panic。 -/// 如果`current_value`为空,则会导致进程被panic。 -/// 如果`old_value`为空,则不进行保存旧计时器信息操作。 -/// -/// 函数执行正确则返回0。 -/// Reference: [setitimer](https://man7.org/linux/man-pages/man2/setitimer.2.html) -#[syscall_func(103)] -pub fn setitimer(which: usize, current_value: usize, old_value: usize) -> isize { - let which = TimerType::try_from(which).unwrap(); - assert_ne!(which, TimerType::NONE); - info!( - "setitimer: which {:?} ,curret_value {:#x}, old_value {:#x}", - which, current_value, old_value - ); - let task = current_task().unwrap(); - if old_value != 0 { - let timer = task.access_inner().get_timer(); - let itimer = ITimerVal { - it_interval: timer.timer_interval.into(), - it_value: timer.timer_remained.into(), - }; - task.access_inner() - .copy_to_user(&itimer, old_value as *mut ITimerVal); - } - assert_ne!(current_value, 0); - let mut itimer = ITimerVal::default(); - task.access_inner() - .copy_from_user(current_value as *const ITimerVal, &mut itimer); - info!("setitimer: itimer {:x?}", itimer); - task.access_inner().set_timer(itimer, which); - 0 -} - -/// 一个系统调用函数,可以根据输入的时钟类型`clock_id`来获取该时钟分辨率(精度),获取的精度将存储在`res`所指向的[`TimeSpec`]结构处。 -/// 时钟的分辨率取决于实现方式,无法由特定进程配置。目前Alien仅支持`Monotonic`一种时钟类型。 -/// -/// Reference: [clock_getres](https://www.man7.org/linux/man-pages/man3/clock_getres.3.html) -#[syscall_func(114)] -pub fn clock_getres(id: usize, res: usize) -> isize { - let id = ClockId::from_raw(id).unwrap(); - info!("clock_getres: id {:?} ,res {:#x}", id, res); - let task = current_task().unwrap(); - let time_res = match id { - ClockId::Monotonic => { - let time = TimeSpec::new(0, 1); - time - } - _ => { - panic!("clock_get_time: clock_id {:?} not supported", id); - } - }; - task.access_inner() - .copy_to_user(&time_res, res as *mut TimeSpec); - 0 -} - -/// 一个系统调用函数,如`nanosleep`一样,暂停本进程直到一段时间后结束,但`clock_nanosleep`可以根据传入的`clock_id`来指定使用的时钟类型。 -/// -/// 要暂停的时间将保存在`req`所指向的[`TimeSpec`]结构处。目前仅支持`Monotonic`,输入其它时钟类型将会返回使得进程panic。 -/// 如`nanosleep`一样,在`clock_nanosleep`执行过程中,本进程也有可能被其他信号唤醒。 -/// -/// 函数若正常停止`req`时间则返回0;如果由于因为其他信号而被唤醒,此时函数返回-1(EINTR)。 -/// -/// Reference: [times](https://man7.org/linux/man-pages/man2/times.2.html) -#[syscall_func(115)] -pub fn clock_nanosleep(clock_id: usize, flags: usize, req: usize, remain: usize) -> isize { - const TIMER_ABSTIME: usize = 1; - let id = ClockId::from_raw(clock_id).unwrap(); - info!( - "clock_nanosleep: id {:?} ,flags {:#x}, req {:#x}, remain {:#x}", - id, flags, req, remain - ); - match id { - ClockId::Monotonic => { - assert_eq!(flags, TIMER_ABSTIME); - let mut target_time = TimeSpec::new(0, 0); - let task = current_task().unwrap().clone(); - task.access_inner() - .copy_from_user(req as *const TimeSpec, &mut target_time); - let end_time = target_time.to_clock(); - - loop { - let now = read_timer(); - if now >= end_time { - break; - } - do_suspend(); - // check signal - let task_inner = task.access_inner(); - let receiver = task_inner.signal_receivers.lock(); - if receiver.have_signal() { - return LinuxErrno::EINTR.into(); - } - } - } - _ => { - panic!("clock_nanotime: clock_id {:?} not supported", id); - } - } - 0 -} +//! Alien 中的有关时钟、计时器的结构 以及 一些计时器的系统调用。 +//! +//! 在对系统时间的记录上,Alien 中使用 [`TimeVal`] 记录 (秒,微秒) 的时间,使用 [`TimeSpec`] 记录 更精细的 (秒,纳秒) 的时间; +//! 在对进程的运行时间的记录上,使用 [`Times`] 结构记录进程运行的时间,记录的信息包括程序在用户态、内核态下分别运行的时间, +//! 其子进程运行的总时间等,在任务控制块中记录相应数据的结构为 [`StatisticalData`]。 +//! +//! 计时器方面, [`Timer`] 结构为实际放入计时器队列 [`TIMER_QUEUE`] 中的计时器结构。 +//! 当发生时钟中断时,会检查所有计时器队列中的计时器是否超时,具体可见 [`check_timer_queue`]。 +//! [`ITimerVal`] 结构为系统调用 [`getitimer`] / [`setitimer`] 指定的类型,用户执行系统调用时获取和输入时需要为该种类型的计时器, +//! 在任务控制块中记录相应数据的字段为 `timer`(结构为 `TaskTimer` )。 +//! +//! 对于时间片 (每次引发时钟中断的时间间隔) 大小的设计:目前 Alien 中用户态和内核态下采用相同的时间片间隔,1s 内触发 10 次时钟中断。 +use crate::task::{current_task, do_suspend, StatisticalData}; +use constants::sys::TimeVal; +use constants::time::{ClockId, TimerType}; +use constants::LinuxErrno; +use log::{info, warn}; +use platform::config::CLOCK_FREQ; +use platform::set_timer; +use syscall_table::syscall_func; +use timer::{read_timer, ITimerVal, TimeNow, TimeSpec, Times}; + +/// 每秒包含的 时间片 数,每隔一个时间片,就会产生一个时钟中断 +const TICKS_PER_SEC: usize = 10; +// const TICKS_PER_SEC_IN_KERNEL: usize = 1000; + +/// 设置下一次时钟的中断 +#[inline] +pub fn set_next_trigger() { + let next = read_timer() + CLOCK_FREQ / TICKS_PER_SEC; + assert!(next > read_timer()); + set_timer(next); +} + +/// 设置内核态中下一次时钟的中断 +/// +/// 原设计为内核态下的时间片设置的更短一些,以免一个进程在进入内核态前后占用过多的时间片。但目前修改为 内核态和用户态下的时间片大小相同。 +#[inline] +pub fn set_next_trigger_in_kernel() { + let next = read_timer() + CLOCK_FREQ / TICKS_PER_SEC; + assert!(next > read_timer()); + set_timer(next); +} + +/// 一个系统调用函数,获取当前的时间,获取的时间将存储在`tv`所指向的[`TimeVal`]结构处。 +/// 执行成功则返回0。 +/// +/// Reference: [get_time_of_day](https://man7.org/linux/man-pages/man2/gettimeofday.2.html) +#[syscall_func(169)] +pub fn get_time_of_day(tv: *mut u8) -> isize { + let time = TimeVal::now(); + let process = current_task().unwrap(); + let tv = process.transfer_raw_ptr(tv as *mut TimeVal); + *tv = time; + 0 +} + +/// 一个系统调用函数,获取当前进程在用户态/内核态下运行的时间、最后一次运行在用户态/内核态下的时间等, +/// 获取的信息将保存在`tms`所指向的[`Times`]结构处。执行成功返回0。 +/// +/// Reference: [times](https://man7.org/linux/man-pages/man2/times.2.html) +#[syscall_func(153)] +pub fn times(tms: *mut u8) -> isize { + let mut task = current_task().unwrap().access_inner(); + let statistic_data = task.statistical_data(); + let time = times_from_process_data(statistic_data); + task.copy_to_user(&time, tms as *mut Times); + 0 +} + +/// 从一个 [`StatisticalData`] 结构 (一般为 task 的 statistical_data 字段) 得到一个 `Times` 变量 +pub fn times_from_process_data(data: &StatisticalData) -> Times { + Times { + tms_stime: data.tms_stime, + tms_utime: data.tms_utime, + tms_cstime: data.tms_cstime, + tms_cutime: data.tms_cutime, + } +} + +/// 一个系统调用函数,暂停本进程直到一段时间后结束,要暂停的时间将保存在`req`所指向的[`TimeSpec`]结构处。 +/// 但在`nanosleep`执行过程中,本进程有可能被其他信号唤醒。 +/// 函数若正常停止`req`时间则返回0;如果由于因为其他信号而被唤醒,此时函数返回-1(EINTR)。 +/// +/// Reference: [nanosleep](https://man7.org/linux/man-pages/man2/nanosleep.2.html) +#[syscall_func(101)] +pub fn nanosleep(req: *mut u8, _: *mut u8) -> isize { + let task = current_task().unwrap().clone(); + let mut time = TimeSpec::new(0, 0); + task.access_inner() + .copy_from_user(req as *const TimeSpec, &mut time); + warn!("nanosleep: {:?}", time); + let end_time = read_timer() + time.to_clock(); + loop { + if read_timer() >= end_time { + break; + } + do_suspend(); + // interrupt by signal + let task_inner = task.access_inner(); + let receiver = task_inner.signal_receivers.lock(); + if receiver.have_signal() { + return LinuxErrno::EINTR as isize; + } + } + 0 +} + +/// 一个系统调用函数,可以根据输入的时钟类型`clock_id`来获取当前的时间,获取的时间将存储在`tp`所指向的[`TimeSpec`]结构处。 +/// +/// 目前仅支持`Monotonic`、`Realtime`和`ProcessCputimeId`三种时钟类型,均会返回当前的系统时间。 +/// 执行成功则返回0;当所输入的`clock_id`不在`Monotonic`、`Realtime`和`ProcessCputimeId`中时,进程将会被panic。 +/// +/// Reference: [clock_get_time](https://www.man7.org/linux/man-pages/man3/clock_gettime.3.html) +#[syscall_func(113)] +pub fn clock_get_time(clock_id: usize, tp: *mut u8) -> isize { + let id = ClockId::from_raw(clock_id).unwrap(); + let task = current_task().unwrap(); + match id { + ClockId::Monotonic | ClockId::Realtime | ClockId::ProcessCputimeId => { + let time = TimeSpec::now(); + task.access_inner().copy_to_user(&time, tp as *mut TimeSpec) + } + _ => { + panic!("clock_get_time: clock_id {:?} not supported", id); + } + } + 0 +} + +/// 当发生时钟中断时,`trap_handler` 会调用该函数检查所有计时器队列中的计时器,并唤醒等待在这些计时器上的进程 +/// +/// 遍历所有计时器队列 [`TIMER_QUEUE`] 中的计时器,若计时器的超时时间在当前时间之前(即已超时),那么将该等待的进程加入 +/// 线程池的首位,马上对其进行调度。 +pub fn check_timer_queue() {} + +/// 一个系统调用函数,用于获取当前进程的计时器,保存在`current_value`指向的[`ITimerVal`]结构处。 +/// 由于Alien目前每个进程只支持一个计时器,原定于分辨计时器种类的`_which`在此处并没有派上用场。 +/// 函数执行成功则返回0。 +/// Reference: [getitimer](https://man7.org/linux/man-pages/man2/setitimer.2.html) +#[syscall_func(102)] +pub fn getitimer(_which: usize, current_value: usize) -> isize { + let task = current_task().unwrap(); + let timer = &task.access_inner().timer; + let itimer = ITimerVal { + it_interval: timer.timer_interval, + it_value: timer.timer_remained.into(), + }; + task.access_inner() + .copy_to_user(&itimer, current_value as *mut ITimerVal); + 0 +} + +/// 一个系统调用函数,用于将当前进程的定时器设置为`current_value`指向的[`ITimerVal`]结构处, +/// 同时将旧计时器的信息保存在`old_value`指向的[`ITimerVal`]结构处。 +/// +/// `which`参数需为目前支持的[`TimerType`]类型且不为`NONE`,否则会导致进程被panic。 +/// 如果`current_value`为空,则会导致进程被panic。 +/// 如果`old_value`为空,则不进行保存旧计时器信息操作。 +/// +/// 函数执行正确则返回0。 +/// Reference: [setitimer](https://man7.org/linux/man-pages/man2/setitimer.2.html) +#[syscall_func(103)] +pub fn setitimer(which: usize, current_value: usize, old_value: usize) -> isize { + let which = TimerType::try_from(which).unwrap(); + assert_ne!(which, TimerType::NONE); + info!( + "setitimer: which {:?} ,curret_value {:#x}, old_value {:#x}", + which, current_value, old_value + ); + let task = current_task().unwrap(); + if old_value != 0 { + let timer = task.access_inner().get_timer(); + let itimer = ITimerVal { + it_interval: timer.timer_interval.into(), + it_value: timer.timer_remained.into(), + }; + task.access_inner() + .copy_to_user(&itimer, old_value as *mut ITimerVal); + } + assert_ne!(current_value, 0); + let mut itimer = ITimerVal::default(); + task.access_inner() + .copy_from_user(current_value as *const ITimerVal, &mut itimer); + info!("setitimer: itimer {:x?}", itimer); + task.access_inner().set_timer(itimer, which); + 0 +} + +/// 一个系统调用函数,可以根据输入的时钟类型`clock_id`来获取该时钟分辨率(精度),获取的精度将存储在`res`所指向的[`TimeSpec`]结构处。 +/// 时钟的分辨率取决于实现方式,无法由特定进程配置。目前Alien仅支持`Monotonic`一种时钟类型。 +/// +/// Reference: [clock_getres](https://www.man7.org/linux/man-pages/man3/clock_getres.3.html) +#[syscall_func(114)] +pub fn clock_getres(id: usize, res: usize) -> isize { + let id = ClockId::from_raw(id).unwrap(); + info!("clock_getres: id {:?} ,res {:#x}", id, res); + let task = current_task().unwrap(); + let time_res = match id { + ClockId::Monotonic => { + let time = TimeSpec::new(0, 1); + time + } + _ => { + panic!("clock_get_time: clock_id {:?} not supported", id); + } + }; + task.access_inner() + .copy_to_user(&time_res, res as *mut TimeSpec); + 0 +} + +/// 一个系统调用函数,如`nanosleep`一样,暂停本进程直到一段时间后结束,但`clock_nanosleep`可以根据传入的`clock_id`来指定使用的时钟类型。 +/// +/// 要暂停的时间将保存在`req`所指向的[`TimeSpec`]结构处。目前仅支持`Monotonic`,输入其它时钟类型将会返回使得进程panic。 +/// 如`nanosleep`一样,在`clock_nanosleep`执行过程中,本进程也有可能被其他信号唤醒。 +/// +/// 函数若正常停止`req`时间则返回0;如果由于因为其他信号而被唤醒,此时函数返回-1(EINTR)。 +/// +/// Reference: [times](https://man7.org/linux/man-pages/man2/times.2.html) +#[syscall_func(115)] +pub fn clock_nanosleep(clock_id: usize, flags: usize, req: usize, remain: usize) -> isize { + const TIMER_ABSTIME: usize = 1; + let id = ClockId::from_raw(clock_id).unwrap(); + info!( + "clock_nanosleep: id {:?} ,flags {:#x}, req {:#x}, remain {:#x}", + id, flags, req, remain + ); + match id { + ClockId::Monotonic => { + assert_eq!(flags, TIMER_ABSTIME); + let mut target_time = TimeSpec::new(0, 0); + let task = current_task().unwrap().clone(); + task.access_inner() + .copy_from_user(req as *const TimeSpec, &mut target_time); + let end_time = target_time.to_clock(); + + loop { + let now = read_timer(); + if now >= end_time { + break; + } + do_suspend(); + // check signal + let task_inner = task.access_inner(); + let receiver = task_inner.signal_receivers.lock(); + if receiver.have_signal() { + return LinuxErrno::EINTR.into(); + } + } + } + _ => { + panic!("clock_nanotime: clock_id {:?} not supported", id); + } + } + 0 +} diff --git a/kernel/src/timer/mod.rs b/kernel/src/timer/mod.rs deleted file mode 100644 index d353fe38..00000000 --- a/kernel/src/timer/mod.rs +++ /dev/null @@ -1,467 +0,0 @@ -//! Alien 中的有关时钟、计时器的结构 以及 一些计时器的系统调用。 -//! -//! 在对系统时间的记录上,Alien 中使用 [`TimeVal`] 记录 (秒,微秒) 的时间,使用 [`TimeSpec`] 记录 更精细的 (秒,纳秒) 的时间; -//! 在对进程的运行时间的记录上,使用 [`Times`] 结构记录进程运行的时间,记录的信息包括程序在用户态、内核态下分别运行的时间, -//! 其子进程运行的总时间等,在任务控制块中记录相应数据的结构为 [`StatisticalData`]。 -//! -//! 计时器方面, [`Timer`] 结构为实际放入计时器队列 [`TIMER_QUEUE`] 中的计时器结构。 -//! 当发生时钟中断时,会检查所有计时器队列中的计时器是否超时,具体可见 [`check_timer_queue`]。 -//! [`ITimerVal`] 结构为系统调用 [`getitimer`] / [`setitimer`] 指定的类型,用户执行系统调用时获取和输入时需要为该种类型的计时器, -//! 在任务控制块中记录相应数据的字段为 `timer`(结构为 `TaskTimer` )。 -//! -//! 对于时间片 (每次引发时钟中断的时间间隔) 大小的设计:目前 Alien 中用户态和内核态下采用相同的时间片间隔,1s 内触发 10 次时钟中断。 -use alloc::collections::BinaryHeap; -use alloc::sync::Arc; -use core::cmp::Ordering; - -use crate::config::CLOCK_FREQ; -use crate::task::{current_task, do_suspend, StatisticalData, Task, GLOBAL_TASK_MANAGER}; -use constants::sys::TimeVal; -use constants::time::{ClockId, TimerType}; -use constants::LinuxErrno; -use ksync::Mutex; -use smpscheduler::FifoTask; -use spin::Lazy; -use syscall_table::syscall_func; -use vfscore::utils::VfsTimeSpec; - -/// 每秒包含的 时间片 数,每隔一个时间片,就会产生一个时钟中断 -const TICKS_PER_SEC: usize = 10; -// const TICKS_PER_SEC_IN_KERNEL: usize = 1000; - -/// 每秒包含的毫秒数 -const MSEC_PER_SEC: usize = 1000; - -/// 程序运行时间 -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Times { - /// the ticks of user mode - pub tms_utime: usize, - /// the ticks of kernel mode - pub tms_stime: usize, - /// the ticks of user mode of child process - pub tms_cutime: usize, - /// the ticks of kernel mode of child process - pub tms_cstime: usize, -} - -impl Times { - /// 创建一个各字段值都为 0 的新 `Times` 变量 - pub fn new() -> Self { - Self { - tms_utime: 0, - tms_stime: 0, - tms_cutime: 0, - tms_cstime: 0, - } - } - - /// 从一个 [`StatisticalData`] 结构 (一般为 task 的 statistical_data 字段) 得到一个 `Times` 变量 - pub fn from_process_data(data: &StatisticalData) -> Self { - Self { - tms_stime: data.tms_stime, - tms_utime: data.tms_utime, - tms_cstime: data.tms_cstime, - tms_cutime: data.tms_cutime, - } - } -} - -/// 实现 `TimeNow` 特征的时钟结构,能够通过调用 `now` 方法得出 表示当前的 cpu 时间的一个本类型时钟 -pub trait TimeNow { - fn now() -> Self; -} - -/// 实现 `ToClock` 特征的时钟结构,能够将所表示的时间间隔,转换为 cpu 时钟 -pub trait ToClock { - fn to_clock(&self) -> usize; -} - -/// 实现 `TimeFromFreq` 特征的时钟结构,能够实现从 cpu时钟跳变的次数 初始化一个本类型的时钟 -pub trait TimeFromFreq { - fn from_freq(freq: usize) -> Self; -} - -impl TimeNow for TimeVal { - fn now() -> Self { - let time = read_timer(); - Self { - tv_sec: time / CLOCK_FREQ, - tv_usec: (time % CLOCK_FREQ) * 1000000 / CLOCK_FREQ, - } - } -} - -impl ToClock for TimeVal { - fn to_clock(&self) -> usize { - self.tv_sec * CLOCK_FREQ + self.tv_usec * CLOCK_FREQ / 1000_000 - } -} - -impl TimeFromFreq for TimeVal { - fn from_freq(freq: usize) -> Self { - Self { - tv_sec: freq / CLOCK_FREQ, - tv_usec: (freq % CLOCK_FREQ) * 1000000 / CLOCK_FREQ, - } - } -} - -/// 更精细的时间,秒(s)+纳秒(ns) -#[repr(C)] -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct TimeSpec { - pub tv_sec: usize, - pub tv_nsec: usize, //0~999999999 -} - -impl TimeSpec { - /// 创建一个新的 [`TimeSpec`] 时钟 - pub fn new(sec: usize, ns: usize) -> Self { - Self { - tv_sec: sec, - tv_nsec: ns, - } - } - - /// 获取一个可以表示当前 cpu 时间的一个 [`TimeSpec`] 时钟 - pub fn now() -> Self { - let time = read_timer(); - Self { - tv_sec: time / CLOCK_FREQ, - tv_nsec: (time % CLOCK_FREQ) * 1000000000 / CLOCK_FREQ, - } - } - - /// 将本时钟所表示的时间间隔转化为 cpu 上时钟的跳变数 - pub fn to_clock(&self) -> usize { - self.tv_sec * CLOCK_FREQ + self.tv_nsec * CLOCK_FREQ / 1000_000_000 - } -} - -impl TimeFromFreq for TimeSpec { - fn from_freq(freq: usize) -> Self { - Self { - tv_sec: freq / CLOCK_FREQ, - tv_nsec: (freq % CLOCK_FREQ) * 1000000000 / CLOCK_FREQ, - } - } -} - -impl Into for TimeSpec { - fn into(self) -> VfsTimeSpec { - VfsTimeSpec::new(self.tv_sec as u64, self.tv_nsec as u64) - } -} - -/// [`getitimer`] / [`setitimer`] 指定的类型,用户执行系统调用时获取和输入的计时器 -#[repr(C)] -#[derive(Debug, Copy, Clone, Default)] -pub struct ITimerVal { - /// 计时器超时间隔 - pub it_interval: TimeVal, - /// 计时器当前所剩时间 - pub it_value: TimeVal, -} - -/// 获取当前计时器的值 -#[inline] -pub fn read_timer() -> usize { - arch::read_timer() -} - -/// 设置下一次时钟的中断 -#[inline] -pub fn set_next_trigger() { - let next = read_timer() + CLOCK_FREQ / TICKS_PER_SEC; - assert!(next > read_timer()); - crate::sbi::set_timer(next); -} - -/// 设置内核态中下一次时钟的中断 -/// -/// 原设计为内核态下的时间片设置的更短一些,以免一个进程在进入内核态前后占用过多的时间片。但目前修改为 内核态和用户态下的时间片大小相同。 -#[inline] -pub fn set_next_trigger_in_kernel() { - let next = read_timer() + CLOCK_FREQ / TICKS_PER_SEC; - assert!(next > read_timer()); - crate::sbi::set_timer(next); -} - -/// 获取当前时间,以 ms 为单位 -pub fn get_time_ms() -> isize { - (read_timer() / (CLOCK_FREQ / MSEC_PER_SEC)) as isize -} - -/// 一个系统调用函数,获取当前的时间,获取的时间将存储在`tv`所指向的[`TimeVal`]结构处。 -/// 执行成功则返回0。 -/// -/// Reference: [get_time_of_day](https://man7.org/linux/man-pages/man2/gettimeofday.2.html) -#[syscall_func(169)] -pub fn get_time_of_day(tv: *mut u8) -> isize { - let time = TimeVal::now(); - let process = current_task().unwrap(); - let tv = process.transfer_raw_ptr(tv as *mut TimeVal); - *tv = time; - 0 -} - -/// 一个系统调用函数,获取当前进程在用户态/内核态下运行的时间、最后一次运行在用户态/内核态下的时间等, -/// 获取的信息将保存在`tms`所指向的[`Times`]结构处。执行成功返回0。 -/// -/// Reference: [times](https://man7.org/linux/man-pages/man2/times.2.html) -#[syscall_func(153)] -pub fn times(tms: *mut u8) -> isize { - let mut task = current_task().unwrap().access_inner(); - let statistic_data = task.statistical_data(); - let time = Times::from_process_data(statistic_data); - task.copy_to_user(&time, tms as *mut Times); - 0 -} - -/// 一个系统调用函数,暂停本进程直到一段时间后结束,要暂停的时间将保存在`req`所指向的[`TimeSpec`]结构处。 -/// 但在`nanosleep`执行过程中,本进程有可能被其他信号唤醒。 -/// 函数若正常停止`req`时间则返回0;如果由于因为其他信号而被唤醒,此时函数返回-1(EINTR)。 -/// -/// Reference: [nanosleep](https://man7.org/linux/man-pages/man2/nanosleep.2.html) -#[syscall_func(101)] -pub fn nanosleep(req: *mut u8, _: *mut u8) -> isize { - let task = current_task().unwrap().clone(); - let mut time = TimeSpec::new(0, 0); - task.access_inner() - .copy_from_user(req as *const TimeSpec, &mut time); - warn!("nanosleep: {:?}", time); - let end_time = read_timer() + time.to_clock(); - loop { - if read_timer() >= end_time { - break; - } - do_suspend(); - // interrupt by signal - let task_inner = task.access_inner(); - let receiver = task_inner.signal_receivers.lock(); - if receiver.have_signal() { - return LinuxErrno::EINTR as isize; - } - } - - 0 -} - -/// 一个系统调用函数,可以根据输入的时钟类型`clock_id`来获取当前的时间,获取的时间将存储在`tp`所指向的[`TimeSpec`]结构处。 -/// -/// 目前仅支持`Monotonic`、`Realtime`和`ProcessCputimeId`三种时钟类型,均会返回当前的系统时间。 -/// 执行成功则返回0;当所输入的`clock_id`不在`Monotonic`、`Realtime`和`ProcessCputimeId`中时,进程将会被panic。 -/// -/// Reference: [clock_get_time](https://www.man7.org/linux/man-pages/man3/clock_gettime.3.html) -#[syscall_func(113)] -pub fn clock_get_time(clock_id: usize, tp: *mut u8) -> isize { - let id = ClockId::from_raw(clock_id).unwrap(); - let task = current_task().unwrap(); - match id { - ClockId::Monotonic | ClockId::Realtime | ClockId::ProcessCputimeId => { - let time = TimeSpec::now(); - task.access_inner().copy_to_user(&time, tp as *mut TimeSpec) - } - _ => { - panic!("clock_get_time: clock_id {:?} not supported", id); - } - } - 0 -} - -/// 实际放入计时器队列中的计时器结构。 -/// -/// 当发生时钟中断时,会检查所有计时器队列中的计时器是否超时,具体可见 [`check_timer_queue`] -#[derive(Debug)] -pub struct Timer { - /// 计时器超时时间 - end_time: usize, - /// 在该计时器上进行等待的进程 - process: Arc, -} - -impl Timer { - /// 通过传入的 超时时间 和 等待进程的控制块 创建一个新的 `Timer` 结构 - pub fn new(end_time: usize, process: Arc) -> Self { - Self { end_time, process } - } - - /// 获取等待在该计时器上的进程的控制块信息 - pub fn get_task(&self) -> &Arc { - &self.process - } -} - -impl PartialEq for Timer { - fn eq(&self, other: &Self) -> bool { - self.end_time == other.end_time - } -} - -impl Eq for Timer {} - -impl PartialOrd for Timer { - fn partial_cmp(&self, other: &Self) -> Option { - // reverse order - Some(other.end_time.cmp(&self.end_time)) - } -} - -impl Ord for Timer { - fn cmp(&self, other: &Self) -> Ordering { - // reverse order - other.end_time.cmp(&self.end_time) - } -} - -/// 存储所有当前处于等待状态的计时器,是一个二叉树结构。 -/// -/// 保证存储在该队列中的计时器,按照超时时间 由先到后 的次序排列。 -pub static TIMER_QUEUE: Lazy>> = - Lazy::new(|| Mutex::new(BinaryHeap::new())); - -/// 将一个需要等待在 超时时间为 `end_time` 的计数器上的进程记录到计数器列表中 -pub fn push_to_timer_queue(process: Arc, end_time: usize) { - TIMER_QUEUE.lock().push(Timer::new(end_time, process)); -} - -/// 当发生时钟中断时,`trap_handler` 会调用该函数检查所有计时器队列中的计时器,并唤醒等待在这些计时器上的进程 -/// -/// 遍历所有计时器队列 [`TIMER_QUEUE`] 中的计时器,若计时器的超时时间在当前时间之前(即已超时),那么将该等待的进程加入 -/// 线程池的首位,马上对其进行调度。 -pub fn check_timer_queue() { - let now = read_timer(); - let mut queue = TIMER_QUEUE.lock(); - while let Some(timer) = queue.peek() { - if timer.end_time <= now { - let timer = queue.pop().unwrap(); - GLOBAL_TASK_MANAGER.put_prev_task(Arc::new(FifoTask::new(timer.process)), true); - } else { - break; - } - } -} - -/// 一个系统调用函数,用于获取当前进程的计时器,保存在`current_value`指向的[`ITimerVal`]结构处。 -/// 由于Alien目前每个进程只支持一个计时器,原定于分辨计时器种类的`_which`在此处并没有派上用场。 -/// 函数执行成功则返回0。 -/// Reference: [getitimer](https://man7.org/linux/man-pages/man2/setitimer.2.html) -#[syscall_func(102)] -pub fn getitimer(_which: usize, current_value: usize) -> isize { - let task = current_task().unwrap(); - let timer = &task.access_inner().timer; - let itimer = ITimerVal { - it_interval: timer.timer_interval, - it_value: timer.timer_remained.into(), - }; - task.access_inner() - .copy_to_user(&itimer, current_value as *mut ITimerVal); - 0 -} - -/// 一个系统调用函数,用于将当前进程的定时器设置为`current_value`指向的[`ITimerVal`]结构处, -/// 同时将旧计时器的信息保存在`old_value`指向的[`ITimerVal`]结构处。 -/// -/// `which`参数需为目前支持的[`TimerType`]类型且不为`NONE`,否则会导致进程被panic。 -/// 如果`current_value`为空,则会导致进程被panic。 -/// 如果`old_value`为空,则不进行保存旧计时器信息操作。 -/// -/// 函数执行正确则返回0。 -/// Reference: [setitimer](https://man7.org/linux/man-pages/man2/setitimer.2.html) -#[syscall_func(103)] -pub fn setitimer(which: usize, current_value: usize, old_value: usize) -> isize { - let which = TimerType::try_from(which).unwrap(); - assert_ne!(which, TimerType::NONE); - info!( - "setitimer: which {:?} ,curret_value {:#x}, old_value {:#x}", - which, current_value, old_value - ); - let task = current_task().unwrap(); - if old_value != 0 { - let timer = task.access_inner().get_timer(); - let itimer = ITimerVal { - it_interval: timer.timer_interval.into(), - it_value: timer.timer_remained.into(), - }; - task.access_inner() - .copy_to_user(&itimer, old_value as *mut ITimerVal); - } - assert_ne!(current_value, 0); - let mut itimer = ITimerVal::default(); - task.access_inner() - .copy_from_user(current_value as *const ITimerVal, &mut itimer); - info!("setitimer: itimer {:x?}", itimer); - task.access_inner().set_timer(itimer, which); - 0 -} - -/// 一个系统调用函数,可以根据输入的时钟类型`clock_id`来获取该时钟分辨率(精度),获取的精度将存储在`res`所指向的[`TimeSpec`]结构处。 -/// 时钟的分辨率取决于实现方式,无法由特定进程配置。目前Alien仅支持`Monotonic`一种时钟类型。 -/// -/// Reference: [clock_getres](https://www.man7.org/linux/man-pages/man3/clock_getres.3.html) -#[syscall_func(114)] -pub fn clock_getres(id: usize, res: usize) -> isize { - let id = ClockId::from_raw(id).unwrap(); - info!("clock_getres: id {:?} ,res {:#x}", id, res); - let task = current_task().unwrap(); - let time_res = match id { - ClockId::Monotonic => { - let time = TimeSpec::new(0, 1); - time - } - _ => { - panic!("clock_get_time: clock_id {:?} not supported", id); - } - }; - task.access_inner() - .copy_to_user(&time_res, res as *mut TimeSpec); - 0 -} - -/// 一个系统调用函数,如`nanosleep`一样,暂停本进程直到一段时间后结束,但`clock_nanosleep`可以根据传入的`clock_id`来指定使用的时钟类型。 -/// -/// 要暂停的时间将保存在`req`所指向的[`TimeSpec`]结构处。目前仅支持`Monotonic`,输入其它时钟类型将会返回使得进程panic。 -/// 如`nanosleep`一样,在`clock_nanosleep`执行过程中,本进程也有可能被其他信号唤醒。 -/// -/// 函数若正常停止`req`时间则返回0;如果由于因为其他信号而被唤醒,此时函数返回-1(EINTR)。 -/// -/// Reference: [times](https://man7.org/linux/man-pages/man2/times.2.html) -#[syscall_func(115)] -pub fn clock_nanosleep(clock_id: usize, flags: usize, req: usize, remain: usize) -> isize { - const TIMER_ABSTIME: usize = 1; - let id = ClockId::from_raw(clock_id).unwrap(); - info!( - "clock_nanosleep: id {:?} ,flags {:#x}, req {:#x}, remain {:#x}", - id, flags, req, remain - ); - let task = current_task().unwrap().clone(); - match id { - ClockId::Monotonic => { - assert_eq!(flags, TIMER_ABSTIME); - let mut target_time = TimeSpec::new(0, 0); - task.access_inner() - .copy_from_user(req as *const TimeSpec, &mut target_time); - let end_time = target_time.to_clock(); - - loop { - let now = read_timer(); - if now >= end_time { - break; - } - do_suspend(); - // check signal - let task_inner = task.access_inner(); - let receiver = task_inner.signal_receivers.lock(); - if receiver.have_signal() { - return LinuxErrno::EINTR.into(); - } - } - } - _ => { - panic!("clock_nanotime: clock_id {:?} not supported", id); - } - } - 0 -} diff --git a/kernel/src/trace/mod.rs b/kernel/src/trace/mod.rs deleted file mode 100644 index 5e0ad98d..00000000 --- a/kernel/src/trace/mod.rs +++ /dev/null @@ -1,57 +0,0 @@ -use core::arch::global_asm; - -extern "C" { - #[allow(unused)] - fn symbol_num(); - #[allow(unused)] - fn symbol_address(); - #[allow(unused)] - fn symbol_index(); - #[allow(unused)] - fn symbol_name(); -} - -global_asm!(include_str!("kernel_symbol.S")); - -pub fn find_symbol_with_addr(addr: usize) -> Option<(usize, &'static str)> { - let symbol_num_addr = symbol_num as usize as *const usize; - let symbol_num = unsafe { symbol_num_addr.read_volatile() }; - if symbol_num == 0 { - return None; - } - let symbol_addr = symbol_address as usize as *const usize; // 符号地址存储区域 - let addr_data = unsafe { core::slice::from_raw_parts(symbol_addr, symbol_num) }; - // find the symbol with the nearest address - let mut index = -1isize; - for i in 0..symbol_num - 1 { - if addr >= addr_data[i] && addr < addr_data[i + 1] { - index = i as isize; - break; - } - } - if addr == addr_data[symbol_num - 1] { - index = (symbol_num - 1) as isize; - } - if index == -1 { - return None; - } - let index = index as usize; - let symbol_index = symbol_index as usize as *const usize; // 符号字符串的起始位置 - let index_data = unsafe { core::slice::from_raw_parts(symbol_index, symbol_num) }; - let symbol_name = symbol_name as usize as *const u8; // 符号字符串 - let mut last = 0; - unsafe { - for i in index_data[index].. { - let c = symbol_name.add(i); - if *c == 0 { - last = i; - break; - } - } - } - let name = unsafe { - core::slice::from_raw_parts(symbol_name.add(index_data[index]), last - index_data[index]) - }; - let name = core::str::from_utf8(name).unwrap(); - Some((addr_data[index], name)) -} diff --git a/kernel/src/trap/context.rs b/kernel/src/trap/context.rs index b8534fb2..5cf2bb4d 100644 --- a/kernel/src/trap/context.rs +++ b/kernel/src/trap/context.rs @@ -23,19 +23,6 @@ pub struct TrapFrame { } impl TrapFrame { - pub fn empty() -> Self { - Self { - x: [0; 32], - sepc: 0, - k_satp: 0, - k_sp: 0, - trap_handler: 0, - hart_id: 0, - sstatus: ExtSstatus::default(), - fg: [0; 2], - } - } - /// 获取当前的 Trap 帧下的 sstatus 寄存器的值 pub fn get_status(&self) -> ExtSstatus { self.sstatus diff --git a/kernel/src/trap/exception.rs b/kernel/src/trap/exception.rs index 6f768f58..2157327a 100644 --- a/kernel/src/trap/exception.rs +++ b/kernel/src/trap/exception.rs @@ -3,12 +3,12 @@ //! 目前包括系统调用异常处理 [`syscall_exception_handler`]、页错误异常处理 [`page_exception_handler`] (包括 //! 指令页错误异常处理 [`instruction_page_fault_exception_handler`]、 加载页错误异常处理[`load_page_fault_exception_handler`]、 //! 储存页错误异常处理 [`store_page_fault_exception_handler`]) 和 文件读入异常处理 [`trap_common_read_file`]。 -use crate::fs::file::File; use crate::task::{current_task, current_trap_frame}; use alloc::sync::Arc; use arch::interrupt_enable; use constants::{AlienError, AlienResult}; use riscv::register::scause::{Exception, Trap}; +use vfs::kfile::File; /// 系统调用异常处理 pub fn syscall_exception_handler() { @@ -21,9 +21,10 @@ pub fn syscall_exception_handler() { let parameters = cx.parameters(); let syscall_name = constants::syscall_name(parameters[0]); - let p_name = current_task().unwrap().get_name(); - let tid = current_task().unwrap().get_tid(); - let pid = current_task().unwrap().get_pid(); + let task = current_task().unwrap(); + let p_name = task.get_name(); + let tid = task.get_tid(); + let pid = task.get_pid(); if !p_name.contains("shell") && !p_name.contains("init") && !p_name.contains("ls") { // ignore shell and init info!( @@ -144,14 +145,13 @@ pub fn store_page_fault_exception_handler(addr: usize) -> AlienResult<()> { /// 文件读入异常处理 pub fn trap_common_read_file(file: Arc, buf: &mut [u8], offset: u64) { - error!( + info!( "trap_common_read_file buf.len: {}, offset:{:#x}", buf.len(), offset ); - // let r = vfs_read_file::(file.get_file(), buf, offset); let r = file.read_at(offset, buf); if r.is_err() { - error!("page fault: read file error"); + info!("page fault: read file error"); } } diff --git a/kernel/src/trap/interrupt.rs b/kernel/src/trap/interrupt.rs index 5b73a731..12daafdb 100644 --- a/kernel/src/trap/interrupt.rs +++ b/kernel/src/trap/interrupt.rs @@ -1,10 +1,10 @@ //! Alien 的外部中断处理 //! //! 目前仅有时钟中断处理函数。 -use crate::interrupt::record::write_irq_info; use crate::ipc::solve_futex_wait; use crate::task::do_suspend; -use crate::timer::{check_timer_queue, set_next_trigger}; +use crate::time::{check_timer_queue, set_next_trigger}; +use interrupt::record::write_irq_info; /// 时钟中断处理函数 pub fn timer_interrupt_handler() { diff --git a/kernel/src/trap/mod.rs b/kernel/src/trap/mod.rs index ae42a8c4..528723e4 100644 --- a/kernel/src/trap/mod.rs +++ b/kernel/src/trap/mod.rs @@ -1,7 +1,5 @@ -use core::arch::{asm, global_asm}; - use bit_field::BitField; -use page_table::addr::VirtAddr; +use core::arch::{asm, global_asm}; use riscv::register::sstatus::SPP; use riscv::register::{sepc, sscratch, sstatus, stval, stvec}; @@ -11,17 +9,16 @@ use constants::time::TimerType; pub use context::TrapFrame; pub use exception::trap_common_read_file; -use crate::config::TRAMPOLINE; -use crate::interrupt::external_interrupt_handler; -use crate::interrupt::record::write_irq_info; use crate::ipc::{send_signal, signal_handler, signal_return, solve_futex_wait}; -use crate::memory::KERNEL_SPACE; use crate::task::{current_task, current_trap_frame, current_user_token, do_exit, do_suspend}; -use crate::timer::{check_timer_queue, set_next_trigger, set_next_trigger_in_kernel}; +use crate::time::{check_timer_queue, set_next_trigger, set_next_trigger_in_kernel}; +use ::interrupt::external_interrupt_handler; +use ::interrupt::record::write_irq_info; use arch::{ - external_interrupt_enable, hart_id, interrupt_disable, interrupt_enable, is_interrupt_enable, + external_interrupt_enable, interrupt_disable, interrupt_enable, is_interrupt_enable, timer_interrupt_enable, }; +use config::TRAMPOLINE; use constants::AlienError; use riscv::register::scause::{Exception, Interrupt, Trap}; use riscv::register::stvec::TrapMode; @@ -54,7 +51,6 @@ pub fn trap_return() -> ! { let sie = sstatues.0.get_bit(1); assert!(enable); assert!(!sie); - let trap_cx_ptr = current_task().unwrap().trap_frame_ptr(); let user_satp = current_user_token(); let restore_va = user_r as usize - user_v as usize + TRAMPOLINE; @@ -209,8 +205,7 @@ impl TrapHandler for Trap { self, stval, sepc ); { - let kernel_space = KERNEL_SPACE.read(); - let phy = kernel_space.query(VirtAddr::from(stval)); + let phy = mem::query_kernel_space(stval); debug!("physical address: {:#x?}", phy); } } @@ -257,12 +252,7 @@ pub fn user_trap_vector() { panic!("user_trap_vector: spp == SPP::Supervisor"); } { - let task = current_task().unwrap_or_else(|| { - panic!( - "can't find task in hart {}, but it's in user mode", - hart_id() as usize - ) - }); + let task = current_task().expect("user_trap_vector: current_task is none"); // update process statistics task.access_inner().update_user_mode_time(); check_task_timer_expired(); @@ -271,12 +261,12 @@ pub fn user_trap_vector() { let cause = riscv::register::scause::read(); let cause = cause.cause(); cause.do_user_handle(); - let process = current_task().unwrap(); + let task = current_task().unwrap(); if cause != Trap::Interrupt(Interrupt::SupervisorTimer) { // update process statistics - process.access_inner().update_kernel_mode_time(); + task.access_inner().update_kernel_mode_time(); } - process.access_inner().update_timer(); + task.access_inner().update_timer(); check_task_timer_expired(); trap_return(); } diff --git a/kkernel/Cargo.toml b/kkernel/Cargo.toml deleted file mode 100644 index 19eb13ad..00000000 --- a/kkernel/Cargo.toml +++ /dev/null @@ -1,56 +0,0 @@ -[package] -name = "kkernel" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -arch = { path = "../subsystems/arch" } -platform = { path = "../subsystems/platform" } -mem = { path = "../subsystems/mem" } -interrupt = { path = "../subsystems/interrupt" } -devices = { path = "../subsystems/devices" } -drivers = { path = "../subsystems/drivers" } -unwinder = { path = "../subsystems/unwinder" } -constants = { path = "../subsystems/constants" } -config = { path = "../subsystems/config" } -vfs = { path = "../subsystems/vfs" } -timer = { path = "../subsystems/timer" } -ksync = { path = "../subsystems/ksync" } - -gmanager = { path = "../dep/gmanager" } - - - - -riscv = "0.10" -bit_field = "0.10" -xmas-elf = "0.9" -bitflags = "1.3.2" -spin = "0" -log = "0" -vfscore = { git = "https://github.com/os-module/rvfs.git", features = [ - "linux_error", -] } -syscall-table = { git = "https://github.com/os-module/syscall-table.git" } -smpscheduler = { git = "https://github.com/os-module/smpscheduler.git" } -page-table = { git = "https://github.com/os-module/page-table.git", branch = "dev" } -downcast-rs = { version = "1.2.0", default-features = false } -netcore = {git = "https://github.com/os-module/simple-net"} - - -[features] -default = ["qemu","smp"] -qemu = ["platform/qemu_riscv","interrupt/qemu"] -vf2 = ["platform/vf2","interrupt/vf2"] -hifive = ["platform/hifive","interrupt/hifive"] -smp = ["platform/smp"] - - -slab = [] -talloc = [] -buddy = [] - -pager_buddy = [] -pager_bitmap = [] \ No newline at end of file diff --git a/kkernel/build.rs b/kkernel/build.rs deleted file mode 100644 index 615bef3e..00000000 --- a/kkernel/build.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::fs::File; -use std::io::Write; -use std::path::Path; -use std::{env, fs}; - -fn main() { - // 指定target - let outdir = env::var("OUT_DIR").unwrap(); - let link_script = Path::new(&outdir).join("link.lds"); - let mut script = File::create(&link_script).unwrap(); - - let ld_path = Path::new("../tools/link.ld"); - let ld = fs::read_to_string(ld_path).unwrap(); - - #[cfg(not(feature = "vf2"))] - let base_addr = 0x80200000usize; - #[cfg(feature = "vf2")] - let base_addr: usize = 0x40200000; - let base_addr = format!("BASE_ADDRESS = {};", base_addr); - let mut new_config = String::new(); - for line in ld.lines() { - if line.starts_with("BASE_ADDRESS = ") { - new_config.push_str(base_addr.as_str()); - } else { - new_config.push_str(line); - new_config.push_str("\n"); - } - } - - script.write_all(new_config.as_bytes()).unwrap(); - println!("cargo:rustc-link-arg=-T{}", &link_script.display()); -} diff --git a/kkernel/src/fs/basic.rs b/kkernel/src/fs/basic.rs deleted file mode 100644 index d463ed16..00000000 --- a/kkernel/src/fs/basic.rs +++ /dev/null @@ -1,714 +0,0 @@ -use super::im2vim; -use crate::fs::file::KernelFile; -use crate::fs::{syscontext_for_vfs, user_path_at}; -use crate::task::current_task; -use alloc::sync::Arc; -use alloc::vec; -use constants::io::{ - FileStat, FsStat, InodeMode, IoVec, MountFlags, OpenFlags, Renameat2Flags, SeekFrom, StatFlags, -}; -use constants::{AlienResult, AT_FDCWD}; -use constants::LinuxErrno; -use core::cmp::min; -use core::ops::Index; -use log::{info, warn}; -use gmanager::ManagerError; -use syscall_table::syscall_func; -use vfscore::path::VfsPath; -use vfscore::utils::{VfsFileStat, VfsFsStat, VfsNodeType, VfsRenameFlag}; -use vfs::{FS, SYSTEM_ROOT_FS}; - -/// 用于将一个设备(通常是存储设备)挂载到一个已经存在的目录上,可以挂载文件系统。 -#[syscall_func(40)] -pub fn sys_mount( - source: *const u8, - dir: *const u8, - fs_type: *const u8, - flags: usize, - data: *const u8, -) -> AlienResult { - let process = current_task().unwrap(); - let source = process.transfer_str(source); - let dir = process.transfer_str(dir); - let fs_type = process.transfer_str(fs_type); - assert!(data.is_null()); - let flags = MountFlags::from_bits(flags as u32).unwrap(); - info!( - "mount special:{:?},dir:{:?},fs_type:{:?},flags:{:?},data:{:?}", - source, dir, fs_type, flags, data - ); - let find = FS - .lock() - .iter() - .find(|(name, _)| name.eq(&&fs_type)) - .map(|(_, fs)| fs.clone()) - .ok_or(LinuxErrno::EINVAL)?; - let path = VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()); - let fs_root = match find.fs_name() { - name @ ("tmpfs" | "ramfs" | "fat32") => { - let fs = FS.lock().index(name).clone(); - let dev = if name.eq("fat32") { - let dev = path.join(source)?.open(None)?; - Some(dev.inode()?) - } else { - None - }; - let new_fs = fs.i_mount(0, &dir, dev, &[])?; - new_fs - } - _ => return Err(LinuxErrno::EINVAL), - }; - path.join(dir)?.mount(fs_root, flags.bits())?; - Ok(0) -} - -/// 用于取消一个目录上的文件挂载(卸载一个文件系统)。 -#[syscall_func(39)] -pub fn sys_umount(dir: *const u8) -> AlienResult { - let process = current_task().unwrap(); - let dir = process.transfer_str(dir); - info!("umount dir:{:?}", dir); - let path = VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()); - path.join(dir)?.umount()?; - Ok(0) -} - -#[syscall_func(56)] -pub fn sys_openat(dirfd: isize, path: *const u8, flag: usize, mode: u32) -> AlienResult { - if path.is_null() { - return Err(LinuxErrno::EFAULT); - } - let flag = OpenFlags::from_bits_truncate(flag); - let file_mode = if flag.contains(OpenFlags::O_CREAT) { - Some(InodeMode::from_bits_truncate(mode)) - } else { - None - } - .map(|x| im2vim(x)); - let process = current_task().unwrap(); - - let _path = process.transfer_str(path); - let path = user_path_at(dirfd, &_path)?; - warn!( - "open file: dirfd:[{}], {:?},flag:{:?}, mode:{:?}", - dirfd, path, flag, file_mode - ); - - let dentry = path.open(file_mode)?; - let file = KernelFile::new(dentry, flag); - - let fd = process.add_file(Arc::new(file)); - warn!("openat fd: {:?}", fd); - if fd.is_err() { - let error = ManagerError::from((fd.unwrap_err()) as usize); - info!("[vfs] openat error: {:?}", error); - match error { - ManagerError::NoSpace => Err(LinuxErrno::EMFILE), - _ => Err(LinuxErrno::ENOMEM), - } - } else { - Ok(fd.unwrap() as isize) - } -} - -/// 一个系统调用,用于关闭一个文件描述符,以便回收该文件描述符。 -/// -/// 传入的文件描述符`fd`指向要关闭的文件。如果`fd`所指向的文件已经被`unlink`, -/// 那么在关闭文件描述符后,还将继续执行`unlink`,删除该文件链接,并回收相应的存储空间。 -/// -/// 如果`sys_close`成功关闭文件描述符,将返回0,否则-1或返回错误的类型。 -/// -/// Reference: [close](https://man7.org/linux/man-pages/man2/close.2.html) -#[syscall_func(57)] -pub fn sys_close(fd: usize) -> AlienResult { - let process = current_task().unwrap(); - let _file = process.remove_file(fd).map_err(|_| LinuxErrno::EBADF)?; - Ok(0) -} - -/// 一个系统调用,用于读取文件的目录项信息。 -/// -/// 参数: -/// + `fd`: 用于指明操作文件的文件描述符。 -/// + `buf`: 用于指明一块缓冲区,保存获取到的目录项信息。 -/// + `len`: 用于指明缓冲区的长度。 -/// -/// 若获取文件的目录项信息成功,则返回获取信息的长度(字节数);否则返回 -1 表示获取相关信息失败。 -/// -/// Reference: [sys_getdents](https://man7.org/linux/man-pages/man2/getdents.2.html) -#[syscall_func(61)] -pub fn sys_getdents(fd: usize, buf: *mut u8, len: usize) -> AlienResult { - info!("[getdents] fd: {}, buf size: {}", fd, len); - let process = current_task().unwrap(); - let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let user_bufs = process.transfer_buffer(buf, len); - let mut buf = vec![0u8; len]; - let len = file.readdir(buf.as_mut_slice())?; - info!("[getdents]: read len: {:?}", len); - let mut offset = 0; - // copy dirent_buf to user space - for user_buf in user_bufs { - let copy_len = user_buf.len(); // user_bufs len is equal to buf len - user_buf.copy_from_slice(&buf[offset..offset + copy_len]); - offset += copy_len; - if offset >= len { - break; - } - } - Ok(len as _) -} - -/// 一个系统调用,用于将一个文件的大小截断到一个指定长度。与 [`sys_ftruncate`] 功能类似。 -/// -/// `path` 用于指明要截断文件的路径,`len` 用于指明要截断到的长度。 -/// 当文件长度小于 `len` 时,多余的部分填充为'/0';当文件长度大于 `len` 时,多余的数据将会被直接舍弃。 -/// -/// 需保证该 `path` 所指出的文件必须是可写的。此外,该调用对于文件的偏移量 offset 将不会改变。 -/// -/// 当截断成功时,返回 0;否则返回 -1 表示截断出现错误。 -/// Reference: https://man7.org/linux/man-pages/man2/truncate64.2.html -#[syscall_func(45)] -pub fn sys_truncate(path: usize, len: usize) -> AlienResult { - let process = current_task().unwrap(); - let path = process.transfer_str(path as *const u8); - let path = user_path_at(AT_FDCWD, &path)?; - path.truncate(len as u64)?; - Ok(0) -} - -/// 一个系统调用,用于将一个文件的大小截断到一个指定长度。与 [`sys_truncate`] 功能类似。 -/// -/// `fd` 用于指明要截断文件的文件描述符,`len` 用于指明要截断到的长度。 -/// 当文件长度小于 `len` 时,多余的部分填充为'/0';当文件长度大于 `len` 时,多余的数据将会被直接舍弃。 -/// -/// 需保证该 `fd` 所指出的文件必须是打开的。此外,该调用对于文件的偏移量 offset 将不会改变。 -/// -/// 当截断成功时,返回 0;否则返回 -1 表示截断出现错误。 -/// Reference: https://man7.org/linux/man-pages/man2/truncate64.2.html -#[syscall_func(46)] -pub fn sys_ftruncate(fd: usize, len: usize) -> AlienResult { - let process = current_task().unwrap(); - let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - file.truncate(len as u64)?; - Ok(0) -} - -/// 一个系统调用,用于从一个打开的文件描述符中读取文件内容。对于每个打开的文件描述符都具有一个偏移量,读取将从该偏移位置开始。 -/// -/// `fd` 指明了要读取并且已经打开的文件的文件描述符,`buf` 指明了读取内容后所要保存的位置, -/// `len` 指明了缓冲区 `buf` 的大小(即最多读取的内容长度) -/// -/// 读取完成后,将返回读取内容的长度(字节数);如果发生错误,将返回错误类型。 -#[syscall_func(63)] -pub fn sys_read(fd: usize, buf: *mut u8, len: usize) -> AlienResult { - let process = current_task().unwrap(); - let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - info!("read file: {:?}, len:{:?}", fd, len); - let mut buf = process.transfer_buffer(buf, len); - - let mut count = 0; - for b in buf.iter_mut() { - let r = file.read(b)?; - count += r; - if r != b.len() { - break; - } - } - - Ok(count as _) -} - -/// 一个系统调用,用于向一个打开的文件描述符中写入内容。对于每个打开的文件描述符都具有一个偏移量,写入将从该偏移位置开始。 -/// -/// `fd` 指明了要写入并且已经打开的文件的文件描述符,`buf` 指明了要写入的内容在内存中保存的位置, -/// `len` 指明了缓冲区 `buf` 的大小(即所要写入的内容长度) -/// -/// 写入完成后,将返回写入内容的长度(字节数);如果发生错误,将返回错误类型。 -#[syscall_func(64)] -pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> AlienResult { - let process = current_task().unwrap(); - let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let mut buf = process.transfer_buffer(buf, len); - let mut count = 0; - for b in buf.iter_mut() { - let w = file.write(b)?; - count += w; - if w != b.len() { - break; - } - } - Ok(count as _) -} - -/// 一个系统调用,用于获取当前工作目录。 -/// 获取的工作目录将直接保存在 `buf` 所指向的缓冲区中,`len` 用于指明 `buf` 的长度。 -/// -/// 获取当前目录成功后,返回 `buf` 的首地址。当 `buf` 为空指针时,会导致函数 panic。 -#[syscall_func(17)] -pub fn sys_getcwd(buf: *mut u8, len: usize) -> isize { - info!("getcwd: {:?}, len: {:?}", buf, len); - assert!(!buf.is_null()); - let task = current_task().unwrap(); - let cwd = task.access_inner().cwd(); - - let mut buf = task.transfer_buffer(buf, len); - let mut count = 0; - let path = cwd.cwd.path(); - let mut cwd = path.as_bytes(); - buf.iter_mut().for_each(|buf| { - // fill buf - if !cwd.is_empty() { - let min = min(cwd.len(), buf.len()); - buf[..min].copy_from_slice(&cwd[..min]); - count += min; - cwd = &cwd[min..]; - } - }); - buf[0].as_ptr() as isize -} - -/// 一个系统调用,用于切换当前工作目录。`path` 指出要切换到的工作目录。 -/// -/// 切换工作目录成功后,将返回 0;当输入的 path 不是一个合法的目录项时,会返回 -1 表示切换目录错误。 -#[syscall_func(49)] -pub fn sys_chdir(path: *const u8) -> AlienResult { - let process = current_task().unwrap(); - let path = process.transfer_str(path); - let dt = user_path_at(AT_FDCWD, &path)?.open(None)?; - - if dt.inode()?.inode_type() != VfsNodeType::Dir { - return Err(LinuxErrno::ENOTDIR); - } - let fs = dt.inode()?.get_super_block()?.fs_type(); - info!( - "chdir: {:?} fs: {}, parent:{:?}", - dt.name(), - fs.fs_name(), - dt.parent().is_some() - ); - process.access_inner().fs_info.cwd = dt; - Ok(0) -} - -/// Like [`sys_chdir`], but uses a file descriptor instead of a path. -#[syscall_func(50)] -pub fn sys_fchdir(fd: usize) -> AlienResult { - let process = current_task().unwrap(); - let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let dt = file.dentry(); - if dt.inode()?.inode_type() != VfsNodeType::Dir { - return Err(LinuxErrno::ENOTDIR); - } - info!("fchdir: {:?}", dt.path()); - process.access_inner().fs_info.cwd = dt; - Ok(0) -} - -/// 一个系统调用,用于在 相对于一个目录某位置处 路径下创建一个空的目录。功能与 [`sys_mkdir`] 相似。 -/// -/// 有关对 `dirfd` 和 `mode` 的解析规则以及 flag 的相关设置可见 [`sys_openat`]。成功创建目录则返回 0;否则返回错误码。 -/// -/// Reference: [mkdirat](https://man7.org/linux/man-pages/man2/mkdirat.2.html) -#[syscall_func(34)] -pub fn sys_mkdirat(dirfd: isize, path: *const u8, mode: u32) -> AlienResult { - let process = current_task().unwrap(); - let path = process.transfer_str(path); - let mut mode = InodeMode::from_bits_truncate(mode); - warn!("mkdirat path: {}, mode: {:?}", path, mode); - let path = user_path_at(dirfd, &path)?; - mode |= InodeMode::DIR; - assert_eq!(mode & InodeMode::TYPE_MASK, InodeMode::DIR); - let _ = path.open(Some(im2vim(mode)))?; - Ok(0) -} - -/// 一个系统调用,用于调整一个已经打开的文件描述符的偏移量。文件描述符的偏移量用于确定读写文件时操作的位置。 -/// -/// 参数: -/// + `fd`: 指明要操作的文件描述符; -/// + `offset`: 指明要调整的偏移量,实际要调整到的位置和 `whence` 的取值有关。 -/// + `whence`: 用于定义参数 offset 偏移量对应的参考值,可以取的值及其含义如下:(详情可见 [`SeekFrom`]) -/// + `SEEK_SET`: 读写偏移量将指向 offset 字节位置处(从文件头部开始算); -/// + `SEEK_CUR`: 读写偏移量将指向当前位置偏移量 + offset 字节位置处, offset 可以为正、也可以为负,如果是正数表示往后偏移,如果是负数则表示往前偏移; -/// + `SEEK_END`: 读写偏移量将指向文件末尾 + offset 字节位置处,同样 offset 可以为正、也可以为负,如果是正数表示往后偏移、如果是负数则表示往前偏移。 -/// -/// 调整成功后,将返回从文件头部开始算起的位置偏移量(字节为单位),也就是当前的读写位置;发生错误将返回错误码, -#[syscall_func(62)] -pub fn sys_lseek(fd: usize, offset: isize, whence: usize) -> AlienResult { - let process = current_task().unwrap(); - let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let seek = SeekFrom::try_from((whence, offset as usize)).unwrap(); - let r = file.seek(seek).map(|x| x as isize)?; - Ok(r) -} - -/// 一个系统调用,用于向一个打开的文件描述符中写入内容,写入的内容将用一组缓冲区给出。 -/// 对于每个打开的文件描述符都具有一个偏移量,写入将从该偏移位置开始。 -/// -/// `fd` 指明了要执行写入操作并且已经打开的文件的文件描述符,`iovec` 指明了该组缓冲区向量的首地址, -/// `iovcnt` 指明了缓冲区向量的长度,即在这组缓冲区向量包含了多少个缓冲区。(每个缓冲区的大小,通过调用 IoVec::len() 来获取) -/// -/// 写入完成后,将返回写入内容的长度(字节数);如果发生错误,将返回错误类型。 -#[syscall_func(66)] -pub fn sys_writev(fd: usize, iovec: usize, iovcnt: usize) -> AlienResult { - let process = current_task().unwrap(); - let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let mut count = 0; - for i in 0..iovcnt { - let mut iov = IoVec::empty(); - let ptr = unsafe { (iovec as *mut IoVec).add(i) }; - process.access_inner().copy_from_user(ptr, &mut iov); - let base = iov.base; - if base as usize == 0 { - // busybox 可能会给stdout两个io_vec,第二个是空地址 - continue; - } - let len = iov.len; - let buf = process.transfer_buffer(base, len); - for b in buf.iter() { - let r = file.write(b)?; - count += r; - } - } - Ok(count as isize) -} - -/// 一个系统调用,用于从一个打开的文件描述符中读取文件内容,将读取到的文件内容保存到一组缓冲区中。 -/// 对于每个打开的文件描述符都具有一个偏移量,读取将从该偏移位置开始。 -/// -/// `fd` 指明了要读取并且已经打开的文件的文件描述符,`iovec` 指明了该组缓冲区向量的首地址, -/// `iovcnt` 指明了缓冲区向量的长度,即在这组缓冲区向量包含了多少个缓冲区。(每个缓冲区的大小,通过调用 IoVec::len() 来获取) -/// -/// 读取完成后,将返回所有被读取内容的总长度(字节数)。 -#[syscall_func(65)] -pub fn sys_readv(fd: usize, iovec: usize, iovcnt: usize) -> AlienResult { - let task = current_task().unwrap(); - let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let mut count = 0; - for i in 0..iovcnt { - let ptr = unsafe { (iovec as *mut IoVec).add(i) }; - let iov = task.transfer_raw_ptr(ptr); - let base = iov.base; - if base as usize == 0 || iov.len == 0 { - continue; - } - let len = iov.len; - let mut buf = task.transfer_buffer(base, len); - for b in buf.iter_mut() { - info!("read file: {:?}, len:{:?}", fd, b.len()); - let r = file.read(b)?; - count += r; - } - } - Ok(count as isize) -} - -/// 一个系统调用,用于从一个打开的文件描述符中读取文件内容。与 [`sys_read`] 不同,该调用将指定一个偏移量 `offset`,读取将从该偏移位置开始。 -/// -/// `fd` 指明了要读取并且已经打开的文件的文件描述符,`buf` 指明了读取内容后所要保存的位置, -/// `len` 指明了缓冲区 `buf` 的大小(即最多读取的内容长度),`offset` 指明开始读取位置的偏移量。 -/// -/// 读取完成后,将返回读取内容的长度(字节数)。 -#[syscall_func(67)] -pub fn sys_pread(fd: usize, buf: usize, count: usize, offset: u64) -> AlienResult { - let task = current_task().unwrap(); - let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let mut buf = task.transfer_buffer(buf as *mut u8, count); - let mut offset = offset; - let mut count = 0; - for b in buf.iter_mut() { - let r = file.read_at(offset, b)?; - count += r; - offset += r as u64; - } - Ok(count as isize) -} - -/// 一个系统调用,用于向一个打开的文件描述符中写入内容。与 [`sys_write`] 不同,该调用将指定一个偏移量 `offset`,写入将从该偏移位置开始。 -/// -/// `fd` 指明了要写入并且已经打开的文件的文件描述符,`buf` 指明了要写入的内容在内存中保存的位置, -/// `count` 指明了缓冲区 `buf` 的大小(即所要写入的内容长度) -/// -/// 写入完成后,将返回写入内容的长度(字节数);如果发生错误(如输入的 fd 不合法等),将返回 -1。 -#[syscall_func(68)] -pub fn sys_pwrite(fd: usize, buf: usize, count: usize, offset: u64) -> AlienResult { - let task = current_task().unwrap(); - let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let buf = task.transfer_buffer(buf as *mut u8, count); - let mut offset = offset; - let mut count = 0; - for b in buf.iter() { - let r = file.write_at(offset, b)?; - count += r; - offset += r as u64; - } - - Ok(count as isize) -} - -/// 一个系统调用,用于获取文件的相关信息。功能与 [`sys_fstat`] 类似。 -/// -/// `sys_fstateat` 中要获取信息的文件 由 `dir_fd` 和 `path` 解析得出。Alien 中有关 `fd` 和 `path` 的路径解析可见 [`user_path_at`]。 -/// 获取的信息会保存在 `stat` 指向的 [`FileStat`] 结构中,`flag` 是一组标志位,用于定义相关的操作类型,具体可见 [`StatFlags`]。 -/// -/// 获取相关信息成功后,函数返回 0;否则函数会返回 -1 表示获取信息出错。 -/// 如果输入的 `stat` 为空指针,那么会导致函数 panic。 -/// -/// Reference: https://man7.org/linux/man-pages/man2/newfstatat.2.html -#[syscall_func(79)] -pub fn sys_fstateat( - dir_fd: isize, - path: *const u8, - stat: *mut u8, - flag: usize, -) -> AlienResult { - let process = current_task().unwrap(); - let path = process.transfer_str(path); - let flag = StatFlags::from_bits_truncate(flag as u32); - warn!("sys_fstateat: path: {:?}, flag: {:?}", path, flag); - let path = user_path_at(dir_fd, &path)?; - - let dt = path.open(None)?; - let attr = dt.inode()?.get_attr()?; - - let mut file_stat = FileStat::default(); - unsafe { - (&mut file_stat as *mut FileStat as *mut usize as *mut VfsFileStat).write(attr); - } - warn!("sys_fstateat: res: {:?}", file_stat); - process - .access_inner() - .copy_to_user(&file_stat, stat as *mut FileStat); - Ok(0) -} - -/// 一个系统调用,用于获取文件的相关信息。获取的信息会保存在 `stat` 指向的 [`FileStat`] 结构中。 -/// `fd` 用于指明要获取信息的文件的文件描述符。 -/// -/// 获取相关信息成功后,函数返回 0;否则函数会返回 -1 表示获取信息出错。 -/// 如果输入的 `stat` 为空指针,那么会导致函数 panic。 -#[syscall_func(80)] -pub fn sys_fstat(fd: usize, stat: *mut u8) -> AlienResult { - assert!(!stat.is_null()); - let process = current_task().unwrap(); - let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let attr = file.get_attr()?; - let mut file_stat = FileStat::default(); - unsafe { - (&mut file_stat as *mut FileStat as *mut usize as *mut VfsFileStat).write(attr); - } - warn!("sys_fstat: {:?}, res: {:?}", fd, file_stat); - process - .access_inner() - .copy_to_user(&file_stat, stat as *mut FileStat); - Ok(0) -} - -/// 一个系统调用,用于获取一个已挂载的文件系统的使用情况。与 [`sys_statfs`] 的功能类似。 -/// 获取到的相关信息将会保存在 `statfs` 所指向的 [`FsStat`] 结构中,`fd` 可以是该已挂载的文件系统下的任意一个文件的文件描述符。 -/// -/// 如果获取成功,函数会返回 0;否则返回 -1 表示获取信息异常。 -/// Reference: https://man7.org/linux/man-pages/man2/fstatfs64.2.html -#[syscall_func(44)] -pub fn sys_fstatfs(fd: isize, buf: *mut u8) -> AlienResult { - let process = current_task().unwrap(); - let buf = process.transfer_raw_ptr(buf as *mut FsStat); - let file = process.get_file(fd as usize).ok_or(LinuxErrno::EBADF)?; - let fs_stat = file.inode().get_super_block()?.stat_fs()?; - unsafe { - (&mut *buf as *mut FsStat as *mut usize as *mut VfsFsStat).write(fs_stat); - } - warn!("sys_fstatfs: res: {:#x?}", fs_stat); - Ok(0) -} - -/// 一个系统调用,用于获取一个已挂载的文件系统的使用情况。 -/// 获取到的相关信息将会保存在 `statfs` 所指向的 [`FsStat`] 结构中,`path` 可以是该已挂载的文件系统下的任意一个文件的路径。 -/// -/// 如果获取成功,函数会返回 0;否则返回 -1 表示获取信息异常。 -/// -/// In libc, [[deprecated]] -#[syscall_func(43)] -pub fn sys_statfs(path: *const u8, statfs: *const u8) -> AlienResult { - let process = current_task().unwrap(); - let buf = process.transfer_raw_ptr(statfs as *mut FsStat); - let path = process.transfer_str(path); - - let path = user_path_at(AT_FDCWD, &path)?; - let dt = path.open(None)?; - let fs_stat = dt.inode()?.get_super_block()?.stat_fs()?; - - unsafe { - (&mut *buf as *mut FsStat as *mut usize as *mut VfsFsStat).write(fs_stat); - } - - warn!("sys_statfs: [{:?}] res: {:#x?}", path, fs_stat); - Ok(0) -} - -/// Like [`sys_renameat2`]. -#[syscall_func(38)] -pub fn sys_renameat( - old_dirfd: isize, - old_path: *const u8, - new_dirfd: isize, - new_path: *const u8, -) -> AlienResult { - let process = current_task().unwrap(); - let old_path = process.transfer_str(old_path); - let new_path = process.transfer_str(new_path); - - info!( - "renameat2: {:?} {:?} {:?} {:?}", - old_dirfd, old_path, new_dirfd, new_path - ); - let old_path = user_path_at(old_dirfd, &old_path)?; - let new_path = user_path_at(new_dirfd, &new_path)?; - old_path.rename_to( - syscontext_for_vfs(process.access_inner().cwd()), - new_path, - VfsRenameFlag::empty(), - )?; - Ok(0) -} - -/// 一个系统调用,用于更改文件所在的路径名。文件的新/旧路径 将分别使用 new_dirfd/old_dirfd 和 new_path/old_path 解析获得。有关解析的相关设计请查看 [`user_path_at`]。 -/// -/// 更改文件路径名成功后,函数会返回 0;否则函数返回-1(即当新路径或旧路径中存在不合法的路径 或 在文件系统中修改路径出错时)。 -/// -/// Reference: https://man7.org/linux/man-pages/man2/renameat.2.html -#[syscall_func(276)] -pub fn sys_renameat2( - old_dirfd: isize, - old_path: *const u8, - new_dirfd: isize, - new_path: *const u8, - flag: u32, -) -> AlienResult { - let process = current_task().unwrap(); - let old_path = process.transfer_str(old_path); - let new_path = process.transfer_str(new_path); - let flag = Renameat2Flags::from_bits_truncate(flag); - info!( - "renameat2: {:?} {:?} {:?} {:?}, flag: {:?}", - old_dirfd, old_path, new_dirfd, new_path, flag - ); - let old_path = user_path_at(old_dirfd, &old_path)?; - let new_path = user_path_at(new_dirfd, &new_path)?; - - if flag.contains(Renameat2Flags::RENAME_EXCHANGE) - && (flag.contains(Renameat2Flags::RENAME_NOREPLACE) - || flag.contains(Renameat2Flags::RENAME_WHITEOUT)) - { - return Err(LinuxErrno::EINVAL); - } - - old_path.rename_to( - syscontext_for_vfs(process.access_inner().cwd()), - new_path, - VfsRenameFlag::from_bits_truncate(flag.bits()), - )?; - Ok(0) -} - -/// 一个系统调用,用于在文件描述符之间传递数据。 -/// -/// 从 `in_fd` 读取最多 `count` 个字符,存到 `out_fd` 中。 -/// - 如果 `offset != 0`,则其指定了 `in_fd` 中文件的偏移,此时完成后会修改 `offset` 为读取后的位置,但不更新文件内部的 `offset` -/// - 否则,正常更新文件内部的 `offset` -/// -/// Reference: [send_file](https://man7.org/linux/man-pages/man2/sendfile64.2.html) -#[syscall_func(71)] -pub fn send_file( - out_fd: usize, - in_fd: usize, - offset_ptr: usize, - count: usize, -) -> AlienResult { - warn!( - "send_file: in_fd: {:?}, out_fd: {:?}, offset_ptr: {:?}, count: {:?}", - in_fd, out_fd, offset_ptr, count - ); - let task = current_task().unwrap(); - let in_file = task.get_file(in_fd).ok_or(LinuxErrno::EINVAL)?; - let out_file = task.get_file(out_fd).ok_or(LinuxErrno::EINVAL)?; - - if !(in_file.is_readable() && out_file.is_writable()) { - return Err(LinuxErrno::EBADF); - } - - let mut buf = vec![0u8; count]; - - let nbytes = match offset_ptr { - // offset 为零则要求更新实际文件 - 0 => in_file.read(&mut buf)?, - _ => { - // offset 非零则要求不更新实际文件,更新这个用户给的值 - let offset_ptr = task.transfer_raw_ptr(offset_ptr as *mut u64); - let nbytes = in_file.read_at(*offset_ptr, &mut buf)?; - *offset_ptr += nbytes as u64; - nbytes - } - }; - info!("sys_sendfile: read {} bytes from in_file", nbytes); - let w = out_file.write(&buf[0..nbytes as usize])?; - Ok(w as _) -} - -/// 一个系统调用函数,用于包把含更新文件的所有内核缓冲区(包含数据块、指针块、元数据等)都flush到磁盘上。 -#[syscall_func(81)] -pub fn sync() -> isize { - 0 -} - -/// 用于把打开的文件描述符fd相关的所有缓冲元数据和数据都刷新到磁盘上。 -#[syscall_func(82)] -pub fn fsync(fd: usize) -> AlienResult { - let task = current_task().unwrap(); - let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let fs = file.inode().get_super_block()?; - fs.sync_fs(false)?; - Ok(0) -} - -#[syscall_func(285)] -pub fn copy_file_range( - fd_in: isize, - off_in_ptr: usize, - fd_out: isize, - off_out_ptr: usize, - len: usize, - _flag: usize, -) -> AlienResult { - info!( - "copy_file_range: {:?} {:?} {:?} {:?} {:?}", - fd_in, off_in_ptr, fd_out, off_out_ptr, len - ); - let task = current_task().unwrap(); - let in_file = task.get_file(fd_in as usize).ok_or(LinuxErrno::EBADF)?; - let out_file = task.get_file(fd_out as usize).ok_or(LinuxErrno::EBADF)?; - if !(in_file.is_readable() && out_file.is_writable()) { - return Err(LinuxErrno::EBADF); - } - let mut buf = vec![0u8; len]; - let r = if off_in_ptr == 0 { - in_file.read(&mut buf)? - } else { - // offset 非零则要求不更新实际文件,更新这个用户给的值 - let off_in_ptr = task.transfer_raw_ptr(off_in_ptr as *mut u64); - let nr = in_file.read_at(*off_in_ptr, &mut buf)?; - *off_in_ptr += nr as u64; - nr - }; - info!("sys_copy_file_range: read {} bytes from in_file", r); - let w = if off_out_ptr == 0 { - out_file.write(&buf[..r])? - } else { - let off_out_ptr = task.transfer_raw_ptr(off_out_ptr as *mut u64); - let wr = out_file.write_at(*off_out_ptr, &buf[..r])?; - *off_out_ptr += wr as u64; - wr - }; - info!("sys_copy_file_range: write {} bytes to out_file", w); - Ok(w as _) -} diff --git a/kkernel/src/fs/control.rs b/kkernel/src/fs/control.rs deleted file mode 100644 index 9998c438..00000000 --- a/kkernel/src/fs/control.rs +++ /dev/null @@ -1,263 +0,0 @@ -use log::{info, warn}; -use crate::fs::user_path_at; -use crate::task::current_task; -use constants::io::{FaccessatFlags, FaccessatMode, Fcntl64Cmd, OpenFlags, TeletypeCommand}; -use constants::{AlienResult, AT_FDCWD}; -use constants::LinuxErrno; -use syscall_table::syscall_func; -use vfscore::utils::*; -use timer::TimeSpec; - -const FD_CLOEXEC: usize = 1; - -/// 一个系统调用,用于对一个文件提供控制。 -/// -/// `fd` 指明要操作的文件的描述符;`cmd` 指明控制操作的类型;`arg` 指明操作的参数。 -/// -/// 目前 Alien 中 fcntl 支持的 `cmd` 类型有:(更多可见 [`Fcntl64Cmd`] ) -/// + F_DUPFD: 复制一个现有的文件描述符,此时返回新的文件描述符 new_fd; -/// + F_DUPFD_CLOEXEC: 复制一个现有的文件描述符,同时修改文件的 flags,使得 `O_CLOSEEXEC`位 为1,返回新的文件描述符 new_fd; -/// + F_GETFD: 返回 fd 所指向的文件的 flags 中的 `O_CLOSEEXEC`位。 -/// + F_SETFD: 设置 fd 所指向的文件的 flags 的 `O_CLOSEEXEC`位,由参数arg的 `FD_CLOEXEC` 位决定。 设置成功返回 0。 -/// + F_GETFL: 返回 fd 所指向的文件的 flags。 -/// + F_SETFL: 根据 arg 设置 fd 的 flags,可以采用的 arg 可见 [`OpenFlags`]。 -/// + 其它操作类型均会使得函数返回 EINVAL。 -/// -/// Reference: [fcntl](https:///man7.org/linux/man-pages/man2/fcntl.2.html) -#[syscall_func(25)] -pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> AlienResult { - let task = current_task().unwrap(); - let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let cmd = Fcntl64Cmd::try_from(cmd).map_err(|_| LinuxErrno::EINVAL)?; - info!("fcntl:{:?} {:?} ", cmd, arg); - match cmd { - Fcntl64Cmd::F_DUPFD => { - let fd = task.add_file(file.clone()).unwrap(); - return Ok(fd as isize); - } - Fcntl64Cmd::F_DUPFD_CLOEXEC => { - let new_file = file.clone(); - new_file.set_open_flag(new_file.get_open_flag() | OpenFlags::O_CLOEXEC); - let new_fd = task.add_file(new_file).unwrap(); - return Ok(new_fd as isize); - } - Fcntl64Cmd::F_GETFD => { - return if file.get_open_flag().contains(OpenFlags::O_CLOEXEC) { - Ok(1) - } else { - Ok(0) - }; - } - Fcntl64Cmd::F_SETFD => { - info!("fcntl: F_SETFD :{:?}", arg & FD_CLOEXEC); - let open_flag = file.get_open_flag(); - if arg & FD_CLOEXEC == 0 { - file.set_open_flag(open_flag & !OpenFlags::O_CLOEXEC); - } else { - file.set_open_flag(open_flag | OpenFlags::O_CLOEXEC); - } - } - Fcntl64Cmd::F_GETFL => { - return Ok(file.get_open_flag().bits() as isize); - } - Fcntl64Cmd::F_SETFL => { - let flag = OpenFlags::from_bits_truncate(arg); - info!("fcntl: F_SETFL :{:?}", flag,); - file.set_open_flag(flag); - } - Fcntl64Cmd::GETLK | Fcntl64Cmd::SETLK | Fcntl64Cmd::SETLKW => { - info!("fcntl: GETLK SETLK SETLKW now ignored"); - } - _ => { - return Err(LinuxErrno::EINVAL.into()); - } - } - Ok(0) -} - -/// 一个系统调用,用于管理 IO 设备。一个字符设备驱动通常会实现设备打开、关闭、读、写等功能, -/// 在一些需要细分的情境下,如果需要扩展新的功能,通常以增设 ioctl() 命令的方式实现。 -/// -/// `fd` 指明要操作的设备的文件描述符;`cmd` 指明控制操作的类型, -/// 目前 Alien 支持的 ioctl 操作可见 [`TeletypeCommand`] 和 `rvfs` 中有关 `ioctl` 的支持; -/// `arg` 指明操作的参数。 -/// -/// 根据不同的 ioctl 命令,将有不同的返回值。 -/// -/// Reference: [ioctl](https:///man7.org/linux/man-pages/man2/ioctl.2.html) -#[syscall_func(29)] -pub fn ioctl(fd: usize, cmd: usize, arg: usize) -> AlienResult { - let process = current_task().unwrap(); - let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let cmd = TeletypeCommand::try_from(cmd as u32).map_err(|_| LinuxErrno::EINVAL)?; - info!("ioctl: {:?} {:?} {:?}", fd, cmd, arg); - let res = file.ioctl(cmd as u32, arg)?; - Ok(res as isize) -} - -const UTIME_NOW: usize = 0x3fffffff; -/// ignore -#[allow(dead_code)] -const UTIME_OMIT: usize = 0x3ffffffe; - -/// 一个系统调用,用于获取 相对于一个目录某位置处 的一个文件上一次的访问时间和修改时间。 -/// -/// 当传入的 `path` 是一个相对地址时,那么 `path` 会被解析成基于文件描述符 `fd` 所指向的目录地址的一个地址;当传入的 `path` 是一个相对地址并且 -/// `fd` 被特殊的设置为 `AT_FDCWD` 时,`path` 会被解析成基于调用该系统调用的进程当前工作目录的一个地址; -/// 当传入的 `path` 是一个绝对地址时,`fd`将被直接忽略。 -/// -/// `times` 指向了一个 `TimeSpec[2]` 的一个数组,其中 TimeSpec[0] 将保存文件上一次访问时间,TimeSpec[1] 将保存文件上一次修改时间。 -/// 用户可从传入的两个 `TimeSpec` 结构中修改 `tv_nsec` 字段值来使得查询到的访问时间变为 上一次的操作时间(`UTIME_OMT`)、当前时间(`UTIME_NOW`)或 0。 -/// -/// `flag` 的值目前还未用到。 -#[syscall_func(88)] -pub fn utimensat( - fd: usize, - path: *const u8, - times: *const u8, - _flags: usize, -) -> AlienResult { - if fd as isize != AT_FDCWD && (fd as isize) < 0 { - return Err(LinuxErrno::EBADF.into()); - } - let task = current_task().unwrap(); - - let dt = if fd as isize > 0 { - let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; - file.dentry() - } else { - let path = task.transfer_str(path); - let path = user_path_at(fd as isize, &path)?; - let dt = path.open(None)?; - dt - }; - - let mut inner = task.access_inner(); - if times.is_null() { - warn!( - "utimensat: {:?} {:?} {:?} {:?}", - fd as isize, - path, - TimeSpec::now(), - TimeSpec::now() - ); - dt.inode()?.update_time( - VfsTime::AccessTime(TimeSpec::now().into()), - TimeSpec::now().into(), - )?; - dt.inode()?.update_time( - VfsTime::AccessTime(TimeSpec::now().into()), - TimeSpec::now().into(), - )?; - } else { - let mut atime = TimeSpec::new(0, 0); - let mut mtime = TimeSpec::new(0, 0); - inner.copy_from_user(times as *const TimeSpec, &mut atime); - unsafe { - inner.copy_from_user((times as *const TimeSpec).add(1), &mut mtime); - } - warn!( - "utimensat: {:?} {:?} {:?} {:?}", - fd as isize, path, atime, mtime - ); - if atime.tv_nsec == UTIME_NOW { - dt.inode()?.update_time( - VfsTime::AccessTime(TimeSpec::now().into()), - TimeSpec::now().into(), - )?; - } else if atime.tv_nsec == UTIME_OMIT { - // do nothing - } else { - dt.inode()? - .update_time(VfsTime::AccessTime(atime.into()), TimeSpec::now().into())?; - }; - if mtime.tv_nsec == UTIME_NOW { - dt.inode()?.update_time( - VfsTime::ModifiedTime(TimeSpec::now().into()), - TimeSpec::now().into(), - )?; - } else if mtime.tv_nsec == UTIME_OMIT { - // do nothing - } else { - dt.inode()? - .update_time(VfsTime::ModifiedTime(mtime.into()), TimeSpec::now().into())?; - }; - }; - - Ok(0) -} - -/// 一个系统调用,用于检测当前进程是否有权限访问一个文件。 -/// -/// 文件的路径由 `dirfd` 和 `path` 解析得到。解析相关信息可见 [`user_path_at`]。 -/// 目前 `mode` 和 `flag` 都未使用。仅检测当前进程是否有打开对应路径下文件的权限。 -/// -/// 如果有打开的权限,则返回 0;否则返回 -1。 -#[syscall_func(48)] -pub fn faccessat(dirfd: isize, path: usize, mode: usize, flag: usize) -> AlienResult { - let task = current_task().unwrap(); - let path = task.transfer_str(path as *const u8); - let mode = FaccessatMode::from_bits_truncate(mode as u32); - let flag = FaccessatFlags::from_bits_truncate(flag as u32); - info!( - "faccessat file: {:?},flag:{:?}, mode:{:?}", - path, flag, mode - ); - // todo! check the AT_SYMLINK_NOFOLLOW flag - let _path = user_path_at(dirfd, &path)?.open(None)?; - Ok(0) -} - -/// 一个系统调用函数,用于修改文件或目录的权限。(待实现) -/// -/// 在Alien系统中,每个文件或目录都有一个权限位, -/// 用于控制该文件或目录的访问权限。sys_chmod函数可以用于修改这些权限位。 -/// -/// sys_chmod函数需要传入两个参数:第一个参数是需要要修改的文件的文件描述符, -/// 第二个参数是新的权限值。 -/// -/// Reference: [chmod](https:///man7.org/linux/man-pages/man2/chmod.2.html) -#[syscall_func(52)] -pub fn chmod(_fd: usize, _mode: usize) -> isize { - 0 -} - -/// (待实现)一个系统调用函数,用于修改相对于某目录某位置处文件或目录的权限。 -/// -/// 当传入的`path`是一个相对地址时,那么`path`会被解析成基于文件描述符`dirfd` -/// 所指向的目录地址的一个地址;当传入的`path`是一个相对地址并且 -/// `dirfd`被特殊的设置为`AT_FDCWD`时,`path`会 -/// 被解析成基于调用该系统调用的进程当前工作目录的一个地址; -/// 当传入的`path`是一个绝对地址时,`dirfd`将被直接忽略。 -/// -/// 当解析出的地址指向的文件是一个软链接时,将根据传入的`flag`的值进行以下的内容: -/// + 若`flag`为0,则将对软链接进行解析,修改软链接的目标文件的权限 -/// + 若`flag`为AT_SYMLINK_NOFOLLOW,则将不对软链接进行解析,直接修改该文件的权限 -/// -/// `flag`处可以传入的值及其含义包括: -/// + AT_SYMLINK_NOFOLLOW: 0x200,如果`path`解析之后指向的文件是一个软链接时,不对软链接进行解析,直接修改该文件的权限 -/// -/// `flag`可以置为AT_SYMLINK_NOFOLLOW或者为0。 -/// -/// Reference: [chmod](https:///man7.org/linux/man-pages/man2/chmod.2.html) -#[syscall_func(53)] -pub fn chmodat(_dirfd: usize, _path: usize, _mode: usize, _flags: usize) -> isize { - 0 -} - -/// 一个系统调用,用于获取并设置当前进程的 `unmask`。在一个进程中,unmask 用于定义新建文件或目录的默认权限。 -/// 每次新建一个文件时,文件的默认权限是由 unmask 的值决定的。如果 unmask 值的某位被设置,在新建文件或目录时将禁用对应的权限。 -/// -/// 函数执行成功后,将会把当前进程的 unmask 值置为传入的 `unmask`,同时返回原来的 unmask 值。 -#[syscall_func(55)] -pub fn fchown() -> isize { - 0 -} - -#[syscall_func(166)] -pub fn unmask(unmask: usize) -> isize { - let task = current_task().unwrap(); - let old_unmask = task.access_inner().unmask; - task.access_inner().unmask = unmask; - old_unmask as isize -} diff --git a/kkernel/src/fs/ext.rs b/kkernel/src/fs/ext.rs deleted file mode 100644 index c1d902be..00000000 --- a/kkernel/src/fs/ext.rs +++ /dev/null @@ -1,231 +0,0 @@ -use constants::{AT_FDCWD, LinuxErrno}; -use core::cmp::min; -use syscall_table::syscall_func; -use vfscore::path::VfsPath; -use constants::AlienResult; -use crate::fs::user_path_at; -use crate::task::current_task; - -/// 一个系统调用,用于设置文件的 扩展属性(xattrs, Extended Attributes)。 -/// -/// 扩展属性(xattrs)提供了一个机制用来将一个(键, 值)对永久地关联到文件,让现有的文件系统得以支持在原始设计中未提供的功能。扩展属性是文件系统不可知论者, -/// 应用程序可以通过一个标准的接口来操纵他们,此接口不因文件系统而异。每个扩展属性可以通过唯一的键来区分,键的内容必须是有效的UTF-8,格式为namespace.attribute, -/// 每个键采用完全限定的形式。 -/// -/// 参数: -/// + `path`: 用于指明要操作文件的路径; -/// + `name`: 用于指明要设置的扩展属性的 `key` 名称,是一个字符串的首地址; -/// + `value`: 用于指明要设置的扩展属性值 `value`,是一段缓冲区的首地址; -/// + `size`: 用于指明缓冲区的长度。请注意该长度最好不要超过一个帧的大小 (4K); -/// + `flag`: 用于调整操作的类型。目前 Alien 中默认未使用该值,请保证该值为0,否则会导致函数 panic。 -/// -/// 返回值: 当设置扩展属性成功时,返回 0;否则返回 -1 表示设置失败。 -/// Reference: https://man7.org/linux/man-pages/man2/setxattr.2.html -#[syscall_func(5)] -pub fn sys_setxattr( - path: *const u8, - name: *const u8, - value: *const u8, - size: usize, - flag: usize, -) -> AlienResult { - // we ignore flag - assert_eq!(flag, 0); - let process = current_task().unwrap(); - let path = process.transfer_str(path); - let name = process.transfer_str(name); - let value = process.transfer_buffer(value, size); - let path = user_path_at(AT_FDCWD, &path)?; - path.set_xattr(&name, value[0])?; - Ok(0) -} - -/// 一个系统调用,用于设置文件的 扩展属性(xattrs, Extended Attributes)。在功能上与 [`sys_setxattr`] 相似。 -/// 唯一的不同点是 `sys_lsetxattr` 不允许设置软链接文件。 -/// -/// 目前的实现为直接调用 [`sys_setxattr`]。 -#[syscall_func(6)] -pub fn sys_lsetxattr( - path: *const u8, - name: *const u8, - value: *const u8, - size: usize, - flag: usize, -) -> AlienResult { - sys_setxattr(path, name, value, size, flag) -} - -/// 一个系统调用,用于设置文件的 扩展属性(xattrs, Extended Attributes)。在功能和实现上与 [`sys_setxattr`] 相似。 -/// 唯一的不同点是 `sys_fsetxattr` 采用文件描述符 `fd` 查找文件,而非文件路径 `path`。 -/// -/// 有关其它参数和 扩展属性 的相关信息可见 [`sys_setxattr`]。 -#[syscall_func(7)] -pub fn sys_fsetxattr( - fd: usize, - name: *const u8, - value: *const u8, - size: usize, - flag: usize, -) -> AlienResult { - // we ignore flag - assert_eq!(flag, 0); - let process = current_task().unwrap(); - let name = process.transfer_str(name); - let value = process.transfer_buffer(value, size); - let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let path = VfsPath::new(file.dentry()); - path.set_xattr(&name, value[0])?; - Ok(0) -} - -/// 一个系统调用,用于获取文件的扩展属性值。有关 扩展属性 的相关信息可见 [`sys_setxattr`]。 -/// -/// 参数: -/// + `path`: 用于指明要操作文件的路径; -/// + `name`: 用于指明要获取的扩展属性的 `key` 名称,是一个字符串的首地址; -/// + `value`: 用于指明要获取的扩展属性值 `value` 保存的位置,是一段缓冲区的首地址; -/// + `size`: 用于指明缓冲区的长度。请注意该长度最好不要超过一个帧的大小 (4K)。 -/// -/// 如果获取扩展属性值成功,返回获取到的扩展属性值的长度;否则返回 -1 表示获取扩展属性值失败。 -/// -/// Reference: https://man7.org/linux/man-pages/man2/getxattr.2.html -#[syscall_func(8)] -pub fn sys_getxattr( - path: *const u8, - name: *const u8, - value: *const u8, - size: usize, -) -> AlienResult { - let process = current_task().unwrap(); - let path = process.transfer_str(path); - let name = process.transfer_str(name); - let mut value = process.transfer_buffer(value, size); - let path = user_path_at(AT_FDCWD, &path)?; - let res = path.get_xattr(&name)?; - let mut copy = 0; - value.iter_mut().for_each(|x| { - let min_copy = min(x.len(), res.len() - copy); - x.copy_from_slice(&res[copy..copy + min_copy]); - copy += min_copy; - }); - Ok(copy as _) -} - -/// 一个系统调用,用于获取文件的 扩展属性。在功能上与 [`sys_getxattr`] 相似。 -/// 唯一的不同点是 `sys_lgetxattr` 不允许获取软链接文件的 扩展属性。 -/// -/// 目前的实现为直接调用 [`sys_getxattr`]。 -#[syscall_func(9)] -pub fn sys_lgetxattr( - path: *const u8, - name: *const u8, - value: *const u8, - size: usize, -) -> AlienResult { - sys_getxattr(path, name, value, size) -} - -/// 一个系统调用,用于获取文件的 扩展属性。在功能上与 [`sys_getxattr`] 相似。 -/// 唯一的不同点是 `sys_fgetxattr` 采用文件描述符 `fd` 查找文件,而非文件路径 `path`。 -/// -/// 有关其它参数和 扩展属性 的相关信息可见 [`sys_getxattr`] 和 [`sys_setxattr`]。 -#[syscall_func(10)] -pub fn sys_fgetxattr( - fd: usize, - name: *const u8, - value: *const u8, - size: usize, -) -> AlienResult { - let process = current_task().unwrap(); - let name = process.transfer_str(name); - let mut value = process.transfer_buffer(value, size); - let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - let path = VfsPath::new(file.dentry()); - let res = path.get_xattr(&name)?; - let mut copy = 0; - value.iter_mut().for_each(|x| { - let min_copy = min(x.len(), res.len() - copy); - x.copy_from_slice(&res[copy..copy + min_copy]); - copy += min_copy; - }); - Ok(copy as _) -} - -/// 一个系统调用,用于获取一个文件的所有扩展属性类型 。有关 扩展属性 的相关信息可见 [`sys_setxattr`]。 -/// -/// 参数: -/// + `path`: 用于指明要操作文件的路径; -/// + `list`: 用于指明要获取的所有扩展属性类型保存的位置,是一段缓冲区的首地址; -/// + `size`: 用于指明缓冲区的长度。请注意该长度最好不要超过一个帧的大小 (4K)。 -/// -/// 如果获取扩展属性类型成功,返回获取到的扩展属性类型的长度(总字节数);否则返回 -1 表示获取扩展属性类型失败。 -/// -/// Note: 获取到的拓展属性类型类似于 `user.name1/0system.name1/0user.name2/0`,每个拓展属性类型后都会使用 `/0` 表示该种拓展属性类型结束。 -/// -/// Reference: https://man7.org/linux/man-pages/man2/listxattr.2.html -#[syscall_func(11)] -pub fn sys_listxattr(path: *const u8, list: *const u8, size: usize) -> AlienResult { - let process = current_task().unwrap(); - let _path = process.transfer_str(path); - let _list = process.transfer_buffer(list, size); - unimplemented!(); -} - -/// 一个系统调用,用于获取一个文件的所有扩展属性类型。在功能上与 [`sys_listxattr`] 相似。 -/// 唯一的不同点是 `sys_llistxattr` 不允许获取软链接文件的所有扩展属性类型。 -/// -/// 目前的实现为直接调用 [`sys_listxattr`]。 -#[syscall_func(12)] -pub fn sys_llistxattr(path: *const u8, list: *const u8, size: usize) -> AlienResult { - sys_listxattr(path, list, size) -} - -/// 一个系统调用,用于获取一个文件的所有扩展属性类型。在功能上与 [`sys_listxattr`] 相似。 -/// 唯一的不同点是 `sys_flistxattr` 采用文件描述符 `fd` 查找文件,而非文件路径 `path`。 -/// -/// 有关其它参数和 扩展属性 的相关信息可见 [`sys_listxattr`] 和 [`sys_setxattr`]。 -#[syscall_func(13)] -pub fn sys_flistxattr(fd: usize, list: *const u8, size: usize) -> AlienResult { - let process = current_task().unwrap(); - let _list = process.transfer_buffer(list, size); - let _file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - unimplemented!(); -} - -/// 一个系统调用,用于删除文件的某个扩展属性值。有关 扩展属性 的相关信息可见 [`sys_setxattr`]。 -/// -/// 参数: -/// + `path`: 用于指明要操作文件的路径; -/// + `name`: 用于指明要删除的扩展属性的 `key` 名称,是一个字符串的首地址。 -/// -/// 如果删除扩展属性值成功,返回0;否则返回 -1 表示删除扩展属性值失败。 -/// -/// Reference: https://man7.org/linux/man-pages/man2/removexattr.2.html -#[syscall_func(14)] -pub fn sys_removexattr(path: *const u8, name: *const u8) -> AlienResult { - let process = current_task().unwrap(); - let _path = process.transfer_str(path); - let _name = process.transfer_str(name); - unimplemented!(); -} - -/// 一个系统调用,用于删除文件的某个扩展属性值。在功能上与 [`sys_removexattr`] 相似。 -/// 唯一的不同点是 `sys_lremovexattr` 不允许删除软链接文件的扩展属性值。 -/// -/// 目前的实现为直接调用 [`sys_removexattr`]。 -#[syscall_func(15)] -pub fn sys_lremovexattr(path: *const u8, name: *const u8) -> AlienResult { - sys_removexattr(path, name) -} - -/// 一个系统调用,用于删除文件的某个扩展属性值型。在功能上与 [`sys_removexattr`] 相似。 -/// 唯一的不同点是 `sys_fremovexattr` 采用文件描述符 `fd` 查找文件,而非文件路径 `path`。 -/// -/// 有关其它参数和 扩展属性 的相关信息可见 [`sys_removexattr`] 和 [`sys_setxattr`]。 -#[syscall_func(16)] -pub fn sys_fremovexattr(fd: usize, name: *const u8) -> AlienResult { - let process = current_task().unwrap(); - let _name = process.transfer_str(name); - let _file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - unimplemented!(); -} diff --git a/kkernel/src/fs/file.rs b/kkernel/src/fs/file.rs deleted file mode 100644 index f6f01bbe..00000000 --- a/kkernel/src/fs/file.rs +++ /dev/null @@ -1,278 +0,0 @@ -use constants::io::DirentType; -pub use kernel_file::{File, KernelFile}; -use vfscore::utils::VfsNodeType; - -mod kernel_file { - use super::vfsnodetype2dirent64; - use alloc::sync::Arc; - use constants::io::{Dirent64, OpenFlags, PollEvents, SeekFrom}; - use constants::AlienResult; - use constants::LinuxErrno; - use core::fmt::{Debug, Formatter}; - use downcast_rs::{impl_downcast, DowncastSync}; - use ksync::Mutex; - use vfscore::dentry::VfsDentry; - use vfscore::error::VfsError; - use vfscore::inode::VfsInode; - use vfscore::path::VfsPath; - use vfscore::utils::{VfsFileStat, VfsPollEvents}; - pub struct KernelFile { - pos: Mutex, - open_flag: Mutex, - dentry: Arc, - } - - impl Debug for KernelFile { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("KernelFile") - .field("pos", &self.pos) - .field("open_flag", &self.open_flag) - .field("name", &self.dentry.name()) - .finish() - } - } - - impl KernelFile { - pub fn new(dentry: Arc, open_flag: OpenFlags) -> Self { - let pos = if open_flag.contains(OpenFlags::O_APPEND) { - dentry.inode().unwrap().get_attr().unwrap().st_size - } else { - 0 - }; - Self { - pos: Mutex::new(pos), - open_flag: Mutex::new(open_flag), - dentry, - } - } - } - - pub trait File: DowncastSync + Debug { - fn read(&self, buf: &mut [u8]) -> AlienResult; - fn write(&self, buf: &[u8]) -> AlienResult; - fn read_at(&self, _offset: u64, _buf: &mut [u8]) -> AlienResult { - Err(LinuxErrno::ENOSYS) - } - fn write_at(&self, _offset: u64, _buf: &[u8]) -> AlienResult { - Err(LinuxErrno::ENOSYS) - } - fn flush(&self) -> AlienResult<()> { - Ok(()) - } - fn fsync(&self) -> AlienResult<()> { - Ok(()) - } - fn seek(&self, pos: SeekFrom) -> AlienResult; - /// Gets the file attributes. - fn get_attr(&self) -> AlienResult; - fn ioctl(&self, _cmd: u32, _arg: usize) -> AlienResult { - Err(LinuxErrno::ENOSYS) - } - fn set_open_flag(&self, _flag: OpenFlags) {} - fn get_open_flag(&self) -> OpenFlags { - OpenFlags::O_RDONLY - } - fn dentry(&self) -> Arc; - fn inode(&self) -> Arc; - fn readdir(&self, _buf: &mut [u8]) -> AlienResult { - Err(LinuxErrno::ENOSYS) - } - fn truncate(&self, _len: u64) -> AlienResult<()> { - Err(LinuxErrno::ENOSYS) - } - fn is_readable(&self) -> bool; - fn is_writable(&self) -> bool; - fn is_append(&self) -> bool; - fn poll(&self, _event: PollEvents) -> AlienResult { - Err(LinuxErrno::ENOSYS) - } - } - - impl_downcast!(sync File); - - // todo! permission check - impl File for KernelFile { - fn read(&self, buf: &mut [u8]) -> AlienResult { - if buf.len() == 0 { - return Ok(0); - } - // warn!("[read] is_interrupt_enable:{}",is_interrupt_enable()); - let pos = *self.pos.lock(); - // warn!("[read] is_interrupt_enable:{}",is_interrupt_enable()); - let read = self.read_at(pos, buf)?; - *self.pos.lock() += read as u64; - Ok(read) - } - fn write(&self, buf: &[u8]) -> AlienResult { - if buf.len() == 0 { - return Ok(0); - } - let mut pos = self.pos.lock(); - let write = self.write_at(*pos, buf)?; - *pos += write as u64; - Ok(write) - } - fn read_at(&self, offset: u64, buf: &mut [u8]) -> AlienResult { - if buf.len() == 0 { - return Ok(0); - } - let open_flag = self.open_flag.lock(); - if !open_flag.contains(OpenFlags::O_RDONLY) && !open_flag.contains(OpenFlags::O_RDWR) { - return Err(LinuxErrno::EPERM); - } - drop(open_flag); - let inode = self.dentry.inode()?; - let read = inode.read_at(offset, buf)?; - Ok(read) - } - - fn write_at(&self, _offset: u64, buf: &[u8]) -> AlienResult { - if buf.len() == 0 { - return Ok(0); - } - let open_flag = self.open_flag.lock(); - if !open_flag.contains(OpenFlags::O_WRONLY) && !open_flag.contains(OpenFlags::O_RDWR) { - return Err(LinuxErrno::EPERM); - } - let inode = self.dentry.inode()?; - let write = inode.write_at(_offset, buf)?; - Ok(write) - } - - fn flush(&self) -> AlienResult<()> { - let open_flag = self.open_flag.lock(); - if !open_flag.contains(OpenFlags::O_WRONLY) & !open_flag.contains(OpenFlags::O_RDWR) { - return Err(LinuxErrno::EPERM); - } - let inode = self.dentry.inode()?; - inode.flush()?; - Ok(()) - } - - fn fsync(&self) -> AlienResult<()> { - let open_flag = self.open_flag.lock(); - if !open_flag.contains(OpenFlags::O_WRONLY) && !open_flag.contains(OpenFlags::O_RDWR) { - return Err(LinuxErrno::EPERM); - } - let inode = self.dentry.inode()?; - inode.fsync()?; - Ok(()) - } - - // check for special file - fn seek(&self, pos: SeekFrom) -> AlienResult { - let mut spos = self.pos.lock(); - let size = self.get_attr()?.st_size; - let new_offset = match pos { - SeekFrom::Start(pos) => Some(pos), - SeekFrom::Current(off) => spos.checked_add_signed(off), - SeekFrom::End(off) => size.checked_add_signed(off), - } - .ok_or_else(|| VfsError::Invalid)?; - *spos = new_offset; - Ok(new_offset) - } - - /// Gets the file attributes. - fn get_attr(&self) -> AlienResult { - self.dentry.inode()?.get_attr().map_err(Into::into) - } - - fn ioctl(&self, _cmd: u32, _arg: usize) -> AlienResult { - let inode = self.dentry.inode().unwrap(); - inode.ioctl(_cmd, _arg).map_err(Into::into) - } - - fn set_open_flag(&self, flag: OpenFlags) { - *self.open_flag.lock() = flag; - } - - fn get_open_flag(&self) -> OpenFlags { - *self.open_flag.lock() - } - fn dentry(&self) -> Arc { - self.dentry.clone() - } - fn inode(&self) -> Arc { - self.dentry.inode().unwrap() - } - fn readdir(&self, buf: &mut [u8]) -> AlienResult { - let inode = self.inode(); - let mut pos = self.pos.lock(); - let mut count = 0; - let mut ptr = buf.as_mut_ptr(); - loop { - let dirent = inode.readdir(*pos as usize).map_err(|e| { - *pos = 0; - e - })?; - match dirent { - Some(d) => { - let dirent64 = - Dirent64::new(&d.name, d.ino, *pos as i64, vfsnodetype2dirent64(d.ty)); - if count + dirent64.len() <= buf.len() { - let dirent_ptr = unsafe { &mut *(ptr as *mut Dirent64) }; - *dirent_ptr = dirent64; - let name_ptr = dirent_ptr.name.as_mut_ptr(); - unsafe { - let mut name = d.name.clone(); - name.push('\0'); - let len = name.len(); - name_ptr.copy_from(name.as_ptr(), len); - ptr = ptr.add(dirent_ptr.len()); - } - count += dirent_ptr.len(); - } else { - break; - } // Buf is small - } - None => { - break; - } // EOF - } - *pos += 1; - } - Ok(count) - } - fn truncate(&self, len: u64) -> AlienResult<()> { - let open_flag = self.open_flag.lock(); - if !open_flag.contains(OpenFlags::O_WRONLY) & !open_flag.contains(OpenFlags::O_RDWR) { - return Err(LinuxErrno::EINVAL); - } - let dt = self.dentry(); - VfsPath::new(dt).truncate(len).map_err(Into::into) - } - fn is_readable(&self) -> bool { - let open_flag = self.open_flag.lock(); - open_flag.contains(OpenFlags::O_RDONLY) | open_flag.contains(OpenFlags::O_RDWR) - } - fn is_writable(&self) -> bool { - let open_flag = self.open_flag.lock(); - open_flag.contains(OpenFlags::O_WRONLY) | open_flag.contains(OpenFlags::O_RDWR) - } - - fn is_append(&self) -> bool { - let open_flag = self.open_flag.lock(); - open_flag.contains(OpenFlags::O_APPEND) - } - - fn poll(&self, _event: PollEvents) -> AlienResult { - let inode = self.dentry.inode()?; - let res = inode - .poll(VfsPollEvents::from_bits_truncate(_event.bits())) - .map(|e| PollEvents::from_bits_truncate(e.bits())); - res.map_err(Into::into) - } - } -} - -fn vfsnodetype2dirent64(ty: VfsNodeType) -> DirentType { - DirentType::from_u8(ty as u8) -} - -impl Drop for KernelFile { - fn drop(&mut self) { - let _ = self.flush(); - let _ = self.fsync(); - } -} diff --git a/kkernel/src/fs/link.rs b/kkernel/src/fs/link.rs deleted file mode 100644 index b7805ac3..00000000 --- a/kkernel/src/fs/link.rs +++ /dev/null @@ -1,142 +0,0 @@ -use alloc::vec; -use log::{info, warn}; -use constants::io::{LinkFlags, UnlinkatFlags}; -use syscall_table::syscall_func; - -use crate::{fs::user_path_at, task::current_task}; -use constants::AlienResult; -/// 一个系统调用,用于创建相对于一个目录某位置处的一个文件的(硬)链接。 -/// -/// 当传入的 `old_name` 是一个相对地址时,那么 `old_name` 会被解析成基于文件描述符 `old_fd` -/// 所指向的目录地址的一个地址;当传入的 `old_name` 是一个相对地址并且 -/// `old_fd` 被特殊的设置为 `AT_FDCWD` 时,`old_name` 会 -/// 被解析成基于调用该系统调用的进程当前工作目录的一个地址; -/// 当传入的 `old_name` 是一个绝对地址时,`old_fd` 将被直接忽略。 -/// 对于 `new_name` 同理,将根据 'new_fd' 进行解析。 -/// -/// `flag` 处可以传入的值及其含义包括: -/// + AT_SYMLINK_FOLLOW: 0x400,允许软链接(Follow symbolic links.)。 -/// + AT_EMPTY_PATH: 0x1000,允许 old_name 和 new_name 为空字符串(Allow empty relative pathname.). -/// -/// `flag` 可以为包括上述值 `OR` 运算的结果。 -/// -/// 如果成功创建文件链接,`sys_linkat` 将返回0;否则返回-1或错误类型。 -/// 出错的情况大致包括:当 `old_name` 或 `new_name` 是一个相对地址,`old_fd` 或 `new_fd` 所指向的文件不是一个目录文件; -/// `old_fd` 或 `new_fd` 不是一个有效的文件描述符等。 -/// -/// Reference: [link](https://man7.org/linux/man-pages/man2/link.2.html) -#[syscall_func(37)] -pub fn sys_linkat( - old_fd: isize, - old_name: *const u8, - new_fd: isize, - new_name: *const u8, - flag: usize, -) -> AlienResult { - let flag = LinkFlags::from_bits_truncate(flag as u32); - let process = current_task().unwrap(); - let old_name = process.transfer_str(old_name); - let old_path = user_path_at(old_fd, &old_name)?; - let new_name = process.transfer_str(new_name); - let new_path = user_path_at(new_fd, &new_name)?; - - warn!( - "old_path: {},new_path: {}, flag:{:?}", - old_name, new_name, flag - ); - - let old_dt = old_path.open(None)?; - - new_path.link(old_dt)?; - Ok(0) -} - -/// 一个系统调用,用于删除相对于一个目录某位置处的一个文件的链接。 -/// -/// `unlinkat`执行的操作将根据`flag`参数是否设置为`AT_REMOVEDIR`而执行`unlink`或`rmdir`操作。 -/// 不同情况下,`unlinkat`删除文件链接成功的结果包括: -/// + 如果要删除的链接是软链接,直接删除链接; -/// + 如果要删除的链接是硬连接,并且不是指向该文件的最后一个链接,那么直接删除链接; -/// + 如果要删除的链接是硬连接,并且是指向该文件的最后一个链接 -/// + 如果该文件在某进程中处于打开状态,该文件会一直存活到进程关闭其文件描述符,而后被删除。 -/// + 如果该文件没有任何进程目前正在打开,该文件会被删除,并回收其所占的存储空间。 -/// -/// 当传入的`path`是一个相对地址时,那么`path`会被解析成基于文件描述符`fd` -/// 所指向的目录地址的一个地址;当传入的`path`是一个相对地址并且 -/// `fd`被特殊的设置为`AT_FDCWD`时,`path`会 -/// 被解析成基于调用该系统调用的进程当前工作目录的一个地址; -/// 当传入的`path`是一个绝对地址时,`fd`将被直接忽略。 -/// -/// -/// `flag`处可以传入的值及其含义包括: -/// + AT_REMOVEDIR: 0x200,`sys_linkat`将执行`rmdir`操作。(`rmdir`要求要删除的目录必须为空) -/// -/// `flag`可以置为AT_REMOVEDIR或者为0。 -/// -/// 如果成功删除文件链接,`sys_linkat`将返回0;否则返回-1或错误类型。 -/// -/// Reference: -/// + [unlink](https://man7.org/linux/man-pages/man2/unlink.2.html) -/// + [rmdir](https://man7.org/linux/man-pages/man2/rmdir.2.html) -/// -#[syscall_func(35)] -pub fn sys_unlinkat(fd: isize, path: *const u8, flag: usize) -> AlienResult { - let task = current_task().unwrap(); - let path = task.transfer_str(path); - let flag = UnlinkatFlags::from_bits_truncate(flag as u32); - info!("unlinkat path: {:?}, flag: {:?}", path, flag); - let path = user_path_at(fd, &path)?; - if flag.contains(UnlinkatFlags::AT_REMOVEDIR) { - path.rmdir()?; - } else { - path.unlink()?; - } - Ok(0) -} - -/// 一个系统调用,用于创建一个指向 `oldname` 的新目录项. -/// -/// `old_name` 指明 要链接到的目录位置;新目录项的位置将由 `new_fd` 和 `new_name` 一起解析出,有关解析的相关信息可见 [`user_path_at`]。 -/// -/// 若创建链接成功,则返回 0;否则返回 -1。 -#[syscall_func(36)] -pub fn sys_symlinkat( - old_name: *const u8, - new_fd: isize, - new_name: *const u8, -) -> AlienResult { - let process = current_task().unwrap(); - let old_name = process.transfer_str(old_name); - let new_name = process.transfer_str(new_name); - let new_path = user_path_at(new_fd, &new_name)?; - new_path.symlink(&old_name)?; - Ok(0) -} - -/// 一个系统调用,从相对于 一个目录某位置处 的一个软链接文件处读取文件的软链接内容(即链接到文件的路径)。 -/// -/// 要读取的文件的路径由 `fd` 和 `path` 解析得出。Alien 中有关 `fd` 和 `path` 的路径解析可见 [`user_path_at`] (解析出的文件需是一个软链接文件,否则函数将返回 `ENOENT`)。 -/// `buf` 指明了读取内容要保存到的缓冲区首地址,`size` 指明了缓冲区的大小,即所能保存的内容的最大值。 -/// -/// 若读取成功,则返回读取内容的长度(即链接到文件的路径的长度);否则返回错误码。 -#[syscall_func(78)] -pub fn sys_readlinkat(fd: isize, path: *const u8, buf: *mut u8, size: usize) -> AlienResult { - let process = current_task().unwrap(); - let path = process.transfer_str(path); - info!("readlink path: {}", path); - let path = user_path_at(fd, &path)?; - let dt = path.open(None)?; - let mut empty_buf = vec![0u8; size]; - let r = dt.inode()?.readlink(empty_buf.as_mut_slice())?; - let buf = process.transfer_buffer(buf, size); - let mut w = 0; - for buf in buf { - let len = buf.len(); - buf.copy_from_slice(&empty_buf[w..w + len]); - w += len; - if w >= r { - break; - } - } - Ok(r as isize) -} diff --git a/kkernel/src/fs/mod.rs b/kkernel/src/fs/mod.rs deleted file mode 100644 index c4cf8510..00000000 --- a/kkernel/src/fs/mod.rs +++ /dev/null @@ -1,96 +0,0 @@ -pub mod stdio; -pub mod basic; -pub mod control; -pub mod ext; -pub mod file; -pub mod link; -pub mod poll; -pub mod select; - - -use alloc::vec::Vec; -use log::info; -use vfscore::path::{SysContext, VfsPath}; -use vfscore::utils::{VfsInodeMode, VfsNodeType}; -use constants::{AlienResult, AT_FDCWD, LinuxErrno}; -use constants::io::InodeMode; -use vfs::SYSTEM_ROOT_FS; -use crate::task::{current_task, FsContext}; - -/// 地址解析函数,通过 `fd` 所指向的一个目录文件 和 相对于该目录文件的路径或绝对路径 `path` 解析出某目标文件的绝对路径。 -/// -/// 当传入的`path`是一个相对地址时,那么`path`会被解析成基于文件描述符`fd`所指向的目录地址的一个地址;当传入的`path`是一个相对地址并且 -/// `fd`被特殊的设置为`AT_FDCWD`时,`path`会被解析成基于调用该系统调用的进程当前工作目录的一个地址;当传入的`path`是一个绝对地址时,`fd`将被直接忽略。 -/// -/// 在`Alien`使用的`rvfs`中,对一个文件路径`path`是相对路径还是绝对路径的的判断条件如下: -/// + 绝对路径:以`/`开头,如`/file1.txt`,表示根目录下的`file1.txt`文件; -/// + 相对路径: 以`./`或者`../`或者其它开头,如`./file1.txt`,表示`dirfd`所指向的目录下的`file1.txt`文件。 -fn user_path_at(fd: isize, path: &str) -> AlienResult { - info!("user_path_at fd: {},path:{}", fd, path); - let process = current_task().unwrap(); - let res = if !path.starts_with("/") { - if fd == AT_FDCWD { - let fs_context = process.access_inner().fs_info.clone(); - VfsPath::new(fs_context.cwd).join(path) - } else { - let fd = fd as usize; - let file = process.get_file(fd).ok_or(LinuxErrno::EBADF)?; - VfsPath::new(file.dentry()).join(path) - } - } else { - VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()).join(path) - }; - res.map_err(|e| e.into()) -} - -pub fn read_all(file_name: &str, buf: &mut Vec) -> bool { - let task = current_task(); - // let cwd = if task.is_some() { - // task.unwrap().access_inner().cwd().cwd - // } else { - // SYSTEM_ROOT_FS.get().unwrap().clone() - // }; - let path = if task.is_none() { - VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()) - .join(file_name) - .unwrap() - } else { - user_path_at(AT_FDCWD, file_name).unwrap() - }; - - let dentry = path.open(None); - if dentry.is_err() { - info!("open file {} failed, err:{:?}", file_name, dentry.err()); - return false; - } - let dentry = dentry.unwrap(); - if dentry.inode().unwrap().inode_type() != VfsNodeType::File { - info!("{} is not a file", file_name); - return false; - } - let size = dentry.inode().unwrap().get_attr().unwrap().st_size; - let mut offset = 0; - while offset < size { - let mut tmp = [0;512]; - let res = dentry.inode().unwrap().read_at(offset, &mut tmp).unwrap(); - offset += res as u64; - buf.extend_from_slice(&tmp); - } - assert_eq!(offset, size); - true -} - -/// [InodeMode](InodeMode)转换为[VfsInodeMode](VfsInodeMode) -fn im2vim(mode: InodeMode) -> VfsInodeMode { - VfsInodeMode::from_bits_truncate(mode.bits()) -} - -fn syscontext_for_vfs(fs_info: FsContext) -> SysContext { - SysContext { - pid: 0, - uid: 0, - gid: 0, - cwd: fs_info.cwd.clone(), - root: fs_info.root.clone(), - } -} diff --git a/kkernel/src/fs/poll.rs b/kkernel/src/fs/poll.rs deleted file mode 100644 index eebde6bb..00000000 --- a/kkernel/src/fs/poll.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::task::{current_task, do_suspend}; -use alloc::vec::Vec; -use log::{info, warn}; -use constants::io::{PollEvents, PollFd}; -use constants::AlienResult; -use constants::LinuxErrno; -use syscall_table::syscall_func; -use timer::TimeSpec; - -/// 一个系统调用,用于在一些文件描述符上等待事件。作用与 [`pselect6`] 相似。 -/// -/// 与 'pselect6' 不同,`ppoll` 并不按照等待事件的类型将所有要等待的文件描述符分成`readfds`、`writefds`、`exceptfds`, -/// 而是按照需要等待的文件描述符,将其加入 `fds_ptr`,再对每一个文件描述符进行等待事件的约束。其中 `fds_ptr` 指向的是一个 -/// [`PollFd'] 向量,每个 Pollfd 结构中都保存了文件描述符、等待事件类型和获取到的事件类型三方面信息。因此对于 `ppoll`, -/// 会周期性检测 `fds_ptr` 中是否有文件描述符发生了所要等待的事件,如果有,那么就把事件的类型记录在 Pollfd 结构的 revents -/// 字段下,并使得计数器自增。在 `fds_ptr` 指向的向量中所有的文件描述符都被遍历一遍后,如果有需要处理的事件,那么此时 `ppoll` -/// 会返回需要处理的事件个数。如果没有,和 'pselect6' 相同,`ppoll` 也会让渡 CPU 后循环查询,直到发生超时事件,此时会返回 0, -/// 表示没有收到需要处理的事件。 -/// -/// 参数: -/// + `fds_ptr`: 用于指明需要等待的文件描述符和等待的事件类型。具体可见 [`PollFd`] 结构 和 [`PollEvents`]结构。 -/// + `nfds`: 用于指明需要等待的文件描述符中的最大值 + 1,用于作为 `fds` 中查询文件描述符是否含有事件需要处理的迭代过程的边界条件。 -/// + `time`: 指明超时的时间限制,是一个 [`TimeSpec`] 结构的指针。根据不同取值,不同的效果如下:(目前需要为0,否则会导致 panic) -/// - 如果该值为空,那么select会一直等待需要处理的IO事件,永远不会超时; -/// - 如果该值不为空,但内部的时间被设为0时,表示即使没有发现需要处理的IO事件,也直接返回。 -/// - 否则按照正常的超时时间计算。 -/// + `mask`: 用于屏蔽某些信号。目前在 Alien 中未使用。(并且需要为0,否则会导致 panic) -/// -/// 当因为检测到需要处理的IO事件返回时,ppoll 会返回接收到的需要处理的IO事件的总数; -/// 当因为超时而返回时,ppoll 会返回0; -/// 当因为接收到信号而返回时, ppoll 会返回 EINTR; -/// 当其他情况导致的函数执行异常,ppoll 将直接返回错误码。 -/// -/// Reference: [ppoll](https://man7.org/linux/man-pages/man2/ppoll.2.html) -#[syscall_func(73)] -pub fn ppoll(fds_ptr: usize, nfds: usize, time: usize, _mask: usize) -> AlienResult { - let task = current_task().unwrap(); - let mut fds = Vec::::with_capacity(nfds); - unsafe { - fds.set_len(nfds); - } - task.access_inner() - .copy_from_user_buffer(fds_ptr as *const PollFd, fds.as_mut_ptr(), nfds); - - info!("fds: {:?}", fds); - let wait_time = if time != 0 { - let time_spec = task.transfer_raw_ptr(time as *mut TimeSpec); - Some(time_spec.to_clock() + TimeSpec::now().to_clock()) - } else { - None - }; // wait forever - let mut res = 0; - let task = current_task().unwrap(); - loop { - for pfd in fds.iter_mut() { - if let Some(file) = task.get_file(pfd.fd as usize) { - let event = file.poll(pfd.events)?; - if !event.is_empty() { - res += 1; - } - info!("[ppoll]: event: {:?}", event); - pfd.revents = event; - } else { - // todo: error - pfd.events = PollEvents::INVAL; - } - } - - if res > 0 { - // copy to user - task.access_inner() - .copy_to_user_buffer(fds.as_ptr(), fds_ptr as *mut PollFd, nfds); - info!("ppoll return {:?}", fds); - return Ok(res as isize); - } - if let Some(wait_time) = wait_time { - if wait_time <= TimeSpec::now().to_clock() { - warn!("ppoll timeout"); - return Ok(0); - } - } - info!("[poll] suspend"); - // suspend - do_suspend(); - // interrupt by signal - // let task = current_task().unwrap(); - let task_inner = task.access_inner(); - let receiver = task_inner.signal_receivers.lock(); - if receiver.have_signal() { - return Err(LinuxErrno::EINTR.into()); - } - } -} diff --git a/kkernel/src/fs/select.rs b/kkernel/src/fs/select.rs deleted file mode 100644 index 9df2276d..00000000 --- a/kkernel/src/fs/select.rs +++ /dev/null @@ -1,220 +0,0 @@ -use config::MAX_FD_NUM; -use crate::task::{current_task, do_suspend}; -use alloc::vec::Vec; -use bit_field::BitField; -use constants::io::PollEvents; -use constants::signal::{SignalNumber, SimpleBitSet}; -use constants::AlienResult; -use constants::LinuxErrno; -use core::cmp::min; -use log::{info, trace}; -use syscall_table::syscall_func; -use timer::TimeSpec; - -/// 一个系统调用,实现 IO 端口的复用。一般用于用户程序的一段循环体中, -/// 用于周期性检测一组关注的文件描述符集里是否有需要进行处理的IO事件发生。 -/// -/// 具体的,pselect6 会周期性检测在 `readfds`、`writefds`、`exceptfds`中的文件描述符, -/// 是否符合可读、可写、发生异常。如果有这样的文件描述符,那么就会记录下来,并使得计数器 -/// 自增。如果在一次循环后,发现有需要处理的IO事件,那么 pselect6 会直接返回计数器的值(即 -/// 事件个数),如果一直没有需要处理的IO事件,pselect6 也会在 `timeout` 所指明的一段时间后 -/// 返回 0,表示在该段时间内没有接收到需要处理的IO事件。pselect6 还可能因为 `SIGKILL` 而被 -/// 打断返回。 -/// -/// 参数有: -/// + `nfds`: 用于指明需要检测的文件描述符中的最大值 + 1,用于作为下面三个 `fds` 中查询 -/// 文件描述符是否符合条件的迭代过程的边界条件。目前在 Aien 中,即使传入的 nfds 大于 64,也会被调整为64。 -/// + `readfds`: 指向一个64位的位图(u64),用于记录哪些文件描述符需要被查询可读状态。在执行操作后,该位图被重用为记录哪些文件描述符有事件需要处理。 -/// + `writefds`: 指向一个64位的位图(u64),用于记录哪些文件描述符需要被查询可写状态。在执行操作后,该位图被重用为记录哪些文件描述符有事件需要处理。 -/// + `exceptfds`: 指向一个64位的位图(u64),用于记录哪些文件描述符需要被查询异常状态。在执行操作后,该位图被重用为记录哪些文件描述符有事件需要处理。 -/// + `timeout`: 指明超时的时间限制,是一个 [`TimeSpec`] 结构的指针。根据不同取值,不同的效果如下: -/// - 如果该值为空,那么select会一直等待需要处理的IO事件,永远不会超时; -/// - 如果该值不为空,但内部的时间被设为0时,表示即使没有发现需要处理的IO事件,也直接返回。 -/// - 否则按照正常的超时时间计算。 -/// + `sigmask`: 用于屏蔽某些信号。目前在 Alien 中未使用。 -/// -/// 有关位图的设计,以 `readfds` 为例:当要检测 fd 为 i 的文件描述符是否已经准备好读时,需要则将位值置为1,否则将该位值置为0。 -/// 在执行操作后,该位图被重用为记录哪些文件描述符有事件需要处理,当有事件需要处理时,该位值置为1,否则置为0。`writefds` 和 `exceptfds` 同理。 -/// -/// 当因为检测到需要处理的IO事件返回时,pselect6 会返回接收到的需要处理的IO事件的总数; -/// 当因为超时而返回时,pselect6 会返回0; -/// 当因为接收到信号而返回时, pselect6 会返回 EINTR; -/// 当其他情况导致的函数执行异常,pselect6 将直接返回错误码。 -/// -/// Reference: [pselect](https://www.man7.org/linux/man-pages/man2/select.2.html) -#[syscall_func(72)] -pub fn pselect6( - nfds: usize, - readfds: usize, - writefds: usize, - exceptfds: usize, - timeout: usize, // pselect 不会更新 timeout 的值,而 select 会 - sigmask: usize, -) -> AlienResult { - if nfds >= MAX_FD_NUM { - return Err(LinuxErrno::EINVAL); - } - info!("pselect6: nfds = {}, readfds = {:#x}, writefds = {:#x}, exceptfds = {:#x}, timeout = {:#x}, sigmask = {:#x}", - nfds, readfds, writefds, exceptfds, timeout, sigmask); - - // 注意 pselect 不会修改用户空间中的 timeout,所以需要内核自己记录 - let task = current_task().unwrap(); - - if sigmask != 0 { - let mask = task.access_inner().transfer_raw_ptr(sigmask as *mut usize); - let mask_num: Vec = SimpleBitSet(*mask).into(); - info!("pselect6: sigmask = {} ---> {:?}, ", *mask, mask_num); - } - - let (wait_time, time_spec) = if timeout != 0 { - let time_spec = task.transfer_raw_ptr(timeout as *mut TimeSpec); - info!("pselect6: timeout = {:#x} ---> {:?}", timeout, time_spec); - ( - Some(time_spec.to_clock() + TimeSpec::now().to_clock()), - Some(time_spec.clone()), - ) - } else { - (Some(usize::MAX), None) - }; - // assert!(nfds <= 64); - let nfds = min(nfds, 64); - - // 这里暂时不考虑 sigmask 的问题 - let ori_readfds = if readfds != 0 { - let readfds = task.transfer_raw_ptr(readfds as *mut u64); - *readfds - } else { - 0 - }; - let ori_writefds = if writefds != 0 { - let writefds = task.transfer_raw_ptr(writefds as *mut u64); - *writefds - } else { - 0 - }; - let ori_exceptfds = if exceptfds != 0 { - let exceptfds = task.transfer_raw_ptr(exceptfds as *mut u64); - *exceptfds - } else { - 0 - }; - - // at iperf test, if readfds hav one fd is ok, but writefds is empty, - // it still return 1 and cause recursion error - do_suspend(); - - loop { - let mut set = 0; - // 如果设置了监视是否可读的 fd - if readfds != 0 { - let readfds = task.transfer_raw_ptr(readfds as *mut u64); - trace!( - "[tid:{}]pselect6: readfds = {:#b}", - task.get_tid(), - ori_readfds - ); - for i in 0..nfds { - if ori_readfds.get_bit(i) { - if let Some(fd) = task.get_file(i) { - let event = fd.poll(PollEvents::IN).expect("poll error"); - if event.contains(PollEvents::IN) { - info!("pselect6: fd {} ready to read", i); - readfds.set_bit(i, true); - set += 1; - } else { - readfds.set_bit(i, false); - } - } else { - return Err(LinuxErrno::EBADF.into()); - } - } - } - } - // 如果设置了监视是否可写的 fd - if writefds != 0 { - let writefds = task.transfer_raw_ptr(writefds as *mut u64); - trace!( - "[tid:{}]pselect6: writefds = {:#b}", - task.get_tid(), - ori_writefds - ); - for i in 0..nfds { - if ori_writefds.get_bit(i) { - if let Some(fd) = task.get_file(i) { - let event = fd.poll(PollEvents::OUT).expect("poll error"); - if event.contains(PollEvents::OUT) { - info!("pselect6: fd {} ready to write", i); - writefds.set_bit(i, true); - set += 1; - } else { - writefds.set_bit(i, false); - } - } else { - return Err(LinuxErrno::EBADF.into()); - } - } - } - } - // 如果设置了监视是否异常的 fd - if exceptfds != 0 { - let exceptfds = task.transfer_raw_ptr(exceptfds as *mut u64); - trace!( - "[tid:{}]pselect6: exceptfds = {:#b}", - task.get_tid(), - ori_exceptfds - ); - for i in 0..nfds { - if ori_exceptfds.get_bit(i) { - if let Some(fd) = task.get_file(i) { - let event = fd.poll(PollEvents::ERR).expect("poll error"); - if event.contains(PollEvents::ERR) { - info!("pselect6: fd {} in exceptional conditions", i); - exceptfds.set_bit(i, true); - set += 1; - } else { - exceptfds.set_bit(i, false); - } - } else { - return Err(LinuxErrno::EBADF.into()); - } - } - } - } - - if set > 0 { - // let readfds = task.transfer_raw_ptr(readfds as *mut u64); - // error!("pselect6: readfds = {:#b}", *readfds); - // 如果找到满足条件的 fd,则返回找到的 fd 数量 - return Ok(set as isize); - } - - if let Some(time_spec) = time_spec { - if time_spec == TimeSpec::new(0, 0) { - // 不阻塞 - return Ok(0); - } - } - - // 否则暂时 block 住 - do_suspend(); - - if let Some(wait_time) = wait_time { - if wait_time <= TimeSpec::now().to_clock() { - info!( - "select timeout, wait_time = {:#x}, now = {:#x}", - wait_time, - TimeSpec::now().to_clock() - ); - return Ok(0); - } - } - - // interrupt by signal - let task_inner = task.access_inner(); - let receiver = task_inner.signal_receivers.lock(); - let res = receiver.have_signal_with_number(); - if res.is_some() && res.unwrap() == SignalNumber::SIGKILL as usize { - return Err(LinuxErrno::EINTR.into()); - } - } -} diff --git a/kkernel/src/fs/stdio.rs b/kkernel/src/fs/stdio.rs deleted file mode 100644 index 064eaa44..00000000 --- a/kkernel/src/fs/stdio.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::fs::file::KernelFile; -use alloc::sync::Arc; -use constants::io::OpenFlags; -use spin::Lazy; -use vfscore::path::VfsPath; -use vfs::SYSTEM_ROOT_FS; - -type Stdin = KernelFile; -type Stdout = KernelFile; - -pub static STDIN: Lazy> = Lazy::new(|| { - let path = VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()) - .join("dev/tty") - .unwrap(); - let dentry = path.open(None).unwrap(); - let file = KernelFile::new(dentry, OpenFlags::O_RDONLY); - Arc::new(file) -}); - -pub static STDOUT: Lazy> = Lazy::new(|| { - let path = VfsPath::new(SYSTEM_ROOT_FS.get().unwrap().clone()) - .join("dev/tty") - .unwrap(); - let dentry = path.open(None).unwrap(); - let file = KernelFile::new(dentry, OpenFlags::O_WRONLY); - Arc::new(file) -}); diff --git a/kkernel/src/gui.rs b/kkernel/src/gui.rs deleted file mode 100644 index 69061884..00000000 --- a/kkernel/src/gui.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! GUI 相关的系统调用 -use page_table::addr::{align_up_4k, PhysAddr, VirtAddr}; -use crate::task::current_task; - - -use devices::GPU_DEVICE; - -const FB_VADDR: usize = 0x1000_0000; - -/// 一个系统调用,用于获取一段帧缓存。执行成功后返回帧缓存的首地址,Alien 中默认该地址为 FB_VADDR (0x1000_0000) -#[syscall_func(2000)] -pub fn sys_framebuffer() -> isize { - let fb = GPU_DEVICE.get().unwrap().get_framebuffer(); - let len = fb.len(); - // println!("[kernel] FrameBuffer: addr 0x{:X}, len {}", fb.as_ptr() as usize , len); - let phy_addr = PhysAddr::from(fb.as_ptr() as usize); - assert!(phy_addr.is_aligned_4k()); - let virt_addr = VirtAddr::from(FB_VADDR); - let current_process = current_task().unwrap(); - let inner = current_process.access_inner(); - inner - .address_space - .lock() - .map_region(virt_addr, phy_addr, align_up_4k(len), "RWUVAD".into(), true) - .unwrap(); - FB_VADDR as isize -} - -/// 一个系统调用,用于刷新帧缓存。执行成功后返回 0。 -#[syscall_func(2001)] -pub fn sys_framebuffer_flush() -> isize { - GPU_DEVICE.get().unwrap().flush(); - 0 -} diff --git a/kkernel/src/ipc/futex.rs b/kkernel/src/ipc/futex.rs deleted file mode 100644 index 751b9feb..00000000 --- a/kkernel/src/ipc/futex.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! Futex按英文翻译过来就是快速用户空间互斥体(Fast Userspace Mutex)。在传统的Unix系统中,System V IPC(inter process communication), -//! 如 semaphores, msgqueues, sockets还有文件锁机制(flock())等进程间同步机制都是对一个内核对象操作来完成的,这 -//! 个内核对象对要同步的进程都是可见的,其提供了共享的状态信息和原子操作。当进程间要同步的时候必须要通过系统调用 -//! (如semop())在内核中完成。可是经研究发现,很多同步是无竞争的,即某个进程进入互斥区,到再从某个互斥区出来这段 -//! 时间,常常是没有进程也要进这个互斥区或者请求同一同步变量的。但是在这种情况下,这个进程也要陷入内核去查询是否发生竞争 -//! 退出的时侯还要陷入内核去查询是否有进程等待在同一同步变量上。这些不必要的系统调用(或者说内核陷入)造 -//! 成了大量的性能开销。为了解决这个问题,设计了Futex这一结构。Futex是一种用户态和内核态混合的同步机制。首先,同步的进 -//! 程间通过mmap共享一段内存,futex变量就位于这段共享的内存中且操作是原子的,当进程尝试进入互斥区或者退出互斥区的 -//! 时候,先去查看共享内存中的futex变量,如果没有竞争发生,则只修改futex, 而不用再执行系统调用了。当通过访问futex -//! 变量告诉进程有竞争发生,则还是得执行系统调用去完成相应的处理(wait 或者 wake up)。简单的说,futex就是通过在用户 -//! 态的检查,(motivation)如果了解到没有竞争就不用陷入内核了,大大提高了low-contention时候的效率。Linux从2.5.7开始支持Futex。 -//! -//! Reference: https://cloud.tencent.com/developer/article/1176832 -//! -use alloc::collections::BTreeMap; -use alloc::sync::Arc; -use alloc::vec; -use alloc::vec::Vec; -use core::cmp::min; - -use ksync::Mutex; -use smpscheduler::FifoTask; - -use crate::task::{Task, GLOBAL_TASK_MANAGER}; -use timer::read_timer; -use constants::{AlienError, AlienResult}; - -/// 用于记录一个进程等待一个 futex 的相关信息 -pub struct FutexWaiter { - /// 进程的控制块 - task: Option>, - /// 进程等待 futex 的等待时间 - wait_time: Option, - /// 超时事件的标志位,标识该进程对于 futex 等待是否超时 - timeout_flag: Arc>, -} - -/// 用于管理 futex 等待队列的数据结构 -/// -/// 包含一个 futex id -> futexWait Vec 的 map -pub struct FutexWaitManager { - map: BTreeMap>, -} - -impl FutexWaiter { - /// 创建一个新的 `FutexWaiter` 保存等待在某 futex 上的一个进程 有关等待的相关信息 - pub fn new(task: Arc, wait_time: Option, timeout_flag: Arc>) -> Self { - Self { - task: Some(task), - wait_time, - timeout_flag, - } - } - - /// 唤醒该进程,返回该进程的控制块 - pub fn wake(&mut self) -> Arc { - self.task.take().unwrap() - } -} - -impl FutexWaitManager { - /// 创建一个新的 futex 管理器,保存 futex 和在其上等待队列的映射关系 - pub fn new() -> Self { - Self { - map: BTreeMap::new(), - } - } - - /// 在某等待队列中加入等待进程 - pub fn add_waiter(&mut self, futex: usize, waiter: FutexWaiter) { - self.map.entry(futex).or_insert(Vec::new()).push(waiter); - } - - ///由于信号引发的唤醒操作 - pub fn wake_for_signal(&mut self) { - for (_, waiters) in self.map.iter_mut() { - let mut record = vec![]; - for (index, waiter) in waiters.iter_mut().enumerate() { - let task = waiter.task.as_ref().unwrap(); - let task_inner = task.access_inner(); - let receiver = task_inner.signal_receivers.lock(); - if receiver.have_signal() { - drop(receiver); - drop(task_inner); - let task = waiter.wake(); - GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); - record.push(index); - } - } - record.iter().for_each(|index| { - waiters.remove(*index); - }) - } - self.delete_empty_waiters(); - } - - /// 由于超时引发的唤醒操作 - pub fn wake_for_timeout(&mut self) { - let now = read_timer(); - for (_, waiters) in self.map.iter_mut() { - let mut record = vec![]; - for (index, waiter) in waiters.iter_mut().enumerate() { - if let Some(wait_time) = waiter.wait_time { - if wait_time <= now { - *waiter.timeout_flag.lock() = true; - let task = waiter.wake(); - GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); - record.push(index); - } - } - } - record.iter().for_each(|index| { - waiters.remove(*index); - }) - } - // delete empty waiters - self.delete_empty_waiters(); - } - - /// 清空所有空的等待队列 - fn delete_empty_waiters(&mut self) { - let mut record = vec![]; - for (futex, waiters) in self.map.iter() { - if waiters.is_empty() { - record.push(*futex); - } - } - record.iter().for_each(|futex| { - self.map.remove(futex); - }) - } - - /// 唤醒 futex 上的至多 num 个等待的进程 - pub fn wake(&mut self, futex: usize, num: usize) -> AlienResult { - if let Some(waiters) = self.map.get_mut(&futex) { - error!("there are {} waiters, wake {}", waiters.len(), num); - let min_index = min(num, waiters.len()); - for i in 0..min_index { - let task = waiters[i].wake(); - GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); - } - // delete waiters - waiters.drain(0..min_index); - warn!("wake {} tasks", min_index); - Ok(min_index) - } else { - error!("futex {} not found", futex); - Err(AlienError::EINVAL) - } - } - - /// 将原来等待在 old_futex 上至多 num 个进程转移到 requeue_futex 上等待,返回转移的进程数 - pub fn requeue( - &mut self, - requeue_futex: usize, - num: usize, - old_futex: usize, - ) -> AlienResult { - if num == 0 { - return Ok(0); - } - // move waiters - let mut waiters = self.map.remove(&old_futex).unwrap(); - // create new waiters - let new_waiters = self.map.entry(requeue_futex).or_insert(Vec::new()); - let min_index = min(num, waiters.len()); - error!("requeue {} waiters", min_index); - for _ in 0..min_index { - let waiter = waiters.pop().unwrap(); - new_waiters.push(waiter); - } - // insert old waiters - if !waiters.is_empty() { - self.map.insert(old_futex, waiters); - } - Ok(min_index) - } -} diff --git a/kkernel/src/ipc/mod.rs b/kkernel/src/ipc/mod.rs deleted file mode 100644 index afc46034..00000000 --- a/kkernel/src/ipc/mod.rs +++ /dev/null @@ -1,262 +0,0 @@ -//! IPC 进程间通信,目前 Alien 支持管道、共享内存、信号以及futex'等进程间的通信机制。 -//! -//! [`futex`] 子模块指明了 Alien 中的 futex (快速用户空间互斥体)结构。 -//! [`pipe`] 子模块指明了 Alien 中管道结构。 -//! [`shm`] 子模块指明了 Alien 中的共享内存结构。 -//! [`signal`] 子模块指明了 Alien 中使用的信号机制。 - -use alloc::sync::Arc; -use core::sync::atomic::{AtomicI32, Ordering}; -use spin::Lazy; - -use constants::ipc::{FutexOp, RobustList}; -use constants::AlienResult; -use constants::LinuxErrno; -use ksync::Mutex; -pub use pipe::*; -pub use shm::*; -pub use signal::*; -use crate::ipc::futex::{FutexWaitManager, FutexWaiter}; -use crate::task::schedule::schedule; -use crate::task::{current_task, TaskState}; -use timer::TimeSpec; -use crate::fs::basic::sys_close; - -pub mod futex; -mod pipe; -pub mod shm; -pub mod signal; - -/// 一个全局变量,用于记录和管理 futex 的等待队列 -pub static FUTEX_WAITER: Lazy> = - Lazy::new(|| Mutex::new(FutexWaitManager::new())); - -/// 一对文件描述符。用于创建管道时,返回管道两个端口的文件描述符。 -#[repr(C)] -#[derive(Debug, Copy, Clone)] -struct FdPair { - fd: [u32; 2], -} - -/// 一个系统调用,用于创建管道。管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。 -/// 调用 `sys_pipe` 系统函数即可创建一个管道。 `Alien` 中有关管道的设计可见[`Pipe`]。 -/// -/// `sys_pipe` 按照传入的 `pipe` 解析出对应的 [`FdPair`] 结构在用户内存中的位置, -/// 并将创建成功的管道的读端赋值给 `fd_pair.fd[0]` ,将管道的写端赋值给 `fd_pair.fd[1]` 。 -/// 目前的 `flag` 未发挥作用。 -/// -/// 若创建管道成功,则会返回 0;若发生创建管道错误,或 `pipe == 0` 会导致函数返回 -1。 -#[syscall_func(59)] -pub fn sys_pipe(pipe: *mut u32, _flag: u32) -> AlienResult { - if pipe.is_null() { - return Err(LinuxErrno::EINVAL); - } - let process = current_task().unwrap(); - let fd_pair = process.transfer_raw_ptr(pipe as *mut FdPair); - let (read, write) = make_pipe_file()?; - let read_fd = process.add_file(read).map_err(|_| LinuxErrno::EMFILE)?; - let write_fd = process.add_file(write).map_err(|_| LinuxErrno::EMFILE)?; - fd_pair.fd[0] = read_fd as u32; - fd_pair.fd[1] = write_fd as u32; - Ok(0) -} - -/// 一个系统调用,将进程中一个已经打开的文件复制一份并分配到一个新的文件描述符中。可以用于IO重定向。 -/// `old_fd` 指明进程中一个已经打开的文件的文件描述符。 -/// -/// 如果传入的 `old_fd` 并不对应一个合法的已打开文件,将会返回 -1; -/// 如果创建新的文件描述符失败,那么会返回 `EMFILE`; -/// 否则创建新的文件描述符成功,返回能够访问已打开文件的新文件描述符。(同时文件描述符分配器会保证新文件描述符是当时情况下所能分配的描述符中最小的) -/// -/// Reference: https://man7.org/linux/man-pages/man2/dup.2.html -#[syscall_func(23)] -pub fn sys_dup(old_fd: usize) -> AlienResult { - let process = current_task().unwrap(); - let file = process.get_file(old_fd).ok_or(LinuxErrno::EBADF)?; - let new_fd = process - .add_file(file.clone()) - .map_err(|_| LinuxErrno::EMFILE)?; - Ok(new_fd as isize) -} - -/// 一个系统调用,将进程中一个已经打开的文件复制一份并分配到一个新的文件描述符中。功能上与 `sys_dup` 大致相同。 -/// -/// `old_fd` 指明进程中一个已经打开的文件的文件描述符,`new_fd` 指明新的文件描述符。 -/// 如果 `new_fd` 已经分配给一个文件,那么将自动关闭 `new_fd` 原来对应的那个文件后,再将复制的文件分配到 `new_fd`。 -/// -/// 如果传入的 `old_fd` 并不对应一个合法的已打开文件或者创建新的文件描述符失败,都将会返回 -1; -/// 如果 `new_fd` 与 `old_fd` 相等, 那么调用将什么也不进行,直接返回 `new_fd`。 -/// 否则创建新的文件描述符成功,返回 `new_fd`。 -/// -/// Reference: https://man7.org/linux/man-pages/man2/dup.2.html -#[syscall_func(24)] -pub fn sys_dup2(old_fd: usize, new_fd: usize, _flag: usize) -> AlienResult { - let process = current_task().unwrap(); - let file = process.get_file(old_fd).ok_or(LinuxErrno::EBADF)?; - let new_file = process.get_file(new_fd); - if new_file.is_some() { - let _ = sys_close(new_fd); - } - process - .add_file_with_fd(file.clone(), new_fd) - .map_err(|_| LinuxErrno::EMFILE)?; - Ok(new_fd as isize) -} - -static FCOUNT: Mutex = Mutex::new(0); - -/// 一个系统调用,对 futex 进行操作。 有关 `futex` 的相关信息请见 [`futex`]。 -/// -/// 参数: -/// + `uaddr`: 用户态下共享内存的地址,里面存放的是一个对齐的整型计数器,指向一个 futex。 -/// + `futex_op`: 指明操作的类型。具体操作类型可见 [`FutexOp`]。目前 Alien 识别的 futex_op 包括: -/// + FutexOp::FutexWaitPrivate | FutexOp::FutexWait: 先比较 uaddr 上计数器的值和 val 是否相等,如果不相等则将直接返回 `EAGAIN`;否则 -/// 该进程将等待在 uaddr 上,并根据 val2 的值确定等待的逻辑。若 val2 值为0,则表示进程一直等待;若 val2 是一个正数,则表示进程将在等待 val2 时间后因超时被唤醒 -/// + FutexOp::FutexCmpRequeuePiPrivate: 先比较 uaddr 上计数器的值和 val3 是否相等,如果不相等则将直接返回 `EAGAIN`;否则 -/// 唤醒至多 val 个在 uaddr 上等待的进程后,将原来等待在 uaddr 上至多 val2 个进程转移到 uaddr2 上等待,最后返回 唤醒的进程数 + 转移的进程数 -/// + FutexOp::FutexRequeuePrivate: 唤醒至多 val 个在 uaddr 上等待的进程后,将原来等待在 uaddr 上至多 val2 个进程转移到 uaddr2 上等待 -/// 最后返回 唤醒的进程数 + 转移的进程数 -/// + FutexOp::FutexWakePrivate | FutexOp::FutexWake: 唤醒至多 val 个在 uaddr 上等待的进程。最后返回 唤醒的进程数。 -/// + `val`: 传入的参数1,将根据 futex_op 发挥不同的作用。 -/// + `val2`: 传入的参数2,将根据 futex_op 发挥不同的作用。 -/// + `uaddr2`: 传入的地址2,将根据 futex_op 发挥不同的作用。 -/// + `val3`: 传入的参数3,将根据 futex_op 发挥不同的作用。 -/// -/// 在此过程中,如果出现异常,会返回异常类型。 -/// -/// Reference: [futex](https://man7.org/linux/man-pages/man2/futex.2.html) -#[syscall_func(98)] -pub fn futex( - uaddr: usize, - futex_op: u32, - val: u32, - val2: usize, - uaddr2: usize, - val3: u32, -) -> isize { - *FCOUNT.lock() += 1; - let futex_op = FutexOp::try_from(futex_op).unwrap(); - let task = current_task().unwrap(); - let task_inner = task.access_inner(); - warn!( - "futex: {:?} {:?} {:?} {:?} {:?} {:?}", - uaddr, futex_op, val, val2, uaddr2, val3 - ); - match futex_op { - FutexOp::FutexWaitPrivate | FutexOp::FutexWait => { - let uaddr_ref = task_inner.transfer_raw_ptr_mut(uaddr as *mut i32); - let uaddr_atomic = AtomicI32::from_mut(uaddr_ref); - - if uaddr_atomic.load(Ordering::SeqCst) != val as i32 { - error!("FutexWait: uaddr_ref != val"); - return LinuxErrno::EAGAIN as isize; - } - // we checkout the timeout - let wait_time = if val2 != 0 { - let time_spec = task_inner.transfer_raw_ptr(val2 as *const TimeSpec); - Some(time_spec.to_clock() + TimeSpec::now().to_clock()) - } else { - // wait forever - None - }; - // add to wait queue - drop(task_inner); - warn!("Futex wait time: {:?}", wait_time); - let timeout_flag = Arc::new(Mutex::new(false)); - let waiter = FutexWaiter::new(task.clone(), wait_time, timeout_flag.clone()); - FUTEX_WAITER.lock().add_waiter(uaddr, waiter); - // switch to other task - task.update_state(TaskState::Waiting); - warn!("Because of futex, we switch to other task"); - schedule(); - // checkout the timeout flag - let timeout_flag = timeout_flag.lock(); - if *timeout_flag { - return 0; - } - } - FutexOp::FutexCmpRequeuePiPrivate => { - let uaddr_ref = task_inner.transfer_raw_ptr(uaddr as *const u32); - if *uaddr_ref != val3 { - error!("FutexRequeuePrivate: uaddr_ref != val"); - return LinuxErrno::EAGAIN as isize; - } - // wake val tasks - let res = FUTEX_WAITER.lock().wake(uaddr, val as usize); - if res.is_err() { - return LinuxErrno::EINVAL as isize; - } - // requeue val2 tasks to uaddr2 - let res2 = FUTEX_WAITER.lock().requeue(uaddr2, val2, uaddr); - if res2.is_err() { - return LinuxErrno::EINVAL as isize; - } - return res2.unwrap() as isize + res.unwrap() as isize; - } - FutexOp::FutexRequeuePrivate => { - // wake val tasks - let res = FUTEX_WAITER.lock().wake(uaddr, val as usize); - if res.is_err() { - return LinuxErrno::EINVAL as isize; - } - // requeue val2 tasks to uaddr2 - let res2 = FUTEX_WAITER.lock().requeue(uaddr2, val2, uaddr); - if res2.is_err() { - return LinuxErrno::EINVAL as isize; - } - return res2.unwrap() as isize + res.unwrap() as isize; - } - FutexOp::FutexWakePrivate | FutexOp::FutexWake => { - let res = FUTEX_WAITER.lock().wake(uaddr, val as usize); - if res.is_err() { - return LinuxErrno::EINVAL as isize; - } - return res.unwrap() as isize; - } - _ => { - panic!("futex: unimplemented futex_op: {:?}", futex_op); - // return LinuxErrno::EINVAL as isize; - } - } - 0 -} - -/// 一个系统调用,用于设置当前进程的 robust 锁的列表头。robust 锁主要是解决当一个持有互斥锁的线程退出之后这个锁成为不可用状态的问题。 -/// -/// 当传入的 `len` 不等于 `HEAD_SIZE` 时,将会返回 `EINVAL`,否则函数将把 `head` 赋值给 tcb 的 robust 的 head 字段,然后返回 0。 -#[syscall_func(99)] -pub fn set_robust_list(head: usize, len: usize) -> isize { - if len != RobustList::HEAD_SIZE { - return LinuxErrno::EINVAL as isize; - } - let task = current_task().unwrap(); - let mut task_inner = task.access_inner(); - task_inner.robust.head = head; - 0 -} - -/// 一个系统调用,用于获取某进程的 robust 锁的列表头。robust 锁主要是解决当一个持有互斥锁的线程退出之后这个锁成为不可用状态的问题。 -/// -/// `pid` 指明了要获取相关信息的进程号;`head_ptr` 指明了获取信息后保存的位置;`len_ptr` 指明了获取列表长度信息后保存的位置。 -/// -/// 当 `pid` 的值为 0 时,将会导致函数 panic;当函数正确执行时,返回 0。 -#[syscall_func(100)] -pub fn get_robust_list(pid: usize, head_ptr: usize, len_ptr: usize) -> isize { - assert_eq!(pid, 0); - let task = current_task().unwrap(); - let task_inner = task.access_inner(); - let head = task_inner.robust.head; - let len = RobustList::HEAD_SIZE; - let head_ref = task_inner.transfer_raw_ptr_mut(head_ptr as *mut usize); - let len_ref = task_inner.transfer_raw_ptr_mut(len_ptr as *mut usize); - *head_ref = head; - *len_ref = len; - 0 -} - -/// 唤醒所有当前正在等待 futex 但因为超时或者信号而需要被唤醒的进程 -pub fn solve_futex_wait() { - let mut futex_waiter = FUTEX_WAITER.lock(); - futex_waiter.wake_for_timeout(); - futex_waiter.wake_for_signal(); -} diff --git a/kkernel/src/ipc/pipe.rs b/kkernel/src/ipc/pipe.rs deleted file mode 100644 index 011e2f10..00000000 --- a/kkernel/src/ipc/pipe.rs +++ /dev/null @@ -1,387 +0,0 @@ -//! 管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。 -//! -//! `Alien` 中对于管道的设计参考了`rCore`的相关设计。创建管道时会同时创建一个环形缓冲区, -//! 管道的两个端口抽象成文件,对两个端口直接的相关的文件操作(读操作或者写操作)都被设计 -//! 成对缓冲区进行数据处理(向缓冲区中传入数据或接收数据)。 -//! -//! 管道文件创建时,依据 Alien 所使用的 rvfs 中对文件 `File` 的规定,我们只需为管道文件规定好 -//! [`pipe_release`]、[`pipe_write`]、[`pipe_read`]、[`pipe_exec`]、[`pipe_llseek`]、 -//! [`pipe_read_is_hang_up`]、[`pipe_write_is_hang_up`]、[`pipe_ready_to_read`] -//! 、[`pipe_ready_to_write`] 几个操作函数,即可快速的创建管道文件,并将其放入进程的文件描述 -//! 符表中。 - -use config::PIPE_BUF; -use crate::fs::file::File; -use crate::task::{current_task, do_suspend}; -use alloc::string::{String, ToString}; -use alloc::sync::{Arc, Weak}; -use alloc::vec::Vec; -use constants::io::{OpenFlags, PollEvents, SeekFrom}; -use constants::AlienResult; -use constants::LinuxErrno; -use core::fmt::{Debug, Formatter}; -use core::sync::atomic::AtomicUsize; -use ksync::Mutex; -use vfscore::dentry::VfsDentry; -use vfscore::error::VfsError; -use vfscore::file::VfsFile; -use vfscore::impl_common_inode_default; -use vfscore::inode::{InodeAttr, VfsInode}; -use vfscore::superblock::VfsSuperBlock; -use vfscore::utils::VfsPollEvents; -use vfscore::utils::*; -use vfscore::VfsResult; -use vfs::pipefs::{PIPE_FS_ROOT, PipeFsDirInodeImpl}; - -static PIPE: AtomicUsize = AtomicUsize::new(0); - -/// 管道文件 -pub struct PipeFile { - open_flag: Mutex, - dentry: Arc, - inode_copy: Arc, -} - -impl Debug for PipeFile { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("PipeFile") - .field("open_flag", &self.open_flag) - .field("name", &self.dentry.name()) - .finish() - } -} - -impl PipeFile { - pub fn new( - dentry: Arc, - open_flag: OpenFlags, - inode_copy: Arc, - ) -> Self { - Self { - open_flag: Mutex::new(open_flag), - dentry, - inode_copy, - } - } -} - -/// create a pipe file -pub fn make_pipe_file() -> VfsResult<(Arc, Arc)> { - let root = PIPE_FS_ROOT.get().unwrap(); - let root_inode = root - .inode()? - .downcast_arc::() - .map_err(|_| VfsError::Invalid) - .unwrap(); - let inode = Arc::new(PipeInode::new()); - let num_str = PIPE.fetch_add(1, core::sync::atomic::Ordering::AcqRel); - let same_inode = - root_inode.add_file_manually(&num_str.to_string(), inode.clone(), "rw-rw-rw-".into())?; - let dt = root.i_insert(&num_str.to_string(), same_inode)?; - let reader = Arc::new(PipeFile::new( - dt.clone(), - OpenFlags::O_RDONLY, - inode.clone(), - )); - let sender = Arc::new(PipeFile::new(dt, OpenFlags::O_WRONLY, inode.clone())); - inode.set_reader(&reader); - inode.set_sender(&sender); - Ok((reader, sender)) -} - -impl File for PipeFile { - fn read(&self, buf: &mut [u8]) -> AlienResult { - if buf.len() == 0 { - return Ok(0); - } - self.dentry.inode()?.read_at(0, buf).map_err(|e| e.into()) - } - fn write(&self, buf: &[u8]) -> AlienResult { - if buf.len() == 0 { - return Ok(0); - } - self.dentry.inode()?.write_at(0, buf).map_err(|e| e.into()) - } - fn seek(&self, _pos: SeekFrom) -> AlienResult { - Err(LinuxErrno::ESPIPE) - } - fn get_attr(&self) -> AlienResult { - Err(LinuxErrno::ENOSYS) - } - fn dentry(&self) -> Arc { - self.dentry.clone() - } - fn inode(&self) -> Arc { - self.dentry.inode().unwrap() - } - fn is_readable(&self) -> bool { - let open_flag = self.open_flag.lock(); - open_flag.contains(OpenFlags::O_RDONLY | OpenFlags::O_RDWR) - } - - fn is_writable(&self) -> bool { - let open_flag = self.open_flag.lock(); - open_flag.contains(OpenFlags::O_WRONLY | OpenFlags::O_RDWR) - } - fn is_append(&self) -> bool { - false - } - fn poll(&self, _event: PollEvents) -> AlienResult { - let inode = self.dentry.inode()?; - let res = inode - .poll(VfsPollEvents::from_bits_truncate(_event.bits())) - .map(|e| PollEvents::from_bits_truncate(e.bits())); - res.map_err(Into::into) - } -} - -/// 环形缓冲区,用于在内存中维护管道的相关信息。 -pub struct PipeInode { - data: Mutex, -} - -struct PipeInodeData { - /// 缓冲区的数据部分 - pub buf: [u8; PIPE_BUF], - /// 缓冲区头部,用于指明当前的读位置 - pub head: usize, - /// 缓冲区尾部,用于指明当前的写位置 - pub tail: usize, - /// 记录 在 读端 进行等待的进程 - pub read_wait: Option>, - /// 记录 在 写端 进行等待的进程 - pub write_wait: Option>, -} - -impl PipeInodeData { - /// 用于返回当前的缓冲区是否为空 - pub fn is_empty(&self) -> bool { - self.head == self.tail - } - - /// 用于返回当前的缓冲区是否为满 - pub fn is_full(&self) -> bool { - (self.tail + 1) % PIPE_BUF == self.head - } - - /// 返回当前缓冲区中能够被读的字节数 - pub fn available_read(&self) -> usize { - if self.head <= self.tail { - self.tail - self.head - } else { - PIPE_BUF - self.head + self.tail - } - } - /// 返回当前缓冲区中还能够写入的字节数 - pub fn available_write(&self) -> usize { - if self.head <= self.tail { - PIPE_BUF - self.tail + self.head - 1 - } else { - self.head - self.tail - 1 - } - } - - /// 向缓冲区中写入数据,返回写入的字节数 - pub fn write(&mut self, buf: &[u8]) -> usize { - let mut count = 0; - while !self.is_full() && count < buf.len() { - self.buf[self.tail] = buf[count]; - self.tail = (self.tail + 1) % PIPE_BUF; - count += 1; - } - count - } - - /// 从缓冲区中读取数据,返回读取的字节数 - pub fn read(&mut self, buf: &mut [u8]) -> usize { - let mut count = 0; - while !self.is_empty() && count < buf.len() { - buf[count] = self.buf[self.head]; - self.head = (self.head + 1) % PIPE_BUF; - count += 1; - } - count - } - - /// 返回是否有进程在 写端等待 - pub fn is_write_wait(&self) -> bool { - self.write_wait.is_some() && self.write_wait.as_ref().unwrap().upgrade().is_some() - } - - /// 返回是否有进程在 读端等待 - pub fn is_read_wait(&self) -> bool { - self.read_wait.is_some() && self.read_wait.as_ref().unwrap().upgrade().is_some() - } -} - -impl PipeInode { - /// 创建一片新的管道缓冲区,在 `Pipe::new` 中被调用 - pub fn new() -> PipeInode { - PipeInode { - data: Mutex::new(PipeInodeData { - buf: [0; PIPE_BUF], - head: 0, - tail: 0, - read_wait: None, - write_wait: None, - }), - } - } - - pub fn set_reader(&self, reader: &Arc) { - let mut data = self.data.lock(); - data.read_wait = Some(Arc::downgrade(reader)) - } - pub fn set_sender(&self, sender: &Arc) { - let mut data = self.data.lock(); - data.write_wait = Some(Arc::downgrade(sender)) - } -} - -impl VfsFile for PipeInode { - fn read_at(&self, _offset: u64, user_buf: &mut [u8]) -> VfsResult { - info!("pipe_read: user_buf's len {:?}", user_buf.len()); - let mut count = 0; - loop { - let mut buf = self.data.lock(); - let available = buf.available_read(); - info!("pipe_read: available:{}", available); - if available == 0 { - if !buf.is_write_wait() { - // if there is no process waiting for writing, we should return - break; - } else { - // wait for writing - drop(buf); - do_suspend(); - warn!("pipe_read: suspend"); - // check signal - let task = current_task().unwrap(); - // interrupt by signal - let task_inner = task.access_inner(); - let receiver = task_inner.signal_receivers.lock(); - if receiver.have_signal() { - error!("pipe_write: have signal"); - return Err(VfsError::EINTR); - } - } - } else { - let min = core::cmp::min(available, user_buf.len() - count); - count += buf.read(&mut user_buf[count..count + min]); - break; - } - } - info!("pipe_read: return count:{}", count); - Ok(count) - } - fn write_at(&self, _offset: u64, user_buf: &[u8]) -> VfsResult { - info!("pipe_write: {:?}", user_buf.len()); - let mut count = 0; - loop { - let mut buf = self.data.lock(); - let available = buf.available_write(); - if available == 0 { - if !buf.is_read_wait() { - // if there is no process waiting for reading, we should return - break; - } - // release lock - drop(buf); - // wait for reading - do_suspend(); - let task = current_task().unwrap(); - let task_inner = task.access_inner(); - let receiver = task_inner.signal_receivers.lock(); - if receiver.have_signal() { - error!("pipe_write: have signal"); - return Err(VfsError::EINTR); - } - } else { - let min = core::cmp::min(available, user_buf.len() - count); - info!("pipe_write: min:{}, count:{}", min, count); - count += buf.write(&user_buf[count..count + min]); - break; - } - } - info!("pipe_write: count:{}", count); - Ok(count) - } - fn poll(&self, event: VfsPollEvents) -> VfsResult { - let data = self.data.lock(); - let mut res = VfsPollEvents::empty(); - if event.contains(VfsPollEvents::IN) { - if data.available_read() > 0 { - res |= VfsPollEvents::IN; - } - } - if event.contains(VfsPollEvents::OUT) { - if data.available_write() > 0 { - res |= VfsPollEvents::OUT - } - } - let is_reader = data.is_read_wait(); - let is_sender = data.is_write_wait(); - if is_reader && !is_sender { - res |= VfsPollEvents::HUP; - } - if !is_reader && is_sender { - res |= VfsPollEvents::ERR; - } - Ok(res) - } -} - -impl VfsInode for PipeInode { - impl_common_inode_default!(); - - fn get_super_block(&self) -> VfsResult> { - Err(VfsError::NoSys) - } - - fn node_perm(&self) -> VfsNodePerm { - VfsNodePerm::empty() - } - - fn readlink(&self, _buf: &mut [u8]) -> VfsResult { - Err(VfsError::NoSys) - } - - fn set_attr(&self, _attr: InodeAttr) -> VfsResult<()> { - Err(VfsError::NoSys) - } - - fn get_attr(&self) -> VfsResult { - Err(VfsError::NoSys) - } - - fn list_xattr(&self) -> VfsResult> { - Err(VfsError::NoSys) - } - - fn inode_type(&self) -> VfsNodeType { - VfsNodeType::Fifo - } - fn update_time(&self, _: VfsTime, _: VfsTimeSpec) -> VfsResult<()> { - Err(VfsError::NoSys) - } -} - -impl Drop for PipeFile { - fn drop(&mut self) { - let data = self.inode_copy.data.lock(); - let is_reader = data.is_read_wait(); - let is_sender = data.is_write_wait(); - if !is_reader && !is_sender { - let name = self.dentry.name(); - let root = PIPE_FS_ROOT.get().unwrap(); - let root_inode = root - .inode() - .unwrap() - .downcast_arc::() - .map_err(|_| VfsError::Invalid) - .unwrap(); - root.remove(&name).unwrap(); - root_inode.remove_manually(&name).unwrap(); - } - } -} diff --git a/kkernel/src/ipc/shm.rs b/kkernel/src/ipc/shm.rs deleted file mode 100644 index 1944282f..00000000 --- a/kkernel/src/ipc/shm.rs +++ /dev/null @@ -1,283 +0,0 @@ -//! 共享内存是一种最为高效的进程间通信方式。因为进程可以直接读写内存,不需要任何数据的拷贝。 -//! 为了在多个进程间交换信息,内核专门留出了一块内存区。这段内存区可以由需要访问的进程将其映射到自己的私有地址空间。 -//! 因此,进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高了效率。 -//! -//! Alien 中的共享内存同时提供了同步机制,也就是说,所有的 [`ShmMemoryInner`] 结构被包裹在一个 Mutex 中, -//! 最后封装成 [`ShmMemory`] 结构。 -//! -use alloc::collections::btree_map::BTreeMap; -use page_table::addr::{align_down_4k, PhysAddr, VirtAddr}; -use constants::ipc::{ShmAtFlags, ShmCtlCmd, ShmGetFlags, IPC_PRIVATE}; -use constants::{AlienResult, LinuxErrno}; -use ksync::{Mutex, MutexGuard}; -use syscall_table::syscall_func; - -use config::FRAME_SIZE; -use mem::{alloc_frame_trackers, FrameTracker}; -use crate::task::current_task; - -/// 共享内存被 Mutex 封装后的结构 -#[derive(Debug)] -pub struct ShmMemory { - /// 封装后的共享内存 - inner: Mutex, -} - -/// 未加入同步机制前的 共享内存 -#[derive(Debug)] -pub struct ShmMemoryInner { - /// 引用计数器 - ref_count: usize, - /// 共享内存数据部分 - pub frames: FrameTracker, - /// 共享内存的状态 - state: ShmMemoryState, -} - -/// 共享内存的信息,在创建一块共享内存时,需要将对应的信息加入到进程控制块中的 `shm` 字段下 -#[derive(Debug, Clone)] -pub struct ShmInfo { - /// 共享内存的虚拟地址首地址 - pub start_va: usize, - /// 共享内存的虚拟地址尾地址 - pub end_va: usize, -} - -impl ShmInfo { - /// 创建新的共享内存信息 - pub fn new(start_va: usize, end_va: usize) -> Self { - Self { start_va, end_va } - } -} - -impl ShmMemory { - /// 创建新的共享内存 - pub fn new(frames: FrameTracker) -> Self { - Self { - inner: Mutex::new(ShmMemoryInner { - ref_count: 0, - frames, - state: ShmMemoryState::Init, - }), - } - } - - /// 同步获取内部的共享内存信息 - pub fn access_inner(&self) -> MutexGuard { - self.inner.lock() - } - - /// 返回共享内存数据区的长度(字节数) - pub fn len(&self) -> usize { - self.access_inner().frames.len() - } - - /// 引用计数器加一 - pub fn add_ref(&self) { - self.access_inner().ref_count += 1; - } - - /// 获取当前共享内存的引用数 - pub fn get_ref(&self) -> usize { - self.access_inner().ref_count - } - - /// 删除当前的共享内存 - pub fn delete(&self) { - self.access_inner().state = ShmMemoryState::Deleted; - } - - /// 查询当前的共享内存是否被删除 - pub fn is_deleted(&self) -> bool { - self.access_inner().state == ShmMemoryState::Deleted - } - -} - -/// 记录共享内存当前状态的结构 -#[derive(Debug, Eq, PartialEq, Copy, Clone)] -pub enum ShmMemoryState { - Init, - Used, - Deleted, -} - -/// 用于记录共享内存分配情况的全局变量,可使用其获取已经被创建的一块共享内存 -pub static SHM_MEMORY: Mutex> = Mutex::new(BTreeMap::new()); - -/// 一个系统调用,用于创建一块共享内存,方便进程间通信。 -/// -/// 参数: -/// + `key`: 指明共享内存的键值,多个进程可以通过它来访问同一个共享内存。当其值为 `IPC_PRIVATE` 时,用于创建当前进程的私有共享内存,多用于父子进程间。 -/// + `size`: 用于指明创建共享内存区大小。在函数执行过程中,内核将自动将该值与帧大小(4K)对齐。 -/// + `shmflg`: 用于指明操作的类型。当包含 `IPC_CREAT` 时,将创建一块共享内存,目前 Alien 中仅对 `IPC_CREAT` 有所识别。其它 flag 具体可见 [`ShmGetFlags`]。 -/// -/// 如果已经有共享内存使用了键值 `key`,那么将直接返回 `key` 的值,不会进行创建共享内存操作。 -/// -/// 返回值:如果创建共享内存成功或已经有共享内存使用了键值 `key`,则返回 `key` 值;否则返回 `ENOENT`。 -/// -/// Reference: [shmget](https://man7.org/linux/man-pages/man2/shmget.2.html) -#[syscall_func(194)] -pub fn shmget(key: usize, size: usize, shmflg: u32) -> isize { - info!( - "shmget key:{},size:{},shmflg:{:?}", - key, - size, - ShmGetFlags::from_bits_truncate(shmflg as i32) - ); - let key = if key == IPC_PRIVATE { - // we must create a key - *SHM_MEMORY.lock().keys().max().unwrap_or(&0) + 1 - } else { - key - }; - let mut shm_memory = SHM_MEMORY.lock(); - let shm = shm_memory.get(&key); - // now we ignore flag - if shm.is_some() { - return key as isize; - } - let flag = ShmGetFlags::from_bits_truncate(shmflg as i32); - if flag.contains(ShmGetFlags::IPC_CREAT) { - info!("create new share memory {}", key); - // alloc frames - let frames = alloc_frame_trackers(align_down_4k(size) / FRAME_SIZE); - // if frames.is_none() { - // return LinuxErrno::ENOMEM as isize; - // } - // let frames = frames.unwrap(); - let share_mem = ShmMemory::new(frames); - shm_memory.insert(key, share_mem); - return key as isize; - } - LinuxErrno::ENOENT as isize -} - -/// 一个系统调用,用于将一块共享内存映射到进程的虚拟空间中。通常与 [`shmget`] 一起使用。 -/// -/// 参数: -/// + `shmid`: 用于指明要映射的共享内存的键值 `key`, 一般为 [`shmget`] 的返回值。 -/// + `shmaddr`: 用于指明共享内存要映射到的虚存地址。一般有以下几种情况(目前Alien只能处理情况1,其余情况会导致 panic 退出) -/// 1. 如果 `shmaddr` 是NULL,系统将自动选择一个合适的地址 -/// 2. 如果 `shmaddr` 不是NULL 并且没有指定 SHM_RND,则此段连接到addr所指定的地址上 -/// 3. 如果 `shmaddr` 不是NULL 并且指定了 SHM_RND,则此段连接到 shmaddr -(shmaddr mod SHMLAB)所表示的地址上 -/// + `shmflg`: 一组标志位,通常为0。详细可见 [`ShmAtFlags`]。 -/// -/// 函数正常执行且映射成功时,则会返回虚拟空间中映射的首地址;当 `shmid` 不合法时,会返回 `EINVAL`。 -/// -/// Reference: [shmat](https://www.man7.org/linux/man-pages/man3/shmat.3p.html) -#[syscall_func(196)] -pub fn shmat(shmid: usize, shmaddr: usize, shmflg: u32) -> AlienResult { - warn!( - "shmat shmid:{},shmaddr:{:#x},shmflg:{:?}", - shmid, - shmaddr, - ShmAtFlags::from_bits_truncate(shmflg as i32) - ); - let shm_memory = SHM_MEMORY.lock(); - let shm = shm_memory.get(&shmid).ok_or(LinuxErrno::EINVAL)?; - - let flag = ShmAtFlags::from_bits_truncate(shmflg as i32); - assert!(flag.is_empty()); - if flag.contains(ShmAtFlags::SHM_RDONLY) { - info!("read only"); - } - assert_eq!(shmaddr, 0); - // we must find a place to map - let task = current_task().unwrap(); - let free_map = task.access_inner().mmap.alloc(shm.len()); - // map to va - error!("shm map range:{:#x?}", free_map); - shm.access_inner().state = ShmMemoryState::Used; - let mut task_inner = task.access_inner(); - let mut address_space = task_inner.address_space.lock(); - // let shm_inner = shm.access_inner(); - // let mut virt_start = free_map.start; - // shm.access_inner().frames.iter().for_each(|x| { - // let phy_start = x.start(); - // address_space - // .map( - // VirtAddr::from(virt_start), - // PhysAddr::from(phy_start), - // PageSize::Size4K, - // "UVRWAD".into(), - // ) - // .unwrap(); - // error!("map {:#x} to {:#x}", phy_start, virt_start); - // virt_start += FRAME_SIZE; - // }); - - let size = shm.len(); - let start_phy = shm.access_inner().frames.start(); - address_space.map_region( - VirtAddr::from(free_map.start), - PhysAddr::from(start_phy), - size, - "UVRWAD".into(), - false, - ).unwrap(); - - info!("shm map range:{:#x?}", free_map); - - drop(address_space); - task_inner - .shm - .insert(shmid, ShmInfo::new(free_map.start, free_map.end)); - shm.add_ref(); - Ok(free_map.start as isize) -} - -/// 一个系统调用,用于控制共享内存。 -/// -/// 参数: -/// + `shmid`: 用于指明要操作的共享内存的键值 `key`, 一般为 [`shmget`] 的返回值。 -/// + `cmd`: 指明要采取的操作。具体可见 [`ShmCtlCmd`],目前Alien仅支持 `IpcRmid`,即删除共享内存操作。 -/// + `_buf`: 指向一个存储共享内存模式和访问权限的结构,目前未用到。 -/// -/// 当接受的 `cmd` 为 `IpcRmid` 且 成功执行后,将返回 0;否则会因为还未支持相关操作类型而 panic。 -/// -/// Reference: [shmctl](https://man7.org/linux/man-pages/man2/shmctl.2.html) -#[syscall_func(195)] -pub fn shmctl(shmid: usize, cmd: usize, _buf: usize) -> AlienResult { - let cmd = ShmCtlCmd::try_from(cmd as u32) - .map_err(|_| LinuxErrno::EINVAL)?; - match cmd { - ShmCtlCmd::IpcRmid => { - //delete - let shm_memory = SHM_MEMORY.lock(); - let shm = shm_memory.get(&shmid) - .ok_or(LinuxErrno::EINVAL)?; - shm.delete(); - let task = current_task().unwrap(); - let task_inner = task.access_inner(); - let have_detach = task_inner.shm.get(&shmid).clone(); - if have_detach.is_some() { - // task_inner.shm.remove(&shmid); - // unmap - // let mut address_space = task_inner.address_space.lock(); - // let mut virt_start = shm.access_inner().start_va; - // let virt_end = shm.access_inner().end_va; - // error!("shm unmap rang: {:#x}-{:#x}",virt_start,virt_end); - // while virt_start < virt_end { - // let (phy, flag, _) = address_space.query( - // VirtAddr::from(virt_start) - // ).unwrap(); - // error!("query {:#x} to {:#x} {:?}",virt_start,phy,flag); - // address_space.unmap(VirtAddr::from(virt_start)).unwrap(); - // virt_start += FRAME_SIZE; - // } - } - let mut flag = false; - if shm.get_ref() == 0 && shm.is_deleted() { - flag = true; - } - if flag { - // shm_memory.remove(&shmid); - } - } - _ => { - panic!("not support") - } - } - Ok(0) -} diff --git a/kkernel/src/ipc/signal.rs b/kkernel/src/ipc/signal.rs deleted file mode 100644 index 822bbadd..00000000 --- a/kkernel/src/ipc/signal.rs +++ /dev/null @@ -1,404 +0,0 @@ -//! 信号是进程间通信机制中唯一的异步通信机制,进程之间可以互相通过系统调用 kill 发送软中断信号。 -//! 内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。 -//! -//! 有关 Alien 中信号的具体处理流程可见 [`signal_handler`]。 -use alloc::collections::BTreeMap; -use alloc::sync::Arc; -use alloc::vec::Vec; -use core::mem::size_of; - -use constants::signal::{ - SigAction, SigActionDefault, SigActionFlags, SigInfo, SigProcMaskHow, SignalNumber, - SignalReceivers, SignalUserContext, SimpleBitSet, -}; -use constants::LinuxErrno; -use ksync::Mutex; -use syscall_table::syscall_func; - -use crate::task::{current_task, do_exit, do_suspend}; -use timer::{read_timer, TimeSpec}; - -/// 记录每个线程的信号量,从 tid 获取信号相关信息 -static TID2SIGNALS: Mutex>>> = - Mutex::new(BTreeMap::new()); - -/// 所有线程初始化时均需要加入表 -pub fn global_register_signals(tid: usize, signals: Arc>) { - TID2SIGNALS.lock().insert(tid, signals).take(); -} - -/// 所有线程退出时均需要从表中删除 -pub fn global_logoff_signals(tid: usize) { - TID2SIGNALS.lock().remove(&tid).take(); -} - -/// 获取信号量。这个函数会复制一个 Arc,不会影响表中的信号本身 -pub fn get_signals_from_tid(tid: usize) -> Option>> { - TID2SIGNALS.lock().get(&tid).map(|s| s.clone()) -} - -/// 发送一个信号给进程 tid -pub fn send_signal(tid: usize, signum: usize) { - if let Some(signals) = get_signals_from_tid(tid) { - // 获取目标线程(可以是自己)的 signals 数组 - warn!("send signal {:?} to {}", SignalNumber::from(signum), tid); - signals.lock().try_add_bit(signum); - } -} - -/// 一个系统调用,用于获取或修改与指定信号相关联的处理动作。 -/// -/// 一个进程,对于每种信号,在不进行特殊设置的情况下,都有其默认的处理方式。有关信号的处理流程具体可见 [`signal_handler`] 与 [`SigActionDefault`]。 -/// 用户可以通过 `sigaction` 获取或修改进程在接收到某信号时的处理动作。 -/// -/// 参数: -/// + `sig`: 指出要修改的处理动作所捕获的信号类型。有关详情可见 [`SignalNumber`]。 -/// + `action`: 指定新的信号处理方式的指针。详情可见 [`SigAction`]。当该值为空指针时,`sigaction` 将不会修改信号的处理动作。 -/// + `old_action`: 指出原信号处理方式要保存到的位置。详情可见 [`SigAction`]。当该值为空指针时,`sigaction` 将不会保存信号的原处理动作。 -/// -/// 函数执行成功后返回 0;若输入的 `sig` 是 `SIGSTOP`, `SIGKILL`, `ERR`中的一个时,将导致函数返回 `EINVAL`。 -#[syscall_func(134)] -pub fn sigaction(sig: usize, action: usize, old_action: usize) -> isize { - let action = action as *const SigAction; - let old_action = old_action as *mut SigAction; - // check whether sig is valid - let signum = SignalNumber::from(sig); - if signum == SignalNumber::SIGSTOP - || signum == SignalNumber::SIGKILL - || signum == SignalNumber::ERR - { - return LinuxErrno::EINVAL as isize; - } - let task = current_task().unwrap(); - let mut task_inner = task.access_inner(); - let signal_handler = task_inner.signal_handlers.clone(); - let mut signal_handler = signal_handler.lock(); - if !old_action.is_null() { - let mut tmp = SigAction::empty(); - signal_handler.get_action(sig, &mut tmp); - task_inner.copy_to_user(&tmp, old_action); - } - if !action.is_null() { - let mut tmp_action = SigAction::empty(); - task_inner.copy_from_user(action, &mut tmp_action); - warn!("sig {:?} action is {:?}", signum, tmp_action); - signal_handler.set_action(sig, &tmp_action); - } - 0 -} - -/// 一个系统调用,用于使得一个进程在一段时间限制内等待一个信号,并保存信号的相关信息。 -/// -/// 参数: -/// + `set`: 用于指明等待的信号集,当进程接收到 `set` 中的任一一种信号时,都会返回。 -/// + `info`: 用于指明保存信号相关信息的位置。 当该值为空时,将不执行保存信号信息的操作。具体可见 [`SigInfo`] 结构。 -/// + `time`: 指明等待的时间。具体可见 [`TimeSpec`] 结构。 -/// -/// 当函数在规定的时间内成功接收到 `set` 中包含的某个信号时,将会返回该信号的序号; -/// 当函数在规定的时间内未接收到 `set` 中包含的某个信号时,将返回 `EAGAIN` 表示超时; -/// 如果 `time` 所指明的时间为 0,那么函数将直接返回-1。 -/// -/// Reference: [sigtimedwait](https://linux.die.net/man/2/sigtimedwait) -#[syscall_func(137)] -pub fn sigtimewait(set: usize, info: usize, time: usize) -> isize { - warn!( - "sigtimewait: set: {:x}, info: {:x}, time: {:x}", - set, info, time - ); - - let mut flag = false; - let mut target_time = 0; - - let task = current_task().unwrap().clone(); - let mut time_spec = TimeSpec::new(0, 0); - task.access_inner() - .copy_from_user(time as *const TimeSpec, &mut time_spec); - loop { - let mut task_inner = task.access_inner(); - let mut signal_receivers = task_inner.signal_receivers.lock(); - for i in 1..64 { - if set & (1 << i) != 0 { - if signal_receivers.check_signal(i) { - if info != 0 { - let mut tmp_info = SigInfo::default(); - tmp_info.si_signo = i as i32; - tmp_info.si_code = 0; - drop(signal_receivers); - task_inner.copy_to_user(&tmp_info, info as *mut SigInfo); - } - return i as isize; - } - } - } - - // wait time - if time_spec.tv_sec == 0 && time_spec.tv_nsec == 0 { - return -1; - } - drop(signal_receivers); - drop(task_inner); - if !flag { - warn!("sigtimewait: sleep for {:?}", time_spec); - let t_time = read_timer() + time_spec.to_clock(); - target_time = t_time; - flag = true; - } - let now = read_timer(); - if now >= target_time { - warn!("sigtimewait: timeout"); - break; - } - do_suspend(); - - // interrupt by signal - let task_inner = task.access_inner(); - let receiver = task_inner.signal_receivers.lock(); - if receiver.have_signal() { - let sig = receiver.have_signal_with_number().unwrap(); - return sig as isize; - } - } - LinuxErrno::EAGAIN.into() -} - -/// 一个系统调用,用于获取和设置信号的屏蔽位。通过 `sigprocmask`,进程可以方便的屏蔽某些信号。 -/// -/// 参数: -/// + `how`: 指明将采取何种逻辑修改信号屏蔽位。大致包括:屏蔽 `set` 中指明的所有信号,将 `set` 中指明的所有信号解除屏蔽或者直接使用 `set` 作为屏蔽码。具体可见 [`SigProcMaskHow`]。 -/// + `set`: 用于指明将要修改的信号屏蔽位。具体可见 [`SimpleBitSet`]。当该值为 null 时,将不修改信号的屏蔽位。 -/// + `oldset`: 用于获取当前对信号的屏蔽位。具体可见 [`SimpleBitSet`]。当该值为 null 时,将不保存信号的旧屏蔽位。 -/// + `_sig_set_size`: 用于指示 `set` 和 `oldset` 所指向的信号屏蔽位的长度,目前在 Alien 中未使用。 -/// -/// 函数正常执行后,返回 0。 -/// -/// Reference: [sigprocmask](https://www.man7.org/linux/man-pages/man2/sigprocmask.2.html) -#[syscall_func(135)] -pub fn sigprocmask(how: usize, set: usize, oldset: usize, _sig_set_size: usize) -> isize { - let task = current_task().unwrap(); - let task_inner = task.access_inner(); - let mut signal_receivers = task_inner.signal_receivers.lock(); - if oldset != 0 { - let set_mut = task_inner.transfer_raw_ptr_mut(oldset as *mut usize); - *set_mut = signal_receivers.mask.bits(); - } - let how = SigProcMaskHow::from(how); - warn!("sigprocmask: how: {:?}, set: {:x}", how, set); - if set != 0 { - let set = task_inner.transfer_raw_ptr(set as *const usize); - match how { - SigProcMaskHow::SigBlock => { - signal_receivers.mask += SimpleBitSet::from(*set); - } - SigProcMaskHow::SigUnblock => { - signal_receivers.mask -= SimpleBitSet::from(*set); - } - SigProcMaskHow::SigSetMask => { - signal_receivers.mask = SimpleBitSet::from(*set); - } - SigProcMaskHow::Unknown => { - return LinuxErrno::EINVAL as isize; - } - } - } - let mask: Vec = signal_receivers.mask.into(); - trace!("after sigprocmask: {:?}", mask); - 0 -} - -/// 一个系统调用函数,向 `pid` 指定的进程发送信号。 -/// 如果进程中有多个线程,则会发送给任意一个未阻塞的线程。 -/// -/// pid 有如下情况 -/// 1. pid > 0,则发送给指定进程 -/// 2. pid = 0,则发送给所有同组进程 -/// 3. pid = -1,则发送给除了初始进程(pid=1)外的所有当前进程有权限的进程 -/// 4. pid < -2,则发送给组内 pid 为参数相反数的进程 -/// -/// 目前 2/3/4 未实现。对于 1,仿照 zCore 的设置,认为**当前进程自己或其直接子进程** 是"有权限"或者"同组"的进程。 -/// -/// 目前如果函数成功执行后会返回0;否则返回错误类型。 -/// -/// Reference: [kill](https://man7.org/linux/man-pages/man2/kill.2.html) -#[syscall_func(129)] -pub fn kill(pid: usize, sig: usize) -> isize { - warn!("kill pid {}, signal id {:?}", pid, SignalNumber::from(sig)); - if pid > 0 { - //println!("kill pid {}, signal id {}", pid, signal_id); - if sig > 0 { - send_signal(pid, sig); - } - 0 - } else if pid == 0 { - LinuxErrno::ESRCH as isize - } else { - // 如果 signal_id == 0,则仅为了检查是否存在对应进程,此时应该返回参数错误。是的,用户库是会刻意触发这个错误的 - LinuxErrno::EINVAL as isize - } -} - -/// 一个系统调用函数,向 `tid` 指定的线程发送信号。在`Alien`中`tid`是task的唯一标识,故 `tid` 只会指向一个线程。 -/// -/// 函数正常执行后会返回0;否则返回错误类型。 -/// -/// Reference: [tkill](https://man7.org/linux/man-pages/man2/tkill.2.html) -#[syscall_func(130)] -pub fn tkill(tid: usize, sig: usize) -> isize { - warn!("tkill tid {}, signal id {:?}", tid, SignalNumber::from(sig)); - if tid > 0 && sig > 0 { - //println!("kill pid {}, signal id {}", pid, signal_id); - send_signal(tid, sig); - 0 - } else { - // 如果 signal_id == 0,则仅为了检查是否存在对应进程,此时应该返回参数错误。是的,用户库是会刻意触发这个错误的 - LinuxErrno::EINVAL as isize - } -} - -/// 一个系统调用函数,用于在用户态执行完信号处理函数后重新装回原 trap 上下文,一般不会被用户态程序调用。函数返回原 trap 上下文的 a0。 -#[syscall_func(139)] -pub fn signal_return() -> isize { - let task = current_task().unwrap(); - let mut task_inner = task.access_inner(); - let a0 = task_inner.load_trap_frame(); - a0 -} - -/// 信号处理函数。该函数在进程即将从内核态回到用户态时被调用,用于处理当前进程所接收到的信号。 -/// -/// 进行信号处理的前提: -/// 1. 有要处理的信号; -/// 2. 该信号目前没有被该进程屏蔽; -/// 3. 该信号没有被当前正在处理的信号屏蔽。 -/// -/// 当进入 `signal_handler` 后,对于该进程 `signal_receivers` 下所有信号种类开始遍历: -/// 先检查此种信号是否满足上面所有的前提,如果有一项以上不满足,直接continue; -/// 否则需要根据该信号是否已经设置非默认的处理函数进行接下来的操作。 -/// -/// + 对于一些固定采用采用默认信号处理方式的信号,或由于未设置其它信号处理函数的信号,仍然使用默认信号处理方式,Alien 中采用 [`SigActionDefault`] 对该信号进行判定: -/// + 如果属于 `Terminate` 类型,将导致进程终止。 -/// + 如果属于 `Ignore` 类型,进程将直接忽略该信号。 -/// + 如果进程已经设置过信号处理函数,由于信号处理函数的位置位于用户虚拟内存空间,需要回到用户态下进行信号处理函数的执行, -/// 但由于原来在用户态下我们还保存有一个 trap 上下文,因此我们需要记录这个 trap 上下文,同时将设计好的新的执行信号处理函数的上下文转移至原trap上下文的位置, -/// 以便其执行用户态下的信号处理函数。 -/// -/// 待用户态下的信号处理函数执行完毕后进程将重新陷入内核态,调用 [`signal_return`] 重新装载回原 trap 上下文。 -/// 至此,一个信号被处理完毕。 -pub fn signal_handler() { - let task = current_task().unwrap(); - let mut task_inner = task.access_inner(); - let receiver = task_inner.signal_receivers.clone(); - let mut receiver = receiver.lock(); - let handler = task_inner.signal_handlers.clone(); - let handler = handler.lock(); - if let Some(signum) = receiver.get_one_signal() { - let sig = SignalNumber::from(signum); - error!("task {:?} receive signal {:?}", task.tid, sig); - match sig { - SignalNumber::SIGSEGV | SignalNumber::SIGBUS => { - // we need exit the process - drop(task_inner); - drop(handler); - drop(receiver); - warn!("task {:?} exit by signal {:?}", task.tid, sig); - do_exit(-1); - } - _ => { - if let Some(action) = handler.get_action_ref(signum) { - // we find the handler - if action.is_ignore() { - return; - } - warn!("find handler for signal {:?}", sig); - if !task_inner.save_trap_frame() { - // we are in signal handler,don't nest - return; - } - // save the trap context - let trap_contex = task_inner.trap_frame(); - // modify trap context - // set ra to save user's stack - trap_contex.regs()[1] = action.get_restorer(); - // - let old_pc = trap_contex.sepc(); - trap_contex.set_sepc(action.handler); - // a0 ==signum - trap_contex.regs()[10] = signum; - assert_eq!(trap_contex.regs()[10], signum); - - warn!( - "task {:?} handle signal {:?} at {:#x}, old pc: {:#x}, old_sp: {:#x}", - task.tid, - sig, - trap_contex.sepc(), - old_pc, - trap_contex.regs()[2] - ); - let mut sp = trap_contex.regs()[2] - 0x200; // 128 - if action.flags.contains(SigActionFlags::SA_SIGINFO) { - task_inner.signal_set_siginfo = true; - // 如果带 SIGINFO,则需要在用户栈上放额外的信息 - sp = (sp - size_of::()) & !0xf; - info!("add siginfo at {:x}", sp); - let mut info = SigInfo::default(); - info.si_signo = signum as i32; - unsafe { - let phy_sp = task_inner.transfer_raw(sp); - *(phy_sp as *mut SigInfo) = info; - } - // a1 = &siginfo - trap_contex.regs()[11] = sp; - sp = (sp - size_of::()) & !0xf; - info!("add ucontext at {:x}", sp); - unsafe { - let phy_sp = task_inner.transfer_raw(sp); - *(phy_sp as *mut SignalUserContext) = - SignalUserContext::init(receiver.mask.bits() as u64, old_pc); - } - // a2 = &ucontext - trap_contex.regs()[12] = sp; - } - // set sp - trap_contex.regs()[2] = sp; - warn!( - "task {:?} handle signal {:?}, pc:{:#x}, sp:{:#x}", - task.tid, - sig, - trap_contex.sepc(), - trap_contex.regs()[2] - ); - } else { - // find the default handler - // 否则,查找默认处理方式 - match SigActionDefault::of_signal(sig) { - SigActionDefault::Terminate => { - // 这里不需要 drop(task),因为当前函数没有用到 task_inner,在 task.save_trap... 内部用过后已经 drop 了 - drop(task_inner); - drop(handler); - drop(receiver); - do_exit(-1); - } - SigActionDefault::Ignore => { - // 忽略信号时,要将已保存的上下文删除 - warn!("ignore signal {:?}", sig); - } - } - } - } - } - } -} - -/// 一个系统调用函数,用于阻塞当前进程,等待其他进程传入信号打断阻塞。当进程接收到某种信号时,终止阻塞,函数返回 `EINTR`。 -#[syscall_func(133)] -pub fn sigsuspend() -> isize { - loop { - do_suspend(); - let task = current_task().unwrap(); - // interrupt by signal - let task_inner = task.access_inner(); - let receiver = task_inner.signal_receivers.lock(); - if receiver.have_signal() { - return LinuxErrno::EINTR.into(); - } - } -} diff --git a/kkernel/src/net/mod.rs b/kkernel/src/net/mod.rs deleted file mode 100644 index afbd60f8..00000000 --- a/kkernel/src/net/mod.rs +++ /dev/null @@ -1,475 +0,0 @@ -//! Alien 内核部分的的网络模块,向下调用 `simple_net` 模块实现 tcp 和 udp 套接字的系统调用。 -//! -//! [`addr`] 子模块指明了在 Alien 内核中使用的 socket 套接字地址结构。 -//! [`port`] 子模块现为将网络异常类型 [`NetError`] 转为 系统异常类型 [`LinuxErrno`]的模块。 -//! [`socket`] 子模块指明了Alien 内核中使用的套接字。 -//! [`unix`] 子模块指明了有关 Unix 协议族下的套接字结构。(目前有关的功能有待支持) -//! -use crate::fs::file::File; -use crate::net::addr::{socket_addr_resolution, RawIpV4Addr}; -use crate::net::socket::{SocketData, SocketFile, SocketFileExt}; -use crate::task::{current_task, do_suspend}; -use alloc::sync::Arc; -use alloc::vec; -use alloc::vec::Vec; -use constants::io::OpenFlags; -use constants::net::*; -use constants::{AlienResult,LinuxErrno}; - -pub mod addr; -pub mod port; -pub mod socket; -mod unix; - -/// 一个系统调用,用于创建一个未绑定的socket套接字。 -/// -/// + `domain`: 指明套接字被创建的协议簇(包括文件路径协议簇和网络地址协议簇,具体可见[`Domain`]); -/// + `s_type`: 指明被创建的socket的类型,具体可见[`SocketType`]; -/// + `protocol`: 指明该socket应用于某一个特定的协议上。当确定了套接字使用的协议簇和类型,该参数可以取为0。 -/// -/// 如果创建套接字成功则返回一个能在之后使用的文件描述符,否则返回错误信息。 -#[syscall_func(198)] -pub fn socket(domain: usize, s_type: usize, protocol: usize) -> AlienResult { - let domain = Domain::try_from(domain).map_err(|_| LinuxErrno::EAFNOSUPPORT)?; - let socket_type = - SocketType::try_from(s_type & SOCKET_TYPE_MASK as usize).map_err(|_| LinuxErrno::EINVAL)?; - let task = current_task().unwrap(); - let file = SocketData::new(domain, socket_type, protocol)?; - info!("socket domain: {:?}, type: {:?}", domain, socket_type); - if s_type & SocketType::SOCK_NONBLOCK as usize != 0 { - let socket = file.get_socketdata()?; - file.set_open_flag(file.get_open_flag() | OpenFlags::O_NONBLOCK); - socket.set_socket_nonblock(true); - info!("socket with nonblock"); - } - if s_type & SocketType::SOCK_CLOEXEC as usize != 0 { - file.set_close_on_exec(); - info!("socket with cloexec"); - } - let fd = task.add_file(file).map_err(|_| LinuxErrno::EMFILE)?; - Ok(fd as isize) -} - -/// 一个系统调用,用于绑定socket的地址和端口。 -/// -/// + `socketfd`: 指明要操作socket的文件描述符fd; -/// + `sockaddr`: 指明存储有关绑定信息([`RawIpV4Addr`])的地址; -/// + `len`: `address`([`RawIpV4Addr`])的长度。 -/// -/// 执行成功则返回0,否则返回错误信息。 -#[syscall_func(200)] -pub fn bind(socketfd: usize, sockaddr: usize, len: usize) -> AlienResult { - let socket_fd = common_socket_syscall(socketfd)?; - let socket_addr = socket_addr_resolution(sockaddr, len)?; - let socket = socket_fd.get_socketdata()?; - match socket.bind(socket_addr.clone()) { - Ok(()) => { - let local_addr = socket.local_addr(); - info!( - "[{:?}] {:?} connect to ip: {:?}", - socket.s_type, local_addr, socket_addr - ); - Ok(0) - } - Err(e) => Err(e.into()), - } -} - -/// 一个系统调用,用于等待client提交连接请求,一般用于bind之后,accept之前 -/// -/// + `socketfd`: 指明要操作socket的文件描述符fd; -/// + `backlog`: 指明套接字侦听队列中正在处于半连接状态(等待accept)的请求数最大值。如果该值小于等于0,则自动调为0,同时也有最大值上限。 -/// -/// 执行成功则返回0,否则返回错误信息。 -#[syscall_func(201)] -pub fn listening(socketfd: usize, backlog: usize) -> AlienResult { - let socket_fd = common_socket_syscall(socketfd)?; - let socket = socket_fd.get_socketdata()?; - match socket.listening(backlog) { - Ok(_) => { - info!("socket {:?} listening", socket.local_addr()); - Ok(0) - } - Err(e) => Err(e), - } -} - -/// 一个系统调用,用于取出套接字listen队列中的第一个连接,创建一个与指定套接字具有相同套接字类型的地址族的新套接字。 -/// 新套接字用于传递数据,原套接字继续处理侦听队列中的连接请求。如果侦听队列中无请求,accept()将阻塞。 -/// -/// + `socketfd`: 指明要操作socket的文件描述符fd,需经过bind()和listen()处理; -/// + `socket_addr`: 要么为空,要么指明保存accept成功的客户端相关信息([`RawIpV4Addr`])的地址; -/// + `addr_len`: 保存连接的client相关信息`address`长度的地址。 -/// -/// 执行成功则返回新的套接字的文件描述符,否则返回错误信息. -#[syscall_func(202)] -pub fn accept(socketfd: usize, socket_addr: usize, addr_len: usize) -> AlienResult { - let socket_fd = common_socket_syscall(socketfd)?; - let socket = socket_fd.get_socketdata()?; - match socket.accept() { - Ok(file) => { - let task = current_task().unwrap(); - // get peer addr - if socket_addr != 0 { - let socket = file.get_socketdata()?; - let peer_addr = socket.peer_addr().unwrap(); - info!("accept peer addr: {:?}", peer_addr); - let raw_ip_addr = RawIpV4Addr::from(peer_addr); - let addr_len_ref = task - .access_inner() - .transfer_raw_ptr_mut(addr_len as *mut u32); - *addr_len_ref = core::mem::size_of::() as u32; - task.access_inner() - .copy_to_user(&raw_ip_addr, socket_addr as *mut RawIpV4Addr); - } - let fd = task.add_file(file).map_err(|_| LinuxErrno::EMFILE)?; - Ok(fd as isize) - } - Err(e) => Err(e), - } -} - -/// 一个系统调用,用于client请求在一个套接字上建立连接。 -/// -/// + `socketfd`: 指明要操作socket的文件描述符fd; -/// + `socket_addr`: 指明保存服务器地址和端口号的数据结构([`RawIpV4Addr`])的地址; -/// + `len`: `socket_addr`长度的地址。 -/// -/// 执行成功则返回0,否则返回错误信息。 -/// -/// Note: For netperf_test, the server may be run after client, so we nedd allow -/// client retry once -#[syscall_func(203)] -pub fn connect(socketfd: usize, socket_addr: usize, len: usize) -> AlienResult { - let socket_addr = socket_addr_resolution(socket_addr, len)?; - let socket_fd = common_socket_syscall(socketfd)?; - let socket = socket_fd.get_socketdata()?; - let mut retry = 1; - while retry >= 0 { - match socket.connect(socket_addr.clone()) { - Ok(_) => { - let local_addr = socket.local_addr(); - info!( - "[{:?}] {:?} connect to ip: {:?}", - socket.s_type, local_addr, socket_addr - ); - return Ok(0); - } - Err(e) => { - if retry == 0 { - return Err(e.into()); - } - if e == LinuxErrno::EAGAIN { - return Err(LinuxErrno::EINPROGRESS.into()); - } - retry -= 1; - do_suspend(); - } - } - } - Ok(0) -} - -/// 一个系统调用,查询一个套接字本地bind()的相关信息。 -/// -/// + `socketfd`: 指明要操作socket的文件描述符fd; -/// + `socket_addr`: 指明相关信息([`RawIpV4Addr`])将要保存的地址; -/// + `len`: 保存`address`长度的地址。 -/// -/// 执行成功则返回0,否则返回错误信息。 -#[syscall_func(204)] -pub fn getsockname(socketfd: usize, socket_addr: usize, len: usize) -> AlienResult { - let socket_fd = common_socket_syscall(socketfd)?; - let socket = socket_fd.get_socketdata()?; - let local_addr = socket.local_addr().ok_or(LinuxErrno::EINVAL)?; - info!("getsockname: {:?}", local_addr); - let raw_ip_addr = RawIpV4Addr::from(local_addr); - let task = current_task().unwrap(); - task.access_inner() - .copy_to_user(&raw_ip_addr, socket_addr as *mut RawIpV4Addr); - let len_ref = task.access_inner().transfer_raw_ptr_mut(len as *mut u32); - *len_ref = core::mem::size_of::() as u32; - Ok(0) -} - -/// 一个系统调用,用于获取一个本地套接字所连接的远程服务器的信息。 -/// -/// + `socketfd`: 指明要操作socket的文件描述符fd; -/// + `socket_addr`: 指明连接的客户端相关信息([`RawIpV4Addr`])将要保存的地址; -/// + `len`: 保存`address`长度的地址。 -/// -/// 执行成功则返回0,否则返回错误信息。 -#[syscall_func(205)] -pub fn get_peer_name(socketfd: usize, sockaddr: usize, len: usize) -> AlienResult { - let socket_fd = common_socket_syscall(socketfd)?; - let socket = socket_fd.get_socketdata()?; - let socket_addr = socket.peer_addr().ok_or(LinuxErrno::EINVAL)?; - info!("get_peer_name: {:?}", socket_addr); - let raw_ip_addr = RawIpV4Addr::from(socket_addr); - let task = current_task().unwrap(); - task.access_inner() - .copy_to_user(&raw_ip_addr, sockaddr as *mut RawIpV4Addr); - let len_ref = task.access_inner().transfer_raw_ptr_mut(len as *mut u32); - *len_ref = core::mem::size_of::() as u32; - Ok(0) -} - -/// 一个系统调用,用于发送消息。当面向连接时,dest_addr被忽略;当非面向连接时,消息发送给dest_addr。 -/// -/// + `socketfd`: 指明要操作socket的文件描述符fd; -/// + `message`: 指明要发送的消息的首地址; -/// + `length`: 指明`message`的长度; -/// + `flags`: 指明发送操作的类型; -/// + `dest_addr`: 指明保存目的地的相关信息([`RawIpV4Addr`])的地址; -/// + `dest_len`: 指明`dest_addr`([`RawIpV4Addr`])的大小。 -/// -/// 如果发送成功,返回发送的字节数;否则返回错误信息. -#[syscall_func(206)] -pub fn sendto( - socketfd: usize, - message: *const u8, - length: usize, - flags: usize, - dest_addr: usize, - dest_len: usize, -) -> AlienResult { - assert_eq!(flags, 0); - let socket_fd = common_socket_syscall(socketfd)?; - let task = current_task().unwrap(); - let message = task.transfer_buffer(message, length); - // to vec - // todo!(don't need) - let message = message - .iter() - .map(|buf| buf.to_vec()) - .flatten() - .collect::>(); - let socket = socket_fd.get_socketdata()?; - match socket.socket_type() { - SocketType::SOCK_STREAM | SocketType::SOCK_SEQPACKET => { - if dest_addr != 0 { - return Err(LinuxErrno::EISCONN.into()); - } - } - _ => {} - } - let socket_addr = if dest_addr != 0 { - let res = socket_addr_resolution(dest_addr, dest_len)?; - Some(res) - } else { - None - }; - info!( - "sendto: {:?}, local_addr: {:?}, message len: {}", - socket_addr, - socket.local_addr(), - message.len() - ); - let send = socket.send_to(message.as_slice(), flags, socket_addr)?; - do_suspend(); - Ok(send as isize) -} - -/// 一个系统调用,用于接收消息。消息源地址的相关信息将会保存在src_addr所指向的位置处。 -/// -/// + `socketfd`: 指明要操作socket的文件描述符fd; -/// + `buffer`: 指明接收消息的缓冲区的首地址; -/// + `length`: 指明缓冲区的长度(能接收消息的最大长度); -/// + `flags`: 指明接收操作的类型; -/// + `src_addr`: 指明消息源地址的相关信息([`RawIpV4Addr`])的保存地址。当该值为空时,不进行相关信息的保存; -/// + `addr_len`: 指明`src_addr`([`RawIpV4Addr`])大小的保存地址。 -/// -/// 如果接收成功,返回接收message的字节数;否则返回错误信息。 -#[syscall_func(207)] -pub fn recvfrom( - socketfd: usize, - buffer: *mut u8, - length: usize, - flags: usize, - src_addr: usize, - addr_len: usize, -) -> AlienResult { - assert_eq!(flags, 0); - let socket_fd = common_socket_syscall(socketfd)?; - let socket = socket_fd.get_socketdata()?; - info!( - "recvfrom: {:?}, local_addr: {:?}", - socket.peer_addr(), - socket.local_addr() - ); - let mut tmp_buffer = vec![0u8; length]; - let recv_info = socket.recvfrom(tmp_buffer.as_mut_slice(), flags)?; - let task = current_task().unwrap(); - task.access_inner() - .copy_to_user_buffer(tmp_buffer.as_ptr(), buffer, recv_info.0); - if src_addr != 0 { - let raw_ip_addr = RawIpV4Addr::from(recv_info.1); - task.access_inner() - .copy_to_user(&raw_ip_addr, src_addr as *mut RawIpV4Addr); - let addr_len_ref = task - .access_inner() - .transfer_raw_ptr_mut(addr_len as *mut u32); - *addr_len_ref = core::mem::size_of::() as u32; - } - Ok(recv_info.0 as isize) -} - -/// (待完成)一个系统调用函数,用于设置套接字的选项。 -/// -/// + `socketfd`: 指明要操作socket的文件描述符fd; -/// + `level`: 定义选项的级别,包括`Ip`,`Socket`,`TCP`等,详情可见[`SocketLevel`]; -/// + `opt_name`: 在对应level下,为其设置值的套接字选项,详情可见[`SocketOption`]; -/// + `_opt_value`: 存储选项值位置的指针; -/// + `_opt_len`: 选项值长度; -/// -/// 如果函数执行成功,则返回0;否则返回错误信息。 -#[syscall_func(208)] -pub fn setsockopt( - socketfd: usize, - level: usize, - opt_name: usize, - _opt_value: usize, - _opt_len: u32, -) -> AlienResult { - let socket_fd = common_socket_syscall(socketfd)?; - let _socket = socket_fd.get_socketdata()?; - let level = SocketLevel::try_from(level).map_err(|_| LinuxErrno::EINVAL)?; - match level { - SocketLevel::Ip => {} - SocketLevel::Socket => { - let opt_name = SocketOption::try_from(opt_name).map_err(|_| LinuxErrno::EINVAL)?; - info!("[setsockopt] level: {:?}, opt_name: {:?}", level, opt_name); - } - SocketLevel::Tcp => { - let opt_name = TcpSocketOption::try_from(opt_name).map_err(|_| LinuxErrno::EINVAL)?; - info!("[setsockopt] level: {:?}, opt_name: {:?}", level, opt_name); - } - } - Ok(0) -} - -/// 一个系统调用函数,用于获取套接字的选项。 -/// -/// + `socketfd`: 指明要操作socket的文件描述符fd; -/// + `level`: 定义选项的级别,包括`Ip`,`Socket`,`TCP`等,详情可见[`SocketLevel`]; -/// + `opt_name`: 在对应level下,要为其检索值的套接字选项,详情可见[`SocketOption`]; -/// + `opt_value`: 一个指向将要保存请求选项值的缓冲区的指针; -/// + `_opt_len`: 指向保存选项值长度的指针; -/// -/// 如果函数执行成功,则返回0;否则返回错误信息。 -#[syscall_func(209)] -pub fn getsockopt( - socketfd: usize, - level: usize, - opt_name: usize, - opt_value: usize, - opt_len: usize, -) -> AlienResult { - let socket_fd = common_socket_syscall(socketfd)?; - let _socket = socket_fd.get_socketdata()?; - let level = SocketLevel::try_from(level).map_err(|_| LinuxErrno::EINVAL)?; - match level { - SocketLevel::Ip => {} - SocketLevel::Socket => { - let opt_name = SocketOption::try_from(opt_name).map_err(|_| LinuxErrno::EINVAL)?; - info!("[getsockopt] level: {:?}, opt_name: {:?}", level, opt_name); - match opt_name { - SocketOption::SO_RCVBUF => { - let opt_value_ref = current_task() - .unwrap() - .transfer_raw_ptr(opt_value as *mut u32); - *opt_value_ref = netcore::common::SOCKET_RECV_BUFFER_SIZE as u32; - } - SocketOption::SO_SNDBUF => { - let opt_value_ref = current_task() - .unwrap() - .transfer_raw_ptr(opt_value as *mut u32); - *opt_value_ref = netcore::common::SOCKET_SEND_BUFFER_SIZE as u32; - } - SocketOption::SO_ERROR => { - let opt_value_ref = current_task() - .unwrap() - .transfer_raw_ptr(opt_value as *mut u32); - *opt_value_ref = 0; - } - _ => {} - } - let opt_len_ref = current_task() - .unwrap() - .transfer_raw_ptr(opt_len as *mut u32); - *opt_len_ref = core::mem::size_of::() as u32; - } - SocketLevel::Tcp => { - let opt_name = TcpSocketOption::try_from(opt_name).map_err(|_| LinuxErrno::EINVAL)?; - info!("[getsockopt] level: {:?}, opt_name: {:?}", level, opt_name); - match opt_name { - TcpSocketOption::TCP_MAXSEG => { - let opt_value_ref = current_task() - .unwrap() - .transfer_raw_ptr(opt_value as *mut u32); - *opt_value_ref = netcore::common::MAX_SEGMENT_SIZE as u32; - } - TcpSocketOption::TCP_NODELAY => { - let opt_value_ref = current_task() - .unwrap() - .transfer_raw_ptr(opt_value as *mut u32); - *opt_value_ref = 0; - } - _ => {} - } - } - } - Ok(0) -} - -/// 一个系统调用,用于关闭一个socket的发送操作或接收操作。 -/// -/// + `socketfd`: 指明要操作socket的文件描述符fd; -/// + `how`: 指明要关闭的操作:包括只关闭Read,只关闭Write,RW都关闭,相关Flag值可见[`ShutdownFlag`]。 -/// -/// 执行成功则返回0,否则返回错误信息。 -#[syscall_func(210)] -pub fn shutdown(socketfd: usize, how: usize) -> AlienResult<()> { - let flag = ShutdownFlag::try_from(how).map_err(|_| LinuxErrno::EINVAL)?; - let socket_fd = common_socket_syscall(socketfd)?; - let socket = socket_fd.get_socketdata()?; - info!( - "shutdown: {:?}, local_addr: {:?}", - flag, - socket.local_addr() - ); - socket.shutdown(flag) -} - -/// (待实现)一个系统调用,创建一对未绑定的socket套接字,该对套接字可以用于全双工通信,或者用于父子进程之间的通信。 -/// -/// 如果向其中的一个socket写入后,再从该socket读时,就会发生阻塞。只能在另一个套接字中读。往往和shutdown()配合使用 -/// -/// + `domain`: 指明套接字被创建的协议簇(包括文件路径协议簇和网络地址协议簇,具体可见[`Domain`]); -/// + `type`: 指明被创建的socket的类型,具体可见[`SocketType`]; -/// + `protocol`: 指明该socket应用于某一个特定的协议上。当确定了套接字使用的协议簇和类型,该参数可以取为0。 -/// + `sv[2]`: 用于存放一对套接字的文件描述符。 -/// -/// 如果创建成功则返回0,否则返回错误信息。 -#[syscall_func(199)] -pub fn socket_pair(domain: usize, c_type: usize, proto: usize, sv: usize) -> AlienResult { - let domain = Domain::try_from(domain).map_err(|_| LinuxErrno::EINVAL)?; - let c_type = SocketType::try_from(c_type).map_err(|_| LinuxErrno::EINVAL)?; - info!( - "socketpair: {:?}, {:?}, {:?}, {:?}", - domain, c_type, proto, sv - ); - // panic!("socketpair"); - Err(LinuxErrno::EAFNOSUPPORT.into()) -} - -/// 通过socket文件描述符fd获取对应的文件 -fn common_socket_syscall(socket_fd: usize) -> AlienResult> { - let task = current_task().unwrap(); - let socket_fd = task.get_file(socket_fd).ok_or(LinuxErrno::EBADF)?; - let socket_file = socket_fd - .downcast_arc::() - .map_err(|_| LinuxErrno::EINVAL) - .expect("socket_fd is not a socket file"); - Ok(socket_file) -} diff --git a/kkernel/src/net/port.rs b/kkernel/src/net/port.rs deleted file mode 100644 index 3183d585..00000000 --- a/kkernel/src/net/port.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! 现为将网络异常类型 [`NetError`] 转为 系统异常类型 [`LinuxErrno`]的模块。原为定义端口全局变量和操作的模块。 - -use constants::AlienError; -use constants::LinuxErrno; -use netcore::common::NetError; - -/// 现为将网络异常类型 [`NetError`] 转为 系统异常类型 [`LinuxErrno`]。 -pub fn neterror2alien(error: NetError) -> AlienError { - match error { - NetError::AddrInUse => LinuxErrno::EADDRINUSE, - NetError::InvalidInput => LinuxErrno::EINVAL, - NetError::WouldBlock => LinuxErrno::EAGAIN, - NetError::NotConnected => LinuxErrno::ENOTCONN, - NetError::BadState => LinuxErrno::EBADF, - NetError::Unaddressable => LinuxErrno::EADDRNOTAVAIL, - NetError::AlreadyExists => LinuxErrno::EEXIST, - NetError::ConnectionRefused => LinuxErrno::ECONNREFUSED, - NetError::ConnectionReset => LinuxErrno::ECONNRESET, - NetError::Interrupted => LinuxErrno::EINTR, - NetError::DeviceError => LinuxErrno::EIO, - NetError::Again => LinuxErrno::EAGAIN, - } - .into() -} diff --git a/kkernel/src/system.rs b/kkernel/src/system.rs deleted file mode 100644 index 9443f5b2..00000000 --- a/kkernel/src/system.rs +++ /dev/null @@ -1,218 +0,0 @@ -//! uname系统调用实现 -use syscall_table::syscall_func; -use constants::sys::{Rusage, RusageFlag, Sysinfo, SyslogAction, TimeVal}; -use constants::{AlienResult, LinuxErrno}; -use core::cmp::min; -use timer::{get_time_ms, TimeFromFreq}; - -use crate::task::current_task; - -/// 记录系统信息的结构,包括操作系统名、在网络中的用户名、操作系统release和version版本、硬件类型、域名等信息。 -#[repr(C)] -#[derive(Copy, Clone)] -pub struct Utsname { - /// 操作系统名 - sysname: [u8; 65], - /// Name within communications network to which the node is attached - nodename: [u8; 65], - /// 系统发行版 - release: [u8; 65], - /// 系统版本 - version: [u8; 65], - /// 硬件类型 - machine: [u8; 65], - /// 域名 - domainname: [u8; 65], -} - -/// 返回系统信息,信息保存在[`Utsname`]结构中。 -fn system_info() -> Utsname { - const SYSNAME: &str = "Linux"; - const NODENAME: &str = "Alien"; - const RELEASE: &str = "5.1"; - const VERSION: &str = "5.1"; - const MACHINE: &str = "riscv64"; - const DOMAINNAME: &str = "RustOS"; - let mut name = Utsname { - sysname: [0; 65], - nodename: [0; 65], - release: [0; 65], - version: [0; 65], - machine: [0; 65], - domainname: [0; 65], - }; - name.sysname[..SYSNAME.len()].copy_from_slice(SYSNAME.as_bytes()); - name.nodename[..NODENAME.len()].copy_from_slice(NODENAME.as_bytes()); - name.release[..RELEASE.len()].copy_from_slice(RELEASE.as_bytes()); - name.version[..VERSION.len()].copy_from_slice(VERSION.as_bytes()); - name.machine[..MACHINE.len()].copy_from_slice(MACHINE.as_bytes()); - name.domainname[..DOMAINNAME.len()].copy_from_slice(DOMAINNAME.as_bytes()); - name -} - -/// 一个系统调用,返回系统信息。信息包括操作系统名、在网络中的用户名、操作系统release和version版本、硬件类型、域名等信息,详情可见[`Utsname`]。 -/// -/// 函数成功执行后返回0。 -#[syscall_func(160)] -pub fn uname(utsname: *const u8) -> isize { - let task = current_task().unwrap(); - task.access_inner() - .copy_to_user(&system_info(), utsname as *mut Utsname); - 0 -} - - -const LOG_BUF_LEN: usize = 4096; -const LOG: &str = r" -[ 0.000000] Linux version 5.10.0-7-riscv64 (debian-kernel@lists.debian.org) (gcc-10 (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2) #1 SMP Debian 5.10.40-1 (2021-05-28) -"; - -/// (待完善)一个系统调用函数,用于对内核消息环状缓冲区进行操作。 -/// -/// + `log_type`: 指明操作的类型,具体值可见[`SyslogAction`]; -/// + `buf`: 指明读取消息时,消息要保存到的位置; -/// + `len`: 指明具体操作时,对于消息读取的长度限制。真正的读取消息的长度将取决于就传入的`len`和`LOG_BUF_LEN`的最小值。 -/// -/// 当`log_type`为`READ`、`ReadAll`、`ReadClear`三种flag,正确执行后返回读取消息的长度; -/// 当`log_type`为`Unknown`时,会返回`EINVAL`;当`log_type`为`OPEN`或`CLOSE`时,函数不进行任何操作后返回0。 -/// 目前Alien仅支持上述`log_type`值,其余值都将不进行任何操作后返回0。 -/// -/// Reference: [syslog](https://man7.org/linux/man-pages/man2/syslog.2.html) -#[syscall_func(116)] -pub fn syslog(log_type: u32, buf: usize, len: usize) -> isize { - let log_type = SyslogAction::try_from(log_type); - if log_type.is_err() { - return LinuxErrno::EINVAL as isize; - } - match log_type.unwrap() { - SyslogAction::OPEN | SyslogAction::CLOSE => 0, - SyslogAction::READ | SyslogAction::ReadAll | SyslogAction::ReadClear => { - let min_len = min(len, LOG_BUF_LEN); - let task = current_task().unwrap(); - // the buf may be not valid, so we need to check it -- > sbrk heap - let mut buf = task.transfer_buffer(buf as *mut u8, min_len); - let log = LOG.as_bytes(); - let mut offset = 0; - buf.iter_mut().for_each(|buf| { - let copy_len = min(log.len() - offset, buf.len()); - buf[..copy_len].copy_from_slice(&log[offset..offset + copy_len]); - offset += copy_len; - }); - offset as isize - } - SyslogAction::Unknown => LinuxErrno::EINVAL as isize, - _ => 0, - } -} - -extern "C" { - fn ekernel(); -} - -/// 一个系统调用函数,用于获取系统相关信息。信息包括系统的自启动经过的时间、对于内存的使用情况、共享存储区的大小、 -/// 缓冲区与交换区的大小、当前进程数目等,具体可见[`Sysinfo`]。获取到的信息将保存到`dst_info`所指向的[`Sysinfo`]结构处。 -/// -/// 目前功能还有待完善。正确执行后返回0。 -#[syscall_func(179)] -pub fn sys_info(dst_info: usize) -> isize { - const LINUX_SYSINFO_LOADS_SCALE: usize = 65536; - let task = current_task().unwrap(); - // calculate the task number - let task_number = 10; // fake task number - let machine_info = platform::platform_machine_info(); - let memory_info = machine_info.memory.clone(); - let info = Sysinfo { - uptime: (get_time_ms() / 1000) as usize, - loads: [ - task_number * LINUX_SYSINFO_LOADS_SCALE / 60, - task_number * LINUX_SYSINFO_LOADS_SCALE / 300, - task_number * LINUX_SYSINFO_LOADS_SCALE / 900, - ], - totalram: memory_info.end - memory_info.start, - freeram: memory_info.end - ekernel as usize, - sharedram: 0, - bufferram: 0, - totalswap: 0, - freeswap: 0, - procs: task_number as u16, - totalhigh: 0, - freehigh: 0, - mem_unit: 1, - }; - task.access_inner() - .copy_to_user(&info, dst_info as *mut Sysinfo); - 0 -} - -/// (待实现)一个系统调用,设置进程调度的参数。目前直接返回0。 -#[syscall_func(118)] -pub fn sched_setparam() -> isize { - 0 -} - -/// (待实现)一个系统调用,获取进程调度的参数。目前直接返回0。 -#[syscall_func(121)] -pub fn sched_getparam() -> isize { - 0 -} - -/// (待实现)一个系统调用,设置进程CPU亲和力(位掩码),使进程绑定在某一个或几个CPU上运行,避免在CPU之间来回切换,从而提高该进程的实时性能。目前直接返回0。 -#[syscall_func(122)] -pub fn sched_setaffinity() -> isize { - 0 -} - -/// (待完善)一个系统调用,获取某进程对CPU的亲和力(位掩码)。当前进程的cpu亲和力将保存到`mask`所指向的位置。函数执行成功后返回8。 -#[syscall_func(123)] -pub fn sched_getaffinity(pid: usize, size: usize, mask: usize) -> isize { - warn!( - "sched_getaffinity: pid: {}, size: {}, mask: {}", - pid, size, mask - ); - assert_eq!(pid, 0); - let task = current_task().unwrap(); - let res = task.access_inner().cpu_affinity; - let mask = task.access_inner().transfer_raw_ptr_mut(mask as *mut usize); - *mask = res; - 8 -} - -/// (待实现)一个系统调用,用于获取当前CPU的调度策略。目前直接返回0。 -#[syscall_func(120)] -pub fn sched_getscheduler(pid: usize) -> isize { - assert_eq!(pid, 0); - // let task = current_task().unwrap(); - 0 -} - -/// (待实现)一个系统调用,用于设置当前CPU的调度策略。目前直接返回0。 -#[syscall_func(119)] -pub fn sched_setscheduler(_pid: usize, _policy: usize, _param: usize) -> isize { - 0 -} - - - -/// (待完善)一个系统调用,用于获取对系统资源的使用量信息。获取的信息将保存到`usage`所指向的[`Rusage`]结构中。 -/// -/// 可以通过`who`修改获取信息的对象,包括: -/// + `RUSAGE_SELF`: 返回调用该函数进程的资源用量统计,会返回该进程下所有线程的资源用量之和; -/// + `RUSAGE_CHILDREN`: 返回调用该函数进程所有已终止且被回收子进程的资源用量统计. -/// + `RUSAGE_THREAD`: 返回调用该函数线程的资源用量统计。 -/// -/// 在Alien中,目前仅支持`RUSAGE_SELF`。且返回的信息目前仅有[`Rusage`]下的`ru_utime`和`ru_stime`字段。 -/// -/// 正确执行后返回0。 -#[syscall_func(165)] -pub fn getrusage(who: isize, usage: usize) -> AlienResult { - let who = RusageFlag::try_from(who).map_err(|_| LinuxErrno::EINVAL)?; - info!("getrusage: who: {:?}, usage: {}", who, usage); - let task = current_task().unwrap(); - let static_info = task.access_inner().statistical_data().clone(); - let mut task_usage = Rusage::new(); - task_usage.ru_utime = TimeVal::from_freq(static_info.tms_utime); - task_usage.ru_stime = TimeVal::from_freq(static_info.tms_stime); - task.access_inner() - .copy_to_user(&task_usage, usage as *mut Rusage); - Ok(0) -} \ No newline at end of file diff --git a/kkernel/src/task/context.rs b/kkernel/src/task/context.rs deleted file mode 100644 index 01a60b56..00000000 --- a/kkernel/src/task/context.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! 线程切换的上下文结构 -use core::arch::global_asm; - -/// 线程切换需要保存的上下文 -/// -/// 线程切换由__switch()完成,这个汇编函数不会由编译器完成寄存器保存,因此需要手动保存 -#[derive(Debug, Clone)] -#[repr(C)] -pub struct Context { - /// ra 寄存器 - ra: usize, - /// sp 寄存器值 - sp: usize, - /// s0 ~ s11 - s: [usize; 12], -} - -impl Context { - /// 创建一个新的上下文,默认 s0 ~ s11 的值为 0 - pub fn new(ra: usize, sp: usize) -> Self { - Self { ra, sp, s: [0; 12] } - } - - /// 创建一个全为 0 的上下文 - pub const fn empty() -> Self { - Self { - ra: 0, - sp: 0, - s: [0; 12], - } - } -} - -global_asm!(include_str!("switch.asm")); - -extern "C" { - pub fn __switch(current_task_cx_ptr: *mut Context, next_task_cx_ptr: *const Context); -} - -/// 交换前后两个线程的上下文,调用 `switch.asm` 中的 `__switch` -#[inline(always)] -pub fn switch(current_task_cx_ptr: *mut Context, next_task_cx_ptr: *const Context) { - unsafe { - __switch(current_task_cx_ptr, next_task_cx_ptr); - } -} diff --git a/kkernel/src/task/cpu.rs b/kkernel/src/task/cpu.rs deleted file mode 100644 index 6a5d3744..00000000 --- a/kkernel/src/task/cpu.rs +++ /dev/null @@ -1,496 +0,0 @@ -//! Alien 中有关进程的系统调用 和 多核的相关支持。 -use alloc::string::{String, ToString}; -use alloc::sync::Arc; -use alloc::vec::Vec; -use core::cell::UnsafeCell; -use log::{error, info, warn}; -use smpscheduler::{FifoSmpScheduler, FifoTask, ScheduleHart}; -use spin::Lazy; - -use constants::ipc::FutexOp; -use constants::signal::SignalNumber; -use constants::task::{CloneFlags, WaitOptions}; -use constants::{AlienError, AlienResult}; -use constants::{PrLimit, PrLimitRes}; -use ksync::Mutex; -use syscall_table::syscall_func; - -use config::CPU_NUM; -use crate::fs; -use crate::ipc::{futex, global_logoff_signals}; -use platform::system_shutdown; -use crate::task::context::Context; -use crate::task::schedule::schedule; -use crate::task::task::{Task, TaskState}; -use crate::task::INIT_PROCESS; -use crate::trap::{check_task_timer_expired, TrapFrame}; -use arch::hart_id; - -/// 记录当前 CPU 上正在执行的线程 和 线程上下文 -#[derive(Debug, Clone)] -pub struct CPU { - /// 正在该 CPU 上运行的线程的控制块 - pub task: Option>, - /// 当前线程的上下文 - pub context: Context, -} - -impl CPU { - /// 获取一个空的 CPU - const fn empty() -> Self { - Self { - task: None, - context: Context::empty(), - } - } - - /// 获取线程上下文的一个 不可变引用 的指针 - pub fn get_context_raw_ptr(&self) -> *const Context { - &self.context as *const Context - } - - /// 获取线程上下文的一个 可变引用 的指针 - pub fn get_context_mut_raw_ptr(&mut self) -> *mut Context { - &mut self.context as *mut Context - } -} -pub struct SafeRefCell(UnsafeCell); -impl SafeRefCell { - const fn new(t: T) -> Self { - Self(UnsafeCell::new(t)) - } -} -/// #Safety: Only the corresponding cpu will access it. -unsafe impl Sync for SafeRefCell {} - -const DEFAULT_CPU: SafeRefCell = SafeRefCell::new(CPU::empty()); -/// 保存每个核的信息 -static CPU_MANAGER: [SafeRefCell; CPU_NUM] = [DEFAULT_CPU; CPU_NUM]; -#[derive(Debug)] -pub struct ScheduleHartImpl; - -impl ScheduleHart for ScheduleHartImpl { - fn hart_id() -> usize { - hart_id() - } -} -/// 多核调度器 -pub static GLOBAL_TASK_MANAGER: Lazy< - FifoSmpScheduler, Mutex<()>, ScheduleHartImpl>, -> = Lazy::new(|| FifoSmpScheduler::new()); - -/// 获取当前 cpu 的信息 -pub fn current_cpu() -> &'static mut CPU { - let hart_id = arch::hart_id(); - unsafe { &mut (*(CPU_MANAGER[hart_id].0.get())) } -} - -/// 获取当前 CPU 上的线程 -pub fn current_task() -> Option<&'static Arc> { - let cpu = current_cpu(); - cpu.task.as_ref() -} - -/// 获取当前进程的虚拟页表的 token (root ppn) -pub fn current_user_token() -> usize { - let task = current_task().unwrap(); - task.token() -} - -/// 获取当前进程的 trap 帧(上下文) -pub fn current_trap_frame() -> &'static mut TrapFrame { - let task = current_task().unwrap(); - task.trap_frame() -} - -/// 一个系统调用,用于终止进程。 -/// -/// 运行成功后,调用该函数的进程将转变为Zombie状态,同时回收部分资源,并让渡CPU执行其他的进程。 -/// 等待父进程得知其终止退出后,将回收该进程的其余资源。 -/// `exit_code`中的值,将会在其父进程调用[`wait4`]时,作为信息传递给父进程。 -/// 当一个具有子进程的进程终止时,其所有子进程将转交至init进程,由init进程完成其子进程相关资源的回收。 -/// 当`clear_child_tid`不为0时,会将`clear_child_tid`该处的值置为0,同时内核唤醒当前正在等待的futex。 -/// -/// 当调用该函数的进程为`pid==0`的init进程时,将直接调用`system_shutdown`使得内核终止。 -#[syscall_func(93)] -pub fn do_exit(exit_code: i32) -> isize { - let task = current_task().unwrap(); - let exit_code = (exit_code & 0xff) << 8; - if task.get_pid() == 0 { - println!("Init process exit with code {}", exit_code); - system_shutdown(); - } - { - let init = INIT_PROCESS.clone(); - task.take_children().into_iter().for_each(|child| { - child.update_parent(init.clone()); - init.insert_child(child); - }); - } - task.update_state(TaskState::Zombie); - task.update_exit_code(exit_code); - global_logoff_signals(task.get_tid() as usize); - // clear_child_tid 的值不为 0,则将这个用户地址处的值写为0 - let addr = task.access_inner().clear_child_tid; - if addr != 0 { - // 确认这个地址在用户地址空间中。如果没有也不需要报错,因为线程马上就退出了 - let addr = task.transfer_raw_ptr(addr as *mut i32); - *addr = 0; - } - - // 回收一些物理页,不然等到wait系统调用真正进行回收时,可能会出现OOM - // 可回收物理页包括trap页以及内核栈页 - // 在这里还不能回收内核栈页,因为还需要用到内核栈页来执行下面的代码 - // 所以只回收trap页 - // 在wait系统调用中,会回收内核栈页 - task.pre_recycle(); - info!("pre recycle done"); - let clear_child_tid = task.futex_wake(); - if clear_child_tid != 0 { - let phy_addr = task.transfer_raw_ptr(clear_child_tid as *mut usize); - *phy_addr = 0; - error!("exit wake futex on {:#x}", clear_child_tid); - futex(clear_child_tid, FutexOp::FutexWake as u32, 1, 0, 0, 0); - } else { - error!("exit clear_child_tid is 0"); - } - schedule(); - 0 -} - -/// 一个系统调用,退出当前进程(进程组)下的所有线程(进程)。 -/// -/// 目前该系统调用直接调用[`do_exit`],有关进程组的相关功能有待实现。 -#[syscall_func(94)] -pub fn exit_group(exit_code: i32) -> isize { - do_exit(exit_code) -} - -/// 一个系统调用,用于使当前正在运行的进程让渡CPU。 -#[syscall_func(124)] -pub fn do_suspend() -> isize { - let task = current_task().unwrap(); - task.access_inner().update_timer(); - check_task_timer_expired(); - task.update_state(TaskState::Ready); - schedule(); - 0 -} - -/// (待实现)设置进程组的id。目前直接返回0。 -#[syscall_func(154)] -pub fn set_pgid() -> isize { - 0 -} - -/// (待实现)获取进程组的id。目前直接返回0。 -#[syscall_func(155)] -pub fn get_pgid() -> isize { - 0 -} - -/// 创建一个新的session,并使得使用系统调用的当前task成为新session的leader,同时也是新进程组的leader(待实现) -#[syscall_func(157)] -pub fn set_sid() -> isize { - 0 -} - -/// 获取当前正在运行task的pid号。在Alien中pid作为线程组的标识符,位于同一线程组中的线程的pid相同。 -#[syscall_func(172)] -pub fn get_pid() -> isize { - let process = current_task().unwrap(); - process.get_pid() -} - -/// 获取当前正在运行task的ppid号,即父task的pid号。 -#[syscall_func(173)] -pub fn get_ppid() -> isize { - let process = current_task().unwrap(); - let parent = process.access_inner().parent.clone(); - if parent.is_none() { - return 0; - } else { - parent.unwrap().upgrade().unwrap().get_pid() - } -} - -/// (待实现)获取用户 id。在实现多用户权限前默认为最高权限。目前直接返回0。 -#[syscall_func(174)] -pub fn getuid() -> isize { - 0 -} - -/// (待实现)获取有效用户 id,即相当于哪个用户的权限。在实现多用户权限前默认为最高权限。目前直接返回0。 -#[syscall_func(175)] -pub fn geteuid() -> isize { - 0 -} - -/// (待实现)获取用户组 id。在实现多用户权限前默认为最高权限。目前直接返回0。 -#[syscall_func(176)] -pub fn getgid() -> isize { - 0 -} - -/// (待实现)获取有效用户组 id,即相当于哪个用户组的权限。在实现多用户组权限前默认为最高权限。目前直接返回0。 -#[syscall_func(177)] -pub fn getegid() -> isize { - 0 -} - -/// 获取当前正在运行task的tid号。在Alien中tid作为task的唯一标识符。 -#[syscall_func(178)] -pub fn get_tid() -> isize { - let process = current_task().unwrap(); - process.get_tid() -} - -/// 一个系统调用,用于创建一个子进程。 -/// -/// 与传统的`fork()`的功能大致相同,创建一个子进程,并将其放入任务队列中等待cpu进行调度。 -/// 但与`fork()`的功能相比,`Alien`中`clone`系统调用提供了更多详细的控制, -/// 管理父进程和子进程之间的共享资源,例如调用者可以控制父子进程之间是否共享虚拟内存空间、文件描述符表、 -/// 信号处理程序等。 -/// -/// `flag`用于控制父子进程之间资源的共享程度,有关flag值及其相关含义设置可见[`CloneFlags`]和[`SignalNumber`]。 -/// `stack`用于控制子进程的用户栈。由于clone产生的子进程有可能和父进程共享内存,所以它不能使用父进程的栈。 -/// `ptid`是一个在父进程地址空间中的地址,用于在创建子进程成功后向该位置写入子进程的tid号。在flag包含`CLONE_PARENT_SETTID`时才会发挥效果。 -/// `tls`用于为子进程创建新的TLS(thread-local storage)值,在flag包含`CLONE_SETTLS`时才会实际产生效果。 -/// `ctid`用于给子进程中的[`set_child_tid`]和[`clear_child_tid`]赋值(分别在flag中包含`CLONE_CHILD_SETTID`和`CLONE_CHILD_CLEARTID`时产生效果)。 -/// -/// 成功创建子进程后父进程会返回子进程的tid号,子进程的返回值将被设置为0;否则返回-1。 -/// -/// Reference: [clone](https://www.man7.org/linux/man-pages/man2/clone.2.html) -#[syscall_func(220)] -pub fn clone(flag: usize, stack: usize, ptid: usize, tls: usize, ctid: usize) -> isize { - let clone_flag = CloneFlags::from_bits_truncate(flag as u32); - // check whether flag include signal - let sig = flag & 0xff; - let sig = SignalNumber::from(sig); - let task = current_task().unwrap(); - - let child_num = task.access_inner().children.len(); - if child_num >= 10 { - do_suspend(); - } - let new_task = task.t_clone(clone_flag, stack, sig, ptid, tls, ctid); - if new_task.is_none() { - return -1; - } - let new_task = new_task.unwrap(); - // update return value - let trap_frame = new_task.trap_frame(); - trap_frame.update_res(0); - let tid = new_task.get_tid(); - GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(new_task))); - // do_suspend(); - tid -} - -/// 一个系统调用,用于执行一个文件。 -/// -/// `path`用于指明要执行的文件的绝对路径。 -/// `args_ptr`用于指明保存启动可执行文件时要传入的参数的地址。 -/// `env`用于指明保存相关环境变量的地址。 -/// -/// 成功执行文件后会返回0;否则会返回-1或错误类型。 -#[syscall_func(221)] -pub fn do_exec(path: *const u8, args_ptr: usize, env: usize) -> AlienResult { - let task = current_task().unwrap(); - let mut path_str = task.transfer_str(path); - // get the args and push them into the new process stack - let (mut args, envs) = parse_user_arg_env(args_ptr, env); - warn!("exec path: {}", path_str); - warn!("exec args: {:?} ,env: {:?}", args, envs); - if path_str.ends_with(".sh") { - if args.is_empty() { - let mut new_path = path_str.clone(); - new_path.push('\0'); - args.insert(0, new_path); - } - path_str = "./busybox".to_string(); - args.insert(0, "sh\0".to_string()); - } - let mut data = Vec::new(); - if path_str.contains("libc-bench") { - path_str = "libc-bench2".to_string(); - } - if fs::read_all(&path_str, &mut data) { - let res = task.exec(&path_str, data.as_slice(), args, envs); - if res.is_err() { - return Err(AlienError::ENOEXEC); - } - Ok(0) - } else { - info!("exec {} failed", path_str); - Err(AlienError::ENOENT) - } -} - -/// 一个系统调用,用于父进程等待某子进程退出。 -/// -/// `pid`用于指明等待的子进程pid号。`pid == -1`表示父进程等待任意子进程返回。 -/// 当`exit_code`非空时,将会把退出的子程序的退出值赋给`exit_code`所指向的位置。 -/// `options`主要用于控制`wait4`的执行逻辑,例如当`wait_options`包含`WNOHANG`时,即使未发现子程序返回,函数也将直接返回0。 -/// -/// 一般`wait4`会使得父进程阻塞,直到子进程退出,返回退出的子进程pid。但当`wait_options`包含`WNOHANG`时,即使未发现子程序返回,函数也将直接返回0。 -/// 当父进程的所有子进程中不包含进程号为pid的子进程,将返回-1。 -/// -/// Reference:[wait](https://man7.org/linux/man-pages/man2/wait.2.html) -#[syscall_func(260)] -pub fn wait4(pid: isize, exit_code: *mut i32, options: u32, _rusage: *const u8) -> isize { - loop { - let task = current_task().unwrap(); - if task - .children() - .iter() - .find(|child| child.get_pid() == pid || pid == -1) - .is_none() - { - return -1; - } - let res = task.check_child(pid); - if let Some(index) = res { - let child = task.remove_child(index); - assert_eq!( - Arc::strong_count(&child), - 1, - "Father is [{}-{}], wait task is [{}-{}]", - task.get_pid(), - task.get_tid(), - child.get_pid(), - child.get_tid() - ); - if !exit_code.is_null() { - let exit_code_ref = task.transfer_raw_ptr(exit_code); - *exit_code_ref = child.exit_code(); - } - return child.get_tid(); - } else { - let wait_options = WaitOptions::from_bits(options).unwrap(); - if wait_options.contains(WaitOptions::WNOHANG) { - return 0; - } else { - do_suspend(); - } - } - } -} - -/// 一个系统调用,用于改变堆区的大小(目前仅可以增加堆区大小) -/// -/// `addr`用于指明扩充堆区后,堆区的末尾位置。 -/// 当`addr`所标识的位置在当前堆起始位置的前方,或者堆当前已使用的末尾位置的前方时,将会导致增加堆区大小失败。 -/// -/// 成功增加堆区大小时,函数返回堆当前已使用的末尾位置;否则返回-1。 -#[syscall_func(214)] -pub fn do_brk(addr: usize) -> isize { - let process = current_task().unwrap(); - let mut inner = process.access_inner(); - let heap_info = inner.heap_info(); - if addr == 0 { - return heap_info.current as isize; - } - if addr < heap_info.start || addr < heap_info.current { - // panic!("heap can't be shrinked"); - return -1; - } - let res = inner.extend_heap(addr); - if res.is_err() { - return -1; - } - res.unwrap() as isize -} - -/// 一个系统调用,用于修改进程clear_child_tid的值,同时返回进程的tid。 -#[syscall_func(96)] -pub fn set_tid_address(tidptr: usize) -> isize { - let task = current_task().unwrap(); - task.set_tid_address(tidptr); - task.get_tid() -} - -/// 一个系统调用,用于修改进程的资源限制。 -/// -/// 进程对其拥有的资源,包括用户栈大小、可以打开的文件描述符数、用户地址空间大小等都有所上限。 -/// -/// `prlimit64`则可以根据资源的种类对不同的资源进行大小的限制。针对每一具体限制都包括软上限和硬上限,具体可见[`PrLimit`]。 -/// `pid`用于指明需要修改资源限制的进程的pid号。 -/// `resource`用于指明需要修改的资源类型,可选的值包括`RLIMIT_STACK`、`RLIMIT_NOFILE`、`RLIMIT_AS`等,详情可见[`PrLimitRes`]。 -/// `new_limit`用于指明新限制的指针,如果为空指针则不进行新限制的赋值。 -/// `old_limit`用于指明存放旧限制的指针,如果为空则不进行旧限制的保存。 -/// -/// 正确执行后会返回0;如果输入的pid为0或者为当前正在运行的进程号,则会直接终止。 -#[syscall_func(261)] -pub fn prlimit64(pid: usize, resource: usize, new_limit: *const u8, old_limit: *mut u8) -> isize { - assert!(pid == 0 || pid == current_task().unwrap().get_pid() as usize); - let task = current_task().unwrap(); - let mut inner = task.access_inner(); - if let Ok(resource) = PrLimitRes::try_from(resource) { - if !old_limit.is_null() { - let limit = inner.get_prlimit(resource); - warn!("get rlimit nofile to {:?}", limit); - inner.copy_to_user(&limit, old_limit as *mut PrLimit); - } - match resource { - PrLimitRes::RlimitStack => {} - PrLimitRes::RlimitNofile => { - if !new_limit.is_null() { - let mut limit = PrLimit::new(0, 0); - inner.copy_from_user(new_limit as *const PrLimit, &mut limit); - warn!("set rlimit nofile to {:?}", limit); - inner.set_prlimit(resource, limit); - } - } - PrLimitRes::RlimitAs => {} - } - } - 0 -} - -/// 用于exec可执行文件时,分别在args_ptr和env_ptr所指向的地址处取出参数和环境变量 -fn parse_user_arg_env(args_ptr: usize, env_ptr: usize) -> (Vec, Vec) { - let task = current_task().unwrap(); - let mut args = Vec::new(); - - if args_ptr != 0 { - let mut start = args_ptr as *mut usize; - loop { - let arg = task.transfer_raw_ptr(start); - if *arg == 0 { - break; - } - args.push(*arg); - start = unsafe { start.add(1) }; - } - } - let args = args - .into_iter() - .map(|arg| { - let mut arg = task.transfer_str(arg as *const u8); - arg.push('\0'); - arg - }) - .collect::>(); - let mut envs = Vec::new(); - if env_ptr != 0 { - let mut start = env_ptr as *mut usize; - loop { - let env = task.transfer_raw_ptr(start); - if *env == 0 { - break; - } - envs.push(*env); - start = unsafe { start.add(1) }; - } - } - let envs = envs - .into_iter() - .map(|env| { - let mut env = task.transfer_str(env as *const u8); - env.push('\0'); - env - }) - .collect::>(); - (args, envs) -} diff --git a/kkernel/src/task/heap.rs b/kkernel/src/task/heap.rs deleted file mode 100644 index cbe663ae..00000000 --- a/kkernel/src/task/heap.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! 记录进程的堆空间的相关信息 - -/// 记录进程的堆空间的相关信息 -#[derive(Debug, Clone)] -pub struct HeapInfo { - /// 堆使用到的位置 - pub current: usize, - /// 堆空间的起始位置 - pub start: usize, - /// 堆空间的末尾位置 - pub end: usize, -} - -impl HeapInfo { - /// 新建一个 HeapInfo - pub fn new(start: usize, end: usize) -> Self { - HeapInfo { - current: start, - start, - end, - } - } - - /// 返回堆的大小 - #[allow(unused)] - pub fn size(&self) -> usize { - self.end - self.start - } - - /// 返回堆是否包括某地址 - #[allow(unused)] - pub fn contains(&self, addr: usize) -> bool { - addr >= self.start && addr < self.end - } - - #[allow(unused)] - /// 堆大小增加 size 个单位 - pub fn increase(&mut self, size: usize) { - self.end += size; - } - - /// 重新设置堆空间的头 - #[allow(unused)] - pub fn set_start(&mut self, start: usize) { - self.start = start; - } - - #[allow(unused)] - /// 重新设置堆空间的尾 - pub fn set_end(&mut self, end: usize) { - self.end = end; - } - - /// 返回堆空间是否为空 - #[allow(unused)] - pub fn is_empty(&self) -> bool { - self.start == self.end - } -} diff --git a/kkernel/src/task/mod.rs b/kkernel/src/task/mod.rs deleted file mode 100644 index 1376dd20..00000000 --- a/kkernel/src/task/mod.rs +++ /dev/null @@ -1,96 +0,0 @@ -//! Alien 中有关进程管理的相关数据结构 -//! -//! [`context`] 子模块定义了 Alien 中线程上下文的相关结构. -//! [`cpu`] 子模块中指明了 Alien 中有关进程的系统调用 和 多核的相关支持。 -//! [`heap`] 子模块定义了 Alien 记录进程堆空间的相关信息的结构。 -//! [`schedule`] 子模块指明了 Alien 中有关 CPU 调度的相关机制 -//! [`stack`] 子模块定义了 Alien 中有关内核栈的相关结构。 -//! [`task`] 子模块定义了 Alien 中有关进程控制块的定义。 -use alloc::sync::Arc; -use alloc::vec::Vec; -use smpscheduler::FifoTask; -use spin::Lazy; -pub use cpu::*; -use devices::DeviceWithTask; -use drivers::{DriverTask, DriverWithTask}; -pub use task::{StatisticalData, Task, TaskState}; -use vfs::SYSTEM_ROOT_FS; - -use crate::fs::{read_all}; -use crate::task::schedule::schedule; -pub use crate::task::task::FsContext; - -mod context; -mod cpu; -mod heap; -pub mod schedule; -mod stack; -mod task; - -/// 初始进程(0号进程) -pub static INIT_PROCESS: Lazy> = Lazy::new(|| { - let mut data = Vec::new(); - read_all("/bin/init", &mut data); - // let data = INIT; - assert!(data.len() > 0); - let task = Task::from_elf("/bin/init", data.as_slice()).unwrap(); - Arc::new(task) -}); - -/// 将初始进程加入进程池中进行调度 -pub fn init_process() { - let task = INIT_PROCESS.clone(); - let cwd = SYSTEM_ROOT_FS.get().unwrap().clone(); - let root = cwd.clone(); - task.access_inner().fs_info = FsContext::new(root, cwd); - GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); - println!("Init process success"); -} - - -impl DriverTask for Task { - fn to_wait(&self) { - self.update_state(TaskState::Waiting) - } - - fn to_wakeup(&self) { - self.update_state(TaskState::Ready) - } - - fn have_signal(&self) -> bool { - self.access_inner().signal_receivers.lock().have_signal() - } -} -pub struct DriverTaskImpl; -impl DriverWithTask for DriverTaskImpl{ - fn get_task(&self) -> Arc { - let task = current_task().unwrap(); - task.clone() - } - - fn put_task(&self, task: Arc) { - let task = task.downcast_arc::().map_err(|_| ()).unwrap(); - GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); - } - - fn suspend(&self) { - do_suspend(); - } -} - - -impl DeviceWithTask for DriverTaskImpl { - fn transfer_ptr_raw(&self, ptr: usize) -> usize { - let task = current_task().unwrap(); - task.transfer_raw(ptr) - } - - fn transfer_buf_raw(&self, src: usize, size:usize) -> Vec<&mut [u8]> { - let task = current_task().unwrap(); - task.transfer_buffer(src as * const u8,size) - } -} - - -// online test has no sort.src -// pub static SORT_SRC: &[u8] = include_bytes!("../../../sdcard/sort.src"); diff --git a/kkernel/src/task/schedule.rs b/kkernel/src/task/schedule.rs deleted file mode 100644 index 4f9f72fe..00000000 --- a/kkernel/src/task/schedule.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! CPU 调度 -use alloc::sync::Arc; -use core::arch::asm; -use smpscheduler::FifoTask; - -use constants::signal::SignalNumber; - -use crate::ipc::send_signal; -use crate::task::context::switch; -use crate::task::cpu::current_cpu; -use crate::task::task::TaskState; -use crate::task::GLOBAL_TASK_MANAGER; -use crate::trap::check_timer_interrupt_pending; - -/// 在 CPU 启动并初始化完毕后初次进入用户态时,或者在一个任务将要让渡 CPU 时 将会执行该函数。 -/// -/// 如果当前 CPU 上有任务正在执行,那么将根据该任务当前的状态进行操作。 -/// - 如果该任务处于睡眠或等待状态,将会把其任务的控制块取出丢弃掉。 -/// - 如果该任务处于僵尸状态,将会向其父进程发送信号,令其回收该任务的控制块。 -/// - 如果该任务处于其他状态,我们将其放入线程池中等待下一次分配。 -/// -/// 之后如果在线程池中有任务需要调度,那么就把该任务的上下文切换到 CPU 上来运行; -/// 否则该 CPU 将进入等待状态,等待其它核的中断信号。 -pub fn run_task() -> ! { - loop { - { - let cpu = current_cpu(); - if cpu.task.is_some() { - let task = cpu.task.take().unwrap(); - match task.state() { - TaskState::Sleeping | TaskState::Waiting => { - // drop(task); - } - TaskState::Zombie => { - // 退出时向父进程发送信号,其中选项可被 sys_clone 控制 - if task.send_sigchld_when_exit || task.pid == task.tid.0 { - let parent = task - .access_inner() - .parent - .clone() - .unwrap() - .upgrade() - .unwrap(); - send_signal(parent.pid, SignalNumber::SIGCHLD as usize); - } - // 通知全局表将 signals 删除 - task.terminate(); - } - _ => { - GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); - } - } - } - } - let cpu = current_cpu(); - if let Some(task) = GLOBAL_TASK_MANAGER.pick_next_task() { - // if process.get_tid() >= 1 { - // warn!("switch to task {}", task.get_tid()); - // } - // update state to running - task.inner().update_state(TaskState::Running); - // get the process context - let context = task.inner().get_context_raw_ptr(); - cpu.task = Some(task.inner().clone()); - // switch to the process context - let cpu_context = cpu.get_context_mut_raw_ptr(); - // warn!("switch to task {}", process.get_tid()); - drop(task); - switch(cpu_context, context); - } else { - unsafe { asm!("wfi") } - } - } -} - -/// 切换线程上下文,调度当前在 CPU 上执行的线程 让渡出 CPU -pub fn schedule() { - check_timer_interrupt_pending(); - let cpu = current_cpu(); - let task = cpu.task.clone().unwrap(); - let cpu_context = cpu.get_context_raw_ptr(); - let context = task.get_context_mut_raw_ptr(); - drop(task); - switch(context, cpu_context); -} diff --git a/kkernel/src/task/stack.rs b/kkernel/src/task/stack.rs deleted file mode 100644 index 31a575de..00000000 --- a/kkernel/src/task/stack.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! 进程内核栈空间 - -use config::{ FRAME_SIZE}; -use mem::{alloc_frames, free_frames}; - -/// 记录进程内核栈空间 -#[derive(Debug)] -pub struct Stack { - /// 栈帧 - start_ptr: usize, - pages: usize, -} - -impl Stack { - /// 通过帧的个数创建一块新的 内核栈 - pub fn new(pages: usize) -> Option { - let frames = alloc_frames(pages); - Some(Stack { - start_ptr:frames as usize, - pages - }) - } - - /// 获取帧顶指针 - pub fn top(&self) -> usize { - self.start_ptr + self.pages * FRAME_SIZE - } - - /// 回收内核栈空间。 - pub fn release(&self) { - free_frames(self.start_ptr as _, self.pages) - } -} diff --git a/kkernel/src/task/switch.asm b/kkernel/src/task/switch.asm deleted file mode 100644 index 3f985d24..00000000 --- a/kkernel/src/task/switch.asm +++ /dev/null @@ -1,34 +0,0 @@ -.altmacro -.macro SAVE_SN n - sd s\n, (\n+2)*8(a0) -.endm -.macro LOAD_SN n - ld s\n, (\n+2)*8(a1) -.endm - .section .text - .globl __switch -__switch: - # __switch( - # current_task_cx_ptr: *mut TaskContext, - # next_task_cx_ptr: *const TaskContext - # ) - # save kernel stack of current task - sd sp, 8(a0) - # save ra & s0~s11 of current execution - sd ra, 0(a0) - .set n, 0 - .rept 12 - SAVE_SN %n - .set n, n + 1 - .endr - # restore ra & s0~s11 of next execution - ld ra, 0(a1) - .set n, 0 - .rept 12 - LOAD_SN %n - .set n, n + 1 - .endr - # restore kernel stack of next task - ld sp, 8(a1) - ret - diff --git a/kkernel/src/task/task.rs b/kkernel/src/task/task.rs deleted file mode 100644 index b127bbef..00000000 --- a/kkernel/src/task/task.rs +++ /dev/null @@ -1,1813 +0,0 @@ -//! Alien 中任务控制块的相关定义。 -//! -//! Alien 中对于进程\线程的相关概念的设计与 Linux 类似,进程和线程共用一个控制块结构。 -//! 使用 `clone` 创建新的进程(线程)时,会根据 flag 指明父子进程之间资源共享的程度。 -//! tid 是标识不同任务的唯一标识。 -use config::*; -use crate::fs::file::File; -use crate::ipc::{global_register_signals, ShmInfo}; -use crate::task::context::Context; -use crate::task::heap::HeapInfo; -use crate::task::stack::Stack; -use timer::{read_timer, ITimerVal, TimeNow, ToClock}; -use crate::trap::{trap_common_read_file, trap_return, user_trap_vector, TrapFrame}; -use alloc::collections::BTreeMap; -use alloc::string::{String, ToString}; -use alloc::sync::{Arc, Weak}; -use alloc::vec::Vec; -use alloc::{format, vec}; -use constants::aux::*; -use constants::io::MapFlags; -use constants::ipc::RobustList; -use constants::signal::{SignalHandlers, SignalNumber, SignalReceivers, SignalUserContext}; -use constants::sys::TimeVal; -use constants::task::CloneFlags; -use constants::time::TimerType; -use constants::{AlienError, AlienResult}; -use constants::{LinuxErrno, PrLimit, PrLimitRes}; -use core::fmt::{Debug, Formatter}; -use core::ops::Range; -use bit_field::BitField; -use gmanager::MinimalManager; -use ksync::{Mutex, MutexGuard}; -use page_table::addr::{align_down_4k, align_up_4k, VirtAddr}; -use page_table::pte::MappingFlags; -use page_table::table::Sv39PageTable; -use spin::Lazy; -use vfscore::dentry::VfsDentry; -use mem::{FRAME_REF_MANAGER, kernel_satp, VmmPageAllocator}; -use vfs::SYSTEM_ROOT_FS; -use crate::fs::stdio::{STDIN, STDOUT}; -use crate::mm::loader::{build_cow_address_space, build_elf_address_space, build_thread_address_space, UserStack}; -use crate::mm::map::{MMapInfo, MMapRegion, ProtFlags}; - -type FdManager = MinimalManager>; - -/// 这里把MinimalManager复用为tid分配器,通常,MinimalManager会将数据插入到最小可用位置并返回位置, -/// 但tid的分配并不需要实际存储信息,因此可以插入任意的数据,这里为了节省空间,将数据定义为u8 -pub static TID_MANAGER: Lazy>> = - Lazy::new(|| Mutex::new(MinimalManager::new(MAX_THREAD_NUM))); - -/// 用于存储线程的tid -#[derive(Debug)] -pub struct TidHandle(pub usize); - -impl TidHandle { - /// 获取一个新的线程 tid (来自于 `TID_MANAGER` 分配) - pub fn new() -> Option { - let tid = TID_MANAGER.lock().insert(0); - if tid.is_err() { - return None; - } - Some(Self(tid.unwrap())) - } -} - -impl Drop for TidHandle { - fn drop(&mut self) { - TID_MANAGER.lock().remove(self.0).unwrap(); - } -} - -#[derive(Debug)] -pub struct Task { - /// 任务的唯一标识 - pub tid: TidHandle, - /// 作为进程时,pid == tid;作为线程时,pid 为其线程组 leader (父进程)的 tid 号。 - pub pid: usize, - /// 当退出时是否向父进程发送信号 SIGCHLD。 - /// 如果创建时带 CLONE_THREAD 选项,则不发送信号,除非它是线程组(即拥有相同pid的所有线程)中最后一个退出的线程; - /// 否则发送信号 - pub send_sigchld_when_exit: bool, - /// 内核栈 - pub kernel_stack: Stack, - /// 更详细的信息 - inner: Mutex, -} - -#[derive(Debug)] -pub struct TaskInner { - /// 任务名,一般为其文件路径加文件名 - pub name: String, - /// 线程计数器,用于分配同一个线程组中的线程序号 - pub threads: MinimalManager<()>, - /// 用于记录当前线程组中的线程个数 - pub thread_number: usize, - /// 地址空间 - pub address_space: Arc>>, - /// 线程状态 - pub state: TaskState, - /// 父亲任务控制块 - pub parent: Option>, - /// 孩子任务控制块的集合 - pub children: Vec>, - /// 文件描述符表 - pub fd_table: Arc>, - /// 任务上下文 - pub context: Context, - /// 文件系统的信息 - pub fs_info: FsContext, - /// 有关任务执行情况的统计信息 - pub statistical_data: StatisticalData, - /// 任务计时器 - pub timer: TaskTimer, - /// 返回值 - pub exit_code: i32, - /// 堆空间 - pub heap: Arc>, - /// 地址空间中的映射信息 - pub mmap: MMapInfo, - /// 信号量对应的一组处理函数。 - /// 因为发送信号是通过 pid/tid 查找的,因此放在 inner 中一起调用时更容易导致死锁 - pub signal_handlers: Arc>, - /// 接收信号的结构。每个线程中一定是独特的,而上面的 handler 可能是共享的 - pub signal_receivers: Arc>, - /// 子线程初始化时,存放 tid 的地址。当且仅当创建时包含 CLONE_CHILD_SETTID 才非0 - pub set_child_tid: usize, - /// 子线程初始化时,将这个地址清空;子线程退出时,触发这里的 futex。 - /// 在创建时包含 CLONE_CHILD_SETTID 时才非0,但可以被 sys_set_tid_address 修改 - pub clear_child_tid: usize, - /// 处理信号时,保存的之前的用户线程的上下文信息 - trap_cx_before_signal: Option, - /// 保存信息时,处理函数是否设置了 SIGINFO 选项 - /// 如果设置了,说明信号触发前的上下文信息通过 ucontext 传递给了用户, - /// 此时用户可能修改其中的 pc 信息(如musl-libc 的 pthread_cancel 函数)。 - /// 在这种情况下,需要手动在 sigreturn 时更新已保存的上下文信息 - pub signal_set_siginfo: bool, - /// robust 锁的列表 - pub robust: RobustList, - /// 共享内存 - pub shm: BTreeMap, - /// cpu 亲和力,用于 cpu 调度时 倾向于将该任务调度给 哪个 CPU - pub cpu_affinity: usize, - /// 进程创建文件时,文件权限的默认掩码 - pub unmask: usize, - /// 栈空间的信息 - pub stack: Range, - /// 是否需要等待 - pub need_wait: u8, -} - -#[derive(Debug, Copy, Clone)] -pub struct TaskTimer { - /// 计时器类型 - pub timer_type: TimerType, - /// 设置下一次触发计时器的区间 - /// - /// 当 timer_remained 归零时,如果 timer_interval 非零,则将其重置为 timer_interval 的值; - /// 否则,则这个计时器不再触发 - pub timer_interval: TimeVal, - /// 当前计时器还剩下多少时间。 - /// - /// 根据 timer_type 的规则不断减少,当归零时触发信号 - pub timer_remained: usize, - /// 上一次计时的开始时间 - pub start: usize, - /// 该计时器是否已经超时 - pub expired: bool, -} - -impl TaskTimer { - /// 清除当前的计数器信息,将 timer_remained 置为 0 - pub fn clear(&mut self) { - self.timer_type = TimerType::NONE; - self.timer_interval = TimeVal::new(); - self.timer_remained = 0; - self.expired = false; - } -} - -impl Default for TaskTimer { - /// 默认的任务计数器 - fn default() -> Self { - Self { - timer_type: TimerType::NONE, - timer_interval: TimeVal::new(), - timer_remained: 0, - start: 0, - expired: false, - } - } -} - -/// statistics of a process -#[derive(Debug, Clone)] -pub struct StatisticalData { - /// The number of times the process was scheduled in user mode. --ticks - pub tms_utime: usize, - /// The number of times the process was scheduled in kernel mode. --ticks - pub tms_stime: usize, - /// The last time the process was scheduled in user mode. --ticks - pub last_utime: usize, - /// The last time the process was scheduled in kernel mode. --ticks - pub last_stime: usize, - - pub tms_cutime: usize, - pub tms_cstime: usize, -} - -impl StatisticalData { - /// 用于创建一个新的 `StatisticalData` 结构 - pub fn new() -> Self { - let now = read_timer(); - StatisticalData { - tms_utime: 0, - tms_stime: 0, - last_utime: now, - last_stime: now, - tms_cutime: 0, - tms_cstime: 0, - } - } - /// 清除当前 `StatisticalData` 结构中储存的数据,并将 `last_utime` 和 `last_stime` 的值置为 当前的时间 - pub fn clear(&mut self) { - let now = read_timer(); - self.tms_utime = 0; - self.tms_stime = 0; - self.last_utime = now; - self.last_stime = now; - self.tms_cutime = 0; - self.tms_cstime = 0; - } -} - -#[derive(Clone)] -pub struct FsContext { - /// 当前工作目录 - pub cwd: Arc, - /// 根目录 - pub root: Arc, -} - -impl Debug for FsContext { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - let cwd = self.cwd.path(); - let root = self.root.path(); - f.debug_struct("FsContext") - .field("cwd", &cwd) - .field("root", &root) - .finish() - } -} - -impl FsContext { - /// 创建一个新的 `FsContext` 结构 - pub fn new(root: Arc, cwd: Arc) -> Self { - FsContext { cwd, root } - } -} - -#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)] -pub enum TaskState { - /// 就绪态 - Ready, - /// 运行态 - Running, - /// 等待一段时间 - Sleeping, - /// 等待一个事件 - Waiting, - /// 僵尸态,等待父进程回收资源 - Zombie, - /// 终止态 - Terminated, -} - -impl Task { - /// 终止进程,回收内核栈等资源,同时将该任务的状态修改为 `Terminated` - pub fn terminate(self: Arc) { - // recycle kernel stack - self.kernel_stack.release(); - if self.access_inner().thread_number != 0 { - let parent = self.inner.lock().parent.clone(); - if let Some(parent) = parent { - let parent = parent.upgrade(); - if let Some(parent) = parent { - parent.remove_child_by_tid(self.get_tid()); - assert_eq!(Arc::strong_count(&self), 1); - } - } - } else { - // if it is a thread, we should not remove it from parent's children - // if self.access_inner().children.len() == 0 { - // self.access_inner().address_space.lock().release(); - // } - } - self.access_inner().state = TaskState::Terminated; - } - - /// 获取进程的 pid 号 - #[inline] - pub fn get_pid(&self) -> isize { - self.pid as isize - } - - /// 获取进程的 tid 号 - #[inline] - pub fn get_tid(&self) -> isize { - self.tid.0 as isize - } - - /// 设置 `clear_child_tid` 字段的 值 - pub fn set_tid_address(&self, tidptr: usize) { - let mut inner = self.inner.lock(); - inner.clear_child_tid = tidptr; - } - - /// 获取文件的名称 - pub fn get_name(&self) -> String { - let inner = self.inner.lock(); - inner.name.clone() - } - - /// 尝试获取 TaskInner - pub fn access_inner(&self) -> MutexGuard { - self.inner.lock() - } - - /// 获取进程页表的root ppn - pub fn token(&self) -> usize { - let inner = self.inner.lock(); - let paddr = inner.address_space.lock().root_paddr(); - (8usize << 60) | (paddr.as_usize() >> 12) - } - - /// 获取 trap 帧的可变引用 - pub fn trap_frame(&self) -> &'static mut TrapFrame { - self.inner.lock().trap_frame() - } - - /// 获取 trap 帧的指针 - pub fn trap_frame_ptr(&self) -> *mut TrapFrame { - self.inner.lock().trap_frame_ptr() - } - - /// 将进程的状态修改为 state - pub fn update_state(&self, state: TaskState) { - let mut inner = self.inner.lock(); - inner.state = state; - } - - /// 返回进程的状态 - pub fn state(&self) -> TaskState { - let inner = self.inner.lock(); - inner.state - } - - /// 更新进程的返回码 - pub fn update_exit_code(&self, code: i32) { - let mut inner = self.inner.lock(); - inner.exit_code = code; - } - - /// 获取任务上下文的指针 - pub fn get_context_raw_ptr(&self) -> *const Context { - let inner = self.inner.lock(); - &inner.context as *const Context - } - - /// 获取任务上下文的可变指针 - pub fn get_context_mut_raw_ptr(&self) -> *mut Context { - let mut inner = self.inner.lock(); - &mut inner.context as *mut Context - } - - /// 获取该进程的子进程的控制块列表 - pub fn children(&self) -> Vec> { - let inner = self.inner.lock(); - inner.children.clone() - } - - /// 查找进程号为pid的子进程是否已经退出。当pid为-1时,任意子进程退出都将返回子进程的pid号。 - pub fn check_child(&self, pid: isize) -> Option { - let res = self - .inner - .lock() - .children - .iter() - .enumerate() - .find(|(_, child)| { - child.state() == TaskState::Terminated && (child.get_pid() == pid || pid == -1) - }) - .map(|(index, _)| index); - res - } - - /// 取走当前进程的子进程控制块列表的所有权 - pub fn take_children(&self) -> Vec> { - let children = self.children(); - self.access_inner().children = Vec::new(); - children - } - - /// 将任务号为 `tid` 的进程 从子进程列表中移除 - pub fn remove_child_by_tid(&self, tid: isize) -> Option> { - let mut inner = self.inner.lock(); - let index = inner - .children - .iter() - .position(|child| child.get_tid() == tid); - if let Some(index) = index { - Some(inner.children.remove(index)) - } else { - None - } - } - - /// 将子进程列表中第 `index` 个进程 从子进程列表中移除 - pub fn remove_child(&self, index: usize) -> Arc { - let mut inner = self.inner.lock(); - assert!(index < inner.children.len()); - inner.children.remove(index) - } - - /// 将进程的父进程更新为 `parent` - pub fn update_parent(&self, parent: Arc) { - let mut inner = self.inner.lock(); - inner.parent = Some(Arc::downgrade(&parent)); - } - - /// 向子进程列表中插入一个新的子进程 - pub fn insert_child(&self, child: Arc) { - let mut inner = self.inner.lock(); - inner.children.push(child); - } - - /// 获取进程当前的返回码 - pub fn exit_code(&self) -> i32 { - let inner = self.inner.lock(); - inner.exit_code - } - - /// 用于获取文件描述符id号为 fd 的 文件描述符 - pub fn get_file(&self, fd: usize) -> Option> { - let inner = self.inner.lock(); - let file = inner.fd_table.lock().get(fd); - return if file.is_err() { None } else { file.unwrap() }; - } - - /// 在进程的文件描述符表中加入 file 文件 - pub fn add_file(&self, file: Arc) -> Result { - self.access_inner() - .fd_table - .lock() - .insert(file) - .map_err(|x| x as isize) - } - - /// 指定文件描述符表中的一个id,在该处加入一个 file 文件 - pub fn add_file_with_fd(&self, file: Arc, fd: usize) -> Result<(), ()> { - let inner = self.access_inner(); - let mut fd_table = inner.fd_table.lock(); - fd_table.insert_with_index(fd, file).map_err(|_| {}) - } - - /// 指明文件描述符表中的一个id,删除并返回该处的 file 文件 - pub fn remove_file(&self, fd: usize) -> Result, ()> { - let inner = self.inner.lock(); - let file = inner.fd_table.lock().get(fd); - if file.is_err() { - return Err(()); - } - let file = file.unwrap(); - if file.is_none() { - return Err(()); - } - let file = file.unwrap(); - inner.fd_table.lock().remove(fd).map_err(|_| {})?; - Ok(file) - } - - /// 获取一个虚拟地址 `ptr` 的实际物理地址 - pub fn transfer_raw(&self, ptr: usize) -> usize { - self.access_inner().transfer_raw(ptr) - } - - /// 获取一个虚拟地址 `ptr` 对应的 T 类型数据 的 可变引用 - pub fn transfer_raw_ptr(&self, ptr: *mut T) -> &'static mut T { - self.access_inner().transfer_raw_ptr_mut(ptr) - } - - /// 通过用户地址空间中一个字符串的首指针 `ptr`,获取一个字符串。 - pub fn transfer_str(&self, ptr: *const u8) -> String { - // we need check the ptr and len before transfer indeed - let mut start = ptr as usize; - let end = start + 128; //todo! string len is unknown - let address_space = self.access_inner().address_space.clone(); - while start < end { - let (_phy, flag, _) = address_space - .lock() - .query(VirtAddr::from(start)) - .expect(format!("transfer_buffer: {:x} failed", start).as_str()); - if !flag.contains(MappingFlags::V) { - error!("transfer_str flag: {:?}, addr:{:#x}", flag, start); - let res = self - .access_inner() - .invalid_page_solver(align_down_4k(start)) - .unwrap(); - if res.is_some() { - let (file, buf, offset) = res.unwrap(); - if file.is_some() { - trap_common_read_file(file.unwrap(), buf, offset); - } - } - } - start += FRAME_SIZE; - } - self.access_inner().transfer_str(ptr) - } - - /// 通过用户地址空间中一个缓冲区的指针 `ptr` 和 缓冲区的长度 `len`,得到一组对用户地址空间中缓冲区的可变引用,每一组引用的长度为 4K - pub fn transfer_buffer(&self, ptr: *const T, len: usize) -> Vec<&'static mut [T]> { - // we need check the ptr and len before transfer indeed - let mut start = ptr as usize; - let end = start + len; - let address_space = self.access_inner().address_space.clone(); - start = align_down_4k(start); - while start < end { - let (_phy, flag, _) = address_space - .lock() - .query(VirtAddr::from(start)) - .expect(format!("transfer_buffer: {:x} failed", start).as_str()); - if !flag.contains(MappingFlags::V) { - error!("transfer_buffer flag: {:?}, addr:{:#x}", flag, start); - let res = self - .access_inner() - .invalid_page_solver(align_down_4k(start)) - .unwrap(); - if res.is_some() { - let (file, buf, offset) = res.unwrap(); - if file.is_some() { - trap_common_read_file(file.unwrap(), buf, offset); - } - } - } - start += FRAME_SIZE; - } - self.access_inner().transfer_buffer(ptr, len) - } -} - -impl TaskInner { - /// 获取进程的文件系统信息 - pub fn cwd(&self) -> FsContext { - self.fs_info.clone() - } - - /// 获取进程的计时器 - pub fn get_timer(&self) -> TaskTimer { - self.timer.clone() - } - - /// 获取当前进程对于资源的限制 - pub fn get_prlimit(&self, resource: PrLimitRes) -> PrLimit { - match resource { - PrLimitRes::RlimitStack => PrLimit::new(USER_STACK_SIZE as u64, USER_STACK_SIZE as u64), - PrLimitRes::RlimitNofile => { - let max_fd = self.fd_table.lock().max(); - PrLimit::new(max_fd as u64, max_fd as u64) - } - PrLimitRes::RlimitAs => PrLimit::new(u64::MAX, u64::MAX), - } - } - - /// 设置当前进程对于资源的限制 - pub fn set_prlimit(&mut self, resource: PrLimitRes, value: PrLimit) { - match resource { - PrLimitRes::RlimitStack => {} - PrLimitRes::RlimitNofile => { - let new_max_fd = value.rlim_cur; - self.fd_table.lock().set_max(new_max_fd as usize); - } - PrLimitRes::RlimitAs => {} - } - } - - /// 返回 trap 上下文的一个可变指针 - pub fn trap_frame_ptr(&self) -> *mut TrapFrame { - let trap_context_base = if self.thread_number != 0 { - let base = TRAP_CONTEXT_BASE - self.thread_number * FRAME_SIZE; - base - } else { - TRAP_CONTEXT_BASE - }; - trap_context_base as *mut TrapFrame - } - - /// 返回 trap 上下文的一个可变引用 - pub fn trap_frame(&self) -> &'static mut TrapFrame { - let trap_context_base = if self.thread_number != 0 { - let base = TRAP_CONTEXT_BASE - self.thread_number * FRAME_SIZE; - base - } else { - TRAP_CONTEXT_BASE - }; - let (physical, _, _) = self - .address_space - .lock() - .query(VirtAddr::from(trap_context_base)) - .unwrap(); - TrapFrame::from_raw_ptr(physical.as_usize() as *mut TrapFrame) - } - - /// 在信号处理需要执行用户态信号处理函数时,保存原 trap 上下文。 - pub fn save_trap_frame(&mut self) -> bool { - let trap_frame = self.trap_frame(); - if self.trap_cx_before_signal.is_some() { - return false; - } - self.trap_cx_before_signal = Some(*trap_frame); - self.signal_set_siginfo = false; - true - } - - /// 待用户态信号处理函数执行完毕后,需要重新加载原 trap 上下文。 - pub fn load_trap_frame(&mut self) -> isize { - if let Some(old_trap_frame) = self.trap_cx_before_signal.take() { - let trap_frame = self.trap_frame(); - // 这里假定是 sigreturn 触发的,即用户的信号处理函数 return 了(cancel_handler) - // 也就是说信号触发时的 sp 就是现在的 sp - let sp = trap_frame.regs()[2]; - // 获取可能被修改的 pc - let phy_sp = self.transfer_raw(sp); - - let pc = unsafe { (*(phy_sp as *const SignalUserContext)).get_pc() }; - *trap_frame = old_trap_frame; - if self.signal_set_siginfo { - // 更新用户修改的 pc - trap_frame.set_sepc(pc); - warn!("sig return sp = {:x} pc = {:x}", sp, pc); - } - trap_frame.regs()[10] as isize // old arg0 - } else { - -1 - } - } - - /// 获取一个虚拟地址 `ptr` 的实际物理地址 - pub fn transfer_raw(&mut self, ptr: usize) -> usize { - let (phy, flag, _) = self - .address_space - .lock() - .query(VirtAddr::from(ptr)) - .unwrap(); - if !flag.contains(MappingFlags::V) { - error!("[transfer_raw] invalid page {:?}, ptr:{:#x}", flag, ptr); - self.invalid_page_solver(ptr).unwrap(); - let (phy, flag, _) = self - .address_space - .lock() - .query(VirtAddr::from(ptr)) - .unwrap(); - assert!(flag.contains(MappingFlags::V)); - return phy.as_usize(); - } - phy.as_usize() - } - - /// 获取 虚拟地址空间中的以 `ptr` 为起始地址,以 '\0' 结尾的字符串 - pub fn transfer_str(&self, ptr: *const u8) -> String { - let mut res = String::new(); - let physical = self - .address_space - .lock() - .query(VirtAddr::from(ptr as usize)); - if physical.is_err() { - return res; - } - let (physical, _, _) = physical.unwrap(); - let mut physical = physical.as_usize(); - loop { - let c = unsafe { &*(physical as *const u8) }; - if *c == 0 { - break; - } - res.push(*c as char); - physical += 1; - } - res - } - - /// 从物理地址的 `src` 处取一个长度为 `len` 类型为 T 的缓冲区 赋到 用户虚拟地址空间下的 `dst` 处 - pub fn copy_to_user_buffer( - &mut self, - src: *const T, - dst: *mut T, - len: usize, - ) { - let size = core::mem::size_of::() * len; - if VirtAddr::from(dst as usize).align_down_4k() - == VirtAddr::from(dst as usize + size - 1).align_down_4k() - { - // the src and dst are in same page - let dst = self.transfer_raw(dst as usize); - unsafe { - core::ptr::copy_nonoverlapping(src as *const u8, dst as *mut u8, size); - } - } else { - let bufs = self.transfer_buffer(dst as *const u8, size); - let src = unsafe { core::slice::from_raw_parts(src as *const u8, size) }; - let mut start = 0; - let src_len = src.len(); - for buffer in bufs { - let len = if start + buffer.len() > src_len { - src_len - start - } else { - buffer.len() - }; - unsafe { - core::ptr::copy_nonoverlapping( - src.as_ptr().add(start), - buffer.as_mut_ptr(), - len, - ); - } - start += len; - } - } - } - - /// 从用户虚拟地址空间的 `src` 处取一个长度为 `len` 类型为 T 的缓冲区 赋到 物理地址下的 `dst` 处 - pub fn copy_from_user_buffer( - &mut self, - src: *const T, - dst: *mut T, - len: usize, - ) { - let size = core::mem::size_of::() * len; - if VirtAddr::from(src as usize).align_down_4k() - == VirtAddr::from(src as usize + size - 1).align_down_4k() - { - // the src and dst are in same page - let src = self.transfer_raw(src as usize); - unsafe { - core::ptr::copy_nonoverlapping(src as *const u8, dst as *mut u8, size); - } - } else { - let mut bufs = self.transfer_buffer(src as *const u8, size); - let dst = unsafe { core::slice::from_raw_parts_mut(dst as *mut u8, size) }; - let mut start = 0; - let dst_len = dst.len(); - for buffer in bufs.iter_mut() { - let len = if start + buffer.len() > dst_len { - dst_len - start - } else { - buffer.len() - }; - unsafe { - core::ptr::copy_nonoverlapping( - buffer.as_ptr(), - dst.as_mut_ptr().add(start), - len, - ); - } - start += len; - } - } - } - - /// 从物理空间下的 `src` 处取一个 T 类型的数据 赋给 虚拟地址空间下的 `dst` 处 - pub fn copy_to_user(&mut self, src: *const T, dst: *mut T) { - // self.copy_to_user_buffer(src, dst, 1); - let size = core::mem::size_of::(); - if VirtAddr::from(dst as usize).align_down_4k() - == VirtAddr::from(dst as usize + size - 1).align_down_4k() - { - // the src and dst are in same page - let dst = self.transfer_raw(dst as usize); - unsafe { - core::ptr::copy_nonoverlapping(src as *const u8, dst as *mut u8, size); - } - } else { - let bufs = self.transfer_buffer(dst as *const u8, size); - let src = unsafe { core::slice::from_raw_parts(src as *const u8, size) }; - let mut start = 0; - let src_len = src.len(); - for buffer in bufs { - let len = if start + buffer.len() > src_len { - src_len - start - } else { - buffer.len() - }; - unsafe { - core::ptr::copy_nonoverlapping( - src.as_ptr().add(start), - buffer.as_mut_ptr(), - len, - ); - } - start += len; - } - } - } - - /// 从用户虚拟地址空间的 `src` 处取一个 T 类型的数据 赋给 物理地址下的 `dst` 处 - pub fn copy_from_user(&mut self, src: *const T, dst: *mut T) { - // self.copy_from_user_buffer(src, dst, 1); - let size = core::mem::size_of::(); - if VirtAddr::from(src as usize).align_down_4k() - == VirtAddr::from(src as usize + size - 1).align_down_4k() - { - // the src and dst are in same page - let src = self.transfer_raw(src as usize); - unsafe { - core::ptr::copy_nonoverlapping(src as *const u8, dst as *mut u8, size); - } - } else { - let mut bufs = self.transfer_buffer(src as *const u8, size); - let dst = unsafe { core::slice::from_raw_parts_mut(dst as *mut u8, size) }; - let mut start = 0; - let dst_len = dst.len(); - for buffer in bufs.iter_mut() { - let len = if start + buffer.len() > dst_len { - dst_len - start - } else { - buffer.len() - }; - unsafe { - core::ptr::copy_nonoverlapping( - buffer.as_ptr(), - dst.as_mut_ptr().add(start), - len, - ); - } - start += len; - } - } - } - - /// 将在进程的虚拟空间中的一段缓冲区的首地址 `ptr` 和 长度 `len` 转换为 实地址下的一组页 - pub fn transfer_buffer( - &mut self, - ptr: *const T, - len: usize, - ) -> Vec<&'static mut [T]> { - let mut start = ptr as usize; - let end = start + len; - let mut v = Vec::new(); - while start < end { - let (start_phy, flag, _) = self - .address_space - .lock() - .query(VirtAddr::from(start)) - .expect(format!("transfer_buffer: {:x} failed", start).as_str()); - if !flag.contains(MappingFlags::V) { - panic!("transfer_buffer: {:x} not mapped", start); - } - // start_phy向上取整到FRAME_SIZE - let bound = (start & !(FRAME_SIZE - 1)) + FRAME_SIZE; - let len = if bound > end { - end - start - } else { - bound - start - }; - unsafe { - let buf = core::slice::from_raw_parts_mut(start_phy.as_usize() as *mut T, len); - v.push(buf); - } - start = bound; - } - v - } - - /// 将一个在进程的虚拟空间中的虚地址 转换为一个实地址的可变引用 - pub fn transfer_raw_ptr_mut(&self, ptr: *mut T) -> &'static mut T { - let (physical, flag, _) = self - .address_space - .lock() - .query(VirtAddr::from(ptr as usize)) - .unwrap(); - assert!(flag.contains(MappingFlags::V)); - unsafe { &mut *(physical.as_usize() as *mut T) } - } - - /// 将一个在进程的虚拟空间中的虚地址 转换为一个实地址的不可变引用 - pub fn transfer_raw_ptr(&self, ptr: *const T) -> &'static T { - let (physical, flag, _) = self - .address_space - .lock() - .query(VirtAddr::from(ptr as usize)) - .unwrap(); - assert!(flag.contains(MappingFlags::V)); - unsafe { &*(physical.as_usize() as *const T) } - } - - /// 当进程回到用户态时,需要更新进程在内核态下的运行时间 - /// WARNING: If the cause of the process returning to the kernel is a timer interrupt, - /// We should not call this function. - pub fn update_kernel_mode_time(&mut self) { - let now = read_timer(); // current cpu clocks - let time = now - self.statistical_data.last_stime; - self.update_timer(); - self.statistical_data.tms_stime += time; - self.statistical_data.last_utime = now; - } - - /// 当进程进入内核态时,需要更新进程在用户态下的运行时间 - pub fn update_user_mode_time(&mut self) { - let now = read_timer(); // current cpu clocks - let time = now - self.statistical_data.last_utime; - self.update_timer(); - self.statistical_data.tms_utime += time; - self.statistical_data.last_stime = now; - } - - /// 设置计时器 - pub fn set_timer(&mut self, itimer: ITimerVal, timer_type: TimerType) { - self.timer.timer_remained = itimer.it_value.to_clock(); - self.timer.timer_interval = itimer.it_interval; - self.timer.timer_type = timer_type; - self.timer.start = TimeVal::now().to_clock(); - } - - /// 更新计时器 - /// - /// 如果没有计时器则直接返回;如果有计时器但时辰未到也直接返回; - /// 如果有计时器且计时器到时间了,根据是否为one-shot计时器,确定重置计时器或者置`timer`的`timer_remained`为0。 - pub fn update_timer(&mut self) { - let now = read_timer(); - let delta = now - self.timer.start; - if self.timer.timer_remained == 0 { - // 等于0说明没有计时器,或者 one-shot 计时器已结束 - return; - } - if self.timer.timer_remained > delta { - // 时辰未到 - return; - } - // 到此说明计时器已经到时间了,更新计时器 - // 如果是 one-shot 计时器,则 timer_interval_us == 0,这样赋值也恰好是符合语义的 - self.timer.timer_remained = if self.timer.timer_interval == TimeVal::new() { - 0 - } else { - self.timer.start = now; - self.timer.timer_interval.to_clock() - }; - self.timer.expired = true; - } - - /// 在调用 `update_user_mode_time` 和 `update_kernel_mode_time` 后,我们需要检查一下计时器是否已经超时 - pub fn check_timer_expired(&mut self) -> Option { - if self.timer.expired { - self.timer.expired = false; - Some(self.timer.timer_type) - } else { - None - } - } - - /// 返回进程的统计信息 - pub fn statistical_data(&self) -> &StatisticalData { - &self.statistical_data - } - - /// 返回堆信息 - pub fn heap_info(&self) -> HeapInfo { - self.heap.lock().clone() - } - - #[allow(unused)] - /// (待实现)缩减堆空间 - pub fn shrink_heap(_addr: usize) -> Result { - todo!() - } - - /// 拓展堆空间 - pub fn extend_heap(&mut self, addr: usize) -> Result { - let mut heap = self.heap.lock(); - heap.current = addr; - if addr < heap.end { - return Ok(heap.current); - } - let addition = addr - heap.end; - // increase heap size - let end = heap.end; - // align addition to PAGE_SIZE - let addition = (addition + FRAME_SIZE - 1) & !(FRAME_SIZE - 1); - trace!("extend heap: {:#x} -- {:#x}", end, addition); - self.address_space - .lock() - .map_region_no_target( - VirtAddr::from(end), - addition, - "RWUAD".into(), // no V flag - false, - true, - ) - .unwrap(); - let new_end = end + addition; - heap.end = new_end; - Ok(heap.current) - } - - /// 在虚拟空间中创建内存映射。 - /// + `start`: 所要创建的映射区的起始地址。当该值为0时,内核将自动为其分配一段内存空间创建内存映射。该值在函数运行过程中将被调整为与4K对齐。 - /// + `len`: 指明所要创建的映射区的长度。该值在函数运行过程中将被调整为与4K对齐。 - /// + `prot`: 指明创建内存映射区的初始保护位。具体可见[`ProtFlags`]。 - /// + `flags`: 指明mmap操作的相关设置。具体可见[`MapFlags`]。 - /// + `fd`: 指明要创建内存映射的文件的文件描述符。 - /// + `offset`: 将从文件中偏移量为`offset`处开始映射。该值需要和4K对齐。 - /// - /// 函数成功执行后将返回所创建的内存映射区的首地址;否则返回错误类型。 - pub fn add_mmap( - &mut self, - start: usize, - len: usize, - prot: ProtFlags, - flags: MapFlags, - fd: usize, - offset: usize, - ) -> AlienResult { - // start == 0 表明需要OS为其找一段内存,而 MAP_FIXED 表明必须 mmap 在固定位置。两者是冲突的 - if start == 0 && flags.contains(MapFlags::MAP_FIXED) { - return Err(LinuxErrno::EINVAL); - } - - // if the map in heap, now we ignore it - if self.heap.lock().contains(start) && self.heap.lock().contains(start + len) { - return Ok(start); - } - - // not map to file - let fd = if flags.contains(MapFlags::MAP_ANONYMOUS) { - None - } else { - let file = self - .fd_table - .lock() - .get(fd) - .map_err(|_| LinuxErrno::EBADF)? - .ok_or(LinuxErrno::EBADF)?; // EBADF - Some(file) - }; - // todo! - // for dynamic link, the linker will map the elf file to the same address - // we must satisfy this requirement - let mut start = align_down_4k(start); - let v_range = if prot.contains(ProtFlags::PROT_EXEC) { - let len = align_up_4k(len); - if start > self.heap.lock().start { - // the mmap region is in heap - return Err(LinuxErrno::EINVAL); - } - if let Some(_region) = self.mmap.get_region(start) { - return Err(LinuxErrno::EINVAL); - } - if start == 0 { - start = 0x1000; - } - start..start + len - } else if flags.contains(MapFlags::MAP_FIXED) { - let len = align_up_4k(len); - if start > self.heap.lock().start { - error!("mmap fixed address conflict with heap"); - return Err(LinuxErrno::EINVAL); - } - // check if the region is already mapped - if let Some(region) = self.mmap.get_region(start) { - // split the region - let (left, mut right) = region.split(start); - // delete the old region - self.mmap.remove_region(region.start); - // add the left region - self.mmap.add_region(left); - if start + len < right.start + right.map_len { - // slice the right region - trace!( - "again slice the right region:{:#x?}, len:{:#x}", - right.start, - right.len - ); - let (mut left, right) = right.split(start + len); - // add the right region - self.mmap.add_region(right); - // update prot and flags - left.set_prot(prot); - left.set_flags(flags); - left.offset = offset; - left.fd = fd; - self.mmap.add_region(left); - } else { - trace!( - "directly add the right region:{:#x?}, len:{:#x}", - right.start, - right.len - ); - // update prot and flags - right.set_prot(prot); - right.set_flags(flags); - right.offset = offset; - right.fd = fd; - self.mmap.add_region(right); - } - return Ok(start); - } - start..start + len - } else { - let v_range = self.mmap.alloc(len); - v_range - }; - - let region = MMapRegion::new( - v_range.start, - len, - v_range.end - v_range.start, - prot, - flags, - fd, - offset, - ); - // warn!("add mmap region:{:#x?}",region); - self.mmap.add_region(region); - let start = v_range.start; - let mut map_flags:MappingFlags = prot.into(); // no V flag - map_flags |= "AD".into(); - self.address_space - .lock() - .map_region_no_target( - VirtAddr::from(start), - v_range.end - start, - map_flags, - false, - true, - ) - .unwrap(); - Ok(start) - } - - /// 用于在进程的虚拟内存空间中消除一段内存映射。传入的`start`需要是某段内存映射的首地址,`len`需要是该段内存映射的长度。 - pub fn unmap(&mut self, start: usize, len: usize) -> Result<(), isize> { - // check whether the start is in mmap - let x = self.mmap.get_region(start); - if x.is_none() { - return Err(LinuxErrno::EINVAL.into()); - } - // now we need make sure the start is equal to the start of the region, and the len is equal to the len of the region - let region = x.unwrap(); - if region.start != start || len != region.len { - return Err(LinuxErrno::EINVAL.into()); - } - self.address_space - .lock() - .unmap_region(VirtAddr::from(start), region.map_len) - .unwrap(); - self.mmap.remove_region(start); - Ok(()) - } - - /// 设置内存映射的保护位,函数会检查传入的`start`和`len`所指示的内存映射区是否已经处于被映射状态,如果是,则将对应内存映射区的保护位与`prot`做或运算。 - pub fn map_protect(&mut self, start: usize, len: usize, prot: ProtFlags) -> AlienResult<()> { - // check whether the start is in mmap - let x = self.mmap.get_region_mut(start); - if x.is_none() { - let res = self.address_space.lock().query(VirtAddr::from(start)); - return if res.is_err() { - Err(LinuxErrno::EINVAL) - } else { - Ok(()) - }; - } - // now we need make sure the start is equal to the start of the region, and the len is equal to the len of the region - let region = x.unwrap(); - if start + len > region.start + region.len { - error!("start+len > region.start + region.len"); - return Err(LinuxErrno::EINVAL); - } - region.prot |= prot; - Ok(()) - } - - /// 用于处理装入页异常 - pub fn do_load_page_fault( - &mut self, - addr: usize, - ) -> AlienResult>, &'static mut [u8], u64)>> { - // check whether the addr is in mmap - let addr = align_down_4k(addr); - let (_phy, flags, page_size) = self - .address_space - .lock() - .query(VirtAddr::from(addr)) - .expect(format!("addr:{:#x}", addr).as_str()); - trace!( - "do load page fault:{:#x}, flags:{:?}, page_size:{:?}", - addr, - flags, - page_size - ); - if !flags.contains(MappingFlags::V) { - return self.invalid_page_solver(addr); - } - assert!(!flags.contains(MappingFlags::RSD)); - - let region = self.mmap.get_region(addr).ok_or(AlienError::EINVAL)?; - // now we need make sure the start is equal to the start of the region, and the len is equal to the len of the region - // update page table - let mut map_flags:MappingFlags = region.prot.into(); - map_flags |= "V".into(); - - let mut address_space = self.address_space.lock(); - - let (_, flags, _) = address_space.query(VirtAddr::from(addr)).unwrap(); - assert!(!flags.contains(MappingFlags::V)); - address_space - .validate(VirtAddr::from(addr), map_flags) - .unwrap(); - let (phy, _, size) = address_space.query(VirtAddr::from(addr)).unwrap(); - let buf = - unsafe { core::slice::from_raw_parts_mut(phy.as_usize() as *mut u8, size.into()) }; - let file = ®ion.fd; - - let read_offset = region.offset + (addr - region.start); - Ok(Some((file.clone(), buf, read_offset as u64))) - } - - /// 用于处理无效页错误 - fn invalid_page_solver( - &mut self, - addr: usize, - ) -> AlienResult>, &'static mut [u8], u64)>> { - trace!("invalid page fault at {:#x}", addr); - let is_mmap = self.mmap.get_region(addr); - let is_heap = self.heap.lock().contains(addr); - - let is_stack = self.stack.contains(&addr); - - if is_mmap.is_none() && !is_heap && !is_stack { - warn!("invalid page fault at {:#x}", addr); - return Err(AlienError::EINVAL); - } - if is_heap { - trace!("invalid page fault in heap"); - let map_flags = "RWUVAD".into(); - self.address_space - .lock() - .validate(VirtAddr::from(addr), map_flags) - .unwrap(); - } else if is_mmap.is_some() { - let region = is_mmap.unwrap(); - // assert_eq!(addr % FRAME_SIZE, 0); - // update page table - let mut map_flags:MappingFlags = region.prot.into(); - map_flags |= "VAD".into(); - warn!( - "invalid page fault at {:#x}, flag is :{:?}", - addr, map_flags - ); - self.address_space - .lock() - .validate(VirtAddr::from(addr).align_down_4k(), map_flags) - .unwrap(); - let (phy, flag, size) = self - .address_space - .lock() - .query(VirtAddr::from(addr)) - .unwrap(); - assert!(flag.contains(MappingFlags::V)); - let buf = - unsafe { core::slice::from_raw_parts_mut(phy.as_usize() as *mut u8, size.into()) }; - let file = ®ion.fd; - let read_offset = region.offset + (addr - region.start); - return Ok(Some((file.clone(), buf, read_offset as u64))); - } else { - warn!("invalid page fault in stack, addr: {:#x}", addr); - let map_flags = "RWUVAD".into(); - self.address_space - .lock() - .validate(VirtAddr::from(addr), map_flags) - .unwrap(); - } - Ok(None) - } - - /// 用于处理指令页异常 - pub fn do_instruction_page_fault( - &mut self, - addr: usize, - ) -> AlienResult>, &'static mut [u8], u64)>> { - let addr = align_down_4k(addr); - let (_phy, flags, page_size) = self - .address_space - .lock() - .query(VirtAddr::from(addr)) - .map_err(|_| AlienError::EINVAL)?; - // - trace!( - "do store page fault:{:#x}, flags:{:?}, page_size:{:?}", - addr, - flags, - page_size - ); - if !flags.contains(MappingFlags::V) { - return self.invalid_page_solver(addr); - } - panic!("instruction page fault"); - } - - /// 用于处理数据页异常 - pub fn do_store_page_fault( - &mut self, - o_addr: usize, - ) -> AlienResult>, &'static mut [u8], u64)>> { - let addr = align_down_4k(o_addr); - let (phy, flags, page_size) = self - .address_space - .lock() - .query(VirtAddr::from(addr)) - .map_err(|_x| { - if self.need_wait < 5 { - self.need_wait += 1; - AlienError::EAGAIN - } else { - error!("do_store_page_fault panic :{:#x}", o_addr); - AlienError::ETMP - } - })?; - // .expect(format!("addr:{:#x}", addr).as_str()); - trace!( - "do store page fault:{:#x}, flags:{:?}, page_size:{:?}", - addr, - flags, - page_size - ); - if !flags.contains(MappingFlags::V) { - return self.invalid_page_solver(addr); - } - // if !flags.contains(MappingFlags::RSD) { - // return Ok(None); - // } - assert!( - flags.contains(MappingFlags::RSD), - "addr:{:#x} flags:{:?}", - o_addr, - flags - ); - // decrease the reference count - let mut flags = flags | "W".into(); - flags -= MappingFlags::RSD; - let new_phy = self - .address_space - .lock() - .modify_pte_flags(VirtAddr::from(addr), flags, true) - .unwrap(); - assert!(new_phy.is_some()); - // copy data - let src_ptr = phy.as_usize() as *const u8; - let dst_ptr = new_phy.unwrap().as_usize() as *mut u8; - unsafe { - core::ptr::copy(src_ptr, dst_ptr, usize::from(page_size)); - } - let mut frame_ref_manager = FRAME_REF_MANAGER.lock(); - for i in 0..usize::from(page_size) / FRAME_SIZE { - let t_phy = phy + i * FRAME_SIZE; - frame_ref_manager.dec_ref(t_phy.as_usize() >> FRAME_BITS); - } - Ok(None) - } -} - -impl Task { - /// 对进程的资源进行预回收,将会回收 trap 帧、子进程控制块列表、文件描述符表等资源。 - pub fn pre_recycle(&self) { - // recycle trap page - let trap_frame_ptr = self.trap_frame_ptr() as usize; - self.access_inner() - .address_space - .lock() - .unmap_region(VirtAddr::from(trap_frame_ptr), FRAME_SIZE) - .unwrap(); - let mut inner = self.inner.lock(); - // delete child process - inner.children.clear(); - let thread_number = inner.thread_number; - if thread_number == 0 { - let _ = inner.fd_table.lock().clear(); - drop(inner); - } - } - - /// 获取进程的 `clear_child_tid` 字段 - pub fn futex_wake(&self) -> usize { - self.access_inner().clear_child_tid - } - - /// 从 elf 文件中创建一个新的进程控制块,只会调用一次(即读取 init 进程的相关信息) - pub fn from_elf(name: &str, elf: &[u8]) -> Option { - let tid = TidHandle::new()?; - let pid = tid.0; - // 创建进程地址空间 - let mut args = vec![]; - let elf_info = build_elf_address_space(elf, &mut args, "/bin/init"); - if elf_info.is_err() { - return None; - } - let elf_info = elf_info.unwrap(); - let address_space = elf_info.address_space; - let k_stack = Stack::new(USER_KERNEL_STACK_SIZE / FRAME_SIZE)?; - let k_stack_top = k_stack.top(); - let stack_info = elf_info.stack_top - USER_STACK_SIZE..elf_info.stack_top; - let cwd = SYSTEM_ROOT_FS.get().unwrap().clone(); - - let process = Task { - tid, - kernel_stack: k_stack, - pid, - inner: Mutex::new(TaskInner { - name: name.to_string(), - threads: MinimalManager::new(MAX_THREAD_NUM), - thread_number: 0, - address_space: Arc::new(Mutex::new(address_space)), - state: TaskState::Ready, - parent: None, - children: Vec::new(), - fd_table: { - let mut fd_table = FdManager::new(MAX_FD_NUM); - fd_table.insert(STDIN.clone()).unwrap(); - fd_table.insert(STDOUT.clone()).unwrap(); - fd_table.insert(STDOUT.clone()).unwrap(); - Arc::new(Mutex::new(fd_table)) - }, - context: Context::new(trap_return as usize, k_stack_top), - fs_info: FsContext::new(cwd.clone(), cwd), - statistical_data: StatisticalData::new(), - timer: TaskTimer::default(), - exit_code: 0, - heap: Arc::new(Mutex::new(HeapInfo::new( - elf_info.heap_bottom, - elf_info.heap_bottom, - ))), - mmap: MMapInfo::new(), - signal_handlers: Arc::new(Mutex::new(SignalHandlers::new())), - signal_receivers: Arc::new(Mutex::new(SignalReceivers::new())), - set_child_tid: 0, - clear_child_tid: 0, - trap_cx_before_signal: None, - signal_set_siginfo: false, - robust: RobustList::default(), - shm: BTreeMap::new(), - cpu_affinity: { - let mut affinity = 0; - affinity.set_bits(0..CPU_NUM, 1 << CPU_NUM - 1); - affinity - }, - unmask: 0o022, - stack: stack_info, - need_wait: 0, - }), - send_sigchld_when_exit: false, - }; - let phy_button = process.transfer_raw(elf_info.stack_top - FRAME_SIZE); - let mut user_stack = UserStack::new(phy_button + FRAME_SIZE, elf_info.stack_top); - user_stack.push(0).unwrap(); - let argc_ptr = user_stack.push(0).unwrap(); - - let trap_frame = process.trap_frame(); - *trap_frame = TrapFrame::init_for_task( - elf_info.entry, - argc_ptr, - kernel_satp(), - process.kernel_stack.top(), - user_trap_vector as usize, - ); - trap_frame.regs()[4] = elf_info.tls; // tp --> tls - let res = Some(process); - res - } - - /// 产生一个新的子进程。 - /// - /// `flag`用于控制父子进程之间资源的共享程度,有关flag值及其相关含义设置可见[`CloneFlags`]。 - /// `stack`用于控制子进程的用户栈。由于clone产生的子进程有可能和父进程共享内存,所以它不能使用父进程的栈。 - /// `sig`用于控制子进程退出时传递给父进程的相关信号。目前Alien中的设计为当其值为`SIGCHLD`时,在子进程退出时会向父程序发送`SIGCHLD`信号。会其它有关值的设置可见[`SignalNumber`]。 - /// `ptid`是一个在父进程地址空间中的地址,用于在创建子进程成功后向该位置写入子进程的tid号。在flag包含`CLONE_PARENT_SETTID`时才会发挥效果。 - /// `tls`用于为子进程创建新的TLS(thread-local storage)值,在flag包含`CLONE_SETTLS`时才会实际产生效果。 - /// `ctid`用于给子进程中的[`set_child_tid`]和[`clear_child_tid`]赋值(分别在flag中包含`CLONE_CHILD_SETTID`和`CLONE_CHILD_CLEARTID`时产生效果)。 - /// - /// 成功创建子进程后父进程会返回子进程的TCB。 - /// - /// Note: 当传入的ptid未在父进程地址空间中被分配时,会引发panic。 - pub fn t_clone( - self: &Arc, - flag: CloneFlags, - stack: usize, - sig: SignalNumber, - ptid: usize, - tls: usize, - ctid: usize, - ) -> Option> { - warn!( - "clone: flag:{:?}, sig:{:?}, stack:{:#x}, ptid:{:#x}, tls:{:#x}, ctid:{:#x}", - flag, sig, stack, ptid, tls, ctid - ); - let tid = TidHandle::new()?; - let mut inner = self.inner.lock(); - let address_space = if flag.contains(CloneFlags::CLONE_VM) { - // to create thread - inner.address_space.clone() - } else { - // to create process - let address_space = - build_cow_address_space(&mut inner.address_space.lock(), inner.shm.clone()); - Arc::new(Mutex::new(address_space)) - }; - - let fd_table = if flag.contains(CloneFlags::CLONE_FILES) { - inner.fd_table.clone() - } else { - Arc::new(Mutex::new(inner.fd_table.lock().clone())) - }; - - let signal_handlers = if flag.contains(CloneFlags::CLONE_SIGHAND) { - inner.signal_handlers.clone() - } else { - Arc::new(Mutex::new(inner.signal_handlers.lock().clone())) - }; - - let parent = if flag.contains(CloneFlags::CLONE_PARENT) { - inner.parent.clone() - } else { - Some(Arc::downgrade(self)) - }; - - let k_stack = Stack::new(USER_KERNEL_STACK_SIZE / FRAME_SIZE)?; - let k_stack_top = k_stack.top(); - let pid = if flag.contains(CloneFlags::CLONE_THREAD) { - self.pid - } else { - tid.0 - }; - let signal_receivers = Arc::new(Mutex::new(SignalReceivers::new())); - // 注册线程-信号对应关系 - global_register_signals(tid.0, signal_receivers.clone()); - // map the thread trap_context if clone_vm - let (trap_context, thread_num) = if flag.contains(CloneFlags::CLONE_VM) { - let thread_num = inner.threads.insert(()).unwrap() + 1; - warn!("thread_num: {}", thread_num); - // calculate the address for thread context - let trap_context = build_thread_address_space(&mut address_space.lock(), thread_num); - (trap_context, thread_num) - } else { - let (physical, _, _) = address_space - .lock() - .query(VirtAddr::from(TRAP_CONTEXT_BASE)) - .unwrap(); - let trap_frame = TrapFrame::from_raw_ptr(physical.as_usize() as *mut TrapFrame); - (trap_frame, 0) - }; - - let heap = if flag.contains(CloneFlags::CLONE_VM) { - inner.heap.clone() - } else { - Arc::new(Mutex::new(inner.heap.lock().clone())) - }; - - // 设置内核栈地址 - trap_context.update_kernel_sp(k_stack_top); - - // 检查是否需要设置 tls - if flag.contains(CloneFlags::CLONE_SETTLS) { - trap_context.update_tp(tls); - } - - // 检查是否在父任务地址中写入 tid - if flag.contains(CloneFlags::CLONE_PARENT_SETTID) { - // 有可能这个地址是 lazy alloc 的,需要先检查 - let res = inner.address_space.lock().query(VirtAddr::from(ptid)); - if res.is_ok() { - let (physical, _, _) = res.unwrap(); - unsafe { - *(physical.as_usize() as *mut i32) = tid.0 as i32; - } - } else { - panic!("clone: ptid is not mapped") - } - } - - let ctid_value = if flag.contains(CloneFlags::CLONE_CHILD_SETTID) - || flag.contains(CloneFlags::CLONE_CHILD_CLEARTID) - { - tid.0 - } else { - 0 - }; - - if flag.contains(CloneFlags::CLONE_CHILD_SETTID) - || flag.contains(CloneFlags::CLONE_CHILD_CLEARTID) - { - // TODO!(may be not map when cow fork) - let (phy, ..) = address_space.lock().query(VirtAddr::from(ctid)).unwrap(); - unsafe { - *(phy.as_usize() as *mut i32) = ctid_value as i32; - } - } - if stack != 0 { - assert!(flag.contains(CloneFlags::CLONE_VM)); - // set the sp of the new process - trap_context.regs()[2] = stack; - } - - warn!("create task pid:{}, tid:{}", pid, tid.0); - let task = Task { - tid, - kernel_stack: k_stack, - pid, - inner: Mutex::new(TaskInner { - name: inner.name.clone(), - threads: MinimalManager::new(MAX_THREAD_NUM), - thread_number: thread_num, - address_space, - state: TaskState::Ready, - parent, - children: Vec::new(), - fd_table, - context: Context::new(trap_return as usize, k_stack_top), - fs_info: inner.fs_info.clone(), - statistical_data: StatisticalData::new(), - timer: TaskTimer::default(), - exit_code: 0, - heap, - mmap: inner.mmap.clone(), - signal_handlers, - signal_receivers, - set_child_tid: if flag.contains(CloneFlags::CLONE_CHILD_SETTID) { - ctid - } else { - 0 - }, - clear_child_tid: if flag.contains(CloneFlags::CLONE_CHILD_CLEARTID) { - ctid - } else { - 0 - }, - trap_cx_before_signal: None, - signal_set_siginfo: false, - robust: RobustList::default(), - shm: inner.shm.clone(), - cpu_affinity: { - let mut affinity = 0; - affinity.set_bits(0..CPU_NUM, 1 << CPU_NUM - 1); - affinity - }, - unmask: 0o022, - stack: inner.stack.clone(), - need_wait: 0, - }), - send_sigchld_when_exit: sig == SignalNumber::SIGCHLD, - }; - let task = Arc::new(task); - if !flag.contains(CloneFlags::CLONE_PARENT) { - inner.children.push(task.clone()); - } - error!("create a task success"); - Some(task) - } - - /// 用于执行一个可执行文件,供sys_exec调用。 - /// - /// `name`用于传入文件的路径和文件名。 - /// `elf_data`用于传入从对应文件处读入的文件数据,用于构造elf_info。 - /// `args`用于指明启动可执行文件时要传入的参数。 - /// `env`用于指明相关环境变量。 - /// - /// 成功执行则返回OK(());否则返回错误码(isize)。 - pub fn exec( - &self, - name: &str, - elf_data: &[u8], - args: Vec, - env: Vec, - ) -> Result<(), isize> { - let mut args = args; - let elf_info = build_elf_address_space(elf_data, &mut args, name); - if elf_info.is_err() { - return Err(-1); - } - let elf_info = elf_info.unwrap(); - let mut inner = self.inner.lock(); - assert_eq!(inner.thread_number, 0); - let name = elf_info.name; - let address_space = elf_info.address_space; - // reset the address space - inner.address_space = Arc::new(Mutex::new(address_space)); - // reset the heap - inner.heap = Arc::new(Mutex::new(HeapInfo::new( - elf_info.heap_bottom, - elf_info.heap_bottom, - ))); - // reset the mmap - inner.mmap = MMapInfo::new(); - // set the name of the process - inner.name = name.to_string(); - // reset time record - inner.statistical_data.clear(); - // close file which contains FD_CLOEXEC flag - // now we delete all fd - // inner.fd_table = - // reset signal handler - inner.signal_handlers.lock().clear(); - inner.signal_receivers.lock().clear(); - inner.timer.clear(); - inner.stack = elf_info.stack_top - USER_STACK_SIZE..elf_info.stack_top; - let env = if env.is_empty() { - let envp = vec![ - "LD_LIBRARY_PATH=/", - "PS1=\x1b[1m\x1b[32mAlien\x1b[0m:\x1b[1m\x1b[34m\\w\x1b[0m\\$ \0", - "PATH=/bin:/usr/bin", - "UB_BINDIR=./", - ] - .iter() - .map(|x| x.to_string()) - .collect::>(); - envp - } else { - env - }; - // we need make sure the args and env size is less than 4KB - let phy_button = inner.transfer_raw(elf_info.stack_top - FRAME_SIZE); - let mut user_stack = UserStack::new(phy_button + FRAME_SIZE, elf_info.stack_top); - // push env to the top of stack of the process - // we have push '\0' into the env string,so we don't need to push it again - let envv = env - .iter() - .rev() - .map(|env| user_stack.push_str(env).unwrap()) - .collect::>(); - // push the args to the top of stack of the process - // we have push '\0' into the arg string,so we don't need to push it again - let argcv = args - .iter() - .rev() - .map(|arg| user_stack.push_str(arg).unwrap()) - .collect::>(); - // push padding to the top of stack of the process - user_stack.align_to(8).unwrap(); - let random_ptr = user_stack.push_bytes(&[0u8; 16]).unwrap(); - // padding - user_stack.push_bytes(&[0u8; 8]).unwrap(); - // push aux - let platform = user_stack.push_str("riscv").unwrap(); - - let ex_path = user_stack.push_str(&name).unwrap(); - user_stack.push(0).unwrap(); - user_stack.push(platform).unwrap(); - user_stack.push(AT_PLATFORM).unwrap(); - user_stack.push(ex_path).unwrap(); - user_stack.push(AT_EXECFN).unwrap(); - user_stack.push(elf_info.ph_num).unwrap(); - user_stack.push(AT_PHNUM).unwrap(); - user_stack.push(FRAME_SIZE).unwrap(); - user_stack.push(AT_PAGESZ).unwrap(); - - user_stack.push(elf_info.bias).unwrap(); - user_stack.push(AT_BASE).unwrap(); - user_stack.push(elf_info.entry).unwrap(); - user_stack.push(AT_ENTRY).unwrap(); - user_stack.push(elf_info.ph_entry_size).unwrap(); - user_stack.push(AT_PHENT).unwrap(); - user_stack.push(elf_info.ph_drift).unwrap(); - user_stack.push(AT_PHDR).unwrap(); - user_stack.push(0).unwrap(); - user_stack.push(AT_GID).unwrap(); - user_stack.push(0).unwrap(); - user_stack.push(AT_EGID).unwrap(); - user_stack.push(0).unwrap(); - user_stack.push(AT_UID).unwrap(); - user_stack.push(0).unwrap(); - user_stack.push(AT_EUID).unwrap(); - user_stack.push(0).unwrap(); - user_stack.push(AT_SECURE).unwrap(); - user_stack.push(random_ptr).unwrap(); - user_stack.push(AT_RANDOM).unwrap(); - - user_stack.push(0).unwrap(); - // push the env addr to the top of stack of the process - envv.iter().for_each(|env| { - user_stack.push(*env).unwrap(); - }); - user_stack.push(0).unwrap(); - // push the args addr to the top of stack of the process - argcv.iter().enumerate().for_each(|(_i, arg)| { - user_stack.push(*arg).unwrap(); - }); - // push the argc to the top of stack of the process - let argc = args.len(); - let argc_ptr = user_stack.push(argc).unwrap(); - let user_sp = argc_ptr; - warn!("args:{:?}, env:{:?}, user_sp: {:#x}", args, env, user_sp); - let (physical, _, _) = inner - .address_space - .lock() - .query(VirtAddr::from(TRAP_CONTEXT_BASE)) - .unwrap(); - let trap_frame = TrapFrame::from_raw_ptr(physical.as_usize() as *mut TrapFrame); - *trap_frame = TrapFrame::init_for_task( - elf_info.entry, - user_sp, - kernel_satp(), - self.kernel_stack.top(), - user_trap_vector as usize, - ); - trap_frame.regs()[4] = elf_info.tls; // tp --> tls - Ok(()) - } -} diff --git a/kkernel/src/trap/context.rs b/kkernel/src/trap/context.rs deleted file mode 100644 index 5cf2bb4d..00000000 --- a/kkernel/src/trap/context.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! Trap 上下文 (Trap帧) 的定义和相关操作 -use arch::ExtSstatus; -use riscv::register::sstatus::SPP; - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct TrapFrame { - /// 整数寄存器组 - x: [usize; 32], - /// sepc 记录陷入地址 - sepc: usize, - /// k_satp 记录内核根页表地址 - k_satp: usize, - /// k_sp记录task内核栈地址 - k_sp: usize, - /// 记录trap处理的地址 - trap_handler: usize, - /// 记录所在的核 - hart_id: usize, - /// 给出 Trap 发生之前 CPU 处在哪个特权级等信息 - sstatus: ExtSstatus, - fg: [usize; 2], -} - -impl TrapFrame { - /// 获取当前的 Trap 帧下的 sstatus 寄存器的值 - pub fn get_status(&self) -> ExtSstatus { - self.sstatus - } - - /// 用于在收到外部中断时,需要将程序计数器 pc + 4 (下一条指令位置加4个字节) - pub fn update_sepc(&mut self) { - self.sepc += 4; - } - - pub fn from_raw_ptr(ptr: *mut TrapFrame) -> &'static mut Self { - unsafe { &mut *(ptr) } - } - - /// 更新 Trap 帧中的内核栈地址 - pub fn update_kernel_sp(&mut self, val: usize) { - self.k_sp = val; - } - - /// 返回 Trap 帧中的 sepc - pub fn sepc(&self) -> usize { - self.sepc - } - - /// 设置 Trap 帧中的 sepc - pub fn set_sepc(&mut self, val: usize) { - self.sepc = val; - } - - /// 用一个从文件系统中读取到的相关app数据,初始化一个 Trap 帧,使通过其创建的进程在初次进入用户态时能正常运行 - pub fn init_for_task( - entry: usize, - sp: usize, - k_satp: usize, - k_sp: usize, - trap_handler: usize, - ) -> Self { - let mut sstatus = ExtSstatus::read(); - sstatus.set_spie(); - // assert!(sstatus.0.get_bit(5)); //spie == 1 - sstatus.set_spp(SPP::User); - sstatus.set_sie(false); - let mut res = Self { - x: [0; 32], - sepc: entry, - k_satp, - k_sp, - trap_handler, - hart_id: 0, - sstatus, - fg: [0; 2], - }; - res.x[2] = sp; - res - } - - /// 更新 Trap 帧中 x[10] (即函数返回值) 的值 - pub fn update_res(&mut self, val: usize) { - self.x[10] = val; - } - - /// 更新 Trap 帧中 x[4] (tp) 的值 - pub fn update_tp(&mut self, val: usize) { - self.x[4] = val; - } - - /// 获取系统调用的参数,一般用于发生 trap 的原因是系统调用时 - pub fn parameters(&self) -> [usize; 7] { - [ - self.x[17], self.x[10], self.x[11], self.x[12], self.x[13], self.x[14], self.x[15], - ] - } - /// 获取整数寄存器组的可变引用 - pub fn regs(&mut self) -> &mut [usize] { - &mut self.x - } -} diff --git a/kkernel/src/trap/exception.rs b/kkernel/src/trap/exception.rs deleted file mode 100644 index bda11334..00000000 --- a/kkernel/src/trap/exception.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! Alien 中对于内部异常的处理 -//! -//! 目前包括系统调用异常处理 [`syscall_exception_handler`]、页错误异常处理 [`page_exception_handler`] (包括 -//! 指令页错误异常处理 [`instruction_page_fault_exception_handler`]、 加载页错误异常处理[`load_page_fault_exception_handler`]、 -//! 储存页错误异常处理 [`store_page_fault_exception_handler`]) 和 文件读入异常处理 [`trap_common_read_file`]。 -use crate::fs::file::File; -use crate::task::{current_task, current_trap_frame}; -use alloc::sync::Arc; -use arch::interrupt_enable; -use constants::{AlienError, AlienResult}; -use riscv::register::scause::{Exception, Trap}; - -/// 系统调用异常处理 -pub fn syscall_exception_handler() { - // enable interrupt - interrupt_enable(); - // jump to next instruction anyway - let mut cx = current_trap_frame(); - cx.update_sepc(); - // get system call return value - let parameters = cx.parameters(); - let syscall_name = constants::syscall_name(parameters[0]); - - let task = current_task().unwrap(); - let p_name = task.get_name(); - let tid = task.get_tid(); - let pid = task.get_pid(); - if !p_name.contains("shell") && !p_name.contains("init") && !p_name.contains("ls") { - // ignore shell and init - info!( - "[pid:{}, tid: {}][p_name: {}] syscall: [{}] {}({:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x})", - pid, - tid, - p_name, - parameters[0], - syscall_name, - parameters[1], - parameters[2], - parameters[3], - parameters[4], - parameters[5], - parameters[6] - ); - } - - let result = invoke_call_id!( - parameters[0], - parameters[1], - parameters[2], - parameters[3], - parameters[4], - parameters[5], - parameters[6] - ); - let result = Some(result); - // cx is changed during sys_exec, so we have to call it again - cx = current_trap_frame(); - - if !p_name.contains("shell") && !p_name.contains("init") && !p_name.contains("ls") { - info!( - "[pid:{}, tid: {}] syscall: [{}] result: {:?}, tp: {:#x}", - pid, - tid, - syscall_name, - result, - cx.regs()[4] - ); - } - cx.update_res(result.unwrap() as usize); -} - -/// 页异常处理,会根据不同的异常类型,分发至指令页错误异常处理 [`instruction_page_fault_exception_handler`]、 -/// 加载页错误异常处理 [`load_page_fault_exception_handler`]、 -/// 储存页错误异常处理 [`store_page_fault_exception_handler`] 等处理方案中。 -pub fn page_exception_handler(trap: Trap, addr: usize) -> AlienResult<()> { - trace!( - "[pid: {}] page fault addr:{:#x} trap:{:?}", - current_task().unwrap().get_pid(), - addr, - trap - ); - match trap { - Trap::Exception(Exception::LoadPageFault) => load_page_fault_exception_handler(addr)?, - Trap::Exception(Exception::StorePageFault) => store_page_fault_exception_handler(addr)?, - Trap::Exception(Exception::InstructionPageFault) => { - instruction_page_fault_exception_handler(addr)? - } - _ => { - return Err(AlienError::ENOSYS); - } - } - Ok(()) -} - -/// 指令页错误异常处理 -pub fn instruction_page_fault_exception_handler(addr: usize) -> AlienResult<()> { - let task = current_task().unwrap(); - trace!( - "[tid: {}] do instruction_page_fault addr:{:#x}", - task.get_tid(), - addr - ); - let res = task.access_inner().do_instruction_page_fault(addr)?; - if res.is_some() { - let (file, buf, offset) = res.unwrap(); - if file.is_some() { - trap_common_read_file(file.unwrap(), buf, offset); - } - } - Ok(()) -} - -/// 加载页错误异常处理 -pub fn load_page_fault_exception_handler(addr: usize) -> AlienResult<()> { - let info = { - let process = current_task().unwrap(); - process.access_inner().do_load_page_fault(addr)? - }; - if info.is_some() { - let (file, buf, offset) = info.unwrap(); - if file.is_some() { - trap_common_read_file(file.unwrap(), buf, offset); - } - } - Ok(()) -} - -/// 储存页错误异常处理 -pub fn store_page_fault_exception_handler(addr: usize) -> AlienResult<()> { - let process = current_task().unwrap(); - trace!( - "[tid: {}] do store page fault addr:{:#x}", - process.get_tid(), - addr - ); - let res = process.access_inner().do_store_page_fault(addr)?; - if res.is_some() { - let (file, buf, offset) = res.unwrap(); - if file.is_some() { - trap_common_read_file(file.unwrap(), buf, offset); - } - } - Ok(()) -} - -/// 文件读入异常处理 -pub fn trap_common_read_file(file: Arc, buf: &mut [u8], offset: u64) { - info!( - "trap_common_read_file buf.len: {}, offset:{:#x}", - buf.len(), - offset - ); - // let r = vfs_read_file::(file.get_file(), buf, offset); - let r = file.read_at(offset, buf); - if r.is_err() { - info!("page fault: read file error"); - } -} diff --git a/kkernel/src/trap/interrupt.rs b/kkernel/src/trap/interrupt.rs deleted file mode 100644 index 82934756..00000000 --- a/kkernel/src/trap/interrupt.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Alien 的外部中断处理 -//! -//! 目前仅有时钟中断处理函数。 -use interrupt::record::write_irq_info; -use crate::ipc::solve_futex_wait; -use crate::task::do_suspend; -use crate::time::{check_timer_queue, set_next_trigger}; - -/// 时钟中断处理函数 -pub fn timer_interrupt_handler() { - write_irq_info(1); - check_timer_queue(); - solve_futex_wait(); - set_next_trigger(); - do_suspend(); -} diff --git a/kkernel/src/trap/kernel_v.asm b/kkernel/src/trap/kernel_v.asm deleted file mode 100644 index b334e184..00000000 --- a/kkernel/src/trap/kernel_v.asm +++ /dev/null @@ -1,47 +0,0 @@ -.attribute arch, "rv64gc" -.altmacro -.macro KSAVE_GP n - sd x\n, \n*8(sp) -.endm -.macro KLOAD_GP n - ld x\n, \n*8(sp) -.endm - - -.section .text -.globl kernel_v -.align 3 -kernel_v: - addi sp, sp, -34*8 - sd x1, 1*8(sp) - sd x3, 3*8(sp) - sd x4, 4*8(sp) - .set n, 5 - .rept 27 - KSAVE_GP %n - .set n, n+1 - .endr - csrr t0, sstatus - csrr t1, sepc - sd t0, 32*8(sp) - sd t1, 33*8(sp) - mv a0, sp - # call the C trap handler in trap.c - csrr t2, sscratch - jalr t2 - - - ld t0, 32*8(sp) - ld t1, 33*8(sp) - csrw sstatus, t0 - csrw sepc, t1 - ld x1, 1*8(sp) - ld x3, 3*8(sp) - ld x4, 4*8(sp) - .set n, 5 - .rept 27 - KLOAD_GP %n - .set n, n+1 - .endr - addi sp, sp, 34*8 - sret diff --git a/kkernel/src/trap/mod.rs b/kkernel/src/trap/mod.rs deleted file mode 100644 index 5a350300..00000000 --- a/kkernel/src/trap/mod.rs +++ /dev/null @@ -1,309 +0,0 @@ -use core::arch::{asm, global_asm}; -use bit_field::BitField; -use riscv::register::sstatus::SPP; -use riscv::register::{sepc, sscratch, sstatus, stval, stvec}; - -use constants::signal::SignalNumber; -use constants::signal::SIGNAL_RETURN_TRAP; -use constants::time::TimerType; -pub use context::TrapFrame; -pub use exception::trap_common_read_file; - -use config::TRAMPOLINE; -use ::interrupt::external_interrupt_handler; -use ::interrupt::record::write_irq_info; -use crate::ipc::{send_signal, signal_handler, signal_return, solve_futex_wait}; -use crate::task::{current_task, current_trap_frame, current_user_token, do_exit, do_suspend}; -use crate::time::{check_timer_queue, set_next_trigger, set_next_trigger_in_kernel}; -use arch::{ - external_interrupt_enable, interrupt_disable, interrupt_enable, is_interrupt_enable, - timer_interrupt_enable, -}; -use constants::AlienError; -use riscv::register::scause::{Exception, Interrupt, Trap}; -use riscv::register::stvec::TrapMode; - -mod context; -mod exception; -mod interrupt; - -global_asm!(include_str!("./kernel_v.asm")); -global_asm!(include_str!("./trampoline.asm")); - -extern "C" { - fn kernel_v(); - fn user_v(); - fn user_r(); -} - -#[no_mangle] -/// set the new addr of __restore asm function in TRAMPOLINE page, -/// set the reg a0 = trap_cx_ptr, reg a1 = phy addr of usr page table, -/// finally, jump to new addr of __restore asm function -pub fn trap_return() -> ! { - check_timer_interrupt_pending(); - signal_handler(); - interrupt_disable(); - set_user_trap_entry(); - let trap_frame = current_trap_frame(); - let sstatues = trap_frame.get_status(); - let enable = sstatues.0.get_bit(5); - let sie = sstatues.0.get_bit(1); - assert!(enable); - assert!(!sie); - - let trap_cx_ptr = current_task().unwrap().trap_frame_ptr(); - let user_satp = current_user_token(); - let restore_va = user_r as usize - user_v as usize + TRAMPOLINE; - unsafe { - asm!( - "fence.i", - "jr {restore_va}", - restore_va = in(reg) restore_va, - in("a0") trap_cx_ptr, - in("a1") user_satp, - options(noreturn) - ) - } -} - -/// 设置用户态 trap 处理例程的入口点 -#[inline] -fn set_user_trap_entry() { - unsafe { - stvec::write(TRAMPOLINE, TrapMode::Direct); - } -} - -/// 设置内核态 trap 处理例程的入口点 -#[inline] -pub fn set_kernel_trap_entry() { - unsafe { - sscratch::write(kernel_trap_vector as usize); - stvec::write(kernel_v as usize, TrapMode::Direct); - } -} - -/// 开启中断/异常 -pub fn init_trap_subsystem() { - println!("++++ setup interrupt ++++"); - set_kernel_trap_entry(); - external_interrupt_enable(); - timer_interrupt_enable(); - interrupt_enable(); - let enable = is_interrupt_enable(); - println!("++++ setup interrupt done, enable:{:?} ++++", enable); -} - -pub trait TrapHandler { - fn do_user_handle(&self); - fn do_kernel_handle(&self, sp: usize); -} - -impl TrapHandler for Trap { - /// 用户态下的 trap 例程 - fn do_user_handle(&self) { - let stval = stval::read(); - let sepc = sepc::read(); - trace!("trap :{:?}", self); - match self { - Trap::Exception(Exception::UserEnvCall) => { - exception::syscall_exception_handler(); - } - Trap::Exception(Exception::StoreFault) - | Trap::Exception(Exception::LoadFault) - | Trap::Exception(Exception::InstructionFault) - | Trap::Exception(Exception::IllegalInstruction) => { - error!( - "[User] {:?} in application,stval:{:#x?} sepc:{:#x?}", - self, stval, sepc - ); - let task = current_task().unwrap(); - send_signal(task.get_tid() as usize, SignalNumber::SIGSEGV as usize) - } - Trap::Exception(Exception::StorePageFault) - | Trap::Exception(Exception::LoadPageFault) => { - let task = current_task().unwrap(); - let tid = task.get_tid(); - warn!( - "[User][tid:{}] {:?} in application,stval:{:#x?} sepc:{:#x?}", - tid, self, stval, sepc - ); - let res = exception::page_exception_handler(self.clone(), stval); - if res.is_err() { - error!( - "[User] {:?} in application,stval:{:#x?} sepc:{:#x?}", - self, stval, sepc - ); - let err = res.err().unwrap(); - if err == AlienError::EAGAIN { - // println!("thread need wait"); - do_suspend(); - } else if err == AlienError::ETMP { - do_exit(-1); - } else { - send_signal(tid as usize, SignalNumber::SIGSEGV as usize) - } - } - } - Trap::Exception(Exception::InstructionPageFault) => { - trace!( - "[User] {:?} in application,stval:{:#x?} sepc:{:#x?}", - self, - stval, - sepc - ); - if stval == SIGNAL_RETURN_TRAP { - // 当作调用了 sigreturn 一样 - let cx = current_trap_frame(); - cx.regs()[10] = signal_return() as usize; - return; - } - - let res = exception::page_exception_handler(self.clone(), stval); - if res.is_err() { - error!( - "[User] {:?} in application,stval:{:#x?} sepc:{:#x?}", - self, stval, sepc - ); - let task = current_task().unwrap(); - send_signal(task.get_tid() as usize, SignalNumber::SIGSEGV as usize) - } - } - Trap::Interrupt(Interrupt::SupervisorTimer) => { - trace!("[User] timer interrupt"); - interrupt::timer_interrupt_handler(); - } - Trap::Interrupt(Interrupt::SupervisorExternal) => { - trace!("external interrupt"); - external_interrupt_handler(); - } - _ => { - panic!( - "unhandled trap: {:?}, stval: {:?}, sepc: {:x}", - self, stval, sepc - ); - } - } - } - - /// 内核态下的 trap 例程 - fn do_kernel_handle(&self, sp: usize) { - let stval = stval::read(); - let sepc = sepc::read(); - match self { - Trap::Interrupt(Interrupt::SupervisorTimer) => { - trace!("[kernel] timer interrupt"); - write_irq_info(1); - check_timer_queue(); - solve_futex_wait(); - // set_next_trigger(); - set_next_trigger_in_kernel(); - } - Trap::Exception(Exception::StorePageFault) => { - debug!( - "[kernel] {:?} in kernel, stval:{:#x?} sepc:{:#x?}", - self, stval, sepc - ); - { - // let kernel_space = KERNEL_SPACE.read(); - // let phy = kernel_space.query(VirtAddr::from(stval)); - let phy = mem::query_kernel_space(stval); - debug!("physical address: {:#x?}", phy); - } - } - Trap::Exception(_) => { - panic!( - "unhandled trap: {:?}, stval: {:#x?}, sepc: {:#x}, sp: {:#x}", - self, stval, sepc, sp - ) - } - Trap::Interrupt(Interrupt::SupervisorExternal) => { - external_interrupt_handler(); - } - _ => { - panic!( - "unhandled trap: {:?}, stval: {:?}, sepc: {:x}", - self, stval, sepc - ) - } - } - // check timer interrupt - check_timer_interrupt_pending(); - } -} - -/// 检查时钟中断是否被屏蔽 -pub fn check_timer_interrupt_pending() { - let sip = riscv::register::sip::read(); - if sip.stimer() { - debug!("timer interrupt pending"); - set_next_trigger(); - } - let sie = riscv::register::sie::read(); - if !sie.stimer() { - panic!("[check_timer_interrupt_pending] timer interrupt not enable"); - } -} - -/// 用户态陷入处理 -#[no_mangle] -pub fn user_trap_vector() { - let sstatus = sstatus::read(); - let spp = sstatus.spp(); - if spp == SPP::Supervisor { - panic!("user_trap_vector: spp == SPP::Supervisor"); - } - { - let task = current_task().expect("user_trap_vector: current_task is none"); - // update process statistics - task.access_inner().update_user_mode_time(); - check_task_timer_expired(); - } - set_kernel_trap_entry(); - let cause = riscv::register::scause::read(); - let cause = cause.cause(); - cause.do_user_handle(); - let task = current_task().unwrap(); - if cause != Trap::Interrupt(Interrupt::SupervisorTimer) { - // update process statistics - task.access_inner().update_kernel_mode_time(); - } - task.access_inner().update_timer(); - check_task_timer_expired(); - trap_return(); -} - -/// 用于检查进程的计时器是否超时。如果超时则会重置计时器,并按照计时器类型向进程发送信号。 -pub fn check_task_timer_expired() { - let task = current_task().unwrap(); - let timer_expired = task.access_inner().check_timer_expired(); - let tid = task.get_tid() as usize; - if timer_expired.is_some() { - error!("timer expired: {:?}", timer_expired); - let timer_type = timer_expired.unwrap(); - match timer_type { - TimerType::REAL => send_signal(tid, SignalNumber::SIGALRM as usize), - TimerType::VIRTUAL => send_signal(tid, SignalNumber::SIGVTALRM as usize), - TimerType::PROF => send_signal(tid, SignalNumber::SIGPROF as usize), - _ => { - panic!("timer type error"); - } - }; - } -} - -/// 只有在内核态下才能进入这个函数 -/// 避免嵌套中断发生这里不会再开启中断 -#[no_mangle] -pub fn kernel_trap_vector(sp: usize) { - let sstatus = sstatus::read(); - let spp = sstatus.spp(); - if spp == SPP::User { - panic!("kernel_trap_vector: spp == SPP::User"); - } - let enable = is_interrupt_enable(); - assert!(!enable); - let cause = riscv::register::scause::read().cause(); - cause.do_kernel_handle(sp) -} diff --git a/kkernel/src/trap/trampoline.asm b/kkernel/src/trap/trampoline.asm deleted file mode 100644 index 00bf2c28..00000000 --- a/kkernel/src/trap/trampoline.asm +++ /dev/null @@ -1,83 +0,0 @@ -.attribute arch, "rv64gc" -.altmacro -.macro SAVE_GP n - sd x\n, \n*8(sp) -.endm -.macro LOAD_GP n - ld x\n, \n*8(sp) -.endm - .section .text.trampoline - .globl user_v - .globl user_r - .align 3 -user_v: - csrrw sp, sscratch, sp - # now sp->*TrapContext in user space, sscratch->user stack - # save other general purpose registers - sd x1, 1*8(sp) - # skip sp(x2), we will save it later - # save x3~x31 - .set n, 3 - .rept 29 - SAVE_GP %n - .set n, n+1 - .endr - # we can use t0/t1/t2 freely, because they have been saved in TrapContext - csrr t0, sstatus - csrr t1, sepc - sd t1, 32*8(sp) - sd t0, 37*8(sp) - fsd fs0, 38*8(sp) - fsd fs1, 39*8(sp) - # read user stack from sscratch and save it in TrapContext - csrr t2, sscratch - sd t2, 2*8(sp) - # load kernel_satp into t0 - ld t0, 33*8(sp) - # load trap_handler into t1 - ld t1, 35*8(sp) - # load tp - ld tp,36*8(sp) - # move to kernel_sp - ld sp, 34*8(sp) - - # load hartid into tp(x4) - # ld tp, 36*8(tp) - # 保证用户态缓存全部刷新到内存 - sfence.vma - # switch to kernel space - csrw satp, t0 - sfence.vma - # jump to trap_handler - jr t1 - -user_r: - # a0: *TrapContext in user space(Constant); a1: user space token - # switch to user space - sfence.vma - csrw satp, a1 - sfence.vma - csrw sscratch, a0 - mv sp, a0 - # now sp points to TrapContext in user space, start restoring based on it - # restore sstatus/sepc - ld t1, 32*8(sp) - ld t0, 37*8(sp) - # save cpu_id - sd tp, 36*8(sp) - - csrw sepc, t1 - csrw sstatus, t0 - # restore general purpose registers except x0/sp - ld x1, 1*8(sp) - .set n, 3 - .rept 29 - LOAD_GP %n - .set n, n+1 - .endr - fld fs0, 38*8(sp) - fld fs1, 39*8(sp) - - # back to user stack - ld sp, 2*8(sp) - sret \ No newline at end of file diff --git a/subsystems/config/build.rs b/subsystems/config/build.rs index 2fdeee20..53e423ec 100644 --- a/subsystems/config/build.rs +++ b/subsystems/config/build.rs @@ -1,21 +1,21 @@ -use std::fs; -use std::path::Path; - -fn main(){ - println!("cargo:rerun-if-changed={}", "src/lib.rs"); - let cpus = option_env!("SMP").unwrap_or("1"); - let cpus = cpus.parse::().unwrap(); - let config_file = Path::new("src/lib.rs"); - let config = fs::read_to_string(config_file).unwrap(); - let cpus = format!("pub const CPU_NUM: usize = {};\n", cpus); - let mut new_config = String::new(); - for line in config.lines() { - if line.starts_with("pub const CPU_NUM: usize = ") { - new_config.push_str(cpus.as_str()); - } else { - new_config.push_str(line); - new_config.push_str("\n"); - } - } - fs::write(config_file, new_config).unwrap(); -} \ No newline at end of file +use std::fs; +use std::path::Path; + +fn main() { + println!("cargo:rerun-if-changed={}", "src/lib.rs"); + let cpus = option_env!("SMP").unwrap_or("1"); + let cpus = cpus.parse::().unwrap(); + let config_file = Path::new("src/lib.rs"); + let config = fs::read_to_string(config_file).unwrap(); + let cpus = format!("pub const CPU_NUM: usize = {};\n", cpus); + let mut new_config = String::new(); + for line in config.lines() { + if line.starts_with("pub const CPU_NUM: usize = ") { + new_config.push_str(cpus.as_str()); + } else { + new_config.push_str(line); + new_config.push_str("\n"); + } + } + fs::write(config_file, new_config).unwrap(); +} diff --git a/subsystems/constants/src/lib.rs b/subsystems/constants/src/lib.rs index 95463953..4797a30e 100644 --- a/subsystems/constants/src/lib.rs +++ b/subsystems/constants/src/lib.rs @@ -35,4 +35,4 @@ impl From for DeviceId { } } -pub const AT_FDCWD: isize = -100isize; \ No newline at end of file +pub const AT_FDCWD: isize = -100isize; diff --git a/subsystems/devices/Cargo.toml b/subsystems/devices/Cargo.toml index f29154d4..91bf978b 100644 --- a/subsystems/devices/Cargo.toml +++ b/subsystems/devices/Cargo.toml @@ -41,5 +41,6 @@ features = [ [features] default = ["test"] -memblk = [] -test = [] \ No newline at end of file +ramdisk = [] +test = [] +vf2 = [] # enable to probe vf2's sdcard diff --git a/subsystems/devices/src/lib.rs b/subsystems/devices/src/lib.rs index dc641708..ebc47c8b 100644 --- a/subsystems/devices/src/lib.rs +++ b/subsystems/devices/src/lib.rs @@ -27,15 +27,13 @@ use platform::println; use spin::{Lazy, Once}; use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; use virtio_drivers::transport::{DeviceType, Transport}; - -pub use block::{BLKDevice,BLOCK_DEVICE}; -pub use gpu::{GPUDevice,GPU_DEVICE}; -pub use input::{INPUTDevice,KEYBOARD_INPUT_DEVICE,MOUSE_INPUT_DEVICE}; +pub use block::{BLKDevice, BLOCK_DEVICE}; +use drivers::block_device::GenericBlockDevice; +pub use gpu::{GPUDevice, GPU_DEVICE}; +pub use input::{INPUTDevice, KEYBOARD_INPUT_DEVICE, MOUSE_INPUT_DEVICE}; use interrupt::register_device_to_plic; -pub use rtc::{RTC_DEVICE,RTCDevice}; -pub use uart::{UARTDevice,UART_DEVICE}; - - +pub use rtc::{RTCDevice, RTC_DEVICE}; +pub use uart::{UARTDevice, UART_DEVICE}; pub struct DeviceInfo { pub device: Arc, @@ -47,15 +45,15 @@ pub static INITIALIZED_DEVICES: Lazy>> = Lazy::new(|| Mute static TASK_FUNC: Once> = Once::new(); -pub trait DeviceWithTask:Send+Sync{ +pub trait DeviceWithTask: Send + Sync { fn transfer_ptr_raw(&self, ptr: usize) -> usize; - fn transfer_buf_raw(&self, src: usize, size:usize) -> Vec<&mut [u8]>; + fn transfer_buf_raw(&self, src: usize, size: usize) -> Vec<&mut [u8]>; } -impl dyn DeviceWithTask{ - fn copy_data_to_task(&self,src: *const T, dst: *mut T){ +impl dyn DeviceWithTask { + fn copy_data_to_task(&self, src: *const T, dst: *mut T) { let size = core::mem::size_of::(); - let bufs = self.transfer_buf_raw(dst as usize,size); + let bufs = self.transfer_buf_raw(dst as usize, size); let src = unsafe { core::slice::from_raw_parts(src as *const u8, size) }; let mut start = 0; for buffer in bufs { @@ -65,18 +63,14 @@ impl dyn DeviceWithTask{ buffer.len() }; unsafe { - core::ptr::copy_nonoverlapping( - src.as_ptr().add(start), - buffer.as_mut_ptr(), - len, - ); + core::ptr::copy_nonoverlapping(src.as_ptr().add(start), buffer.as_mut_ptr(), len); } start += len; } } - fn copy_data_from_task(&self,src: *const T, dst: *mut T){ + fn copy_data_from_task(&self, src: *const T, dst: *mut T) { let size = core::mem::size_of::(); - let bufs = self.transfer_buf_raw(src as usize,size); + let bufs = self.transfer_buf_raw(src as usize, size); let dst = unsafe { core::slice::from_raw_parts_mut(dst as *mut u8, size) }; let mut start = 0; for buffer in bufs { @@ -86,35 +80,29 @@ impl dyn DeviceWithTask{ buffer.len() }; unsafe { - core::ptr::copy_nonoverlapping( - buffer.as_ptr(), - dst.as_mut_ptr().add(start), - len, - ); + core::ptr::copy_nonoverlapping(buffer.as_ptr(), dst.as_mut_ptr().add(start), len); } start += len; } } - fn transfer_ptr_mut(&self, ptr: *mut T) -> &'static mut T{ + fn transfer_ptr_mut(&self, ptr: *mut T) -> &'static mut T { let ptr = ptr as usize; let ptr = self.transfer_ptr_raw(ptr); unsafe { &mut *(ptr as *mut T) } } - fn transfer_ptr(&self, ptr: *const T) -> &'static T{ + fn transfer_ptr(&self, ptr: *const T) -> &'static T { let ptr = ptr as usize; let ptr = self.transfer_ptr_raw(ptr); unsafe { &*(ptr as *const T) } } } - /// Probe all devices from device tree and init them. /// # Warning /// Before init device, we should init platform first. /// /// todo!(The task_func should be replaced) -pub fn init_device(task_func:Box) { - +pub fn init_device(task_func: Box) { TASK_FUNC.call_once(|| task_func); let dtb_ptr = platform::platform_dtb_ptr(); @@ -122,26 +110,34 @@ pub fn init_device(task_func:Box) { let dtb = unsafe { Fdt::from_ptr(dtb_ptr as *const u8).unwrap() }; match dtb.probe_rtc() { Some(rtc) => init_rtc(rtc), - None => { println!("There is no rtc device"); }, + None => { + println!("There is no rtc device"); + } } match dtb.probe_uart() { Some(uart) => init_uart(uart), - None => { println!("There is no uart device"); }, + None => { + println!("There is no uart device"); + } } match dtb.probe_virtio() { Some(virtio_mmio_devices) => init_virtio_mmio(virtio_mmio_devices), - None => { println!("There is no virtio-mmio device"); }, + None => { + println!("There is no virtio-mmio device"); + } } + + + } fn init_rtc(rtc: prob::DeviceInfo) { let info = rtc; println!( "Init rtc, base_addr:{:#x}, irq:{}", - info.base_addr, - info.irq + info.base_addr, info.irq ); match info.compatible.as_str() { "google,goldfish-rtc" => { @@ -226,17 +222,17 @@ pub fn init_virtio_mmio(devices: Vec) { init_input_device(device, "mouse"); } } - DeviceType::Block => init_block_device(device,Some(transport)), + DeviceType::Block => init_block_device(device, Some(transport)), DeviceType::GPU => init_gpu(device), - DeviceType::Network => { init_net(device) }, - _ => {}, + DeviceType::Network => init_net(device), + _ => {} } } } } } -#[cfg(feature = "memblk")] +#[cfg(feature = "ramdisk")] core::arch::global_asm!( r#" .section .data @@ -249,32 +245,30 @@ core::arch::global_asm!( "# ); -#[cfg(feature = "memblk")] +#[cfg(feature = "ramdisk")] extern "C" { pub fn img_start(); pub fn img_end(); } -#[cfg(feature = "memblk")] +#[cfg(feature = "ramdisk")] pub fn checkout_fs_img() { let img_start = img_start as usize; let img_end = img_end as usize; let img_size = img_end - img_start; println!( "img_start: {:#x}, img_end: {:#x}, img_size: {:#x}", - img_start, - img_end, - img_size + img_start, img_end, img_size ); } fn init_block_device(blk: prob::DeviceInfo, mmio_transport: Option) { - use drivers::block_device::{GenericBlockDevice, VirtIOBlkWrapper}; + use drivers::block_device::{VirtIOBlkWrapper}; + let (base_addr, irq) = (blk.base_addr, blk.irq); match blk.compatible.as_str() { "virtio,mmio" => { // qemu // let mut block_device = VirtIOBlkWrapper::new(blk.base_addr); let block_device = VirtIOBlkWrapper::from_mmio(mmio_transport.unwrap()); - let (base_addr, irq) = (blk.base_addr, blk.irq); println!("Init block device, base_addr:{:#x},irq:{}", base_addr, irq); let size = block_device.capacity(); println!("Block device size is {}MB", size * 512 / 1024 / 1024); @@ -283,28 +277,60 @@ fn init_block_device(blk: prob::DeviceInfo, mmio_transport: Option { + // visionfi ve2/starfive2 + #[cfg(not(feature = "ramdisk"))] + { + use arch::read_timer; + use platform::config::CLOCK_FREQ; + pub fn sleep(ms: usize) { + let start = read_timer(); + while read_timer() - start < ms * (CLOCK_FREQ / 1000) { + core::hint::spin_loop(); + } + } + use drivers::block_device::{Vf2SdDriver,VF2SDDriver}; + let block_device = VF2SDDriver::new(Vf2SdDriver::new(sleep)); + let size = block_device.capacity(); + println!("Block device size is {}MB", size * 512 / 1024 / 1024); + let block_device = Arc::new(GenericBlockDevice::new(Box::new(block_device))); + block::init_block_device(block_device); + // register_device_to_plic(irq, block_device); + println!("Init SDIO block device success"); + } + #[cfg(feature = "ramdisk")] + { + init_ramdisk(); + } + } name => { println!("Don't support block device: {}", name); - #[cfg(feature = "memblk")] - { - use drivers::block_device::MemoryFat32Img; - checkout_fs_img(); - let data = unsafe { - core::slice::from_raw_parts_mut( - img_start as *mut u8, - img_end as usize - img_start as usize, - ) - }; - let device = GenericBlockDevice::new(Box::new(MemoryFat32Img::new(data))); - let device = Arc::new(device); - println!("Init fake block device success"); + #[cfg(feature = "ramdisk")]{ + init_ramdisk(); } - #[cfg(not(feature = "memblk"))] + #[cfg(not(feature = "ramdisk"))] panic!("System need block device, but there is no block device"); } } } +#[cfg(feature = "ramdisk")] +fn init_ramdisk() { + use drivers::block_device::MemoryFat32Img; + checkout_fs_img(); + let data = unsafe { + core::slice::from_raw_parts_mut( + img_start as *mut u8, + img_end as usize - img_start as usize, + ) + }; + let block_device = GenericBlockDevice::new(Box::new(MemoryFat32Img::new(data))); + let block_device = Arc::new(block_device); + block::init_block_device(block_device); + println!("Init fake block device success"); +} + + fn init_gpu(gpu: prob::DeviceInfo) { let (base_addr, irq) = (gpu.base_addr, gpu.irq); println!("Init gpu, base_addr:{:#x},irq:{}", base_addr, irq); @@ -330,9 +356,7 @@ fn init_input_device(input: prob::DeviceInfo, name: &str) { let (base_addr, irq) = (input.base_addr, input.irq); println!( "Init {} input device, base_addr:{:#x},irq:{}", - name, - base_addr, - irq + name, base_addr, irq ); match input.compatible.as_str() { "virtio,mmio" => { @@ -359,7 +383,7 @@ fn init_input_device(input: prob::DeviceInfo, name: &str) { } } -fn init_net(nic: prob::DeviceInfo) { +fn init_net(_nic: prob::DeviceInfo) { // If we need run test, we should only init loop device because no we can't route packet #[cfg(feature = "test")] { @@ -367,10 +391,10 @@ fn init_net(nic: prob::DeviceInfo) { } #[cfg(not(feature = "test"))] { - let (base_addr, irq) = (nic.base_addr, nic.irq); + let (base_addr, irq) = (_nic.base_addr, _nic.irq); println!("Init net device, base_addr:{:#x},irq:{}", base_addr, irq); - match nic.compatible.as_str() { + match _nic.compatible.as_str() { "virtio,mmio" => { use config::{QEMU_GATEWAY, QEMU_IP}; use core::str::FromStr; diff --git a/subsystems/devices/src/net.rs b/subsystems/devices/src/net.rs index 8b137891..8c2039d0 100644 --- a/subsystems/devices/src/net.rs +++ b/subsystems/devices/src/net.rs @@ -1 +1,91 @@ +#[cfg(feature = "net_test")] +pub mod nettest { + use crate::net::port::neterror2alien; + use alloc::vec::Vec; + use constants::AlienResult; + use core::net::{IpAddr, SocketAddr}; + use netcore::tcp::TcpSocket; + + /// A TCP stream between a local and a remote socket. + pub struct TcpStream(TcpSocket); + + /// A TCP socket server, listening for connections. + pub struct TcpListener(TcpSocket); + + impl TcpStream { + pub fn read(&mut self, buf: &mut [u8]) -> AlienResult { + self.0.recv(buf).map_err(neterror2alien) + } + pub fn write_all(&mut self, buf: &[u8]) -> AlienResult { + self.0.send(buf).map_err(neterror2alien) + } + } + + impl TcpListener { + pub fn bind(addr: SocketAddr) -> AlienResult { + let socket = TcpSocket::new(); + socket.bind(addr).map_err(neterror2alien)?; + socket.listen().map_err(neterror2alien)?; + Ok(TcpListener(socket)) + } + pub fn local_addr(&self) -> AlienResult { + self.0.local_addr().map_err(neterror2alien) + } + + pub fn accept(&self) -> AlienResult<(TcpStream, SocketAddr)> { + let socket = self.0.accept().map_err(neterror2alien)?; + let addr = socket.peer_addr().map_err(neterror2alien)?; + Ok((TcpStream(socket), addr)) + } + } + + const LOCAL_IP: &str = "0.0.0.0"; + const LOCAL_PORT: u16 = 5555; + + fn reverse(buf: &[u8]) -> Vec { + let mut lines = buf + .split(|&b| b == b'\n') + .map(Vec::from) + .collect::>(); + for line in lines.iter_mut() { + line.reverse(); + } + lines.join(&b'\n') + } + + fn echo_server(mut stream: TcpStream) -> AlienResult<()> { + let mut buf = [0u8; 1024]; + loop { + let n = stream.read(&mut buf).unwrap(); + if n == 0 { + return Ok(()); + } + stream.write_all(reverse(&buf[..n]).as_slice()).unwrap(); + } + } + + pub fn accept_loop() { + let local_addr = SocketAddr::new(IpAddr::V4(LOCAL_IP.parse().unwrap()), LOCAL_PORT); + let listener = TcpListener::bind(local_addr).unwrap(); + println!("listen on: {}", listener.local_addr().unwrap()); + let mut i = 0; + loop { + match listener.accept() { + Ok((stream, addr)) => { + println!("new client {}: {}", i, addr); + match echo_server(stream) { + Err(e) => { + println!("client connection error: {:?}", e); + } + Ok(()) => { + println!("client {} closed successfully", i); + } + } + } + Err(e) => panic!("couldn't get client: {:?}", e), + } + i += 1; + } + } +} \ No newline at end of file diff --git a/subsystems/devices/src/prob.rs b/subsystems/devices/src/prob.rs index 76a163fe..7768d768 100644 --- a/subsystems/devices/src/prob.rs +++ b/subsystems/devices/src/prob.rs @@ -32,6 +32,10 @@ pub trait Probe { /// Get the base address and irq number of the virtio devices from the device tree. fn probe_virtio(&self) -> Option>; fn probe_common(&self, device_name: &str) -> Option; + #[cfg(feature = "vf2")] + fn probe_sdio(&self) -> Option { + self.probe_common("sdio1") + } } impl Probe for Fdt<'_> { diff --git a/subsystems/devices/src/rtc.rs b/subsystems/devices/src/rtc.rs index b2dd7d30..955a5497 100644 --- a/subsystems/devices/src/rtc.rs +++ b/subsystems/devices/src/rtc.rs @@ -1,3 +1,4 @@ +use crate::TASK_FUNC; use alloc::format; use alloc::sync::Arc; use constants::io::{RtcTime, TeletypeCommand}; @@ -11,7 +12,6 @@ use vfscore::inode::{InodeAttr, VfsInode}; use vfscore::superblock::VfsSuperBlock; use vfscore::utils::{VfsFileStat, VfsNodeType}; use vfscore::VfsResult; -use crate::TASK_FUNC; pub static RTC_DEVICE: Once> = Once::new(); @@ -57,7 +57,10 @@ impl VfsFile for RTCDevice { match cmd { TeletypeCommand::RTC_RD_TIME => { let time = self.device.read_time(); - TASK_FUNC.get().unwrap().copy_data_to_task(&time, arg as *mut RtcTime); + TASK_FUNC + .get() + .unwrap() + .copy_data_to_task(&time, arg as *mut RtcTime); } _ => return Err(VfsError::Invalid), } diff --git a/subsystems/devices/src/uart.rs b/subsystems/devices/src/uart.rs index a91ccb63..77a347cd 100644 --- a/subsystems/devices/src/uart.rs +++ b/subsystems/devices/src/uart.rs @@ -1,3 +1,4 @@ +use crate::TASK_FUNC; use alloc::sync::Arc; use constants::io::{LocalModes, TeletypeCommand, Termios, WinSize}; use constants::DeviceId; @@ -10,7 +11,6 @@ use vfscore::inode::{InodeAttr, VfsInode}; use vfscore::superblock::VfsSuperBlock; use vfscore::utils::{VfsFileStat, VfsNodeType, VfsPollEvents}; use vfscore::VfsResult; -use crate::TASK_FUNC; pub static UART_DEVICE: Once> = Once::new(); @@ -102,12 +102,18 @@ impl VfsFile for UARTDevice { return match cmd { TeletypeCommand::TCGETS | TeletypeCommand::TCGETA => { // task_inner.copy_to_user(&io.termios, arg as *mut Termios); - TASK_FUNC.get().unwrap().copy_data_to_task(&io.termios, arg as *mut Termios); + TASK_FUNC + .get() + .unwrap() + .copy_data_to_task(&io.termios, arg as *mut Termios); Ok(0) } TeletypeCommand::TCSETS | TeletypeCommand::TCSETSW | TeletypeCommand::TCSETSF => { // task_inner.copy_from_user(arg as *const Termios, &mut io.termios); - TASK_FUNC.get().unwrap().copy_data_from_task(arg as *const Termios, &mut io.termios); + TASK_FUNC + .get() + .unwrap() + .copy_data_from_task(arg as *const Termios, &mut io.termios); Ok(0) } TeletypeCommand::TIOCGPGRP => { @@ -124,12 +130,18 @@ impl VfsFile for UARTDevice { } TeletypeCommand::TIOCGWINSZ => { // task_inner.copy_to_user(&io.winsize, arg as *mut WinSize); - TASK_FUNC.get().unwrap().copy_data_to_task(&io.winsize, arg as *mut WinSize); + TASK_FUNC + .get() + .unwrap() + .copy_data_to_task(&io.winsize, arg as *mut WinSize); Ok(0) } TeletypeCommand::TIOCSWINSZ => { // task_inner.copy_from_user(arg as *const WinSize, &mut io.winsize); - TASK_FUNC.get().unwrap().copy_data_from_task(arg as *const WinSize, &mut io.winsize); + TASK_FUNC + .get() + .unwrap() + .copy_data_from_task(arg as *const WinSize, &mut io.winsize); Ok(0) } _ => { diff --git a/subsystems/drivers/Cargo.toml b/subsystems/drivers/Cargo.toml index 02fbf061..dfa2bdb8 100644 --- a/subsystems/drivers/Cargo.toml +++ b/subsystems/drivers/Cargo.toml @@ -14,8 +14,6 @@ mem = { path = "../mem" } log = "0" timer = { path = "../timer" } platform = { path = "../platform" } - - spin = "0" virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers",rev = "de1c3b1"} @@ -32,5 +30,6 @@ loopback = {git = "https://github.com/os-module/simple-net"} virtio-net = {git = "https://github.com/os-module/simple-net"} netcore = {git = "https://github.com/os-module/simple-net"} +visionfive2-sd = { git = "https://github.com/os-module/visionfive2-sd.git"} +downcast-rs = { version = "1.2.0", default-features = false } -downcast-rs = { version = "1.2.0", default-features = false } \ No newline at end of file diff --git a/subsystems/drivers/src/block_device.rs b/subsystems/drivers/src/block_device.rs index 9a64881d..3c0e485f 100644 --- a/subsystems/drivers/src/block_device.rs +++ b/subsystems/drivers/src/block_device.rs @@ -14,12 +14,11 @@ use constants::AlienResult; use ksync::Mutex; use crate::hal::HalImpl; -use config::{FRAME_SIZE}; +use config::FRAME_SIZE; use device_interface::{BlockDevice, DeviceBase, LowBlockDevice}; use mem::{alloc_frames, free_frames}; use platform::config::BLOCK_CACHE_FRAMES; - const PAGE_CACHE_SIZE: usize = FRAME_SIZE; pub struct GenericBlockDevice { @@ -207,7 +206,7 @@ impl VirtIOBlkWrapper { Self { device: blk } } - pub fn from_mmio(mmio_transport: MmioTransport)->Self{ + pub fn from_mmio(mmio_transport: MmioTransport) -> Self { let blk = VirtIOBlk::::new(mmio_transport) .expect("failed to create blk driver"); Self { device: blk } @@ -261,3 +260,38 @@ impl MemoryFat32Img { Self { data } } } + + +pub use visionfive2_sd::Vf2SdDriver; +pub struct VF2SDDriver { + driver: Vf2SdDriver, +} + +impl VF2SDDriver { + pub fn new(vf2sd_driver: Vf2SdDriver) -> Self { + Self { + driver: vf2sd_driver, + } + } + pub fn init(&self) { + self.driver.init(); + } +} + +impl LowBlockDevice for VF2SDDriver { + fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> AlienResult<()> { + self.driver.read_block(block_id, buf); + Ok(()) + } + + fn write_block(&mut self, block_id: usize, buf: &[u8]) -> AlienResult<()> { + self.driver.write_block(block_id, buf); + Ok(()) + } + + fn capacity(&self) -> usize { + // unimplemented!() + // 32GB + 32 * 1024 * 1024 * 1024 / 512 + } +} \ No newline at end of file diff --git a/subsystems/drivers/src/input.rs b/subsystems/drivers/src/input.rs index dda4ac8b..f24a4fb3 100644 --- a/subsystems/drivers/src/input.rs +++ b/subsystems/drivers/src/input.rs @@ -8,8 +8,8 @@ use virtio_drivers::device::input::VirtIOInput; use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; use crate::hal::HalImpl; +use crate::{DriverTask, DRIVER_TASK}; use ksync::Mutex; -use crate::{DRIVER_TASK, DriverTask}; pub struct VirtIOInputDriver { inner: Mutex, @@ -68,7 +68,7 @@ impl InputDevice for VirtIOInputDriver { task.to_wait(); inner.wait_queue.push_back(task); } // drop the lock - // schedule(); + // schedule(); DRIVER_TASK.get().unwrap().suspend(); } } diff --git a/subsystems/drivers/src/lib.rs b/subsystems/drivers/src/lib.rs index ad3092e1..86d800c3 100644 --- a/subsystems/drivers/src/lib.rs +++ b/subsystems/drivers/src/lib.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::boxed::Box; use alloc::sync::Arc; -use downcast_rs::{DowncastSync, impl_downcast}; +use downcast_rs::{impl_downcast, DowncastSync}; use spin::Once; pub mod block_device; @@ -14,10 +14,7 @@ pub mod net; pub mod rtc; pub mod uart; - - - -pub trait DriverTask:Send+Sync+DowncastSync{ +pub trait DriverTask: Send + Sync + DowncastSync { fn to_wait(&self); fn to_wakeup(&self); fn have_signal(&self) -> bool; @@ -25,15 +22,14 @@ pub trait DriverTask:Send+Sync+DowncastSync{ impl_downcast!(sync DriverTask); -pub trait DriverWithTask:Send+Sync{ +pub trait DriverWithTask: Send + Sync { fn get_task(&self) -> Arc; - fn put_task(&self,task:Arc); + fn put_task(&self, task: Arc); fn suspend(&self); } +static DRIVER_TASK: Once> = Once::new(); -static DRIVER_TASK:Once> = Once::new(); - -pub fn register_task_func(task_func:Box){ - DRIVER_TASK.call_once(||task_func); -} \ No newline at end of file +pub fn register_task_func(task_func: Box) { + DRIVER_TASK.call_once(|| task_func); +} diff --git a/subsystems/drivers/src/net.rs b/subsystems/drivers/src/net.rs index 36f8af7e..68c4de4c 100644 --- a/subsystems/drivers/src/net.rs +++ b/subsystems/drivers/src/net.rs @@ -6,8 +6,8 @@ use timer::TimeSpec; use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; use virtio_net::VirtIONetDeviceWrapper; -pub use loopback::LoopbackDev; use crate::DRIVER_TASK; +pub use loopback::LoopbackDev; pub const NET_BUFFER_LEN: usize = 4096; pub const NET_QUEUE_SIZE: usize = 128; diff --git a/subsystems/drivers/src/rtc.rs b/subsystems/drivers/src/rtc.rs index d200e5c6..ba7d850d 100644 --- a/subsystems/drivers/src/rtc.rs +++ b/subsystems/drivers/src/rtc.rs @@ -1,8 +1,8 @@ use alloc::format; use alloc::string::String; -use log::trace; use constants::io::RtcTime; use device_interface::{DeviceBase, RtcDevice}; +use log::trace; use rtc::{LowRtcDevice, LowRtcDeviceExt}; type GFish = rtc::goldfish::GoldFishRtc; @@ -10,7 +10,7 @@ pub struct GoldFishRtc { gold_fish_rtc: GFish, } -impl GoldFishRtc{ +impl GoldFishRtc { pub fn read_time_u64(&self) -> u64 { self.gold_fish_rtc.read_time() } diff --git a/subsystems/drivers/src/uart.rs b/subsystems/drivers/src/uart.rs index 550a9e3d..27511770 100644 --- a/subsystems/drivers/src/uart.rs +++ b/subsystems/drivers/src/uart.rs @@ -1,11 +1,11 @@ pub use self::uart16550::Uart16550; pub use self::uart8250::Uart8250; +use crate::{DriverTask, DRIVER_TASK}; use alloc::boxed::Box; use alloc::collections::VecDeque; use alloc::sync::Arc; use device_interface::{DeviceBase, UartDevice}; use ksync::Mutex; -use crate::{DRIVER_TASK, DriverTask}; pub trait LowUartDriver: Send + Sync { fn _init(&mut self); diff --git a/dep/gmanager/Cargo.toml b/subsystems/gmanager/Cargo.toml similarity index 93% rename from dep/gmanager/Cargo.toml rename to subsystems/gmanager/Cargo.toml index adc2c57e..8cea643e 100644 --- a/dep/gmanager/Cargo.toml +++ b/subsystems/gmanager/Cargo.toml @@ -6,6 +6,3 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] - - -[features] \ No newline at end of file diff --git a/dep/gmanager/src/lib.rs b/subsystems/gmanager/src/lib.rs similarity index 91% rename from dep/gmanager/src/lib.rs rename to subsystems/gmanager/src/lib.rs index 5eb9a08b..028b23e9 100644 --- a/dep/gmanager/src/lib.rs +++ b/subsystems/gmanager/src/lib.rs @@ -63,10 +63,6 @@ impl MinimalManager { self.max } - /// get the data reference - pub fn data(&self) -> &Vec> { - &self.data - } /// insert a value pub fn insert(&mut self, val: T) -> Result { if self.usable == self.max { @@ -83,7 +79,7 @@ impl MinimalManager { } /// find the next usable index - pub fn find_next_index(&self) -> Option { + fn find_next_index(&self) -> Option { let data = self .data .iter() @@ -122,16 +118,6 @@ impl MinimalManager { Ok(val.clone()) } - #[allow(unused)] - /// check the index is usable - pub fn is_usable(&self, index: usize) -> Result { - if index > self.max { - return Err(ManagerError::IndexOver); - } - let val = self.data.get(index).unwrap(); - Ok(val.is_none()) - } - /// User should ensure that the index is valid pub fn insert_with_index(&mut self, index: usize, val: T) -> Result<(), ManagerError> { if index >= self.max { diff --git a/subsystems/knet/Cargo.toml b/subsystems/knet/Cargo.toml new file mode 100644 index 00000000..45117675 --- /dev/null +++ b/subsystems/knet/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "knet" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +constants = { path = "../constants" } +ksync = { path = "../ksync" } +netcore = {git = "https://github.com/os-module/simple-net"} +vfs = { path = "../vfs" } +vfscore = { git = "https://github.com/os-module/rvfs.git", features = [ + "linux_error", +] } + +log = "0" \ No newline at end of file diff --git a/kkernel/src/net/addr.rs b/subsystems/knet/src/addr.rs similarity index 63% rename from kkernel/src/net/addr.rs rename to subsystems/knet/src/addr.rs index 91afe025..9a118fc7 100644 --- a/kkernel/src/net/addr.rs +++ b/subsystems/knet/src/addr.rs @@ -10,14 +10,10 @@ //! Alien 将会首先对传入的套接字的协议族进行解析,然后根据不同的地址协议族将其解析成 [`SocketAddrExt`] 结构, //! 向下层的具体套接字中传递相应地址时,传递的也是 [`SocketAddrExt`] 结构。 //! -use alloc::string::{String, ToString}; -use alloc::vec; -use core::fmt::Debug; -use core::net::{IpAddr, Ipv4Addr, SocketAddr}; - -use crate::task::current_task; +use alloc::string::String; use constants::net::Domain; -use constants::{AlienResult,LinuxErrno}; +use core::fmt::Debug; +use core::net::{IpAddr, SocketAddr}; /// 用于存储套接字通信地址的结构,分为本地路径地址和网络套接字地址。 #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] @@ -86,40 +82,3 @@ impl From for RawIpV4Addr { } } } - -/// 地址解析,将根据`family_user_addr`的[`Domain`]类型分类进行解析。 -/// -/// 对于`AF_INET`将解析成SocketAddrExt::SocketAddr(SocketAddr), -/// 对于`AF_UNIX`将解析成ocketAddrExt::LocalPath(String),详情可见[`SocketAddrExt`]。 -pub fn socket_addr_resolution(family_user_addr: usize, len: usize) -> AlienResult { - let task = current_task().unwrap(); - let family = task - .access_inner() - .transfer_raw_ptr(family_user_addr as *const u16); - let domain = Domain::try_from(*family as usize).map_err(|_| LinuxErrno::EINVAL)?; - match domain { - Domain::AF_INET => { - let mut ip_addr = RawIpV4Addr::default(); - task.access_inner() - .copy_from_user(family_user_addr as *const RawIpV4Addr, &mut ip_addr); - let ip = u32::from_be_bytes(ip_addr.addr.to_le_bytes()); - let ipv4_addr = IpAddr::V4(Ipv4Addr::from(ip)); - let port = u16::from_be(ip_addr.port); - Ok(SocketAddrExt::SocketAddr(SocketAddr::new( - ipv4_addr.into(), - port, - ))) - } - Domain::AF_UNIX => { - // local path - let mut buf = vec![0u8; len]; - task.access_inner().copy_from_user_buffer( - family_user_addr as *const u8, - buf.as_mut_ptr(), - len, - ); - let path = String::from_utf8_lossy(&buf[2..len - 2]).to_string(); - Ok(SocketAddrExt::LocalPath(path)) - } - } -} diff --git a/subsystems/knet/src/lib.rs b/subsystems/knet/src/lib.rs new file mode 100644 index 00000000..1a5f6af7 --- /dev/null +++ b/subsystems/knet/src/lib.rs @@ -0,0 +1,11 @@ +#![no_std] +#![feature(ip_in_core)] + +extern crate alloc; +#[macro_use] +extern crate log; + +pub mod addr; +pub mod port; +pub mod socket; +pub mod unix; diff --git a/kernel/src/net/port.rs b/subsystems/knet/src/port.rs similarity index 100% rename from kernel/src/net/port.rs rename to subsystems/knet/src/port.rs diff --git a/kkernel/src/net/socket.rs b/subsystems/knet/src/socket.rs similarity index 98% rename from kkernel/src/net/socket.rs rename to subsystems/knet/src/socket.rs index f0951bf8..0b261a4d 100644 --- a/kkernel/src/net/socket.rs +++ b/subsystems/knet/src/socket.rs @@ -7,23 +7,21 @@ //! 的规定,我们只需为套接字文件规定好 [`socket_file_release`]、[`socket_file_write`]、[`socket_file_read`]、 //! [`socket_ready_to_read`]、[`socket_ready_to_write`] 几个操作函数,即可快速的创建套接字文件,并将其放入进程的文件描述 //! 符表中,具体有关套接字文件的创建,可见 [`SocketData::new`] 的实现。 -use super::ShutdownFlag; -use crate::fs::file::File; -use crate::net::addr::SocketAddrExt; -use crate::net::port::neterror2alien; -use crate::net::unix::UnixSocket; -use constants::AlienResult; -use ksync::{Mutex, MutexGuard}; -// use crate::task::do_suspend; +use crate::addr::SocketAddrExt; +use crate::port::neterror2alien; +use crate::unix::UnixSocket; use alloc::boxed::Box; use alloc::sync::Arc; use constants::io::{OpenFlags, PollEvents, SeekFrom}; -use constants::net::{Domain, SocketType}; +use constants::net::{Domain, ShutdownFlag, SocketType}; +use constants::AlienResult; use constants::LinuxErrno; use core::fmt::{Debug, Formatter}; use core::net::SocketAddr; +use ksync::{Mutex, MutexGuard}; use netcore::tcp::TcpSocket; use netcore::udp::UdpSocket; +use vfs::kfile::File; use vfscore::dentry::VfsDentry; use vfscore::inode::VfsInode; use vfscore::utils::VfsFileStat; diff --git a/kkernel/src/net/unix.rs b/subsystems/knet/src/unix.rs similarity index 96% rename from kkernel/src/net/unix.rs rename to subsystems/knet/src/unix.rs index 5ff469d9..e9594c4e 100644 --- a/kkernel/src/net/unix.rs +++ b/subsystems/knet/src/unix.rs @@ -2,9 +2,8 @@ use alloc::string::String; use alloc::sync::Arc; use constants::LinuxErrno; - -use crate::fs::file::File; use ksync::Mutex; +use vfs::kfile::File; /// Unix 协议族下的套接字结构 #[allow(unused)] diff --git a/subsystems/mem/src/frame.rs b/subsystems/mem/src/frame.rs index fdc24f3f..378a86a0 100644 --- a/subsystems/mem/src/frame.rs +++ b/subsystems/mem/src/frame.rs @@ -1,14 +1,14 @@ +use crate::manager::FRAME_REF_MANAGER; use alloc::format; +use config::{FRAME_BITS, FRAME_SIZE}; use core::mem::forget; use core::ops::{Deref, DerefMut}; +use ksync::Mutex; use log::trace; use page_table::addr::{PhysAddr, VirtAddr}; -use config::{FRAME_BITS, FRAME_SIZE}; -use ksync::Mutex; use page_table::table::PagingIf; use pager::{PageAllocator, PageAllocatorExt}; use platform::println; -use crate::manager::FRAME_REF_MANAGER; #[cfg(feature = "pager_bitmap")] pub static FRAME_ALLOCATOR: Mutex> = Mutex::new(pager::Bitmap::new()); @@ -50,7 +50,6 @@ pub fn free_frames(addr: *mut u8, num: usize) { .expect(format!("free frame start:{:#x},num:{} failed", start, num).as_str()); } - #[derive(Debug)] pub struct FrameTracker { start: usize, @@ -58,12 +57,12 @@ pub struct FrameTracker { } impl FrameTracker { - pub fn new(start: usize, size:usize) -> Self { - Self { start ,size} + pub fn new(start: usize, size: usize) -> Self { + Self { start, size } } - pub fn from_addr(addr: usize,size:usize) -> Self { + pub fn from_addr(addr: usize, size: usize) -> Self { assert_eq!(addr % FRAME_SIZE, 0); - Self::new(addr >> FRAME_BITS,size) + Self::new(addr >> FRAME_BITS, size) } pub fn start(&self) -> usize { self.start << FRAME_BITS @@ -90,28 +89,28 @@ impl Deref for FrameTracker { type Target = [u8]; fn deref(&self) -> &Self::Target { - unsafe { core::slice::from_raw_parts(self.start() as *const u8, FRAME_SIZE*self.size) } + unsafe { core::slice::from_raw_parts(self.start() as *const u8, FRAME_SIZE * self.size) } } } impl DerefMut for FrameTracker { fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { core::slice::from_raw_parts_mut(self.start() as *mut u8, FRAME_SIZE*self.size) } + unsafe { core::slice::from_raw_parts_mut(self.start() as *mut u8, FRAME_SIZE * self.size) } } } - pub fn alloc_frame_trackers(count: usize) -> FrameTracker { - let frame = FRAME_ALLOCATOR.lock().alloc_pages(count, FRAME_SIZE) + let frame = FRAME_ALLOCATOR + .lock() + .alloc_pages(count, FRAME_SIZE) .expect(format!("alloc {} frame failed", count).as_str()); trace!("alloc frame [{}] start page: {:#x}", count, frame); for i in 0..count { let refs = FRAME_REF_MANAGER.lock().add_ref(frame + i); assert_eq!(refs, 1) } - FrameTracker::new(frame,count) + FrameTracker::new(frame, count) } - pub struct VmmPageAllocator; impl PagingIf for VmmPageAllocator { @@ -123,7 +122,7 @@ impl PagingIf for VmmPageAllocator { } fn dealloc_frame(paddr: PhysAddr) { - FrameTracker::from_addr(paddr.as_usize(),1); + FrameTracker::from_addr(paddr.as_usize(), 1); } fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { diff --git a/subsystems/mem/src/heap.rs b/subsystems/mem/src/heap.rs index 648f52d3..bb004252 100644 --- a/subsystems/mem/src/heap.rs +++ b/subsystems/mem/src/heap.rs @@ -1,73 +1,73 @@ -use crate::frame::{alloc_frames, free_frames}; -#[cfg(feature = "buddy")] -use buddy_system_allocator::LockedHeap; -use config::FRAME_SIZE; -use core::alloc::GlobalAlloc; -use ksync::Mutex; -use log::trace; -#[cfg(feature = "rslab")] -use rslab::{init_slab_system, SlabAllocator}; -#[cfg(feature = "talloc")] -use talc::{Talc, Talck}; - -pub struct HeapAllocator { - #[cfg(feature = "talloc")] - allocator: Mutex, - #[cfg(feature = "buddy")] - allocator: Mutex>, - #[cfg(feature = "slab")] - allocator: Mutex, -} - -unsafe impl GlobalAlloc for HeapAllocator { - unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { - if layout.size() >= 5 * 1024 * 1024 { - let need_page = (layout.size() + FRAME_SIZE - 1) / FRAME_SIZE; - trace!("alloc big page: {:#x}", layout.size()); - alloc_frames(need_page) - } else { - self.allocator.lock().alloc(layout) - } - } - unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { - if layout.size() >= 5 * 1024 * 1024 { - let need_page = (layout.size() + FRAME_SIZE - 1) / FRAME_SIZE; - trace!("free big page: {:#x}", layout.size()); - free_frames(ptr, need_page); - } else { - self.allocator.lock().dealloc(ptr, layout); - } - } -} - -impl HeapAllocator { - pub const fn new() -> Self { - Self { - #[cfg(feature = "talloc")] - allocator: Mutex::new(Talc::new().spin_lock()), - #[cfg(feature = "buddy")] - allocator: Mutex::new(LockedHeap::<32>::new()), - #[cfg(feature = "slab")] - allocator: Mutex::new(SlabAllocator), - } - } - pub fn init(&self, heap: &mut [u8]) { - #[cfg(feature = "talloc")] - unsafe { - self.allocator.lock().talc().init(heap.into()) - } - #[cfg(feature = "buddy")] - unsafe { - self.allocator - .lock() - .lock() - .init(heap.as_mut_ptr() as usize, heap.len()) - } - #[cfg(feature = "slab")] - unsafe { - init_slab_system(FRAME_SIZE, 64); - } - #[cfg(any(feature = "talc",feature = "buddy"))] - println!("Kernel Heap size: {:#x}MB", heap.len() / 1024 / 1024); - } -} +use crate::frame::{alloc_frames, free_frames}; +#[cfg(feature = "buddy")] +use buddy_system_allocator::LockedHeap; +use config::FRAME_SIZE; +use core::alloc::GlobalAlloc; +use ksync::Mutex; +use log::trace; +#[cfg(feature = "rslab")] +use rslab::{init_slab_system, SlabAllocator}; +#[cfg(feature = "talloc")] +use talc::{Talc, Talck}; + +pub struct HeapAllocator { + #[cfg(feature = "talloc")] + allocator: Mutex, + #[cfg(feature = "buddy")] + allocator: Mutex>, + #[cfg(feature = "slab")] + allocator: Mutex, +} + +unsafe impl GlobalAlloc for HeapAllocator { + unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { + if layout.size() >= 5 * 1024 * 1024 { + let need_page = (layout.size() + FRAME_SIZE - 1) / FRAME_SIZE; + trace!("alloc big page: {:#x}", layout.size()); + alloc_frames(need_page) + } else { + self.allocator.lock().alloc(layout) + } + } + unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { + if layout.size() >= 5 * 1024 * 1024 { + let need_page = (layout.size() + FRAME_SIZE - 1) / FRAME_SIZE; + trace!("free big page: {:#x}", layout.size()); + free_frames(ptr, need_page); + } else { + self.allocator.lock().dealloc(ptr, layout); + } + } +} + +impl HeapAllocator { + pub const fn new() -> Self { + Self { + #[cfg(feature = "talloc")] + allocator: Mutex::new(Talc::new().spin_lock()), + #[cfg(feature = "buddy")] + allocator: Mutex::new(LockedHeap::<32>::new()), + #[cfg(feature = "slab")] + allocator: Mutex::new(SlabAllocator), + } + } + pub fn init(&self, heap: &mut [u8]) { + #[cfg(feature = "talloc")] + unsafe { + self.allocator.lock().talc().init(heap.into()) + } + #[cfg(feature = "buddy")] + unsafe { + self.allocator + .lock() + .lock() + .init(heap.as_mut_ptr() as usize, heap.len()) + } + #[cfg(feature = "slab")] + unsafe { + init_slab_system(FRAME_SIZE, 64); + } + #[cfg(any(feature = "talc", feature = "buddy"))] + println!("Kernel Heap size: {:#x}MB", heap.len() / 1024 / 1024); + } +} diff --git a/subsystems/mem/src/lib.rs b/subsystems/mem/src/lib.rs index bfb338bf..9d665c89 100644 --- a/subsystems/mem/src/lib.rs +++ b/subsystems/mem/src/lib.rs @@ -4,17 +4,17 @@ extern crate alloc; #[macro_use] extern crate platform; use arch::activate_paging_mode; -use config::{FRAME_BITS}; +use config::FRAME_BITS; use heap::HeapAllocator; use platform::config::HEAP_SIZE; mod frame; mod heap; -mod vmm; mod manager; +mod vmm; -pub use frame::{alloc_frames, free_frames,FrameTracker,VmmPageAllocator,alloc_frame_trackers}; +pub use frame::{alloc_frame_trackers, alloc_frames, free_frames, FrameTracker, VmmPageAllocator}; -pub use vmm::{map_region_to_kernel,query_kernel_space,kernel_pgd,kernel_satp}; +pub use vmm::{kernel_pgd, kernel_satp, map_region_to_kernel, query_kernel_space}; pub use manager::FRAME_REF_MANAGER; #[global_allocator] @@ -23,11 +23,11 @@ static HEAP_ALLOCATOR: HeapAllocator = HeapAllocator::new(); #[cfg(any(feature = "talloc", feature = "buddy"))] static mut KERNEL_HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE]; -extern "C"{ +extern "C" { fn ekernel(); } -pub fn init_memory_system( memory_end: usize, is_first_cpu: bool) { +pub fn init_memory_system(memory_end: usize, is_first_cpu: bool) { if is_first_cpu { frame::init_frame_allocator(ekernel as usize, memory_end); println!("Frame allocator init success"); diff --git a/subsystems/mem/src/manager.rs b/subsystems/mem/src/manager.rs index b27250b1..31b13124 100644 --- a/subsystems/mem/src/manager.rs +++ b/subsystems/mem/src/manager.rs @@ -1,54 +1,52 @@ -use alloc::collections::BTreeMap; -use log::trace; -use pager::PageAllocator; -use spin::Lazy; -use ksync::Mutex; -use crate::frame::FRAME_ALLOCATOR; - - -pub static FRAME_REF_MANAGER: Lazy> = - Lazy::new(|| Mutex::new(FrameRefManager::new())); - - -#[derive(Debug)] -pub struct FrameRefManager { - record: BTreeMap, -} - -impl FrameRefManager { - pub fn new() -> Self { - Self { - record: BTreeMap::new(), - } - } - pub fn add_ref(&mut self, id: usize) -> usize { - if let Some(count) = self.record.get_mut(&id) { - *count += 1; - *count - } else { - self.record.insert(id, 1); - 1 - } - } - pub fn dec_ref(&mut self, id: usize) -> Option { - if let Some(count) = self.record.get_mut(&id) { - *count -= 1; - let now_count = *count; - if *count == 0 { - self.record.remove(&id); - trace!("free frame:{:#x}", id); - FRAME_ALLOCATOR.lock().free(id, 0).unwrap(); - } - return Some(now_count); - } else { - panic!("dec page {:#x?} ref error", id); - } - } - pub fn get_ref(&self, id: usize) -> usize { - if let Some(count) = self.record.get(&id) { - *count - } else { - panic!("get {} ref error", id); - } - } -} +use crate::frame::FRAME_ALLOCATOR; +use alloc::collections::BTreeMap; +use ksync::Mutex; +use log::trace; +use pager::PageAllocator; +use spin::Lazy; + +pub static FRAME_REF_MANAGER: Lazy> = + Lazy::new(|| Mutex::new(FrameRefManager::new())); + +#[derive(Debug)] +pub struct FrameRefManager { + record: BTreeMap, +} + +impl FrameRefManager { + pub fn new() -> Self { + Self { + record: BTreeMap::new(), + } + } + pub fn add_ref(&mut self, id: usize) -> usize { + if let Some(count) = self.record.get_mut(&id) { + *count += 1; + *count + } else { + self.record.insert(id, 1); + 1 + } + } + pub fn dec_ref(&mut self, id: usize) -> Option { + if let Some(count) = self.record.get_mut(&id) { + *count -= 1; + let now_count = *count; + if *count == 0 { + self.record.remove(&id); + trace!("free frame:{:#x}", id); + FRAME_ALLOCATOR.lock().free(id, 0).unwrap(); + } + return Some(now_count); + } else { + panic!("dec page {:#x?} ref error", id); + } + } + pub fn get_ref(&self, id: usize) -> usize { + if let Some(count) = self.record.get(&id) { + *count + } else { + panic!("get {} ref error", id); + } + } +} diff --git a/subsystems/mem/src/vmm.rs b/subsystems/mem/src/vmm.rs index 21a65be5..b36977f3 100644 --- a/subsystems/mem/src/vmm.rs +++ b/subsystems/mem/src/vmm.rs @@ -1,15 +1,13 @@ +use crate::frame::VmmPageAllocator; use alloc::sync::Arc; -use core::sync::atomic::AtomicUsize; +use config::{FRAME_BITS, FRAME_SIZE, TRAMPOLINE}; +use ksync::RwLock; use page_table::addr::{PhysAddr, VirtAddr}; use page_table::pte::MappingFlags; use page_table::table::Sv39PageTable; -use spin::Lazy; -use config::{FRAME_BITS, FRAME_SIZE, TRAMPOLINE}; -use ksync::RwLock; use platform::config::MMIO; -use crate::frame::VmmPageAllocator; +use spin::Lazy; -#[allow(unused)] extern "C" { fn stext(); fn srodata(); @@ -54,7 +52,6 @@ fn kernel_info(memory_end: usize) { ); } - pub static KERNEL_SPACE: Lazy>>> = Lazy::new(|| { Arc::new(RwLock::new( Sv39PageTable::::try_new().unwrap(), @@ -132,7 +129,7 @@ pub fn build_kernel_address_space(memory_end: usize) { } } -static KERNEL_MAP_MAX: AtomicUsize = AtomicUsize::new(0); +// static KERNEL_MAP_MAX: AtomicUsize = AtomicUsize::new(0); pub fn kernel_pgd() -> usize { KERNEL_SPACE.read().root_paddr().as_usize() } @@ -141,12 +138,12 @@ pub fn kernel_satp() -> usize { 8usize << 60 | (KERNEL_SPACE.read().root_paddr().as_usize() >> FRAME_BITS) } -pub fn alloc_kernel_free_region(size: usize) -> usize { - assert!(size > 0 && size % FRAME_SIZE == 0); - KERNEL_MAP_MAX.fetch_add(size, core::sync::atomic::Ordering::SeqCst) -} +// pub fn alloc_kernel_free_region(size: usize) -> usize { +// assert!(size > 0 && size % FRAME_SIZE == 0); +// KERNEL_MAP_MAX.fetch_add(size, core::sync::atomic::Ordering::SeqCst) +// } -pub fn map_region_to_kernel(addr: usize, size: usize, flags: MappingFlags){ +pub fn map_region_to_kernel(addr: usize, size: usize, flags: MappingFlags) { let mut kernel_space = KERNEL_SPACE.write(); kernel_space .map_region( diff --git a/subsystems/platform/Cargo.toml b/subsystems/platform/Cargo.toml index d7e4543a..6bc7c2bd 100644 --- a/subsystems/platform/Cargo.toml +++ b/subsystems/platform/Cargo.toml @@ -12,15 +12,13 @@ config = { path = "../config" } ksync = { path = "../ksync" } spin = "0" - preprint = "0.1.0" -basemachine = { path = "../../dep/basemachine" } +fdt = { git = "https://github.com/repnop/fdt" } [features] -default = ["qemu_riscv"] +default = [] qemu_riscv = [] vf2 = [] hifive = [] - smp = [] \ No newline at end of file diff --git a/dep/basemachine/src/lib.rs b/subsystems/platform/src/basic.rs similarity index 95% rename from dep/basemachine/src/lib.rs rename to subsystems/platform/src/basic.rs index 8557b29e..28583c84 100644 --- a/dep/basemachine/src/lib.rs +++ b/subsystems/platform/src/basic.rs @@ -1,108 +1,104 @@ -//! This crate provides a way to get machine information from a device-tree. -//! -//! # Example -//! ``` -//! use basemachine::machine_info_from_dtb; -//! let machine_info = machine_info_from_dtb(0x80700000); -//! ``` -#![no_std] -#![deny(missing_docs)] -use core::cmp::min; -use core::fmt::Debug; -use core::ops::Range; - -use fdt::Fdt; - -const MEMORY: &str = "memory"; -const PLIC: &str = "plic"; -const CLINT: &str = "clint"; - -/// Machine basic information -#[derive(Clone)] -pub struct MachineInfo { - /// Machine model - pub model: [u8; 32], - /// Number of CPUs - pub smp: usize, - /// Memory range - pub memory: Range, - /// PLIC information - pub plic: Range, - /// CLINT information - pub clint: Range, -} - -impl Debug for MachineInfo { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let index = self.model.iter().position(|&x| x == 0).unwrap_or(32); - let model = core::str::from_utf8(&self.model[..index]).unwrap(); - write!( - f, - "This is a device tree representation of a {} machine\n", - model - ) - .unwrap(); - write!(f, "SMP: {}\n", self.smp).unwrap(); - write!( - f, - "Memory: {:#x}..{:#x}\n", - self.memory.start, self.memory.end - ) - .unwrap(); - write!(f, "PLIC: {:#x}..{:#x}\n", self.plic.start, self.plic.end).unwrap(); - write!(f, "CLINT: {:#x}..{:#x}", self.clint.start, self.clint.end).unwrap(); - Ok(()) - } -} - - -/// Get machine information from a device-tree -pub fn machine_info_from_dtb(ptr: usize) -> MachineInfo { - let fdt = unsafe { Fdt::from_ptr(ptr as *const u8).unwrap() }; - walk_dt(fdt) -} - -// Walk the device-tree and get machine information -fn walk_dt(fdt: Fdt) -> MachineInfo { - let mut machine = MachineInfo { - model: [0; 32], - smp: 0, - memory: 0..0, - plic: 0..0, - clint: 0..0, - }; - let x = fdt.root(); - machine.smp = fdt.cpus().count(); - let model = x.model().as_bytes(); - let len = min(model.len(), machine.model.len()); - machine.model[0..len].copy_from_slice(&model[..len]); - - for node in fdt.all_nodes() { - if node.name.starts_with(MEMORY) { - let reg = node.reg().unwrap(); - reg.for_each(|x| { - machine.memory = Range { - start: x.starting_address as usize, - end: x.starting_address as usize + x.size.unwrap(), - } - }) - } else if node.name.starts_with(PLIC) { - let reg = node.reg().unwrap(); - reg.for_each(|x| { - machine.plic = Range { - start: x.starting_address as usize, - end: x.starting_address as usize + x.size.unwrap(), - } - }) - } else if node.name.starts_with(CLINT) { - let reg = node.reg().unwrap(); - reg.for_each(|x| { - machine.clint = Range { - start: x.starting_address as usize, - end: x.starting_address as usize + x.size.unwrap(), - } - }) - } - } - machine -} +//! This crate provides a way to get machine information from a device-tree. +//! +//! # Example +//! ``` +//! let machine_info = machine_info_from_dtb(0x80700000); +//! ``` +use core::cmp::min; +use core::fmt::Debug; +use core::ops::Range; + +use fdt::Fdt; + +const MEMORY: &str = "memory"; +const PLIC: &str = "plic"; +const CLINT: &str = "clint"; + +/// Machine basic information +#[derive(Clone)] +pub struct MachineInfo { + /// Machine model + pub model: [u8; 32], + /// Number of CPUs + pub smp: usize, + /// Memory range + pub memory: Range, + /// PLIC information + pub plic: Range, + /// CLINT information + pub clint: Range, +} + +impl Debug for MachineInfo { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let index = self.model.iter().position(|&x| x == 0).unwrap_or(32); + let model = core::str::from_utf8(&self.model[..index]).unwrap(); + write!( + f, + "This is a device tree representation of a {} machine\n", + model + ) + .unwrap(); + write!(f, "SMP: {}\n", self.smp).unwrap(); + write!( + f, + "Memory: {:#x}..{:#x}\n", + self.memory.start, self.memory.end + ) + .unwrap(); + write!(f, "PLIC: {:#x}..{:#x}\n", self.plic.start, self.plic.end).unwrap(); + write!(f, "CLINT: {:#x}..{:#x}", self.clint.start, self.clint.end).unwrap(); + Ok(()) + } +} + +/// Get machine information from a device-tree +pub fn machine_info_from_dtb(ptr: usize) -> MachineInfo { + let fdt = unsafe { Fdt::from_ptr(ptr as *const u8).unwrap() }; + walk_dt(fdt) +} + +// Walk the device-tree and get machine information +fn walk_dt(fdt: Fdt) -> MachineInfo { + let mut machine = MachineInfo { + model: [0; 32], + smp: 0, + memory: 0..0, + plic: 0..0, + clint: 0..0, + }; + let x = fdt.root(); + machine.smp = fdt.cpus().count(); + let model = x.model().as_bytes(); + let len = min(model.len(), machine.model.len()); + machine.model[0..len].copy_from_slice(&model[..len]); + + for node in fdt.all_nodes() { + if node.name.starts_with(MEMORY) { + let reg = node.reg().unwrap(); + reg.for_each(|x| { + machine.memory = Range { + start: x.starting_address as usize, + end: x.starting_address as usize + x.size.unwrap(), + } + }) + } else if node.name.starts_with(PLIC) { + let reg = node.reg().unwrap(); + reg.for_each(|x| { + machine.plic = Range { + start: x.starting_address as usize, + end: x.starting_address as usize + x.size.unwrap(), + } + }) + } else if node.name.starts_with(CLINT) { + let reg = node.reg().unwrap(); + reg.for_each(|x| { + machine.clint = Range { + start: x.starting_address as usize, + end: x.starting_address as usize + x.size.unwrap(), + } + }) + } + } + machine +} diff --git a/subsystems/platform/src/common_riscv/boot.rs b/subsystems/platform/src/common_riscv/boot.rs index e5675c71..49425086 100644 --- a/subsystems/platform/src/common_riscv/boot.rs +++ b/subsystems/platform/src/common_riscv/boot.rs @@ -1,70 +1,69 @@ -use config::{CPU_NUM, STACK_SIZE, STACK_SIZE_BITS}; -use core::arch::asm; - -#[link_section = ".bss.stack"] -static mut STACK: [u8; STACK_SIZE * CPU_NUM] = [0; STACK_SIZE * CPU_NUM]; - -/// 内核入口 -/// -/// 用于初始化内核的栈空间,并关闭中断 -#[naked] -#[no_mangle] -#[link_section = ".text.entry"] -extern "C" fn _start() { - unsafe { - asm!("\ - mv tp, a0 - mv gp, a1 - add t0, a0, 1 - slli t0, t0, {stack_size_bits} - la sp, {boot_stack} - add sp, sp, t0 - call clear_bss - mv a0, tp - mv a1, gp - call {platform_init} - ", - stack_size_bits = const STACK_SIZE_BITS, - boot_stack = sym STACK, - platform_init = sym crate::platform_init, - options(noreturn) - ); - } -} - -#[naked] -#[no_mangle] -extern "C" fn _start_secondary() { - unsafe { - asm!("\ - mv tp, a0 - mv gp, a1 - add t0, a0, 1 - slli t0, t0, {stack_size_bits} - la sp, {boot_stack} - add sp, sp, t0 - mv a0, tp - mv a1, gp - call main - ", - stack_size_bits = const STACK_SIZE_BITS, - boot_stack = sym STACK, - options(noreturn) - ); - } -} - - -extern "C" { - fn sbss(); - fn ebss(); -} - -/// 清空.bss段 -#[no_mangle] -fn clear_bss() { - unsafe { - core::slice::from_raw_parts_mut(sbss as usize as *mut u8, ebss as usize - sbss as usize) - .fill(0); - } -} +use config::{CPU_NUM, STACK_SIZE, STACK_SIZE_BITS}; +use core::arch::asm; + +#[link_section = ".bss.stack"] +static mut STACK: [u8; STACK_SIZE * CPU_NUM] = [0; STACK_SIZE * CPU_NUM]; + +/// 内核入口 +/// +/// 用于初始化内核的栈空间,并关闭中断 +#[naked] +#[no_mangle] +#[link_section = ".text.entry"] +extern "C" fn _start() { + unsafe { + asm!("\ + mv tp, a0 + mv gp, a1 + add t0, a0, 1 + slli t0, t0, {stack_size_bits} + la sp, {boot_stack} + add sp, sp, t0 + call clear_bss + mv a0, tp + mv a1, gp + call {platform_init} + ", + stack_size_bits = const STACK_SIZE_BITS, + boot_stack = sym STACK, + platform_init = sym crate::platform_init, + options(noreturn) + ); + } +} + +#[naked] +#[no_mangle] +extern "C" fn _start_secondary() { + unsafe { + asm!("\ + mv tp, a0 + mv gp, a1 + add t0, a0, 1 + slli t0, t0, {stack_size_bits} + la sp, {boot_stack} + add sp, sp, t0 + mv a0, tp + mv a1, gp + call main + ", + stack_size_bits = const STACK_SIZE_BITS, + boot_stack = sym STACK, + options(noreturn) + ); + } +} + +extern "C" { + fn sbss(); + fn ebss(); +} + +/// 清空.bss段 +#[no_mangle] +fn clear_bss() { + unsafe { + core::slice::from_raw_parts_mut(sbss as usize as *mut u8, ebss as usize - sbss as usize) + .fill(0); + } +} diff --git a/subsystems/platform/src/console.rs b/subsystems/platform/src/console.rs index 5bce7a7c..22e491c0 100644 --- a/subsystems/platform/src/console.rs +++ b/subsystems/platform/src/console.rs @@ -1,6 +1,6 @@ use core::fmt::{Arguments, Result, Write}; -use preprint::Print; use ksync::Mutex; +use preprint::Print; /// 系统启动初期使用的输出函数 #[macro_export] macro_rules! print { @@ -47,7 +47,6 @@ pub fn console_write(s: &str) { Stdout.write_str(s).unwrap(); } - pub struct PrePrint; impl Print for PrePrint { @@ -61,4 +60,4 @@ impl Write for PrePrint { print!("{}", s); Ok(()) } -} \ No newline at end of file +} diff --git a/subsystems/platform/src/hifive_riscv/config.rs b/subsystems/platform/src/hifive_riscv/config.rs index c3ae7ac9..5b99f7a2 100644 --- a/subsystems/platform/src/hifive_riscv/config.rs +++ b/subsystems/platform/src/hifive_riscv/config.rs @@ -1,8 +1,7 @@ -pub const CLOCK_FREQ: usize = 100_0000; -pub const BLOCK_CACHE_FRAMES: usize = 1024 * 4 * 4; -pub const HEAP_SIZE: usize = 0x40_00000; //64M - - -pub const MMIO: &[(usize, usize)] = &[ - (0xc000000, 0x4000000), //PLIC -]; \ No newline at end of file +pub const CLOCK_FREQ: usize = 100_0000; +pub const BLOCK_CACHE_FRAMES: usize = 1024 * 4 * 4; +pub const HEAP_SIZE: usize = 0x40_00000; //64M + +pub const MMIO: &[(usize, usize)] = &[ + (0xc000000, 0x4000000), //PLIC +]; diff --git a/subsystems/platform/src/hifive_riscv/mod.rs b/subsystems/platform/src/hifive_riscv/mod.rs index 54676c64..ea0f0a11 100644 --- a/subsystems/platform/src/hifive_riscv/mod.rs +++ b/subsystems/platform/src/hifive_riscv/mod.rs @@ -2,9 +2,7 @@ pub mod config; use spin::Once; -const FDT: &[u8] = include_bytes!( - "../../../../tools/hifive-unmatched-a00.dtb" -); +const FDT: &[u8] = include_bytes!("../../../../tools/hifive-unmatched-a00.dtb"); pub static DTB: Once = Once::new(); diff --git a/subsystems/platform/src/lib.rs b/subsystems/platform/src/lib.rs index 6201052a..f46601aa 100644 --- a/subsystems/platform/src/lib.rs +++ b/subsystems/platform/src/lib.rs @@ -9,16 +9,16 @@ mod common_riscv; #[cfg(feature = "hifive")] mod hifive_riscv; - -use spin::Once; -pub use basemachine::MachineInfo as PlatformInfo; use ::config::CPU_NUM; +pub use basic::MachineInfo as PlatformInfo; +use spin::Once; +mod basic; +pub mod logging; #[cfg(feature = "qemu_riscv")] mod qemu_riscv; #[cfg(feature = "vf2")] mod starfive2_riscv; -pub mod logging; #[cfg(feature = "qemu_riscv")] use qemu_riscv::console_putchar; @@ -33,40 +33,35 @@ pub use starfive2_riscv::{config, set_timer, system_shutdown}; #[cfg(feature = "hifive")] use hifive_riscv::console_putchar; -#[cfg(feature = "hifive")] -pub use hifive_riscv::{config, set_timer, system_shutdown}; use crate::common_riscv::sbi::hart_start; use crate::console::PrePrint; - - +#[cfg(feature = "hifive")] +pub use hifive_riscv::{config, set_timer, system_shutdown}; #[no_mangle] -pub fn platform_init(hart_id:usize,dtb: usize) { - println!("{}",::config::FLAG); +pub fn platform_init(hart_id: usize, dtb: usize) { + println!("{}", ::config::FLAG); #[cfg(feature = "hifive")] hifive_riscv::init_dtb(Some(dtb)); #[cfg(feature = "vf2")] starfive2_riscv::init_dtb(Some(dtb)); #[cfg(feature = "qemu_riscv")] qemu_riscv::init_dtb(Some(dtb)); - let machine_info = basemachine::machine_info_from_dtb(platform_dtb_ptr()); + let machine_info = basic::machine_info_from_dtb(platform_dtb_ptr()); MACHINE_INFO.call_once(|| machine_info); logging::init_logger(); preprint::init_print(&PrePrint); #[cfg(feature = "smp")] init_other_hart(hart_id); - unsafe{ - main(hart_id) - } + unsafe { main(hart_id) } } - /// 唤醒其它核 /// /// 对于qemu来说,只需要工具所有的核都是一样的,因此从严号核开始唤醒。 /// 对于visionfive2/unmatched 来说,0号核只有M态,因此不进行唤醒 fn init_other_hart(hart_id: usize) { - let start_hart = if cfg!(any(feature = "vf2", feature = "hifive")){ + let start_hart = if cfg!(any(feature = "vf2", feature = "hifive")) { 1 } else { 0 @@ -79,13 +74,11 @@ fn init_other_hart(hart_id: usize) { } } - extern "C" { fn main(hart_id: usize); fn _start_secondary(); } - pub fn platform_dtb_ptr() -> usize { #[cfg(feature = "hifive")] return *hifive_riscv::DTB.get().unwrap(); @@ -97,6 +90,6 @@ pub fn platform_dtb_ptr() -> usize { static MACHINE_INFO: Once = Once::new(); -pub fn platform_machine_info()->PlatformInfo{ +pub fn platform_machine_info() -> PlatformInfo { MACHINE_INFO.get().unwrap().clone() } diff --git a/subsystems/platform/src/logging.rs b/subsystems/platform/src/logging.rs index f69ec6ac..1c03d400 100644 --- a/subsystems/platform/src/logging.rs +++ b/subsystems/platform/src/logging.rs @@ -1,6 +1,5 @@ use log::{self, Level, LevelFilter, Log, Metadata, Record}; - struct SimpleLogger; impl Log for SimpleLogger { diff --git a/subsystems/platform/src/qemu_riscv/config.rs b/subsystems/platform/src/qemu_riscv/config.rs index c0981e95..79406337 100644 --- a/subsystems/platform/src/qemu_riscv/config.rs +++ b/subsystems/platform/src/qemu_riscv/config.rs @@ -1,14 +1,12 @@ -pub const CLOCK_FREQ: usize = 1250_0000; -pub const BLOCK_CACHE_FRAMES: usize = 1024 * 4 * 4; -pub const HEAP_SIZE: usize = 0x26_00000; // (32+6)MB - - - -/// qemu的设备地址空间 -pub const MMIO: &[(usize, usize)] = &[ - (0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine - (0x2000000, 0x10000), - (0xc00_0000, 0x21_0000), // VIRT_PLIC in virt machine - (0x1000_0000, 0x9000), // VIRT_UART0 with GPU in virt machine - (0x3000_0000, 0x1000_0000), -]; +pub const CLOCK_FREQ: usize = 1250_0000; +pub const BLOCK_CACHE_FRAMES: usize = 1024 * 4 * 4; +pub const HEAP_SIZE: usize = 0x26_00000; // (32+6)MB + +/// qemu的设备地址空间 +pub const MMIO: &[(usize, usize)] = &[ + (0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine + (0x2000000, 0x10000), + (0xc00_0000, 0x21_0000), // VIRT_PLIC in virt machine + (0x1000_0000, 0x9000), // VIRT_UART0 with GPU in virt machine + (0x3000_0000, 0x1000_0000), +]; diff --git a/subsystems/platform/src/starfive2_riscv/mod.rs b/subsystems/platform/src/starfive2_riscv/mod.rs index 1e3f62a4..46005a3f 100644 --- a/subsystems/platform/src/starfive2_riscv/mod.rs +++ b/subsystems/platform/src/starfive2_riscv/mod.rs @@ -2,9 +2,7 @@ pub mod config; use spin::Once; -pub const FDT: &[u8] = include_bytes!( - "../../../../tools/jh7110-visionfive-v2.dtb" -); +pub const FDT: &[u8] = include_bytes!("../../../../tools/jh7110-visionfive-v2.dtb"); pub static DTB: Once = Once::new(); diff --git a/subsystems/timer/src/lib.rs b/subsystems/timer/src/lib.rs index ecb19824..888e0927 100644 --- a/subsystems/timer/src/lib.rs +++ b/subsystems/timer/src/lib.rs @@ -1,8 +1,8 @@ #![no_std] -use vfscore::utils::VfsTimeSpec; use constants::sys::TimeVal; use platform::config::CLOCK_FREQ; +use vfscore::utils::VfsTimeSpec; /// 每秒包含的毫秒数 const MSEC_PER_SEC: usize = 1000; /// 程序运行时间 @@ -30,7 +30,6 @@ impl Times { } } - /// 实现 `TimeNow` 特征的时钟结构,能够通过调用 `now` 方法得出 表示当前的 cpu 时间的一个本类型时钟 pub trait TimeNow { fn now() -> Self; @@ -70,7 +69,6 @@ impl TimeFromFreq for TimeVal { } } - /// 更精细的时间,秒(s)+纳秒(ns) #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -128,4 +126,4 @@ pub fn read_timer() -> usize { /// 获取当前时间,以 ms 为单位 pub fn get_time_ms() -> isize { (read_timer() / (CLOCK_FREQ / MSEC_PER_SEC)) as isize -} \ No newline at end of file +} diff --git a/subsystems/unwinder/build.rs b/subsystems/unwinder/build.rs index 6565a7ea..071afa14 100644 --- a/subsystems/unwinder/build.rs +++ b/subsystems/unwinder/build.rs @@ -1,22 +1,22 @@ -use std::fs::File; -use std::path::Path; -use std::io::Write; - -fn main(){ - println!("cargo:rerun-if-changed={}", "src/"); - let path = Path::new("src/kernel_symbol.S"); - if !path.exists() { - let mut file = File::create(path).unwrap(); - write!(file, ".section .rodata\n").unwrap(); - write!(file, ".align 3\n").unwrap(); - write!(file, ".global symbol_num\n").unwrap(); - write!(file, ".global symbol_address\n").unwrap(); - write!(file, ".global symbol_index\n").unwrap(); - write!(file, ".global symbol_name\n").unwrap(); - write!(file, "symbol_num:\n").unwrap(); - write!(file, ".quad {}\n", 0).unwrap(); - write!(file, "symbol_address:\n").unwrap(); - write!(file, "symbol_index:\n").unwrap(); - write!(file, "symbol_name:\n").unwrap(); - } -} \ No newline at end of file +use std::fs::File; +use std::io::Write; +use std::path::Path; + +fn main() { + println!("cargo:rerun-if-changed={}", "src/"); + let path = Path::new("src/kernel_symbol.S"); + if !path.exists() { + let mut file = File::create(path).unwrap(); + write!(file, ".section .rodata\n").unwrap(); + write!(file, ".align 3\n").unwrap(); + write!(file, ".global symbol_num\n").unwrap(); + write!(file, ".global symbol_address\n").unwrap(); + write!(file, ".global symbol_index\n").unwrap(); + write!(file, ".global symbol_name\n").unwrap(); + write!(file, "symbol_num:\n").unwrap(); + write!(file, ".quad {}\n", 0).unwrap(); + write!(file, "symbol_address:\n").unwrap(); + write!(file, "symbol_index:\n").unwrap(); + write!(file, "symbol_name:\n").unwrap(); + } +} diff --git a/subsystems/unwinder/src/kernel_symbol.S b/subsystems/unwinder/src/kernel_symbol.S index 6eeb99eb..abee068b 100644 --- a/subsystems/unwinder/src/kernel_symbol.S +++ b/subsystems/unwinder/src/kernel_symbol.S @@ -2,7 +2,7 @@ .section .rodata .globl symbol_num symbol_num: - .quad 3322 + .quad 3595 .globl symbol_address symbol_address: .quad 2149580800 @@ -142,3191 +142,3464 @@ symbol_address: .quad 2149591040 .quad 2149591056 .quad 2149591072 - .quad 2149591114 - .quad 2149591134 - .quad 2149591136 - .quad 2149591186 - .quad 2149592186 - .quad 2149592200 - .quad 2149592360 - .quad 2149592378 - .quad 2149592396 - .quad 2149592414 - .quad 2149592432 - .quad 2149592450 - .quad 2149592468 - .quad 2149592486 - .quad 2149592504 - .quad 2149593104 - .quad 2149593112 - .quad 2149593122 - .quad 2149593132 - .quad 2149593142 - .quad 2149593152 - .quad 2149593162 - .quad 2149593172 - .quad 2149593182 - .quad 2149593192 - .quad 2149593202 - .quad 2149593212 - .quad 2149593222 - .quad 2149593232 - .quad 2149593242 - .quad 2149593242 - .quad 2149593252 - .quad 2149593262 - .quad 2149593272 - .quad 2149593282 - .quad 2149593292 - .quad 2149593302 - .quad 2149593312 - .quad 2149593322 - .quad 2149593332 - .quad 2149593342 - .quad 2149593352 - .quad 2149593362 - .quad 2149593372 - .quad 2149593382 - .quad 2149593392 - .quad 2149593402 - .quad 2149593412 - .quad 2149593422 - .quad 2149593432 - .quad 2149593442 - .quad 2149593452 - .quad 2149593462 - .quad 2149593472 - .quad 2149593482 - .quad 2149593492 - .quad 2149593502 - .quad 2149593512 - .quad 2149593552 - .quad 2149593582 - .quad 2149593602 - .quad 2149593746 - .quad 2149594018 - .quad 2149594292 - .quad 2149594454 - .quad 2149594636 - .quad 2149594760 - .quad 2149594770 - .quad 2149594946 - .quad 2149595048 - .quad 2149595050 - .quad 2149595052 - .quad 2149595052 - .quad 2149595546 - .quad 2149596262 - .quad 2149596392 - .quad 2149597494 - .quad 2149597498 - .quad 2149597510 - .quad 2149598134 - .quad 2149599972 - .quad 2149599976 - .quad 2149599988 - .quad 2149600656 - .quad 2149601440 - .quad 2149602754 - .quad 2149603660 - .quad 2149603668 - .quad 2149603672 - .quad 2149603684 - .quad 2149603696 - .quad 2149603712 - .quad 2149603724 - .quad 2149603824 - .quad 2149603910 - .quad 2149603996 + .quad 2149592718 + .quad 2149594566 + .quad 2149596592 + .quad 2149598310 + .quad 2149600028 + .quad 2149601656 + .quad 2149602124 + .quad 2149602602 + .quad 2149603130 + .quad 2149603586 .quad 2149604114 - .quad 2149604240 - .quad 2149604366 - .quad 2149604562 - .quad 2149604634 - .quad 2149604688 - .quad 2149604934 - .quad 2149604962 - .quad 2149605046 - .quad 2149605092 - .quad 2149605104 - .quad 2149605662 - .quad 2149605786 - .quad 2149605868 - .quad 2149605948 - .quad 2149605952 - .quad 2149605956 - .quad 2149605970 - .quad 2149606102 - .quad 2149606192 - .quad 2149606246 - .quad 2149606256 - .quad 2149607954 - .quad 2149610430 - .quad 2149610440 - .quad 2149610454 - .quad 2149610632 - .quad 2149610644 - .quad 2149610648 - .quad 2149610652 - .quad 2149610736 - .quad 2149611612 - .quad 2149611836 - .quad 2149612064 - .quad 2149612398 - .quad 2149612416 - .quad 2149612420 - .quad 2149612510 - .quad 2149612516 - .quad 2149612530 - .quad 2149612544 - .quad 2149612796 - .quad 2149612808 - .quad 2149613030 - .quad 2149613076 - .quad 2149613208 - .quad 2149613338 - .quad 2149613410 - .quad 2149614254 - .quad 2149614262 - .quad 2149615462 - .quad 2149615480 - .quad 2149617198 - .quad 2149617344 - .quad 2149618394 - .quad 2149618632 - .quad 2149618740 - .quad 2149619032 - .quad 2149619174 - .quad 2149619256 - .quad 2149619394 - .quad 2149619462 - .quad 2149619466 - .quad 2149619472 - .quad 2149619946 - .quad 2149620202 - .quad 2149620290 - .quad 2149620582 - .quad 2149620882 - .quad 2149621112 - .quad 2149621866 - .quad 2149622276 - .quad 2149622464 - .quad 2149622658 - .quad 2149624730 - .quad 2149624740 - .quad 2149624750 - .quad 2149624760 - .quad 2149624770 - .quad 2149624810 - .quad 2149624840 - .quad 2149624840 - .quad 2149624842 - .quad 2149624842 - .quad 2149624842 - .quad 2149624844 - .quad 2149624914 - .quad 2149625152 - .quad 2149625938 - .quad 2149626020 - .quad 2149626118 - .quad 2149626208 - .quad 2149626440 - .quad 2149626774 - .quad 2149627170 - .quad 2149627404 - .quad 2149627612 - .quad 2149627826 - .quad 2149628298 - .quad 2149628678 - .quad 2149628678 - .quad 2149628678 - .quad 2149629058 - .quad 2149629438 - .quad 2149629818 - .quad 2149630760 - .quad 2149632182 - .quad 2149633128 - .quad 2149633422 - .quad 2149633684 - .quad 2149633892 - .quad 2149634724 - .quad 2149635102 - .quad 2149635666 - .quad 2149635666 - .quad 2149635968 - .quad 2149636270 - .quad 2149636572 - .quad 2149636874 - .quad 2149637176 - .quad 2149637478 - .quad 2149637936 - .quad 2149640020 - .quad 2149640468 - .quad 2149640808 - .quad 2149642196 - .quad 2149644210 - .quad 2149644674 - .quad 2149645772 - .quad 2149646354 - .quad 2149654758 - .quad 2149659138 - .quad 2149670896 - .quad 2149670940 - .quad 2149671800 - .quad 2149672958 + .quad 2149604618 + .quad 2149605182 + .quad 2149605694 + .quad 2149606204 + .quad 2149606698 + .quad 2149607238 + .quad 2149607758 + .quad 2149608208 + .quad 2149608642 + .quad 2149609114 + .quad 2149609542 + .quad 2149610186 + .quad 2149610866 + .quad 2149611554 + .quad 2149612204 + .quad 2149612418 + .quad 2149612618 + .quad 2149612860 + .quad 2149613050 + .quad 2149613050 + .quad 2149613256 + .quad 2149613462 + .quad 2149613664 + .quad 2149613682 + .quad 2149613692 + .quad 2149613702 + .quad 2149613712 + .quad 2149613722 + .quad 2149613762 + .quad 2149613792 + .quad 2149613794 + .quad 2149613794 + .quad 2149613796 + .quad 2149613856 + .quad 2149614094 + .quad 2149614740 + .quad 2149614822 + .quad 2149614920 + .quad 2149615010 + .quad 2149615234 + .quad 2149615568 + .quad 2149615948 + .quad 2149616130 + .quad 2149616338 + .quad 2149616552 + .quad 2149617024 + .quad 2149617024 + .quad 2149617024 + .quad 2149617404 + .quad 2149617784 + .quad 2149618164 + .quad 2149618544 + .quad 2149619810 + .quad 2149621222 + .quad 2149622156 + .quad 2149622450 + .quad 2149622712 + .quad 2149622920 + .quad 2149623752 + .quad 2149624304 + .quad 2149624304 + .quad 2149624606 + .quad 2149624908 + .quad 2149625210 + .quad 2149625512 + .quad 2149625814 + .quad 2149626116 + .quad 2149626574 + .quad 2149628658 + .quad 2149629106 + .quad 2149629446 + .quad 2149630828 + .quad 2149632854 + .quad 2149633318 + .quad 2149634416 + .quad 2149635054 + .quad 2149642810 + .quad 2149646754 + .quad 2149658048 + .quad 2149658130 + .quad 2149658210 + .quad 2149658382 + .quad 2149658426 + .quad 2149658518 + .quad 2149658606 + .quad 2149658816 + .quad 2149658922 + .quad 2149659200 + .quad 2149659220 + .quad 2149659332 + .quad 2149659440 + .quad 2149659628 + .quad 2149660074 + .quad 2149660082 + .quad 2149660194 + .quad 2149660194 + .quad 2149660194 + .quad 2149660194 + .quad 2149660194 + .quad 2149660194 + .quad 2149660194 + .quad 2149660194 + .quad 2149660194 + .quad 2149660194 + .quad 2149660194 + .quad 2149660194 + .quad 2149660194 + .quad 2149660198 + .quad 2149660306 + .quad 2149660574 + .quad 2149660998 + .quad 2149661110 + .quad 2149661362 + .quad 2149661474 + .quad 2149661898 + .quad 2149661986 + .quad 2149662140 + .quad 2149662246 + .quad 2149662542 + .quad 2149662774 + .quad 2149662952 + .quad 2149663146 + .quad 2149663258 + .quad 2149663366 + .quad 2149663526 + .quad 2149663714 + .quad 2149663862 + .quad 2149664026 + .quad 2149664114 + .quad 2149664350 + .quad 2149664442 + .quad 2149664550 + .quad 2149664682 + .quad 2149664758 + .quad 2149665070 + .quad 2149665400 + .quad 2149665760 + .quad 2149665868 + .quad 2149665982 + .quad 2149666232 + .quad 2149666338 + .quad 2149666492 + .quad 2149666912 + .quad 2149666920 + .quad 2149667032 + .quad 2149667144 + .quad 2149667388 + .quad 2149667692 + .quad 2149667802 + .quad 2149667908 + .quad 2149668072 + .quad 2149668180 + .quad 2149668188 + .quad 2149668608 + .quad 2149668792 + .quad 2149668912 + .quad 2149669144 + .quad 2149669370 + .quad 2149669476 + .quad 2149669640 + .quad 2149669660 + .quad 2149669974 + .quad 2149669974 + .quad 2149670070 + .quad 2149670264 + .quad 2149670380 + .quad 2149670456 + .quad 2149670562 + .quad 2149670670 + .quad 2149670782 + .quad 2149670930 + .quad 2149671162 + .quad 2149671300 + .quad 2149671600 + .quad 2149671708 + .quad 2149671708 + .quad 2149671798 + .quad 2149671906 + .quad 2149672018 + .quad 2149672336 + .quad 2149672496 + .quad 2149672604 + .quad 2149672716 + .quad 2149672826 + .quad 2149672932 + .quad 2149673352 + .quad 2149673472 + .quad 2149673580 + .quad 2149673694 + .quad 2149673926 + .quad 2149673926 .quad 2149674106 - .quad 2149674726 - .quad 2149675444 - .quad 2149676448 - .quad 2149677862 - .quad 2149678392 - .quad 2149678402 - .quad 2149678462 - .quad 2149678644 - .quad 2149678696 - .quad 2149678872 - .quad 2149679040 - .quad 2149679166 - .quad 2149679246 - .quad 2149679248 - .quad 2149679480 - .quad 2149679666 - .quad 2149679898 + .quad 2149674364 + .quad 2149674452 + .quad 2149674708 + .quad 2149674814 + .quad 2149675046 + .quad 2149675154 + .quad 2149675282 + .quad 2149675446 + .quad 2149675528 + .quad 2149675536 + .quad 2149675768 + .quad 2149675922 + .quad 2149675930 + .quad 2149676036 + .quad 2149676144 + .quad 2149676250 + .quad 2149676410 + .quad 2149676518 + .quad 2149676610 + .quad 2149676798 + .quad 2149677186 + .quad 2149677202 + .quad 2149677286 + .quad 2149677392 + .quad 2149677494 + .quad 2149677594 + .quad 2149677772 + .quad 2149677930 + .quad 2149677952 + .quad 2149678102 + .quad 2149678124 + .quad 2149678140 + .quad 2149678164 + .quad 2149678284 + .quad 2149678306 + .quad 2149678328 + .quad 2149678510 + .quad 2149678532 + .quad 2149678810 + .quad 2149678910 + .quad 2149678910 + .quad 2149679000 + .quad 2149679022 + .quad 2149679124 + .quad 2149679146 + .quad 2149679146 + .quad 2149679146 + .quad 2149679146 + .quad 2149679146 + .quad 2149679146 + .quad 2149679146 + .quad 2149679146 + .quad 2149679146 + .quad 2149679146 + .quad 2149679146 + .quad 2149679146 + .quad 2149679146 + .quad 2149679150 + .quad 2149679272 + .quad 2149679428 + .quad 2149679514 + .quad 2149679614 + .quad 2149679720 + .quad 2149679822 + .quad 2149679980 .quad 2149680084 - .quad 2149682186 - .quad 2149683802 - .quad 2149685374 - .quad 2149687020 - .quad 2149688642 - .quad 2149688770 - .quad 2149691494 - .quad 2149692638 - .quad 2149693550 - .quad 2149694486 - .quad 2149694776 - .quad 2149695298 - .quad 2149695782 - .quad 2149695956 - .quad 2149696614 - .quad 2149697800 - .quad 2149699826 - .quad 2149700424 - .quad 2149700804 - .quad 2149700972 - .quad 2149702662 - .quad 2149702836 - .quad 2149702998 - .quad 2149703450 - .quad 2149705586 - .quad 2149706546 - .quad 2149706796 - .quad 2149707882 - .quad 2149709408 - .quad 2149709986 - .quad 2149710288 - .quad 2149710288 - .quad 2149710520 - .quad 2149710744 - .quad 2149710970 - .quad 2149711206 - .quad 2149711426 - .quad 2149711658 - .quad 2149711930 - .quad 2149712146 - .quad 2149712164 - .quad 2149712182 - .quad 2149712200 - .quad 2149712218 - .quad 2149712286 - .quad 2149712296 - .quad 2149712306 - .quad 2149712316 - .quad 2149712326 - .quad 2149712326 - .quad 2149712336 - .quad 2149712346 - .quad 2149712356 - .quad 2149712366 - .quad 2149712376 - .quad 2149712386 - .quad 2149712396 - .quad 2149712406 - .quad 2149712416 - .quad 2149712426 - .quad 2149712436 - .quad 2149712446 - .quad 2149712476 - .quad 2149712620 - .quad 2149712892 - .quad 2149712946 - .quad 2149713126 - .quad 2149713128 - .quad 2149713130 - .quad 2149713130 - .quad 2149713130 - .quad 2149713318 - .quad 2149713630 - .quad 2149714076 - .quad 2149714348 - .quad 2149714730 - .quad 2149715034 - .quad 2149715306 - .quad 2149715598 - .quad 2149715848 - .quad 2149716096 - .quad 2149716344 - .quad 2149716790 - .quad 2149717138 - .quad 2149717584 - .quad 2149717838 - .quad 2149718094 - .quad 2149718342 - .quad 2149718590 - .quad 2149718876 - .quad 2149719222 - .quad 2149719472 - .quad 2149719724 - .quad 2149719918 - .quad 2149720288 - .quad 2149720836 - .quad 2149721554 - .quad 2149721554 - .quad 2149721638 - .quad 2149723226 - .quad 2149723292 - .quad 2149723364 - .quad 2149723432 - .quad 2149723504 - .quad 2149723576 - .quad 2149723644 - .quad 2149723712 - .quad 2149723780 - .quad 2149723852 - .quad 2149723946 - .quad 2149723954 - .quad 2149723966 - .quad 2149723978 - .quad 2149723994 - .quad 2149724006 - .quad 2149724198 - .quad 2149724434 - .quad 2149724488 - .quad 2149724542 - .quad 2149724588 - .quad 2149724634 - .quad 2149724890 - .quad 2149726018 - .quad 2149726736 - .quad 2149726952 - .quad 2149727092 - .quad 2149727446 - .quad 2149727640 - .quad 2149727984 - .quad 2149728076 - .quad 2149728172 - .quad 2149729234 - .quad 2149729370 - .quad 2149729812 - .quad 2149729818 - .quad 2149729832 - .quad 2149729838 - .quad 2149729852 - .quad 2149729866 - .quad 2149729880 - .quad 2149729892 - .quad 2149729898 - .quad 2149729902 - .quad 2149730032 - .quad 2149730104 - .quad 2149730158 - .quad 2149730166 - .quad 2149731182 - .quad 2149731730 - .quad 2149732238 - .quad 2149732470 - .quad 2149732482 - .quad 2149732486 - .quad 2149732490 - .quad 2149734312 - .quad 2149734316 - .quad 2149734320 - .quad 2149734992 - .quad 2149735652 - .quad 2149735980 - .quad 2149736256 - .quad 2149736628 - .quad 2149737014 - .quad 2149737336 - .quad 2149737722 - .quad 2149738118 - .quad 2149738386 - .quad 2149738540 - .quad 2149738600 - .quad 2149738660 - .quad 2149738688 - .quad 2149738716 - .quad 2149738884 - .quad 2149738928 - .quad 2149740836 - .quad 2149742532 - .quad 2149744288 - .quad 2149746112 - .quad 2149747812 - .quad 2149749490 - .quad 2149749490 - .quad 2149749490 - .quad 2149751434 - .quad 2149753574 - .quad 2149753574 - .quad 2149755330 - .quad 2149756996 - .quad 2149756996 - .quad 2149758662 - .quad 2149760540 - .quad 2149760996 - .quad 2149761512 - .quad 2149761980 - .quad 2149762500 - .quad 2149763028 - .quad 2149763484 - .quad 2149763962 - .quad 2149764466 - .quad 2149764978 - .quad 2149765542 - .quad 2149766046 - .quad 2149766610 - .quad 2149767138 - .quad 2149767696 - .quad 2149768224 - .quad 2149768758 - .quad 2149769306 - .quad 2149769824 - .quad 2149770368 - .quad 2149770870 - .quad 2149771372 - .quad 2149771840 - .quad 2149772320 - .quad 2149772756 - .quad 2149773192 - .quad 2149773660 - .quad 2149774102 - .quad 2149774560 - .quad 2149775210 - .quad 2149775896 - .quad 2149776584 - .quad 2149777278 - .quad 2149777958 - .quad 2149778608 - .quad 2149779252 - .quad 2149779466 - .quad 2149779714 - .quad 2149779904 - .quad 2149779904 + .quad 2149680186 + .quad 2149680208 + .quad 2149680230 + .quad 2149680252 + .quad 2149680252 + .quad 2149680450 + .quad 2149680472 + .quad 2149680494 + .quad 2149680594 + .quad 2149680696 + .quad 2149680878 + .quad 2149680986 + .quad 2149681008 + .quad 2149681030 + .quad 2149681158 + .quad 2149681234 + .quad 2149681460 + .quad 2149681608 + .quad 2149681616 + .quad 2149681700 + .quad 2149681722 + .quad 2149681828 + .quad 2149682008 + .quad 2149682166 + .quad 2149682268 + .quad 2149682374 + .quad 2149682476 + .quad 2149682558 + .quad 2149682714 + .quad 2149682896 + .quad 2149682996 + .quad 2149683098 + .quad 2149683204 + .quad 2149683314 + .quad 2149683614 + .quad 2149683636 + .quad 2149683722 + .quad 2149683744 + .quad 2149683820 + .quad 2149683958 + .quad 2149684060 + .quad 2149684082 + .quad 2149684104 + .quad 2149684210 + .quad 2149684312 + .quad 2149684542 + .quad 2149684626 + .quad 2149684726 + .quad 2149684748 + .quad 2149684770 + .quad 2149684902 + .quad 2149684922 + .quad 2149685008 + .quad 2149685120 + .quad 2149685238 + .quad 2149685254 + .quad 2149685276 + .quad 2149685378 + .quad 2149685536 + .quad 2149685684 + .quad 2149685786 + .quad 2149685808 + .quad 2149685830 + .quad 2149685852 + .quad 2149685972 + .quad 2149686128 + .quad 2149686128 + .quad 2149686224 + .quad 2149686330 + .quad 2149686430 + .quad 2149686530 + .quad 2149686636 + .quad 2149686658 + .quad 2149686742 + .quad 2149686846 + .quad 2149686968 + .quad 2149687070 + .quad 2149687092 + .quad 2149687210 + .quad 2149687312 + .quad 2149687334 + .quad 2149687592 + .quad 2149687896 + .quad 2149687918 + .quad 2149688048 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688154 + .quad 2149688156 + .quad 2149688174 + .quad 2149688194 + .quad 2149688404 + .quad 2149688604 + .quad 2149688898 + .quad 2149689192 + .quad 2149689464 + .quad 2149689736 + .quad 2149690094 + .quad 2149690438 + .quad 2149690678 + .quad 2149690686 + .quad 2149690696 + .quad 2149690706 + .quad 2149690716 + .quad 2149690726 + .quad 2149690748 + .quad 2149690788 + .quad 2149690828 + .quad 2149690830 + .quad 2149690890 + .quad 2149690910 + .quad 2149690930 + .quad 2149691524 + .quad 2149692540 + .quad 2149692908 + .quad 2149693458 + .quad 2149694326 + .quad 2149694894 + .quad 2149695058 + .quad 2149695342 + .quad 2149695908 + .quad 2149696514 + .quad 2149696808 + .quad 2149697054 + .quad 2149697572 + .quad 2149698240 + .quad 2149698960 + .quad 2149699480 + .quad 2149699886 + .quad 2149700200 + .quad 2149700966 + .quad 2149701730 + .quad 2149702802 + .quad 2149703604 + .quad 2149703918 + .quad 2149704788 + .quad 2149706380 + .quad 2149707352 + .quad 2149707542 + .quad 2149707584 + .quad 2149707626 + .quad 2149707668 + .quad 2149707688 + .quad 2149707698 + .quad 2149707698 + .quad 2149707708 + .quad 2149707718 + .quad 2149707728 + .quad 2149707748 + .quad 2149707758 + .quad 2149707798 + .quad 2149707934 + .quad 2149707936 + .quad 2149707936 + .quad 2149707946 + .quad 2149708426 + .quad 2149709080 + .quad 2149709362 + .quad 2149709696 + .quad 2149710158 + .quad 2149710966 + .quad 2149711402 + .quad 2149711972 + .quad 2149713026 + .quad 2149714556 + .quad 2149716050 + .quad 2149717142 + .quad 2149718758 + .quad 2149719308 + .quad 2149719312 + .quad 2149719316 + .quad 2149719490 + .quad 2149719756 + .quad 2149720208 + .quad 2149722306 + .quad 2149722324 + .quad 2149722324 + .quad 2149722324 + .quad 2149722328 + .quad 2149722330 + .quad 2149722342 + .quad 2149722354 + .quad 2149722366 + .quad 2149722372 + .quad 2149722384 + .quad 2149722394 + .quad 2149722394 + .quad 2149722404 + .quad 2149722414 + .quad 2149722424 + .quad 2149722464 + .quad 2149722504 + .quad 2149722544 + .quad 2149722562 + .quad 2149722564 + .quad 2149722566 + .quad 2149722566 + .quad 2149722568 + .quad 2149722666 + .quad 2149722686 + .quad 2149722890 + .quad 2149723334 + .quad 2149723528 + .quad 2149723730 + .quad 2149724104 + .quad 2149724338 + .quad 2149724870 + .quad 2149725254 + .quad 2149725480 + .quad 2149726528 + .quad 2149727008 + .quad 2149729442 + .quad 2149729528 + .quad 2149729610 + .quad 2149729690 + .quad 2149729918 + .quad 2149730152 + .quad 2149730162 + .quad 2149730174 + .quad 2149730178 + .quad 2149732340 + .quad 2149732380 + .quad 2149732382 + .quad 2149732384 + .quad 2149732386 + .quad 2149732640 + .quad 2149732640 + .quad 2149732894 + .quad 2149732894 + .quad 2149733126 + .quad 2149733370 + .quad 2149733632 + .quad 2149734134 + .quad 2149735794 + .quad 2149741068 + .quad 2149741696 + .quad 2149741782 + .quad 2149742174 + .quad 2149742972 + .quad 2149744052 + .quad 2149744396 + .quad 2149745206 + .quad 2149745606 + .quad 2149745840 + .quad 2149745858 + .quad 2149745868 + .quad 2149745878 + .quad 2149745888 + .quad 2149745898 + .quad 2149745908 + .quad 2149745918 + .quad 2149745928 + .quad 2149745938 + .quad 2149746086 + .quad 2149746184 + .quad 2149746186 + .quad 2149746188 + .quad 2149746542 + .quad 2149746712 + .quad 2149746888 + .quad 2149747068 + .quad 2149747236 + .quad 2149748154 + .quad 2149748498 + .quad 2149748566 + .quad 2149748634 + .quad 2149748706 + .quad 2149748774 + .quad 2149748846 + .quad 2149748914 + .quad 2149748986 + .quad 2149748994 + .quad 2149748998 + .quad 2149749010 + .quad 2149749022 + .quad 2149749038 + .quad 2149749050 + .quad 2149749068 + .quad 2149749072 + .quad 2149749086 + .quad 2149749180 + .quad 2149749252 + .quad 2149749306 + .quad 2149749312 + .quad 2149749326 + .quad 2149749344 + .quad 2149749358 + .quad 2149749568 + .quad 2149749580 + .quad 2149749584 + .quad 2149749588 + .quad 2149749638 + .quad 2149749684 + .quad 2149749688 + .quad 2149749702 + .quad 2149749714 + .quad 2149749718 + .quad 2149749934 + .quad 2149750776 + .quad 2149751522 + .quad 2149751954 + .quad 2149752926 + .quad 2149753694 + .quad 2149753930 + .quad 2149754162 + .quad 2149754388 + .quad 2149754620 + .quad 2149754870 + .quad 2149755090 + .quad 2149755092 + .quad 2149755094 + .quad 2149755114 + .quad 2149755354 + .quad 2149755650 + .quad 2149755896 + .quad 2149756160 + .quad 2149756444 + .quad 2149756802 + .quad 2149756822 + .quad 2149757172 + .quad 2149757606 + .quad 2149757834 + .quad 2149758700 + .quad 2149759352 + .quad 2149759992 + .quad 2149760618 + .quad 2149760924 + .quad 2149761278 + .quad 2149761538 + .quad 2149761788 + .quad 2149762846 + .quad 2149764446 + .quad 2149765504 + .quad 2149766538 + .quad 2149766540 + .quad 2149766542 + .quad 2149767172 + .quad 2149767550 + .quad 2149767570 + .quad 2149768226 + .quad 2149769654 + .quad 2149770282 + .quad 2149773238 + .quad 2149774600 + .quad 2149775636 + .quad 2149775978 + .quad 2149775988 + .quad 2149775998 + .quad 2149776008 + .quad 2149776018 + .quad 2149776020 + .quad 2149776142 + .quad 2149776232 + .quad 2149776232 + .quad 2149776232 + .quad 2149776232 + .quad 2149776364 + .quad 2149776364 + .quad 2149776364 + .quad 2149776364 + .quad 2149776496 + .quad 2149776638 + .quad 2149776638 + .quad 2149776770 + .quad 2149776920 + .quad 2149777060 + .quad 2149777060 + .quad 2149777198 + .quad 2149777340 + .quad 2149777340 + .quad 2149777474 + .quad 2149777614 + .quad 2149777694 + .quad 2149777774 + .quad 2149777854 + .quad 2149777934 + .quad 2149778014 + .quad 2149778094 + .quad 2149778174 + .quad 2149778254 + .quad 2149778334 + .quad 2149778414 + .quad 2149778494 + .quad 2149778574 + .quad 2149778654 + .quad 2149778734 + .quad 2149778814 + .quad 2149778894 + .quad 2149778974 + .quad 2149779054 + .quad 2149779134 + .quad 2149779214 + .quad 2149779294 + .quad 2149779374 + .quad 2149779454 + .quad 2149779534 + .quad 2149779614 + .quad 2149779694 + .quad 2149779774 + .quad 2149779854 + .quad 2149779934 + .quad 2149780014 .quad 2149780094 - .quad 2149780294 - .quad 2149780554 - .quad 2149780796 - .quad 2149781018 - .quad 2149781018 - .quad 2149781240 - .quad 2149781462 - .quad 2149781680 - .quad 2149781898 - .quad 2149781898 - .quad 2149782120 - .quad 2149782982 - .quad 2149783780 - .quad 2149783996 - .quad 2149785232 - .quad 2149785572 - .quad 2149786374 - .quad 2149786750 - .quad 2149786984 - .quad 2149787200 - .quad 2149787346 - .quad 2149787492 - .quad 2149787502 - .quad 2149787542 - .quad 2149787836 - .quad 2149787838 - .quad 2149787840 - .quad 2149787844 - .quad 2149787962 - .quad 2149788092 - .quad 2149788222 - .quad 2149788466 - .quad 2149788928 - .quad 2149789440 - .quad 2149789656 - .quad 2149790612 - .quad 2149791462 - .quad 2149791794 - .quad 2149792752 - .quad 2149793440 - .quad 2149794552 - .quad 2149795598 - .quad 2149796100 - .quad 2149797804 - .quad 2149803254 - .quad 2149804172 - .quad 2149804456 - .quad 2149804768 - .quad 2149806636 - .quad 2149807854 - .quad 2149807876 - .quad 2149807900 - .quad 2149808006 - .quad 2149808064 - .quad 2149808064 - .quad 2149808066 - .quad 2149808068 - .quad 2149808070 - .quad 2149808316 - .quad 2149808380 - .quad 2149808380 - .quad 2149808380 - .quad 2149808380 - .quad 2149808380 - .quad 2149808380 - .quad 2149808380 - .quad 2149808380 - .quad 2149808380 - .quad 2149808380 - .quad 2149808380 - .quad 2149808504 - .quad 2149808504 - .quad 2149808666 - .quad 2149808900 - .quad 2149808900 - .quad 2149808954 - .quad 2149809008 - .quad 2149809218 - .quad 2149809398 - .quad 2149809580 - .quad 2149809634 - .quad 2149809860 - .quad 2149809860 - .quad 2149809968 - .quad 2149810130 - .quad 2149810130 - .quad 2149810362 - .quad 2149810468 - .quad 2149810468 - .quad 2149810520 - .quad 2149810720 - .quad 2149810908 - .quad 2149811014 - .quad 2149811132 - .quad 2149811312 - .quad 2149811368 - .quad 2149811572 - .quad 2149811770 - .quad 2149812108 - .quad 2149812352 - .quad 2149812996 - .quad 2149813104 - .quad 2149813190 - .quad 2149813370 - .quad 2149813694 - .quad 2149814430 - .quad 2149814494 - .quad 2149814522 - .quad 2149814888 - .quad 2149815132 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815420 - .quad 2149815440 - .quad 2149817706 - .quad 2149818244 - .quad 2149818248 - .quad 2149818530 - .quad 2149818532 + .quad 2149780174 + .quad 2149780254 + .quad 2149780334 + .quad 2149780414 + .quad 2149780494 + .quad 2149780574 + .quad 2149780654 + .quad 2149780734 + .quad 2149780814 + .quad 2149780894 + .quad 2149780974 + .quad 2149781054 + .quad 2149781134 + .quad 2149781214 + .quad 2149781294 + .quad 2149781374 + .quad 2149781454 + .quad 2149781534 + .quad 2149781614 + .quad 2149781694 + .quad 2149781774 + .quad 2149781854 + .quad 2149781934 + .quad 2149782014 + .quad 2149782094 + .quad 2149782174 + .quad 2149782254 + .quad 2149782334 + .quad 2149782414 + .quad 2149782494 + .quad 2149782574 + .quad 2149782654 + .quad 2149782734 + .quad 2149782814 + .quad 2149782894 + .quad 2149782974 + .quad 2149783054 + .quad 2149783134 + .quad 2149783214 + .quad 2149783294 + .quad 2149783374 + .quad 2149783454 + .quad 2149783534 + .quad 2149783614 + .quad 2149783694 + .quad 2149783774 + .quad 2149783856 + .quad 2149784016 + .quad 2149784034 + .quad 2149784042 + .quad 2149784052 + .quad 2149784062 + .quad 2149784072 + .quad 2149784090 + .quad 2149784110 + .quad 2149784112 + .quad 2149784132 + .quad 2149784200 + .quad 2149784556 + .quad 2149784624 + .quad 2149784784 + .quad 2149785054 + .quad 2149787518 + .quad 2149788578 + .quad 2149790026 + .quad 2149790514 + .quad 2149790548 + .quad 2149790596 + .quad 2149790834 + .quad 2149790908 + .quad 2149790996 + .quad 2149791288 + .quad 2149791476 + .quad 2149791706 + .quad 2149792430 + .quad 2149792840 + .quad 2149793028 + .quad 2149793108 + .quad 2149794442 + .quad 2149794758 + .quad 2149794776 + .quad 2149794786 + .quad 2149794796 + .quad 2149794806 + .quad 2149794816 + .quad 2149794826 + .quad 2149794836 + .quad 2149794846 + .quad 2149794856 + .quad 2149794878 + .quad 2149795400 + .quad 2149795650 + .quad 2149796176 + .quad 2149796206 + .quad 2149796342 + .quad 2149796344 + .quad 2149796346 + .quad 2149796888 + .quad 2149796890 + .quad 2149796890 + .quad 2149796890 + .quad 2149796946 + .quad 2149797010 + .quad 2149797010 + .quad 2149797010 + .quad 2149797010 + .quad 2149797010 + .quad 2149797010 + .quad 2149797126 + .quad 2149797174 + .quad 2149797272 + .quad 2149797350 + .quad 2149797536 + .quad 2149797582 + .quad 2149797628 + .quad 2149797744 + .quad 2149797916 + .quad 2149798108 + .quad 2149798254 + .quad 2149798442 + .quad 2149798608 + .quad 2149798782 + .quad 2149798828 + .quad 2149798892 + .quad 2149798920 + .quad 2149798992 + .quad 2149799236 + .quad 2149799322 + .quad 2149799408 + .quad 2149799494 + .quad 2149799576 + .quad 2149799662 + .quad 2149799748 + .quad 2149799836 + .quad 2149799908 + .quad 2149799962 + .quad 2149800322 + .quad 2149800406 + .quad 2149800452 + .quad 2149800456 + .quad 2149800460 + .quad 2149800514 + .quad 2149802098 + .quad 2149802288 + .quad 2149802878 + .quad 2149802952 + .quad 2149803412 + .quad 2149803420 + .quad 2149803562 + .quad 2149803648 + .quad 2149803870 + .quad 2149803950 + .quad 2149804030 + .quad 2149804110 + .quad 2149804190 + .quad 2149804270 + .quad 2149804350 + .quad 2149804430 + .quad 2149804510 + .quad 2149804590 + .quad 2149804670 + .quad 2149804750 + .quad 2149804830 + .quad 2149804910 + .quad 2149804990 + .quad 2149805070 + .quad 2149805150 + .quad 2149805230 + .quad 2149805310 + .quad 2149805390 + .quad 2149805470 + .quad 2149805550 + .quad 2149805630 + .quad 2149805710 + .quad 2149805790 + .quad 2149805870 + .quad 2149805950 + .quad 2149806030 + .quad 2149806110 + .quad 2149806190 + .quad 2149806270 + .quad 2149806536 + .quad 2149806546 + .quad 2149806546 + .quad 2149806546 + .quad 2149806548 + .quad 2149806582 + .quad 2149806616 + .quad 2149806650 + .quad 2149806684 + .quad 2149806778 + .quad 2149807048 + .quad 2149807048 + .quad 2149807332 + .quad 2149807418 + .quad 2149807510 + .quad 2149807598 + .quad 2149807842 + .quad 2149808304 + .quad 2149808662 + .quad 2149808846 + .quad 2149809370 + .quad 2149809800 + .quad 2149810046 + .quad 2149810350 + .quad 2149810440 + .quad 2149810582 + .quad 2149810886 + .quad 2149810992 + .quad 2149811330 + .quad 2149811668 + .quad 2149811686 + .quad 2149811704 + .quad 2149811722 + .quad 2149811732 + .quad 2149811752 + .quad 2149811762 + .quad 2149811772 + .quad 2149811782 + .quad 2149811792 + .quad 2149811832 + .quad 2149811854 + .quad 2149811884 + .quad 2149811886 + .quad 2149811888 + .quad 2149811906 + .quad 2149811908 + .quad 2149812036 + .quad 2149812056 + .quad 2149812318 + .quad 2149812400 + .quad 2149812470 + .quad 2149812880 + .quad 2149813454 + .quad 2149813454 + .quad 2149813570 + .quad 2149814180 + .quad 2149814328 + .quad 2149814530 + .quad 2149814530 + .quad 2149814656 + .quad 2149814918 + .quad 2149815080 + .quad 2149815452 + .quad 2149815456 + .quad 2149815468 + .quad 2149815484 + .quad 2149816178 + .quad 2149816692 + .quad 2149816846 + .quad 2149818184 + .quad 2149818366 + .quad 2149818548 + .quad 2149818570 + .quad 2149818658 .quad 2149818746 - .quad 2149821524 - .quad 2149821612 - .quad 2149821700 - .quad 2149821788 - .quad 2149821876 - .quad 2149821964 - .quad 2149822052 - .quad 2149822140 - .quad 2149822228 - .quad 2149822316 - .quad 2149822404 - .quad 2149822492 - .quad 2149822580 - .quad 2149822668 - .quad 2149822756 - .quad 2149822844 - .quad 2149822932 - .quad 2149823020 - .quad 2149823108 - .quad 2149823196 - .quad 2149823284 - .quad 2149823372 - .quad 2149823460 - .quad 2149823548 - .quad 2149823636 - .quad 2149823724 - .quad 2149823812 - .quad 2149823900 - .quad 2149823988 - .quad 2149824094 - .quad 2149824182 - .quad 2149824594 - .quad 2149824724 - .quad 2149825026 - .quad 2149825046 - .quad 2149825140 - .quad 2149825284 - .quad 2149825504 - .quad 2149825924 - .quad 2149825924 - .quad 2149825924 - .quad 2149825924 - .quad 2149825924 - .quad 2149825924 - .quad 2149825924 - .quad 2149825924 - .quad 2149825924 - .quad 2149825924 - .quad 2149825924 - .quad 2149825924 - .quad 2149825924 - .quad 2149825928 - .quad 2149826160 - .quad 2149826228 - .quad 2149826348 - .quad 2149826442 - .quad 2149826534 - .quad 2149826626 - .quad 2149826732 - .quad 2149826884 - .quad 2149826968 - .quad 2149827062 - .quad 2149827154 - .quad 2149827512 - .quad 2149827632 - .quad 2149827726 - .quad 2149827836 - .quad 2149827912 - .quad 2149828212 - .quad 2149828356 - .quad 2149828444 - .quad 2149828750 - .quad 2149828834 - .quad 2149828916 - .quad 2149829108 - .quad 2149829108 - .quad 2149829288 - .quad 2149829524 - .quad 2149829608 - .quad 2149829700 - .quad 2149830000 - .quad 2149830094 - .quad 2149830186 - .quad 2149830366 - .quad 2149830492 - .quad 2149830580 - .quad 2149830672 - .quad 2149830760 - .quad 2149830924 - .quad 2149831088 - .quad 2149831330 - .quad 2149831476 - .quad 2149831568 - .quad 2149831712 - .quad 2149831824 - .quad 2149831920 - .quad 2149832000 - .quad 2149832080 - .quad 2149832172 - .quad 2149832382 - .quad 2149832470 - .quad 2149832620 - .quad 2149832714 - .quad 2149832722 - .quad 2149832798 - .quad 2149832866 - .quad 2149833146 - .quad 2149833238 - .quad 2149833458 - .quad 2149833618 - .quad 2149833838 - .quad 2149833944 - .quad 2149834154 - .quad 2149834246 - .quad 2149834334 - .quad 2149834634 - .quad 2149834642 - .quad 2149834774 - .quad 2149834938 - .quad 2149834938 - .quad 2149835028 - .quad 2149835462 - .quad 2149835714 - .quad 2149835834 - .quad 2149835926 - .quad 2149836018 - .quad 2149836328 - .quad 2149836420 - .quad 2149836512 - .quad 2149836732 - .quad 2149836930 - .quad 2149837086 - .quad 2149837086 - .quad 2149837182 - .quad 2149837274 - .quad 2149837368 - .quad 2149837716 - .quad 2149837808 - .quad 2149837894 - .quad 2149838116 - .quad 2149838400 - .quad 2149838620 - .quad 2149839028 - .quad 2149839248 - .quad 2149839502 - .quad 2149839658 - .quad 2149839746 - .quad 2149839926 - .quad 2149840150 - .quad 2149840330 + .quad 2149818836 + .quad 2149819002 + .quad 2149820148 + .quad 2149821242 + .quad 2149821620 + .quad 2149821634 + .quad 2149821638 + .quad 2149821650 + .quad 2149821656 + .quad 2149821668 + .quad 2149821682 + .quad 2149821686 + .quad 2149821692 + .quad 2149822588 + .quad 2149823068 + .quad 2149823732 + .quad 2149823746 + .quad 2149823800 + .quad 2149823814 + .quad 2149823828 + .quad 2149823834 + .quad 2149823840 + .quad 2149823886 + .quad 2149823890 + .quad 2149823902 + .quad 2149823914 + .quad 2149823926 + .quad 2149823932 + .quad 2149823944 + .quad 2149823954 + .quad 2149823964 + .quad 2149823974 + .quad 2149823984 + .quad 2149823994 + .quad 2149824004 + .quad 2149824014 + .quad 2149824054 + .quad 2149824084 + .quad 2149824210 + .quad 2149824212 + .quad 2149824222 + .quad 2149824226 + .quad 2149824236 + .quad 2149824248 + .quad 2149824252 + .quad 2149824552 + .quad 2149824828 + .quad 2149825796 + .quad 2149826436 + .quad 2149827278 + .quad 2149828120 + .quad 2149828618 + .quad 2149829224 + .quad 2149829442 + .quad 2149830498 + .quad 2149830986 + .quad 2149831694 + .quad 2149832830 + .quad 2149833148 + .quad 2149834794 + .quad 2149835704 + .quad 2149835784 + .quad 2149835864 + .quad 2149835944 + .quad 2149836024 + .quad 2149836104 + .quad 2149836184 + .quad 2149836264 + .quad 2149836344 + .quad 2149836424 + .quad 2149836504 + .quad 2149836584 + .quad 2149836664 + .quad 2149836744 + .quad 2149836824 + .quad 2149836904 + .quad 2149836984 + .quad 2149837064 + .quad 2149837144 + .quad 2149837224 + .quad 2149837304 + .quad 2149837384 + .quad 2149837392 + .quad 2149837402 + .quad 2149837442 + .quad 2149837568 + .quad 2149837568 + .quad 2149837568 + .quad 2149837568 + .quad 2149837570 + .quad 2149837674 + .quad 2149837752 + .quad 2149837834 + .quad 2149838210 + .quad 2149838568 + .quad 2149838644 + .quad 2149838722 + .quad 2149838772 + .quad 2149838822 + .quad 2149839068 + .quad 2149839212 + .quad 2149839800 + .quad 2149839878 .quad 2149840420 - .quad 2149840442 - .quad 2149840746 - .quad 2149840838 - .quad 2149841246 - .quad 2149841654 - .quad 2149841834 - .quad 2149841924 - .quad 2149842080 - .quad 2149842096 - .quad 2149842228 - .quad 2149842450 - .quad 2149842450 - .quad 2149842450 - .quad 2149842450 - .quad 2149842450 - .quad 2149842450 - .quad 2149842450 - .quad 2149842450 - .quad 2149842450 - .quad 2149842450 - .quad 2149842450 - .quad 2149842450 - .quad 2149842450 - .quad 2149842454 - .quad 2149842454 - .quad 2149842660 - .quad 2149842754 - .quad 2149842838 - .quad 2149842950 - .quad 2149843044 - .quad 2149843164 - .quad 2149843258 - .quad 2149843350 - .quad 2149843446 - .quad 2149843532 - .quad 2149843540 - .quad 2149843548 - .quad 2149843564 - .quad 2149843716 - .quad 2149843724 - .quad 2149843732 - .quad 2149843888 - .quad 2149843896 - .quad 2149843912 - .quad 2149843920 - .quad 2149844012 - .quad 2149844020 - .quad 2149844088 - .quad 2149844096 - .quad 2149844252 - .quad 2149844344 - .quad 2149844432 - .quad 2149844578 - .quad 2149844670 - .quad 2149844678 - .quad 2149844798 - .quad 2149844886 - .quad 2149845186 - .quad 2149845278 - .quad 2149845286 - .quad 2149845286 - .quad 2149845382 - .quad 2149845390 - .quad 2149845548 - .quad 2149845556 - .quad 2149845556 - .quad 2149845646 - .quad 2149845802 - .quad 2149845922 - .quad 2149846006 - .quad 2149846028 - .quad 2149846138 - .quad 2149846230 - .quad 2149846320 - .quad 2149846408 - .quad 2149846430 - .quad 2149846438 - .quad 2149846530 - .quad 2149846622 - .quad 2149846630 - .quad 2149846722 - .quad 2149846810 - .quad 2149846818 - .quad 2149846826 - .quad 2149846846 - .quad 2149846922 - .quad 2149846930 - .quad 2149847056 - .quad 2149847132 - .quad 2149847312 - .quad 2149847402 - .quad 2149847706 - .quad 2149847886 - .quad 2149847978 - .quad 2149848072 - .quad 2149848080 - .quad 2149848160 - .quad 2149848244 - .quad 2149848312 - .quad 2149848400 - .quad 2149848492 - .quad 2149848636 - .quad 2149848816 - .quad 2149848966 - .quad 2149849058 - .quad 2149849158 - .quad 2149849246 - .quad 2149849254 - .quad 2149849534 - .quad 2149849834 - .quad 2149849952 - .quad 2149850046 - .quad 2149850054 - .quad 2149850148 - .quad 2149850156 - .quad 2149850316 - .quad 2149850410 - .quad 2149850502 - .quad 2149850622 - .quad 2149850630 - .quad 2149850722 - .quad 2149850914 - .quad 2149850996 - .quad 2149851004 - .quad 2149851096 - .quad 2149851104 - .quad 2149851248 - .quad 2149851340 - .quad 2149851420 - .quad 2149851428 + .quad 2149840670 + .quad 2149840722 + .quad 2149841276 + .quad 2149841632 + .quad 2149841912 + .quad 2149842032 + .quad 2149842210 + .quad 2149842418 + .quad 2149842710 + .quad 2149842720 + .quad 2149842730 + .quad 2149842750 + .quad 2149842760 + .quad 2149842802 + .quad 2149842812 + .quad 2149842814 + .quad 2149842930 + .quad 2149843002 + .quad 2149843080 + .quad 2149843324 + .quad 2149843690 + .quad 2149843792 + .quad 2149843870 + .quad 2149843890 + .quad 2149843932 + .quad 2149843932 + .quad 2149843932 + .quad 2149843932 + .quad 2149843932 + .quad 2149843932 + .quad 2149843934 + .quad 2149843968 + .quad 2149844216 + .quad 2149844396 + .quad 2149844734 + .quad 2149844970 + .quad 2149844980 + .quad 2149844982 + .quad 2149845380 + .quad 2149847420 + .quad 2149847640 + .quad 2149848128 + .quad 2149848548 + .quad 2149848634 + .quad 2149848898 + .quad 2149848936 + .quad 2149849442 + .quad 2149849616 + .quad 2149850122 + .quad 2149850284 + .quad 2149850308 + .quad 2149850310 + .quad 2149850490 + .quad 2149850508 + .quad 2149850526 + .quad 2149850536 + .quad 2149850546 + .quad 2149850556 + .quad 2149850566 + .quad 2149850576 + .quad 2149850586 + .quad 2149850596 + .quad 2149850606 + .quad 2149850616 + .quad 2149850626 + .quad 2149850636 + .quad 2149850646 + .quad 2149850656 + .quad 2149850666 + .quad 2149850676 + .quad 2149850686 + .quad 2149850696 + .quad 2149850706 + .quad 2149850716 + .quad 2149850726 + .quad 2149850736 + .quad 2149850746 + .quad 2149850756 + .quad 2149850766 + .quad 2149850776 + .quad 2149850786 + .quad 2149850796 + .quad 2149850806 + .quad 2149850816 + .quad 2149850826 + .quad 2149850836 + .quad 2149850846 + .quad 2149850856 + .quad 2149850866 + .quad 2149850876 + .quad 2149850886 + .quad 2149850896 + .quad 2149850906 + .quad 2149850916 + .quad 2149850926 + .quad 2149850944 + .quad 2149850962 + .quad 2149851098 + .quad 2149851134 + .quad 2149851282 + .quad 2149851312 + .quad 2149851342 + .quad 2149851344 + .quad 2149851374 + .quad 2149851404 + .quad 2149851406 .quad 2149851436 - .quad 2149851566 - .quad 2149851650 - .quad 2149851830 - .quad 2149851922 - .quad 2149852152 - .quad 2149852272 - .quad 2149852390 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852534 - .quad 2149852536 - .quad 2149852562 - .quad 2149852582 - .quad 2149852782 + .quad 2149851438 + .quad 2149851700 + .quad 2149851782 + .quad 2149851816 + .quad 2149851850 + .quad 2149851862 + .quad 2149851866 + .quad 2149851870 + .quad 2149851932 + .quad 2149851936 + .quad 2149851950 + .quad 2149851954 + .quad 2149851958 + .quad 2149851970 + .quad 2149851974 + .quad 2149851988 + .quad 2149852050 + .quad 2149852054 + .quad 2149852116 + .quad 2149852980 + .quad 2149852984 .quad 2149852992 - .quad 2149853302 - .quad 2149853574 - .quad 2149853884 - .quad 2149854156 - .quad 2149854538 - .quad 2149854882 - .quad 2149855272 - .quad 2149856808 - .quad 2149857572 - .quad 2149858320 - .quad 2149858330 - .quad 2149858340 - .quad 2149858350 - .quad 2149858360 - .quad 2149858370 - .quad 2149858380 - .quad 2149858390 - .quad 2149858400 - .quad 2149858410 - .quad 2149858420 - .quad 2149858430 - .quad 2149858440 - .quad 2149858450 - .quad 2149858460 - .quad 2149858470 - .quad 2149858480 - .quad 2149858490 - .quad 2149858500 - .quad 2149858510 - .quad 2149858520 - .quad 2149858530 - .quad 2149858540 - .quad 2149858550 - .quad 2149858560 - .quad 2149858570 - .quad 2149858580 - .quad 2149858590 - .quad 2149858600 - .quad 2149858618 - .quad 2149858636 - .quad 2149858638 - .quad 2149858638 - .quad 2149858638 - .quad 2149858640 - .quad 2149858910 - .quad 2149858912 - .quad 2149859224 - .quad 2149859254 - .quad 2149859284 - .quad 2149859314 - .quad 2149859316 - .quad 2149859346 - .quad 2149859376 - .quad 2149859964 - .quad 2149860620 - .quad 2149860846 - .quad 2149860846 - .quad 2149860928 - .quad 2149860928 - .quad 2149861158 - .quad 2149861362 - .quad 2149861362 - .quad 2149861616 - .quad 2149861616 - .quad 2149861616 - .quad 2149861848 - .quad 2149862078 - .quad 2149862308 - .quad 2149862492 - .quad 2149862492 - .quad 2149862746 - .quad 2149862990 - .quad 2149863214 - .quad 2149863476 - .quad 2149863706 - .quad 2149863706 - .quad 2149863936 - .quad 2149864140 - .quad 2149864394 - .quad 2149864656 - .quad 2149864918 - .quad 2149864926 - .quad 2149864930 - .quad 2149864934 - .quad 2149864938 - .quad 2149864946 - .quad 2149864954 - .quad 2149864958 - .quad 2149864970 - .quad 2149864982 - .quad 2149864998 - .quad 2149865014 - .quad 2149865030 - .quad 2149865044 - .quad 2149865058 - .quad 2149865072 - .quad 2149865078 - .quad 2149865084 - .quad 2149865090 - .quad 2149865096 + .quad 2149853000 + .quad 2149853008 + .quad 2149853016 + .quad 2149853024 + .quad 2149853028 + .quad 2149853040 + .quad 2149853052 + .quad 2149853064 + .quad 2149853076 + .quad 2149853092 + .quad 2149853108 + .quad 2149853124 + .quad 2149853136 + .quad 2149853150 + .quad 2149853164 + .quad 2149853178 + .quad 2149853184 + .quad 2149853190 + .quad 2149853196 + .quad 2149853202 + .quad 2149853208 + .quad 2149853214 + .quad 2149853228 + .quad 2149853242 + .quad 2149853256 + .quad 2149853270 + .quad 2149853284 + .quad 2149853298 + .quad 2149853312 + .quad 2149853326 + .quad 2149853340 + .quad 2149853352 + .quad 2149853364 + .quad 2149853376 + .quad 2149853382 + .quad 2149853388 + .quad 2149853394 + .quad 2149853398 + .quad 2149853402 + .quad 2149853728 + .quad 2149854042 + .quad 2149854356 + .quad 2149854700 + .quad 2149855052 + .quad 2149855404 + .quad 2149855600 + .quad 2149855672 + .quad 2149855726 + .quad 2149855972 + .quad 2149856000 + .quad 2149856084 + .quad 2149856130 + .quad 2149856134 + .quad 2149856146 + .quad 2149856150 + .quad 2149856154 + .quad 2149856162 + .quad 2149856176 + .quad 2149856180 + .quad 2149856184 + .quad 2149856246 + .quad 2149856250 + .quad 2149856520 + .quad 2149856860 + .quad 2149860892 + .quad 2149861148 + .quad 2149861348 + .quad 2149861412 + .quad 2149861614 + .quad 2149861614 + .quad 2149861614 + .quad 2149861614 + .quad 2149861614 + .quad 2149861614 + .quad 2149861614 + .quad 2149861614 + .quad 2149861614 + .quad 2149861730 + .quad 2149861730 + .quad 2149861868 + .quad 2149861868 + .quad 2149861912 + .quad 2149862084 + .quad 2149862248 + .quad 2149862248 + .quad 2149862440 + .quad 2149862628 + .quad 2149862674 + .quad 2149862784 + .quad 2149862988 + .quad 2149862988 + .quad 2149863088 + .quad 2149863410 + .quad 2149863590 + .quad 2149863882 + .quad 2149863982 + .quad 2149864184 + .quad 2149864354 + .quad 2149864432 + .quad 2149864530 + .quad 2149864594 + .quad 2149864622 + .quad 2149864622 + .quad 2149864854 + .quad 2149865074 + .quad 2149865092 .quad 2149865102 - .quad 2149865108 + .quad 2149865112 .quad 2149865122 - .quad 2149865136 - .quad 2149865150 - .quad 2149865164 - .quad 2149865178 + .quad 2149865132 + .quad 2149865142 + .quad 2149865152 + .quad 2149865162 + .quad 2149865172 + .quad 2149865182 .quad 2149865192 - .quad 2149865206 - .quad 2149865220 - .quad 2149865234 + .quad 2149865202 + .quad 2149865212 + .quad 2149865242 + .quad 2149865244 .quad 2149865246 - .quad 2149865258 - .quad 2149865270 - .quad 2149865276 - .quad 2149865282 - .quad 2149865288 - .quad 2149865292 - .quad 2149865296 - .quad 2149865644 - .quad 2149865992 - .quad 2149865996 - .quad 2149866008 - .quad 2149866012 - .quad 2149866074 - .quad 2149866078 - .quad 2149866090 - .quad 2149866152 - .quad 2149866226 - .quad 2149866230 - .quad 2149866244 - .quad 2149866248 - .quad 2149866262 - .quad 2149866266 - .quad 2149866328 - .quad 2149866332 - .quad 2149871770 - .quad 2149871772 - .quad 2149871778 - .quad 2149871780 - .quad 2149871788 - .quad 2149871792 - .quad 2149871800 - .quad 2149871814 - .quad 2149871818 - .quad 2149871822 - .quad 2149871884 - .quad 2149871888 - .quad 2149872150 - .quad 2149872482 - .quad 2149872730 - .quad 2149876354 - .quad 2149876442 - .quad 2149876530 - .quad 2149876618 - .quad 2149876706 - .quad 2149876794 - .quad 2149876882 - .quad 2149876970 - .quad 2149877058 - .quad 2149877146 - .quad 2149877234 - .quad 2149877322 - .quad 2149877410 - .quad 2149877498 - .quad 2149877586 - .quad 2149877674 - .quad 2149877762 - .quad 2149878460 - .quad 2149879958 - .quad 2149880634 - .quad 2149880722 - .quad 2149880810 - .quad 2149880898 - .quad 2149880986 - .quad 2149881074 - .quad 2149881162 - .quad 2149881250 - .quad 2149881338 - .quad 2149881426 - .quad 2149881514 - .quad 2149881602 - .quad 2149881690 - .quad 2149881778 - .quad 2149881866 - .quad 2149881972 - .quad 2149882184 - .quad 2149882376 - .quad 2149882566 - .quad 2149882584 - .quad 2149882594 - .quad 2149882604 - .quad 2149882614 - .quad 2149882624 - .quad 2149882634 - .quad 2149882674 - .quad 2149883212 - .quad 2149883478 - .quad 2149884018 - .quad 2149884040 - .quad 2149884070 - .quad 2149884212 - .quad 2149884212 - .quad 2149884212 - .quad 2149884212 - .quad 2149884214 - .quad 2149884216 - .quad 2149884226 - .quad 2149884308 - .quad 2149884672 - .quad 2149884824 - .quad 2149885462 - .quad 2149885858 - .quad 2149885870 - .quad 2149885882 - .quad 2149885886 - .quad 2149885898 - .quad 2149885910 - .quad 2149885916 - .quad 2149886020 - .quad 2149886396 - .quad 2149886754 - .quad 2149886764 - .quad 2149886776 - .quad 2149886852 - .quad 2149886930 - .quad 2149886980 - .quad 2149887030 - .quad 2149887034 - .quad 2149887038 - .quad 2149887284 - .quad 2149887428 - .quad 2149888030 - .quad 2149888572 - .quad 2149888838 - .quad 2149889408 - .quad 2149889772 - .quad 2149890052 - .quad 2149890172 - .quad 2149890464 - .quad 2149890802 - .quad 2149891456 - .quad 2149891942 - .quad 2149892030 - .quad 2149892118 - .quad 2149895106 - .quad 2149895194 - .quad 2149895282 - .quad 2149895370 - .quad 2149895458 - .quad 2149896304 - .quad 2149896970 - .quad 2149897508 - .quad 2149898770 - .quad 2149899544 - .quad 2149900586 - .quad 2149901680 - .quad 2149902612 - .quad 2149904290 - .quad 2149904770 - .quad 2149904858 - .quad 2149906062 - .quad 2149906512 - .quad 2149906722 - .quad 2149906810 - .quad 2149906898 - .quad 2149906986 - .quad 2149907074 - .quad 2149907156 - .quad 2149907238 - .quad 2149908078 - .quad 2149908572 - .quad 2149909036 - .quad 2149910622 - .quad 2149911222 - .quad 2149912338 - .quad 2149912630 - .quad 2149912640 - .quad 2149912650 - .quad 2149912670 - .quad 2149912860 - .quad 2149913146 - .quad 2149913168 - .quad 2149913190 - .quad 2149913212 - .quad 2149913212 - .quad 2149913212 - .quad 2149913212 - .quad 2149913212 - .quad 2149913212 - .quad 2149913212 - .quad 2149913212 - .quad 2149913212 - .quad 2149913212 - .quad 2149913212 - .quad 2149913214 - .quad 2149913214 - .quad 2149913214 - .quad 2149913216 - .quad 2149913242 - .quad 2149913244 - .quad 2149913338 - .quad 2149913358 - .quad 2149913440 - .quad 2149913534 - .quad 2149913534 - .quad 2149913824 - .quad 2149914078 - .quad 2149914420 - .quad 2149914508 - .quad 2149914594 - .quad 2149914686 - .quad 2149914938 - .quad 2149915130 - .quad 2149915418 - .quad 2149915702 - .quad 2149916042 - .quad 2149916276 - .quad 2149916620 - .quad 2149916932 - .quad 2149917402 - .quad 2149918074 - .quad 2149918204 - .quad 2149918234 - .quad 2149918310 - .quad 2149918438 - .quad 2149918528 - .quad 2149918670 - .quad 2149919134 - .quad 2149919438 - .quad 2149919976 - .quad 2149920354 - .quad 2149920832 - .quad 2149921012 - .quad 2149921278 - .quad 2149921710 - .quad 2149921728 - .quad 2149921746 - .quad 2149921788 - .quad 2149921798 - .quad 2149921808 - .quad 2149921818 - .quad 2149921838 - .quad 2149921848 - .quad 2149921870 - .quad 2149921912 - .quad 2149922030 - .quad 2149922050 - .quad 2149922092 - .quad 2149922134 - .quad 2149922144 - .quad 2149922154 - .quad 2149922196 - .quad 2149922206 - .quad 2149922216 - .quad 2149922258 - .quad 2149922268 - .quad 2149922278 - .quad 2149922288 - .quad 2149922298 - .quad 2149922308 - .quad 2149922318 - .quad 2149922328 - .quad 2149922348 - .quad 2149922388 - .quad 2149922428 - .quad 2149922468 - .quad 2149922486 - .quad 2149922504 - .quad 2149922506 - .quad 2149922508 - .quad 2149922606 - .quad 2149923236 - .quad 2149923236 - .quad 2149923236 - .quad 2149923246 - .quad 2149923334 - .quad 2149923712 - .quad 2149923732 - .quad 2149923752 - .quad 2149923954 - .quad 2149924008 - .quad 2149924062 - .quad 2149924108 - .quad 2149924154 - .quad 2149924530 - .quad 2149924580 - .quad 2149924674 - .quad 2149925854 - .quad 2149925882 - .quad 2149925894 - .quad 2149925906 - .quad 2149925918 - .quad 2149925920 - .quad 2149925924 - .quad 2149925936 - .quad 2149925942 - .quad 2149925952 - .quad 2149925964 - .quad 2149925968 - .quad 2149926206 - .quad 2149927506 - .quad 2149927720 - .quad 2149929488 - .quad 2149930618 - .quad 2149930960 - .quad 2149932028 - .quad 2149932436 - .quad 2149934932 - .quad 2149935462 - .quad 2149935692 - .quad 2149935948 - .quad 2149936162 - .quad 2149936736 - .quad 2149938926 - .quad 2149939168 - .quad 2149940662 - .quad 2149940978 - .quad 2149941344 - .quad 2149941914 - .quad 2149943686 - .quad 2149945196 - .quad 2149945468 - .quad 2149946538 - .quad 2149946858 - .quad 2149948052 - .quad 2149950950 - .quad 2149950960 - .quad 2149951038 - .quad 2149951040 - .quad 2149951042 - .quad 2149951246 - .quad 2149951376 - .quad 2149951376 - .quad 2149951376 - .quad 2149951376 - .quad 2149951376 - .quad 2149951508 - .quad 2149951508 - .quad 2149951508 - .quad 2149951508 - .quad 2149951508 - .quad 2149951508 - .quad 2149951508 - .quad 2149951640 - .quad 2149951640 - .quad 2149951772 - .quad 2149951772 - .quad 2149951910 - .quad 2149952060 - .quad 2149952200 - .quad 2149952342 - .quad 2149952482 - .quad 2149952616 - .quad 2149952616 - .quad 2149952750 - .quad 2149952892 - .quad 2149952900 - .quad 2149953274 - .quad 2149953518 - .quad 2149955830 - .quad 2149958200 - .quad 2149958552 - .quad 2149958718 - .quad 2149958884 - .quad 2149959098 - .quad 2149959950 - .quad 2149961084 - .quad 2149961172 - .quad 2149961260 - .quad 2149961348 - .quad 2149961436 - .quad 2149961524 - .quad 2149961612 - .quad 2149961700 - .quad 2149961788 - .quad 2149961876 - .quad 2149961964 - .quad 2149962052 - .quad 2149962140 - .quad 2149962228 - .quad 2149962316 - .quad 2149962404 - .quad 2149962492 - .quad 2149962580 - .quad 2149962668 - .quad 2149962756 - .quad 2149962844 - .quad 2149962932 - .quad 2149963020 - .quad 2149963108 - .quad 2149963196 - .quad 2149963284 - .quad 2149963372 - .quad 2149963460 - .quad 2149963548 - .quad 2149963636 - .quad 2149963724 - .quad 2149963802 - .quad 2149963890 - .quad 2149963978 - .quad 2149964066 - .quad 2149964672 - .quad 2149964760 - .quad 2149964848 - .quad 2149964936 - .quad 2149965024 - .quad 2149965112 - .quad 2149965200 - .quad 2149965288 - .quad 2149965376 - .quad 2149965464 - .quad 2149965482 - .quad 2149965500 - .quad 2149965518 - .quad 2149965536 - .quad 2149965554 - .quad 2149965572 - .quad 2149965582 - .quad 2149965592 - .quad 2149965602 - .quad 2149965612 - .quad 2149965622 - .quad 2149965632 - .quad 2149965642 - .quad 2149965652 - .quad 2149965662 - .quad 2149965672 - .quad 2149965682 - .quad 2149965692 - .quad 2149965702 - .quad 2149965712 - .quad 2149965722 - .quad 2149965732 - .quad 2149965742 - .quad 2149965752 - .quad 2149965762 - .quad 2149965772 - .quad 2149965782 - .quad 2149965792 - .quad 2149965802 - .quad 2149965812 - .quad 2149965822 - .quad 2149965832 - .quad 2149965842 - .quad 2149965852 - .quad 2149965862 - .quad 2149965872 - .quad 2149965882 - .quad 2149965892 - .quad 2149965902 - .quad 2149965912 - .quad 2149965922 - .quad 2149965932 - .quad 2149965942 - .quad 2149965952 - .quad 2149965962 - .quad 2149965972 - .quad 2149965982 - .quad 2149965992 - .quad 2149966002 - .quad 2149966042 - .quad 2149966328 - .quad 2149966350 - .quad 2149966368 - .quad 2149966370 - .quad 2149966400 - .quad 2149966436 - .quad 2149966560 - .quad 2149966570 - .quad 2149966750 - .quad 2149966752 - .quad 2149966778 - .quad 2149966854 - .quad 2149966856 - .quad 2149967000 - .quad 2149967060 - .quad 2149967080 - .quad 2149967342 - .quad 2149967424 - .quad 2149968562 - .quad 2149970460 - .quad 2149970826 - .quad 2149971228 - .quad 2149971354 - .quad 2149972354 - .quad 2149972358 - .quad 2149972366 - .quad 2149972374 - .quad 2149973254 - .quad 2149973262 - .quad 2149973274 - .quad 2149973278 - .quad 2149973290 - .quad 2149973298 - .quad 2149973306 - .quad 2149973310 - .quad 2149973314 - .quad 2149973326 - .quad 2149973338 - .quad 2149973350 - .quad 2149973366 - .quad 2149973382 - .quad 2149973394 - .quad 2149973406 - .quad 2149973420 - .quad 2149973426 - .quad 2149973480 - .quad 2149973486 - .quad 2149973500 - .quad 2149973514 - .quad 2149973528 - .quad 2149973540 - .quad 2149973546 - .quad 2149973592 - .quad 2149973596 - .quad 2149973608 - .quad 2149973612 - .quad 2149973616 - .quad 2149973626 - .quad 2149973644 - .quad 2149973660 - .quad 2149973852 - .quad 2149974118 - .quad 2149974334 - .quad 2149974492 - .quad 2149974762 - .quad 2149975050 - .quad 2149975286 - .quad 2149975522 - .quad 2149975730 - .quad 2149975892 - .quad 2149976086 - .quad 2149976172 - .quad 2149976254 - .quad 2149976342 - .quad 2149977354 - .quad 2149977582 - .quad 2149977662 - .quad 2149977750 - .quad 2149977838 - .quad 2149978352 - .quad 2149978480 - .quad 2149978580 - .quad 2149978590 - .quad 2149978604 - .quad 2149978608 - .quad 2149978612 - .quad 2149978676 - .quad 2149978680 - .quad 2149978744 - .quad 2149980090 - .quad 2149986980 - .quad 2149987110 - .quad 2149988338 - .quad 2149990004 - .quad 2149990166 - .quad 2149990370 - .quad 2149991854 - .quad 2149992036 - .quad 2149992218 - .quad 2149992218 - .quad 2149992240 - .quad 2149992328 - .quad 2149992416 - .quad 2149992506 - .quad 2149992506 - .quad 2149992672 - .quad 2149993846 - .quad 2149994966 - .quad 2149995344 - .quad 2149995358 - .quad 2149995362 - .quad 2149995374 - .quad 2149995380 - .quad 2149995392 - .quad 2149995406 - .quad 2149995410 - .quad 2149995416 - .quad 2149996320 - .quad 2149996550 - .quad 2149996588 - .quad 2149996676 - .quad 2149996764 - .quad 2149996852 - .quad 2149996940 - .quad 2149997028 - .quad 2149997116 - .quad 2149997204 - .quad 2149997292 - .quad 2149998996 - .quad 2149999084 - .quad 2149999098 - .quad 2149999152 - .quad 2149999166 - .quad 2149999180 - .quad 2149999186 - .quad 2149999192 - .quad 2149999238 - .quad 2149999326 - .quad 2149999414 - .quad 2149999502 - .quad 2149999590 - .quad 2149999678 - .quad 2149999766 - .quad 2149999854 - .quad 2149999942 - .quad 2150000030 - .quad 2150000118 - .quad 2150001460 - .quad 2150001478 - .quad 2150001496 - .quad 2150001514 - .quad 2150001532 - .quad 2150001540 - .quad 2150001550 - .quad 2150001560 - .quad 2150001570 - .quad 2150001580 - .quad 2150001590 - .quad 2150001600 - .quad 2150001610 - .quad 2150001620 - .quad 2150001642 - .quad 2150001682 - .quad 2150001722 - .quad 2150001728 - .quad 2150001872 - .quad 2150001874 - .quad 2150001944 - .quad 2150001964 - .quad 2150001984 - .quad 2150002466 - .quad 2150002466 - .quad 2150002600 - .quad 2150002610 - .quad 2150002898 - .quad 2150002898 - .quad 2150003040 - .quad 2150003094 - .quad 2150003094 - .quad 2150003148 - .quad 2150003148 - .quad 2150003194 - .quad 2150003240 - .quad 2150003244 - .quad 2150003248 - .quad 2150003380 - .quad 2150003576 - .quad 2150003666 - .quad 2150003720 - .quad 2150004028 - .quad 2150004156 - .quad 2150004264 - .quad 2150004348 - .quad 2150004394 - .quad 2150004536 - .quad 2150004566 - .quad 2150004596 - .quad 2150004688 - .quad 2150004780 - .quad 2150005846 - .quad 2150008012 - .quad 2150008618 - .quad 2150009516 - .quad 2150010258 - .quad 2150010596 - .quad 2150010784 - .quad 2150011226 - .quad 2150011558 - .quad 2150012166 - .quad 2150013246 - .quad 2150013874 - .quad 2150014436 - .quad 2150014700 - .quad 2150015482 - .quad 2150016060 - .quad 2150016408 - .quad 2150016756 - .quad 2150017894 - .quad 2150018526 - .quad 2150019116 - .quad 2150020040 - .quad 2150020872 - .quad 2150021814 - .quad 2150022632 - .quad 2150023026 - .quad 2150024046 - .quad 2150024610 - .quad 2150025184 - .quad 2150025946 - .quad 2150026716 - .quad 2150026894 - .quad 2150027068 - .quad 2150027796 - .quad 2150028282 - .quad 2150028696 - .quad 2150029658 - .quad 2150029856 - .quad 2150029874 - .quad 2150029892 - .quad 2150029910 - .quad 2150029928 - .quad 2150029946 - .quad 2150029964 - .quad 2150029982 - .quad 2150029992 - .quad 2150030002 - .quad 2150030012 - .quad 2150030022 - .quad 2150030032 - .quad 2150030042 - .quad 2150030052 - .quad 2150030062 - .quad 2150030072 - .quad 2150030082 - .quad 2150030092 - .quad 2150030102 - .quad 2150030112 - .quad 2150030122 - .quad 2150030132 - .quad 2150030142 - .quad 2150030152 - .quad 2150030162 - .quad 2150030180 - .quad 2150030248 - .quad 2150030392 - .quad 2150030572 - .quad 2150030678 - .quad 2150030680 - .quad 2150030682 - .quad 2150030944 - .quad 2150031026 - .quad 2150031060 - .quad 2150031094 - .quad 2150031128 - .quad 2150031162 - .quad 2150031196 - .quad 2150031230 - .quad 2150031264 - .quad 2150031298 - .quad 2150032386 - .quad 2150032866 - .quad 2150033726 - .quad 2150034262 - .quad 2150034648 - .quad 2150036642 - .quad 2150037078 - .quad 2150038918 - .quad 2150039552 - .quad 2150039744 - .quad 2150039936 - .quad 2150040128 - .quad 2150040220 - .quad 2150040310 - .quad 2150040906 - .quad 2150041192 - .quad 2150041474 - .quad 2150041740 - .quad 2150041812 - .quad 2150041890 - .quad 2150041962 - .quad 2150042040 - .quad 2150042518 - .quad 2150043402 - .quad 2150044360 - .quad 2150045458 - .quad 2150045732 - .quad 2150045740 - .quad 2150045744 - .quad 2150045756 - .quad 2150045768 - .quad 2150045784 - .quad 2150045796 - .quad 2150045850 - .quad 2150045904 - .quad 2150045958 - .quad 2150046004 - .quad 2150046050 - .quad 2150046096 - .quad 2150046350 - .quad 2150046368 - .quad 2150046372 - .quad 2150046386 - .quad 2150046516 - .quad 2150046588 - .quad 2150046642 - .quad 2150046648 - .quad 2150046662 - .quad 2150046680 - .quad 2150046694 - .quad 2150046932 - .quad 2150046944 - .quad 2150046948 - .quad 2150046952 - .quad 2150046952 - .quad 2150047036 - .quad 2150047082 - .quad 2150047168 - .quad 2150047254 - .quad 2150047340 - .quad 2150047422 - .quad 2150047508 - .quad 2150047594 - .quad 2150048628 - .quad 2150048632 - .quad 2150048720 - .quad 2150048792 - .quad 2150048806 - .quad 2150049166 - .quad 2150049178 - .quad 2150049182 - .quad 2150049186 - .quad 2150049214 - .quad 2150049430 - .quad 2150049732 - .quad 2150049864 - .quad 2150050060 - .quad 2150050150 - .quad 2150050204 - .quad 2150050512 - .quad 2150050620 - .quad 2150050820 - .quad 2150050866 - .quad 2150050936 - .quad 2150050974 - .quad 2150051132 - .quad 2150051160 - .quad 2150051612 - .quad 2150052582 - .quad 2150052670 - .quad 2150052822 - .quad 2150053188 - .quad 2150053272 - .quad 2150053668 - .quad 2150053806 - .quad 2150054722 - .quad 2150054810 - .quad 2150055178 - .quad 2150055394 - .quad 2150055476 - .quad 2150056006 - .quad 2150056134 - .quad 2150056234 - .quad 2150056490 - .quad 2150056884 - .quad 2150057418 - .quad 2150057630 - .quad 2150058166 - .quad 2150058858 - .quad 2150059234 - .quad 2150059770 - .quad 2150060608 - .quad 2150061096 - .quad 2150061500 - .quad 2150061554 - .quad 2150061556 - .quad 2150062502 - .quad 2150062804 - .quad 2150062822 - .quad 2150062844 - .quad 2150062946 - .quad 2150062988 - .quad 2150062992 - .quad 2150062998 - .quad 2150063002 - .quad 2150063044 - .quad 2150063046 - .quad 2150063218 - .quad 2150063238 - .quad 2150063280 - .quad 2150063280 - .quad 2150063280 - .quad 2150063280 - .quad 2150063280 - .quad 2150063280 - .quad 2150063282 - .quad 2150063316 - .quad 2150063564 - .quad 2150063744 - .quad 2150064082 - .quad 2150064318 - .quad 2150064328 - .quad 2150064330 - .quad 2150064728 - .quad 2150066768 - .quad 2150066988 - .quad 2150067476 - .quad 2150067896 - .quad 2150067982 - .quad 2150068246 - .quad 2150068284 - .quad 2150068790 - .quad 2150068964 - .quad 2150069470 - .quad 2150069632 - .quad 2150069656 - .quad 2150069658 - .quad 2150069838 - .quad 2150071310 - .quad 2150072200 - .quad 2150072642 - .quad 2150072682 - .quad 2150072750 - .quad 2150072818 - .quad 2150072822 - .quad 2150072826 - .quad 2150072826 - .quad 2150072912 - .quad 2150072912 - .quad 2150072998 - .quad 2150073238 - .quad 2150073238 - .quad 2150073922 - .quad 2150073964 - .quad 2150074036 - .quad 2150074094 - .quad 2150074128 - .quad 2150074130 - .quad 2150074198 - .quad 2150074234 - .quad 2150074302 - .quad 2150074444 - .quad 2150074770 - .quad 2150074934 - .quad 2150075290 - .quad 2150075944 - .quad 2150076278 - .quad 2150076320 - .quad 2150076682 - .quad 2150076748 - .quad 2150077300 - .quad 2150077820 - .quad 2150078268 - .quad 2150078896 - .quad 2150078978 - .quad 2150079020 - .quad 2150079062 - .quad 2150079104 - .quad 2150079114 - .quad 2150079124 - .quad 2150079126 - .quad 2150079388 - .quad 2150079550 - .quad 2150079692 - .quad 2150079814 - .quad 2150079948 - .quad 2150080232 - .quad 2150080350 - .quad 2150080670 - .quad 2150080720 - .quad 2150080796 - .quad 2150080922 - .quad 2150080974 - .quad 2150081014 - .quad 2150081196 - .quad 2150081354 - .quad 2150081394 - .quad 2150081434 - .quad 2150081474 - .quad 2150081476 - .quad 2150081478 - .quad 2150081480 - .quad 2150081482 - .quad 2150081802 - .quad 2150081838 - .quad 2150081900 - .quad 2150081982 - .quad 2150082678 - .quad 2150082842 - .quad 2150083398 - .quad 2150083580 - .quad 2150083656 - .quad 2150083770 - .quad 2150083772 - .quad 2150083842 - .quad 2150083848 - .quad 2150083880 - .quad 2150083902 - .quad 2150083920 - .quad 2150083932 - .quad 2150083942 - .quad 2150083948 - .quad 2150083962 - .quad 2150084186 - .quad 2150084262 - .quad 2150084296 - .quad 2150084310 - .quad 2150084318 - .quad 2150084364 - .quad 2150084468 - .quad 2150084588 - .quad 2150084590 - .quad 2150084634 - .quad 2150085488 - .quad 2150086140 - .quad 2150086790 - .quad 2150086832 - .quad 2150086874 - .quad 2150086916 - .quad 2150086926 - .quad 2150086966 - .quad 2150086968 - .quad 2150086970 - .quad 2150087074 - .quad 2150087372 - .quad 2150087492 - .quad 2150087532 - .quad 2150087572 - .quad 2150087574 + .quad 2149865246 + .quad 2149865246 + .quad 2149865434 + .quad 2149865864 + .quad 2149866128 + .quad 2149866368 + .quad 2149866798 + .quad 2149867102 + .quad 2149867532 + .quad 2149867940 + .quad 2149868188 + .quad 2149868428 + .quad 2149868754 + .quad 2149869084 + .quad 2149869270 + .quad 2149869278 + .quad 2149869282 + .quad 2149869294 + .quad 2149869310 + .quad 2149869322 + .quad 2149869336 + .quad 2149869342 + .quad 2149869396 + .quad 2149869402 + .quad 2149869416 + .quad 2149869430 + .quad 2149869444 + .quad 2149869456 + .quad 2149869462 + .quad 2149869508 + .quad 2149869844 + .quad 2149870198 + .quad 2149870504 + .quad 2149870814 + .quad 2149871176 + .quad 2149871530 + .quad 2149871558 + .quad 2149871568 + .quad 2149871582 + .quad 2149871586 + .quad 2149871590 + .quad 2149871654 + .quad 2149871658 + .quad 2149871722 + .quad 2149872970 + .quad 2149874750 + .quad 2149874750 + .quad 2149874750 + .quad 2149876660 + .quad 2149878288 + .quad 2149880006 + .quad 2149881660 + .quad 2149883546 + .quad 2149884066 + .quad 2149884522 + .quad 2149885000 + .quad 2149885516 + .quad 2149886044 + .quad 2149886602 + .quad 2149887166 + .quad 2149887670 + .quad 2149888164 + .quad 2149888684 + .quad 2149889220 + .quad 2149889746 + .quad 2149890206 + .quad 2149890666 + .quad 2149891094 + .quad 2149891544 + .quad 2149892194 + .quad 2149892888 + .quad 2149893574 + .quad 2149894254 + .quad 2149894514 + .quad 2149894728 + .quad 2149894918 + .quad 2149895166 + .quad 2149895166 + .quad 2149895372 + .quad 2149895574 + .quad 2149895780 + .quad 2149895986 + .quad 2149896192 + .quad 2149896210 + .quad 2149896228 + .quad 2149896246 + .quad 2149896264 + .quad 2149896282 + .quad 2149896292 + .quad 2149896302 + .quad 2149896312 + .quad 2149896322 + .quad 2149896322 + .quad 2149896332 + .quad 2149896342 + .quad 2149896352 + .quad 2149896362 + .quad 2149896372 + .quad 2149896382 + .quad 2149896392 + .quad 2149896402 + .quad 2149896538 + .quad 2149896686 + .quad 2149896784 + .quad 2149897794 + .quad 2149897794 + .quad 2149898342 + .quad 2149898342 + .quad 2149899060 + .quad 2149899060 + .quad 2149899060 + .quad 2149899144 + .quad 2149899144 + .quad 2149900690 + .quad 2149900698 + .quad 2149900710 + .quad 2149900722 + .quad 2149900738 + .quad 2149900750 + .quad 2149900804 + .quad 2149900858 + .quad 2149900912 + .quad 2149900966 + .quad 2149901012 + .quad 2149901058 + .quad 2149901104 + .quad 2149901150 + .quad 2149901168 + .quad 2149901172 + .quad 2149901186 + .quad 2149901316 + .quad 2149901388 + .quad 2149901442 + .quad 2149901448 + .quad 2149901462 + .quad 2149901480 + .quad 2149901494 + .quad 2149901726 + .quad 2149901738 + .quad 2149901742 + .quad 2149901746 + .quad 2149901792 + .quad 2149901796 + .quad 2149901810 + .quad 2149901822 + .quad 2149901826 + .quad 2149901830 + .quad 2149901834 + .quad 2149901878 + .quad 2149901896 + .quad 2149901914 + .quad 2149901932 + .quad 2149901942 + .quad 2149901952 + .quad 2149901962 + .quad 2149901972 + .quad 2149901982 + .quad 2149901992 + .quad 2149902002 + .quad 2149902012 + .quad 2149902022 + .quad 2149902032 + .quad 2149902042 + .quad 2149902052 + .quad 2149902082 + .quad 2149902330 + .quad 2149902476 + .quad 2149902486 + .quad 2149902488 + .quad 2149902610 + .quad 2149902700 + .quad 2149902838 + .quad 2149902970 + .quad 2149903102 + .quad 2149903236 + .quad 2149903376 + .quad 2149903518 + .quad 2149905318 + .quad 2149905322 + .quad 2149905334 + .quad 2149906002 + .quad 2149906762 + .quad 2149906770 + .quad 2149906774 + .quad 2149906786 + .quad 2149906798 + .quad 2149907046 + .quad 2149908090 + .quad 2149908298 + .quad 2149908438 + .quad 2149908784 + .quad 2149908970 + .quad 2149909314 + .quad 2149909406 + .quad 2149909502 + .quad 2149910170 + .quad 2149910306 + .quad 2149910450 + .quad 2149910462 + .quad 2149910466 + .quad 2149910480 + .quad 2149910494 + .quad 2149910506 + .quad 2149910510 + .quad 2149910514 + .quad 2149910656 + .quad 2149910738 + .quad 2149910876 + .quad 2149910944 + .quad 2149911796 + .quad 2149912332 + .quad 2149912710 + .quad 2149913060 + .quad 2149915030 + .quad 2149915458 + .quad 2149917282 + .quad 2149917908 + .quad 2149918100 + .quad 2149918292 + .quad 2149918574 + .quad 2149918840 + .quad 2149919318 + .quad 2149920352 + .quad 2149921212 + .quad 2149921230 + .quad 2149921248 + .quad 2149921266 + .quad 2149921284 + .quad 2149921352 + .quad 2149921362 + .quad 2149921372 + .quad 2149921382 + .quad 2149921382 + .quad 2149921392 + .quad 2149921402 + .quad 2149921412 + .quad 2149921422 + .quad 2149921432 + .quad 2149921442 + .quad 2149921452 + .quad 2149921462 + .quad 2149921472 + .quad 2149921502 + .quad 2149921750 + .quad 2149921786 + .quad 2149921934 + .quad 2149921936 + .quad 2149922226 + .quad 2149922748 + .quad 2149923232 + .quad 2149923406 + .quad 2149924064 + .quad 2149924558 + .quad 2149925250 + .quad 2149925380 + .quad 2149925452 + .quad 2149926436 + .quad 2149926440 + .quad 2149926448 + .quad 2149926942 + .quad 2149927292 + .quad 2149927300 + .quad 2149927304 + .quad 2149927316 + .quad 2149927328 + .quad 2149927340 + .quad 2149927532 + .quad 2149927586 + .quad 2149927640 + .quad 2149927686 + .quad 2149927732 + .quad 2149927736 + .quad 2149927750 + .quad 2149927764 + .quad 2149927776 + .quad 2149927780 + .quad 2149927784 + .quad 2149927908 + .quad 2149927990 + .quad 2149928070 + .quad 2149928088 + .quad 2149928106 + .quad 2149928116 + .quad 2149928126 + .quad 2149928136 + .quad 2149928146 + .quad 2149928156 + .quad 2149928166 + .quad 2149928176 + .quad 2149928186 + .quad 2149928196 + .quad 2149928206 + .quad 2149928216 + .quad 2149928226 + .quad 2149928236 + .quad 2149928246 + .quad 2149928256 + .quad 2149928266 + .quad 2149928276 + .quad 2149928286 + .quad 2149928296 + .quad 2149928306 + .quad 2149928336 + .quad 2149928382 + .quad 2149928530 + .quad 2149928676 + .quad 2149928762 + .quad 2149928770 + .quad 2149928778 + .quad 2149928782 + .quad 2149928794 + .quad 2149928806 + .quad 2149928822 + .quad 2149928834 + .quad 2149928852 + .quad 2149928858 + .quad 2149928872 + .quad 2149928878 + .quad 2149928892 + .quad 2149928906 + .quad 2149928920 + .quad 2149928932 + .quad 2149928938 + .quad 2149928942 + .quad 2149928942 + .quad 2149929072 + .quad 2149929072 + .quad 2149929144 + .quad 2149929198 + .quad 2149929206 + .quad 2149930252 + .quad 2149930270 + .quad 2149930770 + .quad 2149931008 + .quad 2149931020 + .quad 2149931024 + .quad 2149931028 + .quad 2149931028 + .quad 2149931112 + .quad 2149931404 + .quad 2149931422 + .quad 2149931554 + .quad 2149932390 + .quad 2149932398 + .quad 2149933574 + .quad 2149933592 + .quad 2149935194 + .quad 2149935340 + .quad 2149936306 + .quad 2149936544 + .quad 2149936652 + .quad 2149936944 + .quad 2149936956 + .quad 2149936960 + .quad 2149936964 + .quad 2149936982 + .quad 2149937000 + .quad 2149937018 + .quad 2149937036 + .quad 2149937046 + .quad 2149937056 + .quad 2149937066 + .quad 2149937076 + .quad 2149937212 + .quad 2149937404 + .quad 2149937496 + .quad 2149937586 + .quad 2149937856 + .quad 2149938732 + .quad 2149939682 + .quad 2149940772 + .quad 2149941046 + .quad 2149941046 + .quad 2149941100 + .quad 2149941100 + .quad 2149941146 + .quad 2149941400 + .quad 2149941486 + .quad 2149941572 + .quad 2149941658 + .quad 2149941740 + .quad 2149941826 + .quad 2149941912 + .quad 2149942000 + .quad 2149942072 + .quad 2149942072 + .quad 2149942126 + .quad 2149942486 + .quad 2149942486 + .quad 2149942570 + .quad 2149942570 + .quad 2149942616 + .quad 2149942620 + .quad 2149942624 + .quad 2149942652 + .quad 2149942868 + .quad 2149943170 + .quad 2149943302 + .quad 2149943498 + .quad 2149943588 + .quad 2149943896 + .quad 2149944004 + .quad 2149944204 + .quad 2149944296 + .quad 2149944388 + .quad 2149944398 + .quad 2149944648 + .quad 2149944650 + .quad 2149944650 + .quad 2149944732 + .quad 2149944732 + .quad 2149944986 + .quad 2149944986 + .quad 2149945216 + .quad 2149945470 + .quad 2149946598 + .quad 2149947694 + .quad 2149948292 + .quad 2149948672 + .quad 2149949516 + .quad 2149949700 + .quad 2149949760 + .quad 2149949812 + .quad 2149949938 + .quad 2149950010 + .quad 2149950248 + .quad 2149950486 + .quad 2149952558 + .quad 2149953480 + .quad 2149954814 + .quad 2149956572 + .quad 2149958150 + .quad 2149958278 + .quad 2149960962 + .quad 2149961972 + .quad 2149962882 + .quad 2149963796 + .quad 2149965478 + .quad 2149965488 + .quad 2149965670 + .quad 2149965846 + .quad 2149966014 + .quad 2149966016 + .quad 2149967546 + .quad 2149969444 + .quad 2149969810 + .quad 2149970212 + .quad 2149970338 + .quad 2149970524 + .quad 2149970710 + .quad 2149970996 + .quad 2149971284 + .quad 2149971528 + .quad 2149971546 + .quad 2149971564 + .quad 2149971574 + .quad 2149971584 + .quad 2149971594 + .quad 2149971604 + .quad 2149971614 + .quad 2149971624 + .quad 2149971634 + .quad 2149971644 + .quad 2149971654 + .quad 2149971664 + .quad 2149971674 + .quad 2149971684 + .quad 2149971714 + .quad 2149971980 + .quad 2149972126 + .quad 2149972284 + .quad 2149972286 + .quad 2149972288 + .quad 2149973602 + .quad 2149974478 + .quad 2149974486 + .quad 2149974490 + .quad 2149974502 + .quad 2149974518 + .quad 2149974530 + .quad 2149974542 + .quad 2149975078 + .quad 2149975082 + .quad 2149975096 + .quad 2149975228 + .quad 2149975318 + .quad 2149975372 + .quad 2149975382 + .quad 2149977030 + .quad 2149979422 + .quad 2149979432 + .quad 2149979446 + .quad 2149979624 + .quad 2149979636 + .quad 2149979640 + .quad 2149979644 + .quad 2149979728 + .quad 2149980604 + .quad 2149980828 + .quad 2149981056 + .quad 2149981390 + .quad 2149981394 + .quad 2149981484 + .quad 2149981490 + .quad 2149981504 + .quad 2149981518 + .quad 2149981770 + .quad 2149981782 + .quad 2149982004 + .quad 2149982050 + .quad 2149982068 + .quad 2149982078 + .quad 2149982088 + .quad 2149982098 + .quad 2149982108 + .quad 2149982118 + .quad 2149982128 + .quad 2149982138 + .quad 2149982148 + .quad 2149982158 + .quad 2149982168 + .quad 2149982178 + .quad 2149982188 + .quad 2149982198 + .quad 2149982208 + .quad 2149982218 + .quad 2149982228 + .quad 2149982238 + .quad 2149982248 + .quad 2149982258 + .quad 2149982268 + .quad 2149982278 + .quad 2149982288 + .quad 2149982298 + .quad 2149982308 + .quad 2149982490 + .quad 2149982512 + .quad 2149982530 + .quad 2149982560 + .quad 2149982808 + .quad 2149982844 + .quad 2149982960 + .quad 2149982970 + .quad 2149983116 + .quad 2149983118 + .quad 2149983186 + .quad 2149983188 + .quad 2149983240 + .quad 2149983244 + .quad 2149983252 + .quad 2149984282 + .quad 2149984294 + .quad 2149984918 + .quad 2149984922 + .quad 2149984934 + .quad 2149984942 + .quad 2149984946 + .quad 2149984958 + .quad 2149984970 + .quad 2149984982 + .quad 2149985274 + .quad 2149985278 + .quad 2149985290 + .quad 2149985294 + .quad 2149988014 + .quad 2149994638 + .quad 2149994662 + .quad 2149994680 + .quad 2149994698 + .quad 2149994716 + .quad 2149994726 + .quad 2149994768 + .quad 2149994810 + .quad 2149994820 + .quad 2149994842 + .quad 2149994852 + .quad 2149994862 + .quad 2149994872 + .quad 2149994882 + .quad 2149994902 + .quad 2149994912 + .quad 2149994914 + .quad 2149995050 + .quad 2149995068 + .quad 2149995070 + .quad 2149995090 + .quad 2149995184 + .quad 2149995438 + .quad 2149995438 + .quad 2149995492 + .quad 2149995492 + .quad 2149995538 + .quad 2149995542 + .quad 2149995546 + .quad 2149996210 + .quad 2149996546 + .quad 2149996678 + .quad 2149996874 + .quad 2149996964 + .quad 2149997018 + .quad 2149997326 + .quad 2149997454 + .quad 2149997562 + .quad 2149997646 + .quad 2149997692 + .quad 2149997876 + .quad 2149998142 + .quad 2149998358 + .quad 2149998516 + .quad 2149998786 + .quad 2149999074 + .quad 2149999310 + .quad 2149999546 + .quad 2149999754 + .quad 2149999916 + .quad 2150000110 + .quad 2150000196 + .quad 2150000278 + .quad 2150000300 + .quad 2150000388 + .quad 2150001376 + .quad 2150001596 + .quad 2150001676 + .quad 2150001764 + .quad 2150001852 + .quad 2150002018 + .quad 2150002050 + .quad 2150002588 + .quad 2150002708 + .quad 2150002800 + .quad 2150002920 + .quad 2150003012 + .quad 2150003014 + .quad 2150003016 + .quad 2150003056 + .quad 2150003058 + .quad 2150003346 + .quad 2150003582 + .quad 2150003584 + .quad 2150003586 + .quad 2150004166 + .quad 2150004824 + .quad 2150005032 + .quad 2150005052 + .quad 2150005060 + .quad 2150005064 + .quad 2150005068 + .quad 2150005072 + .quad 2150005146 + .quad 2150005150 + .quad 2150005162 + .quad 2150005164 + .quad 2150005172 + .quad 2150005178 + .quad 2150005184 + .quad 2150007014 + .quad 2150009658 + .quad 2150009698 + .quad 2150010514 + .quad 2150010554 + .quad 2150010556 + .quad 2150011180 + .quad 2150011180 + .quad 2150011180 + .quad 2150011180 + .quad 2150011296 + .quad 2150011466 + .quad 2150011582 + .quad 2150011958 + .quad 2150012008 + .quad 2150012102 + .quad 2150013126 + .quad 2150013726 + .quad 2150014076 + .quad 2150014218 + .quad 2150014248 + .quad 2150014278 + .quad 2150015106 + .quad 2150015904 + .quad 2150015904 + .quad 2150016134 + .quad 2150016364 + .quad 2150016594 + .quad 2150016868 + .quad 2150017098 + .quad 2150017322 + .quad 2150017340 + .quad 2150017382 + .quad 2150017424 + .quad 2150017444 + .quad 2150017446 + .quad 2150017480 + .quad 2150017568 + .quad 2150017628 + .quad 2150017688 + .quad 2150017716 + .quad 2150017744 + .quad 2150017836 + .quad 2150017906 + .quad 2150017944 + .quad 2150018094 + .quad 2150018122 + .quad 2150018414 + .quad 2150018536 + .quad 2150018668 + .quad 2150018678 + .quad 2150018746 + .quad 2150018930 + .quad 2150019192 + .quad 2150019704 + .quad 2150019952 + .quad 2150020330 + .quad 2150022048 + .quad 2150023676 + .quad 2150023792 + .quad 2150023916 + .quad 2150024056 + .quad 2150024280 + .quad 2150024522 + .quad 2150024630 + .quad 2150025656 + .quad 2150025660 + .quad 2150025664 + .quad 2150025938 + .quad 2150026068 + .quad 2150026198 + .quad 2150026316 + .quad 2150026432 + .quad 2150026442 + .quad 2150026464 + .quad 2150026474 + .quad 2150026492 + .quad 2150026508 + .quad 2150026940 + .quad 2150027062 + .quad 2150027194 + .quad 2150027332 + .quad 2150027464 + .quad 2150028622 + .quad 2150029770 + .quad 2150030390 + .quad 2150031804 + .quad 2150032522 + .quad 2150033526 + .quad 2150034056 + .quad 2150034248 + .quad 2150034438 + .quad 2150034650 + .quad 2150034970 + .quad 2150035856 + .quad 2150035856 + .quad 2150035858 + .quad 2150035892 + .quad 2150035926 + .quad 2150036106 + .quad 2150036186 + .quad 2150036274 + .quad 2150036628 + .quad 2150036844 + .quad 2150036926 + .quad 2150037236 + .quad 2150037334 + .quad 2150037336 + .quad 2150037338 + .quad 2150037696 + .quad 2150037780 + .quad 2150038162 + .quad 2150038300 + .quad 2150039004 + .quad 2150039020 + .quad 2150039040 + .quad 2150039054 + .quad 2150039056 + .quad 2150039068 + .quad 2150039152 + .quad 2150040886 + .quad 2150042692 + .quad 2150042784 + .quad 2150042884 + .quad 2150043050 + .quad 2150043216 + .quad 2150043236 + .quad 2150043256 + .quad 2150043430 + .quad 2150046370 + .quad 2150046370 + .quad 2150047046 + .quad 2150049304 + .quad 2150049834 + .quad 2150049876 + .quad 2150049918 + .quad 2150049920 + .quad 2150049922 + .quad 2150050762 + .quad 2150050850 + .quad 2150051002 + .quad 2150051384 + .quad 2150051782 + .quad 2150051974 + .quad 2150052364 + .quad 2150053832 + .quad 2150054414 + .quad 2150055162 + .quad 2150055176 + .quad 2150055184 + .quad 2150055198 + .quad 2150055210 + .quad 2150055316 + .quad 2150055410 + .quad 2150055450 + .quad 2150055452 + .quad 2150055606 + .quad 2150056248 + .quad 2150056740 + .quad 2150057000 + .quad 2150057020 + .quad 2150057030 + .quad 2150057050 + .quad 2150057128 + .quad 2150057528 + .quad 2150057538 + .quad 2150057560 + .quad 2150057580 + .quad 2150057628 + .quad 2150057646 + .quad 2150057664 + .quad 2150057800 + .quad 2150057922 + .quad 2150058062 + .quad 2150058080 + .quad 2150058126 + .quad 2150058334 + .quad 2150058492 + .quad 2150058624 + .quad 2150058632 + .quad 2150058636 + .quad 2150058678 + .quad 2150058688 + .quad 2150058728 + .quad 2150058730 + .quad 2150058812 + .quad 2150058894 + .quad 2150058934 + .quad 2150060464 + .quad 2150060890 + .quad 2150061300 + .quad 2150062186 + .quad 2150062740 + .quad 2150063312 + .quad 2150063884 + .quad 2150064268 + .quad 2150064502 + .quad 2150064600 + .quad 2150064982 + .quad 2150064984 + .quad 2150065208 + .quad 2150065556 + .quad 2150065888 + .quad 2150066310 + .quad 2150066560 + .quad 2150066836 + .quad 2150067322 + .quad 2150067664 + .quad 2150068122 + .quad 2150068324 + .quad 2150068782 + .quad 2150069350 + .quad 2150069672 + .quad 2150070198 + .quad 2150070848 + .quad 2150071256 + .quad 2150071258 + .quad 2150071592 + .quad 2150072278 + .quad 2150072874 + .quad 2150073392 + .quad 2150074026 + .quad 2150074564 + .quad 2150075578 + .quad 2150076048 + .quad 2150076332 + .quad 2150079300 + .quad 2150079534 + .quad 2150080758 + .quad 2150080992 + .quad 2150081226 + .quad 2150082400 + .quad 2150083866 + .quad 2150084116 + .quad 2150084380 + .quad 2150084470 + .quad 2150084604 + .quad 2150085242 + .quad 2150085492 + .quad 2150086060 + .quad 2150086452 + .quad 2150086586 + .quad 2150086776 + .quad 2150086918 .quad 2150087576 - .quad 2150087620 - .quad 2150087664 - .quad 2150087826 - .quad 2150087952 - .quad 2150088094 - .quad 2150088214 - .quad 2150088224 - .quad 2150088264 - .quad 2150088266 - .quad 2150088300 - .quad 2150088374 - .quad 2150088458 - .quad 2150088502 - .quad 2150088886 - .quad 2150088928 - .quad 2150088946 - .quad 2150088964 - .quad 2150089100 - .quad 2150089222 - .quad 2150089362 - .quad 2150089380 - .quad 2150089426 - .quad 2150089634 - .quad 2150089792 - .quad 2150089924 - .quad 2150089932 - .quad 2150089936 - .quad 2150089950 - .quad 2150089962 - .quad 2150089970 - .quad 2150089978 - .quad 2150089986 - .quad 2150090000 - .quad 2150090012 - .quad 2150090020 - .quad 2150090032 - .quad 2150090044 - .quad 2150090150 - .quad 2150090244 - .quad 2150090284 - .quad 2150090286 - .quad 2150090440 - .quad 2150091082 - .quad 2150091574 - .quad 2150091834 - .quad 2150091854 - .quad 2150091864 - .quad 2150091884 - .quad 2150091962 - .quad 2150092362 - .quad 2150092372 - .quad 2150092394 - .quad 2150092414 - .quad 2150092462 - .quad 2150092502 - .quad 2150094032 - .quad 2150094458 - .quad 2150094868 - .quad 2150095754 - .quad 2150096308 - .quad 2150096880 - .quad 2150097452 - .quad 2150097836 - .quad 2150098070 - .quad 2150098168 - .quad 2150098550 - .quad 2150098552 - .quad 2150098776 - .quad 2150099124 - .quad 2150099456 - .quad 2150099878 - .quad 2150100128 - .quad 2150100404 - .quad 2150100890 - .quad 2150101232 - .quad 2150101690 - .quad 2150101892 - .quad 2150102350 - .quad 2150102918 - .quad 2150103240 - .quad 2150103766 - .quad 2150104416 - .quad 2150104824 - .quad 2150104826 - .quad 2150105160 - .quad 2150105846 - .quad 2150106442 - .quad 2150106960 - .quad 2150107594 - .quad 2150108132 - .quad 2150109146 - .quad 2150109616 - .quad 2150109900 - .quad 2150112868 - .quad 2150113102 - .quad 2150114326 - .quad 2150114560 - .quad 2150114794 - .quad 2150115968 - .quad 2150117434 - .quad 2150117684 - .quad 2150117948 - .quad 2150118038 - .quad 2150118172 - .quad 2150118810 - .quad 2150119060 - .quad 2150119628 - .quad 2150120020 - .quad 2150120154 - .quad 2150120344 - .quad 2150120486 - .quad 2150121144 - .quad 2150121376 - .quad 2150121620 - .quad 2150121620 - .quad 2150121694 - .quad 2150122092 - .quad 2150122328 - .quad 2150122772 - .quad 2150123410 - .quad 2150124194 - .quad 2150124424 - .quad 2150124658 - .quad 2150124912 - .quad 2150125262 - .quad 2150125264 - .quad 2150126250 - .quad 2150127032 - .quad 2150128646 - .quad 2150128654 - .quad 2150128664 - .quad 2150128706 - .quad 2150128726 - .quad 2150128728 - .quad 2150128730 - .quad 2150128846 - .quad 2150129768 - .quad 2150130174 - .quad 2150130216 - .quad 2150130298 - .quad 2150130700 - .quad 2150130764 - .quad 2150131518 - .quad 2150131774 - .quad 2150131992 - .quad 2150132226 - .quad 2150132348 - .quad 2150132480 - .quad 2150132622 - .quad 2150132632 - .quad 2150133124 - .quad 2150133430 - .quad 2150133936 - .quad 2150133946 - .quad 2150133948 - .quad 2150133982 - .quad 2150134016 - .quad 2150134146 - .quad 2150134434 - .quad 2150134456 - .quad 2150135716 - .quad 2150135842 - .quad 2150135874 - .quad 2150135876 - .quad 2150135944 - .quad 2150135946 - .quad 2150136036 - .quad 2150136038 - .quad 2150136438 - .quad 2150136452 - .quad 2150136456 - .quad 2150136460 - .quad 2150136462 - .quad 2150136464 - .quad 2150136510 - .quad 2150136530 - .quad 2150136542 - .quad 2150136604 - .quad 2150136622 - .quad 2150136780 - .quad 2150137542 - .quad 2150137936 - .quad 2150138188 - .quad 2150139508 - .quad 2150139752 - .quad 2150140162 - .quad 2150140780 - .quad 2150141090 - .quad 2150141574 - .quad 2150142568 - .quad 2150143184 - .quad 2150143816 - .quad 2150146778 - .quad 2150146806 - .quad 2150146834 - .quad 2150146942 - .quad 2150147330 - .quad 2150147546 - .quad 2150147698 - .quad 2150150770 - .quad 2150150810 - .quad 2150150850 - .quad 2150150890 - .quad 2150150892 - .quad 2150150894 - .quad 2150151082 - .quad 2150151184 - .quad 2150152848 - .quad 2150152890 - .quad 2150153072 - .quad 2150153114 - .quad 2150153236 - .quad 2150153278 - .quad 2150153320 - .quad 2150153340 - .quad 2150153344 - .quad 2150153362 - .quad 2150153486 - .quad 2150153626 - .quad 2150154194 - .quad 2150154238 - .quad 2150154238 - .quad 2150154240 - .quad 2150154270 - .quad 2150154352 - .quad 2150154356 - .quad 2150154374 - .quad 2150154408 - .quad 2150154408 - .quad 2150154408 - .quad 2150154524 - .quad 2150154562 - .quad 2150154596 - .quad 2150154638 - .quad 2150154648 - .quad 2150154688 - .quad 2150154728 - .quad 2150154768 - .quad 2150154770 - .quad 2150154772 - .quad 2150154774 - .quad 2150155388 - .quad 2150155810 - .quad 2150156052 - .quad 2150156470 - .quad 2150156582 - .quad 2150156886 - .quad 2150157108 - .quad 2150157268 - .quad 2150157502 - .quad 2150157834 - .quad 2150159376 - .quad 2150161546 - .quad 2150163210 - .quad 2150163506 - .quad 2150163810 - .quad 2150163850 - .quad 2150163852 - .quad 2150165220 - .quad 2150165258 - .quad 2150165260 - .quad 2150166202 - .quad 2150166284 - .quad 2150166326 - .quad 2150166368 - .quad 2150166408 - .quad 2150166408 - .quad 2150166408 - .quad 2150166408 - .quad 2150166408 - .quad 2150166410 - .quad 2150166492 - .quad 2150166534 - .quad 2150168306 - .quad 2150168346 - .quad 2150168348 - .quad 2150168450 - .quad 2150168588 - .quad 2150168604 - .quad 2150168738 - .quad 2150169370 - .quad 2150169412 - .quad 2150169456 - .quad 2150169458 - .quad 2150169724 - .quad 2150169792 - .quad 2150169862 - .quad 2150169930 - .quad 2150170006 - .quad 2150170022 - .quad 2150170076 - .quad 2150170208 - .quad 2150170672 - .quad 2150171162 - .quad 2150171524 - .quad 2150171570 - .quad 2150171762 - .quad 2150171802 - .quad 2150171868 - .quad 2150171910 - .quad 2150172004 - .quad 2150172046 - .quad 2150172086 - .quad 2150172172 - .quad 2150172212 - .quad 2150172252 - .quad 2150172582 - .quad 2150172646 - .quad 2150172784 + .quad 2150087808 + .quad 2150088052 + .quad 2150088052 + .quad 2150088126 + .quad 2150088524 + .quad 2150088760 + .quad 2150089204 + .quad 2150089842 + .quad 2150090626 + .quad 2150090856 + .quad 2150091090 + .quad 2150091344 + .quad 2150091694 + .quad 2150091696 + .quad 2150092682 + .quad 2150093464 + .quad 2150095078 + .quad 2150095086 + .quad 2150095096 + .quad 2150095138 + .quad 2150095158 + .quad 2150095160 + .quad 2150095162 + .quad 2150095278 + .quad 2150096200 + .quad 2150096606 + .quad 2150096648 + .quad 2150096730 + .quad 2150097132 + .quad 2150097196 + .quad 2150097950 + .quad 2150098206 + .quad 2150098424 + .quad 2150098658 + .quad 2150098780 + .quad 2150098912 + .quad 2150099054 + .quad 2150099064 + .quad 2150099556 + .quad 2150099862 + .quad 2150100368 + .quad 2150100378 + .quad 2150100380 + .quad 2150100414 + .quad 2150100448 + .quad 2150100578 + .quad 2150100866 + .quad 2150100888 + .quad 2150102148 + .quad 2150102274 + .quad 2150102314 + .quad 2150102354 + .quad 2150102684 + .quad 2150102748 + .quad 2150102886 + .quad 2150103184 + .quad 2150103490 + .quad 2150103862 + .quad 2150103920 + .quad 2150104062 + .quad 2150104186 + .quad 2150104382 + .quad 2150104922 + .quad 2150105084 + .quad 2150111644 + .quad 2150111962 + .quad 2150112050 + .quad 2150112104 + .quad 2150112146 + .quad 2150112186 + .quad 2150112198 + .quad 2150114422 + .quad 2150114866 + .quad 2150115098 + .quad 2150115108 + .quad 2150115110 + .quad 2150115358 + .quad 2150115420 + .quad 2150115480 + .quad 2150115540 + .quad 2150115598 + .quad 2150116206 + .quad 2150117020 + .quad 2150118202 + .quad 2150118284 + .quad 2150119324 + .quad 2150119826 + .quad 2150119870 + .quad 2150121064 + .quad 2150123708 + .quad 2150124614 + .quad 2150124614 + .quad 2150124636 + .quad 2150124794 + .quad 2150124990 + .quad 2150125252 + .quad 2150125982 + .quad 2150126186 + .quad 2150126574 + .quad 2150126580 + .quad 2150126678 + .quad 2150126722 + .quad 2150126722 + .quad 2150126722 + .quad 2150126722 + .quad 2150126722 + .quad 2150126722 + .quad 2150126722 + .quad 2150126722 + .quad 2150126722 + .quad 2150126722 + .quad 2150126722 + .quad 2150126722 + .quad 2150126724 + .quad 2150127530 + .quad 2150128184 + .quad 2150128248 + .quad 2150129560 + .quad 2150129782 + .quad 2150130006 + .quad 2150130312 + .quad 2150130402 + .quad 2150130404 + .quad 2150130688 + .quad 2150131074 + .quad 2150131114 + .quad 2150131164 + .quad 2150131550 + .quad 2150131640 + .quad 2150131684 + .quad 2150131758 + .quad 2150131892 + .quad 2150131994 + .quad 2150132094 + .quad 2150132116 + .quad 2150132160 + .quad 2150132204 + .quad 2150132550 + .quad 2150133030 + .quad 2150133536 + .quad 2150134052 + .quad 2150134384 + .quad 2150134618 + .quad 2150134966 + .quad 2150135286 + .quad 2150135656 + .quad 2150135700 + .quad 2150135744 + .quad 2150135826 + .quad 2150135828 + .quad 2150135830 + .quad 2150135886 + .quad 2150136002 + .quad 2150136374 + .quad 2150136858 + .quad 2150136922 + .quad 2150136966 + .quad 2150137008 + .quad 2150137130 + .quad 2150137218 + .quad 2150137260 + .quad 2150137346 + .quad 2150137388 + .quad 2150137640 + .quad 2150137660 + .quad 2150137826 + .quad 2150138402 + .quad 2150138474 + .quad 2150138726 + .quad 2150138908 + .quad 2150139216 + .quad 2150139488 + .quad 2150139802 + .quad 2150139944 + .quad 2150139984 + .quad 2150139986 + .quad 2150139988 + .quad 2150139990 + .quad 2150140038 + .quad 2150140268 + .quad 2150140462 + .quad 2150140838 + .quad 2150140932 + .quad 2150141088 + .quad 2150141202 + .quad 2150141212 + .quad 2150141400 + .quad 2150141712 + .quad 2150142244 + .quad 2150142600 + .quad 2150143230 + .quad 2150143288 + .quad 2150143668 + .quad 2150143896 + .quad 2150143896 + .quad 2150143918 + .quad 2150144340 + .quad 2150144348 + .quad 2150144370 + .quad 2150144410 + .quad 2150144412 + .quad 2150146600 + .quad 2150146858 + .quad 2150147116 + .quad 2150147118 + .quad 2150148210 + .quad 2150148210 + .quad 2150148210 + .quad 2150148210 + .quad 2150148210 + .quad 2150148210 + .quad 2150148210 + .quad 2150148210 + .quad 2150148210 + .quad 2150148210 + .quad 2150148210 + .quad 2150148210 + .quad 2150148210 + .quad 2150148216 + .quad 2150149054 + .quad 2150149644 + .quad 2150149686 + .quad 2150149708 + .quad 2150149710 + .quad 2150149712 + .quad 2150149746 + .quad 2150150120 + .quad 2150150478 + .quad 2150150520 + .quad 2150150520 + .quad 2150150520 + .quad 2150150520 + .quad 2150150520 + .quad 2150150520 + .quad 2150150520 + .quad 2150150520 + .quad 2150150520 + .quad 2150150520 + .quad 2150150520 + .quad 2150150520 + .quad 2150150520 + .quad 2150150520 + .quad 2150150578 + .quad 2150150590 + .quad 2150150602 + .quad 2150150642 + .quad 2150150644 + .quad 2150150726 + .quad 2150151200 + .quad 2150151610 + .quad 2150152174 + .quad 2150152454 + .quad 2150153102 + .quad 2150153128 + .quad 2150153200 + .quad 2150153224 + .quad 2150153464 + .quad 2150153724 + .quad 2150153966 + .quad 2150154006 + .quad 2150154024 + .quad 2150154026 + .quad 2150154230 + .quad 2150154362 + .quad 2150154488 + .quad 2150155002 + .quad 2150155042 + .quad 2150155214 + .quad 2150155216 + .quad 2150157522 + .quad 2150157700 + .quad 2150157998 + .quad 2150159296 + .quad 2150159306 + .quad 2150159348 + .quad 2150159350 + .quad 2150159384 + .quad 2150159388 + .quad 2150159716 + .quad 2150160040 + .quad 2150160352 + .quad 2150160966 + .quad 2150160988 + .quad 2150161012 + .quad 2150161118 + .quad 2150161176 + .quad 2150162842 + .quad 2150164520 + .quad 2150164976 + .quad 2150165480 + .quad 2150165982 + .quad 2150166418 + .quad 2150167068 + .quad 2150167258 + .quad 2150167490 + .quad 2150167744 + .quad 2150168184 + .quad 2150169656 + .quad 2150170546 + .quad 2150170988 + .quad 2150171028 + .quad 2150171096 + .quad 2150171164 + .quad 2150171206 + .quad 2150171208 + .quad 2150171380 + .quad 2150171380 + .quad 2150171466 + .quad 2150171466 + .quad 2150171552 + .quad 2150171792 + .quad 2150171792 + .quad 2150172476 + .quad 2150172518 + .quad 2150172590 + .quad 2150172592 + .quad 2150172662 + .quad 2150172668 + .quad 2150172700 + .quad 2150172722 + .quad 2150172740 + .quad 2150172752 + .quad 2150172762 + .quad 2150172768 + .quad 2150172782 + .quad 2150173006 .quad 2150173082 - .quad 2150173388 - .quad 2150173760 - .quad 2150173818 - .quad 2150173960 - .quad 2150174084 - .quad 2150174280 - .quad 2150174820 - .quad 2150174982 - .quad 2150181542 - .quad 2150181860 - .quad 2150181948 - .quad 2150182002 - .quad 2150182044 - .quad 2150182084 - .quad 2150182096 - .quad 2150184320 - .quad 2150184764 - .quad 2150184996 - .quad 2150185006 - .quad 2150185008 - .quad 2150185256 - .quad 2150185318 - .quad 2150185378 - .quad 2150185438 - .quad 2150185496 - .quad 2150186104 - .quad 2150186918 - .quad 2150188100 - .quad 2150188182 - .quad 2150189222 - .quad 2150189724 - .quad 2150189768 - .quad 2150190962 - .quad 2150193606 - .quad 2150194512 - .quad 2150194512 - .quad 2150194534 - .quad 2150194692 - .quad 2150194888 - .quad 2150195150 - .quad 2150195880 - .quad 2150196084 - .quad 2150196472 - .quad 2150196478 - .quad 2150196576 - .quad 2150196620 - .quad 2150196620 - .quad 2150196620 - .quad 2150196620 - .quad 2150196620 - .quad 2150196620 - .quad 2150196620 - .quad 2150196620 - .quad 2150196620 - .quad 2150196620 - .quad 2150196620 - .quad 2150196620 - .quad 2150196622 - .quad 2150197428 - .quad 2150198082 - .quad 2150198146 - .quad 2150199458 - .quad 2150199680 - .quad 2150199904 - .quad 2150200210 - .quad 2150200300 - .quad 2150200302 - .quad 2150200586 - .quad 2150200972 - .quad 2150201012 - .quad 2150201062 - .quad 2150201448 - .quad 2150201538 - .quad 2150201582 - .quad 2150201656 - .quad 2150201790 - .quad 2150201892 - .quad 2150201992 - .quad 2150202014 - .quad 2150202058 - .quad 2150202102 - .quad 2150202448 - .quad 2150202928 - .quad 2150203434 - .quad 2150203950 - .quad 2150204282 - .quad 2150204516 - .quad 2150204864 - .quad 2150205184 - .quad 2150205554 - .quad 2150205598 - .quad 2150205642 - .quad 2150205724 - .quad 2150205726 - .quad 2150205728 - .quad 2150205784 + .quad 2150173116 + .quad 2150173130 + .quad 2150173138 + .quad 2150173184 + .quad 2150173288 + .quad 2150173408 + .quad 2150173410 + .quad 2150173454 + .quad 2150174308 + .quad 2150174960 + .quad 2150175610 + .quad 2150175652 + .quad 2150175694 + .quad 2150175736 + .quad 2150175746 + .quad 2150175786 + .quad 2150175788 + .quad 2150175790 + .quad 2150175894 + .quad 2150176192 + .quad 2150176312 + .quad 2150176352 + .quad 2150176392 + .quad 2150176394 + .quad 2150176396 + .quad 2150176440 + .quad 2150176484 + .quad 2150176646 + .quad 2150176772 + .quad 2150176914 + .quad 2150177034 + .quad 2150177044 + .quad 2150177084 + .quad 2150177086 + .quad 2150177120 + .quad 2150177194 + .quad 2150177278 + .quad 2150177322 + .quad 2150177706 + .quad 2150177748 + .quad 2150177750 + .quad 2150177818 + .quad 2150177854 + .quad 2150177922 + .quad 2150178064 + .quad 2150178390 + .quad 2150178554 + .quad 2150178910 + .quad 2150179564 + .quad 2150179898 + .quad 2150179940 + .quad 2150180302 + .quad 2150180368 + .quad 2150180920 + .quad 2150181440 + .quad 2150181888 + .quad 2150182516 + .quad 2150182598 + .quad 2150182640 + .quad 2150182682 + .quad 2150182724 + .quad 2150182734 + .quad 2150182744 + .quad 2150182746 + .quad 2150183008 + .quad 2150183170 + .quad 2150183312 + .quad 2150183434 + .quad 2150183568 + .quad 2150183852 + .quad 2150183970 + .quad 2150184290 + .quad 2150184340 + .quad 2150184416 + .quad 2150184542 + .quad 2150184594 + .quad 2150184634 + .quad 2150184816 + .quad 2150184974 + .quad 2150185014 + .quad 2150185054 + .quad 2150185094 + .quad 2150185096 + .quad 2150185098 + .quad 2150185100 + .quad 2150185102 + .quad 2150185422 + .quad 2150185458 + .quad 2150185520 + .quad 2150185602 + .quad 2150186298 + .quad 2150186462 + .quad 2150187018 + .quad 2150187200 + .quad 2150187276 + .quad 2150187390 + .quad 2150187422 + .quad 2150187424 + .quad 2150187492 + .quad 2150187494 + .quad 2150187584 + .quad 2150187586 + .quad 2150187986 + .quad 2150188000 + .quad 2150188004 + .quad 2150188008 + .quad 2150188010 + .quad 2150188012 + .quad 2150188058 + .quad 2150188078 + .quad 2150188090 + .quad 2150188152 + .quad 2150188170 + .quad 2150188328 + .quad 2150189090 + .quad 2150189484 + .quad 2150189736 + .quad 2150191056 + .quad 2150191300 + .quad 2150191710 + .quad 2150192328 + .quad 2150192638 + .quad 2150193122 + .quad 2150194116 + .quad 2150194732 + .quad 2150195364 + .quad 2150198326 + .quad 2150198354 + .quad 2150198382 + .quad 2150198490 + .quad 2150198878 + .quad 2150199094 + .quad 2150199246 + .quad 2150202318 + .quad 2150202358 + .quad 2150202398 + .quad 2150202438 + .quad 2150202440 + .quad 2150202442 + .quad 2150202630 + .quad 2150202732 + .quad 2150204396 + .quad 2150204438 + .quad 2150204620 + .quad 2150204662 + .quad 2150204784 + .quad 2150204826 + .quad 2150204868 + .quad 2150204888 + .quad 2150204892 + .quad 2150204910 + .quad 2150205034 + .quad 2150205174 + .quad 2150205742 + .quad 2150205786 + .quad 2150205786 + .quad 2150205788 + .quad 2150205818 .quad 2150205900 - .quad 2150206272 - .quad 2150206756 - .quad 2150206820 - .quad 2150206864 - .quad 2150206906 + .quad 2150205904 + .quad 2150205922 + .quad 2150205956 + .quad 2150205956 + .quad 2150205956 + .quad 2150206072 + .quad 2150206110 + .quad 2150206144 + .quad 2150206186 + .quad 2150206244 + .quad 2150206278 + .quad 2150206288 + .quad 2150206328 + .quad 2150206368 + .quad 2150206408 + .quad 2150206410 + .quad 2150206412 + .quad 2150206414 .quad 2150207028 - .quad 2150207116 - .quad 2150207158 - .quad 2150207244 - .quad 2150207286 - .quad 2150207538 - .quad 2150207558 - .quad 2150207724 - .quad 2150208300 - .quad 2150208372 - .quad 2150208624 - .quad 2150208806 - .quad 2150209114 - .quad 2150209386 - .quad 2150209700 - .quad 2150209842 - .quad 2150209882 - .quad 2150209884 - .quad 2150209886 - .quad 2150209888 - .quad 2150209936 - .quad 2150210166 - .quad 2150210360 - .quad 2150210736 - .quad 2150210830 - .quad 2150210986 - .quad 2150211100 - .quad 2150211110 - .quad 2150211298 - .quad 2150211610 - .quad 2150212142 - .quad 2150212498 - .quad 2150213128 + .quad 2150207450 + .quad 2150207692 + .quad 2150208110 + .quad 2150208222 + .quad 2150208526 + .quad 2150208748 + .quad 2150208908 + .quad 2150209142 + .quad 2150209474 + .quad 2150211016 .quad 2150213186 - .quad 2150213566 - .quad 2150213794 - .quad 2150213794 - .quad 2150213816 - .quad 2150214238 - .quad 2150214334 - .quad 2150214494 - .quad 2150214550 - .quad 2150214594 - .quad 2150214638 - .quad 2150214640 - .quad 2150214712 - .quad 2150214714 - .quad 2150214716 - .quad 2150214738 - .quad 2150214758 - .quad 2150214760 - .quad 2150214762 - .quad 2150214764 - .quad 2150215794 - .quad 2150218216 - .quad 2150218656 - .quad 2150218980 - .quad 2150219218 - .quad 2150219710 - .quad 2150220478 - .quad 2150221660 - .quad 2150222456 - .quad 2150222916 - .quad 2150222964 - .quad 2150223668 - .quad 2150224188 - .quad 2150224570 - .quad 2150224666 - .quad 2150224918 - .quad 2150225810 - .quad 2150225974 - .quad 2150226162 - .quad 2150226204 - .quad 2150226600 - .quad 2150226954 - .quad 2150227064 - .quad 2150227106 - .quad 2150227108 - .quad 2150227142 - .quad 2150227168 - .quad 2150227206 - .quad 2150227266 - .quad 2150227442 - .quad 2150227484 - .quad 2150227536 - .quad 2150227544 - .quad 2150227650 - .quad 2150227756 - .quad 2150227862 - .quad 2150227968 - .quad 2150228074 - .quad 2150228096 - .quad 2150228118 - .quad 2150228120 - .quad 2150228122 - .quad 2150228152 - .quad 2150228156 - .quad 2150228158 - .quad 2150228160 - .quad 2150228258 - .quad 2150228446 - .quad 2150228490 - .quad 2150228512 - .quad 2150228514 - .quad 2150228532 - .quad 2150228672 - .quad 2150228810 - .quad 2150228934 - .quad 2150228986 - .quad 2150229006 - .quad 2150229136 - .quad 2150229364 - .quad 2150229806 - .quad 2150230064 - .quad 2150230180 - .quad 2150230262 - .quad 2150230282 - .quad 2150230348 - .quad 2150230352 - .quad 2150230354 - .quad 2150230356 - .quad 2150230780 - .quad 2150230880 - .quad 2150230898 - .quad 2150230898 - .quad 2150230898 - .quad 2150230960 - .quad 2150230978 - .quad 2150230996 - .quad 2150231052 - .quad 2150231108 - .quad 2150231878 - .quad 2150231946 - .quad 2150232014 - .quad 2150232082 - .quad 2150232150 - .quad 2150232458 - .quad 2150234156 - .quad 2150234182 - .quad 2150234208 - .quad 2150234484 - .quad 2150234954 - .quad 2150235012 - .quad 2150235058 - .quad 2150235106 - .quad 2150235150 - .quad 2150235214 - .quad 2150235258 - .quad 2150235484 - .quad 2150235560 - .quad 2150236036 - .quad 2150236132 - .quad 2150236510 - .quad 2150236602 - .quad 2150236850 - .quad 2150236984 - .quad 2150237242 - .quad 2150237242 + .quad 2150214850 + .quad 2150215146 + .quad 2150215450 + .quad 2150215584 + .quad 2150215624 + .quad 2150215626 + .quad 2150216994 + .quad 2150217032 + .quad 2150217034 + .quad 2150217976 + .quad 2150218058 + .quad 2150218100 + .quad 2150218142 + .quad 2150218184 + .quad 2150218224 + .quad 2150218224 + .quad 2150218224 + .quad 2150218224 + .quad 2150218224 + .quad 2150218226 + .quad 2150218308 + .quad 2150218350 + .quad 2150220122 + .quad 2150220162 + .quad 2150220164 + .quad 2150220266 + .quad 2150220404 + .quad 2150220420 + .quad 2150220554 + .quad 2150221186 + .quad 2150221228 + .quad 2150221272 + .quad 2150221274 + .quad 2150221540 + .quad 2150221608 + .quad 2150221678 + .quad 2150221746 + .quad 2150221822 + .quad 2150221838 + .quad 2150221892 + .quad 2150222024 + .quad 2150222488 + .quad 2150222978 + .quad 2150223340 + .quad 2150223386 + .quad 2150223578 + .quad 2150223618 + .quad 2150223684 + .quad 2150223726 + .quad 2150223820 + .quad 2150223862 + .quad 2150223902 + .quad 2150223988 + .quad 2150224008 + .quad 2150224050 + .quad 2150224060 + .quad 2150224080 + .quad 2150224270 + .quad 2150224292 + .quad 2150224294 + .quad 2150224296 + .quad 2150224346 + .quad 2150224532 + .quad 2150224778 + .quad 2150224844 + .quad 2150224874 + .quad 2150225024 + .quad 2150225052 + .quad 2150225250 + .quad 2150225284 + .quad 2150225316 + .quad 2150225320 + .quad 2150225670 + .quad 2150225672 + .quad 2150225956 + .quad 2150226404 + .quad 2150226460 + .quad 2150226582 + .quad 2150226584 + .quad 2150226586 + .quad 2150226588 + .quad 2150227618 + .quad 2150230056 + .quad 2150230496 + .quad 2150230752 + .quad 2150231076 + .quad 2150231314 + .quad 2150231806 + .quad 2150232988 + .quad 2150233784 + .quad 2150234244 + .quad 2150234292 + .quad 2150234812 + .quad 2150235194 + .quad 2150235290 + .quad 2150235542 + .quad 2150235706 + .quad 2150235894 + .quad 2150235936 + .quad 2150236332 + .quad 2150236686 + .quad 2150236796 + .quad 2150236838 + .quad 2150236840 + .quad 2150236874 + .quad 2150236900 + .quad 2150236938 + .quad 2150236998 + .quad 2150237174 + .quad 2150237216 .quad 2150237268 - .quad 2150237298 - .quad 2150237534 - .quad 2150237770 - .quad 2150238006 - .quad 2150238242 - .quad 2150238264 - .quad 2150238286 - .quad 2150238308 - .quad 2150238330 + .quad 2150237270 + .quad 2150237272 + .quad 2150237294 + .quad 2150237390 + .quad 2150237550 + .quad 2150237606 + .quad 2150237650 + .quad 2150237694 + .quad 2150237696 + .quad 2150237768 + .quad 2150237776 + .quad 2150237882 + .quad 2150237988 + .quad 2150238094 + .quad 2150238200 + .quad 2150238306 + .quad 2150238328 + .quad 2150238350 .quad 2150238352 .quad 2150238370 - .quad 2150238752 - .quad 2150239276 - .quad 2150239362 - .quad 2150239920 - .quad 2150239920 - .quad 2150239928 - .quad 2150239928 - .quad 2150239948 - .quad 2150239994 - .quad 2150240140 - .quad 2150240328 - .quad 2150240554 - .quad 2150240814 - .quad 2150241108 - .quad 2150241302 - .quad 2150241362 - .quad 2150241524 - .quad 2150241714 - .quad 2150241766 - .quad 2150241810 - .quad 2150242556 - .quad 2150242572 - .quad 2150242864 - .quad 2150243060 - .quad 2150243246 - .quad 2150243446 - .quad 2150243722 - .quad 2150243786 - .quad 2150243850 - .quad 2150243914 - .quad 2150243980 - .quad 2150244510 - .quad 2150244910 - .quad 2150245024 - .quad 2150245956 - .quad 2150246488 - .quad 2150246502 - .quad 2150247212 - .quad 2150247480 - .quad 2150247778 - .quad 2150247786 - .quad 2150247786 - .quad 2150247904 - .quad 2150247904 - .quad 2150248022 - .quad 2150248022 - .quad 2150248140 - .quad 2150248140 - .quad 2150248258 - .quad 2150248258 - .quad 2150248356 - .quad 2150248356 - .quad 2150248472 - .quad 2150248472 - .quad 2150248588 - .quad 2150248588 - .quad 2150248588 - .quad 2150248588 - .quad 2150248686 - .quad 2150248686 - .quad 2150248686 - .quad 2150248686 - .quad 2150248800 - .quad 2150248800 + .quad 2150238510 + .quad 2150238648 + .quad 2150238772 + .quad 2150238824 + .quad 2150238844 + .quad 2150238974 + .quad 2150239202 + .quad 2150239644 + .quad 2150239902 + .quad 2150240018 + .quad 2150240100 + .quad 2150240120 + .quad 2150240186 + .quad 2150240208 + .quad 2150240210 + .quad 2150240212 + .quad 2150240242 + .quad 2150240246 + .quad 2150240248 + .quad 2150240250 + .quad 2150240348 + .quad 2150240536 + .quad 2150240580 + .quad 2150240584 + .quad 2150240586 + .quad 2150240588 + .quad 2150241012 + .quad 2150241112 + .quad 2150241130 + .quad 2150241130 + .quad 2150241130 + .quad 2150241192 + .quad 2150241210 + .quad 2150241228 + .quad 2150241284 + .quad 2150241340 + .quad 2150242110 + .quad 2150242178 + .quad 2150242246 + .quad 2150242314 + .quad 2150242382 + .quad 2150242690 + .quad 2150244388 + .quad 2150244414 + .quad 2150244440 + .quad 2150244716 + .quad 2150245186 + .quad 2150245244 + .quad 2150245526 + .quad 2150245572 + .quad 2150245620 + .quad 2150245664 + .quad 2150245728 + .quad 2150245772 + .quad 2150245998 + .quad 2150246074 + .quad 2150246550 + .quad 2150246646 + .quad 2150247024 + .quad 2150247116 + .quad 2150247364 + .quad 2150247498 + .quad 2150247756 + .quad 2150247756 + .quad 2150247782 + .quad 2150247812 + .quad 2150248048 + .quad 2150248284 + .quad 2150248520 + .quad 2150248756 + .quad 2150248778 .quad 2150248800 - .quad 2150248800 - .quad 2150248914 - .quad 2150249162 - .quad 2150249400 - .quad 2150249756 - .quad 2150249772 - .quad 2150249788 - .quad 2150249828 - .quad 2150249844 - .quad 2150249844 - .quad 2150249878 - .quad 2150249878 - .quad 2150249892 - .quad 2150249910 - .quad 2150249920 - .quad 2150250118 - .quad 2150250128 - .quad 2150250136 - .quad 2150250146 - .quad 2150250162 - .quad 2150250172 - .quad 2150250292 - .quad 2150250472 - .quad 2150250754 - .quad 2150250930 - .quad 2150251322 - .quad 2150251424 - .quad 2150251456 - .quad 2150251464 - .quad 2150251570 - .quad 2150253002 - .quad 2150253010 - .quad 2150253018 - .quad 2150256640 - .quad 2150256640 - .quad 2150272128 - .quad 2150272136 - .quad 2150298712 - .quad 2150325288 - .quad 2150577808 - .quad 2150587552 - .quad 2150587648 - .quad 2150588800 - .quad 2150601968 - .quad 2150644944 - .quad 2150654240 - .quad 2150660392 - .quad 2150660524 - .quad 2150662144 - .quad 2150666240 - .quad 2150666240 - .quad 2150666240 - .quad 2150666248 - .quad 2150666256 - .quad 2150666264 - .quad 2150666272 - .quad 2150666280 - .quad 2150666288 - .quad 2150666296 - .quad 2150666304 - .quad 2150666312 - .quad 2150666320 - .quad 2150666328 - .quad 2150666336 - .quad 2150666344 - .quad 2150666352 - .quad 2150666360 - .quad 2150666368 - .quad 2150666376 - .quad 2150666384 - .quad 2150666392 - .quad 2150666400 - .quad 2150666408 - .quad 2150666416 - .quad 2150666424 - .quad 2150666432 - .quad 2150666440 - .quad 2150666448 - .quad 2150666456 - .quad 2150666464 - .quad 2150666472 - .quad 2150666480 - .quad 2150666488 - .quad 2150666496 - .quad 2150666504 - .quad 2150666512 - .quad 2150666520 - .quad 2150666528 - .quad 2150666536 - .quad 2150666544 - .quad 2150666552 - .quad 2150666560 - .quad 2150666568 - .quad 2150666576 - .quad 2150666584 - .quad 2150666592 - .quad 2150666600 - .quad 2150666608 - .quad 2150666616 - .quad 2150666624 - .quad 2150666632 - .quad 2150666640 - .quad 2150666648 - .quad 2150666656 - .quad 2150666664 - .quad 2150666672 - .quad 2150666680 - .quad 2150666688 - .quad 2150666696 - .quad 2150666704 - .quad 2150666712 - .quad 2150666720 - .quad 2150666728 - .quad 2150666736 - .quad 2150666744 - .quad 2150666752 - .quad 2150666760 - .quad 2150666768 - .quad 2150666776 - .quad 2150666784 - .quad 2150666792 - .quad 2150666800 - .quad 2150666808 - .quad 2150666816 - .quad 2150666824 - .quad 2150666832 - .quad 2150666840 - .quad 2150666848 - .quad 2150666856 - .quad 2150666864 - .quad 2150666872 - .quad 2150666880 - .quad 2150666888 - .quad 2150666896 - .quad 2150666904 - .quad 2150666912 - .quad 2150666920 - .quad 2150666928 - .quad 2150666936 - .quad 2150666944 - .quad 2150666952 - .quad 2150666960 - .quad 2150666968 - .quad 2150666976 - .quad 2150666984 - .quad 2150666992 - .quad 2150667000 - .quad 2150667008 - .quad 2150667016 - .quad 2150667024 - .quad 2150667032 - .quad 2150667040 - .quad 2150667048 - .quad 2150667056 - .quad 2150667064 - .quad 2150667072 - .quad 2150667080 - .quad 2150667088 - .quad 2150667096 - .quad 2150667104 - .quad 2150667112 - .quad 2150667120 - .quad 2150667128 - .quad 2150667136 - .quad 2150667144 - .quad 2150667152 - .quad 2150667160 - .quad 2150667168 - .quad 2150667176 - .quad 2150667184 - .quad 2150667192 - .quad 2150667200 - .quad 2150667208 - .quad 2150667216 - .quad 2150667224 - .quad 2150667232 - .quad 2150667240 - .quad 2150667248 - .quad 2150667256 - .quad 2150667264 - .quad 2150667272 - .quad 2150667280 - .quad 2150667280 - .quad 2150667352 - .quad 2150667376 - .quad 2150668488 - .quad 2150668512 - .quad 2150668536 - .quad 2150668560 - .quad 2150668584 - .quad 2150668608 - .quad 2150668632 - .quad 2150668656 - .quad 2150668680 - .quad 2150668704 - .quad 2150668728 - .quad 2150668752 - .quad 2150668776 - .quad 2150668800 - .quad 2150668824 - .quad 2150668848 - .quad 2150668872 - .quad 2150668896 - .quad 2150668920 - .quad 2150668944 - .quad 2150668968 - .quad 2150668992 - .quad 2150669016 - .quad 2150669040 - .quad 2150669064 - .quad 2150669088 - .quad 2150669112 - .quad 2150669136 - .quad 2150669160 - .quad 2150669216 - .quad 2150669272 - .quad 2150669296 - .quad 2150669320 - .quad 2150669344 - .quad 2150669368 - .quad 2150669392 - .quad 2150669416 - .quad 2150669440 - .quad 2150669464 - .quad 2150669488 - .quad 2150669512 - .quad 2150669536 - .quad 2150669560 - .quad 2150669584 - .quad 2150669608 - .quad 2150669632 - .quad 2150669656 - .quad 2150669680 - .quad 2150669704 - .quad 2150669728 - .quad 2150669752 - .quad 2150669776 - .quad 2150669800 - .quad 2150669824 - .quad 2150669848 - .quad 2150669872 - .quad 2150669896 - .quad 2150669920 - .quad 2150669944 - .quad 2150669968 - .quad 2150669992 - .quad 2150670048 - .quad 2150670072 - .quad 2150670096 - .quad 2150670120 - .quad 2150670144 - .quad 2150670168 - .quad 2150670192 - .quad 2150670216 - .quad 2150670240 - .quad 2150670264 - .quad 2150670288 - .quad 2150670312 - .quad 2150670336 - .quad 2150670360 - .quad 2150670384 - .quad 2150670440 - .quad 2150670480 - .quad 2150670504 - .quad 2150670528 - .quad 2150670552 - .quad 2150670576 - .quad 2150670600 - .quad 2150670624 - .quad 2150670648 - .quad 2150670672 - .quad 2150670696 - .quad 2150670720 - .quad 2150670744 - .quad 2150670768 - .quad 2150670792 - .quad 2150670816 - .quad 2150670840 - .quad 2150670864 - .quad 2150670888 - .quad 2150670912 - .quad 2150670936 - .quad 2150670960 - .quad 2150670984 - .quad 2150671008 - .quad 2150671032 - .quad 2150671056 - .quad 2150671080 - .quad 2150671104 - .quad 2150671128 - .quad 2150671152 - .quad 2150671176 - .quad 2150671200 - .quad 2150671224 - .quad 2150671248 - .quad 2150671272 - .quad 2150671296 - .quad 2150671320 - .quad 2150671344 - .quad 2150671368 - .quad 2150671392 - .quad 2150671416 - .quad 2150671440 - .quad 2150671464 - .quad 2150671488 - .quad 2150671512 - .quad 2150671536 - .quad 2150671560 - .quad 2150671584 - .quad 2150671608 - .quad 2150671632 - .quad 2150671656 - .quad 2150671680 - .quad 2150671704 - .quad 2150671728 - .quad 2150671752 - .quad 2150671776 - .quad 2150671800 - .quad 2150671824 - .quad 2150671848 - .quad 2150671872 - .quad 2150671896 - .quad 2150671920 - .quad 2150671944 - .quad 2150672000 - .quad 2150672056 - .quad 2150672112 - .quad 2150672136 - .quad 2150672160 - .quad 2150672216 - .quad 2150672248 - .quad 2150674168 - .quad 2150674176 - .quad 2150678528 - .quad 2150678528 - .quad 2150744064 - .quad 2150744064 - .quad 2150744128 - .quad 2150744168 - .quad 2150744184 - .quad 2190590072 - .quad 2190590112 - .quad 2190590152 - .quad 2190590176 - .quad 2190590296 - .quad 2190590320 - .quad 2190590344 - .quad 2190590384 - .quad 2190590408 - .quad 2190590432 - .quad 2190590528 - .quad 2190590552 - .quad 2190590608 - .quad 2190590632 - .quad 2190590656 - .quad 2190590680 - .quad 2190590704 - .quad 2190591104 - .quad 2190591232 - .quad 2190591240 - .quad 2190591248 - .quad 2190591249 - .quad 2190591250 - .quad 2190591251 - .quad 2190591256 - .quad 2190591264 - .quad 2190591272 - .quad 2190591280 - .quad 2190594048 - .quad 2190594048 + .quad 2150248822 + .quad 2150248844 + .quad 2150248866 + .quad 2150248884 + .quad 2150249266 + .quad 2150249790 + .quad 2150249876 + .quad 2150250434 + .quad 2150250434 + .quad 2150250442 + .quad 2150250442 + .quad 2150250462 + .quad 2150250508 + .quad 2150250696 + .quad 2150250922 + .quad 2150251182 + .quad 2150251476 + .quad 2150251670 + .quad 2150251730 + .quad 2150251892 + .quad 2150252082 + .quad 2150252134 + .quad 2150252178 + .quad 2150252924 + .quad 2150252940 + .quad 2150253232 + .quad 2150253428 + .quad 2150253614 + .quad 2150253814 + .quad 2150254090 + .quad 2150254154 + .quad 2150254218 + .quad 2150254282 + .quad 2150254348 + .quad 2150254878 + .quad 2150255278 + .quad 2150255392 + .quad 2150256324 + .quad 2150256856 + .quad 2150256870 + .quad 2150257580 + .quad 2150257848 + .quad 2150258146 + .quad 2150258154 + .quad 2150258154 + .quad 2150258272 + .quad 2150258272 + .quad 2150258390 + .quad 2150258390 + .quad 2150258508 + .quad 2150258508 + .quad 2150258626 + .quad 2150258626 + .quad 2150258742 + .quad 2150258742 + .quad 2150258858 + .quad 2150258858 + .quad 2150258858 + .quad 2150258858 + .quad 2150258956 + .quad 2150258956 + .quad 2150258956 + .quad 2150258956 + .quad 2150259070 + .quad 2150259070 + .quad 2150259070 + .quad 2150259070 + .quad 2150259184 + .quad 2150259432 + .quad 2150259670 + .quad 2150260026 + .quad 2150260042 + .quad 2150260058 + .quad 2150260098 + .quad 2150260114 + .quad 2150260114 + .quad 2150260148 + .quad 2150260148 + .quad 2150260162 + .quad 2150260180 + .quad 2150260190 + .quad 2150260388 + .quad 2150260398 + .quad 2150260406 + .quad 2150260416 + .quad 2150260432 + .quad 2150260442 + .quad 2150260562 + .quad 2150260742 + .quad 2150261024 + .quad 2150261200 + .quad 2150261592 + .quad 2150261694 + .quad 2150261726 + .quad 2150261734 + .quad 2150261840 + .quad 2150263272 + .quad 2150263280 + .quad 2150263288 + .quad 2150264832 + .quad 2150264832 + .quad 2150339232 + .quad 2150375984 + .quad 2150396304 + .quad 2150416352 + .quad 2150416448 + .quad 2150417600 + .quad 2150447192 + .quad 2150452896 + .quad 2150453028 + .quad 2150457344 + .quad 2150461440 + .quad 2150461440 + .quad 2150461440 + .quad 2150461448 + .quad 2150461456 + .quad 2150461464 + .quad 2150461472 + .quad 2150461480 + .quad 2150461488 + .quad 2150461496 + .quad 2150461504 + .quad 2150461512 + .quad 2150461520 + .quad 2150461528 + .quad 2150461536 + .quad 2150461544 + .quad 2150461552 + .quad 2150461560 + .quad 2150461568 + .quad 2150461576 + .quad 2150461584 + .quad 2150461592 + .quad 2150461600 + .quad 2150461608 + .quad 2150461616 + .quad 2150461624 + .quad 2150461632 + .quad 2150461640 + .quad 2150461648 + .quad 2150461656 + .quad 2150461664 + .quad 2150461672 + .quad 2150461680 + .quad 2150461688 + .quad 2150461696 + .quad 2150461704 + .quad 2150461712 + .quad 2150461720 + .quad 2150461728 + .quad 2150461736 + .quad 2150461744 + .quad 2150461752 + .quad 2150461760 + .quad 2150461768 + .quad 2150461776 + .quad 2150461784 + .quad 2150461792 + .quad 2150461800 + .quad 2150461808 + .quad 2150461816 + .quad 2150461824 + .quad 2150461832 + .quad 2150461840 + .quad 2150461848 + .quad 2150461856 + .quad 2150461864 + .quad 2150461872 + .quad 2150461880 + .quad 2150461888 + .quad 2150461896 + .quad 2150461904 + .quad 2150461912 + .quad 2150461920 + .quad 2150461928 + .quad 2150461936 + .quad 2150461944 + .quad 2150461952 + .quad 2150461960 + .quad 2150461968 + .quad 2150461976 + .quad 2150461984 + .quad 2150461992 + .quad 2150462000 + .quad 2150462008 + .quad 2150462016 + .quad 2150462024 + .quad 2150462032 + .quad 2150462040 + .quad 2150462048 + .quad 2150462056 + .quad 2150462064 + .quad 2150462072 + .quad 2150462080 + .quad 2150462088 + .quad 2150462096 + .quad 2150462104 + .quad 2150462112 + .quad 2150462120 + .quad 2150462128 + .quad 2150462136 + .quad 2150462144 + .quad 2150462152 + .quad 2150462160 + .quad 2150462168 + .quad 2150462176 + .quad 2150462184 + .quad 2150462192 + .quad 2150462200 + .quad 2150462208 + .quad 2150462216 + .quad 2150462224 + .quad 2150462232 + .quad 2150462240 + .quad 2150462248 + .quad 2150462256 + .quad 2150462264 + .quad 2150462272 + .quad 2150462280 + .quad 2150462288 + .quad 2150462296 + .quad 2150462304 + .quad 2150462312 + .quad 2150462320 + .quad 2150462328 + .quad 2150462336 + .quad 2150462344 + .quad 2150462352 + .quad 2150462360 + .quad 2150462368 + .quad 2150462376 + .quad 2150462384 + .quad 2150462392 + .quad 2150462400 + .quad 2150462408 + .quad 2150462416 + .quad 2150462424 + .quad 2150462432 + .quad 2150462440 + .quad 2150462448 + .quad 2150462456 + .quad 2150462464 + .quad 2150462472 + .quad 2150462480 + .quad 2150462480 + .quad 2150462552 + .quad 2150462608 + .quad 2150462632 + .quad 2150462656 + .quad 2150462680 + .quad 2150462704 + .quad 2150462728 + .quad 2150462752 + .quad 2150462776 + .quad 2150462800 + .quad 2150462824 + .quad 2150462848 + .quad 2150462872 + .quad 2150462896 + .quad 2150462920 + .quad 2150462944 + .quad 2150462968 + .quad 2150462992 + .quad 2150463016 + .quad 2150463040 + .quad 2150463064 + .quad 2150463088 + .quad 2150463112 + .quad 2150463136 + .quad 2150463160 + .quad 2150463184 + .quad 2150463208 + .quad 2150463232 + .quad 2150463256 + .quad 2150463280 + .quad 2150463304 + .quad 2150463328 + .quad 2150463352 + .quad 2150463376 + .quad 2150463400 + .quad 2150463424 + .quad 2150463448 + .quad 2150463472 + .quad 2150463496 + .quad 2150463520 + .quad 2150463544 + .quad 2150463568 + .quad 2150463592 + .quad 2150463616 + .quad 2150463640 + .quad 2150463664 + .quad 2150463688 + .quad 2150463712 + .quad 2150463736 + .quad 2150463760 + .quad 2150463784 + .quad 2150463808 + .quad 2150463832 + .quad 2150463856 + .quad 2150463880 + .quad 2150463904 + .quad 2150463928 + .quad 2150463952 + .quad 2150463976 + .quad 2150464000 + .quad 2150464024 + .quad 2150464048 + .quad 2150464072 + .quad 2150464096 + .quad 2150464120 + .quad 2150464144 + .quad 2150464168 + .quad 2150464192 + .quad 2150464216 + .quad 2150464240 + .quad 2150464264 + .quad 2150464288 + .quad 2150464312 + .quad 2150464336 + .quad 2150464360 + .quad 2150464384 + .quad 2150464408 + .quad 2150464432 + .quad 2150464456 + .quad 2150464480 + .quad 2150464504 + .quad 2150464544 + .quad 2150464568 + .quad 2150464592 + .quad 2150464616 + .quad 2150464640 + .quad 2150464664 + .quad 2150464688 + .quad 2150464712 + .quad 2150464736 + .quad 2150464760 + .quad 2150464784 + .quad 2150464808 + .quad 2150464832 + .quad 2150464856 + .quad 2150464880 + .quad 2150464904 + .quad 2150464928 + .quad 2150464952 + .quad 2150464976 + .quad 2150465000 + .quad 2150465024 + .quad 2150465048 + .quad 2150465072 + .quad 2150465096 + .quad 2150465120 + .quad 2150465144 + .quad 2150465168 + .quad 2150465192 + .quad 2150465216 + .quad 2150465240 + .quad 2150465264 + .quad 2150465288 + .quad 2150465312 + .quad 2150465336 + .quad 2150465360 + .quad 2150465384 + .quad 2150465408 + .quad 2150465432 + .quad 2150465456 + .quad 2150465480 + .quad 2150465504 + .quad 2150465528 + .quad 2150465552 + .quad 2150465576 + .quad 2150465600 + .quad 2150465624 + .quad 2150465648 + .quad 2150465672 + .quad 2150465696 + .quad 2150465720 + .quad 2150465744 + .quad 2150465768 + .quad 2150465792 + .quad 2150465816 + .quad 2150465840 + .quad 2150465896 + .quad 2150465952 + .quad 2150466008 + .quad 2150466064 + .quad 2150466088 + .quad 2150466112 + .quad 2150466168 + .quad 2150466200 + .quad 2150466256 + .quad 2150466280 + .quad 2150467392 + .quad 2150469488 + .quad 2150469496 + .quad 2150473728 + .quad 2150473728 + .quad 2150539264 + .quad 2150539264 + .quad 2150539304 + .quad 2150539328 + .quad 2150539368 + .quad 2150539488 + .quad 2150539512 + .quad 2150539536 + .quad 2150539560 + .quad 2150539584 + .quad 2150539608 + .quad 2150539624 + .quad 2150539648 + .quad 2150539672 + .quad 2150539696 + .quad 2150539720 + .quad 2150539760 + .quad 2150539784 + .quad 2150539808 + .quad 2150540208 + .quad 2150540264 + .quad 2190386152 + .quad 2190386168 + .quad 2190386208 + .quad 2190386304 + .quad 2190386432 + .quad 2190386440 + .quad 2190386448 + .quad 2190386449 + .quad 2190386456 + .quad 2190386464 + .quad 2190386472 + .quad 2190389248 + .quad 2190389248 .globl symbol_index symbol_index: .quad 0 @@ -3335,3322 +3608,3595 @@ symbol_index: .quad 26 .quad 33 .quad 40 - .quad 84 - .quad 96 - .quad 140 - .quad 184 - .quad 228 - .quad 272 - .quad 310 - .quad 348 - .quad 386 - .quad 432 - .quad 478 - .quad 515 - .quad 558 - .quad 597 - .quad 644 - .quad 696 - .quad 738 - .quad 779 - .quad 819 - .quad 859 - .quad 899 - .quad 944 - .quad 989 - .quad 1034 - .quad 1077 - .quad 1120 - .quad 1163 - .quad 1206 - .quad 1255 - .quad 1295 - .quad 1339 - .quad 1383 - .quad 1426 - .quad 1464 - .quad 1502 - .quad 1540 - .quad 1578 - .quad 1616 - .quad 1654 - .quad 1700 - .quad 1737 - .quad 1783 - .quad 1829 - .quad 1868 - .quad 1916 - .quad 1963 - .quad 2010 + .quad 79 + .quad 91 + .quad 130 + .quad 169 + .quad 208 + .quad 247 + .quad 286 + .quad 325 + .quad 369 + .quad 413 + .quad 457 + .quad 501 + .quad 545 + .quad 589 + .quad 633 + .quad 677 + .quad 721 + .quad 765 + .quad 809 + .quad 852 + .quad 894 + .quad 935 + .quad 976 + .quad 1017 + .quad 1058 + .quad 1099 + .quad 1137 + .quad 1175 + .quad 1213 + .quad 1251 + .quad 1289 + .quad 1331 + .quad 1373 + .quad 1415 + .quad 1452 + .quad 1489 + .quad 1535 + .quad 1581 + .quad 1627 + .quad 1673 + .quad 1719 + .quad 1765 + .quad 1808 + .quad 1847 + .quad 1891 + .quad 1933 + .quad 1975 + .quad 2016 .quad 2057 - .quad 2101 - .quad 2143 - .quad 2184 - .quad 2225 - .quad 2270 - .quad 2313 - .quad 2356 + .quad 2098 + .quad 2138 + .quad 2178 + .quad 2218 + .quad 2264 + .quad 2309 + .quad 2354 .quad 2399 - .quad 2442 - .quad 2485 - .quad 2528 - .quad 2571 - .quad 2615 - .quad 2659 - .quad 2698 - .quad 2736 - .quad 2782 - .quad 2828 - .quad 2871 - .quad 2919 - .quad 2964 - .quad 3007 - .quad 3047 - .quad 3087 - .quad 3127 - .quad 3171 - .quad 3215 - .quad 3259 - .quad 3303 - .quad 3346 - .quad 3387 - .quad 3425 - .quad 3463 - .quad 3501 - .quad 3542 - .quad 3588 - .quad 3626 - .quad 3663 - .quad 3709 - .quad 3755 - .quad 3801 - .quad 3844 - .quad 3891 - .quad 3938 - .quad 3980 - .quad 4021 - .quad 4062 - .quad 4103 - .quad 4143 - .quad 4183 - .quad 4229 - .quad 4272 - .quad 4315 - .quad 4358 - .quad 4401 - .quad 4444 - .quad 4487 - .quad 4530 - .quad 4573 - .quad 4616 - .quad 4659 - .quad 4702 - .quad 4745 - .quad 4788 - .quad 4828 - .quad 4868 - .quad 4908 - .quad 4948 - .quad 4992 - .quad 5036 - .quad 5080 - .quad 5117 - .quad 5154 - .quad 5200 - .quad 5242 - .quad 5284 - .quad 5325 - .quad 5370 - .quad 5415 - .quad 5459 - .quad 5502 - .quad 5546 - .quad 5589 - .quad 5619 - .quad 5651 - .quad 5684 - .quad 5715 - .quad 5720 - .quad 5747 - .quad 5756 - .quad 5787 - .quad 5818 - .quad 5849 - .quad 5880 - .quad 5911 - .quad 5942 + .quad 2444 + .quad 2489 + .quad 2534 + .quad 2579 + .quad 2622 + .quad 2665 + .quad 2708 + .quad 2752 + .quad 2795 + .quad 2838 + .quad 2881 + .quad 2924 + .quad 2967 + .quad 3010 + .quad 3053 + .quad 3096 + .quad 3139 + .quad 3182 + .quad 3225 + .quad 3268 + .quad 3311 + .quad 3354 + .quad 3392 + .quad 3431 + .quad 3474 + .quad 3518 + .quad 3562 + .quad 3603 + .quad 3644 + .quad 3685 + .quad 3723 + .quad 3761 + .quad 3799 + .quad 3837 + .quad 3875 + .quad 3912 + .quad 3954 + .quad 4000 + .quad 4043 + .quad 4082 + .quad 4121 + .quad 4163 + .quad 4205 + .quad 4246 + .quad 4287 + .quad 4331 + .quad 4374 + .quad 4417 + .quad 4460 + .quad 4503 + .quad 4546 + .quad 4589 + .quad 4632 + .quad 4676 + .quad 4720 + .quad 4764 + .quad 4807 + .quad 4848 + .quad 4889 + .quad 4927 + .quad 4965 + .quad 5003 + .quad 5045 + .quad 5082 + .quad 5119 + .quad 5156 + .quad 5199 + .quad 5241 + .quad 5282 + .quad 5323 + .quad 5363 + .quad 5403 + .quad 5446 + .quad 5489 + .quad 5731 .quad 5973 - .quad 6004 - .quad 6034 - .quad 6066 - .quad 6107 - .quad 6148 - .quad 6189 - .quad 6230 - .quad 6271 - .quad 6312 - .quad 6353 - .quad 6394 - .quad 6435 - .quad 6476 - .quad 6518 - .quad 6560 - .quad 6602 - .quad 6644 - .quad 6691 - .quad 6733 - .quad 6775 - .quad 6817 - .quad 6859 - .quad 6901 - .quad 6943 - .quad 6980 - .quad 7017 - .quad 7054 - .quad 7091 - .quad 7128 - .quad 7165 - .quad 7202 - .quad 7239 - .quad 7276 - .quad 7313 - .quad 7352 - .quad 7391 - .quad 7430 - .quad 7469 - .quad 7508 - .quad 7547 - .quad 7586 - .quad 7625 - .quad 7664 - .quad 7703 - .quad 7756 - .quad 7857 - .quad 7976 - .quad 8087 - .quad 8202 - .quad 8319 - .quad 8442 - .quad 8567 - .quad 8701 - .quad 8841 - .quad 8995 - .quad 9151 - .quad 9191 - .quad 9242 - .quad 9269 - .quad 9296 - .quad 9335 - .quad 9375 - .quad 9432 - .quad 9491 - .quad 9550 - .quad 9609 - .quad 9672 - .quad 9737 - .quad 9802 - .quad 9867 - .quad 9912 - .quad 9963 - .quad 10008 - .quad 10037 - .quad 10067 - .quad 10097 - .quad 10129 - .quad 10161 - .quad 10194 - .quad 10259 - .quad 10325 - .quad 10391 - .quad 10457 - .quad 10525 - .quad 10594 - .quad 10668 - .quad 10746 - .quad 10813 - .quad 10884 - .quad 10955 - .quad 11027 - .quad 11099 - .quad 11172 - .quad 11247 - .quad 11325 - .quad 11400 - .quad 11475 - .quad 11550 - .quad 11630 - .quad 11710 + .quad 6215 + .quad 6457 + .quad 6699 + .quad 6941 + .quad 7013 + .quad 7085 + .quad 7157 + .quad 7229 + .quad 7302 + .quad 7375 + .quad 7448 + .quad 7521 + .quad 7603 + .quad 7685 + .quad 7767 + .quad 7849 + .quad 7914 + .quad 7979 + .quad 8044 + .quad 8109 + .quad 8389 + .quad 8669 + .quad 8949 + .quad 9229 + .quad 9523 + .quad 9817 + .quad 10111 + .quad 10405 + .quad 10704 + .quad 11003 + .quad 11302 + .quad 11601 + .quad 11632 + .quad 11673 + .quad 11715 + .quad 11752 .quad 11791 - .quad 11876 - .quad 11950 - .quad 12025 - .quad 12101 - .quad 12177 - .quad 12253 - .quad 12330 - .quad 12408 - .quad 12486 - .quad 12564 - .quad 12642 - .quad 12721 - .quad 12800 - .quad 12875 - .quad 12952 - .quad 13030 + .quad 11846 + .quad 11885 + .quad 11916 + .quad 11965 + .quad 12022 + .quad 12071 + .quad 12134 + .quad 12170 + .quad 12209 + .quad 12246 + .quad 12287 + .quad 12322 + .quad 12360 + .quad 12400 + .quad 12440 + .quad 12475 + .quad 12510 + .quad 12548 + .quad 12591 + .quad 12634 + .quad 12677 + .quad 12720 + .quad 12763 + .quad 12806 + .quad 12845 + .quad 12887 + .quad 12929 + .quad 12972 + .quad 13014 + .quad 13061 .quad 13105 - .quad 13187 - .quad 13274 - .quad 13351 - .quad 13429 - .quad 13507 - .quad 13587 - .quad 13667 - .quad 13747 - .quad 13828 - .quad 13908 - .quad 13989 - .quad 14074 - .quad 14148 - .quad 14223 - .quad 14299 - .quad 14375 - .quad 14451 - .quad 14536 - .quad 14613 - .quad 14691 - .quad 14769 - .quad 14848 - .quad 14932 - .quad 15013 - .quad 15094 - .quad 15175 - .quad 15263 - .quad 15349 - .quad 15388 - .quad 15416 + .quad 13152 + .quad 13204 + .quad 13256 + .quad 13308 + .quad 13356 + .quad 13404 + .quad 13452 + .quad 13500 + .quad 13543 + .quad 13583 + .quad 13620 + .quad 13663 + .quad 13713 + .quad 13764 + .quad 13821 + .quad 13872 + .quad 13910 + .quad 13945 + .quad 13979 + .quad 14010 + .quad 14089 + .quad 14170 + .quad 14253 + .quad 14310 + .quad 14356 + .quad 14402 + .quad 14448 + .quad 14494 + .quad 14540 + .quad 14586 + .quad 14632 + .quad 14678 + .quad 14724 + .quad 14770 + .quad 14816 + .quad 14862 + .quad 14908 + .quad 14954 + .quad 15000 + .quad 15046 + .quad 15092 + .quad 15138 + .quad 15184 + .quad 15230 + .quad 15276 + .quad 15322 + .quad 15368 + .quad 15414 .quad 15460 - .quad 15472 .quad 15506 - .quad 15550 - .quad 15567 - .quad 15606 - .quad 15625 - .quad 15655 - .quad 15699 - .quad 15740 + .quad 15552 + .quad 15598 + .quad 15644 + .quad 15690 + .quad 15736 .quad 15782 - .quad 15819 - .quad 15858 - .quad 15913 - .quad 15952 - .quad 16067 - .quad 16099 - .quad 16130 - .quad 16179 - .quad 16236 - .quad 16304 - .quad 16367 - .quad 16403 - .quad 16442 - .quad 16479 - .quad 16520 - .quad 16555 - .quad 16593 - .quad 16633 - .quad 16673 - .quad 16708 - .quad 16743 - .quad 16781 - .quad 16824 - .quad 16867 - .quad 16910 - .quad 16953 - .quad 16996 - .quad 17039 - .quad 17078 - .quad 17120 + .quad 15828 + .quad 15874 + .quad 15920 + .quad 15966 + .quad 16012 + .quad 16058 + .quad 16104 + .quad 16150 + .quad 16196 + .quad 16242 + .quad 16288 + .quad 16334 + .quad 16380 + .quad 16426 + .quad 16472 + .quad 16518 + .quad 16564 + .quad 16610 + .quad 16656 + .quad 16702 + .quad 16748 + .quad 16794 + .quad 16840 + .quad 16886 + .quad 16932 + .quad 16978 + .quad 17024 + .quad 17070 + .quad 17116 .quad 17162 - .quad 17205 - .quad 17247 - .quad 17294 - .quad 17338 - .quad 17382 - .quad 17429 - .quad 17481 - .quad 17533 - .quad 17585 - .quad 17633 - .quad 17681 - .quad 17729 - .quad 17777 - .quad 17820 - .quad 17860 - .quad 17897 - .quad 17940 + .quad 17208 + .quad 17254 + .quad 17300 + .quad 17346 + .quad 17392 + .quad 17438 + .quad 17484 + .quad 17530 + .quad 17576 + .quad 17622 + .quad 17668 + .quad 17714 + .quad 17760 + .quad 17806 + .quad 17852 + .quad 17898 + .quad 17944 .quad 17990 - .quad 18041 - .quad 18098 - .quad 18149 - .quad 18187 - .quad 18222 - .quad 18256 - .quad 18287 - .quad 18344 - .quad 18431 - .quad 18490 - .quad 18549 - .quad 18592 - .quad 18635 - .quad 18678 - .quad 18721 - .quad 18769 - .quad 18799 - .quad 18840 - .quad 18881 - .quad 18922 - .quad 18963 - .quad 19000 - .quad 19131 - .quad 19273 - .quad 19327 - .quad 19355 - .quad 19383 - .quad 19411 - .quad 19439 - .quad 19478 - .quad 19517 - .quad 19557 - .quad 19597 - .quad 19641 - .quad 19686 - .quad 19721 - .quad 19756 - .quad 19793 - .quad 19831 - .quad 19859 - .quad 19891 - .quad 19925 - .quad 19972 - .quad 19996 - .quad 20040 - .quad 20080 - .quad 20125 - .quad 20171 - .quad 20220 - .quad 20301 - .quad 20346 - .quad 20389 - .quad 20422 - .quad 20458 - .quad 20476 - .quad 20513 - .quad 20544 + .quad 18036 + .quad 18082 + .quad 18128 + .quad 18174 + .quad 18220 + .quad 18266 + .quad 18312 + .quad 18358 + .quad 18404 + .quad 18450 + .quad 18496 + .quad 18542 + .quad 18588 + .quad 18634 + .quad 18680 + .quad 18726 + .quad 18772 + .quad 18818 + .quad 18864 + .quad 18910 + .quad 18956 + .quad 19002 + .quad 19048 + .quad 19094 + .quad 19140 + .quad 19186 + .quad 19232 + .quad 19278 + .quad 19324 + .quad 19370 + .quad 19416 + .quad 19462 + .quad 19508 + .quad 19554 + .quad 19600 + .quad 19646 + .quad 19692 + .quad 19738 + .quad 19784 + .quad 19830 + .quad 19876 + .quad 19922 + .quad 19968 + .quad 20014 + .quad 20060 + .quad 20106 + .quad 20152 + .quad 20198 + .quad 20244 + .quad 20290 + .quad 20327 + .quad 20377 + .quad 20427 + .quad 20477 + .quad 20527 .quad 20577 - .quad 20610 - .quad 20642 - .quad 20734 - .quad 20826 - .quad 20918 - .quad 21010 - .quad 21102 - .quad 21194 - .quad 21289 - .quad 21387 - .quad 21499 - .quad 21530 - .quad 21561 - .quad 21592 - .quad 21623 - .quad 21653 - .quad 21694 - .quad 21735 - .quad 21776 - .quad 21817 - .quad 21859 - .quad 21906 - .quad 21948 - .quad 21990 - .quad 22032 - .quad 22069 - .quad 22106 - .quad 22143 - .quad 22180 - .quad 22219 - .quad 22258 - .quad 22297 - .quad 22336 - .quad 22437 - .quad 22548 - .quad 22663 - .quad 22812 - .quad 22961 - .quad 22994 - .quad 23053 - .quad 23106 - .quad 23159 - .quad 23212 - .quad 23268 - .quad 23324 - .quad 23380 - .quad 23436 - .quad 23492 - .quad 23548 - .quad 23604 - .quad 23660 - .quad 23716 - .quad 23772 - .quad 23828 - .quad 23884 - .quad 23940 - .quad 23996 - .quad 24052 - .quad 24108 - .quad 24164 - .quad 24220 - .quad 24276 - .quad 24332 - .quad 24388 - .quad 24451 - .quad 24514 - .quad 24555 - .quad 24597 - .quad 24641 - .quad 24713 - .quad 24757 - .quad 24808 - .quad 24859 - .quad 24910 - .quad 24961 - .quad 25012 - .quad 25063 - .quad 25114 - .quad 25165 - .quad 25216 + .quad 20627 + .quad 20677 + .quad 20727 + .quad 20777 + .quad 20827 + .quad 20877 + .quad 20927 + .quad 20977 + .quad 21027 + .quad 21077 + .quad 21127 + .quad 21177 + .quad 21227 + .quad 21277 + .quad 21327 + .quad 21377 + .quad 21427 + .quad 21477 + .quad 21527 + .quad 21577 + .quad 21627 + .quad 21677 + .quad 21727 + .quad 21777 + .quad 21827 + .quad 21877 + .quad 21927 + .quad 21977 + .quad 22027 + .quad 22077 + .quad 22127 + .quad 22177 + .quad 22227 + .quad 22277 + .quad 22327 + .quad 22377 + .quad 22427 + .quad 22477 + .quad 22527 + .quad 22577 + .quad 22627 + .quad 22677 + .quad 22727 + .quad 22777 + .quad 22827 + .quad 22877 + .quad 22927 + .quad 22977 + .quad 23027 + .quad 23077 + .quad 23127 + .quad 23177 + .quad 23227 + .quad 23277 + .quad 23327 + .quad 23377 + .quad 23427 + .quad 23477 + .quad 23527 + .quad 23577 + .quad 23627 + .quad 23677 + .quad 23727 + .quad 23777 + .quad 23827 + .quad 23877 + .quad 23927 + .quad 23977 + .quad 24027 + .quad 24077 + .quad 24127 + .quad 24177 + .quad 24227 + .quad 24277 + .quad 24327 + .quad 24377 + .quad 24427 + .quad 24477 + .quad 24527 + .quad 24577 + .quad 24627 + .quad 24677 + .quad 24727 + .quad 24777 + .quad 24827 + .quad 24877 + .quad 24927 + .quad 24977 + .quad 25027 + .quad 25077 + .quad 25127 + .quad 25177 + .quad 25227 .quad 25277 - .quad 25306 - .quad 25336 - .quad 25368 - .quad 25400 - .quad 25433 - .quad 25462 - .quad 25491 - .quad 25522 - .quad 25553 - .quad 25589 - .quad 25625 - .quad 25668 - .quad 25701 - .quad 25769 - .quad 25843 - .quad 25918 - .quad 25996 + .quad 25327 + .quad 25377 + .quad 25427 + .quad 25477 + .quad 25527 + .quad 25577 + .quad 25627 + .quad 25677 + .quad 25727 + .quad 25777 + .quad 25827 + .quad 25877 + .quad 25927 + .quad 25977 + .quad 26027 .quad 26077 - .quad 26145 - .quad 26213 - .quad 26282 - .quad 26352 - .quad 26422 - .quad 26492 - .quad 26565 - .quad 26638 - .quad 26706 - .quad 26775 - .quad 26844 - .quad 26914 - .quad 26985 - .quad 27056 - .quad 27129 - .quad 27203 - .quad 27281 - .quad 27348 - .quad 27416 - .quad 27485 - .quad 27554 - .quad 27623 - .quad 27694 - .quad 27765 - .quad 27836 - .quad 27907 - .quad 27979 - .quad 28057 - .quad 28132 - .quad 28226 - .quad 28320 - .quad 28401 - .quad 28482 - .quad 28563 - .quad 28644 - .quad 28725 - .quad 28806 - .quad 28887 - .quad 28968 - .quad 28994 - .quad 29064 - .quad 29135 - .quad 29202 - .quad 29270 - .quad 29343 - .quad 29414 - .quad 29656 - .quad 29898 - .quad 30140 - .quad 30382 - .quad 30624 - .quad 30866 - .quad 31108 - .quad 31350 - .quad 31592 - .quad 31834 - .quad 32076 - .quad 32318 - .quad 32560 - .quad 32802 - .quad 33044 - .quad 33286 - .quad 33358 - .quad 33430 - .quad 33502 - .quad 33574 - .quad 33646 - .quad 33718 - .quad 33790 - .quad 33863 - .quad 33936 - .quad 34009 - .quad 34082 - .quad 34155 - .quad 34228 - .quad 34301 - .quad 34383 - .quad 34465 - .quad 34547 - .quad 34629 - .quad 34711 - .quad 34793 - .quad 34875 - .quad 34940 - .quad 35005 - .quad 35070 - .quad 35135 - .quad 35200 - .quad 35265 - .quad 35330 - .quad 35610 - .quad 35890 - .quad 36170 - .quad 36450 - .quad 36730 - .quad 37010 - .quad 37290 - .quad 37584 - .quad 37878 - .quad 38172 - .quad 38466 - .quad 38760 - .quad 39054 - .quad 39348 - .quad 39642 - .quad 39941 - .quad 40240 - .quad 40539 - .quad 40838 - .quad 41137 - .quad 41436 - .quad 41735 - .quad 42034 - .quad 42116 - .quad 42177 - .quad 42239 - .quad 42302 - .quad 42369 - .quad 42440 - .quad 42514 - .quad 42568 - .quad 42626 - .quad 42662 - .quad 42699 - .quad 42729 - .quad 42784 - .quad 42823 - .quad 42880 - .quad 42951 - .quad 42969 - .quad 43020 - .quad 43071 - .quad 43122 - .quad 43194 - .quad 43293 - .quad 43354 - .quad 43403 - .quad 43457 - .quad 43512 - .quad 43571 - .quad 43614 - .quad 43660 - .quad 43693 - .quad 43741 - .quad 43789 - .quad 43834 - .quad 43879 - .quad 43914 - .quad 43989 - .quad 44066 - .quad 44143 - .quad 44222 - .quad 44235 - .quad 44250 - .quad 44265 - .quad 44285 - .quad 44331 - .quad 44394 - .quad 44445 - .quad 44501 - .quad 44555 - .quad 44608 - .quad 44641 - .quad 44674 - .quad 44707 - .quad 44740 - .quad 44773 - .quad 44806 - .quad 44839 - .quad 44872 - .quad 44905 - .quad 44938 - .quad 44971 - .quad 45004 - .quad 45037 - .quad 45070 - .quad 45103 - .quad 45136 - .quad 45169 - .quad 45202 - .quad 45235 - .quad 45268 - .quad 45301 - .quad 45334 - .quad 45367 - .quad 45400 - .quad 45433 - .quad 45466 - .quad 45499 - .quad 45532 - .quad 45565 - .quad 45598 - .quad 45631 - .quad 45664 - .quad 45697 - .quad 45730 - .quad 45763 - .quad 45796 - .quad 45829 - .quad 45862 - .quad 45895 - .quad 45928 - .quad 45961 - .quad 45994 - .quad 46027 - .quad 46060 - .quad 46093 - .quad 46126 - .quad 46197 - .quad 46246 - .quad 46311 - .quad 46376 - .quad 46441 - .quad 46517 - .quad 46593 - .quad 46669 - .quad 46745 - .quad 46821 - .quad 46897 - .quad 46973 - .quad 47049 - .quad 47125 - .quad 47201 - .quad 47277 - .quad 47353 - .quad 47429 - .quad 47505 - .quad 47581 + .quad 26127 + .quad 26177 + .quad 26227 + .quad 26277 + .quad 26327 + .quad 26377 + .quad 26427 + .quad 26477 + .quad 26527 + .quad 26577 + .quad 26627 + .quad 26677 + .quad 26727 + .quad 26777 + .quad 26827 + .quad 26932 + .quad 27038 + .quad 27146 + .quad 27254 + .quad 27363 + .quad 27472 + .quad 27581 + .quad 27690 + .quad 27799 + .quad 27909 + .quad 28019 + .quad 28129 + .quad 28239 + .quad 28350 + .quad 28462 + .quad 28575 + .quad 28688 + .quad 28802 + .quad 28915 + .quad 29028 + .quad 29144 + .quad 29258 + .quad 29375 + .quad 29492 + .quad 29608 + .quad 29724 + .quad 29841 + .quad 29951 + .quad 30070 + .quad 30190 + .quad 30310 + .quad 30430 + .quad 30550 + .quad 30664 + .quad 30786 + .quad 30906 + .quad 31029 + .quad 31152 + .quad 31274 + .quad 31396 + .quad 31519 + .quad 31643 + .quad 31763 + .quad 31886 + .quad 32014 + .quad 32138 + .quad 32263 + .quad 32393 + .quad 32525 + .quad 32658 + .quad 32779 + .quad 32913 + .quad 33047 + .quad 33177 + .quad 33312 + .quad 33450 + .quad 33586 + .quad 33721 + .quad 33861 + .quad 34019 + .quad 34182 + .quad 34344 + .quad 34509 + .quad 34675 + .quad 34842 + .quad 35003 + .quad 35169 + .quad 35337 + .quad 35505 + .quad 35673 + .quad 35842 + .quad 36012 + .quad 36182 + .quad 36347 + .quad 36521 + .quad 36696 + .quad 36869 + .quad 37042 + .quad 37212 + .quad 37387 + .quad 37562 + .quad 37737 + .quad 37912 + .quad 38083 + .quad 38260 + .quad 38437 + .quad 38610 + .quad 38788 + .quad 38963 + .quad 39141 + .quad 39320 + .quad 39501 + .quad 39683 + .quad 39866 + .quad 40044 + .quad 40224 + .quad 40406 + .quad 40585 + .quad 40770 + .quad 40951 + .quad 41132 + .quad 41316 + .quad 41498 + .quad 41681 + .quad 41865 + .quad 42045 + .quad 42232 + .quad 42418 + .quad 42601 + .quad 42785 + .quad 42972 + .quad 43167 + .quad 43355 + .quad 43543 + .quad 43733 + .quad 43923 + .quad 44124 + .quad 44316 + .quad 44509 + .quad 44702 + .quad 44895 + .quad 45089 + .quad 45286 + .quad 45485 + .quad 45684 + .quad 45880 + .quad 46077 + .quad 46279 + .quad 46482 + .quad 46687 + .quad 46735 + .quad 46784 + .quad 46830 + .quad 46876 + .quad 46925 + .quad 46974 + .quad 47023 + .quad 47072 + .quad 47124 + .quad 47176 + .quad 47199 + .quad 47231 + .quad 47272 + .quad 47314 + .quad 47351 + .quad 47390 + .quad 47420 + .quad 47475 + .quad 47530 + .quad 47559 + .quad 47608 .quad 47657 - .quad 47733 - .quad 47809 - .quad 47885 - .quad 47961 - .quad 48037 - .quad 48113 - .quad 48189 - .quad 48265 - .quad 48341 - .quad 48417 - .quad 48493 - .quad 48569 - .quad 48645 - .quad 48721 - .quad 48797 - .quad 48873 - .quad 48949 - .quad 49025 - .quad 49101 - .quad 49147 - .quad 49204 - .quad 49264 - .quad 49320 - .quad 49378 - .quad 49414 - .quad 49442 - .quad 49458 - .quad 49473 - .quad 49485 - .quad 49499 - .quad 49514 - .quad 49522 - .quad 49530 - .quad 49540 - .quad 49556 - .quad 49571 - .quad 49587 - .quad 49603 - .quad 49620 - .quad 49632 - .quad 49649 - .quad 49667 - .quad 49675 - .quad 49693 - .quad 49705 - .quad 49715 - .quad 49727 - .quad 49737 - .quad 49748 - .quad 49761 - .quad 49772 - .quad 49781 - .quad 49791 - .quad 49799 - .quad 49845 - .quad 49891 - .quad 49937 - .quad 49983 + .quad 47708 + .quad 47753 + .quad 47798 + .quad 47843 + .quad 47888 + .quad 47935 + .quad 47982 + .quad 48029 + .quad 48076 + .quad 48123 + .quad 48170 + .quad 48220 + .quad 48270 + .quad 48320 + .quad 48370 + .quad 48420 + .quad 48470 + .quad 48520 + .quad 48573 + .quad 48626 + .quad 48679 + .quad 48732 + .quad 48785 + .quad 48838 + .quad 48894 + .quad 48950 + .quad 49009 + .quad 49060 + .quad 49090 + .quad 49120 + .quad 49150 + .quad 49180 + .quad 49221 + .quad 49263 + .quad 49310 + .quad 49347 + .quad 49386 + .quad 49418 + .quad 49450 + .quad 49505 + .quad 49616 + .quad 49648 + .quad 49682 + .quad 49718 + .quad 49759 + .quad 49801 + .quad 49843 + .quad 49888 + .quad 49935 + .quad 49982 .quad 50029 - .quad 50075 - .quad 50121 - .quad 50167 - .quad 50213 - .quad 50259 - .quad 50305 - .quad 50351 - .quad 50397 - .quad 50443 - .quad 50489 - .quad 50535 - .quad 50581 - .quad 50627 - .quad 50673 - .quad 50719 - .quad 50765 - .quad 50811 - .quad 50857 - .quad 50903 - .quad 50949 - .quad 50995 - .quad 51041 - .quad 51087 - .quad 51133 - .quad 51179 - .quad 51225 - .quad 51271 - .quad 51317 - .quad 51363 - .quad 51409 - .quad 51455 - .quad 51501 - .quad 51547 - .quad 51593 - .quad 51639 - .quad 51685 - .quad 51731 - .quad 51777 - .quad 51823 - .quad 51869 - .quad 51915 - .quad 51961 - .quad 52007 - .quad 52053 - .quad 52099 - .quad 52145 - .quad 52191 - .quad 52237 - .quad 52283 - .quad 52329 - .quad 52375 - .quad 52421 - .quad 52467 - .quad 52513 - .quad 52559 - .quad 52605 - .quad 52651 - .quad 52697 - .quad 52743 - .quad 52789 - .quad 52835 - .quad 52881 - .quad 52927 - .quad 52973 - .quad 53019 - .quad 53065 - .quad 53111 - .quad 53157 - .quad 53203 - .quad 53249 - .quad 53295 - .quad 53341 - .quad 53387 - .quad 53433 - .quad 53479 - .quad 53525 - .quad 53571 - .quad 53617 - .quad 53663 - .quad 53709 - .quad 53755 - .quad 53801 - .quad 53847 - .quad 53893 - .quad 53939 - .quad 53985 - .quad 54031 - .quad 54077 - .quad 54123 - .quad 54169 - .quad 54215 - .quad 54261 - .quad 54307 - .quad 54353 - .quad 54399 - .quad 54445 - .quad 54491 - .quad 54537 - .quad 54583 - .quad 54629 - .quad 54675 - .quad 54721 - .quad 54767 - .quad 54813 - .quad 54859 - .quad 54905 - .quad 54951 - .quad 54997 - .quad 55043 - .quad 55089 - .quad 55135 - .quad 55181 - .quad 55227 - .quad 55273 - .quad 55319 - .quad 55365 - .quad 55411 - .quad 55457 - .quad 55503 - .quad 55549 - .quad 55595 - .quad 55641 - .quad 55687 - .quad 55733 - .quad 55779 - .quad 55816 - .quad 55866 - .quad 55916 - .quad 55966 - .quad 56016 - .quad 56066 - .quad 56116 - .quad 56166 - .quad 56216 - .quad 56266 - .quad 56316 - .quad 56366 - .quad 56416 - .quad 56466 - .quad 56516 - .quad 56566 - .quad 56616 - .quad 56666 - .quad 56716 - .quad 56766 - .quad 56816 - .quad 56866 - .quad 56916 - .quad 56966 - .quad 57016 - .quad 57066 - .quad 57116 - .quad 57166 - .quad 57216 - .quad 57266 - .quad 57316 - .quad 57366 - .quad 57416 - .quad 57466 - .quad 57516 - .quad 57566 - .quad 57616 - .quad 57666 - .quad 57716 - .quad 57766 - .quad 57816 - .quad 57866 - .quad 57916 - .quad 57966 - .quad 58016 - .quad 58066 - .quad 58116 - .quad 58166 - .quad 58216 - .quad 58266 - .quad 58316 - .quad 58366 - .quad 58416 - .quad 58466 - .quad 58516 - .quad 58566 - .quad 58616 - .quad 58666 - .quad 58716 - .quad 58766 - .quad 58816 - .quad 58866 - .quad 58916 - .quad 58966 - .quad 59016 - .quad 59066 - .quad 59116 - .quad 59166 - .quad 59216 - .quad 59266 - .quad 59316 - .quad 59366 + .quad 50076 + .quad 50126 + .quad 50176 + .quad 50226 + .quad 50279 + .quad 50332 + .quad 50385 + .quad 50463 + .quad 50538 + .quad 50583 + .quad 50626 + .quad 50659 + .quad 50695 + .quad 50726 + .quad 50758 + .quad 50782 + .quad 50806 + .quad 50838 + .quad 50862 + .quad 50888 + .quad 50914 + .quad 50941 + .quad 50968 + .quad 51009 + .quad 51051 + .quad 51098 + .quad 51135 + .quad 51174 + .quad 51227 + .quad 51282 + .quad 51337 + .quad 51376 + .quad 51406 + .quad 51438 + .quad 51487 + .quad 51544 + .quad 51598 + .quad 51647 + .quad 51687 + .quad 51729 + .quad 51774 + .quad 51819 + .quad 51866 + .quad 51913 + .quad 51963 + .quad 52013 + .quad 52063 + .quad 52113 + .quad 52166 + .quad 52219 + .quad 52297 + .quad 52372 + .quad 52447 + .quad 52494 + .quad 52530 + .quad 52586 + .quad 52646 + .quad 52707 + .quad 52726 + .quad 52781 + .quad 52812 + .quad 52867 + .quad 52924 + .quad 52966 + .quad 53008 + .quad 53050 + .quad 53092 + .quad 53134 + .quad 53176 + .quad 53218 + .quad 53265 + .quad 53309 + .quad 53353 + .quad 53358 + .quad 53376 + .quad 53458 + .quad 53519 + .quad 53582 + .quad 53649 + .quad 53720 + .quad 53794 + .quad 53848 + .quad 53879 + .quad 53920 + .quad 53961 + .quad 54003 + .quad 54045 + .quad 54082 + .quad 54119 + .quad 54158 + .quad 54197 + .quad 54337 + .quad 54479 + .quad 54512 + .quad 54569 + .quad 54632 + .quad 54703 + .quad 54774 + .quad 54845 + .quad 54916 + .quad 54961 + .quad 55009 + .quad 55060 + .quad 55111 + .quad 55162 + .quad 55213 + .quad 55264 + .quad 55315 + .quad 55366 + .quad 55395 + .quad 55425 + .quad 55455 + .quad 55487 + .quad 55519 + .quad 55552 + .quad 55620 + .quad 55693 + .quad 55766 + .quad 55840 + .quad 55918 + .quad 55985 + .quad 56053 + .quad 56122 + .quad 56191 + .quad 56261 + .quad 56332 + .quad 56403 + .quad 56474 + .quad 56545 + .quad 56617 + .quad 56689 + .quad 56764 + .quad 56835 + .quad 56908 + .quad 56981 + .quad 57030 + .quad 57084 + .quad 57139 + .quad 57198 + .quad 57241 + .quad 57287 + .quad 57379 + .quad 57471 + .quad 57563 + .quad 57658 + .quad 57756 + .quad 57868 + .quad 57919 + .quad 57972 + .quad 58021 + .quad 58077 + .quad 58133 + .quad 58189 + .quad 58245 + .quad 58301 + .quad 58357 + .quad 58408 + .quad 58458 + .quad 58508 + .quad 58537 + .quad 58590 + .quad 58646 + .quad 58740 + .quad 58834 + .quad 58915 + .quad 58996 + .quad 59077 + .quad 59158 + .quad 59183 + .quad 59204 + .quad 59264 + .quad 59306 + .quad 59359 .quad 59416 - .quad 59466 - .quad 59516 - .quad 59566 - .quad 59616 - .quad 59666 - .quad 59716 - .quad 59766 - .quad 59816 - .quad 59866 - .quad 59916 - .quad 59966 - .quad 60016 - .quad 60066 - .quad 60116 - .quad 60166 - .quad 60216 - .quad 60266 - .quad 60316 - .quad 60366 - .quad 60416 - .quad 60466 - .quad 60516 - .quad 60566 - .quad 60616 - .quad 60666 - .quad 60716 - .quad 60766 - .quad 60816 - .quad 60866 - .quad 60916 - .quad 60966 - .quad 61016 - .quad 61066 - .quad 61116 - .quad 61166 - .quad 61216 - .quad 61266 - .quad 61316 - .quad 61366 - .quad 61416 - .quad 61466 - .quad 61516 - .quad 61566 - .quad 61616 - .quad 61666 - .quad 61716 - .quad 61766 - .quad 61816 - .quad 61866 - .quad 61916 - .quad 61966 - .quad 62016 - .quad 62066 - .quad 62116 - .quad 62166 - .quad 62216 - .quad 62266 - .quad 62316 - .quad 62422 - .quad 62530 - .quad 62638 - .quad 62747 - .quad 62856 - .quad 62965 - .quad 63074 - .quad 63183 - .quad 63292 - .quad 63402 - .quad 63512 - .quad 63622 - .quad 63732 - .quad 63843 - .quad 63954 - .quad 64066 - .quad 64180 - .quad 64293 - .quad 64407 - .quad 64524 - .quad 64641 - .quad 64757 - .quad 64873 - .quad 64992 - .quad 65111 - .quad 65229 - .quad 65340 - .quad 65459 - .quad 65579 - .quad 65701 + .quad 59457 + .quad 59512 + .quad 59563 + .quad 59613 + .quad 59663 + .quad 59713 + .quad 59772 + .quad 59823 + .quad 59871 + .quad 59918 + .quad 59948 + .quad 59978 + .quad 60008 + .quad 60038 + .quad 60094 + .quad 60122 + .quad 60163 + .quad 60209 + .quad 60255 + .quad 60301 + .quad 60347 + .quad 60393 + .quad 60439 + .quad 60485 + .quad 60531 + .quad 60577 + .quad 60623 + .quad 60669 + .quad 60715 + .quad 60761 + .quad 60807 + .quad 60853 + .quad 60913 + .quad 60973 + .quad 61033 + .quad 61093 + .quad 61105 + .quad 61117 + .quad 61132 + .quad 61148 + .quad 61159 + .quad 61171 + .quad 61184 + .quad 61197 + .quad 61211 + .quad 61223 + .quad 61236 + .quad 61251 + .quad 61265 + .quad 61280 + .quad 61296 + .quad 61308 + .quad 61315 + .quad 61323 + .quad 61331 + .quad 61339 + .quad 61351 + .quad 61363 + .quad 61371 + .quad 61381 + .quad 61390 + .quad 61399 + .quad 61415 + .quad 61431 + .quad 61447 + .quad 61463 + .quad 61480 + .quad 61499 + .quad 61512 + .quad 61520 + .quad 61531 + .quad 61549 + .quad 61558 + .quad 61570 + .quad 61584 + .quad 61598 + .quad 61605 + .quad 61613 + .quad 61629 + .quad 61639 + .quad 61647 + .quad 61659 + .quad 61667 + .quad 61677 + .quad 61684 + .quad 61698 + .quad 61707 + .quad 61718 + .quad 61732 + .quad 61749 + .quad 61769 + .quad 61789 + .quad 61810 + .quad 61822 + .quad 61840 + .quad 61850 + .quad 61861 + .quad 61872 + .quad 61882 + .quad 61891 + .quad 61901 + .quad 61910 + .quad 61920 + .quad 61930 + .quad 61938 + .quad 61947 + .quad 61959 + .quad 61967 + .quad 61979 + .quad 61996 + .quad 62008 + .quad 62020 + .quad 62035 + .quad 62053 + .quad 62062 + .quad 62093 + .quad 62125 + .quad 62155 + .quad 62185 + .quad 62215 + .quad 62254 + .quad 62373 + .quad 62429 + .quad 62480 + .quad 62522 + .quad 62564 + .quad 62606 + .quad 62651 + .quad 62696 + .quad 62746 + .quad 62799 + .quad 62852 + .quad 62908 + .quad 62939 + .quad 62971 + .quad 63009 + .quad 63047 + .quad 63091 + .quad 63103 + .quad 63137 + .quad 63181 + .quad 63198 + .quad 63237 + .quad 63256 + .quad 63274 + .quad 63301 + .quad 63331 + .quad 63362 + .quad 63403 + .quad 63444 + .quad 63486 + .quad 63528 + .quad 63565 + .quad 63602 + .quad 63641 + .quad 63680 + .quad 63710 + .quad 63749 + .quad 63788 + .quad 63827 + .quad 63928 + .quad 64039 + .quad 64068 + .quad 64101 + .quad 64152 + .quad 64203 + .quad 64236 + .quad 64269 + .quad 64302 + .quad 64355 + .quad 64388 + .quad 64421 + .quad 64454 + .quad 64487 + .quad 64520 + .quad 64553 + .quad 64586 + .quad 64619 + .quad 64652 + .quad 64685 + .quad 64718 + .quad 64751 + .quad 64784 + .quad 64817 + .quad 64850 + .quad 64883 + .quad 64916 + .quad 64949 + .quad 64982 + .quad 65015 + .quad 65086 + .quad 65135 + .quad 65188 + .quad 65253 + .quad 65320 + .quad 65388 + .quad 65456 + .quad 65524 + .quad 65594 + .quad 65665 + .quad 65741 .quad 65821 - .quad 65941 - .quad 66055 - .quad 66176 - .quad 66298 - .quad 66419 - .quad 66542 - .quad 66664 + .quad 65890 + .quad 65963 + .quad 66037 + .quad 66111 + .quad 66189 + .quad 66264 + .quad 66340 + .quad 66373 + .quad 66406 + .quad 66433 + .quad 66501 + .quad 66569 + .quad 66636 + .quad 66712 .quad 66788 + .quad 66837 + .quad 66850 + .quad 66863 + .quad 66875 + .quad 66888 + .quad 66900 .quad 66912 - .quad 67036 - .quad 67162 - .quad 67283 - .quad 67412 - .quad 67539 - .quad 67667 - .quad 67795 - .quad 67920 - .quad 68050 - .quad 68175 - .quad 68307 - .quad 68429 - .quad 68563 - .quad 68693 - .quad 68826 - .quad 68962 - .quad 69101 - .quad 69241 - .quad 69379 - .quad 69515 - .quad 69650 - .quad 69790 - .quad 69948 - .quad 70110 - .quad 70275 - .quad 70441 - .quad 70608 - .quad 70769 - .quad 70935 - .quad 71103 - .quad 71271 - .quad 71440 - .quad 71610 - .quad 71775 - .quad 71949 - .quad 72124 - .quad 72297 - .quad 72467 - .quad 72642 - .quad 72817 - .quad 72992 - .quad 73163 - .quad 73340 - .quad 73517 + .quad 66925 + .quad 66943 + .quad 66961 + .quad 66980 + .quad 66996 + .quad 67013 + .quad 67037 + .quad 67053 + .quad 67062 + .quad 67075 + .quad 67089 + .quad 67102 + .quad 67111 + .quad 67123 + .quad 67133 + .quad 67146 + .quad 67159 + .quad 67167 + .quad 67178 + .quad 67195 + .quad 67205 + .quad 67215 + .quad 67233 + .quad 67251 + .quad 67343 + .quad 67373 + .quad 67419 + .quad 67468 + .quad 67532 + .quad 67563 + .quad 67594 + .quad 67625 + .quad 67656 + .quad 67690 + .quad 67719 + .quad 67836 + .quad 67953 + .quad 68001 + .quad 68049 + .quad 68097 + .quad 68149 + .quad 68199 + .quad 68249 + .quad 68299 + .quad 68358 + .quad 68439 + .quad 68520 + .quad 68601 + .quad 68639 + .quad 68674 + .quad 68728 + .quad 68737 + .quad 68823 + .quad 68909 + .quad 68940 + .quad 68971 + .quad 69002 + .quad 69032 + .quad 69062 + .quad 69103 + .quad 69145 + .quad 69182 + .quad 69221 + .quad 69276 + .quad 69304 + .quad 69405 + .quad 69436 + .quad 69479 + .quad 69527 + .quad 69578 + .quad 69633 + .quad 69682 + .quad 69738 + .quad 69793 + .quad 69835 + .quad 69880 + .quad 69925 + .quad 69972 + .quad 70019 + .quad 70066 + .quad 70113 + .quad 70169 + .quad 70219 + .quad 70269 + .quad 70319 + .quad 70369 + .quad 70419 + .quad 70449 + .quad 70479 + .quad 70511 + .quad 70564 + .quad 70620 + .quad 70675 + .quad 70709 + .quad 70765 + .quad 70822 + .quad 70880 + .quad 70937 + .quad 71000 + .quad 71063 + .quad 71119 + .quad 71185 + .quad 71252 + .quad 71315 + .quad 71391 + .quad 71461 + .quad 71530 + .quad 71599 + .quad 71668 + .quad 71739 + .quad 71810 + .quad 71882 + .quad 71943 + .quad 71973 + .quad 72003 + .quad 72070 + .quad 72135 + .quad 72203 + .quad 72270 + .quad 72336 + .quad 72405 + .quad 72475 + .quad 72499 + .quad 72523 + .quad 72549 + .quad 72575 + .quad 72602 + .quad 72629 + .quad 72659 + .quad 72689 + .quad 72730 + .quad 72772 + .quad 72809 + .quad 72848 + .quad 72880 + .quad 72935 + .quad 73036 + .quad 73087 + .quad 73140 + .quad 73174 + .quad 73234 + .quad 73287 + .quad 73344 + .quad 73402 + .quad 73449 + .quad 73496 + .quad 73546 + .quad 73596 + .quad 73646 .quad 73696 - .quad 73869 - .quad 74047 - .quad 74226 - .quad 74401 - .quad 74579 - .quad 74758 - .quad 74939 - .quad 75121 - .quad 75304 - .quad 75482 - .quad 75662 - .quad 75844 - .quad 76023 - .quad 76208 - .quad 76389 - .quad 76570 - .quad 76754 - .quad 76936 - .quad 77119 - .quad 77303 - .quad 77483 - .quad 77669 - .quad 77852 - .quad 78036 - .quad 78227 - .quad 78414 - .quad 78609 - .quad 78797 - .quad 78985 - .quad 79175 - .quad 79365 - .quad 79566 + .quad 73746 + .quad 73796 + .quad 73849 + .quad 73905 + .quad 73961 + .quad 74020 + .quad 74079 + .quad 74114 + .quad 74191 + .quad 74270 + .quad 74285 + .quad 74297 + .quad 74312 + .quad 74327 + .quad 74343 + .quad 74360 + .quad 74375 + .quad 74383 + .quad 74394 + .quad 74405 + .quad 74423 + .quad 74433 + .quad 74442 + .quad 74458 + .quad 74469 + .quad 74478 + .quad 74499 + .quad 74512 + .quad 74525 + .quad 74536 + .quad 74544 + .quad 74571 + .quad 74601 + .quad 74656 + .quad 74784 + .quad 74816 + .quad 74864 + .quad 74918 + .quad 74976 + .quad 75028 + .quad 75072 + .quad 75146 + .quad 75199 + .quad 75253 + .quad 75315 + .quad 75377 + .quad 75432 + .quad 75486 + .quad 75539 + .quad 75587 + .quad 75617 + .quad 75663 + .quad 75694 + .quad 75727 + .quad 75763 + .quad 75797 + .quad 75831 + .quad 75866 + .quad 75901 + .quad 75938 + .quad 75974 + .quad 76011 + .quad 76041 + .quad 76071 + .quad 76101 + .quad 76131 + .quad 76161 + .quad 76191 + .quad 76221 + .quad 76254 + .quad 76307 + .quad 76360 + .quad 76425 + .quad 76490 + .quad 76581 + .quad 76634 + .quad 76664 + .quad 76694 + .quad 76726 + .quad 76777 + .quad 76831 + .quad 76886 + .quad 76941 + .quad 77004 + .quad 77035 + .quad 77058 + .quad 77087 + .quad 77121 + .quad 77161 + .quad 77191 + .quad 77222 + .quad 77263 + .quad 77307 + .quad 77351 + .quad 77405 + .quad 77445 + .quad 77526 + .quad 77569 + .quad 77612 + .quad 77657 + .quad 77702 + .quad 77747 + .quad 77792 + .quad 77872 + .quad 77902 + .quad 77917 + .quad 77948 + .quad 77979 + .quad 78020 + .quad 78061 + .quad 78102 + .quad 78143 + .quad 78184 + .quad 78225 + .quad 78266 + .quad 78307 + .quad 78348 + .quad 78389 + .quad 78431 + .quad 78473 + .quad 78515 + .quad 78557 + .quad 78599 + .quad 78641 + .quad 78683 + .quad 78725 + .quad 78767 + .quad 78809 + .quad 78846 + .quad 78883 + .quad 78920 + .quad 78957 + .quad 78994 + .quad 79031 + .quad 79068 + .quad 79105 + .quad 79142 + .quad 79179 + .quad 79218 + .quad 79257 + .quad 79296 + .quad 79335 + .quad 79374 + .quad 79413 + .quad 79452 + .quad 79491 + .quad 79530 + .quad 79569 + .quad 79608 + .quad 79647 .quad 79758 - .quad 79951 - .quad 80144 - .quad 80337 - .quad 80531 - .quad 80728 - .quad 80927 - .quad 81126 - .quad 81322 - .quad 81519 - .quad 81721 - .quad 81924 - .quad 82129 - .quad 82177 - .quad 82226 - .quad 82272 - .quad 82318 - .quad 82367 - .quad 82416 - .quad 82465 - .quad 82514 - .quad 82566 - .quad 82618 - .quad 82680 - .quad 82743 - .quad 82792 - .quad 82843 - .quad 82884 - .quad 82925 - .quad 82966 - .quad 83007 - .quad 83048 - .quad 83089 - .quad 83130 - .quad 83172 - .quad 83214 - .quad 83256 - .quad 83298 - .quad 83340 - .quad 83382 - .quad 83424 - .quad 83461 - .quad 83498 - .quad 83535 - .quad 83572 - .quad 83609 - .quad 83646 - .quad 83683 - .quad 83722 - .quad 83761 - .quad 83800 - .quad 83839 - .quad 83878 - .quad 83917 - .quad 83956 - .quad 83995 - .quad 84034 - .quad 84064 - .quad 84096 - .quad 84127 - .quad 84187 - .quad 84235 - .quad 84286 - .quad 84339 - .quad 84396 - .quad 84453 - .quad 84512 - .quad 84571 - .quad 84630 - .quad 84691 - .quad 84755 - .quad 84822 - .quad 84895 - .quad 84932 - .quad 84969 + .quad 79885 + .quad 80025 + .quad 80075 + .quad 80125 + .quad 80176 + .quad 80228 + .quad 80280 + .quad 80333 + .quad 80387 + .quad 80442 + .quad 80495 + .quad 80548 + .quad 80579 + .quad 80610 + .quad 80671 + .quad 80730 + .quad 80796 + .quad 80860 + .quad 80924 + .quad 80995 + .quad 81056 + .quad 81124 + .quad 81190 + .quad 81258 + .quad 81331 + .quad 81397 + .quad 81463 + .quad 81531 + .quad 81588 + .quad 81647 + .quad 81706 + .quad 81765 + .quad 81794 + .quad 81823 + .quad 81852 + .quad 81882 + .quad 81912 + .quad 81942 + .quad 81972 + .quad 82004 + .quad 82036 + .quad 82068 + .quad 82100 + .quad 82133 + .quad 82170 + .quad 82207 + .quad 82244 + .quad 82282 + .quad 82320 + .quad 82358 + .quad 82390 + .quad 82422 + .quad 82454 + .quad 82487 + .quad 82520 + .quad 82553 + .quad 82586 + .quad 82619 + .quad 82652 + .quad 82686 + .quad 82720 + .quad 82754 + .quad 82789 + .quad 82824 + .quad 82859 + .quad 82894 + .quad 82929 + .quad 82964 + .quad 83000 + .quad 83036 + .quad 83101 + .quad 83167 + .quad 83233 + .quad 83299 + .quad 83367 + .quad 83436 + .quad 83510 + .quad 83588 + .quad 83655 + .quad 83726 + .quad 83797 + .quad 83869 + .quad 83941 + .quad 84014 + .quad 84085 + .quad 84156 + .quad 84231 + .quad 84296 + .quad 84370 + .quad 84438 + .quad 84505 + .quad 84572 + .quad 84641 + .quad 84667 + .quad 84693 + .quad 84714 + .quad 84739 + .quad 84760 + .quad 84813 + .quad 84846 + .quad 84879 + .quad 84912 + .quad 84945 + .quad 84978 .quad 85011 - .quad 85053 - .quad 85095 - .quad 85137 - .quad 85179 - .quad 85221 - .quad 85263 - .quad 85305 - .quad 85347 - .quad 85389 - .quad 85431 + .quad 85044 + .quad 85077 + .quad 85110 + .quad 85143 + .quad 85176 + .quad 85209 + .quad 85242 + .quad 85275 + .quad 85308 + .quad 85341 + .quad 85374 + .quad 85407 + .quad 85440 .quad 85473 - .quad 85515 - .quad 85557 - .quad 85599 - .quad 85641 - .quad 85683 - .quad 85725 - .quad 85767 - .quad 85809 - .quad 85851 - .quad 85893 - .quad 85935 - .quad 85997 - .quad 86060 - .quad 86124 - .quad 86193 - .quad 86222 - .quad 86251 - .quad 86281 - .quad 86311 - .quad 86341 - .quad 86373 - .quad 86405 - .quad 86437 - .quad 86474 - .quad 86511 - .quad 86548 + .quad 85506 + .quad 85539 + .quad 85572 + .quad 85605 + .quad 85638 + .quad 85671 + .quad 85704 + .quad 85737 + .quad 85770 + .quad 85803 + .quad 85836 + .quad 85869 + .quad 85940 + .quad 85989 + .quad 86081 + .quad 86173 + .quad 86265 + .quad 86296 + .quad 86337 + .quad 86378 + .quad 86419 + .quad 86460 + .quad 86502 + .quad 86544 .quad 86586 - .quad 86624 - .quad 86662 - .quad 86694 - .quad 86726 - .quad 86758 - .quad 86791 - .quad 86824 - .quad 86857 - .quad 86890 - .quad 86923 - .quad 86956 - .quad 86990 - .quad 87024 - .quad 87058 - .quad 87093 - .quad 87128 - .quad 87163 - .quad 87198 - .quad 87233 - .quad 87268 - .quad 87304 - .quad 87340 - .quad 87424 - .quad 87508 - .quad 87583 - .quad 87651 - .quad 87722 - .quad 87793 - .quad 87866 - .quad 87939 - .quad 88014 - .quad 88080 - .quad 88146 - .quad 88224 - .quad 88292 - .quad 88372 - .quad 88445 - .quad 88518 - .quad 88593 - .quad 88621 - .quad 88673 - .quad 88780 - .quad 88869 - .quad 88960 - .quad 89044 - .quad 89116 - .quad 89197 - .quad 89272 - .quad 89346 - .quad 89420 - .quad 89496 - .quad 89529 - .quad 89562 - .quad 89640 - .quad 89668 - .quad 89680 - .quad 89692 - .quad 89706 - .quad 89718 - .quad 89730 - .quad 89743 - .quad 89751 - .quad 89768 - .quad 89787 - .quad 89802 - .quad 89813 - .quad 89830 + .quad 86628 + .quad 86665 + .quad 86702 + .quad 86739 + .quad 86776 + .quad 86877 + .quad 86927 + .quad 86978 + .quad 87031 + .quad 87084 + .quad 87137 + .quad 87193 + .quad 87249 + .quad 87305 + .quad 87361 + .quad 87417 + .quad 87473 + .quad 87529 + .quad 87585 + .quad 87641 + .quad 87697 + .quad 87753 + .quad 87816 + .quad 87845 + .quad 87875 + .quad 87905 + .quad 87937 + .quad 87970 + .quad 88007 + .quad 88045 + .quad 88076 + .quad 88108 + .quad 88141 + .quad 88174 + .quad 88208 + .quad 88243 + .quad 88278 + .quad 88314 + .quad 88395 + .quad 88476 + .quad 88557 + .quad 88638 + .quad 88719 + .quad 88800 + .quad 88868 + .quad 88944 + .quad 89015 + .quad 89080 + .quad 89144 + .quad 89208 + .quad 89274 + .quad 89343 + .quad 89366 + .quad 89608 .quad 89850 - .quad 89871 - .quad 89882 - .quad 89906 - .quad 89931 - .quad 89955 - .quad 89980 - .quad 89994 - .quad 90002 - .quad 90013 - .quad 90023 - .quad 90032 - .quad 90039 - .quad 90053 - .quad 90062 - .quad 90073 - .quad 90086 - .quad 90099 - .quad 90107 - .quad 90117 - .quad 90129 - .quad 90138 - .quad 90187 - .quad 90236 - .quad 90285 - .quad 90316 - .quad 90346 - .quad 90387 - .quad 90429 - .quad 90466 - .quad 90505 - .quad 90560 - .quad 90599 - .quad 90638 - .quad 90677 - .quad 90716 - .quad 90817 - .quad 90952 - .quad 90984 - .quad 91038 - .quad 91093 - .quad 91151 - .quad 91202 - .quad 91260 - .quad 91294 - .quad 91339 - .quad 91384 - .quad 91431 - .quad 91481 - .quad 91526 - .quad 91572 - .quad 91615 - .quad 91658 - .quad 91703 - .quad 91749 - .quad 91808 - .quad 91887 - .quad 91967 + .quad 90092 + .quad 90334 + .quad 90576 + .quad 90818 + .quad 91060 + .quad 91302 + .quad 91374 + .quad 91446 + .quad 91518 + .quad 91590 + .quad 91663 + .quad 91736 + .quad 91809 + .quad 91882 + .quad 91964 .quad 92046 - .quad 92129 - .quad 92217 - .quad 92305 - .quad 92386 - .quad 92466 - .quad 92552 - .quad 92636 - .quad 92715 - .quad 92770 - .quad 92807 - .quad 92845 - .quad 92885 - .quad 92926 - .quad 92967 - .quad 93009 - .quad 93051 - .quad 93095 - .quad 93130 - .quad 93157 - .quad 93190 - .quad 93198 - .quad 93210 - .quad 93239 - .quad 93248 - .quad 93257 - .quad 93264 - .quad 93278 - .quad 93298 - .quad 93316 - .quad 93339 - .quad 93359 - .quad 93380 - .quad 93405 - .quad 93432 - .quad 93452 - .quad 93474 - .quad 93498 - .quad 93511 - .quad 93535 - .quad 93557 - .quad 93582 - .quad 93600 - .quad 93609 - .quad 93618 - .quad 93636 - .quad 93687 - .quad 93739 - .quad 93764 - .quad 93794 - .quad 93819 - .quad 93844 - .quad 93872 - .quad 93903 - .quad 93995 - .quad 94025 - .quad 94055 - .quad 94085 - .quad 94114 - .quad 94143 - .quad 94171 - .quad 94199 - .quad 94227 - .quad 94334 - .quad 94366 - .quad 94396 - .quad 94427 - .quad 94460 - .quad 94506 - .quad 94559 - .quad 94622 - .quad 94674 - .quad 94738 - .quad 94808 - .quad 94851 - .quad 94908 - .quad 94966 - .quad 95014 - .quad 95063 - .quad 95097 - .quad 95153 - .quad 95208 - .quad 95237 - .quad 95354 - .quad 95471 - .quad 95499 - .quad 95543 - .quad 95591 - .quad 95639 - .quad 95687 - .quad 95739 - .quad 95802 - .quad 95879 - .quad 95926 - .quad 95961 - .quad 95997 - .quad 96078 - .quad 96159 - .quad 96240 - .quad 96321 - .quad 96385 - .quad 96450 - .quad 96482 - .quad 96543 - .quad 96585 - .quad 96624 + .quad 92128 + .quad 92210 + .quad 92275 + .quad 92340 + .quad 92405 + .quad 92470 + .quad 92750 + .quad 93030 + .quad 93310 + .quad 93590 + .quad 93884 + .quad 94178 + .quad 94472 + .quad 94766 + .quad 95065 + .quad 95364 + .quad 95663 + .quad 95962 + .quad 96261 + .quad 96560 + .quad 96591 + .quad 96622 .quad 96653 - .quad 96711 - .quad 96740 - .quad 96773 - .quad 96800 - .quad 96829 - .quad 96919 - .quad 96968 - .quad 96999 - .quad 97030 - .quad 97060 - .quad 97090 - .quad 97120 - .quad 97150 - .quad 97180 - .quad 97210 - .quad 97240 - .quad 97270 - .quad 97300 - .quad 97330 - .quad 97360 - .quad 97390 - .quad 97420 - .quad 97450 - .quad 97480 - .quad 97510 - .quad 97540 - .quad 97570 - .quad 97611 - .quad 97653 - .quad 97690 - .quad 97729 - .quad 97761 - .quad 97793 - .quad 97825 - .quad 97857 - .quad 97910 - .quad 97965 - .quad 98020 - .quad 98059 - .quad 98098 - .quad 98128 - .quad 98160 + .quad 96684 + .quad 96715 + .quad 96756 + .quad 96797 + .quad 96838 + .quad 96880 + .quad 96922 + .quad 96969 + .quad 97011 + .quad 97048 + .quad 97085 + .quad 97122 + .quad 97161 + .quad 97200 + .quad 97239 + .quad 97350 + .quad 97490 + .quad 97632 + .quad 97677 + .quad 97718 + .quad 97759 + .quad 97801 + .quad 97843 + .quad 97887 + .quad 97931 + .quad 98003 + .quad 98047 + .quad 98091 + .quad 98120 + .quad 98150 + .quad 98182 .quad 98214 - .quad 98255 - .quad 98289 - .quad 98325 - .quad 98361 - .quad 98394 - .quad 98449 - .quad 98498 - .quad 98549 - .quad 98605 - .quad 98636 - .quad 98667 - .quad 98703 - .quad 98739 - .quad 98809 - .quad 98880 - .quad 98947 - .quad 99015 - .quad 99090 - .quad 99135 - .quad 99181 + .quad 98247 + .quad 98278 + .quad 98309 + .quad 98340 + .quad 98371 + .quad 98407 + .quad 98443 + .quad 98479 + .quad 98515 + .quad 98583 + .quad 98656 + .quad 98729 + .quad 98803 + .quad 98881 + .quad 98948 + .quad 99016 + .quad 99085 + .quad 99154 .quad 99224 - .quad 99275 - .quad 99326 - .quad 99371 - .quad 99417 - .quad 99492 - .quad 99571 - .quad 99651 - .quad 99689 - .quad 99705 - .quad 99738 - .quad 99789 - .quad 99837 - .quad 99884 - .quad 99911 - .quad 99938 - .quad 99969 - .quad 100000 - .quad 100028 - .quad 100050 - .quad 100071 - .quad 100093 - .quad 100112 - .quad 100141 - .quad 100168 - .quad 100198 - .quad 100226 - .quad 100251 - .quad 100278 - .quad 100303 - .quad 100329 - .quad 100358 - .quad 100425 - .quad 100478 - .quad 100514 - .quad 100544 - .quad 100574 - .quad 100622 - .quad 100691 - .quad 100719 + .quad 99295 + .quad 99366 + .quad 99437 + .quad 99508 + .quad 99580 + .quad 99655 + .quad 99726 + .quad 99799 + .quad 99872 + .quad 99950 + .quad 100025 + .quad 100089 + .quad 100120 + .quad 100151 + .quad 100182 + .quad 100223 + .quad 100264 + .quad 100305 + .quad 100347 + .quad 100389 + .quad 100431 + .quad 100468 + .quad 100505 + .quad 100542 + .quad 100581 + .quad 100620 + .quad 100659 .quad 100760 - .quad 100806 - .quad 100852 - .quad 100898 - .quad 100944 - .quad 100990 - .quad 101036 - .quad 101082 - .quad 101128 - .quad 101174 - .quad 101220 - .quad 101266 - .quad 101312 - .quad 101358 - .quad 101404 - .quad 101450 - .quad 101496 - .quad 101542 - .quad 101588 - .quad 101634 - .quad 101694 - .quad 101754 - .quad 101814 - .quad 101874 - .quad 101934 - .quad 101984 + .quad 100875 + .quad 100998 + .quad 101131 + .quad 101181 + .quad 101209 + .quad 101250 + .quad 101296 + .quad 101342 + .quad 101388 + .quad 101448 + .quad 101508 + .quad 101568 + .quad 101631 + .quad 101696 + .quad 101761 + .quad 101826 + .quad 101871 + .quad 101900 + .quad 101930 + .quad 101962 + .quad 101995 .quad 102038 - .quad 102092 - .quad 102187 - .quad 102283 - .quad 102335 - .quad 102444 - .quad 102554 - .quad 102583 - .quad 102626 - .quad 102668 - .quad 102681 - .quad 102694 - .quad 102706 - .quad 102721 - .quad 102732 - .quad 102744 - .quad 102757 - .quad 102770 - .quad 102782 - .quad 102795 - .quad 102808 - .quad 102823 - .quad 102830 - .quad 102839 - .quad 102854 - .quad 102870 - .quad 102887 - .quad 102905 - .quad 102924 - .quad 102940 - .quad 102960 - .quad 102981 - .quad 102990 - .quad 103004 - .quad 103020 - .quad 103033 - .quad 103044 - .quad 103062 - .quad 103070 - .quad 103083 - .quad 103143 - .quad 103152 - .quad 103168 + .quad 102071 + .quad 102145 + .quad 102220 + .quad 102298 + .quad 102379 + .quad 102447 + .quad 102515 + .quad 102584 + .quad 102654 + .quad 102724 + .quad 102794 + .quad 102867 + .quad 102947 + .quad 103027 + .quad 103104 .quad 103182 - .quad 103204 - .quad 103212 - .quad 103222 - .quad 103232 - .quad 103242 - .quad 103253 - .quad 103263 - .quad 103281 - .quad 103298 - .quad 103313 - .quad 103344 - .quad 103375 - .quad 103406 - .quad 103437 - .quad 103468 - .quad 103499 - .quad 103529 - .quad 103559 - .quad 103589 - .quad 103630 - .quad 103671 - .quad 103712 - .quad 103753 - .quad 103794 - .quad 103835 - .quad 103876 - .quad 103917 - .quad 103958 - .quad 103999 - .quad 104040 - .quad 104082 - .quad 104124 - .quad 104166 - .quad 104208 - .quad 104250 - .quad 104292 - .quad 104334 - .quad 104376 - .quad 104418 - .quad 104460 - .quad 104502 - .quad 104539 - .quad 104576 - .quad 104613 - .quad 104650 - .quad 104687 - .quad 104724 - .quad 104761 - .quad 104798 - .quad 104835 - .quad 104872 - .quad 104909 - .quad 104948 - .quad 104987 - .quad 105026 - .quad 105065 - .quad 105104 - .quad 105143 - .quad 105182 - .quad 105237 - .quad 105266 - .quad 105294 - .quad 105333 - .quad 105439 - .quad 105540 - .quad 105674 - .quad 105808 - .quad 105948 - .quad 106095 - .quad 106138 - .quad 106186 - .quad 106235 - .quad 106286 - .quad 106341 - .quad 106409 - .quad 106458 - .quad 106514 - .quad 106569 - .quad 106613 - .quad 106654 - .quad 106717 - .quad 106781 - .quad 106846 - .quad 106903 - .quad 106962 - .quad 107021 - .quad 107080 - .quad 107137 - .quad 107196 - .quad 107255 - .quad 107320 - .quad 107385 - .quad 107414 - .quad 107443 - .quad 107473 - .quad 107503 - .quad 107533 - .quad 107563 - .quad 107595 - .quad 107627 - .quad 107659 - .quad 107692 - .quad 107725 - .quad 107762 - .quad 107800 - .quad 107831 - .quad 107863 - .quad 107896 + .quad 103260 + .quad 103338 + .quad 103422 + .quad 103503 + .quad 103584 + .quad 103665 + .quad 103713 + .quad 103762 + .quad 103815 + .quad 103872 + .quad 103910 + .quad 103950 + .quad 103993 + .quad 104037 + .quad 104065 + .quad 104093 + .quad 104146 + .quad 104199 + .quad 104254 + .quad 104320 + .quad 104407 + .quad 104438 + .quad 104469 + .quad 104500 + .quad 104531 + .quad 104561 + .quad 104602 + .quad 104643 + .quad 104684 + .quad 104726 + .quad 104773 + .quad 104815 + .quad 104857 + .quad 104894 + .quad 104931 + .quad 104968 + .quad 105007 + .quad 105046 + .quad 105085 + .quad 105186 + .quad 105301 + .quad 105430 + .quad 105572 + .quad 105605 + .quad 105633 + .quad 105665 + .quad 105699 + .quad 105746 + .quad 105770 + .quad 105797 + .quad 105836 + .quad 105876 + .quad 105927 + .quad 105984 + .quad 106043 + .quad 106102 + .quad 106161 + .quad 106215 + .quad 106244 + .quad 106274 + .quad 106304 + .quad 106336 + .quad 106369 + .quad 106398 + .quad 106429 + .quad 106460 + .quad 106496 + .quad 106532 + .quad 106605 + .quad 106678 + .quad 106748 + .quad 106819 + .quad 106890 + .quad 106961 + .quad 107039 + .quad 107114 + .quad 107189 + .quad 107220 + .quad 107251 + .quad 107292 + .quad 107333 + .quad 107374 + .quad 107415 + .quad 107456 + .quad 107498 + .quad 107540 + .quad 107582 + .quad 107624 + .quad 107666 + .quad 107703 + .quad 107740 + .quad 107777 + .quad 107814 + .quad 107851 + .quad 107890 .quad 107929 - .quad 107963 - .quad 107998 - .quad 108033 - .quad 108069 - .quad 108142 - .quad 108213 - .quad 108284 - .quad 108355 - .quad 108446 - .quad 108536 - .quad 108627 - .quad 108696 - .quad 108743 - .quad 108832 - .quad 108922 - .quad 109014 - .quad 109107 - .quad 109197 - .quad 109287 - .quad 109376 - .quad 109469 - .quad 109559 - .quad 109657 - .quad 109755 - .quad 109845 - .quad 109937 - .quad 110030 - .quad 110126 - .quad 110222 - .quad 110316 - .quad 110373 - .quad 110456 - .quad 110542 - .quad 110625 - .quad 110703 - .quad 110775 - .quad 110846 - .quad 110917 + .quad 107968 + .quad 108007 + .quad 108046 + .quad 108147 + .quad 108289 + .quad 108431 + .quad 108578 + .quad 108727 + .quad 108777 + .quad 108806 + .quad 108836 + .quad 108866 + .quad 108898 + .quad 108930 + .quad 108963 + .quad 109031 + .quad 109104 + .quad 109177 + .quad 109245 + .quad 109314 + .quad 109383 + .quad 109453 + .quad 109524 + .quad 109595 + .quad 109668 + .quad 109742 + .quad 109823 + .quad 109901 + .quad 109986 + .quad 110053 + .quad 110121 + .quad 110190 + .quad 110259 + .quad 110328 + .quad 110399 + .quad 110470 + .quad 110541 + .quad 110612 + .quad 110684 + .quad 110763 + .quad 110835 + .quad 110910 .quad 110990 - .quad 111066 - .quad 111096 - .quad 111124 - .quad 111179 - .quad 111204 - .quad 111225 - .quad 111280 - .quad 111311 - .quad 111345 - .quad 111420 - .quad 111496 - .quad 111573 - .quad 111664 - .quad 111740 - .quad 111822 - .quad 111904 - .quad 111979 - .quad 112068 - .quad 112134 - .quad 112201 - .quad 112264 - .quad 112340 - .quad 112410 + .quad 111064 + .quad 111139 + .quad 111215 + .quad 111291 + .quad 111367 + .quad 111452 + .quad 111529 + .quad 111607 + .quad 111685 + .quad 111764 + .quad 111839 + .quad 111921 + .quad 112009 + .quad 112040 + .quad 112071 + .quad 112102 + .quad 112133 + .quad 112174 + .quad 112216 + .quad 112253 + .quad 112292 + .quad 112403 + .quad 112431 .quad 112479 - .quad 112548 - .quad 112617 - .quad 112688 - .quad 112759 - .quad 112831 - .quad 112892 - .quad 112941 - .quad 112967 - .quad 112983 - .quad 112999 - .quad 113011 - .quad 113029 - .quad 113041 - .quad 113050 - .quad 113066 - .quad 113079 - .quad 113103 - .quad 113111 - .quad 113178 - .quad 113243 - .quad 113311 - .quad 113378 - .quad 113444 - .quad 113513 - .quad 113583 - .quad 113595 - .quad 113605 - .quad 113613 - .quad 113624 - .quad 113634 - .quad 113646 - .quad 113654 - .quad 113666 - .quad 113678 - .quad 113696 - .quad 113790 - .quad 113821 - .quad 113852 - .quad 113883 - .quad 113914 - .quad 113946 - .quad 113987 - .quad 114028 - .quad 114070 - .quad 114112 - .quad 114149 - .quad 114186 - .quad 114225 - .quad 114264 - .quad 114294 - .quad 114349 - .quad 114404 - .quad 114443 - .quad 114554 - .quad 114583 - .quad 114651 - .quad 114700 - .quad 114751 - .quad 114796 - .quad 114843 - .quad 114890 - .quad 114949 - .quad 114999 - .quad 115049 - .quad 115099 - .quad 115130 - .quad 115161 - .quad 115192 - .quad 115228 - .quad 115264 - .quad 115300 - .quad 115378 - .quad 115453 - .quad 115541 - .quad 115630 - .quad 115723 - .quad 115805 - .quad 115891 - .quad 115977 - .quad 116063 - .quad 116150 - .quad 116237 - .quad 116306 - .quad 116372 + .quad 112517 + .quad 112556 + .quad 112612 + .quad 112668 + .quad 112726 + .quad 112786 + .quad 112817 + .quad 112848 + .quad 112884 + .quad 112920 + .quad 112982 + .quad 113049 + .quad 113117 + .quad 113185 + .quad 113253 + .quad 113323 + .quad 113394 + .quad 113470 + .quad 113550 + .quad 113619 + .quad 113695 + .quad 113768 + .quad 113842 + .quad 113923 + .quad 113997 + .quad 114078 + .quad 114156 + .quad 114231 + .quad 114305 + .quad 114382 + .quad 114460 + .quad 114542 + .quad 114625 + .quad 114712 + .quad 114792 + .quad 114872 + .quad 114952 + .quad 115013 + .quad 115079 + .quad 115109 + .quad 115195 + .quad 115225 + .quad 115262 + .quad 115299 + .quad 115341 + .quad 115383 + .quad 115425 + .quad 115467 + .quad 115509 + .quad 115553 + .quad 115593 + .quad 115638 + .quad 115684 + .quad 115731 + .quad 115780 + .quad 115821 + .quad 115862 + .quad 115993 + .quad 116135 + .quad 116163 + .quad 116191 + .quad 116230 + .quad 116269 + .quad 116309 + .quad 116349 + .quad 116393 .quad 116438 - .quad 116506 - .quad 116579 - .quad 116643 - .quad 116672 - .quad 116702 - .quad 116732 - .quad 116764 - .quad 116796 - .quad 116829 - .quad 116857 - .quad 116886 - .quad 116916 - .quad 116945 - .quad 116975 - .quad 117006 - .quad 117035 - .quad 117065 - .quad 117094 - .quad 117123 - .quad 117153 - .quad 117185 - .quad 117214 - .quad 117245 - .quad 117275 - .quad 117307 - .quad 117340 - .quad 117369 - .quad 117394 - .quad 117429 + .quad 116473 + .quad 116508 + .quad 116545 + .quad 116583 + .quad 116664 + .quad 116694 + .quad 116735 + .quad 116776 + .quad 116813 + .quad 116843 + .quad 116887 + .quad 116928 + .quad 116991 + .quad 117055 + .quad 117120 + .quad 117148 + .quad 117176 + .quad 117226 + .quad 117291 + .quad 117356 + .quad 117387 + .quad 117418 .quad 117459 - .quad 117490 - .quad 117520 - .quad 117551 + .quad 117500 + .quad 117541 .quad 117583 - .quad 117617 - .quad 117646 - .quad 117677 - .quad 117709 - .quad 117742 - .quad 117793 - .quad 117824 - .quad 117855 - .quad 117886 - .quad 117917 - .quad 117948 - .quad 117979 - .quad 118010 - .quad 118040 - .quad 118070 - .quad 118100 - .quad 118130 - .quad 118160 - .quad 118190 - .quad 118231 - .quad 118272 - .quad 118313 - .quad 118355 - .quad 118397 - .quad 118439 - .quad 118476 + .quad 117625 + .quad 117667 + .quad 117704 + .quad 117741 + .quad 117778 + .quad 117817 + .quad 117856 + .quad 117895 + .quad 117996 + .quad 118113 + .quad 118236 + .quad 118361 + .quad 118411 + .quad 118462 .quad 118513 - .quad 118550 - .quad 118589 - .quad 118628 - .quad 118667 - .quad 118706 - .quad 118745 - .quad 118856 - .quad 119003 - .quad 119152 - .quad 119200 - .quad 119269 - .quad 119322 - .quad 119375 - .quad 119406 - .quad 119437 - .quad 119468 - .quad 119499 - .quad 119530 - .quad 119561 - .quad 119592 - .quad 119623 - .quad 119668 - .quad 119716 - .quad 119764 - .quad 119813 - .quad 119866 - .quad 119904 - .quad 119944 - .quad 119987 - .quad 120031 - .quad 120059 - .quad 120087 - .quad 120115 - .quad 120163 - .quad 120201 - .quad 120240 - .quad 120290 - .quad 120343 - .quad 120396 - .quad 120449 - .quad 120502 - .quad 120555 - .quad 120608 - .quad 120663 - .quad 120719 - .quad 120775 - .quad 120833 - .quad 120893 - .quad 120922 - .quad 120952 - .quad 120982 - .quad 121014 - .quad 121046 - .quad 121079 - .quad 121110 - .quad 121141 - .quad 121172 - .quad 121208 - .quad 121244 - .quad 121280 + .quad 118558 + .quad 118587 + .quad 118617 + .quad 118649 + .quad 118681 + .quad 118714 + .quad 118787 + .quad 118862 + .quad 118942 + .quad 119022 + .quad 119103 + .quad 119188 + .quad 119262 + .quad 119337 + .quad 119413 + .quad 119489 + .quad 119565 + .quad 119642 + .quad 119720 + .quad 119798 + .quad 119876 + .quad 119954 + .quad 120033 + .quad 120112 + .quad 120187 + .quad 120264 + .quad 120342 + .quad 120424 + .quad 120511 + .quad 120588 + .quad 120666 + .quad 120744 + .quad 120824 + .quad 120904 + .quad 120984 + .quad 121065 + .quad 121096 + .quad 121137 + .quad 121178 + .quad 121219 + .quad 121260 + .quad 121301 .quad 121342 - .quad 121410 - .quad 121483 - .quad 121556 - .quad 121630 - .quad 121708 - .quad 121775 - .quad 121843 - .quad 121912 - .quad 121981 - .quad 122051 - .quad 122122 - .quad 122193 - .quad 122264 - .quad 122335 - .quad 122407 - .quad 122488 - .quad 122560 - .quad 122627 - .quad 122695 - .quad 122763 - .quad 122831 - .quad 122901 - .quad 122972 - .quad 123038 - .quad 123113 - .quad 123189 - .quad 123269 - .quad 123340 - .quad 123413 - .quad 123486 - .quad 123559 - .quad 123634 - .quad 123708 - .quad 123785 - .quad 123863 - .quad 123945 - .quad 124028 - .quad 124115 - .quad 124191 - .quad 124271 - .quad 124351 - .quad 124431 - .quad 124512 - .quad 124584 - .quad 124653 - .quad 124721 - .quad 124790 - .quad 124856 - .quad 124899 - .quad 124982 - .quad 125063 - .quad 125115 - .quad 125206 - .quad 125310 - .quad 125417 - .quad 125503 - .quad 125573 - .quad 125643 - .quad 125719 - .quad 125802 - .quad 125874 - .quad 125956 - .quad 126041 - .quad 126083 - .quad 126126 - .quad 126170 - .quad 126239 - .quad 126252 - .quad 126264 - .quad 126299 + .quad 121384 + .quad 121426 + .quad 121468 + .quad 121510 + .quad 121552 + .quad 121594 + .quad 121631 + .quad 121668 + .quad 121705 + .quad 121742 + .quad 121779 + .quad 121816 + .quad 121855 + .quad 121894 + .quad 121933 + .quad 121972 + .quad 122011 + .quad 122050 + .quad 122079 + .quad 122107 + .quad 122146 + .quad 122247 + .quad 122362 + .quad 122489 + .quad 122616 + .quad 122749 + .quad 122896 + .quad 122937 + .quad 122986 + .quad 123037 + .quad 123105 + .quad 123164 + .quad 123223 + .quad 123280 + .quad 123339 + .quad 123398 + .quad 123463 + .quad 123528 + .quad 123557 + .quad 123587 + .quad 123617 + .quad 123649 + .quad 123682 + .quad 123759 + .quad 123839 + .quad 123917 + .quad 123995 + .quad 124016 + .quad 124037 + .quad 124085 + .quad 124116 + .quad 124147 + .quad 124178 + .quad 124208 + .quad 124238 + .quad 124268 + .quad 124298 + .quad 124328 + .quad 124369 + .quad 124411 + .quad 124448 + .quad 124487 + .quad 124519 + .quad 124551 + .quad 124657 + .quad 124768 + .quad 124816 + .quad 124867 + .quad 124916 + .quad 124945 + .quad 124973 + .quad 125004 + .quad 125035 + .quad 125071 + .quad 125107 + .quad 125185 + .quad 125260 + .quad 125341 + .quad 125422 + .quad 125510 + .quad 125599 + .quad 125692 + .quad 125774 + .quad 125860 + .quad 125946 + .quad 126032 + .quad 126119 + .quad 126206 + .quad 126256 + .quad 126284 .quad 126335 - .quad 126381 - .quad 126431 - .quad 126468 - .quad 126531 - .quad 126562 - .quad 126603 - .quad 126633 - .quad 126660 - .quad 126691 - .quad 126750 - .quad 126780 - .quad 126812 - .quad 126850 - .quad 126876 - .quad 126906 - .quad 126939 - .quad 126991 - .quad 127021 - .quad 127051 - .quad 127083 - .quad 127134 - .quad 127188 - .quad 127243 - .quad 127298 - .quad 127361 - .quad 127392 - .quad 127415 - .quad 127444 - .quad 127478 - .quad 127518 - .quad 127548 - .quad 127579 - .quad 127620 - .quad 127664 - .quad 127708 - .quad 127762 - .quad 127802 - .quad 127883 - .quad 127926 - .quad 127969 - .quad 128014 - .quad 128059 - .quad 128104 - .quad 128149 - .quad 128229 - .quad 128259 - .quad 128274 - .quad 128293 - .quad 128310 - .quad 128327 - .quad 128352 - .quad 128416 - .quad 128482 - .quad 128494 - .quad 128505 - .quad 128559 - .quad 128616 - .quad 128670 - .quad 128727 - .quad 128794 - .quad 128851 - .quad 128911 - .quad 128969 - .quad 129024 - .quad 129085 - .quad 129135 - .quad 129186 - .quad 129242 - .quad 129298 - .quad 129352 - .quad 129406 - .quad 129429 - .quad 129454 - .quad 129492 - .quad 129529 - .quad 129574 - .quad 129611 - .quad 129693 - .quad 129780 - .quad 129816 - .quad 129869 - .quad 129914 - .quad 129955 - .quad 129985 - .quad 130015 - .quad 130045 - .quad 130075 - .quad 130105 - .quad 130135 - .quad 130165 - .quad 130218 - .quad 130271 - .quad 130324 - .quad 130352 - .quad 130412 - .quad 130454 - .quad 130504 - .quad 130540 - .quad 130597 - .quad 130655 - .quad 130710 - .quad 130770 - .quad 130838 - .quad 130868 - .quad 130898 - .quad 130950 - .quad 131003 - .quad 131056 - .quad 131085 + .quad 126387 + .quad 126441 + .quad 126496 + .quad 126548 + .quad 126600 + .quad 126651 + .quad 126706 + .quad 126758 + .quad 126818 + .quad 126878 + .quad 126931 + .quad 126983 + .quad 127037 + .quad 127092 + .quad 127150 + .quad 127208 + .quad 127264 + .quad 127315 + .quad 127371 + .quad 127421 + .quad 127497 + .quad 127576 + .quad 127651 + .quad 127729 + .quad 127769 + .quad 127809 + .quad 127862 + .quad 127902 + .quad 127948 + .quad 127996 + .quad 128048 + .quad 128100 + .quad 128157 + .quad 128217 + .quad 128283 + .quad 128332 + .quad 128394 + .quad 128457 + .quad 128521 + .quad 128590 + .quad 128649 + .quad 128722 + .quad 128798 + .quad 128877 + .quad 128958 + .quad 129041 + .quad 129129 + .quad 129150 + .quad 129176 + .quad 129210 + .quad 129237 + .quad 129290 + .quad 129320 + .quad 129353 + .quad 129386 + .quad 129419 + .quad 129452 + .quad 129485 + .quad 129518 + .quad 129551 + .quad 129614 + .quad 129678 + .quad 129738 + .quad 129799 + .quad 129829 + .quad 129883 + .quad 129945 + .quad 130004 + .quad 130063 + .quad 130112 + .quad 130161 + .quad 130203 + .quad 130245 + .quad 130287 + .quad 130329 + .quad 130371 + .quad 130413 + .quad 130455 + .quad 130486 + .quad 130516 + .quad 130546 + .quad 130578 + .quad 130610 + .quad 130641 + .quad 130674 + .quad 130737 + .quad 130801 + .quad 130861 + .quad 130922 + .quad 130988 + .quad 131053 .quad 131115 - .quad 131145 - .quad 131206 - .quad 131239 - .quad 131277 - .quad 131317 - .quad 131361 - .quad 131412 - .quad 131459 - .quad 131519 - .quad 131581 - .quad 131639 - .quad 131699 - .quad 131801 - .quad 131853 - .quad 131911 - .quad 132013 - .quad 132124 - .quad 132236 - .quad 132341 - .quad 132438 - .quad 132539 - .quad 132649 - .quad 132749 - .quad 132851 - .quad 132952 - .quad 133056 - .quad 133136 - .quad 133208 - .quad 133278 - .quad 133308 - .quad 133403 - .quad 133470 - .quad 133498 - .quad 133526 - .quad 133554 - .quad 133584 - .quad 133614 - .quad 133644 - .quad 133677 - .quad 133730 - .quad 133760 - .quad 133792 - .quad 133861 - .quad 133910 - .quad 133940 - .quad 133993 - .quad 134046 - .quad 134076 - .quad 134106 - .quad 134171 - .quad 134235 - .quad 134302 - .quad 134363 - .quad 134435 - .quad 134465 - .quad 134495 - .quad 134550 - .quad 134580 - .quad 134611 - .quad 134651 - .quad 134740 - .quad 134807 - .quad 134885 - .quad 134950 - .quad 134981 - .quad 135024 - .quad 135075 - .quad 135103 - .quad 135149 - .quad 135211 - .quad 135279 - .quad 135338 - .quad 135396 - .quad 135462 - .quad 135515 - .quad 135568 - .quad 135629 - .quad 135689 - .quad 135751 - .quad 135814 - .quad 135875 - .quad 135937 - .quad 135998 - .quad 136061 - .quad 136125 - .quad 136191 - .quad 136231 - .quad 136315 - .quad 136368 - .quad 136398 - .quad 136470 - .quad 136518 - .quad 136562 - .quad 136590 - .quad 136620 - .quad 136650 - .quad 136682 - .quad 136732 - .quad 136798 - .quad 136844 - .quad 136888 - .quad 136908 - .quad 136948 - .quad 137000 - .quad 137033 - .quad 137063 - .quad 137095 - .quad 137127 - .quad 137161 - .quad 137191 - .quad 137221 - .quad 137251 - .quad 137289 - .quad 137346 - .quad 137379 - .quad 137443 - .quad 137527 - .quad 137580 - .quad 137630 - .quad 137680 - .quad 137730 - .quad 137780 - .quad 137834 - .quad 137888 - .quad 137942 - .quad 137996 - .quad 138050 - .quad 138104 - .quad 138158 - .quad 138212 - .quad 138266 - .quad 138311 - .quad 138363 - .quad 138432 - .quad 138496 - .quad 138563 - .quad 138627 - .quad 138691 - .quad 138755 - .quad 138815 - .quad 138849 - .quad 138887 - .quad 138926 - .quad 138989 - .quad 139052 - .quad 139115 - .quad 139178 - .quad 139241 - .quad 139304 - .quad 139376 - .quad 139405 - .quad 139441 - .quad 139476 - .quad 139506 - .quad 139539 - .quad 139574 - .quad 139607 + .quad 131176 + .quad 131238 + .quad 131297 + .quad 131325 + .quad 131371 + .quad 131403 + .quad 131442 + .quad 131484 + .quad 131526 + .quad 131579 + .quad 131613 + .quad 131648 + .quad 131890 + .quad 132132 + .quad 132165 + .quad 132193 + .quad 132253 + .quad 132345 + .quad 132401 + .quad 132422 + .quad 132457 + .quad 132469 + .quad 132480 + .quad 132522 + .quad 132573 + .quad 132624 + .quad 132675 + .quad 132708 + .quad 132767 + .quad 132832 + .quad 132909 + .quad 132985 + .quad 133062 + .quad 133111 + .quad 133139 + .quad 133185 + .quad 133231 + .quad 133277 + .quad 133336 + .quad 133395 + .quad 133438 + .quad 133481 + .quad 133524 + .quad 133567 + .quad 133615 + .quad 133664 + .quad 133713 + .quad 133762 + .quad 133829 + .quad 133882 + .quad 133912 + .quad 133983 + .quad 134014 + .quad 134045 + .quad 134110 + .quad 134135 + .quad 134194 + .quad 134253 + .quad 134318 + .quad 134390 + .quad 134454 + .quad 134482 + .quad 134530 + .quad 134599 + .quad 134644 + .quad 134723 + .quad 134815 + .quad 134910 + .quad 134988 + .quad 135063 + .quad 135137 + .quad 135212 + .quad 135245 + .quad 135314 + .quad 135361 + .quad 135444 + .quad 135528 + .quad 135611 + .quad 135662 + .quad 135752 + .quad 135843 + .quad 135928 + .quad 136014 + .quad 136038 + .quad 136074 + .quad 136100 + .quad 136130 + .quad 136176 + .quad 136233 + .quad 136263 + .quad 136293 + .quad 136341 + .quad 136410 + .quad 136446 + .quad 136521 + .quad 136592 + .quad 136636 + .quad 136706 + .quad 136776 + .quad 136838 + .quad 136901 + .quad 136950 + .quad 137001 + .quad 137062 + .quad 137123 + .quad 137185 + .quad 137246 + .quad 137286 + .quad 137370 + .quad 137423 + .quad 137453 + .quad 137525 + .quad 137573 + .quad 137617 + .quad 137645 + .quad 137675 + .quad 137705 + .quad 137737 + .quad 137787 + .quad 137853 + .quad 137899 + .quad 137943 + .quad 137963 + .quad 138003 + .quad 138034 + .quad 138077 + .quad 138128 + .quad 138156 + .quad 138202 + .quad 138264 + .quad 138332 + .quad 138391 + .quad 138449 + .quad 138515 + .quad 138568 + .quad 138621 + .quad 138651 + .quad 138681 + .quad 138736 + .quad 138768 + .quad 138811 + .quad 138855 + .quad 138907 + .quad 138940 + .quad 138970 + .quad 139002 + .quad 139034 + .quad 139068 + .quad 139098 + .quad 139128 + .quad 139158 + .quad 139196 + .quad 139253 + .quad 139286 + .quad 139350 + .quad 139434 + .quad 139487 + .quad 139537 + .quad 139587 .quad 139637 - .quad 139671 - .quad 139701 - .quad 139736 - .quad 139793 - .quad 139900 - .quad 139972 - .quad 140012 - .quad 140055 - .quad 140100 - .quad 140147 - .quad 140190 - .quad 140246 - .quad 140288 - .quad 140330 - .quad 140372 - .quad 140414 - .quad 140464 - .quad 140519 - .quad 140562 - .quad 140601 - .quad 140633 - .quad 140663 - .quad 140693 - .quad 140725 + .quad 139687 + .quad 139741 + .quad 139795 + .quad 139849 + .quad 139903 + .quad 139957 + .quad 140011 + .quad 140065 + .quad 140119 + .quad 140173 + .quad 140218 + .quad 140270 + .quad 140339 + .quad 140403 + .quad 140470 + .quad 140534 + .quad 140598 + .quad 140662 + .quad 140722 .quad 140756 - .quad 140788 - .quad 140821 - .quad 140853 - .quad 140886 - .quad 140939 - .quad 140996 - .quad 141095 - .quad 141158 - .quad 141193 - .quad 141234 - .quad 141277 - .quad 141320 + .quad 140794 + .quad 140833 + .quad 140896 + .quad 140959 + .quad 141022 + .quad 141085 + .quad 141148 + .quad 141211 + .quad 141283 + .quad 141312 .quad 141348 - .quad 141394 - .quad 141440 - .quad 141476 - .quad 141507 - .quad 141538 - .quad 141596 - .quad 141626 - .quad 141657 - .quad 141688 - .quad 141719 - .quad 141770 - .quad 141822 - .quad 141864 - .quad 141882 - .quad 141907 - .quad 142004 - .quad 142047 - .quad 142096 - .quad 142147 - .quad 142199 - .quad 142253 - .quad 142298 - .quad 142330 - .quad 142357 - .quad 142384 - .quad 142412 - .quad 142440 - .quad 142470 - .quad 142521 - .quad 142586 - .quad 142636 - .quad 142664 - .quad 142693 - .quad 142724 - .quad 142759 - .quad 142790 - .quad 142821 - .quad 142854 - .quad 142884 - .quad 142915 - .quad 142948 - .quad 142980 - .quad 143009 - .quad 143039 - .quad 143070 - .quad 143104 - .quad 143138 - .quad 143172 - .quad 143207 - .quad 143236 - .quad 143268 - .quad 143298 - .quad 143327 - .quad 143380 - .quad 143433 - .quad 143488 - .quad 143518 - .quad 143548 - .quad 143613 - .quad 143648 - .quad 143704 - .quad 143759 - .quad 143812 - .quad 143842 - .quad 143872 - .quad 143902 - .quad 143932 - .quad 143964 - .quad 143990 - .quad 144018 - .quad 144046 - .quad 144106 - .quad 144160 - .quad 144212 + .quad 141383 + .quad 141413 + .quad 141446 + .quad 141481 + .quad 141514 + .quad 141544 + .quad 141578 + .quad 141608 + .quad 141643 + .quad 141700 + .quad 141807 + .quad 141879 + .quad 141919 + .quad 141962 + .quad 142007 + .quad 142054 + .quad 142097 + .quad 142153 + .quad 142195 + .quad 142237 + .quad 142279 + .quad 142321 + .quad 142371 + .quad 142426 + .quad 142469 + .quad 142508 + .quad 142540 + .quad 142570 + .quad 142600 + .quad 142632 + .quad 142663 + .quad 142695 + .quad 142728 + .quad 142760 + .quad 142793 + .quad 142846 + .quad 142903 + .quad 143002 + .quad 143065 + .quad 143100 + .quad 143141 + .quad 143184 + .quad 143227 + .quad 143255 + .quad 143301 + .quad 143347 + .quad 143383 + .quad 143414 + .quad 143445 + .quad 143503 + .quad 143533 + .quad 143564 + .quad 143595 + .quad 143626 + .quad 143677 + .quad 143729 + .quad 143771 + .quad 143789 + .quad 143814 + .quad 143867 + .quad 143920 + .quad 143977 + .quad 144036 + .quad 144080 + .quad 144130 + .quad 144166 + .quad 144202 .quad 144243 - .quad 144276 - .quad 144329 - .quad 144382 - .quad 144408 - .quad 144436 - .quad 144467 - .quad 144500 - .quad 144533 - .quad 144566 - .quad 144609 - .quad 144715 - .quad 144757 - .quad 144787 - .quad 144840 - .quad 144893 - .quad 144946 - .quad 144976 - .quad 145006 - .quad 145036 - .quad 145086 - .quad 145134 - .quad 145182 - .quad 145232 - .quad 145278 - .quad 145331 - .quad 145385 - .quad 145438 - .quad 145487 - .quad 145542 - .quad 145591 - .quad 145641 - .quad 145690 - .quad 145739 - .quad 145793 - .quad 145846 - .quad 145876 - .quad 145905 - .quad 145977 - .quad 146064 - .quad 146118 - .quad 146169 - .quad 146199 - .quad 146229 - .quad 146284 - .quad 146314 - .quad 146345 - .quad 146378 - .quad 146411 - .quad 146494 - .quad 146542 - .quad 146593 - .quad 146645 - .quad 146700 - .quad 146732 - .quad 146760 - .quad 146806 - .quad 146881 - .quad 146942 - .quad 147008 - .quad 147072 - .quad 147102 - .quad 147191 - .quad 147229 - .quad 147272 - .quad 147319 - .quad 147362 - .quad 147410 - .quad 147455 - .quad 147512 - .quad 147627 - .quad 147675 - .quad 147727 - .quad 147778 - .quad 147833 - .quad 147892 - .quad 147953 - .quad 148013 - .quad 148074 - .quad 148138 - .quad 148205 - .quad 148254 - .quad 148305 - .quad 148358 - .quad 148411 - .quad 148468 - .quad 148527 - .quad 148571 - .quad 148621 - .quad 148657 - .quad 148693 - .quad 148734 - .quad 148775 - .quad 148815 - .quad 148855 - .quad 148895 - .quad 148933 - .quad 148971 - .quad 149017 - .quad 149063 - .quad 149110 - .quad 149165 - .quad 149218 - .quad 149260 - .quad 149298 - .quad 149329 - .quad 149361 - .quad 149393 - .quad 149423 - .quad 149503 - .quad 149562 - .quad 149631 - .quad 149700 - .quad 149762 - .quad 149799 - .quad 149835 - .quad 149867 - .quad 149904 - .quad 149935 - .quad 149989 - .quad 150046 - .quad 150150 - .quad 150246 - .quad 150342 - .quad 150404 - .quad 150471 - .quad 150529 - .quad 150583 - .quad 150639 - .quad 150694 - .quad 150743 - .quad 150799 - .quad 150854 - .quad 150894 - .quad 150962 - .quad 151065 - .quad 151175 - .quad 151205 - .quad 151252 - .quad 151306 - .quad 151362 - .quad 151424 - .quad 151487 - .quad 151556 - .quad 151615 - .quad 151695 - .quad 151774 - .quad 151809 - .quad 151843 - .quad 151906 - .quad 151944 - .quad 151984 - .quad 152025 - .quad 152063 - .quad 152095 - .quad 152125 - .quad 152179 - .quad 152217 - .quad 152255 - .quad 152311 - .quad 152368 - .quad 152424 - .quad 152453 + .quad 144284 + .quad 144324 + .quad 144364 + .quad 144404 + .quad 144442 + .quad 144480 + .quad 144526 + .quad 144572 + .quad 144619 + .quad 144674 + .quad 144727 + .quad 144769 + .quad 144807 + .quad 144838 + .quad 144870 + .quad 144902 + .quad 144932 + .quad 145012 + .quad 145071 + .quad 145140 + .quad 145209 + .quad 145271 + .quad 145308 + .quad 145344 + .quad 145376 + .quad 145413 + .quad 145444 + .quad 145498 + .quad 145555 + .quad 145659 + .quad 145755 + .quad 145851 + .quad 145913 + .quad 145980 + .quad 146038 + .quad 146092 + .quad 146148 + .quad 146203 + .quad 146252 + .quad 146308 + .quad 146363 + .quad 146403 + .quad 146471 + .quad 146574 + .quad 146684 + .quad 146714 + .quad 146761 + .quad 146815 + .quad 146871 + .quad 146933 + .quad 146996 + .quad 147065 + .quad 147124 + .quad 147204 + .quad 147283 + .quad 147318 + .quad 147352 + .quad 147415 + .quad 147453 + .quad 147493 + .quad 147534 + .quad 147572 + .quad 147604 + .quad 147634 + .quad 147688 + .quad 147726 + .quad 147764 + .quad 147820 + .quad 147877 + .quad 147933 + .quad 147962 + .quad 148019 + .quad 148082 + .quad 148132 + .quad 148192 + .quad 148257 + .quad 148311 + .quad 148362 + .quad 148412 + .quad 148470 + .quad 148528 + .quad 148586 + .quad 148644 + .quad 148707 + .quad 148767 + .quad 148827 + .quad 148891 + .quad 148939 + .quad 148969 + .quad 148999 + .quad 149031 + .quad 149085 + .quad 149126 + .quad 149184 + .quad 149217 + .quad 149249 + .quad 149312 + .quad 149368 + .quad 149398 + .quad 149428 + .quad 149458 + .quad 149488 + .quad 149518 + .quad 149548 + .quad 149580 + .quad 149612 + .quad 149665 + .quad 149697 + .quad 149742 + .quad 149804 + .quad 149856 + .quad 149895 + .quad 149934 + .quad 149968 + .quad 149998 + .quad 150051 + .quad 150144 + .quad 150174 + .quad 150204 + .quad 150241 + .quad 150277 + .quad 150312 + .quad 150346 + .quad 150400 + .quad 150452 + .quad 150506 + .quad 150538 + .quad 150603 + .quad 150671 + .quad 150715 + .quad 150762 + .quad 150793 + .quad 150863 + .quad 150911 + .quad 150957 + .quad 151002 + .quad 151051 + .quad 151089 + .quad 151121 + .quad 151151 + .quad 151204 + .quad 151233 + .quad 151258 + .quad 151298 + .quad 151339 + .quad 151368 + .quad 151458 + .quad 151549 + .quad 151625 + .quad 151701 + .quad 151779 + .quad 151858 + .quad 151938 + .quad 152018 + .quad 152098 + .quad 152178 + .quad 152259 + .quad 152341 + .quad 152425 .quad 152510 - .quad 152573 - .quad 152623 - .quad 152683 - .quad 152748 - .quad 152802 - .quad 152853 - .quad 152903 - .quad 152961 - .quad 153019 - .quad 153077 - .quad 153135 - .quad 153198 - .quad 153258 - .quad 153318 - .quad 153382 - .quad 153430 - .quad 153460 - .quad 153490 - .quad 153522 - .quad 153576 - .quad 153617 - .quad 153675 - .quad 153708 - .quad 153740 - .quad 153803 - .quad 153859 - .quad 153889 - .quad 153919 - .quad 153949 - .quad 153979 - .quad 154009 - .quad 154039 - .quad 154071 - .quad 154103 - .quad 154156 - .quad 154188 + .quad 152570 + .quad 152636 + .quad 152666 + .quad 152696 + .quad 152726 + .quad 152755 + .quad 152786 + .quad 152817 + .quad 152848 + .quad 152900 + .quad 152949 + .quad 152998 + .quad 153047 + .quad 153096 + .quad 153145 + .quad 153194 + .quad 153243 + .quad 153294 + .quad 153345 + .quad 153396 + .quad 153447 + .quad 153498 + .quad 153549 + .quad 153600 + .quad 153627 + .quad 153654 + .quad 153709 + .quad 153741 + .quad 153775 + .quad 153808 + .quad 153821 + .quad 153833 + .quad 153891 + .quad 153924 + .quad 153999 + .quad 154076 + .quad 154163 .quad 154233 - .quad 154295 - .quad 154347 - .quad 154386 - .quad 154425 - .quad 154459 - .quad 154489 - .quad 154542 - .quad 154635 - .quad 154665 - .quad 154695 - .quad 154732 - .quad 154768 - .quad 154803 - .quad 154837 - .quad 154891 - .quad 154943 - .quad 154997 - .quad 155029 - .quad 155094 - .quad 155162 - .quad 155206 - .quad 155253 - .quad 155284 - .quad 155354 - .quad 155402 - .quad 155448 - .quad 155493 - .quad 155542 - .quad 155580 - .quad 155646 - .quad 155711 - .quad 155745 - .quad 155775 - .quad 155805 - .quad 155836 - .quad 155893 - .quad 155939 - .quad 155987 - .quad 156013 - .quad 156045 - .quad 156085 - .quad 156128 - .quad 156182 - .quad 156234 - .quad 156269 - .quad 156309 - .quad 156333 - .quad 156364 - .quad 156395 - .quad 156426 - .quad 156447 - .quad 156476 - .quad 156507 - .quad 156533 - .quad 156623 - .quad 156642 - .quad 156657 - .quad 156672 - .quad 156692 - .quad 156715 - .quad 156735 - .quad 156759 - .quad 156800 - .quad 156833 - .quad 156871 - .quad 156910 - .quad 156940 - .quad 156970 - .quad 157001 - .quad 157025 - .quad 157052 - .quad 157079 - .quad 157106 - .quad 157134 - .quad 157166 - .quad 157197 - .quad 157238 - .quad 157277 - .quad 157316 - .quad 157357 - .quad 157396 - .quad 157424 - .quad 157454 - .quad 157485 - .quad 157526 - .quad 157566 - .quad 157604 - .quad 157638 - .quad 157674 - .quad 157690 - .quad 157714 - .quad 157761 - .quad 157789 - .quad 157832 - .quad 157880 - .quad 157940 - .quad 157986 - .quad 158014 - .quad 158048 - .quad 158081 - .quad 158091 - .quad 158124 - .quad 158163 - .quad 158191 - .quad 158244 - .quad 158299 - .quad 158355 - .quad 158399 - .quad 158438 - .quad 158531 - .quad 158574 - .quad 158600 - .quad 158656 - .quad 158687 - .quad 158771 - .quad 158817 - .quad 158882 - .quad 158933 - .quad 158987 - .quad 159022 - .quad 159065 - .quad 159116 - .quad 159193 - .quad 159270 - .quad 159347 - .quad 159424 - .quad 159482 - .quad 159540 - .quad 159604 - .quad 159666 - .quad 159732 - .quad 159798 - .quad 159826 - .quad 159853 - .quad 159889 - .quad 159912 - .quad 159948 - .quad 159979 - .quad 160016 - .quad 160044 - .quad 160109 - .quad 160175 - .quad 160215 - .quad 160256 - .quad 160295 - .quad 160335 - .quad 160374 - .quad 160411 - .quad 160449 - .quad 160488 - .quad 160517 - .quad 160546 - .quad 160575 - .quad 160604 - .quad 160632 - .quad 160660 - .quad 160688 - .quad 160716 - .quad 160744 - .quad 160794 - .quad 160811 - .quad 160846 - .quad 160895 - .quad 160921 - .quad 160953 - .quad 161007 - .quad 161039 - .quad 161093 - .quad 161128 - .quad 161177 - .quad 161226 - .quad 161275 - .quad 161324 - .quad 161373 - .quad 161422 - .quad 161456 - .quad 161504 - .quad 161552 - .quad 161585 - .quad 161619 - .quad 161650 - .quad 161683 - .quad 161715 - .quad 161749 - .quad 161778 - .quad 161814 - .quad 161843 - .quad 161890 - .quad 161935 - .quad 161978 - .quad 162038 - .quad 162069 - .quad 162102 - .quad 162159 - .quad 162196 - .quad 162275 - .quad 162303 - .quad 162334 - .quad 162366 - .quad 162405 - .quad 162443 - .quad 162498 - .quad 162553 - .quad 162608 - .quad 162663 - .quad 162719 - .quad 162775 - .quad 162831 - .quad 162887 - .quad 162941 + .quad 154305 + .quad 154336 + .quad 154391 + .quad 154430 + .quad 154481 + .quad 154509 + .quad 154555 + .quad 154594 + .quad 154633 + .quad 154688 + .quad 154727 + .quad 154784 + .quad 154821 + .quad 154843 + .quad 154872 + .quad 154933 + .quad 154963 + .quad 154993 + .quad 155026 + .quad 155057 + .quad 155075 + .quad 155131 + .quad 155187 + .quad 155243 + .quad 155267 + .quad 155280 + .quad 155295 + .quad 155310 + .quad 155330 + .quad 155572 + .quad 155814 + .quad 155886 + .quad 155959 + .quad 156041 + .quad 156106 + .quad 156386 + .quad 156680 + .quad 156722 + .quad 156764 + .quad 156831 + .quad 156850 + .quad 156867 + .quad 156884 + .quad 156909 + .quad 156973 + .quad 157039 + .quad 157069 + .quad 157102 + .quad 157154 + .quad 157208 + .quad 157265 + .quad 157319 + .quad 157376 + .quad 157443 + .quad 157500 + .quad 157560 + .quad 157618 + .quad 157673 + .quad 157775 + .quad 157827 + .quad 157885 + .quad 157987 + .quad 158098 + .quad 158210 + .quad 158315 + .quad 158412 + .quad 158513 + .quad 158623 + .quad 158723 + .quad 158825 + .quad 158926 + .quad 159030 + .quad 159110 + .quad 159182 + .quad 159252 + .quad 159282 + .quad 159377 + .quad 159444 + .quad 159472 + .quad 159500 + .quad 159528 + .quad 159558 + .quad 159588 + .quad 159618 + .quad 159651 + .quad 159704 + .quad 159734 + .quad 159766 + .quad 159835 + .quad 159884 + .quad 159914 + .quad 159967 + .quad 160020 + .quad 160050 + .quad 160080 + .quad 160145 + .quad 160209 + .quad 160276 + .quad 160337 + .quad 160409 + .quad 160439 + .quad 160469 + .quad 160524 + .quad 160554 + .quad 160585 + .quad 160625 + .quad 160714 + .quad 160781 + .quad 160859 + .quad 160924 + .quad 160975 + .quad 161031 + .quad 161087 + .quad 161141 + .quad 161195 + .quad 161218 + .quad 161243 + .quad 161281 + .quad 161318 + .quad 161363 + .quad 161400 + .quad 161482 + .quad 161569 + .quad 161605 + .quad 161658 + .quad 161703 + .quad 161744 + .quad 161774 + .quad 161804 + .quad 161834 + .quad 161864 + .quad 161894 + .quad 161924 + .quad 161954 + .quad 162007 + .quad 162060 + .quad 162113 + .quad 162141 + .quad 162201 + .quad 162243 + .quad 162293 + .quad 162329 + .quad 162386 + .quad 162444 + .quad 162499 + .quad 162559 + .quad 162627 + .quad 162657 + .quad 162687 + .quad 162739 + .quad 162792 + .quad 162845 + .quad 162874 + .quad 162904 + .quad 162934 .quad 162995 - .quad 163051 - .quad 163107 - .quad 163163 - .quad 163219 - .quad 163273 - .quad 163327 - .quad 163383 - .quad 163439 - .quad 163495 - .quad 163551 - .quad 163609 - .quad 163667 - .quad 163723 - .quad 163779 - .quad 163837 - .quad 163895 - .quad 163947 - .quad 164000 - .quad 164029 - .quad 164088 - .quad 164148 - .quad 164208 - .quad 164268 - .quad 164328 - .quad 164390 - .quad 164450 - .quad 164512 - .quad 164556 - .quad 164586 - .quad 164616 - .quad 164646 - .quad 164676 - .quad 164708 - .quad 164740 - .quad 164772 - .quad 164805 - .quad 164860 - .quad 164913 - .quad 164944 - .quad 164976 - .quad 165007 - .quad 165038 - .quad 165045 - .quad 165054 - .quad 165112 - .quad 165119 - .quad 165127 - .quad 165134 - .quad 165140 - .quad 165148 - .quad 165159 - .quad 165174 - .quad 165187 - .quad 165199 - .quad 165231 - .quad 165237 - .quad 165243 - .quad 165249 - .quad 165280 - .quad 165312 - .quad 165333 - .quad 165397 - .quad 165451 - .quad 165459 - .quad 165503 - .quad 165509 - .quad 165515 - .quad 165559 - .quad 165603 - .quad 165647 - .quad 165691 - .quad 165729 - .quad 165767 - .quad 165805 - .quad 165851 - .quad 165897 - .quad 165934 - .quad 165977 - .quad 166016 - .quad 166063 - .quad 166115 - .quad 166157 - .quad 166198 - .quad 166238 - .quad 166278 - .quad 166318 - .quad 166363 - .quad 166408 - .quad 166453 - .quad 166496 - .quad 166539 - .quad 166582 - .quad 166625 - .quad 166674 - .quad 166714 - .quad 166758 - .quad 166802 - .quad 166845 - .quad 166883 - .quad 166921 - .quad 166959 - .quad 166997 - .quad 167035 - .quad 167073 - .quad 167119 - .quad 167156 - .quad 167202 - .quad 167248 - .quad 167287 - .quad 167335 + .quad 163028 + .quad 163066 + .quad 163106 + .quad 163150 + .quad 163201 + .quad 163248 + .quad 163308 + .quad 163370 + .quad 163428 + .quad 163488 + .quad 163585 + .quad 163628 + .quad 163677 + .quad 163728 + .quad 163780 + .quad 163834 + .quad 163879 + .quad 163911 + .quad 163938 + .quad 163965 + .quad 163993 + .quad 164021 + .quad 164051 + .quad 164102 + .quad 164167 + .quad 164217 + .quad 164245 + .quad 164274 + .quad 164305 + .quad 164340 + .quad 164371 + .quad 164402 + .quad 164435 + .quad 164465 + .quad 164496 + .quad 164529 + .quad 164561 + .quad 164590 + .quad 164620 + .quad 164651 + .quad 164685 + .quad 164719 + .quad 164753 + .quad 164788 + .quad 164817 + .quad 164849 + .quad 164879 + .quad 164908 + .quad 164961 + .quad 165014 + .quad 165069 + .quad 165099 + .quad 165129 + .quad 165194 + .quad 165229 + .quad 165285 + .quad 165340 + .quad 165393 + .quad 165423 + .quad 165453 + .quad 165483 + .quad 165513 + .quad 165545 + .quad 165571 + .quad 165599 + .quad 165627 + .quad 165687 + .quad 165741 + .quad 165793 + .quad 165824 + .quad 165857 + .quad 165910 + .quad 165963 + .quad 165989 + .quad 166017 + .quad 166048 + .quad 166081 + .quad 166114 + .quad 166147 + .quad 166190 + .quad 166296 + .quad 166338 + .quad 166399 + .quad 166449 + .quad 166479 + .quad 166532 + .quad 166585 + .quad 166638 + .quad 166668 + .quad 166698 + .quad 166728 + .quad 166778 + .quad 166826 + .quad 166874 + .quad 166924 + .quad 166970 + .quad 167023 + .quad 167077 + .quad 167130 + .quad 167179 + .quad 167234 + .quad 167283 + .quad 167333 .quad 167382 - .quad 167429 - .quad 167476 - .quad 167520 - .quad 167562 - .quad 167603 + .quad 167431 + .quad 167485 + .quad 167532 + .quad 167585 + .quad 167615 .quad 167644 - .quad 167689 - .quad 167732 - .quad 167775 - .quad 167818 - .quad 167861 - .quad 167904 - .quad 167947 - .quad 167990 - .quad 168034 - .quad 168078 - .quad 168117 - .quad 168155 - .quad 168201 - .quad 168247 - .quad 168290 - .quad 168338 - .quad 168383 - .quad 168426 - .quad 168466 - .quad 168506 - .quad 168546 - .quad 168590 - .quad 168634 - .quad 168678 - .quad 168722 - .quad 168765 - .quad 168806 - .quad 168844 - .quad 168882 - .quad 168920 - .quad 168961 - .quad 169007 - .quad 169045 - .quad 169082 - .quad 169128 - .quad 169174 - .quad 169220 - .quad 169263 - .quad 169310 - .quad 169357 - .quad 169399 - .quad 169440 - .quad 169481 - .quad 169522 - .quad 169562 + .quad 167716 + .quad 167803 + .quad 167857 + .quad 167908 + .quad 167938 + .quad 167968 + .quad 167998 + .quad 168053 + .quad 168083 + .quad 168114 + .quad 168147 + .quad 168180 + .quad 168263 + .quad 168311 + .quad 168362 + .quad 168414 + .quad 168469 + .quad 168501 + .quad 168529 + .quad 168575 + .quad 168650 + .quad 168711 + .quad 168777 + .quad 168841 + .quad 168871 + .quad 168960 + .quad 168998 + .quad 169041 + .quad 169088 + .quad 169131 + .quad 169179 + .quad 169224 + .quad 169281 + .quad 169396 + .quad 169444 + .quad 169496 + .quad 169547 .quad 169602 - .quad 169648 - .quad 169691 - .quad 169734 - .quad 169777 - .quad 169820 - .quad 169863 - .quad 169906 - .quad 169949 - .quad 169992 - .quad 170035 - .quad 170078 - .quad 170121 - .quad 170164 - .quad 170207 - .quad 170247 + .quad 169661 + .quad 169722 + .quad 169782 + .quad 169843 + .quad 169907 + .quad 169974 + .quad 170023 + .quad 170074 + .quad 170104 + .quad 170134 + .quad 170166 + .quad 170198 + .quad 170227 + .quad 170255 .quad 170287 - .quad 170327 - .quad 170367 - .quad 170411 - .quad 170455 - .quad 170499 - .quad 170536 - .quad 170573 - .quad 170619 - .quad 170661 - .quad 170703 - .quad 170744 - .quad 170789 - .quad 170834 - .quad 170878 - .quad 170921 - .quad 170965 - .quad 171008 - .quad 171040 - .quad 171046 - .quad 171080 - .quad 171111 - .quad 171160 - .quad 171209 - .quad 171258 - .quad 171307 - .quad 171356 - .quad 171399 - .quad 171442 - .quad 171485 - .quad 171536 - .quad 171587 - .quad 171629 - .quad 171677 - .quad 171721 - .quad 171773 - .quad 171830 - .quad 171877 - .quad 171923 - .quad 171968 - .quad 172013 - .quad 172058 - .quad 172108 - .quad 172158 - .quad 172208 - .quad 172256 - .quad 172304 - .quad 172352 - .quad 172400 - .quad 172454 - .quad 172479 - .quad 172514 - .quad 172559 - .quad 172608 - .quad 172657 - .quad 172705 - .quad 172748 - .quad 172791 - .quad 172834 - .quad 172877 - .quad 172920 - .quad 172963 - .quad 173014 - .quad 173056 - .quad 173107 - .quad 173158 - .quad 173202 - .quad 173255 - .quad 173307 - .quad 173359 - .quad 173411 - .quad 173460 - .quad 173507 - .quad 173553 - .quad 173599 - .quad 173649 - .quad 173697 - .quad 173745 - .quad 173793 - .quad 173841 - .quad 173889 - .quad 173937 - .quad 173964 - .quad 174012 - .quad 174061 - .quad 174110 - .quad 174154 - .quad 174197 - .quad 174248 - .quad 174299 - .quad 174347 - .quad 174400 - .quad 174450 - .quad 174498 - .quad 174523 - .quad 174549 - .quad 174576 - .quad 174602 - .quad 174641 - .quad 174686 - .quad 174731 - .quad 174776 - .quad 174825 - .quad 174874 - .quad 174923 - .quad 174972 - .quad 175020 - .quad 175066 - .quad 175109 - .quad 175152 + .quad 170330 + .quad 170361 + .quad 170403 + .quad 170445 + .quad 170496 + .quad 170555 + .quad 170582 + .quad 170615 + .quad 170671 + .quad 170688 + .quad 170698 + .quad 170753 + .quad 170804 + .quad 170857 + .quad 170888 + .quad 170902 + .quad 170929 + .quad 170961 + .quad 171001 + .quad 171044 + .quad 171098 + .quad 171154 + .quad 171193 + .quad 171233 + .quad 171262 + .quad 171286 + .quad 171317 + .quad 171348 + .quad 171369 + .quad 171398 + .quad 171429 + .quad 171455 + .quad 171474 + .quad 171489 + .quad 171504 + .quad 171524 + .quad 171544 + .quad 171568 + .quad 171609 + .quad 171642 + .quad 171680 + .quad 171719 + .quad 171749 + .quad 171779 + .quad 171810 + .quad 171834 + .quad 171861 + .quad 171888 + .quad 171915 + .quad 171943 + .quad 171975 + .quad 172021 + .quad 172069 + .quad 172095 + .quad 172161 + .quad 172226 + .quad 172260 + .quad 172290 + .quad 172320 + .quad 172351 + .quad 172408 + .quad 172439 + .quad 172480 + .quad 172519 + .quad 172558 + .quad 172599 + .quad 172638 + .quad 172666 + .quad 172694 + .quad 172737 + .quad 172785 + .quad 172845 + .quad 172891 + .quad 172919 + .quad 172953 + .quad 172986 + .quad 172996 + .quad 173029 + .quad 173068 + .quad 173096 + .quad 173149 + .quad 173204 + .quad 173260 + .quad 173304 + .quad 173334 + .quad 173365 + .quad 173406 + .quad 173446 + .quad 173484 + .quad 173518 + .quad 173554 + .quad 173570 + .quad 173594 + .quad 173641 + .quad 173680 + .quad 173773 + .quad 173816 + .quad 173842 + .quad 173898 + .quad 173929 + .quad 174013 + .quad 174059 + .quad 174124 + .quad 174175 + .quad 174229 + .quad 174264 + .quad 174307 + .quad 174358 + .quad 174435 + .quad 174512 + .quad 174589 + .quad 174666 + .quad 174724 + .quad 174782 + .quad 174846 + .quad 174908 + .quad 174974 + .quad 175040 + .quad 175068 + .quad 175132 + .quad 175159 .quad 175195 - .quad 175241 - .quad 175292 - .quad 175335 - .quad 175377 - .quad 175428 - .quad 175479 - .quad 175530 - .quad 175578 - .quad 175630 - .quad 175682 - .quad 175729 - .quad 175775 - .quad 175821 - .quad 175867 - .quad 175912 - .quad 175957 - .quad 176008 - .quad 176056 - .quad 176104 + .quad 175218 + .quad 175254 + .quad 175285 + .quad 175322 + .quad 175350 + .quad 175415 + .quad 175481 + .quad 175521 + .quad 175562 + .quad 175601 + .quad 175641 + .quad 175680 + .quad 175717 + .quad 175755 + .quad 175794 + .quad 175823 + .quad 175852 + .quad 175881 + .quad 175910 + .quad 175938 + .quad 175966 + .quad 175994 + .quad 176022 + .quad 176050 + .quad 176100 + .quad 176117 .quad 176152 - .quad 176200 - .quad 176248 - .quad 176296 - .quad 176344 - .quad 176392 - .quad 176440 - .quad 176488 - .quad 176536 - .quad 176584 - .quad 176632 - .quad 176677 - .quad 176722 - .quad 176767 - .quad 176812 - .quad 176861 - .quad 176910 - .quad 176959 - .quad 177001 - .quad 177043 - .quad 177094 - .quad 177141 - .quad 177188 - .quad 177234 - .quad 177284 - .quad 177334 - .quad 177383 - .quad 177431 - .quad 177480 - .quad 177528 - .quad 177543 - .quad 177587 - .quad 177628 - .quad 177667 - .quad 177706 - .quad 177726 - .quad 177751 - .quad 177767 - .quad 177781 - .quad 177795 - .quad 177814 - .quad 177820 - .quad 177845 - .quad 177850 - .quad 177883 - .quad 177919 - .quad 177947 + .quad 176201 + .quad 176227 + .quad 176259 + .quad 176313 + .quad 176345 + .quad 176399 + .quad 176434 + .quad 176483 + .quad 176532 + .quad 176581 + .quad 176630 + .quad 176679 + .quad 176713 + .quad 176761 + .quad 176809 + .quad 176842 + .quad 176876 + .quad 176907 + .quad 176940 + .quad 176972 + .quad 177006 + .quad 177035 + .quad 177071 + .quad 177100 + .quad 177147 + .quad 177192 + .quad 177235 + .quad 177295 + .quad 177326 + .quad 177359 + .quad 177416 + .quad 177453 + .quad 177532 + .quad 177560 + .quad 177591 + .quad 177623 + .quad 177662 + .quad 177700 + .quad 177755 + .quad 177810 + .quad 177865 + .quad 177920 .quad 177976 - .quad 178005 - .quad 178025 - .quad 178056 - .quad 178090 - .quad 178114 - .quad 178146 - .quad 178178 - .quad 178205 - .quad 178226 - .quad 178258 - .quad 178297 - .quad 178342 - .quad 178384 - .quad 178416 - .quad 178441 - .quad 178464 + .quad 178032 + .quad 178088 + .quad 178144 + .quad 178200 + .quad 178256 + .quad 178312 + .quad 178368 + .quad 178422 .quad 178476 - .quad 178492 - .quad 178503 - .quad 178543 - .quad 178576 - .quad 178601 - .quad 178635 - .quad 178659 - .quad 178733 - .quad 178744 - .quad 178770 - .quad 178775 + .quad 178532 + .quad 178588 + .quad 178644 + .quad 178700 + .quad 178758 + .quad 178816 + .quad 178872 + .quad 178928 + .quad 178986 + .quad 179044 + .quad 179096 + .quad 179149 + .quad 179178 + .quad 179237 + .quad 179297 + .quad 179357 + .quad 179417 + .quad 179477 + .quad 179539 + .quad 179599 + .quad 179661 + .quad 179705 + .quad 179735 + .quad 179765 + .quad 179795 + .quad 179825 + .quad 179857 + .quad 179889 + .quad 179921 + .quad 179954 + .quad 180009 + .quad 180062 + .quad 180093 + .quad 180125 + .quad 180156 + .quad 180187 + .quad 180194 + .quad 180203 + .quad 180261 + .quad 180268 + .quad 180276 + .quad 180283 + .quad 180289 + .quad 180297 + .quad 180328 + .quad 180359 + .quad 180391 + .quad 180397 + .quad 180403 + .quad 180409 + .quad 180430 + .quad 180494 + .quad 180548 + .quad 180556 + .quad 180595 + .quad 180601 + .quad 180607 + .quad 180646 + .quad 180685 + .quad 180724 + .quad 180763 + .quad 180802 + .quad 180841 + .quad 180885 + .quad 180929 + .quad 180973 + .quad 181017 + .quad 181061 + .quad 181105 + .quad 181149 + .quad 181193 + .quad 181237 + .quad 181281 + .quad 181325 + .quad 181368 + .quad 181410 + .quad 181451 + .quad 181492 + .quad 181533 + .quad 181574 + .quad 181615 + .quad 181653 + .quad 181691 + .quad 181729 + .quad 181767 + .quad 181805 + .quad 181847 + .quad 181889 + .quad 181931 + .quad 181968 + .quad 182005 + .quad 182051 + .quad 182097 + .quad 182143 + .quad 182189 + .quad 182235 + .quad 182281 + .quad 182324 + .quad 182363 + .quad 182407 + .quad 182449 + .quad 182491 + .quad 182532 + .quad 182573 + .quad 182614 + .quad 182654 + .quad 182694 + .quad 182734 + .quad 182780 + .quad 182825 + .quad 182870 + .quad 182915 + .quad 182960 + .quad 183005 + .quad 183050 + .quad 183095 + .quad 183138 + .quad 183181 + .quad 183224 + .quad 183268 + .quad 183311 + .quad 183354 + .quad 183397 + .quad 183440 + .quad 183483 + .quad 183526 + .quad 183569 + .quad 183612 + .quad 183655 + .quad 183698 + .quad 183741 + .quad 183784 + .quad 183827 + .quad 183870 + .quad 183908 + .quad 183947 + .quad 183990 + .quad 184034 + .quad 184078 + .quad 184119 + .quad 184160 + .quad 184201 + .quad 184239 + .quad 184277 + .quad 184315 + .quad 184353 + .quad 184391 + .quad 184428 + .quad 184470 + .quad 184516 + .quad 184559 + .quad 184598 + .quad 184637 + .quad 184679 + .quad 184721 + .quad 184762 + .quad 184803 + .quad 184847 + .quad 184890 + .quad 184933 + .quad 184976 + .quad 185019 + .quad 185062 + .quad 185105 + .quad 185148 + .quad 185192 + .quad 185236 + .quad 185280 + .quad 185323 + .quad 185364 + .quad 185405 + .quad 185443 + .quad 185481 + .quad 185519 + .quad 185561 + .quad 185598 + .quad 185635 + .quad 185672 + .quad 185715 + .quad 185757 + .quad 185798 + .quad 185839 + .quad 185879 + .quad 185919 + .quad 185962 + .quad 186005 + .quad 186037 + .quad 186043 + .quad 186069 + .quad 186113 + .quad 186157 + .quad 186201 + .quad 186245 + .quad 186289 + .quad 186333 + .quad 186377 + .quad 186426 + .quad 186475 + .quad 186524 + .quad 186573 + .quad 186622 + .quad 186671 + .quad 186720 + .quad 186769 + .quad 186818 + .quad 186867 + .quad 186916 + .quad 186964 + .quad 187011 + .quad 187057 + .quad 187103 + .quad 187149 + .quad 187195 + .quad 187241 + .quad 187284 + .quad 187327 + .quad 187370 + .quad 187413 + .quad 187456 + .quad 187503 + .quad 187550 + .quad 187597 + .quad 187639 + .quad 187681 + .quad 187732 + .quad 187783 + .quad 187834 + .quad 187885 + .quad 187936 + .quad 187987 + .quad 188035 + .quad 188079 + .quad 188128 + .quad 188175 + .quad 188222 + .quad 188268 + .quad 188314 + .quad 188360 + .quad 188405 + .quad 188450 + .quad 188495 + .quad 188546 + .quad 188596 + .quad 188646 + .quad 188696 + .quad 188746 + .quad 188796 + .quad 188846 + .quad 188896 + .quad 188944 + .quad 188992 + .quad 189040 + .quad 189089 + .quad 189137 + .quad 189185 + .quad 189233 + .quad 189281 + .quad 189329 + .quad 189377 + .quad 189425 + .quad 189473 + .quad 189521 + .quad 189569 + .quad 189617 + .quad 189665 + .quad 189713 + .quad 189761 + .quad 189804 + .quad 189843 + .quad 189887 + .quad 189935 + .quad 189984 + .quad 190033 + .quad 190079 + .quad 190125 + .quad 190171 + .quad 190214 + .quad 190257 + .quad 190300 + .quad 190343 + .quad 190386 + .quad 190428 + .quad 190475 + .quad 190526 + .quad 190574 + .quad 190618 + .quad 190662 + .quad 190709 + .quad 190756 + .quad 190802 + .quad 190848 + .quad 190897 + .quad 190945 + .quad 190993 + .quad 191041 + .quad 191089 + .quad 191137 + .quad 191185 + .quad 191233 + .quad 191258 + .quad 191284 + .quad 191311 + .quad 191360 + .quad 191409 + .quad 191458 + .quad 191506 + .quad 191552 + .quad 191598 + .quad 191641 + .quad 191684 + .quad 191727 + .quad 191774 + .quad 191816 + .quad 191858 + .quad 191900 + .quad 191948 + .quad 191995 + .quad 192041 + .quad 192087 + .quad 192132 + .quad 192177 + .quad 192225 + .quad 192273 + .quad 192291 + .quad 192319 + .quad 192327 + .quad 192363 + .quad 192402 + .quad 192441 + .quad 192461 + .quad 192486 + .quad 192518 + .quad 192541 + .quad 192561 + .quad 192577 + .quad 192591 + .quad 192605 + .quad 192641 + .quad 192647 + .quad 192680 + .quad 192685 + .quad 192705 + .quad 192734 + .quad 192765 + .quad 192791 + .quad 192811 + .quad 192830 + .quad 192857 + .quad 192882 + .quad 192911 + .quad 192949 + .quad 192984 + .quad 193009 + .quad 193025 + .quad 193049 + .quad 193070 + .quad 193095 + .quad 193118 + .quad 193146 + .quad 193163 + .quad 193189 + .quad 193215 + .quad 193238 + .quad 193250 + .quad 193266 + .quad 193290 + .quad 193330 + .quad 193363 + .quad 193437 + .quad 193448 + .quad 193474 + .quad 193479 .globl symbol_name symbol_name: .asciz "skernel" @@ -6658,320 +7204,182 @@ symbol_name: .asciz "strampoline" .asciz "user_v" .asciz "user_r" - .asciz "kernel::task::cpu::__syscall_260::_::__ctor" + .asciz "kernel::time::__syscall_115::_::__ctor" .asciz "etrampoline" + .asciz "kernel::time::__syscall_114::_::__ctor" + .asciz "kernel::time::__syscall_103::_::__ctor" + .asciz "kernel::time::__syscall_102::_::__ctor" + .asciz "kernel::time::__syscall_113::_::__ctor" + .asciz "kernel::time::__syscall_101::_::__ctor" + .asciz "kernel::time::__syscall_153::_::__ctor" + .asciz "kernel::task::cpu::__syscall_261::_::__ctor" + .asciz "kernel::task::cpu::__syscall_214::_::__ctor" + .asciz "kernel::task::cpu::__syscall_260::_::__ctor" + .asciz "kernel::task::cpu::__syscall_221::_::__ctor" .asciz "kernel::task::cpu::__syscall_177::_::__ctor" + .asciz "kernel::task::cpu::__syscall_176::_::__ctor" + .asciz "kernel::task::cpu::__syscall_175::_::__ctor" .asciz "kernel::task::cpu::__syscall_174::_::__ctor" + .asciz "kernel::task::cpu::__syscall_157::_::__ctor" .asciz "kernel::task::cpu::__syscall_155::_::__ctor" - .asciz "kernel::task::cpu::__syscall_124::_::__ctor" - .asciz "kernel::net::__syscall_210::_::__ctor" - .asciz "kernel::net::__syscall_203::_::__ctor" - .asciz "kernel::net::__syscall_201::_::__ctor" - .asciz "kernel::memory::map::__syscall_233::_::__ctor" - .asciz "kernel::memory::map::__syscall_215::_::__ctor" - .asciz "kernel::ipc::__syscall_99::_::__ctor" - .asciz "kernel::ipc::shm::__syscall_196::_::__ctor" - .asciz "kernel::gui::__syscall_2000::_::__ctor" - .asciz "kernel::fs::sys::cpu::__syscall_121::_::__ctor" - .asciz "kernel::fs::proc::process::__syscall_165::_::__ctor" - .asciz "kernel::fs::link::__syscall_78::_::__ctor" - .asciz "kernel::fs::ext::__syscall_10::_::__ctor" - .asciz "kernel::fs::ext::__syscall_9::_::__ctor" - .asciz "kernel::fs::ext::__syscall_8::_::__ctor" - .asciz "kernel::fs::ext::__syscall_6::_::__ctor" - .asciz "kernel::fs::control::__syscall_53::_::__ctor" - .asciz "kernel::fs::control::__syscall_29::_::__ctor" - .asciz "kernel::fs::control::__syscall_25::_::__ctor" - .asciz "kernel::fs::basic::__syscall_38::_::__ctor" - .asciz "kernel::fs::basic::__syscall_44::_::__ctor" - .asciz "kernel::fs::basic::__syscall_67::_::__ctor" - .asciz "kernel::fs::basic::__syscall_45::_::__ctor" - .asciz "kernel::device::input::__syscall_2002::_::__ctor" - .asciz "kernel::timer::__syscall_103::_::__ctor" - .asciz "kernel::task::cpu::__syscall_221::_::__ctor" - .asciz "kernel::task::cpu::__syscall_220::_::__ctor" - .asciz "kernel::task::cpu::__syscall_94::_::__ctor" - .asciz "kernel::net::__syscall_209::_::__ctor" + .asciz "kernel::task::cpu::__syscall_154::_::__ctor" + .asciz "kernel::task::cpu::__syscall_93::_::__ctor" + .asciz "kernel::system::__syscall_2003::_::__ctor" + .asciz "kernel::system::__syscall_165::_::__ctor" + .asciz "kernel::system::__syscall_119::_::__ctor" + .asciz "kernel::system::__syscall_123::_::__ctor" + .asciz "kernel::system::__syscall_122::_::__ctor" + .asciz "kernel::system::__syscall_118::_::__ctor" + .asciz "kernel::net::__syscall_199::_::__ctor" .asciz "kernel::net::__syscall_207::_::__ctor" .asciz "kernel::net::__syscall_206::_::__ctor" .asciz "kernel::net::__syscall_204::_::__ctor" .asciz "kernel::net::__syscall_200::_::__ctor" - .asciz "kernel::net::__syscall_198::_::__ctor" - .asciz "kernel::memory::map::__syscall_222::_::__ctor" - .asciz "kernel::ipc::__syscall_59::_::__ctor" + .asciz "kernel::mm::map::__syscall_233::_::__ctor" + .asciz "kernel::mm::map::__syscall_227::_::__ctor" + .asciz "kernel::mm::map::__syscall_215::_::__ctor" + .asciz "kernel::ipc::__syscall_98::_::__ctor" + .asciz "kernel::ipc::__syscall_23::_::__ctor" + .asciz "kernel::ipc::signal::__syscall_139::_::__ctor" .asciz "kernel::ipc::signal::__syscall_130::_::__ctor" - .asciz "kernel::ipc::signal::__syscall_137::_::__ctor" - .asciz "kernel::gui::__syscall_2001::_::__ctor" - .asciz "kernel::fs::sys::info::__syscall_179::_::__ctor" - .asciz "kernel::fs::sys::cpu::__syscall_120::_::__ctor" - .asciz "kernel::fs::sys::cpu::__syscall_123::_::__ctor" - .asciz "kernel::fs::sys::cpu::__syscall_118::_::__ctor" - .asciz "kernel::fs::select::__syscall_72::_::__ctor" - .asciz "kernel::fs::link::__syscall_35::_::__ctor" - .asciz "kernel::fs::ext::__syscall_15::_::__ctor" - .asciz "kernel::fs::ext::__syscall_13::_::__ctor" - .asciz "kernel::fs::control::__syscall_52::_::__ctor" - .asciz "kernel::fs::basic::__syscall_43::_::__ctor" - .asciz "kernel::fs::basic::__syscall_80::_::__ctor" - .asciz "kernel::fs::basic::__syscall_65::_::__ctor" - .asciz "kernel::fs::basic::__syscall_34::_::__ctor" - .asciz "kernel::fs::basic::__syscall_49::_::__ctor" - .asciz "kernel::fs::basic::__syscall_40::_::__ctor" - .asciz "kernel::task::cpu::__syscall_96::_::__ctor" - .asciz "kernel::task::cpu::__syscall_214::_::__ctor" - .asciz "kernel::task::cpu::__syscall_176::_::__ctor" - .asciz "kernel::sbi::__syscall_2003::_::__ctor" - .asciz "kernel::net::__syscall_208::_::__ctor" - .asciz "kernel::memory::map::__syscall_226::_::__ctor" .asciz "kernel::ipc::signal::__syscall_129::_::__ctor" - .asciz "kernel::ipc::shm::__syscall_194::_::__ctor" - .asciz "kernel::fs::sys::info::__syscall_116::_::__ctor" - .asciz "kernel::fs::control::__syscall_88::_::__ctor" - .asciz "kernel::fs::basic::__syscall_82::_::__ctor" - .asciz "kernel::timer::__syscall_114::_::__ctor" - .asciz "kernel::timer::__syscall_113::_::__ctor" - .asciz "kernel::timer::__syscall_169::_::__ctor" - .asciz "kernel::task::cpu::__syscall_175::_::__ctor" - .asciz "kernel::task::cpu::__syscall_173::_::__ctor" - .asciz "kernel::task::cpu::__syscall_172::_::__ctor" - .asciz "kernel::task::cpu::__syscall_157::_::__ctor" - .asciz "kernel::task::cpu::__syscall_93::_::__ctor" - .asciz "kernel::system::__syscall_160::_::__ctor" - .asciz "kernel::net::__syscall_199::_::__ctor" - .asciz "kernel::net::__syscall_205::_::__ctor" - .asciz "kernel::net::__syscall_202::_::__ctor" - .asciz "kernel::memory::__syscall_283::_::__ctor" - .asciz "kernel::memory::map::__syscall_227::_::__ctor" - .asciz "kernel::ipc::__syscall_100::_::__ctor" - .asciz "kernel::ipc::__syscall_24::_::__ctor" - .asciz "kernel::ipc::signal::__syscall_133::_::__ctor" - .asciz "kernel::ipc::signal::__syscall_139::_::__ctor" .asciz "kernel::ipc::signal::__syscall_135::_::__ctor" + .asciz "kernel::ipc::signal::__syscall_137::_::__ctor" + .asciz "kernel::ipc::signal::__syscall_134::_::__ctor" .asciz "kernel::ipc::shm::__syscall_195::_::__ctor" - .asciz "kernel::fs::sys::cpu::__syscall_119::_::__ctor" - .asciz "kernel::fs::sys::cpu::__syscall_122::_::__ctor" - .asciz "kernel::fs::link::__syscall_36::_::__ctor" + .asciz "kernel::gui::__syscall_2000::_::__ctor" + .asciz "kernel::fs::select::__syscall_72::_::__ctor" + .asciz "kernel::fs::poll::__syscall_73::_::__ctor" + .asciz "kernel::fs::link::__syscall_37::_::__ctor" .asciz "kernel::fs::ext::__syscall_16::_::__ctor" - .asciz "kernel::fs::ext::__syscall_14::_::__ctor" .asciz "kernel::fs::ext::__syscall_12::_::__ctor" + .asciz "kernel::fs::ext::__syscall_11::_::__ctor" + .asciz "kernel::fs::ext::__syscall_9::_::__ctor" .asciz "kernel::fs::ext::__syscall_7::_::__ctor" - .asciz "kernel::fs::ext::__syscall_5::_::__ctor" + .asciz "kernel::fs::ext::__syscall_6::_::__ctor" .asciz "kernel::fs::control::__syscall_166::_::__ctor" + .asciz "kernel::fs::control::__syscall_55::_::__ctor" + .asciz "kernel::fs::control::__syscall_53::_::__ctor" + .asciz "kernel::fs::control::__syscall_52::_::__ctor" + .asciz "kernel::fs::control::__syscall_48::_::__ctor" + .asciz "kernel::fs::control::__syscall_88::_::__ctor" + .asciz "kernel::fs::control::__syscall_29::_::__ctor" + .asciz "kernel::fs::control::__syscall_25::_::__ctor" + .asciz "kernel::fs::basic::__syscall_82::_::__ctor" .asciz "kernel::fs::basic::__syscall_81::_::__ctor" + .asciz "kernel::fs::basic::__syscall_71::_::__ctor" + .asciz "kernel::fs::basic::__syscall_276::_::__ctor" + .asciz "kernel::fs::basic::__syscall_38::_::__ctor" + .asciz "kernel::fs::basic::__syscall_44::_::__ctor" .asciz "kernel::fs::basic::__syscall_79::_::__ctor" .asciz "kernel::fs::basic::__syscall_68::_::__ctor" - .asciz "kernel::fs::basic::__syscall_66::_::__ctor" - .asciz "kernel::fs::basic::__syscall_62::_::__ctor" + .asciz "kernel::fs::basic::__syscall_65::_::__ctor" + .asciz "kernel::fs::basic::__syscall_34::_::__ctor" .asciz "kernel::fs::basic::__syscall_50::_::__ctor" .asciz "kernel::fs::basic::__syscall_17::_::__ctor" .asciz "kernel::fs::basic::__syscall_64::_::__ctor" .asciz "kernel::fs::basic::__syscall_63::_::__ctor" + .asciz "kernel::fs::basic::__syscall_46::_::__ctor" .asciz "kernel::fs::basic::__syscall_61::_::__ctor" .asciz "kernel::fs::basic::__syscall_57::_::__ctor" - .asciz "kernel::fs::basic::__syscall_56::_::__ctor" - .asciz "kernel::fs::basic::__syscall_39::_::__ctor" - .asciz "kernel::timer::__syscall_115::_::__ctor" - .asciz "kernel::timer::__syscall_102::_::__ctor" - .asciz "kernel::timer::__syscall_101::_::__ctor" - .asciz "kernel::timer::__syscall_153::_::__ctor" - .asciz "kernel::task::cpu::__syscall_261::_::__ctor" + .asciz "kernel::fs::basic::__syscall_40::_::__ctor" + .asciz "kernel::ipc::__syscall_100::_::__ctor" + .asciz "kernel::time::__syscall_169::_::__ctor" + .asciz "kernel::task::cpu::__syscall_96::_::__ctor" .asciz "kernel::task::cpu::__syscall_178::_::__ctor" - .asciz "kernel::task::cpu::__syscall_154::_::__ctor" - .asciz "kernel::ipc::__syscall_98::_::__ctor" - .asciz "kernel::ipc::__syscall_23::_::__ctor" - .asciz "kernel::ipc::signal::__syscall_134::_::__ctor" - .asciz "kernel::fs::poll::__syscall_73::_::__ctor" - .asciz "kernel::fs::link::__syscall_37::_::__ctor" - .asciz "kernel::fs::ext::__syscall_11::_::__ctor" - .asciz "kernel::fs::control::__syscall_55::_::__ctor" - .asciz "kernel::fs::control::__syscall_48::_::__ctor" + .asciz "kernel::task::cpu::__syscall_172::_::__ctor" + .asciz "kernel::system::__syscall_121::_::__ctor" + .asciz "kernel::system::__syscall_179::_::__ctor" + .asciz "kernel::system::__syscall_160::_::__ctor" + .asciz "kernel::net::__syscall_209::_::__ctor" + .asciz "kernel::net::__syscall_208::_::__ctor" + .asciz "kernel::net::__syscall_203::_::__ctor" + .asciz "kernel::net::__syscall_201::_::__ctor" + .asciz "kernel::net::__syscall_198::_::__ctor" + .asciz "kernel::mm::__syscall_283::_::__ctor" + .asciz "kernel::mm::map::__syscall_226::_::__ctor" + .asciz "kernel::ipc::signal::__syscall_133::_::__ctor" + .asciz "kernel::ipc::shm::__syscall_194::_::__ctor" + .asciz "kernel::gui::__syscall_2002::_::__ctor" + .asciz "kernel::gui::__syscall_2001::_::__ctor" + .asciz "kernel::fs::link::__syscall_78::_::__ctor" + .asciz "kernel::fs::link::__syscall_36::_::__ctor" + .asciz "kernel::fs::ext::__syscall_15::_::__ctor" + .asciz "kernel::fs::ext::__syscall_14::_::__ctor" .asciz "kernel::fs::basic::__syscall_285::_::__ctor" - .asciz "kernel::fs::basic::__syscall_71::_::__ctor" - .asciz "kernel::fs::basic::__syscall_276::_::__ctor" - .asciz "kernel::fs::basic::__syscall_46::_::__ctor" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Display>::fmt" - .asciz "core::ptr::drop_in_place<&isize>" - .asciz "core::panicking::assert_failed" - .asciz "main" - .asciz "__rust_alloc_error_handler" - .asciz "kernel_v" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" + .asciz "kernel::fs::basic::__syscall_43::_::__ctor" + .asciz "kernel::fs::basic::__syscall_80::_::__ctor" + .asciz "kernel::fs::basic::__syscall_67::_::__ctor" + .asciz "kernel::fs::basic::__syscall_66::_::__ctor" + .asciz "kernel::fs::basic::__syscall_49::_::__ctor" + .asciz "kernel::fs::basic::__syscall_56::_::__ctor" + .asciz "kernel::fs::basic::__syscall_39::_::__ctor" + .asciz "kernel::task::cpu::__syscall_220::_::__ctor" + .asciz "kernel::task::cpu::__syscall_173::_::__ctor" + .asciz "kernel::task::cpu::__syscall_124::_::__ctor" + .asciz "kernel::task::cpu::__syscall_94::_::__ctor" + .asciz "kernel::system::__syscall_120::_::__ctor" + .asciz "kernel::system::__syscall_116::_::__ctor" + .asciz "kernel::net::__syscall_210::_::__ctor" + .asciz "kernel::net::__syscall_205::_::__ctor" + .asciz "kernel::net::__syscall_202::_::__ctor" + .asciz "kernel::mm::map::__syscall_222::_::__ctor" + .asciz "kernel::ipc::__syscall_99::_::__ctor" + .asciz "kernel::ipc::__syscall_24::_::__ctor" + .asciz "kernel::ipc::__syscall_59::_::__ctor" + .asciz "kernel::ipc::shm::__syscall_196::_::__ctor" + .asciz "kernel::fs::link::__syscall_35::_::__ctor" + .asciz "kernel::fs::ext::__syscall_13::_::__ctor" + .asciz "kernel::fs::ext::__syscall_10::_::__ctor" + .asciz "kernel::fs::ext::__syscall_8::_::__ctor" + .asciz "kernel::fs::ext::__syscall_5::_::__ctor" + .asciz "kernel::fs::basic::__syscall_62::_::__ctor" + .asciz "kernel::fs::basic::__syscall_45::_::__ctor" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" .asciz "::type_id" - .asciz "fdt::node::all_nodes::closure" - .asciz "::fmt" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_arc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "core::fmt::num::::fmt" - .asciz "core::ptr::drop_in_place>" - .asciz "core::ptr::drop_in_place>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place<&fatfs::error::Error<()>>" - .asciz "unifs::UniFs::kill_sb" - .asciz "unifs::UniFs::kill_sb" - .asciz "unifs::UniFsSuperBlock::root_dentry" - .asciz "unifs::UniFsSuperBlock::remove_inode" - .asciz " as vfscore::fstype::VfsFsType>::mount" - .asciz " as vfscore::fstype::VfsFsType>::fs_flag" - .asciz " as vfscore::fstype::VfsFsType>::fs_name" - .asciz " as vfscore::fstype::VfsFsType>::kill_sb" - .asciz " as vfscore::fstype::VfsFsType>::mount" - .asciz " as vfscore::fstype::VfsFsType>::fs_flag" - .asciz " as vfscore::fstype::VfsFsType>::fs_name" - .asciz " as vfscore::fstype::VfsFsType>::kill_sb" - .asciz "fat_vfs::fs::FatFsSuperBlock::root_dentry" - .asciz "fat_vfs::inode::dir::FatFsDirInode::delete_file" - .asciz "fat_vfs::inode::file::FatFsFileInode::new" - .asciz "vfscore::file::VfsFile::poll" - .asciz "vfscore::file::VfsFile::flush" - .asciz "vfscore::file::VfsFile::ioctl" - .asciz "vfscore::file::VfsFile::read_at" - .asciz "vfscore::file::VfsFile::readdir" - .asciz "vfscore::file::VfsFile::write_at" - .asciz " as vfscore::file::VfsFile>::poll" - .asciz " as vfscore::file::VfsFile>::flush" - .asciz " as vfscore::file::VfsFile>::fsync" - .asciz " as vfscore::file::VfsFile>::ioctl" - .asciz " as vfscore::file::VfsFile>::read_at" - .asciz " as vfscore::file::VfsFile>::write_at" - .asciz " as vfscore::inode::VfsInode>::update_time" - .asciz " as vfscore::inode::VfsInode>::get_super_block" - .asciz " as vfscore::inode::VfsInode>::link" - .asciz " as vfscore::inode::VfsInode>::get_attr" - .asciz " as vfscore::inode::VfsInode>::set_attr" - .asciz " as vfscore::inode::VfsInode>::node_perm" - .asciz " as vfscore::inode::VfsInode>::rename_to" - .asciz " as vfscore::file::VfsFile>::ioctl" - .asciz " as vfscore::file::VfsFile>::readdir" - .asciz " as vfscore::superblock::VfsSuperBlock>::root_inode" - .asciz " as vfscore::superblock::VfsSuperBlock>::fs_type" - .asciz " as vfscore::superblock::VfsSuperBlock>::stat_fs" - .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" - .asciz " as vfscore::inode::VfsInode>::inode_type" - .asciz " as vfscore::inode::VfsInode>::list_xattr" - .asciz " as vfscore::inode::VfsInode>::update_time" - .asciz " as vfscore::inode::VfsInode>::get_super_block" - .asciz " as vfscore::inode::VfsInode>::link" - .asciz " as vfscore::inode::VfsInode>::rmdir" - .asciz " as vfscore::inode::VfsInode>::create" - .asciz " as vfscore::inode::VfsInode>::lookup" - .asciz " as vfscore::inode::VfsInode>::unlink" - .asciz " as vfscore::inode::VfsInode>::symlink" - .asciz " as vfscore::inode::VfsInode>::get_attr" - .asciz " as vfscore::inode::VfsInode>::readlink" - .asciz " as vfscore::inode::VfsInode>::set_attr" - .asciz " as vfscore::inode::VfsInode>::truncate" - .asciz " as vfscore::inode::VfsInode>::node_perm" - .asciz " as vfscore::inode::VfsInode>::rename_to" - .asciz " as vfscore::file::VfsFile>::flush" - .asciz " as vfscore::file::VfsFile>::read_at" - .asciz " as vfscore::file::VfsFile>::write_at" - .asciz " as vfscore::file::VfsFile>::readdir" - .asciz " as vfscore::inode::VfsInode>::inode_type" - .asciz " as vfscore::inode::VfsInode>::get_super_block" - .asciz " as vfscore::inode::VfsInode>::rmdir" - .asciz " as vfscore::inode::VfsInode>::create" - .asciz " as vfscore::inode::VfsInode>::lookup" - .asciz " as vfscore::inode::VfsInode>::get_attr" - .asciz " as vfscore::inode::VfsInode>::readlink" - .asciz " as vfscore::inode::VfsInode>::truncate" - .asciz " as vfscore::inode::VfsInode>::rename_to" - .asciz " as vfscore::inode::VfsInode>::list_xattr" - .asciz " as vfscore::inode::VfsInode>::update_time" - .asciz " as vfscore::inode::VfsInode>::get_super_block" - .asciz " as vfscore::inode::VfsInode>::link" - .asciz " as vfscore::inode::VfsInode>::rmdir" - .asciz " as vfscore::inode::VfsInode>::create" - .asciz " as vfscore::inode::VfsInode>::lookup" - .asciz " as vfscore::inode::VfsInode>::unlink" - .asciz " as vfscore::inode::VfsInode>::unlink::closure" - .asciz " as vfscore::inode::VfsInode>::symlink" - .asciz " as vfscore::inode::VfsInode>::get_attr" - .asciz " as vfscore::inode::VfsInode>::set_attr" - .asciz " as vfscore::inode::VfsInode>::rename_to" - .asciz " as vfscore::superblock::VfsSuperBlock>::root_inode" - .asciz " as vfscore::superblock::VfsSuperBlock>::fs_type" - .asciz " as vfscore::superblock::VfsSuperBlock>::stat_fs" - .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" - .asciz " as vfscore::inode::VfsInode>::inode_type" - .asciz " as vfscore::inode::VfsInode>::truncate" - .asciz "kernel::board::common::get_device_info" - .asciz "kernel::fs::sys::init_sysfs" - .asciz "kernel::task::task::TaskInner::update_timer" - .asciz "trap_return" - .asciz "kernel::trap::init_trap_subsystem" - .asciz "kernel::trap::check_timer_interrupt_pending" - .asciz "user_trap_vector" - .asciz "kernel::trap::check_task_timer_expired" - .asciz "kernel_trap_vector" - .asciz "kernel::board::qemu::init_dtb" - .asciz "kernel::board::qemu::probe_devices_from_dtb" .asciz "::as_any_mut" .asciz "::into_any_rc" .asciz "::as_any" .asciz "::into_any" .asciz "core::fmt::num::::fmt" .asciz "core::ops::function::FnOnce::call_once" - .asciz "core::ptr::drop_in_place<&kernel_sync::ticket::TicketMutex>" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place<&str>" .asciz "core::ptr::drop_in_place" .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" .asciz "::drop" .asciz "kernel::task::task::Task::terminate" .asciz "kernel::task::task::Task::access_inner" @@ -6997,7 +7405,6 @@ symbol_name: .asciz "kernel::task::task::TaskInner::trap_frame" .asciz "kernel::task::task::TaskInner::load_trap_frame" .asciz "kernel::task::task::TaskInner::transfer_raw" - .asciz "kernel::task::task::TaskInner::transfer_str" .asciz "kernel::task::task::TaskInner::transfer_buffer" .asciz "kernel::task::task::TaskInner::transfer_raw_ptr_mut" .asciz "kernel::task::task::TaskInner::transfer_raw_ptr_mut" @@ -7018,439 +7425,10 @@ symbol_name: .asciz "kernel::task::task::Task::from_elf" .asciz "kernel::task::task::Task::t_clone" .asciz "kernel::task::task::Task::exec" + .asciz "kernel::task::::to_wait" + .asciz "kernel::task::::to_wakeup" + .asciz "kernel::task::::have_signal" .asciz "::fmt" - .asciz " as core::iter::traits::iterator::Iterator>::next" - .asciz "virtio_drivers::queue::VirtQueue::add_notify_wait_pop" - .asciz "virtio_drivers::queue::VirtQueue::add_notify_wait_pop" - .asciz "virtio_drivers::queue::VirtQueue::add" - .asciz "virtio_drivers::queue::VirtQueue::new" - .asciz "virtio_drivers::queue::VirtQueue::new" - .asciz "virtio_drivers::queue::VirtQueue::new" - .asciz "virtio_drivers::queue::VirtQueue::pop_used" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "::read_u16_le" - .asciz "::read_u16_le" - .asciz "::read_u32_le" - .asciz "::read_u32_le" - .asciz "::read_u8" - .asciz "core::ptr::drop_in_place>" - .asciz "core::ptr::drop_in_place>" - .asciz "core::ptr::drop_in_place" - .asciz "fatfs::io::Read::read_exact" - .asciz "fatfs::io::Read::read_exact" - .asciz "fatfs::io::Write::write_all" - .asciz "fatfs::io::Write::write_all" - .asciz "fatfs::dir::Dir::create_dir" - .asciz "fatfs::dir::Dir::find_entry" - .asciz "fatfs::dir::Dir::create_file" - .asciz "fatfs::dir::Dir::write_entry" - .asciz "fatfs::dir::Dir::rename_internal" - .asciz "fatfs::dir::Dir::create_sfn_entry" - .asciz "fatfs::dir::Dir::remove" - .asciz "fatfs::dir::Dir::rename" - .asciz "fatfs::dir::Dir::open_dir" - .asciz "fatfs::dir::Dir::open_file" - .asciz "fatfs::table::alloc_cluster" - .asciz "fatfs::table::find_free_cluster" - .asciz "fatfs::table::count_free_clusters" - .asciz "fatfs::table::ClusterIterator::truncate" - .asciz "fatfs::table::write_fat" - .asciz "fatfs::dir_entry::DirEntryData::deserialize" - .asciz "fatfs::dir_entry::DirEntryEditor::flush" - .asciz "fatfs::dir_entry::DirLfnEntryData::serialize" - .asciz "fatfs::dir_entry::DirFileEntryData::serialize" - .asciz "fatfs::dir_entry::DirEntry::file_name" - .asciz " as core::iter::traits::iterator::Iterator>::next" - .asciz "kernel::ipc::signal::global_register_signals" - .asciz "kernel::ipc::signal::global_logoff_signals" - .asciz "kernel::ipc::signal::send_signal" - .asciz "kernel::ipc::signal::signal_handler" - .asciz "rust_begin_unwind" - .asciz "kernel::trace::find_symbol_with_addr" - .asciz "kernel::ipc::signal::sigaction" - .asciz "kernel::ipc::signal::sigtimewait" - .asciz "kernel::ipc::signal::sigprocmask" - .asciz "kernel::ipc::signal::sigsuspend" - .asciz " as core::iter::traits::iterator::Iterator>::next" - .asciz " as core::iter::traits::iterator::Iterator>::next" - .asciz " as core::iter::traits::iterator::Iterator>::next" - .asciz " as core::iter::traits::iterator::Iterator>::next" - .asciz " as core::iter::traits::iterator::Iterator>::next" - .asciz " as core::iter::traits::iterator::Iterator>::next" - .asciz " as core::iter::traits::iterator::Iterator>::next" - .asciz " as core::iter::traits::iterator::Iterator>::next" - .asciz " as core::iter::traits::double_ended::DoubleEndedIterator>::next_back" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::into_any_rc" - .asciz "::into_any_arc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "core::ptr::drop_in_place>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place<&isize>" - .asciz "core::ptr::drop_in_place" - .asciz "alloc::collections::btree::map::BTreeMap::get" - .asciz "alloc::collections::btree::map::BTreeMap::get" - .asciz "alloc::collections::btree::map::BTreeMap::get" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::insert" - .asciz "alloc::collections::btree::map::BTreeMap::remove" - .asciz "alloc::collections::btree::map::BTreeMap::remove" - .asciz "alloc::collections::btree::map::BTreeMap::remove" - .asciz "alloc::collections::btree::map::BTreeMap::remove" - .asciz "alloc::collections::btree::map::BTreeMap::remove" - .asciz "alloc::collections::btree::map::BTreeMap::remove" - .asciz "alloc::collections::btree::map::BTreeMap::remove" - .asciz "alloc::collections::btree::map::entry::Entry::or_insert" - .asciz "alloc::collections::btree::map::entry::Entry::or_insert" - .asciz "unifs::inode::UniFsDirInode::lookup" - .asciz "unifs::inode::UniFsDirInode::readdir" - .asciz "unifs::inode::UniFsDirInode::node_perm" - .asciz " as vfscore::inode::VfsInode>::node_perm" - .asciz "unifs::inode::UniFsDirInode::rename_to" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::ops::drop::Drop>::drop" - .asciz "vfscore::file::VfsFile::poll" - .asciz "vfscore::file::VfsFile::ioctl" - .asciz "vfscore::file::VfsFile::read_at" - .asciz "vfscore::file::VfsFile::readdir" - .asciz "vfscore::file::VfsFile::write_at" - .asciz "vfscore::path::VfsPath::join" - .asciz "vfscore::path::VfsPath::join" - .asciz "vfscore::inode::VfsInode::link" - .asciz "vfscore::inode::VfsInode::link" - .asciz "vfscore::inode::VfsInode::rename_to" - .asciz "vfscore::inode::VfsInode::rename_to" - .asciz "vfscore::dentry::VfsDentry::is_mount_point" - .asciz "vfscore::dentry::VfsDentry::path" - .asciz " as vfscore::file::VfsFile>::readdir" - .asciz " as vfscore::dentry::VfsDentry>::set_parent" - .asciz " as vfscore::dentry::VfsDentry>::mount_point" - .asciz " as vfscore::dentry::VfsDentry>::to_mount_point" - .asciz " as vfscore::dentry::VfsDentry>::clear_mount_point" - .asciz " as vfscore::dentry::VfsDentry>::find" - .asciz " as vfscore::dentry::VfsDentry>::name" - .asciz " as vfscore::dentry::VfsDentry>::inode" - .asciz " as vfscore::dentry::VfsDentry>::insert" - .asciz " as vfscore::dentry::VfsDentry>::parent" - .asciz " as vfscore::dentry::VfsDentry>::remove" - .asciz " as vfscore::inode::VfsInode>::inode_type" - .asciz " as vfscore::inode::VfsInode>::list_xattr" - .asciz " as vfscore::inode::VfsInode>::rmdir" - .asciz " as vfscore::inode::VfsInode>::create" - .asciz " as vfscore::inode::VfsInode>::lookup" - .asciz " as vfscore::inode::VfsInode>::symlink" - .asciz " as vfscore::inode::VfsInode>::readlink" - .asciz " as vfscore::inode::VfsInode>::truncate" - .asciz " as vfscore::inode::VfsInode>::inode_type" - .asciz " as vfscore::inode::VfsInode>::update_time" - .asciz " as vfscore::inode::VfsInode>::get_super_block" - .asciz " as vfscore::inode::VfsInode>::link" - .asciz " as vfscore::inode::VfsInode>::rmdir" - .asciz " as vfscore::inode::VfsInode>::create" - .asciz " as vfscore::inode::VfsInode>::lookup" - .asciz " as vfscore::inode::VfsInode>::unlink" - .asciz " as vfscore::inode::VfsInode>::get_attr" - .asciz " as vfscore::inode::VfsInode>::readlink" - .asciz " as vfscore::inode::VfsInode>::set_attr" - .asciz " as vfscore::inode::VfsInode>::truncate" - .asciz " as vfscore::inode::VfsInode>::rename_to" - .asciz " as vfscore::superblock::VfsSuperBlock>::super_type" - .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" - .asciz " as core::clone::Clone>::clone::clone_subtree" - .asciz " as core::clone::Clone>::clone::clone_subtree" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz "kernel::print::init_print" - .asciz "::read_at" - .asciz "::write_at" - .asciz "::poll" - .asciz "::ioctl" - .asciz "::get_attr" - .asciz "::read_at" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" - .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" - .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" - .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" - .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" - .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" - .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" - .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" - .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" - .asciz "alloc::collections::btree::node::BalancingContext::do_merge" - .asciz "alloc::collections::btree::node::BalancingContext::do_merge" - .asciz "alloc::collections::btree::node::BalancingContext::do_merge" - .asciz "alloc::collections::btree::node::BalancingContext::do_merge" - .asciz "alloc::collections::btree::node::BalancingContext::do_merge" - .asciz "alloc::collections::btree::node::BalancingContext::do_merge" - .asciz "alloc::collections::btree::node::BalancingContext::do_merge" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" - .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" - .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" - .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" - .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" - .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" - .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" - .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" - .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" - .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" - .asciz " as core::ops::drop::Drop>::drop" - .asciz "page_table::table::bits64::PageTable64::map_region" - .asciz "page_table::table::bits64::PageTable64::alloc_table" - .asciz "page_table::table::bits64::PageTable64::unmap_region" - .asciz "page_table::table::bits64::PageTable64::modify_pte_flags" - .asciz "page_table::table::bits64::PageTable64::map_region_no_target" - .asciz "page_table::table::bits64::PageTable64::get_entry_mut_or_create" - .asciz "page_table::table::bits64::PageTable64::map" - .asciz "page_table::table::bits64::PageTable64::try_new" - .asciz "rtc::LowRtcDeviceExt::read_time_fmt" - .asciz "rtc::LowRtcDeviceExt::read_alarm_fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "core::ops::function::FnOnce::call_once" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "talc::alloc_error" - .asciz "alloc::collections::vec_deque::VecDeque::grow" - .asciz "alloc::collections::vec_deque::VecDeque::grow" - .asciz "alloc::collections::vec_deque::VecDeque::grow" - .asciz "::yield_now" - .asciz "kernel::driver::rtc::::hand_irq" - .asciz "kernel::interrupt::ext_interrupt::external_interrupt_handler" - .asciz "kernel::ipc::futex::FutexWaitManager::add_waiter" - .asciz "kernel::ipc::futex::FutexWaitManager::wake_for_signal" - .asciz "kernel::ipc::futex::FutexWaitManager::wake_for_timeout" - .asciz "kernel::ipc::futex::FutexWaitManager::delete_empty_waiters" - .asciz "kernel::ipc::futex::FutexWaitManager::wake" - .asciz "kernel::ipc::futex::FutexWaitManager::requeue" - .asciz "kernel::memory::vmm::kernel_info" - .asciz "kernel::memory::vmm::build_kernel_address_space" - .asciz "kernel::memory::vmm::build_thread_address_space" - .asciz "kernel::memory::vmm::build_cow_address_space" - .asciz "kernel::memory::vmm::build_elf_address_space" - .asciz "kernel::memory::init_memory_system" - .asciz "::alloc" - .asciz "::dealloc" - .asciz "::do_user_handle" - .asciz "::do_kernel_handle" - .asciz "__rust_alloc" - .asciz "__rust_dealloc" - .asciz "__rust_realloc" - .asciz "__rust_alloc_zeroed" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "alloc::collections::binary_heap::BinaryHeap::pop" - .asciz "alloc::sync::Arc::downgrade::panic_cold_display" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Weak::upgrade::checked_increment::panic_cold_display" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as core::ops::drop::Drop>::drop" - .asciz "hashbrown::raw::RawTable::reserve_rehash" - .asciz "hashbrown::raw::RawTableInner::fallible_with_capacity" - .asciz "::enabled" - .asciz "::log" - .asciz "::flush" - .asciz "kernel::print::logging::init_logger" - .asciz "kernel::fs::ram::init_ramfs" - .asciz "__sys_event_get" - .asciz "__sys_truncate" - .asciz "__sys_pread" - .asciz "__sys_fstatfs" - .asciz "__sys_renameat" - .asciz "__fcntl" - .asciz "__ioctl" - .asciz "__chmodat" - .asciz "__sys_lsetxattr" - .asciz "__sys_getxattr" - .asciz "__sys_lgetxattr" - .asciz "__sys_fgetxattr" - .asciz "__sys_readlinkat" - .asciz "__getrusage" - .asciz "__sched_getparam" - .asciz "__sys_framebuffer" - .asciz "__shmat" - .asciz "__set_robust_list" - .asciz "__do_munmap" - .asciz "__madvise" - .asciz "__listening" - .asciz "__connect" - .asciz "__shutdown" - .asciz "__do_suspend" - .asciz "__get_pgid" - .asciz "__getuid" - .asciz "__getegid" - .asciz "__wait4" .asciz "syscall_table::Service::from_handler::closure" .asciz "syscall_table::Service::from_handler::closure" .asciz "syscall_table::Service::from_handler::closure" @@ -7712,10 +7690,10 @@ symbol_name: .asciz "core::ops::function::FnOnce::call_oncevtable.shim" .asciz "core::ops::function::FnOnce::call_oncevtable.shim" .asciz "core::ops::function::FnOnce::call_oncevtable.shim" + .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" @@ -7726,80 +7704,80 @@ symbol_name: .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" - .asciz "core::ptr::drop_in_place::closure>" + .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place::closure>" .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" - .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" - .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" @@ -7818,10 +7796,10 @@ symbol_name: .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" + .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" - .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" .asciz "core::ptr::drop_in_place>::closure>" @@ -7852,431 +7830,258 @@ symbol_name: .asciz "<(P0,P1,P2,P3) as syscall_table::FromArgs>::from" .asciz "<(P0,P1,P2,P3,P4) as syscall_table::FromArgs>::from" .asciz "<(P0,P1,P2,P3,P4) as syscall_table::FromArgs>::from" - .asciz "virtio_drivers::device::gpu::VirtIOGpu::get_display_info" - .asciz "virtio_drivers::device::gpu::VirtIOGpu::setup_framebuffer" - .asciz "virtio_drivers::device::gpu::VirtIOGpu::new" - .asciz "virtio_drivers::device::gpu::VirtIOGpu::flush" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "core::ops::function::FnOnce::call_once" - .asciz "core::ops::function::FnOnce::call_once" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place<&str>" - .asciz "core::ptr::drop_in_place<&kernel::ipc::shm::ShmMemoryState>" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "spin::once::Once::try_call_once" - .asciz "spin::once::Once::try_call_once" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "::can_receive" - .asciz "::can_transmit" - .asciz "::rx_queue_size" - .asciz "::recycle_tx_buffers" - .asciz "vfscore::file::VfsFile::poll" - .asciz "vfscore::file::VfsFile::poll" - .asciz "vfscore::file::VfsFile::flush" - .asciz "vfscore::file::VfsFile::ioctl" - .asciz "vfscore::file::VfsFile::ioctl" - .asciz "vfscore::file::VfsFile::readdir" - .asciz "vfscore::file::VfsFile::readdir" - .asciz "vfscore::file::VfsFile::readdir" - .asciz "vfscore::inode::VfsInode::list_xattr" - .asciz "vfscore::inode::VfsInode::list_xattr" - .asciz "vfscore::inode::VfsInode::list_xattr" - .asciz "vfscore::inode::VfsInode::update_time" - .asciz "vfscore::inode::VfsInode::update_time" - .asciz "vfscore::inode::VfsInode::update_time" - .asciz "vfscore::inode::VfsInode::rmdir" - .asciz "vfscore::inode::VfsInode::rmdir" - .asciz "vfscore::inode::VfsInode::rmdir" - .asciz "vfscore::inode::VfsInode::create" - .asciz "vfscore::inode::VfsInode::create" - .asciz "vfscore::inode::VfsInode::create" - .asciz "vfscore::inode::VfsInode::lookup" - .asciz "vfscore::inode::VfsInode::lookup" - .asciz "vfscore::inode::VfsInode::lookup" - .asciz "vfscore::inode::VfsInode::symlink" - .asciz "vfscore::inode::VfsInode::symlink" - .asciz "vfscore::inode::VfsInode::symlink" - .asciz "vfscore::inode::VfsInode::readlink" - .asciz "vfscore::inode::VfsInode::readlink" - .asciz "vfscore::inode::VfsInode::readlink" - .asciz "vfscore::inode::VfsInode::truncate" - .asciz "vfscore::inode::VfsInode::truncate" - .asciz "vfscore::inode::VfsInode::truncate" - .asciz "vfscore::inode::VfsInode::node_perm" - .asciz "vfscore::inode::VfsInode::node_perm" - .asciz " as core::iter::traits::iterator::Iterator>::fold" - .asciz " as core::iter::traits::iterator::Iterator>::fold" - .asciz "::inode_type" - .asciz "::read_at" - .asciz "::set_attr" - .asciz "::get_attr" - .asciz "::inode_type" - .asciz "::write_at" - .asciz "::get_attr" - .asciz "::now" - .asciz "::flush" - .asciz "::get_super_block" - .asciz "::flush" - .asciz "::get_super_block" - .asciz "::set_attr" - .asciz "::get_attr" - .asciz "::inode_type" - .asciz "kernel::device::init_device" - .asciz "kernel::driver::block_device::LowBlockDriver::flush" - .asciz "::capacity" - .asciz "::update_cursor" - .asciz "::get_framebuffer" - .asciz "::have_space_to_put" - .asciz "::write_at" - .asciz "::get_super_block" - .asciz "::node_perm" - .asciz "::set_attr" - .asciz "::get_attr" - .asciz "::inode_type" - .asciz "kernel::fs::dev::register_device" - .asciz "kernel::fs::dev::alloc_device_id" - .asciz "::rdev2device" - .asciz "kernel::fs::dev::init_devfs" - .asciz "__sys_mount" - .asciz "__sys_chdir" - .asciz "__sys_mkdirat" - .asciz "__sys_readv" - .asciz "__sys_fstat" - .asciz "__sys_statfs" - .asciz "__chmod" - .asciz "__sys_flistxattr" - .asciz "__sys_lremovexattr" - .asciz "__sys_unlinkat" - .asciz "__pselect6" - .asciz "__sched_setparam" - .asciz "__sched_getaffinity" - .asciz "__sched_getscheduler" - .asciz "__sys_info" - .asciz "__sys_framebuffer_flush" - .asciz "kernel::ipc::shm::shmget" - .asciz "kernel::ipc::shm::shmat" - .asciz "kernel::ipc::shm::shmctl" - .asciz "__sigtimewait" - .asciz "__tkill" - .asciz "__sys_pipe" - .asciz "__do_mmap" - .asciz "__socket" - .asciz "__bind" - .asciz "__getsockname" - .asciz "__sendto" - .asciz "__recvfrom" - .asciz "__getsockopt" - .asciz "__exit_group" - .asciz "__clone" - .asciz "__do_exec" - .asciz "__setitimer" - .asciz "__switch" - .asciz "virtio_drivers::transport::Transport::begin_init" - .asciz "virtio_drivers::transport::Transport::begin_init" - .asciz "virtio_drivers::transport::Transport::begin_init" - .asciz "::type_id" - .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "vfs::system_support_fs" + .asciz "::fmt" .asciz "::as_any_mut" .asciz "::into_any_rc" .asciz "::as_any" .asciz "::into_any" + .asciz "<() as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" .asciz "core::fmt::num::::fmt" - .asciz "core::ops::function::FnOnce::call_once" - .asciz "core::ops::function::FnOnce::call_once" - .asciz "core::ops::function::FnOnce::call_once" - .asciz "core::ops::function::FnOnce::call_once" - .asciz "core::ptr::drop_in_place>" - .asciz "core::ptr::drop_in_place,ksync::KernelLockAction>>" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place<&kernel::net::socket::Socket>" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "<&mut T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<()>" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "::fmt" .asciz ">::call" .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" .asciz ">::call" .asciz ">::call" - .asciz "kernel::fs::file::kernel_file::File::read_at" - .asciz "kernel::fs::file::kernel_file::File::write_at" - .asciz "kernel::fs::file::kernel_file::File::flush" - .asciz "kernel::fs::file::kernel_file::File::ioctl" - .asciz "kernel::fs::file::kernel_file::File::readdir" - .asciz "kernel::fs::file::kernel_file::File::truncate" - .asciz "::fmt" - .asciz "::read" - .asciz "::write" - .asciz "::seek" - .asciz "::get_attr" - .asciz "::set_open_flag" - .asciz "::get_open_flag" - .asciz "::dentry" - .asciz "::inode" - .asciz "::is_readable" - .asciz "::is_append" - .asciz "::poll" - .asciz "::fmt" - .asciz "kernel::net::socket::SocketData::new" - .asciz "kernel::net::socket::SocketData::bind" - .asciz "kernel::net::socket::SocketData::accept" - .asciz "kernel::net::socket::SocketData::connect" - .asciz "kernel::net::socket::SocketData::send_to" - .asciz "kernel::net::socket::SocketData::recvfrom" - .asciz "kernel::net::socket::SocketData::shutdown" - .asciz "kernel::net::socket::SocketData::ready_read" - .asciz "kernel::net::common_socket_syscall" - .asciz "kernel::task::init_process" - .asciz "kernel::timer::check_timer_queue" - .asciz "__fsync" - .asciz "__utimensat" - .asciz "kernel::fs::select::pselect6" - .asciz "__syslog" - .asciz "__shmget" - .asciz "__kill" - .asciz "__map_protect" - .asciz "kernel::net::socket" - .asciz "kernel::net::bind" - .asciz "kernel::net::listening" - .asciz "kernel::net::accept" - .asciz "kernel::net::connect" - .asciz "kernel::net::getsockname" - .asciz "kernel::net::get_peer_name" - .asciz "kernel::net::sendto" - .asciz "kernel::net::recvfrom" - .asciz "kernel::net::setsockopt" - .asciz "__setsockopt" - .asciz "kernel::net::getsockopt" - .asciz "kernel::net::shutdown" - .asciz "kernel::net::socket_pair" - .asciz "__system_shutdown" - .asciz "__getgid" - .asciz "__do_brk" - .asciz "__set_tid_address" - .asciz "::fmt" - .asciz "::fmt" - .asciz "kernel::timer::nanosleep" - .asciz "kernel::timer::clock_get_time" - .asciz "kernel::timer::getitimer" - .asciz "kernel::timer::setitimer" - .asciz "kernel::timer::clock_getres" - .asciz "kernel::timer::clock_nanosleep" - .asciz " as core::iter::traits::iterator::Iterator>::next" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::fmt::Write::write_char" - .asciz "core::fmt::Write::write_char" - .asciz "core::fmt::Write::write_fmt" - .asciz "core::fmt::Write::write_fmt" - .asciz "core::fmt::Write::write_fmt" - .asciz "core::ptr::drop_in_place<&core::option::Option>>" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place<&u8>" - .asciz "core::ptr::drop_in_place<&u32>" - .asciz "core::ptr::drop_in_place<&usize>" - .asciz "core::ptr::drop_in_place<&pconst::io::PollFd>" - .asciz "core::ptr::drop_in_place<&kernel::ipc::shm::ShmInfo>" - .asciz "core::ptr::drop_in_place<&kernel::memory::frame::FrameTracker>" - .asciz "core::ptr::drop_in_place<&core::option::Option<()>>" - .asciz "core::ptr::drop_in_place<&pconst::signal::number::SignalNumber>" - .asciz "core::ptr::drop_in_place<&alloc::sync::Arc>" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "<&mut T as core::fmt::Debug>::fmt" - .asciz "::write_char" - .asciz "::write_str" - .asciz "alloc::vec::Vec::remove" - .asciz "alloc::vec::in_place_collect:: for alloc::vec::Vec>::from_iter" - .asciz "alloc::vec::in_place_collect:: for alloc::vec::Vec>::from_iter" - .asciz "alloc::string::String::push" - .asciz "pager::bitmap::Bitmap<_>::alloc_pages_inner" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::clone::Clone>::clone" - .asciz " as core::ops::drop::Drop>::drop" - .asciz ">::extend" - .asciz "gmanager::MinimalManager::insert_with_index" - .asciz "gmanager::MinimalManager::clear" - .asciz "gmanager::MinimalManager::insert" - .asciz " as alloc::vec::spec_from_iter::SpecFromIter>::from_iter" - .asciz " as alloc::vec::spec_from_iter::SpecFromIter>::from_iter" - .asciz " as alloc::vec::spec_from_iter::SpecFromIter>::from_iter" - .asciz " as alloc::vec::spec_from_iter::SpecFromIter>::from_iter" - .asciz "::write_str" - .asciz "::write_str" - .asciz "kernel::print::console::__print" - .asciz "::print" - .asciz "kernel::memory::map::MMapInfo::add_region" - .asciz "kernel::memory::map::MMapRegion::split" - .asciz "kernel::gui::sys_framebuffer" - .asciz "::fmt" - .asciz "kernel::memory::map::do_mmap" - .asciz "kernel::memory::map::map_protect" - .asciz "kernel::memory::map::msync" - .asciz "kernel::memory::map::madvise" - .asciz " as core::iter::traits::iterator::Iterator>::fold" - .asciz "virtio_drivers::device::blk::VirtIOBlk::new" - .asciz "::type_id" - .asciz "::type_id" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz "smpscheduler::fifo::FifoSmpScheduler<_,T,L,H>::new" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "::as_any_mut" .asciz "::into_any_rc" + .asciz "::into_any_arc" .asciz "::as_any" .asciz "::into_any" .asciz "<&T as core::fmt::Display>::fmt" .asciz "<&T as core::fmt::Display>::fmt" - .asciz "<&T as core::fmt::Display>::fmt" - .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place" + .asciz "<*mut T as core::fmt::Debug>::fmt" + .asciz "<*const T as core::fmt::Debug>::fmt" + .asciz "unifs::inode::UniFsDirInode::lookup" + .asciz "unifs::inode::UniFsDirInode::readdir" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz " as vfscore::superblock::VfsSuperBlock>::super_type" + .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" + .asciz "kernel::ipc::signal::global_register_signals" + .asciz "kernel::ipc::signal::global_logoff_signals" + .asciz "kernel::ipc::signal::send_signal" + .asciz "kernel::ipc::signal::signal_handler" + .asciz "::type_id" + .asciz "vfs::kfile::File::get_open_flag" + .asciz "vfs::kfile::File::flush" + .asciz "vfs::kfile::File::fsync" + .asciz "vfs::kfile::File::set_open_flag" + .asciz "vfs::kfile::File::ioctl" + .asciz "vfs::kfile::File::read_at" + .asciz "vfs::kfile::File::readdir" + .asciz "vfs::kfile::File::truncate" + .asciz "vfs::kfile::File::write_at" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_arc" + .asciz "::as_any" + .asciz "::into_any" .asciz "core::fmt::num::::fmt" .asciz "core::fmt::num::::fmt" .asciz "core::fmt::num::::fmt" .asciz "core::ops::function::FnOnce::call_once" - .asciz "core::ops::function::FnOnce::call_once" .asciz "core::ptr::drop_in_place" .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" .asciz "core::ptr::drop_in_place" - .asciz "core::str::pattern::TwoWaySearcher::next" - .asciz "<*mut T as core::fmt::Debug>::fmt" - .asciz "<*const T as core::fmt::Debug>::fmt" - .asciz "<*mut T as core::fmt::Pointer>::fmt" - .asciz "<(U,T) as core::fmt::Debug>::fmt" - .asciz "<&str as core::str::pattern::Pattern>::is_contained_in" .asciz "::fmt" - .asciz "::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz "vfscore::inode::VfsInode::link" - .asciz "vfscore::inode::VfsInode::link" - .asciz "vfscore::inode::VfsInode::rename_to" - .asciz "vfscore::inode::VfsInode::rename_to" - .asciz "::read_at" - .asciz "::write_at" - .asciz "::poll" - .asciz "::ioctl" - .asciz "::read_at" - .asciz "kernel::fs::file::kernel_file::File::read_at" - .asciz "kernel::fs::file::kernel_file::File::write_at" - .asciz "kernel::fs::file::kernel_file::File::ioctl" - .asciz "kernel::fs::file::kernel_file::File::set_open_flag" - .asciz "kernel::fs::file::kernel_file::File::get_open_flag" - .asciz "kernel::fs::file::kernel_file::File::readdir" - .asciz "kernel::fs::file::kernel_file::File::truncate" - .asciz "::seek" - .asciz "::get_attr" - .asciz "::is_append" - .asciz "kernel::task::cpu::current_user_token" - .asciz "first_into_user" - .asciz "kernel::task::schedule::schedule" - .asciz "kernel::trap::exception::syscall_exception_handler" - .asciz "kernel::trap::exception::page_exception_handler" - .asciz "kernel::trap::exception::trap_common_read_file" - .asciz "kernel::fs::control::fcntl" - .asciz "kernel::fs::control::ioctl" - .asciz "kernel::fs::control::utimensat" - .asciz "kernel::fs::control::faccessat" - .asciz "kernel::fs::control::unmask" - .asciz "kernel::ipc::sys_pipe" - .asciz "kernel::ipc::sys_dup" - .asciz "kernel::ipc::sys_dup2" + .asciz "unifs::UniFsSuperBlock::remove_inode" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz " as vfscore::superblock::VfsSuperBlock>::root_inode" + .asciz " as vfscore::superblock::VfsSuperBlock>::fs_type" + .asciz " as vfscore::superblock::VfsSuperBlock>::stat_fs" + .asciz "gmanager::MinimalManager::insert_with_index" + .asciz "gmanager::MinimalManager::insert" + .asciz "::seek" + .asciz "::get_attr" + .asciz "::is_append" .asciz "kernel::ipc::futex" - .asciz "kernel::ipc::get_robust_list" - .asciz "kernel::task::cpu::do_exit" - .asciz "kernel::task::cpu::do_suspend" - .asciz "kernel::task::cpu::get_ppid" - .asciz "kernel::task::cpu::clone" - .asciz "kernel::task::cpu::do_exec" - .asciz "kernel::task::cpu::wait4" - .asciz "kernel::task::cpu::do_brk" - .asciz "kernel::task::cpu::prlimit64" - .asciz "virtio_drivers::device::input::VirtIOInput::pop_pending_event" - .asciz "virtio_drivers::device::input::VirtIOInput::new" - .asciz "lru::LruCache::capturing_put" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place<&str>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "kernel::mm::loader::build_thread_address_space" + .asciz "kernel::mm::loader::build_cow_address_space" + .asciz "kernel::mm::loader::build_elf_address_space" + .asciz "main" + .asciz "rust_begin_unwind" + .asciz " as core::ops::drop::Drop>::drop" + .asciz "page_table::table::bits64::PageTable64::map_region" + .asciz "page_table::table::bits64::PageTable64::unmap_region" + .asciz "page_table::table::bits64::PageTable64::modify_pte_flags" + .asciz "page_table::table::bits64::PageTable64::map_region_no_target" + .asciz "page_table::table::bits64::PageTable64::get_entry_mut_or_create" + .asciz "page_table::table::bits64::PageTable64::map" + .asciz "::type_id" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place<&isize>" + .asciz "core::ptr::drop_in_place" + .asciz "alloc::collections::btree::map::entry::Entry::or_insert" + .asciz "alloc::collections::btree::map::entry::OccupiedEntry::remove_kv" + .asciz "alloc::collections::btree::map::entry::OccupiedEntry::remove_kv" + .asciz "alloc::collections::btree::map::entry::OccupiedEntry::remove_kv" + .asciz "alloc::collections::btree::map::entry::OccupiedEntry::remove_kv" + .asciz "dynfs::dir::DynFsDirInode::add_manually" + .asciz "dynfs::dir::DynFsDirInode::remove_manually" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::flush" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::read_at" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::write_at" + .asciz " as vfscore::file::VfsFile>::readdir" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::rmdir" + .asciz " as vfscore::inode::VfsInode>::create" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::symlink" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz "kernel::ipc::futex::FutexWaitManager::add_waiter" + .asciz "kernel::ipc::futex::FutexWaitManager::wake_for_signal" + .asciz "kernel::ipc::futex::FutexWaitManager::wake_for_timeout" + .asciz "kernel::ipc::futex::FutexWaitManager::delete_empty_waiters" + .asciz "kernel::ipc::futex::FutexWaitManager::wake" + .asciz "kernel::ipc::futex::FutexWaitManager::requeue" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::double_ended::DoubleEndedIterator>::next_back" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "::fmt" + .asciz ">::call" + .asciz ">::call" + .asciz "vfscore::path::VfsPath::join" + .asciz ">::call" + .asciz ">::call" + .asciz " as core::clone::Clone>::clone::clone_subtree" + .asciz " as core::clone::Clone>::clone::clone_subtree" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz "kernel::fs::user_path_at" + .asciz "kernel::fs::read_all" + .asciz "::relocate" + .asciz "kernel::net::addr::socket_addr_resolution" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::str::pattern::TwoWaySearcher::next" + .asciz "<&str as core::str::pattern::Pattern>::is_contained_in" + .asciz "::fmt" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz "kernel::trap::exception::syscall_exception_handler" + .asciz "kernel::trap::exception::page_exception_handler" + .asciz "kernel::trap::exception::trap_common_read_file" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place" .asciz "alloc::raw_vec::finish_grow" .asciz "alloc::raw_vec::RawVec::allocate_in" .asciz "alloc::raw_vec::RawVec::reserve_for_push" @@ -8294,226 +8099,299 @@ symbol_name: .asciz "alloc::raw_vec::RawVec::reserve_for_push" .asciz "alloc::raw_vec::RawVec::reserve_for_push" .asciz "alloc::raw_vec::RawVec::reserve_for_push" - .asciz "alloc::raw_vec::RawVec::reserve_for_push" - .asciz "alloc::raw_vec::RawVec::reserve_for_push" - .asciz "alloc::raw_vec::RawVec::reserve_for_push" - .asciz "alloc::raw_vec::RawVec::reserve_for_push" .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" - .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::ops::drop::Drop>::drop" - .asciz "kernel::driver::block_device::GenericBlockDevice::new" - .asciz "::read" - .asciz "::write" - .asciz "kernel::driver::block_device::VirtIOBlkWrapper::new" - .asciz "::read_block" - .asciz "::write_block" - .asciz "kernel::interrupt::init_plic" - .asciz "kernel::interrupt::register_device_to_plic" - .asciz "kernel::net::addr::socket_addr_resolution" - .asciz "__sys_umount" - .asciz "__sys_openat" + .asciz "__sys_mount" .asciz "__sys_close" .asciz "__sys_getdents" + .asciz "__sys_ftruncate" .asciz "__sys_read" .asciz "__sys_write" .asciz "__sys_getcwd" .asciz "__sys_fchdir" - .asciz "__sys_lseek" - .asciz "__sys_writev" + .asciz "__sys_mkdirat" + .asciz "__sys_readv" .asciz "__sys_pwrite" .asciz "__sys_fstateat" + .asciz "__sys_fstatfs" + .asciz "__sys_renameat" + .asciz "__sys_renameat2" + .asciz "__send_file" .asciz "__sync" + .asciz "__fsync" + .asciz "__fcntl" + .asciz "__ioctl" + .asciz "__utimensat" + .asciz "__faccessat" + .asciz "__chmod" + .asciz "__chmodat" + .asciz "__fchown" .asciz "__unmask" - .asciz "__sys_setxattr" + .asciz "__sys_lsetxattr" .asciz "__sys_fsetxattr" + .asciz "__sys_lgetxattr" + .asciz "__sys_listxattr" .asciz "__sys_llistxattr" - .asciz "__sys_removexattr" .asciz "__sys_fremovexattr" - .asciz "__sys_symlinkat" - .asciz "__sched_setaffinity" - .asciz "__sched_setscheduler" + .asciz "__sys_linkat" + .asciz "__ppoll" + .asciz "__pselect6" + .asciz "__sys_framebuffer" .asciz "__shmctl" + .asciz "__sigaction" + .asciz "__sigtimewait" .asciz "__sigprocmask" + .asciz "__kill" + .asciz "__tkill" .asciz "__signal_return" - .asciz "__sigsuspend" - .asciz "__sys_dup2" - .asciz "__get_robust_list" + .asciz "__sys_dup" + .asciz "__futex" + .asciz "__do_munmap" .asciz "__msync" - .asciz "__membarrier" - .asciz "::fmt" - .asciz "__accept" - .asciz "__get_peer_name" + .asciz "__madvise" + .asciz "__bind" + .asciz "__getsockname" + .asciz "__sendto" + .asciz "__recvfrom" .asciz "__socket_pair" - .asciz "kernel::system::uname" - .asciz "__uname" + .asciz "__sched_setparam" + .asciz "__sched_setaffinity" + .asciz "__sched_getaffinity" + .asciz "__sched_setscheduler" + .asciz "__getrusage" + .asciz "__system_shutdown" .asciz "__do_exit" + .asciz "__set_pgid" + .asciz "__get_pgid" .asciz "__set_sid" - .asciz "__get_pid" - .asciz "__get_ppid" + .asciz "__getuid" .asciz "__geteuid" - .asciz "__get_time_of_day" + .asciz "__getgid" + .asciz "__getegid" + .asciz "__do_exec" + .asciz "__wait4" + .asciz "__do_brk" + .asciz "__prlimit64" + .asciz "__times" + .asciz "__nanosleep" .asciz "__clock_get_time" + .asciz "__getitimer" + .asciz "__setitimer" .asciz "__clock_getres" + .asciz "__clock_nanosleep" + .asciz "kernel_v" .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" + .asciz "::fmt" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz "kernel::task::cpu::current_cpu" + .asciz "kernel::task::cpu::current_task" + .asciz "kernel::task::cpu::current_user_token" + .asciz "kernel::task::cpu::current_trap_frame" + .asciz "kernel::task::task::TaskInner::update_timer" + .asciz "trap_return" + .asciz "kernel::trap::init_trap_subsystem" + .asciz "kernel::trap::check_timer_interrupt_pending" + .asciz "user_trap_vector" + .asciz "kernel::trap::check_task_timer_expired" + .asciz "kernel_trap_vector" + .asciz "__get_robust_list" + .asciz "kernel::task::cpu::do_exit" + .asciz "kernel::task::cpu::do_suspend" + .asciz "::type_id" .asciz "::as_any_mut" .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" .asciz "::into_any_rc" .asciz "::into_any_rc" .asciz "::as_any" .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" .asciz "::into_any" .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "core::fmt::num::::fmt" - .asciz "core::fmt::Write::write_char" - .asciz "core::fmt::Write::write_fmt" + .asciz "<() as core::fmt::Debug>::fmt" .asciz "core::ops::function::FnOnce::call_once" - .asciz "core::ptr::drop_in_place>" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place<()>" + .asciz "core::ptr::drop_in_place<&isize>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "alloc::sync::Arc::downgrade" + .asciz "alloc::sync::Arc::downgrade" + .asciz "alloc::sync::Arc::downgrade" + .asciz "alloc::sync::Arc::downgrade::panic_cold_display" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Weak::upgrade::checked_increment::panic_cold_display" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as vfscore::file::VfsFile>::poll" + .asciz " as vfscore::file::VfsFile>::flush" + .asciz " as vfscore::file::VfsFile>::fsync" + .asciz " as vfscore::file::VfsFile>::ioctl" + .asciz " as vfscore::file::VfsFile>::read_at" + .asciz " as vfscore::file::VfsFile>::write_at" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::superblock::VfsSuperBlock>::super_type" + .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" + .asciz " as lock_api::mutex::RawMutex>::lock" + .asciz "kernel::task::schedule::run_task" + .asciz "kernel::task::schedule::schedule" + .asciz "kernel::task::init_process" + .asciz "::get_task" + .asciz "::put_task" + .asciz "::suspend" + .asciz "::transfer_ptr_raw" + .asciz "::transfer_buf_raw" + .asciz "kernel::trap::interrupt::timer_interrupt_handler" + .asciz "__sys_umount" + .asciz "__sys_openat" + .asciz "__sys_chdir" + .asciz "__sys_writev" + .asciz "__sys_pread" + .asciz "__sys_fstat" + .asciz "__sys_statfs" + .asciz "__copy_file_range" + .asciz "__sys_removexattr" + .asciz "__sys_lremovexattr" + .asciz "__sys_symlinkat" + .asciz "__sys_readlinkat" + .asciz "__sys_framebuffer_flush" + .asciz "__sys_event_get" + .asciz "__shmget" + .asciz "__sigsuspend" + .asciz "__map_protect" + .asciz "__membarrier" + .asciz "__socket" + .asciz "__listening" + .asciz "__connect" + .asciz "__setsockopt" + .asciz "__getsockopt" + .asciz "__uname" + .asciz "__sys_info" + .asciz "__sched_getparam" + .asciz "__get_pid" + .asciz "__get_tid" + .asciz "__set_tid_address" + .asciz "__get_time_of_day" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&pconst::io::PollFd>" + .asciz "core::ptr::drop_in_place<&alloc::string::String>" + .asciz "core::ptr::drop_in_place<&pconst::signal::number::SignalNumber>" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed" + .asciz "<&mut T as core::fmt::Debug>::fmt" + .asciz "alloc::vec::Vec::resize" + .asciz "alloc::vec::in_place_collect:: for alloc::vec::Vec>::from_iter" + .asciz "alloc::vec::in_place_collect:: for alloc::vec::Vec>::from_iter" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::clone::Clone>::clone" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz " as alloc::vec::spec_from_iter::SpecFromIter>::from_iter" + .asciz " as alloc::vec::spec_from_iter::SpecFromIter>::from_iter" + .asciz " as alloc::vec::spec_from_iter::SpecFromIter>::from_iter" + .asciz "kernel::mm::map::MMapInfo::add_region" + .asciz "kernel::mm::map::MMapRegion::split" + .asciz "::fmt" + .asciz "__switch" + .asciz " as core::iter::traits::iterator::Iterator>::fold" + .asciz " as core::iter::traits::iterator::Iterator>::fold" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::into_any" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::Write::write_fmt" .asciz "core::ptr::drop_in_place>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place<&str>" .asciz "core::ptr::drop_in_place" .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" .asciz "core::ptr::drop_in_place" .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place>" .asciz "::fmt" .asciz "::write_char" .asciz "::write_str" - .asciz "fatfs::boot_sector::BootSector::deserialize" - .asciz "fatfs::boot_sector::BootSector::validate" - .asciz "fatfs::boot_sector::BiosParameterBlock::validate_total_sectors" - .asciz "fatfs::boot_sector::BiosParameterBlock::validate_total_clusters" - .asciz "fatfs::boot_sector::BiosParameterBlock::validate_sectors_per_fat" - .asciz " as vfscore::fstype::VfsFsType>::mount" - .asciz " as vfscore::fstype::VfsFsType>::fs_flag" - .asciz " as vfscore::fstype::VfsFsType>::fs_name" - .asciz " as vfscore::fstype::VfsFsType>::kill_sb" - .asciz " as vfscore::fstype::VfsFsType>::mount" - .asciz " as vfscore::fstype::VfsFsType>::kill_sb" - .asciz " as vfscore::fstype::VfsFsType>::fs_name" - .asciz " as vfscore::fstype::VfsFsType>::fs_flag" - .asciz " as vfscore::fstype::VfsFsType>::fs_name" - .asciz "vfscore::file::VfsFile::poll" - .asciz "vfscore::file::VfsFile::poll" - .asciz "vfscore::file::VfsFile::flush" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz " as core::fmt::Debug>::fmt" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" .asciz "vfscore::file::VfsFile::flush" .asciz "vfscore::file::VfsFile::ioctl" - .asciz "vfscore::file::VfsFile::ioctl" - .asciz "vfscore::file::VfsFile::read_at" .asciz "vfscore::file::VfsFile::readdir" - .asciz "vfscore::file::VfsFile::readdir" - .asciz "vfscore::file::VfsFile::write_at" - .asciz "vfscore::file::VfsFile::write_at" - .asciz "vfscore::inode::VfsInode::list_xattr" - .asciz "vfscore::inode::VfsInode::update_time" - .asciz "vfscore::inode::VfsInode::link" - .asciz "vfscore::inode::VfsInode::rmdir" - .asciz "vfscore::inode::VfsInode::create" - .asciz "vfscore::inode::VfsInode::lookup" - .asciz "vfscore::inode::VfsInode::symlink" - .asciz "vfscore::inode::VfsInode::readlink" - .asciz "vfscore::inode::VfsInode::truncate" - .asciz "vfscore::inode::VfsInode::rename_to" - .asciz " as vfscore::inode::VfsInode>::inode_type" - .asciz " as vfscore::inode::VfsInode>::readlink" - .asciz " as vfscore::inode::VfsInode>::set_attr" - .asciz " as vfscore::inode::VfsInode>::truncate" - .asciz "::_init" - .asciz "::_put" - .asciz "::_read" - .asciz "::fmt" - .asciz "kernel::fs::file::kernel_file::KernelFile::new" - .asciz "::read" - .asciz "::write" - .asciz "::read_at" - .asciz "::write_at" - .asciz "::flush" - .asciz "::fsync" - .asciz "::seek" - .asciz "::get_attr" - .asciz "::ioctl" - .asciz "::set_open_flag" - .asciz "::get_open_flag" - .asciz "::inode" - .asciz "::readdir" - .asciz "::truncate" - .asciz "::is_readable" - .asciz "::is_writable" - .asciz "::is_append" - .asciz "kernel::fs::proc::filesystem::SystemSupportFS::serialize" - .asciz "::read_at" - .asciz "::get_attr" - .asciz "::write_at" - .asciz "::get_super_block" - .asciz "::node_perm" - .asciz "::set_attr" - .asciz "::get_attr" - .asciz "::inode_type" - .asciz "::get_attr" - .asciz "kernel::fs::proc::init_procfs" - .asciz "kernel::fs::init_filesystem" - .asciz "::write_str" - .asciz "kernel::fs::user_path_at" - .asciz "kernel::fs::read_all" + .asciz ">::call" + .asciz ">::call" .asciz "::fmt" - .asciz "kernel::ipc::pipe::init_pipefs" .asciz "kernel::ipc::pipe::make_pipe_file" - .asciz "::read" - .asciz "::write" - .asciz "::dentry" - .asciz "::dentry" - .asciz "::inode" - .asciz "::is_readable" - .asciz "::is_writable" - .asciz "::poll" - .asciz "::poll" + .asciz "::read" + .asciz "::write" + .asciz "::dentry" + .asciz "::inode" + .asciz "::is_readable" + .asciz "::is_writable" + .asciz "::poll" .asciz "::read_at" .asciz "::write_at" .asciz "::poll" @@ -8526,18 +8404,8 @@ symbol_name: .asciz "::inode_type" .asciz "::update_time" .asciz "::drop" - .asciz "kernel::trap::interrupt::timer_interrupt_handler" - .asciz "kernel::init_machine_info" - .asciz "__sys_ftruncate" - .asciz "__sys_renameat2" - .asciz "__send_file" - .asciz "__copy_file_range" - .asciz "__faccessat" - .asciz "__fchown" - .asciz "__sys_listxattr" - .asciz "__sys_linkat" - .asciz "kernel::fs::poll::ppoll" - .asciz "__ppoll" + .asciz "kernel::fs::ext::sys_setxattr" + .asciz "kernel::fs::ext::sys_getxattr" .asciz "::create" .asciz "::link" .asciz "::symlink" @@ -8545,314 +8413,1543 @@ symbol_name: .asciz "::rmdir" .asciz "::truncate" .asciz "::rename_to" - .asciz "__sigaction" - .asciz "__sys_dup" - .asciz "__futex" - .asciz "__set_pgid" - .asciz "__get_tid" - .asciz "__prlimit64" - .asciz "__times" - .asciz "__nanosleep" - .asciz "__getitimer" - .asciz "__clock_nanosleep" - .asciz " as core::iter::traits::iterator::Iterator>::next" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::fmt" - .asciz "::as_any_mut" + .asciz "vfs::kfile::File::flush" + .asciz "vfs::kfile::File::ioctl" + .asciz "vfs::kfile::File::read_at" + .asciz "vfs::kfile::File::readdir" + .asciz "vfs::kfile::File::truncate" + .asciz "vfs::kfile::File::write_at" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" .asciz "::as_any_mut" .asciz "::into_any_rc" - .asciz "::into_any_rc" .asciz "::as_any" - .asciz "::as_any" - .asciz "::into_any" .asciz "::into_any" - .asciz "<() as core::fmt::Debug>::fmt" - .asciz "core::fmt::num::::fmt" + .asciz "<&T as core::fmt::Display>::fmt" .asciz "core::fmt::num::::fmt" - .asciz "core::ops::function::FnOnce::call_once" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place<()>" - .asciz "core::ptr::drop_in_place" - .asciz "::fmt" - .asciz "::fmt" - .asciz ">::call" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "<&mut T as core::fmt::Debug>::fmt" + .asciz "::is_readable" + .asciz "::seek" + .asciz "::get_attr" + .asciz "::is_append" .asciz ">::call" .asciz ">::call" - .asciz " as core::fmt::Debug>::fmt" .asciz ">::call" .asciz ">::call" .asciz ">::call" - .asciz "vfscore::inode::VfsInode::link" - .asciz "vfscore::inode::VfsInode::link" - .asciz "vfscore::inode::VfsInode::link" - .asciz "vfscore::inode::VfsInode::rename_to" - .asciz "vfscore::inode::VfsInode::rename_to" - .asciz "vfscore::inode::VfsInode::rename_to" - .asciz " as vfscore::superblock::VfsSuperBlock>::super_type" - .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" - .asciz " as vfscore::inode::VfsInode>::list_xattr" - .asciz " as vfscore::inode::VfsInode>::update_time" - .asciz " as vfscore::inode::VfsInode>::get_super_block" - .asciz " as vfscore::inode::VfsInode>::link" - .asciz " as vfscore::inode::VfsInode>::get_attr" - .asciz " as vfscore::inode::VfsInode>::readlink" - .asciz " as vfscore::inode::VfsInode>::set_attr" - .asciz " as vfscore::inode::VfsInode>::node_perm" - .asciz " as vfscore::inode::VfsInode>::rename_to" - .asciz "::write_at" - .asciz "::flush" - .asciz "::fsync" - .asciz "::read_at" - .asciz "::read_at" - .asciz "::relocate" - .asciz "kernel::fs::basic::sys_mount" - .asciz "kernel::fs::basic::sys_umount" - .asciz "kernel::fs::basic::sys_openat" - .asciz "kernel::fs::basic::sys_getdents" - .asciz "kernel::fs::basic::sys_truncate" - .asciz "kernel::fs::basic::sys_ftruncate" - .asciz "kernel::fs::basic::sys_read" - .asciz "kernel::fs::basic::sys_write" - .asciz "kernel::fs::basic::sys_getcwd" - .asciz "kernel::fs::basic::sys_chdir" - .asciz "kernel::fs::basic::sys_fchdir" - .asciz "kernel::fs::basic::sys_mkdirat" - .asciz "kernel::fs::basic::sys_lseek" - .asciz "kernel::fs::basic::sys_writev" - .asciz "kernel::fs::basic::sys_readv" - .asciz "kernel::fs::basic::sys_pread" - .asciz "kernel::fs::basic::sys_pwrite" - .asciz "kernel::fs::basic::sys_fstateat" - .asciz "kernel::fs::basic::sys_fstat" - .asciz "kernel::fs::basic::sys_fstatfs" - .asciz "kernel::fs::basic::sys_statfs" - .asciz "kernel::fs::basic::sys_renameat" - .asciz "kernel::fs::basic::sys_renameat2" - .asciz "kernel::fs::basic::send_file" - .asciz "kernel::fs::basic::fsync" - .asciz "kernel::fs::basic::copy_file_range" - .asciz "kernel::fs::ext::sys_setxattr" - .asciz "kernel::fs::ext::sys_fsetxattr" - .asciz "kernel::fs::ext::sys_getxattr" - .asciz "kernel::fs::ext::sys_fgetxattr" - .asciz "kernel::fs::ext::sys_flistxattr" - .asciz "kernel::fs::ext::sys_fremovexattr" - .asciz "kernel::fs::link::sys_linkat" - .asciz "kernel::fs::link::sys_unlinkat" - .asciz "kernel::fs::link::sys_symlinkat" - .asciz "kernel::fs::link::sys_readlinkat" - .asciz "smpscheduler::fifo::FifoSmpScheduler<_,T,L,H>::new" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "::type_id" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::as_any_mut" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::into_any_rc" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::as_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "::into_any" - .asciz "core::ops::function::FnOnce::call_once" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz ">::call" + .asciz "kernel::net::common_socket_syscall" + .asciz "::do_user_handle" + .asciz "::do_kernel_handle" + .asciz "__sys_truncate" + .asciz "__sys_lseek" + .asciz "__sys_setxattr" + .asciz "__sys_getxattr" + .asciz "__sys_fgetxattr" + .asciz "__sys_flistxattr" + .asciz "__sys_unlinkat" + .asciz "__shmat" + .asciz "__sys_pipe" + .asciz "__sys_dup2" + .asciz "__set_robust_list" + .asciz "__do_mmap" + .asciz "__accept" + .asciz "__get_peer_name" + .asciz "__shutdown" + .asciz "__syslog" + .asciz "__sched_getscheduler" + .asciz "__exit_group" + .asciz "__do_suspend" + .asciz "__get_ppid" + .asciz "__clone" + .asciz "__rust_alloc_error_handler" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place,ksync::KernelLockAction>>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place<&knet::socket::Socket>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "knet::socket::SocketFile::set_close_on_exec" + .asciz "::get_socketdata" + .asciz "::read" + .asciz "::write" + .asciz "::set_open_flag" + .asciz "::get_open_flag" + .asciz "::dentry" + .asciz "::inode" + .asciz "::poll" + .asciz "::fmt" + .asciz "knet::socket::SocketData::new" + .asciz "knet::socket::SocketData::set_socket_nonblock" + .asciz "knet::socket::SocketData::bind" + .asciz "knet::socket::SocketData::accept" + .asciz "knet::socket::SocketData::listening" + .asciz "knet::socket::SocketData::connect" + .asciz "knet::socket::SocketData::send_to" + .asciz "knet::socket::SocketData::recvfrom" + .asciz "knet::socket::SocketData::shutdown" + .asciz "knet::socket::SocketData::local_addr" + .asciz "knet::socket::SocketData::peer_addr" + .asciz "knet::socket::SocketData::ready_read" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz "alloc::sync::Arc::drop_slow" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz ">::from" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&&str>" + .asciz "core::ptr::drop_in_place<&xmas_elf::program::Type>" + .asciz "core::ptr::drop_in_place<&xmas_elf::sections::ShType>" + .asciz "core::ptr::drop_in_place<&xmas_elf::dynamic::Tag>" + .asciz "core::ptr::drop_in_place<&xmas_elf::dynamic::Tag>" + .asciz "core::ptr::drop_in_place<&xmas_elf::sections::CompressionType>" + .asciz "core::panicking::assert_failed" + .asciz "xmas_elf::ElfFile::new" + .asciz "xmas_elf::ElfFile::get_shstr" + .asciz "xmas_elf::ElfFile::get_dyn_string" + .asciz "xmas_elf::ElfFile::find_section_by_name" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&str>" + .asciz "xmas_elf::sections::parse_section_header" + .asciz "xmas_elf::sections::SectionHeader::get_data" + .asciz "xmas_elf::sections::SectionHeader::raw_data" + .asciz "::fmt" + .asciz "xmas_elf::program::parse_program_header" + .asciz "::next" + .asciz "xmas_elf::program::ProgramHeader::get_type" + .asciz "xmas_elf::program::ProgramHeader::get_data" + .asciz "xmas_elf::program::ProgramHeader32::get_data" + .asciz "xmas_elf::program::ProgramHeader32::raw_data" + .asciz "xmas_elf::program::ProgramHeader64::get_data" + .asciz "xmas_elf::program::ProgramHeader64::raw_data" + .asciz "::get_name" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz "zero::read_str" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "core::ops::function::FnOnce::call_once" .asciz "core::ops::function::FnOnce::call_once" .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place>>" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place<&vfscore::utils::VfsNodeType>" .asciz "core::array::::fmt" .asciz "core::array::::fmt" .asciz "core::panicking::assert_failed" .asciz "core::panicking::assert_failed" - .asciz "core::panicking::assert_failed" - .asciz "core::panicking::assert_failed" - .asciz "core::panicking::assert_failed" - .asciz "core::panicking::assert_failed" - .asciz "core::panicking::assert_failed" - .asciz "core::panicking::assert_failed" - .asciz "dynfs::dir::DynFsDirInode::add_manually" - .asciz "dynfs::dir::DynFsDirInode::remove_manually" - .asciz "fatfs::fs::FileSystem::alloc_cluster" - .asciz "fatfs::fs::FileSystem::set_dirty_flag" - .asciz "fatfs::fs::FileSystem::free_cluster_chain" - .asciz "fatfs::fs::FileSystem::new" - .asciz "fatfs::fs::FileSystem::stats" - .asciz "fatfs::fs::FileSystem::root_dir" - .asciz "fatfs::fs::FileSystem::fat_slice" - .asciz "fatfs::io::Read::read_exact" - .asciz "fatfs::io::Write::write_all" - .asciz "fatfs::io::Write::write_all" - .asciz "fatfs::file::File::set_first_cluster" - .asciz "fatfs::file::File::abs_pos" - .asciz "fatfs::file::File::truncate" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as fatfs::io::Read>::read" - .asciz " as fatfs::io::Seek>::seek" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as core::fmt::Debug>::fmt" - .asciz " as fatfs::io::Write>::write" - .asciz " as fatfs::io::Read>::read" - .asciz " as fatfs::io::Seek>::seek" - .asciz " as fatfs::io::Write>::write" - .asciz " as core::clone::Clone>::clone" + .asciz "::read_at" + .asciz "::flush" + .asciz "::inode_type" + .asciz "::get_attr" + .asciz "::set_attr" + .asciz "::get_super_block" + .asciz "::flush" + .asciz "::inode_type" + .asciz "::write_at" + .asciz "::inode_type" + .asciz "::get_super_block" + .asciz "::get_attr" + .asciz "::set_attr" + .asciz "::get_attr" + .asciz " as vfscore::fstype::VfsFsType>::mount" + .asciz " as vfscore::fstype::VfsFsType>::fs_flag" + .asciz " as vfscore::fstype::VfsFsType>::fs_name" + .asciz " as vfscore::fstype::VfsFsType>::kill_sb" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::poll" .asciz "vfscore::file::VfsFile::poll" .asciz "vfscore::file::VfsFile::flush" .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::ioctl" .asciz "vfscore::file::VfsFile::read_at" .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::readdir" .asciz "vfscore::file::VfsFile::write_at" - .asciz "vfscore::inode::VfsInode::link" - .asciz "vfscore::inode::VfsInode::link" - .asciz "vfscore::inode::VfsInode::link" - .asciz "vfscore::inode::VfsInode::rename_to" - .asciz "vfscore::inode::VfsInode::rename_to" - .asciz "vfscore::inode::VfsInode::rename_to" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as vfscore::file::VfsFile>::readdir" + .asciz "vfscore::inode::VfsInode::list_xattr" + .asciz "vfscore::inode::VfsInode::list_xattr" + .asciz "vfscore::inode::VfsInode::list_xattr" + .asciz "vfscore::inode::VfsInode::update_time" + .asciz "vfscore::inode::VfsInode::update_time" + .asciz "vfscore::inode::VfsInode::update_time" + .asciz "vfscore::inode::VfsInode::rmdir" + .asciz "vfscore::inode::VfsInode::rmdir" + .asciz "vfscore::inode::VfsInode::rmdir" + .asciz "vfscore::inode::VfsInode::create" + .asciz "vfscore::inode::VfsInode::create" + .asciz "vfscore::inode::VfsInode::create" + .asciz "vfscore::inode::VfsInode::lookup" + .asciz "vfscore::inode::VfsInode::lookup" + .asciz "vfscore::inode::VfsInode::lookup" + .asciz "vfscore::inode::VfsInode::symlink" + .asciz "vfscore::inode::VfsInode::symlink" + .asciz "vfscore::inode::VfsInode::symlink" + .asciz "vfscore::inode::VfsInode::readlink" + .asciz "vfscore::inode::VfsInode::readlink" + .asciz "vfscore::inode::VfsInode::readlink" + .asciz "vfscore::inode::VfsInode::truncate" + .asciz "vfscore::inode::VfsInode::truncate" + .asciz "vfscore::inode::VfsInode::truncate" + .asciz "vfscore::inode::VfsInode::node_perm" + .asciz "vfscore::inode::VfsInode::node_perm" + .asciz " as vfscore::file::VfsFile>::poll" + .asciz " as vfscore::file::VfsFile>::flush" + .asciz " as vfscore::file::VfsFile>::fsync" + .asciz " as vfscore::file::VfsFile>::ioctl" + .asciz " as vfscore::file::VfsFile>::read_at" + .asciz " as vfscore::file::VfsFile>::write_at" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::rename_to" .asciz " as vfscore::inode::VfsInode>::inode_type" - .asciz " as vfscore::inode::VfsInode>::list_xattr" - .asciz " as vfscore::inode::VfsInode>::update_time" - .asciz " as vfscore::inode::VfsInode>::get_super_block" - .asciz " as vfscore::inode::VfsInode>::link" - .asciz " as vfscore::inode::VfsInode>::rmdir" - .asciz " as vfscore::inode::VfsInode>::create" - .asciz " as vfscore::inode::VfsInode>::lookup" - .asciz " as vfscore::inode::VfsInode>::symlink" - .asciz " as vfscore::inode::VfsInode>::get_attr" .asciz " as vfscore::inode::VfsInode>::readlink" - .asciz " as vfscore::inode::VfsInode>::set_attr" .asciz " as vfscore::inode::VfsInode>::truncate" - .asciz " as vfscore::inode::VfsInode>::node_perm" - .asciz " as vfscore::inode::VfsInode>::node_perm" - .asciz " as vfscore::inode::VfsInode>::rename_to" - .asciz " as vfscore::file::VfsFile>::poll" - .asciz " as vfscore::file::VfsFile>::flush" - .asciz " as vfscore::file::VfsFile>::fsync" - .asciz " as vfscore::file::VfsFile>::ioctl" - .asciz " as vfscore::file::VfsFile>::read_at" - .asciz " as vfscore::file::VfsFile>::write_at" - .asciz " as core::ops::drop::Drop>::drop" - .asciz " as vfscore::inode::VfsInode>::inode_type" - .asciz " as vfscore::inode::VfsInode>::update_time" - .asciz " as vfscore::inode::VfsInode>::get_super_block" - .asciz " as vfscore::inode::VfsInode>::lookup" - .asciz " as vfscore::inode::VfsInode>::get_attr" - .asciz " as vfscore::inode::VfsInode>::readlink" - .asciz " as vfscore::inode::VfsInode>::truncate" .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" - .asciz " as vfscore::file::VfsFile>::poll" - .asciz " as vfscore::file::VfsFile>::read_at" - .asciz " as vfscore::file::VfsFile>::write_at" - .asciz " as vfscore::inode::VfsInode>::list_xattr" - .asciz " as vfscore::inode::VfsInode>::update_time" - .asciz " as vfscore::inode::VfsInode>::get_super_block" - .asciz " as vfscore::inode::VfsInode>::link" - .asciz " as vfscore::inode::VfsInode>::get_attr" - .asciz " as vfscore::inode::VfsInode>::set_attr" - .asciz " as vfscore::inode::VfsInode>::truncate" - .asciz " as vfscore::inode::VfsInode>::rename_to" - .asciz "::read_at" - .asciz "::poll" - .asciz "::read_at" - .asciz "::write_at" - .asciz "::ioctl" - .asciz "kernel::driver::gpu::VirtIOGpuWrapper::new" - .asciz "::hand_irq" - .asciz "::flush" - .asciz "kernel::driver::input::VirtIOInputDriver::from_addr" - .asciz "::is_empty" - .asciz "::read_event_with_block" - .asciz "::read_event_without_block" - .asciz "::hand_irq" - .asciz "::put" - .asciz "::get" - .asciz "::put_bytes" - .asciz "::have_data_to_get" - .asciz "::hand_irq" - .asciz "::read_at" - .asciz "::get_attr" - .asciz "kernel::interrupt::record::write_irq_info" - .asciz "kernel::interrupt::record::interrupts_info" - .asciz "kernel::memory::frame::init_frame_allocator" - .asciz "::drop" + .asciz "::write_at" + .asciz "::get_super_block" + .asciz "::node_perm" + .asciz "::set_attr" + .asciz "::get_attr" + .asciz "::inode_type" + .asciz "vfs::dev::register_device" + .asciz "vfs::dev::alloc_device_id" + .asciz "vfs::dev::init_devfs" + .asciz "vfs::pipefs::init_pipefs" + .asciz "vfs::sys::init_sysfs" + .asciz "alloc::sync::Arc::downgrade::panic_cold_display" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Weak::upgrade::checked_increment::panic_cold_display" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz "::type_id" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "alloc::collections::btree::map::BTreeMap::get" + .asciz "alloc::collections::btree::map::BTreeMap::get" + .asciz "alloc::collections::btree::map::BTreeMap::get" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::remove" + .asciz "alloc::collections::btree::map::BTreeMap::remove" + .asciz "alloc::collections::btree::map::BTreeMap::remove" + .asciz "alloc::collections::btree::map::BTreeMap::remove" + .asciz "alloc::collections::btree::map::entry::Entry::or_insert" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::flush" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::write_at" + .asciz "vfscore::inode::VfsInode::list_xattr" + .asciz "vfscore::inode::VfsInode::update_time" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::rmdir" + .asciz "vfscore::inode::VfsInode::create" + .asciz "vfscore::inode::VfsInode::lookup" + .asciz "vfscore::inode::VfsInode::symlink" + .asciz "vfscore::inode::VfsInode::readlink" + .asciz "vfscore::inode::VfsInode::truncate" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::ops::drop::Drop>::drop" + .asciz "::read_at" + .asciz "::write_at" + .asciz "::get_super_block" + .asciz "::node_perm" + .asciz "::set_attr" + .asciz "::get_attr" + .asciz "::inode_type" + .asciz "::get_attr" + .asciz "vfs::proc::init_procfs" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "alloc::collections::btree::navigate::,alloc::collections::btree::node::marker::Edge>>::deallocating_next_unchecked" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_arc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "dynfs::dir::DynFsDirInode::add_manually" + .asciz "unifs::inode::UniFsDirInode::lookup" + .asciz "unifs::inode::UniFsDirInode::lookup" + .asciz "unifs::inode::UniFsDirInode::readdir" + .asciz "unifs::inode::UniFsDirInode::readdir" + .asciz "unifs::inode::UniFsDirInode::node_perm" + .asciz "unifs::inode::UniFsDirInode::node_perm" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz "unifs::inode::UniFsDirInode::rename_to" + .asciz "unifs::inode::UniFsDirInode::rename_to" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::read_at" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::write_at" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz " as vfscore::file::VfsFile>::readdir" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::rmdir" + .asciz " as vfscore::inode::VfsInode>::create" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::symlink" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::superblock::VfsSuperBlock>::super_type" + .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" + .asciz "::read_at" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::allocate_in" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz " as vfscore::fstype::VfsFsType>::mount" + .asciz " as vfscore::fstype::VfsFsType>::fs_flag" + .asciz " as vfscore::fstype::VfsFsType>::fs_name" + .asciz " as vfscore::fstype::VfsFsType>::kill_sb" + .asciz "fat_vfs::fs::FatFsSuperBlock::root_dentry" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::flush" + .asciz "vfscore::file::VfsFile::read_at" + .asciz "vfscore::file::VfsFile::write_at" + .asciz "vfscore::dentry::VfsDentry::is_mount_point" + .asciz "vfscore::dentry::VfsDentry::path" + .asciz " as vfscore::dentry::VfsDentry>::set_parent" + .asciz " as vfscore::dentry::VfsDentry>::mount_point" + .asciz " as vfscore::dentry::VfsDentry>::to_mount_point" + .asciz " as vfscore::dentry::VfsDentry>::clear_mount_point" + .asciz " as vfscore::dentry::VfsDentry>::find" + .asciz " as vfscore::dentry::VfsDentry>::name" + .asciz " as vfscore::dentry::VfsDentry>::inode" + .asciz " as vfscore::dentry::VfsDentry>::insert" + .asciz " as vfscore::dentry::VfsDentry>::parent" + .asciz " as vfscore::dentry::VfsDentry>::remove" + .asciz " as vfscore::file::VfsFile>::ioctl" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::symlink" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::superblock::VfsSuperBlock>::root_inode" + .asciz " as vfscore::superblock::VfsSuperBlock>::fs_type" + .asciz " as vfscore::superblock::VfsSuperBlock>::stat_fs" + .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" + .asciz "fatfs::fs::FileSystem::alloc_cluster" + .asciz "fatfs::fs::FileSystem::set_dirty_flag" + .asciz "fatfs::fs::FileSystem::free_cluster_chain" + .asciz "fatfs::fs::FileSystem::truncate_cluster_chain" + .asciz "fatfs::fs::FileSystem::new" + .asciz "fatfs::fs::FileSystem::stats" + .asciz "fatfs::fs::FileSystem::root_dir" + .asciz "fatfs::fs::FileSystem::fat_slice" + .asciz "fatfs::io::Read::read_exact" + .asciz "fatfs::io::Write::write_all" + .asciz " as fatfs::io::Read>::read" + .asciz " as fatfs::io::Seek>::seek" + .asciz " as fatfs::io::Write>::write" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_arc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place<&usize>" + .asciz "fatfs::table::alloc_cluster" + .asciz "fatfs::table::find_free_cluster" + .asciz "fatfs::table::count_free_clusters" + .asciz "fatfs::table::ClusterIterator::truncate" + .asciz "fatfs::table::write_fat" + .asciz "unifs::UniFs::kill_sb" + .asciz "unifs::UniFsSuperBlock::root_dentry" + .asciz "unifs::UniFsSuperBlock::remove_inode" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as vfscore::fstype::VfsFsType>::mount" + .asciz " as vfscore::fstype::VfsFsType>::fs_flag" + .asciz " as vfscore::fstype::VfsFsType>::fs_name" + .asciz " as vfscore::fstype::VfsFsType>::kill_sb" + .asciz " as core::ops::drop::Drop>::drop" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::flush" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::read_at" + .asciz "vfscore::file::VfsFile::write_at" + .asciz "vfscore::path::VfsPath::join" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::symlink" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::superblock::VfsSuperBlock>::root_inode" + .asciz " as vfscore::superblock::VfsSuperBlock>::fs_type" + .asciz " as vfscore::superblock::VfsSuperBlock>::stat_fs" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz " as core::fmt::Debug>::fmt" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::flush" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::read_at" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::write_at" + .asciz " as vfscore::file::VfsFile>::readdir" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::rmdir" + .asciz " as vfscore::inode::VfsInode>::create" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::symlink" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::rmdir" + .asciz " as vfscore::inode::VfsInode>::create" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::unlink" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::file::VfsFile>::readdir" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::rmdir" + .asciz " as vfscore::inode::VfsInode>::create" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::unlink" + .asciz " as vfscore::inode::VfsInode>::unlink::closure" + .asciz " as vfscore::inode::VfsInode>::symlink" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::file::VfsFile>::ioctl" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::into_any" + .asciz "core::ptr::drop_in_place>>" + .asciz "fatfs::io::Write::write_all" + .asciz "fatfs::file::File::set_first_cluster" + .asciz "fatfs::file::File::abs_pos" + .asciz "fatfs::file::File::truncate" + .asciz " as fatfs::io::Read>::read" + .asciz " as fatfs::io::Seek>::seek" + .asciz " as fatfs::io::Write>::write" + .asciz " as core::clone::Clone>::clone" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz " as core::ops::drop::Drop>::drop" + .asciz " as vfscore::file::VfsFile>::poll" + .asciz " as vfscore::file::VfsFile>::flush" + .asciz " as vfscore::file::VfsFile>::fsync" + .asciz " as vfscore::file::VfsFile>::ioctl" + .asciz " as vfscore::file::VfsFile>::read_at" + .asciz " as vfscore::file::VfsFile>::write_at" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::superblock::VfsSuperBlock>::super_type" + .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" + .asciz " as vfscore::file::VfsFile>::poll" + .asciz " as vfscore::file::VfsFile>::read_at" + .asciz " as vfscore::file::VfsFile>::write_at" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz "::read_at" + .asciz "::read_at" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ops::function::impls:: for &mut F>::call_mut" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz "spin::once::Once::try_call_once" + .asciz "spin::once::Once::try_call_once" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "fatfs::dir_entry::DirEntryData::deserialize" + .asciz "fatfs::dir_entry::DirEntryEditor::flush" + .asciz "fatfs::dir_entry::DirLfnEntryData::serialize" + .asciz "fatfs::dir_entry::DirFileEntryData::serialize" + .asciz "fatfs::dir_entry::DirEntry::eq_name" + .asciz "fatfs::dir_entry::DirEntry::file_name" + .asciz "::read_u16_le" + .asciz "::read_u32_le" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>" + .asciz "fatfs::io::Read::read_exact" + .asciz "fatfs::io::Write::write_all" + .asciz "fatfs::dir::Dir::create_dir" + .asciz "fatfs::dir::Dir::find_entry" + .asciz "fatfs::dir::Dir::create_file" + .asciz "fatfs::dir::Dir::write_entry" + .asciz "fatfs::dir::Dir::rename_internal" + .asciz "fatfs::dir::Dir::create_sfn_entry" + .asciz "fatfs::dir::Dir::remove" + .asciz "fatfs::dir::Dir::rename" + .asciz "fatfs::dir::Dir::open_dir" + .asciz "fatfs::dir::Dir::open_file" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "::read_u16_le" + .asciz "::read_u32_le" + .asciz "::read_u8" + .asciz "core::ptr::drop_in_place<&()>" + .asciz "fatfs::boot_sector::BootSector::deserialize" + .asciz "fatfs::boot_sector::BootSector::validate" + .asciz "fatfs::boot_sector::BiosParameterBlock::validate_total_sectors" + .asciz "fatfs::boot_sector::BiosParameterBlock::validate_total_clusters" + .asciz "fatfs::boot_sector::BiosParameterBlock::validate_sectors_per_fat" + .asciz "fatfs::io::Read::read_exact" + .asciz "fatfs::io::Write::write_all" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz " as core::fmt::Debug>::fmt" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place<&fatfs::error::Error<()>>" + .asciz "fat_vfs::inode::dir::FatFsDirInode::delete_file" + .asciz "fat_vfs::inode::file::FatFsFileInode::new" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::flush" + .asciz "vfscore::file::VfsFile::read_at" + .asciz "vfscore::file::VfsFile::readdir" + .asciz "vfscore::file::VfsFile::write_at" + .asciz " as vfscore::file::VfsFile>::ioctl" + .asciz " as vfscore::file::VfsFile>::readdir" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::rmdir" + .asciz " as vfscore::inode::VfsInode>::create" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::unlink" + .asciz " as vfscore::inode::VfsInode>::symlink" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz " as vfscore::file::VfsFile>::flush" + .asciz " as vfscore::file::VfsFile>::read_at" + .asciz " as vfscore::file::VfsFile>::write_at" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::rmdir" + .asciz " as vfscore::inode::VfsInode>::create" + .asciz " as vfscore::inode::VfsInode>::lookup" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz "::type_id" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::as_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "::into_any" + .asciz "core::fmt::Write::write_char" + .asciz "core::fmt::Write::write_fmt" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place>" + .asciz " as vfscore::fstype::VfsFsType>::fs_flag" + .asciz " as vfscore::fstype::VfsFsType>::fs_name" + .asciz " as vfscore::fstype::VfsFsType>::mount" + .asciz " as vfscore::fstype::VfsFsType>::fs_name" + .asciz " as vfscore::fstype::VfsFsType>::kill_sb" + .asciz " as vfscore::fstype::VfsFsType>::fs_flag" + .asciz " as vfscore::fstype::VfsFsType>::fs_name" + .asciz "vfscore::file::VfsFile::poll" + .asciz "vfscore::file::VfsFile::flush" + .asciz "vfscore::file::VfsFile::ioctl" + .asciz "vfscore::file::VfsFile::read_at" + .asciz "vfscore::file::VfsFile::write_at" + .asciz ">::extend" + .asciz " as vfscore::inode::VfsInode>::inode_type" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::truncate" + .asciz "vfs::ram::init_ramfs" + .asciz "vfs::init_filesystem" + .asciz "::write_str" + .asciz "::type_id" + .asciz "::type_id" + .asciz "::type_id" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "::as_any_mut" + .asciz "::into_any_rc" + .asciz "::as_any" + .asciz "::into_any" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::ptr::drop_in_place>" + .asciz "core::ptr::drop_in_place>>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "alloc::vec::Vec::remove" + .asciz "alloc::string::String::push" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::link" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz "vfscore::inode::VfsInode::rename_to" + .asciz " as vfscore::superblock::VfsSuperBlock>::super_type" + .asciz " as vfscore::superblock::VfsSuperBlock>::sync_fs" + .asciz " as alloc::vec::spec_from_iter::SpecFromIter>::from_iter" + .asciz " as alloc::vec::spec_from_iter::SpecFromIter>::from_iter" + .asciz " as vfscore::inode::VfsInode>::list_xattr" + .asciz " as vfscore::inode::VfsInode>::update_time" + .asciz " as vfscore::inode::VfsInode>::get_super_block" + .asciz " as vfscore::inode::VfsInode>::link" + .asciz " as vfscore::inode::VfsInode>::get_attr" + .asciz " as vfscore::inode::VfsInode>::readlink" + .asciz " as vfscore::inode::VfsInode>::set_attr" + .asciz " as vfscore::inode::VfsInode>::node_perm" + .asciz " as vfscore::inode::VfsInode>::rename_to" + .asciz "::fmt" + .asciz "vfs::kfile::KernelFile::new" + .asciz "::read" + .asciz "::write" + .asciz "::read_at" + .asciz "::write_at" + .asciz "::flush" + .asciz "::fsync" + .asciz "::seek" + .asciz "::get_attr" + .asciz "::ioctl" + .asciz "::set_open_flag" + .asciz "::get_open_flag" + .asciz "::dentry" + .asciz "::inode" + .asciz "::readdir" + .asciz "::truncate" + .asciz "::is_readable" + .asciz "::is_writable" + .asciz "::is_append" + .asciz "::poll" + .asciz "::drop" + .asciz "vfs::proc::filesystem::SystemSupportFS::serialize" + .asciz "::read_at" + .asciz "::get_attr" + .asciz "::read_at" + .asciz "::get_attr" + .asciz "device_interface::LowBlockDevice::flush" + .asciz "device_interface::LowBlockDevice::flush" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "::can_receive" + .asciz "::can_transmit" + .asciz "::rx_queue_size" + .asciz "::recycle_tx_buffers" + .asciz "::now" + .asciz "::have_space_to_put" + .asciz "::resolution" + .asciz "::update_cursor" + .asciz "::get_framebuffer" + .asciz "::capacity" + .asciz "::capacity" + .asciz "devices::init_device" + .asciz "devices::init_virtio_mmio" + .asciz "devices::init_block_device::sleep" + .asciz "devices::init_input_device" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "::read_at" + .asciz "::write_at" + .asciz "::poll" + .asciz "::ioctl" + .asciz "fdt::node::all_nodes::closure" + .asciz " as core::ops::drop::Drop>::drop" + .asciz "::write_at" + .asciz "::flush" + .asciz "::fsync" + .asciz "::probe_virtio" + .asciz "::probe_common" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "::type_id" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::panicking::assert_failed" + .asciz "<(U,T) as core::fmt::Debug>::fmt" + .asciz "::read_at" + .asciz "::write_at" + .asciz "::poll" + .asciz "::ioctl" + .asciz "::get_attr" + .asciz "::read_at" + .asciz "::poll" + .asciz "::read_at" + .asciz "::write_at" + .asciz "::ioctl" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "interrupt::ext_interrupt::external_interrupt_handler" + .asciz "interrupt::record::write_irq_info" + .asciz "interrupt::record::interrupts_info" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz " as core::iter::traits::iterator::Iterator>::next" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "interrupt::init_plic" + .asciz "interrupt::register_device_to_plic" + .asciz "plic::write" + .asciz "plic::read" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "alloc::collections::vec_deque::VecDeque::grow" + .asciz "alloc::collections::vec_deque::VecDeque::grow" + .asciz "alloc::collections::vec_deque::VecDeque::grow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz " as core::fmt::Debug>::fmt" + .asciz "::dma_dealloc" + .asciz "::_init" + .asciz "::_put" + .asciz "::_read" + .asciz "virtio_drivers::device::blk::VirtIOBlk::new" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "virtio_drivers::queue::VirtQueue::add_notify_wait_pop" + .asciz "virtio_drivers::queue::VirtQueue::add_notify_wait_pop" + .asciz "virtio_drivers::queue::VirtQueue::add" + .asciz "virtio_drivers::queue::VirtQueue::new" + .asciz "virtio_drivers::queue::VirtQueue::new" + .asciz "virtio_drivers::queue::VirtQueue::new" + .asciz "virtio_drivers::queue::VirtQueue::pop_used" + .asciz "virtio_drivers::transport::Transport::begin_init" + .asciz "virtio_drivers::transport::Transport::begin_init" + .asciz "virtio_drivers::transport::Transport::begin_init" + .asciz "virtio_drivers::device::input::VirtIOInput::pop_pending_event" + .asciz "virtio_drivers::device::input::VirtIOInput::new" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz "core::ptr::drop_in_place" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed" + .asciz "::yield_now" + .asciz "drivers::uart::Uart::new" + .asciz "::put" + .asciz "::get" + .asciz "::put_bytes" + .asciz "::have_data_to_get" + .asciz "::hand_irq" + .asciz "drivers::register_task_func" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "drivers::input::VirtIOInputDriver::from_addr" + .asciz "::is_empty" + .asciz "::read_event_with_block" + .asciz "::read_event_without_block" + .asciz "::hand_irq" + .asciz "::_init" + .asciz "::_put" + .asciz "::_read" + .asciz "core::ptr::drop_in_place<&usize>" + .asciz "::drop" + .asciz "drivers::block_device::GenericBlockDevice::new" + .asciz "::read" + .asciz "::write" + .asciz "::size" + .asciz "drivers::block_device::VirtIOBlkWrapper::from_mmio" + .asciz "::read_block" + .asciz "::write_block" + .asciz "::read_block" + .asciz "::write_block" + .asciz "lru::LruCache::new" + .asciz "lru::LruCache::capturing_put" + .asciz "lru::LruCache::get" + .asciz "lru::LruCache::get_mut" + .asciz "hashbrown::raw::RawTable::reserve_rehash" + .asciz "hashbrown::raw::RawTableInner::fallible_with_capacity" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "drivers::gpu::VirtIOGpuWrapper::new" + .asciz "::hand_irq" + .asciz "::flush" + .asciz "drivers::rtc::GoldFishRtc::read_time_string" + .asciz "::hand_irq" + .asciz "::read_time" + .asciz "virtio_drivers::device::gpu::VirtIOGpu::get_display_info" + .asciz "virtio_drivers::device::gpu::VirtIOGpu::setup_framebuffer" + .asciz "virtio_drivers::device::gpu::VirtIOGpu::new" + .asciz "virtio_drivers::device::gpu::VirtIOGpu::flush" + .asciz "::read_time" + .asciz "::clear_irq" + .asciz "::read_alarm" + .asciz "::set_alarm" + .asciz "::fmt" + .asciz ">::from" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "time::date_time::DateTime::checked_to_offset" + .asciz "time::date::Date::from_julian_day_unchecked" + .asciz "time::date::Date::month_day" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "time::offset_date_time::OffsetDateTime::to_offset" + .asciz "time::offset_date_time::OffsetDateTime::from_unix_timestamp_nanos" + .asciz "time::offset_date_time::OffsetDateTime::month" + .asciz "time::offset_date_time::OffsetDateTime::day" + .asciz "time::expect_failed" + .asciz "time::expect_failed::panic_cold_display" + .asciz "::type_id" + .asciz "core::ptr::drop_in_place" + .asciz "alloc::collections::vec_deque::VecDeque::grow" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "::mac_address" + .asciz "::recycle_rx_buffer" + .asciz "::transmit" + .asciz "::receive" + .asciz "::alloc_tx_buffer" + .asciz "::packet_mut" + .asciz "::packet_len" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "netcore::tcp::TcpSocket::connect" + .asciz "netcore::tcp::TcpSocket::bind" + .asciz "netcore::tcp::TcpSocket::listen" + .asciz "netcore::tcp::TcpSocket::accept" + .asciz "netcore::tcp::TcpSocket::shutdown" + .asciz "netcore::tcp::TcpSocket::recv" + .asciz "netcore::tcp::TcpSocket::send" + .asciz "netcore::tcp::TcpSocket::poll" + .asciz "netcore::tcp::TcpSocket::poll_connect" + .asciz "::drop" + .asciz "netcore::tcp::get_ephemeral_port" + .asciz "core::ptr::drop_in_place" + .asciz "::poll" + .asciz "netcore::interface::SocketSetWrapper::new_udp_socket" + .asciz "netcore::interface::SocketSetWrapper::with_socket" + .asciz "netcore::interface::SocketSetWrapper::with_socket" + .asciz "netcore::interface::SocketSetWrapper::with_socket" + .asciz "netcore::interface::SocketSetWrapper::with_socket" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" + .asciz "netcore::interface::SocketSetWrapper::remove" + .asciz "core::ptr::drop_in_place" + .asciz "::receive" + .asciz "::consume" + .asciz "::preprocess" + .asciz "::consume" + .asciz "::consume" + .asciz "::consume" + .asciz "netcore::device::NetDeviceWrapper::bench_transmit_bandwidth" + .asciz "smoltcp::socket::tcp::Socket::new" + .asciz "smoltcp::socket::tcp::Socket::connect" + .asciz "smoltcp::socket::tcp::Socket::dispatch" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "core::ptr::drop_in_place>" + .asciz "netcore::udp::UdpSocket::new" + .asciz "netcore::udp::UdpSocket::local_addr" + .asciz "netcore::udp::UdpSocket::peer_addr" + .asciz "netcore::udp::UdpSocket::bind" + .asciz "netcore::udp::UdpSocket::send_to" + .asciz "netcore::udp::UdpSocket::recv_from" + .asciz "netcore::udp::UdpSocket::connect" + .asciz "netcore::udp::UdpSocket::send" + .asciz "netcore::udp::UdpSocket::shutdown" + .asciz "netcore::udp::UdpSocket::poll" + .asciz "netcore::udp::UdpSocket::send_impl" + .asciz "::drop" + .asciz "core::ptr::drop_in_place>>" + .asciz "::default" + .asciz "netcore::listen_table::ListenTable::new" + .asciz "netcore::listen_table::ListenTable::listen" + .asciz "netcore::listen_table::ListenTable::unlisten" + .asciz "netcore::listen_table::ListenTable::can_accept" + .asciz "netcore::listen_table::ListenTable::accept" + .asciz "netcore::listen_table::ListenTable::incoming_tcp_packet" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "core::ptr::drop_in_place" + .asciz "smoltcp::iface::interface::InterfaceInner::dispatch_ip" + .asciz "smoltcp::iface::interface::Interface::poll" + .asciz "smoltcp::socket::dns::Socket::dispatch" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place<&bool>" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "smoltcp::wire::ipv4::Repr::emit" + .asciz "smoltcp::wire::ipv4::Repr::parse" + .asciz "::fmt" + .asciz "::fmt" + .asciz " as core::iter::traits::iterator::Iterator>::try_fold" + .asciz ">::from" + .asciz "smoltcp::wire::icmpv4::Repr::parse" + .asciz "smoltcp::socket::udp::Socket::send_slice" + .asciz "smoltcp::iface::socket_set::SocketSet::add" + .asciz "smoltcp::iface::socket_set::SocketSet::add" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "<&mut T as core::fmt::Display>::fmt" + .asciz "smoltcp::wire::arp::Repr::emit" + .asciz "smoltcp::wire::dns::Repr::emit" + .asciz "smoltcp::storage::packet_buffer::PacketBuffer::enqueue" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&u16>" + .asciz "core::panicking::assert_failed" + .asciz "core::panicking::assert_failed" + .asciz "alloc::collections::vec_deque::VecDeque::grow" + .asciz "smoltcp::iface::socket_meta::Meta::egress_permitted" + .asciz "netcore::interface::SocketSetWrapper::new" + .asciz "netcore::init_net" + .asciz "netcore::poll_interfaces" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "::fmt" + .asciz "smoltcp::socket::tcp::RttEstimator::retransmission_timeout" + .asciz "smoltcp::socket::tcp::RttEstimator::on_send" + .asciz "smoltcp::socket::tcp::RttEstimator::on_retransmit" + .asciz "smoltcp::socket::tcp::Socket::reset" + .asciz "smoltcp::socket::tcp::Socket::close" + .asciz "smoltcp::socket::tcp::Socket::send_slice" + .asciz "smoltcp::socket::tcp::Socket::recv_slice" + .asciz "smoltcp::socket::tcp::Socket::set_state" + .asciz "smoltcp::socket::tcp::Socket::rst_reply" + .asciz "smoltcp::socket::tcp::Socket::ack_reply" + .asciz "smoltcp::socket::tcp::Socket::accepts" + .asciz "smoltcp::socket::tcp::Socket::process" + .asciz "smoltcp::socket::tcp::Socket::seq_to_transmit" + .asciz "smoltcp::socket::tcp::Socket::ack_to_transmit" + .asciz "smoltcp::socket::tcp::Socket::window_to_update" + .asciz "::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "smoltcp::socket::dns::DnsQuery::set_state" + .asciz "smoltcp::socket::dns::Socket::process" + .asciz "smoltcp::socket::dns::eq_names" + .asciz "smoltcp::socket::dns::copy_name" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz " as core::iter::traits::iterator::Iterator>::fold" + .asciz "::fmt" + .asciz ">::add" + .asciz ">::sub" + .asciz "::sub" + .asciz "smoltcp::wire::tcp::TcpOption::parse" + .asciz "smoltcp::wire::tcp::TcpOption::emit" + .asciz "smoltcp::wire::tcp::Repr::parse" + .asciz "smoltcp::wire::tcp::Repr::buffer_len" + .asciz "smoltcp::wire::tcp::Repr::emit" + .asciz "::fmt" + .asciz "::fmt" + .asciz "smoltcp::iface::interface::ethernet::::process_ethernet" + .asciz "smoltcp::iface::interface::ipv4::::process_ipv4" + .asciz "smoltcp::iface::interface::ipv4::::icmpv4_reply" + .asciz "smoltcp::iface::interface::InterfaceInner::get_source_address" + .asciz "smoltcp::iface::interface::InterfaceInner::get_source_address_ipv4" + .asciz "smoltcp::iface::interface::InterfaceInner::check_ip_addrs" + .asciz "smoltcp::iface::interface::InterfaceInner::process_ip" + .asciz "smoltcp::iface::interface::InterfaceInner::is_broadcast" + .asciz "smoltcp::iface::interface::InterfaceInner::process_udp" + .asciz "smoltcp::iface::interface::InterfaceInner::route" + .asciz "smoltcp::iface::interface::InterfaceInner::has_neighbor" + .asciz "smoltcp::iface::interface::InterfaceInner::flush_cache" + .asciz "smoltcp::wire::udp::Packet<&T>::payload" + .asciz "::fmt" + .asciz "core::ptr::drop_in_place<&smoltcp::storage::packet_buffer::PacketMetadata>" + .asciz "core::ptr::drop_in_place<&smoltcp::storage::packet_buffer::PacketMetadata>" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz "core::ptr::drop_in_place<&alloc::vec::Vec>" + .asciz "core::ptr::drop_in_place<&smoltcp::wire::ip::Address>" + .asciz "core::ptr::drop_in_place<&smoltcp::iface::route::Route>" + .asciz "core::ptr::drop_in_place<&smoltcp::iface::neighbor::Neighbor>" + .asciz "core::ptr::drop_in_place<&smoltcp::storage::assembler::Contig>" + .asciz "core::ptr::drop_in_place<&smoltcp::iface::socket_set::SocketStorage>" + .asciz "core::ptr::drop_in_place<&core::option::Option<(u32,u32)>>" + .asciz "core::ptr::drop_in_place<&core::option::Option>" + .asciz "core::ptr::drop_in_place<&smoltcp::storage::packet_buffer::PacketMetadata<()>>" + .asciz "smoltcp::wire::icmpv4::Repr::parse" + .asciz "smoltcp::wire::icmpv4::Repr::emit" + .asciz ">::from" + .asciz "smoltcp::iface::neighbor::Cache::fill" + .asciz "smoltcp::iface::neighbor::Cache::lookup" + .asciz "smoltcp::socket::udp::Socket::recv_slice" + .asciz "smoltcp::socket::udp::Socket::process" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "smoltcp::iface::route::Routes::add_default_ipv4_route" + .asciz "smoltcp::iface::route::Routes::lookup" + .asciz "smoltcp::wire::ip::Version::of_packet" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "smoltcp::wire::ip::Cidr::new" + .asciz "::fmt" + .asciz "::fmt" + .asciz "smoltcp::wire::HardwareAddress::ethernet_or_panic" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "smoltcp::iface::ip_packet::IpPacket::emit_payload" + .asciz "smoltcp::storage::packet_buffer::PacketBuffer::enqueue" + .asciz "smoltcp::storage::packet_buffer::PacketBuffer::enqueue" + .asciz "smoltcp::storage::packet_buffer::PacketBuffer::enqueue" + .asciz "smoltcp::storage::packet_buffer::PacketBuffer::dequeue" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::enqueue_slice" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_slice" + .asciz "smoltcp::storage::ring_buffer::RingBuffer::write_unallocated" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "smoltcp::wire::ipv4::Address::from_bytes" + .asciz "::fmt" + .asciz "smoltcp::wire::ipv4::Repr::parse" + .asciz "smoltcp::wire::ipv4::Repr::emit" + .asciz ">::from" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "::fmt" + .asciz "smoltcp::wire::arp::Repr::parse" + .asciz "smoltcp::wire::ethernet::Address::from_bytes" + .asciz "::fmt" + .asciz "smoltcp::iface::socket_meta::Meta::neighbor_missing" + .asciz "smoltcp::socket::icmp::Socket::accepts" + .asciz "smoltcp::socket::icmp::Socket::process" + .asciz "smoltcp::wire::ip::checksum::data" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place<&&mut alloc::collections::vec_deque::VecDeque>>" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "smoltcp::wire::dns::Packet::rcode" + .asciz "smoltcp::wire::dns::Question::parse" + .asciz "smoltcp::wire::dns::Question::emit" + .asciz "smoltcp::wire::dns::Record::parse" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "smoltcp::storage::assembler::Assembler::add" + .asciz "smoltcp::wire::udp::Packet::verify_checksum" + .asciz "smoltcp::wire::udp::Repr::emit" + .asciz "::fmt" + .asciz "smoltcp::iface::socket_set::SocketSet::add::put" + .asciz "smoltcp::iface::socket_set::SocketSet::remove" + .asciz "smoltcp::iface::socket_set::SocketSet::items" + .asciz "smoltcp::iface::socket_set::SocketSet::items_mut" + .asciz "smoltcp::socket::raw::Socket::process" + .asciz "::fmt" + .asciz "<() as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place<()>" + .asciz "visionfive2_sd::send_cmd" + .asciz "visionfive2_sd::Vf2SdDriver::read_block" + .asciz "visionfive2_sd::Vf2SdDriver::write_block" + .asciz "core::ptr::drop_in_place" + .asciz ">::from" + .asciz ">::try_from" + .asciz ">::try_from" + .asciz ">::try_from" + .asciz ">::try_from" + .asciz ">::try_from" + .asciz ">::try_from" + .asciz ">::try_from" + .asciz ">::try_from" + .asciz ">::try_from" + .asciz ">::try_from" + .asciz ">::try_from" + .asciz ">::try_from" + .asciz ">::try_from" + .asciz "::fmt" + .asciz "::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<() as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz "core::ptr::drop_in_place<()>" + .asciz "core::panicking::assert_failed" + .asciz "visionfive2_sd::utils::wait_ms" + .asciz "visionfive2_sd::utils::wait_ms" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "bit_struct::types::u5::new" + .asciz "bit_struct::types::u6::new" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "<&mut T as core::fmt::Debug>::fmt" + .asciz "mem::frame::init_frame_allocator" .asciz "alloc_frames" .asciz "free_frames" - .asciz "kernel::memory::frame::frame_alloc" - .asciz "kernel::memory::frame::frames_alloc" - .asciz "kernel::memory::frame::frame_alloc_contiguous" - .asciz "kernel::memory::manager::FrameRefManager::dec_ref" - .asciz "kernel::device::input::sys_event_get" - .asciz "::fmt" - .asciz "core::ptr::drop_in_place<&u32>" - .asciz "tracer::compiler::InstructionSp::try_new" - .asciz "tracer::compiler::check_sd_ra" - .asciz "tracer::compiler::is_caddi" - .asciz "tracer::compiler::is_caddi16sp" - .asciz "::fmt" + .asciz "::drop" + .asciz "mem::frame::alloc_frame_trackers" + .asciz "::alloc_frame" + .asciz "::dealloc_frame" + .asciz "::alloc_contiguous_frames" + .asciz "::alloc" + .asciz "::dealloc" + .asciz "mem::heap::HeapAllocator::init" + .asciz "core::fmt::num::::fmt" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz "mem::manager::FrameRefManager::add_ref" + .asciz "mem::manager::FrameRefManager::dec_ref" + .asciz "core::fmt::num::::fmt" + .asciz "core::ops::function::FnOnce::call_once" + .asciz "core::ptr::drop_in_place" + .asciz "mem::vmm::build_kernel_address_space" + .asciz "mem::vmm::kernel_satp" + .asciz "mem::vmm::query_kernel_space" + .asciz "page_table::table::bits64::PageTable64::map_region" .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "tracer::utils::read_instruction" - .asciz "tracer::utils::read_instruction_short" - .asciz "tracer::utils::read_value" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "core::ptr::drop_in_place<&usize>" - .asciz "::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::ptr::drop_in_place<&&str>" - .asciz "core::ptr::drop_in_place<&xmas_elf::program::Type>" - .asciz "core::ptr::drop_in_place<&xmas_elf::sections::ShType>" - .asciz "core::ptr::drop_in_place<&xmas_elf::dynamic::Tag>" - .asciz "core::ptr::drop_in_place<&xmas_elf::dynamic::Tag>" - .asciz "core::ptr::drop_in_place<&xmas_elf::sections::CompressionType>" .asciz "core::panicking::assert_failed" - .asciz "xmas_elf::ElfFile::new" - .asciz "xmas_elf::ElfFile::get_shstr" - .asciz "xmas_elf::ElfFile::get_dyn_string" - .asciz "xmas_elf::ElfFile::find_section_by_name" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::ptr::drop_in_place<&str>" - .asciz "xmas_elf::sections::parse_section_header" - .asciz "xmas_elf::sections::SectionHeader::get_data" - .asciz "xmas_elf::sections::SectionHeader::raw_data" - .asciz "::fmt" - .asciz "xmas_elf::program::parse_program_header" - .asciz "::next" - .asciz "xmas_elf::program::ProgramHeader::get_type" - .asciz "xmas_elf::program::ProgramHeader::get_data" - .asciz "xmas_elf::program::ProgramHeader32::get_data" - .asciz "xmas_elf::program::ProgramHeader32::raw_data" - .asciz "xmas_elf::program::ProgramHeader64::get_data" - .asciz "xmas_elf::program::ProgramHeader64::raw_data" - .asciz "::get_name" - .asciz "core::ptr::drop_in_place<&u8>" - .asciz "zero::read_str" + .asciz "talc::alloc_error" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::insert" + .asciz "alloc::collections::btree::map::BTreeMap::remove" + .asciz "mem::init_memory_system" + .asciz "__rust_alloc" + .asciz "__rust_dealloc" + .asciz "__rust_realloc" + .asciz "__rust_alloc_zeroed" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::Handle,alloc::collections::btree::node::marker::Edge>::insert_recursing" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_left" + .asciz "alloc::collections::btree::node::BalancingContext::bulk_steal_right" + .asciz "alloc::collections::btree::node::BalancingContext::merge_tracking_child_edge" + .asciz "alloc::collections::btree::node::BalancingContext::do_merge" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_leaf_kv" + .asciz "alloc::collections::btree::remove::,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz " as pager::PageAllocatorExt>::alloc_pages" .asciz "talc::Talc::malloc" .asciz "talc::Talc::free" .asciz "talc::Talc::init" .asciz "talc::talck::Talck::talc" .asciz "::alloc" .asciz "::dealloc" - .asciz "plic::write" - .asciz "plic::read" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&usize>" + .asciz "::fmt" .asciz "::fmt" .asciz "::fmt" .asciz "::fmt" @@ -8862,64 +9959,6 @@ symbol_name: .asciz "::fmt" .asciz "::fmt" .asciz "::fmt" - .asciz ">::from" - .asciz "::fmt" - .asciz "core::ptr::drop_in_place" - .asciz "::write" - .asciz "::flush" - .asciz "::read" - .asciz "::seek" - .asciz "fatfs::dir::split_path" - .asciz "fatfs::dir::lfn_checksum" - .asciz "fatfs::dir::LongNameBuilder::into_buf" - .asciz "fatfs::dir::LongNameBuilder::process" - .asciz "fatfs::dir::LongNameBuilder::validate_chksum" - .asciz "fatfs::dir::LfnEntriesGenerator::new" - .asciz "::next" - .asciz "::size_hint" - .asciz "fatfs::dir::ShortNameGenerator::new" - .asciz "fatfs::dir::ShortNameGenerator::copy_short_name_part" - .asciz "fatfs::dir::ShortNameGenerator::add_existing" - .asciz "fatfs::dir::ShortNameGenerator::generate" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::ptr::drop_in_place" - .asciz "core::array::::fmt" - .asciz "core::array::::fmt" - .asciz "core::array::::fmt" - .asciz "alloc::raw_vec::finish_grow" - .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" - .asciz "fatfs::fs::FsInfoSector::validate_and_fix" - .asciz "::fmt" - .asciz "core::str::::trim_matches" - .asciz "fatfs::boot_sector::BiosParameterBlock::root_dir_sectors" - .asciz "fatfs::boot_sector::BiosParameterBlock::first_data_sector" - .asciz "fatfs::boot_sector::BiosParameterBlock::total_clusters" - .asciz "fatfs::boot_sector::BiosParameterBlock::clusters_from_bytes" - .asciz "::default" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "fatfs::dir_entry::ShortName::new" - .asciz "fatfs::dir_entry::ShortName::as_bytes" - .asciz "fatfs::dir_entry::DirFileEntryData::new" - .asciz "fatfs::dir_entry::DirFileEntryData::renamed" - .asciz "fatfs::dir_entry::DirFileEntryData::lowercase_name" - .asciz "fatfs::dir_entry::DirEntryEditor::set_modified" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" .asciz "core::ptr::drop_in_place>" .asciz "virtio_drivers::transport::mmio::MmioTransport::new" .asciz "virtio_drivers::transport::mmio::MmioTransport::vendor_id" @@ -8972,153 +10011,62 @@ symbol_name: .asciz "::fmt" .asciz "::fmt" .asciz "::fmt" - .asciz "::type_id" - .asciz "core::ptr::drop_in_place" - .asciz "alloc::collections::vec_deque::VecDeque::grow" - .asciz "alloc::raw_vec::finish_grow" - .asciz "alloc::raw_vec::RawVec::reserve_for_push" - .asciz "::mac_address" - .asciz "::recycle_rx_buffer" - .asciz "::transmit" - .asciz "::receive" - .asciz "::alloc_tx_buffer" - .asciz "::packet_mut" - .asciz "::packet_len" - .asciz "::read_time" - .asciz "::set_time" - .asciz "::enable_irq" - .asciz "::disable_irq" - .asciz "::clear_irq" - .asciz "::read_alarm" - .asciz "::set_alarm" - .asciz "::clear_alarm" - .asciz "::alarm_status" - .asciz "::is_irq_enabled" - .asciz "::fmt" - .asciz ">::from" - .asciz "core::fmt::num::::fmt" - .asciz "core::ptr::drop_in_place" - .asciz "::fmt" - .asciz "time::date_time::DateTime::checked_to_offset" - .asciz "time::date::Date::from_julian_day_unchecked" - .asciz "time::date::Date::month_day" + .asciz "core::ptr::drop_in_place" + .asciz "::write" + .asciz "::flush" + .asciz "::read" + .asciz "::seek" + .asciz "fatfs::dir::split_path" + .asciz "fatfs::dir::lfn_checksum" + .asciz "fatfs::dir::LongNameBuilder::into_buf" + .asciz "fatfs::dir::LongNameBuilder::process" + .asciz "fatfs::dir::LongNameBuilder::validate_chksum" + .asciz "fatfs::dir::LfnEntriesGenerator::new" + .asciz "::next" + .asciz "::size_hint" + .asciz "fatfs::dir::ShortNameGenerator::new" + .asciz "fatfs::dir::ShortNameGenerator::copy_short_name_part" + .asciz "fatfs::dir::ShortNameGenerator::add_existing" + .asciz "fatfs::dir::ShortNameGenerator::generate" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Display>::fmt" - .asciz "time::offset_date_time::OffsetDateTime::to_offset" - .asciz "time::offset_date_time::OffsetDateTime::from_unix_timestamp_nanos" - .asciz "time::offset_date_time::OffsetDateTime::month" - .asciz "time::offset_date_time::OffsetDateTime::day" - .asciz "time::expect_failed" - .asciz "time::expect_failed::panic_cold_display" - .asciz "core::fmt::num::::fmt" - .asciz "netcore::tcp::TcpSocket::connect" - .asciz "netcore::tcp::TcpSocket::bind" - .asciz "netcore::tcp::TcpSocket::listen" - .asciz "netcore::tcp::TcpSocket::accept" - .asciz "netcore::tcp::TcpSocket::shutdown" - .asciz "netcore::tcp::TcpSocket::recv" - .asciz "netcore::tcp::TcpSocket::send" - .asciz "netcore::tcp::TcpSocket::poll" - .asciz "netcore::tcp::TcpSocket::poll_connect" - .asciz "::drop" - .asciz "netcore::tcp::get_ephemeral_port" - .asciz "core::ptr::drop_in_place" - .asciz "::poll" - .asciz "netcore::interface::SocketSetWrapper::new_udp_socket" - .asciz "netcore::interface::SocketSetWrapper::with_socket" - .asciz "netcore::interface::SocketSetWrapper::with_socket" - .asciz "netcore::interface::SocketSetWrapper::with_socket" - .asciz "netcore::interface::SocketSetWrapper::with_socket" - .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" - .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" - .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" - .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" - .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" - .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" - .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" - .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" - .asciz "netcore::interface::SocketSetWrapper::with_socket_mut" - .asciz "netcore::interface::SocketSetWrapper::remove" - .asciz "core::ptr::drop_in_place" - .asciz "::receive" - .asciz "::consume" - .asciz "::preprocess" - .asciz "::consume" - .asciz "::consume" - .asciz "::consume" - .asciz "netcore::device::NetDeviceWrapper::bench_transmit_bandwidth" - .asciz "smoltcp::socket::tcp::Socket::new" - .asciz "smoltcp::socket::tcp::Socket::connect" - .asciz "smoltcp::socket::tcp::Socket::dispatch" - .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" - .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" - .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" - .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" - .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" - .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" - .asciz "core::ptr::drop_in_place>" - .asciz "netcore::udp::UdpSocket::new" - .asciz "netcore::udp::UdpSocket::local_addr" - .asciz "netcore::udp::UdpSocket::peer_addr" - .asciz "netcore::udp::UdpSocket::bind" - .asciz "netcore::udp::UdpSocket::send_to" - .asciz "netcore::udp::UdpSocket::recv_from" - .asciz "netcore::udp::UdpSocket::connect" - .asciz "netcore::udp::UdpSocket::send" - .asciz "netcore::udp::UdpSocket::shutdown" - .asciz "netcore::udp::UdpSocket::poll" - .asciz "netcore::udp::UdpSocket::send_impl" - .asciz "::drop" - .asciz "core::ptr::drop_in_place>>" - .asciz "::default" - .asciz "netcore::listen_table::ListenTable::new" - .asciz "netcore::listen_table::ListenTable::listen" - .asciz "netcore::listen_table::ListenTable::unlisten" - .asciz "netcore::listen_table::ListenTable::can_accept" - .asciz "netcore::listen_table::ListenTable::accept" - .asciz "netcore::listen_table::ListenTable::incoming_tcp_packet" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "spin::once::Once::try_call_once_slow" - .asciz "core::ptr::drop_in_place" - .asciz "smoltcp::iface::interface::InterfaceInner::dispatch_ip" - .asciz "smoltcp::iface::interface::Interface::poll" - .asciz "smoltcp::socket::dns::Socket::dispatch" - .asciz "::fmt" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Display>::fmt" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place<&bool>" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "smoltcp::wire::ipv4::Repr::emit" - .asciz "smoltcp::wire::ipv4::Repr::parse" - .asciz "::fmt" - .asciz "::fmt" - .asciz " as core::iter::traits::iterator::Iterator>::try_fold" - .asciz ">::from" - .asciz "smoltcp::wire::icmpv4::Repr::parse" - .asciz "smoltcp::socket::udp::Socket::send_slice" - .asciz "smoltcp::iface::socket_set::SocketSet::add" - .asciz "smoltcp::iface::socket_set::SocketSet::add" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::array::::fmt" + .asciz "core::array::::fmt" + .asciz "core::array::::fmt" .asciz "alloc::raw_vec::finish_grow" - .asciz "alloc::raw_vec::RawVec::reserve_for_push" - .asciz "alloc::raw_vec::RawVec::reserve_for_push" - .asciz "<&mut T as core::fmt::Display>::fmt" - .asciz "smoltcp::wire::arp::Repr::emit" - .asciz "smoltcp::wire::dns::Repr::emit" - .asciz "smoltcp::storage::packet_buffer::PacketBuffer::enqueue" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz "fatfs::fs::FsInfoSector::validate_and_fix" + .asciz "::fmt" + .asciz "core::str::::trim_matches" + .asciz "fatfs::boot_sector::BiosParameterBlock::root_dir_sectors" + .asciz "fatfs::boot_sector::BiosParameterBlock::first_data_sector" + .asciz "fatfs::boot_sector::BiosParameterBlock::total_clusters" + .asciz "fatfs::boot_sector::BiosParameterBlock::clusters_from_bytes" + .asciz "::default" .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::ptr::drop_in_place<&u16>" - .asciz "core::panicking::assert_failed" - .asciz "core::panicking::assert_failed" - .asciz "alloc::collections::vec_deque::VecDeque::grow" - .asciz "smoltcp::iface::socket_meta::Meta::egress_permitted" - .asciz "netcore::interface::SocketSetWrapper::new" - .asciz "netcore::init_net" - .asciz "netcore::poll_interfaces" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "fatfs::dir_entry::ShortName::new" + .asciz "fatfs::dir_entry::ShortName::as_bytes" + .asciz "fatfs::dir_entry::DirFileEntryData::new" + .asciz "fatfs::dir_entry::DirFileEntryData::renamed" + .asciz "fatfs::dir_entry::DirFileEntryData::lowercase_name" + .asciz "fatfs::dir_entry::DirEntryEditor::set_modified" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" .asciz "core::ptr::drop_in_place>>" .asciz "core::ptr::drop_in_place" .asciz "core::ptr::drop_in_place" @@ -9163,282 +10111,151 @@ symbol_name: .asciz "core::ptr::drop_in_place" .asciz "core::ptr::drop_in_place" .asciz ">::from" - .asciz "vfscore::utils::VfsInodeMode::from" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Display>::fmt" - .asciz "core::error::Error::cause" - .asciz "core::error::Error::type_id" - .asciz "alloc::raw_vec::finish_grow" - .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" - .asciz "::fmt" - .asciz "::fmt" - .asciz "core::ptr::drop_in_place<&i32>" - .asciz "core::ptr::drop_in_place<&isize>" - .asciz "core::ptr::drop_in_place" - .asciz "core::array::::fmt" - .asciz "core::error::Error::cause" - .asciz "core::error::Error::type_id" - .asciz "core::panicking::assert_failed" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "alloc::sync::Arc::drop_slow" - .asciz "::i_insert" - .asciz "vfscore::error:: for pconst::consts::LinuxErrno>::from" - .asciz "::i_mount" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "core::ptr::drop_in_place" - .asciz "pconst::consts::syscall_name" - .asciz ">::try_from" - .asciz "pconst::consts:: for isize>::from" - .asciz "::fmt" - .asciz "::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "core::ptr::drop_in_place<&u8>" - .asciz "core::ptr::drop_in_place<&i32>" - .asciz "core::ptr::drop_in_place<&isize>" - .asciz "core::ptr::drop_in_place<&usize>" - .asciz "core::ptr::drop_in_place<&core::option::Option>" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "core::ptr::drop_in_place" - .asciz "alloc::raw_vec::finish_grow" - .asciz "alloc::raw_vec::RawVec::reserve_for_push" - .asciz ">::from" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::ptr::drop_in_place<&[core::option::Option; 64]>" - .asciz "pconst::signal::SignalHandlers::clear" - .asciz "pconst::signal::SignalHandlers::get_action" - .asciz "pconst::signal::SignalHandlers::get_action_ref" - .asciz "pconst::signal::SignalHandlers::set_action" - .asciz "pconst::signal::SignalReceivers::get_one_signal" - .asciz "pconst::signal::SignalReceivers::have_signal" - .asciz "pconst::signal::SignalReceivers::have_signal_with_number" - .asciz ">>::into" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "::fmt" - .asciz "smoltcp::socket::tcp::RttEstimator::retransmission_timeout" - .asciz "smoltcp::socket::tcp::RttEstimator::on_send" - .asciz "smoltcp::socket::tcp::RttEstimator::on_retransmit" - .asciz "smoltcp::socket::tcp::Socket::reset" - .asciz "smoltcp::socket::tcp::Socket::close" - .asciz "smoltcp::socket::tcp::Socket::send_slice" - .asciz "smoltcp::socket::tcp::Socket::recv_slice" - .asciz "smoltcp::socket::tcp::Socket::set_state" - .asciz "smoltcp::socket::tcp::Socket::rst_reply" - .asciz "smoltcp::socket::tcp::Socket::ack_reply" - .asciz "smoltcp::socket::tcp::Socket::accepts" - .asciz "smoltcp::socket::tcp::Socket::process" - .asciz "smoltcp::socket::tcp::Socket::seq_to_transmit" - .asciz "smoltcp::socket::tcp::Socket::ack_to_transmit" - .asciz "smoltcp::socket::tcp::Socket::window_to_update" - .asciz "::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "smoltcp::socket::dns::DnsQuery::set_state" - .asciz "smoltcp::socket::dns::Socket::process" - .asciz "smoltcp::socket::dns::eq_names" - .asciz "smoltcp::socket::dns::copy_name" - .asciz "<&T as core::fmt::Display>::fmt" - .asciz "core::ptr::drop_in_place<&u8>" - .asciz " as core::iter::traits::iterator::Iterator>::fold" - .asciz "::fmt" - .asciz ">::add" - .asciz ">::sub" - .asciz "::sub" - .asciz "smoltcp::wire::tcp::TcpOption::parse" - .asciz "smoltcp::wire::tcp::TcpOption::emit" - .asciz "smoltcp::wire::tcp::Repr::parse" - .asciz "smoltcp::wire::tcp::Repr::buffer_len" - .asciz "smoltcp::wire::tcp::Repr::emit" - .asciz "::fmt" - .asciz "::fmt" - .asciz "smoltcp::iface::interface::ethernet::::process_ethernet" - .asciz "smoltcp::iface::interface::ipv4::::process_ipv4" - .asciz "smoltcp::iface::interface::ipv4::::icmpv4_reply" - .asciz "smoltcp::iface::interface::InterfaceInner::get_source_address" - .asciz "smoltcp::iface::interface::InterfaceInner::get_source_address_ipv4" - .asciz "smoltcp::iface::interface::InterfaceInner::check_ip_addrs" - .asciz "smoltcp::iface::interface::InterfaceInner::process_ip" - .asciz "smoltcp::iface::interface::InterfaceInner::is_broadcast" - .asciz "smoltcp::iface::interface::InterfaceInner::process_udp" - .asciz "smoltcp::iface::interface::InterfaceInner::route" - .asciz "smoltcp::iface::interface::InterfaceInner::has_neighbor" - .asciz "smoltcp::iface::interface::InterfaceInner::flush_cache" - .asciz "smoltcp::wire::udp::Packet<&T>::payload" - .asciz "::fmt" - .asciz "core::ptr::drop_in_place<&smoltcp::storage::packet_buffer::PacketMetadata>" - .asciz "core::ptr::drop_in_place<&smoltcp::storage::packet_buffer::PacketMetadata>" - .asciz "core::ptr::drop_in_place<&u8>" - .asciz "core::ptr::drop_in_place<&alloc::vec::Vec>" - .asciz "core::ptr::drop_in_place<&smoltcp::wire::ip::Address>" - .asciz "core::ptr::drop_in_place<&smoltcp::iface::route::Route>" - .asciz "core::ptr::drop_in_place<&smoltcp::iface::neighbor::Neighbor>" - .asciz "core::ptr::drop_in_place<&smoltcp::storage::assembler::Contig>" - .asciz "core::ptr::drop_in_place<&smoltcp::iface::socket_set::SocketStorage>" - .asciz "core::ptr::drop_in_place<&core::option::Option<(u32,u32)>>" - .asciz "core::ptr::drop_in_place<&core::option::Option>" - .asciz "core::ptr::drop_in_place<&smoltcp::storage::packet_buffer::PacketMetadata<()>>" - .asciz "smoltcp::wire::icmpv4::Repr::parse" - .asciz "smoltcp::wire::icmpv4::Repr::emit" - .asciz ">::from" - .asciz "smoltcp::iface::neighbor::Cache::fill" - .asciz "smoltcp::iface::neighbor::Cache::lookup" - .asciz "smoltcp::socket::udp::Socket::recv_slice" - .asciz "smoltcp::socket::udp::Socket::process" - .asciz "<&T as core::fmt::Display>::fmt" - .asciz "core::ptr::drop_in_place" - .asciz "smoltcp::iface::route::Routes::add_default_ipv4_route" - .asciz "smoltcp::iface::route::Routes::lookup" - .asciz "smoltcp::wire::ip::Version::of_packet" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "smoltcp::wire::ip::Cidr::new" - .asciz "::fmt" - .asciz "::fmt" - .asciz "smoltcp::wire::HardwareAddress::ethernet_or_panic" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "smoltcp::iface::ip_packet::IpPacket::emit_payload" - .asciz "smoltcp::storage::packet_buffer::PacketBuffer::enqueue" - .asciz "smoltcp::storage::packet_buffer::PacketBuffer::enqueue" - .asciz "smoltcp::storage::packet_buffer::PacketBuffer::enqueue" - .asciz "smoltcp::storage::packet_buffer::PacketBuffer::dequeue" - .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_one_with" - .asciz "smoltcp::storage::ring_buffer::RingBuffer::enqueue_slice" - .asciz "smoltcp::storage::ring_buffer::RingBuffer::dequeue_slice" - .asciz "smoltcp::storage::ring_buffer::RingBuffer::write_unallocated" - .asciz "::fmt" + .asciz "vfscore::utils::VfsInodeMode::from" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "smoltcp::wire::ipv4::Address::from_bytes" - .asciz "::fmt" - .asciz "smoltcp::wire::ipv4::Repr::parse" - .asciz "smoltcp::wire::ipv4::Repr::emit" - .asciz ">::from" - .asciz "::fmt" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::error::Error::cause" + .asciz "core::error::Error::type_id" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::reserve::do_reserve_and_handle" + .asciz "::fmt" + .asciz "::fmt" + .asciz "core::ptr::drop_in_place<&i32>" + .asciz "core::ptr::drop_in_place<&isize>" + .asciz "core::ptr::drop_in_place" + .asciz "core::array::::fmt" + .asciz "core::error::Error::cause" + .asciz "core::error::Error::type_id" + .asciz "core::panicking::assert_failed" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "alloc::sync::Arc::drop_slow" + .asciz "::i_insert" + .asciz "vfscore::error:: for pconst::consts::LinuxErrno>::from" + .asciz "::i_mount" + .asciz ">::from" + .asciz "::fmt" .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "pconst::consts::syscall_name" + .asciz ">::try_from" + .asciz "pconst::consts:: for isize>::from" + .asciz "::fmt" + .asciz "::fmt" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "<&T as core::fmt::Display>::fmt" - .asciz "<&T as core::fmt::Display>::fmt" - .asciz "::fmt" - .asciz "smoltcp::wire::arp::Repr::parse" - .asciz "smoltcp::wire::ethernet::Address::from_bytes" - .asciz "::fmt" - .asciz "smoltcp::iface::socket_meta::Meta::neighbor_missing" - .asciz "smoltcp::socket::icmp::Socket::accepts" - .asciz "smoltcp::socket::icmp::Socket::process" - .asciz "smoltcp::wire::ip::checksum::data" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place<&u8>" + .asciz "core::ptr::drop_in_place<&i32>" + .asciz "core::ptr::drop_in_place<&isize>" + .asciz "core::ptr::drop_in_place<&usize>" + .asciz "core::ptr::drop_in_place<&core::option::Option>" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "core::fmt::num::::fmt" + .asciz "core::ptr::drop_in_place" + .asciz "alloc::raw_vec::finish_grow" + .asciz "alloc::raw_vec::RawVec::reserve_for_push" + .asciz ">::from" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "core::ptr::drop_in_place<&&mut alloc::collections::vec_deque::VecDeque>>" - .asciz "core::ptr::drop_in_place" - .asciz "core::ptr::drop_in_place" - .asciz "smoltcp::wire::dns::Packet::rcode" - .asciz "smoltcp::wire::dns::Question::parse" - .asciz "smoltcp::wire::dns::Question::emit" - .asciz "smoltcp::wire::dns::Record::parse" - .asciz "::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "<&T as core::fmt::Display>::fmt" - .asciz "::fmt" - .asciz "::fmt" - .asciz "smoltcp::storage::assembler::Assembler::add" - .asciz "smoltcp::wire::udp::Packet::verify_checksum" - .asciz "smoltcp::wire::udp::Repr::emit" - .asciz "::fmt" - .asciz "smoltcp::iface::socket_set::SocketSet::add::put" - .asciz "smoltcp::iface::socket_set::SocketSet::remove" - .asciz "smoltcp::iface::socket_set::SocketSet::items" - .asciz "smoltcp::iface::socket_set::SocketSet::items_mut" - .asciz "smoltcp::socket::raw::Socket::process" - .asciz "::before_lock" - .asciz "::after_lock" - .asciz "arch::riscv::activate_paging_mode" + .asciz "core::ptr::drop_in_place<&[core::option::Option; 64]>" + .asciz "pconst::signal::SignalHandlers::clear" + .asciz "pconst::signal::SignalHandlers::get_action" + .asciz "pconst::signal::SignalHandlers::get_action_ref" + .asciz "pconst::signal::SignalHandlers::set_action" + .asciz "pconst::signal::SignalReceivers::get_one_signal" + .asciz "pconst::signal::SignalReceivers::have_signal" + .asciz "pconst::signal::SignalReceivers::have_signal_with_number" + .asciz ">>::into" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" + .asciz "::fmt" .asciz "<&T as core::fmt::Debug>::fmt" .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::ptr::drop_in_place<&u32>" - .asciz "::fmt" - .asciz "core::ptr::drop_in_place" - .asciz "::print" - .asciz "preprint::__private_print" .asciz "<&T as core::fmt::Display>::fmt" + .asciz "<&T as core::fmt::Display>::fmt" + .asciz "core::fmt::Write::write_char" + .asciz "core::fmt::Write::write_fmt" + .asciz "core::ptr::drop_in_place" + .asciz "core::ptr::drop_in_place" + .asciz "core::panicking::assert_failed" + .asciz "spin::once::Once::try_call_once_slow" + .asciz "spin::once::Once::try_call_once_slow" + .asciz " as core::fmt::Debug>::fmt" + .asciz "::write_str" + .asciz "platform::console::__print" + .asciz "platform::console::console_write" + .asciz "::print" + .asciz "_start_secondary" + .asciz "clear_bss" + .asciz "::enabled" + .asciz "::log" + .asciz "::flush" + .asciz "platform::logging::init_logger" + .asciz "platform_init" + .asciz "platform::platform_dtb_ptr" + .asciz "platform::platform_machine_info" .asciz "core::ptr::drop_in_place" .asciz "core::ptr::drop_in_place" .asciz "core::ptr::drop_in_place" - .asciz "::fmt" - .asciz "basemachine::machine_info_from_dtb" + .asciz "::fmt" + .asciz "platform::basic::machine_info_from_dtb" .asciz "core::str::iter::SplitInternal

::next" + .asciz "fdt::node::FdtNode::property" .asciz "fdt::node::FdtNode::reg" .asciz "fdt::node::FdtNode::compatible" .asciz "fdt::node::FdtNode::cell_sizes" - .asciz "fdt::node::FdtNode::interrupts" .asciz "fdt::node::find_node" .asciz "fdt::node::skip_current_node" .asciz "fdt::node::NodeProperty::parse" .asciz "fdt::node::skip_4_aligned" - .asciz " as core::iter::traits::iterator::Iterator>::next" .asciz "fdt::Fdt::from_ptr" .asciz "fdt::Fdt::cpus" .asciz "fdt::Fdt::root" .asciz "fdt::Fdt::find_node" - .asciz "fdt::Fdt::find_phandle" .asciz "fdt::Fdt::all_nodes" .asciz "fdt::Fdt::str_at_offset" .asciz "::fmt" @@ -9454,6 +10271,16 @@ symbol_name: .asciz "fdt::parsing::FdtData::u64" .asciz "fdt::parsing::FdtData::skip" .asciz "fdt::parsing::FdtData::peek_u32" + .asciz "core::ptr::drop_in_place" + .asciz "::print" + .asciz "preprint::__private_print" + .asciz "::before_lock" + .asciz "::after_lock" + .asciz "arch::riscv::activate_paging_mode" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&u32>" + .asciz "::fmt" .asciz "syscall_table::Service::handle" .asciz "::from" .asciz "::from" @@ -9461,16 +10288,6 @@ symbol_name: .asciz "::from" .asciz "::from" .asciz "inventory::Registry::submit" - .asciz "<&T as core::fmt::Debug>::fmt" - .asciz "core::ptr::drop_in_place<&u32>" - .asciz "core::ptr::drop_in_place" - .asciz "::fmt" - .asciz "::enabled" - .asciz "::log" - .asciz "::flush" - .asciz "log::set_logger" - .asciz "log::__private_api::log" - .asciz "::fmt" .asciz "core::fmt::Write::write_fmt" .asciz "core::ptr::drop_in_place" .asciz "core::ptr::drop_in_place" @@ -9487,6 +10304,16 @@ symbol_name: .asciz "::write_str" .asciz "::write_char" .asciz "alloc::vec::Vec::remove::assert_failed" + .asciz "<&T as core::fmt::Debug>::fmt" + .asciz "core::ptr::drop_in_place<&u32>" + .asciz "core::ptr::drop_in_place" + .asciz "::fmt" + .asciz "::enabled" + .asciz "::log" + .asciz "::flush" + .asciz "log::set_logger" + .asciz "log::__private_api::log" + .asciz "::fmt" .asciz "core::ops::function::FnOnce::call_once" .asciz "core::ptr::drop_in_place<&core::iter::adapters::copied::Copied>>" .asciz "core::ptr::drop_in_place" @@ -9512,6 +10339,7 @@ symbol_name: .asciz "::fmt" .asciz "::fmt" .asciz "core::option::expect_failed" + .asciz "::fmt" .asciz "core::panicking::panic_fmt" .asciz "core::panicking::panic_nounwind_fmt" .asciz "core::panicking::panic" @@ -9548,7 +10376,6 @@ symbol_name: .asciz "core::fmt::Formatter::write_fmt" .asciz "::write_fmt" .asciz "core::fmt::Formatter::debug_struct" - .asciz "core::fmt::Formatter::debug_struct_field1_finish" .asciz "core::fmt::Formatter::debug_struct_field2_finish" .asciz "core::fmt::Formatter::debug_struct_field3_finish" .asciz "core::fmt::Formatter::debug_struct_field4_finish" @@ -9588,8 +10415,6 @@ symbol_name: .asciz "core::fmt::num::::fmt" .asciz "core::fmt::num::::fmt" .asciz "core::fmt::num::::fmt" - .asciz "core::fmt::num::::fmt" - .asciz "core::fmt::num::::fmt" .asciz "core::fmt::num::::fmt" .asciz "core::fmt::num::::fmt" .asciz "core::fmt::num::::fmt" @@ -9640,336 +10465,330 @@ symbol_name: .asciz "memcpy" .asciz "etext" .asciz "srodata" - .asciz "symbol_num" - .asciz "symbol_address" - .asciz "symbol_index" - .asciz "symbol_name" - .asciz "str.1.llvm.17000698678205763346" + .asciz "str.0.llvm.1187392117675697175" + .asciz "str.0.llvm.9032329141667060801" + .asciz "str.0.llvm.12830073343055868386" .asciz "str.0" .asciz "str.1" .asciz "str.0" - .asciz "str.0.llvm.9032329141667060801" - .asciz "str.0.llvm.12830073343055868386" .asciz "log::LOG_LEVEL_NAMES" .asciz "core::unicode::unicode_data::grapheme_extend::SHORT_OFFSET_RUNS" .asciz "core::unicode::unicode_data::grapheme_extend::OFFSETS" .asciz "erodata" - .asciz "kernel::task::cpu::__syscall_260::_::__CTOR" + .asciz "kernel::time::__syscall_115::_::__CTOR" .asciz "sdata" .asciz "sinit" + .asciz "kernel::time::__syscall_114::_::__CTOR" + .asciz "kernel::time::__syscall_103::_::__CTOR" + .asciz "kernel::time::__syscall_102::_::__CTOR" + .asciz "kernel::time::__syscall_113::_::__CTOR" + .asciz "kernel::time::__syscall_101::_::__CTOR" + .asciz "kernel::time::__syscall_153::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_261::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_214::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_260::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_221::_::__CTOR" .asciz "kernel::task::cpu::__syscall_177::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_176::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_175::_::__CTOR" .asciz "kernel::task::cpu::__syscall_174::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_157::_::__CTOR" .asciz "kernel::task::cpu::__syscall_155::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_124::_::__CTOR" - .asciz "kernel::net::__syscall_210::_::__CTOR" - .asciz "kernel::net::__syscall_203::_::__CTOR" - .asciz "kernel::net::__syscall_201::_::__CTOR" - .asciz "kernel::memory::map::__syscall_233::_::__CTOR" - .asciz "kernel::memory::map::__syscall_215::_::__CTOR" - .asciz "kernel::ipc::__syscall_99::_::__CTOR" - .asciz "kernel::ipc::shm::__syscall_196::_::__CTOR" - .asciz "kernel::gui::__syscall_2000::_::__CTOR" - .asciz "kernel::fs::sys::cpu::__syscall_121::_::__CTOR" - .asciz "kernel::fs::proc::process::__syscall_165::_::__CTOR" - .asciz "kernel::fs::link::__syscall_78::_::__CTOR" - .asciz "kernel::fs::ext::__syscall_10::_::__CTOR" - .asciz "kernel::fs::ext::__syscall_9::_::__CTOR" - .asciz "kernel::fs::ext::__syscall_8::_::__CTOR" - .asciz "kernel::fs::ext::__syscall_6::_::__CTOR" - .asciz "kernel::fs::control::__syscall_53::_::__CTOR" - .asciz "kernel::fs::control::__syscall_29::_::__CTOR" - .asciz "kernel::fs::control::__syscall_25::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_38::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_44::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_67::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_45::_::__CTOR" - .asciz "kernel::device::input::__syscall_2002::_::__CTOR" - .asciz "kernel::timer::__syscall_103::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_221::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_220::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_94::_::__CTOR" - .asciz "kernel::net::__syscall_209::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_154::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_93::_::__CTOR" + .asciz "kernel::system::__syscall_2003::_::__CTOR" + .asciz "kernel::system::__syscall_165::_::__CTOR" + .asciz "kernel::system::__syscall_119::_::__CTOR" + .asciz "kernel::system::__syscall_123::_::__CTOR" + .asciz "kernel::system::__syscall_122::_::__CTOR" + .asciz "kernel::system::__syscall_118::_::__CTOR" + .asciz "kernel::net::__syscall_199::_::__CTOR" .asciz "kernel::net::__syscall_207::_::__CTOR" .asciz "kernel::net::__syscall_206::_::__CTOR" .asciz "kernel::net::__syscall_204::_::__CTOR" .asciz "kernel::net::__syscall_200::_::__CTOR" - .asciz "kernel::net::__syscall_198::_::__CTOR" - .asciz "kernel::memory::map::__syscall_222::_::__CTOR" - .asciz "kernel::ipc::__syscall_59::_::__CTOR" + .asciz "kernel::mm::map::__syscall_233::_::__CTOR" + .asciz "kernel::mm::map::__syscall_227::_::__CTOR" + .asciz "kernel::mm::map::__syscall_215::_::__CTOR" + .asciz "kernel::ipc::__syscall_98::_::__CTOR" + .asciz "kernel::ipc::__syscall_23::_::__CTOR" + .asciz "kernel::ipc::signal::__syscall_139::_::__CTOR" .asciz "kernel::ipc::signal::__syscall_130::_::__CTOR" - .asciz "kernel::ipc::signal::__syscall_137::_::__CTOR" - .asciz "kernel::gui::__syscall_2001::_::__CTOR" - .asciz "kernel::fs::sys::info::__syscall_179::_::__CTOR" - .asciz "kernel::fs::sys::cpu::__syscall_120::_::__CTOR" - .asciz "kernel::fs::sys::cpu::__syscall_123::_::__CTOR" - .asciz "kernel::fs::sys::cpu::__syscall_118::_::__CTOR" - .asciz "kernel::fs::select::__syscall_72::_::__CTOR" - .asciz "kernel::fs::link::__syscall_35::_::__CTOR" - .asciz "kernel::fs::ext::__syscall_15::_::__CTOR" - .asciz "kernel::fs::ext::__syscall_13::_::__CTOR" - .asciz "kernel::fs::control::__syscall_52::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_43::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_80::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_65::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_34::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_49::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_40::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_96::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_214::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_176::_::__CTOR" - .asciz "kernel::sbi::__syscall_2003::_::__CTOR" - .asciz "kernel::net::__syscall_208::_::__CTOR" - .asciz "kernel::memory::map::__syscall_226::_::__CTOR" .asciz "kernel::ipc::signal::__syscall_129::_::__CTOR" - .asciz "kernel::ipc::shm::__syscall_194::_::__CTOR" - .asciz "kernel::fs::sys::info::__syscall_116::_::__CTOR" - .asciz "kernel::fs::control::__syscall_88::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_82::_::__CTOR" - .asciz "kernel::timer::__syscall_114::_::__CTOR" - .asciz "kernel::timer::__syscall_113::_::__CTOR" - .asciz "kernel::timer::__syscall_169::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_175::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_173::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_172::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_157::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_93::_::__CTOR" - .asciz "kernel::system::__syscall_160::_::__CTOR" - .asciz "kernel::net::__syscall_199::_::__CTOR" - .asciz "kernel::net::__syscall_205::_::__CTOR" - .asciz "kernel::net::__syscall_202::_::__CTOR" - .asciz "kernel::memory::__syscall_283::_::__CTOR" - .asciz "kernel::memory::map::__syscall_227::_::__CTOR" - .asciz "kernel::ipc::__syscall_100::_::__CTOR" - .asciz "kernel::ipc::__syscall_24::_::__CTOR" - .asciz "kernel::ipc::signal::__syscall_133::_::__CTOR" - .asciz "kernel::ipc::signal::__syscall_139::_::__CTOR" .asciz "kernel::ipc::signal::__syscall_135::_::__CTOR" + .asciz "kernel::ipc::signal::__syscall_137::_::__CTOR" + .asciz "kernel::ipc::signal::__syscall_134::_::__CTOR" .asciz "kernel::ipc::shm::__syscall_195::_::__CTOR" - .asciz "kernel::fs::sys::cpu::__syscall_119::_::__CTOR" - .asciz "kernel::fs::sys::cpu::__syscall_122::_::__CTOR" - .asciz "kernel::fs::link::__syscall_36::_::__CTOR" + .asciz "kernel::gui::__syscall_2000::_::__CTOR" + .asciz "kernel::fs::select::__syscall_72::_::__CTOR" + .asciz "kernel::fs::poll::__syscall_73::_::__CTOR" + .asciz "kernel::fs::link::__syscall_37::_::__CTOR" .asciz "kernel::fs::ext::__syscall_16::_::__CTOR" - .asciz "kernel::fs::ext::__syscall_14::_::__CTOR" .asciz "kernel::fs::ext::__syscall_12::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_11::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_9::_::__CTOR" .asciz "kernel::fs::ext::__syscall_7::_::__CTOR" - .asciz "kernel::fs::ext::__syscall_5::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_6::_::__CTOR" .asciz "kernel::fs::control::__syscall_166::_::__CTOR" + .asciz "kernel::fs::control::__syscall_55::_::__CTOR" + .asciz "kernel::fs::control::__syscall_53::_::__CTOR" + .asciz "kernel::fs::control::__syscall_52::_::__CTOR" + .asciz "kernel::fs::control::__syscall_48::_::__CTOR" + .asciz "kernel::fs::control::__syscall_88::_::__CTOR" + .asciz "kernel::fs::control::__syscall_29::_::__CTOR" + .asciz "kernel::fs::control::__syscall_25::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_82::_::__CTOR" .asciz "kernel::fs::basic::__syscall_81::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_71::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_276::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_38::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_44::_::__CTOR" .asciz "kernel::fs::basic::__syscall_79::_::__CTOR" .asciz "kernel::fs::basic::__syscall_68::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_66::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_62::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_65::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_34::_::__CTOR" .asciz "kernel::fs::basic::__syscall_50::_::__CTOR" .asciz "kernel::fs::basic::__syscall_17::_::__CTOR" .asciz "kernel::fs::basic::__syscall_64::_::__CTOR" .asciz "kernel::fs::basic::__syscall_63::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_46::_::__CTOR" .asciz "kernel::fs::basic::__syscall_61::_::__CTOR" .asciz "kernel::fs::basic::__syscall_57::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_56::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_39::_::__CTOR" - .asciz "kernel::timer::__syscall_115::_::__CTOR" - .asciz "kernel::timer::__syscall_102::_::__CTOR" - .asciz "kernel::timer::__syscall_101::_::__CTOR" - .asciz "kernel::timer::__syscall_153::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_261::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_40::_::__CTOR" + .asciz "kernel::ipc::__syscall_100::_::__CTOR" + .asciz "kernel::time::__syscall_169::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_96::_::__CTOR" .asciz "kernel::task::cpu::__syscall_178::_::__CTOR" - .asciz "kernel::task::cpu::__syscall_154::_::__CTOR" - .asciz "kernel::ipc::__syscall_98::_::__CTOR" - .asciz "kernel::ipc::__syscall_23::_::__CTOR" - .asciz "kernel::ipc::signal::__syscall_134::_::__CTOR" - .asciz "kernel::fs::poll::__syscall_73::_::__CTOR" - .asciz "kernel::fs::link::__syscall_37::_::__CTOR" - .asciz "kernel::fs::ext::__syscall_11::_::__CTOR" - .asciz "kernel::fs::control::__syscall_55::_::__CTOR" - .asciz "kernel::fs::control::__syscall_48::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_172::_::__CTOR" + .asciz "kernel::system::__syscall_121::_::__CTOR" + .asciz "kernel::system::__syscall_179::_::__CTOR" + .asciz "kernel::system::__syscall_160::_::__CTOR" + .asciz "kernel::net::__syscall_209::_::__CTOR" + .asciz "kernel::net::__syscall_208::_::__CTOR" + .asciz "kernel::net::__syscall_203::_::__CTOR" + .asciz "kernel::net::__syscall_201::_::__CTOR" + .asciz "kernel::net::__syscall_198::_::__CTOR" + .asciz "kernel::mm::__syscall_283::_::__CTOR" + .asciz "kernel::mm::map::__syscall_226::_::__CTOR" + .asciz "kernel::ipc::signal::__syscall_133::_::__CTOR" + .asciz "kernel::ipc::shm::__syscall_194::_::__CTOR" + .asciz "kernel::gui::__syscall_2002::_::__CTOR" + .asciz "kernel::gui::__syscall_2001::_::__CTOR" + .asciz "kernel::fs::link::__syscall_78::_::__CTOR" + .asciz "kernel::fs::link::__syscall_36::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_15::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_14::_::__CTOR" .asciz "kernel::fs::basic::__syscall_285::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_71::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_276::_::__CTOR" - .asciz "kernel::fs::basic::__syscall_46::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_43::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_80::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_67::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_66::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_49::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_56::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_39::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_220::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_173::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_124::_::__CTOR" + .asciz "kernel::task::cpu::__syscall_94::_::__CTOR" + .asciz "kernel::system::__syscall_120::_::__CTOR" + .asciz "kernel::system::__syscall_116::_::__CTOR" + .asciz "kernel::net::__syscall_210::_::__CTOR" + .asciz "kernel::net::__syscall_205::_::__CTOR" + .asciz "kernel::net::__syscall_202::_::__CTOR" + .asciz "kernel::mm::map::__syscall_222::_::__CTOR" + .asciz "kernel::ipc::__syscall_99::_::__CTOR" + .asciz "kernel::ipc::__syscall_24::_::__CTOR" + .asciz "kernel::ipc::__syscall_59::_::__CTOR" + .asciz "kernel::ipc::shm::__syscall_196::_::__CTOR" + .asciz "kernel::fs::link::__syscall_35::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_13::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_10::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_8::_::__CTOR" + .asciz "kernel::fs::ext::__syscall_5::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_62::_::__CTOR" + .asciz "kernel::fs::basic::__syscall_45::_::__CTOR" .asciz "kernel::task::task::TID_MANAGER" .asciz "einit" - .asciz "kernel::memory::vmm::KERNEL_SPACE" - .asciz "kernel::memory::HEAP_ALLOCATOR" + .asciz "kernel::ipc::FUTEX_WAITER" + .asciz "kernel::time::__syscall_115::_::__INVENTORY" + .asciz "kernel::time::__syscall_114::_::__INVENTORY" + .asciz "kernel::time::__syscall_103::_::__INVENTORY" + .asciz "kernel::time::__syscall_102::_::__INVENTORY" + .asciz "kernel::time::__syscall_113::_::__INVENTORY" + .asciz "kernel::time::__syscall_101::_::__INVENTORY" + .asciz "kernel::time::__syscall_153::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_261::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_214::_::__INVENTORY" .asciz "kernel::task::cpu::__syscall_260::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_221::_::__INVENTORY" .asciz "kernel::task::cpu::__syscall_177::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_176::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_175::_::__INVENTORY" .asciz "kernel::task::cpu::__syscall_174::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_157::_::__INVENTORY" .asciz "kernel::task::cpu::__syscall_155::_::__INVENTORY" - .asciz "kernel::task::cpu::__syscall_124::_::__INVENTORY" - .asciz "kernel::net::__syscall_210::_::__INVENTORY" - .asciz "kernel::net::__syscall_203::_::__INVENTORY" - .asciz "kernel::net::__syscall_201::_::__INVENTORY" - .asciz "kernel::memory::map::__syscall_233::_::__INVENTORY" - .asciz "kernel::memory::map::__syscall_215::_::__INVENTORY" - .asciz "kernel::ipc::__syscall_99::_::__INVENTORY" - .asciz "kernel::ipc::shm::__syscall_196::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_154::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_93::_::__INVENTORY" + .asciz "kernel::system::__syscall_2003::_::__INVENTORY" + .asciz "kernel::system::__syscall_165::_::__INVENTORY" + .asciz "kernel::system::__syscall_119::_::__INVENTORY" + .asciz "kernel::system::__syscall_123::_::__INVENTORY" + .asciz "kernel::system::__syscall_122::_::__INVENTORY" + .asciz "kernel::system::__syscall_118::_::__INVENTORY" + .asciz "kernel::net::__syscall_199::_::__INVENTORY" + .asciz "kernel::net::__syscall_207::_::__INVENTORY" + .asciz "kernel::net::__syscall_206::_::__INVENTORY" + .asciz "kernel::net::__syscall_204::_::__INVENTORY" + .asciz "kernel::net::__syscall_200::_::__INVENTORY" + .asciz "kernel::mm::map::__syscall_233::_::__INVENTORY" + .asciz "kernel::mm::map::__syscall_227::_::__INVENTORY" + .asciz "kernel::mm::map::__syscall_215::_::__INVENTORY" + .asciz "kernel::ipc::__syscall_98::_::__INVENTORY" + .asciz "kernel::ipc::__syscall_23::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_139::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_130::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_129::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_135::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_137::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_134::_::__INVENTORY" + .asciz "kernel::ipc::shm::__syscall_195::_::__INVENTORY" .asciz "kernel::gui::__syscall_2000::_::__INVENTORY" - .asciz "kernel::fs::sys::cpu::__syscall_121::_::__INVENTORY" - .asciz "kernel::fs::proc::process::__syscall_165::_::__INVENTORY" - .asciz "kernel::fs::link::__syscall_78::_::__INVENTORY" - .asciz "kernel::fs::ext::__syscall_10::_::__INVENTORY" + .asciz "kernel::fs::select::__syscall_72::_::__INVENTORY" + .asciz "kernel::fs::poll::__syscall_73::_::__INVENTORY" + .asciz "kernel::fs::link::__syscall_37::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_16::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_12::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_11::_::__INVENTORY" .asciz "kernel::fs::ext::__syscall_9::_::__INVENTORY" - .asciz "kernel::fs::ext::__syscall_8::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_7::_::__INVENTORY" .asciz "kernel::fs::ext::__syscall_6::_::__INVENTORY" + .asciz "kernel::fs::control::__syscall_166::_::__INVENTORY" + .asciz "kernel::fs::control::__syscall_55::_::__INVENTORY" .asciz "kernel::fs::control::__syscall_53::_::__INVENTORY" + .asciz "kernel::fs::control::__syscall_52::_::__INVENTORY" + .asciz "kernel::fs::control::__syscall_48::_::__INVENTORY" + .asciz "kernel::fs::control::__syscall_88::_::__INVENTORY" .asciz "kernel::fs::control::__syscall_29::_::__INVENTORY" .asciz "kernel::fs::control::__syscall_25::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_82::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_81::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_71::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_276::_::__INVENTORY" .asciz "kernel::fs::basic::__syscall_38::_::__INVENTORY" .asciz "kernel::fs::basic::__syscall_44::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_67::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_45::_::__INVENTORY" - .asciz "kernel::device::input::__syscall_2002::_::__INVENTORY" - .asciz "kernel::fs::dev::DEVICES" - .asciz "kernel::fs::dev::DEVICE_ID_MANAGER" - .asciz "kernel::timer::__syscall_103::_::__INVENTORY" - .asciz "kernel::task::cpu::__syscall_221::_::__INVENTORY" - .asciz "kernel::task::cpu::__syscall_220::_::__INVENTORY" - .asciz "kernel::task::cpu::__syscall_94::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_79::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_68::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_65::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_34::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_50::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_17::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_64::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_63::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_46::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_61::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_57::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_40::_::__INVENTORY" + .asciz "kernel::ipc::__syscall_100::_::__INVENTORY" + .asciz "kernel::task::cpu::GLOBAL_TASK_MANAGER" + .asciz "kernel::time::__syscall_169::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_96::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_178::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_172::_::__INVENTORY" + .asciz "kernel::system::__syscall_121::_::__INVENTORY" + .asciz "kernel::system::__syscall_179::_::__INVENTORY" + .asciz "kernel::system::__syscall_160::_::__INVENTORY" .asciz "kernel::net::__syscall_209::_::__INVENTORY" - .asciz "kernel::net::__syscall_207::_::__INVENTORY" - .asciz "kernel::net::__syscall_206::_::__INVENTORY" - .asciz "kernel::net::__syscall_204::_::__INVENTORY" - .asciz "kernel::net::__syscall_200::_::__INVENTORY" + .asciz "kernel::net::__syscall_208::_::__INVENTORY" + .asciz "kernel::net::__syscall_203::_::__INVENTORY" + .asciz "kernel::net::__syscall_201::_::__INVENTORY" .asciz "kernel::net::__syscall_198::_::__INVENTORY" - .asciz "kernel::memory::map::__syscall_222::_::__INVENTORY" - .asciz "kernel::ipc::__syscall_59::_::__INVENTORY" - .asciz "kernel::ipc::signal::__syscall_130::_::__INVENTORY" - .asciz "kernel::ipc::signal::__syscall_137::_::__INVENTORY" + .asciz "kernel::mm::__syscall_283::_::__INVENTORY" + .asciz "kernel::mm::map::__syscall_226::_::__INVENTORY" + .asciz "kernel::ipc::signal::__syscall_133::_::__INVENTORY" + .asciz "kernel::ipc::shm::__syscall_194::_::__INVENTORY" + .asciz "kernel::gui::__syscall_2002::_::__INVENTORY" .asciz "kernel::gui::__syscall_2001::_::__INVENTORY" - .asciz "kernel::fs::sys::info::__syscall_179::_::__INVENTORY" - .asciz "kernel::fs::sys::cpu::__syscall_120::_::__INVENTORY" - .asciz "kernel::fs::sys::cpu::__syscall_123::_::__INVENTORY" - .asciz "kernel::fs::sys::cpu::__syscall_118::_::__INVENTORY" - .asciz "kernel::fs::select::__syscall_72::_::__INVENTORY" - .asciz "kernel::fs::link::__syscall_35::_::__INVENTORY" + .asciz "kernel::fs::link::__syscall_78::_::__INVENTORY" + .asciz "kernel::fs::link::__syscall_36::_::__INVENTORY" .asciz "kernel::fs::ext::__syscall_15::_::__INVENTORY" - .asciz "kernel::fs::ext::__syscall_13::_::__INVENTORY" - .asciz "kernel::fs::control::__syscall_52::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_14::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_285::_::__INVENTORY" .asciz "kernel::fs::basic::__syscall_43::_::__INVENTORY" .asciz "kernel::fs::basic::__syscall_80::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_65::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_34::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_67::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_66::_::__INVENTORY" .asciz "kernel::fs::basic::__syscall_49::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_40::_::__INVENTORY" - .asciz "kernel::timer::TIMER_QUEUE" - .asciz "kernel::task::cpu::__syscall_96::_::__INVENTORY" - .asciz "kernel::task::cpu::__syscall_214::_::__INVENTORY" - .asciz "kernel::task::cpu::__syscall_176::_::__INVENTORY" - .asciz "kernel::sbi::__syscall_2003::_::__INVENTORY" - .asciz "kernel::net::__syscall_208::_::__INVENTORY" - .asciz "kernel::memory::map::__syscall_226::_::__INVENTORY" - .asciz "kernel::ipc::signal::__syscall_129::_::__INVENTORY" - .asciz "kernel::ipc::shm::__syscall_194::_::__INVENTORY" - .asciz "kernel::fs::sys::info::__syscall_116::_::__INVENTORY" - .asciz "kernel::fs::control::__syscall_88::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_82::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_56::_::__INVENTORY" + .asciz "kernel::fs::basic::__syscall_39::_::__INVENTORY" .asciz "kernel::fs::stdio::STDIN" .asciz "kernel::fs::stdio::STDOUT" .asciz "kernel::task::INIT_PROCESS" - .asciz "kernel::ipc::FUTEX_WAITER" - .asciz "kernel::task::cpu::GLOBAL_TASK_MANAGER" - .asciz "kernel::timer::__syscall_114::_::__INVENTORY" - .asciz "kernel::timer::__syscall_113::_::__INVENTORY" - .asciz "kernel::timer::__syscall_169::_::__INVENTORY" - .asciz "kernel::task::cpu::__syscall_175::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_220::_::__INVENTORY" .asciz "kernel::task::cpu::__syscall_173::_::__INVENTORY" - .asciz "kernel::task::cpu::__syscall_172::_::__INVENTORY" - .asciz "kernel::task::cpu::__syscall_157::_::__INVENTORY" - .asciz "kernel::task::cpu::__syscall_93::_::__INVENTORY" - .asciz "kernel::system::__syscall_160::_::__INVENTORY" - .asciz "kernel::net::__syscall_199::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_124::_::__INVENTORY" + .asciz "kernel::task::cpu::__syscall_94::_::__INVENTORY" + .asciz "kernel::system::__syscall_120::_::__INVENTORY" + .asciz "kernel::system::__syscall_116::_::__INVENTORY" + .asciz "kernel::net::__syscall_210::_::__INVENTORY" .asciz "kernel::net::__syscall_205::_::__INVENTORY" .asciz "kernel::net::__syscall_202::_::__INVENTORY" - .asciz "kernel::memory::__syscall_283::_::__INVENTORY" - .asciz "kernel::memory::map::__syscall_227::_::__INVENTORY" - .asciz "kernel::ipc::__syscall_100::_::__INVENTORY" + .asciz "kernel::mm::map::__syscall_222::_::__INVENTORY" + .asciz "kernel::ipc::__syscall_99::_::__INVENTORY" .asciz "kernel::ipc::__syscall_24::_::__INVENTORY" - .asciz "kernel::ipc::signal::__syscall_133::_::__INVENTORY" - .asciz "kernel::ipc::signal::__syscall_139::_::__INVENTORY" - .asciz "kernel::ipc::signal::__syscall_135::_::__INVENTORY" - .asciz "kernel::ipc::shm::__syscall_195::_::__INVENTORY" - .asciz "kernel::fs::sys::cpu::__syscall_119::_::__INVENTORY" - .asciz "kernel::fs::sys::cpu::__syscall_122::_::__INVENTORY" - .asciz "kernel::fs::link::__syscall_36::_::__INVENTORY" - .asciz "kernel::fs::ext::__syscall_16::_::__INVENTORY" - .asciz "kernel::fs::ext::__syscall_14::_::__INVENTORY" - .asciz "kernel::fs::ext::__syscall_12::_::__INVENTORY" - .asciz "kernel::fs::ext::__syscall_7::_::__INVENTORY" + .asciz "kernel::ipc::__syscall_59::_::__INVENTORY" + .asciz "kernel::ipc::shm::__syscall_196::_::__INVENTORY" + .asciz "kernel::fs::link::__syscall_35::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_13::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_10::_::__INVENTORY" + .asciz "kernel::fs::ext::__syscall_8::_::__INVENTORY" .asciz "kernel::fs::ext::__syscall_5::_::__INVENTORY" - .asciz "kernel::fs::control::__syscall_166::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_81::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_79::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_68::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_66::_::__INVENTORY" .asciz "kernel::fs::basic::__syscall_62::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_50::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_17::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_64::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_63::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_61::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_57::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_56::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_39::_::__INVENTORY" - .asciz "kernel::timer::__syscall_115::_::__INVENTORY" - .asciz "kernel::timer::__syscall_102::_::__INVENTORY" - .asciz "kernel::timer::__syscall_101::_::__INVENTORY" - .asciz "kernel::timer::__syscall_153::_::__INVENTORY" - .asciz "kernel::task::cpu::__syscall_261::_::__INVENTORY" - .asciz "kernel::task::cpu::__syscall_178::_::__INVENTORY" - .asciz "kernel::task::cpu::__syscall_154::_::__INVENTORY" - .asciz "kernel::ipc::__syscall_98::_::__INVENTORY" - .asciz "kernel::ipc::__syscall_23::_::__INVENTORY" - .asciz "kernel::ipc::signal::__syscall_134::_::__INVENTORY" - .asciz "kernel::fs::poll::__syscall_73::_::__INVENTORY" - .asciz "kernel::fs::link::__syscall_37::_::__INVENTORY" - .asciz "kernel::fs::ext::__syscall_11::_::__INVENTORY" - .asciz "kernel::fs::control::__syscall_55::_::__INVENTORY" - .asciz "kernel::fs::control::__syscall_48::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_285::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_71::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_276::_::__INVENTORY" - .asciz "kernel::fs::basic::__syscall_46::_::__INVENTORY" - .asciz "kernel::fs::FS" - .asciz "kernel::interrupt::record::INTERRUPT_RECORD" - .asciz "kernel::memory::frame::FRAME_REF_MANAGER" + .asciz "kernel::fs::basic::__syscall_45::_::__INVENTORY" + .asciz "vfs::dev::DEVICES" + .asciz "vfs::dev::DEVICE_ID_MANAGER" + .asciz "vfs::FS" + .asciz "interrupt::record::INTERRUPT_RECORD" .asciz "netcore::tcp::get_ephemeral_port::CURR" .asciz "netcore::udp::get_ephemeral_port::CURR" .asciz "netcore::SOCKET_SET" .asciz "netcore::LISTENING_TABLE" + .asciz "mem::manager::FRAME_REF_MANAGER" + .asciz "mem::vmm::KERNEL_SPACE" + .asciz "mem::HEAP_ALLOCATOR" .asciz "preprint::PRINT" .asciz "log::LOGGER.0" .asciz "log::LOGGER.1" - .asciz "boot::entry::STACK" + .asciz "platform::common_riscv::boot::STACK" .asciz "edata" - .asciz "kernel::board::qemu::DTB" - .asciz "sbss" .asciz "kernel::ipc::signal::TID2SIGNALS" - .asciz "kernel::device::block::BLOCK_DEVICE" - .asciz "kernel::memory::KERNEL_HEAP" - .asciz "kernel::board::BOARD_DEVICES" - .asciz "kernel::ipc::shm::SHM_MEMORY" + .asciz "sbss" .asciz "kernel::ipc::FCOUNT" + .asciz "kernel::ipc::shm::SHM_MEMORY" .asciz "kernel::task::cpu::CPU_MANAGER" - .asciz "kernel::device::uart::UART_DEVICE" - .asciz "kernel::interrupt::PLIC" - .asciz "kernel::interrupt::DEVICE_TABLE" - .asciz "kernel::ipc::pipe::PIPE_FS_ROOT" - .asciz "kernel::fs::SYSTEM_ROOT_FS" - .asciz "kernel::MACHINE_INFO" - .asciz "kernel::device::gpu::GPU_DEVICE" - .asciz "kernel::memory::frame::FRAME_ALLOCATOR" - .asciz "kernel::device::input::KEYBOARD_INPUT_DEVICE" - .asciz "kernel::device::input::MOUSE_INPUT_DEVICE" - .asciz "kernel::device::rtc::RTC_DEVICE" + .asciz "vfs::pipefs::PIPE_FS_ROOT" + .asciz "vfs::SYSTEM_ROOT_FS" + .asciz "devices::TASK_FUNC" + .asciz "devices::uart::UART_DEVICE" + .asciz "devices::gpu::GPU_DEVICE" + .asciz "devices::block::BLOCK_DEVICE" + .asciz "devices::input::KEYBOARD_INPUT_DEVICE" + .asciz "devices::input::MOUSE_INPUT_DEVICE" + .asciz "devices::rtc::RTC_DEVICE" + .asciz "interrupt::PLIC" + .asciz "interrupt::DEVICE_TABLE" + .asciz "drivers::DRIVER_TASK" .asciz "netcore::KERNEL_NET_FUNC" .asciz "netcore::NET_INTERFACE" + .asciz "mem::frame::FRAME_ALLOCATOR" + .asciz "mem::KERNEL_HEAP" + .asciz "platform::console::STDOUT" + .asciz "platform::qemu_riscv::DTB" + .asciz "platform::MACHINE_INFO" .asciz "ksync::CPUS" - .asciz "boot::STARTED.0" - .asciz "boot::CPUS" + .asciz "kernel::STARTED" + .asciz "kernel::ipc::pipe::PIPE" .asciz "__rust_alloc_error_handler_should_panic" .asciz "__rust_no_alloc_shim_is_unstable" - .asciz "kernel::panic::RECURSION" - .asciz "kernel::print::console::UART_FLAG" - .asciz "kernel::ipc::pipe::PIPE" .asciz "::registry::REGISTRY" .asciz "log::STATE" .asciz "log::MAX_LOG_LEVEL_FILTER" diff --git a/subsystems/unwinder/src/lib.rs b/subsystems/unwinder/src/lib.rs index a2dc7e03..b8a85f2a 100644 --- a/subsystems/unwinder/src/lib.rs +++ b/subsystems/unwinder/src/lib.rs @@ -1,4 +1,4 @@ #![no_std] #![feature(panic_info_message)] mod panic; -mod symbol; \ No newline at end of file +mod symbol; diff --git a/subsystems/unwinder/src/panic.rs b/subsystems/unwinder/src/panic.rs index e3d471c4..4b47b18e 100644 --- a/subsystems/unwinder/src/panic.rs +++ b/subsystems/unwinder/src/panic.rs @@ -1,93 +1,91 @@ -//! panic 处理 - - -use core::panic::PanicInfo; -use core::sync::atomic::AtomicBool; -#[cfg(all(not(feature = "debug-eh-frame"), not(feature = "debug-frame-point")))] -use tracer::CompilerTracer; -#[cfg(feature = "debug-eh-frame")] -use tracer::DwarfTracer; -#[cfg(feature = "debug-frame-point")] -use tracer::FramePointTracer; -use tracer::{Tracer, TracerProvider}; -use platform::{system_shutdown, println}; -use crate::symbol::find_symbol_with_addr; - -/// 递归标志 -static RECURSION: AtomicBool = AtomicBool::new(false); - -/// 错误处理 -/// -/// 发生 panic 是进行结果处理.目前我们会读取符号表信息,进行堆栈回溯 -#[panic_handler] -fn panic_handler(info: &PanicInfo) -> ! { - if let Some(p) = info.location() { - println!( - "line {}, file {}: {}", - p.line(), - p.file(), - info.message().unwrap() - ); - } else { - println!("no location information available"); - } - if !RECURSION.swap(true, core::sync::atomic::Ordering::SeqCst) { - back_trace(); - } - println!("!TEST FINISH!"); - system_shutdown(); -} - -#[derive(Clone)] -struct TracerProviderImpl; -impl TracerProvider for TracerProviderImpl { - fn address2symbol(&self, addr: usize) -> Option<(usize, &'static str)> { - find_symbol_with_addr(addr) - } -} - -#[cfg(feature = "debug-eh-frame")] -extern "C" { - fn kernel_eh_frame(); - fn kernel_eh_frame_end(); - fn kernel_eh_frame_hdr(); - fn kernel_eh_frame_hdr_end(); -} - -#[cfg(feature = "debug-eh-frame")] -struct DwarfProviderImpl; - -#[cfg(feature = "debug-eh-frame")] -impl DwarfProvider for DwarfProviderImpl { - fn kernel_eh_frame_hdr(&self) -> usize { - kernel_eh_frame_hdr as usize - } - - fn kernel_eh_frame(&self) -> usize { - kernel_eh_frame as usize - } - - fn kernel_eh_frame_hdr_end(&self) -> usize { - kernel_eh_frame_hdr_end as usize - } - - fn kernel_eh_frame_end(&self) -> usize { - kernel_eh_frame_end as usize - } -} - -/// 打印堆栈回溯信息 -fn back_trace() { - println!("---START BACKTRACE---"); - #[cfg(all(not(feature = "debug-eh-frame"), not(feature = "debug-frame-point")))] - let tracer = CompilerTracer::new(TracerProviderImpl); - #[cfg(feature = "debug-frame-point")] - let tracer = FramePointTracer::new(TracerProviderImpl); - #[cfg(feature = "debug-eh-frame")] - let tracer = DwarfTracer::new(DwarfProviderImpl, TracerProviderImpl); - for x in tracer.trace() { - println!("[{:#x}] (+{:0>4x}) {}", x.func_addr, x.bias, x.func_name); - } - println!("---END BACKTRACE---"); -} - +//! panic 处理 + +use crate::symbol::find_symbol_with_addr; +use core::panic::PanicInfo; +use core::sync::atomic::AtomicBool; +use platform::{println, system_shutdown}; +#[cfg(all(not(feature = "debug-eh-frame"), not(feature = "debug-frame-point")))] +use tracer::CompilerTracer; +#[cfg(feature = "debug-eh-frame")] +use tracer::DwarfTracer; +#[cfg(feature = "debug-frame-point")] +use tracer::FramePointTracer; +use tracer::{Tracer, TracerProvider}; + +/// 递归标志 +static RECURSION: AtomicBool = AtomicBool::new(false); + +/// 错误处理 +/// +/// 发生 panic 是进行结果处理.目前我们会读取符号表信息,进行堆栈回溯 +#[panic_handler] +fn panic_handler(info: &PanicInfo) -> ! { + if let Some(p) = info.location() { + println!( + "line {}, file {}: {}", + p.line(), + p.file(), + info.message().unwrap() + ); + } else { + println!("no location information available"); + } + if !RECURSION.swap(true, core::sync::atomic::Ordering::SeqCst) { + back_trace(); + } + println!("!TEST FINISH!"); + system_shutdown(); +} + +#[derive(Clone)] +struct TracerProviderImpl; +impl TracerProvider for TracerProviderImpl { + fn address2symbol(&self, addr: usize) -> Option<(usize, &'static str)> { + find_symbol_with_addr(addr) + } +} + +#[cfg(feature = "debug-eh-frame")] +extern "C" { + fn kernel_eh_frame(); + fn kernel_eh_frame_end(); + fn kernel_eh_frame_hdr(); + fn kernel_eh_frame_hdr_end(); +} + +#[cfg(feature = "debug-eh-frame")] +struct DwarfProviderImpl; + +#[cfg(feature = "debug-eh-frame")] +impl DwarfProvider for DwarfProviderImpl { + fn kernel_eh_frame_hdr(&self) -> usize { + kernel_eh_frame_hdr as usize + } + + fn kernel_eh_frame(&self) -> usize { + kernel_eh_frame as usize + } + + fn kernel_eh_frame_hdr_end(&self) -> usize { + kernel_eh_frame_hdr_end as usize + } + + fn kernel_eh_frame_end(&self) -> usize { + kernel_eh_frame_end as usize + } +} + +/// 打印堆栈回溯信息 +fn back_trace() { + println!("---START BACKTRACE---"); + #[cfg(all(not(feature = "debug-eh-frame"), not(feature = "debug-frame-point")))] + let tracer = CompilerTracer::new(TracerProviderImpl); + #[cfg(feature = "debug-frame-point")] + let tracer = FramePointTracer::new(TracerProviderImpl); + #[cfg(feature = "debug-eh-frame")] + let tracer = DwarfTracer::new(DwarfProviderImpl, TracerProviderImpl); + for x in tracer.trace() { + println!("[{:#x}] (+{:0>4x}) {}", x.func_addr, x.bias, x.func_name); + } + println!("---END BACKTRACE---"); +} diff --git a/subsystems/vfs/Cargo.toml b/subsystems/vfs/Cargo.toml index 9e7208b8..1b083864 100644 --- a/subsystems/vfs/Cargo.toml +++ b/subsystems/vfs/Cargo.toml @@ -14,7 +14,7 @@ constants = { path = "../constants" } interrupt = { path = "../interrupt" } platform = { path = "../platform" } - +downcast-rs = { version = "1.2.0", default-features = false } vfscore = { git = "https://github.com/os-module/rvfs.git", features = [ "linux_error", ] } diff --git a/subsystems/vfs/src/dev/mod.rs b/subsystems/vfs/src/dev/mod.rs index 8c833014..fdb51df8 100644 --- a/subsystems/vfs/src/dev/mod.rs +++ b/subsystems/vfs/src/dev/mod.rs @@ -1,13 +1,13 @@ -use devices::{ - BLKDevice, GPUDevice, INPUTDevice, RTCDevice, UARTDevice, BLOCK_DEVICE, GPU_DEVICE, - KEYBOARD_INPUT_DEVICE, MOUSE_INPUT_DEVICE, RTC_DEVICE, UART_DEVICE, -}; use alloc::collections::BTreeMap; use alloc::sync::Arc; use constants::DeviceId; use devfs::DevKernelProvider; -use log::info; +use devices::{ + BLKDevice, GPUDevice, INPUTDevice, RTCDevice, UARTDevice, BLOCK_DEVICE, GPU_DEVICE, + KEYBOARD_INPUT_DEVICE, MOUSE_INPUT_DEVICE, RTC_DEVICE, UART_DEVICE, +}; use ksync::Mutex; +use log::info; use null::NullDevice; use random::RandomDevice; use spin::Lazy; diff --git a/subsystems/vfs/src/kfile.rs b/subsystems/vfs/src/kfile.rs new file mode 100644 index 00000000..2016a37f --- /dev/null +++ b/subsystems/vfs/src/kfile.rs @@ -0,0 +1,272 @@ +use alloc::sync::Arc; +use constants::io::{Dirent64, DirentType, OpenFlags, PollEvents, SeekFrom}; +use constants::AlienResult; +use constants::LinuxErrno; +use core::fmt::{Debug, Formatter}; +use downcast_rs::{impl_downcast, DowncastSync}; +use ksync::Mutex; +use vfscore::dentry::VfsDentry; +use vfscore::error::VfsError; +use vfscore::inode::VfsInode; +use vfscore::path::VfsPath; +use vfscore::utils::{VfsFileStat, VfsNodeType, VfsPollEvents}; + +pub struct KernelFile { + pos: Mutex, + open_flag: Mutex, + dentry: Arc, +} + +impl Debug for KernelFile { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("KernelFile") + .field("pos", &self.pos) + .field("open_flag", &self.open_flag) + .field("name", &self.dentry.name()) + .finish() + } +} + +impl KernelFile { + pub fn new(dentry: Arc, open_flag: OpenFlags) -> Self { + let pos = if open_flag.contains(OpenFlags::O_APPEND) { + dentry.inode().unwrap().get_attr().unwrap().st_size + } else { + 0 + }; + Self { + pos: Mutex::new(pos), + open_flag: Mutex::new(open_flag), + dentry, + } + } +} + +pub trait File: DowncastSync + Debug { + fn read(&self, buf: &mut [u8]) -> AlienResult; + fn write(&self, buf: &[u8]) -> AlienResult; + fn read_at(&self, _offset: u64, _buf: &mut [u8]) -> AlienResult { + Err(LinuxErrno::ENOSYS) + } + fn write_at(&self, _offset: u64, _buf: &[u8]) -> AlienResult { + Err(LinuxErrno::ENOSYS) + } + fn flush(&self) -> AlienResult<()> { + Ok(()) + } + fn fsync(&self) -> AlienResult<()> { + Ok(()) + } + fn seek(&self, pos: SeekFrom) -> AlienResult; + /// Gets the file attributes. + fn get_attr(&self) -> AlienResult; + fn ioctl(&self, _cmd: u32, _arg: usize) -> AlienResult { + Err(LinuxErrno::ENOSYS) + } + fn set_open_flag(&self, _flag: OpenFlags) {} + fn get_open_flag(&self) -> OpenFlags { + OpenFlags::O_RDONLY + } + fn dentry(&self) -> Arc; + fn inode(&self) -> Arc; + fn readdir(&self, _buf: &mut [u8]) -> AlienResult { + Err(LinuxErrno::ENOSYS) + } + fn truncate(&self, _len: u64) -> AlienResult<()> { + Err(LinuxErrno::ENOSYS) + } + fn is_readable(&self) -> bool; + fn is_writable(&self) -> bool; + fn is_append(&self) -> bool; + fn poll(&self, _event: PollEvents) -> AlienResult { + Err(LinuxErrno::ENOSYS) + } +} + +impl_downcast!(sync File); + +// todo! permission check +impl File for KernelFile { + fn read(&self, buf: &mut [u8]) -> AlienResult { + if buf.len() == 0 { + return Ok(0); + } + // warn!("[read] is_interrupt_enable:{}",is_interrupt_enable()); + let pos = *self.pos.lock(); + // warn!("[read] is_interrupt_enable:{}",is_interrupt_enable()); + let read = self.read_at(pos, buf)?; + *self.pos.lock() += read as u64; + Ok(read) + } + fn write(&self, buf: &[u8]) -> AlienResult { + if buf.len() == 0 { + return Ok(0); + } + let mut pos = self.pos.lock(); + let write = self.write_at(*pos, buf)?; + *pos += write as u64; + Ok(write) + } + fn read_at(&self, offset: u64, buf: &mut [u8]) -> AlienResult { + if buf.len() == 0 { + return Ok(0); + } + let open_flag = self.open_flag.lock(); + if !open_flag.contains(OpenFlags::O_RDONLY) && !open_flag.contains(OpenFlags::O_RDWR) { + return Err(LinuxErrno::EPERM); + } + drop(open_flag); + let inode = self.dentry.inode()?; + let read = inode.read_at(offset, buf)?; + Ok(read) + } + + fn write_at(&self, _offset: u64, buf: &[u8]) -> AlienResult { + if buf.len() == 0 { + return Ok(0); + } + let open_flag = self.open_flag.lock(); + if !open_flag.contains(OpenFlags::O_WRONLY) && !open_flag.contains(OpenFlags::O_RDWR) { + return Err(LinuxErrno::EPERM); + } + let inode = self.dentry.inode()?; + let write = inode.write_at(_offset, buf)?; + Ok(write) + } + + fn flush(&self) -> AlienResult<()> { + let open_flag = self.open_flag.lock(); + if !open_flag.contains(OpenFlags::O_WRONLY) & !open_flag.contains(OpenFlags::O_RDWR) { + return Err(LinuxErrno::EPERM); + } + let inode = self.dentry.inode()?; + inode.flush()?; + Ok(()) + } + + fn fsync(&self) -> AlienResult<()> { + let open_flag = self.open_flag.lock(); + if !open_flag.contains(OpenFlags::O_WRONLY) && !open_flag.contains(OpenFlags::O_RDWR) { + return Err(LinuxErrno::EPERM); + } + let inode = self.dentry.inode()?; + inode.fsync()?; + Ok(()) + } + + // check for special file + fn seek(&self, pos: SeekFrom) -> AlienResult { + let mut spos = self.pos.lock(); + let size = self.get_attr()?.st_size; + let new_offset = match pos { + SeekFrom::Start(pos) => Some(pos), + SeekFrom::Current(off) => spos.checked_add_signed(off), + SeekFrom::End(off) => size.checked_add_signed(off), + } + .ok_or_else(|| VfsError::Invalid)?; + *spos = new_offset; + Ok(new_offset) + } + + /// Gets the file attributes. + fn get_attr(&self) -> AlienResult { + self.dentry.inode()?.get_attr().map_err(Into::into) + } + + fn ioctl(&self, _cmd: u32, _arg: usize) -> AlienResult { + let inode = self.dentry.inode().unwrap(); + inode.ioctl(_cmd, _arg).map_err(Into::into) + } + + fn set_open_flag(&self, flag: OpenFlags) { + *self.open_flag.lock() = flag; + } + + fn get_open_flag(&self) -> OpenFlags { + *self.open_flag.lock() + } + fn dentry(&self) -> Arc { + self.dentry.clone() + } + fn inode(&self) -> Arc { + self.dentry.inode().unwrap() + } + fn readdir(&self, buf: &mut [u8]) -> AlienResult { + let inode = self.inode(); + let mut pos = self.pos.lock(); + let mut count = 0; + let mut ptr = buf.as_mut_ptr(); + loop { + let dirent = inode.readdir(*pos as usize).map_err(|e| { + *pos = 0; + e + })?; + match dirent { + Some(d) => { + let dirent64 = + Dirent64::new(&d.name, d.ino, *pos as i64, vfsnodetype2dirent64(d.ty)); + if count + dirent64.len() <= buf.len() { + let dirent_ptr = unsafe { &mut *(ptr as *mut Dirent64) }; + *dirent_ptr = dirent64; + let name_ptr = dirent_ptr.name.as_mut_ptr(); + unsafe { + let mut name = d.name.clone(); + name.push('\0'); + let len = name.len(); + name_ptr.copy_from(name.as_ptr(), len); + ptr = ptr.add(dirent_ptr.len()); + } + count += dirent_ptr.len(); + } else { + break; + } // Buf is small + } + None => { + break; + } // EOF + } + *pos += 1; + } + Ok(count) + } + fn truncate(&self, len: u64) -> AlienResult<()> { + let open_flag = self.open_flag.lock(); + if !open_flag.contains(OpenFlags::O_WRONLY) & !open_flag.contains(OpenFlags::O_RDWR) { + return Err(LinuxErrno::EINVAL); + } + let dt = self.dentry(); + VfsPath::new(dt).truncate(len).map_err(Into::into) + } + fn is_readable(&self) -> bool { + let open_flag = self.open_flag.lock(); + open_flag.contains(OpenFlags::O_RDONLY) | open_flag.contains(OpenFlags::O_RDWR) + } + fn is_writable(&self) -> bool { + let open_flag = self.open_flag.lock(); + open_flag.contains(OpenFlags::O_WRONLY) | open_flag.contains(OpenFlags::O_RDWR) + } + + fn is_append(&self) -> bool { + let open_flag = self.open_flag.lock(); + open_flag.contains(OpenFlags::O_APPEND) + } + + fn poll(&self, _event: PollEvents) -> AlienResult { + let inode = self.dentry.inode()?; + let res = inode + .poll(VfsPollEvents::from_bits_truncate(_event.bits())) + .map(|e| PollEvents::from_bits_truncate(e.bits())); + res.map_err(Into::into) + } +} + +fn vfsnodetype2dirent64(ty: VfsNodeType) -> DirentType { + DirentType::from_u8(ty as u8) +} + +impl Drop for KernelFile { + fn drop(&mut self) { + let _ = self.flush(); + let _ = self.fsync(); + } +} diff --git a/subsystems/vfs/src/lib.rs b/subsystems/vfs/src/lib.rs index 35604a15..2dd4f54f 100644 --- a/subsystems/vfs/src/lib.rs +++ b/subsystems/vfs/src/lib.rs @@ -16,18 +16,19 @@ use spin::{Lazy, Once}; use vfscore::dentry::VfsDentry; use vfscore::fstype::VfsFsType; use vfscore::path::VfsPath; -use vfscore::utils::{VfsTimeSpec}; +use vfscore::utils::VfsTimeSpec; pub mod dev; +pub mod kfile; +pub mod pipefs; pub mod proc; pub mod ram; pub mod sys; -pub mod pipefs; pub static FS: Lazy>>> = Lazy::new(|| Mutex::new(BTreeMap::new())); -pub static SYSTEM_ROOT_FS: Once> = Once::new(); +static SYSTEM_ROOT_FS: Once> = Once::new(); type SysFs = dynfs::DynFs>; type ProcFs = dynfs::DynFs>; @@ -131,3 +132,20 @@ impl core::fmt::Write for VfsOutPut { } } +/// Get the root filesystem of the system +#[inline] +pub fn system_root_fs() -> Arc { + SYSTEM_ROOT_FS.get().unwrap().clone() +} + +/// Get the filesystem by name +#[inline] +pub fn system_support_fs(fs_name: &str) -> Option> { + FS.lock().iter().find_map(|(name, fs)| { + if name == fs_name { + Some(fs.clone()) + } else { + None + } + }) +} diff --git a/subsystems/vfs/src/pipefs.rs b/subsystems/vfs/src/pipefs.rs index cb1fe1d5..eeaca02a 100644 --- a/subsystems/vfs/src/pipefs.rs +++ b/subsystems/vfs/src/pipefs.rs @@ -1,20 +1,20 @@ -use alloc::sync::Arc; -use dynfs::DynFsDirInode; -use spin::Once; -use vfscore::dentry::VfsDentry; -use vfscore::fstype::VfsFsType; -use constants::io::MountFlags; - -use ksync::Mutex; -use crate::CommonFsProviderImpl; - -pub type PipeFsDirInodeImpl = DynFsDirInode>; -pub static PIPE_FS_ROOT: Once> = Once::new(); - -pub fn init_pipefs(fs: Arc) { - let root = fs - .i_mount(MountFlags::empty().bits(), "", None, &[]) - .unwrap(); - PIPE_FS_ROOT.call_once(|| root); - println!("pipefs init success"); -} \ No newline at end of file +use alloc::sync::Arc; +use constants::io::MountFlags; +use dynfs::DynFsDirInode; +use spin::Once; +use vfscore::dentry::VfsDentry; +use vfscore::fstype::VfsFsType; + +use crate::CommonFsProviderImpl; +use ksync::Mutex; + +pub type PipeFsDirInodeImpl = DynFsDirInode>; +pub static PIPE_FS_ROOT: Once> = Once::new(); + +pub fn init_pipefs(fs: Arc) { + let root = fs + .i_mount(MountFlags::empty().bits(), "", None, &[]) + .unwrap(); + PIPE_FS_ROOT.call_once(|| root); + println!("pipefs init success"); +} diff --git a/subsystems/vfs/src/ram/mod.rs b/subsystems/vfs/src/ram/mod.rs index 8f688408..002e06c0 100644 --- a/subsystems/vfs/src/ram/mod.rs +++ b/subsystems/vfs/src/ram/mod.rs @@ -3,7 +3,6 @@ use vfscore::dentry::VfsDentry; use vfscore::fstype::VfsFsType; use vfscore::utils::VfsNodeType; - /// /// ```bash /// | From 2e8213ece80b1667d2c69ed5e92d3423106ee0ad Mon Sep 17 00:00:00 2001 From: Godones <1925466036@qq.com> Date: Tue, 16 Jan 2024 22:43:07 +0800 Subject: [PATCH 4/5] update doc --- README.md | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index bc319168..1c692a51 100644 --- a/README.md +++ b/README.md @@ -57,36 +57,43 @@ A simple operating system implemented in rust. The purpose is to explore how to 2. install rust nightly ``` -make run LOG= SMP=1 +# 一键运行 +# 可以指定LOG=ERROR/WARN/INFO/DEBUG/TRACE开启调式 +make run [LOG=] [SMP=] +``` + +构建测试程序镜像: + +``` +make sdcard [GUI=n/y] ``` 如果只想重新构建`kernel`而不改变测试程序,可以使用: ``` -make build LOG= SMP=1 +make build LOG= [LOG=] [SMP=] ``` 使用已经编译好的程序运行而不是再次编译可以使用: ``` -make fake_run SMP=1 +# 确保和make build的SMP一致 +make fake_run [SMP=] ``` -可以指定LOG=ERROR/WARN/INFO/DEBUG/TRACE开启调式 - 运行测试(in bash) ``` > cd bin +> ls > final_test ``` - - -### Run with Gui +### Run with GUI (QEMU) ``` -make run LOG= SMP=1 GUI=y +make run GUI=y +cd bin slint or guitest or todo or printdemo or memorygame or ... ``` @@ -112,8 +119,8 @@ make unmatched LOG= UNMATCHED=y SMP=2 ## GDB -1. `gdb-server` -2. `gdb-client` +1. `make gdb-server` +2. `make gdb-client` ## [Doc](docs/doc/doc.md) From b470f78123e7ca1038a45717cc5b42b664c9a841 Mon Sep 17 00:00:00 2001 From: Godones <1925466036@qq.com> Date: Wed, 17 Jan 2024 10:50:05 +0800 Subject: [PATCH 5/5] update toolchain version --- kernel/src/task/schedule.rs | 44 +++++++++++++++---------------------- rust-toolchain.toml | 2 +- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/kernel/src/task/schedule.rs b/kernel/src/task/schedule.rs index f35e0e38..7dfaf768 100644 --- a/kernel/src/task/schedule.rs +++ b/kernel/src/task/schedule.rs @@ -23,36 +23,28 @@ use crate::trap::check_timer_interrupt_pending; /// 否则该 CPU 将进入等待状态,等待其它核的中断信号。 pub fn run_task() -> ! { loop { - { - let cpu = current_cpu(); - if cpu.task.is_some() { - let task = cpu.task.take().unwrap(); - match task.state() { - TaskState::Waiting => { - // drop(task); - } - TaskState::Zombie => { - // 退出时向父进程发送信号,其中选项可被 sys_clone 控制 - if task.send_sigchld_when_exit || task.pid == task.tid.0 { - let parent = task - .access_inner() - .parent - .clone() - .unwrap() - .upgrade() - .unwrap(); - send_signal(parent.pid, SignalNumber::SIGCHLD as usize); - } - // 通知全局表将 signals 删除 - task.terminate(); - } - _ => { - GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); + let cpu = current_cpu(); + if cpu.task.is_some() { + let task = cpu.task.take().unwrap(); + match task.state() { + TaskState::Waiting => { + // drop(task); + } + TaskState::Zombie => { + // 退出时向父进程发送信号,其中选项可被 sys_clone 控制 + if task.send_sigchld_when_exit || task.pid == task.tid.0 { + let parent = task + .access_inner() + .parent.as_ref().unwrap().upgrade().unwrap(); + send_signal(parent.pid, SignalNumber::SIGCHLD as usize); } + task.terminate(); + } + _ => { + GLOBAL_TASK_MANAGER.add_task(Arc::new(FifoTask::new(task))); } } } - let cpu = current_cpu(); if let Some(task) = GLOBAL_TASK_MANAGER.pick_next_task() { // if process.get_tid() >= 1 { // warn!("switch to task {}", task.get_tid()); diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 34757309..dad58ce0 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2023-11-05" +channel = "nightly-2023-12-01" components = ["rust-src", "llvm-tools-preview", "rustfmt", "clippy"] targets = ["riscv64gc-unknown-none-elf"]