├── bootloader ├── .gitignore ├── OVMF.fd ├── .cargo │ └── config ├── cargo.toml └── src │ ├── lib.rs │ ├── main.rs │ └── page_table.rs ├── kernel ├── .gitignore ├── src │ ├── board │ │ ├── timer.rs │ │ ├── mod.rs │ │ ├── mouse.rs │ │ ├── keyboard.rs │ │ ├── cpu.rs │ │ └── acpi_table.rs │ ├── drivers │ │ ├── bus │ │ │ ├── mod.rs │ │ │ └── pci.rs │ │ ├── block │ │ │ ├── mod.rs │ │ │ └── ahci.rs │ │ ├── serial │ │ │ └── mod.rs │ │ ├── gpu │ │ │ └── mod.rs │ │ ├── provider.rs │ │ └── mod.rs │ ├── memory │ │ ├── heap.rs │ │ └── mod.rs │ ├── console │ │ ├── io.rs │ │ └── mod.rs │ ├── task │ │ ├── mod.rs │ │ ├── keyboard.rs │ │ └── executor.rs │ ├── lang.rs │ ├── fs │ │ ├── mod.rs │ │ └── inode_ext.rs │ ├── main.rs │ ├── mal │ │ ├── printer.rs │ │ ├── env.rs │ │ ├── types.rs │ │ ├── core.rs │ │ ├── reader.rs │ │ └── mod.rs │ ├── interrupts │ │ └── mod.rs │ └── shell.rs ├── .cargo │ ├── config │ ├── linker-amd64.ld │ └── amd64.json └── cargo.toml ├── uefi.png ├── .gitignore ├── j-file.png ├── juneros.png ├── user ├── core.jmal ├── entry.jmal └── hello.jmal ├── Cargo.toml ├── Readme_zh_CN.md ├── Makefile ├── README_OLD.md ├── README.md ├── grammar_zh.md └── grammar.md /bootloader/.gitignore: -------------------------------------------------------------------------------- 1 | /target -------------------------------------------------------------------------------- /kernel/.gitignore: -------------------------------------------------------------------------------- 1 | /target -------------------------------------------------------------------------------- /kernel/src/board/timer.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /kernel/src/drivers/bus/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod pci; 2 | -------------------------------------------------------------------------------- /uefi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhgithub/juner_os/HEAD/uefi.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | /build 4 | Cargo.lock 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /j-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhgithub/juner_os/HEAD/j-file.png -------------------------------------------------------------------------------- /juneros.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhgithub/juner_os/HEAD/juneros.png -------------------------------------------------------------------------------- /bootloader/OVMF.fd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhgithub/juner_os/HEAD/bootloader/OVMF.fd -------------------------------------------------------------------------------- /kernel/src/board/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod acpi_table; 2 | pub mod cpu; 3 | pub mod timer; 4 | pub mod keyboard; 5 | pub mod mouse; -------------------------------------------------------------------------------- /user/core.jmal: -------------------------------------------------------------------------------- 1 | ;;; core lib 2 | 3 | ;; fun def defun! 4 | 5 | (defmacro! defun! (lambda [fun_name params body] 6 | `(def! ~fun_name (lambda ~params ~body)))) 7 | 8 | -------------------------------------------------------------------------------- /user/entry.jmal: -------------------------------------------------------------------------------- 1 | ;;; the entry of junner os load module of lisp 2 | 3 | (def! load (lambda [name] (load-file (str name ".jmal")))) 4 | 5 | ;; load core function 6 | (load "core") 7 | 8 | -------------------------------------------------------------------------------- /user/hello.jmal: -------------------------------------------------------------------------------- 1 | (+ 1 1) 2 | (def! say-hello (lambda [x] 3 | (prn (str 4 | "Hello " 5 | x 6 | "! this func load mal !" )))) 7 | ;; 测试 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "bootloader", 4 | "kernel", 5 | ] 6 | 7 | 8 | [profile.dev] 9 | panic = "abort" 10 | 11 | [profile.release] 12 | panic = "abort" -------------------------------------------------------------------------------- /bootloader/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "x86_64-unknown-uefi" 3 | 4 | [unstable] 5 | build-std = ["core","alloc", "compiler_builtins"] 6 | build-std-features = ["compiler-builtins-mem"] -------------------------------------------------------------------------------- /kernel/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = ".cargo/amd64.json" 3 | 4 | [unstable] 5 | build-std = ["core","alloc", "compiler_builtins"] 6 | build-std-features = ["compiler-builtins-mem"] 7 | -------------------------------------------------------------------------------- /kernel/src/drivers/block/mod.rs: -------------------------------------------------------------------------------- 1 | use super::Driver; 2 | pub mod ahci; 3 | 4 | pub trait BlockDriver: Driver { 5 | fn read_block(&self, _block_id: usize, _buf: &mut [u8]) -> bool { 6 | unimplemented!("not a block driver") 7 | } 8 | 9 | fn write_block(&self, _block_id: usize, _buf: &[u8]) -> bool { 10 | unimplemented!("not a block driver") 11 | } 12 | } 13 | 14 | 15 | -------------------------------------------------------------------------------- /kernel/.cargo/linker-amd64.ld: -------------------------------------------------------------------------------- 1 | KERNEL_BEGIN = 0xffffff0000000000; 2 | 3 | SECTIONS { 4 | 5 | . = KERNEL_BEGIN; 6 | 7 | .text ALIGN(4K): 8 | { 9 | *(.text .text.*) 10 | } 11 | 12 | .data ALIGN(4K): 13 | { 14 | *(.data .data.*) 15 | } 16 | 17 | .got ALIGN(4K): 18 | { 19 | *(.got .got.*) 20 | } 21 | 22 | .bss ALIGN(4K): 23 | { 24 | *(.bss .bss.*) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bootloader/cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bootloader" 3 | version = "1.0.0" 4 | authors = ["zzhgithub "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | uefi = "0.6.0" 11 | uefi-services = { version = "0.3.0", optional = true } 12 | log = "0.4.11" 13 | uart_16550 = "0.2.10" 14 | xmas-elf = "0.7.0" 15 | x86_64 = "0.12.2" 16 | 17 | [features] 18 | boot = ["uefi-services"] 19 | default = ["boot"] -------------------------------------------------------------------------------- /kernel/src/memory/heap.rs: -------------------------------------------------------------------------------- 1 | use crate::memory::HEAP_ALLOCATOR; 2 | use core::mem; 3 | 4 | pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024; 5 | const MACHINE_ALGIN: usize = mem::size_of::(); 6 | const HEAP_BLOCK: usize = KERNEL_HEAP_SIZE / MACHINE_ALGIN; 7 | 8 | pub fn init_heap() { 9 | static mut HEAP: [usize; HEAP_BLOCK] = [0; HEAP_BLOCK]; 10 | unsafe { 11 | HEAP_ALLOCATOR 12 | .lock() 13 | .init(HEAP.as_ptr() as usize, HEAP_BLOCK * MACHINE_ALGIN); 14 | } 15 | // println!("Init Heap"); 16 | } 17 | -------------------------------------------------------------------------------- /kernel/.cargo/amd64.json: -------------------------------------------------------------------------------- 1 | { 2 | "llvm-target": "x86_64-unknown-none", 3 | "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", 4 | "linker-flavor": "ld.lld", 5 | "target-endian": "little", 6 | "target-pointer-width": "64", 7 | "target-c-int-width": "32", 8 | "arch": "x86_64", 9 | "os": "none", 10 | "executables": true, 11 | "dynamic-linking": true, 12 | "linker": "rust-lld", 13 | "pre-link-args": { 14 | "ld.lld": [ 15 | "-Tkernel/.cargo/linker-amd64.ld", 16 | "-export-dynamic" 17 | ] 18 | }, 19 | "disable-redzone": true, 20 | "features": "-mmx,-sse,+soft-float", 21 | "panic-strategy": "abort", 22 | "eliminate-frame-pointer": false 23 | } 24 | -------------------------------------------------------------------------------- /kernel/src/board/mouse.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use ps2_mouse::{Mouse, MouseState}; 3 | use spin::Mutex; 4 | use x86_64::instructions::port::PortReadOnly; 5 | 6 | lazy_static! { 7 | pub static ref MOUSE: Mutex = Mutex::new(Mouse::new()); 8 | } 9 | 10 | // 初始化鼠标配置 11 | pub fn init_mouse() { 12 | MOUSE.lock().init().unwrap(); 13 | MOUSE.lock().set_on_complete(on_complete); 14 | } 15 | 16 | // This will be fired when a packet is finished being processed. 17 | fn on_complete(mouse_state: MouseState) { 18 | // 当你要进行鼠标的操作时 要处理这行 19 | // println!("{:?}", mouse_state); 20 | } 21 | 22 | pub fn mouse() { 23 | let mut port = PortReadOnly::new(0x60); 24 | let packet = unsafe { port.read() }; 25 | MOUSE.lock().process_packet(packet); 26 | } 27 | -------------------------------------------------------------------------------- /kernel/src/console/io.rs: -------------------------------------------------------------------------------- 1 | use crate::drivers::gpu::CONSOLE; 2 | use crate::drivers::serial::COM1; 3 | use core::fmt::{Arguments, Write}; 4 | 5 | pub fn getchar() -> u8 { 6 | unsafe { 7 | COM1.force_unlock(); 8 | } 9 | COM1.lock().receive() as u8 10 | } 11 | 12 | pub fn putfmt(fmt: Arguments) { 13 | // Out put Serial 14 | unsafe { 15 | COM1.force_unlock(); 16 | } 17 | COM1.lock().write_fmt(fmt).unwrap(); 18 | 19 | // Out put graphic 20 | unsafe { 21 | CONSOLE.force_unlock(); 22 | } 23 | 24 | if let Some(console) = CONSOLE.lock().as_mut() { 25 | console.write_fmt(fmt).unwrap(); 26 | } 27 | } 28 | 29 | pub fn clear_screen() { 30 | unsafe { CONSOLE.force_unlock() } 31 | if let Some(console) = CONSOLE.lock().as_mut() { 32 | console.clear(); 33 | } 34 | } -------------------------------------------------------------------------------- /kernel/src/drivers/serial/mod.rs: -------------------------------------------------------------------------------- 1 | use spin::Mutex; 2 | use uart_16550::SerialPort; 3 | use alloc::vec::Vec; 4 | use lazy_static::*; 5 | use alloc::collections::VecDeque; 6 | use alloc::boxed::Box; 7 | 8 | pub static COM1: Mutex = Mutex::new(unsafe { SerialPort::new(0x3F8) }); 9 | pub static COM2: Mutex = Mutex::new(unsafe { SerialPort::new(0x2F8) }); 10 | 11 | 12 | lazy_static! { 13 | static ref STDIN: Mutex> = Mutex::new(VecDeque::new()); 14 | static ref STDIN_CALLBACK: Mutex bool + Send + Sync>>> = Mutex::new(Vec::new()); 15 | } 16 | 17 | pub fn init() { 18 | COM1.lock().init(); 19 | COM2.lock().init(); 20 | println!("Init Serial"); 21 | } 22 | 23 | /// Put a char by serial interrupt handler. 24 | pub fn serial_put(mut x: u8) { 25 | if x == b'\r' { 26 | x = b'\n'; 27 | } 28 | STDIN.lock().push_back(x); 29 | STDIN_CALLBACK.lock().retain(|f| !f()); 30 | } -------------------------------------------------------------------------------- /kernel/src/task/mod.rs: -------------------------------------------------------------------------------- 1 | use alloc::boxed::Box; 2 | use core::{ 3 | future::Future, 4 | pin::Pin, 5 | sync::atomic::{AtomicU64, Ordering}, 6 | task::{Context, Poll}, 7 | }; 8 | 9 | pub mod executor; 10 | pub mod keyboard; 11 | 12 | pub struct Task { 13 | id: TaskId, 14 | future: Pin>>, 15 | } 16 | 17 | impl Task { 18 | pub fn new(future: impl Future + 'static) -> Task { 19 | Task { 20 | id: TaskId::new(), 21 | future: Box::pin(future), 22 | } 23 | } 24 | 25 | fn poll(&mut self, context: &mut Context) -> Poll<()> { 26 | self.future.as_mut().poll(context) 27 | } 28 | } 29 | 30 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 31 | struct TaskId(u64); 32 | 33 | impl TaskId { 34 | fn new() -> Self { 35 | static NEXT_ID: AtomicU64 = AtomicU64::new(0); 36 | TaskId(NEXT_ID.fetch_add(1, Ordering::Relaxed)) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /kernel/src/board/keyboard.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; 3 | use spin::Mutex; 4 | use x86_64::instructions::port::Port; 5 | 6 | /// Receive character from keyboard 7 | /// Should be called on every interrupt 8 | pub fn receive() -> Option { 9 | lazy_static! { 10 | static ref KEYBOARD: Mutex> = Mutex::new( 11 | Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::Ignore) 12 | ); 13 | } 14 | 15 | let mut keyboard = KEYBOARD.lock(); 16 | let mut data_port = Port::::new(0x60); 17 | let mut status_port = Port::::new(0x64); 18 | 19 | // Output buffer status = 1 20 | if unsafe { status_port.read() } & 1 != 0 { 21 | let scancode = unsafe { data_port.read() }; 22 | if let Ok(Some(key_event)) = keyboard.add_byte(scancode) { 23 | return keyboard.process_keyevent(key_event); 24 | } 25 | } 26 | None 27 | } 28 | -------------------------------------------------------------------------------- /kernel/src/lang.rs: -------------------------------------------------------------------------------- 1 | use core::alloc::Layout; 2 | use core::panic::PanicInfo; 3 | 4 | #[panic_handler] 5 | pub fn panic(info: &PanicInfo) -> ! { 6 | print!("\n\n"); 7 | print!(31;r" 8 | 9 | 10 | 11 | IIIIIIII III OO III II IIIIIIIIIIII 12 | II II II II IIII II II 13 | II II II II II II II II II 14 | II II IIIIIIIIII II II II II II 15 | IIIIIIII II II II II II II II 16 | II II II II II IIII II 17 | II II II II II III IIIIIIIIIIIII 18 | 19 | 20 | 21 | "); 22 | println!("{}", info); 23 | loop {} 24 | } 25 | 26 | #[no_mangle] 27 | extern "C" fn abort() -> ! { 28 | panic!("abort!"); 29 | } 30 | 31 | #[lang = "oom"] 32 | pub fn oom(layout: Layout) -> ! { 33 | panic!("Memory allocation of {} bytes failed", layout.size()); 34 | } 35 | 36 | #[lang = "eh_personality"] 37 | #[no_mangle] 38 | pub fn eh_personality() -> ! { 39 | loop {} 40 | } 41 | -------------------------------------------------------------------------------- /kernel/src/board/cpu.rs: -------------------------------------------------------------------------------- 1 | use core::sync::atomic::{spin_loop_hint, AtomicBool, Ordering}; 2 | use raw_cpuid::CpuId; 3 | use x86_64::registers::control::{Cr0, Cr0Flags, Cr4, Cr4Flags}; 4 | 5 | pub static AP_CAN_INIT: AtomicBool = AtomicBool::new(false); 6 | 7 | pub fn init_cpu() { 8 | let cpu_id = CpuId::new() 9 | .get_feature_info() 10 | .unwrap() 11 | .initial_local_apic_id() as usize; 12 | println!("I'm from {} cpu", cpu_id); 13 | if cpu_id != 0 { 14 | while !AP_CAN_INIT.load(Ordering::Relaxed) { 15 | spin_loop_hint(); 16 | } 17 | println!("I'm Two!"); 18 | } 19 | let cpuid = CpuId::new(); 20 | if let Some(vendor_info) = cpuid.get_vendor_info() { 21 | println!("CPU {}", vendor_info); 22 | } 23 | 24 | unsafe { 25 | Cr4::update(|cr4| { 26 | // enable fxsave/fxrstor 27 | cr4.insert(Cr4Flags::OSFXSR); 28 | // sse 29 | cr4.insert(Cr4Flags::OSXMMEXCPT_ENABLE); 30 | }); 31 | Cr0::update(|cr0| { 32 | // enable fpu 33 | cr0.remove(Cr0Flags::EMULATE_COPROCESSOR); 34 | cr0.insert(Cr0Flags::MONITOR_COPROCESSOR); 35 | }); 36 | } 37 | 38 | // wake up other CPUs 39 | AP_CAN_INIT.store(true, Ordering::Relaxed); 40 | test!("Init CPU and FPU"); 41 | test!("init CPU"); 42 | } 43 | -------------------------------------------------------------------------------- /kernel/src/drivers/gpu/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::memory::phys_to_virt; 2 | use bootloader::BootInfo; 3 | use rcore_console::{Console, ConsoleOnGraphic, DrawTarget, Pixel, Rgb888, Size}; 4 | use spin::Mutex; 5 | 6 | pub static CONSOLE: Mutex>> = Mutex::new(None); 7 | 8 | pub struct Framebuffer { 9 | width: usize, 10 | height: usize, 11 | buf: &'static mut [u32], 12 | } 13 | 14 | impl DrawTarget for Framebuffer { 15 | type Error = core::convert::Infallible; 16 | 17 | fn draw_pixel(&mut self, item: Pixel) -> Result<(), Self::Error> { 18 | let idx = item.0.x as usize + item.0.y as usize * self.width; 19 | self.buf[idx] = unsafe { core::mem::transmute(item.1) }; 20 | Ok(()) 21 | } 22 | 23 | fn size(&self) -> Size { 24 | Size::new(self.width as u32, self.height as u32) 25 | } 26 | } 27 | 28 | pub fn init_graphic_framebuffer(boot_info: &BootInfo) { 29 | let (width, height) = boot_info.graphic_info.mode.resolution(); 30 | let fb_addr = boot_info.graphic_info.fb_addr as usize; 31 | let fb = Framebuffer { 32 | width, 33 | height, 34 | buf: unsafe { 35 | core::slice::from_raw_parts_mut( 36 | phys_to_virt(fb_addr) as *mut u32, 37 | (width * height) as usize, 38 | ) 39 | }, 40 | }; 41 | let console = Console::on_frame_buffer(fb); 42 | *CONSOLE.lock() = Some(console); 43 | println!("Init Graphic framebuffer"); 44 | } -------------------------------------------------------------------------------- /kernel/src/fs/mod.rs: -------------------------------------------------------------------------------- 1 | use core::mem::MaybeUninit; 2 | 3 | use crate::drivers::{BlockDriver, BlockDriverWrapper}; 4 | use crate::drivers::{DeviceType, DRIVERS}; 5 | use rcore_fs::{dev::Device, vfs}; 6 | 7 | pub mod inode_ext; 8 | 9 | use alloc::sync::Arc; 10 | use inode_ext::INodeExt; 11 | use lazy_static::*; 12 | use rcore_fs::{dev::block_cache::BlockCache, vfs::INode}; 13 | use rcore_fs_mountfs::MountFS; 14 | use rcore_fs_sfs::{AsBuf, BlockId, SimpleFileSystem, SuperBlock, BLKN_SUPER}; 15 | 16 | lazy_static! { 17 | /// 根文件系统的根目录的 INode 18 | pub static ref ROOT_INODE: Arc = { 19 | // 选择第一个块设备 20 | let device = { 21 | let blc_dvice = crate::drivers::BLK_DRIVERS 22 | .read().iter() 23 | .next().expect("Block device not found") 24 | .clone(); 25 | let driver = BlockDriverWrapper( 26 | blc_dvice 27 | ); 28 | // debug!("{:?}",crate::drivers::BLK_DRIVERS.read(); 29 | debug!("{}",crate::drivers::BLK_DRIVERS.read().len()); 30 | // enable block cache 31 | // Arc::new(BlockCache::new(driver, 0x100)) 32 | Arc::new(driver) 33 | }; 34 | 35 | let sfs = SimpleFileSystem::open(device).expect("failed to open SFS"); 36 | let rootfs = MountFS::new(sfs); 37 | let root = rootfs.root_inode(); 38 | root 39 | }; 40 | } 41 | 42 | pub fn init() { 43 | ROOT_INODE.ls(); 44 | debug!("Fs init!"); 45 | } 46 | -------------------------------------------------------------------------------- /kernel/src/drivers/provider.rs: -------------------------------------------------------------------------------- 1 | use crate::memory::{alloc_frame_contiguous, dealloc_frame, phys_to_virt, virt_to_phys, PAGE_SIZE}; 2 | use isomorphic_drivers::provider; 3 | use log::*; 4 | 5 | pub struct Provider; 6 | 7 | impl provider::Provider for Provider { 8 | const PAGE_SIZE: usize = PAGE_SIZE; 9 | 10 | fn alloc_dma(size: usize) -> (usize, usize) { 11 | let paddr = virtio_dma_alloc(size / PAGE_SIZE); 12 | let vaddr = phys_to_virt(paddr); 13 | (vaddr, paddr) 14 | } 15 | 16 | fn dealloc_dma(vaddr: usize, size: usize) { 17 | let paddr = virt_to_phys(vaddr); 18 | for i in 0..size / PAGE_SIZE { 19 | dealloc_frame(paddr + i * PAGE_SIZE); 20 | } 21 | } 22 | } 23 | 24 | #[no_mangle] 25 | extern "C" fn virtio_dma_alloc(pages: usize) -> PhysAddr { 26 | let paddr = alloc_frame_contiguous(pages, 0).unwrap(); 27 | trace!("alloc DMA: paddr={:#x}, pages={}", paddr, pages); 28 | paddr 29 | } 30 | 31 | #[no_mangle] 32 | extern "C" fn virtio_dma_dealloc(paddr: PhysAddr, pages: usize) -> i32 { 33 | for i in 0..pages { 34 | dealloc_frame(paddr + i * PAGE_SIZE); 35 | } 36 | trace!("dealloc DMA: paddr={:#x}, pages={}", paddr, pages); 37 | 0 38 | } 39 | 40 | #[no_mangle] 41 | extern "C" fn virtio_phys_to_virt(paddr: PhysAddr) -> VirtAddr { 42 | phys_to_virt(paddr) 43 | } 44 | 45 | #[no_mangle] 46 | extern "C" fn virtio_virt_to_phys(vaddr: VirtAddr) -> PhysAddr { 47 | virt_to_phys(vaddr) 48 | } 49 | 50 | type VirtAddr = usize; 51 | type PhysAddr = usize; 52 | -------------------------------------------------------------------------------- /kernel/src/fs/inode_ext.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use alloc::str::from_utf8; 3 | use alloc::string::{String, ToString}; 4 | use alloc::vec::Vec; 5 | 6 | pub trait INodeExt { 7 | /// 打印当前目录的文件 8 | fn ls(&self); 9 | fn ls_as_vec(&self) -> Result, usize>; 10 | /// 读取文件内容到 11 | fn read_as_vec(&self) -> Result, usize>; 12 | /// 读文件到字符串 13 | fn read_as_string(&self) -> Result; 14 | } 15 | 16 | impl INodeExt for dyn INode { 17 | fn ls(&self) { 18 | let mut id = 0; 19 | while let Ok(name) = self.get_entry(id) { 20 | //TODO 这里应该也可以返回值 而不是简单的打印! 21 | println!("{}", name); 22 | id += 1; 23 | } 24 | } 25 | fn read_as_vec(&self) -> Result, usize> { 26 | let size = self.metadata().unwrap().size; 27 | let mut buf = Vec::with_capacity(size); 28 | unsafe { 29 | buf.set_len(size); 30 | } 31 | self.read_at(0, buf.as_mut_slice()).unwrap(); 32 | Ok(buf) 33 | } 34 | 35 | fn read_as_string(&self) -> Result { 36 | let data = self.read_as_vec().unwrap(); 37 | match from_utf8(&data) { 38 | Ok(v) => Ok(v.to_string()), 39 | Err(e) => panic!("Invalid UTF-8 sequence: {}", e), 40 | } 41 | } 42 | 43 | fn ls_as_vec(&self) -> Result, usize> { 44 | let mut res = Vec::new(); 45 | let mut id = 0; 46 | while let Ok(name) = self.get_entry(id) { 47 | res.push(name); 48 | id += 1; 49 | } 50 | Ok(res) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /kernel/src/console/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod io; 2 | ///! 使用串口,该功能也可以在内核中使用,可直接移植 3 | use core::fmt::Arguments; 4 | 5 | #[macro_export] 6 | macro_rules! with_color { 7 | ($args: ident, $color_code: ident) => { 8 | format_args!("\u{1B}[{}m{}\u{1B}[0m", $color_code as u8, $args) 9 | }; 10 | } 11 | 12 | #[macro_export] 13 | macro_rules! print { 14 | ($color:expr;$($arg:tt)*) => (crate::console::print_in_color($color, format_args!($($arg)*))); 15 | ($($arg:tt)*) => (crate::console::print(format_args!($($arg)*))); 16 | } 17 | 18 | #[macro_export] 19 | macro_rules! println { 20 | () => (crate::print!("\n")); 21 | ($($arg:tt)*) => (crate::print!(36; "[Info] :# {}\n", format_args!($($arg)*))); 22 | } 23 | 24 | #[macro_export] 25 | macro_rules! test { 26 | () => (crate::print!("\n")); 27 | ($($arg:tt)*) => (crate::print!(96; "[-OK-] :) {} \n", format_args!($($arg)*))); 28 | } 29 | 30 | #[macro_export] 31 | macro_rules! warn { 32 | () => (crate::print!("\n")); 33 | ($($arg:tt)*) => (crate::print!(31; "[Warn] :! {}\n", format_args!($($arg)*))); 34 | } 35 | 36 | #[macro_export] 37 | macro_rules! debug { 38 | () => (crate::print!("\n")); 39 | ($($arg:tt)*) => (crate::print!(93; "[Debug] :? {}\n", format_args!($($arg)*))); 40 | } 41 | 42 | #[macro_export] 43 | macro_rules! error { 44 | () => (crate::print!("\n")); 45 | ($($arg:tt)*) => (crate::print!(91; "[error] :< {}\n", format_args!($($arg)*))); 46 | } 47 | 48 | pub fn print(fmt: Arguments) { 49 | io::putfmt(fmt); 50 | } 51 | 52 | pub fn print_in_color(color: u8, fmt: Arguments) { 53 | io::putfmt(with_color!(fmt, color)); 54 | } 55 | -------------------------------------------------------------------------------- /kernel/src/drivers/block/ahci.rs: -------------------------------------------------------------------------------- 1 | use crate::drivers::provider::Provider; 2 | use alloc::{ 3 | string::{String, ToString}, 4 | sync::Arc, 5 | }; 6 | use isomorphic_drivers::block::ahci::{AHCI, BLOCK_SIZE}; 7 | use spin::Mutex; 8 | 9 | use super::{ 10 | super::{DeviceType, Driver, BLK_DRIVERS, DRIVERS}, 11 | BlockDriver, 12 | }; 13 | 14 | pub struct AHCIDriver(Mutex>); 15 | 16 | impl Driver for AHCIDriver { 17 | fn try_handle_interrupt(&self, irq: Option) -> bool { 18 | false 19 | } 20 | 21 | fn device_type(&self) -> DeviceType { 22 | DeviceType::Block 23 | } 24 | 25 | fn get_id(&self) -> String { 26 | "ahci".to_string() 27 | } 28 | 29 | fn as_block(&self) -> Option<&dyn BlockDriver> { 30 | Some(self) 31 | } 32 | } 33 | 34 | impl BlockDriver for AHCIDriver { 35 | fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { 36 | let mut driver = self.0.lock(); 37 | driver.read_block(block_id, buf); 38 | true 39 | } 40 | 41 | fn write_block(&self, block_id: usize, buf: &[u8]) -> bool { 42 | if buf.len() < BLOCK_SIZE { 43 | return false; 44 | } 45 | let mut driver = self.0.lock(); 46 | driver.write_block(block_id, buf); 47 | true 48 | } 49 | } 50 | 51 | pub fn init(_irq: Option, header: usize, size: usize) -> Option> { 52 | if let Some(ahci) = AHCI::new(header, size) { 53 | let driver = Arc::new(AHCIDriver(Mutex::new(ahci))); 54 | DRIVERS.write().push(driver.clone()); 55 | BLK_DRIVERS.write().push(driver.clone()); 56 | Some(driver) 57 | } else { 58 | None 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Readme_zh_CN.md: -------------------------------------------------------------------------------- 1 | # juner_os 2 | 3 | ![juner_os](j-file.png) 4 | 5 | [English](.README.md) 6 | 7 | # 简介 8 | 9 | 这个项目结合了[blog_os](https://os.phil-opp.com/)和[mal](https://github.com/kanaka/mal)两个项目的内容。 10 | 现在实现了一个可以运行交互的 lisp shell.后续目标是使用 lisp 和 rust 混合的方式组织操作系统的代码。并而核心库准备使用 lisp 进行加载和维护。项目进行中。 11 | 12 | # 特性 13 | 14 | - rust 实现的内核 15 | - LISP REPL 16 | - 支持了 load-file 方法,可以在内核加载后加载 mal 文件 17 | - 现在代码可以写在 user 文件夹下。在内核启动后的 repl 中可以使用 laod-file 方法进行加载。 18 | - 内核加载后会加载`entry.jaml`作为入口文件 19 | - lisp 方言的扩展名为`jmal`(Juner-os's Make A Lisp!) 20 | - 支持ps2鼠标。打开kernel/src/board/mouse.rs中的注释即可。 21 | 22 | 23 | # 依赖 24 | 25 | - rustc 1.48.0-nightly 26 | - qemu 27 | 28 | # 运行 29 | 30 | ``` 31 | make all 32 | ``` 33 | 34 | # Lisp 的语法: 35 | 36 | - [语法](./grammar_zh.md) 37 | 38 | # 梦想清单 39 | 40 | - [ ] VGA text mode 下显示打印 41 | - [x] 光标跟随 42 | - [x] 删除 43 | - [ ] 代码提示 Tab 44 | - [x] 光标移动编辑 45 | - [ ] 滚动条 46 | - [ ] Lisp 完整功能 47 | - [x] 支持宏 48 | - [ ] 支持代码提示 49 | - [ ] sacnf 方法 50 | - [ ] 文件读写 51 | - [ ] 模块加载 52 | - [ ] JIT 53 | - [ ] 支持 call/cc 54 | - [ ] 设备 55 | - [x] 识别硬盘 (ahci 使用 rcore-fuse) 56 | - [ ] 声音驱动 57 | - [ ] 网卡支持 58 | - [ ] 抽象的功能 59 | - [x] UEFI 支持 60 | - [ ] 并行多任务 61 | - [ ] 支持 GUI 62 | - [ ] 网络加载 lisp 模块 63 | - [ ] 多核心利用 64 | - [ ] 自举(支持 rust 环境) 65 | - [ ] 梦中的 app 66 | - [ ] MAL 这个方言的编辑器 67 | - [ ] NoteBook 68 | - [ ] mal 的 vscode 编辑器插件 69 | 70 | # 现在的工作和目标 71 | 72 | ~~目前来说实现的功能还很初步,lisp 内有没有实现的机制,内核里有要实现的内容。现在在研究使用 UEFI 进行引导,让系统可以读写文件,并在 lisp 内运行。后面 uefi 的分支会合并到主分支上,并且作为主流。~~ 73 | 74 | load-file 已经基本实现了。现在有两个方向可以做。~~一个是写一个 vscode 的 mal 语言的插件(当然要单独项目开发)。~~还有一个是写一个简单的编辑器,实现一个类似 freeze 的方法。让当前在内核运行的方法写到磁盘文件中,再用脚本反向保存出来。 75 | 76 | # 期待你加入并完善这个项目 77 | 78 | 联系我: zzhggmm@gmail.com 79 | 80 | # 感谢 81 | 82 | - blog_os 83 | - mal 84 | - rcore 85 | - @senseiod 和我拷贝了很多的项目 https://github.com/senseiod/AiliceOS 86 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all amd64 crate_esp run clean install-depends build rcore-fs-fuse pack 2 | 3 | all: amd64 run 4 | 5 | BOOTLOADER_DIR := bootloader 6 | OVMF = ${BOOTLOADER_DIR}/OVMF.fd 7 | USER_DIR = user 8 | OUT_IMG = build/SYS.img 9 | USER_QCOW2 = build/x86_64.qcow2 10 | rcore_fs_fuse_revision := 7f5eeac 11 | 12 | # build 13 | build: 14 | @cd bootloader && cargo build --release 15 | @cd kernel && cargo build --release 16 | @make pack 17 | 18 | # 编译bootloader和kernel 19 | amd64: 20 | @make build 21 | @make crate_esp 22 | 23 | # x86_64编译出的文件目录 24 | crate_esp: 25 | @mkdir -p build/pc/esp/EFI/kernel build/pc/esp/EFI/Boot 26 | @cp target/x86_64-unknown-uefi/release/bootloader.efi build/pc/esp/EFI/Boot/BootX64.efi 27 | @cp target/amd64/release/kernel build/pc/esp/EFI/kernel/kernel.elf 28 | 29 | # QEMU运行x86_64 30 | run: 31 | @qemu-system-x86_64 \ 32 | -bios ${OVMF} \ 33 | -drive format=raw,file=fat:rw:build/pc/esp \ 34 | -m 4096 \ 35 | -smp 2 \ 36 | -serial mon:stdio \ 37 | -device isa-debug-exit \ 38 | -drive format=qcow2,file=$(USER_QCOW2),media=disk,cache=writeback,id=sfsimg,if=none \ 39 | -device ahci,id=ahci0 \ 40 | -device ide-hd,drive=sfsimg,bus=ahci0.0 41 | # -nographic \ 42 | 43 | # 清理编译出来的文件 44 | clean: 45 | @cargo clean 46 | @rm -rf build 47 | 48 | # 依赖安装 49 | install-depends: 50 | rustup install nightly 51 | rustup default nightly 52 | rustup component add rust-src 53 | rustup component add llvm-tools-preview 54 | 55 | # 安装依赖 56 | rcore-fs-fuse: 57 | ifneq ($(shell rcore-fs-fuse dir image git-version), $(rcore_fs_fuse_revision)) 58 | @echo Installing rcore-fs-fuse 59 | @cargo install rcore-fs-fuse --git https://github.com/rcore-os/rcore-fs --rev $(rcore_fs_fuse_revision) --force 60 | endif 61 | 62 | # 打包文件 63 | pack: 64 | @mkdir -p build 65 | @rcore-fs-fuse $(OUT_IMG) $(USER_DIR) zip 66 | @qemu-img convert -f raw $(OUT_IMG) -O qcow2 $(USER_QCOW2) 67 | @qemu-img resize $(USER_QCOW2) +1G -------------------------------------------------------------------------------- /kernel/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | #![feature(lang_items)] 4 | #![feature(default_alloc_error_handler)] 5 | #![feature(untagged_unions)] 6 | #![feature(abi_x86_interrupt)] 7 | #![feature(box_syntax)] 8 | #![feature(wake_trait)] 9 | 10 | extern crate alloc; 11 | 12 | #[macro_use] 13 | pub mod console; 14 | 15 | pub mod board; 16 | pub mod drivers; 17 | pub mod fs; 18 | pub mod interrupts; 19 | pub mod lang; 20 | pub mod mal; 21 | pub mod memory; 22 | pub mod shell; 23 | pub mod task; 24 | 25 | use bootloader::{entry_point, BootInfo}; 26 | use task::{executor::Executor, Task}; 27 | use log::*; 28 | entry_point!(main); 29 | 30 | pub fn main(boot_info: &'static BootInfo) -> ! { 31 | init_log(); 32 | memory::heap::init_heap(); // 初始化堆分配,以启用alloc库 33 | memory::init_frame(boot_info); // 初始化内存Frame 34 | drivers::init_driver(boot_info); // 初始化串口输出和显示输出 35 | board::cpu::init_cpu(); // 初始化CPU特性 36 | board::acpi_table::get_acpi_addr(boot_info); // 从 boot_info中读取acpi_table address 37 | interrupts::init(); // 初始化Trap frame和中断 38 | drivers::bus::pci::init(); 39 | test!("This is test"); 40 | error!("This is error"); 41 | warn!("This is warn"); 42 | debug!("This is debug"); 43 | println!("This is println"); 44 | fs::init(); 45 | shell::init_shell(); 46 | hlt_loop(); 47 | } 48 | 49 | pub fn hlt_loop() -> ! { 50 | loop { 51 | x86_64::instructions::hlt(); 52 | } 53 | } 54 | 55 | 56 | fn init_log() { 57 | struct SimpleLogger; 58 | impl Log for SimpleLogger { 59 | fn enabled(&self, metadata: &Metadata) -> bool { 60 | true 61 | } 62 | 63 | fn log(&self, record: &Record) { 64 | println!("[{:>5}] {}", record.level(), record.args()); 65 | } 66 | 67 | fn flush(&self) {} 68 | } 69 | 70 | static LOGGER: SimpleLogger = SimpleLogger; 71 | set_logger(&LOGGER).unwrap(); 72 | set_max_level(LevelFilter::Trace); 73 | } -------------------------------------------------------------------------------- /kernel/cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel" 3 | version = "0.1.0" 4 | authors = ["zzhgithub "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | uart_16550 = "0.2.10" 11 | x86_64 = "0.12.2" 12 | lazy_static = {version = "1.4.0", features = ["spin_no_std"]} 13 | buddy_system_allocator = "0.5.0" 14 | spin = "0.6.0" 15 | pic8259_simple = "0.2.0" 16 | pc-keyboard = "0.5.1" 17 | acpi = "1.1.0" 18 | raw-cpuid = "8.0.0" 19 | hashbrown = "0.9.1" 20 | log = "0.4" 21 | ps2-mouse = "0.1.3" 22 | 23 | # Others Dependencies 24 | bootloader = { path = "../bootloader",default-features = false} 25 | trapframe = { git = "https://github.com/rcore-os/trapframe-rs.git" } 26 | rcore-console = { git = "https://github.com/rcore-os/rcore-console.git", default-features = false} 27 | bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator" } 28 | apic = { git = "https://github.com/rcore-os/apic-rs.git" } 29 | pci = { git = "https://github.com/rcore-os/pci-rs", rev = "a4e7cea6" } 30 | isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers", rev = "fcf694d2", features = ["log"] } 31 | rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "517af47" } 32 | rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "517af47" } 33 | rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "517af47" } 34 | rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "517af47" } 35 | 36 | # rcore-fs = {path="../../rcore-fs/rcore-fs"} 37 | # rcore-fs-devfs = {path="../../rcore-fs/rcore-fs-devfs"} 38 | # rcore-fs-sfs = {path="../../rcore-fs/rcore-fs-sfs"} 39 | # rcore-fs-mountfs = {path="../../rcore-fs/rcore-fs-mountfs"} 40 | 41 | [dependencies.conquer-once] 42 | version = "0.2.0" 43 | default-features = false 44 | 45 | [dependencies.crossbeam-queue] 46 | version = "0.3.0" 47 | default-features = false 48 | features = ["alloc"] 49 | 50 | [dependencies.futures-util] 51 | version = "0.3.4" 52 | default-features = false 53 | features = ["alloc"] -------------------------------------------------------------------------------- /bootloader/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | extern crate alloc; 4 | 5 | use alloc::vec::Vec; 6 | pub use uefi::proto::console::gop::ModeInfo; 7 | pub use uefi::table::boot::{MemoryAttribute, MemoryDescriptor, MemoryType}; 8 | use x86_64::VirtAddr; 9 | 10 | /// This structure represents the information that the bootloader passes to the kernel. 11 | /// 引导信息 要传给内核的数据结构 12 | #[repr(C)] 13 | #[derive(Debug)] 14 | pub struct BootInfo { 15 | /// 内存地址 映射 MemoryDescriptor 内存描述符 16 | pub memory_map: Vec<&'static MemoryDescriptor>, 17 | /// The offset into the virtual address space where the physical memory is mapped. 18 | /// 虚拟地址偏移量 19 | pub physical_memory_offset: u64, 20 | /// The graphic output information 21 | /// 图像信息 22 | pub graphic_info: GraphicInfo, 23 | /// Physical address of ACPI2 RSDP 24 | /// 电源管理地址 25 | pub acpi2_rsdp_addr: u64, 26 | pub smbios_addr: u64, 27 | } 28 | 29 | /// Kernel entry's virtual address. 30 | /// 内核入口 的 虚拟地址 31 | #[derive(Clone, Copy, Debug)] 32 | #[repr(transparent)] 33 | pub struct KernelEntry(pub VirtAddr); 34 | 35 | /// Function signature for kernel entry point. 36 | /// 内核 入口点 方法签名! 37 | pub type KernelEntryFn = extern "sysv64" fn(boot_info: &'static BootInfo) -> !; 38 | 39 | /// Graphic output information 40 | #[derive(Debug, Copy, Clone)] 41 | #[repr(C)] 42 | pub struct GraphicInfo { 43 | /// Graphic mode 44 | pub mode: ModeInfo, 45 | /// Framebuffer base physical address 46 | pub fb_addr: u64, 47 | /// Framebuffer size 48 | pub fb_size: u64, 49 | } 50 | 51 | /// Defines the entry point function. 52 | /// 53 | /// The function must have the signature `fn(&'static BootInfo) -> !`. 54 | /// 55 | /// This macro just creates A function named `_start`, which the linker will use as the entry 56 | /// point. The advantage of using this macro instead of providing an own `_start` function is 57 | /// that the macro ensures that the function and argument types are correct. 58 | #[macro_export] 59 | macro_rules! entry_point { 60 | ($path:path) => { 61 | #[export_name = "_start"] 62 | pub extern "C" fn __impl_start(boot_info: &'static $crate::BootInfo) -> ! { 63 | // validate the signature of the program entry point 64 | let f: fn(&'static $crate::BootInfo) -> ! = $path; 65 | f(boot_info) 66 | } 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /kernel/src/mal/printer.rs: -------------------------------------------------------------------------------- 1 | use alloc::string::{String,ToString}; 2 | use crate::mal::types::MalVal; 3 | use crate::mal::types::MalVal::{Atom, Bool, Func, Hash, Int, List, MalFunc, Nil, Str, Sym, Vector}; 4 | use crate::format; 5 | use crate::vec; 6 | use alloc::vec::Vec; 7 | 8 | // 转义字符串 9 | fn escape_str(s: &str) -> String { 10 | s.chars() 11 | .map(|c| match c { 12 | '"' => "\\\"".to_string(), 13 | '\n' => "\\n".to_string(), 14 | '\\' => "\\\\".to_string(), 15 | _ => c.to_string(), 16 | }) 17 | .collect::>() 18 | .join("") 19 | } 20 | 21 | impl MalVal { 22 | pub fn pr_str(&self, print_readably: bool) -> String { 23 | match self { 24 | Nil => String::from("nil"), 25 | Bool(true) => String::from("true"), 26 | Bool(false) => String::from("false"), 27 | Int(i) => format!("{}", i), 28 | //Float(f) => format!("{}", f), 29 | Str(s) => { 30 | if s.starts_with("\u{29e}") { 31 | format!(":{}", &s[2..]) 32 | } else if print_readably { 33 | format!("\"{}\"", escape_str(s)) 34 | } else { 35 | s.clone() 36 | } 37 | } 38 | Sym(s) => s.clone(), 39 | List(l, _) => pr_seq(&**l, print_readably, "(", ")", " "), 40 | Vector(l, _) => pr_seq(&**l, print_readably, "[", "]", " "), 41 | Hash(hm, _) => { 42 | let l: Vec = hm 43 | .iter() 44 | .flat_map(|(k, v)| vec![Str(k.to_string()), v.clone()]) 45 | .collect(); 46 | pr_seq(&l, print_readably, "{", "}", " ") 47 | } 48 | Func(f, _) => format!("#", f), 49 | MalFunc { 50 | ast: a, params: p, .. 51 | } => format!("(lambda {} {})", p.pr_str(true), a.pr_str(true)), 52 | Atom(a) => format!("(atom {})", a.borrow().pr_str(true)), 53 | } 54 | } 55 | } 56 | 57 | pub fn pr_seq( 58 | seq: &Vec, 59 | print_readably: bool, 60 | start: &str, 61 | end: &str, 62 | join: &str, 63 | ) -> String { 64 | let strs: Vec = seq.iter().map(|x| x.pr_str(print_readably)).collect(); 65 | format!("{}{}{}", start, strs.join(join), end) 66 | } -------------------------------------------------------------------------------- /README_OLD.md: -------------------------------------------------------------------------------- 1 | # juner_os 2 | 3 | ![juner_os](juneros.png) 4 | 5 | 6 | 联系我: zzhggmm@gmail.com 7 | # introduction 8 | A lisp shell that can run interactive is now implemented. The subsequent goal is to organize the code of the operating system in a mixed way of lisp and rust. At the same time, the core library is ready to be loaded and maintained using lisp. The project is in progress. 9 | 10 | # 简介 11 | 这个项目结合了blog_os和mal两个项目的内容。现在实现了一个可以运行交互的lisp shell.后续目标是使用lisp和rust混合的方式组织操作系统的代码。并而核心库准备使用lisp进行加载和维护。项目进行中。 12 | 13 | 14 | # 功能计划(没有实现的) 15 | - [ ] VGA text mode 下显示打印 16 | - [x] 光标跟随 17 | - [x] 删除 18 | - [ ] 代码提示Tab 19 | - [ ] 光标移动编辑 20 | - [ ] 滚动条 21 | - [ ] Lisp 完整功能 22 | - [x] 支持宏 23 | - [ ] 支持代码提示 24 | - [ ] sacnf方法 25 | - [ ] 文件读写 26 | - [ ] 模块加载 27 | - [ ] JIT 28 | - [ ] 支持call/cc 29 | - [ ] 设备 30 | - [ ] 识别硬盘 31 | - [ ] 声音驱动 32 | - [ ] 网卡支持 33 | - [ ] 抽象的功能 34 | - [ ] 并行多任务 35 | - [ ] 支持GUI 36 | - [ ] 网络加载lisp模块 37 | - [ ] 多核心利用 38 | - [ ] 自举(支持rust环境) 39 | - [ ] 梦中的app 40 | - [ ] MAL 这个方言的编辑器 41 | - [ ] NoteBook 42 | 43 | ## 开发日志 44 | 45 | - [开发日志详细文档](https://www.yuque.com/xiaohao-i0lwb/fn1hxc) 46 | 47 | ## 直接测试运行 48 | 49 | ``` 50 | cargo xrun 51 | ``` 52 | 53 | ## 使用rust-gdb 进行断点执行 54 | 55 | ``` 56 | ./gdb.sh 57 | ./touchme.sh 58 | 59 | ``` 60 | ### 断点指令 61 | - b 打断点 62 | - n 执行下一行( 这个方法比较哈! 只能执行当前文件的一行) 63 | - tui enable 打开源代码视图 64 | - print 打印变量值 65 | - c 继续执行到下一个断点 66 | - s 运行到下一步(但是没有进入到内联汇编的汇编中 比较遗憾) 67 | 68 | 69 | 70 | ## todo 71 | - 正常输入输出 72 | - 多线程支持 73 | - lisp REPL基础实现 74 | - 实现hashmap和关键字类型 75 | - 实现gemsym方法 76 | - 实现call/cc方法 77 | - 在操作系统层面实现文件系统,并且允许lisp进行加载(最好在修改以后可以永久的进行改变) 或者直接加载网络上 78 | 79 | ## Lisp 的语法: 80 | - [语法](./grammar.md) 81 | 82 | ### BNF 83 | > 在双引号中的字(“word”)代表着这些字符本身。而double_quote用来代表双引号。 84 | > 在双引号外的字(有可能有下划线)代表着语法部分。 85 | > 尖括号( < > )内包含的为必选项。 86 | > 方括号( [ ] )内包含的为可选项。 87 | > 大括号( { } )内包含的为可重复0至无数次的项。 88 | > 竖线( | )表示在其左右两边任选一项,相当于”OR”的意思。 89 | > ::= 是“被定义为”的意思。 90 | 91 | 基本s表达式生成语法 92 | 93 | ```bnf 94 | s_expression ::= atomic_symbol | 95 | | "(" s_expression "."s_expression ")" | 96 | | list 97 | 98 | list ::= "(" s_expression < s_expression > ")" 99 | 100 | atomic_symbol ::= letter atom_part 101 | 102 | atom_part ::= empty | letter atom_part | number atom_part 103 | 104 | letter ::= "a" | "b" | " ..." | "z" 105 | 106 | number ::= "1" | "2" | " ..." | "9" 107 | 108 | empty ::= " " 109 | ``` 110 | 111 | TODO!!问题上面的定义不能很好的识别出字符串作为元素!!! 112 | 113 | 114 | ## rust 镶嵌lisp 115 | ## lisp与rust交互数据 116 | 117 | ## 核心库? 118 | 119 | ## 是否可以用lisp中的进程管理和多线程实现一个打scanf方法 120 | 疑问?需要使用syscall和信号量等概念吗? 121 | 122 | # 参考资料 123 | - (Lisp Bnf)[https://iamwilhelm.github.io/bnf-examples/lisp] 124 | - (Json 识别状态机 【参考用】)[https://www.json.org/json-en.html] -------------------------------------------------------------------------------- /kernel/src/mal/env.rs: -------------------------------------------------------------------------------- 1 | use alloc::rc::Rc; 2 | use alloc::string::{String,ToString}; 3 | use core::cell::RefCell; 4 | use hashbrown::HashMap; 5 | use alloc::vec::Vec; 6 | 7 | use crate::mal::types::MalErr::ErrString; 8 | use crate::mal::types::MalVal::{List, Nil, Sym, Vector,Func,Int}; 9 | use crate::mal::types::{error, MalErr, MalRet, MalVal}; 10 | 11 | use crate::format; 12 | use crate::list; 13 | 14 | #[derive(Debug)] 15 | pub struct EnvSturct { 16 | data: RefCell>, 17 | pub outer: Option, 18 | } 19 | 20 | pub type Env = Rc; 21 | 22 | pub fn env_new(outer: Option)->Env{ 23 | Rc::new(EnvSturct{ 24 | data: RefCell::new(HashMap::default()), 25 | outer: outer, 26 | }) 27 | } 28 | 29 | // 查找符号所在环境 30 | pub fn env_find(env: &Env, key: &str) -> Option { 31 | match (env.data.borrow().contains_key(key), env.outer.clone()) { 32 | (true, _) => Some(env.clone()), 33 | (false, Some(o)) => env_find(&o, key), 34 | _ => None, 35 | } 36 | } 37 | 38 | // 再环境中查找符号 39 | pub fn env_get(env: &Env, key: &MalVal) -> MalRet { 40 | match key { 41 | Sym(ref s) => match env_find(env, s) { 42 | Some(e) => Ok(e 43 | .data 44 | .borrow() 45 | .get(s) 46 | .ok_or(ErrString(format!("'{}' not found", s)))? 47 | .clone()), 48 | _ => error(&format!("'{}' not found", s)), 49 | }, 50 | _ => error("Env.get called with non-Str"), 51 | } 52 | } 53 | 54 | // 在环境中绑定符号 MalVal是move进来的 适合使用Rust直接定义函数 55 | pub fn env_sets(env:&Env,key:&str,val:MalVal){ 56 | env.data.borrow_mut().insert(key.to_string(),val); 57 | } 58 | 59 | 60 | // 给环境中的符号绑定 抽象语法树! 61 | pub fn env_set(env: &Env, key: MalVal, val: MalVal) -> MalRet { 62 | match key { 63 | Sym(ref s) => { 64 | env.data.borrow_mut().insert(s.to_string(), val.clone()); 65 | Ok(val) 66 | } 67 | _ => error("Env.set called with non-Str"), 68 | } 69 | } 70 | 71 | // 给符号绑定 对应的抽象语法树 并且返回一个待使用的Env子环境, 类似与形参绑定实参 72 | pub fn env_bind(outer: Option, mbinds: MalVal, exprs: Vec) -> Result { 73 | let env = env_new(outer); 74 | match mbinds { 75 | List(binds, _) | Vector(binds, _) => { 76 | for (i, b) in binds.iter().enumerate() { 77 | match b { 78 | // 这个特性保证 & 后面的其他参数都进入到一个list里面 79 | Sym(s) if s == "&" => { 80 | env_set(&env, binds[i + 1].clone(), list!(exprs[i..].to_vec()))?; 81 | break; 82 | } 83 | _ => { 84 | env_set(&env, b.clone(), exprs[i].clone())?; 85 | } 86 | } 87 | } 88 | Ok(env) 89 | } 90 | _ => Err(ErrString("env_bind binds not List/Vector".to_string())), 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /kernel/src/drivers/mod.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | use alloc::{string::String, sync::Arc}; 3 | use bootloader::BootInfo; 4 | use lazy_static::*; 5 | use rcore_fs::dev::{self, BlockDevice, DevError}; 6 | use spin::RwLock; 7 | 8 | pub mod block; 9 | pub mod bus; 10 | pub mod gpu; 11 | pub mod provider; 12 | pub mod serial; 13 | 14 | pub use block::BlockDriver; 15 | 16 | pub fn init_driver(boot_info: &BootInfo) { 17 | serial::init(); 18 | gpu::init_graphic_framebuffer(boot_info); 19 | test!("Init Drivers"); 20 | } 21 | 22 | #[derive(Debug, Eq, PartialEq)] 23 | pub enum DeviceType { 24 | Net, 25 | Gpu, 26 | Input, 27 | Block, 28 | Rtc, 29 | Serial, 30 | Intc, 31 | } 32 | 33 | pub trait Driver: Send + Sync { 34 | // if interrupt belongs to this driver, handle it and return true 35 | // return false otherwise 36 | // irq number is provided when available 37 | // driver should skip handling when irq number is mismatched 38 | fn try_handle_interrupt(&self, irq: Option) -> bool; 39 | 40 | // return the correspondent device type, see DeviceType 41 | fn device_type(&self) -> DeviceType; 42 | 43 | // get unique identifier for this device 44 | // should be different for each instance 45 | fn get_id(&self) -> String; 46 | 47 | // trait casting 48 | // fn as_net(&self) -> Option<&dyn NetDriver> { 49 | // None 50 | // } 51 | 52 | fn as_block(&self) -> Option<&dyn BlockDriver> { 53 | None 54 | } 55 | 56 | // fn as_rtc(&self) -> Option<&dyn RtcDriver> { 57 | // None 58 | // } 59 | } 60 | 61 | pub struct BlockDriverWrapper(pub Arc); 62 | 63 | impl BlockDevice for BlockDriverWrapper { 64 | const BLOCK_SIZE_LOG2: u8 = 9; // 512 65 | fn read_at(&self, block_id: usize, buf: &mut [u8]) -> dev::Result<()> { 66 | match self.0.read_block(block_id, buf) { 67 | true => Ok(()), 68 | false => Err(DevError), 69 | } 70 | } 71 | 72 | fn write_at(&self, block_id: usize, buf: &[u8]) -> dev::Result<()> { 73 | match self.0.write_block(block_id, buf) { 74 | true => Ok(()), 75 | false => Err(DevError), 76 | } 77 | } 78 | 79 | fn sync(&self) -> dev::Result<()> { 80 | Ok(()) 81 | } 82 | } 83 | 84 | 85 | 86 | lazy_static! { 87 | // NOTE: RwLock only write when initializing drivers 88 | pub static ref DRIVERS: RwLock>> = RwLock::new(Vec::new()); 89 | // pub static ref NET_DRIVERS: RwLock>> = RwLock::new(Vec::new()); 90 | pub static ref BLK_DRIVERS: RwLock>> = RwLock::new(Vec::new()); 91 | // pub static ref RTC_DRIVERS: RwLock>> = RwLock::new(Vec::new()); 92 | // pub static ref SERIAL_DRIVERS: RwLock>> = RwLock::new(Vec::new()); 93 | // pub static ref IRQ_MANAGER: RwLock = RwLock::new(irq::IrqManager::new(true)); 94 | } 95 | -------------------------------------------------------------------------------- /kernel/src/task/keyboard.rs: -------------------------------------------------------------------------------- 1 | // OnceCell 保证一次性初始化 2 | use conquer_once::spin::OnceCell; 3 | use core::{ 4 | pin::Pin, 5 | task::{Context, Poll}, 6 | }; 7 | use crossbeam_queue::ArrayQueue; 8 | use futures_util::stream::{Stream, StreamExt}; 9 | use futures_util::task::AtomicWaker; 10 | 11 | use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; 12 | 13 | use crate::print; 14 | use crate::println; 15 | 16 | // 扫码队列 17 | static SCANCODE_QUEUE: OnceCell> = OnceCell::uninit(); 18 | static WAKER: AtomicWaker = AtomicWaker::new(); 19 | 20 | pub(crate) fn add_scancode(scancode: u8) { 21 | if let Ok(queue) = SCANCODE_QUEUE.try_get() { 22 | if let Err(_) = queue.push(scancode) { 23 | println!("WARNING: scancode queue full; dropping keyboard input"); 24 | } else { 25 | //唤醒wake 26 | WAKER.wake(); 27 | } 28 | } else { 29 | println!("WARNING: scancode queue uninitialized"); 30 | } 31 | } 32 | 33 | pub struct ScancodeStream { 34 | //_private域的目的是防止从模块外部构造结构。这使new函数成为构造该类型的唯一方法。 35 | _private: (), 36 | } 37 | 38 | impl ScancodeStream { 39 | pub fn new() -> Self { 40 | SCANCODE_QUEUE 41 | .try_init_once(|| ArrayQueue::new(100)) 42 | .expect("ScancodeStream::new should only be called once"); 43 | ScancodeStream { _private: () } 44 | } 45 | } 46 | 47 | impl Stream for ScancodeStream { 48 | type Item = u8; 49 | 50 | fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 51 | let queue = SCANCODE_QUEUE.try_get().expect("not initialized"); 52 | 53 | let scancode_op = queue.pop(); 54 | match scancode_op { 55 | Some(_) => { 56 | return Poll::Ready(scancode_op); 57 | } 58 | None => { 59 | WAKER.register(&cx.waker()); 60 | let scancode_op2 = queue.pop(); 61 | match scancode_op2 { 62 | Some(_) => { 63 | WAKER.take(); 64 | return Poll::Ready(scancode_op2); 65 | } 66 | None => { 67 | return Poll::Pending; 68 | } 69 | } 70 | } 71 | } 72 | } 73 | } 74 | 75 | //打印键盘键入函数 76 | pub async fn print_keypresses() { 77 | let mut scancodes = ScancodeStream::new(); 78 | let mut keyboard = Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::Ignore); 79 | 80 | while let Some(scancode) = scancodes.next().await { 81 | if let Ok(Some(key_event)) = keyboard.add_byte(scancode) { 82 | if let Some(key) = keyboard.process_keyevent(key_event) { 83 | match key { 84 | DecodedKey::Unicode(character) => print!("{}", character), 85 | DecodedKey::RawKey(key) => print!("{:?}", key), 86 | } 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # juner_os 2 | 3 | ![juner_os](j-file.png) 4 | 5 | [中文](./Readme_zh_CN.md) 6 | 7 | # introduction 8 | 9 | This project combines elements from both [blog_os](https://os.phil-opp.com/) and [mal](https://github.com/kanaka/mal). 10 | A lisp shell that can run interactive is now implemented. The subsequent goal is to organize the code of the operating system in a mixed way of lisp and rust. At the same time, the core library is ready to be loaded and maintained using lisp. The project is in progress. 11 | 12 | # features 13 | 14 | - rust implementation of the kernel (load BIOS) 15 | - LISP REPL 16 | - Support for load-file method to load mal files after kernel load. 17 | - The code can now be written in the user folder. It can be loaded using the laod-file method in the replica after kernel boot. 18 | - The kernel loads `entry.jaml` as an entry file. 19 | - The extension of the lisp dialect is `jmal` (Juner-os's Make A Lisp!). 20 | - Supports ps2 mouse. Just open the comments in kernel/src/board/mouse.rs. 21 | 22 | # dependencies 23 | 24 | - rustc 1.48.0-nightly 25 | - qemu 26 | 27 | # run 28 | 29 | ``` 30 | make all 31 | ``` 32 | 33 | # Lisp mal grammar 34 | 35 | - [Grammar](./grammar.md) 36 | 37 | # Dream List 38 | 39 | - [ ] display printing in VGA text mode 40 | - [x] Cursor Follow 41 | - [x] Delete 42 | - [ ] Code Tip Tab 43 | - [x] Cursor mobile editing 44 | - [ ] Scroll bar 45 | - [ ] Lisp Full Functionality 46 | - [x] Macro support 47 | - [ ] Support for code hints 48 | - [ ] sacnf method 49 | - [ ] File Read/Write 50 | - [ ] module loading 51 | - [ ] JIT 52 | - [ ] support for call/cc 53 | - [ ] Equipment 54 | - [ ] Identify the hard drive 55 | - [ ] Sound Drive 56 | - [ ] Network Card Support 57 | - [ ] abstract function 58 | - [x] UEFI support 59 | - [ ] Parallel Multitasking 60 | - [ ] GUI support 61 | - [ ] network load lisp module 62 | - [ ] Multiple Core Utilization 63 | - [ ] bootstrapping (supporting rust environments) 64 | - [ ] the dream app 65 | - [ ] MAL, the editor of the dialect. 66 | - [ ] NoteBook 67 | - [ ] mal's vscode editor plugin 68 | 69 | # Work and goals now 70 | 71 | ~~At present the realization of the function is still very preliminary, lisp inside there is no mechanism to achieve, the kernel has to realize the content. Now we are working on using UEFI to boot, so that the system can read and write files, and run them within lisp.Later the uefi branch will be merged into the master branch and used as a mainstream.~~ 72 | 73 | The load-file has been largely implemented. Now there are two directions to go.~~ One is to write a mal language plugin for vscode (developed as a separate project, of course).~~ The other is to write a simple editor to implement a freeze-like method. Let the methods currently running in the kernel be written to a disk file and then saved out in reverse by a script. 74 | 75 | # Looking forward to you joining and improving the project 76 | 77 | Contact me: zzhggmm@gmail.com 78 | 79 | # Thanks 80 | 81 | - blog_os 82 | - mal 83 | - rcore 84 | - @senseiod and wich project I copy a lot: https://github.com/senseiod/AiliceOS 85 | -------------------------------------------------------------------------------- /kernel/src/task/executor.rs: -------------------------------------------------------------------------------- 1 | use super::{Task, TaskId}; 2 | use alloc::{collections::BTreeMap, sync::Arc, task::Wake}; 3 | use core::task::{Context, Poll, Waker}; 4 | use crossbeam_queue::ArrayQueue; 5 | 6 | pub struct Executor { 7 | tasks: BTreeMap, 8 | task_queue: Arc>, 9 | waker_cache: BTreeMap, 10 | } 11 | 12 | impl Executor { 13 | pub fn new() -> Self { 14 | Executor { 15 | tasks: BTreeMap::new(), 16 | task_queue: Arc::new(ArrayQueue::new(100)), 17 | waker_cache: BTreeMap::new(), 18 | } 19 | } 20 | 21 | pub fn spawn(&mut self, task: Task) { 22 | let task_id = task.id; 23 | if self.tasks.insert(task.id, task).is_some() { 24 | panic!("task with same ID already in tasks"); 25 | } 26 | self.task_queue.push(task_id).expect("queue full"); 27 | } 28 | 29 | pub fn run(&mut self) -> ! { 30 | loop { 31 | self.run_ready_tasks(); 32 | self.sleep_if_idle(); 33 | } 34 | } 35 | 36 | fn run_ready_tasks(&mut self) { 37 | // destructure `self` to avoid borrow checker errors 38 | let Self { 39 | tasks, 40 | task_queue, 41 | waker_cache, 42 | } = self; 43 | 44 | loop { 45 | let task_op = task_queue.pop(); 46 | match task_op { 47 | Some(_) => { 48 | let task_id = task_op.unwrap(); 49 | let task = match tasks.get_mut(&task_id) { 50 | Some(task) => task, 51 | None => continue, // task no longer exists 52 | }; 53 | let waker = waker_cache 54 | .entry(task_id) 55 | .or_insert_with(|| TaskWaker::new(task_id, task_queue.clone())); 56 | let mut context = Context::from_waker(waker); 57 | match task.poll(&mut context) { 58 | Poll::Ready(()) => { 59 | // task done -> remove it and its cached waker 60 | tasks.remove(&task_id); 61 | waker_cache.remove(&task_id); 62 | } 63 | Poll::Pending => {} 64 | } 65 | } 66 | None => {} 67 | } 68 | } 69 | } 70 | 71 | fn sleep_if_idle(&self) { 72 | use x86_64::instructions::interrupts::{self, enable_interrupts_and_hlt}; 73 | 74 | interrupts::disable(); 75 | if self.task_queue.is_empty() { 76 | enable_interrupts_and_hlt(); 77 | } else { 78 | interrupts::enable(); 79 | } 80 | } 81 | } 82 | 83 | struct TaskWaker { 84 | task_id: TaskId, 85 | task_queue: Arc>, 86 | } 87 | 88 | impl TaskWaker { 89 | fn new(task_id: TaskId, task_queue: Arc>) -> Waker { 90 | Waker::from(Arc::new(TaskWaker { 91 | task_id, 92 | task_queue, 93 | })) 94 | } 95 | 96 | fn wake_task(&self) { 97 | self.task_queue.push(self.task_id).expect("task_queue full"); 98 | } 99 | } 100 | 101 | impl Wake for TaskWaker { 102 | fn wake(self: Arc) { 103 | self.wake_task(); 104 | } 105 | 106 | fn wake_by_ref(self: &Arc) { 107 | self.wake_task(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /kernel/src/memory/mod.rs: -------------------------------------------------------------------------------- 1 | use bitmap_allocator::BitAlloc; 2 | use bootloader::{BootInfo, MemoryType}; 3 | use buddy_system_allocator::LockedHeap; 4 | use lazy_static::*; 5 | use log::*; 6 | use spin::Mutex; 7 | 8 | pub const PAGE_SIZE: usize = 1 << 12; 9 | pub const PHYSICAL_MEMORY_OFFSET: usize = 0xffff8000_00000000; 10 | pub const KERNEL_OFFSET: usize = 0xffffff00_00000000; 11 | pub const MEMORY_OFFSET: usize = 0; 12 | 13 | pub mod heap; 14 | 15 | #[global_allocator] 16 | static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty(); 17 | 18 | pub type FrameAlloc = bitmap_allocator::BitAlloc256M; 19 | 20 | lazy_static! { 21 | pub static ref FRAME_ALLOCATOR: Mutex = Mutex::new(FrameAlloc::default()); 22 | } 23 | 24 | pub fn init_frame(boot_info: &BootInfo) { 25 | let mut all_size: f64 = 0.0; 26 | let memory_map = &boot_info.memory_map; 27 | println!( 28 | "Kernel usable memory range ({} total)", 29 | memory_map.clone().iter().len() 30 | ); 31 | for descriptor in memory_map.clone().iter() { 32 | if descriptor.ty == MemoryType::CONVENTIONAL { 33 | let start_frame = descriptor.phys_start as usize / PAGE_SIZE; 34 | let end_frame = start_frame + descriptor.page_count as usize; 35 | println!( 36 | "{:#x} - {:#x} ({} Kib)", 37 | start_frame, end_frame, descriptor.page_count 38 | ); 39 | all_size += descriptor.page_count as f64; 40 | FRAME_ALLOCATOR.lock().insert(start_frame..end_frame); 41 | } 42 | } 43 | let all_size = all_size * PAGE_SIZE as f64 / (1024 * 1024) as f64; 44 | println!("Total memory: {} M", all_size); 45 | println!("Init memory Frame"); 46 | } 47 | 48 | /// Convert physical address to virtual address 49 | #[inline] 50 | pub const fn phys_to_virt(paddr: usize) -> usize { 51 | PHYSICAL_MEMORY_OFFSET + paddr 52 | } 53 | 54 | /// Convert virtual address to physical address 55 | #[inline] 56 | pub const fn virt_to_phys(vaddr: usize) -> usize { 57 | vaddr - PHYSICAL_MEMORY_OFFSET 58 | } 59 | 60 | /// Convert virtual address to the offset of kernel 61 | #[inline] 62 | pub const fn kernel_offset(vaddr: usize) -> usize { 63 | vaddr - KERNEL_OFFSET 64 | } 65 | 66 | #[derive(Debug, Clone, Copy)] 67 | pub struct GlobalFrameAlloc; 68 | 69 | trait FrameAllocator { 70 | fn alloc(&self) -> Option; 71 | fn alloc_contiguous(&self, size: usize, align_log2: usize) -> Option; 72 | fn dealloc(&self, target: usize); 73 | } 74 | 75 | impl FrameAllocator for GlobalFrameAlloc { 76 | fn alloc(&self) -> Option { 77 | let ret = FRAME_ALLOCATOR 78 | .lock() 79 | .alloc() 80 | .map(|id| id * PAGE_SIZE + MEMORY_OFFSET); 81 | trace!("Allocate frame: {:x?}", ret); 82 | ret 83 | } 84 | 85 | fn alloc_contiguous(&self, size: usize, align_log2: usize) -> Option { 86 | let ret = FRAME_ALLOCATOR 87 | .lock() 88 | .alloc_contiguous(size, align_log2) 89 | .map(|id| id * PAGE_SIZE + MEMORY_OFFSET); 90 | trace!("Allocate frame: {:x?}", ret); 91 | ret 92 | } 93 | 94 | fn dealloc(&self, target: usize) { 95 | trace!("Deallocate frame: {:x}", target); 96 | FRAME_ALLOCATOR 97 | .lock() 98 | .dealloc((target - MEMORY_OFFSET) / PAGE_SIZE); 99 | } 100 | } 101 | 102 | pub fn alloc_frame() -> Option { 103 | GlobalFrameAlloc.alloc() 104 | } 105 | pub fn dealloc_frame(target: usize) { 106 | GlobalFrameAlloc.dealloc(target); 107 | } 108 | pub fn alloc_frame_contiguous(size: usize, align_log2: usize) -> Option { 109 | GlobalFrameAlloc.alloc_contiguous(size, align_log2) 110 | } 111 | 112 | type VirtAddr = usize; 113 | type PhysAddr = usize; 114 | -------------------------------------------------------------------------------- /kernel/src/board/acpi_table.rs: -------------------------------------------------------------------------------- 1 | pub use acpi::{ 2 | interrupt::{InterruptModel, InterruptSourceOverride, IoApic, Polarity, TriggerMode}, 3 | Acpi, 4 | }; 5 | use alloc::vec::Vec; 6 | use lazy_static::*; 7 | use spin::Mutex; 8 | use acpi::{parse_rsdp, AcpiHandler, PhysicalMapping}; 9 | use crate::memory::{PAGE_SIZE, phys_to_virt}; 10 | use core::ptr::NonNull; 11 | use bootloader::BootInfo; 12 | 13 | pub struct AcpiTable { 14 | inner: Acpi, 15 | } 16 | 17 | static mut CONFIG: Config = Config { 18 | acpi_rsdp: 0, 19 | smbios: 0, 20 | }; 21 | 22 | /// Configuration of HAL. 23 | pub struct Config { 24 | pub acpi_rsdp: u64, 25 | pub smbios: u64, 26 | } 27 | 28 | lazy_static! { 29 | static ref ACPI_TABLE: Mutex> = Mutex::default(); 30 | } 31 | 32 | impl AcpiTable { 33 | fn initialize_check() { 34 | let mut table = ACPI_TABLE.lock(); 35 | if table.is_none() { 36 | *table = get_acpi_table().map(|x| AcpiTable { inner: x }); 37 | } 38 | } 39 | pub fn invalidate() { 40 | *ACPI_TABLE.lock() = None; 41 | } 42 | pub fn get_ioapic() -> Vec { 43 | Self::initialize_check(); 44 | let table = ACPI_TABLE.lock(); 45 | match &*table { 46 | None => Vec::default(), 47 | Some(table) => match table.inner.interrupt_model.as_ref().unwrap() { 48 | InterruptModel::Apic(apic) => { 49 | apic.io_apics.iter().map(|x| IoApic { ..*x }).collect() 50 | } 51 | _ => Vec::default(), 52 | }, 53 | } 54 | } 55 | pub fn get_interrupt_source_overrides() -> Vec { 56 | Self::initialize_check(); 57 | let table = ACPI_TABLE.lock(); 58 | match &*table { 59 | None => Vec::default(), 60 | Some(table) => match table.inner.interrupt_model.as_ref().unwrap() { 61 | InterruptModel::Apic(apic) => apic 62 | .interrupt_source_overrides 63 | .iter() 64 | .map(|x| InterruptSourceOverride { 65 | polarity: Self::clone_polarity(&x.polarity), 66 | trigger_mode: Self::clone_trigger_mode(&x.trigger_mode), 67 | ..*x 68 | }) 69 | .collect(), 70 | _ => Vec::default(), 71 | }, 72 | } 73 | } 74 | fn clone_polarity(x: &Polarity) -> Polarity { 75 | match x { 76 | Polarity::SameAsBus => Polarity::SameAsBus, 77 | Polarity::ActiveHigh => Polarity::ActiveHigh, 78 | Polarity::ActiveLow => Polarity::ActiveLow, 79 | } 80 | } 81 | fn clone_trigger_mode(x: &TriggerMode) -> TriggerMode { 82 | match x { 83 | TriggerMode::SameAsBus => TriggerMode::SameAsBus, 84 | TriggerMode::Edge => TriggerMode::Edge, 85 | TriggerMode::Level => TriggerMode::Level, 86 | } 87 | } 88 | } 89 | 90 | /// Get physical address of `acpi_rsdp` and `smbios` on x86_64. 91 | pub fn pc_firmware_tables() -> (u64, u64) { 92 | unsafe { (CONFIG.acpi_rsdp, CONFIG.smbios) } 93 | } 94 | 95 | pub fn get_acpi_addr(boot_info: &BootInfo) { 96 | unsafe { 97 | CONFIG = Config { 98 | acpi_rsdp: boot_info.acpi2_rsdp_addr, 99 | smbios: boot_info.smbios_addr, 100 | }; 101 | } 102 | } 103 | 104 | pub fn get_acpi_table() -> Option { 105 | let mut handler = AcpiHelper {}; 106 | println!("Get ACPI address :{:#x?}\n Smbios address: {:#x?}", pc_firmware_tables().0, pc_firmware_tables().1); 107 | match unsafe { parse_rsdp(&mut handler, pc_firmware_tables().0 as usize) } { 108 | Ok(table) => Some(table), 109 | Err(info) => { 110 | warn!("get_acpi_table error: {:#x?}", info); 111 | None 112 | } 113 | } 114 | } 115 | 116 | /// Build ACPI Table 117 | struct AcpiHelper {} 118 | impl AcpiHandler for AcpiHelper { 119 | unsafe fn map_physical_region( 120 | &mut self, 121 | physical_address: usize, 122 | size: usize, 123 | ) -> PhysicalMapping { 124 | #[allow(non_snake_case)] 125 | let OFFSET = 0; 126 | let page_start = physical_address / PAGE_SIZE; 127 | let page_end = (physical_address + size + PAGE_SIZE - 1) / PAGE_SIZE; 128 | PhysicalMapping:: { 129 | physical_start: physical_address, 130 | virtual_start: NonNull::new_unchecked(phys_to_virt(physical_address + OFFSET) as *mut T), 131 | mapped_length: size, 132 | region_length: PAGE_SIZE * (page_end - page_start), 133 | } 134 | } 135 | fn unmap_physical_region(&mut self, _region: PhysicalMapping) {} 136 | } -------------------------------------------------------------------------------- /kernel/src/interrupts/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::board::{ 2 | acpi_table::AcpiTable, 3 | mouse::{init_mouse, mouse}, 4 | }; 5 | use crate::memory::phys_to_virt; 6 | use alloc::boxed::Box; 7 | use alloc::vec::Vec; 8 | use apic::{IoApic, LocalApic, XApic}; 9 | use lazy_static::*; 10 | use spin::Mutex; 11 | use trapframe; 12 | use trapframe::TrapFrame; 13 | use x86_64::instructions::interrupts; 14 | use x86_64::registers::control::{Cr4, Cr4Flags}; 15 | 16 | const TABLE_SIZE: usize = 256; 17 | const LAPIC_ADDR: usize = 0xfee0_0000; 18 | const IOAPIC_ADDR: usize = 0xfec0_0000; 19 | pub type InterruptHandle = Box; 20 | 21 | lazy_static! { 22 | static ref IRQ_TABLE: Mutex>> = Default::default(); 23 | } 24 | 25 | pub fn init() { 26 | unsafe { 27 | trapframe::init(); 28 | } 29 | init_ioapic(); 30 | init_irq_table(); 31 | irq_add_handle(KEYBOARD + IRQ0, Box::new(keyboard)); 32 | irq_add_handle(COM1 + IRQ0, Box::new(com1)); 33 | irq_add_handle(PS2MOUSE + IRQ0, Box::new(mouse)); 34 | irq_enable_raw(KEYBOARD, KEYBOARD + IRQ0); 35 | irq_enable_raw(COM1, COM1 + IRQ0); 36 | init_mouse(); 37 | irq_enable_raw(PS2MOUSE, PS2MOUSE + IRQ0); 38 | crate::drivers::serial::COM1.lock().init(); 39 | unsafe { 40 | // enable global page 41 | Cr4::update(|f| f.insert(Cr4Flags::PAGE_GLOBAL)); 42 | } 43 | interrupts::enable(); 44 | test!("Init Interrupts"); 45 | } 46 | 47 | fn init_irq_table() { 48 | let mut table = IRQ_TABLE.lock(); 49 | for _ in 0..TABLE_SIZE { 50 | table.push(None); 51 | } 52 | } 53 | 54 | fn irq_enable_raw(irq: u8, vector: u8) { 55 | println!("irq_enable_raw: irq={:#x?}, vector={:#x?}", irq, vector); 56 | let mut ioapic = unsafe { IoApic::new(phys_to_virt(IOAPIC_ADDR)) }; 57 | ioapic.set_irq_vector(irq, vector); 58 | ioapic.enable(irq, 0) 59 | } 60 | 61 | #[no_mangle] 62 | pub extern "C" fn trap_handler(tf: &mut TrapFrame) { 63 | // debug!("Interrupt: {:#x} @ CPU{}", tf.trap_num, 0); // TODO 0 should replace in multi-core case 64 | match tf.trap_num as u8 { 65 | DOUBLE_FAULT => double_fault(tf), 66 | PAGE_FAULT => page_fault(tf), 67 | BREAKPOINT => breakpoint(), 68 | IRQ0..=63 => irq_handle(tf.trap_num as u8), 69 | _ => panic!("Unhandled interrupt {:x} {:#x?}", tf.trap_num, tf), 70 | } 71 | } 72 | 73 | pub fn irq_handle(irq: u8) { 74 | let mut lapic = unsafe { XApic::new(phys_to_virt(LAPIC_ADDR)) }; 75 | lapic.eoi(); 76 | let table = IRQ_TABLE.lock(); 77 | match &table[irq as usize] { 78 | Some(f) => f(), 79 | None => panic!("unhandled external IRQ number: {}", irq), 80 | } 81 | } 82 | 83 | fn breakpoint() { 84 | panic!("\nEXCEPTION: BREAKPOINT"); 85 | } 86 | 87 | fn double_fault(tf: &TrapFrame) { 88 | panic!("\nEXCEPTION: Double Fault\n{:#x?}", tf); 89 | } 90 | 91 | fn page_fault(tf: &mut TrapFrame) { 92 | panic!("\nEXCEPTION: Page Fault\n{:#x?}", tf); 93 | } 94 | 95 | fn com1() { 96 | let c = crate::drivers::serial::COM1.lock().receive(); 97 | crate::drivers::serial::serial_put(c); 98 | } 99 | 100 | fn keyboard() { 101 | use pc_keyboard::{DecodedKey, KeyCode}; 102 | if let Some(key) = crate::board::keyboard::receive() { 103 | match key { 104 | DecodedKey::Unicode(c) => print!("{}", c), 105 | DecodedKey::RawKey(code) => { 106 | let s = match code { 107 | KeyCode::ArrowUp => "\u{1b}[A", 108 | KeyCode::ArrowDown => "\u{1b}[B", 109 | KeyCode::ArrowRight => "\u{1b}[C", 110 | KeyCode::ArrowLeft => "\u{1b}[D", 111 | _ => "", 112 | }; 113 | for c in s.bytes() { 114 | print!("{}", c); 115 | } 116 | } 117 | } 118 | } 119 | } 120 | 121 | fn init_ioapic() { 122 | unsafe { 123 | for ioapic in AcpiTable::get_ioapic() { 124 | println!("Ioapic found: {:#x?}", ioapic); 125 | let mut ip = IoApic::new(phys_to_virt(ioapic.address as usize)); 126 | ip.disable_all(); 127 | let mut lapic = XApic::new(phys_to_virt(ioapic.address as usize)); 128 | lapic.cpu_init(); 129 | } 130 | } 131 | let mut ip = unsafe { IoApic::new(phys_to_virt(IOAPIC_ADDR)) }; 132 | ip.disable_all(); 133 | } 134 | 135 | /// Add a handle to IRQ table. Return the specified irq or an allocated irq on success 136 | pub fn irq_add_handle(irq: u8, handle: InterruptHandle) -> Option { 137 | debug!("IRQ add handle {:#x?}", irq); 138 | let mut table = IRQ_TABLE.lock(); 139 | // allocate a valid irq number 140 | if irq == 0 { 141 | let mut id = 0x20; 142 | while id < table.len() { 143 | if table[id].is_none() { 144 | table[id] = Some(handle); 145 | return Some(id as u8); 146 | } 147 | id += 1; 148 | } 149 | return None; 150 | } 151 | match table[irq as usize] { 152 | Some(_) => None, 153 | None => { 154 | table[irq as usize] = Some(handle); 155 | Some(irq) 156 | } 157 | } 158 | } 159 | 160 | // Reference: https://wiki.osdev.org/Exceptions 161 | //const DivideError: u8 = 0; 162 | //const Debug: u8 = 1; 163 | //const NonMaskableInterrupt: u8 = 2; 164 | const BREAKPOINT: u8 = 3; 165 | //const Overflow: u8 = 4; 166 | //const BoundRangeExceeded: u8 = 5; 167 | //const InvalidOpcode: u8 = 6; 168 | //const DeviceNotAvailable: u8 = 7; 169 | const DOUBLE_FAULT: u8 = 8; 170 | //const CoprocessorSegmentOverrun: u8 = 9; 171 | //const InvalidTSS: u8 = 10; 172 | //const SegmentNotPresent: u8 = 11; 173 | //const StackSegmentFault: u8 = 12; 174 | //const GeneralProtectionFault: u8 = 13; 175 | const PAGE_FAULT: u8 = 14; 176 | //const FloatingPointException: u8 = 16; 177 | //const AlignmentCheck: u8 = 17; 178 | //const MachineCheck: u8 = 18; 179 | //const SIMDFloatingPointException: u8 = 19; 180 | //const VirtualizationException: u8 = 20; 181 | //const SecurityException: u8 = 30; 182 | 183 | pub(crate) const IRQ0: u8 = 32; 184 | 185 | // IRQ 186 | pub const TIMER: u8 = 0; 187 | pub const KEYBOARD: u8 = 1; 188 | pub const PS2MOUSE: u8 = 12; 189 | //const COM2: u8 = 3; 190 | pub const COM1: u8 = 4; 191 | //const IDE: u8 = 14; 192 | //const Error: u8 = 19; 193 | //const Spurious: u8 = 31; 194 | -------------------------------------------------------------------------------- /kernel/src/drivers/bus/pci.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | drivers::block::ahci, 3 | memory::{phys_to_virt, PAGE_SIZE}, 4 | }; 5 | use alloc::{collections::BTreeMap, sync::Arc}; 6 | use lazy_static::*; 7 | use pci::*; 8 | use spin::Mutex; 9 | use x86_64::instructions::port::Port; 10 | 11 | use crate::drivers::Driver; 12 | 13 | // 存PCI设备 14 | lazy_static! { 15 | pub static ref PCI_DRIVERS: Mutex>> = 16 | Mutex::new(BTreeMap::new()); 17 | } 18 | 19 | struct PortOpsImpl; 20 | 21 | impl PortOps for PortOpsImpl { 22 | unsafe fn read8(&self, port: u16) -> u8 { 23 | Port::new(port).read() 24 | } 25 | unsafe fn read16(&self, port: u16) -> u16 { 26 | Port::new(port).read() 27 | } 28 | unsafe fn read32(&self, port: u16) -> u32 { 29 | Port::new(port).read() 30 | } 31 | unsafe fn write8(&self, port: u16, val: u8) { 32 | Port::new(port).write(val); 33 | } 34 | unsafe fn write16(&self, port: u16, val: u16) { 35 | Port::new(port).write(val); 36 | } 37 | unsafe fn write32(&self, port: u16, val: u32) { 38 | Port::new(port).write(val); 39 | } 40 | } 41 | 42 | pub fn init() { 43 | let pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) }; 44 | for dev in pci_iter { 45 | debug!( 46 | "pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) irq: {}:{:?}", 47 | dev.loc.bus, 48 | dev.loc.device, 49 | dev.loc.function, 50 | dev.id.vendor_id, 51 | dev.id.device_id, 52 | dev.id.class, 53 | dev.id.subclass, 54 | dev.pic_interrupt_line, 55 | dev.interrupt_pin, 56 | ); 57 | init_driver(&dev); 58 | } 59 | } 60 | 61 | pub fn init_driver(dev: &PCIDevice) { 62 | // let name = format!("enp{}s{}f{}", dev.loc.bus, dev.loc.device, dev.loc.function); 63 | // match (dev.id.vendor_id, dev.id.device_id) { 64 | // (0x8086, 0x100e) | (0x8086, 0x100f) | (0x8086, 0x10d3) => { 65 | // // 0x100e 66 | // // 82540EM Gigabit Ethernet Controller 67 | // // 0x100f 68 | // // 82545EM Gigabit Ethernet Controller (Copper) 69 | // // 0x10d3 70 | // // 82574L Gigabit Network Connection 71 | // if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { 72 | // let irq = unsafe { enable(dev.loc) }; 73 | // let vaddr = phys_to_virt(addr as usize); 74 | // // let index = NET_DRIVERS.read().len(); 75 | // e1000::init(name, irq, vaddr, len as usize, index); 76 | // return; 77 | // } 78 | // } 79 | // (0x8086, 0x10fb) => { 80 | // // 82599ES 10-Gigabit SFI/SFP+ Network Connection 81 | // if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { 82 | // let irq = unsafe { enable(dev.loc) }; 83 | // let vaddr = phys_to_virt(addr as usize); 84 | // // let index = NET_DRIVERS.read().len(); 85 | // PCI_DRIVERS.lock().insert( 86 | // dev.loc, 87 | // ixgbe::ixgbe_init(name, irq, vaddr, len as usize, index), 88 | // ); 89 | // return; 90 | // } 91 | // } 92 | // _ => {} 93 | // } 94 | if dev.id.class == 0x01 && dev.id.subclass == 0x06 { 95 | // Mass storage class 96 | // SATA subclass 97 | if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[5] { 98 | debug!("Found AHCI dev {:?} BAR5 {:x?}", dev, addr); 99 | let irq = unsafe { enable(dev.loc) }; 100 | assert!(len as usize <= PAGE_SIZE); 101 | let vaddr = phys_to_virt(addr as usize); 102 | if let Some(driver) = ahci::init(irq, vaddr, len as usize) { 103 | PCI_DRIVERS.lock().insert(dev.loc, driver); 104 | } 105 | } 106 | } 107 | } 108 | 109 | unsafe fn enable(loc: Location) -> Option { 110 | let ops = &PortOpsImpl; 111 | let am = CSpaceAccessMethod::IO; 112 | 113 | // 23 and lower are used 114 | static mut MSI_IRQ: u32 = 23; 115 | 116 | let orig = am.read16(ops, loc, PCI_COMMAND); 117 | // IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable 118 | am.write32(ops, loc, PCI_COMMAND, (orig | 0x40f) as u32); 119 | 120 | // find MSI cap 121 | let mut msi_found = false; 122 | let mut cap_ptr = am.read8(ops, loc, PCI_CAP_PTR) as u16; 123 | let mut assigned_irq = None; 124 | while cap_ptr > 0 { 125 | let cap_id = am.read8(ops, loc, cap_ptr); 126 | if cap_id == PCI_CAP_ID_MSI { 127 | let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP); 128 | // The manual Volume 3 Chapter 10.11 Message Signalled Interrupts 129 | // 0 is (usually) the apic id of the bsp. 130 | am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12)); 131 | MSI_IRQ += 1; 132 | let irq = MSI_IRQ; 133 | assigned_irq = Some(irq as usize); 134 | // we offset all our irq numbers by 32 135 | if (orig_ctrl >> 16) & (1 << 7) != 0 { 136 | // 64bit 137 | am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_64, irq + 32); 138 | } else { 139 | // 32bit 140 | am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_32, irq + 32); 141 | } 142 | 143 | // enable MSI interrupt, assuming 64bit for now 144 | am.write32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000); 145 | debug!( 146 | "MSI control {:#b}, enabling MSI interrupt {}", 147 | orig_ctrl >> 16, 148 | irq 149 | ); 150 | msi_found = true; 151 | } 152 | debug!("PCI device has cap id {} at {:#X}", cap_id, cap_ptr); 153 | cap_ptr = am.read8(ops, loc, cap_ptr + 1) as u16; 154 | } 155 | 156 | if !msi_found { 157 | // Use PCI legacy interrupt instead 158 | // IO Space | MEM Space | Bus Mastering | Special Cycles 159 | am.write32(ops, loc, PCI_COMMAND, (orig | 0xf) as u32); 160 | debug!("MSI not found, using PCI interrupt"); 161 | } 162 | 163 | debug!("pci device enable done"); 164 | 165 | assigned_irq 166 | } 167 | 168 | const PCI_COMMAND: u16 = 0x04; 169 | const PCI_CAP_PTR: u16 = 0x34; 170 | const PCI_INTERRUPT_LINE: u16 = 0x3c; 171 | const PCI_INTERRUPT_PIN: u16 = 0x3d; 172 | 173 | const PCI_MSI_CTRL_CAP: u16 = 0x00; 174 | const PCI_MSI_ADDR: u16 = 0x04; 175 | const PCI_MSI_UPPER_ADDR: u16 = 0x08; 176 | const PCI_MSI_DATA_32: u16 = 0x08; 177 | const PCI_MSI_DATA_64: u16 = 0x0C; 178 | 179 | const PCI_CAP_ID_MSI: u8 = 0x05; 180 | -------------------------------------------------------------------------------- /grammar_zh.md: -------------------------------------------------------------------------------- 1 | # Lisp 语法 2 | 3 | ## 数据类型 4 | 5 | - 布尔型 true/false 6 | - 空类型 nil 7 | 8 | ## 给符号绑定“值”(S 表达式) 9 | 10 | ### def! 11 | 12 | ```lisp 13 | (def! x1 S) 14 | ``` 15 | 16 | - x1 是要绑定的符号 17 | - S 要绑定的 S 表达式 18 | 19 | example: 20 | 21 | ```lisp 22 | 23 | (def! mynum 111) 24 | => 111 25 | ;; 此时绑定值到了mynum 这个符号上 26 | ``` 27 | 28 | ### let\* 29 | 30 | ```lisp 31 | (let* (p (+ 2 3) 32 | q (+ 2 p)) (+ p q)) 33 | => 12 34 | ``` 35 | 36 | 使用 let\* 临时赋值 37 | 38 | ### lambda 39 | 40 | ``` 41 | ((lambda [x] (+ 1 x)) 1) 42 | => 2 43 | ``` 44 | 45 | 定义一个闭包过程。可以和 def!组合起来定义一个函数。 46 | 47 | 注意参数的语法 如果在参数前使用&符号可以表示多个参数都到一个 list 中。而且只能使用在最后一个参数的前面。 48 | 49 | ### do 50 | 51 | ```lisp 52 | (do (+ 1 2) (+ 3 4) 5) 53 | => 5 54 | ``` 55 | 56 | 计算列表中的每个元素的值,然后返回最后一个元素的值。 57 | 58 | ### list 59 | 60 | ```lisp 61 | (list 1 2 3) 62 | => (1 2 3) 63 | ``` 64 | 65 | 生成一个 Lisp 的列表。 66 | 67 | ### read-string 68 | 69 | ```lisp 70 | (read-string "Nil") 71 | => Nil 72 | 73 | (read-string "(+ 1 1)") 74 | => (Fn* 1 1) 75 | 76 | ``` 77 | 78 | 读一个字符串生成一个 Lisp 对象,注意只生成对象,但是不进行求值。 79 | 80 | ### eval 81 | 82 | ```lisp 83 | (eval (read-string "(+ 1 3)")) 84 | => 4 85 | 86 | (eval (list + 1 3)) 87 | => 4 88 | 89 | ``` 90 | 91 | 对 Lisp 对象进行求值。使用这个方法后,Lisp 中没有了数据和代码的界限。捅破了数据和代码的那层窗户纸。 92 | 93 | ### prn 94 | 95 | 打印一个符号如果不存在就报错 96 | 97 | ```lisp 98 | (prn abc) 99 | => not found 'abc' 100 | ``` 101 | 102 | ### quote 103 | 104 | 表示后面的值是这个符号本身 105 | 可以和 prn 进行配合使用 106 | 107 | ```lisp 108 | (prn (quote abc)) 109 | 110 | => abc 111 | => Nil 112 | ``` 113 | 114 | 解释:打印 abc 是 prn 函数的副作用。prn 函数真正的返回是 Nil。 115 | 116 | ### ' 117 | 118 | ' 是 quote 的语法糖。 119 | 'abc 和 (quote abc)是完全等效的。实际上它在解释器内部也会翻译成 quote 的形式。 120 | 121 | ### quasiquote 、 unquote 和 splice-unquote 122 | 123 | quasiquote 建立一个可以临时求值的的符号。如果单独使用和 quote 没有什么区别。 124 | 要和 unquote 与 splice-unquote 联合使用。其中有轻微的差别。unquote 表示对下一个符号进行临时取值。 125 | splice-unquote 临时取值后把列表展开。 126 | 127 | 具体例子如下: 128 | 129 | ```lisp 130 | (def! lst '(2 3)) 131 | => (2 3) 132 | 133 | (quasiquote (1 (unquote lst))) 134 | => (1 (2 3)) 135 | 136 | (quasiquote (1 (splice-unquote lst))) 137 | => (1 2 3) 138 | ``` 139 | 140 | ### ` 、 ~ 和 ~@ 141 | 142 | quasiquote 、 unquote 和 splice-unquote 的语法糖。 143 | 144 | ```lisp 145 | (def! lst '(2 3)) 146 | => (2 3) 147 | 148 | `(1 ~lst) 149 | => (1 (2 3)) 150 | 151 | `(1 ~@lst) 152 | => (1 2 3) 153 | ``` 154 | 155 | ### cons 156 | 157 | 这个函数将它的第一个参数连接到它的第二个参数 (一个列表) 前面,返回一个新列表。 158 | 159 | ```lisp 160 | (cons [1] [2 3]) 161 | => ([1] 2 3) 162 | 163 | (cons 1 [2 3]) 164 | => (1 2 3) 165 | ``` 166 | 167 | ### concat 168 | 169 | 这个函数接受零个或多个列表作为参数,并且返回由这些列表的所有参数组成的一个新列表。 170 | 171 | ```lisp 172 | (concat [1 2] (list 3 4) [5 6]) 173 | => (1 2 3 4 5 6) 174 | 175 | (concat [1 2]) 176 | => (1 2) 177 | ``` 178 | 179 | ### defmacro! 和 macroexpand 180 | 181 | 宏定义和宏展开 182 | 183 | 宏定义 定义一个符号。它的返回值会被继续当做 ast 进行求值。所有这里可以广泛的运用到之前的' ` ~ ~@ d 等语法糖。 184 | 宏展开。展开一个宏,只计算出它要求值的 ast 而不进行求值。 185 | 186 | ```lisp 187 | (defmacro! unless (lambda (pred a b) `(if ~pred ~b ~a))) 188 | 189 | => ...(此处省略) 190 | 191 | (unless false 7 8) 192 | => 7 193 | 194 | (macroexpand (unless false 7 8)) 195 | => (if fasle 7 8) 196 | ``` 197 | 198 | ### nth 199 | 200 | 这个函数接受一个列表(或向量)以及一个数字(序号)作为参数,返回列表中给定序号位置的元素。如果序号超出了返回,函数抛出一个异常。 201 | 202 | ```lisp 203 | (nth [1 2 3] 0) 204 | => 1 205 | 206 | (nth '(1 2 3) 1) 207 | => 2 208 | ``` 209 | 210 | ### first 211 | 212 | 这个函数接受一个列表(或向量)作为参数,返回它的第一个元素,如果列表(或向量)是空的,或者参数本身是 nil,则返回 nil。 213 | 214 | ```lisp 215 | (first '((1 2) 2 3)) 216 | 217 | => (1 2) 218 | ``` 219 | 220 | ### count 221 | 222 | 接受一个列表或者向量返回列表或者向量的长度 223 | 224 | ```lisp 225 | (count '(1 2 (2 3))) 226 | => 3 227 | 228 | (count [1 2 3]) 229 | => 3 230 | ``` 231 | 232 | ### empty? 233 | 234 | 接受一个列表或者向量判断这个对象是否事空。如果我空的情况下返回 true 否则返回 false 235 | 236 | ```lisp 237 | (empty? '()) 238 | => true 239 | 240 | (empty? nil) 241 | => true 242 | ``` 243 | 244 | ### try* catch* 和 throw 245 | 246 | try-catch 代码块和其他 语言的 try-catch 并没有什么特别的不同。try 后面跟着一个语句。如果有多条语句可以使用 do 语句进行配合,而 catch 247 | 语句中,会有一个异常,并且可以控制代码段的返回。如果使用了 throw 可以主动的抛出一个异常。 248 | 249 | ```lisp 250 | (throw "err1") 251 | => err1 252 | 253 | (try* abc (catch* exc (prn "exc is:" exc))) 254 | => "exc is:" "not found 'abc'" 255 | 256 | (try* (throw "my exception") (catch* exc (do (prn "exc:" exc) 7))) 257 | => "exc:" "my exception" 258 | => 7 259 | ``` 260 | 261 | ### apply 262 | 263 | 它有两个参数,第一个参数是一个函数。而第二个参数是这个函数需要的入参的列表。这个函数会返回这个求值的结果。 264 | 265 | ```lisp 266 | (apply + (list 1 3)) 267 | => 4 268 | 269 | (apply + '(2 3)) 270 | => 5 271 | 272 | (apply (lambda [x y] (do (prn x "+" y) (+ x y))) '(7 8)) 273 | => 7 "+" 8 274 | => 15 275 | ``` 276 | 277 | ### map 278 | 279 | 它有两个参数,第一个参数是一个函数,第二个参数是一个向量或者列表。之后它会对第二个参数中的每个值进行求值,然后结果返回一个新的列表。 280 | 注意 map 每个函数只接受一个参数。但是可以配合 apply 达到传多个值的效果。 281 | 282 | ```lisp 283 | 284 | (map (lambda [x] (apply + x)) (list [1 2] [2 3])) 285 | => (3 5) 286 | 287 | ``` 288 | 289 | ### 几个简单的类型判断函数 290 | 291 | - nil? 292 | - true? 293 | - false? 294 | - symbol? (判断是不是符号) 295 | 296 | ### Atom 进行原子操作 297 | 298 | - atom: 输入一个 mal 值,并返回一个新的指向这个值的原子。 299 | - atom?: 判断输入的参数是不是原子,如果是,返回 true。 300 | - deref: 输入一个原子作为参数,返回这个原子所引用的值。 301 | - reset!: 输入一个原子以及一个 mal 值,修改原子,让它指向这个 mal 值,并返回这个 mal 值。 302 | - swap!: 输入一个原子,一个函数,以及零个或多个函数参数。将原子的值作为第一参数,并将余下的函数参数作为可选的参数传输函数中,将原子的值置为函数的求值结果。返回新的原子的值。(边注: Mal 是单线程的,但在像 Clojure 之类的并发语言中,swap!将是一个原子操作,(swap! myatom (fn\* [x] (+ 1 x)))总是会把 myatom 计数增加 1,并且在原子被多个线程操作时不会导致结果出错) 303 | 304 | ```lisp 305 | (def! *test-atom* (atom 0)) 306 | => (atom 0) 307 | 308 | (reset! *test-atom* 10) 309 | => 10 310 | 311 | (deref *test-atom*) | @*test-atom* 312 | => 10 313 | 314 | (swap! *test-atom* (lambda [x] (+ x 1))) 315 | => 11 316 | ``` 317 | 318 | @ 是 deref 的语法糖 319 | 320 | ### Hash-Map 的操作和 关键字 321 | 322 | 在此方言中 hashmap 是一种基本的类型。使用{}大括号表示字面量。其中 key 可以使用两种方式。字符串和关键字。关键字是使用:开头的字符串。 323 | {"a" 1 "b" 2} 324 | {:a 1 :b 2} 325 | 上面两种形式都可以表示一个 map. 326 | 327 | - hash-map: 接受偶数数量的参数,返回一个新的 mal 哈希表,其中键为奇数位置的参数,它们的值分别为与之对应的偶数位置的参数,它基本上是 {}reader 字面语法的函数形式。 328 | - map?: 接受一个参数,如果参数是哈希表的话,返回 true(mal 中的 true 值),否则返回 false(mal 中的 false 值) 329 | - assoc: 接受一个哈希表作为第一个参数,余下的参数为需要关联(合并)到哈希表里的奇/偶-键/值对。注意,原始的哈希表不会被修改(记住,mal 的值是不可变的),旧哈希表中的键/值与参数中的键/值对合并而成的新的哈希表作为结果返回。 330 | - dissoc:接受一个哈希表作为第一个参数,余下的参数为需要从哈希表中删除的键。与前面一样,注意原始的哈希表是不变的,只是把删除了参数中指定的键的新哈希表返回出来。参数列表中在原哈希表不存在的键会被忽略。 331 | - get: 接受一个哈希表和一个键,返回哈希表中与这个键对应的值,如果哈希表中不存在这个键,则返回 nil。 332 | - contains?: 接受一个哈希表和一个键,如果哈希表中包含这个键,则返回 true(mal 中的 true 值),否则返回 false(mal 中的 false 值)。 333 | - keys: 接受一个哈希表,并返回一个列表(mal 中的 列表值),其中包含了哈希表中的所有的键。 334 | - vals: 接受一个哈希表,并返回一个列表(mal 中的 列表值),其中包含了哈希表中的所有的值。 335 | 336 | 注意上面的方法都没有产生副作用,也就是没有改变原理的值。如果你要这么做的话建议你使用 atom 或者重新 def! 337 | 338 | ### gensym 生成一个系统中全新的符号 339 | 340 | ```lisp 341 | (gensym) 342 | => 每次运行不一样! 343 | ``` 344 | 345 | ### cond 多条件 346 | 347 | 有偶数个参数一个是条件一个是返回的值 348 | 349 | ```lisp 350 | (def! ten-test (lambda [data] 351 | (cond 352 | (> data 10) 1 353 | (= data 10) 0 354 | (< data 10) -1))) 355 | 356 | (ten-test 15) 357 | => 1 358 | ``` 359 | 360 | # ls 361 | 362 | 列出当前目录下的文件和文件夹 363 | 364 | ```lisp 365 | (ls) 366 | => (. .. mal) 367 | 368 | (ls "mal") 369 | => (. .. hello.mal) 370 | ``` 371 | 372 | # read-file 373 | 374 | 读取文件内容到字符串 375 | 376 | ```lisp 377 | (read-file "mal/hello.mal") 378 | => "(+ 1 1)" 379 | ``` 380 | 381 | # load-file 382 | 383 | 读取 mal 格式的文件,并且加载里面的语句。返回 nil 384 | 385 | a.mal 386 | 387 | ```lisp 388 | (def! test (lambda [x] (prn x))) 389 | ``` 390 | 391 | ```lisp 392 | (load-file "a.mal") 393 | => nil 394 | (test "x") 395 | => "x" 396 | => nil 397 | ``` 398 | 399 | TODO 其他基本函数 400 | -------------------------------------------------------------------------------- /bootloader/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | #![feature(abi_efiapi)] 4 | #![feature(llvm_asm)] 5 | 6 | #[macro_use] 7 | extern crate alloc; 8 | 9 | mod page_table; 10 | 11 | use alloc::boxed::Box; 12 | use alloc::string::ToString; 13 | use log::*; 14 | use uefi::prelude::*; 15 | use uefi::proto::console::gop::GraphicsOutput; 16 | use uefi::proto::media::file::{ 17 | File, FileAttribute, FileInfo, FileMode, FileSystemVolumeLabel, RegularFile, 18 | }; 19 | use uefi::proto::media::fs::SimpleFileSystem; 20 | use uefi::table::boot::AllocateType; 21 | use uefi::table::cfg::{ACPI2_GUID,SMBIOS_GUID}; 22 | use x86_64::registers::control::{Cr0, Cr0Flags, Efer, EferFlags}; 23 | use xmas_elf::ElfFile; 24 | 25 | use alloc::vec::Vec; 26 | use bootloader::{BootInfo, GraphicInfo, KernelEntry, KernelEntryFn, MemoryType}; 27 | use core::mem; 28 | use x86_64::structures::paging::{PageSize, Size4KiB}; 29 | use x86_64::VirtAddr; 30 | 31 | const PHYSICAL_MEMORY_OFFSET: u64 = 0xFFFF800000000000; 32 | 33 | #[entry] 34 | fn efi_main(image_handle: Handle, system_table: SystemTable) -> Status { 35 | uefi_services::init(&system_table).expect_success("failed to initialize utilities"); 36 | 37 | let boot_services = system_table.boot_services(); 38 | // Initialize our "kernel" frame allocator which marks frames as `MEMORY_TYPE_KERNEL`. 39 | let mut frame_allocator = page_table::UEFIFrameAllocator::new(boot_services); 40 | let mut page_table = page_table::init_recursive(&mut frame_allocator); 41 | 42 | // RSDP(根系统描述指针)是ACPI编程接口中使用的数据结构。 43 | // 如果您使用的是UEFI,则可以在EFI_SYSTEM_TABLE中的某个位置找到它。因此,无需搜索RAM。 44 | let acpi2_addr = system_table 45 | .config_table() 46 | .iter() 47 | .find(|entry| entry.guid == ACPI2_GUID) 48 | .expect("Failed to find RSDP") 49 | .address; 50 | 51 | info!("ACPI2 RSDP address is : {:?}", acpi2_addr); 52 | // Get smbios addr 53 | let smbios_addr = system_table 54 | .config_table() 55 | .iter() 56 | .find(|entry| entry.guid == SMBIOS_GUID) 57 | .expect("failed to find SMBIOS") 58 | .address; 59 | info!("smbios: {:?}", smbios_addr); 60 | 61 | // 获取memory map 62 | let max_mmap_size = boot_services.memory_map_size(); 63 | let mmap_storage = Box::leak(vec![0; max_mmap_size * 2].into_boxed_slice()); 64 | let mmap_iter = boot_services 65 | .memory_map(mmap_storage) 66 | .expect_success("failed to get memory map") 67 | .1; 68 | 69 | let max_phys_addr = mmap_iter 70 | .map(|m| m.phys_start + m.page_count * Size4KiB::SIZE - 1) 71 | .max() 72 | .unwrap() 73 | .max(0xFFFF_FFFF); 74 | 75 | unsafe { 76 | Cr0::update(|f| f.remove(Cr0Flags::WRITE_PROTECT)); 77 | Efer::update(|f| f.insert(EferFlags::NO_EXECUTE_ENABLE)); 78 | } // 根页表是只读的,禁用写入保护 79 | 80 | let (elf, kernel_entry) = load_kernel(boot_services); 81 | 82 | page_table::map_elf(&elf, &mut page_table, &mut frame_allocator).expect("failed to map ELF"); 83 | 84 | page_table::map_physical_memory( 85 | PHYSICAL_MEMORY_OFFSET, 86 | max_phys_addr, 87 | &mut page_table, 88 | &mut frame_allocator, 89 | ); 90 | 91 | unsafe { 92 | Cr0::update(|f| f.insert(Cr0Flags::WRITE_PROTECT)); 93 | } // 恢复写入保护 94 | 95 | let resolution: (usize, usize) = (1280, 720); 96 | let graphic_info = init_graphic(boot_services, Option::from(resolution)); 97 | 98 | // 创造一个128宽度的Vec 99 | // 必须在退出boot_services之前创建,否则退出后无法正常分配alloc 100 | let mut memory_map = Vec::with_capacity(128); 101 | 102 | // 退出启动服务,启动kernel 103 | let (_rt, mmap_iter) = system_table 104 | .exit_boot_services(image_handle, mmap_storage) 105 | .expect_success("Failed to exit boot services"); 106 | 107 | for desc in mmap_iter { 108 | memory_map.push(desc); 109 | } 110 | 111 | // construct BootInfo 112 | let boot_info = BootInfo { 113 | memory_map, 114 | physical_memory_offset: PHYSICAL_MEMORY_OFFSET, 115 | graphic_info, 116 | acpi2_rsdp_addr: acpi2_addr as u64, 117 | smbios_addr: smbios_addr as u64, 118 | }; 119 | 120 | // 将bootinfo传递给内核,并跳转到内核 121 | jump_to_entry(&boot_info, kernel_entry); 122 | } 123 | 124 | fn jump_to_entry(boot_info: *const BootInfo, kernel_entry: KernelEntry) -> ! { 125 | let kernel_entry: KernelEntryFn = unsafe { mem::transmute(kernel_entry) }; 126 | kernel_entry(unsafe { &*boot_info }) 127 | } 128 | 129 | fn load_kernel(boot_services: &BootServices) -> (ElfFile, KernelEntry) { 130 | let kernel_path = r"EFI\kernel\kernel.elf"; 131 | let mut info_buf = [0u8; 0x100]; 132 | let file_system = unsafe { 133 | &mut *boot_services 134 | .locate_protocol::() 135 | .expect_success("Failed to open SimpleFileSystem") 136 | .get() 137 | }; 138 | let mut root = file_system 139 | .open_volume() 140 | .expect_success("Failed to open volumes"); 141 | let volume_label = file_system 142 | .open_volume() 143 | .expect_success("Failed to open volume") 144 | .get_info::(&mut info_buf) 145 | .expect_success("Failed to open volumes") 146 | .volume_label() 147 | .to_string(); 148 | info!("The Volume Label is: {}", volume_label); 149 | let file_handle = root 150 | .open(kernel_path, FileMode::Read, FileAttribute::empty()) 151 | .expect_success("Failed to open file"); 152 | let mut file_handle = unsafe { RegularFile::new(file_handle) }; 153 | info!("Loading file to memory"); 154 | let info = file_handle 155 | .get_info::(&mut info_buf) 156 | .expect_success("Failed to get file info"); 157 | let pages = info.file_size() as usize / 0x1000 + 1; 158 | let mem_start = boot_services 159 | .allocate_pages(AllocateType::AnyPages, MemoryType::LOADER_DATA, pages) 160 | .expect_success("Failed to allocate pages"); 161 | let buf = unsafe { core::slice::from_raw_parts_mut(mem_start as *mut u8, pages * 0x1000) }; 162 | let len: usize = file_handle.read(buf).expect_success("Failed to read file"); 163 | let elf = ElfFile::new(buf[..len].as_ref()).expect("Failed to parse ELF"); 164 | let kernel_entry_addr = elf.header.pt2.entry_point(); 165 | info!("Kernel Entry Point: {:x}", kernel_entry_addr); 166 | let kernel_entry: KernelEntry = KernelEntry(VirtAddr::new(kernel_entry_addr)); 167 | // 读取内核entry地址 168 | (elf, kernel_entry) 169 | } 170 | 171 | /// If `resolution` is some, then set graphic mode matching the resolution. 172 | /// Return information of the final graphic mode. 173 | fn init_graphic(bs: &BootServices, resolution: Option<(usize, usize)>) -> GraphicInfo { 174 | let gop = bs 175 | .locate_protocol::() 176 | .expect_success("failed to get GraphicsOutput"); 177 | let gop = unsafe { &mut *gop.get() }; 178 | if let Some(resolution) = resolution { 179 | let mode = gop 180 | .modes() 181 | .map(|mode| mode.expect("Warnings encountered while querying mode")) 182 | .find(|ref mode| { 183 | let info = mode.info(); 184 | info.resolution() == resolution 185 | }) 186 | .expect("graphic mode not found"); 187 | info!("switching graphic mode"); 188 | gop.set_mode(&mode) 189 | .expect_success("Failed to set graphics mode"); 190 | } 191 | GraphicInfo { 192 | mode: gop.current_mode_info(), 193 | fb_addr: gop.frame_buffer().as_mut_ptr() as u64, 194 | fb_size: gop.frame_buffer().size() as u64, 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /kernel/src/mal/types.rs: -------------------------------------------------------------------------------- 1 | use alloc::rc::Rc; 2 | use alloc::string::{String,ToString}; 3 | use crate::mal::types::MalErr::{ErrString,ErrMalVal}; 4 | use alloc::vec::Vec; 5 | use core::cell::RefCell; 6 | use hashbrown::HashMap; 7 | use crate::mal::types::MalVal::{Hash,Str,Nil,Func,Bool,Int,Sym,List,Vector,MalFunc,Atom}; 8 | use crate::mal::env::{Env,env_bind}; 9 | 10 | #[derive(Debug,Clone)] 11 | pub enum MalVal{ 12 | Nil, 13 | Bool(bool), //布尔类型 14 | Int(i64), // int类型 15 | Str(String), // 字符串类型 16 | Sym(String), 17 | List(Rc>, Rc), // 列表类型 18 | Vector(Rc>, Rc), // 向量类型 19 | Hash(Rc>,Rc), // hashMap 类型 20 | Func(fn(MalArgs) -> MalRet,Rc), //函数 相当于 lambda (x)-> M 21 | MalFunc { 22 | eval: fn(ast: MalVal, env: Env) -> MalRet, 23 | ast: Rc, // 函数 抽象语法树 24 | env: Env, // repl 环境 25 | params: Rc, // 参数值 TODO: 其实可以单值然后用柯里化 26 | is_macro: bool, // 是否是宏 27 | meta: Rc, // 元数据 28 | }, 29 | Atom(Rc>) //原子 30 | } 31 | 32 | // Mal 报错结构 33 | #[derive(Debug)] 34 | pub enum MalErr { 35 | ErrString(String), 36 | ErrMalVal(MalVal), 37 | } 38 | 39 | // Mal 入参 40 | pub type MalArgs = Vec; 41 | // Mal 出参结构 42 | pub type MalRet = Result; 43 | 44 | #[macro_export] 45 | macro_rules! list { 46 | ($seq:expr) => {{ 47 | List(Rc::new($seq),Rc::new(Nil)) 48 | }}; 49 | [$($args:expr),*] => {{ 50 | let v: Vec = vec![$($args),*]; 51 | List(Rc::new(v),Rc::new(Nil)) 52 | }} 53 | } 54 | 55 | #[macro_export] 56 | macro_rules! vector { 57 | ($seq:expr) => {{ 58 | Vector(Rc::new($seq),Rc::new(Nil)) 59 | }}; 60 | [$($args:expr),*] => {{ 61 | let v: Vec = vec![$($args),*]; 62 | Vector(Rc::new(v),Rc::new(Nil)) 63 | }} 64 | } 65 | 66 | #[macro_export] 67 | macro_rules! vec { 68 | ($elem:expr;$n:expr) => { 69 | $crate::alloc::vec::from_elem($elem, n) 70 | }; 71 | ($($x:expr),*) => { 72 | <[_]>::into_vec(box[$($x),*]) 73 | }; 74 | ($($x:expr,)*) => {$crate::vec![$($x),*]} 75 | } 76 | 77 | #[macro_export] 78 | macro_rules! format { 79 | ($($arg:tt)*) => ($crate::alloc::fmt::format(format_args!($($arg)*))) 80 | } 81 | 82 | // type utility functions 83 | 84 | //抛出错误 85 | pub fn error(s: &str) -> MalRet { 86 | Err(ErrString(s.to_string())) 87 | } 88 | 89 | //格式化错误输出 90 | pub fn format_error(e: MalErr) -> String { 91 | match e { 92 | ErrString(s) => s.clone(), 93 | ErrMalVal(mv) => mv.pr_str(true), 94 | } 95 | } 96 | 97 | // 把参数 变成hashmap 98 | pub fn _assoc(mut hm: HashMap, kvs: MalArgs) -> MalRet { 99 | if kvs.len() % 2 != 0 { 100 | return error("odd number of elements"); 101 | } 102 | let mut itre = kvs.iter(); 103 | loop{ 104 | let k = itre.next(); 105 | match k { 106 | Some(Str(s))=>{ 107 | match itre.next() { 108 | Some(v) => { 109 | hm.insert(s.to_string(), v.clone()); 110 | }, 111 | // 这里应该永远也不会发生 112 | None => return error("key to value,vlaue is not a MalVal"), 113 | } 114 | }, 115 | None => break, 116 | _ => return error("key is not string"), 117 | } 118 | } 119 | Ok(Hash(Rc::new(hm), Rc::new(Nil))) 120 | } 121 | 122 | // 创建hashmap 123 | pub fn hash_map(kvs: MalArgs) -> MalRet { 124 | let hm: HashMap = HashMap::new(); 125 | _assoc(hm, kvs) 126 | } 127 | 128 | // 创建一个函数 129 | pub fn func(f: fn(MalArgs) -> MalRet) -> MalVal { 130 | Func(f, Rc::new(Nil)) 131 | } 132 | 133 | // 创造一个原子 134 | pub fn atom(mv:&MalVal) ->MalVal { 135 | Atom(Rc::new(RefCell::new(mv.clone()))) 136 | } 137 | 138 | // 实现比较方法 判断两个 MalVal 是否相等 139 | impl PartialEq for MalVal { 140 | fn eq(&self, other: &MalVal) -> bool { 141 | match (self, other) { 142 | (Nil, Nil) => true, 143 | (Bool(ref a), Bool(ref b)) => a == b, 144 | (Int(ref a), Int(ref b)) => a == b, 145 | (Str(ref a), Str(ref b)) => a == b, 146 | (Sym(ref a), Sym(ref b)) => a == b, 147 | (List(ref a, _), List(ref b, _)) 148 | | (Vector(ref a, _), Vector(ref b, _)) 149 | | (List(ref a, _), Vector(ref b, _)) 150 | | (Vector(ref a, _), List(ref b, _)) => a == b, 151 | (Hash(ref a, _), Hash(ref b, _)) => a == b, 152 | (MalFunc { .. }, MalFunc { .. }) => false, // 两个函数永远也不能相同! 153 | _ => false, 154 | } 155 | } 156 | } 157 | 158 | // 删除hash map 中指定的key, 并且返回 删除后的map,不改变原来的值 159 | pub fn _dissoc(mut hm: HashMap, ks: MalArgs) -> MalRet { 160 | for k in ks.iter() { 161 | match k { 162 | Str(ref s) => { 163 | hm.remove(s); 164 | } 165 | _ => return error("key is not string"), 166 | } 167 | } 168 | Ok(Hash(Rc::new(hm), Rc::new(Nil))) 169 | } 170 | 171 | impl MalVal { 172 | 173 | pub fn apply(&self, args: MalArgs) -> MalRet { 174 | match *self { 175 | Func(f, _) => f(args), 176 | MalFunc { 177 | eval, 178 | ref ast, 179 | ref env, 180 | ref params, 181 | .. 182 | } => { 183 | let a = &**ast; 184 | let p = &**params; 185 | // 给环境中的变量绑定值 相当于形参绑定实参 然后返回一个子环境 注意这个子环境是可以追溯到母环境的绑定的 186 | let fn_env = env_bind(Some(env.clone()), p.clone(), args)?; 187 | Ok(eval(a.clone(), fn_env)?) 188 | } 189 | _ => error("attempt to call non-function"), 190 | } 191 | } 192 | 193 | // 获取一个原子所对应的值 194 | pub fn deref(&self) -> MalRet { 195 | match self { 196 | Atom(a) => Ok(a.borrow().clone()), 197 | _ => error("attempt to deref a non-Atom") 198 | } 199 | } 200 | 201 | // 重新绑定原子, 使他指向这个新的ast对象,下面的new 202 | pub fn reset_bang(&self, new: &MalVal) -> MalRet { 203 | match self { 204 | Atom(a) => { 205 | *a.borrow_mut() = new.clone(); 206 | Ok(new.clone()) 207 | } 208 | _ => error("attempt to reset! a non-Atom"), 209 | } 210 | } 211 | 212 | // 对于一个atom 输入一个函数 然后把atom的值加在最开始作为输入使用进行求值 并且更新原子的值 213 | pub fn swap_bang(&self, args: &MalArgs) -> MalRet { 214 | match self { 215 | Atom(a) => { 216 | let f = &args[0]; 217 | let mut fargs = args[1..].to_vec(); 218 | fargs.insert(0, a.borrow().clone()); 219 | *a.borrow_mut() = f.apply(fargs)?; 220 | Ok(a.borrow().clone()) 221 | } 222 | _ => error("attempt to swap! a non-Atom"), 223 | } 224 | } 225 | 226 | // 判断对象是否为空 227 | pub fn empty_q(&self) -> MalRet { 228 | match self { 229 | List(l,_) | Vector(l,_) => Ok(Bool(l.len()==0)), 230 | Nil => Ok(Bool(true)), 231 | _ => error("invalid empty value!"), 232 | } 233 | } 234 | 235 | pub fn count(&self) -> MalRet { 236 | match self{ 237 | List(l, _) | Vector(l, _) => Ok(Int(l.len() as i64)), 238 | Nil => Ok(Int(0)), 239 | _ => error("invalid type for count"), 240 | } 241 | } 242 | 243 | // 将Str转换成关键字 244 | pub fn keyword(&self) -> MalRet { 245 | match self { 246 | Str(s) if s.starts_with("\u{29e}") => Ok(Str(s.to_string())), 247 | Str(s) => Ok(Str(format!("\u{29e}{}", s))), 248 | _ => error("invalid type for keyword"), 249 | } 250 | } 251 | 252 | } 253 | -------------------------------------------------------------------------------- /kernel/src/shell.rs: -------------------------------------------------------------------------------- 1 | use crate::mal::core::load_core; 2 | use crate::mal::env::env_new; 3 | use crate::mal::env::Env; 4 | use crate::mal::rep; 5 | use crate::mal::types::format_error; 6 | use alloc::string::String; 7 | use alloc::vec::Vec; 8 | use core::fmt::Arguments; 9 | 10 | pub fn init_shell() { 11 | //清屏 12 | crate::console::io::clear_screen(); 13 | head(); 14 | // 本地程序 15 | shell(format_args!("MAL")); 16 | } 17 | 18 | pub fn shell(args: Arguments) { 19 | let mut history = Vec::new(); 20 | let kernel_env: Env = env_new(None); 21 | load_core(&kernel_env); 22 | print!(93;"\n"); 23 | loop { 24 | print!(93; "{} [IN]:",args); 25 | let cmd = get_line(&mut history); 26 | if cmd == String::from("") { 27 | continue; 28 | } 29 | let name = cmd.trim(); 30 | print!(93;"{}\n",name); 31 | match rep(name, &kernel_env) { 32 | Ok(out) => print!(93;">>:{}\n", out), 33 | Err(e) => print!(93;">>:{}\n", format_error(e)), 34 | } 35 | } 36 | } 37 | 38 | const BEL: u8 = 0x07u8; 39 | const BS: u8 = 0x08u8; 40 | const LF: u8 = 0x0au8; 41 | const CR: u8 = 0x0du8; 42 | const ESC: u8 = 0x1bu8; 43 | const DEL: u8 = 0x7fu8; 44 | 45 | fn get_line(history: &mut Vec>) -> String { 46 | let mut cursor = 0; 47 | let mut line_vec = Vec::with_capacity(512); 48 | let mut history_index = history.len(); 49 | loop { 50 | match get_char() { 51 | BS | DEL => { 52 | // Backspace 53 | if cursor > 0 { 54 | cursor -= 1; 55 | line_vec.remove(cursor); 56 | 57 | put_char(BS); 58 | for byte in &line_vec[cursor..] { 59 | put_char(*byte); 60 | } 61 | put_char(b' '); 62 | for _i in cursor..line_vec.len() { 63 | put_char(ESC); 64 | put_char(b'['); 65 | put_char(b'D'); 66 | } 67 | put_char(ESC); 68 | put_char(b'['); 69 | put_char(b'D'); 70 | } else { 71 | put_char(BEL); 72 | } 73 | } 74 | CR | LF => { 75 | // Return 76 | put_char(CR); 77 | put_char(LF); 78 | break; 79 | } 80 | ESC => { 81 | match get_char() { 82 | b'[' => { 83 | match get_char() { 84 | b'D' => { 85 | // Left arrow 86 | if cursor > 0 { 87 | cursor -= 1; 88 | put_char(ESC); 89 | put_char(b'['); 90 | put_char(b'D'); 91 | } else { 92 | put_char(BEL); 93 | } 94 | } 95 | b'C' => { 96 | // Right arrow 97 | if cursor < line_vec.len() { 98 | cursor += 1; 99 | put_char(ESC); 100 | put_char(b'['); 101 | put_char(b'C'); 102 | } else { 103 | put_char(BEL); 104 | } 105 | } 106 | direction @ b'A' | direction @ b'B' => { 107 | if direction == b'A' && history_index > 0 { 108 | // Up arrow 109 | history_index -= 1; 110 | } else if direction == b'B' && !history.is_empty() // usize underflow 111 | && history_index < history.len() - 1 112 | { 113 | // Down arrow 114 | history_index += 1; 115 | } else { 116 | put_char(BEL); 117 | continue; 118 | } 119 | 120 | for _ in 0..line_vec.len() { 121 | put_char(ESC); 122 | put_char(b'['); 123 | put_char(b'D'); 124 | } 125 | for _ in 0..line_vec.len() { 126 | put_char(b' '); 127 | } 128 | for _ in 0..line_vec.len() { 129 | put_char(ESC); 130 | put_char(b'['); 131 | put_char(b'D'); 132 | } 133 | line_vec = history[history_index].clone(); 134 | cursor = line_vec.len(); 135 | for byte in &line_vec { 136 | put_char(*byte); 137 | } 138 | } 139 | _ => { 140 | put_char(BEL); 141 | } 142 | } 143 | } 144 | _ => { 145 | put_char(BEL); 146 | } 147 | } 148 | } 149 | byte if byte.is_ascii_graphic() || byte == b' ' => { 150 | line_vec.insert(cursor, byte); 151 | for byte in &line_vec[cursor..] { 152 | put_char(*byte); 153 | } 154 | cursor += 1; 155 | for _i in cursor..line_vec.len() { 156 | put_char(ESC); 157 | put_char(b'['); 158 | put_char(b'D'); 159 | } 160 | } 161 | _ => { 162 | // unrecognized characters 163 | put_char(BEL); 164 | } 165 | } 166 | } 167 | 168 | if !line_vec.is_empty() { 169 | history.push(line_vec.clone()); 170 | } 171 | String::from_utf8(line_vec).unwrap_or_default() 172 | } 173 | 174 | fn get_char() -> u8 { 175 | crate::console::io::getchar() 176 | } 177 | 178 | pub fn put_char(ch: u8) { 179 | print!("{}", ch as char); 180 | } 181 | 182 | fn head() { 183 | print!(96;" 184 | ** ** ** **** ** ******** ******* 185 | /** /** /** /**/** /** /**///// /**////** 186 | /** /** /** /**//** /** /** /** /** 187 | /** /** /** /** //** /** /******* /******* 188 | /** /** /** /** //**/** /**//// /**///** 189 | ** /** /** /** /** //**** /** /** //** 190 | //***** //******* /** //*** /******** /** //** 191 | ///// /////// // /// //////// // // 192 | ******* ******** 193 | **/////** **////// 194 | ** //**/** 195 | /** /**/********* 196 | /** /**////////** 197 | //** ** /** version: V0.0.1 198 | //******* ******** since @ 2019 199 | /////// //////// made by zhouzihao \n" 200 | ); 201 | print!(96;"Weclome to my page:https://github.com/zzhgithub/juner_os\n"); 202 | print!(96;"you can use MAL a small lisp!\n"); 203 | print!(96;"\n"); 204 | } 205 | -------------------------------------------------------------------------------- /bootloader/src/page_table.rs: -------------------------------------------------------------------------------- 1 | //! 该文件是从'rust-osdev/bootloader'中的'page_table.rs'修改而来的 2 | use log::*; 3 | use uefi::table::boot::{AllocateType, BootServices, MemoryType}; 4 | use uefi::ResultExt; 5 | use x86_64::registers::control::{Cr3, Cr3Flags, Cr4, Cr4Flags, Efer, EferFlags}; 6 | use x86_64::structures::paging::{ 7 | mapper::*, FrameAllocator, Mapper, Page, PageSize, PageTable, PageTableFlags, PhysFrame, 8 | Size2MiB, Size4KiB, 9 | }; 10 | use x86_64::{align_up, PhysAddr, VirtAddr}; 11 | use xmas_elf::{program, ElfFile}; 12 | 13 | pub struct UEFIFrameAllocator<'a>(&'a BootServices); 14 | 15 | impl<'a> UEFIFrameAllocator<'a> { 16 | pub fn new(services: &'a BootServices) -> Self { 17 | Self(services) 18 | } 19 | } 20 | 21 | unsafe impl<'a> FrameAllocator for UEFIFrameAllocator<'a> { 22 | fn allocate_frame(&mut self) -> Option> { 23 | let phys_addr = self 24 | .0 25 | .allocate_pages(AllocateType::AnyPages, MemoryType::LOADER_DATA, 1) 26 | .expect_success("Failed to allocate physical frame"); 27 | let phys_addr = PhysAddr::new(phys_addr); 28 | let phys_frame = PhysFrame::containing_address(phys_addr); 29 | Some(phys_frame) 30 | } 31 | } 32 | 33 | pub fn map_elf( 34 | elf: &ElfFile, 35 | page_table: &mut impl Mapper, 36 | frame_allocator: &mut impl FrameAllocator, 37 | ) -> Result<(), MapToError> { 38 | info!("mapping ELF"); 39 | let kernel_start = PhysAddr::new(elf.input.as_ptr() as u64); 40 | for segment in elf.program_iter() { 41 | map_segment(&segment, kernel_start, page_table, frame_allocator)?; 42 | } 43 | Ok(()) 44 | } 45 | 46 | // 段地址映射 47 | fn map_segment( 48 | segment: &program::ProgramHeader, 49 | kernel_start: PhysAddr, 50 | page_table: &mut impl Mapper, 51 | frame_allocator: &mut impl FrameAllocator, 52 | ) -> Result<(), MapToError> { 53 | if let program::Type::Load = segment.get_type().unwrap() { 54 | let mem_size = segment.mem_size(); 55 | let file_size = segment.file_size(); 56 | let file_offset = segment.offset() & !0xfff; 57 | let phys_start_addr = kernel_start + file_offset; 58 | let virt_start_addr = VirtAddr::new(segment.virtual_addr()); 59 | 60 | let start_page: Page = Page::containing_address(virt_start_addr); 61 | let start_frame = PhysFrame::containing_address(phys_start_addr); 62 | let end_frame = PhysFrame::containing_address(phys_start_addr + file_size - 1u64); 63 | 64 | let flags = segment.flags(); 65 | let mut page_table_flags = PageTableFlags::PRESENT; 66 | if !flags.is_execute() { 67 | page_table_flags |= PageTableFlags::NO_EXECUTE 68 | }; 69 | if flags.is_write() { 70 | page_table_flags |= PageTableFlags::WRITABLE 71 | }; 72 | 73 | for frame in PhysFrame::range_inclusive(start_frame, end_frame) { 74 | let offset = frame - start_frame; 75 | let page = start_page + offset; 76 | unsafe { 77 | page_table 78 | .map_to(page, frame, page_table_flags, frame_allocator)? 79 | .flush(); 80 | } 81 | } 82 | 83 | if mem_size > file_size { 84 | // .bss section (or similar), which needs to be zeroed 85 | let zero_start = virt_start_addr + file_size; 86 | let zero_end = virt_start_addr + mem_size; 87 | if zero_start.as_u64() & 0xfff != 0 { 88 | // A part of the last mapped frame needs to be zeroed. This is 89 | // not possible since it could already contains parts of the next 90 | // segment. Thus, we need to copy it before zeroing. 91 | 92 | let new_frame = frame_allocator 93 | .allocate_frame() 94 | .ok_or(MapToError::FrameAllocationFailed)?; 95 | 96 | type PageArray = [u64; Size4KiB::SIZE as usize / 8]; 97 | 98 | let last_page = Page::containing_address(virt_start_addr + file_size - 1u64); 99 | let last_page_ptr = end_frame.start_address().as_u64() as *mut PageArray; 100 | let temp_page_ptr = new_frame.start_address().as_u64() as *mut PageArray; 101 | 102 | unsafe { 103 | // copy contents 104 | temp_page_ptr.write(last_page_ptr.read()); 105 | } 106 | 107 | // remap last page 108 | if let Err(e) = page_table.unmap(last_page) { 109 | return Err(match e { 110 | UnmapError::ParentEntryHugePage => MapToError::ParentEntryHugePage, 111 | UnmapError::PageNotMapped => unreachable!(), 112 | UnmapError::InvalidFrameAddress(_) => unreachable!(), 113 | }); 114 | } 115 | unsafe { 116 | page_table 117 | .map_to(last_page, new_frame, page_table_flags, frame_allocator)? 118 | .flush(); 119 | } 120 | } 121 | 122 | // Map additional frames. 123 | let start_page: Page = Page::containing_address(VirtAddr::new(align_up( 124 | zero_start.as_u64(), 125 | Size4KiB::SIZE, 126 | ))); 127 | let end_page = Page::containing_address(zero_end); 128 | for page in Page::range_inclusive(start_page, end_page) { 129 | let frame = frame_allocator 130 | .allocate_frame() 131 | .ok_or(MapToError::FrameAllocationFailed)?; 132 | unsafe { 133 | page_table 134 | .map_to(page, frame, page_table_flags, frame_allocator)? 135 | .flush(); 136 | } 137 | } 138 | 139 | // zero bss 140 | unsafe { 141 | core::ptr::write_bytes( 142 | zero_start.as_mut_ptr::(), 143 | 0, 144 | (mem_size - file_size) as usize, 145 | ); 146 | } 147 | } 148 | } 149 | Ok(()) 150 | } 151 | 152 | /// 将物理内存[0, max_addr]映射到虚拟空间[offset, offset + max_addr] 153 | pub fn map_physical_memory( 154 | offset: u64, 155 | max_addr: u64, 156 | page_table: &mut impl Mapper, 157 | frame_allocator: &mut impl FrameAllocator, 158 | ) { 159 | info!("mapping physical memory"); 160 | let start_frame = PhysFrame::containing_address(PhysAddr::new(0)); 161 | let end_frame = PhysFrame::containing_address(PhysAddr::new(max_addr)); 162 | for frame in PhysFrame::range_inclusive(start_frame, end_frame) { 163 | let page = Page::containing_address(VirtAddr::new(frame.start_address().as_u64() + offset)); 164 | let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; 165 | unsafe { 166 | page_table 167 | .map_to(page, frame, flags, frame_allocator) 168 | .expect("failed to map physical memory") 169 | .flush(); 170 | } 171 | } 172 | } 173 | 174 | /// Set up a basic recursive page table. 175 | /// 递归 页!! 176 | pub fn init_recursive( 177 | allocator: &mut impl FrameAllocator, 178 | ) -> RecursivePageTable<'static> { 179 | // First we do a copy for the level 4 table here, because the old table 180 | // has memory type `BOOT_SERVICES_DATA`. Level 3 ~ level 1 tables will 181 | // be discarded eventually so we can ignore them. 182 | let old_l4_table_addr = Cr3::read().0.start_address().as_u64(); 183 | let l4_table_frame = allocator.allocate_frame().unwrap(); 184 | let l4_table_addr = l4_table_frame.start_address().as_u64(); 185 | 186 | // Safety: newly allocated frame is guaranteed to be valid and unused 187 | unsafe { 188 | core::ptr::copy( 189 | old_l4_table_addr as *const u8, 190 | l4_table_addr as *mut u8, 191 | l4_table_frame.size() as usize, 192 | ) 193 | }; 194 | 195 | // Safety: same as above 196 | let l4_table = unsafe { &mut *(l4_table_addr as *mut PageTable) }; 197 | 198 | // Recursive mapping 199 | l4_table[0b111_111_111].set_frame( 200 | l4_table_frame, 201 | PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE, 202 | ); 203 | 204 | // Enable all CPU extensions we need. 205 | unsafe { 206 | Cr4::update(|cr4| { 207 | cr4.insert( 208 | Cr4Flags::PAGE_SIZE_EXTENSION 209 | | Cr4Flags::PHYSICAL_ADDRESS_EXTENSION 210 | | Cr4Flags::PAGE_GLOBAL 211 | | Cr4Flags::OSFXSR, 212 | ) 213 | }); 214 | Efer::update(|efer| efer.insert(EferFlags::NO_EXECUTE_ENABLE)); 215 | }; 216 | 217 | // Switch to the new page table... 218 | unsafe { Cr3::write(l4_table_frame, Cr3Flags::empty()) }; 219 | 220 | // And we have it! 221 | let l4_table = unsafe { &mut *(0xFFFF_FFFF_FFFF_F000 as *mut PageTable) }; 222 | 223 | RecursivePageTable::new(l4_table).unwrap() 224 | } 225 | -------------------------------------------------------------------------------- /grammar.md: -------------------------------------------------------------------------------- 1 | # Lisp Syntax 2 | 3 | ## Data type 4 | 5 | - Boolean true/false 6 | - Empty type nil 7 | 8 | ## Bind "values" to symbols (S-expressions) 9 | 10 | ### def! 11 | 12 | ```lisp 13 | (def! x1 S) 14 | ``` 15 | 16 | - x1 is the symbol to bind to. 17 | - S The S expression to bind to. 18 | 19 | example: 20 | 21 | ```lisp 22 | 23 | (def! mynum 111) 24 | => 111 25 | ;; This binds the value to the mynum symbol. 26 | ``` 27 | 28 | ### let\* 29 | 30 | ```lisp 31 | (let* (p (+ 2 3) 32 | q (+ 2 p)) (+ p q)) 33 | => 12 34 | ``` 35 | 36 | Temporary assignment using let\* 37 | 38 | ### lambda 39 | 40 | ``` 41 | ((lambda [x] (+ 1 x)) 1) 42 | => 2 43 | ``` 44 | 45 | Define a closure procedure. It can be combined with def! to define a function. 46 | 47 | Note the syntax of arguments If you use the & symbol before an argument, you can indicate that multiple arguments are in a list. It can only be used before the last argument. 48 | 49 | ### do 50 | 51 | ```lisp 52 | (do (+ 1 2) (+ 3 4) 5) 53 | => 5 54 | ``` 55 | 56 | Calculates the value of each element in the list and then returns the value of the last element. 57 | 58 | ### list 59 | 60 | ```lisp 61 | (list 1 2 3) 62 | => (1 2 3) 63 | ``` 64 | 65 | Generate a list of Lisp. 66 | 67 | ### read-string 68 | 69 | ```lisp 70 | (read-string "Nil") 71 | => Nil 72 | 73 | (read-string "(+ 1 1)") 74 | => (Fn* 1 1) 75 | 76 | ``` 77 | 78 | Read a string to generate a Lisp object, note that only the object is generated, but no evaluation is done. 79 | 80 | ### eval 81 | 82 | ```lisp 83 | (eval (read-string "(+ 1 3)")) 84 | => 4 85 | 86 | (eval (list + 1 3)) 87 | => 4 88 | 89 | ``` 90 | 91 | Evaluate the Lisp object. With this method, there is no boundary between data and code in Lisp. The layer of data and code is poked through. 92 | 93 | ### prn 94 | 95 | Print a symbol and report an error if it does not exist 96 | 97 | ```lisp 98 | (prn abc) 99 | => not found 'abc' 100 | ``` 101 | 102 | ### quote 103 | 104 | indicates that the value that follows is the symbol itself. 105 | Can be used in conjunction with prn 106 | 107 | ```lisp 108 | (prn (quote abc)) 109 | 110 | => abc 111 | => Nil 112 | ``` 113 | 114 | Explanation: printing abc is a side-effect of the prn function. the real return of the prn function is Nil. 115 | 116 | ### ' 117 | 118 | ' is the grammatical sugar of quote. 119 | 'abc and (quote abc) are completely equivalent. It actually translates into quote form inside the interpreter as well. 120 | 121 | ### quasiquote, unquote and splice-unquote 122 | 123 | quasiquote creates a notation that can be evaluated temporarily. If used alone there is no difference between unquote and quote. 124 | To be used in conjunction with unquote and splice-unquote.There is a minor difference. unquote means that the next symbol is temporarily evaluated. 125 | A splice-unquote takes a temporary value and then expands the list. 126 | 127 | Specific examples are as follows. 128 | 129 | ```lisp 130 | (def! lst '(2 3)) 131 | => (2 3) 132 | 133 | (quasiquote (1 (unquote lst))) 134 | => (1 (2 3)) 135 | 136 | (quasiquote (1 (splice-unquote lst))) 137 | => (1 2 3) 138 | ``` 139 | 140 | ### ` 、 ~ 和 ~@ 141 | 142 | grammatical sugar of quasiquote 、 unquote and splice-unquote ; 143 | 144 | ```lisp 145 | (def! lst '(2 3)) 146 | => (2 3) 147 | 148 | `(1 ~lst) 149 | => (1 (2 3)) 150 | 151 | `(1 ~@lst) 152 | => (1 2 3) 153 | ``` 154 | 155 | ### cons 156 | 157 | This function connects its first argument to its second argument (a list) and returns a new list. 158 | 159 | ```lisp 160 | (cons [1] [2 3]) 161 | => ([1] 2 3) 162 | 163 | (cons 1 [2 3]) 164 | => (1 2 3) 165 | ``` 166 | 167 | ### concat 168 | 169 | This function accepts zero or more lists as arguments and returns a new list consisting of all the arguments of those lists. 170 | 171 | ```lisp 172 | (concat [1 2] (list 3 4) [5 6]) 173 | => (1 2 3 4 5 6) 174 | 175 | (concat [1 2]) 176 | => (1 2) 177 | ``` 178 | 179 | ### defmacro! 和 macroexpand 180 | 181 | Macro definition and macro expansion 182 | 183 | Macro Definition Defines a symbol. Its return value will continue to be evaluated as AST. All of which can be used extensively with the previous syntactic sugars such as ' ` ~ ~ @ d etc. 184 | Macro expansion. Expands a macro to calculate only the last of its required values without evaluating it. 185 | 186 | ```lisp 187 | (defmacro! unless (lambda (pred a b) `(if ~pred ~b ~a))) 188 | 189 | => ...(Omitted here) 190 | 191 | (unless false 7 8) 192 | => 7 193 | 194 | (macroexpand (unless false 7 8)) 195 | => (if fasle 7 8) 196 | ``` 197 | 198 | ### nth 199 | 200 | This function takes a list (or vector) and a number (ordinal number) as arguments and returns the element of the list at the given ordinal position. If the ordinal number is exceeded, the function throws an exception. 201 | 202 | ```lisp 203 | (nth [1 2 3] 0) 204 | => 1 205 | 206 | (nth '(1 2 3) 1) 207 | => 2 208 | ``` 209 | 210 | ### first 211 | 212 | This function accepts a list (or vector) as an argument and returns its first element, or nil if the list (or vector) is empty, or if the argument itself is nil. 213 | 214 | ```lisp 215 | (first '((1 2) 2 3)) 216 | 217 | => (1 2) 218 | ``` 219 | 220 | ### count 221 | 222 | Accepts a list or vector and returns the length of the list or vector. 223 | 224 | ```lisp 225 | (count '(1 2 (2 3))) 226 | => 3 227 | 228 | (count [1 2 3]) 229 | => 3 230 | ``` 231 | 232 | ### empty? 233 | 234 | Accept a list or vector to determine if the object is empty. Returns true if I'm empty and false otherwise. 235 | 236 | ```lisp 237 | (empty? '()) 238 | => true 239 | 240 | (empty? nil) 241 | => true 242 | ``` 243 | 244 | ### try* catch* 和 throw 245 | 246 | The try-catch block is no different than try-catch in other languages. try is followed by a statement. If there are multiple statements that can be matched with a do statement, the catch 247 | statement, an exception is thrown, and the return of the code segment can be controlled. If throw is used an exception can be actively thrown. 248 | 249 | ```lisp 250 | (throw "err1") 251 | => err1 252 | 253 | (try* abc (catch* exc (prn "exc is:" exc))) 254 | => "exc is:" "not found 'abc'" 255 | 256 | (try* (throw "my exception") (catch* exc (do (prn "exc:" exc) 7))) 257 | => "exc:" "my exception" 258 | => 7 259 | ``` 260 | 261 | ### apply 262 | 263 | It has two arguments, the first argument is a function. The second argument is a list of the required parameters for the function. This function will return the result of this evaluation. 264 | 265 | ```lisp 266 | (apply + (list 1 3)) 267 | => 4 268 | 269 | (apply + '(2 3)) 270 | => 5 271 | 272 | (apply (lambda [x y] (do (prn x "+" y) (+ x y))) '(7 8)) 273 | => 7 "+" 8 274 | => 15 275 | ``` 276 | 277 | ### map 278 | 279 | It has two arguments, the first argument is a function and the second is a vector or a list. It then evaluates each value in the second argument, and the result returns a new list. 280 | Note that map accepts only one argument per function. However, it is possible to pass multiple values with apply. 281 | 282 | ```lisp 283 | 284 | (map (lambda [x] (apply + x)) (list [1 2] [2 3])) 285 | => (3 5) 286 | 287 | ``` 288 | 289 | ### A few simple type determination functions 290 | 291 | - nil? 292 | - true? 293 | - false? 294 | - symbol? (Determine if it's a symbol.) 295 | 296 | ### Atomic manipulation by Atom 297 | 298 | - atom: Enter a value of mal, and return a new atom pointing to it. 299 | - atom?: Determines whether the argument is an atom or not, and returns true if it is. 300 | - deref: Enter an atom as an argument, and return the value referenced by the atom. 301 | - reset!: Enter an atom and a mal value, modify the atom to point to the mal value, and return the mal value. 302 | - swap!: Enter an atom, a function, and zero or more function arguments. Take the value of the atom as the first argument, and transfer the remaining function arguments to the function as optional arguments, setting the value of the atom as the result of the function's evaluation. Return the new value of the atom. (Side note: Mal is single-threaded, but in a concurrent language like Clojure, swap! will be an atomic operation, and (swap! myatom (fn\* [x] (+ 1 x)) will always increase the myatom count by 1, and will not cause an error in the result when the atom is manipulated by multiple threads) 303 | 304 | ```lisp 305 | (def! *test-atom* (atom 0)) 306 | => (atom 0) 307 | 308 | (reset! *test-atom* 10) 309 | => 10 310 | 311 | (deref *test-atom*) | @*test-atom* 312 | => 10 313 | 314 | (swap! *test-atom* (lambda [x] (+ x 1))) 315 | => 11 316 | ``` 317 | 318 | @ is grammatical sugar of deref 319 | 320 | ### Hash-Map Operations and keywords 321 | 322 | In this dialect hashmap is a basic type. Use {} curly brackets to represent literal quantities. Where key can be used in two ways. Strings and keywords. The keyword is a string using: beginning. 323 | {"a" 1 "b" 2} 324 | {:a 1 :b 2} 325 | Both of the above forms can be used to represent a map. 326 | 327 | - hash-map: accepts an even number of arguments and returns a new mal hash table, where the keys are the arguments at odd positions and their values are the arguments at even positions, which is essentially a function of the {}reader literal syntax. 328 | - map?: accepts an argument, returns true if it is a hash, or false if it is a mal. 329 | - assoc: accepts a hash table as the first argument, and the remaining arguments are the odd/even-key/value pairs that need to be associated (merged) into the hash table. Note that the original hash table will not be modified (remember, the value of mal is immutable) and the new hash table is returned as a result of merging the keys/values in the old hash table with the key/value pairs in the arguments. 330 | - dissoc: accepts a hash table as the first argument, with the remaining arguments being the keys that need to be removed from the hash table. As before, note that the original hash table is unchanged, except that the new hash table is returned with the key specified in the argument removed. Keys in the parameter list that did not exist in the original hash table are ignored. 331 | - get: accepts a hash table and a key, returns the value corresponding to the key in the hash table, or nil if the key does not exist in the hash table. 332 | - contains?: accepts a hash table and a key, returns true if the hash table contains the key, otherwise returns false if the key is false. 333 | - keys: accepts a hash table and returns a list (the list value in mal) containing all the keys in the hash table. 334 | - vals: Accepts a hash table and returns a list (of values in mal) containing all the values in the hash table. 335 | 336 | Note that none of the above methods have side effects, i.e., they do not change the values of the principle. If you're going to do this it is recommended that you use atom or redef! 337 | 338 | ### gensym generates a new symbol for the system 339 | 340 | ```lisp 341 | (gensym) 342 | => It's different every run! 343 | ``` 344 | 345 | ### cond multiconditional 346 | 347 | There are an even number of arguments one for the condition and one for the returned value. 348 | 349 | ```lisp 350 | (def! ten-test (lambda [data] 351 | (cond 352 | (> data 10) 1 353 | (= data 10) 0 354 | (< data 10) -1))) 355 | 356 | (ten-test 15) 357 | => 1 358 | ``` 359 | 360 | # ls 361 | 362 | List the files and folders in the current directory 363 | 364 | ```lisp 365 | (ls) 366 | => (. .. mal) 367 | 368 | (ls "mal") 369 | => (. .. hello.mal) 370 | ``` 371 | 372 | # read-file 373 | 374 | Read file contents to a string 375 | 376 | ```lisp 377 | (read-file "mal/hello.mal") 378 | => "(+ 1 1)" 379 | ``` 380 | 381 | # load-file 382 | 383 | Read a file in mal format and load the statements inside. Return nil 384 | 385 | a.mal 386 | 387 | ```lisp 388 | (def! test (lambda [x] (prn x))) 389 | ``` 390 | 391 | ```lisp 392 | (load-file "a.mal") 393 | => nil 394 | (test "x") 395 | => "x" 396 | => nil 397 | ``` 398 | 399 | TODO others baisc function 400 | -------------------------------------------------------------------------------- /kernel/src/mal/core.rs: -------------------------------------------------------------------------------- 1 | // mal 语言核心库 2 | use crate::list; 3 | use crate::mal::env::Env; 4 | use crate::mal::env::{env_set, env_sets}; 5 | use crate::mal::printer::pr_seq; 6 | use crate::mal::reader::read_str; 7 | use crate::mal::rep; 8 | use crate::mal::types::MalErr::{ErrMalVal, ErrString}; 9 | use crate::mal::types::MalVal::{ 10 | Atom, Bool, Func, Hash, Int, List, MalFunc, Nil, Str, Sym, Vector, 11 | }; 12 | use crate::mal::types::{MalArgs, MalRet, MalVal, _assoc, _dissoc, atom, error, func, hash_map}; 13 | use crate::vec; 14 | use crate::vector; 15 | 16 | use crate::fs::{inode_ext::INodeExt, ROOT_INODE}; 17 | use alloc::rc::Rc; 18 | use alloc::string::{String, ToString}; 19 | use alloc::vec::Vec; 20 | use log::*; 21 | 22 | // 处理两个值入参 23 | macro_rules! fn_t_int_int { 24 | ($ret:ident, $fn:expr) => {{ 25 | |a: MalArgs| match (a[0].clone(), a[1].clone()) { 26 | (Int(a0), Int(a1)) => Ok($ret($fn(a0, a1))), 27 | _ => error("expecting (int,int) args"), 28 | } 29 | }}; 30 | } 31 | 32 | macro_rules! fn_str { 33 | ($fn:expr) => {{ 34 | |a: MalArgs| match a[0].clone() { 35 | Str(a0) => $fn(a0), 36 | _ => error("expecting (str) arg"), 37 | } 38 | }}; 39 | } 40 | 41 | macro_rules! fn_is_type { 42 | ($($ps:pat),*) => {{ 43 | |a:MalArgs| {Ok(Bool(match a[0] {$($ps => true,)* _=>false}))} 44 | }}; 45 | ($p:pat if $e:expr) => {{ 46 | |a:MalArgs| { Ok(Bool(match a[0] { $p if $e => true, _ => false})) } 47 | }}; 48 | ($p:pat if $e:expr,$($ps:pat),*) => {{ 49 | |a:MalArgs| { Ok(Bool(match a[0] { $p if $e => true, $($ps => true,)* _ => false})) } 50 | }}; 51 | } 52 | 53 | fn cons(a: MalArgs) -> MalRet { 54 | match a[1].clone() { 55 | List(v, _) | Vector(v, _) => { 56 | let mut new_v = vec![a[0].clone()]; 57 | new_v.extend_from_slice(&v); 58 | Ok(list!(new_v.to_vec())) 59 | } 60 | _ => error("cons expects seq as second arg"), 61 | } 62 | } 63 | 64 | fn concat(a: MalArgs) -> MalRet { 65 | let mut new_v = vec![]; 66 | for seq in a.iter() { 67 | match seq { 68 | List(v, _) | Vector(v, _) => new_v.extend_from_slice(v), 69 | _ => return error("non-seq passed to concat"), 70 | } 71 | } 72 | Ok(list!(new_v.to_vec())) 73 | } 74 | 75 | fn nth(a: MalArgs) -> MalRet { 76 | match (a[0].clone(), a[1].clone()) { 77 | (List(seq, _), Int(idx)) | (Vector(seq, _), Int(idx)) => { 78 | if seq.len() <= idx as usize { 79 | return error("nth:index out of range"); 80 | } 81 | Ok(seq[idx as usize].clone()) 82 | } 83 | _ => error("invalid args to nth"), 84 | } 85 | } 86 | 87 | fn first(a: MalArgs) -> MalRet { 88 | match a[0].clone() { 89 | List(ref seq, _) | Vector(ref seq, _) if seq.len() == 0 => Ok(Nil), 90 | List(ref seq, _) | Vector(ref seq, _) => Ok(seq[0].clone()), 91 | Nil => Ok(Nil), 92 | _ => error("invalid args to first"), 93 | } 94 | } 95 | 96 | fn rest(a: MalArgs) -> MalRet { 97 | match a[0].clone() { 98 | List(ref seq, _) | Vector(ref seq, _) => { 99 | if seq.len() > 1 { 100 | Ok(list![seq[1..].to_vec()]) 101 | } else { 102 | Ok(list![]) 103 | } 104 | } 105 | Nil => Ok(list![]), 106 | _ => error("invalid args to list"), 107 | } 108 | } 109 | 110 | fn apply(a: MalArgs) -> MalRet { 111 | match a[a.len() - 1] { 112 | List(ref v, _) | Vector(ref v, _) => { 113 | let f = &a[0]; 114 | let mut fargs = a[1..a.len() - 1].to_vec(); 115 | // Q: 这个的extend_from_slice的方法的文档 116 | fargs.extend_from_slice(&v); 117 | f.apply(fargs) 118 | } 119 | _ => error("apply called with no-seq"), 120 | } 121 | } 122 | 123 | // 生成一个符号 124 | fn symbol(a: MalArgs) -> MalRet { 125 | match a[0] { 126 | Str(ref s) => Ok(Sym(s.to_string())), 127 | _ => error("illegal symbol call"), 128 | } 129 | } 130 | 131 | fn map(a: MalArgs) -> MalRet { 132 | match a[1] { 133 | List(ref v, _) | Vector(ref v, _) => { 134 | let mut res = vec![]; 135 | for mv in v.iter() { 136 | res.push(a[0].apply(vec![mv.clone()])?); 137 | } 138 | Ok(list!(res)) 139 | } 140 | _ => error("map called with no-seq"), 141 | } 142 | } 143 | 144 | // 向hash map 中添加新的 key-value不改变原理的值 返回新的hashmap 145 | fn assoc(a: MalArgs) -> MalRet { 146 | match a[0] { 147 | Hash(ref hm, _) => _assoc((**hm).clone(), a[1..].to_vec()), 148 | _ => error("assoc on non-Hash Map"), 149 | } 150 | } 151 | 152 | fn dissoc(a: MalArgs) -> MalRet { 153 | match a[0] { 154 | Hash(ref hm, _) => _dissoc((**hm).clone(), a[1..].to_vec()), 155 | _ => error("dissoc on non-Hash Map"), 156 | } 157 | } 158 | 159 | // 通过关键字获取 vlaue的值 160 | fn get(a: MalArgs) -> MalRet { 161 | match (a[0].clone(), a[1].clone()) { 162 | (Nil, _) => Ok(Nil), 163 | (Hash(ref hm, _), Str(ref s)) => match hm.get(s) { 164 | Some(mv) => Ok(mv.clone()), 165 | None => Ok(Nil), 166 | }, 167 | _ => error("illegal get args"), 168 | } 169 | } 170 | 171 | // hash map 是否包含某个key 172 | fn contains_q(a: MalArgs) -> MalRet { 173 | match (a[0].clone(), a[1].clone()) { 174 | (Hash(ref hm, _), Str(ref s)) => Ok(Bool(hm.contains_key(s))), 175 | _ => error("illefal contains args"), 176 | } 177 | } 178 | 179 | fn keys(a: MalArgs) -> MalRet { 180 | match a[0] { 181 | Hash(ref hm, _) => Ok(list!(hm.keys().map(|k| { Str(k.to_string()) }).collect())), 182 | _ => error("keys requires Hash Map"), 183 | } 184 | } 185 | 186 | fn vals(a: MalArgs) -> MalRet { 187 | match a[0] { 188 | Hash(ref hm, _) => Ok(list!(hm.values().map(|v| { v.clone() }).collect())), 189 | _ => error("vals requires Hash Map"), 190 | } 191 | } 192 | 193 | fn read_file(a: MalArgs) -> MalRet { 194 | match &a[0] { 195 | Str(path) => { 196 | let rs = ROOT_INODE 197 | .lookup(path.clone().as_str()) 198 | .unwrap() 199 | .read_as_string() 200 | .unwrap(); 201 | Ok(Str(rs)) 202 | } 203 | _ => error("read_file requires path String"), 204 | } 205 | } 206 | 207 | fn ls_dir(a: MalArgs) -> MalRet { 208 | if a.len() > 0 { 209 | match &a[0] { 210 | Str(name) => { 211 | // FIXME 处理这段函数 212 | let list = ROOT_INODE.lookup(name).unwrap().ls_as_vec().unwrap(); 213 | let rs: Vec = list.iter().map(|v| Str(v.to_string()) as MalVal).collect(); 214 | Ok(list!(rs.to_vec())) 215 | } 216 | _ => error("ls requires a path string!"), 217 | } 218 | } else { 219 | let tmp = ROOT_INODE.ls_as_vec().unwrap(); 220 | let tmp_rs: Vec = tmp.iter().map(|v| Str(v.to_string()) as MalVal).collect(); 221 | Ok(list!(tmp_rs.to_vec())) 222 | } 223 | } 224 | 225 | pub fn ns() -> Vec<(&'static str, MalVal)> { 226 | vec![ 227 | ("=", func(|a| Ok(Bool(a[0] == a[1])))), 228 | ("read-string", func(fn_str!(|s| { read_str(s) }))), 229 | ("list", func(|a| Ok(list!(a)))), 230 | ("<", func(fn_t_int_int!(Bool, |i, j| { i < j }))), 231 | ("<=", func(fn_t_int_int!(Bool, |i, j| { i <= j }))), 232 | (">", func(fn_t_int_int!(Bool, |i, j| { i > j }))), 233 | (">=", func(fn_t_int_int!(Bool, |i, j| { i >= j }))), 234 | ("+", func(fn_t_int_int!(Int, |i, j| { i + j }))), 235 | ("-", func(fn_t_int_int!(Int, |i, j| { i - j }))), 236 | ("*", func(fn_t_int_int!(Int, |i, j| { i * j }))), 237 | ("/", func(fn_t_int_int!(Int, |i, j| { i / j }))), 238 | ( 239 | "prn", 240 | func(|a| { 241 | print!(93; "{}",pr_seq(&a, true, "", "", "")); 242 | Ok(Nil) 243 | }), 244 | ), 245 | ("cons", func(cons)), 246 | ("concat", func(concat)), 247 | ("nth", func(nth)), 248 | ("first", func(first)), 249 | ("rest", func(rest)), 250 | ("count", func(|x| x[0].count())), // 获取列表 或者向量的长度 251 | ("empty?", func(|a| a[0].empty_q())), // 判断一个符号是否为空 252 | ("throw", func(|a| Err(ErrMalVal(a[0].clone())))), // 主动的抛出异常 253 | ("apply", func(apply)), 254 | ("map", func(map)), 255 | ("nil?", func(fn_is_type!(Nil))), 256 | ("ture?", func(fn_is_type!(Bool(true)))), 257 | ("false?", func(fn_is_type!(Bool(false)))), 258 | ("symbol?", func(fn_is_type!(Sym(_)))), 259 | // 原子操作 260 | ("atom", func(|a| Ok(atom(&a[0])))), 261 | ("atom?", func(fn_is_type!(Atom(_)))), 262 | ("reset!", func(|a| a[0].reset_bang(&a[1]))), 263 | ("deref", func(|a| a[0].deref())), 264 | ("swap!", func(|a| a[0].swap_bang(&a[1..].to_vec()))), 265 | // 生成一个符号 266 | ("symbol", func(symbol)), 267 | // 生成一个关键字 一个关键字是一个:开头的字符串! 268 | ("keyword", func(|a| a[0].keyword())), 269 | ( 270 | "keyword?", 271 | func(fn_is_type!(Str(ref s) if s.starts_with("\u{29e}"))), 272 | ), 273 | // 判断是否是整形数字 274 | ("number?", func(fn_is_type!(Int(_)))), 275 | ( 276 | "lambda?", 277 | func(fn_is_type!(MalFunc{is_macro,..} if !is_macro,Func(_,_))), 278 | ), 279 | ( 280 | "macro?", 281 | func(fn_is_type!(MalFunc{is_macro,..} if is_macro)), 282 | ), 283 | // 生成字符串并且打印 284 | ("pr-str", func(|a| Ok(Str(pr_seq(&a, true, "", "", " "))))), 285 | // 生成字符串不进行打印 286 | ("str", func(|a| Ok(Str(pr_seq(&a, false, "", "", ""))))), 287 | // 判断一个符号是否是 列表 或者 向量 288 | ("sequential?", func(fn_is_type!(List(_, _), Vector(_, _)))), 289 | ("list", func(|a| Ok(list!(a)))), 290 | ("list?", func(fn_is_type!(List(_, _)))), 291 | ("vector", func(|a| Ok(vector!(a)))), 292 | ("vector?", func(fn_is_type!(Vector(_, _)))), 293 | // 哈希表支持的方法 294 | ("hash-map", func(|a| hash_map(a))), 295 | ("map?", func(fn_is_type!(Hash(_, _)))), 296 | ("assoc", func(assoc)), 297 | ("dissoc", func(dissoc)), 298 | ("get", func(get)), 299 | ("contains?", func(contains_q)), 300 | ("keys", func(keys)), 301 | ("vals", func(vals)), 302 | // 添加文件操作 303 | ("read-file", func(read_file)), 304 | ("ls", func(ls_dir)), 305 | ] 306 | } 307 | 308 | fn mal() -> Vec<&'static str> { 309 | vec![ 310 | "(prn \"load core lisp Lib!\")", 311 | "(def! *gensym-counter* (atom 0))", 312 | "(def! gensym (lambda [] (symbol (str \"G__\"(swap! *gensym-counter* (lambda [x] (+ 1 x)))))))", 313 | "(defmacro! or (v (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) (let* (condvar (gensym)) `(let* (~condvar ~(first xs)) (if ~condvar ~condvar (or ~@(rest xs)))))))))", 314 | "(def! not (lambda (a) (if a false true)))", 315 | "(defmacro! cond (lambda (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))", 316 | "(def! load-file (lambda (f) (eval (read-string (str \"(do \" (read-file f) \"nil)\" )))))", 317 | // 初始化时添加进入系统入口 318 | "(load-file \"entry.jmal\")", 319 | ] 320 | } 321 | 322 | // 加载核心函数 使用rust进行定义 323 | pub fn load_core(env: &Env) { 324 | for (k, v) in ns() { 325 | env_sets(&env, k, v); 326 | } 327 | load_core_lib(&env); 328 | } 329 | 330 | // 加载mal核心函数库 331 | // 这个库的目的是使用mal 语言自己实现扩展 332 | fn load_core_lib(env: &Env) { 333 | for s in mal() { 334 | let _ = rep(s, &env); 335 | } 336 | } 337 | -------------------------------------------------------------------------------- /kernel/src/mal/reader.rs: -------------------------------------------------------------------------------- 1 | use crate::format; 2 | use crate::list; 3 | use crate::mal::reader::State::{Comment, Others, Start, StateStr, StateSym}; 4 | use crate::mal::types::error; 5 | use crate::mal::types::hash_map; 6 | use crate::mal::types::MalErr; 7 | use crate::mal::types::MalErr::ErrString; 8 | use crate::mal::types::MalRet; 9 | use crate::mal::types::MalVal; 10 | use crate::mal::types::MalVal::{Bool, Int, List, Nil, Str, Sym, Vector}; 11 | use crate::vec; 12 | use crate::vector; 13 | use alloc::rc::Rc; 14 | use alloc::string::{String, ToString}; 15 | use alloc::vec::Vec; 16 | use hashbrown::HashMap; 17 | 18 | #[derive(Debug, Clone)] 19 | struct Reader { 20 | tokens: Vec, 21 | pos: usize, 22 | } 23 | 24 | impl Reader { 25 | // 阅读下一项 26 | fn next(&mut self) -> Result { 27 | self.pos = self.pos + 1; 28 | Ok(self 29 | .tokens 30 | .get(self.pos - 1) 31 | .ok_or(ErrString(String::from("underflow")))? 32 | .to_string()) 33 | } 34 | // 看一眼下一项 35 | fn peek(&self) -> Result { 36 | Ok(self 37 | .tokens 38 | .get(self.pos) 39 | .ok_or(ErrString(String::from("underflow")))? 40 | .to_string()) 41 | } 42 | } 43 | 44 | // token 识别状态 45 | #[derive(Debug, Clone)] 46 | enum State { 47 | Start, // 开始状态 48 | StateSym(String), // 特殊符号 49 | Comment(String), //注释 50 | Others(String), 51 | StateStr(String), //进入到字符串 52 | } 53 | 54 | // token化 55 | fn tokenize(str: &str) -> Vec { 56 | let mut res = Vec::new(); 57 | let mut code = String::from(str).chars().rev().collect::(); 58 | let mut state: State = Start; 59 | loop { 60 | let pre_state = state.clone(); 61 | match code.pop() { 62 | Some(t) => { 63 | match t { 64 | '`' | '\'' | '~' | '^' | '@' | '[' | ']' | '(' | ')' | '{' | '}' => { 65 | match pre_state { 66 | Start => { 67 | state = StateSym(t.to_string()); 68 | } 69 | StateSym(s) => { 70 | if s == "~" && t == '@' { 71 | res.push(String::from("~@")); 72 | state = Start; 73 | } else { 74 | res.push(s); 75 | res.push(t.to_string()); 76 | state = Start; 77 | } 78 | } 79 | Comment(s) => { 80 | let mut tmp = s.clone(); 81 | tmp.push(t); 82 | state = Comment(tmp); 83 | } 84 | Others(s) => { 85 | res.push(s); 86 | state = StateSym(t.to_string()); 87 | } 88 | StateStr(s) => { 89 | let mut tmp = s.clone(); 90 | tmp.push(t); 91 | state = StateStr(tmp); 92 | } 93 | } 94 | } 95 | ' ' => { 96 | match pre_state { 97 | Start => { 98 | // do nothing 99 | } 100 | StateSym(s) => { 101 | res.push(s); 102 | state = Start; 103 | } 104 | Comment(s) => { 105 | let mut tmp = s.clone(); 106 | tmp.push(t); 107 | state = Comment(tmp); 108 | } 109 | Others(s) => { 110 | res.push(s); 111 | state = Start; 112 | } 113 | StateStr(s) => { 114 | let mut tmp = s.clone(); 115 | tmp.push(t); 116 | state = StateStr(tmp); 117 | } 118 | } 119 | } 120 | '\n' => { 121 | match pre_state { 122 | Start => { 123 | // do nothing 124 | } 125 | StateSym(s) => { 126 | res.push(s); 127 | state = Start; 128 | } 129 | Comment(s) => { 130 | // 这里跳过 对注释的保存 131 | // res.push(s); 132 | state = Start; 133 | } 134 | Others(s) => { 135 | res.push(s); 136 | state = Start; 137 | } 138 | StateStr(s) => { 139 | let mut tmp = s.clone(); 140 | tmp.push(t); 141 | state = StateStr(tmp); 142 | } 143 | } 144 | } 145 | ';' => match pre_state { 146 | Start => { 147 | state = Comment(String::from(t.to_string())); 148 | } 149 | StateSym(s) => { 150 | res.push(s); 151 | state = Comment(String::from(t.to_string())); 152 | } 153 | Comment(s) => { 154 | let mut tmp = s.clone(); 155 | tmp.push(t); 156 | state = Comment(tmp); 157 | } 158 | Others(s) => { 159 | res.push(s); 160 | state = Comment(String::from(t.to_string())); 161 | } 162 | StateStr(s) => { 163 | let mut tmp = s.clone(); 164 | tmp.push(t); 165 | state = StateStr(tmp); 166 | } 167 | }, 168 | '\"' => match pre_state { 169 | Start => { 170 | state = StateStr(t.to_string()); 171 | } 172 | StateSym(s) => { 173 | res.push(s); 174 | state = StateStr(t.to_string()); 175 | } 176 | Comment(s) => { 177 | let mut tmp = s.clone(); 178 | tmp.push(t); 179 | state = Comment(tmp); 180 | } 181 | Others(s) => { 182 | let mut tmp = s.clone(); 183 | tmp.push(t); 184 | state = Others(tmp); 185 | } 186 | StateStr(s) => { 187 | let mut tmp = s.clone(); 188 | tmp.push(t); 189 | if s.ends_with("\\") { 190 | state = StateStr(tmp); 191 | } else { 192 | res.push(tmp); 193 | state = Start; 194 | } 195 | } 196 | }, 197 | _ => { 198 | // trace!("Run in Other: {}", t); 199 | match pre_state { 200 | Start => { 201 | state = Others(t.to_string()); 202 | } 203 | StateSym(s) => { 204 | res.push(s); 205 | state = Others(t.to_string()); 206 | } 207 | Comment(s) => { 208 | let mut tmp = s.clone(); 209 | tmp.push(t); 210 | state = Comment(tmp); 211 | } 212 | Others(s) => { 213 | let mut tmp = s.clone(); 214 | tmp.push(t); 215 | state = Others(tmp); 216 | } 217 | StateStr(s) => { 218 | let mut tmp = s.clone(); 219 | tmp.push(t); 220 | state = StateStr(tmp); 221 | } 222 | } 223 | } 224 | } 225 | } 226 | None => { 227 | break; 228 | } 229 | } 230 | } 231 | // 应该把当前状态没有识别结束的值 保存到vec中 232 | match state { 233 | Start => {} 234 | StateSym(s) => { 235 | res.push(s); 236 | } 237 | Comment(s) => { 238 | // res.push(s); 239 | } 240 | Others(s) => { 241 | res.push(s); 242 | } 243 | StateStr(mut s) => { 244 | if !s.ends_with("\"") { 245 | s.push('\"'); 246 | } 247 | res.push(s); 248 | } 249 | } 250 | res 251 | } 252 | 253 | // 判断一个字符串都是数字 254 | fn is_numbers(s: &String) -> bool { 255 | for r in s.chars() { 256 | if !r.is_ascii_digit() { 257 | return false; 258 | } 259 | } 260 | true 261 | } 262 | 263 | fn read_atom(rdr: &mut Reader) -> MalRet { 264 | let token = rdr.next()?; 265 | match &token[..] { 266 | "nil" => Ok(Nil), 267 | "false" => Ok(Bool(false)), 268 | "true" => Ok(Bool(true)), 269 | _ => { 270 | if is_numbers(&token) { 271 | Ok(Int(token.parse().unwrap())) 272 | // fixme 这里要失败字符串 再rust中使用的时候 必须加速这个\" 就很难受 273 | // TODO 而且上方也没有正常的识别出来 274 | } else if token.starts_with('\"') && token.ends_with('\"') { 275 | // fixme 这里要转义字符对转义字符进行判断 276 | Ok(Str(token[1..token.len() - 1].to_string())) 277 | } else if token.starts_with(":") { 278 | Ok(Str(format!("\u{29e}{}", &token[1..]))) 279 | // Ok(Str(String::from("\u{29e}")+&token[1..token.len()])) 280 | } else { 281 | Ok(Sym(token.to_string())) 282 | } 283 | } 284 | } 285 | } 286 | 287 | // 读符合 并且识别两个括号 288 | fn read_seq(rdr: &mut Reader, end: &str) -> MalRet { 289 | let mut seq: Vec = vec![]; 290 | rdr.next()?; 291 | loop { 292 | let token = match rdr.peek() { 293 | Ok(t) => t, 294 | Err(_) => return error(&format!("expected '{}', got EOF", end)), 295 | }; 296 | if token == end { 297 | break; 298 | } 299 | seq.push(read_form(rdr)?) 300 | } 301 | let _ = rdr.next(); 302 | match end { 303 | ")" => Ok(list!(seq)), 304 | "]" => Ok(vector!(seq)), 305 | "}" => hash_map(seq), 306 | _ => error("read_seq unknown end value"), 307 | } 308 | } 309 | 310 | fn read_form(rdr: &mut Reader) -> MalRet { 311 | let token = rdr.peek()?; 312 | match &token[..] { 313 | "'" => { 314 | let _ = rdr.next(); 315 | Ok(list![Sym("quote".to_string()), read_form(rdr)?]) 316 | } 317 | "`" => { 318 | let _ = rdr.next(); 319 | Ok(list![Sym("quasiquote".to_string()), read_form(rdr)?]) 320 | } 321 | "~" => { 322 | let _ = rdr.next(); 323 | Ok(list![Sym("unquote".to_string()), read_form(rdr)?]) 324 | } 325 | "~@" => { 326 | let _ = rdr.next(); 327 | Ok(list![Sym("splice-unquote".to_string()), read_form(rdr)?]) 328 | } 329 | "^" => { 330 | let _ = rdr.next(); 331 | let meta = read_form(rdr)?; 332 | Ok(list![Sym("with-meta".to_string()), read_form(rdr)?, meta]) 333 | } 334 | "@" => { 335 | let _ = rdr.next(); 336 | Ok(list![Sym("deref".to_string()), read_form(rdr)?]) 337 | } 338 | ")" => error("unexpected ')'"), 339 | "(" => read_seq(rdr, ")"), 340 | "]" => error("unexpected ']'"), 341 | "[" => read_seq(rdr, "]"), 342 | "}" => error("unexpected '}'"), 343 | "{" => read_seq(rdr, "}"), 344 | _ => read_atom(rdr), 345 | } 346 | } 347 | 348 | pub fn read_str(str: String) -> MalRet { 349 | let tokens = tokenize(&str); 350 | // println!("tokens: {:?}", tokens); 351 | if tokens.len() == 0 { 352 | return error("no input"); 353 | } 354 | read_form(&mut Reader { 355 | pos: 0, 356 | tokens: tokens, 357 | }) 358 | } 359 | -------------------------------------------------------------------------------- /kernel/src/mal/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::alloc::string::{String,ToString}; 2 | use crate::mal::reader::read_str; 3 | use hashbrown::HashMap; 4 | use alloc::rc::Rc; 5 | use alloc::vec::Vec; 6 | 7 | 8 | pub mod types; 9 | pub mod reader; 10 | pub mod env; 11 | pub mod printer; 12 | pub mod core; 13 | 14 | use crate::mal::types::MalVal::{List,Sym,Str,Vector,Hash,Nil,Int,MalFunc,Bool,Func}; 15 | use crate::mal::types::{error,MalRet,MalArgs,MalVal,MalErr}; 16 | use crate::mal::types::MalErr::{ErrMalVal,ErrString}; 17 | use crate::mal::env::Env; 18 | use crate::mal::env::{env_get,env_set,env_new,env_bind,env_find}; 19 | use crate::vec; 20 | use crate::vector; 21 | use crate::list; 22 | 23 | // 输入-求值-打印 不循环 24 | pub fn rep(str: &str, env: &Env) -> Result { 25 | let ast = read_str(str.to_string())?; 26 | let exp = eval(ast, env.clone())?; 27 | Ok(exp.pr_str(true)) 28 | } 29 | 30 | // 对符号列表支持临时求值的 (quote 的升级版) 31 | fn quasiquote(ast: &MalVal) -> MalVal { 32 | match ast { 33 | List(ref v,_) | Vector(ref v, _) if v.len() > 0 => { 34 | let a0 = &v[0]; 35 | match a0 { 36 | Sym(ref s) if s == "unquote" => v[1].clone(), 37 | _ => match a0 { 38 | List(ref v0,_) | Vector(ref v0,_) if v0.len() > 0 => match v0[0] { 39 | Sym(ref s) if s == "splice-unquote" => list![ 40 | Sym("concat".to_string()), 41 | v0[1].clone(), 42 | quasiquote(&list!(v[1..].to_vec())) 43 | ], 44 | _ => list![ 45 | Sym("cons".to_string()), 46 | quasiquote(a0), 47 | quasiquote(&list!(v[1..].to_vec())) 48 | ], 49 | }, 50 | _ => list![ 51 | Sym("cons".to_string()), 52 | quasiquote(a0), 53 | quasiquote(&list!(v[1..].to_vec())) 54 | ], 55 | }, 56 | } 57 | } 58 | _ => list![Sym("quote".to_string()),ast.clone()] 59 | } 60 | } 61 | 62 | //是否是宏调用 并且返回AST的入参 63 | fn is_macro_call(ast: &MalVal, env: &Env) -> Option<(MalVal, MalArgs)> { 64 | match ast { 65 | List(v, _) => match v[0] { 66 | Sym(ref s) => match env_find(env, s) { 67 | Some(e) => match env_get(&e, &v[0]) { 68 | Ok(f @ MalFunc { is_macro: true, .. }) => Some((f, v[1..].to_vec())), 69 | _ => None, 70 | }, 71 | _ => None, 72 | }, 73 | _ => None, 74 | }, 75 | _ => None, 76 | } 77 | } 78 | 79 | // 宏展开函数 80 | fn macroexpand(mut ast: MalVal, env: &Env) -> (bool, MalRet) { 81 | let mut was_expanded = false; 82 | while let Some((mf,args)) = is_macro_call(&ast, env) { 83 | ast = match mf.apply(args) { 84 | Err(e) => return (false, Err(e)), 85 | Ok(a) => a, 86 | }; 87 | was_expanded = true; 88 | } 89 | (was_expanded,Ok(ast)) 90 | } 91 | 92 | 93 | // 求值 94 | fn eval(mut ast: MalVal,mut env: Env) -> MalRet { 95 | let ret:MalRet; 96 | 'tco: loop { 97 | ret = match ast.clone(){ 98 | List(l,_)=>{ 99 | if l.len() == 0 { 100 | return Ok(ast); 101 | } 102 | // 展开尝试并且求值 103 | match macroexpand(ast.clone(), &env) { 104 | (true,Ok(new_ast)) => { 105 | ast = new_ast; 106 | continue 'tco; 107 | } 108 | (_,Err(e)) => return Err(e), 109 | _ => (), // 理论上不会到这个分支 110 | } 111 | let a0 = &l[0]; 112 | match a0 { 113 | Sym(ref a0sym) if a0sym == "def!" => { 114 | env_set(&env, l[1].clone(), eval(l[2].clone(), env.clone())?) 115 | }, 116 | Sym(ref a0sym) if a0sym == "let*" => { 117 | // 对let* 语法进行支持 118 | env = env_new(Some(env.clone())); 119 | let (a1,a2) = (l[1].clone(),l[2].clone()); 120 | match a1 { 121 | List(ref binds,_) | Vector(ref binds,_) => { 122 | let mut binds_iter = binds.iter(); 123 | 'letloop: loop { 124 | match binds_iter.next(){ 125 | Some(b) =>{ 126 | match binds_iter.next() { 127 | Some(e) => { 128 | let _ = env_set( 129 | &env, 130 | b.clone(), 131 | eval(e.clone(), env.clone())? 132 | ); 133 | }, 134 | None => { 135 | return error("let* with non-Sym binding"); 136 | } 137 | } 138 | }, 139 | None => { 140 | break 'letloop; 141 | }, 142 | } 143 | } 144 | }, 145 | _ => { 146 | return error("let* with non-List bindings"); 147 | }, 148 | } 149 | ast = a2; 150 | continue 'tco; 151 | } 152 | // 定义闭包函数的语法 153 | Sym(a0sym) if a0sym == "lambda" => { 154 | let (a1,a2) = (l[1].clone(),l[2].clone()); 155 | Ok(MalFunc { 156 | eval: eval, 157 | ast: Rc::new(a2), 158 | env: env, 159 | params: Rc::new(a1), 160 | is_macro: false, 161 | meta: Rc::new(Nil), 162 | }) 163 | }, 164 | Sym(ref a0sym) if a0sym == "if" => { 165 | let cond = eval(l[1].clone(), env.clone())?; 166 | match cond { 167 | Bool(false) | Nil if l.len() >= 4 => { 168 | ast = l[3].clone(); 169 | continue 'tco; 170 | }, 171 | Bool(false) | Nil => Ok(Nil), 172 | _ if l.len() >= 3 => { 173 | ast = l[2].clone(); 174 | continue 'tco; 175 | }, 176 | _ => Ok(Nil), 177 | } 178 | }, 179 | Sym(ref a0sym) if a0sym == "do" => { 180 | match eval_ast(&list!(l[1..].to_vec()),&env)?{ 181 | List(_,_) => { 182 | ast = l.last().unwrap_or(&Nil).clone(); 183 | continue 'tco; 184 | } 185 | _ => error("invalid do form"), 186 | } 187 | } 188 | Sym(ref a0sym) if a0sym == "quote" => Ok(l[1].clone()), 189 | Sym(ref a0sym) if a0sym == "quasiquote" => { 190 | ast = quasiquote(&l[1]); 191 | continue 'tco; 192 | }, 193 | Sym(ref a0sym) if a0sym == "eval" =>{ 194 | ast = eval(l[1].clone(), env.clone())?; 195 | while let Some(ref e) = env.clone().outer { 196 | env = e.clone(); 197 | } 198 | continue 'tco; 199 | }, 200 | // todo 这里实现其他的符号逻辑 201 | Sym(ref a0sym) if a0sym == "try*" => match eval(l[1].clone(), env.clone()) { 202 | Err(ref e) if l.len() >= 3 => { 203 | let exc = match e { 204 | ErrMalVal(mv) => mv.clone(), 205 | ErrString(s) => Str(s.to_string()), 206 | }; 207 | match l[2].clone() { 208 | List(c,_) => { 209 | let catch_env = env_bind( 210 | Some(env.clone()), 211 | list![vec![c[1].clone()]], 212 | vec![exc], 213 | )?; 214 | eval(c[2].clone(), catch_env) 215 | }, 216 | _ => error("invalid catch b,lock"), 217 | } 218 | } 219 | res => res, 220 | }, 221 | // 进行宏定义 222 | Sym(ref a0sym) if a0sym == "defmacro!" => { 223 | let (a1,a2) = (l[1].clone(),l[2].clone()); 224 | let r = eval(a2, env.clone())?; 225 | match r { 226 | MalFunc { 227 | eval, 228 | ast, 229 | env, 230 | params, 231 | .. 232 | }=> Ok(env_set(&env, a1.clone(), MalFunc { 233 | eval:eval, 234 | ast:ast.clone(), 235 | env:env.clone(), 236 | params:params.clone(), 237 | is_macro:true, 238 | meta: Rc::new(Nil), 239 | // mate 的作用是什么? 240 | })?), 241 | _ => error("set_macro on non-function"), 242 | } 243 | }, 244 | // 进行宏展开 245 | Sym(ref a0sym) if a0sym == "macroexpand" => { 246 | match macroexpand(l[1].clone(), &env) { 247 | (_, Ok(new_ast)) => Ok(new_ast), 248 | (_, e) => return e, 249 | } 250 | }, 251 | _ => match eval_ast(&ast, &env)? { 252 | List(ref el, _) => { 253 | let ref f = el[0].clone(); 254 | let args = el[1..].to_vec(); 255 | match f { 256 | Func(_,_) => f.apply(args), 257 | MalFunc{ 258 | ast: mast, 259 | env: menv, 260 | params, 261 | .. 262 | } => { 263 | let a = &**mast; 264 | let p = &**params; 265 | env = env_bind(Some(menv.clone()), p.clone(), args)?; 266 | ast = a.clone(); 267 | continue 'tco; 268 | }, 269 | _ => error("attempt to call non-function"), 270 | } 271 | } 272 | _ => error("expected a list"), 273 | } 274 | } 275 | }, 276 | _ => eval_ast(&ast, &env), 277 | }; 278 | break 'tco; 279 | } 280 | ret 281 | } 282 | 283 | // 对下级的AST求值 284 | fn eval_ast(ast: &MalVal, env: &Env) -> MalRet { 285 | match ast { 286 | Sym(_) => Ok(env_get(&env, &ast)?), 287 | List(v,_) => { 288 | let mut lst:MalArgs = vec![]; 289 | for a in v.iter() { 290 | lst.push(eval(a.clone(),env.clone())?) 291 | } 292 | Ok(list!(lst)) 293 | }, 294 | Vector(v,_) => { 295 | let mut lst:MalArgs = vec![]; 296 | for a in v.iter() { 297 | lst.push(eval(a.clone(),env.clone())?) 298 | } 299 | Ok(vector!(lst)) 300 | }, 301 | Hash(hm,_) => { 302 | let mut new_hm:HashMap = HashMap::default(); 303 | for (k,v) in hm.iter() { 304 | new_hm.insert(k.to_string(), eval(v.clone(),env.clone())?); 305 | } 306 | Ok(Hash(Rc::new(new_hm),Rc::new(Nil))) 307 | }, 308 | _ => Ok(ast.clone()), 309 | } 310 | } 311 | 312 | // 这是个临时的方法其实已经不需要了 313 | // 把一个MalArgs 如此作用于一个rust的fn 314 | pub fn int_op(op: fn(i64, i64) -> i64, a: MalArgs) -> MalRet { 315 | match (a[0].clone(), a[1].clone()) { 316 | (Int(a0), Int(a1)) => Ok(Int(op(a0, a1))), 317 | _ => error("invalid int_op args"),//fixme 函数的运算至少要有两个值 但是应该支持多个值 不要着急 还没有实现宏 318 | } 319 | } --------------------------------------------------------------------------------