├── .gitignore ├── .vscode └── tasks.json ├── LanOS_compile_env ├── makeall │ ├── Dockerfile │ └── entrypoint.sh └── makeclean │ ├── Dockerfile │ └── entrypoint.sh ├── README.md ├── demos ├── a20_not_open │ ├── boot.s │ ├── head.s │ ├── lan_main.c │ ├── makefile │ └── n.lds ├── a20_open │ ├── boot.s │ ├── head.s │ ├── lan_main.c │ ├── makefile │ ├── n.lds │ └── readme.md ├── asm_call_c │ ├── asm_int_80.s │ ├── lan_main.c │ └── makefile ├── asm_int_80 │ ├── asm_int_80.s │ └── makefile ├── common_header_demo │ ├── bin │ │ ├── loop │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ │ ├── ls │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ │ ├── readme.md │ │ ├── shell │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ │ └── test │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ ├── boot.s │ ├── common │ │ ├── header │ │ │ └── lanstd.h │ │ └── lib │ │ │ ├── lansys.c │ │ │ ├── liblansys.a │ │ │ └── makefile │ ├── exit.c │ ├── fork.c │ ├── fs_patch_tool │ │ └── patch.js │ ├── gate_tool.h │ ├── head.s │ ├── intel_err_handle.c │ ├── keyboard.c │ ├── lan_main.c │ ├── makefile │ ├── mm.c │ ├── mm.h │ ├── move_to_user_mode.h │ ├── n.lds │ ├── print_str.c │ ├── readme.md │ ├── root_fs │ │ ├── hello_fs │ │ ├── lan_sh │ │ ├── loop │ │ ├── ls │ │ └── test │ ├── sched.c │ ├── sched.h │ └── sys_call.c ├── cp_on_write │ ├── boot.s │ ├── fork.c │ ├── gate_tool.h │ ├── head.s │ ├── intel_err_handle.c │ ├── lan_main.c │ ├── makefile │ ├── mm.c │ ├── mm.h │ ├── move_to_user_mode.h │ ├── n.lds │ ├── readme.md │ ├── sched.c │ ├── sched.h │ └── sys_call.c ├── exec_demo │ ├── bin │ │ └── test │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ ├── boot.s │ ├── fork.c │ ├── fs_patch_tool │ │ └── patch.js │ ├── gate_tool.h │ ├── head.s │ ├── intel_err_handle.c │ ├── lan_main.c │ ├── makefile │ ├── mm.c │ ├── mm.h │ ├── move_to_user_mode.h │ ├── n.lds │ ├── print_str.c │ ├── readme.md │ ├── root_fs │ │ ├── hello_fs │ │ └── test │ ├── sched.c │ ├── sched.h │ └── sys_call.c ├── exit_demo │ ├── bin │ │ ├── loop │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ │ ├── ls │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ │ ├── shell │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ │ └── test │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ ├── boot.s │ ├── exit.c │ ├── fork.c │ ├── fs_patch_tool │ │ └── patch.js │ ├── gate_tool.h │ ├── head.s │ ├── intel_err_handle.c │ ├── keyboard.c │ ├── lan_main.c │ ├── makefile │ ├── mm.c │ ├── mm.h │ ├── move_to_user_mode.h │ ├── n.lds │ ├── print_str.c │ ├── readme.md │ ├── root_fs │ │ ├── hello_fs │ │ ├── lan_sh │ │ ├── loop │ │ ├── ls │ │ └── test │ ├── sched.c │ ├── sched.h │ └── sys_call.c ├── fork_demo │ ├── boot.s │ ├── fork.c │ ├── gate_tool.h │ ├── head.s │ ├── intel_err_handle.c │ ├── lan_main.c │ ├── makefile │ ├── mm.c │ ├── mm.h │ ├── move_to_user_mode.h │ ├── n.lds │ ├── readme.md │ ├── sched.c │ ├── sched.h │ └── sys_call.c ├── fs_demo │ ├── boot.s │ ├── fork.c │ ├── fs_patch_tool │ │ └── patch.js │ ├── gate_tool.h │ ├── head.s │ ├── intel_err_handle.c │ ├── lan_main.c │ ├── makefile │ ├── mm.c │ ├── mm.h │ ├── move_to_user_mode.h │ ├── n.lds │ ├── print_str.c │ ├── readme.md │ ├── root_fs │ │ └── hello_fs │ ├── sched.c │ ├── sched.h │ └── sys_call.c ├── init_8259a │ ├── boot.s │ ├── gate_tool.h │ ├── head.s │ ├── lan_main.c │ ├── makefile │ ├── n.lds │ └── readme.md ├── keyboard_demo │ ├── bin │ │ └── test │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ ├── boot.s │ ├── fork.c │ ├── fs_patch_tool │ │ └── patch.js │ ├── gate_tool.h │ ├── head.s │ ├── intel_err_handle.c │ ├── keyboard.c │ ├── lan_main.c │ ├── makefile │ ├── mm.c │ ├── mm.h │ ├── move_to_user_mode.h │ ├── n.lds │ ├── print_str.c │ ├── readme.md │ ├── root_fs │ │ ├── hello_fs │ │ └── test │ ├── sched.c │ ├── sched.h │ └── sys_call.c ├── lds_test │ ├── asm_int_80.s │ ├── makefile │ ├── n.lds │ └── show.sh ├── ls_demo │ ├── bin │ │ ├── loop │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ │ ├── ls │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ │ ├── shell │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ │ └── test │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ ├── boot.s │ ├── fork.c │ ├── fs_patch_tool │ │ └── patch.js │ ├── gate_tool.h │ ├── head.s │ ├── intel_err_handle.c │ ├── keyboard.c │ ├── lan_main.c │ ├── makefile │ ├── mm.c │ ├── mm.h │ ├── move_to_user_mode.h │ ├── n.lds │ ├── print_str.c │ ├── root_fs │ │ ├── hello_fs │ │ ├── lan_sh │ │ ├── loop │ │ ├── ls │ │ └── test │ ├── sched.c │ ├── sched.h │ └── sys_call.c ├── mm │ ├── boot.s │ ├── gate_tool.h │ ├── head.s │ ├── lan_main.c │ ├── makefile │ ├── n.lds │ └── readme.md ├── pic │ ├── a20notopen.png │ ├── cpp.png │ ├── exec.gif │ ├── init_8259a_succ.png │ ├── loop.png │ ├── ls.gif │ ├── multitask.gif │ ├── opena20.png │ ├── orange1.png │ ├── orange2.png │ └── orange3.png ├── print_str_demo │ ├── boot.s │ ├── fork.c │ ├── gate_tool.h │ ├── head.s │ ├── intel_err_handle.c │ ├── lan_main.c │ ├── makefile │ ├── mm.c │ ├── mm.h │ ├── move_to_user_mode.h │ ├── n.lds │ ├── print_str.c │ ├── sched.c │ ├── sched.h │ ├── sys_call.c │ └── test ├── protect_mode_cpp_demo │ ├── boot.s │ ├── lan_main.cpp │ ├── loader.s │ ├── makefile │ └── n.lds ├── protect_mode_demo │ ├── boot.s │ ├── header.s │ ├── lan_main.c │ ├── makefile │ ├── n.lds │ └── readme.md ├── shell_demo │ ├── bin │ │ ├── shell │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ │ └── test │ │ │ ├── lan_main.c │ │ │ ├── makefile │ │ │ └── n.lds │ ├── boot.s │ ├── fork.c │ ├── fs_patch_tool │ │ └── patch.js │ ├── gate_tool.h │ ├── head.s │ ├── intel_err_handle.c │ ├── keyboard.c │ ├── lan_main.c │ ├── makefile │ ├── mm.c │ ├── mm.h │ ├── move_to_user_mode.h │ ├── n.lds │ ├── print_str.c │ ├── root_fs │ │ ├── hello_fs │ │ ├── lan_sh │ │ └── test │ ├── sched.c │ ├── sched.h │ └── sys_call.c └── user_mode_demo │ ├── boot.s │ ├── gate_tool.h │ ├── head.s │ ├── intel_err_handle.c │ ├── lan_main.c │ ├── makefile │ ├── move_to_user_mode.h │ ├── n.lds │ ├── readme.md │ └── sys_call.c ├── doc ├── 8259A.md ├── a20.md ├── big_map.md ├── control_binary.md ├── fbi_warning.md ├── fork.md ├── how_to_build.md ├── main_point.md ├── mm.md ├── questions.md ├── quick_protect_mode.md ├── target_and_prepare.md └── to_direction_compare.md ├── lan_os_rc ├── make_os.sh ├── src └── tool ├── makeall.sh ├── makeclean.sh └── start_vbox.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac DS_Store files 2 | .DS_Store 3 | a.vfd -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "build LanOS", 8 | "type": "shell", 9 | "command": "./make_os.sh", 10 | "options": { 11 | "cwd": "${workspaceFolder}" 12 | }, 13 | "problemMatcher": [], 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /LanOS_compile_env/makeall/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN apt update \ 4 | && apt-get -y install nasm gcc make nodejs 5 | 6 | COPY entrypoint.sh /root/entrypoint.sh 7 | WORKDIR /root/ 8 | ENTRYPOINT ["/root/entrypoint.sh"] 9 | -------------------------------------------------------------------------------- /LanOS_compile_env/makeall/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd /share && make 4 | -------------------------------------------------------------------------------- /LanOS_compile_env/makeclean/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN apt update \ 4 | && apt-get -y install nasm gcc make 5 | 6 | COPY entrypoint.sh /root/entrypoint.sh 7 | WORKDIR /root/ 8 | ENTRYPOINT ["/root/entrypoint.sh"] 9 | -------------------------------------------------------------------------------- /LanOS_compile_env/makeclean/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd /share && make clean 4 | -------------------------------------------------------------------------------- /demos/a20_not_open/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 17 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+SYSLEN ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | jnc ok_load 16 | jmp $ 17 | 18 | ok_load: 19 | cli 20 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 21 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 22 | xor ax, ax 23 | mov es, ax 24 | mov cx, 0x1000 25 | sub si, si 26 | sub di, di 27 | cld ;df = 0 rep movsw是正向的 28 | rep movsw 29 | mov ax, 0x0 ;重新恢复ds指向0x0 30 | mov ds, ax 31 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 32 | mov ax, 0x0001 33 | lmsw ax 34 | jmp dword 8:0 35 | gdt: 36 | dw 0, 0, 0, 0 ;第一个描述符,没有用 37 | dw 0x07ff ;代码段 从0地址开始 38 | dw 0x0000 39 | dw 0x9a00 40 | dw 0x00c0 41 | dw 0x07ff ;数据段 从0地址开始 42 | dw 0x0000 43 | dw 0x9200 44 | dw 0x00c0 45 | 46 | 47 | gdt_48: 48 | dw 0x7ff ;2048/8=256个描述符 49 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 50 | 51 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 52 | times 510 - ($-$$) db 0 53 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/a20_not_open/head.s: -------------------------------------------------------------------------------- 1 | [BITS 32] 2 | 3 | LATCH equ 11930 4 | SCRN_SEL equ 0x18 5 | TSS0_SEL equ 0x20 6 | LDT0_SEL equ 0x28 7 | TSS1_SEL equ 0x30 8 | LDT1_SEL equ 0x38 9 | global write_char 10 | extern lan_main 11 | start_up32: 12 | mov dword eax, 0x10 ;这时候使用的0x10还是loader.asm中定义的,虽然boot.asm之后定义的0x10描述符与之完全相同 13 | mov ds, ax 14 | lss esp, [init_stack];接下来要使用call指令,所以这里要初始化好栈 15 | call setup_gdt 16 | call setup_idt 17 | 18 | mov eax, 0x10 ;加载完gdt之后重新加载所有的段寄存器,因为要更新段寄存器中段描述符的缓存(不可见部分)参见《linux内核完全剖析》94页 19 | mov ds, ax 20 | mov es, ax 21 | mov fs, ax 22 | mov gs, ax 23 | 24 | lss esp, [init_stack];因为ds可能更新了(这个例子中实际上没有),所以要重新加载ss 25 | push dword lan_main 26 | ret 27 | 28 | setup_gdt: 29 | lgdt [lgdt_48] 30 | ret 31 | 32 | setup_idt: 33 | lea edx, [ignore_int] 34 | mov eax, dword 0x00080000 35 | mov ax, dx 36 | mov dx, 0x8e00 37 | lea edi, [idt] 38 | mov ecx, 256 39 | rp_idt: 40 | mov dword [edi], eax 41 | mov dword [edi+4], edx 42 | add dword edi, 8 43 | dec ecx 44 | jne rp_idt 45 | lidt [lidt_48] 46 | ret 47 | 48 | write_char: 49 | push gs 50 | push dword ebx 51 | mov ebx, SCRN_SEL 52 | mov gs, bx 53 | mov bx, [src_loc] 54 | shl ebx, 1 55 | push dword eax 56 | mov eax, edi 57 | mov byte [gs:ebx], al 58 | pop dword eax 59 | shr ebx, 1 60 | inc dword ebx 61 | cmp dword ebx, 2000 62 | jb not_equ ;jb : jump if below 63 | mov dword ebx, 0 64 | not_equ: 65 | mov dword [src_loc], ebx 66 | pop dword ebx 67 | pop gs 68 | ret 69 | 70 | align 4 71 | ignore_int: 72 | iret 73 | 74 | current: dd 0 75 | src_loc: dd 0 76 | 77 | align 4 78 | lidt_48: 79 | dw 256*8-1 80 | dd idt 81 | lgdt_48: 82 | dw end_gdt-gdt-1 83 | dd gdt 84 | 85 | align 8 86 | idt: 87 | times 256 dq 0 88 | gdt: 89 | dq 0x0000000000000000 90 | dq 0x00c09a00000007ff ;0x08 这两个段描述符和loader.asm中的代码段数据段是一样的 91 | dq 0x00c09200000007ff ;0x10 92 | dq 0x00c0920b80000002 ;0x18 显存数据段 93 | end_gdt: 94 | 95 | times 128 dd 0 96 | init_stack: ;从这里开始是一个48位操作数 97 | dd init_stack ;32位代表初始的esp 98 | dw 0x10 ;16位栈的段选择符,lss之后会加载到ss中 99 | -------------------------------------------------------------------------------- /demos/a20_not_open/lan_main.c: -------------------------------------------------------------------------------- 1 | extern void write_char(char ch); 2 | 3 | void check_a20_valid() { 4 | unsigned char *p0 = 0x0; 5 | unsigned char *p1 = 0x100000; 6 | for (unsigned char i = 0; i < 10; ++i) { 7 | *p0 = i; 8 | if (*p0 != *p1) { 9 | write_char('b'); 10 | break; 11 | } else { 12 | write_char('e'); 13 | } 14 | } 15 | } 16 | 17 | void lan_main() { 18 | write_char('L'); 19 | write_char('O'); 20 | write_char('V'); 21 | write_char('E'); 22 | check_a20_valid(); 23 | while (1) 24 | ; 25 | } 26 | -------------------------------------------------------------------------------- /demos/a20_not_open/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=17 skip=4096 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=18 conv=notrunc 6 | link: head lan_main boot 7 | ld -T n.lds -o lan_os head.o lan_main.o 8 | head: 9 | nasm -felf64 -o head.o head.s 10 | lan_main: 11 | gcc -c lan_main.c 12 | boot: 13 | nasm -o boot.bin boot.s -l boot.lst 14 | clean: 15 | rm lan_os lan_main.o head.o boot.bin boot.lst a.img a.vfd 16 | 17 | -------------------------------------------------------------------------------- /demos/a20_not_open/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/a20_open/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 17 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+SYSLEN ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | jnc ok_load 16 | jmp $ 17 | 18 | ok_load: 19 | cli 20 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 21 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 22 | xor ax, ax 23 | mov es, ax 24 | mov cx, 0x1000 25 | sub si, si 26 | sub di, di 27 | cld ;df = 0 rep movsw是正向的 28 | rep movsw 29 | mov ax, 0x0 ;重新恢复ds指向0x0 30 | mov ds, ax 31 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 32 | mov ax, 0x0001 33 | lmsw ax 34 | jmp dword 8:0 35 | gdt: 36 | dw 0, 0, 0, 0 ;第一个描述符,没有用 37 | dw 0x07ff ;代码段 从0地址开始 38 | dw 0x0000 39 | dw 0x9a00 40 | dw 0x00c0 41 | dw 0x07ff ;数据段 从0地址开始 42 | dw 0x0000 43 | dw 0x9200 44 | dw 0x00c0 45 | 46 | 47 | gdt_48: 48 | dw 0x7ff ;2048/8=256个描述符 49 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 50 | 51 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 52 | times 510 - ($-$$) db 0 53 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/a20_open/head.s: -------------------------------------------------------------------------------- 1 | [BITS 32] 2 | 3 | LATCH equ 11930 4 | SCRN_SEL equ 0x18 5 | TSS0_SEL equ 0x20 6 | LDT0_SEL equ 0x28 7 | TSS1_SEL equ 0x30 8 | LDT1_SEL equ 0x38 9 | global write_char, open_a20 10 | extern lan_main 11 | start_up32: 12 | mov dword eax, 0x10 ;这时候使用的0x10还是loader.asm中定义的,虽然boot.asm之后定义的0x10描述符与之完全相同 13 | mov ds, ax 14 | lss esp, [init_stack];接下来要使用call指令,所以这里要初始化好栈 15 | call setup_gdt 16 | call setup_idt 17 | 18 | mov eax, 0x10 ;加载完gdt之后重新加载所有的段寄存器,因为要更新段寄存器中段描述符的缓存(不可见部分)参见《linux内核完全剖析》94页 19 | mov ds, ax 20 | mov es, ax 21 | mov fs, ax 22 | mov gs, ax 23 | 24 | lss esp, [init_stack];因为ds可能更新了(这个例子中实际上没有),所以要重新加载ss 25 | push dword lan_main 26 | ret 27 | 28 | setup_gdt: 29 | lgdt [lgdt_48] 30 | ret 31 | 32 | setup_idt: 33 | lea edx, [ignore_int] 34 | mov eax, dword 0x00080000 35 | mov ax, dx 36 | mov dx, 0x8e00 37 | lea edi, [idt] 38 | mov ecx, 256 39 | rp_idt: 40 | mov dword [edi], eax 41 | mov dword [edi+4], edx 42 | add dword edi, 8 43 | dec ecx 44 | jne rp_idt 45 | lidt [lidt_48] 46 | ret 47 | 48 | write_char: 49 | push gs 50 | push dword ebx 51 | mov ebx, SCRN_SEL 52 | mov gs, bx 53 | mov bx, [src_loc] 54 | shl ebx, 1 55 | push dword eax 56 | mov eax, edi 57 | mov byte [gs:ebx], al 58 | pop dword eax 59 | shr ebx, 1 60 | inc dword ebx 61 | cmp dword ebx, 2000 62 | jb not_equ ;jb : jump if below 63 | mov dword ebx, 0 64 | not_equ: 65 | mov dword [src_loc], ebx 66 | pop dword ebx 67 | pop gs 68 | ret 69 | 70 | open_a20: 71 | call empty_8042 72 | mov al, 0xd1 73 | out 0x64, al 74 | call empty_8042 75 | mov al, 0xdf 76 | out 0x60, al 77 | call empty_8042 78 | ret 79 | 80 | empty_8042: 81 | dw 0x00eb 82 | dw 0x00eb 83 | in al, 0x64 84 | test al, 0x2 85 | jnz empty_8042 86 | ret 87 | 88 | align 4 89 | ignore_int: 90 | iret 91 | 92 | current: dd 0 93 | src_loc: dd 0 94 | 95 | align 4 96 | lidt_48: 97 | dw 256*8-1 98 | dd idt 99 | lgdt_48: 100 | dw end_gdt-gdt-1 101 | dd gdt 102 | 103 | align 8 104 | idt: 105 | times 256 dq 0 106 | gdt: 107 | dq 0x0000000000000000 108 | dq 0x00c09a00000007ff ;0x08 这两个段描述符和loader.asm中的代码段数据段是一样的 109 | dq 0x00c09200000007ff ;0x10 110 | dq 0x00c0920b80000002 ;0x18 显存数据段 111 | end_gdt: 112 | 113 | times 128 dd 0 114 | init_stack: ;从这里开始是一个48位操作数 115 | dd init_stack ;32位代表初始的esp 116 | dw 0x10 ;16位栈的段选择符,lss之后会加载到ss中 117 | -------------------------------------------------------------------------------- /demos/a20_open/lan_main.c: -------------------------------------------------------------------------------- 1 | extern void write_char(char ch); 2 | extern void open_a20(); 3 | 4 | void check_a20_valid() { 5 | unsigned char *p0 = 0x0; 6 | unsigned char *p1 = 0x100000; 7 | for (unsigned char i = 0; i < 10; ++i) { 8 | *p0 = i; 9 | if (*p0 != *p1) { 10 | write_char('b'); 11 | break; 12 | } else { 13 | write_char('e'); 14 | } 15 | } 16 | } 17 | 18 | void lan_main() { 19 | write_char('L'); 20 | write_char('O'); 21 | write_char('V'); 22 | write_char('E'); 23 | open_a20(); 24 | check_a20_valid(); 25 | while (1) 26 | ; 27 | } 28 | -------------------------------------------------------------------------------- /demos/a20_open/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=17 skip=4096 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=18 conv=notrunc 6 | link: head lan_main boot 7 | ld -T n.lds -o lan_os head.o lan_main.o 8 | head: 9 | nasm -felf64 -o head.o head.s 10 | lan_main: 11 | gcc -c lan_main.c 12 | boot: 13 | nasm -o boot.bin boot.s -l boot.lst 14 | clean: 15 | rm lan_os lan_main.o head.o boot.bin boot.lst a.img a.vfd 16 | 17 | -------------------------------------------------------------------------------- /demos/a20_open/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/asm_call_c/asm_int_80.s: -------------------------------------------------------------------------------- 1 | global _start, write 2 | extern lan_main 3 | _start: 4 | mov dword edx, 13 5 | mov dword ecx, message 6 | mov dword ebx, 1 7 | mov dword eax, 4 8 | int 0x80 9 | push dword lan_main 10 | ret 11 | message: 12 | db "Hello, World", 10 13 | message_c_write: 14 | db "Hello, Write", 10 15 | write: 16 | mov dword edx, 13 17 | mov dword ecx, message_c_write 18 | mov dword ebx, 1 19 | mov dword eax, 4 20 | int 0x80 21 | mov dword ebx, 0 22 | mov dword eax, 1 23 | int 0x80 24 | -------------------------------------------------------------------------------- /demos/asm_call_c/lan_main.c: -------------------------------------------------------------------------------- 1 | extern void write(); 2 | void lan_main() { write(); } 3 | -------------------------------------------------------------------------------- /demos/asm_call_c/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -c lan_main.c 3 | nasm -felf64 -o asm_int_80.o asm_int_80.s 4 | ld -o asm_int_80 lan_main.o asm_int_80.o 5 | clean: 6 | rm asm_int_80 asm_int_80.o lan_main.o 7 | 8 | -------------------------------------------------------------------------------- /demos/asm_int_80/asm_int_80.s: -------------------------------------------------------------------------------- 1 | global _start 2 | _start: 3 | mov dword edx, 13 4 | mov dword ecx, message 5 | mov dword ebx, 1 6 | mov dword eax, 4 7 | int 0x80 8 | mov dword ebx, 0 9 | mov dword eax, 1 10 | int 0x80 11 | message: 12 | db "Hello, World", 10 13 | -------------------------------------------------------------------------------- /demos/asm_int_80/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | nasm -felf64 -o asm_int_80.o asm_int_80.s 3 | ld -o asm_int_80 asm_int_80.o 4 | clean: 5 | rm asm_int_80 asm_int_80.o 6 | 7 | -------------------------------------------------------------------------------- /demos/common_header_demo/bin/loop/lan_main.c: -------------------------------------------------------------------------------- 1 | #include "lanstd.h" 2 | 3 | void lan_main() { 4 | s_print_str("start printing 20 times."); 5 | s_print_crlf(); 6 | for (int i = 0; i < 200; ++ i) { 7 | s_print_str("im a loop."); 8 | s_print_num(i); 9 | s_print_crlf(); 10 | for (int j = 0; j < 10000000; ++j) 11 | ; 12 | } 13 | s_exit(); 14 | } -------------------------------------------------------------------------------- /demos/common_header_demo/bin/loop/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=loop bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o -L/common/lib -llansys 5 | lan_main: 6 | gcc -I/common/header -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm loop test_elf lan_main.o 9 | cp: 10 | cp loop ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/common_header_demo/bin/loop/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/common_header_demo/bin/ls/lan_main.c: -------------------------------------------------------------------------------- 1 | #include "lanstd.h" 2 | 3 | void lan_main() { 4 | char buffer[124]; 5 | s_ls(buffer); 6 | int cnt = *((int *)buffer); 7 | s_print_str("There are "); 8 | s_print_num(cnt); 9 | s_print_str(" files in our filesystem:"); 10 | s_print_crlf(); 11 | s_print_str("---------------"); 12 | s_print_crlf(); 13 | for (int i = 0; i < cnt; ++i) { 14 | char *start = buffer + 4 + i * 12; 15 | int length = *((int *)start); 16 | char name[9] = {0}; 17 | for (int j = 0; j < 8; ++j) { 18 | name[j] = (start + 4)[j]; 19 | } 20 | s_print_str(name); 21 | s_print_str(" "); 22 | s_print_num(length); 23 | s_print_str(" bytes"); 24 | s_print_crlf(); 25 | } 26 | s_print_str("---------------"); 27 | s_print_crlf(); 28 | s_exit(); 29 | } 30 | -------------------------------------------------------------------------------- /demos/common_header_demo/bin/ls/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=ls bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o -L/common/lib -llansys 5 | lan_main: 6 | gcc -I/common/header -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm ls test_elf lan_main.o 9 | cp: 10 | cp ls ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/common_header_demo/bin/ls/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/common_header_demo/bin/readme.md: -------------------------------------------------------------------------------- 1 | # bin目录下二进制文件的编译方法 2 | 3 | 以loop为例 4 | 首先要source根目录下的 lan_os_rc 5 | 然后 cd loop 6 | 执行 lan_make -------------------------------------------------------------------------------- /demos/common_header_demo/bin/shell/lan_main.c: -------------------------------------------------------------------------------- 1 | #include "lanstd.h" 2 | 3 | #define SHELL_VER "0.2" 4 | int equal_buffer(char *a, char *b, int len); 5 | void lan_main() { 6 | s_print_str("--------------------------"); 7 | s_print_crlf(); 8 | s_print_str("| |"); 9 | s_print_crlf(); 10 | s_print_str("| welcome to lan_os 0.1! |"); 11 | s_print_crlf(); 12 | s_print_str("| |"); 13 | s_print_crlf(); 14 | s_print_str("| shell version is "); 15 | s_print_str(SHELL_VER); 16 | s_print_str(" |"); 17 | s_print_crlf(); 18 | s_print_str("| |"); 19 | s_print_crlf(); 20 | s_print_str("--------------------------"); 21 | s_print_crlf(); 22 | s_print_str("shell started."); 23 | s_print_crlf(); 24 | char buffer0[256]; 25 | char buffer1[256]; 26 | for (int i = 0; i < 256; ++i) { 27 | buffer0[i] = buffer1[i] = 0; 28 | } 29 | s_print_shell(buffer0); 30 | while (1) { 31 | s_get_keyboad_buffer(buffer0); 32 | if (0 != equal_buffer(buffer0, buffer1, 256)) { 33 | int enter = 0; 34 | for (int i = 0; i < 256; ++i) { 35 | if (buffer0[i] == 'E') { 36 | enter = 1; 37 | buffer0[i] = 0; 38 | break; 39 | } 40 | } 41 | if (enter) { 42 | s_clean_keyboard(); 43 | if (!s_fork()) { 44 | s_exec(buffer0); 45 | s_exit(); 46 | } 47 | } 48 | s_print_shell(buffer0); 49 | } 50 | for (int i = 0; i < 256; ++i) { 51 | buffer1[i] = buffer0[i]; 52 | } 53 | } 54 | } 55 | 56 | int equal_buffer(char *a, char *b, int len) { 57 | for (int i = 0; i < len; ++i) { 58 | if (a[i] != b[i]) { 59 | return 1; 60 | } 61 | } 62 | return 0; 63 | } -------------------------------------------------------------------------------- /demos/common_header_demo/bin/shell/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=lan_sh bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o -L/common/lib -llansys 5 | lan_main: 6 | gcc -I/common/header -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm lan_sh test_elf lan_main.o 9 | cp: 10 | cp lan_sh ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/common_header_demo/bin/shell/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/common_header_demo/bin/test/lan_main.c: -------------------------------------------------------------------------------- 1 | #include "lanstd.h" 2 | 3 | void lan_main() { 4 | s_print_str("I am a test executable file."); 5 | s_print_crlf(); 6 | s_print_str("I can print a number."); 7 | s_print_crlf(); 8 | s_print_num(222); 9 | s_print_crlf(); 10 | char buffer[64] = {0}; 11 | s_read_file_content("hello_fs", buffer); 12 | s_print_str("hello_fs content is:"); 13 | s_print_crlf(); 14 | s_print_str(buffer); 15 | s_print_crlf(); 16 | s_exit(); 17 | } -------------------------------------------------------------------------------- /demos/common_header_demo/bin/test/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=test bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o -L/common/lib -llansys 5 | lan_main: 6 | gcc -I/common/header -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm test test_elf lan_main.o 9 | cp: 10 | cp test ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/common_header_demo/bin/test/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/common_header_demo/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 72 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+17 ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | mov ax, 01220h 16 | mov es, ax 17 | mov cx, 0001h 18 | jnc ok_load1 19 | jmp $ 20 | 21 | ok_load1: 22 | mov ax, 0200h+18 ;ah 读扇区功能号2 al读扇区数量 18 23 | xor dh, 1 ;这两句是为了切换磁头 1->0 / 0->1 24 | and dh, 1 25 | int 013h 26 | mov ax, es 27 | add ax, 0240h 28 | mov es, ax 29 | jnc ok_load2 30 | jmp $ 31 | 32 | ok_load2: 33 | test dh, dh ;如果是0号磁头刚刚读取完毕,则不增加磁道号 34 | jz dontaddch 35 | add ch, 1 36 | dontaddch: 37 | mov ax, [index] 38 | sub ax, 1 39 | mov [index], ax 40 | test ax, ax 41 | jnz ok_load1 42 | 43 | ok_load: 44 | cli 45 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 46 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 47 | xor ax, ax 48 | mov es, ax 49 | mov cx, 0x3000 ;这时拷贝 0x3000*2(字节)/512=48(扇区) 48个扇区末端是0x6000 这里如果超过0x7c00就很危险了,因为可能覆盖掉第一个临时gdt 50 | sub si, si 51 | sub di, di 52 | cld ;df = 0 rep movsw是正向的 53 | rep movsw 54 | mov ax, 0x0 ;重新恢复ds指向0x0 55 | mov ds, ax 56 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 57 | mov ax, 0x0001 58 | lmsw ax 59 | jmp dword 8:0 60 | index: 61 | dw 63 ;这里63是极限 位置末尾是0x9fe00 接近显示缓冲区0xA0000 (63*18(扇区)+17(扇区))*512+0x10000=0x9fe00 62 | gdt: 63 | dw 0, 0, 0, 0 ;第一个描述符,没有用 64 | dw 0x07ff ;代码段 从0地址开始 65 | dw 0x0000 66 | dw 0x9a00 67 | dw 0x00c0 68 | dw 0x07ff ;数据段 从0地址开始 69 | dw 0x0000 70 | dw 0x9200 71 | dw 0x00c0 72 | 73 | gdt_48: 74 | dw 0x7ff ;2048/8=256个描述符 75 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 76 | 77 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 78 | times 510 - ($-$$) db 0 79 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/common_header_demo/common/header/lanstd.h: -------------------------------------------------------------------------------- 1 | #ifndef LANSTD_H 2 | #define LANSTD_H 3 | /* 4 | _syscall0(int, s_test_sys_call) 5 | _syscall0(int, s_fork) 6 | _syscall0(int, s_test_sys_call2) 7 | _syscall1(int, s_print_str, char*, msg) 8 | _syscall1(int, s_print_num, int, num) 9 | _syscall2(int, s_read_file_content, char*, file_name, char*, buffer) 10 | _syscall1(int, s_exec, char*, file_name) 11 | _syscall1(int, s_get_keyboad_buffer, char*, buffer) 12 | _syscall0(int, s_clean_keyboard) 13 | _syscall1(int, s_print_shell, char*, buffer) 14 | _syscall0(int, s_exit) 15 | */ 16 | int s_test_sys_call(); 17 | int s_fork(); 18 | int s_test_sys_call2(); 19 | int s_print_str(char *); 20 | int s_print_num(int); 21 | int s_read_file_content(char *, char *); 22 | int s_exec(char *); 23 | int s_get_keyboad_buffer(char *); 24 | int s_clean_keyboard(); 25 | int s_print_shell(char *); 26 | int s_ls(char *); 27 | int s_exit(); 28 | int s_print_crlf(); 29 | #endif -------------------------------------------------------------------------------- /demos/common_header_demo/common/lib/liblansys.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/common_header_demo/common/lib/liblansys.a -------------------------------------------------------------------------------- /demos/common_header_demo/common/lib/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -m32 -g -fno-stack-protector -fno-pie -c lansys.c 3 | ar -r liblansys.a lansys.o 4 | clean: 5 | rm lansys.o liblansys.a 6 | -------------------------------------------------------------------------------- /demos/common_header_demo/exit.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | #include "sched.h" 3 | void _sys_exit() { 4 | current->state = TASK_ZOMBIE; 5 | unsigned long data_base = get_data_base(current); 6 | unsigned long data_limit = get_limit(0x17); 7 | free_page_tables(data_base, data_limit); 8 | schedule(); 9 | } -------------------------------------------------------------------------------- /demos/common_header_demo/fork.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | #include "sched.h" 3 | 4 | extern void panic(char *msg); 5 | 6 | extern void first_return_from_kernel(); 7 | unsigned long get_data_base(struct task_struct *s) { 8 | unsigned long ret = (s->ldt[2].a) >> 16; 9 | ret |= (s->ldt[2].b & 0xff) << 16; 10 | ret |= s->ldt[2].b & 0xff000000; 11 | return ret; 12 | } 13 | 14 | int copy_mem(int nr, struct task_struct *p) { 15 | unsigned long old_data_base, new_data_base, data_limit; 16 | unsigned long new_code_base, code_limit; 17 | 18 | code_limit = get_limit(0x0f); 19 | data_limit = get_limit(0x17); 20 | old_data_base = get_data_base(current); 21 | new_data_base = new_code_base = nr * TASK_SIZE + PG_NUM * 4 * 1024 * 1024; 22 | p->start_code = new_code_base; 23 | set_base(&(p->ldt[1]), new_code_base); 24 | set_base(&(p->ldt[2]), new_data_base); 25 | if (copy_page_tables(old_data_base, new_data_base, data_limit)) { 26 | // todo 27 | // free_page_tables 28 | panic("copy page tables failed."); 29 | } 30 | return 0; 31 | } 32 | 33 | int find_empty_process() { 34 | for (int i = 0; i < NR_TASKS; ++i) { 35 | if (!task_used[i]) { 36 | task_used[i] = 1; 37 | return i; 38 | } 39 | } 40 | return -1; 41 | } 42 | 43 | int copy_process(long eax, long ebp, long edi, long esi, long gs, long none, 44 | long ebx, long ecx, long edx, long orig_eax, long fs, long es, 45 | long ds, long eip, long cs, long eflags, long esp, long ss) { 46 | if (eax < 0) { 47 | panic("no emtpy task."); 48 | } 49 | struct task_struct *p = (struct task_struct *)get_free_page(); 50 | 51 | if (!p) { 52 | // todo 53 | } 54 | *p = *current; 55 | p->state = TASK_UNINTERRUPTIBLE; 56 | p->pid = eax; 57 | task[eax] = p; 58 | long *krnstack = (long *)(PAGE_SIZE + (long)p); 59 | *(--krnstack) = ss; 60 | *(--krnstack) = esp; 61 | *(--krnstack) = eflags; 62 | *(--krnstack) = cs; 63 | *(--krnstack) = eip; 64 | *(--krnstack) = first_return_from_kernel; 65 | *(--krnstack) = 0; // eax 66 | *(--krnstack) = ebx; 67 | *(--krnstack) = ecx; 68 | *(--krnstack) = edx; 69 | *(--krnstack) = ebp; 70 | *(--krnstack) = esi; 71 | *(--krnstack) = edi; 72 | *(--krnstack) = es & 0xffff; 73 | *(--krnstack) = ds & 0xffff; 74 | *(--krnstack) = fs & 0xffff; 75 | *(--krnstack) = gs & 0xffff; 76 | p->kernel_stack = krnstack; 77 | if (copy_mem(eax, p)) { 78 | // todo: 79 | // abort 80 | } 81 | set_ldt_desc(gdt + eax + FIRST_LDT_ENTRY, &(p->ldt)); 82 | p->state = TASK_RUNNING; 83 | return 1; 84 | } 85 | -------------------------------------------------------------------------------- /demos/common_header_demo/fs_patch_tool/patch.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const file_list = [ 4 | 'hello_fs', 5 | 'test', 6 | 'lan_sh', 7 | 'ls', 8 | 'loop', 9 | ]; 10 | 11 | function zero_buffer(size) { 12 | let ret = Buffer.alloc(size); 13 | for (let i = 0; i < size; ++i) { 14 | ret[i] = 0; 15 | } 16 | return ret; 17 | } 18 | 19 | async function main() { 20 | const vfd_path = `${__dirname}/../a.vfd`; 21 | const vfd_content = fs.readFileSync(vfd_path); 22 | console.log('vfd_content length : ', vfd_content.length); 23 | const vfd_length = vfd_content.length; 24 | let fs_header = zero_buffer(4); 25 | const file_cnt = file_list.length; 26 | fs_header.writeInt32LE(file_cnt); 27 | let file_buffer = zero_buffer(0); 28 | for (let i = 0; i < file_cnt; ++i) { 29 | const path = `${__dirname}/../root_fs/${file_list[i]}`; 30 | const content = fs.readFileSync(path); 31 | const content_length = content.length; 32 | console.log(`path ${path} : ${content_length}`); 33 | const file_length_buffer = zero_buffer(4); 34 | const file_name_buffer = zero_buffer(8); 35 | file_length_buffer.writeInt32LE(content_length); 36 | Buffer.from(file_list[i]).copy(file_name_buffer); 37 | fs_header = Buffer.concat([fs_header, file_length_buffer, file_name_buffer]); 38 | const file_pad = zero_buffer(20 * 1024 - content_length); 39 | file_buffer = Buffer.concat([file_buffer, content, file_pad]); 40 | } 41 | const fs_header_pad = zero_buffer(124 - fs_header.length); 42 | fs_header = Buffer.concat([fs_header, fs_header_pad]); 43 | console.log('fs_header length : ', fs_header.length); 44 | const start = 0x5df84; // 0x90000-200k-124 在内存中的位置应该是0x5df84-0x200+0x10000=0x6dd84 45 | const p0 = vfd_content.slice(0, start); 46 | const p1 = Buffer.concat([fs_header, file_buffer]); 47 | const p2 = vfd_content.slice(start + p1.length); 48 | const final_buffer = Buffer.concat([p0, p1, p2]); 49 | fs.writeFileSync(vfd_path, final_buffer); 50 | process.exit(); 51 | } 52 | main(); -------------------------------------------------------------------------------- /demos/common_header_demo/gate_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef GATE_TOOL_H 2 | #define GATE_TOOL_H 3 | 4 | #include "sched.h" 5 | 6 | #define _set_gate(gate_addr, type, dpl, addr) \ 7 | __asm__( \ 8 | "movw %%dx,%%ax\n\t" \ 9 | "movw %0,%%dx\n\t" \ 10 | "movl %%eax,%1\n\t" \ 11 | "movl %%edx,%2" \ 12 | : \ 13 | : "i"((short)(0x8000 + (dpl << 13) + (type << 8))), \ 14 | "o"(*((char *)(gate_addr))), "o"(*(4 + (char *)(gate_addr))), \ 15 | "d"((char *)(addr)), "a"(0x00080000)) 16 | 17 | #define set_intr_gate(n, addr) _set_gate(&idt[n], 14, 0, addr) 18 | 19 | #define set_trap_gate(n, addr) _set_gate(&idt[n], 15, 0, addr) 20 | 21 | #define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr) 22 | #endif -------------------------------------------------------------------------------- /demos/common_header_demo/intel_err_handle.c: -------------------------------------------------------------------------------- 1 | extern void print_str(char *s); 2 | extern void panic(char *msg); 3 | 4 | void e0() { print_str("e0"); } 5 | 6 | void e1() { print_str("e1"); } 7 | 8 | void e2() { print_str("e2"); } 9 | 10 | void e3() { print_str("e3"); } 11 | 12 | void e4() { print_str("e4"); } 13 | 14 | void e5() { print_str("e5"); } 15 | 16 | void e6() { print_str("e6"); } 17 | 18 | void e7() { print_str("e7"); } 19 | 20 | void e8() { print_str("e8"); } 21 | 22 | void e9() { print_str("e9"); } 23 | 24 | void e10() { print_str("e10"); } 25 | 26 | void e11() { print_str("e11"); } 27 | 28 | void e12() { panic("e12"); } 29 | 30 | void e13() { panic("e13"); } 31 | 32 | void e15() { print_str("e15"); } 33 | 34 | void e16() { print_str("e16"); } 35 | -------------------------------------------------------------------------------- /demos/common_header_demo/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=62 skip=8 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=63 conv=notrunc 6 | node fs_patch_tool/patch.js 7 | link: head lan_main boot 8 | ld -m elf_i386 -T n.lds -o lan_os head.o lan_main.o sys_call.o intel_err_handle.o sched.o fork.o mm.o print_str.o keyboard.o exit.o 9 | head: 10 | nasm -felf32 -o head.o head.s 11 | lan_main: 12 | gcc -O0 -m32 -g -fno-stack-protector -fno-pie -c lan_main.c sys_call.c intel_err_handle.c sched.c fork.c mm.c print_str.c keyboard.c exit.c 13 | boot: 14 | nasm -o boot.bin boot.s -l boot.lst 15 | clean: 16 | rm lan_os lan_main.o sys_call.o intel_err_handle.o head.o sched.o fork.o mm.o print_str.o keyboard.o exit.o boot.bin boot.lst a.img a.vfd 17 | -------------------------------------------------------------------------------- /demos/common_header_demo/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef MM_H 2 | #define MM_H 3 | 4 | #define PAGE_SIZE 4096 5 | #define PAGE_DIR 0x10000 6 | #define PG_NUM 16 7 | 8 | #define LOW_MEM 0x100000 9 | #define MAP_NR(addr) (((addr)-LOW_MEM) >> 12) 10 | #define invalidate() __asm__("movl %%eax,%%cr3" ::"a"(PAGE_DIR)) 11 | 12 | #include "sched.h" 13 | 14 | extern void mm_init(); 15 | extern unsigned long get_free_page(); 16 | extern int free_page_tables(unsigned long from, unsigned long size); 17 | extern int copy_page_tables(unsigned long from, unsigned long to, long size); 18 | extern unsigned long get_data_base(struct task_struct *s); 19 | extern void free_page(unsigned long addr); 20 | #endif -------------------------------------------------------------------------------- /demos/common_header_demo/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/common_header_demo/readme.md: -------------------------------------------------------------------------------- 1 | # 整理头文件和库文件 -------------------------------------------------------------------------------- /demos/common_header_demo/root_fs/hello_fs: -------------------------------------------------------------------------------- 1 | hi, lan_os. it's a nice day!!! -------------------------------------------------------------------------------- /demos/common_header_demo/root_fs/lan_sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/common_header_demo/root_fs/lan_sh -------------------------------------------------------------------------------- /demos/common_header_demo/root_fs/loop: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/common_header_demo/root_fs/loop -------------------------------------------------------------------------------- /demos/common_header_demo/root_fs/ls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/common_header_demo/root_fs/ls -------------------------------------------------------------------------------- /demos/common_header_demo/root_fs/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/common_header_demo/root_fs/test -------------------------------------------------------------------------------- /demos/common_header_demo/sched.c: -------------------------------------------------------------------------------- 1 | #include "sched.h" 2 | #include "mm.h" 3 | 4 | struct task_struct *task[NR_TASKS]; 5 | int task_used[NR_TASKS]; 6 | struct task_struct init_task; 7 | struct task_struct *current = (struct task_struct *)&init_task; 8 | long last_sched_i = 0; 9 | 10 | extern void switch_to(unsigned long, struct task_struct *); 11 | extern void set_tss0_esp0(unsigned long); 12 | extern void get_esp0_when_switch(unsigned long *); 13 | extern void krn_stk0(); 14 | 15 | void sched_init() { 16 | for (int i = 0; i < NR_TASKS; ++i) { 17 | task[i] = 0; 18 | task_used[i] = 0; 19 | } 20 | task_used[0] = 1; 21 | init_task.state = TASK_UNINTERRUPTIBLE; 22 | init_task.pid = 0; 23 | init_task.ldt[0].a = 0; 24 | init_task.ldt[0].b = 0; 25 | init_task.ldt[1].a = 0x3ff; 26 | init_task.ldt[1].b = 0xc0fa00; 27 | init_task.ldt[2].a = 0x3ff; 28 | init_task.ldt[2].b = 0xc0f200; 29 | set_ldt_desc(gdt + 0 + FIRST_LDT_ENTRY, &(init_task.ldt)); 30 | task[0] = &init_task; 31 | lldt(0); 32 | init_task.state = TASK_RUNNING; 33 | } 34 | 35 | void schedule() { 36 | int i = last_sched_i; 37 | while (1) { 38 | ++i; 39 | i %= NR_TASKS; 40 | if (task[i]) { 41 | if (task[i]->state == TASK_ZOMBIE) { 42 | free_page((unsigned long)task[i]); 43 | task[i] = 0; 44 | task_used[i] = 0; 45 | continue; 46 | } 47 | if (current->pid != i) { 48 | if (task[i]->state == TASK_RUNNING) { 49 | last_sched_i = i; 50 | if (0 == i) { 51 | set_tss0_esp0( 52 | krn_stk0); // 0任务的内核栈是写死的,不能用task[i])+PAGE_SIZE来计算 53 | } else { 54 | set_tss0_esp0((unsigned long)(task[i]) + 55 | PAGE_SIZE); //给切换栈机制搭桥 56 | } 57 | unsigned long esp0 = 0; 58 | get_esp0_when_switch(&esp0); 59 | current->kernel_stack = esp0; 60 | current = task[i]; 61 | switch_to(_LDT(i), task[i]); 62 | return; 63 | } 64 | } 65 | } 66 | } 67 | } 68 | 69 | void do_timer(unsigned long cs) { 70 | if (0x8 == cs) { 71 | } else if (0xf == cs) { 72 | schedule(); 73 | } else { 74 | } 75 | } -------------------------------------------------------------------------------- /demos/cp_on_write/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 48 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+SYSLEN ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | jnc ok_load 16 | jmp $ 17 | 18 | ok_load: 19 | cli 20 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 21 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 22 | xor ax, ax 23 | mov es, ax 24 | mov cx, 0x3000 ;这时拷贝 0x3000*2(字节)/512=48(扇区) 25 | sub si, si 26 | sub di, di 27 | cld ;df = 0 rep movsw是正向的 28 | rep movsw 29 | mov ax, 0x0 ;重新恢复ds指向0x0 30 | mov ds, ax 31 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 32 | mov ax, 0x0001 33 | lmsw ax 34 | jmp dword 8:0 35 | gdt: 36 | dw 0, 0, 0, 0 ;第一个描述符,没有用 37 | dw 0x07ff ;代码段 从0地址开始 38 | dw 0x0000 39 | dw 0x9a00 40 | dw 0x00c0 41 | dw 0x07ff ;数据段 从0地址开始 42 | dw 0x0000 43 | dw 0x9200 44 | dw 0x00c0 45 | 46 | 47 | gdt_48: 48 | dw 0x7ff ;2048/8=256个描述符 49 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 50 | 51 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 52 | times 510 - ($-$$) db 0 53 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/cp_on_write/fork.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | #include "sched.h" 3 | 4 | extern void first_return_from_kernel(); 5 | unsigned long get_data_base(struct task_struct *s) { 6 | unsigned long ret = (s->ldt[2].a) >> 16; 7 | ret |= (s->ldt[2].b & 0xff) << 16; 8 | ret |= s->ldt[2].b & 0xff000000; 9 | return ret; 10 | } 11 | 12 | int copy_mem(int nr, struct task_struct *p) { 13 | unsigned long old_data_base, new_data_base, data_limit; 14 | unsigned long new_code_base, code_limit; 15 | 16 | code_limit = get_limit(0x0f); 17 | data_limit = get_limit(0x17); 18 | old_data_base = get_data_base(current); 19 | new_data_base = new_code_base = nr * TASK_SIZE + PG_NUM * 4 * 1024 * 1024; 20 | p->start_code = new_code_base; 21 | set_base(&(p->ldt[1]), new_code_base); 22 | set_base(&(p->ldt[2]), new_data_base); 23 | if (copy_page_tables(old_data_base, new_data_base, data_limit)) { 24 | // todo 25 | // free_page_tables 26 | } 27 | return 0; 28 | } 29 | 30 | int find_empty_process() { return ++last_pid; } 31 | 32 | int copy_process(long eax, long ebp, long edi, long esi, long gs, long none, 33 | long ebx, long ecx, long edx, long orig_eax, long fs, long es, 34 | long ds, long eip, long cs, long eflags, long esp, long ss) { 35 | struct task_struct *p = (struct task_struct *)get_free_page(); 36 | 37 | if (!p) { 38 | // todo 39 | } 40 | *p = *current; 41 | p->state = TASK_UNINTERRUPTIBLE; 42 | p->pid = eax; 43 | task[last_pid] = p; 44 | long *krnstack = (long *)(PAGE_SIZE + (long)p); 45 | *(--krnstack) = ss; 46 | *(--krnstack) = esp; 47 | *(--krnstack) = eflags; 48 | *(--krnstack) = cs; 49 | *(--krnstack) = eip; 50 | *(--krnstack) = first_return_from_kernel; 51 | *(--krnstack) = 0; // eax 52 | *(--krnstack) = ebx; 53 | *(--krnstack) = ecx; 54 | *(--krnstack) = edx; 55 | *(--krnstack) = ebp; 56 | *(--krnstack) = esi; 57 | *(--krnstack) = edi; 58 | *(--krnstack) = es & 0xffff; 59 | *(--krnstack) = ds & 0xffff; 60 | *(--krnstack) = fs & 0xffff; 61 | *(--krnstack) = gs & 0xffff; 62 | p->kernel_stack = krnstack; 63 | if (copy_mem(last_pid, p)) { 64 | // todo: 65 | // abort 66 | } 67 | set_ldt_desc(gdt + last_pid + FIRST_LDT_ENTRY, &(p->ldt)); 68 | p->state = TASK_RUNNING; 69 | return 1; 70 | } 71 | -------------------------------------------------------------------------------- /demos/cp_on_write/gate_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef GATE_TOOL_H 2 | #define GATE_TOOL_H 3 | 4 | #include "sched.h" 5 | 6 | #define _set_gate(gate_addr, type, dpl, addr) \ 7 | __asm__( \ 8 | "movw %%dx,%%ax\n\t" \ 9 | "movw %0,%%dx\n\t" \ 10 | "movl %%eax,%1\n\t" \ 11 | "movl %%edx,%2" \ 12 | : \ 13 | : "i"((short)(0x8000 + (dpl << 13) + (type << 8))), \ 14 | "o"(*((char *)(gate_addr))), "o"(*(4 + (char *)(gate_addr))), \ 15 | "d"((char *)(addr)), "a"(0x00080000)) 16 | 17 | #define set_intr_gate(n, addr) _set_gate(&idt[n], 14, 0, addr) 18 | 19 | #define set_trap_gate(n, addr) _set_gate(&idt[n], 15, 0, addr) 20 | 21 | #define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr) 22 | #endif -------------------------------------------------------------------------------- /demos/cp_on_write/intel_err_handle.c: -------------------------------------------------------------------------------- 1 | extern void write_char(char ch); 2 | 3 | void e0() { write_char('0'); } 4 | 5 | void e1() { write_char('1'); } 6 | 7 | void e2() { write_char('2'); } 8 | 9 | void e3() { write_char('3'); } 10 | 11 | void e4() { write_char('4'); } 12 | 13 | void e5() { write_char('5'); } 14 | 15 | void e6() { write_char('6'); } 16 | 17 | void e7() { write_char('7'); } 18 | 19 | void e8() { write_char('8'); } 20 | 21 | void e9() { write_char('9'); } 22 | 23 | void e10() { 24 | write_char('1'); 25 | write_char('0'); 26 | } 27 | 28 | void e11() { 29 | write_char('1'); 30 | write_char('1'); 31 | } 32 | 33 | void e12() { 34 | write_char('1'); 35 | write_char('2'); 36 | } 37 | 38 | void e13() { 39 | write_char('1'); 40 | write_char('3'); 41 | } 42 | 43 | void e15() { 44 | write_char('1'); 45 | write_char('5'); 46 | } 47 | 48 | void e16() { 49 | write_char('1'); 50 | write_char('6'); 51 | } 52 | -------------------------------------------------------------------------------- /demos/cp_on_write/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=44 skip=8 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=45 conv=notrunc 6 | link: head lan_main boot 7 | ld -m elf_i386 -T n.lds -o lan_os head.o lan_main.o sys_call.o intel_err_handle.o sched.o fork.o mm.o 8 | head: 9 | nasm -felf32 -o head.o head.s 10 | lan_main: 11 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c sys_call.c intel_err_handle.c sched.c fork.c mm.c 12 | boot: 13 | nasm -o boot.bin boot.s -l boot.lst 14 | clean: 15 | rm lan_os lan_main.o sys_call.o intel_err_handle.o head.o sched.o fork.o mm.o boot.bin boot.lst a.img a.vfd 16 | 17 | -------------------------------------------------------------------------------- /demos/cp_on_write/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef MM_H 2 | #define MM_H 3 | 4 | #define PAGE_SIZE 4096 5 | #define PAGE_DIR 0x8000 6 | #define PG_NUM 16 7 | 8 | #define LOW_MEM 0x100000 9 | #define MAP_NR(addr) (((addr)-LOW_MEM) >> 12) 10 | #define invalidate() __asm__("movl %%eax,%%cr3" ::"a"(PAGE_DIR)) 11 | 12 | extern void mm_init(); 13 | extern unsigned long get_free_page(); 14 | extern int copy_page_tables(unsigned long from, unsigned long to, long size); 15 | 16 | #endif -------------------------------------------------------------------------------- /demos/cp_on_write/move_to_user_mode.h: -------------------------------------------------------------------------------- 1 | #ifndef MOV_TO_USER_MODE_H 2 | #define MOV_TO_USER_MODE_H 3 | #define move_to_user_mode() \ 4 | __asm__( \ 5 | "movl %%esp,%%eax\n\t" \ 6 | "pushl $0x17\n\t" \ 7 | "pushl %%eax\n\t" \ 8 | "pushfl\n\t" \ 9 | "pushl $0x0f\n\t" \ 10 | "pushl $1f\n\t" \ 11 | "iret\n" \ 12 | "1:\tmovl $0x17,%%eax\n\t" \ 13 | "mov %%ax,%%ds\n\t" \ 14 | "mov %%ax,%%es\n\t" \ 15 | "mov %%ax,%%fs\n\t" \ 16 | "mov %%ax,%%gs" :: \ 17 | : "ax") 18 | #define sti() __asm__("sti" ::) 19 | 20 | #define _syscall0(type, name) \ 21 | type name(void) { \ 22 | long __res; \ 23 | __asm__ volatile("int $0x80" : "=a"(__res) : "0"(__NR_##name)); \ 24 | if (__res >= 0) return (type)__res; \ 25 | return -1; \ 26 | } 27 | #endif -------------------------------------------------------------------------------- /demos/cp_on_write/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/cp_on_write/readme.md: -------------------------------------------------------------------------------- 1 | ### 调试中遇到的问题 2 | 1. int14 iret的时候需要将栈上的错误码pop出去或者将esp加4 3 | 2. int14 时需要将gs的原始值保存,需要将gs置为0x10,也就是内核数据段 -------------------------------------------------------------------------------- /demos/cp_on_write/sched.c: -------------------------------------------------------------------------------- 1 | #include "sched.h" 2 | #include "mm.h" 3 | 4 | struct task_struct *task[NR_TASKS]; 5 | struct task_struct init_task; 6 | struct task_struct *current = (struct task_struct *)&init_task; 7 | long last_pid = -1; 8 | long last_sched_i = 0; 9 | 10 | extern void switch_to(unsigned long, struct task_struct *); 11 | extern void set_tss0_esp0(unsigned long); 12 | extern void get_esp0_when_switch(unsigned long *); 13 | extern void krn_stk0(); 14 | 15 | void sched_init() { 16 | for (int i = 0; i < NR_TASKS; ++i) { 17 | task[i] = 0; 18 | } 19 | init_task.state = TASK_UNINTERRUPTIBLE; 20 | init_task.pid = ++last_pid; 21 | init_task.ldt[0].a = 0; 22 | init_task.ldt[0].b = 0; 23 | init_task.ldt[1].a = 0x3ff; 24 | init_task.ldt[1].b = 0xc0fa00; 25 | init_task.ldt[2].a = 0x3ff; 26 | init_task.ldt[2].b = 0xc0f200; 27 | set_ldt_desc(gdt + 0 + FIRST_LDT_ENTRY, &(init_task.ldt)); 28 | task[0] = &init_task; 29 | lldt(0); 30 | init_task.state = TASK_RUNNING; 31 | } 32 | 33 | void schedule() { 34 | int i = last_sched_i; 35 | while (1) { 36 | ++i; 37 | i %= NR_TASKS; 38 | if (task[i]) { 39 | if (current->pid != i) { 40 | if (task[i]->state == TASK_RUNNING) { 41 | last_sched_i = i; 42 | if (0 == i) { 43 | set_tss0_esp0( 44 | krn_stk0); // 0任务的内核栈是写死的,不能用task[i])+PAGE_SIZE来计算 45 | } else { 46 | set_tss0_esp0((unsigned long)(task[i]) + 47 | PAGE_SIZE); //给切换栈机制搭桥 48 | } 49 | unsigned long esp0 = 0; 50 | get_esp0_when_switch(&esp0); 51 | current->kernel_stack = esp0; 52 | current = task[i]; 53 | switch_to(_LDT(i), task[i]); 54 | return; 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | void do_timer(unsigned long cs) { 62 | if (0x8 == cs) { 63 | // write_char('K'); 64 | } else if (0xf == cs) { 65 | // write_char('T'); 66 | schedule(); 67 | } else { 68 | write_char('U'); 69 | } 70 | } -------------------------------------------------------------------------------- /demos/cp_on_write/sys_call.c: -------------------------------------------------------------------------------- 1 | extern void write_char(char ch); 2 | typedef int (*sys_call)(); 3 | 4 | int _test_sys_call() { 5 | write_char('f'); 6 | return 0; 7 | } 8 | 9 | int _test_sys_call1() { 10 | write_char('g'); 11 | return 0; 12 | } 13 | 14 | int _test_sys_call2() { 15 | write_char('h'); 16 | return 0; 17 | } 18 | 19 | extern void sys_fork(); 20 | 21 | extern sys_call sys_call_table[] = {_test_sys_call, sys_fork, _test_sys_call1, 22 | _test_sys_call2}; -------------------------------------------------------------------------------- /demos/exec_demo/bin/test/lan_main.c: -------------------------------------------------------------------------------- 1 | #define _syscall1(type, name, atype, a) \ 2 | type name(atype a) { \ 3 | long __res; \ 4 | __asm__ volatile("int $0x80" \ 5 | : "=a"(__res) \ 6 | : "0"(__NR_##name), "b"((long)(a))); \ 7 | if (__res >= 0) return (type)__res; \ 8 | return -1; \ 9 | } 10 | 11 | int s_print_str(char*); 12 | int s_print_num(int); 13 | 14 | void lan_main() { 15 | s_print_str("im test"); 16 | s_print_num(222); 17 | while (1) 18 | ; 19 | } 20 | #define __NR_s_print_str 4 21 | #define __NR_s_print_num 5 22 | _syscall1(int, s_print_str, char*, msg) _syscall1(int, s_print_num, int, num) -------------------------------------------------------------------------------- /demos/exec_demo/bin/test/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=test bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o 5 | lan_main: 6 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm test test_elf lan_main.o 9 | cp: 10 | cp test ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/exec_demo/bin/test/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/exec_demo/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 72 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+17 ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | mov ax, 01220h 16 | mov es, ax 17 | mov cx, 0001h 18 | jnc ok_load1 19 | jmp $ 20 | 21 | ok_load1: 22 | mov ax, 0200h+18 ;ah 读扇区功能号2 al读扇区数量 18 23 | xor dh, 1 24 | and dh, 1 25 | int 013h 26 | mov ax, es 27 | add ax, 0240h 28 | mov es, ax 29 | jnc ok_load2 30 | jmp $ 31 | 32 | ok_load2: 33 | test dh, dh 34 | jz dontaddch 35 | add ch, 1 36 | dontaddch: 37 | mov ax, [index] 38 | sub ax, 1 39 | mov [index], ax 40 | test ax, ax 41 | jnz ok_load1 42 | 43 | ok_load: 44 | cli 45 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 46 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 47 | xor ax, ax 48 | mov es, ax 49 | mov cx, 0x3000 ;这时拷贝 0x3000*2(字节)/512=48(扇区) 50 | sub si, si 51 | sub di, di 52 | cld ;df = 0 rep movsw是正向的 53 | rep movsw 54 | mov ax, 0x0 ;重新恢复ds指向0x0 55 | mov ds, ax 56 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 57 | mov ax, 0x0001 58 | lmsw ax 59 | jmp dword 8:0 60 | index: 61 | dw 63 ;这里63是极限 位置末尾是0x9fe00 接近显示缓冲区0xA0000 62 | gdt: 63 | dw 0, 0, 0, 0 ;第一个描述符,没有用 64 | dw 0x07ff ;代码段 从0地址开始 65 | dw 0x0000 66 | dw 0x9a00 67 | dw 0x00c0 68 | dw 0x07ff ;数据段 从0地址开始 69 | dw 0x0000 70 | dw 0x9200 71 | dw 0x00c0 72 | 73 | gdt_48: 74 | dw 0x7ff ;2048/8=256个描述符 75 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 76 | 77 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 78 | times 510 - ($-$$) db 0 79 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/exec_demo/fork.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | #include "sched.h" 3 | 4 | extern void panic(char *msg); 5 | 6 | extern void first_return_from_kernel(); 7 | unsigned long get_data_base(struct task_struct *s) { 8 | unsigned long ret = (s->ldt[2].a) >> 16; 9 | ret |= (s->ldt[2].b & 0xff) << 16; 10 | ret |= s->ldt[2].b & 0xff000000; 11 | return ret; 12 | } 13 | 14 | int copy_mem(int nr, struct task_struct *p) { 15 | unsigned long old_data_base, new_data_base, data_limit; 16 | unsigned long new_code_base, code_limit; 17 | 18 | code_limit = get_limit(0x0f); 19 | data_limit = get_limit(0x17); 20 | old_data_base = get_data_base(current); 21 | new_data_base = new_code_base = nr * TASK_SIZE + PG_NUM * 4 * 1024 * 1024; 22 | p->start_code = new_code_base; 23 | set_base(&(p->ldt[1]), new_code_base); 24 | set_base(&(p->ldt[2]), new_data_base); 25 | if (copy_page_tables(old_data_base, new_data_base, data_limit)) { 26 | // todo 27 | // free_page_tables 28 | panic("copy page tables failed."); 29 | } 30 | return 0; 31 | } 32 | 33 | int find_empty_process() { return ++last_pid; } 34 | 35 | int copy_process(long eax, long ebp, long edi, long esi, long gs, long none, 36 | long ebx, long ecx, long edx, long orig_eax, long fs, long es, 37 | long ds, long eip, long cs, long eflags, long esp, long ss) { 38 | struct task_struct *p = (struct task_struct *)get_free_page(); 39 | 40 | if (!p) { 41 | // todo 42 | } 43 | *p = *current; 44 | p->state = TASK_UNINTERRUPTIBLE; 45 | p->pid = eax; 46 | task[last_pid] = p; 47 | long *krnstack = (long *)(PAGE_SIZE + (long)p); 48 | *(--krnstack) = ss; 49 | *(--krnstack) = esp; 50 | *(--krnstack) = eflags; 51 | *(--krnstack) = cs; 52 | *(--krnstack) = eip; 53 | *(--krnstack) = first_return_from_kernel; 54 | *(--krnstack) = 0; // eax 55 | *(--krnstack) = ebx; 56 | *(--krnstack) = ecx; 57 | *(--krnstack) = edx; 58 | *(--krnstack) = ebp; 59 | *(--krnstack) = esi; 60 | *(--krnstack) = edi; 61 | *(--krnstack) = es & 0xffff; 62 | *(--krnstack) = ds & 0xffff; 63 | *(--krnstack) = fs & 0xffff; 64 | *(--krnstack) = gs & 0xffff; 65 | p->kernel_stack = krnstack; 66 | if (copy_mem(last_pid, p)) { 67 | // todo: 68 | // abort 69 | } 70 | set_ldt_desc(gdt + last_pid + FIRST_LDT_ENTRY, &(p->ldt)); 71 | p->state = TASK_RUNNING; 72 | return 1; 73 | } 74 | -------------------------------------------------------------------------------- /demos/exec_demo/fs_patch_tool/patch.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const file_list = [ 4 | 'hello_fs', 5 | 'test' 6 | ]; 7 | 8 | function zero_buffer(size) { 9 | let ret = Buffer.alloc(size); 10 | for (let i = 0; i < size; ++i) { 11 | ret[i] = 0; 12 | } 13 | return ret; 14 | } 15 | 16 | async function main() { 17 | const vfd_path = `${__dirname}/../a.vfd`; 18 | const vfd_content = fs.readFileSync(vfd_path); 19 | console.log('vfd_content length : ', vfd_content.length); 20 | const vfd_length = vfd_content.length; 21 | let fs_header = zero_buffer(4); 22 | const file_cnt = file_list.length; 23 | fs_header.writeInt32LE(file_cnt); 24 | let file_buffer = zero_buffer(0); 25 | for (let i = 0; i < file_cnt; ++i) { 26 | const path = `${__dirname}/../root_fs/${file_list[i]}`; 27 | const content = fs.readFileSync(path); 28 | const content_length = content.length; 29 | console.log(`path ${path} : ${content_length}`); 30 | const file_length_buffer = zero_buffer(4); 31 | const file_name_buffer = zero_buffer(8); 32 | file_length_buffer.writeInt32LE(content_length); 33 | Buffer.from(file_list[i]).copy(file_name_buffer); 34 | fs_header = Buffer.concat([fs_header, file_length_buffer, file_name_buffer]); 35 | const file_pad = zero_buffer(20 * 1024 - content_length); 36 | file_buffer = Buffer.concat([file_buffer, content, file_pad]); 37 | } 38 | const fs_header_pad = zero_buffer(124 - fs_header.length); 39 | fs_header = Buffer.concat([fs_header, fs_header_pad]); 40 | console.log('fs_header length : ', fs_header.length); 41 | const start = 0x5df84; // 0x90000-200k-124 在内存中的位置应该是0x5df84-0x200+0x10000=0x6dd84 42 | const p0 = vfd_content.slice(0, start); 43 | const p1 = Buffer.concat([fs_header, file_buffer]); 44 | const p2 = vfd_content.slice(start + p1.length); 45 | const final_buffer = Buffer.concat([p0, p1, p2]); 46 | fs.writeFileSync(vfd_path, final_buffer); 47 | process.exit(); 48 | } 49 | main(); -------------------------------------------------------------------------------- /demos/exec_demo/gate_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef GATE_TOOL_H 2 | #define GATE_TOOL_H 3 | 4 | #include "sched.h" 5 | 6 | #define _set_gate(gate_addr, type, dpl, addr) \ 7 | __asm__( \ 8 | "movw %%dx,%%ax\n\t" \ 9 | "movw %0,%%dx\n\t" \ 10 | "movl %%eax,%1\n\t" \ 11 | "movl %%edx,%2" \ 12 | : \ 13 | : "i"((short)(0x8000 + (dpl << 13) + (type << 8))), \ 14 | "o"(*((char *)(gate_addr))), "o"(*(4 + (char *)(gate_addr))), \ 15 | "d"((char *)(addr)), "a"(0x00080000)) 16 | 17 | #define set_intr_gate(n, addr) _set_gate(&idt[n], 14, 0, addr) 18 | 19 | #define set_trap_gate(n, addr) _set_gate(&idt[n], 15, 0, addr) 20 | 21 | #define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr) 22 | #endif -------------------------------------------------------------------------------- /demos/exec_demo/intel_err_handle.c: -------------------------------------------------------------------------------- 1 | extern void print_str(char *s); 2 | extern void panic(char *msg); 3 | 4 | void e0() { print_str("e0"); } 5 | 6 | void e1() { print_str("e1"); } 7 | 8 | void e2() { print_str("e2"); } 9 | 10 | void e3() { print_str("e3"); } 11 | 12 | void e4() { print_str("e4"); } 13 | 14 | void e5() { print_str("e5"); } 15 | 16 | void e6() { print_str("e6"); } 17 | 18 | void e7() { print_str("e7"); } 19 | 20 | void e8() { print_str("e8"); } 21 | 22 | void e9() { print_str("e9"); } 23 | 24 | void e10() { print_str("e10"); } 25 | 26 | void e11() { print_str("e11"); } 27 | 28 | void e12() { panic("e12"); } 29 | 30 | void e13() { panic("e13"); } 31 | 32 | void e15() { print_str("e15"); } 33 | 34 | void e16() { print_str("e16"); } 35 | -------------------------------------------------------------------------------- /demos/exec_demo/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=62 skip=8 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=63 conv=notrunc 6 | node fs_patch_tool/patch.js 7 | link: head lan_main boot 8 | ld -m elf_i386 -T n.lds -o lan_os head.o lan_main.o sys_call.o intel_err_handle.o sched.o fork.o mm.o print_str.o 9 | head: 10 | nasm -felf32 -o head.o head.s 11 | lan_main: 12 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c sys_call.c intel_err_handle.c sched.c fork.c mm.c print_str.c 13 | boot: 14 | nasm -o boot.bin boot.s -l boot.lst 15 | clean: 16 | rm lan_os lan_main.o sys_call.o intel_err_handle.o head.o sched.o fork.o mm.o print_str.o boot.bin boot.lst a.img a.vfd 17 | -------------------------------------------------------------------------------- /demos/exec_demo/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef MM_H 2 | #define MM_H 3 | 4 | #define PAGE_SIZE 4096 5 | #define PAGE_DIR 0x8000 6 | #define PG_NUM 16 7 | 8 | #define LOW_MEM 0x100000 9 | #define MAP_NR(addr) (((addr)-LOW_MEM) >> 12) 10 | #define invalidate() __asm__("movl %%eax,%%cr3" ::"a"(PAGE_DIR)) 11 | 12 | extern void mm_init(); 13 | extern unsigned long get_free_page(); 14 | extern int free_page_tables(unsigned long from, unsigned long size); 15 | extern int copy_page_tables(unsigned long from, unsigned long to, long size); 16 | 17 | #endif -------------------------------------------------------------------------------- /demos/exec_demo/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/exec_demo/print_str.c: -------------------------------------------------------------------------------- 1 | #define MAX_L 25 2 | #define SCREEN_LEN 2000 3 | char screen_buff[SCREEN_LEN]; 4 | int cur_l = 0; 5 | extern void write_char(char ch, int pos); 6 | 7 | void init_screen_buff() { 8 | for (int i = 0; i < SCREEN_LEN; ++i) { 9 | screen_buff[i] = 0; 10 | } 11 | } 12 | 13 | void validate_screen() { 14 | for (int i = 0; i < SCREEN_LEN; ++i) { 15 | write_char(screen_buff[i], i); 16 | } 17 | } 18 | 19 | void print_str(char *s) { 20 | if (cur_l >= MAX_L) { 21 | for (int i = 0; i < 24; ++i) { 22 | for (int j = 0; j < 80; ++j) { 23 | screen_buff[i * 80 + j] = screen_buff[(i + 1) * 80 + j]; 24 | } 25 | } 26 | for (int j = 0; j < 80; ++j) { 27 | screen_buff[24 * 80 + j] = 0; 28 | } 29 | cur_l = MAX_L - 1; 30 | } 31 | int y = cur_l; 32 | int x = 0; 33 | while (s[x] != 0) { 34 | screen_buff[y * 80 + x] = s[x]; 35 | x++; 36 | } 37 | cur_l++; 38 | validate_screen(); 39 | } 40 | 41 | void print_num(int num) { 42 | char buf[64]; 43 | int index = 0; 44 | for (int i = 0; i < 64; ++i) { 45 | buf[i] = 0; 46 | } 47 | if (num == 0) { 48 | buf[index++] = '0'; 49 | } else if (num < 0) { 50 | num = -num; 51 | buf[index++] = '-'; 52 | } 53 | char tmp[64]; 54 | int index_tmp = 0; 55 | while (num > 0) { 56 | tmp[index_tmp++] = num % 10 + '0'; 57 | num /= 10; 58 | } 59 | for (int i = index_tmp - 1; i >= 0; --i) { 60 | buf[index++] = tmp[i]; 61 | } 62 | print_str(buf); 63 | } 64 | 65 | void panic(char *msg) { 66 | print_str(msg); 67 | while (1) { 68 | validate_screen(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /demos/exec_demo/readme.md: -------------------------------------------------------------------------------- 1 | ### 血与泪 2 | 3 | ### 调试过程中遇到的问题 4 | 5 | 1. 应用程序的main函数一定要是第一个函数,一定要在0地址 -------------------------------------------------------------------------------- /demos/exec_demo/root_fs/hello_fs: -------------------------------------------------------------------------------- 1 | hi, lan_os. it's a nice day!!! -------------------------------------------------------------------------------- /demos/exec_demo/root_fs/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/exec_demo/root_fs/test -------------------------------------------------------------------------------- /demos/exec_demo/sched.c: -------------------------------------------------------------------------------- 1 | #include "sched.h" 2 | #include "mm.h" 3 | 4 | struct task_struct *task[NR_TASKS]; 5 | struct task_struct init_task; 6 | struct task_struct *current = (struct task_struct *)&init_task; 7 | long last_pid = -1; 8 | long last_sched_i = 0; 9 | 10 | extern void switch_to(unsigned long, struct task_struct *); 11 | extern void set_tss0_esp0(unsigned long); 12 | extern void get_esp0_when_switch(unsigned long *); 13 | extern void krn_stk0(); 14 | 15 | void sched_init() { 16 | for (int i = 0; i < NR_TASKS; ++i) { 17 | task[i] = 0; 18 | } 19 | init_task.state = TASK_UNINTERRUPTIBLE; 20 | init_task.pid = ++last_pid; 21 | init_task.ldt[0].a = 0; 22 | init_task.ldt[0].b = 0; 23 | init_task.ldt[1].a = 0x3ff; 24 | init_task.ldt[1].b = 0xc0fa00; 25 | init_task.ldt[2].a = 0x3ff; 26 | init_task.ldt[2].b = 0xc0f200; 27 | set_ldt_desc(gdt + 0 + FIRST_LDT_ENTRY, &(init_task.ldt)); 28 | task[0] = &init_task; 29 | lldt(0); 30 | init_task.state = TASK_RUNNING; 31 | } 32 | 33 | void schedule() { 34 | int i = last_sched_i; 35 | while (1) { 36 | ++i; 37 | i %= NR_TASKS; 38 | if (task[i]) { 39 | if (current->pid != i) { 40 | if (task[i]->state == TASK_RUNNING) { 41 | last_sched_i = i; 42 | if (0 == i) { 43 | set_tss0_esp0( 44 | krn_stk0); // 0任务的内核栈是写死的,不能用task[i])+PAGE_SIZE来计算 45 | } else { 46 | set_tss0_esp0((unsigned long)(task[i]) + 47 | PAGE_SIZE); //给切换栈机制搭桥 48 | } 49 | unsigned long esp0 = 0; 50 | get_esp0_when_switch(&esp0); 51 | current->kernel_stack = esp0; 52 | current = task[i]; 53 | switch_to(_LDT(i), task[i]); 54 | return; 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | void do_timer(unsigned long cs) { 62 | if (0x8 == cs) { 63 | } else if (0xf == cs) { 64 | schedule(); 65 | } else { 66 | } 67 | } -------------------------------------------------------------------------------- /demos/exit_demo/bin/loop/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=loop bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o 5 | lan_main: 6 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm loop test_elf lan_main.o 9 | cp: 10 | cp loop ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/exit_demo/bin/loop/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/exit_demo/bin/ls/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=ls bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o 5 | lan_main: 6 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm ls test_elf lan_main.o 9 | cp: 10 | cp ls ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/exit_demo/bin/ls/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/exit_demo/bin/shell/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=lan_sh bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o 5 | lan_main: 6 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm lan_sh test_elf lan_main.o 9 | cp: 10 | cp lan_sh ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/exit_demo/bin/shell/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/exit_demo/bin/test/lan_main.c: -------------------------------------------------------------------------------- 1 | #define _syscall0(type, name) \ 2 | type name(void) { \ 3 | long __res; \ 4 | __asm__ volatile("int $0x80" : "=a"(__res) : "0"(__NR_##name)); \ 5 | if (__res >= 0) return (type)__res; \ 6 | return -1; \ 7 | } 8 | #define _syscall1(type, name, atype, a) \ 9 | type name(atype a) { \ 10 | long __res; \ 11 | __asm__ volatile("int $0x80" \ 12 | : "=a"(__res) \ 13 | : "0"(__NR_##name), "b"((long)(a))); \ 14 | if (__res >= 0) return (type)__res; \ 15 | return -1; \ 16 | } 17 | #define _syscall2(type, name, atype, a, btype, b) \ 18 | type name(atype a, btype b) { \ 19 | long __res; \ 20 | __asm__ volatile("int $0x80" \ 21 | : "=a"(__res) \ 22 | : "0"(__NR_##name), "b"((long)(a)), "c"((long)(b))); \ 23 | if (__res >= 0) return (type)__res; \ 24 | return -1; \ 25 | } 26 | int s_exit(); 27 | 28 | int s_print_str(char*); 29 | int s_read_file_content(char*, char*); 30 | int s_print_num(int); 31 | 32 | void lan_main() { 33 | s_print_str("I am a test executable file !"); 34 | s_print_str("I can print a number."); 35 | s_print_num(222); 36 | char buffer[64] = {0}; 37 | s_read_file_content("hello_fs", buffer); 38 | s_print_str("hello_fs content is:"); 39 | s_print_str(buffer); 40 | s_exit(); 41 | } 42 | #define __NR_s_print_str 4 43 | #define __NR_s_print_num 5 44 | #define __NR_s_exit 12 45 | #define __NR_s_read_file_content 6 46 | _syscall2(int, s_read_file_content, char*, file_name, char*, buffer) 47 | _syscall1(int, s_print_str, char*, msg) 48 | _syscall1(int, s_print_num, int, num) _syscall0(int, s_exit) -------------------------------------------------------------------------------- /demos/exit_demo/bin/test/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=test bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o 5 | lan_main: 6 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm test test_elf lan_main.o 9 | cp: 10 | cp test ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/exit_demo/bin/test/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/exit_demo/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 72 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+17 ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | mov ax, 01220h 16 | mov es, ax 17 | mov cx, 0001h 18 | jnc ok_load1 19 | jmp $ 20 | 21 | ok_load1: 22 | mov ax, 0200h+18 ;ah 读扇区功能号2 al读扇区数量 18 23 | xor dh, 1 24 | and dh, 1 25 | int 013h 26 | mov ax, es 27 | add ax, 0240h 28 | mov es, ax 29 | jnc ok_load2 30 | jmp $ 31 | 32 | ok_load2: 33 | test dh, dh 34 | jz dontaddch 35 | add ch, 1 36 | dontaddch: 37 | mov ax, [index] 38 | sub ax, 1 39 | mov [index], ax 40 | test ax, ax 41 | jnz ok_load1 42 | 43 | ok_load: 44 | cli 45 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 46 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 47 | xor ax, ax 48 | mov es, ax 49 | mov cx, 0x3000 ;这时拷贝 0x3000*2(字节)/512=48(扇区) 50 | sub si, si 51 | sub di, di 52 | cld ;df = 0 rep movsw是正向的 53 | rep movsw 54 | mov ax, 0x0 ;重新恢复ds指向0x0 55 | mov ds, ax 56 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 57 | mov ax, 0x0001 58 | lmsw ax 59 | jmp dword 8:0 60 | index: 61 | dw 63 ;这里63是极限 位置末尾是0x9fe00 接近显示缓冲区0xA0000 62 | gdt: 63 | dw 0, 0, 0, 0 ;第一个描述符,没有用 64 | dw 0x07ff ;代码段 从0地址开始 65 | dw 0x0000 66 | dw 0x9a00 67 | dw 0x00c0 68 | dw 0x07ff ;数据段 从0地址开始 69 | dw 0x0000 70 | dw 0x9200 71 | dw 0x00c0 72 | 73 | gdt_48: 74 | dw 0x7ff ;2048/8=256个描述符 75 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 76 | 77 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 78 | times 510 - ($-$$) db 0 79 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/exit_demo/exit.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | #include "sched.h" 3 | void _sys_exit() { 4 | current->state = TASK_ZOMBIE; 5 | unsigned long data_base = get_data_base(current); 6 | unsigned long data_limit = get_limit(0x17); 7 | free_page_tables(data_base, data_limit); 8 | schedule(); 9 | } -------------------------------------------------------------------------------- /demos/exit_demo/fork.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | #include "sched.h" 3 | 4 | extern void panic(char *msg); 5 | 6 | extern void first_return_from_kernel(); 7 | unsigned long get_data_base(struct task_struct *s) { 8 | unsigned long ret = (s->ldt[2].a) >> 16; 9 | ret |= (s->ldt[2].b & 0xff) << 16; 10 | ret |= s->ldt[2].b & 0xff000000; 11 | return ret; 12 | } 13 | 14 | int copy_mem(int nr, struct task_struct *p) { 15 | unsigned long old_data_base, new_data_base, data_limit; 16 | unsigned long new_code_base, code_limit; 17 | 18 | code_limit = get_limit(0x0f); 19 | data_limit = get_limit(0x17); 20 | old_data_base = get_data_base(current); 21 | new_data_base = new_code_base = nr * TASK_SIZE + PG_NUM * 4 * 1024 * 1024; 22 | p->start_code = new_code_base; 23 | set_base(&(p->ldt[1]), new_code_base); 24 | set_base(&(p->ldt[2]), new_data_base); 25 | if (copy_page_tables(old_data_base, new_data_base, data_limit)) { 26 | // todo 27 | // free_page_tables 28 | panic("copy page tables failed."); 29 | } 30 | return 0; 31 | } 32 | 33 | int find_empty_process() { 34 | for (int i = 0; i < NR_TASKS; ++i) { 35 | if (!task_used[i]) { 36 | task_used[i] = 1; 37 | return i; 38 | } 39 | } 40 | return -1; 41 | } 42 | 43 | int copy_process(long eax, long ebp, long edi, long esi, long gs, long none, 44 | long ebx, long ecx, long edx, long orig_eax, long fs, long es, 45 | long ds, long eip, long cs, long eflags, long esp, long ss) { 46 | if (eax < 0) { 47 | panic("no emtpy task."); 48 | } 49 | struct task_struct *p = (struct task_struct *)get_free_page(); 50 | 51 | if (!p) { 52 | // todo 53 | } 54 | *p = *current; 55 | p->state = TASK_UNINTERRUPTIBLE; 56 | p->pid = eax; 57 | task[eax] = p; 58 | long *krnstack = (long *)(PAGE_SIZE + (long)p); 59 | *(--krnstack) = ss; 60 | *(--krnstack) = esp; 61 | *(--krnstack) = eflags; 62 | *(--krnstack) = cs; 63 | *(--krnstack) = eip; 64 | *(--krnstack) = first_return_from_kernel; 65 | *(--krnstack) = 0; // eax 66 | *(--krnstack) = ebx; 67 | *(--krnstack) = ecx; 68 | *(--krnstack) = edx; 69 | *(--krnstack) = ebp; 70 | *(--krnstack) = esi; 71 | *(--krnstack) = edi; 72 | *(--krnstack) = es & 0xffff; 73 | *(--krnstack) = ds & 0xffff; 74 | *(--krnstack) = fs & 0xffff; 75 | *(--krnstack) = gs & 0xffff; 76 | p->kernel_stack = krnstack; 77 | if (copy_mem(eax, p)) { 78 | // todo: 79 | // abort 80 | } 81 | set_ldt_desc(gdt + eax + FIRST_LDT_ENTRY, &(p->ldt)); 82 | p->state = TASK_RUNNING; 83 | return 1; 84 | } 85 | -------------------------------------------------------------------------------- /demos/exit_demo/fs_patch_tool/patch.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const file_list = [ 4 | 'hello_fs', 5 | 'test', 6 | 'lan_sh', 7 | 'ls', 8 | 'loop', 9 | ]; 10 | 11 | function zero_buffer(size) { 12 | let ret = Buffer.alloc(size); 13 | for (let i = 0; i < size; ++i) { 14 | ret[i] = 0; 15 | } 16 | return ret; 17 | } 18 | 19 | async function main() { 20 | const vfd_path = `${__dirname}/../a.vfd`; 21 | const vfd_content = fs.readFileSync(vfd_path); 22 | console.log('vfd_content length : ', vfd_content.length); 23 | const vfd_length = vfd_content.length; 24 | let fs_header = zero_buffer(4); 25 | const file_cnt = file_list.length; 26 | fs_header.writeInt32LE(file_cnt); 27 | let file_buffer = zero_buffer(0); 28 | for (let i = 0; i < file_cnt; ++i) { 29 | const path = `${__dirname}/../root_fs/${file_list[i]}`; 30 | const content = fs.readFileSync(path); 31 | const content_length = content.length; 32 | console.log(`path ${path} : ${content_length}`); 33 | const file_length_buffer = zero_buffer(4); 34 | const file_name_buffer = zero_buffer(8); 35 | file_length_buffer.writeInt32LE(content_length); 36 | Buffer.from(file_list[i]).copy(file_name_buffer); 37 | fs_header = Buffer.concat([fs_header, file_length_buffer, file_name_buffer]); 38 | const file_pad = zero_buffer(20 * 1024 - content_length); 39 | file_buffer = Buffer.concat([file_buffer, content, file_pad]); 40 | } 41 | const fs_header_pad = zero_buffer(124 - fs_header.length); 42 | fs_header = Buffer.concat([fs_header, fs_header_pad]); 43 | console.log('fs_header length : ', fs_header.length); 44 | const start = 0x5df84; // 0x90000-200k-124 在内存中的位置应该是0x5df84-0x200+0x10000=0x6dd84 45 | const p0 = vfd_content.slice(0, start); 46 | const p1 = Buffer.concat([fs_header, file_buffer]); 47 | const p2 = vfd_content.slice(start + p1.length); 48 | const final_buffer = Buffer.concat([p0, p1, p2]); 49 | fs.writeFileSync(vfd_path, final_buffer); 50 | process.exit(); 51 | } 52 | main(); -------------------------------------------------------------------------------- /demos/exit_demo/gate_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef GATE_TOOL_H 2 | #define GATE_TOOL_H 3 | 4 | #include "sched.h" 5 | 6 | #define _set_gate(gate_addr, type, dpl, addr) \ 7 | __asm__( \ 8 | "movw %%dx,%%ax\n\t" \ 9 | "movw %0,%%dx\n\t" \ 10 | "movl %%eax,%1\n\t" \ 11 | "movl %%edx,%2" \ 12 | : \ 13 | : "i"((short)(0x8000 + (dpl << 13) + (type << 8))), \ 14 | "o"(*((char *)(gate_addr))), "o"(*(4 + (char *)(gate_addr))), \ 15 | "d"((char *)(addr)), "a"(0x00080000)) 16 | 17 | #define set_intr_gate(n, addr) _set_gate(&idt[n], 14, 0, addr) 18 | 19 | #define set_trap_gate(n, addr) _set_gate(&idt[n], 15, 0, addr) 20 | 21 | #define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr) 22 | #endif -------------------------------------------------------------------------------- /demos/exit_demo/intel_err_handle.c: -------------------------------------------------------------------------------- 1 | extern void print_str(char *s); 2 | extern void panic(char *msg); 3 | 4 | void e0() { print_str("e0"); } 5 | 6 | void e1() { print_str("e1"); } 7 | 8 | void e2() { print_str("e2"); } 9 | 10 | void e3() { print_str("e3"); } 11 | 12 | void e4() { print_str("e4"); } 13 | 14 | void e5() { print_str("e5"); } 15 | 16 | void e6() { print_str("e6"); } 17 | 18 | void e7() { print_str("e7"); } 19 | 20 | void e8() { print_str("e8"); } 21 | 22 | void e9() { print_str("e9"); } 23 | 24 | void e10() { print_str("e10"); } 25 | 26 | void e11() { print_str("e11"); } 27 | 28 | void e12() { panic("e12"); } 29 | 30 | void e13() { panic("e13"); } 31 | 32 | void e15() { print_str("e15"); } 33 | 34 | void e16() { print_str("e16"); } 35 | -------------------------------------------------------------------------------- /demos/exit_demo/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=62 skip=8 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=63 conv=notrunc 6 | node fs_patch_tool/patch.js 7 | link: head lan_main boot 8 | ld -m elf_i386 -T n.lds -o lan_os head.o lan_main.o sys_call.o intel_err_handle.o sched.o fork.o mm.o print_str.o keyboard.o exit.o 9 | head: 10 | nasm -felf32 -o head.o head.s 11 | lan_main: 12 | gcc -O0 -m32 -g -fno-stack-protector -fno-pie -c lan_main.c sys_call.c intel_err_handle.c sched.c fork.c mm.c print_str.c keyboard.c exit.c 13 | boot: 14 | nasm -o boot.bin boot.s -l boot.lst 15 | clean: 16 | rm lan_os lan_main.o sys_call.o intel_err_handle.o head.o sched.o fork.o mm.o print_str.o keyboard.o exit.o boot.bin boot.lst a.img a.vfd 17 | -------------------------------------------------------------------------------- /demos/exit_demo/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef MM_H 2 | #define MM_H 3 | 4 | #define PAGE_SIZE 4096 5 | #define PAGE_DIR 0x10000 6 | #define PG_NUM 16 7 | 8 | #define LOW_MEM 0x100000 9 | #define MAP_NR(addr) (((addr)-LOW_MEM) >> 12) 10 | #define invalidate() __asm__("movl %%eax,%%cr3" ::"a"(PAGE_DIR)) 11 | 12 | #include "sched.h" 13 | 14 | extern void mm_init(); 15 | extern unsigned long get_free_page(); 16 | extern int free_page_tables(unsigned long from, unsigned long size); 17 | extern int copy_page_tables(unsigned long from, unsigned long to, long size); 18 | extern unsigned long get_data_base(struct task_struct *s); 19 | extern void free_page(unsigned long addr); 20 | #endif -------------------------------------------------------------------------------- /demos/exit_demo/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/exit_demo/readme.md: -------------------------------------------------------------------------------- 1 | # 血与泪 2 | 3 | ## 调试中遇到的问题 4 | 5 | 1. get_free_page 在linux0.12中是以汇编实现的,移植的时候没有做把页面清零的操作,导致申请一块也表的时候有非0的值,修正后正常了 6 | 2. c语言的全局变量的位置不可控,所以都要在head.s中声明,在c中extern定义,所有的内存都要通过get_free_page去拿 -------------------------------------------------------------------------------- /demos/exit_demo/root_fs/hello_fs: -------------------------------------------------------------------------------- 1 | hi, lan_os. it's a nice day!!! -------------------------------------------------------------------------------- /demos/exit_demo/root_fs/lan_sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/exit_demo/root_fs/lan_sh -------------------------------------------------------------------------------- /demos/exit_demo/root_fs/loop: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/exit_demo/root_fs/loop -------------------------------------------------------------------------------- /demos/exit_demo/root_fs/ls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/exit_demo/root_fs/ls -------------------------------------------------------------------------------- /demos/exit_demo/root_fs/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/exit_demo/root_fs/test -------------------------------------------------------------------------------- /demos/exit_demo/sched.c: -------------------------------------------------------------------------------- 1 | #include "sched.h" 2 | #include "mm.h" 3 | 4 | struct task_struct *task[NR_TASKS]; 5 | int task_used[NR_TASKS]; 6 | struct task_struct init_task; 7 | struct task_struct *current = (struct task_struct *)&init_task; 8 | long last_sched_i = 0; 9 | 10 | extern void switch_to(unsigned long, struct task_struct *); 11 | extern void set_tss0_esp0(unsigned long); 12 | extern void get_esp0_when_switch(unsigned long *); 13 | extern void krn_stk0(); 14 | 15 | void sched_init() { 16 | for (int i = 0; i < NR_TASKS; ++i) { 17 | task[i] = 0; 18 | task_used[i] = 0; 19 | } 20 | task_used[0] = 1; 21 | init_task.state = TASK_UNINTERRUPTIBLE; 22 | init_task.pid = 0; 23 | init_task.ldt[0].a = 0; 24 | init_task.ldt[0].b = 0; 25 | init_task.ldt[1].a = 0x3ff; 26 | init_task.ldt[1].b = 0xc0fa00; 27 | init_task.ldt[2].a = 0x3ff; 28 | init_task.ldt[2].b = 0xc0f200; 29 | set_ldt_desc(gdt + 0 + FIRST_LDT_ENTRY, &(init_task.ldt)); 30 | task[0] = &init_task; 31 | lldt(0); 32 | init_task.state = TASK_RUNNING; 33 | } 34 | 35 | void schedule() { 36 | int i = last_sched_i; 37 | while (1) { 38 | ++i; 39 | i %= NR_TASKS; 40 | if (task[i]) { 41 | if (task[i]->state == TASK_ZOMBIE) { 42 | free_page((unsigned long)task[i]); 43 | task[i] = 0; 44 | task_used[i] = 0; 45 | continue; 46 | } 47 | if (current->pid != i) { 48 | if (task[i]->state == TASK_RUNNING) { 49 | last_sched_i = i; 50 | if (0 == i) { 51 | set_tss0_esp0( 52 | krn_stk0); // 0任务的内核栈是写死的,不能用task[i])+PAGE_SIZE来计算 53 | } else { 54 | set_tss0_esp0((unsigned long)(task[i]) + 55 | PAGE_SIZE); //给切换栈机制搭桥 56 | } 57 | unsigned long esp0 = 0; 58 | get_esp0_when_switch(&esp0); 59 | current->kernel_stack = esp0; 60 | current = task[i]; 61 | switch_to(_LDT(i), task[i]); 62 | return; 63 | } 64 | } 65 | } 66 | } 67 | } 68 | 69 | void do_timer(unsigned long cs) { 70 | if (0x8 == cs) { 71 | } else if (0xf == cs) { 72 | schedule(); 73 | } else { 74 | } 75 | } -------------------------------------------------------------------------------- /demos/fork_demo/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 48 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+SYSLEN ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | jnc ok_load 16 | jmp $ 17 | 18 | ok_load: 19 | cli 20 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 21 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 22 | xor ax, ax 23 | mov es, ax 24 | mov cx, 0x3000 ;这时拷贝 0x3000*2(字节)/512=48(扇区) 25 | sub si, si 26 | sub di, di 27 | cld ;df = 0 rep movsw是正向的 28 | rep movsw 29 | mov ax, 0x0 ;重新恢复ds指向0x0 30 | mov ds, ax 31 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 32 | mov ax, 0x0001 33 | lmsw ax 34 | jmp dword 8:0 35 | gdt: 36 | dw 0, 0, 0, 0 ;第一个描述符,没有用 37 | dw 0x07ff ;代码段 从0地址开始 38 | dw 0x0000 39 | dw 0x9a00 40 | dw 0x00c0 41 | dw 0x07ff ;数据段 从0地址开始 42 | dw 0x0000 43 | dw 0x9200 44 | dw 0x00c0 45 | 46 | 47 | gdt_48: 48 | dw 0x7ff ;2048/8=256个描述符 49 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 50 | 51 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 52 | times 510 - ($-$$) db 0 53 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/fork_demo/fork.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | #include "sched.h" 3 | 4 | extern void first_return_from_kernel(); 5 | unsigned long get_data_base(struct task_struct *s) { 6 | unsigned long ret = (s->ldt[2].a) >> 16; 7 | ret |= (s->ldt[2].b & 0xff) << 16; 8 | ret |= s->ldt[2].b & 0xff000000; 9 | return ret; 10 | } 11 | 12 | int copy_mem(int nr, struct task_struct *p) { 13 | unsigned long old_data_base, new_data_base, data_limit; 14 | unsigned long new_code_base, code_limit; 15 | 16 | code_limit = get_limit(0x0f); 17 | data_limit = get_limit(0x17); 18 | old_data_base = get_data_base(current); 19 | new_data_base = new_code_base = nr * TASK_SIZE + PG_NUM * 4 * 1024 * 1024; 20 | p->start_code = new_code_base; 21 | set_base(&(p->ldt[1]), new_code_base); 22 | set_base(&(p->ldt[2]), new_data_base); 23 | if (copy_page_tables(old_data_base, new_data_base, data_limit)) { 24 | // todo 25 | // free_page_tables 26 | } 27 | return 0; 28 | } 29 | 30 | int find_empty_process() { return ++last_pid; } 31 | 32 | int copy_process(long eax, long ebp, long edi, long esi, long gs, long none, 33 | long ebx, long ecx, long edx, long orig_eax, long fs, long es, 34 | long ds, long eip, long cs, long eflags, long esp, long ss) { 35 | struct task_struct *p = (struct task_struct *)get_free_page(); 36 | 37 | if (!p) { 38 | // todo 39 | } 40 | *p = *current; 41 | p->state = TASK_UNINTERRUPTIBLE; 42 | p->pid = eax; 43 | task[last_pid] = p; 44 | long *krnstack = (long *)(PAGE_SIZE + (long)p); 45 | *(--krnstack) = ss; 46 | *(--krnstack) = esp; 47 | *(--krnstack) = eflags; 48 | *(--krnstack) = cs; 49 | *(--krnstack) = eip; 50 | *(--krnstack) = first_return_from_kernel; 51 | *(--krnstack) = 0; // eax 52 | *(--krnstack) = ebx; 53 | *(--krnstack) = ecx; 54 | *(--krnstack) = edx; 55 | *(--krnstack) = ebp; 56 | *(--krnstack) = esi; 57 | *(--krnstack) = edi; 58 | *(--krnstack) = es & 0xffff; 59 | *(--krnstack) = ds & 0xffff; 60 | *(--krnstack) = fs & 0xffff; 61 | *(--krnstack) = gs & 0xffff; 62 | p->kernel_stack = krnstack; 63 | if (copy_mem(last_pid, p)) { 64 | // todo: 65 | // abort 66 | } 67 | set_ldt_desc(gdt + last_pid + FIRST_LDT_ENTRY, &(p->ldt)); 68 | p->state = TASK_RUNNING; 69 | return 1; 70 | } 71 | -------------------------------------------------------------------------------- /demos/fork_demo/gate_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef GATE_TOOL_H 2 | #define GATE_TOOL_H 3 | 4 | #include "sched.h" 5 | 6 | #define _set_gate(gate_addr, type, dpl, addr) \ 7 | __asm__( \ 8 | "movw %%dx,%%ax\n\t" \ 9 | "movw %0,%%dx\n\t" \ 10 | "movl %%eax,%1\n\t" \ 11 | "movl %%edx,%2" \ 12 | : \ 13 | : "i"((short)(0x8000 + (dpl << 13) + (type << 8))), \ 14 | "o"(*((char *)(gate_addr))), "o"(*(4 + (char *)(gate_addr))), \ 15 | "d"((char *)(addr)), "a"(0x00080000)) 16 | 17 | #define set_intr_gate(n, addr) _set_gate(&idt[n], 14, 0, addr) 18 | 19 | #define set_trap_gate(n, addr) _set_gate(&idt[n], 15, 0, addr) 20 | 21 | #define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr) 22 | #endif -------------------------------------------------------------------------------- /demos/fork_demo/intel_err_handle.c: -------------------------------------------------------------------------------- 1 | extern void write_char(char ch); 2 | 3 | void e0() { write_char('0'); } 4 | 5 | void e1() { write_char('1'); } 6 | 7 | void e2() { write_char('2'); } 8 | 9 | void e3() { write_char('3'); } 10 | 11 | void e4() { write_char('4'); } 12 | 13 | void e5() { write_char('5'); } 14 | 15 | void e6() { write_char('6'); } 16 | 17 | void e7() { write_char('7'); } 18 | 19 | void e8() { write_char('8'); } 20 | 21 | void e9() { write_char('9'); } 22 | 23 | void e10() { 24 | write_char('1'); 25 | write_char('0'); 26 | } 27 | 28 | void e11() { 29 | write_char('1'); 30 | write_char('1'); 31 | } 32 | 33 | void e12() { 34 | write_char('1'); 35 | write_char('2'); 36 | } 37 | 38 | void e13() { 39 | write_char('1'); 40 | write_char('3'); 41 | } 42 | 43 | void e14() { 44 | write_char('1'); 45 | write_char('4'); 46 | } 47 | 48 | void e15() { 49 | write_char('1'); 50 | write_char('5'); 51 | } 52 | 53 | void e16() { 54 | write_char('1'); 55 | write_char('6'); 56 | } 57 | -------------------------------------------------------------------------------- /demos/fork_demo/lan_main.c: -------------------------------------------------------------------------------- 1 | extern void write_char(char ch); 2 | extern void open_a20(); 3 | extern void init_8259A(); 4 | extern void timer_interrupt(); 5 | extern void init_latch(); 6 | extern void page_fault(); 7 | extern void system_call(); 8 | extern void _e0(); 9 | extern void _e1(); 10 | extern void _e2(); 11 | extern void _e3(); 12 | extern void _e4(); 13 | extern void _e5(); 14 | extern void _e6(); 15 | extern void _e7(); 16 | extern void _e8(); 17 | extern void _e9(); 18 | extern void _e10(); 19 | extern void _e11(); 20 | extern void _e12(); 21 | extern void _e13(); 22 | extern void _e14(); 23 | extern void _e15(); 24 | extern void _e16(); 25 | extern void init_0(); 26 | 27 | #include "gate_tool.h" 28 | #include "mm.h" 29 | #include "move_to_user_mode.h" 30 | #include "sched.h" 31 | 32 | #define __NR_test_sys_call 0 33 | #define __NR_fork1 1 34 | #define __NR_test_sys_call1 2 35 | //_syscall0(int, test_sys_call) 36 | // _syscall0(int, fork1) 37 | 38 | void check_a20_valid() { 39 | unsigned char *p0 = 0x0; 40 | unsigned char *p1 = 0x100000; 41 | for (unsigned char i = 0; i < 10; ++i) { 42 | *p0 = i; 43 | if (*p0 != *p1) { 44 | write_char('b'); 45 | break; 46 | } else { 47 | write_char('e'); 48 | } 49 | } 50 | } 51 | 52 | void lan_main() { 53 | write_char('L'); 54 | write_char('O'); 55 | write_char('V'); 56 | write_char('E'); 57 | write_char('U'); 58 | write_char('S'); 59 | write_char('E'); 60 | write_char('R'); 61 | open_a20(); 62 | check_a20_valid(); 63 | mm_init(); 64 | init_latch(); 65 | init_8259A(); 66 | set_intr_gate(0x20, &timer_interrupt); 67 | // set_trap_gate(14, &page_fault); 68 | set_system_gate(0x80, &system_call); 69 | 70 | set_trap_gate(0, &_e0); 71 | set_trap_gate(1, &_e1); 72 | set_trap_gate(2, &_e2); 73 | set_system_gate(3, &_e3); /* int3-5 can be called from all */ 74 | set_system_gate(4, &_e4); 75 | set_system_gate(5, &_e5); 76 | set_trap_gate(6, &_e6); 77 | set_trap_gate(7, &_e7); 78 | set_trap_gate(8, &_e8); 79 | set_trap_gate(9, &_e9); 80 | set_trap_gate(10, &_e10); 81 | set_trap_gate(11, &_e11); 82 | set_trap_gate(12, &_e12); 83 | set_trap_gate(13, &_e13); 84 | set_trap_gate(14, &_e14); 85 | set_trap_gate(15, &_e15); 86 | set_trap_gate(16, &_e16); 87 | sched_init(); 88 | sti(); 89 | move_to_user_mode(); 90 | 91 | __asm__( 92 | "int $0x80 \n\t" 93 | "testl %%eax, %%eax \n\t" 94 | "je 1f \n\t" 95 | "movl %%ebx, %%eax \n\t" 96 | "2: \n\t" 97 | "int $0x80\n\t" 98 | "jmp 2b \n\t" 99 | "1: \n\t" ::"a"(__NR_fork1), 100 | "b"(__NR_test_sys_call) 101 | :); 102 | 103 | while (1) { 104 | { 105 | __asm__("int $0x80" ::"a"(__NR_test_sys_call1) :); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /demos/fork_demo/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=44 skip=8 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=45 conv=notrunc 6 | link: head lan_main boot 7 | ld -m elf_i386 -T n.lds -o lan_os head.o lan_main.o sys_call.o intel_err_handle.o sched.o fork.o mm.o 8 | head: 9 | nasm -felf32 -o head.o head.s 10 | lan_main: 11 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c sys_call.c intel_err_handle.c sched.c fork.c mm.c 12 | boot: 13 | nasm -o boot.bin boot.s -l boot.lst 14 | clean: 15 | rm lan_os lan_main.o sys_call.o intel_err_handle.o head.o sched.o fork.o mm.o boot.bin boot.lst a.img a.vfd 16 | 17 | -------------------------------------------------------------------------------- /demos/fork_demo/mm.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | 3 | #define PAGEING_PAGES (63 * 1024 * 1024) / (4 * 1024) 4 | 5 | unsigned char mem_map[PAGEING_PAGES]; 6 | #define RESERVE_PAGES 896 7 | 8 | extern void assign_cr3_cr0(unsigned long); 9 | 10 | void setup_paging() { 11 | unsigned long *pg_dir = PAGE_DIR; // lan_os最多不能超过0x8000 64个扇区 12 | unsigned long *pg[PG_NUM]; //虚拟机必须给64M以上的物理内存 13 | pg[0] = (unsigned long)(pg_dir) + 0x1000; 14 | for (int i = 1; i < PG_NUM; ++i) { 15 | pg[i] = (unsigned long)pg[i - 1] + 0x1000; 16 | } 17 | for (int i = 0; i < PG_NUM; ++i) { 18 | pg_dir[i] = (unsigned long)(pg[i]) + 7; 19 | } 20 | for (int i = 0; i < 1024 * PG_NUM; ++i) { 21 | pg[0][i] = (i << 12) + 7; 22 | } 23 | assign_cr3_cr0(pg_dir); 24 | /*char *p = 0x3ffffff; 25 | p[0] = 1;*/ 26 | } 27 | 28 | void init_mem_map() { 29 | for (int i = 0; i < PAGEING_PAGES; ++i) { 30 | mem_map[i] = 0; 31 | } 32 | for (int i = 0; i < RESERVE_PAGES; ++i) { 33 | mem_map[i] = 100; 34 | } 35 | } 36 | 37 | void mm_init() { 38 | init_mem_map(); 39 | setup_paging(); 40 | } 41 | 42 | unsigned long get_free_page() { 43 | for (int i = PAGEING_PAGES - 1; i >= 0; --i) { 44 | if (0 == mem_map[i]) { 45 | mem_map[i] = 1; 46 | return LOW_MEM + i * 4096; 47 | } 48 | } 49 | return 0; 50 | } 51 | 52 | int copy_page_tables(unsigned long from, unsigned long to, long size) { 53 | unsigned long *from_page_table; 54 | unsigned long *to_page_table; 55 | unsigned long this_page; 56 | unsigned long *from_dir, *to_dir; 57 | unsigned long new_page; 58 | unsigned long nr; 59 | 60 | if ((from & 0x3fffff) || (to & 0x3fffff)) { 61 | // todo panic 62 | } 63 | from_dir = 64 | (unsigned long 65 | *)(((from >> 20) & 0xffc) + 66 | PAGE_DIR); /* _pg_dir 和linux0.12定义不同,我们是从0x8000开始 */ 67 | to_dir = (unsigned long *)(((to >> 20) & 0xffc) + PAGE_DIR); 68 | size = ((unsigned)(size + 0x3fffff)) >> 22; 69 | for (; size-- > 0; from_dir++, to_dir++) { 70 | from_page_table = (unsigned long *)(0xfffff000 & *from_dir); 71 | if (!(to_page_table = (unsigned long *)get_free_page())) { 72 | // todo panic 73 | } 74 | *to_dir = ((unsigned long)to_page_table) | 7; 75 | nr = 1024; 76 | for (; nr-- > 0; from_page_table++, to_page_table++) { 77 | this_page = *from_page_table; 78 | this_page &= ~2; 79 | *to_page_table = this_page; 80 | if (this_page > LOW_MEM) { 81 | *from_page_table = this_page; 82 | this_page -= LOW_MEM; 83 | this_page >>= 12; 84 | mem_map[this_page]++; 85 | } 86 | } 87 | } 88 | invalidate(); 89 | return 0; 90 | } -------------------------------------------------------------------------------- /demos/fork_demo/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef MM_H 2 | #define MM_H 3 | 4 | #define PAGE_SIZE 4096 5 | #define PAGE_DIR 0x8000 6 | #define PG_NUM 16 7 | 8 | #define LOW_MEM 0x100000 9 | #define invalidate() __asm__("movl %%eax,%%cr3" ::"a"(PAGE_DIR)) 10 | 11 | extern void mm_init(); 12 | extern unsigned long get_free_page(); 13 | extern int copy_page_tables(unsigned long from, unsigned long to, long size); 14 | 15 | #endif -------------------------------------------------------------------------------- /demos/fork_demo/move_to_user_mode.h: -------------------------------------------------------------------------------- 1 | #ifndef MOV_TO_USER_MODE_H 2 | #define MOV_TO_USER_MODE_H 3 | #define move_to_user_mode() \ 4 | __asm__( \ 5 | "movl %%esp,%%eax\n\t" \ 6 | "pushl $0x17\n\t" \ 7 | "pushl %%eax\n\t" \ 8 | "pushfl\n\t" \ 9 | "pushl $0x0f\n\t" \ 10 | "pushl $1f\n\t" \ 11 | "iret\n" \ 12 | "1:\tmovl $0x17,%%eax\n\t" \ 13 | "mov %%ax,%%ds\n\t" \ 14 | "mov %%ax,%%es\n\t" \ 15 | "mov %%ax,%%fs\n\t" \ 16 | "mov %%ax,%%gs" :: \ 17 | : "ax") 18 | #define sti() __asm__("sti" ::) 19 | 20 | #define _syscall0(type, name) \ 21 | type name(void) { \ 22 | long __res; \ 23 | __asm__ volatile("int $0x80" : "=a"(__res) : "0"(__NR_##name)); \ 24 | if (__res >= 0) return (type)__res; \ 25 | return -1; \ 26 | } 27 | #endif -------------------------------------------------------------------------------- /demos/fork_demo/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/fork_demo/readme.md: -------------------------------------------------------------------------------- 1 | # 血与泪 2 | 3 | ## 调试中遇到的问题 4 | 1. loader读取扇区数量已经小于生成的二进制程序的大小了,现在增加到30个扇区,拷贝扇区增加到32个到0x00地址 5 | 2. `new_data_base = new_code_base = nr * TASK_SIZE + PG_NUM*4*1024*1024;` 新进程的任务基地址要避开物理内存,目前每个进程4M内存空间,一共可以创建10个进程 6 | 3. 由于页目录表的基地址和linux0.12的不同,我用的是0x8000而0.12用的是0x0,所以在移植memory.c中的copy_page_tables的时候要关注相关逻辑,把基地址相关的地址都要加上0x8000,并且invalidate()函数的实现也要改变成这样`#define invalidate() 7 | __asm__("movl %%eax,%%cr3"::"a" (0x8000))` 8 | 9 | ## 为什linux中的进程都是以1进程为模版而不是0进程 10 | 11 | * 假设创建的进程以0进程为模版,那么我们要复制的页表的逻辑地址是从0开始的,这里面有页目录表和页表(这里面的头部的逻辑地址和物理地址是相同的) 12 | * 那么由于写时复制机制,正常情况下要把老进程和新进程的页表都置为只读,这样当有一个进程有对页面有写操作的时候,再开始申请新的物理内存做映射,并把这一页复制到新的物理内存,并解锁该页。 13 | * 那么看这样的情况,如果刚好0进程先写了内存触发了写时复制机制,能不能分配一页物理内存给0进程然后复制页呢? 14 | * 不行,0进程的头部页面必须要保证逻辑地址和物理地址是相同的,因为你要给cr3一个物理地址来告诉它页目录表在哪,这个地址必须是物理地址。 15 | * 起始1号进程是以0号进程为模版创建的,但是为了避免上面所说的锁住0号进程的内存,0号进程在fork的时候不锁自己的页表只锁1号进程的页表。这就造成了这时0号进程不会写时复制,而1号进程会写时复制。那么让1号进程先写一下内存不久好了?答案是不行,因为fork过后0号和1号进程的执行顺序是未知的。所以这里对于fork的调用一定不能用栈,这样0号进程就不会写内存。于是就有了0号进程第一次调用fork是用一段汇编代码直接调用`int 0x80` 16 | * 那么问题来了,如果0号进程用了栈,会有什么问题?假设这种场景,0号进程fork了,栈中写入了fork的返回地址,这时cpu调度到了0号进程,0号进程执行了ret指令,把栈修改了,这个修改对1号进程是可见的,当1号进程要执行ret操作的时候栈上的返回地址已经不见了,1号进程就会崩溃。 17 | -------------------------------------------------------------------------------- /demos/fork_demo/sched.c: -------------------------------------------------------------------------------- 1 | #include "sched.h" 2 | #include "mm.h" 3 | 4 | struct task_struct *task[NR_TASKS]; 5 | struct task_struct init_task; 6 | struct task_struct *current = (struct task_struct *)&init_task; 7 | long last_pid = -1; 8 | 9 | extern void switch_to(unsigned long, struct task_struct *); 10 | extern void set_tss0_esp0(unsigned long); 11 | extern void get_esp0_when_switch(unsigned long *); 12 | extern void krn_stk0(); 13 | 14 | void sched_init() { 15 | for (int i = 0; i < NR_TASKS; ++i) { 16 | task[i] = 0; 17 | } 18 | init_task.state = TASK_UNINTERRUPTIBLE; 19 | init_task.pid = ++last_pid; 20 | init_task.ldt[0].a = 0; 21 | init_task.ldt[0].b = 0; 22 | init_task.ldt[1].a = 0x3ff; 23 | init_task.ldt[1].b = 0xc0fa00; 24 | init_task.ldt[2].a = 0x3ff; 25 | init_task.ldt[2].b = 0xc0f200; 26 | set_ldt_desc(gdt + 0 + FIRST_LDT_ENTRY, &(init_task.ldt)); 27 | task[0] = &init_task; 28 | lldt(0); 29 | init_task.state = TASK_RUNNING; 30 | } 31 | 32 | void schedule() { 33 | while (1) { 34 | for (int i = 0; i < NR_TASKS; ++i) { 35 | if (task[i]) { 36 | if (current->pid != i) { 37 | if (task[i]->state == TASK_RUNNING) { 38 | if (0 == i) { 39 | set_tss0_esp0( 40 | krn_stk0); // 0任务的内核栈是写死的,不能用task[i])+PAGE_SIZE来计算 41 | } else { 42 | set_tss0_esp0((unsigned long)(task[i]) + 43 | PAGE_SIZE); //给切换栈机制搭桥 44 | } 45 | unsigned long esp0 = 0; 46 | get_esp0_when_switch(&esp0); 47 | current->kernel_stack = esp0; 48 | current = task[i]; 49 | switch_to(_LDT(i), task[i]); 50 | return; 51 | } 52 | } 53 | } 54 | } 55 | } 56 | } 57 | 58 | void do_timer(unsigned long cs) { 59 | if (0x8 == cs) { 60 | // write_char('K'); 61 | } else if (0xf == cs) { 62 | // write_char('T'); 63 | schedule(); 64 | } else { 65 | write_char('U'); 66 | } 67 | } -------------------------------------------------------------------------------- /demos/fork_demo/sys_call.c: -------------------------------------------------------------------------------- 1 | extern void write_char(char ch); 2 | typedef int (*sys_call)(); 3 | 4 | int _test_sys_call() { 5 | write_char('f'); 6 | return 0; 7 | } 8 | 9 | int _test_sys_call1() { 10 | write_char('g'); 11 | return 0; 12 | } 13 | 14 | extern void sys_fork(); 15 | 16 | extern sys_call sys_call_table[] = {_test_sys_call, sys_fork, _test_sys_call1}; -------------------------------------------------------------------------------- /demos/fs_demo/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 72 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+17 ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | mov ax, 01220h 16 | mov es, ax 17 | mov cx, 0001h 18 | jnc ok_load1 19 | jmp $ 20 | 21 | ok_load1: 22 | mov ax, 0200h+18 ;ah 读扇区功能号2 al读扇区数量 18 23 | xor dh, 1 24 | and dh, 1 25 | int 013h 26 | mov ax, es 27 | add ax, 0240h 28 | mov es, ax 29 | jnc ok_load2 30 | jmp $ 31 | 32 | ok_load2: 33 | test dh, dh 34 | jz dontaddch 35 | add ch, 1 36 | dontaddch: 37 | mov ax, [index] 38 | sub ax, 1 39 | mov [index], ax 40 | test ax, ax 41 | jnz ok_load1 42 | 43 | ok_load: 44 | cli 45 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 46 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 47 | xor ax, ax 48 | mov es, ax 49 | mov cx, 0x3000 ;这时拷贝 0x3000*2(字节)/512=48(扇区) 50 | sub si, si 51 | sub di, di 52 | cld ;df = 0 rep movsw是正向的 53 | rep movsw 54 | mov ax, 0x0 ;重新恢复ds指向0x0 55 | mov ds, ax 56 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 57 | mov ax, 0x0001 58 | lmsw ax 59 | jmp dword 8:0 60 | index: 61 | dw 63 ;这里63是极限 位置末尾是0x9fe00 接近显示缓冲区0xA0000 62 | gdt: 63 | dw 0, 0, 0, 0 ;第一个描述符,没有用 64 | dw 0x07ff ;代码段 从0地址开始 65 | dw 0x0000 66 | dw 0x9a00 67 | dw 0x00c0 68 | dw 0x07ff ;数据段 从0地址开始 69 | dw 0x0000 70 | dw 0x9200 71 | dw 0x00c0 72 | 73 | gdt_48: 74 | dw 0x7ff ;2048/8=256个描述符 75 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 76 | 77 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 78 | times 510 - ($-$$) db 0 79 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/fs_demo/fork.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | #include "sched.h" 3 | 4 | extern void first_return_from_kernel(); 5 | unsigned long get_data_base(struct task_struct *s) { 6 | unsigned long ret = (s->ldt[2].a) >> 16; 7 | ret |= (s->ldt[2].b & 0xff) << 16; 8 | ret |= s->ldt[2].b & 0xff000000; 9 | return ret; 10 | } 11 | 12 | int copy_mem(int nr, struct task_struct *p) { 13 | unsigned long old_data_base, new_data_base, data_limit; 14 | unsigned long new_code_base, code_limit; 15 | 16 | code_limit = get_limit(0x0f); 17 | data_limit = get_limit(0x17); 18 | old_data_base = get_data_base(current); 19 | new_data_base = new_code_base = nr * TASK_SIZE + PG_NUM * 4 * 1024 * 1024; 20 | p->start_code = new_code_base; 21 | set_base(&(p->ldt[1]), new_code_base); 22 | set_base(&(p->ldt[2]), new_data_base); 23 | if (copy_page_tables(old_data_base, new_data_base, data_limit)) { 24 | // todo 25 | // free_page_tables 26 | } 27 | return 0; 28 | } 29 | 30 | int find_empty_process() { return ++last_pid; } 31 | 32 | int copy_process(long eax, long ebp, long edi, long esi, long gs, long none, 33 | long ebx, long ecx, long edx, long orig_eax, long fs, long es, 34 | long ds, long eip, long cs, long eflags, long esp, long ss) { 35 | struct task_struct *p = (struct task_struct *)get_free_page(); 36 | 37 | if (!p) { 38 | // todo 39 | } 40 | *p = *current; 41 | p->state = TASK_UNINTERRUPTIBLE; 42 | p->pid = eax; 43 | task[last_pid] = p; 44 | long *krnstack = (long *)(PAGE_SIZE + (long)p); 45 | *(--krnstack) = ss; 46 | *(--krnstack) = esp; 47 | *(--krnstack) = eflags; 48 | *(--krnstack) = cs; 49 | *(--krnstack) = eip; 50 | *(--krnstack) = first_return_from_kernel; 51 | *(--krnstack) = 0; // eax 52 | *(--krnstack) = ebx; 53 | *(--krnstack) = ecx; 54 | *(--krnstack) = edx; 55 | *(--krnstack) = ebp; 56 | *(--krnstack) = esi; 57 | *(--krnstack) = edi; 58 | *(--krnstack) = es & 0xffff; 59 | *(--krnstack) = ds & 0xffff; 60 | *(--krnstack) = fs & 0xffff; 61 | *(--krnstack) = gs & 0xffff; 62 | p->kernel_stack = krnstack; 63 | if (copy_mem(last_pid, p)) { 64 | // todo: 65 | // abort 66 | } 67 | set_ldt_desc(gdt + last_pid + FIRST_LDT_ENTRY, &(p->ldt)); 68 | p->state = TASK_RUNNING; 69 | return 1; 70 | } 71 | -------------------------------------------------------------------------------- /demos/fs_demo/fs_patch_tool/patch.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const file_list = [ 4 | 'hello_fs' 5 | ]; 6 | 7 | function zero_buffer(size) { 8 | let ret = Buffer.alloc(size); 9 | for (let i = 0; i < size; ++i) { 10 | ret[i] = 0; 11 | } 12 | return ret; 13 | } 14 | 15 | async function main() { 16 | const vfd_path = `${__dirname}/../a.vfd`; 17 | const vfd_content = fs.readFileSync(vfd_path); 18 | console.log('vfd_content length : ', vfd_content.length); 19 | const vfd_length = vfd_content.length; 20 | let fs_header = zero_buffer(4); 21 | const file_cnt = file_list.length; 22 | fs_header.writeInt32LE(file_cnt); 23 | let file_buffer = zero_buffer(0); 24 | for (let i = 0; i < file_cnt; ++i) { 25 | const path = `${__dirname}/../root_fs/${file_list[i]}`; 26 | const content = fs.readFileSync(path); 27 | const content_length = content.length; 28 | console.log(`path ${path} : ${content_length}`); 29 | const file_length_buffer = zero_buffer(4); 30 | const file_name_buffer = zero_buffer(8); 31 | file_length_buffer.writeInt32LE(content_length); 32 | Buffer.from(file_list[i]).copy(file_name_buffer); 33 | fs_header = Buffer.concat([fs_header, file_length_buffer, file_name_buffer]); 34 | const file_pad = zero_buffer(20 * 1024 - content_length); 35 | file_buffer = Buffer.concat([file_buffer, content, file_pad]); 36 | } 37 | const fs_header_pad = zero_buffer(124 - fs_header.length); 38 | fs_header = Buffer.concat([fs_header, fs_header_pad]); 39 | console.log('fs_header length : ', fs_header.length); 40 | const start = 0x5df84; // 0x90000-200k-124 在内存中的位置应该是0x5df84-0x200+0x10000=0x6dd84 41 | const p0 = vfd_content.slice(0, start); 42 | const p1 = Buffer.concat([fs_header, file_buffer]); 43 | const p2 = vfd_content.slice(start + p1.length); 44 | const final_buffer = Buffer.concat([p0, p1, p2]); 45 | fs.writeFileSync(vfd_path, final_buffer); 46 | process.exit(); 47 | } 48 | main(); -------------------------------------------------------------------------------- /demos/fs_demo/gate_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef GATE_TOOL_H 2 | #define GATE_TOOL_H 3 | 4 | #include "sched.h" 5 | 6 | #define _set_gate(gate_addr, type, dpl, addr) \ 7 | __asm__( \ 8 | "movw %%dx,%%ax\n\t" \ 9 | "movw %0,%%dx\n\t" \ 10 | "movl %%eax,%1\n\t" \ 11 | "movl %%edx,%2" \ 12 | : \ 13 | : "i"((short)(0x8000 + (dpl << 13) + (type << 8))), \ 14 | "o"(*((char *)(gate_addr))), "o"(*(4 + (char *)(gate_addr))), \ 15 | "d"((char *)(addr)), "a"(0x00080000)) 16 | 17 | #define set_intr_gate(n, addr) _set_gate(&idt[n], 14, 0, addr) 18 | 19 | #define set_trap_gate(n, addr) _set_gate(&idt[n], 15, 0, addr) 20 | 21 | #define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr) 22 | #endif -------------------------------------------------------------------------------- /demos/fs_demo/intel_err_handle.c: -------------------------------------------------------------------------------- 1 | extern void print_str(char *s); 2 | 3 | void e0() { print_str("e0"); } 4 | 5 | void e1() { print_str("e1"); } 6 | 7 | void e2() { print_str("e2"); } 8 | 9 | void e3() { print_str("e3"); } 10 | 11 | void e4() { print_str("e4"); } 12 | 13 | void e5() { print_str("e5"); } 14 | 15 | void e6() { print_str("e6"); } 16 | 17 | void e7() { print_str("e7"); } 18 | 19 | void e8() { print_str("e8"); } 20 | 21 | void e9() { print_str("e9"); } 22 | 23 | void e10() { print_str("e10"); } 24 | 25 | void e11() { print_str("e11"); } 26 | 27 | void e12() { print_str("e12"); } 28 | 29 | void e13() { print_str("e13"); } 30 | 31 | void e15() { print_str("e15"); } 32 | 33 | void e16() { print_str("e16"); } 34 | -------------------------------------------------------------------------------- /demos/fs_demo/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=62 skip=8 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=63 conv=notrunc 6 | node fs_patch_tool/patch.js 7 | link: head lan_main boot 8 | ld -m elf_i386 -T n.lds -o lan_os head.o lan_main.o sys_call.o intel_err_handle.o sched.o fork.o mm.o print_str.o 9 | head: 10 | nasm -felf32 -o head.o head.s 11 | lan_main: 12 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c sys_call.c intel_err_handle.c sched.c fork.c mm.c print_str.c 13 | boot: 14 | nasm -o boot.bin boot.s -l boot.lst 15 | clean: 16 | rm lan_os lan_main.o sys_call.o intel_err_handle.o head.o sched.o fork.o mm.o print_str.o boot.bin boot.lst a.img a.vfd 17 | -------------------------------------------------------------------------------- /demos/fs_demo/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef MM_H 2 | #define MM_H 3 | 4 | #define PAGE_SIZE 4096 5 | #define PAGE_DIR 0x8000 6 | #define PG_NUM 16 7 | 8 | #define LOW_MEM 0x100000 9 | #define MAP_NR(addr) (((addr)-LOW_MEM) >> 12) 10 | #define invalidate() __asm__("movl %%eax,%%cr3" ::"a"(PAGE_DIR)) 11 | 12 | extern void mm_init(); 13 | extern unsigned long get_free_page(); 14 | extern int copy_page_tables(unsigned long from, unsigned long to, long size); 15 | 16 | #endif -------------------------------------------------------------------------------- /demos/fs_demo/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/fs_demo/print_str.c: -------------------------------------------------------------------------------- 1 | #define MAX_L 25 2 | #define SCREEN_LEN 2000 3 | char screen_buff[SCREEN_LEN]; 4 | int cur_l = 0; 5 | extern void write_char(char ch, int pos); 6 | void validate_screen() { 7 | for (int i = 0; i < SCREEN_LEN; ++i) { 8 | write_char(screen_buff[i], i); 9 | } 10 | } 11 | 12 | void print_str(char *s) { 13 | if (cur_l >= MAX_L) { 14 | for (int i = 0; i < 24; ++i) { 15 | for (int j = 0; j < 80; ++j) { 16 | screen_buff[i * 80 + j] = screen_buff[(i + 1) * 80 + j]; 17 | } 18 | } 19 | for (int j = 0; j < 80; ++j) { 20 | screen_buff[24 * 80 + j] = 0; 21 | } 22 | cur_l = MAX_L - 1; 23 | } 24 | int y = cur_l; 25 | int x = 0; 26 | while (s[x] != 0) { 27 | screen_buff[y * 80 + x] = s[x]; 28 | x++; 29 | } 30 | cur_l++; 31 | validate_screen(); 32 | } 33 | -------------------------------------------------------------------------------- /demos/fs_demo/readme.md: -------------------------------------------------------------------------------- 1 | ### 血与泪 2 | 3 | ### 调试过程中遇到的问题 4 | 5 | 1. 首先要改造调用bios 0x13中断来读取更多的扇区数,这里就要不断修改磁头号,磁道号来读取下18个扇区的内容[bios int 0x13](https://blog.csdn.net/zxl3901/article/details/50072539) 6 | 2. 把读取后的数据放在0x10000开始的内存中,每读18个扇区es 要增加0x240 因为 (0x240 << 4) = 0x2400 = 18*512 7 | 3. ~~如果读入的扇区数过多会读入到0xb0000~0xb2000中,这里是显存地址,会冲调奇数字节调属性,所以要调整write_char函数在写入显存时也要强制写入属性~~ 8 | 4. 实际上我们读入的数据不能超过0xA0000,这里已经是显示缓冲区了(见《linux内核完全剖析》18页图),所以我最多循环63次 9 | 5. 是什么提醒我去查看内存分布的: 10 | 由于一直不能把磁盘上的数据写入到接近1M的高地址处,所以去查看软盘控制器参数表,0x1E中断,地址是0x1E*4=0x78 11 | 这里存放的4字节操作数,给lgs指令调用,高8位给gs,低8位给通用寄存器如si 12 | 最终[gs:si]是磁盘参数表的地址 13 | 发现这个地址是[0x0f00:efc7]=0xfefc7,是接近1M的高地址,提醒了我去看一下PC 1M以下的内存布局,发现这里是ROM BIOS映射区,我猜应该是没法写入的 -------------------------------------------------------------------------------- /demos/fs_demo/root_fs/hello_fs: -------------------------------------------------------------------------------- 1 | hi, lan_os -------------------------------------------------------------------------------- /demos/fs_demo/sched.c: -------------------------------------------------------------------------------- 1 | #include "sched.h" 2 | #include "mm.h" 3 | 4 | struct task_struct *task[NR_TASKS]; 5 | struct task_struct init_task; 6 | struct task_struct *current = (struct task_struct *)&init_task; 7 | long last_pid = -1; 8 | long last_sched_i = 0; 9 | 10 | extern void switch_to(unsigned long, struct task_struct *); 11 | extern void set_tss0_esp0(unsigned long); 12 | extern void get_esp0_when_switch(unsigned long *); 13 | extern void krn_stk0(); 14 | 15 | void sched_init() { 16 | for (int i = 0; i < NR_TASKS; ++i) { 17 | task[i] = 0; 18 | } 19 | init_task.state = TASK_UNINTERRUPTIBLE; 20 | init_task.pid = ++last_pid; 21 | init_task.ldt[0].a = 0; 22 | init_task.ldt[0].b = 0; 23 | init_task.ldt[1].a = 0x3ff; 24 | init_task.ldt[1].b = 0xc0fa00; 25 | init_task.ldt[2].a = 0x3ff; 26 | init_task.ldt[2].b = 0xc0f200; 27 | set_ldt_desc(gdt + 0 + FIRST_LDT_ENTRY, &(init_task.ldt)); 28 | task[0] = &init_task; 29 | lldt(0); 30 | init_task.state = TASK_RUNNING; 31 | } 32 | 33 | void schedule() { 34 | int i = last_sched_i; 35 | while (1) { 36 | ++i; 37 | i %= NR_TASKS; 38 | if (task[i]) { 39 | if (current->pid != i) { 40 | if (task[i]->state == TASK_RUNNING) { 41 | last_sched_i = i; 42 | if (0 == i) { 43 | set_tss0_esp0( 44 | krn_stk0); // 0任务的内核栈是写死的,不能用task[i])+PAGE_SIZE来计算 45 | } else { 46 | set_tss0_esp0((unsigned long)(task[i]) + 47 | PAGE_SIZE); //给切换栈机制搭桥 48 | } 49 | unsigned long esp0 = 0; 50 | get_esp0_when_switch(&esp0); 51 | current->kernel_stack = esp0; 52 | current = task[i]; 53 | switch_to(_LDT(i), task[i]); 54 | return; 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | void do_timer(unsigned long cs) { 62 | if (0x8 == cs) { 63 | } else if (0xf == cs) { 64 | schedule(); 65 | } else { 66 | } 67 | } -------------------------------------------------------------------------------- /demos/init_8259a/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 17 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+SYSLEN ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | jnc ok_load 16 | jmp $ 17 | 18 | ok_load: 19 | cli 20 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 21 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 22 | xor ax, ax 23 | mov es, ax 24 | mov cx, 0x1000 25 | sub si, si 26 | sub di, di 27 | cld ;df = 0 rep movsw是正向的 28 | rep movsw 29 | mov ax, 0x0 ;重新恢复ds指向0x0 30 | mov ds, ax 31 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 32 | mov ax, 0x0001 33 | lmsw ax 34 | jmp dword 8:0 35 | gdt: 36 | dw 0, 0, 0, 0 ;第一个描述符,没有用 37 | dw 0x07ff ;代码段 从0地址开始 38 | dw 0x0000 39 | dw 0x9a00 40 | dw 0x00c0 41 | dw 0x07ff ;数据段 从0地址开始 42 | dw 0x0000 43 | dw 0x9200 44 | dw 0x00c0 45 | 46 | 47 | gdt_48: 48 | dw 0x7ff ;2048/8=256个描述符 49 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 50 | 51 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 52 | times 510 - ($-$$) db 0 53 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/init_8259a/gate_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef GATE_TOOL_H 2 | #define GATE_TOOL_H 3 | 4 | typedef struct desc_struct { 5 | unsigned long a, b; 6 | } desc_table[256]; 7 | 8 | extern desc_table idt; 9 | 10 | #define _set_gate(gate_addr, type, dpl, addr) \ 11 | __asm__( \ 12 | "movw %%dx,%%ax\n\t" \ 13 | "movw %0,%%dx\n\t" \ 14 | "movl %%eax,%1\n\t" \ 15 | "movl %%edx,%2" \ 16 | : \ 17 | : "i"((short)(0x8000 + (dpl << 13) + (type << 8))), \ 18 | "o"(*((char *)(gate_addr))), "o"(*(4 + (char *)(gate_addr))), \ 19 | "d"((char *)(addr)), "a"(0x00080000)) 20 | 21 | #define set_intr_gate(n, addr) _set_gate(&idt[n], 14, 0, addr) 22 | 23 | #define set_trap_gate(n, addr) _set_gate(&idt[n], 15, 0, addr) 24 | 25 | #define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr) 26 | #endif -------------------------------------------------------------------------------- /demos/init_8259a/lan_main.c: -------------------------------------------------------------------------------- 1 | extern void write_char(char ch); 2 | extern void open_a20(); 3 | extern void init_8259A(); 4 | extern void timer_interrupt(); 5 | extern void init_latch(); 6 | extern void set_sti(); 7 | 8 | #include "gate_tool.h" 9 | 10 | void check_a20_valid() { 11 | unsigned char *p0 = 0x0; 12 | unsigned char *p1 = 0x100000; 13 | for (unsigned char i = 0; i < 10; ++i) { 14 | *p0 = i; 15 | if (*p0 != *p1) { 16 | write_char('b'); 17 | break; 18 | } else { 19 | write_char('e'); 20 | } 21 | } 22 | } 23 | 24 | void lan_main() { 25 | write_char('L'); 26 | write_char('O'); 27 | write_char('V'); 28 | write_char('E'); 29 | open_a20(); 30 | check_a20_valid(); 31 | init_latch(); 32 | init_8259A(); 33 | set_intr_gate(0x20, &timer_interrupt); 34 | set_sti(); 35 | while (1) 36 | ; 37 | } 38 | 39 | void do_timer() { 40 | write_char('T'); 41 | write_char('I'); 42 | write_char('M'); 43 | write_char('E'); 44 | write_char('R'); 45 | } 46 | -------------------------------------------------------------------------------- /demos/init_8259a/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=17 skip=8 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=18 conv=notrunc 6 | link: head lan_main boot 7 | ld -m elf_i386 -T n.lds -o lan_os head.o lan_main.o 8 | head: 9 | nasm -felf32 -o head.o head.s 10 | lan_main: 11 | gcc -m32 -c lan_main.c 12 | boot: 13 | nasm -o boot.bin boot.s -l boot.lst 14 | clean: 15 | rm lan_os lan_main.o head.o boot.bin boot.lst a.img a.vfd 16 | 17 | -------------------------------------------------------------------------------- /demos/init_8259a/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/keyboard_demo/bin/test/lan_main.c: -------------------------------------------------------------------------------- 1 | #define _syscall1(type, name, atype, a) \ 2 | type name(atype a) { \ 3 | long __res; \ 4 | __asm__ volatile("int $0x80" \ 5 | : "=a"(__res) \ 6 | : "0"(__NR_##name), "b"((long)(a))); \ 7 | if (__res >= 0) return (type)__res; \ 8 | return -1; \ 9 | } 10 | 11 | int s_print_str(char*); 12 | int s_print_num(int); 13 | 14 | void lan_main() { 15 | s_print_str("im test"); 16 | s_print_num(222); 17 | while (1) 18 | ; 19 | } 20 | #define __NR_s_print_str 4 21 | #define __NR_s_print_num 5 22 | _syscall1(int, s_print_str, char*, msg) _syscall1(int, s_print_num, int, num) -------------------------------------------------------------------------------- /demos/keyboard_demo/bin/test/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=test bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o 5 | lan_main: 6 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm test test_elf lan_main.o 9 | cp: 10 | cp test ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/keyboard_demo/bin/test/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/keyboard_demo/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 72 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+17 ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | mov ax, 01220h 16 | mov es, ax 17 | mov cx, 0001h 18 | jnc ok_load1 19 | jmp $ 20 | 21 | ok_load1: 22 | mov ax, 0200h+18 ;ah 读扇区功能号2 al读扇区数量 18 23 | xor dh, 1 24 | and dh, 1 25 | int 013h 26 | mov ax, es 27 | add ax, 0240h 28 | mov es, ax 29 | jnc ok_load2 30 | jmp $ 31 | 32 | ok_load2: 33 | test dh, dh 34 | jz dontaddch 35 | add ch, 1 36 | dontaddch: 37 | mov ax, [index] 38 | sub ax, 1 39 | mov [index], ax 40 | test ax, ax 41 | jnz ok_load1 42 | 43 | ok_load: 44 | cli 45 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 46 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 47 | xor ax, ax 48 | mov es, ax 49 | mov cx, 0x3000 ;这时拷贝 0x3000*2(字节)/512=48(扇区) 50 | sub si, si 51 | sub di, di 52 | cld ;df = 0 rep movsw是正向的 53 | rep movsw 54 | mov ax, 0x0 ;重新恢复ds指向0x0 55 | mov ds, ax 56 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 57 | mov ax, 0x0001 58 | lmsw ax 59 | jmp dword 8:0 60 | index: 61 | dw 63 ;这里63是极限 位置末尾是0x9fe00 接近显示缓冲区0xA0000 62 | gdt: 63 | dw 0, 0, 0, 0 ;第一个描述符,没有用 64 | dw 0x07ff ;代码段 从0地址开始 65 | dw 0x0000 66 | dw 0x9a00 67 | dw 0x00c0 68 | dw 0x07ff ;数据段 从0地址开始 69 | dw 0x0000 70 | dw 0x9200 71 | dw 0x00c0 72 | 73 | gdt_48: 74 | dw 0x7ff ;2048/8=256个描述符 75 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 76 | 77 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 78 | times 510 - ($-$$) db 0 79 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/keyboard_demo/fork.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | #include "sched.h" 3 | 4 | extern void panic(char *msg); 5 | 6 | extern void first_return_from_kernel(); 7 | unsigned long get_data_base(struct task_struct *s) { 8 | unsigned long ret = (s->ldt[2].a) >> 16; 9 | ret |= (s->ldt[2].b & 0xff) << 16; 10 | ret |= s->ldt[2].b & 0xff000000; 11 | return ret; 12 | } 13 | 14 | int copy_mem(int nr, struct task_struct *p) { 15 | unsigned long old_data_base, new_data_base, data_limit; 16 | unsigned long new_code_base, code_limit; 17 | 18 | code_limit = get_limit(0x0f); 19 | data_limit = get_limit(0x17); 20 | old_data_base = get_data_base(current); 21 | new_data_base = new_code_base = nr * TASK_SIZE + PG_NUM * 4 * 1024 * 1024; 22 | p->start_code = new_code_base; 23 | set_base(&(p->ldt[1]), new_code_base); 24 | set_base(&(p->ldt[2]), new_data_base); 25 | if (copy_page_tables(old_data_base, new_data_base, data_limit)) { 26 | // todo 27 | // free_page_tables 28 | panic("copy page tables failed."); 29 | } 30 | return 0; 31 | } 32 | 33 | int find_empty_process() { return ++last_pid; } 34 | 35 | int copy_process(long eax, long ebp, long edi, long esi, long gs, long none, 36 | long ebx, long ecx, long edx, long orig_eax, long fs, long es, 37 | long ds, long eip, long cs, long eflags, long esp, long ss) { 38 | struct task_struct *p = (struct task_struct *)get_free_page(); 39 | 40 | if (!p) { 41 | // todo 42 | } 43 | *p = *current; 44 | p->state = TASK_UNINTERRUPTIBLE; 45 | p->pid = eax; 46 | task[last_pid] = p; 47 | long *krnstack = (long *)(PAGE_SIZE + (long)p); 48 | *(--krnstack) = ss; 49 | *(--krnstack) = esp; 50 | *(--krnstack) = eflags; 51 | *(--krnstack) = cs; 52 | *(--krnstack) = eip; 53 | *(--krnstack) = first_return_from_kernel; 54 | *(--krnstack) = 0; // eax 55 | *(--krnstack) = ebx; 56 | *(--krnstack) = ecx; 57 | *(--krnstack) = edx; 58 | *(--krnstack) = ebp; 59 | *(--krnstack) = esi; 60 | *(--krnstack) = edi; 61 | *(--krnstack) = es & 0xffff; 62 | *(--krnstack) = ds & 0xffff; 63 | *(--krnstack) = fs & 0xffff; 64 | *(--krnstack) = gs & 0xffff; 65 | p->kernel_stack = krnstack; 66 | if (copy_mem(last_pid, p)) { 67 | // todo: 68 | // abort 69 | } 70 | set_ldt_desc(gdt + last_pid + FIRST_LDT_ENTRY, &(p->ldt)); 71 | p->state = TASK_RUNNING; 72 | return 1; 73 | } 74 | -------------------------------------------------------------------------------- /demos/keyboard_demo/fs_patch_tool/patch.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const file_list = [ 4 | 'hello_fs', 5 | 'test' 6 | ]; 7 | 8 | function zero_buffer(size) { 9 | let ret = Buffer.alloc(size); 10 | for (let i = 0; i < size; ++i) { 11 | ret[i] = 0; 12 | } 13 | return ret; 14 | } 15 | 16 | async function main() { 17 | const vfd_path = `${__dirname}/../a.vfd`; 18 | const vfd_content = fs.readFileSync(vfd_path); 19 | console.log('vfd_content length : ', vfd_content.length); 20 | const vfd_length = vfd_content.length; 21 | let fs_header = zero_buffer(4); 22 | const file_cnt = file_list.length; 23 | fs_header.writeInt32LE(file_cnt); 24 | let file_buffer = zero_buffer(0); 25 | for (let i = 0; i < file_cnt; ++i) { 26 | const path = `${__dirname}/../root_fs/${file_list[i]}`; 27 | const content = fs.readFileSync(path); 28 | const content_length = content.length; 29 | console.log(`path ${path} : ${content_length}`); 30 | const file_length_buffer = zero_buffer(4); 31 | const file_name_buffer = zero_buffer(8); 32 | file_length_buffer.writeInt32LE(content_length); 33 | Buffer.from(file_list[i]).copy(file_name_buffer); 34 | fs_header = Buffer.concat([fs_header, file_length_buffer, file_name_buffer]); 35 | const file_pad = zero_buffer(20 * 1024 - content_length); 36 | file_buffer = Buffer.concat([file_buffer, content, file_pad]); 37 | } 38 | const fs_header_pad = zero_buffer(124 - fs_header.length); 39 | fs_header = Buffer.concat([fs_header, fs_header_pad]); 40 | console.log('fs_header length : ', fs_header.length); 41 | const start = 0x5df84; // 0x90000-200k-124 在内存中的位置应该是0x5df84-0x200+0x10000=0x6dd84 42 | const p0 = vfd_content.slice(0, start); 43 | const p1 = Buffer.concat([fs_header, file_buffer]); 44 | const p2 = vfd_content.slice(start + p1.length); 45 | const final_buffer = Buffer.concat([p0, p1, p2]); 46 | fs.writeFileSync(vfd_path, final_buffer); 47 | process.exit(); 48 | } 49 | main(); -------------------------------------------------------------------------------- /demos/keyboard_demo/gate_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef GATE_TOOL_H 2 | #define GATE_TOOL_H 3 | 4 | #include "sched.h" 5 | 6 | #define _set_gate(gate_addr, type, dpl, addr) \ 7 | __asm__( \ 8 | "movw %%dx,%%ax\n\t" \ 9 | "movw %0,%%dx\n\t" \ 10 | "movl %%eax,%1\n\t" \ 11 | "movl %%edx,%2" \ 12 | : \ 13 | : "i"((short)(0x8000 + (dpl << 13) + (type << 8))), \ 14 | "o"(*((char *)(gate_addr))), "o"(*(4 + (char *)(gate_addr))), \ 15 | "d"((char *)(addr)), "a"(0x00080000)) 16 | 17 | #define set_intr_gate(n, addr) _set_gate(&idt[n], 14, 0, addr) 18 | 19 | #define set_trap_gate(n, addr) _set_gate(&idt[n], 15, 0, addr) 20 | 21 | #define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr) 22 | #endif -------------------------------------------------------------------------------- /demos/keyboard_demo/intel_err_handle.c: -------------------------------------------------------------------------------- 1 | extern void print_str(char *s); 2 | extern void panic(char *msg); 3 | 4 | void e0() { print_str("e0"); } 5 | 6 | void e1() { print_str("e1"); } 7 | 8 | void e2() { print_str("e2"); } 9 | 10 | void e3() { print_str("e3"); } 11 | 12 | void e4() { print_str("e4"); } 13 | 14 | void e5() { print_str("e5"); } 15 | 16 | void e6() { print_str("e6"); } 17 | 18 | void e7() { print_str("e7"); } 19 | 20 | void e8() { print_str("e8"); } 21 | 22 | void e9() { print_str("e9"); } 23 | 24 | void e10() { print_str("e10"); } 25 | 26 | void e11() { print_str("e11"); } 27 | 28 | void e12() { panic("e12"); } 29 | 30 | void e13() { panic("e13"); } 31 | 32 | void e15() { print_str("e15"); } 33 | 34 | void e16() { print_str("e16"); } 35 | -------------------------------------------------------------------------------- /demos/keyboard_demo/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=62 skip=8 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=63 conv=notrunc 6 | node fs_patch_tool/patch.js 7 | link: head lan_main boot 8 | ld -m elf_i386 -T n.lds -o lan_os head.o lan_main.o sys_call.o intel_err_handle.o sched.o fork.o mm.o print_str.o keyboard.o 9 | head: 10 | nasm -felf32 -o head.o head.s 11 | lan_main: 12 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c sys_call.c intel_err_handle.c sched.c fork.c mm.c print_str.c keyboard.c 13 | boot: 14 | nasm -o boot.bin boot.s -l boot.lst 15 | clean: 16 | rm lan_os lan_main.o sys_call.o intel_err_handle.o head.o sched.o fork.o mm.o print_str.o keyboard.o boot.bin boot.lst a.img a.vfd 17 | -------------------------------------------------------------------------------- /demos/keyboard_demo/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef MM_H 2 | #define MM_H 3 | 4 | #define PAGE_SIZE 4096 5 | #define PAGE_DIR 0x10000 6 | #define PG_NUM 16 7 | 8 | #define LOW_MEM 0x100000 9 | #define MAP_NR(addr) (((addr)-LOW_MEM) >> 12) 10 | #define invalidate() __asm__("movl %%eax,%%cr3" ::"a"(PAGE_DIR)) 11 | 12 | extern void mm_init(); 13 | extern unsigned long get_free_page(); 14 | extern int free_page_tables(unsigned long from, unsigned long size); 15 | extern int copy_page_tables(unsigned long from, unsigned long to, long size); 16 | 17 | #endif -------------------------------------------------------------------------------- /demos/keyboard_demo/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/keyboard_demo/print_str.c: -------------------------------------------------------------------------------- 1 | #define MAX_L 24 2 | #define SCREEN_LEN 2000 3 | char screen_buff[SCREEN_LEN]; 4 | int cur_l = 0; 5 | extern void write_char(char ch, int pos); 6 | 7 | void init_screen_buff() { 8 | for (int i = 0; i < SCREEN_LEN; ++i) { 9 | screen_buff[i] = 0; 10 | } 11 | } 12 | 13 | void validate_screen() { 14 | for (int i = 0; i < SCREEN_LEN; ++i) { 15 | write_char(screen_buff[i], i); 16 | } 17 | } 18 | 19 | void print_str(char *s) { 20 | if (cur_l >= MAX_L) { 21 | cur_l = MAX_L - 1; 22 | for (int i = 0; i < cur_l; ++i) { 23 | for (int j = 0; j < 80; ++j) { 24 | screen_buff[i * 80 + j] = screen_buff[(i + 1) * 80 + j]; 25 | } 26 | } 27 | for (int j = 0; j < 80; ++j) { 28 | screen_buff[cur_l * 80 + j] = 0; 29 | } 30 | } 31 | int y = cur_l; 32 | int x = 0; 33 | while (s[x] != 0) { 34 | screen_buff[y * 80 + x] = s[x]; 35 | x++; 36 | } 37 | cur_l++; 38 | validate_screen(); 39 | } 40 | 41 | void print_num(int num) { 42 | char buf[64]; 43 | int index = 0; 44 | for (int i = 0; i < 64; ++i) { 45 | buf[i] = 0; 46 | } 47 | if (num == 0) { 48 | buf[index++] = '0'; 49 | } else if (num < 0) { 50 | num = -num; 51 | buf[index++] = '-'; 52 | } 53 | char tmp[64]; 54 | int index_tmp = 0; 55 | while (num > 0) { 56 | tmp[index_tmp++] = num % 10 + '0'; 57 | num /= 10; 58 | } 59 | for (int i = index_tmp - 1; i >= 0; --i) { 60 | buf[index++] = tmp[i]; 61 | } 62 | print_str(buf); 63 | } 64 | 65 | void print_hex(int num) { 66 | char buf[64]; 67 | int index = 0; 68 | for (int i = 0; i < 64; ++i) { 69 | buf[i] = 0; 70 | } 71 | if (num == 0) { 72 | buf[index++] = '0'; 73 | } else if (num < 0) { 74 | num = -num; 75 | buf[index++] = '-'; 76 | } 77 | buf[index++] = '0'; 78 | buf[index++] = 'x'; 79 | char tmp[64]; 80 | int index_tmp = 0; 81 | while (num > 0) { 82 | unsigned char ch = num % 16; 83 | if (ch < 10) { 84 | ch += '0'; 85 | } else { 86 | ch -= 10; 87 | ch += 'a'; 88 | } 89 | tmp[index_tmp++] = ch; 90 | num /= 16; 91 | } 92 | for (int i = index_tmp - 1; i >= 0; --i) { 93 | buf[index++] = tmp[i]; 94 | } 95 | print_str(buf); 96 | } 97 | 98 | void panic(char *msg) { 99 | print_str(msg); 100 | while (1) { 101 | validate_screen(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /demos/keyboard_demo/readme.md: -------------------------------------------------------------------------------- 1 | ### 调试中遇到的问题 2 | 3 | 本次把pg_dir 调整到0x10000 4 | 5 | 另外lds脚本可以强制指定符号的地址(虽然没有用上) 6 | 7 | SECTIONS 8 | { 9 | . = 0x0; 10 | .text : { *(.text) } 11 | pg_dir = 0x8000 12 | } 13 | 14 | 如果定义了符号 `pg_dir` 这样就能把它强制定位到0x8000处 -------------------------------------------------------------------------------- /demos/keyboard_demo/root_fs/hello_fs: -------------------------------------------------------------------------------- 1 | hi, lan_os. it's a nice day!!! -------------------------------------------------------------------------------- /demos/keyboard_demo/root_fs/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/keyboard_demo/root_fs/test -------------------------------------------------------------------------------- /demos/keyboard_demo/sched.c: -------------------------------------------------------------------------------- 1 | #include "sched.h" 2 | #include "mm.h" 3 | 4 | struct task_struct *task[NR_TASKS]; 5 | struct task_struct init_task; 6 | struct task_struct *current = (struct task_struct *)&init_task; 7 | long last_pid = -1; 8 | long last_sched_i = 0; 9 | 10 | extern void switch_to(unsigned long, struct task_struct *); 11 | extern void set_tss0_esp0(unsigned long); 12 | extern void get_esp0_when_switch(unsigned long *); 13 | extern void krn_stk0(); 14 | 15 | void sched_init() { 16 | for (int i = 0; i < NR_TASKS; ++i) { 17 | task[i] = 0; 18 | } 19 | init_task.state = TASK_UNINTERRUPTIBLE; 20 | init_task.pid = ++last_pid; 21 | init_task.ldt[0].a = 0; 22 | init_task.ldt[0].b = 0; 23 | init_task.ldt[1].a = 0x3ff; 24 | init_task.ldt[1].b = 0xc0fa00; 25 | init_task.ldt[2].a = 0x3ff; 26 | init_task.ldt[2].b = 0xc0f200; 27 | set_ldt_desc(gdt + 0 + FIRST_LDT_ENTRY, &(init_task.ldt)); 28 | task[0] = &init_task; 29 | lldt(0); 30 | init_task.state = TASK_RUNNING; 31 | } 32 | 33 | void schedule() { 34 | int i = last_sched_i; 35 | while (1) { 36 | ++i; 37 | i %= NR_TASKS; 38 | if (task[i]) { 39 | if (current->pid != i) { 40 | if (task[i]->state == TASK_RUNNING) { 41 | last_sched_i = i; 42 | if (0 == i) { 43 | set_tss0_esp0( 44 | krn_stk0); // 0任务的内核栈是写死的,不能用task[i])+PAGE_SIZE来计算 45 | } else { 46 | set_tss0_esp0((unsigned long)(task[i]) + 47 | PAGE_SIZE); //给切换栈机制搭桥 48 | } 49 | unsigned long esp0 = 0; 50 | get_esp0_when_switch(&esp0); 51 | current->kernel_stack = esp0; 52 | current = task[i]; 53 | switch_to(_LDT(i), task[i]); 54 | return; 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | void do_timer(unsigned long cs) { 62 | if (0x8 == cs) { 63 | } else if (0xf == cs) { 64 | schedule(); 65 | } else { 66 | } 67 | } -------------------------------------------------------------------------------- /demos/lds_test/asm_int_80.s: -------------------------------------------------------------------------------- 1 | global _start 2 | _start: 3 | mov dword edx, 13 4 | mov dword ecx, message 5 | mov dword ebx, 1 6 | mov dword eax, 4 7 | int 0x80 8 | mov dword ebx, 0 9 | mov dword eax, 1 10 | int 0x80 11 | message: 12 | db "Hello, World", 10 13 | -------------------------------------------------------------------------------- /demos/lds_test/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | nasm -felf64 -o asm_int_80.o asm_int_80.s 3 | ld -T n.lds -o asm_int_80 asm_int_80.o 4 | clean: 5 | rm asm_int_80 asm_int_80.o 6 | 7 | -------------------------------------------------------------------------------- /demos/lds_test/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/lds_test/show.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | od -A x -x asm_int_80 3 | readelf -l asm_int_80 4 | -------------------------------------------------------------------------------- /demos/ls_demo/bin/loop/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=loop bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o 5 | lan_main: 6 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm loop test_elf lan_main.o 9 | cp: 10 | cp loop ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/ls_demo/bin/loop/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/ls_demo/bin/ls/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=ls bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o 5 | lan_main: 6 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm ls test_elf lan_main.o 9 | cp: 10 | cp ls ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/ls_demo/bin/ls/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/ls_demo/bin/shell/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=lan_sh bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o 5 | lan_main: 6 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm lan_sh test_elf lan_main.o 9 | cp: 10 | cp lan_sh ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/ls_demo/bin/shell/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/ls_demo/bin/test/lan_main.c: -------------------------------------------------------------------------------- 1 | #define _syscall1(type, name, atype, a) \ 2 | type name(atype a) { \ 3 | long __res; \ 4 | __asm__ volatile("int $0x80" \ 5 | : "=a"(__res) \ 6 | : "0"(__NR_##name), "b"((long)(a))); \ 7 | if (__res >= 0) return (type)__res; \ 8 | return -1; \ 9 | } 10 | 11 | int s_print_str(char*); 12 | int s_print_num(int); 13 | 14 | void lan_main() { 15 | s_print_str("I am a test executable file !"); 16 | s_print_str("I can print a number."); 17 | s_print_num(222); 18 | while (1) 19 | ; 20 | } 21 | #define __NR_s_print_str 4 22 | #define __NR_s_print_num 5 23 | _syscall1(int, s_print_str, char*, msg) _syscall1(int, s_print_num, int, num) -------------------------------------------------------------------------------- /demos/ls_demo/bin/test/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=test bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o 5 | lan_main: 6 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm test test_elf lan_main.o 9 | cp: 10 | cp test ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/ls_demo/bin/test/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/ls_demo/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 72 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+17 ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | mov ax, 01220h 16 | mov es, ax 17 | mov cx, 0001h 18 | jnc ok_load1 19 | jmp $ 20 | 21 | ok_load1: 22 | mov ax, 0200h+18 ;ah 读扇区功能号2 al读扇区数量 18 23 | xor dh, 1 24 | and dh, 1 25 | int 013h 26 | mov ax, es 27 | add ax, 0240h 28 | mov es, ax 29 | jnc ok_load2 30 | jmp $ 31 | 32 | ok_load2: 33 | test dh, dh 34 | jz dontaddch 35 | add ch, 1 36 | dontaddch: 37 | mov ax, [index] 38 | sub ax, 1 39 | mov [index], ax 40 | test ax, ax 41 | jnz ok_load1 42 | 43 | ok_load: 44 | cli 45 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 46 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 47 | xor ax, ax 48 | mov es, ax 49 | mov cx, 0x3000 ;这时拷贝 0x3000*2(字节)/512=48(扇区) 50 | sub si, si 51 | sub di, di 52 | cld ;df = 0 rep movsw是正向的 53 | rep movsw 54 | mov ax, 0x0 ;重新恢复ds指向0x0 55 | mov ds, ax 56 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 57 | mov ax, 0x0001 58 | lmsw ax 59 | jmp dword 8:0 60 | index: 61 | dw 63 ;这里63是极限 位置末尾是0x9fe00 接近显示缓冲区0xA0000 62 | gdt: 63 | dw 0, 0, 0, 0 ;第一个描述符,没有用 64 | dw 0x07ff ;代码段 从0地址开始 65 | dw 0x0000 66 | dw 0x9a00 67 | dw 0x00c0 68 | dw 0x07ff ;数据段 从0地址开始 69 | dw 0x0000 70 | dw 0x9200 71 | dw 0x00c0 72 | 73 | gdt_48: 74 | dw 0x7ff ;2048/8=256个描述符 75 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 76 | 77 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 78 | times 510 - ($-$$) db 0 79 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/ls_demo/fork.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | #include "sched.h" 3 | 4 | extern void panic(char *msg); 5 | 6 | extern void first_return_from_kernel(); 7 | unsigned long get_data_base(struct task_struct *s) { 8 | unsigned long ret = (s->ldt[2].a) >> 16; 9 | ret |= (s->ldt[2].b & 0xff) << 16; 10 | ret |= s->ldt[2].b & 0xff000000; 11 | return ret; 12 | } 13 | 14 | int copy_mem(int nr, struct task_struct *p) { 15 | unsigned long old_data_base, new_data_base, data_limit; 16 | unsigned long new_code_base, code_limit; 17 | 18 | code_limit = get_limit(0x0f); 19 | data_limit = get_limit(0x17); 20 | old_data_base = get_data_base(current); 21 | new_data_base = new_code_base = nr * TASK_SIZE + PG_NUM * 4 * 1024 * 1024; 22 | p->start_code = new_code_base; 23 | set_base(&(p->ldt[1]), new_code_base); 24 | set_base(&(p->ldt[2]), new_data_base); 25 | if (copy_page_tables(old_data_base, new_data_base, data_limit)) { 26 | // todo 27 | // free_page_tables 28 | panic("copy page tables failed."); 29 | } 30 | return 0; 31 | } 32 | 33 | int find_empty_process() { 34 | for (int i = 0; i < NR_TASKS; ++i) { 35 | if (!task_used[i]) { 36 | task_used[i] = 1; 37 | return i; 38 | } 39 | } 40 | return -1; 41 | } 42 | 43 | int copy_process(long eax, long ebp, long edi, long esi, long gs, long none, 44 | long ebx, long ecx, long edx, long orig_eax, long fs, long es, 45 | long ds, long eip, long cs, long eflags, long esp, long ss) { 46 | if (eax < 0) { 47 | panic("no emtpy task."); 48 | } 49 | struct task_struct *p = (struct task_struct *)get_free_page(); 50 | 51 | if (!p) { 52 | // todo 53 | } 54 | *p = *current; 55 | p->state = TASK_UNINTERRUPTIBLE; 56 | p->pid = eax; 57 | task[eax] = p; 58 | long *krnstack = (long *)(PAGE_SIZE + (long)p); 59 | *(--krnstack) = ss; 60 | *(--krnstack) = esp; 61 | *(--krnstack) = eflags; 62 | *(--krnstack) = cs; 63 | *(--krnstack) = eip; 64 | *(--krnstack) = first_return_from_kernel; 65 | *(--krnstack) = 0; // eax 66 | *(--krnstack) = ebx; 67 | *(--krnstack) = ecx; 68 | *(--krnstack) = edx; 69 | *(--krnstack) = ebp; 70 | *(--krnstack) = esi; 71 | *(--krnstack) = edi; 72 | *(--krnstack) = es & 0xffff; 73 | *(--krnstack) = ds & 0xffff; 74 | *(--krnstack) = fs & 0xffff; 75 | *(--krnstack) = gs & 0xffff; 76 | p->kernel_stack = krnstack; 77 | if (copy_mem(eax, p)) { 78 | // todo: 79 | // abort 80 | } 81 | set_ldt_desc(gdt + eax + FIRST_LDT_ENTRY, &(p->ldt)); 82 | p->state = TASK_RUNNING; 83 | return 1; 84 | } 85 | -------------------------------------------------------------------------------- /demos/ls_demo/fs_patch_tool/patch.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const file_list = [ 4 | 'hello_fs', 5 | 'test', 6 | 'lan_sh', 7 | 'ls', 8 | 'loop', 9 | ]; 10 | 11 | function zero_buffer(size) { 12 | let ret = Buffer.alloc(size); 13 | for (let i = 0; i < size; ++i) { 14 | ret[i] = 0; 15 | } 16 | return ret; 17 | } 18 | 19 | async function main() { 20 | const vfd_path = `${__dirname}/../a.vfd`; 21 | const vfd_content = fs.readFileSync(vfd_path); 22 | console.log('vfd_content length : ', vfd_content.length); 23 | const vfd_length = vfd_content.length; 24 | let fs_header = zero_buffer(4); 25 | const file_cnt = file_list.length; 26 | fs_header.writeInt32LE(file_cnt); 27 | let file_buffer = zero_buffer(0); 28 | for (let i = 0; i < file_cnt; ++i) { 29 | const path = `${__dirname}/../root_fs/${file_list[i]}`; 30 | const content = fs.readFileSync(path); 31 | const content_length = content.length; 32 | console.log(`path ${path} : ${content_length}`); 33 | const file_length_buffer = zero_buffer(4); 34 | const file_name_buffer = zero_buffer(8); 35 | file_length_buffer.writeInt32LE(content_length); 36 | Buffer.from(file_list[i]).copy(file_name_buffer); 37 | fs_header = Buffer.concat([fs_header, file_length_buffer, file_name_buffer]); 38 | const file_pad = zero_buffer(20 * 1024 - content_length); 39 | file_buffer = Buffer.concat([file_buffer, content, file_pad]); 40 | } 41 | const fs_header_pad = zero_buffer(124 - fs_header.length); 42 | fs_header = Buffer.concat([fs_header, fs_header_pad]); 43 | console.log('fs_header length : ', fs_header.length); 44 | const start = 0x5df84; // 0x90000-200k-124 在内存中的位置应该是0x5df84-0x200+0x10000=0x6dd84 45 | const p0 = vfd_content.slice(0, start); 46 | const p1 = Buffer.concat([fs_header, file_buffer]); 47 | const p2 = vfd_content.slice(start + p1.length); 48 | const final_buffer = Buffer.concat([p0, p1, p2]); 49 | fs.writeFileSync(vfd_path, final_buffer); 50 | process.exit(); 51 | } 52 | main(); -------------------------------------------------------------------------------- /demos/ls_demo/gate_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef GATE_TOOL_H 2 | #define GATE_TOOL_H 3 | 4 | #include "sched.h" 5 | 6 | #define _set_gate(gate_addr, type, dpl, addr) \ 7 | __asm__( \ 8 | "movw %%dx,%%ax\n\t" \ 9 | "movw %0,%%dx\n\t" \ 10 | "movl %%eax,%1\n\t" \ 11 | "movl %%edx,%2" \ 12 | : \ 13 | : "i"((short)(0x8000 + (dpl << 13) + (type << 8))), \ 14 | "o"(*((char *)(gate_addr))), "o"(*(4 + (char *)(gate_addr))), \ 15 | "d"((char *)(addr)), "a"(0x00080000)) 16 | 17 | #define set_intr_gate(n, addr) _set_gate(&idt[n], 14, 0, addr) 18 | 19 | #define set_trap_gate(n, addr) _set_gate(&idt[n], 15, 0, addr) 20 | 21 | #define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr) 22 | #endif -------------------------------------------------------------------------------- /demos/ls_demo/intel_err_handle.c: -------------------------------------------------------------------------------- 1 | extern void print_str(char *s); 2 | extern void panic(char *msg); 3 | 4 | void e0() { print_str("e0"); } 5 | 6 | void e1() { print_str("e1"); } 7 | 8 | void e2() { print_str("e2"); } 9 | 10 | void e3() { print_str("e3"); } 11 | 12 | void e4() { print_str("e4"); } 13 | 14 | void e5() { print_str("e5"); } 15 | 16 | void e6() { print_str("e6"); } 17 | 18 | void e7() { print_str("e7"); } 19 | 20 | void e8() { print_str("e8"); } 21 | 22 | void e9() { print_str("e9"); } 23 | 24 | void e10() { print_str("e10"); } 25 | 26 | void e11() { print_str("e11"); } 27 | 28 | void e12() { panic("e12"); } 29 | 30 | void e13() { panic("e13"); } 31 | 32 | void e15() { print_str("e15"); } 33 | 34 | void e16() { print_str("e16"); } 35 | -------------------------------------------------------------------------------- /demos/ls_demo/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=62 skip=8 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=63 conv=notrunc 6 | node fs_patch_tool/patch.js 7 | link: head lan_main boot 8 | ld -m elf_i386 -T n.lds -o lan_os head.o lan_main.o sys_call.o intel_err_handle.o sched.o fork.o mm.o print_str.o keyboard.o 9 | head: 10 | nasm -felf32 -o head.o head.s 11 | lan_main: 12 | gcc -O0 -m32 -g -fno-stack-protector -fno-pie -c lan_main.c sys_call.c intel_err_handle.c sched.c fork.c mm.c print_str.c keyboard.c 13 | boot: 14 | nasm -o boot.bin boot.s -l boot.lst 15 | clean: 16 | rm lan_os lan_main.o sys_call.o intel_err_handle.o head.o sched.o fork.o mm.o print_str.o keyboard.o boot.bin boot.lst a.img a.vfd 17 | -------------------------------------------------------------------------------- /demos/ls_demo/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef MM_H 2 | #define MM_H 3 | 4 | #define PAGE_SIZE 4096 5 | #define PAGE_DIR 0x10000 6 | #define PG_NUM 16 7 | 8 | #define LOW_MEM 0x100000 9 | #define MAP_NR(addr) (((addr)-LOW_MEM) >> 12) 10 | #define invalidate() __asm__("movl %%eax,%%cr3" ::"a"(PAGE_DIR)) 11 | 12 | extern void mm_init(); 13 | extern unsigned long get_free_page(); 14 | extern int free_page_tables(unsigned long from, unsigned long size); 15 | extern int copy_page_tables(unsigned long from, unsigned long to, long size); 16 | 17 | #endif -------------------------------------------------------------------------------- /demos/ls_demo/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/ls_demo/root_fs/hello_fs: -------------------------------------------------------------------------------- 1 | hi, lan_os. it's a nice day!!! -------------------------------------------------------------------------------- /demos/ls_demo/root_fs/lan_sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/ls_demo/root_fs/lan_sh -------------------------------------------------------------------------------- /demos/ls_demo/root_fs/loop: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/ls_demo/root_fs/loop -------------------------------------------------------------------------------- /demos/ls_demo/root_fs/ls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/ls_demo/root_fs/ls -------------------------------------------------------------------------------- /demos/ls_demo/root_fs/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/ls_demo/root_fs/test -------------------------------------------------------------------------------- /demos/ls_demo/sched.c: -------------------------------------------------------------------------------- 1 | #include "sched.h" 2 | #include "mm.h" 3 | 4 | struct task_struct *task[NR_TASKS]; 5 | int task_used[NR_TASKS]; 6 | struct task_struct init_task; 7 | struct task_struct *current = (struct task_struct *)&init_task; 8 | long last_sched_i = 0; 9 | 10 | extern void switch_to(unsigned long, struct task_struct *); 11 | extern void set_tss0_esp0(unsigned long); 12 | extern void get_esp0_when_switch(unsigned long *); 13 | extern void krn_stk0(); 14 | 15 | void sched_init() { 16 | for (int i = 0; i < NR_TASKS; ++i) { 17 | task[i] = 0; 18 | task_used[i] = 0; 19 | } 20 | task_used[0] = 1; 21 | init_task.state = TASK_UNINTERRUPTIBLE; 22 | init_task.pid = 0; 23 | init_task.ldt[0].a = 0; 24 | init_task.ldt[0].b = 0; 25 | init_task.ldt[1].a = 0x3ff; 26 | init_task.ldt[1].b = 0xc0fa00; 27 | init_task.ldt[2].a = 0x3ff; 28 | init_task.ldt[2].b = 0xc0f200; 29 | set_ldt_desc(gdt + 0 + FIRST_LDT_ENTRY, &(init_task.ldt)); 30 | task[0] = &init_task; 31 | lldt(0); 32 | init_task.state = TASK_RUNNING; 33 | } 34 | 35 | void schedule() { 36 | int i = last_sched_i; 37 | while (1) { 38 | ++i; 39 | i %= NR_TASKS; 40 | if (task[i]) { 41 | if (current->pid != i) { 42 | if (task[i]->state == TASK_RUNNING) { 43 | last_sched_i = i; 44 | if (0 == i) { 45 | set_tss0_esp0( 46 | krn_stk0); // 0任务的内核栈是写死的,不能用task[i])+PAGE_SIZE来计算 47 | } else { 48 | set_tss0_esp0((unsigned long)(task[i]) + 49 | PAGE_SIZE); //给切换栈机制搭桥 50 | } 51 | unsigned long esp0 = 0; 52 | get_esp0_when_switch(&esp0); 53 | current->kernel_stack = esp0; 54 | current = task[i]; 55 | switch_to(_LDT(i), task[i]); 56 | return; 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | void do_timer(unsigned long cs) { 64 | if (0x8 == cs) { 65 | } else if (0xf == cs) { 66 | schedule(); 67 | } else { 68 | } 69 | } -------------------------------------------------------------------------------- /demos/mm/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 17 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+SYSLEN ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | jnc ok_load 16 | jmp $ 17 | 18 | ok_load: 19 | cli 20 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 21 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 22 | xor ax, ax 23 | mov es, ax 24 | mov cx, 0x1000 25 | sub si, si 26 | sub di, di 27 | cld ;df = 0 rep movsw是正向的 28 | rep movsw 29 | mov ax, 0x0 ;重新恢复ds指向0x0 30 | mov ds, ax 31 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 32 | mov ax, 0x0001 33 | lmsw ax 34 | jmp dword 8:0 35 | gdt: 36 | dw 0, 0, 0, 0 ;第一个描述符,没有用 37 | dw 0x07ff ;代码段 从0地址开始 38 | dw 0x0000 39 | dw 0x9a00 40 | dw 0x00c0 41 | dw 0x07ff ;数据段 从0地址开始 42 | dw 0x0000 43 | dw 0x9200 44 | dw 0x00c0 45 | 46 | 47 | gdt_48: 48 | dw 0x7ff ;2048/8=256个描述符 49 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 50 | 51 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 52 | times 510 - ($-$$) db 0 53 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/mm/gate_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef GATE_TOOL_H 2 | #define GATE_TOOL_H 3 | 4 | typedef struct desc_struct { 5 | unsigned long a, b; 6 | } desc_table[256]; 7 | 8 | extern desc_table idt; 9 | 10 | #define _set_gate(gate_addr, type, dpl, addr) \ 11 | __asm__( \ 12 | "movw %%dx,%%ax\n\t" \ 13 | "movw %0,%%dx\n\t" \ 14 | "movl %%eax,%1\n\t" \ 15 | "movl %%edx,%2" \ 16 | : \ 17 | : "i"((short)(0x8000 + (dpl << 13) + (type << 8))), \ 18 | "o"(*((char *)(gate_addr))), "o"(*(4 + (char *)(gate_addr))), \ 19 | "d"((char *)(addr)), "a"(0x00080000)) 20 | 21 | #define set_intr_gate(n, addr) _set_gate(&idt[n], 14, 0, addr) 22 | 23 | #define set_trap_gate(n, addr) _set_gate(&idt[n], 15, 0, addr) 24 | 25 | #define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr) 26 | #endif -------------------------------------------------------------------------------- /demos/mm/lan_main.c: -------------------------------------------------------------------------------- 1 | extern void write_char(char ch); 2 | extern void open_a20(); 3 | extern void init_8259A(); 4 | extern void timer_interrupt(); 5 | extern void init_latch(); 6 | extern void set_sti(); 7 | extern void assign_cr3_cr0(unsigned long); 8 | 9 | #include "gate_tool.h" 10 | 11 | void check_a20_valid() { 12 | unsigned char *p0 = 0x0; 13 | unsigned char *p1 = 0x100000; 14 | for (unsigned char i = 0; i < 10; ++i) { 15 | *p0 = i; 16 | if (*p0 != *p1) { 17 | write_char('b'); 18 | break; 19 | } else { 20 | write_char('e'); 21 | } 22 | } 23 | } 24 | 25 | void setup_paging() { 26 | unsigned long *pg_dir = 0x8000; // lan_os最多不能超过8k 27 | unsigned long *pg0 = (unsigned long)(pg_dir) + 0x1000; 28 | unsigned long *pg1 = (unsigned long)(pg0) + 0x1000; 29 | unsigned long *pg2 = (unsigned long)(pg1) + 0x1000; 30 | unsigned long *pg3 = (unsigned long)(pg2) + 0x1000; 31 | pg_dir[0] = (unsigned long)(pg0) + 7; 32 | pg_dir[1] = (unsigned long)(pg1) + 7; 33 | pg_dir[2] = (unsigned long)(pg2) + 7; 34 | pg_dir[3] = (unsigned long)(pg3) + 7; 35 | for (int i = 0; i < 0x1000; ++i) { 36 | pg0[i] = (i << 12) + 7; 37 | } 38 | assign_cr3_cr0(pg_dir); 39 | } 40 | 41 | void lan_main() { 42 | write_char('L'); 43 | write_char('O'); 44 | write_char('V'); 45 | write_char('E'); 46 | write_char('M'); 47 | write_char('M'); 48 | open_a20(); 49 | check_a20_valid(); 50 | setup_paging(); 51 | init_latch(); 52 | init_8259A(); 53 | set_intr_gate(0x20, &timer_interrupt); 54 | set_sti(); 55 | while (1) 56 | ; 57 | } 58 | 59 | void do_timer() { 60 | write_char('T'); 61 | write_char('I'); 62 | write_char('M'); 63 | write_char('E'); 64 | write_char('R'); 65 | } 66 | -------------------------------------------------------------------------------- /demos/mm/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=17 skip=8 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=18 conv=notrunc 6 | link: head lan_main boot 7 | ld -m elf_i386 -T n.lds -o lan_os head.o lan_main.o 8 | head: 9 | nasm -felf32 -o head.o head.s 10 | lan_main: 11 | gcc -m32 -c lan_main.c 12 | boot: 13 | nasm -o boot.bin boot.s -l boot.lst 14 | clean: 15 | rm lan_os lan_main.o head.o boot.bin boot.lst a.img a.vfd 16 | 17 | -------------------------------------------------------------------------------- /demos/mm/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/mm/readme.md: -------------------------------------------------------------------------------- 1 | # 梳理linux0.12知识点系列 2 | # 之 3 | # 内存管理初始化 4 | 5 | ## 背景 6 | 7 | -------------------------------------------------------------------------------- /demos/pic/a20notopen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/pic/a20notopen.png -------------------------------------------------------------------------------- /demos/pic/cpp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/pic/cpp.png -------------------------------------------------------------------------------- /demos/pic/exec.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/pic/exec.gif -------------------------------------------------------------------------------- /demos/pic/init_8259a_succ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/pic/init_8259a_succ.png -------------------------------------------------------------------------------- /demos/pic/loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/pic/loop.png -------------------------------------------------------------------------------- /demos/pic/ls.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/pic/ls.gif -------------------------------------------------------------------------------- /demos/pic/multitask.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/pic/multitask.gif -------------------------------------------------------------------------------- /demos/pic/opena20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/pic/opena20.png -------------------------------------------------------------------------------- /demos/pic/orange1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/pic/orange1.png -------------------------------------------------------------------------------- /demos/pic/orange2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/pic/orange2.png -------------------------------------------------------------------------------- /demos/pic/orange3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/pic/orange3.png -------------------------------------------------------------------------------- /demos/print_str_demo/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 61 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+SYSLEN ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | jnc ok_load 16 | jmp $ 17 | 18 | ok_load: 19 | cli 20 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 21 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 22 | xor ax, ax 23 | mov es, ax 24 | mov cx, 0x3000 ;这时拷贝 0x3000*2(字节)/512=48(扇区) 25 | sub si, si 26 | sub di, di 27 | cld ;df = 0 rep movsw是正向的 28 | rep movsw 29 | mov ax, 0x0 ;重新恢复ds指向0x0 30 | mov ds, ax 31 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 32 | mov ax, 0x0001 33 | lmsw ax 34 | jmp dword 8:0 35 | gdt: 36 | dw 0, 0, 0, 0 ;第一个描述符,没有用 37 | dw 0x07ff ;代码段 从0地址开始 38 | dw 0x0000 39 | dw 0x9a00 40 | dw 0x00c0 41 | dw 0x07ff ;数据段 从0地址开始 42 | dw 0x0000 43 | dw 0x9200 44 | dw 0x00c0 45 | 46 | 47 | gdt_48: 48 | dw 0x7ff ;2048/8=256个描述符 49 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 50 | 51 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 52 | times 510 - ($-$$) db 0 53 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/print_str_demo/fork.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | #include "sched.h" 3 | 4 | extern void first_return_from_kernel(); 5 | unsigned long get_data_base(struct task_struct *s) { 6 | unsigned long ret = (s->ldt[2].a) >> 16; 7 | ret |= (s->ldt[2].b & 0xff) << 16; 8 | ret |= s->ldt[2].b & 0xff000000; 9 | return ret; 10 | } 11 | 12 | int copy_mem(int nr, struct task_struct *p) { 13 | unsigned long old_data_base, new_data_base, data_limit; 14 | unsigned long new_code_base, code_limit; 15 | 16 | code_limit = get_limit(0x0f); 17 | data_limit = get_limit(0x17); 18 | old_data_base = get_data_base(current); 19 | new_data_base = new_code_base = nr * TASK_SIZE + PG_NUM * 4 * 1024 * 1024; 20 | p->start_code = new_code_base; 21 | set_base(&(p->ldt[1]), new_code_base); 22 | set_base(&(p->ldt[2]), new_data_base); 23 | if (copy_page_tables(old_data_base, new_data_base, data_limit)) { 24 | // todo 25 | // free_page_tables 26 | } 27 | return 0; 28 | } 29 | 30 | int find_empty_process() { return ++last_pid; } 31 | 32 | int copy_process(long eax, long ebp, long edi, long esi, long gs, long none, 33 | long ebx, long ecx, long edx, long orig_eax, long fs, long es, 34 | long ds, long eip, long cs, long eflags, long esp, long ss) { 35 | struct task_struct *p = (struct task_struct *)get_free_page(); 36 | 37 | if (!p) { 38 | // todo 39 | } 40 | *p = *current; 41 | p->state = TASK_UNINTERRUPTIBLE; 42 | p->pid = eax; 43 | task[last_pid] = p; 44 | long *krnstack = (long *)(PAGE_SIZE + (long)p); 45 | *(--krnstack) = ss; 46 | *(--krnstack) = esp; 47 | *(--krnstack) = eflags; 48 | *(--krnstack) = cs; 49 | *(--krnstack) = eip; 50 | *(--krnstack) = first_return_from_kernel; 51 | *(--krnstack) = 0; // eax 52 | *(--krnstack) = ebx; 53 | *(--krnstack) = ecx; 54 | *(--krnstack) = edx; 55 | *(--krnstack) = ebp; 56 | *(--krnstack) = esi; 57 | *(--krnstack) = edi; 58 | *(--krnstack) = es & 0xffff; 59 | *(--krnstack) = ds & 0xffff; 60 | *(--krnstack) = fs & 0xffff; 61 | *(--krnstack) = gs & 0xffff; 62 | p->kernel_stack = krnstack; 63 | if (copy_mem(last_pid, p)) { 64 | // todo: 65 | // abort 66 | } 67 | set_ldt_desc(gdt + last_pid + FIRST_LDT_ENTRY, &(p->ldt)); 68 | p->state = TASK_RUNNING; 69 | return 1; 70 | } 71 | -------------------------------------------------------------------------------- /demos/print_str_demo/gate_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef GATE_TOOL_H 2 | #define GATE_TOOL_H 3 | 4 | #include "sched.h" 5 | 6 | #define _set_gate(gate_addr, type, dpl, addr) \ 7 | __asm__( \ 8 | "movw %%dx,%%ax\n\t" \ 9 | "movw %0,%%dx\n\t" \ 10 | "movl %%eax,%1\n\t" \ 11 | "movl %%edx,%2" \ 12 | : \ 13 | : "i"((short)(0x8000 + (dpl << 13) + (type << 8))), \ 14 | "o"(*((char *)(gate_addr))), "o"(*(4 + (char *)(gate_addr))), \ 15 | "d"((char *)(addr)), "a"(0x00080000)) 16 | 17 | #define set_intr_gate(n, addr) _set_gate(&idt[n], 14, 0, addr) 18 | 19 | #define set_trap_gate(n, addr) _set_gate(&idt[n], 15, 0, addr) 20 | 21 | #define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr) 22 | #endif -------------------------------------------------------------------------------- /demos/print_str_demo/intel_err_handle.c: -------------------------------------------------------------------------------- 1 | extern void print_str(char *s); 2 | 3 | void e0() { print_str("e0"); } 4 | 5 | void e1() { print_str("e1"); } 6 | 7 | void e2() { print_str("e2"); } 8 | 9 | void e3() { print_str("e3"); } 10 | 11 | void e4() { print_str("e4"); } 12 | 13 | void e5() { print_str("e5"); } 14 | 15 | void e6() { print_str("e6"); } 16 | 17 | void e7() { print_str("e7"); } 18 | 19 | void e8() { print_str("e8"); } 20 | 21 | void e9() { print_str("e9"); } 22 | 23 | void e10() { print_str("e10"); } 24 | 25 | void e11() { print_str("e11"); } 26 | 27 | void e12() { print_str("e12"); } 28 | 29 | void e13() { print_str("e13"); } 30 | 31 | void e15() { print_str("e15"); } 32 | 33 | void e16() { print_str("e16"); } 34 | -------------------------------------------------------------------------------- /demos/print_str_demo/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=62 skip=8 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=63 conv=notrunc 6 | link: head lan_main boot 7 | ld -m elf_i386 -T n.lds -o lan_os head.o lan_main.o sys_call.o intel_err_handle.o sched.o fork.o mm.o print_str.o 8 | head: 9 | nasm -felf32 -o head.o head.s 10 | lan_main: 11 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c sys_call.c intel_err_handle.c sched.c fork.c mm.c print_str.c 12 | boot: 13 | nasm -o boot.bin boot.s -l boot.lst 14 | clean: 15 | rm lan_os lan_main.o sys_call.o intel_err_handle.o head.o sched.o fork.o mm.o print_str.o boot.bin boot.lst a.img a.vfd 16 | -------------------------------------------------------------------------------- /demos/print_str_demo/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef MM_H 2 | #define MM_H 3 | 4 | #define PAGE_SIZE 4096 5 | #define PAGE_DIR 0x8000 6 | #define PG_NUM 16 7 | 8 | #define LOW_MEM 0x100000 9 | #define MAP_NR(addr) (((addr)-LOW_MEM) >> 12) 10 | #define invalidate() __asm__("movl %%eax,%%cr3" ::"a"(PAGE_DIR)) 11 | 12 | extern void mm_init(); 13 | extern unsigned long get_free_page(); 14 | extern int copy_page_tables(unsigned long from, unsigned long to, long size); 15 | 16 | #endif -------------------------------------------------------------------------------- /demos/print_str_demo/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/print_str_demo/print_str.c: -------------------------------------------------------------------------------- 1 | #define MAX_L 25 2 | #define SCREEN_LEN 2000 3 | char screen_buff[SCREEN_LEN]; 4 | int cur_l = 0; 5 | extern void write_char(char ch, int pos); 6 | void validate_screen() { 7 | for (int i = 0; i < SCREEN_LEN; ++i) { 8 | write_char(screen_buff[i], i); 9 | } 10 | } 11 | 12 | void print_str(char *s) { 13 | if (cur_l >= MAX_L) { 14 | for (int i = 0; i < 24; ++i) { 15 | for (int j = 0; j < 80; ++j) { 16 | screen_buff[i * 80 + j] = screen_buff[(i + 1) * 80 + j]; 17 | } 18 | } 19 | for (int j = 0; j < 80; ++j) { 20 | screen_buff[24 * 80 + j] = 0; 21 | } 22 | cur_l = MAX_L - 1; 23 | } 24 | int y = cur_l; 25 | int x = 0; 26 | while (s[x] != 0) { 27 | screen_buff[y * 80 + x] = s[x]; 28 | x++; 29 | } 30 | cur_l++; 31 | validate_screen(); 32 | } 33 | -------------------------------------------------------------------------------- /demos/print_str_demo/sched.c: -------------------------------------------------------------------------------- 1 | #include "sched.h" 2 | #include "mm.h" 3 | 4 | struct task_struct *task[NR_TASKS]; 5 | struct task_struct init_task; 6 | struct task_struct *current = (struct task_struct *)&init_task; 7 | long last_pid = -1; 8 | long last_sched_i = 0; 9 | 10 | extern void switch_to(unsigned long, struct task_struct *); 11 | extern void set_tss0_esp0(unsigned long); 12 | extern void get_esp0_when_switch(unsigned long *); 13 | extern void krn_stk0(); 14 | 15 | void sched_init() { 16 | for (int i = 0; i < NR_TASKS; ++i) { 17 | task[i] = 0; 18 | } 19 | init_task.state = TASK_UNINTERRUPTIBLE; 20 | init_task.pid = ++last_pid; 21 | init_task.ldt[0].a = 0; 22 | init_task.ldt[0].b = 0; 23 | init_task.ldt[1].a = 0x3ff; 24 | init_task.ldt[1].b = 0xc0fa00; 25 | init_task.ldt[2].a = 0x3ff; 26 | init_task.ldt[2].b = 0xc0f200; 27 | set_ldt_desc(gdt + 0 + FIRST_LDT_ENTRY, &(init_task.ldt)); 28 | task[0] = &init_task; 29 | lldt(0); 30 | init_task.state = TASK_RUNNING; 31 | } 32 | 33 | void schedule() { 34 | int i = last_sched_i; 35 | while (1) { 36 | ++i; 37 | i %= NR_TASKS; 38 | if (task[i]) { 39 | if (current->pid != i) { 40 | if (task[i]->state == TASK_RUNNING) { 41 | last_sched_i = i; 42 | if (0 == i) { 43 | set_tss0_esp0( 44 | krn_stk0); // 0任务的内核栈是写死的,不能用task[i])+PAGE_SIZE来计算 45 | } else { 46 | set_tss0_esp0((unsigned long)(task[i]) + 47 | PAGE_SIZE); //给切换栈机制搭桥 48 | } 49 | unsigned long esp0 = 0; 50 | get_esp0_when_switch(&esp0); 51 | current->kernel_stack = esp0; 52 | current = task[i]; 53 | switch_to(_LDT(i), task[i]); 54 | return; 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | void do_timer(unsigned long cs) { 62 | if (0x8 == cs) { 63 | } else if (0xf == cs) { 64 | schedule(); 65 | } else { 66 | } 67 | } -------------------------------------------------------------------------------- /demos/print_str_demo/sys_call.c: -------------------------------------------------------------------------------- 1 | typedef int (*sys_call)(); 2 | extern void print_str(char *s); 3 | 4 | unsigned char get_fs_byte(const char *addr) { 5 | unsigned register char _v; 6 | __asm__("movb %%fs:%1,%0" : "=r"(_v) : "m"(*addr)); 7 | return _v; 8 | } 9 | 10 | int _test_sys_call() { 11 | print_str("ggg"); 12 | return 0; 13 | } 14 | 15 | int _test_sys_call1() { return 0; } 16 | 17 | int _test_sys_call2() { 18 | print_str("hhh"); 19 | return 0; 20 | } 21 | 22 | int _sys_print_str(char *msg) { 23 | char buf[64]; 24 | for (int j = 0; j < 64; ++j) { 25 | buf[j] = 0; 26 | } 27 | int i = 0; 28 | while (1) { 29 | buf[i] = get_fs_byte(msg + i); 30 | if (buf[i] == 0) { 31 | break; 32 | } 33 | i++; 34 | } 35 | print_str(buf); 36 | return 0; 37 | } 38 | 39 | int _sys_print_num(int num) { 40 | char buf[64]; 41 | int index = 0; 42 | for (int i = 0; i < 64; ++i) { 43 | buf[i] = 0; 44 | } 45 | if (num == 0) { 46 | buf[index++] = '0'; 47 | } else if (num < 0) { 48 | num = -num; 49 | buf[index++] = '-'; 50 | } 51 | char tmp[64]; 52 | int index_tmp = 0; 53 | while (num > 0) { 54 | tmp[index_tmp++] = num % 10 + '0'; 55 | num /= 10; 56 | } 57 | for (int i = index_tmp - 1; i >= 0; --i) { 58 | buf[index++] = tmp[i]; 59 | } 60 | print_str(buf); 61 | return 0; 62 | } 63 | 64 | extern void sys_fork(); 65 | extern void sys_print_str(); 66 | extern void sys_print_num(); 67 | 68 | extern sys_call sys_call_table[] = {_test_sys_call, sys_fork, 69 | _test_sys_call1, _test_sys_call2, 70 | sys_print_str, sys_print_num}; -------------------------------------------------------------------------------- /demos/protect_mode_cpp_demo/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 32] 2 | 3 | LATCH equ 11930 4 | SCRN_SEL equ 0x18 5 | TSS0_SEL equ 0x20 6 | LDT0_SEL equ 0x28 7 | TSS1_SEL equ 0x30 8 | LDT1_SEL equ 0x38 9 | global write_char 10 | extern lan_main 11 | start_up32: 12 | mov dword eax, 0x10 ;这时候使用的0x10还是loader.asm中定义的,虽然boot.asm之后定义的0x10描述符与之完全相同 13 | mov ds, ax 14 | lss esp, [init_stack];接下来要使用call指令,所以这里要初始化好栈 15 | call setup_gdt 16 | call setup_idt 17 | 18 | mov eax, 0x10 ;加载完gdt之后重新加载所有的段寄存器,因为要更新段寄存器中段描述符的缓存(不可见部分)参见《linux内核完全剖析》94页 19 | mov ds, ax 20 | mov es, ax 21 | mov fs, ax 22 | mov gs, ax 23 | 24 | lss esp, [init_stack];因为ds可能更新了(这个例子中实际上没有),所以要重新加载ss 25 | push dword lan_main 26 | ret 27 | 28 | setup_gdt: 29 | lgdt [lgdt_48] 30 | ret 31 | 32 | setup_idt: 33 | lea edx, [ignore_int] 34 | mov eax, dword 0x00080000 35 | mov ax, dx 36 | mov dx, 0x8e00 37 | lea edi, [idt] 38 | mov ecx, 256 39 | rp_idt: 40 | mov dword [edi], eax 41 | mov dword [edi+4], edx 42 | add dword edi, 8 43 | dec ecx 44 | jne rp_idt 45 | lidt [lidt_48] 46 | ret 47 | 48 | write_char: 49 | push gs 50 | push dword ebx 51 | mov ebx, SCRN_SEL 52 | mov gs, bx 53 | mov bx, [src_loc] 54 | shl ebx, 1 55 | push dword eax 56 | mov eax, edi 57 | mov byte [gs:ebx], al 58 | pop dword eax 59 | shr ebx, 1 60 | inc dword ebx 61 | cmp dword ebx, 2000 62 | jb not_equ ;jb : jump if below 63 | mov dword ebx, 0 64 | not_equ: 65 | mov dword [src_loc], ebx 66 | pop dword ebx 67 | pop gs 68 | ret 69 | 70 | align 4 71 | ignore_int: 72 | iret 73 | 74 | current: dd 0 75 | src_loc: dd 0 76 | 77 | align 4 78 | lidt_48: 79 | dw 256*8-1 80 | dd idt 81 | lgdt_48: 82 | dw end_gdt-gdt-1 83 | dd gdt 84 | 85 | align 8 86 | idt: 87 | times 256 dq 0 88 | gdt: 89 | dq 0x0000000000000000 90 | dq 0x00c09a00000007ff ;0x08 这两个段描述符和loader.asm中的代码段数据段是一样的 91 | dq 0x00c09200000007ff ;0x10 92 | dq 0x00c0920b80000002 ;0x18 显存数据段 93 | end_gdt: 94 | 95 | times 128 dd 0 96 | init_stack: ;从这里开始是一个48位操作数 97 | dd init_stack ;32位代表初始的esp 98 | dw 0x10 ;16位栈的段选择符,lss之后会加载到ss中 99 | -------------------------------------------------------------------------------- /demos/protect_mode_cpp_demo/lan_main.cpp: -------------------------------------------------------------------------------- 1 | extern "C" void write_char(char ch); 2 | class L { 3 | public: 4 | L() { write_char('L'); } 5 | }; 6 | class O : public L { 7 | public: 8 | O() { write_char('O'); } 9 | }; 10 | 11 | class V : public O { 12 | public: 13 | V() { write_char('V'); } 14 | }; 15 | 16 | class E : public V { 17 | public: 18 | E() { write_char('E'); } 19 | }; 20 | 21 | extern "C" void lan_main() { 22 | E e; 23 | while (1) 24 | ; 25 | } -------------------------------------------------------------------------------- /demos/protect_mode_cpp_demo/loader.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 17 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+SYSLEN ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | jnc ok_load 16 | jmp $ 17 | 18 | ok_load: 19 | cli 20 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 21 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 22 | xor ax, ax 23 | mov es, ax 24 | mov cx, 0x1000 25 | sub si, si 26 | sub di, di 27 | cld ;df = 0 rep movsw是正向的 28 | rep movsw 29 | mov ax, 0x0 ;重新恢复ds指向0x0 30 | mov ds, ax 31 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 32 | mov ax, 0x0001 33 | lmsw ax 34 | jmp dword 8:0 35 | gdt: 36 | dw 0, 0, 0, 0 ;第一个描述符,没有用 37 | dw 0x07ff ;代码段 从0地址开始 38 | dw 0x0000 39 | dw 0x9a00 40 | dw 0x00c0 41 | dw 0x07ff ;数据段 从0地址开始 42 | dw 0x0000 43 | dw 0x9200 44 | dw 0x00c0 45 | 46 | 47 | gdt_48: 48 | dw 0x7ff ;2048/8=256个描述符 49 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 50 | 51 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 52 | times 510 - ($-$$) db 0 53 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/protect_mode_cpp_demo/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=loader.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=17 skip=4096 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=18 conv=notrunc 6 | link: boot lan_main loader 7 | ld -T n.lds -o lan_os boot.o lan_main.o 8 | boot: 9 | nasm -felf64 -o boot.o boot.s 10 | lan_main: 11 | gcc -c lan_main.cpp 12 | loader: 13 | nasm -o loader.bin loader.s -l loader.lst 14 | clean: 15 | rm lan_os lan_main.o boot.o loader.bin loader.lst a.img a.vfd 16 | 17 | -------------------------------------------------------------------------------- /demos/protect_mode_cpp_demo/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/protect_mode_demo/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 17 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+SYSLEN ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | jnc ok_load 16 | jmp $ 17 | 18 | ok_load: 19 | cli 20 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 21 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 22 | xor ax, ax 23 | mov es, ax 24 | mov cx, 0x1000 25 | sub si, si 26 | sub di, di 27 | cld ;df = 0 rep movsw是正向的 28 | rep movsw 29 | mov ax, 0x0 ;重新恢复ds指向0x0 30 | mov ds, ax 31 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 32 | mov ax, 0x0001 33 | lmsw ax 34 | jmp dword 8:0 35 | gdt: 36 | dw 0, 0, 0, 0 ;第一个描述符,没有用 37 | dw 0x07ff ;代码段 从0地址开始 38 | dw 0x0000 39 | dw 0x9a00 40 | dw 0x00c0 41 | dw 0x07ff ;数据段 从0地址开始 42 | dw 0x0000 43 | dw 0x9200 44 | dw 0x00c0 45 | 46 | 47 | gdt_48: 48 | dw 0x7ff ;2048/8=256个描述符 49 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 50 | 51 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 52 | times 510 - ($-$$) db 0 53 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/protect_mode_demo/header.s: -------------------------------------------------------------------------------- 1 | [BITS 32] 2 | 3 | LATCH equ 11930 4 | SCRN_SEL equ 0x18 5 | TSS0_SEL equ 0x20 6 | LDT0_SEL equ 0x28 7 | TSS1_SEL equ 0x30 8 | LDT1_SEL equ 0x38 9 | global write_char 10 | extern lan_main 11 | start_up32: 12 | mov dword eax, 0x10 ;这时候使用的0x10还是loader.asm中定义的,虽然boot.asm之后定义的0x10描述符与之完全相同 13 | mov ds, ax 14 | lss esp, [init_stack];接下来要使用call指令,所以这里要初始化好栈 15 | call setup_gdt 16 | call setup_idt 17 | 18 | mov eax, 0x10 ;加载完gdt之后重新加载所有的段寄存器,因为要更新段寄存器中段描述符的缓存(不可见部分)参见《linux内核完全剖析》94页 19 | mov ds, ax 20 | mov es, ax 21 | mov fs, ax 22 | mov gs, ax 23 | 24 | lss esp, [init_stack];因为ds可能更新了(这个例子中实际上没有),所以要重新加载ss 25 | push dword lan_main 26 | ret 27 | 28 | setup_gdt: 29 | lgdt [lgdt_48] 30 | ret 31 | 32 | setup_idt: 33 | lea edx, [ignore_int] 34 | mov eax, dword 0x00080000 35 | mov ax, dx 36 | mov dx, 0x8e00 37 | lea edi, [idt] 38 | mov ecx, 256 39 | rp_idt: 40 | mov dword [edi], eax 41 | mov dword [edi+4], edx 42 | add dword edi, 8 43 | dec ecx 44 | jne rp_idt 45 | lidt [lidt_48] 46 | ret 47 | 48 | write_char: 49 | push gs 50 | push dword ebx 51 | mov ebx, SCRN_SEL 52 | mov gs, bx 53 | mov bx, [src_loc] 54 | shl ebx, 1 55 | push dword eax 56 | mov eax, edi 57 | mov byte [gs:ebx], al 58 | pop dword eax 59 | shr ebx, 1 60 | inc dword ebx 61 | cmp dword ebx, 2000 62 | jb not_equ ;jb : jump if below 63 | mov dword ebx, 0 64 | not_equ: 65 | mov dword [src_loc], ebx 66 | pop dword ebx 67 | pop gs 68 | ret 69 | 70 | align 4 71 | ignore_int: 72 | iret 73 | 74 | current: dd 0 75 | src_loc: dd 0 76 | 77 | align 4 78 | lidt_48: 79 | dw 256*8-1 80 | dd idt 81 | lgdt_48: 82 | dw end_gdt-gdt-1 83 | dd gdt 84 | 85 | align 8 86 | idt: 87 | times 256 dq 0 88 | gdt: 89 | dq 0x0000000000000000 90 | dq 0x00c09a00000007ff ;0x08 这两个段描述符和loader.asm中的代码段数据段是一样的 91 | dq 0x00c09200000007ff ;0x10 92 | dq 0x00c0920b80000002 ;0x18 显存数据段 93 | end_gdt: 94 | 95 | times 128 dd 0 96 | init_stack: ;从这里开始是一个48位操作数 97 | dd init_stack ;32位代表初始的esp 98 | dw 0x10 ;16位栈的段选择符,lss之后会加载到ss中 99 | -------------------------------------------------------------------------------- /demos/protect_mode_demo/lan_main.c: -------------------------------------------------------------------------------- 1 | extern void write_char(char ch); 2 | void lan_main() { 3 | write_char('L'); 4 | write_char('O'); 5 | write_char('V'); 6 | write_char('E'); 7 | while (1) 8 | ; 9 | } 10 | -------------------------------------------------------------------------------- /demos/protect_mode_demo/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=17 skip=4096 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=18 conv=notrunc 6 | link: header lan_main boot 7 | ld -T n.lds -o lan_os header.o lan_main.o 8 | header: 9 | nasm -felf64 -o header.o header.s 10 | lan_main: 11 | gcc -g -c lan_main.c 12 | boot: 13 | nasm -o boot.bin boot.s -l boot.lst 14 | clean: 15 | rm lan_os lan_main.o header.o boot.bin boot.lst a.img a.vfd 16 | 17 | -------------------------------------------------------------------------------- /demos/protect_mode_demo/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/shell_demo/bin/shell/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=lan_sh bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o 5 | lan_main: 6 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm lan_sh test_elf lan_main.o 9 | cp: 10 | cp lan_sh ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/shell_demo/bin/shell/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/shell_demo/bin/test/lan_main.c: -------------------------------------------------------------------------------- 1 | #define _syscall1(type, name, atype, a) \ 2 | type name(atype a) { \ 3 | long __res; \ 4 | __asm__ volatile("int $0x80" \ 5 | : "=a"(__res) \ 6 | : "0"(__NR_##name), "b"((long)(a))); \ 7 | if (__res >= 0) return (type)__res; \ 8 | return -1; \ 9 | } 10 | 11 | int s_print_str(char*); 12 | int s_print_num(int); 13 | 14 | void lan_main() { 15 | s_print_str("I am a test executable file !"); 16 | s_print_str("I can print a number."); 17 | s_print_num(222); 18 | while (1) 19 | ; 20 | } 21 | #define __NR_s_print_str 4 22 | #define __NR_s_print_num 5 23 | _syscall1(int, s_print_str, char*, msg) _syscall1(int, s_print_num, int, num) -------------------------------------------------------------------------------- /demos/shell_demo/bin/test/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=test_elf of=test bs=512 skip=8 conv=notrunc 3 | link: lan_main 4 | ld -m elf_i386 -T n.lds -o test_elf lan_main.o 5 | lan_main: 6 | gcc -m32 -g -fno-stack-protector -fno-pie -c lan_main.c 7 | clean: 8 | rm test test_elf lan_main.o 9 | cp: 10 | cp test ../../root_fs/ 11 | -------------------------------------------------------------------------------- /demos/shell_demo/bin/test/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/shell_demo/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 72 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+17 ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | mov ax, 01220h 16 | mov es, ax 17 | mov cx, 0001h 18 | jnc ok_load1 19 | jmp $ 20 | 21 | ok_load1: 22 | mov ax, 0200h+18 ;ah 读扇区功能号2 al读扇区数量 18 23 | xor dh, 1 24 | and dh, 1 25 | int 013h 26 | mov ax, es 27 | add ax, 0240h 28 | mov es, ax 29 | jnc ok_load2 30 | jmp $ 31 | 32 | ok_load2: 33 | test dh, dh 34 | jz dontaddch 35 | add ch, 1 36 | dontaddch: 37 | mov ax, [index] 38 | sub ax, 1 39 | mov [index], ax 40 | test ax, ax 41 | jnz ok_load1 42 | 43 | ok_load: 44 | cli 45 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 46 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 47 | xor ax, ax 48 | mov es, ax 49 | mov cx, 0x3000 ;这时拷贝 0x3000*2(字节)/512=48(扇区) 50 | sub si, si 51 | sub di, di 52 | cld ;df = 0 rep movsw是正向的 53 | rep movsw 54 | mov ax, 0x0 ;重新恢复ds指向0x0 55 | mov ds, ax 56 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 57 | mov ax, 0x0001 58 | lmsw ax 59 | jmp dword 8:0 60 | index: 61 | dw 63 ;这里63是极限 位置末尾是0x9fe00 接近显示缓冲区0xA0000 62 | gdt: 63 | dw 0, 0, 0, 0 ;第一个描述符,没有用 64 | dw 0x07ff ;代码段 从0地址开始 65 | dw 0x0000 66 | dw 0x9a00 67 | dw 0x00c0 68 | dw 0x07ff ;数据段 从0地址开始 69 | dw 0x0000 70 | dw 0x9200 71 | dw 0x00c0 72 | 73 | gdt_48: 74 | dw 0x7ff ;2048/8=256个描述符 75 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 76 | 77 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 78 | times 510 - ($-$$) db 0 79 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/shell_demo/fork.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | #include "sched.h" 3 | 4 | extern void panic(char *msg); 5 | 6 | extern void first_return_from_kernel(); 7 | unsigned long get_data_base(struct task_struct *s) { 8 | unsigned long ret = (s->ldt[2].a) >> 16; 9 | ret |= (s->ldt[2].b & 0xff) << 16; 10 | ret |= s->ldt[2].b & 0xff000000; 11 | return ret; 12 | } 13 | 14 | int copy_mem(int nr, struct task_struct *p) { 15 | unsigned long old_data_base, new_data_base, data_limit; 16 | unsigned long new_code_base, code_limit; 17 | 18 | code_limit = get_limit(0x0f); 19 | data_limit = get_limit(0x17); 20 | old_data_base = get_data_base(current); 21 | new_data_base = new_code_base = nr * TASK_SIZE + PG_NUM * 4 * 1024 * 1024; 22 | p->start_code = new_code_base; 23 | set_base(&(p->ldt[1]), new_code_base); 24 | set_base(&(p->ldt[2]), new_data_base); 25 | if (copy_page_tables(old_data_base, new_data_base, data_limit)) { 26 | // todo 27 | // free_page_tables 28 | panic("copy page tables failed."); 29 | } 30 | return 0; 31 | } 32 | 33 | int find_empty_process() { 34 | for (int i = 0; i < NR_TASKS; ++i) { 35 | if (!task_used[i]) { 36 | task_used[i] = 1; 37 | return i; 38 | } 39 | } 40 | return -1; 41 | } 42 | 43 | int copy_process(long eax, long ebp, long edi, long esi, long gs, long none, 44 | long ebx, long ecx, long edx, long orig_eax, long fs, long es, 45 | long ds, long eip, long cs, long eflags, long esp, long ss) { 46 | if (eax < 0) { 47 | panic("no emtpy task."); 48 | } 49 | struct task_struct *p = (struct task_struct *)get_free_page(); 50 | 51 | if (!p) { 52 | // todo 53 | } 54 | *p = *current; 55 | p->state = TASK_UNINTERRUPTIBLE; 56 | p->pid = eax; 57 | task[eax] = p; 58 | long *krnstack = (long *)(PAGE_SIZE + (long)p); 59 | *(--krnstack) = ss; 60 | *(--krnstack) = esp; 61 | *(--krnstack) = eflags; 62 | *(--krnstack) = cs; 63 | *(--krnstack) = eip; 64 | *(--krnstack) = first_return_from_kernel; 65 | *(--krnstack) = 0; // eax 66 | *(--krnstack) = ebx; 67 | *(--krnstack) = ecx; 68 | *(--krnstack) = edx; 69 | *(--krnstack) = ebp; 70 | *(--krnstack) = esi; 71 | *(--krnstack) = edi; 72 | *(--krnstack) = es & 0xffff; 73 | *(--krnstack) = ds & 0xffff; 74 | *(--krnstack) = fs & 0xffff; 75 | *(--krnstack) = gs & 0xffff; 76 | p->kernel_stack = krnstack; 77 | if (copy_mem(eax, p)) { 78 | // todo: 79 | // abort 80 | } 81 | set_ldt_desc(gdt + eax + FIRST_LDT_ENTRY, &(p->ldt)); 82 | p->state = TASK_RUNNING; 83 | return 1; 84 | } 85 | -------------------------------------------------------------------------------- /demos/shell_demo/fs_patch_tool/patch.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const file_list = [ 4 | 'hello_fs', 5 | 'test', 6 | 'lan_sh', 7 | ]; 8 | 9 | function zero_buffer(size) { 10 | let ret = Buffer.alloc(size); 11 | for (let i = 0; i < size; ++i) { 12 | ret[i] = 0; 13 | } 14 | return ret; 15 | } 16 | 17 | async function main() { 18 | const vfd_path = `${__dirname}/../a.vfd`; 19 | const vfd_content = fs.readFileSync(vfd_path); 20 | console.log('vfd_content length : ', vfd_content.length); 21 | const vfd_length = vfd_content.length; 22 | let fs_header = zero_buffer(4); 23 | const file_cnt = file_list.length; 24 | fs_header.writeInt32LE(file_cnt); 25 | let file_buffer = zero_buffer(0); 26 | for (let i = 0; i < file_cnt; ++i) { 27 | const path = `${__dirname}/../root_fs/${file_list[i]}`; 28 | const content = fs.readFileSync(path); 29 | const content_length = content.length; 30 | console.log(`path ${path} : ${content_length}`); 31 | const file_length_buffer = zero_buffer(4); 32 | const file_name_buffer = zero_buffer(8); 33 | file_length_buffer.writeInt32LE(content_length); 34 | Buffer.from(file_list[i]).copy(file_name_buffer); 35 | fs_header = Buffer.concat([fs_header, file_length_buffer, file_name_buffer]); 36 | const file_pad = zero_buffer(20 * 1024 - content_length); 37 | file_buffer = Buffer.concat([file_buffer, content, file_pad]); 38 | } 39 | const fs_header_pad = zero_buffer(124 - fs_header.length); 40 | fs_header = Buffer.concat([fs_header, fs_header_pad]); 41 | console.log('fs_header length : ', fs_header.length); 42 | const start = 0x5df84; // 0x90000-200k-124 在内存中的位置应该是0x5df84-0x200+0x10000=0x6dd84 43 | const p0 = vfd_content.slice(0, start); 44 | const p1 = Buffer.concat([fs_header, file_buffer]); 45 | const p2 = vfd_content.slice(start + p1.length); 46 | const final_buffer = Buffer.concat([p0, p1, p2]); 47 | fs.writeFileSync(vfd_path, final_buffer); 48 | process.exit(); 49 | } 50 | main(); -------------------------------------------------------------------------------- /demos/shell_demo/gate_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef GATE_TOOL_H 2 | #define GATE_TOOL_H 3 | 4 | #include "sched.h" 5 | 6 | #define _set_gate(gate_addr, type, dpl, addr) \ 7 | __asm__( \ 8 | "movw %%dx,%%ax\n\t" \ 9 | "movw %0,%%dx\n\t" \ 10 | "movl %%eax,%1\n\t" \ 11 | "movl %%edx,%2" \ 12 | : \ 13 | : "i"((short)(0x8000 + (dpl << 13) + (type << 8))), \ 14 | "o"(*((char *)(gate_addr))), "o"(*(4 + (char *)(gate_addr))), \ 15 | "d"((char *)(addr)), "a"(0x00080000)) 16 | 17 | #define set_intr_gate(n, addr) _set_gate(&idt[n], 14, 0, addr) 18 | 19 | #define set_trap_gate(n, addr) _set_gate(&idt[n], 15, 0, addr) 20 | 21 | #define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr) 22 | #endif -------------------------------------------------------------------------------- /demos/shell_demo/intel_err_handle.c: -------------------------------------------------------------------------------- 1 | extern void print_str(char *s); 2 | extern void panic(char *msg); 3 | 4 | void e0() { print_str("e0"); } 5 | 6 | void e1() { print_str("e1"); } 7 | 8 | void e2() { print_str("e2"); } 9 | 10 | void e3() { print_str("e3"); } 11 | 12 | void e4() { print_str("e4"); } 13 | 14 | void e5() { print_str("e5"); } 15 | 16 | void e6() { print_str("e6"); } 17 | 18 | void e7() { print_str("e7"); } 19 | 20 | void e8() { print_str("e8"); } 21 | 22 | void e9() { print_str("e9"); } 23 | 24 | void e10() { print_str("e10"); } 25 | 26 | void e11() { print_str("e11"); } 27 | 28 | void e12() { panic("e12"); } 29 | 30 | void e13() { panic("e13"); } 31 | 32 | void e15() { print_str("e15"); } 33 | 34 | void e16() { print_str("e16"); } 35 | -------------------------------------------------------------------------------- /demos/shell_demo/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=62 skip=8 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=63 conv=notrunc 6 | node fs_patch_tool/patch.js 7 | link: head lan_main boot 8 | ld -m elf_i386 -T n.lds -o lan_os head.o lan_main.o sys_call.o intel_err_handle.o sched.o fork.o mm.o print_str.o keyboard.o 9 | head: 10 | nasm -felf32 -o head.o head.s 11 | lan_main: 12 | gcc -O0 -m32 -g -fno-stack-protector -fno-pie -c lan_main.c sys_call.c intel_err_handle.c sched.c fork.c mm.c print_str.c keyboard.c 13 | boot: 14 | nasm -o boot.bin boot.s -l boot.lst 15 | clean: 16 | rm lan_os lan_main.o sys_call.o intel_err_handle.o head.o sched.o fork.o mm.o print_str.o keyboard.o boot.bin boot.lst a.img a.vfd 17 | -------------------------------------------------------------------------------- /demos/shell_demo/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef MM_H 2 | #define MM_H 3 | 4 | #define PAGE_SIZE 4096 5 | #define PAGE_DIR 0x10000 6 | #define PG_NUM 16 7 | 8 | #define LOW_MEM 0x100000 9 | #define MAP_NR(addr) (((addr)-LOW_MEM) >> 12) 10 | #define invalidate() __asm__("movl %%eax,%%cr3" ::"a"(PAGE_DIR)) 11 | 12 | extern void mm_init(); 13 | extern unsigned long get_free_page(); 14 | extern int free_page_tables(unsigned long from, unsigned long size); 15 | extern int copy_page_tables(unsigned long from, unsigned long to, long size); 16 | 17 | #endif -------------------------------------------------------------------------------- /demos/shell_demo/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/shell_demo/root_fs/hello_fs: -------------------------------------------------------------------------------- 1 | hi, lan_os. it's a nice day!!! -------------------------------------------------------------------------------- /demos/shell_demo/root_fs/lan_sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/shell_demo/root_fs/lan_sh -------------------------------------------------------------------------------- /demos/shell_demo/root_fs/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freelw/LanOS/d1ed946fb0ce86f4d19520ab298c0ed2b51a3a77/demos/shell_demo/root_fs/test -------------------------------------------------------------------------------- /demos/shell_demo/sched.c: -------------------------------------------------------------------------------- 1 | #include "sched.h" 2 | #include "mm.h" 3 | 4 | struct task_struct *task[NR_TASKS]; 5 | int task_used[NR_TASKS]; 6 | struct task_struct init_task; 7 | struct task_struct *current = (struct task_struct *)&init_task; 8 | long last_sched_i = 0; 9 | 10 | extern void switch_to(unsigned long, struct task_struct *); 11 | extern void set_tss0_esp0(unsigned long); 12 | extern void get_esp0_when_switch(unsigned long *); 13 | extern void krn_stk0(); 14 | 15 | void sched_init() { 16 | for (int i = 0; i < NR_TASKS; ++i) { 17 | task[i] = 0; 18 | task_used[i] = 0; 19 | } 20 | task_used[0] = 1; 21 | init_task.state = TASK_UNINTERRUPTIBLE; 22 | init_task.pid = 0; 23 | init_task.ldt[0].a = 0; 24 | init_task.ldt[0].b = 0; 25 | init_task.ldt[1].a = 0x3ff; 26 | init_task.ldt[1].b = 0xc0fa00; 27 | init_task.ldt[2].a = 0x3ff; 28 | init_task.ldt[2].b = 0xc0f200; 29 | set_ldt_desc(gdt + 0 + FIRST_LDT_ENTRY, &(init_task.ldt)); 30 | task[0] = &init_task; 31 | lldt(0); 32 | init_task.state = TASK_RUNNING; 33 | } 34 | 35 | void schedule() { 36 | int i = last_sched_i; 37 | while (1) { 38 | ++i; 39 | i %= NR_TASKS; 40 | if (task[i]) { 41 | if (current->pid != i) { 42 | if (task[i]->state == TASK_RUNNING) { 43 | last_sched_i = i; 44 | if (0 == i) { 45 | set_tss0_esp0( 46 | krn_stk0); // 0任务的内核栈是写死的,不能用task[i])+PAGE_SIZE来计算 47 | } else { 48 | set_tss0_esp0((unsigned long)(task[i]) + 49 | PAGE_SIZE); //给切换栈机制搭桥 50 | } 51 | unsigned long esp0 = 0; 52 | get_esp0_when_switch(&esp0); 53 | current->kernel_stack = esp0; 54 | current = task[i]; 55 | switch_to(_LDT(i), task[i]); 56 | return; 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | void do_timer(unsigned long cs) { 64 | if (0x8 == cs) { 65 | } else if (0xf == cs) { 66 | schedule(); 67 | } else { 68 | } 69 | } -------------------------------------------------------------------------------- /demos/user_mode_demo/boot.s: -------------------------------------------------------------------------------- 1 | [BITS 16] 2 | ORG 07c00h 3 | SYSSEG equ 01000h 4 | SYSLEN equ 17 5 | jmp 07c0h:(load_system-$) 6 | 7 | load_system: 8 | mov dx, 00000h 9 | mov cx, 00002h 10 | mov ax, SYSSEG 11 | mov es, ax ;es:bx 01000h:0h bios读取磁盘写入内存的目标位置 12 | xor bx, bx 13 | mov ax, 0200h+SYSLEN ;ah 读扇区功能号2 al读扇区数量 17 14 | int 013h 15 | jnc ok_load 16 | jmp $ 17 | 18 | ok_load: 19 | cli 20 | mov ax, SYSSEG ;开始把010000h位置的数据拷贝到0h处 21 | mov ds, ax ;注意这时bios的代码就会被冲掉,无法再使用int 10h 22 | xor ax, ax 23 | mov es, ax 24 | mov cx, 0x1000 25 | sub si, si 26 | sub di, di 27 | cld ;df = 0 rep movsw是正向的 28 | rep movsw 29 | mov ax, 0x0 ;重新恢复ds指向0x0 30 | mov ds, ax 31 | lgdt [gdt_48] ;ds+gdt_48 因为第一句话ORG 07c00h 所以此时gdt_48这个常量是:07c00h+到文件首的偏移 32 | mov ax, 0x0001 33 | lmsw ax 34 | jmp dword 8:0 35 | gdt: 36 | dw 0, 0, 0, 0 ;第一个描述符,没有用 37 | dw 0x07ff ;代码段 从0地址开始 38 | dw 0x0000 39 | dw 0x9a00 40 | dw 0x00c0 41 | dw 0x07ff ;数据段 从0地址开始 42 | dw 0x0000 43 | dw 0x9200 44 | dw 0x00c0 45 | 46 | 47 | gdt_48: 48 | dw 0x7ff ;2048/8=256个描述符 49 | dw gdt, 0 ;基地址是从0x7c00开始的gdt位置 50 | 51 | ;----------注意!所有的有效语句要写在这之前,并且总长出小于等于510字节---------- 52 | times 510 - ($-$$) db 0 53 | dw 0xaa55 -------------------------------------------------------------------------------- /demos/user_mode_demo/gate_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef GATE_TOOL_H 2 | #define GATE_TOOL_H 3 | 4 | typedef struct desc_struct { 5 | unsigned long a, b; 6 | } desc_table[256]; 7 | 8 | extern desc_table idt; 9 | 10 | #define _set_gate(gate_addr, type, dpl, addr) \ 11 | __asm__( \ 12 | "movw %%dx,%%ax\n\t" \ 13 | "movw %0,%%dx\n\t" \ 14 | "movl %%eax,%1\n\t" \ 15 | "movl %%edx,%2" \ 16 | : \ 17 | : "i"((short)(0x8000 + (dpl << 13) + (type << 8))), \ 18 | "o"(*((char *)(gate_addr))), "o"(*(4 + (char *)(gate_addr))), \ 19 | "d"((char *)(addr)), "a"(0x00080000)) 20 | 21 | #define set_intr_gate(n, addr) _set_gate(&idt[n], 14, 0, addr) 22 | 23 | #define set_trap_gate(n, addr) _set_gate(&idt[n], 15, 0, addr) 24 | 25 | #define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr) 26 | #endif -------------------------------------------------------------------------------- /demos/user_mode_demo/intel_err_handle.c: -------------------------------------------------------------------------------- 1 | extern void write_char(char ch); 2 | 3 | void e0() { write_char('0'); } 4 | 5 | void e1() { write_char('1'); } 6 | 7 | void e2() { write_char('2'); } 8 | 9 | void e3() { write_char('3'); } 10 | 11 | void e4() { write_char('4'); } 12 | 13 | void e5() { write_char('5'); } 14 | 15 | void e6() { write_char('6'); } 16 | 17 | void e7() { write_char('7'); } 18 | 19 | void e8() { write_char('8'); } 20 | 21 | void e9() { write_char('9'); } 22 | 23 | void e10() { 24 | write_char('1'); 25 | write_char('0'); 26 | } 27 | 28 | void e11() { 29 | write_char('1'); 30 | write_char('1'); 31 | } 32 | 33 | void e12() { 34 | write_char('1'); 35 | write_char('2'); 36 | } 37 | 38 | void e13() { 39 | write_char('1'); 40 | write_char('3'); 41 | } 42 | 43 | void e14() { 44 | write_char('1'); 45 | write_char('4'); 46 | } 47 | 48 | void e15() { 49 | write_char('1'); 50 | write_char('5'); 51 | } 52 | 53 | void e16() { 54 | write_char('1'); 55 | write_char('6'); 56 | } 57 | -------------------------------------------------------------------------------- /demos/user_mode_demo/makefile: -------------------------------------------------------------------------------- 1 | all: link 2 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 3 | dd if=lan_os of=a.img bs=512 count=17 skip=8 seek=1 conv=notrunc 4 | head -c 1474560 /dev/zero > a.vfd 5 | dd if=a.img of=a.vfd bs=512 count=18 conv=notrunc 6 | link: head lan_main boot 7 | ld -m elf_i386 -T n.lds -o lan_os head.o lan_main.o sys_call.o intel_err_handle.o 8 | head: 9 | nasm -felf32 -o head.o head.s 10 | lan_main: 11 | gcc -m32 -fno-pie -c lan_main.c sys_call.c intel_err_handle.c 12 | boot: 13 | nasm -o boot.bin boot.s -l boot.lst 14 | clean: 15 | rm lan_os lan_main.o sys_call.o intel_err_handle.o head.o boot.bin boot.lst a.img a.vfd 16 | 17 | -------------------------------------------------------------------------------- /demos/user_mode_demo/move_to_user_mode.h: -------------------------------------------------------------------------------- 1 | #ifndef MOV_TO_USER_MODE_H 2 | #define MOV_TO_USER_MODE_H 3 | #define move_to_user_mode() \ 4 | __asm__( \ 5 | "movl %%esp,%%eax\n\t" \ 6 | "pushl $0x17\n\t" \ 7 | "pushl %%eax\n\t" \ 8 | "pushfl\n\t" \ 9 | "pushl $0x0f\n\t" \ 10 | "pushl $1f\n\t" \ 11 | "iret\n" \ 12 | "1:\tmovl $0x17,%%eax\n\t" \ 13 | "mov %%ax,%%ds\n\t" \ 14 | "mov %%ax,%%es\n\t" \ 15 | "mov %%ax,%%fs\n\t" \ 16 | "mov %%ax,%%gs" :: \ 17 | : "ax") 18 | #define sti() __asm__("sti" ::) 19 | 20 | #define _syscall0(type, name) \ 21 | type name(void) { \ 22 | long __res; \ 23 | __asm__ volatile("int $0x80" : "=a"(__res) : "0"(__NR_##name)); \ 24 | if (__res >= 0) return (type)__res; \ 25 | return -1; \ 26 | } 27 | #endif -------------------------------------------------------------------------------- /demos/user_mode_demo/n.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0; 4 | .text : { *(.text) } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demos/user_mode_demo/readme.md: -------------------------------------------------------------------------------- 1 | # 血与泪 2 | 3 | ### 记录一下刚刚调试的要点 4 | 5 | 最初崩溃现象如下 6 | 7 | 在调用了一段时间的系统调用之后,莫名随机崩溃 8 | 发现栈一致在涨,溢出了 9 | 发现默认中断处理函数ignore_int一直被调用 10 | 关闭时钟终端之后崩溃消失 11 | 猜测应该是cpu报错 12 | 实现cpu报错的0-16错误函数 13 | 发现报错在13号终端,也就是general_protection 14 | 在时钟中断下断点,发现如果在系统调用内核态时发生时钟中断 15 | 由于要使用out指令,需要临时用al寄存器,但是并没有正确恢复 16 | 在返回到系统调用代码时,eax被当作系统调用号,原本是0 17 | 这里被改成0x20 18 | 所以造成访问函数列表数组越界 19 | 20 | 解决方案 21 | 22 | 在timer_interrupt中push eax 最后pop eax,保证eax的正确即可 -------------------------------------------------------------------------------- /demos/user_mode_demo/sys_call.c: -------------------------------------------------------------------------------- 1 | extern void write_char(char ch); 2 | typedef int (*sys_call)(); 3 | 4 | int _test_sys_call() { 5 | write_char('t'); 6 | return 0; 7 | } 8 | 9 | extern sys_call sys_call_table[] = {_test_sys_call}; -------------------------------------------------------------------------------- /doc/8259A.md: -------------------------------------------------------------------------------- 1 | # 真·三十天 2 | ## 系统的心跳 & 8259A 3 | 4 | 欢迎来到真三十天第七个视频 5 | 6 | 本节的标题是 《系统的心跳 & 8259A》 7 | 8 | 我们先来聊一聊心跳 9 | 10 | https://blog.csdn.net/shadkit/article/details/78852748?utm_source=blogxgwz2 11 | 12 | 感谢shadkit 13 | 14 | 看一下《编码》中与或非门的构造 15 | 16 | minecraft 17 | https://www.bilibili.com/video/BV1jt411c7kD?t=56 18 | 19 | ra95 20 | https://tieba.baidu.com/p/425319434 21 | 22 | 抖腿爆米花 23 | 24 | -------------------------------------------------------------------------------- /doc/a20.md: -------------------------------------------------------------------------------- 1 | # 真·三十天 2 | ## a20地址线 3 | 4 | 欢迎来到真三十天第六个视频 5 | 6 | 本期我们来讨论一下关于A20地址线的问题 7 | 8 | 首先我们来看一下这张图片 9 | 10 | 这是取自《汇编语言:从实模式到保护模式》194页的一张图 11 | 12 | 这本书从第193页开始的11.5小节开始就是讲解关于A20地址线的相关历史 13 | 14 | 我这里只取我们会用到的信息简单来讲解一下 15 | 16 | 这张图上面画的是一个80286cpu 17 | 18 | 它和早期推出的8086cpu有一个很大的区别是它有24根地址线 19 | 20 | 而8086只有20根地址线 21 | 22 | 所以8086实际上能只用的内存范围是 0x00000 ~ 0xFFFFF 23 | 24 | 而我们知道一个内存地址是由段基址和偏移决定的 25 | 26 | 比如段基址是A偏移是B 27 | 28 | 那么在实模式下要访问的地址是 (A<<4) + B 29 | 30 | 如果这个地址超过了0xFFFFF,在8086下的处理方式就是回卷到0地址处 31 | 32 | 比如你访问了0x100000,就相当于访问了0x00000 33 | 34 | 许多早期在8086的程序利用了这样的特性 35 | 36 | 但是80286出现之后是有能力访问0xFFFFF以上的地址的 37 | 38 | 于是IBM在主板上把键盘控制器的0x60端口的引脚用一个与门和a20相连 39 | 40 | 这样如果0x60输出0,那么A20就恒为0 41 | 42 | 这样就可以模拟8086的那种特性了 43 | 44 | (具体实操一下) 45 | 46 | 如果我们需要使用1M以上的物理内存,据需要让0x60这个端口的输出为 1 47 | 48 | 这样A20地址线输出才不会被屏蔽 49 | 50 | 本节就是讲解一下如何打开A20地址线 51 | -------------------------------------------------------------------------------- /doc/big_map.md: -------------------------------------------------------------------------------- 1 | # 一个操作系统是如何工作起来的 2 | 3 | ## 两个视角 4 | 5 | * 从用户使用的方式来感受 6 | 7 | * 从硬件底层来感受 -------------------------------------------------------------------------------- /doc/fbi_warning.md: -------------------------------------------------------------------------------- 1 | 1. x86架构的32位的os 2 | 3 | 2. 它支持多任务,最多8个任务同时运行 4 | 5 | 3. 使用了x86芯片的MMU机制,内存管理支持虚拟内存,但是不支持swap 6 | 7 | 4. 总共管理64MB的物理内存,虚拟内存空间也是总共64MB 8 | 9 | 5. 有一个简陋的只读文件系统,以内存形式实现,最多容纳10个文件 10 | 11 | 6. 不支持目录结构,每个文件最大20K 12 | 13 | 7. 支持写时复制机制,支持需求加载机制 14 | 15 | 8. 有一个简单的shell -------------------------------------------------------------------------------- /doc/fork.md: -------------------------------------------------------------------------------- 1 | # 梳理linux0.12知识点系列 2 | # 之 3 | # 多任务的初始化 4 | 5 | ## 从用户视角看待多任务 -------------------------------------------------------------------------------- /doc/how_to_build.md: -------------------------------------------------------------------------------- 1 | # 如何编译和运行demo 2 | 3 | 4 | ## 编译 5 | ### 依赖软件 6 | * [docker](https://www.docker.com/) 7 | 8 | ### 编译步骤 9 | 10 | 1. clone 工程 11 | 12 | git clone https://github.com/freelw/LanOS.git 13 | 14 | 2. 加载`lan_os_rc` 15 | 16 | source lan_os_rc 17 | 18 | 3. 进入一个demo编译,这里以`protect_mode_demo`为例,执行`lan_make`首次执行编译会拉取编译镜像 19 | 20 | $ cd demos/protect_mode_demo/ 21 | $ lan_make 22 | Unable to find image 'freelw/lan_make:latest' locally 23 | latest: Pulling from freelw/lan_make 24 | 5c939e3a4d10: Pull complete 25 | c63719cdbe7a: Pull complete 26 | 19a861ea6baf: Pull complete 27 | 651c9d2d6c4f: Pull complete 28 | 7e23ae3a25f1: Pull complete 29 | 51bb6ba7ea1d: Pull complete 30 | Digest: sha256:2b43e62a591836b22007c9daa6cf6cad2244d5f032390e676e8ab786b823e207 31 | Status: Downloaded newer image for freelw/lan_make:latest 32 | nasm -felf64 -o boot.o boot.s 33 | gcc -c lan_main.c 34 | nasm -o loader.bin loader.s -l loader.lst 35 | ld -T n.lds -o lan_os boot.o lan_main.o 36 | dd if=loader.bin of=a.img bs=512 count=1 conv=notrunc 37 | 1+0 records in 38 | 1+0 records out 39 | 512 bytes copied, 0.00183839 s, 279 kB/s 40 | dd if=lan_os of=a.img bs=512 count=17 skip=4096 seek=1 conv=notrunc 41 | 8+1 records in 42 | 8+1 records out 43 | 4304 bytes (4.3 kB, 4.2 KiB) copied, 0.00605137 s, 711 kB/s 44 | head -c 1474560 /dev/zero > a.vfd 45 | dd if=a.img of=a.vfd bs=512 count=18 conv=notrunc 46 | 9+1 records in 47 | 9+1 records out 48 | 4816 bytes (4.8 kB, 4.7 KiB) copied, 0.00466217 s, 1.0 MB/s 49 | 50 | 4. 清理编译结果的方法,执行`lan_clean`,同样首次执行会拉取镜像 51 | 52 | $ lan_clean 53 | Unable to find image 'freelw/lan_clean:latest' locally 54 | latest: Pulling from freelw/lan_clean 55 | 5c939e3a4d10: Already exists 56 | c63719cdbe7a: Already exists 57 | 19a861ea6baf: Already exists 58 | 651c9d2d6c4f: Already exists 59 | a43ee7839f30: Pull complete 60 | fb472c71d652: Pull complete 61 | Digest: sha256:276b8860b910214803ee2c91a89bbb7692fd0135f2d538ac553e9d09b699ec90 62 | Status: Downloaded newer image for freelw/lan_clean:latest 63 | rm lan_os lan_main.o boot.o loader.bin loader.lst a.img a.vfd 64 | 65 | ## 运行 66 | ### 依赖软件 67 | * [virtual box](https://www.virtualbox.org/) 68 | 69 | ### 运行方法 70 | * 将编译生成的a.vfd文件作为一个floppy加入到虚拟机的存储中 71 | * 分配多于16M的内存给虚拟机 72 | * 无需创建硬盘 73 | * 启动虚拟机 -------------------------------------------------------------------------------- /doc/mm.md: -------------------------------------------------------------------------------- 1 | # 真·三十天 2 | ## 内存管理 3 | 4 | 上图 5 | 6 | clk.pdf 页码 159 7 | 8 | 系统最终运行的状态 9 | 10 | 多任务交替执行 11 | 每个任务占用一段连续的内存 12 | 13 | 内存管理带来的好处 14 | 15 | 1. 用户程序有从0开始的内存空间 16 | 2. 可以使用更大的逻辑内存空间 17 | 3. 不必完全装入 18 | 19 | 20 | x86 21 | 分段 22 | 分页 23 | 24 | 物理地址空间 25 | 26 | 线性地址空间 27 | 28 | 进程的逻辑地址空间 29 | 30 | 31 | 2M 物理内存 32 | 4G 操作系统管理 33 | 64M 用户进程 34 | -------------------------------------------------------------------------------- /doc/questions.md: -------------------------------------------------------------------------------- 1 | #  网上的相关资料整理 2 | 3 | 4 | ### [如何将vdi文件转换成原始格式的磁盘镜像文件](https://superuser.com/questions/241269/exporting-a-virtualbox-vdi-to-a-harddrive-to-boot-it-natively) 5 | 6 | VBoxManage clonemedium --format RAW debian.vdi debian.img 7 | 8 | ### 反汇编 9 | 10 | objdump -l lan_os > disasm.txt 11 | makefile 要加上 gcc -g 12 | 13 | ### [bios int 0x13](https://blog.csdn.net/zxl3901/article/details/50072539) 14 | 15 | ### [内核中断号列表](http://www.360doc.com/content/11/0506/08/6580811_114716856.shtml) 16 | 17 | ### [看雪论坛 操作系统开发入门基础](https://bbs.pediy.com/thread-248745.htm) 18 | 19 | ### [ne2000 网卡编程](https://www.docin.com/p-1251912432.html) 20 | 21 | -------------------------------------------------------------------------------- /doc/target_and_prepare.md: -------------------------------------------------------------------------------- 1 | # 真·三十天 2 | ## 目标 & 准备 3 | 4 | 看到标题进来的小伙伴们应该有看多人看过《30天自制操作系统》这本书 5 | 6 | 但是很少有人能真正能完全实现书中的内容 7 | 8 | 并非这本书写的不好,这本书本身来说非常棒,作者呕心沥血,目的是为了身体力行的让读者看到从0开始实现操作系统的过程 9 | 10 | 然而尽管作者尽量简化系统的各个部件,书中的内容依旧太过于丰富,导致学习的难度还是比较大 11 | 12 | 但这本书依然是初学者学习操作系统内核的精品参考书,我在这里首先向川合秀实先生致敬 13 | 14 | ---- 15 | 16 | 我相信对操作系统本身感兴趣的各位一定是有抱负,对技术有追求的人 17 | 18 | 针对这样一个群体,其实缺乏的并不是喂到嘴边的知识,而是为了探寻知识链条的线索 19 | 20 | 况且操作系统知识本身内容非常庞杂,而且许多知识依赖是非线性的,可能会出现环状依赖 21 | 22 | 这就导致了即便是喂到嘴边的知识,你可能也消化不了 23 | 24 | 而我们真正需要的应该是一个能够快速一览全貌的知识图谱 25 | 26 | ---- 27 | 28 | 我们这个系列视频就是想要通过构建一个非常简陋的操作系统的过程来呈现这个知识图谱 29 | 30 | 因为是图谱,所以很多细枝末节可能会省略,会含糊不清,但会给出线索 31 | 32 | 标题是 真·30天自制操作系统,“真”的意思是说我们的操作系统会比《30天自制操作系统》中的简单 33 | 34 | 通过上期的视频也看到了,确实简单的过分,但是也就更容易实现了 35 | 36 | 虽然不能够达到“麻雀虽小,五脏俱全”,但是也能够“管中窥豹,可见一斑” 37 | 38 | 整个工程的代码都已经在github上了,我会把连接放在视频的简介中 39 | 40 | 工程的主页的最下方,有所有demo的按照历史顺序的链接,一共18个例子 41 | 42 | 最后一个例子就是我们最新的系统 43 | 44 | 18个例子,30天,应该是绰绰有余了 45 | 46 | ---- 47 | 48 | 下面是一个 FBI warning 49 | 50 | 由于本个系统过于简陋,先罗列一下功能,如果觉得没有学习的必要可以自行撤离 51 | 52 | 首先这个操作系统是基于x86架构的32位的os 53 | 54 | 它支持多任务,最多8个任务同时运行 55 | 56 | 使用了x86芯片的MMU机制,内存管理支持虚拟内存,但是不支持swap 57 | 58 | 总共管理64Mb的物理内存,虚拟内存空间也是总共64Mb 59 | 60 | 有一个简陋的只读文件系统,以内存形式实现,最多容纳10个文件 61 | 62 | 不支持目录结构,每个文件最大20K 63 | 64 | 支持写时复制机制,支持需求加载机制 65 | 66 | 有一个简单的shell 67 | 68 | 那么觉得有需求继续学习的同学请弹幕打1,这样我就能用脚本统计到有多少人需要,另外请不要sql注入 69 | 70 | ---- 71 | 72 | 本个操作系统借鉴了linux 0.12的源码和《orange 一个操作系统的实现》的源码 73 | 74 | 使用的汇编器是nasm还有c代码中有一些嵌入汇编,这是从orange书中学来的 75 | 76 | 在这里也向赵炯和于渊两位老师致敬 77 | 78 | 那么为什么不直接拿linux 0.12代码作为教程呢 79 | 80 | 首先,代码实在太多了,我hold不住 81 | 82 | 然后,编译环境实在太老了,找不全 83 | 84 | 最关键的是,我们想要一点一点构建自己的每个部件并且调试,必须要有一个非常方便的构建环境 85 | 86 | 所以我制作了容器编译环境,等一会我会展示如何使用这个环境编译各个demo 87 | 88 | -------------------------------------------------------------------------------- /lan_os_rc: -------------------------------------------------------------------------------- 1 | alias lan_make=`pwd`/tool/makeall.sh 2 | alias lan_clean=`pwd`/tool/makeclean.sh 3 | alias lan_format_c="indent -i4 -ts8 -sob -l80 -ss -bs -bbb -bl -bli0 -nce -psl" 4 | export lan_base_dir=`pwd` 5 | -------------------------------------------------------------------------------- /make_os.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | shopt -s expand_aliases 4 | source ./lan_os_rc 5 | cd src && 6 | echo 'builing lan os...' 7 | lan_make > /dev/null 2>&1 && 8 | cp a.vfd ../../ && 9 | echo 'cleaning temp files...' 10 | lan_clean > /dev/null 2>&1 11 | echo "file [a.vfd] is our os image with a simple ramdisk filesystem." -------------------------------------------------------------------------------- /src: -------------------------------------------------------------------------------- 1 | demos/common_header_demo/ -------------------------------------------------------------------------------- /tool/makeall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker run --rm -v `pwd`/:/share -v ${lan_base_dir}/demos/common_header_demo/common:/common freelw/lan_make:latest 4 | -------------------------------------------------------------------------------- /tool/makeclean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker run --rm -v `pwd`/:/share freelw/lan_clean:latest 4 | -------------------------------------------------------------------------------- /tool/start_vbox.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export VBOX_GUI_DBG_ENABLED=true 3 | export VBOX_GUI_DBG_AUTO_SHOW=true 4 | VirtualBox 5 | --------------------------------------------------------------------------------