├── os ├── lab2 │ ├── tools │ │ ├── gdbinit │ │ ├── fw_jump.bin │ │ ├── toolchain.mk │ │ └── linker.ld │ ├── init │ │ ├── entry.s │ │ ├── Makefile │ │ └── main.c │ ├── include │ │ ├── kdebug.h │ │ ├── clock.h │ │ ├── stdarg.h │ │ ├── string.h │ │ ├── stddef.h │ │ ├── uart.h │ │ ├── rtc.h │ │ ├── sbi.h │ │ ├── trap.h │ │ ├── plic.h │ │ └── dtb.h │ ├── lib │ │ ├── Makefile │ │ └── string.c │ └── trap │ │ ├── Makefile │ │ ├── clock.c │ │ ├── uart │ │ ├── uart.c │ │ └── uart_qemu.c │ │ ├── rtc │ │ └── rtc.c │ │ ├── trapentry.S │ │ └── plic.c ├── lab3 │ ├── tools │ │ ├── gdbinit │ │ ├── fw_jump.bin │ │ ├── toolchain.mk │ │ └── linker.ld │ ├── include │ │ ├── string.h │ │ ├── kdebug.h │ │ ├── clock.h │ │ ├── stdarg.h │ │ ├── stddef.h │ │ ├── plic.h │ │ ├── uart.h │ │ ├── mm.h │ │ ├── assert.h │ │ ├── sbi.h │ │ └── trap.h │ ├── init │ │ ├── entry.s │ │ ├── main.c │ │ └── Makefile │ ├── lib │ │ ├── string.c │ │ └── Makefile │ ├── .projections.json │ ├── trap │ │ ├── Makefile │ │ ├── clock.c │ │ ├── uart.c │ │ ├── plic.c │ │ └── trapentry.S │ ├── mm │ │ └── Makefile │ └── Makefile ├── lab1 │ ├── fw_jump.bin │ ├── gdbinit │ ├── entry.s │ ├── stddef.h │ ├── linker.ld │ ├── sbi.h │ ├── main.c │ └── Makefile ├── lab5 │ ├── lib │ │ ├── errno.c │ │ ├── Makefile │ │ └── string.c │ ├── tools │ │ ├── fw_jump.bin │ │ ├── gdbinit │ │ ├── toolchain.mk │ │ └── linker.ld │ ├── include │ │ ├── string.h │ │ ├── kdebug.h │ │ ├── clock.h │ │ ├── stdarg.h │ │ ├── syscall.h │ │ ├── stddef.h │ │ ├── plic.h │ │ ├── assert.h │ │ ├── uart.h │ │ ├── sbi.h │ │ ├── errno.h │ │ └── trap.h │ ├── init │ │ ├── Makefile │ │ ├── main.c │ │ └── entry.s │ ├── mm │ │ └── Makefile │ ├── kernel │ │ ├── Makefile │ │ ├── clock.c │ │ ├── uart.c │ │ ├── plic.c │ │ ├── syscall.c │ │ └── fork.c │ └── Makefile ├── lab6 │ ├── drivers │ │ ├── irq.c │ │ ├── loader.c │ │ ├── memory.c │ │ ├── Makefile │ │ ├── virtio.c │ │ ├── reset │ │ │ └── sifive_test.c │ │ ├── drivers_test.c │ │ ├── base.c │ │ └── virtio │ │ │ ├── virtio_queue.c │ │ │ └── virtio_mmio.c │ ├── lib │ │ ├── errno.c │ │ ├── Makefile │ │ ├── string.c │ │ ├── sleep.c │ │ └── stdio.c │ ├── tools │ │ ├── fw_jump.bin │ │ ├── gdbinit │ │ ├── toolchain.mk │ │ └── linker.ld │ ├── include │ │ ├── device │ │ │ ├── reset │ │ │ │ └── sifive_test.h │ │ │ ├── virtio.h │ │ │ ├── loader.h │ │ │ ├── reset.h │ │ │ ├── serial.h │ │ │ ├── block.h │ │ │ ├── serial │ │ │ │ └── uart8250.h │ │ │ ├── irq │ │ │ │ └── plic.h │ │ │ ├── virtio │ │ │ │ ├── virtio_net.h │ │ │ │ ├── virtio_blk.h │ │ │ │ └── virtio_mmio.h │ │ │ └── irq.h │ │ ├── kdebug.h │ │ ├── string.h │ │ ├── clock.h │ │ ├── fs │ │ │ ├── ramfs.h │ │ │ └── vfs.h │ │ ├── lib │ │ │ ├── sleep.h │ │ │ └── stdio.h │ │ ├── stdarg.h │ │ ├── syscall.h │ │ ├── stddef.h │ │ ├── assert.h │ │ ├── sbi.h │ │ ├── utils │ │ │ ├── lru.h │ │ │ ├── hash_table.h │ │ │ ├── atomic.h │ │ │ └── linked_list.h │ │ ├── errno.h │ │ └── trap.h │ ├── init │ │ ├── Makefile │ │ └── entry.s │ ├── fs │ │ └── Makefile │ ├── mm │ │ └── Makefile │ ├── kernel │ │ ├── Makefile │ │ ├── clock.c │ │ └── fork.c │ └── Makefile └── lab4 │ ├── tools │ ├── fw_jump.bin │ ├── gdbinit │ ├── toolchain.mk │ └── linker.ld │ ├── include │ ├── string.h │ ├── kdebug.h │ ├── clock.h │ ├── stdarg.h │ ├── stddef.h │ ├── plic.h │ ├── assert.h │ ├── uart.h │ ├── sbi.h │ └── trap.h │ ├── lib │ ├── string.c │ └── Makefile │ ├── init │ ├── main.c │ ├── Makefile │ └── entry.s │ ├── trap │ ├── Makefile │ ├── clock.c │ ├── uart.c │ ├── plic.c │ └── trapentry.S │ ├── mm │ └── Makefile │ └── Makefile ├── .devcontainer ├── Dockerfile.develop ├── devcontainer.json └── Dockerfile.environment ├── doc ├── lab_guidance │ ├── images │ │ ├── pte.png │ │ ├── satp.png │ │ ├── satp-mode.png │ │ ├── physical-address.png │ │ ├── virtual-address.png │ │ └── virtual-to-physical.png │ └── device-tree.md └── meeting_record │ ├── 20201122.md │ ├── 20201115.md │ └── 20201206.md ├── setup_mac.sh ├── README.md ├── .editorconfig ├── setup_openeuler.sh ├── setup.sh └── .gitignore /os/lab2/tools/gdbinit: -------------------------------------------------------------------------------- 1 | file kernel.bin 2 | target remote localhost:1234 3 | b _start 4 | -------------------------------------------------------------------------------- /os/lab3/tools/gdbinit: -------------------------------------------------------------------------------- 1 | file kernel.bin 2 | target remote localhost:1234 3 | b _start 4 | -------------------------------------------------------------------------------- /os/lab1/fw_jump.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RvOSLab/lzu_oslab/HEAD/os/lab1/fw_jump.bin -------------------------------------------------------------------------------- /os/lab5/lib/errno.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file errno.c 3 | * @brief 定义 errno 4 | */ 5 | int errno; 6 | -------------------------------------------------------------------------------- /os/lab6/drivers/irq.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct irq_device *g_irq_dev = NULL; 4 | -------------------------------------------------------------------------------- /os/lab6/lib/errno.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file errno.c 3 | * @brief 定义 errno 4 | */ 5 | int errno; 6 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile.develop: -------------------------------------------------------------------------------- 1 | FROM mapleee/lzuoslab:env 2 | WORKDIR /root/ 3 | CMD [ "bash" ] 4 | -------------------------------------------------------------------------------- /os/lab2/tools/fw_jump.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RvOSLab/lzu_oslab/HEAD/os/lab2/tools/fw_jump.bin -------------------------------------------------------------------------------- /os/lab3/tools/fw_jump.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RvOSLab/lzu_oslab/HEAD/os/lab3/tools/fw_jump.bin -------------------------------------------------------------------------------- /os/lab4/tools/fw_jump.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RvOSLab/lzu_oslab/HEAD/os/lab4/tools/fw_jump.bin -------------------------------------------------------------------------------- /os/lab5/tools/fw_jump.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RvOSLab/lzu_oslab/HEAD/os/lab5/tools/fw_jump.bin -------------------------------------------------------------------------------- /os/lab6/tools/fw_jump.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RvOSLab/lzu_oslab/HEAD/os/lab6/tools/fw_jump.bin -------------------------------------------------------------------------------- /os/lab1/gdbinit: -------------------------------------------------------------------------------- 1 | file kernel.bin 2 | target remote localhost:1234 3 | layout src 4 | b main 5 | focus cmd 6 | -------------------------------------------------------------------------------- /doc/lab_guidance/images/pte.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RvOSLab/lzu_oslab/HEAD/doc/lab_guidance/images/pte.png -------------------------------------------------------------------------------- /doc/lab_guidance/images/satp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RvOSLab/lzu_oslab/HEAD/doc/lab_guidance/images/satp.png -------------------------------------------------------------------------------- /os/lab4/tools/gdbinit: -------------------------------------------------------------------------------- 1 | file kernel.bin 2 | target remote localhost:1234 3 | layout src 4 | b main 5 | focus cmd 6 | -------------------------------------------------------------------------------- /os/lab5/tools/gdbinit: -------------------------------------------------------------------------------- 1 | file kernel.bin 2 | target remote localhost:1234 3 | layout src 4 | b main 5 | focus cmd 6 | -------------------------------------------------------------------------------- /os/lab6/tools/gdbinit: -------------------------------------------------------------------------------- 1 | file kernel.bin 2 | target remote localhost:1234 3 | layout src 4 | b main 5 | focus cmd 6 | -------------------------------------------------------------------------------- /doc/lab_guidance/images/satp-mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RvOSLab/lzu_oslab/HEAD/doc/lab_guidance/images/satp-mode.png -------------------------------------------------------------------------------- /doc/lab_guidance/images/physical-address.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RvOSLab/lzu_oslab/HEAD/doc/lab_guidance/images/physical-address.png -------------------------------------------------------------------------------- /doc/lab_guidance/images/virtual-address.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RvOSLab/lzu_oslab/HEAD/doc/lab_guidance/images/virtual-address.png -------------------------------------------------------------------------------- /doc/lab_guidance/images/virtual-to-physical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RvOSLab/lzu_oslab/HEAD/doc/lab_guidance/images/virtual-to-physical.png -------------------------------------------------------------------------------- /setup_mac.sh: -------------------------------------------------------------------------------- 1 | brew tap riscv/riscv 2 | brew install riscv-gnu-toolchain qemu tmux 3 | echo 'PATH=$PATH:/usr/local/opt/riscv-gnu-toolchain/bin' >> ~/.zprofile 4 | -------------------------------------------------------------------------------- /os/lab3/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef __STRING_H__ 2 | #define __STRING_H__ 3 | #include 4 | size_t strlen(const char *str); 5 | void *memset(void *src, char ch, size_t cnt); 6 | #endif 7 | -------------------------------------------------------------------------------- /os/lab4/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef __STRING_H__ 2 | #define __STRING_H__ 3 | #include 4 | size_t strlen(const char *str); 5 | void *memset(void *src, char ch, size_t cnt); 6 | #endif 7 | -------------------------------------------------------------------------------- /os/lab6/include/device/reset/sifive_test.h: -------------------------------------------------------------------------------- 1 | #ifndef SIFIVE_TEST 2 | #define SIFIVE_TEST 3 | 4 | #include 5 | 6 | #define SIFIVE_TEST_MAJOR 0x1234 7 | 8 | extern struct device_driver test_driver; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /os/lab1/entry.s: -------------------------------------------------------------------------------- 1 | .globl boot_stack, boot_stack_top, _start 2 | .section .text.entry 3 | _start: 4 | la sp, boot_stack_top 5 | call main 6 | 7 | .section .bss 8 | boot_stack: 9 | .space 4096 * 16 10 | boot_stack_top: 11 | -------------------------------------------------------------------------------- /os/lab5/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef __STRING_H__ 2 | #define __STRING_H__ 3 | #include 4 | size_t strlen(const char *str); 5 | void *memset(void *src, char ch, size_t cnt); 6 | void *memcpy(void *dest, const void *src, size_t n); 7 | #endif 8 | -------------------------------------------------------------------------------- /os/lab2/init/entry.s: -------------------------------------------------------------------------------- 1 | .globl boot_stack, boot_stack_top, _start 2 | .section .text.entry 3 | _start: 4 | la sp, boot_stack_top 5 | call main 6 | 7 | .section .bss 8 | boot_stack: 9 | .space 4096 * 16 10 | boot_stack_top: 11 | -------------------------------------------------------------------------------- /os/lab3/init/entry.s: -------------------------------------------------------------------------------- 1 | .globl boot_stack, boot_stack_top, _start 2 | .section .text.entry 3 | _start: 4 | la sp, boot_stack_top 5 | call main 6 | 7 | .section .bss 8 | boot_stack: 9 | .space 4096 * 16 10 | boot_stack_top: 11 | -------------------------------------------------------------------------------- /os/lab6/include/device/virtio.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICE_VIRTIO_H 2 | #define DEVICE_VIRTIO_H 3 | 4 | #include 5 | #include 6 | 7 | extern struct device_driver virtio_driver; 8 | 9 | #define VIRTIO_MAJOR 0x7485 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /os/lab2/include/kdebug.h: -------------------------------------------------------------------------------- 1 | #ifndef __KDEBUG_H__ 2 | #define __KDEBUG_H__ 3 | #include 4 | #include 5 | #include 6 | int kputs(const char *msg); 7 | int kprintf(const char *fmt, ...); 8 | void kputchar(char ch); 9 | #endif 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lzu_oslab 2 | A simple OS running on RISC-V for education 3 | 4 | 要想部署支持 RISC-V 的 QEMU,可以执行以下命令: 5 | 6 | ```shell 7 | sudo apt update 8 | sudo apt install git 9 | # 提前配置 ssh 的密钥方便上传 10 | git clone git@github.com:LZU-OSLab/lzu_oslab.git 11 | cd lzu_oslab 12 | ./setup.sh 13 | ``` 14 | -------------------------------------------------------------------------------- /os/lab6/include/device/loader.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICE_LOADER 2 | #define DEVICE_LOADER 3 | 4 | #include 5 | #include 6 | 7 | extern struct device_driver *driver_list[]; 8 | 9 | void fdt_loader(const struct fdt_header *fdt, struct device_driver *driver_list[]); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /os/lab3/include/kdebug.h: -------------------------------------------------------------------------------- 1 | #ifndef __KDEBUG_H__ 2 | #define __KDEBUG_H__ 3 | #include 4 | #include 5 | #include 6 | int kputs(const char *msg); 7 | int kprintf(const char *fmt, ...); 8 | void kputchar(char ch); 9 | void do_panic(const char* file, int line, const char* fmt, ...); 10 | #endif 11 | -------------------------------------------------------------------------------- /os/lab4/include/kdebug.h: -------------------------------------------------------------------------------- 1 | #ifndef __KDEBUG_H__ 2 | #define __KDEBUG_H__ 3 | #include 4 | #include 5 | #include 6 | int kputs(const char *msg); 7 | int kprintf(const char *fmt, ...); 8 | void kputchar(char ch); 9 | void do_panic(const char* file, int line, const char* fmt, ...); 10 | #endif 11 | -------------------------------------------------------------------------------- /os/lab5/include/kdebug.h: -------------------------------------------------------------------------------- 1 | #ifndef __KDEBUG_H__ 2 | #define __KDEBUG_H__ 3 | #include 4 | #include 5 | #include 6 | int kputs(const char *msg); 7 | int kprintf(const char *fmt, ...); 8 | void kputchar(char ch); 9 | void do_panic(const char* file, int line, const char* fmt, ...); 10 | #endif 11 | -------------------------------------------------------------------------------- /os/lab6/include/kdebug.h: -------------------------------------------------------------------------------- 1 | #ifndef __KDEBUG_H__ 2 | #define __KDEBUG_H__ 3 | #include 4 | #include 5 | #include 6 | int kputs(const char *msg); 7 | int kprintf(const char *fmt, ...); 8 | void kputchar(char ch); 9 | void do_panic(const char* file, int line, const char* fmt, ...); 10 | #endif 11 | -------------------------------------------------------------------------------- /os/lab6/include/device/reset.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICE_RESET_H 2 | #define DEVICE_RESET_H 3 | 4 | #include 5 | 6 | #define RESET_INTERFACE_BIT (1 << 12) 7 | 8 | struct reset_device { 9 | struct device *dev; 10 | void (*shutdown)(struct device *dev); 11 | void (*reboot)(struct device *dev); 12 | }; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /os/lab3/init/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | int main() 5 | { 6 | kputs("\nLZU OS STARTING...................."); 7 | print_system_infomation(); 8 | mem_init(); 9 | mem_test(); 10 | kputs("Hello LZU OS"); 11 | while (1) 12 | ; /* infinite loop */ 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /os/lab6/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef __STRING_H__ 2 | #define __STRING_H__ 3 | #include 4 | size_t strlen(const char *str); 5 | void *memset(void *src, char ch, size_t cnt); 6 | void *memcpy(void *dest, const void *src, size_t n); 7 | int64_t strcmp(const char *s, const char *t); 8 | const char *strchr(const char *str, char c); 9 | #endif 10 | -------------------------------------------------------------------------------- /os/lab3/lib/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | size_t strlen(const char *str) 4 | { 5 | size_t i = 0; 6 | for (; str[i] != '\0'; ++i) 7 | ; 8 | return i; 9 | } 10 | 11 | void *memset(void *src, char ch, size_t cnt) 12 | { 13 | for (size_t i = 0; i < cnt; ++i) 14 | *((char *)src + i) = ch; 15 | return src; 16 | } 17 | -------------------------------------------------------------------------------- /os/lab4/lib/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | size_t strlen(const char *str) 4 | { 5 | size_t i = 0; 6 | for (; str[i] != '\0'; ++i) 7 | ; 8 | return i; 9 | } 10 | 11 | void *memset(void *src, char ch, size_t cnt) 12 | { 13 | for (size_t i = 0; i < cnt; ++i) 14 | *((char *)src + i) = ch; 15 | return src; 16 | } 17 | -------------------------------------------------------------------------------- /os/lab2/include/clock.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file clock.h 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 本文件声明时钟中断相关的全局变量和函数 5 | */ 6 | #ifndef __CLOCK_H__ 7 | #define __CLOCK_H__ 8 | 9 | #include 10 | #include 11 | 12 | extern volatile size_t ticks; 13 | 14 | void clock_init(); 15 | void clock_set_next_event(); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /os/lab3/include/clock.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file clock.h 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 本文件声明时钟中断相关的全局变量和函数 5 | */ 6 | #ifndef __CLOCK_H__ 7 | #define __CLOCK_H__ 8 | 9 | #include 10 | #include 11 | 12 | extern volatile size_t ticks; 13 | 14 | void clock_init(); 15 | void clock_set_next_event(); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /os/lab4/include/clock.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file clock.h 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 本文件声明时钟中断相关的全局变量和函数 5 | */ 6 | #ifndef __CLOCK_H__ 7 | #define __CLOCK_H__ 8 | 9 | #include 10 | #include 11 | 12 | extern volatile size_t ticks; 13 | 14 | void clock_init(); 15 | void clock_set_next_event(); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /os/lab5/include/clock.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file clock.h 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 本文件声明时钟中断相关的全局变量和函数 5 | */ 6 | #ifndef __CLOCK_H__ 7 | #define __CLOCK_H__ 8 | 9 | #include 10 | #include 11 | 12 | extern volatile size_t ticks; 13 | 14 | void clock_init(); 15 | void clock_set_next_event(); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /os/lab6/include/clock.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file clock.h 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 本文件声明时钟中断相关的全局变量和函数 5 | */ 6 | #ifndef __CLOCK_H__ 7 | #define __CLOCK_H__ 8 | 9 | #include 10 | #include 11 | 12 | extern volatile size_t ticks; 13 | 14 | void clock_init(); 15 | void clock_set_next_event(); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /os/lab6/include/device/serial.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICE_SERIAL_H 2 | #define DEVICE_SERIAL_H 3 | 4 | #include 5 | #include 6 | 7 | #define SERIAL_INTERFACE_BIT (1 << 6) 8 | 9 | struct serial_device { 10 | struct device *dev; 11 | uint64_t (*request)(struct device *dev, void *buffer, uint64_t size, uint64_t is_read); 12 | }; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /os/lab4/init/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | int main() 5 | { 6 | kputs("\nLZU OS STARTING...................."); 7 | print_system_infomation(); 8 | mem_init(); 9 | mem_test(); 10 | malloc_test(); 11 | kputs("Hello LZU OS"); 12 | 13 | while (1) 14 | ; /* infinite loop */ 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /os/lab2/init/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I ../include 3 | 4 | vpath %.h ../include 5 | vpath $.a ../lib 6 | 7 | .PHONY : clean build 8 | 9 | build : lib.a init.o 10 | 11 | init.o : entry.s main.c 12 | 13 | clean : 14 | -find . -regex '.*\.o' -exec rm {} \; 15 | -------------------------------------------------------------------------------- /os/lab2/include/stdarg.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file stdarg.h 3 | * 本文件实现可变参数 4 | * 5 | * @note 可变参数需要编译器的支持,不可能由程序员独立实现。 6 | * 因此我们只是简单的包装编译器提供的内建函数、类型。 7 | */ 8 | #ifndef __STDARG_H__ 9 | #define __STDARG_H__ 10 | typedef __builtin_va_list va_list; 11 | #define va_start(ap, last) (__builtin_va_start(ap, last)) 12 | #define va_arg(ap, type) (__builtin_va_arg(ap, type)) 13 | #define va_end(ap) 14 | #endif 15 | -------------------------------------------------------------------------------- /os/lab3/include/stdarg.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file stdarg.h 3 | * 本文件实现可变参数 4 | * 5 | * @note 可变参数需要编译器的支持,不可能由程序员独立实现。 6 | * 因此我们只是简单的包装编译器提供的内建函数、类型。 7 | */ 8 | #ifndef __STDARG_H__ 9 | #define __STDARG_H__ 10 | typedef __builtin_va_list va_list; 11 | #define va_start(ap, last) (__builtin_va_start(ap, last)) 12 | #define va_arg(ap, type) (__builtin_va_arg(ap, type)) 13 | #define va_end(ap) 14 | #endif 15 | -------------------------------------------------------------------------------- /os/lab4/include/stdarg.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file stdarg.h 3 | * 本文件实现可变参数 4 | * 5 | * @note 可变参数需要编译器的支持,不可能由程序员独立实现。 6 | * 因此我们只是简单的包装编译器提供的内建函数、类型。 7 | */ 8 | #ifndef __STDARG_H__ 9 | #define __STDARG_H__ 10 | typedef __builtin_va_list va_list; 11 | #define va_start(ap, last) (__builtin_va_start(ap, last)) 12 | #define va_arg(ap, type) (__builtin_va_arg(ap, type)) 13 | #define va_end(ap) 14 | #endif 15 | -------------------------------------------------------------------------------- /os/lab5/include/stdarg.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file stdarg.h 3 | * 本文件实现可变参数 4 | * 5 | * @note 可变参数需要编译器的支持,不可能由程序员独立实现。 6 | * 因此我们只是简单的包装编译器提供的内建函数、类型。 7 | */ 8 | #ifndef __STDARG_H__ 9 | #define __STDARG_H__ 10 | typedef __builtin_va_list va_list; 11 | #define va_start(ap, last) (__builtin_va_start(ap, last)) 12 | #define va_arg(ap, type) (__builtin_va_arg(ap, type)) 13 | #define va_end(ap) 14 | #endif 15 | -------------------------------------------------------------------------------- /os/lab6/include/fs/ramfs.h: -------------------------------------------------------------------------------- 1 | #ifndef RAMFS_H 2 | #define RAMFS_H 3 | 4 | #include 5 | 6 | enum ramfs_inode_type { 7 | RAMFS_INODE_DIR = 0, 8 | RAMFS_INODE_FILE = 1 9 | }; 10 | 11 | struct ramfs_inode { 12 | uint64_t type; 13 | struct vfs_stat stat; 14 | void *data; 15 | uint64_t length; 16 | }; 17 | 18 | extern struct vfs_interface ramfs_interface; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /os/lab6/include/lib/sleep.h: -------------------------------------------------------------------------------- 1 | #ifndef __SLEEP_H__ 2 | #define __SLEEP_H__ 3 | #include 4 | #include 5 | 6 | struct usleep_queue_node { 7 | int64_t remaining_time; 8 | struct linked_list_node list_node; 9 | struct task_struct *task; 10 | }; 11 | 12 | void usleep_queue_init(); 13 | int64_t usleep_set(int64_t time); 14 | void usleep_handler(); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /os/lab6/include/stdarg.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file stdarg.h 3 | * 本文件实现可变参数 4 | * 5 | * @note 可变参数需要编译器的支持,不可能由程序员独立实现。 6 | * 因此我们只是简单的包装编译器提供的内建函数、类型。 7 | */ 8 | #ifndef __STDARG_H__ 9 | #define __STDARG_H__ 10 | typedef __builtin_va_list va_list; 11 | #define va_start(ap, last) (__builtin_va_start(ap, last)) 12 | #define va_arg(ap, type) (__builtin_va_arg(ap, type)) 13 | #define va_end(ap) 14 | #endif 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # 顶层 EditorConfig 文件 2 | root = true 3 | 4 | [*] 5 | # 删除行尾空白 6 | trim_trailing_whitespace = true 7 | # 使用 UTF-8 编码 8 | charset = utf-8 9 | # 使用 UNIX 风格 EOL 10 | end_of_line = lf 11 | # 文件末尾插入空白行 12 | insert_final_newline = true 13 | 14 | [*.{c,h}] 15 | # 使用 Space 缩进 16 | indent_style = space 17 | # 缩进长度为 4 Space 18 | indent_size = 4 19 | 20 | [Makefile] 21 | # 使用 Tab 缩进 22 | indent_style = tab 23 | -------------------------------------------------------------------------------- /os/lab6/drivers/loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct device_driver *driver_list[] = { 11 | &test_driver, 12 | &plic_driver, 13 | &uart8250_driver, 14 | &virtio_driver, 15 | NULL 16 | }; 17 | -------------------------------------------------------------------------------- /os/lab6/include/lib/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDIO_H__ 2 | #define __STDIO_H__ 3 | #include 4 | #include 5 | 6 | #define get_char() ((uint8_t) syscall(NR_char, 0)) 7 | #define put_char(c) (syscall(NR_char, (uint64_t) (c))) 8 | #define puts(str) do { \ 9 | for (char *cp = str; *cp; cp++) put_char(*cp); \ 10 | } while (0) 11 | 12 | int printf(const char* fmt, ...); 13 | int scanf(const char *format_str, ...); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /os/lab2/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef __STRING_H__ 2 | #define __STRING_H__ 3 | #include 4 | size_t strlen(const char *str); 5 | int64_t strcmp(const char *s, const char *t); 6 | uint64_t is_begin_with(const char *str1, const char *str2); 7 | static inline uint32_t fdt32_to_cpu(uint32_t val) 8 | { 9 | uint8_t *byte_i = (uint8_t *)&val; 10 | return (byte_i[0] << 24) | (byte_i[1] << 16) | (byte_i[2] << 8) | byte_i[3]; 11 | } 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /os/lab3/.projections.json: -------------------------------------------------------------------------------- 1 | { 2 | "include/*.h": { 3 | "alternate": "lib/{}.c", 4 | "type": "header" 5 | }, 6 | "lib/*.c": { 7 | "alternate": "include/{}.h", 8 | "type": "source" 9 | }, 10 | "include/mm.h": { 11 | "alternate": "mm/memory.c", 12 | "type": "header" 13 | }, 14 | "mm/memory.c": { 15 | "alternate": "include/mm.h", 16 | "type": "source" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /os/lab3/init/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I ../include 3 | 4 | vpath %.h ../include 5 | vpath $.a ../lib 6 | 7 | .PHONY : clean build 8 | 9 | build : entry.o main.o 10 | 11 | entry.o : entry.s 12 | main.o : main.c 13 | make -C ../lib build 14 | $(CC) $(CFLAGS) -c main.c 15 | 16 | clean : 17 | -find . -regex '.*\.o' -exec rm {} \; 18 | 19 | 20 | -------------------------------------------------------------------------------- /os/lab2/lib/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | 7 | .PHONY : clean build 8 | build : libstd.a 9 | 10 | libstd.a : $(objects) 11 | $(AR) vq $@ $^ 12 | 13 | $(objects) : %.o : %.c 14 | $(CC) $(CFLAGS) -c $< 15 | 16 | clean: 17 | -find . -name '*.o' -exec rm {} \; 18 | -find . -name '*.a' -exec rm {} \; 19 | -------------------------------------------------------------------------------- /os/lab3/lib/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | 7 | .PHONY : clean build 8 | build : libstd.a 9 | 10 | libstd.a : $(objects) 11 | $(AR) vq $@ $^ 12 | 13 | $(objects) : %.o : %.c 14 | $(CC) $(CFLAGS) -c $< 15 | 16 | clean: 17 | -find . -name '*.o' -exec rm {} \; 18 | -find . -name '*.a' -exec rm {} \; 19 | -------------------------------------------------------------------------------- /os/lab4/lib/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | 7 | .PHONY : clean build 8 | build : libstd.a 9 | 10 | libstd.a : $(objects) 11 | $(AR) vq $@ $^ 12 | 13 | $(objects) : %.o : %.c 14 | $(CC) $(CFLAGS) -c $< 15 | 16 | clean: 17 | -find . -name '*.o' -exec rm {} \; 18 | -find . -name '*.a' -exec rm {} \; 19 | -------------------------------------------------------------------------------- /doc/meeting_record/20201122.md: -------------------------------------------------------------------------------- 1 | # 2020-11-24 2 | 3 | **与会人员**:孔俊 俞腾飞 刑霜 宋胜利 薛睿卓 4 | 5 | 主要内容: 6 | 7 | - 阅读、讨论 Linux 0.12 内存管理模块(目录 mm) 8 | - 讨论要进行的工作 9 | 10 | TODO: 11 | - [ ] 修改项目目录结构。启动相关的代码放到 boot/ 下,内存管理的代码放到 mm/ 下,工具配置文件放到 tool/ 下,库放到 lib/ 下,头文件放到 include/下。每个目录中单独编写 Makefile,由上层 Makefile 调用。 12 | - [ ] 将 mm/memory.c 移植到 RISC-V 上,暂时不处理和进程、文件系统相关的部分。 13 | - [ ] 将 mm/page.s 移植到 RISC-V 上,并完成中断处理函数的设置。 14 | - [ ] 修改 entry.s,设置好页表。 15 | - [ ] 将 lib/ 中的简易标准库移植到 RISC-V 上。 16 | - [ ] 将内核分配函数`malloc()`移植到 RISC-V 上。 17 | 18 | 19 | -------------------------------------------------------------------------------- /os/lab5/lib/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-pie -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | 7 | .PHONY : clean build 8 | build : libstd.a 9 | 10 | libstd.a : $(objects) 11 | $(AR) vq $@ $^ 12 | 13 | $(objects) : %.o : %.c 14 | $(CC) $(CFLAGS) -c $< 15 | 16 | clean: 17 | -find . -name '*.o' -exec rm {} \; 18 | -find . -name '*.a' -exec rm {} \; 19 | 20 | 21 | -------------------------------------------------------------------------------- /os/lab6/lib/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-pie -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | 7 | .PHONY : clean build 8 | build : libstd.a 9 | 10 | libstd.a : $(objects) 11 | $(AR) vq $@ $^ 12 | 13 | $(objects) : %.o : %.c 14 | $(CC) $(CFLAGS) -c $< 15 | 16 | clean: 17 | -find . -name '*.o' -exec rm {} \; 18 | -find . -name '*.a' -exec rm {} \; 19 | 20 | 21 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LZU OSLab 开发环境", 3 | "build": { 4 | "dockerfile": "Dockerfile.develop", 5 | "context": "." 6 | }, 7 | "postStartCommand": "cp -d /root/* ${containerWorkspaceFolder}/", 8 | 9 | "settings": { 10 | "terminal.integrated.defaultProfile.linux": "bash" 11 | }, 12 | "extensions": [ 13 | "ms-vscode.cpptools", 14 | "ms-ceintl.vscode-language-pack-zh-hans", 15 | "ms-vscode.hexeditor", 16 | "zhwu95.riscv" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /os/lab3/trap/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | ASFLAGS := -g 5 | 6 | vpath %.h ../include 7 | 8 | .PHONY : clean build 9 | build : libtrap.a 10 | 11 | libtrap.a : $(objects) trapentry.o 12 | $(AR) vq $@ $^ 13 | 14 | $(objects) : %.o : %.c 15 | $(CC) $(CFLAGS) -c $< 16 | 17 | clean: 18 | -find . -name '*.o' -exec rm {} \; 19 | -find . -name '*.a' -exec rm {} \; 20 | -------------------------------------------------------------------------------- /os/lab4/init/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | # -fno-pie 禁止生成位置无关代码,可以简单地理解为:禁止 GCC 生成使用 auipc/ld 指令获取符号地址的代码 3 | CFLAGS := -mcmodel=medany -fno-pie -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | vpath $.a ../lib 7 | 8 | .PHONY : clean build 9 | 10 | build : entry.o main.o 11 | 12 | entry.o : entry.s 13 | $(CC) $(CFLAGS) -c entry.s 14 | main.o : main.c 15 | $(CC) $(CFLAGS) -c main.c 16 | 17 | clean : 18 | -find . -regex '.*\.o' -exec rm {} \; 19 | 20 | 21 | -------------------------------------------------------------------------------- /os/lab4/trap/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | ASFLAGS := -g 5 | 6 | vpath %.h ../include 7 | 8 | .PHONY : clean build 9 | build : libtrap.a 10 | 11 | libtrap.a : $(objects) trapentry.o 12 | $(AR) vq $@ $^ 13 | 14 | $(objects) : %.o : %.c 15 | $(CC) $(CFLAGS) -c $< 16 | 17 | clean: 18 | -find . -name '*.o' -exec rm {} \; 19 | -find . -name '*.a' -exec rm {} \; 20 | -------------------------------------------------------------------------------- /os/lab5/init/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | # -fno-pie 禁止生成位置无关代码,可以简单地理解为:禁止 GCC 生成使用 auipc/ld 指令获取符号地址的代码 3 | CFLAGS := -mcmodel=medany -fno-pie -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | vpath $.a ../lib 7 | 8 | .PHONY : clean build 9 | 10 | build : entry.o main.o 11 | 12 | entry.o : entry.s 13 | $(CC) $(CFLAGS) -c entry.s 14 | main.o : main.c 15 | $(CC) $(CFLAGS) -c main.c 16 | 17 | clean : 18 | -find . -regex '.*\.o' -exec rm {} \; 19 | 20 | 21 | -------------------------------------------------------------------------------- /os/lab6/include/device/block.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICE_BLOCK_H 2 | #define DEVICE_BLOCK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define BLOCK_INTERFACE_BIT (1 << 7) 10 | 11 | struct block_request { 12 | uint64_t is_read; 13 | uint64_t sector; 14 | void *buffer; 15 | struct task_struct * wait_queue; 16 | }; 17 | 18 | struct block_device { 19 | struct device *dev; 20 | void (*request)(struct device *dev, struct block_request *request); 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /os/lab6/init/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | # -fno-pie 禁止生成位置无关代码,可以简单地理解为:禁止 GCC 生成使用 auipc/ld 指令获取符号地址的代码 3 | CFLAGS := -mcmodel=medany -fno-pie -Wno-main -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | vpath $.a ../lib 7 | 8 | .PHONY : clean build 9 | 10 | build : entry.o main.o 11 | 12 | entry.o : entry.s 13 | $(CC) $(CFLAGS) -c entry.s 14 | main.o : main.c 15 | $(CC) $(CFLAGS) -c main.c 16 | 17 | clean : 18 | -find . -regex '.*\.o' -exec rm {} \; 19 | 20 | 21 | -------------------------------------------------------------------------------- /os/lab1/stddef.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 本文件定义常用数据类型 3 | */ 4 | #ifndef __STDDEF_H__ 5 | #define __STDDEF_H__ 6 | 7 | #define NULL (void *)0 8 | typedef signed int int32_t; 9 | typedef unsigned int uint32_t; 10 | typedef signed long long int64_t; 11 | typedef unsigned long long uint64_t; 12 | typedef unsigned char uint8_t; 13 | typedef signed char int8_t; 14 | typedef unsigned long long size_t; 15 | typedef signed long long ssize_t; 16 | /** 17 | * 不要使用 intptr_t, uintptr_t,请用 int64_t, uint64_t 代替 18 | * typedef int64_t intptr_t; 19 | * typedef uint64_t uintptr_t; 20 | */ 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /os/lab6/drivers/memory.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define DRIVER_MEM_START 0xCC000000 5 | uint64_t mem_resource_ptr = DRIVER_MEM_START; 6 | 7 | void mem_resource_map(struct driver_resource *res) { 8 | uint64_t map_start = FLOOR(res->resource_start); 9 | uint64_t map_end = CEIL(res->resource_end); 10 | res->map_address = mem_resource_ptr; 11 | while (map_start < map_end) { 12 | put_page(map_start, mem_resource_ptr, KERN_RW | PAGE_VALID); 13 | map_start += PAGE_SIZE; 14 | mem_resource_ptr += PAGE_SIZE; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /os/lab6/fs/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c) $(wildcard **/*.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-pie -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | 7 | .PHONY : clean build 8 | build : libfs.a 9 | 10 | libfs.a : $(objects) ../mm/libmm.a ../lib/libstd.a 11 | $(AR) vq $@ $^ 12 | 13 | ../lib/libstd.a: 14 | make -C ../lib build 15 | 16 | ../lib/libmm.a: 17 | make -C ../mm build 18 | 19 | clean: 20 | -find . -name '*.o' -exec rm {} \; 21 | -find . -name '*.a' -exec rm {} \; 22 | -------------------------------------------------------------------------------- /os/lab3/mm/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | 7 | .PHONY : clean build 8 | build : libmm.a 9 | 10 | libmm.a : $(objects) ../lib/libstd.a 11 | make -C ../lib build 12 | $(AR) vq $@ $^ 13 | 14 | $(objects) : %.o : %.c 15 | $(CC) $(CFLAGS) -c $< 16 | 17 | ../lib/libstd.a : 18 | make -C ../lib build 19 | 20 | clean: 21 | -find . -name '*.o' -exec rm {} \; 22 | -find . -name '*.a' -exec rm {} \; 23 | 24 | 25 | -------------------------------------------------------------------------------- /os/lab4/mm/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | 7 | .PHONY : clean build 8 | build : libmm.a 9 | 10 | libmm.a : $(objects) ../lib/libstd.a 11 | make -C ../lib build 12 | $(AR) vq $@ $^ 13 | 14 | $(objects) : %.o : %.c 15 | $(CC) $(CFLAGS) -c $< 16 | 17 | ../lib/libstd.a : 18 | make -C ../lib build 19 | 20 | clean: 21 | -find . -name '*.o' -exec rm {} \; 22 | -find . -name '*.a' -exec rm {} \; 23 | 24 | 25 | -------------------------------------------------------------------------------- /os/lab5/mm/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-pie -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | 7 | .PHONY : clean build 8 | build : libmm.a 9 | 10 | libmm.a : $(objects) ../lib/libstd.a 11 | make -C ../lib build 12 | $(AR) vq $@ $^ 13 | 14 | $(objects) : %.o : %.c 15 | $(CC) $(CFLAGS) -c $< 16 | 17 | ../lib/libstd.a : 18 | make -C ../lib build 19 | 20 | clean: 21 | -find . -name '*.o' -exec rm {} \; 22 | -find . -name '*.a' -exec rm {} \; 23 | 24 | 25 | -------------------------------------------------------------------------------- /os/lab6/drivers/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c) $(wildcard **/*.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-pie -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | 7 | .PHONY : clean build 8 | build : libdrivers.a 9 | 10 | libdrivers.a : $(objects) ../mm/libmm.a ../lib/libstd.a 11 | $(AR) vq $@ $^ 12 | 13 | ../lib/libstd.a: 14 | make -C ../lib build 15 | 16 | ../lib/libmm.a: 17 | make -C ../mm build 18 | 19 | clean: 20 | -find . -name '*.o' -exec rm {} \; 21 | -find . -name '*.a' -exec rm {} \; 22 | -------------------------------------------------------------------------------- /os/lab6/mm/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-pie -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | 5 | vpath %.h ../include 6 | 7 | .PHONY : clean build 8 | build : libmm.a 9 | 10 | libmm.a : $(objects) ../lib/libstd.a 11 | make -C ../lib build 12 | $(AR) vq $@ $^ 13 | 14 | $(objects) : %.o : %.c 15 | $(CC) $(CFLAGS) -c $< 16 | 17 | ../lib/libstd.a : 18 | make -C ../lib build 19 | 20 | clean: 21 | -find . -name '*.o' -exec rm {} \; 22 | -find . -name '*.a' -exec rm {} \; 23 | 24 | 25 | -------------------------------------------------------------------------------- /os/lab5/include/syscall.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file syscall.h 3 | * @brief 声明系统调用号、系统调用表和系统调用创建宏 4 | */ 5 | #ifndef __SYSCALL_H__ 6 | #define __SYSCALL_H__ 7 | #include 8 | typedef long (*fn_ptr)(struct trapframe *); /**< 系统调用指针类型 */ 9 | extern fn_ptr syscall_table[]; 10 | extern long test_fork; 11 | /// @{ @name 系统调用号 12 | #define NR_syscalls 5 /**< 系统调用数量 */ 13 | #define NR_fork 1 14 | #define NR_test_fork 2 15 | #define NR_getpid 3 16 | #define NR_getppid 4 17 | /// @} 18 | 19 | long syscall(long number, ...); 20 | 21 | #endif /* end of include guard: __SYSCALL_H__ */ 22 | -------------------------------------------------------------------------------- /os/lab2/trap/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | ASFLAGS := -g 5 | 6 | vpath %.h ../include 7 | 8 | .PHONY : clean build 9 | build : libtrap.a 10 | 11 | libtrap.a : $(objects) trapentry.o rtc/rtc_goldfish.o rtc/rtc_sunxi.o rtc/rtc.o uart/uart.o uart/uart_sunxi.o uart/uart_qemu.o 12 | $(AR) vq $@ $^ 13 | 14 | $(objects) : %.o : %.c 15 | $(CC) $(CFLAGS) -c $< 16 | 17 | clean: 18 | -find . -name '*.o' -exec rm {} \; 19 | -find . -name '*.a' -exec rm {} \; 20 | -------------------------------------------------------------------------------- /os/lab5/kernel/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-pie -fno-pic -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | ASFLAGS := -g 5 | 6 | vpath %.h ../include 7 | 8 | .PHONY : clean build 9 | build : libkernel.a 10 | 11 | libkernel.a : $(objects) trapentry.o ../lib/libstd.a 12 | $(AR) vq $@ $^ 13 | 14 | $(objects) : %.o : %.c 15 | $(CC) $(CFLAGS) -c $< 16 | 17 | ../lib/libstd.a: 18 | make -C ../lib 19 | 20 | clean: 21 | -find . -name '*.o' -exec rm {} \; 22 | -find . -name '*.a' -exec rm {} \; 23 | -------------------------------------------------------------------------------- /os/lab6/kernel/Makefile: -------------------------------------------------------------------------------- 1 | include ../tools/toolchain.mk 2 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) 3 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-pie -fno-pic -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I../include 4 | ASFLAGS := -g 5 | 6 | vpath %.h ../include 7 | 8 | .PHONY : clean build 9 | build : libkernel.a 10 | 11 | libkernel.a : $(objects) trapentry.o ../lib/libstd.a 12 | $(AR) vq $@ $^ 13 | 14 | $(objects) : %.o : %.c 15 | $(CC) $(CFLAGS) -c $< 16 | 17 | ../lib/libstd.a: 18 | make -C ../lib 19 | 20 | clean: 21 | -find . -name '*.o' -exec rm {} \; 22 | -find . -name '*.a' -exec rm {} \; 23 | -------------------------------------------------------------------------------- /os/lab2/include/stddef.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 本文件定义常用数据类型 3 | */ 4 | #ifndef __STDDEF_H__ 5 | #define __STDDEF_H__ 6 | 7 | #define NULL (void *)0 8 | typedef signed int int32_t; 9 | typedef unsigned int uint32_t; 10 | typedef signed long long int64_t; 11 | typedef unsigned long long uint64_t; 12 | typedef unsigned short uint16_t; 13 | typedef short int16_t; 14 | typedef unsigned char uint8_t; 15 | typedef signed char int8_t; 16 | typedef unsigned long long size_t; 17 | typedef signed long long ssize_t; 18 | /** 19 | * 不要使用 intptr_t, uintptr_t,请用 int64_t, uint64_t 代替 20 | * typedef int64_t intptr_t; 21 | * typedef uint64_t uintptr_t; 22 | */ 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /os/lab3/include/stddef.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 本文件定义常用数据类型 3 | */ 4 | #ifndef __STDDEF_H__ 5 | #define __STDDEF_H__ 6 | 7 | #define NULL (void *)0 8 | typedef signed int int32_t; 9 | typedef unsigned int uint32_t; 10 | typedef signed long long int64_t; 11 | typedef unsigned long long uint64_t; 12 | typedef unsigned short uint16_t; 13 | typedef short int16_t; 14 | typedef unsigned char uint8_t; 15 | typedef signed char int8_t; 16 | typedef unsigned long long size_t; 17 | typedef signed long long ssize_t; 18 | /** 19 | * 不要使用 intptr_t, uintptr_t,请用 int64_t, uint64_t 代替 20 | * typedef int64_t intptr_t; 21 | * typedef uint64_t uintptr_t; 22 | */ 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /os/lab4/include/stddef.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 本文件定义常用数据类型 3 | */ 4 | #ifndef __STDDEF_H__ 5 | #define __STDDEF_H__ 6 | 7 | #define NULL (void *)0 8 | typedef signed int int32_t; 9 | typedef unsigned int uint32_t; 10 | typedef signed long long int64_t; 11 | typedef unsigned long long uint64_t; 12 | typedef unsigned short uint16_t; 13 | typedef short int16_t; 14 | typedef unsigned char uint8_t; 15 | typedef signed char int8_t; 16 | typedef unsigned long long size_t; 17 | typedef signed long long ssize_t; 18 | /** 19 | * 不要使用 intptr_t, uintptr_t,请用 int64_t, uint64_t 代替 20 | * typedef int64_t intptr_t; 21 | * typedef uint64_t uintptr_t; 22 | */ 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /os/lab5/include/stddef.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 本文件定义常用数据类型 3 | */ 4 | #ifndef __STDDEF_H__ 5 | #define __STDDEF_H__ 6 | 7 | #define NULL (void *)0 8 | typedef signed int int32_t; 9 | typedef unsigned int uint32_t; 10 | typedef signed long long int64_t; 11 | typedef unsigned long long uint64_t; 12 | typedef unsigned short uint16_t; 13 | typedef short int16_t; 14 | typedef unsigned char uint8_t; 15 | typedef signed char int8_t; 16 | typedef unsigned long long size_t; 17 | typedef signed long long ssize_t; 18 | /** 19 | * 不要使用 intptr_t, uintptr_t,请用 int64_t, uint64_t 代替 20 | * typedef int64_t intptr_t; 21 | * typedef uint64_t uintptr_t; 22 | */ 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /os/lab5/lib/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | size_t strlen(const char *str) 4 | { 5 | size_t i = 0; 6 | for (; str[i] != '\0'; ++i) 7 | ; 8 | return i; 9 | } 10 | 11 | void *memset(void *src, char ch, size_t cnt) 12 | { 13 | for (size_t i = 0; i < cnt; ++i) 14 | *((char *)src + i) = ch; 15 | return src; 16 | } 17 | 18 | void *memcpy(void *dest, const void *src, size_t n) 19 | { 20 | void *ret = dest; 21 | while (n--) { 22 | /* 23 | * ++ 和 (type) 运算符优先级相同,从右往左结合, 24 | * 因此修改的是指针,而不是转型创建的临时值。 25 | */ 26 | *((char *)dest++) = *((char *)src++); 27 | } 28 | return ret; 29 | } 30 | -------------------------------------------------------------------------------- /os/lab2/tools/toolchain.mk: -------------------------------------------------------------------------------- 1 | # 以下是工具链的定义,其中部分是 Makefile 的默认变量,使用 := 符号定义可以覆盖原变量的定义 2 | # CC - 编译器;LD - 链接器;OBJCOPY - 二进制拷贝程序;OBJDUMP - 反汇编程序 3 | # NM - 符号提取程序;AS - 编译器;GDB - 调试程序;TMUX - 终端复用器;QEMU - RISC-V模拟器 4 | ifneq ($(wildcard $(foreach p,$(subst :, ,$(PATH)),$(p)/riscv64-linux-gnu-*)),) 5 | PREFIX := riscv64-linux-gnu 6 | else 7 | PREFIX := riscv64-unknown-elf 8 | endif 9 | 10 | CC := $(PREFIX)-gcc 11 | LD := $(PREFIX)-ld 12 | AR := $(PREFIX)-ar 13 | OBJCOPY := $(PREFIX)-objcopy 14 | OBJDUMP := $(PREFIX)-objdump 15 | READELF := $(PREFIX)-readelf 16 | NM := $(PREFIX)-nm 17 | AS := $(PREFIX)-as 18 | TMUX := tmux 19 | QEMU := qemu-system-riscv64 20 | GDB := riscv64-unknown-elf-gdb 21 | -------------------------------------------------------------------------------- /os/lab3/tools/toolchain.mk: -------------------------------------------------------------------------------- 1 | # 以下是工具链的定义,其中部分是 Makefile 的默认变量,使用 := 符号定义可以覆盖原变量的定义 2 | # CC - 编译器;LD - 链接器;OBJCOPY - 二进制拷贝程序;OBJDUMP - 反汇编程序 3 | # NM - 符号提取程序;AS - 编译器;GDB - 调试程序;TMUX - 终端复用器;QEMU - RISC-V模拟器 4 | ifneq ($(wildcard $(foreach p,$(subst :, ,$(PATH)),$(p)/riscv64-linux-gnu-*)),) 5 | PREFIX := riscv64-linux-gnu 6 | else 7 | PREFIX := riscv64-unknown-elf 8 | endif 9 | 10 | CC := $(PREFIX)-gcc 11 | LD := $(PREFIX)-ld 12 | AR := $(PREFIX)-ar 13 | OBJCOPY := $(PREFIX)-objcopy 14 | OBJDUMP := $(PREFIX)-objdump 15 | READELF := $(PREFIX)-readelf 16 | NM := $(PREFIX)-nm 17 | AS := $(PREFIX)-as 18 | TMUX := tmux 19 | QEMU := qemu-system-riscv64 20 | GDB := riscv64-unknown-elf-gdb 21 | -------------------------------------------------------------------------------- /os/lab4/tools/toolchain.mk: -------------------------------------------------------------------------------- 1 | # 以下是工具链的定义,其中部分是 Makefile 的默认变量,使用 := 符号定义可以覆盖原变量的定义 2 | # CC - 编译器;LD - 链接器;OBJCOPY - 二进制拷贝程序;OBJDUMP - 反汇编程序 3 | # NM - 符号提取程序;AS - 编译器;GDB - 调试程序;TMUX - 终端复用器;QEMU - RISC-V模拟器 4 | ifneq ($(wildcard $(foreach p,$(subst :, ,$(PATH)),$(p)/riscv64-linux-gnu-*)),) 5 | PREFIX := riscv64-linux-gnu 6 | else 7 | PREFIX := riscv64-unknown-elf 8 | endif 9 | 10 | CC := $(PREFIX)-gcc 11 | LD := $(PREFIX)-ld 12 | AR := $(PREFIX)-ar 13 | OBJCOPY := $(PREFIX)-objcopy 14 | OBJDUMP := $(PREFIX)-objdump 15 | READELF := $(PREFIX)-readelf 16 | NM := $(PREFIX)-nm 17 | AS := $(PREFIX)-as 18 | TMUX := tmux 19 | QEMU := qemu-system-riscv64 20 | GDB := riscv64-unknown-elf-gdb 21 | -------------------------------------------------------------------------------- /os/lab5/tools/toolchain.mk: -------------------------------------------------------------------------------- 1 | # 以下是工具链的定义,其中部分是 Makefile 的默认变量,使用 := 符号定义可以覆盖原变量的定义 2 | # CC - 编译器;LD - 链接器;OBJCOPY - 二进制拷贝程序;OBJDUMP - 反汇编程序 3 | # NM - 符号提取程序;AS - 编译器;GDB - 调试程序;TMUX - 终端复用器;QEMU - RISC-V模拟器 4 | ifneq ($(wildcard $(foreach p,$(subst :, ,$(PATH)),$(p)/riscv64-linux-gnu-*)),) 5 | PREFIX := riscv64-linux-gnu 6 | else 7 | PREFIX := riscv64-unknown-elf 8 | endif 9 | 10 | CC := $(PREFIX)-gcc 11 | LD := $(PREFIX)-ld 12 | AR := $(PREFIX)-ar 13 | OBJCOPY := $(PREFIX)-objcopy 14 | OBJDUMP := $(PREFIX)-objdump 15 | READELF := $(PREFIX)-readelf 16 | NM := $(PREFIX)-nm 17 | AS := $(PREFIX)-as 18 | TMUX := tmux 19 | QEMU := qemu-system-riscv64 20 | GDB := riscv64-unknown-elf-gdb 21 | -------------------------------------------------------------------------------- /os/lab6/tools/toolchain.mk: -------------------------------------------------------------------------------- 1 | # 以下是工具链的定义,其中部分是 Makefile 的默认变量,使用 := 符号定义可以覆盖原变量的定义 2 | # CC - 编译器;LD - 链接器;OBJCOPY - 二进制拷贝程序;OBJDUMP - 反汇编程序 3 | # NM - 符号提取程序;AS - 编译器;GDB - 调试程序;TMUX - 终端复用器;QEMU - RISC-V模拟器 4 | ifneq ($(wildcard $(foreach p,$(subst :, ,$(PATH)),$(p)/riscv64-linux-gnu-*)),) 5 | PREFIX := riscv64-linux-gnu 6 | else 7 | PREFIX := riscv64-unknown-elf 8 | endif 9 | 10 | CC := $(PREFIX)-gcc 11 | LD := $(PREFIX)-ld 12 | AR := $(PREFIX)-ar 13 | OBJCOPY := $(PREFIX)-objcopy 14 | OBJDUMP := $(PREFIX)-objdump 15 | READELF := $(PREFIX)-readelf 16 | NM := $(PREFIX)-nm 17 | AS := $(PREFIX)-as 18 | TMUX := tmux 19 | QEMU := qemu-system-riscv64 20 | GDB := riscv64-unknown-elf-gdb 21 | -------------------------------------------------------------------------------- /os/lab2/lib/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | size_t strlen(const char *str) 5 | { 6 | size_t i = 0; 7 | for (; str[i] != '\0'; ++i) 8 | ; 9 | return i; 10 | } 11 | 12 | int64_t strcmp(const char *s, const char *t) 13 | { 14 | while (*s && *t && *s == *t) { 15 | s++; 16 | t++; 17 | } 18 | return *s - *t; 19 | } 20 | 21 | uint64_t is_begin_with(const char *str1, const char *str2) 22 | { 23 | if (!str1 || !str2) 24 | return 0; 25 | const char *p = str2; 26 | int i = 0; 27 | while (*p != '\0') { 28 | if (*p != str1[i]) 29 | return 0; 30 | p++; 31 | i++; 32 | } 33 | return 1; 34 | } -------------------------------------------------------------------------------- /doc/meeting_record/20201115.md: -------------------------------------------------------------------------------- 1 | # 2020-11-15 2 | 3 | **与会人员**:孔俊 俞腾飞 刑霜 宋胜利 薛睿卓 4 | 5 | **主要内容**: 6 | 7 | - 配置实验环境 8 | - 讨论实验一文档的撰写 9 | - 讨论存在的问题 10 | 11 | **存在的问题**: 12 | 13 | - [x] 无法在终端同时打开 qemu 和 gdb 14 | 15 | 使用 tmux 复用终端,实现同时打开 qemu 和 gdb 16 | 17 | - [x] qemu 源码包太大,克隆仓库耗时太长 18 | 19 | - [x] gdb 无法接入 qemu 20 | 21 | 编译出来的目标平台为 riscv64 的 gdb 名为 **riscv64-unknown-elf-gdb**,键入命令 **gdb** 会启动系统中存在的目标平台为 x86 的 gdb。 22 | 23 | **文档撰写**: 24 | 25 | 1. 实验环境配置 26 | 2. 内核的制作 27 | 3. 启动过程 28 | 4. SBI 和内联汇编简介 29 | 5. 实验题 30 | 1. 熟悉实验环境,使用 gdb 连接到 qemu 模拟器,反汇编并单步跟踪 31 | 2. 了解 RISC-V SBI,使用封装好的 ecall 调用检测环境 32 | 3. 了解 RISC-V 汇编,设置堆栈并跳转到 main 函数(注:文档的指导详细到每一行代码) 33 | 34 | 6. 参考资料 35 | 36 | 薛睿卓完成 1, 俞腾飞完成 2,孔俊完成 3~ 6。 37 | 38 | -------------------------------------------------------------------------------- /os/lab5/init/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() 10 | { 11 | kputs("\nLZU OS STARTING...................."); 12 | print_system_infomation(); 13 | mem_init(); 14 | mem_test(); 15 | set_stvec(); 16 | sched_init(); 17 | clock_init(); 18 | kputs("Hello LZU OS"); 19 | enable_interrupt(); 20 | init_task0(); 21 | syscall(NR_fork); /* task 0 creates task 1 */ 22 | syscall(NR_fork); /* task 0 creates task 2, task 1 creates task 3 */ 23 | long local = syscall(NR_getpid) + 100; 24 | syscall(NR_test_fork, local); 25 | while (1) 26 | ; /* infinite loop */ 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /os/lab2/include/uart.h: -------------------------------------------------------------------------------- 1 | #ifndef __UART_H__ 2 | #define __UART_H__ 3 | #include 4 | 5 | struct uart_class_ops { 6 | void (*uart_directly_write)(int8_t c); 7 | void (*uart_putc)(int8_t c); 8 | int8_t (*uart_read)(); 9 | void (*uart_interrupt_handler)(); 10 | }; 11 | 12 | struct uart_class_device { 13 | uint32_t id; 14 | uint64_t uart_start_addr; 15 | uint16_t divisor; 16 | struct uart_class_ops ops; 17 | }; 18 | enum uart_device_type { 19 | UART_QEMU = 0, 20 | UART_SUNXI = 1, 21 | }; 22 | 23 | void uart_init(); 24 | int8_t uart_read(); 25 | void uart_directly_write(int8_t c); 26 | void uart_putc(int8_t c); 27 | void uart_interrupt_handler(); 28 | void uart_qemu_init(); 29 | void uart_sunxi_init(); 30 | #endif /* end of include guard: __UART_H__ */ 31 | -------------------------------------------------------------------------------- /os/lab4/init/entry.s: -------------------------------------------------------------------------------- 1 | .globl boot_stack, boot_stack_top, _start, boot_pg_dir 2 | .section .text.entry 3 | 4 | # 本项目所用代码模型为 medany, 该代码模型下编译器生成的代码以 PC 相对寻址的方式访问任意地址,地址通过 auipc 和 addi 指令获取。 5 | # 可执行文件中的地址与加载后的内存地址相差 0x40000000,因此处理器访问到的地址加 0x40000000 才是可执行文件中符号的地址。 6 | 7 | _start: 8 | la t0, boot_pg_dir 9 | srli t0, t0, 12 10 | li t1, (8 << 60) 11 | or t0, t0, t1 12 | csrw satp, t0 13 | sfence.vma 14 | 15 | li t1, 0x40000000 16 | la sp, boot_stack_top 17 | add sp, sp, t1 18 | la t0, main 19 | add t0, t0, t1 20 | jr t0 21 | 22 | .section .bss 23 | boot_stack: 24 | .space 4096 * 8 25 | boot_stack_top: 26 | 27 | .section .data 28 | boot_pg_dir: 29 | .zero 2 * 8 30 | .quad (0x80000000 >> 2) | 0x0F 31 | .quad (0x80000000 >> 2) | 0x0F 32 | .zero 508 * 8 33 | -------------------------------------------------------------------------------- /os/lab5/init/entry.s: -------------------------------------------------------------------------------- 1 | .globl boot_stack, boot_stack_top, _start, boot_pg_dir 2 | .section .text.entry 3 | 4 | # 本项目所用代码模型为 medany, 该代码模型下编译器生成的代码以 PC 相对寻址的方式访问任意地址,地址通过 auipc 和 addi 指令获取。 5 | # 可执行文件中的地址与加载后的内存地址相差 0x40000000,因此处理器访问到的地址加 0x40000000 才是可执行文件中符号的地址。 6 | 7 | _start: 8 | la t0, boot_pg_dir 9 | srli t0, t0, 12 10 | li t1, (8 << 60) 11 | or t0, t0, t1 12 | csrw satp, t0 13 | sfence.vma 14 | 15 | li t1, 0x40000000 16 | la sp, boot_stack_top 17 | add sp, sp, t1 18 | la t0, main 19 | add t0, t0, t1 20 | jr t0 21 | 22 | # .section .bss 23 | .section .data 24 | boot_stack: 25 | .space 4096 * 4 26 | boot_stack_top: 27 | 28 | boot_pg_dir: 29 | .zero 2 * 8 30 | .quad (0x80000000 >> 2) | 0x0F 31 | .quad (0x80000000 >> 2) | 0x0F 32 | .zero 508 * 8 33 | -------------------------------------------------------------------------------- /os/lab6/include/syscall.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file syscall.h 3 | * @brief 声明系统调用号、系统调用表和系统调用创建宏 4 | */ 5 | #ifndef __SYSCALL_H__ 6 | #define __SYSCALL_H__ 7 | #include 8 | typedef long (*fn_ptr)(struct trapframe *); /**< 系统调用指针类型 */ 9 | extern fn_ptr syscall_table[]; 10 | extern long test_fork; 11 | /// @{ @name 系统调用号 12 | #define NR_syscalls 13 /**< 系统调用数量 */ 13 | #define NR_fork 1 14 | #define NR_test_fork 2 15 | #define NR_getpid 3 16 | #define NR_getppid 4 17 | #define NR_char 5 18 | #define NR_block 6 19 | #define NR_open 7 20 | #define NR_close 8 21 | #define NR_stat 9 22 | #define NR_read 10 23 | #define NR_reset 11 24 | #define NR_usleep 12 25 | /// @} 26 | 27 | long syscall(long number, ...); 28 | 29 | #endif /* end of include guard: __SYSCALL_H__ */ 30 | -------------------------------------------------------------------------------- /os/lab6/init/entry.s: -------------------------------------------------------------------------------- 1 | .globl boot_stack, boot_stack_top, _start, boot_pg_dir 2 | .section .text.entry 3 | 4 | # 本项目所用代码模型为 medany, 该代码模型下编译器生成的代码以 PC 相对寻址的方式访问任意地址,地址通过 auipc 和 addi 指令获取。 5 | # 可执行文件中的地址与加载后的内存地址相差 0x40000000,因此处理器访问到的地址加 0x40000000 才是可执行文件中符号的地址。 6 | 7 | _start: 8 | la t0, boot_pg_dir 9 | srli t0, t0, 12 10 | li t1, (8 << 60) 11 | or t0, t0, t1 12 | csrw satp, t0 13 | sfence.vma 14 | 15 | li t1, 0x40000000 16 | la sp, boot_stack_top 17 | add sp, sp, t1 18 | la t0, main 19 | add t0, t0, t1 20 | jr t0 21 | 22 | # .section .bss 23 | .section .data 24 | boot_stack: 25 | .space 4096 * 4 26 | boot_stack_top: 27 | 28 | boot_pg_dir: 29 | .zero 2 * 8 30 | .quad (0x80000000 >> 2) | 0x0F 31 | .quad (0x80000000 >> 2) | 0x0F 32 | .zero 508 * 8 33 | -------------------------------------------------------------------------------- /os/lab6/include/device/serial/uart8250.h: -------------------------------------------------------------------------------- 1 | #ifndef UART8250_H 2 | #define UART8250_H 3 | 4 | #include 5 | 6 | #define UART8250_MAJOR 0x8250 7 | 8 | struct uart_qemu_regs { 9 | volatile uint8_t RBR_THR_DLL; // 0x00, Receiver Buffer Register/Transmitter Holding Register/Divisor Latch LSB 10 | volatile uint8_t IER_DLM; // 0x01, Interrupt Enable Register/Divisor Latch MSB 11 | volatile uint8_t IIR_FCR; // 0x02, Interrupt Identification Register/FIFO Control Register 12 | volatile uint8_t LCR; // 0x03, Line Control Register 13 | volatile uint8_t MCR; // 0x04, Modem Control Register 14 | volatile uint8_t LSR; // 0x05, Line Status Register 15 | }; 16 | 17 | enum uart8250_reg_bit { 18 | IER_ERBFI = 0, 19 | LSR_DR = 0, 20 | LSR_THRE = 5, 21 | LCR_DLAB = 7, 22 | }; 23 | 24 | extern struct device_driver uart8250_driver; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /os/lab6/include/device/irq/plic.h: -------------------------------------------------------------------------------- 1 | #ifndef PLIC_H 2 | #define PLIC_H 3 | 4 | #include 5 | #include 6 | 7 | #define PLIC_MAJOR 0x5678 8 | 9 | #define PLIC_PRIORITY_BASE 0x0 10 | #define PLIC_PENDING_BASE 0x1000 11 | #define PLIC_ENABLE_BASE 0x2000 12 | #define PLIC_ENABLE_STRIDE 0x80 13 | #define PLIC_CONTEXT_BASE 0x200000 14 | #define PLIC_CONTEXT_STRIDE 0x1000 15 | 16 | #define PLIC_THRESHOLD_OFFSET 0 17 | #define PLIC_CLAIM_OFFSET 4 18 | #define PLIC_COMPLETE_OFFSET 4 19 | 20 | struct plic_match_data { 21 | uint64_t mmio_start_addr; 22 | uint64_t mmio_end_addr; 23 | uint64_t num_sources; 24 | uint64_t num_priorities; 25 | }; 26 | 27 | #define PLIC_HANDLER_BUFFER_LENGTH 11 28 | struct plic_handler { 29 | uint32_t irq_id; 30 | struct irq_descriptor* descriptor; 31 | 32 | struct hash_table_node hash_node; 33 | }; 34 | 35 | 36 | extern struct device_driver plic_driver; 37 | 38 | #endif -------------------------------------------------------------------------------- /doc/lab_guidance/device-tree.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | - [ ] 中断 4 | - [ ] 地址映射 5 | 6 | # 目的 7 | 8 | 提供 *boot program* 和 *client program* 之间统一的借口 9 | 10 | # 格式 11 | 12 | DTB 和 DTS 13 | 14 | # 使用方法 15 | 16 | boot program 探测设备,并将设备表示为设备树,存储到内存中并将指向该内存的指针传递给 client program 17 | 18 | 19 | 20 | # 结构 21 | 22 | 树装结构,每个节点代表一个设备 23 | 24 | # 命名 25 | 26 | `node-name@unit-address` 27 | 28 | > The unit-address must match the first address specified in the 29 | > reg property of the node. If the node has no reg property, the @unit-address must be omitted and the node-name alone 30 | > differentiates the node from other nodes at the same level in the tree. 31 | 32 | 根节点命名为`/`,其他节点根据设备类型,规范推荐了一些名字 33 | 34 | ## 定位 35 | 36 | 可以使用 UNIX 风格路径进行定位:`/node-name-1/node-name-2/node-name-N` 37 | 38 | *phandle* 属性似乎也是一种方法,相当于节点 ID? 39 | 40 | # 属性 41 | 42 | 每个节点中有多个属性-值键值对,标准允许厂商提供非标准的属性,非标准属性需要加上独一无二的前缀来表示该属性是某厂商添加的,如`linux,network-index`。 43 | 44 | ## 属性值 45 | 46 | 值有一下几种类型:------------------ 47 | 48 | 注意,` 2 | 3 | size_t strlen(const char *str) 4 | { 5 | size_t i = 0; 6 | for (; str[i] != '\0'; ++i) 7 | ; 8 | return i; 9 | } 10 | 11 | void *memset(void *src, char ch, size_t cnt) 12 | { 13 | for (size_t i = 0; i < cnt; ++i) 14 | *((char *)src + i) = ch; 15 | return src; 16 | } 17 | 18 | void *memcpy(void *dest, const void *src, size_t n) 19 | { 20 | void *ret = dest; 21 | while (n--) { 22 | /* 23 | * ++ 和 (type) 运算符优先级相同,从右往左结合, 24 | * 因此修改的是指针,而不是转型创建的临时值。 25 | */ 26 | *((char *)dest++) = *((char *)src++); 27 | } 28 | return ret; 29 | } 30 | 31 | int64_t strcmp(const char *s, const char *t) 32 | { 33 | while (*s && *t && *s == *t) { 34 | s++; 35 | t++; 36 | } 37 | return *s - *t; 38 | } 39 | 40 | const char *strchr (const char *str, char c) 41 | { 42 | while(*str) { 43 | if (*str == c) return str; 44 | str++; 45 | } 46 | return NULL; 47 | } 48 | -------------------------------------------------------------------------------- /os/lab2/trap/clock.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file clock.c 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 实现时钟中断 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /** 时钟中断发生次数 */ 12 | volatile size_t ticks; 13 | 14 | /** 每隔 timebase 次时钟周期发生一次时钟中断 */ 15 | static uint64_t timebase; 16 | 17 | /** 18 | * @brief 获取开机后经过的时钟周期数 19 | * @return uint64_t 20 | */ 21 | static inline uint64_t get_cycles() 22 | { 23 | uint64_t n; 24 | __asm__ __volatile__("rdtime %0" : "=r"(n)); 25 | return n; 26 | } 27 | 28 | /** 29 | * @brief 初始化时钟 30 | * 设置时钟响应的频率与开启时钟中断 31 | */ 32 | void clock_init() 33 | { 34 | /* QEMU 的时钟频率为 10MHz,设置timebase = 100000表示时钟中断频率为100Hz */ 35 | timebase = 100000; 36 | ticks = 0; 37 | /* 开启时钟中断(设置CSR_MIE) */ 38 | set_csr(sie, 1 << IRQ_S_TIMER); 39 | clock_set_next_event(); 40 | kputs("Setup Timer!"); 41 | } 42 | 43 | /** 44 | * @brief 设置下一次时钟中断 45 | */ 46 | void clock_set_next_event() 47 | { 48 | sbi_set_timer(get_cycles() + timebase); 49 | } 50 | -------------------------------------------------------------------------------- /os/lab3/trap/clock.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file clock.c 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 实现时钟中断 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /** 时钟中断发生次数 */ 12 | volatile size_t ticks; 13 | 14 | /** 每隔 timebase 次时钟周期发生一次时钟中断 */ 15 | static uint64_t timebase; 16 | 17 | /** 18 | * @brief 获取开机后经过的时钟周期数 19 | * @return uint64_t 20 | */ 21 | static inline uint64_t get_cycles() 22 | { 23 | uint64_t n; 24 | __asm__ __volatile__("rdtime %0" : "=r"(n)); 25 | return n; 26 | } 27 | 28 | /** 29 | * @brief 初始化时钟 30 | * 设置时钟响应的频率与开启时钟中断 31 | */ 32 | void clock_init() 33 | { 34 | /* QEMU 的时钟频率为 10MHz,设置timebase = 100000表示时钟中断频率为100Hz */ 35 | timebase = 100000; 36 | ticks = 0; 37 | /* 开启时钟中断(设置CSR_MIE) */ 38 | set_csr(sie, 1 << IRQ_S_TIMER); 39 | clock_set_next_event(); 40 | kputs("Setup Timer!"); 41 | } 42 | 43 | /** 44 | * @brief 设置下一次时钟中断 45 | */ 46 | void clock_set_next_event() 47 | { 48 | sbi_set_timer(get_cycles() + timebase); 49 | } 50 | -------------------------------------------------------------------------------- /os/lab4/trap/clock.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file clock.c 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 实现时钟中断 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /** 时钟中断发生次数 */ 12 | volatile size_t ticks; 13 | 14 | /** 每隔 timebase 次时钟周期发生一次时钟中断 */ 15 | static uint64_t timebase; 16 | 17 | /** 18 | * @brief 获取开机后经过的时钟周期数 19 | * @return uint64_t 20 | */ 21 | static inline uint64_t get_cycles() 22 | { 23 | uint64_t n; 24 | __asm__ __volatile__("rdtime %0" : "=r"(n)); 25 | return n; 26 | } 27 | 28 | /** 29 | * @brief 初始化时钟 30 | * 设置时钟响应的频率与开启时钟中断 31 | */ 32 | void clock_init() 33 | { 34 | /* QEMU 的时钟频率为 10MHz,设置timebase = 100000表示时钟中断频率为100Hz */ 35 | timebase = 100000; 36 | ticks = 0; 37 | /* 开启时钟中断(设置CSR_MIE) */ 38 | set_csr(sie, 1 << IRQ_S_TIMER); 39 | clock_set_next_event(); 40 | kputs("Setup Timer!"); 41 | } 42 | 43 | /** 44 | * @brief 设置下一次时钟中断 45 | */ 46 | void clock_set_next_event() 47 | { 48 | sbi_set_timer(get_cycles() + timebase); 49 | } 50 | -------------------------------------------------------------------------------- /os/lab5/kernel/clock.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file clock.c 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 实现时钟中断 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /** 时钟中断发生次数 */ 12 | volatile size_t ticks; 13 | 14 | /** 每隔 timebase 次时钟周期发生一次时钟中断 */ 15 | static uint64_t timebase; 16 | 17 | /** 18 | * @brief 获取开机后经过的时钟周期数 19 | * @return uint64_t 20 | */ 21 | static inline uint64_t get_cycles() 22 | { 23 | uint64_t n; 24 | __asm__ __volatile__("rdtime %0" : "=r"(n)); 25 | return n; 26 | } 27 | 28 | /** 29 | * @brief 初始化时钟 30 | * 设置时钟响应的频率与开启时钟中断 31 | */ 32 | void clock_init() 33 | { 34 | /* QEMU 的时钟频率为 10MHz,设置timebase = 100000表示时钟中断频率为100Hz */ 35 | timebase = 100000; 36 | ticks = 0; 37 | /* 开启时钟中断(设置CSR_MIE) */ 38 | set_csr(sie, 1 << IRQ_S_TIMER); 39 | clock_set_next_event(); 40 | kputs("Setup Timer!"); 41 | } 42 | 43 | /** 44 | * @brief 设置下一次时钟中断 45 | */ 46 | void clock_set_next_event() 47 | { 48 | sbi_set_timer(get_cycles() + timebase); 49 | } 50 | -------------------------------------------------------------------------------- /os/lab6/kernel/clock.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file clock.c 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 实现时钟中断 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /** 时钟中断发生次数 */ 12 | volatile size_t ticks; 13 | 14 | /** 每隔 timebase 次时钟周期发生一次时钟中断 */ 15 | static uint64_t timebase; 16 | 17 | /** 18 | * @brief 获取开机后经过的时钟周期数 19 | * @return uint64_t 20 | */ 21 | static inline uint64_t get_cycles() 22 | { 23 | uint64_t n; 24 | __asm__ __volatile__("rdtime %0" : "=r"(n)); 25 | return n; 26 | } 27 | 28 | /** 29 | * @brief 初始化时钟 30 | * 设置时钟响应的频率与开启时钟中断 31 | */ 32 | void clock_init() 33 | { 34 | /* QEMU 的时钟频率为 10MHz,设置timebase = 100000表示时钟中断频率为100Hz */ 35 | timebase = 100000; 36 | ticks = 0; 37 | /* 开启时钟中断(设置CSR_MIE) */ 38 | set_csr(sie, 1 << IRQ_S_TIMER); 39 | clock_set_next_event(); 40 | kputs("Setup Timer!"); 41 | } 42 | 43 | /** 44 | * @brief 设置下一次时钟中断 45 | */ 46 | void clock_set_next_event() 47 | { 48 | sbi_set_timer(get_cycles() + timebase); 49 | } 50 | -------------------------------------------------------------------------------- /os/lab6/include/stddef.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 本文件定义常用数据类型 3 | */ 4 | #ifndef __STDDEF_H__ 5 | #define __STDDEF_H__ 6 | 7 | #define NULL (void *)0 8 | typedef signed int int32_t; 9 | typedef unsigned int uint32_t; 10 | typedef signed long long int64_t; 11 | typedef unsigned long long uint64_t; 12 | typedef unsigned short uint16_t; 13 | typedef short int16_t; 14 | typedef unsigned char uint8_t; 15 | typedef signed char int8_t; 16 | typedef unsigned long long size_t; 17 | typedef signed long long ssize_t; 18 | /** 19 | * 不要使用 intptr_t, uintptr_t,请用 int64_t, uint64_t 代替 20 | * typedef int64_t intptr_t; 21 | * typedef uint64_t uintptr_t; 22 | */ 23 | 24 | #define typeof __typeof__ 25 | #ifdef __compiler_offsetof 26 | #define offsetof(type, member) __compiler_offsetof(type, member) 27 | #else 28 | #define offsetof(type, member) ((uint64_t) & ((type *)0)->member) 29 | #endif 30 | #define container_of(ptr, type, member) \ 31 | ({ \ 32 | const typeof(((type *)0)->member) *_mptr = (ptr); \ 33 | (type *)((char *)_mptr - offsetof(type, member)); \ 34 | }) 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /os/lab6/include/device/virtio/virtio_net.h: -------------------------------------------------------------------------------- 1 | #ifndef VIRTIO_NET_H 2 | #define VIRTIO_NET_H 3 | 4 | #include 5 | 6 | #define VIRTIO_NET_F_MAC (1 << 5) 7 | 8 | #define VIRTIO_NET_CONFIG_OFFSET 0x100 9 | struct virtio_net_config { 10 | uint8_t mac[6]; 11 | uint16_t status; 12 | uint16_t max_virtqueue_pairs; 13 | uint16_t mtu; 14 | }; 15 | 16 | #define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 17 | #define VIRTIO_NET_HDR_F_DATA_VALID 2 18 | #define VIRTIO_NET_HDR_F_RSC_INFO 4 19 | 20 | #define VIRTIO_NET_HDR_GSO_NONE 0 21 | #define VIRTIO_NET_HDR_GSO_TCPV4 1 22 | #define VIRTIO_NET_HDR_GSO_UDP 3 23 | #define VIRTIO_NET_HDR_GSO_TCPV6 4 24 | #define VIRTIO_NET_HDR_GSO_ECN 0x80 25 | 26 | struct virtio_net_header { 27 | uint8_t flags; 28 | uint8_t gso_type; 29 | uint16_t hdr_len; 30 | uint16_t gso_size; 31 | uint16_t csum_start; 32 | uint16_t csum_offset; 33 | }; 34 | 35 | void virtio_net_init(struct virtio_device *device, uint64_t is_legacy); 36 | void virtio_net_test(struct virtio_device *device); 37 | 38 | #endif /* VIRTIO_NET_H */ 39 | -------------------------------------------------------------------------------- /os/lab3/trap/uart.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void uart_init() 5 | { 6 | volatile uint8_t *base = (uint8_t *)UART_START_ADDR; 7 | *(base + UART_LCR) = 0b11; /* 8bits char */ 8 | *(base + UART_FCR) = 1 << 0; /* FIFO Enable */ 9 | *(base + UART_IER) = 1 << 0; /* Enable receiver data interrupt */ 10 | 11 | uint16_t divisor = 592; /* 分频系数 */ 12 | uint8_t divisor_least = divisor & 0xFF; 13 | uint8_t divisor_most = divisor >> 8; 14 | uint8_t lcr = *(base + UART_LCR); 15 | *(base + UART_LCR) = lcr | 1 << 7; /* set LCR_DLAB to access divisor latch */ 16 | *(base + UART_DLL) = divisor_least; 17 | *(base + UART_DLM) = divisor_most; 18 | *(base + UART_LCR) = lcr; /* back to normal */ 19 | } 20 | 21 | int8_t uart_read() 22 | { 23 | volatile int8_t *base = (int8_t *)UART_START_ADDR; 24 | if ((*(base + UART_LSR) & 1) == 0) { 25 | return -1; 26 | } else { 27 | return *(base + UART_THR); 28 | } 29 | } 30 | 31 | void uart_write(int8_t c) 32 | { 33 | volatile int8_t *base = (int8_t *)UART_START_ADDR; 34 | *(base + UART_THR) = c; 35 | } -------------------------------------------------------------------------------- /os/lab4/trap/uart.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void uart_init() 5 | { 6 | volatile uint8_t *base = (uint8_t *)UART_START_ADDR; 7 | *(base + UART_LCR) = 0b11; /* 8bits char */ 8 | *(base + UART_FCR) = 1 << 0; /* FIFO Enable */ 9 | *(base + UART_IER) = 1 << 0; /* Enable receiver data interrupt */ 10 | 11 | uint16_t divisor = 592; /* 分频系数 */ 12 | uint8_t divisor_least = divisor & 0xFF; 13 | uint8_t divisor_most = divisor >> 8; 14 | uint8_t lcr = *(base + UART_LCR); 15 | *(base + UART_LCR) = lcr | 1 << 7; /* set LCR_DLAB to access divisor latch */ 16 | *(base + UART_DLL) = divisor_least; 17 | *(base + UART_DLM) = divisor_most; 18 | *(base + UART_LCR) = lcr; /* back to normal */ 19 | } 20 | 21 | int8_t uart_read() 22 | { 23 | volatile int8_t *base = (int8_t *)UART_START_ADDR; 24 | if ((*(base + UART_LSR) & 1) == 0) { 25 | return -1; 26 | } else { 27 | return *(base + UART_THR); 28 | } 29 | } 30 | 31 | void uart_write(int8_t c) 32 | { 33 | volatile int8_t *base = (int8_t *)UART_START_ADDR; 34 | *(base + UART_THR) = c; 35 | } -------------------------------------------------------------------------------- /os/lab5/kernel/uart.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void uart_init() 5 | { 6 | volatile uint8_t *base = (uint8_t *)UART_START_ADDR; 7 | *(base + UART_LCR) = 0b11; /* 8bits char */ 8 | *(base + UART_FCR) = 1 << 0; /* FIFO Enable */ 9 | *(base + UART_IER) = 1 << 0; /* Enable receiver data interrupt */ 10 | 11 | uint16_t divisor = 592; /* 分频系数 */ 12 | uint8_t divisor_least = divisor & 0xFF; 13 | uint8_t divisor_most = divisor >> 8; 14 | uint8_t lcr = *(base + UART_LCR); 15 | *(base + UART_LCR) = lcr | 1 << 7; /* set LCR_DLAB to access divisor latch */ 16 | *(base + UART_DLL) = divisor_least; 17 | *(base + UART_DLM) = divisor_most; 18 | *(base + UART_LCR) = lcr; /* back to normal */ 19 | } 20 | 21 | int8_t uart_read() 22 | { 23 | volatile int8_t *base = (int8_t *)UART_START_ADDR; 24 | if ((*(base + UART_LSR) & 1) == 0) { 25 | return -1; 26 | } else { 27 | return *(base + UART_THR); 28 | } 29 | } 30 | 31 | void uart_write(int8_t c) 32 | { 33 | volatile int8_t *base = (int8_t *)UART_START_ADDR; 34 | *(base + UART_THR) = c; 35 | } -------------------------------------------------------------------------------- /os/lab2/init/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(void *nothing, const void *dtb_start) 12 | { 13 | kputs("\nLZU OS STARTING...................."); 14 | print_system_infomation(); 15 | kputs("Hello LZU OS"); 16 | 17 | set_stvec(); 18 | clock_init(); 19 | kprintf("complete timer init\n"); 20 | //dtb_start = (const void *)0x82200000; 21 | unflatten_device_tree(dtb_start); 22 | 23 | plic_init(); 24 | kprintf("complete plic init\n"); 25 | uart_init(); 26 | kprintf("complete uart init\n"); 27 | 28 | rtc_init(); 29 | kprintf("timestamp now: %u\n", read_time()); 30 | set_alarm(read_time() + 1000000000); 31 | kprintf("alarm time: %u\n", read_alarm()); 32 | 33 | enable_interrupt(); // 启用 interrupt,sstatus的SSTATUS_SIE位置1 34 | 35 | __asm__ __volatile__("ebreak \n\t"); 36 | 37 | kputs("SYSTEM END"); 38 | 39 | while (1) 40 | ; /* infinite loop */ 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /os/lab2/include/rtc.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTC_H__ 2 | #define __RTC_H__ 3 | #include 4 | 5 | // 所有时间都以纳秒级时间戳表示 6 | 7 | struct rtc_class_ops { 8 | //int (*ioctl)(struct device *, unsigned int, unsigned long); 9 | uint64_t (*read_time)(); 10 | void (*set_time)(uint64_t now); 11 | uint64_t (*read_alarm)(); 12 | void (*set_alarm)(uint64_t alarm); 13 | void (*rtc_interrupt_handler)(); 14 | void (*clear_alarm)(); 15 | //int (*proc)(struct device *, struct seq_file *); 16 | //int (*alarm_irq_enable)(struct device *, unsigned int enabled); 17 | //int (*read_offset)(struct device *, long *offset); 18 | //int (*set_offset)(struct device *, long offset); 19 | }; 20 | struct rtc_class_device { 21 | uint32_t id; 22 | struct rtc_class_ops ops; 23 | }; 24 | 25 | enum rtc_device_type { 26 | GOLDFISH_RTC = 0, 27 | SUNXI_RTC = 1, 28 | }; 29 | 30 | uint64_t read_time(); 31 | void set_time(uint64_t now); 32 | uint64_t read_alarm(); 33 | void set_alarm(uint64_t alarm); 34 | void rtc_interrupt_handler(); 35 | void clear_alarm(); 36 | void rtc_init(); 37 | 38 | void goldfish_rtc_init(); 39 | void sunxi_rtc_init(); 40 | #endif /* end of include guard: __RTC_H__ */ 41 | -------------------------------------------------------------------------------- /setup_openeuler.sh: -------------------------------------------------------------------------------- 1 | sudo dnf install g++ ncurses-devel python3-devel ninja-build texinfo git 2 | sudo dnf install autoconf automake python3 libmpc-devel mpfr-devel gmp-devel gawk bison flex texinfo patchutils gcc gcc-c++ zlib-devel expat-devel 3 | 4 | wget https://download.qemu.org/qemu-6.0.0.tar.xz 5 | wget https://mirror.lzu.edu.cn/gnu/gdb/gdb-10.2.tar.xz 6 | 7 | tar xJf qemu-6.0.0.tar.xz 8 | tar xJf gdb-10.2.tar.xz 9 | 10 | git clone https://github.com/riscv/riscv-gnu-toolchain 11 | cd riscv-gnu-toolchain 12 | ./configure --prefix=/opt/riscv 13 | sudo make -j$(nproc) 14 | echo 'PATH=$PATH:/opt/riscv/bin' >> ~/.bashrc 15 | 16 | cd qemu-6.0.0 17 | echo -e "\033[41;37m 开始编译安装 QEMU \033[0m" 18 | ./configure --target-list=riscv32-softmmu,riscv64-softmmu --enable-gtk 19 | make -j$(nproc) 20 | sudo make install 21 | 22 | echo -e "\033[41;37m 开始编译安装 GDB \033[0m" 23 | cd ../gdb-10.2/ 24 | ./configure --target=riscv64-unknown-elf --enable-tui=yes -with-python=python3 25 | make -j$(nproc) 26 | sudo make install 27 | 28 | echo -e "\033[41;37m GDB安装完成,版本信息: \033[0m" 29 | riscv64-unknown-elf-gdb -v 30 | echo -e "\033[41;37m QEMU安装完成,版本信息: \033[0m" 31 | qemu-system-riscv64 --version 32 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | echo -e "\033[41;37m 正在安装必要软件包 \033[0m" 2 | sudo apt update 3 | sudo apt install -y build-essential gettext pkg-config libgmp-dev libglib2.0-dev python3-dev libpixman-1-dev binutils libgtk-3-dev texinfo make gcc-riscv64-linux-gnu libncurses5-dev ninja-build tmux axel git 4 | echo -e "\033[41;37m 正在下载必要源码包 \033[0m" 5 | mkdir resource 6 | cd resource 7 | axel -n 15 https://download.qemu.org/qemu-6.2.0.tar.xz 8 | axel -n 15 https://mirror.lzu.edu.cn/gnu/gdb/gdb-11.2.tar.xz 9 | echo -e "\033[41;37m 正在解压 \033[0m" 10 | tar xJf qemu-6.2.0.tar.xz 11 | tar xJf gdb-11.2.tar.xz 12 | echo -e "\033[41;37m 解压完成 \033[0m" 13 | cd qemu-6.2.0 14 | echo -e "\033[41;37m 开始编译安装 QEMU \033[0m" 15 | ./configure --target-list=riscv32-softmmu,riscv64-softmmu --enable-gtk 16 | make -j$(nproc) 17 | sudo make install 18 | echo -e "\033[41;37m 开始编译安装 GDB \033[0m" 19 | cd ../gdb-11.2/ 20 | ./configure --target=riscv64-unknown-elf --enable-tui=yes -with-python=python3 21 | make -j$(nproc) 22 | sudo make install 23 | echo -e "\033[41;37m GDB安装完成,版本信息: \033[0m" 24 | riscv64-unknown-elf-gdb -v 25 | echo -e "\033[41;37m QEMU安装完成,版本信息: \033[0m" 26 | qemu-system-riscv64 --version 27 | echo -e "\033[41;37m 清理安装文件 \033[0m" 28 | cd ../.. 29 | rm -rf resource 30 | -------------------------------------------------------------------------------- /os/lab1/linker.ld: -------------------------------------------------------------------------------- 1 | /* 有关 Linker Script 可以参考:https://sourceware.org/binutils/docs/ld/Scripts.html */ 2 | 3 | /* 目标架构 */ 4 | OUTPUT_ARCH(riscv) 5 | 6 | /* 起始地址 */ 7 | BASE_ADDRESS = 0x80200000; 8 | 9 | SECTIONS 10 | { 11 | /* . 表示当前地址(location counter) */ 12 | . = ALIGN(4K); 13 | . = BASE_ADDRESS; 14 | 15 | /* start 符号表示全部的开始位置 */ 16 | kernel_start = .; 17 | 18 | text_start = .; 19 | 20 | /* .text 字段 */ 21 | .text : { 22 | /* 把 entry 函数放在最前面 */ 23 | *(.text.entry) 24 | /* 要链接的文件的 .text 字段集中放在这里 */ 25 | *(.text .text.*) 26 | } 27 | 28 | . = ALIGN(4K); 29 | rodata_start = .; 30 | 31 | /* .rodata 字段 */ 32 | .rodata : { 33 | /* 要链接的文件的 .rodata 字段集中放在这里 */ 34 | *(.rodata .rodata.*) 35 | } 36 | 37 | . = ALIGN(4K); 38 | data_start = .; 39 | 40 | /* .data 字段 */ 41 | .data : { 42 | /* 要链接的文件的 .data 字段集中放在这里 */ 43 | *(.data .data.*) 44 | } 45 | 46 | . = ALIGN(4K); 47 | bss_start = .; 48 | 49 | /* .bss 字段 */ 50 | .bss : { 51 | /* 要链接的文件的 .bss 字段集中放在这里 */ 52 | *(.sbss .bss .bss.*) 53 | } 54 | 55 | . = ALIGN(4K); 56 | /* 结束地址 */ 57 | kernel_end = .; 58 | } 59 | -------------------------------------------------------------------------------- /os/lab2/tools/linker.ld: -------------------------------------------------------------------------------- 1 | /* 有关 Linker Script 可以参考:https://sourceware.org/binutils/docs/ld/Scripts.html */ 2 | 3 | /* 目标架构 */ 4 | OUTPUT_ARCH(riscv) 5 | 6 | /* 起始地址 */ 7 | BASE_ADDRESS = 0x80200000; 8 | 9 | SECTIONS 10 | { 11 | /* . 表示当前地址(location counter) */ 12 | . = ALIGN(4K); 13 | . = BASE_ADDRESS; 14 | 15 | /* start 符号表示全部的开始位置 */ 16 | kernel_start = .; 17 | 18 | text_start = .; 19 | 20 | /* .text 字段 */ 21 | .text : { 22 | /* 把 entry 函数放在最前面 */ 23 | *(.text.entry) 24 | /* 要链接的文件的 .text 字段集中放在这里 */ 25 | *(.text .text.*) 26 | } 27 | 28 | . = ALIGN(4K); 29 | rodata_start = .; 30 | 31 | /* .rodata 字段 */ 32 | .rodata : { 33 | /* 要链接的文件的 .rodata 字段集中放在这里 */ 34 | *(.rodata .rodata.*) 35 | } 36 | 37 | . = ALIGN(4K); 38 | data_start = .; 39 | 40 | /* .data 字段 */ 41 | .data : { 42 | /* 要链接的文件的 .data 字段集中放在这里 */ 43 | *(.data .data.*) 44 | } 45 | 46 | . = ALIGN(4K); 47 | bss_start = .; 48 | 49 | /* .bss 字段 */ 50 | .bss : { 51 | /* 要链接的文件的 .bss 字段集中放在这里 */ 52 | *(.sbss .bss .bss.*) 53 | } 54 | 55 | . = ALIGN(4K); 56 | /* 结束地址 */ 57 | kernel_end = .; 58 | } 59 | -------------------------------------------------------------------------------- /os/lab3/tools/linker.ld: -------------------------------------------------------------------------------- 1 | /* 有关 Linker Script 可以参考:https://sourceware.org/binutils/docs/ld/Scripts.html */ 2 | 3 | /* 目标架构 */ 4 | OUTPUT_ARCH(riscv) 5 | 6 | /* 起始地址 */ 7 | BASE_ADDRESS = 0x80200000; 8 | 9 | SECTIONS 10 | { 11 | /* . 表示当前地址(location counter) */ 12 | . = ALIGN(4K); 13 | . = BASE_ADDRESS; 14 | 15 | /* start 符号表示全部的开始位置 */ 16 | kernel_start = .; 17 | 18 | text_start = .; 19 | 20 | /* .text 字段 */ 21 | .text : { 22 | /* 把 entry 函数放在最前面 */ 23 | *(.text.entry) 24 | /* 要链接的文件的 .text 字段集中放在这里 */ 25 | *(.text .text.*) 26 | } 27 | 28 | . = ALIGN(4K); 29 | rodata_start = .; 30 | 31 | /* .rodata 字段 */ 32 | .rodata : { 33 | /* 要链接的文件的 .rodata 字段集中放在这里 */ 34 | *(.rodata .rodata.*) 35 | } 36 | 37 | . = ALIGN(4K); 38 | data_start = .; 39 | 40 | /* .data 字段 */ 41 | .data : { 42 | /* 要链接的文件的 .data 字段集中放在这里 */ 43 | *(.data .data.*) 44 | } 45 | 46 | . = ALIGN(4K); 47 | bss_start = .; 48 | 49 | /* .bss 字段 */ 50 | .bss : { 51 | /* 要链接的文件的 .bss 字段集中放在这里 */ 52 | *(.sbss .bss .bss.*) 53 | } 54 | 55 | . = ALIGN(4K); 56 | /* 结束地址 */ 57 | kernel_end = .; 58 | } 59 | -------------------------------------------------------------------------------- /os/lab4/tools/linker.ld: -------------------------------------------------------------------------------- 1 | /* 有关 Linker Script 可以参考:https://sourceware.org/binutils/docs/ld/Scripts.html */ 2 | 3 | /* 目标架构 */ 4 | OUTPUT_ARCH(riscv) 5 | 6 | /* 起始地址 */ 7 | BASE_ADDRESS = 0xc0200000; 8 | 9 | SECTIONS 10 | { 11 | /* . 表示当前地址(location counter) */ 12 | . = ALIGN(4K); 13 | . = BASE_ADDRESS; 14 | 15 | /* start 符号表示全部的开始位置 */ 16 | kernel_start = .; 17 | 18 | text_start = .; 19 | 20 | /* .text 字段 */ 21 | .text : { 22 | /* 把 entry 函数放在最前面 */ 23 | *(.text.entry) 24 | /* 要链接的文件的 .text 字段集中放在这里 */ 25 | *(.text .text.*) 26 | } 27 | 28 | . = ALIGN(4K); 29 | rodata_start = .; 30 | 31 | /* .rodata 字段 */ 32 | .rodata : { 33 | /* 要链接的文件的 .rodata 字段集中放在这里 */ 34 | *(.rodata .rodata.*) 35 | } 36 | 37 | . = ALIGN(4K); 38 | data_start = .; 39 | 40 | /* .data 字段 */ 41 | .data : { 42 | /* 要链接的文件的 .data 字段集中放在这里 */ 43 | *(.data .data.*) 44 | } 45 | 46 | . = ALIGN(4K); 47 | bss_start = .; 48 | 49 | /* .bss 字段 */ 50 | .bss : { 51 | /* 要链接的文件的 .bss 字段集中放在这里 */ 52 | *(.sbss .bss .bss.*) 53 | } 54 | 55 | . = ALIGN(4K); 56 | /* 结束地址 */ 57 | kernel_end = .; 58 | } 59 | -------------------------------------------------------------------------------- /os/lab5/tools/linker.ld: -------------------------------------------------------------------------------- 1 | /* 有关 Linker Script 可以参考:https://sourceware.org/binutils/docs/ld/Scripts.html */ 2 | 3 | /* 目标架构 */ 4 | OUTPUT_ARCH(riscv) 5 | 6 | /* 起始地址 */ 7 | BASE_ADDRESS = 0xc0200000; 8 | 9 | SECTIONS 10 | { 11 | /* . 表示当前地址(location counter) */ 12 | . = ALIGN(4K); 13 | . = BASE_ADDRESS; 14 | 15 | /* start 符号表示全部的开始位置 */ 16 | kernel_start = .; 17 | 18 | text_start = .; 19 | 20 | /* .text 字段 */ 21 | .text : { 22 | /* 把 entry 函数放在最前面 */ 23 | *(.text.entry) 24 | /* 要链接的文件的 .text 字段集中放在这里 */ 25 | *(.text .text.*) 26 | } 27 | 28 | . = ALIGN(4K); 29 | rodata_start = .; 30 | 31 | /* .rodata 字段 */ 32 | .rodata : { 33 | /* 要链接的文件的 .rodata 字段集中放在这里 */ 34 | *(.rodata .rodata.*) 35 | } 36 | 37 | . = ALIGN(4K); 38 | data_start = .; 39 | 40 | /* .data 字段 */ 41 | .data : { 42 | /* 要链接的文件的 .data 字段集中放在这里 */ 43 | *(.data .data.*) 44 | } 45 | 46 | . = ALIGN(4K); 47 | bss_start = .; 48 | 49 | /* .bss 字段 */ 50 | .bss : { 51 | /* 要链接的文件的 .bss 字段集中放在这里 */ 52 | *(.sbss .bss .bss.*) 53 | } 54 | 55 | . = ALIGN(4K); 56 | /* 结束地址 */ 57 | kernel_end = .; 58 | } 59 | -------------------------------------------------------------------------------- /os/lab6/tools/linker.ld: -------------------------------------------------------------------------------- 1 | /* 有关 Linker Script 可以参考:https://sourceware.org/binutils/docs/ld/Scripts.html */ 2 | 3 | /* 目标架构 */ 4 | OUTPUT_ARCH(riscv) 5 | 6 | /* 起始地址 */ 7 | BASE_ADDRESS = 0xc0200000; 8 | 9 | SECTIONS 10 | { 11 | /* . 表示当前地址(location counter) */ 12 | . = ALIGN(4K); 13 | . = BASE_ADDRESS; 14 | 15 | /* start 符号表示全部的开始位置 */ 16 | kernel_start = .; 17 | 18 | text_start = .; 19 | 20 | /* .text 字段 */ 21 | .text : { 22 | /* 把 entry 函数放在最前面 */ 23 | *(.text.entry) 24 | /* 要链接的文件的 .text 字段集中放在这里 */ 25 | *(.text .text.*) 26 | } 27 | 28 | . = ALIGN(4K); 29 | rodata_start = .; 30 | 31 | /* .rodata 字段 */ 32 | .rodata : { 33 | /* 要链接的文件的 .rodata 字段集中放在这里 */ 34 | *(.rodata .rodata.*) 35 | } 36 | 37 | . = ALIGN(4K); 38 | data_start = .; 39 | 40 | /* .data 字段 */ 41 | .data : { 42 | /* 要链接的文件的 .data 字段集中放在这里 */ 43 | *(.data .data.*) 44 | } 45 | 46 | . = ALIGN(4K); 47 | bss_start = .; 48 | 49 | /* .bss 字段 */ 50 | .bss : { 51 | /* 要链接的文件的 .bss 字段集中放在这里 */ 52 | *(.sbss .bss .bss.*) 53 | } 54 | 55 | . = ALIGN(4K); 56 | /* 结束地址 */ 57 | kernel_end = .; 58 | } 59 | -------------------------------------------------------------------------------- /os/lab3/include/plic.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file plic.h 3 | * @brief 所有和 PLIC(Platform Level Interrupt Controller) 有关的声明 4 | */ 5 | #ifndef __PLIC_H__ 6 | #define __PLIC_H__ 7 | #include 8 | 9 | /// @{ @name PLIC 内存映射 IO 地址 10 | /** PLIC 的内存映射为 [0x0c000000, 0x1000_0000), 仅使用 hart 0 相关的 PLIC */ 11 | #define PLIC_START 0x0c000000 /**< PLIC 起始物理地址 */ 12 | #define PLIC_LENGTH 0x04000000 /**< PLIC MMIO 内存大小 */ 13 | #define PLIC_END PLIC_START + PLIC_LENGTH /**< PLIC 结束物理地址 */ 14 | #define PLIC_START_ADDR PLIC_START /**< PLIC 起始地址(为虚拟分页预留) */ 15 | /// @} 16 | 17 | /// @{ @name PLIC 偏移 18 | #define PLIC_PRIORITY 0x0000000 /**< 设置中断优先级 */ 19 | #define PLIC_PENDING 0x00001000 /**< 待处理的中断位图 */ 20 | #define PLIC_ENABLE 0x00002080 /**< 使能中断 */ 21 | #define PLIC_THRESHOLD 0x00200000 /**< 发生中断的阈值,当且仅当中断优先级高于此阈值时发生中断 */ 22 | #define PLIC_CLAIM 0x00200004 /**< 获取优先级最高的待处理中断 */ 23 | #define PLIC_COMPLETE 0x00200004 /**< 告知 PLIC 已完成中断处理 */ 24 | /// @} 25 | 26 | void plic_enable_interrupt(uint32_t id); 27 | void plic_set_priority(uint32_t id, uint8_t priority); 28 | void plic_set_threshold(uint8_t threshold); 29 | uint32_t plic_claim(); 30 | void plic_complete(uint32_t id); 31 | void plic_init(); 32 | int plic_is_pending(uint32_t id); 33 | uint64_t plic_pending(); 34 | #endif /* end of include guard: __PLIC_H__ */ 35 | -------------------------------------------------------------------------------- /os/lab6/drivers/virtio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | uint64_t virtio_device_probe(struct device *dev) { 11 | device_init(dev); 12 | struct fdt_header *fdt = device_get_fdt(dev); 13 | struct fdt_node_header * node = device_get_fdt_node(dev); 14 | struct fdt_property *reg = fdt_get_prop(fdt, node, "reg"); 15 | struct driver_resource *mem = (struct driver_resource *)kmalloc(sizeof(struct driver_resource)); 16 | mem->resource_type = DRIVER_RESOURCE_MEM; 17 | mem->resource_start = fdt_get_prop_num_value(reg, 0) << sizeof(fdt32_t); 18 | mem->resource_start += fdt_get_prop_num_value(reg, 1); 19 | mem->resource_end = mem->resource_start; 20 | mem->resource_end += fdt_get_prop_num_value(reg, 2) << sizeof(fdt32_t); 21 | mem->resource_end += fdt_get_prop_num_value(reg, 3); 22 | device_add_resource(dev, mem); 23 | device_set_data(dev, mem); 24 | virtio_mmio_probe(dev); 25 | return 0; 26 | } 27 | 28 | struct driver_match_table virtio_match_table[] = { 29 | { .compatible = "virtio,mmio" }, 30 | { NULL } 31 | }; 32 | 33 | struct device_driver virtio_driver = { 34 | .driver_name = "MaPl VirtIO driver", 35 | .match_table = virtio_match_table, 36 | .device_probe = virtio_device_probe 37 | }; 38 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile.environment: -------------------------------------------------------------------------------- 1 | FROM node:17-alpine AS build-workspace 2 | WORKDIR /home/node/ 3 | COPY gen_workspace.js . 4 | RUN node gen_workspace.js && \ 5 | rm gen_workspace.js && \ 6 | chmod 644 ./* 7 | 8 | FROM ubuntu:20.04 AS build-qemu 9 | WORKDIR /root/ 10 | RUN sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \ 11 | apt-get update && \ 12 | apt-get install -y --no-install-recommends \ 13 | ca-certificates git build-essential python-is-python3 ninja-build pkg-config libglib2.0-dev libpixman-1-dev && \ 14 | apt-get clean && \ 15 | rm -rf /var/lib/apt/lists/* && \ 16 | git clone http://mirrors.tuna.tsinghua.edu.cn/git/qemu.git && \ 17 | cd qemu && \ 18 | git checkout v6.2.0 && \ 19 | ./configure --target-list=riscv32-softmmu,riscv64-softmmu && \ 20 | make 21 | 22 | FROM ubuntu:20.04 23 | WORKDIR /root/ 24 | RUN sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \ 25 | apt-get update && \ 26 | apt-get install -y --no-install-recommends \ 27 | ca-certificates git make gcc-riscv64-unknown-elf gdb-multiarch libpixman-1-0 && \ 28 | apt-get clean && \ 29 | rm -rf /var/lib/apt/lists/* 30 | COPY --from=build-workspace --chown=root:root \ 31 | /home/node/* . 32 | COPY --from=build-qemu --chown=root:root \ 33 | /root/qemu/build/qemu-system-riscv64 /usr/local/bin/ 34 | 35 | CMD [ "bash" ] 36 | -------------------------------------------------------------------------------- /os/lab4/include/plic.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file plic.h 3 | * @brief 所有和 PLIC(Platform Level Interrupt Controller) 有关的声明 4 | */ 5 | #ifndef __PLIC_H__ 6 | #define __PLIC_H__ 7 | #include 8 | #include 9 | 10 | /// @{ @name PLIC 内存映射 IO 地址 11 | /** PLIC 的内存映射为 [0x0c000000, 0x1000_0000), 仅使用 hart 0 相关的 PLIC */ 12 | #define PLIC_START 0x0c000000 /**< PLIC 起始物理地址 */ 13 | #define PLIC_LENGTH 0x04000000 /**< PLIC MMIO 内存大小 */ 14 | #define PLIC_END PLIC_START + PLIC_LENGTH /**< PLIC 结束物理地址 */ 15 | #define PLIC_START_ADDR DEVICE_ADDRESS /**< PLIC 起始虚拟地址 */ 16 | #define PLIC_END_ADDR (PLIC_START_ADDR + PLIC_LENGTH) /**< PLIC 结束虚拟地址 */ 17 | /// @} 18 | 19 | /// @{ @name PLIC 偏移 20 | #define PLIC_PRIORITY 0x0000000 /**< 设置中断优先级 */ 21 | #define PLIC_PENDING 0x00001000 /**< 待处理的中断位图 */ 22 | #define PLIC_ENABLE 0x00002080 /**< 使能中断 */ 23 | #define PLIC_THRESHOLD 0x00200000 /**< 发生中断的阈值,当且仅当中断优先级高于此阈值时发生中断 */ 24 | #define PLIC_CLAIM 0x00200004 /**< 获取优先级最高的待处理中断 */ 25 | #define PLIC_COMPLETE 0x00200004 /**< 告知 PLIC 已完成中断处理 */ 26 | /// @} 27 | 28 | void plic_enable_interrupt(uint32_t id); 29 | void plic_set_priority(uint32_t id, uint8_t priority); 30 | void plic_set_threshold(uint8_t threshold); 31 | uint32_t plic_claim(); 32 | void plic_complete(uint32_t id); 33 | void plic_init(); 34 | int plic_is_pending(uint32_t id); 35 | uint64_t plic_pending(); 36 | #endif /* end of include guard: __PLIC_H__ */ 37 | -------------------------------------------------------------------------------- /os/lab5/include/plic.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file plic.h 3 | * @brief 所有和 PLIC(Platform Level Interrupt Controller) 有关的声明 4 | */ 5 | #ifndef __PLIC_H__ 6 | #define __PLIC_H__ 7 | #include 8 | #include 9 | 10 | /// @{ @name PLIC 内存映射 IO 地址 11 | /** PLIC 的内存映射为 [0x0c000000, 0x1000_0000), 仅使用 hart 0 相关的 PLIC */ 12 | #define PLIC_START 0x0c000000 /**< PLIC 起始物理地址 */ 13 | #define PLIC_LENGTH 0x04000000 /**< PLIC MMIO 内存大小 */ 14 | #define PLIC_END PLIC_START + PLIC_LENGTH /**< PLIC 结束物理地址 */ 15 | #define PLIC_START_ADDR DEVICE_ADDRESS /**< PLIC 起始虚拟地址 */ 16 | #define PLIC_END_ADDR (PLIC_START_ADDR + PLIC_LENGTH) /**< PLIC 结束虚拟地址 */ 17 | /// @} 18 | 19 | /// @{ @name PLIC 偏移 20 | #define PLIC_PRIORITY 0x0000000 /**< 设置中断优先级 */ 21 | #define PLIC_PENDING 0x00001000 /**< 待处理的中断位图 */ 22 | #define PLIC_ENABLE 0x00002080 /**< 使能中断 */ 23 | #define PLIC_THRESHOLD 0x00200000 /**< 发生中断的阈值,当且仅当中断优先级高于此阈值时发生中断 */ 24 | #define PLIC_CLAIM 0x00200004 /**< 获取优先级最高的待处理中断 */ 25 | #define PLIC_COMPLETE 0x00200004 /**< 告知 PLIC 已完成中断处理 */ 26 | /// @} 27 | 28 | void plic_enable_interrupt(uint32_t id); 29 | void plic_set_priority(uint32_t id, uint8_t priority); 30 | void plic_set_threshold(uint8_t threshold); 31 | uint32_t plic_claim(); 32 | void plic_complete(uint32_t id); 33 | void plic_init(); 34 | int plic_is_pending(uint32_t id); 35 | uint64_t plic_pending(); 36 | #endif /* end of include guard: __PLIC_H__ */ 37 | -------------------------------------------------------------------------------- /os/lab3/include/uart.h: -------------------------------------------------------------------------------- 1 | #ifndef __UART_H__ 2 | #define __UART_H__ 3 | #include 4 | 5 | /// @{ @name UART MMIO 地址 6 | /** 7 | * qemu 模拟器包含一个 UART 实例,MMIO 地址分别为 [0x10000000, 0x10000100) 8 | */ 9 | #define UART_START 0x10000000 /**< UART MMIO 起始物理地址 */ 10 | #define UART_LENGTH 0x00000100 /**< UART MMIO 内存大小 */ 11 | #define UART_END (UART_START + UART_LENGTH) /**< UART MMIO 结束物理地址 */ 12 | #define UART_START_ADDR UART_START /**< UART MMIO 起始地址(为虚拟分页预留) */ 13 | /// @} 14 | 15 | /// @{ @name UART 寄存器偏移 16 | #define UART_RBR 0x00 /** Receiver Buffer Register **/ 17 | #define UART_THR 0x00 /** Transmitter Holding Register **/ 18 | #define UART_DLL 0x00 /** Divisor Latch (Least Significant Byte) Register **/ 19 | #define UART_DLM 0x01 /** Divisor Latch (Most Significant Byte) Register **/ 20 | #define UART_IER 0x01 /** Interrupt Enable Register **/ 21 | #define UART_IIR 0x02 /** Interrupt Identification Register **/ 22 | #define UART_FCR 0x02 /** FIFO Control Register **/ 23 | #define UART_LCR 0x03 /** Line Control Register **/ 24 | #define UART_MCR 0x04 /** Modem Control Register **/ 25 | #define UART_LSR 0x05 /** Line Status Register **/ 26 | #define UART_MSR 0x06 /** Modem Status Register **/ 27 | #define UART_SCR 0x07 /** Scratch Register **/ 28 | /// @} 29 | // 30 | void uart_init(); 31 | int8_t uart_read(); 32 | void uart_write(int8_t c); 33 | #endif /* end of include guard: __UART_H__ */ 34 | -------------------------------------------------------------------------------- /os/lab3/include/mm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file mm.h 3 | * @brief 声明内存管理模块的宏、函数、全局变量 4 | */ 5 | #ifndef __MM_H__ 6 | #define __MM_H__ 7 | #include 8 | /// @{ @name 物理内存布局和物理地址操作 9 | #define PAGE_SIZE 4096 10 | #define FLOOR(addr) ((addr) / PAGE_SIZE * PAGE_SIZE)/**< 向下取整到 4K 边界 */ 11 | #define CEIL(addr) \ 12 | (((addr) / PAGE_SIZE + ((addr) % PAGE_SIZE != 0)) * PAGE_SIZE) /**< 向上取整到 4K 边界 */ 13 | #define DEVICE_START 0x10000000 /**< 设备树地址空间,暂时不使用 */ 14 | #define DEVICE_END 0x10010000 15 | #define MEM_START 0x80000000 /**< 物理内存地址空间 */ 16 | #define MEM_END 0x88000000 17 | #define SBI_START 0x80000000 /**< SBI 物理内存起始地址 */ 18 | #define SBI_END 0x80200000 /**< 用户程序(包括内核)可用的物理内存地址空间开始 */ 19 | #define HIGH_MEM 0x88000000 /**< 空闲内存区结束 */ 20 | #define LOW_MEM 0x82000000 /**< 空闲内存区开始(可用于用户进程和数据放置) */ 21 | #define PAGING_MEMORY (1024 * 1024 * 128) /**< 系统物理内存大小 (bytes) */ 22 | #define PAGING_PAGES (PAGING_MEMORY >> 12) /**< 系统物理内存页数 */ 23 | #define MAP_NR(addr) (((addr)-MEM_START) >> 12) /**< 物理地址 addr 在 mem_map[] 中的下标 */ 24 | /// @} 25 | 26 | /// @{ @name 物理页标志位 27 | #define USED 100 28 | #define UNUSED 0 29 | /// @} 30 | 31 | extern unsigned char mem_map[PAGING_PAGES]; /**< 物理内存位图,记录物理内存使用情况 */ 32 | void mem_test(); 33 | void mem_init(); 34 | void free_page(uint64_t addr); 35 | uint64_t get_free_page(void); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /os/lab6/drivers/reset/sifive_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | struct driver_resource sifive_test_mmio_res = { 6 | .resource_start = 0x100000, 7 | .resource_end = 0x101000, 8 | .resource_type = DRIVER_RESOURCE_MEM 9 | }; 10 | 11 | void sifive_test_shutdown(struct device *dev) { 12 | *((uint32_t *)sifive_test_mmio_res.map_address) = 0x5555; 13 | } 14 | 15 | void sifive_test_reboot(struct device *dev) { 16 | *((uint32_t *)sifive_test_mmio_res.map_address) = 0x7777; 17 | } 18 | 19 | struct reset_device sifive_test_device = { 20 | .shutdown = sifive_test_shutdown, 21 | .reboot = sifive_test_reboot 22 | }; 23 | 24 | void * sifive_test_get_interface(struct device *dev, uint64_t flag) { 25 | if(flag & RESET_INTERFACE_BIT) return &sifive_test_device; 26 | return NULL; 27 | } 28 | 29 | uint64_t test_device_probe(struct device *dev) { 30 | device_init(dev); 31 | device_set_data(dev, NULL); 32 | sifive_test_device.dev = dev; 33 | device_set_interface(dev, RESET_INTERFACE_BIT, sifive_test_get_interface); 34 | device_register(dev, "sifive test", SIFIVE_TEST_MAJOR, NULL); 35 | device_add_resource(dev, &sifive_test_mmio_res); 36 | return 0; 37 | } 38 | 39 | struct driver_match_table test_match_table[] = { 40 | { .compatible = "sifive,test1" }, 41 | { NULL } 42 | }; 43 | 44 | struct device_driver test_driver = { 45 | .driver_name = "MaPl SiFive test driver", 46 | .match_table = &test_match_table[0], 47 | .device_probe = test_device_probe 48 | }; 49 | -------------------------------------------------------------------------------- /os/lab3/include/assert.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file assert.h 3 | * 本文件实现 assert() 和 panic() 4 | */ 5 | #ifndef __ASSERT_H__ 6 | #define __ASSERT_H__ 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define GET_ARRAY_CONTENT_IMP(...) __VA_ARGS__ 13 | #define GET_ARRAY_CONTENT(array) "" GET_ARRAY_CONTENT##_IMP array 14 | #define __do_panic(array) do_panic(__FILE__, __LINE__, GET_ARRAY_CONTENT(array)) 15 | 16 | /** 17 | * @brief 终止程序 18 | * 19 | * 这个宏是可变参数宏,可以不加参数地调用(直接终止程序) 20 | * 也可以加参数当成 printf() 使用(终止程序并打印信息)。 21 | * 例子: 22 | * ``` 23 | * panic(); 24 | * panic("Hello young programmer."); 25 | * panic("Correct value: %d", 100); 26 | * ``` 27 | * 28 | * @see printf(), assert() 29 | */ 30 | #define panic(...) __do_panic((__VA_ARGS__)) 31 | 32 | /** 33 | * @brief 断言宏 34 | * 35 | * @param cond 条件表达式 当 cond 为假时,终止程序。 36 | * 37 | * 这个宏是可变参数宏,可以当成 printf() 使用。 38 | * 例子: 39 | * ``` 40 | * assert(i == 100); 41 | * assert(i == 100, "i should be 100"); 42 | * assert(i == 100, "i should be %d", 100); 43 | * ``` 44 | */ 45 | #define assert(cond, ...) \ 46 | do { \ 47 | if (!(cond)) { \ 48 | panic(__VA_ARGS__); \ 49 | } \ 50 | } while (0) 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /os/lab4/include/assert.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file assert.h 3 | * 本文件实现 assert() 和 panic() 4 | */ 5 | #ifndef __ASSERT_H__ 6 | #define __ASSERT_H__ 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define GET_ARRAY_CONTENT_IMP(...) __VA_ARGS__ 13 | #define GET_ARRAY_CONTENT(array) "" GET_ARRAY_CONTENT##_IMP array 14 | #define __do_panic(array) do_panic(__FILE__, __LINE__, GET_ARRAY_CONTENT(array)) 15 | 16 | /** 17 | * @brief 终止程序 18 | * 19 | * 这个宏是可变参数宏,可以不加参数地调用(直接终止程序) 20 | * 也可以加参数当成 printf() 使用(终止程序并打印信息)。 21 | * 例子: 22 | * ``` 23 | * panic(); 24 | * panic("Hello young programmer."); 25 | * panic("Correct value: %d", 100); 26 | * ``` 27 | * 28 | * @see printf(), assert() 29 | */ 30 | #define panic(...) __do_panic((__VA_ARGS__)) 31 | 32 | /** 33 | * @brief 断言宏 34 | * 35 | * @param cond 条件表达式 当 cond 为假时,终止程序。 36 | * 37 | * 这个宏是可变参数宏,可以当成 printf() 使用。 38 | * 例子: 39 | * ``` 40 | * assert(i == 100); 41 | * assert(i == 100, "i should be 100"); 42 | * assert(i == 100, "i should be %d", 100); 43 | * ``` 44 | */ 45 | #define assert(cond, ...) \ 46 | do { \ 47 | if (!(cond)) { \ 48 | panic(__VA_ARGS__); \ 49 | } \ 50 | } while (0) 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /os/lab5/include/assert.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file assert.h 3 | * 本文件实现 assert() 和 panic() 4 | */ 5 | #ifndef __ASSERT_H__ 6 | #define __ASSERT_H__ 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define GET_ARRAY_CONTENT_IMP(...) __VA_ARGS__ 13 | #define GET_ARRAY_CONTENT(array) "" GET_ARRAY_CONTENT##_IMP array 14 | #define __do_panic(array) do_panic(__FILE__, __LINE__, GET_ARRAY_CONTENT(array)) 15 | 16 | /** 17 | * @brief 终止程序 18 | * 19 | * 这个宏是可变参数宏,可以不加参数地调用(直接终止程序) 20 | * 也可以加参数当成 printf() 使用(终止程序并打印信息)。 21 | * 例子: 22 | * ``` 23 | * panic(); 24 | * panic("Hello young programmer."); 25 | * panic("Correct value: %d", 100); 26 | * ``` 27 | * 28 | * @see printf(), assert() 29 | */ 30 | #define panic(...) __do_panic((__VA_ARGS__)) 31 | 32 | /** 33 | * @brief 断言宏 34 | * 35 | * @param cond 条件表达式 当 cond 为假时,终止程序。 36 | * 37 | * 这个宏是可变参数宏,可以当成 printf() 使用。 38 | * 例子: 39 | * ``` 40 | * assert(i == 100); 41 | * assert(i == 100, "i should be 100"); 42 | * assert(i == 100, "i should be %d", 100); 43 | * ``` 44 | */ 45 | #define assert(cond, ...) \ 46 | do { \ 47 | if (!(cond)) { \ 48 | panic(__VA_ARGS__); \ 49 | } \ 50 | } while (0) 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /os/lab6/include/assert.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file assert.h 3 | * 本文件实现 assert() 和 panic() 4 | */ 5 | #ifndef __ASSERT_H__ 6 | #define __ASSERT_H__ 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define GET_ARRAY_CONTENT_IMP(...) __VA_ARGS__ 13 | #define GET_ARRAY_CONTENT(array) "" GET_ARRAY_CONTENT##_IMP array 14 | #define __do_panic(array) do_panic(__FILE__, __LINE__, GET_ARRAY_CONTENT(array)) 15 | 16 | /** 17 | * @brief 终止程序 18 | * 19 | * 这个宏是可变参数宏,可以不加参数地调用(直接终止程序) 20 | * 也可以加参数当成 printf() 使用(终止程序并打印信息)。 21 | * 例子: 22 | * ``` 23 | * panic(); 24 | * panic("Hello young programmer."); 25 | * panic("Correct value: %d", 100); 26 | * ``` 27 | * 28 | * @see printf(), assert() 29 | */ 30 | #define panic(...) __do_panic((__VA_ARGS__)) 31 | 32 | /** 33 | * @brief 断言宏 34 | * 35 | * @param cond 条件表达式 当 cond 为假时,终止程序。 36 | * 37 | * 这个宏是可变参数宏,可以当成 printf() 使用。 38 | * 例子: 39 | * ``` 40 | * assert(i == 100); 41 | * assert(i == 100, "i should be 100"); 42 | * assert(i == 100, "i should be %d", 100); 43 | * ``` 44 | */ 45 | #define assert(cond, ...) \ 46 | do { \ 47 | if (!(cond)) { \ 48 | panic(__VA_ARGS__); \ 49 | } \ 50 | } while (0) 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /os/lab4/include/uart.h: -------------------------------------------------------------------------------- 1 | #ifndef __UART_H__ 2 | #define __UART_H__ 3 | #include 4 | #include 5 | 6 | /// @{ @name UART MMIO 地址 7 | /** 8 | * qemu 模拟器包含一个 UART 实例,MMIO 地址分别为 [0x10000000, 0x10000100) 9 | */ 10 | #define UART_START 0x10000000 /**< UART MMIO 起始物理地址 */ 11 | #define UART_LENGTH 0x00000100 /**< UART MMIO 内存大小 */ 12 | #define UART_END (UART_START + UART_LENGTH) /**< UART MMIO 结束物理地址 */ 13 | #define UART_START_ADDR PLIC_END_ADDR /**< UART MMIO 起始虚拟地址 */ 14 | #define UART_END_ADDR (PLIC_END_ADDR + UART_LENGTH) /**< UART MMIO 结束虚拟地址 */ 15 | /// @} 16 | 17 | /// @{ @name UART 寄存器偏移 18 | #define UART_RBR 0x00 /** Receiver Buffer Register **/ 19 | #define UART_THR 0x00 /** Transmitter Holding Register **/ 20 | #define UART_DLL 0x00 /** Divisor Latch (Least Significant Byte) Register **/ 21 | #define UART_DLM 0x01 /** Divisor Latch (Most Significant Byte) Register **/ 22 | #define UART_IER 0x01 /** Interrupt Enable Register **/ 23 | #define UART_IIR 0x02 /** Interrupt Identification Register **/ 24 | #define UART_FCR 0x02 /** FIFO Control Register **/ 25 | #define UART_LCR 0x03 /** Line Control Register **/ 26 | #define UART_MCR 0x04 /** Modem Control Register **/ 27 | #define UART_LSR 0x05 /** Line Status Register **/ 28 | #define UART_MSR 0x06 /** Modem Status Register **/ 29 | #define UART_SCR 0x07 /** Scratch Register **/ 30 | /// @} 31 | // 32 | void uart_init(); 33 | int8_t uart_read(); 34 | void uart_write(int8_t c); 35 | #endif /* end of include guard: __UART_H__ */ 36 | -------------------------------------------------------------------------------- /os/lab5/include/uart.h: -------------------------------------------------------------------------------- 1 | #ifndef __UART_H__ 2 | #define __UART_H__ 3 | #include 4 | #include 5 | 6 | /// @{ @name UART MMIO 地址 7 | /** 8 | * qemu 模拟器包含一个 UART 实例,MMIO 地址分别为 [0x10000000, 0x10000100) 9 | */ 10 | #define UART_START 0x10000000 /**< UART MMIO 起始物理地址 */ 11 | #define UART_LENGTH 0x00000100 /**< UART MMIO 内存大小 */ 12 | #define UART_END (UART_START + UART_LENGTH) /**< UART MMIO 结束物理地址 */ 13 | #define UART_START_ADDR PLIC_END_ADDR /**< UART MMIO 起始虚拟地址 */ 14 | #define UART_END_ADDR (PLIC_END_ADDR + UART_LENGTH) /**< UART MMIO 结束虚拟地址 */ 15 | /// @} 16 | 17 | /// @{ @name UART 寄存器偏移 18 | #define UART_RBR 0x00 /** Receiver Buffer Register **/ 19 | #define UART_THR 0x00 /** Transmitter Holding Register **/ 20 | #define UART_DLL 0x00 /** Divisor Latch (Least Significant Byte) Register **/ 21 | #define UART_DLM 0x01 /** Divisor Latch (Most Significant Byte) Register **/ 22 | #define UART_IER 0x01 /** Interrupt Enable Register **/ 23 | #define UART_IIR 0x02 /** Interrupt Identification Register **/ 24 | #define UART_FCR 0x02 /** FIFO Control Register **/ 25 | #define UART_LCR 0x03 /** Line Control Register **/ 26 | #define UART_MCR 0x04 /** Modem Control Register **/ 27 | #define UART_LSR 0x05 /** Line Status Register **/ 28 | #define UART_MSR 0x06 /** Modem Status Register **/ 29 | #define UART_SCR 0x07 /** Scratch Register **/ 30 | /// @} 31 | // 32 | void uart_init(); 33 | int8_t uart_read(); 34 | void uart_write(int8_t c); 35 | #endif /* end of include guard: __UART_H__ */ 36 | -------------------------------------------------------------------------------- /os/lab6/include/device/irq.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICE_IRQ_H 2 | #define DEVICE_IRQ_H 3 | 4 | #include 5 | #include 6 | 7 | #define IRQ_INTERFACE_BIT (1 << 11) 8 | 9 | struct irq_descriptor { 10 | const char* name; 11 | struct device *dev; 12 | void (*handler)(struct device *dev); 13 | }; 14 | 15 | /* 初始状态: 不使能任何IRQ, 阈值为最低 */ 16 | struct irq_device { 17 | struct device *dev; 18 | void (*enable_irq)(struct device *dev, uint32_t hart_id, uint32_t irq_id); 19 | void (*disable_irq)(struct device *dev, uint32_t hart_id, uint32_t irq_id); 20 | void (*set_threshold)(struct device *dev, uint32_t hart_id, uint32_t threshold); 21 | void (*set_priority)(struct device *dev, uint32_t irq_id, uint32_t priority); 22 | void (*set_handler)(struct device *dev, uint32_t hart_id, uint32_t irq_id, struct irq_descriptor* descriptor); 23 | void (*interrupt_handle)(struct device *dev); 24 | }; 25 | 26 | extern struct irq_device *g_irq_dev; 27 | static inline void setup_irq_dev(struct device *dev) { 28 | if (dev) { 29 | g_irq_dev = dev->get_interface(dev, IRQ_INTERFACE_BIT); 30 | } 31 | } 32 | static inline struct irq_device *get_irq_device() { 33 | return g_irq_dev; 34 | } 35 | static inline void irq_handle() { 36 | if(g_irq_dev) { 37 | g_irq_dev->interrupt_handle(g_irq_dev->dev); 38 | } 39 | } 40 | static inline void irq_add(uint32_t hart_id, uint32_t irq_id, struct irq_descriptor* descriptor) { 41 | if(g_irq_dev) { 42 | g_irq_dev->set_handler(g_irq_dev->dev, hart_id, irq_id, descriptor); 43 | } 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /os/lab3/include/sbi.h: -------------------------------------------------------------------------------- 1 | #ifndef __SBI_H__ 2 | #define __SBI_H__ 3 | #include 4 | 5 | /** error type */ 6 | #define SBI_SUCCESS 0 7 | #define SBI_ERR_FAILED -1 8 | #define SBI_ERR_NOT_SUPPORTED -2 9 | #define SBI_ERR_INVALID_PARAM -3 10 | #define SBI_ERR_DENIED -4 11 | #define SBI_ERR_INVALID_ADDRESS -5 12 | #define SBI_ERR_ALERADY_AVAILABLE -6 13 | 14 | /** extenstion id */ 15 | #define BASE_EXTENSTION 0x10 16 | #define TIMER_EXTENTION 0x54494D45 17 | #define HART_STATE_EXTENTION 0x48534D 18 | #define RESET_EXTENTION 0x53525354 19 | 20 | /** sbi implementation id */ 21 | 22 | /** we only use OpenSBI */ 23 | #define BERKELY_BOOT_LOADER 0 24 | #define OPENSBI 1 25 | #define XVISOR 2 26 | #define KVM 3 27 | #define RUSTSBI 4 28 | #define DIOSIX 5 29 | 30 | /** sbi ecall return type */ 31 | struct sbiret { 32 | long error; 33 | long value; 34 | }; 35 | 36 | struct sbiret sbi_get_spec_version(); /** get sbi specification version */ 37 | struct sbiret sbi_get_impl_id(); /** get sbi implementation id */ 38 | struct sbiret sbi_get_impl_version(); /** get sbi implementation version */ 39 | struct sbiret sbi_probe_extension(long extension_id); /** probe sbi extenstion */ 40 | void sbi_set_timer(uint64_t stime_value); /** set timer */ 41 | char sbi_console_getchar(); /** read a byte from debug console */ 42 | void sbi_console_putchar(char ch); /** print character to debug console */ 43 | void sbi_shutdown(); /** shutdown */ 44 | void print_system_infomation(); 45 | 46 | #endif -------------------------------------------------------------------------------- /os/lab4/include/sbi.h: -------------------------------------------------------------------------------- 1 | #ifndef __SBI_H__ 2 | #define __SBI_H__ 3 | #include 4 | 5 | /** error type */ 6 | #define SBI_SUCCESS 0 7 | #define SBI_ERR_FAILED -1 8 | #define SBI_ERR_NOT_SUPPORTED -2 9 | #define SBI_ERR_INVALID_PARAM -3 10 | #define SBI_ERR_DENIED -4 11 | #define SBI_ERR_INVALID_ADDRESS -5 12 | #define SBI_ERR_ALERADY_AVAILABLE -6 13 | 14 | /** extenstion id */ 15 | #define BASE_EXTENSTION 0x10 16 | #define TIMER_EXTENTION 0x54494D45 17 | #define HART_STATE_EXTENTION 0x48534D 18 | #define RESET_EXTENTION 0x53525354 19 | 20 | /** sbi implementation id */ 21 | 22 | /** we only use OpenSBI */ 23 | #define BERKELY_BOOT_LOADER 0 24 | #define OPENSBI 1 25 | #define XVISOR 2 26 | #define KVM 3 27 | #define RUSTSBI 4 28 | #define DIOSIX 5 29 | 30 | /** sbi ecall return type */ 31 | struct sbiret { 32 | long error; 33 | long value; 34 | }; 35 | 36 | struct sbiret sbi_get_spec_version(); /** get sbi specification version */ 37 | struct sbiret sbi_get_impl_id(); /** get sbi implementation id */ 38 | struct sbiret sbi_get_impl_version(); /** get sbi implementation version */ 39 | struct sbiret sbi_probe_extension(long extension_id); /** probe sbi extenstion */ 40 | void sbi_set_timer(uint64_t stime_value); /** set timer */ 41 | char sbi_console_getchar(); /** read a byte from debug console */ 42 | void sbi_console_putchar(char ch); /** print character to debug console */ 43 | void sbi_shutdown(); /** shutdown */ 44 | void print_system_infomation(); 45 | 46 | #endif -------------------------------------------------------------------------------- /os/lab5/include/sbi.h: -------------------------------------------------------------------------------- 1 | #ifndef __SBI_H__ 2 | #define __SBI_H__ 3 | #include 4 | 5 | /** error type */ 6 | #define SBI_SUCCESS 0 7 | #define SBI_ERR_FAILED -1 8 | #define SBI_ERR_NOT_SUPPORTED -2 9 | #define SBI_ERR_INVALID_PARAM -3 10 | #define SBI_ERR_DENIED -4 11 | #define SBI_ERR_INVALID_ADDRESS -5 12 | #define SBI_ERR_ALERADY_AVAILABLE -6 13 | 14 | /** extenstion id */ 15 | #define BASE_EXTENSTION 0x10 16 | #define TIMER_EXTENTION 0x54494D45 17 | #define HART_STATE_EXTENTION 0x48534D 18 | #define RESET_EXTENTION 0x53525354 19 | 20 | /** sbi implementation id */ 21 | 22 | /** we only use OpenSBI */ 23 | #define BERKELY_BOOT_LOADER 0 24 | #define OPENSBI 1 25 | #define XVISOR 2 26 | #define KVM 3 27 | #define RUSTSBI 4 28 | #define DIOSIX 5 29 | 30 | /** sbi ecall return type */ 31 | struct sbiret { 32 | long error; 33 | long value; 34 | }; 35 | 36 | struct sbiret sbi_get_spec_version(); /** get sbi specification version */ 37 | struct sbiret sbi_get_impl_id(); /** get sbi implementation id */ 38 | struct sbiret sbi_get_impl_version(); /** get sbi implementation version */ 39 | struct sbiret sbi_probe_extension(long extension_id); /** probe sbi extenstion */ 40 | void sbi_set_timer(uint64_t stime_value); /** set timer */ 41 | char sbi_console_getchar(); /** read a byte from debug console */ 42 | void sbi_console_putchar(char ch); /** print character to debug console */ 43 | void sbi_shutdown(); /** shutdown */ 44 | void print_system_infomation(); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /os/lab6/include/sbi.h: -------------------------------------------------------------------------------- 1 | #ifndef __SBI_H__ 2 | #define __SBI_H__ 3 | #include 4 | 5 | /** error type */ 6 | #define SBI_SUCCESS 0 7 | #define SBI_ERR_FAILED -1 8 | #define SBI_ERR_NOT_SUPPORTED -2 9 | #define SBI_ERR_INVALID_PARAM -3 10 | #define SBI_ERR_DENIED -4 11 | #define SBI_ERR_INVALID_ADDRESS -5 12 | #define SBI_ERR_ALERADY_AVAILABLE -6 13 | 14 | /** extenstion id */ 15 | #define BASE_EXTENSTION 0x10 16 | #define TIMER_EXTENTION 0x54494D45 17 | #define HART_STATE_EXTENTION 0x48534D 18 | #define RESET_EXTENTION 0x53525354 19 | 20 | /** sbi implementation id */ 21 | 22 | /** we only use OpenSBI */ 23 | #define BERKELY_BOOT_LOADER 0 24 | #define OPENSBI 1 25 | #define XVISOR 2 26 | #define KVM 3 27 | #define RUSTSBI 4 28 | #define DIOSIX 5 29 | 30 | /** sbi ecall return type */ 31 | struct sbiret { 32 | long error; 33 | long value; 34 | }; 35 | 36 | struct sbiret sbi_get_spec_version(); /** get sbi specification version */ 37 | struct sbiret sbi_get_impl_id(); /** get sbi implementation id */ 38 | struct sbiret sbi_get_impl_version(); /** get sbi implementation version */ 39 | struct sbiret sbi_probe_extension(long extension_id); /** probe sbi extenstion */ 40 | void sbi_set_timer(uint64_t stime_value); /** set timer */ 41 | char sbi_console_getchar(); /** read a byte from debug console */ 42 | void sbi_console_putchar(char ch); /** print character to debug console */ 43 | void sbi_shutdown(); /** shutdown */ 44 | void print_system_infomation(); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /os/lab2/trap/uart/uart.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct uart_class_device uart_device; 6 | extern struct device_node node[100]; 7 | extern struct property prop[100]; 8 | extern int64_t node_used; 9 | extern int64_t prop_used; 10 | 11 | static uint64_t uart_probe() 12 | { 13 | for (size_t i = 0; i < node_used + 20; i++) { 14 | if (is_begin_with(node[i].name, "uart")) { 15 | for (struct property *prop_ptr = node[i].properties; prop_ptr; prop_ptr = prop_ptr->next) { 16 | if (strcmp(prop_ptr->name, "compatible") == 0) { 17 | if (strcmp(prop_ptr->value, "ns16550a") == 0) { 18 | return UART_QEMU; 19 | } else if (strcmp(prop_ptr->value, "allwinner,sun20i-uart") == 0) { 20 | return UART_SUNXI; 21 | } 22 | } 23 | } 24 | } 25 | } 26 | return -1; 27 | } 28 | 29 | void uart_init() 30 | { 31 | uart_device.id = uart_probe(); 32 | switch (uart_device.id) { 33 | case UART_QEMU: 34 | uart_qemu_init(); 35 | break; 36 | case UART_SUNXI: 37 | uart_sunxi_init(); 38 | break; 39 | } 40 | } 41 | 42 | int8_t uart_read() 43 | { 44 | return (*uart_device.ops.uart_read)(); 45 | } 46 | 47 | void uart_directly_write(int8_t c) 48 | { 49 | (*uart_device.ops.uart_directly_write)(c); 50 | } 51 | 52 | void uart_interrupt_handler() 53 | { 54 | (*uart_device.ops.uart_interrupt_handler)(); 55 | } 56 | 57 | void uart_putc(int8_t c) 58 | { 59 | (*uart_device.ops.uart_putc)(c); 60 | } -------------------------------------------------------------------------------- /os/lab1/sbi.h: -------------------------------------------------------------------------------- 1 | #ifndef __SBI_H__ 2 | #define __SBI_H__ 3 | #include 4 | 5 | /** error type */ 6 | #define SBI_SUCCESS 0 7 | #define SBI_ERR_FAILED -1 8 | #define SBI_ERR_NOT_SUPPORTED -2 9 | #define SBI_ERR_INVALID_PARAM -3 10 | #define SBI_ERR_DENIED -4 11 | #define SBI_ERR_INVALID_ADDRESS -5 12 | #define SBI_ERR_ALERADY_AVAILABLE -6 13 | 14 | /** extenstion id */ 15 | #define BASE_EXTENSTION 0x10 16 | #define TIMER_EXTENTION 0x54494D45 17 | #define HART_STATE_EXTENTION 0x48534D 18 | #define RESET_EXTENTION 0x53525354 19 | 20 | /** sbi implementation id */ 21 | 22 | /** we only use OpenSBI */ 23 | #define BERKELY_BOOT_LOADER 0 24 | #define OPENSBI 1 25 | #define XVISOR 2 26 | #define KVM 3 27 | #define RUSTSBI 4 28 | #define DIOSIX 5 29 | 30 | /** sbi ecall return type */ 31 | struct sbiret { 32 | long error; 33 | long value; 34 | }; 35 | 36 | struct sbiret sbi_get_spec_version(); /** get sbi specification version */ 37 | struct sbiret sbi_get_impl_id(); /** get sbi implementation id */ 38 | struct sbiret sbi_get_impl_version(); /** get sbi implementation version */ 39 | struct sbiret sbi_probe_extension(long extension_id); /** probe sbi extenstion */ 40 | struct sbiret sbi_get_mvendorid(); /** get sbi manufacturer id */ 41 | void sbi_set_timer(uint64_t stime_value); /** set timer */ 42 | char sbi_console_getchar(); /** read a byte from debug console */ 43 | void sbi_console_putchar(char ch); /** print character to debug console */ 44 | void sbi_shutdown(); /** shutdown */ 45 | 46 | #endif -------------------------------------------------------------------------------- /os/lab2/include/sbi.h: -------------------------------------------------------------------------------- 1 | #ifndef __SBI_H__ 2 | #define __SBI_H__ 3 | #include 4 | 5 | /** error type */ 6 | #define SBI_SUCCESS 0 7 | #define SBI_ERR_FAILED -1 8 | #define SBI_ERR_NOT_SUPPORTED -2 9 | #define SBI_ERR_INVALID_PARAM -3 10 | #define SBI_ERR_DENIED -4 11 | #define SBI_ERR_INVALID_ADDRESS -5 12 | #define SBI_ERR_ALERADY_AVAILABLE -6 13 | 14 | /** extenstion id */ 15 | #define BASE_EXTENSTION 0x10 16 | #define TIMER_EXTENTION 0x54494D45 17 | #define HART_STATE_EXTENTION 0x48534D 18 | #define RESET_EXTENTION 0x53525354 19 | 20 | /** sbi implementation id */ 21 | 22 | /** we only use OpenSBI */ 23 | #define BERKELY_BOOT_LOADER 0 24 | #define OPENSBI 1 25 | #define XVISOR 2 26 | #define KVM 3 27 | #define RUSTSBI 4 28 | #define DIOSIX 5 29 | 30 | /** sbi ecall return type */ 31 | struct sbiret { 32 | long error; 33 | long value; 34 | }; 35 | 36 | struct sbiret sbi_get_spec_version(); /** get sbi specification version */ 37 | struct sbiret sbi_get_impl_id(); /** get sbi implementation id */ 38 | struct sbiret sbi_get_impl_version(); /** get sbi implementation version */ 39 | struct sbiret sbi_probe_extension(long extension_id); /** probe sbi extenstion */ 40 | void sbi_set_timer(uint64_t stime_value); /** set timer */ 41 | char sbi_console_getchar(); /** read a byte from debug console */ 42 | void sbi_console_putchar(char ch); /** print character to debug console */ 43 | void sbi_shutdown(); /** shutdown */ 44 | void sbi_reboot(); /** reboot */ 45 | void print_system_infomation(); 46 | 47 | #endif -------------------------------------------------------------------------------- /os/lab6/drivers/drivers_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | uint64_t char_dev_test(uint64_t c) { 8 | struct device *dev = get_dev_by_major_minor(UART8250_MAJOR, 1); 9 | struct serial_device *char_test = dev->get_interface(dev, SERIAL_INTERFACE_BIT); 10 | char_test->request(dev, &c, 1, !c); 11 | return c; 12 | } 13 | 14 | uint64_t reset_dev_test(uint64_t function) { 15 | struct device *dev = get_dev_by_major_minor(SIFIVE_TEST_MAJOR, 1); 16 | struct reset_device *reset_test = dev->get_interface(dev, RESET_INTERFACE_BIT); 17 | #define SHUTDOWN_FUNCTION 0 18 | #define REBOOT_FUNCTION 1 19 | switch (function) 20 | { 21 | case SHUTDOWN_FUNCTION: 22 | reset_test->shutdown(dev); 23 | break; 24 | case REBOOT_FUNCTION: 25 | reset_test->reboot(dev); 26 | break; 27 | default: 28 | break; 29 | } 30 | return 0; 31 | } 32 | 33 | uint64_t block_dev_test() { 34 | struct device *dev = get_dev_by_major_minor(VIRTIO_MAJOR, 1); 35 | struct block_device *block_test = dev->get_interface(dev, BLOCK_INTERFACE_BIT); 36 | char buffer[512]; 37 | struct block_request req = { 38 | .is_read = 1, 39 | .sector = 0, 40 | .buffer = buffer, 41 | .wait_queue = NULL 42 | }; 43 | block_test->request(dev, &req); 44 | for (uint64_t i = 0; i < 16; i += 1) { 45 | if(buffer[i] < 0x10) kprintf("0"); 46 | kprintf("%x ", buffer[i]); 47 | if(i%8 == 7) kprintf(" "); 48 | if(i%16 == 15) kprintf("\n"); 49 | } 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /os/lab3/trap/plic.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file plic.c 3 | * @note 访问 MMIO 内存必须使用 volatile 关键字,详情见 **Effectice Modern C++** 4 | * Item 40: Use std::atomic for concurrency, volatile for special memory 5 | */ 6 | #include 7 | #include 8 | void plic_init() 9 | { 10 | plic_set_threshold(0); 11 | plic_enable_interrupt(0xa); 12 | plic_set_priority(0xa, 1); 13 | set_csr(sie, 1 << IRQ_S_EXT); 14 | } 15 | 16 | void plic_enable_interrupt(uint32_t id) 17 | { 18 | volatile uint32_t *plic_enable_address = (volatile uint32_t *)(PLIC_START_ADDR + PLIC_ENABLE); 19 | *plic_enable_address |= (1 << id); 20 | } 21 | 22 | void plic_set_priority(uint32_t id, uint8_t priority) 23 | { 24 | ((volatile uint32_t*)(PLIC_START_ADDR + PLIC_PRIORITY))[id] = priority & 7; 25 | } 26 | 27 | void plic_set_threshold(uint8_t threshold) 28 | { 29 | *(volatile uint32_t*)(PLIC_START_ADDR + PLIC_PENDING + PLIC_THRESHOLD) = threshold & 7; 30 | } 31 | 32 | /** 33 | * @brief 获取外中断号 34 | * 35 | * @return 最高优先级的待处理中断号,不存在则返回 0 36 | */ 37 | uint32_t plic_claim() 38 | { 39 | return *(volatile uint32_t*)(PLIC_START_ADDR + PLIC_PENDING + PLIC_CLAIM); 40 | } 41 | 42 | void plic_complete(uint32_t id) 43 | { 44 | *(volatile uint32_t*)(PLIC_START_ADDR + PLIC_PENDING + PLIC_COMPLETE) = id; 45 | } 46 | 47 | /* 48 | * 49 | * @brief 返回待处理终端向量 50 | * 51 | * @note 可以先 enable 再 claim 来清空 pending 52 | */ 53 | uint64_t plic_pending() 54 | { 55 | return *(volatile uint64_t*)(PLIC_START_ADDR + PLIC_PENDING); 56 | } 57 | 58 | /** 59 | * @brief 判断某终端是否带处理 60 | */ 61 | int plic_is_pending(uint32_t id) 62 | { 63 | uint64_t pending = plic_pending(); 64 | volatile uint32_t *p = (volatile uint32_t*)&pending; 65 | return p[id/32] & (id % 32); 66 | } 67 | -------------------------------------------------------------------------------- /os/lab4/trap/plic.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file plic.c 3 | * @note 访问 MMIO 内存必须使用 volatile 关键字,详情见 **Effectice Modern C++** 4 | * Item 40: Use std::atomic for concurrency, volatile for special memory 5 | */ 6 | #include 7 | #include 8 | void plic_init() 9 | { 10 | plic_set_threshold(0); 11 | plic_enable_interrupt(0xa); 12 | plic_set_priority(0xa, 1); 13 | set_csr(sie, 1 << IRQ_S_EXT); 14 | } 15 | 16 | void plic_enable_interrupt(uint32_t id) 17 | { 18 | volatile uint32_t *plic_enable_address = (volatile uint32_t *)(PLIC_START_ADDR + PLIC_ENABLE); 19 | *plic_enable_address |= (1 << id); 20 | } 21 | 22 | void plic_set_priority(uint32_t id, uint8_t priority) 23 | { 24 | ((volatile uint32_t*)(PLIC_START_ADDR + PLIC_PRIORITY))[id] = priority & 7; 25 | } 26 | 27 | void plic_set_threshold(uint8_t threshold) 28 | { 29 | *(volatile uint32_t*)(PLIC_START_ADDR + PLIC_PENDING + PLIC_THRESHOLD) = threshold & 7; 30 | } 31 | 32 | /** 33 | * @brief 获取外中断号 34 | * 35 | * @return 最高优先级的待处理中断号,不存在则返回 0 36 | */ 37 | uint32_t plic_claim() 38 | { 39 | return *(volatile uint32_t*)(PLIC_START_ADDR + PLIC_PENDING + PLIC_CLAIM); 40 | } 41 | 42 | void plic_complete(uint32_t id) 43 | { 44 | *(volatile uint32_t*)(PLIC_START_ADDR + PLIC_PENDING + PLIC_COMPLETE) = id; 45 | } 46 | 47 | /* 48 | * 49 | * @brief 返回待处理终端向量 50 | * 51 | * @note 可以先 enable 再 claim 来清空 pending 52 | */ 53 | uint64_t plic_pending() 54 | { 55 | return *(volatile uint64_t*)(PLIC_START_ADDR + PLIC_PENDING); 56 | } 57 | 58 | /** 59 | * @brief 判断某终端是否带处理 60 | */ 61 | int plic_is_pending(uint32_t id) 62 | { 63 | uint64_t pending = plic_pending(); 64 | volatile uint32_t *p = (volatile uint32_t*)&pending; 65 | return p[id/32] & (id % 32); 66 | } 67 | -------------------------------------------------------------------------------- /os/lab5/kernel/plic.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file plic.c 3 | * @note 访问 MMIO 内存必须使用 volatile 关键字,详情见 **Effectice Modern C++** 4 | * Item 40: Use std::atomic for concurrency, volatile for special memory 5 | */ 6 | #include 7 | #include 8 | void plic_init() 9 | { 10 | plic_set_threshold(0); 11 | plic_enable_interrupt(0xa); 12 | plic_set_priority(0xa, 1); 13 | set_csr(sie, 1 << IRQ_S_EXT); 14 | } 15 | 16 | void plic_enable_interrupt(uint32_t id) 17 | { 18 | volatile uint32_t *plic_enable_address = (volatile uint32_t *)(PLIC_START_ADDR + PLIC_ENABLE); 19 | *plic_enable_address |= (1 << id); 20 | } 21 | 22 | void plic_set_priority(uint32_t id, uint8_t priority) 23 | { 24 | ((volatile uint32_t*)(PLIC_START_ADDR + PLIC_PRIORITY))[id] = priority & 7; 25 | } 26 | 27 | void plic_set_threshold(uint8_t threshold) 28 | { 29 | *(volatile uint32_t*)(PLIC_START_ADDR + PLIC_PENDING + PLIC_THRESHOLD) = threshold & 7; 30 | } 31 | 32 | /** 33 | * @brief 获取外中断号 34 | * 35 | * @return 最高优先级的待处理中断号,不存在则返回 0 36 | */ 37 | uint32_t plic_claim() 38 | { 39 | return *(volatile uint32_t*)(PLIC_START_ADDR + PLIC_PENDING + PLIC_CLAIM); 40 | } 41 | 42 | void plic_complete(uint32_t id) 43 | { 44 | *(volatile uint32_t*)(PLIC_START_ADDR + PLIC_PENDING + PLIC_COMPLETE) = id; 45 | } 46 | 47 | /* 48 | * 49 | * @brief 返回待处理终端向量 50 | * 51 | * @note 可以先 enable 再 claim 来清空 pending 52 | */ 53 | uint64_t plic_pending() 54 | { 55 | return *(volatile uint64_t*)(PLIC_START_ADDR + PLIC_PENDING); 56 | } 57 | 58 | /** 59 | * @brief 判断某终端是否带处理 60 | */ 61 | int plic_is_pending(uint32_t id) 62 | { 63 | uint64_t pending = plic_pending(); 64 | volatile uint32_t *p = (volatile uint32_t*)&pending; 65 | return p[id/32] & (id % 32); 66 | } 67 | -------------------------------------------------------------------------------- /doc/meeting_record/20201206.md: -------------------------------------------------------------------------------- 1 | **与会人员**: 2 | 3 | ​ 孔俊 俞腾飞 4 | 5 | 6 | 7 | **主要内容**: 8 | 9 | - 讨论 RISC-V 中断处理 10 | - 讨论进程的虚拟地址空间 11 | - 讨论项目的构建方式 12 | - 讨论 Lab 1 要完善的地方 13 | 14 | 15 | 16 | **中断处理**: 17 | 18 | ​ 使用统一的分派函数进行中断处理。RISC-V 中中断处理有向量模式,可以向 x86 那样通过中断向量表调用中断处理函数,但异常不支持向量模式。为了简化、统一中断和异常的处理,不再使用向量模式,通过统一的分派函数根据中断、异常类型调用对应的处理函数。 19 | 20 | 21 | 22 | **虚拟地址空间**: 23 | 24 | ​ Linux 0.12 最多管理 16 M 内存,进程虚拟地址空间大小为 64 M,每个进程占据 N * 64 M 到 (N+1) * 64 M 的线性地址空间,整个系统共用一个页目录。Linux 0.12 有意让虚拟地址空间大于物理内存空间,并将进程 0 的线性地址空间设置为 0 到 64 M,因此用户进程一定不会修改线性地址 0 ~ 64 M 的映射(线性地址等于物理地址),在内核态下,线性地址等于物理地址。 25 | 26 | RISC-V 版同样采用 x86 版的思路,让内核态下线性地址等于物理地址。RISC-V 管理 128 M 物理内存,每个进程虚拟地址空间大小为 128 M,占据线性地址空间 N * 128 M 到 (N+1) * 128 M。物理地址从 0x8000_0000 开始,但 0x1000_0000 到 0x1001_0000(内存映射 IO, 设备段内存区)同样需要内核管理,最后系统线性地址空间布局如下: 27 | 28 | ``` 29 | | OpenSBI | 内核、设备段内存区域(进程 0) | 进程 1 | ... | 进程 N | 30 | ^ ^ ^ ^ 31 | | | | | 32 | 0x8000_0000 0x8200_0000 0x8000_0000 + 128M 0x8000_0000 + N * 128M 33 | ``` 34 | 35 | 0x8200_0000 到 0x8000_0000 + 64 M 作为内核区域,前端存放内核,尾部映射设备段内存区域。这段区域中,除了尾部的设备内存区域被映射到物理地址 0x1000_0000 到 0x1001_0000,其他部分线性地址被映射为等于物理地址。物理内存 0x8000_0000 到 0x8200_0000 被 OpenSBI 占据,不参与物理内存分配,尾部 0x001_0000 字节的物理内存也不参与分配。 36 | 37 | 38 | 39 | **项目的构建**: 40 | 41 | ​ 基本保留 x86 版本的项目结构。x86 版本中 Makefile 里手写了大量依赖,在 RISC-V 版本中所有目录(除了 main.c)都编译为静态库,供其他目录的代码调用,避免手写依赖。 42 | 43 | ​ 每个实验单独存放在一个目录中,后面的实验目录是前面的实验目录的超集。 44 | 45 | ​ 因为有很多代码需要改写,为了避免风格不统一,最后用代码格式化工具格式化为统一的风格。注释安装 Doxygen 格式写,方便生成 API 文档。 46 | 47 | 48 | 49 | **Lab 1 要完善的地方**: 50 | 51 | - 实验指导书添加 GDB 的使用介绍 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /os/lab2/trap/rtc/rtc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct rtc_class_device rtc_device; 6 | extern struct device_node node[100]; 7 | extern struct property prop[100]; 8 | extern int64_t node_used; 9 | extern int64_t prop_used; 10 | 11 | static uint64_t rtc_probe() 12 | { 13 | for (size_t i = 0; i < node_used+20; i++) { 14 | if (is_begin_with(node[i].name, "rtc")) { 15 | for (struct property *prop_ptr = node[i].properties; prop_ptr; 16 | prop_ptr = prop_ptr->next) { 17 | if (strcmp(prop_ptr->name, "compatible") == 0) { 18 | if (strcmp(prop_ptr->value, "google,goldfish-rtc") == 0) { 19 | return GOLDFISH_RTC; 20 | } else if (strcmp(prop_ptr->value, 21 | "allwinner,sun20iw1-rtc") == 0) { 22 | return SUNXI_RTC; 23 | } 24 | } 25 | } 26 | } 27 | } 28 | return -1; 29 | } 30 | 31 | void rtc_init() 32 | { 33 | rtc_device.id = rtc_probe(); 34 | switch (rtc_device.id) { 35 | case GOLDFISH_RTC: 36 | goldfish_rtc_init(); 37 | break; 38 | case SUNXI_RTC: 39 | sunxi_rtc_init(); 40 | break; 41 | } 42 | } 43 | 44 | uint64_t read_time() 45 | { 46 | return (*rtc_device.ops.read_time)(); 47 | } 48 | void set_time(uint64_t now) 49 | { 50 | (*rtc_device.ops.set_time)(now); 51 | } 52 | uint64_t read_alarm() 53 | { 54 | return (*rtc_device.ops.read_alarm)(); 55 | } 56 | void set_alarm(uint64_t alarm) 57 | { 58 | (*rtc_device.ops.set_alarm)(alarm); 59 | } 60 | void rtc_interrupt_handler() 61 | { 62 | (*rtc_device.ops.rtc_interrupt_handler)(); 63 | } 64 | void clear_alarm() 65 | { 66 | (*rtc_device.ops.clear_alarm)(); 67 | } -------------------------------------------------------------------------------- /os/lab6/include/utils/lru.h: -------------------------------------------------------------------------------- 1 | #ifndef LRU_H 2 | #define LRU_H 3 | 4 | #include "hash_table.h" 5 | #include "linked_list.h" 6 | #include 7 | 8 | struct lru_node { 9 | struct hash_table_node cache_node; 10 | struct linked_list_node used_list_node; 11 | }; 12 | 13 | struct lru { 14 | uint64_t cache_length; 15 | uint64_t used_length; 16 | struct hash_table cache; 17 | struct linked_list_node used_list; 18 | }; 19 | 20 | static inline void lru_init(struct lru *table) { 21 | hash_table_init(&(table->cache)); 22 | linked_list_init(&(table->used_list)); 23 | table->used_length = 0; 24 | } 25 | 26 | static inline struct lru_node *lru_get(struct lru *table, struct lru_node *node) { 27 | struct hash_table_node *hash_node = hash_table_get(&(table->cache), &(node->cache_node)); 28 | if (!hash_node) return (struct lru_node *)NULL; 29 | struct lru_node *real_node = container_of(hash_node, struct lru_node, cache_node); 30 | linked_list_remove(&(real_node->used_list_node)); 31 | linked_list_unshift(&(table->used_list), &(real_node->used_list_node)); 32 | return real_node; 33 | } 34 | 35 | static inline struct lru_node *lru_set(struct lru *table, struct lru_node *node) { 36 | hash_table_set(&(table->cache), &(node->cache_node)); 37 | linked_list_unshift(&(table->used_list), &(node->used_list_node)); 38 | struct lru_node *dropped_node = (struct lru_node *)NULL; 39 | if (table->cache_length == table->used_length) { // cache has full 40 | struct linked_list_node *dropped_list_node = linked_list_pop(&(table->used_list)); 41 | dropped_node = container_of(dropped_list_node, struct lru_node, used_list_node); 42 | hash_table_del(&(table->cache), &(dropped_node->cache_node)); 43 | } else { 44 | table->used_length += 1; 45 | } 46 | return dropped_node; 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /os/lab1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | void kputchar(char ch); 3 | int kputs(const char *msg); 4 | 5 | int main() 6 | { 7 | kputs("\nLZU OS STARTING...................."); 8 | struct sbiret ret; 9 | ret = sbi_probe_extension(TIMER_EXTENTION); 10 | if (ret.value != 0) 11 | kputs("TIMER_EXTENTION: available"); 12 | else 13 | kputs("TIMER_EXTENTION: unavailable"); 14 | 15 | ret = sbi_probe_extension(HART_STATE_EXTENTION); 16 | if (ret.value != 0) 17 | kputs("HART_STATE_EXTENTION: available"); 18 | else 19 | kputs("HART_STATE_EXTENTION: unavailable"); 20 | 21 | ret = sbi_probe_extension(RESET_EXTENTION); 22 | if (ret.value != 0) 23 | kputs("RESET_EXTENTION: available"); 24 | else 25 | kputs("RESET_EXTENTION: unavailable"); 26 | 27 | ret = sbi_get_impl_id(); 28 | switch (ret.value) 29 | { 30 | case BERKELY_BOOT_LOADER: 31 | kputs("Implemention ID: Berkely boot loader"); 32 | break; 33 | case OPENSBI: 34 | kputs("Implemention ID: OpenSBI"); 35 | break; 36 | case XVISOR: 37 | kputs("Implemention ID: XVISOR"); 38 | break; 39 | case KVM: 40 | kputs("Implemention ID: KVM"); 41 | break; 42 | case RUSTSBI: 43 | kputs("Implemention ID: RustSBI"); 44 | break; 45 | case DIOSIX: 46 | kputs("Implemention ID: DIOSIX"); 47 | break; 48 | default: 49 | kputs("Implemention ID: Unkonwn"); 50 | } 51 | kputs("Hello LZU OS"); 52 | while (1) 53 | ; /* infinite loop */ 54 | return 0; 55 | } 56 | 57 | void kputchar(char ch) 58 | { 59 | sbi_console_putchar(ch); 60 | } 61 | 62 | int kputs(const char *msg) 63 | { 64 | const char *ret = msg; 65 | for (; *msg != '\0'; ++msg) 66 | { 67 | kputchar(*msg); 68 | } 69 | kputchar('\n'); 70 | return ret == msg; 71 | } 72 | -------------------------------------------------------------------------------- /os/lab1/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(wildcard $(foreach p,$(subst :, ,$(PATH)),$(p)/riscv64-linux-gnu-*)),) 2 | PREFIX := riscv64-linux-gnu 3 | else 4 | PREFIX := riscv64-unknown-elf 5 | endif 6 | 7 | CC := $(PREFIX)-gcc 8 | LD := $(PREFIX)-ld 9 | AR := $(PREFIX)-ar 10 | OBJCOPY := $(PREFIX)-objcopy 11 | OBJDUMP := $(PREFIX)-objdump 12 | READELF := $(PREFIX)-readelf 13 | NM := $(PREFIX)-nm 14 | AS := $(PREFIX)-as 15 | TMUX := tmux 16 | QEMU := qemu-system-riscv64 17 | GDB := riscv64-unknown-elf-gdb 18 | 19 | KERN_IMG := kernel.img 20 | KERN_BIN := kernel.bin 21 | KERN_MAP := kernel.map 22 | KERN_SYM := kernel.sym 23 | KERN_ASM := kernel.asm 24 | 25 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I . 26 | 27 | objects := $(patsubst %.c, %.o, $(wildcard *.c)) entry.o 28 | 29 | .PHONY : all build run run-gui symbol debug clean disassembly 30 | 31 | all: build 32 | 33 | build : $(KERN_BIN) 34 | 35 | $(KERN_BIN) : $(objects) 36 | $(LD) -T linker.ld -Map=$(KERN_MAP) -o $(KERN_BIN) $^ 37 | $(OBJCOPY) $(KERN_BIN) --strip-all -O binary $(KERN_IMG) 38 | 39 | run : build 40 | @$(QEMU) \ 41 | -machine virt \ 42 | -nographic \ 43 | -bios fw_jump.bin \ 44 | -device loader,file=$(KERN_IMG),addr=0x80200000 45 | 46 | run-gui : build 47 | @$(QEMU) \ 48 | -machine virt \ 49 | -bios fw_jump.bin \ 50 | -device loader,file=$(KERN_IMG),addr=0x80200000 51 | 52 | debug : 53 | $(TMUX) new -s debug -d "$(QEMU) \ 54 | -machine virt \ 55 | -s -S \ 56 | -serial mon:stdio \ 57 | -nographic \ 58 | -bios fw_jump.bin \ 59 | -device loader,file=$(KERN_IMG),addr=0x80200000" && $(TMUX) split-window -h "$(GDB) -q -x gdbinit" 60 | $(TMUX) attach-session -t debug 61 | 62 | 63 | symbol : $(KERN_BIN) 64 | $(NM) -s $(KERN_BIN) > $(KERN_SYM) 65 | 66 | disassembly: $(KERN_BIN) 67 | $(OBJDUMP) -d $(KERN_BIN) > $(KERN_ASM) 68 | 69 | 70 | clean: 71 | -rm -f *.o $(KERN_BIN) $(KERN_IMG) $(KERN_SYM) $(KERN_ASM) 72 | -------------------------------------------------------------------------------- /os/lab6/include/utils/hash_table.h: -------------------------------------------------------------------------------- 1 | #ifndef HASH_TABLE_H 2 | #define HASH_TABLE_H 3 | 4 | #include "linked_list.h" 5 | #include 6 | 7 | struct hash_table_node { 8 | struct linked_list_node confliced_list; 9 | }; 10 | 11 | struct hash_table { 12 | uint64_t buffer_length; 13 | uint64_t (*is_equal)(struct hash_table_node *nodeA, struct hash_table_node *nodeB); 14 | uint64_t (*get_hash)(struct hash_table_node *node); 15 | struct hash_table_node *buffer; 16 | }; 17 | 18 | static inline void hash_table_init(struct hash_table *table) { 19 | for (uint64_t i = 0; i < table->buffer_length; i += 1) { 20 | linked_list_init(&(table->buffer[i].confliced_list)); 21 | } 22 | } 23 | 24 | static inline struct hash_table_node *hash_table_get(struct hash_table *table, struct hash_table_node *node) { 25 | uint64_t hash = table->get_hash(node) % table->buffer_length; 26 | struct linked_list_node *confliced_list = &(table->buffer[hash].confliced_list); 27 | struct linked_list_node *list_node; 28 | struct hash_table_node *hash_node; 29 | for_each_linked_list_node(list_node, confliced_list) { 30 | hash_node = container_of(list_node, struct hash_table_node, confliced_list); 31 | if (table->is_equal(node, hash_node)) break; 32 | } 33 | if (list_node == confliced_list) return (struct hash_table_node *)NULL; 34 | return hash_node; 35 | } 36 | 37 | static inline void hash_table_set(struct hash_table *table, struct hash_table_node *node) { 38 | uint64_t hash = table->get_hash(node) % table->buffer_length; 39 | struct linked_list_node *confliced_list = &(table->buffer[hash].confliced_list); 40 | linked_list_unshift(confliced_list, &(node->confliced_list)); 41 | } 42 | 43 | static inline struct hash_table_node *hash_table_del(struct hash_table *table, struct hash_table_node *node) { 44 | struct hash_table_node *hash_node = hash_table_get(table, node); 45 | if (hash_node) linked_list_remove(&(hash_node->confliced_list)); 46 | return hash_node; 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### C ### 2 | # Prerequisites 3 | *.d 4 | 5 | # Object files 6 | *.o 7 | 8 | # Linker output 9 | *.map 10 | 11 | # Libraries 12 | *.a 13 | 14 | # Shared objects 15 | *.so 16 | 17 | ### Linux ### 18 | *~ 19 | 20 | # temporary files which can be created if a process still has a handle open of a deleted file 21 | .fuse_hidden* 22 | 23 | # KDE directory preferences 24 | .directory 25 | 26 | # Linux trash folder which might appear on any partition or disk 27 | .Trash-* 28 | 29 | # .nfs files are created when an open file is removed but is still being accessed 30 | .nfs* 31 | 32 | ### macOS ### 33 | # General 34 | .DS_Store 35 | .AppleDouble 36 | .LSOverride 37 | 38 | # Icon must end with a \r 39 | Icon? 40 | 41 | # Thumbnails 42 | ._* 43 | 44 | # Files that might appear in the root of a volume 45 | .DocumentRevisions-V100 46 | .fseventsd 47 | .Spotlight-V100 48 | .TemporaryItems 49 | .Trashes 50 | .VolumeIcon.icns 51 | .com.apple.timemachine.donotpresent 52 | 53 | # Directories potentially created on remote AFP share 54 | .AppleDB 55 | .AppleDesktop 56 | Network Trash Folder 57 | Temporary Items 58 | .apdisk 59 | 60 | ### Vim ### 61 | # Swap 62 | [._]*.s[a-v][a-z] 63 | !*.svg 64 | [._]*.sw[a-p] 65 | [._]s[a-rt-v][a-z] 66 | [._]ss[a-gi-z] 67 | [._]sw[a-p] 68 | 69 | # Session 70 | Session.vim 71 | Sessionx.vim 72 | 73 | # Temporary 74 | .netrwhist 75 | # Auto-generated tag files 76 | tags 77 | # Persistent undo 78 | [._]*.un~ 79 | 80 | ### Windows ### 81 | # Windows thumbnail cache files 82 | Thumbs.db 83 | Thumbs.db:encryptable 84 | ehthumbs.db 85 | ehthumbs_vista.db 86 | 87 | # Folder config file 88 | [Dd]esktop.ini 89 | 90 | # Recycle Bin used on file shares 91 | $RECYCLE.BIN/ 92 | 93 | # Windows shortcuts 94 | *.lnk 95 | 96 | ### Virual Studio Code ### 97 | # Workspace config 98 | .vscode/ 99 | .vscode-test/ 100 | *.code-workspace 101 | 102 | ### LZU OSLab ### 103 | vsc_diag_suppress.h 104 | doc/html/ 105 | *.img 106 | *.bin 107 | !fw_jump.bin -------------------------------------------------------------------------------- /os/lab2/include/trap.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file trap.h 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 本文件声明了中断处理相关的数据结构和函数 5 | */ 6 | #ifndef __TRAP_H__ 7 | #define __TRAP_H__ 8 | 9 | #include 10 | 11 | /** 12 | * @brief 保存通用寄存器的结构体抽象,用于trapframe结构体 13 | */ 14 | struct pushregs { 15 | uint64_t zero; // Hard-wired zero 16 | uint64_t ra; // Return address 17 | uint64_t sp; // Stack pointer 18 | uint64_t gp; // Global pointer 19 | uint64_t tp; // Thread pointer 20 | uint64_t t0; // Temporary 21 | uint64_t t1; // Temporary 22 | uint64_t t2; // Temporary 23 | uint64_t s0; // Saved register/frame pointer 24 | uint64_t s1; // Saved register 25 | uint64_t a0; // Function argument/return value 26 | uint64_t a1; // Function argument/return value 27 | uint64_t a2; // Function argument 28 | uint64_t a3; // Function argument 29 | uint64_t a4; // Function argument 30 | uint64_t a5; // Function argument 31 | uint64_t a6; // Function argument 32 | uint64_t a7; // Function argument 33 | uint64_t s2; // Saved register 34 | uint64_t s3; // Saved register 35 | uint64_t s4; // Saved register 36 | uint64_t s5; // Saved register 37 | uint64_t s6; // Saved register 38 | uint64_t s7; // Saved register 39 | uint64_t s8; // Saved register 40 | uint64_t s9; // Saved register 41 | uint64_t s10; // Saved register 42 | uint64_t s11; // Saved register 43 | uint64_t t3; // Temporary 44 | uint64_t t4; // Temporary 45 | uint64_t t5; // Temporary 46 | uint64_t t6; // Temporary 47 | }; 48 | 49 | /** 50 | * @brief 保存上下文的栈的结构体抽象,和trap.S中分配的36*XLENB相对应 51 | */ 52 | struct trapframe { 53 | struct pushregs gpr; // x0-x31 (general purpose register) 54 | uint64_t status; // sstatus 55 | uint64_t epc; // sepc 56 | uint64_t badvaddr; // stval 57 | uint64_t cause; // scause 58 | }; 59 | 60 | struct trapframe* trap(struct trapframe* tf); 61 | void set_stvec(); 62 | void print_trapframe(struct trapframe *tf); 63 | void print_regs(struct pushregs *gpr); 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /os/lab3/include/trap.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file trap.h 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 本文件声明了中断处理相关的数据结构和函数 5 | */ 6 | #ifndef __TRAP_H__ 7 | #define __TRAP_H__ 8 | 9 | #include 10 | 11 | /** 12 | * @brief 保存通用寄存器的结构体抽象,用于trapframe结构体 13 | */ 14 | struct pushregs { 15 | uint64_t zero; // Hard-wired zero 16 | uint64_t ra; // Return address 17 | uint64_t sp; // Stack pointer 18 | uint64_t gp; // Global pointer 19 | uint64_t tp; // Thread pointer 20 | uint64_t t0; // Temporary 21 | uint64_t t1; // Temporary 22 | uint64_t t2; // Temporary 23 | uint64_t s0; // Saved register/frame pointer 24 | uint64_t s1; // Saved register 25 | uint64_t a0; // Function argument/return value 26 | uint64_t a1; // Function argument/return value 27 | uint64_t a2; // Function argument 28 | uint64_t a3; // Function argument 29 | uint64_t a4; // Function argument 30 | uint64_t a5; // Function argument 31 | uint64_t a6; // Function argument 32 | uint64_t a7; // Function argument 33 | uint64_t s2; // Saved register 34 | uint64_t s3; // Saved register 35 | uint64_t s4; // Saved register 36 | uint64_t s5; // Saved register 37 | uint64_t s6; // Saved register 38 | uint64_t s7; // Saved register 39 | uint64_t s8; // Saved register 40 | uint64_t s9; // Saved register 41 | uint64_t s10; // Saved register 42 | uint64_t s11; // Saved register 43 | uint64_t t3; // Temporary 44 | uint64_t t4; // Temporary 45 | uint64_t t5; // Temporary 46 | uint64_t t6; // Temporary 47 | }; 48 | 49 | /** 50 | * @brief 保存上下文的栈的结构体抽象,和trap.S中分配的36*XLENB相对应 51 | */ 52 | struct trapframe { 53 | struct pushregs gpr; // x0-x31 (general purpose register) 54 | uint64_t status; // sstatus 55 | uint64_t epc; // sepc 56 | uint64_t badvaddr; // stval 57 | uint64_t cause; // scause 58 | }; 59 | 60 | struct trapframe* trap(struct trapframe* tf); 61 | void set_stvec(); 62 | void print_trapframe(struct trapframe *tf); 63 | void print_regs(struct pushregs *gpr); 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /os/lab4/include/trap.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file trap.h 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 本文件声明了中断处理相关的数据结构和函数 5 | */ 6 | #ifndef __TRAP_H__ 7 | #define __TRAP_H__ 8 | 9 | #include 10 | 11 | /** 12 | * @brief 保存通用寄存器的结构体抽象,用于trapframe结构体 13 | */ 14 | struct pushregs { 15 | uint64_t zero; // Hard-wired zero 16 | uint64_t ra; // Return address 17 | uint64_t sp; // Stack pointer 18 | uint64_t gp; // Global pointer 19 | uint64_t tp; // Thread pointer 20 | uint64_t t0; // Temporary 21 | uint64_t t1; // Temporary 22 | uint64_t t2; // Temporary 23 | uint64_t s0; // Saved register/frame pointer 24 | uint64_t s1; // Saved register 25 | uint64_t a0; // Function argument/return value 26 | uint64_t a1; // Function argument/return value 27 | uint64_t a2; // Function argument 28 | uint64_t a3; // Function argument 29 | uint64_t a4; // Function argument 30 | uint64_t a5; // Function argument 31 | uint64_t a6; // Function argument 32 | uint64_t a7; // Function argument 33 | uint64_t s2; // Saved register 34 | uint64_t s3; // Saved register 35 | uint64_t s4; // Saved register 36 | uint64_t s5; // Saved register 37 | uint64_t s6; // Saved register 38 | uint64_t s7; // Saved register 39 | uint64_t s8; // Saved register 40 | uint64_t s9; // Saved register 41 | uint64_t s10; // Saved register 42 | uint64_t s11; // Saved register 43 | uint64_t t3; // Temporary 44 | uint64_t t4; // Temporary 45 | uint64_t t5; // Temporary 46 | uint64_t t6; // Temporary 47 | }; 48 | 49 | /** 50 | * @brief 保存上下文的栈的结构体抽象,和trap.S中分配的36*XLENB相对应 51 | */ 52 | struct trapframe { 53 | struct pushregs gpr; // x0-x31 (general purpose register) 54 | uint64_t status; // sstatus 55 | uint64_t epc; // sepc 56 | uint64_t badvaddr; // stval 57 | uint64_t cause; // scause 58 | }; 59 | 60 | struct trapframe* trap(struct trapframe* tf); 61 | void set_stvec(); 62 | void print_trapframe(struct trapframe *tf); 63 | void print_regs(struct pushregs *gpr); 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /os/lab6/include/fs/vfs.h: -------------------------------------------------------------------------------- 1 | #ifndef VFS_H 2 | #define VFS_H 3 | 4 | #include 5 | 6 | struct vfs_inode; 7 | struct vfs_stat; 8 | 9 | struct vfs_interface { 10 | void *fs_data; 11 | struct vfs_inode *root; 12 | void (*init_fs)(struct vfs_interface *fs); 13 | struct vfs_inode *(*open_inode)(struct vfs_inode *inode); 14 | void (*close_inode)(struct vfs_inode *inode); 15 | struct vfs_stat *(*get_stat)(struct vfs_inode *inode); 16 | uint64_t (*is_dir)(struct vfs_inode *inode); 17 | struct vfs_dir_entry *(*dir_inode)(struct vfs_inode *inode, uint64_t dir_idx); 18 | void (*inode_request)(struct vfs_inode *inode, void *buffer, uint64_t length, uint64_t offset, uint64_t is_read); 19 | uint64_t ref_cnt; 20 | }; 21 | 22 | struct vfs_stat { 23 | // uint64_t type; 24 | uint64_t size; 25 | uint64_t time; 26 | uint64_t gid; 27 | uint64_t uid; 28 | }; 29 | 30 | struct vfs_inode { 31 | void *inode_data; 32 | uint64_t inode_idx; 33 | struct vfs_interface *fs; 34 | uint64_t ref_cnt; 35 | }; 36 | 37 | struct vfs_dir_entry { 38 | const char *name; 39 | uint64_t inode_idx; 40 | }; 41 | 42 | /* 其他子系统要持有vfs_inode必须调用vfs_ref_inode,否则可能inode资源会被自动释放 */ 43 | /* 无论是否持有,使用完inode后必须调用vfs_free_inode,系统会自动释放资源 */ 44 | /* TODO: vfs_new_inode 已新建inode缓冲区 */ 45 | /* TODO: vfs_free_inode 懒释放缓冲区 */ 46 | 47 | /* 从指定文件系统中提取inode */ 48 | struct vfs_inode *vfs_new_inode(struct vfs_interface *fs, uint64_t inode_idx); 49 | 50 | /* vfs提供的引用计数管理操作 */ 51 | void vfs_ref_inode(struct vfs_inode *inode); 52 | void vfs_free_inode(struct vfs_inode *inode); 53 | 54 | /* vsf提供的inode操作 */ 55 | struct vfs_stat *vfs_get_stat(struct vfs_inode *inode); 56 | void vfs_inode_request(struct vfs_inode *inode, void *buffer, uint64_t length, uint64_t offset, uint64_t is_read); 57 | uint64_t vfs_is_dir(struct vfs_inode *inode); 58 | struct vfs_dir_entry *vfs_inode_dir_entry(struct vfs_inode *inode, uint64_t dir_idx); 59 | 60 | /* vfs提供的path操作 */ 61 | struct vfs_inode *vfs_search_inode_in_dir(struct vfs_inode *inode, const char *name); 62 | struct vfs_inode *vfs_get_inode(const char *path, struct vfs_inode *cwd); 63 | 64 | void vfs_init(); 65 | 66 | extern struct vfs_inode *vfs_root; 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /os/lab2/include/plic.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file plic.h 3 | * @brief 所有和 PLIC(Platform Level Interrupt Controller) 有关的声明 4 | */ 5 | #ifndef __PLIC_H__ 6 | #define __PLIC_H__ 7 | #include 8 | 9 | /// @{ @name PLIC 内存映射 IO 地址 10 | /** PLIC 的内存映射为 [0x0c000000, 0x1000_0000), 仅使用 hart 0 相关的 PLIC */ 11 | //#define PLIC_START 0x10000000 /**< PLIC 起始物理地址 */ 12 | //#define PLIC_LENGTH 0x04000000 /**< PLIC MMIO 内存大小 */ 13 | //#define PLIC_END PLIC_START + PLIC_LENGTH /**< PLIC 结束物理地址 */ 14 | //#define PLIC_START_ADDR PLIC_START /**< PLIC 起始地址(为虚拟分页预留) */ 15 | /// @} 16 | 17 | struct plic_regs { 18 | volatile uint32_t PLIC_PRIO_REG[1024]; /**< 中断优先级寄存器,0保留 */ 19 | volatile uint32_t PLIC_IP_REG[32]; /**< 待处理中断寄存器 */ 20 | volatile uint32_t PLIC_PADDING1[(0x2000 - 0x1000 - 4 * 32) >> 2]; 21 | volatile uint32_t PLIC_IE_REG[15871][32]; /**< 中断使能寄存器 */ 22 | volatile uint32_t PLIC_PADDING2[(0x1FFFFC - 0x2000 - 4 * 32 * 15871) >> 2]; 23 | volatile uint32_t PLIC_CTRL_REG; /**< 0x1FFFFC 中断访问权限控制寄存器(D1专属) */ 24 | volatile struct { 25 | volatile uint32_t PLIC_TH_REG; /**< 中断阈值寄存器 */ 26 | volatile uint32_t PLIC_CLAIM_REG; /**< 中断声明与完成寄存器 */ 27 | volatile uint32_t PADDING[(0x1000 - 2 * 4) >> 2]; 28 | } PLIC_TH_CLAIM_COMPLITE_REG[15871]; 29 | }; 30 | 31 | struct plic_class_device { 32 | uint32_t id; 33 | volatile struct plic_regs *plic_start_addr; 34 | }; 35 | 36 | enum plic_device_type { 37 | QEMU_PLIC = 0, 38 | SUNXI_PLIC = 1, 39 | }; 40 | 41 | enum qemu_irq { 42 | UART_QEMU_IRQ = 10, 43 | RTC_GOLDFISH_IRQ = 11, 44 | VIRTIO_IRQ = 1, /* 1 to 8 */ 45 | VIRTIO_COUNT = 8, 46 | PCIE_IRQ = 0x20, /* 32 to 35 */ 47 | VIRTIO_NDEV = 0x35, /* Arbitrary maximum number of interrupts */ 48 | }; 49 | 50 | enum nezha_irq { 51 | RTC_SUNXI_IRQ = 160, 52 | UART_SUNXI_IRQ = 0x12, 53 | }; 54 | 55 | void plic_enable_interrupt(uint32_t id); 56 | void plic_set_priority(uint32_t id, uint8_t priority); 57 | void plic_set_threshold(uint8_t threshold); 58 | uint32_t plic_claim(); 59 | void plic_complete(uint32_t id); 60 | void plic_init(); 61 | uint32_t plic_is_pending(uint32_t id); 62 | uint64_t plic_pending(); 63 | 64 | #endif /* end of include guard: __PLIC_H__ */ 65 | -------------------------------------------------------------------------------- /os/lab5/include/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef __ERRNO_H__ 2 | #define __ERRNO_H__ 3 | /** 4 | * @file errno.h 5 | * @brief 声明 errno 编号 6 | * 7 | * UNIX 系统调用失败时,返回码设为 -1,并根据失败原因 8 | * 设置 errno。 9 | * 10 | * 实际的 UNIX 系统中,每个线程都有一个 errno,errno 是 11 | * 一个可以展开为线程特定变量的宏。本内核没有实现线程, 12 | * 将 errno 简单的实现为全局变量。 13 | * 14 | * 本文件中的编号与最新的 Linux 内核一致。 15 | */ 16 | extern int errno; 17 | 18 | #define EPERM 1 /**< Operation not permitted */ 19 | #define ENOENT 2 /**< No such file or directory */ 20 | #define ESRCH 3 /**< No such process */ 21 | #define EINTR 4 /**< Interrupted system call */ 22 | #define EIO 5 /**< I/O error */ 23 | #define ENXIO 6 /**< No such device or address */ 24 | #define E2BIG 7 /**< Argument list too long */ 25 | #define ENOEXEC 8 /**< Exec format error */ 26 | #define EBADF 9 /**< Bad file number */ 27 | #define ECHILD 10 /**< No child processes */ 28 | #define EAGAIN 11 /**< Try again */ 29 | #define ENOMEM 12 /**< Out of memory */ 30 | #define EACCES 13 /**< Permission denied */ 31 | #define EFAULT 14 /**< Bad address */ 32 | #define ENOTBLK 15 /**< Block device required */ 33 | #define EBUSY 16 /**< Device or resource busy */ 34 | #define EEXIST 17 /**< File exists */ 35 | #define EXDEV 18 /**< Cross-device link */ 36 | #define ENODEV 19 /**< No such device */ 37 | #define ENOTDIR 20 /**< Not a directory */ 38 | #define EISDIR 21 /**< Is a directory */ 39 | #define EINVAL 22 /**< Invalid argument */ 40 | #define ENFILE 23 /**< File table overflow */ 41 | #define EMFILE 24 /**< Too many open files */ 42 | #define ENOTTY 25 /**< Not a typewriter */ 43 | #define ETXTBSY 26 /**< Text file busy */ 44 | #define EFBIG 27 /**< File too large */ 45 | #define ENOSPC 28 /**< No space left on device */ 46 | #define ESPIPE 29 /**< Illegal seek */ 47 | #define EROFS 30 /**< Read-only file system */ 48 | #define ENOSYS 38 /**< Invalid system call number */ 49 | #define ERESTART 85 /**< Interrupted system call should be restarted */ 50 | 51 | #endif /** end of include guard: __ERRNO_H__ */ 52 | -------------------------------------------------------------------------------- /os/lab6/include/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef __ERRNO_H__ 2 | #define __ERRNO_H__ 3 | /** 4 | * @file errno.h 5 | * @brief 声明 errno 编号 6 | * 7 | * UNIX 系统调用失败时,返回码设为 -1,并根据失败原因 8 | * 设置 errno。 9 | * 10 | * 实际的 UNIX 系统中,每个线程都有一个 errno,errno 是 11 | * 一个可以展开为线程特定变量的宏。本内核没有实现线程, 12 | * 将 errno 简单的实现为全局变量。 13 | * 14 | * 本文件中的编号与最新的 Linux 内核一致。 15 | */ 16 | extern int errno; 17 | 18 | #define EPERM 1 /**< Operation not permitted */ 19 | #define ENOENT 2 /**< No such file or directory */ 20 | #define ESRCH 3 /**< No such process */ 21 | #define EINTR 4 /**< Interrupted system call */ 22 | #define EIO 5 /**< I/O error */ 23 | #define ENXIO 6 /**< No such device or address */ 24 | #define E2BIG 7 /**< Argument list too long */ 25 | #define ENOEXEC 8 /**< Exec format error */ 26 | #define EBADF 9 /**< Bad file number */ 27 | #define ECHILD 10 /**< No child processes */ 28 | #define EAGAIN 11 /**< Try again */ 29 | #define ENOMEM 12 /**< Out of memory */ 30 | #define EACCES 13 /**< Permission denied */ 31 | #define EFAULT 14 /**< Bad address */ 32 | #define ENOTBLK 15 /**< Block device required */ 33 | #define EBUSY 16 /**< Device or resource busy */ 34 | #define EEXIST 17 /**< File exists */ 35 | #define EXDEV 18 /**< Cross-device link */ 36 | #define ENODEV 19 /**< No such device */ 37 | #define ENOTDIR 20 /**< Not a directory */ 38 | #define EISDIR 21 /**< Is a directory */ 39 | #define EINVAL 22 /**< Invalid argument */ 40 | #define ENFILE 23 /**< File table overflow */ 41 | #define EMFILE 24 /**< Too many open files */ 42 | #define ENOTTY 25 /**< Not a typewriter */ 43 | #define ETXTBSY 26 /**< Text file busy */ 44 | #define EFBIG 27 /**< File too large */ 45 | #define ENOSPC 28 /**< No space left on device */ 46 | #define ESPIPE 29 /**< Illegal seek */ 47 | #define EROFS 30 /**< Read-only file system */ 48 | #define ENOSYS 38 /**< Invalid system call number */ 49 | #define ERESTART 85 /**< Interrupted system call should be restarted */ 50 | 51 | #endif /** end of include guard: __ERRNO_H__ */ 52 | -------------------------------------------------------------------------------- /os/lab6/include/utils/atomic.h: -------------------------------------------------------------------------------- 1 | #ifndef __ATOMIC_H__ 2 | #define __ATOMIC_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* 用法: 9 | #include 10 | struct spinlock lock_a; 11 | init_lock(&lock_a,"lock_a"); 12 | acquire_lock(&lock_a); 13 | release_lock(&lock_a); 14 | */ 15 | 16 | // Mutual exclusion lock. 17 | struct spinlock 18 | { 19 | uint64_t locked; // Is the lock held? 20 | 21 | // For debugging: 22 | char *name; // Name of lock. 23 | }; 24 | 25 | static inline void init_lock(struct spinlock *lk, char *name) 26 | { 27 | lk->name = name; 28 | lk->locked = 0; 29 | } 30 | 31 | // Acquire the lock. 32 | // Loops (spins) until the lock is acquired. 33 | static inline void acquire_lock(struct spinlock *lk) 34 | { 35 | // On RISC-V, sync_lock_test_and_set turns into an atomic swap: 36 | // a5 = 1 37 | // s1 = &lk->locked 38 | // amoswap.w.aq a5, a5, (s1) 39 | while (__sync_lock_test_and_set(&lk->locked, 1) != 0) 40 | ; 41 | 42 | // Tell the C compiler and the processor to not move loads or stores 43 | // past this point, to ensure that the critical section's memory 44 | // references happen strictly after the lock is acquired. 45 | // On RISC-V, this emits a fence instruction. 46 | __sync_synchronize(); 47 | } 48 | 49 | // Release the lock. 50 | static inline void release_lock(struct spinlock *lk) 51 | { 52 | // Tell the C compiler and the CPU to not move loads or stores 53 | // past this point, to ensure that all the stores in the critical 54 | // section are visible to other CPUs before the lock is released, 55 | // and that loads in the critical section occur strictly before 56 | // the lock is released. 57 | // On RISC-V, this emits a fence instruction. 58 | __sync_synchronize(); 59 | 60 | // Release the lock, equivalent to lk->locked = 0. 61 | // This code doesn't use a C assignment, since the C standard 62 | // implies that an assignment might be implemented with 63 | // multiple store instructions. 64 | // On RISC-V, sync_lock_release turns into an atomic swap: 65 | // s1 = &lk->locked 66 | // amoswap.w zero, zero, (s1) 67 | __sync_lock_release(&lk->locked); 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /os/lab5/include/trap.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file trap.h 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 本文件声明了中断处理相关的数据结构和函数 5 | */ 6 | #ifndef __TRAP_H__ 7 | #define __TRAP_H__ 8 | 9 | #include 10 | 11 | /** 12 | * @brief 保存通用寄存器的结构体抽象,用于trapframe结构体 13 | */ 14 | struct pushregs { 15 | uint64_t zero; // Hard-wired zero 16 | uint64_t ra; // Return address 17 | uint64_t sp; // Stack pointer 18 | uint64_t gp; // Global pointer 19 | uint64_t tp; // Thread pointer 20 | uint64_t t0; // Temporary 21 | uint64_t t1; // Temporary 22 | uint64_t t2; // Temporary 23 | uint64_t s0; // Saved register/frame pointer 24 | uint64_t s1; // Saved register 25 | uint64_t a0; // Function argument/return value 26 | uint64_t a1; // Function argument/return value 27 | uint64_t a2; // Function argument 28 | uint64_t a3; // Function argument 29 | uint64_t a4; // Function argument 30 | uint64_t a5; // Function argument 31 | uint64_t a6; // Function argument 32 | uint64_t a7; // Function argument 33 | uint64_t s2; // Saved register 34 | uint64_t s3; // Saved register 35 | uint64_t s4; // Saved register 36 | uint64_t s5; // Saved register 37 | uint64_t s6; // Saved register 38 | uint64_t s7; // Saved register 39 | uint64_t s8; // Saved register 40 | uint64_t s9; // Saved register 41 | uint64_t s10; // Saved register 42 | uint64_t s11; // Saved register 43 | uint64_t t3; // Temporary 44 | uint64_t t4; // Temporary 45 | uint64_t t5; // Temporary 46 | uint64_t t6; // Temporary 47 | }; 48 | 49 | /** 50 | * @brief 保存上下文的栈的结构体抽象,和trap.S中分配的36*XLENB相对应 51 | */ 52 | struct trapframe { 53 | struct pushregs gpr; // x0-x31 (general purpose register) 54 | uint64_t status; // sstatus 55 | uint64_t epc; // sepc 56 | uint64_t badvaddr; // stval 57 | uint64_t cause; // scause 58 | }; 59 | 60 | extern void set_stack(char *stack); 61 | extern void __trapret(); 62 | extern void __alltraps(); 63 | 64 | struct trapframe * trap(struct trapframe *tf); 65 | void set_stvec(); 66 | void print_trapframe(struct trapframe *tf); 67 | void print_regs(struct pushregs *gpr); 68 | int trap_in_kernel(struct trapframe *tf); 69 | #endif 70 | -------------------------------------------------------------------------------- /os/lab6/include/trap.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file trap.h 3 | * @author Hanabichan (93yutf@gmail.com) 4 | * @brief 本文件声明了中断处理相关的数据结构和函数 5 | */ 6 | #ifndef __TRAP_H__ 7 | #define __TRAP_H__ 8 | 9 | #include 10 | 11 | /** 12 | * @brief 保存通用寄存器的结构体抽象,用于trapframe结构体 13 | */ 14 | struct pushregs { 15 | uint64_t zero; // Hard-wired zero 16 | uint64_t ra; // Return address 17 | uint64_t sp; // Stack pointer 18 | uint64_t gp; // Global pointer 19 | uint64_t tp; // Thread pointer 20 | uint64_t t0; // Temporary 21 | uint64_t t1; // Temporary 22 | uint64_t t2; // Temporary 23 | uint64_t s0; // Saved register/frame pointer 24 | uint64_t s1; // Saved register 25 | uint64_t a0; // Function argument/return value 26 | uint64_t a1; // Function argument/return value 27 | uint64_t a2; // Function argument 28 | uint64_t a3; // Function argument 29 | uint64_t a4; // Function argument 30 | uint64_t a5; // Function argument 31 | uint64_t a6; // Function argument 32 | uint64_t a7; // Function argument 33 | uint64_t s2; // Saved register 34 | uint64_t s3; // Saved register 35 | uint64_t s4; // Saved register 36 | uint64_t s5; // Saved register 37 | uint64_t s6; // Saved register 38 | uint64_t s7; // Saved register 39 | uint64_t s8; // Saved register 40 | uint64_t s9; // Saved register 41 | uint64_t s10; // Saved register 42 | uint64_t s11; // Saved register 43 | uint64_t t3; // Temporary 44 | uint64_t t4; // Temporary 45 | uint64_t t5; // Temporary 46 | uint64_t t6; // Temporary 47 | }; 48 | 49 | /** 50 | * @brief 保存上下文的栈的结构体抽象,和trap.S中分配的36*XLENB相对应 51 | */ 52 | struct trapframe { 53 | struct pushregs gpr; // x0-x31 (general purpose register) 54 | uint64_t status; // sstatus 55 | uint64_t epc; // sepc 56 | uint64_t badvaddr; // stval 57 | uint64_t cause; // scause 58 | }; 59 | 60 | extern void set_stack(char *stack); 61 | extern void __trapret(); 62 | extern void __alltraps(); 63 | 64 | struct trapframe * trap(struct trapframe *tf); 65 | void set_stvec(); 66 | void print_trapframe(struct trapframe *tf); 67 | void print_regs(struct pushregs *gpr); 68 | int trap_in_kernel(struct trapframe *tf); 69 | #endif 70 | -------------------------------------------------------------------------------- /os/lab6/lib/sleep.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | struct usleep_queue_node usleep_queue; 6 | 7 | // 计时队列每次只对队首节点计时,时间到后移除队首节点,对新队首节点计时 8 | void usleep_queue_init() { 9 | usleep_queue.remaining_time = 0; 10 | usleep_queue.task = NULL; 11 | linked_list_init(&usleep_queue.list_node); 12 | } 13 | 14 | int64_t usleep_set(int64_t utime) 15 | { 16 | uint64_t is_disable = read_csr(sstatus) & SSTATUS_SIE; 17 | disable_interrupt(); 18 | 19 | struct linked_list_node *node; 20 | for_each_linked_list_node(node, &usleep_queue.list_node) // 找一个合适的队列插入位置 21 | { 22 | struct usleep_queue_node *cur_node = container_of(node, struct usleep_queue_node, list_node); 23 | utime -= cur_node->remaining_time; // 计算上一个节点结束计时后当前节点还需计时多久 24 | if (utime <= 0) // 若剩余需计时时间小于等于 0,则表明找到合适插入位置,插入找到的节点之前 25 | { 26 | utime += cur_node->remaining_time; // 并把多减去的剩余时间加回来 27 | break; 28 | } 29 | } 30 | struct usleep_queue_node new_node = { 31 | .remaining_time = utime, 32 | .task = current, 33 | }; 34 | linked_list_insert_before(node, &new_node.list_node); // 插入找到的节点之前或表尾 35 | container_of(node, struct usleep_queue_node, list_node)->remaining_time -= utime; // 将插入节点的下一个节点计时时间减去差值 36 | 37 | sleep_on(&new_node.task); 38 | 39 | // 防止由其他事件唤醒进程导致计时队列没有删除,重复唤醒 40 | if (new_node.remaining_time > 0) 41 | { 42 | linked_list_remove(&new_node.list_node); 43 | } 44 | 45 | set_csr(sstatus, is_disable); 46 | return new_node.remaining_time; 47 | } 48 | 49 | void usleep_handler() 50 | { 51 | while (!linked_list_empty(&usleep_queue.list_node)) { 52 | struct linked_list_node *first_list_node = linked_list_first(&usleep_queue.list_node); 53 | struct usleep_queue_node *first_usleep_node = container_of(first_list_node, struct usleep_queue_node, list_node); 54 | first_usleep_node->remaining_time -= 10000; // 对首节点减去一次时钟中断经过的时间 55 | if (first_usleep_node->remaining_time <= 0) { // 若已到时 56 | linked_list_remove(first_list_node); // 移除首节点 57 | // 不需要 free usleep_queue_node 结构体,结构体在那个被sleep的进程的内核栈上,唤醒返回值后直接被清除 58 | wake_up(&first_usleep_node->task); // 唤醒 sleep 的进程 59 | } else { 60 | return; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /os/lab2/include/dtb.h: -------------------------------------------------------------------------------- 1 | #include 2 | #ifndef __DTB_H__ 3 | #define __DTB_H__ 4 | 5 | enum fdt_config { 6 | FDT_MAGIC = 0xd00dfeed, 7 | FDT_FIRST_SUPPORTED_VERSION = 2, 8 | FDT_LAST_SUPPORTED_VERSION = 17, 9 | FDT_4B_ALIGN = 0x3, 10 | FDT_V1_SIZE = 7 * sizeof(uint32_t), 11 | FDT_V2_SIZE = FDT_V1_SIZE + sizeof(uint32_t), 12 | FDT_V3_SIZE = FDT_V2_SIZE + sizeof(uint32_t), 13 | FDT_V17_SIZE = FDT_V3_SIZE + sizeof(uint32_t), 14 | }; 15 | 16 | enum dt_tag { 17 | DT_BEGIN_NODE = 0x1, 18 | DT_END_NODE = 0x2, 19 | DT_PROP = 0x3, 20 | DT_NOP = 0x4, 21 | DT_END = 0x9, 22 | }; 23 | 24 | struct fdt_header { 25 | uint32_t magic; /* magic word FDT_MAGIC */ 26 | uint32_t totalsize; /* total size of DT block */ 27 | uint32_t off_dt_struct; /* offset to structure */ 28 | uint32_t off_dt_strings; /* offset to strings */ 29 | uint32_t off_mem_rsvmap; /* offset to memory reserve map */ 30 | uint32_t version; /* format version */ 31 | uint32_t last_comp_version; /* last compatible version */ 32 | /* version 2 fields below */ 33 | uint32_t boot_cpuid_phys; /* Which physical CPU id we're booting on */ 34 | /* version 3 fields below */ 35 | uint32_t size_dt_strings; /* size of the strings block */ 36 | /* version 17 fields below */ 37 | uint32_t size_dt_struct; /* size of the structure block */ 38 | }; 39 | 40 | struct property { 41 | const char *name; /* name of property */ 42 | uint32_t length; /* length of property value */ 43 | const void *value; /* property value */ 44 | struct property *next; /* next property */ 45 | }; 46 | struct device_node { 47 | const char *name; /* node的名称,取最后一次“/”和“@”之间子串 */ 48 | const char *type; /* device_type的属性名称,没有为 */ 49 | // uint32_t phandle; /* phandle属性值 */ 50 | const char * 51 | full_name; /* 指向该结构体结束的位置,存放node的路径全名,例如:/chosen */ 52 | // struct fwnode_handle fwnode; 53 | 54 | struct property * 55 | properties; /* 指向该节点下的第一个属性,其他属性与该属性链表相接 */ 56 | // struct property *deadprops; /* removed properties */ 57 | struct device_node *parent; /* 父节点 */ 58 | struct device_node *child; /* 子节点 */ 59 | struct device_node *sibling; /* 姊妹节点,与自己同等级的node */ 60 | uint32_t depth; /* 节点的深度 */ 61 | void *data; 62 | }; 63 | 64 | void unflatten_device_tree(const void *fdt_start); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /os/lab6/drivers/base.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint64_t device_table_get_hash(struct hash_table_node *node) { 4 | struct device *dev = container_of(node, struct device, hash_node); 5 | return (dev->device_id * 0x10001) + 19; 6 | } 7 | 8 | uint64_t device_table_is_equal(struct hash_table_node *nodeA, struct hash_table_node *nodeB) { 9 | struct device *devA = container_of(nodeA, struct device, hash_node); 10 | struct device *devB = container_of(nodeB, struct device, hash_node); 11 | return devA->device_id == devB->device_id; 12 | } 13 | 14 | struct hash_table_node device_table_buffer[DEVICE_TABLE_BUFFER_LENGTH]; 15 | struct hash_table device_table = { 16 | .buffer = device_table_buffer, 17 | .buffer_length = DEVICE_TABLE_BUFFER_LENGTH, 18 | .get_hash = device_table_get_hash, 19 | .is_equal = device_table_is_equal 20 | }; 21 | 22 | void init_device_table() { 23 | hash_table_init(&device_table); 24 | } 25 | 26 | uint32_t device_table_get_major_num(uint32_t major) { 27 | uint64_t buffer_length = device_table.buffer_length; 28 | uint32_t num = 0; 29 | for (uint64_t i = 0; i < buffer_length; i += 1) { 30 | struct linked_list_node *list_node; 31 | struct hash_table_node *hash_node; 32 | struct device *dev; 33 | for_each_linked_list_node(list_node, &device_table.buffer[i].confliced_list) { 34 | hash_node = container_of(list_node, struct hash_table_node, confliced_list); 35 | dev = container_of(hash_node, struct device, hash_node); 36 | if (device_get_major(dev) == major) { 37 | num += 1; 38 | } 39 | } 40 | } 41 | return num; 42 | } 43 | 44 | uint32_t device_table_get_next_minor(uint32_t major, uint32_t minor_start) { 45 | struct device dev; 46 | struct hash_table_node *node; 47 | device_set_major(&dev, major); 48 | uint32_t minor = minor_start; 49 | while(1) { 50 | device_set_minor(&dev, minor); 51 | node = hash_table_get(&device_table, &dev.hash_node); 52 | if(!node) return minor; 53 | minor += 1; 54 | } 55 | } 56 | 57 | struct device *get_dev_by_major_minor(uint32_t major, uint32_t minor) { 58 | struct device dev; 59 | device_set_major(&dev, major); 60 | device_set_minor(&dev, minor); 61 | struct hash_table_node *node; 62 | node = hash_table_get(&device_table, &dev.hash_node); 63 | return container_of(node, struct device, hash_node); 64 | } 65 | -------------------------------------------------------------------------------- /os/lab6/drivers/virtio/virtio_queue.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | uint16_t virtq_get_desc(struct virtq *vq) { 7 | uint16_t next_idx = vq->next_empty_desc; 8 | if(next_idx != 0xff) { 9 | vq->next_empty_desc = vq->desc[next_idx].next; 10 | } 11 | return next_idx; 12 | } 13 | 14 | void virtq_free_desc(struct virtq *vq, uint16_t idx) { 15 | vq->desc[idx].next = vq->next_empty_desc; 16 | vq->next_empty_desc = idx; 17 | } 18 | 19 | void virtq_free_desc_chain(struct virtq *vq, uint16_t idx) { 20 | uint16_t tmp_idx; 21 | while (vq->desc[idx].flags & VIRTQ_DESC_F_NEXT) 22 | { 23 | tmp_idx = vq->desc[idx].next; 24 | virtq_free_desc(vq, idx); 25 | idx = tmp_idx; 26 | } 27 | virtq_free_desc(vq, idx); 28 | } 29 | 30 | void virtq_put_avail(struct virtq *vq, uint16_t idx) { 31 | vq->avail->ring[vq->avail->idx % VIRTQ_RING_NUM] = idx; 32 | synchronize(); 33 | vq->avail->idx += 1; 34 | synchronize(); 35 | } 36 | 37 | struct virtq_used_elem* virtq_get_used_elem(struct virtq *vq) { 38 | if(vq->used->idx == vq->last_used_idx) { 39 | return NULL; 40 | } else { 41 | struct virtq_used_elem* used_elem = vq->used->ring + (vq->last_used_idx % VIRTQ_RING_NUM); 42 | vq->last_used_idx += 1; 43 | return used_elem; 44 | } 45 | } 46 | 47 | void virtio_queue_init(struct virtq* virtio_queue, uint64_t is_legacy) { 48 | uint64_t virtq_legacy_mem = get_free_page(); 49 | uint64_t virtq_phy_addr = get_free_page(); 50 | uint64_t virtq_vir_addr = VIRTUAL(virtq_phy_addr); 51 | memset((uint8_t *)virtq_vir_addr, 0, VIRTQ_LENGTH); 52 | virtio_queue->num = VIRTQ_RING_NUM; 53 | virtio_queue->desc = (struct virtq_desc *) (virtq_vir_addr); 54 | virtio_queue->avail = (struct virtq_avail *) (virtq_vir_addr + VIRTQ_DESC_TABLE_LENGTH); 55 | if (is_legacy) { 56 | /* Each virtqueue occupies two or more physically-contiguous pages */ 57 | virtio_queue->used = (struct virtq_used *) VIRTUAL(virtq_legacy_mem); 58 | } else { 59 | free_page(virtq_legacy_mem); 60 | virtio_queue->used = (struct virtq_used *) (virtq_vir_addr + VIRTQ_DESC_TABLE_LENGTH + VIRTQ_AVAIL_RING_LENGTH); 61 | } 62 | virtio_queue->last_used_idx = 0; 63 | virtio_queue->physical_addr = virtq_phy_addr; 64 | uint16_t idx; 65 | for (idx = 0; idx < VIRTQ_RING_NUM - 1; ++idx) { 66 | virtio_queue->desc[idx].next = idx + 1; 67 | } 68 | virtio_queue->desc[idx].next = 0xff; 69 | } 70 | -------------------------------------------------------------------------------- /os/lab6/drivers/virtio/virtio_mmio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | void virtio_mmio_probe(struct device *dev) { 10 | struct driver_resource *mem = (struct driver_resource *)device_get_data(dev); 11 | struct virtio_device *device = (struct virtio_device *)mem->map_address; 12 | if(device->magic_value == VIRTIO_MAGIC) { 13 | if(device->version == VIRTIO_VERSION || device->version == VIRTIO_VERSION_LEGACY) { 14 | uint64_t is_legacy = device->version == VIRTIO_VERSION_LEGACY; 15 | if (is_legacy) kprintf("virtio: device is legacy\n"); 16 | if(device->device_id == VIRTIO_DEVICE_ID_BLOCK) { 17 | virtio_block_device_probe(dev, device, is_legacy); 18 | } 19 | if(device->device_id == VIRTIO_DEVICE_ID_NETWORK) { 20 | virtio_net_init(device, is_legacy); 21 | virtio_net_test(device); 22 | } 23 | } 24 | } 25 | } 26 | 27 | void virtio_set_queue(struct virtio_device *device, uint64_t is_legacy, uint32_t queue_idx, uint64_t virtq_phy_addr) { 28 | // 1. select the queue 0 29 | device->queue_sel = queue_idx; 30 | if(!is_legacy) { 31 | // 2. check if the queue is not already in use 32 | assert(device->queue_ready == 0); 33 | } 34 | // 3. check the queue num max 35 | assert(device->queue_num_max >= VIRTQ_RING_NUM); 36 | // 4. allocate and zero the queue memory (see virtio_queue_init) 37 | // 5. set queue num 38 | device->queue_num = VIRTQ_RING_NUM; 39 | // 6. set the queue address 40 | if(is_legacy) { 41 | device->queue_align = PAGE_SIZE; 42 | device->guest_page_size = PAGE_SIZE; 43 | device->queue_pfn = virtq_phy_addr / PAGE_SIZE; 44 | } else { 45 | device->queue_desc_low = VIRTIO_ADDR_LOW32(virtq_phy_addr); 46 | device->queue_desc_high = VIRTIO_ADDR_HIGH32(virtq_phy_addr); 47 | device->queue_driver_low = VIRTIO_ADDR_LOW32(virtq_phy_addr + VIRTQ_DESC_TABLE_LENGTH); 48 | device->queue_driver_high = VIRTIO_ADDR_HIGH32(virtq_phy_addr + VIRTQ_DESC_TABLE_LENGTH); 49 | device->queue_device_low = VIRTIO_ADDR_LOW32(virtq_phy_addr + VIRTQ_DESC_TABLE_LENGTH + VIRTQ_AVAIL_RING_LENGTH); 50 | device->queue_device_high = VIRTIO_ADDR_HIGH32(virtq_phy_addr + VIRTQ_DESC_TABLE_LENGTH + VIRTQ_AVAIL_RING_LENGTH); 51 | // 7. set queue ready 52 | device->queue_ready = 1; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /os/lab6/include/device/virtio/virtio_blk.h: -------------------------------------------------------------------------------- 1 | #ifndef VIRTIO_BLK_H 2 | #define VIRTIO_BLK_H 3 | 4 | #include 5 | #include 6 | 7 | #define VIRTIO_BLK_F_BARRIER (1 << 0) 8 | #define VIRTIO_BLK_F_SIZE_MAX (1 << 1) 9 | #define VIRTIO_BLK_F_SEG_MAX (1 << 2) 10 | #define VIRTIO_BLK_F_GEOMETRY (1 << 4) 11 | #define VIRTIO_BLK_F_RO (1 << 5) 12 | #define VIRTIO_BLK_F_BLK_SIZE (1 << 6) 13 | #define VIRTIO_BLK_F_SCSI (1 << 7) 14 | #define VIRTIO_BLK_F_FLUSH (1 << 9) 15 | #define VIRTIO_BLK_F_TOPOLOGY (1 << 10) 16 | #define VIRTIO_BLK_F_CONFIG_WCE (1 << 11) 17 | #define VIRTIO_BLK_F_DISCARD (1 << 13) 18 | #define VIRTIO_BLK_F_WRITE_ZEROES (1 << 14) 19 | 20 | #define VIRTIO_BLK_CONFIG_OFFSET 0x100 21 | 22 | struct virtio_blk_data { 23 | struct virtio_device *virtio_device; 24 | struct virtq virtio_blk_queue; 25 | }; 26 | 27 | struct virtio_blk_qmap { 28 | uint16_t desp_idx; 29 | struct block_request *request; 30 | 31 | struct hash_table_node hash_node; 32 | }; 33 | 34 | struct virtio_blk_config { 35 | uint64_t capacity; 36 | uint32_t size_max; 37 | uint32_t seg_max; 38 | struct virtio_blk_geometry { 39 | uint16_t cylinders; 40 | uint8_t heads; 41 | uint8_t sectors; 42 | } geometry; 43 | uint32_t blk_size; 44 | struct virtio_blk_topology { 45 | // # of logical blocks per physical block (log2) 46 | uint8_t physical_block_exp; 47 | // offset of first aligned logical block 48 | uint8_t alignment_offset; 49 | // suggested minimum I/O size in blocks 50 | uint16_t min_io_size; 51 | // optimal (suggested maximum) I/O size in blocks 52 | uint32_t opt_io_size; 53 | } topology; 54 | uint8_t writeback; 55 | uint8_t unused0[3]; 56 | uint32_t max_discard_sectors; 57 | uint32_t max_discard_seg; 58 | uint32_t discard_sector_alignment; 59 | uint32_t max_write_zeroes_sectors; 60 | uint32_t max_write_zeroes_seg; 61 | uint8_t write_zeroes_may_unmap; 62 | uint8_t unused1[3]; 63 | }; 64 | 65 | #define VIRTIO_BLK_T_IN 0 66 | #define VIRTIO_BLK_T_OUT 1 67 | #define VIRTIO_BLK_T_FLUSH 4 68 | #define VIRTIO_BLK_T_DISCARD 11 69 | #define VIRTIO_BLK_T_WRITE_ZEROES 13 70 | 71 | #define VIRTIO_BLK_S_OK 0 72 | #define VIRTIO_BLK_S_IOERR 1 73 | #define VIRTIO_BLK_S_UNSUPP 2 74 | 75 | struct virtio_blk_req { 76 | uint32_t type; 77 | uint32_t reserved; 78 | uint64_t sector; 79 | uint8_t status; 80 | }; 81 | 82 | uint64_t virtio_block_device_probe(struct device *dev, struct virtio_device *device, uint64_t is_legacy); 83 | 84 | #endif /* VIRTIO_BLK_H */ 85 | -------------------------------------------------------------------------------- /os/lab4/Makefile: -------------------------------------------------------------------------------- 1 | include tools/toolchain.mk 2 | # 二进制文件,可直接启动系统 3 | KERN_IMG := kernel.img 4 | # 链接得到的 ELF 格式的可执行文件 5 | KERN_BIN := kernel.bin 6 | # 导出的内存布局文件 7 | KERN_MAP := kernel.map 8 | # 导出的符号表(存放了变量等符号信息) 9 | KERN_SYM := kernel.sym 10 | # 反汇编得到的汇编程序 11 | KERN_ASM := kernel.asm 12 | 13 | # -mcmodel=medany 适用于64位RISC-V的CPU(RV64I指令集),使一些C语言代码中的寻址操作可以被编译为auipc指令,用于相对寻址,可使程序的运行与程序被加载的位置无关 14 | # -Wall 将所有的警告信息全开 15 | # -g3 添加适用于gdb的调试信息 16 | # -fno-builtin 不使用 GCC 内建函数 17 | # -fno-stack-protector 不使用栈保护 18 | # -fno-strict-aliasing 允许未定义的类型间强制转换 19 | # -nostdinc 不使用系统标准库 20 | # -I include 优先在include目录搜索头文件 21 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I include 22 | 23 | # .PHONY表示后面这些都是伪造的target,无论同名文件是否存在都会运行 24 | .PHONY : all build run run-gui symbol debug clean disassembly format 25 | 26 | # make 不加参数默认选取第一个 target 运行,此处 all 就是第一个 target,要想生成 target 需要先决条件 build(见下) 27 | all : build 28 | 29 | build : 30 | make -C init build 31 | make -C lib build 32 | make -C trap build 33 | make -C mm build 34 | $(LD) -T tools/linker.ld -Map=$(KERN_MAP) -o $(KERN_BIN) init/entry.o init/main.o lib/libstd.a mm/libmm.a trap/libtrap.a 35 | $(OBJCOPY) $(KERN_BIN) --strip-all -O binary $(KERN_IMG) 36 | # run,启动 TUI 的 QEMU 运行操作系统,先决条件是 build (见上) 37 | # bios 使用 tools/fw_jump.bin (OpenSBI v0.9) 作为 BIOS。 38 | run : build 39 | @$(QEMU) \ 40 | -machine virt \ 41 | -nographic \ 42 | -bios tools/fw_jump.bin \ 43 | -device loader,file=$(KERN_IMG),addr=0x80200000 44 | 45 | # run-gui,启动图形形式的 QEMU 运行操作系统,需要 X 服务器,先决条件是 build (见上) 46 | run-gui : build 47 | @$(QEMU) \ 48 | -machine virt \ 49 | -bios tools/fw_jump.bin \ 50 | -device loader,file=$(KERN_IMG),addr=0x80200000 \ 51 | -monitor stdio \ 52 | 53 | # debug,启动 QEMU 调试支持,使用我们编译的 GDB 连接上 QEMU 的调试端口,使用 tmux 分割终端,使 QEMU 执行和 GDB 调试界面一起显示 54 | debug : build 55 | $(TMUX) new -s debug -d "$(QEMU) \ 56 | -machine virt \ 57 | -s -S \ 58 | -nographic \ 59 | -bios tools/fw_jump.bin \ 60 | -device loader,file=$(KERN_IMG),addr=0x80200000" && $(TMUX) split-window -h "$(GDB) -q -x tools/gdbinit" 61 | $(TMUX) attach-session -t debug 62 | 63 | # 使用 riscv64-linux-gnu-nm 命令输出 kernel.bin 中符号的信息到 kernel.sym,先决条件是 $(KERN_BIN) 64 | # -v:按照地址由低到高排序。 65 | symbol : $(KERN_BIN) 66 | $(READELF) -s $(KERN_BIN) > $(KERN_SYM) 67 | 68 | # 使用 objdump 命令输出 kernel.bin 的反汇编后的汇编代码,先决条件是 $(KERN_BIN) 69 | # -d:仅反汇编代码段内容 70 | disassembly : $(KERN_BIN) 71 | $(OBJDUMP) -d $(KERN_BIN) > $(KERN_ASM) 72 | 73 | # 格式化代码 74 | format: 75 | @find . -regex '.*\.\(c\|h\)' -exec clang-format -i {} \; 76 | # 清理编译产生的文件。 77 | # 命令前面加上“-”,即使这条命令出错,make 也会继续执行后续命令 78 | clean : 79 | -make -C init/ clean 80 | -make -C lib/ clean 81 | -make -C trap/ clean 82 | -make -C mm/ clean 83 | -rm -f $(KERN_BIN) $(KERN_IMG) $(KERN_SYM) $(KERN_ASM) $(KERN_MAP) 84 | -------------------------------------------------------------------------------- /os/lab3/Makefile: -------------------------------------------------------------------------------- 1 | include tools/toolchain.mk 2 | # 二进制文件,可直接启动系统 3 | KERN_IMG := kernel.img 4 | # 链接得到的 ELF 格式的可执行文件 5 | KERN_BIN := kernel.bin 6 | # 导出的内存布局文件 7 | KERN_MAP := kernel.map 8 | # 导出的符号表(存放了变量等符号信息) 9 | KERN_SYM := kernel.sym 10 | # 反汇编得到的汇编程序 11 | KERN_ASM := kernel.asm 12 | 13 | # -mcmodel=medany 适用于64位RISC-V的CPU(RV64I指令集),使一些C语言代码中的寻址操作可以被编译为auipc指令,用于相对寻址,可使程序的运行与程序被加载的位置无关 14 | # -Wall 将所有的警告信息全开 15 | # -g3 添加适用于gdb的调试信息 16 | # -fno-builtin 不使用 GCC 内建函数 17 | # -fno-stack-protector 不使用栈保护 18 | # -fno-strict-aliasing 允许未定义的类型间强制转换 19 | # -nostdinc 不使用系统标准库 20 | # -I include 优先在include目录搜索头文件 21 | CFLAGS := -mcmodel=medany -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I include 22 | 23 | # .PHONY表示后面这些都是伪造的target,无论同名文件是否存在都会运行 24 | .PHONY : all build run run-gui symbol debug clean disassembly format 25 | 26 | # make 不加参数默认选取第一个 target 运行,此处 all 就是第一个 target,要想生成 target 需要先决条件 build(见下) 27 | all : build 28 | 29 | build : 30 | make -C init build 31 | make -C lib build 32 | make -C trap build 33 | make -C mm build 34 | $(LD) -T tools/linker.ld -Map=$(KERN_MAP) -o $(KERN_BIN) init/entry.o init/main.o lib/libstd.a mm/libmm.a trap/libtrap.a 35 | $(OBJCOPY) $(KERN_BIN) --strip-all -O binary $(KERN_IMG) 36 | # run,启动 TUI 的 QEMU 运行操作系统,先决条件是 build (见上) 37 | # bios 使用 tools/fw_jump.bin (OpenSBI v0.9) 作为 BIOS。 38 | run : build 39 | @$(QEMU) \ 40 | -machine virt \ 41 | -nographic \ 42 | -bios tools/fw_jump.bin \ 43 | -device loader,file=$(KERN_IMG),addr=0x80200000 44 | 45 | # run-gui,启动图形形式的 QEMU 运行操作系统,需要 X 服务器,先决条件是 build (见上) 46 | run-gui : build 47 | @$(QEMU) \ 48 | -machine virt \ 49 | -bios tools/fw_jump.bin \ 50 | -device loader,file=$(KERN_IMG),addr=0x80200000 \ 51 | -monitor stdio \ 52 | 53 | # debug,启动 QEMU 调试支持,使用我们编译的 GDB 连接上 QEMU 的调试端口,使用 tmux 分割终端,使 QEMU 执行和 GDB 调试界面一起显示 54 | debug : build 55 | $(TMUX) new -s debug -d "$(QEMU) \ 56 | -machine virt \ 57 | -s -S \ 58 | -nographic \ 59 | -bios tools/fw_jump.bin \ 60 | -device loader,file=$(KERN_IMG),addr=0x80200000" && $(TMUX) split-window -h "$(GDB) -q -x tools/gdbinit" 61 | $(TMUX) attach-session -t debug 62 | 63 | # 使用 riscv64-linux-gnu-nm 命令输出 kernel.bin 中符号的信息到 kernel.sym,先决条件是 $(KERN_BIN) 64 | # -v:按照地址由低到高排序。 65 | symbol : $(KERN_BIN) 66 | $(READELF) -s $(KERN_BIN) > $(KERN_SYM) 67 | 68 | # 使用 objdump 命令输出 kernel.bin 的反汇编后的汇编代码,先决条件是 $(KERN_BIN) 69 | # -d:仅反汇编代码段内容 70 | disassembly : $(KERN_BIN) 71 | $(OBJDUMP) -d $(KERN_BIN) > $(KERN_ASM) 72 | 73 | # 格式化代码 74 | format: 75 | @find . -regex '.*\.\(c\|h\)' -exec clang-format -i {} \; 76 | # 清理编译产生的文件。 77 | # 命令前面加上“-”,即使这条命令出错,make 也会继续执行后续命令 78 | clean : 79 | -make -C init/ clean 80 | -make -C lib/ clean 81 | -make -C trap/ clean 82 | -make -C mm/ clean 83 | -rm -f $(KERN_BIN) $(KERN_IMG) $(KERN_SYM) $(KERN_ASM) $(KERN_MAP) 84 | -------------------------------------------------------------------------------- /os/lab5/Makefile: -------------------------------------------------------------------------------- 1 | include tools/toolchain.mk 2 | # 二进制文件,可直接启动系统 3 | KERN_IMG := kernel.img 4 | # 链接得到的 ELF 格式的可执行文件 5 | KERN_BIN := kernel.bin 6 | # 导出的内存布局文件 7 | KERN_MAP := kernel.map 8 | # 导出的符号表(存放了变量等符号信息) 9 | KERN_SYM := kernel.sym 10 | # 反汇编得到的汇编程序 11 | KERN_ASM := kernel.asm 12 | 13 | # -mcmodel=medany 适用于64位RISC-V的CPU(RV64I指令集),使一些C语言代码中的寻址操作可以被编译为auipc指令,用于相对寻址,可使程序的运行与程序被加载的位置无关 14 | # -Wall 将所有的警告信息全开 15 | # -g3 添加适用于gdb的调试信息 16 | # -fno-builtin 不使用 GCC 内建函数 17 | # -fno-stack-protector 不使用栈保护 18 | # -fno-strict-aliasing 允许未定义的类型间强制转换 19 | # -nostdinc 不使用系统标准库 20 | # -I include 优先在include目录搜索头文件 21 | CFLAGS := -mcmodel=medany -fno-pie -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I include 22 | 23 | # .PHONY表示后面这些都是伪造的target,无论同名文件是否存在都会运行 24 | .PHONY : all build run run-gui symbol debug clean disassembly format 25 | 26 | # make 不加参数默认选取第一个 target 运行,此处 all 就是第一个 target,要想生成 target 需要先决条件 build(见下) 27 | all : build 28 | 29 | build : 30 | make -C init build 31 | make -C lib build 32 | make -C mm build 33 | make -C kernel build 34 | $(LD) -T tools/linker.ld -Map=$(KERN_MAP) -o $(KERN_BIN) init/entry.o init/main.o mm/libmm.a kernel/libkernel.a lib/libstd.a 35 | $(OBJCOPY) $(KERN_BIN) --strip-all -O binary $(KERN_IMG) 36 | # run,启动 TUI 的 QEMU 运行操作系统,先决条件是 build (见上) 37 | # bios 使用 tools/fw_jump.bin (OpenSBI v0.9) 作为 BIOS。 38 | run : build 39 | @$(QEMU) \ 40 | -machine virt \ 41 | -nographic \ 42 | -bios tools/fw_jump.bin \ 43 | -device loader,file=$(KERN_IMG),addr=0x80200000 44 | 45 | # run-gui,启动图形形式的 QEMU 运行操作系统,需要 X 服务器,先决条件是 build (见上) 46 | run-gui : build 47 | @$(QEMU) \ 48 | -machine virt \ 49 | -bios tools/fw_jump.bin \ 50 | -device loader,file=$(KERN_IMG),addr=0x80200000 \ 51 | -monitor stdio \ 52 | 53 | # debug,启动 QEMU 调试支持,使用我们编译的 GDB 连接上 QEMU 的调试端口,使用 tmux 分割终端,使 QEMU 执行和 GDB 调试界面一起显示 54 | debug : build 55 | $(TMUX) new -s debug -d "$(QEMU) \ 56 | -machine virt \ 57 | -s -S \ 58 | -nographic \ 59 | -bios tools/fw_jump.bin \ 60 | -device loader,file=$(KERN_IMG),addr=0x80200000" && $(TMUX) split-window -h "$(GDB) -q -x tools/gdbinit" 61 | $(TMUX) attach-session -t debug 62 | 63 | # 使用 riscv64-linux-gnu-nm 命令输出 kernel.bin 中符号的信息到 kernel.sym,先决条件是 $(KERN_BIN) 64 | # -v:按照地址由低到高排序。 65 | symbol : $(KERN_BIN) 66 | $(READELF) -s $(KERN_BIN) > $(KERN_SYM) 67 | 68 | # 使用 objdump 命令输出 kernel.bin 的反汇编后的汇编代码,先决条件是 $(KERN_BIN) 69 | # -d:仅反汇编代码段内容 70 | disassembly : $(KERN_BIN) 71 | $(OBJDUMP) -d $(KERN_BIN) > $(KERN_ASM) 72 | 73 | # 格式化代码 74 | format: 75 | @find . -regex '.*\.\(c\|h\)' -exec clang-format -i {} \; 76 | # 清理编译产生的文件。 77 | # 命令前面加上“-”,即使这条命令出错,make 也会继续执行后续命令 78 | clean : 79 | -make -C init/ clean 80 | -make -C lib/ clean 81 | -make -C kernel/ clean 82 | -make -C mm/ clean 83 | -rm -f $(KERN_BIN) $(KERN_IMG) $(KERN_SYM) $(KERN_ASM) $(KERN_MAP) 84 | -------------------------------------------------------------------------------- /os/lab6/include/device/virtio/virtio_mmio.h: -------------------------------------------------------------------------------- 1 | #ifndef VIRTIO_MMIO_H 2 | #define VIRTIO_MMIO_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define VIRTIO_MAGIC 0x74726976 10 | #define VIRTIO_VERSION_LEGACY 0x1 11 | #define VIRTIO_VERSION 0x2 12 | 13 | #define VIRTIO_DEVICE_ID_NETWORK 1 14 | #define VIRTIO_DEVICE_ID_BLOCK 2 15 | #define VIRTIO_DEVICE_ID_CONSOLE 3 16 | #define VIRTIO_DEVICE_ID_INPUT 18 17 | 18 | #define VIRTIO_ADDR_LOW32(addr) ((uint32_t)((uint64_t)(addr) & 0xFFFFFFFF)) 19 | #define VIRTIO_ADDR_HIGH32(addr) ((uint32_t)((uint64_t)(addr) >> 32)) 20 | 21 | struct virtio_device { 22 | volatile uint32_t magic_value; // 0x00 23 | volatile uint32_t version; // 0x04 24 | volatile uint32_t device_id; // 0x08 25 | volatile uint32_t vendor_id; // 0x0c 26 | volatile uint32_t device_features; // 0x10 27 | volatile uint32_t device_features_sel; // 0x14 28 | volatile uint32_t padding_0[2]; 29 | volatile uint32_t driver_features; // 0x20 30 | volatile uint32_t driver_features_sel; // 0x24 31 | volatile uint32_t guest_page_size; // 0x28 32 | volatile uint32_t padding_1; 33 | volatile uint32_t queue_sel; // 0x30 34 | volatile uint32_t queue_num_max; // 0x34 35 | volatile uint32_t queue_num; // 0x38 36 | volatile uint32_t queue_align; // 0x3c 37 | volatile uint32_t queue_pfn; // 0x40 38 | volatile uint32_t queue_ready; // 0x44 39 | volatile uint32_t padding_2[2]; 40 | volatile uint32_t queue_notify; // 0x50 41 | volatile uint32_t padding_3[3]; 42 | volatile uint32_t interrupt_status; // 0x60 43 | volatile uint32_t interrupt_ack; // 0x64 44 | volatile uint32_t padding_4[2]; 45 | volatile uint32_t status; // 0x70 46 | volatile uint32_t padding_5[3]; 47 | volatile uint32_t queue_desc_low; // 0x80 48 | volatile uint32_t queue_desc_high; // 0x84 49 | volatile uint32_t padding_6[2]; 50 | volatile uint32_t queue_driver_low; // 0x90 51 | volatile uint32_t queue_driver_high; // 0x94 52 | volatile uint32_t padding_7[2]; 53 | volatile uint32_t queue_device_low; // 0xa0 54 | volatile uint32_t queue_device_high; // 0xa4 55 | }; 56 | 57 | #define VIRTIO_STATUS_RESET 0 58 | #define VIRTIO_STATUS_ACKNOWLEDGE 1 59 | #define VIRTIO_STATUS_DRIVER 2 60 | #define VIRTIO_STATUS_FAILED 128 61 | #define VIRTIO_STATUS_FEATURES_OK 8 62 | #define VIRTIO_STATUS_DRIVER_OK 4 63 | #define VIRTIO_STATUS_DEVICE_NEEDS_RESET 64 64 | 65 | void virtio_mmio_probe(struct device *dev); 66 | void virtio_set_queue(struct virtio_device *device, uint64_t is_legacy, uint32_t queue_idx, uint64_t virtq_phy_addr); 67 | 68 | #endif /* VIRTIO_MMIO */ 69 | -------------------------------------------------------------------------------- /os/lab5/kernel/syscall.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file syscall.c 3 | * @brief 定义系统调用表,实现大部分系统调用 4 | * 5 | * 所有系统调用都由`sys_xxx()`实现,`sys_xxx()`以中断堆栈指针为 6 | * 参数。系统调用具体的参数类型和大小从堆栈指针中获取。通过`syscall(nr, ...)` 7 | * 调用系统调用。 8 | * 9 | */ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | extern long sys_init(struct trapframe *); 19 | extern long sys_fork(struct trapframe *); 20 | 21 | /** 22 | * @brief 测试 fork() 是否正常工作 23 | * 24 | * 如果`fork()`和虚拟内存正常工作,将实现写时复制, 25 | * 不同进程的同一局部变量可以被写入不同的值。 26 | * 暂时还未实现字符 IO,因此只能在内核态下以这种办法 27 | * 检测`fork()`和写时复制是否正常。 28 | * 29 | * @param 参数1 - 局部变量(8 字节) 30 | */ 31 | static long sys_test_fork(struct trapframe *tf) 32 | { 33 | kprintf("process %u: local - %u\n", 34 | (uint64_t)current->pid, 35 | tf->gpr.a0); 36 | return 0; 37 | } 38 | 39 | /** 40 | * @brief 获取当前进程 PID 41 | */ 42 | static long sys_getpid(struct trapframe *tf) 43 | { 44 | return current->pid; 45 | } 46 | 47 | /** 48 | * @brief 获取当前进程父进程 ID 49 | */ 50 | static long sys_getppid(struct trapframe *tf) 51 | { 52 | if (current == tasks[0]) { 53 | return 0; 54 | } else { 55 | return current->p_pptr->pid; 56 | } 57 | } 58 | 59 | /** 60 | * @brief 系统调用表 61 | * 存储所有系统调用的指针的数组,系统调用号是其中的下标。 62 | * 所有系统调用都通过系统调用表调用 63 | */ 64 | fn_ptr syscall_table[] = {sys_init, sys_fork, sys_test_fork, sys_getpid, sys_getppid}; 65 | 66 | /** 67 | * @brief 通过系统调用号调用对应的系统调用 68 | * 69 | * @param number 系统调用号 70 | * @param ... 系统调用参数 71 | * @note 本实现中所有系统调用都仅在失败时返回负数,但实际上极小一部分 UNIX 系统调用(如 72 | * `getpriority()`的正常返回值可能是负数的)。 73 | */ 74 | long syscall(long number, ...) 75 | { 76 | va_list ap; 77 | va_start(ap, number); 78 | long arg1 = va_arg(ap, long); 79 | long arg2 = va_arg(ap, long); 80 | long arg3 = va_arg(ap, long); 81 | long arg4 = va_arg(ap, long); 82 | long arg5 = va_arg(ap, long); 83 | long arg6 = va_arg(ap, long); 84 | long ret = 0; 85 | va_end(ap); 86 | if (number > 0 && number < NR_TASKS) { 87 | /* 小心寄存器变量被覆盖 */ 88 | register long a0 asm("a0") = arg1; 89 | register long a1 asm("a1") = arg2; 90 | register long a2 asm("a2") = arg3; 91 | register long a3 asm("a3") = arg4; 92 | register long a4 asm("a4") = arg5; 93 | register long a5 asm("a5") = arg6; 94 | register long a7 asm("a7") = number; 95 | __asm__ __volatile__ ("ecall\n\t" 96 | :"=r"(a0) 97 | :"r" (a1), "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a7) 98 | :"memory"); 99 | ret = a0; 100 | } else { 101 | panic("Try to call unknown system call"); 102 | } 103 | if (ret < 0) { 104 | errno = -ret; 105 | return -1; 106 | } 107 | return ret; 108 | } 109 | -------------------------------------------------------------------------------- /os/lab6/Makefile: -------------------------------------------------------------------------------- 1 | include tools/toolchain.mk 2 | # 二进制文件,可直接启动系统 3 | KERN_IMG := kernel.img 4 | # 链接得到的 ELF 格式的可执行文件 5 | KERN_BIN := kernel.bin 6 | # 导出的内存布局文件 7 | KERN_MAP := kernel.map 8 | # 导出的符号表(存放了变量等符号信息) 9 | KERN_SYM := kernel.sym 10 | # 反汇编得到的汇编程序 11 | KERN_ASM := kernel.asm 12 | 13 | # -mcmodel=medany 适用于64位RISC-V的CPU(RV64I指令集),使一些C语言代码中的寻址操作可以被编译为auipc指令,用于相对寻址,可使程序的运行与程序被加载的位置无关 14 | # -Wall 将所有的警告信息全开 15 | # -g3 添加适用于gdb的调试信息 16 | # -fno-builtin 不使用 GCC 内建函数 17 | # -fno-stack-protector 不使用栈保护 18 | # -fno-strict-aliasing 允许未定义的类型间强制转换 19 | # -nostdinc 不使用系统标准库 20 | # -I include 优先在include目录搜索头文件 21 | CFLAGS := -mcmodel=medany -fno-pie -Wall -g3 -fno-builtin -fno-stack-protector -fno-strict-aliasing -nostdinc -I include 22 | 23 | # .PHONY表示后面这些都是伪造的target,无论同名文件是否存在都会运行 24 | .PHONY : all build run run-gui symbol debug clean disassembly format 25 | 26 | # make 不加参数默认选取第一个 target 运行,此处 all 就是第一个 target,要想生成 target 需要先决条件 build(见下) 27 | all : build 28 | 29 | build : 30 | make -C init build 31 | make -C lib build 32 | make -C mm build 33 | make -C kernel build 34 | make -C drivers build 35 | make -C fs build 36 | $(LD) -T tools/linker.ld -Map=$(KERN_MAP) -o $(KERN_BIN) init/entry.o init/main.o kernel/libkernel.a fs/libfs.a drivers/libdrivers.a mm/libmm.a lib/libstd.a 37 | $(OBJCOPY) $(KERN_BIN) --strip-all -O binary $(KERN_IMG) 38 | # run,启动 TUI 的 QEMU 运行操作系统,先决条件是 build (见上) 39 | # bios 使用 tools/fw_jump.bin (OpenSBI v0.9) 作为 BIOS。 40 | run : build 41 | @$(QEMU) \ 42 | -machine virt \ 43 | -nographic \ 44 | -bios tools/fw_jump.bin \ 45 | -device loader,file=$(KERN_IMG),addr=0x80200000 46 | 47 | # run-gui,启动图形形式的 QEMU 运行操作系统,需要 X 服务器,先决条件是 build (见上) 48 | run-gui : build 49 | @$(QEMU) \ 50 | -machine virt \ 51 | -bios tools/fw_jump.bin \ 52 | -device loader,file=$(KERN_IMG),addr=0x80200000 \ 53 | -monitor stdio \ 54 | 55 | # debug,启动 QEMU 调试支持,使用我们编译的 GDB 连接上 QEMU 的调试端口,使用 tmux 分割终端,使 QEMU 执行和 GDB 调试界面一起显示 56 | debug : build 57 | $(TMUX) new -s debug -d "$(QEMU) \ 58 | -machine virt \ 59 | -s -S \ 60 | -nographic \ 61 | -bios tools/fw_jump.bin \ 62 | -device loader,file=$(KERN_IMG),addr=0x80200000" && $(TMUX) split-window -h "$(GDB) -q -x tools/gdbinit" 63 | $(TMUX) attach-session -t debug 64 | 65 | # 使用 riscv64-linux-gnu-nm 命令输出 kernel.bin 中符号的信息到 kernel.sym,先决条件是 $(KERN_BIN) 66 | # -v:按照地址由低到高排序。 67 | symbol : $(KERN_BIN) 68 | $(READELF) -s $(KERN_BIN) > $(KERN_SYM) 69 | 70 | # 使用 objdump 命令输出 kernel.bin 的反汇编后的汇编代码,先决条件是 $(KERN_BIN) 71 | # -d:仅反汇编代码段内容 72 | disassembly : $(KERN_BIN) 73 | $(OBJDUMP) -d $(KERN_BIN) > $(KERN_ASM) 74 | 75 | # 格式化代码 76 | format: 77 | @find . -regex '.*\.\(c\|h\)' -exec clang-format -i {} \; 78 | # 清理编译产生的文件。 79 | # 命令前面加上“-”,即使这条命令出错,make 也会继续执行后续命令 80 | clean : 81 | -make -C init/ clean 82 | -make -C lib/ clean 83 | -make -C kernel/ clean 84 | -make -C mm/ clean 85 | -make -C drivers/ clean 86 | -make -C fs/ clean 87 | -rm -f $(KERN_BIN) $(KERN_IMG) $(KERN_SYM) $(KERN_ASM) $(KERN_MAP) 88 | -------------------------------------------------------------------------------- /os/lab5/kernel/fork.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file fork.c 3 | * @brief 实现系统调用 fork() 4 | * 5 | * fork() 的原型为`pid_t fork(void)`,返回值(PID)不一定是整数。 6 | * 这里将 PID 实现为整数。 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /** 15 | * @brief 将当前进程的虚拟地址空间拷贝给进程 p 16 | * 17 | * @param p task_struct 指针 18 | */ 19 | int copy_mem(struct task_struct * p) 20 | { 21 | copy_page_tables(0, p->pg_dir, 0, current->start_kernel); 22 | copy_page_tables(current->start_kernel, p->pg_dir, p->start_kernel, 0x100000000 - current->start_kernel); 23 | return 1; 24 | } 25 | 26 | /** 27 | * @brief 取消从 addr 开始 size 字节的写保护 28 | * 29 | * @param addr 起始虚拟地址 30 | * @param size 字节数 31 | */ 32 | void verify_area(uint64_t addr,int size) 33 | { 34 | size += addr & 0xFFF; 35 | addr &= ~0x00000FFF; 36 | while (size>0) { 37 | size -= 4096; 38 | write_verify(addr); 39 | addr += 4096; 40 | } 41 | } 42 | /** 43 | * @brief 获取可用的 PID 44 | * 45 | * 返回的子进程 PID 不等于任何进程的 PID 和 PGID(进程组 ID)。 46 | * PID 被实现为`tasks[]`数组下标。 47 | * 48 | * @return 返回可用的 PID;无可用 PID 则返回 NR_TASKS。 49 | */ 50 | static uint32_t find_empty_process() 51 | { 52 | uint32_t pid = 0; 53 | size_t i; 54 | while (++pid < NR_TASKS) { 55 | for (i = 0; i < NR_TASKS; ++i) { 56 | if (tasks[i] && (pid == i || pid == tasks[i]->pgid)) { 57 | break; 58 | } 59 | } 60 | if (i == NR_TASKS) { 61 | break; 62 | } 63 | } 64 | return pid; 65 | } 66 | 67 | /** 68 | * @brief 实现系统调用 fork() 69 | */ 70 | long sys_fork(struct trapframe *tf) 71 | { 72 | uint32_t nr = find_empty_process(); 73 | if (nr == NR_TASKS) { 74 | return -EAGAIN; 75 | } 76 | uint64_t page = get_free_page(); 77 | if (!page) { 78 | return -EAGAIN; 79 | } 80 | struct task_struct* p = (struct task_struct *)VIRTUAL(page); 81 | 82 | uint64_t page_dir = get_free_page(); 83 | if (!page_dir) { 84 | free_page(page); 85 | return -EAGAIN; 86 | } 87 | 88 | memcpy(p, current, sizeof(struct task_struct) - sizeof(struct trapframe)); 89 | p->context = *tf; 90 | p->context.epc += 4; 91 | p->pg_dir = (uint64_t *)VIRTUAL(page_dir); 92 | tasks[nr] = p; 93 | kprintf("process %x forks process %x\n", (uint64_t)current->pid, (uint64_t)nr); 94 | 95 | /* 在此之间发生错误,将不会创建进程,系统处于安全状态 */ 96 | copy_mem(p); 97 | 98 | p->state = TASK_UNINTERRUPTIBLE; 99 | p->pid = nr; 100 | p->counter = p->priority = 15; 101 | p->start_time = ticks; 102 | p->p_pptr = current; 103 | p->p_osptr = current->p_ysptr; 104 | if (p->p_osptr) { 105 | p->p_osptr->p_ysptr = current; 106 | } 107 | current->p_cptr = p; 108 | p->context.gpr.a0 = 0; /* 新进程 fork() 返回值 */ 109 | p->state= TASK_RUNNING; 110 | return nr; 111 | } 112 | -------------------------------------------------------------------------------- /os/lab6/kernel/fork.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file fork.c 3 | * @brief 实现系统调用 fork() 4 | * 5 | * fork() 的原型为`pid_t fork(void)`,返回值(PID)不一定是整数。 6 | * 这里将 PID 实现为整数。 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /** 15 | * @brief 将当前进程的虚拟地址空间拷贝给进程 p 16 | * 17 | * @param p task_struct 指针 18 | */ 19 | int copy_mem(struct task_struct * p) 20 | { 21 | copy_page_tables(0, p->pg_dir, 0, current->start_kernel); 22 | copy_page_tables(current->start_kernel, p->pg_dir, p->start_kernel, 0x100000000 - current->start_kernel); 23 | return 1; 24 | } 25 | 26 | /** 27 | * @brief 取消从 addr 开始 size 字节的写保护 28 | * 29 | * @param addr 起始虚拟地址 30 | * @param size 字节数 31 | */ 32 | void verify_area(uint64_t addr,int size) 33 | { 34 | size += addr & 0xFFF; 35 | addr &= ~0x00000FFF; 36 | while (size>0) { 37 | size -= 4096; 38 | write_verify(addr); 39 | addr += 4096; 40 | } 41 | } 42 | /** 43 | * @brief 获取可用的 PID 44 | * 45 | * 返回的子进程 PID 不等于任何进程的 PID 和 PGID(进程组 ID)。 46 | * PID 被实现为`tasks[]`数组下标。 47 | * 48 | * @return 返回可用的 PID;无可用 PID 则返回 NR_TASKS。 49 | */ 50 | static uint32_t find_empty_process() 51 | { 52 | uint32_t pid = 0; 53 | size_t i; 54 | while (++pid < NR_TASKS) { 55 | for (i = 0; i < NR_TASKS; ++i) { 56 | if (tasks[i] && (pid == i || pid == tasks[i]->pgid)) { 57 | break; 58 | } 59 | } 60 | if (i == NR_TASKS) { 61 | break; 62 | } 63 | } 64 | return pid; 65 | } 66 | 67 | /** 68 | * @brief 实现系统调用 fork() 69 | */ 70 | long sys_fork(struct trapframe *tf) 71 | { 72 | uint32_t nr = find_empty_process(); 73 | if (nr == NR_TASKS) { 74 | return -EAGAIN; 75 | } 76 | uint64_t page = get_free_page(); 77 | if (!page) { 78 | return -EAGAIN; 79 | } 80 | struct task_struct* p = (struct task_struct *)VIRTUAL(page); 81 | 82 | uint64_t page_dir = get_free_page(); 83 | if (!page_dir) { 84 | free_page(page); 85 | return -EAGAIN; 86 | } 87 | 88 | memcpy(p, current, sizeof(struct task_struct) - sizeof(struct trapframe)); 89 | p->context = *tf; 90 | p->context.epc += INST_LEN(p->context.epc); 91 | p->pg_dir = (uint64_t *)VIRTUAL(page_dir); 92 | tasks[nr] = p; 93 | kprintf("process %x forks process %x\n", (uint64_t)current->pid, (uint64_t)nr); 94 | 95 | /* 在此之间发生错误,将不会创建进程,系统处于安全状态 */ 96 | copy_mem(p); 97 | 98 | p->state = TASK_UNINTERRUPTIBLE; 99 | p->pid = nr; 100 | p->counter = p->priority = 15; 101 | p->start_time = ticks; 102 | p->p_pptr = current; 103 | p->p_osptr = current->p_ysptr; 104 | if (p->p_osptr) { 105 | p->p_osptr->p_ysptr = current; 106 | } 107 | current->p_cptr = p; 108 | p->context.gpr.a0 = 0; /* 新进程 fork() 返回值 */ 109 | p->state= TASK_RUNNING; 110 | return nr; 111 | } 112 | -------------------------------------------------------------------------------- /os/lab6/include/utils/linked_list.h: -------------------------------------------------------------------------------- 1 | #ifndef LINKED_LIST_H 2 | #define LINKED_LIST_H 3 | 4 | #include 5 | 6 | // 一个带头结点的双向循环链表,最后一个节点接到链表头,适用于放在结构体中,配合 container_of 函数使用 7 | struct linked_list_node { 8 | struct linked_list_node *prev; 9 | struct linked_list_node *next; 10 | }; 11 | 12 | // 初始化头结点 13 | static inline void linked_list_init(struct linked_list_node *head) { 14 | head->prev = head; 15 | head->next = head; 16 | } 17 | 18 | // 在某节点后插入新节点 19 | static inline void linked_list_insert_after(struct linked_list_node *target, struct linked_list_node *node) { 20 | node->next = target->next; 21 | node->prev = target; 22 | target->next = node; 23 | node->next->prev = node; 24 | } 25 | 26 | // 在某节点前插入新节点 27 | static inline void linked_list_insert_before(struct linked_list_node *target, struct linked_list_node *node) { 28 | node->prev = target->prev; 29 | node->next = target; 30 | target->prev = node; 31 | node->prev->next = node; 32 | } 33 | 34 | // 删除某节点,注意需要自行 free 包含链表的整个结构体 35 | static inline void linked_list_remove(struct linked_list_node *target) { 36 | target->prev->next = target->next; 37 | target->next->prev = target->prev; 38 | } 39 | 40 | // 判断链表是否为空 41 | static inline uint64_t linked_list_empty(struct linked_list_node *head) { 42 | return head->next == head; 43 | } 44 | 45 | // 返回链表第一个节点(除头结点外,若链表为空则返回 NULL) 46 | static inline struct linked_list_node *linked_list_first(struct linked_list_node *head) { 47 | if (linked_list_empty(head)) return (struct linked_list_node *)NULL; 48 | return head->next; 49 | } 50 | 51 | // 返回链表最后一个节点(若链表为空则返回 NULL) 52 | static inline struct linked_list_node *linked_list_last(struct linked_list_node *head) { 53 | if (linked_list_empty(head)) return (struct linked_list_node *)NULL; 54 | return head->prev; 55 | } 56 | 57 | // 将节点插入至链表尾 58 | static inline void linked_list_push(struct linked_list_node *head, struct linked_list_node *node) { 59 | linked_list_insert_before(head, node); 60 | } 61 | 62 | // 返回链表尾节点并从删除 63 | static inline struct linked_list_node *linked_list_pop(struct linked_list_node *head) { 64 | if (linked_list_empty(head)) return (struct linked_list_node *)NULL; 65 | struct linked_list_node *last_node = linked_list_last(head); 66 | linked_list_remove(last_node); 67 | return last_node; 68 | } 69 | 70 | // 将节点插入至链表第一个节点 71 | static inline void linked_list_unshift(struct linked_list_node *head, struct linked_list_node *node) { 72 | linked_list_insert_after(head, node); 73 | } 74 | 75 | // 返回链表第一个节点并从删除 76 | static inline struct linked_list_node *linked_list_shift(struct linked_list_node *head) { 77 | if (linked_list_empty(head)) return (struct linked_list_node *)NULL; 78 | struct linked_list_node *first_node = linked_list_first(head); 79 | linked_list_remove(first_node); 80 | return first_node; 81 | } 82 | 83 | // 遍历链表 84 | #define for_each_linked_list_node(node, list_ptr) for (node = (list_ptr)->next; node != (list_ptr); node = node->next) 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /os/lab2/trap/trapentry.S: -------------------------------------------------------------------------------- 1 | # 定义常量XLENB=8(每个寄存器 64 bit= 8 bytes) 2 | .equ XLENB, 8 3 | 4 | # 定义宏:LOAD,读取内存地址 sp+a2*8 的值到寄存器 a1 5 | .macro LOAD a1, a2 6 | ld \a1, \a2*XLENB(sp) 7 | .endm 8 | 9 | # 定义宏:STORE,将寄存器 a1 的值保存到内存地址 sp+a2*8 10 | .macro STORE a1, a2 11 | sd \a1, \a2*XLENB(sp) 12 | .endm 13 | 14 | # 定义宏:保存上下文(所有通用寄存器及额外的CSR寄存器) 15 | .macro SAVE_ALL 16 | # 借用无用的寄存器 sscratch 保存原 sp 17 | csrw sscratch,sp 18 | 19 | # 将栈指针下移为TrapFrame预留足够的空间用于将所有通用寄存器值存入栈中(36个寄存器的空间) 20 | addi sp, sp, -36*XLENB 21 | # 保存所有通用寄存器,除了 x2 (x2就是sp,sp 本应保存的是发生中断前的值,这个值目前被交换到了 sscratch 中,因此留到后面处理。) 22 | STORE x1, 1 23 | STORE x3, 3 24 | STORE x4, 4 25 | STORE x5, 5 26 | STORE x6, 6 27 | STORE x7, 7 28 | STORE x8, 8 29 | STORE x9, 9 30 | STORE x10, 10 31 | STORE x11, 11 32 | STORE x12, 12 33 | STORE x13, 13 34 | STORE x14, 14 35 | STORE x15, 15 36 | STORE x16, 16 37 | STORE x17, 17 38 | STORE x18, 18 39 | STORE x19, 19 40 | STORE x20, 20 41 | STORE x21, 21 42 | STORE x22, 22 43 | STORE x23, 23 44 | STORE x24, 24 45 | STORE x25, 25 46 | STORE x26, 26 47 | STORE x27, 27 48 | STORE x28, 28 49 | STORE x29, 29 50 | STORE x30, 30 51 | STORE x31, 31 52 | 53 | # 保存完x0-x31之后这些寄存器就可以随意使用了,下面马上用到: 54 | # 读取sscratch到s0,借s0中转后将原sp存入内存 55 | csrr s0, sscratch 56 | 57 | # 读取 sstatus, sepc, stval, scause寄存器的值到s0-s4(x1-x31中的特定几个)寄存器 58 | csrr s1, sstatus 59 | csrr s2, sepc 60 | csrr s3, stval 61 | csrr s4, scause 62 | 63 | # 存储 sp, sstatus, sepc, sbadvaddr, scause 到栈中 64 | # 其中把s0存到x2(sp)的位置以便于返回时直接恢复栈 65 | STORE s0, 2 66 | STORE s1, 32 67 | STORE s2, 33 68 | STORE s3, 34 69 | STORE s4, 35 70 | .endm 71 | 72 | # 定义宏:恢复寄存器 73 | .macro RESTORE_ALL 74 | LOAD s1, 32 # s1 = sstatus 75 | LOAD s2, 33 # s2 = sepc 76 | # 恢复 sstatus, sepc 77 | csrw sstatus, s1 78 | csrw sepc, s2 79 | 80 | # 恢复除了 x2 (sp) 以外的其余通用寄存器 81 | LOAD x1, 1 82 | LOAD x3, 3 83 | LOAD x4, 4 84 | LOAD x5, 5 85 | LOAD x6, 6 86 | LOAD x7, 7 87 | LOAD x8, 8 88 | LOAD x9, 9 89 | LOAD x10, 10 90 | LOAD x11, 11 91 | LOAD x12, 12 92 | LOAD x13, 13 93 | LOAD x14, 14 94 | LOAD x15, 15 95 | LOAD x16, 16 96 | LOAD x17, 17 97 | LOAD x18, 18 98 | LOAD x19, 19 99 | LOAD x20, 20 100 | LOAD x21, 21 101 | LOAD x22, 22 102 | LOAD x23, 23 103 | LOAD x24, 24 104 | LOAD x25, 25 105 | LOAD x26, 26 106 | LOAD x27, 27 107 | LOAD x28, 28 108 | LOAD x29, 29 109 | LOAD x30, 30 110 | LOAD x31, 31 111 | # 最后恢复栈指针(x2, sp)为原指针(无论是用户态还是内核态) 112 | LOAD x2, 2 113 | .endm 114 | 115 | # 代码段开始 116 | .section .text 117 | .globl __alltraps 118 | .align 4 119 | __alltraps: 120 | # 保存上下文 121 | SAVE_ALL 122 | # 将sp存入a0作为trap函数的第一个参数 123 | mv a0, sp 124 | # 跳转到trap函数执行(PC+4的值存入了x1寄存器),执行结束后会返回到这里继续向下执行恢复上下文 125 | call trap 126 | .globl __trapret 127 | __trapret: 128 | # 恢复上下文 129 | move sp, a0 130 | RESTORE_ALL 131 | # 从内核态中断中返回 132 | sret 133 | -------------------------------------------------------------------------------- /os/lab3/trap/trapentry.S: -------------------------------------------------------------------------------- 1 | # 定义常量XLENB=8(每个寄存器 64 bit= 8 bytes) 2 | .equ XLENB, 8 3 | 4 | # 定义宏:LOAD,读取内存地址 sp+a2*8 的值到寄存器 a1 5 | .macro LOAD a1, a2 6 | ld \a1, \a2*XLENB(sp) 7 | .endm 8 | 9 | # 定义宏:STORE,将寄存器 a1 的值保存到内存地址 sp+a2*8 10 | .macro STORE a1, a2 11 | sd \a1, \a2*XLENB(sp) 12 | .endm 13 | 14 | # 定义宏:保存上下文(所有通用寄存器及额外的CSR寄存器) 15 | .macro SAVE_ALL 16 | # 借用无用的寄存器 sscratch 保存原 sp 17 | csrw sscratch,sp 18 | 19 | # 将栈指针下移为TrapFrame预留足够的空间用于将所有通用寄存器值存入栈中(36个寄存器的空间) 20 | addi sp, sp, -36*XLENB 21 | # 保存所有通用寄存器,除了 x2 (x2就是sp,sp 本应保存的是发生中断前的值,这个值目前被交换到了 sscratch 中,因此留到后面处理。) 22 | STORE x1, 1 23 | STORE x3, 3 24 | STORE x4, 4 25 | STORE x5, 5 26 | STORE x6, 6 27 | STORE x7, 7 28 | STORE x8, 8 29 | STORE x9, 9 30 | STORE x10, 10 31 | STORE x11, 11 32 | STORE x12, 12 33 | STORE x13, 13 34 | STORE x14, 14 35 | STORE x15, 15 36 | STORE x16, 16 37 | STORE x17, 17 38 | STORE x18, 18 39 | STORE x19, 19 40 | STORE x20, 20 41 | STORE x21, 21 42 | STORE x22, 22 43 | STORE x23, 23 44 | STORE x24, 24 45 | STORE x25, 25 46 | STORE x26, 26 47 | STORE x27, 27 48 | STORE x28, 28 49 | STORE x29, 29 50 | STORE x30, 30 51 | STORE x31, 31 52 | 53 | # 保存完x0-x31之后这些寄存器就可以随意使用了,下面马上用到: 54 | # 读取sscratch到s0,借s0中转后将原sp存入内存 55 | csrr s0, sscratch 56 | 57 | # 读取 sstatus, sepc, stval, scause寄存器的值到s0-s4(x1-x31中的特定几个)寄存器 58 | csrr s1, sstatus 59 | csrr s2, sepc 60 | csrr s3, stval 61 | csrr s4, scause 62 | 63 | # 存储 sp, sstatus, sepc, sbadvaddr, scause 到栈中 64 | # 其中把s0存到x2(sp)的位置以便于返回时直接恢复栈 65 | STORE s0, 2 66 | STORE s1, 32 67 | STORE s2, 33 68 | STORE s3, 34 69 | STORE s4, 35 70 | .endm 71 | 72 | # 定义宏:恢复寄存器 73 | .macro RESTORE_ALL 74 | LOAD s1, 32 # s1 = sstatus 75 | LOAD s2, 33 # s2 = sepc 76 | # 恢复 sstatus, sepc 77 | csrw sstatus, s1 78 | csrw sepc, s2 79 | 80 | # 恢复除了 x2 (sp) 以外的其余通用寄存器 81 | LOAD x1, 1 82 | LOAD x3, 3 83 | LOAD x4, 4 84 | LOAD x5, 5 85 | LOAD x6, 6 86 | LOAD x7, 7 87 | LOAD x8, 8 88 | LOAD x9, 9 89 | LOAD x10, 10 90 | LOAD x11, 11 91 | LOAD x12, 12 92 | LOAD x13, 13 93 | LOAD x14, 14 94 | LOAD x15, 15 95 | LOAD x16, 16 96 | LOAD x17, 17 97 | LOAD x18, 18 98 | LOAD x19, 19 99 | LOAD x20, 20 100 | LOAD x21, 21 101 | LOAD x22, 22 102 | LOAD x23, 23 103 | LOAD x24, 24 104 | LOAD x25, 25 105 | LOAD x26, 26 106 | LOAD x27, 27 107 | LOAD x28, 28 108 | LOAD x29, 29 109 | LOAD x30, 30 110 | LOAD x31, 31 111 | # 最后恢复栈指针(x2, sp)为原指针(无论是用户态还是内核态) 112 | LOAD x2, 2 113 | .endm 114 | 115 | # 代码段开始 116 | .section .text 117 | .globl __alltraps 118 | .align 4 119 | __alltraps: 120 | # 保存上下文 121 | SAVE_ALL 122 | # 将sp存入a0作为trap函数的第一个参数 123 | mv a0, sp 124 | # 跳转到trap函数执行(PC+4的值存入了x1寄存器),执行结束后会返回到这里继续向下执行恢复上下文 125 | call trap 126 | .globl __trapret 127 | __trapret: 128 | # 恢复上下文 129 | move sp, a0 130 | RESTORE_ALL 131 | # 从内核态中断中返回 132 | sret 133 | -------------------------------------------------------------------------------- /os/lab4/trap/trapentry.S: -------------------------------------------------------------------------------- 1 | # 定义常量XLENB=8(每个寄存器 64 bit= 8 bytes) 2 | .equ XLENB, 8 3 | 4 | # 定义宏:LOAD,读取内存地址 sp+a2*8 的值到寄存器 a1 5 | .macro LOAD a1, a2 6 | ld \a1, \a2*XLENB(sp) 7 | .endm 8 | 9 | # 定义宏:STORE,将寄存器 a1 的值保存到内存地址 sp+a2*8 10 | .macro STORE a1, a2 11 | sd \a1, \a2*XLENB(sp) 12 | .endm 13 | 14 | # 定义宏:保存上下文(所有通用寄存器及额外的CSR寄存器) 15 | .macro SAVE_ALL 16 | # 借用无用的寄存器 sscratch 保存原 sp 17 | csrw sscratch,sp 18 | 19 | # 将栈指针下移为TrapFrame预留足够的空间用于将所有通用寄存器值存入栈中(36个寄存器的空间) 20 | addi sp, sp, -36*XLENB 21 | # 保存所有通用寄存器,除了 x2 (x2就是sp,sp 本应保存的是发生中断前的值,这个值目前被交换到了 sscratch 中,因此留到后面处理。) 22 | STORE x1, 1 23 | STORE x3, 3 24 | STORE x4, 4 25 | STORE x5, 5 26 | STORE x6, 6 27 | STORE x7, 7 28 | STORE x8, 8 29 | STORE x9, 9 30 | STORE x10, 10 31 | STORE x11, 11 32 | STORE x12, 12 33 | STORE x13, 13 34 | STORE x14, 14 35 | STORE x15, 15 36 | STORE x16, 16 37 | STORE x17, 17 38 | STORE x18, 18 39 | STORE x19, 19 40 | STORE x20, 20 41 | STORE x21, 21 42 | STORE x22, 22 43 | STORE x23, 23 44 | STORE x24, 24 45 | STORE x25, 25 46 | STORE x26, 26 47 | STORE x27, 27 48 | STORE x28, 28 49 | STORE x29, 29 50 | STORE x30, 30 51 | STORE x31, 31 52 | 53 | # 保存完x0-x31之后这些寄存器就可以随意使用了,下面马上用到: 54 | # 读取sscratch到s0,借s0中转后将原sp存入内存 55 | csrr s0, sscratch 56 | 57 | # 读取 sstatus, sepc, stval, scause寄存器的值到s0-s4(x1-x31中的特定几个)寄存器 58 | csrr s1, sstatus 59 | csrr s2, sepc 60 | csrr s3, stval 61 | csrr s4, scause 62 | 63 | # 存储 sp, sstatus, sepc, sbadvaddr, scause 到栈中 64 | # 其中把s0存到x2(sp)的位置以便于返回时直接恢复栈 65 | STORE s0, 2 66 | STORE s1, 32 67 | STORE s2, 33 68 | STORE s3, 34 69 | STORE s4, 35 70 | .endm 71 | 72 | # 定义宏:恢复寄存器 73 | .macro RESTORE_ALL 74 | LOAD s1, 32 # s1 = sstatus 75 | LOAD s2, 33 # s2 = sepc 76 | # 恢复 sstatus, sepc 77 | csrw sstatus, s1 78 | csrw sepc, s2 79 | 80 | # 恢复除了 x2 (sp) 以外的其余通用寄存器 81 | LOAD x1, 1 82 | LOAD x3, 3 83 | LOAD x4, 4 84 | LOAD x5, 5 85 | LOAD x6, 6 86 | LOAD x7, 7 87 | LOAD x8, 8 88 | LOAD x9, 9 89 | LOAD x10, 10 90 | LOAD x11, 11 91 | LOAD x12, 12 92 | LOAD x13, 13 93 | LOAD x14, 14 94 | LOAD x15, 15 95 | LOAD x16, 16 96 | LOAD x17, 17 97 | LOAD x18, 18 98 | LOAD x19, 19 99 | LOAD x20, 20 100 | LOAD x21, 21 101 | LOAD x22, 22 102 | LOAD x23, 23 103 | LOAD x24, 24 104 | LOAD x25, 25 105 | LOAD x26, 26 106 | LOAD x27, 27 107 | LOAD x28, 28 108 | LOAD x29, 29 109 | LOAD x30, 30 110 | LOAD x31, 31 111 | # 最后恢复栈指针(x2, sp)为原指针(无论是用户态还是内核态) 112 | LOAD x2, 2 113 | .endm 114 | 115 | # 代码段开始 116 | .section .text 117 | .globl __alltraps 118 | .align 4 119 | __alltraps: 120 | # 保存上下文 121 | SAVE_ALL 122 | # 将sp存入a0作为trap函数的第一个参数 123 | mv a0, sp 124 | # 跳转到trap函数执行(PC+4的值存入了x1寄存器),执行结束后会返回到这里继续向下执行恢复上下文 125 | call trap 126 | .globl __trapret 127 | __trapret: 128 | # 恢复上下文 129 | move sp, a0 130 | RESTORE_ALL 131 | # 从内核态中断中返回 132 | sret 133 | -------------------------------------------------------------------------------- /os/lab2/trap/uart/uart_qemu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | static int8_t uart_16550a_read(); 4 | static void uart_16550a_directly_write(int8_t c); 5 | static void uart_16550a_interrupt_handler(); 6 | static void uart_16550a_putc(int8_t c); 7 | static void uart_16550a_init(); 8 | void uart_qemu_init(); 9 | 10 | extern struct uart_class_device uart_device; 11 | 12 | struct uart_qemu_regs { 13 | uint8_t RBR_THR_DLL; // 0x00, Receiver Buffer Register/Transmitter Holding Register/Divisor Latch LSB 14 | uint8_t IER_DLM; // 0x01, Interrupt Enable Register/Divisor Latch MSB 15 | uint8_t IIR_FCR; // 0x02, Interrupt Identification Register/FIFO Control Register 16 | uint8_t LCR; // 0x03, Line Control Register 17 | uint8_t MCR; // 0x04, Modem Control Register 18 | uint8_t LSR; // 0x05, Line Status Register 19 | }; 20 | 21 | static const struct uart_class_ops uart_16550a_ops = { 22 | .uart_interrupt_handler = uart_16550a_interrupt_handler, 23 | .uart_read = uart_16550a_read, 24 | .uart_directly_write = uart_16550a_directly_write, 25 | .uart_putc = uart_16550a_putc, 26 | }; 27 | 28 | enum reg_bit { 29 | IER_ERBFI = 0, 30 | LSR_DR = 0, 31 | LSR_THRE = 5, 32 | LCR_DLAB = 7, 33 | }; 34 | 35 | void uart_qemu_init() 36 | { 37 | uart_device.uart_start_addr = 0x10000000; 38 | uart_device.divisor = 592; 39 | uart_16550a_init(); 40 | } 41 | 42 | static void uart_16550a_init() 43 | { 44 | volatile struct uart_qemu_regs *regs = (struct uart_qemu_regs *)uart_device.uart_start_addr; 45 | 46 | regs->IER_DLM = 0; // 关闭 16550a 的所有中断,避免初始化未完成就发生中断 47 | while(!(regs->LSR & (1 << LSR_THRE))); // 等待发送缓冲区为空 48 | 49 | // 设置波特率 50 | uint8_t divisor_least = uart_device.divisor & 0xFF; 51 | uint8_t divisor_most = uart_device.divisor >> 8; 52 | regs->LCR |= 1 << LCR_DLAB; // 设置 DLAB=1,进入波特率设置模式,访问 DLL 和 DLM 寄存器设置波特率 53 | regs->RBR_THR_DLL = divisor_least; // 设置 DLL 54 | regs->IER_DLM = divisor_most; // 设置 DLM 55 | 56 | regs->LCR = 0b00000011; // 一次传输 8bit(1字节),无校验,1 位停止位,禁用 break 信号,设置 DLAB=0,进入数据传输/中断设置模式 57 | regs->IIR_FCR |= 0b00000001; // 设置 FCR[TL]=00,设置中断阈值为 1 字节,设置 FCR[FIFOE]=1,启动 FIFO 58 | regs->IER_DLM |= 1 << IER_ERBFI; // 设置 IER,启用接收数据时发生的中断 59 | 60 | uart_device.ops = uart_16550a_ops; 61 | } 62 | 63 | static int8_t uart_16550a_read() 64 | { 65 | volatile struct uart_qemu_regs *regs = (struct uart_qemu_regs *)uart_device.uart_start_addr; 66 | return regs->RBR_THR_DLL; /* read RBR */ 67 | } 68 | 69 | static void uart_16550a_directly_write(int8_t c) 70 | { 71 | volatile struct uart_qemu_regs *regs = (struct uart_qemu_regs *)uart_device.uart_start_addr; 72 | regs->RBR_THR_DLL = c; /* write THR */ 73 | } 74 | 75 | static void uart_16550a_putc(int8_t c) 76 | { 77 | volatile struct uart_qemu_regs *regs = (struct uart_qemu_regs *)uart_device.uart_start_addr; 78 | while (!(regs->LSR & (1 << LSR_THRE))) 79 | ; 80 | uart_16550a_directly_write(c); 81 | } 82 | 83 | static void uart_16550a_interrupt_handler() 84 | { 85 | volatile struct uart_qemu_regs *regs = (struct uart_qemu_regs *)uart_device.uart_start_addr; 86 | while (regs->LSR & (1 << LSR_DR)) { 87 | int8_t c = uart_read(); 88 | if (c > -1) 89 | uart_16550a_putc(c); 90 | } 91 | } -------------------------------------------------------------------------------- /os/lab2/trap/plic.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file plic.c 3 | * @note 访问 MMIO 内存必须使用 volatile 关键字,详情见 **Effectice Modern C++** 4 | * Item 40: Use std::atomic for concurrency, volatile for special memory 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | struct plic_class_device plic_device; 13 | extern struct device_node node[100]; 14 | extern struct property prop[100]; 15 | extern int64_t node_used; 16 | extern int64_t prop_used; 17 | 18 | static uint64_t plic_probe() 19 | { 20 | for (size_t i = 0; i < prop_used; i++) { 21 | if (strcmp(prop[i].name, "compatible") == 0) { 22 | if (strcmp(prop[i].value, "thead,c900-plic") == 0) { 23 | return SUNXI_PLIC; 24 | } 25 | if (strcmp(prop[i].value, "sifive,plic-1.0.0") == 0) { 26 | return QEMU_PLIC; 27 | } 28 | } 29 | } 30 | return -1; 31 | } 32 | 33 | void plic_init() 34 | { 35 | plic_device.id = plic_probe(); 36 | switch (plic_device.id) { 37 | case QEMU_PLIC: 38 | plic_device.plic_start_addr = (volatile struct plic_regs *)0x0c000000; 39 | plic_enable_interrupt(RTC_GOLDFISH_IRQ); 40 | plic_enable_interrupt(UART_QEMU_IRQ); 41 | plic_set_priority(RTC_GOLDFISH_IRQ, 1); 42 | plic_set_priority(UART_QEMU_IRQ, 1); 43 | break; 44 | case SUNXI_PLIC: 45 | plic_device.plic_start_addr = (volatile struct plic_regs *)0x10000000; 46 | plic_enable_interrupt(UART_SUNXI_IRQ); 47 | plic_enable_interrupt(RTC_SUNXI_IRQ); 48 | plic_set_priority(UART_SUNXI_IRQ, 1); 49 | plic_set_priority(RTC_SUNXI_IRQ, 1); 50 | break; 51 | } 52 | plic_set_threshold(0); 53 | set_csr(sie, 1 << IRQ_S_EXT); 54 | } 55 | 56 | void plic_enable_interrupt(uint32_t id) 57 | { 58 | plic_device.plic_start_addr->PLIC_IE_REG[1][id / 32] |= (1 << (id % 32)); 59 | } 60 | 61 | // QEMU Virt machine support 7 priority (1 - 7), 62 | // The "0" is reserved, and the lowest priority is "1". 63 | void plic_set_priority(uint32_t id, uint8_t priority) 64 | { 65 | plic_device.plic_start_addr->PLIC_PRIO_REG[id] = priority & 7; 66 | } 67 | 68 | void plic_set_threshold(uint8_t threshold) 69 | { 70 | plic_device.plic_start_addr->PLIC_TH_CLAIM_COMPLITE_REG[1].PLIC_TH_REG = threshold & 7; 71 | } 72 | 73 | /** 74 | * @brief 主动获取外中断号 75 | * 76 | * @return 最高优先级的待处理中断号,不存在则返回 0 77 | */ 78 | uint32_t plic_claim() 79 | { 80 | return plic_device.plic_start_addr->PLIC_TH_CLAIM_COMPLITE_REG[1].PLIC_CLAIM_REG; 81 | } 82 | 83 | void plic_complete(uint32_t id) 84 | { 85 | plic_device.plic_start_addr->PLIC_TH_CLAIM_COMPLITE_REG[1].PLIC_CLAIM_REG = id; 86 | //plic_enable_interrupt(id); 87 | } 88 | 89 | /* 90 | * 91 | * @brief 返回待处理终端向量 92 | * 93 | * @note 可以先 enable 再 claim 来清空 pending 94 | 95 | uint64_t plic_pending() 96 | { 97 | return plic_device.plic_start_addr->PLIC_IP_REG; 98 | } 99 | */ 100 | 101 | /** 102 | * @brief 判断某中断是否待处理 103 | */ 104 | uint32_t plic_is_pending(uint32_t id) 105 | { 106 | volatile uint32_t *p = (volatile uint32_t *)&plic_device.plic_start_addr->PLIC_IP_REG; 107 | return p[id / 32] & (1 << (id % 32)); 108 | } 109 | -------------------------------------------------------------------------------- /os/lab6/lib/stdio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | static uint64_t pow(uint64_t x, uint64_t y); 4 | 5 | int printf(const char* fmt, ...) 6 | { 7 | va_list ap; 8 | uint64_t val; 9 | uint64_t temp; 10 | uint64_t len; 11 | uint64_t rev = 0; 12 | int ch; 13 | const char* str = NULL; 14 | 15 | va_start(ap, fmt); 16 | while (*fmt != '\0') 17 | { 18 | switch (*fmt) 19 | { 20 | case '%': 21 | fmt++; 22 | switch (*fmt) 23 | { 24 | case 'u': //Decimal 25 | val = va_arg(ap, uint64_t); 26 | temp = val; 27 | len = 0; 28 | do 29 | { 30 | len++; 31 | temp /= 10; 32 | } while (temp); 33 | rev += len; 34 | temp = val; 35 | while (len) 36 | { 37 | ch = temp / pow(10, len - 1); 38 | temp %= pow(10, len - 1); 39 | put_char(ch + '0'); 40 | len--; 41 | } 42 | break; 43 | case 'p': 44 | put_char('0'); 45 | put_char('x'); 46 | case 'x': 47 | val = va_arg(ap, uint64_t); 48 | temp = val; 49 | len = 0; 50 | do 51 | { 52 | len++; 53 | temp /= 16; 54 | } while (temp); 55 | rev += len; 56 | temp = val; 57 | while (len) 58 | { 59 | ch = temp / pow(16, len - 1); 60 | temp %= pow(16, len - 1); 61 | if (ch <= 9) 62 | { 63 | put_char(ch + '0'); 64 | } 65 | else 66 | { 67 | put_char(ch - 10 + 'a'); 68 | } 69 | len--; 70 | } 71 | break; 72 | case 's': 73 | str = va_arg(ap, const char*); 74 | 75 | while (*str) 76 | { 77 | put_char(*str); 78 | str++; 79 | } 80 | break; 81 | case 'c': //character 82 | put_char(va_arg(ap, int)); 83 | rev += 1; 84 | break; 85 | default: 86 | break; 87 | } 88 | break; 89 | case '\n': 90 | put_char('\n'); 91 | rev += 1; 92 | break; 93 | case '\r': 94 | put_char('\r'); 95 | rev += 1; 96 | break; 97 | case '\t': 98 | put_char('\t'); 99 | rev += 1; 100 | break; 101 | default: 102 | put_char(*fmt); 103 | } 104 | fmt++; 105 | } 106 | va_end(ap); 107 | return rev; 108 | } 109 | 110 | static uint64_t pow(uint64_t x, uint64_t y) 111 | { 112 | uint64_t sum = 1; 113 | while (y--) { 114 | sum *= x; 115 | } 116 | return sum; 117 | } 118 | --------------------------------------------------------------------------------