diff options
| author | Andrew Lee <alee14498@protonmail.com> | 2021-08-15 00:16:45 -0400 |
|---|---|---|
| committer | Andrew Lee <alee14498@protonmail.com> | 2021-08-15 00:16:45 -0400 |
| commit | 723428bebe3105ad3c3406e416402d1831b482c4 (patch) | |
| tree | ff990e306163515973746ddfb261f29ba8765441 /linux | |
| download | linux-0.01-distro-723428bebe3105ad3c3406e416402d1831b482c4.tar.gz linux-0.01-distro-723428bebe3105ad3c3406e416402d1831b482c4.tar.bz2 linux-0.01-distro-723428bebe3105ad3c3406e416402d1831b482c4.zip | |
Inital commit
Diffstat (limited to 'linux')
88 files changed, 10239 insertions, 0 deletions
diff --git a/linux/Makefile b/linux/Makefile new file mode 100644 index 0000000..d9d9fab --- /dev/null +++ b/linux/Makefile @@ -0,0 +1,96 @@ +# +# Makefile for linux. +# If you don't have '-mstring-insns' in your gcc (and nobody but me has :-) +# remove them from the CFLAGS defines. +# + +AS86 =as -0 -a +CC86 =cc -0 +LD86 =ld -0 + +AS =gas +LD =gld +LDFLAGS =-s -x -M +CC =gcc +CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs +CPP =gcc -E -nostdinc -Iinclude + +ARCHIVES=kernel/kernel.o mm/mm.o fs/fs.o +LIBS =lib/lib.a + +.c.s: + $(CC) $(CFLAGS) \ + -nostdinc -Iinclude -S -o $*.s $< +.s.o: + $(AS) -c -o $*.o $< +.c.o: + $(CC) $(CFLAGS) \ + -nostdinc -Iinclude -c -o $*.o $< + +all: Image + +Image: boot/boot tools/system tools/build + tools/build boot/boot tools/system > Image + sync + +tools/build: tools/build.c + $(CC) $(CFLAGS) \ + -o tools/build tools/build.c + chmem +65000 tools/build + +boot/head.o: boot/head.s + +tools/system: boot/head.o init/main.o \ + $(ARCHIVES) $(LIBS) + $(LD) $(LDFLAGS) boot/head.o init/main.o \ + $(ARCHIVES) \ + $(LIBS) \ + -o tools/system > System.map + +kernel/kernel.o: + (cd kernel; make) + +mm/mm.o: + (cd mm; make) + +fs/fs.o: + (cd fs; make) + +lib/lib.a: + (cd lib; make) + +boot/boot: boot/boot.s tools/system + (echo -n "SYSSIZE = (";ls -l tools/system | grep system \ + | cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s + cat boot/boot.s >> tmp.s + $(AS86) -o boot/boot.o tmp.s + rm -f tmp.s + $(LD86) -s -o boot/boot boot/boot.o + +clean: + rm -f Image System.map tmp_make boot/boot core + rm -f init/*.o boot/*.o tools/system tools/build + (cd mm;make clean) + (cd fs;make clean) + (cd kernel;make clean) + (cd lib;make clean) + +backup: clean + (cd .. ; tar cf - linux | compress16 - > backup.Z) + sync + +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/asm/system.h include/asm/io.h include/stddef.h \ + include/stdarg.h include/fcntl.h diff --git a/linux/boot/boot.s b/linux/boot/boot.s new file mode 100644 index 0000000..e19bbd2 --- /dev/null +++ b/linux/boot/boot.s @@ -0,0 +1,329 @@ +| +| boot.s +| +| boot.s is loaded at 0x7c00 by the bios-startup routines, and moves itself +| out of the way to address 0x90000, and jumps there. +| +| It then loads the system at 0x10000, using BIOS interrupts. Thereafter +| it disables all interrupts, moves the system down to 0x0000, changes +| to protected mode, and calls the start of system. System then must +| RE-initialize the protected mode in it's own tables, and enable +| interrupts as needed. +| +| 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 - in fact more would mean we'd have to move +| not just these start-up routines, but also do something about the cache- +| memory (block IO devices). The area left over in the lower 640 kB is meant +| for these. No other memory is assumed to be "physical", ie all memory +| over 1Mb is demand-paging. All addresses under 1Mb are guaranteed to match +| their physical addresses. +| +| NOTE1 abouve is no longer valid in it's entirety. cache-memory is allocated +| above the 1Mb mark as well as below. Otherwise it is mainly correct. +| +| NOTE 2! The boot disk type must be set at compile-time, by setting +| the following equ. Having the boot-up procedure hunt for the right +| disk type is severe brain-damage. +| The loader has been made as simple as possible (had to, to get it +| in 512 bytes with the code to move to protected mode), 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. + +| 1.44Mb disks: +sectors = 18 +| 1.2Mb disks: +| sectors = 15 +| 720kB disks: +| sectors = 9 + +.globl begtext, begdata, begbss, endtext, enddata, endbss +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +BOOTSEG = 0x07c0 +INITSEG = 0x9000 +SYSSEG = 0x1000 | system loaded at 0x10000 (65536). +ENDSEG = SYSSEG + SYSSIZE + +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 + mov ss,ax + mov sp,#0x400 | arbitrary value >>512 + + 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 + +| if the read went well we get current cursor position ans save it for +| posterity. + + mov ah,#0x03 | read cursor pos + xor bh,bh + int 0x10 | save it in known place, con_init fetches + mov [510],dx | it from 0x90510. + +| now we want to move to protected mode ... + + cli | no interrupts allowed ! + +| first we move the system to it's rightful place + + mov ax,#0x0000 + cld | 'direction'=0, movs moves forward +do_move: + mov es,ax | destination segment + add ax,#0x1000 + cmp ax,#0x9000 + jz end_move + mov ds,ax | source segment + sub di,di + sub si,si + mov cx,#0x8000 + rep + movsw + j do_move + +| then we load the segment descriptors + +end_move: + + mov ax,cs | right, forgot this at first. didn't work :-) + mov ds,ax + lidt idt_48 | load idt with 0,0 + lgdt gdt_48 | load gdt with whatever appropriate + +| that was painless, now we enable A20 + + call empty_8042 + mov al,#0xD1 | command write + out #0x64,al + call empty_8042 + mov al,#0xDF | A20 on + out #0x60,al + call empty_8042 + +| well, that went ok, I hope. Now we have to reprogram the interrupts :-( +| we put them right after the intel-reserved hardware interrupts, at +| int 0x20-0x2F. There they won't mess up anything. Sadly IBM really +| messed this up with the original PC, and they haven't been able to +| rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, +| which is used for the internal hardware interrupts as well. We just +| have to reprogram the 8259's, and it isn't fun. + + mov al,#0x11 | initialization sequence + out #0x20,al | send it to 8259A-1 + .word 0x00eb,0x00eb | jmp $+2, jmp $+2 + out #0xA0,al | and to 8259A-2 + .word 0x00eb,0x00eb + mov al,#0x20 | start of hardware int's (0x20) + out #0x21,al + .word 0x00eb,0x00eb + mov al,#0x28 | start of hardware int's 2 (0x28) + out #0xA1,al + .word 0x00eb,0x00eb + mov al,#0x04 | 8259-1 is master + out #0x21,al + .word 0x00eb,0x00eb + mov al,#0x02 | 8259-2 is slave + out #0xA1,al + .word 0x00eb,0x00eb + mov al,#0x01 | 8086 mode for both + out #0x21,al + .word 0x00eb,0x00eb + out #0xA1,al + .word 0x00eb,0x00eb + mov al,#0xFF | mask off all interrupts for now + out #0x21,al + .word 0x00eb,0x00eb + out #0xA1,al + +| well, that certainly wasn't fun :-(. Hopefully it works, and we don't +| need no steenking BIOS anyway (except for the initial loading :-). +| The BIOS-routine wants lots of unnecessary data, and it's less +| "interesting" anyway. This is how REAL programmers do it. +| +| Well, now's the time to actually move into protected mode. To make +| things as simple as possible, we do no register set-up or anything, +| we let the gnu-compiled 32-bit programs do that. We just jump to +| absolute address 0x00000, in 32-bit protected mode. + + mov ax,#0x0001 | protected mode (PE) bit + lmsw ax | This is it! + jmpi 0,8 | jmp offset 0 of segment 8 (cs) + +| This routine checks that the keyboard command queue is empty +| No timeout is used - if this hangs there is something wrong with +| the machine, and we probably couldn't proceed anyway. +empty_8042: + .word 0x00eb,0x00eb + in al,#0x64 | 8042 status port + test al,#2 | is input buffer full? + jnz empty_8042 | yes - loop + ret + +| 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) +| +| This routine has to be recompiled to fit another drive type, +| just change the "sectors" variable at the start of the file +| (originally 18, for a 1.44Mb drive) +| +sread: .word 1 | 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: + 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 + 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 + +gdt: + .word 0,0,0,0 | dummy + + .word 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb) + .word 0x0000 | base address=0 + .word 0x9A00 | code read/exec + .word 0x00C0 | granularity=4096, 386 + + .word 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb) + .word 0x0000 | base address=0 + .word 0x9200 | data read/write + .word 0x00C0 | granularity=4096, 386 + +idt_48: + .word 0 | idt limit=0 + .word 0,0 | idt base=0L + +gdt_48: + .word 0x800 | gdt limit=2048, 256 GDT entries + .word gdt,0x9 | gdt base = 0X9xxxx + +msg1: + .byte 13,10 + .ascii "Loading system ..." + .byte 13,10,13,10 + +.text +endtext: +.data +enddata: +.bss +endbss: diff --git a/linux/boot/head.s b/linux/boot/head.s new file mode 100644 index 0000000..c008ba8 --- /dev/null +++ b/linux/boot/head.s @@ -0,0 +1,175 @@ +/* + * 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 +_pg_dir: +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 + cmpl %eax,0x100000 + je 1b + movl %cr0,%eax # check math chip + andl $0x80000011,%eax # Save PG,ET,PE + testl $0x10,%eax + jne 1f # ET is set - 387 is present + orl $4,%eax # else set emulate bit +1: movl %eax,%cr0 + jmp after_page_tables + +/* + * 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 + +.org 0x1000 +pg0: + +.org 0x2000 +pg1: + +.org 0x3000 +pg2: # This is not used yet, but if you + # want to expand past 8 Mb, you'll have + # to use it. + +.org 0x4000 +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" :-) */ +.align 2 +ignore_int: + incb 0xb8000+160 # put something on the screen + movb $2,0xb8000+161 # so that we know something + iret # happened + + +/* + * Setup_paging + * + * This routine sets up paging by setting the page bit + * in cr0. The page tables are set up, identity-mapping + * the first 8MB. 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 8 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 8Mb, 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 "8Mb"), but I + * won't guarantee that's all :-( ) + */ +.align 2 +setup_paging: + movl $1024*3,%ecx + 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 $pg1+4092,%edi + movl $0x7ff007,%eax /* 8Mb - 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 */ + ret /* this also flushes prefetch-queue */ + +.align 2 +.word 0 +idt_descr: + .word 256*8-1 # idt contains 256 entries + .long _idt +.align 2 +.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 3 +_idt: .fill 256,8,0 # idt is uninitialized + +_gdt: .quad 0x0000000000000000 /* NULL descriptor */ + .quad 0x00c09a00000007ff /* 8Mb */ + .quad 0x00c09200000007ff /* 8Mb */ + .quad 0x0000000000000000 /* TEMPORARY - don't use */ + .fill 252,8,0 /* space for LDT's and TSS's etc */ diff --git a/linux/fs/Makefile b/linux/fs/Makefile new file mode 100644 index 0000000..24e7e4c --- /dev/null +++ b/linux/fs/Makefile @@ -0,0 +1,95 @@ +AR =gar +AS =gas +CC =gcc +LD =gld +CFLAGS =-Wall -O -fstrength-reduce -fcombine-regs -fomit-frame-pointer \ + -mstring-insns -nostdinc -I../include +CPP =gcc -E -nostdinc -I../include + +.c.s: + $(CC) $(CFLAGS) \ + -S -o $*.s $< +.c.o: + $(CC) $(CFLAGS) \ + -c -o $*.o $< +.s.o: + $(AS) -o $*.o $< + +OBJS= open.o read_write.o inode.o file_table.o buffer.o super.o \ + block_dev.o char_dev.o file_dev.o stat.o exec.o pipe.o namei.o \ + bitmap.o fcntl.o ioctl.o tty_ioctl.o truncate.o + +fs.o: $(OBJS) + $(LD) -r -o fs.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: +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/linux/kernel.h +block_dev.o : block_dev.c ../include/errno.h ../include/linux/fs.h \ + ../include/sys/types.h ../include/linux/kernel.h ../include/asm/segment.h +buffer.o : buffer.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/linux/kernel.h ../include/asm/system.h +char_dev.o : char_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/linux/kernel.h +exec.o : exec.c ../include/errno.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/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/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/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/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.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 +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/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/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/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/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/linux/kernel.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/sys/stat.h +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/linux/kernel.h \ + ../include/linux/tty.h ../include/asm/segment.h ../include/asm/system.h diff --git a/linux/fs/bitmap.c b/linux/fs/bitmap.c new file mode 100644 index 0000000..49bb81b --- /dev/null +++ b/linux/fs/bitmap.c @@ -0,0 +1,158 @@ +/* bitmap.c contains the code that handles the inode and block bitmaps */ +#include <string.h> + +#include <linux/sched.h> +#include <linux/kernel.h> + +#define clear_block(addr) \ +__asm__("cld\n\t" \ + "rep\n\t" \ + "stosl" \ + ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di") + +#define set_bit(nr,addr) ({\ +register int res __asm__("ax"); \ +__asm__("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__("btrl %2,%3\n\tsetnb %%al":"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \ +res;}) + +#define find_first_zero(addr) ({ \ +int __res; \ +__asm__("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):"ax","dx","si"); \ +__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)) + panic("free_inode: bit already cleared"); + 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_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..7bbae6a --- /dev/null +++ b/linux/fs/block_dev.c @@ -0,0 +1,86 @@ +#include <errno.h> + +#include <linux/fs.h> +#include <linux/kernel.h> +#include <asm/segment.h> + +#define NR_BLK_DEV ((sizeof (rd_blk))/(sizeof (rd_blk[0]))) + +int block_write(int dev, long * pos, char * buf, int count) +{ + int block = *pos / BLOCK_SIZE; + int offset = *pos % BLOCK_SIZE; + int chars; + int written = 0; + struct buffer_head * bh; + register char * p; + + while (count>0) { + bh = bread(dev,block); + if (!bh) + return written?written:-EIO; + chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE; + p = offset + bh->b_data; + offset = 0; + block++; + *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; + int offset = *pos % BLOCK_SIZE; + int chars; + int read = 0; + struct buffer_head * bh; + register char * p; + + while (count>0) { + bh = bread(dev,block); + if (!bh) + return read?read:-EIO; + chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE; + p = offset + bh->b_data; + offset = 0; + block++; + *pos += chars; + read += chars; + count -= chars; + while (chars-->0) + put_fs_byte(*(p++),buf++); + bh->b_dirt = 1; + brelse(bh); + } + return read; +} + +extern void rw_hd(int rw, struct buffer_head * bh); + +typedef void (*blk_fn)(int rw, struct buffer_head * bh); + +static blk_fn rd_blk[]={ + NULL, /* nodev */ + NULL, /* dev mem */ + NULL, /* dev fd */ + rw_hd, /* dev hd */ + NULL, /* dev ttyx */ + NULL, /* dev tty */ + NULL}; /* dev lp */ + +void ll_rw_block(int rw, struct buffer_head * bh) +{ + blk_fn blk_addr; + unsigned int major; + + if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || !(blk_addr=rd_blk[major])) + panic("Trying to read nonexistent block-device"); + blk_addr(rw, bh); +} diff --git a/linux/fs/buffer.c b/linux/fs/buffer.c new file mode 100644 index 0000000..312ab17 --- /dev/null +++ b/linux/fs/buffer.c @@ -0,0 +1,254 @@ +/* + * '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). + */ + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <asm/system.h> + +#if (BUFFER_END & 0xfff) +#error "Bad BUFFER_END value" +#endif + +#if (BUFFER_END > 0xA0000 && BUFFER_END <= 0x100000) +#error "Bad BUFFER_END value" +#endif + +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 ; i<NR_BUFFERS ; i++,bh++) { + wait_on_buffer(bh); + if (bh->b_dirt) + ll_rw_block(WRITE,bh); + } + return 0; +} + +static int sync_dev(int dev) +{ + int i; + struct buffer_head * bh; + + bh = start_buffer; + for (i=0 ; i<NR_BUFFERS ; i++,bh++) { + if (bh->b_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dirt) + ll_rw_block(WRITE,bh); + } + return 0; +} + +#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH) +#define hash(dev,block) hash_table[_hashfn(dev,block)] + +static inline void remove_from_queues(struct buffer_head * bh) +{ +/* remove from hash-queue */ + if (bh->b_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; + +repeat: + if (!(bh=find_buffer(dev,block))) + return NULL; + bh->b_count++; + wait_on_buffer(bh); + if (bh->b_dev != dev || bh->b_blocknr != block) { + brelse(bh); + goto repeat; + } + return bh; +} + +/* + * 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. + */ +struct buffer_head * getblk(int dev,int block) +{ + struct buffer_head * tmp; + +repeat: + if (tmp=get_hash_table(dev,block)) + return tmp; + tmp = free_list; + do { + if (!tmp->b_count) { + wait_on_buffer(tmp); /* we still have to wait */ + if (!tmp->b_count) /* on it, it might be dirty */ + break; + } + tmp = tmp->b_next_free; + } while (tmp != free_list || (tmp=NULL)); + /* Kids, don't try THIS at home ^^^^^. Magic */ + if (!tmp) { + printk("Sleeping on free buffer .."); + sleep_on(&buffer_wait); + printk("ok\n"); + goto repeat; + } + tmp->b_count++; + remove_from_queues(tmp); +/* + * Now, when we know nobody can get to this node (as it's removed from the + * free list), we write it out. We can sleep here without fear of race- + * conditions. + */ + if (tmp->b_dirt) + sync_dev(tmp->b_dev); +/* update buffer contents */ + tmp->b_dev=dev; + tmp->b_blocknr=block; + tmp->b_dirt=0; + tmp->b_uptodate=0; +/* NOTE!! While we possibly slept in sync_dev(), somebody else might have + * added "this" block already, so check for that. Thank God for goto's. + */ + if (find_buffer(dev,block)) { + tmp->b_dev=0; /* ok, someone else has beaten us */ + tmp->b_blocknr=0; /* to it - free this block and */ + tmp->b_count=0; /* try again */ + insert_into_queues(tmp); + goto repeat; + } +/* and then insert into correct position */ + insert_into_queues(tmp); + return tmp; +} + +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); + if (bh->b_uptodate) + return bh; + brelse(bh); + return (NULL); +} + +void buffer_init(void) +{ + struct buffer_head * h = start_buffer; + void * b = (void *) BUFFER_END; + int i; + + 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<NR_HASH;i++) + hash_table[i]=NULL; +} diff --git a/linux/fs/char_dev.c b/linux/fs/char_dev.c new file mode 100644 index 0000000..e974242 --- /dev/null +++ b/linux/fs/char_dev.c @@ -0,0 +1,50 @@ +#include <errno.h> + +#include <linux/sched.h> +#include <linux/kernel.h> + +extern int tty_read(unsigned minor,char * buf,int count); +extern int tty_write(unsigned minor,char * buf,int count); + +static int rw_ttyx(int rw,unsigned minor,char * buf,int count); +static int rw_tty(int rw,unsigned minor,char * buf,int count); + +typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count); + +#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr))) + +static crw_ptr crw_table[]={ + NULL, /* nodev */ + NULL, /* /dev/mem */ + NULL, /* /dev/fd */ + NULL, /* /dev/hd */ + rw_ttyx, /* /dev/ttyx */ + rw_tty, /* /dev/tty */ + NULL, /* /dev/lp */ + NULL}; /* unnamed pipes */ + +static int rw_ttyx(int rw,unsigned minor,char * buf,int count) +{ + 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) +{ + if (current->tty<0) + return -EPERM; + return rw_ttyx(rw,current->tty,buf,count); +} + +int rw_char(int rw,int dev, char * buf, int count) +{ + crw_ptr call_addr; + + if (MAJOR(dev)>=NRDEVS) + panic("rw_char: dev>NRDEV"); + if (!(call_addr=crw_table[MAJOR(dev)])) { + printk("dev: %04x\n",dev); + panic("Trying to r/w from/to nonexistent character device"); + } + return call_addr(rw,MINOR(dev),buf,count); +} diff --git a/linux/fs/exec.c b/linux/fs/exec.c new file mode 100644 index 0000000..e9d5058 --- /dev/null +++ b/linux/fs/exec.c @@ -0,0 +1,306 @@ +#include <errno.h> +#include <sys/stat.h> +#include <a.out.h> + +#include <linux/fs.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <asm/segment.h> + +extern int sys_exit(int exit_code); +extern int sys_close(int fd); + +/* + * 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 + +#define cp_block(from,to) \ +__asm__("pushl $0x10\n\t" \ + "pushl $0x17\n\t" \ + "pop %%es\n\t" \ + "cld\n\t" \ + "rep\n\t" \ + "movsl\n\t" \ + "pop %%es" \ + ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \ + :"cx","di","si") + +/* + * read_head() reads blocks 1-6 (not 0). Block 0 has already been + * read for header information. + */ +int read_head(struct m_inode * inode,int blocks) +{ + struct buffer_head * bh; + int count; + + if (blocks>6) + blocks=6; + for(count = 0 ; count<blocks ; count++) { + if (!inode->i_zone[count+1]) + continue; + if (!(bh=bread(inode->i_dev,inode->i_zone[count+1]))) + return -1; + cp_block(bh->b_data,count*BLOCK_SIZE); + brelse(bh); + } + return 0; +} + +int read_ind(int dev,int ind,long size,unsigned long offset) +{ + struct buffer_head * ih, * bh; + unsigned short * table,block; + + if (size<=0) + panic("size<=0 in read_ind"); + if (size>512*BLOCK_SIZE) + size=512*BLOCK_SIZE; + if (!ind) + return 0; + if (!(ih=bread(dev,ind))) + return -1; + table = (unsigned short *) ih->b_data; + while (size>0) { + if (block=*(table++)) + if (!(bh=bread(dev,block))) { + brelse(ih); + return -1; + } else { + cp_block(bh->b_data,offset); + brelse(bh); + } + size -= BLOCK_SIZE; + offset += BLOCK_SIZE; + } + brelse(ih); + return 0; +} + +/* + * read_area() reads an area into %fs:mem. + */ +int read_area(struct m_inode * inode,long size) +{ + struct buffer_head * dind; + unsigned short * table; + int i,count; + + if ((i=read_head(inode,(size+BLOCK_SIZE-1)/BLOCK_SIZE)) || + (size -= BLOCK_SIZE*6)<=0) + return i; + if ((i=read_ind(inode->i_dev,inode->i_zone[7],size,BLOCK_SIZE*6)) || + (size -= BLOCK_SIZE*512)<=0) + return i; + if (!(i=inode->i_zone[8])) + return 0; + if (!(dind = bread(inode->i_dev,i))) + return -1; + table = (unsigned short *) dind->b_data; + for(count=0 ; count<512 ; count++) + if ((i=read_ind(inode->i_dev,*(table++),size, + BLOCK_SIZE*(518+count))) || (size -= BLOCK_SIZE*512)<=0) + return i; + panic("Impossibly long executable"); +} + +/* + * 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. + */ +static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, + unsigned long p) +{ + int len,i; + char *tmp; + + while (argc-- > 0) { + if (!(tmp = (char *)get_fs_long(((unsigned long *) argv)+argc))) + panic("argc is wrong"); + len=0; /* remember zero-padding */ + do { + len++; + } while (get_fs_byte(tmp++)); + if (p-len < 0) /* this shouldn't happen - 128kB */ + return 0; + i = ((unsigned) (p-len)) >> 12; + while (i<MAX_ARG_PAGES && !page[i]) { + if (!(page[i]=get_free_page())) + return 0; + i++; + } + do { + --p; + if (!page[p/PAGE_SIZE]) + panic("nonexistent page in exec.c"); + ((char *) page[p/PAGE_SIZE])[p%PAGE_SIZE] = + get_fs_byte(--tmp); + } while (--len); + } + 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; + unsigned long p; + + if ((0xffff & eip[1]) != 0x000f) + panic("execve called from supervisor mode"); + for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ + page[i]=0; + if (!(inode=namei(filename))) /* get executables inode */ + return -ENOENT; + if (!S_ISREG(inode->i_mode)) { /* must be regular file */ + iput(inode); + return -EACCES; + } + i = inode->i_mode; + if (current->uid && current->euid) { + if (current->euid == inode->i_uid) + i >>= 6; + else if (current->egid == inode->i_gid) + i >>= 3; + } else if (i & 0111) + i=1; + if (!(i & 1)) { + iput(inode); + return -ENOEXEC; + } + if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) { + iput(inode); + return -EACCES; + } + ex = *((struct exec *) bh->b_data); /* read exec-header */ + 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)) { + iput(inode); + return -ENOEXEC; + } + if (N_TXTOFF(ex) != BLOCK_SIZE) + panic("N_TXTOFF != BLOCK_SIZE. See a.out.h."); + argc = count(argv); + envc = count(envp); + p = copy_strings(envc,envp,page,PAGE_SIZE*MAX_ARG_PAGES-4); + p = copy_strings(argc,argv,page,p); + if (!p) { + for (i=0 ; i<MAX_ARG_PAGES ; i++) + free_page(page[i]); + iput(inode); + return -1; + } +/* OK, This is the point of no return */ + for (i=0 ; i<32 ; i++) + current->sig_fn[i] = NULL; + for (i=0 ; i<NR_OPEN ; i++) + if ((current->close_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; + i = read_area(inode,ex.a_text+ex.a_data); + iput(inode); + if (i<0) + sys_exit(-1); + 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; +} diff --git a/linux/fs/fcntl.c b/linux/fs/fcntl.c new file mode 100644 index 0000000..169f376 --- /dev/null +++ b/linux/fs/fcntl.c @@ -0,0 +1,69 @@ +#include <string.h> +#include <errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <asm/segment.h> + +#include <fcntl.h> +#include <sys/stat.h> + +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<<arg); + (current->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<<fd); + else + current->close_on_exec &= ~(1<<fd); + return 0; + case F_GETFL: + return filp->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..da5d014 --- /dev/null +++ b/linux/fs/file_dev.c @@ -0,0 +1,84 @@ +#include <errno.h> +#include <fcntl.h> + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <asm/segment.h> + +#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 (i<count) { + if (!(block = create_block(inode,pos/BLOCK_SIZE))) + break; + if (!(bh=bread(inode->i_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..ab7cebf --- /dev/null +++ b/linux/fs/file_table.c @@ -0,0 +1,3 @@ +#include <linux/fs.h> + +struct file file_table[NR_FILE]; diff --git a/linux/fs/inode.c b/linux/fs/inode.c new file mode 100644 index 0000000..d06ff90 --- /dev/null +++ b/linux/fs/inode.c @@ -0,0 +1,288 @@ +#include <string.h> + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <asm/system.h> + +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 sync_inodes(void) +{ + int i; + struct m_inode * inode; + + inode = 0+inode_table; + for(i=0 ; i<NR_INODE ; i++,inode++) { + wait_on_inode(inode); + if (inode->i_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>1) { + inode->i_count--; + return; + } +repeat: + 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; +} + +static volatile int last_allocated_inode = 0; + +struct m_inode * get_empty_inode(void) +{ + struct m_inode * inode; + int inr; + + while (1) { + inode = NULL; + inr = last_allocated_inode; + do { + if (!inode_table[inr].i_count) { + inode = inr + inode_table; + break; + } + inr++; + if (inr>=NR_INODE) + inr=0; + } while (inr != last_allocated_inode); + if (!inode) { + for (inr=0 ; inr<NR_INODE ; inr++) + printk("%04x: %6d\t",inode_table[inr].i_dev, + inode_table[inr].i_num); + panic("No free inodes in mem"); + } + last_allocated_inode = inr; + wait_on_inode(inode); + while (inode->i_dirt) { + write_inode(inode); + wait_on_inode(inode); + } + if (!inode->i_count) + break; + } + 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 (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); + sb=get_super(inode->i_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"); + *(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); + sb=get_super(inode->i_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"); + ((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..131561b --- /dev/null +++ b/linux/fs/ioctl.c @@ -0,0 +1,40 @@ +#include <string.h> +#include <errno.h> +#include <sys/stat.h> + +#include <linux/sched.h> + +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) + panic("unknown device for ioctl"); + 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..600737b --- /dev/null +++ b/linux/fs/namei.c @@ -0,0 +1,678 @@ +#include <linux/sched.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> + +#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; + if (!(current->uid && current->euid)) + mode=0777; + else if (current->uid==inode->i_uid || current->euid==inode->i_uid) + mode >>= 6; + else if (current->gid==inode->i_gid || current->egid==inode->i_gid) + mode >>= 3; + return mode & mask & 0007; +} + +/* + * 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) + :"cx","di","si"); + return same; +} + +/* + * find_entry() + * + * finds and 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. + */ +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; + +#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; + 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]=(i<namelen)?get_fs_byte(name+i):0; + bh->b_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_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))!=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_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 (current->euid && current->uid) + 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<len) { + if ((void *) de >= (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 (current->euid && current->uid) + return -EPERM; + if (!(dir = dir_namei(name,&namelen,&basename))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + bh = find_entry(dir,basename,namelen,&de); + if (!bh) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + brelse(bh); + return -EPERM; + } + if (!(inode = iget(dir->i_dev, de->inode))) { + iput(dir); + 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; + } + inode = iget(dir->i_dev, de->inode); + if (!inode) { + printk("iget failed in delete (%04x:%d)",dir->i_dev,de->inode); + iput(dir); + brelse(bh); + return -ENOENT; + } + if (!S_ISREG(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_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_ISREG(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..6918690 --- /dev/null +++ b/linux/fs/open.c @@ -0,0 +1,188 @@ +#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/tty.h> +#include <linux/kernel.h> +#include <asm/segment.h> + +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; +} + +int sys_access(const char * filename,int mode) +{ + struct m_inode * inode; + int res; + + mode &= 0007; + if (!(inode=namei(filename))) + return -EACCES; + res = inode->i_mode & 0777; + iput(inode); + if (!(current->euid && current->uid)) + if (res & 0111) + res = 0777; + else + res = 0666; + if (current->euid == inode->i_uid) + res >>= 6; + else if (current->egid == inode->i_gid) + res >>= 6; + if ((res & 0007 & mode) == mode) + 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->uid && current->euid) + if (current->uid!=inode->i_uid && current->euid!=inode->i_uid) { + iput(inode); + return -EACCES; + } else + mode = (mode & 0777) | (inode->i_mode & 07000); + 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 (current->uid && current->euid) { + 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 ; fd<NR_OPEN ; fd++) + if (!current->filp[fd]) + break; + if (fd>=NR_OPEN) + return -EINVAL; + current->close_on_exec &= ~(1<<fd); + f=0+file_table; + for (i=0 ; i<NR_FILE ; i++,f++) + if (!f->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; + } + 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<<fd); + if (!(filp = current->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..7e03e13 --- /dev/null +++ b/linux/fs/pipe.c @@ -0,0 +1,92 @@ +#include <signal.h> + +#include <linux/sched.h> +#include <linux/mm.h> /* for get_free_page */ +#include <asm/segment.h> + +int read_pipe(struct m_inode * inode, char * buf, int count) +{ + char * b=buf; + + while (PIPE_EMPTY(*inode)) { + wake_up(&inode->i_wait); + if (inode->i_count != 2) /* are there any writers left? */ + return 0; + sleep_on(&inode->i_wait); + } + while (count>0 && !(PIPE_EMPTY(*inode))) { + count --; + put_fs_byte(((char *)inode->i_size)[PIPE_TAIL(*inode)],b++); + INC_PIPE( PIPE_TAIL(*inode) ); + } + wake_up(&inode->i_wait); + return b-buf; +} + +int write_pipe(struct m_inode * inode, char * buf, int count) +{ + char * b=buf; + + wake_up(&inode->i_wait); + if (inode->i_count != 2) { /* no readers */ + current->signal |= (1<<(SIGPIPE-1)); + return -1; + } + while (count-->0) { + while (PIPE_FULL(*inode)) { + wake_up(&inode->i_wait); + if (inode->i_count != 2) { + current->signal |= (1<<(SIGPIPE-1)); + return b-buf; + } + sleep_on(&inode->i_wait); + } + ((char *)inode->i_size)[PIPE_HEAD(*inode)] = get_fs_byte(b++); + INC_PIPE( PIPE_HEAD(*inode) ); + wake_up(&inode->i_wait); + } + wake_up(&inode->i_wait); + return b-buf; +} + +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 && i<NR_FILE;i++) + if (!file_table[i].f_count) + (f[j++]=i+file_table)->f_count++; + if (j==1) + f[0]->f_count=0; + if (j<2) + return -1; + j=0; + for(i=0;j<2 && i<NR_OPEN;i++) + if (!current->filp[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..93faac2 --- /dev/null +++ b/linux/fs/read_write.c @@ -0,0 +1,97 @@ +#include <sys/stat.h> +#include <errno.h> +#include <sys/types.h> + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <asm/segment.h> + +extern int rw_char(int rw,int dev, char * buf, int count); +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_BLOCKDEV(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):-1; + if (S_ISCHR(inode->i_mode)) + return rw_char(READ,inode->i_zone[0],buf,count); + 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):-1; + if (S_ISCHR(inode->i_mode)) + return rw_char(WRITE,inode->i_zone[0],buf,count); + 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/stat.c b/linux/fs/stat.c new file mode 100644 index 0000000..4bec71d --- /dev/null +++ b/linux/fs/stat.c @@ -0,0 +1,51 @@ +#include <errno.h> +#include <sys/stat.h> + +#include <linux/fs.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <asm/segment.h> + +static int 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<sizeof (tmp) ; i++) + put_fs_byte(((char *) &tmp)[i],&((char *) statbuf)[i]); + return (0); +} + +int sys_stat(char * filename, struct stat * statbuf) +{ + int i; + struct m_inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + i=cp_stat(inode,statbuf); + iput(inode); + return i; +} + +int sys_fstat(unsigned int fd, struct stat * statbuf) +{ + struct file * f; + struct m_inode * inode; + + if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode)) + return -ENOENT; + return cp_stat(inode,statbuf); +} diff --git a/linux/fs/super.c b/linux/fs/super.c new file mode 100644 index 0000000..d832289 --- /dev/null +++ b/linux/fs/super.c @@ -0,0 +1,102 @@ +/* + * super.c contains code to handle the super-block tables. + */ +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/kernel.h> + +/* 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]; + +struct super_block * do_mount(int dev) +{ + struct super_block * p; + struct buffer_head * bh; + int i,block; + + for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++ ) + if (!(p->s_dev)) + break; + p->s_dev = -1; /* mark it in use */ + if (p >= &super_block[NR_SUPER]) + return NULL; + if (!(bh = bread(dev,1))) + return NULL; + *p = *((struct super_block *) bh->b_data); + brelse(bh); + if (p->s_magic != SUPER_MAGIC) { + p->s_dev = 0; + return NULL; + } + for (i=0;i<I_MAP_SLOTS;i++) + p->s_imap[i] = NULL; + for (i=0;i<Z_MAP_SLOTS;i++) + p->s_zmap[i] = NULL; + block=2; + for (i=0 ; i < p->s_imap_blocks ; i++) + if (p->s_imap[i]=bread(dev,block)) + block++; + else + break; + for (i=0 ; i < p->s_zmap_blocks ; i++) + if (p->s_zmap[i]=bread(dev,block)) + block++; + else + break; + if (block != 2+p->s_imap_blocks+p->s_zmap_blocks) { + for(i=0;i<I_MAP_SLOTS;i++) + brelse(p->s_imap[i]); + for(i=0;i<Z_MAP_SLOTS;i++) + brelse(p->s_zmap[i]); + p->s_dev=0; + return NULL; + } + p->s_imap[0]->b_data[0] |= 1; + p->s_zmap[0]->b_data[0] |= 1; + p->s_dev = dev; + p->s_isup = NULL; + p->s_imount = NULL; + p->s_time = 0; + p->s_rd_only = 0; + p->s_dirt = 0; + return p; +} + +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;i<NR_FILE;i++) + file_table[i].f_count=0; + for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++) + p->s_dev = 0; + if (!(p=do_mount(ROOT_DEV))) + panic("Unable to mount root"); + if (!(mi=iget(ROOT_DEV,1))) + 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..fd82db8 --- /dev/null +++ b/linux/fs/truncate.c @@ -0,0 +1,59 @@ +#include <linux/sched.h> + +#include <sys/stat.h> + +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/fs/tty_ioctl.c b/linux/fs/tty_ioctl.c new file mode 100644 index 0000000..b4d9bf7 --- /dev/null +++ b/linux/fs/tty_ioctl.c @@ -0,0 +1,166 @@ +#include <errno.h> +#include <termios.h> + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/tty.h> + +#include <asm/segment.h> +#include <asm/system.h> + +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); + 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; +} + +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]; + 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 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/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..4b0a98e --- /dev/null +++ b/linux/include/asm/memory.h @@ -0,0 +1,14 @@ +/* + * 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)) \ + :"di","si","cx"); \ +_res; \ +}) diff --git a/linux/include/asm/segment.h b/linux/include/asm/segment.h new file mode 100644 index 0000000..1a53b08 --- /dev/null +++ b/linux/include/asm/segment.h @@ -0,0 +1,38 @@ +extern inline unsigned char get_fs_byte(const char * addr) +{ + unsigned register char _v; + + __asm__ ("movb %%fs:%1,%0":"=r" (_v):"m" (*addr)); + return _v; +} + +extern inline unsigned short get_fs_word(const unsigned short *addr) +{ + unsigned short _v; + + __asm__ ("movw %%fs:%1,%0":"=r" (_v):"m" (*addr)); + return _v; +} + +extern inline unsigned long get_fs_long(const unsigned long *addr) +{ + unsigned long _v; + + __asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \ + return _v; +} + +extern inline void put_fs_byte(char val,char *addr) +{ +__asm__ ("movb %0,%%fs:%1"::"r" (val),"m" (*addr)); +} + +extern inline void put_fs_word(short val,short * addr) +{ +__asm__ ("movw %0,%%fs:%1"::"r" (val),"m" (*addr)); +} + +extern inline void put_fs_long(unsigned long val,unsigned long * addr) +{ +__asm__ ("movl %0,%%fs:%1"::"r" (val),"m" (*addr)); +} 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..4043d6e --- /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 <sys/types.h> + +/* 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..c84cacc --- /dev/null +++ b/linux/include/linux/config.h @@ -0,0 +1,53 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +/* #define LASU_HD */ +#define LINUS_HD + +/* + * Amount of ram memory (in bytes, 640k-1M not discounted). Currently 8Mb. + * Don't make this bigger without making sure that there are enough page + * directory entries (boot/head.s) + */ +#if defined(LINUS_HD) +#define HIGH_MEMORY (0x800000) +#elif defined(LASU_HD) +#define HIGH_MEMORY (0x400000) +#else +#error "must define hd" +#endif + +/* End of buffer memory. Must be 0xA0000, or > 0x100000, 4096-byte aligned */ +#if (HIGH_MEMORY>=0x600000) +#define BUFFER_END 0x200000 +#else +#define BUFFER_END 0xA0000 +#endif + +/* Root device at bootup. */ +#if defined(LINUS_HD) +#define ROOT_DEV 0x306 +#elif defined(LASU_HD) +#define ROOT_DEV 0x302 +#else +#error "must define HD" +#endif + +/* + * HD type. If 2, put 2 structures with a comma. If just 1, put + * only 1 struct. The structs are { HEAD, SECTOR, TRACKS, WPCOM, LZONE, CTL } + * + * NOTE. CTL is supposed to be 0 for drives with less than 8 heads, and + * 8 if heads >= 8. Don't know why, and I haven't tested it on a drive with + * more than 8 heads, but that is what the bios-listings seem to imply. I + * just love not having a manual. + */ +#if defined(LASU_HD) +#define HD_TYPE { 7,35,915,65536,920,0 } +#elif defined(LINUS_HD) +#define HD_TYPE { 5,17,980,300,980,0 },{ 5,17,980,300,980,0 } +#else +#error "must define a hard-disk type" +#endif + +#endif diff --git a/linux/include/linux/fs.h b/linux/include/linux/fs.h new file mode 100644 index 0000000..e5db892 --- /dev/null +++ b/linux/include/linux/fs.h @@ -0,0 +1,185 @@ +/* + * This file has definitions for some important file table + * structures etc. + */ + +#ifndef _FS_H +#define _FS_H + +#include <sys/types.h> + +/* 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_BLOCKDEV(x) ((x)==2 || (x)==3) + +#define READ 0 +#define WRITE 1 + +void buffer_init(void); + +#define MAJOR(a) (((unsigned)(a))>>8) +#define MINOR(a) ((a)&0xff) + +#define NAME_LEN 14 + +#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 +#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))) + +typedef char buffer_block[BLOCK_SIZE]; + +struct buffer_head { + char * b_data; /* pointer to data block (1024 bytes) */ + unsigned short b_dev; /* device (0 = free) */ + unsigned short b_blocknr; /* block number */ + 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; +}; + +#define PIPE_HEAD(inode) (((long *)((inode).i_zone))[0]) +#define PIPE_TAIL(inode) (((long *)((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)) + +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; + unsigned char s_rd_only; + unsigned char s_dirt; +}; + +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 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 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 void mount_root(void); + +extern inline struct super_block * get_super(int dev) +{ + struct super_block * s; + + for(s = 0+super_block;s < NR_SUPER+super_block; s++) + if (s->s_dev == dev) + return s; + return NULL; +} + +#endif diff --git a/linux/include/linux/hdreg.h b/linux/include/linux/hdreg.h new file mode 100644 index 0000000..04ebf87 --- /dev/null +++ b/linux/include/linux/hdreg.h @@ -0,0 +1,99 @@ +/* + * 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 + +/* currently supports only 1 hd, put type here */ +#define HARD_DISK_TYPE 17 + +/* + * Ok, hard-disk-type is currently hardcoded. Not beatiful, + * but easier. We don't use BIOS for anything else, why should + * we get HD-type from it? Get these values from Reference Guide. + */ + +#if HARD_DISK_TYPE == 17 +#define _CYL 977 +#define _HEAD 5 +#define __WPCOM 300 +#define _LZONE 977 +#define _SECT 17 +#define _CTL 0 +#elif HARD_DISK_TYPE == 18 +#define _CYL 977 +#define _HEAD 7 +#define __WPCOM (-1) +#define _LZONE 977 +#define _SECT 17 +#define _CTL 0 +#else +#error Define HARD_DISK_TYPE and parameters, add your own entries as well +#endif + +/* Controller wants just wp-com/4 */ +#if __WPCOM >= 0 +#define _WPCOM ((__WPCOM)>>2) +#else +#define _WPCOM __WPCOM +#endif + +/* 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..9e533a7 --- /dev/null +++ b/linux/include/linux/kernel.h @@ -0,0 +1,8 @@ +/* + * '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); 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..bf6b639 --- /dev/null +++ b/linux/include/linux/sched.h @@ -0,0 +1,230 @@ +#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 <linux/head.h> +#include <linux/fs.h> +#include <linux/mm.h> + +#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, 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; + fn_ptr sig_restorer; + fn_ptr sig_fn[32]; +/* various fields */ + int exit_code; + unsigned long 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; + 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,NULL,{(fn_ptr) 0,}, \ +/* ec,brk... */ 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,0133,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 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" \ + "xchgl %%ecx,_current\n\t" \ + "movw %%dx,%1\n\t" \ + "ljmp %0\n\t" \ + "cmpl %%ecx,%2\n\t" \ + "jne 1f\n\t" \ + "clts\n" \ + "1:" \ + ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ + "m" (last_task_used_math),"d" _TSS(n),"c" ((long) task[n])); \ +} + +#define PAGE_ALIGN(n) (((n)+0xfff)&0xfffff000) + +#define _set_base(addr,base) \ +__asm__("movw %%dx,%0\n\t" \ + "rorl $16,%%edx\n\t" \ + "movb %%dl,%1\n\t" \ + "movb %%dh,%2" \ + ::"m" (*((addr)+2)), \ + "m" (*((addr)+4)), \ + "m" (*((addr)+7)), \ + "d" (base) \ + :"dx") + +#define _set_limit(addr,limit) \ +__asm__("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" \ + ::"m" (*(addr)), \ + "m" (*((addr)+6)), \ + "d" (limit) \ + :"dx") + +#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base ) +#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 ) + +#define _get_base(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))); \ +__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..acdcc95 --- /dev/null +++ b/linux/include/linux/sys.h @@ -0,0 +1,80 @@ +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(); + +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}; diff --git a/linux/include/linux/tty.h b/linux/include/linux/tty.h new file mode 100644 index 0000000..1d103e0 --- /dev/null +++ b/linux/include/linux/tty.h @@ -0,0 +1,74 @@ +/* + * '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 <termios.h> + +#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 EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF]) +#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR]) +#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP]) +#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART]) +#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE]) + +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=^Y 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\031\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..b895813 --- /dev/null +++ b/linux/include/signal.h @@ -0,0 +1,65 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include <sys/types.h> + +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 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 (*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 100755 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..05a6d9c --- /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):"si","di","ax"); +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):"si","di","ax","cx"); +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):"si","di","ax","cx"); +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) + :"si","di","ax","cx"); +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):"si","di"); +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):"si","di","cx"); +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):"si"); +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):"ax","si"); +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) + :"ax","cx","dx","di"); +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) + :"ax","cx","dx","di"); +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) + :"ax","cx","dx","di"); +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) + :"cx","dx","di","si"); +return __res; +} + +extern inline int strlen(const char * s) +{ +register int __res __asm__("cx"); +__asm__("cld\n\t" + "repne\n\t" + "scasb\n\t" + "notl %0\n\t" + "decl %0" + :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di"); +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) + :"ax","cx","dx","di"); +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) + :"cx","si","di"); +return dest; +} + +extern inline void * memmove(void * dest,const void * src, int n) +{ +if (dest<src) +__asm__("cld\n\t" + "rep\n\t" + "movsb" + ::"c" (n),"S" (src),"D" (dest) + :"cx","si","di"); +else +__asm__("std\n\t" + "rep\n\t" + "movsb" + ::"c" (n),"S" (src+n-1),"D" (dest+n-1) + :"cx","si","di"); +return dest; +} + +extern inline int memcmp(const void * cs,const void * ct,int count) +{ +register int __res __asm__("ax"); +__asm__("cld\n\t" + "repe\n\t" + "cmpsb\n\t" + "je 1f\n\t" + "movl $1,%%eax\n\t" + "jl 1f\n\t" + "negl %%eax\n" + "1:" + :"=a" (__res):"0" (0),"D" (cs),"S" (ct),"c" (count) + :"si","di","cx"); +return __res; +} + +extern inline void * memchr(const void * cs,char c,int count) +{ +register void * __res __asm__("di"); +if (!count) + return NULL; +__asm__("cld\n\t" + "repne\n\t" + "scasb\n\t" + "je 1f\n\t" + "movl $1,%0\n" + "1:\tdecl %0" + :"=D" (__res):"a" (c),"D" (cs),"c" (count) + :"cx"); +return __res; +} + +extern inline void * memset(void * s,char c,int count) +{ +__asm__("cld\n\t" + "rep\n\t" + "stosb" + ::"a" (c),"D" (s),"c" (count) + :"cx","di"); +return s; +} + +#endif diff --git a/linux/include/sys/stat.h b/linux/include/sys/stat.h new file mode 100644 index 0000000..41c3840 --- /dev/null +++ b/linux/include/sys/stat.h @@ -0,0 +1,58 @@ +#ifndef _SYS_STAT_H +#define _SYS_STAT_H + +#include <sys/types.h> + +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_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_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 <sys/types.h> + +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 <sys/types.h> + +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 <sys/types.h> + +#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..f707674 --- /dev/null +++ b/linux/include/termios.h @@ -0,0 +1,222 @@ +#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 + +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 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 */ + +/* 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..eb10771 --- /dev/null +++ b/linux/include/unistd.h @@ -0,0 +1,247 @@ +#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*/ /* 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 <sys/stat.h> +#include <sys/times.h> +#include <sys/utsname.h> +#include <utime.h> + +#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 _syscall0(type,name) \ +type name(void) \ +{ \ +type __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name)); \ +if (__res >= 0) \ + return __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall1(type,name,atype,a) \ +type name(atype a) \ +{ \ +type __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" (a)); \ +if (__res >= 0) \ + return __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall2(type,name,atype,a,btype,b) \ +type name(atype a,btype b) \ +{ \ +type __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" (a),"c" (b)); \ +if (__res >= 0) \ + return __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall3(type,name,atype,a,btype,b,ctype,c) \ +type name(atype a,btype b,ctype c) \ +{ \ +type __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" (a),"c" (b),"d" (c)); \ +if (__res<0) \ + errno=-__res , __res = -1; \ +return __res;\ +} + +#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); + +#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 <sys/types.h> /* 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..1192119 --- /dev/null +++ b/linux/init/main.c @@ -0,0 +1,147 @@ +#define __LIBRARY__ +#include <unistd.h> +#include <time.h> + +/* + * 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. + */ +static inline _syscall0(int,fork) +static inline _syscall0(int,pause) +static inline _syscall0(int,setup) +static inline _syscall0(int,sync) + +#include <linux/tty.h> +#include <linux/sched.h> +#include <linux/head.h> +#include <asm/system.h> +#include <asm/io.h> + +#include <stddef.h> +#include <stdarg.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> + +#include <linux/fs.h> + +static char printbuf[1024]; + +extern int vsprintf(); +extern void init(void); +extern void hd_init(void); +extern long kernel_mktime(struct tm * tm); +extern long startup_time; + +/* + * 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)-1; + 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); + startup_time = kernel_mktime(&time); +} + +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 + */ + time_init(); + tty_init(); + trap_init(); + sched_init(); + buffer_init(); + hd_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[] = { "-",NULL }; +static char * envp[] = { "HOME=/usr/root", NULL }; + +void init(void) +{ + int i,j; + + setup(); + if (!fork()) + _exit(execve("/bin/update",NULL,NULL)); + (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(" Ok.\n\r"); + if ((i=fork())<0) + printf("Fork failed in init\r\n"); + else if (!i) { + 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)); + } + j=wait(&i); + printf("child %d died with code %04x\n",j,i); + sync(); + _exit(0); /* NOTE! _exit, not exit() */ +} diff --git a/linux/kernel/Makefile b/linux/kernel/Makefile new file mode 100644 index 0000000..23fe7dd --- /dev/null +++ b/linux/kernel/Makefile @@ -0,0 +1,90 @@ +# +# 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 =gar +AS =gas +LD =gld +LDFLAGS =-s -x +CC =gcc +CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \ + -finline-functions -mstring-insns -nostdinc -I../include +CPP =gcc -E -nostdinc -I../include + +.c.s: + $(CC) $(CFLAGS) \ + -S -o $*.s $< +.s.o: + $(AS) -c -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 tty_io.o console.o \ + keyboard.o rs_io.o hd.o sys.o exit.o serial.o \ + mktime.o + +kernel.o: $(OBJS) + $(LD) -r -o kernel.o $(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: +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/linux/tty.h ../include/termios.h ../include/asm/io.h \ + ../include/asm/system.h +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/linux/kernel.h ../include/asm/segment.h \ + ../include/asm/system.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/linux/kernel.h ../include/linux/hdreg.h \ + ../include/asm/system.h ../include/asm/io.h ../include/asm/segment.h +mktime.s mktime.o : mktime.c ../include/time.h +panic.s panic.o : panic.c ../include/linux/kernel.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/linux/kernel.h ../include/signal.h ../include/linux/sys.h \ + ../include/asm/system.h ../include/asm/io.h ../include/asm/segment.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/asm/system.h \ + ../include/asm/io.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/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/linux/kernel.h ../include/asm/system.h \ + ../include/asm/segment.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 +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..6fe1981 --- /dev/null +++ b/linux/kernel/asm.s @@ -0,0 +1,157 @@ +/* + * 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 _device_not_available,_double_fault,_coprocessor_segment_overrun +.globl _invalid_TSS,_segment_not_present,_stack_segment +.globl _general_protection,_coprocessor_error,_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 + +math_emulate: + popl %eax + pushl $_do_device_not_available + jmp no_error_code +_device_not_available: + pushl %eax + movl %cr0,%eax + bt $2,%eax # EM (math emulation bit) + jc math_emulate + clts # clear TS so that we can use math + movl _current,%eax + cmpl _last_task_used_math,%eax + je 1f # shouldn't happen really ... + pushl %ecx + pushl %edx + push %ds + movl $0x10,%eax + mov %ax,%ds + call _math_state_restore + pop %ds + popl %edx + popl %ecx +1: popl %eax + iret + +_coprocessor_segment_overrun: + pushl $_do_coprocessor_segment_overrun + jmp no_error_code + +_reserved: + pushl $_do_reserved + jmp no_error_code + +_coprocessor_error: + pushl $_do_coprocessor_error + jmp no_error_code + +_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/console.c b/linux/kernel/console.c new file mode 100644 index 0000000..9e00b31 --- /dev/null +++ b/linux/kernel/console.c @@ -0,0 +1,550 @@ +/* + * 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. + * + */ + +/* + * 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. + */ + +#include <linux/sched.h> +#include <linux/tty.h> +#include <asm/io.h> +#include <asm/system.h> + +#define SCREEN_START 0xb8000 +#define SCREEN_END 0xc0000 +#define LINES 25 +#define COLUMNS 80 +#define NPAR 16 + +extern void keyboard_interrupt(void); + +static unsigned long origin=SCREEN_START; +static unsigned long scr_end=SCREEN_START+LINES*COLUMNS*2; +static unsigned long pos; +static unsigned long x,y; +static unsigned long top=0,bottom=LINES; +static unsigned long lines=LINES,columns=COLUMNS; +static unsigned long state=0; +static unsigned long npar,par[NPAR]; +static unsigned long ques=0; +static unsigned char attr=0x07; + +/* + * this is what the terminal answers to a ESC-Z or csi0c + * query (= vt100 response). + */ +#define RESPONSE "\033[?1;2c" + +static inline void gotoxy(unsigned int new_x,unsigned int new_y) +{ + if (new_x>=columns || new_y>=lines) + return; + x=new_x; + y=new_y; + pos=origin+((y*columns+x)<<1); +} + +static inline void set_origin(void) +{ + cli(); + outb_p(12,0x3d4); + outb_p(0xff&((origin-SCREEN_START)>>9),0x3d5); + outb_p(13,0x3d4); + outb_p(0xff&((origin-SCREEN_START)>>1),0x3d5); + sti(); +} + +static void scrup(void) +{ + if (!top && bottom==lines) { + origin += columns<<1; + pos += columns<<1; + scr_end += columns<<1; + if (scr_end>SCREEN_END) { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl _columns,%1\n\t" + "rep\n\t" + "stosw" + ::"a" (0x0720), + "c" ((lines-1)*columns>>1), + "D" (SCREEN_START), + "S" (origin) + :"cx","di","si"); + scr_end -= origin-SCREEN_START; + pos -= origin-SCREEN_START; + origin = SCREEN_START; + } else { + __asm__("cld\n\t" + "rep\n\t" + "stosl" + ::"a" (0x07200720), + "c" (columns>>1), + "D" (scr_end-(columns<<1)) + :"cx","di"); + } + set_origin(); + } else { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl _columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (0x0720), + "c" ((bottom-top-1)*columns>>1), + "D" (origin+(columns<<1)*top), + "S" (origin+(columns<<1)*(top+1)) + :"cx","di","si"); + } +} + +static void scrdown(void) +{ + __asm__("std\n\t" + "rep\n\t" + "movsl\n\t" + "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ + "movl _columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (0x0720), + "c" ((bottom-top-1)*columns>>1), + "D" (origin+(columns<<1)*bottom-4), + "S" (origin+(columns<<1)*(bottom-1)-4) + :"ax","cx","di","si"); +} + +static void lf(void) +{ + if (y+1<bottom) { + y++; + pos += columns<<1; + return; + } + scrup(); +} + +static void ri(void) +{ + if (y>top) { + y--; + pos -= columns<<1; + return; + } + scrdown(); +} + +static void cr(void) +{ + pos -= x<<1; + x=0; +} + +static void del(void) +{ + if (x) { + pos -= 2; + x--; + *(unsigned short *)pos = 0x0720; + } +} + +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 = columns*lines; + start = origin; + break; + default: + return; + } + __asm__("cld\n\t" + "rep\n\t" + "stosw\n\t" + ::"c" (count), + "D" (start),"a" (0x0720) + :"cx","di"); +} + +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>=columns) + return; + count = columns-x; + start = pos; + break; + case 1: /* erase from start of line to cursor */ + start = pos - (x<<1); + count = (x<columns)?x:columns; + break; + case 2: /* erase whole line */ + start = pos - (x<<1); + count = columns; + break; + default: + return; + } + __asm__("cld\n\t" + "rep\n\t" + "stosw\n\t" + ::"c" (count), + "D" (start),"a" (0x0720) + :"cx","di"); +} + +void csi_m(void) +{ + int i; + + for (i=0;i<=npar;i++) + switch (par[i]) { + case 0:attr=0x07;break; + case 1:attr=0x0f;break; + case 4:attr=0x0f;break; + case 7:attr=0x70;break; + case 27:attr=0x07;break; + } +} + +static inline void set_cursor(void) +{ + cli(); + outb_p(14,0x3d4); + outb_p(0xff&((pos-SCREEN_START)>>9),0x3d5); + outb_p(15,0x3d4); + outb_p(0xff&((pos-SCREEN_START)>>1),0x3d5); + 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=0x0720; + unsigned short * p = (unsigned short *) pos; + + while (i++<columns) { + tmp=*p; + *p=old; + old=tmp; + p++; + } +} + +static void insert_line(void) +{ + int oldtop,oldbottom; + + oldtop=top; + oldbottom=bottom; + top=y; + bottom=lines; + scrdown(); + top=oldtop; + bottom=oldbottom; +} + +static void delete_char(void) +{ + int i; + unsigned short * p = (unsigned short *) pos; + + if (x>=columns) + return; + i = x; + while (++i < columns) { + *p = *(p+1); + p++; + } + *p=0x0720; +} + +static void delete_line(void) +{ + int oldtop,oldbottom; + + oldtop=top; + oldbottom=bottom; + top=y; + bottom=lines; + scrup(); + top=oldtop; + bottom=oldbottom; +} + +static void csi_at(int nr) +{ + if (nr>columns) + nr=columns; + else if (!nr) + nr=1; + while (nr--) + insert_char(); +} + +static void csi_L(int nr) +{ + if (nr>lines) + nr=lines; + else if (!nr) + nr=1; + while (nr--) + insert_line(); +} + +static void csi_P(int nr) +{ + if (nr>columns) + nr=columns; + else if (!nr) + nr=1; + while (nr--) + delete_char(); +} + +static void csi_M(int nr) +{ + if (nr>lines) + nr=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) +{ + x=saved_x; + y=saved_y; + pos=origin+((y*columns+x)<<1); +} + +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>=columns) { + x -= columns; + pos -= columns<<1; + lf(); + } + __asm__("movb _attr,%%ah\n\t" + "movw %%ax,%1\n\t" + ::"a" (c),"m" (*(short *)pos) + :"ax"); + 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>columns) { + x -= columns; + pos -= columns<<1; + lf(); + } + c=9; + } + 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<NPAR;npar++) + par[npar]=0; + npar=0; + state=3; + if (ques=(c=='?')) + break; + case 3: + if (c==';' && npar<NPAR-1) { + npar++; + break; + } else if (c>='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]=lines; + if (par[0] < par[1] && + par[1] <= 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. + */ +void con_init(void) +{ + register unsigned char a; + + gotoxy(*(unsigned char *)(0x90000+510),*(unsigned char *)(0x90000+511)); + 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); +} diff --git a/linux/kernel/exit.c b/linux/kernel/exit.c new file mode 100644 index 0000000..3402c33 --- /dev/null +++ b/linux/kernel/exit.c @@ -0,0 +1,135 @@ +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/tty.h> +#include <asm/segment.h> + +int sys_pause(void); +int sys_close(int fd); + +void release(struct task_struct * p) +{ + int i; + + if (!p) + return; + for (i=1 ; i<NR_TASKS ; i++) + if (task[i]==p) { + task[i]=NULL; + free_page((long)p); + schedule(); + return; + } + panic("trying to release non-existent task"); +} + +static inline void send_sig(long sig,struct task_struct * p,int priv) +{ + if (!p || sig<1 || sig>32) + return; + if (priv || + current->uid==p->uid || + current->euid==p->uid || + current->uid==p->euid || + current->euid==p->euid) + p->signal |= (1<<(sig-1)); +} + +void do_kill(long pid,long sig,int priv) +{ + struct task_struct **p = NR_TASKS + task; + + if (!pid) while (--p > &FIRST_TASK) { + if (*p && (*p)->pgrp == current->pid) + send_sig(sig,*p,priv); + } else if (pid>0) while (--p > &FIRST_TASK) { + if (*p && (*p)->pid == pid) + send_sig(sig,*p,priv); + } else if (pid == -1) while (--p > &FIRST_TASK) + send_sig(sig,*p,priv); + else while (--p > &FIRST_TASK) + if (*p && (*p)->pgrp == -pid) + send_sig(sig,*p,priv); +} + +int sys_kill(int pid,int sig) +{ + do_kill(pid,sig,!(current->uid || current->euid)); + return 0; +} + +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 ; i<NR_TASKS ; i++) + if (task[i] && task[i]->father == current->pid) + task[i]->father = 0; + for (i=0 ; i<NR_OPEN ; i++) + if (current->filp[i]) + sys_close(i); + iput(current->pwd); + current->pwd=NULL; + iput(current->root); + current->root=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->father) { + current->state = TASK_ZOMBIE; + do_kill(current->father,SIGCHLD,1); + current->exit_code = code; + } else + release(current); + 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,int * stat_addr, int options) +{ + int flag=0; + struct task_struct ** p; + + verify_area(stat_addr,4); +repeat: + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if (*p && *p != current && + (pid==-1 || (*p)->pid==pid || + (pid==0 && (*p)->pgrp==current->pgrp) || + (pid<0 && (*p)->pgrp==-pid))) + if ((*p)->father == current->pid) { + flag=1; + if ((*p)->state==TASK_ZOMBIE) { + put_fs_long((*p)->exit_code, + (unsigned long *) stat_addr); + current->cutime += (*p)->utime; + current->cstime += (*p)->stime; + flag = (*p)->pid; + release(*p); + return flag; + } + } + if (flag) { + if (options & WNOHANG) + return 0; + sys_pause(); + 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..70f9ddd --- /dev/null +++ b/linux/kernel/fork.c @@ -0,0 +1,136 @@ +/* + * '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 <errno.h> + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <asm/segment.h> +#include <asm/system.h> + +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; + 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; + *p = *current; /* NOTE! this doesn't copy the supervisor stack */ + p->state = TASK_RUNNING; + 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__("fnsave %0"::"m" (p->tss.i387)); + if (copy_mem(nr,p)) { + free_page((long) p); + return -EAGAIN; + } + for (i=0; i<NR_OPEN;i++) + if (f=p->filp[i]) + f->f_count++; + if (current->pwd) + current->pwd->i_count++; + if (current->root) + current->root->i_count++; + set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss)); + set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt)); + task[nr] = p; /* 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 ; i<NR_TASKS ; i++) + if (task[i] && task[i]->pid == last_pid) goto repeat; + for(i=1 ; i<NR_TASKS ; i++) + if (!task[i]) + return i; + return -EAGAIN; +} diff --git a/linux/kernel/hd.c b/linux/kernel/hd.c new file mode 100644 index 0000000..d3e6140 --- /dev/null +++ b/linux/kernel/hd.c @@ -0,0 +1,413 @@ +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/hdreg.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/segment.h> + +/* + * This code handles all hd-interrupts, and read/write requests to + * the hard-disk. It is relatively straigthforward (not obvious maybe, + * but interrupts never are), while still being efficient, and never + * disabling interrupts (except to overcome possible race-condition). + * The elevator block-seek algorithm doesn't need to disable interrupts + * due to clever programming. + */ + +/* Max read/write errors/sector */ +#define MAX_ERRORS 5 +#define MAX_HD 2 +#define NR_REQUEST 32 + +/* + * This struct defines the HD's and their types. + * Currently defined for CP3044's, ie a modified + * type 17. + */ +static struct hd_i_struct{ + int head,sect,cyl,wpcom,lzone,ctl; + } hd_info[]= { HD_TYPE }; + +#define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct))) + +static struct hd_struct { + long start_sect; + long nr_sects; +} hd[5*MAX_HD]={{0,0},}; + +static struct hd_request { + int hd; /* -1 if no request */ + int nsector; + int sector; + int head; + int cyl; + int cmd; + int errors; + struct buffer_head * bh; + struct hd_request * next; +} request[NR_REQUEST]; + +#define IN_ORDER(s1,s2) \ +((s1)->hd<(s2)->hd || (s1)->hd==(s2)->hd && \ +((s1)->cyl<(s2)->cyl || (s1)->cyl==(s2)->cyl && \ +((s1)->head<(s2)->head || (s1)->head==(s2)->head && \ +((s1)->sector<(s2)->sector)))) + +static struct hd_request * this_request = NULL; + +static int sorting=0; + +static void do_request(void); +static void reset_controller(void); +static void rw_abs_hd(int rw,unsigned int nr,unsigned int sec,unsigned int head, + unsigned int cyl,struct buffer_head * bh); +void hd_init(void); + +#define port_read(port,buf,nr) \ +__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di") + +#define port_write(port,buf,nr) \ +__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si") + +extern void hd_interrupt(void); + +static struct task_struct * wait_for_request=NULL; + +static inline void lock_buffer(struct buffer_head * bh) +{ + if (bh->b_lock) + printk("hd.c: buffer multiply locked\n"); + bh->b_lock=1; +} + +static inline void unlock_buffer(struct buffer_head * bh) +{ + if (!bh->b_lock) + printk("hd.c: free buffer being unlocked\n"); + bh->b_lock=0; + wake_up(&bh->b_wait); +} + +static inline void wait_on_buffer(struct buffer_head * bh) +{ + cli(); + while (bh->b_lock) + sleep_on(&bh->b_wait); + sti(); +} + +void rw_hd(int rw, struct buffer_head * bh) +{ + unsigned int block,dev; + unsigned int sec,head,cyl; + + block = bh->b_blocknr << 1; + dev = MINOR(bh->b_dev); + if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) + return; + 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)); + rw_abs_hd(rw,dev,sec+1,head,cyl,bh); +} + +/* This may be used only once, enforced by 'static int callable' */ +int sys_setup(void) +{ + static int callable = 1; + int i,drive; + struct partition *p; + + if (!callable) + return -1; + callable = 0; + for (drive=0 ; drive<NR_HD ; drive++) { + rw_abs_hd(READ,drive,1,0,0,(struct buffer_head *) start_buffer); + if (!start_buffer->b_uptodate) { + printk("Unable to read partition table of drive %d\n\r", + drive); + panic(""); + } + if (start_buffer->b_data[510] != 0x55 || (unsigned char) + start_buffer->b_data[511] != 0xAA) { + printk("Bad partition table on drive %d\n\r",drive); + panic(""); + } + p = 0x1BE + (void *)start_buffer->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; + } + } + printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":""); + mount_root(); + return (0); +} + +/* + * This is the pointer to a routine to be executed at every hd-interrupt. + * Interesting way of doing things, but should be rather practical. + */ +void (*do_hd)(void) = NULL; + +static int controller_ready(void) +{ + int retries=1000; + + while (--retries && (inb(HD_STATUS)&0xc0)!=0x40); + return (retries); +} + +static int win_result(void) +{ + int i=inb(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(_CTL,HD_CMD); + port=HD_DATA; + outb_p(_WPCOM,++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 < 100000; i++) + if (READY_STAT == (inb(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 < 1000; i++) nop(); + outb(0,HD_CMD); + for(i = 0; i < 10000 && drive_busy(); i++) /* nothing */; + if (drive_busy()) + printk("HD-controller still busy\n\r"); + if((i = inb(ERR_STAT)) != 1) + printk("HD-controller reset failed: %02x\n\r",i); +} + +static void reset_hd(int nr) +{ + reset_controller(); + hd_out(nr,_SECT,_SECT,_HEAD-1,_CYL,WIN_SPECIFY,&do_request); +} + +void unexpected_hd_interrupt(void) +{ + panic("Unexpected HD interrupt\n\r"); +} + +static void bad_rw_intr(void) +{ + int i = this_request->hd; + + if (this_request->errors++ >= MAX_ERRORS) { + this_request->bh->b_uptodate = 0; + unlock_buffer(this_request->bh); + wake_up(&wait_for_request); + this_request->hd = -1; + this_request=this_request->next; + } + reset_hd(i); +} + +static void read_intr(void) +{ + if (win_result()) { + bad_rw_intr(); + return; + } + port_read(HD_DATA,this_request->bh->b_data+ + 512*(this_request->nsector&1),256); + this_request->errors = 0; + if (--this_request->nsector) + return; + this_request->bh->b_uptodate = 1; + this_request->bh->b_dirt = 0; + wake_up(&wait_for_request); + unlock_buffer(this_request->bh); + this_request->hd = -1; + this_request=this_request->next; + do_request(); +} + +static void write_intr(void) +{ + if (win_result()) { + bad_rw_intr(); + return; + } + if (--this_request->nsector) { + port_write(HD_DATA,this_request->bh->b_data+512,256); + return; + } + this_request->bh->b_uptodate = 1; + this_request->bh->b_dirt = 0; + wake_up(&wait_for_request); + unlock_buffer(this_request->bh); + this_request->hd = -1; + this_request=this_request->next; + do_request(); +} + +static void do_request(void) +{ + int i,r; + + if (sorting) + return; + if (!this_request) { + do_hd=NULL; + return; + } + if (this_request->cmd == WIN_WRITE) { + hd_out(this_request->hd,this_request->nsector,this_request-> + sector,this_request->head,this_request->cyl, + this_request->cmd,&write_intr); + for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++) + /* nothing */ ; + if (!r) { + reset_hd(this_request->hd); + return; + } + port_write(HD_DATA,this_request->bh->b_data+ + 512*(this_request->nsector&1),256); + } else if (this_request->cmd == WIN_READ) { + hd_out(this_request->hd,this_request->nsector,this_request-> + sector,this_request->head,this_request->cyl, + this_request->cmd,&read_intr); + } else + panic("unknown hd-command"); +} + +/* + * add-request adds a request to the linked list. + * It sets the 'sorting'-variable when doing something + * that interrupts shouldn't touch. + */ +static void add_request(struct hd_request * req) +{ + struct hd_request * tmp; + + if (req->nsector != 2) + panic("nsector!=2 not implemented"); +/* + * Not to mess up the linked lists, we never touch the two first + * entries (not this_request, as it is used by current interrups, + * and not this_request->next, as it can be assigned to this_request). + * This is not too high a price to pay for the ability of not + * disabling interrupts. + */ + sorting=1; + if (!(tmp=this_request)) + this_request=req; + else { + if (!(tmp->next)) + tmp->next=req; + else { + tmp=tmp->next; + 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; + } + } + sorting=0; +/* + * NOTE! As a result of sorting, the interrupts may have died down, + * as they aren't redone due to locking with sorting=1. They might + * also never have started, if this is the first request in the queue, + * so we restart them if necessary. + */ + if (!do_hd) + do_request(); +} + +void rw_abs_hd(int rw,unsigned int nr,unsigned int sec,unsigned int head, + unsigned int cyl,struct buffer_head * bh) +{ + struct hd_request * req; + + if (rw!=READ && rw!=WRITE) + panic("Bad hd command, must be R/W"); + lock_buffer(bh); +repeat: + for (req=0+request ; req<NR_REQUEST+request ; req++) + if (req->hd<0) + break; + if (req==NR_REQUEST+request) { + sleep_on(&wait_for_request); + goto repeat; + } + req->hd=nr; + req->nsector=2; + req->sector=sec; + req->head=head; + req->cyl=cyl; + req->cmd = ((rw==READ)?WIN_READ:WIN_WRITE); + req->bh=bh; + req->errors=0; + req->next=NULL; + add_request(req); + wait_on_buffer(bh); +} + +void hd_init(void) +{ + int i; + + for (i=0 ; i<NR_REQUEST ; i++) { + request[i].hd = -1; + request[i].next = NULL; + } + for (i=0 ; i<NR_HD ; i++) { + hd[i*5].start_sect = 0; + hd[i*5].nr_sects = hd_info[i].head* + hd_info[i].sect*hd_info[i].cyl; + } + set_trap_gate(0x2E,&hd_interrupt); + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xbf,0xA1); +} diff --git a/linux/kernel/keyboard.s b/linux/kernel/keyboard.s new file mode 100644 index 0000000..ba54be5 --- /dev/null +++ b/linux/kernel/keyboard.s @@ -0,0 +1,409 @@ +/* + * keyboard.s + */ + +.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 + xorl %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 + +num_table: + .ascii "789 456 1230," +cur_table: + .ascii "HA5 DGC YB623" + +/* + * this routine handles function keys + */ +func: + 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 + +key_map: + .byte 0,27 + .ascii "1234567890+'" + .byte 127,9 + .ascii "qwertyuiop}" + .byte 0,10,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 10,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 '~,10,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 + +/* + * 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 $'z,%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/mktime.c b/linux/kernel/mktime.c new file mode 100644 index 0000000..3ba79be --- /dev/null +++ b/linux/kernel/mktime.c @@ -0,0 +1,52 @@ +#include <time.h> + +/* + * 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; + + 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..feab0cc --- /dev/null +++ b/linux/kernel/panic.c @@ -0,0 +1,11 @@ +/* + * This function is used through-out the kernel (includeinh mm and fs) + * to indicate a major problem. + */ +#include <linux/kernel.h> + +volatile void panic(const char * s) +{ + printk("Kernel panic: %s\n\r",s); + for(;;); +} diff --git a/linux/kernel/printk.c b/linux/kernel/printk.c new file mode 100644 index 0000000..7a70dc3 --- /dev/null +++ b/linux/kernel/printk.c @@ -0,0 +1,33 @@ +/* + * 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 <stdarg.h> +#include <stddef.h> + +#include <linux/kernel.h> + +static char buf[1024]; + +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/rs_io.s b/linux/kernel/rs_io.s new file mode 100644 index 0000000..62f075f --- /dev/null +++ b/linux/kernel/rs_io.s @@ -0,0 +1,141 @@ +/* + * 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 2 +_rs1_interrupt: + pushl $_table_list+8 + jmp rs_int +.align 2 +_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 2 +modem_status: + addl $6,%edx /* clear intr by reading modem status reg */ + inb %dx,%al + ret + +.align 2 +line_status: + addl $5,%edx /* clear intr by reading line status reg. */ + inb %dx,%al + ret + +.align 2 +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) + pushl %edx + call _do_tty_interrupt + addl $4,%esp +1: ret + +.align 2 +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 2 +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/sched.c b/linux/kernel/sched.c new file mode 100644 index 0000000..03399fa --- /dev/null +++ b/linux/kernel/sched.c @@ -0,0 +1,254 @@ +/* + * '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 <linux/sched.h> +#include <linux/kernel.h> +#include <signal.h> +#include <linux/sys.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/segment.h> + +#define LATCH (1193180/HZ) + +extern void mem_use(void); + +extern int timer_interrupt(void); +extern int system_call(void); + +union task_union { + struct task_struct task; + char stack[PAGE_SIZE]; +}; + +static union task_union init_task = {INIT_TASK,}; + +long volatile jiffies=0; +long startup_time=0; +struct task_struct *current = &(init_task.task), *last_task_used_math = NULL; + +struct task_struct * task[NR_TASKS] = {&(init_task.task), }; + +long user_stack [ PAGE_SIZE>>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) + __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387)); + if (current->used_math) + __asm__("frstor %0"::"m" (current->tss.i387)); + else { + __asm__("fninit"::); + current->used_math=1; + } + last_task_used_math=current; +} + +/* + * '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 && (*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; + } +} + +void do_timer(long cpl) +{ + if (cpl) + current->utime++; + else + current->stime++; + if ((--current->counter)>0) return; + current->counter=0; + if (!cpl) return; + schedule(); +} + +int sys_alarm(long seconds) +{ + current->alarm = (seconds>0)?(jiffies+HZ*seconds):0; + return seconds; +} + +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; +} + +int sys_signal(long signal,long addr,long restorer) +{ + long i; + + switch (signal) { + case SIGHUP: case SIGINT: case SIGQUIT: case SIGILL: + case SIGTRAP: case SIGABRT: case SIGFPE: case SIGUSR1: + case SIGSEGV: case SIGUSR2: case SIGPIPE: case SIGALRM: + case SIGCHLD: + i=(long) current->sig_fn[signal-1]; + current->sig_fn[signal-1] = (fn_ptr) addr; + current->sig_restorer = (fn_ptr) restorer; + return i; + default: return -1; + } +} + +void sched_init(void) +{ + int i; + struct desc_struct * p; + + 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;i<NR_TASKS;i++) { + task[i] = NULL; + p->a=p->b=0; + p++; + p->a=p->b=0; + p++; + } + 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/serial.c b/linux/kernel/serial.c new file mode 100644 index 0000000..f542513 --- /dev/null +++ b/linux/kernel/serial.c @@ -0,0 +1,53 @@ +/* + * 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 <linux/tty.h> +#include <linux/sched.h> +#include <asm/system.h> +#include <asm/io.h> + +#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/sys.c b/linux/kernel/sys.c new file mode 100644 index 0000000..f18ee7e --- /dev/null +++ b/linux/kernel/sys.c @@ -0,0 +1,216 @@ +#include <errno.h> + +#include <linux/sched.h> +#include <linux/tty.h> +#include <linux/kernel.h> +#include <asm/segment.h> +#include <sys/times.h> +#include <sys/utsname.h> + +int sys_ftime() +{ + return -ENOSYS; +} + +int sys_mknod() +{ + return -ENOSYS; +} + +int sys_break() +{ + return -ENOSYS; +} + +int sys_mount() +{ + return -ENOSYS; +} + +int sys_umount() +{ + return -ENOSYS; +} + +int sys_ustat(int dev,struct ustat * ubuf) +{ + return -1; +} + +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_setgid(int gid) +{ + if (current->euid && current->uid) + if (current->gid==gid || current->sgid==gid) + current->egid=gid; + else + return -EPERM; + else + current->gid=current->egid=gid; + 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; +} + +int sys_setuid(int uid) +{ + if (current->euid && current->uid) + if (uid==current->uid || current->suid==current->uid) + current->euid=uid; + else + return -EPERM; + else + current->euid=current->uid=uid; + return 0; +} + +int sys_stime(long * tptr) +{ + if (current->euid && current->uid) + return -1; + startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ; + return 0; +} + +int sys_times(struct tms * tbuf) +{ + if (!tbuf) + return jiffies; + 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 = pid; + for (i=0 ; i<NR_TASKS ; i++) + if (task[i] && task[i]->pid==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->uid && current->euid) + return -EPERM; + if (current->leader) + return -EPERM; + current->leader = 1; + current->session = current->pgrp = current->pid; + current->tty = -1; + return current->pgrp; +} + +int sys_uname(struct utsname * name) +{ + static struct utsname thisname = { + "linux .0","nodename","release ","version ","machine " + }; + int i; + + if (!name) return -1; + verify_area(name,sizeof *name); + for(i=0;i<sizeof *name;i++) + put_fs_byte(((char *) &thisname)[i],i+(char *) name); + return (0); +} + +int sys_umask(int mask) +{ + int old = current->umask; + + 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..df4f072 --- /dev/null +++ b/linux/kernel/system_call.s @@ -0,0 +1,219 @@ +/* + * 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-interrupt is 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 +restorer = 16 # address of info-restorer +sig_fn = 20 # table of 32 signal addresses + +nr_system_calls = 67 + +.globl _system_call,_sys_fork,_timer_interrupt,_hd_interrupt,_sys_execve + +.align 2 +bad_sys_call: + movl $-1,%eax + iret +.align 2 +reschedule: + pushl $ret_from_sys_call + jmp _schedule +.align 2 +_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 + movl CS(%esp),%ebx # was old code segment supervisor + testl $3,%ebx # mode? If so - don't check signals + je 3f + cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ? + jne 3f +2: movl signal(%eax),%ebx # signals (bitmap, 32 signals) + bsfl %ebx,%ecx # %ecx is signal nr, return if none + je 3f + btrl %ecx,%ebx # clear it + movl %ebx,signal(%eax) + movl sig_fn(%eax,%ecx,4),%ebx # %ebx is signal handler address + cmpl $1,%ebx + jb default_signal # 0 is default signal handler - exit + je 2b # 1 is ignore - find next signal + movl $0,sig_fn(%eax,%ecx,4) # reset signal handler address + incl %ecx + xchgl %ebx,EIP(%esp) # put new return address on stack + subl $28,OLDESP(%esp) + movl OLDESP(%esp),%edx # push old return address on stack + pushl %eax # but first check that it's ok. + pushl %ecx + pushl $28 + pushl %edx + call _verify_area + popl %edx + addl $4,%esp + popl %ecx + popl %eax + movl restorer(%eax),%eax + movl %eax,%fs:(%edx) # flag/reg restorer + movl %ecx,%fs:4(%edx) # signal nr + movl EAX(%esp),%eax + movl %eax,%fs:8(%edx) # old eax + movl ECX(%esp),%eax + movl %eax,%fs:12(%edx) # old ecx + movl EDX(%esp),%eax + movl %eax,%fs:16(%edx) # old edx + movl EFLAGS(%esp),%eax + movl %eax,%fs:20(%edx) # old eflags + movl %ebx,%fs:24(%edx) # old return addr +3: popl %eax + popl %ebx + popl %ecx + popl %edx + pop %fs + pop %es + pop %ds + iret + +default_signal: + incl %ecx + cmpl $SIG_CHLD,%ecx + je 2b + pushl %ecx + call _do_exit # remember to set bit 7 when dumping core + addl $4,%esp + jmp 3b + +.align 2 +_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 2 +_sys_execve: + lea EIP(%esp),%eax + pushl %eax + call _do_execve + addl $4,%esp + ret + +.align 2 +_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,$0x20 # EOI to interrupt controller #1 + jmp 1f # give port chance to breathe +1: jmp 1f +1: outb %al,$0xA0 # same to controller #2 + movl _do_hd,%eax + testl %eax,%eax + jne 1f + movl $_unexpected_hd_interrupt,%eax +1: call *%eax # "interesting" way of handling intr. + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + diff --git a/linux/kernel/traps.c b/linux/kernel/traps.c new file mode 100644 index 0000000..b6e8bdb --- /dev/null +++ b/linux/kernel/traps.c @@ -0,0 +1,199 @@ +/* + * '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 <string.h> + +#include <linux/head.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <asm/system.h> +#include <asm/segment.h> + +#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); + +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) +{ + die("coprocessor error",esp,error_code); +} + +void do_reserved(long esp, long error_code) +{ + die("reserved (15,17-31) 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<32;i++) + set_trap_gate(i,&reserved); +/* __asm__("movl $0x3ff000,%%eax\n\t" + "movl %%eax,%%db0\n\t" + "movl $0x000d0303,%%eax\n\t" + "movl %%eax,%%db7" + :::"ax");*/ +} + diff --git a/linux/kernel/tty_io.c b/linux/kernel/tty_io.c new file mode 100644 index 0000000..68a390c --- /dev/null +++ b/linux/kernel/tty_io.c @@ -0,0 +1,306 @@ +/* + * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles + * or rs-channels. It also implements echoing, cooked mode etc (well, + * not currently, but ...) + */ +#include <ctype.h> +#include <errno.h> +#include <signal.h> + +#define ALRMMASK (1<<(SIGALRM-1)) + +#include <linux/sched.h> +#include <linux/tty.h> +#include <asm/segment.h> +#include <asm/system.h> + +#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[] = { + { + {0, + OPOST|ONLCR, /* change outgoing NL to CRNL */ + 0, + 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, /*IGNCR*/ + OPOST | ONLRET, /* change outgoing NL to CR */ + 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, /*IGNCR*/ + OPOST | ONLRET, /* change outgoing NL to CR */ + 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 signal) +{ + int i; + + if (tty->pgrp <= 0) + return; + for (i=0;i<NR_TASKS;i++) + if (task[i] && task[i]->pgrp==tty->pgrp) + task[i]->signal |= 1<<(signal-1); +} + +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 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==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,SIGINT); + 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 = (unsigned) 10*tty->termios.c_cc[VTIME]; + minimum = (unsigned) tty->termios.c_cc[VMIN]; + if (time && !minimum) { + minimum=1; + if (flag=(!oldalarm || time+jiffies<oldalarm)) + current->alarm = 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+jiffies<oldalarm)) + current->alarm = 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. + */ +void do_tty_interrupt(int tty) +{ + copy_to_cooked(tty_table+tty); +} diff --git a/linux/kernel/vsprintf.c b/linux/kernel/vsprintf.c new file mode 100644 index 0000000..69c0578 --- /dev/null +++ b/linux/kernel/vsprintf.c @@ -0,0 +1,227 @@ +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include <stdarg.h> +#include <string.h> + +/* 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(i<precision--) + *str++ = '0'; + while(i-->0) + *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..a06698d --- /dev/null +++ b/linux/lib/Makefile @@ -0,0 +1,44 @@ +# +# 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 =gar +AS =gas +LD =gld +LDFLAGS =-s -x +CC =gcc +CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \ + -finline-functions -mstring-insns -nostdinc -I../include +CPP =gcc -E -nostdinc -I../include + +.c.s: + $(CC) $(CFLAGS) \ + -S -o $*.s $< +.s.o: + $(AS) -c -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 + +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: diff --git a/linux/lib/_exit.c b/linux/lib/_exit.c new file mode 100644 index 0000000..44a74e1 --- /dev/null +++ b/linux/lib/_exit.c @@ -0,0 +1,7 @@ +#define __LIBRARY__ +#include <unistd.h> + +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..182d7eb --- /dev/null +++ b/linux/lib/close.c @@ -0,0 +1,4 @@ +#define __LIBRARY__ +#include <unistd.h> + +_syscall1(int,close,int,fd) diff --git a/linux/lib/ctype.c b/linux/lib/ctype.c new file mode 100644 index 0000000..bf58aac --- /dev/null +++ b/linux/lib/ctype.c @@ -0,0 +1,29 @@ +#include <ctype.h> + +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..03bd5d0 --- /dev/null +++ b/linux/lib/dup.c @@ -0,0 +1,4 @@ +#define __LIBRARY__ +#include <unistd.h> + +_syscall1(int,dup,int,fd) diff --git a/linux/lib/errno.c b/linux/lib/errno.c new file mode 100644 index 0000000..6e7bb62 --- /dev/null +++ b/linux/lib/errno.c @@ -0,0 +1 @@ +int errno; diff --git a/linux/lib/execve.c b/linux/lib/execve.c new file mode 100644 index 0000000..03772e3 --- /dev/null +++ b/linux/lib/execve.c @@ -0,0 +1,4 @@ +#define __LIBRARY__ +#include <unistd.h> + +_syscall3(int,execve,const char *,file,char **,argv,char **,envp) diff --git a/linux/lib/open.c b/linux/lib/open.c new file mode 100644 index 0000000..057039c --- /dev/null +++ b/linux/lib/open.c @@ -0,0 +1,19 @@ +#define __LIBRARY__ +#include <unistd.h> +#include <stdarg.h> + +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..730abf0 --- /dev/null +++ b/linux/lib/setsid.c @@ -0,0 +1,4 @@ +#define __LIBRARY__ +#include <unistd.h> + +_syscall0(pid_t,setsid) diff --git a/linux/lib/string.c b/linux/lib/string.c new file mode 100644 index 0000000..f6befd9 --- /dev/null +++ b/linux/lib/string.c @@ -0,0 +1,8 @@ +#ifndef __GNUC__ +#error I want gcc! +#endif + +#define extern +#define inline +#define __LIBRARY__ +#include <string.h> diff --git a/linux/lib/wait.c b/linux/lib/wait.c new file mode 100644 index 0000000..a14555c --- /dev/null +++ b/linux/lib/wait.c @@ -0,0 +1,10 @@ +#define __LIBRARY__ +#include <unistd.h> +#include <sys/wait.h> + +_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..2613f17 --- /dev/null +++ b/linux/lib/write.c @@ -0,0 +1,4 @@ +#define __LIBRARY__ +#include <unistd.h> + +_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..cee1f09 --- /dev/null +++ b/linux/mm/Makefile @@ -0,0 +1,37 @@ +CC =gcc +CFLAGS =-O -Wall -fstrength-reduce -fcombine-regs -fomit-frame-pointer \ + -finline-functions -nostdinc -I../include +AS =gas +AR =gar +LD =gld +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/linux/config.h ../include/linux/head.h ../include/linux/kernel.h \ + ../include/asm/system.h diff --git a/linux/mm/memory.c b/linux/mm/memory.c new file mode 100644 index 0000000..7cdcfb6 --- /dev/null +++ b/linux/mm/memory.c @@ -0,0 +1,264 @@ +#include <signal.h> + +#include <linux/config.h> +#include <linux/head.h> +#include <linux/kernel.h> +#include <asm/system.h> + +int do_exit(long code); + +#define invalidate() \ +__asm__("movl %%eax,%%cr3"::"a" (0)) + +#if (BUFFER_END < 0x100000) +#define LOW_MEM 0x100000 +#else +#define LOW_MEM BUFFER_END +#endif + +/* these are not to be changed - thay are calculated from the above */ +#define PAGING_MEMORY (HIGH_MEMORY - LOW_MEM) +#define PAGING_PAGES (PAGING_MEMORY/4096) +#define MAP_NR(addr) (((addr)-LOW_MEM)>>12) + +#if (PAGING_PAGES < 10) +#error "Won't work" +#endif + +#define copy_page(from,to) \ +__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si") + +static unsigned short 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 ; scasw\n\t" + "jne 1f\n\t" + "movw $1,2(%%edi)\n\t" + "sall $12,%%ecx\n\t" + "movl %%ecx,%%edx\n\t" + "addl %2,%%edx\n\t" + "movl $1024,%%ecx\n\t" + "leal 4092(%%edx),%%edi\n\t" + "rep ; stosl\n\t" + "movl %%edx,%%eax\n" + "1:" + :"=a" (__res) + :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES), + "D" (mem_map+PAGING_PAGES-1) + :"di","cx","dx"); +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; + 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; + return; + } + if (!(new_page=get_free_page())) + do_exit(SIGSEGV); + if (old_page >= LOW_MEM) + mem_map[MAP_NR(old_page)]--; + *table_entry = new_page | 7; + 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. + */ +void do_wp_page(unsigned long error_code,unsigned long address) +{ + 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 do_no_page(unsigned long error_code,unsigned long address) +{ + unsigned long tmp; + + if (tmp=get_free_page()) + if (put_page(tmp,address)) + return; + do_exit(SIGSEGV); +} + +void calc_mem(void) +{ + int i,j,k,free=0; + long * pg_tbl; + + for(i=0 ; i<PAGING_PAGES ; i++) + if (!mem_map[i]) free++; + printk("%d pages free (of %d)\n\r",free,PAGING_PAGES); + for(i=2 ; i<1024 ; i++) { + if (1&pg_dir[i]) { + pg_tbl=(long *) (0xfffff000 & pg_dir[i]); + for(j=k=0 ; j<1024 ; j++) + if (pg_tbl[j]&1) + k++; + printk("Pg-dir[%d] uses %d pages\n",i,k); + } + } +} diff --git a/linux/mm/page.s b/linux/mm/page.s new file mode 100644 index 0000000..27488c2 --- /dev/null +++ b/linux/mm/page.s @@ -0,0 +1,34 @@ +/* + * page.s contains the low-level page-exception code. + * the real work is done in mm.c + */ + +.globl _page_fault + +_page_fault: + xchgl %eax,(%esp) + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + movl $0x10,%edx + mov %dx,%ds + mov %dx,%es + mov %dx,%fs + movl %cr2,%edx + pushl %edx + pushl %eax + testl $1,%eax + jne 1f + call _do_no_page + jmp 2f +1: call _do_wp_page +2: addl $8,%esp + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret diff --git a/linux/tools/build.c b/linux/tools/build.c new file mode 100644 index 0000000..6afe58c --- /dev/null +++ b/linux/tools/build.c @@ -0,0 +1,68 @@ +#include <stdio.h> /* fprintf */ +#include <stdlib.h> /* contains exit */ +#include <sys/types.h> /* unistd.h needs this */ +#include <unistd.h> /* contains read/write */ +#include <fcntl.h> + +#define MINIX_HEADER 32 +#define GCC_HEADER 1024 + +void die(char * str) +{ + fprintf(stderr,"%s\n",str); + exit(1); +} + +void usage(void) +{ + die("Usage: build boot system [> image]"); +} + +int main(int argc, char ** argv) +{ + int i,c,id; + char buf[1024]; + + if (argc != 3) + usage(); + for (i=0;i<sizeof buf; i++) buf[i]=0; + if ((id=open(argv[1],O_RDONLY,0))<0) + die("Unable to open 'boot'"); + if (read(id,buf,MINIX_HEADER) != MINIX_HEADER) + die("Unable to read header of 'boot'"); + if (((long *) buf)[0]!=0x04100301) + die("Non-Minix header of 'boot'"); + if (((long *) buf)[1]!=MINIX_HEADER) + die("Non-Minix header of 'boot'"); + if (((long *) buf)[3]!=0) + die("Illegal data segment in 'boot'"); + if (((long *) buf)[4]!=0) + die("Illegal bss in 'boot'"); + if (((long *) buf)[5] != 0) + die("Non-Minix header of 'boot'"); + if (((long *) buf)[7] != 0) + die("Illegal symbol table in 'boot'"); + i=read(id,buf,sizeof buf); + fprintf(stderr,"Boot sector %d bytes.\n",i); + if (i>510) + die("Boot block may not exceed 510 bytes"); + buf[510]=0x55; + buf[511]=0xAA; + i=write(1,buf,512); + if (i!=512) + die("Write call failed"); + close (id); + + if ((id=open(argv[2],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 %d bytes.\n",i); + return(0); +} |
