From: yu.dongliang Date: Wed, 2 Nov 2022 05:03:26 +0000 (+0800) Subject: siska OS demo for bochs, this code is also in github X-Git-Url: http://baseworks.info/?a=commitdiff_plain;h=b1efc4e5714a450da3dbbf50159807d6bd543ce3;p=siska.git siska OS demo for bochs, this code is also in github --- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..11dd9a4 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ + +CFILES += siska_vfs.c +CFILES += siska_fs0.c +CFILES += siska_printf.c +CFILES += siska_fops_memory_dev.c + +all: + gcc -g -O3 $(CFILES) diff --git a/boot.s b/boot.s new file mode 100644 index 0000000..c5a0eeb --- /dev/null +++ b/boot.s @@ -0,0 +1,221 @@ + +BOOT_SEG = 0x07c0 + +INIT_SEG = 0x9000 +INIT_OFFSET = 0x0200 +INIT_SECTIONS = 1 +INIT_SECTION_START = 1 + +SYS_SEG = 0x1000 +SYS_SECTIONS = 137 + 1 + 20 +SYS_SECTION_START = 2 + +.code16 +.text +.global _start + +.align 4 +_start: + ljmp $BOOT_SEG, $_start2 + +_start2: + movw %cs, %ax + movw %ax, %ds + + movw $INIT_SEG, %ax + movw %ax, %es + + xorw %si, %si + xorw %di, %di + movw $0x100, %cx + rep movsw + + ljmp $INIT_SEG, $_read +_read: + movw %cs, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw $0x1000, %sp + +#read init code + movw $INIT_OFFSET, %bx + movw $INIT_SECTION_START, %cx + movw $INIT_SECTIONS, %dx + call _read_floppy + +#read sys code + movw $SYS_SEG, %ax + xorw %bx, %bx + movw $SYS_SECTION_START, %cx + movw $SYS_SECTIONS, %dx + call _read_floppy + + ljmp $INIT_SEG, $INIT_OFFSET + +_read_error: + movw $_msg_err, %ax + movw $8, %cx + call _print +1: + jmp 1b + +.align 4 +_nb_sections: + .word 0 +_cylind: + .byte 0 +_section: + .byte 0 +_head: + .byte 0 +.align 4 +_read_floppy: +#BIOS int 13H +#ah = 02H +#al = section count +#ch = cylind number +#cl = section number start +#dh = head number +#dl = driver number +#es:bx = buffer +#return value: cf = 0 ok, ah = 0, al = section count +#return value: cf != 0 error, ah = error number + +#input args: +#ax, buffer seg +#bx, buffer offset +#cx, start section +#dx, total sections + + cmpw $1024, %dx + jl 1f + + movw $_msg_kernel_too_big, %ax + movw $14, %cx + call _print +_too_big: + jmp _too_big + +1: + movw %dx, _nb_sections + movw %ax, %es + +#floppy 80 cylinds, 2 head, 18 sections, we count section No. from 0 +#get start cylind, head, section. + movw %cx, %ax + movb $36, %cl + divb %cl + movb %al, _cylind + + shrw $8, %ax + movb $18, %cl + divb %cl + movb %al, _head + movb %ah, _section + +_rep_read: + movb _section, %cl + movb $18, %al + subb %cl, %al + addb $1, %cl + xorb %ah, %ah + + cmpw %ax, _nb_sections + jge 2f + movw _nb_sections, %ax +2: + movw %bx, %dx + shrw $9, %dx + addw %ax, %dx + subw $128, %dx + jle 3f + subb %dl, %al +3: + movb $0x2, %ah + + movb _cylind, %ch + movb _head, %dh + movb $0, %dl + int $0x13 + jc _read_error + + movb $0, %ah + subw %ax, _nb_sections + je _read_ok + + movw %ax, %dx + shlw $9, %dx + + addb %al, _section + cmpb $18, _section + jl 4f + + movb $0, _section + addb $1, _head + cmpb $2, _head + jl 4f + + movb $0, _head + addb $1, _cylind +4: + addw %dx, %bx + jnc _rep_read + + movw %es, %ax + addw $0x1000, %ax + movw %ax, %es + xorw %bx, %bx + jmp _rep_read + +_read_ok: + movw $_msg_ok, %ax + movw $7, %cx + call _print + ret + +.align 4 +_print: +#ah = 13h +#al = show mode +#bh = page No. +#bl = priority +#cx = string len +#dh = row +#dl = col +#es:bp = string addr +#int 10h + + movw %ax, %bp + movw %cs, %ax + movw %ax, %es + + movb $0x13, %ah + movb $0x0, %al + movb $0x0, %bh + movb $0x8f, %bl + movw $0x0, %dx + int $0x10 + ret + +.align 4 +_msg_ok: +.asciz "read ok" + +.align 4 +_msg_err: +.asciz "read err" + +.align 4 +_msg_kernel_too_big: +.asciz "kernel too big" + +.org 500 +_rootfs_data: +.word 138, 0 +_rootfs_size: +.word 20, 0 +.word 0 + +.byte 0x55 +.byte 0xAA diff --git a/build_boot.sh b/build_boot.sh new file mode 100755 index 0000000..e9a0d8d --- /dev/null +++ b/build_boot.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +as boot.s --32 -o boot.o +as init.s --32 -o init.o +as head.s --32 -o head.o +as siska_syscall.s --32 -o siska_syscall.o +as siska_page.s --32 -o siska_page.o + +as execve.s --32 -o execve.o + +gcc -c -O3 -m32 main.c -fno-stack-protector +gcc -c -O3 -m32 siska_mm.c -fno-stack-protector +gcc -c -O3 -m32 siska_task.c -fno-stack-protector +gcc -c -O3 -m32 siska_printf.c -fno-stack-protector +gcc -c -O3 -m32 siska_console.c -fno-stack-protector +gcc -c -O3 -m32 siska_vfs.c -fno-stack-protector +gcc -c -O3 -m32 siska_fs0.c -fno-stack-protector +gcc -c -O3 -m32 siska_api.c -fno-stack-protector +gcc -c -O3 -m32 siska_fops_memory_dev.c -fno-stack-protector + +FILES="head.o \ + main.o \ + siska_syscall.o \ + siska_task.o \ + siska_printf.o \ + siska_console.o \ + siska_vfs.o \ + siska_fs0.o \ + siska_fops_memory_dev.o \ + siska_mm.o \ + siska_page.o \ + siska_api.o" + +ld -static -melf_i386 -Ttext 0x00000000 $FILES -o siska + +objdump -d boot.o -M i8086 > boot.txt +#objdump -d init.o -M i8086 +#objdump -d head.o -M i8086 +objdump -d siska -M i386 > siska.txt + +objdump -d execve.o -M i386 > execve.txt + +objcopy -S -O binary boot.o boot.bin +objcopy -S -O binary init.o init.bin +objcopy -S -O binary siska siska.bin +objcopy -S -O binary execve.o execve.bin + +dd if=boot.bin of=~/3rdparty/bochs/a.img bs=512 count=1 conv=notrunc +dd if=init.bin of=~/3rdparty/bochs/a.img bs=512 count=1 conv=notrunc seek=1 +dd if=siska.bin of=~/3rdparty/bochs/a.img bs=512 conv=notrunc seek=2 +dd if=fs.bin of=~/3rdparty/bochs/a.img bs=512 conv=notrunc seek=140 + +rm *.o siska + diff --git a/execve.s b/execve.s new file mode 100644 index 0000000..fbc106c --- /dev/null +++ b/execve.s @@ -0,0 +1,21 @@ + +.code32 +.text +.global _start + +.align 4 +_start: + jmp 2f +1: + popl %ebx + movl $3, %eax + movl $9, %ecx + int $0x80 + + movl $6, %eax + int $0x80 +2: + call 1b +_exec_msg: +.asciz "exec ok!\n" + diff --git a/head.s b/head.s new file mode 100644 index 0000000..84d4abe --- /dev/null +++ b/head.s @@ -0,0 +1,202 @@ + +.code32 +.text +.global _start, _task0, _tss0, _idt +.global siska_printk, _main + +.align 4 +_start: +_pg_dir: + + movl $0x10, %eax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + lss _init_stack, %esp + + call _setup_idt + call _setup_gdt + + movl $0x10, %eax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + lss _init_stack, %esp + + xorl %eax, %eax +1: + incl %eax + movl %eax, 0x000000 + cmpl %eax, 0x100000 + je 1b + + movl %cr0, %eax + andl $0x80000011, %eax + orl $0x2, %eax + movl %eax, %cr0 + + call _check_x87 + jmp _after_page_tables + +_check_x87: + fninit + fstsw %ax + cmpb $0, %al + je 1f + + movl %cr0, %eax + xorl $0x6, %eax + movl %eax, %cr0 + ret +.align 4 +1: + .byte 0xdb, 0xe4 + ret + +.align 4 +_setup_idt: + lea _ignore_int_handler, %edx + + movl $0x00080000, %eax + movw %dx, %ax + movw $0x8e00, %dx + + lea _idt, %edi + movl $256, %ecx +1: + movl %eax, (%edi) + movl %edx, 4(%edi) + addl $8, %edi + decl %ecx + jne 1b + + lidt _idt_desc + ret + +.align 4 +_setup_gdt: + lgdt _gdt_desc + ret + +.org 0x1000 +_pg_table0: + +.org 0x5000 +_task0: + .fill 4096, 1, 0 +_init_stack: + .long _init_stack + .word 0x10 +.align 4 +_tmp_floppy_area: + .fill 1024, 1, 0 + +.align 4 +_after_page_tables: + pushl $0 + pushl $0 + pushl $0 + pushl $_L6 + pushl $_main + + jmp _setup_pages +_L6: + jmp _L6 + +.align 4 +_setup_pages: + movl $1024 * 5, %ecx + xorl %eax, %eax + xorl %edi, %edi + cld + rep stosl + + xorl %edi, %edi + movl $0x1007, (%edi) + movl $0x2007, 4(%edi) + movl $0x3007, 8(%edi) + movl $0x4007, 12(%edi) + + movl $0x0007, %eax + movl $0x1000, %edi +1: + movl %eax, (%edi) + addl $0x1000, %eax + addl $4, %edi + cmpl $0x1000007, %eax + jl 1b + + xorl %eax, %eax + movl %eax, %cr3 + movl %cr0, %eax + orl $0x80000000, %eax + movl %eax, %cr0 + ret + +.align 4 +_init_msg: +.asciz "unknown interrupt!\n" + +.align 4 +_ignore_int_handler: + pushl %eax + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + + movl $0x10, %eax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + + pushl $_init_msg + call siska_printk + popl %eax + + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +.align 4 +.word 0 +_idt_desc: + .word 256 * 8 - 1 + .long _idt + +.align 4 +.word 0 +_gdt_desc: + .word 256 * 8 - 1 + .long _gdt + +.align 4 +_idt: + .fill 256, 8, 0 + +_gdt: + .word 0x0000, 0x0000, 0x0000, 0x0000 # 0 not use + + .word 0xffff, 0x0000, 0x9a00, 0x00cf # 0x8 kernel code + .word 0xffff, 0x0000, 0x9200, 0x00cf # 0x10 kernel data + + .word 0x0000, 0x0000, 0x0000, 0x0000 # 0x18 not use + + .word 0x0068, _tss0, 0xe900, 0x0000 # 0x20 tss0 + .word 0x0040, _ldt0, 0xe200, 0x0000 # 0x28 ldt0 + + .fill 250, 8, 0 +_ldt0: + .word 0x0000, 0x0000, 0x0000, 0x0000 # 0 not use + .word 0xffff, 0x0000, 0xfa00, 0x00cf # 0xf user code + .word 0xffff, 0x0000, 0xf200, 0x00cf # 0x17 user data +_tss0: + .fill 104, 1, 0 + diff --git a/init.s b/init.s new file mode 100644 index 0000000..ab705be --- /dev/null +++ b/init.s @@ -0,0 +1,201 @@ + +INIT_SEG = 0x9000 +INIT_OFFSET = 0x0200 + +SYS_SEG = 0x1000 + +DATA_OFFSET_VGA_CUR_COL = 0x0 +DATA_OFFSET_VGA_CUR_ROW = 0x1 + +DATA_OFFSET_MEM_SIZE = 0x2 + +DATA_OFFSET_VGA_CUR_PAGE = 0x5 +DATA_OFFSET_VGA_CUR_MODE = 0x6 +DATA_OFFSET_VGA_CUR_WIDTH = 0x7 + +DATA_OFFSET_VGA_SIZE = 0xa +DATA_OFFSET_VGA_MODE = 0xb +DATA_OFFSET_VGA_PARAM = 0xc +DATA_OFFSET_VGA_ROW = 0xe +DATA_OFFSET_VGA_COL = 0xf + +.code16 +.text +.global _start + +.align 4 +_start: + +#get extended memory size > 1M, based on KB + movb $0x88, %ah + int $0x15 + movw %ax, (DATA_OFFSET_MEM_SIZE) + +#get VGA params + movb $0x12, %ah + movb $0x10, %bl + int $0x10 + movb %bl, (DATA_OFFSET_VGA_SIZE) + movb %bh, (DATA_OFFSET_VGA_MODE) + movw %cx, (DATA_OFFSET_VGA_PARAM) + movw $0x5019, %ax + movb %al, (DATA_OFFSET_VGA_ROW) + movb %ah, (DATA_OFFSET_VGA_COL) + + movb $0x03, %ah + xorb %bh, %bh + int $0x10 + movb %dl, (DATA_OFFSET_VGA_CUR_COL) + movb %dh, (DATA_OFFSET_VGA_CUR_ROW) + + movb $0x0f, %ah + int $0x10 + movb %al, (DATA_OFFSET_VGA_CUR_MODE) + movb %ah, (DATA_OFFSET_VGA_CUR_WIDTH) + movb %bh, (DATA_OFFSET_VGA_CUR_PAGE) + + cli + xorw %ax, %ax + cld +_mov_sys: + movw %ax, %es + + addw $SYS_SEG, %ax + cmpw $INIT_SEG, %ax + jz _end_mov_sys + + movw %ax, %ds + xorw %si, %si + xorw %di, %di + movw $0x8000, %cx + rep movsw + jmp _mov_sys + +_end_mov_sys: + + movw $INIT_SEG, %ax + movw %ax, %ds + +#load global description table & interrupt description table + lidt _idt_48 + INIT_OFFSET + lgdt _gdt_48 + INIT_OFFSET + +#enable A20 + call _empty_8042 + + movb $0xd1, %al + out %al, $0x64 + call _empty_8042 + + movb $0xdf, %al + out %al, $0x60 + call _empty_8042 + +#set 8259 interrupt chips, 0x20-0x21 for master, 0xa0-0xa1 for slave + +#start programming + movb $0x11, %al + out %al, $0x20 + .word 0x00eb, 0x00eb + out %al, $0xa0 + .word 0x00eb, 0x00eb + +#interrupt NO. from 0x20 in master + movb $0x20, %al + out %al, $0x21 + .word 0x00eb, 0x00eb + +#interrupt NO. from 0x28 in slave + movb $0x28, %al + out %al, $0xa1 + .word 0x00eb, 0x00eb + +#master irq 2 connect to slave + movb $0x04, %al + out %al, $0x21 + .word 0x00eb, 0x00eb + +#slave connect to master's irq 2 + movb $0x02, %al + out %al, $0xa1 + .word 0x00eb, 0x00eb + + movb $0x01, %al + out %al, $0x21 + .word 0x00eb, 0x00eb + out %al, $0xa1 + .word 0x00eb, 0x00eb + +#disable all interrupts of master and slave + movb $0xff, %al + out %al, $0x21 + .word 0x00eb, 0x00eb + out %al, $0xa1 + .word 0x00eb, 0x00eb + + movw $0x1, %ax + lmsw %ax + ljmp $8, $0 + +1: + jmp 1b + +.align 4 +_empty_8042: + .word 0x00eb, 0x00eb + in $0x64, %al + test $0x2, %al + jnz _empty_8042 + ret + +.align 16 +_gdt: + .word 0, 0, 0, 0 + + .word 0x07ff + .word 0x0000 + .word 0x9a00 + .word 0x00c0 + + .word 0x07ff + .word 0x0000 + .word 0x9200 + .word 0x00c0 + +.align 16 +_idt_48: + .word 0, 0, 0 + +.align 16 +_gdt_48: + .word 0x800 + .word INIT_OFFSET + _gdt + .word 0x9 + +.align 4 +_print: +#ah = 13h +#al = show mode +#bh = page No. +#bl = priority +#cx = string len +#dh = row +#dl = col +#es:bp = string addr +#int 10h + + movw %ax, %bp + movw %cs, %ax + movw %ax, %es + + movb $0x13, %ah + movb $0x0, %al + movb $0x0, %bh + movb $0x8f, %bl + movw $0x0, %dx + int $0x10 + ret + +.align 4 +_init_msg: +.asciz "init ok" diff --git a/main.c b/main.c new file mode 100644 index 0000000..21ee9aa --- /dev/null +++ b/main.c @@ -0,0 +1,181 @@ + +#include"siska_task.h" +#include"siska_mm.h" +#include"siska_vfs.h" +#include"siska_api.h" + +void siska_console_init(); + +int siska_write(siska_regs_t* regs) +{ + const char* fmt = (const char*)regs->ebx; + + return siska_console_write(fmt); +} + +int _do_timer() +{ + siska_schedule(); + return 0; +} + +int _do_syscall_default() +{ + siska_printk("syscall default!\n"); + return 0; +} + +void _syscall_init() +{ + int i; + for (i = 0; i < 256; i++) + set_syscall_handler(i, _do_syscall_default); + + set_syscall_handler(SISKA_SYSCALL_FORK, siska_fork); + set_syscall_handler(SISKA_SYSCALL_SCHED, siska_schedule); + + set_syscall_handler(SISKA_SYSCALL_WRITE, siska_write); + + set_syscall_handler(SISKA_SYSCALL_KILL, siska_kill); + set_syscall_handler(SISKA_SYSCALL_SIGNAL, siska_signal); + + set_syscall_handler(SISKA_SYSCALL_EXIT, siska_exit); + set_syscall_handler(SISKA_SYSCALL_WAIT, siska_wait); + + set_syscall_handler(SISKA_SYSCALL_GETPID, siska_getpid); + set_syscall_handler(SISKA_SYSCALL_GETPPID, siska_getppid); + + set_syscall_handler(SISKA_SYSCALL_EXECVE, siska_execve); +} + +int _main() +{ + siska_tss_t* tss0 = get_asm_addr(_tss0); + siska_task_t* task0 = get_asm_addr(_task0); + + set_intr_handler(SISKA_INTERRUPT_PAGE_FAULT, _page_fault_int_handler); + + _jiffies = 0; + +#define HZ 100u +#define LATCH (1193180u / HZ) +#if 1 + outb_p(0x36, 0x43); + outb_p(LATCH & 0xff, 0x40); + outb(LATCH >> 8, 0x40); + set_intr_handler(SISKA_INTERRUPT_TIMER, _timer_int_handler); + outb(inb_p(0x21) & ~0x01, 0x21); +#endif + set_trap_handler(SISKA_INTERRUPT_SYSCALL, _syscall_handler); + + siska_console_init(); + + _syscall_init(); + + siska_task_init(); + siska_mm_init(); + siska_fs_init(); + +#if 0 + siska_file_t* file = NULL; + + int ret = siska_vfs_open(&file, "/home/execve", + SISKA_FILE_FILE | SISKA_FILE_FLAG_R | SISKA_FILE_FLAG_W, + 0777); + siska_printk("open /home/execve, ret: %d\n", ret); + if (ret < 0) { + return -1; + } +#if 1 + char buf[64]; + ret = siska_vfs_read(file, buf, sizeof(buf) - 1); + if (ret < 0) { + siska_printk("read /home/execve error, ret: %d\n", ret); + return -1; + } + siska_printk("/home/execve, ret: %d, buf: %s\n", ret, buf); +#endif +#endif + + tss0->esp0 = (unsigned long)task0 + PG_SIZE; + tss0->ss0 = 0x10; + tss0->cs = 0xf; + tss0->ds = 0x17; + tss0->es = 0x17; + tss0->fs = 0x17; + tss0->gs = 0x17; + tss0->ldt = 0x28; + tss0->iomap = 0x80000000; + + task0->pid = 0; + task0->ppid = -1; + task0->cr3 = 0; + + task0->code3 = (unsigned long)task0 + sizeof(siska_task_t); + task0->data3 = (unsigned long)task0 + sizeof(siska_task_t); + task0->heap3 = (unsigned long)task0 + sizeof(siska_task_t); + task0->brk3 = (unsigned long)task0 + sizeof(siska_task_t); + task0->ebp3 = (unsigned long)task0 + PG_SIZE; + task0->end3 = (unsigned long)task0 + PG_SIZE; + + task0->signal_flags = 0; + siska_memset(task0->signal_handlers, (unsigned long)SISKA_SIG_DFL, SISKA_NB_SIGNALS * sizeof(void*)); + + asm volatile( + "pushfl\n\t" + "andl $0xffffbfff, (%%esp)\n\t" + "popfl\n\t" + "movl $0x20, %%eax\n\t" + "ltr %%ax\n\t" + "movl $0x28, %%eax\n\t" + "lldt %%ax\n\t" + "sti\n\t" + : + : + :"eax" + ); + + asm volatile( + "movl %%esp, %%eax\n\t" + "pushl $0x17\n\t" + "pushl %%eax\n\t" + "pushfl\n\t" + "pushl $0xf\n\t" + "pushl $1f\n\t" + "iret\n\t" + "1:\n\t" + "movl $0x17, %%eax\n\t" + "movl %%eax, %%ds\n\t" + "movl %%eax, %%es\n\t" + "movl %%eax, %%fs\n\t" + "movl %%eax, %%gs\n\t" + : + : + :"eax" + ); +#if 1 + int cpid = siska_api_syscall(SISKA_SYSCALL_FORK, 0, 0, 0); + if (-1 == cpid) { + while (1) { + } + } else if (0 == cpid) { + siska_api_execve(get_asm_addr(_execve_msg), 0, 0); + while (1) { + +// siska_api_syscall(SISKA_SYSCALL_KILL, 0, SISKA_SIGINT, 0); +// siska_api_printf(get_asm_addr(_fork1_msg)); +// volatile unsigned long* p = (volatile unsigned long*)(1u << 30); +// *p = 0x1234; +// siska_api_syscall(SISKA_SYSCALL_SCHED, 0, 0, 0); + } + } else { + while (1) { +// siska_api_printf(get_asm_addr(_fork0_msg)); + +// siska_api_syscall(SISKA_SYSCALL_KILL, 1, SISKA_SIGINT, 0); + } + } +#endif + return 0; +} + diff --git a/siska_api.c b/siska_api.c new file mode 100644 index 0000000..61bf060 --- /dev/null +++ b/siska_api.c @@ -0,0 +1,23 @@ + +#include"siska_api.h" + +int siska_api_printf(const char* fmt, ...) +{ + char buf[128]; + + siska_va_list ap; + + siska_va_start(ap, fmt); + int n = siska_vsnprintf(buf, sizeof(buf), fmt, ap); + siska_va_end(ap); + + if (n > 0) + return siska_api_syscall(SISKA_SYSCALL_WRITE, (unsigned long)buf, n, 0); + return n; +} + +int siska_api_execve(const char* filename, char* const argv, char* const envp) +{ + return siska_api_syscall(SISKA_SYSCALL_EXECVE, (unsigned long)filename, (unsigned long)argv, (unsigned long)envp); +} + diff --git a/siska_api.h b/siska_api.h new file mode 100644 index 0000000..15c9264 --- /dev/null +++ b/siska_api.h @@ -0,0 +1,35 @@ +#ifndef SISKA_API_H +#define SISKA_API_H + +#include"siska_def.h" +#include"siska_list.h" + +static inline int siska_api_syscall(unsigned long num, unsigned long arg0, unsigned long arg1, unsigned long arg2) +{ + int ret; + + asm volatile( + "int $0x80\n\t" + :"=a"(ret) + :"a"(num), "b"(arg0), "c"(arg1), "d"(arg2) + : + ); + return ret; +} + +int siska_api_printf(const char* fmt, ...); +int siska_api_execve(const char* filename, char* const argv, char* const envp); + +static inline int siska_api_getpid() +{ + return siska_api_syscall(SISKA_SYSCALL_GETPID, 0, 0, 0); +} + +static inline int siska_api_getppid() +{ + return siska_api_syscall(SISKA_SYSCALL_GETPPID, 0, 0, 0); +} + + +#endif + diff --git a/siska_atomic.h b/siska_atomic.h new file mode 100644 index 0000000..a498ac4 --- /dev/null +++ b/siska_atomic.h @@ -0,0 +1,114 @@ +#ifndef SISKA_ATOMIC_H +#define SISKA_ATOMIC_H + +typedef struct { + volatile int refs; +} siska_atomic_t; + +typedef struct { + siska_atomic_t v; +} siska_spinlock_t; + +#define LOCK "lock;" + + +static inline int siska_atomic_xchg(siska_atomic_t* v, int i) +{ + asm volatile("xchg %0, %1" + :"=m"(v->refs), "=r"(i) + :"1"(i) + : + ); + return i; +} + +static inline void siska_atomic_inc(siska_atomic_t* v) +{ + asm volatile(LOCK"incl %0":"=m"(v->refs) ::); +} + +static inline void siska_atomic_dec(siska_atomic_t* v) +{ + asm volatile(LOCK"decl %0":"=m"(v->refs) ::); +} + +static inline int siska_atomic_dec_and_test(siska_atomic_t* v) +{ + char ret; + asm volatile(LOCK"decl %0; setz %1":"=m"(v->refs), "=r"(ret)::); + return ret; +} + +static inline void siska_cli() +{ + asm volatile("cli":::); +} +static inline void siska_sti() +{ + asm volatile("sti":::); +} + +#define SISKA_SPINLOCK_INIT {0} + +static inline void siska_spinlock_init(siska_spinlock_t* lock) +{ + lock->v.refs = 0; +} + +#define siska_irqsave(flags) \ + do { \ + asm volatile( \ + "pushfl\n\t" \ + "popl %0\n\t" \ + :"=r"(flags) \ + : \ + : \ + ); \ + siska_cli(); \ + } while (0) + +#define siska_irqrestore(flags) \ + do { \ + asm volatile( \ + "pushl %0\n\t" \ + "popfl\n\t" \ + : \ + :"r"(flags) \ + :"flags" \ + ); \ + } while (0) + +#undef SISKA_SMP + +#ifdef SISKA_SMP +#define siska_spin_lock_irqsave(lock, flags) \ + do { \ + siska_irqsave(flags); \ + while(0 != siska_atomic_xchg(&lock->v, 1)); \ + } while (0) + +#define siska_spin_unlock_irqrestore(lock, flags) \ + do { \ + lock->v.refs = 0; \ + siska_irqrestore(flags); \ + } while (0) + +#define siska_spin_lock(lock) \ + do { \ + while(0 != siska_atomic_xchg(&lock->v, 1)); \ + } while (0) + +#define siska_spin_unlock(lock) \ + do { \ + lock->v.refs = 0; \ + } while (0) + +#else +#define siska_spin_lock_irqsave(lock, flags) siska_irqsave(flags) +#define siska_spin_unlock_irqrestore(lock, flags) siska_irqrestore(flags) +#define siska_spin_lock(lock) +#define siska_spin_unlock(lock) +#endif + +#endif + diff --git a/siska_console.c b/siska_console.c new file mode 100644 index 0000000..227e6f9 --- /dev/null +++ b/siska_console.c @@ -0,0 +1,76 @@ + +#include"siska_task.h" +#include"siska_mm.h" + +static int console_x = 0; +static int console_y = 0; + +static int console_rows = 25; +static int console_cols = 80; + +void siska_console_init() +{ + console_x = 0; + console_y = 0; + + console_rows = 25; + console_cols = 80; +} + +int siska_console_write(const char* fmt) +{ + unsigned char* buf = (unsigned char*)0xb8000; + unsigned char* p = (unsigned char*)fmt; + + unsigned long flags; + siska_irqsave(flags); + while (*p) { + + if (console_x >= console_cols) { + console_x = 0; + console_y++; + + if (console_y >= console_rows) + console_y = 0; + } + + if ('\n' == *p) { + p++; + console_x = 0; + console_y++; + if (console_y >= console_rows) + console_y = 0; + continue; + } + + int pos = console_y * console_cols + console_x; + + buf[pos * 2] = *p++; + buf[pos * 2 + 1] = 0x0f; + + console_x++; + } + siska_irqrestore(flags); + + return (int)(p - (unsigned char*)fmt); +} + +static char printk_buf[128]; + +int siska_printk(const char* fmt, ...) +{ + siska_va_list ap; + unsigned long flags; + + siska_irqsave(flags); + siska_va_start(ap, fmt); + int n = siska_vsnprintf(printk_buf, sizeof(printk_buf), fmt, ap); + siska_va_end(ap); + + if (n > 0) + n = siska_console_write(printk_buf); + + siska_irqrestore(flags); + return n; +} + diff --git a/siska_core.h b/siska_core.h new file mode 100644 index 0000000..7367c94 --- /dev/null +++ b/siska_core.h @@ -0,0 +1,155 @@ +#ifndef SISKA_CORE_H +#define SISKA_CORE_H + +#include"siska_def.h" +#include"siska_list.h" + +typedef struct siska_task_s siska_task_t; +typedef struct siska_tss_s siska_tss_t; +typedef struct siska_mm_s siska_mm_t; + +typedef struct siska_vfs_s siska_vfs_t; +typedef struct siska_fs_s siska_fs_t; +typedef struct siska_file_ops_s siska_file_ops_t; +typedef struct siska_file_s siska_file_t; +typedef struct siska_dev_s siska_dev_t; + +typedef struct siska_sblock_s siska_sblock_t; +typedef struct siska_inode_s siska_inode_t; + +typedef struct siska_sblock_dev_s siska_sblock_dev_t; +typedef struct siska_inode_dev_s siska_inode_dev_t; + +#define PG_SHIFT 12 +#define PG_SIZE (1u << PG_SHIFT) + +#define PGDIR_KERNEL 0 + +extern volatile unsigned long _jiffies; + +#define SISKA_INTERRUPT_PAGE_FAULT 14 +#define SISKA_INTERRUPT_TIMER 0x20 +#define SISKA_INTERRUPT_SYSCALL 0x80 + +#define get_asm_addr(_id) \ + ({ \ + void* addr; \ + asm volatile("lea "#_id", %0\n\t" :"=r"(addr)::); \ + addr; \ + }) + +static inline void switch_to_pgdir(unsigned long pgdir) +{ + asm volatile( + "movl %0, %%cr3\n\t" + "jmp 1f\n\t" + "1:\n\t" + : + :"r"(pgdir) + : + ); +} + +static inline unsigned long get_jiffies() +{ + unsigned long jiffies; + asm volatile( + "lea _jiffies, %0\n\t" + "movl (%0), %0\n\t" + :"=r"(jiffies) + : + : + ); + return jiffies; +} + +static inline siska_task_t* get_current() +{ + siska_task_t* current; + asm volatile( + "andl %%esp, %0" + :"=r"(current) + :"0"(~(PG_SIZE - 1)) + : + ); + return current; +} +#define current get_current() + +#define set_gate_handler(num, type, handler) \ + do { \ + asm volatile( \ + "lea "#handler", %%edx\n\t" \ + "movl $0x00080000, %%eax\n\t" \ + "movw %%dx, %%ax\n\t" \ + "movw %1, %%dx\n\t" \ + "lea _idt(, %0, 8), %0\n\t" \ + "movl %%eax, (%0)\n\t" \ + "movl %%edx, 4(%0)\n\t" \ + : \ + :"r"(num), "i"(type) \ + :"eax", "edx" \ + ); \ + } while (0) +#define set_intr_handler(num, handler) set_gate_handler(num, 0x8e00, handler) +#define set_trap_handler(num, handler) set_gate_handler(num, 0xef00, handler) + +#define set_syscall_handler(num, handler) \ + do { \ + asm volatile( \ + "lea "#handler", %%eax\n\t" \ + "movl %%eax, _syscall_table(, %0, 4)\n\t" \ + : \ + :"r"(num) \ + :"eax" \ + ); \ + } while (0) + +static inline void outb_p(unsigned char data, unsigned short port) +{ + asm volatile( + "movb %0, %%al\n\t" + "outb %%al, %1\n\t" + "jmp 1f\n\t" + "1: jmp 1f\n\t" + "1:\n\t" + : + :"r"(data), "i"(port) + : + ); +} +static inline void outb(unsigned char data, unsigned short port) +{ + asm volatile( + "movb %0, %%al\n\t" + "outb %%al, %1\n\t" + : + :"r"(data), "i"(port) + : + ); +} +static inline unsigned char inb_p(unsigned short port) +{ + unsigned char data; + asm volatile( + "inb %1, %%al\n\t" + "movb %%al, %0\n\t" + "jmp 1f\n\t" + "1: jmp 1f\n\t" + "1:\n\t" + :"=r"(data) + :"i"(port) + : + ); + return data; +} + +int siska_console_write(const char* fmt); +#ifdef ON_BOCHS +int siska_printk(const char* fmt, ...); +#else +#define siska_printk printf +#endif + +#endif + diff --git a/siska_def.h b/siska_def.h new file mode 100644 index 0000000..74de50b --- /dev/null +++ b/siska_def.h @@ -0,0 +1,49 @@ +#ifndef SISKA_DEF_H +#define SISKA_DEF_H + +#define ON_BOCHS +#ifdef ON_BOCHS +#define NULL ((void*)0) + +typedef char* siska_va_list; +#define INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1)) +#define siska_va_start(ap,v) (ap = (siska_va_list)&v + INTSIZEOF(v)) +#define siska_va_arg(ap,t) (*(t*)((ap += INTSIZEOF(t)) - INTSIZEOF(t))) +#define siska_va_end(ap) (ap = (siska_va_list)0) + +#else +#include +#include +#define siska_va_list va_list +#define siska_va_start va_start +#define siska_va_arg va_arg +#define siska_va_end va_end +#endif + +#include"siska_atomic.h" +#include"siska_string.h" + +#define SISKA_SYSCALL_FORK 1 +#define SISKA_SYSCALL_SCHED 2 +#define SISKA_SYSCALL_WRITE 3 +#define SISKA_SYSCALL_KILL 4 +#define SISKA_SYSCALL_SIGNAL 5 +#define SISKA_SYSCALL_EXIT 6 +#define SISKA_SYSCALL_WAIT 7 +#define SISKA_SYSCALL_GETPID 8 +#define SISKA_SYSCALL_GETPPID 9 +#define SISKA_SYSCALL_EXECVE 10 + +#define SISKA_SIGINT 2 +#define SISKA_SIGKILL 9 +#define SISKA_SIGSEGV 11 +#define SISKA_SIGCHLD 17 +#define SISKA_NB_SIGNALS (sizeof(unsigned long) * 8) +#define SISKA_SIG_DFL NULL +#define SISKA_SIG_IGN ((void*)0x1) + +int siska_vsnprintf(char* buf, int size, const char* fmt, siska_va_list ap); +int siska_snprintf (char* buf, int size, const char* fmt, ...); + +#endif + diff --git a/siska_fops_memory_dev.c b/siska_fops_memory_dev.c new file mode 100644 index 0000000..fcfc554 --- /dev/null +++ b/siska_fops_memory_dev.c @@ -0,0 +1,105 @@ +#include"siska_vfs.h" +#include"siska_mm.h" + +int memory_dev_open(siska_file_t* file, int flags, unsigned int mode) +{ + if (file && file->dev) { + + if (file->dev->priv && file->dev->priv_size > 0) { + file->dev->priv_pos = 0; + return 0; + } + } + return -1; +} + +int memory_dev_close(siska_file_t* file) +{ + return 0; +} + +int memory_dev_read(siska_file_t* file, void* buf, int size) +{ + if (!file || !buf || size < 0) + return -1; + + siska_dev_t* dev = file->dev; + + if (!dev || !dev->priv || dev->priv_size <= 0) + return -1; + + int len = dev->priv_size - dev->priv_pos; + if (len < 0) + return -1; + + len = size > len ? len : size; + +// siska_printk("%s(), %d, dev p: %p, len: %d\n", __func__, __LINE__, dev->priv + dev->priv_pos, len); + + siska_memcpy(buf, dev->priv + dev->priv_pos, len); + dev->priv_pos += len; + + return len; +} + +int memory_dev_write(siska_file_t* file, const void* buf, int size) +{ + if (!file || !buf || size < 0) + return -1; + + siska_dev_t* dev = file->dev; + + if (!dev || !dev->priv || dev->priv_size <= 0) + return -1; + + int len = dev->priv_size - dev->priv_pos; + if (len < 0) + return -1; + + len = size > len ? len : size; + + siska_memcpy(dev->priv + dev->priv_pos, buf, len); + dev->priv_pos += len; + + return len; +} + +int memory_dev_lseek(siska_file_t* file, long offset, int whence) +{ + if (!file || !file->dev || offset < 0 || SISKA_SEEK_SET != whence) + return -1; + + file->dev->priv_pos = offset; +// siska_printk("%s(), %d, dev->priv_pos: %d\n", __func__, __LINE__, file->dev->priv_pos); + return 0; +} + +int memory_dev_sync(siska_file_t* file) +{ + return 0; +} + +int memory_dev_ioctl(siska_file_t* file, unsigned long cmd, ...) +{ + return 0; +} + + +siska_file_ops_t siska_fops_memory_dev = +{ + .type = "memory_dev", + + .next = NULL, + + .open = memory_dev_open, + .close = memory_dev_close, + + .read = memory_dev_read, + .write = memory_dev_write, + + .lseek = memory_dev_lseek, + .sync = memory_dev_sync, + + .ioctl = memory_dev_ioctl, +}; + diff --git a/siska_fs.h b/siska_fs.h new file mode 100644 index 0000000..06a8bea --- /dev/null +++ b/siska_fs.h @@ -0,0 +1,81 @@ +#ifndef SISKA_FS_H +#define SISKA_FS_H + +#include"siska_vfs.h" + +// super block, 512 +// inode, 244 * 8 * sizeof(inode_dev) +// block, 244 * 8 * (1024 << sblock_dev->block_size) + +#define SISKA_FS0_NB_INODES (16u << 3) +#define SISKA_FS0_NB_BLOCKS (16u << 3) +#define SISKA_FS0_INODE_START (sizeof(siska_sblock_dev_t)) +#define SISKA_FS0_BLOCK_START (sizeof(siska_sblock_dev_t) + SISKA_FS0_NB_INODES * sizeof(siska_inode_dev_t)) + +struct siska_sblock_dev_s +{ + unsigned char magic[7]; + unsigned char block_size; + + union { + unsigned long next; + unsigned char fill[8]; + }; + + unsigned char inode_map[SISKA_FS0_NB_INODES >> 3]; + unsigned char block_map[SISKA_FS0_NB_BLOCKS >> 3]; + unsigned char reserved[8]; +}; + +struct siska_inode_dev_s +{ + union { + unsigned long size; + unsigned char fill0[8]; + }; +#define SISKA_INODE_NAME_OFFSET (1u << 29) + union { + unsigned long mode; + unsigned char fill1[8]; + }; + + union { + unsigned long block_offset; + unsigned char fill2[8]; + }; + + union { + unsigned long block_count; + unsigned char fill3[8]; + }; + + union { + unsigned long inode_parent; + unsigned char fill4[8]; + }; + + union { + unsigned long name_parent_offset; + unsigned char name[8]; + }; +}; + +typedef struct siska_dir_dev_s siska_dir_dev_t; + +struct siska_dir_dev_s +{ + union { + unsigned long inode_index; + unsigned char fill0[8]; + }; + + union { + unsigned long name_len; + unsigned char fill1[8]; + }; + + unsigned char name[0]; // string ended by '\0' +}; + +#endif + diff --git a/siska_fs0.c b/siska_fs0.c new file mode 100644 index 0000000..b129911 --- /dev/null +++ b/siska_fs0.c @@ -0,0 +1,919 @@ +#include"siska_vfs.h" +#include"siska_fs.h" +#include"siska_mm.h" + +extern siska_vfs_t siska_fs_siska0; + +int siska0_find_in_dir(siska_dir_dev_t* dir_dev, siska_inode_dev_t* inode_dev, const char* filename, siska_fs_t* fs) +{ + unsigned long block_size; + unsigned long offset; + unsigned long i; + + block_size = 1024 << fs->sblock->sblock_dev->block_size; + + offset = SISKA_FS0_BLOCK_START + inode_dev->block_offset * block_size; + + int ret = fs->dev->fops->lseek(fs->dir, offset, SISKA_SEEK_SET); + if (ret < 0) + return -1; + + siska_printk("%s(), %d, filename: %s\n", __func__, __LINE__, filename); +// siska_printk("%s(), %d, offset: %d, block_offset: %d, block_size: %d\n", __func__, __LINE__, offset, inode_dev->block_offset, block_size); + + siska_printk("%s(), %d, inode_dev->size: %d\n", __func__, __LINE__, inode_dev->size); + + for (i = 0; i < inode_dev->size; ) { + + ret = fs->dev->fops->read(fs->dir, dir_dev, sizeof(siska_dir_dev_t)); + if (ret != sizeof(siska_dir_dev_t)) + return -1; + i += ret; + + if (i + dir_dev->name_len > inode_dev->size) + return -1; + + char* name = siska_kmalloc(dir_dev->name_len); + if (!name) + return -1; + + ret = fs->dev->fops->read(fs->dir, name, dir_dev->name_len); + if (ret != dir_dev->name_len) { + siska_kfree(name); + return -1; + } + i += ret; + + if (!siska_strcmp(filename, name)) { + siska_printk("%s(), %d, filename: %s, name: %s\n", __func__, __LINE__, filename, name); + siska_kfree(name); + return 0; + } + + siska_kfree(name); + } + + siska_printk("%s(), %d, inode_dev->size: %d\n", __func__, __LINE__, inode_dev->size); + return -404; +} + +int siska0_read_inode(siska_file_t* file, siska_fs_t* fs, siska_inode_dev_t* inode_dev, unsigned long index) +{ + siska_inode_t* inode; + unsigned long offset; + + offset = SISKA_FS0_INODE_START + index * sizeof(siska_inode_dev_t); + + int ret = fs->dev->fops->lseek(fs->dir, offset, SISKA_SEEK_SET); + if (ret < 0) + return -1; + + ret = fs->dev->fops->read(fs->dir, inode_dev, sizeof(siska_inode_dev_t)); + if (ret != sizeof(siska_inode_dev_t)) + return -1; + + inode = siska_inode_alloc(); + if (!inode) + return -1; + + inode->file = file; + inode->sblock = fs->sblock; + inode->index = index; + inode->inode_dev = inode_dev; + + file->inode = inode; + return 0; +} + +static unsigned long __siska0_find_blocks(siska_sblock_dev_t* sblock_dev, unsigned int nblocks) +{ + unsigned long block_index = 0; + unsigned long k = 0; + unsigned long i; + unsigned long j; + + for (i = 0; i < sizeof(sblock_dev->block_map); i++) { + + for (j = 0; j < 8; j++) { + + if (sblock_dev->block_map[i] & (1u << j)) { + k = 0; + continue; + } + + if (0 == k) + block_index = i * 8 + j; + + if (++k == nblocks) + return block_index; + } + } + return 0; +} + +static void __siska0_blocks_set_used(siska_sblock_dev_t* sbd, unsigned long block_index, unsigned int nblocks) +{ + unsigned long i; + unsigned long j; + unsigned long k; + + for (k = 0; k < nblocks; k++) { + i = (block_index + k) >> 3; + j = (block_index + k) & 0x7; + + sbd->block_map[i] |= 1u << j; + } +} + +static void __siska0_blocks_set_free(siska_sblock_dev_t* sbd, unsigned long block_index, unsigned int nblocks) +{ + unsigned long i; + unsigned long j; + unsigned long k; + + for (k = 0; k < nblocks; k++) { + i = (block_index + k) >> 3; + j = (block_index + k) & 0x7; + + sbd->block_map[i] &= ~(1u << j); + } +} + +static int __siska0_realloc_blocks(siska_fs_t* fs, siska_sblock_dev_t* sbd, siska_inode_dev_t* inode_dev, unsigned long append_size) +{ + unsigned long block_size = 1024 << sbd->block_size; + + unsigned long empty_len = inode_dev->block_count * block_size - inode_dev->size; + + if (empty_len >= append_size) + return 0; + + empty_len = append_size - empty_len; + + unsigned long nblocks = (empty_len + block_size - 1) / block_size; + + unsigned long block_index = inode_dev->block_offset + inode_dev->block_count; + unsigned long i; + unsigned long j; + unsigned long k; + + for (k = 0; k < nblocks; k++) { + i = (block_index + k) / 8; + j = (block_index + k) % 8; + + if (sbd->block_map[i] & (1u << j)) + break; + } + + if (k == nblocks) { + + __siska0_blocks_set_used(sbd, block_index, nblocks); + + inode_dev->block_count += nblocks; + return 0; + } + + nblocks += inode_dev->block_count; + + block_index = __siska0_find_blocks(sbd, nblocks); + if (0 == block_index) + return -1; + + char* buf = siska_kmalloc(1024); + if (!buf) + return -1; + + for (i = 0; i < inode_dev->size; ) { + + unsigned long offset; + + offset = SISKA_FS0_BLOCK_START + inode_dev->block_offset * block_size; + offset += i; + int ret = fs->dev->fops->lseek(fs->dir, offset, SISKA_SEEK_SET); + if (ret < 0) { + siska_kfree(buf); + return -1; + } + + k = inode_dev->size - i; + k = k > 1024 ? 1024 : k; + ret = fs->dev->fops->read(fs->dir, buf, k); + if (ret != k) { + siska_kfree(buf); + return -1; + } + + offset = SISKA_FS0_BLOCK_START + block_index * block_size; + offset += i; + ret = fs->dev->fops->lseek(fs->dir, offset, SISKA_SEEK_SET); + if (ret < 0) { + siska_kfree(buf); + return -1; + } + + ret = fs->dev->fops->read(fs->dir, buf, k); + if (ret != k) { + siska_kfree(buf); + return -1; + } + + i += k; + } + + siska_kfree(buf); + buf = NULL; + + __siska0_blocks_set_free(sbd, inode_dev->block_offset, inode_dev->block_count); + + __siska0_blocks_set_used(sbd, block_index, nblocks); + + inode_dev->block_offset = block_index; + inode_dev->block_count = nblocks; + return 0; +} + +int siska0_write_dir(siska_file_t* file, siska_fs_t* fs, siska_inode_dev_t* parent, unsigned long parent_index) +{ + siska_dir_dev_t* dir_dev; + unsigned long block_size; + unsigned long offset; + unsigned long i; + + unsigned long empty_pos = 0; + unsigned long empty_len = 0; + unsigned long filename_len = siska_strlen(file->name) + 1; + + dir_dev = siska_kmalloc(sizeof(siska_dir_dev_t)); + if (!dir_dev) + return -1; + + block_size = 1024 << fs->sblock->sblock_dev->block_size; + + offset = SISKA_FS0_BLOCK_START + parent->block_offset * block_size; + + int ret = fs->dev->fops->lseek(fs->dir, offset, SISKA_SEEK_SET); + if (ret < 0) + goto _error; + + for (i = 0; i < parent->size; ) { + + ret = fs->dev->fops->read(fs->dir, dir_dev, sizeof(siska_dir_dev_t)); + if (ret != sizeof(siska_dir_dev_t)) + goto _error; + i += ret; + + if (i + dir_dev->name_len > parent->size) + goto _error; + + if (0 == dir_dev->inode_index && dir_dev->name_len >= filename_len) { + if (empty_len > dir_dev->name_len) { + empty_len = dir_dev->name_len; + empty_pos = i - ret; + } + } + + char* name = siska_kmalloc(dir_dev->name_len); + if (!name) + goto _error; + + ret = fs->dev->fops->read(fs->dir, name, dir_dev->name_len); + if (ret != dir_dev->name_len) { + siska_kfree(name); + goto _error; + } + i += ret; + + if (!siska_strcmp(file->name, name)) { + siska_kfree(name); + goto _error; + } + + siska_kfree(name); + } + + if (0 == empty_len) { + + unsigned long append_size = filename_len + sizeof(siska_dir_dev_t); + + ret = __siska0_realloc_blocks(fs, fs->sblock->sblock_dev, parent, append_size); + if (ret < 0) + goto _error; + + empty_len = parent->block_count * block_size - parent->size; + empty_pos = parent->size; + } + + if (empty_len > 0) { + offset = SISKA_FS0_BLOCK_START + parent->block_offset * block_size; + offset += empty_pos; + + ret = fs->dev->fops->lseek(fs->dir, offset, SISKA_SEEK_SET); + if (ret < 0) + goto _error; + + dir_dev->inode_index = file->inode->index; + dir_dev->name_len = filename_len; + + ret = fs->dev->fops->write(fs->dir, dir_dev, sizeof(siska_dir_dev_t)); + if (ret != sizeof(siska_dir_dev_t)) + goto _error; + + ret = fs->dev->fops->write(fs->dir, file->name, filename_len); + if (ret != filename_len) + goto _error; + + if (empty_pos == parent->size) + parent->size += sizeof(siska_dir_dev_t) + filename_len; + + siska_printk("%s(), %d, parent->size: %d\n", __func__, __LINE__, parent->size); + + offset = SISKA_FS0_INODE_START + sizeof(siska_inode_dev_t) * parent_index; + ret = fs->dev->fops->lseek(fs->dir, offset, SISKA_SEEK_SET); + if (ret < 0) + goto _error; + + ret = fs->dev->fops->write(fs->dir, parent, sizeof(siska_inode_dev_t)); + if (ret != sizeof(siska_inode_dev_t)) + goto _error; + return 0; + } + +_error: + siska_kfree(dir_dev); + return -1; +} + +int siska0_create_inode(siska_file_t* file, siska_fs_t* fs, siska_inode_dev_t* parent, unsigned long parent_index) +{ + siska_sblock_dev_t* sblock_dev; + siska_sblock_t* sblock; + + siska_inode_dev_t* inode_dev; + siska_inode_t* inode; + + unsigned long i; + unsigned long j; + unsigned long index; + + sblock = fs->sblock; + + while (sblock) { + + sblock_dev = sblock->sblock_dev; + + for (i = 0; i < sizeof(sblock_dev->inode_map); i++) { + + if (0xff == sblock_dev->inode_map[i]) + continue; + + for (j = 0; j < 8; j++) { + + if (0 == i && 0 == j) + continue; + + if (!(sblock_dev->inode_map[i] & (1u << j))) + goto _found; + } + } + + sblock = sblock->next; + } + return -1; + +_found: + inode = siska_inode_alloc(); + if (!inode) + return -1; + + inode_dev = siska_kmalloc(sizeof(siska_inode_dev_t)); + if (!inode_dev) { + siska_inode_free(inode); + return -1; + } + + inode_dev->size = 0; + inode_dev->block_offset = 0; + inode_dev->block_count = 0; + + if (file->parent->fs == fs) + inode_dev->inode_parent = 0; + else + inode_dev->inode_parent = file->parent->inode->index; + + inode_dev->name_parent_offset = 0; + + inode->index = i * 8 + j; + inode->file = file; + inode->sblock = sblock; + inode->inode_dev = inode_dev; + + file->inode = inode; + + if (siska0_write_dir(file, fs, parent, parent_index) < 0) { + siska_inode_free(inode); + return -1; + } + + sblock_dev->inode_map[i] |= 1u << j; + + int ret = fs->dev->fops->lseek(fs->dir, 0, SISKA_SEEK_SET); + if (ret < 0) { + siska_inode_free(inode); + return -1; + } + + ret = fs->dev->fops->write(fs->dir, sblock_dev, sizeof(siska_sblock_dev_t)); + if (ret != sizeof(siska_sblock_dev_t)) { + siska_inode_free(inode); + return -1; + } + + inode->next = sblock->inodes; + sblock->inodes = inode; + return 0; +} + +int siska0_open_in_sblock(siska_file_t* file, siska_fs_t* fs, int flags, unsigned int mode) +{ + siska_inode_dev_t* inode_dev; + siska_dir_dev_t* dir_dev; + unsigned long block_size; + + inode_dev = siska_kmalloc(sizeof(siska_inode_dev_t)); + if (!inode_dev) + return -1; + + dir_dev = siska_kmalloc(sizeof(siska_dir_dev_t)); + if (!dir_dev) { + siska_kfree(inode_dev); + return -1; + } + + // read first inode + int ret = fs->dev->fops->lseek(fs->dir, SISKA_FS0_INODE_START, SISKA_SEEK_SET); + if (ret < 0) + goto _error; + + ret = fs->dev->fops->read(fs->dir, inode_dev, sizeof(siska_inode_dev_t)); + if (ret != sizeof(siska_inode_dev_t)) + goto _error; + + siska_printk("%s(), %d, inode_dev->size: %d\n", __func__, __LINE__, inode_dev->size); + + // read sub dirs of fs rootdir + ret = siska0_find_in_dir(dir_dev, inode_dev, file->name, fs); + if (-1 == ret) + goto _error; + + if (-404 == ret) { + siska_printk("%s(), %d, file->name: %s, ret: %d\n", __func__, __LINE__, file->name, ret); + + ret = siska0_create_inode(file, fs, inode_dev, 0); + + siska_printk("%s(), %d, file->name: %s, ret: %d\n", __func__, __LINE__, file->name, ret); + } else { + ret = siska0_read_inode(file, fs, inode_dev, dir_dev->inode_index); + + siska_printk("%s(), %d, file->name: %s, ret: %d\n", __func__, __LINE__, file->name, ret); + } + + if (ret < 0) + goto _error; + + siska_kfree(dir_dev); + return 0; + +_error: + siska_kfree(inode_dev); + siska_kfree(dir_dev); + return -1; +} + +int siska0_recursive_open(siska_file_t* file, siska_fs_t* fs, int flags, unsigned int mode) +{ + if (!file->parent) + return -1; + + siska_printk("%s(), %d, file->name: %s, type: %d\n", __func__, __LINE__, file->name, siska_file_type(file)); + + if (file->parent->fs == fs) + return siska0_open_in_sblock(file, fs, flags, mode); + + if (!file->parent->inode || !file->parent->inode->inode_dev) { + + int ret = siska0_recursive_open(file->parent, fs, file->parent->flags, 0); + if (ret < 0) { + siska_printk("%s(), %d, file->parent: %s\n", __func__, __LINE__, file->parent->name); + return -1; + } + } + + siska_inode_dev_t* inode_dev; + siska_dir_dev_t* dir_dev; + + dir_dev = siska_kmalloc(sizeof(siska_dir_dev_t)); + if (!dir_dev) + return -1; + + int ret = siska0_find_in_dir(dir_dev, file->parent->inode->inode_dev, file->name, fs); + if (-1 == ret) { + siska_kfree(dir_dev); + return -1; + } + + siska_printk("%s(), %d, ret: %d, file->name: %s, type: %d\n", __func__, __LINE__, ret, file->name, siska_file_type(file)); + + if (-404 == ret) { + + ret = siska0_create_inode(file, fs, file->parent->inode->inode_dev, file->parent->inode->index); + + } else { + inode_dev = siska_kmalloc(sizeof(siska_inode_dev_t)); + if (!inode_dev) { + siska_kfree(dir_dev); + return -1; + } + + ret = siska0_read_inode(file, fs, inode_dev, dir_dev->inode_index); + if (ret < 0) + siska_kfree(inode_dev); + } + + siska_kfree(dir_dev); + return ret; +} + +int siska0_open(siska_file_t* file, int flags, unsigned int mode) +{ + if (!file || !file->name) + return -1; + + siska_fs_t* fs; + + fs = siska_vfs_find_fs(file->parent); + if (!fs) + return -1; + + if (!fs->sblock || !fs->sblock->sblock_dev) + return -1; + + if (siska_strncmp(fs->sblock->sblock_dev->magic, "siska00", 7)) + return -1; + + return siska0_recursive_open(file, fs, flags, mode); +} + +int siska0_close(siska_file_t* file) +{ + return 0; +} + +int siska0_read(siska_file_t* file, void* buf, int size) +{ + if (!file || !buf || size < 0) + return -1; + + if (!file->inode || !file->inode->inode_dev) + return -1; + + if (0 == size) + return 0; + + siska_fs_t* fs; + + fs = siska_vfs_find_fs(file->parent); + if (!fs) + return -1; + + siska_sblock_dev_t* sblock_dev = file->inode->sblock->sblock_dev; + siska_inode_dev_t* inode_dev = file->inode->inode_dev; + + if (size > inode_dev->size - file->offset) + size = inode_dev->size - file->offset; + + if (0 == size) + return 0; + + unsigned long block_size = 1024u << sblock_dev->block_size; + + unsigned long offset = SISKA_FS0_BLOCK_START + + inode_dev->block_offset * block_size + + file->offset; + + int ret = fs->dev->fops->lseek(fs->dir, offset, SISKA_SEEK_SET); + if (ret < 0) + return -1; + + ret = fs->dev->fops->read(fs->dir, buf, size); + if (ret != size) + return -1; + + file->offset += size; + return ret; +} + +int siska0_write(siska_file_t* file, const void* buf, int size) +{ + if (!file || !buf || size < 0) + return -1; + + if (!file->inode || !file->inode->inode_dev) + return -1; + + if (0 == size) + return 0; + + siska_fs_t* fs; + + fs = siska_vfs_find_fs(file->parent); + if (!fs) + return -1; + + siska_sblock_dev_t* sblock_dev = file->inode->sblock->sblock_dev; + siska_inode_dev_t* inode_dev = file->inode->inode_dev; + + unsigned long block_size = 1024u << sblock_dev->block_size; + unsigned long nblocks = (file->offset + size + block_size - 1) / block_size; + + if (0 == inode_dev->block_offset) { + + inode_dev->block_offset = __siska0_find_blocks(sblock_dev, nblocks); + + if (0 == inode_dev->block_offset) + return -1; + + inode_dev->block_count = nblocks; + + __siska0_blocks_set_used(sblock_dev, inode_dev->block_offset, nblocks); + + } else if (nblocks > inode_dev->block_count) { + + unsigned long append_size = (nblocks - inode_dev->block_count) * block_size; + + int ret = __siska0_realloc_blocks(fs, sblock_dev, inode_dev, append_size); + if (ret < 0) + return -1; + } + + unsigned long offset = SISKA_FS0_BLOCK_START + + inode_dev->block_offset * block_size + + file->offset; + + int ret = fs->dev->fops->lseek(fs->dir, offset, SISKA_SEEK_SET); + if (ret < 0) + return -1; + + ret = fs->dev->fops->write(fs->dir, buf, size); + if (ret != size) + return -1; + + if (inode_dev->size < file->offset + size) + inode_dev->size = file->offset + size; + + offset = SISKA_FS0_INODE_START + sizeof(siska_inode_dev_t) * file->inode->index; + ret = fs->dev->fops->lseek(fs->dir, offset, SISKA_SEEK_SET); + if (ret < 0) + return -1; + + ret = fs->dev->fops->write(fs->dir, inode_dev, sizeof(siska_inode_dev_t)); + if (ret != sizeof(siska_inode_dev_t)) + return -1; + siska_printk("%s(), %d, file->inode->index: %d, inode_dev->size: %d\n", + __func__, __LINE__, file->inode->index, inode_dev->size); + + ret = fs->dev->fops->lseek(fs->dir, 0, SISKA_SEEK_SET); + if (ret < 0) + return -1; + + ret = fs->dev->fops->write(fs->dir, sblock_dev, sizeof(siska_sblock_dev_t)); + if (ret != sizeof(siska_sblock_dev_t)) + return -1; + + file->offset += size; + return ret; +} + +int siska0_lseek(siska_file_t* file, long offset, int whence) +{ + if (!file || offset < 0 || SISKA_SEEK_SET != whence) + return -1; + + file->offset = offset; + return offset; +} + +int siska0_sync(siska_file_t* file) +{ + return -1; +} + +int siska0_ioctl(siska_file_t* file, unsigned long cmd, ...) +{ + return -1; +} + +siska_file_ops_t siska_fops_siska0 = +{ + .type = "siska0", + .next = NULL, + + .open = siska0_open, + .close = siska0_close, + .read = siska0_read, + .write = siska0_write, + .lseek = siska0_lseek, + .sync = siska0_sync, + .ioctl = siska0_ioctl, +}; + +int siska0_mkfs(siska_file_t* devfile) +{ + siska_sblock_dev_t* sblock_dev; + siska_inode_dev_t* inode_dev; + + siska_dev_t* dev; + + if (!devfile || !devfile->dev) + return -1; + + dev = devfile->dev; + + if (!dev->fops->write || !dev->fops->lseek) + return -1; + + int size = sizeof(siska_sblock_dev_t) + sizeof(siska_inode_dev_t); + + sblock_dev = siska_kmalloc(size); + if (!sblock_dev) + return -1; + + inode_dev = (siska_inode_dev_t*)((char*)sblock_dev + sizeof(siska_sblock_dev_t)); + + sblock_dev->magic[0] = 's'; + sblock_dev->magic[1] = 'i'; + sblock_dev->magic[2] = 's'; + sblock_dev->magic[3] = 'k'; + sblock_dev->magic[4] = 'a'; + sblock_dev->magic[5] = '0'; + sblock_dev->magic[6] = '0'; + + sblock_dev->block_size = 0; + sblock_dev->next = 0; + + siska_memset(sblock_dev->inode_map, 0, sizeof(sblock_dev->inode_map)); + siska_memset(sblock_dev->block_map, 0, sizeof(sblock_dev->block_map)); + + sblock_dev->inode_map[0] |= 0x1; + sblock_dev->block_map[0] |= 0x1; + + inode_dev->size = 0; + inode_dev->mode = 0x777; + inode_dev->block_offset = 0; + inode_dev->block_count = 1; + inode_dev->inode_parent = 0xffffffff; + inode_dev->name[0] = 'r'; + inode_dev->name[1] = 'o'; + inode_dev->name[2] = 'o'; + inode_dev->name[3] = 't'; + inode_dev->name[4] = 'd'; + inode_dev->name[5] = 'i'; + inode_dev->name[6] = 'r'; + inode_dev->name[7] = '\0'; + + int ret = dev->fops->lseek(devfile, 0, SISKA_SEEK_SET); + if (ret < 0) + return -1; + + ret = dev->fops->write(devfile, sblock_dev, size); + if (ret != size) + return -1; + + return 0; +} + +int siska0_mount(siska_fs_t** pfs, siska_file_t* dir, siska_dev_t* dev) +{ + siska_sblock_dev_t* sblock_dev; + siska_sblock_t* sblock; + + siska_inode_dev_t* inode_dev; + siska_inode_t* inode; + + siska_fs_t* fs; + int ret; + + if (!pfs || !dir || !dev || !dev->fops) + return -1; + + if (!dev->fops->read || !dev->fops->lseek) + return -1; + + if (!siska_list_empty(&dir->childs)) + return -1; + + fs = siska_kmalloc(sizeof(siska_fs_t)); + if (!fs) + return -1; + + dir->dev = dev; + + fs->dir = dir; + fs->dev = dev; + fs->vfs = &siska_fs_siska0; + fs->fops = &siska_fops_siska0; + fs->sblock = NULL; + + if (dev->fops->open) { + ret = dev->fops->open(dir, SISKA_FILE_FLAG_R | SISKA_FILE_FLAG_W, 0); + if (ret < 0) { + siska_printk("fs open dev error"); + goto _open_dev; + } + } + + unsigned long number = 0; + unsigned long block_offset = 0; + while (1) { + sblock = siska_sblock_alloc(); + if (!sblock) { + siska_printk("fs sblock error"); + goto _error; + } + + sblock_dev = siska_kmalloc(sizeof(siska_sblock_dev_t)); + if (!sblock_dev) { + siska_printk("fs sblock dev error"); + + siska_kfree(sblock); + goto _error; + } + sblock->sblock_dev = sblock_dev; + sblock->number = number++; + + siska_sblock_t** pp = &fs->sblock; + while (*pp) + pp = &(*pp)->next; + *pp = sblock; + + ret = dev->fops->read(dir, sblock_dev, sizeof(siska_sblock_dev_t)); + if (ret != sizeof(siska_sblock_dev_t)) { + siska_printk("fs sblock read error"); + goto _error; + } + + if (siska_strncmp(sblock_dev->magic, "siska00", 7)) { + siska_printk("fs magic error"); + goto _error; + } + + if (0 == sblock_dev->next) + break; + + block_offset += sizeof(siska_sblock_dev_t); + block_offset += sizeof(siska_inode_dev_t) * 8 * sizeof(sblock_dev->inode_map); + block_offset += (1024 << sblock_dev->block_size) * 8 * sizeof(sblock_dev->block_map); + block_offset += sizeof(siska_sblock_dev_t); + + ret = dev->fops->lseek(dir, block_offset, SISKA_SEEK_SET); + if (ret != block_offset) { + siska_printk("fs sblock seek error"); + goto _error; + } + } + + *pfs = fs; + return 0; + +_error: + while (fs->sblock) { + sblock = fs->sblock; + fs->sblock = sblock->next; + + siska_sblock_free(sblock); + } +_close_dev: + if (dev->fops->close) + dev->fops->close(dir); + dir->dev = NULL; +_open_dev: + siska_kfree(fs); + return -1; +} + +int siska0_umount(siska_file_t* dir) +{ + return 0; +} + +siska_vfs_t siska_fs_siska0 = +{ + .name = "siska0", + + .next = NULL, + + .mkfs = siska0_mkfs, + + .mount = siska0_mount, + .umount = siska0_umount, +}; + diff --git a/siska_list.h b/siska_list.h new file mode 100644 index 0000000..6f1f2dd --- /dev/null +++ b/siska_list.h @@ -0,0 +1,71 @@ +#ifndef SISKA_LIST_H +#define SISKA_LIST_H + +#include"siska_def.h" + +typedef struct siska_list_s siska_list_t; + +struct siska_list_s { + struct siska_list_s* prev; + struct siska_list_s* next; +}; + +static inline void siska_list_init(siska_list_t* h) +{ + h->prev = h; + h->next = h; +} + +static inline void siska_list_del(siska_list_t* n) +{ + n->prev->next = n->next; + n->next->prev = n->prev; + + // only to avoid some wrong operations for these 2 invalid pointers + n->prev = NULL; + n->next = NULL; +} + +static inline void siska_list_add_tail(siska_list_t* h, siska_list_t* n) +{ + h->prev->next = n; + n->prev = h->prev; + n->next = h; + h->prev = n; +} + +static inline void siska_list_add_front(siska_list_t* h, siska_list_t* n) +{ + h->next->prev = n; + n->next = h->next; + n->prev = h; + h->next = n; +} + +#define SISKA_LIST_INIT(h) {&h, &h} + +#define siska_offsetof(type, member) ((char*) &((type*)0)->member) + +#define siska_list_data(l, type, member) ((type*)((char*)l - siska_offsetof(type, member))) + +#define siska_list_head(h) ((h)->next) +#define siska_list_tail(h) ((h)->prev) +#define siska_list_sentinel(h) (h) +#define siska_list_next(l) ((l)->next) +#define siska_list_prev(l) ((l)->prev) +#define siska_list_empty(h) ((h)->next == (h)) + +#define siska_list_clear(h, type, member, type_free) \ + do {\ + siska_list_t* l;\ + for (l = siska_list_head(h); l != siska_list_sentinel(h);) {\ + type* t = siska_list_data(l, type, member);\ + l = siska_list_next(l);\ + siska_list_del(&t->member);\ + type_free(t);\ + t = NULL;\ + }\ + } while(0) + +#endif + diff --git a/siska_mm.c b/siska_mm.c new file mode 100644 index 0000000..ddc6e8d --- /dev/null +++ b/siska_mm.c @@ -0,0 +1,730 @@ +#if 0 +#include +#include +#include +#endif + +#include"siska_mm.h" +#include"siska_task.h" + +#define SISKA_KERNEL_SIZE (128 * 1024) + +#define SISKA_MM_EXT_PTR 0x90002 +#define SISKA_MM_EXT_KB (*(volatile unsigned short*)SISKA_MM_EXT_PTR) +//#define SISKA_MM_EXT_KB (4 * 4) +#define SISKA_MM_EXT_MAX_KB (15 * 1024) + +siska_page_t* siska_pages = (siska_page_t*)(1UL << 20); +unsigned long siska_total_pages = 0; +unsigned long siska_used_pages = 0; + +#define BLOCK_SHIFT_MIN 5 +static siska_block_head_t siska_block_heads[PG_SHIFT]; + +static unsigned long base = 0; + +static inline int siska_block_is_used(siska_block_t* b) +{ + return b->size_used & 0x1; +} + +static inline void siska_block_set_used(siska_block_t* b) +{ + b->size_used |= 0x1; +} + +static inline long siska_block_get_shift(long size) +{ + long n; + asm volatile( + "bsr %1, %0" + :"=r"(n) + :"r"(size) + : + ); + + return n; +} + +static inline siska_block_t* siska_block_head(void* p) +{ + return (siska_block_t*)((unsigned long)p - sizeof(long)); +} + +static inline void* siska_block_data(siska_block_t* b) +{ + return (void*)((unsigned long)b + sizeof(long)); +} + +static inline long siska_block_size(siska_block_t* b) +{ + long used = b->size_used & 0x1; + return used ? b->size_used & ~0x1 : b->size_free; +} + +static inline long siska_block_data_size(siska_block_t* b) +{ + long used = b->size_used & 0x1; + return used ? (b->size_used & ~0x1) - sizeof(long) : 0; +} + +static inline long siska_block_need_shift(long size) +{ + size += sizeof(long); + long n; + asm volatile( + "bsr %1, %0" + :"=r"(n) + :"r"(size) + : + ); + + n += !!(size & ~(1u << n)); + return n; +} + +void siska_mm_init() +{ + siska_block_head_t* bh; + + unsigned long i; + unsigned long mm_ext_KB = SISKA_MM_EXT_KB; + + if (mm_ext_KB > SISKA_MM_EXT_MAX_KB) + mm_ext_KB = SISKA_MM_EXT_MAX_KB; + + siska_total_pages = (1024 + mm_ext_KB) >> (PG_SHIFT - 10); + + siska_used_pages = (siska_total_pages * sizeof(siska_page_t) + PG_SIZE - 1) >> PG_SHIFT; + siska_used_pages += 1u << 20 >> PG_SHIFT; + +// siska_printk("siska_pages: %p, total_pages: %d, used_pages: %d\n", siska_pages, siska_total_pages, siska_used_pages); + + for (i = 0; i < siska_total_pages; i++) { + + siska_spinlock_init(&(siska_pages[i].lock)); + + if (i < siska_used_pages) + siska_pages[i].refs = 1; + else + siska_pages[i].refs = 0; + } + + for (i = 0; i < PG_SHIFT; i++) { + bh = &siska_block_heads[i]; + + siska_list_init(&bh->head); + siska_spinlock_init(&bh->lock); + } +} + +int siska_get_free_pages(siska_page_t** pages, int nb_pages) +{ + siska_page_t* pg; + siska_page_t* pg2; + int i; + int j; + + for (i = siska_used_pages; i + nb_pages < siska_total_pages; i += nb_pages) { + + pg = siska_pages + i; + + unsigned long flags; + siska_irqsave(flags); + + for (j = 0; j < nb_pages; j++) { + pg2 = pg + j; + + siska_spin_lock(&pg2->lock); + if (pg2->refs > 0) { + siska_spin_unlock(&pg2->lock); + break; + } + + pg2->refs++; + } + + if (j < nb_pages) { + for (--j; j >= 0; j--) { + pg2 = pg + j; + pg2->refs--; + siska_spin_unlock(&pg2->lock); + } + siska_irqrestore(flags); + + } else { + for (--j; j >= 0; j--) { + pg2 = pg + j; + siska_spin_unlock(&pg2->lock); + } + siska_irqrestore(flags); + + *pages = pg; + return nb_pages; + } + } + + return -1; +} + +int siska_free_pages(siska_page_t* pages, int nb_pages) +{ + siska_page_t* pg; + int i; + + for (i = 0; i < nb_pages; i++) { + pg = pages + i; + + unsigned long flags; + siska_spin_lock_irqsave(&pg->lock, flags); + pg->refs--; + siska_spin_unlock_irqrestore(&pg->lock, flags); + } + return 0; +} + +void* siska_kmalloc(int size) +{ + if (size + sizeof(long) > (PG_SIZE >> 1)) + return NULL; + + siska_block_head_t* bh; + siska_block_t* b; + siska_block_t* b2; + siska_list_t* l; + + long shift; + long i; + + shift = siska_block_need_shift(size); + + shift = shift < BLOCK_SHIFT_MIN ? BLOCK_SHIFT_MIN : shift; + + bh = &siska_block_heads[shift]; + + unsigned long flags; + siska_spin_lock_irqsave(&bh->lock, flags); + if (!siska_list_empty(&bh->head)) { + + l = siska_list_head(&bh->head); + b = siska_list_data(l, siska_block_t, list); + + siska_list_del(&b->list); + siska_spin_unlock_irqrestore(&bh->lock, flags); + + b->size_used = 1u << shift; + siska_block_set_used(b); + + return siska_block_data(b); + } + siska_spin_unlock_irqrestore(&bh->lock, flags); + + for (i = shift + 1; i < PG_SHIFT; i++) { + bh = &siska_block_heads[i]; + + siska_spin_lock_irqsave(&bh->lock, flags); + if (siska_list_empty(&bh->head)) { + siska_spin_unlock_irqrestore(&bh->lock, flags); + continue; + } + + l = siska_list_head(&bh->head); + b = siska_list_data(l, siska_block_t, list); + + siska_list_del(&b->list); + siska_spin_unlock_irqrestore(&bh->lock, flags); + + long j; + for (j = i - 1; j >= shift; j--) { + bh = &siska_block_heads[j]; + + b2 = (siska_block_t*)((unsigned long)b + (1u << j)); + b->size_free = 1u << j; + + siska_spin_lock_irqsave(&bh->lock, flags); + siska_list_add_front(&bh->head, &b->list); + siska_spin_unlock_irqrestore(&bh->lock, flags); + b = b2; + } + + b->size_used = 1u << shift; + siska_block_set_used(b); + + return siska_block_data(b); + } + + siska_page_t* pg = NULL; + if (siska_get_free_pages(&pg, 1) < 0) + return NULL; + + b = (siska_block_t*) siska_page_addr(pg); + +// printf("%s(), %d, b: %p, size: %ld, shift: %ld, pg: %p\n", __func__, __LINE__, b, size, shift, pg); + + for (i = PG_SHIFT - 1; i >= shift; i--) { + bh = &siska_block_heads[i]; + + b2 = (siska_block_t*)((unsigned long)b + (1u << i)); + +// printf("%s(), %d, b2: %p, size: %ld, shift: %ld\n", __func__, __LINE__, b2, 1u << i, i); + b->size_free = 1u << i; + + siska_spin_lock_irqsave(&bh->lock, flags); + siska_list_add_front(&bh->head, &b->list); + siska_spin_unlock_irqrestore(&bh->lock, flags); + b = b2; + } + + b->size_used = 1u << shift; + siska_block_set_used(b); + + return siska_block_data(b); +} + +void siska_memset(void* dst, unsigned long data, unsigned long size) +{ + asm volatile( + "movl %0, %%ecx\n\t" + "movl %1, %%edi\n\t" + "movl %2, %%eax\n\t" + "cld\n\t" + "rep stosb\n\t" + : + :"r"(size), "r"(dst), "r"(data) + :"ecx", "edi", "eax" + ); +} + +void siska_memcpy(void* dst, const void* src, unsigned long size) +{ + asm volatile( + "movl %0, %%ecx\n\t" + "movl %1, %%edi\n\t" + "movl %2, %%esi\n\t" + "cld\n\t" + "rep movsb\n\t" + : + :"r"(size), "r"(dst), "r"(src) + :"ecx", "edi", "esi" + ); +} + +void* siska_krealloc(void* p, int size) +{ + if (size <= 0) { + siska_kfree(p); + return NULL; + } + + if (size + sizeof(long) > (PG_SIZE >> 1)) + return NULL; + + siska_block_t* b = siska_block_head(p); +// printf("b: %p\n", b); + long old_datasize = siska_block_data_size(b); + + if (old_datasize < size) { + void* p2 = siska_kmalloc(size); + if (!p2) + return NULL; + + siska_memcpy(p2, p, size); + siska_kfree(p); + return p2; + + } else if (old_datasize == size) + return p; + + long old_size = siska_block_size(b); + long old_shift = siska_block_get_shift(old_size); + long new_shift = siska_block_need_shift(size); + +// printf("%s(), %d, b: %p, size: %ld, shift: %ld\n", __func__, __LINE__, b, size, old_shift); + + long i; + for (i = old_shift - 1; i >= new_shift; i--) { + + siska_block_head_t* bh; + siska_block_t* b2; + + bh = &siska_block_heads[i]; + + b2 = (siska_block_t*)((unsigned long)b + (1u << i)); + b2->size_free = 1u << i; + +// printf("%s(), %d, b2: %p, shift i: %ld\n", __func__, __LINE__, b, i); + + unsigned long flags; + siska_spin_lock_irqsave(&bh->lock, flags); + siska_list_add_front(&bh->head, &b2->list); + siska_spin_unlock_irqrestore(&bh->lock, flags); + } + + b->size_used = 1u << new_shift; + siska_block_set_used(b); + return p; +} + +void siska_kfree(void* p) +{ + if (!p) + return; + + siska_block_head_t* bh; + siska_block_t* b; + siska_block_t* b2; + + b = siska_block_head(p); + + long size = siska_block_size(b); + long shift = siska_block_get_shift(size); + + b->size_free = size; +// printf("%s(), %d, b: %p, size: %ld, shift: %ld\n", __func__, __LINE__, b, size, shift); + + long i; + for (i = shift; i < PG_SHIFT; i++) { + + bh = &siska_block_heads[i]; + +// printf("%s(), %d, b: %p, size: %ld, shift i: %ld\n", __func__, __LINE__, b, size, i); + + if (!((unsigned long)b & ((size << 1) - 1))) { + + b2 = (siska_block_t*)((unsigned long)b + size); + + unsigned long flags; + siska_spin_lock_irqsave(&bh->lock, flags); + if (siska_block_is_used(b2)) { + + siska_list_add_front(&bh->head, &b->list); + siska_spin_unlock_irqrestore(&bh->lock, flags); + return; + } + siska_list_del(&b2->list); + siska_spin_unlock_irqrestore(&bh->lock, flags); + + if (b2->size_free != size) { + while (1); + } + + size <<= 1; + b->size_free = size; + continue; + } + + b2 = (siska_block_t*)((unsigned long)b - size); +// printf("%s(), %d, b2: %p, b: %p, size: %ld, i: %ld\n", __func__, __LINE__, b2, b, size, i); + + unsigned long flags; + siska_spin_lock_irqsave(&bh->lock, flags); + if (siska_block_is_used(b2)) { + + siska_list_add_front(&bh->head, &b->list); + siska_spin_unlock_irqrestore(&bh->lock, flags); + return; + } + siska_list_del(&b2->list); + siska_spin_unlock_irqrestore(&bh->lock, flags); + + b = b2; + size <<= 1; + b->size_free = size; + } +// printf("%s(), %d, b: %p, size: %ld, shift i: %ld\n", __func__, __LINE__, b, size, i); + + if (b->size_free != PG_SIZE) { + while (1); + } + + siska_page_t* pg = siska_addr_page((unsigned long)b); + +// printf("%s(), %d, b: %p, size: %ld, pg: %p\n", __func__, __LINE__, b, size, pg); + + siska_free_pages(pg, 1); +} + +void _do_page_fault(unsigned long vaddr, unsigned long error_code, unsigned long CPL) +{ + unsigned long* pg_dir; + unsigned long* pg_table; + unsigned long paddr; + unsigned long paddr2; + siska_page_t* pg = NULL; + siska_page_t* pg2 = NULL; + + pg_dir = (unsigned long*) current->cr3; + + if (!(pg_dir[vaddr >> 22] & PG_FLAG_PRESENT)) { + + if (siska_get_free_pages(&pg, 1) < 0) + return; + + paddr = siska_page_addr(pg); + + pg_table = (unsigned long*)paddr; + + pg_dir[vaddr >> 22] = paddr | 0x7; + + siska_memset(pg_table, 0, PG_SIZE); + } else { + paddr = pg_dir[vaddr >> 22] & ~(PG_SIZE - 1); + + pg = siska_addr_page(paddr); + + unsigned long flags; + siska_spin_lock_irqsave(&pg->lock, flags); + if (pg->refs > 1) { + siska_spin_unlock_irqrestore(&pg->lock, flags); + + if (siska_get_free_pages(&pg2, 1) < 0) + return; + + paddr2 = siska_page_addr(pg2); + siska_memcpy((void*)paddr2, (void*)paddr, PG_SIZE); + + pg_dir[vaddr >> 22] = paddr2 | 0x7; + + siska_unref_page(pg); + + pg_table = (unsigned long*)paddr2; + } else { + siska_spin_unlock_irqrestore(&pg->lock, flags); + + pg_dir[vaddr >> 22] = paddr2 | 0x7; + + pg_table = (unsigned long*)paddr; + + int i; + for (i = 0; i < 1024; i++) + pg_table[i] &= ~PG_FLAG_WRITE; + } + } + + if (!(error_code & PG_FLAG_PRESENT)) { + // page not exist + + if (siska_get_free_pages(&pg, 1) < 0) + return; + + paddr = siska_page_addr(pg); + + pg_table[(vaddr >> 12) & 0x3ff] = paddr | 0x7; + + } else if (error_code & PG_FLAG_WRITE) { + // page can't write, read only + + paddr = pg_table[(vaddr >> 12) & 0x3ff] & ~(PG_SIZE - 1); + + pg = siska_addr_page(paddr); + + unsigned long flags; + siska_spin_lock_irqsave(&pg->lock, flags); + if (pg->refs > 1) { + siska_spin_unlock_irqrestore(&pg->lock, flags); + + if (siska_get_free_pages(&pg2, 1) < 0) + return; + + paddr2 = siska_page_addr(pg2); + siska_memcpy((void*)paddr2, (void*)paddr, PG_SIZE); + + pg_table[(vaddr >> 12) & 0x3ff] = paddr2 | 0x7; + + siska_unref_page(pg); + } else { + siska_spin_unlock_irqrestore(&pg->lock, flags); + + pg_table[(vaddr >> 12) & 0x3ff] = paddr | 0x7; + } + } +} + +void siska_free_memory(siska_task_t* task) +{ + unsigned long* dir = (unsigned long*)task->cr3; + + unsigned long i; + unsigned long j; + unsigned long paddr; + unsigned long vaddr; + + for (i = 0; i < 1024; i++) { + + if (!(dir[i] & PG_FLAG_PRESENT)) + continue; + + unsigned long* table = (unsigned long*) (dir[i] & ~(PG_SIZE - 1)); + siska_page_t* pg; + + for (j = 0; j < 1024; j++) { + + if (!(table[j] & PG_FLAG_PRESENT)) + continue; + + paddr = table[j] & ~(PG_SIZE - 1); + vaddr = (i << 22) | (j << 12); + + if (vaddr >= task->code3 & ~(PG_SIZE - 1) + && vaddr < task->end3 & ~(PG_SIZE - 1)) { + table[j] &= ~PG_FLAG_WRITE; + + pg = siska_addr_page(paddr); + siska_free_pages(pg, 1); + pg = NULL; + } + } + + pg = siska_addr_page((unsigned long)table); + siska_free_pages(pg, 1); + pg = NULL; + } +} + +int siska_copy_memory(siska_task_t* child, siska_task_t* parent, unsigned long esp3) +{ + unsigned long* child_dir = (unsigned long*)child->cr3; + unsigned long* parent_dir = (unsigned long*)parent->cr3; + + unsigned long i; + unsigned long j; + + unsigned long vaddr; + unsigned long paddr; + + for (i = 0; i < 1024; i++) { + + child_dir[i] = parent_dir[i]; + + if (!(parent_dir[i] & PG_FLAG_PRESENT)) + continue; + + unsigned long* table = (unsigned long*) (parent_dir[i] & ~(PG_SIZE - 1)); + + siska_page_t* pg = siska_addr_page((unsigned long)table); + siska_ref_page(pg); + + for (j = 0; j < 1024; j++) { + + if (!(table[j] & PG_FLAG_PRESENT)) + continue; + + paddr = table[j] & ~(PG_SIZE - 1); + vaddr = (i << 22) | (j << 12); + + // share user code & data + if (vaddr >= parent->code3 & ~(PG_SIZE - 1) + && vaddr <= parent->brk3 & ~(PG_SIZE - 1)) { + table[j] &= ~PG_FLAG_WRITE; + + pg = siska_addr_page(paddr); + siska_ref_page(pg); + } + } + } + + for (vaddr = esp3 & ~(PG_SIZE - 1); vaddr < parent->ebp3; vaddr += PG_SIZE) { + + i = vaddr >> 22; + j = (vaddr >> 12) & 0x3ff; + + if (!(parent_dir[i] & PG_FLAG_PRESENT)) + continue; + + unsigned long* child_table = (unsigned long*) ( child_dir[i] & ~(PG_SIZE - 1)); + unsigned long* parent_table = (unsigned long*) (parent_dir[i] & ~(PG_SIZE - 1)); + + siska_page_t* pg = NULL; + + if (child_table == parent_table) { + + if (siska_get_free_pages(&pg, 1) < 0) { + siska_printk("siska_copy_memory, error0\n"); + goto _error; + } + + child_table = (unsigned long*)siska_page_addr(pg); + child_dir[i] = (unsigned long )child_table | 0x7; + + siska_memcpy(child_table, parent_table, PG_SIZE); + + pg = siska_addr_page((unsigned long)parent_table); + siska_unref_page(pg); + pg = NULL; + } + + if (!(parent_table[j] & PG_FLAG_PRESENT)) + continue; + + if (siska_get_free_pages(&pg, 1) < 0) { + siska_printk("siska_copy_memory, error1\n"); + goto _error; + } + + unsigned long child_paddr = siska_page_addr(pg); + unsigned long parent_paddr = parent_table[j] & ~(PG_SIZE - 1); + + child_table[j] = child_paddr | 0x7; + + siska_memcpy((void*)child_paddr, (void*)parent_paddr, PG_SIZE); + + pg = siska_addr_page(parent_paddr); + siska_unref_page(pg); + pg = NULL; + + parent_table[j] |= PG_FLAG_WRITE; + } + return 0; + +_error: + siska_free_memory(child); + return -1; +} + +#if 0 +int main() +{ + siska_mm_init(); + + void* p0 = siska_kmalloc(5); + void* p1 = siska_kmalloc(17); + + printf("p0: %p\n", p0); + printf("p1: %p\n", p1); + + void* p2 = siska_kmalloc(37); + void* p3 = siska_kmalloc(43); + + printf("p2: %p\n", p2); + printf("p3: %p\n", p3); + + char* str = "hello world!"; + int len = strlen(str); + siska_memcpy(p2, str, len + 1); + siska_memcpy(p3, str, len + 1); + + void* p4 = siska_krealloc(p3, 47); + void* p5 = siska_krealloc(p2, 23); + + printf("p4: %p, %s\n", p4, p4); + printf("p5: %p, %s\n", p5, p5); + printf("\n"); + + printf("p0: %p\n", p0); + siska_kfree(p0); + printf("\n"); + + printf("p1: %p\n", p1); + siska_kfree(p1); + printf("\n"); + + printf("p4: %p\n", p4); + siska_kfree(p4); + printf("\n"); + + printf("p5: %p\n", p5); + siska_kfree(p5); + + return 0; +} +#endif diff --git a/siska_mm.h b/siska_mm.h new file mode 100644 index 0000000..491d2e3 --- /dev/null +++ b/siska_mm.h @@ -0,0 +1,90 @@ +#ifndef SISKA_MM_H +#define SISKA_MM_H + +#include"siska_core.h" + +struct siska_mm_s +{ +}; + +typedef struct { + siska_spinlock_t lock; + + int refs; +} siska_page_t; + +typedef struct { + union { + siska_list_t list; + long size_used; + }; + long size_free; +} siska_block_t; + +typedef struct { + siska_list_t head; + siska_spinlock_t lock; +} siska_block_head_t; + +#define PG_FLAG_PRESENT 0x1 +#define PG_FLAG_WRITE 0x2 + +extern siska_page_t* siska_pages; + +void siska_mm_init(); + +int siska_get_free_pages(siska_page_t** pages, int nb_pages); +int siska_free_pages (siska_page_t* pages, int nb_pages); + +static inline void siska_ref_page(siska_page_t* pg) +{ + if (pg) { + unsigned long flags; + siska_spin_lock_irqsave(&pg->lock, flags); + pg->refs++; + siska_spin_unlock_irqrestore(&pg->lock, flags); + } +} +static inline void siska_unref_page(siska_page_t* pg) +{ + if (pg) { + unsigned long flags; + siska_spin_lock_irqsave(&pg->lock, flags); + pg->refs--; + siska_spin_unlock_irqrestore(&pg->lock, flags); + } +} + +static inline unsigned long siska_page_addr(siska_page_t* page) +{ + unsigned long index = (unsigned long)(page - siska_pages); + unsigned long addr = index << PG_SHIFT; + return addr; +} + +static inline siska_page_t* siska_addr_page(unsigned long addr) +{ + return siska_pages + (addr >> PG_SHIFT); +} +#ifdef ON_BOCHS +void* siska_kmalloc(int size); +void* siska_krealloc(void* p, int size); +void siska_kfree(void* p); + +void siska_memcpy(void* dst, const void* src, unsigned long size); +void siska_memset(void* dst, unsigned long data, unsigned long size); +#else +#include +#include +#define siska_kmalloc malloc +#define siska_krealloc realloc +#define siska_kfree free +#define siska_memcpy memcpy +#define siska_memset memset +#endif + +int siska_copy_memory(siska_task_t* child, siska_task_t* parent, unsigned long esp3); +void siska_free_memory(siska_task_t* task); + +#endif + diff --git a/siska_page.s b/siska_page.s new file mode 100644 index 0000000..d54b24f --- /dev/null +++ b/siska_page.s @@ -0,0 +1,67 @@ + +.code32 +.text +.global _page_fault_int_handler, _do_page_fault + +.align 4 +_page_fault_msg: +.asciz "page fault interrupt!\n" + +.align 4 +_page_fault_int_handler: +#40 cs +#36 eip +#32 error_code +#28 ds +#24 es +#20 fs +#16 gs +#12 eax +#8 ebx +#4 ecx +#0 edx + + cli + + push %ds + push %es + push %fs + push %gs + + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + + movl $0x10, %eax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + movl 40(%esp), %edx + movl 32(%esp), %ecx + movl %cr2, %eax + sti + + andl $0x3, %edx + + pushl %edx + pushl %ecx + pushl %eax + call _do_page_fault + addl $12, %esp + + popl %edx + popl %ecx + popl %ebx + popl %eax + + pop %gs + pop %fs + pop %es + pop %ds + + addl $4, %esp #drop error code + iret + diff --git a/siska_printf.c b/siska_printf.c new file mode 100644 index 0000000..6234fa1 --- /dev/null +++ b/siska_printf.c @@ -0,0 +1,225 @@ +#include"siska_def.h" + +int siska_ulong2a(char* buf, int* pn, int size, unsigned long num) +{ + int n = *pn; + int i = n; + + while (n < size - 1) { + + buf[n++] = num % 10 + '0'; + + num /= 10; + if (0 == num) + break; + } + + *pn = n--; + + while (i < n) { + char c = buf[i]; + buf[i++] = buf[n]; + buf[n--] = c; + } + return *pn; +} + +int siska_long2a(char* buf, int* pn, int size, long num) +{ + int n = *pn; + + if (n < size - 1 && num < 0) { + buf[n++] = '-'; + num = -num; + } + + *pn = n; + return siska_ulong2a(buf, pn, size, num); +} + +int siska_double2a(char* buf, int* pn, int size, double num) +{ + if (*pn < size - 1 && num < 0.0) { + buf[(*pn)++] = '-'; + num = -num; + } + + long l = (long)num; + long diff = (long)((num - l) * 1e6); + + siska_ulong2a(buf, pn, size, l); + + if (*pn < size - 1) + buf[(*pn)++] = '.'; + + return siska_ulong2a(buf, pn, size, diff); +} + +int siska_hex2a(char* buf, int* pn, int size, unsigned long num) +{ + int n = *pn; + int i = n; + + while (n < size - 1) { + + unsigned char x = num % 16; + + buf[n++] = x > 9 ? x - 10 + 'a' : x + '0'; + + num /= 16; + if (0 == num) + break; + } + + *pn = n--; + + while (i < n) { + char c = buf[i]; + buf[i++] = buf[n]; + buf[n--] = c; + } + return *pn; +} + +int siska_hex2a_prefix(char* buf, int* pn, int size, unsigned long num) +{ + int n = *pn; + + if (n < size - 1 - 2) { + buf[n++] = '0'; + buf[n++] = 'x'; + } + + *pn = n; + return siska_hex2a(buf, pn, size, num); +} + +int siska_p2a(char* buf, int* pn, int size, unsigned long num) +{ + if (0 == num) { + int n = *pn; + char* p = "null"; + + while (n < size - 1 && *p) + buf[n++] = *p++; + + *pn = n; + return n; + } + + return siska_hex2a_prefix(buf, pn, size, num); +} + +int siska_str2a(char* buf, int* pn, int size, const char* str) +{ + int n = *pn; + + while (n < size - 1 && *str) + buf[n++] = *str++; + + *pn = n; + return n; +} + +int siska_vsnprintf(char* buf, int size, const char* fmt, siska_va_list ap) +{ + int n = 0; + + while (n < size - 1 && *fmt) { + + if ('%' != *fmt) { + buf[n++] = *fmt++; + continue; + } + + fmt++; + if ('%' == *fmt) { + buf[n++] = *fmt++; + continue; + } + + int prefix = 0; + if ('#' == *fmt) { + prefix++; + fmt++; + } + + int l = 0; + if ('l' == *fmt) { + l++; + fmt++; + } + + switch (*fmt) { + case 'c': + buf[n++] = siska_va_arg(ap, int); + break; + case 'd': + if (l) + siska_long2a(buf, &n, size, siska_va_arg(ap, long)); + else + siska_long2a(buf, &n, size, siska_va_arg(ap, int)); + break; + case 'u': + if (l) + siska_ulong2a(buf, &n, size, siska_va_arg(ap, unsigned long)); + else + siska_ulong2a(buf, &n, size, siska_va_arg(ap, unsigned int)); + break; + case 'x': + if (prefix) { + if (l) + siska_hex2a_prefix(buf, &n, size, siska_va_arg(ap, unsigned long)); + else + siska_hex2a_prefix(buf, &n, size, siska_va_arg(ap, unsigned int)); + } else { + if (l) + siska_hex2a(buf, &n, size, siska_va_arg(ap, unsigned long)); + else + siska_hex2a(buf, &n, size, siska_va_arg(ap, unsigned int)); + } + break; + case 'p': + siska_p2a(buf, &n, size, siska_va_arg(ap, unsigned long)); + break; + case 'f': + case 'g': + siska_double2a(buf, &n, size, siska_va_arg(ap, double)); + break; + case 's': + siska_str2a(buf, &n, size, siska_va_arg(ap, char*)); + break; + default: + return -1; + break; + } + + fmt++; + } + + buf[n] = '\0'; + return n; +} + +int siska_snprintf(char* buf, int size, const char* fmt, ...) +{ + siska_va_list ap; + + siska_va_start(ap, fmt); + int n = siska_vsnprintf(buf, size, fmt, ap); + siska_va_end(ap); + + return n; +} +#if 0 +int main() +{ + char buf[1024]; + siska_snprintf(buf, 1023, "i: %d, ld: %ld, x: %x, x: %#lx, p: %p, s: %s, f: %f, d: %lg\n", + 100, -255ll, 254, 253, buf, "hello", 2.71828, -3.1415926); + + printf("%s\n", buf); + printf("%p\n", buf); + return 0; +} +#endif diff --git a/siska_string.h b/siska_string.h new file mode 100644 index 0000000..5d5e7aa --- /dev/null +++ b/siska_string.h @@ -0,0 +1,68 @@ +#ifndef SISKA_STRING_H +#define SISKA_STRING_H + +static inline int siska_strcmp(const unsigned char* s0, const unsigned char* s1) +{ + while (*s0 && *s1) { + + if (*s0 < *s1) + return -1; + else if (*s0 > *s1) + return 1; + + s0++; + s1++; + } + + if (*s0 == *s1) + return 0; + + return *s0 < *s1 ? -1 : 1; +} + +static inline int siska_strncmp(const unsigned char* s0, const unsigned char* s1, unsigned int n) +{ + unsigned int len = 0; + + while (*s0 && *s1 && len < n) { + + if (*s0 < *s1) + return -1; + else if (*s0 > *s1) + return 1; + + s0++; + s1++; + len++; + } + + if (len == n) + return 0; + + return *s0 < *s1 ? -1 : 1; +} + +static inline unsigned int siska_strlen(const unsigned char* s) +{ + const unsigned char* p = s; + while (*p) + p++; + return (unsigned int)(p - s); +} + +static inline unsigned char* siska_strncpy(unsigned char* dst, const unsigned char* src, unsigned int n) +{ + unsigned int len = 0; + + while (*src && len < n) { + *dst++ = *src++; + len++; + } + + if (len < n) + *dst = '\0'; + return dst; +} + +#endif + diff --git a/siska_syscall.s b/siska_syscall.s new file mode 100644 index 0000000..f7e2da5 --- /dev/null +++ b/siska_syscall.s @@ -0,0 +1,152 @@ + +.code32 +.text +.global _timer_int_handler, _syscall_handler, _ret_from_fork, _syscall_table +.global _jiffies, _do_timer, siska_printk +.global _fork0_msg, _fork1_msg, _execve_msg +.global _signal_handler_entry + +.align 4 +_timer_msg: +.asciz "timer interrupt!\n" + +.align 4 +_jiffies: +.long 0 + +.align 4 +_timer_int_handler: +#48 old ss +#44 old esp +#40 eflags +#36 cs +#32 eip +#28 ds +#24 es +#20 fs +#16 gs +#12 edx +#8 ecx +#4 ebx +#0 eax + + push %ds + push %es + push %fs + push %gs + + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + + movl $0x10, %eax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + incl _jiffies + + movb $0x20, %al + outb %al, $0x20 + + movl 36(%esp), %eax + testl $0x3, %eax + je 1f + + call _do_timer + +1: +_ret_from_syscall: + pushl %esp + call siska_do_signal + popl %esp + + popl %eax + popl %ebx + popl %ecx + popl %edx + + pop %gs + pop %fs + pop %es + pop %ds + iret + +.align 4 +_signal_handler_entry: +#24 ret +#20 sig +#16 handler +#12 edx +#8 ecx +#4 ebx +#0 eax + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + + movl 16(%esp), %eax + movl 20(%esp), %edx + + pushl %edx + call *%eax + popl %edx + + popl %eax + popl %ebx + popl %ecx + popl %edx + addl $8, %esp + ret + +.align 4 +_syscall_msg: +.asciz "syscall interrupt!\n" + +.align 4 +_syscall_handler: + push %ds + push %es + push %fs + push %gs + + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + + movl $0x10, %eax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + movl (%esp), %eax + movl _syscall_table(, %eax, 4), %eax + + pushl %esp + call *%eax + popl %esp + + movl %eax, (%esp) + jmp _ret_from_syscall + +_ret_from_fork: + movl $0, (%esp) + jmp _ret_from_syscall + +.align 4 +_syscall_table: + .fill 256, 4, 0 + +_fork0_msg: +.asciz "fork0 process!\n" +_fork1_msg: +.asciz "fork1 process!\n" + +_execve_msg: +.asciz "/home/execve" + diff --git a/siska_task.c b/siska_task.c new file mode 100644 index 0000000..002f209 --- /dev/null +++ b/siska_task.c @@ -0,0 +1,408 @@ + +#include"siska_task.h" +#include"siska_mm.h" +#include"siska_vfs.h" +#include"siska_api.h" + +#define SISKA_NB_TASKS 16 + +static siska_task_t* siska_tasks[SISKA_NB_TASKS]; + +static siska_spinlock_t siska_task_lock; + +static siska_list_t siska_task_head; + + + +void siska_task_init() +{ + siska_memset(siska_tasks, 0, sizeof(siska_task_t*) * SISKA_NB_TASKS); + + siska_spinlock_init(&siska_task_lock); + + siska_list_init(&siska_task_head); + + siska_tasks[0] = get_asm_addr(_task0); + + siska_list_add_tail(&siska_task_head, &(siska_tasks[0]->list)); +} + +void siska_switch_to(siska_task_t* prev, siska_task_t* next) +{ + siska_tss_t* tss = get_asm_addr(_tss0); + + switch_to_pgdir(PGDIR_KERNEL); + + asm volatile( + "pushl %%ebp\n\t" + "pushfl\n\t" + "movl %%esp, %0\n\t" + "movl $1f, %1\n\t" + "movl %2, %%esp\n\t" + "addl $0x1000, %5\n\t" + "movl %5, 4(%6)\n\t" + "movl %4, %%cr3\n\t" + "jmp *%3\n\t" + "1:\n\t" + "popfl\n\t" + "popl %%ebp\n\t" + :"=m"(prev->esp0), "=m"(prev->eip) + :"r"(next->esp0), "r"(next->eip), "r"(next->cr3), "r"(next), "r"(tss) + :"esp", "ebp", "flags" + ); +} + +void siska_schedule() +{ + siska_list_t* l; + siska_task_t* next; + siska_task_t* parent; + + unsigned long flags; + siska_spin_lock_irqsave(&siska_task_lock, flags); +#if 1 + for (l = siska_list_head(&siska_task_head); + l != siska_list_sentinel(&siska_task_head); + l = siska_list_next(l)) { + + next = siska_list_data(l, siska_task_t, list); + +// if (SISKA_TASK_SLEEP == next->status) +// continue; + + if (next != current) + break; + } + + if (l == siska_list_sentinel(&siska_task_head)) + next = siska_tasks[0]; +#else + siska_list_del(¤t->list); + siska_list_add_tail(&siska_task_head, ¤t->list); + + l = siska_list_head(&siska_task_head); + next = siska_list_data(l, siska_task_t, list); +#endif +#if 0 + if (next->ppid >= 0) { + parent = siska_tasks[next->ppid]; + if (SISKA_TASK_SLEEP == parent->status) + parent->status = SISKA_TASK_RUNNING; + } +#endif + siska_spin_unlock_irqrestore(&siska_task_lock, flags); + + if (next == current) + return; + + siska_switch_to(current, next); +} + +int siska_fork(siska_regs_t* regs) +{ + siska_task_t* child; + siska_page_t* pg; + + unsigned long esp = (unsigned long)regs; + unsigned long* dir; + int cpid = -1; + int i; + + pg = NULL; + if (siska_get_free_pages(&pg, 2) < 0) { + siska_printk("fork error0!\n"); + return -1; + } + + child = (siska_task_t*) siska_page_addr(pg); + + current->status = SISKA_TASK_SLEEP; + + unsigned long flags; + siska_spin_lock_irqsave(&siska_task_lock, flags); + for (i = 1; i < SISKA_NB_TASKS; i++) { + if (!siska_tasks[i]) { + cpid = i; + siska_tasks[i] = child; + break; + } + } + siska_spin_unlock_irqrestore(&siska_task_lock, flags); + + if (-1 == cpid) { + siska_free_pages(pg, 2); + current->status = SISKA_TASK_RUNNING; + siska_printk("fork error1!\n"); + goto error; + } + + siska_memcpy(child, current, PG_SIZE); + + child->cr3 = siska_page_addr(pg + 1); + + if (siska_copy_memory(child, current, regs->esp) < 0) { + siska_free_pages(pg, 2); + current->status = SISKA_TASK_RUNNING; + siska_printk("fork error2!\n"); + goto error; + } + + child->pid = cpid; + child->ppid = current->pid; + child->eip = (unsigned long)get_asm_addr(_ret_from_fork); + child->esp0 = esp; + child->status = SISKA_TASK_RUNNING; + + child->signal_flags = 0; + siska_memset(child->signal_handlers, (unsigned long)SISKA_SIG_DFL, SISKA_NB_SIGNALS * sizeof(void*)); + + siska_spin_lock_irqsave(&siska_task_lock, flags); + siska_list_add_front(&siska_task_head, &child->list); + siska_spin_unlock_irqrestore(&siska_task_lock, flags); + + siska_printk("fork ok!\n"); + + siska_schedule(); +error: + return cpid; +} + +int __siska_kill(int pid, int signal) +{ +// siska_printk("kill, pid: %d, signal: %d\n", pid, signal); + if (pid < 0 || pid >= SISKA_NB_TASKS) + return -1; + + if (signal < 0 || signal >= SISKA_NB_SIGNALS) + return -1; + + if (0 == signal) { + if (siska_tasks[pid]) + return 0; + return -1; + } + + unsigned long flags; + siska_spin_lock_irqsave(&siska_task_lock, flags); + if (siska_tasks[pid]) { + + switch_to_pgdir(PGDIR_KERNEL); + siska_tasks[pid]->signal_flags |= 1u << signal; + switch_to_pgdir(current->cr3); + + if (SISKA_SIGCHLD == signal) + siska_printk("kill, pid: %d, siska_tasks[%d]: %p, signal: %d\n", pid, pid, siska_tasks[pid], signal); + siska_spin_unlock_irqrestore(&siska_task_lock, flags); + return 0; + } + + siska_spin_unlock_irqrestore(&siska_task_lock, flags); + return -1; +} + +int siska_kill(siska_regs_t* regs) +{ + int pid = (int)regs->ebx; + int signal = (int)regs->ecx; + + return __siska_kill(pid, signal); +} + +int siska_signal(siska_regs_t* regs) +{ + int signal = (int)regs->ebx; + void* handler = (void*)regs->ecx; + + if (signal < 0 || signal >= SISKA_NB_SIGNALS) + return -1; + + current->signal_handlers[signal] = handler; + return 0; +} + +void _signal_handler_default(int sig) +{ + int pid = siska_api_syscall(SISKA_SYSCALL_GETPID, 0, 0, 0); + if (0 != pid) + siska_api_printf("pid %d, received signal %d\n", pid, sig); + siska_api_syscall(SISKA_SYSCALL_EXIT, 0, 0, 0); +} + +void _signal_handler_kill(int sig) +{ + siska_api_syscall(SISKA_SYSCALL_EXIT, 0, 0, 0); +} + +void __siska_do_signal(siska_regs_t* regs, int sig, void (*handler)(int sig), int count) +{ + void* entry = get_asm_addr(_signal_handler_entry); + + if (0 == count) { + regs->esp -= sizeof(long); + + *(unsigned long*)regs->esp = regs->eip; + } + + *(long* )(regs->esp - 1 * sizeof(long)) = sig; + *(void**)(regs->esp - 2 * sizeof(long)) = handler; + *(void**)(regs->esp - 3 * sizeof(long)) = entry; + + regs->esp -= 3 * sizeof(long); +} + +int __siska_wait() +{ + int i; + for (i = 1; i < SISKA_NB_TASKS; i++) { + + siska_task_t* task; + siska_page_t* pg; + unsigned long flags; + + siska_spin_lock_irqsave(&siska_task_lock, flags); + task = siska_tasks[i]; + if (!task || SISKA_TASK_ZOMBIE != task->status) { + siska_spin_unlock_irqrestore(&siska_task_lock, flags); + continue; + } + + siska_tasks[i] = NULL; + siska_spin_unlock_irqrestore(&siska_task_lock, flags); + + siska_printk("wait, parent: %d, child: %d, exit_code: %d\n", current->pid, task->pid, task->exit_code); + + pg = siska_addr_page((unsigned long)task); + siska_printk("pg, refs: %d\n", pg->refs); + siska_printk("pg + 1, refs: %d\n", (pg + 1)->refs); + siska_free_pages(pg, 2); + + siska_printk("pg, refs: %d\n", pg->refs); + siska_printk("pg + 1, refs: %d\n", (pg + 1)->refs); + pg = NULL; + } + + return 0; +} + +int siska_do_signal(siska_regs_t* regs) +{ + int i; + int count = 0; + + for (i = 1; i < SISKA_NB_SIGNALS; i++) { + + if (!(current->signal_flags & (1u << i))) + continue; + + if (SISKA_SIGCHLD == i) + siska_printk("do signal, pid: %d, signal: %d\n", current->pid, i); + + current->signal_flags &= ~(1u << i); + + void* handler = current->signal_handlers[i]; + + if (SISKA_SIGCHLD == i) { + __siska_wait(); + continue; + } + + if (SISKA_SIGKILL == i) { + __siska_do_signal(regs, SISKA_SIGKILL, _signal_handler_kill, count); + count++; + break; + } + + if (SISKA_SIG_IGN == handler) + continue; + + if (SISKA_SIG_DFL == handler) + __siska_do_signal(regs, i, _signal_handler_default, count); + else + __siska_do_signal(regs, i, handler, count); + count++; + } + + if (count > 0) { + regs->esp += sizeof(long); + regs->eip = (unsigned long)get_asm_addr(_signal_handler_entry); + } + + return 0; +} + +void siska_exit(siska_regs_t* regs) +{ + if (0 == current->pid) + return; + + current->exit_code = (int)regs->ebx; + current->status = SISKA_TASK_ZOMBIE; + + siska_printk("exit, pid: %d, ppid: %d, code: %d\n", current->pid, current->ppid, current->exit_code); +#if 1 + unsigned long flags; + siska_spin_lock_irqsave(&siska_task_lock, flags); + siska_list_del(¤t->list); + __siska_kill(current->ppid, SISKA_SIGCHLD); + siska_spin_unlock_irqrestore(&siska_task_lock, flags); + + siska_free_memory(current); + siska_schedule(); +#endif +} + +int siska_wait(siska_regs_t* regs) +{ + __siska_wait(); + return 0; +} + +int siska_execve(siska_regs_t* regs) +{ + if (0 == current->pid) + return -1; + + char* filename = (char*)regs->ebx; + + siska_printk("execve, filename: %s\n", filename); + + siska_file_t* file = NULL; + + int ret = siska_vfs_open(&file, filename, + SISKA_FILE_FILE | SISKA_FILE_FLAG_R | SISKA_FILE_FLAG_W, + 0777); + if (ret < 0) { + siska_printk("open %s, ret: %d\n", filename, ret); + return -1; + } + + ret = siska_vfs_read(file, (char*)0x800000, 1024); + if (ret < 0) { + siska_printk("read %s error, ret: %d\n", filename, ret); + return -1; + } + siska_printk("read %s, ret: %d\n", filename, ret); + + current->code3 = 0x800000; + current->data3 = 0x800000 + ret; + current->heap3 = (current->data3 + PG_SIZE - 1) >> PG_SHIFT << PG_SHIFT; + current->brk3 = current->heap3; + + current->ebp3 = 0x900000; + current->end3 = current->ebp3; + + regs->esp = 0x900000; + regs->eip = 0x800000; + return 0; +} + +int siska_getpid() +{ + return current->pid; +} + +int siska_getppid() +{ + return current->ppid; +} + diff --git a/siska_task.h b/siska_task.h new file mode 100644 index 0000000..d6cb691 --- /dev/null +++ b/siska_task.h @@ -0,0 +1,115 @@ +#ifndef SISKA_TASK_H +#define SISKA_TASK_H + +#include"siska_core.h" + +typedef struct { + unsigned long eax; + unsigned long ebx; + unsigned long ecx; + unsigned long edx; + + unsigned long gs; + unsigned long fs; + unsigned long es; + unsigned long ds; + + unsigned long eip; + unsigned long cs; + unsigned long eflags; + unsigned long esp; + unsigned long ss; +} siska_regs_t; + +struct siska_tss_s +{ + unsigned long tss_prev; + + unsigned long esp0; + unsigned long ss0; + + unsigned long esp1; + unsigned long ss1; + + unsigned long esp2; + unsigned long ss2; + + unsigned long cr3; + unsigned long eip; + unsigned long eflags; + + unsigned long eax; + unsigned long ecx; + unsigned long edx; + unsigned long ebx; + + unsigned long esp; + unsigned long ebp; + + unsigned long esi; + unsigned long edi; + + unsigned long es; + unsigned long cs; + unsigned long ss; + unsigned long ds; + unsigned long fs; + unsigned long gs; + + unsigned long ldt; + + unsigned long iomap; + + unsigned long ssp; +}; + +struct siska_task_s +{ + siska_list_t list; + + int pid; + int ppid; + int exit_code; + +#define SISKA_TASK_RUNNING 1 +#define SISKA_TASK_SLEEP 2 +#define SISKA_TASK_ZOMBIE 3 + int status; + + unsigned long eip; + + unsigned long esp0; + unsigned long ss0; + + unsigned long cr3; + + siska_mm_t* mm; + + unsigned long signal_flags; + void (*signal_handlers[SISKA_NB_SIGNALS])(int signal); + + unsigned long code3; + unsigned long data3; + unsigned long heap3; + unsigned long brk3; + + unsigned long ebp3; + unsigned long end3; +}; + +void siska_task_init(); + +void siska_schedule(); +int siska_fork(siska_regs_t* regs); + +void siska_exit(siska_regs_t* regs); +int siska_wait(siska_regs_t* regs); + +int siska_kill(siska_regs_t* regs); +int siska_signal(siska_regs_t* regs); + +int siska_getpid(); +int siska_getppid(); + +#endif + diff --git a/siska_vfs.c b/siska_vfs.c new file mode 100644 index 0000000..9b050b6 --- /dev/null +++ b/siska_vfs.c @@ -0,0 +1,725 @@ +#include"siska_vfs.h" +#include"siska_mm.h" + +static siska_dev_t siska_dev_root; +static siska_file_t siska_dir_root; +static siska_spinlock_t siska_spinlock_root; + +static siska_vfs_t* siska_vfs_head = NULL; +static siska_file_ops_t* siska_fops_head = NULL; + +#define ROOTFS_OFFSET_PTR (0x90000 + 500) +#define ROOTFS_SIZE_PTR (0x90000 + 504) +#define ROOTFS_OFFSET ((*(volatile unsigned long*) ROOTFS_OFFSET_PTR) << 9) +#define ROOTFS_SIZE ((*(volatile unsigned long*) ROOTFS_SIZE_PTR) << 9) + +extern siska_vfs_t siska_fs_siska0; + +static siska_vfs_t* siska_vfs_array[] = +{ + &siska_fs_siska0, + NULL +}; + +extern siska_file_ops_t siska_fops_memory_dev; +extern siska_file_ops_t siska_fops_siska0; + +static siska_file_ops_t* siska_fops_array[] = +{ + &siska_fops_memory_dev, + &siska_fops_siska0, + NULL +}; + +void siska_vfs_init() +{ + siska_file_ops_t* fops; + siska_vfs_t* vfs; + + siska_vfs_head = NULL; + siska_fops_head = NULL; + + int i; + for (i = 0; siska_vfs_array[i]; i++) { + + vfs = siska_vfs_array[i]; + + vfs->next = siska_vfs_head; + siska_vfs_head = vfs; + } + + for (i = 0; siska_fops_array[i]; i++) { + + fops = siska_fops_array[i]; + + fops->next = siska_fops_head; + siska_fops_head = fops; + } +} + +int siska_vfs_mkfs(siska_file_t* devfile, const char* fsname) +{ + siska_vfs_t* vfs; + + if (!devfile || !fsname) + return -1; + + for (vfs = siska_vfs_head; vfs; vfs = vfs->next) { + if (!siska_strcmp(vfs->name, fsname)) + break; + } + + if (!vfs) + return -1; + + if (vfs->mkfs) + return vfs->mkfs(devfile); + + return -1; +} + +int siska_vfs_mount(siska_file_t* dir, siska_dev_t* dev, const char* fsname) +{ + siska_vfs_t* vfs; + + if (!dir || !dev || !fsname) + return -1; + + if (dir->fs) + return -1; + + for (vfs = siska_vfs_head; vfs; vfs = vfs->next) { + if (!siska_strcmp(vfs->name, fsname)) + break; + } + + if (!vfs) + return -1; + + if (vfs->mount) + return vfs->mount(&dir->fs, dir, dev); + return -1; +} + +int siska_vfs_umount(siska_file_t* dir) +{ + siska_vfs_t* vfs; + + if (dir && dir->fs) { + vfs = dir->fs->vfs; + + if (vfs && vfs->umount) { + if (vfs->umount(dir) < 0) + return -1; + } + + dir->fs = NULL; + return 0; + } + + return -1; +} + +siska_file_t* siska_dir_find_child(siska_file_t* dir, const char* name, int len) +{ + siska_file_t* file; + siska_list_t* l; + + for (l = siska_list_head(&dir->childs); l != siska_list_sentinel(&dir->childs); + l = siska_list_next(l)) { + + file = siska_list_data(l, siska_file_t, list); + + if (siska_strlen(file->name) != len) + continue; + + if (!siska_strncmp(file->name, name, len)) + return file; + } + return NULL; +} + +siska_file_t* siska_dir_add_file(siska_file_t* dir, const char* name, int len) +{ + siska_file_t* file; + + file = siska_file_alloc(); + if (!file) + return NULL; + + file->name = siska_kmalloc(len + 1); + if (!file->name) { + siska_file_free(file); + return NULL; + } + + siska_memcpy(file->name, name, len); + file->name[len] = '\0'; + file->len = len; + + file->parent = dir; + + siska_list_add_tail(&dir->childs, &file->list); + + return file; +} + +int siska_vfs_open(siska_file_t** pfile, const char* path, int flags, int mode) +{ + if (!pfile || !path) + return -1; + + char* p0 = (char*)path; + char* p1 = p0; + + if ('.' == *p1) + return -1; + + if ('/' != *p1) + return -1; + + siska_file_t* sentinel; + siska_file_t* file; + siska_file_t* dir; + + dir = &siska_dir_root; + sentinel = NULL; + + p0++; + p1 = p0; + + unsigned long eflags; + siska_spin_lock_irqsave(&siska_spinlock_root, eflags); + while (*p1) { + p1++; + + if ('/' != *p1) + continue; + + file = siska_dir_find_child(dir, p0, (int)(p1 - p0)); + + if (!file) { + file = siska_dir_add_file(dir, p0, (int)(p1 - p0)); + if (!file) + goto _error; + + if (!sentinel) { + sentinel = dir; +// siska_printk("sentinel: %s, type: %d, file: %s\n", +// sentinel->name, siska_file_get_type(sentinel), file->name); + } + + siska_file_set_type(file, SISKA_FILE_DIR); + + } else if (SISKA_FILE_DIR != siska_file_type(file)) { + siska_printk("file: %s, already exist\n", file->name); + + siska_spin_unlock_irqrestore(&siska_spinlock_root, eflags); + return -1; + } + + dir = file; + + p1++; + while (*p1 && '/' == *p1) + p1++; + p0 = p1; + } + + if ('/' != *p0) { + + file = siska_dir_find_child(dir, p0, (int)(p1 - p0)); + + if (!file) { + file = siska_dir_add_file(dir, p0, (int)(p1 - p0)); + if (!file) + goto _error; + + if (!sentinel) + sentinel = dir; + + siska_file_set_type(file, siska_file_type_of_flags(flags)); +// siska_printk("file: %s, type: %d\n", file->name, siska_file_get_type(file)); +// siska_printk("file: %s, type: %d\n", file->name, siska_file_get_type(file)); + + } else if (siska_file_type(file) == siska_file_type_of_flags(flags)) { + siska_printk("file: %s, already exist\n", file->name); + + siska_spin_unlock_irqrestore(&siska_spinlock_root, eflags); + return -1; + } + } + + if (!file->ops) { + + siska_file_t* f; + + for (f = file; f; f = f->parent) { + if (f->fs) { + file->ops = f->fs->fops; + break; + } + } + + if (!file->ops) { + siska_printk("file: %s, ops not found\n", file->name); + + dir = file; + goto _error; + } + + if (file->ops->open) { + unsigned int fflags; + int ret; + + fflags = file->flags; + + siska_spin_lock(&file->lock); + ret = file->ops->open(file, flags, mode); + siska_spin_unlock(&file->lock); + + file->flags = fflags; + + if (ret < 0) { + siska_printk("file: %s, ops->open() error\n", file->name); + + dir = file; + goto _error; + } + } + } + siska_spin_unlock_irqrestore(&siska_spinlock_root, eflags); + + *pfile = file; + return 0; + +_error: + if (!sentinel) { + siska_spin_unlock_irqrestore(&siska_spinlock_root, eflags); + return -1; + } + +// siska_printk("delete sentinel file: %s, type: %d\n", sentinel->name, siska_file_get_type(sentinel)); + + while (dir != sentinel) { + + if (!siska_list_empty(&dir->childs)) { + siska_spin_unlock_irqrestore(&siska_spinlock_root, eflags); + return -1; + } + + siska_file_t* tmp = dir->parent; + +// siska_printk("delete new file: %s, type: %d\n", dir->name, siska_file_get_type(dir)); + + siska_list_del(&dir->list); + siska_file_free(dir); + dir = tmp; + } + + siska_spin_unlock_irqrestore(&siska_spinlock_root, eflags); + return -1; +} + +int siska_vfs_write(siska_file_t* file, const char* buf, int count) +{ + if (!file || !buf || count < 0) + return -1; + + if (0 == count) + return 0; + + unsigned long flags; + int ret = -1; + + siska_spin_lock_irqsave(&file->lock, flags); + if (file->ops && file->ops->write) + ret = file->ops->write(file, buf, count); + siska_spin_unlock_irqrestore(&file->lock, flags); + + if (ret < 0) + siska_printk("write file: %s, file->ops: %p\n", file->name, file->ops); + + return ret; +} + +int siska_vfs_read(siska_file_t* file, char* buf, int count) +{ + if (!file || !buf || count < 0) + return -1; + + if (0 == count) + return 0; + + unsigned long flags; + int ret = -1; + + siska_spin_lock_irqsave(&file->lock, flags); + if (file->ops && file->ops->read) + ret = file->ops->read(file, buf, count); + siska_spin_unlock_irqrestore(&file->lock, flags); + + if (ret < 0) + siska_printk("read file: %s, file->ops: %p\n", file->name, file->ops); + + return ret; +} + +int siska_vfs_lseek(siska_file_t* file, long offset, int whence) +{ + if (!file) + return -1; + + unsigned long flags; + int ret = -1; + + siska_spin_lock_irqsave(&file->lock, flags); + if (file->ops && file->ops->lseek) + ret = file->ops->lseek(file, offset, whence); + siska_spin_unlock_irqrestore(&file->lock, flags); + + if (ret < 0) + siska_printk("lseek file: %s, file->ops: %p\n", file->name, file->ops); + + return ret; +} + +void siska_dir_print(siska_file_t* dir) +{ + siska_file_t* file; + siska_list_t* l; + + if (!dir) + return; + + if (siska_list_empty(&dir->childs)) + siska_printk("%s\n", dir->name); + else + siska_printk("%s/\n", dir->name); + + for (l = siska_list_head(&dir->childs); l != siska_list_sentinel(&dir->childs); + l = siska_list_next(l)) { + + file = siska_list_data(l, siska_file_t, list); + + siska_printk("%s/%s\n", dir->name, file->name); + } +} + +void siska_dir_print_recursive(siska_file_t* dir, siska_file_t* root) +{ + siska_file_t* file; + siska_list_t* l; + + if (!dir) + return; + + int n = 0; + file = dir; + while (file != root) { + file = file->parent; + n++; + } + + siska_file_t** path = siska_kmalloc(sizeof(siska_file_t*) * n); + if (!path) + return; + + n = 0; + file = dir; + while (file != root) { + path[n++] = file; + file = file->parent; + } + + if (root && root != dir) { + if ('/' == root->name[0]) + siska_printk("/"); + else + siska_printk("./%s/", root->name); + } + + while (--n > 0) + siska_printk("%s/", path[n]->name); + + siska_printk("%s\n", dir->name); + siska_kfree(path); + path = NULL; + + for (l = siska_list_head(&dir->childs); l != siska_list_sentinel(&dir->childs); + l = siska_list_next(l)) { + + file = siska_list_data(l, siska_file_t, list); + + siska_dir_print_recursive(file, root); + } +} + +siska_file_t* siska_file_alloc() +{ + siska_file_t* file = siska_kmalloc(sizeof(siska_file_t)); + if (!file) + return NULL; + + siska_list_init(&file->list); + siska_list_init(&file->childs); + file->parent = NULL; + + file->name = NULL; + file->len = 0; + + file->flags = 0; + file->mode = 0; + + siska_spinlock_init(&file->lock); + + file->data = NULL; + file->size = 0; + file->offset = 0; + + file->ops = NULL; + file->inode = NULL; + file->dev = NULL; + file->fs = NULL; + + return file; +} + +void siska_file_free(siska_file_t* file) +{ + if (file) + siska_kfree(file); +} + +siska_sblock_t* siska_sblock_alloc() +{ + siska_sblock_t* sblock = siska_kmalloc(sizeof(siska_sblock_t)); + if (!sblock) + return NULL; + + sblock->next = NULL; + sblock->number = 0; + sblock->inodes = NULL; + sblock->sblock_dev = NULL; + + return sblock; +} + +void siska_sblock_free(siska_sblock_t* sblock) +{ + if (sblock) { + + if (sblock->sblock_dev) + siska_kfree(sblock->sblock_dev); + + siska_kfree(sblock); + } +} + +siska_inode_t* siska_inode_alloc() +{ + siska_inode_t* inode = siska_kmalloc(sizeof(siska_inode_t)); + if (!inode) + return NULL; + + inode->next = NULL; + inode->file = NULL; + inode->sblock = NULL; + inode->index = 0; + inode->inode_dev = NULL; + + return inode; +} + +void siska_inode_free(siska_inode_t* inode) +{ + if (inode) { + + if (inode->inode_dev) + siska_kfree(inode->inode_dev); + + siska_kfree(inode); + } +} +#ifndef ON_BOCHS +#include +#include +#include +#include +#include +#endif + +int siska_fs_init() +{ + siska_vfs_init(); + + siska_spinlock_init(&siska_spinlock_root); + + siska_dev_root.name ="rootdev"; + siska_dev_root.fops = &siska_fops_memory_dev; +#ifdef ON_BOCHS + siska_dev_root.priv = (void*)ROOTFS_OFFSET; + siska_dev_root.priv_size = ROOTFS_SIZE; +#else +#if 0 + siska_dev_root.priv = malloc(1024 * 10); + siska_dev_root.priv_size = 1024 * 10; +#else + int fd = open("fs.bin", O_RDONLY, 0666); + if (fd < 0) + return -1; + + siska_dev_root.priv = mmap(NULL, 1024 * 10, PROT_READ , MAP_PRIVATE, fd, 0); + if (MAP_FAILED == siska_dev_root.priv) + return -1; + siska_dev_root.priv_size = 1024 * 10; +#endif +#endif + siska_dev_root.priv_pos = 0; + + siska_list_init(&siska_dir_root.list); + siska_list_init(&siska_dir_root.childs); + + siska_dir_root.parent = NULL; + + siska_dir_root.name = "/"; + siska_dir_root.len = 1; + siska_dir_root.flags = SISKA_FILE_FLAG_R | SISKA_FILE_FLAG_W; + + siska_file_set_type(&siska_dir_root, SISKA_FILE_DIR); + + siska_dir_root.mode = SISKA_FILE_MOD_R | SISKA_FILE_MOD_W | SISKA_FILE_MOD_X; + + siska_dir_root.data = NULL; + siska_dir_root.size = 0; + siska_dir_root.offset = 0; + + siska_dir_root.ops = NULL; + siska_dir_root.inode = NULL; + siska_dir_root.dev = &siska_dev_root; + siska_dir_root.fs = NULL; +#if 0 + if (siska_vfs_mkfs(&siska_dir_root, "siska0") < 0) { + printf("%s(),%d\n", __func__, __LINE__); + return -1; + } +#endif + int ret = siska_vfs_mount(&siska_dir_root, &siska_dev_root, "siska0"); + siska_printk("root fs init, ret: %d\n", ret); + return ret; +} + +#ifndef ON_BOCHS +static int make_file(siska_file_t** pfile, const char* fname, const char* data, int len) +{ + siska_file_t* file = NULL; + + int ret = siska_vfs_open(&file, fname, + SISKA_FILE_FILE | SISKA_FILE_FLAG_R | SISKA_FILE_FLAG_W, + 0777); + if (ret < 0) { + printf("%s(),%d, error\n", __func__, __LINE__); + return -1; + } + + if (data && len > 0) { + ret = siska_vfs_write(file, data, len); + if (ret < 0) { + printf("%s(),%d, ret: %d\n", __func__, __LINE__, ret); + return -1; + } + printf("%s(),%d, ret: %d\n", __func__, __LINE__, ret); + } + + *pfile = file; + return 0; +} + +static int read_file(siska_file_t* file) +{ + unsigned char buf[128] = {0}; + + int ret = siska_vfs_lseek(file, 0, SISKA_SEEK_SET); + if (ret < 0) { + printf("%s(),%d, ret: %d\n", __func__, __LINE__, ret); + return -1; + } + + ret = siska_vfs_read(file, buf, sizeof(buf) - 1); + if (ret < 0) { + printf("%s(),%d, ret: %d\n", __func__, __LINE__, ret); + return -1; + } + printf("%s(),%d, ret: %d\n", __func__, __LINE__, ret); + printf("%s(),%d, buf: %s\n", __func__, __LINE__, buf); + + printf("%s(),%d, binary:\n", __func__, __LINE__); + + int i; + for (i = 0; i < ret; i++) + printf("%#x ", buf[i]); + printf("\n"); + return 0; +} + +int main() +{ + int ret = siska_fs_init(); + if (ret < 0) { + printf("%s(),%d, error\n", __func__, __LINE__); + return -1; + } + + siska_file_t* file = NULL; + siska_file_t* file2 = NULL; +#if 0 + if (make_file(&file, "/home/my", "hello", 6) < 0) { + printf("%s(),%d, error\n", __func__, __LINE__); + return -1; + } + printf("\n"); + + int fd_exec = open("./execve.bin", O_RDONLY); + if (fd_exec < 0) { + printf("%s(),%d, error\n", __func__, __LINE__); + return -1; + } + + char buf[256]; + ret = read(fd_exec, buf, 256); + if (ret < 0) { + printf("%s(),%d, error\n", __func__, __LINE__); + return -1; + } + printf("%s(),%d, ret: %d\n", __func__, __LINE__, ret); + + if (make_file(&file2, "/home/execve", buf, ret) < 0) { + printf("%s(),%d, error\n", __func__, __LINE__); + return -1; + } +#else +#if 1 + if (make_file(&file, "/home/my", NULL, 0) < 0) { + printf("%s(),%d, error\n", __func__, __LINE__); + return -1; + } +#endif + if (make_file(&file2, "/home/execve", NULL, 0) < 0) { + printf("%s(),%d, error\n", __func__, __LINE__); + return -1; + } +#endif + printf("\n"); + siska_dir_print_recursive(&siska_dir_root, &siska_dir_root); + + read_file(file); + read_file(file2); +#if 0 + int fd = open("fs.bin", O_RDWR | O_CREAT | O_TRUNC, 0666); + if (fd > 0) { + ret = write(fd, siska_dev_root.priv, siska_dev_root.priv_size); + } +#endif + return 0; +} +#endif diff --git a/siska_vfs.h b/siska_vfs.h new file mode 100644 index 0000000..5b57514 --- /dev/null +++ b/siska_vfs.h @@ -0,0 +1,179 @@ +#ifndef SISKA_VFS_H +#define SISKA_VFS_H + +#include"siska_core.h" + +struct siska_file_s +{ + siska_list_t list; + + siska_list_t childs; + siska_file_t* parent; + + char* name; + int len; + +#define SISKA_FILE_MOD_X 1u +#define SISKA_FILE_MOD_W (1u << 1) +#define SISKA_FILE_MOD_R (1u << 2) + +#define SISKA_FILE_FLAG_R (1u) +#define SISKA_FILE_FLAG_W (1u << 1) +#define SISKA_FILE_FLAG_NONBLOCK (1u << 2) + +#define SISKA_FILE_DIR (1u << 24) +#define SISKA_FILE_FILE (2u << 24) +#define SISKA_FILE_DEV (3u << 24) +#define SISKA_FILE_SOCK (4u << 24) + +#define SISKA_SEEK_SET 0 +#define SISKA_SEEK_CUR 1 +#define SISKA_SEEK_END 2 + +#define siska_file_type_of_flags(flags) (flags & ~0xffffff) + + unsigned int flags; + unsigned int mode; + + siska_spinlock_t lock; + + unsigned char* data; + long size; + long offset; + + siska_file_ops_t* ops; + + siska_inode_t* inode; + siska_dev_t* dev; + + siska_fs_t* fs; +}; + +struct siska_dev_s +{ + char* name; + + void* priv; + int priv_size; + int priv_pos; + + siska_file_ops_t* fops; +}; + +struct siska_file_ops_s +{ + const char* type; + + siska_file_ops_t* next; + + int (*open )(siska_file_t* file, int flags, unsigned int mode); + int (*close)(siska_file_t* file); + + int (*read )(siska_file_t* file, void* buf, int size); + int (*write)(siska_file_t* file, const void* buf, int size); + + int (*lseek)(siska_file_t* file, long offset, int whence); + int (*sync )(siska_file_t* file); + + int (*ioctl)(siska_file_t* file, unsigned long cmd, ...); +}; + +struct siska_vfs_s +{ + const char* name; + + siska_vfs_t* next; + + int (*mkfs) (siska_file_t* devfile); + + int (*mount) (siska_fs_t** pfs, siska_file_t* dir, siska_dev_t* dev); + int (*umount)(siska_file_t* dir); +}; + +struct siska_fs_s +{ + siska_file_t* dir; + siska_dev_t* dev; + siska_vfs_t* vfs; + + siska_file_ops_t* fops; + + siska_sblock_t* sblock; +}; + +struct siska_sblock_s +{ + siska_sblock_t* next; + unsigned long number; + + siska_inode_t* inodes; + + siska_sblock_dev_t* sblock_dev; +}; + +struct siska_inode_s +{ + siska_inode_t* next; + + siska_file_t* file; + + siska_sblock_t* sblock; + unsigned long index; + + siska_inode_dev_t* inode_dev; +}; + +siska_file_t* siska_file_alloc(); +void siska_file_free(siska_file_t* file); + +siska_sblock_t* siska_sblock_alloc(); +siska_inode_t* siska_inode_alloc(); + +void siska_sblock_free(siska_sblock_t* sblock); +void siska_inode_free(siska_inode_t* inode); + +void siska_vfs_init(); + +int siska_vfs_mkfs (siska_file_t* devfile, const char* fsname); + +int siska_vfs_mount (siska_file_t* dir, siska_dev_t* dev, const char* fsname); +int siska_vfs_umount(siska_file_t* dir); + +int siska_vfs_open (siska_file_t** pfile, const char* path, int flags, int mode); +int siska_vfs_write(siska_file_t* file, const char* buf, int count); + +int siska_vfs_read (siska_file_t* file, char* buf, int count); +int siska_vfs_lseek(siska_file_t* file, long offset, int whence); + +void siska_dir_print(siska_file_t* dir); +void siska_dir_print_recursive(siska_file_t* dir, siska_file_t* root); + +int siska_fs_init(); + +static inline unsigned int siska_file_type(siska_file_t* file) +{ + return file->flags & ~0xffffff; +} +static inline unsigned int siska_file_get_type(siska_file_t* file) +{ + return (file->flags >> 24) & 0xff; +} +static inline void siska_file_set_type(siska_file_t* file, unsigned int type) +{ + file->flags = (file->flags & 0xffffff) | type; +} + +static inline siska_fs_t* siska_vfs_find_fs(siska_file_t* file) +{ + siska_file_t* p; + + for (p = file; p; p = p->parent) { + + if (p->fs) + return p->fs; + } + return NULL; +} + +#endif + diff --git a/string_test.c b/string_test.c new file mode 100644 index 0000000..8e8e52e --- /dev/null +++ b/string_test.c @@ -0,0 +1,27 @@ +#include +#include"siska_string.h" + +int main() +{ + char* s0 = "hello world\n"; + char* s1 = "hello world\n"; + char* s2 = "hello\n"; + char* s3 = "hello"; + + char buf[8]; + + printf("strcmp(s0, s1): %d\n", siska_strcmp(s0, s1)); + printf("strcmp(s0, s2): %d\n", siska_strcmp(s0, s2)); + printf("strcmp(s0, s2, 5): %d\n", siska_strncmp(s0, s2, 5)); + printf("strcmp(s0, s2, 6): %d\n", siska_strncmp(s0, s2, 6)); + + printf("strlen(s2): %d\n", siska_strlen(s2)); + printf("strlen(s3): %d\n", siska_strlen(s3)); + + char* p = siska_strncpy(buf, s3, 8); + printf("buf: %s, p - buf: %d\n", buf, (int)(p - buf)); + + p = siska_strncpy(buf, s3, 4); + buf[p - buf] = '\0'; + printf("buf: %s, p - buf: %d\n", buf, (int)(p - buf)); +}