siska OS demo for bochs, this code is also in github master
authoryu.dongliang <maja_creater@qq.com>
Wed, 2 Nov 2022 05:03:26 +0000 (13:03 +0800)
committeryu.dongliang <maja_creater@qq.com>
Wed, 2 Nov 2022 05:03:26 +0000 (13:03 +0800)
28 files changed:
Makefile [new file with mode: 0644]
boot.s [new file with mode: 0644]
build_boot.sh [new file with mode: 0755]
execve.s [new file with mode: 0644]
head.s [new file with mode: 0644]
init.s [new file with mode: 0644]
main.c [new file with mode: 0644]
siska_api.c [new file with mode: 0644]
siska_api.h [new file with mode: 0644]
siska_atomic.h [new file with mode: 0644]
siska_console.c [new file with mode: 0644]
siska_core.h [new file with mode: 0644]
siska_def.h [new file with mode: 0644]
siska_fops_memory_dev.c [new file with mode: 0644]
siska_fs.h [new file with mode: 0644]
siska_fs0.c [new file with mode: 0644]
siska_list.h [new file with mode: 0644]
siska_mm.c [new file with mode: 0644]
siska_mm.h [new file with mode: 0644]
siska_page.s [new file with mode: 0644]
siska_printf.c [new file with mode: 0644]
siska_string.h [new file with mode: 0644]
siska_syscall.s [new file with mode: 0644]
siska_task.c [new file with mode: 0644]
siska_task.h [new file with mode: 0644]
siska_vfs.c [new file with mode: 0644]
siska_vfs.h [new file with mode: 0644]
string_test.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
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 (executable)
index 0000000..e9a0d8d
--- /dev/null
@@ -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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
index 0000000..61bf060
--- /dev/null
@@ -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 (file)
index 0000000..15c9264
--- /dev/null
@@ -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 (file)
index 0000000..a498ac4
--- /dev/null
@@ -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 (file)
index 0000000..227e6f9
--- /dev/null
@@ -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 (file)
index 0000000..7367c94
--- /dev/null
@@ -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 (file)
index 0000000..74de50b
--- /dev/null
@@ -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<stdio.h>
+#include<stdarg.h>
+#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 (file)
index 0000000..fcfc554
--- /dev/null
@@ -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 (file)
index 0000000..06a8bea
--- /dev/null
@@ -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 (file)
index 0000000..b129911
--- /dev/null
@@ -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 (file)
index 0000000..6f1f2dd
--- /dev/null
@@ -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 (file)
index 0000000..ddc6e8d
--- /dev/null
@@ -0,0 +1,730 @@
+#if 0
+#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+#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 (file)
index 0000000..491d2e3
--- /dev/null
@@ -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<stdlib.h>
+#include<string.h>
+#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 (file)
index 0000000..d54b24f
--- /dev/null
@@ -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 (file)
index 0000000..6234fa1
--- /dev/null
@@ -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 (file)
index 0000000..5d5e7aa
--- /dev/null
@@ -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 (file)
index 0000000..f7e2da5
--- /dev/null
@@ -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 (file)
index 0000000..002f209
--- /dev/null
@@ -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(&current->list);
+       siska_list_add_tail(&siska_task_head, &current->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(&current->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 (file)
index 0000000..d6cb691
--- /dev/null
@@ -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 (file)
index 0000000..9b050b6
--- /dev/null
@@ -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<sys/types.h>
+#include<sys/stat.h>
+#include<sys/mman.h>
+#include<fcntl.h>
+#include<unistd.h>
+#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 (file)
index 0000000..5b57514
--- /dev/null
@@ -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 (file)
index 0000000..8e8e52e
--- /dev/null
@@ -0,0 +1,27 @@
+#include<stdio.h>
+#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));
+}