From b604781fde43344e68e71758fa81924cdb2d2b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E5=87=A0=E6=96=B9?= Date: Fri, 9 Jul 2021 00:34:53 +0800 Subject: [PATCH] first commit --- linux/Image | Bin 0 -> 134916 bytes linux/Image.bkp | Bin 0 -> 131556 bytes linux/Makefile | 125 ++++ linux/System.map.2 | 1080 +++++++++++++++++++++++++++++ linux/boot/bootsect | Bin 0 -> 544 bytes linux/boot/bootsect.s | 260 +++++++ linux/boot/head.s | 240 +++++++ linux/boot/setup | Bin 0 -> 344 bytes linux/boot/setup.s | 231 ++++++ linux/fs/Makefile | 101 +++ linux/fs/bitmap.c | 168 +++++ linux/fs/block_dev.c | 73 ++ linux/fs/buffer.c | 384 ++++++++++ linux/fs/char_dev.c | 104 +++ linux/fs/exec.c | 543 +++++++++++++++ linux/fs/fcntl.c | 75 ++ linux/fs/file_dev.c | 90 +++ linux/fs/file_table.c | 9 + linux/fs/inode.c | 340 +++++++++ linux/fs/ioctl.c | 46 ++ linux/fs/namei.c | 783 +++++++++++++++++++++ linux/fs/open.c | 208 ++++++ linux/fs/pipe.c | 111 +++ linux/fs/read_write.c | 103 +++ linux/fs/select.c | 10 + linux/fs/stat.c | 66 ++ linux/fs/super.c | 282 ++++++++ linux/fs/truncate.c | 65 ++ linux/include/a.out.h | 220 ++++++ linux/include/asm/io.h | 24 + linux/include/asm/memory.h | 15 + linux/include/asm/segment.h | 65 ++ linux/include/asm/system.h | 66 ++ linux/include/const.h | 15 + linux/include/ctype.h | 34 + linux/include/errno.h | 60 ++ linux/include/fcntl.h | 55 ++ linux/include/linux/config.h | 48 ++ linux/include/linux/fdreg.h | 71 ++ linux/include/linux/fs.h | 202 ++++++ linux/include/linux/hdreg.h | 65 ++ linux/include/linux/head.h | 20 + linux/include/linux/kernel.h | 22 + linux/include/linux/mm.h | 10 + linux/include/linux/sched.h | 239 +++++++ linux/include/linux/sys.h | 116 ++++ linux/include/linux/tty.h | 77 ++ linux/include/signal.h | 68 ++ linux/include/stdarg.h | 28 + linux/include/stddef.h | 19 + linux/include/string.h | 405 +++++++++++ linux/include/sys/stat.h | 60 ++ linux/include/sys/times.h | 15 + linux/include/sys/types.h | 46 ++ linux/include/sys/utsname.h | 16 + linux/include/sys/wait.h | 23 + linux/include/termios.h | 228 ++++++ linux/include/time.h | 42 ++ linux/include/unistd.h | 282 ++++++++ linux/include/utime.h | 13 + linux/init/main.c | 210 ++++++ linux/kernel/Makefile | 83 +++ linux/kernel/asm.s | 146 ++++ linux/kernel/blk_drv/Makefile | 58 ++ linux/kernel/blk_drv/blk.h | 140 ++++ linux/kernel/blk_drv/floppy.c | 463 +++++++++++++ linux/kernel/blk_drv/hd.c | 351 ++++++++++ linux/kernel/blk_drv/ll_rw_blk.c | 165 +++++ linux/kernel/blk_drv/ramdisk.c | 126 ++++ linux/kernel/chr_drv/Makefile | 68 ++ linux/kernel/chr_drv/console.c | 710 +++++++++++++++++++ linux/kernel/chr_drv/keyboard.2.s | 466 +++++++++++++ linux/kernel/chr_drv/keyboard.S | 588 ++++++++++++++++ linux/kernel/chr_drv/rs_io.s | 147 ++++ linux/kernel/chr_drv/serial.c | 59 ++ linux/kernel/chr_drv/tty_io.c | 349 ++++++++++ linux/kernel/chr_drv/tty_ioctl.c | 204 ++++++ linux/kernel/exit.c | 197 ++++++ linux/kernel/fork.c | 148 ++++ linux/kernel/getdents.c | 46 ++ linux/kernel/math/Makefile | 43 ++ linux/kernel/math/math_emulate.c | 42 ++ linux/kernel/mktime.c | 58 ++ linux/kernel/panic.c | 24 + linux/kernel/pipe2.c | 12 + linux/kernel/printk.c | 41 ++ linux/kernel/sched.c | 412 +++++++++++ linux/kernel/signal.c | 129 ++++ linux/kernel/sleep.c | 16 + linux/kernel/sys.c | 292 ++++++++ linux/kernel/system_call.s | 296 ++++++++ linux/kernel/traps.c | 208 ++++++ linux/kernel/vsprintf.c | 233 +++++++ linux/lib/Makefile | 73 ++ linux/lib/_exit.c | 13 + linux/lib/close.c | 10 + linux/lib/ctype.c | 35 + linux/lib/dup.c | 10 + linux/lib/errno.c | 7 + linux/lib/execve.c | 11 + linux/lib/execve2.c | 19 + linux/lib/malloc.c | 232 +++++++ linux/lib/open.c | 25 + linux/lib/setsid.c | 10 + linux/lib/string.c | 14 + linux/lib/wait.c | 16 + linux/lib/write.c | 10 + linux/mm/Makefile | 38 + linux/mm/memory.c | 433 ++++++++++++ linux/mm/page.s | 40 ++ linux/tools/build | Bin 0 -> 15144 bytes linux/tools/build.c | 171 +++++ linux/tools/system | Bin 0 -> 294428 bytes 113 files changed, 15863 insertions(+) create mode 100644 linux/Image create mode 100644 linux/Image.bkp create mode 100644 linux/Makefile create mode 100644 linux/System.map.2 create mode 100644 linux/boot/bootsect create mode 100644 linux/boot/bootsect.s create mode 100644 linux/boot/head.s create mode 100644 linux/boot/setup create mode 100644 linux/boot/setup.s create mode 100644 linux/fs/Makefile create mode 100644 linux/fs/bitmap.c create mode 100644 linux/fs/block_dev.c create mode 100644 linux/fs/buffer.c create mode 100644 linux/fs/char_dev.c create mode 100644 linux/fs/exec.c create mode 100644 linux/fs/fcntl.c create mode 100644 linux/fs/file_dev.c create mode 100644 linux/fs/file_table.c create mode 100644 linux/fs/inode.c create mode 100644 linux/fs/ioctl.c create mode 100644 linux/fs/namei.c create mode 100644 linux/fs/open.c create mode 100644 linux/fs/pipe.c create mode 100644 linux/fs/read_write.c create mode 100644 linux/fs/select.c create mode 100644 linux/fs/stat.c create mode 100644 linux/fs/super.c create mode 100644 linux/fs/truncate.c create mode 100644 linux/include/a.out.h create mode 100644 linux/include/asm/io.h create mode 100644 linux/include/asm/memory.h create mode 100644 linux/include/asm/segment.h create mode 100644 linux/include/asm/system.h create mode 100644 linux/include/const.h create mode 100644 linux/include/ctype.h create mode 100644 linux/include/errno.h create mode 100644 linux/include/fcntl.h create mode 100644 linux/include/linux/config.h create mode 100644 linux/include/linux/fdreg.h create mode 100644 linux/include/linux/fs.h create mode 100644 linux/include/linux/hdreg.h create mode 100644 linux/include/linux/head.h create mode 100644 linux/include/linux/kernel.h create mode 100644 linux/include/linux/mm.h create mode 100644 linux/include/linux/sched.h create mode 100644 linux/include/linux/sys.h create mode 100644 linux/include/linux/tty.h create mode 100644 linux/include/signal.h create mode 100644 linux/include/stdarg.h create mode 100644 linux/include/stddef.h create mode 100644 linux/include/string.h create mode 100644 linux/include/sys/stat.h create mode 100644 linux/include/sys/times.h create mode 100644 linux/include/sys/types.h create mode 100644 linux/include/sys/utsname.h create mode 100644 linux/include/sys/wait.h create mode 100644 linux/include/termios.h create mode 100644 linux/include/time.h create mode 100644 linux/include/unistd.h create mode 100644 linux/include/utime.h create mode 100644 linux/init/main.c create mode 100644 linux/kernel/Makefile create mode 100644 linux/kernel/asm.s create mode 100644 linux/kernel/blk_drv/Makefile create mode 100644 linux/kernel/blk_drv/blk.h create mode 100644 linux/kernel/blk_drv/floppy.c create mode 100644 linux/kernel/blk_drv/hd.c create mode 100644 linux/kernel/blk_drv/ll_rw_blk.c create mode 100644 linux/kernel/blk_drv/ramdisk.c create mode 100644 linux/kernel/chr_drv/Makefile create mode 100644 linux/kernel/chr_drv/console.c create mode 100644 linux/kernel/chr_drv/keyboard.2.s create mode 100644 linux/kernel/chr_drv/keyboard.S create mode 100644 linux/kernel/chr_drv/rs_io.s create mode 100644 linux/kernel/chr_drv/serial.c create mode 100644 linux/kernel/chr_drv/tty_io.c create mode 100644 linux/kernel/chr_drv/tty_ioctl.c create mode 100644 linux/kernel/exit.c create mode 100644 linux/kernel/fork.c create mode 100644 linux/kernel/getdents.c create mode 100644 linux/kernel/math/Makefile create mode 100644 linux/kernel/math/math_emulate.c create mode 100644 linux/kernel/mktime.c create mode 100644 linux/kernel/panic.c create mode 100644 linux/kernel/pipe2.c create mode 100644 linux/kernel/printk.c create mode 100644 linux/kernel/sched.c create mode 100644 linux/kernel/signal.c create mode 100644 linux/kernel/sleep.c create mode 100644 linux/kernel/sys.c create mode 100644 linux/kernel/system_call.s create mode 100644 linux/kernel/traps.c create mode 100644 linux/kernel/vsprintf.c create mode 100644 linux/lib/Makefile create mode 100644 linux/lib/_exit.c create mode 100644 linux/lib/close.c create mode 100644 linux/lib/ctype.c create mode 100644 linux/lib/dup.c create mode 100644 linux/lib/errno.c create mode 100644 linux/lib/execve.c create mode 100644 linux/lib/execve2.c create mode 100644 linux/lib/malloc.c create mode 100644 linux/lib/open.c create mode 100644 linux/lib/setsid.c create mode 100644 linux/lib/string.c create mode 100644 linux/lib/wait.c create mode 100644 linux/lib/write.c create mode 100644 linux/mm/Makefile create mode 100644 linux/mm/memory.c create mode 100644 linux/mm/page.s create mode 100644 linux/tools/build create mode 100644 linux/tools/build.c create mode 100644 linux/tools/system diff --git a/linux/Image b/linux/Image new file mode 100644 index 0000000000000000000000000000000000000000..03d944f525f1c724c512027f4af97166f7cce2f9 GIT binary patch literal 134916 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 literal 0 HcmV?d00001 diff --git a/linux/Image.bkp b/linux/Image.bkp new file mode 100644 index 0000000000000000000000000000000000000000..9869a43badb77318312737429c1972e920db1e68 GIT binary patch literal 131556 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
TAw^h{Bk%XPI3U;z625+ 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[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 Cri=yv literal 0 HcmV?d00001 diff --git a/linux/Makefile b/linux/Makefile new file mode 100644 index 0000000..ecbcf30 --- /dev/null +++ b/linux/Makefile @@ -0,0 +1,125 @@ +# +# if you want the ram-disk device, define this to be the +# size in blocks. +# +RAMDISK = #-DRAMDISK=512 + +AS86 =as86 -0 -a +LD86 =ld86 -0 + +AS =as +LD =ld +LDFLAGS =-m elf_i386 -Ttext 0 -e startup_32 -Map=System.map.2 -N +CC =gcc -march=i386 $(RAMDISK) +CFLAGS =-w -g -fstrength-reduce -fomit-frame-pointer -fno-stack-protector -mcld +CPP =cpp -nostdinc -Iinclude + +# +# ROOT_DEV specifies the default root-device when making the image. +# This can be either FLOPPY, /dev/xxxx or empty, in which case the +# default of /dev/hd6 is used by 'build'. +# +ROOT_DEV= + +ARCHIVES=kernel/kernel.o mm/mm.o fs/fs.o +DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a +MATH =kernel/math/math.a +LIBS =lib/lib.a + +.c.s: + $(CC) $(CFLAGS) \ + -nostdinc -Iinclude -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) \ + -nostdinc -Iinclude -c -o $*.o $< + +all: Image + +Image: boot/bootsect boot/setup tools/system tools/build + cp -f tools/system system.tmp + strip system.tmp + tools/build boot/bootsect boot/setup system.tmp $(ROOT_DEV) > Image + rm -f system.tmp + sync + +disk: Image + dd bs=8192 if=Image of=/dev/PS0 + +tools/build: tools/build.c + $(CC) $(CFLAGS) \ + -o tools/build tools/build.c + +boot/head.o: boot/head.s + +tools/system: boot/head.o init/main.o \ + $(ARCHIVES) $(DRIVERS) $(MATH) $(LIBS) + $(LD) $(LDFLAGS) boot/head.o init/main.o \ + $(ARCHIVES) \ + $(DRIVERS) \ + $(MATH) \ + $(LIBS) \ + -o tools/system + nm tools/system | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw]\)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort >System.map + +kernel/math/math.a: FORCE + (cd kernel/math; make) + +kernel/blk_drv/blk_drv.a: FORCE + (cd kernel/blk_drv; make) + +kernel/chr_drv/chr_drv.a: FORCE + (cd kernel/chr_drv; make) + +kernel/kernel.o: FORCE + (cd kernel; make) + +mm/mm.o: FORCE + (cd mm; make) + +fs/fs.o: FORCE + (cd fs; make) + +lib/lib.a: FORCE + (cd lib; make) + +FORCE: + +boot/setup: boot/setup.s + $(AS86) -o boot/setup.o boot/setup.s + $(LD86) -s -o boot/setup boot/setup.o + +boot/bootsect: boot/bootsect.s + $(AS86) -o boot/bootsect.o boot/bootsect.s + $(LD86) -s -o boot/bootsect boot/bootsect.o + +tmp.s: boot/bootsect.s tools/system + (echo -n "SYSSIZE = (";ls -l tools/system | grep system \ + | cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s + cat boot/bootsect.s >> tmp.s + +clean: + rm -f Image System.map tmp_make core System.map.2 + rm -f boot/bootsect boot/setup + rm -f init/*.o tools/system tools/build boot/*.o + (cd mm;make clean) + (cd fs;make clean) + (cd kernel;make clean) + (cd lib;make clean) + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + (cd fs; make dep) + (cd kernel; make dep) + (cd mm; make dep) + +### Dependencies: +init/main.o : init/main.c include/unistd.h include/sys/stat.h \ + include/sys/types.h include/sys/times.h include/sys/utsname.h \ + include/utime.h include/time.h include/linux/tty.h include/termios.h \ + include/linux/sched.h include/linux/head.h include/linux/fs.h \ + include/linux/mm.h include/signal.h include/asm/system.h include/asm/io.h \ + include/stddef.h include/stdarg.h include/fcntl.h diff --git a/linux/System.map.2 b/linux/System.map.2 new file mode 100644 index 0000000..3484bf5 --- /dev/null +++ b/linux/System.map.2 @@ -0,0 +1,1080 @@ +Archive member included to satisfy reference by file (symbol) + +kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + fs/fs.o (ll_rw_block) +kernel/blk_drv/blk_drv.a(floppy.o) + kernel/kernel.o (do_floppy) +kernel/blk_drv/blk_drv.a(hd.o) + kernel/kernel.o (do_hd) +kernel/blk_drv/blk_drv.a(ramdisk.o) + kernel/blk_drv/blk_drv.a(hd.o) (rd_load) +kernel/chr_drv/chr_drv.a(tty_io.o) + kernel/kernel.o (tty_table) +kernel/chr_drv/chr_drv.a(console.o) + kernel/chr_drv/chr_drv.a(tty_io.o) (con_write) +kernel/chr_drv/chr_drv.a(keyboard.2.o) + kernel/chr_drv/chr_drv.a(console.o) (keyboard_interrupt) +kernel/chr_drv/chr_drv.a(serial.o) + kernel/chr_drv/chr_drv.a(tty_io.o) (rs_init) +kernel/chr_drv/chr_drv.a(rs_io.o) + kernel/chr_drv/chr_drv.a(serial.o) (rs1_interrupt) +kernel/chr_drv/chr_drv.a(tty_ioctl.o) + fs/fs.o (tty_ioctl) +kernel/math/math.a(math_emulate.o) + kernel/kernel.o (math_emulate) +lib/lib.a(ctype.o) kernel/chr_drv/chr_drv.a(tty_io.o) (_ctmp) +lib/lib.a(_exit.o) init/main.o (_exit) +lib/lib.a(open.o) init/main.o (open) +lib/lib.a(close.o) init/main.o (close) +lib/lib.a(errno.o) init/main.o (errno) +lib/lib.a(write.o) init/main.o (write) +lib/lib.a(dup.o) init/main.o (dup) +lib/lib.a(setsid.o) init/main.o (setsid) +lib/lib.a(execve.o) init/main.o (execve) +lib/lib.a(wait.o) init/main.o (wait) +lib/lib.a(string.o) fs/fs.o (strncpy) + +分配公共符号 +公共符号 大小 文件 + +errno 0x4 lib/lib.a(errno.o) +hash_table 0x4cc fs/fs.o +___strtok 0x4 lib/lib.a(string.o) +rd_start 0x4 kernel/blk_drv/blk_drv.a(ramdisk.o) +request 0x480 kernel/blk_drv/blk_drv.a(ll_rw_blk.o) +user_stack 0x1000 kernel/kernel.o +_ctmp 0x1 lib/lib.a(ctype.o) +super_block 0x360 fs/fs.o +drive_info 0x20 init/main.o +file_table 0x400 fs/fs.o + +Discarded input sections + + .note.GNU-stack + 0x0000000000000000 0x0 init/main.o + .note.GNU-stack + 0x0000000000000000 0x0 kernel/kernel.o + .note.GNU-stack + 0x0000000000000000 0x0 mm/mm.o + .note.GNU-stack + 0x0000000000000000 0x0 fs/fs.o + .note.GNU-stack + 0x0000000000000000 0x0 kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + .note.GNU-stack + 0x0000000000000000 0x0 kernel/blk_drv/blk_drv.a(floppy.o) + .note.GNU-stack + 0x0000000000000000 0x0 kernel/blk_drv/blk_drv.a(hd.o) + .note.GNU-stack + 0x0000000000000000 0x0 kernel/blk_drv/blk_drv.a(ramdisk.o) + .note.GNU-stack + 0x0000000000000000 0x0 kernel/chr_drv/chr_drv.a(tty_io.o) + .note.GNU-stack + 0x0000000000000000 0x0 kernel/chr_drv/chr_drv.a(console.o) + .note.GNU-stack + 0x0000000000000000 0x0 kernel/chr_drv/chr_drv.a(serial.o) + .note.GNU-stack + 0x0000000000000000 0x0 kernel/chr_drv/chr_drv.a(tty_ioctl.o) + .note.GNU-stack + 0x0000000000000000 0x0 kernel/math/math.a(math_emulate.o) + .note.GNU-stack + 0x0000000000000000 0x0 lib/lib.a(ctype.o) + .note.GNU-stack + 0x0000000000000000 0x0 lib/lib.a(_exit.o) + .note.GNU-stack + 0x0000000000000000 0x0 lib/lib.a(open.o) + .note.GNU-stack + 0x0000000000000000 0x0 lib/lib.a(close.o) + .note.GNU-stack + 0x0000000000000000 0x0 lib/lib.a(errno.o) + .note.GNU-stack + 0x0000000000000000 0x0 lib/lib.a(write.o) + .note.GNU-stack + 0x0000000000000000 0x0 lib/lib.a(dup.o) + .note.GNU-stack + 0x0000000000000000 0x0 lib/lib.a(setsid.o) + .note.GNU-stack + 0x0000000000000000 0x0 lib/lib.a(execve.o) + .note.GNU-stack + 0x0000000000000000 0x0 lib/lib.a(wait.o) + .note.GNU-stack + 0x0000000000000000 0x0 lib/lib.a(string.o) + +内存配置 + +名称 来源 长度 属性 +*default* 0x0000000000000000 0xffffffffffffffff + +Linker script and memory map + +段 .text 的地址设置为 0x0 +LOAD boot/head.o +LOAD init/main.o +LOAD kernel/kernel.o +LOAD mm/mm.o +LOAD fs/fs.o +LOAD kernel/blk_drv/blk_drv.a +LOAD kernel/chr_drv/chr_drv.a +LOAD kernel/math/math.a +LOAD lib/lib.a + 0x0000000008048000 PROVIDE (__executable_start, 0x8048000) + 0x0000000008048074 . = (0x8048000 + SIZEOF_HEADERS) + +.interp + *(.interp) + +.note.gnu.build-id + *(.note.gnu.build-id) + +.hash + *(.hash) + +.gnu.hash + *(.gnu.hash) + +.dynsym + *(.dynsym) + +.dynstr + *(.dynstr) + +.gnu.version + *(.gnu.version) + +.gnu.version_d + *(.gnu.version_d) + +.gnu.version_r + *(.gnu.version_r) + +.rel.init + *(.rel.init) + +.rel.text 0x0000000008048074 0x0 + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + .rel.text 0x0000000000000000 0x0 boot/head.o + +.rel.fini + *(.rel.fini) + +.rel.rodata + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + +.rel.data.rel.ro + *(.rel.data.rel.ro .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*) + +.rel.data 0x0000000008048074 0x0 + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + .rel.data 0x0000000000000000 0x0 boot/head.o + +.rel.tdata + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + +.rel.tbss + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + +.rel.ctors + *(.rel.ctors) + +.rel.dtors + *(.rel.dtors) + +.rel.got + *(.rel.got) + +.rel.bss + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + +.rel.ifunc + *(.rel.ifunc) + +.rel.plt 0x0000000008048074 0x0 + *(.rel.plt) + 0x0000000008048074 PROVIDE (__rel_iplt_start, .) + *(.rel.iplt) + .rel.iplt 0x0000000000000000 0x0 boot/head.o + 0x0000000008048074 PROVIDE (__rel_iplt_end, .) + +.init + *(SORT(.init)) + +.plt 0x0000000008048080 0x0 + *(.plt) + *(.iplt) + .iplt 0x0000000000000000 0x0 boot/head.o + +.text 0x0000000000000000 0x18973 + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub .text.* .gnu.linkonce.t.*) + .text 0x0000000000000000 0x64c0 boot/head.o + 0x0000000000000000 startup_32 + 0x0000000000000000 pg_dir + 0x0000000000005000 tmp_floppy_area + 0x00000000000054c0 idt + 0x0000000000005cc0 gdt + .text 0x00000000000064c0 0x713 init/main.o + 0x00000000000064c0 fork + 0x00000000000064ef pause + 0x000000000000651e setup + 0x0000000000006555 sync + 0x0000000000006799 main + 0x000000000000695b init + *fill* 0x0000000000006bd3 0x1 + .text 0x0000000000006bd4 0x3ac8 kernel/kernel.o + 0x0000000000006bd4 show_task + 0x0000000000006c59 show_stat + 0x0000000000006c9f math_state_restore + 0x0000000000006cfd schedule + 0x0000000000006eaf sys_pause + 0x0000000000006ec5 sleep_on + 0x0000000000006f24 interruptible_sleep_on + 0x0000000000006fb7 wake_up + 0x0000000000006fdf ticks_to_floppy_on + 0x00000000000070aa floppy_on + 0x00000000000070d9 floppy_off + 0x00000000000070e9 do_floppy_timer + 0x00000000000071bd add_timer + 0x00000000000072e1 do_timer + 0x00000000000073d0 sys_alarm + 0x000000000000744f sys_getpid + 0x000000000000745b sys_getppid + 0x0000000000007467 sys_getuid + 0x0000000000007476 sys_geteuid + 0x0000000000007486 sys_getgid + 0x0000000000007496 sys_getegid + 0x00000000000074a5 sys_nice + 0x00000000000074d0 sched_init + 0x0000000000007674 system_call + 0x00000000000076f0 coprocessor_error + 0x0000000000007712 device_not_available + 0x000000000000774c timer_interrupt + 0x0000000000007784 sys_execve + 0x0000000000007794 sys_execve2 + 0x00000000000077a4 sys_fork + 0x00000000000077bc hd_interrupt + 0x00000000000077f8 floppy_interrupt + 0x000000000000782e parallel_interrupt + 0x0000000000007a49 do_double_fault + 0x0000000000007a6c do_general_protection + 0x0000000000007a8f do_divide_error + 0x0000000000007ab2 do_int3 + 0x0000000000007b7a do_nmi + 0x0000000000007b9d do_debug + 0x0000000000007bc0 do_overflow + 0x0000000000007be3 do_bounds + 0x0000000000007c06 do_invalid_op + 0x0000000000007c29 do_device_not_available + 0x0000000000007c4c do_coprocessor_segment_overrun + 0x0000000000007c6f do_invalid_TSS + 0x0000000000007c92 do_segment_not_present + 0x0000000000007cb5 do_stack_segment + 0x0000000000007cd8 do_coprocessor_error + 0x0000000000007d0c do_reserved + 0x0000000000007d2f trap_init + 0x0000000000008013 divide_error + 0x0000000000008048 debug + 0x000000000000804f nmi + 0x0000000000008056 int3 + 0x000000000000805d overflow + 0x0000000000008064 bounds + 0x000000000000806b invalid_op + 0x0000000000008072 coprocessor_segment_overrun + 0x0000000000008079 reserved + 0x0000000000008080 irq13 + 0x0000000000008095 double_fault + 0x00000000000080cc invalid_TSS + 0x00000000000080d3 segment_not_present + 0x00000000000080da stack_segment + 0x00000000000080e1 general_protection + 0x000000000000811a verify_area + 0x0000000000008181 copy_mem + 0x00000000000082db copy_process + 0x0000000000008788 find_empty_process + 0x000000000000881c panic + 0x0000000000008857 printk + 0x0000000000008b74 vsprintf + 0x000000000000903a sys_ftime + 0x0000000000009040 sys_break + 0x0000000000009046 sys_ptrace + 0x000000000000904c sys_stty + 0x0000000000009052 sys_gtty + 0x0000000000009058 sys_rename + 0x000000000000905e sys_prof + 0x0000000000009064 sys_setregid + 0x000000000000911d sys_setgid + 0x00000000000091b4 sys_acct + 0x00000000000091ba sys_phys + 0x00000000000091c0 sys_lock + 0x00000000000091c6 sys_mpx + 0x00000000000091cc sys_ulimit + 0x00000000000091d2 sys_time + 0x000000000000922e sys_setreuid + 0x0000000000009310 sys_setuid + 0x00000000000093a5 sys_stime + 0x00000000000093fb sys_times + 0x000000000000949b sys_brk + 0x00000000000094dd sys_setpgid + 0x00000000000095b6 sys_getpgrp + 0x00000000000095c2 sys_setsid + 0x000000000000963c sys_getgroups + 0x0000000000009642 sys_setgroups + 0x0000000000009648 sys_uname + 0x00000000000096b1 sys_sethostname + 0x00000000000096b7 sys_getrlimit + 0x00000000000096bd sys_setrlimit + 0x00000000000096c3 sys_getrusage + 0x00000000000096c9 sys_gettimeofday + 0x00000000000096cf sys_settimeofday + 0x00000000000096d5 sys_umask + 0x0000000000009746 release + 0x0000000000009883 sys_kill + 0x0000000000009abd do_exit + 0x0000000000009cf1 sys_exit + 0x0000000000009d0a sys_waitpid + 0x0000000000009f62 sys_sgetmask + 0x0000000000009f6e sys_ssetmask + 0x0000000000009f9a sys_sigpending + 0x0000000000009fa0 sys_sigsuspend + 0x000000000000a039 sys_signal + 0x000000000000a0bd sys_sigaction + 0x000000000000a1c7 do_signal + 0x000000000000a3b3 kernel_mktime + 0x000000000000a4f8 sys_getdents + 0x000000000000a650 sys_pipe2 + 0x000000000000a663 sys_sleep + .text 0x000000000000a69c 0xb01 mm/mm.o + 0x000000000000a6bb get_free_page + 0x000000000000a6f7 free_page + 0x000000000000a766 free_page_tables + 0x000000000000a865 copy_page_tables + 0x000000000000a9e6 put_page + 0x000000000000aad2 un_wp_page + 0x000000000000ab8a do_wp_page + 0x000000000000abbc write_verify + 0x000000000000ac15 get_empty_page + 0x000000000000ae9b do_no_page + 0x000000000000affd mem_init + 0x000000000000b071 calc_mem + 0x000000000000b166 page_fault + .text 0x000000000000b19d 0x800b fs/fs.o + 0x000000000000b1b3 sys_ustat + 0x000000000000b1b9 sys_utime + 0x000000000000b266 sys_access + 0x000000000000b342 sys_chdir + 0x000000000000b3b6 sys_chroot + 0x000000000000b42a sys_chmod + 0x000000000000b4c4 sys_chown + 0x000000000000b53f sys_open + 0x000000000000b7e2 sys_creat + 0x000000000000b805 sys_close + 0x000000000000b8d4 sys_lseek + 0x000000000000b9eb sys_read + 0x000000000000bbde sys_write + 0x000000000000bdd7 invalidate_inodes + 0x000000000000be46 sync_inodes + 0x000000000000c289 bmap + 0x000000000000c2ac create_block + 0x000000000000c2cf iput + 0x000000000000c43e get_empty_inode + 0x000000000000c593 get_pipe_inode + 0x000000000000c608 iget + 0x000000000000ca03 sys_sync + 0x000000000000ca66 sync_dev + 0x000000000000cb5f invalidate_buffers + 0x000000000000cbd1 check_disk_change + 0x000000000000ce9f get_hash_table + 0x000000000000cf21 getblk + 0x000000000000d0bf brelse + 0x000000000000d108 bread + 0x000000000000d18d bread_page + 0x000000000000d2af breada + 0x000000000000d3a4 buffer_init + 0x000000000000d545 get_super + 0x000000000000d5b4 put_super + 0x000000000000d9ca sys_umount + 0x000000000000db2b sys_mount + 0x000000000000dc9c mount_root + 0x000000000000ded0 block_write + 0x000000000000e022 block_read + 0x000000000000e38d rw_char + 0x000000000000e41d file_read + 0x000000000000e5c8 file_write + 0x000000000000e8b1 sys_stat + 0x000000000000e8fb sys_lstat + 0x000000000000e916 sys_fstat + 0x000000000000e973 sys_readlink + 0x000000000000ea22 sys_uselib + 0x000000000000eef1 do_execve + 0x000000000000f973 do_execve2 + 0x0000000000010477 read_pipe + 0x00000000000105cd write_pipe + 0x000000000001074c sys_pipe + 0x000000000001112b namei + 0x0000000000011241 open_namei + 0x0000000000011594 sys_mknod + 0x00000000000117c4 sys_mkdir + 0x0000000000011d53 sys_rmdir + 0x00000000000120ab sys_unlink + 0x000000000001234c sys_symlink + 0x0000000000012352 sys_link + 0x00000000000125ac free_block + 0x000000000001271e new_block + 0x00000000000128c2 free_inode + 0x0000000000012a29 new_inode + 0x0000000000012cdd sys_dup2 + 0x0000000000012d04 sys_dup + 0x0000000000012d1f sys_fcntl + 0x0000000000012e5e sys_ioctl + 0x000000000001306d truncate + 0x00000000000131a2 sys_select + .text 0x00000000000131a8 0x46a kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + 0x000000000001356b ll_rw_block + 0x00000000000135c4 blk_dev_init + .text 0x0000000000013612 0xb9d kernel/blk_drv/blk_drv.a(floppy.o) + 0x00000000000136f8 floppy_deselect + 0x000000000001372f floppy_change + 0x0000000000013aec setup_rw_floppy + 0x0000000000013d85 unexpected_floppy_interrupt + 0x000000000001415d floppy_init + .text 0x00000000000141af 0xc8f kernel/blk_drv/blk_drv.a(hd.o) + 0x0000000000014283 sys_setup + 0x0000000000014932 unexpected_hd_interrupt + 0x0000000000014dc4 hd_init + .text 0x0000000000014e3e 0x50c kernel/blk_drv/blk_drv.a(ramdisk.o) + 0x0000000000015048 rd_init + 0x000000000001509e rd_load + .text 0x000000000001534a 0xcbb kernel/chr_drv/chr_drv.a(tty_io.o) + 0x0000000000015370 tty_init + 0x0000000000015381 tty_intr + 0x000000000001548e wait_for_keypress + 0x00000000000154a1 copy_to_cooked + 0x0000000000015a5c tty_read + 0x0000000000015dca tty_write + 0x0000000000015fdc do_tty_interrupt + 0x0000000000016004 chr_dev_init + .text 0x0000000000016005 0x1283 kernel/chr_drv/chr_drv.a(console.o) + 0x00000000000165a2 csi_m + 0x000000000001693c con_write + 0x0000000000016fca con_init + 0x0000000000017201 sysbeepstop + .text 0x0000000000017288 0x7e2 kernel/chr_drv/chr_drv.a(keyboard.2.o) + 0x000000000001728b keyboard_interrupt + .text 0x0000000000017a6a 0x145 kernel/chr_drv/chr_drv.a(serial.o) + 0x0000000000017adf rs_init + 0x0000000000017b62 rs_write + *fill* 0x0000000000017baf 0x1 + .text 0x0000000000017bb0 0xf7 kernel/chr_drv/chr_drv.a(rs_io.o) + 0x0000000000017bb0 rs1_interrupt + 0x0000000000017bb8 rs2_interrupt + .text 0x0000000000017ca7 0x60f kernel/chr_drv/chr_drv.a(tty_ioctl.o) + 0x0000000000017fb8 tty_ioctl + .text 0x00000000000182b6 0x111 kernel/math/math.a(math_emulate.o) + 0x00000000000182c4 math_emulate + 0x00000000000183a7 math_error + .text 0x00000000000183c7 0x0 lib/lib.a(ctype.o) + .text 0x00000000000183c7 0x10 lib/lib.a(_exit.o) + 0x00000000000183c7 _exit + .text 0x00000000000183d7 0x49 lib/lib.a(open.o) + 0x00000000000183d7 open + .text 0x0000000000018420 0x37 lib/lib.a(close.o) + 0x0000000000018420 close + .text 0x0000000000018457 0x0 lib/lib.a(errno.o) + .text 0x0000000000018457 0x3d lib/lib.a(write.o) + 0x0000000000018457 write + .text 0x0000000000018494 0x37 lib/lib.a(dup.o) + 0x0000000000018494 dup + .text 0x00000000000184cb 0x2f lib/lib.a(setsid.o) + 0x00000000000184cb setsid + .text 0x00000000000184fa 0x3d lib/lib.a(execve.o) + 0x00000000000184fa execve + .text 0x0000000000018537 0x60 lib/lib.a(wait.o) + 0x0000000000018537 waitpid + 0x0000000000018574 wait + .text 0x0000000000018597 0x3dc lib/lib.a(string.o) + 0x0000000000018597 strcpy + 0x00000000000185b3 strncpy + 0x00000000000185d8 strcat + 0x0000000000018603 strncat + 0x0000000000018638 strcmp + 0x000000000001865f strncmp + 0x000000000001868d strchr + 0x00000000000186ba strrchr + 0x00000000000186e9 strspn + 0x0000000000018726 strcspn + 0x0000000000018763 strpbrk + 0x000000000001879a strstr + 0x00000000000187d3 strlen + 0x00000000000187f6 strtok + 0x0000000000018879 memcpy + 0x0000000000018899 memmove + 0x00000000000188ed memcmp + 0x0000000000018917 memchr + 0x000000000001894f memset + *(.gnu.warning) + +.fini + *(SORT(.fini)) + 0x0000000000018973 PROVIDE (__etext, .) + 0x0000000000018973 PROVIDE (_etext, .) + 0x0000000000018973 PROVIDE (etext, .) + +.rodata 0x0000000000018974 0x13ca + *(.rodata .rodata.* .gnu.linkonce.r.*) + .rodata 0x0000000000018974 0xad init/main.o + *fill* 0x0000000000018a21 0x3 + .rodata 0x0000000000018a24 0x438 kernel/kernel.o + .rodata 0x0000000000018e5c 0x18f mm/mm.o + *fill* 0x0000000000018feb 0x1 + .rodata 0x0000000000018fec 0x62c fs/fs.o + .rodata 0x0000000000019618 0x7a kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + *fill* 0x0000000000019692 0x2 + .rodata 0x0000000000019694 0x133 kernel/blk_drv/blk_drv.a(floppy.o) + *fill* 0x00000000000197c7 0x1 + .rodata 0x00000000000197c8 0x19b kernel/blk_drv/blk_drv.a(hd.o) + *fill* 0x0000000000019963 0x1 + .rodata 0x0000000000019964 0x188 kernel/blk_drv/blk_drv.a(ramdisk.o) + .rodata 0x0000000000019aec 0x17d kernel/chr_drv/chr_drv.a(console.o) + *fill* 0x0000000000019c69 0x3 + .rodata 0x0000000000019c6c 0x80 kernel/chr_drv/chr_drv.a(tty_ioctl.o) + .rodata 0x0000000000019cec 0x52 kernel/math/math.a(math_emulate.o) + +.rodata1 + *(.rodata1) + +.eh_frame_hdr + *(.eh_frame_hdr) + +.eh_frame 0x0000000000019d40 0x2af0 + *(.eh_frame) + .eh_frame 0x0000000000019d40 0xf0 init/main.o + .eh_frame 0x0000000000019e30 0xb50 kernel/kernel.o + 0xc88 (size before relaxing) + .eh_frame 0x000000000001a980 0x194 mm/mm.o + 0x1ac (size before relaxing) + .eh_frame 0x000000000001ab14 0xe10 fs/fs.o + 0xfa8 (size before relaxing) + .eh_frame 0x000000000001b924 0x98 kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + 0xb0 (size before relaxing) + .eh_frame 0x000000000001b9bc 0x23c kernel/blk_drv/blk_drv.a(floppy.o) + 0x254 (size before relaxing) + .eh_frame 0x000000000001bbf8 0x1e8 kernel/blk_drv/blk_drv.a(hd.o) + 0x200 (size before relaxing) + .eh_frame 0x000000000001bde0 0xac kernel/blk_drv/blk_drv.a(ramdisk.o) + 0xc4 (size before relaxing) + .eh_frame 0x000000000001be8c 0x12c kernel/chr_drv/chr_drv.a(tty_io.o) + 0x144 (size before relaxing) + .eh_frame 0x000000000001bfb8 0x2c0 kernel/chr_drv/chr_drv.a(console.o) + 0x2d8 (size before relaxing) + .eh_frame 0x000000000001c278 0x54 kernel/chr_drv/chr_drv.a(serial.o) + 0x6c (size before relaxing) + .eh_frame 0x000000000001c2cc 0x148 kernel/chr_drv/chr_drv.a(tty_ioctl.o) + 0x160 (size before relaxing) + .eh_frame 0x000000000001c414 0x5c kernel/math/math.a(math_emulate.o) + 0x74 (size before relaxing) + .eh_frame 0x000000000001c470 0x1c lib/lib.a(_exit.o) + 0x34 (size before relaxing) + .eh_frame 0x000000000001c48c 0x24 lib/lib.a(open.o) + 0x3c (size before relaxing) + .eh_frame 0x000000000001c4b0 0x20 lib/lib.a(close.o) + 0x38 (size before relaxing) + .eh_frame 0x000000000001c4d0 0x20 lib/lib.a(write.o) + 0x38 (size before relaxing) + .eh_frame 0x000000000001c4f0 0x20 lib/lib.a(dup.o) + 0x38 (size before relaxing) + .eh_frame 0x000000000001c510 0x18 lib/lib.a(setsid.o) + 0x30 (size before relaxing) + .eh_frame 0x000000000001c528 0x20 lib/lib.a(execve.o) + 0x38 (size before relaxing) + .eh_frame 0x000000000001c548 0x38 lib/lib.a(wait.o) + 0x50 (size before relaxing) + .eh_frame 0x000000000001c580 0x2b0 lib/lib.a(string.o) + 0x2c8 (size before relaxing) + +.gcc_except_table + *(.gcc_except_table .gcc_except_table.*) + +.exception_ranges + *(.exception_ranges .exception_ranges*) + 0x000000000001c830 . = . + +.eh_frame + *(.eh_frame) + +.gcc_except_table + *(.gcc_except_table .gcc_except_table.*) + +.exception_ranges + *(.exception_ranges .exception_ranges*) + +.tdata + *(.tdata .tdata.* .gnu.linkonce.td.*) + +.tbss + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + +.preinit_array 0x000000000001c830 0x0 + 0x000000000001c830 PROVIDE (__preinit_array_start, .) + *(.preinit_array) + 0x000000000001c830 PROVIDE (__preinit_array_end, .) + +.init_array 0x000000000001c830 0x0 + 0x000000000001c830 PROVIDE (__init_array_start, .) + *(SORT(.init_array.*) SORT(.ctors.*)) + *(.init_array EXCLUDE_FILE(*crtend?.o *crtend.o *crtbegin?.o *crtbegin.o) .ctors) + 0x000000000001c830 PROVIDE (__init_array_end, .) + +.fini_array 0x000000000001c830 0x0 + 0x000000000001c830 PROVIDE (__fini_array_start, .) + *(SORT(.fini_array.*) SORT(.dtors.*)) + *(.fini_array EXCLUDE_FILE(*crtend?.o *crtend.o *crtbegin?.o *crtbegin.o) .dtors) + 0x000000000001c830 PROVIDE (__fini_array_end, .) + +.ctors + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + +.dtors + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + +.jcr + *(.jcr) + +.data.rel.ro + *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) + *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) + +.dynamic + *(.dynamic) + +.got + *(.got) + *(.igot) + +.got.plt 0x000000000001c830 0x0 + *(.got.plt) + *(.igot.plt) + .igot.plt 0x0000000000000000 0x0 boot/head.o + +.data 0x000000000001c840 0x3b21 + *(.data .data.* .gnu.linkonce.d.*) + .data 0x000000000001c840 0x0 boot/head.o + .data 0x000000000001c840 0x28 init/main.o + *fill* 0x000000000001c868 0x18 + .data 0x000000000001c880 0x1330 kernel/kernel.o + 0x000000000001c880 sys_call_table + 0x000000000001c9ec NR_syscalls + 0x000000000001da00 current + 0x000000000001da20 task + 0x000000000001db20 stack_start + 0x000000000001db28 current_DOR + .data 0x000000000001dbb0 0x0 mm/mm.o + *fill* 0x000000000001dbb0 0x10 + .data 0x000000000001dbc0 0x60 fs/fs.o + 0x000000000001dbc4 start_buffer + .data 0x000000000001dc20 0x0 kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + .data 0x000000000001dc20 0xcd kernel/blk_drv/blk_drv.a(floppy.o) + *fill* 0x000000000001dced 0x3 + .data 0x000000000001dcf0 0x4 kernel/blk_drv/blk_drv.a(hd.o) + .data 0x000000000001dcf4 0x0 kernel/blk_drv/blk_drv.a(ramdisk.o) + *fill* 0x000000000001dcf4 0xc + .data 0x000000000001dd00 0x2538 kernel/chr_drv/chr_drv.a(tty_io.o) + 0x000000000001dd00 tty_table + 0x0000000000020220 table_list + .data 0x0000000000020238 0x1 kernel/chr_drv/chr_drv.a(console.o) + .data 0x0000000000020239 0x0 kernel/chr_drv/chr_drv.a(keyboard.2.o) + .data 0x0000000000020239 0x0 kernel/chr_drv/chr_drv.a(serial.o) + .data 0x0000000000020239 0x0 kernel/chr_drv/chr_drv.a(rs_io.o) + *fill* 0x0000000000020239 0x7 + .data 0x0000000000020240 0x20 kernel/chr_drv/chr_drv.a(tty_ioctl.o) + .data 0x0000000000020260 0x0 kernel/math/math.a(math_emulate.o) + .data 0x0000000000020260 0x101 lib/lib.a(ctype.o) + 0x0000000000020260 _ctype + .data 0x0000000000020361 0x0 lib/lib.a(_exit.o) + .data 0x0000000000020361 0x0 lib/lib.a(open.o) + .data 0x0000000000020361 0x0 lib/lib.a(close.o) + .data 0x0000000000020361 0x0 lib/lib.a(errno.o) + .data 0x0000000000020361 0x0 lib/lib.a(write.o) + .data 0x0000000000020361 0x0 lib/lib.a(dup.o) + .data 0x0000000000020361 0x0 lib/lib.a(setsid.o) + .data 0x0000000000020361 0x0 lib/lib.a(execve.o) + .data 0x0000000000020361 0x0 lib/lib.a(wait.o) + .data 0x0000000000020361 0x0 lib/lib.a(string.o) + +.data1 + *(.data1) + 0x0000000000020361 _edata = . + 0x0000000000020361 PROVIDE (edata, .) + 0x0000000000020361 . = . + 0x0000000000020361 __bss_start = . + +.bss 0x0000000000020380 0x44b0 + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + .bss 0x0000000000020380 0x0 boot/head.o + .bss 0x0000000000020380 0x40c init/main.o + *fill* 0x000000000002078c 0x14 + .bss 0x00000000000207a0 0x760 kernel/kernel.o + 0x00000000000207a0 jiffies + 0x00000000000207a4 startup_time + 0x00000000000207a8 last_task_used_math + 0x0000000000020ae4 last_pid + .bss 0x0000000000020f00 0xf20 mm/mm.o + .bss 0x0000000000021e20 0x710 fs/fs.o + 0x0000000000021e20 inode_table + 0x0000000000022520 nr_buffers + 0x000000000002252c ROOT_DEV + *fill* 0x0000000000022530 0x10 + .bss 0x0000000000022540 0x58 kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + 0x0000000000022540 wait_for_request + 0x0000000000022560 blk_dev + .bss 0x0000000000022598 0x25 kernel/blk_drv/blk_drv.a(floppy.o) + 0x0000000000022598 do_floppy + 0x000000000002259c selected + 0x00000000000225a0 wait_on_floppy_select + *fill* 0x00000000000225bd 0x3 + .bss 0x00000000000225c0 0xb0 kernel/blk_drv/blk_drv.a(hd.o) + 0x00000000000225c0 do_hd + 0x00000000000225e0 hd_info + .bss 0x0000000000022670 0x4 kernel/blk_drv/blk_drv.a(ramdisk.o) + 0x0000000000022670 rd_length + .bss 0x0000000000022674 0x4 kernel/chr_drv/chr_drv.a(tty_io.o) + *fill* 0x0000000000022678 0x8 + .bss 0x0000000000022680 0xac kernel/chr_drv/chr_drv.a(console.o) + 0x0000000000022680 beepcount + .bss 0x000000000002272c 0x0 kernel/chr_drv/chr_drv.a(keyboard.2.o) + .bss 0x000000000002272c 0x0 kernel/chr_drv/chr_drv.a(serial.o) + .bss 0x000000000002272c 0x0 kernel/chr_drv/chr_drv.a(rs_io.o) + .bss 0x000000000002272c 0x0 kernel/chr_drv/chr_drv.a(tty_ioctl.o) + .bss 0x000000000002272c 0x0 kernel/math/math.a(math_emulate.o) + .bss 0x000000000002272c 0x0 lib/lib.a(ctype.o) + .bss 0x000000000002272c 0x0 lib/lib.a(_exit.o) + .bss 0x000000000002272c 0x0 lib/lib.a(open.o) + .bss 0x000000000002272c 0x0 lib/lib.a(close.o) + .bss 0x000000000002272c 0x0 lib/lib.a(errno.o) + .bss 0x000000000002272c 0x0 lib/lib.a(write.o) + .bss 0x000000000002272c 0x0 lib/lib.a(dup.o) + .bss 0x000000000002272c 0x0 lib/lib.a(setsid.o) + .bss 0x000000000002272c 0x0 lib/lib.a(execve.o) + .bss 0x000000000002272c 0x0 lib/lib.a(wait.o) + .bss 0x000000000002272c 0x0 lib/lib.a(string.o) + *(COMMON) + *fill* 0x000000000002272c 0x14 + COMMON 0x0000000000022740 0x20 init/main.o + 0x0000000000022740 drive_info + COMMON 0x0000000000022760 0x1000 kernel/kernel.o + 0x0000000000022760 user_stack + COMMON 0x0000000000023760 0xc40 fs/fs.o + 0x0000000000023760 hash_table + 0x0000000000023c40 super_block + 0x0000000000023fa0 file_table + COMMON 0x00000000000243a0 0x480 kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + 0x00000000000243a0 request + COMMON 0x0000000000024820 0x4 kernel/blk_drv/blk_drv.a(ramdisk.o) + 0x0000000000024820 rd_start + COMMON 0x0000000000024824 0x1 lib/lib.a(ctype.o) + 0x0000000000024824 _ctmp + *fill* 0x0000000000024825 0x3 + COMMON 0x0000000000024828 0x4 lib/lib.a(errno.o) + 0x0000000000024828 errno + COMMON 0x000000000002482c 0x4 lib/lib.a(string.o) + 0x000000000002482c ___strtok + 0x0000000000024830 . = ALIGN ((. != 0x0)?0x4:0x1) + 0x0000000000024830 . = ALIGN (0x4) + 0x0000000000024830 . = SEGMENT_START ("ldata-segment", .) + 0x0000000000024830 . = ALIGN (0x4) + 0x0000000000024830 _end = . + 0x0000000000024830 PROVIDE (end, .) + +.stab + *(.stab) + +.stabstr + *(.stabstr) + +.stab.excl + *(.stab.excl) + +.stab.exclstr + *(.stab.exclstr) + +.stab.index + *(.stab.index) + +.stab.indexstr + *(.stab.indexstr) + +.comment 0x0000000000000000 0x29 + *(.comment) + .comment 0x0000000000000000 0x29 init/main.o + 0x2a (size before relaxing) + .comment 0x0000000000000000 0x222 kernel/kernel.o + .comment 0x0000000000000000 0x2a mm/mm.o + .comment 0x0000000000000000 0x2f4 fs/fs.o + .comment 0x0000000000000000 0x2a kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + .comment 0x0000000000000000 0x2a kernel/blk_drv/blk_drv.a(floppy.o) + .comment 0x0000000000000000 0x2a kernel/blk_drv/blk_drv.a(hd.o) + .comment 0x0000000000000000 0x2a kernel/blk_drv/blk_drv.a(ramdisk.o) + .comment 0x0000000000000000 0x2a kernel/chr_drv/chr_drv.a(tty_io.o) + .comment 0x0000000000000000 0x2a kernel/chr_drv/chr_drv.a(console.o) + .comment 0x0000000000000000 0x2a kernel/chr_drv/chr_drv.a(serial.o) + .comment 0x0000000000000000 0x2a kernel/chr_drv/chr_drv.a(tty_ioctl.o) + .comment 0x0000000000000000 0x2a kernel/math/math.a(math_emulate.o) + .comment 0x0000000000000000 0x2a lib/lib.a(ctype.o) + .comment 0x0000000000000000 0x2a lib/lib.a(_exit.o) + .comment 0x0000000000000000 0x2a lib/lib.a(open.o) + .comment 0x0000000000000000 0x2a lib/lib.a(close.o) + .comment 0x0000000000000000 0x2a lib/lib.a(errno.o) + .comment 0x0000000000000000 0x2a lib/lib.a(write.o) + .comment 0x0000000000000000 0x2a lib/lib.a(dup.o) + .comment 0x0000000000000000 0x2a lib/lib.a(setsid.o) + .comment 0x0000000000000000 0x2a lib/lib.a(execve.o) + .comment 0x0000000000000000 0x2a lib/lib.a(wait.o) + .comment 0x0000000000000000 0x2a lib/lib.a(string.o) + +.debug + *(.debug) + +.line + *(.line) + +.debug_srcinfo + *(.debug_srcinfo) + +.debug_sfnames + *(.debug_sfnames) + +.debug_aranges 0x0000000000000000 0x688 + *(.debug_aranges) + .debug_aranges + 0x0000000000000000 0x20 init/main.o + .debug_aranges + 0x0000000000000020 0x1a0 kernel/kernel.o + .debug_aranges + 0x00000000000001c0 0x20 mm/mm.o + .debug_aranges + 0x00000000000001e0 0x238 fs/fs.o + .debug_aranges + 0x0000000000000418 0x20 kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + .debug_aranges + 0x0000000000000438 0x20 kernel/blk_drv/blk_drv.a(floppy.o) + .debug_aranges + 0x0000000000000458 0x20 kernel/blk_drv/blk_drv.a(hd.o) + .debug_aranges + 0x0000000000000478 0x20 kernel/blk_drv/blk_drv.a(ramdisk.o) + .debug_aranges + 0x0000000000000498 0x20 kernel/chr_drv/chr_drv.a(tty_io.o) + .debug_aranges + 0x00000000000004b8 0x20 kernel/chr_drv/chr_drv.a(console.o) + .debug_aranges + 0x00000000000004d8 0x20 kernel/chr_drv/chr_drv.a(serial.o) + .debug_aranges + 0x00000000000004f8 0x20 kernel/chr_drv/chr_drv.a(tty_ioctl.o) + .debug_aranges + 0x0000000000000518 0x20 kernel/math/math.a(math_emulate.o) + .debug_aranges + 0x0000000000000538 0x18 lib/lib.a(ctype.o) + .debug_aranges + 0x0000000000000550 0x20 lib/lib.a(_exit.o) + .debug_aranges + 0x0000000000000570 0x20 lib/lib.a(open.o) + .debug_aranges + 0x0000000000000590 0x20 lib/lib.a(close.o) + .debug_aranges + 0x00000000000005b0 0x18 lib/lib.a(errno.o) + .debug_aranges + 0x00000000000005c8 0x20 lib/lib.a(write.o) + .debug_aranges + 0x00000000000005e8 0x20 lib/lib.a(dup.o) + .debug_aranges + 0x0000000000000608 0x20 lib/lib.a(setsid.o) + .debug_aranges + 0x0000000000000628 0x20 lib/lib.a(execve.o) + .debug_aranges + 0x0000000000000648 0x20 lib/lib.a(wait.o) + .debug_aranges + 0x0000000000000668 0x20 lib/lib.a(string.o) + +.debug_pubnames + *(.debug_pubnames) + +.debug_info 0x0000000000000000 0x178c8 + *(.debug_info .gnu.linkonce.wi.*) + .debug_info 0x0000000000000000 0x553 init/main.o + .debug_info 0x0000000000000553 0x566e kernel/kernel.o + .debug_info 0x0000000000005bc1 0xb2b mm/mm.o + .debug_info 0x00000000000066ec 0xa47d fs/fs.o + .debug_info 0x0000000000010b69 0x932 kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + .debug_info 0x000000000001149b 0xc9f kernel/blk_drv/blk_drv.a(floppy.o) + .debug_info 0x000000000001213a 0xd5f kernel/blk_drv/blk_drv.a(hd.o) + .debug_info 0x0000000000012e99 0xad5 kernel/blk_drv/blk_drv.a(ramdisk.o) + .debug_info 0x000000000001396e 0xacd kernel/chr_drv/chr_drv.a(tty_io.o) + .debug_info 0x000000000001443b 0xdb0 kernel/chr_drv/chr_drv.a(console.o) + .debug_info 0x00000000000151eb 0x85c kernel/chr_drv/chr_drv.a(serial.o) + .debug_info 0x0000000000015a47 0xb47 kernel/chr_drv/chr_drv.a(tty_ioctl.o) + .debug_info 0x000000000001658e 0x7b5 kernel/math/math.a(math_emulate.o) + .debug_info 0x0000000000016d43 0x66 lib/lib.a(ctype.o) + .debug_info 0x0000000000016da9 0x77 lib/lib.a(_exit.o) + .debug_info 0x0000000000016e20 0xd0 lib/lib.a(open.o) + .debug_info 0x0000000000016ef0 0x97 lib/lib.a(close.o) + .debug_info 0x0000000000016f87 0x36 lib/lib.a(errno.o) + .debug_info 0x0000000000016fbd 0xc9 lib/lib.a(write.o) + .debug_info 0x0000000000017086 0x97 lib/lib.a(dup.o) + .debug_info 0x000000000001711d 0x95 lib/lib.a(setsid.o) + .debug_info 0x00000000000171b2 0xcb lib/lib.a(execve.o) + .debug_info 0x000000000001727d 0xed lib/lib.a(wait.o) + .debug_info 0x000000000001736a 0x55e lib/lib.a(string.o) + +.debug_abbrev 0x0000000000000000 0x4669 + *(.debug_abbrev) + .debug_abbrev 0x0000000000000000 0x1d3 init/main.o + .debug_abbrev 0x00000000000001d3 0x11ca kernel/kernel.o + .debug_abbrev 0x000000000000139d 0x20b mm/mm.o + .debug_abbrev 0x00000000000015a8 0x1a3a fs/fs.o + .debug_abbrev 0x0000000000002fe2 0x169 kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + .debug_abbrev 0x000000000000314b 0x27d kernel/blk_drv/blk_drv.a(floppy.o) + .debug_abbrev 0x00000000000033c8 0x23c kernel/blk_drv/blk_drv.a(hd.o) + .debug_abbrev 0x0000000000003604 0x1a8 kernel/blk_drv/blk_drv.a(ramdisk.o) + .debug_abbrev 0x00000000000037ac 0x279 kernel/chr_drv/chr_drv.a(tty_io.o) + .debug_abbrev 0x0000000000003a25 0x26b kernel/chr_drv/chr_drv.a(console.o) + .debug_abbrev 0x0000000000003c90 0x175 kernel/chr_drv/chr_drv.a(serial.o) + .debug_abbrev 0x0000000000003e05 0x18d kernel/chr_drv/chr_drv.a(tty_ioctl.o) + .debug_abbrev 0x0000000000003f92 0x163 kernel/math/math.a(math_emulate.o) + .debug_abbrev 0x00000000000040f5 0x3e lib/lib.a(ctype.o) + .debug_abbrev 0x0000000000004133 0x51 lib/lib.a(_exit.o) + .debug_abbrev 0x0000000000004184 0x97 lib/lib.a(open.o) + .debug_abbrev 0x000000000000421b 0x75 lib/lib.a(close.o) + .debug_abbrev 0x0000000000004290 0x2c lib/lib.a(errno.o) + .debug_abbrev 0x00000000000042bc 0xa1 lib/lib.a(write.o) + .debug_abbrev 0x000000000000435d 0x75 lib/lib.a(dup.o) + .debug_abbrev 0x00000000000043d2 0x73 lib/lib.a(setsid.o) + .debug_abbrev 0x0000000000004445 0x85 lib/lib.a(execve.o) + .debug_abbrev 0x00000000000044ca 0xb6 lib/lib.a(wait.o) + .debug_abbrev 0x0000000000004580 0xe9 lib/lib.a(string.o) + +.debug_line 0x0000000000000000 0x48af + *(.debug_line .debug_line.* .debug_line_end) + .debug_line 0x0000000000000000 0x1a7 init/main.o + .debug_line 0x00000000000001a7 0x1004 kernel/kernel.o + .debug_line 0x00000000000011ab 0x274 mm/mm.o + .debug_line 0x000000000000141f 0x1de8 fs/fs.o + .debug_line 0x0000000000003207 0x197 kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + .debug_line 0x000000000000339e 0x24c kernel/blk_drv/blk_drv.a(floppy.o) + .debug_line 0x00000000000035ea 0x2bf kernel/blk_drv/blk_drv.a(hd.o) + .debug_line 0x00000000000038a9 0x160 kernel/blk_drv/blk_drv.a(ramdisk.o) + .debug_line 0x0000000000003a09 0x33b kernel/chr_drv/chr_drv.a(tty_io.o) + .debug_line 0x0000000000003d44 0x3ab kernel/chr_drv/chr_drv.a(console.o) + .debug_line 0x00000000000040ef 0xd9 kernel/chr_drv/chr_drv.a(serial.o) + .debug_line 0x00000000000041c8 0x1db kernel/chr_drv/chr_drv.a(tty_ioctl.o) + .debug_line 0x00000000000043a3 0xe1 kernel/math/math.a(math_emulate.o) + .debug_line 0x0000000000004484 0x28 lib/lib.a(ctype.o) + .debug_line 0x00000000000044ac 0x39 lib/lib.a(_exit.o) + .debug_line 0x00000000000044e5 0x62 lib/lib.a(open.o) + .debug_line 0x0000000000004547 0x5c lib/lib.a(close.o) + .debug_line 0x00000000000045a3 0x28 lib/lib.a(errno.o) + .debug_line 0x00000000000045cb 0x76 lib/lib.a(write.o) + .debug_line 0x0000000000004641 0x5a lib/lib.a(dup.o) + .debug_line 0x000000000000469b 0x77 lib/lib.a(setsid.o) + .debug_line 0x0000000000004712 0x5d lib/lib.a(execve.o) + .debug_line 0x000000000000476f 0x7a lib/lib.a(wait.o) + .debug_line 0x00000000000047e9 0xc6 lib/lib.a(string.o) + +.debug_frame + *(.debug_frame) + +.debug_str 0x0000000000000000 0x2189 + *(.debug_str) + .debug_str 0x0000000000000000 0x1bc init/main.o + 0x1fb (size before relaxing) + .debug_str 0x00000000000001bc 0xbda kernel/kernel.o + 0x298e (size before relaxing) + .debug_str 0x0000000000000d96 0x181 mm/mm.o + 0x4dc (size before relaxing) + .debug_str 0x0000000000000f17 0x8bf fs/fs.o + 0x49be (size before relaxing) + .debug_str 0x00000000000017d6 0xf0 kernel/blk_drv/blk_drv.a(ll_rw_blk.o) + 0x491 (size before relaxing) + .debug_str 0x00000000000018c6 0x1cf kernel/blk_drv/blk_drv.a(floppy.o) + 0x673 (size before relaxing) + .debug_str 0x0000000000001a95 0x15e kernel/blk_drv/blk_drv.a(hd.o) + 0x5e8 (size before relaxing) + .debug_str 0x0000000000001bf3 0x43 kernel/blk_drv/blk_drv.a(ramdisk.o) + 0x58a (size before relaxing) + .debug_str 0x0000000000001c36 0xfb kernel/chr_drv/chr_drv.a(tty_io.o) + 0x4e3 (size before relaxing) + .debug_str 0x0000000000001d31 0x1b9 kernel/chr_drv/chr_drv.a(console.o) + 0x5b7 (size before relaxing) + .debug_str 0x0000000000001eea 0x1a kernel/chr_drv/chr_drv.a(serial.o) + 0x3fc (size before relaxing) + .debug_str 0x0000000000001f04 0x8b kernel/chr_drv/chr_drv.a(tty_ioctl.o) + 0x4a7 (size before relaxing) + .debug_str 0x0000000000001f8f 0x70 kernel/math/math.a(math_emulate.o) + 0x392 (size before relaxing) + .debug_str 0x0000000000001fff 0x8d lib/lib.a(ctype.o) + 0xb6 (size before relaxing) + .debug_str 0x000000000000208c 0x31 lib/lib.a(_exit.o) + 0xde (size before relaxing) + .debug_str 0x0000000000000000 0x31 lib/lib.a(open.o) + 0xee (size before relaxing) + .debug_str 0x00000000000020bd 0x8 lib/lib.a(close.o) + 0xe0 (size before relaxing) + .debug_str 0x00000000000020c5 0x8 lib/lib.a(errno.o) + 0x93 (size before relaxing) + .debug_str 0x0000000000000000 0x8 lib/lib.a(write.o) + 0xec (size before relaxing) + .debug_str 0x00000000000020cd 0x6 lib/lib.a(dup.o) + 0xd8 (size before relaxing) + .debug_str 0x00000000000020d3 0x9 lib/lib.a(setsid.o) + 0xe8 (size before relaxing) + .debug_str 0x00000000000020dc 0x9 lib/lib.a(execve.o) + 0xf1 (size before relaxing) + .debug_str 0x00000000000020e5 0x11 lib/lib.a(wait.o) + 0xfe (size before relaxing) + .debug_str 0x00000000000020f6 0x93 lib/lib.a(string.o) + 0x147 (size before relaxing) + +.debug_loc + *(.debug_loc) + +.debug_macinfo + *(.debug_macinfo) + +.debug_weaknames + *(.debug_weaknames) + +.debug_funcnames + *(.debug_funcnames) + +.debug_typenames + *(.debug_typenames) + +.debug_varnames + *(.debug_varnames) + +.debug_pubtypes + *(.debug_pubtypes) + +.debug_ranges 0x0000000000000000 0x18 + *(.debug_ranges) + .debug_ranges 0x0000000000000000 0x18 init/main.o + +.debug_macro + *(.debug_macro) + +.gnu.attributes + *(.gnu.attributes) + +/DISCARD/ + *(.note.GNU-stack) + *(.gnu_debuglink) + *(.gnu.lto_*) +OUTPUT(tools/system elf32-i386) diff --git a/linux/boot/bootsect b/linux/boot/bootsect new file mode 100644 index 0000000000000000000000000000000000000000..4fbb8f823afe23687f1887d48deeb19fdcf83049 GIT binary patch literal 544 zcmZQ%7GP0e00JfufdrZ$>>UT#`)=%Dn9z4%Cj+DAH_iW_m%fre~uHUSwNXN9*i=ymehGJ;Ln!ff#WtiVnQ zhTZH8d+ix_Fbba)*ufysci@E)!;7N~dJF$B+A=VditBaD0d;UNHUH)>;o2bsq=ibD zUjNfu{D<)s1B1c@RhzFW-(_8 zyWs)N8wX!-zAym_G6SXbtl4ZCONDkYGHA2SVkl+#&o+l)@hk?z1B+)cfHa*h-qdq| z733tt+pm`g1P2Cni_Kx^=9|Ib*m1R6Y!*YuwM`6-j~E!Y0DW7;8WkBGaTw@dps&vg zgE+6x1nv67yn*3e)L{k&UM`>f#FWgubcN!|;*!){1wB1IUM^lPq<|j0Og84wRRH+h BgWdoD literal 0 HcmV?d00001 diff --git a/linux/boot/bootsect.s b/linux/boot/bootsect.s new file mode 100644 index 0000000..711f103 --- /dev/null +++ b/linux/boot/bootsect.s @@ -0,0 +1,260 @@ +! +! SYS_SIZE is the number of clicks (16 bytes) to be loaded. +! 0x3000 is 0x30000 bytes = 196kB, more than enough for current +! versions of linux +! +SYSSIZE = 0x3000 +! +! bootsect.s (C) 1991 Linus Torvalds +! +! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves +! iself out of the way to address 0x90000, and jumps there. +! +! It then loads 'setup' directly after itself (0x90200), and the system +! at 0x10000, using BIOS interrupts. +! +! NOTE! currently system is at most 8*65536 bytes long. This should be no +! problem, even in the future. I want to keep it simple. This 512 kB +! kernel size should be enough, especially as this doesn't contain the +! buffer cache as in minix +! +! The loader has been made as simple as possible, and continuos +! read errors will result in a unbreakable loop. Reboot by hand. It +! loads pretty fast by getting whole sectors at a time whenever possible. + +.globl begtext, begdata, begbss, endtext, enddata, endbss +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +SETUPLEN = 4 ! nr of setup-sectors +BOOTSEG = 0x07c0 ! original address of boot-sector +INITSEG = 0x9000 ! we move boot here - out of the way +SETUPSEG = 0x9020 ! setup starts here +SYSSEG = 0x1000 ! system loaded at 0x10000 (65536). +ENDSEG = SYSSEG + SYSSIZE ! where to stop loading + +! ROOT_DEV: 0x000 - same type of floppy as boot. +! 0x301 - first partition on first drive etc +ROOT_DEV = 0x306 + +entry start +start: + mov ax,#BOOTSEG + mov ds,ax + mov ax,#INITSEG + mov es,ax + mov cx,#256 + sub si,si + sub di,di + rep + movw + jmpi go,INITSEG +go: mov ax,cs + mov ds,ax + mov es,ax +! put stack at 0x9ff00. + mov ss,ax + mov sp,#0xFF00 ! arbitrary value >>512 + +! load the setup-sectors directly after the bootblock. +! Note that 'es' is already set up. + +load_setup: + mov dx,#0x0000 ! drive 0, head 0 + mov cx,#0x0002 ! sector 2, track 0 + mov bx,#0x0200 ! address = 512, in INITSEG + mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors + int 0x13 ! read it + jnc ok_load_setup ! ok - continue + mov dx,#0x0000 + mov ax,#0x0000 ! reset the diskette + int 0x13 + j load_setup + +ok_load_setup: + +! Get disk drive parameters, specifically nr of sectors/track + + mov dl,#0x00 + mov ax,#0x0800 ! AH=8 is get drive parameters + int 0x13 + mov ch,#0x00 + seg cs + mov sectors,cx + mov ax,#INITSEG + mov es,ax + +! Print some inane message + + mov ah,#0x03 ! read cursor pos + xor bh,bh + int 0x10 + + mov cx,#24 + mov bx,#0x0007 ! page 0, attribute 7 (normal) + mov bp,#msg1 + mov ax,#0x1301 ! write string, move cursor + int 0x10 + +! ok, we've written the message, now +! we want to load the system (at 0x10000) + + mov ax,#SYSSEG + mov es,ax ! segment of 0x010000 + call read_it + call kill_motor + +! After that we check which root-device to use. If the device is +! defined (!= 0), nothing is done and the given device is used. +! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending +! on the number of sectors that the BIOS reports currently. + + seg cs + mov ax,root_dev + cmp ax,#0 + jne root_defined + seg cs + mov bx,sectors + mov ax,#0x0208 ! /dev/ps0 - 1.2Mb + cmp bx,#15 + je root_defined + mov ax,#0x021c ! /dev/PS0 - 1.44Mb + cmp bx,#18 + je root_defined +undef_root: + jmp undef_root +root_defined: + seg cs + mov root_dev,ax + +! after that (everyting loaded), we jump to +! the setup-routine loaded directly after +! the bootblock: + + jmpi 0,SETUPSEG + +! This routine loads the system at address 0x10000, making sure +! no 64kB boundaries are crossed. We try to load it as fast as +! possible, loading whole tracks whenever we can. +! +! in: es - starting address segment (normally 0x1000) +! +sread: .word 1+SETUPLEN ! sectors read of current track +head: .word 0 ! current head +track: .word 0 ! current track + +read_it: + mov ax,es + test ax,#0x0fff +die: jne die ! es must be at 64kB boundary + xor bx,bx ! bx is starting address within segment +rp_read: + mov ax,es + cmp ax,#ENDSEG ! have we loaded all yet? + jb ok1_read + ret +ok1_read: + seg cs + mov ax,sectors + sub ax,sread + mov cx,ax + shl cx,#9 + add cx,bx + jnc ok2_read + je ok2_read + xor ax,ax + sub ax,bx + shr ax,#9 +ok2_read: + call read_track + mov cx,ax + add ax,sread + seg cs + cmp ax,sectors + jne ok3_read + mov ax,#1 + sub ax,head + jne ok4_read + inc track +ok4_read: + mov head,ax + xor ax,ax +ok3_read: + mov sread,ax + shl cx,#9 + add bx,cx + jnc rp_read + mov ax,es + add ax,#0x1000 + mov es,ax + xor bx,bx + jmp rp_read + +read_track: + push ax + push bx + push cx + push dx + mov dx,track + mov cx,sread + inc cx + mov ch,dl + mov dx,head + mov dh,dl + mov dl,#0 + and dx,#0x0100 + mov ah,#2 + int 0x13 + jc bad_rt + pop dx + pop cx + pop bx + pop ax + ret +bad_rt: mov ax,#0 + mov dx,#0 + int 0x13 + pop dx + pop cx + pop bx + pop ax + jmp read_track + +/* + * This procedure turns off the floppy drive motor, so + * that we enter the kernel in a known state, and + * don't have to worry about it later. + */ +kill_motor: + push dx + mov dx,#0x3f2 + mov al,#0 + outb + pop dx + ret + +sectors: + .word 0 + +msg1: + .byte 13,10 + .ascii "Loading system ..." + .byte 13,10,13,10 + +.org 508 +root_dev: + .word ROOT_DEV +boot_flag: + .word 0xAA55 + +.text +endtext: +.data +enddata: +.bss +endbss: diff --git a/linux/boot/head.s b/linux/boot/head.s new file mode 100644 index 0000000..651e95c --- /dev/null +++ b/linux/boot/head.s @@ -0,0 +1,240 @@ +/* + * linux/boot/head.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * head.s contains the 32-bit startup code. + * + * NOTE!!! Startup happens at absolute address 0x00000000, which is also where + * the page directory will exist. The startup code will be overwritten by + * the page directory. + */ +.text +.globl idt,gdt,pg_dir,tmp_floppy_area +pg_dir: +.globl startup_32 +startup_32: + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + mov %ax,%gs + lss stack_start,%esp + call setup_idt + call setup_gdt + movl $0x10,%eax # reload all the segment registers + mov %ax,%ds # after changing gdt. CS was already + mov %ax,%es # reloaded in 'setup_gdt' + mov %ax,%fs + mov %ax,%gs + lss stack_start,%esp + xorl %eax,%eax +1: incl %eax # check that A20 really IS enabled + movl %eax,0x000000 # loop forever if it isn't + cmpl %eax,0x100000 + je 1b +/* + * NOTE! 486 should set bit 16, to check for write-protect in supervisor + * mode. Then it would be unnecessary with the "verify_area()"-calls. + * 486 users probably want to set the NE (#5) bit also, so as to use + * int 16 for math errors. + */ + movl %cr0,%eax # check math chip + andl $0x80000011,%eax # Save PG,PE,ET +/* "orl $0x10020,%eax" here for 486 might be good */ + orl $2,%eax # set MP + movl %eax,%cr0 + call check_x87 + jmp after_page_tables + +/* + * We depend on ET to be correct. This checks for 287/387. + */ +check_x87: + fninit + fstsw %ax + cmpb $0,%al + je 1f /* no coprocessor: have to set bits */ + movl %cr0,%eax + xorl $6,%eax /* reset MP, set EM */ + movl %eax,%cr0 + ret +.align 4 +1: .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ + ret + +/* + * setup_idt + * + * sets up a idt with 256 entries pointing to + * ignore_int, interrupt gates. It then loads + * idt. Everything that wants to install itself + * in the idt-table may do so themselves. Interrupts + * are enabled elsewhere, when we can be relatively + * sure everything is ok. This routine will be over- + * written by the page tables. + */ +setup_idt: + lea ignore_int,%edx + movl $0x00080000,%eax + movw %dx,%ax /* selector = 0x0008 = cs */ + movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ + + lea idt,%edi + mov $256,%ecx +rp_sidt: + movl %eax,(%edi) + movl %edx,4(%edi) + addl $8,%edi + dec %ecx + jne rp_sidt + lidt idt_descr + ret + +/* + * setup_gdt + * + * This routines sets up a new gdt and loads it. + * Only two entries are currently built, the same + * ones that were built in init.s. The routine + * is VERY complicated at two whole lines, so this + * rather long comment is certainly needed :-). + * This routine will beoverwritten by the page tables. + */ +setup_gdt: + lgdt gdt_descr + ret + +/* + * I put the kernel page tables right after the page directory, + * using 4 of them to span 16 Mb of physical memory. People with + * more than 16MB will have to expand this. + */ +.org 0x1000 +pg0: + +.org 0x2000 +pg1: + +.org 0x3000 +pg2: + +.org 0x4000 +pg3: + +.org 0x5000 +/* + * tmp_floppy_area is used by the floppy-driver when DMA cannot + * reach to a buffer-block. It needs to be aligned, so that it isn't + * on a 64kB border. + */ +tmp_floppy_area: + .fill 1024,1,0 + +after_page_tables: + pushl $0 # These are the parameters to main :-) + pushl $0 + pushl $0 + pushl $L6 # return address for main, if it decides to. + pushl $main + jmp setup_paging +L6: + jmp L6 # main should never return here, but + # just in case, we know what happens. + +/* This is the default interrupt "handler" :-) */ +int_msg: + .asciz "Unknown interrupt\n\r" +.align 4 +ignore_int: + 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 $int_msg + call printk + popl %eax + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + + +/* + * Setup_paging + * + * This routine sets up paging by setting the page bit + * in cr0. The page tables are set up, identity-mapping + * the first 16MB. The pager assumes that no illegal + * addresses are produced (ie >4Mb on a 4Mb machine). + * + * NOTE! Although all physical memory should be identity + * mapped by this routine, only the kernel page functions + * use the >1Mb addresses directly. All "normal" functions + * use just the lower 1Mb, or the local data space, which + * will be mapped to some other place - mm keeps track of + * that. + * + * For those with more memory than 16 Mb - tough luck. I've + * not got it, why should you :-) The source is here. Change + * it. (Seriously - it shouldn't be too difficult. Mostly + * change some constants etc. I left it at 16Mb, as my machine + * even cannot be extended past that (ok, but it was cheap :-) + * I've tried to show which constants to change by having + * some kind of marker at them (search for "16Mb"), but I + * won't guarantee that's all :-( ) + */ +.align 4 +setup_paging: + movl $1024*5,%ecx /* 5 pages - pg_dir+4 page tables */ + xorl %eax,%eax + xorl %edi,%edi /* pg_dir is at 0x000 */ + cld;rep;stosl + movl $pg0+7,pg_dir /* set present bit/user r/w */ + movl $pg1+7,pg_dir+4 /* --------- " " --------- */ + movl $pg2+7,pg_dir+8 /* --------- " " --------- */ + movl $pg3+7,pg_dir+12 /* --------- " " --------- */ + movl $pg3+4092,%edi + movl $0xfff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */ + std +1: stosl /* fill pages backwards - more efficient :-) */ + subl $0x1000,%eax + jge 1b + xorl %eax,%eax /* pg_dir is at 0x0000 */ + movl %eax,%cr3 /* cr3 - page directory start */ + movl %cr0,%eax + orl $0x80000000,%eax + movl %eax,%cr0 /* set paging (PG) bit */ + cld /* by wyj */ + ret /* this also flushes prefetch-queue */ + +.align 4 +.word 0 +idt_descr: + .word 256*8-1 # idt contains 256 entries + .long idt +.align 4 +.word 0 +gdt_descr: + .word 256*8-1 # so does gdt (not that that's any + .long gdt # magic number, but it works for me :^) + + .align 8 +idt: .fill 256,8,0 # idt is uninitialized + +gdt: .quad 0x0000000000000000 /* NULL descriptor */ + .quad 0x00c09a0000000fff /* 16Mb */ + .quad 0x00c0920000000fff /* 16Mb */ + .quad 0x0000000000000000 /* TEMPORARY - don't use */ + .fill 252,8,0 /* space for LDT's and TSS's etc */ diff --git a/linux/boot/setup b/linux/boot/setup new file mode 100644 index 0000000000000000000000000000000000000000..0e70f4846819f560fb2e22a8eb1e7186c7956ab0 GIT binary patch literal 344 zcmZQ%7GP0eU|_Id1QJNVq7lN`!7!ok#ujFS|7Qg{#TXd2bet7k%*3#TAIOzsVOY$@ zutjLIz*&LC91NXuTnwFjJPbP+82WA;HDh4}X+5yNfnlcr!{;SXQ3*l_<@!izwL4T8@UUNgLAc(wpUZcuop2&OfjEd tmp_make + (for i in *.c;do $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +bitmap.o : bitmap.c ../include/string.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h +block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/segment.h ../include/asm/system.h +buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/system.h ../include/asm/io.h +char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/segment.h ../include/asm/io.h +exec.o : exec.c ../include/errno.h ../include/string.h \ + ../include/sys/stat.h ../include/sys/types.h ../include/a.out.h \ + ../include/linux/fs.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/segment.h +fcntl.o : fcntl.c ../include/string.h ../include/errno.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/segment.h ../include/fcntl.h \ + ../include/sys/stat.h +file_dev.o : file_dev.c ../include/errno.h ../include/fcntl.h \ + ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/segment.h +file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h +inode.o : inode.c ../include/string.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/system.h +ioctl.o : ioctl.c ../include/string.h ../include/errno.h \ + ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/signal.h +namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h \ + ../include/string.h ../include/fcntl.h ../include/errno.h \ + ../include/const.h ../include/sys/stat.h +open.o : open.c ../include/string.h ../include/errno.h ../include/fcntl.h \ + ../include/sys/types.h ../include/utime.h ../include/sys/stat.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/tty.h \ + ../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h +pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/asm/segment.h +read_write.o : read_write.c ../include/sys/stat.h ../include/sys/types.h \ + ../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/signal.h ../include/asm/segment.h +stat.o : stat.c ../include/errno.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/linux/fs.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/segment.h +super.o : super.c ../include/linux/config.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/system.h ../include/errno.h ../include/sys/stat.h +truncate.o : truncate.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/signal.h ../include/sys/stat.h diff --git a/linux/fs/bitmap.c b/linux/fs/bitmap.c new file mode 100644 index 0000000..73951a8 --- /dev/null +++ b/linux/fs/bitmap.c @@ -0,0 +1,168 @@ +/* + * linux/fs/bitmap.c + * + * (C) 1991 Linus Torvalds + */ + +/* bitmap.c contains the code that handles the inode and block bitmaps */ +#include + +#include +#include + +#define clear_block(addr) \ +__asm__ __volatile__ ("cld\n\t" \ + "rep\n\t" \ + "stosl" \ + ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr))) + +#define set_bit(nr,addr) ({\ +register int res __asm__("ax"); \ +__asm__ __volatile__("btsl %2,%3\n\tsetb %%al": \ +"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \ +res;}) + +#define clear_bit(nr,addr) ({\ +register int res __asm__("ax"); \ +__asm__ __volatile__("btrl %2,%3\n\tsetnb %%al": \ +"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \ +res;}) + +#define find_first_zero(addr) ({ \ +int __res; \ +__asm__ __volatile__ ("cld\n" \ + "1:\tlodsl\n\t" \ + "notl %%eax\n\t" \ + "bsfl %%eax,%%edx\n\t" \ + "je 2f\n\t" \ + "addl %%edx,%%ecx\n\t" \ + "jmp 3f\n" \ + "2:\taddl $32,%%ecx\n\t" \ + "cmpl $8192,%%ecx\n\t" \ + "jl 1b\n" \ + "3:" \ + :"=c" (__res):"c" (0),"S" (addr)); \ +__res;}) + +void free_block(int dev, int block) +{ + struct super_block * sb; + struct buffer_head * bh; + + if (!(sb = get_super(dev))) + panic("trying to free block on nonexistent device"); + if (block < sb->s_firstdatazone || block >= sb->s_nzones) + panic("trying to free block not in datazone"); + bh = get_hash_table(dev,block); + if (bh) { + if (bh->b_count != 1) { + printk("trying to free block (%04x:%d), count=%d\n", + dev,block,bh->b_count); + return; + } + bh->b_dirt=0; + bh->b_uptodate=0; + brelse(bh); + } + block -= sb->s_firstdatazone - 1 ; + if (clear_bit(block&8191,sb->s_zmap[block/8192]->b_data)) { + printk("block (%04x:%d) ",dev,block+sb->s_firstdatazone-1); + panic("free_block: bit already cleared"); + } + sb->s_zmap[block/8192]->b_dirt = 1; +} + +int new_block(int dev) +{ + struct buffer_head * bh; + struct super_block * sb; + int i,j; + + if (!(sb = get_super(dev))) + panic("trying to get new block from nonexistant device"); + j = 8192; + for (i=0 ; i<8 ; i++) + if (bh=sb->s_zmap[i]) + if ((j=find_first_zero(bh->b_data))<8192) + break; + if (i>=8 || !bh || j>=8192) + return 0; + if (set_bit(j,bh->b_data)) + panic("new_block: bit already set"); + bh->b_dirt = 1; + j += i*8192 + sb->s_firstdatazone-1; + if (j >= sb->s_nzones) + return 0; + if (!(bh=getblk(dev,j))) + panic("new_block: cannot get block"); + if (bh->b_count != 1) + panic("new block: count is != 1"); + clear_block(bh->b_data); + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse(bh); + return j; +} + +void free_inode(struct m_inode * inode) +{ + struct super_block * sb; + struct buffer_head * bh; + + if (!inode) + return; + if (!inode->i_dev) { + memset(inode,0,sizeof(*inode)); + return; + } + if (inode->i_count>1) { + printk("trying to free inode with count=%d\n",inode->i_count); + panic("free_inode"); + } + if (inode->i_nlinks) + panic("trying to free inode with links"); + if (!(sb = get_super(inode->i_dev))) + panic("trying to free inode on nonexistent device"); + if (inode->i_num < 1 || inode->i_num > sb->s_ninodes) + panic("trying to free inode 0 or nonexistant inode"); + if (!(bh=sb->s_imap[inode->i_num>>13])) + panic("nonexistent imap in superblock"); + if (clear_bit(inode->i_num&8191,bh->b_data)) + printk("free_inode: bit already cleared.\n\r"); + bh->b_dirt = 1; + memset(inode,0,sizeof(*inode)); +} + +struct m_inode * new_inode(int dev) +{ + struct m_inode * inode; + struct super_block * sb; + struct buffer_head * bh; + int i,j; + + if (!(inode=get_empty_inode())) + return NULL; + if (!(sb = get_super(dev))) + panic("new_inode with unknown device"); + j = 8192; + for (i=0 ; i<8 ; i++) + if (bh=sb->s_imap[i]) + if ((j=find_first_zero(bh->b_data))<8192) + break; + if (!bh || j >= 8192 || j+i*8192 > sb->s_ninodes) { + iput(inode); + return NULL; + } + if (set_bit(j,bh->b_data)) + panic("new_inode: bit already set"); + bh->b_dirt = 1; + inode->i_count=1; + inode->i_nlinks=1; + inode->i_dev=dev; + inode->i_uid=current->euid; + inode->i_gid=current->egid; + inode->i_dirt=1; + inode->i_num = j + i*8192; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + return inode; +} diff --git a/linux/fs/block_dev.c b/linux/fs/block_dev.c new file mode 100644 index 0000000..a50ae3f --- /dev/null +++ b/linux/fs/block_dev.c @@ -0,0 +1,73 @@ +/* + * linux/fs/block_dev.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include +#include +#include + +int block_write(int dev, long * pos, char * buf, int count) +{ + int block = *pos >> BLOCK_SIZE_BITS; + int offset = *pos & (BLOCK_SIZE-1); + int chars; + int written = 0; + struct buffer_head * bh; + register char * p; + + while (count>0) { + chars = BLOCK_SIZE - offset; + if (chars > count) + chars=count; + if (chars == BLOCK_SIZE) + bh = getblk(dev,block); + else + bh = breada(dev,block,block+1,block+2,-1); + block++; + if (!bh) + return written?written:-EIO; + p = offset + bh->b_data; + offset = 0; + *pos += chars; + written += chars; + count -= chars; + while (chars-->0) + *(p++) = get_fs_byte(buf++); + bh->b_dirt = 1; + brelse(bh); + } + return written; +} + +int block_read(int dev, unsigned long * pos, char * buf, int count) +{ + int block = *pos >> BLOCK_SIZE_BITS; + int offset = *pos & (BLOCK_SIZE-1); + int chars; + int read = 0; + struct buffer_head * bh; + register char * p; + + while (count>0) { + chars = BLOCK_SIZE-offset; + if (chars > count) + chars = count; + if (!(bh = breada(dev,block,block+1,block+2,-1))) + return read?read:-EIO; + block++; + p = offset + bh->b_data; + offset = 0; + *pos += chars; + read += chars; + count -= chars; + while (chars-->0) + put_fs_byte(*(p++),buf++); + brelse(bh); + } + return read; +} diff --git a/linux/fs/buffer.c b/linux/fs/buffer.c new file mode 100644 index 0000000..a6643aa --- /dev/null +++ b/linux/fs/buffer.c @@ -0,0 +1,384 @@ +/* + * linux/fs/buffer.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'buffer.c' implements the buffer-cache functions. Race-conditions have + * been avoided by NEVER letting a interrupt change a buffer (except for the + * data, of course), but instead letting the caller do it. NOTE! As interrupts + * can wake up a caller, some cli-sti sequences are needed to check for + * sleep-on-calls. These should be extremely quick, though (I hope). + */ + +/* + * NOTE! There is one discordant note here: checking floppies for + * disk change. This is where it fits best, I think, as it should + * invalidate changed floppy-disk-caches. + */ + +#include + +#include +#include +#include +#include +#include + +extern void put_super(int dev); +extern void invalidate_inodes(int dev); + +extern int end; +struct buffer_head * start_buffer = (struct buffer_head *) &end; +struct buffer_head * hash_table[NR_HASH]; +static struct buffer_head * free_list; +static struct task_struct * buffer_wait = NULL; +int NR_BUFFERS = 0; + +static inline void wait_on_buffer(struct buffer_head * bh) +{ + cli(); + while (bh->b_lock) + sleep_on(&bh->b_wait); + sti(); +} + +int sys_sync(void) +{ + int i; + struct buffer_head * bh; + + sync_inodes(); /* write out inodes into buffers */ + bh = start_buffer; + for (i=0 ; ib_dirt) + ll_rw_block(WRITE,bh); + } + return 0; +} + +int sync_dev(int dev) +{ + int i; + struct buffer_head * bh; + + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_dirt) + ll_rw_block(WRITE,bh); + } + sync_inodes(); + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_dirt) + ll_rw_block(WRITE,bh); + } + return 0; +} + +void inline invalidate_buffers(int dev) +{ + int i; + struct buffer_head * bh; + + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev) + bh->b_uptodate = bh->b_dirt = 0; + } +} + +/* + * This routine checks whether a floppy has been changed, and + * invalidates all buffer-cache-entries in that case. This + * is a relatively slow routine, so we have to try to minimize using + * it. Thus it is called only upon a 'mount' or 'open'. This + * is the best way of combining speed and utility, I think. + * People changing diskettes in the middle of an operation deserve + * to loose :-) + * + * NOTE! Although currently this is only for floppies, the idea is + * that any additional removable block-device will use this routine, + * and that mount/open needn't know that floppies/whatever are + * special. + */ +void check_disk_change(int dev) +{ + int i; + + if (MAJOR(dev) != 2) + return; + if (!floppy_change(dev & 0x03)) + return; + for (i=0 ; ib_next) + bh->b_next->b_prev = bh->b_prev; + if (bh->b_prev) + bh->b_prev->b_next = bh->b_next; + if (hash(bh->b_dev,bh->b_blocknr) == bh) + hash(bh->b_dev,bh->b_blocknr) = bh->b_next; +/* remove from free list */ + if (!(bh->b_prev_free) || !(bh->b_next_free)) + panic("Free block list corrupted"); + bh->b_prev_free->b_next_free = bh->b_next_free; + bh->b_next_free->b_prev_free = bh->b_prev_free; + if (free_list == bh) + free_list = bh->b_next_free; +} + +static inline void insert_into_queues(struct buffer_head * bh) +{ +/* put at end of free list */ + bh->b_next_free = free_list; + bh->b_prev_free = free_list->b_prev_free; + free_list->b_prev_free->b_next_free = bh; + free_list->b_prev_free = bh; +/* put the buffer in new hash-queue if it has a device */ + bh->b_prev = NULL; + bh->b_next = NULL; + if (!bh->b_dev) + return; + bh->b_next = hash(bh->b_dev,bh->b_blocknr); + hash(bh->b_dev,bh->b_blocknr) = bh; + bh->b_next->b_prev = bh; +} + +static struct buffer_head * find_buffer(int dev, int block) +{ + struct buffer_head * tmp; + + for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next) + if (tmp->b_dev==dev && tmp->b_blocknr==block) + return tmp; + return NULL; +} + +/* + * Why like this, I hear you say... The reason is race-conditions. + * As we don't lock buffers (unless we are readint them, that is), + * something might happen to it while we sleep (ie a read-error + * will force it bad). This shouldn't really happen currently, but + * the code is ready. + */ +struct buffer_head * get_hash_table(int dev, int block) +{ + struct buffer_head * bh; + + for (;;) { + if (!(bh=find_buffer(dev,block))) + return NULL; + bh->b_count++; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_blocknr == block) + return bh; + bh->b_count--; + } +} + +/* + * Ok, this is getblk, and it isn't very clear, again to hinder + * race-conditions. Most of the code is seldom used, (ie repeating), + * so it should be much more efficient than it looks. + * + * The algoritm is changed: hopefully better, and an elusive bug removed. + */ +#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock) +struct buffer_head * getblk(int dev,int block) +{ + struct buffer_head * tmp, * bh; + +repeat: + if (bh = get_hash_table(dev,block)) + return bh; + tmp = free_list; + do { + if (tmp->b_count) + continue; + if (!bh || BADNESS(tmp)b_next_free) != free_list); + if (!bh) { + sleep_on(&buffer_wait); + goto repeat; + } + wait_on_buffer(bh); + if (bh->b_count) + goto repeat; + while (bh->b_dirt) { + sync_dev(bh->b_dev); + wait_on_buffer(bh); + if (bh->b_count) + goto repeat; + } +/* NOTE!! While we slept waiting for this block, somebody else might */ +/* already have added "this" block to the cache. check it */ + if (find_buffer(dev,block)) + goto repeat; +/* OK, FINALLY we know that this buffer is the only one of it's kind, */ +/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */ + bh->b_count=1; + bh->b_dirt=0; + bh->b_uptodate=0; + remove_from_queues(bh); + bh->b_dev=dev; + bh->b_blocknr=block; + insert_into_queues(bh); + return bh; +} + +void brelse(struct buffer_head * buf) +{ + if (!buf) + return; + wait_on_buffer(buf); + if (!(buf->b_count--)) + panic("Trying to free free buffer"); + wake_up(&buffer_wait); +} + +/* + * bread() reads a specified block and returns the buffer that contains + * it. It returns NULL if the block was unreadable. + */ +struct buffer_head * bread(int dev,int block) +{ + struct buffer_head * bh; + + if (!(bh=getblk(dev,block))) + panic("bread: getblk returned NULL\n"); + if (bh->b_uptodate) + return bh; + ll_rw_block(READ,bh); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return NULL; +} + +#define COPYBLK(from,to) \ +__asm__("cld\n\t" \ + "rep\n\t" \ + "movsl\n\t" \ + ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \ + ) + +/* + * bread_page reads four buffers into memory at the desired address. It's + * a function of its own, as there is some speed to be got by reading them + * all at the same time, not waiting for one to be read, and then another + * etc. + */ +void bread_page(unsigned long address,int dev,int b[4]) +{ + struct buffer_head * bh[4]; + int i; + + for (i=0 ; i<4 ; i++) + if (b[i]) { + if (bh[i] = getblk(dev,b[i])) + if (!bh[i]->b_uptodate) + ll_rw_block(READ,bh[i]); + } else + bh[i] = NULL; + for (i=0 ; i<4 ; i++,address += BLOCK_SIZE) + if (bh[i]) { + wait_on_buffer(bh[i]); + if (bh[i]->b_uptodate) + COPYBLK((unsigned long) bh[i]->b_data,address); + brelse(bh[i]); + } +} + +/* + * Ok, breada can be used as bread, but additionally to mark other + * blocks for reading as well. End the argument list with a negative + * number. + */ +struct buffer_head * breada(int dev,int first, ...) +{ + va_list args; + struct buffer_head * bh, *tmp; + + va_start(args,first); + if (!(bh=getblk(dev,first))) + panic("bread: getblk returned NULL\n"); + if (!bh->b_uptodate) + ll_rw_block(READ,bh); + while ((first=va_arg(args,int))>=0) { + tmp=getblk(dev,first); + if (tmp) { + if (!tmp->b_uptodate) + ll_rw_block(READA,bh); + tmp->b_count--; + } + } + va_end(args); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return (NULL); +} + +void buffer_init(long buffer_end) +{ + struct buffer_head * h = start_buffer; + void * b; + int i; + + if (buffer_end == 1<<20) + b = (void *) (640*1024); + else + b = (void *) buffer_end; + while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) { + h->b_dev = 0; + h->b_dirt = 0; + h->b_count = 0; + h->b_lock = 0; + h->b_uptodate = 0; + h->b_wait = NULL; + h->b_next = NULL; + h->b_prev = NULL; + h->b_data = (char *) b; + h->b_prev_free = h-1; + h->b_next_free = h+1; + h++; + NR_BUFFERS++; + if (b == (void *) 0x100000) + b = (void *) 0xA0000; + } + h--; + free_list = start_buffer; + free_list->b_prev_free = h; + h->b_next_free = free_list; + for (i=0;i +#include + +#include +#include + +#include +#include + +extern int tty_read(unsigned minor,char * buf,int count); +extern int tty_write(unsigned minor,char * buf,int count); + +typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count,off_t * pos); + +static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos) +{ + return ((rw==READ)?tty_read(minor,buf,count): + tty_write(minor,buf,count)); +} + +static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos) +{ + if (current->tty<0) + return -EPERM; + return rw_ttyx(rw,current->tty,buf,count,pos); +} + +static int rw_ram(int rw,char * buf, int count, off_t *pos) +{ + return -EIO; +} + +static int rw_mem(int rw,char * buf, int count, off_t * pos) +{ + return -EIO; +} + +static int rw_kmem(int rw,char * buf, int count, off_t * pos) +{ + return -EIO; +} + +static int rw_port(int rw,char * buf, int count, off_t * pos) +{ + int i=*pos; + + while (count-->0 && i<65536) { + if (rw==READ) + put_fs_byte(inb(i),buf++); + else + outb(get_fs_byte(buf++),i); + i++; + } + i -= *pos; + *pos += i; + return i; +} + +static int rw_memory(int rw, unsigned minor, char * buf, int count, off_t * pos) +{ + switch(minor) { + case 0: + return rw_ram(rw,buf,count,pos); + case 1: + return rw_mem(rw,buf,count,pos); + case 2: + return rw_kmem(rw,buf,count,pos); + case 3: + return (rw==READ)?0:count; /* rw_null */ + case 4: + return rw_port(rw,buf,count,pos); + default: + return -EIO; + } +} + +#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr))) + +static crw_ptr crw_table[]={ + NULL, /* nodev */ + rw_memory, /* /dev/mem etc */ + NULL, /* /dev/fd */ + NULL, /* /dev/hd */ + rw_ttyx, /* /dev/ttyx */ + rw_tty, /* /dev/tty */ + NULL, /* /dev/lp */ + NULL}; /* unnamed pipes */ + +int rw_char(int rw,int dev, char * buf, int count, off_t * pos) +{ + crw_ptr call_addr; + + if (MAJOR(dev)>=NRDEVS) + return -ENODEV; + if (!(call_addr=crw_table[MAJOR(dev)])) + return -ENODEV; + return call_addr(rw,MINOR(dev),buf,count,pos); +} diff --git a/linux/fs/exec.c b/linux/fs/exec.c new file mode 100644 index 0000000..80f9381 --- /dev/null +++ b/linux/fs/exec.c @@ -0,0 +1,543 @@ +/* + * linux/fs/exec.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * #!-checking implemented by tytso. + */ + +/* + * Demand-loading implemented 01.12.91 - no need to read anything but + * the header into memory. The inode of the executable is put into + * "current->executable", and page faults do the actual loading. Clean. + * + * Once more I can proudly say that linux stood up to being changed: it + * was less than 2 hours work to get demand-loading completely implemented. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern int sys_exit(int exit_code); +extern int sys_close(int fd); +extern void do_no_page(unsigned long error_code,unsigned long address); + +/* + * MAX_ARG_PAGES defines the number of pages allocated for arguments + * and envelope for the new program. 32 should suffice, this gives + * a maximum env+arg of 128kB ! + */ +#define MAX_ARG_PAGES 32 + + +int sys_uselib() +{ + return -ENOSYS; +} + +/* + * create_tables() parses the env- and arg-strings in new user + * memory and creates the pointer tables from them, and puts their + * addresses on the "stack", returning the new stack pointer value. + */ +static unsigned long * create_tables(char * p,int argc,int envc) +{ + unsigned long *argv,*envp; + unsigned long * sp; + + sp = (unsigned long *) (0xfffffffc & (unsigned long) p); + sp -= envc+1; + envp = sp; + sp -= argc+1; + argv = sp; + put_fs_long((unsigned long)envp,--sp); + put_fs_long((unsigned long)argv,--sp); + put_fs_long((unsigned long)argc,--sp); + while (argc-->0) { + put_fs_long((unsigned long) p,argv++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,argv); + while (envc-->0) { + put_fs_long((unsigned long) p,envp++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,envp); + return sp; +} + +/* + * count() counts the number of arguments/envelopes + */ +static int count(char ** argv) +{ + int i=0; + char ** tmp; + + if (tmp = argv) + while (get_fs_long((unsigned long *) (tmp++))) + i++; + + return i; +} + +/* + * 'copy_string()' copies argument/envelope strings from user + * memory to free pages in kernel mem. These are in a format ready + * to be put directly into the top of new user memory. + * + * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies + * whether the string and the string array are from user or kernel segments: + * + * from_kmem argv * argv ** + * 0 user space user space + * 1 kernel space user space + * 2 kernel space kernel space + * + * We do this by playing games with the fs segment register. Since it + * it is expensive to load a segment register, we try to avoid calling + * set_fs() unless we absolutely have to. + */ +static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, + unsigned long p, int from_kmem) +{ + char *tmp, *pag; + int len, offset = 0; + unsigned long old_fs, new_fs; + + if (!p) + return 0; /* bullet-proofing */ + new_fs = get_ds(); + old_fs = get_fs(); + if (from_kmem==2) + set_fs(new_fs); + while (argc-- > 0) { + if (from_kmem == 1) + set_fs(new_fs); + if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc))) + panic("argc is wrong"); + if (from_kmem == 1) + set_fs(old_fs); + len=0; /* remember zero-padding */ + do { + len++; + } while (get_fs_byte(tmp++)); + if (p-len < 0) { /* this shouldn't happen - 128kB */ + set_fs(old_fs); + return 0; + } + while (len) { + --p; --tmp; --len; + if (--offset < 0) { + offset = p % PAGE_SIZE; + if (from_kmem==2) + set_fs(old_fs); + if (!(pag = (char *) page[p/PAGE_SIZE]) && + !(pag = (char *) (page[p/PAGE_SIZE] = + (unsigned long *) get_free_page()))) + return 0; + if (from_kmem==2) + set_fs(new_fs); + + } + *(pag + offset) = get_fs_byte(tmp); + } + } + if (from_kmem==2) + set_fs(old_fs); + return p; +} + +static unsigned long change_ldt(unsigned long text_size,unsigned long * page) +{ + unsigned long code_limit,data_limit,code_base,data_base; + int i; + + code_limit = text_size+PAGE_SIZE -1; + code_limit &= 0xFFFFF000; + data_limit = 0x4000000; + code_base = get_base(current->ldt[1]); + data_base = code_base; + set_base(current->ldt[1],code_base); + set_limit(current->ldt[1],code_limit); + set_base(current->ldt[2],data_base); + set_limit(current->ldt[2],data_limit); +/* make sure fs points to the NEW data segment */ + __asm__("pushl $0x17\n\tpop %%fs"::); + data_base += data_limit; + for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) { + data_base -= PAGE_SIZE; + if (page[i]) + put_page(page[i],data_base); + } + return data_limit; +} + +/* + * 'do_execve()' executes a new program. + */ +int do_execve(unsigned long * eip,long tmp,char * filename, + char ** argv, char ** envp) +{ + struct m_inode * inode; + struct buffer_head * bh; + struct exec ex; + unsigned long page[MAX_ARG_PAGES]; + int i,argc,envc; + int e_uid, e_gid; + int retval; + int sh_bang = 0; + unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4; + + if ((0xffff & eip[1]) != 0x000f) + panic("execve called from supervisor mode"); + for (i=0 ; ii_mode)) { /* must be regular file */ + retval = -EACCES; + goto exec_error2; + } + i = inode->i_mode; + e_uid = (i & S_ISUID) ? inode->i_uid : current->euid; + e_gid = (i & S_ISGID) ? inode->i_gid : current->egid; + if (current->euid == inode->i_uid) + i >>= 6; + else if (current->egid == inode->i_gid) + i >>= 3; + if (!(i & 1) && + !((inode->i_mode & 0111) && suser())) { + retval = -ENOEXEC; + goto exec_error2; + } + if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) { + retval = -EACCES; + goto exec_error2; + } + ex = *((struct exec *) bh->b_data); /* read exec-header */ + if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) { + /* + * This section does the #! interpretation. + * Sorta complicated, but hopefully it will work. -TYT + */ + + char buf[1023], *cp, *interp, *i_name, *i_arg; + unsigned long old_fs; + + strncpy(buf, bh->b_data+2, 1022); + brelse(bh); + iput(inode); + buf[1022] = '\0'; + if (cp = strchr(buf, '\n')) { + *cp = '\0'; + for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++); + } + if (!cp || *cp == '\0') { + retval = -ENOEXEC; /* No interpreter name found */ + goto exec_error1; + } + interp = i_name = cp; + i_arg = 0; + for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) { + if (*cp == '/') + i_name = cp+1; + } + if (*cp) { + *cp++ = '\0'; + i_arg = cp; + } + /* + * OK, we've parsed out the interpreter name and + * (optional) argument. + */ + if (sh_bang++ == 0) { + p = copy_strings(envc, envp, page, p, 0); + p = copy_strings(--argc, argv+1, page, p, 0); + } + /* + * Splice in (1) the interpreter's name for argv[0] + * (2) (optional) argument to interpreter + * (3) filename of shell script + * + * This is done in reverse order, because of how the + * user environment and arguments are stored. + */ + p = copy_strings(1, &filename, page, p, 1); + argc++; + if (i_arg) { + p = copy_strings(1, &i_arg, page, p, 2); + argc++; + } + p = copy_strings(1, &i_name, page, p, 2); + argc++; + if (!p) { + retval = -ENOMEM; + goto exec_error1; + } + /* + * OK, now restart the process with the interpreter's inode. + */ + old_fs = get_fs(); + set_fs(get_ds()); + if (!(inode=namei(interp))) { /* get executables inode */ + set_fs(old_fs); + retval = -ENOENT; + goto exec_error1; + } + set_fs(old_fs); + goto restart_interp; + } + brelse(bh); + if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize || + ex.a_text+ex.a_data+ex.a_bss>0x3000000 || + inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { + retval = -ENOEXEC; + goto exec_error2; + } + if (N_TXTOFF(ex) != BLOCK_SIZE) { + printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename); + retval = -ENOEXEC; + goto exec_error2; + } + if (!sh_bang) { + p = copy_strings(envc,envp,page,p,0); + p = copy_strings(argc,argv,page,p,0); + if (!p) { + retval = -ENOMEM; + goto exec_error2; + } + } +/* OK, This is the point of no return */ + if (current->executable) + iput(current->executable); + current->executable = inode; + for (i=0 ; i<32 ; i++) + current->sigaction[i].sa_handler = NULL; + for (i=0 ; iclose_on_exec>>i)&1) + sys_close(i); + current->close_on_exec = 0; + free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); + free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); + if (last_task_used_math == current) + last_task_used_math = NULL; + current->used_math = 0; + p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE; + p = (unsigned long) create_tables((char *)p,argc,envc); + current->brk = ex.a_bss + + (current->end_data = ex.a_data + + (current->end_code = ex.a_text)); + current->start_stack = p & 0xfffff000; + current->euid = e_uid; + current->egid = e_gid; + i = ex.a_text+ex.a_data; + while (i&0xfff) + put_fs_byte(0,(char *) (i++)); + eip[0] = ex.a_entry; /* eip, magic happens :-) */ + eip[3] = p; /* stack pointer */ + return 0; +exec_error2: + iput(inode); +exec_error1: + for (i=0 ; ii_mode)) { /* must be regular file */ + retval = -EACCES; + goto exec_error2; + } + i = inode->i_mode; + e_uid = (i & S_ISUID) ? inode->i_uid : current->euid; + e_gid = (i & S_ISGID) ? inode->i_gid : current->egid; + if (current->euid == inode->i_uid) + i >>= 6; + else if (current->egid == inode->i_gid) + i >>= 3; + if (!(i & 1) && + !((inode->i_mode & 0111) && suser())) { + retval = -ENOEXEC; + goto exec_error2; + } + if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) { + retval = -EACCES; + goto exec_error2; + } + ex = *((struct exec *) bh->b_data); /* read exec-header */ + if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) { + /* + * This section does the #! interpretation. + * Sorta complicated, but hopefully it will work. -TYT + */ + + char buf[1023], *cp, *interp, *i_name, *i_arg; + unsigned long old_fs; + + strncpy(buf, bh->b_data+2, 1022); + brelse(bh); + iput(inode); + buf[1022] = '\0'; + if (cp = strchr(buf, '\n')) { + *cp = '\0'; + for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++); + } + if (!cp || *cp == '\0') { + retval = -ENOEXEC; /* No interpreter name found */ + goto exec_error1; + } + interp = i_name = cp; + i_arg = 0; + for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) { + if (*cp == '/') + i_name = cp+1; + } + if (*cp) { + *cp++ = '\0'; + i_arg = cp; + } + /* + * OK, we've parsed out the interpreter name and + * (optional) argument. + */ + if (sh_bang++ == 0) { + p = copy_strings(envc, envp, page, p, 0); + p = copy_strings(--argc, argv+1, page, p, 0); + } + /* + * Splice in (1) the interpreter's name for argv[0] + * (2) (optional) argument to interpreter + * (3) filename of shell script + * + * This is done in reverse order, because of how the + * user environment and arguments are stored. + */ + p = copy_strings(1, &filename, page, p, 1); + argc++; + if (i_arg) { + p = copy_strings(1, &i_arg, page, p, 2); + argc++; + } + p = copy_strings(1, &i_name, page, p, 2); + argc++; + if (!p) { + retval = -ENOMEM; + goto exec_error1; + } + /* + * OK, now restart the process with the interpreter's inode. + */ + old_fs = get_fs(); + set_fs(get_ds()); + if (!(inode=namei(interp))) { /* get executables inode */ + set_fs(old_fs); + retval = -ENOENT; + goto exec_error1; + } + set_fs(old_fs); + goto restart_interp; + } + brelse(bh); + if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize || + ex.a_text+ex.a_data+ex.a_bss>0x3000000 || + inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { + retval = -ENOEXEC; + goto exec_error2; + } + if (N_TXTOFF(ex) != BLOCK_SIZE) { + printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename); + retval = -ENOEXEC; + goto exec_error2; + } + if (!sh_bang) { + p = copy_strings(envc,envp,page,p,0); + p = copy_strings(argc,argv,page,p,0); + if (!p) { + retval = -ENOMEM; + goto exec_error2; + } + } +/* OK, This is the point of no return */ + if (current->executable) + iput(current->executable); + current->executable = inode; + for (i=0 ; i<32 ; i++) + current->sigaction[i].sa_handler = NULL; + for (i=0 ; iclose_on_exec>>i)&1) + sys_close(i); + current->close_on_exec = 0; + free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); + free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); + if (last_task_used_math == current) + last_task_used_math = NULL; + current->used_math = 0; + p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE; + p = (unsigned long) create_tables((char *)p,argc,envc); + current->brk = ex.a_bss + + (current->end_data = ex.a_data + + (current->end_code = ex.a_text)); + current->start_stack = p & 0xfffff000; + current->euid = e_uid; + current->egid = e_gid; + i = ex.a_text+ex.a_data; + while (i&0xfff) + put_fs_byte(0,(char *) (i++)); + eip[0] = ex.a_entry; /* eip, magic happens :-) */ + eip[3] = p; /* stack pointer */ + + phy_add_brk = 0; + while (phy_add_brk < current->brk) + { + do_no_page(1, phy_add_brk + current->start_code); + phy_add_brk += PAGE_SIZE; + } + + return 0; +exec_error2: + iput(inode); +exec_error1: + for (i=0 ; i +#include +#include +#include +#include + +#include +#include + +extern int sys_close(int fd); + +static int dupfd(unsigned int fd, unsigned int arg) +{ + if (fd >= NR_OPEN || !current->filp[fd]) + return -EBADF; + if (arg >= NR_OPEN) + return -EINVAL; + while (arg < NR_OPEN) + if (current->filp[arg]) + arg++; + else + break; + if (arg >= NR_OPEN) + return -EMFILE; + current->close_on_exec &= ~(1<filp[arg] = current->filp[fd])->f_count++; + return arg; +} + +int sys_dup2(unsigned int oldfd, unsigned int newfd) +{ + sys_close(newfd); + return dupfd(oldfd,newfd); +} + +int sys_dup(unsigned int fildes) +{ + return dupfd(fildes,0); +} + +int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + switch (cmd) { + case F_DUPFD: + return dupfd(fd,arg); + case F_GETFD: + return (current->close_on_exec>>fd)&1; + case F_SETFD: + if (arg&1) + current->close_on_exec |= (1<close_on_exec &= ~(1<f_flags; + case F_SETFL: + filp->f_flags &= ~(O_APPEND | O_NONBLOCK); + filp->f_flags |= arg & (O_APPEND | O_NONBLOCK); + return 0; + case F_GETLK: case F_SETLK: case F_SETLKW: + return -1; + default: + return -1; + } +} diff --git a/linux/fs/file_dev.c b/linux/fs/file_dev.c new file mode 100644 index 0000000..0c50eaa --- /dev/null +++ b/linux/fs/file_dev.c @@ -0,0 +1,90 @@ +/* + * linux/fs/file_dev.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) +{ + int left,chars,nr; + struct buffer_head * bh; + + if ((left=count)<=0) + return 0; + while (left) { + if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) { + if (!(bh=bread(inode->i_dev,nr))) + break; + } else + bh = NULL; + nr = filp->f_pos % BLOCK_SIZE; + chars = MIN( BLOCK_SIZE-nr , left ); + filp->f_pos += chars; + left -= chars; + if (bh) { + char * p = nr + bh->b_data; + while (chars-->0) + put_fs_byte(*(p++),buf++); + brelse(bh); + } else { + while (chars-->0) + put_fs_byte(0,buf++); + } + } + inode->i_atime = CURRENT_TIME; + return (count-left)?(count-left):-ERROR; +} + +int file_write(struct m_inode * inode, struct file * filp, char * buf, int count) +{ + off_t pos; + int block,c; + struct buffer_head * bh; + char * p; + int i=0; + +/* + * ok, append may not work when many processes are writing at the same time + * but so what. That way leads to madness anyway. + */ + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + else + pos = filp->f_pos; + while (ii_dev,block))) + break; + c = pos % BLOCK_SIZE; + p = c + bh->b_data; + bh->b_dirt = 1; + c = BLOCK_SIZE-c; + if (c > count-i) c = count-i; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + i += c; + while (c-->0) + *(p++) = get_fs_byte(buf++); + brelse(bh); + } + inode->i_mtime = CURRENT_TIME; + if (!(filp->f_flags & O_APPEND)) { + filp->f_pos = pos; + inode->i_ctime = CURRENT_TIME; + } + return (i?i:-1); +} diff --git a/linux/fs/file_table.c b/linux/fs/file_table.c new file mode 100644 index 0000000..e0589ac --- /dev/null +++ b/linux/fs/file_table.c @@ -0,0 +1,9 @@ +/* + * linux/fs/file_table.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +struct file file_table[NR_FILE]; diff --git a/linux/fs/inode.c b/linux/fs/inode.c new file mode 100644 index 0000000..9bb10b3 --- /dev/null +++ b/linux/fs/inode.c @@ -0,0 +1,340 @@ +/* + * linux/fs/inode.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include + +struct m_inode inode_table[NR_INODE]={{0,},}; + +static void read_inode(struct m_inode * inode); +static void write_inode(struct m_inode * inode); + +static inline void wait_on_inode(struct m_inode * inode) +{ + cli(); + while (inode->i_lock) + sleep_on(&inode->i_wait); + sti(); +} + +static inline void lock_inode(struct m_inode * inode) +{ + cli(); + while (inode->i_lock) + sleep_on(&inode->i_wait); + inode->i_lock=1; + sti(); +} + +static inline void unlock_inode(struct m_inode * inode) +{ + inode->i_lock=0; + wake_up(&inode->i_wait); +} + +void invalidate_inodes(int dev) +{ + int i; + struct m_inode * inode; + + inode = 0+inode_table; + for(i=0 ; ii_dev == dev) { + if (inode->i_count) + printk("inode in use on removed disk\n\r"); + inode->i_dev = inode->i_dirt = 0; + } + } +} + +void sync_inodes(void) +{ + int i; + struct m_inode * inode; + + inode = 0+inode_table; + for(i=0 ; ii_dirt && !inode->i_pipe) + write_inode(inode); + } +} + +static int _bmap(struct m_inode * inode,int block,int create) +{ + struct buffer_head * bh; + int i; + + if (block<0) + panic("_bmap: block<0"); + if (block >= 7+512+512*512) + panic("_bmap: block>big"); + if (block<7) { + if (create && !inode->i_zone[block]) + if (inode->i_zone[block]=new_block(inode->i_dev)) { + inode->i_ctime=CURRENT_TIME; + inode->i_dirt=1; + } + return inode->i_zone[block]; + } + block -= 7; + if (block<512) { + if (create && !inode->i_zone[7]) + if (inode->i_zone[7]=new_block(inode->i_dev)) { + inode->i_dirt=1; + inode->i_ctime=CURRENT_TIME; + } + if (!inode->i_zone[7]) + return 0; + if (!(bh = bread(inode->i_dev,inode->i_zone[7]))) + return 0; + i = ((unsigned short *) (bh->b_data))[block]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block]=i; + bh->b_dirt=1; + } + brelse(bh); + return i; + } + block -= 512; + if (create && !inode->i_zone[8]) + if (inode->i_zone[8]=new_block(inode->i_dev)) { + inode->i_dirt=1; + inode->i_ctime=CURRENT_TIME; + } + if (!inode->i_zone[8]) + return 0; + if (!(bh=bread(inode->i_dev,inode->i_zone[8]))) + return 0; + i = ((unsigned short *)bh->b_data)[block>>9]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block>>9]=i; + bh->b_dirt=1; + } + brelse(bh); + if (!i) + return 0; + if (!(bh=bread(inode->i_dev,i))) + return 0; + i = ((unsigned short *)bh->b_data)[block&511]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block&511]=i; + bh->b_dirt=1; + } + brelse(bh); + return i; +} + +int bmap(struct m_inode * inode,int block) +{ + return _bmap(inode,block,0); +} + +int create_block(struct m_inode * inode, int block) +{ + return _bmap(inode,block,1); +} + +void iput(struct m_inode * inode) +{ + if (!inode) + return; + wait_on_inode(inode); + if (!inode->i_count) + panic("iput: trying to free free inode"); + if (inode->i_pipe) { + wake_up(&inode->i_wait); + if (--inode->i_count) + return; + free_page(inode->i_size); + inode->i_count=0; + inode->i_dirt=0; + inode->i_pipe=0; + return; + } + if (!inode->i_dev) { + inode->i_count--; + return; + } + if (S_ISBLK(inode->i_mode)) { + sync_dev(inode->i_zone[0]); + wait_on_inode(inode); + } +repeat: + if (inode->i_count>1) { + inode->i_count--; + return; + } + if (!inode->i_nlinks) { + truncate(inode); + free_inode(inode); + return; + } + if (inode->i_dirt) { + write_inode(inode); /* we can sleep - so do again */ + wait_on_inode(inode); + goto repeat; + } + inode->i_count--; + return; +} + +struct m_inode * get_empty_inode(void) +{ + struct m_inode * inode; + static struct m_inode * last_inode = inode_table; + int i; + + do { + inode = NULL; + for (i = NR_INODE; i ; i--) { + if (++last_inode >= inode_table + NR_INODE) + last_inode = inode_table; + if (!last_inode->i_count) { + inode = last_inode; + if (!inode->i_dirt && !inode->i_lock) + break; + } + } + if (!inode) { + for (i=0 ; ii_dirt) { + write_inode(inode); + wait_on_inode(inode); + } + } while (inode->i_count); + memset(inode,0,sizeof(*inode)); + inode->i_count = 1; + return inode; +} + +struct m_inode * get_pipe_inode(void) +{ + struct m_inode * inode; + + if (!(inode = get_empty_inode())) + return NULL; + if (!(inode->i_size=get_free_page())) { + inode->i_count = 0; + return NULL; + } + inode->i_count = 2; /* sum of readers/writers */ + PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0; + inode->i_pipe = 1; + return inode; +} + +struct m_inode * iget(int dev,int nr) +{ + struct m_inode * inode, * empty; + + if (!dev) + panic("iget with dev==0"); + empty = get_empty_inode(); + inode = inode_table; + while (inode < NR_INODE+inode_table) { + if (inode->i_dev != dev || inode->i_num != nr) { + inode++; + continue; + } + wait_on_inode(inode); + if (inode->i_dev != dev || inode->i_num != nr) { + inode = inode_table; + continue; + } + inode->i_count++; + if (inode->i_mount) { + int i; + + for (i = 0 ; i= NR_SUPER) { + printk("Mounted inode hasn't got sb\n"); + if (empty) + iput(empty); + return inode; + } + iput(inode); + dev = super_block[i].s_dev; + nr = ROOT_INO; + inode = inode_table; + continue; + } + if (empty) + iput(empty); + return inode; + } + if (!empty) + return (NULL); + inode=empty; + inode->i_dev = dev; + inode->i_num = nr; + read_inode(inode); + return inode; +} + +static void read_inode(struct m_inode * inode) +{ + struct super_block * sb; + struct buffer_head * bh; + int block; + + lock_inode(inode); + if (!(sb=get_super(inode->i_dev))) + panic("trying to read inode without dev"); + block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks + + (inode->i_num-1)/INODES_PER_BLOCK; + if (!(bh=bread(inode->i_dev,block))) + panic("unable to read i-node block"); + __asm__ volatile ("cld"); /* by wyj */ + *(struct d_inode *)inode = + ((struct d_inode *)bh->b_data) + [(inode->i_num-1)%INODES_PER_BLOCK]; + brelse(bh); + unlock_inode(inode); +} + +static void write_inode(struct m_inode * inode) +{ + struct super_block * sb; + struct buffer_head * bh; + int block; + + lock_inode(inode); + if (!inode->i_dirt || !inode->i_dev) { + unlock_inode(inode); + return; + } + if (!(sb=get_super(inode->i_dev))) + panic("trying to write inode without device"); + block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks + + (inode->i_num-1)/INODES_PER_BLOCK; + if (!(bh=bread(inode->i_dev,block))) + panic("unable to read i-node block"); + __asm__ volatile ("cld"); /* by wyj */ + ((struct d_inode *)bh->b_data) + [(inode->i_num-1)%INODES_PER_BLOCK] = + *(struct d_inode *)inode; + bh->b_dirt=1; + inode->i_dirt=0; + brelse(bh); + unlock_inode(inode); +} diff --git a/linux/fs/ioctl.c b/linux/fs/ioctl.c new file mode 100644 index 0000000..36fc976 --- /dev/null +++ b/linux/fs/ioctl.c @@ -0,0 +1,46 @@ +/* + * linux/fs/ioctl.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include + +extern int tty_ioctl(int dev, int cmd, int arg); + +typedef int (*ioctl_ptr)(int dev,int cmd,int arg); + +#define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr))) + +static ioctl_ptr ioctl_table[]={ + NULL, /* nodev */ + NULL, /* /dev/mem */ + NULL, /* /dev/fd */ + NULL, /* /dev/hd */ + tty_ioctl, /* /dev/ttyx */ + tty_ioctl, /* /dev/tty */ + NULL, /* /dev/lp */ + NULL}; /* named pipes */ + + +int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + int dev,mode; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + mode=filp->f_inode->i_mode; + if (!S_ISCHR(mode) && !S_ISBLK(mode)) + return -EINVAL; + dev = filp->f_inode->i_zone[0]; + if (MAJOR(dev) >= NRDEVS) + return -ENODEV; + if (!ioctl_table[MAJOR(dev)]) + return -ENOTTY; + return ioctl_table[MAJOR(dev)](dev,cmd,arg); +} diff --git a/linux/fs/namei.c b/linux/fs/namei.c new file mode 100644 index 0000000..f8a02b9 --- /dev/null +++ b/linux/fs/namei.c @@ -0,0 +1,783 @@ +/* + * linux/fs/namei.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * Some corrections by tytso. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE]) + +/* + * comment out this line if you want names > NAME_LEN chars to be + * truncated. Else they will be disallowed. + */ +/* #define NO_TRUNCATE */ + +#define MAY_EXEC 1 +#define MAY_WRITE 2 +#define MAY_READ 4 + +/* + * permission() + * + * is used to check for read/write/execute permissions on a file. + * I don't know if we should look at just the euid or both euid and + * uid, but that should be easily changed. + */ +static int permission(struct m_inode * inode,int mask) +{ + int mode = inode->i_mode; + +/* special case: not even root can read/write a deleted file */ + if (inode->i_dev && !inode->i_nlinks) + return 0; + else if (current->euid==inode->i_uid) + mode >>= 6; + else if (current->egid==inode->i_gid) + mode >>= 3; + if (((mode & mask & 0007) == mask) || suser()) + return 1; + return 0; +} + +/* + * ok, we cannot use strncmp, as the name is not in our data space. + * Thus we'll have to use match. No big problem. Match also makes + * some sanity tests. + * + * NOTE! unlike strncmp, match returns 1 for success, 0 for failure. + */ +static int match(int len,const char * name,struct dir_entry * de) +{ + register int same __asm__("ax"); + + if (!de || !de->inode || len > NAME_LEN) + return 0; + if (len < NAME_LEN && de->name[len]) + return 0; + __asm__("cld\n\t" + "fs ; repe ; cmpsb\n\t" + "setz %%al" + :"=a" (same) + :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len) + ); + return same; +} + +/* + * find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + * + * This also takes care of the few special cases due to '..'-traversal + * over a pseudo-root and a mount point. + */ +static struct buffer_head * find_entry(struct m_inode ** dir, + const char * name, int namelen, struct dir_entry ** res_dir) +{ + int entries; + int block,i; + struct buffer_head * bh; + struct dir_entry * de; + struct super_block * sb; + +#ifdef NO_TRUNCATE + if (namelen > NAME_LEN) + return NULL; +#else + if (namelen > NAME_LEN) + namelen = NAME_LEN; +#endif + entries = (*dir)->i_size / (sizeof (struct dir_entry)); + *res_dir = NULL; + if (!namelen) + return NULL; +/* check for '..', as we might have to do some "magic" for it */ + if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') { +/* '..' in a pseudo-root results in a faked '.' (just change namelen) */ + if ((*dir) == current->root) + namelen=1; + else if ((*dir)->i_num == ROOT_INO) { +/* '..' over a mount-point results in 'dir' being exchanged for the mounted + directory-inode. NOTE! We set mounted, so that we can iput the new dir */ + sb=get_super((*dir)->i_dev); + if (sb->s_imount) { + iput(*dir); + (*dir)=sb->s_imount; + (*dir)->i_count++; + } + } + } + if (!(block = (*dir)->i_zone[0])) + return NULL; + if (!(bh = bread((*dir)->i_dev,block))) + return NULL; + i = 0; + de = (struct dir_entry *) bh->b_data; + while (i < entries) { + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; + if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) || + !(bh = bread((*dir)->i_dev,block))) { + i += DIR_ENTRIES_PER_BLOCK; + continue; + } + de = (struct dir_entry *) bh->b_data; + } + if (match(namelen,name,de)) { + *res_dir = de; + return bh; + } + de++; + i++; + } + brelse(bh); + return NULL; +} + +/* + * add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as find_entry(). It returns NULL if it failed. + * + * NOTE!! The inode part of 'de' is left at 0 - which means you + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ +static struct buffer_head * add_entry(struct m_inode * dir, + const char * name, int namelen, struct dir_entry ** res_dir) +{ + int block,i; + struct buffer_head * bh; + struct dir_entry * de; + + *res_dir = NULL; +#ifdef NO_TRUNCATE + if (namelen > NAME_LEN) + return NULL; +#else + if (namelen > NAME_LEN) + namelen = NAME_LEN; +#endif + if (!namelen) + return NULL; + if (!(block = dir->i_zone[0])) + return NULL; + if (!(bh = bread(dir->i_dev,block))) + return NULL; + i = 0; + de = (struct dir_entry *) bh->b_data; + while (1) { + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; + block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK); + if (!block) + return NULL; + if (!(bh = bread(dir->i_dev,block))) { + i += DIR_ENTRIES_PER_BLOCK; + continue; + } + de = (struct dir_entry *) bh->b_data; + } + if (i*sizeof(struct dir_entry) >= dir->i_size) { + de->inode=0; + dir->i_size = (i+1)*sizeof(struct dir_entry); + dir->i_dirt = 1; + dir->i_ctime = CURRENT_TIME; + } + if (!de->inode) { + dir->i_mtime = CURRENT_TIME; + for (i=0; i < NAME_LEN ; i++) + de->name[i]=(ib_dirt = 1; + *res_dir = de; + return bh; + } + de++; + i++; + } + brelse(bh); + return NULL; +} + +/* + * get_dir() + * + * Getdir traverses the pathname until it hits the topmost directory. + * It returns NULL on failure. + */ +static struct m_inode * get_dir(const char * pathname) +{ + char c; + const char * thisname; + struct m_inode * inode; + struct buffer_head * bh; + int namelen,inr,idev; + struct dir_entry * de; + + if (!current->root || !current->root->i_count) + panic("No root inode"); + if (!current->pwd || !current->pwd->i_count) + panic("No cwd inode"); + if ((c=get_fs_byte(pathname))=='/') { + inode = current->root; + pathname++; + } else if (c) + inode = current->pwd; + else + return NULL; /* empty name is bad */ + inode->i_count++; + while (1) { + thisname = pathname; + if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) { + iput(inode); + return NULL; + } + for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++) + /* nothing */ ; + if (!c) + return inode; + if (!(bh = find_entry(&inode,thisname,namelen,&de))) { + iput(inode); + return NULL; + } + inr = de->inode; + idev = inode->i_dev; + brelse(bh); + iput(inode); + if (!(inode = iget(idev,inr))) + return NULL; + } +} + +/* + * dir_namei() + * + * dir_namei() returns the inode of the directory of the + * specified name, and the name within that directory. + */ +static struct m_inode * dir_namei(const char * pathname, + int * namelen, const char ** name) +{ + char c; + const char * basename; + struct m_inode * dir; + + if (!(dir = get_dir(pathname))) + return NULL; + basename = pathname; + while (c=get_fs_byte(pathname++)) + if (c=='/') + basename=pathname; + *namelen = pathname-basename-1; + *name = basename; + return dir; +} + +/* + * namei() + * + * is used by most simple commands to get the inode of a specified name. + * Open, link etc use their own routines, but this is enough for things + * like 'chmod' etc. + */ +struct m_inode * namei(const char * pathname) +{ + const char * basename; + int inr,dev,namelen; + struct m_inode * dir; + struct buffer_head * bh; + struct dir_entry * de; + + if (!(dir = dir_namei(pathname,&namelen,&basename))) + return NULL; + if (!namelen) /* special case: '/usr/' etc */ + return dir; + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + iput(dir); + return NULL; + } + inr = de->inode; + dev = dir->i_dev; + brelse(bh); + iput(dir); + dir=iget(dev,inr); + if (dir) { + dir->i_atime=CURRENT_TIME; + dir->i_dirt=1; + } + return dir; +} + +/* + * open_namei() + * + * namei for open - this is in fact almost the whole open-routine. + */ +int open_namei(const char * pathname, int flag, int mode, + struct m_inode ** res_inode) +{ + const char * basename; + int inr,dev,namelen; + struct m_inode * dir, *inode; + struct buffer_head * bh; + struct dir_entry * de; + + if ((flag & O_TRUNC) && !(flag & O_ACCMODE)) + flag |= O_WRONLY; + mode &= 0777 & ~current->umask; + mode |= I_REGULAR; + if (!(dir = dir_namei(pathname,&namelen,&basename))) + return -ENOENT; + if (!namelen) { /* special case: '/usr/' etc */ + if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) { + *res_inode=dir; + return 0; + } + iput(dir); + return -EISDIR; + } + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + if (!(flag & O_CREAT)) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EACCES; + } + inode = new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_uid = current->euid; + inode->i_mode = mode; + inode->i_dirt = 1; + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + inode->i_nlinks--; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->inode = inode->i_num; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + *res_inode = inode; + return 0; + } + inr = de->inode; + dev = dir->i_dev; + brelse(bh); + iput(dir); + if (flag & O_EXCL) + return -EEXIST; + if (!(inode=iget(dev,inr))) + return -EACCES; + if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) || + !permission(inode,ACC_MODE(flag))) { + iput(inode); + return -EPERM; + } + inode->i_atime = CURRENT_TIME; + if (flag & O_TRUNC) + truncate(inode); + *res_inode = inode; + return 0; +} + +int sys_mknod(const char * filename, int mode, int dev) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh; + struct dir_entry * de; + + if (!suser()) + return -EPERM; + if (!(dir = dir_namei(filename,&namelen,&basename))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + bh = find_entry(&dir,basename,namelen,&de); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_mode = mode; + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_zone[0] = dev; + inode->i_mtime = inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + iput(dir); + inode->i_nlinks=0; + iput(inode); + return -ENOSPC; + } + de->inode = inode->i_num; + bh->b_dirt = 1; + iput(dir); + iput(inode); + brelse(bh); + return 0; +} + +int sys_mkdir(const char * pathname, int mode) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh, *dir_block; + struct dir_entry * de; + + if (!suser()) + return -EPERM; + if (!(dir = dir_namei(pathname,&namelen,&basename))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + bh = find_entry(&dir,basename,namelen,&de); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_size = 32; + inode->i_dirt = 1; + inode->i_mtime = inode->i_atime = CURRENT_TIME; + if (!(inode->i_zone[0]=new_block(inode->i_dev))) { + iput(dir); + inode->i_nlinks--; + iput(inode); + return -ENOSPC; + } + inode->i_dirt = 1; + if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) { + iput(dir); + free_block(inode->i_dev,inode->i_zone[0]); + inode->i_nlinks--; + iput(inode); + return -ERROR; + } + de = (struct dir_entry *) dir_block->b_data; + de->inode=inode->i_num; + strcpy(de->name,"."); + de++; + de->inode = dir->i_num; + strcpy(de->name,".."); + inode->i_nlinks = 2; + dir_block->b_dirt = 1; + brelse(dir_block); + inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask); + inode->i_dirt = 1; + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + iput(dir); + free_block(inode->i_dev,inode->i_zone[0]); + inode->i_nlinks=0; + iput(inode); + return -ENOSPC; + } + de->inode = inode->i_num; + bh->b_dirt = 1; + dir->i_nlinks++; + dir->i_dirt = 1; + iput(dir); + iput(inode); + brelse(bh); + return 0; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +static int empty_dir(struct m_inode * inode) +{ + int nr,block; + int len; + struct buffer_head * bh; + struct dir_entry * de; + + len = inode->i_size / sizeof (struct dir_entry); + if (len<2 || !inode->i_zone[0] || + !(bh=bread(inode->i_dev,inode->i_zone[0]))) { + printk("warning - bad directory on dev %04x\n",inode->i_dev); + return 0; + } + de = (struct dir_entry *) bh->b_data; + if (de[0].inode != inode->i_num || !de[1].inode || + strcmp(".",de[0].name) || strcmp("..",de[1].name)) { + printk("warning - bad directory on dev %04x\n",inode->i_dev); + return 0; + } + nr = 2; + de += 2; + while (nr= (void *) (bh->b_data+BLOCK_SIZE)) { + brelse(bh); + block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK); + if (!block) { + nr += DIR_ENTRIES_PER_BLOCK; + continue; + } + if (!(bh=bread(inode->i_dev,block))) + return 0; + de = (struct dir_entry *) bh->b_data; + } + if (de->inode) { + brelse(bh); + return 0; + } + de++; + nr++; + } + brelse(bh); + return 1; +} + +int sys_rmdir(const char * name) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh; + struct dir_entry * de; + + if (!suser()) + return -EPERM; + if (!(dir = dir_namei(name,&namelen,&basename))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + iput(dir); + return -ENOENT; + } + if (!(inode = iget(dir->i_dev, de->inode))) { + iput(dir); + brelse(bh); + return -EPERM; + } + if ((dir->i_mode & S_ISVTX) && current->euid && + inode->i_uid != current->euid) { + iput(dir); + iput(inode); + brelse(bh); + return -EPERM; + } + if (inode->i_dev != dir->i_dev || inode->i_count>1) { + iput(dir); + iput(inode); + brelse(bh); + return -EPERM; + } + if (inode == dir) { /* we may not delete ".", but "../dir" is ok */ + iput(inode); + iput(dir); + brelse(bh); + return -EPERM; + } + if (!S_ISDIR(inode->i_mode)) { + iput(inode); + iput(dir); + brelse(bh); + return -ENOTDIR; + } + if (!empty_dir(inode)) { + iput(inode); + iput(dir); + brelse(bh); + return -ENOTEMPTY; + } + if (inode->i_nlinks != 2) + printk("empty directory has nlink!=2 (%d)",inode->i_nlinks); + de->inode = 0; + bh->b_dirt = 1; + brelse(bh); + inode->i_nlinks=0; + inode->i_dirt=1; + dir->i_nlinks--; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt=1; + iput(dir); + iput(inode); + return 0; +} + +int sys_unlink(const char * name) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh; + struct dir_entry * de; + + if (!(dir = dir_namei(name,&namelen,&basename))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + iput(dir); + return -ENOENT; + } + if (!(inode = iget(dir->i_dev, de->inode))) { + iput(dir); + brelse(bh); + return -ENOENT; + } + if ((dir->i_mode & S_ISVTX) && !suser() && + current->euid != inode->i_uid && + current->euid != dir->i_uid) { + iput(dir); + iput(inode); + brelse(bh); + return -EPERM; + } + if (S_ISDIR(inode->i_mode)) { + iput(inode); + iput(dir); + brelse(bh); + return -EPERM; + } + if (!inode->i_nlinks) { + printk("Deleting nonexistent file (%04x:%d), %d\n", + inode->i_dev,inode->i_num,inode->i_nlinks); + inode->i_nlinks=1; + } + de->inode = 0; + bh->b_dirt = 1; + brelse(bh); + inode->i_nlinks--; + inode->i_dirt = 1; + inode->i_ctime = CURRENT_TIME; + iput(inode); + iput(dir); + return 0; +} + +int sys_symlink() +{ + return -ENOSYS; +} + +int sys_link(const char * oldname, const char * newname) +{ + struct dir_entry * de; + struct m_inode * oldinode, * dir; + struct buffer_head * bh; + const char * basename; + int namelen; + + oldinode=namei(oldname); + if (!oldinode) + return -ENOENT; + if (S_ISDIR(oldinode->i_mode)) { + iput(oldinode); + return -EPERM; + } + dir = dir_namei(newname,&namelen,&basename); + if (!dir) { + iput(oldinode); + return -EACCES; + } + if (!namelen) { + iput(oldinode); + iput(dir); + return -EPERM; + } + if (dir->i_dev != oldinode->i_dev) { + iput(dir); + iput(oldinode); + return -EXDEV; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + iput(oldinode); + return -EACCES; + } + bh = find_entry(&dir,basename,namelen,&de); + if (bh) { + brelse(bh); + iput(dir); + iput(oldinode); + return -EEXIST; + } + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + iput(dir); + iput(oldinode); + return -ENOSPC; + } + de->inode = oldinode->i_num; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + oldinode->i_nlinks++; + oldinode->i_ctime = CURRENT_TIME; + oldinode->i_dirt = 1; + iput(oldinode); + return 0; +} diff --git a/linux/fs/open.c b/linux/fs/open.c new file mode 100644 index 0000000..3695ff1 --- /dev/null +++ b/linux/fs/open.c @@ -0,0 +1,208 @@ +/* + * linux/fs/open.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +int sys_ustat(int dev, struct ustat * ubuf) +{ + return -ENOSYS; +} + +int sys_utime(char * filename, struct utimbuf * times) +{ + struct m_inode * inode; + long actime,modtime; + + if (!(inode=namei(filename))) + return -ENOENT; + if (times) { + actime = get_fs_long((unsigned long *) ×->actime); + modtime = get_fs_long((unsigned long *) ×->modtime); + } else + actime = modtime = CURRENT_TIME; + inode->i_atime = actime; + inode->i_mtime = modtime; + inode->i_dirt = 1; + iput(inode); + return 0; +} + +/* + * XXX should we use the real or effective uid? BSD uses the real uid, + * so as to make this call useful to setuid programs. + */ +int sys_access(const char * filename,int mode) +{ + struct m_inode * inode; + int res, i_mode; + + mode &= 0007; + if (!(inode=namei(filename))) + return -EACCES; + i_mode = res = inode->i_mode & 0777; + iput(inode); + if (current->uid == inode->i_uid) + res >>= 6; + else if (current->gid == inode->i_gid) + res >>= 6; + if ((res & 0007 & mode) == mode) + return 0; + /* + * XXX we are doing this test last because we really should be + * swapping the effective with the real user id (temporarily), + * and then calling suser() routine. If we do call the + * suser() routine, it needs to be called last. + */ + if ((!current->uid) && + (!(mode & 1) || (i_mode & 0111))) + return 0; + return -EACCES; +} + +int sys_chdir(const char * filename) +{ + struct m_inode * inode; + + if (!(inode = namei(filename))) + return -ENOENT; + if (!S_ISDIR(inode->i_mode)) { + iput(inode); + return -ENOTDIR; + } + iput(current->pwd); + current->pwd = inode; + return (0); +} + +int sys_chroot(const char * filename) +{ + struct m_inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if (!S_ISDIR(inode->i_mode)) { + iput(inode); + return -ENOTDIR; + } + iput(current->root); + current->root = inode; + return (0); +} + +int sys_chmod(const char * filename,int mode) +{ + struct m_inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if ((current->euid != inode->i_uid) && !suser()) { + iput(inode); + return -EACCES; + } + inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777); + inode->i_dirt = 1; + iput(inode); + return 0; +} + +int sys_chown(const char * filename,int uid,int gid) +{ + struct m_inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if (!suser()) { + iput(inode); + return -EACCES; + } + inode->i_uid=uid; + inode->i_gid=gid; + inode->i_dirt=1; + iput(inode); + return 0; +} + +int sys_open(const char * filename,int flag,int mode) +{ + struct m_inode * inode; + struct file * f; + int i,fd; + + mode &= 0777 & ~current->umask; + for(fd=0 ; fdfilp[fd]) + break; + if (fd>=NR_OPEN) + return -EINVAL; + current->close_on_exec &= ~(1<f_count) break; + if (i>=NR_FILE) + return -EINVAL; + (current->filp[fd]=f)->f_count++; + if ((i=open_namei(filename,flag,mode,&inode))<0) { + current->filp[fd]=NULL; + f->f_count=0; + return i; + } +/* ttys are somewhat special (ttyxx major==4, tty major==5) */ + if (S_ISCHR(inode->i_mode)) + if (MAJOR(inode->i_zone[0])==4) { + if (current->leader && current->tty<0) { + current->tty = MINOR(inode->i_zone[0]); + tty_table[current->tty].pgrp = current->pgrp; + } + } else if (MAJOR(inode->i_zone[0])==5) + if (current->tty<0) { + iput(inode); + current->filp[fd]=NULL; + f->f_count=0; + return -EPERM; + } +/* Likewise with block-devices: check for floppy_change */ + if (S_ISBLK(inode->i_mode)) + check_disk_change(inode->i_zone[0]); + f->f_mode = inode->i_mode; + f->f_flags = flag; + f->f_count = 1; + f->f_inode = inode; + f->f_pos = 0; + return (fd); +} + +int sys_creat(const char * pathname, int mode) +{ + return sys_open(pathname, O_CREAT | O_TRUNC, mode); +} + +int sys_close(unsigned int fd) +{ + struct file * filp; + + if (fd >= NR_OPEN) + return -EINVAL; + current->close_on_exec &= ~(1<filp[fd])) + return -EINVAL; + current->filp[fd] = NULL; + if (filp->f_count == 0) + panic("Close: file count is 0"); + if (--filp->f_count) + return (0); + iput(filp->f_inode); + return (0); +} diff --git a/linux/fs/pipe.c b/linux/fs/pipe.c new file mode 100644 index 0000000..dfc4480 --- /dev/null +++ b/linux/fs/pipe.c @@ -0,0 +1,111 @@ +/* + * linux/fs/pipe.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include /* for get_free_page */ +#include + +int read_pipe(struct m_inode * inode, char * buf, int count) +{ + int chars, size, read = 0; + + while (count>0) { + while (!(size=PIPE_SIZE(*inode))) { + wake_up(&inode->i_wait); + if (inode->i_count != 2) /* are there any writers? */ + return read; + sleep_on(&inode->i_wait); + } + chars = PAGE_SIZE-PIPE_TAIL(*inode); + if (chars > count) + chars = count; + if (chars > size) + chars = size; + count -= chars; + read += chars; + size = PIPE_TAIL(*inode); + PIPE_TAIL(*inode) += chars; + PIPE_TAIL(*inode) &= (PAGE_SIZE-1); + while (chars-->0) + put_fs_byte(((char *)inode->i_size)[size++],buf++); + } + wake_up(&inode->i_wait); + return read; +} + +int write_pipe(struct m_inode * inode, char * buf, int count) +{ + int chars, size, written = 0; + + while (count>0) { + while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) { + wake_up(&inode->i_wait); + if (inode->i_count != 2) { /* no readers */ + current->signal |= (1<<(SIGPIPE-1)); + return written?written:-1; + } + sleep_on(&inode->i_wait); + } + chars = PAGE_SIZE-PIPE_HEAD(*inode); + if (chars > count) + chars = count; + if (chars > size) + chars = size; + count -= chars; + written += chars; + size = PIPE_HEAD(*inode); + PIPE_HEAD(*inode) += chars; + PIPE_HEAD(*inode) &= (PAGE_SIZE-1); + while (chars-->0) + ((char *)inode->i_size)[size++]=get_fs_byte(buf++); + } + wake_up(&inode->i_wait); + return written; +} + +int sys_pipe(unsigned long * fildes) +{ + struct m_inode * inode; + struct file * f[2]; + int fd[2]; + int i,j; + + j=0; + for(i=0;j<2 && if_count++; + if (j==1) + f[0]->f_count=0; + if (j<2) + return -1; + j=0; + for(i=0;j<2 && ifilp[i]) { + current->filp[ fd[j]=i ] = f[j]; + j++; + } + if (j==1) + current->filp[fd[0]]=NULL; + if (j<2) { + f[0]->f_count=f[1]->f_count=0; + return -1; + } + if (!(inode=get_pipe_inode())) { + current->filp[fd[0]] = + current->filp[fd[1]] = NULL; + f[0]->f_count = f[1]->f_count = 0; + return -1; + } + f[0]->f_inode = f[1]->f_inode = inode; + f[0]->f_pos = f[1]->f_pos = 0; + f[0]->f_mode = 1; /* read */ + f[1]->f_mode = 2; /* write */ + put_fs_long(fd[0],0+fildes); + put_fs_long(fd[1],1+fildes); + return 0; +} diff --git a/linux/fs/read_write.c b/linux/fs/read_write.c new file mode 100644 index 0000000..341274a --- /dev/null +++ b/linux/fs/read_write.c @@ -0,0 +1,103 @@ +/* + * linux/fs/read_write.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include +#include + +extern int rw_char(int rw,int dev, char * buf, int count, off_t * pos); +extern int read_pipe(struct m_inode * inode, char * buf, int count); +extern int write_pipe(struct m_inode * inode, char * buf, int count); +extern int block_read(int dev, off_t * pos, char * buf, int count); +extern int block_write(int dev, off_t * pos, char * buf, int count); +extern int file_read(struct m_inode * inode, struct file * filp, + char * buf, int count); +extern int file_write(struct m_inode * inode, struct file * filp, + char * buf, int count); + +int sys_lseek(unsigned int fd,off_t offset, int origin) +{ + struct file * file; + int tmp; + + if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode) + || !IS_SEEKABLE(MAJOR(file->f_inode->i_dev))) + return -EBADF; + if (file->f_inode->i_pipe) + return -ESPIPE; + switch (origin) { + case 0: + if (offset<0) return -EINVAL; + file->f_pos=offset; + break; + case 1: + if (file->f_pos+offset<0) return -EINVAL; + file->f_pos += offset; + break; + case 2: + if ((tmp=file->f_inode->i_size+offset) < 0) + return -EINVAL; + file->f_pos = tmp; + break; + default: + return -EINVAL; + } + return file->f_pos; +} + +int sys_read(unsigned int fd,char * buf,int count) +{ + struct file * file; + struct m_inode * inode; + + if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd])) + return -EINVAL; + if (!count) + return 0; + verify_area(buf,count); + inode = file->f_inode; + if (inode->i_pipe) + return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO; + if (S_ISCHR(inode->i_mode)) + return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos); + if (S_ISBLK(inode->i_mode)) + return block_read(inode->i_zone[0],&file->f_pos,buf,count); + if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) { + if (count+file->f_pos > inode->i_size) + count = inode->i_size - file->f_pos; + if (count<=0) + return 0; + return file_read(inode,file,buf,count); + } + printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode); + return -EINVAL; +} + +int sys_write(unsigned int fd,char * buf,int count) +{ + struct file * file; + struct m_inode * inode; + + if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd])) + return -EINVAL; + if (!count) + return 0; + inode=file->f_inode; + if (inode->i_pipe) + return (file->f_mode&2)?write_pipe(inode,buf,count):-EIO; + if (S_ISCHR(inode->i_mode)) + return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos); + if (S_ISBLK(inode->i_mode)) + return block_write(inode->i_zone[0],&file->f_pos,buf,count); + if (S_ISREG(inode->i_mode)) + return file_write(inode,file,buf,count); + printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode); + return -EINVAL; +} diff --git a/linux/fs/select.c b/linux/fs/select.c new file mode 100644 index 0000000..cef8b43 --- /dev/null +++ b/linux/fs/select.c @@ -0,0 +1,10 @@ +/* nothing , only the stub */ +/* gohigh */ + +#include + +int sys_select() +{ + return -ENOSYS; +} + diff --git a/linux/fs/stat.c b/linux/fs/stat.c new file mode 100644 index 0000000..ef09856 --- /dev/null +++ b/linux/fs/stat.c @@ -0,0 +1,66 @@ +/* + * linux/fs/stat.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include + +static void cp_stat(struct m_inode * inode, struct stat * statbuf) +{ + struct stat tmp; + int i; + + verify_area(statbuf,sizeof (* statbuf)); + tmp.st_dev = inode->i_dev; + tmp.st_ino = inode->i_num; + tmp.st_mode = inode->i_mode; + tmp.st_nlink = inode->i_nlinks; + tmp.st_uid = inode->i_uid; + tmp.st_gid = inode->i_gid; + tmp.st_rdev = inode->i_zone[0]; + tmp.st_size = inode->i_size; + tmp.st_atime = inode->i_atime; + tmp.st_mtime = inode->i_mtime; + tmp.st_ctime = inode->i_ctime; + for (i=0 ; i= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode)) + return -EBADF; + cp_stat(inode,statbuf); + return 0; +} + +int sys_readlink() +{ + return -ENOSYS; +} diff --git a/linux/fs/super.c b/linux/fs/super.c new file mode 100644 index 0000000..6a4ccb1 --- /dev/null +++ b/linux/fs/super.c @@ -0,0 +1,282 @@ +/* + * linux/fs/super.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * super.c contains code to handle the super-block tables. + */ +#include +#include +#include +#include + +#include +#include + +int sync_dev(int dev); +void wait_for_keypress(void); + +/* set_bit uses setb, as gas doesn't recognize setc */ +#define set_bit(bitnr,addr) ({ \ +register int __res __asm__("ax"); \ +__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \ +__res; }) + +struct super_block super_block[NR_SUPER]; +/* this is initialized in init/main.c */ +int ROOT_DEV = 0; + +static void lock_super(struct super_block * sb) +{ + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); + sb->s_lock = 1; + sti(); +} + +static void free_super(struct super_block * sb) +{ + cli(); + sb->s_lock = 0; + wake_up(&(sb->s_wait)); + sti(); +} + +static void wait_on_super(struct super_block * sb) +{ + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); + sti(); +} + +struct super_block * get_super(int dev) +{ + struct super_block * s; + + if (!dev) + return NULL; + s = 0+super_block; + while (s < NR_SUPER+super_block) + if (s->s_dev == dev) { + wait_on_super(s); + if (s->s_dev == dev) + return s; + s = 0+super_block; + } else + s++; + return NULL; +} + +void put_super(int dev) +{ + struct super_block * sb; +/* struct m_inode * inode; */ + int i; + + if (dev == ROOT_DEV) { + printk("root diskette changed: prepare for armageddon\n\r"); + return; + } + if (!(sb = get_super(dev))) + return; + if (sb->s_imount) { + printk("Mounted disk changed - tssk, tssk\n\r"); + return; + } + lock_super(sb); + sb->s_dev = 0; + for(i=0;is_imap[i]); + for(i=0;is_zmap[i]); + free_super(sb); + return; +} + +static struct super_block * read_super(int dev) +{ + struct super_block * s; + struct buffer_head * bh; + int i,block; + + if (!dev) + return NULL; + check_disk_change(dev); + if (s = get_super(dev)) + return s; + for (s = 0+super_block ;; s++) { + if (s >= NR_SUPER+super_block) + return NULL; + if (!s->s_dev) + break; + } + s->s_dev = dev; + s->s_isup = NULL; + s->s_imount = NULL; + s->s_time = 0; + s->s_rd_only = 0; + s->s_dirt = 0; + lock_super(s); + if (!(bh = bread(dev,1))) { + s->s_dev=0; + free_super(s); + return NULL; + } + __asm__ volatile ("cld"); /* by wyj */ + *((struct d_super_block *) s) = + *((struct d_super_block *) bh->b_data); + brelse(bh); + if (s->s_magic != SUPER_MAGIC) { + s->s_dev = 0; + free_super(s); + return NULL; + } + for (i=0;is_imap[i] = NULL; + for (i=0;is_zmap[i] = NULL; + block=2; + for (i=0 ; i < s->s_imap_blocks ; i++) + if (s->s_imap[i]=bread(dev,block)) + block++; + else + break; + for (i=0 ; i < s->s_zmap_blocks ; i++) + if (s->s_zmap[i]=bread(dev,block)) + block++; + else + break; + if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) { + for(i=0;is_imap[i]); + for(i=0;is_zmap[i]); + s->s_dev=0; + free_super(s); + return NULL; + } + s->s_imap[0]->b_data[0] |= 1; + s->s_zmap[0]->b_data[0] |= 1; + free_super(s); + return s; +} + +int sys_umount(char * dev_name) +{ + struct m_inode * inode; + struct super_block * sb; + int dev; + + if (!(inode=namei(dev_name))) + return -ENOENT; + dev = inode->i_zone[0]; + if (!S_ISBLK(inode->i_mode)) { + iput(inode); + return -ENOTBLK; + } + iput(inode); + if (dev==ROOT_DEV) + return -EBUSY; + if (!(sb=get_super(dev)) || !(sb->s_imount)) + return -ENOENT; + if (!sb->s_imount->i_mount) + printk("Mounted inode has i_mount=0\n"); + for (inode=inode_table+0 ; inodei_dev==dev && inode->i_count) + return -EBUSY; + sb->s_imount->i_mount=0; + iput(sb->s_imount); + sb->s_imount = NULL; + iput(sb->s_isup); + sb->s_isup = NULL; + put_super(dev); + sync_dev(dev); + return 0; +} + +int sys_mount(char * dev_name, char * dir_name, int rw_flag) +{ + struct m_inode * dev_i, * dir_i; + struct super_block * sb; + int dev; + + if (!(dev_i=namei(dev_name))) + return -ENOENT; + dev = dev_i->i_zone[0]; + if (!S_ISBLK(dev_i->i_mode)) { + iput(dev_i); + return -EPERM; + } + iput(dev_i); + if (!(dir_i=namei(dir_name))) + return -ENOENT; + if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) { + iput(dir_i); + return -EBUSY; + } + if (!S_ISDIR(dir_i->i_mode)) { + iput(dir_i); + return -EPERM; + } + if (!(sb=read_super(dev))) { + iput(dir_i); + return -EBUSY; + } + if (sb->s_imount) { + iput(dir_i); + return -EBUSY; + } + if (dir_i->i_mount) { + iput(dir_i); + return -EPERM; + } + sb->s_imount=dir_i; + dir_i->i_mount=1; + dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */ + return 0; /* we do that in umount */ +} + +void mount_root(void) +{ + int i,free; + struct super_block * p; + struct m_inode * mi; + + if (32 != sizeof (struct d_inode)) + panic("bad i-node size"); + for(i=0;is_dev = 0; + p->s_lock = 0; + p->s_wait = NULL; + } + if (!(p=read_super(ROOT_DEV))) + panic("Unable to mount root"); + if (!(mi=iget(ROOT_DEV,ROOT_INO))) + panic("Unable to read root i-node"); + mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ + p->s_isup = p->s_imount = mi; + current->pwd = mi; + current->root = mi; + free=0; + i=p->s_nzones; + while (-- i >= 0) + if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data)) + free++; + printk("%d/%d free blocks\n\r",free,p->s_nzones); + free=0; + i=p->s_ninodes+1; + while (-- i >= 0) + if (!set_bit(i&8191,p->s_imap[i>>13]->b_data)) + free++; + printk("%d/%d free inodes\n\r",free,p->s_ninodes); +} diff --git a/linux/fs/truncate.c b/linux/fs/truncate.c new file mode 100644 index 0000000..36f3ea2 --- /dev/null +++ b/linux/fs/truncate.c @@ -0,0 +1,65 @@ +/* + * linux/fs/truncate.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include + +static void free_ind(int dev,int block) +{ + struct buffer_head * bh; + unsigned short * p; + int i; + + if (!block) + return; + if (bh=bread(dev,block)) { + p = (unsigned short *) bh->b_data; + for (i=0;i<512;i++,p++) + if (*p) + free_block(dev,*p); + brelse(bh); + } + free_block(dev,block); +} + +static void free_dind(int dev,int block) +{ + struct buffer_head * bh; + unsigned short * p; + int i; + + if (!block) + return; + if (bh=bread(dev,block)) { + p = (unsigned short *) bh->b_data; + for (i=0;i<512;i++,p++) + if (*p) + free_ind(dev,*p); + brelse(bh); + } + free_block(dev,block); +} + +void truncate(struct m_inode * inode) +{ + int i; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) + return; + for (i=0;i<7;i++) + if (inode->i_zone[i]) { + free_block(inode->i_dev,inode->i_zone[i]); + inode->i_zone[i]=0; + } + free_ind(inode->i_dev,inode->i_zone[7]); + free_dind(inode->i_dev,inode->i_zone[8]); + inode->i_zone[7] = inode->i_zone[8] = 0; + inode->i_size = 0; + inode->i_dirt = 1; + inode->i_mtime = inode->i_ctime = CURRENT_TIME; +} + diff --git a/linux/include/a.out.h b/linux/include/a.out.h new file mode 100644 index 0000000..3e67974 --- /dev/null +++ b/linux/include/a.out.h @@ -0,0 +1,220 @@ +#ifndef _A_OUT_H +#define _A_OUT_H + +#define __GNU_EXEC_MACROS__ + +struct exec { + unsigned long a_magic; /* Use macros N_MAGIC, etc for access */ + unsigned a_text; /* length of text, in bytes */ + unsigned a_data; /* length of data, in bytes */ + unsigned a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned a_syms; /* length of symbol table data in file, in bytes */ + unsigned a_entry; /* start address */ + unsigned a_trsize; /* length of relocation info for text, in bytes */ + unsigned a_drsize; /* length of relocation info for data, in bytes */ +}; + +#ifndef N_MAGIC +#define N_MAGIC(exec) ((exec).a_magic) +#endif + +#ifndef OMAGIC +/* Code indicating object file or impure executable. */ +#define OMAGIC 0407 +/* Code indicating pure executable. */ +#define NMAGIC 0410 +/* Code indicating demand-paged executable. */ +#define ZMAGIC 0413 +#endif /* not OMAGIC */ + +#ifndef N_BADMAG +#define N_BADMAG(x) \ + (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) +#endif + +#define _N_BADMAG(x) \ + (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) + +#define _N_HDROFF(x) (SEGMENT_SIZE - sizeof (struct exec)) + +#ifndef N_TXTOFF +#define N_TXTOFF(x) \ + (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec)) +#endif + +#ifndef N_DATOFF +#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) +#endif + +#ifndef N_TRELOFF +#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data) +#endif + +#ifndef N_DRELOFF +#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize) +#endif + +#ifndef N_SYMOFF +#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize) +#endif + +#ifndef N_STROFF +#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms) +#endif + +/* Address of text segment in memory after it is loaded. */ +#ifndef N_TXTADDR +#define N_TXTADDR(x) 0 +#endif + +/* Address of data segment in memory after it is loaded. + Note that it is up to you to define SEGMENT_SIZE + on machines not listed here. */ +#if defined(vax) || defined(hp300) || defined(pyr) +#define SEGMENT_SIZE PAGE_SIZE +#endif +#ifdef hp300 +#define PAGE_SIZE 4096 +#endif +#ifdef sony +#define SEGMENT_SIZE 0x2000 +#endif /* Sony. */ +#ifdef is68k +#define SEGMENT_SIZE 0x20000 +#endif +#if defined(m68k) && defined(PORTAR) +#define PAGE_SIZE 0x400 +#define SEGMENT_SIZE PAGE_SIZE +#endif + +#define PAGE_SIZE 4096 +#define SEGMENT_SIZE 1024 + +#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1)) + +#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) + +#ifndef N_DATADDR +#define N_DATADDR(x) \ + (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ + : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) +#endif + +/* Address of bss segment in memory after it is loaded. */ +#ifndef N_BSSADDR +#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) +#endif + +#ifndef N_NLIST_DECLARED +struct nlist { + union { + char *n_name; + struct nlist *n_next; + long n_strx; + } n_un; + unsigned char n_type; + char n_other; + short n_desc; + unsigned long n_value; +}; +#endif + +#ifndef N_UNDF +#define N_UNDF 0 +#endif +#ifndef N_ABS +#define N_ABS 2 +#endif +#ifndef N_TEXT +#define N_TEXT 4 +#endif +#ifndef N_DATA +#define N_DATA 6 +#endif +#ifndef N_BSS +#define N_BSS 8 +#endif +#ifndef N_COMM +#define N_COMM 18 +#endif +#ifndef N_FN +#define N_FN 15 +#endif + +#ifndef N_EXT +#define N_EXT 1 +#endif +#ifndef N_TYPE +#define N_TYPE 036 +#endif +#ifndef N_STAB +#define N_STAB 0340 +#endif + +/* The following type indicates the definition of a symbol as being + an indirect reference to another symbol. The other symbol + appears as an undefined reference, immediately following this symbol. + + Indirection is asymmetrical. The other symbol's value will be used + to satisfy requests for the indirect symbol, but not vice versa. + If the other symbol does not have a definition, libraries will + be searched to find a definition. */ +#define N_INDR 0xa + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + element's value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +/* These appear as input to LD, in a .o file. */ +#define N_SETA 0x14 /* Absolute set element symbol */ +#define N_SETT 0x16 /* Text set element symbol */ +#define N_SETD 0x18 /* Data set element symbol */ +#define N_SETB 0x1A /* Bss set element symbol */ + +/* This is output from LD. */ +#define N_SETV 0x1C /* Pointer to set vector in data area. */ + +#ifndef N_RELOCATION_INFO_DECLARED + +/* This structure describes a single relocation to be performed. + The text-relocation section of the file is a vector of these structures, + all of which apply to the text section. + Likewise, the data-relocation section applies to the data section. */ + +struct relocation_info +{ + /* Address (within segment) to be relocated. */ + int r_address; + /* The meaning of r_symbolnum depends on r_extern. */ + unsigned int r_symbolnum:24; + /* Nonzero means value is a pc-relative offset + and it should be relocated for changes in its own address + as well as for changes in the symbol or section specified. */ + unsigned int r_pcrel:1; + /* Length (as exponent of 2) of the field to be relocated. + Thus, a value of 2 indicates 1<<2 bytes. */ + unsigned int r_length:2; + /* 1 => relocate with value of symbol. + r_symbolnum is the index of the symbol + in file's the symbol table. + 0 => relocate with the address of a segment. + r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS + (the N_EXT bit may be set also, but signifies nothing). */ + unsigned int r_extern:1; + /* Four bits that aren't used, but when writing an object file + it is desirable to clear them. */ + unsigned int r_pad:4; +}; +#endif /* no N_RELOCATION_INFO_DECLARED. */ + + +#endif /* __A_OUT_GNU_H__ */ diff --git a/linux/include/asm/io.h b/linux/include/asm/io.h new file mode 100644 index 0000000..d5cc42a --- /dev/null +++ b/linux/include/asm/io.h @@ -0,0 +1,24 @@ +#define outb(value,port) \ +__asm__ ("outb %%al,%%dx"::"a" (value),"d" (port)) + + +#define inb(port) ({ \ +unsigned char _v; \ +__asm__ volatile ("inb %%dx,%%al":"=a" (_v):"d" (port)); \ +_v; \ +}) + +#define outb_p(value,port) \ +__asm__ ("outb %%al,%%dx\n" \ + "\tjmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:"::"a" (value),"d" (port)) + +#define inb_p(port) ({ \ +unsigned char _v; \ +__asm__ volatile ("inb %%dx,%%al\n" \ + "\tjmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:":"=a" (_v):"d" (port)); \ +_v; \ +}) diff --git a/linux/include/asm/memory.h b/linux/include/asm/memory.h new file mode 100644 index 0000000..51b69e7 --- /dev/null +++ b/linux/include/asm/memory.h @@ -0,0 +1,15 @@ +/* + * NOTE!!! memcpy(dest,src,n) assumes ds=es=normal data segment. This + * goes for all kernel functions (ds=es=kernel space, fs=local data, + * gs=null), as well as for all well-behaving user programs (ds=es= + * user data space). This is NOT a bug, as any user program that changes + * es deserves to die if it isn't careful. + */ +#define memcpy(dest,src,n) ({ \ +void * _res = dest; \ +__asm__ ("cld;rep;movsb" \ + ::"D" ((long)(_res)),"S" ((long)(src)),"c" ((long) (n)) \ + ); \ +_res; \ +}) + diff --git a/linux/include/asm/segment.h b/linux/include/asm/segment.h new file mode 100644 index 0000000..94dd102 --- /dev/null +++ b/linux/include/asm/segment.h @@ -0,0 +1,65 @@ +static inline unsigned char get_fs_byte(const char * addr) +{ + unsigned register char _v; + + __asm__ ("movb %%fs:%1,%0":"=r" (_v):"m" (*addr)); + return _v; +} + +static inline unsigned short get_fs_word(const unsigned short *addr) +{ + unsigned short _v; + + __asm__ ("movw %%fs:%1,%0":"=r" (_v):"m" (*addr)); + return _v; +} + +static inline unsigned long get_fs_long(const unsigned long *addr) +{ + unsigned long _v; + + __asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \ + return _v; +} + +static inline void put_fs_byte(char val,char *addr) +{ +__asm__ ("movb %0,%%fs:%1"::"r" (val),"m" (*addr)); +} + +static inline void put_fs_word(short val,short * addr) +{ +__asm__ ("movw %0,%%fs:%1"::"r" (val),"m" (*addr)); +} + +static inline void put_fs_long(unsigned long val,unsigned long * addr) +{ +__asm__ ("movl %0,%%fs:%1"::"r" (val),"m" (*addr)); +} + +/* + * Someone who knows GNU asm better than I should double check the followig. + * It seems to work, but I don't know if I'm doing something subtly wrong. + * --- TYT, 11/24/91 + * [ nothing wrong here, Linus ] + */ + +static inline unsigned long get_fs() +{ + unsigned short _v; + __asm__("mov %%fs,%%ax":"=a" (_v):); + return _v; +} + +static inline unsigned long get_ds() +{ + unsigned short _v; + __asm__("mov %%ds,%%ax":"=a" (_v):); + return _v; +} + +static inline void set_fs(unsigned long val) +{ + __asm__("mov %0,%%fs"::"a" ((unsigned short) val)); +} + diff --git a/linux/include/asm/system.h b/linux/include/asm/system.h new file mode 100644 index 0000000..0b5a21d --- /dev/null +++ b/linux/include/asm/system.h @@ -0,0 +1,66 @@ +#define move_to_user_mode() \ +__asm__ ("movl %%esp,%%eax\n\t" \ + "pushl $0x17\n\t" \ + "pushl %%eax\n\t" \ + "pushfl\n\t" \ + "pushl $0x0f\n\t" \ + "pushl $1f\n\t" \ + "iret\n" \ + "1:\tmovl $0x17,%%eax\n\t" \ + "movw %%ax,%%ds\n\t" \ + "movw %%ax,%%es\n\t" \ + "movw %%ax,%%fs\n\t" \ + "movw %%ax,%%gs" \ + :::"ax") + +#define sti() __asm__ ("sti"::) +#define cli() __asm__ ("cli"::) +#define nop() __asm__ ("nop"::) + +#define iret() __asm__ ("iret"::) + +#define _set_gate(gate_addr,type,dpl,addr) \ +__asm__ ("movw %%dx,%%ax\n\t" \ + "movw %0,%%dx\n\t" \ + "movl %%eax,%1\n\t" \ + "movl %%edx,%2" \ + : \ + : "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ + "o" (*((char *) (gate_addr))), \ + "o" (*(4+(char *) (gate_addr))), \ + "d" ((char *) (addr)),"a" (0x00080000)) + +#define set_intr_gate(n,addr) \ + _set_gate(&idt[n],14,0,addr) + +#define set_trap_gate(n,addr) \ + _set_gate(&idt[n],15,0,addr) + +#define set_system_gate(n,addr) \ + _set_gate(&idt[n],15,3,addr) + +#define _set_seg_desc(gate_addr,type,dpl,base,limit) {\ + *(gate_addr) = ((base) & 0xff000000) | \ + (((base) & 0x00ff0000)>>16) | \ + ((limit) & 0xf0000) | \ + ((dpl)<<13) | \ + (0x00408000) | \ + ((type)<<8); \ + *((gate_addr)+1) = (((base) & 0x0000ffff)<<16) | \ + ((limit) & 0x0ffff); } + +#define _set_tssldt_desc(n,addr,type) \ +__asm__ ("movw $104,%1\n\t" \ + "movw %%ax,%2\n\t" \ + "rorl $16,%%eax\n\t" \ + "movb %%al,%3\n\t" \ + "movb $" type ",%4\n\t" \ + "movb $0x00,%5\n\t" \ + "movb %%ah,%6\n\t" \ + "rorl $16,%%eax" \ + ::"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \ + "m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \ + ) + +#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr,"0x89") +#define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr,"0x82") diff --git a/linux/include/const.h b/linux/include/const.h new file mode 100644 index 0000000..7828e61 --- /dev/null +++ b/linux/include/const.h @@ -0,0 +1,15 @@ +#ifndef _CONST_H +#define _CONST_H + +#define BUFFER_END 0x200000 + +#define I_TYPE 0170000 +#define I_DIRECTORY 0040000 +#define I_REGULAR 0100000 +#define I_BLOCK_SPECIAL 0060000 +#define I_CHAR_SPECIAL 0020000 +#define I_NAMED_PIPE 0010000 +#define I_SET_UID_BIT 0004000 +#define I_SET_GID_BIT 0002000 + +#endif diff --git a/linux/include/ctype.h b/linux/include/ctype.h new file mode 100644 index 0000000..7acf55d --- /dev/null +++ b/linux/include/ctype.h @@ -0,0 +1,34 @@ +#ifndef _CTYPE_H +#define _CTYPE_H + +#define _U 0x01 /* upper */ +#define _L 0x02 /* lower */ +#define _D 0x04 /* digit */ +#define _C 0x08 /* cntrl */ +#define _P 0x10 /* punct */ +#define _S 0x20 /* white space (space/lf/tab) */ +#define _X 0x40 /* hex digit */ +#define _SP 0x80 /* hard space (0x20) */ + +extern unsigned char _ctype[]; +extern char _ctmp; + +#define isalnum(c) ((_ctype+1)[c]&(_U|_L|_D)) +#define isalpha(c) ((_ctype+1)[c]&(_U|_L)) +#define iscntrl(c) ((_ctype+1)[c]&(_C)) +#define isdigit(c) ((_ctype+1)[c]&(_D)) +#define isgraph(c) ((_ctype+1)[c]&(_P|_U|_L|_D)) +#define islower(c) ((_ctype+1)[c]&(_L)) +#define isprint(c) ((_ctype+1)[c]&(_P|_U|_L|_D|_SP)) +#define ispunct(c) ((_ctype+1)[c]&(_P)) +#define isspace(c) ((_ctype+1)[c]&(_S)) +#define isupper(c) ((_ctype+1)[c]&(_U)) +#define isxdigit(c) ((_ctype+1)[c]&(_D|_X)) + +#define isascii(c) (((unsigned) c)<=0x7f) +#define toascii(c) (((unsigned) c)&0x7f) + +#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp-('A'-'a'):_ctmp) +#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp-('a'-'A'):_ctmp) + +#endif diff --git a/linux/include/errno.h b/linux/include/errno.h new file mode 100644 index 0000000..c282f69 --- /dev/null +++ b/linux/include/errno.h @@ -0,0 +1,60 @@ +#ifndef _ERRNO_H +#define _ERRNO_H + +/* + * ok, as I hadn't got any other source of information about + * possible error numbers, I was forced to use the same numbers + * as minix. + * Hopefully these are posix or something. I wouldn't know (and posix + * isn't telling me - they want $$$ for their f***ing standard). + * + * We don't use the _SIGN cludge of minix, so kernel returns must + * see to the sign by themselves. + * + * NOTE! Remember to change strerror() if you change this file! + */ + +extern int errno; + +#define ERROR 99 +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define ENOTBLK 15 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define EINVAL 22 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define ETXTBSY 26 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define ERANGE 34 +#define EDEADLK 35 +#define ENAMETOOLONG 36 +#define ENOLCK 37 +#define ENOSYS 38 +#define ENOTEMPTY 39 + +#endif diff --git a/linux/include/fcntl.h b/linux/include/fcntl.h new file mode 100644 index 0000000..a5bf9af --- /dev/null +++ b/linux/include/fcntl.h @@ -0,0 +1,55 @@ +#ifndef _FCNTL_H +#define _FCNTL_H + +#include + +/* open/fcntl - NOCTTY, NDELAY isn't implemented yet */ +#define O_ACCMODE 00003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 00100 /* not fcntl */ +#define O_EXCL 00200 /* not fcntl */ +#define O_NOCTTY 00400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 /* not fcntl */ +#define O_NDELAY O_NONBLOCK + +/* Defines for fcntl-commands. Note that currently + * locking isn't supported, and other things aren't really + * tested. + */ +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get f_flags */ +#define F_SETFD 2 /* set f_flags */ +#define F_GETFL 3 /* more flags (cloexec) */ +#define F_SETFL 4 +#define F_GETLK 5 /* not implemented */ +#define F_SETLK 6 +#define F_SETLKW 7 + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* Ok, these are locking features, and aren't implemented at any + * level. POSIX wants them. + */ +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +/* Once again - not implemented, but ... */ +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +extern int creat(const char * filename,mode_t mode); +extern int fcntl(int fildes,int cmd, ...); +extern int open(const char * filename, int flags, ...); + +#endif diff --git a/linux/include/linux/config.h b/linux/include/linux/config.h new file mode 100644 index 0000000..c979fb3 --- /dev/null +++ b/linux/include/linux/config.h @@ -0,0 +1,48 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +/* + * The root-device is no longer hard-coded. You can change the default + * root-device by changing the line ROOT_DEV = XXX in boot/bootsect.s + */ + +/* + * define your keyboard here - + * KBD_FINNISH for Finnish keyboards + * KBD_US for US-type + * KBD_GR for German keyboards + * KBD_FR for Frech keyboard + */ +#define KBD_US +/*#define KBD_GR */ +/*#define KBD_FR */ +/*#define KBD_FINNISH */ + +/* + * Normally, Linux can get the drive parameters from the BIOS at + * startup, but if this for some unfathomable reason fails, you'd + * be left stranded. For this case, you can define HD_TYPE, which + * contains all necessary info on your harddisk. + * + * The HD_TYPE macro should look like this: + * + * #define HD_TYPE { head, sect, cyl, wpcom, lzone, ctl} + * + * In case of two harddisks, the info should be sepatated by + * commas: + * + * #define HD_TYPE { h,s,c,wpcom,lz,ctl },{ h,s,c,wpcom,lz,ctl } + */ +/* + This is an example, two drives, first is type 2, second is type 3: + +#define HD_TYPE { 4,17,615,300,615,8 }, { 6,17,615,300,615,0 } + + NOTE: ctl is 0 for all drives with heads<=8, and ctl=8 for drives + with more than 8 heads. + + If you want the BIOS to tell what kind of drive you have, just + leave HD_TYPE undefined. This is the normal thing to do. +*/ + +#endif diff --git a/linux/include/linux/fdreg.h b/linux/include/linux/fdreg.h new file mode 100644 index 0000000..01355af --- /dev/null +++ b/linux/include/linux/fdreg.h @@ -0,0 +1,71 @@ +/* + * This file contains some defines for the floppy disk controller. + * Various sources. Mostly "IBM Microcomputers: A Programmers + * Handbook", Sanches and Canton. + */ +#ifndef _FDREG_H +#define _FDREG_H + +extern int ticks_to_floppy_on(unsigned int nr); +extern void floppy_on(unsigned int nr); +extern void floppy_off(unsigned int nr); +extern void floppy_select(unsigned int nr); +extern void floppy_deselect(unsigned int nr); + +/* Fd controller regs. S&C, about page 340 */ +#define FD_STATUS 0x3f4 +#define FD_DATA 0x3f5 +#define FD_DOR 0x3f2 /* Digital Output Register */ +#define FD_DIR 0x3f7 /* Digital Input Register (read) */ +#define FD_DCR 0x3f7 /* Diskette Control Register (write)*/ + +/* Bits of main status register */ +#define STATUS_BUSYMASK 0x0F /* drive busy mask */ +#define STATUS_BUSY 0x10 /* FDC busy */ +#define STATUS_DMA 0x20 /* 0- DMA mode */ +#define STATUS_DIR 0x40 /* 0- cpu->fdc */ +#define STATUS_READY 0x80 /* Data reg ready */ + +/* Bits of FD_ST0 */ +#define ST0_DS 0x03 /* drive select mask */ +#define ST0_HA 0x04 /* Head (Address) */ +#define ST0_NR 0x08 /* Not Ready */ +#define ST0_ECE 0x10 /* Equipment chech error */ +#define ST0_SE 0x20 /* Seek end */ +#define ST0_INTR 0xC0 /* Interrupt code mask */ + +/* Bits of FD_ST1 */ +#define ST1_MAM 0x01 /* Missing Address Mark */ +#define ST1_WP 0x02 /* Write Protect */ +#define ST1_ND 0x04 /* No Data - unreadable */ +#define ST1_OR 0x10 /* OverRun */ +#define ST1_CRC 0x20 /* CRC error in data or addr */ +#define ST1_EOC 0x80 /* End Of Cylinder */ + +/* Bits of FD_ST2 */ +#define ST2_MAM 0x01 /* Missing Addess Mark (again) */ +#define ST2_BC 0x02 /* Bad Cylinder */ +#define ST2_SNS 0x04 /* Scan Not Satisfied */ +#define ST2_SEH 0x08 /* Scan Equal Hit */ +#define ST2_WC 0x10 /* Wrong Cylinder */ +#define ST2_CRC 0x20 /* CRC error in data field */ +#define ST2_CM 0x40 /* Control Mark = deleted */ + +/* Bits of FD_ST3 */ +#define ST3_HA 0x04 /* Head (Address) */ +#define ST3_TZ 0x10 /* Track Zero signal (1=track 0) */ +#define ST3_WP 0x40 /* Write Protect */ + +/* Values for FD_COMMAND */ +#define FD_RECALIBRATE 0x07 /* move to track 0 */ +#define FD_SEEK 0x0F /* seek track */ +#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */ +#define FD_WRITE 0xC5 /* write with MT, MFM */ +#define FD_SENSEI 0x08 /* Sense Interrupt Status */ +#define FD_SPECIFY 0x03 /* specify HUT etc */ + +/* DMA commands */ +#define DMA_READ 0x46 +#define DMA_WRITE 0x4A + +#endif diff --git a/linux/include/linux/fs.h b/linux/include/linux/fs.h new file mode 100644 index 0000000..7a90b10 --- /dev/null +++ b/linux/include/linux/fs.h @@ -0,0 +1,202 @@ +/* + * This file has definitions for some important file table + * structures etc. + */ + +#ifndef _FS_H +#define _FS_H + +#include + +/* devices are as follows: (same as minix, so we can use the minix + * file system. These are major numbers.) + * + * 0 - unused (nodev) + * 1 - /dev/mem + * 2 - /dev/fd + * 3 - /dev/hd + * 4 - /dev/ttyx + * 5 - /dev/tty + * 6 - /dev/lp + * 7 - unnamed pipes + */ + +#define IS_SEEKABLE(x) ((x)>=1 && (x)<=3) + +#define READ 0 +#define WRITE 1 +#define READA 2 /* read-ahead - don't pause */ +#define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */ + +void buffer_init(long buffer_end); + +#define MAJOR(a) (((unsigned)(a))>>8) +#define MINOR(a) ((a)&0xff) + +#define NAME_LEN 14 +#define ROOT_INO 1 + +#define I_MAP_SLOTS 8 +#define Z_MAP_SLOTS 8 +#define SUPER_MAGIC 0x137F + +#define NR_OPEN 20 +#define NR_INODE 32 +#define NR_FILE 64 +#define NR_SUPER 8 +#define NR_HASH 307 +#define NR_BUFFERS nr_buffers +#define BLOCK_SIZE 1024 +#define BLOCK_SIZE_BITS 10 +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#define INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct d_inode))) +#define DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct dir_entry))) + +#define PIPE_HEAD(inode) ((inode).i_zone[0]) +#define PIPE_TAIL(inode) ((inode).i_zone[1]) +#define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1)) +#define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode)) +#define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1)) +#define INC_PIPE(head) \ +__asm__("incl %0\n\tandl $4095,%0"::"m" (head)) + +typedef char buffer_block[BLOCK_SIZE]; + +struct buffer_head { + char * b_data; /* pointer to data block (1024 bytes) */ + unsigned long b_blocknr; /* block number */ + unsigned short b_dev; /* device (0 = free) */ + unsigned char b_uptodate; + unsigned char b_dirt; /* 0-clean,1-dirty */ + unsigned char b_count; /* users using this block */ + unsigned char b_lock; /* 0 - ok, 1 -locked */ + struct task_struct * b_wait; + struct buffer_head * b_prev; + struct buffer_head * b_next; + struct buffer_head * b_prev_free; + struct buffer_head * b_next_free; +}; + +struct d_inode { + unsigned short i_mode; + unsigned short i_uid; + unsigned long i_size; + unsigned long i_time; + unsigned char i_gid; + unsigned char i_nlinks; + unsigned short i_zone[9]; +}; + +struct m_inode { + unsigned short i_mode; + unsigned short i_uid; + unsigned long i_size; + unsigned long i_mtime; + unsigned char i_gid; + unsigned char i_nlinks; + unsigned short i_zone[9]; +/* these are in memory also */ + struct task_struct * i_wait; + unsigned long i_atime; + unsigned long i_ctime; + unsigned short i_dev; + unsigned short i_num; + unsigned short i_count; + unsigned char i_lock; + unsigned char i_dirt; + unsigned char i_pipe; + unsigned char i_mount; + unsigned char i_seek; + unsigned char i_update; +}; + +struct file { + unsigned short f_mode; + unsigned short f_flags; + unsigned short f_count; + struct m_inode * f_inode; + off_t f_pos; +}; + +struct super_block { + unsigned short s_ninodes; + unsigned short s_nzones; + unsigned short s_imap_blocks; + unsigned short s_zmap_blocks; + unsigned short s_firstdatazone; + unsigned short s_log_zone_size; + unsigned long s_max_size; + unsigned short s_magic; +/* These are only in memory */ + struct buffer_head * s_imap[8]; + struct buffer_head * s_zmap[8]; + unsigned short s_dev; + struct m_inode * s_isup; + struct m_inode * s_imount; + unsigned long s_time; + struct task_struct * s_wait; + unsigned char s_lock; + unsigned char s_rd_only; + unsigned char s_dirt; +}; + +struct d_super_block { + unsigned short s_ninodes; + unsigned short s_nzones; + unsigned short s_imap_blocks; + unsigned short s_zmap_blocks; + unsigned short s_firstdatazone; + unsigned short s_log_zone_size; + unsigned long s_max_size; + unsigned short s_magic; +}; + +struct dir_entry { + unsigned short inode; + char name[NAME_LEN]; +}; + +extern struct m_inode inode_table[NR_INODE]; +extern struct file file_table[NR_FILE]; +extern struct super_block super_block[NR_SUPER]; +extern struct buffer_head * start_buffer; +extern int nr_buffers; + +extern void check_disk_change(int dev); +extern int floppy_change(unsigned int nr); +extern int ticks_to_floppy_on(unsigned int dev); +extern void floppy_on(unsigned int dev); +extern void floppy_off(unsigned int dev); +extern void truncate(struct m_inode * inode); +extern void sync_inodes(void); +extern void wait_on(struct m_inode * inode); +extern int bmap(struct m_inode * inode,int block); +extern int create_block(struct m_inode * inode,int block); +extern struct m_inode * namei(const char * pathname); +extern int open_namei(const char * pathname, int flag, int mode, + struct m_inode ** res_inode); +extern void iput(struct m_inode * inode); +extern struct m_inode * iget(int dev,int nr); +extern struct m_inode * get_empty_inode(void); +extern struct m_inode * get_pipe_inode(void); +extern struct buffer_head * get_hash_table(int dev, int block); +extern struct buffer_head * getblk(int dev, int block); +extern void ll_rw_block(int rw, struct buffer_head * bh); +extern void brelse(struct buffer_head * buf); +extern struct buffer_head * bread(int dev,int block); +extern void bread_page(unsigned long addr,int dev,int b[4]); +extern struct buffer_head * breada(int dev,int block,...); +extern int new_block(int dev); +extern void free_block(int dev, int block); +extern struct m_inode * new_inode(int dev); +extern void free_inode(struct m_inode * inode); +extern int sync_dev(int dev); +extern struct super_block * get_super(int dev); +extern int ROOT_DEV; + +extern void mount_root(void); + +#endif diff --git a/linux/include/linux/hdreg.h b/linux/include/linux/hdreg.h new file mode 100644 index 0000000..e6c593f --- /dev/null +++ b/linux/include/linux/hdreg.h @@ -0,0 +1,65 @@ +/* + * This file contains some defines for the AT-hd-controller. + * Various sources. Check out some definitions (see comments with + * a ques). + */ +#ifndef _HDREG_H +#define _HDREG_H + +/* Hd controller regs. Ref: IBM AT Bios-listing */ +#define HD_DATA 0x1f0 /* _CTL when writing */ +#define HD_ERROR 0x1f1 /* see err-bits */ +#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */ +#define HD_SECTOR 0x1f3 /* starting sector */ +#define HD_LCYL 0x1f4 /* starting cylinder */ +#define HD_HCYL 0x1f5 /* high byte of starting cyl */ +#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */ +#define HD_STATUS 0x1f7 /* see status-bits */ +#define HD_PRECOMP HD_ERROR /* same io address, read=error, write=precomp */ +#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */ + +#define HD_CMD 0x3f6 + +/* Bits of HD_STATUS */ +#define ERR_STAT 0x01 +#define INDEX_STAT 0x02 +#define ECC_STAT 0x04 /* Corrected error */ +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Values for HD_COMMAND */ +#define WIN_RESTORE 0x10 +#define WIN_READ 0x20 +#define WIN_WRITE 0x30 +#define WIN_VERIFY 0x40 +#define WIN_FORMAT 0x50 +#define WIN_INIT 0x60 +#define WIN_SEEK 0x70 +#define WIN_DIAGNOSE 0x90 +#define WIN_SPECIFY 0x91 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark ? */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* ? */ +#define ID_ERR 0x10 /* ? */ +#define ECC_ERR 0x40 /* ? */ +#define BBD_ERR 0x80 /* ? */ + +struct partition { + unsigned char boot_ind; /* 0x80 - active (unused) */ + unsigned char head; /* ? */ + unsigned char sector; /* ? */ + unsigned char cyl; /* ? */ + unsigned char sys_ind; /* ? */ + unsigned char end_head; /* ? */ + unsigned char end_sector; /* ? */ + unsigned char end_cyl; /* ? */ + unsigned int start_sect; /* starting sector counting from 0 */ + unsigned int nr_sects; /* nr of sectors in partition */ +}; + +#endif diff --git a/linux/include/linux/head.h b/linux/include/linux/head.h new file mode 100644 index 0000000..db3dda2 --- /dev/null +++ b/linux/include/linux/head.h @@ -0,0 +1,20 @@ +#ifndef _HEAD_H +#define _HEAD_H + +typedef struct desc_struct { + unsigned long a,b; +} desc_table[256]; + +extern unsigned long pg_dir[1024]; +extern desc_table idt,gdt; + +#define GDT_NUL 0 +#define GDT_CODE 1 +#define GDT_DATA 2 +#define GDT_TMP 3 + +#define LDT_NUL 0 +#define LDT_CODE 1 +#define LDT_DATA 2 + +#endif diff --git a/linux/include/linux/kernel.h b/linux/include/linux/kernel.h new file mode 100644 index 0000000..cb40dd5 --- /dev/null +++ b/linux/include/linux/kernel.h @@ -0,0 +1,22 @@ +/* + * 'kernel.h' contains some often-used function prototypes etc + */ +void verify_area(void * addr,int count); +volatile void panic(const char * str); +int printf(const char * fmt, ...); +int printk(const char * fmt, ...); +int tty_write(unsigned ch,char * buf,int count); +void * malloc(unsigned int size); +void free_s(void * obj, int size); + +#define free(x) free_s((x), 0) + +/* + * This is defined as a macro, but at some point this might become a + * real subroutine that sets a flag if it returns true (to do + * BSD-style accounting where the process is flagged if it uses root + * privs). The implication of this is that you should do normal + * permissions checks first, and check suser() last. + */ +#define suser() (current->euid == 0) + diff --git a/linux/include/linux/mm.h b/linux/include/linux/mm.h new file mode 100644 index 0000000..5a160f3 --- /dev/null +++ b/linux/include/linux/mm.h @@ -0,0 +1,10 @@ +#ifndef _MM_H +#define _MM_H + +#define PAGE_SIZE 4096 + +extern unsigned long get_free_page(void); +extern unsigned long put_page(unsigned long page,unsigned long address); +extern void free_page(unsigned long addr); + +#endif diff --git a/linux/include/linux/sched.h b/linux/include/linux/sched.h new file mode 100644 index 0000000..772646a --- /dev/null +++ b/linux/include/linux/sched.h @@ -0,0 +1,239 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#define NR_TASKS 64 +#define HZ 100 + +#define FIRST_TASK task[0] +#define LAST_TASK task[NR_TASKS-1] + +#include +#include +#include +#include + +#if (NR_OPEN > 32) +#error "Currently the close-on-exec-flags are in one word, max 32 files/proc" +#endif + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_ZOMBIE 3 +#define TASK_STOPPED 4 + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +extern int copy_page_tables(unsigned long from, unsigned long to, long size); +extern int free_page_tables(unsigned long from, unsigned long size); + +extern void sched_init(void); +extern void schedule(void); +extern void trap_init(void); +extern void panic(const char * str); +extern int tty_write(unsigned minor,char * buf,int count); + +typedef int (*fn_ptr)(); + +struct i387_struct { + long cwd; + long swd; + long twd; + long fip; + long fcs; + long foo; + long fos; + long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ +}; + +struct tss_struct { + long back_link; /* 16 high bits zero */ + long esp0; + long ss0; /* 16 high bits zero */ + long esp1; + long ss1; /* 16 high bits zero */ + long esp2; + long ss2; /* 16 high bits zero */ + long cr3; + long eip; + long eflags; + long eax,ecx,edx,ebx; + long esp; + long ebp; + long esi; + long edi; + long es; /* 16 high bits zero */ + long cs; /* 16 high bits zero */ + long ss; /* 16 high bits zero */ + long ds; /* 16 high bits zero */ + long fs; /* 16 high bits zero */ + long gs; /* 16 high bits zero */ + long ldt; /* 16 high bits zero */ + long trace_bitmap; /* bits: trace 0, bitmap 16-31 */ + struct i387_struct i387; +}; + +struct task_struct { +/* these are hardcoded - don't touch */ + long state; /* -1 unrunnable, 0 runnable, >0 stopped */ + long counter; + long priority; + long signal; + struct sigaction sigaction[32]; + long blocked; /* bitmap of masked signals */ +/* various fields */ + int exit_code; + unsigned long start_code,end_code,end_data,brk,start_stack; + long pid,father,pgrp,session,leader; + unsigned short uid,euid,suid; + unsigned short gid,egid,sgid; + long alarm; + long utime,stime,cutime,cstime,start_time; + unsigned short used_math; +/* file system info */ + int tty; /* -1 if no tty, so it must be signed */ + unsigned short umask; + struct m_inode * pwd; + struct m_inode * root; + struct m_inode * executable; + unsigned long close_on_exec; + struct file * filp[NR_OPEN]; +/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */ + struct desc_struct ldt[3]; +/* tss for this task */ + struct tss_struct tss; +}; + +/* + * INIT_TASK is used to set up the first task table, touch at + * your own risk!. Base=0, limit=0x9ffff (=640kB) + */ +#define INIT_TASK \ +/* state etc */ { 0,15,15, \ +/* signals */ 0,{{},},0, \ +/* ec,brk... */ 0,0,0,0,0,0, \ +/* pid etc.. */ 0,-1,0,0,0, \ +/* uid etc */ 0,0,0,0,0,0, \ +/* alarm */ 0,0,0,0,0,0, \ +/* math */ 0, \ +/* fs info */ -1,0022,NULL,NULL,NULL,0, \ +/* filp */ {NULL,}, \ + { \ + {0,0}, \ +/* ldt */ {0x9f,0xc0fa00}, \ + {0x9f,0xc0f200}, \ + }, \ +/*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\ + 0,0,0,0,0,0,0,0, \ + 0,0,0x17,0x17,0x17,0x17,0x17,0x17, \ + _LDT(0),0x80000000, \ + {} \ + }, \ +} + +extern struct task_struct *task[NR_TASKS]; +extern struct task_struct *last_task_used_math; +extern struct task_struct *current; +extern long volatile jiffies; +extern long startup_time; + +#define CURRENT_TIME (startup_time+jiffies/HZ) + +extern void add_timer(long jiffies, void (*fn)(void)); +extern void sleep_on(struct task_struct ** p); +extern void interruptible_sleep_on(struct task_struct ** p); +extern void wake_up(struct task_struct ** p); + +/* + * Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall + * 4-TSS0, 5-LDT0, 6-TSS1 etc ... + */ +#define FIRST_TSS_ENTRY 4 +#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1) +#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3)) +#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3)) +#define ltr(n) __asm__("ltr %%ax"::"a" (_TSS(n))) +#define lldt(n) __asm__("lldt %%ax"::"a" (_LDT(n))) +#define str(n) \ +__asm__("str %%ax\n\t" \ + "subl %2,%%eax\n\t" \ + "shrl $4,%%eax" \ + :"=a" (n) \ + :"a" (0),"i" (FIRST_TSS_ENTRY<<3)) +/* + * switch_to(n) should switch tasks to task nr n, first + * checking that n isn't the current task, in which case it does nothing. + * This also clears the TS-flag if the task we switched to has used + * tha math co-processor latest. + */ +#define switch_to(n) {\ +struct {long a,b;} __tmp; \ +__asm__("cmpl %%ecx,current\n\t" \ + "je 1f\n\t" \ + "movw %%dx,%1\n\t" \ + "xchgl %%ecx,current\n\t" \ + "ljmp *%0\n\t" \ + "cmpl %%ecx,last_task_used_math\n\t" \ + "jne 1f\n\t" \ + "clts\n" \ + "1:" \ + ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ + "d" (_TSS(n)),"c" ((long) task[n])); \ +} + +#define PAGE_ALIGN(n) (((n)+0xfff)&0xfffff000) + +#define _set_base(addr,base) \ +__asm__ ("push %%edx\n\t" \ + "movw %%dx,%0\n\t" \ + "rorl $16,%%edx\n\t" \ + "movb %%dl,%1\n\t" \ + "movb %%dh,%2\n\t" \ + "pop %%edx" \ + ::"m" (*((addr)+2)), \ + "m" (*((addr)+4)), \ + "m" (*((addr)+7)), \ + "d" (base) \ + ) + +#define _set_limit(addr,limit) \ +__asm__ ("push %%edx\n\t" \ + "movw %%dx,%0\n\t" \ + "rorl $16,%%edx\n\t" \ + "movb %1,%%dh\n\t" \ + "andb $0xf0,%%dh\n\t" \ + "orb %%dh,%%dl\n\t" \ + "movb %%dl,%1\n\t" \ + "pop %%edx" \ + ::"m" (*(addr)), \ + "m" (*((addr)+6)), \ + "d" (limit) \ + ) + +#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) ) +#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 ) + +static inline unsigned long _get_base(char * addr) +{ + unsigned long __base; + __asm__("movb %3,%%dh\n\t" + "movb %2,%%dl\n\t" + "shll $16,%%edx\n\t" + "movw %1,%%dx" + :"=&d" (__base) + :"m" (*((addr)+2)), + "m" (*((addr)+4)), + "m" (*((addr)+7))); + return __base; +} + +#define get_base(ldt) _get_base( ((char *)&(ldt)) ) + +#define get_limit(segment) ({ \ +unsigned long __limit; \ +__asm__("lsll %1,%0\n\tincl %0":"=r" (__limit):"r" (segment)); \ +__limit;}) + +#endif diff --git a/linux/include/linux/sys.h b/linux/include/linux/sys.h new file mode 100644 index 0000000..4fd4be1 --- /dev/null +++ b/linux/include/linux/sys.h @@ -0,0 +1,116 @@ +/* + * Why isn't this a .c file? Enquiring minds.... + */ + +extern int sys_setup(); +extern int sys_exit(); +extern int sys_fork(); +extern int sys_read(); +extern int sys_write(); +extern int sys_open(); +extern int sys_close(); +extern int sys_waitpid(); +extern int sys_creat(); +extern int sys_link(); +extern int sys_unlink(); +extern int sys_execve(); +extern int sys_chdir(); +extern int sys_time(); +extern int sys_mknod(); +extern int sys_chmod(); +extern int sys_chown(); +extern int sys_break(); +extern int sys_stat(); +extern int sys_lseek(); +extern int sys_getpid(); +extern int sys_mount(); +extern int sys_umount(); +extern int sys_setuid(); +extern int sys_getuid(); +extern int sys_stime(); +extern int sys_ptrace(); +extern int sys_alarm(); +extern int sys_fstat(); +extern int sys_pause(); +extern int sys_utime(); +extern int sys_stty(); +extern int sys_gtty(); +extern int sys_access(); +extern int sys_nice(); +extern int sys_ftime(); +extern int sys_sync(); +extern int sys_kill(); +extern int sys_rename(); +extern int sys_mkdir(); +extern int sys_rmdir(); +extern int sys_dup(); +extern int sys_pipe(); +extern int sys_times(); +extern int sys_prof(); +extern int sys_brk(); +extern int sys_setgid(); +extern int sys_getgid(); +extern int sys_signal(); +extern int sys_geteuid(); +extern int sys_getegid(); +extern int sys_acct(); +extern int sys_phys(); +extern int sys_lock(); +extern int sys_ioctl(); +extern int sys_fcntl(); +extern int sys_mpx(); +extern int sys_setpgid(); +extern int sys_ulimit(); +extern int sys_uname(); +extern int sys_umask(); +extern int sys_chroot(); +extern int sys_ustat(); +extern int sys_dup2(); +extern int sys_getppid(); +extern int sys_getpgrp(); +extern int sys_setsid(); +extern int sys_sigaction(); +extern int sys_sgetmask(); +extern int sys_ssetmask(); +extern int sys_setreuid(); +extern int sys_setregid(); +extern int sys_sigpending(); +extern int sys_sigsuspend(); +extern int sys_sethostname(); +extern int sys_setrlimit(); +extern int sys_getrlimit(); +extern int sys_getrusage(); +extern int sys_gettimeofday(); +extern int sys_settimeofday(); +extern int sys_getgroups(); +extern int sys_setgroups(); +extern int sys_select(); +extern int sys_symlink(); +extern int sys_lstat(); +extern int sys_readlink(); +extern int sys_uselib(); +extern int sys_execve2(); +extern int sys_getdents(); +extern int sys_pipe2(); +extern int sys_sleep(); + +fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read, +sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link, +sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod, +sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount, +sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm, +sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access, +sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir, +sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid, +sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys, +sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit, +sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid, +sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask, +sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_sethostname, +sys_setrlimit, sys_getrlimit, sys_getrusage, sys_gettimeofday, +sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink, +sys_lstat, sys_readlink, sys_uselib, sys_execve2, sys_getdents, sys_pipe2, +sys_sleep}; + +/* So we don't have to do any more manual updating.... */ +int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); diff --git a/linux/include/linux/tty.h b/linux/include/linux/tty.h new file mode 100644 index 0000000..ad846b3 --- /dev/null +++ b/linux/include/linux/tty.h @@ -0,0 +1,77 @@ +/* + * 'tty.h' defines some structures used by tty_io.c and some defines. + * + * NOTE! Don't touch this without checking that nothing in rs_io.s or + * con_io.s breaks. Some constants are hardwired into the system (mainly + * offsets into 'tty_queue' + */ + +#ifndef _TTY_H +#define _TTY_H + +#include + +#define TTY_BUF_SIZE 1024 + +struct tty_queue { + unsigned long data; + unsigned long head; + unsigned long tail; + struct task_struct * proc_list; + char buf[TTY_BUF_SIZE]; +}; + +#define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1)) +#define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1)) +#define EMPTY(a) ((a).head == (a).tail) +#define LEFT(a) (((a).tail-(a).head-1)&(TTY_BUF_SIZE-1)) +#define LAST(a) ((a).buf[(TTY_BUF_SIZE-1)&((a).head-1)]) +#define FULL(a) (!LEFT(a)) +#define CHARS(a) (((a).head-(a).tail)&(TTY_BUF_SIZE-1)) +#define GETCH(queue,c) \ +(void)({c=(queue).buf[(queue).tail];INC((queue).tail);}) +#define PUTCH(c,queue) \ +(void)({(queue).buf[(queue).head]=(c);INC((queue).head);}) + +#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR]) +#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT]) +#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE]) +#define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL]) +#define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF]) +#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART]) +#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP]) +#define SUSPEND_CHAR(tty) ((tty)->termios.c_cc[VSUSP]) + +struct tty_struct { + struct termios termios; + int pgrp; + int stopped; + void (*write)(struct tty_struct * tty); + struct tty_queue read_q; + struct tty_queue write_q; + struct tty_queue secondary; + }; + +extern struct tty_struct tty_table[]; + +/* intr=^C quit=^| erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" + +void rs_init(void); +void con_init(void); +void tty_init(void); + +int tty_read(unsigned c, char * buf, int n); +int tty_write(unsigned c, char * buf, int n); + +void rs_write(struct tty_struct * tty); +void con_write(struct tty_struct * tty); + +void copy_to_cooked(struct tty_struct * tty); + +#endif diff --git a/linux/include/signal.h b/linux/include/signal.h new file mode 100644 index 0000000..0eea9a3 --- /dev/null +++ b/linux/include/signal.h @@ -0,0 +1,68 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include + +typedef int sig_atomic_t; +typedef unsigned int sigset_t; /* 32 bits */ + +#define _NSIG 32 +#define NSIG _NSIG + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGUNUSED 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 + +/* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */ +#define SA_NOCLDSTOP 1 +#define SA_NOMASK 0x40000000 +#define SA_ONESHOT 0x80000000 + +#define SIG_BLOCK 0 /* for blocking signals */ +#define SIG_UNBLOCK 1 /* for unblocking signals */ +#define SIG_SETMASK 2 /* for setting the signal mask */ + +#define SIG_DFL ((void (*)(int))0) /* default signal handling */ +#define SIG_IGN ((void (*)(int))1) /* ignore signal */ + +struct sigaction { + void (*sa_handler)(int); + sigset_t sa_mask; + int sa_flags; + void (*sa_restorer)(void); +}; + +void (*signal(int _sig, void (*_func)(int)))(int); +int raise(int sig); +int kill(pid_t pid, int sig); +int sigaddset(sigset_t *mask, int signo); +int sigdelset(sigset_t *mask, int signo); +int sigemptyset(sigset_t *mask); +int sigfillset(sigset_t *mask); +int sigismember(sigset_t *mask, int signo); /* 1 - is, 0 - not, -1 error */ +int sigpending(sigset_t *set); +int sigprocmask(int how, sigset_t *set, sigset_t *oldset); +int sigsuspend(sigset_t *sigmask); +int sigaction(int sig, struct sigaction *act, struct sigaction *oldact); + +#endif /* _SIGNAL_H */ diff --git a/linux/include/stdarg.h b/linux/include/stdarg.h new file mode 100644 index 0000000..fd79ec0 --- /dev/null +++ b/linux/include/stdarg.h @@ -0,0 +1,28 @@ +#ifndef _STDARG_H +#define _STDARG_H + +typedef char *va_list; + +/* Amount of space required in an argument list for an arg of type TYPE. + TYPE may alternatively be an expression whose type is used. */ + +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) + +#ifndef __sparc__ +#define va_start(AP, LASTARG) \ + (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG))) +#else +#define va_start(AP, LASTARG) \ + (__builtin_saveregs (), \ + AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG))) +#endif + +void va_end (va_list); /* Defined in gnulib */ +#define va_end(AP) + +#define va_arg(AP, TYPE) \ + (AP += __va_rounded_size (TYPE), \ + *((TYPE *) (AP - __va_rounded_size (TYPE)))) + +#endif /* _STDARG_H */ diff --git a/linux/include/stddef.h b/linux/include/stddef.h new file mode 100644 index 0000000..97f72ff --- /dev/null +++ b/linux/include/stddef.h @@ -0,0 +1,19 @@ +#ifndef _STDDEF_H +#define _STDDEF_H + +#ifndef _PTRDIFF_T +#define _PTRDIFF_T +typedef long ptrdiff_t; +#endif + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned long size_t; +#endif + +#undef NULL +#define NULL ((void *)0) + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#endif diff --git a/linux/include/string.h b/linux/include/string.h new file mode 100644 index 0000000..48b91e5 --- /dev/null +++ b/linux/include/string.h @@ -0,0 +1,405 @@ +#ifndef _STRING_H_ +#define _STRING_H_ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned int size_t; +#endif + +extern char * strerror(int errno); + +/* + * This string-include defines all string functions as inline + * functions. Use gcc. It also assumes ds=es=data space, this should be + * normal. Most of the string-functions are rather heavily hand-optimized, + * see especially strtok,strstr,str[c]spn. They should work, but are not + * very easy to understand. Everything is done entirely within the register + * set, making the functions fast and clean. String instructions have been + * used through-out, making for "slightly" unclear code :-) + * + * (C) 1991 Linus Torvalds + */ + +extern inline char * strcpy(char * dest,const char *src) +{ +__asm__("cld\n" + "1:\tlodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b" + ::"S" (src),"D" (dest)); +return dest; +} + +extern inline char * strncpy(char * dest,const char *src,int count) +{ +__asm__("cld\n" + "1:\tdecl %2\n\t" + "js 2f\n\t" + "lodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "rep\n\t" + "stosb\n" + "2:" + ::"S" (src),"D" (dest),"c" (count)); +return dest; +} + +extern inline char * strcat(char * dest,const char * src) +{ +__asm__("cld\n\t" + "repne\n\t" + "scasb\n\t" + "decl %1\n" + "1:\tlodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b" + ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff)); +return dest; +} + +extern inline char * strncat(char * dest,const char * src,int count) +{ +__asm__("cld\n\t" + "repne\n\t" + "scasb\n\t" + "decl %1\n\t" + "movl %4,%3\n" + "1:\tdecl %3\n\t" + "js 2f\n\t" + "lodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n" + "2:\txorl %2,%2\n\t" + "stosb" + ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count) + ); +return dest; +} + +extern inline int strcmp(const char * cs,const char * ct) +{ +register int __res __asm__("ax"); +__asm__("cld\n" + "1:\tlodsb\n\t" + "scasb\n\t" + "jne 2f\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "xorl %%eax,%%eax\n\t" + "jmp 3f\n" + "2:\tmovl $1,%%eax\n\t" + "jl 3f\n\t" + "negl %%eax\n" + "3:" + :"=a" (__res):"D" (cs),"S" (ct)); +return __res; +} + +extern inline int strncmp(const char * cs,const char * ct,int count) +{ +register int __res __asm__("ax"); +__asm__("cld\n" + "1:\tdecl %3\n\t" + "js 2f\n\t" + "lodsb\n\t" + "scasb\n\t" + "jne 3f\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n" + "2:\txorl %%eax,%%eax\n\t" + "jmp 4f\n" + "3:\tmovl $1,%%eax\n\t" + "jl 4f\n\t" + "negl %%eax\n" + "4:" + :"=a" (__res):"D" (cs),"S" (ct),"c" (count)); +return __res; +} + +extern inline char * strchr(const char * s,char c) +{ +register char * __res __asm__("ax"); +__asm__("cld\n\t" + "movb %%al,%%ah\n" + "1:\tlodsb\n\t" + "cmpb %%ah,%%al\n\t" + "je 2f\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "movl $1,%1\n" + "2:\tmovl %1,%0\n\t" + "decl %0" + :"=a" (__res):"S" (s),"0" (c)); +return __res; +} + +extern inline char * strrchr(const char * s,char c) +{ +register char * __res __asm__("dx"); +__asm__("cld\n\t" + "movb %%al,%%ah\n" + "1:\tlodsb\n\t" + "cmpb %%ah,%%al\n\t" + "jne 2f\n\t" + "movl %%esi,%0\n\t" + "decl %0\n" + "2:\ttestb %%al,%%al\n\t" + "jne 1b" + :"=d" (__res):"0" (0),"S" (s),"a" (c)); +return __res; +} + +extern inline int strspn(const char * cs, const char * ct) +{ +register char * __res __asm__("si"); +__asm__("cld\n\t" + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" + "movl %%ecx,%%edx\n" + "1:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 2f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "je 1b\n" + "2:\tdecl %0" + :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct) + ); +return __res-cs; +} + +extern inline int strcspn(const char * cs, const char * ct) +{ +register char * __res __asm__("si"); +__asm__("cld\n\t" + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" + "movl %%ecx,%%edx\n" + "1:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 2f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "jne 1b\n" + "2:\tdecl %0" + :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct) + ); +return __res-cs; +} + +extern inline char * strpbrk(const char * cs,const char * ct) +{ +register char * __res __asm__("si"); +__asm__("cld\n\t" + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" + "movl %%ecx,%%edx\n" + "1:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 2f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "jne 1b\n\t" + "decl %0\n\t" + "jmp 3f\n" + "2:\txorl %0,%0\n" + "3:" + :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct) + ); +return __res; +} + +extern inline char * strstr(const char * cs,const char * ct) +{ +register char * __res __asm__("ax"); +__asm__("cld\n\t" \ + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */ + "movl %%ecx,%%edx\n" + "1:\tmovl %4,%%edi\n\t" + "movl %%esi,%%eax\n\t" + "movl %%edx,%%ecx\n\t" + "repe\n\t" + "cmpsb\n\t" + "je 2f\n\t" /* also works for empty string, see above */ + "xchgl %%eax,%%esi\n\t" + "incl %%esi\n\t" + "cmpb $0,-1(%%eax)\n\t" + "jne 1b\n\t" + "xorl %%eax,%%eax\n\t" + "2:" + :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct) + ); +return __res; +} + +extern inline int strlen(const char * s) +{ +register int __res ; +__asm__("cld\n\t" + "repne\n\t" + "scasb\n\t" + "notl %0\n\t" + "decl %0" + :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff)); +return __res; +} + +extern char * ___strtok; + +extern inline char * strtok(char * s,const char * ct) +{ +register char * __res __asm__("si"); +__asm__("testl %1,%1\n\t" + "jne 1f\n\t" + "testl %0,%0\n\t" + "je 8f\n\t" + "movl %0,%1\n" + "1:\txorl %0,%0\n\t" + "movl $-1,%%ecx\n\t" + "xorl %%eax,%%eax\n\t" + "cld\n\t" + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" + "je 7f\n\t" /* empty delimeter-string */ + "movl %%ecx,%%edx\n" + "2:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 7f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "je 2b\n\t" + "decl %1\n\t" + "cmpb $0,(%1)\n\t" + "je 7f\n\t" + "movl %1,%0\n" + "3:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 5f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "jne 3b\n\t" + "decl %1\n\t" + "cmpb $0,(%1)\n\t" + "je 5f\n\t" + "movb $0,(%1)\n\t" + "incl %1\n\t" + "jmp 6f\n" + "5:\txorl %1,%1\n" + "6:\tcmpb $0,(%0)\n\t" + "jne 7f\n\t" + "xorl %0,%0\n" + "7:\ttestl %0,%0\n\t" + "jne 8f\n\t" + "movl %0,%1\n" + "8:" + :"=b" (__res),"=S" (___strtok) + :"0" (___strtok),"1" (s),"g" (ct) + ); +return __res; +} + +extern inline void * memcpy(void * dest,const void * src, int n) +{ +__asm__("cld\n\t" + "rep\n\t" + "movsb" + ::"c" (n),"S" (src),"D" (dest) + ); +return dest; +} + +extern inline void * memmove(void * dest,const void * src, int n) +{ +if (dest + +struct stat { + dev_t st_dev; + ino_t st_ino; + umode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +}; + +#define S_IFMT 00170000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +extern int chmod(const char *_path, mode_t mode); +extern int fstat(int fildes, struct stat *stat_buf); +extern int mkdir(const char *_path, mode_t mode); +extern int mkfifo(const char *_path, mode_t mode); +extern int stat(const char *filename, struct stat *stat_buf); +extern mode_t umask(mode_t mask); + +#endif diff --git a/linux/include/sys/times.h b/linux/include/sys/times.h new file mode 100644 index 0000000..68d5bfb --- /dev/null +++ b/linux/include/sys/times.h @@ -0,0 +1,15 @@ +#ifndef _TIMES_H +#define _TIMES_H + +#include + +struct tms { + time_t tms_utime; + time_t tms_stime; + time_t tms_cutime; + time_t tms_cstime; +}; + +extern time_t times(struct tms * tp); + +#endif diff --git a/linux/include/sys/types.h b/linux/include/sys/types.h new file mode 100644 index 0000000..557aa31 --- /dev/null +++ b/linux/include/sys/types.h @@ -0,0 +1,46 @@ +#ifndef _SYS_TYPES_H +#define _SYS_TYPES_H + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned int size_t; +#endif + +#ifndef _TIME_T +#define _TIME_T +typedef long time_t; +#endif + +#ifndef _PTRDIFF_T +#define _PTRDIFF_T +typedef long ptrdiff_t; +#endif + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +typedef int pid_t; +typedef unsigned short uid_t; +typedef unsigned char gid_t; +typedef unsigned short dev_t; +typedef unsigned short ino_t; +typedef unsigned short mode_t; +typedef unsigned short umode_t; +typedef unsigned char nlink_t; +typedef int daddr_t; +typedef long off_t; +typedef unsigned char u_char; +typedef unsigned short ushort; + +typedef struct { int quot,rem; } div_t; +typedef struct { long quot,rem; } ldiv_t; + +struct ustat { + daddr_t f_tfree; + ino_t f_tinode; + char f_fname[6]; + char f_fpack[6]; +}; + +#endif diff --git a/linux/include/sys/utsname.h b/linux/include/sys/utsname.h new file mode 100644 index 0000000..0a1c5a0 --- /dev/null +++ b/linux/include/sys/utsname.h @@ -0,0 +1,16 @@ +#ifndef _SYS_UTSNAME_H +#define _SYS_UTSNAME_H + +#include + +struct utsname { + char sysname[9]; + char nodename[9]; + char release[9]; + char version[9]; + char machine[9]; +}; + +extern int uname(struct utsname * utsbuf); + +#endif diff --git a/linux/include/sys/wait.h b/linux/include/sys/wait.h new file mode 100644 index 0000000..53190c2 --- /dev/null +++ b/linux/include/sys/wait.h @@ -0,0 +1,23 @@ +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include + +#define _LOW(v) ( (v) & 0377) +#define _HIGH(v) ( ((v) >> 8) & 0377) + +/* options for waitpid, WUNTRACED not supported */ +#define WNOHANG 1 +#define WUNTRACED 2 + +#define WIFEXITED(s) (!((s)&0xFF) +#define WIFSTOPPED(s) (((s)&0xFF)==0x7F) +#define WEXITSTATUS(s) (((s)>>8)&0xFF) +#define WTERMSIG(s) ((s)&0x7F) +#define WSTOPSIG(s) (((s)>>8)&0xFF) +#define WIFSIGNALED(s) (((unsigned int)(s)-1 & 0xFFFF) < 0xFF) + +pid_t wait(int *stat_loc); +pid_t waitpid(pid_t pid, int *stat_loc, int options); + +#endif diff --git a/linux/include/termios.h b/linux/include/termios.h new file mode 100644 index 0000000..2b7b913 --- /dev/null +++ b/linux/include/termios.h @@ -0,0 +1,228 @@ +#ifndef _TERMIOS_H +#define _TERMIOS_H + +#define TTY_BUF_SIZE 1024 + +/* 0x54 is just a magic number to make these relatively uniqe ('T') */ + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define TIOCINQ 0x541B + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +#define NCCS 17 +struct termios { + unsigned long c_iflag; /* input mode flags */ + unsigned long c_oflag; /* output mode flags */ + unsigned long c_cflag; /* control mode flags */ + unsigned long c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0040000 +#define FF0 0000000 +#define FF1 0040000 + +/* c_cflag bit meaning */ +#define CBAUD 0000017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define CPARENB 0000400 +#define CPARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 +#define CIBAUD 03600000 /* input baud rate (not used) */ +#define CRTSCTS 020000000000 /* flow control */ + +#define PARENB CPARENB +#define PARODD CPARODD + +/* c_lflag bits */ +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +typedef int speed_t; + +extern speed_t cfgetispeed(struct termios *termios_p); +extern speed_t cfgetospeed(struct termios *termios_p); +extern int cfsetispeed(struct termios *termios_p, speed_t speed); +extern int cfsetospeed(struct termios *termios_p, speed_t speed); +extern int tcdrain(int fildes); +extern int tcflow(int fildes, int action); +extern int tcflush(int fildes, int queue_selector); +extern int tcgetattr(int fildes, struct termios *termios_p); +extern int tcsendbreak(int fildes, int duration); +extern int tcsetattr(int fildes, int optional_actions, + struct termios *termios_p); + +#endif diff --git a/linux/include/time.h b/linux/include/time.h new file mode 100644 index 0000000..d0a765d --- /dev/null +++ b/linux/include/time.h @@ -0,0 +1,42 @@ +#ifndef _TIME_H +#define _TIME_H + +#ifndef _TIME_T +#define _TIME_T +typedef long time_t; +#endif + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned int size_t; +#endif + +#define CLOCKS_PER_SEC 100 + +typedef long clock_t; + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +clock_t clock(void); +time_t time(time_t * tp); +double difftime(time_t time2, time_t time1); +time_t mktime(struct tm * tp); + +char * asctime(const struct tm * tp); +char * ctime(const time_t * tp); +struct tm * gmtime(const time_t *tp); +struct tm *localtime(const time_t * tp); +size_t strftime(char * s, size_t smax, const char * fmt, const struct tm * tp); +void tzset(void); + +#endif diff --git a/linux/include/unistd.h b/linux/include/unistd.h new file mode 100644 index 0000000..a09d1d5 --- /dev/null +++ b/linux/include/unistd.h @@ -0,0 +1,282 @@ +#ifndef _UNISTD_H +#define _UNISTD_H + +/* ok, this may be a joke, but I'm working on it */ +#define _POSIX_VERSION 198808L + +#define _POSIX_CHOWN_RESTRICTED /* only root can do a chown (I think..) */ +#define _POSIX_NO_TRUNC /* no pathname truncation (but see in kernel) */ +#define _POSIX_VDISABLE '\0' /* character to disable things like ^C */ +/*#define _POSIX_SAVED_IDS */ /* we'll get to this yet */ +/*#define _POSIX_JOB_CONTROL */ /* we aren't there quite yet. Soon hopefully */ + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#ifndef NULL +#define NULL ((void *)0) +#endif + +/* access */ +#define F_OK 0 +#define X_OK 1 +#define W_OK 2 +#define R_OK 4 + +/* lseek */ +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +/* _SC stands for System Configuration. We don't use them much */ +#define _SC_ARG_MAX 1 +#define _SC_CHILD_MAX 2 +#define _SC_CLOCKS_PER_SEC 3 +#define _SC_NGROUPS_MAX 4 +#define _SC_OPEN_MAX 5 +#define _SC_JOB_CONTROL 6 +#define _SC_SAVED_IDS 7 +#define _SC_VERSION 8 + +/* more (possibly) configurable things - now pathnames */ +#define _PC_LINK_MAX 1 +#define _PC_MAX_CANON 2 +#define _PC_MAX_INPUT 3 +#define _PC_NAME_MAX 4 +#define _PC_PATH_MAX 5 +#define _PC_PIPE_BUF 6 +#define _PC_NO_TRUNC 7 +#define _PC_VDISABLE 8 +#define _PC_CHOWN_RESTRICTED 9 + +#include +#include +#include +#include + +#ifdef __LIBRARY__ + +#define __NR_setup 0 /* used only by init, to get system going */ +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_stat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_fstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_phys 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_uname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_lstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 + +#define __NR_execve2 87 +#define __NR_getdents 88 +#define __NR_pipe2 89 +#define __NR_sleep 90 +#define __NR_getcwd 91 +#define __NR_mmap 92 +#define __NR_munmap 93 +#define __NR_clone 94 + +#define _syscall0(type,name) \ +type name(void) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name)); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall1(type,name,atype,a) \ +type name(atype a) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a))); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall2(type,name,atype,a,btype,b) \ +type name(atype a,btype b) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b))); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall3(type,name,atype,a,btype,b,ctype,c) \ +type name(atype a,btype b,ctype c) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \ +if (__res>=0) \ + return (type) __res; \ +errno=-__res; \ +return -1; \ +} + +#endif /* __LIBRARY__ */ + +extern int errno; + +int access(const char * filename, mode_t mode); +int acct(const char * filename); +int alarm(int sec); +int brk(void * end_data_segment); +void * sbrk(ptrdiff_t increment); +int chdir(const char * filename); +int chmod(const char * filename, mode_t mode); +int chown(const char * filename, uid_t owner, gid_t group); +int chroot(const char * filename); +int close(int fildes); +int creat(const char * filename, mode_t mode); +int dup(int fildes); +int execve(const char * filename, char ** argv, char ** envp); +int execv(const char * pathname, char ** argv); +int execvp(const char * file, char ** argv); +int execl(const char * pathname, char * arg0, ...); +int execlp(const char * file, char * arg0, ...); +int execle(const char * pathname, char * arg0, ...); +volatile void exit(int status); +volatile void _exit(int status); +int fcntl(int fildes, int cmd, ...); +int fork(void); +int getpid(void); +int getuid(void); +int geteuid(void); +int getgid(void); +int getegid(void); +int ioctl(int fildes, int cmd, ...); +int kill(pid_t pid, int signal); +int link(const char * filename1, const char * filename2); +int lseek(int fildes, off_t offset, int origin); +int mknod(const char * filename, mode_t mode, dev_t dev); +int mount(const char * specialfile, const char * dir, int rwflag); +int nice(int val); +int open(const char * filename, int flag, ...); +int pause(void); +int pipe(int * fildes); +int read(int fildes, char * buf, off_t count); +int setpgrp(void); +int setpgid(pid_t pid,pid_t pgid); +int setuid(uid_t uid); +int setgid(gid_t gid); +void (*signal(int sig, void (*fn)(int)))(int); +int stat(const char * filename, struct stat * stat_buf); +int fstat(int fildes, struct stat * stat_buf); +int stime(time_t * tptr); +int sync(void); +time_t time(time_t * tloc); +time_t times(struct tms * tbuf); +int ulimit(int cmd, long limit); +mode_t umask(mode_t mask); +int umount(const char * specialfile); +int uname(struct utsname * name); +int unlink(const char * filename); +int ustat(dev_t dev, struct ustat * ubuf); +int utime(const char * filename, struct utimbuf * times); +pid_t waitpid(pid_t pid,int * wait_stat,int options); +pid_t wait(int * wait_stat); +int write(int fildes, const char * buf, off_t count); +int dup2(int oldfd, int newfd); +int getppid(void); +pid_t getpgrp(void); +pid_t setsid(void); +int sleep(unsigned int seconds); +int execve2(const char * filename, char ** argv, char ** envp); +int getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count); +int pipe2(int fd[2], int flags); +#define __always_inline inline __attribute__((always_inline)) + +#endif diff --git a/linux/include/utime.h b/linux/include/utime.h new file mode 100644 index 0000000..83f07c7 --- /dev/null +++ b/linux/include/utime.h @@ -0,0 +1,13 @@ +#ifndef _UTIME_H +#define _UTIME_H + +#include /* I know - shouldn't do this, but .. */ + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +extern int utime(const char *filename, struct utimbuf *times); + +#endif diff --git a/linux/init/main.c b/linux/init/main.c new file mode 100644 index 0000000..0892fdc --- /dev/null +++ b/linux/init/main.c @@ -0,0 +1,210 @@ +/* + * linux/init/main.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ + +__always_inline _syscall0(int,fork) +__always_inline _syscall0(int,pause) +__always_inline _syscall1(int,setup,void *,BIOS) +__always_inline _syscall0(int,sync) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +static char printbuf[1024]; + +extern int vsprintf(); +extern void init(void); +extern void blk_dev_init(void); +extern void chr_dev_init(void); +extern void hd_init(void); +extern void floppy_init(void); +extern void mem_init(long start, long end); +extern long rd_init(long mem_start, int length); +extern long kernel_mktime(struct tm * tm); +extern long startup_time; + +/* + * This is set up by the setup-routine at boot-time + */ +#define EXT_MEM_K (*(unsigned short *)0x90002) +#define DRIVE_INFO (*(struct drive_info *)0x90080) +#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC) + +/* + * Yeah, yeah, it's ugly, but I cannot find how to do this correctly + * and this seems to work. I anybody has more info on the real-time + * clock I'd be interested. Most of this was trial and error, and some + * bios-listing reading. Urghh. + */ + +#define CMOS_READ(addr) ({ \ +outb_p(0x80|addr,0x70); \ +inb_p(0x71); \ +}) + +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) + +static void time_init(void) +{ + struct tm time; + + do { + time.tm_sec = CMOS_READ(0); + time.tm_min = CMOS_READ(2); + time.tm_hour = CMOS_READ(4); + time.tm_mday = CMOS_READ(7); + time.tm_mon = CMOS_READ(8); + time.tm_year = CMOS_READ(9); + } while (time.tm_sec != CMOS_READ(0)); + BCD_TO_BIN(time.tm_sec); + BCD_TO_BIN(time.tm_min); + BCD_TO_BIN(time.tm_hour); + BCD_TO_BIN(time.tm_mday); + BCD_TO_BIN(time.tm_mon); + BCD_TO_BIN(time.tm_year); + time.tm_mon--; + startup_time = kernel_mktime(&time); +} + +static long memory_end = 0; +static long buffer_memory_end = 0; +static long main_memory_start = 0; + +struct drive_info { char dummy[32]; } drive_info; + +void main(void) /* This really IS void, no error here. */ +{ /* The startup routine assumes (well, ...) this */ +/* + * Interrupts are still disabled. Do necessary setups, then + * enable them + */ + ROOT_DEV = ORIG_ROOT_DEV; + __asm__ volatile ("cld"); /* by wyj */ + drive_info = DRIVE_INFO; + memory_end = (1<<20) + (EXT_MEM_K<<10); + memory_end &= 0xfffff000; + if (memory_end > 16*1024*1024) + memory_end = 16*1024*1024; + if (memory_end > 12*1024*1024) + buffer_memory_end = 4*1024*1024; + else if (memory_end > 6*1024*1024) + buffer_memory_end = 2*1024*1024; + else + buffer_memory_end = 1*1024*1024; + main_memory_start = buffer_memory_end; +#ifdef RAMDISK + main_memory_start += rd_init(main_memory_start, RAMDISK*1024); +#endif + mem_init(main_memory_start,memory_end); + trap_init(); + blk_dev_init(); + chr_dev_init(); + tty_init(); + time_init(); + sched_init(); + buffer_init(buffer_memory_end); + hd_init(); + floppy_init(); + sti(); + move_to_user_mode(); + if (!fork()) { /* we count on this going ok */ + init(); + } +/* + * NOTE!! For any other task 'pause()' would mean we have to get a + * signal to awaken, but task0 is the sole exception (see 'schedule()') + * as task 0 gets activated at every idle moment (when no other tasks + * can run). For task0 'pause()' just means we go check if some other + * task can run, and if not we return here. + */ + for(;;) pause(); +} + +static int printf(const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + write(1,printbuf,i=vsprintf(printbuf, fmt, args)); + va_end(args); + return i; +} + +static char * argv_rc[] = { "/bin/sh", NULL }; +static char * envp_rc[] = { "HOME=/", NULL, NULL }; + +static char * argv[] = { "-/bin/sh",NULL }; +static char * envp[] = { "HOME=/usr/root", NULL, NULL }; + +void init(void) +{ + int pid,i; + + setup((void *) &drive_info); + (void) open("/dev/tty0",O_RDWR,0); + (void) dup(0); + (void) dup(0); + printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS, + NR_BUFFERS*BLOCK_SIZE); + printf("Free mem: %d bytes\n\r",memory_end-main_memory_start); + if (!(pid=fork())) { + close(0); + if (open("/etc/rc",O_RDONLY,0)) + _exit(1); + execve("/bin/sh",argv_rc,envp_rc); + _exit(2); + } + if (pid>0) + while (pid != wait(&i)) + /* nothing */; + while (1) { + if ((pid=fork())<0) { + printf("Fork failed in init\r\n"); + continue; + } + if (!pid) { + close(0);close(1);close(2); + setsid(); + (void) open("/dev/tty0",O_RDWR,0); + (void) dup(0); + (void) dup(0); + _exit(execve("/bin/sh",argv,envp)); + } + while (1) + if (pid == wait(&i)) + break; + printf("\n\rchild %d died with code %04x\n\r",pid,i); + sync(); + } + _exit(0); /* NOTE! _exit, not exit() */ +} diff --git a/linux/kernel/Makefile b/linux/kernel/Makefile new file mode 100644 index 0000000..ed16e9f --- /dev/null +++ b/linux/kernel/Makefile @@ -0,0 +1,83 @@ +# +# Makefile for the FREAX-kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =ar +AS =as +LD =ld +LDFLAGS =-m elf_i386 -Ttext 0 -e startup_32 +CC =gcc -march=i386 +CFLAGS =-w -g -fomit-frame-pointer -finline-functions \ + -nostdinc -fno-stack-protector -mcld -I../include +CPP =gcc -E -nostdinc -I../include + +.c.s: + $(CC) $(CFLAGS) \ + -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) \ + -c -o $*.o $< + +OBJS = sched.o system_call.o traps.o asm.o fork.o \ + panic.o printk.o vsprintf.o sys.o exit.o \ + signal.o mktime.o getdents.o pipe2.o sleep.o + +kernel.o: $(OBJS) + $(LD) -r -o kernel.o $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make keyboard.s + for i in *.c;do rm -f `basename $$i .c`.s;done + (cd chr_drv; make clean) + (cd blk_drv; make clean) + (cd math; make clean) + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + (cd chr_drv; make dep) + (cd blk_drv; make dep) + +### Dependencies: +exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \ + ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \ + ../include/asm/segment.h +fork.s fork.o : fork.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/segment.h ../include/asm/system.h +mktime.s mktime.o : mktime.c ../include/time.h +panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h +printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \ + ../include/linux/kernel.h +sched.s sched.o : sched.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/signal.h ../include/linux/kernel.h ../include/linux/sys.h \ + ../include/linux/fdreg.h ../include/asm/system.h ../include/asm/io.h \ + ../include/asm/segment.h +signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h +sys.s sys.o : sys.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/tty.h \ + ../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h \ + ../include/sys/times.h ../include/sys/utsname.h +traps.s traps.o : traps.c ../include/string.h ../include/linux/head.h \ + ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/system.h ../include/asm/segment.h ../include/asm/io.h +vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h diff --git a/linux/kernel/asm.s b/linux/kernel/asm.s new file mode 100644 index 0000000..1022817 --- /dev/null +++ b/linux/kernel/asm.s @@ -0,0 +1,146 @@ +/* + * linux/kernel/asm.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * asm.s contains the low-level code for most hardware faults. + * page_exception is handled by the mm, so that isn't here. This + * file also handles (hopefully) fpu-exceptions due to TS-bit, as + * the fpu must be properly saved/resored. This hasn't been tested. + */ + +.globl divide_error,debug,nmi,int3,overflow,bounds,invalid_op +.globl double_fault,coprocessor_segment_overrun +.globl invalid_TSS,segment_not_present,stack_segment +.globl general_protection,coprocessor_error,irq13,reserved + +divide_error: + pushl $do_divide_error +no_error_code: + xchgl %eax,(%esp) + pushl %ebx + pushl %ecx + pushl %edx + pushl %edi + pushl %esi + pushl %ebp + push %ds + push %es + push %fs + pushl $0 # "error code" + lea 44(%esp),%edx + pushl %edx + movl $0x10,%edx + mov %dx,%ds + mov %dx,%es + mov %dx,%fs + call *%eax + addl $8,%esp + pop %fs + pop %es + pop %ds + popl %ebp + popl %esi + popl %edi + popl %edx + popl %ecx + popl %ebx + popl %eax + iret + +debug: + pushl $do_int3 # _do_debug + jmp no_error_code + +nmi: + pushl $do_nmi + jmp no_error_code + +int3: + pushl $do_int3 + jmp no_error_code + +overflow: + pushl $do_overflow + jmp no_error_code + +bounds: + pushl $do_bounds + jmp no_error_code + +invalid_op: + pushl $do_invalid_op + jmp no_error_code + +coprocessor_segment_overrun: + pushl $do_coprocessor_segment_overrun + jmp no_error_code + +reserved: + pushl $do_reserved + jmp no_error_code + +irq13: + pushl %eax + xorb %al,%al + outb %al,$0xF0 + movb $0x20,%al + outb %al,$0x20 + jmp 1f +1: jmp 1f +1: outb %al,$0xA0 + popl %eax + jmp coprocessor_error + +double_fault: + pushl $do_double_fault +error_code: + xchgl %eax,4(%esp) # error code <-> %eax + xchgl %ebx,(%esp) # &function <-> %ebx + pushl %ecx + pushl %edx + pushl %edi + pushl %esi + pushl %ebp + push %ds + push %es + push %fs + pushl %eax # error code + lea 44(%esp),%eax # offset + pushl %eax + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + call *%ebx + addl $8,%esp + pop %fs + pop %es + pop %ds + popl %ebp + popl %esi + popl %edi + popl %edx + popl %ecx + popl %ebx + popl %eax + iret + +invalid_TSS: + pushl $do_invalid_TSS + jmp error_code + +segment_not_present: + pushl $do_segment_not_present + jmp error_code + +stack_segment: + pushl $do_stack_segment + jmp error_code + +general_protection: + pushl $do_general_protection + jmp error_code + diff --git a/linux/kernel/blk_drv/Makefile b/linux/kernel/blk_drv/Makefile new file mode 100644 index 0000000..1fb57f9 --- /dev/null +++ b/linux/kernel/blk_drv/Makefile @@ -0,0 +1,58 @@ +# +# Makefile for the FREAX-kernel block device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =ar +AS =as +LD =ld +LDFLAGS =-s -x +CC =gcc -march=i386 +CFLAGS =-w -g -fstrength-reduce -fomit-frame-pointer -mcld \ + -finline-functions -nostdinc -fno-stack-protector -I../../include +CPP =gcc -E -nostdinc -I../../include + +.c.s: + $(CC) $(CFLAGS) \ + -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) \ + -c -o $*.o $< + +OBJS = ll_rw_blk.o floppy.o hd.o ramdisk.o + +blk_drv.a: $(OBJS) + $(AR) rcs blk_drv.a $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/signal.h ../../include/linux/kernel.h \ + ../../include/linux/fdreg.h ../../include/asm/system.h \ + ../../include/asm/io.h ../../include/asm/segment.h blk.h +hd.s hd.o : hd.c ../../include/linux/config.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h ../../include/signal.h \ + ../../include/linux/kernel.h ../../include/linux/hdreg.h \ + ../../include/asm/system.h ../../include/asm/io.h \ + ../../include/asm/segment.h blk.h +ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h ../../include/signal.h \ + ../../include/linux/kernel.h ../../include/asm/system.h blk.h diff --git a/linux/kernel/blk_drv/blk.h b/linux/kernel/blk_drv/blk.h new file mode 100644 index 0000000..7a69b71 --- /dev/null +++ b/linux/kernel/blk_drv/blk.h @@ -0,0 +1,140 @@ +#ifndef _BLK_H +#define _BLK_H + +#define NR_BLK_DEV 7 +/* + * NR_REQUEST is the number of entries in the request-queue. + * NOTE that writes may use only the low 2/3 of these: reads + * take precedence. + * + * 32 seems to be a reasonable number: enough to get some benefit + * from the elevator-mechanism, but not so much as to lock a lot of + * buffers when they are in the queue. 64 seems to be too many (easily + * long pauses in reading when heavy writing/syncing is going on) + */ +#define NR_REQUEST 32 + +/* + * Ok, this is an expanded form so that we can use the same + * request for paging requests when that is implemented. In + * paging, 'bh' is NULL, and 'waiting' is used to wait for + * read/write completion. + */ +struct request { + int dev; /* -1 if no request */ + int cmd; /* READ or WRITE */ + int errors; + unsigned long sector; + unsigned long nr_sectors; + char * buffer; + struct task_struct * waiting; + struct buffer_head * bh; + struct request * next; +}; + +/* + * This is used in the elevator algorithm: Note that + * reads always go before writes. This is natural: reads + * are much more time-critical than writes. + */ +#define IN_ORDER(s1,s2) \ +((s1)->cmd<(s2)->cmd || (s1)->cmd==(s2)->cmd && \ +((s1)->dev < (s2)->dev || ((s1)->dev == (s2)->dev && \ +(s1)->sector < (s2)->sector))) + +struct blk_dev_struct { + void (*request_fn)(void); + struct request * current_request; +}; + +extern struct blk_dev_struct blk_dev[NR_BLK_DEV]; +extern struct request request[NR_REQUEST]; +extern struct task_struct * wait_for_request; + +#ifdef MAJOR_NR + +/* + * Add entries as needed. Currently the only block devices + * supported are hard-disks and floppies. + */ + +#if (MAJOR_NR == 1) +/* ram disk */ +#define DEVICE_NAME "ramdisk" +#define DEVICE_REQUEST do_rd_request +#define DEVICE_NR(device) ((device) & 7) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == 2) +/* floppy */ +#define DEVICE_NAME "floppy" +#define DEVICE_INTR do_floppy +#define DEVICE_REQUEST do_fd_request +#define DEVICE_NR(device) ((device) & 3) +#define DEVICE_ON(device) floppy_on(DEVICE_NR(device)) +#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) + +#elif (MAJOR_NR == 3) +/* harddisk */ +#define DEVICE_NAME "harddisk" +#define DEVICE_INTR do_hd +#define DEVICE_REQUEST do_hd_request +#define DEVICE_NR(device) (MINOR(device)/5) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR > 3) +/* unknown blk device */ +#error "unknown blk device" + +#endif + +#define CURRENT (blk_dev[MAJOR_NR].current_request) +#define CURRENT_DEV DEVICE_NR(CURRENT->dev) + +#ifdef DEVICE_INTR +void (*DEVICE_INTR)(void) = NULL; +#endif +static void (DEVICE_REQUEST)(void); + +static inline void unlock_buffer(struct buffer_head * bh) +{ + if (!bh->b_lock) + printk(DEVICE_NAME ": free buffer being unlocked\n"); + bh->b_lock=0; + wake_up(&bh->b_wait); +} + +static inline void end_request(int uptodate) +{ + DEVICE_OFF(CURRENT->dev); + if (CURRENT->bh) { + CURRENT->bh->b_uptodate = uptodate; + unlock_buffer(CURRENT->bh); + } + if (!uptodate) { + printk(DEVICE_NAME " I/O error\n\r"); + printk("dev %04x, block %d\n\r",CURRENT->dev, + CURRENT->bh->b_blocknr); + } + wake_up(&CURRENT->waiting); + wake_up(&wait_for_request); + CURRENT->dev = -1; + CURRENT = CURRENT->next; +} + +#define INIT_REQUEST \ +repeat: \ + if (!CURRENT) \ + return; \ + if (MAJOR(CURRENT->dev) != MAJOR_NR) \ + panic(DEVICE_NAME ": request list destroyed"); \ + if (CURRENT->bh) { \ + if (!CURRENT->bh->b_lock) \ + panic(DEVICE_NAME ": block not locked"); \ + } + +#endif + +#endif diff --git a/linux/kernel/blk_drv/floppy.c b/linux/kernel/blk_drv/floppy.c new file mode 100644 index 0000000..b1a7f3a --- /dev/null +++ b/linux/kernel/blk_drv/floppy.c @@ -0,0 +1,463 @@ +/* + * linux/kernel/floppy.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 02.12.91 - Changed to static variables to indicate need for reset + * and recalibrate. This makes some things easier (output_byte reset + * checking etc), and means less interrupt jumping in case of errors, + * so the code is hopefully easier to understand. + */ + +/* + * This file is certainly a mess. I've tried my best to get it working, + * but I don't like programming floppies, and I have only one anyway. + * Urgel. I should check for more errors, and do more graceful error + * recovery. Seems there are problems with several drives. I've tried to + * correct them. No promises. + */ + +/* + * As with hd.c, all routines within this file can (and will) be called + * by interrupts, so extreme caution is needed. A hardware interrupt + * handler may not sleep, or a kernel panic will happen. Thus I cannot + * call "floppy-on" directly, but have to set a special timer interrupt + * etc. + * + * Also, I'm not certain this works on more than 1 floppy. Bugs may + * abund. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 2 +#include "blk.h" + +static int recalibrate = 0; +static int reset = 0; +static int seek = 0; + +extern unsigned char current_DOR; + +#define immoutb_p(val,port) \ +__asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port)) + +#define TYPE(x) ((x)>>2) +#define DRIVE(x) ((x)&0x03) +/* + * Note that MAX_ERRORS=8 doesn't imply that we retry every bad read + * max 8 times - some types of errors increase the errorcount by 2, + * so we might actually retry only 5-6 times before giving up. + */ +#define MAX_ERRORS 8 + +/* + * globals used by 'result()' + */ +#define MAX_REPLIES 7 +static unsigned char reply_buffer[MAX_REPLIES]; +#define ST0 (reply_buffer[0]) +#define ST1 (reply_buffer[1]) +#define ST2 (reply_buffer[2]) +#define ST3 (reply_buffer[3]) + +/* + * This struct defines the different floppy types. Unlike minix + * linux doesn't have a "search for right type"-type, as the code + * for that is convoluted and weird. I've got enough problems with + * this driver as it is. + * + * The 'stretch' tells if the tracks need to be boubled for some + * types (ie 360kB diskette in 1.2MB drive etc). Others should + * be self-explanatory. + */ +static struct floppy_struct { + unsigned int size, sect, head, track, stretch; + unsigned char gap,rate,spec1; +} floppy_type[] = { + { 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */ + { 720, 9,2,40,0,0x2A,0x02,0xDF }, /* 360kB PC diskettes */ + { 2400,15,2,80,0,0x1B,0x00,0xDF }, /* 1.2 MB AT-diskettes */ + { 720, 9,2,40,1,0x2A,0x02,0xDF }, /* 360kB in 720kB drive */ + { 1440, 9,2,80,0,0x2A,0x02,0xDF }, /* 3.5" 720kB diskette */ + { 720, 9,2,40,1,0x23,0x01,0xDF }, /* 360kB in 1.2MB drive */ + { 1440, 9,2,80,0,0x23,0x01,0xDF }, /* 720kB in 1.2MB drive */ + { 2880,18,2,80,0,0x1B,0x00,0xCF }, /* 1.44MB diskette */ +}; +/* + * Rate is 0 for 500kb/s, 2 for 300kbps, 1 for 250kbps + * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc), + * H is head unload time (1=16ms, 2=32ms, etc) + * + * Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms etc) + * and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA). + */ + +extern void floppy_interrupt(void); +extern char tmp_floppy_area[1024]; + +/* + * These are global variables, as that's the easiest way to give + * information to interrupts. They are the data used for the current + * request. + */ +static int cur_spec1 = -1; +static int cur_rate = -1; +static struct floppy_struct * floppy = floppy_type; +static unsigned char current_drive = 0; +static unsigned char sector = 0; +static unsigned char head = 0; +static unsigned char track = 0; +static unsigned char seek_track = 0; +static unsigned char current_track = 255; +static unsigned char command = 0; +unsigned char selected = 0; +struct task_struct * wait_on_floppy_select = NULL; + +void floppy_deselect(unsigned int nr) +{ + if (nr != (current_DOR & 3)) + printk("floppy_deselect: drive not selected\n\r"); + selected = 0; + wake_up(&wait_on_floppy_select); +} + +/* + * floppy-change is never called from an interrupt, so we can relax a bit + * here, sleep etc. Note that floppy-on tries to set current_DOR to point + * to the desired drive, but it will probably not survive the sleep if + * several floppies are used at the same time: thus the loop. + */ +int floppy_change(unsigned int nr) +{ +repeat: + floppy_on(nr); + while ((current_DOR & 3) != nr && selected) + interruptible_sleep_on(&wait_on_floppy_select); + if ((current_DOR & 3) != nr) + goto repeat; + if (inb(FD_DIR) & 0x80) { + floppy_off(nr); + return 1; + } + floppy_off(nr); + return 0; +} + +#define copy_buffer(from,to) \ +__asm__("cld ; rep ; movsl" \ + ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \ + ) + +static void setup_DMA(void) +{ + long addr = (long) CURRENT->buffer; + + cli(); + if (addr >= 0x100000) { + addr = (long) tmp_floppy_area; + if (command == FD_WRITE) + copy_buffer(CURRENT->buffer,tmp_floppy_area); + } +/* mask DMA 2 */ + immoutb_p(4|2,10); +/* output command byte. I don't know why, but everyone (minix, */ +/* sanches & canton) output this twice, first to 12 then to 11 */ + __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t" + "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:":: + "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE))); +/* 8 low bits of addr */ + immoutb_p(addr,4); + addr >>= 8; +/* bits 8-15 of addr */ + immoutb_p(addr,4); + addr >>= 8; +/* bits 16-19 of addr */ + immoutb_p(addr,0x81); +/* low 8 bits of count-1 (1024-1=0x3ff) */ + immoutb_p(0xff,5); +/* high 8 bits of count-1 */ + immoutb_p(3,5); +/* activate DMA 2 */ + immoutb_p(0|2,10); + sti(); +} + +static void output_byte(char byte) +{ + int counter; + unsigned char status; + + if (reset) + return; + for(counter = 0 ; counter < 10000 ; counter++) { + status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR); + if (status == STATUS_READY) { + outb(byte,FD_DATA); + return; + } + } + reset = 1; + printk("Unable to send byte to FDC\n\r"); +} + +static int result(void) +{ + int i = 0, counter, status; + + if (reset) + return -1; + for (counter = 0 ; counter < 10000 ; counter++) { + status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY); + if (status == STATUS_READY) + return i; + if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) { + if (i >= MAX_REPLIES) + break; + reply_buffer[i++] = inb_p(FD_DATA); + } + } + reset = 1; + printk("Getstatus times out\n\r"); + return -1; +} + +static void bad_flp_intr(void) +{ + CURRENT->errors++; + if (CURRENT->errors > MAX_ERRORS) { + floppy_deselect(current_drive); + end_request(0); + } + if (CURRENT->errors > MAX_ERRORS/2) + reset = 1; + else + recalibrate = 1; +} + +/* + * Ok, this interrupt is called after a DMA read/write has succeeded, + * so we check the results, and copy any buffers. + */ +static void rw_interrupt(void) +{ + if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73)) { + if (ST1 & 0x02) { + printk("Drive %d is write protected\n\r",current_drive); + floppy_deselect(current_drive); + end_request(0); + } else + bad_flp_intr(); + do_fd_request(); + return; + } + if (command == FD_READ && (unsigned long)(CURRENT->buffer) >= 0x100000) + copy_buffer(tmp_floppy_area,CURRENT->buffer); + floppy_deselect(current_drive); + end_request(1); + do_fd_request(); +} + +inline void setup_rw_floppy(void) +{ + setup_DMA(); + do_floppy = rw_interrupt; + output_byte(command); + output_byte(head<<2 | current_drive); + output_byte(track); + output_byte(head); + output_byte(sector); + output_byte(2); /* sector size = 512 */ + output_byte(floppy->sect); + output_byte(floppy->gap); + output_byte(0xFF); /* sector size (0xff when n!=0 ?) */ + if (reset) + do_fd_request(); +} + +/* + * This is the routine called after every seek (or recalibrate) interrupt + * from the floppy controller. Note that the "unexpected interrupt" routine + * also does a recalibrate, but doesn't come here. + */ +static void seek_interrupt(void) +{ +/* sense drive status */ + output_byte(FD_SENSEI); + if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) { + bad_flp_intr(); + do_fd_request(); + return; + } + current_track = ST1; + setup_rw_floppy(); +} + +/* + * This routine is called when everything should be correctly set up + * for the transfer (ie floppy motor is on and the correct floppy is + * selected). + */ +static void transfer(void) +{ + if (cur_spec1 != floppy->spec1) { + cur_spec1 = floppy->spec1; + output_byte(FD_SPECIFY); + output_byte(cur_spec1); /* hut etc */ + output_byte(6); /* Head load time =6ms, DMA */ + } + if (cur_rate != floppy->rate) + outb_p(cur_rate = floppy->rate,FD_DCR); + if (reset) { + do_fd_request(); + return; + } + if (!seek) { + setup_rw_floppy(); + return; + } + do_floppy = seek_interrupt; + if (seek_track) { + output_byte(FD_SEEK); + output_byte(head<<2 | current_drive); + output_byte(seek_track); + } else { + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); + } + if (reset) + do_fd_request(); +} + +/* + * Special case - used after a unexpected interrupt (or reset) + */ +static void recal_interrupt(void) +{ + output_byte(FD_SENSEI); + if (result()!=2 || (ST0 & 0xE0) == 0x60) + reset = 1; + else + recalibrate = 0; + do_fd_request(); +} + +void unexpected_floppy_interrupt(void) +{ + output_byte(FD_SENSEI); + if (result()!=2 || (ST0 & 0xE0) == 0x60) + reset = 1; + else + recalibrate = 1; +} + +static void recalibrate_floppy(void) +{ + recalibrate = 0; + current_track = 0; + current_drive = 1; /* by wyj, ?? */ + do_floppy = recal_interrupt; + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); + if (reset) + do_fd_request(); +} + +static void reset_interrupt(void) +{ + output_byte(FD_SENSEI); + (void) result(); + output_byte(FD_SPECIFY); + output_byte(cur_spec1); /* hut etc */ + output_byte(6); /* Head load time =6ms, DMA */ + do_fd_request(); +} + +/* + * reset is done by pulling bit 2 of DOR low for a while. + */ +static void reset_floppy(void) +{ + int i; + + reset = 0; + cur_spec1 = -1; + cur_rate = -1; + recalibrate = 1; + printk("Reset-floppy called\n\r"); + cli(); + do_floppy = reset_interrupt; + outb_p(current_DOR & ~0x04,FD_DOR); + for (i=0 ; i<100 ; i++) + __asm__("nop"); + outb(current_DOR,FD_DOR); + sti(); +} + +static void floppy_on_interrupt(void) +{ +/* We cannot do a floppy-select, as that might sleep. We just force it */ + selected = 1; + if (current_drive != (current_DOR & 3)) { + current_DOR &= 0xFC; + current_DOR |= current_drive; + outb(current_DOR,FD_DOR); + add_timer(2,&transfer); + } else + transfer(); +} + +void do_fd_request(void) +{ + unsigned int block; + + seek = 0; + if (reset) { + reset_floppy(); + return; + } + if (recalibrate) { + recalibrate_floppy(); + return; + } + INIT_REQUEST; + floppy = (MINOR(CURRENT->dev)>>2) + floppy_type; + if (current_drive != CURRENT_DEV) + seek = 1; + current_drive = CURRENT_DEV; + block = CURRENT->sector; + if (block+2 > floppy->size) { + end_request(0); + goto repeat; + } + sector = block % floppy->sect; + block /= floppy->sect; + head = block % floppy->head; + track = block / floppy->head; + seek_track = track << floppy->stretch; + if (seek_track != current_track) + seek = 1; + sector++; + if (CURRENT->cmd == READ) + command = FD_READ; + else if (CURRENT->cmd == WRITE) + command = FD_WRITE; + else + panic("do_fd_request: unknown command"); + add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt); +} + +void floppy_init(void) +{ + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + set_trap_gate(0x26,&floppy_interrupt); + outb(inb_p(0x21)&~0x40,0x21); +} diff --git a/linux/kernel/blk_drv/hd.c b/linux/kernel/blk_drv/hd.c new file mode 100644 index 0000000..c0e908f --- /dev/null +++ b/linux/kernel/blk_drv/hd.c @@ -0,0 +1,351 @@ +/* + * linux/kernel/hd.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This is the low-level hd interrupt support. It traverses the + * request-list, using interrupts to jump between functions. As + * all the functions are called within interrupts, we may not + * sleep. Special care is recommended. + * + * modified by Drew Eckhardt to check nr of hd's from the CMOS. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 3 +#include "blk.h" + +#define CMOS_READ(addr) ({ \ +outb_p(0x80|addr,0x70); \ +inb_p(0x71); \ +}) + +/* Max read/write errors/sector */ +#define MAX_ERRORS 7 +#define MAX_HD 2 + +static void recal_intr(void); + +static int recalibrate = 0; /* 1, wen */ +static int reset = 0; + +/* + * This struct defines the HD's and their types. + */ +struct hd_i_struct { + int head,sect,cyl,wpcom,lzone,ctl; + }; +#ifdef HD_TYPE +struct hd_i_struct hd_info[] = { HD_TYPE }; +#define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct))) +#else +struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} }; +static int NR_HD = 0; +#endif + +static struct hd_struct { + long start_sect; + long nr_sects; +} hd[5*MAX_HD]={{0,0},}; + +#define port_read(port,buf,nr) \ +__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr)) + +#define port_write(port,buf,nr) \ +__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr)) + +extern void hd_interrupt(void); +extern void rd_load(void); + +/* This may be used only once, enforced by 'static int callable' */ +int sys_setup(void * BIOS) +{ + static int callable = 1; + int i,drive; + unsigned char cmos_disks; + struct partition *p; + struct buffer_head * bh; + + if (!callable) + return -1; + callable = 0; +#ifndef HD_TYPE + for (drive=0 ; drive<2 ; drive++) { + hd_info[drive].cyl = *(unsigned short *) BIOS; + hd_info[drive].head = *(unsigned char *) (2+BIOS); + hd_info[drive].wpcom = *(unsigned short *) (5+BIOS); + hd_info[drive].ctl = *(unsigned char *) (8+BIOS); + hd_info[drive].lzone = *(unsigned short *) (12+BIOS); + hd_info[drive].sect = *(unsigned char *) (14+BIOS); + BIOS += 16; + } + if (hd_info[1].cyl) + NR_HD=2; + else + NR_HD=1; +#endif + for (i=0 ; i are the primary drives in the system, and + the ones reflected as drive 1 or 2. + + The first drive is stored in the high nibble of CMOS + byte 0x12, the second in the low nibble. This will be + either a 4 bit drive type or 0xf indicating use byte 0x19 + for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. + + Needless to say, a non-zero value means we have + an AT controller hard disk for that drive. + + + */ + + if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) + if (cmos_disks & 0x0f) + NR_HD = 2; + else + NR_HD = 1; + else + NR_HD = 0; + for (i = NR_HD ; i < 2 ; i++) { + hd[i*5].start_sect = 0; + hd[i*5].nr_sects = 0; + } + for (drive=0 ; driveb_data[510] != 0x55 || (unsigned char) + bh->b_data[511] != 0xAA) { + printk("Bad partition table on drive %d\n\r",drive); + panic(""); + } + p = 0x1BE + (void *)bh->b_data; + for (i=1;i<5;i++,p++) { + hd[i+5*drive].start_sect = p->start_sect; + hd[i+5*drive].nr_sects = p->nr_sects; + } + brelse(bh); + } + if (NR_HD) + printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":""); + rd_load(); + mount_root(); + return (0); +} + +static int controller_ready(void) +{ + /* int retries=10000; */ + int retries=100000; + + /* while (--retries && (inb_p(HD_STATUS)&0xc0)!=0x40); */ + while (--retries && (inb_p(HD_STATUS)&0x80)); + return (retries); +} + +static int win_result(void) +{ + int i=inb_p(HD_STATUS); + + if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)) + == (READY_STAT | SEEK_STAT)) + return(0); /* ok */ + if (i&1) i=inb(HD_ERROR); + return (1); +} + +static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect, + unsigned int head,unsigned int cyl,unsigned int cmd, + void (*intr_addr)(void)) +{ + register int port asm("dx"); + + if (drive>1 || head>15) + panic("Trying to write bad sector"); + if (!controller_ready()) + panic("HD controller not ready"); + do_hd = intr_addr; + outb_p(hd_info[drive].ctl,HD_CMD); + port=HD_DATA; + outb_p(hd_info[drive].wpcom>>2,++port); + outb_p(nsect,++port); + outb_p(sect,++port); + outb_p(cyl,++port); + outb_p(cyl>>8,++port); + outb_p(0xA0|(drive<<4)|head,++port); + outb(cmd,++port); +} + +static int drive_busy(void) +{ + unsigned int i; + + for (i = 0; i < 10000; i++) + if (READY_STAT == (inb_p(HD_STATUS) & (BUSY_STAT|READY_STAT))) + break; + i = inb(HD_STATUS); + i &= BUSY_STAT | READY_STAT | SEEK_STAT; + if (i == READY_STAT | SEEK_STAT) + return(0); + printk("HD controller times out\n\r"); + return(1); +} + +static void reset_controller(void) +{ + int i; + + outb(4,HD_CMD); + for(i = 0; i < 100; i++) nop(); + outb(hd_info[0].ctl & 0x0f ,HD_CMD); + if (drive_busy()) + printk("HD-controller still busy\n\r"); + if ((i = inb(HD_ERROR)) != 1) + printk("HD-controller reset failed: %02x\n\r",i); +} + +static void reset_hd(int nr) +{ + reset_controller(); + hd_out(nr,hd_info[nr].sect,hd_info[nr].sect,hd_info[nr].head-1, + hd_info[nr].cyl,WIN_SPECIFY,&recal_intr); +} + +void unexpected_hd_interrupt(void) +{ + printk("Unexpected HD interrupt\n\r"); +} + +static void bad_rw_intr(void) +{ + if (++CURRENT->errors >= MAX_ERRORS) + end_request(0); + if (CURRENT->errors > MAX_ERRORS/2) + reset = 1; +} + +static void read_intr(void) +{ + if (win_result()) { + bad_rw_intr(); + do_hd_request(); + return; + } + port_read(HD_DATA,CURRENT->buffer,256); + CURRENT->errors = 0; + CURRENT->buffer += 512; + CURRENT->sector++; + if (--CURRENT->nr_sectors) { + do_hd = &read_intr; + return; + } + end_request(1); + do_hd_request(); +} + +static void write_intr(void) +{ + if (win_result()) { + bad_rw_intr(); + do_hd_request(); + return; + } + if (--CURRENT->nr_sectors) { + CURRENT->sector++; + CURRENT->buffer += 512; + do_hd = &write_intr; + port_write(HD_DATA,CURRENT->buffer,256); + return; + } + end_request(1); + do_hd_request(); +} + +static void recal_intr(void) +{ + if (win_result()) + bad_rw_intr(); + do_hd_request(); +} + +void do_hd_request(void) +{ + int i,r; + unsigned int block,dev; + unsigned int sec,head,cyl; + unsigned int nsect; + + INIT_REQUEST; + dev = MINOR(CURRENT->dev); + block = CURRENT->sector; + if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) { + end_request(0); + goto repeat; + } + block += hd[dev].start_sect; + dev /= 5; + __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0), + "r" (hd_info[dev].sect)); + __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0), + "r" (hd_info[dev].head)); + sec++; + nsect = CURRENT->nr_sectors; + if (reset) { + reset = 0; + recalibrate = 1; + reset_hd(CURRENT_DEV); + return; + } + if (recalibrate) { + recalibrate = 0; + hd_out(dev,hd_info[CURRENT_DEV].sect,0,0,0, + WIN_RESTORE,&recal_intr); + return; + } + if (CURRENT->cmd == WRITE) { + hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr); + for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++) + /* nothing */ ; + if (!r) { + bad_rw_intr(); + goto repeat; + } + port_write(HD_DATA,CURRENT->buffer,256); + } else if (CURRENT->cmd == READ) { + hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr); + } else + panic("unknown hd-command"); +} + +void hd_init(void) +{ + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + set_intr_gate(0x2E,&hd_interrupt); + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xbf,0xA1); +} diff --git a/linux/kernel/blk_drv/ll_rw_blk.c b/linux/kernel/blk_drv/ll_rw_blk.c new file mode 100644 index 0000000..f57d998 --- /dev/null +++ b/linux/kernel/blk_drv/ll_rw_blk.c @@ -0,0 +1,165 @@ +/* + * linux/kernel/blk_dev/ll_rw.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This handles all read/write requests to block devices + */ +#include +#include +#include +#include + +#include "blk.h" + +/* + * The request-struct contains all necessary data + * to load a nr of sectors into memory + */ +struct request request[NR_REQUEST]; + +/* + * used to wait on when there are no free requests + */ +struct task_struct * wait_for_request = NULL; + +/* blk_dev_struct is: + * do_request-address + * next-request + */ +struct blk_dev_struct blk_dev[NR_BLK_DEV] = { + { NULL, NULL }, /* no_dev */ + { NULL, NULL }, /* dev mem */ + { NULL, NULL }, /* dev fd */ + { NULL, NULL }, /* dev hd */ + { NULL, NULL }, /* dev ttyx */ + { NULL, NULL }, /* dev tty */ + { NULL, NULL } /* dev lp */ +}; + +static inline void lock_buffer(struct buffer_head * bh) +{ + cli(); + while (bh->b_lock) + sleep_on(&bh->b_wait); + bh->b_lock=1; + sti(); +} + +static inline void unlock_buffer(struct buffer_head * bh) +{ + if (!bh->b_lock) + printk("ll_rw_block.c: buffer not locked\n\r"); + bh->b_lock = 0; + wake_up(&bh->b_wait); +} + +/* + * add-request adds a request to the linked list. + * It disables interrupts so that it can muck with the + * request-lists in peace. + */ +static void add_request(struct blk_dev_struct * dev, struct request * req) +{ + struct request * tmp; + + req->next = NULL; + cli(); + if (req->bh) + req->bh->b_dirt = 0; + if (!(tmp = dev->current_request)) { + dev->current_request = req; + sti(); + (dev->request_fn)(); + return; + } + for ( ; tmp->next ; tmp=tmp->next) + if ((IN_ORDER(tmp,req) || + !IN_ORDER(tmp,tmp->next)) && + IN_ORDER(req,tmp->next)) + break; + req->next=tmp->next; + tmp->next=req; + sti(); +} + +static void make_request(int major,int rw, struct buffer_head * bh) +{ + struct request * req; + int rw_ahead; + +/* WRITEA/READA is special case - it is not really needed, so if the */ +/* buffer is locked, we just forget about it, else it's a normal read */ + if (rw_ahead = (rw == READA || rw == WRITEA)) { + if (bh->b_lock) + return; + if (rw == READA) + rw = READ; + else + rw = WRITE; + } + if (rw!=READ && rw!=WRITE) + panic("Bad block dev command, must be R/W/RA/WA"); + lock_buffer(bh); + if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) { + unlock_buffer(bh); + return; + } +repeat: +/* we don't allow the write-requests to fill up the queue completely: + * we want some room for reads: they take precedence. The last third + * of the requests are only for reads. + */ + if (rw == READ) + req = request+NR_REQUEST; + else + req = request+((NR_REQUEST*2)/3); +/* find an empty request */ + while (--req >= request) + if (req->dev<0) + break; +/* if none found, sleep on new requests: check for rw_ahead */ + if (req < request) { + if (rw_ahead) { + unlock_buffer(bh); + return; + } + sleep_on(&wait_for_request); + goto repeat; + } +/* fill up the request-info, and add it to the queue */ + req->dev = bh->b_dev; + req->cmd = rw; + req->errors=0; + req->sector = bh->b_blocknr<<1; + req->nr_sectors = 2; + req->buffer = bh->b_data; + req->waiting = NULL; + req->bh = bh; + req->next = NULL; + add_request(major+blk_dev,req); +} + +void ll_rw_block(int rw, struct buffer_head * bh) +{ + unsigned int major; + + if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || + !(blk_dev[major].request_fn)) { + printk("Trying to read nonexistent block-device\n\r"); + return; + } + make_request(major,rw,bh); +} + +void blk_dev_init(void) +{ + int i; + + for (i=0 ; i + +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 1 +#include "blk.h" + +char *rd_start; +int rd_length = 0; + +void do_rd_request(void) +{ + int len; + char *addr; + + INIT_REQUEST; + addr = rd_start + (CURRENT->sector << 9); + len = CURRENT->nr_sectors << 9; + if ((MINOR(CURRENT->dev) != 1) || (addr+len > rd_start+rd_length)) { + end_request(0); + goto repeat; + } + if (CURRENT-> cmd == WRITE) { + (void ) memcpy(addr, + CURRENT->buffer, + len); + } else if (CURRENT->cmd == READ) { + (void) memcpy(CURRENT->buffer, + addr, + len); + } else + panic("unknown ramdisk-command"); + end_request(1); + goto repeat; +} + +/* + * Returns amount of memory which needs to be reserved. + */ +long rd_init(long mem_start, int length) +{ + int i; + char *cp; + + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + rd_start = (char *) mem_start; + rd_length = length; + cp = rd_start; + for (i=0; i < length; i++) + *cp++ = '\0'; + return(length); +} + +/* + * If the root device is the ram disk, try to load it. + * In order to do this, the root device is originally set to the + * floppy, and we later change it to be ram disk. + */ +void rd_load(void) +{ + struct buffer_head *bh; + struct super_block s; + int block = 256; /* Start at block 256 */ + int i = 1; + int nblocks; + char *cp; /* Move pointer */ + + if (!rd_length) + return; + printk("Ram disk: %d bytes, starting at 0x%x\n", rd_length, + (int) rd_start); + if (MAJOR(ROOT_DEV) != 2) + return; + bh = breada(ROOT_DEV,block+1,block,block+2,-1); + if (!bh) { + printk("Disk error while looking for ramdisk!\n"); + return; + } + __asm__ volatile ("cld"); /* by wyj */ + *((struct d_super_block *) &s) = *((struct d_super_block *) bh->b_data); + brelse(bh); + if (s.s_magic != SUPER_MAGIC) + /* No ram disk image present, assume normal floppy boot */ + return; + nblocks = s.s_nzones << s.s_log_zone_size; + if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) { + printk("Ram disk image too big! (%d blocks, %d avail)\n", + nblocks, rd_length >> BLOCK_SIZE_BITS); + return; + } + printk("Loading %d bytes into ram disk... 0000k", + nblocks << BLOCK_SIZE_BITS); + cp = rd_start; + while (nblocks) { + if (nblocks > 2) + bh = breada(ROOT_DEV, block, block+1, block+2, -1); + else + bh = bread(ROOT_DEV, block); + if (!bh) { + printk("I/O error on block %d, aborting load\n", + block); + return; + } + (void) memcpy(cp, bh->b_data, BLOCK_SIZE); + brelse(bh); + printk("\010\010\010\010\010%4dk",i); + cp += BLOCK_SIZE; + block++; + nblocks--; + i++; + } + printk("\010\010\010\010\010done \n"); + ROOT_DEV=0x0101; +} diff --git a/linux/kernel/chr_drv/Makefile b/linux/kernel/chr_drv/Makefile new file mode 100644 index 0000000..9d4d8d1 --- /dev/null +++ b/linux/kernel/chr_drv/Makefile @@ -0,0 +1,68 @@ +# +# Makefile for the FREAX-kernel character device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =ar +AS =as +LD =ld +LDFLAGS =-s -x +CC =gcc -march=i386 +CFLAGS =-w -g -fstrength-reduce -fomit-frame-pointer -mcld \ + -finline-functions -nostdinc -fno-stack-protector -I../../include +CPP =gcc -E -nostdinc -I../../include + +.c.s: + $(CC) $(CFLAGS) \ + -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) \ + -c -o $*.o $< + +OBJS = tty_io.o console.o keyboard.2.o serial.o rs_io.o \ + tty_ioctl.o + +chr_drv.a: $(OBJS) + $(AR) rcs chr_drv.a $(OBJS) + sync + +keyboard.2.s: keyboard.S ../../include/linux/config.h + $(CPP) -traditional keyboard.S -o keyboard.2.s + +clean: + rm -f core *.o *.a tmp_make keyboard.2.s + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +console.s console.o : console.c ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h ../../include/signal.h \ + ../../include/linux/tty.h ../../include/termios.h ../../include/asm/io.h \ + ../../include/asm/system.h +serial.s serial.o : serial.c ../../include/linux/tty.h ../../include/termios.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/signal.h ../../include/asm/system.h ../../include/asm/io.h +tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \ + ../../include/signal.h ../../include/sys/types.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/linux/mm.h ../../include/linux/tty.h \ + ../../include/termios.h ../../include/asm/segment.h \ + ../../include/asm/system.h +tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/signal.h ../../include/linux/kernel.h \ + ../../include/linux/tty.h ../../include/asm/io.h \ + ../../include/asm/segment.h ../../include/asm/system.h diff --git a/linux/kernel/chr_drv/console.c b/linux/kernel/chr_drv/console.c new file mode 100644 index 0000000..a12ffbf --- /dev/null +++ b/linux/kernel/chr_drv/console.c @@ -0,0 +1,710 @@ +/* + * linux/kernel/console.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * console.c + * + * This module implements the console io functions + * 'void con_init(void)' + * 'void con_write(struct tty_queue * queue)' + * Hopefully this will be a rather complete VT102 implementation. + * + * Beeping thanks to John T Kohl. + */ + +/* + * NOTE!!! We sometimes disable and enable interrupts for a short while + * (to put a word in video IO), but this will work even for keyboard + * interrupts. We know interrupts aren't enabled when getting a keyboard + * interrupt, as we use trap-gates. Hopefully all is well. + */ + +/* + * Code to check for different video-cards mostly by Galen Hunt, + * + */ + +#include +#include +#include +#include + +/* + * These are set up by the setup-routine at boot-time: + */ + +#define ORIG_X (*(unsigned char *)0x90000) +#define ORIG_Y (*(unsigned char *)0x90001) +#define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004) +#define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff) +#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8) +#define ORIG_VIDEO_LINES (25) +#define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008) +#define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a) +#define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c) + +#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ +#define VIDEO_TYPE_CGA 0x11 /* CGA Display */ +#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */ +#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */ + +#define NPAR 16 + +extern void keyboard_interrupt(void); + +static unsigned char video_type; /* Type of display being used */ +static unsigned long video_num_columns; /* Number of text columns */ +static unsigned long video_size_row; /* Bytes per row */ +static unsigned long video_num_lines; /* Number of test lines */ +static unsigned char video_page; /* Initial video page */ +static unsigned long video_mem_start; /* Start of video RAM */ +static unsigned long video_mem_end; /* End of video RAM (sort of) */ +static unsigned short video_port_reg; /* Video register select port */ +static unsigned short video_port_val; /* Video register value port */ +static unsigned short video_erase_char; /* Char+Attrib to erase with */ + +static unsigned long origin; /* Used for EGA/VGA fast scroll */ +static unsigned long scr_end; /* Used for EGA/VGA fast scroll */ +static unsigned long pos; +static unsigned long x,y; +static unsigned long top,bottom; +static unsigned long state=0; +static unsigned long npar,par[NPAR]; +static unsigned long ques=0; +static unsigned char attr=0x07; + +static void sysbeep(void); + +/* + * this is what the terminal answers to a ESC-Z or csi0c + * query (= vt100 response). + */ +#define RESPONSE "\033[?1;2c" + +/* NOTE! gotoxy thinks x==video_num_columns is ok */ +static inline void gotoxy(unsigned int new_x,unsigned int new_y) +{ + if (new_x > video_num_columns || new_y >= video_num_lines) + return; + x=new_x; + y=new_y; + pos=origin + y*video_size_row + (x<<1); +} + +static inline void set_origin(void) +{ + cli(); + outb_p(12, video_port_reg); + outb_p(0xff&((origin-video_mem_start)>>9), video_port_val); + outb_p(13, video_port_reg); + outb_p(0xff&((origin-video_mem_start)>>1), video_port_val); + sti(); +} + +static void scrup(void) +{ + if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) + { + if (!top && bottom == video_num_lines) { + origin += video_size_row; + pos += video_size_row; + scr_end += video_size_row; + if (scr_end > video_mem_end) { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl video_num_columns,%1\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((video_num_lines-1)*video_num_columns>>1), + "D" (video_mem_start), + "S" (origin) + ); + scr_end -= origin-video_mem_start; + pos -= origin-video_mem_start; + origin = video_mem_start; + } else { + __asm__("cld\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" (video_num_columns), + "D" (scr_end-video_size_row) + ); + } + set_origin(); + } else { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*top), + "S" (origin+video_size_row*(top+1)) + ); + } + } + else /* Not EGA/VGA */ + { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*top), + "S" (origin+video_size_row*(top+1)) + ); + } +} + +static void scrdown(void) +{ + if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) + { + __asm__("std\n\t" + "rep\n\t" + "movsl\n\t" + "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ + "movl video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*bottom-4), + "S" (origin+video_size_row*(bottom-1)-4) + ); + } + else /* Not EGA/VGA */ + { + __asm__("std\n\t" + "rep\n\t" + "movsl\n\t" + "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ + "movl video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*bottom-4), + "S" (origin+video_size_row*(bottom-1)-4) + ); + } +} + +static void lf(void) +{ + if (y+1top) { + y--; + pos -= video_size_row; + return; + } + scrdown(); +} + +static void cr(void) +{ + pos -= x<<1; + x=0; +} + +static void del(void) +{ + if (x) { + pos -= 2; + x--; + *(unsigned short *)pos = video_erase_char; + } +} + +static void csi_J(int par) +{ + long count __asm__("cx"); + long start __asm__("di"); + + switch (par) { + case 0: /* erase from cursor to end of display */ + count = (scr_end-pos)>>1; + start = pos; + break; + case 1: /* erase from start to cursor */ + count = (pos-origin)>>1; + start = origin; + break; + case 2: /* erase whole display */ + count = video_num_columns * video_num_lines; + start = origin; + break; + default: + return; + } + __asm__("cld\n\t" + "rep\n\t" + "stosw\n\t" + ::"c" (count), + "D" (start),"a" (video_erase_char) + ); +} + +static void csi_K(int par) +{ + long count __asm__("cx"); + long start __asm__("di"); + + switch (par) { + case 0: /* erase from cursor to end of line */ + if (x>=video_num_columns) + return; + count = video_num_columns-x; + start = pos; + break; + case 1: /* erase from start of line to cursor */ + start = pos - (x<<1); + count = (x>9), video_port_val); + outb_p(15, video_port_reg); + outb_p(0xff&((pos-video_mem_start)>>1), video_port_val); + sti(); +} + +static void respond(struct tty_struct * tty) +{ + char * p = RESPONSE; + + cli(); + while (*p) { + PUTCH(*p,tty->read_q); + p++; + } + sti(); + copy_to_cooked(tty); +} + +static void insert_char(void) +{ + int i=x; + unsigned short tmp, old = video_erase_char; + unsigned short * p = (unsigned short *) pos; + + while (i++=video_num_columns) + return; + i = x; + while (++i < video_num_columns) { + *p = *(p+1); + p++; + } + *p = video_erase_char; +} + +static void delete_line(void) +{ + int oldtop,oldbottom; + + oldtop=top; + oldbottom=bottom; + top=y; + bottom = video_num_lines; + scrup(); + top=oldtop; + bottom=oldbottom; +} + +static void csi_at(unsigned int nr) +{ + if (nr > video_num_columns) + nr = video_num_columns; + else if (!nr) + nr = 1; + while (nr--) + insert_char(); +} + +static void csi_L(unsigned int nr) +{ + if (nr > video_num_lines) + nr = video_num_lines; + else if (!nr) + nr = 1; + while (nr--) + insert_line(); +} + +static void csi_P(unsigned int nr) +{ + if (nr > video_num_columns) + nr = video_num_columns; + else if (!nr) + nr = 1; + while (nr--) + delete_char(); +} + +static void csi_M(unsigned int nr) +{ + if (nr > video_num_lines) + nr = video_num_lines; + else if (!nr) + nr=1; + while (nr--) + delete_line(); +} + +static int saved_x=0; +static int saved_y=0; + +static void save_cur(void) +{ + saved_x=x; + saved_y=y; +} + +static void restore_cur(void) +{ + gotoxy(saved_x, saved_y); +} + +void con_write(struct tty_struct * tty) +{ + int nr; + char c; + + nr = CHARS(tty->write_q); + while (nr--) { + GETCH(tty->write_q,c); + switch(state) { + case 0: + if (c>31 && c<127) { + if (x>=video_num_columns) { + x -= video_num_columns; + pos -= video_size_row; + lf(); + } + __asm__("movb attr,%%ah\n\t" + "movw %%ax,%1\n\t" + ::"a" (c),"m" (*(short *)pos) + ); + pos += 2; + x++; + } else if (c==27) + state=1; + else if (c==10 || c==11 || c==12) + lf(); + else if (c==13) + cr(); + else if (c==ERASE_CHAR(tty)) + del(); + else if (c==8) { + if (x) { + x--; + pos -= 2; + } + } else if (c==9) { + c=8-(x&7); + x += c; + pos += c<<1; + if (x>video_num_columns) { + x -= video_num_columns; + pos -= video_size_row; + lf(); + } + c=9; + } else if (c==7) + sysbeep(); + break; + case 1: + state=0; + if (c=='[') + state=2; + else if (c=='E') + gotoxy(0,y+1); + else if (c=='M') + ri(); + else if (c=='D') + lf(); + else if (c=='Z') + respond(tty); + else if (x=='7') + save_cur(); + else if (x=='8') + restore_cur(); + break; + case 2: + for(npar=0;npar='0' && c<='9') { + par[npar]=10*par[npar]+c-'0'; + break; + } else state=4; + case 4: + state=0; + switch(c) { + case 'G': case '`': + if (par[0]) par[0]--; + gotoxy(par[0],y); + break; + case 'A': + if (!par[0]) par[0]++; + gotoxy(x,y-par[0]); + break; + case 'B': case 'e': + if (!par[0]) par[0]++; + gotoxy(x,y+par[0]); + break; + case 'C': case 'a': + if (!par[0]) par[0]++; + gotoxy(x+par[0],y); + break; + case 'D': + if (!par[0]) par[0]++; + gotoxy(x-par[0],y); + break; + case 'E': + if (!par[0]) par[0]++; + gotoxy(0,y+par[0]); + break; + case 'F': + if (!par[0]) par[0]++; + gotoxy(0,y-par[0]); + break; + case 'd': + if (par[0]) par[0]--; + gotoxy(x,par[0]); + break; + case 'H': case 'f': + if (par[0]) par[0]--; + if (par[1]) par[1]--; + gotoxy(par[1],par[0]); + break; + case 'J': + csi_J(par[0]); + break; + case 'K': + csi_K(par[0]); + break; + case 'L': + csi_L(par[0]); + break; + case 'M': + csi_M(par[0]); + break; + case 'P': + csi_P(par[0]); + break; + case '@': + csi_at(par[0]); + break; + case 'm': + csi_m(); + break; + case 'r': + if (par[0]) par[0]--; + if (!par[1]) par[1] = video_num_lines; + if (par[0] < par[1] && + par[1] <= video_num_lines) { + top=par[0]; + bottom=par[1]; + } + break; + case 's': + save_cur(); + break; + case 'u': + restore_cur(); + break; + } + } + } + set_cursor(); +} + +/* + * void con_init(void); + * + * This routine initalizes console interrupts, and does nothing + * else. If you want the screen to clear, call tty_write with + * the appropriate escape-sequece. + * + * Reads the information preserved by setup.s to determine the current display + * type and sets everything accordingly. + */ +void con_init(void) +{ + register unsigned char a; + char *display_desc = "????"; + char *display_ptr; + + video_num_columns = ORIG_VIDEO_COLS; + video_size_row = video_num_columns * 2; + video_num_lines = ORIG_VIDEO_LINES; + video_page = ORIG_VIDEO_PAGE; + video_erase_char = 0x0720; + + if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */ + { + video_mem_start = 0xb0000; + video_port_reg = 0x3b4; + video_port_val = 0x3b5; + if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) + { + video_type = VIDEO_TYPE_EGAM; + video_mem_end = 0xb8000; + display_desc = "EGAm"; + } + else + { + video_type = VIDEO_TYPE_MDA; + video_mem_end = 0xb2000; + display_desc = "*MDA"; + } + } + else /* If not, it is color. */ + { + video_mem_start = 0xb8000; + video_port_reg = 0x3d4; + video_port_val = 0x3d5; + if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) + { + video_type = VIDEO_TYPE_EGAC; + video_mem_end = 0xbc000; + display_desc = "EGAc"; + } + else + { + video_type = VIDEO_TYPE_CGA; + video_mem_end = 0xba000; + display_desc = "*CGA"; + } + } + + /* Let the user known what kind of display driver we are using */ + + display_ptr = ((char *)video_mem_start) + video_size_row - 8; + while (*display_desc) + { + *display_ptr++ = *display_desc++; + display_ptr++; + } + + /* Initialize the variables used for scrolling (mostly EGA/VGA) */ + + origin = video_mem_start; + scr_end = video_mem_start + video_num_lines * video_size_row; + top = 0; + bottom = video_num_lines; + + gotoxy(ORIG_X,ORIG_Y); + set_trap_gate(0x21,&keyboard_interrupt); + outb_p(inb_p(0x21)&0xfd,0x21); + a=inb_p(0x61); + outb_p(a|0x80,0x61); + outb(a,0x61); +} +/* from bsd-net-2: */ + +void sysbeepstop(void) +{ + /* disable counter 2 */ + outb(inb_p(0x61)&0xFC, 0x61); +} + +int beepcount = 0; + +static void sysbeep(void) +{ + /* enable counter 2 */ + outb_p(inb_p(0x61)|3, 0x61); + /* set command for counter 2, 2 byte write */ + outb_p(0xB6, 0x43); + /* send 0x637 for 750 HZ */ + outb_p(0x37, 0x42); + outb(0x06, 0x42); + /* 1/8 second */ + beepcount = HZ/8; +} diff --git a/linux/kernel/chr_drv/keyboard.2.s b/linux/kernel/chr_drv/keyboard.2.s new file mode 100644 index 0000000..a348410 --- /dev/null +++ b/linux/kernel/chr_drv/keyboard.2.s @@ -0,0 +1,466 @@ +# 1 "keyboard.S" +# 1 "" +# 1 "" +# 1 "keyboard.S" + + + + + + + + + + + + + +# 1 "../../include/linux/config.h" 1 + + + + + + + + + + + + + + + + + + + + + +# 36 "../../include/linux/config.h" + +# 47 "../../include/linux/config.h" + +# 14 "keyboard.S" 2 + +.text +.globl keyboard_interrupt + + + + +size = 1024 + +head = 4 +tail = 8 +proc_list = 12 +buf = 16 + +mode: .byte 0 +leds: .byte 2 +e0: .byte 0 + + + + + + +keyboard_interrupt: + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + push %ds + push %es + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + xor %al,%al + inb $0x60,%al + cmpb $0xe0,%al + je set_e0 + cmpb $0xe1,%al + je set_e1 + call key_table(,%eax,4) + movb $0,e0 +e0_e1: inb $0x61,%al + jmp 1f +1: jmp 1f +1: orb $0x80,%al + jmp 1f +1: jmp 1f +1: outb %al,$0x61 + jmp 1f +1: jmp 1f +1: andb $0x7F,%al + outb %al,$0x61 + movb $0x20,%al + outb %al,$0x20 + pushl $0 + call do_tty_interrupt + addl $4,%esp + pop %es + pop %ds + popl %edx + popl %ecx + popl %ebx + popl %eax + iret +set_e0: movb $1,e0 + jmp e0_e1 +set_e1: movb $2,e0 + jmp e0_e1 + + + + + + +put_queue: + pushl %ecx + pushl %edx + movl table_list,%edx # read-queue for console + movl head(%edx),%ecx +1: movb %al,buf(%edx,%ecx) + incl %ecx + andl $size-1,%ecx + cmpl tail(%edx),%ecx # buffer full - discard everything + je 3f + shrdl $8,%ebx,%eax + je 2f + shrl $8,%ebx + jmp 1b +2: movl %ecx,head(%edx) + movl proc_list(%edx),%ecx + testl %ecx,%ecx + je 3f + movl $0,(%ecx) +3: popl %edx + popl %ecx + ret + +ctrl: movb $0x04,%al + jmp 1f +alt: movb $0x10,%al +1: cmpb $0,e0 + je 2f + addb %al,%al +2: orb %al,mode + ret +unctrl: movb $0x04,%al + jmp 1f +unalt: movb $0x10,%al +1: cmpb $0,e0 + je 2f + addb %al,%al +2: notb %al + andb %al,mode + ret + +lshift: + orb $0x01,mode + ret +unlshift: + andb $0xfe,mode + ret +rshift: + orb $0x02,mode + ret +unrshift: + andb $0xfd,mode + ret + +caps: testb $0x80,mode + jne 1f + xorb $4,leds + xorb $0x40,mode + orb $0x80,mode +set_leds: + call kb_wait + movb $0xed,%al + outb %al,$0x60 + call kb_wait + movb leds,%al + outb %al,$0x60 + ret +uncaps: andb $0x7f,mode + ret +scroll: + xorb $1,leds + jmp set_leds +num: xorb $2,leds + jmp set_leds + + + + + +cursor: + subb $0x47,%al + jb 1f + cmpb $12,%al + ja 1f + jne cur2 + testb $0x0c,mode + je cur2 + testb $0x30,mode + jne reboot +cur2: cmpb $0x01,e0 + je cur + testb $0x02,leds + je cur + testb $0x03,mode + jne cur + xorl %ebx,%ebx + movb num_table(%eax),%al + jmp put_queue +1: ret + +cur: movb cur_table(%eax),%al + cmpb $'9,%al + ja ok_cur + movb $'~,%ah +ok_cur: shll $16,%eax + movw $0x5b1b,%ax + xorl %ebx,%ebx + jmp put_queue + + + + + +num_table: + .ascii "789 456 1230," + +cur_table: + .ascii "HA5 DGC YB623" + + + + +func: + pushl %eax + pushl %ecx + pushl %edx + call show_stat + popl %edx + popl %ecx + popl %eax + subb $0x3B,%al + jb end_func + cmpb $9,%al + jbe ok_func + subb $18,%al + cmpb $10,%al + jb end_func + cmpb $11,%al + ja end_func +ok_func: + cmpl $4,%ecx + jl end_func + movl func_table(,%eax,4),%eax + xorl %ebx,%ebx + jmp put_queue +end_func: + ret + + + + +func_table: + .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b + .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b + .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b + +# 294 "keyboard.S" + +key_map: + .byte 0,27 + .ascii "1234567890-=" + .byte 127,9 + .ascii "qwertyuiop[]" + .byte 13,0 + .ascii "asdfghjkl;'" + .byte '`,0 + .ascii "\\zxcvbnm,./" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 + .byte '-,0,0,0,'+ + .byte 0,0,0,0,0,0,0 + .byte '< + .fill 10,1,0 + + +shift_map: + .byte 0,27 + .ascii "!@#$%^&*()_+" + .byte 127,9 + .ascii "QWERTYUIOP{}" + .byte 13,0 + .ascii "ASDFGHJKL:\"" + .byte '~,0 + .ascii "|ZXCVBNM<>?" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 + .byte '-,0,0,0,'+ + .byte 0,0,0,0,0,0,0 + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 + .fill 16,1,0 + .byte 0,0,0,0,0 + .byte 0,0,0,0,0,0,0 + .byte '| + .fill 10,1,0 + +# 449 "keyboard.S" + + + + +do_self: + lea alt_map,%ebx + testb $0x20,mode + jne 1f + lea shift_map,%ebx + testb $0x03,mode + jne 1f + lea key_map,%ebx +1: movb (%ebx,%eax),%al + orb %al,%al + je none + testb $0x4c,mode + je 2f + cmpb $'a,%al + jb 2f + cmpb $'},%al + ja 2f + subb $32,%al +2: testb $0x0c,mode + je 3f + cmpb $64,%al + jb 3f + cmpb $64+32,%al + jae 3f + subb $64,%al +3: testb $0x10,mode + je 4f + orb $0x80,%al +4: andl $0xff,%eax + xorl %ebx,%ebx + call put_queue +none: ret + + + + + + +minus: cmpb $1,e0 + jne do_self + movl $'/,%eax + xorl %ebx,%ebx + jmp put_queue + + + + + + +key_table: + .long none,do_self,do_self,do_self + .long do_self,do_self,do_self,do_self + .long do_self,do_self,do_self,do_self + .long do_self,do_self,do_self,do_self + .long do_self,do_self,do_self,do_self + .long do_self,do_self,do_self,do_self + .long do_self,do_self,do_self,do_self + .long do_self,ctrl,do_self,do_self + .long do_self,do_self,do_self,do_self + .long do_self,do_self,do_self,do_self + .long do_self,do_self,lshift,do_self + .long do_self,do_self,do_self,do_self + .long do_self,do_self,do_self,do_self + .long do_self,minus,rshift,do_self + .long alt,do_self,caps,func + .long func,func,func,func + .long func,func,func,func + .long func,num,scroll,cursor + .long cursor,cursor,do_self,cursor + .long cursor,cursor,do_self,cursor + .long cursor,cursor,cursor,cursor + .long none,none,do_self,func + .long func,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,unctrl,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,unlshift,none + .long none,none,none,none + .long none,none,none,none + .long none,none,unrshift,none + .long unalt,none,uncaps,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + .long none,none,none,none + + + + + +kb_wait: + pushl %eax +1: inb $0x64,%al + testb $0x02,%al + jne 1b + popl %eax + ret + + + + +reboot: + call kb_wait + movw $0x1234,0x472 + movb $0xfc,%al + outb %al,$0x64 +die: jmp die diff --git a/linux/kernel/chr_drv/keyboard.S b/linux/kernel/chr_drv/keyboard.S new file mode 100644 index 0000000..25210b4 --- /dev/null +++ b/linux/kernel/chr_drv/keyboard.S @@ -0,0 +1,588 @@ +/* + * linux/kernel/keyboard.S + * + * (C) 1991 Linus Torvalds + */ + +/* + * Thanks to Alfred Leung for US keyboard patches + * Wolfgang Thiel for German keyboard patches + * Marc Corsini for the French keyboard + */ + +#include + +.text +.globl keyboard_interrupt + +/* + * these are for the keyboard read functions + */ +size = 1024 /* must be a power of two ! And MUST be the same + as in tty_io.c !!!! */ +head = 4 +tail = 8 +proc_list = 12 +buf = 16 + +mode: .byte 0 /* caps, alt, ctrl and shift mode */ +leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */ +e0: .byte 0 + +/* + * con_int is the real interrupt routine that reads the + * keyboard scan-code and converts it into the appropriate + * ascii character(s). + */ +keyboard_interrupt: + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + push %ds + push %es + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + xor %al,%al /* %eax is scan code */ + inb $0x60,%al + cmpb $0xe0,%al + je set_e0 + cmpb $0xe1,%al + je set_e1 + call key_table(,%eax,4) + movb $0,e0 +e0_e1: inb $0x61,%al + jmp 1f +1: jmp 1f +1: orb $0x80,%al + jmp 1f +1: jmp 1f +1: outb %al,$0x61 + jmp 1f +1: jmp 1f +1: andb $0x7F,%al + outb %al,$0x61 + movb $0x20,%al + outb %al,$0x20 + pushl $0 + call do_tty_interrupt + addl $4,%esp + pop %es + pop %ds + popl %edx + popl %ecx + popl %ebx + popl %eax + iret +set_e0: movb $1,e0 + jmp e0_e1 +set_e1: movb $2,e0 + jmp e0_e1 + +/* + * This routine fills the buffer with max 8 bytes, taken from + * %ebx:%eax. (%edx is high). The bytes are written in the + * order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero. + */ +put_queue: + pushl %ecx + pushl %edx + movl table_list,%edx # read-queue for console + movl head(%edx),%ecx +1: movb %al,buf(%edx,%ecx) + incl %ecx + andl $size-1,%ecx + cmpl tail(%edx),%ecx # buffer full - discard everything + je 3f + shrdl $8,%ebx,%eax + je 2f + shrl $8,%ebx + jmp 1b +2: movl %ecx,head(%edx) + movl proc_list(%edx),%ecx + testl %ecx,%ecx + je 3f + movl $0,(%ecx) +3: popl %edx + popl %ecx + ret + +ctrl: movb $0x04,%al + jmp 1f +alt: movb $0x10,%al +1: cmpb $0,e0 + je 2f + addb %al,%al +2: orb %al,mode + ret +unctrl: movb $0x04,%al + jmp 1f +unalt: movb $0x10,%al +1: cmpb $0,e0 + je 2f + addb %al,%al +2: notb %al + andb %al,mode + ret + +lshift: + orb $0x01,mode + ret +unlshift: + andb $0xfe,mode + ret +rshift: + orb $0x02,mode + ret +unrshift: + andb $0xfd,mode + ret + +caps: testb $0x80,mode + jne 1f + xorb $4,leds + xorb $0x40,mode + orb $0x80,mode +set_leds: + call kb_wait + movb $0xed,%al /* set leds command */ + outb %al,$0x60 + call kb_wait + movb leds,%al + outb %al,$0x60 + ret +uncaps: andb $0x7f,mode + ret +scroll: + xorb $1,leds + jmp set_leds +num: xorb $2,leds + jmp set_leds + +/* + * curosr-key/numeric keypad cursor keys are handled here. + * checking for numeric keypad etc. + */ +cursor: + subb $0x47,%al + jb 1f + cmpb $12,%al + ja 1f + jne cur2 /* check for ctrl-alt-del */ + testb $0x0c,mode + je cur2 + testb $0x30,mode + jne reboot +cur2: cmpb $0x01,e0 /* e0 forces cursor movement */ + je cur + testb $0x02,leds /* not num-lock forces cursor */ + je cur + testb $0x03,mode /* shift forces cursor */ + jne cur + xorl %ebx,%ebx + movb num_table(%eax),%al + jmp put_queue +1: ret + +cur: movb cur_table(%eax),%al + cmpb $'9,%al + ja ok_cur + movb $'~,%ah +ok_cur: shll $16,%eax + movw $0x5b1b,%ax + xorl %ebx,%ebx + jmp put_queue + +#if defined(KBD_FR) +num_table: + .ascii "789 456 1230." +#else +num_table: + .ascii "789 456 1230," +#endif +cur_table: + .ascii "HA5 DGC YB623" + +/* + * this routine handles function keys + */ +func: + pushl %eax + pushl %ecx + pushl %edx + call show_stat + popl %edx + popl %ecx + popl %eax + subb $0x3B,%al + jb end_func + cmpb $9,%al + jbe ok_func + subb $18,%al + cmpb $10,%al + jb end_func + cmpb $11,%al + ja end_func +ok_func: + cmpl $4,%ecx /* check that there is enough room */ + jl end_func + movl func_table(,%eax,4),%eax + xorl %ebx,%ebx + jmp put_queue +end_func: + ret + +/* + * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc. + */ +func_table: + .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b + .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b + .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b + +#if defined(KBD_FINNISH) +key_map: + .byte 0,27 + .ascii "1234567890+'" + .byte 127,9 + .ascii "qwertyuiop}" + .byte 0,13,0 + .ascii "asdfghjkl|{" + .byte 0,0 + .ascii "'zxcvbnm,.-" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + +shift_map: + .byte 0,27 + .ascii "!\"#$%&/()=?`" + .byte 127,9 + .ascii "QWERTYUIOP]^" + .byte 13,0 + .ascii "ASDFGHJKL\\[" + .byte 0,0 + .ascii "*ZXCVBNM;:_" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#elif defined(KBD_US) + +key_map: + .byte 0,27 + .ascii "1234567890-=" + .byte 127,9 + .ascii "qwertyuiop[]" + .byte 13,0 + .ascii "asdfghjkl;'" + .byte '`,0 + .ascii "\\zxcvbnm,./" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + + +shift_map: + .byte 0,27 + .ascii "!@#$%^&*()_+" + .byte 127,9 + .ascii "QWERTYUIOP{}" + .byte 13,0 + .ascii "ASDFGHJKL:\"" + .byte '~,0 + .ascii "|ZXCVBNM<>?" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#elif defined(KBD_GR) + +key_map: + .byte 0,27 + .ascii "1234567890\\'" + .byte 127,9 + .ascii "qwertzuiop@+" + .byte 13,0 + .ascii "asdfghjkl[]^" + .byte 0,'# + .ascii "yxcvbnm,.-" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + + +shift_map: + .byte 0,27 + .ascii "!\"#$%&/()=?`" + .byte 127,9 + .ascii "QWERTZUIOP\\*" + .byte 13,0 + .ascii "ASDFGHJKL{}~" + .byte 0,'' + .ascii "YXCVBNM;:_" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte '@,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + + +#elif defined(KBD_FR) + +key_map: + .byte 0,27 + .ascii "&{\"'(-}_/@)=" + .byte 127,9 + .ascii "azertyuiop^$" + .byte 13,0 + .ascii "qsdfghjklm|" + .byte '`,0,42 /* coin sup gauche, don't know, [*|mu] */ + .ascii "wxcvbn,;:!" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + +shift_map: + .byte 0,27 + .ascii "1234567890]+" + .byte 127,9 + .ascii "AZERTYUIOP<>" + .byte 13,0 + .ascii "QSDFGHJKLM%" + .byte '~,0,'# + .ascii "WXCVBN?./\\" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0~#{[|`\\^@]}" + .byte 0,0 + .byte '@,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#else +#error "KBD-type not defined" +#endif +/* + * do_self handles "normal" keys, ie keys that don't change meaning + * and which have just one character returns. + */ +do_self: + lea alt_map,%ebx + testb $0x20,mode /* alt-gr */ + jne 1f + lea shift_map,%ebx + testb $0x03,mode + jne 1f + lea key_map,%ebx +1: movb (%ebx,%eax),%al + orb %al,%al + je none + testb $0x4c,mode /* ctrl or caps */ + je 2f + cmpb $'a,%al + jb 2f + cmpb $'},%al + ja 2f + subb $32,%al +2: testb $0x0c,mode /* ctrl */ + je 3f + cmpb $64,%al + jb 3f + cmpb $64+32,%al + jae 3f + subb $64,%al +3: testb $0x10,mode /* left alt */ + je 4f + orb $0x80,%al +4: andl $0xff,%eax + xorl %ebx,%ebx + call put_queue +none: ret + +/* + * minus has a routine of it's own, as a 'E0h' before + * the scan code for minus means that the numeric keypad + * slash was pushed. + */ +minus: cmpb $1,e0 + jne do_self + movl $'/,%eax + xorl %ebx,%ebx + jmp put_queue + +/* + * This table decides which routine to call when a scan-code has been + * gotten. Most routines just call do_self, or none, depending if + * they are make or break. + */ +key_table: + .long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */ + .long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */ + .long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */ + .long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */ + .long do_self,do_self,do_self,do_self /* 10-13 q w e r */ + .long do_self,do_self,do_self,do_self /* 14-17 t y u i */ + .long do_self,do_self,do_self,do_self /* 18-1B o p } ^ */ + .long do_self,ctrl,do_self,do_self /* 1C-1F enter ctrl a s */ + .long do_self,do_self,do_self,do_self /* 20-23 d f g h */ + .long do_self,do_self,do_self,do_self /* 24-27 j k l | */ + .long do_self,do_self,lshift,do_self /* 28-2B { para lshift , */ + .long do_self,do_self,do_self,do_self /* 2C-2F z x c v */ + .long do_self,do_self,do_self,do_self /* 30-33 b n m , */ + .long do_self,minus,rshift,do_self /* 34-37 . - rshift * */ + .long alt,do_self,caps,func /* 38-3B alt sp caps f1 */ + .long func,func,func,func /* 3C-3F f2 f3 f4 f5 */ + .long func,func,func,func /* 40-43 f6 f7 f8 f9 */ + .long func,num,scroll,cursor /* 44-47 f10 num scr home */ + .long cursor,cursor,do_self,cursor /* 48-4B up pgup - left */ + .long cursor,cursor,do_self,cursor /* 4C-4F n5 right + end */ + .long cursor,cursor,cursor,cursor /* 50-53 dn pgdn ins del */ + .long none,none,do_self,func /* 54-57 sysreq ? < f11 */ + .long func,none,none,none /* 58-5B f12 ? ? ? */ + .long none,none,none,none /* 5C-5F ? ? ? ? */ + .long none,none,none,none /* 60-63 ? ? ? ? */ + .long none,none,none,none /* 64-67 ? ? ? ? */ + .long none,none,none,none /* 68-6B ? ? ? ? */ + .long none,none,none,none /* 6C-6F ? ? ? ? */ + .long none,none,none,none /* 70-73 ? ? ? ? */ + .long none,none,none,none /* 74-77 ? ? ? ? */ + .long none,none,none,none /* 78-7B ? ? ? ? */ + .long none,none,none,none /* 7C-7F ? ? ? ? */ + .long none,none,none,none /* 80-83 ? br br br */ + .long none,none,none,none /* 84-87 br br br br */ + .long none,none,none,none /* 88-8B br br br br */ + .long none,none,none,none /* 8C-8F br br br br */ + .long none,none,none,none /* 90-93 br br br br */ + .long none,none,none,none /* 94-97 br br br br */ + .long none,none,none,none /* 98-9B br br br br */ + .long none,unctrl,none,none /* 9C-9F br unctrl br br */ + .long none,none,none,none /* A0-A3 br br br br */ + .long none,none,none,none /* A4-A7 br br br br */ + .long none,none,unlshift,none /* A8-AB br br unlshift br */ + .long none,none,none,none /* AC-AF br br br br */ + .long none,none,none,none /* B0-B3 br br br br */ + .long none,none,unrshift,none /* B4-B7 br br unrshift br */ + .long unalt,none,uncaps,none /* B8-BB unalt br uncaps br */ + .long none,none,none,none /* BC-BF br br br br */ + .long none,none,none,none /* C0-C3 br br br br */ + .long none,none,none,none /* C4-C7 br br br br */ + .long none,none,none,none /* C8-CB br br br br */ + .long none,none,none,none /* CC-CF br br br br */ + .long none,none,none,none /* D0-D3 br br br br */ + .long none,none,none,none /* D4-D7 br br br br */ + .long none,none,none,none /* D8-DB br ? ? ? */ + .long none,none,none,none /* DC-DF ? ? ? ? */ + .long none,none,none,none /* E0-E3 e0 e1 ? ? */ + .long none,none,none,none /* E4-E7 ? ? ? ? */ + .long none,none,none,none /* E8-EB ? ? ? ? */ + .long none,none,none,none /* EC-EF ? ? ? ? */ + .long none,none,none,none /* F0-F3 ? ? ? ? */ + .long none,none,none,none /* F4-F7 ? ? ? ? */ + .long none,none,none,none /* F8-FB ? ? ? ? */ + .long none,none,none,none /* FC-FF ? ? ? ? */ + +/* + * kb_wait waits for the keyboard controller buffer to empty. + * there is no timeout - if the buffer doesn't empty, we hang. + */ +kb_wait: + pushl %eax +1: inb $0x64,%al + testb $0x02,%al + jne 1b + popl %eax + ret +/* + * This routine reboots the machine by asking the keyboard + * controller to pulse the reset-line low. + */ +reboot: + call kb_wait + movw $0x1234,0x472 /* don't do memory check */ + movb $0xfc,%al /* pulse reset and A20 low */ + outb %al,$0x64 +die: jmp die diff --git a/linux/kernel/chr_drv/rs_io.s b/linux/kernel/chr_drv/rs_io.s new file mode 100644 index 0000000..ba1e55e --- /dev/null +++ b/linux/kernel/chr_drv/rs_io.s @@ -0,0 +1,147 @@ +/* + * linux/kernel/rs_io.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * rs_io.s + * + * This module implements the rs232 io interrupts. + */ + +.text +.globl rs1_interrupt,rs2_interrupt + +size = 1024 /* must be power of two ! + and must match the value + in tty_io.c!!! */ + +/* these are the offsets into the read/write buffer structures */ +rs_addr = 0 +head = 4 +tail = 8 +proc_list = 12 +buf = 16 + +startup = 256 /* chars left in write queue when we restart it */ + +/* + * These are the actual interrupt routines. They look where + * the interrupt is coming from, and take appropriate action. + */ +.align 4 +rs1_interrupt: + pushl $table_list+8 + jmp rs_int +.align 4 +rs2_interrupt: + pushl $table_list+16 +rs_int: + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + push %es + push %ds /* as this is an interrupt, we cannot */ + pushl $0x10 /* know that bs is ok. Load it */ + pop %ds + pushl $0x10 + pop %es + movl 24(%esp),%edx + movl (%edx),%edx + movl rs_addr(%edx),%edx + addl $2,%edx /* interrupt ident. reg */ +rep_int: + xorl %eax,%eax + inb %dx,%al + testb $1,%al + jne end + cmpb $6,%al /* this shouldn't happen, but ... */ + ja end + movl 24(%esp),%ecx + pushl %edx + subl $2,%edx + call jmp_table(,%eax,2) /* NOTE! not *4, bit0 is 0 already */ + popl %edx + jmp rep_int +end: movb $0x20,%al + outb %al,$0x20 /* EOI */ + pop %ds + pop %es + popl %eax + popl %ebx + popl %ecx + popl %edx + addl $4,%esp # jump over _table_list entry + iret + +jmp_table: + .long modem_status,write_char,read_char,line_status + +.align 4 +modem_status: + addl $6,%edx /* clear intr by reading modem status reg */ + inb %dx,%al + ret + +.align 4 +line_status: + addl $5,%edx /* clear intr by reading line status reg. */ + inb %dx,%al + ret + +.align 4 +read_char: + inb %dx,%al + movl %ecx,%edx + subl $table_list,%edx + shrl $3,%edx + movl (%ecx),%ecx # read-queue + movl head(%ecx),%ebx + movb %al,buf(%ecx,%ebx) + incl %ebx + andl $size-1,%ebx + cmpl tail(%ecx),%ebx + je 1f + movl %ebx,head(%ecx) +1: pushl %edx + call do_tty_interrupt + addl $4,%esp + ret + +.align 4 +write_char: + movl 4(%ecx),%ecx # write-queue + movl head(%ecx),%ebx + subl tail(%ecx),%ebx + andl $size-1,%ebx # nr chars in queue + je write_buffer_empty + cmpl $startup,%ebx + ja 1f + movl proc_list(%ecx),%ebx # wake up sleeping process + testl %ebx,%ebx # is there any? + je 1f + movl $0,(%ebx) +1: movl tail(%ecx),%ebx + movb buf(%ecx,%ebx),%al + outb %al,%dx + incl %ebx + andl $size-1,%ebx + movl %ebx,tail(%ecx) + cmpl head(%ecx),%ebx + je write_buffer_empty + ret +.align 4 +write_buffer_empty: + movl proc_list(%ecx),%ebx # wake up sleeping process + testl %ebx,%ebx # is there any? + je 1f + movl $0,(%ebx) +1: incl %edx + inb %dx,%al + jmp 1f +1: jmp 1f +1: andb $0xd,%al /* disable transmit interrupt */ + outb %al,%dx + ret diff --git a/linux/kernel/chr_drv/serial.c b/linux/kernel/chr_drv/serial.c new file mode 100644 index 0000000..aba25df --- /dev/null +++ b/linux/kernel/chr_drv/serial.c @@ -0,0 +1,59 @@ +/* + * linux/kernel/serial.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * serial.c + * + * This module implements the rs232 io functions + * void rs_write(struct tty_struct * queue); + * void rs_init(void); + * and all interrupts pertaining to serial IO. + */ + +#include +#include +#include +#include + +#define WAKEUP_CHARS (TTY_BUF_SIZE/4) + +extern void rs1_interrupt(void); +extern void rs2_interrupt(void); + +static void init(int port) +{ + outb_p(0x80,port+3); /* set DLAB of line control reg */ + outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */ + outb_p(0x00,port+1); /* MS of divisor */ + outb_p(0x03,port+3); /* reset DLAB */ + outb_p(0x0b,port+4); /* set DTR,RTS, OUT_2 */ + outb_p(0x0d,port+1); /* enable all intrs but writes */ + (void)inb(port); /* read data port to reset things (?) */ +} + +void rs_init(void) +{ + set_intr_gate(0x24,rs1_interrupt); + set_intr_gate(0x23,rs2_interrupt); + init(tty_table[1].read_q.data); + init(tty_table[2].read_q.data); + outb(inb_p(0x21)&0xE7,0x21); +} + +/* + * This routine gets called when tty_write has put something into + * the write_queue. It must check wheter the queue is empty, and + * set the interrupt register accordingly + * + * void _rs_write(struct tty_struct * tty); + */ +void rs_write(struct tty_struct * tty) +{ + cli(); + if (!EMPTY(tty->write_q)) + outb(inb_p(tty->write_q.data+1)|0x02,tty->write_q.data+1); + sti(); +} diff --git a/linux/kernel/chr_drv/tty_io.c b/linux/kernel/chr_drv/tty_io.c new file mode 100644 index 0000000..b8da643 --- /dev/null +++ b/linux/kernel/chr_drv/tty_io.c @@ -0,0 +1,349 @@ +/* + * linux/kernel/tty_io.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles + * or rs-channels. It also implements echoing, cooked mode etc. + * + * Kill-line thanks to John T Kohl. + */ +#include +#include +#include + +#define ALRMMASK (1<<(SIGALRM-1)) +#define KILLMASK (1<<(SIGKILL-1)) +#define INTMASK (1<<(SIGINT-1)) +#define QUITMASK (1<<(SIGQUIT-1)) +#define TSTPMASK (1<<(SIGTSTP-1)) + +#include +#include +#include +#include + +#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f) +#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f) +#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f) + +#define L_CANON(tty) _L_FLAG((tty),ICANON) +#define L_ISIG(tty) _L_FLAG((tty),ISIG) +#define L_ECHO(tty) _L_FLAG((tty),ECHO) +#define L_ECHOE(tty) _L_FLAG((tty),ECHOE) +#define L_ECHOK(tty) _L_FLAG((tty),ECHOK) +#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL) +#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE) + +#define I_UCLC(tty) _I_FLAG((tty),IUCLC) +#define I_NLCR(tty) _I_FLAG((tty),INLCR) +#define I_CRNL(tty) _I_FLAG((tty),ICRNL) +#define I_NOCR(tty) _I_FLAG((tty),IGNCR) + +#define O_POST(tty) _O_FLAG((tty),OPOST) +#define O_NLCR(tty) _O_FLAG((tty),ONLCR) +#define O_CRNL(tty) _O_FLAG((tty),OCRNL) +#define O_NLRET(tty) _O_FLAG((tty),ONLRET) +#define O_LCUC(tty) _O_FLAG((tty),OLCUC) + +struct tty_struct tty_table[] = { + { + {ICRNL, /* change incoming CR to NL */ + OPOST|ONLCR, /* change outgoing NL to CRNL */ + 0, + ISIG | ICANON | ECHO | ECHOCTL | ECHOKE, + 0, /* console termio */ + INIT_C_CC}, + 0, /* initial pgrp */ + 0, /* initial stopped */ + con_write, + {0,0,0,0,""}, /* console read-queue */ + {0,0,0,0,""}, /* console write-queue */ + {0,0,0,0,""} /* console secondary queue */ + },{ + {0, /* no translation */ + 0, /* no translation */ + B2400 | CS8, + 0, + 0, + INIT_C_CC}, + 0, + 0, + rs_write, + {0x3f8,0,0,0,""}, /* rs 1 */ + {0x3f8,0,0,0,""}, + {0,0,0,0,""} + },{ + {0, /* no translation */ + 0, /* no translation */ + B2400 | CS8, + 0, + 0, + INIT_C_CC}, + 0, + 0, + rs_write, + {0x2f8,0,0,0,""}, /* rs 2 */ + {0x2f8,0,0,0,""}, + {0,0,0,0,""} + } +}; + +/* + * these are the tables used by the machine code handlers. + * you can implement pseudo-tty's or something by changing + * them. Currently not done. + */ +struct tty_queue * table_list[]={ + &tty_table[0].read_q, &tty_table[0].write_q, + &tty_table[1].read_q, &tty_table[1].write_q, + &tty_table[2].read_q, &tty_table[2].write_q + }; + +void tty_init(void) +{ + rs_init(); + con_init(); +} + +void tty_intr(struct tty_struct * tty, int mask) +{ + int i; + + if (tty->pgrp <= 0) + return; + for (i=0;ipgrp==tty->pgrp) + task[i]->signal |= mask; +} + +static void sleep_if_empty(struct tty_queue * queue) +{ + cli(); + while (!current->signal && EMPTY(*queue)) + interruptible_sleep_on(&queue->proc_list); + sti(); +} + +static void sleep_if_full(struct tty_queue * queue) +{ + if (!FULL(*queue)) + return; + cli(); + while (!current->signal && LEFT(*queue)<128) + interruptible_sleep_on(&queue->proc_list); + sti(); +} + +void wait_for_keypress(void) +{ + sleep_if_empty(&tty_table[0].secondary); +} + +void copy_to_cooked(struct tty_struct * tty) +{ + signed char c; + + while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) { + GETCH(tty->read_q,c); + if (c==13) + if (I_CRNL(tty)) + c=10; + else if (I_NOCR(tty)) + continue; + else ; + else if (c==10 && I_NLCR(tty)) + c=13; + if (I_UCLC(tty)) + c=tolower(c); + if (L_CANON(tty)) { + if (c==KILL_CHAR(tty)) { + /* deal with killing the input line */ + while(!(EMPTY(tty->secondary) || + (c=LAST(tty->secondary))==10 || + c==EOF_CHAR(tty))) { + if (L_ECHO(tty)) { + if (c<32) + PUTCH(127,tty->write_q); + PUTCH(127,tty->write_q); + tty->write(tty); + } + DEC(tty->secondary.head); + } + continue; + } + if (c==ERASE_CHAR(tty)) { + if (EMPTY(tty->secondary) || + (c=LAST(tty->secondary))==10 || + c==EOF_CHAR(tty)) + continue; + if (L_ECHO(tty)) { + if (c<32) + PUTCH(127,tty->write_q); + PUTCH(127,tty->write_q); + tty->write(tty); + } + DEC(tty->secondary.head); + continue; + } + if (c==STOP_CHAR(tty)) { + tty->stopped=1; + continue; + } + if (c==START_CHAR(tty)) { + tty->stopped=0; + continue; + } + } + if (L_ISIG(tty)) { + if (c==INTR_CHAR(tty)) { + tty_intr(tty,INTMASK); + continue; + } + if (c==QUIT_CHAR(tty)) { + tty_intr(tty,QUITMASK); + continue; + } + } + if (c==10 || c==EOF_CHAR(tty)) + tty->secondary.data++; + if (L_ECHO(tty)) { + if (c==10) { + PUTCH(10,tty->write_q); + PUTCH(13,tty->write_q); + } else if (c<32) { + if (L_ECHOCTL(tty)) { + PUTCH('^',tty->write_q); + PUTCH(c+64,tty->write_q); + } + } else + PUTCH(c,tty->write_q); + tty->write(tty); + } + PUTCH(c,tty->secondary); + } + wake_up(&tty->secondary.proc_list); +} + +int tty_read(unsigned channel, char * buf, int nr) +{ + struct tty_struct * tty; + char c, * b=buf; + int minimum,time,flag=0; + long oldalarm; + + if (channel>2 || nr<0) return -1; + tty = &tty_table[channel]; + oldalarm = current->alarm; + time = 10L*tty->termios.c_cc[VTIME]; + minimum = tty->termios.c_cc[VMIN]; + if (time && !minimum) { + minimum=1; + if (flag=(!oldalarm || time+jiffiesalarm = time+jiffies; + } + if (minimum>nr) + minimum=nr; + while (nr>0) { + if (flag && (current->signal & ALRMMASK)) { + current->signal &= ~ALRMMASK; + break; + } + if (current->signal) + break; + if (EMPTY(tty->secondary) || (L_CANON(tty) && + !tty->secondary.data && LEFT(tty->secondary)>20)) { + sleep_if_empty(&tty->secondary); + continue; + } + do { + GETCH(tty->secondary,c); + if (c==EOF_CHAR(tty) || c==10) + tty->secondary.data--; + if (c==EOF_CHAR(tty) && L_CANON(tty)) + return (b-buf); + else { + put_fs_byte(c,b++); + if (!--nr) + break; + } + } while (nr>0 && !EMPTY(tty->secondary)); + if (time && !L_CANON(tty)) + if (flag=(!oldalarm || time+jiffiesalarm = time+jiffies; + else + current->alarm = oldalarm; + if (L_CANON(tty)) { + if (b-buf) + break; + } else if (b-buf >= minimum) + break; + } + current->alarm = oldalarm; + if (current->signal && !(b-buf)) + return -EINTR; + return (b-buf); +} + +int tty_write(unsigned channel, char * buf, int nr) +{ + static cr_flag=0; + struct tty_struct * tty; + char c, *b=buf; + + if (channel>2 || nr<0) return -1; + tty = channel + tty_table; + while (nr>0) { + sleep_if_full(&tty->write_q); + if (current->signal) + break; + while (nr>0 && !FULL(tty->write_q)) { + c=get_fs_byte(b); + if (O_POST(tty)) { + if (c=='\r' && O_CRNL(tty)) + c='\n'; + else if (c=='\n' && O_NLRET(tty)) + c='\r'; + if (c=='\n' && !cr_flag && O_NLCR(tty)) { + cr_flag = 1; + PUTCH(13,tty->write_q); + continue; + } + if (O_LCUC(tty)) + c=toupper(c); + } + b++; nr--; + cr_flag = 0; + PUTCH(c,tty->write_q); + } + tty->write(tty); + if (nr>0) + schedule(); + } + return (b-buf); +} + +/* + * Jeh, sometimes I really like the 386. + * This routine is called from an interrupt, + * and there should be absolutely no problem + * with sleeping even in an interrupt (I hope). + * Of course, if somebody proves me wrong, I'll + * hate intel for all time :-). We'll have to + * be careful and see to reinstating the interrupt + * chips before calling this, though. + * + * I don't think we sleep here under normal circumstances + * anyway, which is good, as the task sleeping might be + * totally innocent. + */ +void do_tty_interrupt(int tty) +{ + copy_to_cooked(tty_table+tty); +} + +void chr_dev_init(void) +{ +} diff --git a/linux/kernel/chr_drv/tty_ioctl.c b/linux/kernel/chr_drv/tty_ioctl.c new file mode 100644 index 0000000..e4e3745 --- /dev/null +++ b/linux/kernel/chr_drv/tty_ioctl.c @@ -0,0 +1,204 @@ +/* + * linux/kernel/chr_drv/tty_ioctl.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +static unsigned short quotient[] = { + 0, 2304, 1536, 1047, 857, + 768, 576, 384, 192, 96, + 64, 48, 24, 12, 6, 3 +}; + +static void change_speed(struct tty_struct * tty) +{ + unsigned short port,quot; + + if (!(port = tty->read_q.data)) + return; + quot = quotient[tty->termios.c_cflag & CBAUD]; + cli(); + outb_p(0x80,port+3); /* set DLAB */ + outb_p(quot & 0xff,port); /* LS of divisor */ + outb_p(quot >> 8,port+1); /* MS of divisor */ + outb(0x03,port+3); /* reset DLAB */ + sti(); +} + +static void flush(struct tty_queue * queue) +{ + cli(); + queue->head = queue->tail; + sti(); +} + +static void wait_until_sent(struct tty_struct * tty) +{ + /* do nothing - not implemented */ +} + +static void send_break(struct tty_struct * tty) +{ + /* do nothing - not implemented */ +} + +static int get_termios(struct tty_struct * tty, struct termios * termios) +{ + int i; + + verify_area(termios, sizeof (*termios)); + for (i=0 ; i< (sizeof (*termios)) ; i++) + put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios ); + return 0; +} + +static int set_termios(struct tty_struct * tty, struct termios * termios) +{ + int i; + + for (i=0 ; i< (sizeof (*termios)) ; i++) + ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios); + change_speed(tty); + return 0; +} + +static int get_termio(struct tty_struct * tty, struct termio * termio) +{ + int i; + struct termio tmp_termio; + + verify_area(termio, sizeof (*termio)); + tmp_termio.c_iflag = tty->termios.c_iflag; + tmp_termio.c_oflag = tty->termios.c_oflag; + tmp_termio.c_cflag = tty->termios.c_cflag; + tmp_termio.c_lflag = tty->termios.c_lflag; + tmp_termio.c_line = tty->termios.c_line; + for(i=0 ; i < NCC ; i++) + tmp_termio.c_cc[i] = tty->termios.c_cc[i]; + for (i=0 ; i< (sizeof (*termio)) ; i++) + put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio ); + return 0; +} + +/* + * This only works as the 386 is low-byt-first + */ +static int set_termio(struct tty_struct * tty, struct termio * termio) +{ + int i; + struct termio tmp_termio; + + for (i=0 ; i< (sizeof (*termio)) ; i++) + ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio); + *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag; + *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag; + *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag; + *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag; + tty->termios.c_line = tmp_termio.c_line; + for(i=0 ; i < NCC ; i++) + tty->termios.c_cc[i] = tmp_termio.c_cc[i]; + change_speed(tty); + return 0; +} + +int tty_ioctl(int dev, int cmd, int arg) +{ + struct tty_struct * tty; + if (MAJOR(dev) == 5) { + dev=current->tty; + if (dev<0) + panic("tty_ioctl: dev<0"); + } else + dev=MINOR(dev); + tty = dev + tty_table; + switch (cmd) { + case TCGETS: + return get_termios(tty,(struct termios *) arg); + case TCSETSF: + flush(&tty->read_q); /* fallthrough */ + case TCSETSW: + wait_until_sent(tty); /* fallthrough */ + case TCSETS: + return set_termios(tty,(struct termios *) arg); + case TCGETA: + return get_termio(tty,(struct termio *) arg); + case TCSETAF: + flush(&tty->read_q); /* fallthrough */ + case TCSETAW: + wait_until_sent(tty); /* fallthrough */ + case TCSETA: + return set_termio(tty,(struct termio *) arg); + case TCSBRK: + if (!arg) { + wait_until_sent(tty); + send_break(tty); + } + return 0; + case TCXONC: + return -EINVAL; /* not implemented */ + case TCFLSH: + if (arg==0) + flush(&tty->read_q); + else if (arg==1) + flush(&tty->write_q); + else if (arg==2) { + flush(&tty->read_q); + flush(&tty->write_q); + } else + return -EINVAL; + return 0; + case TIOCEXCL: + return -EINVAL; /* not implemented */ + case TIOCNXCL: + return -EINVAL; /* not implemented */ + case TIOCSCTTY: + return -EINVAL; /* set controlling term NI */ + case TIOCGPGRP: + verify_area((void *) arg,4); + put_fs_long(tty->pgrp,(unsigned long *) arg); + return 0; + case TIOCSPGRP: + tty->pgrp=get_fs_long((unsigned long *) arg); + return 0; + case TIOCOUTQ: + verify_area((void *) arg,4); + put_fs_long(CHARS(tty->write_q),(unsigned long *) arg); + return 0; + case TIOCINQ: + verify_area((void *) arg,4); + put_fs_long(CHARS(tty->secondary), + (unsigned long *) arg); + return 0; + case TIOCSTI: + return -EINVAL; /* not implemented */ + case TIOCGWINSZ: + return -EINVAL; /* not implemented */ + case TIOCSWINSZ: + return -EINVAL; /* not implemented */ + case TIOCMGET: + return -EINVAL; /* not implemented */ + case TIOCMBIS: + return -EINVAL; /* not implemented */ + case TIOCMBIC: + return -EINVAL; /* not implemented */ + case TIOCMSET: + return -EINVAL; /* not implemented */ + case TIOCGSOFTCAR: + return -EINVAL; /* not implemented */ + case TIOCSSOFTCAR: + return -EINVAL; /* not implemented */ + default: + return -EINVAL; + } +} diff --git a/linux/kernel/exit.c b/linux/kernel/exit.c new file mode 100644 index 0000000..2406ebe --- /dev/null +++ b/linux/kernel/exit.c @@ -0,0 +1,197 @@ +/* + * linux/kernel/exit.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include +#include +#include + +int sys_pause(void); +int sys_close(int fd); + +void release(struct task_struct * p) +{ + int i; + + if (!p) + return; + for (i=1 ; i32) + return -EINVAL; + if (priv || (current->euid==p->euid) || suser()) + p->signal |= (1<<(sig-1)); + else + return -EPERM; + return 0; +} + +static void kill_session(void) +{ + struct task_struct **p = NR_TASKS + task; + + while (--p > &FIRST_TASK) { + if (*p && (*p)->session == current->session) + (*p)->signal |= 1<<(SIGHUP-1); + } +} + +/* + * XXX need to check permissions needed to send signals to process + * groups, etc. etc. kill() permissions semantics are tricky! + */ +int sys_kill(int pid,int sig) +{ + struct task_struct **p = NR_TASKS + task; + int err, retval = 0; + + if (!pid) while (--p > &FIRST_TASK) { + if (*p && (*p)->pgrp == current->pid) + if (err=send_sig(sig,*p,1)) + retval = err; + } else if (pid>0) while (--p > &FIRST_TASK) { + if (*p && (*p)->pid == pid) + if (err=send_sig(sig,*p,0)) + retval = err; + } else if (pid == -1) while (--p > &FIRST_TASK) + if (err = send_sig(sig,*p,0)) + retval = err; + else while (--p > &FIRST_TASK) + if (*p && (*p)->pgrp == -pid) + if (err = send_sig(sig,*p,0)) + retval = err; + return retval; +} + +static void tell_father(int pid) +{ + int i; + + if (pid) + for (i=0;ipid != pid) + continue; + task[i]->signal |= (1<<(SIGCHLD-1)); + return; + } +/* if we don't find any fathers, we just release ourselves */ +/* This is not really OK. Must change it to make father 1 */ + printk("BAD BAD - no father found\n\r"); + release(current); +} + +int do_exit(long code) +{ + int i; + + free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); + free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); + for (i=0 ; ifather == current->pid) { + task[i]->father = 1; + if (task[i]->state == TASK_ZOMBIE) + /* assumption task[1] is always init */ + (void) send_sig(SIGCHLD, task[1], 1); + } + for (i=0 ; ifilp[i]) + sys_close(i); + iput(current->pwd); + current->pwd=NULL; + iput(current->root); + current->root=NULL; + iput(current->executable); + current->executable=NULL; + if (current->leader && current->tty >= 0) + tty_table[current->tty].pgrp = 0; + if (last_task_used_math == current) + last_task_used_math = NULL; + if (current->leader) + kill_session(); + current->state = TASK_ZOMBIE; + current->exit_code = code; + tell_father(current->father); + schedule(); + return (-1); /* just to suppress warnings */ +} + +int sys_exit(int error_code) +{ + return do_exit((error_code&0xff)<<8); +} + +int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options) +{ + int flag, code; + struct task_struct ** p; + + verify_area(stat_addr,4); +repeat: + flag=0; + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if (!*p || *p == current) + continue; + if ((*p)->father != current->pid) + continue; + if (pid>0) { + if ((*p)->pid != pid) + continue; + } else if (!pid) { + if ((*p)->pgrp != current->pgrp) + continue; + } else if (pid != -1) { + if ((*p)->pgrp != -pid) + continue; + } + switch ((*p)->state) { + case TASK_STOPPED: + if (!(options & WUNTRACED)) + continue; + put_fs_long(0x7f,stat_addr); + return (*p)->pid; + case TASK_ZOMBIE: + current->cutime += (*p)->utime; + current->cstime += (*p)->stime; + flag = (*p)->pid; + code = (*p)->exit_code; + release(*p); + put_fs_long(code,stat_addr); + return flag; + default: + flag=1; + continue; + } + } + if (flag) { + if (options & WNOHANG) + return 0; + current->state=TASK_INTERRUPTIBLE; + schedule(); + if (!(current->signal &= ~(1<<(SIGCHLD-1)))) + goto repeat; + else + return -EINTR; + } + return -ECHILD; +} + + diff --git a/linux/kernel/fork.c b/linux/kernel/fork.c new file mode 100644 index 0000000..816fdba --- /dev/null +++ b/linux/kernel/fork.c @@ -0,0 +1,148 @@ +/* + * linux/kernel/fork.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'fork.c' contains the help-routines for the 'fork' system call + * (see also system_call.s), and some misc functions ('verify_area'). + * Fork is rather simple, once you get the hang of it, but the memory + * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()' + */ +#include + +#include +#include +#include +#include + +extern void write_verify(unsigned long address); + +long last_pid=0; + +void verify_area(void * addr,int size) +{ + unsigned long start; + + start = (unsigned long) addr; + size += start & 0xfff; + start &= 0xfffff000; + start += get_base(current->ldt[2]); + while (size>0) { + size -= 4096; + write_verify(start); + start += 4096; + } +} + +int copy_mem(int nr,struct task_struct * p) +{ + unsigned long old_data_base,new_data_base,data_limit; + unsigned long old_code_base,new_code_base,code_limit; + + code_limit=get_limit(0x0f); + data_limit=get_limit(0x17); + old_code_base = get_base(current->ldt[1]); + old_data_base = get_base(current->ldt[2]); + if (old_data_base != old_code_base) + panic("We don't support separate I&D"); + if (data_limit < code_limit) + panic("Bad data_limit"); + new_data_base = new_code_base = nr * 0x4000000; + p->start_code = new_code_base; + set_base(p->ldt[1],new_code_base); + set_base(p->ldt[2],new_data_base); + if (copy_page_tables(old_data_base,new_data_base,data_limit)) { + free_page_tables(new_data_base,data_limit); + return -ENOMEM; + } + return 0; +} + +/* + * Ok, this is the main fork-routine. It copies the system process + * information (task[nr]) and sets up the necessary registers. It + * also copies the data segment in it's entirety. + */ +int copy_process(int nr,long ebp,long edi,long esi,long gs,long none, + long ebx,long ecx,long edx, + long fs,long es,long ds, + long eip,long cs,long eflags,long esp,long ss) +{ + struct task_struct *p; + int i; + struct file *f; + + p = (struct task_struct *) get_free_page(); + if (!p) + return -EAGAIN; + task[nr] = p; + __asm__ volatile ("cld"); /* by wyj */ + *p = *current; /* NOTE! this doesn't copy the supervisor stack */ + p->state = TASK_UNINTERRUPTIBLE; + p->pid = last_pid; + p->father = current->pid; + p->counter = p->priority; + p->signal = 0; + p->alarm = 0; + p->leader = 0; /* process leadership doesn't inherit */ + p->utime = p->stime = 0; + p->cutime = p->cstime = 0; + p->start_time = jiffies; + p->tss.back_link = 0; + p->tss.esp0 = PAGE_SIZE + (long) p; + p->tss.ss0 = 0x10; + p->tss.eip = eip; + p->tss.eflags = eflags; + p->tss.eax = 0; + p->tss.ecx = ecx; + p->tss.edx = edx; + p->tss.ebx = ebx; + p->tss.esp = esp; + p->tss.ebp = ebp; + p->tss.esi = esi; + p->tss.edi = edi; + p->tss.es = es & 0xffff; + p->tss.cs = cs & 0xffff; + p->tss.ss = ss & 0xffff; + p->tss.ds = ds & 0xffff; + p->tss.fs = fs & 0xffff; + p->tss.gs = gs & 0xffff; + p->tss.ldt = _LDT(nr); + p->tss.trace_bitmap = 0x80000000; + if (last_task_used_math == current) + __asm__("clts ; fnsave %0"::"m" (p->tss.i387)); + if (copy_mem(nr,p)) { + task[nr] = NULL; + free_page((long) p); + return -EAGAIN; + } + for (i=0; ifilp[i]) + f->f_count++; + if (current->pwd) + current->pwd->i_count++; + if (current->root) + current->root->i_count++; + if (current->executable) + current->executable->i_count++; + set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss)); + set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt)); + p->state = TASK_RUNNING; /* do this last, just in case */ + return last_pid; +} + +int find_empty_process(void) +{ + int i; + + repeat: + if ((++last_pid)<0) last_pid=1; + for(i=0 ; ipid == last_pid) goto repeat; + for(i=1 ; i +#include +#include +#include +#include +#include +#include +struct linux_dirent { + long d_ino; + off_t d_off; + unsigned short d_reclen; + char d_name[14]; +}; + +int sys_getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count) +{ + struct m_inode *m_ino; + struct buffer_head *buff_hd; + struct dir_entry *dir; + struct linux_dirent usr; + int i, j, res; + i = 0; + res = 0; + m_ino = current->filp[fd]->f_inode; + buff_hd = bread(m_ino->i_dev, m_ino->i_zone[0]); + dir = (struct dir_entry *)buff_hd->b_data; + while (dir[i].inode > 0) + { + if (res + sizeof(struct linux_dirent) > count) + break; + usr.d_ino = dir[i].inode; + usr.d_off = 0; + usr.d_reclen = sizeof(struct linux_dirent); + for (j = 0; j < 14; j++) + { + usr.d_name[j] = dir[i].name[j]; + } + for(j = 0;j tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: diff --git a/linux/kernel/math/math_emulate.c b/linux/kernel/math/math_emulate.c new file mode 100644 index 0000000..825e528 --- /dev/null +++ b/linux/kernel/math/math_emulate.c @@ -0,0 +1,42 @@ +/* + * linux/kernel/math/math_emulate.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This directory should contain the math-emulation code. + * Currently only results in a signal. + */ + +#include + +#include +#include +#include + +void math_emulate(long edi, long esi, long ebp, long sys_call_ret, + long eax,long ebx,long ecx,long edx, + unsigned short fs,unsigned short es,unsigned short ds, + unsigned long eip,unsigned short cs,unsigned long eflags, + unsigned short ss, unsigned long esp) +{ + unsigned char first, second; + +/* 0x0007 means user code space */ + if (cs != 0x000F) { + printk("math_emulate: %04x:%08x\n\r",cs,eip); + panic("Math emulation needed in kernel"); + } + first = get_fs_byte((char *)((*&eip)++)); + second = get_fs_byte((char *)((*&eip)++)); + printk("%04x:%08x %02x %02x\n\r",cs,eip-2,first,second); + current->signal |= 1<<(SIGFPE-1); +} + +void math_error(void) +{ + __asm__("fnclex"); + if (last_task_used_math) + last_task_used_math->signal |= 1<<(SIGFPE-1); +} diff --git a/linux/kernel/mktime.c b/linux/kernel/mktime.c new file mode 100644 index 0000000..a6d03ca --- /dev/null +++ b/linux/kernel/mktime.c @@ -0,0 +1,58 @@ +/* + * linux/kernel/mktime.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +/* + * This isn't the library routine, it is only used in the kernel. + * as such, we don't care about years<1970 etc, but assume everything + * is ok. Similarly, TZ etc is happily ignored. We just do everything + * as easily as possible. Let's find something public for the library + * routines (although I think minix times is public). + */ +/* + * PS. I hate whoever though up the year 1970 - couldn't they have gotten + * a leap-year instead? I also hate Gregorius, pope or no. I'm grumpy. + */ +#define MINUTE 60 +#define HOUR (60*MINUTE) +#define DAY (24*HOUR) +#define YEAR (365*DAY) + +/* interestingly, we assume leap-years */ +static int month[12] = { + 0, + DAY*(31), + DAY*(31+29), + DAY*(31+29+31), + DAY*(31+29+31+30), + DAY*(31+29+31+30+31), + DAY*(31+29+31+30+31+30), + DAY*(31+29+31+30+31+30+31), + DAY*(31+29+31+30+31+30+31+31), + DAY*(31+29+31+30+31+30+31+31+30), + DAY*(31+29+31+30+31+30+31+31+30+31), + DAY*(31+29+31+30+31+30+31+31+30+31+30) +}; + +long kernel_mktime(struct tm * tm) +{ + long res; + int year; + if (tm->tm_year < 70 ) tm->tm_year += 100; /* gohigh */ + year = tm->tm_year - 70; +/* magic offsets (y+1) needed to get leapyears right.*/ + res = YEAR*year + DAY*((year+1)/4); + res += month[tm->tm_mon]; +/* and (y+2) here. If it wasn't a leap-year, we have to adjust */ + if (tm->tm_mon>1 && ((year+2)%4)) + res -= DAY; + res += DAY*(tm->tm_mday-1); + res += HOUR*tm->tm_hour; + res += MINUTE*tm->tm_min; + res += tm->tm_sec; + return res; +} diff --git a/linux/kernel/panic.c b/linux/kernel/panic.c new file mode 100644 index 0000000..7d8a06b --- /dev/null +++ b/linux/kernel/panic.c @@ -0,0 +1,24 @@ +/* + * linux/kernel/panic.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This function is used through-out the kernel (includeinh mm and fs) + * to indicate a major problem. + */ +#include +#include + +void sys_sync(void); /* it's really int */ + +volatile void panic(const char * s) +{ + printk("Kernel panic: %s\n\r",s); + if (current == task[0]) + printk("In swapper task - not syncing\n\r"); + else + sys_sync(); + for(;;); +} diff --git a/linux/kernel/pipe2.c b/linux/kernel/pipe2.c new file mode 100644 index 0000000..54f9a3c --- /dev/null +++ b/linux/kernel/pipe2.c @@ -0,0 +1,12 @@ +#define __LIBRARY__ +#include +#include +#include +#include +#include +#include +#include + +int sys_pipe2(int fd[2], int flags){ + return sys_pipe(fd); +} \ No newline at end of file diff --git a/linux/kernel/printk.c b/linux/kernel/printk.c new file mode 100644 index 0000000..0daa097 --- /dev/null +++ b/linux/kernel/printk.c @@ -0,0 +1,41 @@ +/* + * linux/kernel/printk.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * When in kernel-mode, we cannot use printf, as fs is liable to + * point to 'interesting' things. Make a printf with fs-saving, and + * all is well. + */ +#include +#include + +#include + +static char buf[1024]; + +extern int vsprintf(char * buf, const char * fmt, va_list args); + +int printk(const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + __asm__("push %%fs\n\t" + "push %%ds\n\t" + "pop %%fs\n\t" + "pushl %0\n\t" + "pushl $buf\n\t" + "pushl $0\n\t" + "call tty_write\n\t" + "addl $8,%%esp\n\t" + "popl %0\n\t" + "pop %%fs" + ::"r" (i):"ax","cx","dx"); + return i; +} diff --git a/linux/kernel/sched.c b/linux/kernel/sched.c new file mode 100644 index 0000000..15d839b --- /dev/null +++ b/linux/kernel/sched.c @@ -0,0 +1,412 @@ +/* + * linux/kernel/sched.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'sched.c' is the main kernel file. It contains scheduling primitives + * (sleep_on, wakeup, schedule etc) as well as a number of simple system + * call functions (type getpid(), which just extracts a field from + * current-task + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#define _S(nr) (1<<((nr)-1)) +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + +void show_task(int nr,struct task_struct * p) +{ + int i,j = 4096-sizeof(struct task_struct); + + printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state); + i=0; + while (i>2 ] ; + +struct { + long * a; + short b; + } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 }; +/* + * 'math_state_restore()' saves the current math information in the + * old math state array, and gets the new ones from the current task + */ +void math_state_restore() +{ + if (last_task_used_math == current) + return; + __asm__("fwait"); + if (last_task_used_math) { + __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387)); + } + last_task_used_math=current; + if (current->used_math) { + __asm__("frstor %0"::"m" (current->tss.i387)); + } else { + __asm__("fninit"::); + current->used_math=1; + } +} + +/* + * 'schedule()' is the scheduler function. This is GOOD CODE! There + * probably won't be any reason to change this, as it should work well + * in all circumstances (ie gives IO-bound processes good response etc). + * The one thing you might take a look at is the signal-handler code here. + * + * NOTE!! Task 0 is the 'idle' task, which gets called when no other + * tasks can run. It can not be killed, and it cannot sleep. The 'state' + * information in task[0] is never used. + */ +void schedule(void) +{ + int i,next,c; + struct task_struct ** p; + +/* check alarm, wake up any interruptible tasks that have got a signal */ + + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if (*p) { + if ((*p)->alarm && (*p)->alarm < jiffies) { + (*p)->signal |= (1<<(SIGALRM-1)); + (*p)->alarm = 0; + } + if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) && + (*p)->state==TASK_INTERRUPTIBLE) + (*p)->state=TASK_RUNNING; + } + +/* this is the scheduler proper: */ + + while (1) { + c = -1; + next = 0; + i = NR_TASKS; + p = &task[NR_TASKS]; + while (--i) { + if (!*--p) + continue; + if ((*p)->state == TASK_RUNNING && (*p)->counter > c) + c = (*p)->counter, next = i; + } + if (c) break; + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if (*p) + (*p)->counter = ((*p)->counter >> 1) + + (*p)->priority; + } + switch_to(next); +} + +int sys_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return 0; +} + +void sleep_on(struct task_struct **p) +{ + struct task_struct *tmp; + + if (!p) + return; + if (current == &(init_task.task)) + panic("task[0] trying to sleep"); + tmp = *p; + *p = current; + current->state = TASK_UNINTERRUPTIBLE; + schedule(); + if (tmp) + tmp->state=0; +} + +void interruptible_sleep_on(struct task_struct **p) +{ + struct task_struct *tmp; + + if (!p) + return; + if (current == &(init_task.task)) + panic("task[0] trying to sleep"); + tmp=*p; + *p=current; +repeat: current->state = TASK_INTERRUPTIBLE; + schedule(); + if (*p && *p != current) { + (**p).state=0; + goto repeat; + } + *p=NULL; + if (tmp) + tmp->state=0; +} + +void wake_up(struct task_struct **p) +{ + if (p && *p) { + (**p).state=0; + *p=NULL; + } +} + +/* + * OK, here are some floppy things that shouldn't be in the kernel + * proper. They are here because the floppy needs a timer, and this + * was the easiest way of doing it. + */ +static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL}; +static int mon_timer[4]={0,0,0,0}; +static int moff_timer[4]={0,0,0,0}; +unsigned char current_DOR = 0x0C; + +int ticks_to_floppy_on(unsigned int nr) +{ + extern unsigned char selected; + unsigned char mask = 0x10 << nr; + + if (nr>3) + panic("floppy_on: nr>3"); + moff_timer[nr]=10000; /* 100 s = very big :-) */ + cli(); /* use floppy_off to turn it off */ + mask |= current_DOR; + if (!selected) { + mask &= 0xFC; + mask |= nr; + } + if (mask != current_DOR) { + outb(mask,FD_DOR); + if ((mask ^ current_DOR) & 0xf0) + mon_timer[nr] = HZ/2; + else if (mon_timer[nr] < 2) + mon_timer[nr] = 2; + current_DOR = mask; + } + sti(); + return mon_timer[nr]; +} + +void floppy_on(unsigned int nr) +{ + cli(); + while (ticks_to_floppy_on(nr)) + sleep_on(nr+wait_motor); + sti(); +} + +void floppy_off(unsigned int nr) +{ + moff_timer[nr]=3*HZ; +} + +void do_floppy_timer(void) +{ + int i; + unsigned char mask = 0x10; + + for (i=0 ; i<4 ; i++,mask <<= 1) { + if (!(mask & current_DOR)) + continue; + if (mon_timer[i]) { + if (!--mon_timer[i]) + wake_up(i+wait_motor); + } else if (!moff_timer[i]) { + current_DOR &= ~mask; + outb(current_DOR,FD_DOR); + } else + moff_timer[i]--; + } +} + +#define TIME_REQUESTS 64 + +static struct timer_list { + long jiffies; + void (*fn)(); + struct timer_list * next; +} timer_list[TIME_REQUESTS], * next_timer = NULL; + +void add_timer(long jiffies, void (*fn)(void)) +{ + struct timer_list * p; + + if (!fn) + return; + cli(); + if (jiffies <= 0) + (fn)(); + else { + for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++) + if (!p->fn) + break; + if (p >= timer_list + TIME_REQUESTS) + panic("No more time requests free"); + p->fn = fn; + p->jiffies = jiffies; + p->next = next_timer; + next_timer = p; + while (p->next && p->next->jiffies < p->jiffies) { + p->jiffies -= p->next->jiffies; + fn = p->fn; + p->fn = p->next->fn; + p->next->fn = fn; + jiffies = p->jiffies; + p->jiffies = p->next->jiffies; + p->next->jiffies = jiffies; + p = p->next; + } + } + sti(); +} + +void do_timer(long cpl) +{ + extern int beepcount; + extern void sysbeepstop(void); + + if (beepcount) + if (!--beepcount) + sysbeepstop(); + + if (cpl) + current->utime++; + else + current->stime++; + + if (next_timer) { + next_timer->jiffies--; + while (next_timer && next_timer->jiffies <= 0) { + void (*fn)(void); + + fn = next_timer->fn; + next_timer->fn = NULL; + next_timer = next_timer->next; + (fn)(); + } + } + if (current_DOR & 0xf0) + do_floppy_timer(); + if ((--current->counter)>0) return; + current->counter=0; + if (!cpl) return; + schedule(); +} + +int sys_alarm(long seconds) +{ + int old = current->alarm; + + if (old) + old = (old - jiffies) / HZ; + current->alarm = (seconds>0)?(jiffies+HZ*seconds):0; + return (old); +} + +int sys_getpid(void) +{ + return current->pid; +} + +int sys_getppid(void) +{ + return current->father; +} + +int sys_getuid(void) +{ + return current->uid; +} + +int sys_geteuid(void) +{ + return current->euid; +} + +int sys_getgid(void) +{ + return current->gid; +} + +int sys_getegid(void) +{ + return current->egid; +} + +int sys_nice(long increment) +{ + if (current->priority-increment>0) + current->priority -= increment; + return 0; +} + +void sched_init(void) +{ + int i; + struct desc_struct * p; + + if (sizeof(struct sigaction) != 16) + panic("Struct sigaction MUST be 16 bytes"); + set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); + set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); + p = gdt+2+FIRST_TSS_ENTRY; + for(i=1;ia=p->b=0; + p++; + p->a=p->b=0; + p++; + } +/* Clear NT, so that we won't have troubles with that later on */ + __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); + ltr(0); + lldt(0); + outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */ + outb_p(LATCH & 0xff , 0x40); /* LSB */ + outb(LATCH >> 8 , 0x40); /* MSB */ + set_intr_gate(0x20,&timer_interrupt); + outb(inb_p(0x21)&~0x01,0x21); + set_system_gate(0x80,&system_call); +} diff --git a/linux/kernel/signal.c b/linux/kernel/signal.c new file mode 100644 index 0000000..8d5a65f --- /dev/null +++ b/linux/kernel/signal.c @@ -0,0 +1,129 @@ +/* + * linux/kernel/signal.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include +#include +#include + +volatile void do_exit(int error_code); + +int sys_sgetmask() +{ + return current->blocked; +} + +int sys_ssetmask(int newmask) +{ + int old=current->blocked; + + current->blocked = newmask & ~(1<<(SIGKILL-1)); + return old; +} + +int sys_sigpending() +{ + return -ENOSYS; +} + +int sys_sigsuspend() +{ + return -ENOSYS; +} + +static inline void save_old(char * from,char * to) +{ + int i; + + verify_area(to, sizeof(struct sigaction)); + for (i=0 ; i< sizeof(struct sigaction) ; i++) { + put_fs_byte(*from,to); + from++; + to++; + } +} + +static inline void get_new(char * from,char * to) +{ + int i; + + for (i=0 ; i< sizeof(struct sigaction) ; i++) + *(to++) = get_fs_byte(from++); +} + +int sys_signal(int signum, long handler, long restorer) +{ + struct sigaction tmp; + + if (signum<1 || signum>32 || signum==SIGKILL) + return -1; + tmp.sa_handler = (void (*)(int)) handler; + tmp.sa_mask = 0; + tmp.sa_flags = SA_ONESHOT | SA_NOMASK; + tmp.sa_restorer = (void (*)(void)) restorer; + handler = (long) current->sigaction[signum-1].sa_handler; + current->sigaction[signum-1] = tmp; + return handler; +} + +int sys_sigaction(int signum, const struct sigaction * action, + struct sigaction * oldaction) +{ + struct sigaction tmp; + + if (signum<1 || signum>32 || signum==SIGKILL) + return -1; + tmp = current->sigaction[signum-1]; + get_new((char *) action, + (char *) (signum-1+current->sigaction)); + if (oldaction) + save_old((char *) &tmp,(char *) oldaction); + if (current->sigaction[signum-1].sa_flags & SA_NOMASK) + current->sigaction[signum-1].sa_mask = 0; + else + current->sigaction[signum-1].sa_mask |= (1<<(signum-1)); + return 0; +} + +void do_signal(long signr,long eax, long ebx, long ecx, long edx, + long fs, long es, long ds, + long eip, long cs, long eflags, + unsigned long * esp, long ss) +{ + unsigned long sa_handler; + long old_eip=eip; + struct sigaction * sa = current->sigaction + signr - 1; + int longs; + unsigned long * tmp_esp; + + sa_handler = (unsigned long) sa->sa_handler; + if (sa_handler==1) + return; + if (!sa_handler) { + if (signr==SIGCHLD) + return; + else + do_exit(1<<(signr-1)); + } + if (sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; + *(&eip) = sa_handler; + longs = (sa->sa_flags & SA_NOMASK)?7:8; + *(&esp) -= longs; + verify_area(esp,longs*4); + tmp_esp=esp; + put_fs_long((long) sa->sa_restorer,tmp_esp++); + put_fs_long(signr,tmp_esp++); + if (!(sa->sa_flags & SA_NOMASK)) + put_fs_long(current->blocked,tmp_esp++); + put_fs_long(eax,tmp_esp++); + put_fs_long(ecx,tmp_esp++); + put_fs_long(edx,tmp_esp++); + put_fs_long(eflags,tmp_esp++); + put_fs_long(old_eip,tmp_esp++); + current->blocked |= sa->sa_mask; +} diff --git a/linux/kernel/sleep.c b/linux/kernel/sleep.c new file mode 100644 index 0000000..31dfeee --- /dev/null +++ b/linux/kernel/sleep.c @@ -0,0 +1,16 @@ +#define __LIBRARY__ +#include +#include +#include +#include +#include +#include +#include + +int sys_sleep(unsigned int seconds) +{ + sys_signal(SIGALRM, SIG_IGN, NULL); + sys_alarm(seconds); + sys_pause(); + return 0; +} \ No newline at end of file diff --git a/linux/kernel/sys.c b/linux/kernel/sys.c new file mode 100644 index 0000000..695f287 --- /dev/null +++ b/linux/kernel/sys.c @@ -0,0 +1,292 @@ +/* + * linux/kernel/sys.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include +#include +#include +#include +#include + +int sys_ftime() +{ + return -ENOSYS; +} + +int sys_break() +{ + return -ENOSYS; +} + +int sys_ptrace() +{ + return -ENOSYS; +} + +int sys_stty() +{ + return -ENOSYS; +} + +int sys_gtty() +{ + return -ENOSYS; +} + +int sys_rename() +{ + return -ENOSYS; +} + +int sys_prof() +{ + return -ENOSYS; +} + +int sys_setregid(int rgid, int egid) +{ + if (rgid>0) { + if ((current->gid == rgid) || + suser()) + current->gid = rgid; + else + return(-EPERM); + } + if (egid>0) { + if ((current->gid == egid) || + (current->egid == egid) || + suser()) { + current->egid = egid; + current->sgid = egid; + } else + return(-EPERM); + } + return 0; +} + +int sys_setgid(int gid) +{ +/* return(sys_setregid(gid, gid)); */ + if (suser()) + current->gid = current->egid = current->sgid = gid; + else if ((gid == current->gid) || (gid == current->sgid)) + current->egid = gid; + else + return -EPERM; + return 0; +} + +int sys_acct() +{ + return -ENOSYS; +} + +int sys_phys() +{ + return -ENOSYS; +} + +int sys_lock() +{ + return -ENOSYS; +} + +int sys_mpx() +{ + return -ENOSYS; +} + +int sys_ulimit() +{ + return -ENOSYS; +} + +int sys_time(long * tloc) +{ + int i; + + i = CURRENT_TIME; + if (tloc) { + verify_area(tloc,4); + put_fs_long(i,(unsigned long *)tloc); + } + return i; +} + +/* + * Unprivileged users may change the real user id to the effective uid + * or vice versa. + */ +int sys_setreuid(int ruid, int euid) +{ + int old_ruid = current->uid; + + if (ruid>0) { + if ((current->euid==ruid) || + (old_ruid == ruid) || + suser()) + current->uid = ruid; + else + return(-EPERM); + } + if (euid>0) { + if ((old_ruid == euid) || + (current->euid == euid) || + suser()) { + current->euid = euid; + current->suid = euid; + } else { + current->uid = old_ruid; + return(-EPERM); + } + } + return 0; +} + +int sys_setuid(int uid) +{ +/* return(sys_setreuid(uid, uid)); */ + if (suser()) + current->uid = current->euid = current->suid = uid; + else if ((uid == current->uid) || (uid == current->suid)) + current->euid = uid; + else + return -EPERM; + return(0); +} + +int sys_stime(long * tptr) +{ + if (!suser()) + return -EPERM; + startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ; + return 0; +} + +int sys_times(struct tms * tbuf) +{ + if (tbuf) { + verify_area(tbuf,sizeof *tbuf); + put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime); + put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime); + put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime); + put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime); + } + return jiffies; +} + +int sys_brk(unsigned long end_data_seg) +{ + if (end_data_seg >= current->end_code && + end_data_seg < current->start_stack - 16384) + current->brk = end_data_seg; + return current->brk; +} + +/* + * This needs some heave checking ... + * I just haven't get the stomach for it. I also don't fully + * understand sessions/pgrp etc. Let somebody who does explain it. + */ +int sys_setpgid(int pid, int pgid) +{ + int i; + + if (!pid) + pid = current->pid; + if (!pgid) + pgid = current->pid; + for (i=0 ; ipid==pid) { + if (task[i]->leader) + return -EPERM; + if (task[i]->session != current->session) + return -EPERM; + task[i]->pgrp = pgid; + return 0; + } + return -ESRCH; +} + +int sys_getpgrp(void) +{ + return current->pgrp; +} + +int sys_setsid(void) +{ + if (current->leader && !suser()) + return -EPERM; + current->leader = 1; + current->session = current->pgrp = current->pid; + current->tty = -1; + return current->pgrp; +} + +int sys_getgroups() +{ + return -ENOSYS; +} + +int sys_setgroups() +{ + return -ENOSYS; +} + +int sys_uname(struct utsname * name) +{ + static struct utsname thisname = { + "linux .0","nodename","release ","version ","machine " + }; + int i; + + if (!name) return -ERROR; + verify_area(name,sizeof *name); + for(i=0;iumask; + + current->umask = mask & 0777; + return (old); +} diff --git a/linux/kernel/system_call.s b/linux/kernel/system_call.s new file mode 100644 index 0000000..d19ec60 --- /dev/null +++ b/linux/kernel/system_call.s @@ -0,0 +1,296 @@ +/* + * linux/kernel/system_call.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * system_call.s contains the system-call low-level handling routines. + * This also contains the timer-interrupt handler, as some of the code is + * the same. The hd- and flopppy-interrupts are also here. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. Ordinary interrupts + * don't handle signal-recognition, as that would clutter them up totally + * unnecessarily. + * + * Stack layout in 'ret_from_system_call': + * + * 0(%esp) - %eax + * 4(%esp) - %ebx + * 8(%esp) - %ecx + * C(%esp) - %edx + * 10(%esp) - %fs + * 14(%esp) - %es + * 18(%esp) - %ds + * 1C(%esp) - %eip + * 20(%esp) - %cs + * 24(%esp) - %eflags + * 28(%esp) - %oldesp + * 2C(%esp) - %oldss + */ + +SIG_CHLD = 17 + +EAX = 0x00 +EBX = 0x04 +ECX = 0x08 +EDX = 0x0C +FS = 0x10 +ES = 0x14 +DS = 0x18 +EIP = 0x1C +CS = 0x20 +EFLAGS = 0x24 +OLDESP = 0x28 +OLDSS = 0x2C + +state = 0 # these are offsets into the task-struct. +counter = 4 +priority = 8 +signal = 12 +sigaction = 16 # MUST be 16 (=len of sigaction) +blocked = (33*16) + +# offsets within sigaction +sa_handler = 0 +sa_mask = 4 +sa_flags = 8 +sa_restorer = 12 + +nr_system_calls = 94 /* 72 */ + +/* + * Ok, I get parallel printer interrupts while using the floppy for some + * strange reason. Urgel. Now I just ignore them. + */ +.globl system_call,sys_fork,timer_interrupt,sys_execve,sys_execve2 +.globl hd_interrupt,floppy_interrupt,parallel_interrupt +.globl device_not_available, coprocessor_error + +.align 4 +bad_sys_call: + movl $-1,%eax + iret +.align 4 +reschedule: + pushl $ret_from_sys_call + jmp schedule +.align 4 +system_call: + cmpl $nr_system_calls-1,%eax + ja bad_sys_call + push %ds + push %es + push %fs + pushl %edx + pushl %ecx # push %ebx,%ecx,%edx as parameters + pushl %ebx # to the system call + movl $0x10,%edx # set up ds,es to kernel space + mov %dx,%ds + mov %dx,%es + movl $0x17,%edx # fs points to local data space + mov %dx,%fs + + + + call sys_call_table(,%eax,4) + pushl %eax + movl current,%eax + cmpl $0,state(%eax) # state + jne reschedule + cmpl $0,counter(%eax) # counter + je reschedule +ret_from_sys_call: + movl current,%eax # task[0] cannot have signals + cmpl task,%eax + je 3f + cmpw $0x0f,CS(%esp) # was old code segment supervisor ? + jne 3f + cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ? + jne 3f + movl signal(%eax),%ebx + movl blocked(%eax),%ecx + notl %ecx + andl %ebx,%ecx + bsfl %ecx,%ecx + je 3f + btrl %ecx,%ebx + movl %ebx,signal(%eax) + incl %ecx + pushl %ecx + call do_signal + popl %eax +3: popl %eax + popl %ebx + popl %ecx + popl %edx + pop %fs + pop %es + pop %ds + iret + +.align 4 +coprocessor_error: + push %ds + push %es + push %fs + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + pushl $ret_from_sys_call + jmp math_error + +.align 2 +device_not_available: + push %ds + push %es + push %fs + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + pushl $ret_from_sys_call + clts # clear TS so that we can use math + movl %cr0,%eax + testl $0x4,%eax # EM (math emulation bit) + je math_state_restore + pushl %ebp + pushl %esi + pushl %edi + call math_emulate + popl %edi + popl %esi + popl %ebp + ret + +.align 4 +timer_interrupt: + push %ds # save ds,es and put kernel data space + push %es # into them. %fs is used by _system_call + push %fs + pushl %edx # we save %eax,%ecx,%edx as gcc doesn't + pushl %ecx # save those across function calls. %ebx + pushl %ebx # is saved as we use that in ret_sys_call + pushl %eax + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + incl jiffies + movb $0x20,%al # EOI to interrupt controller #1 + outb %al,$0x20 + movl CS(%esp),%eax + andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor) + pushl %eax + call do_timer # 'do_timer(long CPL)' does everything from + addl $4,%esp # task switching to accounting ... + jmp ret_from_sys_call + +.align 4 +sys_execve: + lea EIP(%esp),%eax + pushl %eax + call do_execve + addl $4,%esp + ret + +.align 4 +sys_execve2: + lea EIP(%esp),%eax + pushl %eax + call do_execve2 + addl $4,%esp + ret + +.align 4 +sys_fork: + call find_empty_process + testl %eax,%eax + js 1f + push %gs + pushl %esi + pushl %edi + pushl %ebp + pushl %eax + call copy_process + addl $20,%esp +1: ret + +hd_interrupt: + pushl %eax + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + movb $0x20,%al + outb %al,$0xA0 # EOI to interrupt controller #1 + jmp 1f # give port chance to breathe +1: jmp 1f +1: xorl %edx,%edx + xchgl do_hd,%edx + testl %edx,%edx + jne 1f + movl $unexpected_hd_interrupt,%edx +1: outb %al,$0x20 + call *%edx # "interesting" way of handling intr. + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +floppy_interrupt: + pushl %eax + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + movb $0x20,%al + outb %al,$0x20 # EOI to interrupt controller #1 + xorl %eax,%eax + xchgl do_floppy,%eax + testl %eax,%eax + jne 1f + movl $unexpected_floppy_interrupt,%eax +1: call *%eax # "interesting" way of handling intr. + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +parallel_interrupt: + pushl %eax + movb $0x20,%al + outb %al,$0x20 + popl %eax + iret diff --git a/linux/kernel/traps.c b/linux/kernel/traps.c new file mode 100644 index 0000000..f9bd8f1 --- /dev/null +++ b/linux/kernel/traps.c @@ -0,0 +1,208 @@ +/* + * linux/kernel/traps.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'asm.s'. Currently mostly a debugging-aid, will be extended + * to mainly kill the offending process (probably by giving it a signal, + * but possibly by killing it outright if necessary). + */ +#include + +#include +#include +#include +#include +#include +#include + +#define get_seg_byte(seg,addr) ({ \ +register char __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define get_seg_long(seg,addr) ({ \ +register unsigned long __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define _fs() ({ \ +register unsigned short __res; \ +__asm__("mov %%fs,%%ax":"=a" (__res):); \ +__res;}) + +int do_exit(long code); + +void page_exception(void); + +void divide_error(void); +void debug(void); +void nmi(void); +void int3(void); +void overflow(void); +void bounds(void); +void invalid_op(void); +void device_not_available(void); +void double_fault(void); +void coprocessor_segment_overrun(void); +void invalid_TSS(void); +void segment_not_present(void); +void stack_segment(void); +void general_protection(void); +void page_fault(void); +void coprocessor_error(void); +void reserved(void); +void parallel_interrupt(void); +void irq13(void); + +static void die(char * str,long esp_ptr,long nr) +{ + long * esp = (long *) esp_ptr; + int i; + + printk("%s: %04x\n\r",str,nr&0xffff); + printk("EIP:\t%04x:%p\nEFLAGS:\t%p\nESP:\t%04x:%p\n", + esp[1],esp[0],esp[2],esp[4],esp[3]); + printk("fs: %04x\n",_fs()); + printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x17)); + if (esp[4] == 0x17) { + printk("Stack: "); + for (i=0;i<4;i++) + printk("%p ",get_seg_long(0x17,i+(long *)esp[3])); + printk("\n"); + } + str(i); + printk("Pid: %d, process nr: %d\n\r",current->pid,0xffff & i); + for(i=0;i<10;i++) + printk("%02x ",0xff & get_seg_byte(esp[1],(i+(char *)esp[0]))); + printk("\n\r"); + do_exit(11); /* play segment exception */ +} + +void do_double_fault(long esp, long error_code) +{ + die("double fault",esp,error_code); +} + +void do_general_protection(long esp, long error_code) +{ + die("general protection",esp,error_code); +} + +void do_divide_error(long esp, long error_code) +{ + die("divide error",esp,error_code); +} + +void do_int3(long * esp, long error_code, + long fs,long es,long ds, + long ebp,long esi,long edi, + long edx,long ecx,long ebx,long eax) +{ + int tr; + + __asm__("str %%ax":"=a" (tr):"0" (0)); + printk("eax\t\tebx\t\tecx\t\tedx\n\r%8x\t%8x\t%8x\t%8x\n\r", + eax,ebx,ecx,edx); + printk("esi\t\tedi\t\tebp\t\tesp\n\r%8x\t%8x\t%8x\t%8x\n\r", + esi,edi,ebp,(long) esp); + printk("\n\rds\tes\tfs\ttr\n\r%4x\t%4x\t%4x\t%4x\n\r", + ds,es,fs,tr); + printk("EIP: %8x CS: %4x EFLAGS: %8x\n\r",esp[0],esp[1],esp[2]); +} + +void do_nmi(long esp, long error_code) +{ + die("nmi",esp,error_code); +} + +void do_debug(long esp, long error_code) +{ + die("debug",esp,error_code); +} + +void do_overflow(long esp, long error_code) +{ + die("overflow",esp,error_code); +} + +void do_bounds(long esp, long error_code) +{ + die("bounds",esp,error_code); +} + +void do_invalid_op(long esp, long error_code) +{ + die("invalid operand",esp,error_code); +} + +void do_device_not_available(long esp, long error_code) +{ + die("device not available",esp,error_code); +} + +void do_coprocessor_segment_overrun(long esp, long error_code) +{ + die("coprocessor segment overrun",esp,error_code); +} + +void do_invalid_TSS(long esp,long error_code) +{ + die("invalid TSS",esp,error_code); +} + +void do_segment_not_present(long esp,long error_code) +{ + die("segment not present",esp,error_code); +} + +void do_stack_segment(long esp,long error_code) +{ + die("stack segment",esp,error_code); +} + +void do_coprocessor_error(long esp, long error_code) +{ + if (last_task_used_math != current) + return; + die("coprocessor error",esp,error_code); +} + +void do_reserved(long esp, long error_code) +{ + die("reserved (15,17-47) error",esp,error_code); +} + +void trap_init(void) +{ + int i; + + set_trap_gate(0,÷_error); + set_trap_gate(1,&debug); + set_trap_gate(2,&nmi); + set_system_gate(3,&int3); /* int3-5 can be called from all */ + set_system_gate(4,&overflow); + set_system_gate(5,&bounds); + set_trap_gate(6,&invalid_op); + set_trap_gate(7,&device_not_available); + set_trap_gate(8,&double_fault); + set_trap_gate(9,&coprocessor_segment_overrun); + set_trap_gate(10,&invalid_TSS); + set_trap_gate(11,&segment_not_present); + set_trap_gate(12,&stack_segment); + set_trap_gate(13,&general_protection); + set_trap_gate(14,&page_fault); + set_trap_gate(15,&reserved); + set_trap_gate(16,&coprocessor_error); + for (i=17;i<48;i++) + set_trap_gate(i,&reserved); + set_trap_gate(45,&irq13); + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xdf,0xA1); + set_trap_gate(39,¶llel_interrupt); +} diff --git a/linux/kernel/vsprintf.c b/linux/kernel/vsprintf.c new file mode 100644 index 0000000..06b910e --- /dev/null +++ b/linux/kernel/vsprintf.c @@ -0,0 +1,233 @@ +/* + * linux/kernel/vsprintf.c + * + * (C) 1991 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include +#include + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ + +#define do_div(n,base) ({ \ +int __res; \ +__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ +__res; }) + +static char * number(char * str, int num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[36]; + const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + + if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; + if (type&LEFT) type &= ~ZEROPAD; + if (base<2 || base>36) + return 0; + c = (type & ZEROPAD) ? '0' : ' ' ; + if (type&SIGN && num<0) { + sign='-'; + num = -num; + } else + sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); + if (sign) size--; + if (type&SPECIAL) + if (base==16) size -= 2; + else if (base==8) size--; + i=0; + if (num==0) + tmp[i++]='0'; + else while (num!=0) + tmp[i++]=digits[do_div(num,base)]; + if (i>precision) precision=i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type&SPECIAL) + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + if (!(type&LEFT)) + while(size-->0) + *str++ = c; + while(i0) + *str++ = tmp[i]; + while(size-->0) + *str++ = ' '; + return str; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + int i; + char * str; + char *s; + int *ip; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + break; + + case 's': + s = va_arg(args, char *); + len = strlen(s); + if (precision < 0) + precision = len; + else if (len > precision) + len = precision; + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + break; + + case 'o': + str = number(str, va_arg(args, unsigned long), 8, + field_width, precision, flags); + break; + + case 'p': + if (field_width == -1) { + field_width = 8; + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + break; + + case 'x': + flags |= SMALL; + case 'X': + str = number(str, va_arg(args, unsigned long), 16, + field_width, precision, flags); + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + str = number(str, va_arg(args, unsigned long), 10, + field_width, precision, flags); + break; + + case 'n': + ip = va_arg(args, int *); + *ip = (str - buf); + break; + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + break; + } + } + *str = '\0'; + return str-buf; +} diff --git a/linux/lib/Makefile b/linux/lib/Makefile new file mode 100644 index 0000000..608faf5 --- /dev/null +++ b/linux/lib/Makefile @@ -0,0 +1,73 @@ +# +# Makefile for some libs needed in the kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =ar +AS =as +LD =ld +LDFLAGS =-s -x +CC =gcc -march=i386 +CFLAGS =-w -g -fstrength-reduce -fomit-frame-pointer \ + -finline-functions -nostdinc -fno-stack-protector -I../include +CPP =gcc -E -nostdinc -I../include + +.c.s: + $(CC) $(CFLAGS) \ + -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) \ + -c -o $*.o $< + +OBJS = ctype.o _exit.o open.o close.o errno.o write.o dup.o setsid.o \ + execve.o wait.o string.o malloc.o + +lib.a: $(OBJS) + $(AR) rcs lib.a $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +_exit.s _exit.o : _exit.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +close.s close.o : close.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +ctype.s ctype.o : ctype.c ../include/ctype.h +dup.s dup.o : dup.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +errno.s errno.o : errno.c +execve.s execve.o : execve.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +malloc.s malloc.o : malloc.c ../include/linux/kernel.h ../include/linux/mm.h \ + ../include/asm/system.h +open.s open.o : open.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h ../include/stdarg.h +setsid.s setsid.o : setsid.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +string.s string.o : string.c ../include/string.h +wait.s wait.o : wait.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h ../include/sys/wait.h +write.s write.o : write.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h diff --git a/linux/lib/_exit.c b/linux/lib/_exit.c new file mode 100644 index 0000000..c0c9d69 --- /dev/null +++ b/linux/lib/_exit.c @@ -0,0 +1,13 @@ +/* + * linux/lib/_exit.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +volatile void _exit(int exit_code) +{ + __asm__("int $0x80"::"a" (__NR_exit),"b" (exit_code)); +} diff --git a/linux/lib/close.c b/linux/lib/close.c new file mode 100644 index 0000000..afd8364 --- /dev/null +++ b/linux/lib/close.c @@ -0,0 +1,10 @@ +/* + * linux/lib/close.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall1(int,close,int,fd) diff --git a/linux/lib/ctype.c b/linux/lib/ctype.c new file mode 100644 index 0000000..877e629 --- /dev/null +++ b/linux/lib/ctype.c @@ -0,0 +1,35 @@ +/* + * linux/lib/ctype.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +char _ctmp; +unsigned char _ctype[] = {0x00, /* EOF */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */ + diff --git a/linux/lib/dup.c b/linux/lib/dup.c new file mode 100644 index 0000000..dd13414 --- /dev/null +++ b/linux/lib/dup.c @@ -0,0 +1,10 @@ +/* + * linux/lib/dup.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall1(int,dup,int,fd) diff --git a/linux/lib/errno.c b/linux/lib/errno.c new file mode 100644 index 0000000..50aca2e --- /dev/null +++ b/linux/lib/errno.c @@ -0,0 +1,7 @@ +/* + * linux/lib/errno.c + * + * (C) 1991 Linus Torvalds + */ + +int errno; diff --git a/linux/lib/execve.c b/linux/lib/execve.c new file mode 100644 index 0000000..7669b50 --- /dev/null +++ b/linux/lib/execve.c @@ -0,0 +1,11 @@ +/* + * linux/lib/execve.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall3(int,execve,const char *,file,char **,argv,char **,envp) + diff --git a/linux/lib/execve2.c b/linux/lib/execve2.c new file mode 100644 index 0000000..54bb6b5 --- /dev/null +++ b/linux/lib/execve2.c @@ -0,0 +1,19 @@ +#define __LIBRARY__ +#include +#include +#include +#include +#include +#include +#include +struct linux_dirent { + long d_ino; + off_t d_off; + unsigned short d_reclen; + char d_name[14]; +}; + +int sys_execve2(const char * filename, char ** argv, char ** envp) +{ + return 0; +} \ No newline at end of file diff --git a/linux/lib/malloc.c b/linux/lib/malloc.c new file mode 100644 index 0000000..d7c95d5 --- /dev/null +++ b/linux/lib/malloc.c @@ -0,0 +1,232 @@ +/* + * malloc.c --- a general purpose kernel memory allocator for Linux. + * + * Written by Theodore Ts'o (tytso@mit.edu), 11/29/91 + * + * This routine is written to be as fast as possible, so that it + * can be called from the interrupt level. + * + * Limitations: maximum size of memory we can allocate using this routine + * is 4k, the size of a page in Linux. + * + * The general game plan is that each page (called a bucket) will only hold + * objects of a given size. When all of the object on a page are released, + * the page can be returned to the general free pool. When malloc() is + * called, it looks for the smallest bucket size which will fulfill its + * request, and allocate a piece of memory from that bucket pool. + * + * Each bucket has as its control block a bucket descriptor which keeps + * track of how many objects are in use on that page, and the free list + * for that page. Like the buckets themselves, bucket descriptors are + * stored on pages requested from get_free_page(). However, unlike buckets, + * pages devoted to bucket descriptor pages are never released back to the + * system. Fortunately, a system should probably only need 1 or 2 bucket + * descriptor pages, since a page can hold 256 bucket descriptors (which + * corresponds to 1 megabyte worth of bucket pages.) If the kernel is using + * that much allocated memory, it's probably doing something wrong. :-) + * + * Note: malloc() and free() both call get_free_page() and free_page() + * in sections of code where interrupts are turned off, to allow + * malloc() and free() to be safely called from an interrupt routine. + * (We will probably need this functionality when networking code, + * particularily things like NFS, is added to Linux.) However, this + * presumes that get_free_page() and free_page() are interrupt-level + * safe, which they may not be once paging is added. If this is the + * case, we will need to modify malloc() to keep a few unused pages + * "pre-allocated" so that it can safely draw upon those pages if + * it is called from an interrupt routine. + * + * Another concern is that get_free_page() should not sleep; if it + * does, the code is carefully ordered so as to avoid any race + * conditions. The catch is that if malloc() is called re-entrantly, + * there is a chance that unecessary pages will be grabbed from the + * system. Except for the pages for the bucket descriptor page, the + * extra pages will eventually get released back to the system, though, + * so it isn't all that bad. + */ + +#include +#include +#include + +struct bucket_desc { /* 16 bytes */ + void *page; + struct bucket_desc *next; + void *freeptr; + unsigned short refcnt; + unsigned short bucket_size; +}; + +struct _bucket_dir { /* 8 bytes */ + int size; + struct bucket_desc *chain; +}; + +/* + * The following is the where we store a pointer to the first bucket + * descriptor for a given size. + * + * If it turns out that the Linux kernel allocates a lot of objects of a + * specific size, then we may want to add that specific size to this list, + * since that will allow the memory to be allocated more efficiently. + * However, since an entire page must be dedicated to each specific size + * on this list, some amount of temperance must be exercised here. + * + * Note that this list *must* be kept in order. + */ +struct _bucket_dir bucket_dir[] = { + { 16, (struct bucket_desc *) 0}, + { 32, (struct bucket_desc *) 0}, + { 64, (struct bucket_desc *) 0}, + { 128, (struct bucket_desc *) 0}, + { 256, (struct bucket_desc *) 0}, + { 512, (struct bucket_desc *) 0}, + { 1024, (struct bucket_desc *) 0}, + { 2048, (struct bucket_desc *) 0}, + { 4096, (struct bucket_desc *) 0}, + { 0, (struct bucket_desc *) 0}}; /* End of list marker */ + +/* + * This contains a linked list of free bucket descriptor blocks + */ +struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0; + +/* + * This routine initializes a bucket description page. + */ +static inline void init_bucket_desc() +{ + struct bucket_desc *bdesc, *first; + int i; + + first = bdesc = (struct bucket_desc *) get_free_page(); + if (!bdesc) + panic("Out of memory in init_bucket_desc()"); + for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) { + bdesc->next = bdesc+1; + bdesc++; + } + /* + * This is done last, to avoid race conditions in case + * get_free_page() sleeps and this routine gets called again.... + */ + bdesc->next = free_bucket_desc; + free_bucket_desc = first; +} + +void *malloc(unsigned int len) +{ + struct _bucket_dir *bdir; + struct bucket_desc *bdesc; + void *retval; + + /* + * First we search the bucket_dir to find the right bucket change + * for this request. + */ + for (bdir = bucket_dir; bdir->size; bdir++) + if (bdir->size >= len) + break; + if (!bdir->size) { + printk("malloc called with impossibly large argument (%d)\n", + len); + panic("malloc: bad arg"); + } + /* + * Now we search for a bucket descriptor which has free space + */ + cli(); /* Avoid race conditions */ + for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) + if (bdesc->freeptr) + break; + /* + * If we didn't find a bucket with free space, then we'll + * allocate a new one. + */ + if (!bdesc) { + char *cp; + int i; + + if (!free_bucket_desc) + init_bucket_desc(); + bdesc = free_bucket_desc; + free_bucket_desc = bdesc->next; + bdesc->refcnt = 0; + bdesc->bucket_size = bdir->size; + bdesc->page = bdesc->freeptr = (void *) (cp = get_free_page()); + if (!cp) + panic("Out of memory in kernel malloc()"); + /* Set up the chain of free objects */ + for (i=PAGE_SIZE/bdir->size; i > 1; i--) { + *((char **) cp) = cp + bdir->size; + cp += bdir->size; + } + *((char **) cp) = 0; + bdesc->next = bdir->chain; /* OK, link it in! */ + bdir->chain = bdesc; + } + retval = (void *) bdesc->freeptr; + bdesc->freeptr = *((void **) retval); + bdesc->refcnt++; + sti(); /* OK, we're safe again */ + return(retval); +} + +/* + * Here is the free routine. If you know the size of the object that you + * are freeing, then free_s() will use that information to speed up the + * search for the bucket descriptor. + * + * We will #define a macro so that "free(x)" is becomes "free_s(x, 0)" + */ +void free_s(void *obj, int size) +{ + void *page; + struct _bucket_dir *bdir; + struct bucket_desc *bdesc, *prev; + + /* Calculate what page this object lives in */ + page = (void *) ((unsigned long) obj & 0xfffff000); + /* Now search the buckets looking for that page */ + for (bdir = bucket_dir; bdir->size; bdir++) { + prev = 0; + /* If size is zero then this conditional is always false */ + if (bdir->size < size) + continue; + for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) { + if (bdesc->page == page) + goto found; + prev = bdesc; + } + } + panic("Bad address passed to kernel free_s()"); +found: + cli(); /* To avoid race conditions */ + *((void **)obj) = bdesc->freeptr; + bdesc->freeptr = obj; + bdesc->refcnt--; + if (bdesc->refcnt == 0) { + /* + * We need to make sure that prev is still accurate. It + * may not be, if someone rudely interrupted us.... + */ + if ((prev && (prev->next != bdesc)) || + (!prev && (bdir->chain != bdesc))) + for (prev = bdir->chain; prev; prev = prev->next) + if (prev->next == bdesc) + break; + if (prev) + prev->next = bdesc->next; + else { + if (bdir->chain != bdesc) + panic("malloc bucket chains corrupted"); + bdir->chain = bdesc->next; + } + free_page((unsigned long) bdesc->page); + bdesc->next = free_bucket_desc; + free_bucket_desc = bdesc; + } + sti(); + return; +} + diff --git a/linux/lib/open.c b/linux/lib/open.c new file mode 100644 index 0000000..8c3fc58 --- /dev/null +++ b/linux/lib/open.c @@ -0,0 +1,25 @@ +/* + * linux/lib/open.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +int open(const char * filename, int flag, ...) +{ + register int res; + va_list arg; + + va_start(arg,flag); + __asm__("int $0x80" + :"=a" (res) + :"0" (__NR_open),"b" (filename),"c" (flag), + "d" (va_arg(arg,int))); + if (res>=0) + return res; + errno = -res; + return -1; +} diff --git a/linux/lib/setsid.c b/linux/lib/setsid.c new file mode 100644 index 0000000..68516c7 --- /dev/null +++ b/linux/lib/setsid.c @@ -0,0 +1,10 @@ +/* + * linux/lib/setsid.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall0(pid_t,setsid) diff --git a/linux/lib/string.c b/linux/lib/string.c new file mode 100644 index 0000000..1182e63 --- /dev/null +++ b/linux/lib/string.c @@ -0,0 +1,14 @@ +/* + * linux/lib/string.c + * + * (C) 1991 Linus Torvalds + */ + +#ifndef __GNUC__ +#error I want gcc! +#endif + +#define extern +#define inline +#define __LIBRARY__ +#include diff --git a/linux/lib/wait.c b/linux/lib/wait.c new file mode 100644 index 0000000..2815c16 --- /dev/null +++ b/linux/lib/wait.c @@ -0,0 +1,16 @@ +/* + * linux/lib/wait.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +_syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) + +pid_t wait(int * wait_stat) +{ + return waitpid(-1,wait_stat,0); +} diff --git a/linux/lib/write.c b/linux/lib/write.c new file mode 100644 index 0000000..df52e74 --- /dev/null +++ b/linux/lib/write.c @@ -0,0 +1,10 @@ +/* + * linux/lib/write.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall3(int,write,int,fd,const char *,buf,off_t,count) diff --git a/linux/mm/Makefile b/linux/mm/Makefile new file mode 100644 index 0000000..e0bcd73 --- /dev/null +++ b/linux/mm/Makefile @@ -0,0 +1,38 @@ +AR =ar +AS =as +LD =ld +LDFLAGS =-m elf_i386 -Ttext 0 -e startup_32 +CC =gcc -march=i386 +CFLAGS =-w -g -fstrength-reduce -fomit-frame-pointer -mcld \ + -finline-functions -nostdinc -fno-stack-protector -I../include +CPP =gcc -E -nostdinc -I../include + +.c.o: + $(CC) $(CFLAGS) \ + -c -o $*.o $< +.s.o: + $(AS) -o $*.o $< +.c.s: + $(CC) $(CFLAGS) \ + -S -o $*.s $< + +OBJS = memory.o page.o + +all: mm.o + +mm.o: $(OBJS) + $(LD) -r -o mm.o $(OBJS) + +clean: + rm -f core *.o *.a tmp_make + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +memory.o : memory.c ../include/signal.h ../include/sys/types.h \ + ../include/asm/system.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h diff --git a/linux/mm/memory.c b/linux/mm/memory.c new file mode 100644 index 0000000..d884e08 --- /dev/null +++ b/linux/mm/memory.c @@ -0,0 +1,433 @@ +/* + * linux/mm/memory.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * demand-loading started 01.12.91 - seems it is high on the list of + * things wanted, and it should be easy to implement. - Linus + */ + +/* + * Ok, demand-loading was easy, shared pages a little bit tricker. Shared + * pages started 02.12.91, seems to work. - Linus. + * + * Tested sharing by executing about 30 /bin/sh: under the old kernel it + * would have taken more than the 6M I have free, but it worked well as + * far as I could see. + * + * Also corrected some "invalidate()"s - I wasn't doing enough of them. + */ + +#include + +#include + +#include +#include +#include + +volatile void do_exit(long code); + +static inline volatile void oom(void) +{ + printk("out of memory\n\r"); + do_exit(SIGSEGV); +} + +#define invalidate() \ +__asm__("movl %%eax,%%cr3"::"a" (0)) + +/* these are not to be changed without changing head.s etc */ +#define LOW_MEM 0x100000 +#define PAGING_MEMORY (15*1024*1024) +#define PAGING_PAGES (PAGING_MEMORY>>12) +#define MAP_NR(addr) (((addr)-LOW_MEM)>>12) +#define USED 100 + +#define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \ +current->start_code + current->end_code) + +static long HIGH_MEMORY = 0; + +#define copy_page(from,to) \ +__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024)) + +static unsigned char mem_map [ PAGING_PAGES ] = {0,}; + +/* + * Get physical address of first (actually last :-) free page, and mark it + * used. If no free pages left, return 0. + */ +unsigned long get_free_page(void) +{ +register unsigned long __res asm("ax"); + +__asm__("std ; repne ; scasb\n\t" + "jne 1f\n\t" + "movb $1,1(%%edi)\n\t" + "sall $12,%%ecx\n\t" + "addl %2,%%ecx\n\t" + "movl %%ecx,%%edx\n\t" + "movl $1024,%%ecx\n\t" + "leal 4092(%%edx),%%edi\n\t" + "rep ; stosl\n\t" + "movl %%edx,%%eax\n\t" + "1:" + "cld\n\t" /* by wyj */ + :"=a" (__res) + :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES), + "D" (mem_map+PAGING_PAGES-1) + ); +return __res; +} + +/* + * Free a page of memory at physical address 'addr'. Used by + * 'free_page_tables()' + */ +void free_page(unsigned long addr) +{ + if (addr < LOW_MEM) return; + if (addr >= HIGH_MEMORY) + panic("trying to free nonexistent page"); + addr -= LOW_MEM; + addr >>= 12; + if (mem_map[addr]--) return; + mem_map[addr]=0; + panic("trying to free free page"); +} + +/* + * This function frees a continuos block of page tables, as needed + * by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks. + */ +int free_page_tables(unsigned long from,unsigned long size) +{ + unsigned long *pg_table; + unsigned long * dir, nr; + + if (from & 0x3fffff) + panic("free_page_tables called with wrong alignment"); + if (!from) + panic("Trying to free up swapper memory space"); + size = (size + 0x3fffff) >> 22; + dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */ + for ( ; size-->0 ; dir++) { + if (!(1 & *dir)) + continue; + pg_table = (unsigned long *) (0xfffff000 & *dir); + for (nr=0 ; nr<1024 ; nr++) { + if (1 & *pg_table) + free_page(0xfffff000 & *pg_table); + *pg_table = 0; + pg_table++; + } + free_page(0xfffff000 & *dir); + *dir = 0; + } + invalidate(); + return 0; +} + +/* + * Well, here is one of the most complicated functions in mm. It + * copies a range of linerar addresses by copying only the pages. + * Let's hope this is bug-free, 'cause this one I don't want to debug :-) + * + * Note! We don't copy just any chunks of memory - addresses have to + * be divisible by 4Mb (one page-directory entry), as this makes the + * function easier. It's used only by fork anyway. + * + * NOTE 2!! When from==0 we are copying kernel space for the first + * fork(). Then we DONT want to copy a full page-directory entry, as + * that would lead to some serious memory waste - we just copy the + * first 160 pages - 640kB. Even that is more than we need, but it + * doesn't take any more memory - we don't copy-on-write in the low + * 1 Mb-range, so the pages can be shared with the kernel. Thus the + * special case for nr=xxxx. + */ +int copy_page_tables(unsigned long from,unsigned long to,long size) +{ + unsigned long * from_page_table; + unsigned long * to_page_table; + unsigned long this_page; + unsigned long * from_dir, * to_dir; + unsigned long nr; + + if ((from&0x3fffff) || (to&0x3fffff)) + panic("copy_page_tables called with wrong alignment"); + from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */ + to_dir = (unsigned long *) ((to>>20) & 0xffc); + size = ((unsigned) (size+0x3fffff)) >> 22; + for( ; size-->0 ; from_dir++,to_dir++) { + if (1 & *to_dir) + panic("copy_page_tables: already exist"); + if (!(1 & *from_dir)) + continue; + from_page_table = (unsigned long *) (0xfffff000 & *from_dir); + if (!(to_page_table = (unsigned long *) get_free_page())) + return -1; /* Out of memory, see freeing */ + *to_dir = ((unsigned long) to_page_table) | 7; + nr = (from==0)?0xA0:1024; + for ( ; nr-- > 0 ; from_page_table++,to_page_table++) { + this_page = *from_page_table; + if (!(1 & this_page)) + continue; + this_page &= ~2; + *to_page_table = this_page; + if (this_page > LOW_MEM) { + *from_page_table = this_page; + this_page -= LOW_MEM; + this_page >>= 12; + mem_map[this_page]++; + } + } + } + invalidate(); + return 0; +} + +/* + * This function puts a page in memory at the wanted address. + * It returns the physical address of the page gotten, 0 if + * out of memory (either when trying to access page-table or + * page.) + */ +unsigned long put_page(unsigned long page,unsigned long address) +{ + unsigned long tmp, *page_table; + +/* NOTE !!! This uses the fact that _pg_dir=0 */ + + if (page < LOW_MEM || page >= HIGH_MEMORY) + printk("Trying to put page %p at %p\n",page,address); + if (mem_map[(page-LOW_MEM)>>12] != 1) + printk("mem_map disagrees with %p at %p\n",page,address); + page_table = (unsigned long *) ((address>>20) & 0xffc); + if ((*page_table)&1) + page_table = (unsigned long *) (0xfffff000 & *page_table); + else { + if (!(tmp=get_free_page())) + return 0; + *page_table = tmp|7; + page_table = (unsigned long *) tmp; + } + page_table[(address>>12) & 0x3ff] = page | 7; +/* no need for invalidate */ + return page; +} + +void un_wp_page(unsigned long * table_entry) +{ + unsigned long old_page,new_page; + + old_page = 0xfffff000 & *table_entry; + if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) { + *table_entry |= 2; + invalidate(); + return; + } + if (!(new_page=get_free_page())) + oom(); + if (old_page >= LOW_MEM) + mem_map[MAP_NR(old_page)]--; + *table_entry = new_page | 7; + invalidate(); + copy_page(old_page,new_page); +} + +/* + * This routine handles present pages, when users try to write + * to a shared page. It is done by copying the page to a new address + * and decrementing the shared-page counter for the old page. + * + * If it's in code space we exit with a segment error. + */ +void do_wp_page(unsigned long error_code,unsigned long address) +{ +#if 0 +/* we cannot do this yet: the estdio library writes to code space */ +/* stupid, stupid. I really want the libc.a from GNU */ + if (CODE_SPACE(address)) + do_exit(SIGSEGV); +#endif + un_wp_page((unsigned long *) + (((address>>10) & 0xffc) + (0xfffff000 & + *((unsigned long *) ((address>>20) &0xffc))))); + +} + +void write_verify(unsigned long address) +{ + unsigned long page; + + if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1)) + return; + page &= 0xfffff000; + page += ((address>>10) & 0xffc); + if ((3 & *(unsigned long *) page) == 1) /* non-writeable, present */ + un_wp_page((unsigned long *) page); + return; +} + +void get_empty_page(unsigned long address) +{ + unsigned long tmp; + + if (!(tmp=get_free_page()) || !put_page(tmp,address)) { + free_page(tmp); /* 0 is ok - ignored */ + oom(); + } +} + +/* + * try_to_share() checks the page at address "address" in the task "p", + * to see if it exists, and if it is clean. If so, share it with the current + * task. + * + * NOTE! This assumes we have checked that p != current, and that they + * share the same executable. + */ +static int try_to_share(unsigned long address, struct task_struct * p) +{ + unsigned long from; + unsigned long to; + unsigned long from_page; + unsigned long to_page; + unsigned long phys_addr; + + from_page = to_page = ((address>>20) & 0xffc); + from_page += ((p->start_code>>20) & 0xffc); + to_page += ((current->start_code>>20) & 0xffc); +/* is there a page-directory at from? */ + from = *(unsigned long *) from_page; + if (!(from & 1)) + return 0; + from &= 0xfffff000; + from_page = from + ((address>>10) & 0xffc); + phys_addr = *(unsigned long *) from_page; +/* is the page clean and present? */ + if ((phys_addr & 0x41) != 0x01) + return 0; + phys_addr &= 0xfffff000; + if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM) + return 0; + to = *(unsigned long *) to_page; + if (!(to & 1)) + if (to = get_free_page()) + *(unsigned long *) to_page = to | 7; + else + oom(); + to &= 0xfffff000; + to_page = to + ((address>>10) & 0xffc); + if (1 & *(unsigned long *) to_page) + panic("try_to_share: to_page already exists"); +/* share them: write-protect */ + *(unsigned long *) from_page &= ~2; + *(unsigned long *) to_page = *(unsigned long *) from_page; + invalidate(); + phys_addr -= LOW_MEM; + phys_addr >>= 12; + mem_map[phys_addr]++; + return 1; +} + +/* + * share_page() tries to find a process that could share a page with + * the current one. Address is the address of the wanted page relative + * to the current data space. + * + * We first check if it is at all feasible by checking executable->i_count. + * It should be >1 if there are other tasks sharing this inode. + */ +static int share_page(unsigned long address) +{ + struct task_struct ** p; + + if (!current->executable) + return 0; + if (current->executable->i_count < 2) + return 0; + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if (!*p) + continue; + if (current == *p) + continue; + if ((*p)->executable != current->executable) + continue; + if (try_to_share(address,*p)) + return 1; + } + return 0; +} + +void do_no_page(unsigned long error_code,unsigned long address) +{ + int nr[4]; + unsigned long tmp; + unsigned long page; + int block,i; + + address &= 0xfffff000; + + + tmp = address - current->start_code; + if (!current->executable || tmp >= current->end_data) { + get_empty_page(address); + return; + } + if (share_page(tmp)) + return; + if (!(page = get_free_page())) + oom(); +/* remember that 1 block is used for header */ + block = 1 + tmp/BLOCK_SIZE; + for (i=0 ; i<4 ; block++,i++) + nr[i] = bmap(current->executable,block); + bread_page(page,current->executable->i_dev,nr); + i = tmp + 4096 - current->end_data; + tmp = page + 4096; + while (i-- > 0) { + tmp--; + *(char *)tmp = 0; + } + if (put_page(page,address)) + return; + free_page(page); + oom(); +} + +void mem_init(long start_mem, long end_mem) +{ + int i; + + HIGH_MEMORY = end_mem; + for (i=0 ; i>= 12; + while (end_mem-->0) + mem_map[i++]=0; +} + +void calc_mem(void) +{ + int i,j,k,free=0; + long * pg_tbl; + + for(i=0 ; iT@#lCNna>cIHh8 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 N^|Cbi(V*L${{d;jp)>#h literal 0 HcmV?d00001 diff --git a/linux/tools/build.c b/linux/tools/build.c new file mode 100644 index 0000000..8b8c7ab --- /dev/null +++ b/linux/tools/build.c @@ -0,0 +1,171 @@ +/* + * linux/tools/build.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This file builds a disk-image from three different files: + * + * - bootsect: max 510 bytes of 8086 machine code, loads the rest + * - setup: max 4 sectors of 8086 machine code, sets up system parm + * - system: 80386 code for actual system + * + * It does some checking that all files are of the correct type, and + * just writes the result to stdout, removing headers and padding to + * the right amount. It also writes some system data to stderr. + */ + +/* + * Changes by tytso to allow root device specification + */ + +#include /* fprintf */ +#include +#include /* contains exit */ +#include /* unistd.h needs this */ +#include +#include +#include /* contains read/write */ +#include + +#define MAJOR(a) (((unsigned)(a))>>8) +#define MINOR(a) ((a)&0xff) + +#define MINIX_HEADER 32 +#define GCC_HEADER 0x80 /* 0x1000 */ /* by wyj */ + +#define SYS_SIZE 0x3000 + +#define DEFAULT_MAJOR_ROOT 0x03 //0x02 /* by wyj */ +#define DEFAULT_MINOR_ROOT 0x00 //0x1d + +/* max nr of sectors of setup: don't change unless you also change + * bootsect etc */ +#define SETUP_SECTS 4 + +#define STRINGIFY(x) #x + +void die(char * str) +{ + fprintf(stderr,"%s\n",str); + exit(1); +} + +void usage(void) +{ + die("Usage: build bootsect setup system [rootdev] [> image]"); +} + +int main(int argc, char ** argv) +{ + int i,c,id; + char buf[1024*4]; /* by wyj */ + char major_root, minor_root; + struct stat sb; + + if ((argc != 4) && (argc != 5)) + usage(); + if (argc == 5) { + if (strcmp(argv[4], "FLOPPY")) { + if (stat(argv[4], &sb)) { + perror(argv[4]); + die("Couldn't stat root device."); + } + major_root = MAJOR(sb.st_rdev); + minor_root = MINOR(sb.st_rdev); + } else { + major_root = 0; + minor_root = 0; + } + } else { + major_root = DEFAULT_MAJOR_ROOT; + minor_root = DEFAULT_MINOR_ROOT; + } + fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); + if ((major_root != 2) && (major_root != 3) && + (major_root != 0)) { + fprintf(stderr, "Illegal root device (major = %d)\n", + major_root); + die("Bad root device --- major #"); + } + for (i=0;i0 ; i+=c ) + if (write(1,buf,c)!=c) + die("Write call failed"); + close (id); + if (i > SETUP_SECTS*512) + die("Setup exceeds " STRINGIFY(SETUP_SECTS) + " sectors - rewrite build/boot/setup"); + fprintf(stderr,"Setup is %d bytes.\n",i); + for (c=0 ; c sizeof(buf)) + c = sizeof(buf); + if (write(1,buf,c) != c) + die("Write call failed"); + i += c; + } + + if ((id=open(argv[3],O_RDONLY,0))<0) + die("Unable to open 'system'"); + if (read(id,buf,GCC_HEADER) != GCC_HEADER) + die("Unable to read header of 'system'"); +// if (((long *) buf)[5] != 0) +// die("Non-GCC header of 'system'"); + for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c ) + if (write(1,buf,c)!=c) + die("Write call failed"); + close(id); + fprintf(stderr,"System is %d bytes.\n",i); + if (i > SYS_SIZE*16) + die("System is too big"); + return(0); +} diff --git a/linux/tools/system b/linux/tools/system new file mode 100644 index 0000000000000000000000000000000000000000..9b3bdb2dbfc37f9a217dfdc15d55a4d6c6383e49 GIT binary patch literal 294428 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