diff --git "a/source/_posts/2024\347\247\213\345\206\254\345\255\243\345\274\200\346\272\220\346\223\215\344\275\234\347\263\273\347\273\237\350\256\255\347\273\203\350\220\245\347\254\254\344\270\211\351\230\266\346\256\265\346\200\273\347\273\223\346\212\245\345\221\212-hxingjie.md" "b/source/_posts/2024\347\247\213\345\206\254\345\255\243\345\274\200\346\272\220\346\223\215\344\275\234\347\263\273\347\273\237\350\256\255\347\273\203\350\220\245\347\254\254\344\270\211\351\230\266\346\256\265\346\200\273\347\273\223\346\212\245\345\221\212-hxingjie.md" new file mode 100644 index 0000000000..0f62c7f194 --- /dev/null +++ "b/source/_posts/2024\347\247\213\345\206\254\345\255\243\345\274\200\346\272\220\346\223\215\344\275\234\347\263\273\347\273\237\350\256\255\347\273\203\350\220\245\347\254\254\344\270\211\351\230\266\346\256\265\346\200\273\347\273\223\346\212\245\345\221\212-hxingjie.md" @@ -0,0 +1,308 @@ +--- +title: 2024秋冬季开源操作系统训练营第三阶段总结报告-hxingjie +date: 2024-11-30 23:22:06 +categories: + - summary report +tags: + - author:hxingjie + - repo:https://github.com/hxingjie/oscamp_0 +--- + + +## 一、前言 + +在过去三周,我学习了Unikernel, Monolithic Kernel, Hypervisor三种内核架构。经过学习,我对组件化操作系统有了初步的认识和掌握。以下是我对这三周学习过程的总结。 + + + +## 二、学习内容 + +### 1. Unikernel +在第一部分,学习了Unikernel的相关知识,完成了三个作业 + +1.1 实现带颜色的打印输出 + +(1) 修改 axstd 实现带颜色的打印输出 +在 ulib/axstd/src/lib.rs 中添加打印函数 + +```rust +fn println_with_color(msg: &str, color: &str), +``` + +使用match表达式匹配需要打印的颜色 + +```rust +let color = match color { + "black" => "\x1b[30m", + "red" => "\x1b[31m", + "green" => "\x1b[32m", + "yellow" => "\x1b[33m", + "blue" => "\x1b[34m", + _ => "\x1b[30m", +}; +``` + +实现带颜色的打印输出 + +```rust +println!("{}[WithColor]: {}\x1b[0m", color, msg); +``` +(2) 修改 axhal 实现带颜色的打印输出 +在 module/axhal/src/lib.rs 修改函数 fn write_bytes(bytes: &[u8]) + +在函数的首尾添加打印颜色符号的字符串即可 + +```rust +let beg = b"\x1b[34m"; +for c in beg { + putchar(*c); +} +//... +let end = b"\x1b[0m"; +for c in end { + putchar(*c); +} +``` + + +1.2 手写HashMap +使用拉链法实现哈希表, +(1) 设计数据结构: + +```rust +pub struct MyHashMap +where + K: ToString + PartialEq + Clone, + V: Clone, +{ + size: usize, // 键值对数量 + capacity: usize, // map中第一维的长度 + map: Vec>, // 邻接表 +} +``` +(2) 哈希函数: +```rust +fn hashcode(&self, string: &str) -> usize{ + let mut sum: usize = 0; + // a0*31^0 + a1*31^1 + ... + ai*31^i + for byte in string.as_bytes() { + sum = sum * 31 + *byte as usize; + } + sum % self.capacity +} +``` +(3) 插入函数: 根据key计算哈希值,根据哈希值插入对应的链表即可, + +实现细节: 先使用迭代器检查key是否存在于相应的链表中,如果已存在就更新键值,不存在就插入键值对;然后检查 self.size 是否大于 self.capacity as f64 * 0.75,大于的话就扩容到 self.capacity * 2 + +(4) 实现 iter 函数 + +```rust +pub fn (&self) -> MyHashMapIterator +``` + +MyHashMapIterator的实现 + +```rust +pub struct MyHashMapIterator<'a, K, V> { + current: usize, + len: usize, + data: Vec<(&'a K, &'a V)>, +} +``` + + + +1.3 EarlyAllocator +数据结构: + +```rust +struct MemUnit { + ptr_byte: usize, // 字节分配指针 + ptr_page: usize, // 页分配指针 + size: usize, +} + +pub struct EarlyAllocator { + total_bytes: usize, + used_bytes: usize, + + total_pages: usize, + used_pages: usize, + + mem: [MemUnit; 8192], + mem_sz: usize, +} +``` +只负责分配,需要分配地址时,首先遍历可用的内存数组,先对齐地址,再检查是否有足够的内存可供分配,有的话直接分配即可,然后更新对应的指针 + + + +1.4 shell 程序 + +(1) rename + +```rust +fn do_rename(args: &str) { + // 处理空格获取 old_name, new_name + // 检查是否新旧命名是否相同 + + // 辅助函数 + fn rename_one(old_name: &str, new_name: &str) -> io::Result<()> { + fs::rename(old_name, new_name)?; // 调用 fs 提供的接口即可 + Ok(()) + } + + if let Err(err) = rename_one(old_name, new_name) { + print_err!("rename", err); + } +} +``` + + + +(2) mv + +递归的思路,如果是文件就直接赋值,如果是文件夹就递归调用函数 + +```rust +// 辅助函数,调用 fs 中的 remove 接口 +fn my_rm(path: &str) -> io::Result<()> { + if fs::metadata(path)?.is_dir() { + fs::remove_dir(path) + } else { + fs::remove_file(path) + } +} +``` + +```rust +// 辅助函数,读取旧文件,创建新文件并写入 +fn my_mv_file(src_path: &str, file_path: &str, file_name: &str, tar_path: &str) -> io::Result<()> { + //... 路径相关 + let mut file = File::open(file_name).unwrap(); + file.read(&mut buf)?; // 读取旧文件 + my_rm(file_name)?; // 删除旧文件 + + // 创建新文件并写入 + let mut file = File::create(file_name).unwrap(); + file.write_all(&buf)?; + + //... 路径相关 +} +``` + +```rust +// 核心函数 +fn my_mv (old_path: &str, tar_path: &str) -> io::Result<()>{ + //... + if fs::metadata(old_path)?.is_dir() { // 如果是文件夹 + //... 路径相关 + // 读取文件夹的内容 + for entry in entries { // 遍历文件夹 + //... + if fs::metadata(path.as_str())?.is_dir() { // 递归调用该函数 + path.push('/'); + my_mv(path.as_str(), tar_path)?; + } else { // 直接移动文件 + my_mv_file(src_path, old_path, entry, tar_path)?; + } + } + + my_rm(old_path) // 移除旧文件夹 + } else { + //... 路径相关 + my_mv_file(src_path, file_path, file_name, tar_path) + } + } +``` + +```rust +// 接口函数 +fn do_mv(args: &str) { + //... + let (old_path, tar_path) = split_whitespace(args); + if let Err(err) = my_mv(old_path, tar_path) { + print_err!("mv", err); + } + +} +``` + + + +### 2. Monolithic Kernel + +2.1 lazy映射 +```rust +fn handle_page_fault(vaddr: VirtAddr, mut access_flags: MappingFlags, is_user: bool) -> bool { + ax_println!("handle_page_fault ..."); + // 调用相应的函数即可 + axtask::current().task_ext().aspace.lock().handle_page_fault(vaddr, access_flags) +} +``` + + + +2.2 sys_mmap +实现 sys_mmap + +```rust +fn sys_mmap(addr: *mut usize, length: usize, prot: i32, flags: i32, fd: i32, _offset: isize) -> isize +``` + +```rust +// 使用函数读取内容 +api::sys_read(fd, &mut buf as *mut[u8] as *mut c_void, length); + +// 找空余空间 +let vaddr = uspace.lock().find_free_area(start, length, VirtAddrRange::new(start, end)).unwrap(); + +// 映射, 写入 +uspace.lock().map_alloc(vaddr, 0x1000, MappingFlags::READ|MappingFlags::WRITE|MappingFlags::USER, true); +uspace.lock().write(vaddr, &buf[..]) +``` + + + +### 3. Hypervisor + +3.1 处理异常 +```rust +Trap::Exception(Exception::IllegalInstruction) => { + //"csrr a1, mhartid", + ax_println!("Bad instruction: {:#x} sepc: {:#x}", + stval::read(), + ctx.guest_regs.sepc + ); + ctx.guest_regs.gprs.set_reg(A1, 0x1234); + ctx.guest_regs.sepc += 4; +}, +Trap::Exception(Exception::LoadGuestPageFault) => { + //"ld a0, 64(zero)", + ax_println!("LoadGuestPageFault: stval{:#x} sepc: {:#x}", + stval::read(), + ctx.guest_regs.sepc + ); + ctx.guest_regs.gprs.set_reg(A0, 0x6688); + ctx.guest_regs.sepc += 4; +}, +``` + + + +3.2 加载外部文件 + +```rust +NestedPageFault{addr, access_flags} => { + // ... + let buffer = read("/sbin/pflash.img"); // 读取文件 + if let Ok(buf) = buffer { + let tmp = &buf[..4]; + aspace.map_alloc(addr, 4096, mapping_flags, true); // 映射 + aspace.write(addr, tmp); // 写入 + } else { + warn!("read fail"); + } +}, +``` diff --git "a/source/_posts/2024\347\247\213\345\206\254\345\255\243\345\274\200\346\272\220\346\223\215\344\275\234\347\263\273\347\273\237\350\256\255\347\273\203\350\220\245\347\254\254\345\233\233\351\230\266\346\256\265\346\200\273\347\273\223\346\212\245\345\221\212-hxingjie" "b/source/_posts/2024\347\247\213\345\206\254\345\255\243\345\274\200\346\272\220\346\223\215\344\275\234\347\263\273\347\273\237\350\256\255\347\273\203\350\220\245\347\254\254\345\233\233\351\230\266\346\256\265\346\200\273\347\273\223\346\212\245\345\221\212-hxingjie" new file mode 100644 index 0000000000..b64cc282d9 --- /dev/null +++ "b/source/_posts/2024\347\247\213\345\206\254\345\255\243\345\274\200\346\272\220\346\223\215\344\275\234\347\263\273\347\273\237\350\256\255\347\273\203\350\220\245\347\254\254\345\233\233\351\230\266\346\256\265\346\200\273\347\273\223\346\212\245\345\221\212-hxingjie" @@ -0,0 +1,23 @@ +--- +title: 2024秋冬季开源操作系统训练营第四阶段总结报告-hxingjie +date: 2024-12-21 14:55:06 +categories: + - summary report +tags: + - author:hxingjie + - repo:https://github.com/hxingjie/Starry-On-ArceOS +--- + + +## 一、前言 + +在过去三周,我参加了项目二宏内核扩展的实习项目,经过学习,我对基于ArceOS扩展的Starry操作系统有了初步的认识。。 + + +## 二、学习内容 +首先是将原系统的加载程序的方式改为从文件系统加载,之后的工作就是实现系统调用,通过尽可能多的测例,当前已实现的系统调用有:gettimeofday, getcwd, dup, duo3, chdir, mkdirat, openat, close, execve, uname, fstat,clone(只实现了复制当前进程) + + +## 三、总结 +刚准备开始学习rust语言的时候,偶然间在知乎看到了陈老师的帖子,了解到原来有一个这么优秀的训练营。经过四个阶段的学习,有了很大的收获。一阶段的rust学习让我了解到了这门优秀的系统编程语言,二阶段让我将考研时学习到的操作系统知识有了具象化的认识,三四阶段让我了解到组件化操作系统这一方向。越往后面学习,越认识到自己的rust编程能力还很薄弱,对系统的认识还很浅显,在之后的时间要系统性的学习rust语言,更深入地学习操作系统的知识,希望下一次的训练营能够做的更好。 +