diff --git a/kernel/0.00/11.21.linux.tar.gz b/kernel/0.00/11.21.linux.tar.gz new file mode 100644 index 00000000..137e3141 Binary files /dev/null and b/kernel/0.00/11.21.linux.tar.gz differ diff --git a/kernel/0.00/linux-0.00-041217.tar.gz b/kernel/0.00/linux-0.00-041217.tar.gz new file mode 100644 index 00000000..0cacc3fb Binary files /dev/null and b/kernel/0.00/linux-0.00-041217.tar.gz differ diff --git a/kernel/0.00/linux-0.00-050613.tar.gz b/kernel/0.00/linux-0.00-050613.tar.gz new file mode 100644 index 00000000..710f6c20 Binary files /dev/null and b/kernel/0.00/linux-0.00-050613.tar.gz differ diff --git a/kernel/0.00/linux-0.00-rh9-050120.tar.gz b/kernel/0.00/linux-0.00-rh9-050120.tar.gz new file mode 100644 index 00000000..425fe667 Binary files /dev/null and b/kernel/0.00/linux-0.00-rh9-050120.tar.gz differ diff --git a/kernel/0.00/linux-0.00-rh9-050613.tar.gz b/kernel/0.00/linux-0.00-rh9-050613.tar.gz new file mode 100644 index 00000000..49addbf9 Binary files /dev/null and b/kernel/0.00/linux-0.00-rh9-050613.tar.gz differ diff --git a/kernel/0.00/linux-0.01/Makefile b/kernel/0.00/linux-0.01/Makefile new file mode 100644 index 00000000..768b9b9b --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/boot/boot.s b/kernel/0.00/linux-0.01/boot/boot.s new file mode 100644 index 00000000..d19da279 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/boot/head.s b/kernel/0.00/linux-0.01/boot/head.s new file mode 100644 index 00000000..5b180f05 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/fs/Makefile b/kernel/0.00/linux-0.01/fs/Makefile new file mode 100644 index 00000000..4e346182 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/fs/bitmap.c b/kernel/0.00/linux-0.01/fs/bitmap.c new file mode 100644 index 00000000..750f1144 --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/bitmap.c @@ -0,0 +1,158 @@ +/* bitmap.c contains the code that handles the inode and block bitmaps */ +#include + +#include +#include + +#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/kernel/0.00/linux-0.01/fs/block_dev.c b/kernel/0.00/linux-0.01/fs/block_dev.c new file mode 100644 index 00000000..04c0ba2e --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/block_dev.c @@ -0,0 +1,86 @@ +#include + +#include +#include +#include + +#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 = (countb_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 = (countb_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/kernel/0.00/linux-0.01/fs/buffer.c b/kernel/0.00/linux-0.01/fs/buffer.c new file mode 100644 index 00000000..223f9fa2 --- /dev/null +++ b/kernel/0.00/linux-0.01/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 +#include +#include +#include + +#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 ; ib_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 ; ib_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 + +#include +#include + +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/kernel/0.00/linux-0.01/fs/exec.c b/kernel/0.00/linux-0.01/fs/exec.c new file mode 100644 index 00000000..6b90886c --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/exec.c @@ -0,0 +1,306 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +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 ; counti_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 (ildt[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 ; ii_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 ; isig_fn[i] = NULL; + for (i=0 ; iclose_on_exec>>i)&1) + sys_close(i); + current->close_on_exec = 0; + free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); + free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); + if (last_task_used_math == current) + last_task_used_math = NULL; + current->used_math = 0; + p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE; + p = (unsigned long) create_tables((char *)p,argc,envc); + current->brk = ex.a_bss + + (current->end_data = ex.a_data + + (current->end_code = ex.a_text)); + current->start_stack = p & 0xfffff000; + 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/kernel/0.00/linux-0.01/fs/fcntl.c b/kernel/0.00/linux-0.01/fs/fcntl.c new file mode 100644 index 00000000..49581a4c --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/fcntl.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include + +#include +#include + +extern int sys_close(int fd); + +static int dupfd(unsigned int fd, unsigned int arg) +{ + if (fd >= NR_OPEN || !current->filp[fd]) + return -EBADF; + if (arg >= NR_OPEN) + return -EINVAL; + while (arg < NR_OPEN) + if (current->filp[arg]) + arg++; + else + break; + if (arg >= NR_OPEN) + return -EMFILE; + current->close_on_exec &= ~(1<filp[arg] = current->filp[fd])->f_count++; + return arg; +} + +int sys_dup2(unsigned int oldfd, unsigned int newfd) +{ + sys_close(newfd); + return dupfd(oldfd,newfd); +} + +int sys_dup(unsigned int fildes) +{ + return dupfd(fildes,0); +} + +int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + switch (cmd) { + case F_DUPFD: + return dupfd(fd,arg); + case F_GETFD: + return (current->close_on_exec>>fd)&1; + case F_SETFD: + if (arg&1) + current->close_on_exec |= (1<close_on_exec &= ~(1<f_flags; + case F_SETFL: + filp->f_flags &= ~(O_APPEND | O_NONBLOCK); + filp->f_flags |= arg & (O_APPEND | O_NONBLOCK); + return 0; + case F_GETLK: case F_SETLK: case F_SETLKW: + return -1; + default: + return -1; + } +} diff --git a/kernel/0.00/linux-0.01/fs/file_dev.c b/kernel/0.00/linux-0.01/fs/file_dev.c new file mode 100644 index 00000000..f3129086 --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/file_dev.c @@ -0,0 +1,84 @@ +#include +#include + +#include +#include +#include + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) +{ + int left,chars,nr; + struct buffer_head * bh; + + if ((left=count)<=0) + return 0; + while (left) { + if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) { + if (!(bh=bread(inode->i_dev,nr))) + break; + } else + bh = NULL; + nr = filp->f_pos % BLOCK_SIZE; + chars = MIN( BLOCK_SIZE-nr , left ); + filp->f_pos += chars; + left -= chars; + if (bh) { + char * p = nr + bh->b_data; + while (chars-->0) + put_fs_byte(*(p++),buf++); + brelse(bh); + } else { + while (chars-->0) + put_fs_byte(0,buf++); + } + } + inode->i_atime = CURRENT_TIME; + return (count-left)?(count-left):-ERROR; +} + +int file_write(struct m_inode * inode, struct file * filp, char * buf, int count) +{ + off_t pos; + int block,c; + struct buffer_head * bh; + char * p; + int i=0; + +/* + * ok, append may not work when many processes are writing at the same time + * but so what. That way leads to madness anyway. + */ + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + else + pos = filp->f_pos; + while (ii_dev,block))) + break; + c = pos % BLOCK_SIZE; + p = c + bh->b_data; + bh->b_dirt = 1; + c = BLOCK_SIZE-c; + if (c > count-i) c = count-i; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + i += c; + while (c-->0) + *(p++) = get_fs_byte(buf++); + brelse(bh); + } + inode->i_mtime = CURRENT_TIME; + if (!(filp->f_flags & O_APPEND)) { + filp->f_pos = pos; + inode->i_ctime = CURRENT_TIME; + } + return (i?i:-1); +} diff --git a/kernel/0.00/linux-0.01/fs/file_table.c b/kernel/0.00/linux-0.01/fs/file_table.c new file mode 100644 index 00000000..08e48079 --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/file_table.c @@ -0,0 +1,3 @@ +#include + +struct file file_table[NR_FILE]; diff --git a/kernel/0.00/linux-0.01/fs/inode.c b/kernel/0.00/linux-0.01/fs/inode.c new file mode 100644 index 00000000..901a660a --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/inode.c @@ -0,0 +1,288 @@ +#include + +#include +#include +#include +#include + +struct m_inode inode_table[NR_INODE]={{0,},}; + +static void read_inode(struct m_inode * inode); +static void write_inode(struct m_inode * inode); + +static inline void wait_on_inode(struct m_inode * inode) +{ + cli(); + while (inode->i_lock) + sleep_on(&inode->i_wait); + sti(); +} + +static inline void lock_inode(struct m_inode * inode) +{ + cli(); + while (inode->i_lock) + sleep_on(&inode->i_wait); + inode->i_lock=1; + sti(); +} + +static inline void unlock_inode(struct m_inode * inode) +{ + inode->i_lock=0; + wake_up(&inode->i_wait); +} + +void sync_inodes(void) +{ + int i; + struct m_inode * inode; + + inode = 0+inode_table; + for(i=0 ; ii_dirt && !inode->i_pipe) + write_inode(inode); + } +} + +static int _bmap(struct m_inode * inode,int block,int create) +{ + struct buffer_head * bh; + int i; + + if (block<0) + panic("_bmap: block<0"); + if (block >= 7+512+512*512) + panic("_bmap: block>big"); + if (block<7) { + if (create && !inode->i_zone[block]) + if (inode->i_zone[block]=new_block(inode->i_dev)) { + inode->i_ctime=CURRENT_TIME; + inode->i_dirt=1; + } + return inode->i_zone[block]; + } + block -= 7; + if (block<512) { + if (create && !inode->i_zone[7]) + if (inode->i_zone[7]=new_block(inode->i_dev)) { + inode->i_dirt=1; + inode->i_ctime=CURRENT_TIME; + } + if (!inode->i_zone[7]) + return 0; + if (!(bh = bread(inode->i_dev,inode->i_zone[7]))) + return 0; + i = ((unsigned short *) (bh->b_data))[block]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block]=i; + bh->b_dirt=1; + } + brelse(bh); + return i; + } + block -= 512; + if (create && !inode->i_zone[8]) + if (inode->i_zone[8]=new_block(inode->i_dev)) { + inode->i_dirt=1; + inode->i_ctime=CURRENT_TIME; + } + if (!inode->i_zone[8]) + return 0; + if (!(bh=bread(inode->i_dev,inode->i_zone[8]))) + return 0; + i = ((unsigned short *)bh->b_data)[block>>9]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block>>9]=i; + bh->b_dirt=1; + } + brelse(bh); + if (!i) + return 0; + if (!(bh=bread(inode->i_dev,i))) + return 0; + i = ((unsigned short *)bh->b_data)[block&511]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block&511]=i; + bh->b_dirt=1; + } + brelse(bh); + return i; +} + +int bmap(struct m_inode * inode,int block) +{ + return _bmap(inode,block,0); +} + +int create_block(struct m_inode * inode, int block) +{ + return _bmap(inode,block,1); +} + +void iput(struct m_inode * inode) +{ + if (!inode) + return; + wait_on_inode(inode); + if (!inode->i_count) + panic("iput: trying to free free inode"); + if (inode->i_pipe) { + wake_up(&inode->i_wait); + if (--inode->i_count) + return; + free_page(inode->i_size); + inode->i_count=0; + inode->i_dirt=0; + inode->i_pipe=0; + return; + } + if (!inode->i_dev || inode->i_count>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 ; inri_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/kernel/0.00/linux-0.01/fs/ioctl.c b/kernel/0.00/linux-0.01/fs/ioctl.c new file mode 100644 index 00000000..f1c5197e --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/ioctl.c @@ -0,0 +1,40 @@ +#include +#include +#include + +#include + +extern int tty_ioctl(int dev, int cmd, int arg); + +typedef int (*ioctl_ptr)(int dev,int cmd,int arg); + +#define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr))) + +static ioctl_ptr ioctl_table[]={ + NULL, /* nodev */ + NULL, /* /dev/mem */ + NULL, /* /dev/fd */ + NULL, /* /dev/hd */ + tty_ioctl, /* /dev/ttyx */ + tty_ioctl, /* /dev/tty */ + NULL, /* /dev/lp */ + NULL}; /* named pipes */ + + +int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + int dev,mode; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + mode=filp->f_inode->i_mode; + if (!S_ISCHR(mode) && !S_ISBLK(mode)) + return -EINVAL; + dev = filp->f_inode->i_zone[0]; + if (MAJOR(dev) >= NRDEVS) + panic("unknown device for ioctl"); + if (!ioctl_table[MAJOR(dev)]) + return -ENOTTY; + return ioctl_table[MAJOR(dev)](dev,cmd,arg); +} diff --git a/kernel/0.00/linux-0.01/fs/namei.c b/kernel/0.00/linux-0.01/fs/namei.c new file mode 100644 index 00000000..21fb93a0 --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/namei.c @@ -0,0 +1,678 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE]) + +/* + * comment out this line if you want names > NAME_LEN chars to be + * truncated. Else they will be disallowed. + */ +/* #define NO_TRUNCATE */ + +#define MAY_EXEC 1 +#define MAY_WRITE 2 +#define MAY_READ 4 + +/* + * permission() + * + * is used to check for read/write/execute permissions on a file. + * I don't know if we should look at just the euid or both euid and + * uid, but that should be easily changed. + */ +static int permission(struct m_inode * inode,int mask) +{ + int mode = inode->i_mode; + +/* special case: not even root can read/write a deleted file */ + if (inode->i_dev && !inode->i_nlinks) + return 0; + 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]=(ib_dirt = 1; + *res_dir = de; + return bh; + } + de++; + i++; + } + brelse(bh); + return NULL; +} + +/* + * get_dir() + * + * Getdir traverses the pathname until it hits the topmost directory. + * It returns NULL on failure. + */ +static struct m_inode * get_dir(const char * pathname) +{ + char c; + const char * thisname; + struct m_inode * inode; + struct buffer_head * bh; + int namelen,inr,idev; + struct dir_entry * de; + + if (!current->root || !current->root->i_count) + panic("No root inode"); + if (!current->pwd || !current->pwd->i_count) + panic("No cwd inode"); + if ((c=get_fs_byte(pathname))=='/') { + inode = current->root; + pathname++; + } else if (c) + inode = current->pwd; + else + return NULL; /* empty name is bad */ + inode->i_count++; + while (1) { + thisname = pathname; + if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) { + iput(inode); + return NULL; + } + for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++) + /* nothing */ ; + if (!c) + return inode; + if (!(bh = find_entry(inode,thisname,namelen,&de))) { + iput(inode); + return NULL; + } + inr = de->inode; + idev = inode->i_dev; + brelse(bh); + iput(inode); + if (!(inode = iget(idev,inr))) + return NULL; + } +} + +/* + * dir_namei() + * + * dir_namei() returns the inode of the directory of the + * specified name, and the name within that directory. + */ +static struct m_inode * dir_namei(const char * pathname, + int * namelen, const char ** name) +{ + char c; + const char * basename; + struct m_inode * dir; + + if (!(dir = get_dir(pathname))) + return NULL; + basename = pathname; + while (c=get_fs_byte(pathname++)) + if (c=='/') + basename=pathname; + *namelen = pathname-basename-1; + *name = basename; + return dir; +} + +/* + * namei() + * + * is used by most simple commands to get the inode of a specified name. + * Open, link etc use their own routines, but this is enough for things + * like 'chmod' etc. + */ +struct m_inode * namei(const char * pathname) +{ + const char * basename; + int inr,dev,namelen; + struct m_inode * dir; + struct buffer_head * bh; + struct dir_entry * de; + + if (!(dir = dir_namei(pathname,&namelen,&basename))) + return NULL; + if (!namelen) /* special case: '/usr/' etc */ + return dir; + bh = find_entry(dir,basename,namelen,&de); + if (!bh) { + iput(dir); + return NULL; + } + inr = de->inode; + dev = dir->i_dev; + brelse(bh); + iput(dir); + dir=iget(dev,inr); + if (dir) { + dir->i_atime=CURRENT_TIME; + dir->i_dirt=1; + } + return dir; +} + +/* + * open_namei() + * + * namei for open - this is in fact almost the whole open-routine. + */ +int open_namei(const char * pathname, int flag, int mode, + struct m_inode ** res_inode) +{ + const char * basename; + int inr,dev,namelen; + struct m_inode * dir, *inode; + struct buffer_head * bh; + struct dir_entry * de; + + if ((flag & O_TRUNC) && !(flag & O_ACCMODE)) + flag |= O_WRONLY; + mode &= 0777 & ~current->umask; + mode |= I_REGULAR; + if (!(dir = dir_namei(pathname,&namelen,&basename))) + return -ENOENT; + if (!namelen) { /* special case: '/usr/' etc */ + if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) { + *res_inode=dir; + return 0; + } + iput(dir); + return -EISDIR; + } + bh = find_entry(dir,basename,namelen,&de); + if (!bh) { + if (!(flag & O_CREAT)) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EACCES; + } + inode = new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_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= (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/kernel/0.00/linux-0.01/fs/open.c b/kernel/0.00/linux-0.01/fs/open.c new file mode 100644 index 00000000..88f8e540 --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/open.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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 ; fdfilp[fd]) + break; + if (fd>=NR_OPEN) + return -EINVAL; + current->close_on_exec &= ~(1<f_count) break; + if (i>=NR_FILE) + return -EINVAL; + (current->filp[fd]=f)->f_count++; + if ((i=open_namei(filename,flag,mode,&inode))<0) { + current->filp[fd]=NULL; + f->f_count=0; + return i; + } +/* ttys are somewhat special (ttyxx major==4, tty major==5) */ + if (S_ISCHR(inode->i_mode)) + if (MAJOR(inode->i_zone[0])==4) { + if (current->leader && current->tty<0) { + current->tty = MINOR(inode->i_zone[0]); + tty_table[current->tty].pgrp = current->pgrp; + } + } else if (MAJOR(inode->i_zone[0])==5) + if (current->tty<0) { + iput(inode); + current->filp[fd]=NULL; + f->f_count=0; + return -EPERM; + } + f->f_mode = inode->i_mode; + f->f_flags = flag; + f->f_count = 1; + f->f_inode = inode; + f->f_pos = 0; + return (fd); +} + +int sys_creat(const char * pathname, int mode) +{ + return sys_open(pathname, O_CREAT | O_TRUNC, mode); +} + +int sys_close(unsigned int fd) +{ + struct file * filp; + + if (fd >= NR_OPEN) + return -EINVAL; + current->close_on_exec &= ~(1<filp[fd])) + return -EINVAL; + current->filp[fd] = NULL; + if (filp->f_count == 0) + panic("Close: file count is 0"); + if (--filp->f_count) + return (0); + iput(filp->f_inode); + return (0); +} diff --git a/kernel/0.00/linux-0.01/fs/pipe.c b/kernel/0.00/linux-0.01/fs/pipe.c new file mode 100644 index 00000000..c1c02b8e --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/pipe.c @@ -0,0 +1,92 @@ +#include + +#include +#include /* for get_free_page */ +#include + +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 && if_count++; + if (j==1) + f[0]->f_count=0; + if (j<2) + return -1; + j=0; + for(i=0;j<2 && ifilp[i]) { + current->filp[ fd[j]=i ] = f[j]; + j++; + } + if (j==1) + current->filp[fd[0]]=NULL; + if (j<2) { + f[0]->f_count=f[1]->f_count=0; + return -1; + } + if (!(inode=get_pipe_inode())) { + current->filp[fd[0]] = + current->filp[fd[1]] = NULL; + f[0]->f_count = f[1]->f_count = 0; + return -1; + } + f[0]->f_inode = f[1]->f_inode = inode; + f[0]->f_pos = f[1]->f_pos = 0; + f[0]->f_mode = 1; /* read */ + f[1]->f_mode = 2; /* write */ + put_fs_long(fd[0],0+fildes); + put_fs_long(fd[1],1+fildes); + return 0; +} diff --git a/kernel/0.00/linux-0.01/fs/read_write.c b/kernel/0.00/linux-0.01/fs/read_write.c new file mode 100644 index 00000000..cde0fa87 --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/read_write.c @@ -0,0 +1,97 @@ +#include +#include +#include + +#include +#include +#include + +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/kernel/0.00/linux-0.01/fs/stat.c b/kernel/0.00/linux-0.01/fs/stat.c new file mode 100644 index 00000000..2f61f462 --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/stat.c @@ -0,0 +1,51 @@ +#include +#include + +#include +#include +#include +#include + +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= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode)) + return -ENOENT; + return cp_stat(inode,statbuf); +} diff --git a/kernel/0.00/linux-0.01/fs/super.c b/kernel/0.00/linux-0.01/fs/super.c new file mode 100644 index 00000000..f4920918 --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/super.c @@ -0,0 +1,102 @@ +/* + * super.c contains code to handle the super-block tables. + */ +#include +#include +#include + +/* 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;is_imap[i] = NULL; + for (i=0;is_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;is_imap[i]); + for(i=0;is_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;is_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/kernel/0.00/linux-0.01/fs/truncate.c b/kernel/0.00/linux-0.01/fs/truncate.c new file mode 100644 index 00000000..9aec07cd --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/truncate.c @@ -0,0 +1,59 @@ +#include + +#include + +static void free_ind(int dev,int block) +{ + struct buffer_head * bh; + unsigned short * p; + int i; + + if (!block) + return; + if (bh=bread(dev,block)) { + p = (unsigned short *) bh->b_data; + for (i=0;i<512;i++,p++) + if (*p) + free_block(dev,*p); + brelse(bh); + } + free_block(dev,block); +} + +static void free_dind(int dev,int block) +{ + struct buffer_head * bh; + unsigned short * p; + int i; + + if (!block) + return; + if (bh=bread(dev,block)) { + p = (unsigned short *) bh->b_data; + for (i=0;i<512;i++,p++) + if (*p) + free_ind(dev,*p); + brelse(bh); + } + free_block(dev,block); +} + +void truncate(struct m_inode * inode) +{ + int i; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) + return; + for (i=0;i<7;i++) + if (inode->i_zone[i]) { + free_block(inode->i_dev,inode->i_zone[i]); + inode->i_zone[i]=0; + } + free_ind(inode->i_dev,inode->i_zone[7]); + free_dind(inode->i_dev,inode->i_zone[8]); + inode->i_zone[7] = inode->i_zone[8] = 0; + inode->i_size = 0; + inode->i_dirt = 1; + inode->i_mtime = inode->i_ctime = CURRENT_TIME; +} + diff --git a/kernel/0.00/linux-0.01/fs/tty_ioctl.c b/kernel/0.00/linux-0.01/fs/tty_ioctl.c new file mode 100644 index 00000000..9d345aee --- /dev/null +++ b/kernel/0.00/linux-0.01/fs/tty_ioctl.c @@ -0,0 +1,166 @@ +#include +#include + +#include +#include +#include + +#include +#include + +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/kernel/0.00/linux-0.01/include/a.out.h b/kernel/0.00/linux-0.01/include/a.out.h new file mode 100644 index 00000000..2f5f3dcd --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/asm/io.h b/kernel/0.00/linux-0.01/include/asm/io.h new file mode 100644 index 00000000..53646abc --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/asm/memory.h b/kernel/0.00/linux-0.01/include/asm/memory.h new file mode 100644 index 00000000..dba1062f --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/asm/segment.h b/kernel/0.00/linux-0.01/include/asm/segment.h new file mode 100644 index 00000000..78cde928 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/asm/system.h b/kernel/0.00/linux-0.01/include/asm/system.h new file mode 100644 index 00000000..231c8f34 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/const.h b/kernel/0.00/linux-0.01/include/const.h new file mode 100644 index 00000000..88e96416 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/ctype.h b/kernel/0.00/linux-0.01/include/ctype.h new file mode 100644 index 00000000..7df9443b --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/errno.h b/kernel/0.00/linux-0.01/include/errno.h new file mode 100644 index 00000000..18f2aaf6 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/fcntl.h b/kernel/0.00/linux-0.01/include/fcntl.h new file mode 100644 index 00000000..d339b5e7 --- /dev/null +++ b/kernel/0.00/linux-0.01/include/fcntl.h @@ -0,0 +1,55 @@ +#ifndef _FCNTL_H +#define _FCNTL_H + +#include + +/* open/fcntl - NOCTTY, NDELAY isn't implemented yet */ +#define O_ACCMODE 00003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 00100 /* not fcntl */ +#define O_EXCL 00200 /* not fcntl */ +#define O_NOCTTY 00400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 /* not fcntl */ +#define O_NDELAY O_NONBLOCK + +/* Defines for fcntl-commands. Note that currently + * locking isn't supported, and other things aren't really + * tested. + */ +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get f_flags */ +#define F_SETFD 2 /* set f_flags */ +#define F_GETFL 3 /* more flags (cloexec) */ +#define F_SETFL 4 +#define F_GETLK 5 /* not implemented */ +#define F_SETLK 6 +#define F_SETLKW 7 + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* Ok, these are locking features, and aren't implemented at any + * level. POSIX wants them. + */ +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +/* Once again - not implemented, but ... */ +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +extern int creat(const char * filename,mode_t mode); +extern int fcntl(int fildes,int cmd, ...); +extern int open(const char * filename, int flags, ...); + +#endif diff --git a/kernel/0.00/linux-0.01/include/linux/config.h b/kernel/0.00/linux-0.01/include/linux/config.h new file mode 100644 index 00000000..fb2ec101 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/linux/fs.h b/kernel/0.00/linux-0.01/include/linux/fs.h new file mode 100644 index 00000000..57cec3d3 --- /dev/null +++ b/kernel/0.00/linux-0.01/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 + +/* 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/kernel/0.00/linux-0.01/include/linux/hdreg.h b/kernel/0.00/linux-0.01/include/linux/hdreg.h new file mode 100644 index 00000000..7c4a8b77 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/linux/head.h b/kernel/0.00/linux-0.01/include/linux/head.h new file mode 100644 index 00000000..f5468a0e --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/linux/kernel.h b/kernel/0.00/linux-0.01/include/linux/kernel.h new file mode 100644 index 00000000..29f9c7cf --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/linux/mm.h b/kernel/0.00/linux-0.01/include/linux/mm.h new file mode 100644 index 00000000..e13acb32 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/linux/sched.h b/kernel/0.00/linux-0.01/include/linux/sched.h new file mode 100644 index 00000000..a1d30c0d --- /dev/null +++ b/kernel/0.00/linux-0.01/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 +#include +#include + +#if (NR_OPEN > 32) +#error "Currently the close-on-exec-flags are in one word, max 32 files/proc" +#endif + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_ZOMBIE 3 +#define TASK_STOPPED 4 + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +extern int copy_page_tables(unsigned long from, unsigned long to, long size); +extern int free_page_tables(unsigned long from, 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/kernel/0.00/linux-0.01/include/linux/sys.h b/kernel/0.00/linux-0.01/include/linux/sys.h new file mode 100644 index 00000000..3c87f269 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/linux/tty.h b/kernel/0.00/linux-0.01/include/linux/tty.h new file mode 100644 index 00000000..735cf9c2 --- /dev/null +++ b/kernel/0.00/linux-0.01/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 + +#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/kernel/0.00/linux-0.01/include/signal.h b/kernel/0.00/linux-0.01/include/signal.h new file mode 100644 index 00000000..f54e413b --- /dev/null +++ b/kernel/0.00/linux-0.01/include/signal.h @@ -0,0 +1,65 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include + +typedef int sig_atomic_t; +typedef unsigned int sigset_t; /* 32 bits */ + +#define _NSIG 32 +#define NSIG _NSIG + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGUNUSED 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 + +/* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */ +#define SA_NOCLDSTOP 1 + +#define 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/kernel/0.00/linux-0.01/include/stdarg.h b/kernel/0.00/linux-0.01/include/stdarg.h new file mode 100644 index 00000000..0126a7cf --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/stddef.h b/kernel/0.00/linux-0.01/include/stddef.h new file mode 100644 index 00000000..41957264 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/string.h b/kernel/0.00/linux-0.01/include/string.h new file mode 100644 index 00000000..f06f6139 --- /dev/null +++ b/kernel/0.00/linux-0.01/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 + +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/kernel/0.00/linux-0.01/include/sys/times.h b/kernel/0.00/linux-0.01/include/sys/times.h new file mode 100644 index 00000000..aa78d000 --- /dev/null +++ b/kernel/0.00/linux-0.01/include/sys/times.h @@ -0,0 +1,15 @@ +#ifndef _TIMES_H +#define _TIMES_H + +#include + +struct tms { + time_t tms_utime; + time_t tms_stime; + time_t tms_cutime; + time_t tms_cstime; +}; + +extern time_t times(struct tms * tp); + +#endif diff --git a/kernel/0.00/linux-0.01/include/sys/types.h b/kernel/0.00/linux-0.01/include/sys/types.h new file mode 100644 index 00000000..89c03d97 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/sys/utsname.h b/kernel/0.00/linux-0.01/include/sys/utsname.h new file mode 100644 index 00000000..9c6aa5c5 --- /dev/null +++ b/kernel/0.00/linux-0.01/include/sys/utsname.h @@ -0,0 +1,16 @@ +#ifndef _SYS_UTSNAME_H +#define _SYS_UTSNAME_H + +#include + +struct utsname { + char sysname[9]; + char nodename[9]; + char release[9]; + char version[9]; + char machine[9]; +}; + +extern int uname(struct utsname * utsbuf); + +#endif diff --git a/kernel/0.00/linux-0.01/include/sys/wait.h b/kernel/0.00/linux-0.01/include/sys/wait.h new file mode 100644 index 00000000..88414fcf --- /dev/null +++ b/kernel/0.00/linux-0.01/include/sys/wait.h @@ -0,0 +1,23 @@ +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include + +#define _LOW(v) ( (v) & 0377) +#define _HIGH(v) ( ((v) >> 8) & 0377) + +/* options for waitpid, WUNTRACED not supported */ +#define WNOHANG 1 +#define WUNTRACED 2 + +#define WIFEXITED(s) (!((s)&0xFF) +#define WIFSTOPPED(s) (((s)&0xFF)==0x7F) +#define WEXITSTATUS(s) (((s)>>8)&0xFF) +#define WTERMSIG(s) ((s)&0x7F) +#define WSTOPSIG(s) (((s)>>8)&0xFF) +#define WIFSIGNALED(s) (((unsigned int)(s)-1 & 0xFFFF) < 0xFF) + +pid_t wait(int *stat_loc); +pid_t waitpid(pid_t pid, int *stat_loc, int options); + +#endif diff --git a/kernel/0.00/linux-0.01/include/termios.h b/kernel/0.00/linux-0.01/include/termios.h new file mode 100644 index 00000000..cb3797f7 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/time.h b/kernel/0.00/linux-0.01/include/time.h new file mode 100644 index 00000000..f4368ad7 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/include/unistd.h b/kernel/0.00/linux-0.01/include/unistd.h new file mode 100644 index 00000000..026695bc --- /dev/null +++ b/kernel/0.00/linux-0.01/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 +#include +#include +#include + +#ifdef __LIBRARY__ + +#define __NR_setup 0 /* used only by init, to get system going */ +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_stat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_fstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_phys 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_uname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 + +#define _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/kernel/0.00/linux-0.01/include/utime.h b/kernel/0.00/linux-0.01/include/utime.h new file mode 100644 index 00000000..7b6d6971 --- /dev/null +++ b/kernel/0.00/linux-0.01/include/utime.h @@ -0,0 +1,13 @@ +#ifndef _UTIME_H +#define _UTIME_H + +#include /* I know - shouldn't do this, but .. */ + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +extern int utime(const char *filename, struct utimbuf *times); + +#endif diff --git a/kernel/0.00/linux-0.01/init/main.c b/kernel/0.00/linux-0.01/init/main.c new file mode 100644 index 00000000..3e9e733b --- /dev/null +++ b/kernel/0.00/linux-0.01/init/main.c @@ -0,0 +1,147 @@ +#define __LIBRARY__ +#include +#include + +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ +static inline _syscall0(int,fork) +static inline _syscall0(int,pause) +static inline _syscall0(int,setup) +static inline _syscall0(int,sync) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +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/kernel/0.00/linux-0.01/kernel/Makefile b/kernel/0.00/linux-0.01/kernel/Makefile new file mode 100644 index 00000000..dba89a59 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/kernel/asm.s b/kernel/0.00/linux-0.01/kernel/asm.s new file mode 100644 index 00000000..51641a04 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/kernel/console.c b/kernel/0.00/linux-0.01/kernel/console.c new file mode 100644 index 00000000..4b55f4bd --- /dev/null +++ b/kernel/0.00/linux-0.01/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 +#include +#include +#include + +#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+1top) { + 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>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) + 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='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/kernel/0.00/linux-0.01/kernel/exit.c b/kernel/0.00/linux-0.01/kernel/exit.c new file mode 100644 index 00000000..f73ad276 --- /dev/null +++ b/kernel/0.00/linux-0.01/kernel/exit.c @@ -0,0 +1,135 @@ +#include +#include +#include + +#include +#include +#include +#include + +int sys_pause(void); +int sys_close(int fd); + +void release(struct task_struct * p) +{ + int i; + + if (!p) + return; + for (i=1 ; i32) + return; + 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 ; ifather == current->pid) + task[i]->father = 0; + for (i=0 ; ifilp[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/kernel/0.00/linux-0.01/kernel/fork.c b/kernel/0.00/linux-0.01/kernel/fork.c new file mode 100644 index 00000000..d546a53e --- /dev/null +++ b/kernel/0.00/linux-0.01/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 + +#include +#include +#include +#include + +extern void write_verify(unsigned long address); + +long last_pid=0; + +void verify_area(void * addr,int size) +{ + unsigned long start; + + start = (unsigned long) addr; + size += start & 0xfff; + start &= 0xfffff000; + start += get_base(current->ldt[2]); + while (size>0) { + size -= 4096; + write_verify(start); + start += 4096; + } +} + +int copy_mem(int nr,struct task_struct * p) +{ + unsigned long old_data_base,new_data_base,data_limit; + unsigned long old_code_base,new_code_base,code_limit; + + code_limit=get_limit(0x0f); + data_limit=get_limit(0x17); + old_code_base = get_base(current->ldt[1]); + old_data_base = get_base(current->ldt[2]); + if (old_data_base != old_code_base) + panic("We don't support separate I&D"); + if (data_limit < code_limit) + panic("Bad data_limit"); + new_data_base = new_code_base = nr * 0x4000000; + 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; ifilp[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 ; ipid == last_pid) goto repeat; + for(i=1 ; i +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 ; driveb_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 ; reqhd<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 + .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/kernel/0.00/linux-0.01/kernel/mktime.c b/kernel/0.00/linux-0.01/kernel/mktime.c new file mode 100644 index 00000000..3f6a0e90 --- /dev/null +++ b/kernel/0.00/linux-0.01/kernel/mktime.c @@ -0,0 +1,52 @@ +#include + +/* + * This isn't the library routine, it is only used in the kernel. + * as such, we don't care about years<1970 etc, but assume everything + * is ok. Similarly, TZ etc is happily ignored. We just do everything + * as easily as possible. Let's find something public for the library + * routines (although I think minix times is public). + */ +/* + * PS. I hate whoever though up the year 1970 - couldn't they have gotten + * a leap-year instead? I also hate Gregorius, pope or no. I'm grumpy. + */ +#define MINUTE 60 +#define HOUR (60*MINUTE) +#define DAY (24*HOUR) +#define YEAR (365*DAY) + +/* interestingly, we assume leap-years */ +static int month[12] = { + 0, + DAY*(31), + DAY*(31+29), + DAY*(31+29+31), + DAY*(31+29+31+30), + DAY*(31+29+31+30+31), + DAY*(31+29+31+30+31+30), + DAY*(31+29+31+30+31+30+31), + DAY*(31+29+31+30+31+30+31+31), + DAY*(31+29+31+30+31+30+31+31+30), + DAY*(31+29+31+30+31+30+31+31+30+31), + DAY*(31+29+31+30+31+30+31+31+30+31+30) +}; + +long kernel_mktime(struct tm * tm) +{ + long res; + int year; + + 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/kernel/0.00/linux-0.01/kernel/panic.c b/kernel/0.00/linux-0.01/kernel/panic.c new file mode 100644 index 00000000..93a206f4 --- /dev/null +++ b/kernel/0.00/linux-0.01/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 + +volatile void panic(const char * s) +{ + printk("Kernel panic: %s\n\r",s); + for(;;); +} diff --git a/kernel/0.00/linux-0.01/kernel/printk.c b/kernel/0.00/linux-0.01/kernel/printk.c new file mode 100644 index 00000000..f19ca004 --- /dev/null +++ b/kernel/0.00/linux-0.01/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 +#include + +#include + +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/kernel/0.00/linux-0.01/kernel/rs_io.s b/kernel/0.00/linux-0.01/kernel/rs_io.s new file mode 100644 index 00000000..ea6f08c4 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/kernel/sched.c b/kernel/0.00/linux-0.01/kernel/sched.c new file mode 100644 index 00000000..fd27682d --- /dev/null +++ b/kernel/0.00/linux-0.01/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 +#include +#include +#include +#include +#include +#include + +#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;ia=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/kernel/0.00/linux-0.01/kernel/serial.c b/kernel/0.00/linux-0.01/kernel/serial.c new file mode 100644 index 00000000..7636b51a --- /dev/null +++ b/kernel/0.00/linux-0.01/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 +#include +#include +#include + +#define WAKEUP_CHARS (TTY_BUF_SIZE/4) + +extern void rs1_interrupt(void); +extern void rs2_interrupt(void); + +static void init(int port) +{ + outb_p(0x80,port+3); /* set DLAB of line control reg */ + outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */ + outb_p(0x00,port+1); /* MS of divisor */ + outb_p(0x03,port+3); /* reset DLAB */ + outb_p(0x0b,port+4); /* set DTR,RTS, OUT_2 */ + outb_p(0x0d,port+1); /* enable all intrs but writes */ + (void)inb(port); /* read data port to reset things (?) */ +} + +void rs_init(void) +{ + set_intr_gate(0x24,rs1_interrupt); + set_intr_gate(0x23,rs2_interrupt); + init(tty_table[1].read_q.data); + init(tty_table[2].read_q.data); + outb(inb_p(0x21)&0xE7,0x21); +} + +/* + * This routine gets called when tty_write has put something into + * the write_queue. It must check wheter the queue is empty, and + * set the interrupt register accordingly + * + * void _rs_write(struct tty_struct * tty); + */ +void rs_write(struct tty_struct * tty) +{ + cli(); + if (!EMPTY(tty->write_q)) + outb(inb_p(tty->write_q.data+1)|0x02,tty->write_q.data+1); + sti(); +} diff --git a/kernel/0.00/linux-0.01/kernel/sys.c b/kernel/0.00/linux-0.01/kernel/sys.c new file mode 100644 index 00000000..0de26083 --- /dev/null +++ b/kernel/0.00/linux-0.01/kernel/sys.c @@ -0,0 +1,216 @@ +#include + +#include +#include +#include +#include +#include +#include + +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 ; ipid==pid) { + if (task[i]->leader) + return -EPERM; + if (task[i]->session != current->session) + return -EPERM; + task[i]->pgrp = pgid; + return 0; + } + return -ESRCH; +} + +int sys_getpgrp(void) +{ + return current->pgrp; +} + +int sys_setsid(void) +{ + if (current->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;iumask; + + current->umask = mask & 0777; + return (old); +} diff --git a/kernel/0.00/linux-0.01/kernel/system_call.s b/kernel/0.00/linux-0.01/kernel/system_call.s new file mode 100644 index 00000000..d28f5fb7 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/kernel/traps.c b/kernel/0.00/linux-0.01/kernel/traps.c new file mode 100644 index 00000000..80acbb6f --- /dev/null +++ b/kernel/0.00/linux-0.01/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 + +#include +#include +#include +#include +#include + +#define get_seg_byte(seg,addr) ({ \ +register char __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define get_seg_long(seg,addr) ({ \ +register unsigned long __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define _fs() ({ \ +register unsigned short __res; \ +__asm__("mov %%fs,%%ax":"=a" (__res):); \ +__res;}) + +int do_exit(long code); + +void page_exception(void); + +void divide_error(void); +void debug(void); +void nmi(void); +void int3(void); +void overflow(void); +void bounds(void); +void invalid_op(void); +void device_not_available(void); +void double_fault(void); +void coprocessor_segment_overrun(void); +void invalid_TSS(void); +void segment_not_present(void); +void stack_segment(void); +void general_protection(void); +void page_fault(void); +void coprocessor_error(void); +void reserved(void); + +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/kernel/0.00/linux-0.01/kernel/tty_io.c b/kernel/0.00/linux-0.01/kernel/tty_io.c new file mode 100644 index 00000000..f865dc82 --- /dev/null +++ b/kernel/0.00/linux-0.01/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 +#include +#include + +#define ALRMMASK (1<<(SIGALRM-1)) + +#include +#include +#include +#include + +#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f) +#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f) +#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f) + +#define L_CANON(tty) _L_FLAG((tty),ICANON) +#define L_ISIG(tty) _L_FLAG((tty),ISIG) +#define L_ECHO(tty) _L_FLAG((tty),ECHO) +#define L_ECHOE(tty) _L_FLAG((tty),ECHOE) +#define L_ECHOK(tty) _L_FLAG((tty),ECHOK) +#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL) +#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE) + +#define I_UCLC(tty) _I_FLAG((tty),IUCLC) +#define I_NLCR(tty) _I_FLAG((tty),INLCR) +#define I_CRNL(tty) _I_FLAG((tty),ICRNL) +#define I_NOCR(tty) _I_FLAG((tty),IGNCR) + +#define O_POST(tty) _O_FLAG((tty),OPOST) +#define O_NLCR(tty) _O_FLAG((tty),ONLCR) +#define O_CRNL(tty) _O_FLAG((tty),OCRNL) +#define O_NLRET(tty) _O_FLAG((tty),ONLRET) +#define O_LCUC(tty) _O_FLAG((tty),OLCUC) + +struct tty_struct tty_table[] = { + { + {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;ipgrp==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+jiffiesalarm = time+jiffies; + } + if (minimum>nr) + minimum=nr; + while (nr>0) { + if (flag && (current->signal & ALRMMASK)) { + current->signal &= ~ALRMMASK; + break; + } + if (current->signal) + break; + if (EMPTY(tty->secondary) || (L_CANON(tty) && + !tty->secondary.data && LEFT(tty->secondary)>20)) { + sleep_if_empty(&tty->secondary); + continue; + } + do { + GETCH(tty->secondary,c); + if (c==EOF_CHAR(tty) || c==10) + tty->secondary.data--; + if (c==EOF_CHAR(tty) && L_CANON(tty)) + return (b-buf); + else { + put_fs_byte(c,b++); + if (!--nr) + break; + } + } while (nr>0 && !EMPTY(tty->secondary)); + if (time && !L_CANON(tty)) + if (flag=(!oldalarm || time+jiffiesalarm = time+jiffies; + else + current->alarm = oldalarm; + if (L_CANON(tty)) { + if (b-buf) + break; + } else if (b-buf >= minimum) + break; + } + current->alarm = oldalarm; + if (current->signal && !(b-buf)) + return -EINTR; + return (b-buf); +} + +int tty_write(unsigned channel, char * buf, int nr) +{ + static cr_flag=0; + struct tty_struct * tty; + char c, *b=buf; + + if (channel>2 || nr<0) return -1; + tty = channel + tty_table; + while (nr>0) { + sleep_if_full(&tty->write_q); + if (current->signal) + break; + while (nr>0 && !FULL(tty->write_q)) { + c=get_fs_byte(b); + if (O_POST(tty)) { + if (c=='\r' && O_CRNL(tty)) + c='\n'; + else if (c=='\n' && O_NLRET(tty)) + c='\r'; + if (c=='\n' && !cr_flag && O_NLCR(tty)) { + cr_flag = 1; + PUTCH(13,tty->write_q); + continue; + } + if (O_LCUC(tty)) + c=toupper(c); + } + b++; nr--; + cr_flag = 0; + PUTCH(c,tty->write_q); + } + tty->write(tty); + if (nr>0) + schedule(); + } + return (b-buf); +} + +/* + * Jeh, sometimes I really like the 386. + * This routine is called from an interrupt, + * and there should be absolutely no problem + * with sleeping even in an interrupt (I hope). + * Of course, if somebody proves me wrong, I'll + * hate intel for all time :-). We'll have to + * be careful and see to reinstating the interrupt + * chips before calling this, though. + */ +void do_tty_interrupt(int tty) +{ + copy_to_cooked(tty_table+tty); +} diff --git a/kernel/0.00/linux-0.01/kernel/vsprintf.c b/kernel/0.00/linux-0.01/kernel/vsprintf.c new file mode 100644 index 00000000..67f5e779 --- /dev/null +++ b/kernel/0.00/linux-0.01/kernel/vsprintf.c @@ -0,0 +1,227 @@ +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include +#include + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ + +#define do_div(n,base) ({ \ +int __res; \ +__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ +__res; }) + +static char * number(char * str, int num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[36]; + const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + + if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; + if (type&LEFT) type &= ~ZEROPAD; + if (base<2 || base>36) + return 0; + c = (type & ZEROPAD) ? '0' : ' ' ; + if (type&SIGN && num<0) { + sign='-'; + num = -num; + } else + sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); + if (sign) size--; + if (type&SPECIAL) + if (base==16) size -= 2; + else if (base==8) size--; + i=0; + if (num==0) + tmp[i++]='0'; + else while (num!=0) + tmp[i++]=digits[do_div(num,base)]; + if (i>precision) precision=i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type&SPECIAL) + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + if (!(type&LEFT)) + while(size-->0) + *str++ = c; + while(i0) + *str++ = tmp[i]; + while(size-->0) + *str++ = ' '; + return str; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + int i; + char * str; + char *s; + int *ip; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + break; + + case 's': + s = va_arg(args, char *); + len = strlen(s); + if (precision < 0) + precision = len; + else if (len > precision) + len = precision; + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + break; + + case 'o': + str = number(str, va_arg(args, unsigned long), 8, + field_width, precision, flags); + break; + + case 'p': + if (field_width == -1) { + field_width = 8; + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + break; + + case 'x': + flags |= SMALL; + case 'X': + str = number(str, va_arg(args, unsigned long), 16, + field_width, precision, flags); + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + str = number(str, va_arg(args, unsigned long), 10, + field_width, precision, flags); + break; + + case 'n': + ip = va_arg(args, int *); + *ip = (str - buf); + break; + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + break; + } + } + *str = '\0'; + return str-buf; +} diff --git a/kernel/0.00/linux-0.01/lib/Makefile b/kernel/0.00/linux-0.01/lib/Makefile new file mode 100644 index 00000000..67cc0446 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/lib/_exit.c b/kernel/0.00/linux-0.01/lib/_exit.c new file mode 100644 index 00000000..2948e8ad --- /dev/null +++ b/kernel/0.00/linux-0.01/lib/_exit.c @@ -0,0 +1,7 @@ +#define __LIBRARY__ +#include + +volatile void _exit(int exit_code) +{ + __asm__("int $0x80"::"a" (__NR_exit),"b" (exit_code)); +} diff --git a/kernel/0.00/linux-0.01/lib/close.c b/kernel/0.00/linux-0.01/lib/close.c new file mode 100644 index 00000000..83bc36a4 --- /dev/null +++ b/kernel/0.00/linux-0.01/lib/close.c @@ -0,0 +1,4 @@ +#define __LIBRARY__ +#include + +_syscall1(int,close,int,fd) diff --git a/kernel/0.00/linux-0.01/lib/ctype.c b/kernel/0.00/linux-0.01/lib/ctype.c new file mode 100644 index 00000000..8b2dd919 --- /dev/null +++ b/kernel/0.00/linux-0.01/lib/ctype.c @@ -0,0 +1,29 @@ +#include + +char _ctmp; +unsigned char _ctype[] = {0x00, /* EOF */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */ + diff --git a/kernel/0.00/linux-0.01/lib/dup.c b/kernel/0.00/linux-0.01/lib/dup.c new file mode 100644 index 00000000..e2a157cf --- /dev/null +++ b/kernel/0.00/linux-0.01/lib/dup.c @@ -0,0 +1,4 @@ +#define __LIBRARY__ +#include + +_syscall1(int,dup,int,fd) diff --git a/kernel/0.00/linux-0.01/lib/errno.c b/kernel/0.00/linux-0.01/lib/errno.c new file mode 100644 index 00000000..015fbfd2 --- /dev/null +++ b/kernel/0.00/linux-0.01/lib/errno.c @@ -0,0 +1 @@ +int errno; diff --git a/kernel/0.00/linux-0.01/lib/execve.c b/kernel/0.00/linux-0.01/lib/execve.c new file mode 100644 index 00000000..31e9cb7b --- /dev/null +++ b/kernel/0.00/linux-0.01/lib/execve.c @@ -0,0 +1,4 @@ +#define __LIBRARY__ +#include + +_syscall3(int,execve,const char *,file,char **,argv,char **,envp) diff --git a/kernel/0.00/linux-0.01/lib/open.c b/kernel/0.00/linux-0.01/lib/open.c new file mode 100644 index 00000000..18774602 --- /dev/null +++ b/kernel/0.00/linux-0.01/lib/open.c @@ -0,0 +1,19 @@ +#define __LIBRARY__ +#include +#include + +int open(const char * filename, int flag, ...) +{ + register int res; + va_list arg; + + va_start(arg,flag); + __asm__("int $0x80" + :"=a" (res) + :"0" (__NR_open),"b" (filename),"c" (flag), + "d" (va_arg(arg,int))); + if (res>=0) + return res; + errno = -res; + return -1; +} diff --git a/kernel/0.00/linux-0.01/lib/setsid.c b/kernel/0.00/linux-0.01/lib/setsid.c new file mode 100644 index 00000000..91b6421a --- /dev/null +++ b/kernel/0.00/linux-0.01/lib/setsid.c @@ -0,0 +1,4 @@ +#define __LIBRARY__ +#include + +_syscall0(pid_t,setsid) diff --git a/kernel/0.00/linux-0.01/lib/string.c b/kernel/0.00/linux-0.01/lib/string.c new file mode 100644 index 00000000..f262e2e1 --- /dev/null +++ b/kernel/0.00/linux-0.01/lib/string.c @@ -0,0 +1,8 @@ +#ifndef __GNUC__ +#error I want gcc! +#endif + +#define extern +#define inline +#define __LIBRARY__ +#include diff --git a/kernel/0.00/linux-0.01/lib/wait.c b/kernel/0.00/linux-0.01/lib/wait.c new file mode 100644 index 00000000..bdf21afe --- /dev/null +++ b/kernel/0.00/linux-0.01/lib/wait.c @@ -0,0 +1,10 @@ +#define __LIBRARY__ +#include +#include + +_syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) + +pid_t wait(int * wait_stat) +{ + return waitpid(-1,wait_stat,0); +} diff --git a/kernel/0.00/linux-0.01/lib/write.c b/kernel/0.00/linux-0.01/lib/write.c new file mode 100644 index 00000000..a152a2c2 --- /dev/null +++ b/kernel/0.00/linux-0.01/lib/write.c @@ -0,0 +1,4 @@ +#define __LIBRARY__ +#include + +_syscall3(int,write,int,fd,const char *,buf,off_t,count) diff --git a/kernel/0.00/linux-0.01/mm/Makefile b/kernel/0.00/linux-0.01/mm/Makefile new file mode 100644 index 00000000..c2368dc2 --- /dev/null +++ b/kernel/0.00/linux-0.01/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/kernel/0.00/linux-0.01/mm/memory.c b/kernel/0.00/linux-0.01/mm/memory.c new file mode 100644 index 00000000..4e7f3beb --- /dev/null +++ b/kernel/0.00/linux-0.01/mm/memory.c @@ -0,0 +1,264 @@ +#include + +#include +#include +#include +#include + +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 (addrHIGH_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 /* fprintf */ +#include /* contains exit */ +#include /* unistd.h needs this */ +#include /* contains read/write */ +#include + +#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;i510) + 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); +} diff --git a/kernel/0.1x/linux-0.10.tar.gz b/kernel/0.1x/linux-0.10.tar.gz new file mode 100644 index 00000000..b960598d Binary files /dev/null and b/kernel/0.1x/linux-0.10.tar.gz differ diff --git a/kernel/0.1x/linux-0.10/Makefile b/kernel/0.1x/linux-0.10/Makefile new file mode 100644 index 00000000..a04585c0 --- /dev/null +++ b/kernel/0.1x/linux-0.10/Makefile @@ -0,0 +1,106 @@ +ROOTDEV= /dev/hd3 + +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 =cpp -nostdinc -Iinclude + +ARCHIVES=kernel/kernel.o mm/mm.o fs/fs.o +DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a +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/bootsect boot/setup tools/system tools/build + tools/build boot/bootsect boot/setup tools/system $(ROOTDEV) > 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) $(DRIVERS) $(LIBS) + $(LD) $(LDFLAGS) boot/head.o init/main.o \ + $(ARCHIVES) \ + $(DRIVERS) \ + $(LIBS) \ + -o tools/system > System.map + +kernel/blk_drv/blk_drv.a: + (cd kernel/blk_drv; make) + +kernel/chr_drv/chr_drv.a: + (cd kernel/chr_drv; make) + +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/setup: boot/setup.s +# $(AS86) -o boot/setup.o boot/setup.s +# $(LD86) -s -o boot/setup boot/setup.o + +#boot/bootsect: tmp.s +# $(AS86) -o boot/bootsect.o tmp.s +# rm -f tmp.s +# $(LD86) -s -o boot/bootsect boot/bootsect.o + +#tmp.s: boot/bootsect.s tools/system +# (echo -n "SYSSIZE = (";ls -l tools/system | grep system \ +# | cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s +# cat boot/bootsect.s >> tmp.s + +clean: + rm -f Image System.map tmp_make core + 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/signal.h include/asm/system.h include/asm/io.h \ + include/stddef.h include/stdarg.h include/fcntl.h diff --git a/kernel/0.1x/linux-0.10/boot.rar b/kernel/0.1x/linux-0.10/boot.rar new file mode 100644 index 00000000..aa6d03b5 Binary files /dev/null and b/kernel/0.1x/linux-0.10/boot.rar differ diff --git a/kernel/0.1x/linux-0.10/boot/bootsect.s b/kernel/0.1x/linux-0.10/boot/bootsect.s new file mode 100644 index 00000000..685e0636 --- /dev/null +++ b/kernel/0.1x/linux-0.10/boot/bootsect.s @@ -0,0 +1,254 @@ +| +| bootsect.s (C) 1991 Linus Torvalds +| +| bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves +| iself out of the way to address 0x90000, and jumps there. +| +| It then loads 'setup' directly after itself (0x90200), and the system +| at 0x10000, using BIOS interrupts. +| +| NOTE! currently system is at most 8*65536 bytes long. This should be no +| problem, even in the future. I want to keep it simple. This 512 kB +| kernel size should be enough, especially as this doesn't contain the +| buffer cache as in minix +| +| The loader has been made as simple as possible, and continuos +| read errors will result in a unbreakable loop. Reboot by hand. It +| loads pretty fast by getting whole sectors at a time whenever possible. + +.globl begtext, begdata, begbss, endtext, enddata, endbss +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +SETUPLEN = 4 | nr of setup-sectors +BOOTSEG = 0x07c0 | original address of boot-sector +INITSEG = 0x9000 | we move boot here - out of the way +SETUPSEG = 0x9020 | setup starts here +SYSSEG = 0x1000 | system loaded at 0x10000 (65536). +ENDSEG = SYSSEG + SYSSIZE | where to stop loading + +| ROOT_DEV: 0x000 - same type of floppy as boot. +| 0x301 - first partition on first drive etc +ROOT_DEV = 0 | 0x306 + +entry start +start: + mov ax,#BOOTSEG + mov ds,ax + mov ax,#INITSEG + mov es,ax + mov cx,#256 + sub si,si + sub di,di + rep + movw + jmpi go,INITSEG +go: mov ax,cs + mov ds,ax + mov es,ax +| put stack at 0x9ff00. + mov ss,ax + mov sp,#0xFF00 | arbitrary value >>512 + +| load the setup-sectors directly after the bootblock. +| Note that 'es' is already set up. + +load_setup: + mov dx,#0x0000 | drive 0, head 0 + mov cx,#0x0002 | sector 2, track 0 + mov bx,#0x0200 | address = 512, in INITSEG + mov ax,#0x0200+SETUPLEN | service 2, nr of sectors + int 0x13 | read it + jnc ok_load_setup | ok - continue + mov dx,#0x0000 + mov ax,#0x0000 | reset the diskette + int 0x13 + j load_setup + +ok_load_setup: + +| Get disk drive parameters, specifically nr of sectors/track + + mov dl,#0x00 + mov ax,#0x0800 | AH=8 is get drive parameters + int 0x13 + mov ch,#0x00 + seg cs + mov sectors,cx + mov ax,#INITSEG + mov es,ax + +| Print some inane message + + mov ah,#0x03 | read cursor pos + xor bh,bh + int 0x10 + + mov cx,#24 + mov bx,#0x0007 | page 0, attribute 7 (normal) + mov bp,#msg1 + mov ax,#0x1301 | write string, move cursor + int 0x10 + +| ok, we've written the message, now +| we want to load the system (at 0x10000) + + mov ax,#SYSSEG + mov es,ax | segment of 0x010000 + call read_it + call kill_motor + +| After that we check which root-device to use. If the device is +| defined (!= 0), nothing is done and the given device is used. +| Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending +| on the number of sectors that the BIOS reports currently. + + seg cs + mov ax,root_dev + cmp ax,#0 + jne root_defined + seg cs + mov bx,sectors + mov ax,#0x0208 | /dev/ps0 - 1.2Mb + cmp bx,#15 + je root_defined + mov ax,#0x021c | /dev/PS0 - 1.44Mb + cmp bx,#18 + je root_defined +undef_root: + jmp undef_root +root_defined: + seg cs + mov root_dev,ax + +| after that (everyting loaded), we jump to +| the setup-routine loaded directly after +| the bootblock: + + jmpi 0,SETUPSEG + +| This routine loads the system at address 0x10000, making sure +| no 64kB boundaries are crossed. We try to load it as fast as +| possible, loading whole tracks whenever we can. +| +| in: es - starting address segment (normally 0x1000) +| +sread: .word 1+SETUPLEN | sectors read of current track +head: .word 0 | current head +track: .word 0 | current track + +read_it: + mov ax,es + test ax,#0x0fff +die: jne die | es must be at 64kB boundary + xor bx,bx | bx is starting address within segment +rp_read: + mov ax,es + cmp ax,#ENDSEG | have we loaded all yet? + jb ok1_read + ret +ok1_read: + seg cs + mov ax,sectors + sub ax,sread + mov cx,ax + shl cx,#9 + add cx,bx + jnc ok2_read + je ok2_read + xor ax,ax + sub ax,bx + shr ax,#9 +ok2_read: + call read_track + mov cx,ax + add ax,sread + seg cs + cmp ax,sectors + jne ok3_read + mov ax,#1 + sub ax,head + jne ok4_read + inc track +ok4_read: + mov head,ax + xor ax,ax +ok3_read: + mov sread,ax + shl cx,#9 + add bx,cx + jnc rp_read + mov ax,es + add ax,#0x1000 + mov es,ax + xor bx,bx + jmp rp_read + +read_track: + push ax + push bx + push cx + push dx + mov dx,track + mov cx,sread + inc cx + mov ch,dl + mov dx,head + mov dh,dl + mov dl,#0 + and dx,#0x0100 + mov ah,#2 + int 0x13 + jc bad_rt + pop dx + pop cx + pop bx + pop ax + ret +bad_rt: mov ax,#0 + mov dx,#0 + int 0x13 + pop dx + pop cx + pop bx + pop ax + jmp read_track + +/* + * This procedure turns off the floppy drive motor, so + * that we enter the kernel in a known state, and + * don't have to worry about it later. + */ +kill_motor: + push dx + mov dx,#0x3f2 + mov al,#0 + outb + pop dx + ret + +sectors: + .word 0 + +msg1: + .byte 13,10 + .ascii "Loading system ..." + .byte 13,10,13,10 + +.org 508 +root_dev: + .word ROOT_DEV +boot_flag: + .word 0xAA55 + +.text +endtext: +.data +enddata: +.bss +endbss: diff --git a/kernel/0.1x/linux-0.10/boot/bootsect.sg b/kernel/0.1x/linux-0.10/boot/bootsect.sg new file mode 100644 index 00000000..3b87b45e --- /dev/null +++ b/kernel/0.1x/linux-0.10/boot/bootsect.sg @@ -0,0 +1,274 @@ +/* + * + * bootsect.s (C) 1991 Linus Torvalds + * + * bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves + * iself out of the way to address 0x90000, and jumps there. + * + * It then loads 'setup' directly after itself (0x90200), and the system + * at 0x10000, using BIOS interrupts. + * + * NOTE! currently system is at most 8*65536 bytes long. This should be no + * problem, even in the future. I want to keep it simple. This 512 kB + * kernel size should be enough, especially as this doesn't contain the + * buffer cache as in minix + * + * The loader has been made as simple as possible, and continuos + * read errors will result in a unbreakable loop. Reboot by hand. It + * loads pretty fast by getting whole sectors at a time whenever possible. + */ + +.globl begtext, begdata, begbss, endtext, enddata, endbss +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +SETUPLEN = 4 # nr of setup-sectors +BOOTSEG = 0x07c0 # original address of boot-sector +INITSEG = 0x9000 # we move boot here - out of the way +SETUPSEG = 0x9020 # setup starts here +SYSSEG = 0x1000 # system loaded at 0x10000 (65536). +ENDSEG = SYSSEG + SYSSIZE # where to stop loading + +/* + * ROOT_DEV: 0x000 - same type of floppy as boot. + * 0x301 - first partition on first drive etc + */ +ROOT_DEV = 0 # 0x306 + +entry start +start: + mov $BOOTSEG,%ax + mov %ax,%ds + mov $INITSEG,%ax + mov %ax,%es + mov $256,%cx + sub %si,%si + sub %di,%di + rep + movw + jmpi go,INITSEG +go: mov %cs,%ax + mov %ax,%ds + mov %ax,%es +/* + * put stack at 0x9ff00. + */ + mov %ax,%ss + mov $0xFF00,%sp # arbitrary value >>512 + +/* + * load the setup-sectors directly after the bootblock. + * Note that 'es' is already set up. + */ + +load_setup: + mov $0x0000,%dx # drive 0, head 0 + mov $0x0002,%cx # sector 2, track 0 + mov $0x0200,%bx # address = 512, in INITSEG + mov $0x0200,%ax+SETUPLEN # service 2, nr of sectors + int 0x13 # read it + jnc ok_load_setup # ok - continue + mov $0x0000,%dx + mov $0x0000,%ax # reset the diskette + int 0x13 + j load_setup + +ok_load_setup: + +/* + * Get disk drive parameters, specifically nr of sectors/track + */ + + mov $0x00,%dl + mov $0x0800,%ax # AH=8 is get drive parameters + int 0x13 + mov $0x00,%ch + seg %cs + mov %cx,sectors + mov $INITSEG,%ax + mov %ax,%es + +/* + * Print some inane message + */ + + mov $0x03,%ah # read cursor pos + xor %bh,%bh + int 0x10 + + mov $24,%cx + mov $0x0007,%bx # page 0, attribute 7 (normal) + mov $msg1,%bp + mov $0x1301,%ax # write string, move cursor + int 0x10 + +/* + * ok, we've written the message, now + * we want to load the system (at 0x10000) + */ + + mov $SYSSEG,%ax + mov %ax,%es # segment of 0x010000 + call read_it + call kill_motor + +/* + * After that we check which root-device to use. If the device is + * defined (!= 0), nothing is done and the given device is used. + * Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending + * on the number of sectors that the BIOS reports currently. + */ + + seg %cs + mov root,%ax_dev + cmp %ax,$0 + jne root_defined + seg %cs + mov sectors,%bx + mov $0x0208,%ax # /dev/ps0 - 1.2Mb + cmp %bx,$15 + je root_defined + mov $0x021c,%ax # /dev/PS0 - 1.44Mb + cmp %bx,$18 + je root_defined +undef_root: + jmp undef_root +root_defined: + seg %cs + mov root_%ax,dev + +/* + * after that (everyting loaded), we jump to + * the setup-routine loaded directly after + * the bootblock: + */ + + jmpi 0,SETUPSEG + +/* + * This routine loads the system at address 0x10000, making sure + * no 64kB boundaries are crossed. We try to load it as fast as + * possible, loading whole tracks whenever we can. + * + * in: es - starting address segment (normally 0x1000) + * + */ +sread: .word 1+SETUPLEN # sectors read of current track +head: .word 0 # current head +track: .word 0 # current track + +read_it: + mov %es,%ax + test %ax,$0x0fff +die: jne die # %es must be at 64kB boundary + xor %bx,%bx # %bx is starting address within segment +rp_read: + mov %es,%ax + cmp %ax,$ENDSEG # have we loaded all yet? + jb ok1_read + ret +ok1_read: + seg %cs + mov sectors,%ax + sub sread,%ax + mov %ax,%cx + shl $9,%cx + add %bx,%cx + jnc ok2_read + je ok2_read + xor %ax,%ax + sub %bx,%ax + shr $9,%ax +ok2_read: + call read_track + mov %ax,%cx + add sread,%ax + seg %cs + cmp %ax,sectors + jne ok3_read + mov $1,%ax + sub head,%ax + jne ok4_read + inc track +ok4_read: + mov %ax,head + xor %ax,%ax +ok3_read: + mov %ax,sread + shl $9,%cx + add %cx,%bx + jnc rp_read + mov %es,%ax + add $0x1000,%ax + mov %ax,%es + xor %bx,%bx + jmp rp_read + +read_track: + push %ax + push %bx + push %cx + push %dx + mov track,%dx + mov sread,%cx + inc %cx + mov %dl,%ch + mov head,%dx + mov %dl,%dh + mov $0,%dl + and $0x0100,%dx + mov $2,%ah + int 0x13 + jc bad_rt + pop %dx + pop %cx + pop %bx + pop %ax + ret +bad_rt: mov %ax,$0 + mov $0,%dx + 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 $0x3f2,%dx + mov $0,%al + outb + pop %dx + ret + +sectors: + .word 0 + +msg1: + .byte 13,10 + .ascii "Loading system ..." + .byte 13,10,13,10 + +.org 508 +root_dev: + .word ROOT_DEV +boot_flag: + .word 0xAA55 + +.text +endtext: +.data +enddata: +.bss +endbss: diff --git a/kernel/0.1x/linux-0.10/boot/gas-convert b/kernel/0.1x/linux-0.10/boot/gas-convert new file mode 100644 index 00000000..f69227b6 --- /dev/null +++ b/kernel/0.1x/linux-0.10/boot/gas-convert @@ -0,0 +1,47 @@ +#!/usr/bin/perl +# +# + +$in_block_comment = 0; + +while (<>) { + if (/^\|/) { + if (! $in_block_comment) { + print "/* \n"; + $in_block_comment = 1; + } + s/\|/ */; + print; + next; + } else { + if ($in_block_comment) { + print " */\n"; + $in_block_comment = 0; + } + } + + s/#/$/; # Convert immediate references + s/\|/#/; # Convert in-line comments + + s/(\b|,)([abcd][xhl])(\b|,|$)/\1%\2\3/g; + s/(\b|,)([cdsefg]s)(\b|,|$)/\1%\2\3/g; + s/(\b|,)([sd]i)(\b|,|$)/\1%\2\3/g; + s/(\b|,)([sb]p)(\b|,|$)/\1%\2\3/g; + s/(\b|,)(e[abcd]x)(\b|,|$)/\1%\2\3/g; + + if (/^(([a-zA-Z]+:[ \t]+)|[ \t]+)([a-zA-Z]+)/) { + $op = $3; + if (($op eq "mov") || ($op eq "add") || ($op eq "sub") || + ($op eq "xor") || ($op eq "and") || ($op eq "shr") || + ($op eq "shl") || ($op eq "in") || ($op eq "out")) { + # + # We need to swap arguments... + # + s/([0-9a-zA-Z%\$]+)(,)([0-9a-zA-Z%\$]+)/\3\2\1/; + } + } + + print; +} + + diff --git a/kernel/0.1x/linux-0.10/boot/head.s b/kernel/0.1x/linux-0.10/boot/head.s new file mode 100644 index 00000000..58e92319 --- /dev/null +++ b/kernel/0.1x/linux-0.10/boot/head.s @@ -0,0 +1,224 @@ +/* + * linux/boot/head.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * head.s contains the 32-bit startup code. + * + * NOTE!!! Startup happens at absolute address 0x00000000, which is also where + * the page directory will exist. The startup code will be overwritten by + * the page directory. + */ +.text +.globl _idt,_gdt,_pg_dir,_tmp_floppy_area +_pg_dir: +startup_32: + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + mov %ax,%gs + lss _stack_start,%esp + call setup_idt + call setup_gdt + movl $0x10,%eax # reload all the segment registers + mov %ax,%ds # after changing gdt. CS was already + mov %ax,%es # reloaded in 'setup_gdt' + mov %ax,%fs + mov %ax,%gs + lss _stack_start,%esp + xorl %eax,%eax +1: incl %eax # check that A20 really IS enabled + movl %eax,0x000000 # loop forever if it isn't + cmpl %eax,0x100000 + je 1b +/* + * NOTE! 486 should set bit 16, to check for write-protect in supervisor + * mode. Then it would be unnecessary with the "verify_area()"-calls. + * 486 users probably want to set the NE (#5) bit also, so as to use + * int 16 for math errors. + */ + movl %cr0,%eax # check math chip + andl $0x80000011,%eax # Save PG,ET,PE +/* "orl $0x10020,%eax" here for 486 might be good */ + orl $2,%eax # set MP + testl $0x10,%eax + jne 1f # ET is set - 387 is present + xorl $6,%eax # else reset MP and set EM +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 + +/* + * I put the kernel page tables right after the page directory, + * using 4 of them to span 16 Mb of physical memory. People with + * more than 16MB will have to expand this. + */ +.org 0x1000 +pg0: + +.org 0x2000 +pg1: + +.org 0x3000 +pg2: + +.org 0x4000 +pg3: + +.org 0x5000 +/* + * tmp_floppy_area is used by the floppy-driver when DMA cannot + * reach to a buffer-block. It needs to be aligned, so that it isn't + * on a 64kB border. + */ +_tmp_floppy_area: + .fill 1024,1,0 + +after_page_tables: + pushl $0 # These are the parameters to main :-) + pushl $0 + pushl $0 + pushl $L6 # return address for main, if it decides to. + pushl $_main + jmp setup_paging +L6: + jmp L6 # main should never return here, but + # just in case, we know what happens. + +/* This is the default interrupt "handler" :-) */ +int_msg: + .asciz "Unknown interrupt\n\r" +.align 2 +ignore_int: + pushl %eax + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + pushl $int_msg + call _printk + popl %eax + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + + +/* + * Setup_paging + * + * This routine sets up paging by setting the page bit + * in cr0. The page tables are set up, identity-mapping + * the first 16MB. The pager assumes that no illegal + * addresses are produced (ie >4Mb on a 4Mb machine). + * + * NOTE! Although all physical memory should be identity + * mapped by this routine, only the kernel page functions + * use the >1Mb addresses directly. All "normal" functions + * use just the lower 1Mb, or the local data space, which + * will be mapped to some other place - mm keeps track of + * that. + * + * For those with more memory than 16 Mb - tough luck. I've + * not got it, why should you :-) The source is here. Change + * it. (Seriously - it shouldn't be too difficult. Mostly + * change some constants etc. I left it at 16Mb, as my machine + * even cannot be extended past that (ok, but it was cheap :-) + * I've tried to show which constants to change by having + * some kind of marker at them (search for "16Mb"), but I + * won't guarantee that's all :-( ) + */ +.align 2 +setup_paging: + movl $1024*5,%ecx /* 5 pages - pg_dir+4 page tables */ + xorl %eax,%eax + xorl %edi,%edi /* pg_dir is at 0x000 */ + cld;rep;stosl + movl $pg0+7,_pg_dir /* set present bit/user r/w */ + movl $pg1+7,_pg_dir+4 /* --------- " " --------- */ + movl $pg2+7,_pg_dir+8 /* --------- " " --------- */ + movl $pg3+7,_pg_dir+12 /* --------- " " --------- */ + movl $pg3+4092,%edi + movl $0xfff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */ + std +1: stosl /* fill pages backwards - more efficient :-) */ + subl $0x1000,%eax + jge 1b + xorl %eax,%eax /* pg_dir is at 0x0000 */ + movl %eax,%cr3 /* cr3 - page directory start */ + movl %cr0,%eax + orl $0x80000000,%eax + movl %eax,%cr0 /* set paging (PG) bit */ + 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 0x00c09a0000000fff /* 16Mb */ + .quad 0x00c0920000000fff /* 16Mb */ + .quad 0x0000000000000000 /* TEMPORARY - don't use */ + .fill 252,8,0 /* space for LDT's and TSS's etc */ diff --git a/kernel/0.1x/linux-0.10/boot/setup.s b/kernel/0.1x/linux-0.10/boot/setup.s new file mode 100644 index 00000000..782cf33e --- /dev/null +++ b/kernel/0.1x/linux-0.10/boot/setup.s @@ -0,0 +1,215 @@ +| +| setup.s (C) 1991 Linus Torvalds +| +| setup.s is responsible for getting the system data from the BIOS, +| and putting them into the appropriate places in system memory. +| both setup.s and system has been loaded by the bootblock. +| +| This code asks the bios for memory/disk/other parameters, and +| puts them in a "safe" place: 0x90000-0x901FF, ie where the +| boot-block used to be. It is then up to the protected mode +| system to read them from there before the area is overwritten +| for buffer-blocks. +| + +| NOTE! These had better be the same as in bootsect.s! + +INITSEG = 0x9000 | we move boot here - out of the way +SYSSEG = 0x1000 | system loaded at 0x10000 (65536). +SETUPSEG = 0x9020 | this is the current segment + +.globl begtext, begdata, begbss, endtext, enddata, endbss +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +entry start +start: + +| ok, the read went well so we get current cursor position and save it for +| posterity. + + mov ax,#INITSEG | this is done in bootsect already, but... + mov ds,ax + mov ah,#0x03 | read cursor pos + xor bh,bh + int 0x10 | save it in known place, con_init fetches + mov [0],dx | it from 0x90000. + +| Get memory size (extended mem, kB) + + mov ah,#0x88 + int 0x15 + mov [2],ax + +| Get hd0 data + + mov ax,#0x0000 + mov ds,ax + lds si,[4*0x41] + mov ax,#INITSEG + mov es,ax + mov di,#0x0080 + mov cx,#0x10 + rep + movsb + +| Get hd1 data + + mov ax,#0x0000 + mov ds,ax + lds si,[4*0x46] + mov ax,#INITSEG + mov es,ax + mov di,#0x0090 + mov cx,#0x10 + rep + movsb + +| Check that there IS a hd1 :-) + + mov ax,#0x01500 + mov dl,#0x81 + int 0x13 + jc no_disk1 + cmp ah,#3 + je is_disk1 +no_disk1: + mov ax,#INITSEG + mov es,ax + mov di,#0x0090 + mov cx,#0x10 + mov ax,#0x00 + rep + stosb +is_disk1: + +| 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 + jmp do_move + +| then we load the segment descriptors + +end_move: + mov ax,#SETUPSEG | 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 + +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 512+gdt,0x9 | gdt base = 0X9xxxx + +.text +endtext: +.data +enddata: +.bss +endbss: diff --git a/kernel/0.1x/linux-0.10/boot/setup.sg b/kernel/0.1x/linux-0.10/boot/setup.sg new file mode 100644 index 00000000..4d3ee3fd --- /dev/null +++ b/kernel/0.1x/linux-0.10/boot/setup.sg @@ -0,0 +1,243 @@ +/* + * + * setup.s (C) 1991 Linus Torvalds + * + * setup.s is responsible for getting the system data from the BIOS, + * and putting them into the appropriate places in system memory. + * both setup.s and system has been loaded by the bootblock. + * + * This code asks the bios for memory/disk/other parameters, and + * puts them in a "safe" place: 0x90000-0x901FF, ie where the + * boot-block used to be. It is then up to the protected mode + * system to read them from there before the area is overwritten + * for buffer-blocks. + * + */ + +/* + * NOTE! These had better be the same as in bootsect.s! + */ + +INITSEG = 0x9000 # we move boot here - out of the way +SYSSEG = 0x1000 # system loaded at 0x10000 (65536). +SETUPSEG = 0x9020 # this is the current segment + +.globl begtext, begdata, begbss, endtext, enddata, endbss +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +entry start +start: + +/* + * ok, the read went well so we get current cursor position and save it for + * posterity. + */ + + mov $INITSEG,%ax # this is done in bootsect already, but... + mov %ax,%ds + mov $0x03,%ah # read cursor pos + xor %bh,%bh + int 0x10 # save it in known place, con_init fetches + mov [0],%dx # it from 0x90000. + +/* + * Get memory size (extended mem, kB) + */ + + mov $0x88,%ah + int 0x15 + mov [2],%ax + +/* + * Get hd0 data + */ + + mov $0x0000,%ax + mov %ax,%ds + lds %si,[4*0x41] + mov $INITSEG,%ax + mov %ax,%es + mov $0x0080,%di + mov $0x10,%cx + rep + movsb + +/* + * Get hd1 data + */ + + mov $0x0000,%ax + mov %ax,%ds + lds %si,[4*0x46] + mov $INITSEG,%ax + mov %ax,%es + mov $0x0090,%di + mov $0x10,%cx + rep + movsb + +/* + * Check that there IS a hd1 :-) + */ + + mov $0x01500,%ax + mov $0x81,%dl + int 0x13 + jc no_disk1 + cmp %ah,$3 + je is_disk1 +no_disk1: + mov $INITSEG,%ax + mov %ax,%es + mov $0x0090,%di + mov $0x10,%cx + mov $0x00,%ax + rep + stosb +is_disk1: + +/* + * now we want to move to protected mode ... + */ + + cli # no interrupts allowed ! + +/* + * first we move the system to it's rightful place + */ + + mov $0x0000,%ax + cld # 'direction'=0, movs moves forward +do_move: + mov %ax,%es # destination segment + add $0x1000,%ax + cmp %ax,$0x9000 + jz end_move + mov %ax,%ds # source segment + sub %di,%di + sub %si,%si + mov $0x8000,%cx + rep + movsw + jmp do_move + +/* + * then we load the segment descriptors + */ + +end_move: + mov $SETUPSEG,%ax # right, forgot this at first. didn't work :-) + mov %ax,%ds + 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 $0xD1,%al # command write + out %al,$0x64 + call empty_8042 + mov $0xDF,%al # A20 on + out %al,$0x60 + 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 $0x11,%al # initialization sequence + out %al,$0x20 # send it to 8259A-1 + .word 0x00eb,0x00eb # jmp $+2, jmp $+2 + out %al,$0xA0 # and to 8259A-2 + .word 0x00eb,0x00eb + mov $0x20,%al # start of hardware int's (0x20) + out %al,$0x21 + .word 0x00eb,0x00eb + mov $0x28,%al # start of hardware int's 2 (0x28) + out %al,$0xA1 + .word 0x00eb,0x00eb + mov $0x04,%al # 8259-1 is master + out %al,$0x21 + .word 0x00eb,0x00eb + mov $0x02,%al # 8259-2 is slave + out %al,$0xA1 + .word 0x00eb,0x00eb + mov $0x01,%al # 8086 mode for both + out %al,$0x21 + .word 0x00eb,0x00eb + out %al,$0xA1 + .word 0x00eb,0x00eb + mov $0xFF,%al # mask off all interrupts for now + out %al,$0x21 + .word 0x00eb,0x00eb + out %al,$0xA1 + +/* + * 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 $0x0001,%ax # 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 $0x64,%al # 8042 status port + test %al,$2 # is input buffer full? + jnz empty_8042 # yes - loop + 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 512+gdt,0x9 # gdt base = 0X9xxxx + +.text +endtext: +.data +enddata: +.bss +endbss: diff --git a/kernel/0.1x/linux-0.10/fs/Makefile b/kernel/0.1x/linux-0.10/fs/Makefile new file mode 100644 index 00000000..1aa89a5e --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/Makefile @@ -0,0 +1,104 @@ +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/signal.h ../include/linux/kernel.h +block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/segment.h ../include/asm/system.h +buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/system.h ../include/asm/io.h +char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/segment.h ../include/asm/io.h +exec.o : exec.c ../include/errno.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/a.out.h ../include/linux/fs.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/mm.h \ + ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h +fcntl.o : fcntl.c ../include/string.h ../include/errno.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/segment.h ../include/fcntl.h \ + ../include/sys/stat.h +file_dev.o : file_dev.c ../include/errno.h ../include/fcntl.h \ + ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/segment.h +file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h +inode.o : inode.c ../include/string.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/system.h +ioctl.o : ioctl.c ../include/string.h ../include/errno.h \ + ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/signal.h +namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h \ + ../include/string.h ../include/fcntl.h ../include/errno.h \ + ../include/const.h ../include/sys/stat.h +open.o : open.c ../include/string.h ../include/errno.h ../include/fcntl.h \ + ../include/sys/types.h ../include/utime.h ../include/sys/stat.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/tty.h \ + ../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h +pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/asm/segment.h +read_write.o : read_write.c ../include/sys/stat.h ../include/sys/types.h \ + ../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/signal.h ../include/asm/segment.h +stat.o : stat.c ../include/errno.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/linux/fs.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/segment.h +super.o : super.c ../include/linux/config.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/system.h ../include/errno.h ../include/sys/stat.h +truncate.o : truncate.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/signal.h ../include/sys/stat.h +tty_ioctl.o : tty_ioctl.c ../include/errno.h ../include/termios.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/linux/tty.h ../include/asm/segment.h \ + ../include/asm/system.h diff --git a/kernel/0.1x/linux-0.10/fs/bitmap.c b/kernel/0.1x/linux-0.10/fs/bitmap.c new file mode 100644 index 00000000..b2ee1f70 --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/bitmap.c @@ -0,0 +1,164 @@ +/* + * linux/fs/bitmap.c + * + * (C) 1991 Linus Torvalds + */ + +/* bitmap.c contains the code that handles the inode and block bitmaps */ +#include + +#include +#include + +#define clear_block(addr) \ +__asm__("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/kernel/0.1x/linux-0.10/fs/block_dev.c b/kernel/0.1x/linux-0.10/fs/block_dev.c new file mode 100644 index 00000000..5af8f401 --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/block_dev.c @@ -0,0 +1,73 @@ +/* + * linux/fs/block_dev.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include +#include +#include + +int block_write(int dev, long * pos, char * buf, int count) +{ + int block = *pos >> BLOCK_SIZE_BITS; + int offset = *pos & (BLOCK_SIZE-1); + int chars; + int written = 0; + struct buffer_head * bh; + register char * p; + + while (count>0) { + chars = BLOCK_SIZE - offset; + if (chars > count) + chars=count; + if (chars == BLOCK_SIZE) + bh = getblk(dev,block); + else + bh = breada(dev,block,block+1,block+2,-1); + block++; + if (!bh) + return written?written:-EIO; + p = offset + bh->b_data; + offset = 0; + *pos += chars; + written += chars; + count -= chars; + while (chars-->0) + *(p++) = get_fs_byte(buf++); + bh->b_dirt = 1; + brelse(bh); + } + return written; +} + +int block_read(int dev, unsigned long * pos, char * buf, int count) +{ + int block = *pos >> BLOCK_SIZE_BITS; + int offset = *pos & (BLOCK_SIZE-1); + int chars; + int read = 0; + struct buffer_head * bh; + register char * p; + + while (count>0) { + chars = BLOCK_SIZE-offset; + if (chars > count) + chars = count; + if (!(bh = breada(dev,block,block+1,block+2,-1))) + return read?read:-EIO; + block++; + p = offset + bh->b_data; + offset = 0; + *pos += chars; + read += chars; + count -= chars; + while (chars-->0) + put_fs_byte(*(p++),buf++); + brelse(bh); + } + return read; +} diff --git a/kernel/0.1x/linux-0.10/fs/buffer.c b/kernel/0.1x/linux-0.10/fs/buffer.c new file mode 100644 index 00000000..0d73ac27 --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/buffer.c @@ -0,0 +1,341 @@ +/* + * linux/fs/buffer.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'buffer.c' implements the buffer-cache functions. Race-conditions have + * been avoided by NEVER letting a interrupt change a buffer (except for the + * data, of course), but instead letting the caller do it. NOTE! As interrupts + * can wake up a caller, some cli-sti sequences are needed to check for + * sleep-on-calls. These should be extremely quick, though (I hope). + */ + +/* + * NOTE! There is one discordant note here: checking floppies for + * disk change. This is where it fits best, I think, as it should + * invalidate changed floppy-disk-caches. + */ + +#include + +#include +#include +#include +#include +#include + +extern int end; +struct buffer_head * start_buffer = (struct buffer_head *) &end; +struct buffer_head * hash_table[NR_HASH]; +static struct buffer_head * free_list; +static struct task_struct * buffer_wait = NULL; +int NR_BUFFERS = 0; + +static inline void wait_on_buffer(struct buffer_head * bh) +{ + cli(); + while (bh->b_lock) + sleep_on(&bh->b_wait); + sti(); +} + +int sys_sync(void) +{ + int i; + struct buffer_head * bh; + + sync_inodes(); /* write out inodes into buffers */ + bh = start_buffer; + for (i=0 ; ib_dirt) + ll_rw_block(WRITE,bh); + } + return 0; +} + +int sync_dev(int dev) +{ + int i; + struct buffer_head * bh; + + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_dirt) + ll_rw_block(WRITE,bh); + } + sync_inodes(); + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_dirt) + ll_rw_block(WRITE,bh); + } + return 0; +} + +/* + * This routine checks whether a floppy has been changed, and + * invalidates all buffer-cache-entries in that case. This + * is a relatively slow routine, so we have to try to minimize using + * it. Thus it is called only upon a 'mount' or 'open'. This + * is the best way of combining speed and utility, I think. + * People changing diskettes in the middle of an operation deserve + * to loose :-) + * + * NOTE! Although currently this is only for floppies, the idea is + * that any additional removable block-device will use this routine, + * and that mount/open needn't know that floppies/whatever are + * special. + */ +void check_disk_change(int dev) +{ + int i; + struct buffer_head * bh; + + if (MAJOR(dev) != 2) + return; + dev=MINOR(dev) & 0x03; /* which floppy is it? */ + if (!floppy_change(dev)) + return; + dev |= 0x200; + for (i=0 ; ib_dev & 0xff03) != dev) + continue; + wait_on_buffer(bh); + if ((bh->b_dev & 0xff03) == dev) + bh->b_uptodate = bh->b_dirt = 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; + + for (;;) { + if (!(bh=find_buffer(dev,block))) + return NULL; + bh->b_count++; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_blocknr == block) + return bh; + bh->b_count--; + } +} + +/* + * Ok, this is getblk, and it isn't very clear, again to hinder + * race-conditions. Most of the code is seldom used, (ie repeating), + * so it should be much more efficient than it looks. + * + * The algoritm is changed: better, and an elusive bug removed. + * LBT 11.11.91 + */ +#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock) +struct buffer_head * getblk(int dev,int block) +{ + struct buffer_head * tmp, * bh; + +repeat: + if (bh = get_hash_table(dev,block)) + return bh; + tmp = free_list; + do { + if (tmp->b_count) + continue; + if (!bh || BADNESS(tmp)b_next_free) != free_list); + if (!bh) { + sleep_on(&buffer_wait); + goto repeat; + } + wait_on_buffer(bh); + if (bh->b_count) + goto repeat; + while (bh->b_dirt) { + sync_dev(bh->b_dev); + wait_on_buffer(bh); + if (bh->b_count) + goto repeat; + } +/* NOTE!! While we slept waiting for this block, somebody else might */ +/* already have added "this" block to the cache. check it */ + if (find_buffer(dev,block)) + goto repeat; +/* OK, FINALLY we know that this buffer is the only one of it's kind, */ +/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */ + bh->b_count=1; + bh->b_dirt=0; + bh->b_uptodate=0; + remove_from_queues(bh); + bh->b_dev=dev; + bh->b_blocknr=block; + insert_into_queues(bh); + return bh; +} + +void brelse(struct buffer_head * buf) +{ + if (!buf) + return; + wait_on_buffer(buf); + if (!(buf->b_count--)) + panic("Trying to free free buffer"); + wake_up(&buffer_wait); +} + +/* + * bread() reads a specified block and returns the buffer that contains + * it. It returns NULL if the block was unreadable. + */ +struct buffer_head * bread(int dev,int block) +{ + struct buffer_head * bh; + + if (!(bh=getblk(dev,block))) + panic("bread: getblk returned NULL\n"); + if (bh->b_uptodate) + return bh; + ll_rw_block(READ,bh); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return NULL; +} + +/* + * Ok, breada can be used as bread, but additionally to mark other + * blocks for reading as well. End the argument list with a negative + * number. + */ +struct buffer_head * breada(int dev,int first, ...) +{ + va_list args; + struct buffer_head * bh, *tmp; + + va_start(args,first); + if (!(bh=getblk(dev,first))) + panic("bread: getblk returned NULL\n"); + if (!bh->b_uptodate) + ll_rw_block(READ,bh); + while ((first=va_arg(args,int))>=0) { + tmp=getblk(dev,first); + if (tmp) { + if (!tmp->b_uptodate) + ll_rw_block(READA,bh); + tmp->b_count--; + } + } + va_end(args); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return (NULL); +} + +void buffer_init(long buffer_end) +{ + struct buffer_head * h = start_buffer; + void * b; + int i; + + if (buffer_end == 1<<20) + b = (void *) (640*1024); + else + b = (void *) buffer_end; + while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) { + h->b_dev = 0; + h->b_dirt = 0; + h->b_count = 0; + h->b_lock = 0; + h->b_uptodate = 0; + h->b_wait = NULL; + h->b_next = NULL; + h->b_prev = NULL; + h->b_data = (char *) b; + h->b_prev_free = h-1; + h->b_next_free = h+1; + h++; + NR_BUFFERS++; + if (b == (void *) 0x100000) + b = (void *) 0xA0000; + } + h--; + free_list = start_buffer; + free_list->b_prev_free = h; + h->b_next_free = free_list; + for (i=0;i +#include + +#include +#include + +#include +#include + +extern int tty_read(unsigned minor,char * buf,int count); +extern int tty_write(unsigned minor,char * buf,int count); + +typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count,off_t * pos); + +static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos) +{ + return ((rw==READ)?tty_read(minor,buf,count): + tty_write(minor,buf,count)); +} + +static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos) +{ + if (current->tty<0) + return -EPERM; + return rw_ttyx(rw,current->tty,buf,count,pos); +} + +static int rw_ram(int rw,char * buf, int count, off_t *pos) +{ + return -EIO; +} + +static int rw_mem(int rw,char * buf, int count, off_t * pos) +{ + return -EIO; +} + +static int rw_kmem(int rw,char * buf, int count, off_t * pos) +{ + return -EIO; +} + +static int rw_port(int rw,char * buf, int count, off_t * pos) +{ + int i=*pos; + + while (count-->0 && i<65536) { + if (rw==READ) + put_fs_byte(inb(i),buf++); + else + outb(get_fs_byte(buf++),i); + i++; + } + i -= *pos; + *pos += i; + return i; +} + +static int rw_memory(int rw, unsigned minor, char * buf, int count, off_t * pos) +{ + switch(minor) { + case 0: + return rw_ram(rw,buf,count,pos); + case 1: + return rw_mem(rw,buf,count,pos); + case 2: + return rw_kmem(rw,buf,count,pos); + case 3: + return (rw==READ)?0:count; /* rw_null */ + case 4: + return rw_port(rw,buf,count,pos); + default: + return -EIO; + } +} + +#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr))) + +static crw_ptr crw_table[]={ + NULL, /* nodev */ + rw_memory, /* /dev/mem etc */ + NULL, /* /dev/fd */ + NULL, /* /dev/hd */ + rw_ttyx, /* /dev/ttyx */ + rw_tty, /* /dev/tty */ + NULL, /* /dev/lp */ + NULL}; /* unnamed pipes */ + +int rw_char(int rw,int dev, char * buf, int count, off_t * pos) +{ + crw_ptr call_addr; + + if (MAJOR(dev)>=NRDEVS) + 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,pos); +} diff --git a/kernel/0.1x/linux-0.10/fs/exec.c b/kernel/0.1x/linux-0.10/fs/exec.c new file mode 100644 index 00000000..a78c8f51 --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/exec.c @@ -0,0 +1,438 @@ +/* + * linux/fs/exec.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 ; counti_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. + * + * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies + * whether the string and the string array are from user or kernel segments: + * + * from_kmem argv * argv ** + * 0 user space user space + * 1 kernel space user space + * 2 kernel space kernel space + * + * We do this by playing games with the fs segment register. Since it + * it is expensive to load a segment register, we try to avoid calling + * set_fs() unless we absolutely have to. + */ +static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, + unsigned long p, int from_kmem) +{ + char *tmp, *pag; + int len, offset = 0; + unsigned long old_fs, new_fs; + + if (!p) + return 0; /* bullet-proofing */ + new_fs = get_ds(); + old_fs = get_fs(); + if (from_kmem==2) + set_fs(new_fs); + while (argc-- > 0) { + if (from_kmem == 1) + set_fs(new_fs); + if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc))) + panic("argc is wrong"); + if (from_kmem == 1) + set_fs(old_fs); + len=0; /* remember zero-padding */ + do { + len++; + } while (get_fs_byte(tmp++)); + if (p-len < 0) { /* this shouldn't happen - 128kB */ + set_fs(old_fs); + return 0; + } + while (len) { + --p; --tmp; --len; + if (--offset < 0) { + offset = p % PAGE_SIZE; + if (from_kmem==2) + set_fs(old_fs); + if (!(pag = (char *) page[p/PAGE_SIZE]) && + !(pag = (char *) page[p/PAGE_SIZE] = + (unsigned long *) get_free_page())) + return 0; + if (from_kmem==2) + set_fs(new_fs); + + } + *(pag + offset) = get_fs_byte(tmp); + } + } + if (from_kmem==2) + set_fs(old_fs); + return p; +} + +static unsigned long change_ldt(unsigned long text_size,unsigned long * page) +{ + unsigned long code_limit,data_limit,code_base,data_base; + int i; + + code_limit = text_size+PAGE_SIZE -1; + code_limit &= 0xFFFFF000; + data_limit = 0x4000000; + code_base = get_base(current->ldt[1]); + data_base = code_base; + set_base(current->ldt[1],code_base); + set_limit(current->ldt[1],code_limit); + set_base(current->ldt[2],data_base); + set_limit(current->ldt[2],data_limit); +/* make sure fs points to the NEW data segment */ + __asm__("pushl $0x17\n\tpop %%fs"::); + data_base += data_limit; + for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) { + data_base -= PAGE_SIZE; + if (page[i]) + put_page(page[i],data_base); + } + return data_limit; +} + +/* + * 'do_execve()' executes a new program. + */ +int do_execve(unsigned long * eip,long tmp,char * filename, + char ** argv, char ** envp) +{ + struct m_inode * inode; + struct buffer_head * bh; + struct exec ex; + unsigned long page[MAX_ARG_PAGES]; + int i,argc,envc; + int e_uid, e_gid; + int retval; + int sh_bang = 0; + char *buf = 0; + unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4; + + if ((0xffff & eip[1]) != 0x000f) + panic("execve called from supervisor mode"); + for (i=0 ; ii_mode)) { /* must be regular file */ + retval = -EACCES; + goto exec_error2; + } + i = inode->i_mode; + e_uid = (i & S_ISUID) ? inode->i_uid : current->euid; + e_gid = (i & S_ISGID) ? inode->i_gid : current->egid; + if (current->euid == inode->i_uid) + i >>= 6; + else if (current->egid == inode->i_gid) + i >>= 3; + if (!(i & 1) && + !((inode->i_mode & 0111) && suser())) { + retval = -ENOEXEC; + goto exec_error2; + } + if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) { + retval = -EACCES; + goto exec_error2; + } + ex = *((struct exec *) bh->b_data); /* read exec-header */ + if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) { + /* + * This section does the #! interpretation. + * Sorta complicated, but hopefully it will work. -TYT + */ + + char *cp, *interp, *i_name, *i_arg; + unsigned long old_fs; + + if (!buf) + buf = malloc(1024); + strncpy(buf, bh->b_data+2, 1022); + brelse(bh); + iput(inode); + buf[1022] = '\0'; + if (cp = strchr(buf, '\n')) { + *cp = '\0'; + for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++); + } + if (!cp || *cp == '\0') { + retval = -ENOEXEC; /* No interpreter name found */ + goto exec_error1; + } + interp = i_name = cp; + i_arg = 0; + for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) { + if (*cp == '/') + i_name = cp+1; + } + if (*cp) { + *cp++ = '\0'; + i_arg = cp; + } + /* + * OK, we've parsed out the interpreter name and + * (optional) argument. + */ + if (sh_bang++ == 0) { + p = copy_strings(envc, envp, page, p, 0); + p = copy_strings(--argc, argv+1, page, p, 0); + } + /* + * Splice in (1) the interpreter's name for argv[0] + * (2) (optional) argument to interpreter + * (3) filename of shell script + * + * This is done in reverse order, because of how the + * user environment and arguments are stored. + */ + p = copy_strings(1, &filename, page, p, 1); + argc++; + if (i_arg) { + p = copy_strings(1, &i_arg, page, p, 2); + argc++; + } + p = copy_strings(1, &i_name, page, p, 2); + argc++; + if (!p) { + retval = -ENOMEM; + goto exec_error1; + } + /* + * OK, now restart the process with the interpreter's inode. + */ + old_fs = get_fs(); + set_fs(get_ds()); + if (!(inode=namei(interp))) { /* get executables inode */ + set_fs(old_fs); + retval = -ENOENT; + goto exec_error1; + } + set_fs(old_fs); + goto restart_interp; + } + brelse(bh); + if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize || + ex.a_text+ex.a_data+ex.a_bss>0x3000000 || + inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { + retval = -ENOEXEC; + goto exec_error2; + } + if (N_TXTOFF(ex) != BLOCK_SIZE) { + printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename); + retval = -ENOEXEC; + goto exec_error2; + } + if (!sh_bang) { + p = copy_strings(envc,envp,page,p,0); + p = copy_strings(argc,argv,page,p,0); + if (!p) { + retval = -ENOMEM; + goto exec_error2; + } + } +/* OK, This is the point of no return */ + if (buf) + free_s(buf, 1024); + for (i=0 ; i<32 ; i++) + current->sigaction[i].sa_handler = NULL; + for (i=0 ; iclose_on_exec>>i)&1) + sys_close(i); + current->close_on_exec = 0; + free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); + free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); + if (last_task_used_math == current) + last_task_used_math = NULL; + current->used_math = 0; + p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE; + p = (unsigned long) create_tables((char *)p,argc,envc); + current->brk = ex.a_bss + + (current->end_data = ex.a_data + + (current->end_code = ex.a_text)); + current->start_stack = p & 0xfffff000; + current->euid = e_uid; + current->egid = e_gid; + i = 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; +exec_error2: + iput(inode); +exec_error1: + if (buf) + free(buf); + for (i=0 ; i +#include +#include +#include +#include + +#include +#include + +extern int sys_close(int fd); + +static int dupfd(unsigned int fd, unsigned int arg) +{ + if (fd >= NR_OPEN || !current->filp[fd]) + return -EBADF; + if (arg >= NR_OPEN) + return -EINVAL; + while (arg < NR_OPEN) + if (current->filp[arg]) + arg++; + else + break; + if (arg >= NR_OPEN) + return -EMFILE; + current->close_on_exec &= ~(1<filp[arg] = current->filp[fd])->f_count++; + return arg; +} + +int sys_dup2(unsigned int oldfd, unsigned int newfd) +{ + sys_close(newfd); + return dupfd(oldfd,newfd); +} + +int sys_dup(unsigned int fildes) +{ + return dupfd(fildes,0); +} + +int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + switch (cmd) { + case F_DUPFD: + return dupfd(fd,arg); + case F_GETFD: + return (current->close_on_exec>>fd)&1; + case F_SETFD: + if (arg&1) + current->close_on_exec |= (1<close_on_exec &= ~(1<f_flags; + case F_SETFL: + filp->f_flags &= ~(O_APPEND | O_NONBLOCK); + filp->f_flags |= arg & (O_APPEND | O_NONBLOCK); + return 0; + case F_GETLK: case F_SETLK: case F_SETLKW: + return -1; + default: + return -1; + } +} diff --git a/kernel/0.1x/linux-0.10/fs/file_dev.c b/kernel/0.1x/linux-0.10/fs/file_dev.c new file mode 100644 index 00000000..42eaf37a --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/file_dev.c @@ -0,0 +1,90 @@ +/* + * linux/fs/file_dev.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) +{ + int left,chars,nr; + struct buffer_head * bh; + + if ((left=count)<=0) + return 0; + while (left) { + if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) { + if (!(bh=bread(inode->i_dev,nr))) + break; + } else + bh = NULL; + nr = filp->f_pos % BLOCK_SIZE; + chars = MIN( BLOCK_SIZE-nr , left ); + filp->f_pos += chars; + left -= chars; + if (bh) { + char * p = nr + bh->b_data; + while (chars-->0) + put_fs_byte(*(p++),buf++); + brelse(bh); + } else { + while (chars-->0) + put_fs_byte(0,buf++); + } + } + inode->i_atime = CURRENT_TIME; + return (count-left)?(count-left):-ERROR; +} + +int file_write(struct m_inode * inode, struct file * filp, char * buf, int count) +{ + off_t pos; + int block,c; + struct buffer_head * bh; + char * p; + int i=0; + +/* + * ok, append may not work when many processes are writing at the same time + * but so what. That way leads to madness anyway. + */ + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + else + pos = filp->f_pos; + while (ii_dev,block))) + break; + c = pos % BLOCK_SIZE; + p = c + bh->b_data; + bh->b_dirt = 1; + c = BLOCK_SIZE-c; + if (c > count-i) c = count-i; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + i += c; + while (c-->0) + *(p++) = get_fs_byte(buf++); + brelse(bh); + } + inode->i_mtime = CURRENT_TIME; + if (!(filp->f_flags & O_APPEND)) { + filp->f_pos = pos; + inode->i_ctime = CURRENT_TIME; + } + return (i?i:-1); +} diff --git a/kernel/0.1x/linux-0.10/fs/file_table.c b/kernel/0.1x/linux-0.10/fs/file_table.c new file mode 100644 index 00000000..0cf8b1b8 --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/file_table.c @@ -0,0 +1,9 @@ +/* + * linux/fs/file_table.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +struct file file_table[NR_FILE]; diff --git a/kernel/0.1x/linux-0.10/fs/inode.c b/kernel/0.1x/linux-0.10/fs/inode.c new file mode 100644 index 00000000..735c57dd --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/inode.c @@ -0,0 +1,317 @@ +/* + * linux/fs/inode.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include + +struct m_inode inode_table[NR_INODE]={{0,},}; + +static void read_inode(struct m_inode * inode); +static void write_inode(struct m_inode * inode); + +static inline void wait_on_inode(struct m_inode * inode) +{ + cli(); + while (inode->i_lock) + sleep_on(&inode->i_wait); + sti(); +} + +static inline void lock_inode(struct m_inode * inode) +{ + cli(); + while (inode->i_lock) + sleep_on(&inode->i_wait); + inode->i_lock=1; + sti(); +} + +static inline void unlock_inode(struct m_inode * inode) +{ + inode->i_lock=0; + wake_up(&inode->i_wait); +} + +void sync_inodes(void) +{ + int i; + struct m_inode * inode; + + inode = 0+inode_table; + for(i=0 ; ii_dirt && !inode->i_pipe) + write_inode(inode); + } +} + +static int _bmap(struct m_inode * inode,int block,int create) +{ + struct buffer_head * bh; + int i; + + if (block<0) + panic("_bmap: block<0"); + if (block >= 7+512+512*512) + panic("_bmap: block>big"); + if (block<7) { + if (create && !inode->i_zone[block]) + if (inode->i_zone[block]=new_block(inode->i_dev)) { + inode->i_ctime=CURRENT_TIME; + inode->i_dirt=1; + } + return inode->i_zone[block]; + } + block -= 7; + if (block<512) { + if (create && !inode->i_zone[7]) + if (inode->i_zone[7]=new_block(inode->i_dev)) { + inode->i_dirt=1; + inode->i_ctime=CURRENT_TIME; + } + if (!inode->i_zone[7]) + return 0; + if (!(bh = bread(inode->i_dev,inode->i_zone[7]))) + return 0; + i = ((unsigned short *) (bh->b_data))[block]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block]=i; + bh->b_dirt=1; + } + brelse(bh); + return i; + } + block -= 512; + if (create && !inode->i_zone[8]) + if (inode->i_zone[8]=new_block(inode->i_dev)) { + inode->i_dirt=1; + inode->i_ctime=CURRENT_TIME; + } + if (!inode->i_zone[8]) + return 0; + if (!(bh=bread(inode->i_dev,inode->i_zone[8]))) + return 0; + i = ((unsigned short *)bh->b_data)[block>>9]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block>>9]=i; + bh->b_dirt=1; + } + brelse(bh); + if (!i) + return 0; + if (!(bh=bread(inode->i_dev,i))) + return 0; + i = ((unsigned short *)bh->b_data)[block&511]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block&511]=i; + bh->b_dirt=1; + } + brelse(bh); + return i; +} + +int bmap(struct m_inode * inode,int block) +{ + return _bmap(inode,block,0); +} + +int create_block(struct m_inode * inode, int block) +{ + return _bmap(inode,block,1); +} + +void iput(struct m_inode * inode) +{ + if (!inode) + return; + wait_on_inode(inode); + if (!inode->i_count) + panic("iput: trying to free free inode"); + if (inode->i_pipe) { + wake_up(&inode->i_wait); + if (--inode->i_count) + return; + free_page(inode->i_size); + inode->i_count=0; + inode->i_dirt=0; + inode->i_pipe=0; + return; + } + if (!inode->i_dev || inode->i_count>1) { + inode->i_count--; + return; + } +repeat: + if (S_ISBLK(inode->i_mode)) { + sync_dev(inode->i_zone[0]); + wait_on_inode(inode); + } + 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 ; inri_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 (inode->i_mount) { + int i; + + for (i = 0 ; i= NR_SUPER) { + printk("Mounted inode hasn't got sb\n"); + if (empty) + iput(empty); + return inode; + } + iput(inode); + dev = super_block[i].s_dev; + nr = ROOT_INO; + inode = inode_table; + continue; + } + if (empty) + iput(empty); + return inode; + } + if (!empty) + return (NULL); + inode=empty; + inode->i_dev = dev; + inode->i_num = nr; + read_inode(inode); + return inode; +} + +static void read_inode(struct m_inode * inode) +{ + struct super_block * sb; + struct buffer_head * bh; + int block; + + lock_inode(inode); + 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/kernel/0.1x/linux-0.10/fs/ioctl.c b/kernel/0.1x/linux-0.10/fs/ioctl.c new file mode 100644 index 00000000..ef33d332 --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/ioctl.c @@ -0,0 +1,46 @@ +/* + * linux/fs/ioctl.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include + +extern int tty_ioctl(int dev, int cmd, int arg); + +typedef int (*ioctl_ptr)(int dev,int cmd,int arg); + +#define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr))) + +static ioctl_ptr ioctl_table[]={ + NULL, /* nodev */ + NULL, /* /dev/mem */ + NULL, /* /dev/fd */ + NULL, /* /dev/hd */ + tty_ioctl, /* /dev/ttyx */ + tty_ioctl, /* /dev/tty */ + NULL, /* /dev/lp */ + NULL}; /* named pipes */ + + +int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + int dev,mode; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + mode=filp->f_inode->i_mode; + if (!S_ISCHR(mode) && !S_ISBLK(mode)) + return -EINVAL; + dev = filp->f_inode->i_zone[0]; + if (MAJOR(dev) >= NRDEVS) + panic("unknown device for ioctl"); + if (!ioctl_table[MAJOR(dev)]) + return -ENOTTY; + return ioctl_table[MAJOR(dev)](dev,cmd,arg); +} diff --git a/kernel/0.1x/linux-0.10/fs/namei.c b/kernel/0.1x/linux-0.10/fs/namei.c new file mode 100644 index 00000000..3843db8a --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/namei.c @@ -0,0 +1,769 @@ +/* + * linux/fs/namei.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE]) + +/* + * comment out this line if you want names > NAME_LEN chars to be + * truncated. Else they will be disallowed. + */ +/* #define NO_TRUNCATE */ + +#define MAY_EXEC 1 +#define MAY_WRITE 2 +#define MAY_READ 4 + +/* + * permission() + * + * is used to check for read/write/execute permissions on a file. + * I don't know if we should look at just the euid or both euid and + * uid, but that should be easily changed. + */ +static int permission(struct m_inode * inode,int mask) +{ + int mode = inode->i_mode; + +/* special case: not even root can read/write a deleted file */ + if (inode->i_dev && !inode->i_nlinks) + return 0; + else if (current->euid==inode->i_uid) + mode >>= 6; + else if (current->egid==inode->i_gid) + mode >>= 3; + if (((mode & mask & 0007) == mask) || suser()) + return 1; + return 0; +} + +/* + * ok, we cannot use strncmp, as the name is not in our data space. + * Thus we'll have to use match. No big problem. Match also makes + * some sanity tests. + * + * NOTE! unlike strncmp, match returns 1 for success, 0 for failure. + */ +static int match(int len,const char * name,struct dir_entry * de) +{ + register int same __asm__("ax"); + + if (!de || !de->inode || len > NAME_LEN) + return 0; + if (len < NAME_LEN && de->name[len]) + return 0; + __asm__("cld\n\t" + "fs ; repe ; cmpsb\n\t" + "setz %%al" + :"=a" (same) + :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len) + :"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. + * + * This also takes care of the few special cases due to '..'-traversal + * over a pseudo-root and a mount point. + */ +static struct buffer_head * find_entry(struct m_inode ** dir, + const char * name, int namelen, struct dir_entry ** res_dir) +{ + int entries; + int block,i; + struct buffer_head * bh; + struct dir_entry * de; + struct super_block * sb; + +#ifdef NO_TRUNCATE + if (namelen > NAME_LEN) + return NULL; +#else + if (namelen > NAME_LEN) + namelen = NAME_LEN; +#endif + entries = (*dir)->i_size / (sizeof (struct dir_entry)); + *res_dir = NULL; + if (!namelen) + return NULL; +/* check for '..', as we might have to do some "magic" for it */ + if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') { +/* '..' in a pseudo-root results in a faked '.' (just change namelen) */ + if ((*dir) == current->root) + namelen=1; + else if ((*dir)->i_num == ROOT_INO) { +/* '..' over a mount-point results in 'dir' being exchanged for the mounted + directory-inode. NOTE! We set mounted, so that we can iput the new dir */ + sb=get_super((*dir)->i_dev); + if (sb->s_imount) { + iput(*dir); + (*dir)=sb->s_imount; + (*dir)->i_count++; + } + } + } + if (!(block = (*dir)->i_zone[0])) + return NULL; + if (!(bh = bread((*dir)->i_dev,block))) + return NULL; + i = 0; + de = (struct dir_entry *) bh->b_data; + while (i < entries) { + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; + if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) || + !(bh = bread((*dir)->i_dev,block))) { + i += DIR_ENTRIES_PER_BLOCK; + continue; + } + de = (struct dir_entry *) bh->b_data; + } + if (match(namelen,name,de)) { + *res_dir = de; + return bh; + } + de++; + i++; + } + brelse(bh); + return NULL; +} + +/* + * add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as find_entry(). It returns NULL if it failed. + * + * NOTE!! The inode part of 'de' is left at 0 - which means you + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ +static struct buffer_head * add_entry(struct m_inode * dir, + const char * name, int namelen, struct dir_entry ** res_dir) +{ + int block,i; + struct buffer_head * bh; + struct dir_entry * de; + + *res_dir = NULL; +#ifdef NO_TRUNCATE + if (namelen > NAME_LEN) + return NULL; +#else + if (namelen > NAME_LEN) + namelen = NAME_LEN; +#endif + if (!namelen) + return NULL; + if (!(block = dir->i_zone[0])) + return NULL; + if (!(bh = bread(dir->i_dev,block))) + return NULL; + i = 0; + de = (struct dir_entry *) bh->b_data; + while (1) { + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; + block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK); + if (!block) + return NULL; + if (!(bh = bread(dir->i_dev,block))) { + i += DIR_ENTRIES_PER_BLOCK; + continue; + } + de = (struct dir_entry *) bh->b_data; + } + if (i*sizeof(struct dir_entry) >= dir->i_size) { + de->inode=0; + dir->i_size = (i+1)*sizeof(struct dir_entry); + dir->i_dirt = 1; + dir->i_ctime = CURRENT_TIME; + } + if (!de->inode) { + dir->i_mtime = CURRENT_TIME; + for (i=0; i < NAME_LEN ; i++) + de->name[i]=(ib_dirt = 1; + *res_dir = de; + return bh; + } + de++; + i++; + } + brelse(bh); + return NULL; +} + +/* + * get_dir() + * + * Getdir traverses the pathname until it hits the topmost directory. + * It returns NULL on failure. + */ +static struct m_inode * get_dir(const char * pathname) +{ + char c; + const char * thisname; + struct m_inode * inode; + struct buffer_head * bh; + int namelen,inr,idev; + struct dir_entry * de; + + if (!current->root || !current->root->i_count) + panic("No root inode"); + if (!current->pwd || !current->pwd->i_count) + panic("No cwd inode"); + if ((c=get_fs_byte(pathname))=='/') { + inode = current->root; + pathname++; + } else if (c) + inode = current->pwd; + else + return NULL; /* empty name is bad */ + inode->i_count++; + while (1) { + thisname = pathname; + if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) { + iput(inode); + return NULL; + } + for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++) + /* nothing */ ; + if (!c) + return inode; + if (!(bh = find_entry(&inode,thisname,namelen,&de))) { + iput(inode); + return NULL; + } + inr = de->inode; + idev = inode->i_dev; + brelse(bh); + iput(inode); + if (!(inode = iget(idev,inr))) + return NULL; + } +} + +/* + * dir_namei() + * + * dir_namei() returns the inode of the directory of the + * specified name, and the name within that directory. + */ +static struct m_inode * dir_namei(const char * pathname, + int * namelen, const char ** name) +{ + char c; + const char * basename; + struct m_inode * dir; + + if (!(dir = get_dir(pathname))) + return NULL; + basename = pathname; + while (c=get_fs_byte(pathname++)) + if (c=='/') + basename=pathname; + *namelen = pathname-basename-1; + *name = basename; + return dir; +} + +/* + * namei() + * + * is used by most simple commands to get the inode of a specified name. + * Open, link etc use their own routines, but this is enough for things + * like 'chmod' etc. + */ +struct m_inode * namei(const char * pathname) +{ + const char * basename; + int inr,dev,namelen; + struct m_inode * dir; + struct buffer_head * bh; + struct dir_entry * de; + + if (!(dir = dir_namei(pathname,&namelen,&basename))) + return NULL; + if (!namelen) /* special case: '/usr/' etc */ + return dir; + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + iput(dir); + return NULL; + } + inr = de->inode; + dev = dir->i_dev; + brelse(bh); + iput(dir); + dir=iget(dev,inr); + if (dir) { + dir->i_atime=CURRENT_TIME; + dir->i_dirt=1; + } + return dir; +} + +/* + * open_namei() + * + * namei for open - this is in fact almost the whole open-routine. + */ +int open_namei(const char * pathname, int flag, int mode, + struct m_inode ** res_inode) +{ + const char * basename; + int inr,dev,namelen; + struct m_inode * dir, *inode; + struct buffer_head * bh; + struct dir_entry * de; + + if ((flag & O_TRUNC) && !(flag & O_ACCMODE)) + flag |= O_WRONLY; + mode &= 0777 & ~current->umask; + mode |= I_REGULAR; + if (!(dir = dir_namei(pathname,&namelen,&basename))) + return -ENOENT; + if (!namelen) { /* special case: '/usr/' etc */ + if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) { + *res_inode=dir; + return 0; + } + iput(dir); + return -EISDIR; + } + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + if (!(flag & O_CREAT)) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EACCES; + } + inode = new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_uid = current->euid; + inode->i_mode = mode; + inode->i_dirt = 1; + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + inode->i_nlinks--; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->inode = inode->i_num; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + *res_inode = inode; + return 0; + } + inr = de->inode; + dev = dir->i_dev; + brelse(bh); + iput(dir); + if (flag & O_EXCL) + return -EEXIST; + if (!(inode=iget(dev,inr))) + return -EACCES; + if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) || + !permission(inode,ACC_MODE(flag))) { + iput(inode); + return -EPERM; + } + inode->i_atime = CURRENT_TIME; + if (flag & O_TRUNC) + truncate(inode); + *res_inode = inode; + return 0; +} + +int sys_mknod(const char * filename, int mode, int dev) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh; + struct dir_entry * de; + + if (!suser()) + return -EPERM; + if (!(dir = dir_namei(filename,&namelen,&basename))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + bh = find_entry(&dir,basename,namelen,&de); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_mode = mode; + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_zone[0] = dev; + inode->i_mtime = inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + iput(dir); + inode->i_nlinks=0; + iput(inode); + return -ENOSPC; + } + de->inode = inode->i_num; + bh->b_dirt = 1; + iput(dir); + iput(inode); + brelse(bh); + return 0; +} + +int sys_mkdir(const char * pathname, int mode) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh, *dir_block; + struct dir_entry * de; + + if (!suser()) + return -EPERM; + if (!(dir = dir_namei(pathname,&namelen,&basename))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + bh = find_entry(&dir,basename,namelen,&de); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_size = 32; + inode->i_dirt = 1; + inode->i_mtime = inode->i_atime = CURRENT_TIME; + if (!(inode->i_zone[0]=new_block(inode->i_dev))) { + iput(dir); + inode->i_nlinks--; + iput(inode); + return -ENOSPC; + } + inode->i_dirt = 1; + if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) { + iput(dir); + free_block(inode->i_dev,inode->i_zone[0]); + inode->i_nlinks--; + iput(inode); + return -ERROR; + } + de = (struct dir_entry *) dir_block->b_data; + de->inode=inode->i_num; + strcpy(de->name,"."); + de++; + de->inode = dir->i_num; + strcpy(de->name,".."); + inode->i_nlinks = 2; + dir_block->b_dirt = 1; + brelse(dir_block); + inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask); + inode->i_dirt = 1; + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + iput(dir); + free_block(inode->i_dev,inode->i_zone[0]); + inode->i_nlinks=0; + iput(inode); + return -ENOSPC; + } + de->inode = inode->i_num; + bh->b_dirt = 1; + dir->i_nlinks++; + dir->i_dirt = 1; + iput(dir); + iput(inode); + brelse(bh); + return 0; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +static int empty_dir(struct m_inode * inode) +{ + int nr,block; + int len; + struct buffer_head * bh; + struct dir_entry * de; + + len = inode->i_size / sizeof (struct dir_entry); + if (len<2 || !inode->i_zone[0] || + !(bh=bread(inode->i_dev,inode->i_zone[0]))) { + printk("warning - bad directory on dev %04x\n",inode->i_dev); + return 0; + } + de = (struct dir_entry *) bh->b_data; + if (de[0].inode != inode->i_num || !de[1].inode || + strcmp(".",de[0].name) || strcmp("..",de[1].name)) { + printk("warning - bad directory on dev %04x\n",inode->i_dev); + return 0; + } + nr = 2; + de += 2; + while (nr= (void *) (bh->b_data+BLOCK_SIZE)) { + brelse(bh); + block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK); + if (!block) { + nr += DIR_ENTRIES_PER_BLOCK; + continue; + } + if (!(bh=bread(inode->i_dev,block))) + return 0; + de = (struct dir_entry *) bh->b_data; + } + if (de->inode) { + brelse(bh); + return 0; + } + de++; + nr++; + } + brelse(bh); + return 1; +} + +int sys_rmdir(const char * name) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh; + struct dir_entry * de; + + if (!suser()) + return -EPERM; + if (!(dir = dir_namei(name,&namelen,&basename))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + 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_ISDIR(inode->i_mode)) { + iput(inode); + iput(dir); + brelse(bh); + return -EPERM; + } + /* + * If the directory has the sticky bit, the user must either + * own the file or own the directory or be the superuser to + * delete a file in that directory. This is typically used + * for /tmp and /usr/tmp. + */ + if ((dir->i_mode & S_ISVTX) && (current->euid != inode->i_uid) && + (current->euid != dir->i_uid) && !suser()) { + 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_ISDIR(oldinode->i_mode)) { + iput(oldinode); + return -EPERM; + } + dir = dir_namei(newname,&namelen,&basename); + if (!dir) { + iput(oldinode); + return -EACCES; + } + if (!namelen) { + iput(oldinode); + iput(dir); + return -EPERM; + } + if (dir->i_dev != oldinode->i_dev) { + iput(dir); + iput(oldinode); + return -EXDEV; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + iput(oldinode); + return -EACCES; + } + bh = find_entry(&dir,basename,namelen,&de); + if (bh) { + brelse(bh); + iput(dir); + iput(oldinode); + return -EEXIST; + } + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + iput(dir); + iput(oldinode); + return -ENOSPC; + } + de->inode = oldinode->i_num; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + oldinode->i_nlinks++; + oldinode->i_ctime = CURRENT_TIME; + oldinode->i_dirt = 1; + iput(oldinode); + return 0; +} diff --git a/kernel/0.1x/linux-0.10/fs/open.c b/kernel/0.1x/linux-0.10/fs/open.c new file mode 100644 index 00000000..d043e94a --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/open.c @@ -0,0 +1,208 @@ +/* + * linux/fs/open.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +int sys_ustat(int dev, struct ustat * ubuf) +{ + return -ENOSYS; +} + +int sys_utime(char * filename, struct utimbuf * times) +{ + struct m_inode * inode; + long actime,modtime; + + if (!(inode=namei(filename))) + return -ENOENT; + if (times) { + actime = get_fs_long((unsigned long *) ×->actime); + modtime = get_fs_long((unsigned long *) ×->modtime); + } else + actime = modtime = CURRENT_TIME; + inode->i_atime = actime; + inode->i_mtime = modtime; + inode->i_dirt = 1; + iput(inode); + return 0; +} + +/* + * XXX should we use the real or effective uid? BSD uses the real uid, + * so as to make this call useful to setuid programs. + */ +int sys_access(const char * filename,int mode) +{ + struct m_inode * inode; + int res, i_mode; + + mode &= 0007; + if (!(inode=namei(filename))) + return -EACCES; + i_mode = res = inode->i_mode & 0777; + iput(inode); + if (current->uid == inode->i_uid) + res >>= 6; + else if (current->gid == inode->i_gid) + res >>= 6; + if ((res & 0007 & mode) == mode) + return 0; + /* + * XXX we are doing this test last because we really should be + * swapping the effective with the real user id (temporarily), + * and then calling suser() routine. If we do call the + * suser() routine, it needs to be called last. + */ + if ((!current->uid) && + (!(mode & 1) || (i_mode & 0111))) + return 0; + return -EACCES; +} + +int sys_chdir(const char * filename) +{ + struct m_inode * inode; + + if (!(inode = namei(filename))) + return -ENOENT; + if (!S_ISDIR(inode->i_mode)) { + iput(inode); + return -ENOTDIR; + } + iput(current->pwd); + current->pwd = inode; + return (0); +} + +int sys_chroot(const char * filename) +{ + struct m_inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if (!S_ISDIR(inode->i_mode)) { + iput(inode); + return -ENOTDIR; + } + iput(current->root); + current->root = inode; + return (0); +} + +int sys_chmod(const char * filename,int mode) +{ + struct m_inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if ((current->euid != inode->i_uid) && !suser()) { + iput(inode); + return -EACCES; + } + inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777); + inode->i_dirt = 1; + iput(inode); + return 0; +} + +int sys_chown(const char * filename,int uid,int gid) +{ + struct m_inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if (!suser()) { + iput(inode); + return -EACCES; + } + inode->i_uid=uid; + inode->i_gid=gid; + inode->i_dirt=1; + iput(inode); + return 0; +} + +int sys_open(const char * filename,int flag,int mode) +{ + struct m_inode * inode; + struct file * f; + int i,fd; + + mode &= 0777 & ~current->umask; + for(fd=0 ; fdfilp[fd]) + break; + if (fd>=NR_OPEN) + return -EINVAL; + current->close_on_exec &= ~(1<f_count) break; + if (i>=NR_FILE) + return -EINVAL; + (current->filp[fd]=f)->f_count++; + if ((i=open_namei(filename,flag,mode,&inode))<0) { + current->filp[fd]=NULL; + f->f_count=0; + return i; + } +/* ttys are somewhat special (ttyxx major==4, tty major==5) */ + if (S_ISCHR(inode->i_mode)) + if (MAJOR(inode->i_zone[0])==4) { + if (current->leader && current->tty<0) { + current->tty = MINOR(inode->i_zone[0]); + tty_table[current->tty].pgrp = current->pgrp; + } + } else if (MAJOR(inode->i_zone[0])==5) + if (current->tty<0) { + iput(inode); + current->filp[fd]=NULL; + f->f_count=0; + return -EPERM; + } +/* Likewise with block-devices: check for floppy_change */ + if (S_ISBLK(inode->i_mode)) + check_disk_change(inode->i_zone[0]); + f->f_mode = inode->i_mode; + f->f_flags = flag; + f->f_count = 1; + f->f_inode = inode; + f->f_pos = 0; + return (fd); +} + +int sys_creat(const char * pathname, int mode) +{ + return sys_open(pathname, O_CREAT | O_TRUNC, mode); +} + +int sys_close(unsigned int fd) +{ + struct file * filp; + + if (fd >= NR_OPEN) + return -EINVAL; + current->close_on_exec &= ~(1<filp[fd])) + return -EINVAL; + current->filp[fd] = NULL; + if (filp->f_count == 0) + panic("Close: file count is 0"); + if (--filp->f_count) + return (0); + iput(filp->f_inode); + return (0); +} diff --git a/kernel/0.1x/linux-0.10/fs/pipe.c b/kernel/0.1x/linux-0.10/fs/pipe.c new file mode 100644 index 00000000..93c5d881 --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/pipe.c @@ -0,0 +1,111 @@ +/* + * linux/fs/pipe.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include /* for get_free_page */ +#include + +int read_pipe(struct m_inode * inode, char * buf, int count) +{ + int chars, size, read = 0; + + while (count>0) { + while (!(size=PIPE_SIZE(*inode))) { + wake_up(&inode->i_wait); + if (inode->i_count != 2) /* are there any writers? */ + return read; + sleep_on(&inode->i_wait); + } + chars = PAGE_SIZE-PIPE_TAIL(*inode); + if (chars > count) + chars = count; + if (chars > size) + chars = size; + count -= chars; + read += chars; + size = PIPE_TAIL(*inode); + PIPE_TAIL(*inode) += chars; + PIPE_TAIL(*inode) &= (PAGE_SIZE-1); + while (chars-->0) + put_fs_byte(((char *)inode->i_size)[size++],buf++); + } + wake_up(&inode->i_wait); + return read; +} + +int write_pipe(struct m_inode * inode, char * buf, int count) +{ + int chars, size, written = 0; + + while (count>0) { + while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) { + wake_up(&inode->i_wait); + if (inode->i_count != 2) { /* no readers */ + current->signal |= (1<<(SIGPIPE-1)); + return written?written:-1; + } + sleep_on(&inode->i_wait); + } + chars = PAGE_SIZE-PIPE_HEAD(*inode); + if (chars > count) + chars = count; + if (chars > size) + chars = size; + count -= chars; + written += chars; + size = PIPE_HEAD(*inode); + PIPE_HEAD(*inode) += chars; + PIPE_HEAD(*inode) &= (PAGE_SIZE-1); + while (chars-->0) + ((char *)inode->i_size)[size++]=get_fs_byte(buf++); + } + wake_up(&inode->i_wait); + return written; +} + +int sys_pipe(unsigned long * fildes) +{ + struct m_inode * inode; + struct file * f[2]; + int fd[2]; + int i,j; + + j=0; + for(i=0;j<2 && if_count++; + if (j==1) + f[0]->f_count=0; + if (j<2) + return -1; + j=0; + for(i=0;j<2 && ifilp[i]) { + current->filp[ fd[j]=i ] = f[j]; + j++; + } + if (j==1) + current->filp[fd[0]]=NULL; + if (j<2) { + f[0]->f_count=f[1]->f_count=0; + return -1; + } + if (!(inode=get_pipe_inode())) { + current->filp[fd[0]] = + current->filp[fd[1]] = NULL; + f[0]->f_count = f[1]->f_count = 0; + return -1; + } + f[0]->f_inode = f[1]->f_inode = inode; + f[0]->f_pos = f[1]->f_pos = 0; + f[0]->f_mode = 1; /* read */ + f[1]->f_mode = 2; /* write */ + put_fs_long(fd[0],0+fildes); + put_fs_long(fd[1],1+fildes); + return 0; +} diff --git a/kernel/0.1x/linux-0.10/fs/read_write.c b/kernel/0.1x/linux-0.10/fs/read_write.c new file mode 100644 index 00000000..bab36584 --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/read_write.c @@ -0,0 +1,103 @@ +/* + * linux/fs/read_write.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include +#include + +extern int rw_char(int rw,int dev, char * buf, int count, off_t * pos); +extern int read_pipe(struct m_inode * inode, char * buf, int count); +extern int write_pipe(struct m_inode * inode, char * buf, int count); +extern int block_read(int dev, off_t * pos, char * buf, int count); +extern int block_write(int dev, off_t * pos, char * buf, int count); +extern int file_read(struct m_inode * inode, struct file * filp, + char * buf, int count); +extern int file_write(struct m_inode * inode, struct file * filp, + char * buf, int count); + +int sys_lseek(unsigned int fd,off_t offset, int origin) +{ + struct file * file; + int tmp; + + if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode) + || !IS_SEEKABLE(MAJOR(file->f_inode->i_dev))) + return -EBADF; + if (file->f_inode->i_pipe) + return -ESPIPE; + switch (origin) { + case 0: + if (offset<0) return -EINVAL; + file->f_pos=offset; + break; + case 1: + if (file->f_pos+offset<0) return -EINVAL; + file->f_pos += offset; + break; + case 2: + if ((tmp=file->f_inode->i_size+offset) < 0) + return -EINVAL; + file->f_pos = tmp; + break; + default: + return -EINVAL; + } + return file->f_pos; +} + +int sys_read(unsigned int fd,char * buf,int count) +{ + struct file * file; + struct m_inode * inode; + + if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd])) + return -EINVAL; + if (!count) + return 0; + verify_area(buf,count); + inode = file->f_inode; + if (inode->i_pipe) + return (file->f_mode&1)?read_pipe(inode,buf,count):-1; + if (S_ISCHR(inode->i_mode)) + return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos); + if (S_ISBLK(inode->i_mode)) + return block_read(inode->i_zone[0],&file->f_pos,buf,count); + if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) { + if (count+file->f_pos > inode->i_size) + count = inode->i_size - file->f_pos; + if (count<=0) + return 0; + return file_read(inode,file,buf,count); + } + printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode); + return -EINVAL; +} + +int sys_write(unsigned int fd,char * buf,int count) +{ + struct file * file; + struct m_inode * inode; + + if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd])) + return -EINVAL; + if (!count) + return 0; + inode=file->f_inode; + if (inode->i_pipe) + return (file->f_mode&2)?write_pipe(inode,buf,count):-1; + if (S_ISCHR(inode->i_mode)) + return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos); + if (S_ISBLK(inode->i_mode)) + return block_write(inode->i_zone[0],&file->f_pos,buf,count); + if (S_ISREG(inode->i_mode)) + return file_write(inode,file,buf,count); + printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode); + return -EINVAL; +} diff --git a/kernel/0.1x/linux-0.10/fs/stat.c b/kernel/0.1x/linux-0.10/fs/stat.c new file mode 100644 index 00000000..0ec56c9a --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/stat.c @@ -0,0 +1,56 @@ +/* + * linux/fs/stat.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include + +static void cp_stat(struct m_inode * inode, struct stat * statbuf) +{ + struct stat tmp; + int i; + + verify_area(statbuf,sizeof (* statbuf)); + tmp.st_dev = inode->i_dev; + tmp.st_ino = inode->i_num; + tmp.st_mode = inode->i_mode; + tmp.st_nlink = inode->i_nlinks; + tmp.st_uid = inode->i_uid; + tmp.st_gid = inode->i_gid; + tmp.st_rdev = inode->i_zone[0]; + tmp.st_size = inode->i_size; + tmp.st_atime = inode->i_atime; + tmp.st_mtime = inode->i_mtime; + tmp.st_ctime = inode->i_ctime; + for (i=0 ; i= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode)) + return -EBADF; + cp_stat(inode,statbuf); + return 0; +} diff --git a/kernel/0.1x/linux-0.10/fs/super.c b/kernel/0.1x/linux-0.10/fs/super.c new file mode 100644 index 00000000..7edea1b4 --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/super.c @@ -0,0 +1,280 @@ +/* + * linux/fs/super.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * super.c contains code to handle the super-block tables. + */ +#include +#include +#include +#include + +#include +#include + +int sync_dev(int dev); +void wait_for_keypress(void); + +/* set_bit uses setb, as gas doesn't recognize setc */ +#define set_bit(bitnr,addr) ({ \ +register int __res __asm__("ax"); \ +__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \ +__res; }) + +struct super_block super_block[NR_SUPER]; +/* this is initialized in init/main.c */ +int ROOT_DEV = 0; + +static void lock_super(struct super_block * sb) +{ + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); + sb->s_lock = 1; + sti(); +} + +static void free_super(struct super_block * sb) +{ + cli(); + sb->s_lock = 0; + wake_up(&(sb->s_wait)); + sti(); +} + +static void wait_on_super(struct super_block * sb) +{ + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); + sti(); +} + +struct super_block * get_super(int dev) +{ + struct super_block * s; + + if (!dev) + return NULL; + s = 0+super_block; + while (s < NR_SUPER+super_block) + if (s->s_dev == dev) { + wait_on_super(s); + if (s->s_dev == dev) + return s; + s = 0+super_block; + } else + s++; + return NULL; +} + +void put_super(int dev) +{ + struct super_block * sb; + int i; + + if (dev == ROOT_DEV) { + printk("root diskette changed: prepare for armageddon\n\r"); + return; + } + if (!(sb = get_super(dev))) + return; + if (sb->s_imount) { + printk("Mounted disk changed - tssk, tssk\n\r"); + return; + } + lock_super(sb); + sb->s_dev = 0; + for(i=0;is_imap[i]); + for(i=0;is_zmap[i]); + free_super(sb); + return; +} + +static struct super_block * read_super(int dev) +{ + struct super_block * s; + struct buffer_head * bh; + int i,block; + + if (!dev) + return NULL; + check_disk_change(dev); + if (s = get_super(dev)) + return s; + for (s = 0+super_block ;; s++) { + if (s >= NR_SUPER+super_block) + return NULL; + if (!s->s_dev) + break; + } + s->s_dev = dev; + s->s_isup = NULL; + s->s_imount = NULL; + s->s_time = 0; + s->s_rd_only = 0; + s->s_dirt = 0; + lock_super(s); + if (!(bh = bread(dev,1))) { + s->s_dev=0; + free_super(s); + return NULL; + } + *((struct d_super_block *) s) = + *((struct d_super_block *) bh->b_data); + brelse(bh); + if (s->s_magic != SUPER_MAGIC) { + s->s_dev = 0; + free_super(s); + return NULL; + } + for (i=0;is_imap[i] = NULL; + for (i=0;is_zmap[i] = NULL; + block=2; + for (i=0 ; i < s->s_imap_blocks ; i++) + if (s->s_imap[i]=bread(dev,block)) + block++; + else + break; + for (i=0 ; i < s->s_zmap_blocks ; i++) + if (s->s_zmap[i]=bread(dev,block)) + block++; + else + break; + if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) { + for(i=0;is_imap[i]); + for(i=0;is_zmap[i]); + s->s_dev=0; + free_super(s); + return NULL; + } + s->s_imap[0]->b_data[0] |= 1; + s->s_zmap[0]->b_data[0] |= 1; + free_super(s); + return s; +} + +int sys_umount(char * dev_name) +{ + struct m_inode * inode; + struct super_block * sb; + int dev; + + if (!(inode=namei(dev_name))) + return -ENOENT; + dev = inode->i_zone[0]; + if (!S_ISBLK(inode->i_mode)) { + iput(inode); + return -ENOTBLK; + } + iput(inode); + if (dev==ROOT_DEV) + return -EBUSY; + if (!(sb=get_super(dev)) || !(sb->s_imount)) + return -ENOENT; + if (!sb->s_imount->i_mount) + printk("Mounted inode has i_mount=0\n"); + for(inode=inode_table+0 ; inodei_dev==dev && inode->i_count) + return -EBUSY; + sb->s_imount->i_mount=0; + iput(sb->s_imount); + sb->s_imount = NULL; + iput(sb->s_isup); + sb->s_isup = NULL; + put_super(dev); + sync_dev(dev); + return 0; +} + +int sys_mount(char * dev_name, char * dir_name, int rw_flag) +{ + struct m_inode * dev_i, * dir_i; + struct super_block * sb; + int dev; + + if (!(dev_i=namei(dev_name))) + return -ENOENT; + dev = dev_i->i_zone[0]; + if (!S_ISBLK(dev_i->i_mode)) { + iput(dev_i); + return -EPERM; + } + iput(dev_i); + if (!(dir_i=namei(dir_name))) + return -ENOENT; + if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) { + iput(dir_i); + return -EBUSY; + } + if (!S_ISDIR(dir_i->i_mode)) { + iput(dir_i); + return -EPERM; + } + if (!(sb=read_super(dev))) { + iput(dir_i); + return -EBUSY; + } + if (sb->s_imount) { + iput(dir_i); + return -EBUSY; + } + if (dir_i->i_mount) { + iput(dir_i); + return -EPERM; + } + sb->s_imount=dir_i; + dir_i->i_mount=1; + dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */ + return 0; /* we do that in umount */ +} + +void mount_root(void) +{ + int i,free; + struct super_block * p; + struct m_inode * mi; + + if (32 != sizeof (struct d_inode)) + panic("bad i-node size"); + for(i=0;is_dev = 0; + p->s_lock = 0; + p->s_wait = NULL; + } + if (!(p=read_super(ROOT_DEV))) + panic("Unable to mount root"); + if (!(mi=iget(ROOT_DEV,ROOT_INO))) + panic("Unable to read root i-node"); + mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ + p->s_isup = p->s_imount = mi; + current->pwd = mi; + current->root = mi; + free=0; + i=p->s_nzones; + while (-- i >= 0) + if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data)) + free++; + printk("%d/%d free blocks\n\r",free,p->s_nzones); + free=0; + i=p->s_ninodes+1; + while (-- i >= 0) + if (!set_bit(i&8191,p->s_imap[i>>13]->b_data)) + free++; + printk("%d/%d free inodes\n\r",free,p->s_ninodes); +} diff --git a/kernel/0.1x/linux-0.10/fs/truncate.c b/kernel/0.1x/linux-0.10/fs/truncate.c new file mode 100644 index 00000000..769e1090 --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/truncate.c @@ -0,0 +1,65 @@ +/* + * linux/fs/truncate.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include + +static void free_ind(int dev,int block) +{ + struct buffer_head * bh; + unsigned short * p; + int i; + + if (!block) + return; + if (bh=bread(dev,block)) { + p = (unsigned short *) bh->b_data; + for (i=0;i<512;i++,p++) + if (*p) + free_block(dev,*p); + brelse(bh); + } + free_block(dev,block); +} + +static void free_dind(int dev,int block) +{ + struct buffer_head * bh; + unsigned short * p; + int i; + + if (!block) + return; + if (bh=bread(dev,block)) { + p = (unsigned short *) bh->b_data; + for (i=0;i<512;i++,p++) + if (*p) + free_ind(dev,*p); + brelse(bh); + } + free_block(dev,block); +} + +void truncate(struct m_inode * inode) +{ + int i; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) + return; + for (i=0;i<7;i++) + if (inode->i_zone[i]) { + free_block(inode->i_dev,inode->i_zone[i]); + inode->i_zone[i]=0; + } + free_ind(inode->i_dev,inode->i_zone[7]); + free_dind(inode->i_dev,inode->i_zone[8]); + inode->i_zone[7] = inode->i_zone[8] = 0; + inode->i_size = 0; + inode->i_dirt = 1; + inode->i_mtime = inode->i_ctime = CURRENT_TIME; +} + diff --git a/kernel/0.1x/linux-0.10/fs/tty_ioctl.c b/kernel/0.1x/linux-0.10/fs/tty_ioctl.c new file mode 100644 index 00000000..2bf510c8 --- /dev/null +++ b/kernel/0.1x/linux-0.10/fs/tty_ioctl.c @@ -0,0 +1,175 @@ +/* + * linux/fs/tty_ioctl.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include + +#include +#include + +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; +} + +/* + * This only works as the 386 is low-byt-first + */ +static int set_termio(struct tty_struct * tty, struct termio * termio) +{ + int i; + struct termio tmp_termio; + + for (i=0 ; i< (sizeof (*termio)) ; i++) + ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio); + *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag; + *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag; + *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag; + *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag; + tty->termios.c_line = tmp_termio.c_line; + for(i=0 ; i < NCC ; i++) + tty->termios.c_cc[i] = tmp_termio.c_cc[i]; + 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/kernel/0.1x/linux-0.10/include/a.out.h b/kernel/0.1x/linux-0.10/include/a.out.h new file mode 100644 index 00000000..2f5f3dcd --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/asm/io.h b/kernel/0.1x/linux-0.10/include/asm/io.h new file mode 100644 index 00000000..53646abc --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/asm/memory.h b/kernel/0.1x/linux-0.10/include/asm/memory.h new file mode 100644 index 00000000..dba1062f --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/asm/segment.h b/kernel/0.1x/linux-0.10/include/asm/segment.h new file mode 100644 index 00000000..69419d45 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/asm/segment.h @@ -0,0 +1,65 @@ +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)); +} + +/* + * Someone who knows GNU asm better than I should double check the followig. + * It seems to work, but I don't know if I'm doing something subtly wrong. + * --- TYT, 11/24/91 + */ + +extern inline unsigned long get_fs() +{ + unsigned short _v; + __asm__("mov %%fs,%%ax":"=a" (_v):); + return _v; +} + +extern inline unsigned long get_ds() +{ + unsigned short _v; + __asm__("mov %%ds,%%ax":"=a" (_v):); + return _v; +} + +extern inline void set_fs(unsigned long val) +{ + __asm__("mov %0,%%fs"::"a" ((unsigned short) val)); +} + + diff --git a/kernel/0.1x/linux-0.10/include/asm/system.h b/kernel/0.1x/linux-0.10/include/asm/system.h new file mode 100644 index 00000000..231c8f34 --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/const.h b/kernel/0.1x/linux-0.10/include/const.h new file mode 100644 index 00000000..88e96416 --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/ctype.h b/kernel/0.1x/linux-0.10/include/ctype.h new file mode 100644 index 00000000..83338bbc --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/errno.h b/kernel/0.1x/linux-0.10/include/errno.h new file mode 100644 index 00000000..18f2aaf6 --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/fcntl.h b/kernel/0.1x/linux-0.10/include/fcntl.h new file mode 100644 index 00000000..d339b5e7 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/fcntl.h @@ -0,0 +1,55 @@ +#ifndef _FCNTL_H +#define _FCNTL_H + +#include + +/* open/fcntl - NOCTTY, NDELAY isn't implemented yet */ +#define O_ACCMODE 00003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 00100 /* not fcntl */ +#define O_EXCL 00200 /* not fcntl */ +#define O_NOCTTY 00400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 /* not fcntl */ +#define O_NDELAY O_NONBLOCK + +/* Defines for fcntl-commands. Note that currently + * locking isn't supported, and other things aren't really + * tested. + */ +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get f_flags */ +#define F_SETFD 2 /* set f_flags */ +#define F_GETFL 3 /* more flags (cloexec) */ +#define F_SETFL 4 +#define F_GETLK 5 /* not implemented */ +#define F_SETLK 6 +#define F_SETLKW 7 + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* Ok, these are locking features, and aren't implemented at any + * level. POSIX wants them. + */ +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +/* Once again - not implemented, but ... */ +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +extern int creat(const char * filename,mode_t mode); +extern int fcntl(int fildes,int cmd, ...); +extern int open(const char * filename, int flags, ...); + +#endif diff --git a/kernel/0.1x/linux-0.10/include/linux/config.h b/kernel/0.1x/linux-0.10/include/linux/config.h new file mode 100644 index 00000000..1aedc561 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/linux/config.h @@ -0,0 +1,40 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +/* + * The root-device is no longer hard-coded. You can change the default + * root-device by changing the line ROOT_DEV = XXX in boot/bootsect.s + */ + +/* define your keyboard here - US (KBD_US) or Finnish (KBD_FINNISH) */ +#define KBD_US +/* #define KBD_FINNISH */ + +/* + * Normally, Linux can get the drive parameters from the BIOS at + * startup, but if this for some unfathomable reason fails, you'd + * be left stranded. For this case, you can define HD_TYPE, which + * contains all necessary info on your harddisk. + * + * The HD_TYPE macro should look like this: + * + * #define HD_TYPE { head, sect, cyl, wpcom, lzone, ctl} + * + * In case of two harddisks, the info should be sepatated by + * commas: + * + * #define HD_TYPE { h,s,c,wpcom,lz,ctl },{ h,s,c,wpcom,lz,ctl } + */ +/* + This is an example, two drives, first is type 2, second is type 3: + +#define HD_TYPE { 4,17,615,300,615,8 }, { 6,17,615,300,615,0 } + + NOTE: ctl is 0 for all drives with heads<=8, and ctl=8 for drives + with more than 8 heads. + + If you want the BIOS to tell what kind of drive you have, just + leave HD_TYPE undefined. +*/ + +#endif diff --git a/kernel/0.1x/linux-0.10/include/linux/fdreg.h b/kernel/0.1x/linux-0.10/include/linux/fdreg.h new file mode 100644 index 00000000..61f4da90 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/linux/fdreg.h @@ -0,0 +1,71 @@ +/* + * This file contains some defines for the floppy disk controller. + * Various sources. Mostly "IBM Microcomputers: A Programmers + * Handbook", Sanches and Canton. + */ +#ifndef _FDREG_H +#define _FDREG_H + +extern int ticks_to_floppy_on(unsigned int nr); +extern void floppy_on(unsigned int nr); +extern void floppy_off(unsigned int nr); +extern void floppy_select(unsigned int nr); +extern void floppy_deselect(unsigned int nr); + +/* Fd controller regs. S&C, about page 340 */ +#define FD_STATUS 0x3f4 +#define FD_DATA 0x3f5 +#define FD_DOR 0x3f2 /* Digital Output Register */ +#define FD_DIR 0x3f7 /* Digital Input Register (read) */ +#define FD_DCR 0x3f7 /* Diskette Control Register (write)*/ + +/* Bits of main status register */ +#define STATUS_BUSYMASK 0x0F /* drive busy mask */ +#define STATUS_BUSY 0x10 /* FDC busy */ +#define STATUS_DMA 0x20 /* 0- DMA mode */ +#define STATUS_DIR 0x40 /* 0- cpu->fdc */ +#define STATUS_READY 0x80 /* Data reg ready */ + +/* Bits of FD_ST0 */ +#define ST0_DS 0x03 /* drive select mask */ +#define ST0_HA 0x04 /* Head (Address) */ +#define ST0_NR 0x08 /* Not Ready */ +#define ST0_ECE 0x10 /* Equipment chech error */ +#define ST0_SE 0x20 /* Seek end */ +#define ST0_INTR 0xC0 /* Interrupt code mask */ + +/* Bits of FD_ST1 */ +#define ST1_MAM 0x01 /* Missing Address Mark */ +#define ST1_WP 0x02 /* Write Protect */ +#define ST1_ND 0x04 /* No Data - unreadable */ +#define ST1_OR 0x10 /* OverRun */ +#define ST1_CRC 0x20 /* CRC error in data or addr */ +#define ST1_EOC 0x80 /* End Of Cylinder */ + +/* Bits of FD_ST2 */ +#define ST2_MAM 0x01 /* Missing Addess Mark (again) */ +#define ST2_BC 0x02 /* Bad Cylinder */ +#define ST2_SNS 0x04 /* Scan Not Satisfied */ +#define ST2_SEH 0x08 /* Scan Equal Hit */ +#define ST2_WC 0x10 /* Wrong Cylinder */ +#define ST2_CRC 0x20 /* CRC error in data field */ +#define ST2_CM 0x40 /* Control Mark = deleted */ + +/* Bits of FD_ST3 */ +#define ST3_HA 0x04 /* Head (Address) */ +#define ST3_TZ 0x10 /* Track Zero signal (1=track 0) */ +#define ST3_WP 0x40 /* Write Protect */ + +/* Values for FD_COMMAND */ +#define FD_RECALIBRATE 0x07 /* move to track 0 */ +#define FD_SEEK 0x0F /* seek track */ +#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */ +#define FD_WRITE 0xC5 /* write with MT, MFM */ +#define FD_SENSEI 0x08 /* Sense Interrupt Status */ +#define FD_SPECIFY 0x03 /* specify HUT etc */ + +/* DMA commands */ +#define DMA_READ 0x46 +#define DMA_WRITE 0x4A + +#endif diff --git a/kernel/0.1x/linux-0.10/include/linux/fs.h b/kernel/0.1x/linux-0.10/include/linux/fs.h new file mode 100644 index 00000000..a4e4cfe3 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/linux/fs.h @@ -0,0 +1,200 @@ +/* + * This file has definitions for some important file table + * structures etc. + */ + +#ifndef _FS_H +#define _FS_H + +#include + +/* devices are as follows: (same as minix, so we can use the minix + * file system. These are major numbers.) + * + * 0 - unused (nodev) + * 1 - /dev/mem + * 2 - /dev/fd + * 3 - /dev/hd + * 4 - /dev/ttyx + * 5 - /dev/tty + * 6 - /dev/lp + * 7 - unnamed pipes + */ + +#define IS_SEEKABLE(x) ((x)>=1 && (x)<=3) + +#define READ 0 +#define WRITE 1 +#define READA 2 /* read-ahead - don't pause */ + +void buffer_init(long buffer_end); + +#define MAJOR(a) (((unsigned)(a))>>8) +#define MINOR(a) ((a)&0xff) + +#define NAME_LEN 14 +#define ROOT_INO 1 + +#define I_MAP_SLOTS 8 +#define Z_MAP_SLOTS 8 +#define SUPER_MAGIC 0x137F + +#define NR_OPEN 20 +#define NR_INODE 32 +#define NR_FILE 64 +#define NR_SUPER 8 +#define NR_HASH 307 +#define NR_BUFFERS nr_buffers +#define BLOCK_SIZE 1024 +#define BLOCK_SIZE_BITS 10 +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#define INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct d_inode))) +#define DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct dir_entry))) + +#define PIPE_HEAD(inode) ((inode).i_zone[0]) +#define PIPE_TAIL(inode) ((inode).i_zone[1]) +#define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1)) +#define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode)) +#define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1)) +#define INC_PIPE(head) \ +__asm__("incl %0\n\tandl $4095,%0"::"m" (head)) + +typedef char buffer_block[BLOCK_SIZE]; + +struct buffer_head { + char * b_data; /* pointer to data block (1024 bytes) */ + unsigned 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; +}; + +struct file { + unsigned short f_mode; + unsigned short f_flags; + unsigned short f_count; + struct m_inode * f_inode; + off_t f_pos; +}; + +struct super_block { + unsigned short s_ninodes; + unsigned short s_nzones; + unsigned short s_imap_blocks; + unsigned short s_zmap_blocks; + unsigned short s_firstdatazone; + unsigned short s_log_zone_size; + unsigned long s_max_size; + unsigned short s_magic; +/* These are only in memory */ + struct buffer_head * s_imap[8]; + struct buffer_head * s_zmap[8]; + unsigned short s_dev; + struct m_inode * s_isup; + struct m_inode * s_imount; + unsigned long s_time; + struct task_struct * s_wait; + unsigned char s_lock; + unsigned char s_rd_only; + unsigned char s_dirt; +}; + +struct d_super_block { + unsigned short s_ninodes; + unsigned short s_nzones; + unsigned short s_imap_blocks; + unsigned short s_zmap_blocks; + unsigned short s_firstdatazone; + unsigned short s_log_zone_size; + unsigned long s_max_size; + unsigned short s_magic; +}; + +struct dir_entry { + unsigned short inode; + char name[NAME_LEN]; +}; + +extern struct m_inode inode_table[NR_INODE]; +extern struct file file_table[NR_FILE]; +extern struct super_block super_block[NR_SUPER]; +extern struct buffer_head * start_buffer; +extern int nr_buffers; + +extern void check_disk_change(int dev); +extern int floppy_change(unsigned int nr); +extern int ticks_to_floppy_on(unsigned int dev); +extern void floppy_on(unsigned int dev); +extern void floppy_off(unsigned int dev); +extern void truncate(struct m_inode * inode); +extern void sync_inodes(void); +extern void wait_on(struct m_inode * inode); +extern int bmap(struct m_inode * inode,int block); +extern int create_block(struct m_inode * inode,int block); +extern struct m_inode * namei(const char * pathname); +extern int open_namei(const char * pathname, int flag, int mode, + struct m_inode ** res_inode); +extern void iput(struct m_inode * inode); +extern struct m_inode * iget(int dev,int nr); +extern struct m_inode * get_empty_inode(void); +extern struct m_inode * get_pipe_inode(void); +extern struct buffer_head * get_hash_table(int dev, int block); +extern struct buffer_head * getblk(int dev, int block); +extern void ll_rw_block(int rw, struct buffer_head * bh); +extern void brelse(struct buffer_head * buf); +extern struct buffer_head * bread(int dev,int block); +extern struct buffer_head * breada(int dev,int block,...); +extern int new_block(int dev); +extern void free_block(int dev, int block); +extern struct m_inode * new_inode(int dev); +extern void free_inode(struct m_inode * inode); +extern int sync_dev(int dev); +extern struct super_block * get_super(int dev); +extern int ROOT_DEV; + +extern void mount_root(void); + +#endif diff --git a/kernel/0.1x/linux-0.10/include/linux/hdreg.h b/kernel/0.1x/linux-0.10/include/linux/hdreg.h new file mode 100644 index 00000000..202db422 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/linux/hdreg.h @@ -0,0 +1,65 @@ +/* + * This file contains some defines for the AT-hd-controller. + * Various sources. Check out some definitions (see comments with + * a ques). + */ +#ifndef _HDREG_H +#define _HDREG_H + +/* Hd controller regs. Ref: IBM AT Bios-listing */ +#define HD_DATA 0x1f0 /* _CTL when writing */ +#define HD_ERROR 0x1f1 /* see err-bits */ +#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */ +#define HD_SECTOR 0x1f3 /* starting sector */ +#define HD_LCYL 0x1f4 /* starting cylinder */ +#define HD_HCYL 0x1f5 /* high byte of starting cyl */ +#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */ +#define HD_STATUS 0x1f7 /* see status-bits */ +#define HD_PRECOMP HD_ERROR /* same io address, read=error, write=precomp */ +#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */ + +#define HD_CMD 0x3f6 + +/* Bits of HD_STATUS */ +#define ERR_STAT 0x01 +#define INDEX_STAT 0x02 +#define ECC_STAT 0x04 /* Corrected error */ +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Values for HD_COMMAND */ +#define WIN_RESTORE 0x10 +#define WIN_READ 0x20 +#define WIN_WRITE 0x30 +#define WIN_VERIFY 0x40 +#define WIN_FORMAT 0x50 +#define WIN_INIT 0x60 +#define WIN_SEEK 0x70 +#define WIN_DIAGNOSE 0x90 +#define WIN_SPECIFY 0x91 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark ? */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* ? */ +#define ID_ERR 0x10 /* ? */ +#define ECC_ERR 0x40 /* ? */ +#define BBD_ERR 0x80 /* ? */ + +struct partition { + unsigned char boot_ind; /* 0x80 - active (unused) */ + unsigned char head; /* ? */ + unsigned char sector; /* ? */ + unsigned char cyl; /* ? */ + unsigned char sys_ind; /* ? */ + unsigned char end_head; /* ? */ + unsigned char end_sector; /* ? */ + unsigned char end_cyl; /* ? */ + unsigned int start_sect; /* starting sector counting from 0 */ + unsigned int nr_sects; /* nr of sectors in partition */ +}; + +#endif diff --git a/kernel/0.1x/linux-0.10/include/linux/head.h b/kernel/0.1x/linux-0.10/include/linux/head.h new file mode 100644 index 00000000..f5468a0e --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/linux/kernel.h b/kernel/0.1x/linux-0.10/include/linux/kernel.h new file mode 100644 index 00000000..81eade46 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/linux/kernel.h @@ -0,0 +1,21 @@ +/* + * 'kernel.h' contains some often-used function prototypes etc + */ +void verify_area(void * addr,int count); +volatile void panic(const char * str); +int printf(const char * fmt, ...); +int printk(const char * fmt, ...); +int tty_write(unsigned ch,char * buf,int count); +void *malloc(unsigned int len); +void free_s(void *obj, int size); + +#define free(x) free_s((x), 0) + +/* + * This is defined as a macro, but at some point this might become a + * real subroutine that sets a flag if it returns true (to do + * BSD-style accounting where the process is flagged if it uses root + * privs). The implication of this is that you should do normal + * permissions checks first, and check suser() last. + */ +#define suser() (current->euid == 0) diff --git a/kernel/0.1x/linux-0.10/include/linux/mm.h b/kernel/0.1x/linux-0.10/include/linux/mm.h new file mode 100644 index 00000000..e13acb32 --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/linux/sched.h b/kernel/0.1x/linux-0.10/include/linux/sched.h new file mode 100644 index 00000000..2b772387 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/linux/sched.h @@ -0,0 +1,232 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#define NR_TASKS 64 +#define HZ 100 + +#define FIRST_TASK task[0] +#define LAST_TASK task[NR_TASKS-1] + +#include +#include +#include +#include + +#if (NR_OPEN > 32) +#error "Currently the close-on-exec-flags are in one word, max 32 files/proc" +#endif + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_ZOMBIE 3 +#define TASK_STOPPED 4 + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +extern int copy_page_tables(unsigned long from, unsigned long to, long size); +extern int free_page_tables(unsigned long from, long size); + +extern void sched_init(void); +extern void schedule(void); +extern void trap_init(void); +extern void panic(const char * str); +extern int tty_write(unsigned minor,char * buf,int count); + +typedef int (*fn_ptr)(); + +struct i387_struct { + long cwd; + long swd; + long twd; + long fip; + long fcs; + long foo; + long fos; + long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ +}; + +struct tss_struct { + long back_link; /* 16 high bits zero */ + long esp0; + long ss0; /* 16 high bits zero */ + long esp1; + long ss1; /* 16 high bits zero */ + long esp2; + long ss2; /* 16 high bits zero */ + long cr3; + long eip; + long eflags; + long eax,ecx,edx,ebx; + long esp; + long ebp; + long esi; + long edi; + long es; /* 16 high bits zero */ + long cs; /* 16 high bits zero */ + long ss; /* 16 high bits zero */ + long ds; /* 16 high bits zero */ + long fs; /* 16 high bits zero */ + long gs; /* 16 high bits zero */ + long ldt; /* 16 high bits zero */ + long trace_bitmap; /* bits: trace 0, bitmap 16-31 */ + struct i387_struct i387; +}; + +struct task_struct { +/* these are hardcoded - don't touch */ + long state; /* -1 unrunnable, 0 runnable, >0 stopped */ + long counter; + long priority; + long signal; + struct sigaction sigaction[32]; + long blocked; /* bitmap of masked signals */ +/* various fields */ + int exit_code; + unsigned long 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,{{},},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,0022,NULL,NULL,0, \ +/* filp */ {NULL,}, \ + { \ + {0,0}, \ +/* ldt */ {0x9f,0xc0fa00}, \ + {0x9f,0xc0f200}, \ + }, \ +/*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\ + 0,0,0,0,0,0,0,0, \ + 0,0,0x17,0x17,0x17,0x17,0x17,0x17, \ + _LDT(0),0x80000000, \ + {} \ + }, \ +} + +extern struct task_struct *task[NR_TASKS]; +extern struct task_struct *last_task_used_math; +extern struct task_struct *current; +extern long volatile jiffies; +extern long startup_time; + +#define CURRENT_TIME (startup_time+jiffies/HZ) + +extern void add_timer(long jiffies, void (*fn)(void)); +extern void sleep_on(struct task_struct ** p); +extern void interruptible_sleep_on(struct task_struct ** p); +extern void wake_up(struct task_struct ** p); + +/* + * Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall + * 4-TSS0, 5-LDT0, 6-TSS1 etc ... + */ +#define FIRST_TSS_ENTRY 4 +#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1) +#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3)) +#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3)) +#define ltr(n) __asm__("ltr %%ax"::"a" (_TSS(n))) +#define lldt(n) __asm__("lldt %%ax"::"a" (_LDT(n))) +#define str(n) \ +__asm__("str %%ax\n\t" \ + "subl %2,%%eax\n\t" \ + "shrl $4,%%eax" \ + :"=a" (n) \ + :"a" (0),"i" (FIRST_TSS_ENTRY<<3)) +/* + * switch_to(n) should switch tasks to task nr n, first + * checking that n isn't the current task, in which case it does nothing. + * This also clears the TS-flag if the task we switched to has used + * tha math co-processor latest. + */ +#define switch_to(n) {\ +struct {long a,b;} __tmp; \ +__asm__("cmpl %%ecx,_current\n\t" \ + "je 1f\n\t" \ + "movw %%dx,%1\n\t" \ + "xchgl %%ecx,_current\n\t" \ + "ljmp %0\n\t" \ + "cmpl %%ecx,_last_task_used_math\n\t" \ + "jne 1f\n\t" \ + "clts\n" \ + "1:" \ + ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ + "d" (_TSS(n)),"c" ((long) task[n])); \ +} + +#define PAGE_ALIGN(n) (((n)+0xfff)&0xfffff000) + +#define _set_base(addr,base) \ +__asm__("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/kernel/0.1x/linux-0.10/include/linux/sys.h b/kernel/0.1x/linux-0.10/include/linux/sys.h new file mode 100644 index 00000000..51ac075b --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/linux/sys.h @@ -0,0 +1,83 @@ +extern int sys_setup(); +extern int sys_exit(); +extern int sys_fork(); +extern int sys_read(); +extern int sys_write(); +extern int sys_open(); +extern int sys_close(); +extern int sys_waitpid(); +extern int sys_creat(); +extern int sys_link(); +extern int sys_unlink(); +extern int sys_execve(); +extern int sys_chdir(); +extern int sys_time(); +extern int sys_mknod(); +extern int sys_chmod(); +extern int sys_chown(); +extern int sys_break(); +extern int sys_stat(); +extern int sys_lseek(); +extern int sys_getpid(); +extern int sys_mount(); +extern int sys_umount(); +extern int sys_setuid(); +extern int sys_getuid(); +extern int sys_stime(); +extern int sys_ptrace(); +extern int sys_alarm(); +extern int sys_fstat(); +extern int sys_pause(); +extern int sys_utime(); +extern int sys_stty(); +extern int sys_gtty(); +extern int sys_access(); +extern int sys_nice(); +extern int sys_ftime(); +extern int sys_sync(); +extern int sys_kill(); +extern int sys_rename(); +extern int sys_mkdir(); +extern int sys_rmdir(); +extern int sys_dup(); +extern int sys_pipe(); +extern int sys_times(); +extern int sys_prof(); +extern int sys_brk(); +extern int sys_setgid(); +extern int sys_getgid(); +extern int sys_signal(); +extern int sys_geteuid(); +extern int sys_getegid(); +extern int sys_acct(); +extern int sys_phys(); +extern int sys_lock(); +extern int sys_ioctl(); +extern int sys_fcntl(); +extern int sys_mpx(); +extern int sys_setpgid(); +extern int sys_ulimit(); +extern int sys_uname(); +extern int sys_umask(); +extern int sys_chroot(); +extern int sys_ustat(); +extern int sys_dup2(); +extern int sys_getppid(); +extern int sys_getpgrp(); +extern int sys_setsid(); +extern int sys_sigaction(); +extern int sys_sgetmask(); +extern int sys_ssetmask(); + +fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read, +sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link, +sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod, +sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount, +sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm, +sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access, +sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir, +sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid, +sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys, +sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit, +sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid, +sys_getpgrp,sys_setsid,sys_sigaction,sys_sgetmask,sys_ssetmask }; diff --git a/kernel/0.1x/linux-0.10/include/linux/tty.h b/kernel/0.1x/linux-0.10/include/linux/tty.h new file mode 100644 index 00000000..bc665440 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/linux/tty.h @@ -0,0 +1,77 @@ +/* + * 'tty.h' defines some structures used by tty_io.c and some defines. + * + * NOTE! Don't touch this without checking that nothing in rs_io.s or + * con_io.s breaks. Some constants are hardwired into the system (mainly + * offsets into 'tty_queue' + */ + +#ifndef _TTY_H +#define _TTY_H + +#include + +#define TTY_BUF_SIZE 1024 + +struct tty_queue { + unsigned long data; + unsigned long head; + unsigned long tail; + struct task_struct * proc_list; + char buf[TTY_BUF_SIZE]; +}; + +#define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1)) +#define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1)) +#define EMPTY(a) ((a).head == (a).tail) +#define LEFT(a) (((a).tail-(a).head-1)&(TTY_BUF_SIZE-1)) +#define LAST(a) ((a).buf[(TTY_BUF_SIZE-1)&((a).head-1)]) +#define FULL(a) (!LEFT(a)) +#define CHARS(a) (((a).head-(a).tail)&(TTY_BUF_SIZE-1)) +#define GETCH(queue,c) \ +(void)({c=(queue).buf[(queue).tail];INC((queue).tail);}) +#define PUTCH(c,queue) \ +(void)({(queue).buf[(queue).head]=(c);INC((queue).head);}) + +#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR]) +#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT]) +#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE]) +#define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL]) +#define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF]) +#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART]) +#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP]) +#define SUSPEND_CHAR(tty) ((tty)->termios.c_cc[VSUSP]) + +struct tty_struct { + struct termios termios; + int pgrp; + int stopped; + void (*write)(struct tty_struct * tty); + struct tty_queue read_q; + struct tty_queue write_q; + struct tty_queue secondary; + }; + +extern struct tty_struct tty_table[]; + +/* intr=^C quit=^| erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" + +void rs_init(void); +void con_init(void); +void tty_init(void); + +int tty_read(unsigned c, char * buf, int n); +int tty_write(unsigned c, char * buf, int n); + +void rs_write(struct tty_struct * tty); +void con_write(struct tty_struct * tty); + +void copy_to_cooked(struct tty_struct * tty); + +#endif diff --git a/kernel/0.1x/linux-0.10/include/signal.h b/kernel/0.1x/linux-0.10/include/signal.h new file mode 100644 index 00000000..b6ba6056 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/signal.h @@ -0,0 +1,68 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include + +typedef int sig_atomic_t; +typedef unsigned int sigset_t; /* 32 bits */ + +#define _NSIG 32 +#define NSIG _NSIG + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGUNUSED 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 + +/* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */ +#define SA_NOCLDSTOP 1 +#define SA_NOMASK 0x40000000 +#define SA_ONESHOT 0x80000000 + +#define SIG_BLOCK 0 /* for blocking signals */ +#define SIG_UNBLOCK 1 /* for unblocking signals */ +#define SIG_SETMASK 2 /* for setting the signal mask */ + +#define SIG_DFL ((void (*)(int))0) /* default signal handling */ +#define SIG_IGN ((void (*)(int))1) /* ignore signal */ + +struct sigaction { + void (*sa_handler)(int); + sigset_t sa_mask; + int sa_flags; + void (*sa_restorer)(void); +}; + +void (*signal(int _sig, void (*_func)(int)))(int); +int raise(int sig); +int kill(pid_t pid, int sig); +int sigaddset(sigset_t *mask, int signo); +int sigdelset(sigset_t *mask, int signo); +int sigemptyset(sigset_t *mask); +int sigfillset(sigset_t *mask); +int sigismember(sigset_t *mask, int signo); /* 1 - is, 0 - not, -1 error */ +int sigpending(sigset_t *set); +int sigprocmask(int how, sigset_t *set, sigset_t *oldset); +int sigsuspend(sigset_t *sigmask); +int sigaction(int sig, struct sigaction *act, struct sigaction *oldact); + +#endif /* _SIGNAL_H */ diff --git a/kernel/0.1x/linux-0.10/include/stdarg.h b/kernel/0.1x/linux-0.10/include/stdarg.h new file mode 100644 index 00000000..0126a7cf --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/stddef.h b/kernel/0.1x/linux-0.10/include/stddef.h new file mode 100644 index 00000000..41957264 --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/string.h b/kernel/0.1x/linux-0.10/include/string.h new file mode 100644 index 00000000..f06f6139 --- /dev/null +++ b/kernel/0.1x/linux-0.10/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 + +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/kernel/0.1x/linux-0.10/include/sys/times.h b/kernel/0.1x/linux-0.10/include/sys/times.h new file mode 100644 index 00000000..aa78d000 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/sys/times.h @@ -0,0 +1,15 @@ +#ifndef _TIMES_H +#define _TIMES_H + +#include + +struct tms { + time_t tms_utime; + time_t tms_stime; + time_t tms_cutime; + time_t tms_cstime; +}; + +extern time_t times(struct tms * tp); + +#endif diff --git a/kernel/0.1x/linux-0.10/include/sys/types.h b/kernel/0.1x/linux-0.10/include/sys/types.h new file mode 100644 index 00000000..89c03d97 --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/sys/utsname.h b/kernel/0.1x/linux-0.10/include/sys/utsname.h new file mode 100644 index 00000000..9c6aa5c5 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/sys/utsname.h @@ -0,0 +1,16 @@ +#ifndef _SYS_UTSNAME_H +#define _SYS_UTSNAME_H + +#include + +struct utsname { + char sysname[9]; + char nodename[9]; + char release[9]; + char version[9]; + char machine[9]; +}; + +extern int uname(struct utsname * utsbuf); + +#endif diff --git a/kernel/0.1x/linux-0.10/include/sys/wait.h b/kernel/0.1x/linux-0.10/include/sys/wait.h new file mode 100644 index 00000000..88414fcf --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/sys/wait.h @@ -0,0 +1,23 @@ +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include + +#define _LOW(v) ( (v) & 0377) +#define _HIGH(v) ( ((v) >> 8) & 0377) + +/* options for waitpid, WUNTRACED not supported */ +#define WNOHANG 1 +#define WUNTRACED 2 + +#define WIFEXITED(s) (!((s)&0xFF) +#define WIFSTOPPED(s) (((s)&0xFF)==0x7F) +#define WEXITSTATUS(s) (((s)>>8)&0xFF) +#define WTERMSIG(s) ((s)&0x7F) +#define WSTOPSIG(s) (((s)>>8)&0xFF) +#define WIFSIGNALED(s) (((unsigned int)(s)-1 & 0xFFFF) < 0xFF) + +pid_t wait(int *stat_loc); +pid_t waitpid(pid_t pid, int *stat_loc, int options); + +#endif diff --git a/kernel/0.1x/linux-0.10/include/termios.h b/kernel/0.1x/linux-0.10/include/termios.h new file mode 100644 index 00000000..cb3797f7 --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/time.h b/kernel/0.1x/linux-0.10/include/time.h new file mode 100644 index 00000000..f4368ad7 --- /dev/null +++ b/kernel/0.1x/linux-0.10/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/kernel/0.1x/linux-0.10/include/unistd.h b/kernel/0.1x/linux-0.10/include/unistd.h new file mode 100644 index 00000000..fa646053 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/unistd.h @@ -0,0 +1,248 @@ +#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 +#include +#include +#include + +#ifdef __LIBRARY__ + +#define __NR_setup 0 /* used only by init, to get system going */ +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_stat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_fstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_phys 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_uname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 + +#define _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/kernel/0.1x/linux-0.10/include/utime.h b/kernel/0.1x/linux-0.10/include/utime.h new file mode 100644 index 00000000..7b6d6971 --- /dev/null +++ b/kernel/0.1x/linux-0.10/include/utime.h @@ -0,0 +1,13 @@ +#ifndef _UTIME_H +#define _UTIME_H + +#include /* I know - shouldn't do this, but .. */ + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +extern int utime(const char *filename, struct utimbuf *times); + +#endif diff --git a/kernel/0.1x/linux-0.10/init/main.c b/kernel/0.1x/linux-0.10/init/main.c new file mode 100644 index 00000000..76107d2e --- /dev/null +++ b/kernel/0.1x/linux-0.10/init/main.c @@ -0,0 +1,185 @@ +/* + * linux/init/main.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ +static inline _syscall0(int,fork) +static inline _syscall0(int,pause) +static inline _syscall1(int,setup,void *,BIOS) +static inline _syscall0(int,sync) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +static char printbuf[1024]; + +extern int vsprintf(); +extern void init(void); +extern void blk_dev_init(void); +extern void chr_dev_init(void); +extern void hd_init(void); +extern void floppy_init(void); +extern void mem_init(long start, long end); +extern long kernel_mktime(struct tm * tm); +extern long startup_time; + +/* + * This is set up by the setup-routine at boot-time + */ +#define EXT_MEM_K (*(unsigned short *)0x90002) +#define DRIVE_INFO (*(struct drive_info *)0x90080) +#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC) + +/* + * Yeah, yeah, it's ugly, but I cannot find how to do this correctly + * and this seems to work. I anybody has more info on the real-time + * clock I'd be interested. Most of this was trial and error, and some + * bios-listing reading. Urghh. + */ + +#define CMOS_READ(addr) ({ \ +outb_p(0x80|addr,0x70); \ +inb_p(0x71); \ +}) + +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) + +static void time_init(void) +{ + struct tm time; + + do { + time.tm_sec = CMOS_READ(0); + time.tm_min = CMOS_READ(2); + time.tm_hour = CMOS_READ(4); + time.tm_mday = CMOS_READ(7); + time.tm_mon = CMOS_READ(8); + time.tm_year = CMOS_READ(9); + } while (time.tm_sec != CMOS_READ(0)); + BCD_TO_BIN(time.tm_sec); + BCD_TO_BIN(time.tm_min); + BCD_TO_BIN(time.tm_hour); + BCD_TO_BIN(time.tm_mday); + BCD_TO_BIN(time.tm_mon); + BCD_TO_BIN(time.tm_year); + time.tm_mon--; + startup_time = kernel_mktime(&time); +} + +static long memory_end = 0; +static long buffer_memory_end = 0; + +struct drive_info { char dummy[32]; } drive_info; + +void main(void) /* This really IS void, no error here. */ +{ /* The startup routine assumes (well, ...) this */ +/* + * Interrupts are still disabled. Do necessary setups, then + * enable them + */ + ROOT_DEV = ORIG_ROOT_DEV; + drive_info = DRIVE_INFO; + memory_end = (1<<20) + (EXT_MEM_K<<10); + memory_end &= 0xfffff000; + if (memory_end > 16*1024*1024) + memory_end = 16*1024*1024; + if (memory_end > 6*1024*1024) + buffer_memory_end = 2*1024*1024; + else + buffer_memory_end = 1*1024*1024; + mem_init(buffer_memory_end,memory_end); + trap_init(); + blk_dev_init(); + chr_dev_init(); + tty_init(); + time_init(); + sched_init(); + buffer_init(buffer_memory_end); + hd_init(); + floppy_init(); + sti(); + move_to_user_mode(); + if (!fork()) { /* we count on this going ok */ + init(); + } +/* + * NOTE!! For any other task 'pause()' would mean we have to get a + * signal to awaken, but task0 is the sole exception (see 'schedule()') + * as task 0 gets activated at every idle moment (when no other tasks + * can run). For task0 'pause()' just means we go check if some other + * task can run, and if not we return here. + */ + for(;;) pause(); +} + +static int printf(const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + write(1,printbuf,i=vsprintf(printbuf, fmt, args)); + va_end(args); + return i; +} + +static char * argv[] = { "-/bin/sh",NULL }; +static char * envp[] = { "HOME=/usr/root", NULL }; + +void init(void) +{ + int i,j; + + setup((void *) &drive_info); + 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("Free mem: %d bytes\n\r",memory_end-buffer_memory_end); + 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/kernel/0.1x/linux-0.10/kernel/Makefile b/kernel/0.1x/linux-0.10/kernel/Makefile new file mode 100644 index 00000000..31ba9146 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/Makefile @@ -0,0 +1,82 @@ +# +# 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 sys.o exit.o \ + signal.o mktime.o + +kernel.o: $(OBJS) + $(LD) -r -o kernel.o $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make keyboard.s + for i in *.c;do rm -f `basename $$i .c`.s;done + (cd chr_drv; make clean) + (cd blk_drv; make clean) + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + (cd chr_drv; make dep) + (cd blk_drv; make dep) + +### Dependencies: +exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \ + ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \ + ../include/asm/segment.h +fork.s fork.o : fork.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/segment.h ../include/asm/system.h +mktime.s mktime.o : mktime.c ../include/time.h +panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h +printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \ + ../include/linux/kernel.h +sched.s sched.o : sched.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/signal.h ../include/linux/kernel.h ../include/linux/sys.h \ + ../include/linux/fdreg.h ../include/asm/system.h ../include/asm/io.h \ + ../include/asm/segment.h +signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h +sys.s sys.o : sys.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/tty.h \ + ../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h \ + ../include/sys/times.h ../include/sys/utsname.h +traps.s traps.o : traps.c ../include/string.h ../include/linux/head.h \ + ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/system.h ../include/asm/segment.h ../include/asm/io.h +vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h diff --git a/kernel/0.1x/linux-0.10/kernel/asm.s b/kernel/0.1x/linux-0.10/kernel/asm.s new file mode 100644 index 00000000..3f24edee --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/asm.s @@ -0,0 +1,171 @@ +/* + * linux/kernel/asm.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * asm.s contains the low-level code for most hardware faults. + * page_exception is handled by the mm, so that isn't here. This + * file also handles (hopefully) fpu-exceptions due to TS-bit, as + * the fpu must be properly saved/resored. This hasn't been tested. + */ + +.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op +.globl _device_not_available,_double_fault,_coprocessor_segment_overrun +.globl _invalid_TSS,_segment_not_present,_stack_segment +.globl _general_protection,_coprocessor_error,_irq13,_reserved + +_divide_error: + pushl $_do_divide_error +no_error_code: + xchgl %eax,(%esp) + pushl %ebx + pushl %ecx + pushl %edx + pushl %edi + pushl %esi + pushl %ebp + push %ds + push %es + push %fs + pushl $0 # "error code" + lea 44(%esp),%edx + pushl %edx + movl $0x10,%edx + mov %dx,%ds + mov %dx,%es + mov %dx,%fs + call *%eax + addl $8,%esp + pop %fs + pop %es + pop %ds + popl %ebp + popl %esi + popl %edi + popl %edx + popl %ecx + popl %ebx + popl %eax + iret + +_debug: + pushl $_do_int3 # _do_debug + jmp no_error_code + +_nmi: + pushl $_do_nmi + jmp no_error_code + +_int3: + pushl $_do_int3 + jmp no_error_code + +_overflow: + pushl $_do_overflow + jmp no_error_code + +_bounds: + pushl $_do_bounds + jmp no_error_code + +_invalid_op: + pushl $_do_invalid_op + jmp no_error_code + +math_emulate: + popl %eax + pushl $_do_device_not_available + jmp no_error_code +_device_not_available: + pushl %eax + movl %cr0,%eax + testl $0x4,%eax # EM (math emulation bit) + jne math_emulate + clts # clear TS so that we can use math + pushl %ecx + pushl %edx + push %ds + movl $0x10,%eax + mov %ax,%ds + call _math_state_restore + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +_coprocessor_segment_overrun: + pushl $_do_coprocessor_segment_overrun + jmp no_error_code + +_reserved: + pushl $_do_reserved + jmp no_error_code + +_irq13: + pushl %eax + xorb %al,%al + outb %al,$0xF0 + movb $0x20,%al + outb %al,$0x20 + jmp 1f +1: jmp 1f +1: outb %al,$0xA0 + popl %eax +_coprocessor_error: + fnclex + 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/kernel/0.1x/linux-0.10/kernel/blk_drv/Makefile b/kernel/0.1x/linux-0.10/kernel/blk_drv/Makefile new file mode 100644 index 00000000..c7f49831 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/blk_drv/Makefile @@ -0,0 +1,58 @@ +# +# Makefile for the FREAX-kernel block device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =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 = ll_rw_blk.o floppy.o hd.o + +blk_drv.a: $(OBJS) + $(AR) rcs blk_drv.a $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/signal.h ../../include/linux/kernel.h \ + ../../include/linux/fdreg.h ../../include/asm/system.h \ + ../../include/asm/io.h ../../include/asm/segment.h blk.h +hd.s hd.o : hd.c ../../include/linux/config.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h ../../include/signal.h \ + ../../include/linux/kernel.h ../../include/linux/hdreg.h \ + ../../include/asm/system.h ../../include/asm/io.h \ + ../../include/asm/segment.h blk.h +ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h ../../include/signal.h \ + ../../include/linux/kernel.h ../../include/asm/system.h blk.h diff --git a/kernel/0.1x/linux-0.10/kernel/blk_drv/blk.h b/kernel/0.1x/linux-0.10/kernel/blk_drv/blk.h new file mode 100644 index 00000000..e1e386d7 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/blk_drv/blk.h @@ -0,0 +1,116 @@ +#ifndef _BLK_H +#define _BLK_H + +#define NR_BLK_DEV 7 +#define NR_REQUEST 64 + +/* + * Ok, this is an expanded form so that we can use the same + * request for paging requests when that is implemented. In + * paging, 'bh' is NULL, and 'waiting' is used to wait for + * read/write completion. + */ +struct request { + int dev; /* -1 if no request */ + int cmd; /* READ or WRITE */ + int errors; + unsigned long sector; + unsigned long nr_sectors; + char * buffer; + struct task_struct * waiting; + struct buffer_head * bh; + struct request * next; +}; + +#define IN_ORDER(s1,s2) \ +((s1)->dev < (s2)->dev || ((s1)->dev == (s2)->dev && \ +(s1)->sector < (s2)->sector)) + +struct blk_dev_struct { + void (*request_fn)(void); + struct request * current_request; +}; + +extern struct blk_dev_struct blk_dev[NR_BLK_DEV]; +extern struct request request[NR_REQUEST]; +extern struct task_struct * wait_for_request; + +#ifdef MAJOR_NR + +/* + * Add entries as needed. Currently the only block devices + * supported are hard-disks and floppies. + */ +#if (MAJOR_NR == 2) +/* floppy */ +#define DEVICE_NAME "floppy" +#define DEVICE_INTR do_floppy +#define DEVICE_REQUEST do_fd_request +#define DEVICE_NR(device) ((device) & 3) +#define DEVICE_ON(device) floppy_on(DEVICE_NR(device)) +#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) + +#elif (MAJOR_NR == 3) +/* harddisk */ +#define DEVICE_NAME "harddisk" +#define DEVICE_INTR do_hd +#define DEVICE_REQUEST do_hd_request +#define DEVICE_NR(device) (MINOR(device)/5) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif +/* unknown blk device */ +#error "unknown blk device" + +#endif + +#define CURRENT (blk_dev[MAJOR_NR].current_request) +#define CURRENT_DEV DEVICE_NR(CURRENT->dev) + +void (*DEVICE_INTR)(void) = NULL; +static void (DEVICE_REQUEST)(void); + +extern inline void unlock_buffer(struct buffer_head * bh) +{ + if (!bh->b_lock) + printk(DEVICE_NAME ": free buffer being unlocked\n"); + bh->b_lock=0; + wake_up(&bh->b_wait); +} + +extern inline void end_request(int uptodate) +{ + DEVICE_OFF(CURRENT->dev); + if (CURRENT->bh) { + CURRENT->bh->b_uptodate = uptodate; + unlock_buffer(CURRENT->bh); + } + if (!uptodate) { + printk(DEVICE_NAME " I/O error\n\r"); + printk("dev %04x, block %d\n\r",CURRENT->dev, + CURRENT->bh->b_blocknr); + } + wake_up(&CURRENT->waiting); + wake_up(&wait_for_request); + CURRENT->dev = -1; + CURRENT = CURRENT->next; +} + +#define INIT_REQUEST \ +repeat: \ + if (!CURRENT) \ + return; \ + if (MAJOR(CURRENT->dev) != MAJOR_NR) \ + panic(DEVICE_NAME ": request list destroyed"); \ + if (CURRENT->bh) \ + if (!CURRENT->bh->b_lock) \ + panic(DEVICE_NAME ": block not locked"); \ + else { \ + CURRENT->bh->b_dirt = 0; \ + CURRENT->bh->b_uptodate = 0; \ + } + +#endif + +#endif diff --git a/kernel/0.1x/linux-0.10/kernel/blk_drv/floppy.c b/kernel/0.1x/linux-0.10/kernel/blk_drv/floppy.c new file mode 100644 index 00000000..03596e7d --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/blk_drv/floppy.c @@ -0,0 +1,382 @@ +/* + * linux/kernel/floppy.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * As with hd.c, all routines within this file can (and will) be called + * by interrupts, so extreme caution is needed. A hardware interrupt + * handler may not sleep, or a kernel panic will happen. Thus I cannot + * call "floppy-on" directly, but have to set a special timer interrupt + * etc. + * + * Also, I'm not certain this works on more than 1 floppy. Bugs may + * abund. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 2 +#include "blk.h" + +static void reset_floppy(void); +static void seek_interrupt(void); +static void rw_interrupt(void); + +extern unsigned char current_DOR; +extern unsigned char selected; + +#define immoutb_p(val,port) \ +__asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port)) + +#define TYPE(x) ((x)>>2) +#define DRIVE(x) ((x)&0x03) +/* + * Note that MAX_ERRORS=10 doesn't imply that we retry every bad read + * max 10 times - some types of errors increase the errorcount by 2, + * so we might actually retry only 6-7 times before giving up. + */ +#define MAX_ERRORS 10 + +/* + * globals used by 'result()' + */ +#define MAX_REPLIES 7 +static unsigned char reply_buffer[MAX_REPLIES]; +#define ST0 (reply_buffer[0]) +#define ST1 (reply_buffer[1]) +#define ST2 (reply_buffer[2]) +#define ST3 (reply_buffer[3]) + +/* + * This struct defines the different floppy types. Unlike minix + * linux doesn't have a "search for right type"-type, as the code + * for that is convoluted and weird. + * + * The 'stretch' tells if the tracks need to be boubled for some + * types (ie 360kB diskette in 1.2MB drive etc). Others should + * be self-explanatory. + */ +static struct floppy_struct { + int size, sect, head, track, stretch; + unsigned char gap,rate,spec1; +} floppy_type[] = { + { 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */ + { 720, 9,2,40,0,0x2A,0x02,0xDF }, /* 360kB PC diskettes */ + { 2400,15,2,80,0,0x1B,0x00,0xDF }, /* 1.2 MB AT-diskettes */ + { 720, 9,2,40,1,0x2A,0x02,0xDF }, /* 360kB in 720kB drive */ + { 1440, 9,2,80,0,0x2A,0x02,0xDF }, /* 3.5" 720kB diskette */ + { 720, 9,2,40,1,0x23,0x01,0xDF }, /* 360kB in 1.2MB drive */ + { 1440, 9,2,80,0,0x23,0x01,0xDF }, /* 720kB in 1.2MB drive */ + { 2880,18,2,80,0,0x1B,0x00,0xCF }, /* 1.44MB diskette */ +}; +/* + * Rate is 0 for 500kb/s, 2 for 300kbps, 1 for 250kbps + * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc), + * H is head unload time (1=16ms, 2=32ms, etc) + * + * Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms etc) + * and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA). + */ + +extern void floppy_interrupt(void); +extern char tmp_floppy_area[1024]; + +/* + * These are global variables, as that's the easiest way to give + * information to interrupts. They are the data used for the current + * request. + */ +static int cur_spec1 = -1; +static int cur_rate = -1; +static struct floppy_struct * floppy = floppy_type; +static unsigned char current_drive = 0; +static unsigned char sector = 0; +static unsigned char head = 0; +static unsigned char track = 0; +static unsigned char seek_track = 0; +static unsigned char command = 0; + +/* + * floppy-change is never called from an interrupt, so we can relax a bit + * here. + */ +int floppy_change(unsigned int nr) +{ + floppy_on(nr); + floppy_select(nr); + if (inb(FD_DIR) & 0x80) { + floppy_off(nr); + return 1; + } + floppy_off(nr); + return 0; +} + +#define copy_buffer(from,to) \ +__asm__("cld ; rep ; movsl" \ + ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \ + :"cx","di","si") + +static void setup_DMA(void) +{ + long addr = (long) CURRENT->buffer; + + if (addr >= 0x100000) { + addr = (long) tmp_floppy_area; + if (command == FD_WRITE) + copy_buffer(CURRENT->buffer,tmp_floppy_area); + } +/* mask DMA 2 */ + immoutb_p(4|2,10); +/* output command byte. I don't know why, but everyone (minix, */ +/* sanches & canton) output this twice, first to 12 then to 11 */ + __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t" + "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:":: + "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE))); +/* 8 low bits of addr */ + immoutb_p(addr,4); + addr >>= 8; +/* bits 8-15 of addr */ + immoutb_p(addr,4); + addr >>= 8; +/* bits 16-19 of addr */ + immoutb_p(addr,0x81); +/* low 8 bits of count-1 (1024-1=0x3ff) */ + immoutb_p(0xff,5); +/* high 8 bits of count-1 */ + immoutb_p(3,5); +/* activate DMA 2 */ + immoutb_p(0|2,10); +} + +static void output_byte(char byte) +{ + int counter; + unsigned char status; + + for(counter = 0 ; counter < 10000 ; counter++) { + status = inb(FD_STATUS) & (STATUS_READY | STATUS_DIR); + if (status == STATUS_READY) { + outb(byte,FD_DATA); + return; + } + } + printk("Unable to send byte to FDC\n\r"); +} + +static int result(void) +{ + int i = 0, counter, status; + + for (counter = 0 ; counter < 10000 ; counter++) { + status = inb(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY); + if (status == STATUS_READY) + return i; + if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) { + if (i >= MAX_REPLIES) + break; + reply_buffer[i++] = inb(FD_DATA); + } + } + printk("Getstatus times out\n\r"); + return -1; +} + +/* + * This is the routine called after every seek (or recalibrate) interrupt + * from the floppy controller. Note that the "unexpected interrupt" routine + * also does a recalibrate, but doesn't come here. + */ +static void seek_interrupt(void) +{ +/* sense drive status */ + output_byte(FD_SENSEI); + if (result() != 2 || (ST0 & 0xF8) != 0x20) { + CURRENT->errors++; + if (CURRENT->errors > MAX_ERRORS) { + floppy_deselect(current_drive); + end_request(0); + reset_floppy(); + return; + } + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); + return; + } +/* are we on the right track? */ + if (ST1 != seek_track) { + CURRENT->errors++; + if (CURRENT->errors > MAX_ERRORS) { + floppy_deselect(current_drive); + end_request(0); + reset_floppy(); + return; + } + output_byte(FD_SEEK); + output_byte(head<<2 | current_drive); + output_byte(seek_track); + return; + } +/* yes - set up DMA and read/write command */ + setup_DMA(); + do_floppy = rw_interrupt; + output_byte(command); + output_byte(head<<2 | current_drive); + output_byte(track); + output_byte(head); + output_byte(sector); + output_byte(2); /* sector size = 512 */ + output_byte(floppy->sect); + output_byte(floppy->gap); + output_byte(0xFF); /* sector size (0xff when n!=0 ?) */ +} + +/* + * Ok, this interrupt is called after a DMA read/write has succeeded, + * so we check the results, and copy any buffers. + */ +static void rw_interrupt(void) +{ + if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || + (ST2 & 0x73)) { + CURRENT->errors++; + if (CURRENT->errors > MAX_ERRORS || (ST1 & 0x02)) { + if (ST1 & 0x02) + printk("Drive %d is write protected\n\r", + current_drive); + floppy_deselect(current_drive); + end_request(0); + do_fd_request(); + return; + } + do_floppy = seek_interrupt; + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); + return; + } + if (command == FD_READ && (long)(CURRENT->buffer) >= 0x100000) + copy_buffer(tmp_floppy_area,CURRENT->buffer); + floppy_deselect(current_drive); + end_request(1); + do_fd_request(); +} + +/* + * This routine is called when everything should be correctly set up + * for the transfer (ie floppy motor is on and the correct floppy is + * selected). + */ +static void transfer(void) +{ + if (cur_spec1 != floppy->spec1) { + cur_spec1 = floppy->spec1; + output_byte(FD_SPECIFY); + output_byte(cur_spec1); /* hut etc */ + output_byte(6); /* Head load time =6ms, DMA */ + } + if (cur_rate != floppy->rate) + outb_p(cur_rate = floppy->rate,FD_DCR); + do_floppy = seek_interrupt; + if (seek_track) { + output_byte(FD_SEEK); + output_byte(head<<2 | current_drive); + output_byte(seek_track); + } else { + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); + } +} + +/* + * Special case - used after a unexpected interrupt (or reset) + */ +static void recal_interrupt(void) +{ + do_floppy = NULL; + output_byte(FD_SENSEI); + if (result()!=2 || (ST0 & 0xE0) == 0x60) { + reset_floppy(); + return; + } + do_fd_request(); +} + +void unexpected_floppy_interrupt(void) +{ + output_byte(FD_SENSEI); + if (result()!=2 || (ST0 & 0xE0) == 0x60) { + reset_floppy(); + return; + } + do_floppy = recal_interrupt; + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); +} + +static void reset_interrupt(void) +{ + output_byte(FD_SENSEI); + (void) result(); + do_floppy = recal_interrupt; + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); +} + +static void reset_floppy(void) +{ + printk("Reset-floppy called\n\r"); + do_floppy = reset_interrupt; + outb_p(0,FD_DOR); + outb(current_DOR,FD_DOR); +} + +static void floppy_on_interrupt(void) +{ +/* We cannot do a floppy-select, as that might sleep. We just force it */ + selected = 1; + current_DOR &= 0xFC; + current_DOR |= current_drive; + transfer(); +} + +void do_fd_request(void) +{ + unsigned int block; + + INIT_REQUEST; + floppy = (MINOR(CURRENT->dev)>>2) + floppy_type; + current_drive = CURRENT_DEV; + block = CURRENT->sector; + if (block+2 > floppy->size) { + end_request(0); + goto repeat; + } + sector = block % floppy->sect; + block /= floppy->sect; + head = block % floppy->head; + track = block / floppy->head; + seek_track = track << floppy->stretch; + sector++; + if (CURRENT->cmd == READ) + command = FD_READ; + else if (CURRENT->cmd == WRITE) + command = FD_WRITE; + else + panic("do_fd_request: unknown command"); + add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt); +} + +void floppy_init(void) +{ + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + set_intr_gate(0x26,&floppy_interrupt); + outb(inb_p(0x21)&~0x40,0x21); +} diff --git a/kernel/0.1x/linux-0.10/kernel/blk_drv/hd.c b/kernel/0.1x/linux-0.10/kernel/blk_drv/hd.c new file mode 100644 index 00000000..9ac346d0 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/blk_drv/hd.c @@ -0,0 +1,283 @@ +/* + * linux/kernel/hd.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This is the low-level hd interrupt support. It traverses the + * request-list, using interrupts to jump between functions. As + * all the functions are called within interrupts, we may not + * sleep. Special care is recommended. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 3 +#include "blk.h" + +/* Max read/write errors/sector */ +#define MAX_ERRORS 5 +#define MAX_HD 2 + +/* + * This struct defines the HD's and their types. + */ +struct hd_i_struct { + int head,sect,cyl,wpcom,lzone,ctl; + }; +#ifdef HD_TYPE +struct hd_i_struct hd_info[] = { HD_TYPE }; +#define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct))) +#else +struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} }; +static int NR_HD = 0; +#endif + +static struct hd_struct { + long start_sect; + long nr_sects; +} hd[5*MAX_HD]={{0,0},}; + +#define port_read(port,buf,nr) \ +__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"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); + +/* This may be used only once, enforced by 'static int callable' */ +int sys_setup(void * BIOS) +{ + static int callable = 1; + int i,drive; + struct partition *p; + struct buffer_head * bh; + + if (!callable) + return -1; + callable = 0; +#ifndef HD_TYPE + for (drive=0 ; drive<2 ; drive++) { + hd_info[drive].cyl = *(unsigned short *) BIOS; + hd_info[drive].head = *(unsigned char *) (2+BIOS); + hd_info[drive].wpcom = *(unsigned short *) (5+BIOS); + hd_info[drive].ctl = *(unsigned char *) (8+BIOS); + hd_info[drive].lzone = *(unsigned short *) (12+BIOS); + hd_info[drive].sect = *(unsigned char *) (14+BIOS); + BIOS += 16; + } + if (hd_info[1].cyl) + NR_HD=2; + else + NR_HD=1; +#endif + for (i=0 ; ib_data[510] != 0x55 || (unsigned char) + bh->b_data[511] != 0xAA) { + printk("Bad partition table on drive %d\n\r",drive); + panic(""); + } + p = 0x1BE + (void *)bh->b_data; + for (i=1;i<5;i++,p++) { + hd[i+5*drive].start_sect = p->start_sect; + hd[i+5*drive].nr_sects = p->nr_sects; + } + brelse(bh); + } + printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":""); + mount_root(); + return (0); +} + +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(hd_info[drive].ctl,HD_CMD); + port=HD_DATA; + outb_p(hd_info[drive].wpcom>>2,++port); + outb_p(nsect,++port); + outb_p(sect,++port); + outb_p(cyl,++port); + outb_p(cyl>>8,++port); + outb_p(0xA0|(drive<<4)|head,++port); + outb(cmd,++port); +} + +static int drive_busy(void) +{ + unsigned int i; + + for (i = 0; i < 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 redo_hd_request(void) +{ + do_hd = NULL; + do_hd_request(); +} + +static void reset_hd(int nr) +{ + reset_controller(); + hd_out(nr,hd_info[nr].sect,hd_info[nr].sect,hd_info[nr].head-1, + hd_info[nr].cyl,WIN_SPECIFY,&redo_hd_request); +} + +void unexpected_hd_interrupt(void) +{ + printk("Unexpected HD interrupt\n\r"); +} + +static void bad_rw_intr(void) +{ + int i = CURRENT_DEV; + + if (CURRENT->errors++ >= MAX_ERRORS) + end_request(0); + reset_hd(i); +} + +static void read_intr(void) +{ + if (win_result()) { + bad_rw_intr(); + return; + } + port_read(HD_DATA,CURRENT->buffer,256); + CURRENT->errors = 0; + CURRENT->buffer += 512; + CURRENT->sector++; + if (--CURRENT->nr_sectors) + return; + end_request(1); + do_hd_request(); +} + +static void write_intr(void) +{ + if (win_result()) { + bad_rw_intr(); + return; + } + if (--CURRENT->nr_sectors) { + CURRENT->sector++; + CURRENT->buffer += 512; + port_write(HD_DATA,CURRENT->buffer,256); + return; + } + end_request(1); + do_hd_request(); +} + +void do_hd_request(void) +{ + int i,r; + unsigned int block,dev; + unsigned int sec,head,cyl; + unsigned int nsect; + + INIT_REQUEST; + dev = MINOR(CURRENT->dev); + block = CURRENT->sector; + if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) { + end_request(0); + goto repeat; + } + block += hd[dev].start_sect; + dev /= 5; + __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0), + "r" (hd_info[dev].sect)); + __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0), + "r" (hd_info[dev].head)); + sec++; + nsect = CURRENT->nr_sectors; + if (CURRENT->cmd == WRITE) { + hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr); + for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++) + /* nothing */ ; + if (!r) { + reset_hd(CURRENT_DEV); + return; + } + port_write(HD_DATA,CURRENT->buffer,256); + } else if (CURRENT->cmd == READ) { + hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr); + } else + panic("unknown hd-command"); +} + +void hd_init(void) +{ + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + set_trap_gate(0x2E,&hd_interrupt); + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xbf,0xA1); +} diff --git a/kernel/0.1x/linux-0.10/kernel/blk_drv/ll_rw_blk.c b/kernel/0.1x/linux-0.10/kernel/blk_drv/ll_rw_blk.c new file mode 100644 index 00000000..dfc3477e --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/blk_drv/ll_rw_blk.c @@ -0,0 +1,143 @@ +/* + * linux/kernel/blk_dev/ll_rw.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This handles all read/write requests to block devices + */ +#include +#include +#include +#include + +#include "blk.h" + +/* + * The request-struct contains all necessary data + * to load a nr of sectors into memory + */ +struct request request[NR_REQUEST]; + +/* + * used to wait on when there are no free requests + */ +struct task_struct * wait_for_request = NULL; + +/* blk_dev_struct is: + * do_request-address + * next-request + */ +struct blk_dev_struct blk_dev[NR_BLK_DEV] = { + { NULL, NULL }, /* no_dev */ + { NULL, NULL }, /* dev mem */ + { NULL, NULL }, /* dev fd */ + { NULL, NULL }, /* dev hd */ + { NULL, NULL }, /* dev ttyx */ + { NULL, NULL }, /* dev tty */ + { NULL, NULL } /* dev lp */ +}; + +static inline void lock_buffer(struct buffer_head * bh) +{ + cli(); + while (bh->b_lock) + sleep_on(&bh->b_wait); + bh->b_lock=1; + sti(); +} + +static inline void unlock_buffer(struct buffer_head * bh) +{ + if (!bh->b_lock) + printk("ll_rw_block.c: buffer not locked\n\r"); + bh->b_lock = 0; + wake_up(&bh->b_wait); +} + +/* + * add-request adds a request to the linked list. + * It disables interrupts so that it can muck with the + * request-lists in peace. + */ +static void add_request(struct blk_dev_struct * dev, struct request * req) +{ + struct request * tmp; + + req->next = NULL; + cli(); + if (!(tmp = dev->current_request)) { + dev->current_request = req; + sti(); + (dev->request_fn)(); + } else { + for ( ; tmp->next ; tmp=tmp->next) + if ((IN_ORDER(tmp,req) || + !IN_ORDER(tmp,tmp->next)) && + IN_ORDER(req,tmp->next)) + break; + req->next=tmp->next; + tmp->next=req; + } + sti(); +} + +static void make_request(int major,int rw, struct buffer_head * bh) +{ + struct request * req; + +/* READA is special case - the read is not really needed, so if the */ +/* buffer is locked, we just forget about it, else it's a normal read */ + if (rw == READA) { + if (bh->b_lock) + return; + else + rw=READ; + } + if (rw!=READ && rw!=WRITE) + panic("Bad block dev command, must be R/W/RA"); + lock_buffer(bh); + if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) { + unlock_buffer(bh); + return; + } +repeat: + for (req=0+request ; reqdev<0) + break; + if (req==NR_REQUEST+request) { + sleep_on(&wait_for_request); + goto repeat; + } + req->dev = bh->b_dev; + req->cmd = rw; + req->errors=0; + req->sector = bh->b_blocknr<<1; + req->nr_sectors = 2; + req->buffer = bh->b_data; + req->waiting = NULL; + req->bh = bh; + req->next = NULL; + add_request(major+blk_dev,req); +} + +void ll_rw_block(int rw, struct buffer_head * bh) +{ + unsigned int major; + + if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || + !(blk_dev[major].request_fn)) + panic("Trying to read nonexistent block-device"); + make_request(major,rw,bh); +} + +void blk_dev_init(void) +{ + int i; + + for (i=0 ; i +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 1 +#include "blk.h" + +char *ram_disk; /* Start of ram disk */ +int ram_disk_size; /* Size of ram disk */ + +void do_ram_request(void) +{ + int i,r; + unsigned int block,dev; + unsigned int sec,head,cyl; + unsigned int nsect; + + INIT_REQUEST; + if (MINOR(CURRENT->dev) != 0) { + end_request(0); + goto repeat; + } + block = CURRENT->sector; + end_request(1); +} + +void ram_init(void) +{ + +} diff --git a/kernel/0.1x/linux-0.10/kernel/chr_drv/Makefile b/kernel/0.1x/linux-0.10/kernel/chr_drv/Makefile new file mode 100644 index 00000000..d79fe59e --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/chr_drv/Makefile @@ -0,0 +1,61 @@ +# +# Makefile for the FREAX-kernel character device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =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 = tty_io.o console.o keyboard.o serial.o rs_io.o + +chr_drv.a: $(OBJS) + $(AR) rcs chr_drv.a $(OBJS) + sync + +keyboard.s: keyboard.S ../../include/linux/config.h + $(CPP) -traditional keyboard.S -o keyboard.s + +clean: + rm -f core *.o *.a tmp_make keyboard.s + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +console.s console.o : console.c ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h ../../include/signal.h \ + ../../include/linux/tty.h ../../include/termios.h ../../include/asm/io.h \ + ../../include/asm/system.h +serial.s serial.o : serial.c ../../include/linux/tty.h ../../include/termios.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/signal.h ../../include/asm/system.h ../../include/asm/io.h +tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \ + ../../include/signal.h ../../include/sys/types.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/linux/mm.h ../../include/linux/tty.h \ + ../../include/termios.h ../../include/asm/segment.h \ + ../../include/asm/system.h diff --git a/kernel/0.1x/linux-0.10/kernel/chr_drv/console.c b/kernel/0.1x/linux-0.10/kernel/chr_drv/console.c new file mode 100644 index 00000000..d8b195d8 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/chr_drv/console.c @@ -0,0 +1,561 @@ +/* + * linux/kernel/console.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * console.c + * + * This module implements the console io functions + * 'void con_init(void)' + * 'void con_write(struct tty_queue * queue)' + * Hopefully this will be a rather complete VT102 implementation. + * + */ + +/* + * 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 +#include +#include +#include + +/* + * These are set up by the setup-routine at boot-time: + */ +#define ORIG_X (*(unsigned char *)0x90000) +#define ORIG_Y (*(unsigned char *)0x90001) + +#define 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" + +/* NOTE! gotoxy thinks x==columns is ok */ +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+1top) { + 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>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) + 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(unsigned int nr) +{ + if (nr>columns) + nr=columns; + else if (!nr) + nr=1; + while (nr--) + insert_char(); +} + +static void csi_L(unsigned int nr) +{ + if (nr>lines) + nr=lines; + else if (!nr) + nr=1; + while (nr--) + insert_line(); +} + +static void csi_P(unsigned int nr) +{ + if (nr>columns) + nr=columns; + else if (!nr) + nr=1; + while (nr--) + delete_char(); +} + +static void csi_M(unsigned 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) +{ + gotoxy(saved_x, saved_y); +} + +void con_write(struct tty_struct * tty) +{ + int nr; + char c; + + nr = CHARS(tty->write_q); + while (nr--) { + GETCH(tty->write_q,c); + switch(state) { + case 0: + if (c>31 && c<127) { + if (x>=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='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(ORIG_X,ORIG_Y); + set_trap_gate(0x21,&keyboard_interrupt); + outb_p(inb_p(0x21)&0xfd,0x21); + a=inb_p(0x61); + outb_p(a|0x80,0x61); + outb(a,0x61); +} diff --git a/kernel/0.1x/linux-0.10/kernel/chr_drv/keyboard.S b/kernel/0.1x/linux-0.10/kernel/chr_drv/keyboard.S new file mode 100644 index 00000000..1ce39731 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/chr_drv/keyboard.S @@ -0,0 +1,497 @@ +/* + * linux/kernel/keyboard.S + * + * (C) 1991 Linus Torvalds + */ + +/* + * Thanks to Alfred Leung for US keyboard patches + */ + +#include + +.text +.globl _keyboard_interrupt + +/* + * these are for the keyboard read functions + */ +size = 1024 /* must be a power of two ! And MUST be the same + as in tty_io.c !!!! */ +head = 4 +tail = 8 +proc_list = 12 +buf = 16 + +mode: .byte 0 /* caps, alt, ctrl and shift mode */ +leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */ +e0: .byte 0 +flags: .byte 0 /* 0x1 - map caps lock to ctrl */ + +/* + * 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 $0x1,flags + je ctrl + 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: testb $0x1,flags + je unctrl + 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: + pushl %eax + pushl %ecx + pushl %edx + call _show_stat + popl %edx + popl %ecx + popl %eax + subb $0x3B,%al + jb end_func + cmpb $9,%al + jbe ok_func + subb $18,%al + cmpb $10,%al + jb end_func + cmpb $11,%al + ja end_func +ok_func: + cmpl $4,%ecx /* check that there is enough room */ + jl end_func + movl func_table(,%eax,4),%eax + xorl %ebx,%ebx + jmp put_queue +end_func: + ret + +/* + * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc. + */ +func_table: + .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b + .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b + .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b + +#if defined(KBD_FINNISH) +key_map: + .byte 0,27 + .ascii "1234567890+'" + .byte 127,9 + .ascii "qwertyuiop}" + .byte 0,13,0 + .ascii "asdfghjkl|{" + .byte 0,0 + .ascii "'zxcvbnm,.-" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + +shift_map: + .byte 0,27 + .ascii "!\"#$%&/()=?`" + .byte 127,9 + .ascii "QWERTYUIOP]^" + .byte 13,0 + .ascii "ASDFGHJKL\\[" + .byte 0,0 + .ascii "*ZXCVBNM;:_" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#elif defined(KBD_US) + +key_map: + .byte 0,27 + .ascii "1234567890-=" + .byte 127,9 + .ascii "qwertyuiop[]" + .byte 13,0 + .ascii "asdfghjkl;'" + .byte '`,0 + .ascii "\\zxcvbnm,./" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + + +shift_map: + .byte 0,27 + .ascii "!@#$%^&*()_+" + .byte 127,9 + .ascii "QWERTYUIOP{}" + .byte 13,0 + .ascii "ASDFGHJKL:\"" + .byte '~,0 + .ascii "|ZXCVBNM<>?" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#else +#error "KBD-type not defined" +#endif +/* + * do_self handles "normal" keys, ie keys that don't change meaning + * and which have just one character returns. + */ +do_self: + lea alt_map,%ebx + testb $0x20,mode /* alt-gr */ + jne 1f + lea shift_map,%ebx + testb $0x03,mode + jne 1f + lea key_map,%ebx +1: movb (%ebx,%eax),%al + orb %al,%al + je none + testb $0x4c,mode /* ctrl or caps */ + je 2f + cmpb $'a,%al + jb 2f + cmpb $'},%al + ja 2f + subb $32,%al +2: testb $0x0c,mode /* ctrl */ + je 3f + cmpb $64,%al + jb 3f + cmpb $64+32,%al + jae 3f + subb $64,%al +3: testb $0x10,mode /* left alt */ + je 4f + orb $0x80,%al +4: andl $0xff,%eax + xorl %ebx,%ebx + call put_queue +none: ret + +/* + * minus has a routine of it's own, as a 'E0h' before + * the scan code for minus means that the numeric keypad + * slash was pushed. + */ +minus: cmpb $1,e0 + jne do_self + movl $'/,%eax + xorl %ebx,%ebx + jmp put_queue +/* + * do_space handles ctrl-space as an ASCII NUL. Old habits die hard. + */ +do_space: + testb $0x04,mode /* ctrl */ + je do_self + testb $0x03,mode /* shift */ + jne 1f + xorb $0x01, flags /* toggle caps lock flag */ + ret +1f: movl $0,%al /* ASCII NUL */ + 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_space,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/kernel/0.1x/linux-0.10/kernel/chr_drv/keyboard.S.jtkohl b/kernel/0.1x/linux-0.10/kernel/chr_drv/keyboard.S.jtkohl new file mode 100644 index 00000000..5fc37879 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/chr_drv/keyboard.S.jtkohl @@ -0,0 +1,488 @@ +/* + * linux/kernel/keyboard.S + * + * (C) 1991 Linus Torvalds + */ + +/* + * Thanks to Alfred Leung for US keyboard patches + */ + +#include + +.text +.globl _keyboard_interrupt + +/* + * these are for the keyboard read functions + */ +size = 1024 /* must be a power of two ! And MUST be the same + as in tty_io.c !!!! */ +head = 4 +tail = 8 +proc_list = 12 +buf = 16 + +mode: .byte 0 /* caps, alt, ctrl and shift mode */ +leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */ +e0: .byte 0 + +/* + * con_int is the real interrupt routine that reads the + * keyboard scan-code and converts it into the appropriate + * ascii character(s). + */ +_keyboard_interrupt: + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + push %ds + push %es + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + 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: + pushl %eax + pushl %ecx + pushl %edx + call _show_stat + popl %edx + popl %ecx + popl %eax + subb $0x3B,%al + jb end_func + cmpb $9,%al + jbe ok_func + subb $18,%al + cmpb $10,%al + jb end_func + cmpb $11,%al + ja end_func +ok_func: + cmpl $4,%ecx /* check that there is enough room */ + jl end_func + movl func_table(,%eax,4),%eax + xorl %ebx,%ebx + jmp put_queue +end_func: + ret + +/* + * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc. + */ +func_table: + .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b + .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b + .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b + +#if defined(KBD_FINNISH) +key_map: + .byte 0,27 + .ascii "1234567890+'" + .byte 127,9 + .ascii "qwertyuiop}" + .byte 0,13,0 + .ascii "asdfghjkl|{" + .byte 0,0 + .ascii "'zxcvbnm,.-" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + +shift_map: + .byte 0,27 + .ascii "!\"#$%&/()=?`" + .byte 127,9 + .ascii "QWERTYUIOP]^" + .byte 13,0 + .ascii "ASDFGHJKL\\[" + .byte 0,0 + .ascii "*ZXCVBNM;:_" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#elif defined(KBD_US) + +key_map: + .byte 0,27 + .ascii "1234567890-=" + .byte 127,9 + .ascii "qwertyuiop[]" + .byte 13,0 + .ascii "asdfghjkl;'" + .byte '`,0 + .ascii "\\zxcvbnm,./" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + + +shift_map: + .byte 0,27 + .ascii "!@#$%^&*()_+" + .byte 127,9 + .ascii "QWERTYUIOP{}" + .byte 13,0 + .ascii "ASDFGHJKL:\"" + .byte '~,0 + .ascii "|ZXCVBNM<>?" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#else +#error "KBD-type not defined" +#endif +/* + * do_self handles "normal" keys, ie keys that don't change meaning + * and which have just one character returns. + */ +do_self: + lea alt_map,%ebx + testb $0x20,mode /* alt-gr */ + jne 1f + lea shift_map,%ebx + testb $0x03,mode + jne 1f + lea key_map,%ebx +1: movb (%ebx,%eax),%al + orb %al,%al + je none + testb $0x4c,mode /* ctrl or caps */ + je 2f + cmpb $'a,%al + jb 2f + cmpb $'},%al + ja 2f + subb $32,%al +2: testb $0x0c,mode /* ctrl */ + je 3f + cmpb $64,%al + jb 3f + cmpb $64+32,%al + jae 3f + subb $64,%al +3: testb $0x10,mode /* left alt */ + je 4f + orb $0x80,%al +4: andl $0xff,%eax + xorl %ebx,%ebx + call put_queue +none: ret + +/* + * minus has a routine of it's own, as a 'E0h' before + * the scan code for minus means that the numeric keypad + * slash was pushed. + */ +minus: cmpb $1,e0 + jne do_self + movl $'/,%eax + xorl %ebx,%ebx + jmp put_queue +/* + * do_space handles ctrl-space as an ASCII NUL. Old habits die hard. + */ +do_space: + testb $0x04,mode /* ctrl */ + je do_self + movl $0,%al /* ASCII NUL */ + 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_space,ctrl,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,unctrl,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/kernel/0.1x/linux-0.10/kernel/chr_drv/rs_io.s b/kernel/0.1x/linux-0.10/kernel/chr_drv/rs_io.s new file mode 100644 index 00000000..a2f8be36 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/chr_drv/rs_io.s @@ -0,0 +1,147 @@ +/* + * linux/kernel/rs_io.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * rs_io.s + * + * This module implements the rs232 io interrupts. + */ + +.text +.globl _rs1_interrupt,_rs2_interrupt + +size = 1024 /* must be power of two ! + and must match the value + in tty_io.c!!! */ + +/* these are the offsets into the read/write buffer structures */ +rs_addr = 0 +head = 4 +tail = 8 +proc_list = 12 +buf = 16 + +startup = 256 /* chars left in write queue when we restart it */ + +/* + * These are the actual interrupt routines. They look where + * the interrupt is coming from, and take appropriate action. + */ +.align 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) +1: pushl %edx + call _do_tty_interrupt + addl $4,%esp + 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/kernel/0.1x/linux-0.10/kernel/chr_drv/serial.c b/kernel/0.1x/linux-0.10/kernel/chr_drv/serial.c new file mode 100644 index 00000000..2c320c49 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/chr_drv/serial.c @@ -0,0 +1,59 @@ +/* + * linux/kernel/serial.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * serial.c + * + * This module implements the rs232 io functions + * void rs_write(struct tty_struct * queue); + * void rs_init(void); + * and all interrupts pertaining to serial IO. + */ + +#include +#include +#include +#include + +#define WAKEUP_CHARS (TTY_BUF_SIZE/4) + +extern void rs1_interrupt(void); +extern void rs2_interrupt(void); + +static void init(int port) +{ + outb_p(0x80,port+3); /* set DLAB of line control reg */ + outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */ + outb_p(0x00,port+1); /* MS of divisor */ + outb_p(0x03,port+3); /* reset DLAB */ + outb_p(0x0b,port+4); /* set DTR,RTS, OUT_2 */ + outb_p(0x0d,port+1); /* enable all intrs but writes */ + (void)inb(port); /* read data port to reset things (?) */ +} + +void rs_init(void) +{ + set_intr_gate(0x24,rs1_interrupt); + set_intr_gate(0x23,rs2_interrupt); + init(tty_table[1].read_q.data); + init(tty_table[2].read_q.data); + outb(inb_p(0x21)&0xE7,0x21); +} + +/* + * This routine gets called when tty_write has put something into + * the write_queue. It must check wheter the queue is empty, and + * set the interrupt register accordingly + * + * void _rs_write(struct tty_struct * tty); + */ +void rs_write(struct tty_struct * tty) +{ + cli(); + if (!EMPTY(tty->write_q)) + outb(inb_p(tty->write_q.data+1)|0x02,tty->write_q.data+1); + sti(); +} diff --git a/kernel/0.1x/linux-0.10/kernel/chr_drv/tty_io.c b/kernel/0.1x/linux-0.10/kernel/chr_drv/tty_io.c new file mode 100644 index 00000000..05de15b2 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/chr_drv/tty_io.c @@ -0,0 +1,333 @@ +/* + * linux/kernel/tty_io.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles + * or rs-channels. It also implements echoing, cooked mode etc (well, + * not currently, but ...) + */ +#include +#include +#include + +#define ALRMMASK (1<<(SIGALRM-1)) +#define KILLMASK (1<<(SIGKILL-1)) +#define INTMASK (1<<(SIGINT-1)) +#define QUITMASK (1<<(SIGQUIT-1)) +#define TSTPMASK (1<<(SIGTSTP-1)) + +#include +#include +#include +#include + +#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f) +#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f) +#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f) + +#define L_CANON(tty) _L_FLAG((tty),ICANON) +#define L_ISIG(tty) _L_FLAG((tty),ISIG) +#define L_ECHO(tty) _L_FLAG((tty),ECHO) +#define L_ECHOE(tty) _L_FLAG((tty),ECHOE) +#define L_ECHOK(tty) _L_FLAG((tty),ECHOK) +#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL) +#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE) + +#define I_UCLC(tty) _I_FLAG((tty),IUCLC) +#define I_NLCR(tty) _I_FLAG((tty),INLCR) +#define I_CRNL(tty) _I_FLAG((tty),ICRNL) +#define I_NOCR(tty) _I_FLAG((tty),IGNCR) + +#define O_POST(tty) _O_FLAG((tty),OPOST) +#define O_NLCR(tty) _O_FLAG((tty),ONLCR) +#define O_CRNL(tty) _O_FLAG((tty),OCRNL) +#define O_NLRET(tty) _O_FLAG((tty),ONLRET) +#define O_LCUC(tty) _O_FLAG((tty),OLCUC) + +struct tty_struct tty_table[] = { + { + {ICRNL, + 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 mask) +{ + int i; + + if (tty->pgrp <= 0) + return; + for (i=0;ipgrp==tty->pgrp) + task[i]->signal |= mask; +} + +static void sleep_if_empty(struct tty_queue * queue) +{ + cli(); + while (!current->signal && EMPTY(*queue)) + interruptible_sleep_on(&queue->proc_list); + sti(); +} + +static void sleep_if_full(struct tty_queue * queue) +{ + if (!FULL(*queue)) + return; + cli(); + while (!current->signal && LEFT(*queue)<128) + interruptible_sleep_on(&queue->proc_list); + sti(); +} + +void wait_for_keypress(void) +{ + sleep_if_empty(&tty_table[0].secondary); +} + +void copy_to_cooked(struct tty_struct * tty) +{ + signed char c; + + while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) { + GETCH(tty->read_q,c); + if (c==13) + if (I_CRNL(tty)) + c=10; + else if (I_NOCR(tty)) + continue; + else ; + else if (c==10 && I_NLCR(tty)) + c=13; + if (I_UCLC(tty)) + c=tolower(c); + if (L_CANON(tty)) { + if (c==ERASE_CHAR(tty)) { + if (EMPTY(tty->secondary) || + (c=LAST(tty->secondary))==10 || + c==EOF_CHAR(tty)) + continue; + if (L_ECHO(tty)) { + if (c<32) + PUTCH(127,tty->write_q); + PUTCH(127,tty->write_q); + tty->write(tty); + } + DEC(tty->secondary.head); + continue; + } + if (c==STOP_CHAR(tty)) { + tty->stopped=1; + continue; + } + if (c==START_CHAR(tty)) { + tty->stopped=0; + continue; + } + } + if (!L_ISIG(tty)) { + if (c==INTR_CHAR(tty)) { + tty_intr(tty,INTMASK); + continue; + } + if (c==KILL_CHAR(tty)) { + tty_intr(tty,KILLMASK); + 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+jiffiesalarm = time+jiffies; + } + if (minimum>nr) + minimum=nr; + while (nr>0) { + if (flag && (current->signal & ALRMMASK)) { + current->signal &= ~ALRMMASK; + break; + } + if (current->signal) + break; + if (EMPTY(tty->secondary) || (L_CANON(tty) && + !tty->secondary.data && LEFT(tty->secondary)>20)) { + sleep_if_empty(&tty->secondary); + continue; + } + do { + GETCH(tty->secondary,c); + if (c==EOF_CHAR(tty) || c==10) + tty->secondary.data--; + if (c==EOF_CHAR(tty) && L_CANON(tty)) + return (b-buf); + else { + put_fs_byte(c,b++); + if (!--nr) + break; + } + } while (nr>0 && !EMPTY(tty->secondary)); + if (time && !L_CANON(tty)) + if (flag=(!oldalarm || time+jiffiesalarm = time+jiffies; + else + current->alarm = oldalarm; + if (L_CANON(tty)) { + if (b-buf) + break; + } else if (b-buf >= minimum) + break; + } + current->alarm = oldalarm; + if (current->signal && !(b-buf)) + return -EINTR; + return (b-buf); +} + +int tty_write(unsigned channel, char * buf, int nr) +{ + static cr_flag=0; + struct tty_struct * tty; + char c, *b=buf; + + if (channel>2 || nr<0) return -1; + tty = channel + tty_table; + while (nr>0) { + sleep_if_full(&tty->write_q); + if (current->signal) + break; + while (nr>0 && !FULL(tty->write_q)) { + c=get_fs_byte(b); + if (O_POST(tty)) { + if (c=='\r' && O_CRNL(tty)) + c='\n'; + else if (c=='\n' && O_NLRET(tty)) + c='\r'; + if (c=='\n' && !cr_flag && O_NLCR(tty)) { + cr_flag = 1; + PUTCH(13,tty->write_q); + continue; + } + if (O_LCUC(tty)) + c=toupper(c); + } + b++; nr--; + cr_flag = 0; + PUTCH(c,tty->write_q); + } + tty->write(tty); + if (nr>0) + schedule(); + } + return (b-buf); +} + +/* + * Jeh, sometimes I really like the 386. + * This routine is called from an interrupt, + * and there should be absolutely no problem + * with sleeping even in an interrupt (I hope). + * Of course, if somebody proves me wrong, I'll + * hate intel for all time :-). We'll have to + * be careful and see to reinstating the interrupt + * chips before calling this, though. + * + * I don't think we sleep here under normal circumstances + * anyway, which is good, as the task sleeping might be + * totally innocent. + */ +void do_tty_interrupt(int tty) +{ + copy_to_cooked(tty_table+tty); +} + +void chr_dev_init(void) +{ +} diff --git a/kernel/0.1x/linux-0.10/kernel/exit.c b/kernel/0.1x/linux-0.10/kernel/exit.c new file mode 100644 index 00000000..10bbacc2 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/exit.c @@ -0,0 +1,188 @@ +/* + * linux/kernel/exit.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include +#include +#include + +int sys_pause(void); +int sys_close(int fd); + +void release(struct task_struct * p) +{ + int i; + + if (!p) + return; + for (i=1 ; i32) + return -EINVAL; + if (priv || (current->euid==p->euid) || suser()) + p->signal |= (1<<(sig-1)); + else + return -EPERM; + return 0; +} + +static void kill_session(void) +{ + struct task_struct **p = NR_TASKS + task; + + while (--p > &FIRST_TASK) { + if (*p && (*p)->session == current->session) + (*p)->signal |= 1<<(SIGHUP-1); + } +} + +/* + * XXX need to check permissions needed to send signals to process + * groups, etc. etc. kill() permissions semantics are tricky! + */ +int sys_kill(int pid,int sig) +{ + struct task_struct **p = NR_TASKS + task; + int err, retval = 0; + + if (!pid) while (--p > &FIRST_TASK) { + if (*p && (*p)->pgrp == current->pid) + if (err=send_sig(sig,*p,1)) + retval = err; + } else if (pid>0) while (--p > &FIRST_TASK) { + if (*p && (*p)->pid == pid) + if (err=send_sig(sig,*p,0)) + retval = err; + } else if (pid == -1) while (--p > &FIRST_TASK) + if (err = send_sig(sig,*p,0)) + retval = err; + else while (--p > &FIRST_TASK) + if (*p && (*p)->pgrp == -pid) + if (err = send_sig(sig,*p,0)) + retval = err; + return retval; +} + +static void tell_father(int pid) +{ + int i; + + if (pid) + for (i=0;ipid != pid) + continue; + task[i]->signal |= (1<<(SIGCHLD-1)); + return; + } +/* if we don't find any fathers, we just release ourselves */ + release(current); +} + +int do_exit(long code) +{ + int i; + + free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); + free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); + for (i=0 ; ifather == current->pid) + task[i]->father = 0; + for (i=0 ; ifilp[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->leader) + kill_session(); + current->state = TASK_ZOMBIE; + current->exit_code = code; + tell_father(current->father); + schedule(); + return (-1); /* just to suppress warnings */ +} + +int sys_exit(int error_code) +{ + return do_exit((error_code&0xff)<<8); +} + +int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options) +{ + int flag; + struct task_struct ** p; + + verify_area(stat_addr,4); +repeat: + flag=0; + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if (!*p || *p == current) + continue; + if ((*p)->father != current->pid) + continue; + if (pid>0) { + if ((*p)->pid != pid) + continue; + } else if (!pid) { + if ((*p)->pgrp != current->pgrp) + continue; + } else if (pid != -1) { + if ((*p)->pgrp != -pid) + continue; + } + switch ((*p)->state) { + case TASK_STOPPED: + if (!(options & WUNTRACED)) + continue; + put_fs_long(0x7f,stat_addr); + return (*p)->pid; + case TASK_ZOMBIE: + current->cutime += (*p)->utime; + current->cstime += (*p)->stime; + flag = (*p)->pid; + put_fs_long((*p)->exit_code,stat_addr); + release(*p); + return flag; + default: + flag=1; + continue; + } + } + if (flag) { + if (options & WNOHANG) + return 0; + current->state=TASK_INTERRUPTIBLE; + schedule(); + if (!(current->signal &= ~(1<<(SIGCHLD-1)))) + goto repeat; + else + return -EINTR; + } + return -ECHILD; +} + + diff --git a/kernel/0.1x/linux-0.10/kernel/fork.c b/kernel/0.1x/linux-0.10/kernel/fork.c new file mode 100644 index 00000000..6d8c3633 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/fork.c @@ -0,0 +1,142 @@ +/* + * linux/kernel/fork.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'fork.c' contains the help-routines for the 'fork' system call + * (see also system_call.s), and some misc functions ('verify_area'). + * Fork is rather simple, once you get the hang of it, but the memory + * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()' + */ +#include + +#include +#include +#include +#include + +extern void write_verify(unsigned long address); + +long last_pid=0; + +void verify_area(void * addr,int size) +{ + unsigned long start; + + start = (unsigned long) addr; + size += start & 0xfff; + start &= 0xfffff000; + start += get_base(current->ldt[2]); + while (size>0) { + size -= 4096; + write_verify(start); + start += 4096; + } +} + +int copy_mem(int nr,struct task_struct * p) +{ + unsigned long old_data_base,new_data_base,data_limit; + unsigned long old_code_base,new_code_base,code_limit; + + code_limit=get_limit(0x0f); + data_limit=get_limit(0x17); + old_code_base = get_base(current->ldt[1]); + old_data_base = get_base(current->ldt[2]); + if (old_data_base != old_code_base) + panic("We don't support separate I&D"); + if (data_limit < code_limit) + panic("Bad data_limit"); + new_data_base = new_code_base = nr * 0x4000000; + 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; ifilp[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 ; ipid == last_pid) goto repeat; + for(i=1 ; i +#include +#include + +struct bucket_desc { /* 16 bytes */ + void *page; + struct bucket_desc *next; + void *freeptr; + unsigned short refcnt; + unsigned short bucket_size; +}; + +struct _bucket_dir { /* 8 bytes */ + int size; + struct bucket_desc *chain; +}; + +/* + * The following is the where we store a pointer to the first bucket + * descriptor for a given size. + * + * If it turns out that the Linux kernel allocates a lot of objects of a + * specific size, then we may want to add that specific size to this list, + * since that will allow the memory to be allocated more efficiently. + * However, since an entire page must be dedicated to each specific size + * on this list, some amount of temperance must be exercised here. + * + * Note that this list *must* be kept in order. + */ +struct _bucket_dir bucket_dir[] = { + { 16, (struct bucket_desc *) 0}, + { 32, (struct bucket_desc *) 0}, + { 64, (struct bucket_desc *) 0}, + { 128, (struct bucket_desc *) 0}, + { 256, (struct bucket_desc *) 0}, + { 512, (struct bucket_desc *) 0}, + { 1024, (struct bucket_desc *) 0}, + { 2048, (struct bucket_desc *) 0}, + { 4096, (struct bucket_desc *) 0}, + { 0, (struct bucket_desc *) 0}}; /* End of list marker */ + +/* + * This contains a linked list of free bucket descriptor blocks + */ +struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0; + +/* + * This routine initializes a bucket description page. + */ +static inline void init_bucket_desc() +{ + struct bucket_desc *bdesc, *first; + int i; + + first = bdesc = (struct bucket_desc *) get_free_page(); + if (!bdesc) + panic("Out of memory in init_bucket_desc()"); + for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) { + bdesc->next = bdesc+1; + bdesc++; + } + /* + * This is done last, to avoid race conditions in case + * get_free_page() sleeps and this routine gets called again.... + */ + bdesc->next = free_bucket_desc; + free_bucket_desc = first; +} + +void *malloc(unsigned int len) +{ + struct _bucket_dir *bdir; + struct bucket_desc *bdesc; + void *retval; + + /* + * First we search the bucket_dir to find the right bucket change + * for this request. + */ + for (bdir = bucket_dir; bdir->size; bdir++) + if (bdir->size >= len) + break; + if (!bdir->size) { + printk("malloc called with impossibly large argument (%d)\n", + len); + panic("malloc: bad arg"); + } + /* + * Now we search for a bucket descriptor which has free space + */ + cli(); /* Avoid race conditions */ + for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) + if (bdesc->freeptr) + break; + /* + * If we didn't find a bucket with free space, then we'll + * allocate a new one. + */ + if (!bdesc) { + char *cp; + int i; + + if (!free_bucket_desc) + init_bucket_desc(); + bdesc = free_bucket_desc; + free_bucket_desc = bdesc->next; + bdesc->refcnt = 0; + bdesc->bucket_size = bdir->size; + bdesc->page = bdesc->freeptr = (void *) cp = get_free_page(); + if (!cp) + panic("Out of memory in kernel malloc()"); + /* Set up the chain of free objects */ + for (i=PAGE_SIZE/bdir->size; i > 1; i--) { + *((char **) cp) = cp + bdir->size; + cp += bdir->size; + } + *((char **) cp) = 0; + bdesc->next = bdir->chain; /* OK, link it in! */ + bdir->chain = bdesc; + } + retval = (void *) bdesc->freeptr; + bdesc->freeptr = *((void **) retval); + bdesc->refcnt++; + sti(); /* OK, we're safe again */ + return(retval); +} + +/* + * Here is the free routine. If you know the size of the object that you + * are freeing, then free_s() will use that information to speed up the + * search for the bucket descriptor. + * + * We will #define a macro so that "free(x)" is becomes "free_s(x, 0)" + */ +void free_s(void *obj, int size) +{ + void *page; + struct _bucket_dir *bdir; + struct bucket_desc *bdesc, *prev; + + /* Calculate what page this object lives in */ + page = (void *) ((unsigned long) obj & 0xfffff000); + /* Now search the buckets looking for that page */ + for (bdir = bucket_dir; bdir->size; bdir++) { + prev = 0; + /* If size is zero then this conditional is always false */ + if (bdir->size < size) + continue; + for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) { + if (bdesc->page == page) + goto found; + prev = bdesc; + } + } + panic("Bad address passed to kernel free_s()"); +found: + cli(); /* To avoid race conditions */ + *((void **)obj) = bdesc->freeptr; + bdesc->freeptr = obj; + bdesc->refcnt--; + if (bdesc->refcnt == 0) { + /* + * We need to make sure that prev is still accurate. It + * may not be, if someone rudely interrupted us.... + */ + if ((prev && (prev->next != bdesc)) || + (!prev && (bdir->chain != bdesc))) + for (prev = bdir->chain; prev; prev = prev->next) + if (prev->next == bdesc) + break; + if (prev) + prev->next = bdesc->next; + else { + if (bdir->chain != bdesc) + panic("malloc bucket chains corrupted"); + bdir->chain = bdesc->next; + } + free_page((unsigned long) bdesc->page); + bdesc->next = free_bucket_desc; + free_bucket_desc = bdesc; + } + sti(); + return; +} + diff --git a/kernel/0.1x/linux-0.10/kernel/mktime.c b/kernel/0.1x/linux-0.10/kernel/mktime.c new file mode 100644 index 00000000..ccb7cb22 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/mktime.c @@ -0,0 +1,58 @@ +/* + * linux/kernel/mktime.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +/* + * This isn't the library routine, it is only used in the kernel. + * as such, we don't care about years<1970 etc, but assume everything + * is ok. Similarly, TZ etc is happily ignored. We just do everything + * as easily as possible. Let's find something public for the library + * routines (although I think minix times is public). + */ +/* + * PS. I hate whoever though up the year 1970 - couldn't they have gotten + * a leap-year instead? I also hate Gregorius, pope or no. I'm grumpy. + */ +#define MINUTE 60 +#define HOUR (60*MINUTE) +#define DAY (24*HOUR) +#define YEAR (365*DAY) + +/* interestingly, we assume leap-years */ +static int month[12] = { + 0, + DAY*(31), + DAY*(31+29), + DAY*(31+29+31), + DAY*(31+29+31+30), + DAY*(31+29+31+30+31), + DAY*(31+29+31+30+31+30), + DAY*(31+29+31+30+31+30+31), + DAY*(31+29+31+30+31+30+31+31), + DAY*(31+29+31+30+31+30+31+31+30), + DAY*(31+29+31+30+31+30+31+31+30+31), + DAY*(31+29+31+30+31+30+31+31+30+31+30) +}; + +long kernel_mktime(struct tm * tm) +{ + long res; + int year; + + 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/kernel/0.1x/linux-0.10/kernel/panic.c b/kernel/0.1x/linux-0.10/kernel/panic.c new file mode 100644 index 00000000..6624d505 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/panic.c @@ -0,0 +1,24 @@ +/* + * linux/kernel/panic.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This function is used through-out the kernel (includeinh mm and fs) + * to indicate a major problem. + */ +#include +#include + +void sys_sync(void); /* it's really int */ + +volatile void panic(const char * s) +{ + printk("Kernel panic: %s\n\r",s); + if (current == task[0]) + printk("In swapper task - not syncing\n\r"); + else + sys_sync(); + for(;;); +} diff --git a/kernel/0.1x/linux-0.10/kernel/printk.c b/kernel/0.1x/linux-0.10/kernel/printk.c new file mode 100644 index 00000000..79cfba04 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/printk.c @@ -0,0 +1,41 @@ +/* + * linux/kernel/printk.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * When in kernel-mode, we cannot use printf, as fs is liable to + * point to 'interesting' things. Make a printf with fs-saving, and + * all is well. + */ +#include +#include + +#include + +static char buf[1024]; + +extern int vsprintf(char * buf, const char * fmt, va_list args); + +int printk(const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + __asm__("push %%fs\n\t" + "push %%ds\n\t" + "pop %%fs\n\t" + "pushl %0\n\t" + "pushl $_buf\n\t" + "pushl $0\n\t" + "call _tty_write\n\t" + "addl $8,%%esp\n\t" + "popl %0\n\t" + "pop %%fs" + ::"r" (i):"ax","cx","dx"); + return i; +} diff --git a/kernel/0.1x/linux-0.10/kernel/sched.c b/kernel/0.1x/linux-0.10/kernel/sched.c new file mode 100644 index 00000000..8c920bb0 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/sched.c @@ -0,0 +1,414 @@ +/* + * linux/kernel/sched.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'sched.c' is the main kernel file. It contains scheduling primitives + * (sleep_on, wakeup, schedule etc) as well as a number of simple system + * call functions (type getpid(), which just extracts a field from + * current-task + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#define _S(nr) (1<<((nr)-1)) +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + +void show_task(int nr,struct task_struct * p) +{ + printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state); + printk("eip=%04x:%08x\n\r",p->tss.cs&0xffff,p->tss.eip); +} + +void show_stat(void) +{ + int i; + + for (i=0;i>2 ] ; + +struct { + long * a; + short b; + } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 }; +/* + * 'math_state_restore()' saves the current math information in the + * old math state array, and gets the new ones from the current task + */ +void math_state_restore() +{ + if (last_task_used_math == current) + return; + 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 & ~(_BLOCKABLE & (*p)->blocked)) && + (*p)->state==TASK_INTERRUPTIBLE) + (*p)->state=TASK_RUNNING; + } + +/* this is the scheduler proper: */ + + while (1) { + c = -1; + next = 0; + i = NR_TASKS; + p = &task[NR_TASKS]; + while (--i) { + if (!*--p) + continue; + if ((*p)->state == TASK_RUNNING && (*p)->counter > c) + c = (*p)->counter, next = i; + } + if (c) break; + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if (*p) + (*p)->counter = ((*p)->counter >> 1) + + (*p)->priority; + } + switch_to(next); +} + +int sys_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return 0; +} + +void sleep_on(struct task_struct **p) +{ + struct task_struct *tmp; + + if (!p) + return; + if (current == &(init_task.task)) + panic("task[0] trying to sleep"); + tmp = *p; + *p = current; + current->state = TASK_UNINTERRUPTIBLE; + schedule(); + if (tmp) + tmp->state=0; +} + +void interruptible_sleep_on(struct task_struct **p) +{ + struct task_struct *tmp; + + if (!p) + return; + if (current == &(init_task.task)) + panic("task[0] trying to sleep"); + tmp=*p; + *p=current; +repeat: current->state = TASK_INTERRUPTIBLE; + schedule(); + if (*p && *p != current) { + (**p).state=0; + goto repeat; + } + *p=NULL; + if (tmp) + tmp->state=0; +} + +void wake_up(struct task_struct **p) +{ + if (p && *p) { + (**p).state=0; + *p=NULL; + } +} + +/* + * OK, here are some floppy things that shouldn't be in the kernel + * proper. They are here because the floppy needs a timer, and this + * was the easiest way of doing it. + */ +static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL}; +static int mon_timer[4]={0,0,0,0}; +static int moff_timer[4]={0,0,0,0}; +unsigned char current_DOR = 0x0C; +unsigned char selected = 0; +struct task_struct * wait_on_floppy_select = NULL; + +void floppy_select(unsigned int nr) +{ + if (nr>3) + printk("floppy_select: nr>3\n\r"); + cli(); + while (selected) + sleep_on(&wait_on_floppy_select); + current_DOR &= 0xFC; + current_DOR |= nr; + outb(current_DOR,FD_DOR); + sti(); +} + +void floppy_deselect(unsigned int nr) +{ + if (nr != (current_DOR & 3)) + printk("floppy_deselect: drive not selected\n\r"); + selected = 0; + wake_up(&wait_on_floppy_select); +} + +int ticks_to_floppy_on(unsigned int nr) +{ + unsigned char mask = 1<<(nr+4); + + if (nr>3) + panic("floppy_on: nr>3"); + moff_timer[nr]=10000; /* 100 s = very big :-) */ + cli(); /* use floppy_off to turn it off */ + if (!(mask & current_DOR)) { + current_DOR |= mask; + if (!selected) { + current_DOR &= 0xFC; + current_DOR |= nr; + } + outb(current_DOR,FD_DOR); + mon_timer[nr] = HZ; + } + sti(); + return mon_timer[nr]; +} + +void floppy_on(unsigned int nr) +{ + cli(); + while (ticks_to_floppy_on(nr)) + sleep_on(nr+wait_motor); + sti(); +} + +void floppy_off(unsigned int nr) +{ + moff_timer[nr]=3*HZ; +} + +void do_floppy_timer(void) +{ + int i; + unsigned char mask = 0x10; + + for (i=0 ; i<4 ; i++,mask <<= 1) { + if (!(mask & current_DOR)) + continue; + if (mon_timer[i]) { + if (!--mon_timer[i]) + wake_up(i+wait_motor); + } else if (!moff_timer[i]) { + current_DOR &= ~mask; + outb(current_DOR,FD_DOR); + } else + moff_timer[i]--; + } +} + +#define TIME_REQUESTS 64 + +static struct timer_list { + long jiffies; + void (*fn)(); + struct timer_list * next; +} timer_list[TIME_REQUESTS], * next_timer = NULL; + +void add_timer(long jiffies, void (*fn)(void)) +{ + struct timer_list * p; + + if (!fn) + return; + cli(); + if (jiffies <= 0) + (fn)(); + else { + for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++) + if (!p->fn) + break; + if (p >= timer_list + TIME_REQUESTS) + panic("No more time requests free"); + p->fn = fn; + p->jiffies = jiffies; + p->next = next_timer; + next_timer = p; + while (p->next && p->next->jiffies < p->jiffies) { + p->jiffies -= p->next->jiffies; + fn = p->fn; + p->fn = p->next->fn; + p->next->fn = fn; + jiffies = p->jiffies; + p->jiffies = p->next->jiffies; + p->next->jiffies = jiffies; + p = p->next; + } + } + sti(); +} + +void do_timer(long cpl) +{ + if (cpl) + current->utime++; + else + current->stime++; + if (next_timer) { + next_timer->jiffies--; + while (next_timer && next_timer->jiffies <= 0) { + void (*fn)(void); + + fn = next_timer->fn; + next_timer->fn = NULL; + next_timer = next_timer->next; + (fn)(); + } + } + if (current_DOR & 0xf0) + do_floppy_timer(); + if ((--current->counter)>0) return; + current->counter=0; + if (!cpl) return; + schedule(); +} + +int sys_alarm(long seconds) +{ + int old = current->alarm; + + if (old) + old = (old - jiffies) / HZ; + current->alarm = (seconds>0)?(jiffies+HZ*seconds):0; + return (old); +} + +int sys_getpid(void) +{ + return current->pid; +} + +int sys_getppid(void) +{ + return current->father; +} + +int sys_getuid(void) +{ + return current->uid; +} + +int sys_geteuid(void) +{ + return current->euid; +} + +int sys_getgid(void) +{ + return current->gid; +} + +int sys_getegid(void) +{ + return current->egid; +} + +int sys_nice(long increment) +{ + if (current->priority-increment>0) + current->priority -= increment; + return 0; +} + +void sched_init(void) +{ + int i; + struct desc_struct * p; + + if (sizeof(struct sigaction) != 16) + panic("Struct sigaction MUST be 16 bytes"); + set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); + set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); + p = gdt+2+FIRST_TSS_ENTRY; + for(i=1;ia=p->b=0; + p++; + p->a=p->b=0; + p++; + } + 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/kernel/0.1x/linux-0.10/kernel/signal.c b/kernel/0.1x/linux-0.10/kernel/signal.c new file mode 100644 index 00000000..abbaa952 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/signal.c @@ -0,0 +1,119 @@ +/* + * linux/kernel/signal.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include + +volatile void do_exit(int error_code); + +int sys_sgetmask() +{ + return current->blocked; +} + +int sys_ssetmask(int newmask) +{ + int old=current->blocked; + + current->blocked = newmask & ~(1<<(SIGKILL-1)); + return old; +} + +static inline void save_old(char * from,char * to) +{ + int i; + + verify_area(to, sizeof(struct sigaction)); + for (i=0 ; i< sizeof(struct sigaction) ; i++) { + put_fs_byte(*from,to); + from++; + to++; + } +} + +static inline void get_new(char * from,char * to) +{ + int i; + + for (i=0 ; i< sizeof(struct sigaction) ; i++) + *(to++) = get_fs_byte(from++); +} + +int sys_signal(int signum, long handler, long restorer) +{ + struct sigaction tmp; + + if (signum<1 || signum>32 || signum==SIGKILL) + return -1; + tmp.sa_handler = (void (*)(int)) handler; + tmp.sa_mask = 0; + tmp.sa_flags = SA_ONESHOT | SA_NOMASK; + tmp.sa_restorer = (void (*)(void)) restorer; + handler = (long) current->sigaction[signum-1].sa_handler; + current->sigaction[signum-1] = tmp; + return handler; +} + +int sys_sigaction(int signum, const struct sigaction * action, + struct sigaction * oldaction) +{ + struct sigaction tmp; + + if (signum<1 || signum>32 || signum==SIGKILL) + return -1; + tmp = current->sigaction[signum-1]; + get_new((char *) action, + (char *) (signum-1+current->sigaction)); + if (oldaction) + save_old((char *) &tmp,(char *) oldaction); + if (current->sigaction[signum-1].sa_flags & SA_NOMASK) + current->sigaction[signum-1].sa_mask = 0; + else + current->sigaction[signum-1].sa_mask |= (1<<(signum-1)); + return 0; +} + +void do_signal(long signr,long eax, long ebx, long ecx, long edx, + long fs, long es, long ds, + long eip, long cs, long eflags, + unsigned long * esp, long ss) +{ + long sa_handler; + long old_eip=eip; + struct sigaction * sa = current->sigaction + signr - 1; + int longs; + unsigned long * tmp_esp; + + sa_handler = (long) sa->sa_handler; + if (sa_handler==1) + return; + if (!sa_handler) { + if (signr==SIGCHLD) + return; + else + do_exit(1<<(signr-1)); + } + if (sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; + *(&eip) = sa_handler; + longs = (sa->sa_flags & SA_NOMASK)?7:8; + *(&esp) -= longs; + verify_area(esp,longs*4); + tmp_esp=esp; + put_fs_long((long) sa->sa_restorer,tmp_esp++); + put_fs_long(signr,tmp_esp++); + if (!(sa->sa_flags & SA_NOMASK)) + put_fs_long(current->blocked,tmp_esp++); + put_fs_long(eax,tmp_esp++); + put_fs_long(ecx,tmp_esp++); + put_fs_long(edx,tmp_esp++); + put_fs_long(eflags,tmp_esp++); + put_fs_long(old_eip,tmp_esp++); + current->blocked |= sa->sa_mask; +} diff --git a/kernel/0.1x/linux-0.10/kernel/sys.c b/kernel/0.1x/linux-0.10/kernel/sys.c new file mode 100644 index 00000000..1539d09f --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/sys.c @@ -0,0 +1,236 @@ +/* + * linux/kernel/sys.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include +#include +#include +#include +#include + +int sys_ftime() +{ + return -ENOSYS; +} + +int sys_break() +{ + return -ENOSYS; +} + +int sys_ptrace() +{ + return -ENOSYS; +} + +int sys_stty() +{ + return -ENOSYS; +} + +int sys_gtty() +{ + return -ENOSYS; +} + +int sys_rename() +{ + return -ENOSYS; +} + +int sys_prof() +{ + return -ENOSYS; +} + +int sys_setregid(int rgid, int egid) +{ + if (rgid>0) { + if ((current->gid == rgid) || + suser()) + current->gid = rgid; + else + return(-EPERM); + } + if (egid>0) { + if ((current->gid == egid) || + (current->egid == egid) || + (current->sgid == egid) || + suser()) + current->egid = egid; + else + return(-EPERM); + } + return 0; +} + +int sys_setgid(int gid) +{ + return(sys_setregid(gid, gid)); +} + +int sys_acct() +{ + return -ENOSYS; +} + +int sys_phys() +{ + return -ENOSYS; +} + +int sys_lock() +{ + return -ENOSYS; +} + +int sys_mpx() +{ + return -ENOSYS; +} + +int sys_ulimit() +{ + return -ENOSYS; +} + +int sys_time(long * tloc) +{ + int i; + + i = CURRENT_TIME; + if (tloc) { + verify_area(tloc,4); + put_fs_long(i,(unsigned long *)tloc); + } + return i; +} + +/* + * Unprivileged users may change the real user id to the effective uid + * or vice versa. + */ +int sys_setreuid(int ruid, int euid) +{ + int old_ruid = current->uid; + + if (ruid>0) { + if ((current->euid==ruid) || + (old_ruid == ruid) || + suser()) + current->uid = ruid; + else + return(-EPERM); + } + if (euid>0) { + if ((old_ruid == euid) || + (current->euid == euid) || + suser()) + current->euid = euid; + else { + current->uid = old_ruid; + return(-EPERM); + } + } + return 0; +} + +int sys_setuid(int uid) +{ + return(sys_setreuid(uid, uid)); +} + +int sys_stime(long * tptr) +{ + if (!suser()) + return -EPERM; + startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ; + return 0; +} + +int sys_times(struct tms * tbuf) +{ + if (tbuf) { + verify_area(tbuf,sizeof *tbuf); + put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime); + put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime); + put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime); + put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime); + } + return jiffies; +} + +int sys_brk(unsigned long end_data_seg) +{ + if (end_data_seg >= current->end_code && + end_data_seg < current->start_stack - 16384) + current->brk = end_data_seg; + return current->brk; +} + +/* + * This needs some heave checking ... + * I just haven't get the stomach for it. I also don't fully + * understand sessions/pgrp etc. Let somebody who does explain it. + */ +int sys_setpgid(int pid, int pgid) +{ + int i; + + if (!pid) + pid = current->pid; + if (!pgid) + pgid = current->pid; + for (i=0 ; ipid==pid) { + if (task[i]->leader) + return -EPERM; + if (task[i]->session != current->session) + return -EPERM; + task[i]->pgrp = pgid; + return 0; + } + return -ESRCH; +} + +int sys_getpgrp(void) +{ + return current->pgrp; +} + +int sys_setsid(void) +{ + if (current->leader && !suser()) + return -EPERM; + current->leader = 1; + current->session = current->pgrp = current->pid; + current->tty = -1; + return current->pgrp; +} + +int sys_uname(struct utsname * name) +{ + static struct utsname thisname = { + "linux .0","nodename","release ","version ","machine " + }; + int i; + + if (!name) return -ERROR; + verify_area(name,sizeof *name); + for(i=0;iumask; + + current->umask = mask & 0777; + return (old); +} diff --git a/kernel/0.1x/linux-0.10/kernel/system_call.s b/kernel/0.1x/linux-0.10/kernel/system_call.s new file mode 100644 index 00000000..6d499cb1 --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/system_call.s @@ -0,0 +1,235 @@ +/* + * linux/kernel/system_call.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * system_call.s contains the system-call low-level handling routines. + * This also contains the timer-interrupt handler, as some of the code is + * the same. The hd- and flopppy-interrupts are also here. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. Ordinary interrupts + * don't handle signal-recognition, as that would clutter them up totally + * unnecessarily. + * + * Stack layout in 'ret_from_system_call': + * + * 0(%esp) - %eax + * 4(%esp) - %ebx + * 8(%esp) - %ecx + * C(%esp) - %edx + * 10(%esp) - %fs + * 14(%esp) - %es + * 18(%esp) - %ds + * 1C(%esp) - %eip + * 20(%esp) - %cs + * 24(%esp) - %eflags + * 28(%esp) - %oldesp + * 2C(%esp) - %oldss + */ + +SIG_CHLD = 17 + +EAX = 0x00 +EBX = 0x04 +ECX = 0x08 +EDX = 0x0C +FS = 0x10 +ES = 0x14 +DS = 0x18 +EIP = 0x1C +CS = 0x20 +EFLAGS = 0x24 +OLDESP = 0x28 +OLDSS = 0x2C + +state = 0 # these are offsets into the task-struct. +counter = 4 +priority = 8 +signal = 12 +sigaction = 16 # MUST be 16 (=len of sigaction) +blocked = (33*16) + +# offsets within sigaction +sa_handler = 0 +sa_mask = 4 +sa_flags = 8 +sa_restorer = 12 + +nr_system_calls = 70 + +/* + * Ok, I get parallel printer interrupts while using the floppy for some + * strange reason. Urgel. Now I just ignore them. + */ +.globl _system_call,_sys_fork,_timer_interrupt,_sys_execve +.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt + +.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 + cmpw $0x0f,CS(%esp) # was old code segment supervisor ? + jne 3f + cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ? + jne 3f + movl signal(%eax),%ebx + movl blocked(%eax),%ecx + notl %ecx + andl %ebx,%ecx + bsfl %ecx,%ecx + je 3f + btrl %ecx,%ebx + movl %ebx,signal(%eax) + incl %ecx + pushl %ecx + call _do_signal + popl %eax +3: popl %eax + popl %ebx + popl %ecx + popl %edx + pop %fs + pop %es + pop %ds + iret + +.align 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 + 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 + +_floppy_interrupt: + pushl %eax + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + movb $0x20,%al + outb %al,$0x20 # EOI to interrupt controller #1 + movl _do_floppy,%eax + testl %eax,%eax + jne 1f + movl $_unexpected_floppy_interrupt,%eax +1: call *%eax # "interesting" way of handling intr. + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +_parallel_interrupt: + pushl %eax + movb $0x20,%al + outb %al,$0x20 + popl %eax + iret diff --git a/kernel/0.1x/linux-0.10/kernel/traps.c b/kernel/0.1x/linux-0.10/kernel/traps.c new file mode 100644 index 00000000..bafdd87e --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/traps.c @@ -0,0 +1,208 @@ +/* + * linux/kernel/traps.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'asm.s'. Currently mostly a debugging-aid, will be extended + * to mainly kill the offending process (probably by giving it a signal, + * but possibly by killing it outright if necessary). + */ +#include + +#include +#include +#include +#include +#include +#include + +#define get_seg_byte(seg,addr) ({ \ +register char __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define get_seg_long(seg,addr) ({ \ +register unsigned long __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define _fs() ({ \ +register unsigned short __res; \ +__asm__("mov %%fs,%%ax":"=a" (__res):); \ +__res;}) + +int do_exit(long code); + +void page_exception(void); + +void divide_error(void); +void debug(void); +void nmi(void); +void int3(void); +void overflow(void); +void bounds(void); +void invalid_op(void); +void device_not_available(void); +void double_fault(void); +void coprocessor_segment_overrun(void); +void invalid_TSS(void); +void segment_not_present(void); +void stack_segment(void); +void general_protection(void); +void page_fault(void); +void coprocessor_error(void); +void reserved(void); +void parallel_interrupt(void); +void irq13(void); + +static void die(char * str,long esp_ptr,long nr) +{ + long * esp = (long *) esp_ptr; + int i; + + printk("%s: %04x\n\r",str,nr&0xffff); + printk("EIP:\t%04x:%p\nEFLAGS:\t%p\nESP:\t%04x:%p\n", + esp[1],esp[0],esp[2],esp[4],esp[3]); + printk("fs: %04x\n",_fs()); + printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x17)); + if (esp[4] == 0x17) { + printk("Stack: "); + for (i=0;i<4;i++) + printk("%p ",get_seg_long(0x17,i+(long *)esp[3])); + printk("\n"); + } + str(i); + printk("Pid: %d, process nr: %d\n\r",current->pid,0xffff & i); + for(i=0;i<10;i++) + printk("%02x ",0xff & get_seg_byte(esp[1],(i+(char *)esp[0]))); + printk("\n\r"); + do_exit(11); /* play segment exception */ +} + +void do_double_fault(long esp, long error_code) +{ + die("double fault",esp,error_code); +} + +void do_general_protection(long esp, long error_code) +{ + die("general protection",esp,error_code); +} + +void do_divide_error(long esp, long error_code) +{ + die("divide error",esp,error_code); +} + +void do_int3(long * esp, long error_code, + long fs,long es,long ds, + long ebp,long esi,long edi, + long edx,long ecx,long ebx,long eax) +{ + int tr; + + __asm__("str %%ax":"=a" (tr):"0" (0)); + printk("eax\t\tebx\t\tecx\t\tedx\n\r%8x\t%8x\t%8x\t%8x\n\r", + eax,ebx,ecx,edx); + printk("esi\t\tedi\t\tebp\t\tesp\n\r%8x\t%8x\t%8x\t%8x\n\r", + esi,edi,ebp,(long) esp); + printk("\n\rds\tes\tfs\ttr\n\r%4x\t%4x\t%4x\t%4x\n\r", + ds,es,fs,tr); + printk("EIP: %8x CS: %4x EFLAGS: %8x\n\r",esp[0],esp[1],esp[2]); +} + +void do_nmi(long esp, long error_code) +{ + die("nmi",esp,error_code); +} + +void do_debug(long esp, long error_code) +{ + die("debug",esp,error_code); +} + +void do_overflow(long esp, long error_code) +{ + die("overflow",esp,error_code); +} + +void do_bounds(long esp, long error_code) +{ + die("bounds",esp,error_code); +} + +void do_invalid_op(long esp, long error_code) +{ + die("invalid operand",esp,error_code); +} + +void do_device_not_available(long esp, long error_code) +{ + die("device not available",esp,error_code); +} + +void do_coprocessor_segment_overrun(long esp, long error_code) +{ + die("coprocessor segment overrun",esp,error_code); +} + +void do_invalid_TSS(long esp,long error_code) +{ + die("invalid TSS",esp,error_code); +} + +void do_segment_not_present(long esp,long error_code) +{ + die("segment not present",esp,error_code); +} + +void do_stack_segment(long esp,long error_code) +{ + die("stack segment",esp,error_code); +} + +void do_coprocessor_error(long esp, long error_code) +{ + if (last_task_used_math != current) + return; + die("coprocessor error",esp,error_code); +} + +void do_reserved(long esp, long error_code) +{ + die("reserved (15,17-47) error",esp,error_code); +} + +void trap_init(void) +{ + int i; + + set_trap_gate(0,÷_error); + set_trap_gate(1,&debug); + set_trap_gate(2,&nmi); + set_system_gate(3,&int3); /* int3-5 can be called from all */ + set_system_gate(4,&overflow); + set_system_gate(5,&bounds); + set_trap_gate(6,&invalid_op); + set_trap_gate(7,&device_not_available); + set_trap_gate(8,&double_fault); + set_trap_gate(9,&coprocessor_segment_overrun); + set_trap_gate(10,&invalid_TSS); + set_trap_gate(11,&segment_not_present); + set_trap_gate(12,&stack_segment); + set_trap_gate(13,&general_protection); + set_trap_gate(14,&page_fault); + set_trap_gate(15,&reserved); + set_trap_gate(16,&coprocessor_error); + for (i=17;i<48;i++) + set_trap_gate(i,&reserved); + set_trap_gate(45,&irq13); + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xdf,0xA1); + set_trap_gate(39,¶llel_interrupt); +} diff --git a/kernel/0.1x/linux-0.10/kernel/vsprintf.c b/kernel/0.1x/linux-0.10/kernel/vsprintf.c new file mode 100644 index 00000000..9bfd010b --- /dev/null +++ b/kernel/0.1x/linux-0.10/kernel/vsprintf.c @@ -0,0 +1,233 @@ +/* + * linux/kernel/vsprintf.c + * + * (C) 1991 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include +#include + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ + +#define do_div(n,base) ({ \ +int __res; \ +__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ +__res; }) + +static char * number(char * str, int num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[36]; + const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + + if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; + if (type&LEFT) type &= ~ZEROPAD; + if (base<2 || base>36) + return 0; + c = (type & ZEROPAD) ? '0' : ' ' ; + if (type&SIGN && num<0) { + sign='-'; + num = -num; + } else + sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); + if (sign) size--; + if (type&SPECIAL) + if (base==16) size -= 2; + else if (base==8) size--; + i=0; + if (num==0) + tmp[i++]='0'; + else while (num!=0) + tmp[i++]=digits[do_div(num,base)]; + if (i>precision) precision=i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type&SPECIAL) + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + if (!(type&LEFT)) + while(size-->0) + *str++ = c; + while(i0) + *str++ = tmp[i]; + while(size-->0) + *str++ = ' '; + return str; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + int i; + char * str; + char *s; + int *ip; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + break; + + case 's': + s = va_arg(args, char *); + len = strlen(s); + if (precision < 0) + precision = len; + else if (len > precision) + len = precision; + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + break; + + case 'o': + str = number(str, va_arg(args, unsigned long), 8, + field_width, precision, flags); + break; + + case 'p': + if (field_width == -1) { + field_width = 8; + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + break; + + case 'x': + flags |= SMALL; + case 'X': + str = number(str, va_arg(args, unsigned long), 16, + field_width, precision, flags); + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + str = number(str, va_arg(args, unsigned long), 10, + field_width, precision, flags); + break; + + case 'n': + ip = va_arg(args, int *); + *ip = (str - buf); + break; + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + break; + } + } + *str = '\0'; + return str-buf; +} diff --git a/kernel/0.1x/linux-0.10/lib/Makefile b/kernel/0.1x/linux-0.10/lib/Makefile new file mode 100644 index 00000000..3a912bbc --- /dev/null +++ b/kernel/0.1x/linux-0.10/lib/Makefile @@ -0,0 +1,71 @@ +# +# 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: +_exit.s _exit.o : _exit.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +close.s close.o : close.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +ctype.s ctype.o : ctype.c ../include/ctype.h +dup.s dup.o : dup.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +errno.s errno.o : errno.c +execve.s execve.o : execve.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +open.s open.o : open.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h ../include/stdarg.h +setsid.s setsid.o : setsid.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +string.s string.o : string.c ../include/string.h +wait.s wait.o : wait.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h ../include/sys/wait.h +write.s write.o : write.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h diff --git a/kernel/0.1x/linux-0.10/lib/_exit.c b/kernel/0.1x/linux-0.10/lib/_exit.c new file mode 100644 index 00000000..50f1c8fa --- /dev/null +++ b/kernel/0.1x/linux-0.10/lib/_exit.c @@ -0,0 +1,13 @@ +/* + * linux/lib/_exit.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +volatile void _exit(int exit_code) +{ + __asm__("int $0x80"::"a" (__NR_exit),"b" (exit_code)); +} diff --git a/kernel/0.1x/linux-0.10/lib/close.c b/kernel/0.1x/linux-0.10/lib/close.c new file mode 100644 index 00000000..98e5ceee --- /dev/null +++ b/kernel/0.1x/linux-0.10/lib/close.c @@ -0,0 +1,10 @@ +/* + * linux/lib/close.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall1(int,close,int,fd) diff --git a/kernel/0.1x/linux-0.10/lib/ctype.c b/kernel/0.1x/linux-0.10/lib/ctype.c new file mode 100644 index 00000000..9ac21819 --- /dev/null +++ b/kernel/0.1x/linux-0.10/lib/ctype.c @@ -0,0 +1,35 @@ +/* + * linux/lib/ctype.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +char _ctmp; +unsigned char _ctype[] = {0x00, /* EOF */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */ + diff --git a/kernel/0.1x/linux-0.10/lib/dup.c b/kernel/0.1x/linux-0.10/lib/dup.c new file mode 100644 index 00000000..d56d6d07 --- /dev/null +++ b/kernel/0.1x/linux-0.10/lib/dup.c @@ -0,0 +1,10 @@ +/* + * linux/lib/dup.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall1(int,dup,int,fd) diff --git a/kernel/0.1x/linux-0.10/lib/errno.c b/kernel/0.1x/linux-0.10/lib/errno.c new file mode 100644 index 00000000..b6d10473 --- /dev/null +++ b/kernel/0.1x/linux-0.10/lib/errno.c @@ -0,0 +1,7 @@ +/* + * linux/lib/errno.c + * + * (C) 1991 Linus Torvalds + */ + +int errno; diff --git a/kernel/0.1x/linux-0.10/lib/execve.c b/kernel/0.1x/linux-0.10/lib/execve.c new file mode 100644 index 00000000..67f22cb0 --- /dev/null +++ b/kernel/0.1x/linux-0.10/lib/execve.c @@ -0,0 +1,10 @@ +/* + * linux/lib/execve.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall3(int,execve,const char *,file,char **,argv,char **,envp) diff --git a/kernel/0.1x/linux-0.10/lib/open.c b/kernel/0.1x/linux-0.10/lib/open.c new file mode 100644 index 00000000..9b95a8f3 --- /dev/null +++ b/kernel/0.1x/linux-0.10/lib/open.c @@ -0,0 +1,25 @@ +/* + * linux/lib/open.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +int open(const char * filename, int flag, ...) +{ + register int res; + va_list arg; + + va_start(arg,flag); + __asm__("int $0x80" + :"=a" (res) + :"0" (__NR_open),"b" (filename),"c" (flag), + "d" (va_arg(arg,int))); + if (res>=0) + return res; + errno = -res; + return -1; +} diff --git a/kernel/0.1x/linux-0.10/lib/setsid.c b/kernel/0.1x/linux-0.10/lib/setsid.c new file mode 100644 index 00000000..b47a358f --- /dev/null +++ b/kernel/0.1x/linux-0.10/lib/setsid.c @@ -0,0 +1,10 @@ +/* + * linux/lib/setsid.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall0(pid_t,setsid) diff --git a/kernel/0.1x/linux-0.10/lib/string.c b/kernel/0.1x/linux-0.10/lib/string.c new file mode 100644 index 00000000..e4ef9257 --- /dev/null +++ b/kernel/0.1x/linux-0.10/lib/string.c @@ -0,0 +1,14 @@ +/* + * linux/lib/string.c + * + * (C) 1991 Linus Torvalds + */ + +#ifndef __GNUC__ +#error I want gcc! +#endif + +#define extern +#define inline +#define __LIBRARY__ +#include diff --git a/kernel/0.1x/linux-0.10/lib/wait.c b/kernel/0.1x/linux-0.10/lib/wait.c new file mode 100644 index 00000000..72f27313 --- /dev/null +++ b/kernel/0.1x/linux-0.10/lib/wait.c @@ -0,0 +1,16 @@ +/* + * linux/lib/wait.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +_syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) + +pid_t wait(int * wait_stat) +{ + return waitpid(-1,wait_stat,0); +} diff --git a/kernel/0.1x/linux-0.10/lib/write.c b/kernel/0.1x/linux-0.10/lib/write.c new file mode 100644 index 00000000..68ea9cf9 --- /dev/null +++ b/kernel/0.1x/linux-0.10/lib/write.c @@ -0,0 +1,10 @@ +/* + * linux/lib/write.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall3(int,write,int,fd,const char *,buf,off_t,count) diff --git a/kernel/0.1x/linux-0.10/mm/Makefile b/kernel/0.1x/linux-0.10/mm/Makefile new file mode 100644 index 00000000..8eb975e2 --- /dev/null +++ b/kernel/0.1x/linux-0.10/mm/Makefile @@ -0,0 +1,36 @@ +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/head.h ../include/linux/kernel.h ../include/asm/system.h diff --git a/kernel/0.1x/linux-0.10/mm/memory.c b/kernel/0.1x/linux-0.10/mm/memory.c new file mode 100644 index 00000000..51880192 --- /dev/null +++ b/kernel/0.1x/linux-0.10/mm/memory.c @@ -0,0 +1,277 @@ +/* + * linux/mm/memory.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include +#include + +int do_exit(long code); + +#define invalidate() \ +__asm__("movl %%eax,%%cr3"::"a" (0)) + +/* these are not to be changed without changing head.s etc */ +#define LOW_MEM 0x100000 +#define PAGING_MEMORY (15*1024*1024) +#define PAGING_PAGES (PAGING_MEMORY>>12) +#define MAP_NR(addr) (((addr)-LOW_MEM)>>12) +#define USED 100 + +static long HIGH_MEMORY = 0; + +#define copy_page(from,to) \ +__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si") + +static unsigned char mem_map [ PAGING_PAGES ] = {0,}; + +/* + * Get physical address of first (actually last :-) free page, and mark it + * used. If no free pages left, return 0. + */ +unsigned long get_free_page(void) +{ +register unsigned long __res asm("ax"); + +__asm__("std ; repne ; scasb\n\t" + "jne 1f\n\t" + "movb $1,1(%%edi)\n\t" + "sall $12,%%ecx\n\t" + "addl %2,%%ecx\n\t" + "movl %%ecx,%%edx\n\t" + "movl $1024,%%ecx\n\t" + "leal 4092(%%edx),%%edi\n\t" + "rep ; stosl\n\t" + "movl %%edx,%%eax\n" + "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 mem_init(long start_mem, long end_mem) +{ + int i; + + HIGH_MEMORY = end_mem; + for (i=0 ; i>= 12; + while (end_mem-->0) + mem_map[i++]=0; +} + +void calc_mem(void) +{ + int i,j,k,free=0; + long * pg_tbl; + + for(i=0 ; i /* fprintf */ +#include +#include /* contains exit */ +#include /* unistd.h needs this */ +#include +#include +#include /* contains read/write */ +#include + +#define MINIX_HEADER 32 +#define GCC_HEADER 1024 + +#define DEFAULT_MAJOR_ROOT 3 +#define DEFAULT_MINOR_ROOT 6 + +/* max nr of sectors of setup: don't change unless you also change + * bootsect etc */ +#define SETUP_SECTS 4 + +#define STRINGIFY(x) #x + +void die(char * str) +{ + fprintf(stderr,"%s\n",str); + exit(1); +} + +void usage(void) +{ + die("Usage: build bootsect setup system [> image]"); +} + +int main(int argc, char ** argv) +{ + int i,c,id; + char buf[1024]; + char major_root, minor_root; + struct stat sb; + + if ((argc != 4) && (argc != 5)) + usage(); + if (argc == 5) { + if (strcmp(argv[4], "FLOPPY")) { + if (stat(argv[4], &sb)) { + perror(argv[4]); + die("Couldn't stat root device."); + } + major_root = MAJOR(sb.st_rdev); + minor_root = MINOR(sb.st_rdev); + } else { + major_root = 0; + minor_root = 0; + } + } else { + major_root = DEFAULT_MAJOR_ROOT; + minor_root = DEFAULT_MINOR_ROOT; + } + fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); + if ((major_root != 2) && (major_root != 3) && + (major_root != 0)) { + fprintf(stderr, "Illegal root device (major = %d)\n", + major_root); + die("Bad root device --- major #"); + } + for (i=0;i0 ; i+=c ) + if (write(1,buf,c)!=c) + die("Write call failed"); + close (id); + if (i > SETUP_SECTS*512) + die("Setup exceeds " STRINGIFY(SETUP_SECTS) + " sectors - rewrite build/boot/setup"); + fprintf(stderr,"Setup is %d bytes.\n",i); + for (c=0 ; c sizeof(buf)) + c = sizeof(buf); + if (write(1,buf,c) != c) + die("Write call failed"); + i += c; + } + + if ((id=open(argv[3],O_RDONLY,0))<0) + die("Unable to open 'system'"); + if (read(id,buf,GCC_HEADER) != GCC_HEADER) + die("Unable to read header of 'system'"); + if (((long *) buf)[5] != 0) + die("Non-GCC header of 'system'"); + for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c ) + if (write(1,buf,c)!=c) + die("Write call failed"); + close(id); + fprintf(stderr,"System is %d bytes.\n",i); + return(0); +} diff --git a/kernel/0.1x/linux-0.11-030920.tar.gz b/kernel/0.1x/linux-0.11-030920.tar.gz new file mode 100644 index 00000000..baa3b3d9 Binary files /dev/null and b/kernel/0.1x/linux-0.11-030920.tar.gz differ diff --git a/kernel/0.1x/linux-0.11-040327-rh9.diff.gz b/kernel/0.1x/linux-0.11-040327-rh9.diff.gz new file mode 100644 index 00000000..86fb08a9 Binary files /dev/null and b/kernel/0.1x/linux-0.11-040327-rh9.diff.gz differ diff --git a/kernel/0.1x/linux-0.11-040327-rh9.tar.gz b/kernel/0.1x/linux-0.11-040327-rh9.tar.gz new file mode 100644 index 00000000..ad0bb029 Binary files /dev/null and b/kernel/0.1x/linux-0.11-040327-rh9.tar.gz differ diff --git a/kernel/0.1x/linux-0.11-060617-gcc4-diff.gz b/kernel/0.1x/linux-0.11-060617-gcc4-diff.gz new file mode 100644 index 00000000..0e2829be Binary files /dev/null and b/kernel/0.1x/linux-0.11-060617-gcc4-diff.gz differ diff --git a/kernel/0.1x/linux-0.11-060618-gcc4.tar.gz b/kernel/0.1x/linux-0.11-060618-gcc4.tar.gz new file mode 100644 index 00000000..790341d0 Binary files /dev/null and b/kernel/0.1x/linux-0.11-060618-gcc4.tar.gz differ diff --git a/kernel/0.1x/linux-0.11.tar b/kernel/0.1x/linux-0.11.tar new file mode 100644 index 00000000..db11f005 Binary files /dev/null and b/kernel/0.1x/linux-0.11.tar differ diff --git a/kernel/0.1x/linux-0.11.tar.gz b/kernel/0.1x/linux-0.11.tar.gz new file mode 100644 index 00000000..e6461824 Binary files /dev/null and b/kernel/0.1x/linux-0.11.tar.gz differ diff --git a/kernel/0.1x/linux-0.11/Makefile b/kernel/0.1x/linux-0.11/Makefile new file mode 100644 index 00000000..37eb3e1b --- /dev/null +++ b/kernel/0.1x/linux-0.11/Makefile @@ -0,0 +1,123 @@ +# +# if you want the ram-disk device, define this to be the +# size in blocks. +# +RAMDISK = #-DRAMDISK=512 + +AS86 =as86 -0 -a +LD86 =ld86 -0 + +AS =gas +LD =gld +LDFLAGS =-s -x -M +CC =gcc $(RAMDISK) +CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ +-fcombine-regs -mstring-insns +CPP =cpp -nostdinc -Iinclude + +# +# ROOT_DEV specifies the default root-device when making the image. +# This can be either FLOPPY, /dev/xxxx or empty, in which case the +# default of /dev/hd6 is used by 'build'. +# +ROOT_DEV=/dev/hd6 + +ARCHIVES=kernel/kernel.o mm/mm.o fs/fs.o +DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a +MATH =kernel/math/math.a +LIBS =lib/lib.a + +.c.s: + $(CC) $(CFLAGS) \ + -nostdinc -Iinclude -S -o $*.s $< +.s.o: + $(AS) -c -o $*.o $< +.c.o: + $(CC) $(CFLAGS) \ + -nostdinc -Iinclude -c -o $*.o $< + +all: Image + +Image: boot/bootsect boot/setup tools/system tools/build + tools/build boot/bootsect boot/setup tools/system $(ROOT_DEV) > Image + sync + +disk: Image + dd bs=8192 if=Image of=/dev/PS0 + +tools/build: tools/build.c + $(CC) $(CFLAGS) \ + -o tools/build tools/build.c + +boot/head.o: boot/head.s + +tools/system: boot/head.o init/main.o \ + $(ARCHIVES) $(DRIVERS) $(MATH) $(LIBS) + $(LD) $(LDFLAGS) boot/head.o init/main.o \ + $(ARCHIVES) \ + $(DRIVERS) \ + $(MATH) \ + $(LIBS) \ + -o tools/system > System.map + +kernel/math/math.a: + (cd kernel/math; make) + +kernel/blk_drv/blk_drv.a: + (cd kernel/blk_drv; make) + +kernel/chr_drv/chr_drv.a: + (cd kernel/chr_drv; make) + +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/setup: boot/setup.s + $(AS86) -o boot/setup.o boot/setup.s + $(LD86) -s -o boot/setup boot/setup.o + +boot/bootsect: boot/bootsect.s + $(AS86) -o boot/bootsect.o boot/bootsect.s + $(LD86) -s -o boot/bootsect boot/bootsect.o + +tmp.s: boot/bootsect.s tools/system + (echo -n "SYSSIZE = (";ls -l tools/system | grep system \ + | cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s + cat boot/bootsect.s >> tmp.s + +clean: + rm -f Image System.map tmp_make core boot/bootsect boot/setup + rm -f init/*.o tools/system tools/build boot/*.o + (cd mm;make clean) + (cd fs;make clean) + (cd kernel;make clean) + (cd lib;make clean) + +backup: clean + (cd .. ; tar cf - linux | compress - > 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/signal.h include/asm/system.h include/asm/io.h \ + include/stddef.h include/stdarg.h include/fcntl.h diff --git a/kernel/0.1x/linux-0.11/boot/bootsect.s b/kernel/0.1x/linux-0.11/boot/bootsect.s new file mode 100644 index 00000000..289543c9 --- /dev/null +++ b/kernel/0.1x/linux-0.11/boot/bootsect.s @@ -0,0 +1,260 @@ +! +! SYS_SIZE is the number of clicks (16 bytes) to be loaded. +! 0x3000 is 0x30000 bytes = 196kB, more than enough for current +! versions of linux +! +SYSSIZE = 0x3000 +! +! bootsect.s (C) 1991 Linus Torvalds +! +! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves +! iself out of the way to address 0x90000, and jumps there. +! +! It then loads 'setup' directly after itself (0x90200), and the system +! at 0x10000, using BIOS interrupts. +! +! NOTE! currently system is at most 8*65536 bytes long. This should be no +! problem, even in the future. I want to keep it simple. This 512 kB +! kernel size should be enough, especially as this doesn't contain the +! buffer cache as in minix +! +! The loader has been made as simple as possible, and continuos +! read errors will result in a unbreakable loop. Reboot by hand. It +! loads pretty fast by getting whole sectors at a time whenever possible. + +.globl begtext, begdata, begbss, endtext, enddata, endbss +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +SETUPLEN = 4 ! nr of setup-sectors +BOOTSEG = 0x07c0 ! original address of boot-sector +INITSEG = 0x9000 ! we move boot here - out of the way +SETUPSEG = 0x9020 ! setup starts here +SYSSEG = 0x1000 ! system loaded at 0x10000 (65536). +ENDSEG = SYSSEG + SYSSIZE ! where to stop loading + +! ROOT_DEV: 0x000 - same type of floppy as boot. +! 0x301 - first partition on first drive etc +ROOT_DEV = 0x306 + +entry start +start: + mov ax,#BOOTSEG + mov ds,ax + mov ax,#INITSEG + mov es,ax + mov cx,#256 + sub si,si + sub di,di + rep + movw + jmpi go,INITSEG +go: mov ax,cs + mov ds,ax + mov es,ax +! put stack at 0x9ff00. + mov ss,ax + mov sp,#0xFF00 ! arbitrary value >>512 + +! load the setup-sectors directly after the bootblock. +! Note that 'es' is already set up. + +load_setup: + mov dx,#0x0000 ! drive 0, head 0 + mov cx,#0x0002 ! sector 2, track 0 + mov bx,#0x0200 ! address = 512, in INITSEG + mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors + int 0x13 ! read it + jnc ok_load_setup ! ok - continue + mov dx,#0x0000 + mov ax,#0x0000 ! reset the diskette + int 0x13 + j load_setup + +ok_load_setup: + +! Get disk drive parameters, specifically nr of sectors/track + + mov dl,#0x00 + mov ax,#0x0800 ! AH=8 is get drive parameters + int 0x13 + mov ch,#0x00 + seg cs + mov sectors,cx + mov ax,#INITSEG + mov es,ax + +! Print some inane message + + mov ah,#0x03 ! read cursor pos + xor bh,bh + int 0x10 + + mov cx,#24 + mov bx,#0x0007 ! page 0, attribute 7 (normal) + mov bp,#msg1 + mov ax,#0x1301 ! write string, move cursor + int 0x10 + +! ok, we've written the message, now +! we want to load the system (at 0x10000) + + mov ax,#SYSSEG + mov es,ax ! segment of 0x010000 + call read_it + call kill_motor + +! After that we check which root-device to use. If the device is +! defined (!= 0), nothing is done and the given device is used. +! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending +! on the number of sectors that the BIOS reports currently. + + seg cs + mov ax,root_dev + cmp ax,#0 + jne root_defined + seg cs + mov bx,sectors + mov ax,#0x0208 ! /dev/ps0 - 1.2Mb + cmp bx,#15 + je root_defined + mov ax,#0x021c ! /dev/PS0 - 1.44Mb + cmp bx,#18 + je root_defined +undef_root: + jmp undef_root +root_defined: + seg cs + mov root_dev,ax + +! after that (everyting loaded), we jump to +! the setup-routine loaded directly after +! the bootblock: + + jmpi 0,SETUPSEG + +! This routine loads the system at address 0x10000, making sure +! no 64kB boundaries are crossed. We try to load it as fast as +! possible, loading whole tracks whenever we can. +! +! in: es - starting address segment (normally 0x1000) +! +sread: .word 1+SETUPLEN ! sectors read of current track +head: .word 0 ! current head +track: .word 0 ! current track + +read_it: + mov ax,es + test ax,#0x0fff +die: jne die ! es must be at 64kB boundary + xor bx,bx ! bx is starting address within segment +rp_read: + mov ax,es + cmp ax,#ENDSEG ! have we loaded all yet? + jb ok1_read + ret +ok1_read: + seg cs + mov ax,sectors + sub ax,sread + mov cx,ax + shl cx,#9 + add cx,bx + jnc ok2_read + je ok2_read + xor ax,ax + sub ax,bx + shr ax,#9 +ok2_read: + call read_track + mov cx,ax + add ax,sread + seg cs + cmp ax,sectors + jne ok3_read + mov ax,#1 + sub ax,head + jne ok4_read + inc track +ok4_read: + mov head,ax + xor ax,ax +ok3_read: + mov sread,ax + shl cx,#9 + add bx,cx + jnc rp_read + mov ax,es + add ax,#0x1000 + mov es,ax + xor bx,bx + jmp rp_read + +read_track: + push ax + push bx + push cx + push dx + mov dx,track + mov cx,sread + inc cx + mov ch,dl + mov dx,head + mov dh,dl + mov dl,#0 + and dx,#0x0100 + mov ah,#2 + int 0x13 + jc bad_rt + pop dx + pop cx + pop bx + pop ax + ret +bad_rt: mov ax,#0 + mov dx,#0 + int 0x13 + pop dx + pop cx + pop bx + pop ax + jmp read_track + +/* + * This procedure turns off the floppy drive motor, so + * that we enter the kernel in a known state, and + * don't have to worry about it later. + */ +kill_motor: + push dx + mov dx,#0x3f2 + mov al,#0 + outb + pop dx + ret + +sectors: + .word 0 + +msg1: + .byte 13,10 + .ascii "Loading system ..." + .byte 13,10,13,10 + +.org 508 +root_dev: + .word ROOT_DEV +boot_flag: + .word 0xAA55 + +.text +endtext: +.data +enddata: +.bss +endbss: diff --git a/kernel/0.1x/linux-0.11/boot/head.s b/kernel/0.1x/linux-0.11/boot/head.s new file mode 100644 index 00000000..a8ce5fab --- /dev/null +++ b/kernel/0.1x/linux-0.11/boot/head.s @@ -0,0 +1,238 @@ +/* + * linux/boot/head.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * head.s contains the 32-bit startup code. + * + * NOTE!!! Startup happens at absolute address 0x00000000, which is also where + * the page directory will exist. The startup code will be overwritten by + * the page directory. + */ +.text +.globl _idt,_gdt,_pg_dir,_tmp_floppy_area +_pg_dir: +startup_32: + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + mov %ax,%gs + lss _stack_start,%esp + call setup_idt + call setup_gdt + movl $0x10,%eax # reload all the segment registers + mov %ax,%ds # after changing gdt. CS was already + mov %ax,%es # reloaded in 'setup_gdt' + mov %ax,%fs + mov %ax,%gs + lss _stack_start,%esp + xorl %eax,%eax +1: incl %eax # check that A20 really IS enabled + movl %eax,0x000000 # loop forever if it isn't + cmpl %eax,0x100000 + je 1b +/* + * NOTE! 486 should set bit 16, to check for write-protect in supervisor + * mode. Then it would be unnecessary with the "verify_area()"-calls. + * 486 users probably want to set the NE (#5) bit also, so as to use + * int 16 for math errors. + */ + movl %cr0,%eax # check math chip + andl $0x80000011,%eax # Save PG,PE,ET +/* "orl $0x10020,%eax" here for 486 might be good */ + orl $2,%eax # set MP + movl %eax,%cr0 + call check_x87 + jmp after_page_tables + +/* + * We depend on ET to be correct. This checks for 287/387. + */ +check_x87: + fninit + fstsw %ax + cmpb $0,%al + je 1f /* no coprocessor: have to set bits */ + movl %cr0,%eax + xorl $6,%eax /* reset MP, set EM */ + movl %eax,%cr0 + ret +.align 2 +1: .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ + ret + +/* + * setup_idt + * + * sets up a idt with 256 entries pointing to + * ignore_int, interrupt gates. It then loads + * idt. Everything that wants to install itself + * in the idt-table may do so themselves. Interrupts + * are enabled elsewhere, when we can be relatively + * sure everything is ok. This routine will be over- + * written by the page tables. + */ +setup_idt: + lea ignore_int,%edx + movl $0x00080000,%eax + movw %dx,%ax /* selector = 0x0008 = cs */ + movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ + + lea _idt,%edi + mov $256,%ecx +rp_sidt: + movl %eax,(%edi) + movl %edx,4(%edi) + addl $8,%edi + dec %ecx + jne rp_sidt + lidt idt_descr + ret + +/* + * setup_gdt + * + * This routines sets up a new gdt and loads it. + * Only two entries are currently built, the same + * ones that were built in init.s. The routine + * is VERY complicated at two whole lines, so this + * rather long comment is certainly needed :-). + * This routine will beoverwritten by the page tables. + */ +setup_gdt: + lgdt gdt_descr + ret + +/* + * I put the kernel page tables right after the page directory, + * using 4 of them to span 16 Mb of physical memory. People with + * more than 16MB will have to expand this. + */ +.org 0x1000 +pg0: + +.org 0x2000 +pg1: + +.org 0x3000 +pg2: + +.org 0x4000 +pg3: + +.org 0x5000 +/* + * tmp_floppy_area is used by the floppy-driver when DMA cannot + * reach to a buffer-block. It needs to be aligned, so that it isn't + * on a 64kB border. + */ +_tmp_floppy_area: + .fill 1024,1,0 + +after_page_tables: + pushl $0 # These are the parameters to main :-) + pushl $0 + pushl $0 + pushl $L6 # return address for main, if it decides to. + pushl $_main + jmp setup_paging +L6: + jmp L6 # main should never return here, but + # just in case, we know what happens. + +/* This is the default interrupt "handler" :-) */ +int_msg: + .asciz "Unknown interrupt\n\r" +.align 2 +ignore_int: + pushl %eax + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + pushl $int_msg + call _printk + popl %eax + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + + +/* + * Setup_paging + * + * This routine sets up paging by setting the page bit + * in cr0. The page tables are set up, identity-mapping + * the first 16MB. The pager assumes that no illegal + * addresses are produced (ie >4Mb on a 4Mb machine). + * + * NOTE! Although all physical memory should be identity + * mapped by this routine, only the kernel page functions + * use the >1Mb addresses directly. All "normal" functions + * use just the lower 1Mb, or the local data space, which + * will be mapped to some other place - mm keeps track of + * that. + * + * For those with more memory than 16 Mb - tough luck. I've + * not got it, why should you :-) The source is here. Change + * it. (Seriously - it shouldn't be too difficult. Mostly + * change some constants etc. I left it at 16Mb, as my machine + * even cannot be extended past that (ok, but it was cheap :-) + * I've tried to show which constants to change by having + * some kind of marker at them (search for "16Mb"), but I + * won't guarantee that's all :-( ) + */ +.align 2 +setup_paging: + movl $1024*5,%ecx /* 5 pages - pg_dir+4 page tables */ + xorl %eax,%eax + xorl %edi,%edi /* pg_dir is at 0x000 */ + cld;rep;stosl + movl $pg0+7,_pg_dir /* set present bit/user r/w */ + movl $pg1+7,_pg_dir+4 /* --------- " " --------- */ + movl $pg2+7,_pg_dir+8 /* --------- " " --------- */ + movl $pg3+7,_pg_dir+12 /* --------- " " --------- */ + movl $pg3+4092,%edi + movl $0xfff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */ + std +1: stosl /* fill pages backwards - more efficient :-) */ + subl $0x1000,%eax + jge 1b + xorl %eax,%eax /* pg_dir is at 0x0000 */ + movl %eax,%cr3 /* cr3 - page directory start */ + movl %cr0,%eax + orl $0x80000000,%eax + movl %eax,%cr0 /* set paging (PG) bit */ + 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 0x00c09a0000000fff /* 16Mb */ + .quad 0x00c0920000000fff /* 16Mb */ + .quad 0x0000000000000000 /* TEMPORARY - don't use */ + .fill 252,8,0 /* space for LDT's and TSS's etc */ diff --git a/kernel/0.1x/linux-0.11/boot/setup.s b/kernel/0.1x/linux-0.11/boot/setup.s new file mode 100644 index 00000000..7e4b6303 --- /dev/null +++ b/kernel/0.1x/linux-0.11/boot/setup.s @@ -0,0 +1,231 @@ +! +! setup.s (C) 1991 Linus Torvalds +! +! setup.s is responsible for getting the system data from the BIOS, +! and putting them into the appropriate places in system memory. +! both setup.s and system has been loaded by the bootblock. +! +! This code asks the bios for memory/disk/other parameters, and +! puts them in a "safe" place: 0x90000-0x901FF, ie where the +! boot-block used to be. It is then up to the protected mode +! system to read them from there before the area is overwritten +! for buffer-blocks. +! + +! NOTE! These had better be the same as in bootsect.s! + +INITSEG = 0x9000 ! we move boot here - out of the way +SYSSEG = 0x1000 ! system loaded at 0x10000 (65536). +SETUPSEG = 0x9020 ! this is the current segment + +.globl begtext, begdata, begbss, endtext, enddata, endbss +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +entry start +start: + +! ok, the read went well so we get current cursor position and save it for +! posterity. + + mov ax,#INITSEG ! this is done in bootsect already, but... + mov ds,ax + mov ah,#0x03 ! read cursor pos + xor bh,bh + int 0x10 ! save it in known place, con_init fetches + mov [0],dx ! it from 0x90000. + +! Get memory size (extended mem, kB) + + mov ah,#0x88 + int 0x15 + mov [2],ax + +! Get video-card data: + + mov ah,#0x0f + int 0x10 + mov [4],bx ! bh = display page + mov [6],ax ! al = video mode, ah = window width + +! check for EGA/VGA and some config parameters + + mov ah,#0x12 + mov bl,#0x10 + int 0x10 + mov [8],ax + mov [10],bx + mov [12],cx + +! Get hd0 data + + mov ax,#0x0000 + mov ds,ax + lds si,[4*0x41] + mov ax,#INITSEG + mov es,ax + mov di,#0x0080 + mov cx,#0x10 + rep + movsb + +! Get hd1 data + + mov ax,#0x0000 + mov ds,ax + lds si,[4*0x46] + mov ax,#INITSEG + mov es,ax + mov di,#0x0090 + mov cx,#0x10 + rep + movsb + +! Check that there IS a hd1 :-) + + mov ax,#0x01500 + mov dl,#0x81 + int 0x13 + jc no_disk1 + cmp ah,#3 + je is_disk1 +no_disk1: + mov ax,#INITSEG + mov es,ax + mov di,#0x0090 + mov cx,#0x10 + mov ax,#0x00 + rep + stosb +is_disk1: + +! 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 + jmp do_move + +! then we load the segment descriptors + +end_move: + mov ax,#SETUPSEG ! 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 + +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 512+gdt,0x9 ! gdt base = 0X9xxxx + +.text +endtext: +.data +enddata: +.bss +endbss: diff --git a/kernel/0.1x/linux-0.11/fs/Makefile b/kernel/0.1x/linux-0.11/fs/Makefile new file mode 100644 index 00000000..144bb066 --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/Makefile @@ -0,0 +1,100 @@ +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 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/signal.h ../include/linux/kernel.h +block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/segment.h ../include/asm/system.h +buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/system.h ../include/asm/io.h +char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/segment.h ../include/asm/io.h +exec.o : exec.c ../include/errno.h ../include/string.h \ + ../include/sys/stat.h ../include/sys/types.h ../include/a.out.h \ + ../include/linux/fs.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/segment.h +fcntl.o : fcntl.c ../include/string.h ../include/errno.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/segment.h ../include/fcntl.h \ + ../include/sys/stat.h +file_dev.o : file_dev.c ../include/errno.h ../include/fcntl.h \ + ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/segment.h +file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h +inode.o : inode.c ../include/string.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/system.h +ioctl.o : ioctl.c ../include/string.h ../include/errno.h \ + ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/signal.h +namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h \ + ../include/string.h ../include/fcntl.h ../include/errno.h \ + ../include/const.h ../include/sys/stat.h +open.o : open.c ../include/string.h ../include/errno.h ../include/fcntl.h \ + ../include/sys/types.h ../include/utime.h ../include/sys/stat.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/tty.h \ + ../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h +pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/asm/segment.h +read_write.o : read_write.c ../include/sys/stat.h ../include/sys/types.h \ + ../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/signal.h ../include/asm/segment.h +stat.o : stat.c ../include/errno.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/linux/fs.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/mm.h ../include/signal.h \ + ../include/linux/kernel.h ../include/asm/segment.h +super.o : super.c ../include/linux/config.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/system.h ../include/errno.h ../include/sys/stat.h +truncate.o : truncate.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/signal.h ../include/sys/stat.h diff --git a/kernel/0.1x/linux-0.11/fs/bitmap.c b/kernel/0.1x/linux-0.11/fs/bitmap.c new file mode 100644 index 00000000..a08f7380 --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/bitmap.c @@ -0,0 +1,168 @@ +/* + * linux/fs/bitmap.c + * + * (C) 1991 Linus Torvalds + */ + +/* bitmap.c contains the code that handles the inode and block bitmaps */ +#include + +#include +#include + +#define clear_block(addr) \ +__asm__("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__ __volatile__("btsl %2,%3\n\tsetb %%al": \ +"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \ +res;}) + +#define clear_bit(nr,addr) ({\ +register int res __asm__("ax"); \ +__asm__ __volatile__("btrl %2,%3\n\tsetnb %%al": \ +"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \ +res;}) + +#define find_first_zero(addr) ({ \ +int __res; \ +__asm__("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)) + printk("free_inode: bit already cleared.\n\r"); + bh->b_dirt = 1; + memset(inode,0,sizeof(*inode)); +} + +struct m_inode * new_inode(int dev) +{ + struct m_inode * inode; + struct super_block * sb; + struct buffer_head * bh; + int i,j; + + if (!(inode=get_empty_inode())) + return NULL; + if (!(sb = get_super(dev))) + panic("new_inode with unknown device"); + j = 8192; + for (i=0 ; i<8 ; i++) + if (bh=sb->s_imap[i]) + if ((j=find_first_zero(bh->b_data))<8192) + break; + if (!bh || j >= 8192 || j+i*8192 > sb->s_ninodes) { + iput(inode); + return NULL; + } + if (set_bit(j,bh->b_data)) + panic("new_inode: bit already set"); + bh->b_dirt = 1; + inode->i_count=1; + inode->i_nlinks=1; + inode->i_dev=dev; + inode->i_uid=current->euid; + inode->i_gid=current->egid; + inode->i_dirt=1; + inode->i_num = j + i*8192; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + return inode; +} diff --git a/kernel/0.1x/linux-0.11/fs/block_dev.c b/kernel/0.1x/linux-0.11/fs/block_dev.c new file mode 100644 index 00000000..5af8f401 --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/block_dev.c @@ -0,0 +1,73 @@ +/* + * linux/fs/block_dev.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include +#include +#include + +int block_write(int dev, long * pos, char * buf, int count) +{ + int block = *pos >> BLOCK_SIZE_BITS; + int offset = *pos & (BLOCK_SIZE-1); + int chars; + int written = 0; + struct buffer_head * bh; + register char * p; + + while (count>0) { + chars = BLOCK_SIZE - offset; + if (chars > count) + chars=count; + if (chars == BLOCK_SIZE) + bh = getblk(dev,block); + else + bh = breada(dev,block,block+1,block+2,-1); + block++; + if (!bh) + return written?written:-EIO; + p = offset + bh->b_data; + offset = 0; + *pos += chars; + written += chars; + count -= chars; + while (chars-->0) + *(p++) = get_fs_byte(buf++); + bh->b_dirt = 1; + brelse(bh); + } + return written; +} + +int block_read(int dev, unsigned long * pos, char * buf, int count) +{ + int block = *pos >> BLOCK_SIZE_BITS; + int offset = *pos & (BLOCK_SIZE-1); + int chars; + int read = 0; + struct buffer_head * bh; + register char * p; + + while (count>0) { + chars = BLOCK_SIZE-offset; + if (chars > count) + chars = count; + if (!(bh = breada(dev,block,block+1,block+2,-1))) + return read?read:-EIO; + block++; + p = offset + bh->b_data; + offset = 0; + *pos += chars; + read += chars; + count -= chars; + while (chars-->0) + put_fs_byte(*(p++),buf++); + brelse(bh); + } + return read; +} diff --git a/kernel/0.1x/linux-0.11/fs/buffer.c b/kernel/0.1x/linux-0.11/fs/buffer.c new file mode 100644 index 00000000..8ec3376c --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/buffer.c @@ -0,0 +1,381 @@ +/* + * linux/fs/buffer.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'buffer.c' implements the buffer-cache functions. Race-conditions have + * been avoided by NEVER letting a interrupt change a buffer (except for the + * data, of course), but instead letting the caller do it. NOTE! As interrupts + * can wake up a caller, some cli-sti sequences are needed to check for + * sleep-on-calls. These should be extremely quick, though (I hope). + */ + +/* + * NOTE! There is one discordant note here: checking floppies for + * disk change. This is where it fits best, I think, as it should + * invalidate changed floppy-disk-caches. + */ + +#include + +#include +#include +#include +#include +#include + +extern int end; +struct buffer_head * start_buffer = (struct buffer_head *) &end; +struct buffer_head * hash_table[NR_HASH]; +static struct buffer_head * free_list; +static struct task_struct * buffer_wait = NULL; +int NR_BUFFERS = 0; + +static inline void wait_on_buffer(struct buffer_head * bh) +{ + cli(); + while (bh->b_lock) + sleep_on(&bh->b_wait); + sti(); +} + +int sys_sync(void) +{ + int i; + struct buffer_head * bh; + + sync_inodes(); /* write out inodes into buffers */ + bh = start_buffer; + for (i=0 ; ib_dirt) + ll_rw_block(WRITE,bh); + } + return 0; +} + +int sync_dev(int dev) +{ + int i; + struct buffer_head * bh; + + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_dirt) + ll_rw_block(WRITE,bh); + } + sync_inodes(); + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_dirt) + ll_rw_block(WRITE,bh); + } + return 0; +} + +void inline invalidate_buffers(int dev) +{ + int i; + struct buffer_head * bh; + + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev) + bh->b_uptodate = bh->b_dirt = 0; + } +} + +/* + * This routine checks whether a floppy has been changed, and + * invalidates all buffer-cache-entries in that case. This + * is a relatively slow routine, so we have to try to minimize using + * it. Thus it is called only upon a 'mount' or 'open'. This + * is the best way of combining speed and utility, I think. + * People changing diskettes in the middle of an operation deserve + * to loose :-) + * + * NOTE! Although currently this is only for floppies, the idea is + * that any additional removable block-device will use this routine, + * and that mount/open needn't know that floppies/whatever are + * special. + */ +void check_disk_change(int dev) +{ + int i; + + if (MAJOR(dev) != 2) + return; + if (!floppy_change(dev & 0x03)) + return; + for (i=0 ; ib_next) + bh->b_next->b_prev = bh->b_prev; + if (bh->b_prev) + bh->b_prev->b_next = bh->b_next; + if (hash(bh->b_dev,bh->b_blocknr) == bh) + hash(bh->b_dev,bh->b_blocknr) = bh->b_next; +/* remove from free list */ + if (!(bh->b_prev_free) || !(bh->b_next_free)) + panic("Free block list corrupted"); + bh->b_prev_free->b_next_free = bh->b_next_free; + bh->b_next_free->b_prev_free = bh->b_prev_free; + if (free_list == bh) + free_list = bh->b_next_free; +} + +static inline void insert_into_queues(struct buffer_head * bh) +{ +/* put at end of free list */ + bh->b_next_free = free_list; + bh->b_prev_free = free_list->b_prev_free; + free_list->b_prev_free->b_next_free = bh; + free_list->b_prev_free = bh; +/* put the buffer in new hash-queue if it has a device */ + bh->b_prev = NULL; + bh->b_next = NULL; + if (!bh->b_dev) + return; + bh->b_next = hash(bh->b_dev,bh->b_blocknr); + hash(bh->b_dev,bh->b_blocknr) = bh; + bh->b_next->b_prev = bh; +} + +static struct buffer_head * find_buffer(int dev, int block) +{ + struct buffer_head * tmp; + + for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next) + if (tmp->b_dev==dev && tmp->b_blocknr==block) + return tmp; + return NULL; +} + +/* + * Why like this, I hear you say... The reason is race-conditions. + * As we don't lock buffers (unless we are readint them, that is), + * something might happen to it while we sleep (ie a read-error + * will force it bad). This shouldn't really happen currently, but + * the code is ready. + */ +struct buffer_head * get_hash_table(int dev, int block) +{ + struct buffer_head * bh; + + for (;;) { + if (!(bh=find_buffer(dev,block))) + return NULL; + bh->b_count++; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_blocknr == block) + return bh; + bh->b_count--; + } +} + +/* + * Ok, this is getblk, and it isn't very clear, again to hinder + * race-conditions. Most of the code is seldom used, (ie repeating), + * so it should be much more efficient than it looks. + * + * The algoritm is changed: hopefully better, and an elusive bug removed. + */ +#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock) +struct buffer_head * getblk(int dev,int block) +{ + struct buffer_head * tmp, * bh; + +repeat: + if (bh = get_hash_table(dev,block)) + return bh; + tmp = free_list; + do { + if (tmp->b_count) + continue; + if (!bh || BADNESS(tmp)b_next_free) != free_list); + if (!bh) { + sleep_on(&buffer_wait); + goto repeat; + } + wait_on_buffer(bh); + if (bh->b_count) + goto repeat; + while (bh->b_dirt) { + sync_dev(bh->b_dev); + wait_on_buffer(bh); + if (bh->b_count) + goto repeat; + } +/* NOTE!! While we slept waiting for this block, somebody else might */ +/* already have added "this" block to the cache. check it */ + if (find_buffer(dev,block)) + goto repeat; +/* OK, FINALLY we know that this buffer is the only one of it's kind, */ +/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */ + bh->b_count=1; + bh->b_dirt=0; + bh->b_uptodate=0; + remove_from_queues(bh); + bh->b_dev=dev; + bh->b_blocknr=block; + insert_into_queues(bh); + return bh; +} + +void brelse(struct buffer_head * buf) +{ + if (!buf) + return; + wait_on_buffer(buf); + if (!(buf->b_count--)) + panic("Trying to free free buffer"); + wake_up(&buffer_wait); +} + +/* + * bread() reads a specified block and returns the buffer that contains + * it. It returns NULL if the block was unreadable. + */ +struct buffer_head * bread(int dev,int block) +{ + struct buffer_head * bh; + + if (!(bh=getblk(dev,block))) + panic("bread: getblk returned NULL\n"); + if (bh->b_uptodate) + return bh; + ll_rw_block(READ,bh); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return NULL; +} + +#define COPYBLK(from,to) \ +__asm__("cld\n\t" \ + "rep\n\t" \ + "movsl\n\t" \ + ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \ + :"cx","di","si") + +/* + * bread_page reads four buffers into memory at the desired address. It's + * a function of its own, as there is some speed to be got by reading them + * all at the same time, not waiting for one to be read, and then another + * etc. + */ +void bread_page(unsigned long address,int dev,int b[4]) +{ + struct buffer_head * bh[4]; + int i; + + for (i=0 ; i<4 ; i++) + if (b[i]) { + if (bh[i] = getblk(dev,b[i])) + if (!bh[i]->b_uptodate) + ll_rw_block(READ,bh[i]); + } else + bh[i] = NULL; + for (i=0 ; i<4 ; i++,address += BLOCK_SIZE) + if (bh[i]) { + wait_on_buffer(bh[i]); + if (bh[i]->b_uptodate) + COPYBLK((unsigned long) bh[i]->b_data,address); + brelse(bh[i]); + } +} + +/* + * Ok, breada can be used as bread, but additionally to mark other + * blocks for reading as well. End the argument list with a negative + * number. + */ +struct buffer_head * breada(int dev,int first, ...) +{ + va_list args; + struct buffer_head * bh, *tmp; + + va_start(args,first); + if (!(bh=getblk(dev,first))) + panic("bread: getblk returned NULL\n"); + if (!bh->b_uptodate) + ll_rw_block(READ,bh); + while ((first=va_arg(args,int))>=0) { + tmp=getblk(dev,first); + if (tmp) { + if (!tmp->b_uptodate) + ll_rw_block(READA,bh); + tmp->b_count--; + } + } + va_end(args); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return (NULL); +} + +void buffer_init(long buffer_end) +{ + struct buffer_head * h = start_buffer; + void * b; + int i; + + if (buffer_end == 1<<20) + b = (void *) (640*1024); + else + b = (void *) buffer_end; + while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) { + h->b_dev = 0; + h->b_dirt = 0; + h->b_count = 0; + h->b_lock = 0; + h->b_uptodate = 0; + h->b_wait = NULL; + h->b_next = NULL; + h->b_prev = NULL; + h->b_data = (char *) b; + h->b_prev_free = h-1; + h->b_next_free = h+1; + h++; + NR_BUFFERS++; + if (b == (void *) 0x100000) + b = (void *) 0xA0000; + } + h--; + free_list = start_buffer; + free_list->b_prev_free = h; + h->b_next_free = free_list; + for (i=0;i +#include + +#include +#include + +#include +#include + +extern int tty_read(unsigned minor,char * buf,int count); +extern int tty_write(unsigned minor,char * buf,int count); + +typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count,off_t * pos); + +static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos) +{ + return ((rw==READ)?tty_read(minor,buf,count): + tty_write(minor,buf,count)); +} + +static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos) +{ + if (current->tty<0) + return -EPERM; + return rw_ttyx(rw,current->tty,buf,count,pos); +} + +static int rw_ram(int rw,char * buf, int count, off_t *pos) +{ + return -EIO; +} + +static int rw_mem(int rw,char * buf, int count, off_t * pos) +{ + return -EIO; +} + +static int rw_kmem(int rw,char * buf, int count, off_t * pos) +{ + return -EIO; +} + +static int rw_port(int rw,char * buf, int count, off_t * pos) +{ + int i=*pos; + + while (count-->0 && i<65536) { + if (rw==READ) + put_fs_byte(inb(i),buf++); + else + outb(get_fs_byte(buf++),i); + i++; + } + i -= *pos; + *pos += i; + return i; +} + +static int rw_memory(int rw, unsigned minor, char * buf, int count, off_t * pos) +{ + switch(minor) { + case 0: + return rw_ram(rw,buf,count,pos); + case 1: + return rw_mem(rw,buf,count,pos); + case 2: + return rw_kmem(rw,buf,count,pos); + case 3: + return (rw==READ)?0:count; /* rw_null */ + case 4: + return rw_port(rw,buf,count,pos); + default: + return -EIO; + } +} + +#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr))) + +static crw_ptr crw_table[]={ + NULL, /* nodev */ + rw_memory, /* /dev/mem etc */ + NULL, /* /dev/fd */ + NULL, /* /dev/hd */ + rw_ttyx, /* /dev/ttyx */ + rw_tty, /* /dev/tty */ + NULL, /* /dev/lp */ + NULL}; /* unnamed pipes */ + +int rw_char(int rw,int dev, char * buf, int count, off_t * pos) +{ + crw_ptr call_addr; + + if (MAJOR(dev)>=NRDEVS) + return -ENODEV; + if (!(call_addr=crw_table[MAJOR(dev)])) + return -ENODEV; + return call_addr(rw,MINOR(dev),buf,count,pos); +} diff --git a/kernel/0.1x/linux-0.11/fs/exec.c b/kernel/0.1x/linux-0.11/fs/exec.c new file mode 100644 index 00000000..36367a60 --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/exec.c @@ -0,0 +1,353 @@ +/* + * linux/fs/exec.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * #!-checking implemented by tytso. + */ + +/* + * Demand-loading implemented 01.12.91 - no need to read anything but + * the header into memory. The inode of the executable is put into + * "current->executable", and page faults do the actual loading. Clean. + * + * Once more I can proudly say that linux stood up to being changed: it + * was less than 2 hours work to get demand-loading completely implemented. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern int sys_exit(int exit_code); +extern int sys_close(int fd); + +/* + * 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 + +/* + * create_tables() parses the env- and arg-strings in new user + * memory and creates the pointer tables from them, and puts their + * addresses on the "stack", returning the new stack pointer value. + */ +static unsigned long * create_tables(char * p,int argc,int envc) +{ + unsigned long *argv,*envp; + unsigned long * sp; + + sp = (unsigned long *) (0xfffffffc & (unsigned long) p); + sp -= envc+1; + envp = sp; + sp -= argc+1; + argv = sp; + put_fs_long((unsigned long)envp,--sp); + put_fs_long((unsigned long)argv,--sp); + put_fs_long((unsigned long)argc,--sp); + while (argc-->0) { + put_fs_long((unsigned long) p,argv++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,argv); + while (envc-->0) { + put_fs_long((unsigned long) p,envp++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,envp); + return sp; +} + +/* + * count() counts the number of arguments/envelopes + */ +static int count(char ** argv) +{ + int i=0; + char ** tmp; + + if (tmp = argv) + while (get_fs_long((unsigned long *) (tmp++))) + i++; + + return i; +} + +/* + * 'copy_string()' copies argument/envelope strings from user + * memory to free pages in kernel mem. These are in a format ready + * to be put directly into the top of new user memory. + * + * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies + * whether the string and the string array are from user or kernel segments: + * + * from_kmem argv * argv ** + * 0 user space user space + * 1 kernel space user space + * 2 kernel space kernel space + * + * We do this by playing games with the fs segment register. Since it + * it is expensive to load a segment register, we try to avoid calling + * set_fs() unless we absolutely have to. + */ +static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, + unsigned long p, int from_kmem) +{ + char *tmp, *pag; + int len, offset = 0; + unsigned long old_fs, new_fs; + + if (!p) + return 0; /* bullet-proofing */ + new_fs = get_ds(); + old_fs = get_fs(); + if (from_kmem==2) + set_fs(new_fs); + while (argc-- > 0) { + if (from_kmem == 1) + set_fs(new_fs); + if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc))) + panic("argc is wrong"); + if (from_kmem == 1) + set_fs(old_fs); + len=0; /* remember zero-padding */ + do { + len++; + } while (get_fs_byte(tmp++)); + if (p-len < 0) { /* this shouldn't happen - 128kB */ + set_fs(old_fs); + return 0; + } + while (len) { + --p; --tmp; --len; + if (--offset < 0) { + offset = p % PAGE_SIZE; + if (from_kmem==2) + set_fs(old_fs); + if (!(pag = (char *) page[p/PAGE_SIZE]) && + !(pag = (char *) page[p/PAGE_SIZE] = + (unsigned long *) get_free_page())) + return 0; + if (from_kmem==2) + set_fs(new_fs); + + } + *(pag + offset) = get_fs_byte(tmp); + } + } + if (from_kmem==2) + set_fs(old_fs); + return p; +} + +static unsigned long change_ldt(unsigned long text_size,unsigned long * page) +{ + unsigned long code_limit,data_limit,code_base,data_base; + int i; + + code_limit = text_size+PAGE_SIZE -1; + code_limit &= 0xFFFFF000; + data_limit = 0x4000000; + code_base = get_base(current->ldt[1]); + data_base = code_base; + set_base(current->ldt[1],code_base); + set_limit(current->ldt[1],code_limit); + set_base(current->ldt[2],data_base); + set_limit(current->ldt[2],data_limit); +/* make sure fs points to the NEW data segment */ + __asm__("pushl $0x17\n\tpop %%fs"::); + data_base += data_limit; + for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) { + data_base -= PAGE_SIZE; + if (page[i]) + put_page(page[i],data_base); + } + return data_limit; +} + +/* + * 'do_execve()' executes a new program. + */ +int do_execve(unsigned long * eip,long tmp,char * filename, + char ** argv, char ** envp) +{ + struct m_inode * inode; + struct buffer_head * bh; + struct exec ex; + unsigned long page[MAX_ARG_PAGES]; + int i,argc,envc; + int e_uid, e_gid; + int retval; + int sh_bang = 0; + unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4; + + if ((0xffff & eip[1]) != 0x000f) + panic("execve called from supervisor mode"); + for (i=0 ; ii_mode)) { /* must be regular file */ + retval = -EACCES; + goto exec_error2; + } + i = inode->i_mode; + e_uid = (i & S_ISUID) ? inode->i_uid : current->euid; + e_gid = (i & S_ISGID) ? inode->i_gid : current->egid; + if (current->euid == inode->i_uid) + i >>= 6; + else if (current->egid == inode->i_gid) + i >>= 3; + if (!(i & 1) && + !((inode->i_mode & 0111) && suser())) { + retval = -ENOEXEC; + goto exec_error2; + } + if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) { + retval = -EACCES; + goto exec_error2; + } + ex = *((struct exec *) bh->b_data); /* read exec-header */ + if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) { + /* + * This section does the #! interpretation. + * Sorta complicated, but hopefully it will work. -TYT + */ + + char buf[1023], *cp, *interp, *i_name, *i_arg; + unsigned long old_fs; + + strncpy(buf, bh->b_data+2, 1022); + brelse(bh); + iput(inode); + buf[1022] = '\0'; + if (cp = strchr(buf, '\n')) { + *cp = '\0'; + for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++); + } + if (!cp || *cp == '\0') { + retval = -ENOEXEC; /* No interpreter name found */ + goto exec_error1; + } + interp = i_name = cp; + i_arg = 0; + for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) { + if (*cp == '/') + i_name = cp+1; + } + if (*cp) { + *cp++ = '\0'; + i_arg = cp; + } + /* + * OK, we've parsed out the interpreter name and + * (optional) argument. + */ + if (sh_bang++ == 0) { + p = copy_strings(envc, envp, page, p, 0); + p = copy_strings(--argc, argv+1, page, p, 0); + } + /* + * Splice in (1) the interpreter's name for argv[0] + * (2) (optional) argument to interpreter + * (3) filename of shell script + * + * This is done in reverse order, because of how the + * user environment and arguments are stored. + */ + p = copy_strings(1, &filename, page, p, 1); + argc++; + if (i_arg) { + p = copy_strings(1, &i_arg, page, p, 2); + argc++; + } + p = copy_strings(1, &i_name, page, p, 2); + argc++; + if (!p) { + retval = -ENOMEM; + goto exec_error1; + } + /* + * OK, now restart the process with the interpreter's inode. + */ + old_fs = get_fs(); + set_fs(get_ds()); + if (!(inode=namei(interp))) { /* get executables inode */ + set_fs(old_fs); + retval = -ENOENT; + goto exec_error1; + } + set_fs(old_fs); + goto restart_interp; + } + brelse(bh); + if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize || + ex.a_text+ex.a_data+ex.a_bss>0x3000000 || + inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { + retval = -ENOEXEC; + goto exec_error2; + } + if (N_TXTOFF(ex) != BLOCK_SIZE) { + printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename); + retval = -ENOEXEC; + goto exec_error2; + } + if (!sh_bang) { + p = copy_strings(envc,envp,page,p,0); + p = copy_strings(argc,argv,page,p,0); + if (!p) { + retval = -ENOMEM; + goto exec_error2; + } + } +/* OK, This is the point of no return */ + if (current->executable) + iput(current->executable); + current->executable = inode; + for (i=0 ; i<32 ; i++) + current->sigaction[i].sa_handler = NULL; + for (i=0 ; iclose_on_exec>>i)&1) + sys_close(i); + current->close_on_exec = 0; + free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); + free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); + if (last_task_used_math == current) + last_task_used_math = NULL; + current->used_math = 0; + p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE; + p = (unsigned long) create_tables((char *)p,argc,envc); + current->brk = ex.a_bss + + (current->end_data = ex.a_data + + (current->end_code = ex.a_text)); + current->start_stack = p & 0xfffff000; + current->euid = e_uid; + current->egid = e_gid; + i = ex.a_text+ex.a_data; + while (i&0xfff) + put_fs_byte(0,(char *) (i++)); + eip[0] = ex.a_entry; /* eip, magic happens :-) */ + eip[3] = p; /* stack pointer */ + return 0; +exec_error2: + iput(inode); +exec_error1: + for (i=0 ; i +#include +#include +#include +#include + +#include +#include + +extern int sys_close(int fd); + +static int dupfd(unsigned int fd, unsigned int arg) +{ + if (fd >= NR_OPEN || !current->filp[fd]) + return -EBADF; + if (arg >= NR_OPEN) + return -EINVAL; + while (arg < NR_OPEN) + if (current->filp[arg]) + arg++; + else + break; + if (arg >= NR_OPEN) + return -EMFILE; + current->close_on_exec &= ~(1<filp[arg] = current->filp[fd])->f_count++; + return arg; +} + +int sys_dup2(unsigned int oldfd, unsigned int newfd) +{ + sys_close(newfd); + return dupfd(oldfd,newfd); +} + +int sys_dup(unsigned int fildes) +{ + return dupfd(fildes,0); +} + +int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + switch (cmd) { + case F_DUPFD: + return dupfd(fd,arg); + case F_GETFD: + return (current->close_on_exec>>fd)&1; + case F_SETFD: + if (arg&1) + current->close_on_exec |= (1<close_on_exec &= ~(1<f_flags; + case F_SETFL: + filp->f_flags &= ~(O_APPEND | O_NONBLOCK); + filp->f_flags |= arg & (O_APPEND | O_NONBLOCK); + return 0; + case F_GETLK: case F_SETLK: case F_SETLKW: + return -1; + default: + return -1; + } +} diff --git a/kernel/0.1x/linux-0.11/fs/file_dev.c b/kernel/0.1x/linux-0.11/fs/file_dev.c new file mode 100644 index 00000000..42eaf37a --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/file_dev.c @@ -0,0 +1,90 @@ +/* + * linux/fs/file_dev.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) +{ + int left,chars,nr; + struct buffer_head * bh; + + if ((left=count)<=0) + return 0; + while (left) { + if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) { + if (!(bh=bread(inode->i_dev,nr))) + break; + } else + bh = NULL; + nr = filp->f_pos % BLOCK_SIZE; + chars = MIN( BLOCK_SIZE-nr , left ); + filp->f_pos += chars; + left -= chars; + if (bh) { + char * p = nr + bh->b_data; + while (chars-->0) + put_fs_byte(*(p++),buf++); + brelse(bh); + } else { + while (chars-->0) + put_fs_byte(0,buf++); + } + } + inode->i_atime = CURRENT_TIME; + return (count-left)?(count-left):-ERROR; +} + +int file_write(struct m_inode * inode, struct file * filp, char * buf, int count) +{ + off_t pos; + int block,c; + struct buffer_head * bh; + char * p; + int i=0; + +/* + * ok, append may not work when many processes are writing at the same time + * but so what. That way leads to madness anyway. + */ + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + else + pos = filp->f_pos; + while (ii_dev,block))) + break; + c = pos % BLOCK_SIZE; + p = c + bh->b_data; + bh->b_dirt = 1; + c = BLOCK_SIZE-c; + if (c > count-i) c = count-i; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + i += c; + while (c-->0) + *(p++) = get_fs_byte(buf++); + brelse(bh); + } + inode->i_mtime = CURRENT_TIME; + if (!(filp->f_flags & O_APPEND)) { + filp->f_pos = pos; + inode->i_ctime = CURRENT_TIME; + } + return (i?i:-1); +} diff --git a/kernel/0.1x/linux-0.11/fs/file_table.c b/kernel/0.1x/linux-0.11/fs/file_table.c new file mode 100644 index 00000000..0cf8b1b8 --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/file_table.c @@ -0,0 +1,9 @@ +/* + * linux/fs/file_table.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +struct file file_table[NR_FILE]; diff --git a/kernel/0.1x/linux-0.11/fs/inode.c b/kernel/0.1x/linux-0.11/fs/inode.c new file mode 100644 index 00000000..0a4cb048 --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/inode.c @@ -0,0 +1,338 @@ +/* + * linux/fs/inode.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include + +struct m_inode inode_table[NR_INODE]={{0,},}; + +static void read_inode(struct m_inode * inode); +static void write_inode(struct m_inode * inode); + +static inline void wait_on_inode(struct m_inode * inode) +{ + cli(); + while (inode->i_lock) + sleep_on(&inode->i_wait); + sti(); +} + +static inline void lock_inode(struct m_inode * inode) +{ + cli(); + while (inode->i_lock) + sleep_on(&inode->i_wait); + inode->i_lock=1; + sti(); +} + +static inline void unlock_inode(struct m_inode * inode) +{ + inode->i_lock=0; + wake_up(&inode->i_wait); +} + +void invalidate_inodes(int dev) +{ + int i; + struct m_inode * inode; + + inode = 0+inode_table; + for(i=0 ; ii_dev == dev) { + if (inode->i_count) + printk("inode in use on removed disk\n\r"); + inode->i_dev = inode->i_dirt = 0; + } + } +} + +void sync_inodes(void) +{ + int i; + struct m_inode * inode; + + inode = 0+inode_table; + for(i=0 ; ii_dirt && !inode->i_pipe) + write_inode(inode); + } +} + +static int _bmap(struct m_inode * inode,int block,int create) +{ + struct buffer_head * bh; + int i; + + if (block<0) + panic("_bmap: block<0"); + if (block >= 7+512+512*512) + panic("_bmap: block>big"); + if (block<7) { + if (create && !inode->i_zone[block]) + if (inode->i_zone[block]=new_block(inode->i_dev)) { + inode->i_ctime=CURRENT_TIME; + inode->i_dirt=1; + } + return inode->i_zone[block]; + } + block -= 7; + if (block<512) { + if (create && !inode->i_zone[7]) + if (inode->i_zone[7]=new_block(inode->i_dev)) { + inode->i_dirt=1; + inode->i_ctime=CURRENT_TIME; + } + if (!inode->i_zone[7]) + return 0; + if (!(bh = bread(inode->i_dev,inode->i_zone[7]))) + return 0; + i = ((unsigned short *) (bh->b_data))[block]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block]=i; + bh->b_dirt=1; + } + brelse(bh); + return i; + } + block -= 512; + if (create && !inode->i_zone[8]) + if (inode->i_zone[8]=new_block(inode->i_dev)) { + inode->i_dirt=1; + inode->i_ctime=CURRENT_TIME; + } + if (!inode->i_zone[8]) + return 0; + if (!(bh=bread(inode->i_dev,inode->i_zone[8]))) + return 0; + i = ((unsigned short *)bh->b_data)[block>>9]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block>>9]=i; + bh->b_dirt=1; + } + brelse(bh); + if (!i) + return 0; + if (!(bh=bread(inode->i_dev,i))) + return 0; + i = ((unsigned short *)bh->b_data)[block&511]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block&511]=i; + bh->b_dirt=1; + } + brelse(bh); + return i; +} + +int bmap(struct m_inode * inode,int block) +{ + return _bmap(inode,block,0); +} + +int create_block(struct m_inode * inode, int block) +{ + return _bmap(inode,block,1); +} + +void iput(struct m_inode * inode) +{ + if (!inode) + return; + wait_on_inode(inode); + if (!inode->i_count) + panic("iput: trying to free free inode"); + if (inode->i_pipe) { + wake_up(&inode->i_wait); + if (--inode->i_count) + return; + free_page(inode->i_size); + inode->i_count=0; + inode->i_dirt=0; + inode->i_pipe=0; + return; + } + if (!inode->i_dev) { + inode->i_count--; + return; + } + if (S_ISBLK(inode->i_mode)) { + sync_dev(inode->i_zone[0]); + wait_on_inode(inode); + } +repeat: + if (inode->i_count>1) { + inode->i_count--; + return; + } + if (!inode->i_nlinks) { + truncate(inode); + free_inode(inode); + return; + } + if (inode->i_dirt) { + write_inode(inode); /* we can sleep - so do again */ + wait_on_inode(inode); + goto repeat; + } + inode->i_count--; + return; +} + +struct m_inode * get_empty_inode(void) +{ + struct m_inode * inode; + static struct m_inode * last_inode = inode_table; + int i; + + do { + inode = NULL; + for (i = NR_INODE; i ; i--) { + if (++last_inode >= inode_table + NR_INODE) + last_inode = inode_table; + if (!last_inode->i_count) { + inode = last_inode; + if (!inode->i_dirt && !inode->i_lock) + break; + } + } + if (!inode) { + for (i=0 ; ii_dirt) { + write_inode(inode); + wait_on_inode(inode); + } + } while (inode->i_count); + memset(inode,0,sizeof(*inode)); + inode->i_count = 1; + return inode; +} + +struct m_inode * get_pipe_inode(void) +{ + struct m_inode * inode; + + if (!(inode = get_empty_inode())) + return NULL; + if (!(inode->i_size=get_free_page())) { + inode->i_count = 0; + return NULL; + } + inode->i_count = 2; /* sum of readers/writers */ + PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0; + inode->i_pipe = 1; + return inode; +} + +struct m_inode * iget(int dev,int nr) +{ + struct m_inode * inode, * empty; + + if (!dev) + panic("iget with dev==0"); + empty = get_empty_inode(); + inode = inode_table; + while (inode < NR_INODE+inode_table) { + if (inode->i_dev != dev || inode->i_num != nr) { + inode++; + continue; + } + wait_on_inode(inode); + if (inode->i_dev != dev || inode->i_num != nr) { + inode = inode_table; + continue; + } + inode->i_count++; + if (inode->i_mount) { + int i; + + for (i = 0 ; i= NR_SUPER) { + printk("Mounted inode hasn't got sb\n"); + if (empty) + iput(empty); + return inode; + } + iput(inode); + dev = super_block[i].s_dev; + nr = ROOT_INO; + inode = inode_table; + continue; + } + if (empty) + iput(empty); + return inode; + } + if (!empty) + return (NULL); + inode=empty; + inode->i_dev = dev; + inode->i_num = nr; + read_inode(inode); + return inode; +} + +static void read_inode(struct m_inode * inode) +{ + struct super_block * sb; + struct buffer_head * bh; + int block; + + lock_inode(inode); + if (!(sb=get_super(inode->i_dev))) + panic("trying to read inode without dev"); + block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks + + (inode->i_num-1)/INODES_PER_BLOCK; + if (!(bh=bread(inode->i_dev,block))) + panic("unable to read i-node block"); + *(struct d_inode *)inode = + ((struct d_inode *)bh->b_data) + [(inode->i_num-1)%INODES_PER_BLOCK]; + brelse(bh); + unlock_inode(inode); +} + +static void write_inode(struct m_inode * inode) +{ + struct super_block * sb; + struct buffer_head * bh; + int block; + + lock_inode(inode); + if (!inode->i_dirt || !inode->i_dev) { + unlock_inode(inode); + return; + } + if (!(sb=get_super(inode->i_dev))) + panic("trying to write inode without device"); + block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks + + (inode->i_num-1)/INODES_PER_BLOCK; + if (!(bh=bread(inode->i_dev,block))) + panic("unable to read i-node block"); + ((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/kernel/0.1x/linux-0.11/fs/ioctl.c b/kernel/0.1x/linux-0.11/fs/ioctl.c new file mode 100644 index 00000000..b4b83d62 --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/ioctl.c @@ -0,0 +1,46 @@ +/* + * linux/fs/ioctl.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include + +extern int tty_ioctl(int dev, int cmd, int arg); + +typedef int (*ioctl_ptr)(int dev,int cmd,int arg); + +#define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr))) + +static ioctl_ptr ioctl_table[]={ + NULL, /* nodev */ + NULL, /* /dev/mem */ + NULL, /* /dev/fd */ + NULL, /* /dev/hd */ + tty_ioctl, /* /dev/ttyx */ + tty_ioctl, /* /dev/tty */ + NULL, /* /dev/lp */ + NULL}; /* named pipes */ + + +int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + int dev,mode; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + mode=filp->f_inode->i_mode; + if (!S_ISCHR(mode) && !S_ISBLK(mode)) + return -EINVAL; + dev = filp->f_inode->i_zone[0]; + if (MAJOR(dev) >= NRDEVS) + return -ENODEV; + if (!ioctl_table[MAJOR(dev)]) + return -ENOTTY; + return ioctl_table[MAJOR(dev)](dev,cmd,arg); +} diff --git a/kernel/0.1x/linux-0.11/fs/namei.c b/kernel/0.1x/linux-0.11/fs/namei.c new file mode 100644 index 00000000..08eff761 --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/namei.c @@ -0,0 +1,778 @@ +/* + * linux/fs/namei.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * Some corrections by tytso. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE]) + +/* + * comment out this line if you want names > NAME_LEN chars to be + * truncated. Else they will be disallowed. + */ +/* #define NO_TRUNCATE */ + +#define MAY_EXEC 1 +#define MAY_WRITE 2 +#define MAY_READ 4 + +/* + * permission() + * + * is used to check for read/write/execute permissions on a file. + * I don't know if we should look at just the euid or both euid and + * uid, but that should be easily changed. + */ +static int permission(struct m_inode * inode,int mask) +{ + int mode = inode->i_mode; + +/* special case: not even root can read/write a deleted file */ + if (inode->i_dev && !inode->i_nlinks) + return 0; + else if (current->euid==inode->i_uid) + mode >>= 6; + else if (current->egid==inode->i_gid) + mode >>= 3; + if (((mode & mask & 0007) == mask) || suser()) + return 1; + return 0; +} + +/* + * ok, we cannot use strncmp, as the name is not in our data space. + * Thus we'll have to use match. No big problem. Match also makes + * some sanity tests. + * + * NOTE! unlike strncmp, match returns 1 for success, 0 for failure. + */ +static int match(int len,const char * name,struct dir_entry * de) +{ + register int same __asm__("ax"); + + if (!de || !de->inode || len > NAME_LEN) + return 0; + if (len < NAME_LEN && de->name[len]) + return 0; + __asm__("cld\n\t" + "fs ; repe ; cmpsb\n\t" + "setz %%al" + :"=a" (same) + :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len) + :"cx","di","si"); + return same; +} + +/* + * find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + * + * This also takes care of the few special cases due to '..'-traversal + * over a pseudo-root and a mount point. + */ +static struct buffer_head * find_entry(struct m_inode ** dir, + const char * name, int namelen, struct dir_entry ** res_dir) +{ + int entries; + int block,i; + struct buffer_head * bh; + struct dir_entry * de; + struct super_block * sb; + +#ifdef NO_TRUNCATE + if (namelen > NAME_LEN) + return NULL; +#else + if (namelen > NAME_LEN) + namelen = NAME_LEN; +#endif + entries = (*dir)->i_size / (sizeof (struct dir_entry)); + *res_dir = NULL; + if (!namelen) + return NULL; +/* check for '..', as we might have to do some "magic" for it */ + if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') { +/* '..' in a pseudo-root results in a faked '.' (just change namelen) */ + if ((*dir) == current->root) + namelen=1; + else if ((*dir)->i_num == ROOT_INO) { +/* '..' over a mount-point results in 'dir' being exchanged for the mounted + directory-inode. NOTE! We set mounted, so that we can iput the new dir */ + sb=get_super((*dir)->i_dev); + if (sb->s_imount) { + iput(*dir); + (*dir)=sb->s_imount; + (*dir)->i_count++; + } + } + } + if (!(block = (*dir)->i_zone[0])) + return NULL; + if (!(bh = bread((*dir)->i_dev,block))) + return NULL; + i = 0; + de = (struct dir_entry *) bh->b_data; + while (i < entries) { + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; + if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) || + !(bh = bread((*dir)->i_dev,block))) { + i += DIR_ENTRIES_PER_BLOCK; + continue; + } + de = (struct dir_entry *) bh->b_data; + } + if (match(namelen,name,de)) { + *res_dir = de; + return bh; + } + de++; + i++; + } + brelse(bh); + return NULL; +} + +/* + * add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as find_entry(). It returns NULL if it failed. + * + * NOTE!! The inode part of 'de' is left at 0 - which means you + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ +static struct buffer_head * add_entry(struct m_inode * dir, + const char * name, int namelen, struct dir_entry ** res_dir) +{ + int block,i; + struct buffer_head * bh; + struct dir_entry * de; + + *res_dir = NULL; +#ifdef NO_TRUNCATE + if (namelen > NAME_LEN) + return NULL; +#else + if (namelen > NAME_LEN) + namelen = NAME_LEN; +#endif + if (!namelen) + return NULL; + if (!(block = dir->i_zone[0])) + return NULL; + if (!(bh = bread(dir->i_dev,block))) + return NULL; + i = 0; + de = (struct dir_entry *) bh->b_data; + while (1) { + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; + block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK); + if (!block) + return NULL; + if (!(bh = bread(dir->i_dev,block))) { + i += DIR_ENTRIES_PER_BLOCK; + continue; + } + de = (struct dir_entry *) bh->b_data; + } + if (i*sizeof(struct dir_entry) >= dir->i_size) { + de->inode=0; + dir->i_size = (i+1)*sizeof(struct dir_entry); + dir->i_dirt = 1; + dir->i_ctime = CURRENT_TIME; + } + if (!de->inode) { + dir->i_mtime = CURRENT_TIME; + for (i=0; i < NAME_LEN ; i++) + de->name[i]=(ib_dirt = 1; + *res_dir = de; + return bh; + } + de++; + i++; + } + brelse(bh); + return NULL; +} + +/* + * get_dir() + * + * Getdir traverses the pathname until it hits the topmost directory. + * It returns NULL on failure. + */ +static struct m_inode * get_dir(const char * pathname) +{ + char c; + const char * thisname; + struct m_inode * inode; + struct buffer_head * bh; + int namelen,inr,idev; + struct dir_entry * de; + + if (!current->root || !current->root->i_count) + panic("No root inode"); + if (!current->pwd || !current->pwd->i_count) + panic("No cwd inode"); + if ((c=get_fs_byte(pathname))=='/') { + inode = current->root; + pathname++; + } else if (c) + inode = current->pwd; + else + return NULL; /* empty name is bad */ + inode->i_count++; + while (1) { + thisname = pathname; + if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) { + iput(inode); + return NULL; + } + for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++) + /* nothing */ ; + if (!c) + return inode; + if (!(bh = find_entry(&inode,thisname,namelen,&de))) { + iput(inode); + return NULL; + } + inr = de->inode; + idev = inode->i_dev; + brelse(bh); + iput(inode); + if (!(inode = iget(idev,inr))) + return NULL; + } +} + +/* + * dir_namei() + * + * dir_namei() returns the inode of the directory of the + * specified name, and the name within that directory. + */ +static struct m_inode * dir_namei(const char * pathname, + int * namelen, const char ** name) +{ + char c; + const char * basename; + struct m_inode * dir; + + if (!(dir = get_dir(pathname))) + return NULL; + basename = pathname; + while (c=get_fs_byte(pathname++)) + if (c=='/') + basename=pathname; + *namelen = pathname-basename-1; + *name = basename; + return dir; +} + +/* + * namei() + * + * is used by most simple commands to get the inode of a specified name. + * Open, link etc use their own routines, but this is enough for things + * like 'chmod' etc. + */ +struct m_inode * namei(const char * pathname) +{ + const char * basename; + int inr,dev,namelen; + struct m_inode * dir; + struct buffer_head * bh; + struct dir_entry * de; + + if (!(dir = dir_namei(pathname,&namelen,&basename))) + return NULL; + if (!namelen) /* special case: '/usr/' etc */ + return dir; + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + iput(dir); + return NULL; + } + inr = de->inode; + dev = dir->i_dev; + brelse(bh); + iput(dir); + dir=iget(dev,inr); + if (dir) { + dir->i_atime=CURRENT_TIME; + dir->i_dirt=1; + } + return dir; +} + +/* + * open_namei() + * + * namei for open - this is in fact almost the whole open-routine. + */ +int open_namei(const char * pathname, int flag, int mode, + struct m_inode ** res_inode) +{ + const char * basename; + int inr,dev,namelen; + struct m_inode * dir, *inode; + struct buffer_head * bh; + struct dir_entry * de; + + if ((flag & O_TRUNC) && !(flag & O_ACCMODE)) + flag |= O_WRONLY; + mode &= 0777 & ~current->umask; + mode |= I_REGULAR; + if (!(dir = dir_namei(pathname,&namelen,&basename))) + return -ENOENT; + if (!namelen) { /* special case: '/usr/' etc */ + if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) { + *res_inode=dir; + return 0; + } + iput(dir); + return -EISDIR; + } + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + if (!(flag & O_CREAT)) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EACCES; + } + inode = new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_uid = current->euid; + inode->i_mode = mode; + inode->i_dirt = 1; + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + inode->i_nlinks--; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->inode = inode->i_num; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + *res_inode = inode; + return 0; + } + inr = de->inode; + dev = dir->i_dev; + brelse(bh); + iput(dir); + if (flag & O_EXCL) + return -EEXIST; + if (!(inode=iget(dev,inr))) + return -EACCES; + if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) || + !permission(inode,ACC_MODE(flag))) { + iput(inode); + return -EPERM; + } + inode->i_atime = CURRENT_TIME; + if (flag & O_TRUNC) + truncate(inode); + *res_inode = inode; + return 0; +} + +int sys_mknod(const char * filename, int mode, int dev) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh; + struct dir_entry * de; + + if (!suser()) + return -EPERM; + if (!(dir = dir_namei(filename,&namelen,&basename))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + bh = find_entry(&dir,basename,namelen,&de); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_mode = mode; + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_zone[0] = dev; + inode->i_mtime = inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + iput(dir); + inode->i_nlinks=0; + iput(inode); + return -ENOSPC; + } + de->inode = inode->i_num; + bh->b_dirt = 1; + iput(dir); + iput(inode); + brelse(bh); + return 0; +} + +int sys_mkdir(const char * pathname, int mode) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh, *dir_block; + struct dir_entry * de; + + if (!suser()) + return -EPERM; + if (!(dir = dir_namei(pathname,&namelen,&basename))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + bh = find_entry(&dir,basename,namelen,&de); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_size = 32; + inode->i_dirt = 1; + inode->i_mtime = inode->i_atime = CURRENT_TIME; + if (!(inode->i_zone[0]=new_block(inode->i_dev))) { + iput(dir); + inode->i_nlinks--; + iput(inode); + return -ENOSPC; + } + inode->i_dirt = 1; + if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) { + iput(dir); + free_block(inode->i_dev,inode->i_zone[0]); + inode->i_nlinks--; + iput(inode); + return -ERROR; + } + de = (struct dir_entry *) dir_block->b_data; + de->inode=inode->i_num; + strcpy(de->name,"."); + de++; + de->inode = dir->i_num; + strcpy(de->name,".."); + inode->i_nlinks = 2; + dir_block->b_dirt = 1; + brelse(dir_block); + inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask); + inode->i_dirt = 1; + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + iput(dir); + free_block(inode->i_dev,inode->i_zone[0]); + inode->i_nlinks=0; + iput(inode); + return -ENOSPC; + } + de->inode = inode->i_num; + bh->b_dirt = 1; + dir->i_nlinks++; + dir->i_dirt = 1; + iput(dir); + iput(inode); + brelse(bh); + return 0; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +static int empty_dir(struct m_inode * inode) +{ + int nr,block; + int len; + struct buffer_head * bh; + struct dir_entry * de; + + len = inode->i_size / sizeof (struct dir_entry); + if (len<2 || !inode->i_zone[0] || + !(bh=bread(inode->i_dev,inode->i_zone[0]))) { + printk("warning - bad directory on dev %04x\n",inode->i_dev); + return 0; + } + de = (struct dir_entry *) bh->b_data; + if (de[0].inode != inode->i_num || !de[1].inode || + strcmp(".",de[0].name) || strcmp("..",de[1].name)) { + printk("warning - bad directory on dev %04x\n",inode->i_dev); + return 0; + } + nr = 2; + de += 2; + while (nr= (void *) (bh->b_data+BLOCK_SIZE)) { + brelse(bh); + block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK); + if (!block) { + nr += DIR_ENTRIES_PER_BLOCK; + continue; + } + if (!(bh=bread(inode->i_dev,block))) + return 0; + de = (struct dir_entry *) bh->b_data; + } + if (de->inode) { + brelse(bh); + return 0; + } + de++; + nr++; + } + brelse(bh); + return 1; +} + +int sys_rmdir(const char * name) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh; + struct dir_entry * de; + + if (!suser()) + return -EPERM; + if (!(dir = dir_namei(name,&namelen,&basename))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + iput(dir); + return -ENOENT; + } + if (!(inode = iget(dir->i_dev, de->inode))) { + iput(dir); + brelse(bh); + return -EPERM; + } + if ((dir->i_mode & S_ISVTX) && current->euid && + inode->i_uid != current->euid) { + iput(dir); + iput(inode); + brelse(bh); + return -EPERM; + } + if (inode->i_dev != dir->i_dev || inode->i_count>1) { + iput(dir); + iput(inode); + brelse(bh); + return -EPERM; + } + if (inode == dir) { /* we may not delete ".", but "../dir" is ok */ + iput(inode); + iput(dir); + brelse(bh); + return -EPERM; + } + if (!S_ISDIR(inode->i_mode)) { + iput(inode); + iput(dir); + brelse(bh); + return -ENOTDIR; + } + if (!empty_dir(inode)) { + iput(inode); + iput(dir); + brelse(bh); + return -ENOTEMPTY; + } + if (inode->i_nlinks != 2) + printk("empty directory has nlink!=2 (%d)",inode->i_nlinks); + de->inode = 0; + bh->b_dirt = 1; + brelse(bh); + inode->i_nlinks=0; + inode->i_dirt=1; + dir->i_nlinks--; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt=1; + iput(dir); + iput(inode); + return 0; +} + +int sys_unlink(const char * name) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh; + struct dir_entry * de; + + if (!(dir = dir_namei(name,&namelen,&basename))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + iput(dir); + return -ENOENT; + } + if (!(inode = iget(dir->i_dev, de->inode))) { + iput(dir); + brelse(bh); + return -ENOENT; + } + if ((dir->i_mode & S_ISVTX) && !suser() && + current->euid != inode->i_uid && + current->euid != dir->i_uid) { + iput(dir); + iput(inode); + brelse(bh); + return -EPERM; + } + if (S_ISDIR(inode->i_mode)) { + iput(inode); + iput(dir); + brelse(bh); + return -EPERM; + } + if (!inode->i_nlinks) { + printk("Deleting nonexistent file (%04x:%d), %d\n", + inode->i_dev,inode->i_num,inode->i_nlinks); + inode->i_nlinks=1; + } + de->inode = 0; + bh->b_dirt = 1; + brelse(bh); + inode->i_nlinks--; + inode->i_dirt = 1; + inode->i_ctime = CURRENT_TIME; + iput(inode); + iput(dir); + return 0; +} + +int sys_link(const char * oldname, const char * newname) +{ + struct dir_entry * de; + struct m_inode * oldinode, * dir; + struct buffer_head * bh; + const char * basename; + int namelen; + + oldinode=namei(oldname); + if (!oldinode) + return -ENOENT; + if (S_ISDIR(oldinode->i_mode)) { + iput(oldinode); + return -EPERM; + } + dir = dir_namei(newname,&namelen,&basename); + if (!dir) { + iput(oldinode); + return -EACCES; + } + if (!namelen) { + iput(oldinode); + iput(dir); + return -EPERM; + } + if (dir->i_dev != oldinode->i_dev) { + iput(dir); + iput(oldinode); + return -EXDEV; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + iput(oldinode); + return -EACCES; + } + bh = find_entry(&dir,basename,namelen,&de); + if (bh) { + brelse(bh); + iput(dir); + iput(oldinode); + return -EEXIST; + } + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + iput(dir); + iput(oldinode); + return -ENOSPC; + } + de->inode = oldinode->i_num; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + oldinode->i_nlinks++; + oldinode->i_ctime = CURRENT_TIME; + oldinode->i_dirt = 1; + iput(oldinode); + return 0; +} diff --git a/kernel/0.1x/linux-0.11/fs/open.c b/kernel/0.1x/linux-0.11/fs/open.c new file mode 100644 index 00000000..d043e94a --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/open.c @@ -0,0 +1,208 @@ +/* + * linux/fs/open.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +int sys_ustat(int dev, struct ustat * ubuf) +{ + return -ENOSYS; +} + +int sys_utime(char * filename, struct utimbuf * times) +{ + struct m_inode * inode; + long actime,modtime; + + if (!(inode=namei(filename))) + return -ENOENT; + if (times) { + actime = get_fs_long((unsigned long *) ×->actime); + modtime = get_fs_long((unsigned long *) ×->modtime); + } else + actime = modtime = CURRENT_TIME; + inode->i_atime = actime; + inode->i_mtime = modtime; + inode->i_dirt = 1; + iput(inode); + return 0; +} + +/* + * XXX should we use the real or effective uid? BSD uses the real uid, + * so as to make this call useful to setuid programs. + */ +int sys_access(const char * filename,int mode) +{ + struct m_inode * inode; + int res, i_mode; + + mode &= 0007; + if (!(inode=namei(filename))) + return -EACCES; + i_mode = res = inode->i_mode & 0777; + iput(inode); + if (current->uid == inode->i_uid) + res >>= 6; + else if (current->gid == inode->i_gid) + res >>= 6; + if ((res & 0007 & mode) == mode) + return 0; + /* + * XXX we are doing this test last because we really should be + * swapping the effective with the real user id (temporarily), + * and then calling suser() routine. If we do call the + * suser() routine, it needs to be called last. + */ + if ((!current->uid) && + (!(mode & 1) || (i_mode & 0111))) + return 0; + return -EACCES; +} + +int sys_chdir(const char * filename) +{ + struct m_inode * inode; + + if (!(inode = namei(filename))) + return -ENOENT; + if (!S_ISDIR(inode->i_mode)) { + iput(inode); + return -ENOTDIR; + } + iput(current->pwd); + current->pwd = inode; + return (0); +} + +int sys_chroot(const char * filename) +{ + struct m_inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if (!S_ISDIR(inode->i_mode)) { + iput(inode); + return -ENOTDIR; + } + iput(current->root); + current->root = inode; + return (0); +} + +int sys_chmod(const char * filename,int mode) +{ + struct m_inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if ((current->euid != inode->i_uid) && !suser()) { + iput(inode); + return -EACCES; + } + inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777); + inode->i_dirt = 1; + iput(inode); + return 0; +} + +int sys_chown(const char * filename,int uid,int gid) +{ + struct m_inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if (!suser()) { + iput(inode); + return -EACCES; + } + inode->i_uid=uid; + inode->i_gid=gid; + inode->i_dirt=1; + iput(inode); + return 0; +} + +int sys_open(const char * filename,int flag,int mode) +{ + struct m_inode * inode; + struct file * f; + int i,fd; + + mode &= 0777 & ~current->umask; + for(fd=0 ; fdfilp[fd]) + break; + if (fd>=NR_OPEN) + return -EINVAL; + current->close_on_exec &= ~(1<f_count) break; + if (i>=NR_FILE) + return -EINVAL; + (current->filp[fd]=f)->f_count++; + if ((i=open_namei(filename,flag,mode,&inode))<0) { + current->filp[fd]=NULL; + f->f_count=0; + return i; + } +/* ttys are somewhat special (ttyxx major==4, tty major==5) */ + if (S_ISCHR(inode->i_mode)) + if (MAJOR(inode->i_zone[0])==4) { + if (current->leader && current->tty<0) { + current->tty = MINOR(inode->i_zone[0]); + tty_table[current->tty].pgrp = current->pgrp; + } + } else if (MAJOR(inode->i_zone[0])==5) + if (current->tty<0) { + iput(inode); + current->filp[fd]=NULL; + f->f_count=0; + return -EPERM; + } +/* Likewise with block-devices: check for floppy_change */ + if (S_ISBLK(inode->i_mode)) + check_disk_change(inode->i_zone[0]); + f->f_mode = inode->i_mode; + f->f_flags = flag; + f->f_count = 1; + f->f_inode = inode; + f->f_pos = 0; + return (fd); +} + +int sys_creat(const char * pathname, int mode) +{ + return sys_open(pathname, O_CREAT | O_TRUNC, mode); +} + +int sys_close(unsigned int fd) +{ + struct file * filp; + + if (fd >= NR_OPEN) + return -EINVAL; + current->close_on_exec &= ~(1<filp[fd])) + return -EINVAL; + current->filp[fd] = NULL; + if (filp->f_count == 0) + panic("Close: file count is 0"); + if (--filp->f_count) + return (0); + iput(filp->f_inode); + return (0); +} diff --git a/kernel/0.1x/linux-0.11/fs/pipe.c b/kernel/0.1x/linux-0.11/fs/pipe.c new file mode 100644 index 00000000..93c5d881 --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/pipe.c @@ -0,0 +1,111 @@ +/* + * linux/fs/pipe.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include /* for get_free_page */ +#include + +int read_pipe(struct m_inode * inode, char * buf, int count) +{ + int chars, size, read = 0; + + while (count>0) { + while (!(size=PIPE_SIZE(*inode))) { + wake_up(&inode->i_wait); + if (inode->i_count != 2) /* are there any writers? */ + return read; + sleep_on(&inode->i_wait); + } + chars = PAGE_SIZE-PIPE_TAIL(*inode); + if (chars > count) + chars = count; + if (chars > size) + chars = size; + count -= chars; + read += chars; + size = PIPE_TAIL(*inode); + PIPE_TAIL(*inode) += chars; + PIPE_TAIL(*inode) &= (PAGE_SIZE-1); + while (chars-->0) + put_fs_byte(((char *)inode->i_size)[size++],buf++); + } + wake_up(&inode->i_wait); + return read; +} + +int write_pipe(struct m_inode * inode, char * buf, int count) +{ + int chars, size, written = 0; + + while (count>0) { + while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) { + wake_up(&inode->i_wait); + if (inode->i_count != 2) { /* no readers */ + current->signal |= (1<<(SIGPIPE-1)); + return written?written:-1; + } + sleep_on(&inode->i_wait); + } + chars = PAGE_SIZE-PIPE_HEAD(*inode); + if (chars > count) + chars = count; + if (chars > size) + chars = size; + count -= chars; + written += chars; + size = PIPE_HEAD(*inode); + PIPE_HEAD(*inode) += chars; + PIPE_HEAD(*inode) &= (PAGE_SIZE-1); + while (chars-->0) + ((char *)inode->i_size)[size++]=get_fs_byte(buf++); + } + wake_up(&inode->i_wait); + return written; +} + +int sys_pipe(unsigned long * fildes) +{ + struct m_inode * inode; + struct file * f[2]; + int fd[2]; + int i,j; + + j=0; + for(i=0;j<2 && if_count++; + if (j==1) + f[0]->f_count=0; + if (j<2) + return -1; + j=0; + for(i=0;j<2 && ifilp[i]) { + current->filp[ fd[j]=i ] = f[j]; + j++; + } + if (j==1) + current->filp[fd[0]]=NULL; + if (j<2) { + f[0]->f_count=f[1]->f_count=0; + return -1; + } + if (!(inode=get_pipe_inode())) { + current->filp[fd[0]] = + current->filp[fd[1]] = NULL; + f[0]->f_count = f[1]->f_count = 0; + return -1; + } + f[0]->f_inode = f[1]->f_inode = inode; + f[0]->f_pos = f[1]->f_pos = 0; + f[0]->f_mode = 1; /* read */ + f[1]->f_mode = 2; /* write */ + put_fs_long(fd[0],0+fildes); + put_fs_long(fd[1],1+fildes); + return 0; +} diff --git a/kernel/0.1x/linux-0.11/fs/read_write.c b/kernel/0.1x/linux-0.11/fs/read_write.c new file mode 100644 index 00000000..b6c96fde --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/read_write.c @@ -0,0 +1,103 @@ +/* + * linux/fs/read_write.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include +#include + +extern int rw_char(int rw,int dev, char * buf, int count, off_t * pos); +extern int read_pipe(struct m_inode * inode, char * buf, int count); +extern int write_pipe(struct m_inode * inode, char * buf, int count); +extern int block_read(int dev, off_t * pos, char * buf, int count); +extern int block_write(int dev, off_t * pos, char * buf, int count); +extern int file_read(struct m_inode * inode, struct file * filp, + char * buf, int count); +extern int file_write(struct m_inode * inode, struct file * filp, + char * buf, int count); + +int sys_lseek(unsigned int fd,off_t offset, int origin) +{ + struct file * file; + int tmp; + + if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode) + || !IS_SEEKABLE(MAJOR(file->f_inode->i_dev))) + return -EBADF; + if (file->f_inode->i_pipe) + return -ESPIPE; + switch (origin) { + case 0: + if (offset<0) return -EINVAL; + file->f_pos=offset; + break; + case 1: + if (file->f_pos+offset<0) return -EINVAL; + file->f_pos += offset; + break; + case 2: + if ((tmp=file->f_inode->i_size+offset) < 0) + return -EINVAL; + file->f_pos = tmp; + break; + default: + return -EINVAL; + } + return file->f_pos; +} + +int sys_read(unsigned int fd,char * buf,int count) +{ + struct file * file; + struct m_inode * inode; + + if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd])) + return -EINVAL; + if (!count) + return 0; + verify_area(buf,count); + inode = file->f_inode; + if (inode->i_pipe) + return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO; + if (S_ISCHR(inode->i_mode)) + return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos); + if (S_ISBLK(inode->i_mode)) + return block_read(inode->i_zone[0],&file->f_pos,buf,count); + if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) { + if (count+file->f_pos > inode->i_size) + count = inode->i_size - file->f_pos; + if (count<=0) + return 0; + return file_read(inode,file,buf,count); + } + printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode); + return -EINVAL; +} + +int sys_write(unsigned int fd,char * buf,int count) +{ + struct file * file; + struct m_inode * inode; + + if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd])) + return -EINVAL; + if (!count) + return 0; + inode=file->f_inode; + if (inode->i_pipe) + return (file->f_mode&2)?write_pipe(inode,buf,count):-EIO; + if (S_ISCHR(inode->i_mode)) + return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos); + if (S_ISBLK(inode->i_mode)) + return block_write(inode->i_zone[0],&file->f_pos,buf,count); + if (S_ISREG(inode->i_mode)) + return file_write(inode,file,buf,count); + printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode); + return -EINVAL; +} diff --git a/kernel/0.1x/linux-0.11/fs/stat.c b/kernel/0.1x/linux-0.11/fs/stat.c new file mode 100644 index 00000000..0ec56c9a --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/stat.c @@ -0,0 +1,56 @@ +/* + * linux/fs/stat.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include + +static void cp_stat(struct m_inode * inode, struct stat * statbuf) +{ + struct stat tmp; + int i; + + verify_area(statbuf,sizeof (* statbuf)); + tmp.st_dev = inode->i_dev; + tmp.st_ino = inode->i_num; + tmp.st_mode = inode->i_mode; + tmp.st_nlink = inode->i_nlinks; + tmp.st_uid = inode->i_uid; + tmp.st_gid = inode->i_gid; + tmp.st_rdev = inode->i_zone[0]; + tmp.st_size = inode->i_size; + tmp.st_atime = inode->i_atime; + tmp.st_mtime = inode->i_mtime; + tmp.st_ctime = inode->i_ctime; + for (i=0 ; i= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode)) + return -EBADF; + cp_stat(inode,statbuf); + return 0; +} diff --git a/kernel/0.1x/linux-0.11/fs/super.c b/kernel/0.1x/linux-0.11/fs/super.c new file mode 100644 index 00000000..d0474641 --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/super.c @@ -0,0 +1,281 @@ +/* + * linux/fs/super.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * super.c contains code to handle the super-block tables. + */ +#include +#include +#include +#include + +#include +#include + +int sync_dev(int dev); +void wait_for_keypress(void); + +/* set_bit uses setb, as gas doesn't recognize setc */ +#define set_bit(bitnr,addr) ({ \ +register int __res __asm__("ax"); \ +__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \ +__res; }) + +struct super_block super_block[NR_SUPER]; +/* this is initialized in init/main.c */ +int ROOT_DEV = 0; + +static void lock_super(struct super_block * sb) +{ + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); + sb->s_lock = 1; + sti(); +} + +static void free_super(struct super_block * sb) +{ + cli(); + sb->s_lock = 0; + wake_up(&(sb->s_wait)); + sti(); +} + +static void wait_on_super(struct super_block * sb) +{ + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); + sti(); +} + +struct super_block * get_super(int dev) +{ + struct super_block * s; + + if (!dev) + return NULL; + s = 0+super_block; + while (s < NR_SUPER+super_block) + if (s->s_dev == dev) { + wait_on_super(s); + if (s->s_dev == dev) + return s; + s = 0+super_block; + } else + s++; + return NULL; +} + +void put_super(int dev) +{ + struct super_block * sb; + struct m_inode * inode; + int i; + + if (dev == ROOT_DEV) { + printk("root diskette changed: prepare for armageddon\n\r"); + return; + } + if (!(sb = get_super(dev))) + return; + if (sb->s_imount) { + printk("Mounted disk changed - tssk, tssk\n\r"); + return; + } + lock_super(sb); + sb->s_dev = 0; + for(i=0;is_imap[i]); + for(i=0;is_zmap[i]); + free_super(sb); + return; +} + +static struct super_block * read_super(int dev) +{ + struct super_block * s; + struct buffer_head * bh; + int i,block; + + if (!dev) + return NULL; + check_disk_change(dev); + if (s = get_super(dev)) + return s; + for (s = 0+super_block ;; s++) { + if (s >= NR_SUPER+super_block) + return NULL; + if (!s->s_dev) + break; + } + s->s_dev = dev; + s->s_isup = NULL; + s->s_imount = NULL; + s->s_time = 0; + s->s_rd_only = 0; + s->s_dirt = 0; + lock_super(s); + if (!(bh = bread(dev,1))) { + s->s_dev=0; + free_super(s); + return NULL; + } + *((struct d_super_block *) s) = + *((struct d_super_block *) bh->b_data); + brelse(bh); + if (s->s_magic != SUPER_MAGIC) { + s->s_dev = 0; + free_super(s); + return NULL; + } + for (i=0;is_imap[i] = NULL; + for (i=0;is_zmap[i] = NULL; + block=2; + for (i=0 ; i < s->s_imap_blocks ; i++) + if (s->s_imap[i]=bread(dev,block)) + block++; + else + break; + for (i=0 ; i < s->s_zmap_blocks ; i++) + if (s->s_zmap[i]=bread(dev,block)) + block++; + else + break; + if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) { + for(i=0;is_imap[i]); + for(i=0;is_zmap[i]); + s->s_dev=0; + free_super(s); + return NULL; + } + s->s_imap[0]->b_data[0] |= 1; + s->s_zmap[0]->b_data[0] |= 1; + free_super(s); + return s; +} + +int sys_umount(char * dev_name) +{ + struct m_inode * inode; + struct super_block * sb; + int dev; + + if (!(inode=namei(dev_name))) + return -ENOENT; + dev = inode->i_zone[0]; + if (!S_ISBLK(inode->i_mode)) { + iput(inode); + return -ENOTBLK; + } + iput(inode); + if (dev==ROOT_DEV) + return -EBUSY; + if (!(sb=get_super(dev)) || !(sb->s_imount)) + return -ENOENT; + if (!sb->s_imount->i_mount) + printk("Mounted inode has i_mount=0\n"); + for (inode=inode_table+0 ; inodei_dev==dev && inode->i_count) + return -EBUSY; + sb->s_imount->i_mount=0; + iput(sb->s_imount); + sb->s_imount = NULL; + iput(sb->s_isup); + sb->s_isup = NULL; + put_super(dev); + sync_dev(dev); + return 0; +} + +int sys_mount(char * dev_name, char * dir_name, int rw_flag) +{ + struct m_inode * dev_i, * dir_i; + struct super_block * sb; + int dev; + + if (!(dev_i=namei(dev_name))) + return -ENOENT; + dev = dev_i->i_zone[0]; + if (!S_ISBLK(dev_i->i_mode)) { + iput(dev_i); + return -EPERM; + } + iput(dev_i); + if (!(dir_i=namei(dir_name))) + return -ENOENT; + if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) { + iput(dir_i); + return -EBUSY; + } + if (!S_ISDIR(dir_i->i_mode)) { + iput(dir_i); + return -EPERM; + } + if (!(sb=read_super(dev))) { + iput(dir_i); + return -EBUSY; + } + if (sb->s_imount) { + iput(dir_i); + return -EBUSY; + } + if (dir_i->i_mount) { + iput(dir_i); + return -EPERM; + } + sb->s_imount=dir_i; + dir_i->i_mount=1; + dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */ + return 0; /* we do that in umount */ +} + +void mount_root(void) +{ + int i,free; + struct super_block * p; + struct m_inode * mi; + + if (32 != sizeof (struct d_inode)) + panic("bad i-node size"); + for(i=0;is_dev = 0; + p->s_lock = 0; + p->s_wait = NULL; + } + if (!(p=read_super(ROOT_DEV))) + panic("Unable to mount root"); + if (!(mi=iget(ROOT_DEV,ROOT_INO))) + panic("Unable to read root i-node"); + mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ + p->s_isup = p->s_imount = mi; + current->pwd = mi; + current->root = mi; + free=0; + i=p->s_nzones; + while (-- i >= 0) + if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data)) + free++; + printk("%d/%d free blocks\n\r",free,p->s_nzones); + free=0; + i=p->s_ninodes+1; + while (-- i >= 0) + if (!set_bit(i&8191,p->s_imap[i>>13]->b_data)) + free++; + printk("%d/%d free inodes\n\r",free,p->s_ninodes); +} diff --git a/kernel/0.1x/linux-0.11/fs/truncate.c b/kernel/0.1x/linux-0.11/fs/truncate.c new file mode 100644 index 00000000..769e1090 --- /dev/null +++ b/kernel/0.1x/linux-0.11/fs/truncate.c @@ -0,0 +1,65 @@ +/* + * linux/fs/truncate.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include + +static void free_ind(int dev,int block) +{ + struct buffer_head * bh; + unsigned short * p; + int i; + + if (!block) + return; + if (bh=bread(dev,block)) { + p = (unsigned short *) bh->b_data; + for (i=0;i<512;i++,p++) + if (*p) + free_block(dev,*p); + brelse(bh); + } + free_block(dev,block); +} + +static void free_dind(int dev,int block) +{ + struct buffer_head * bh; + unsigned short * p; + int i; + + if (!block) + return; + if (bh=bread(dev,block)) { + p = (unsigned short *) bh->b_data; + for (i=0;i<512;i++,p++) + if (*p) + free_ind(dev,*p); + brelse(bh); + } + free_block(dev,block); +} + +void truncate(struct m_inode * inode) +{ + int i; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) + return; + for (i=0;i<7;i++) + if (inode->i_zone[i]) { + free_block(inode->i_dev,inode->i_zone[i]); + inode->i_zone[i]=0; + } + free_ind(inode->i_dev,inode->i_zone[7]); + free_dind(inode->i_dev,inode->i_zone[8]); + inode->i_zone[7] = inode->i_zone[8] = 0; + inode->i_size = 0; + inode->i_dirt = 1; + inode->i_mtime = inode->i_ctime = CURRENT_TIME; +} + diff --git a/kernel/0.1x/linux-0.11/include/a.out.h b/kernel/0.1x/linux-0.11/include/a.out.h new file mode 100644 index 00000000..2f5f3dcd --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/kernel/0.1x/linux-0.11/include/asm/io.h b/kernel/0.1x/linux-0.11/include/asm/io.h new file mode 100644 index 00000000..53646abc --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/kernel/0.1x/linux-0.11/include/asm/memory.h b/kernel/0.1x/linux-0.11/include/asm/memory.h new file mode 100644 index 00000000..dba1062f --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/kernel/0.1x/linux-0.11/include/asm/segment.h b/kernel/0.1x/linux-0.11/include/asm/segment.h new file mode 100644 index 00000000..9a643e08 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/asm/segment.h @@ -0,0 +1,65 @@ +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)); +} + +/* + * Someone who knows GNU asm better than I should double check the followig. + * It seems to work, but I don't know if I'm doing something subtly wrong. + * --- TYT, 11/24/91 + * [ nothing wrong here, Linus ] + */ + +extern inline unsigned long get_fs() +{ + unsigned short _v; + __asm__("mov %%fs,%%ax":"=a" (_v):); + return _v; +} + +extern inline unsigned long get_ds() +{ + unsigned short _v; + __asm__("mov %%ds,%%ax":"=a" (_v):); + return _v; +} + +extern inline void set_fs(unsigned long val) +{ + __asm__("mov %0,%%fs"::"a" ((unsigned short) val)); +} + diff --git a/kernel/0.1x/linux-0.11/include/asm/system.h b/kernel/0.1x/linux-0.11/include/asm/system.h new file mode 100644 index 00000000..231c8f34 --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/kernel/0.1x/linux-0.11/include/const.h b/kernel/0.1x/linux-0.11/include/const.h new file mode 100644 index 00000000..88e96416 --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/kernel/0.1x/linux-0.11/include/ctype.h b/kernel/0.1x/linux-0.11/include/ctype.h new file mode 100644 index 00000000..2d833c62 --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/kernel/0.1x/linux-0.11/include/errno.h b/kernel/0.1x/linux-0.11/include/errno.h new file mode 100644 index 00000000..18f2aaf6 --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/kernel/0.1x/linux-0.11/include/fcntl.h b/kernel/0.1x/linux-0.11/include/fcntl.h new file mode 100644 index 00000000..d339b5e7 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/fcntl.h @@ -0,0 +1,55 @@ +#ifndef _FCNTL_H +#define _FCNTL_H + +#include + +/* open/fcntl - NOCTTY, NDELAY isn't implemented yet */ +#define O_ACCMODE 00003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 00100 /* not fcntl */ +#define O_EXCL 00200 /* not fcntl */ +#define O_NOCTTY 00400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 /* not fcntl */ +#define O_NDELAY O_NONBLOCK + +/* Defines for fcntl-commands. Note that currently + * locking isn't supported, and other things aren't really + * tested. + */ +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get f_flags */ +#define F_SETFD 2 /* set f_flags */ +#define F_GETFL 3 /* more flags (cloexec) */ +#define F_SETFL 4 +#define F_GETLK 5 /* not implemented */ +#define F_SETLK 6 +#define F_SETLKW 7 + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* Ok, these are locking features, and aren't implemented at any + * level. POSIX wants them. + */ +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +/* Once again - not implemented, but ... */ +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +extern int creat(const char * filename,mode_t mode); +extern int fcntl(int fildes,int cmd, ...); +extern int open(const char * filename, int flags, ...); + +#endif diff --git a/kernel/0.1x/linux-0.11/include/linux/config.h b/kernel/0.1x/linux-0.11/include/linux/config.h new file mode 100644 index 00000000..328a07b0 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/linux/config.h @@ -0,0 +1,48 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +/* + * The root-device is no longer hard-coded. You can change the default + * root-device by changing the line ROOT_DEV = XXX in boot/bootsect.s + */ + +/* + * define your keyboard here - + * KBD_FINNISH for Finnish keyboards + * KBD_US for US-type + * KBD_GR for German keyboards + * KBD_FR for Frech keyboard + */ +/*#define KBD_US */ +/*#define KBD_GR */ +/*#define KBD_FR */ +#define KBD_FINNISH + +/* + * Normally, Linux can get the drive parameters from the BIOS at + * startup, but if this for some unfathomable reason fails, you'd + * be left stranded. For this case, you can define HD_TYPE, which + * contains all necessary info on your harddisk. + * + * The HD_TYPE macro should look like this: + * + * #define HD_TYPE { head, sect, cyl, wpcom, lzone, ctl} + * + * In case of two harddisks, the info should be sepatated by + * commas: + * + * #define HD_TYPE { h,s,c,wpcom,lz,ctl },{ h,s,c,wpcom,lz,ctl } + */ +/* + This is an example, two drives, first is type 2, second is type 3: + +#define HD_TYPE { 4,17,615,300,615,8 }, { 6,17,615,300,615,0 } + + NOTE: ctl is 0 for all drives with heads<=8, and ctl=8 for drives + with more than 8 heads. + + If you want the BIOS to tell what kind of drive you have, just + leave HD_TYPE undefined. This is the normal thing to do. +*/ + +#endif diff --git a/kernel/0.1x/linux-0.11/include/linux/fdreg.h b/kernel/0.1x/linux-0.11/include/linux/fdreg.h new file mode 100644 index 00000000..61f4da90 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/linux/fdreg.h @@ -0,0 +1,71 @@ +/* + * This file contains some defines for the floppy disk controller. + * Various sources. Mostly "IBM Microcomputers: A Programmers + * Handbook", Sanches and Canton. + */ +#ifndef _FDREG_H +#define _FDREG_H + +extern int ticks_to_floppy_on(unsigned int nr); +extern void floppy_on(unsigned int nr); +extern void floppy_off(unsigned int nr); +extern void floppy_select(unsigned int nr); +extern void floppy_deselect(unsigned int nr); + +/* Fd controller regs. S&C, about page 340 */ +#define FD_STATUS 0x3f4 +#define FD_DATA 0x3f5 +#define FD_DOR 0x3f2 /* Digital Output Register */ +#define FD_DIR 0x3f7 /* Digital Input Register (read) */ +#define FD_DCR 0x3f7 /* Diskette Control Register (write)*/ + +/* Bits of main status register */ +#define STATUS_BUSYMASK 0x0F /* drive busy mask */ +#define STATUS_BUSY 0x10 /* FDC busy */ +#define STATUS_DMA 0x20 /* 0- DMA mode */ +#define STATUS_DIR 0x40 /* 0- cpu->fdc */ +#define STATUS_READY 0x80 /* Data reg ready */ + +/* Bits of FD_ST0 */ +#define ST0_DS 0x03 /* drive select mask */ +#define ST0_HA 0x04 /* Head (Address) */ +#define ST0_NR 0x08 /* Not Ready */ +#define ST0_ECE 0x10 /* Equipment chech error */ +#define ST0_SE 0x20 /* Seek end */ +#define ST0_INTR 0xC0 /* Interrupt code mask */ + +/* Bits of FD_ST1 */ +#define ST1_MAM 0x01 /* Missing Address Mark */ +#define ST1_WP 0x02 /* Write Protect */ +#define ST1_ND 0x04 /* No Data - unreadable */ +#define ST1_OR 0x10 /* OverRun */ +#define ST1_CRC 0x20 /* CRC error in data or addr */ +#define ST1_EOC 0x80 /* End Of Cylinder */ + +/* Bits of FD_ST2 */ +#define ST2_MAM 0x01 /* Missing Addess Mark (again) */ +#define ST2_BC 0x02 /* Bad Cylinder */ +#define ST2_SNS 0x04 /* Scan Not Satisfied */ +#define ST2_SEH 0x08 /* Scan Equal Hit */ +#define ST2_WC 0x10 /* Wrong Cylinder */ +#define ST2_CRC 0x20 /* CRC error in data field */ +#define ST2_CM 0x40 /* Control Mark = deleted */ + +/* Bits of FD_ST3 */ +#define ST3_HA 0x04 /* Head (Address) */ +#define ST3_TZ 0x10 /* Track Zero signal (1=track 0) */ +#define ST3_WP 0x40 /* Write Protect */ + +/* Values for FD_COMMAND */ +#define FD_RECALIBRATE 0x07 /* move to track 0 */ +#define FD_SEEK 0x0F /* seek track */ +#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */ +#define FD_WRITE 0xC5 /* write with MT, MFM */ +#define FD_SENSEI 0x08 /* Sense Interrupt Status */ +#define FD_SPECIFY 0x03 /* specify HUT etc */ + +/* DMA commands */ +#define DMA_READ 0x46 +#define DMA_WRITE 0x4A + +#endif diff --git a/kernel/0.1x/linux-0.11/include/linux/fs.h b/kernel/0.1x/linux-0.11/include/linux/fs.h new file mode 100644 index 00000000..6a84e5d9 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/linux/fs.h @@ -0,0 +1,202 @@ +/* + * This file has definitions for some important file table + * structures etc. + */ + +#ifndef _FS_H +#define _FS_H + +#include + +/* devices are as follows: (same as minix, so we can use the minix + * file system. These are major numbers.) + * + * 0 - unused (nodev) + * 1 - /dev/mem + * 2 - /dev/fd + * 3 - /dev/hd + * 4 - /dev/ttyx + * 5 - /dev/tty + * 6 - /dev/lp + * 7 - unnamed pipes + */ + +#define IS_SEEKABLE(x) ((x)>=1 && (x)<=3) + +#define READ 0 +#define WRITE 1 +#define READA 2 /* read-ahead - don't pause */ +#define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */ + +void buffer_init(long buffer_end); + +#define MAJOR(a) (((unsigned)(a))>>8) +#define MINOR(a) ((a)&0xff) + +#define NAME_LEN 14 +#define ROOT_INO 1 + +#define I_MAP_SLOTS 8 +#define Z_MAP_SLOTS 8 +#define SUPER_MAGIC 0x137F + +#define NR_OPEN 20 +#define NR_INODE 32 +#define NR_FILE 64 +#define NR_SUPER 8 +#define NR_HASH 307 +#define NR_BUFFERS nr_buffers +#define BLOCK_SIZE 1024 +#define BLOCK_SIZE_BITS 10 +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#define INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct d_inode))) +#define DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct dir_entry))) + +#define PIPE_HEAD(inode) ((inode).i_zone[0]) +#define PIPE_TAIL(inode) ((inode).i_zone[1]) +#define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1)) +#define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode)) +#define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1)) +#define INC_PIPE(head) \ +__asm__("incl %0\n\tandl $4095,%0"::"m" (head)) + +typedef char buffer_block[BLOCK_SIZE]; + +struct buffer_head { + char * b_data; /* pointer to data block (1024 bytes) */ + unsigned long b_blocknr; /* block number */ + unsigned short b_dev; /* device (0 = free) */ + unsigned char b_uptodate; + unsigned char b_dirt; /* 0-clean,1-dirty */ + unsigned char b_count; /* users using this block */ + unsigned char b_lock; /* 0 - ok, 1 -locked */ + struct task_struct * b_wait; + struct buffer_head * b_prev; + struct buffer_head * b_next; + struct buffer_head * b_prev_free; + struct buffer_head * b_next_free; +}; + +struct d_inode { + unsigned short i_mode; + unsigned short i_uid; + unsigned long i_size; + unsigned long i_time; + unsigned char i_gid; + unsigned char i_nlinks; + unsigned short i_zone[9]; +}; + +struct m_inode { + unsigned short i_mode; + unsigned short i_uid; + unsigned long i_size; + unsigned long i_mtime; + unsigned char i_gid; + unsigned char i_nlinks; + unsigned short i_zone[9]; +/* these are in memory also */ + struct task_struct * i_wait; + unsigned long i_atime; + unsigned long i_ctime; + unsigned short i_dev; + unsigned short i_num; + unsigned short i_count; + unsigned char i_lock; + unsigned char i_dirt; + unsigned char i_pipe; + unsigned char i_mount; + unsigned char i_seek; + unsigned char i_update; +}; + +struct file { + unsigned short f_mode; + unsigned short f_flags; + unsigned short f_count; + struct m_inode * f_inode; + off_t f_pos; +}; + +struct super_block { + unsigned short s_ninodes; + unsigned short s_nzones; + unsigned short s_imap_blocks; + unsigned short s_zmap_blocks; + unsigned short s_firstdatazone; + unsigned short s_log_zone_size; + unsigned long s_max_size; + unsigned short s_magic; +/* These are only in memory */ + struct buffer_head * s_imap[8]; + struct buffer_head * s_zmap[8]; + unsigned short s_dev; + struct m_inode * s_isup; + struct m_inode * s_imount; + unsigned long s_time; + struct task_struct * s_wait; + unsigned char s_lock; + unsigned char s_rd_only; + unsigned char s_dirt; +}; + +struct d_super_block { + unsigned short s_ninodes; + unsigned short s_nzones; + unsigned short s_imap_blocks; + unsigned short s_zmap_blocks; + unsigned short s_firstdatazone; + unsigned short s_log_zone_size; + unsigned long s_max_size; + unsigned short s_magic; +}; + +struct dir_entry { + unsigned short inode; + char name[NAME_LEN]; +}; + +extern struct m_inode inode_table[NR_INODE]; +extern struct file file_table[NR_FILE]; +extern struct super_block super_block[NR_SUPER]; +extern struct buffer_head * start_buffer; +extern int nr_buffers; + +extern void check_disk_change(int dev); +extern int floppy_change(unsigned int nr); +extern int ticks_to_floppy_on(unsigned int dev); +extern void floppy_on(unsigned int dev); +extern void floppy_off(unsigned int dev); +extern void truncate(struct m_inode * inode); +extern void sync_inodes(void); +extern void wait_on(struct m_inode * inode); +extern int bmap(struct m_inode * inode,int block); +extern int create_block(struct m_inode * inode,int block); +extern struct m_inode * namei(const char * pathname); +extern int open_namei(const char * pathname, int flag, int mode, + struct m_inode ** res_inode); +extern void iput(struct m_inode * inode); +extern struct m_inode * iget(int dev,int nr); +extern struct m_inode * get_empty_inode(void); +extern struct m_inode * get_pipe_inode(void); +extern struct buffer_head * get_hash_table(int dev, int block); +extern struct buffer_head * getblk(int dev, int block); +extern void ll_rw_block(int rw, struct buffer_head * bh); +extern void brelse(struct buffer_head * buf); +extern struct buffer_head * bread(int dev,int block); +extern void bread_page(unsigned long addr,int dev,int b[4]); +extern struct buffer_head * breada(int dev,int block,...); +extern int new_block(int dev); +extern void free_block(int dev, int block); +extern struct m_inode * new_inode(int dev); +extern void free_inode(struct m_inode * inode); +extern int sync_dev(int dev); +extern struct super_block * get_super(int dev); +extern int ROOT_DEV; + +extern void mount_root(void); + +#endif diff --git a/kernel/0.1x/linux-0.11/include/linux/hdreg.h b/kernel/0.1x/linux-0.11/include/linux/hdreg.h new file mode 100644 index 00000000..202db422 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/linux/hdreg.h @@ -0,0 +1,65 @@ +/* + * This file contains some defines for the AT-hd-controller. + * Various sources. Check out some definitions (see comments with + * a ques). + */ +#ifndef _HDREG_H +#define _HDREG_H + +/* Hd controller regs. Ref: IBM AT Bios-listing */ +#define HD_DATA 0x1f0 /* _CTL when writing */ +#define HD_ERROR 0x1f1 /* see err-bits */ +#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */ +#define HD_SECTOR 0x1f3 /* starting sector */ +#define HD_LCYL 0x1f4 /* starting cylinder */ +#define HD_HCYL 0x1f5 /* high byte of starting cyl */ +#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */ +#define HD_STATUS 0x1f7 /* see status-bits */ +#define HD_PRECOMP HD_ERROR /* same io address, read=error, write=precomp */ +#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */ + +#define HD_CMD 0x3f6 + +/* Bits of HD_STATUS */ +#define ERR_STAT 0x01 +#define INDEX_STAT 0x02 +#define ECC_STAT 0x04 /* Corrected error */ +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Values for HD_COMMAND */ +#define WIN_RESTORE 0x10 +#define WIN_READ 0x20 +#define WIN_WRITE 0x30 +#define WIN_VERIFY 0x40 +#define WIN_FORMAT 0x50 +#define WIN_INIT 0x60 +#define WIN_SEEK 0x70 +#define WIN_DIAGNOSE 0x90 +#define WIN_SPECIFY 0x91 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark ? */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* ? */ +#define ID_ERR 0x10 /* ? */ +#define ECC_ERR 0x40 /* ? */ +#define BBD_ERR 0x80 /* ? */ + +struct partition { + unsigned char boot_ind; /* 0x80 - active (unused) */ + unsigned char head; /* ? */ + unsigned char sector; /* ? */ + unsigned char cyl; /* ? */ + unsigned char sys_ind; /* ? */ + unsigned char end_head; /* ? */ + unsigned char end_sector; /* ? */ + unsigned char end_cyl; /* ? */ + unsigned int start_sect; /* starting sector counting from 0 */ + unsigned int nr_sects; /* nr of sectors in partition */ +}; + +#endif diff --git a/kernel/0.1x/linux-0.11/include/linux/head.h b/kernel/0.1x/linux-0.11/include/linux/head.h new file mode 100644 index 00000000..f5468a0e --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/kernel/0.1x/linux-0.11/include/linux/kernel.h b/kernel/0.1x/linux-0.11/include/linux/kernel.h new file mode 100644 index 00000000..3b28aac7 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/linux/kernel.h @@ -0,0 +1,22 @@ +/* + * 'kernel.h' contains some often-used function prototypes etc + */ +void verify_area(void * addr,int count); +volatile void panic(const char * str); +int printf(const char * fmt, ...); +int printk(const char * fmt, ...); +int tty_write(unsigned ch,char * buf,int count); +void * malloc(unsigned int size); +void free_s(void * obj, int size); + +#define free(x) free_s((x), 0) + +/* + * This is defined as a macro, but at some point this might become a + * real subroutine that sets a flag if it returns true (to do + * BSD-style accounting where the process is flagged if it uses root + * privs). The implication of this is that you should do normal + * permissions checks first, and check suser() last. + */ +#define suser() (current->euid == 0) + diff --git a/kernel/0.1x/linux-0.11/include/linux/mm.h b/kernel/0.1x/linux-0.11/include/linux/mm.h new file mode 100644 index 00000000..e13acb32 --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/kernel/0.1x/linux-0.11/include/linux/sched.h b/kernel/0.1x/linux-0.11/include/linux/sched.h new file mode 100644 index 00000000..b86a8703 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/linux/sched.h @@ -0,0 +1,233 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#define NR_TASKS 64 +#define HZ 100 + +#define FIRST_TASK task[0] +#define LAST_TASK task[NR_TASKS-1] + +#include +#include +#include +#include + +#if (NR_OPEN > 32) +#error "Currently the close-on-exec-flags are in one word, max 32 files/proc" +#endif + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_ZOMBIE 3 +#define TASK_STOPPED 4 + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +extern int copy_page_tables(unsigned long from, unsigned long to, long size); +extern int free_page_tables(unsigned long from, unsigned long size); + +extern void sched_init(void); +extern void schedule(void); +extern void trap_init(void); +extern void panic(const char * str); +extern int tty_write(unsigned minor,char * buf,int count); + +typedef int (*fn_ptr)(); + +struct i387_struct { + long cwd; + long swd; + long twd; + long fip; + long fcs; + long foo; + long fos; + long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ +}; + +struct tss_struct { + long back_link; /* 16 high bits zero */ + long esp0; + long ss0; /* 16 high bits zero */ + long esp1; + long ss1; /* 16 high bits zero */ + long esp2; + long ss2; /* 16 high bits zero */ + long cr3; + long eip; + long eflags; + long eax,ecx,edx,ebx; + long esp; + long ebp; + long esi; + long edi; + long es; /* 16 high bits zero */ + long cs; /* 16 high bits zero */ + long ss; /* 16 high bits zero */ + long ds; /* 16 high bits zero */ + long fs; /* 16 high bits zero */ + long gs; /* 16 high bits zero */ + long ldt; /* 16 high bits zero */ + long trace_bitmap; /* bits: trace 0, bitmap 16-31 */ + struct i387_struct i387; +}; + +struct task_struct { +/* these are hardcoded - don't touch */ + long state; /* -1 unrunnable, 0 runnable, >0 stopped */ + long counter; + long priority; + long signal; + struct sigaction sigaction[32]; + long blocked; /* bitmap of masked signals */ +/* various fields */ + int exit_code; + unsigned long start_code,end_code,end_data,brk,start_stack; + long pid,father,pgrp,session,leader; + unsigned short uid,euid,suid; + unsigned short gid,egid,sgid; + long alarm; + long utime,stime,cutime,cstime,start_time; + unsigned short used_math; +/* file system info */ + int tty; /* -1 if no tty, so it must be signed */ + unsigned short umask; + struct m_inode * pwd; + struct m_inode * root; + struct m_inode * executable; + unsigned long close_on_exec; + struct file * filp[NR_OPEN]; +/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */ + struct desc_struct ldt[3]; +/* tss for this task */ + struct tss_struct tss; +}; + +/* + * INIT_TASK is used to set up the first task table, touch at + * your own risk!. Base=0, limit=0x9ffff (=640kB) + */ +#define INIT_TASK \ +/* state etc */ { 0,15,15, \ +/* signals */ 0,{{},},0, \ +/* ec,brk... */ 0,0,0,0,0,0, \ +/* pid etc.. */ 0,-1,0,0,0, \ +/* uid etc */ 0,0,0,0,0,0, \ +/* alarm */ 0,0,0,0,0,0, \ +/* math */ 0, \ +/* fs info */ -1,0022,NULL,NULL,NULL,0, \ +/* filp */ {NULL,}, \ + { \ + {0,0}, \ +/* ldt */ {0x9f,0xc0fa00}, \ + {0x9f,0xc0f200}, \ + }, \ +/*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\ + 0,0,0,0,0,0,0,0, \ + 0,0,0x17,0x17,0x17,0x17,0x17,0x17, \ + _LDT(0),0x80000000, \ + {} \ + }, \ +} + +extern struct task_struct *task[NR_TASKS]; +extern struct task_struct *last_task_used_math; +extern struct task_struct *current; +extern long volatile jiffies; +extern long startup_time; + +#define CURRENT_TIME (startup_time+jiffies/HZ) + +extern void add_timer(long jiffies, void (*fn)(void)); +extern void sleep_on(struct task_struct ** p); +extern void interruptible_sleep_on(struct task_struct ** p); +extern void wake_up(struct task_struct ** p); + +/* + * Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall + * 4-TSS0, 5-LDT0, 6-TSS1 etc ... + */ +#define FIRST_TSS_ENTRY 4 +#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1) +#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3)) +#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3)) +#define ltr(n) __asm__("ltr %%ax"::"a" (_TSS(n))) +#define lldt(n) __asm__("lldt %%ax"::"a" (_LDT(n))) +#define str(n) \ +__asm__("str %%ax\n\t" \ + "subl %2,%%eax\n\t" \ + "shrl $4,%%eax" \ + :"=a" (n) \ + :"a" (0),"i" (FIRST_TSS_ENTRY<<3)) +/* + * switch_to(n) should switch tasks to task nr n, first + * checking that n isn't the current task, in which case it does nothing. + * This also clears the TS-flag if the task we switched to has used + * tha math co-processor latest. + */ +#define switch_to(n) {\ +struct {long a,b;} __tmp; \ +__asm__("cmpl %%ecx,_current\n\t" \ + "je 1f\n\t" \ + "movw %%dx,%1\n\t" \ + "xchgl %%ecx,_current\n\t" \ + "ljmp %0\n\t" \ + "cmpl %%ecx,_last_task_used_math\n\t" \ + "jne 1f\n\t" \ + "clts\n" \ + "1:" \ + ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ + "d" (_TSS(n)),"c" ((long) task[n])); \ +} + +#define PAGE_ALIGN(n) (((n)+0xfff)&0xfffff000) + +#define _set_base(addr,base) \ +__asm__("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/kernel/0.1x/linux-0.11/include/linux/sys.h b/kernel/0.1x/linux-0.11/include/linux/sys.h new file mode 100644 index 00000000..6fe69599 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/linux/sys.h @@ -0,0 +1,86 @@ +extern int sys_setup(); +extern int sys_exit(); +extern int sys_fork(); +extern int sys_read(); +extern int sys_write(); +extern int sys_open(); +extern int sys_close(); +extern int sys_waitpid(); +extern int sys_creat(); +extern int sys_link(); +extern int sys_unlink(); +extern int sys_execve(); +extern int sys_chdir(); +extern int sys_time(); +extern int sys_mknod(); +extern int sys_chmod(); +extern int sys_chown(); +extern int sys_break(); +extern int sys_stat(); +extern int sys_lseek(); +extern int sys_getpid(); +extern int sys_mount(); +extern int sys_umount(); +extern int sys_setuid(); +extern int sys_getuid(); +extern int sys_stime(); +extern int sys_ptrace(); +extern int sys_alarm(); +extern int sys_fstat(); +extern int sys_pause(); +extern int sys_utime(); +extern int sys_stty(); +extern int sys_gtty(); +extern int sys_access(); +extern int sys_nice(); +extern int sys_ftime(); +extern int sys_sync(); +extern int sys_kill(); +extern int sys_rename(); +extern int sys_mkdir(); +extern int sys_rmdir(); +extern int sys_dup(); +extern int sys_pipe(); +extern int sys_times(); +extern int sys_prof(); +extern int sys_brk(); +extern int sys_setgid(); +extern int sys_getgid(); +extern int sys_signal(); +extern int sys_geteuid(); +extern int sys_getegid(); +extern int sys_acct(); +extern int sys_phys(); +extern int sys_lock(); +extern int sys_ioctl(); +extern int sys_fcntl(); +extern int sys_mpx(); +extern int sys_setpgid(); +extern int sys_ulimit(); +extern int sys_uname(); +extern int sys_umask(); +extern int sys_chroot(); +extern int sys_ustat(); +extern int sys_dup2(); +extern int sys_getppid(); +extern int sys_getpgrp(); +extern int sys_setsid(); +extern int sys_sigaction(); +extern int sys_sgetmask(); +extern int sys_ssetmask(); +extern int sys_setreuid(); +extern int sys_setregid(); + +fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read, +sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link, +sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod, +sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount, +sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm, +sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access, +sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir, +sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid, +sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys, +sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit, +sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid, +sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask, +sys_setreuid,sys_setregid }; diff --git a/kernel/0.1x/linux-0.11/include/linux/tty.h b/kernel/0.1x/linux-0.11/include/linux/tty.h new file mode 100644 index 00000000..bc665440 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/linux/tty.h @@ -0,0 +1,77 @@ +/* + * 'tty.h' defines some structures used by tty_io.c and some defines. + * + * NOTE! Don't touch this without checking that nothing in rs_io.s or + * con_io.s breaks. Some constants are hardwired into the system (mainly + * offsets into 'tty_queue' + */ + +#ifndef _TTY_H +#define _TTY_H + +#include + +#define TTY_BUF_SIZE 1024 + +struct tty_queue { + unsigned long data; + unsigned long head; + unsigned long tail; + struct task_struct * proc_list; + char buf[TTY_BUF_SIZE]; +}; + +#define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1)) +#define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1)) +#define EMPTY(a) ((a).head == (a).tail) +#define LEFT(a) (((a).tail-(a).head-1)&(TTY_BUF_SIZE-1)) +#define LAST(a) ((a).buf[(TTY_BUF_SIZE-1)&((a).head-1)]) +#define FULL(a) (!LEFT(a)) +#define CHARS(a) (((a).head-(a).tail)&(TTY_BUF_SIZE-1)) +#define GETCH(queue,c) \ +(void)({c=(queue).buf[(queue).tail];INC((queue).tail);}) +#define PUTCH(c,queue) \ +(void)({(queue).buf[(queue).head]=(c);INC((queue).head);}) + +#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR]) +#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT]) +#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE]) +#define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL]) +#define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF]) +#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART]) +#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP]) +#define SUSPEND_CHAR(tty) ((tty)->termios.c_cc[VSUSP]) + +struct tty_struct { + struct termios termios; + int pgrp; + int stopped; + void (*write)(struct tty_struct * tty); + struct tty_queue read_q; + struct tty_queue write_q; + struct tty_queue secondary; + }; + +extern struct tty_struct tty_table[]; + +/* intr=^C quit=^| erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" + +void rs_init(void); +void con_init(void); +void tty_init(void); + +int tty_read(unsigned c, char * buf, int n); +int tty_write(unsigned c, char * buf, int n); + +void rs_write(struct tty_struct * tty); +void con_write(struct tty_struct * tty); + +void copy_to_cooked(struct tty_struct * tty); + +#endif diff --git a/kernel/0.1x/linux-0.11/include/signal.h b/kernel/0.1x/linux-0.11/include/signal.h new file mode 100644 index 00000000..b6ba6056 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/signal.h @@ -0,0 +1,68 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include + +typedef int sig_atomic_t; +typedef unsigned int sigset_t; /* 32 bits */ + +#define _NSIG 32 +#define NSIG _NSIG + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGUNUSED 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 + +/* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */ +#define SA_NOCLDSTOP 1 +#define SA_NOMASK 0x40000000 +#define SA_ONESHOT 0x80000000 + +#define SIG_BLOCK 0 /* for blocking signals */ +#define SIG_UNBLOCK 1 /* for unblocking signals */ +#define SIG_SETMASK 2 /* for setting the signal mask */ + +#define SIG_DFL ((void (*)(int))0) /* default signal handling */ +#define SIG_IGN ((void (*)(int))1) /* ignore signal */ + +struct sigaction { + void (*sa_handler)(int); + sigset_t sa_mask; + int sa_flags; + void (*sa_restorer)(void); +}; + +void (*signal(int _sig, void (*_func)(int)))(int); +int raise(int sig); +int kill(pid_t pid, int sig); +int sigaddset(sigset_t *mask, int signo); +int sigdelset(sigset_t *mask, int signo); +int sigemptyset(sigset_t *mask); +int sigfillset(sigset_t *mask); +int sigismember(sigset_t *mask, int signo); /* 1 - is, 0 - not, -1 error */ +int sigpending(sigset_t *set); +int sigprocmask(int how, sigset_t *set, sigset_t *oldset); +int sigsuspend(sigset_t *sigmask); +int sigaction(int sig, struct sigaction *act, struct sigaction *oldact); + +#endif /* _SIGNAL_H */ diff --git a/kernel/0.1x/linux-0.11/include/stdarg.h b/kernel/0.1x/linux-0.11/include/stdarg.h new file mode 100644 index 00000000..0126a7cf --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/kernel/0.1x/linux-0.11/include/stddef.h b/kernel/0.1x/linux-0.11/include/stddef.h new file mode 100644 index 00000000..41957264 --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/kernel/0.1x/linux-0.11/include/string.h b/kernel/0.1x/linux-0.11/include/string.h new file mode 100644 index 00000000..f06f6139 --- /dev/null +++ b/kernel/0.1x/linux-0.11/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 + +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/kernel/0.1x/linux-0.11/include/sys/times.h b/kernel/0.1x/linux-0.11/include/sys/times.h new file mode 100644 index 00000000..aa78d000 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/sys/times.h @@ -0,0 +1,15 @@ +#ifndef _TIMES_H +#define _TIMES_H + +#include + +struct tms { + time_t tms_utime; + time_t tms_stime; + time_t tms_cutime; + time_t tms_cstime; +}; + +extern time_t times(struct tms * tp); + +#endif diff --git a/kernel/0.1x/linux-0.11/include/sys/types.h b/kernel/0.1x/linux-0.11/include/sys/types.h new file mode 100644 index 00000000..89c03d97 --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/kernel/0.1x/linux-0.11/include/sys/utsname.h b/kernel/0.1x/linux-0.11/include/sys/utsname.h new file mode 100644 index 00000000..9c6aa5c5 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/sys/utsname.h @@ -0,0 +1,16 @@ +#ifndef _SYS_UTSNAME_H +#define _SYS_UTSNAME_H + +#include + +struct utsname { + char sysname[9]; + char nodename[9]; + char release[9]; + char version[9]; + char machine[9]; +}; + +extern int uname(struct utsname * utsbuf); + +#endif diff --git a/kernel/0.1x/linux-0.11/include/sys/wait.h b/kernel/0.1x/linux-0.11/include/sys/wait.h new file mode 100644 index 00000000..88414fcf --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/sys/wait.h @@ -0,0 +1,23 @@ +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include + +#define _LOW(v) ( (v) & 0377) +#define _HIGH(v) ( ((v) >> 8) & 0377) + +/* options for waitpid, WUNTRACED not supported */ +#define WNOHANG 1 +#define WUNTRACED 2 + +#define WIFEXITED(s) (!((s)&0xFF) +#define WIFSTOPPED(s) (((s)&0xFF)==0x7F) +#define WEXITSTATUS(s) (((s)>>8)&0xFF) +#define WTERMSIG(s) ((s)&0x7F) +#define WSTOPSIG(s) (((s)>>8)&0xFF) +#define WIFSIGNALED(s) (((unsigned int)(s)-1 & 0xFFFF) < 0xFF) + +pid_t wait(int *stat_loc); +pid_t waitpid(pid_t pid, int *stat_loc, int options); + +#endif diff --git a/kernel/0.1x/linux-0.11/include/termios.h b/kernel/0.1x/linux-0.11/include/termios.h new file mode 100644 index 00000000..a3c17344 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/termios.h @@ -0,0 +1,228 @@ +#ifndef _TERMIOS_H +#define _TERMIOS_H + +#define TTY_BUF_SIZE 1024 + +/* 0x54 is just a magic number to make these relatively uniqe ('T') */ + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define TIOCINQ 0x541B + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +#define NCCS 17 +struct termios { + unsigned long c_iflag; /* input mode flags */ + unsigned long c_oflag; /* output mode flags */ + unsigned long c_cflag; /* control mode flags */ + unsigned long c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0040000 +#define FF0 0000000 +#define FF1 0040000 + +/* c_cflag bit meaning */ +#define CBAUD 0000017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define CPARENB 0000400 +#define CPARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 +#define CIBAUD 03600000 /* input baud rate (not used) */ +#define CRTSCTS 020000000000 /* flow control */ + +#define PARENB CPARENB +#define PARODD CPARODD + +/* c_lflag bits */ +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +typedef int speed_t; + +extern speed_t cfgetispeed(struct termios *termios_p); +extern speed_t cfgetospeed(struct termios *termios_p); +extern int cfsetispeed(struct termios *termios_p, speed_t speed); +extern int cfsetospeed(struct termios *termios_p, speed_t speed); +extern int tcdrain(int fildes); +extern int tcflow(int fildes, int action); +extern int tcflush(int fildes, int queue_selector); +extern int tcgetattr(int fildes, struct termios *termios_p); +extern int tcsendbreak(int fildes, int duration); +extern int tcsetattr(int fildes, int optional_actions, + struct termios *termios_p); + +#endif diff --git a/kernel/0.1x/linux-0.11/include/time.h b/kernel/0.1x/linux-0.11/include/time.h new file mode 100644 index 00000000..f4368ad7 --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/kernel/0.1x/linux-0.11/include/unistd.h b/kernel/0.1x/linux-0.11/include/unistd.h new file mode 100644 index 00000000..02595915 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/unistd.h @@ -0,0 +1,253 @@ +#ifndef _UNISTD_H +#define _UNISTD_H + +/* ok, this may be a joke, but I'm working on it */ +#define _POSIX_VERSION 198808L + +#define _POSIX_CHOWN_RESTRICTED /* only root can do a chown (I think..) */ +#define _POSIX_NO_TRUNC /* no pathname truncation (but see in kernel) */ +#define _POSIX_VDISABLE '\0' /* character to disable things like ^C */ +/*#define _POSIX_SAVED_IDS */ /* we'll get to this yet */ +/*#define _POSIX_JOB_CONTROL */ /* we aren't there quite yet. Soon hopefully */ + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#ifndef NULL +#define NULL ((void *)0) +#endif + +/* access */ +#define F_OK 0 +#define X_OK 1 +#define W_OK 2 +#define R_OK 4 + +/* lseek */ +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +/* _SC stands for System Configuration. We don't use them much */ +#define _SC_ARG_MAX 1 +#define _SC_CHILD_MAX 2 +#define _SC_CLOCKS_PER_SEC 3 +#define _SC_NGROUPS_MAX 4 +#define _SC_OPEN_MAX 5 +#define _SC_JOB_CONTROL 6 +#define _SC_SAVED_IDS 7 +#define _SC_VERSION 8 + +/* more (possibly) configurable things - now pathnames */ +#define _PC_LINK_MAX 1 +#define _PC_MAX_CANON 2 +#define _PC_MAX_INPUT 3 +#define _PC_NAME_MAX 4 +#define _PC_PATH_MAX 5 +#define _PC_PIPE_BUF 6 +#define _PC_NO_TRUNC 7 +#define _PC_VDISABLE 8 +#define _PC_CHOWN_RESTRICTED 9 + +#include +#include +#include +#include + +#ifdef __LIBRARY__ + +#define __NR_setup 0 /* used only by init, to get system going */ +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_stat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_fstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_phys 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_uname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 + +#define _syscall0(type,name) \ +type name(void) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name)); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall1(type,name,atype,a) \ +type name(atype a) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a))); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall2(type,name,atype,a,btype,b) \ +type name(atype a,btype b) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b))); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall3(type,name,atype,a,btype,b,ctype,c) \ +type name(atype a,btype b,ctype c) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \ +if (__res>=0) \ + return (type) __res; \ +errno=-__res; \ +return -1; \ +} + +#endif /* __LIBRARY__ */ + +extern int errno; + +int access(const char * filename, mode_t mode); +int acct(const char * filename); +int alarm(int sec); +int brk(void * end_data_segment); +void * sbrk(ptrdiff_t increment); +int chdir(const char * filename); +int chmod(const char * filename, mode_t mode); +int chown(const char * filename, uid_t owner, gid_t group); +int chroot(const char * filename); +int close(int fildes); +int creat(const char * filename, mode_t mode); +int dup(int fildes); +int execve(const char * filename, char ** argv, char ** envp); +int execv(const char * pathname, char ** argv); +int execvp(const char * file, char ** argv); +int execl(const char * pathname, char * arg0, ...); +int execlp(const char * file, char * arg0, ...); +int execle(const char * pathname, char * arg0, ...); +volatile void exit(int status); +volatile void _exit(int status); +int fcntl(int fildes, int cmd, ...); +int fork(void); +int getpid(void); +int getuid(void); +int geteuid(void); +int getgid(void); +int getegid(void); +int ioctl(int fildes, int cmd, ...); +int kill(pid_t pid, int signal); +int link(const char * filename1, const char * filename2); +int lseek(int fildes, off_t offset, int origin); +int mknod(const char * filename, mode_t mode, dev_t dev); +int mount(const char * specialfile, const char * dir, int rwflag); +int nice(int val); +int open(const char * filename, int flag, ...); +int pause(void); +int pipe(int * fildes); +int read(int fildes, char * buf, off_t count); +int setpgrp(void); +int setpgid(pid_t pid,pid_t pgid); +int setuid(uid_t uid); +int setgid(gid_t gid); +void (*signal(int sig, void (*fn)(int)))(int); +int stat(const char * filename, struct stat * stat_buf); +int fstat(int fildes, struct stat * stat_buf); +int stime(time_t * tptr); +int sync(void); +time_t time(time_t * tloc); +time_t times(struct tms * tbuf); +int ulimit(int cmd, long limit); +mode_t umask(mode_t mask); +int umount(const char * specialfile); +int uname(struct utsname * name); +int unlink(const char * filename); +int ustat(dev_t dev, struct ustat * ubuf); +int utime(const char * filename, struct utimbuf * times); +pid_t waitpid(pid_t pid,int * wait_stat,int options); +pid_t wait(int * wait_stat); +int write(int fildes, const char * buf, off_t count); +int dup2(int oldfd, int newfd); +int getppid(void); +pid_t getpgrp(void); +pid_t setsid(void); + +#endif diff --git a/kernel/0.1x/linux-0.11/include/utime.h b/kernel/0.1x/linux-0.11/include/utime.h new file mode 100644 index 00000000..7b6d6971 --- /dev/null +++ b/kernel/0.1x/linux-0.11/include/utime.h @@ -0,0 +1,13 @@ +#ifndef _UTIME_H +#define _UTIME_H + +#include /* I know - shouldn't do this, but .. */ + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +extern int utime(const char *filename, struct utimbuf *times); + +#endif diff --git a/kernel/0.1x/linux-0.11/init/main.c b/kernel/0.1x/linux-0.11/init/main.c new file mode 100644 index 00000000..d055f98f --- /dev/null +++ b/kernel/0.1x/linux-0.11/init/main.c @@ -0,0 +1,209 @@ +/* + * linux/init/main.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ +static inline _syscall0(int,fork) +static inline _syscall0(int,pause) +static inline _syscall1(int,setup,void *,BIOS) +static inline _syscall0(int,sync) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +static char printbuf[1024]; + +extern int vsprintf(); +extern void init(void); +extern void blk_dev_init(void); +extern void chr_dev_init(void); +extern void hd_init(void); +extern void floppy_init(void); +extern void mem_init(long start, long end); +extern long rd_init(long mem_start, int length); +extern long kernel_mktime(struct tm * tm); +extern long startup_time; + +/* + * This is set up by the setup-routine at boot-time + */ +#define EXT_MEM_K (*(unsigned short *)0x90002) +#define DRIVE_INFO (*(struct drive_info *)0x90080) +#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC) + +/* + * Yeah, yeah, it's ugly, but I cannot find how to do this correctly + * and this seems to work. I anybody has more info on the real-time + * clock I'd be interested. Most of this was trial and error, and some + * bios-listing reading. Urghh. + */ + +#define CMOS_READ(addr) ({ \ +outb_p(0x80|addr,0x70); \ +inb_p(0x71); \ +}) + +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) + +static void time_init(void) +{ + struct tm time; + + do { + time.tm_sec = CMOS_READ(0); + time.tm_min = CMOS_READ(2); + time.tm_hour = CMOS_READ(4); + time.tm_mday = CMOS_READ(7); + time.tm_mon = CMOS_READ(8); + time.tm_year = CMOS_READ(9); + } while (time.tm_sec != CMOS_READ(0)); + BCD_TO_BIN(time.tm_sec); + BCD_TO_BIN(time.tm_min); + BCD_TO_BIN(time.tm_hour); + BCD_TO_BIN(time.tm_mday); + BCD_TO_BIN(time.tm_mon); + BCD_TO_BIN(time.tm_year); + time.tm_mon--; + startup_time = kernel_mktime(&time); +} + +static long memory_end = 0; +static long buffer_memory_end = 0; +static long main_memory_start = 0; + +struct drive_info { char dummy[32]; } drive_info; + +void main(void) /* This really IS void, no error here. */ +{ /* The startup routine assumes (well, ...) this */ +/* + * Interrupts are still disabled. Do necessary setups, then + * enable them + */ + ROOT_DEV = ORIG_ROOT_DEV; + drive_info = DRIVE_INFO; + memory_end = (1<<20) + (EXT_MEM_K<<10); + memory_end &= 0xfffff000; + if (memory_end > 16*1024*1024) + memory_end = 16*1024*1024; + if (memory_end > 12*1024*1024) + buffer_memory_end = 4*1024*1024; + else if (memory_end > 6*1024*1024) + buffer_memory_end = 2*1024*1024; + else + buffer_memory_end = 1*1024*1024; + main_memory_start = buffer_memory_end; +#ifdef RAMDISK + main_memory_start += rd_init(main_memory_start, RAMDISK*1024); +#endif + mem_init(main_memory_start,memory_end); + trap_init(); + blk_dev_init(); + chr_dev_init(); + tty_init(); + time_init(); + sched_init(); + buffer_init(buffer_memory_end); + hd_init(); + floppy_init(); + sti(); + move_to_user_mode(); + if (!fork()) { /* we count on this going ok */ + init(); + } +/* + * NOTE!! For any other task 'pause()' would mean we have to get a + * signal to awaken, but task0 is the sole exception (see 'schedule()') + * as task 0 gets activated at every idle moment (when no other tasks + * can run). For task0 'pause()' just means we go check if some other + * task can run, and if not we return here. + */ + for(;;) pause(); +} + +static int printf(const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + write(1,printbuf,i=vsprintf(printbuf, fmt, args)); + va_end(args); + return i; +} + +static char * argv_rc[] = { "/bin/sh", NULL }; +static char * envp_rc[] = { "HOME=/", NULL }; + +static char * argv[] = { "-/bin/sh",NULL }; +static char * envp[] = { "HOME=/usr/root", NULL }; + +void init(void) +{ + int pid,i; + + setup((void *) &drive_info); + (void) open("/dev/tty0",O_RDWR,0); + (void) dup(0); + (void) dup(0); + printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS, + NR_BUFFERS*BLOCK_SIZE); + printf("Free mem: %d bytes\n\r",memory_end-main_memory_start); + if (!(pid=fork())) { + close(0); + if (open("/etc/rc",O_RDONLY,0)) + _exit(1); + execve("/bin/sh",argv_rc,envp_rc); + _exit(2); + } + if (pid>0) + while (pid != wait(&i)) + /* nothing */; + while (1) { + if ((pid=fork())<0) { + printf("Fork failed in init\r\n"); + continue; + } + if (!pid) { + close(0);close(1);close(2); + setsid(); + (void) open("/dev/tty0",O_RDWR,0); + (void) dup(0); + (void) dup(0); + _exit(execve("/bin/sh",argv,envp)); + } + while (1) + if (pid == wait(&i)) + break; + printf("\n\rchild %d died with code %04x\n\r",pid,i); + sync(); + } + _exit(0); /* NOTE! _exit, not exit() */ +} diff --git a/kernel/0.1x/linux-0.11/kernel/Makefile b/kernel/0.1x/linux-0.11/kernel/Makefile new file mode 100644 index 00000000..eda0c8b5 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/Makefile @@ -0,0 +1,83 @@ +# +# Makefile for the FREAX-kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =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 sys.o exit.o \ + signal.o mktime.o + +kernel.o: $(OBJS) + $(LD) -r -o kernel.o $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make keyboard.s + for i in *.c;do rm -f `basename $$i .c`.s;done + (cd chr_drv; make clean) + (cd blk_drv; make clean) + (cd math; make clean) + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + (cd chr_drv; make dep) + (cd blk_drv; make dep) + +### Dependencies: +exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \ + ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \ + ../include/asm/segment.h +fork.s fork.o : fork.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/segment.h ../include/asm/system.h +mktime.s mktime.o : mktime.c ../include/time.h +panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h +printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \ + ../include/linux/kernel.h +sched.s sched.o : sched.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/signal.h ../include/linux/kernel.h ../include/linux/sys.h \ + ../include/linux/fdreg.h ../include/asm/system.h ../include/asm/io.h \ + ../include/asm/segment.h +signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h +sys.s sys.o : sys.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/tty.h \ + ../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h \ + ../include/sys/times.h ../include/sys/utsname.h +traps.s traps.o : traps.c ../include/string.h ../include/linux/head.h \ + ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ + ../include/asm/system.h ../include/asm/segment.h ../include/asm/io.h +vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h diff --git a/kernel/0.1x/linux-0.11/kernel/asm.s b/kernel/0.1x/linux-0.11/kernel/asm.s new file mode 100644 index 00000000..e561de4c --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/asm.s @@ -0,0 +1,146 @@ +/* + * linux/kernel/asm.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * asm.s contains the low-level code for most hardware faults. + * page_exception is handled by the mm, so that isn't here. This + * file also handles (hopefully) fpu-exceptions due to TS-bit, as + * the fpu must be properly saved/resored. This hasn't been tested. + */ + +.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op +.globl _double_fault,_coprocessor_segment_overrun +.globl _invalid_TSS,_segment_not_present,_stack_segment +.globl _general_protection,_coprocessor_error,_irq13,_reserved + +_divide_error: + pushl $_do_divide_error +no_error_code: + xchgl %eax,(%esp) + pushl %ebx + pushl %ecx + pushl %edx + pushl %edi + pushl %esi + pushl %ebp + push %ds + push %es + push %fs + pushl $0 # "error code" + lea 44(%esp),%edx + pushl %edx + movl $0x10,%edx + mov %dx,%ds + mov %dx,%es + mov %dx,%fs + call *%eax + addl $8,%esp + pop %fs + pop %es + pop %ds + popl %ebp + popl %esi + popl %edi + popl %edx + popl %ecx + popl %ebx + popl %eax + iret + +_debug: + pushl $_do_int3 # _do_debug + jmp no_error_code + +_nmi: + pushl $_do_nmi + jmp no_error_code + +_int3: + pushl $_do_int3 + jmp no_error_code + +_overflow: + pushl $_do_overflow + jmp no_error_code + +_bounds: + pushl $_do_bounds + jmp no_error_code + +_invalid_op: + pushl $_do_invalid_op + jmp no_error_code + +_coprocessor_segment_overrun: + pushl $_do_coprocessor_segment_overrun + jmp no_error_code + +_reserved: + pushl $_do_reserved + jmp no_error_code + +_irq13: + pushl %eax + xorb %al,%al + outb %al,$0xF0 + movb $0x20,%al + outb %al,$0x20 + jmp 1f +1: jmp 1f +1: outb %al,$0xA0 + popl %eax + jmp _coprocessor_error + +_double_fault: + pushl $_do_double_fault +error_code: + xchgl %eax,4(%esp) # error code <-> %eax + xchgl %ebx,(%esp) # &function <-> %ebx + pushl %ecx + pushl %edx + pushl %edi + pushl %esi + pushl %ebp + push %ds + push %es + push %fs + pushl %eax # error code + lea 44(%esp),%eax # offset + pushl %eax + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + call *%ebx + addl $8,%esp + pop %fs + pop %es + pop %ds + popl %ebp + popl %esi + popl %edi + popl %edx + popl %ecx + popl %ebx + popl %eax + iret + +_invalid_TSS: + pushl $_do_invalid_TSS + jmp error_code + +_segment_not_present: + pushl $_do_segment_not_present + jmp error_code + +_stack_segment: + pushl $_do_stack_segment + jmp error_code + +_general_protection: + pushl $_do_general_protection + jmp error_code + diff --git a/kernel/0.1x/linux-0.11/kernel/blk_drv/Makefile b/kernel/0.1x/linux-0.11/kernel/blk_drv/Makefile new file mode 100644 index 00000000..828ad079 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/blk_drv/Makefile @@ -0,0 +1,58 @@ +# +# Makefile for the FREAX-kernel block device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =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 = ll_rw_blk.o floppy.o hd.o ramdisk.o + +blk_drv.a: $(OBJS) + $(AR) rcs blk_drv.a $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/signal.h ../../include/linux/kernel.h \ + ../../include/linux/fdreg.h ../../include/asm/system.h \ + ../../include/asm/io.h ../../include/asm/segment.h blk.h +hd.s hd.o : hd.c ../../include/linux/config.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h ../../include/signal.h \ + ../../include/linux/kernel.h ../../include/linux/hdreg.h \ + ../../include/asm/system.h ../../include/asm/io.h \ + ../../include/asm/segment.h blk.h +ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h ../../include/signal.h \ + ../../include/linux/kernel.h ../../include/asm/system.h blk.h diff --git a/kernel/0.1x/linux-0.11/kernel/blk_drv/blk.h b/kernel/0.1x/linux-0.11/kernel/blk_drv/blk.h new file mode 100644 index 00000000..2ab078cc --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/blk_drv/blk.h @@ -0,0 +1,140 @@ +#ifndef _BLK_H +#define _BLK_H + +#define NR_BLK_DEV 7 +/* + * NR_REQUEST is the number of entries in the request-queue. + * NOTE that writes may use only the low 2/3 of these: reads + * take precedence. + * + * 32 seems to be a reasonable number: enough to get some benefit + * from the elevator-mechanism, but not so much as to lock a lot of + * buffers when they are in the queue. 64 seems to be too many (easily + * long pauses in reading when heavy writing/syncing is going on) + */ +#define NR_REQUEST 32 + +/* + * Ok, this is an expanded form so that we can use the same + * request for paging requests when that is implemented. In + * paging, 'bh' is NULL, and 'waiting' is used to wait for + * read/write completion. + */ +struct request { + int dev; /* -1 if no request */ + int cmd; /* READ or WRITE */ + int errors; + unsigned long sector; + unsigned long nr_sectors; + char * buffer; + struct task_struct * waiting; + struct buffer_head * bh; + struct request * next; +}; + +/* + * This is used in the elevator algorithm: Note that + * reads always go before writes. This is natural: reads + * are much more time-critical than writes. + */ +#define IN_ORDER(s1,s2) \ +((s1)->cmd<(s2)->cmd || (s1)->cmd==(s2)->cmd && \ +((s1)->dev < (s2)->dev || ((s1)->dev == (s2)->dev && \ +(s1)->sector < (s2)->sector))) + +struct blk_dev_struct { + void (*request_fn)(void); + struct request * current_request; +}; + +extern struct blk_dev_struct blk_dev[NR_BLK_DEV]; +extern struct request request[NR_REQUEST]; +extern struct task_struct * wait_for_request; + +#ifdef MAJOR_NR + +/* + * Add entries as needed. Currently the only block devices + * supported are hard-disks and floppies. + */ + +#if (MAJOR_NR == 1) +/* ram disk */ +#define DEVICE_NAME "ramdisk" +#define DEVICE_REQUEST do_rd_request +#define DEVICE_NR(device) ((device) & 7) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == 2) +/* floppy */ +#define DEVICE_NAME "floppy" +#define DEVICE_INTR do_floppy +#define DEVICE_REQUEST do_fd_request +#define DEVICE_NR(device) ((device) & 3) +#define DEVICE_ON(device) floppy_on(DEVICE_NR(device)) +#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) + +#elif (MAJOR_NR == 3) +/* harddisk */ +#define DEVICE_NAME "harddisk" +#define DEVICE_INTR do_hd +#define DEVICE_REQUEST do_hd_request +#define DEVICE_NR(device) (MINOR(device)/5) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif +/* unknown blk device */ +#error "unknown blk device" + +#endif + +#define CURRENT (blk_dev[MAJOR_NR].current_request) +#define CURRENT_DEV DEVICE_NR(CURRENT->dev) + +#ifdef DEVICE_INTR +void (*DEVICE_INTR)(void) = NULL; +#endif +static void (DEVICE_REQUEST)(void); + +extern inline void unlock_buffer(struct buffer_head * bh) +{ + if (!bh->b_lock) + printk(DEVICE_NAME ": free buffer being unlocked\n"); + bh->b_lock=0; + wake_up(&bh->b_wait); +} + +extern inline void end_request(int uptodate) +{ + DEVICE_OFF(CURRENT->dev); + if (CURRENT->bh) { + CURRENT->bh->b_uptodate = uptodate; + unlock_buffer(CURRENT->bh); + } + if (!uptodate) { + printk(DEVICE_NAME " I/O error\n\r"); + printk("dev %04x, block %d\n\r",CURRENT->dev, + CURRENT->bh->b_blocknr); + } + wake_up(&CURRENT->waiting); + wake_up(&wait_for_request); + CURRENT->dev = -1; + CURRENT = CURRENT->next; +} + +#define INIT_REQUEST \ +repeat: \ + if (!CURRENT) \ + return; \ + if (MAJOR(CURRENT->dev) != MAJOR_NR) \ + panic(DEVICE_NAME ": request list destroyed"); \ + if (CURRENT->bh) { \ + if (!CURRENT->bh->b_lock) \ + panic(DEVICE_NAME ": block not locked"); \ + } + +#endif + +#endif diff --git a/kernel/0.1x/linux-0.11/kernel/blk_drv/floppy.c b/kernel/0.1x/linux-0.11/kernel/blk_drv/floppy.c new file mode 100644 index 00000000..b3d8dfbe --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/blk_drv/floppy.c @@ -0,0 +1,462 @@ +/* + * linux/kernel/floppy.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 02.12.91 - Changed to static variables to indicate need for reset + * and recalibrate. This makes some things easier (output_byte reset + * checking etc), and means less interrupt jumping in case of errors, + * so the code is hopefully easier to understand. + */ + +/* + * This file is certainly a mess. I've tried my best to get it working, + * but I don't like programming floppies, and I have only one anyway. + * Urgel. I should check for more errors, and do more graceful error + * recovery. Seems there are problems with several drives. I've tried to + * correct them. No promises. + */ + +/* + * As with hd.c, all routines within this file can (and will) be called + * by interrupts, so extreme caution is needed. A hardware interrupt + * handler may not sleep, or a kernel panic will happen. Thus I cannot + * call "floppy-on" directly, but have to set a special timer interrupt + * etc. + * + * Also, I'm not certain this works on more than 1 floppy. Bugs may + * abund. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 2 +#include "blk.h" + +static int recalibrate = 0; +static int reset = 0; +static int seek = 0; + +extern unsigned char current_DOR; + +#define immoutb_p(val,port) \ +__asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port)) + +#define TYPE(x) ((x)>>2) +#define DRIVE(x) ((x)&0x03) +/* + * Note that MAX_ERRORS=8 doesn't imply that we retry every bad read + * max 8 times - some types of errors increase the errorcount by 2, + * so we might actually retry only 5-6 times before giving up. + */ +#define MAX_ERRORS 8 + +/* + * globals used by 'result()' + */ +#define MAX_REPLIES 7 +static unsigned char reply_buffer[MAX_REPLIES]; +#define ST0 (reply_buffer[0]) +#define ST1 (reply_buffer[1]) +#define ST2 (reply_buffer[2]) +#define ST3 (reply_buffer[3]) + +/* + * This struct defines the different floppy types. Unlike minix + * linux doesn't have a "search for right type"-type, as the code + * for that is convoluted and weird. I've got enough problems with + * this driver as it is. + * + * The 'stretch' tells if the tracks need to be boubled for some + * types (ie 360kB diskette in 1.2MB drive etc). Others should + * be self-explanatory. + */ +static struct floppy_struct { + unsigned int size, sect, head, track, stretch; + unsigned char gap,rate,spec1; +} floppy_type[] = { + { 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */ + { 720, 9,2,40,0,0x2A,0x02,0xDF }, /* 360kB PC diskettes */ + { 2400,15,2,80,0,0x1B,0x00,0xDF }, /* 1.2 MB AT-diskettes */ + { 720, 9,2,40,1,0x2A,0x02,0xDF }, /* 360kB in 720kB drive */ + { 1440, 9,2,80,0,0x2A,0x02,0xDF }, /* 3.5" 720kB diskette */ + { 720, 9,2,40,1,0x23,0x01,0xDF }, /* 360kB in 1.2MB drive */ + { 1440, 9,2,80,0,0x23,0x01,0xDF }, /* 720kB in 1.2MB drive */ + { 2880,18,2,80,0,0x1B,0x00,0xCF }, /* 1.44MB diskette */ +}; +/* + * Rate is 0 for 500kb/s, 2 for 300kbps, 1 for 250kbps + * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc), + * H is head unload time (1=16ms, 2=32ms, etc) + * + * Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms etc) + * and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA). + */ + +extern void floppy_interrupt(void); +extern char tmp_floppy_area[1024]; + +/* + * These are global variables, as that's the easiest way to give + * information to interrupts. They are the data used for the current + * request. + */ +static int cur_spec1 = -1; +static int cur_rate = -1; +static struct floppy_struct * floppy = floppy_type; +static unsigned char current_drive = 0; +static unsigned char sector = 0; +static unsigned char head = 0; +static unsigned char track = 0; +static unsigned char seek_track = 0; +static unsigned char current_track = 255; +static unsigned char command = 0; +unsigned char selected = 0; +struct task_struct * wait_on_floppy_select = NULL; + +void floppy_deselect(unsigned int nr) +{ + if (nr != (current_DOR & 3)) + printk("floppy_deselect: drive not selected\n\r"); + selected = 0; + wake_up(&wait_on_floppy_select); +} + +/* + * floppy-change is never called from an interrupt, so we can relax a bit + * here, sleep etc. Note that floppy-on tries to set current_DOR to point + * to the desired drive, but it will probably not survive the sleep if + * several floppies are used at the same time: thus the loop. + */ +int floppy_change(unsigned int nr) +{ +repeat: + floppy_on(nr); + while ((current_DOR & 3) != nr && selected) + interruptible_sleep_on(&wait_on_floppy_select); + if ((current_DOR & 3) != nr) + goto repeat; + if (inb(FD_DIR) & 0x80) { + floppy_off(nr); + return 1; + } + floppy_off(nr); + return 0; +} + +#define copy_buffer(from,to) \ +__asm__("cld ; rep ; movsl" \ + ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \ + :"cx","di","si") + +static void setup_DMA(void) +{ + long addr = (long) CURRENT->buffer; + + cli(); + if (addr >= 0x100000) { + addr = (long) tmp_floppy_area; + if (command == FD_WRITE) + copy_buffer(CURRENT->buffer,tmp_floppy_area); + } +/* mask DMA 2 */ + immoutb_p(4|2,10); +/* output command byte. I don't know why, but everyone (minix, */ +/* sanches & canton) output this twice, first to 12 then to 11 */ + __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t" + "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:":: + "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE))); +/* 8 low bits of addr */ + immoutb_p(addr,4); + addr >>= 8; +/* bits 8-15 of addr */ + immoutb_p(addr,4); + addr >>= 8; +/* bits 16-19 of addr */ + immoutb_p(addr,0x81); +/* low 8 bits of count-1 (1024-1=0x3ff) */ + immoutb_p(0xff,5); +/* high 8 bits of count-1 */ + immoutb_p(3,5); +/* activate DMA 2 */ + immoutb_p(0|2,10); + sti(); +} + +static void output_byte(char byte) +{ + int counter; + unsigned char status; + + if (reset) + return; + for(counter = 0 ; counter < 10000 ; counter++) { + status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR); + if (status == STATUS_READY) { + outb(byte,FD_DATA); + return; + } + } + reset = 1; + printk("Unable to send byte to FDC\n\r"); +} + +static int result(void) +{ + int i = 0, counter, status; + + if (reset) + return -1; + for (counter = 0 ; counter < 10000 ; counter++) { + status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY); + if (status == STATUS_READY) + return i; + if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) { + if (i >= MAX_REPLIES) + break; + reply_buffer[i++] = inb_p(FD_DATA); + } + } + reset = 1; + printk("Getstatus times out\n\r"); + return -1; +} + +static void bad_flp_intr(void) +{ + CURRENT->errors++; + if (CURRENT->errors > MAX_ERRORS) { + floppy_deselect(current_drive); + end_request(0); + } + if (CURRENT->errors > MAX_ERRORS/2) + reset = 1; + else + recalibrate = 1; +} + +/* + * Ok, this interrupt is called after a DMA read/write has succeeded, + * so we check the results, and copy any buffers. + */ +static void rw_interrupt(void) +{ + if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73)) { + if (ST1 & 0x02) { + printk("Drive %d is write protected\n\r",current_drive); + floppy_deselect(current_drive); + end_request(0); + } else + bad_flp_intr(); + do_fd_request(); + return; + } + if (command == FD_READ && (unsigned long)(CURRENT->buffer) >= 0x100000) + copy_buffer(tmp_floppy_area,CURRENT->buffer); + floppy_deselect(current_drive); + end_request(1); + do_fd_request(); +} + +inline void setup_rw_floppy(void) +{ + setup_DMA(); + do_floppy = rw_interrupt; + output_byte(command); + output_byte(head<<2 | current_drive); + output_byte(track); + output_byte(head); + output_byte(sector); + output_byte(2); /* sector size = 512 */ + output_byte(floppy->sect); + output_byte(floppy->gap); + output_byte(0xFF); /* sector size (0xff when n!=0 ?) */ + if (reset) + do_fd_request(); +} + +/* + * This is the routine called after every seek (or recalibrate) interrupt + * from the floppy controller. Note that the "unexpected interrupt" routine + * also does a recalibrate, but doesn't come here. + */ +static void seek_interrupt(void) +{ +/* sense drive status */ + output_byte(FD_SENSEI); + if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) { + bad_flp_intr(); + do_fd_request(); + return; + } + current_track = ST1; + setup_rw_floppy(); +} + +/* + * This routine is called when everything should be correctly set up + * for the transfer (ie floppy motor is on and the correct floppy is + * selected). + */ +static void transfer(void) +{ + if (cur_spec1 != floppy->spec1) { + cur_spec1 = floppy->spec1; + output_byte(FD_SPECIFY); + output_byte(cur_spec1); /* hut etc */ + output_byte(6); /* Head load time =6ms, DMA */ + } + if (cur_rate != floppy->rate) + outb_p(cur_rate = floppy->rate,FD_DCR); + if (reset) { + do_fd_request(); + return; + } + if (!seek) { + setup_rw_floppy(); + return; + } + do_floppy = seek_interrupt; + if (seek_track) { + output_byte(FD_SEEK); + output_byte(head<<2 | current_drive); + output_byte(seek_track); + } else { + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); + } + if (reset) + do_fd_request(); +} + +/* + * Special case - used after a unexpected interrupt (or reset) + */ +static void recal_interrupt(void) +{ + output_byte(FD_SENSEI); + if (result()!=2 || (ST0 & 0xE0) == 0x60) + reset = 1; + else + recalibrate = 0; + do_fd_request(); +} + +void unexpected_floppy_interrupt(void) +{ + output_byte(FD_SENSEI); + if (result()!=2 || (ST0 & 0xE0) == 0x60) + reset = 1; + else + recalibrate = 1; +} + +static void recalibrate_floppy(void) +{ + recalibrate = 0; + current_track = 0; + do_floppy = recal_interrupt; + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); + if (reset) + do_fd_request(); +} + +static void reset_interrupt(void) +{ + output_byte(FD_SENSEI); + (void) result(); + output_byte(FD_SPECIFY); + output_byte(cur_spec1); /* hut etc */ + output_byte(6); /* Head load time =6ms, DMA */ + do_fd_request(); +} + +/* + * reset is done by pulling bit 2 of DOR low for a while. + */ +static void reset_floppy(void) +{ + int i; + + reset = 0; + cur_spec1 = -1; + cur_rate = -1; + recalibrate = 1; + printk("Reset-floppy called\n\r"); + cli(); + do_floppy = reset_interrupt; + outb_p(current_DOR & ~0x04,FD_DOR); + for (i=0 ; i<100 ; i++) + __asm__("nop"); + outb(current_DOR,FD_DOR); + sti(); +} + +static void floppy_on_interrupt(void) +{ +/* We cannot do a floppy-select, as that might sleep. We just force it */ + selected = 1; + if (current_drive != (current_DOR & 3)) { + current_DOR &= 0xFC; + current_DOR |= current_drive; + outb(current_DOR,FD_DOR); + add_timer(2,&transfer); + } else + transfer(); +} + +void do_fd_request(void) +{ + unsigned int block; + + seek = 0; + if (reset) { + reset_floppy(); + return; + } + if (recalibrate) { + recalibrate_floppy(); + return; + } + INIT_REQUEST; + floppy = (MINOR(CURRENT->dev)>>2) + floppy_type; + if (current_drive != CURRENT_DEV) + seek = 1; + current_drive = CURRENT_DEV; + block = CURRENT->sector; + if (block+2 > floppy->size) { + end_request(0); + goto repeat; + } + sector = block % floppy->sect; + block /= floppy->sect; + head = block % floppy->head; + track = block / floppy->head; + seek_track = track << floppy->stretch; + if (seek_track != current_track) + seek = 1; + sector++; + if (CURRENT->cmd == READ) + command = FD_READ; + else if (CURRENT->cmd == WRITE) + command = FD_WRITE; + else + panic("do_fd_request: unknown command"); + add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt); +} + +void floppy_init(void) +{ + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + set_trap_gate(0x26,&floppy_interrupt); + outb(inb_p(0x21)&~0x40,0x21); +} diff --git a/kernel/0.1x/linux-0.11/kernel/blk_drv/hd.c b/kernel/0.1x/linux-0.11/kernel/blk_drv/hd.c new file mode 100644 index 00000000..36377a73 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/blk_drv/hd.c @@ -0,0 +1,349 @@ +/* + * linux/kernel/hd.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This is the low-level hd interrupt support. It traverses the + * request-list, using interrupts to jump between functions. As + * all the functions are called within interrupts, we may not + * sleep. Special care is recommended. + * + * modified by Drew Eckhardt to check nr of hd's from the CMOS. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 3 +#include "blk.h" + +#define CMOS_READ(addr) ({ \ +outb_p(0x80|addr,0x70); \ +inb_p(0x71); \ +}) + +/* Max read/write errors/sector */ +#define MAX_ERRORS 7 +#define MAX_HD 2 + +static void recal_intr(void); + +static int recalibrate = 1; +static int reset = 1; + +/* + * This struct defines the HD's and their types. + */ +struct hd_i_struct { + int head,sect,cyl,wpcom,lzone,ctl; + }; +#ifdef HD_TYPE +struct hd_i_struct hd_info[] = { HD_TYPE }; +#define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct))) +#else +struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} }; +static int NR_HD = 0; +#endif + +static struct hd_struct { + long start_sect; + long nr_sects; +} hd[5*MAX_HD]={{0,0},}; + +#define port_read(port,buf,nr) \ +__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"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); +extern void rd_load(void); + +/* This may be used only once, enforced by 'static int callable' */ +int sys_setup(void * BIOS) +{ + static int callable = 1; + int i,drive; + unsigned char cmos_disks; + struct partition *p; + struct buffer_head * bh; + + if (!callable) + return -1; + callable = 0; +#ifndef HD_TYPE + for (drive=0 ; drive<2 ; drive++) { + hd_info[drive].cyl = *(unsigned short *) BIOS; + hd_info[drive].head = *(unsigned char *) (2+BIOS); + hd_info[drive].wpcom = *(unsigned short *) (5+BIOS); + hd_info[drive].ctl = *(unsigned char *) (8+BIOS); + hd_info[drive].lzone = *(unsigned short *) (12+BIOS); + hd_info[drive].sect = *(unsigned char *) (14+BIOS); + BIOS += 16; + } + if (hd_info[1].cyl) + NR_HD=2; + else + NR_HD=1; +#endif + for (i=0 ; i are the primary drives in the system, and + the ones reflected as drive 1 or 2. + + The first drive is stored in the high nibble of CMOS + byte 0x12, the second in the low nibble. This will be + either a 4 bit drive type or 0xf indicating use byte 0x19 + for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. + + Needless to say, a non-zero value means we have + an AT controller hard disk for that drive. + + + */ + + if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) + if (cmos_disks & 0x0f) + NR_HD = 2; + else + NR_HD = 1; + else + NR_HD = 0; + for (i = NR_HD ; i < 2 ; i++) { + hd[i*5].start_sect = 0; + hd[i*5].nr_sects = 0; + } + for (drive=0 ; driveb_data[510] != 0x55 || (unsigned char) + bh->b_data[511] != 0xAA) { + printk("Bad partition table on drive %d\n\r",drive); + panic(""); + } + p = 0x1BE + (void *)bh->b_data; + for (i=1;i<5;i++,p++) { + hd[i+5*drive].start_sect = p->start_sect; + hd[i+5*drive].nr_sects = p->nr_sects; + } + brelse(bh); + } + if (NR_HD) + printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":""); + rd_load(); + mount_root(); + return (0); +} + +static int controller_ready(void) +{ + int retries=10000; + + while (--retries && (inb_p(HD_STATUS)&0xc0)!=0x40); + return (retries); +} + +static int win_result(void) +{ + int i=inb_p(HD_STATUS); + + if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)) + == (READY_STAT | SEEK_STAT)) + return(0); /* ok */ + if (i&1) i=inb(HD_ERROR); + return (1); +} + +static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect, + unsigned int head,unsigned int cyl,unsigned int cmd, + void (*intr_addr)(void)) +{ + register int port asm("dx"); + + if (drive>1 || head>15) + panic("Trying to write bad sector"); + if (!controller_ready()) + panic("HD controller not ready"); + do_hd = intr_addr; + outb_p(hd_info[drive].ctl,HD_CMD); + port=HD_DATA; + outb_p(hd_info[drive].wpcom>>2,++port); + outb_p(nsect,++port); + outb_p(sect,++port); + outb_p(cyl,++port); + outb_p(cyl>>8,++port); + outb_p(0xA0|(drive<<4)|head,++port); + outb(cmd,++port); +} + +static int drive_busy(void) +{ + unsigned int i; + + for (i = 0; i < 10000; i++) + if (READY_STAT == (inb_p(HD_STATUS) & (BUSY_STAT|READY_STAT))) + break; + i = inb(HD_STATUS); + i &= BUSY_STAT | READY_STAT | SEEK_STAT; + if (i == READY_STAT | SEEK_STAT) + return(0); + printk("HD controller times out\n\r"); + return(1); +} + +static void reset_controller(void) +{ + int i; + + outb(4,HD_CMD); + for(i = 0; i < 100; i++) nop(); + outb(hd_info[0].ctl & 0x0f ,HD_CMD); + if (drive_busy()) + printk("HD-controller still busy\n\r"); + if ((i = inb(HD_ERROR)) != 1) + printk("HD-controller reset failed: %02x\n\r",i); +} + +static void reset_hd(int nr) +{ + reset_controller(); + hd_out(nr,hd_info[nr].sect,hd_info[nr].sect,hd_info[nr].head-1, + hd_info[nr].cyl,WIN_SPECIFY,&recal_intr); +} + +void unexpected_hd_interrupt(void) +{ + printk("Unexpected HD interrupt\n\r"); +} + +static void bad_rw_intr(void) +{ + if (++CURRENT->errors >= MAX_ERRORS) + end_request(0); + if (CURRENT->errors > MAX_ERRORS/2) + reset = 1; +} + +static void read_intr(void) +{ + if (win_result()) { + bad_rw_intr(); + do_hd_request(); + return; + } + port_read(HD_DATA,CURRENT->buffer,256); + CURRENT->errors = 0; + CURRENT->buffer += 512; + CURRENT->sector++; + if (--CURRENT->nr_sectors) { + do_hd = &read_intr; + return; + } + end_request(1); + do_hd_request(); +} + +static void write_intr(void) +{ + if (win_result()) { + bad_rw_intr(); + do_hd_request(); + return; + } + if (--CURRENT->nr_sectors) { + CURRENT->sector++; + CURRENT->buffer += 512; + do_hd = &write_intr; + port_write(HD_DATA,CURRENT->buffer,256); + return; + } + end_request(1); + do_hd_request(); +} + +static void recal_intr(void) +{ + if (win_result()) + bad_rw_intr(); + do_hd_request(); +} + +void do_hd_request(void) +{ + int i,r; + unsigned int block,dev; + unsigned int sec,head,cyl; + unsigned int nsect; + + INIT_REQUEST; + dev = MINOR(CURRENT->dev); + block = CURRENT->sector; + if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) { + end_request(0); + goto repeat; + } + block += hd[dev].start_sect; + dev /= 5; + __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0), + "r" (hd_info[dev].sect)); + __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0), + "r" (hd_info[dev].head)); + sec++; + nsect = CURRENT->nr_sectors; + if (reset) { + reset = 0; + recalibrate = 1; + reset_hd(CURRENT_DEV); + return; + } + if (recalibrate) { + recalibrate = 0; + hd_out(dev,hd_info[CURRENT_DEV].sect,0,0,0, + WIN_RESTORE,&recal_intr); + return; + } + if (CURRENT->cmd == WRITE) { + hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr); + for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++) + /* nothing */ ; + if (!r) { + bad_rw_intr(); + goto repeat; + } + port_write(HD_DATA,CURRENT->buffer,256); + } else if (CURRENT->cmd == READ) { + hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr); + } else + panic("unknown hd-command"); +} + +void hd_init(void) +{ + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + set_intr_gate(0x2E,&hd_interrupt); + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xbf,0xA1); +} diff --git a/kernel/0.1x/linux-0.11/kernel/blk_drv/ll_rw_blk.c b/kernel/0.1x/linux-0.11/kernel/blk_drv/ll_rw_blk.c new file mode 100644 index 00000000..39a21a76 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/blk_drv/ll_rw_blk.c @@ -0,0 +1,165 @@ +/* + * linux/kernel/blk_dev/ll_rw.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This handles all read/write requests to block devices + */ +#include +#include +#include +#include + +#include "blk.h" + +/* + * The request-struct contains all necessary data + * to load a nr of sectors into memory + */ +struct request request[NR_REQUEST]; + +/* + * used to wait on when there are no free requests + */ +struct task_struct * wait_for_request = NULL; + +/* blk_dev_struct is: + * do_request-address + * next-request + */ +struct blk_dev_struct blk_dev[NR_BLK_DEV] = { + { NULL, NULL }, /* no_dev */ + { NULL, NULL }, /* dev mem */ + { NULL, NULL }, /* dev fd */ + { NULL, NULL }, /* dev hd */ + { NULL, NULL }, /* dev ttyx */ + { NULL, NULL }, /* dev tty */ + { NULL, NULL } /* dev lp */ +}; + +static inline void lock_buffer(struct buffer_head * bh) +{ + cli(); + while (bh->b_lock) + sleep_on(&bh->b_wait); + bh->b_lock=1; + sti(); +} + +static inline void unlock_buffer(struct buffer_head * bh) +{ + if (!bh->b_lock) + printk("ll_rw_block.c: buffer not locked\n\r"); + bh->b_lock = 0; + wake_up(&bh->b_wait); +} + +/* + * add-request adds a request to the linked list. + * It disables interrupts so that it can muck with the + * request-lists in peace. + */ +static void add_request(struct blk_dev_struct * dev, struct request * req) +{ + struct request * tmp; + + req->next = NULL; + cli(); + if (req->bh) + req->bh->b_dirt = 0; + if (!(tmp = dev->current_request)) { + dev->current_request = req; + sti(); + (dev->request_fn)(); + return; + } + for ( ; tmp->next ; tmp=tmp->next) + if ((IN_ORDER(tmp,req) || + !IN_ORDER(tmp,tmp->next)) && + IN_ORDER(req,tmp->next)) + break; + req->next=tmp->next; + tmp->next=req; + sti(); +} + +static void make_request(int major,int rw, struct buffer_head * bh) +{ + struct request * req; + int rw_ahead; + +/* WRITEA/READA is special case - it is not really needed, so if the */ +/* buffer is locked, we just forget about it, else it's a normal read */ + if (rw_ahead = (rw == READA || rw == WRITEA)) { + if (bh->b_lock) + return; + if (rw == READA) + rw = READ; + else + rw = WRITE; + } + if (rw!=READ && rw!=WRITE) + panic("Bad block dev command, must be R/W/RA/WA"); + lock_buffer(bh); + if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) { + unlock_buffer(bh); + return; + } +repeat: +/* we don't allow the write-requests to fill up the queue completely: + * we want some room for reads: they take precedence. The last third + * of the requests are only for reads. + */ + if (rw == READ) + req = request+NR_REQUEST; + else + req = request+((NR_REQUEST*2)/3); +/* find an empty request */ + while (--req >= request) + if (req->dev<0) + break; +/* if none found, sleep on new requests: check for rw_ahead */ + if (req < request) { + if (rw_ahead) { + unlock_buffer(bh); + return; + } + sleep_on(&wait_for_request); + goto repeat; + } +/* fill up the request-info, and add it to the queue */ + req->dev = bh->b_dev; + req->cmd = rw; + req->errors=0; + req->sector = bh->b_blocknr<<1; + req->nr_sectors = 2; + req->buffer = bh->b_data; + req->waiting = NULL; + req->bh = bh; + req->next = NULL; + add_request(major+blk_dev,req); +} + +void ll_rw_block(int rw, struct buffer_head * bh) +{ + unsigned int major; + + if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || + !(blk_dev[major].request_fn)) { + printk("Trying to read nonexistent block-device\n\r"); + return; + } + make_request(major,rw,bh); +} + +void blk_dev_init(void) +{ + int i; + + for (i=0 ; i + +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 1 +#include "blk.h" + +char *rd_start; +int rd_length = 0; + +void do_rd_request(void) +{ + int len; + char *addr; + + INIT_REQUEST; + addr = rd_start + (CURRENT->sector << 9); + len = CURRENT->nr_sectors << 9; + if ((MINOR(CURRENT->dev) != 1) || (addr+len > rd_start+rd_length)) { + end_request(0); + goto repeat; + } + if (CURRENT-> cmd == WRITE) { + (void ) memcpy(addr, + CURRENT->buffer, + len); + } else if (CURRENT->cmd == READ) { + (void) memcpy(CURRENT->buffer, + addr, + len); + } else + panic("unknown ramdisk-command"); + end_request(1); + goto repeat; +} + +/* + * Returns amount of memory which needs to be reserved. + */ +long rd_init(long mem_start, int length) +{ + int i; + char *cp; + + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + rd_start = (char *) mem_start; + rd_length = length; + cp = rd_start; + for (i=0; i < length; i++) + *cp++ = '\0'; + return(length); +} + +/* + * If the root device is the ram disk, try to load it. + * In order to do this, the root device is originally set to the + * floppy, and we later change it to be ram disk. + */ +void rd_load(void) +{ + struct buffer_head *bh; + struct super_block s; + int block = 256; /* Start at block 256 */ + int i = 1; + int nblocks; + char *cp; /* Move pointer */ + + if (!rd_length) + return; + printk("Ram disk: %d bytes, starting at 0x%x\n", rd_length, + (int) rd_start); + if (MAJOR(ROOT_DEV) != 2) + return; + bh = breada(ROOT_DEV,block+1,block,block+2,-1); + if (!bh) { + printk("Disk error while looking for ramdisk!\n"); + return; + } + *((struct d_super_block *) &s) = *((struct d_super_block *) bh->b_data); + brelse(bh); + if (s.s_magic != SUPER_MAGIC) + /* No ram disk image present, assume normal floppy boot */ + return; + nblocks = s.s_nzones << s.s_log_zone_size; + if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) { + printk("Ram disk image too big! (%d blocks, %d avail)\n", + nblocks, rd_length >> BLOCK_SIZE_BITS); + return; + } + printk("Loading %d bytes into ram disk... 0000k", + nblocks << BLOCK_SIZE_BITS); + cp = rd_start; + while (nblocks) { + if (nblocks > 2) + bh = breada(ROOT_DEV, block, block+1, block+2, -1); + else + bh = bread(ROOT_DEV, block); + if (!bh) { + printk("I/O error on block %d, aborting load\n", + block); + return; + } + (void) memcpy(cp, bh->b_data, BLOCK_SIZE); + brelse(bh); + printk("\010\010\010\010\010%4dk",i); + cp += BLOCK_SIZE; + block++; + nblocks--; + i++; + } + printk("\010\010\010\010\010done \n"); + ROOT_DEV=0x0101; +} diff --git a/kernel/0.1x/linux-0.11/kernel/chr_drv/Makefile b/kernel/0.1x/linux-0.11/kernel/chr_drv/Makefile new file mode 100644 index 00000000..5cb1b06c --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/chr_drv/Makefile @@ -0,0 +1,68 @@ +# +# Makefile for the FREAX-kernel character device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =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 = tty_io.o console.o keyboard.o serial.o rs_io.o \ + tty_ioctl.o + +chr_drv.a: $(OBJS) + $(AR) rcs chr_drv.a $(OBJS) + sync + +keyboard.s: keyboard.S ../../include/linux/config.h + $(CPP) -traditional keyboard.S -o keyboard.s + +clean: + rm -f core *.o *.a tmp_make keyboard.s + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +console.s console.o : console.c ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h ../../include/signal.h \ + ../../include/linux/tty.h ../../include/termios.h ../../include/asm/io.h \ + ../../include/asm/system.h +serial.s serial.o : serial.c ../../include/linux/tty.h ../../include/termios.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/signal.h ../../include/asm/system.h ../../include/asm/io.h +tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \ + ../../include/signal.h ../../include/sys/types.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/linux/mm.h ../../include/linux/tty.h \ + ../../include/termios.h ../../include/asm/segment.h \ + ../../include/asm/system.h +tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/signal.h ../../include/linux/kernel.h \ + ../../include/linux/tty.h ../../include/asm/io.h \ + ../../include/asm/segment.h ../../include/asm/system.h diff --git a/kernel/0.1x/linux-0.11/kernel/chr_drv/console.c b/kernel/0.1x/linux-0.11/kernel/chr_drv/console.c new file mode 100644 index 00000000..cb304bd7 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/chr_drv/console.c @@ -0,0 +1,710 @@ +/* + * linux/kernel/console.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * console.c + * + * This module implements the console io functions + * 'void con_init(void)' + * 'void con_write(struct tty_queue * queue)' + * Hopefully this will be a rather complete VT102 implementation. + * + * Beeping thanks to John T Kohl. + */ + +/* + * NOTE!!! We sometimes disable and enable interrupts for a short while + * (to put a word in video IO), but this will work even for keyboard + * interrupts. We know interrupts aren't enabled when getting a keyboard + * interrupt, as we use trap-gates. Hopefully all is well. + */ + +/* + * Code to check for different video-cards mostly by Galen Hunt, + * + */ + +#include +#include +#include +#include + +/* + * These are set up by the setup-routine at boot-time: + */ + +#define ORIG_X (*(unsigned char *)0x90000) +#define ORIG_Y (*(unsigned char *)0x90001) +#define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004) +#define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff) +#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8) +#define ORIG_VIDEO_LINES (25) +#define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008) +#define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a) +#define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c) + +#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ +#define VIDEO_TYPE_CGA 0x11 /* CGA Display */ +#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */ +#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */ + +#define NPAR 16 + +extern void keyboard_interrupt(void); + +static unsigned char video_type; /* Type of display being used */ +static unsigned long video_num_columns; /* Number of text columns */ +static unsigned long video_size_row; /* Bytes per row */ +static unsigned long video_num_lines; /* Number of test lines */ +static unsigned char video_page; /* Initial video page */ +static unsigned long video_mem_start; /* Start of video RAM */ +static unsigned long video_mem_end; /* End of video RAM (sort of) */ +static unsigned short video_port_reg; /* Video register select port */ +static unsigned short video_port_val; /* Video register value port */ +static unsigned short video_erase_char; /* Char+Attrib to erase with */ + +static unsigned long origin; /* Used for EGA/VGA fast scroll */ +static unsigned long scr_end; /* Used for EGA/VGA fast scroll */ +static unsigned long pos; +static unsigned long x,y; +static unsigned long top,bottom; +static unsigned long state=0; +static unsigned long npar,par[NPAR]; +static unsigned long ques=0; +static unsigned char attr=0x07; + +static void sysbeep(void); + +/* + * this is what the terminal answers to a ESC-Z or csi0c + * query (= vt100 response). + */ +#define RESPONSE "\033[?1;2c" + +/* NOTE! gotoxy thinks x==video_num_columns is ok */ +static inline void gotoxy(unsigned int new_x,unsigned int new_y) +{ + if (new_x > video_num_columns || new_y >= video_num_lines) + return; + x=new_x; + y=new_y; + pos=origin + y*video_size_row + (x<<1); +} + +static inline void set_origin(void) +{ + cli(); + outb_p(12, video_port_reg); + outb_p(0xff&((origin-video_mem_start)>>9), video_port_val); + outb_p(13, video_port_reg); + outb_p(0xff&((origin-video_mem_start)>>1), video_port_val); + sti(); +} + +static void scrup(void) +{ + if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) + { + if (!top && bottom == video_num_lines) { + origin += video_size_row; + pos += video_size_row; + scr_end += video_size_row; + if (scr_end > video_mem_end) { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl _video_num_columns,%1\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((video_num_lines-1)*video_num_columns>>1), + "D" (video_mem_start), + "S" (origin) + :"cx","di","si"); + scr_end -= origin-video_mem_start; + pos -= origin-video_mem_start; + origin = video_mem_start; + } else { + __asm__("cld\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" (video_num_columns), + "D" (scr_end-video_size_row) + :"cx","di"); + } + set_origin(); + } else { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl _video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*top), + "S" (origin+video_size_row*(top+1)) + :"cx","di","si"); + } + } + else /* Not EGA/VGA */ + { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl _video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*top), + "S" (origin+video_size_row*(top+1)) + :"cx","di","si"); + } +} + +static void scrdown(void) +{ + if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) + { + __asm__("std\n\t" + "rep\n\t" + "movsl\n\t" + "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ + "movl _video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*bottom-4), + "S" (origin+video_size_row*(bottom-1)-4) + :"ax","cx","di","si"); + } + else /* Not EGA/VGA */ + { + __asm__("std\n\t" + "rep\n\t" + "movsl\n\t" + "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ + "movl _video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*bottom-4), + "S" (origin+video_size_row*(bottom-1)-4) + :"ax","cx","di","si"); + } +} + +static void lf(void) +{ + if (y+1top) { + y--; + pos -= video_size_row; + return; + } + scrdown(); +} + +static void cr(void) +{ + pos -= x<<1; + x=0; +} + +static void del(void) +{ + if (x) { + pos -= 2; + x--; + *(unsigned short *)pos = video_erase_char; + } +} + +static void csi_J(int par) +{ + long count __asm__("cx"); + long start __asm__("di"); + + switch (par) { + case 0: /* erase from cursor to end of display */ + count = (scr_end-pos)>>1; + start = pos; + break; + case 1: /* erase from start to cursor */ + count = (pos-origin)>>1; + start = origin; + break; + case 2: /* erase whole display */ + count = video_num_columns * video_num_lines; + start = origin; + break; + default: + return; + } + __asm__("cld\n\t" + "rep\n\t" + "stosw\n\t" + ::"c" (count), + "D" (start),"a" (video_erase_char) + :"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>=video_num_columns) + return; + count = video_num_columns-x; + start = pos; + break; + case 1: /* erase from start of line to cursor */ + start = pos - (x<<1); + count = (x>9), video_port_val); + outb_p(15, video_port_reg); + outb_p(0xff&((pos-video_mem_start)>>1), video_port_val); + sti(); +} + +static void respond(struct tty_struct * tty) +{ + char * p = RESPONSE; + + cli(); + while (*p) { + PUTCH(*p,tty->read_q); + p++; + } + sti(); + copy_to_cooked(tty); +} + +static void insert_char(void) +{ + int i=x; + unsigned short tmp, old = video_erase_char; + unsigned short * p = (unsigned short *) pos; + + while (i++=video_num_columns) + return; + i = x; + while (++i < video_num_columns) { + *p = *(p+1); + p++; + } + *p = video_erase_char; +} + +static void delete_line(void) +{ + int oldtop,oldbottom; + + oldtop=top; + oldbottom=bottom; + top=y; + bottom = video_num_lines; + scrup(); + top=oldtop; + bottom=oldbottom; +} + +static void csi_at(unsigned int nr) +{ + if (nr > video_num_columns) + nr = video_num_columns; + else if (!nr) + nr = 1; + while (nr--) + insert_char(); +} + +static void csi_L(unsigned int nr) +{ + if (nr > video_num_lines) + nr = video_num_lines; + else if (!nr) + nr = 1; + while (nr--) + insert_line(); +} + +static void csi_P(unsigned int nr) +{ + if (nr > video_num_columns) + nr = video_num_columns; + else if (!nr) + nr = 1; + while (nr--) + delete_char(); +} + +static void csi_M(unsigned int nr) +{ + if (nr > video_num_lines) + nr = video_num_lines; + else if (!nr) + nr=1; + while (nr--) + delete_line(); +} + +static int saved_x=0; +static int saved_y=0; + +static void save_cur(void) +{ + saved_x=x; + saved_y=y; +} + +static void restore_cur(void) +{ + gotoxy(saved_x, saved_y); +} + +void con_write(struct tty_struct * tty) +{ + int nr; + char c; + + nr = CHARS(tty->write_q); + while (nr--) { + GETCH(tty->write_q,c); + switch(state) { + case 0: + if (c>31 && c<127) { + if (x>=video_num_columns) { + x -= video_num_columns; + pos -= video_size_row; + lf(); + } + __asm__("movb _attr,%%ah\n\t" + "movw %%ax,%1\n\t" + ::"a" (c),"m" (*(short *)pos) + :"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>video_num_columns) { + x -= video_num_columns; + pos -= video_size_row; + lf(); + } + c=9; + } else if (c==7) + sysbeep(); + break; + case 1: + state=0; + if (c=='[') + state=2; + else if (c=='E') + gotoxy(0,y+1); + else if (c=='M') + ri(); + else if (c=='D') + lf(); + else if (c=='Z') + respond(tty); + else if (x=='7') + save_cur(); + else if (x=='8') + restore_cur(); + break; + case 2: + for(npar=0;npar='0' && c<='9') { + par[npar]=10*par[npar]+c-'0'; + break; + } else state=4; + case 4: + state=0; + switch(c) { + case 'G': case '`': + if (par[0]) par[0]--; + gotoxy(par[0],y); + break; + case 'A': + if (!par[0]) par[0]++; + gotoxy(x,y-par[0]); + break; + case 'B': case 'e': + if (!par[0]) par[0]++; + gotoxy(x,y+par[0]); + break; + case 'C': case 'a': + if (!par[0]) par[0]++; + gotoxy(x+par[0],y); + break; + case 'D': + if (!par[0]) par[0]++; + gotoxy(x-par[0],y); + break; + case 'E': + if (!par[0]) par[0]++; + gotoxy(0,y+par[0]); + break; + case 'F': + if (!par[0]) par[0]++; + gotoxy(0,y-par[0]); + break; + case 'd': + if (par[0]) par[0]--; + gotoxy(x,par[0]); + break; + case 'H': case 'f': + if (par[0]) par[0]--; + if (par[1]) par[1]--; + gotoxy(par[1],par[0]); + break; + case 'J': + csi_J(par[0]); + break; + case 'K': + csi_K(par[0]); + break; + case 'L': + csi_L(par[0]); + break; + case 'M': + csi_M(par[0]); + break; + case 'P': + csi_P(par[0]); + break; + case '@': + csi_at(par[0]); + break; + case 'm': + csi_m(); + break; + case 'r': + if (par[0]) par[0]--; + if (!par[1]) par[1] = video_num_lines; + if (par[0] < par[1] && + par[1] <= video_num_lines) { + top=par[0]; + bottom=par[1]; + } + break; + case 's': + save_cur(); + break; + case 'u': + restore_cur(); + break; + } + } + } + set_cursor(); +} + +/* + * void con_init(void); + * + * This routine initalizes console interrupts, and does nothing + * else. If you want the screen to clear, call tty_write with + * the appropriate escape-sequece. + * + * Reads the information preserved by setup.s to determine the current display + * type and sets everything accordingly. + */ +void con_init(void) +{ + register unsigned char a; + char *display_desc = "????"; + char *display_ptr; + + video_num_columns = ORIG_VIDEO_COLS; + video_size_row = video_num_columns * 2; + video_num_lines = ORIG_VIDEO_LINES; + video_page = ORIG_VIDEO_PAGE; + video_erase_char = 0x0720; + + if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */ + { + video_mem_start = 0xb0000; + video_port_reg = 0x3b4; + video_port_val = 0x3b5; + if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) + { + video_type = VIDEO_TYPE_EGAM; + video_mem_end = 0xb8000; + display_desc = "EGAm"; + } + else + { + video_type = VIDEO_TYPE_MDA; + video_mem_end = 0xb2000; + display_desc = "*MDA"; + } + } + else /* If not, it is color. */ + { + video_mem_start = 0xb8000; + video_port_reg = 0x3d4; + video_port_val = 0x3d5; + if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) + { + video_type = VIDEO_TYPE_EGAC; + video_mem_end = 0xbc000; + display_desc = "EGAc"; + } + else + { + video_type = VIDEO_TYPE_CGA; + video_mem_end = 0xba000; + display_desc = "*CGA"; + } + } + + /* Let the user known what kind of display driver we are using */ + + display_ptr = ((char *)video_mem_start) + video_size_row - 8; + while (*display_desc) + { + *display_ptr++ = *display_desc++; + display_ptr++; + } + + /* Initialize the variables used for scrolling (mostly EGA/VGA) */ + + origin = video_mem_start; + scr_end = video_mem_start + video_num_lines * video_size_row; + top = 0; + bottom = video_num_lines; + + gotoxy(ORIG_X,ORIG_Y); + set_trap_gate(0x21,&keyboard_interrupt); + outb_p(inb_p(0x21)&0xfd,0x21); + a=inb_p(0x61); + outb_p(a|0x80,0x61); + outb(a,0x61); +} +/* from bsd-net-2: */ + +void sysbeepstop(void) +{ + /* disable counter 2 */ + outb(inb_p(0x61)&0xFC, 0x61); +} + +int beepcount = 0; + +static void sysbeep(void) +{ + /* enable counter 2 */ + outb_p(inb_p(0x61)|3, 0x61); + /* set command for counter 2, 2 byte write */ + outb_p(0xB6, 0x43); + /* send 0x637 for 750 HZ */ + outb_p(0x37, 0x42); + outb(0x06, 0x42); + /* 1/8 second */ + beepcount = HZ/8; +} diff --git a/kernel/0.1x/linux-0.11/kernel/chr_drv/keyboard.S b/kernel/0.1x/linux-0.11/kernel/chr_drv/keyboard.S new file mode 100644 index 00000000..c1e23783 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/chr_drv/keyboard.S @@ -0,0 +1,588 @@ +/* + * linux/kernel/keyboard.S + * + * (C) 1991 Linus Torvalds + */ + +/* + * Thanks to Alfred Leung for US keyboard patches + * Wolfgang Thiel for German keyboard patches + * Marc Corsini for the French keyboard + */ + +#include + +.text +.globl _keyboard_interrupt + +/* + * these are for the keyboard read functions + */ +size = 1024 /* must be a power of two ! And MUST be the same + as in tty_io.c !!!! */ +head = 4 +tail = 8 +proc_list = 12 +buf = 16 + +mode: .byte 0 /* caps, alt, ctrl and shift mode */ +leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */ +e0: .byte 0 + +/* + * con_int is the real interrupt routine that reads the + * keyboard scan-code and converts it into the appropriate + * ascii character(s). + */ +_keyboard_interrupt: + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + push %ds + push %es + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + 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 + +#if defined(KBD_FR) +num_table: + .ascii "789 456 1230." +#else +num_table: + .ascii "789 456 1230," +#endif +cur_table: + .ascii "HA5 DGC YB623" + +/* + * this routine handles function keys + */ +func: + pushl %eax + pushl %ecx + pushl %edx + call _show_stat + popl %edx + popl %ecx + popl %eax + subb $0x3B,%al + jb end_func + cmpb $9,%al + jbe ok_func + subb $18,%al + cmpb $10,%al + jb end_func + cmpb $11,%al + ja end_func +ok_func: + cmpl $4,%ecx /* check that there is enough room */ + jl end_func + movl func_table(,%eax,4),%eax + xorl %ebx,%ebx + jmp put_queue +end_func: + ret + +/* + * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc. + */ +func_table: + .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b + .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b + .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b + +#if defined(KBD_FINNISH) +key_map: + .byte 0,27 + .ascii "1234567890+'" + .byte 127,9 + .ascii "qwertyuiop}" + .byte 0,13,0 + .ascii "asdfghjkl|{" + .byte 0,0 + .ascii "'zxcvbnm,.-" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + +shift_map: + .byte 0,27 + .ascii "!\"#$%&/()=?`" + .byte 127,9 + .ascii "QWERTYUIOP]^" + .byte 13,0 + .ascii "ASDFGHJKL\\[" + .byte 0,0 + .ascii "*ZXCVBNM;:_" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#elif defined(KBD_US) + +key_map: + .byte 0,27 + .ascii "1234567890-=" + .byte 127,9 + .ascii "qwertyuiop[]" + .byte 13,0 + .ascii "asdfghjkl;'" + .byte '`,0 + .ascii "\\zxcvbnm,./" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + + +shift_map: + .byte 0,27 + .ascii "!@#$%^&*()_+" + .byte 127,9 + .ascii "QWERTYUIOP{}" + .byte 13,0 + .ascii "ASDFGHJKL:\"" + .byte '~,0 + .ascii "|ZXCVBNM<>?" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#elif defined(KBD_GR) + +key_map: + .byte 0,27 + .ascii "1234567890\\'" + .byte 127,9 + .ascii "qwertzuiop@+" + .byte 13,0 + .ascii "asdfghjkl[]^" + .byte 0,'# + .ascii "yxcvbnm,.-" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + + +shift_map: + .byte 0,27 + .ascii "!\"#$%&/()=?`" + .byte 127,9 + .ascii "QWERTZUIOP\\*" + .byte 13,0 + .ascii "ASDFGHJKL{}~" + .byte 0,'' + .ascii "YXCVBNM;:_" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte '@,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + + +#elif defined(KBD_FR) + +key_map: + .byte 0,27 + .ascii "&{\"'(-}_/@)=" + .byte 127,9 + .ascii "azertyuiop^$" + .byte 13,0 + .ascii "qsdfghjklm|" + .byte '`,0,42 /* coin sup gauche, don't know, [*|mu] */ + .ascii "wxcvbn,;:!" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + +shift_map: + .byte 0,27 + .ascii "1234567890]+" + .byte 127,9 + .ascii "AZERTYUIOP<>" + .byte 13,0 + .ascii "QSDFGHJKLM%" + .byte '~,0,'# + .ascii "WXCVBN?./\\" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0~#{[|`\\^@]}" + .byte 0,0 + .byte '@,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#else +#error "KBD-type not defined" +#endif +/* + * do_self handles "normal" keys, ie keys that don't change meaning + * and which have just one character returns. + */ +do_self: + lea alt_map,%ebx + testb $0x20,mode /* alt-gr */ + jne 1f + lea shift_map,%ebx + testb $0x03,mode + jne 1f + lea key_map,%ebx +1: movb (%ebx,%eax),%al + orb %al,%al + je none + testb $0x4c,mode /* ctrl or caps */ + je 2f + cmpb $'a,%al + jb 2f + cmpb $'},%al + ja 2f + subb $32,%al +2: testb $0x0c,mode /* ctrl */ + je 3f + cmpb $64,%al + jb 3f + cmpb $64+32,%al + jae 3f + subb $64,%al +3: testb $0x10,mode /* left alt */ + je 4f + orb $0x80,%al +4: andl $0xff,%eax + xorl %ebx,%ebx + call put_queue +none: ret + +/* + * minus has a routine of it's own, as a 'E0h' before + * the scan code for minus means that the numeric keypad + * slash was pushed. + */ +minus: cmpb $1,e0 + jne do_self + movl $'/,%eax + xorl %ebx,%ebx + jmp put_queue + +/* + * This table decides which routine to call when a scan-code has been + * gotten. Most routines just call do_self, or none, depending if + * they are make or break. + */ +key_table: + .long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */ + .long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */ + .long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */ + .long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */ + .long do_self,do_self,do_self,do_self /* 10-13 q w e r */ + .long do_self,do_self,do_self,do_self /* 14-17 t y u i */ + .long do_self,do_self,do_self,do_self /* 18-1B o p } ^ */ + .long do_self,ctrl,do_self,do_self /* 1C-1F enter ctrl a s */ + .long do_self,do_self,do_self,do_self /* 20-23 d f g h */ + .long do_self,do_self,do_self,do_self /* 24-27 j k l | */ + .long do_self,do_self,lshift,do_self /* 28-2B { para lshift , */ + .long do_self,do_self,do_self,do_self /* 2C-2F z x c v */ + .long do_self,do_self,do_self,do_self /* 30-33 b n m , */ + .long do_self,minus,rshift,do_self /* 34-37 . - rshift * */ + .long alt,do_self,caps,func /* 38-3B alt sp caps f1 */ + .long func,func,func,func /* 3C-3F f2 f3 f4 f5 */ + .long func,func,func,func /* 40-43 f6 f7 f8 f9 */ + .long func,num,scroll,cursor /* 44-47 f10 num scr home */ + .long cursor,cursor,do_self,cursor /* 48-4B up pgup - left */ + .long cursor,cursor,do_self,cursor /* 4C-4F n5 right + end */ + .long cursor,cursor,cursor,cursor /* 50-53 dn pgdn ins del */ + .long none,none,do_self,func /* 54-57 sysreq ? < f11 */ + .long func,none,none,none /* 58-5B f12 ? ? ? */ + .long none,none,none,none /* 5C-5F ? ? ? ? */ + .long none,none,none,none /* 60-63 ? ? ? ? */ + .long none,none,none,none /* 64-67 ? ? ? ? */ + .long none,none,none,none /* 68-6B ? ? ? ? */ + .long none,none,none,none /* 6C-6F ? ? ? ? */ + .long none,none,none,none /* 70-73 ? ? ? ? */ + .long none,none,none,none /* 74-77 ? ? ? ? */ + .long none,none,none,none /* 78-7B ? ? ? ? */ + .long none,none,none,none /* 7C-7F ? ? ? ? */ + .long none,none,none,none /* 80-83 ? br br br */ + .long none,none,none,none /* 84-87 br br br br */ + .long none,none,none,none /* 88-8B br br br br */ + .long none,none,none,none /* 8C-8F br br br br */ + .long none,none,none,none /* 90-93 br br br br */ + .long none,none,none,none /* 94-97 br br br br */ + .long none,none,none,none /* 98-9B br br br br */ + .long none,unctrl,none,none /* 9C-9F br unctrl br br */ + .long none,none,none,none /* A0-A3 br br br br */ + .long none,none,none,none /* A4-A7 br br br br */ + .long none,none,unlshift,none /* A8-AB br br unlshift br */ + .long none,none,none,none /* AC-AF br br br br */ + .long none,none,none,none /* B0-B3 br br br br */ + .long none,none,unrshift,none /* B4-B7 br br unrshift br */ + .long unalt,none,uncaps,none /* B8-BB unalt br uncaps br */ + .long none,none,none,none /* BC-BF br br br br */ + .long none,none,none,none /* C0-C3 br br br br */ + .long none,none,none,none /* C4-C7 br br br br */ + .long none,none,none,none /* C8-CB br br br br */ + .long none,none,none,none /* CC-CF br br br br */ + .long none,none,none,none /* D0-D3 br br br br */ + .long none,none,none,none /* D4-D7 br br br br */ + .long none,none,none,none /* D8-DB br ? ? ? */ + .long none,none,none,none /* DC-DF ? ? ? ? */ + .long none,none,none,none /* E0-E3 e0 e1 ? ? */ + .long none,none,none,none /* E4-E7 ? ? ? ? */ + .long none,none,none,none /* E8-EB ? ? ? ? */ + .long none,none,none,none /* EC-EF ? ? ? ? */ + .long none,none,none,none /* F0-F3 ? ? ? ? */ + .long none,none,none,none /* F4-F7 ? ? ? ? */ + .long none,none,none,none /* F8-FB ? ? ? ? */ + .long none,none,none,none /* FC-FF ? ? ? ? */ + +/* + * kb_wait waits for the keyboard controller buffer to empty. + * there is no timeout - if the buffer doesn't empty, we hang. + */ +kb_wait: + pushl %eax +1: inb $0x64,%al + testb $0x02,%al + jne 1b + popl %eax + ret +/* + * This routine reboots the machine by asking the keyboard + * controller to pulse the reset-line low. + */ +reboot: + call kb_wait + movw $0x1234,0x472 /* don't do memory check */ + movb $0xfc,%al /* pulse reset and A20 low */ + outb %al,$0x64 +die: jmp die diff --git a/kernel/0.1x/linux-0.11/kernel/chr_drv/rs_io.s b/kernel/0.1x/linux-0.11/kernel/chr_drv/rs_io.s new file mode 100644 index 00000000..a2f8be36 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/chr_drv/rs_io.s @@ -0,0 +1,147 @@ +/* + * linux/kernel/rs_io.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * rs_io.s + * + * This module implements the rs232 io interrupts. + */ + +.text +.globl _rs1_interrupt,_rs2_interrupt + +size = 1024 /* must be power of two ! + and must match the value + in tty_io.c!!! */ + +/* these are the offsets into the read/write buffer structures */ +rs_addr = 0 +head = 4 +tail = 8 +proc_list = 12 +buf = 16 + +startup = 256 /* chars left in write queue when we restart it */ + +/* + * These are the actual interrupt routines. They look where + * the interrupt is coming from, and take appropriate action. + */ +.align 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) +1: pushl %edx + call _do_tty_interrupt + addl $4,%esp + 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/kernel/0.1x/linux-0.11/kernel/chr_drv/serial.c b/kernel/0.1x/linux-0.11/kernel/chr_drv/serial.c new file mode 100644 index 00000000..2c320c49 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/chr_drv/serial.c @@ -0,0 +1,59 @@ +/* + * linux/kernel/serial.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * serial.c + * + * This module implements the rs232 io functions + * void rs_write(struct tty_struct * queue); + * void rs_init(void); + * and all interrupts pertaining to serial IO. + */ + +#include +#include +#include +#include + +#define WAKEUP_CHARS (TTY_BUF_SIZE/4) + +extern void rs1_interrupt(void); +extern void rs2_interrupt(void); + +static void init(int port) +{ + outb_p(0x80,port+3); /* set DLAB of line control reg */ + outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */ + outb_p(0x00,port+1); /* MS of divisor */ + outb_p(0x03,port+3); /* reset DLAB */ + outb_p(0x0b,port+4); /* set DTR,RTS, OUT_2 */ + outb_p(0x0d,port+1); /* enable all intrs but writes */ + (void)inb(port); /* read data port to reset things (?) */ +} + +void rs_init(void) +{ + set_intr_gate(0x24,rs1_interrupt); + set_intr_gate(0x23,rs2_interrupt); + init(tty_table[1].read_q.data); + init(tty_table[2].read_q.data); + outb(inb_p(0x21)&0xE7,0x21); +} + +/* + * This routine gets called when tty_write has put something into + * the write_queue. It must check wheter the queue is empty, and + * set the interrupt register accordingly + * + * void _rs_write(struct tty_struct * tty); + */ +void rs_write(struct tty_struct * tty) +{ + cli(); + if (!EMPTY(tty->write_q)) + outb(inb_p(tty->write_q.data+1)|0x02,tty->write_q.data+1); + sti(); +} diff --git a/kernel/0.1x/linux-0.11/kernel/chr_drv/tty_io.c b/kernel/0.1x/linux-0.11/kernel/chr_drv/tty_io.c new file mode 100644 index 00000000..902f7ce3 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/chr_drv/tty_io.c @@ -0,0 +1,349 @@ +/* + * linux/kernel/tty_io.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles + * or rs-channels. It also implements echoing, cooked mode etc. + * + * Kill-line thanks to John T Kohl. + */ +#include +#include +#include + +#define ALRMMASK (1<<(SIGALRM-1)) +#define KILLMASK (1<<(SIGKILL-1)) +#define INTMASK (1<<(SIGINT-1)) +#define QUITMASK (1<<(SIGQUIT-1)) +#define TSTPMASK (1<<(SIGTSTP-1)) + +#include +#include +#include +#include + +#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f) +#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f) +#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f) + +#define L_CANON(tty) _L_FLAG((tty),ICANON) +#define L_ISIG(tty) _L_FLAG((tty),ISIG) +#define L_ECHO(tty) _L_FLAG((tty),ECHO) +#define L_ECHOE(tty) _L_FLAG((tty),ECHOE) +#define L_ECHOK(tty) _L_FLAG((tty),ECHOK) +#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL) +#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE) + +#define I_UCLC(tty) _I_FLAG((tty),IUCLC) +#define I_NLCR(tty) _I_FLAG((tty),INLCR) +#define I_CRNL(tty) _I_FLAG((tty),ICRNL) +#define I_NOCR(tty) _I_FLAG((tty),IGNCR) + +#define O_POST(tty) _O_FLAG((tty),OPOST) +#define O_NLCR(tty) _O_FLAG((tty),ONLCR) +#define O_CRNL(tty) _O_FLAG((tty),OCRNL) +#define O_NLRET(tty) _O_FLAG((tty),ONLRET) +#define O_LCUC(tty) _O_FLAG((tty),OLCUC) + +struct tty_struct tty_table[] = { + { + {ICRNL, /* change incoming CR to NL */ + OPOST|ONLCR, /* change outgoing NL to CRNL */ + 0, + ISIG | ICANON | ECHO | ECHOCTL | ECHOKE, + 0, /* console termio */ + INIT_C_CC}, + 0, /* initial pgrp */ + 0, /* initial stopped */ + con_write, + {0,0,0,0,""}, /* console read-queue */ + {0,0,0,0,""}, /* console write-queue */ + {0,0,0,0,""} /* console secondary queue */ + },{ + {0, /* no translation */ + 0, /* no translation */ + B2400 | CS8, + 0, + 0, + INIT_C_CC}, + 0, + 0, + rs_write, + {0x3f8,0,0,0,""}, /* rs 1 */ + {0x3f8,0,0,0,""}, + {0,0,0,0,""} + },{ + {0, /* no translation */ + 0, /* no translation */ + B2400 | CS8, + 0, + 0, + INIT_C_CC}, + 0, + 0, + rs_write, + {0x2f8,0,0,0,""}, /* rs 2 */ + {0x2f8,0,0,0,""}, + {0,0,0,0,""} + } +}; + +/* + * these are the tables used by the machine code handlers. + * you can implement pseudo-tty's or something by changing + * them. Currently not done. + */ +struct tty_queue * table_list[]={ + &tty_table[0].read_q, &tty_table[0].write_q, + &tty_table[1].read_q, &tty_table[1].write_q, + &tty_table[2].read_q, &tty_table[2].write_q + }; + +void tty_init(void) +{ + rs_init(); + con_init(); +} + +void tty_intr(struct tty_struct * tty, int mask) +{ + int i; + + if (tty->pgrp <= 0) + return; + for (i=0;ipgrp==tty->pgrp) + task[i]->signal |= mask; +} + +static void sleep_if_empty(struct tty_queue * queue) +{ + cli(); + while (!current->signal && EMPTY(*queue)) + interruptible_sleep_on(&queue->proc_list); + sti(); +} + +static void sleep_if_full(struct tty_queue * queue) +{ + if (!FULL(*queue)) + return; + cli(); + while (!current->signal && LEFT(*queue)<128) + interruptible_sleep_on(&queue->proc_list); + sti(); +} + +void wait_for_keypress(void) +{ + sleep_if_empty(&tty_table[0].secondary); +} + +void copy_to_cooked(struct tty_struct * tty) +{ + signed char c; + + while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) { + GETCH(tty->read_q,c); + if (c==13) + if (I_CRNL(tty)) + c=10; + else if (I_NOCR(tty)) + continue; + else ; + else if (c==10 && I_NLCR(tty)) + c=13; + if (I_UCLC(tty)) + c=tolower(c); + if (L_CANON(tty)) { + if (c==KILL_CHAR(tty)) { + /* deal with killing the input line */ + while(!(EMPTY(tty->secondary) || + (c=LAST(tty->secondary))==10 || + c==EOF_CHAR(tty))) { + if (L_ECHO(tty)) { + if (c<32) + PUTCH(127,tty->write_q); + PUTCH(127,tty->write_q); + tty->write(tty); + } + DEC(tty->secondary.head); + } + continue; + } + if (c==ERASE_CHAR(tty)) { + if (EMPTY(tty->secondary) || + (c=LAST(tty->secondary))==10 || + c==EOF_CHAR(tty)) + continue; + if (L_ECHO(tty)) { + if (c<32) + PUTCH(127,tty->write_q); + PUTCH(127,tty->write_q); + tty->write(tty); + } + DEC(tty->secondary.head); + continue; + } + if (c==STOP_CHAR(tty)) { + tty->stopped=1; + continue; + } + if (c==START_CHAR(tty)) { + tty->stopped=0; + continue; + } + } + if (L_ISIG(tty)) { + if (c==INTR_CHAR(tty)) { + tty_intr(tty,INTMASK); + continue; + } + if (c==QUIT_CHAR(tty)) { + tty_intr(tty,QUITMASK); + continue; + } + } + if (c==10 || c==EOF_CHAR(tty)) + tty->secondary.data++; + if (L_ECHO(tty)) { + if (c==10) { + PUTCH(10,tty->write_q); + PUTCH(13,tty->write_q); + } else if (c<32) { + if (L_ECHOCTL(tty)) { + PUTCH('^',tty->write_q); + PUTCH(c+64,tty->write_q); + } + } else + PUTCH(c,tty->write_q); + tty->write(tty); + } + PUTCH(c,tty->secondary); + } + wake_up(&tty->secondary.proc_list); +} + +int tty_read(unsigned channel, char * buf, int nr) +{ + struct tty_struct * tty; + char c, * b=buf; + int minimum,time,flag=0; + long oldalarm; + + if (channel>2 || nr<0) return -1; + tty = &tty_table[channel]; + oldalarm = current->alarm; + time = 10L*tty->termios.c_cc[VTIME]; + minimum = tty->termios.c_cc[VMIN]; + if (time && !minimum) { + minimum=1; + if (flag=(!oldalarm || time+jiffiesalarm = time+jiffies; + } + if (minimum>nr) + minimum=nr; + while (nr>0) { + if (flag && (current->signal & ALRMMASK)) { + current->signal &= ~ALRMMASK; + break; + } + if (current->signal) + break; + if (EMPTY(tty->secondary) || (L_CANON(tty) && + !tty->secondary.data && LEFT(tty->secondary)>20)) { + sleep_if_empty(&tty->secondary); + continue; + } + do { + GETCH(tty->secondary,c); + if (c==EOF_CHAR(tty) || c==10) + tty->secondary.data--; + if (c==EOF_CHAR(tty) && L_CANON(tty)) + return (b-buf); + else { + put_fs_byte(c,b++); + if (!--nr) + break; + } + } while (nr>0 && !EMPTY(tty->secondary)); + if (time && !L_CANON(tty)) + if (flag=(!oldalarm || time+jiffiesalarm = time+jiffies; + else + current->alarm = oldalarm; + if (L_CANON(tty)) { + if (b-buf) + break; + } else if (b-buf >= minimum) + break; + } + current->alarm = oldalarm; + if (current->signal && !(b-buf)) + return -EINTR; + return (b-buf); +} + +int tty_write(unsigned channel, char * buf, int nr) +{ + static cr_flag=0; + struct tty_struct * tty; + char c, *b=buf; + + if (channel>2 || nr<0) return -1; + tty = channel + tty_table; + while (nr>0) { + sleep_if_full(&tty->write_q); + if (current->signal) + break; + while (nr>0 && !FULL(tty->write_q)) { + c=get_fs_byte(b); + if (O_POST(tty)) { + if (c=='\r' && O_CRNL(tty)) + c='\n'; + else if (c=='\n' && O_NLRET(tty)) + c='\r'; + if (c=='\n' && !cr_flag && O_NLCR(tty)) { + cr_flag = 1; + PUTCH(13,tty->write_q); + continue; + } + if (O_LCUC(tty)) + c=toupper(c); + } + b++; nr--; + cr_flag = 0; + PUTCH(c,tty->write_q); + } + tty->write(tty); + if (nr>0) + schedule(); + } + return (b-buf); +} + +/* + * Jeh, sometimes I really like the 386. + * This routine is called from an interrupt, + * and there should be absolutely no problem + * with sleeping even in an interrupt (I hope). + * Of course, if somebody proves me wrong, I'll + * hate intel for all time :-). We'll have to + * be careful and see to reinstating the interrupt + * chips before calling this, though. + * + * I don't think we sleep here under normal circumstances + * anyway, which is good, as the task sleeping might be + * totally innocent. + */ +void do_tty_interrupt(int tty) +{ + copy_to_cooked(tty_table+tty); +} + +void chr_dev_init(void) +{ +} diff --git a/kernel/0.1x/linux-0.11/kernel/chr_drv/tty_ioctl.c b/kernel/0.1x/linux-0.11/kernel/chr_drv/tty_ioctl.c new file mode 100644 index 00000000..b3acbdc9 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/chr_drv/tty_ioctl.c @@ -0,0 +1,204 @@ +/* + * linux/kernel/chr_drv/tty_ioctl.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +static unsigned short quotient[] = { + 0, 2304, 1536, 1047, 857, + 768, 576, 384, 192, 96, + 64, 48, 24, 12, 6, 3 +}; + +static void change_speed(struct tty_struct * tty) +{ + unsigned short port,quot; + + if (!(port = tty->read_q.data)) + return; + quot = quotient[tty->termios.c_cflag & CBAUD]; + cli(); + outb_p(0x80,port+3); /* set DLAB */ + outb_p(quot & 0xff,port); /* LS of divisor */ + outb_p(quot >> 8,port+1); /* MS of divisor */ + outb(0x03,port+3); /* reset DLAB */ + sti(); +} + +static void flush(struct tty_queue * queue) +{ + cli(); + queue->head = queue->tail; + sti(); +} + +static void wait_until_sent(struct tty_struct * tty) +{ + /* do nothing - not implemented */ +} + +static void send_break(struct tty_struct * tty) +{ + /* do nothing - not implemented */ +} + +static int get_termios(struct tty_struct * tty, struct termios * termios) +{ + int i; + + verify_area(termios, sizeof (*termios)); + for (i=0 ; i< (sizeof (*termios)) ; i++) + put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios ); + return 0; +} + +static int set_termios(struct tty_struct * tty, struct termios * termios) +{ + int i; + + for (i=0 ; i< (sizeof (*termios)) ; i++) + ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios); + change_speed(tty); + return 0; +} + +static int get_termio(struct tty_struct * tty, struct termio * termio) +{ + int i; + struct termio tmp_termio; + + verify_area(termio, sizeof (*termio)); + tmp_termio.c_iflag = tty->termios.c_iflag; + tmp_termio.c_oflag = tty->termios.c_oflag; + tmp_termio.c_cflag = tty->termios.c_cflag; + tmp_termio.c_lflag = tty->termios.c_lflag; + tmp_termio.c_line = tty->termios.c_line; + for(i=0 ; i < NCC ; i++) + tmp_termio.c_cc[i] = tty->termios.c_cc[i]; + for (i=0 ; i< (sizeof (*termio)) ; i++) + put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio ); + return 0; +} + +/* + * This only works as the 386 is low-byt-first + */ +static int set_termio(struct tty_struct * tty, struct termio * termio) +{ + int i; + struct termio tmp_termio; + + for (i=0 ; i< (sizeof (*termio)) ; i++) + ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio); + *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag; + *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag; + *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag; + *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag; + tty->termios.c_line = tmp_termio.c_line; + for(i=0 ; i < NCC ; i++) + tty->termios.c_cc[i] = tmp_termio.c_cc[i]; + change_speed(tty); + return 0; +} + +int tty_ioctl(int dev, int cmd, int arg) +{ + struct tty_struct * tty; + if (MAJOR(dev) == 5) { + dev=current->tty; + if (dev<0) + panic("tty_ioctl: dev<0"); + } else + dev=MINOR(dev); + tty = dev + tty_table; + switch (cmd) { + case TCGETS: + return get_termios(tty,(struct termios *) arg); + case TCSETSF: + flush(&tty->read_q); /* fallthrough */ + case TCSETSW: + wait_until_sent(tty); /* fallthrough */ + case TCSETS: + return set_termios(tty,(struct termios *) arg); + case TCGETA: + return get_termio(tty,(struct termio *) arg); + case TCSETAF: + flush(&tty->read_q); /* fallthrough */ + case TCSETAW: + wait_until_sent(tty); /* fallthrough */ + case TCSETA: + return set_termio(tty,(struct termio *) arg); + case TCSBRK: + if (!arg) { + wait_until_sent(tty); + send_break(tty); + } + return 0; + case TCXONC: + return -EINVAL; /* not implemented */ + case TCFLSH: + if (arg==0) + flush(&tty->read_q); + else if (arg==1) + flush(&tty->write_q); + else if (arg==2) { + flush(&tty->read_q); + flush(&tty->write_q); + } else + return -EINVAL; + return 0; + case TIOCEXCL: + return -EINVAL; /* not implemented */ + case TIOCNXCL: + return -EINVAL; /* not implemented */ + case TIOCSCTTY: + return -EINVAL; /* set controlling term NI */ + case TIOCGPGRP: + verify_area((void *) arg,4); + put_fs_long(tty->pgrp,(unsigned long *) arg); + return 0; + case TIOCSPGRP: + tty->pgrp=get_fs_long((unsigned long *) arg); + return 0; + case TIOCOUTQ: + verify_area((void *) arg,4); + put_fs_long(CHARS(tty->write_q),(unsigned long *) arg); + return 0; + case TIOCINQ: + verify_area((void *) arg,4); + put_fs_long(CHARS(tty->secondary), + (unsigned long *) arg); + return 0; + case TIOCSTI: + return -EINVAL; /* not implemented */ + case TIOCGWINSZ: + return -EINVAL; /* not implemented */ + case TIOCSWINSZ: + return -EINVAL; /* not implemented */ + case TIOCMGET: + return -EINVAL; /* not implemented */ + case TIOCMBIS: + return -EINVAL; /* not implemented */ + case TIOCMBIC: + return -EINVAL; /* not implemented */ + case TIOCMSET: + return -EINVAL; /* not implemented */ + case TIOCGSOFTCAR: + return -EINVAL; /* not implemented */ + case TIOCSSOFTCAR: + return -EINVAL; /* not implemented */ + default: + return -EINVAL; + } +} diff --git a/kernel/0.1x/linux-0.11/kernel/exit.c b/kernel/0.1x/linux-0.11/kernel/exit.c new file mode 100644 index 00000000..88f97dff --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/exit.c @@ -0,0 +1,197 @@ +/* + * linux/kernel/exit.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include +#include +#include + +int sys_pause(void); +int sys_close(int fd); + +void release(struct task_struct * p) +{ + int i; + + if (!p) + return; + for (i=1 ; i32) + return -EINVAL; + if (priv || (current->euid==p->euid) || suser()) + p->signal |= (1<<(sig-1)); + else + return -EPERM; + return 0; +} + +static void kill_session(void) +{ + struct task_struct **p = NR_TASKS + task; + + while (--p > &FIRST_TASK) { + if (*p && (*p)->session == current->session) + (*p)->signal |= 1<<(SIGHUP-1); + } +} + +/* + * XXX need to check permissions needed to send signals to process + * groups, etc. etc. kill() permissions semantics are tricky! + */ +int sys_kill(int pid,int sig) +{ + struct task_struct **p = NR_TASKS + task; + int err, retval = 0; + + if (!pid) while (--p > &FIRST_TASK) { + if (*p && (*p)->pgrp == current->pid) + if (err=send_sig(sig,*p,1)) + retval = err; + } else if (pid>0) while (--p > &FIRST_TASK) { + if (*p && (*p)->pid == pid) + if (err=send_sig(sig,*p,0)) + retval = err; + } else if (pid == -1) while (--p > &FIRST_TASK) + if (err = send_sig(sig,*p,0)) + retval = err; + else while (--p > &FIRST_TASK) + if (*p && (*p)->pgrp == -pid) + if (err = send_sig(sig,*p,0)) + retval = err; + return retval; +} + +static void tell_father(int pid) +{ + int i; + + if (pid) + for (i=0;ipid != pid) + continue; + task[i]->signal |= (1<<(SIGCHLD-1)); + return; + } +/* if we don't find any fathers, we just release ourselves */ +/* This is not really OK. Must change it to make father 1 */ + printk("BAD BAD - no father found\n\r"); + release(current); +} + +int do_exit(long code) +{ + int i; + + free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); + free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); + for (i=0 ; ifather == current->pid) { + task[i]->father = 1; + if (task[i]->state == TASK_ZOMBIE) + /* assumption task[1] is always init */ + (void) send_sig(SIGCHLD, task[1], 1); + } + for (i=0 ; ifilp[i]) + sys_close(i); + iput(current->pwd); + current->pwd=NULL; + iput(current->root); + current->root=NULL; + iput(current->executable); + current->executable=NULL; + if (current->leader && current->tty >= 0) + tty_table[current->tty].pgrp = 0; + if (last_task_used_math == current) + last_task_used_math = NULL; + if (current->leader) + kill_session(); + current->state = TASK_ZOMBIE; + current->exit_code = code; + tell_father(current->father); + schedule(); + return (-1); /* just to suppress warnings */ +} + +int sys_exit(int error_code) +{ + return do_exit((error_code&0xff)<<8); +} + +int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options) +{ + int flag, code; + struct task_struct ** p; + + verify_area(stat_addr,4); +repeat: + flag=0; + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if (!*p || *p == current) + continue; + if ((*p)->father != current->pid) + continue; + if (pid>0) { + if ((*p)->pid != pid) + continue; + } else if (!pid) { + if ((*p)->pgrp != current->pgrp) + continue; + } else if (pid != -1) { + if ((*p)->pgrp != -pid) + continue; + } + switch ((*p)->state) { + case TASK_STOPPED: + if (!(options & WUNTRACED)) + continue; + put_fs_long(0x7f,stat_addr); + return (*p)->pid; + case TASK_ZOMBIE: + current->cutime += (*p)->utime; + current->cstime += (*p)->stime; + flag = (*p)->pid; + code = (*p)->exit_code; + release(*p); + put_fs_long(code,stat_addr); + return flag; + default: + flag=1; + continue; + } + } + if (flag) { + if (options & WNOHANG) + return 0; + current->state=TASK_INTERRUPTIBLE; + schedule(); + if (!(current->signal &= ~(1<<(SIGCHLD-1)))) + goto repeat; + else + return -EINTR; + } + return -ECHILD; +} + + diff --git a/kernel/0.1x/linux-0.11/kernel/fork.c b/kernel/0.1x/linux-0.11/kernel/fork.c new file mode 100644 index 00000000..334a34bd --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/fork.c @@ -0,0 +1,147 @@ +/* + * linux/kernel/fork.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'fork.c' contains the help-routines for the 'fork' system call + * (see also system_call.s), and some misc functions ('verify_area'). + * Fork is rather simple, once you get the hang of it, but the memory + * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()' + */ +#include + +#include +#include +#include +#include + +extern void write_verify(unsigned long address); + +long last_pid=0; + +void verify_area(void * addr,int size) +{ + unsigned long start; + + start = (unsigned long) addr; + size += start & 0xfff; + start &= 0xfffff000; + start += get_base(current->ldt[2]); + while (size>0) { + size -= 4096; + write_verify(start); + start += 4096; + } +} + +int copy_mem(int nr,struct task_struct * p) +{ + unsigned long old_data_base,new_data_base,data_limit; + unsigned long old_code_base,new_code_base,code_limit; + + code_limit=get_limit(0x0f); + data_limit=get_limit(0x17); + old_code_base = get_base(current->ldt[1]); + old_data_base = get_base(current->ldt[2]); + if (old_data_base != old_code_base) + panic("We don't support separate I&D"); + if (data_limit < code_limit) + panic("Bad data_limit"); + new_data_base = new_code_base = nr * 0x4000000; + p->start_code = new_code_base; + set_base(p->ldt[1],new_code_base); + set_base(p->ldt[2],new_data_base); + if (copy_page_tables(old_data_base,new_data_base,data_limit)) { + free_page_tables(new_data_base,data_limit); + return -ENOMEM; + } + return 0; +} + +/* + * Ok, this is the main fork-routine. It copies the system process + * information (task[nr]) and sets up the necessary registers. It + * also copies the data segment in it's entirety. + */ +int copy_process(int nr,long ebp,long edi,long esi,long gs,long none, + long ebx,long ecx,long edx, + long fs,long es,long ds, + long eip,long cs,long eflags,long esp,long ss) +{ + struct task_struct *p; + int i; + struct file *f; + + p = (struct task_struct *) get_free_page(); + if (!p) + return -EAGAIN; + task[nr] = p; + *p = *current; /* NOTE! this doesn't copy the supervisor stack */ + p->state = TASK_UNINTERRUPTIBLE; + p->pid = last_pid; + p->father = current->pid; + p->counter = p->priority; + p->signal = 0; + p->alarm = 0; + p->leader = 0; /* process leadership doesn't inherit */ + p->utime = p->stime = 0; + p->cutime = p->cstime = 0; + p->start_time = jiffies; + p->tss.back_link = 0; + p->tss.esp0 = PAGE_SIZE + (long) p; + p->tss.ss0 = 0x10; + p->tss.eip = eip; + p->tss.eflags = eflags; + p->tss.eax = 0; + p->tss.ecx = ecx; + p->tss.edx = edx; + p->tss.ebx = ebx; + p->tss.esp = esp; + p->tss.ebp = ebp; + p->tss.esi = esi; + p->tss.edi = edi; + p->tss.es = es & 0xffff; + p->tss.cs = cs & 0xffff; + p->tss.ss = ss & 0xffff; + p->tss.ds = ds & 0xffff; + p->tss.fs = fs & 0xffff; + p->tss.gs = gs & 0xffff; + p->tss.ldt = _LDT(nr); + p->tss.trace_bitmap = 0x80000000; + if (last_task_used_math == current) + __asm__("clts ; fnsave %0"::"m" (p->tss.i387)); + if (copy_mem(nr,p)) { + task[nr] = NULL; + free_page((long) p); + return -EAGAIN; + } + for (i=0; ifilp[i]) + f->f_count++; + if (current->pwd) + current->pwd->i_count++; + if (current->root) + current->root->i_count++; + if (current->executable) + current->executable->i_count++; + set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss)); + set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt)); + p->state = TASK_RUNNING; /* do this last, just in case */ + return last_pid; +} + +int find_empty_process(void) +{ + int i; + + repeat: + if ((++last_pid)<0) last_pid=1; + for(i=0 ; ipid == last_pid) goto repeat; + for(i=1 ; i 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/kernel/0.1x/linux-0.11/kernel/math/math_emulate.c b/kernel/0.1x/linux-0.11/kernel/math/math_emulate.c new file mode 100644 index 00000000..24c1c2f3 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/math/math_emulate.c @@ -0,0 +1,42 @@ +/* + * linux/kernel/math/math_emulate.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This directory should contain the math-emulation code. + * Currently only results in a signal. + */ + +#include + +#include +#include +#include + +void math_emulate(long edi, long esi, long ebp, long sys_call_ret, + long eax,long ebx,long ecx,long edx, + unsigned short fs,unsigned short es,unsigned short ds, + unsigned long eip,unsigned short cs,unsigned long eflags, + unsigned short ss, unsigned long esp) +{ + unsigned char first, second; + +/* 0x0007 means user code space */ + if (cs != 0x000F) { + printk("math_emulate: %04x:%08x\n\r",cs,eip); + panic("Math emulation needed in kernel"); + } + first = get_fs_byte((char *)((*&eip)++)); + second = get_fs_byte((char *)((*&eip)++)); + printk("%04x:%08x %02x %02x\n\r",cs,eip-2,first,second); + current->signal |= 1<<(SIGFPE-1); +} + +void math_error(void) +{ + __asm__("fnclex"); + if (last_task_used_math) + last_task_used_math->signal |= 1<<(SIGFPE-1); +} diff --git a/kernel/0.1x/linux-0.11/kernel/mktime.c b/kernel/0.1x/linux-0.11/kernel/mktime.c new file mode 100644 index 00000000..ccb7cb22 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/mktime.c @@ -0,0 +1,58 @@ +/* + * linux/kernel/mktime.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +/* + * This isn't the library routine, it is only used in the kernel. + * as such, we don't care about years<1970 etc, but assume everything + * is ok. Similarly, TZ etc is happily ignored. We just do everything + * as easily as possible. Let's find something public for the library + * routines (although I think minix times is public). + */ +/* + * PS. I hate whoever though up the year 1970 - couldn't they have gotten + * a leap-year instead? I also hate Gregorius, pope or no. I'm grumpy. + */ +#define MINUTE 60 +#define HOUR (60*MINUTE) +#define DAY (24*HOUR) +#define YEAR (365*DAY) + +/* interestingly, we assume leap-years */ +static int month[12] = { + 0, + DAY*(31), + DAY*(31+29), + DAY*(31+29+31), + DAY*(31+29+31+30), + DAY*(31+29+31+30+31), + DAY*(31+29+31+30+31+30), + DAY*(31+29+31+30+31+30+31), + DAY*(31+29+31+30+31+30+31+31), + DAY*(31+29+31+30+31+30+31+31+30), + DAY*(31+29+31+30+31+30+31+31+30+31), + DAY*(31+29+31+30+31+30+31+31+30+31+30) +}; + +long kernel_mktime(struct tm * tm) +{ + long res; + int year; + + 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/kernel/0.1x/linux-0.11/kernel/panic.c b/kernel/0.1x/linux-0.11/kernel/panic.c new file mode 100644 index 00000000..6624d505 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/panic.c @@ -0,0 +1,24 @@ +/* + * linux/kernel/panic.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This function is used through-out the kernel (includeinh mm and fs) + * to indicate a major problem. + */ +#include +#include + +void sys_sync(void); /* it's really int */ + +volatile void panic(const char * s) +{ + printk("Kernel panic: %s\n\r",s); + if (current == task[0]) + printk("In swapper task - not syncing\n\r"); + else + sys_sync(); + for(;;); +} diff --git a/kernel/0.1x/linux-0.11/kernel/printk.c b/kernel/0.1x/linux-0.11/kernel/printk.c new file mode 100644 index 00000000..79cfba04 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/printk.c @@ -0,0 +1,41 @@ +/* + * linux/kernel/printk.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * When in kernel-mode, we cannot use printf, as fs is liable to + * point to 'interesting' things. Make a printf with fs-saving, and + * all is well. + */ +#include +#include + +#include + +static char buf[1024]; + +extern int vsprintf(char * buf, const char * fmt, va_list args); + +int printk(const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + __asm__("push %%fs\n\t" + "push %%ds\n\t" + "pop %%fs\n\t" + "pushl %0\n\t" + "pushl $_buf\n\t" + "pushl $0\n\t" + "call _tty_write\n\t" + "addl $8,%%esp\n\t" + "popl %0\n\t" + "pop %%fs" + ::"r" (i):"ax","cx","dx"); + return i; +} diff --git a/kernel/0.1x/linux-0.11/kernel/sched.c b/kernel/0.1x/linux-0.11/kernel/sched.c new file mode 100644 index 00000000..7eaabbfb --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/sched.c @@ -0,0 +1,412 @@ +/* + * linux/kernel/sched.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'sched.c' is the main kernel file. It contains scheduling primitives + * (sleep_on, wakeup, schedule etc) as well as a number of simple system + * call functions (type getpid(), which just extracts a field from + * current-task + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#define _S(nr) (1<<((nr)-1)) +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + +void show_task(int nr,struct task_struct * p) +{ + int i,j = 4096-sizeof(struct task_struct); + + printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state); + i=0; + while (i>2 ] ; + +struct { + long * a; + short b; + } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 }; +/* + * 'math_state_restore()' saves the current math information in the + * old math state array, and gets the new ones from the current task + */ +void math_state_restore() +{ + if (last_task_used_math == current) + return; + __asm__("fwait"); + if (last_task_used_math) { + __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387)); + } + last_task_used_math=current; + if (current->used_math) { + __asm__("frstor %0"::"m" (current->tss.i387)); + } else { + __asm__("fninit"::); + current->used_math=1; + } +} + +/* + * 'schedule()' is the scheduler function. This is GOOD CODE! There + * probably won't be any reason to change this, as it should work well + * in all circumstances (ie gives IO-bound processes good response etc). + * The one thing you might take a look at is the signal-handler code here. + * + * NOTE!! Task 0 is the 'idle' task, which gets called when no other + * tasks can run. It can not be killed, and it cannot sleep. The 'state' + * information in task[0] is never used. + */ +void schedule(void) +{ + int i,next,c; + struct task_struct ** p; + +/* check alarm, wake up any interruptible tasks that have got a signal */ + + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if (*p) { + if ((*p)->alarm && (*p)->alarm < jiffies) { + (*p)->signal |= (1<<(SIGALRM-1)); + (*p)->alarm = 0; + } + if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) && + (*p)->state==TASK_INTERRUPTIBLE) + (*p)->state=TASK_RUNNING; + } + +/* this is the scheduler proper: */ + + while (1) { + c = -1; + next = 0; + i = NR_TASKS; + p = &task[NR_TASKS]; + while (--i) { + if (!*--p) + continue; + if ((*p)->state == TASK_RUNNING && (*p)->counter > c) + c = (*p)->counter, next = i; + } + if (c) break; + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if (*p) + (*p)->counter = ((*p)->counter >> 1) + + (*p)->priority; + } + switch_to(next); +} + +int sys_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return 0; +} + +void sleep_on(struct task_struct **p) +{ + struct task_struct *tmp; + + if (!p) + return; + if (current == &(init_task.task)) + panic("task[0] trying to sleep"); + tmp = *p; + *p = current; + current->state = TASK_UNINTERRUPTIBLE; + schedule(); + if (tmp) + tmp->state=0; +} + +void interruptible_sleep_on(struct task_struct **p) +{ + struct task_struct *tmp; + + if (!p) + return; + if (current == &(init_task.task)) + panic("task[0] trying to sleep"); + tmp=*p; + *p=current; +repeat: current->state = TASK_INTERRUPTIBLE; + schedule(); + if (*p && *p != current) { + (**p).state=0; + goto repeat; + } + *p=NULL; + if (tmp) + tmp->state=0; +} + +void wake_up(struct task_struct **p) +{ + if (p && *p) { + (**p).state=0; + *p=NULL; + } +} + +/* + * OK, here are some floppy things that shouldn't be in the kernel + * proper. They are here because the floppy needs a timer, and this + * was the easiest way of doing it. + */ +static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL}; +static int mon_timer[4]={0,0,0,0}; +static int moff_timer[4]={0,0,0,0}; +unsigned char current_DOR = 0x0C; + +int ticks_to_floppy_on(unsigned int nr) +{ + extern unsigned char selected; + unsigned char mask = 0x10 << nr; + + if (nr>3) + panic("floppy_on: nr>3"); + moff_timer[nr]=10000; /* 100 s = very big :-) */ + cli(); /* use floppy_off to turn it off */ + mask |= current_DOR; + if (!selected) { + mask &= 0xFC; + mask |= nr; + } + if (mask != current_DOR) { + outb(mask,FD_DOR); + if ((mask ^ current_DOR) & 0xf0) + mon_timer[nr] = HZ/2; + else if (mon_timer[nr] < 2) + mon_timer[nr] = 2; + current_DOR = mask; + } + sti(); + return mon_timer[nr]; +} + +void floppy_on(unsigned int nr) +{ + cli(); + while (ticks_to_floppy_on(nr)) + sleep_on(nr+wait_motor); + sti(); +} + +void floppy_off(unsigned int nr) +{ + moff_timer[nr]=3*HZ; +} + +void do_floppy_timer(void) +{ + int i; + unsigned char mask = 0x10; + + for (i=0 ; i<4 ; i++,mask <<= 1) { + if (!(mask & current_DOR)) + continue; + if (mon_timer[i]) { + if (!--mon_timer[i]) + wake_up(i+wait_motor); + } else if (!moff_timer[i]) { + current_DOR &= ~mask; + outb(current_DOR,FD_DOR); + } else + moff_timer[i]--; + } +} + +#define TIME_REQUESTS 64 + +static struct timer_list { + long jiffies; + void (*fn)(); + struct timer_list * next; +} timer_list[TIME_REQUESTS], * next_timer = NULL; + +void add_timer(long jiffies, void (*fn)(void)) +{ + struct timer_list * p; + + if (!fn) + return; + cli(); + if (jiffies <= 0) + (fn)(); + else { + for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++) + if (!p->fn) + break; + if (p >= timer_list + TIME_REQUESTS) + panic("No more time requests free"); + p->fn = fn; + p->jiffies = jiffies; + p->next = next_timer; + next_timer = p; + while (p->next && p->next->jiffies < p->jiffies) { + p->jiffies -= p->next->jiffies; + fn = p->fn; + p->fn = p->next->fn; + p->next->fn = fn; + jiffies = p->jiffies; + p->jiffies = p->next->jiffies; + p->next->jiffies = jiffies; + p = p->next; + } + } + sti(); +} + +void do_timer(long cpl) +{ + extern int beepcount; + extern void sysbeepstop(void); + + if (beepcount) + if (!--beepcount) + sysbeepstop(); + + if (cpl) + current->utime++; + else + current->stime++; + + if (next_timer) { + next_timer->jiffies--; + while (next_timer && next_timer->jiffies <= 0) { + void (*fn)(void); + + fn = next_timer->fn; + next_timer->fn = NULL; + next_timer = next_timer->next; + (fn)(); + } + } + if (current_DOR & 0xf0) + do_floppy_timer(); + if ((--current->counter)>0) return; + current->counter=0; + if (!cpl) return; + schedule(); +} + +int sys_alarm(long seconds) +{ + int old = current->alarm; + + if (old) + old = (old - jiffies) / HZ; + current->alarm = (seconds>0)?(jiffies+HZ*seconds):0; + return (old); +} + +int sys_getpid(void) +{ + return current->pid; +} + +int sys_getppid(void) +{ + return current->father; +} + +int sys_getuid(void) +{ + return current->uid; +} + +int sys_geteuid(void) +{ + return current->euid; +} + +int sys_getgid(void) +{ + return current->gid; +} + +int sys_getegid(void) +{ + return current->egid; +} + +int sys_nice(long increment) +{ + if (current->priority-increment>0) + current->priority -= increment; + return 0; +} + +void sched_init(void) +{ + int i; + struct desc_struct * p; + + if (sizeof(struct sigaction) != 16) + panic("Struct sigaction MUST be 16 bytes"); + set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); + set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); + p = gdt+2+FIRST_TSS_ENTRY; + for(i=1;ia=p->b=0; + p++; + p->a=p->b=0; + p++; + } +/* Clear NT, so that we won't have troubles with that later on */ + __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); + ltr(0); + lldt(0); + outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */ + outb_p(LATCH & 0xff , 0x40); /* LSB */ + outb(LATCH >> 8 , 0x40); /* MSB */ + set_intr_gate(0x20,&timer_interrupt); + outb(inb_p(0x21)&~0x01,0x21); + set_system_gate(0x80,&system_call); +} diff --git a/kernel/0.1x/linux-0.11/kernel/signal.c b/kernel/0.1x/linux-0.11/kernel/signal.c new file mode 100644 index 00000000..be009286 --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/signal.c @@ -0,0 +1,119 @@ +/* + * linux/kernel/signal.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include + +volatile void do_exit(int error_code); + +int sys_sgetmask() +{ + return current->blocked; +} + +int sys_ssetmask(int newmask) +{ + int old=current->blocked; + + current->blocked = newmask & ~(1<<(SIGKILL-1)); + return old; +} + +static inline void save_old(char * from,char * to) +{ + int i; + + verify_area(to, sizeof(struct sigaction)); + for (i=0 ; i< sizeof(struct sigaction) ; i++) { + put_fs_byte(*from,to); + from++; + to++; + } +} + +static inline void get_new(char * from,char * to) +{ + int i; + + for (i=0 ; i< sizeof(struct sigaction) ; i++) + *(to++) = get_fs_byte(from++); +} + +int sys_signal(int signum, long handler, long restorer) +{ + struct sigaction tmp; + + if (signum<1 || signum>32 || signum==SIGKILL) + return -1; + tmp.sa_handler = (void (*)(int)) handler; + tmp.sa_mask = 0; + tmp.sa_flags = SA_ONESHOT | SA_NOMASK; + tmp.sa_restorer = (void (*)(void)) restorer; + handler = (long) current->sigaction[signum-1].sa_handler; + current->sigaction[signum-1] = tmp; + return handler; +} + +int sys_sigaction(int signum, const struct sigaction * action, + struct sigaction * oldaction) +{ + struct sigaction tmp; + + if (signum<1 || signum>32 || signum==SIGKILL) + return -1; + tmp = current->sigaction[signum-1]; + get_new((char *) action, + (char *) (signum-1+current->sigaction)); + if (oldaction) + save_old((char *) &tmp,(char *) oldaction); + if (current->sigaction[signum-1].sa_flags & SA_NOMASK) + current->sigaction[signum-1].sa_mask = 0; + else + current->sigaction[signum-1].sa_mask |= (1<<(signum-1)); + return 0; +} + +void do_signal(long signr,long eax, long ebx, long ecx, long edx, + long fs, long es, long ds, + long eip, long cs, long eflags, + unsigned long * esp, long ss) +{ + unsigned long sa_handler; + long old_eip=eip; + struct sigaction * sa = current->sigaction + signr - 1; + int longs; + unsigned long * tmp_esp; + + sa_handler = (unsigned long) sa->sa_handler; + if (sa_handler==1) + return; + if (!sa_handler) { + if (signr==SIGCHLD) + return; + else + do_exit(1<<(signr-1)); + } + if (sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; + *(&eip) = sa_handler; + longs = (sa->sa_flags & SA_NOMASK)?7:8; + *(&esp) -= longs; + verify_area(esp,longs*4); + tmp_esp=esp; + put_fs_long((long) sa->sa_restorer,tmp_esp++); + put_fs_long(signr,tmp_esp++); + if (!(sa->sa_flags & SA_NOMASK)) + put_fs_long(current->blocked,tmp_esp++); + put_fs_long(eax,tmp_esp++); + put_fs_long(ecx,tmp_esp++); + put_fs_long(edx,tmp_esp++); + put_fs_long(eflags,tmp_esp++); + put_fs_long(old_eip,tmp_esp++); + current->blocked |= sa->sa_mask; +} diff --git a/kernel/0.1x/linux-0.11/kernel/sys.c b/kernel/0.1x/linux-0.11/kernel/sys.c new file mode 100644 index 00000000..1539d09f --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/sys.c @@ -0,0 +1,236 @@ +/* + * linux/kernel/sys.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include +#include +#include +#include +#include + +int sys_ftime() +{ + return -ENOSYS; +} + +int sys_break() +{ + return -ENOSYS; +} + +int sys_ptrace() +{ + return -ENOSYS; +} + +int sys_stty() +{ + return -ENOSYS; +} + +int sys_gtty() +{ + return -ENOSYS; +} + +int sys_rename() +{ + return -ENOSYS; +} + +int sys_prof() +{ + return -ENOSYS; +} + +int sys_setregid(int rgid, int egid) +{ + if (rgid>0) { + if ((current->gid == rgid) || + suser()) + current->gid = rgid; + else + return(-EPERM); + } + if (egid>0) { + if ((current->gid == egid) || + (current->egid == egid) || + (current->sgid == egid) || + suser()) + current->egid = egid; + else + return(-EPERM); + } + return 0; +} + +int sys_setgid(int gid) +{ + return(sys_setregid(gid, gid)); +} + +int sys_acct() +{ + return -ENOSYS; +} + +int sys_phys() +{ + return -ENOSYS; +} + +int sys_lock() +{ + return -ENOSYS; +} + +int sys_mpx() +{ + return -ENOSYS; +} + +int sys_ulimit() +{ + return -ENOSYS; +} + +int sys_time(long * tloc) +{ + int i; + + i = CURRENT_TIME; + if (tloc) { + verify_area(tloc,4); + put_fs_long(i,(unsigned long *)tloc); + } + return i; +} + +/* + * Unprivileged users may change the real user id to the effective uid + * or vice versa. + */ +int sys_setreuid(int ruid, int euid) +{ + int old_ruid = current->uid; + + if (ruid>0) { + if ((current->euid==ruid) || + (old_ruid == ruid) || + suser()) + current->uid = ruid; + else + return(-EPERM); + } + if (euid>0) { + if ((old_ruid == euid) || + (current->euid == euid) || + suser()) + current->euid = euid; + else { + current->uid = old_ruid; + return(-EPERM); + } + } + return 0; +} + +int sys_setuid(int uid) +{ + return(sys_setreuid(uid, uid)); +} + +int sys_stime(long * tptr) +{ + if (!suser()) + return -EPERM; + startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ; + return 0; +} + +int sys_times(struct tms * tbuf) +{ + if (tbuf) { + verify_area(tbuf,sizeof *tbuf); + put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime); + put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime); + put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime); + put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime); + } + return jiffies; +} + +int sys_brk(unsigned long end_data_seg) +{ + if (end_data_seg >= current->end_code && + end_data_seg < current->start_stack - 16384) + current->brk = end_data_seg; + return current->brk; +} + +/* + * This needs some heave checking ... + * I just haven't get the stomach for it. I also don't fully + * understand sessions/pgrp etc. Let somebody who does explain it. + */ +int sys_setpgid(int pid, int pgid) +{ + int i; + + if (!pid) + pid = current->pid; + if (!pgid) + pgid = current->pid; + for (i=0 ; ipid==pid) { + if (task[i]->leader) + return -EPERM; + if (task[i]->session != current->session) + return -EPERM; + task[i]->pgrp = pgid; + return 0; + } + return -ESRCH; +} + +int sys_getpgrp(void) +{ + return current->pgrp; +} + +int sys_setsid(void) +{ + if (current->leader && !suser()) + return -EPERM; + current->leader = 1; + current->session = current->pgrp = current->pid; + current->tty = -1; + return current->pgrp; +} + +int sys_uname(struct utsname * name) +{ + static struct utsname thisname = { + "linux .0","nodename","release ","version ","machine " + }; + int i; + + if (!name) return -ERROR; + verify_area(name,sizeof *name); + for(i=0;iumask; + + current->umask = mask & 0777; + return (old); +} diff --git a/kernel/0.1x/linux-0.11/kernel/system_call.s b/kernel/0.1x/linux-0.11/kernel/system_call.s new file mode 100644 index 00000000..d2156b0c --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/system_call.s @@ -0,0 +1,285 @@ +/* + * linux/kernel/system_call.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * system_call.s contains the system-call low-level handling routines. + * This also contains the timer-interrupt handler, as some of the code is + * the same. The hd- and flopppy-interrupts are also here. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. Ordinary interrupts + * don't handle signal-recognition, as that would clutter them up totally + * unnecessarily. + * + * Stack layout in 'ret_from_system_call': + * + * 0(%esp) - %eax + * 4(%esp) - %ebx + * 8(%esp) - %ecx + * C(%esp) - %edx + * 10(%esp) - %fs + * 14(%esp) - %es + * 18(%esp) - %ds + * 1C(%esp) - %eip + * 20(%esp) - %cs + * 24(%esp) - %eflags + * 28(%esp) - %oldesp + * 2C(%esp) - %oldss + */ + +SIG_CHLD = 17 + +EAX = 0x00 +EBX = 0x04 +ECX = 0x08 +EDX = 0x0C +FS = 0x10 +ES = 0x14 +DS = 0x18 +EIP = 0x1C +CS = 0x20 +EFLAGS = 0x24 +OLDESP = 0x28 +OLDSS = 0x2C + +state = 0 # these are offsets into the task-struct. +counter = 4 +priority = 8 +signal = 12 +sigaction = 16 # MUST be 16 (=len of sigaction) +blocked = (33*16) + +# offsets within sigaction +sa_handler = 0 +sa_mask = 4 +sa_flags = 8 +sa_restorer = 12 + +nr_system_calls = 72 + +/* + * Ok, I get parallel printer interrupts while using the floppy for some + * strange reason. Urgel. Now I just ignore them. + */ +.globl _system_call,_sys_fork,_timer_interrupt,_sys_execve +.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt +.globl _device_not_available, _coprocessor_error + +.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 + cmpw $0x0f,CS(%esp) # was old code segment supervisor ? + jne 3f + cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ? + jne 3f + movl signal(%eax),%ebx + movl blocked(%eax),%ecx + notl %ecx + andl %ebx,%ecx + bsfl %ecx,%ecx + je 3f + btrl %ecx,%ebx + movl %ebx,signal(%eax) + incl %ecx + pushl %ecx + call _do_signal + popl %eax +3: popl %eax + popl %ebx + popl %ecx + popl %edx + pop %fs + pop %es + pop %ds + iret + +.align 2 +_coprocessor_error: + push %ds + push %es + push %fs + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + pushl $ret_from_sys_call + jmp _math_error + +.align 2 +_device_not_available: + push %ds + push %es + push %fs + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + pushl $ret_from_sys_call + clts # clear TS so that we can use math + movl %cr0,%eax + testl $0x4,%eax # EM (math emulation bit) + je _math_state_restore + pushl %ebp + pushl %esi + pushl %edi + call _math_emulate + popl %edi + popl %esi + popl %ebp + ret + +.align 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,$0xA0 # EOI to interrupt controller #1 + jmp 1f # give port chance to breathe +1: jmp 1f +1: xorl %edx,%edx + xchgl _do_hd,%edx + testl %edx,%edx + jne 1f + movl $_unexpected_hd_interrupt,%edx +1: outb %al,$0x20 + call *%edx # "interesting" way of handling intr. + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +_floppy_interrupt: + pushl %eax + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + movb $0x20,%al + outb %al,$0x20 # EOI to interrupt controller #1 + xorl %eax,%eax + xchgl _do_floppy,%eax + testl %eax,%eax + jne 1f + movl $_unexpected_floppy_interrupt,%eax +1: call *%eax # "interesting" way of handling intr. + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +_parallel_interrupt: + pushl %eax + movb $0x20,%al + outb %al,$0x20 + popl %eax + iret diff --git a/kernel/0.1x/linux-0.11/kernel/traps.c b/kernel/0.1x/linux-0.11/kernel/traps.c new file mode 100644 index 00000000..bafdd87e --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/traps.c @@ -0,0 +1,208 @@ +/* + * linux/kernel/traps.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'asm.s'. Currently mostly a debugging-aid, will be extended + * to mainly kill the offending process (probably by giving it a signal, + * but possibly by killing it outright if necessary). + */ +#include + +#include +#include +#include +#include +#include +#include + +#define get_seg_byte(seg,addr) ({ \ +register char __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define get_seg_long(seg,addr) ({ \ +register unsigned long __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define _fs() ({ \ +register unsigned short __res; \ +__asm__("mov %%fs,%%ax":"=a" (__res):); \ +__res;}) + +int do_exit(long code); + +void page_exception(void); + +void divide_error(void); +void debug(void); +void nmi(void); +void int3(void); +void overflow(void); +void bounds(void); +void invalid_op(void); +void device_not_available(void); +void double_fault(void); +void coprocessor_segment_overrun(void); +void invalid_TSS(void); +void segment_not_present(void); +void stack_segment(void); +void general_protection(void); +void page_fault(void); +void coprocessor_error(void); +void reserved(void); +void parallel_interrupt(void); +void irq13(void); + +static void die(char * str,long esp_ptr,long nr) +{ + long * esp = (long *) esp_ptr; + int i; + + printk("%s: %04x\n\r",str,nr&0xffff); + printk("EIP:\t%04x:%p\nEFLAGS:\t%p\nESP:\t%04x:%p\n", + esp[1],esp[0],esp[2],esp[4],esp[3]); + printk("fs: %04x\n",_fs()); + printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x17)); + if (esp[4] == 0x17) { + printk("Stack: "); + for (i=0;i<4;i++) + printk("%p ",get_seg_long(0x17,i+(long *)esp[3])); + printk("\n"); + } + str(i); + printk("Pid: %d, process nr: %d\n\r",current->pid,0xffff & i); + for(i=0;i<10;i++) + printk("%02x ",0xff & get_seg_byte(esp[1],(i+(char *)esp[0]))); + printk("\n\r"); + do_exit(11); /* play segment exception */ +} + +void do_double_fault(long esp, long error_code) +{ + die("double fault",esp,error_code); +} + +void do_general_protection(long esp, long error_code) +{ + die("general protection",esp,error_code); +} + +void do_divide_error(long esp, long error_code) +{ + die("divide error",esp,error_code); +} + +void do_int3(long * esp, long error_code, + long fs,long es,long ds, + long ebp,long esi,long edi, + long edx,long ecx,long ebx,long eax) +{ + int tr; + + __asm__("str %%ax":"=a" (tr):"0" (0)); + printk("eax\t\tebx\t\tecx\t\tedx\n\r%8x\t%8x\t%8x\t%8x\n\r", + eax,ebx,ecx,edx); + printk("esi\t\tedi\t\tebp\t\tesp\n\r%8x\t%8x\t%8x\t%8x\n\r", + esi,edi,ebp,(long) esp); + printk("\n\rds\tes\tfs\ttr\n\r%4x\t%4x\t%4x\t%4x\n\r", + ds,es,fs,tr); + printk("EIP: %8x CS: %4x EFLAGS: %8x\n\r",esp[0],esp[1],esp[2]); +} + +void do_nmi(long esp, long error_code) +{ + die("nmi",esp,error_code); +} + +void do_debug(long esp, long error_code) +{ + die("debug",esp,error_code); +} + +void do_overflow(long esp, long error_code) +{ + die("overflow",esp,error_code); +} + +void do_bounds(long esp, long error_code) +{ + die("bounds",esp,error_code); +} + +void do_invalid_op(long esp, long error_code) +{ + die("invalid operand",esp,error_code); +} + +void do_device_not_available(long esp, long error_code) +{ + die("device not available",esp,error_code); +} + +void do_coprocessor_segment_overrun(long esp, long error_code) +{ + die("coprocessor segment overrun",esp,error_code); +} + +void do_invalid_TSS(long esp,long error_code) +{ + die("invalid TSS",esp,error_code); +} + +void do_segment_not_present(long esp,long error_code) +{ + die("segment not present",esp,error_code); +} + +void do_stack_segment(long esp,long error_code) +{ + die("stack segment",esp,error_code); +} + +void do_coprocessor_error(long esp, long error_code) +{ + if (last_task_used_math != current) + return; + die("coprocessor error",esp,error_code); +} + +void do_reserved(long esp, long error_code) +{ + die("reserved (15,17-47) error",esp,error_code); +} + +void trap_init(void) +{ + int i; + + set_trap_gate(0,÷_error); + set_trap_gate(1,&debug); + set_trap_gate(2,&nmi); + set_system_gate(3,&int3); /* int3-5 can be called from all */ + set_system_gate(4,&overflow); + set_system_gate(5,&bounds); + set_trap_gate(6,&invalid_op); + set_trap_gate(7,&device_not_available); + set_trap_gate(8,&double_fault); + set_trap_gate(9,&coprocessor_segment_overrun); + set_trap_gate(10,&invalid_TSS); + set_trap_gate(11,&segment_not_present); + set_trap_gate(12,&stack_segment); + set_trap_gate(13,&general_protection); + set_trap_gate(14,&page_fault); + set_trap_gate(15,&reserved); + set_trap_gate(16,&coprocessor_error); + for (i=17;i<48;i++) + set_trap_gate(i,&reserved); + set_trap_gate(45,&irq13); + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xdf,0xA1); + set_trap_gate(39,¶llel_interrupt); +} diff --git a/kernel/0.1x/linux-0.11/kernel/vsprintf.c b/kernel/0.1x/linux-0.11/kernel/vsprintf.c new file mode 100644 index 00000000..9bfd010b --- /dev/null +++ b/kernel/0.1x/linux-0.11/kernel/vsprintf.c @@ -0,0 +1,233 @@ +/* + * linux/kernel/vsprintf.c + * + * (C) 1991 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include +#include + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ + +#define do_div(n,base) ({ \ +int __res; \ +__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ +__res; }) + +static char * number(char * str, int num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[36]; + const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + + if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; + if (type&LEFT) type &= ~ZEROPAD; + if (base<2 || base>36) + return 0; + c = (type & ZEROPAD) ? '0' : ' ' ; + if (type&SIGN && num<0) { + sign='-'; + num = -num; + } else + sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); + if (sign) size--; + if (type&SPECIAL) + if (base==16) size -= 2; + else if (base==8) size--; + i=0; + if (num==0) + tmp[i++]='0'; + else while (num!=0) + tmp[i++]=digits[do_div(num,base)]; + if (i>precision) precision=i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type&SPECIAL) + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + if (!(type&LEFT)) + while(size-->0) + *str++ = c; + while(i0) + *str++ = tmp[i]; + while(size-->0) + *str++ = ' '; + return str; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + int i; + char * str; + char *s; + int *ip; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + break; + + case 's': + s = va_arg(args, char *); + len = strlen(s); + if (precision < 0) + precision = len; + else if (len > precision) + len = precision; + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + break; + + case 'o': + str = number(str, va_arg(args, unsigned long), 8, + field_width, precision, flags); + break; + + case 'p': + if (field_width == -1) { + field_width = 8; + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + break; + + case 'x': + flags |= SMALL; + case 'X': + str = number(str, va_arg(args, unsigned long), 16, + field_width, precision, flags); + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + str = number(str, va_arg(args, unsigned long), 10, + field_width, precision, flags); + break; + + case 'n': + ip = va_arg(args, int *); + *ip = (str - buf); + break; + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + break; + } + } + *str = '\0'; + return str-buf; +} diff --git a/kernel/0.1x/linux-0.11/lib/Makefile b/kernel/0.1x/linux-0.11/lib/Makefile new file mode 100644 index 00000000..2bf36663 --- /dev/null +++ b/kernel/0.1x/linux-0.11/lib/Makefile @@ -0,0 +1,73 @@ +# +# Makefile for some libs needed in the kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =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 malloc.o + +lib.a: $(OBJS) + $(AR) rcs lib.a $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +_exit.s _exit.o : _exit.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +close.s close.o : close.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +ctype.s ctype.o : ctype.c ../include/ctype.h +dup.s dup.o : dup.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +errno.s errno.o : errno.c +execve.s execve.o : execve.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +malloc.s malloc.o : malloc.c ../include/linux/kernel.h ../include/linux/mm.h \ + ../include/asm/system.h +open.s open.o : open.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h ../include/stdarg.h +setsid.s setsid.o : setsid.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +string.s string.o : string.c ../include/string.h +wait.s wait.o : wait.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h ../include/sys/wait.h +write.s write.o : write.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h diff --git a/kernel/0.1x/linux-0.11/lib/_exit.c b/kernel/0.1x/linux-0.11/lib/_exit.c new file mode 100644 index 00000000..50f1c8fa --- /dev/null +++ b/kernel/0.1x/linux-0.11/lib/_exit.c @@ -0,0 +1,13 @@ +/* + * linux/lib/_exit.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +volatile void _exit(int exit_code) +{ + __asm__("int $0x80"::"a" (__NR_exit),"b" (exit_code)); +} diff --git a/kernel/0.1x/linux-0.11/lib/close.c b/kernel/0.1x/linux-0.11/lib/close.c new file mode 100644 index 00000000..98e5ceee --- /dev/null +++ b/kernel/0.1x/linux-0.11/lib/close.c @@ -0,0 +1,10 @@ +/* + * linux/lib/close.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall1(int,close,int,fd) diff --git a/kernel/0.1x/linux-0.11/lib/ctype.c b/kernel/0.1x/linux-0.11/lib/ctype.c new file mode 100644 index 00000000..9ac21819 --- /dev/null +++ b/kernel/0.1x/linux-0.11/lib/ctype.c @@ -0,0 +1,35 @@ +/* + * linux/lib/ctype.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +char _ctmp; +unsigned char _ctype[] = {0x00, /* EOF */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */ + diff --git a/kernel/0.1x/linux-0.11/lib/dup.c b/kernel/0.1x/linux-0.11/lib/dup.c new file mode 100644 index 00000000..d56d6d07 --- /dev/null +++ b/kernel/0.1x/linux-0.11/lib/dup.c @@ -0,0 +1,10 @@ +/* + * linux/lib/dup.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall1(int,dup,int,fd) diff --git a/kernel/0.1x/linux-0.11/lib/errno.c b/kernel/0.1x/linux-0.11/lib/errno.c new file mode 100644 index 00000000..b6d10473 --- /dev/null +++ b/kernel/0.1x/linux-0.11/lib/errno.c @@ -0,0 +1,7 @@ +/* + * linux/lib/errno.c + * + * (C) 1991 Linus Torvalds + */ + +int errno; diff --git a/kernel/0.1x/linux-0.11/lib/execve.c b/kernel/0.1x/linux-0.11/lib/execve.c new file mode 100644 index 00000000..67f22cb0 --- /dev/null +++ b/kernel/0.1x/linux-0.11/lib/execve.c @@ -0,0 +1,10 @@ +/* + * linux/lib/execve.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall3(int,execve,const char *,file,char **,argv,char **,envp) diff --git a/kernel/0.1x/linux-0.11/lib/malloc.c b/kernel/0.1x/linux-0.11/lib/malloc.c new file mode 100644 index 00000000..d3df5519 --- /dev/null +++ b/kernel/0.1x/linux-0.11/lib/malloc.c @@ -0,0 +1,232 @@ +/* + * malloc.c --- a general purpose kernel memory allocator for Linux. + * + * Written by Theodore Ts'o (tytso@mit.edu), 11/29/91 + * + * This routine is written to be as fast as possible, so that it + * can be called from the interrupt level. + * + * Limitations: maximum size of memory we can allocate using this routine + * is 4k, the size of a page in Linux. + * + * The general game plan is that each page (called a bucket) will only hold + * objects of a given size. When all of the object on a page are released, + * the page can be returned to the general free pool. When malloc() is + * called, it looks for the smallest bucket size which will fulfill its + * request, and allocate a piece of memory from that bucket pool. + * + * Each bucket has as its control block a bucket descriptor which keeps + * track of how many objects are in use on that page, and the free list + * for that page. Like the buckets themselves, bucket descriptors are + * stored on pages requested from get_free_page(). However, unlike buckets, + * pages devoted to bucket descriptor pages are never released back to the + * system. Fortunately, a system should probably only need 1 or 2 bucket + * descriptor pages, since a page can hold 256 bucket descriptors (which + * corresponds to 1 megabyte worth of bucket pages.) If the kernel is using + * that much allocated memory, it's probably doing something wrong. :-) + * + * Note: malloc() and free() both call get_free_page() and free_page() + * in sections of code where interrupts are turned off, to allow + * malloc() and free() to be safely called from an interrupt routine. + * (We will probably need this functionality when networking code, + * particularily things like NFS, is added to Linux.) However, this + * presumes that get_free_page() and free_page() are interrupt-level + * safe, which they may not be once paging is added. If this is the + * case, we will need to modify malloc() to keep a few unused pages + * "pre-allocated" so that it can safely draw upon those pages if + * it is called from an interrupt routine. + * + * Another concern is that get_free_page() should not sleep; if it + * does, the code is carefully ordered so as to avoid any race + * conditions. The catch is that if malloc() is called re-entrantly, + * there is a chance that unecessary pages will be grabbed from the + * system. Except for the pages for the bucket descriptor page, the + * extra pages will eventually get released back to the system, though, + * so it isn't all that bad. + */ + +#include +#include +#include + +struct bucket_desc { /* 16 bytes */ + void *page; + struct bucket_desc *next; + void *freeptr; + unsigned short refcnt; + unsigned short bucket_size; +}; + +struct _bucket_dir { /* 8 bytes */ + int size; + struct bucket_desc *chain; +}; + +/* + * The following is the where we store a pointer to the first bucket + * descriptor for a given size. + * + * If it turns out that the Linux kernel allocates a lot of objects of a + * specific size, then we may want to add that specific size to this list, + * since that will allow the memory to be allocated more efficiently. + * However, since an entire page must be dedicated to each specific size + * on this list, some amount of temperance must be exercised here. + * + * Note that this list *must* be kept in order. + */ +struct _bucket_dir bucket_dir[] = { + { 16, (struct bucket_desc *) 0}, + { 32, (struct bucket_desc *) 0}, + { 64, (struct bucket_desc *) 0}, + { 128, (struct bucket_desc *) 0}, + { 256, (struct bucket_desc *) 0}, + { 512, (struct bucket_desc *) 0}, + { 1024, (struct bucket_desc *) 0}, + { 2048, (struct bucket_desc *) 0}, + { 4096, (struct bucket_desc *) 0}, + { 0, (struct bucket_desc *) 0}}; /* End of list marker */ + +/* + * This contains a linked list of free bucket descriptor blocks + */ +struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0; + +/* + * This routine initializes a bucket description page. + */ +static inline void init_bucket_desc() +{ + struct bucket_desc *bdesc, *first; + int i; + + first = bdesc = (struct bucket_desc *) get_free_page(); + if (!bdesc) + panic("Out of memory in init_bucket_desc()"); + for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) { + bdesc->next = bdesc+1; + bdesc++; + } + /* + * This is done last, to avoid race conditions in case + * get_free_page() sleeps and this routine gets called again.... + */ + bdesc->next = free_bucket_desc; + free_bucket_desc = first; +} + +void *malloc(unsigned int len) +{ + struct _bucket_dir *bdir; + struct bucket_desc *bdesc; + void *retval; + + /* + * First we search the bucket_dir to find the right bucket change + * for this request. + */ + for (bdir = bucket_dir; bdir->size; bdir++) + if (bdir->size >= len) + break; + if (!bdir->size) { + printk("malloc called with impossibly large argument (%d)\n", + len); + panic("malloc: bad arg"); + } + /* + * Now we search for a bucket descriptor which has free space + */ + cli(); /* Avoid race conditions */ + for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) + if (bdesc->freeptr) + break; + /* + * If we didn't find a bucket with free space, then we'll + * allocate a new one. + */ + if (!bdesc) { + char *cp; + int i; + + if (!free_bucket_desc) + init_bucket_desc(); + bdesc = free_bucket_desc; + free_bucket_desc = bdesc->next; + bdesc->refcnt = 0; + bdesc->bucket_size = bdir->size; + bdesc->page = bdesc->freeptr = (void *) cp = get_free_page(); + if (!cp) + panic("Out of memory in kernel malloc()"); + /* Set up the chain of free objects */ + for (i=PAGE_SIZE/bdir->size; i > 1; i--) { + *((char **) cp) = cp + bdir->size; + cp += bdir->size; + } + *((char **) cp) = 0; + bdesc->next = bdir->chain; /* OK, link it in! */ + bdir->chain = bdesc; + } + retval = (void *) bdesc->freeptr; + bdesc->freeptr = *((void **) retval); + bdesc->refcnt++; + sti(); /* OK, we're safe again */ + return(retval); +} + +/* + * Here is the free routine. If you know the size of the object that you + * are freeing, then free_s() will use that information to speed up the + * search for the bucket descriptor. + * + * We will #define a macro so that "free(x)" is becomes "free_s(x, 0)" + */ +void free_s(void *obj, int size) +{ + void *page; + struct _bucket_dir *bdir; + struct bucket_desc *bdesc, *prev; + + /* Calculate what page this object lives in */ + page = (void *) ((unsigned long) obj & 0xfffff000); + /* Now search the buckets looking for that page */ + for (bdir = bucket_dir; bdir->size; bdir++) { + prev = 0; + /* If size is zero then this conditional is always false */ + if (bdir->size < size) + continue; + for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) { + if (bdesc->page == page) + goto found; + prev = bdesc; + } + } + panic("Bad address passed to kernel free_s()"); +found: + cli(); /* To avoid race conditions */ + *((void **)obj) = bdesc->freeptr; + bdesc->freeptr = obj; + bdesc->refcnt--; + if (bdesc->refcnt == 0) { + /* + * We need to make sure that prev is still accurate. It + * may not be, if someone rudely interrupted us.... + */ + if ((prev && (prev->next != bdesc)) || + (!prev && (bdir->chain != bdesc))) + for (prev = bdir->chain; prev; prev = prev->next) + if (prev->next == bdesc) + break; + if (prev) + prev->next = bdesc->next; + else { + if (bdir->chain != bdesc) + panic("malloc bucket chains corrupted"); + bdir->chain = bdesc->next; + } + free_page((unsigned long) bdesc->page); + bdesc->next = free_bucket_desc; + free_bucket_desc = bdesc; + } + sti(); + return; +} + diff --git a/kernel/0.1x/linux-0.11/lib/open.c b/kernel/0.1x/linux-0.11/lib/open.c new file mode 100644 index 00000000..9b95a8f3 --- /dev/null +++ b/kernel/0.1x/linux-0.11/lib/open.c @@ -0,0 +1,25 @@ +/* + * linux/lib/open.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +int open(const char * filename, int flag, ...) +{ + register int res; + va_list arg; + + va_start(arg,flag); + __asm__("int $0x80" + :"=a" (res) + :"0" (__NR_open),"b" (filename),"c" (flag), + "d" (va_arg(arg,int))); + if (res>=0) + return res; + errno = -res; + return -1; +} diff --git a/kernel/0.1x/linux-0.11/lib/setsid.c b/kernel/0.1x/linux-0.11/lib/setsid.c new file mode 100644 index 00000000..b47a358f --- /dev/null +++ b/kernel/0.1x/linux-0.11/lib/setsid.c @@ -0,0 +1,10 @@ +/* + * linux/lib/setsid.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall0(pid_t,setsid) diff --git a/kernel/0.1x/linux-0.11/lib/string.c b/kernel/0.1x/linux-0.11/lib/string.c new file mode 100644 index 00000000..e4ef9257 --- /dev/null +++ b/kernel/0.1x/linux-0.11/lib/string.c @@ -0,0 +1,14 @@ +/* + * linux/lib/string.c + * + * (C) 1991 Linus Torvalds + */ + +#ifndef __GNUC__ +#error I want gcc! +#endif + +#define extern +#define inline +#define __LIBRARY__ +#include diff --git a/kernel/0.1x/linux-0.11/lib/wait.c b/kernel/0.1x/linux-0.11/lib/wait.c new file mode 100644 index 00000000..72f27313 --- /dev/null +++ b/kernel/0.1x/linux-0.11/lib/wait.c @@ -0,0 +1,16 @@ +/* + * linux/lib/wait.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +_syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) + +pid_t wait(int * wait_stat) +{ + return waitpid(-1,wait_stat,0); +} diff --git a/kernel/0.1x/linux-0.11/lib/write.c b/kernel/0.1x/linux-0.11/lib/write.c new file mode 100644 index 00000000..68ea9cf9 --- /dev/null +++ b/kernel/0.1x/linux-0.11/lib/write.c @@ -0,0 +1,10 @@ +/* + * linux/lib/write.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall3(int,write,int,fd,const char *,buf,off_t,count) diff --git a/kernel/0.1x/linux-0.11/mm/Makefile b/kernel/0.1x/linux-0.11/mm/Makefile new file mode 100644 index 00000000..14f11f9e --- /dev/null +++ b/kernel/0.1x/linux-0.11/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/asm/system.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h diff --git a/kernel/0.1x/linux-0.11/mm/memory.c b/kernel/0.1x/linux-0.11/mm/memory.c new file mode 100644 index 00000000..9e7e8dba --- /dev/null +++ b/kernel/0.1x/linux-0.11/mm/memory.c @@ -0,0 +1,430 @@ +/* + * linux/mm/memory.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * demand-loading started 01.12.91 - seems it is high on the list of + * things wanted, and it should be easy to implement. - Linus + */ + +/* + * Ok, demand-loading was easy, shared pages a little bit tricker. Shared + * pages started 02.12.91, seems to work. - Linus. + * + * Tested sharing by executing about 30 /bin/sh: under the old kernel it + * would have taken more than the 6M I have free, but it worked well as + * far as I could see. + * + * Also corrected some "invalidate()"s - I wasn't doing enough of them. + */ + +#include + +#include + +#include +#include +#include + +volatile void do_exit(long code); + +static inline volatile void oom(void) +{ + printk("out of memory\n\r"); + do_exit(SIGSEGV); +} + +#define invalidate() \ +__asm__("movl %%eax,%%cr3"::"a" (0)) + +/* these are not to be changed without changing head.s etc */ +#define LOW_MEM 0x100000 +#define PAGING_MEMORY (15*1024*1024) +#define PAGING_PAGES (PAGING_MEMORY>>12) +#define MAP_NR(addr) (((addr)-LOW_MEM)>>12) +#define USED 100 + +#define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \ +current->start_code + current->end_code) + +static long HIGH_MEMORY = 0; + +#define copy_page(from,to) \ +__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si") + +static unsigned char mem_map [ PAGING_PAGES ] = {0,}; + +/* + * Get physical address of first (actually last :-) free page, and mark it + * used. If no free pages left, return 0. + */ +unsigned long get_free_page(void) +{ +register unsigned long __res asm("ax"); + +__asm__("std ; repne ; scasb\n\t" + "jne 1f\n\t" + "movb $1,1(%%edi)\n\t" + "sall $12,%%ecx\n\t" + "addl %2,%%ecx\n\t" + "movl %%ecx,%%edx\n\t" + "movl $1024,%%ecx\n\t" + "leal 4092(%%edx),%%edi\n\t" + "rep ; stosl\n\t" + "movl %%edx,%%eax\n" + "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; +/* no need for invalidate */ + return page; +} + +void un_wp_page(unsigned long * table_entry) +{ + unsigned long old_page,new_page; + + old_page = 0xfffff000 & *table_entry; + if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) { + *table_entry |= 2; + invalidate(); + return; + } + if (!(new_page=get_free_page())) + oom(); + if (old_page >= LOW_MEM) + mem_map[MAP_NR(old_page)]--; + *table_entry = new_page | 7; + invalidate(); + copy_page(old_page,new_page); +} + +/* + * This routine handles present pages, when users try to write + * to a shared page. It is done by copying the page to a new address + * and decrementing the shared-page counter for the old page. + * + * If it's in code space we exit with a segment error. + */ +void do_wp_page(unsigned long error_code,unsigned long address) +{ +#if 0 +/* we cannot do this yet: the estdio library writes to code space */ +/* stupid, stupid. I really want the libc.a from GNU */ + if (CODE_SPACE(address)) + do_exit(SIGSEGV); +#endif + un_wp_page((unsigned long *) + (((address>>10) & 0xffc) + (0xfffff000 & + *((unsigned long *) ((address>>20) &0xffc))))); + +} + +void write_verify(unsigned long address) +{ + unsigned long page; + + if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1)) + return; + page &= 0xfffff000; + page += ((address>>10) & 0xffc); + if ((3 & *(unsigned long *) page) == 1) /* non-writeable, present */ + un_wp_page((unsigned long *) page); + return; +} + +void get_empty_page(unsigned long address) +{ + unsigned long tmp; + + if (!(tmp=get_free_page()) || !put_page(tmp,address)) { + free_page(tmp); /* 0 is ok - ignored */ + oom(); + } +} + +/* + * try_to_share() checks the page at address "address" in the task "p", + * to see if it exists, and if it is clean. If so, share it with the current + * task. + * + * NOTE! This assumes we have checked that p != current, and that they + * share the same executable. + */ +static int try_to_share(unsigned long address, struct task_struct * p) +{ + unsigned long from; + unsigned long to; + unsigned long from_page; + unsigned long to_page; + unsigned long phys_addr; + + from_page = to_page = ((address>>20) & 0xffc); + from_page += ((p->start_code>>20) & 0xffc); + to_page += ((current->start_code>>20) & 0xffc); +/* is there a page-directory at from? */ + from = *(unsigned long *) from_page; + if (!(from & 1)) + return 0; + from &= 0xfffff000; + from_page = from + ((address>>10) & 0xffc); + phys_addr = *(unsigned long *) from_page; +/* is the page clean and present? */ + if ((phys_addr & 0x41) != 0x01) + return 0; + phys_addr &= 0xfffff000; + if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM) + return 0; + to = *(unsigned long *) to_page; + if (!(to & 1)) + if (to = get_free_page()) + *(unsigned long *) to_page = to | 7; + else + oom(); + to &= 0xfffff000; + to_page = to + ((address>>10) & 0xffc); + if (1 & *(unsigned long *) to_page) + panic("try_to_share: to_page already exists"); +/* share them: write-protect */ + *(unsigned long *) from_page &= ~2; + *(unsigned long *) to_page = *(unsigned long *) from_page; + invalidate(); + phys_addr -= LOW_MEM; + phys_addr >>= 12; + mem_map[phys_addr]++; + return 1; +} + +/* + * share_page() tries to find a process that could share a page with + * the current one. Address is the address of the wanted page relative + * to the current data space. + * + * We first check if it is at all feasible by checking executable->i_count. + * It should be >1 if there are other tasks sharing this inode. + */ +static int share_page(unsigned long address) +{ + struct task_struct ** p; + + if (!current->executable) + return 0; + if (current->executable->i_count < 2) + return 0; + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if (!*p) + continue; + if (current == *p) + continue; + if ((*p)->executable != current->executable) + continue; + if (try_to_share(address,*p)) + return 1; + } + return 0; +} + +void do_no_page(unsigned long error_code,unsigned long address) +{ + int nr[4]; + unsigned long tmp; + unsigned long page; + int block,i; + + address &= 0xfffff000; + tmp = address - current->start_code; + if (!current->executable || tmp >= current->end_data) { + get_empty_page(address); + return; + } + if (share_page(tmp)) + return; + if (!(page = get_free_page())) + oom(); +/* remember that 1 block is used for header */ + block = 1 + tmp/BLOCK_SIZE; + for (i=0 ; i<4 ; block++,i++) + nr[i] = bmap(current->executable,block); + bread_page(page,current->executable->i_dev,nr); + i = tmp + 4096 - current->end_data; + tmp = page + 4096; + while (i-- > 0) { + tmp--; + *(char *)tmp = 0; + } + if (put_page(page,address)) + return; + free_page(page); + oom(); +} + +void mem_init(long start_mem, long end_mem) +{ + int i; + + HIGH_MEMORY = end_mem; + for (i=0 ; i>= 12; + while (end_mem-->0) + mem_map[i++]=0; +} + +void calc_mem(void) +{ + int i,j,k,free=0; + long * pg_tbl; + + for(i=0 ; i /* fprintf */ +#include +#include /* contains exit */ +#include /* unistd.h needs this */ +#include +#include +#include /* contains read/write */ +#include + +#define MINIX_HEADER 32 +#define GCC_HEADER 1024 + +#define SYS_SIZE 0x2000 + +#define DEFAULT_MAJOR_ROOT 3 +#define DEFAULT_MINOR_ROOT 6 + +/* max nr of sectors of setup: don't change unless you also change + * bootsect etc */ +#define SETUP_SECTS 4 + +#define STRINGIFY(x) #x + +void die(char * str) +{ + fprintf(stderr,"%s\n",str); + exit(1); +} + +void usage(void) +{ + die("Usage: build bootsect setup system [rootdev] [> image]"); +} + +int main(int argc, char ** argv) +{ + int i,c,id; + char buf[1024]; + char major_root, minor_root; + struct stat sb; + + if ((argc != 4) && (argc != 5)) + usage(); + if (argc == 5) { + if (strcmp(argv[4], "FLOPPY")) { + if (stat(argv[4], &sb)) { + perror(argv[4]); + die("Couldn't stat root device."); + } + major_root = MAJOR(sb.st_rdev); + minor_root = MINOR(sb.st_rdev); + } else { + major_root = 0; + minor_root = 0; + } + } else { + major_root = DEFAULT_MAJOR_ROOT; + minor_root = DEFAULT_MINOR_ROOT; + } + fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); + if ((major_root != 2) && (major_root != 3) && + (major_root != 0)) { + fprintf(stderr, "Illegal root device (major = %d)\n", + major_root); + die("Bad root device --- major #"); + } + for (i=0;i0 ; i+=c ) + if (write(1,buf,c)!=c) + die("Write call failed"); + close (id); + if (i > SETUP_SECTS*512) + die("Setup exceeds " STRINGIFY(SETUP_SECTS) + " sectors - rewrite build/boot/setup"); + fprintf(stderr,"Setup is %d bytes.\n",i); + for (c=0 ; c sizeof(buf)) + c = sizeof(buf); + if (write(1,buf,c) != c) + die("Write call failed"); + i += c; + } + + if ((id=open(argv[3],O_RDONLY,0))<0) + die("Unable to open 'system'"); + if (read(id,buf,GCC_HEADER) != GCC_HEADER) + die("Unable to read header of 'system'"); + if (((long *) buf)[5] != 0) + die("Non-GCC header of 'system'"); + for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c ) + if (write(1,buf,c)!=c) + die("Write call failed"); + close(id); + fprintf(stderr,"System is %d bytes.\n",i); + if (i > SYS_SIZE*16) + die("System is too big"); + return(0); +} diff --git a/kernel/0.1x/linux-0.12.tar b/kernel/0.1x/linux-0.12.tar new file mode 100644 index 00000000..1217d26d Binary files /dev/null and b/kernel/0.1x/linux-0.12.tar differ diff --git a/kernel/0.1x/linux-0.12.tar.gz b/kernel/0.1x/linux-0.12.tar.gz new file mode 100644 index 00000000..e6d9969b Binary files /dev/null and b/kernel/0.1x/linux-0.12.tar.gz differ diff --git a/kernel/0.1x/linux-0.12/Makefile b/kernel/0.1x/linux-0.12/Makefile new file mode 100644 index 00000000..08a805ec --- /dev/null +++ b/kernel/0.1x/linux-0.12/Makefile @@ -0,0 +1,129 @@ +# +# if you want the ram-disk device, define this to be the +# size in blocks. +# +RAMDISK = #-DRAMDISK=512 + +AS86 =as86 -0 -a +LD86 =ld86 -0 + +AS =gas +LD =gld +LDFLAGS =-s -x -M +CC =gcc $(RAMDISK) +CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ +-fcombine-regs -mstring-insns +CPP =cpp -nostdinc -Iinclude + +# +# ROOT_DEV specifies the default root-device when making the image. +# This can be either FLOPPY, /dev/xxxx or empty, in which case the +# default of /dev/hd6 is used by 'build'. +# +ROOT_DEV=/dev/hd6 +SWAP_DEV=/dev/hd2 + +ARCHIVES=kernel/kernel.o mm/mm.o fs/fs.o +DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a +MATH =kernel/math/math.a +LIBS =lib/lib.a + +.c.s: + $(CC) $(CFLAGS) \ + -nostdinc -Iinclude -S -o $*.s $< +.s.o: + $(AS) -c -o $*.o $< +.c.o: + $(CC) $(CFLAGS) \ + -nostdinc -Iinclude -c -o $*.o $< + +all: Image + +Image: boot/bootsect boot/setup tools/system tools/build + tools/build boot/bootsect boot/setup tools/system $(ROOT_DEV) \ + $(SWAP_DEV) > Image + sync + +disk: Image + dd bs=8192 if=Image of=/dev/PS0 + +tools/build: tools/build.c + $(CC) $(CFLAGS) \ + -o tools/build tools/build.c + +boot/head.o: boot/head.s + +tools/system: boot/head.o init/main.o \ + $(ARCHIVES) $(DRIVERS) $(MATH) $(LIBS) + $(LD) $(LDFLAGS) boot/head.o init/main.o \ + $(ARCHIVES) \ + $(DRIVERS) \ + $(MATH) \ + $(LIBS) \ + -o tools/system > System.map + +kernel/math/math.a: + (cd kernel/math; make) + +kernel/blk_drv/blk_drv.a: + (cd kernel/blk_drv; make) + +kernel/chr_drv/chr_drv.a: + (cd kernel/chr_drv; make) + +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/setup: boot/setup.s + $(AS86) -o boot/setup.o boot/setup.s + $(LD86) -s -o boot/setup boot/setup.o + +boot/setup.s: boot/setup.S include/linux/config.h + $(CPP) -traditional boot/setup.S -o boot/setup.s + +boot/bootsect.s: boot/bootsect.S include/linux/config.h + $(CPP) -traditional boot/bootsect.S -o boot/bootsect.s + +boot/bootsect: boot/bootsect.s + $(AS86) -o boot/bootsect.o boot/bootsect.s + $(LD86) -s -o boot/bootsect boot/bootsect.o + +clean: + rm -f Image System.map tmp_make core boot/bootsect boot/setup \ + boot/bootsect.s boot/setup.s + rm -f init/*.o tools/system tools/build boot/*.o + (cd mm;make clean) + (cd fs;make clean) + (cd kernel;make clean) + (cd lib;make clean) + +backup: clean + (cd .. ; tar cf - linux | compress - > 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/time.h include/time.h include/sys/times.h \ + include/sys/utsname.h include/sys/param.h include/sys/resource.h \ + include/utime.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/linux/kernel.h include/signal.h include/asm/system.h \ + include/asm/io.h include/stddef.h include/stdarg.h include/fcntl.h \ + include/string.h diff --git a/kernel/0.1x/linux-0.12/boot/bootsect.S b/kernel/0.1x/linux-0.12/boot/bootsect.S new file mode 100644 index 00000000..dc0806c9 --- /dev/null +++ b/kernel/0.1x/linux-0.12/boot/bootsect.S @@ -0,0 +1,404 @@ +! +! SYS_SIZE is the number of clicks (16 bytes) to be loaded. +! 0x3000 is 0x30000 bytes = 196kB, more than enough for current +! versions of linux +! +#include +SYSSIZE = DEF_SYSSIZE +! +! bootsect.s (C) 1991 Linus Torvalds +! modified by Drew Eckhardt +! +! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves +! iself out of the way to address 0x90000, and jumps there. +! +! It then loads 'setup' directly after itself (0x90200), and the system +! at 0x10000, using BIOS interrupts. +! +! NOTE! currently system is at most 8*65536 bytes long. This should be no +! problem, even in the future. I want to keep it simple. This 512 kB +! kernel size should be enough, especially as this doesn't contain the +! buffer cache as in minix +! +! The loader has been made as simple as possible, and continuos +! read errors will result in a unbreakable loop. Reboot by hand. It +! loads pretty fast by getting whole sectors at a time whenever possible. + +.globl begtext, begdata, begbss, endtext, enddata, endbss +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +SETUPLEN = 4 ! nr of setup-sectors +BOOTSEG = 0x07c0 ! original address of boot-sector +INITSEG = DEF_INITSEG ! we move boot here - out of the way +SETUPSEG = DEF_SETUPSEG ! setup starts here +SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). +ENDSEG = SYSSEG + SYSSIZE ! where to stop loading + +! ROOT_DEV & SWAP_DEV are now written by "build". +ROOT_DEV = 0 +SWAP_DEV = 0 + +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 dx,#0xfef4 ! arbitrary value >>512 - disk parm size + + mov ds,ax + mov es,ax + push ax + + mov ss,ax ! put stack at 0x9ff00 - 12. + mov sp,dx +/* + * Many BIOS's default disk parameter tables will not + * recognize multi-sector reads beyond the maximum sector number + * specified in the default diskette parameter tables - this may + * mean 7 sectors in some cases. + * + * Since single sector reads are slow and out of the question, + * we must take care of this by creating new parameter tables + * (for the first disk) in RAM. We will set the maximum sector + * count to 18 - the most we will encounter on an HD 1.44. + * + * High doesn't hurt. Low does. + * + * Segments are as follows: ds=es=ss=cs - INITSEG, + * fs = 0, gs = parameter table segment + */ + + + push #0 + pop fs + mov bx,#0x78 ! fs:bx is parameter table address + seg fs + lgs si,(bx) ! gs:si is source + + mov di,dx ! es:di is destination + mov cx,#6 ! copy 12 bytes + cld + + rep + seg gs + movw + + mov di,dx + movb 4(di),*18 ! patch sector count + + seg fs + mov (bx),di + seg fs + mov 2(bx),es + + pop ax + mov fs,ax + mov gs,ax + + xor ah,ah ! reset FDC + xor dl,dl + int 0x13 + +! load the setup-sectors directly after the bootblock. +! Note that 'es' is already set up. + +load_setup: + xor dx, dx ! drive 0, head 0 + mov cx,#0x0002 ! sector 2, track 0 + mov bx,#0x0200 ! address = 512, in INITSEG + mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors + int 0x13 ! read it + jnc ok_load_setup ! ok - continue + + push ax ! dump error code + call print_nl + mov bp, sp + call print_hex + pop ax + + xor dl, dl ! reset FDC + xor ah, ah + int 0x13 + j load_setup + +ok_load_setup: + +! Get disk drive parameters, specifically nr of sectors/track + + xor dl,dl + mov ah,#0x08 ! AH=8 is get drive parameters + int 0x13 + xor ch,ch + seg cs + mov sectors,cx + mov ax,#INITSEG + mov es,ax + +! Print some inane message + + mov ah,#0x03 ! read cursor pos + xor bh,bh + int 0x10 + + mov cx,#9 + 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 + call print_nl + +! After that we check which root-device to use. If the device is +! defined (!= 0), nothing is done and the given device is used. +! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending +! on the number of sectors that the BIOS reports currently. + + seg cs + mov ax,root_dev + or ax,ax + jne root_defined + seg cs + mov bx,sectors + mov ax,#0x0208 ! /dev/ps0 - 1.2Mb + cmp bx,#15 + je root_defined + mov ax,#0x021c ! /dev/PS0 - 1.44Mb + cmp bx,#18 + je root_defined +undef_root: + jmp undef_root +root_defined: + seg cs + mov root_dev,ax + +! after that (everyting loaded), we jump to +! the setup-routine loaded directly after +! the bootblock: + + jmpi 0,SETUPSEG + +! This routine loads the system at address 0x10000, making sure +! no 64kB boundaries are crossed. We try to load it as fast as +! possible, loading whole tracks whenever we can. +! +! in: es - starting address segment (normally 0x1000) +! +sread: .word 1+SETUPLEN ! sectors read of current track +head: .word 0 ! current head +track: .word 0 ! current track + +read_it: + mov ax,es + test ax,#0x0fff +die: jne die ! es must be at 64kB boundary + xor bx,bx ! bx is starting address within segment +rp_read: + mov ax,es + cmp ax,#ENDSEG ! have we loaded all yet? + jb ok1_read + ret +ok1_read: + seg cs + mov ax,sectors + sub ax,sread + mov cx,ax + shl cx,#9 + add cx,bx + jnc ok2_read + je ok2_read + xor ax,ax + sub ax,bx + shr ax,#9 +ok2_read: + call read_track + mov cx,ax + add ax,sread + seg cs + cmp ax,sectors + jne ok3_read + mov ax,#1 + sub ax,head + jne ok4_read + inc track +ok4_read: + mov head,ax + xor ax,ax +ok3_read: + mov sread,ax + shl cx,#9 + add bx,cx + jnc rp_read + mov ax,es + add ah,#0x10 + mov es,ax + xor bx,bx + jmp rp_read + +read_track: + pusha + pusha + mov ax, #0xe2e ! loading... message 2e = . + mov bx, #7 + int 0x10 + popa + + mov dx,track + mov cx,sread + inc cx + mov ch,dl + mov dx,head + mov dh,dl + and dx,#0x0100 + mov ah,#2 + + push dx ! save for error dump + push cx + push bx + push ax + + int 0x13 + jc bad_rt + add sp, #8 + popa + ret + +bad_rt: push ax ! save error code + call print_all ! ah = error, al = read + + + xor ah,ah + xor dl,dl + int 0x13 + + + add sp, #10 + popa + jmp read_track + +/* + * print_all is for debugging purposes. + * It will print out all of the registers. The assumption is that this is + * called from a routine, with a stack frame like + * dx + * cx + * bx + * ax + * error + * ret <- sp + * +*/ + +print_all: + mov cx, #5 ! error code + 4 registers + mov bp, sp + +print_loop: + push cx ! save count left + call print_nl ! nl for readability + jae no_reg ! see if register name is needed + + mov ax, #0xe05 + 0x41 - 1 + sub al, cl + int 0x10 + + mov al, #0x58 ! X + int 0x10 + + mov al, #0x3a ! : + int 0x10 + +no_reg: + add bp, #2 ! next register + call print_hex ! print it + pop cx + loop print_loop + ret + +print_nl: + mov ax, #0xe0d ! CR + int 0x10 + mov al, #0xa ! LF + int 0x10 + ret + +/* + * print_hex is for debugging purposes, and prints the word + * pointed to by ss:bp in hexadecmial. +*/ + +print_hex: + mov cx, #4 ! 4 hex digits + mov dx, (bp) ! load word into dx +print_digit: + rol dx, #4 ! rotate so that lowest 4 bits are used + mov ah, #0xe + mov al, dl ! mask off so we have only next nibble + and al, #0xf + add al, #0x30 ! convert to 0 based digit, '0' + cmp al, #0x39 ! check for overflow + jbe good_digit + add al, #0x41 - 0x30 - 0xa ! 'A' - '0' - 0xa + +good_digit: + int 0x10 + loop print_digit + ret + + +/* + * 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 + xor al, al + outb + pop dx + ret + +sectors: + .word 0 + +msg1: + .byte 13,10 + .ascii "Loading" + +.org 506 +swap_dev: + .word SWAP_DEV +root_dev: + .word ROOT_DEV +boot_flag: + .word 0xAA55 + +.text +endtext: +.data +enddata: +.bss +endbss: + diff --git a/kernel/0.1x/linux-0.12/boot/head.s b/kernel/0.1x/linux-0.12/boot/head.s new file mode 100644 index 00000000..a8ce5fab --- /dev/null +++ b/kernel/0.1x/linux-0.12/boot/head.s @@ -0,0 +1,238 @@ +/* + * linux/boot/head.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * head.s contains the 32-bit startup code. + * + * NOTE!!! Startup happens at absolute address 0x00000000, which is also where + * the page directory will exist. The startup code will be overwritten by + * the page directory. + */ +.text +.globl _idt,_gdt,_pg_dir,_tmp_floppy_area +_pg_dir: +startup_32: + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + mov %ax,%gs + lss _stack_start,%esp + call setup_idt + call setup_gdt + movl $0x10,%eax # reload all the segment registers + mov %ax,%ds # after changing gdt. CS was already + mov %ax,%es # reloaded in 'setup_gdt' + mov %ax,%fs + mov %ax,%gs + lss _stack_start,%esp + xorl %eax,%eax +1: incl %eax # check that A20 really IS enabled + movl %eax,0x000000 # loop forever if it isn't + cmpl %eax,0x100000 + je 1b +/* + * NOTE! 486 should set bit 16, to check for write-protect in supervisor + * mode. Then it would be unnecessary with the "verify_area()"-calls. + * 486 users probably want to set the NE (#5) bit also, so as to use + * int 16 for math errors. + */ + movl %cr0,%eax # check math chip + andl $0x80000011,%eax # Save PG,PE,ET +/* "orl $0x10020,%eax" here for 486 might be good */ + orl $2,%eax # set MP + movl %eax,%cr0 + call check_x87 + jmp after_page_tables + +/* + * We depend on ET to be correct. This checks for 287/387. + */ +check_x87: + fninit + fstsw %ax + cmpb $0,%al + je 1f /* no coprocessor: have to set bits */ + movl %cr0,%eax + xorl $6,%eax /* reset MP, set EM */ + movl %eax,%cr0 + ret +.align 2 +1: .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ + ret + +/* + * setup_idt + * + * sets up a idt with 256 entries pointing to + * ignore_int, interrupt gates. It then loads + * idt. Everything that wants to install itself + * in the idt-table may do so themselves. Interrupts + * are enabled elsewhere, when we can be relatively + * sure everything is ok. This routine will be over- + * written by the page tables. + */ +setup_idt: + lea ignore_int,%edx + movl $0x00080000,%eax + movw %dx,%ax /* selector = 0x0008 = cs */ + movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ + + lea _idt,%edi + mov $256,%ecx +rp_sidt: + movl %eax,(%edi) + movl %edx,4(%edi) + addl $8,%edi + dec %ecx + jne rp_sidt + lidt idt_descr + ret + +/* + * setup_gdt + * + * This routines sets up a new gdt and loads it. + * Only two entries are currently built, the same + * ones that were built in init.s. The routine + * is VERY complicated at two whole lines, so this + * rather long comment is certainly needed :-). + * This routine will beoverwritten by the page tables. + */ +setup_gdt: + lgdt gdt_descr + ret + +/* + * I put the kernel page tables right after the page directory, + * using 4 of them to span 16 Mb of physical memory. People with + * more than 16MB will have to expand this. + */ +.org 0x1000 +pg0: + +.org 0x2000 +pg1: + +.org 0x3000 +pg2: + +.org 0x4000 +pg3: + +.org 0x5000 +/* + * tmp_floppy_area is used by the floppy-driver when DMA cannot + * reach to a buffer-block. It needs to be aligned, so that it isn't + * on a 64kB border. + */ +_tmp_floppy_area: + .fill 1024,1,0 + +after_page_tables: + pushl $0 # These are the parameters to main :-) + pushl $0 + pushl $0 + pushl $L6 # return address for main, if it decides to. + pushl $_main + jmp setup_paging +L6: + jmp L6 # main should never return here, but + # just in case, we know what happens. + +/* This is the default interrupt "handler" :-) */ +int_msg: + .asciz "Unknown interrupt\n\r" +.align 2 +ignore_int: + pushl %eax + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + pushl $int_msg + call _printk + popl %eax + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + + +/* + * Setup_paging + * + * This routine sets up paging by setting the page bit + * in cr0. The page tables are set up, identity-mapping + * the first 16MB. The pager assumes that no illegal + * addresses are produced (ie >4Mb on a 4Mb machine). + * + * NOTE! Although all physical memory should be identity + * mapped by this routine, only the kernel page functions + * use the >1Mb addresses directly. All "normal" functions + * use just the lower 1Mb, or the local data space, which + * will be mapped to some other place - mm keeps track of + * that. + * + * For those with more memory than 16 Mb - tough luck. I've + * not got it, why should you :-) The source is here. Change + * it. (Seriously - it shouldn't be too difficult. Mostly + * change some constants etc. I left it at 16Mb, as my machine + * even cannot be extended past that (ok, but it was cheap :-) + * I've tried to show which constants to change by having + * some kind of marker at them (search for "16Mb"), but I + * won't guarantee that's all :-( ) + */ +.align 2 +setup_paging: + movl $1024*5,%ecx /* 5 pages - pg_dir+4 page tables */ + xorl %eax,%eax + xorl %edi,%edi /* pg_dir is at 0x000 */ + cld;rep;stosl + movl $pg0+7,_pg_dir /* set present bit/user r/w */ + movl $pg1+7,_pg_dir+4 /* --------- " " --------- */ + movl $pg2+7,_pg_dir+8 /* --------- " " --------- */ + movl $pg3+7,_pg_dir+12 /* --------- " " --------- */ + movl $pg3+4092,%edi + movl $0xfff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */ + std +1: stosl /* fill pages backwards - more efficient :-) */ + subl $0x1000,%eax + jge 1b + xorl %eax,%eax /* pg_dir is at 0x0000 */ + movl %eax,%cr3 /* cr3 - page directory start */ + movl %cr0,%eax + orl $0x80000000,%eax + movl %eax,%cr0 /* set paging (PG) bit */ + 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 0x00c09a0000000fff /* 16Mb */ + .quad 0x00c0920000000fff /* 16Mb */ + .quad 0x0000000000000000 /* TEMPORARY - don't use */ + .fill 252,8,0 /* space for LDT's and TSS's etc */ diff --git a/kernel/0.1x/linux-0.12/boot/setup.S b/kernel/0.1x/linux-0.12/boot/setup.S new file mode 100644 index 00000000..24809ee3 --- /dev/null +++ b/kernel/0.1x/linux-0.12/boot/setup.S @@ -0,0 +1,631 @@ +! +! setup.s (C) 1991 Linus Torvalds +! +! setup.s is responsible for getting the system data from the BIOS, +! and putting them into the appropriate places in system memory. +! both setup.s and system has been loaded by the bootblock. +! +! This code asks the bios for memory/disk/other parameters, and +! puts them in a "safe" place: 0x90000-0x901FF, ie where the +! boot-block used to be. It is then up to the protected mode +! system to read them from there before the area is overwritten +! for buffer-blocks. +! + +! NOTE! These had better be the same as in bootsect.s! +#include + +INITSEG = DEF_INITSEG ! we move boot here - out of the way +SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). +SETUPSEG = DEF_SETUPSEG ! this is the current segment + +.globl begtext, begdata, begbss, endtext, enddata, endbss +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +entry start +start: + +! ok, the read went well so we get current cursor position and save it for +! posterity. + + mov ax,#INITSEG ! this is done in bootsect already, but... + mov ds,ax + +! Get memory size (extended mem, kB) + + mov ah,#0x88 + int 0x15 + mov [2],ax + +! check for EGA/VGA and some config parameters + + mov ah,#0x12 + mov bl,#0x10 + int 0x10 + mov [8],ax + mov [10],bx + mov [12],cx + mov ax,#0x5019 + cmp bl,#0x10 + je novga + call chsvga +novga: mov [14],ax + mov ah,#0x03 ! read cursor pos + xor bh,bh + int 0x10 ! save it in known place, con_init fetches + mov [0],dx ! it from 0x90000. + +! Get video-card data: + + mov ah,#0x0f + int 0x10 + mov [4],bx ! bh = display page + mov [6],ax ! al = video mode, ah = window width + +! Get hd0 data + + mov ax,#0x0000 + mov ds,ax + lds si,[4*0x41] + mov ax,#INITSEG + mov es,ax + mov di,#0x0080 + mov cx,#0x10 + rep + movsb + +! Get hd1 data + + mov ax,#0x0000 + mov ds,ax + lds si,[4*0x46] + mov ax,#INITSEG + mov es,ax + mov di,#0x0090 + mov cx,#0x10 + rep + movsb + +! Check that there IS a hd1 :-) + + mov ax,#0x01500 + mov dl,#0x81 + int 0x13 + jc no_disk1 + cmp ah,#3 + je is_disk1 +no_disk1: + mov ax,#INITSEG + mov es,ax + mov di,#0x0090 + mov cx,#0x10 + mov ax,#0x00 + rep + stosb +is_disk1: + +! 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 + jmp do_move + +! then we load the segment descriptors + +end_move: + mov ax,#SETUPSEG ! 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 + +! Routine trying to recognize type of SVGA-board present (if any) +! and if it recognize one gives the choices of resolution it offers. +! If one is found the resolution chosen is given by al,ah (rows,cols). + +chsvga: cld + push ds + push cs + pop ds + mov ax,#0xc000 + mov es,ax + lea si,msg1 + call prtstr +nokey: in al,#0x60 + cmp al,#0x82 + jb nokey + cmp al,#0xe0 + ja nokey + cmp al,#0x9c + je svga + mov ax,#0x5019 + pop ds + ret +svga: lea si,idati ! Check ATI 'clues' + mov di,#0x31 + mov cx,#0x09 + repe + cmpsb + jne noati + lea si,dscati + lea di,moati + lea cx,selmod + jmp cx +noati: mov ax,#0x200f ! Check Ahead 'clues' + mov dx,#0x3ce + out dx,ax + inc dx + in al,dx + cmp al,#0x20 + je isahed + cmp al,#0x21 + jne noahed +isahed: lea si,dscahead + lea di,moahead + lea cx,selmod + jmp cx +noahed: mov dx,#0x3c3 ! Check Chips & Tech. 'clues' + in al,dx + or al,#0x10 + out dx,al + mov dx,#0x104 + in al,dx + mov bl,al + mov dx,#0x3c3 + in al,dx + and al,#0xef + out dx,al + cmp bl,[idcandt] + jne nocant + lea si,dsccandt + lea di,mocandt + lea cx,selmod + jmp cx +nocant: mov dx,#0x3d4 ! Check Cirrus 'clues' + mov al,#0x0c + out dx,al + inc dx + in al,dx + mov bl,al + xor al,al + out dx,al + dec dx + mov al,#0x1f + out dx,al + inc dx + in al,dx + mov bh,al + xor ah,ah + shl al,#4 + mov cx,ax + mov al,bh + shr al,#4 + add cx,ax + shl cx,#8 + add cx,#6 + mov ax,cx + mov dx,#0x3c4 + out dx,ax + inc dx + in al,dx + and al,al + jnz nocirr + mov al,bh + out dx,al + in al,dx + cmp al,#0x01 + jne nocirr + call rst3d4 + lea si,dsccirrus + lea di,mocirrus + lea cx,selmod + jmp cx +rst3d4: mov dx,#0x3d4 + mov al,bl + xor ah,ah + shl ax,#8 + add ax,#0x0c + out dx,ax + ret +nocirr: call rst3d4 ! Check Everex 'clues' + mov ax,#0x7000 + xor bx,bx + int 0x10 + cmp al,#0x70 + jne noevrx + shr dx,#4 + cmp dx,#0x678 + je istrid + cmp dx,#0x236 + je istrid + lea si,dsceverex + lea di,moeverex + lea cx,selmod + jmp cx +istrid: lea cx,ev2tri + jmp cx +noevrx: lea si,idgenoa ! Check Genoa 'clues' + xor ax,ax + seg es + mov al,[0x37] + mov di,ax + mov cx,#0x04 + dec si + dec di +l1: inc si + inc di + mov al,(si) + seg es + and al,(di) + cmp al,(si) + loope l1 + cmp cx,#0x00 + jne nogen + lea si,dscgenoa + lea di,mogenoa + lea cx,selmod + jmp cx +nogen: lea si,idparadise ! Check Paradise 'clues' + mov di,#0x7d + mov cx,#0x04 + repe + cmpsb + jne nopara + lea si,dscparadise + lea di,moparadise + lea cx,selmod + jmp cx +nopara: mov dx,#0x3c4 ! Check Trident 'clues' + mov al,#0x0e + out dx,al + inc dx + in al,dx + xchg ah,al + mov al,#0x00 + out dx,al + in al,dx + xchg al,ah + mov bl,al ! Strange thing ... in the book this wasn't + and bl,#0x02 ! necessary but it worked on my card which + jz setb2 ! is a trident. Without it the screen goes + and al,#0xfd ! blurred ... + jmp clrb2 ! +setb2: or al,#0x02 ! +clrb2: out dx,al + and ah,#0x0f + cmp ah,#0x02 + jne notrid +ev2tri: lea si,dsctrident + lea di,motrident + lea cx,selmod + jmp cx +notrid: mov dx,#0x3cd ! Check Tseng 'clues' + in al,dx ! Could things be this simple ! :-) + mov bl,al + mov al,#0x55 + out dx,al + in al,dx + mov ah,al + mov al,bl + out dx,al + cmp ah,#0x55 + jne notsen + lea si,dsctseng + lea di,motseng + lea cx,selmod + jmp cx +notsen: mov dx,#0x3cc ! Check Video7 'clues' + in al,dx + mov dx,#0x3b4 + and al,#0x01 + jz even7 + mov dx,#0x3d4 +even7: mov al,#0x0c + out dx,al + inc dx + in al,dx + mov bl,al + mov al,#0x55 + out dx,al + in al,dx + dec dx + mov al,#0x1f + out dx,al + inc dx + in al,dx + mov bh,al + dec dx + mov al,#0x0c + out dx,al + inc dx + mov al,bl + out dx,al + mov al,#0x55 + xor al,#0xea + cmp al,bh + jne novid7 + lea si,dscvideo7 + lea di,movideo7 +selmod: push si + lea si,msg2 + call prtstr + xor cx,cx + mov cl,(di) + pop si + push si + push cx +tbl: pop bx + push bx + mov al,bl + sub al,cl + call dprnt + call spcing + lodsw + xchg al,ah + call dprnt + xchg ah,al + push ax + mov al,#0x78 + call prnt1 + pop ax + call dprnt + call docr + loop tbl + pop cx + call docr + lea si,msg3 + call prtstr + pop si + add cl,#0x80 +nonum: in al,#0x60 ! Quick and dirty... + cmp al,#0x82 + jb nonum + cmp al,#0x8b + je zero + cmp al,cl + ja nonum + jmp nozero +zero: sub al,#0x0a +nozero: sub al,#0x80 + dec al + xor ah,ah + add di,ax + inc di + push ax + mov al,(di) + int 0x10 + pop ax + shl ax,#1 + add si,ax + lodsw + pop ds + ret +novid7: pop ds ! Here could be code to support standard 80x50,80x30 + mov ax,#0x5019 + ret + +! Routine that 'tabs' to next col. + +spcing: mov al,#0x2e + call prnt1 + mov al,#0x20 + call prnt1 + mov al,#0x20 + call prnt1 + mov al,#0x20 + call prnt1 + mov al,#0x20 + call prnt1 + ret + +! Routine to print asciiz-string at DS:SI + +prtstr: lodsb + and al,al + jz fin + call prnt1 + jmp prtstr +fin: ret + +! Routine to print a decimal value on screen, the value to be +! printed is put in al (i.e 0-255). + +dprnt: push ax + push cx + mov ah,#0x00 + mov cl,#0x0a + idiv cl + cmp al,#0x09 + jbe lt100 + call dprnt + jmp skip10 +lt100: add al,#0x30 + call prnt1 +skip10: mov al,ah + add al,#0x30 + call prnt1 + pop cx + pop ax + ret + +! Part of above routine, this one just prints ascii al + +prnt1: push ax + push cx + mov bh,#0x00 + mov cx,#0x01 + mov ah,#0x0e + int 0x10 + pop cx + pop ax + ret + +! Prints + + +docr: push ax + push cx + mov bh,#0x00 + mov ah,#0x0e + mov al,#0x0a + mov cx,#0x01 + int 0x10 + mov al,#0x0d + int 0x10 + pop cx + pop ax + 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 512+gdt,0x9 ! gdt base = 0X9xxxx + +msg1: .ascii "Press to see SVGA-modes available or any other key to continue." + db 0x0d, 0x0a, 0x0a, 0x00 +msg2: .ascii "Mode: COLSxROWS:" + db 0x0d, 0x0a, 0x0a, 0x00 +msg3: .ascii "Choose mode by pressing the corresponding number." + db 0x0d, 0x0a, 0x00 + +idati: .ascii "761295520" +idcandt: .byte 0xa5 +idgenoa: .byte 0x77, 0x00, 0x66, 0x99 +idparadise: .ascii "VGA=" + +! Manufacturer: Numofmodes: Mode: + +moati: .byte 0x02, 0x23, 0x33 +moahead: .byte 0x05, 0x22, 0x23, 0x24, 0x2f, 0x34 +mocandt: .byte 0x02, 0x60, 0x61 +mocirrus: .byte 0x04, 0x1f, 0x20, 0x22, 0x31 +moeverex: .byte 0x0a, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40 +mogenoa: .byte 0x0a, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78 +moparadise: .byte 0x02, 0x55, 0x54 +motrident: .byte 0x07, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a +motseng: .byte 0x05, 0x26, 0x2a, 0x23, 0x24, 0x22 +movideo7: .byte 0x06, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45 + +! msb = Cols lsb = Rows: + +dscati: .word 0x8419, 0x842c +dscahead: .word 0x842c, 0x8419, 0x841c, 0xa032, 0x5042 +dsccandt: .word 0x8419, 0x8432 +dsccirrus: .word 0x8419, 0x842c, 0x841e, 0x6425 +dsceverex: .word 0x5022, 0x503c, 0x642b, 0x644b, 0x8419, 0x842c, 0x501e, 0x641b, 0xa040, 0x841e +dscgenoa: .word 0x5020, 0x642a, 0x8419, 0x841d, 0x8420, 0x842c, 0x843c, 0x503c, 0x5042, 0x644b +dscparadise: .word 0x8419, 0x842b +dsctrident: .word 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c +dsctseng: .word 0x503c, 0x6428, 0x8419, 0x841c, 0x842c +dscvideo7: .word 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c + +.text +endtext: +.data +enddata: +.bss +endbss: diff --git a/kernel/0.1x/linux-0.12/fs/Makefile b/kernel/0.1x/linux-0.12/fs/Makefile new file mode 100644 index 00000000..2854b45d --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/Makefile @@ -0,0 +1,129 @@ +AR =gar +AS =gas +CC =gcc +LD =gld +CFLAGS =-Wall -O -fstrength-reduce -fcombine-regs -fomit-frame-pointer \ + -fno-defer-pop -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 truncate.o select.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 ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h +block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h +buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \ + ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/system.h \ + ../include/asm/io.h +char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/asm/segment.h ../include/asm/io.h +exec.o : exec.c ../include/signal.h ../include/sys/types.h \ + ../include/errno.h ../include/string.h ../include/sys/stat.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/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.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/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.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/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/segment.h +file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h +inode.o : inode.c ../include/string.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \ + ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/system.h +ioctl.o : ioctl.c ../include/string.h ../include/errno.h \ + ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.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/signal.h ../include/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.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/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/linux/tty.h ../include/termios.h \ + ../include/asm/segment.h +pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \ + ../include/errno.h ../include/termios.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/segment.h +read_write.o : read_write.c ../include/sys/stat.h ../include/sys/types.h \ + ../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/segment.h +select.o : select.c ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/mm.h \ + ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \ + ../include/asm/system.h ../include/sys/stat.h ../include/string.h \ + ../include/const.h ../include/errno.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/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.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 ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/asm/system.h ../include/errno.h \ + ../include/sys/stat.h +truncate.o : truncate.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ + ../include/sys/stat.h diff --git a/kernel/0.1x/linux-0.12/fs/bitmap.c b/kernel/0.1x/linux-0.12/fs/bitmap.c new file mode 100644 index 00000000..aebecded --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/bitmap.c @@ -0,0 +1,169 @@ +/* + * linux/fs/bitmap.c + * + * (C) 1991 Linus Torvalds + */ + +/* bitmap.c contains the code that handles the inode and block bitmaps */ +#include + +#include +#include + +#define clear_block(addr) \ +__asm__("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__ __volatile__("btsl %2,%3\n\tsetb %%al": \ +"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \ +res;}) + +#define clear_bit(nr,addr) ({\ +register int res __asm__("ax"); \ +__asm__ __volatile__("btrl %2,%3\n\tsetnb %%al": \ +"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \ +res;}) + +#define find_first_zero(addr) ({ \ +int __res; \ +__asm__("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;}) + +int 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) { + brelse(bh); + return 0; + } + bh->b_dirt=0; + bh->b_uptodate=0; + if (bh->b_count) + 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); + printk("free_block: bit already cleared\n"); + } + sb->s_zmap[block/8192]->b_dirt = 1; + return 1; +} + +int new_block(int dev) +{ + struct buffer_head * bh; + struct super_block * sb; + int i,j; + + if (!(sb = get_super(dev))) + panic("trying to get new block from nonexistant device"); + j = 8192; + for (i=0 ; i<8 ; i++) + if (bh=sb->s_zmap[i]) + if ((j=find_first_zero(bh->b_data))<8192) + break; + if (i>=8 || !bh || j>=8192) + return 0; + if (set_bit(j,bh->b_data)) + panic("new_block: bit already set"); + bh->b_dirt = 1; + j += i*8192 + sb->s_firstdatazone-1; + if (j >= sb->s_nzones) + return 0; + if (!(bh=getblk(dev,j))) + panic("new_block: cannot get block"); + if (bh->b_count != 1) + panic("new block: count is != 1"); + clear_block(bh->b_data); + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse(bh); + return j; +} + +void free_inode(struct m_inode * inode) +{ + struct super_block * sb; + struct buffer_head * bh; + + if (!inode) + return; + if (!inode->i_dev) { + memset(inode,0,sizeof(*inode)); + return; + } + if (inode->i_count>1) { + printk("trying to free inode with count=%d\n",inode->i_count); + panic("free_inode"); + } + if (inode->i_nlinks) + panic("trying to free inode with links"); + if (!(sb = get_super(inode->i_dev))) + panic("trying to free inode on nonexistent device"); + if (inode->i_num < 1 || inode->i_num > sb->s_ninodes) + panic("trying to free inode 0 or nonexistant inode"); + if (!(bh=sb->s_imap[inode->i_num>>13])) + panic("nonexistent imap in superblock"); + if (clear_bit(inode->i_num&8191,bh->b_data)) + printk("free_inode: bit already cleared.\n\r"); + bh->b_dirt = 1; + memset(inode,0,sizeof(*inode)); +} + +struct m_inode * new_inode(int dev) +{ + struct m_inode * inode; + struct super_block * sb; + struct buffer_head * bh; + int i,j; + + if (!(inode=get_empty_inode())) + return NULL; + if (!(sb = get_super(dev))) + panic("new_inode with unknown device"); + j = 8192; + for (i=0 ; i<8 ; i++) + if (bh=sb->s_imap[i]) + if ((j=find_first_zero(bh->b_data))<8192) + break; + if (!bh || j >= 8192 || j+i*8192 > sb->s_ninodes) { + iput(inode); + return NULL; + } + if (set_bit(j,bh->b_data)) + panic("new_inode: bit already set"); + bh->b_dirt = 1; + inode->i_count=1; + inode->i_nlinks=1; + inode->i_dev=dev; + inode->i_uid=current->euid; + inode->i_gid=current->egid; + inode->i_dirt=1; + inode->i_num = j + i*8192; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + return inode; +} diff --git a/kernel/0.1x/linux-0.12/fs/block_dev.c b/kernel/0.1x/linux-0.12/fs/block_dev.c new file mode 100644 index 00000000..e8d5e514 --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/block_dev.c @@ -0,0 +1,89 @@ +/* + * linux/fs/block_dev.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include +#include +#include + +extern int *blk_size[]; + +int block_write(int dev, long * pos, char * buf, int count) +{ + int block = *pos >> BLOCK_SIZE_BITS; + int offset = *pos & (BLOCK_SIZE-1); + int chars; + int written = 0; + int size; + struct buffer_head * bh; + register char * p; + + if (blk_size[MAJOR(dev)]) + size = blk_size[MAJOR(dev)][MINOR(dev)]; + else + size = 0x7fffffff; + while (count>0) { + if (block >= size) + return written?written:-EIO; + chars = BLOCK_SIZE - offset; + if (chars > count) + chars=count; + if (chars == BLOCK_SIZE) + bh = getblk(dev,block); + else + bh = breada(dev,block,block+1,block+2,-1); + block++; + if (!bh) + return written?written:-EIO; + p = offset + bh->b_data; + offset = 0; + *pos += chars; + written += chars; + count -= chars; + while (chars-->0) + *(p++) = get_fs_byte(buf++); + bh->b_dirt = 1; + brelse(bh); + } + return written; +} + +int block_read(int dev, unsigned long * pos, char * buf, int count) +{ + int block = *pos >> BLOCK_SIZE_BITS; + int offset = *pos & (BLOCK_SIZE-1); + int chars; + int size; + int read = 0; + struct buffer_head * bh; + register char * p; + + if (blk_size[MAJOR(dev)]) + size = blk_size[MAJOR(dev)][MINOR(dev)]; + else + size = 0x7fffffff; + while (count>0) { + if (block >= size) + return read?read:-EIO; + chars = BLOCK_SIZE-offset; + if (chars > count) + chars = count; + if (!(bh = breada(dev,block,block+1,block+2,-1))) + return read?read:-EIO; + block++; + p = offset + bh->b_data; + offset = 0; + *pos += chars; + read += chars; + count -= chars; + while (chars-->0) + put_fs_byte(*(p++),buf++); + brelse(bh); + } + return read; +} diff --git a/kernel/0.1x/linux-0.12/fs/buffer.c b/kernel/0.1x/linux-0.12/fs/buffer.c new file mode 100644 index 00000000..8ec3376c --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/buffer.c @@ -0,0 +1,381 @@ +/* + * linux/fs/buffer.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'buffer.c' implements the buffer-cache functions. Race-conditions have + * been avoided by NEVER letting a interrupt change a buffer (except for the + * data, of course), but instead letting the caller do it. NOTE! As interrupts + * can wake up a caller, some cli-sti sequences are needed to check for + * sleep-on-calls. These should be extremely quick, though (I hope). + */ + +/* + * NOTE! There is one discordant note here: checking floppies for + * disk change. This is where it fits best, I think, as it should + * invalidate changed floppy-disk-caches. + */ + +#include + +#include +#include +#include +#include +#include + +extern int end; +struct buffer_head * start_buffer = (struct buffer_head *) &end; +struct buffer_head * hash_table[NR_HASH]; +static struct buffer_head * free_list; +static struct task_struct * buffer_wait = NULL; +int NR_BUFFERS = 0; + +static inline void wait_on_buffer(struct buffer_head * bh) +{ + cli(); + while (bh->b_lock) + sleep_on(&bh->b_wait); + sti(); +} + +int sys_sync(void) +{ + int i; + struct buffer_head * bh; + + sync_inodes(); /* write out inodes into buffers */ + bh = start_buffer; + for (i=0 ; ib_dirt) + ll_rw_block(WRITE,bh); + } + return 0; +} + +int sync_dev(int dev) +{ + int i; + struct buffer_head * bh; + + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_dirt) + ll_rw_block(WRITE,bh); + } + sync_inodes(); + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_dirt) + ll_rw_block(WRITE,bh); + } + return 0; +} + +void inline invalidate_buffers(int dev) +{ + int i; + struct buffer_head * bh; + + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev) + bh->b_uptodate = bh->b_dirt = 0; + } +} + +/* + * This routine checks whether a floppy has been changed, and + * invalidates all buffer-cache-entries in that case. This + * is a relatively slow routine, so we have to try to minimize using + * it. Thus it is called only upon a 'mount' or 'open'. This + * is the best way of combining speed and utility, I think. + * People changing diskettes in the middle of an operation deserve + * to loose :-) + * + * NOTE! Although currently this is only for floppies, the idea is + * that any additional removable block-device will use this routine, + * and that mount/open needn't know that floppies/whatever are + * special. + */ +void check_disk_change(int dev) +{ + int i; + + if (MAJOR(dev) != 2) + return; + if (!floppy_change(dev & 0x03)) + return; + for (i=0 ; ib_next) + bh->b_next->b_prev = bh->b_prev; + if (bh->b_prev) + bh->b_prev->b_next = bh->b_next; + if (hash(bh->b_dev,bh->b_blocknr) == bh) + hash(bh->b_dev,bh->b_blocknr) = bh->b_next; +/* remove from free list */ + if (!(bh->b_prev_free) || !(bh->b_next_free)) + panic("Free block list corrupted"); + bh->b_prev_free->b_next_free = bh->b_next_free; + bh->b_next_free->b_prev_free = bh->b_prev_free; + if (free_list == bh) + free_list = bh->b_next_free; +} + +static inline void insert_into_queues(struct buffer_head * bh) +{ +/* put at end of free list */ + bh->b_next_free = free_list; + bh->b_prev_free = free_list->b_prev_free; + free_list->b_prev_free->b_next_free = bh; + free_list->b_prev_free = bh; +/* put the buffer in new hash-queue if it has a device */ + bh->b_prev = NULL; + bh->b_next = NULL; + if (!bh->b_dev) + return; + bh->b_next = hash(bh->b_dev,bh->b_blocknr); + hash(bh->b_dev,bh->b_blocknr) = bh; + bh->b_next->b_prev = bh; +} + +static struct buffer_head * find_buffer(int dev, int block) +{ + struct buffer_head * tmp; + + for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next) + if (tmp->b_dev==dev && tmp->b_blocknr==block) + return tmp; + return NULL; +} + +/* + * Why like this, I hear you say... The reason is race-conditions. + * As we don't lock buffers (unless we are readint them, that is), + * something might happen to it while we sleep (ie a read-error + * will force it bad). This shouldn't really happen currently, but + * the code is ready. + */ +struct buffer_head * get_hash_table(int dev, int block) +{ + struct buffer_head * bh; + + for (;;) { + if (!(bh=find_buffer(dev,block))) + return NULL; + bh->b_count++; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_blocknr == block) + return bh; + bh->b_count--; + } +} + +/* + * Ok, this is getblk, and it isn't very clear, again to hinder + * race-conditions. Most of the code is seldom used, (ie repeating), + * so it should be much more efficient than it looks. + * + * The algoritm is changed: hopefully better, and an elusive bug removed. + */ +#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock) +struct buffer_head * getblk(int dev,int block) +{ + struct buffer_head * tmp, * bh; + +repeat: + if (bh = get_hash_table(dev,block)) + return bh; + tmp = free_list; + do { + if (tmp->b_count) + continue; + if (!bh || BADNESS(tmp)b_next_free) != free_list); + if (!bh) { + sleep_on(&buffer_wait); + goto repeat; + } + wait_on_buffer(bh); + if (bh->b_count) + goto repeat; + while (bh->b_dirt) { + sync_dev(bh->b_dev); + wait_on_buffer(bh); + if (bh->b_count) + goto repeat; + } +/* NOTE!! While we slept waiting for this block, somebody else might */ +/* already have added "this" block to the cache. check it */ + if (find_buffer(dev,block)) + goto repeat; +/* OK, FINALLY we know that this buffer is the only one of it's kind, */ +/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */ + bh->b_count=1; + bh->b_dirt=0; + bh->b_uptodate=0; + remove_from_queues(bh); + bh->b_dev=dev; + bh->b_blocknr=block; + insert_into_queues(bh); + return bh; +} + +void brelse(struct buffer_head * buf) +{ + if (!buf) + return; + wait_on_buffer(buf); + if (!(buf->b_count--)) + panic("Trying to free free buffer"); + wake_up(&buffer_wait); +} + +/* + * bread() reads a specified block and returns the buffer that contains + * it. It returns NULL if the block was unreadable. + */ +struct buffer_head * bread(int dev,int block) +{ + struct buffer_head * bh; + + if (!(bh=getblk(dev,block))) + panic("bread: getblk returned NULL\n"); + if (bh->b_uptodate) + return bh; + ll_rw_block(READ,bh); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return NULL; +} + +#define COPYBLK(from,to) \ +__asm__("cld\n\t" \ + "rep\n\t" \ + "movsl\n\t" \ + ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \ + :"cx","di","si") + +/* + * bread_page reads four buffers into memory at the desired address. It's + * a function of its own, as there is some speed to be got by reading them + * all at the same time, not waiting for one to be read, and then another + * etc. + */ +void bread_page(unsigned long address,int dev,int b[4]) +{ + struct buffer_head * bh[4]; + int i; + + for (i=0 ; i<4 ; i++) + if (b[i]) { + if (bh[i] = getblk(dev,b[i])) + if (!bh[i]->b_uptodate) + ll_rw_block(READ,bh[i]); + } else + bh[i] = NULL; + for (i=0 ; i<4 ; i++,address += BLOCK_SIZE) + if (bh[i]) { + wait_on_buffer(bh[i]); + if (bh[i]->b_uptodate) + COPYBLK((unsigned long) bh[i]->b_data,address); + brelse(bh[i]); + } +} + +/* + * Ok, breada can be used as bread, but additionally to mark other + * blocks for reading as well. End the argument list with a negative + * number. + */ +struct buffer_head * breada(int dev,int first, ...) +{ + va_list args; + struct buffer_head * bh, *tmp; + + va_start(args,first); + if (!(bh=getblk(dev,first))) + panic("bread: getblk returned NULL\n"); + if (!bh->b_uptodate) + ll_rw_block(READ,bh); + while ((first=va_arg(args,int))>=0) { + tmp=getblk(dev,first); + if (tmp) { + if (!tmp->b_uptodate) + ll_rw_block(READA,bh); + tmp->b_count--; + } + } + va_end(args); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return (NULL); +} + +void buffer_init(long buffer_end) +{ + struct buffer_head * h = start_buffer; + void * b; + int i; + + if (buffer_end == 1<<20) + b = (void *) (640*1024); + else + b = (void *) buffer_end; + while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) { + h->b_dev = 0; + h->b_dirt = 0; + h->b_count = 0; + h->b_lock = 0; + h->b_uptodate = 0; + h->b_wait = NULL; + h->b_next = NULL; + h->b_prev = NULL; + h->b_data = (char *) b; + h->b_prev_free = h-1; + h->b_next_free = h+1; + h++; + NR_BUFFERS++; + if (b == (void *) 0x100000) + b = (void *) 0xA0000; + } + h--; + free_list = start_buffer; + free_list->b_prev_free = h; + h->b_next_free = free_list; + for (i=0;i +#include + +#include +#include + +#include +#include + +extern int tty_read(unsigned minor,char * buf,int count); +extern int tty_write(unsigned minor,char * buf,int count); + +typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count,off_t * pos); + +static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos) +{ + return ((rw==READ)?tty_read(minor,buf,count): + tty_write(minor,buf,count)); +} + +static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos) +{ + if (current->tty<0) + return -EPERM; + return rw_ttyx(rw,current->tty,buf,count,pos); +} + +static int rw_ram(int rw,char * buf, int count, off_t *pos) +{ + return -EIO; +} + +static int rw_mem(int rw,char * buf, int count, off_t * pos) +{ + return -EIO; +} + +static int rw_kmem(int rw,char * buf, int count, off_t * pos) +{ + return -EIO; +} + +static int rw_port(int rw,char * buf, int count, off_t * pos) +{ + int i=*pos; + + while (count-->0 && i<65536) { + if (rw==READ) + put_fs_byte(inb(i),buf++); + else + outb(get_fs_byte(buf++),i); + i++; + } + i -= *pos; + *pos += i; + return i; +} + +static int rw_memory(int rw, unsigned minor, char * buf, int count, off_t * pos) +{ + switch(minor) { + case 0: + return rw_ram(rw,buf,count,pos); + case 1: + return rw_mem(rw,buf,count,pos); + case 2: + return rw_kmem(rw,buf,count,pos); + case 3: + return (rw==READ)?0:count; /* rw_null */ + case 4: + return rw_port(rw,buf,count,pos); + default: + return -EIO; + } +} + +#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr))) + +static crw_ptr crw_table[]={ + NULL, /* nodev */ + rw_memory, /* /dev/mem etc */ + NULL, /* /dev/fd */ + NULL, /* /dev/hd */ + rw_ttyx, /* /dev/ttyx */ + rw_tty, /* /dev/tty */ + NULL, /* /dev/lp */ + NULL}; /* unnamed pipes */ + +int rw_char(int rw,int dev, char * buf, int count, off_t * pos) +{ + crw_ptr call_addr; + + if (MAJOR(dev)>=NRDEVS) + return -ENODEV; + if (!(call_addr=crw_table[MAJOR(dev)])) + return -ENODEV; + return call_addr(rw,MINOR(dev),buf,count,pos); +} diff --git a/kernel/0.1x/linux-0.12/fs/exec.c b/kernel/0.1x/linux-0.12/fs/exec.c new file mode 100644 index 00000000..1944a81a --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/exec.c @@ -0,0 +1,382 @@ +/* + * linux/fs/exec.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * #!-checking implemented by tytso. + */ + +/* + * Demand-loading implemented 01.12.91 - no need to read anything but + * the header into memory. The inode of the executable is put into + * "current->executable", and page faults do the actual loading. Clean. + * + * Once more I can proudly say that linux stood up to being changed: it + * was less than 2 hours work to get demand-loading completely implemented. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 + +int sys_uselib(const char * library) +{ + struct m_inode * inode; + unsigned long base; + + if (get_limit(0x17) != TASK_SIZE) + return -EINVAL; + if (library) { + if (!(inode=namei(library))) /* get library inode */ + return -ENOENT; + } else + inode = NULL; +/* we should check filetypes (headers etc), but we don't */ + iput(current->library); + current->library = NULL; + base = get_base(current->ldt[2]); + base += LIBRARY_OFFSET; + free_page_tables(base,LIBRARY_SIZE); + current->library = inode; + return 0; +} + +/* + * create_tables() parses the env- and arg-strings in new user + * memory and creates the pointer tables from them, and puts their + * addresses on the "stack", returning the new stack pointer value. + */ +static unsigned long * create_tables(char * p,int argc,int envc) +{ + unsigned long *argv,*envp; + unsigned long * sp; + + sp = (unsigned long *) (0xfffffffc & (unsigned long) p); + sp -= envc+1; + envp = sp; + sp -= argc+1; + argv = sp; + put_fs_long((unsigned long)envp,--sp); + put_fs_long((unsigned long)argv,--sp); + put_fs_long((unsigned long)argc,--sp); + while (argc-->0) { + put_fs_long((unsigned long) p,argv++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,argv); + while (envc-->0) { + put_fs_long((unsigned long) p,envp++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,envp); + return sp; +} + +/* + * count() counts the number of arguments/envelopes + */ +static int count(char ** argv) +{ + int i=0; + char ** tmp; + + if (tmp = argv) + while (get_fs_long((unsigned long *) (tmp++))) + i++; + + return i; +} + +/* + * 'copy_string()' copies argument/envelope strings from user + * memory to free pages in kernel mem. These are in a format ready + * to be put directly into the top of new user memory. + * + * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies + * whether the string and the string array are from user or kernel segments: + * + * from_kmem argv * argv ** + * 0 user space user space + * 1 kernel space user space + * 2 kernel space kernel space + * + * We do this by playing games with the fs segment register. Since it + * it is expensive to load a segment register, we try to avoid calling + * set_fs() unless we absolutely have to. + */ +static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, + unsigned long p, int from_kmem) +{ + char *tmp, *pag; + int len, offset = 0; + unsigned long old_fs, new_fs; + + if (!p) + return 0; /* bullet-proofing */ + new_fs = get_ds(); + old_fs = get_fs(); + if (from_kmem==2) + set_fs(new_fs); + while (argc-- > 0) { + if (from_kmem == 1) + set_fs(new_fs); + if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc))) + panic("argc is wrong"); + if (from_kmem == 1) + set_fs(old_fs); + len=0; /* remember zero-padding */ + do { + len++; + } while (get_fs_byte(tmp++)); + if (p-len < 0) { /* this shouldn't happen - 128kB */ + set_fs(old_fs); + return 0; + } + while (len) { + --p; --tmp; --len; + if (--offset < 0) { + offset = p % PAGE_SIZE; + if (from_kmem==2) + set_fs(old_fs); + if (!(pag = (char *) page[p/PAGE_SIZE]) && + !(pag = (char *) page[p/PAGE_SIZE] = + (unsigned long *) get_free_page())) + return 0; + if (from_kmem==2) + set_fs(new_fs); + + } + *(pag + offset) = get_fs_byte(tmp); + } + } + if (from_kmem==2) + set_fs(old_fs); + return p; +} + +static unsigned long change_ldt(unsigned long text_size,unsigned long * page) +{ + unsigned long code_limit,data_limit,code_base,data_base; + int i; + + code_limit = TASK_SIZE; + data_limit = TASK_SIZE; + 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 - LIBRARY_SIZE; + for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) { + data_base -= PAGE_SIZE; + if (page[i]) + put_dirty_page(page[i],data_base); + } + return data_limit; +} + +/* + * 'do_execve()' executes a new program. + * + * NOTE! We leave 4MB free at the top of the data-area for a loadable + * library. + */ +int do_execve(unsigned long * eip,long tmp,char * filename, + char ** argv, char ** envp) +{ + struct m_inode * inode; + struct buffer_head * bh; + struct exec ex; + unsigned long page[MAX_ARG_PAGES]; + int i,argc,envc; + int e_uid, e_gid; + int retval; + int sh_bang = 0; + unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4; + + if ((0xffff & eip[1]) != 0x000f) + panic("execve called from supervisor mode"); + for (i=0 ; ii_mode)) { /* must be regular file */ + retval = -EACCES; + goto exec_error2; + } + i = inode->i_mode; + e_uid = (i & S_ISUID) ? inode->i_uid : current->euid; + e_gid = (i & S_ISGID) ? inode->i_gid : current->egid; + if (current->euid == inode->i_uid) + i >>= 6; + else if (in_group_p(inode->i_gid)) + i >>= 3; + if (!(i & 1) && + !((inode->i_mode & 0111) && suser())) { + retval = -ENOEXEC; + goto exec_error2; + } + if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) { + retval = -EACCES; + goto exec_error2; + } + ex = *((struct exec *) bh->b_data); /* read exec-header */ + if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) { + /* + * This section does the #! interpretation. + * Sorta complicated, but hopefully it will work. -TYT + */ + + char buf[128], *cp, *interp, *i_name, *i_arg; + unsigned long old_fs; + + strncpy(buf, bh->b_data+2, 127); + brelse(bh); + iput(inode); + buf[127] = '\0'; + if (cp = strchr(buf, '\n')) { + *cp = '\0'; + for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++); + } + if (!cp || *cp == '\0') { + retval = -ENOEXEC; /* No interpreter name found */ + goto exec_error1; + } + interp = i_name = cp; + i_arg = 0; + for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) { + if (*cp == '/') + i_name = cp+1; + } + if (*cp) { + *cp++ = '\0'; + i_arg = cp; + } + /* + * OK, we've parsed out the interpreter name and + * (optional) argument. + */ + if (sh_bang++ == 0) { + p = copy_strings(envc, envp, page, p, 0); + p = copy_strings(--argc, argv+1, page, p, 0); + } + /* + * Splice in (1) the interpreter's name for argv[0] + * (2) (optional) argument to interpreter + * (3) filename of shell script + * + * This is done in reverse order, because of how the + * user environment and arguments are stored. + */ + p = copy_strings(1, &filename, page, p, 1); + argc++; + if (i_arg) { + p = copy_strings(1, &i_arg, page, p, 2); + argc++; + } + p = copy_strings(1, &i_name, page, p, 2); + argc++; + if (!p) { + retval = -ENOMEM; + goto exec_error1; + } + /* + * OK, now restart the process with the interpreter's inode. + */ + old_fs = get_fs(); + set_fs(get_ds()); + if (!(inode=namei(interp))) { /* get executables inode */ + set_fs(old_fs); + retval = -ENOENT; + goto exec_error1; + } + set_fs(old_fs); + goto restart_interp; + } + brelse(bh); + if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize || + ex.a_text+ex.a_data+ex.a_bss>0x3000000 || + inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { + retval = -ENOEXEC; + goto exec_error2; + } + if (N_TXTOFF(ex) != BLOCK_SIZE) { + printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename); + retval = -ENOEXEC; + goto exec_error2; + } + if (!sh_bang) { + p = copy_strings(envc,envp,page,p,0); + p = copy_strings(argc,argv,page,p,0); + if (!p) { + retval = -ENOMEM; + goto exec_error2; + } + } +/* OK, This is the point of no return */ +/* note that current->library stays unchanged by an exec */ + if (current->executable) + iput(current->executable); + current->executable = inode; + current->signal = 0; + for (i=0 ; i<32 ; i++) { + current->sigaction[i].sa_mask = 0; + current->sigaction[i].sa_flags = 0; + if (current->sigaction[i].sa_handler != SIG_IGN) + current->sigaction[i].sa_handler = NULL; + } + for (i=0 ; iclose_on_exec>>i)&1) + sys_close(i); + current->close_on_exec = 0; + free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); + free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); + if (last_task_used_math == current) + last_task_used_math = NULL; + current->used_math = 0; + p += change_ldt(ex.a_text,page); + p -= LIBRARY_SIZE + MAX_ARG_PAGES*PAGE_SIZE; + p = (unsigned long) create_tables((char *)p,argc,envc); + current->brk = ex.a_bss + + (current->end_data = ex.a_data + + (current->end_code = ex.a_text)); + current->start_stack = p & 0xfffff000; + current->suid = current->euid = e_uid; + current->sgid = current->egid = e_gid; + eip[0] = ex.a_entry; /* eip, magic happens :-) */ + eip[3] = p; /* stack pointer */ + return 0; +exec_error2: + iput(inode); +exec_error1: + for (i=0 ; i +#include +#include +#include +#include + +#include +#include + +extern int sys_close(int fd); + +static int dupfd(unsigned int fd, unsigned int arg) +{ + if (fd >= NR_OPEN || !current->filp[fd]) + return -EBADF; + if (arg >= NR_OPEN) + return -EINVAL; + while (arg < NR_OPEN) + if (current->filp[arg]) + arg++; + else + break; + if (arg >= NR_OPEN) + return -EMFILE; + current->close_on_exec &= ~(1<filp[arg] = current->filp[fd])->f_count++; + return arg; +} + +int sys_dup2(unsigned int oldfd, unsigned int newfd) +{ + sys_close(newfd); + return dupfd(oldfd,newfd); +} + +int sys_dup(unsigned int fildes) +{ + return dupfd(fildes,0); +} + +int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + switch (cmd) { + case F_DUPFD: + return dupfd(fd,arg); + case F_GETFD: + return (current->close_on_exec>>fd)&1; + case F_SETFD: + if (arg&1) + current->close_on_exec |= (1<close_on_exec &= ~(1<f_flags; + case F_SETFL: + filp->f_flags &= ~(O_APPEND | O_NONBLOCK); + filp->f_flags |= arg & (O_APPEND | O_NONBLOCK); + return 0; + case F_GETLK: case F_SETLK: case F_SETLKW: + return -1; + default: + return -1; + } +} diff --git a/kernel/0.1x/linux-0.12/fs/file_dev.c b/kernel/0.1x/linux-0.12/fs/file_dev.c new file mode 100644 index 00000000..42eaf37a --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/file_dev.c @@ -0,0 +1,90 @@ +/* + * linux/fs/file_dev.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) +{ + int left,chars,nr; + struct buffer_head * bh; + + if ((left=count)<=0) + return 0; + while (left) { + if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) { + if (!(bh=bread(inode->i_dev,nr))) + break; + } else + bh = NULL; + nr = filp->f_pos % BLOCK_SIZE; + chars = MIN( BLOCK_SIZE-nr , left ); + filp->f_pos += chars; + left -= chars; + if (bh) { + char * p = nr + bh->b_data; + while (chars-->0) + put_fs_byte(*(p++),buf++); + brelse(bh); + } else { + while (chars-->0) + put_fs_byte(0,buf++); + } + } + inode->i_atime = CURRENT_TIME; + return (count-left)?(count-left):-ERROR; +} + +int file_write(struct m_inode * inode, struct file * filp, char * buf, int count) +{ + off_t pos; + int block,c; + struct buffer_head * bh; + char * p; + int i=0; + +/* + * ok, append may not work when many processes are writing at the same time + * but so what. That way leads to madness anyway. + */ + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + else + pos = filp->f_pos; + while (ii_dev,block))) + break; + c = pos % BLOCK_SIZE; + p = c + bh->b_data; + bh->b_dirt = 1; + c = BLOCK_SIZE-c; + if (c > count-i) c = count-i; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + i += c; + while (c-->0) + *(p++) = get_fs_byte(buf++); + brelse(bh); + } + inode->i_mtime = CURRENT_TIME; + if (!(filp->f_flags & O_APPEND)) { + filp->f_pos = pos; + inode->i_ctime = CURRENT_TIME; + } + return (i?i:-1); +} diff --git a/kernel/0.1x/linux-0.12/fs/file_table.c b/kernel/0.1x/linux-0.12/fs/file_table.c new file mode 100644 index 00000000..0cf8b1b8 --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/file_table.c @@ -0,0 +1,9 @@ +/* + * linux/fs/file_table.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +struct file file_table[NR_FILE]; diff --git a/kernel/0.1x/linux-0.12/fs/inode.c b/kernel/0.1x/linux-0.12/fs/inode.c new file mode 100644 index 00000000..0d807714 --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/inode.c @@ -0,0 +1,348 @@ +/* + * linux/fs/inode.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include + +extern int *blk_size[]; + +struct m_inode inode_table[NR_INODE]={{0,},}; + +static void read_inode(struct m_inode * inode); +static void write_inode(struct m_inode * inode); + +static inline void wait_on_inode(struct m_inode * inode) +{ + cli(); + while (inode->i_lock) + sleep_on(&inode->i_wait); + sti(); +} + +static inline void lock_inode(struct m_inode * inode) +{ + cli(); + while (inode->i_lock) + sleep_on(&inode->i_wait); + inode->i_lock=1; + sti(); +} + +static inline void unlock_inode(struct m_inode * inode) +{ + inode->i_lock=0; + wake_up(&inode->i_wait); +} + +void invalidate_inodes(int dev) +{ + int i; + struct m_inode * inode; + + inode = 0+inode_table; + for(i=0 ; ii_dev == dev) { + if (inode->i_count) + printk("inode in use on removed disk\n\r"); + inode->i_dev = inode->i_dirt = 0; + } + } +} + +void sync_inodes(void) +{ + int i; + struct m_inode * inode; + + inode = 0+inode_table; + for(i=0 ; ii_dirt && !inode->i_pipe) + write_inode(inode); + } +} + +static int _bmap(struct m_inode * inode,int block,int create) +{ + struct buffer_head * bh; + int i; + + if (block<0) + panic("_bmap: block<0"); + if (block >= 7+512+512*512) + panic("_bmap: block>big"); + if (block<7) { + if (create && !inode->i_zone[block]) + if (inode->i_zone[block]=new_block(inode->i_dev)) { + inode->i_ctime=CURRENT_TIME; + inode->i_dirt=1; + } + return inode->i_zone[block]; + } + block -= 7; + if (block<512) { + if (create && !inode->i_zone[7]) + if (inode->i_zone[7]=new_block(inode->i_dev)) { + inode->i_dirt=1; + inode->i_ctime=CURRENT_TIME; + } + if (!inode->i_zone[7]) + return 0; + if (!(bh = bread(inode->i_dev,inode->i_zone[7]))) + return 0; + i = ((unsigned short *) (bh->b_data))[block]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block]=i; + bh->b_dirt=1; + } + brelse(bh); + return i; + } + block -= 512; + if (create && !inode->i_zone[8]) + if (inode->i_zone[8]=new_block(inode->i_dev)) { + inode->i_dirt=1; + inode->i_ctime=CURRENT_TIME; + } + if (!inode->i_zone[8]) + return 0; + if (!(bh=bread(inode->i_dev,inode->i_zone[8]))) + return 0; + i = ((unsigned short *)bh->b_data)[block>>9]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block>>9]=i; + bh->b_dirt=1; + } + brelse(bh); + if (!i) + return 0; + if (!(bh=bread(inode->i_dev,i))) + return 0; + i = ((unsigned short *)bh->b_data)[block&511]; + if (create && !i) + if (i=new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block&511]=i; + bh->b_dirt=1; + } + brelse(bh); + return i; +} + +int bmap(struct m_inode * inode,int block) +{ + return _bmap(inode,block,0); +} + +int create_block(struct m_inode * inode, int block) +{ + return _bmap(inode,block,1); +} + +void iput(struct m_inode * inode) +{ + if (!inode) + return; + wait_on_inode(inode); + if (!inode->i_count) + panic("iput: trying to free free inode"); + if (inode->i_pipe) { + wake_up(&inode->i_wait); + wake_up(&inode->i_wait2); + if (--inode->i_count) + return; + free_page(inode->i_size); + inode->i_count=0; + inode->i_dirt=0; + inode->i_pipe=0; + return; + } + if (!inode->i_dev) { + inode->i_count--; + return; + } + if (S_ISBLK(inode->i_mode)) { + sync_dev(inode->i_zone[0]); + wait_on_inode(inode); + } +repeat: + if (inode->i_count>1) { + inode->i_count--; + return; + } + if (!inode->i_nlinks) { + truncate(inode); + free_inode(inode); + return; + } + if (inode->i_dirt) { + write_inode(inode); /* we can sleep - so do again */ + wait_on_inode(inode); + goto repeat; + } + inode->i_count--; + return; +} + +struct m_inode * get_empty_inode(void) +{ + struct m_inode * inode; + static struct m_inode * last_inode = inode_table; + int i; + + do { + inode = NULL; + for (i = NR_INODE; i ; i--) { + if (++last_inode >= inode_table + NR_INODE) + last_inode = inode_table; + if (!last_inode->i_count) { + inode = last_inode; + if (!inode->i_dirt && !inode->i_lock) + break; + } + } + if (!inode) { + for (i=0 ; ii_dirt) { + write_inode(inode); + wait_on_inode(inode); + } + } while (inode->i_count); + memset(inode,0,sizeof(*inode)); + inode->i_count = 1; + return inode; +} + +struct m_inode * get_pipe_inode(void) +{ + struct m_inode * inode; + + if (!(inode = get_empty_inode())) + return NULL; + if (!(inode->i_size=get_free_page())) { + inode->i_count = 0; + return NULL; + } + inode->i_count = 2; /* sum of readers/writers */ + PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0; + inode->i_pipe = 1; + return inode; +} + +struct m_inode * iget(int dev,int nr) +{ + struct m_inode * inode, * empty; + + if (!dev) + panic("iget with dev==0"); + empty = get_empty_inode(); + inode = inode_table; + while (inode < NR_INODE+inode_table) { + if (inode->i_dev != dev || inode->i_num != nr) { + inode++; + continue; + } + wait_on_inode(inode); + if (inode->i_dev != dev || inode->i_num != nr) { + inode = inode_table; + continue; + } + inode->i_count++; + if (inode->i_mount) { + int i; + + for (i = 0 ; i= NR_SUPER) { + printk("Mounted inode hasn't got sb\n"); + if (empty) + iput(empty); + return inode; + } + iput(inode); + dev = super_block[i].s_dev; + nr = ROOT_INO; + inode = inode_table; + continue; + } + if (empty) + iput(empty); + return inode; + } + if (!empty) + return (NULL); + inode=empty; + inode->i_dev = dev; + inode->i_num = nr; + read_inode(inode); + return inode; +} + +static void read_inode(struct m_inode * inode) +{ + struct super_block * sb; + struct buffer_head * bh; + int block; + + lock_inode(inode); + if (!(sb=get_super(inode->i_dev))) + panic("trying to read inode without dev"); + block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks + + (inode->i_num-1)/INODES_PER_BLOCK; + if (!(bh=bread(inode->i_dev,block))) + panic("unable to read i-node block"); + *(struct d_inode *)inode = + ((struct d_inode *)bh->b_data) + [(inode->i_num-1)%INODES_PER_BLOCK]; + brelse(bh); + if (S_ISBLK(inode->i_mode)) { + int i = inode->i_zone[0]; + if (blk_size[MAJOR(i)]) + inode->i_size = 1024*blk_size[MAJOR(i)][MINOR(i)]; + else + inode->i_size = 0x7fffffff; + } + unlock_inode(inode); +} + +static void write_inode(struct m_inode * inode) +{ + struct super_block * sb; + struct buffer_head * bh; + int block; + + lock_inode(inode); + if (!inode->i_dirt || !inode->i_dev) { + unlock_inode(inode); + return; + } + if (!(sb=get_super(inode->i_dev))) + panic("trying to write inode without device"); + block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks + + (inode->i_num-1)/INODES_PER_BLOCK; + if (!(bh=bread(inode->i_dev,block))) + panic("unable to read i-node block"); + ((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/kernel/0.1x/linux-0.12/fs/ioctl.c b/kernel/0.1x/linux-0.12/fs/ioctl.c new file mode 100644 index 00000000..f2dbccf5 --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/ioctl.c @@ -0,0 +1,49 @@ +/* + * linux/fs/ioctl.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include + +extern int tty_ioctl(int dev, int cmd, int arg); +extern int pipe_ioctl(struct m_inode *pino, 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; + if (filp->f_inode->i_pipe) + return (filp->f_mode&1)?pipe_ioctl(filp->f_inode,cmd,arg):-EBADF; + mode=filp->f_inode->i_mode; + if (!S_ISCHR(mode) && !S_ISBLK(mode)) + return -EINVAL; + dev = filp->f_inode->i_zone[0]; + if (MAJOR(dev) >= NRDEVS) + return -ENODEV; + if (!ioctl_table[MAJOR(dev)]) + return -ENOTTY; + return ioctl_table[MAJOR(dev)](dev,cmd,arg); +} diff --git a/kernel/0.1x/linux-0.12/fs/namei.c b/kernel/0.1x/linux-0.12/fs/namei.c new file mode 100644 index 00000000..8f6289f7 --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/namei.c @@ -0,0 +1,894 @@ +/* + * linux/fs/namei.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * Some corrections by tytso. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +static struct m_inode * _namei(const char * filename, struct m_inode * base, + int follow_links); + +#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE]) + +/* + * comment out this line if you want names > NAME_LEN chars to be + * truncated. Else they will be disallowed. + */ +/* #define NO_TRUNCATE */ + +#define MAY_EXEC 1 +#define MAY_WRITE 2 +#define MAY_READ 4 + +/* + * permission() + * + * is used to check for read/write/execute permissions on a file. + * I don't know if we should look at just the euid or both euid and + * uid, but that should be easily changed. + */ +static int permission(struct m_inode * inode,int mask) +{ + int mode = inode->i_mode; + +/* special case: not even root can read/write a deleted file */ + if (inode->i_dev && !inode->i_nlinks) + return 0; + else if (current->euid==inode->i_uid) + mode >>= 6; + else if (in_group_p(inode->i_gid)) + mode >>= 3; + if (((mode & mask & 0007) == mask) || suser()) + return 1; + return 0; +} + +/* + * ok, we cannot use strncmp, as the name is not in our data space. + * Thus we'll have to use match. No big problem. Match also makes + * some sanity tests. + * + * NOTE! unlike strncmp, match returns 1 for success, 0 for failure. + */ +static int match(int len,const char * name,struct dir_entry * de) +{ + register int same __asm__("ax"); + + if (!de || !de->inode || len > NAME_LEN) + return 0; + /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ + if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) + return 1; + 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 an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + * + * This also takes care of the few special cases due to '..'-traversal + * over a pseudo-root and a mount point. + */ +static struct buffer_head * find_entry(struct m_inode ** dir, + const char * name, int namelen, struct dir_entry ** res_dir) +{ + int entries; + int block,i; + struct buffer_head * bh; + struct dir_entry * de; + struct super_block * sb; + +#ifdef NO_TRUNCATE + if (namelen > NAME_LEN) + return NULL; +#else + if (namelen > NAME_LEN) + namelen = NAME_LEN; +#endif + entries = (*dir)->i_size / (sizeof (struct dir_entry)); + *res_dir = NULL; +/* check for '..', as we might have to do some "magic" for it */ + if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') { +/* '..' in a pseudo-root results in a faked '.' (just change namelen) */ + if ((*dir) == current->root) + namelen=1; + else if ((*dir)->i_num == ROOT_INO) { +/* '..' over a mount-point results in 'dir' being exchanged for the mounted + directory-inode. NOTE! We set mounted, so that we can iput the new dir */ + sb=get_super((*dir)->i_dev); + if (sb->s_imount) { + iput(*dir); + (*dir)=sb->s_imount; + (*dir)->i_count++; + } + } + } + if (!(block = (*dir)->i_zone[0])) + return NULL; + if (!(bh = bread((*dir)->i_dev,block))) + return NULL; + i = 0; + de = (struct dir_entry *) bh->b_data; + while (i < entries) { + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; + if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) || + !(bh = bread((*dir)->i_dev,block))) { + i += DIR_ENTRIES_PER_BLOCK; + continue; + } + de = (struct dir_entry *) bh->b_data; + } + if (match(namelen,name,de)) { + *res_dir = de; + return bh; + } + de++; + i++; + } + brelse(bh); + return NULL; +} + +/* + * add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as find_entry(). It returns NULL if it failed. + * + * NOTE!! The inode part of 'de' is left at 0 - which means you + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ +static struct buffer_head * add_entry(struct m_inode * dir, + const char * name, int namelen, struct dir_entry ** res_dir) +{ + int block,i; + struct buffer_head * bh; + struct dir_entry * de; + + *res_dir = NULL; +#ifdef NO_TRUNCATE + if (namelen > NAME_LEN) + return NULL; +#else + if (namelen > NAME_LEN) + namelen = NAME_LEN; +#endif + if (!namelen) + return NULL; + if (!(block = dir->i_zone[0])) + return NULL; + if (!(bh = bread(dir->i_dev,block))) + return NULL; + i = 0; + de = (struct dir_entry *) bh->b_data; + while (1) { + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; + block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK); + if (!block) + return NULL; + if (!(bh = bread(dir->i_dev,block))) { + i += DIR_ENTRIES_PER_BLOCK; + continue; + } + de = (struct dir_entry *) bh->b_data; + } + if (i*sizeof(struct dir_entry) >= dir->i_size) { + de->inode=0; + dir->i_size = (i+1)*sizeof(struct dir_entry); + dir->i_dirt = 1; + dir->i_ctime = CURRENT_TIME; + } + if (!de->inode) { + dir->i_mtime = CURRENT_TIME; + for (i=0; i < NAME_LEN ; i++) + de->name[i]=(ib_dirt = 1; + *res_dir = de; + return bh; + } + de++; + i++; + } + brelse(bh); + return NULL; +} + +static struct m_inode * follow_link(struct m_inode * dir, struct m_inode * inode) +{ + unsigned short fs; + struct buffer_head * bh; + + if (!dir) { + dir = current->root; + dir->i_count++; + } + if (!inode) { + iput(dir); + return NULL; + } + if (!S_ISLNK(inode->i_mode)) { + iput(dir); + return inode; + } + __asm__("mov %%fs,%0":"=r" (fs)); + if (fs != 0x17 || !inode->i_zone[0] || + !(bh = bread(inode->i_dev, inode->i_zone[0]))) { + iput(dir); + iput(inode); + return NULL; + } + iput(inode); + __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); + inode = _namei(bh->b_data,dir,0); + __asm__("mov %0,%%fs"::"r" (fs)); + brelse(bh); + return inode; +} + +/* + * 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, struct m_inode * inode) +{ + char c; + const char * thisname; + struct buffer_head * bh; + int namelen,inr; + struct dir_entry * de; + struct m_inode * dir; + + if (!inode) { + inode = current->pwd; + inode->i_count++; + } + if ((c=get_fs_byte(pathname))=='/') { + iput(inode); + inode = current->root; + pathname++; + 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; + brelse(bh); + dir = inode; + if (!(inode = iget(dir->i_dev,inr))) { + iput(dir); + return NULL; + } + if (!(inode = follow_link(dir,inode))) + 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, struct m_inode * base) +{ + char c; + const char * basename; + struct m_inode * dir; + + if (!(dir = get_dir(pathname,base))) + return NULL; + basename = pathname; + while (c=get_fs_byte(pathname++)) + if (c=='/') + basename=pathname; + *namelen = pathname-basename-1; + *name = basename; + return dir; +} + +struct m_inode * _namei(const char * pathname, struct m_inode * base, + int follow_links) +{ + const char * basename; + int inr,namelen; + struct m_inode * inode; + struct buffer_head * bh; + struct dir_entry * de; + + if (!(base = dir_namei(pathname,&namelen,&basename,base))) + return NULL; + if (!namelen) /* special case: '/usr/' etc */ + return base; + bh = find_entry(&base,basename,namelen,&de); + if (!bh) { + iput(base); + return NULL; + } + inr = de->inode; + brelse(bh); + if (!(inode = iget(base->i_dev,inr))) { + iput(base); + return NULL; + } + if (follow_links) + inode = follow_link(base,inode); + else + iput(base); + inode->i_atime=CURRENT_TIME; + inode->i_dirt=1; + return inode; +} + +struct m_inode * lnamei(const char * pathname) +{ + return _namei(pathname, NULL, 0); +} + +/* + * 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) +{ + return _namei(pathname,NULL,1); +} + +/* + * 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,NULL))) + return -ENOENT; + if (!namelen) { /* special case: '/usr/' etc */ + if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) { + *res_inode=dir; + return 0; + } + iput(dir); + return -EISDIR; + } + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + if (!(flag & O_CREAT)) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EACCES; + } + inode = new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_uid = current->euid; + inode->i_mode = mode; + inode->i_dirt = 1; + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + inode->i_nlinks--; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->inode = inode->i_num; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + *res_inode = inode; + return 0; + } + inr = de->inode; + dev = dir->i_dev; + brelse(bh); + if (flag & O_EXCL) { + iput(dir); + return -EEXIST; + } + if (!(inode = follow_link(dir,iget(dev,inr)))) + return -EACCES; + if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) || + !permission(inode,ACC_MODE(flag))) { + iput(inode); + return -EPERM; + } + inode->i_atime = CURRENT_TIME; + if (flag & O_TRUNC) + truncate(inode); + *res_inode = inode; + return 0; +} + +int sys_mknod(const char * filename, int mode, int dev) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh; + struct dir_entry * de; + + if (!suser()) + return -EPERM; + if (!(dir = dir_namei(filename,&namelen,&basename, NULL))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + bh = find_entry(&dir,basename,namelen,&de); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_mode = mode; + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_zone[0] = dev; + inode->i_mtime = inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + iput(dir); + inode->i_nlinks=0; + iput(inode); + return -ENOSPC; + } + de->inode = inode->i_num; + bh->b_dirt = 1; + iput(dir); + iput(inode); + brelse(bh); + return 0; +} + +int sys_mkdir(const char * pathname, int mode) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh, *dir_block; + struct dir_entry * de; + + if (!(dir = dir_namei(pathname,&namelen,&basename, NULL))) + 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); + 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); + inode->i_nlinks=0; + iput(inode); + return -ENOSPC; + } + de->inode = inode->i_num; + bh->b_dirt = 1; + dir->i_nlinks++; + dir->i_dirt = 1; + iput(dir); + iput(inode); + brelse(bh); + return 0; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +static int empty_dir(struct m_inode * inode) +{ + int nr,block; + int len; + struct buffer_head * bh; + struct dir_entry * de; + + len = inode->i_size / sizeof (struct dir_entry); + if (len<2 || !inode->i_zone[0] || + !(bh=bread(inode->i_dev,inode->i_zone[0]))) { + printk("warning - bad directory on dev %04x\n",inode->i_dev); + return 0; + } + de = (struct dir_entry *) bh->b_data; + if (de[0].inode != inode->i_num || !de[1].inode || + strcmp(".",de[0].name) || strcmp("..",de[1].name)) { + printk("warning - bad directory on dev %04x\n",inode->i_dev); + return 0; + } + nr = 2; + de += 2; + while (nr= (void *) (bh->b_data+BLOCK_SIZE)) { + brelse(bh); + block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK); + if (!block) { + nr += DIR_ENTRIES_PER_BLOCK; + continue; + } + if (!(bh=bread(inode->i_dev,block))) + return 0; + de = (struct dir_entry *) bh->b_data; + } + if (de->inode) { + brelse(bh); + return 0; + } + de++; + nr++; + } + brelse(bh); + return 1; +} + +int sys_rmdir(const char * name) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh; + struct dir_entry * de; + + if (!(dir = dir_namei(name,&namelen,&basename, NULL))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + iput(dir); + return -ENOENT; + } + if (!(inode = iget(dir->i_dev, de->inode))) { + iput(dir); + brelse(bh); + return -EPERM; + } + if ((dir->i_mode & S_ISVTX) && current->euid && + inode->i_uid != current->euid) { + iput(dir); + iput(inode); + brelse(bh); + return -EPERM; + } + if (inode->i_dev != dir->i_dev || inode->i_count>1) { + iput(dir); + iput(inode); + brelse(bh); + return -EPERM; + } + if (inode == dir) { /* we may not delete ".", but "../dir" is ok */ + iput(inode); + iput(dir); + brelse(bh); + return -EPERM; + } + if (!S_ISDIR(inode->i_mode)) { + iput(inode); + iput(dir); + brelse(bh); + return -ENOTDIR; + } + if (!empty_dir(inode)) { + iput(inode); + iput(dir); + brelse(bh); + return -ENOTEMPTY; + } + if (inode->i_nlinks != 2) + printk("empty directory has nlink!=2 (%d)",inode->i_nlinks); + de->inode = 0; + bh->b_dirt = 1; + brelse(bh); + inode->i_nlinks=0; + inode->i_dirt=1; + dir->i_nlinks--; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt=1; + iput(dir); + iput(inode); + return 0; +} + +int sys_unlink(const char * name) +{ + const char * basename; + int namelen; + struct m_inode * dir, * inode; + struct buffer_head * bh; + struct dir_entry * de; + + if (!(dir = dir_namei(name,&namelen,&basename, NULL))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + bh = find_entry(&dir,basename,namelen,&de); + if (!bh) { + iput(dir); + return -ENOENT; + } + if (!(inode = iget(dir->i_dev, de->inode))) { + iput(dir); + brelse(bh); + return -ENOENT; + } + if ((dir->i_mode & S_ISVTX) && !suser() && + current->euid != inode->i_uid && + current->euid != dir->i_uid) { + iput(dir); + iput(inode); + brelse(bh); + return -EPERM; + } + if (S_ISDIR(inode->i_mode)) { + iput(inode); + iput(dir); + brelse(bh); + return -EPERM; + } + if (!inode->i_nlinks) { + printk("Deleting nonexistent file (%04x:%d), %d\n", + inode->i_dev,inode->i_num,inode->i_nlinks); + inode->i_nlinks=1; + } + de->inode = 0; + bh->b_dirt = 1; + brelse(bh); + inode->i_nlinks--; + inode->i_dirt = 1; + inode->i_ctime = CURRENT_TIME; + iput(inode); + iput(dir); + return 0; +} + +int sys_symlink(const char * oldname, const char * newname) +{ + struct dir_entry * de; + struct m_inode * dir, * inode; + struct buffer_head * bh, * name_block; + const char * basename; + int namelen, i; + char c; + + dir = dir_namei(newname,&namelen,&basename, NULL); + if (!dir) + return -EACCES; + if (!namelen) { + iput(dir); + return -EPERM; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EACCES; + } + if (!(inode = new_inode(dir->i_dev))) { + iput(dir); + return -ENOSPC; + } + inode->i_mode = S_IFLNK | (0777 & ~current->umask); + inode->i_dirt = 1; + if (!(inode->i_zone[0]=new_block(inode->i_dev))) { + iput(dir); + inode->i_nlinks--; + iput(inode); + return -ENOSPC; + } + inode->i_dirt = 1; + if (!(name_block=bread(inode->i_dev,inode->i_zone[0]))) { + iput(dir); + inode->i_nlinks--; + iput(inode); + return -ERROR; + } + i = 0; + while (i < 1023 && (c=get_fs_byte(oldname++))) + name_block->b_data[i++] = c; + name_block->b_data[i] = 0; + name_block->b_dirt = 1; + brelse(name_block); + inode->i_size = i; + inode->i_dirt = 1; + bh = find_entry(&dir,basename,namelen,&de); + if (bh) { + inode->i_nlinks--; + iput(inode); + brelse(bh); + iput(dir); + return -EEXIST; + } + 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); + iput(inode); + 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_ISDIR(oldinode->i_mode)) { + iput(oldinode); + return -EPERM; + } + dir = dir_namei(newname,&namelen,&basename, NULL); + 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/kernel/0.1x/linux-0.12/fs/open.c b/kernel/0.1x/linux-0.12/fs/open.c new file mode 100644 index 00000000..648a9ffe --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/open.c @@ -0,0 +1,235 @@ +/* + * linux/fs/open.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +int sys_ustat(int dev, struct ustat * ubuf) +{ + return -ENOSYS; +} + +int sys_utime(char * filename, struct utimbuf * times) +{ + struct m_inode * inode; + long actime,modtime; + + if (!(inode=namei(filename))) + return -ENOENT; + if (times) { + actime = get_fs_long((unsigned long *) ×->actime); + modtime = get_fs_long((unsigned long *) ×->modtime); + } else + actime = modtime = CURRENT_TIME; + inode->i_atime = actime; + inode->i_mtime = modtime; + inode->i_dirt = 1; + iput(inode); + return 0; +} + +/* + * XXX should we use the real or effective uid? BSD uses the real uid, + * so as to make this call useful to setuid programs. + */ +int sys_access(const char * filename,int mode) +{ + struct m_inode * inode; + int res, i_mode; + + mode &= 0007; + if (!(inode=namei(filename))) + return -EACCES; + i_mode = res = inode->i_mode & 0777; + iput(inode); + if (current->uid == inode->i_uid) + res >>= 6; + else if (current->gid == inode->i_gid) + res >>= 6; + if ((res & 0007 & mode) == mode) + return 0; + /* + * XXX we are doing this test last because we really should be + * swapping the effective with the real user id (temporarily), + * and then calling suser() routine. If we do call the + * suser() routine, it needs to be called last. + */ + if ((!current->uid) && + (!(mode & 1) || (i_mode & 0111))) + return 0; + return -EACCES; +} + +int sys_chdir(const char * filename) +{ + struct m_inode * inode; + + if (!(inode = namei(filename))) + return -ENOENT; + if (!S_ISDIR(inode->i_mode)) { + iput(inode); + return -ENOTDIR; + } + iput(current->pwd); + current->pwd = inode; + return (0); +} + +int sys_chroot(const char * filename) +{ + struct m_inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if (!S_ISDIR(inode->i_mode)) { + iput(inode); + return -ENOTDIR; + } + iput(current->root); + current->root = inode; + return (0); +} + +int sys_chmod(const char * filename,int mode) +{ + struct m_inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if ((current->euid != inode->i_uid) && !suser()) { + iput(inode); + return -EACCES; + } + inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777); + inode->i_dirt = 1; + iput(inode); + return 0; +} + +int sys_chown(const char * filename,int uid,int gid) +{ + struct m_inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if (!suser()) { + iput(inode); + return -EACCES; + } + inode->i_uid=uid; + inode->i_gid=gid; + inode->i_dirt=1; + iput(inode); + return 0; +} + +static int check_char_dev(struct m_inode * inode, int dev, int flag) +{ + struct tty_struct *tty; + int min; + + if (MAJOR(dev) == 4 || MAJOR(dev) == 5) { + if (MAJOR(dev) == 5) + min = current->tty; + else + min = MINOR(dev); + if (min < 0) + return -1; + if ((IS_A_PTY_MASTER(min)) && (inode->i_count>1)) + return -1; + tty = TTY_TABLE(min); + if (!(flag & O_NOCTTY) && + current->leader && + current->tty<0 && + tty->session==0) { + current->tty = min; + tty->session= current->session; + tty->pgrp = current->pgrp; + } + if (flag & O_NONBLOCK) { + TTY_TABLE(min)->termios.c_cc[VMIN] =0; + TTY_TABLE(min)->termios.c_cc[VTIME] =0; + TTY_TABLE(min)->termios.c_lflag &= ~ICANON; + } + } + return 0; +} + +int sys_open(const char * filename,int flag,int mode) +{ + struct m_inode * inode; + struct file * f; + int i,fd; + + mode &= 0777 & ~current->umask; + for(fd=0 ; fdfilp[fd]) + break; + if (fd>=NR_OPEN) + return -EINVAL; + current->close_on_exec &= ~(1<f_count) break; + if (i>=NR_FILE) + return -EINVAL; + (current->filp[fd]=f)->f_count++; + if ((i=open_namei(filename,flag,mode,&inode))<0) { + current->filp[fd]=NULL; + f->f_count=0; + return i; + } +/* ttys are somewhat special (ttyxx major==4, tty major==5) */ + if (S_ISCHR(inode->i_mode)) + if (check_char_dev(inode,inode->i_zone[0],flag)) { + iput(inode); + current->filp[fd]=NULL; + f->f_count=0; + return -EAGAIN; + } +/* Likewise with block-devices: check for floppy_change */ + if (S_ISBLK(inode->i_mode)) + check_disk_change(inode->i_zone[0]); + f->f_mode = inode->i_mode; + f->f_flags = flag; + f->f_count = 1; + f->f_inode = inode; + f->f_pos = 0; + return (fd); +} + +int sys_creat(const char * pathname, int mode) +{ + return sys_open(pathname, O_CREAT | O_TRUNC, mode); +} + +int sys_close(unsigned int fd) +{ + struct file * filp; + + if (fd >= NR_OPEN) + return -EINVAL; + current->close_on_exec &= ~(1<filp[fd])) + return -EINVAL; + current->filp[fd] = NULL; + if (filp->f_count == 0) + panic("Close: file count is 0"); + if (--filp->f_count) + return (0); + iput(filp->f_inode); + return (0); +} diff --git a/kernel/0.1x/linux-0.12/fs/pipe.c b/kernel/0.1x/linux-0.12/fs/pipe.c new file mode 100644 index 00000000..c4dc6a62 --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/pipe.c @@ -0,0 +1,128 @@ +/* + * linux/fs/pipe.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include /* for get_free_page */ +#include +#include + +int read_pipe(struct m_inode * inode, char * buf, int count) +{ + int chars, size, read = 0; + + while (count>0) { + while (!(size=PIPE_SIZE(*inode))) { + wake_up(& PIPE_WRITE_WAIT(*inode)); + if (inode->i_count != 2) /* are there any writers? */ + return read; + if (current->signal & ~current->blocked) + return read?read:-ERESTARTSYS; + interruptible_sleep_on(& PIPE_READ_WAIT(*inode)); + } + chars = PAGE_SIZE-PIPE_TAIL(*inode); + if (chars > count) + chars = count; + if (chars > size) + chars = size; + count -= chars; + read += chars; + size = PIPE_TAIL(*inode); + PIPE_TAIL(*inode) += chars; + PIPE_TAIL(*inode) &= (PAGE_SIZE-1); + while (chars-->0) + put_fs_byte(((char *)inode->i_size)[size++],buf++); + } + wake_up(& PIPE_WRITE_WAIT(*inode)); + return read; +} + +int write_pipe(struct m_inode * inode, char * buf, int count) +{ + int chars, size, written = 0; + + while (count>0) { + while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) { + wake_up(& PIPE_READ_WAIT(*inode)); + if (inode->i_count != 2) { /* no readers */ + current->signal |= (1<<(SIGPIPE-1)); + return written?written:-1; + } + sleep_on(& PIPE_WRITE_WAIT(*inode)); + } + chars = PAGE_SIZE-PIPE_HEAD(*inode); + if (chars > count) + chars = count; + if (chars > size) + chars = size; + count -= chars; + written += chars; + size = PIPE_HEAD(*inode); + PIPE_HEAD(*inode) += chars; + PIPE_HEAD(*inode) &= (PAGE_SIZE-1); + while (chars-->0) + ((char *)inode->i_size)[size++]=get_fs_byte(buf++); + } + wake_up(& PIPE_READ_WAIT(*inode)); + return written; +} + +int sys_pipe(unsigned long * fildes) +{ + struct m_inode * inode; + struct file * f[2]; + int fd[2]; + int i,j; + + j=0; + for(i=0;j<2 && if_count++; + if (j==1) + f[0]->f_count=0; + if (j<2) + return -1; + j=0; + for(i=0;j<2 && ifilp[i]) { + current->filp[ fd[j]=i ] = f[j]; + j++; + } + if (j==1) + current->filp[fd[0]]=NULL; + if (j<2) { + f[0]->f_count=f[1]->f_count=0; + return -1; + } + if (!(inode=get_pipe_inode())) { + current->filp[fd[0]] = + current->filp[fd[1]] = NULL; + f[0]->f_count = f[1]->f_count = 0; + return -1; + } + f[0]->f_inode = f[1]->f_inode = inode; + f[0]->f_pos = f[1]->f_pos = 0; + f[0]->f_mode = 1; /* read */ + f[1]->f_mode = 2; /* write */ + put_fs_long(fd[0],0+fildes); + put_fs_long(fd[1],1+fildes); + return 0; +} + +int pipe_ioctl(struct m_inode *pino, int cmd, int arg) +{ + switch (cmd) { + case FIONREAD: + verify_area((void *) arg,4); + put_fs_long(PIPE_SIZE(*pino),(unsigned long *) arg); + return 0; + default: + return -EINVAL; + } +} diff --git a/kernel/0.1x/linux-0.12/fs/read_write.c b/kernel/0.1x/linux-0.12/fs/read_write.c new file mode 100644 index 00000000..b6c96fde --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/read_write.c @@ -0,0 +1,103 @@ +/* + * linux/fs/read_write.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include +#include + +extern int rw_char(int rw,int dev, char * buf, int count, off_t * pos); +extern int read_pipe(struct m_inode * inode, char * buf, int count); +extern int write_pipe(struct m_inode * inode, char * buf, int count); +extern int block_read(int dev, off_t * pos, char * buf, int count); +extern int block_write(int dev, off_t * pos, char * buf, int count); +extern int file_read(struct m_inode * inode, struct file * filp, + char * buf, int count); +extern int file_write(struct m_inode * inode, struct file * filp, + char * buf, int count); + +int sys_lseek(unsigned int fd,off_t offset, int origin) +{ + struct file * file; + int tmp; + + if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode) + || !IS_SEEKABLE(MAJOR(file->f_inode->i_dev))) + return -EBADF; + if (file->f_inode->i_pipe) + return -ESPIPE; + switch (origin) { + case 0: + if (offset<0) return -EINVAL; + file->f_pos=offset; + break; + case 1: + if (file->f_pos+offset<0) return -EINVAL; + file->f_pos += offset; + break; + case 2: + if ((tmp=file->f_inode->i_size+offset) < 0) + return -EINVAL; + file->f_pos = tmp; + break; + default: + return -EINVAL; + } + return file->f_pos; +} + +int sys_read(unsigned int fd,char * buf,int count) +{ + struct file * file; + struct m_inode * inode; + + if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd])) + return -EINVAL; + if (!count) + return 0; + verify_area(buf,count); + inode = file->f_inode; + if (inode->i_pipe) + return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO; + if (S_ISCHR(inode->i_mode)) + return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos); + if (S_ISBLK(inode->i_mode)) + return block_read(inode->i_zone[0],&file->f_pos,buf,count); + if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) { + if (count+file->f_pos > inode->i_size) + count = inode->i_size - file->f_pos; + if (count<=0) + return 0; + return file_read(inode,file,buf,count); + } + printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode); + return -EINVAL; +} + +int sys_write(unsigned int fd,char * buf,int count) +{ + struct file * file; + struct m_inode * inode; + + if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd])) + return -EINVAL; + if (!count) + return 0; + inode=file->f_inode; + if (inode->i_pipe) + return (file->f_mode&2)?write_pipe(inode,buf,count):-EIO; + if (S_ISCHR(inode->i_mode)) + return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos); + if (S_ISBLK(inode->i_mode)) + return block_write(inode->i_zone[0],&file->f_pos,buf,count); + if (S_ISREG(inode->i_mode)) + return file_write(inode,file,buf,count); + printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode); + return -EINVAL; +} diff --git a/kernel/0.1x/linux-0.12/fs/select.c b/kernel/0.1x/linux-0.12/fs/select.c new file mode 100644 index 00000000..0598c354 --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/select.c @@ -0,0 +1,278 @@ +/* + * This file contains the procedures for the handling of select + * + * Created for Linux based loosely upon Mathius Lattner's minix + * patches by Peter MacDonald. Heavily edited by Linus. + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * Ok, Peter made a complicated, but straightforward multiple_wait() function. + * I have rewritten this, taking some shortcuts: This code may not be easy to + * follow, but it should be free of race-conditions, and it's practical. If you + * understand what I'm doing here, then you understand how the linux sleep/wakeup + * mechanism works. + * + * Two very simple procedures, add_wait() and free_wait() make all the work. We + * have to have interrupts disabled throughout the select, but that's not really + * such a loss: sleeping automatically frees interrupts when we aren't in this + * task. + */ + +typedef struct { + struct task_struct * old_task; + struct task_struct ** wait_address; +} wait_entry; + +typedef struct { + int nr; + wait_entry entry[NR_OPEN*3]; +} select_table; + +static void add_wait(struct task_struct ** wait_address, select_table * p) +{ + int i; + + if (!wait_address) + return; + for (i = 0 ; i < p->nr ; i++) + if (p->entry[i].wait_address == wait_address) + return; + p->entry[p->nr].wait_address = wait_address; + p->entry[p->nr].old_task = * wait_address; + *wait_address = current; + p->nr++; +} + +static void free_wait(select_table * p) +{ + int i; + struct task_struct ** tpp; + + for (i = 0; i < p->nr ; i++) { + tpp = p->entry[i].wait_address; + while (*tpp && *tpp != current) { + (*tpp)->state = 0; + current->state = TASK_UNINTERRUPTIBLE; + schedule(); + } + if (!*tpp) + printk("free_wait: NULL"); + if (*tpp = p->entry[i].old_task) + (**tpp).state = 0; + } + p->nr = 0; +} + +static struct tty_struct * get_tty(struct m_inode * inode) +{ + int major, minor; + + if (!S_ISCHR(inode->i_mode)) + return NULL; + if ((major = MAJOR(inode->i_zone[0])) != 5 && major != 4) + return NULL; + if (major == 5) + minor = current->tty; + else + minor = MINOR(inode->i_zone[0]); + if (minor < 0) + return NULL; + return TTY_TABLE(minor); +} + +/* + * The check_XX functions check out a file. We know it's either + * a pipe, a character device or a fifo (fifo's not implemented) + */ +static int check_in(select_table * wait, struct m_inode * inode) +{ + struct tty_struct * tty; + + if (tty = get_tty(inode)) + if (!EMPTY(tty->secondary)) + return 1; + else + add_wait(&tty->secondary->proc_list, wait); + else if (inode->i_pipe) + if (!PIPE_EMPTY(*inode)) + return 1; + else + add_wait(&inode->i_wait, wait); + return 0; +} + +static int check_out(select_table * wait, struct m_inode * inode) +{ + struct tty_struct * tty; + + if (tty = get_tty(inode)) + if (!FULL(tty->write_q)) + return 1; + else + add_wait(&tty->write_q->proc_list, wait); + else if (inode->i_pipe) + if (!PIPE_FULL(*inode)) + return 1; + else + add_wait(&inode->i_wait, wait); + return 0; +} + +static int check_ex(select_table * wait, struct m_inode * inode) +{ + struct tty_struct * tty; + + if (tty = get_tty(inode)) + if (!FULL(tty->write_q)) + return 0; + else + return 0; + else if (inode->i_pipe) + if (inode->i_count < 2) + return 1; + else + add_wait(&inode->i_wait,wait); + return 0; +} + +int do_select(fd_set in, fd_set out, fd_set ex, + fd_set *inp, fd_set *outp, fd_set *exp) +{ + int count; + select_table wait_table; + int i; + fd_set mask; + + mask = in | out | ex; + for (i = 0 ; i < NR_OPEN ; i++,mask >>= 1) { + if (!(mask & 1)) + continue; + if (!current->filp[i]) + return -EBADF; + if (!current->filp[i]->f_inode) + return -EBADF; + if (current->filp[i]->f_inode->i_pipe) + continue; + if (S_ISCHR(current->filp[i]->f_inode->i_mode)) + continue; + if (S_ISFIFO(current->filp[i]->f_inode->i_mode)) + continue; + return -EBADF; + } +repeat: + wait_table.nr = 0; + *inp = *outp = *exp = 0; + count = 0; + mask = 1; + for (i = 0 ; i < NR_OPEN ; i++, mask += mask) { + if (mask & in) + if (check_in(&wait_table,current->filp[i]->f_inode)) { + *inp |= mask; + count++; + } + if (mask & out) + if (check_out(&wait_table,current->filp[i]->f_inode)) { + *outp |= mask; + count++; + } + if (mask & ex) + if (check_ex(&wait_table,current->filp[i]->f_inode)) { + *exp |= mask; + count++; + } + } + if (!(current->signal & ~current->blocked) && + (wait_table.nr || current->timeout) && !count) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + free_wait(&wait_table); + goto repeat; + } + free_wait(&wait_table); + return count; +} + +/* + * Note that we cannot return -ERESTARTSYS, as we change our input + * parameters. Sad, but there you are. We could do some tweaking in + * the library function ... + */ +int sys_select( unsigned long *buffer ) +{ +/* Perform the select(nd, in, out, ex, tv) system call. */ + int i; + fd_set res_in, in = 0, *inp; + fd_set res_out, out = 0, *outp; + fd_set res_ex, ex = 0, *exp; + fd_set mask; + struct timeval *tvp; + unsigned long timeout; + + mask = ~((~0) << get_fs_long(buffer++)); + inp = (fd_set *) get_fs_long(buffer++); + outp = (fd_set *) get_fs_long(buffer++); + exp = (fd_set *) get_fs_long(buffer++); + tvp = (struct timeval *) get_fs_long(buffer); + + if (inp) + in = mask & get_fs_long(inp); + if (outp) + out = mask & get_fs_long(outp); + if (exp) + ex = mask & get_fs_long(exp); + timeout = 0xffffffff; + if (tvp) { + timeout = get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ); + timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ; + timeout += jiffies; + } + current->timeout = timeout; + cli(); + i = do_select(in, out, ex, &res_in, &res_out, &res_ex); + if (current->timeout > jiffies) + timeout = current->timeout - jiffies; + else + timeout = 0; + sti(); + current->timeout = 0; + if (i < 0) + return i; + if (inp) { + verify_area(inp, 4); + put_fs_long(res_in,inp); + } + if (outp) { + verify_area(outp,4); + put_fs_long(res_out,outp); + } + if (exp) { + verify_area(exp,4); + put_fs_long(res_ex,exp); + } + if (tvp) { + verify_area(tvp, sizeof(*tvp)); + put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec); + timeout %= HZ; + timeout *= (1000000/HZ); + put_fs_long(timeout, (unsigned long *) &tvp->tv_usec); + } + if (!i && (current->signal & ~current->blocked)) + return -EINTR; + return i; +} diff --git a/kernel/0.1x/linux-0.12/fs/stat.c b/kernel/0.1x/linux-0.12/fs/stat.c new file mode 100644 index 00000000..392b8e7f --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/stat.c @@ -0,0 +1,97 @@ +/* + * linux/fs/stat.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include + +static void cp_stat(struct m_inode * inode, struct stat * statbuf) +{ + struct stat tmp; + int i; + + verify_area(statbuf,sizeof (struct stat)); + tmp.st_dev = inode->i_dev; + tmp.st_ino = inode->i_num; + tmp.st_mode = inode->i_mode; + tmp.st_nlink = inode->i_nlinks; + tmp.st_uid = inode->i_uid; + tmp.st_gid = inode->i_gid; + tmp.st_rdev = inode->i_zone[0]; + tmp.st_size = inode->i_size; + tmp.st_atime = inode->i_atime; + tmp.st_mtime = inode->i_mtime; + tmp.st_ctime = inode->i_ctime; + for (i=0 ; i= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode)) + return -EBADF; + cp_stat(inode,statbuf); + return 0; +} + +int sys_readlink(const char * path, char * buf, int bufsiz) +{ + struct m_inode * inode; + struct buffer_head * bh; + int i; + char c; + + if (bufsiz <= 0) + return -EBADF; + if (bufsiz > 1023) + bufsiz = 1023; + verify_area(buf,bufsiz); + if (!(inode = lnamei(path))) + return -ENOENT; + if (inode->i_zone[0]) + bh = bread(inode->i_dev, inode->i_zone[0]); + else + bh = NULL; + iput(inode); + if (!bh) + return 0; + i = 0; + while (ib_data[i])) { + i++; + put_fs_byte(c,buf++); + } + brelse(bh); + return i; +} diff --git a/kernel/0.1x/linux-0.12/fs/super.c b/kernel/0.1x/linux-0.12/fs/super.c new file mode 100644 index 00000000..c75e1fed --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/super.c @@ -0,0 +1,280 @@ +/* + * linux/fs/super.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * super.c contains code to handle the super-block tables. + */ +#include +#include +#include +#include + +#include +#include + +int sync_dev(int dev); +void wait_for_keypress(void); + +/* set_bit uses setb, as gas doesn't recognize setc */ +#define set_bit(bitnr,addr) ({ \ +register int __res __asm__("ax"); \ +__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \ +__res; }) + +struct super_block super_block[NR_SUPER]; +/* this is initialized in init/main.c */ +int ROOT_DEV = 0; + +static void lock_super(struct super_block * sb) +{ + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); + sb->s_lock = 1; + sti(); +} + +static void free_super(struct super_block * sb) +{ + cli(); + sb->s_lock = 0; + wake_up(&(sb->s_wait)); + sti(); +} + +static void wait_on_super(struct super_block * sb) +{ + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); + sti(); +} + +struct super_block * get_super(int dev) +{ + struct super_block * s; + + if (!dev) + return NULL; + s = 0+super_block; + while (s < NR_SUPER+super_block) + if (s->s_dev == dev) { + wait_on_super(s); + if (s->s_dev == dev) + return s; + s = 0+super_block; + } else + s++; + return NULL; +} + +void put_super(int dev) +{ + struct super_block * sb; + int i; + + if (dev == ROOT_DEV) { + printk("root diskette changed: prepare for armageddon\n\r"); + return; + } + if (!(sb = get_super(dev))) + return; + if (sb->s_imount) { + printk("Mounted disk changed - tssk, tssk\n\r"); + return; + } + lock_super(sb); + sb->s_dev = 0; + for(i=0;is_imap[i]); + for(i=0;is_zmap[i]); + free_super(sb); + return; +} + +static struct super_block * read_super(int dev) +{ + struct super_block * s; + struct buffer_head * bh; + int i,block; + + if (!dev) + return NULL; + check_disk_change(dev); + if (s = get_super(dev)) + return s; + for (s = 0+super_block ;; s++) { + if (s >= NR_SUPER+super_block) + return NULL; + if (!s->s_dev) + break; + } + s->s_dev = dev; + s->s_isup = NULL; + s->s_imount = NULL; + s->s_time = 0; + s->s_rd_only = 0; + s->s_dirt = 0; + lock_super(s); + if (!(bh = bread(dev,1))) { + s->s_dev=0; + free_super(s); + return NULL; + } + *((struct d_super_block *) s) = + *((struct d_super_block *) bh->b_data); + brelse(bh); + if (s->s_magic != SUPER_MAGIC) { + s->s_dev = 0; + free_super(s); + return NULL; + } + for (i=0;is_imap[i] = NULL; + for (i=0;is_zmap[i] = NULL; + block=2; + for (i=0 ; i < s->s_imap_blocks ; i++) + if (s->s_imap[i]=bread(dev,block)) + block++; + else + break; + for (i=0 ; i < s->s_zmap_blocks ; i++) + if (s->s_zmap[i]=bread(dev,block)) + block++; + else + break; + if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) { + for(i=0;is_imap[i]); + for(i=0;is_zmap[i]); + s->s_dev=0; + free_super(s); + return NULL; + } + s->s_imap[0]->b_data[0] |= 1; + s->s_zmap[0]->b_data[0] |= 1; + free_super(s); + return s; +} + +int sys_umount(char * dev_name) +{ + struct m_inode * inode; + struct super_block * sb; + int dev; + + if (!(inode=namei(dev_name))) + return -ENOENT; + dev = inode->i_zone[0]; + if (!S_ISBLK(inode->i_mode)) { + iput(inode); + return -ENOTBLK; + } + iput(inode); + if (dev==ROOT_DEV) + return -EBUSY; + if (!(sb=get_super(dev)) || !(sb->s_imount)) + return -ENOENT; + if (!sb->s_imount->i_mount) + printk("Mounted inode has i_mount=0\n"); + for (inode=inode_table+0 ; inodei_dev==dev && inode->i_count) + return -EBUSY; + sb->s_imount->i_mount=0; + iput(sb->s_imount); + sb->s_imount = NULL; + iput(sb->s_isup); + sb->s_isup = NULL; + put_super(dev); + sync_dev(dev); + return 0; +} + +int sys_mount(char * dev_name, char * dir_name, int rw_flag) +{ + struct m_inode * dev_i, * dir_i; + struct super_block * sb; + int dev; + + if (!(dev_i=namei(dev_name))) + return -ENOENT; + dev = dev_i->i_zone[0]; + if (!S_ISBLK(dev_i->i_mode)) { + iput(dev_i); + return -EPERM; + } + iput(dev_i); + if (!(dir_i=namei(dir_name))) + return -ENOENT; + if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) { + iput(dir_i); + return -EBUSY; + } + if (!S_ISDIR(dir_i->i_mode)) { + iput(dir_i); + return -EPERM; + } + if (!(sb=read_super(dev))) { + iput(dir_i); + return -EBUSY; + } + if (sb->s_imount) { + iput(dir_i); + return -EBUSY; + } + if (dir_i->i_mount) { + iput(dir_i); + return -EPERM; + } + sb->s_imount=dir_i; + dir_i->i_mount=1; + dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */ + return 0; /* we do that in umount */ +} + +void mount_root(void) +{ + int i,free; + struct super_block * p; + struct m_inode * mi; + + if (32 != sizeof (struct d_inode)) + panic("bad i-node size"); + for(i=0;is_dev = 0; + p->s_lock = 0; + p->s_wait = NULL; + } + if (!(p=read_super(ROOT_DEV))) + panic("Unable to mount root"); + if (!(mi=iget(ROOT_DEV,ROOT_INO))) + panic("Unable to read root i-node"); + mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ + p->s_isup = p->s_imount = mi; + current->pwd = mi; + current->root = mi; + free=0; + i=p->s_nzones; + while (-- i >= 0) + if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data)) + free++; + printk("%d/%d free blocks\n\r",free,p->s_nzones); + free=0; + i=p->s_ninodes+1; + while (-- i >= 0) + if (!set_bit(i&8191,p->s_imap[i>>13]->b_data)) + free++; + printk("%d/%d free inodes\n\r",free,p->s_ninodes); +} diff --git a/kernel/0.1x/linux-0.12/fs/truncate.c b/kernel/0.1x/linux-0.12/fs/truncate.c new file mode 100644 index 00000000..83a66f77 --- /dev/null +++ b/kernel/0.1x/linux-0.12/fs/truncate.c @@ -0,0 +1,99 @@ +/* + * linux/fs/truncate.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include + +static int free_ind(int dev,int block) +{ + struct buffer_head * bh; + unsigned short * p; + int i; + int block_busy; + + if (!block) + return 1; + block_busy = 0; + if (bh=bread(dev,block)) { + p = (unsigned short *) bh->b_data; + for (i=0;i<512;i++,p++) + if (*p) + if (free_block(dev,*p)) { + *p = 0; + bh->b_dirt = 1; + } else + block_busy = 1; + brelse(bh); + } + if (block_busy) + return 0; + else + return free_block(dev,block); +} + +static int free_dind(int dev,int block) +{ + struct buffer_head * bh; + unsigned short * p; + int i; + int block_busy; + + if (!block) + return 1; + block_busy = 0; + if (bh=bread(dev,block)) { + p = (unsigned short *) bh->b_data; + for (i=0;i<512;i++,p++) + if (*p) + if (free_ind(dev,*p)) { + *p = 0; + bh->b_dirt = 1; + } else + block_busy = 1; + brelse(bh); + } + if (block_busy) + return 0; + else + return free_block(dev,block); +} + +void truncate(struct m_inode * inode) +{ + int i; + int block_busy; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; +repeat: + block_busy = 0; + for (i=0;i<7;i++) + if (inode->i_zone[i]) { + if (free_block(inode->i_dev,inode->i_zone[i])) + inode->i_zone[i]=0; + else + block_busy = 1; + } + if (free_ind(inode->i_dev,inode->i_zone[7])) + inode->i_zone[7] = 0; + else + block_busy = 1; + if (free_dind(inode->i_dev,inode->i_zone[8])) + inode->i_zone[8] = 0; + else + block_busy = 1; + inode->i_dirt = 1; + if (block_busy) { + current->counter = 0; + schedule(); + goto repeat; + } + inode->i_size = 0; + inode->i_mtime = inode->i_ctime = CURRENT_TIME; +} + diff --git a/kernel/0.1x/linux-0.12/include/a.out.h b/kernel/0.1x/linux-0.12/include/a.out.h new file mode 100644 index 00000000..2f5f3dcd --- /dev/null +++ b/kernel/0.1x/linux-0.12/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/kernel/0.1x/linux-0.12/include/asm/io.h b/kernel/0.1x/linux-0.12/include/asm/io.h new file mode 100644 index 00000000..53646abc --- /dev/null +++ b/kernel/0.1x/linux-0.12/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/kernel/0.1x/linux-0.12/include/asm/memory.h b/kernel/0.1x/linux-0.12/include/asm/memory.h new file mode 100644 index 00000000..dba1062f --- /dev/null +++ b/kernel/0.1x/linux-0.12/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/kernel/0.1x/linux-0.12/include/asm/segment.h b/kernel/0.1x/linux-0.12/include/asm/segment.h new file mode 100644 index 00000000..9a643e08 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/asm/segment.h @@ -0,0 +1,65 @@ +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)); +} + +/* + * Someone who knows GNU asm better than I should double check the followig. + * It seems to work, but I don't know if I'm doing something subtly wrong. + * --- TYT, 11/24/91 + * [ nothing wrong here, Linus ] + */ + +extern inline unsigned long get_fs() +{ + unsigned short _v; + __asm__("mov %%fs,%%ax":"=a" (_v):); + return _v; +} + +extern inline unsigned long get_ds() +{ + unsigned short _v; + __asm__("mov %%ds,%%ax":"=a" (_v):); + return _v; +} + +extern inline void set_fs(unsigned long val) +{ + __asm__("mov %0,%%fs"::"a" ((unsigned short) val)); +} + diff --git a/kernel/0.1x/linux-0.12/include/asm/system.h b/kernel/0.1x/linux-0.12/include/asm/system.h new file mode 100644 index 00000000..2e17653c --- /dev/null +++ b/kernel/0.1x/linux-0.12/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" \ + "mov %%ax,%%ds\n\t" \ + "mov %%ax,%%es\n\t" \ + "mov %%ax,%%fs\n\t" \ + "mov %%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/kernel/0.1x/linux-0.12/include/const.h b/kernel/0.1x/linux-0.12/include/const.h new file mode 100644 index 00000000..88e96416 --- /dev/null +++ b/kernel/0.1x/linux-0.12/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/kernel/0.1x/linux-0.12/include/ctype.h b/kernel/0.1x/linux-0.12/include/ctype.h new file mode 100644 index 00000000..2d833c62 --- /dev/null +++ b/kernel/0.1x/linux-0.12/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/kernel/0.1x/linux-0.12/include/errno.h b/kernel/0.1x/linux-0.12/include/errno.h new file mode 100644 index 00000000..7d8b30a9 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/errno.h @@ -0,0 +1,64 @@ +#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 + +/* Should never be seen by user programs */ +#define ERESTARTSYS 512 +#define ERESTARTNOINTR 513 + +#endif diff --git a/kernel/0.1x/linux-0.12/include/fcntl.h b/kernel/0.1x/linux-0.12/include/fcntl.h new file mode 100644 index 00000000..d339b5e7 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/fcntl.h @@ -0,0 +1,55 @@ +#ifndef _FCNTL_H +#define _FCNTL_H + +#include + +/* open/fcntl - NOCTTY, NDELAY isn't implemented yet */ +#define O_ACCMODE 00003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 00100 /* not fcntl */ +#define O_EXCL 00200 /* not fcntl */ +#define O_NOCTTY 00400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 /* not fcntl */ +#define O_NDELAY O_NONBLOCK + +/* Defines for fcntl-commands. Note that currently + * locking isn't supported, and other things aren't really + * tested. + */ +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get f_flags */ +#define F_SETFD 2 /* set f_flags */ +#define F_GETFL 3 /* more flags (cloexec) */ +#define F_SETFL 4 +#define F_GETLK 5 /* not implemented */ +#define F_SETLK 6 +#define F_SETLKW 7 + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* Ok, these are locking features, and aren't implemented at any + * level. POSIX wants them. + */ +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +/* Once again - not implemented, but ... */ +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +extern int creat(const char * filename,mode_t mode); +extern int fcntl(int fildes,int cmd, ...); +extern int open(const char * filename, int flags, ...); + +#endif diff --git a/kernel/0.1x/linux-0.12/include/linux/config.h b/kernel/0.1x/linux-0.12/include/linux/config.h new file mode 100644 index 00000000..cf64e9ed --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/linux/config.h @@ -0,0 +1,55 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +/* + * Defines for what uname() should return + */ +#define UTS_SYSNAME "Linux" +#define UTS_NODENAME "(none)" /* set by sethostname() */ +#define UTS_RELEASE "0" /* patchlevel */ +#define UTS_VERSION "0.12" +#define UTS_MACHINE "i386" /* hardware type */ + +/* Don't touch these, unless you really know what your doing. */ +#define DEF_INITSEG 0x9000 +#define DEF_SYSSEG 0x1000 +#define DEF_SETUPSEG 0x9020 +#define DEF_SYSSIZE 0x3000 + +/* + * The root-device is no longer hard-coded. You can change the default + * root-device by changing the line ROOT_DEV = XXX in boot/bootsect.s + */ + +/* + * The keyboard is now defined in kernel/chr_dev/keyboard.S + */ + +/* + * Normally, Linux can get the drive parameters from the BIOS at + * startup, but if this for some unfathomable reason fails, you'd + * be left stranded. For this case, you can define HD_TYPE, which + * contains all necessary info on your harddisk. + * + * The HD_TYPE macro should look like this: + * + * #define HD_TYPE { head, sect, cyl, wpcom, lzone, ctl} + * + * In case of two harddisks, the info should be sepatated by + * commas: + * + * #define HD_TYPE { h,s,c,wpcom,lz,ctl },{ h,s,c,wpcom,lz,ctl } + */ +/* + This is an example, two drives, first is type 2, second is type 3: + +#define HD_TYPE { 4,17,615,300,615,8 }, { 6,17,615,300,615,0 } + + NOTE: ctl is 0 for all drives with heads<=8, and ctl=8 for drives + with more than 8 heads. + + If you want the BIOS to tell what kind of drive you have, just + leave HD_TYPE undefined. This is the normal thing to do. +*/ + +#endif diff --git a/kernel/0.1x/linux-0.12/include/linux/fdreg.h b/kernel/0.1x/linux-0.12/include/linux/fdreg.h new file mode 100644 index 00000000..61f4da90 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/linux/fdreg.h @@ -0,0 +1,71 @@ +/* + * This file contains some defines for the floppy disk controller. + * Various sources. Mostly "IBM Microcomputers: A Programmers + * Handbook", Sanches and Canton. + */ +#ifndef _FDREG_H +#define _FDREG_H + +extern int ticks_to_floppy_on(unsigned int nr); +extern void floppy_on(unsigned int nr); +extern void floppy_off(unsigned int nr); +extern void floppy_select(unsigned int nr); +extern void floppy_deselect(unsigned int nr); + +/* Fd controller regs. S&C, about page 340 */ +#define FD_STATUS 0x3f4 +#define FD_DATA 0x3f5 +#define FD_DOR 0x3f2 /* Digital Output Register */ +#define FD_DIR 0x3f7 /* Digital Input Register (read) */ +#define FD_DCR 0x3f7 /* Diskette Control Register (write)*/ + +/* Bits of main status register */ +#define STATUS_BUSYMASK 0x0F /* drive busy mask */ +#define STATUS_BUSY 0x10 /* FDC busy */ +#define STATUS_DMA 0x20 /* 0- DMA mode */ +#define STATUS_DIR 0x40 /* 0- cpu->fdc */ +#define STATUS_READY 0x80 /* Data reg ready */ + +/* Bits of FD_ST0 */ +#define ST0_DS 0x03 /* drive select mask */ +#define ST0_HA 0x04 /* Head (Address) */ +#define ST0_NR 0x08 /* Not Ready */ +#define ST0_ECE 0x10 /* Equipment chech error */ +#define ST0_SE 0x20 /* Seek end */ +#define ST0_INTR 0xC0 /* Interrupt code mask */ + +/* Bits of FD_ST1 */ +#define ST1_MAM 0x01 /* Missing Address Mark */ +#define ST1_WP 0x02 /* Write Protect */ +#define ST1_ND 0x04 /* No Data - unreadable */ +#define ST1_OR 0x10 /* OverRun */ +#define ST1_CRC 0x20 /* CRC error in data or addr */ +#define ST1_EOC 0x80 /* End Of Cylinder */ + +/* Bits of FD_ST2 */ +#define ST2_MAM 0x01 /* Missing Addess Mark (again) */ +#define ST2_BC 0x02 /* Bad Cylinder */ +#define ST2_SNS 0x04 /* Scan Not Satisfied */ +#define ST2_SEH 0x08 /* Scan Equal Hit */ +#define ST2_WC 0x10 /* Wrong Cylinder */ +#define ST2_CRC 0x20 /* CRC error in data field */ +#define ST2_CM 0x40 /* Control Mark = deleted */ + +/* Bits of FD_ST3 */ +#define ST3_HA 0x04 /* Head (Address) */ +#define ST3_TZ 0x10 /* Track Zero signal (1=track 0) */ +#define ST3_WP 0x40 /* Write Protect */ + +/* Values for FD_COMMAND */ +#define FD_RECALIBRATE 0x07 /* move to track 0 */ +#define FD_SEEK 0x0F /* seek track */ +#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */ +#define FD_WRITE 0xC5 /* write with MT, MFM */ +#define FD_SENSEI 0x08 /* Sense Interrupt Status */ +#define FD_SPECIFY 0x03 /* specify HUT etc */ + +/* DMA commands */ +#define DMA_READ 0x46 +#define DMA_WRITE 0x4A + +#endif diff --git a/kernel/0.1x/linux-0.12/include/linux/fs.h b/kernel/0.1x/linux-0.12/include/linux/fs.h new file mode 100644 index 00000000..946cae02 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/linux/fs.h @@ -0,0 +1,210 @@ +/* + * This file has definitions for some important file table + * structures etc. + */ + +#ifndef _FS_H +#define _FS_H + +#include + +/* devices are as follows: (same as minix, so we can use the minix + * file system. These are major numbers.) + * + * 0 - unused (nodev) + * 1 - /dev/mem + * 2 - /dev/fd + * 3 - /dev/hd + * 4 - /dev/ttyx + * 5 - /dev/tty + * 6 - /dev/lp + * 7 - unnamed pipes + */ + +#define IS_SEEKABLE(x) ((x)>=1 && (x)<=3) + +#define READ 0 +#define WRITE 1 +#define READA 2 /* read-ahead - don't pause */ +#define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */ + +void buffer_init(long buffer_end); + +#define MAJOR(a) (((unsigned)(a))>>8) +#define MINOR(a) ((a)&0xff) + +#define NAME_LEN 14 +#define ROOT_INO 1 + +#define I_MAP_SLOTS 8 +#define Z_MAP_SLOTS 8 +#define SUPER_MAGIC 0x137F + +#define NR_OPEN 20 +#define NR_INODE 64 +#define NR_FILE 64 +#define NR_SUPER 8 +#define NR_HASH 307 +#define NR_BUFFERS nr_buffers +#define BLOCK_SIZE 1024 +#define BLOCK_SIZE_BITS 10 +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#define INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct d_inode))) +#define DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct dir_entry))) + +#define PIPE_READ_WAIT(inode) ((inode).i_wait) +#define PIPE_WRITE_WAIT(inode) ((inode).i_wait2) +#define PIPE_HEAD(inode) ((inode).i_zone[0]) +#define PIPE_TAIL(inode) ((inode).i_zone[1]) +#define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1)) +#define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode)) +#define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1)) + +#define NIL_FILP ((struct file *)0) +#define SEL_IN 1 +#define SEL_OUT 2 +#define SEL_EX 4 + +typedef char buffer_block[BLOCK_SIZE]; + +struct buffer_head { + char * b_data; /* pointer to data block (1024 bytes) */ + unsigned long b_blocknr; /* block number */ + unsigned short b_dev; /* device (0 = free) */ + unsigned char b_uptodate; + unsigned char b_dirt; /* 0-clean,1-dirty */ + unsigned char b_count; /* users using this block */ + unsigned char b_lock; /* 0 - ok, 1 -locked */ + struct task_struct * b_wait; + struct buffer_head * b_prev; + struct buffer_head * b_next; + struct buffer_head * b_prev_free; + struct buffer_head * b_next_free; +}; + +struct d_inode { + unsigned short i_mode; + unsigned short i_uid; + unsigned long i_size; + unsigned long i_time; + unsigned char i_gid; + unsigned char i_nlinks; + unsigned short i_zone[9]; +}; + +struct m_inode { + unsigned short i_mode; + unsigned short i_uid; + unsigned long i_size; + unsigned long i_mtime; + unsigned char i_gid; + unsigned char i_nlinks; + unsigned short i_zone[9]; +/* these are in memory also */ + struct task_struct * i_wait; + struct task_struct * i_wait2; /* for pipes */ + unsigned long i_atime; + unsigned long i_ctime; + unsigned short i_dev; + unsigned short i_num; + unsigned short i_count; + unsigned char i_lock; + unsigned char i_dirt; + unsigned char i_pipe; + unsigned char i_mount; + unsigned char i_seek; + unsigned char i_update; +}; + +struct file { + unsigned short f_mode; + unsigned short f_flags; + unsigned short f_count; + struct m_inode * f_inode; + off_t f_pos; +}; + +struct super_block { + unsigned short s_ninodes; + unsigned short s_nzones; + unsigned short s_imap_blocks; + unsigned short s_zmap_blocks; + unsigned short s_firstdatazone; + unsigned short s_log_zone_size; + unsigned long s_max_size; + unsigned short s_magic; +/* These are only in memory */ + struct buffer_head * s_imap[8]; + struct buffer_head * s_zmap[8]; + unsigned short s_dev; + struct m_inode * s_isup; + struct m_inode * s_imount; + unsigned long s_time; + struct task_struct * s_wait; + unsigned char s_lock; + unsigned char s_rd_only; + unsigned char s_dirt; +}; + +struct d_super_block { + unsigned short s_ninodes; + unsigned short s_nzones; + unsigned short s_imap_blocks; + unsigned short s_zmap_blocks; + unsigned short s_firstdatazone; + unsigned short s_log_zone_size; + unsigned long s_max_size; + unsigned short s_magic; +}; + +struct dir_entry { + unsigned short inode; + char name[NAME_LEN]; +}; + +extern struct m_inode inode_table[NR_INODE]; +extern struct file file_table[NR_FILE]; +extern struct super_block super_block[NR_SUPER]; +extern struct buffer_head * start_buffer; +extern int nr_buffers; + +extern void check_disk_change(int dev); +extern int floppy_change(unsigned int nr); +extern int ticks_to_floppy_on(unsigned int dev); +extern void floppy_on(unsigned int dev); +extern void floppy_off(unsigned int dev); +extern void truncate(struct m_inode * inode); +extern void sync_inodes(void); +extern void wait_on(struct m_inode * inode); +extern int bmap(struct m_inode * inode,int block); +extern int create_block(struct m_inode * inode,int block); +extern struct m_inode * namei(const char * pathname); +extern struct m_inode * lnamei(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 ll_rw_page(int rw, int dev, int nr, char * buffer); +extern void brelse(struct buffer_head * buf); +extern struct buffer_head * bread(int dev,int block); +extern void bread_page(unsigned long addr,int dev,int b[4]); +extern struct buffer_head * breada(int dev,int block,...); +extern int new_block(int dev); +extern int free_block(int dev, int block); +extern struct m_inode * new_inode(int dev); +extern void free_inode(struct m_inode * inode); +extern int sync_dev(int dev); +extern struct super_block * get_super(int dev); +extern int ROOT_DEV; + +extern void mount_root(void); + +#endif diff --git a/kernel/0.1x/linux-0.12/include/linux/hdreg.h b/kernel/0.1x/linux-0.12/include/linux/hdreg.h new file mode 100644 index 00000000..202db422 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/linux/hdreg.h @@ -0,0 +1,65 @@ +/* + * This file contains some defines for the AT-hd-controller. + * Various sources. Check out some definitions (see comments with + * a ques). + */ +#ifndef _HDREG_H +#define _HDREG_H + +/* Hd controller regs. Ref: IBM AT Bios-listing */ +#define HD_DATA 0x1f0 /* _CTL when writing */ +#define HD_ERROR 0x1f1 /* see err-bits */ +#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */ +#define HD_SECTOR 0x1f3 /* starting sector */ +#define HD_LCYL 0x1f4 /* starting cylinder */ +#define HD_HCYL 0x1f5 /* high byte of starting cyl */ +#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */ +#define HD_STATUS 0x1f7 /* see status-bits */ +#define HD_PRECOMP HD_ERROR /* same io address, read=error, write=precomp */ +#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */ + +#define HD_CMD 0x3f6 + +/* Bits of HD_STATUS */ +#define ERR_STAT 0x01 +#define INDEX_STAT 0x02 +#define ECC_STAT 0x04 /* Corrected error */ +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Values for HD_COMMAND */ +#define WIN_RESTORE 0x10 +#define WIN_READ 0x20 +#define WIN_WRITE 0x30 +#define WIN_VERIFY 0x40 +#define WIN_FORMAT 0x50 +#define WIN_INIT 0x60 +#define WIN_SEEK 0x70 +#define WIN_DIAGNOSE 0x90 +#define WIN_SPECIFY 0x91 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark ? */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* ? */ +#define ID_ERR 0x10 /* ? */ +#define ECC_ERR 0x40 /* ? */ +#define BBD_ERR 0x80 /* ? */ + +struct partition { + unsigned char boot_ind; /* 0x80 - active (unused) */ + unsigned char head; /* ? */ + unsigned char sector; /* ? */ + unsigned char cyl; /* ? */ + unsigned char sys_ind; /* ? */ + unsigned char end_head; /* ? */ + unsigned char end_sector; /* ? */ + unsigned char end_cyl; /* ? */ + unsigned int start_sect; /* starting sector counting from 0 */ + unsigned int nr_sects; /* nr of sectors in partition */ +}; + +#endif diff --git a/kernel/0.1x/linux-0.12/include/linux/head.h b/kernel/0.1x/linux-0.12/include/linux/head.h new file mode 100644 index 00000000..f5468a0e --- /dev/null +++ b/kernel/0.1x/linux-0.12/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/kernel/0.1x/linux-0.12/include/linux/kernel.h b/kernel/0.1x/linux-0.12/include/linux/kernel.h new file mode 100644 index 00000000..33fb0b86 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/linux/kernel.h @@ -0,0 +1,33 @@ +/* + * 'kernel.h' contains some often-used function prototypes etc + */ +void verify_area(void * addr,int count); +volatile void panic(const char * str); +volatile void do_exit(long error_code); +int printf(const char * fmt, ...); +int printk(const char * fmt, ...); +void console_print(const char * str); +int tty_write(unsigned ch,char * buf,int count); +void * malloc(unsigned int size); +void free_s(void * obj, int size); +extern void hd_times_out(void); +extern void sysbeepstop(void); +extern void blank_screen(void); +extern void unblank_screen(void); + +extern int beepcount; +extern int hd_timeout; +extern int blankinterval; +extern int blankcount; + +#define free(x) free_s((x), 0) + +/* + * This is defined as a macro, but at some point this might become a + * real subroutine that sets a flag if it returns true (to do + * BSD-style accounting where the process is flagged if it uses root + * privs). The implication of this is that you should do normal + * permissions checks first, and check suser() last. + */ +#define suser() (current->euid == 0) + diff --git a/kernel/0.1x/linux-0.12/include/linux/math_emu.h b/kernel/0.1x/linux-0.12/include/linux/math_emu.h new file mode 100644 index 00000000..3894ead3 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/linux/math_emu.h @@ -0,0 +1,185 @@ +/* + * linux/include/linux/math_emu.h + * + * (C) 1991 Linus Torvalds + */ +#ifndef _LINUX_MATH_EMU_H +#define _LINUX_MATH_EMU_H + +#include + +struct info { + long ___math_ret; + long ___orig_eip; + long ___edi; + long ___esi; + long ___ebp; + long ___sys_call_ret; + long ___eax; + long ___ebx; + long ___ecx; + long ___edx; + long ___orig_eax; + long ___fs; + long ___es; + long ___ds; + long ___eip; + long ___cs; + long ___eflags; + long ___esp; + long ___ss; +}; + +#define EAX (info->___eax) +#define EBX (info->___ebx) +#define ECX (info->___ecx) +#define EDX (info->___edx) +#define ESI (info->___esi) +#define EDI (info->___edi) +#define EBP (info->___ebp) +#define ESP (info->___esp) +#define EIP (info->___eip) +#define ORIG_EIP (info->___orig_eip) +#define EFLAGS (info->___eflags) +#define DS (*(unsigned short *) &(info->___ds)) +#define ES (*(unsigned short *) &(info->___es)) +#define FS (*(unsigned short *) &(info->___fs)) +#define CS (*(unsigned short *) &(info->___cs)) +#define SS (*(unsigned short *) &(info->___ss)) + +void __math_abort(struct info *, unsigned int); + +#define math_abort(x,y) \ +(((volatile void (*)(struct info *,unsigned int)) __math_abort)((x),(y))) + +/* + * Gcc forces this stupid alignment problem: I want to use only two longs + * for the temporary real 64-bit mantissa, but then gcc aligns out the + * structure to 12 bytes which breaks things in math_emulate.c. Shit. I + * want some kind of "no-alignt" pragma or something. + */ + +typedef struct { + long a,b; + short exponent; +} temp_real; + +typedef struct { + short m0,m1,m2,m3; + short exponent; +} temp_real_unaligned; + +#define real_to_real(a,b) \ +((*(long long *) (b) = *(long long *) (a)),((b)->exponent = (a)->exponent)) + +typedef struct { + long a,b; +} long_real; + +typedef long short_real; + +typedef struct { + long a,b; + short sign; +} temp_int; + +struct swd { + int ie:1; + int de:1; + int ze:1; + int oe:1; + int ue:1; + int pe:1; + int sf:1; + int ir:1; + int c0:1; + int c1:1; + int c2:1; + int top:3; + int c3:1; + int b:1; +}; + +#define I387 (current->tss.i387) +#define SWD (*(struct swd *) &I387.swd) +#define ROUNDING ((I387.cwd >> 10) & 3) +#define PRECISION ((I387.cwd >> 8) & 3) + +#define BITS24 0 +#define BITS53 2 +#define BITS64 3 + +#define ROUND_NEAREST 0 +#define ROUND_DOWN 1 +#define ROUND_UP 2 +#define ROUND_0 3 + +#define CONSTZ (temp_real_unaligned) {0x0000,0x0000,0x0000,0x0000,0x0000} +#define CONST1 (temp_real_unaligned) {0x0000,0x0000,0x0000,0x8000,0x3FFF} +#define CONSTPI (temp_real_unaligned) {0xC235,0x2168,0xDAA2,0xC90F,0x4000} +#define CONSTLN2 (temp_real_unaligned) {0x79AC,0xD1CF,0x17F7,0xB172,0x3FFE} +#define CONSTLG2 (temp_real_unaligned) {0xF799,0xFBCF,0x9A84,0x9A20,0x3FFD} +#define CONSTL2E (temp_real_unaligned) {0xF0BC,0x5C17,0x3B29,0xB8AA,0x3FFF} +#define CONSTL2T (temp_real_unaligned) {0x8AFE,0xCD1B,0x784B,0xD49A,0x4000} + +#define set_IE() (I387.swd |= 1) +#define set_DE() (I387.swd |= 2) +#define set_ZE() (I387.swd |= 4) +#define set_OE() (I387.swd |= 8) +#define set_UE() (I387.swd |= 16) +#define set_PE() (I387.swd |= 32) + +#define set_C0() (I387.swd |= 0x0100) +#define set_C1() (I387.swd |= 0x0200) +#define set_C2() (I387.swd |= 0x0400) +#define set_C3() (I387.swd |= 0x4000) + +/* ea.c */ + +char * ea(struct info * __info, unsigned short __code); + +/* convert.c */ + +void short_to_temp(const short_real * __a, temp_real * __b); +void long_to_temp(const long_real * __a, temp_real * __b); +void temp_to_short(const temp_real * __a, short_real * __b); +void temp_to_long(const temp_real * __a, long_real * __b); +void real_to_int(const temp_real * __a, temp_int * __b); +void int_to_real(const temp_int * __a, temp_real * __b); + +/* get_put.c */ + +void get_short_real(temp_real *, struct info *, unsigned short); +void get_long_real(temp_real *, struct info *, unsigned short); +void get_temp_real(temp_real *, struct info *, unsigned short); +void get_short_int(temp_real *, struct info *, unsigned short); +void get_long_int(temp_real *, struct info *, unsigned short); +void get_longlong_int(temp_real *, struct info *, unsigned short); +void get_BCD(temp_real *, struct info *, unsigned short); +void put_short_real(const temp_real *, struct info *, unsigned short); +void put_long_real(const temp_real *, struct info *, unsigned short); +void put_temp_real(const temp_real *, struct info *, unsigned short); +void put_short_int(const temp_real *, struct info *, unsigned short); +void put_long_int(const temp_real *, struct info *, unsigned short); +void put_longlong_int(const temp_real *, struct info *, unsigned short); +void put_BCD(const temp_real *, struct info *, unsigned short); + +/* add.c */ + +void fadd(const temp_real *, const temp_real *, temp_real *); + +/* mul.c */ + +void fmul(const temp_real *, const temp_real *, temp_real *); + +/* div.c */ + +void fdiv(const temp_real *, const temp_real *, temp_real *); + +/* compare.c */ + +void fcom(const temp_real *, const temp_real *); +void fucom(const temp_real *, const temp_real *); +void ftst(const temp_real *); + +#endif diff --git a/kernel/0.1x/linux-0.12/include/linux/mm.h b/kernel/0.1x/linux-0.12/include/linux/mm.h new file mode 100644 index 00000000..2ac61cc5 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/linux/mm.h @@ -0,0 +1,45 @@ +#ifndef _MM_H +#define _MM_H + +#define PAGE_SIZE 4096 + +#include +#include + +extern int SWAP_DEV; + +#define read_swap_page(nr,buffer) ll_rw_page(READ,SWAP_DEV,(nr),(buffer)); +#define write_swap_page(nr,buffer) ll_rw_page(WRITE,SWAP_DEV,(nr),(buffer)); + +extern unsigned long get_free_page(void); +extern unsigned long put_dirty_page(unsigned long page,unsigned long address); +extern void free_page(unsigned long addr); +void swap_free(int page_nr); +void swap_in(unsigned long *table_ptr); + +extern inline volatile void oom(void) +{ + printk("out of memory\n\r"); + do_exit(SIGSEGV); +} + +#define invalidate() \ +__asm__("movl %%eax,%%cr3"::"a" (0)) + +/* these are not to be changed without changing head.s etc */ +#define LOW_MEM 0x100000 +extern unsigned long HIGH_MEMORY; +#define PAGING_MEMORY (15*1024*1024) +#define PAGING_PAGES (PAGING_MEMORY>>12) +#define MAP_NR(addr) (((addr)-LOW_MEM)>>12) +#define USED 100 + +extern unsigned char mem_map [ PAGING_PAGES ]; + +#define PAGE_DIRTY 0x40 +#define PAGE_ACCESSED 0x20 +#define PAGE_USER 0x04 +#define PAGE_RW 0x02 +#define PAGE_PRESENT 0x01 + +#endif diff --git a/kernel/0.1x/linux-0.12/include/linux/sched.h b/kernel/0.1x/linux-0.12/include/linux/sched.h new file mode 100644 index 00000000..650befb9 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/linux/sched.h @@ -0,0 +1,284 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#define HZ 100 + +#define NR_TASKS 64 +#define TASK_SIZE 0x04000000 +#define LIBRARY_SIZE 0x00400000 + +#if (TASK_SIZE & 0x3fffff) +#error "TASK_SIZE must be multiple of 4M" +#endif + +#if (LIBRARY_SIZE & 0x3fffff) +#error "LIBRARY_SIZE must be a multiple of 4M" +#endif + +#if (LIBRARY_SIZE >= (TASK_SIZE/2)) +#error "LIBRARY_SIZE too damn big!" +#endif + +#if (((TASK_SIZE>>16)*NR_TASKS) != 0x10000) +#error "TASK_SIZE*NR_TASKS must be 4GB" +#endif + +#define LIBRARY_OFFSET (TASK_SIZE - LIBRARY_SIZE) + +#define CT_TO_SECS(x) ((x) / HZ) +#define CT_TO_USECS(x) (((x) % HZ) * 1000000/HZ) + +#define FIRST_TASK task[0] +#define LAST_TASK task[NR_TASKS-1] + +#include +#include +#include +#include +#include +#include +#include + +#if (NR_OPEN > 32) +#error "Currently the close-on-exec-flags and select masks are in one long, max 32 files/proc" +#endif + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_ZOMBIE 3 +#define TASK_STOPPED 4 + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +extern int copy_page_tables(unsigned long from, unsigned long to, long size); +extern int free_page_tables(unsigned long from, unsigned long size); + +extern void sched_init(void); +extern void schedule(void); +extern void trap_init(void); +extern void panic(const char * str); +extern int tty_write(unsigned minor,char * buf,int count); + +typedef int (*fn_ptr)(); + +struct i387_struct { + long cwd; + long swd; + long twd; + long fip; + long fcs; + long foo; + long fos; + long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ +}; + +struct tss_struct { + long back_link; /* 16 high bits zero */ + long esp0; + long ss0; /* 16 high bits zero */ + long esp1; + long ss1; /* 16 high bits zero */ + long esp2; + long ss2; /* 16 high bits zero */ + long cr3; + long eip; + long eflags; + long eax,ecx,edx,ebx; + long esp; + long ebp; + long esi; + long edi; + long es; /* 16 high bits zero */ + long cs; /* 16 high bits zero */ + long ss; /* 16 high bits zero */ + long ds; /* 16 high bits zero */ + long fs; /* 16 high bits zero */ + long gs; /* 16 high bits zero */ + long ldt; /* 16 high bits zero */ + long trace_bitmap; /* bits: trace 0, bitmap 16-31 */ + struct i387_struct i387; +}; + +struct task_struct { +/* these are hardcoded - don't touch */ + long state; /* -1 unrunnable, 0 runnable, >0 stopped */ + long counter; + long priority; + long signal; + struct sigaction sigaction[32]; + long blocked; /* bitmap of masked signals */ +/* various fields */ + int exit_code; + unsigned long start_code,end_code,end_data,brk,start_stack; + long pid,pgrp,session,leader; + int groups[NGROUPS]; + /* + * pointers to parent process, youngest child, younger sibling, + * older sibling, respectively. (p->father can be replaced with + * p->p_pptr->pid) + */ + struct task_struct *p_pptr, *p_cptr, *p_ysptr, *p_osptr; + unsigned short uid,euid,suid; + unsigned short gid,egid,sgid; + unsigned long timeout,alarm; + long utime,stime,cutime,cstime,start_time; + struct rlimit rlim[RLIM_NLIMITS]; + unsigned int flags; /* per process flags, defined below */ + unsigned short used_math; +/* file system info */ + int tty; /* -1 if no tty, so it must be signed */ + unsigned short umask; + struct m_inode * pwd; + struct m_inode * root; + struct m_inode * executable; + struct m_inode * library; + 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; +}; + +/* + * Per process flags + */ +#define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */ + /* Not implemented yet, only for 486*/ + +/* + * INIT_TASK is used to set up the first task table, touch at + * your own risk!. Base=0, limit=0x9ffff (=640kB) + */ +#define INIT_TASK \ +/* state etc */ { 0,15,15, \ +/* signals */ 0,{{},},0, \ +/* ec,brk... */ 0,0,0,0,0,0, \ +/* pid etc.. */ 0,0,0,0, \ +/* suppl grps*/ {NOGROUP,}, \ +/* proc links*/ &init_task.task,0,0,0, \ +/* uid etc */ 0,0,0,0,0,0, \ +/* timeout */ 0,0,0,0,0,0,0, \ +/* rlimits */ { {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \ + {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \ + {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}}, \ +/* flags */ 0, \ +/* math */ 0, \ +/* fs info */ -1,0022,NULL,NULL,NULL,NULL,0, \ +/* filp */ {NULL,}, \ + { \ + {0,0}, \ +/* ldt */ {0x9f,0xc0fa00}, \ + {0x9f,0xc0f200}, \ + }, \ +/*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\ + 0,0,0,0,0,0,0,0, \ + 0,0,0x17,0x17,0x17,0x17,0x17,0x17, \ + _LDT(0),0x80000000, \ + {} \ + }, \ +} + +extern struct task_struct *task[NR_TASKS]; +extern struct task_struct *last_task_used_math; +extern struct task_struct *current; +extern unsigned long volatile jiffies; +extern unsigned long startup_time; +extern int jiffies_offset; + +#define CURRENT_TIME (startup_time+(jiffies+jiffies_offset)/HZ) + +extern void add_timer(long jiffies, void (*fn)(void)); +extern void sleep_on(struct task_struct ** p); +extern void interruptible_sleep_on(struct task_struct ** p); +extern void wake_up(struct task_struct ** p); +extern int in_group_p(gid_t grp); + +/* + * Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall + * 4-TSS0, 5-LDT0, 6-TSS1 etc ... + */ +#define FIRST_TSS_ENTRY 4 +#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1) +#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3)) +#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3)) +#define ltr(n) __asm__("ltr %%ax"::"a" (_TSS(n))) +#define lldt(n) __asm__("lldt %%ax"::"a" (_LDT(n))) +#define str(n) \ +__asm__("str %%ax\n\t" \ + "subl %2,%%eax\n\t" \ + "shrl $4,%%eax" \ + :"=a" (n) \ + :"a" (0),"i" (FIRST_TSS_ENTRY<<3)) +/* + * switch_to(n) should switch tasks to task nr n, first + * checking that n isn't the current task, in which case it does nothing. + * This also clears the TS-flag if the task we switched to has used + * tha math co-processor latest. + */ +#define switch_to(n) {\ +struct {long a,b;} __tmp; \ +__asm__("cmpl %%ecx,_current\n\t" \ + "je 1f\n\t" \ + "movw %%dx,%1\n\t" \ + "xchgl %%ecx,_current\n\t" \ + "ljmp %0\n\t" \ + "cmpl %%ecx,_last_task_used_math\n\t" \ + "jne 1f\n\t" \ + "clts\n" \ + "1:" \ + ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ + "d" (_TSS(n)),"c" ((long) task[n])); \ +} + +#define PAGE_ALIGN(n) (((n)+0xfff)&0xfffff000) + +#define _set_base(addr,base) \ +__asm__("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/kernel/0.1x/linux-0.12/include/linux/sys.h b/kernel/0.1x/linux-0.12/include/linux/sys.h new file mode 100644 index 00000000..6bae3fc1 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/linux/sys.h @@ -0,0 +1,111 @@ +/* + * Why isn't this a .c file? Enquiring minds.... + */ + +extern int sys_setup(); +extern int sys_exit(); +extern int sys_fork(); +extern int sys_read(); +extern int sys_write(); +extern int sys_open(); +extern int sys_close(); +extern int sys_waitpid(); +extern int sys_creat(); +extern int sys_link(); +extern int sys_unlink(); +extern int sys_execve(); +extern int sys_chdir(); +extern int sys_time(); +extern int sys_mknod(); +extern int sys_chmod(); +extern int sys_chown(); +extern int sys_break(); +extern int sys_stat(); +extern int sys_lseek(); +extern int sys_getpid(); +extern int sys_mount(); +extern int sys_umount(); +extern int sys_setuid(); +extern int sys_getuid(); +extern int sys_stime(); +extern int sys_ptrace(); +extern int sys_alarm(); +extern int sys_fstat(); +extern int sys_pause(); +extern int sys_utime(); +extern int sys_stty(); +extern int sys_gtty(); +extern int sys_access(); +extern int sys_nice(); +extern int sys_ftime(); +extern int sys_sync(); +extern int sys_kill(); +extern int sys_rename(); +extern int sys_mkdir(); +extern int sys_rmdir(); +extern int sys_dup(); +extern int sys_pipe(); +extern int sys_times(); +extern int sys_prof(); +extern int sys_brk(); +extern int sys_setgid(); +extern int sys_getgid(); +extern int sys_signal(); +extern int sys_geteuid(); +extern int sys_getegid(); +extern int sys_acct(); +extern int sys_phys(); +extern int sys_lock(); +extern int sys_ioctl(); +extern int sys_fcntl(); +extern int sys_mpx(); +extern int sys_setpgid(); +extern int sys_ulimit(); +extern int sys_uname(); +extern int sys_umask(); +extern int sys_chroot(); +extern int sys_ustat(); +extern int sys_dup2(); +extern int sys_getppid(); +extern int sys_getpgrp(); +extern int sys_setsid(); +extern int sys_sigaction(); +extern int sys_sgetmask(); +extern int sys_ssetmask(); +extern int sys_setreuid(); +extern int sys_setregid(); +extern int sys_sigpending(); +extern int sys_sigsuspend(); +extern int sys_sethostname(); +extern int sys_setrlimit(); +extern int sys_getrlimit(); +extern int sys_getrusage(); +extern int sys_gettimeofday(); +extern int sys_settimeofday(); +extern int sys_getgroups(); +extern int sys_setgroups(); +extern int sys_select(); +extern int sys_symlink(); +extern int sys_lstat(); +extern int sys_readlink(); +extern int sys_uselib(); + +fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read, +sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link, +sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod, +sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount, +sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm, +sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access, +sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir, +sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid, +sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys, +sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit, +sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid, +sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask, +sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_sethostname, +sys_setrlimit, sys_getrlimit, sys_getrusage, sys_gettimeofday, +sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink, +sys_lstat, sys_readlink, sys_uselib }; + +/* So we don't have to do any more manual updating.... */ +int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); diff --git a/kernel/0.1x/linux-0.12/include/linux/tty.h b/kernel/0.1x/linux-0.12/include/linux/tty.h new file mode 100644 index 00000000..a265bc1b --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/linux/tty.h @@ -0,0 +1,99 @@ +/* + * '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 + +#define MAX_CONSOLES 8 +#define NR_SERIALS 2 +#define NR_PTYS 4 + +extern int NR_CONSOLES; + +#include + +#define TTY_BUF_SIZE 1024 + +struct tty_queue { + unsigned long data; + unsigned long head; + unsigned long tail; + struct task_struct * proc_list; + char buf[TTY_BUF_SIZE]; +}; + +#define IS_A_CONSOLE(min) (((min) & 0xC0) == 0x00) +#define IS_A_SERIAL(min) (((min) & 0xC0) == 0x40) +#define IS_A_PTY(min) ((min) & 0x80) +#define IS_A_PTY_MASTER(min) (((min) & 0xC0) == 0x80) +#define IS_A_PTY_SLAVE(min) (((min) & 0xC0) == 0xC0) +#define PTY_OTHER(min) ((min) ^ 0x40) + +#define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1)) +#define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1)) +#define EMPTY(a) ((a)->head == (a)->tail) +#define LEFT(a) (((a)->tail-(a)->head-1)&(TTY_BUF_SIZE-1)) +#define LAST(a) ((a)->buf[(TTY_BUF_SIZE-1)&((a)->head-1)]) +#define FULL(a) (!LEFT(a)) +#define CHARS(a) (((a)->head-(a)->tail)&(TTY_BUF_SIZE-1)) +#define GETCH(queue,c) \ +(void)({c=(queue)->buf[(queue)->tail];INC((queue)->tail);}) +#define PUTCH(c,queue) \ +(void)({(queue)->buf[(queue)->head]=(c);INC((queue)->head);}) + +#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR]) +#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT]) +#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE]) +#define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL]) +#define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF]) +#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART]) +#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP]) +#define SUSPEND_CHAR(tty) ((tty)->termios.c_cc[VSUSP]) + +struct tty_struct { + struct termios termios; + int pgrp; + int session; + 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[]; +extern int fg_console; + +#define TTY_TABLE(nr) \ +(tty_table + ((nr) ? (((nr) < 64)? (nr)-1:(nr)) : fg_console)) + +/* intr=^C quit=^| erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" + +void rs_init(void); +void con_init(void); +void tty_init(void); + +int tty_read(unsigned c, char * buf, int n); +int tty_write(unsigned c, char * buf, int n); + +void con_write(struct tty_struct * tty); +void rs_write(struct tty_struct * tty); +void mpty_write(struct tty_struct * tty); +void spty_write(struct tty_struct * tty); + +void copy_to_cooked(struct tty_struct * tty); + +void update_screen(void); + +#endif diff --git a/kernel/0.1x/linux-0.12/include/signal.h b/kernel/0.1x/linux-0.12/include/signal.h new file mode 100644 index 00000000..c4815cde --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/signal.h @@ -0,0 +1,75 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include + +typedef int sig_atomic_t; +typedef unsigned int sigset_t; /* 32 bits */ + +#define _NSIG 32 +#define NSIG _NSIG + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGUNUSED 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 + +/* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */ +#define SA_NOCLDSTOP 1 +#define SA_INTERRUPT 0x20000000 +#define SA_NOMASK 0x40000000 +#define SA_ONESHOT 0x80000000 + +#define SIG_BLOCK 0 /* for blocking signals */ +#define SIG_UNBLOCK 1 /* for unblocking signals */ +#define SIG_SETMASK 2 /* for setting the signal mask */ + +#define SIG_DFL ((void (*)(int))0) /* default signal handling */ +#define SIG_IGN ((void (*)(int))1) /* ignore signal */ +#define SIG_ERR ((void (*)(int))-1) /* error return from signal */ + +#ifdef notdef +#define sigemptyset(mask) ((*(mask) = 0), 1) +#define sigfillset(mask) ((*(mask) = ~0), 1) +#endif + +struct sigaction { + void (*sa_handler)(int); + sigset_t sa_mask; + int sa_flags; + void (*sa_restorer)(void); +}; + +void (*signal(int _sig, void (*_func)(int)))(int); +int raise(int sig); +int kill(pid_t pid, int sig); +int sigaddset(sigset_t *mask, int signo); +int sigdelset(sigset_t *mask, int signo); +int sigemptyset(sigset_t *mask); +int sigfillset(sigset_t *mask); +int sigismember(sigset_t *mask, int signo); /* 1 - is, 0 - not, -1 error */ +int sigpending(sigset_t *set); +int sigprocmask(int how, sigset_t *set, sigset_t *oldset); +int sigsuspend(sigset_t *sigmask); +int sigaction(int sig, struct sigaction *act, struct sigaction *oldact); + +#endif /* _SIGNAL_H */ diff --git a/kernel/0.1x/linux-0.12/include/stdarg.h b/kernel/0.1x/linux-0.12/include/stdarg.h new file mode 100644 index 00000000..0126a7cf --- /dev/null +++ b/kernel/0.1x/linux-0.12/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/kernel/0.1x/linux-0.12/include/stddef.h b/kernel/0.1x/linux-0.12/include/stddef.h new file mode 100644 index 00000000..cf08fde9 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/stddef.h @@ -0,0 +1,18 @@ +#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/kernel/0.1x/linux-0.12/include/string.h b/kernel/0.1x/linux-0.12/include/string.h new file mode 100644 index 00000000..f06f6139 --- /dev/null +++ b/kernel/0.1x/linux-0.12/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 + +struct stat { + dev_t st_dev; + ino_t st_ino; + umode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +}; + +#define S_IFMT 00170000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +extern int chmod(const char *_path, mode_t mode); +extern int fstat(int fildes, struct stat *stat_buf); +extern int mkdir(const char *_path, mode_t mode); +extern int mkfifo(const char *_path, mode_t mode); +extern int stat(const char *filename, struct stat *stat_buf); +extern mode_t umask(mode_t mask); + +#endif diff --git a/kernel/0.1x/linux-0.12/include/sys/time.h b/kernel/0.1x/linux-0.12/include/sys/time.h new file mode 100644 index 00000000..8a0cd687 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/sys/time.h @@ -0,0 +1,63 @@ +#ifndef _SYS_TIME_H +#define _SYS_TIME_H + +/* gettimofday returns this */ +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* microseconds */ +}; + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +#define DST_NONE 0 /* not on dst */ +#define DST_USA 1 /* USA style dst */ +#define DST_AUST 2 /* Australian style dst */ +#define DST_WET 3 /* Western European dst */ +#define DST_MET 4 /* Middle European dst */ +#define DST_EET 5 /* Eastern European dst */ +#define DST_CAN 6 /* Canada */ +#define DST_GB 7 /* Great Britain and Eire */ +#define DST_RUM 8 /* Rumania */ +#define DST_TUR 9 /* Turkey */ +#define DST_AUSTALT 10 /* Australian style with shift in 1986 */ + +#define FD_SET(fd,fdsetp) (*(fdsetp) |= (1 << (fd))) +#define FD_CLR(fd,fdsetp) (*(fdsetp) &= ~(1 << (fd))) +#define FD_ISSET(fd,fdsetp) ((*(fdsetp) >> fd) & 1) +#define FD_ZERO(fdsetp) (*(fdsetp) = 0) + +/* + * Operations on timevals. + * + * NB: timercmp does not work for >= or <=. + */ +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#define timercmp(tvp, uvp, cmp) \ + ((tvp)->tv_sec cmp (uvp)->tv_sec || \ + (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) +#define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0) + +/* + * Names of the interval timers, and structure + * defining a timer setting. + */ +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +struct itimerval { + struct timeval it_interval; /* timer interval */ + struct timeval it_value; /* current value */ +}; + +#include +#include + +int gettimeofday(struct timeval * tp, struct timezone * tz); +int select(int width, fd_set * readfds, fd_set * writefds, + fd_set * exceptfds, struct timeval * timeout); + +#endif /*_SYS_TIME_H*/ diff --git a/kernel/0.1x/linux-0.12/include/sys/times.h b/kernel/0.1x/linux-0.12/include/sys/times.h new file mode 100644 index 00000000..aa78d000 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/sys/times.h @@ -0,0 +1,15 @@ +#ifndef _TIMES_H +#define _TIMES_H + +#include + +struct tms { + time_t tms_utime; + time_t tms_stime; + time_t tms_cutime; + time_t tms_cstime; +}; + +extern time_t times(struct tms * tp); + +#endif diff --git a/kernel/0.1x/linux-0.12/include/sys/types.h b/kernel/0.1x/linux-0.12/include/sys/types.h new file mode 100644 index 00000000..c1680714 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/sys/types.h @@ -0,0 +1,52 @@ +#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 short 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 unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned long tcflag_t; + +typedef unsigned long fd_set; + +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/kernel/0.1x/linux-0.12/include/sys/utsname.h b/kernel/0.1x/linux-0.12/include/sys/utsname.h new file mode 100644 index 00000000..10f2425a --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/sys/utsname.h @@ -0,0 +1,17 @@ +#ifndef _SYS_UTSNAME_H +#define _SYS_UTSNAME_H + +#include +#include + +struct utsname { + char sysname[9]; + char nodename[MAXHOSTNAMELEN+1]; + char release[9]; + char version[9]; + char machine[9]; +}; + +extern int uname(struct utsname * utsbuf); + +#endif diff --git a/kernel/0.1x/linux-0.12/include/sys/wait.h b/kernel/0.1x/linux-0.12/include/sys/wait.h new file mode 100644 index 00000000..99a1f3d2 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/sys/wait.h @@ -0,0 +1,24 @@ +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include + +#define _LOW(v) ( (v) & 0377) +#define _HIGH(v) ( ((v) >> 8) & 0377) + +/* options for waitpid, WUNTRACED not supported */ +#define WNOHANG 1 +#define WUNTRACED 2 + +#define WIFEXITED(s) (!((s)&0xFF)) +#define WIFSTOPPED(s) (((s)&0xFF)==0x7F) +#define WEXITSTATUS(s) (((s)>>8)&0xFF) +#define WTERMSIG(s) ((s)&0x7F) +#define WCOREDUMP(s) ((s)&0x80) +#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/kernel/0.1x/linux-0.12/include/termios.h b/kernel/0.1x/linux-0.12/include/termios.h new file mode 100644 index 00000000..53e40a73 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/termios.h @@ -0,0 +1,226 @@ +#ifndef _TERMIOS_H +#define _TERMIOS_H + +#include + +#define TTY_BUF_SIZE 1024 + +/* 0x54 is just a magic number to make these relatively uniqe ('T') */ + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD + +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 { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0040000 +#define FF0 0000000 +#define FF1 0040000 + +/* c_cflag bit meaning */ +#define CBAUD 0000017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 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 + +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/kernel/0.1x/linux-0.12/include/time.h b/kernel/0.1x/linux-0.12/include/time.h new file mode 100644 index 00000000..2cb599a3 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/time.h @@ -0,0 +1,49 @@ +#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 + +#ifndef NULL +#define NULL ((void *) 0) +#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; +}; + +#define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 1000 == 0)) + +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/kernel/0.1x/linux-0.12/include/unistd.h b/kernel/0.1x/linux-0.12/include/unistd.h new file mode 100644 index 00000000..68f09c25 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/unistd.h @@ -0,0 +1,280 @@ +#ifndef _UNISTD_H +#define _UNISTD_H + +/* ok, this may be a joke, but I'm working on it */ +#define _POSIX_VERSION 198808L + +#define _POSIX_CHOWN_RESTRICTED /* only root can do a chown (I think..) */ +#define _POSIX_NO_TRUNC /* no pathname truncation (but see in kernel) */ +#define _POSIX_VDISABLE '\0' /* character to disable things like ^C */ +#define _POSIX_JOB_CONTROL +#define _POSIX_SAVED_IDS /* Implemented, for whatever good it is */ + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#ifndef NULL +#define NULL ((void *)0) +#endif + +/* access */ +#define F_OK 0 +#define X_OK 1 +#define W_OK 2 +#define R_OK 4 + +/* lseek */ +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +/* _SC stands for System Configuration. We don't use them much */ +#define _SC_ARG_MAX 1 +#define _SC_CHILD_MAX 2 +#define _SC_CLOCKS_PER_SEC 3 +#define _SC_NGROUPS_MAX 4 +#define _SC_OPEN_MAX 5 +#define _SC_JOB_CONTROL 6 +#define _SC_SAVED_IDS 7 +#define _SC_VERSION 8 + +/* more (possibly) configurable things - now pathnames */ +#define _PC_LINK_MAX 1 +#define _PC_MAX_CANON 2 +#define _PC_MAX_INPUT 3 +#define _PC_NAME_MAX 4 +#define _PC_PATH_MAX 5 +#define _PC_PIPE_BUF 6 +#define _PC_NO_TRUNC 7 +#define _PC_VDISABLE 8 +#define _PC_CHOWN_RESTRICTED 9 + +#include +#include +#include +#include +#include +#include + +#ifdef __LIBRARY__ + +#define __NR_setup 0 /* used only by init, to get system going */ +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_stat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_fstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_phys 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_uname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_lstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 + +#define _syscall0(type,name) \ +type name(void) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name)); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall1(type,name,atype,a) \ +type name(atype a) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a))); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall2(type,name,atype,a,btype,b) \ +type name(atype a,btype b) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b))); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall3(type,name,atype,a,btype,b,ctype,c) \ +type name(atype a,btype b,ctype c) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \ +if (__res>=0) \ + return (type) __res; \ +errno=-__res; \ +return -1; \ +} + +#endif /* __LIBRARY__ */ + +extern int errno; + +int access(const char * filename, mode_t mode); +int acct(const char * filename); +int alarm(int sec); +int brk(void * end_data_segment); +void * sbrk(ptrdiff_t increment); +int chdir(const char * filename); +int chmod(const char * filename, mode_t mode); +int chown(const char * filename, uid_t owner, gid_t group); +int chroot(const char * filename); +int close(int fildes); +int creat(const char * filename, mode_t mode); +int dup(int fildes); +int execve(const char * filename, char ** argv, char ** envp); +int execv(const char * pathname, char ** argv); +int execvp(const char * file, char ** argv); +int execl(const char * pathname, char * arg0, ...); +int execlp(const char * file, char * arg0, ...); +int execle(const char * pathname, char * arg0, ...); +volatile void exit(int status); +volatile void _exit(int status); +int fcntl(int fildes, int cmd, ...); +int fork(void); +int getpid(void); +int getuid(void); +int geteuid(void); +int getgid(void); +int getegid(void); +int ioctl(int fildes, int cmd, ...); +int kill(pid_t pid, int signal); +int link(const char * filename1, const char * filename2); +int lseek(int fildes, off_t offset, int origin); +int mknod(const char * filename, mode_t mode, dev_t dev); +int mount(const char * specialfile, const char * dir, int rwflag); +int nice(int val); +int open(const char * filename, int flag, ...); +int pause(void); +int pipe(int * fildes); +int read(int fildes, char * buf, off_t count); +int setpgrp(void); +int setpgid(pid_t pid,pid_t pgid); +int setuid(uid_t uid); +int setgid(gid_t gid); +void (*signal(int sig, void (*fn)(int)))(int); +int stat(const char * filename, struct stat * stat_buf); +int fstat(int fildes, struct stat * stat_buf); +int stime(time_t * tptr); +int sync(void); +time_t time(time_t * tloc); +time_t times(struct tms * tbuf); +int ulimit(int cmd, long limit); +mode_t umask(mode_t mask); +int umount(const char * specialfile); +int uname(struct utsname * name); +int unlink(const char * filename); +int ustat(dev_t dev, struct ustat * ubuf); +int utime(const char * filename, struct utimbuf * times); +pid_t waitpid(pid_t pid,int * wait_stat,int options); +pid_t wait(int * wait_stat); +int write(int fildes, const char * buf, off_t count); +int dup2(int oldfd, int newfd); +int getppid(void); +pid_t getpgrp(void); +pid_t setsid(void); +int sethostname(char *name, int len); +int setrlimit(int resource, struct rlimit *rlp); +int getrlimit(int resource, struct rlimit *rlp); +int getrusage(int who, struct rusage *rusage); +int gettimeofday(struct timeval *tv, struct timezone *tz); +int settimeofday(struct timeval *tv, struct timezone *tz); +int getgroups(int gidsetlen, gid_t *gidset); +int setgroups(int gidsetlen, gid_t *gidset); +int select(int width, fd_set * readfds, fd_set * writefds, + fd_set * exceptfds, struct timeval * timeout); + +#endif diff --git a/kernel/0.1x/linux-0.12/include/utime.h b/kernel/0.1x/linux-0.12/include/utime.h new file mode 100644 index 00000000..7b6d6971 --- /dev/null +++ b/kernel/0.1x/linux-0.12/include/utime.h @@ -0,0 +1,13 @@ +#ifndef _UTIME_H +#define _UTIME_H + +#include /* I know - shouldn't do this, but .. */ + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +extern int utime(const char *filename, struct utimbuf *times); + +#endif diff --git a/kernel/0.1x/linux-0.12/init/main.c b/kernel/0.1x/linux-0.12/init/main.c new file mode 100644 index 00000000..c7c7a7cc --- /dev/null +++ b/kernel/0.1x/linux-0.12/init/main.c @@ -0,0 +1,231 @@ +/* + * linux/init/main.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ +static inline _syscall0(int,fork) +static inline _syscall0(int,pause) +static inline _syscall1(int,setup,void *,BIOS) +static inline _syscall0(int,sync) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +static char printbuf[1024]; + +extern char *strcpy(); +extern int vsprintf(); +extern void init(void); +extern void blk_dev_init(void); +extern void chr_dev_init(void); +extern void hd_init(void); +extern void floppy_init(void); +extern void mem_init(long start, long end); +extern long rd_init(long mem_start, int length); +extern long kernel_mktime(struct tm * tm); + +static int sprintf(char * str, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i = vsprintf(str, fmt, args); + va_end(args); + return i; +} + +/* + * This is set up by the setup-routine at boot-time + */ +#define EXT_MEM_K (*(unsigned short *)0x90002) +#define CON_ROWS ((*(unsigned short *)0x9000e) & 0xff) +#define CON_COLS (((*(unsigned short *)0x9000e) & 0xff00) >> 8) +#define DRIVE_INFO (*(struct drive_info *)0x90080) +#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC) +#define ORIG_SWAP_DEV (*(unsigned short *)0x901FA) + +/* + * Yeah, yeah, it's ugly, but I cannot find how to do this correctly + * and this seems to work. I anybody has more info on the real-time + * clock I'd be interested. Most of this was trial and error, and some + * bios-listing reading. Urghh. + */ + +#define CMOS_READ(addr) ({ \ +outb_p(0x80|addr,0x70); \ +inb_p(0x71); \ +}) + +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) + +static void time_init(void) +{ + struct tm time; + + do { + time.tm_sec = CMOS_READ(0); + time.tm_min = CMOS_READ(2); + time.tm_hour = CMOS_READ(4); + time.tm_mday = CMOS_READ(7); + time.tm_mon = CMOS_READ(8); + time.tm_year = CMOS_READ(9); + } while (time.tm_sec != CMOS_READ(0)); + BCD_TO_BIN(time.tm_sec); + BCD_TO_BIN(time.tm_min); + BCD_TO_BIN(time.tm_hour); + BCD_TO_BIN(time.tm_mday); + BCD_TO_BIN(time.tm_mon); + BCD_TO_BIN(time.tm_year); + time.tm_mon--; + startup_time = kernel_mktime(&time); +} + +static long memory_end = 0; +static long buffer_memory_end = 0; +static long main_memory_start = 0; +static char term[32]; + +static char * argv_rc[] = { "/bin/sh", NULL }; +static char * envp_rc[] = { "HOME=/", NULL ,NULL }; + +static char * argv[] = { "-/bin/sh",NULL }; +static char * envp[] = { "HOME=/usr/root", NULL, NULL }; + +struct drive_info { char dummy[32]; } drive_info; + +void main(void) /* This really IS void, no error here. */ +{ /* The startup routine assumes (well, ...) this */ +/* + * Interrupts are still disabled. Do necessary setups, then + * enable them + */ + ROOT_DEV = ORIG_ROOT_DEV; + SWAP_DEV = ORIG_SWAP_DEV; + sprintf(term, "TERM=con%dx%d", CON_COLS, CON_ROWS); + envp[1] = term; + envp_rc[1] = term; + drive_info = DRIVE_INFO; + memory_end = (1<<20) + (EXT_MEM_K<<10); + memory_end &= 0xfffff000; + if (memory_end > 16*1024*1024) + memory_end = 16*1024*1024; + if (memory_end > 12*1024*1024) + buffer_memory_end = 4*1024*1024; + else if (memory_end > 6*1024*1024) + buffer_memory_end = 2*1024*1024; + else + buffer_memory_end = 1*1024*1024; + main_memory_start = buffer_memory_end; +#ifdef RAMDISK + main_memory_start += rd_init(main_memory_start, RAMDISK*1024); +#endif + mem_init(main_memory_start,memory_end); + trap_init(); + blk_dev_init(); + chr_dev_init(); + tty_init(); + time_init(); + sched_init(); + buffer_init(buffer_memory_end); + hd_init(); + floppy_init(); + sti(); + move_to_user_mode(); + if (!fork()) { /* we count on this going ok */ + init(); + } +/* + * NOTE!! For any other task 'pause()' would mean we have to get a + * signal to awaken, but task0 is the sole exception (see 'schedule()') + * as task 0 gets activated at every idle moment (when no other tasks + * can run). For task0 'pause()' just means we go check if some other + * task can run, and if not we return here. + */ + for(;;) + __asm__("int $0x80"::"a" (__NR_pause):"ax"); +} + +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; +} + +void init(void) +{ + int pid,i; + + setup((void *) &drive_info); + (void) open("/dev/tty1",O_RDWR,0); + (void) dup(0); + (void) dup(0); + printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS, + NR_BUFFERS*BLOCK_SIZE); + printf("Free mem: %d bytes\n\r",memory_end-main_memory_start); + if (!(pid=fork())) { + close(0); + if (open("/etc/rc",O_RDONLY,0)) + _exit(1); + execve("/bin/sh",argv_rc,envp_rc); + _exit(2); + } + if (pid>0) + while (pid != wait(&i)) + /* nothing */; + while (1) { + if ((pid=fork())<0) { + printf("Fork failed in init\r\n"); + continue; + } + if (!pid) { + close(0);close(1);close(2); + setsid(); + (void) open("/dev/tty1",O_RDWR,0); + (void) dup(0); + (void) dup(0); + _exit(execve("/bin/sh",argv,envp)); + } + while (1) + if (pid == wait(&i)) + break; + printf("\n\rchild %d died with code %04x\n\r",pid,i); + sync(); + } + _exit(0); /* NOTE! _exit, not exit() */ +} diff --git a/kernel/0.1x/linux-0.12/init/main.s b/kernel/0.1x/linux-0.12/init/main.s new file mode 100644 index 00000000..10d9f508 --- /dev/null +++ b/kernel/0.1x/linux-0.12/init/main.s @@ -0,0 +1,551 @@ + .file "init/main.c" +gcc_compiled.: +.text +LC0: + .ascii "out of memory\12\15\0" + .align 2 +_sprintf: + movl 4(%esp),%edx + leal 12(%esp),%eax + pushl %eax + pushl 12(%esp) + pushl %edx + call _vsprintf + addl $12,%esp + ret + .align 2 +_time_init: + pushl %ebp + movl %esp,%ebp + subl $44,%esp +L65: + movl $128,%eax + movl $112,%edx +/APP + outb %al,%dx + jmp 1f +1: jmp 1f +1: +/NO_APP + movl $113,%edx +/APP + inb %dx,%al + jmp 1f +1: jmp 1f +1: +/NO_APP + movb %al,-40(%ebp) + movzbl -40(%ebp),%eax + movl %eax,-36(%ebp) + movl $130,%eax + movl $112,%edx +/APP + outb %al,%dx + jmp 1f +1: jmp 1f +1: +/NO_APP + movl $113,%edx +/APP + inb %dx,%al + jmp 1f +1: jmp 1f +1: +/NO_APP + movb %al,-40(%ebp) + movzbl -40(%ebp),%eax + movl %eax,-32(%ebp) + movl $132,%eax + movl $112,%edx +/APP + outb %al,%dx + jmp 1f +1: jmp 1f +1: +/NO_APP + movl $113,%edx +/APP + inb %dx,%al + jmp 1f +1: jmp 1f +1: +/NO_APP + movb %al,-40(%ebp) + movzbl -40(%ebp),%eax + movl %eax,-28(%ebp) + movl $135,%eax + movl $112,%edx +/APP + outb %al,%dx + jmp 1f +1: jmp 1f +1: +/NO_APP + movl $113,%edx +/APP + inb %dx,%al + jmp 1f +1: jmp 1f +1: +/NO_APP + movb %al,-40(%ebp) + movzbl -40(%ebp),%eax + movl %eax,-24(%ebp) + movl $136,%eax + movl $112,%edx +/APP + outb %al,%dx + jmp 1f +1: jmp 1f +1: +/NO_APP + movl $113,%edx +/APP + inb %dx,%al + jmp 1f +1: jmp 1f +1: +/NO_APP + movb %al,-40(%ebp) + movzbl -40(%ebp),%eax + movl %eax,-20(%ebp) + movl $137,%eax + movl $112,%edx +/APP + outb %al,%dx + jmp 1f +1: jmp 1f +1: +/NO_APP + movl $113,%edx +/APP + inb %dx,%al + jmp 1f +1: jmp 1f +1: +/NO_APP + movb %al,-40(%ebp) + movzbl -40(%ebp),%eax + movl %eax,-16(%ebp) + movl $128,%eax + movl $112,%edx +/APP + outb %al,%dx + jmp 1f +1: jmp 1f +1: +/NO_APP + movl $113,%edx +/APP + inb %dx,%al + jmp 1f +1: jmp 1f +1: +/NO_APP + movb %al,-40(%ebp) + movzbl -40(%ebp),%eax + cmpl -36(%ebp),%eax + jne L65 + movl -36(%ebp),%eax + andl $15,%eax + movl -36(%ebp),%edx + sarl $4,%edx + leal (%edx,%edx,4),%edx + leal (%eax,%edx,2),%eax + movl %eax,-36(%ebp) + movl -32(%ebp),%eax + andl $15,%eax + movl -32(%ebp),%edx + sarl $4,%edx + leal (%edx,%edx,4),%edx + leal (%eax,%edx,2),%eax + movl %eax,-32(%ebp) + movl -28(%ebp),%eax + andl $15,%eax + movl -28(%ebp),%edx + sarl $4,%edx + leal (%edx,%edx,4),%edx + leal (%eax,%edx,2),%eax + movl %eax,-28(%ebp) + movl -24(%ebp),%eax + andl $15,%eax + movl -24(%ebp),%edx + sarl $4,%edx + leal (%edx,%edx,4),%edx + leal (%eax,%edx,2),%eax + movl %eax,-24(%ebp) + movl -20(%ebp),%eax + andl $15,%eax + movl -20(%ebp),%edx + sarl $4,%edx + leal (%edx,%edx,4),%edx + leal (%eax,%edx,2),%eax + movl %eax,-20(%ebp) + movl -16(%ebp),%eax + andl $15,%eax + movl -16(%ebp),%edx + sarl $4,%edx + leal (%edx,%edx,4),%edx + leal (%eax,%edx,2),%eax + movl %eax,-16(%ebp) + decl -20(%ebp) + leal -36(%ebp),%eax + pushl %eax + call _kernel_mktime + movl %eax,_startup_time + leave + ret +.data + .align 2 +_memory_end: + .long 0 + .align 2 +_buffer_memory_end: + .long 0 + .align 2 +_main_memory_start: + .long 0 +.text +LC1: + .ascii "/bin/sh\0" +.data + .align 2 +_argv_rc: + .long LC1 + .long 0 +.text +LC2: + .ascii "HOME=/\0" +.data + .align 2 +_envp_rc: + .long LC2 + .long 0 + .long 0 +.text +LC3: + .ascii "-/bin/sh\0" +.data + .align 2 +_argv: + .long LC3 + .long 0 +.text +LC4: + .ascii "HOME=/usr/root\0" +.data + .align 2 +_envp: + .long LC4 + .long 0 + .long 0 +.text +LC5: + .ascii "TERM=con%dx%d\0" + .align 2 +.globl _main +_main: + pushl %ebp + movl %esp,%ebp + subl $8,%esp + pushl %edi + pushl %esi + movzwl 590332,%eax + movl %eax,_ROOT_DEV + movzwl 590330,%eax + movl %eax,_SWAP_DEV + movw 589838,%dx + andl $255,%edx + pushl %edx + movw 589838,%ax + andw $65280,%ax + shrw $8,%ax + movw %ax,-4(%ebp) + movzwl -4(%ebp),%eax + pushl %eax + pushl $LC5 + pushl $_term + call _sprintf + movl $_term,_envp+4 + movl $_term,_envp_rc+4 + movl $_drive_info,%edi + movl $589952,%esi + movl $8,%ecx + cld + rep + movsl + movzwl 589826,%eax + sall $10,%eax + addl $1048576,%eax + movl %eax,_memory_end + andl $-4096,_memory_end + addl $16,%esp + cmpl $16777216,_memory_end + jle L69 + movl $16777216,_memory_end +L69: + cmpl $12582912,_memory_end + jle L70 + movl $4194304,_buffer_memory_end + jmp L71 + .align 2 +L70: + cmpl $6291456,_memory_end + jle L72 + movl $2097152,_buffer_memory_end + jmp L71 + .align 2 +L72: + movl $1048576,_buffer_memory_end +L71: + movl _buffer_memory_end,%eax + movl %eax,_main_memory_start + pushl _memory_end + pushl _buffer_memory_end + call _mem_init + call _trap_init + call _blk_dev_init + call _chr_dev_init + call _tty_init + call _time_init + call _sched_init + pushl _buffer_memory_end + call _buffer_init + call _hd_init + call _floppy_init +/APP + sti + movl %esp,%eax + pushl $0x17 + pushl %eax + pushfl + pushl $0x0f + pushl $1f + iret +1: movl $0x17,%eax + movw %ax,%ds + movw %ax,%es + movw %ax,%fs + movw %ax,%gs +/NO_APP + addl $12,%esp + movl $2,%eax +/APP + int $0x80 +/NO_APP + movl %eax,%edx + testl %edx,%edx + jge L75 + negl %edx + movl %edx,_errno + movl $-1,%edx +L75: + testl %edx,%edx + jne L74 + call _init +L74: +L77: + movl $29,%eax +/APP + int $0x80 +/NO_APP + jmp L77 + .align 2 + leal -16(%ebp),%esp + popl %esi + popl %edi + leave + ret + .align 2 +_printf: + pushl %ebx + leal 12(%esp),%eax + pushl %eax + pushl 12(%esp) + pushl $_printbuf + call _vsprintf + movl %eax,%ebx + pushl %ebx + pushl $_printbuf + pushl $1 + call _write + movl %ebx,%eax + addl $24,%esp + popl %ebx + ret +LC6: + .ascii "/dev/tty1\0" +LC7: + .ascii "%d buffers = %d bytes buffer space\12\15\0" +LC8: + .ascii "Free mem: %d bytes\12\15\0" +LC9: + .ascii "/etc/rc\0" +LC10: + .ascii "Fork failed in init\15\12\0" +LC11: + .ascii "\12\15child %d died with code %04x\12\15\0" + .align 2 +.globl _init +_init: + pushl %ebp + movl %esp,%ebp + subl $4,%esp + pushl %edi + pushl %esi + pushl %ebx + xorl %eax,%eax + movl $_drive_info,%ebx +/APP + int $0x80 +/NO_APP + testl %eax,%eax + jge L82 + negl %eax + movl %eax,_errno +L82: + pushl $0 + pushl $2 + pushl $LC6 + call _open + pushl $0 + call _dup + pushl $0 + call _dup + movl _nr_buffers,%eax + sall $10,%eax + pushl %eax + pushl _nr_buffers + pushl $LC7 + call _printf + addl $32,%esp + movl _memory_end,%eax + subl _main_memory_start,%eax + pushl %eax + pushl $LC8 + call _printf + addl $8,%esp + movl $2,%eax +/APP + int $0x80 +/NO_APP + testl %eax,%eax + jl L86 + movl %eax,%edi + jmp L85 + .align 2 +L86: + negl %eax + movl %eax,_errno + movl $-1,%edi +L85: + testl %edi,%edi + jne L84 + pushl $0 + call _close + pushl $0 + pushl $0 + pushl $LC9 + call _open + addl $16,%esp + testl %eax,%eax + je L87 + pushl $1 + call __exit + .align 2 +L87: + pushl $_envp_rc + pushl $_argv_rc + pushl $LC1 + call _execve + pushl $2 + call __exit + .align 2 +L84: + testl %edi,%edi + jle L88 + leal -4(%ebp),%esi +L89: + pushl %esi + call _wait + addl $4,%esp + cmpl %edi,%eax + jne L89 +L88: + leal -4(%ebp),%esi +L91: + movl $2,%eax +/APP + int $0x80 +/NO_APP + testl %eax,%eax + jge L94 + negl %eax + movl %eax,_errno + movl $-1,%eax +L94: + movl %eax,%edi + testl %edi,%edi + jge L93 + pushl $LC10 + call _printf + addl $4,%esp + jmp L91 + .align 2 +L93: + testl %edi,%edi + jne L96 + pushl $0 + call _close + pushl $1 + call _close + pushl $2 + call _close + call _setsid + pushl $0 + pushl $2 + pushl $LC6 + call _open + pushl $0 + call _dup + pushl $0 + call _dup + addl $32,%esp + pushl $_envp + pushl $_argv + pushl $LC1 + call _execve + pushl %eax + call __exit + .align 2 +L96: +L97: + pushl %esi + call _wait + addl $4,%esp + cmpl %edi,%eax + jne L97 + pushl -4(%ebp) + pushl %edi + pushl $LC11 + call _printf + addl $12,%esp + movl $36,%eax +/APP + int $0x80 +/NO_APP + testl %eax,%eax + jge L91 + negl %eax + movl %eax,_errno + jmp L91 + .align 2 + leal -16(%ebp),%esp + popl %ebx + popl %esi + popl %edi + leave + ret +.comm _drive_info,32 +.lcomm _term,32 +.lcomm _printbuf,1024 diff --git a/kernel/0.1x/linux-0.12/kernel/Makefile b/kernel/0.1x/linux-0.12/kernel/Makefile new file mode 100644 index 00000000..2c461117 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/Makefile @@ -0,0 +1,93 @@ +# +# 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 sys_call.o traps.o asm.o fork.o \ + panic.o printk.o vsprintf.o sys.o exit.o \ + signal.o mktime.o + +kernel.o: $(OBJS) + $(LD) -r -o kernel.o $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make keyboard.s + for i in *.c;do rm -f `basename $$i .c`.s;done + (cd chr_drv; make clean) + (cd blk_drv; make clean) + (cd math; make clean) + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + (cd chr_drv; make dep) + (cd blk_drv; make dep) + +### Dependencies: +exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \ + ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.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/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h +mktime.s mktime.o : mktime.c ../include/time.h +panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.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/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ + ../include/linux/sys.h ../include/linux/fdreg.h ../include/asm/system.h \ + ../include/asm/io.h ../include/asm/segment.h +signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ + ../include/asm/segment.h ../include/errno.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/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/linux/tty.h ../include/termios.h \ + ../include/linux/config.h ../include/asm/segment.h ../include/sys/times.h \ + ../include/sys/utsname.h ../include/string.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/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/asm/system.h ../include/asm/segment.h \ + ../include/asm/io.h +vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h diff --git a/kernel/0.1x/linux-0.12/kernel/asm.s b/kernel/0.1x/linux-0.12/kernel/asm.s new file mode 100644 index 00000000..074bbeac --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/asm.s @@ -0,0 +1,151 @@ +/* + * linux/kernel/asm.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * asm.s contains the low-level code for most hardware faults. + * page_exception is handled by the mm, so that isn't here. This + * file also handles (hopefully) fpu-exceptions due to TS-bit, as + * the fpu must be properly saved/resored. This hasn't been tested. + */ + +.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op +.globl _double_fault,_coprocessor_segment_overrun +.globl _invalid_TSS,_segment_not_present,_stack_segment +.globl _general_protection,_coprocessor_error,_irq13,_reserved +.globl _alignment_check + +_divide_error: + pushl $_do_divide_error +no_error_code: + xchgl %eax,(%esp) + pushl %ebx + pushl %ecx + pushl %edx + pushl %edi + pushl %esi + pushl %ebp + push %ds + push %es + push %fs + pushl $0 # "error code" + lea 44(%esp),%edx + pushl %edx + movl $0x10,%edx + mov %dx,%ds + mov %dx,%es + mov %dx,%fs + call *%eax + addl $8,%esp + pop %fs + pop %es + pop %ds + popl %ebp + popl %esi + popl %edi + popl %edx + popl %ecx + popl %ebx + popl %eax + iret + +_debug: + pushl $_do_int3 # _do_debug + jmp no_error_code + +_nmi: + pushl $_do_nmi + jmp no_error_code + +_int3: + pushl $_do_int3 + jmp no_error_code + +_overflow: + pushl $_do_overflow + jmp no_error_code + +_bounds: + pushl $_do_bounds + jmp no_error_code + +_invalid_op: + pushl $_do_invalid_op + jmp no_error_code + +_coprocessor_segment_overrun: + pushl $_do_coprocessor_segment_overrun + jmp no_error_code + +_reserved: + pushl $_do_reserved + jmp no_error_code + +_irq13: + pushl %eax + xorb %al,%al + outb %al,$0xF0 + movb $0x20,%al + outb %al,$0x20 + jmp 1f +1: jmp 1f +1: outb %al,$0xA0 + popl %eax + jmp _coprocessor_error + +_double_fault: + pushl $_do_double_fault +error_code: + xchgl %eax,4(%esp) # error code <-> %eax + xchgl %ebx,(%esp) # &function <-> %ebx + pushl %ecx + pushl %edx + pushl %edi + pushl %esi + pushl %ebp + push %ds + push %es + push %fs + pushl %eax # error code + lea 44(%esp),%eax # offset + pushl %eax + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + call *%ebx + addl $8,%esp + pop %fs + pop %es + pop %ds + popl %ebp + popl %esi + popl %edi + popl %edx + popl %ecx + popl %ebx + popl %eax + iret + +_invalid_TSS: + pushl $_do_invalid_TSS + jmp error_code + +_segment_not_present: + pushl $_do_segment_not_present + jmp error_code + +_stack_segment: + pushl $_do_stack_segment + jmp error_code + +_general_protection: + pushl $_do_general_protection + jmp error_code + +_alignment_check: + pushl $_do_alignment_check + jmp error_code + diff --git a/kernel/0.1x/linux-0.12/kernel/blk_drv/Makefile b/kernel/0.1x/linux-0.12/kernel/blk_drv/Makefile new file mode 100644 index 00000000..dec1af96 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/blk_drv/Makefile @@ -0,0 +1,71 @@ +# +# Makefile for the FREAX-kernel block device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =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 = ll_rw_blk.o floppy.o hd.o ramdisk.o + +blk_drv.a: $(OBJS) + $(AR) rcs blk_drv.a $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/fdreg.h \ + ../../include/asm/system.h ../../include/asm/io.h \ + ../../include/asm/segment.h blk.h +hd.s hd.o : hd.c ../../include/linux/config.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/hdreg.h \ + ../../include/asm/system.h ../../include/asm/io.h \ + ../../include/asm/segment.h blk.h +ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/asm/system.h blk.h +ramdisk.s ramdisk.o : ramdisk.c ../../include/string.h ../../include/linux/config.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/asm/system.h \ + ../../include/asm/segment.h ../../include/asm/memory.h blk.h diff --git a/kernel/0.1x/linux-0.12/kernel/blk_drv/blk.h b/kernel/0.1x/linux-0.12/kernel/blk_drv/blk.h new file mode 100644 index 00000000..54774a1e --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/blk_drv/blk.h @@ -0,0 +1,164 @@ +#ifndef _BLK_H +#define _BLK_H + +#define NR_BLK_DEV 7 +/* + * NR_REQUEST is the number of entries in the request-queue. + * NOTE that writes may use only the low 2/3 of these: reads + * take precedence. + * + * 32 seems to be a reasonable number: enough to get some benefit + * from the elevator-mechanism, but not so much as to lock a lot of + * buffers when they are in the queue. 64 seems to be too many (easily + * long pauses in reading when heavy writing/syncing is going on) + */ +#define NR_REQUEST 32 + +/* + * Ok, this is an expanded form so that we can use the same + * request for paging requests when that is implemented. In + * paging, 'bh' is NULL, and 'waiting' is used to wait for + * read/write completion. + */ +struct request { + int dev; /* -1 if no request */ + int cmd; /* READ or WRITE */ + int errors; + unsigned long sector; + unsigned long nr_sectors; + char * buffer; + struct task_struct * waiting; + struct buffer_head * bh; + struct request * next; +}; + +/* + * This is used in the elevator algorithm: Note that + * reads always go before writes. This is natural: reads + * are much more time-critical than writes. + */ +#define IN_ORDER(s1,s2) \ +((s1)->cmd<(s2)->cmd || (s1)->cmd==(s2)->cmd && \ +((s1)->dev < (s2)->dev || ((s1)->dev == (s2)->dev && \ +(s1)->sector < (s2)->sector))) + +struct blk_dev_struct { + void (*request_fn)(void); + struct request * current_request; +}; + +extern struct blk_dev_struct blk_dev[NR_BLK_DEV]; +extern struct request request[NR_REQUEST]; +extern struct task_struct * wait_for_request; + +extern int * blk_size[NR_BLK_DEV]; + +#ifdef MAJOR_NR + +/* + * Add entries as needed. Currently the only block devices + * supported are hard-disks and floppies. + */ + +#if (MAJOR_NR == 1) +/* ram disk */ +#define DEVICE_NAME "ramdisk" +#define DEVICE_REQUEST do_rd_request +#define DEVICE_NR(device) ((device) & 7) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == 2) +/* floppy */ +#define DEVICE_NAME "floppy" +#define DEVICE_INTR do_floppy +#define DEVICE_REQUEST do_fd_request +#define DEVICE_NR(device) ((device) & 3) +#define DEVICE_ON(device) floppy_on(DEVICE_NR(device)) +#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) + +#elif (MAJOR_NR == 3) +/* harddisk */ +#define DEVICE_NAME "harddisk" +#define DEVICE_INTR do_hd +#define DEVICE_TIMEOUT hd_timeout +#define DEVICE_REQUEST do_hd_request +#define DEVICE_NR(device) (MINOR(device)/5) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif +/* unknown blk device */ +#error "unknown blk device" + +#endif + +#define CURRENT (blk_dev[MAJOR_NR].current_request) +#define CURRENT_DEV DEVICE_NR(CURRENT->dev) + +#ifdef DEVICE_INTR +void (*DEVICE_INTR)(void) = NULL; +#endif +#ifdef DEVICE_TIMEOUT +int DEVICE_TIMEOUT = 0; +#define SET_INTR(x) (DEVICE_INTR = (x),DEVICE_TIMEOUT = 200) +#else +#define SET_INTR(x) (DEVICE_INTR = (x)) +#endif +static void (DEVICE_REQUEST)(void); + +extern inline void unlock_buffer(struct buffer_head * bh) +{ + if (!bh->b_lock) + printk(DEVICE_NAME ": free buffer being unlocked\n"); + bh->b_lock=0; + wake_up(&bh->b_wait); +} + +extern inline void end_request(int uptodate) +{ + DEVICE_OFF(CURRENT->dev); + if (CURRENT->bh) { + CURRENT->bh->b_uptodate = uptodate; + unlock_buffer(CURRENT->bh); + } + if (!uptodate) { + printk(DEVICE_NAME " I/O error\n\r"); + printk("dev %04x, block %d\n\r",CURRENT->dev, + CURRENT->bh->b_blocknr); + } + wake_up(&CURRENT->waiting); + wake_up(&wait_for_request); + CURRENT->dev = -1; + CURRENT = CURRENT->next; +} + +#ifdef DEVICE_TIMEOUT +#define CLEAR_DEVICE_TIMEOUT DEVICE_TIMEOUT = 0; +#else +#define CLEAR_DEVICE_TIMEOUT +#endif + +#ifdef DEVICE_INTR +#define CLEAR_DEVICE_INTR DEVICE_INTR = 0; +#else +#define CLEAR_DEVICE_INTR +#endif + +#define INIT_REQUEST \ +repeat: \ + if (!CURRENT) {\ + CLEAR_DEVICE_INTR \ + CLEAR_DEVICE_TIMEOUT \ + return; \ + } \ + if (MAJOR(CURRENT->dev) != MAJOR_NR) \ + panic(DEVICE_NAME ": request list destroyed"); \ + if (CURRENT->bh) { \ + if (!CURRENT->bh->b_lock) \ + panic(DEVICE_NAME ": block not locked"); \ + } + +#endif + +#endif diff --git a/kernel/0.1x/linux-0.12/kernel/blk_drv/floppy.c b/kernel/0.1x/linux-0.12/kernel/blk_drv/floppy.c new file mode 100644 index 00000000..644ad382 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/blk_drv/floppy.c @@ -0,0 +1,475 @@ +/* + * linux/kernel/floppy.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 02.12.91 - Changed to static variables to indicate need for reset + * and recalibrate. This makes some things easier (output_byte reset + * checking etc), and means less interrupt jumping in case of errors, + * so the code is hopefully easier to understand. + */ + +/* + * This file is certainly a mess. I've tried my best to get it working, + * but I don't like programming floppies, and I have only one anyway. + * Urgel. I should check for more errors, and do more graceful error + * recovery. Seems there are problems with several drives. I've tried to + * correct them. No promises. + */ + +/* + * As with hd.c, all routines within this file can (and will) be called + * by interrupts, so extreme caution is needed. A hardware interrupt + * handler may not sleep, or a kernel panic will happen. Thus I cannot + * call "floppy-on" directly, but have to set a special timer interrupt + * etc. + * + * Also, I'm not certain this works on more than 1 floppy. Bugs may + * abund. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 2 +#include "blk.h" + +static int recalibrate = 0; +static int reset = 0; +static int seek = 0; + +extern unsigned char current_DOR; + +#define immoutb_p(val,port) \ +__asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port)) + +#define TYPE(x) ((x)>>2) +#define DRIVE(x) ((x)&0x03) +/* + * Note that MAX_ERRORS=8 doesn't imply that we retry every bad read + * max 8 times - some types of errors increase the errorcount by 2, + * so we might actually retry only 5-6 times before giving up. + */ +#define MAX_ERRORS 8 + +/* + * globals used by 'result()' + */ +#define MAX_REPLIES 7 +static unsigned char reply_buffer[MAX_REPLIES]; +#define ST0 (reply_buffer[0]) +#define ST1 (reply_buffer[1]) +#define ST2 (reply_buffer[2]) +#define ST3 (reply_buffer[3]) + +/* + * This struct defines the different floppy types. Unlike minix + * linux doesn't have a "search for right type"-type, as the code + * for that is convoluted and weird. I've got enough problems with + * this driver as it is. + * + * The 'stretch' tells if the tracks need to be boubled for some + * types (ie 360kB diskette in 1.2MB drive etc). Others should + * be self-explanatory. + */ +static struct floppy_struct { + unsigned int size, sect, head, track, stretch; + unsigned char gap,rate,spec1; +} floppy_type[] = { + { 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */ + { 720, 9,2,40,0,0x2A,0x02,0xDF }, /* 360kB PC diskettes */ + { 2400,15,2,80,0,0x1B,0x00,0xDF }, /* 1.2 MB AT-diskettes */ + { 720, 9,2,40,1,0x2A,0x02,0xDF }, /* 360kB in 720kB drive */ + { 1440, 9,2,80,0,0x2A,0x02,0xDF }, /* 3.5" 720kB diskette */ + { 720, 9,2,40,1,0x23,0x01,0xDF }, /* 360kB in 1.2MB drive */ + { 1440, 9,2,80,0,0x23,0x01,0xDF }, /* 720kB in 1.2MB drive */ + { 2880,18,2,80,0,0x1B,0x00,0xCF }, /* 1.44MB diskette */ +}; + +/* + * Rate is 0 for 500kb/s, 2 for 300kbps, 1 for 250kbps + * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc), + * H is head unload time (1=16ms, 2=32ms, etc) + * + * Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms etc) + * and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA). + */ + +extern void floppy_interrupt(void); +extern char tmp_floppy_area[1024]; + +/* + * These are global variables, as that's the easiest way to give + * information to interrupts. They are the data used for the current + * request. + */ +static int cur_spec1 = -1; +static int cur_rate = -1; +static struct floppy_struct * floppy = floppy_type; +static unsigned char current_drive = 0; +static unsigned char sector = 0; +static unsigned char head = 0; +static unsigned char track = 0; +static unsigned char seek_track = 0; +static unsigned char current_track = 255; +static unsigned char command = 0; +unsigned char selected = 0; +struct task_struct * wait_on_floppy_select = NULL; + +void floppy_deselect(unsigned int nr) +{ + if (nr != (current_DOR & 3)) + printk("floppy_deselect: drive not selected\n\r"); + selected = 0; + wake_up(&wait_on_floppy_select); +} + +/* + * floppy-change is never called from an interrupt, so we can relax a bit + * here, sleep etc. Note that floppy-on tries to set current_DOR to point + * to the desired drive, but it will probably not survive the sleep if + * several floppies are used at the same time: thus the loop. + */ +int floppy_change(unsigned int nr) +{ +repeat: + floppy_on(nr); + while ((current_DOR & 3) != nr && selected) + sleep_on(&wait_on_floppy_select); + if ((current_DOR & 3) != nr) + goto repeat; + if (inb(FD_DIR) & 0x80) { + floppy_off(nr); + return 1; + } + floppy_off(nr); + return 0; +} + +#define copy_buffer(from,to) \ +__asm__("cld ; rep ; movsl" \ + ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \ + :"cx","di","si") + +static void setup_DMA(void) +{ + long addr = (long) CURRENT->buffer; + + cli(); + if (addr >= 0x100000) { + addr = (long) tmp_floppy_area; + if (command == FD_WRITE) + copy_buffer(CURRENT->buffer,tmp_floppy_area); + } +/* mask DMA 2 */ + immoutb_p(4|2,10); +/* output command byte. I don't know why, but everyone (minix, */ +/* sanches & canton) output this twice, first to 12 then to 11 */ + __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t" + "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:":: + "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE))); +/* 8 low bits of addr */ + immoutb_p(addr,4); + addr >>= 8; +/* bits 8-15 of addr */ + immoutb_p(addr,4); + addr >>= 8; +/* bits 16-19 of addr */ + immoutb_p(addr,0x81); +/* low 8 bits of count-1 (1024-1=0x3ff) */ + immoutb_p(0xff,5); +/* high 8 bits of count-1 */ + immoutb_p(3,5); +/* activate DMA 2 */ + immoutb_p(0|2,10); + sti(); +} + +static void output_byte(char byte) +{ + int counter; + unsigned char status; + + if (reset) + return; + for(counter = 0 ; counter < 10000 ; counter++) { + status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR); + if (status == STATUS_READY) { + outb(byte,FD_DATA); + return; + } + } + reset = 1; + printk("Unable to send byte to FDC\n\r"); +} + +static int result(void) +{ + int i = 0, counter, status; + + if (reset) + return -1; + for (counter = 0 ; counter < 10000 ; counter++) { + status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY); + if (status == STATUS_READY) + return i; + if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) { + if (i >= MAX_REPLIES) + break; + reply_buffer[i++] = inb_p(FD_DATA); + } + } + reset = 1; + printk("Getstatus times out\n\r"); + return -1; +} + +static void bad_flp_intr(void) +{ + CURRENT->errors++; + if (CURRENT->errors > MAX_ERRORS) { + floppy_deselect(current_drive); + end_request(0); + } + if (CURRENT->errors > MAX_ERRORS/2) + reset = 1; + else + recalibrate = 1; +} + +/* + * Ok, this interrupt is called after a DMA read/write has succeeded, + * so we check the results, and copy any buffers. + */ +static void rw_interrupt(void) +{ + if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73)) { + if (ST1 & 0x02) { + printk("Drive %d is write protected\n\r",current_drive); + floppy_deselect(current_drive); + end_request(0); + } else + bad_flp_intr(); + do_fd_request(); + return; + } + if (command == FD_READ && (unsigned long)(CURRENT->buffer) >= 0x100000) + copy_buffer(tmp_floppy_area,CURRENT->buffer); + floppy_deselect(current_drive); + end_request(1); + do_fd_request(); +} + +inline void setup_rw_floppy(void) +{ + setup_DMA(); + do_floppy = rw_interrupt; + output_byte(command); + output_byte(head<<2 | current_drive); + output_byte(track); + output_byte(head); + output_byte(sector); + output_byte(2); /* sector size = 512 */ + output_byte(floppy->sect); + output_byte(floppy->gap); + output_byte(0xFF); /* sector size (0xff when n!=0 ?) */ + if (reset) + do_fd_request(); +} + +/* + * This is the routine called after every seek (or recalibrate) interrupt + * from the floppy controller. Note that the "unexpected interrupt" routine + * also does a recalibrate, but doesn't come here. + */ +static void seek_interrupt(void) +{ +/* sense drive status */ + output_byte(FD_SENSEI); + if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) { + bad_flp_intr(); + do_fd_request(); + return; + } + current_track = ST1; + setup_rw_floppy(); +} + +/* + * This routine is called when everything should be correctly set up + * for the transfer (ie floppy motor is on and the correct floppy is + * selected). + */ +static void transfer(void) +{ + if (cur_spec1 != floppy->spec1) { + cur_spec1 = floppy->spec1; + output_byte(FD_SPECIFY); + output_byte(cur_spec1); /* hut etc */ + output_byte(6); /* Head load time =6ms, DMA */ + } + if (cur_rate != floppy->rate) + outb_p(cur_rate = floppy->rate,FD_DCR); + if (reset) { + do_fd_request(); + return; + } + if (!seek) { + setup_rw_floppy(); + return; + } + do_floppy = seek_interrupt; + if (seek_track) { + output_byte(FD_SEEK); + output_byte(head<<2 | current_drive); + output_byte(seek_track); + } else { + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); + } + if (reset) + do_fd_request(); +} + +/* + * Special case - used after a unexpected interrupt (or reset) + */ +static void recal_interrupt(void) +{ + output_byte(FD_SENSEI); + if (result()!=2 || (ST0 & 0xE0) == 0x60) + reset = 1; + else + recalibrate = 0; + do_fd_request(); +} + +void unexpected_floppy_interrupt(void) +{ + output_byte(FD_SENSEI); + if (result()!=2 || (ST0 & 0xE0) == 0x60) + reset = 1; + else + recalibrate = 1; +} + +static void recalibrate_floppy(void) +{ + recalibrate = 0; + current_track = 0; + do_floppy = recal_interrupt; + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); + if (reset) + do_fd_request(); +} + +static void reset_interrupt(void) +{ + output_byte(FD_SENSEI); + (void) result(); + output_byte(FD_SPECIFY); + output_byte(cur_spec1); /* hut etc */ + output_byte(6); /* Head load time =6ms, DMA */ + do_fd_request(); +} + +/* + * reset is done by pulling bit 2 of DOR low for a while. + */ +static void reset_floppy(void) +{ + int i; + + reset = 0; + cur_spec1 = -1; + cur_rate = -1; + recalibrate = 1; + printk("Reset-floppy called\n\r"); + cli(); + do_floppy = reset_interrupt; + outb_p(current_DOR & ~0x04,FD_DOR); + for (i=0 ; i<100 ; i++) + __asm__("nop"); + outb(current_DOR,FD_DOR); + sti(); +} + +static void floppy_on_interrupt(void) +{ +/* We cannot do a floppy-select, as that might sleep. We just force it */ + selected = 1; + if (current_drive != (current_DOR & 3)) { + current_DOR &= 0xFC; + current_DOR |= current_drive; + outb(current_DOR,FD_DOR); + add_timer(2,&transfer); + } else + transfer(); +} + +void do_fd_request(void) +{ + unsigned int block; + + seek = 0; + if (reset) { + reset_floppy(); + return; + } + if (recalibrate) { + recalibrate_floppy(); + return; + } + INIT_REQUEST; + floppy = (MINOR(CURRENT->dev)>>2) + floppy_type; + if (current_drive != CURRENT_DEV) + seek = 1; + current_drive = CURRENT_DEV; + block = CURRENT->sector; + if (block+2 > floppy->size) { + end_request(0); + goto repeat; + } + sector = block % floppy->sect; + block /= floppy->sect; + head = block % floppy->head; + track = block / floppy->head; + seek_track = track << floppy->stretch; + if (seek_track != current_track) + seek = 1; + sector++; + if (CURRENT->cmd == READ) + command = FD_READ; + else if (CURRENT->cmd == WRITE) + command = FD_WRITE; + else + panic("do_fd_request: unknown command"); + add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt); +} + +static int floppy_sizes[] ={ + 0, 0, 0, 0, + 360, 360 ,360, 360, + 1200,1200,1200,1200, + 360, 360, 360, 360, + 720, 720, 720, 720, + 360, 360, 360, 360, + 720, 720, 720, 720, + 1440,1440,1440,1440 +}; + +void floppy_init(void) +{ + blk_size[MAJOR_NR] = floppy_sizes; + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + set_trap_gate(0x26,&floppy_interrupt); + outb(inb_p(0x21)&~0x40,0x21); +} diff --git a/kernel/0.1x/linux-0.12/kernel/blk_drv/hd.c b/kernel/0.1x/linux-0.12/kernel/blk_drv/hd.c new file mode 100644 index 00000000..9aba4bf0 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/blk_drv/hd.c @@ -0,0 +1,384 @@ +/* + * linux/kernel/hd.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This is the low-level hd interrupt support. It traverses the + * request-list, using interrupts to jump between functions. As + * all the functions are called within interrupts, we may not + * sleep. Special care is recommended. + * + * modified by Drew Eckhardt to check nr of hd's from the CMOS. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 3 +#include "blk.h" + +#define CMOS_READ(addr) ({ \ +outb_p(0x80|addr,0x70); \ +inb_p(0x71); \ +}) + +/* Max read/write errors/sector */ +#define MAX_ERRORS 7 +#define MAX_HD 2 + +static void recal_intr(void); +static void bad_rw_intr(void); + +static int recalibrate = 0; +static int reset = 0; + +/* + * This struct defines the HD's and their types. + */ +struct hd_i_struct { + int head,sect,cyl,wpcom,lzone,ctl; + }; +#ifdef HD_TYPE +struct hd_i_struct hd_info[] = { HD_TYPE }; +#define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct))) +#else +struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} }; +static int NR_HD = 0; +#endif + +static struct hd_struct { + long start_sect; + long nr_sects; +} hd[5*MAX_HD]={{0,0},}; + +static int hd_sizes[5*MAX_HD] = {0, }; + +#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); +extern void rd_load(void); + +/* This may be used only once, enforced by 'static int callable' */ +int sys_setup(void * BIOS) +{ + static int callable = 1; + int i,drive; + unsigned char cmos_disks; + struct partition *p; + struct buffer_head * bh; + + if (!callable) + return -1; + callable = 0; +#ifndef HD_TYPE + for (drive=0 ; drive<2 ; drive++) { + hd_info[drive].cyl = *(unsigned short *) BIOS; + hd_info[drive].head = *(unsigned char *) (2+BIOS); + hd_info[drive].wpcom = *(unsigned short *) (5+BIOS); + hd_info[drive].ctl = *(unsigned char *) (8+BIOS); + hd_info[drive].lzone = *(unsigned short *) (12+BIOS); + hd_info[drive].sect = *(unsigned char *) (14+BIOS); + BIOS += 16; + } + if (hd_info[1].cyl) + NR_HD=2; + else + NR_HD=1; +#endif + for (i=0 ; i are the primary drives in the system, and + the ones reflected as drive 1 or 2. + + The first drive is stored in the high nibble of CMOS + byte 0x12, the second in the low nibble. This will be + either a 4 bit drive type or 0xf indicating use byte 0x19 + for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. + + Needless to say, a non-zero value means we have + an AT controller hard disk for that drive. + + + */ + + if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) + if (cmos_disks & 0x0f) + NR_HD = 2; + else + NR_HD = 1; + else + NR_HD = 0; + for (i = NR_HD ; i < 2 ; i++) { + hd[i*5].start_sect = 0; + hd[i*5].nr_sects = 0; + } + for (drive=0 ; driveb_data[510] != 0x55 || (unsigned char) + bh->b_data[511] != 0xAA) { + printk("Bad partition table on drive %d\n\r",drive); + panic(""); + } + p = 0x1BE + (void *)bh->b_data; + for (i=1;i<5;i++,p++) { + hd[i+5*drive].start_sect = p->start_sect; + hd[i+5*drive].nr_sects = p->nr_sects; + } + brelse(bh); + } + for (i=0 ; i<5*MAX_HD ; i++) + hd_sizes[i] = hd[i].nr_sects>>1 ; + blk_size[MAJOR_NR] = hd_sizes; + if (NR_HD) + printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":""); + rd_load(); + init_swapping(); + mount_root(); + return (0); +} + +static int controller_ready(void) +{ + int retries = 100000; + + while (--retries && (inb_p(HD_STATUS)&0xc0)!=0x40); + return (retries); +} + +static int win_result(void) +{ + int i=inb_p(HD_STATUS); + + if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)) + == (READY_STAT | SEEK_STAT)) + return(0); /* ok */ + if (i&1) i=inb(HD_ERROR); + return (1); +} + +static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect, + unsigned int head,unsigned int cyl,unsigned int cmd, + void (*intr_addr)(void)) +{ + register int port asm("dx"); + + if (drive>1 || head>15) + panic("Trying to write bad sector"); + if (!controller_ready()) + panic("HD controller not ready"); + SET_INTR(intr_addr); + outb_p(hd_info[drive].ctl,HD_CMD); + port=HD_DATA; + outb_p(hd_info[drive].wpcom>>2,++port); + outb_p(nsect,++port); + outb_p(sect,++port); + outb_p(cyl,++port); + outb_p(cyl>>8,++port); + outb_p(0xA0|(drive<<4)|head,++port); + outb(cmd,++port); +} + +static int drive_busy(void) +{ + unsigned int i; + unsigned char c; + + for (i = 0; i < 50000; i++) { + c = inb_p(HD_STATUS); + c &= (BUSY_STAT | READY_STAT | SEEK_STAT); + if (c == (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(hd_info[0].ctl & 0x0f ,HD_CMD); + if (drive_busy()) + printk("HD-controller still busy\n\r"); + if ((i = inb(HD_ERROR)) != 1) + printk("HD-controller reset failed: %02x\n\r",i); +} + +static void reset_hd(void) +{ + static int i; + +repeat: + if (reset) { + reset = 0; + i = -1; + reset_controller(); + } else if (win_result()) { + bad_rw_intr(); + if (reset) + goto repeat; + } + i++; + if (i < NR_HD) { + hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1, + hd_info[i].cyl,WIN_SPECIFY,&reset_hd); + } else + do_hd_request(); +} + +void unexpected_hd_interrupt(void) +{ + printk("Unexpected HD interrupt\n\r"); + reset = 1; + do_hd_request(); +} + +static void bad_rw_intr(void) +{ + if (++CURRENT->errors >= MAX_ERRORS) + end_request(0); + if (CURRENT->errors > MAX_ERRORS/2) + reset = 1; +} + +static void read_intr(void) +{ + if (win_result()) { + bad_rw_intr(); + do_hd_request(); + return; + } + port_read(HD_DATA,CURRENT->buffer,256); + CURRENT->errors = 0; + CURRENT->buffer += 512; + CURRENT->sector++; + if (--CURRENT->nr_sectors) { + SET_INTR(&read_intr); + return; + } + end_request(1); + do_hd_request(); +} + +static void write_intr(void) +{ + if (win_result()) { + bad_rw_intr(); + do_hd_request(); + return; + } + if (--CURRENT->nr_sectors) { + CURRENT->sector++; + CURRENT->buffer += 512; + SET_INTR(&write_intr); + port_write(HD_DATA,CURRENT->buffer,256); + return; + } + end_request(1); + do_hd_request(); +} + +static void recal_intr(void) +{ + if (win_result()) + bad_rw_intr(); + do_hd_request(); +} + +void hd_times_out(void) +{ + if (!CURRENT) + return; + printk("HD timeout"); + if (++CURRENT->errors >= MAX_ERRORS) + end_request(0); + SET_INTR(NULL); + reset = 1; + do_hd_request(); +} + +void do_hd_request(void) +{ + int i,r; + unsigned int block,dev; + unsigned int sec,head,cyl; + unsigned int nsect; + + INIT_REQUEST; + dev = MINOR(CURRENT->dev); + block = CURRENT->sector; + if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) { + end_request(0); + goto repeat; + } + block += hd[dev].start_sect; + dev /= 5; + __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0), + "r" (hd_info[dev].sect)); + __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0), + "r" (hd_info[dev].head)); + sec++; + nsect = CURRENT->nr_sectors; + if (reset) { + recalibrate = 1; + reset_hd(); + return; + } + if (recalibrate) { + recalibrate = 0; + hd_out(dev,hd_info[CURRENT_DEV].sect,0,0,0, + WIN_RESTORE,&recal_intr); + return; + } + if (CURRENT->cmd == WRITE) { + hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr); + for(i=0 ; i<10000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++) + /* nothing */ ; + if (!r) { + bad_rw_intr(); + goto repeat; + } + port_write(HD_DATA,CURRENT->buffer,256); + } else if (CURRENT->cmd == READ) { + hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr); + } else + panic("unknown hd-command"); +} + +void hd_init(void) +{ + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + set_intr_gate(0x2E,&hd_interrupt); + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xbf,0xA1); +} diff --git a/kernel/0.1x/linux-0.12/kernel/blk_drv/ll_rw_blk.c b/kernel/0.1x/linux-0.12/kernel/blk_drv/ll_rw_blk.c new file mode 100644 index 00000000..a28fc7b1 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/blk_drv/ll_rw_blk.c @@ -0,0 +1,218 @@ +/* + * linux/kernel/blk_dev/ll_rw.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This handles all read/write requests to block devices + */ +#include +#include +#include +#include + +#include "blk.h" + +/* + * The request-struct contains all necessary data + * to load a nr of sectors into memory + */ +struct request request[NR_REQUEST]; + +/* + * used to wait on when there are no free requests + */ +struct task_struct * wait_for_request = NULL; + +/* blk_dev_struct is: + * do_request-address + * next-request + */ +struct blk_dev_struct blk_dev[NR_BLK_DEV] = { + { NULL, NULL }, /* no_dev */ + { NULL, NULL }, /* dev mem */ + { NULL, NULL }, /* dev fd */ + { NULL, NULL }, /* dev hd */ + { NULL, NULL }, /* dev ttyx */ + { NULL, NULL }, /* dev tty */ + { NULL, NULL } /* dev lp */ +}; + +/* + * blk_size contains the size of all block-devices: + * + * blk_size[MAJOR][MINOR] + * + * if (!blk_size[MAJOR]) then no minor size checking is done. + */ +int * blk_size[NR_BLK_DEV] = { NULL, NULL, }; + +static inline void lock_buffer(struct buffer_head * bh) +{ + cli(); + while (bh->b_lock) + sleep_on(&bh->b_wait); + bh->b_lock=1; + sti(); +} + +static inline void unlock_buffer(struct buffer_head * bh) +{ + if (!bh->b_lock) + printk("ll_rw_block.c: buffer not locked\n\r"); + bh->b_lock = 0; + wake_up(&bh->b_wait); +} + +/* + * add-request adds a request to the linked list. + * It disables interrupts so that it can muck with the + * request-lists in peace. + * + * Note that swapping requests always go before other requests, + * and are done in the order they appear. + */ +static void add_request(struct blk_dev_struct * dev, struct request * req) +{ + struct request * tmp; + + req->next = NULL; + cli(); + if (req->bh) + req->bh->b_dirt = 0; + if (!(tmp = dev->current_request)) { + dev->current_request = req; + sti(); + (dev->request_fn)(); + return; + } + for ( ; tmp->next ; tmp=tmp->next) { + if (!req->bh) + if (tmp->next->bh) + break; + else + continue; + if ((IN_ORDER(tmp,req) || + !IN_ORDER(tmp,tmp->next)) && + IN_ORDER(req,tmp->next)) + break; + } + req->next=tmp->next; + tmp->next=req; + sti(); +} + +static void make_request(int major,int rw, struct buffer_head * bh) +{ + struct request * req; + int rw_ahead; + +/* WRITEA/READA is special case - it is not really needed, so if the */ +/* buffer is locked, we just forget about it, else it's a normal read */ + if (rw_ahead = (rw == READA || rw == WRITEA)) { + if (bh->b_lock) + return; + if (rw == READA) + rw = READ; + else + rw = WRITE; + } + if (rw!=READ && rw!=WRITE) + panic("Bad block dev command, must be R/W/RA/WA"); + lock_buffer(bh); + if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) { + unlock_buffer(bh); + return; + } +repeat: +/* we don't allow the write-requests to fill up the queue completely: + * we want some room for reads: they take precedence. The last third + * of the requests are only for reads. + */ + if (rw == READ) + req = request+NR_REQUEST; + else + req = request+((NR_REQUEST*2)/3); +/* find an empty request */ + while (--req >= request) + if (req->dev<0) + break; +/* if none found, sleep on new requests: check for rw_ahead */ + if (req < request) { + if (rw_ahead) { + unlock_buffer(bh); + return; + } + sleep_on(&wait_for_request); + goto repeat; + } +/* fill up the request-info, and add it to the queue */ + req->dev = bh->b_dev; + req->cmd = rw; + req->errors=0; + req->sector = bh->b_blocknr<<1; + req->nr_sectors = 2; + req->buffer = bh->b_data; + req->waiting = NULL; + req->bh = bh; + req->next = NULL; + add_request(major+blk_dev,req); +} + +void ll_rw_page(int rw, int dev, int page, char * buffer) +{ + struct request * req; + unsigned int major = MAJOR(dev); + + if (major >= NR_BLK_DEV || !(blk_dev[major].request_fn)) { + printk("Trying to read nonexistent block-device\n\r"); + return; + } + if (rw!=READ && rw!=WRITE) + panic("Bad block dev command, must be R/W"); +repeat: + req = request+NR_REQUEST; + while (--req >= request) + if (req->dev<0) + break; + if (req < request) { + sleep_on(&wait_for_request); + goto repeat; + } +/* fill up the request-info, and add it to the queue */ + req->dev = dev; + req->cmd = rw; + req->errors = 0; + req->sector = page<<3; + req->nr_sectors = 8; + req->buffer = buffer; + req->waiting = current; + req->bh = NULL; + req->next = NULL; + current->state = TASK_UNINTERRUPTIBLE; + add_request(major+blk_dev,req); + schedule(); +} + +void ll_rw_block(int rw, struct buffer_head * bh) +{ + unsigned int major; + + if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || + !(blk_dev[major].request_fn)) { + printk("Trying to read nonexistent block-device\n\r"); + return; + } + make_request(major,rw,bh); +} + +void blk_dev_init(void) +{ + int i; + + for (i=0 ; i + +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 1 +#include "blk.h" + +char *rd_start; +int rd_length = 0; + +void do_rd_request(void) +{ + int len; + char *addr; + + INIT_REQUEST; + addr = rd_start + (CURRENT->sector << 9); + len = CURRENT->nr_sectors << 9; + if ((MINOR(CURRENT->dev) != 1) || (addr+len > rd_start+rd_length)) { + end_request(0); + goto repeat; + } + if (CURRENT-> cmd == WRITE) { + (void ) memcpy(addr, + CURRENT->buffer, + len); + } else if (CURRENT->cmd == READ) { + (void) memcpy(CURRENT->buffer, + addr, + len); + } else + panic("unknown ramdisk-command"); + end_request(1); + goto repeat; +} + +/* + * Returns amount of memory which needs to be reserved. + */ +long rd_init(long mem_start, int length) +{ + int i; + char *cp; + + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + rd_start = (char *) mem_start; + rd_length = length; + cp = rd_start; + for (i=0; i < length; i++) + *cp++ = '\0'; + return(length); +} + +/* + * If the root device is the ram disk, try to load it. + * In order to do this, the root device is originally set to the + * floppy, and we later change it to be ram disk. + */ +void rd_load(void) +{ + struct buffer_head *bh; + struct super_block s; + int block = 256; /* Start at block 256 */ + int i = 1; + int nblocks; + char *cp; /* Move pointer */ + + if (!rd_length) + return; + printk("Ram disk: %d bytes, starting at 0x%x\n", rd_length, + (int) rd_start); + if (MAJOR(ROOT_DEV) != 2) + return; + bh = breada(ROOT_DEV,block+1,block,block+2,-1); + if (!bh) { + printk("Disk error while looking for ramdisk!\n"); + return; + } + *((struct d_super_block *) &s) = *((struct d_super_block *) bh->b_data); + brelse(bh); + if (s.s_magic != SUPER_MAGIC) + /* No ram disk image present, assume normal floppy boot */ + return; + nblocks = s.s_nzones << s.s_log_zone_size; + if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) { + printk("Ram disk image too big! (%d blocks, %d avail)\n", + nblocks, rd_length >> BLOCK_SIZE_BITS); + return; + } + printk("Loading %d bytes into ram disk... 0000k", + nblocks << BLOCK_SIZE_BITS); + cp = rd_start; + while (nblocks) { + if (nblocks > 2) + bh = breada(ROOT_DEV, block, block+1, block+2, -1); + else + bh = bread(ROOT_DEV, block); + if (!bh) { + printk("I/O error on block %d, aborting load\n", + block); + return; + } + (void) memcpy(cp, bh->b_data, BLOCK_SIZE); + brelse(bh); + printk("\010\010\010\010\010%4dk",i); + cp += BLOCK_SIZE; + block++; + nblocks--; + i++; + } + printk("\010\010\010\010\010done \n"); + ROOT_DEV=0x0101; +} diff --git a/kernel/0.1x/linux-0.12/kernel/chr_drv/Makefile b/kernel/0.1x/linux-0.12/kernel/chr_drv/Makefile new file mode 100644 index 00000000..ac074cfe --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/chr_drv/Makefile @@ -0,0 +1,88 @@ +# +# Makefile for the FREAX-kernel character device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =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 = tty_io.o console.o keyboard.o serial.o rs_io.o \ + tty_ioctl.o pty.o + +chr_drv.a: $(OBJS) + $(AR) rcs chr_drv.a $(OBJS) + sync + +keyboard.s: keyboard.S + $(CPP) -traditional keyboard.S -o keyboard.s + +clean: + rm -f core *.o *.a tmp_make keyboard.s + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +console.s console.o : console.c ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/tty.h \ + ../../include/termios.h ../../include/linux/config.h ../../include/asm/io.h \ + ../../include/asm/system.h ../../include/asm/segment.h \ + ../../include/string.h ../../include/errno.h +pty.s pty.o : pty.c ../../include/linux/tty.h ../../include/termios.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ + ../../include/time.h ../../include/sys/resource.h \ + ../../include/asm/system.h ../../include/asm/io.h +serial.s serial.o : serial.c ../../include/linux/tty.h ../../include/termios.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ + ../../include/time.h ../../include/sys/resource.h \ + ../../include/asm/system.h ../../include/asm/io.h +tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \ + ../../include/signal.h ../../include/sys/types.h ../../include/unistd.h \ + ../../include/sys/stat.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/times.h ../../include/sys/utsname.h \ + ../../include/sys/param.h ../../include/sys/resource.h \ + ../../include/utime.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 ../../include/asm/system.h +tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ + ../../include/time.h ../../include/sys/resource.h ../../include/linux/tty.h \ + ../../include/asm/io.h ../../include/asm/segment.h \ + ../../include/asm/system.h diff --git a/kernel/0.1x/linux-0.12/kernel/chr_drv/console.c b/kernel/0.1x/linux-0.12/kernel/chr_drv/console.c new file mode 100644 index 00000000..b5021915 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/chr_drv/console.c @@ -0,0 +1,1025 @@ +/* + * linux/kernel/console.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * console.c + * + * This module implements the console io functions + * 'void con_init(void)' + * 'void con_write(struct tty_queue * queue)' + * Hopefully this will be a rather complete VT102 implementation. + * + * Beeping thanks to John T Kohl. + * + * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics + * Chars, and VT100 enhancements by Peter MacDonald. + */ + +/* + * NOTE!!! We sometimes disable and enable interrupts for a short while + * (to put a word in video IO), but this will work even for keyboard + * interrupts. We know interrupts aren't enabled when getting a keyboard + * interrupt, as we use trap-gates. Hopefully all is well. + */ + +/* + * Code to check for different video-cards mostly by Galen Hunt, + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define DEF_TERMIOS \ +(struct termios) { \ + ICRNL, \ + OPOST | ONLCR, \ + 0, \ + IXON | ISIG | ICANON | ECHO | ECHOCTL | ECHOKE, \ + 0, \ + INIT_C_CC \ +} + + +/* + * These are set up by the setup-routine at boot-time: + */ + +#define ORIG_X (*(unsigned char *)0x90000) +#define ORIG_Y (*(unsigned char *)0x90001) +#define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004) +#define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff) +#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8) +#define ORIG_VIDEO_LINES ((*(unsigned short *)0x9000e) & 0xff) +#define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008) +#define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a) +#define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c) + +#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ +#define VIDEO_TYPE_CGA 0x11 /* CGA Display */ +#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */ +#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */ + +#define NPAR 16 + +int NR_CONSOLES = 0; + +extern void keyboard_interrupt(void); + +static unsigned char video_type; /* Type of display being used */ +static unsigned long video_num_columns; /* Number of text columns */ +static unsigned long video_mem_base; /* Base of video memory */ +static unsigned long video_mem_term; /* End of video memory */ +static unsigned long video_size_row; /* Bytes per row */ +static unsigned long video_num_lines; /* Number of test lines */ +static unsigned char video_page; /* Initial video page */ +static unsigned short video_port_reg; /* Video register select port */ +static unsigned short video_port_val; /* Video register value port */ +static int can_do_colour = 0; + +static struct { + unsigned short vc_video_erase_char; + unsigned char vc_attr; + unsigned char vc_def_attr; + int vc_bold_attr; + unsigned long vc_ques; + unsigned long vc_state; + unsigned long vc_restate; + unsigned long vc_checkin; + unsigned long vc_origin; /* Used for EGA/VGA fast scroll */ + unsigned long vc_scr_end; /* Used for EGA/VGA fast scroll */ + unsigned long vc_pos; + unsigned long vc_x,vc_y; + unsigned long vc_top,vc_bottom; + unsigned long vc_npar,vc_par[NPAR]; + unsigned long vc_video_mem_start; /* Start of video RAM */ + unsigned long vc_video_mem_end; /* End of video RAM (sort of) */ + unsigned int vc_saved_x; + unsigned int vc_saved_y; + unsigned int vc_iscolor; + char * vc_translate; +} vc_cons [MAX_CONSOLES]; + +#define origin (vc_cons[currcons].vc_origin) +#define scr_end (vc_cons[currcons].vc_scr_end) +#define pos (vc_cons[currcons].vc_pos) +#define top (vc_cons[currcons].vc_top) +#define bottom (vc_cons[currcons].vc_bottom) +#define x (vc_cons[currcons].vc_x) +#define y (vc_cons[currcons].vc_y) +#define state (vc_cons[currcons].vc_state) +#define restate (vc_cons[currcons].vc_restate) +#define checkin (vc_cons[currcons].vc_checkin) +#define npar (vc_cons[currcons].vc_npar) +#define par (vc_cons[currcons].vc_par) +#define ques (vc_cons[currcons].vc_ques) +#define attr (vc_cons[currcons].vc_attr) +#define saved_x (vc_cons[currcons].vc_saved_x) +#define saved_y (vc_cons[currcons].vc_saved_y) +#define translate (vc_cons[currcons].vc_translate) +#define video_mem_start (vc_cons[currcons].vc_video_mem_start) +#define video_mem_end (vc_cons[currcons].vc_video_mem_end) +#define def_attr (vc_cons[currcons].vc_def_attr) +#define video_erase_char (vc_cons[currcons].vc_video_erase_char) +#define iscolor (vc_cons[currcons].vc_iscolor) + +int blankinterval = 0; +int blankcount = 0; + +static void sysbeep(void); + +/* + * this is what the terminal answers to a ESC-Z or csi0c + * query (= vt100 response). + */ +#define RESPONSE "\033[?1;2c" + +static char * translations[] = { +/* normal 7-bit ascii */ + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~ ", +/* vt100 graphics */ + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ " + "\004\261\007\007\007\007\370\361\007\007\275\267\326\323\327\304" + "\304\304\304\304\307\266\320\322\272\363\362\343\\007\234\007 " +}; + +#define NORM_TRANS (translations[0]) +#define GRAF_TRANS (translations[1]) + +/* NOTE! gotoxy thinks x==video_num_columns is ok */ +static inline void gotoxy(int currcons, int new_x,unsigned int new_y) +{ + if (new_x > video_num_columns || new_y >= video_num_lines) + return; + x = new_x; + y = new_y; + pos = origin + y*video_size_row + (x<<1); +} + +static inline void set_origin(int currcons) +{ + if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM) + return; + if (currcons != fg_console) + return; + cli(); + outb_p(12, video_port_reg); + outb_p(0xff&((origin-video_mem_base)>>9), video_port_val); + outb_p(13, video_port_reg); + outb_p(0xff&((origin-video_mem_base)>>1), video_port_val); + sti(); +} + +static void scrup(int currcons) +{ + if (bottom<=top) + return; + if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) + { + if (!top && bottom == video_num_lines) { + origin += video_size_row; + pos += video_size_row; + scr_end += video_size_row; + if (scr_end > video_mem_end) { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl _video_num_columns,%1\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((video_num_lines-1)*video_num_columns>>1), + "D" (video_mem_start), + "S" (origin) + :"cx","di","si"); + scr_end -= origin-video_mem_start; + pos -= origin-video_mem_start; + origin = video_mem_start; + } else { + __asm__("cld\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" (video_num_columns), + "D" (scr_end-video_size_row) + :"cx","di"); + } + set_origin(currcons); + } else { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl _video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*top), + "S" (origin+video_size_row*(top+1)) + :"cx","di","si"); + } + } + else /* Not EGA/VGA */ + { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl _video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*top), + "S" (origin+video_size_row*(top+1)) + :"cx","di","si"); + } +} + +static void scrdown(int currcons) +{ + if (bottom <= top) + return; + if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) + { + __asm__("std\n\t" + "rep\n\t" + "movsl\n\t" + "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ + "movl _video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*bottom-4), + "S" (origin+video_size_row*(bottom-1)-4) + :"ax","cx","di","si"); + } + else /* Not EGA/VGA */ + { + __asm__("std\n\t" + "rep\n\t" + "movsl\n\t" + "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ + "movl _video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*bottom-4), + "S" (origin+video_size_row*(bottom-1)-4) + :"ax","cx","di","si"); + } +} + +static void lf(int currcons) +{ + if (y+1top) { + y--; + pos -= video_size_row; + return; + } + scrdown(currcons); +} + +static void cr(int currcons) +{ + pos -= x<<1; + x=0; +} + +static void del(int currcons) +{ + if (x) { + pos -= 2; + x--; + *(unsigned short *)pos = video_erase_char; + } +} + +static void csi_J(int currcons, int vpar) +{ + long count __asm__("cx"); + long start __asm__("di"); + + switch (vpar) { + case 0: /* erase from cursor to end of display */ + count = (scr_end-pos)>>1; + start = pos; + break; + case 1: /* erase from start to cursor */ + count = (pos-origin)>>1; + start = origin; + break; + case 2: /* erase whole display */ + count = video_num_columns * video_num_lines; + start = origin; + break; + default: + return; + } + __asm__("cld\n\t" + "rep\n\t" + "stosw\n\t" + ::"c" (count), + "D" (start),"a" (video_erase_char) + :"cx","di"); +} + +static void csi_K(int currcons, int vpar) +{ + long count __asm__("cx"); + long start __asm__("di"); + + switch (vpar) { + case 0: /* erase from cursor to end of line */ + if (x>=video_num_columns) + return; + count = video_num_columns-x; + start = pos; + break; + case 1: /* erase from start of line to cursor */ + start = pos - (x<<1); + count = (x>4)&0xf)? + (attr&0xf0)|(((attr&0xf)+1)%0xf): + newattr); + } + } + break; + case 5: attr=attr|0x80;break; /* blinking */ + case 7: attr=(attr<<4)|(attr>>4);break; /* negative */ + case 22: attr=attr&0xf7;break; /* not bold */ + case 24: attr=attr&0xfe;break; /* not underline */ + case 25: attr=attr&0x7f;break; /* not blinking */ + case 27: attr=def_attr;break; /* positive image */ + case 39: attr=(attr & 0xf0)|(def_attr & 0x0f); break; + case 49: attr=(attr & 0x0f)|(def_attr & 0xf0); break; + default: + if (!can_do_colour) + break; + iscolor = 1; + if ((par[i]>=30) && (par[i]<=38)) + attr = (attr & 0xf0) | (par[i]-30); + else /* Background color */ + if ((par[i]>=40) && (par[i]<=48)) + attr = (attr & 0x0f) | ((par[i]-40)<<4); + else + break; + } +} + +static inline void set_cursor(int currcons) +{ + blankcount = blankinterval; + if (currcons != fg_console) + return; + cli(); + outb_p(14, video_port_reg); + outb_p(0xff&((pos-video_mem_base)>>9), video_port_val); + outb_p(15, video_port_reg); + outb_p(0xff&((pos-video_mem_base)>>1), video_port_val); + sti(); +} + +static inline void hide_cursor(int currcons) +{ + outb_p(14, video_port_reg); + outb_p(0xff&((scr_end-video_mem_base)>>9), video_port_val); + outb_p(15, video_port_reg); + outb_p(0xff&((scr_end-video_mem_base)>>1), video_port_val); +} + +static void respond(int currcons, 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(int currcons) +{ + int i=x; + unsigned short tmp, old = video_erase_char; + unsigned short * p = (unsigned short *) pos; + + while (i++=video_num_columns) + return; + i = x; + while (++i < video_num_columns) { + *p = *(p+1); + p++; + } + *p = video_erase_char; +} + +static void delete_line(int currcons) +{ + int oldtop,oldbottom; + + oldtop=top; + oldbottom=bottom; + top=y; + bottom = video_num_lines; + scrup(currcons); + top=oldtop; + bottom=oldbottom; +} + +static void csi_at(int currcons, unsigned int nr) +{ + if (nr > video_num_columns) + nr = video_num_columns; + else if (!nr) + nr = 1; + while (nr--) + insert_char(currcons); +} + +static void csi_L(int currcons, unsigned int nr) +{ + if (nr > video_num_lines) + nr = video_num_lines; + else if (!nr) + nr = 1; + while (nr--) + insert_line(currcons); +} + +static void csi_P(int currcons, unsigned int nr) +{ + if (nr > video_num_columns) + nr = video_num_columns; + else if (!nr) + nr = 1; + while (nr--) + delete_char(currcons); +} + +static void csi_M(int currcons, unsigned int nr) +{ + if (nr > video_num_lines) + nr = video_num_lines; + else if (!nr) + nr=1; + while (nr--) + delete_line(currcons); +} + +static void save_cur(int currcons) +{ + saved_x=x; + saved_y=y; +} + +static void restore_cur(int currcons) +{ + gotoxy(currcons,saved_x, saved_y); +} + + +enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, + ESsetterm, ESsetgraph }; + +void con_write(struct tty_struct * tty) +{ + int nr; + char c; + int currcons; + + currcons = tty - tty_table; + if ((currcons>=MAX_CONSOLES) || (currcons<0)) + panic("con_write: illegal tty"); + + nr = CHARS(tty->write_q); + while (nr--) { + if (tty->stopped) + break; + GETCH(tty->write_q,c); + if (c == 24 || c == 26) + state = ESnormal; + switch(state) { + case ESnormal: + if (c>31 && c<127) { + if (x>=video_num_columns) { + x -= video_num_columns; + pos -= video_size_row; + lf(currcons); + } + __asm__("movb %2,%%ah\n\t" + "movw %%ax,%1\n\t" + ::"a" (translate[c-32]), + "m" (*(short *)pos), + "m" (attr) + :"ax"); + pos += 2; + x++; + } else if (c==27) + state=ESesc; + else if (c==10 || c==11 || c==12) + lf(currcons); + else if (c==13) + cr(currcons); + else if (c==ERASE_CHAR(tty)) + del(currcons); + else if (c==8) { + if (x) { + x--; + pos -= 2; + } + } else if (c==9) { + c=8-(x&7); + x += c; + pos += c<<1; + if (x>video_num_columns) { + x -= video_num_columns; + pos -= video_size_row; + lf(currcons); + } + c=9; + } else if (c==7) + sysbeep(); + else if (c == 14) + translate = GRAF_TRANS; + else if (c == 15) + translate = NORM_TRANS; + break; + case ESesc: + state = ESnormal; + switch (c) + { + case '[': + state=ESsquare; + break; + case 'E': + gotoxy(currcons,0,y+1); + break; + case 'M': + ri(currcons); + break; + case 'D': + lf(currcons); + break; + case 'Z': + respond(currcons,tty); + break; + case '7': + save_cur(currcons); + break; + case '8': + restore_cur(currcons); + break; + case '(': case ')': + state = ESsetgraph; + break; + case 'P': + state = ESsetterm; + break; + case '#': + state = -1; + break; + case 'c': + tty->termios = DEF_TERMIOS; + state = restate = ESnormal; + checkin = 0; + top = 0; + bottom = video_num_lines; + break; + /* case '>': Numeric keypad */ + /* case '=': Appl. keypad */ + } + break; + case ESsquare: + for(npar=0;npar='0' && c<='9') { + par[npar]=10*par[npar]+c-'0'; + break; + } else state=ESgotpars; + case ESgotpars: + state = ESnormal; + if (ques) + { ques =0; + break; + } + switch(c) { + case 'G': case '`': + if (par[0]) par[0]--; + gotoxy(currcons,par[0],y); + break; + case 'A': + if (!par[0]) par[0]++; + gotoxy(currcons,x,y-par[0]); + break; + case 'B': case 'e': + if (!par[0]) par[0]++; + gotoxy(currcons,x,y+par[0]); + break; + case 'C': case 'a': + if (!par[0]) par[0]++; + gotoxy(currcons,x+par[0],y); + break; + case 'D': + if (!par[0]) par[0]++; + gotoxy(currcons,x-par[0],y); + break; + case 'E': + if (!par[0]) par[0]++; + gotoxy(currcons,0,y+par[0]); + break; + case 'F': + if (!par[0]) par[0]++; + gotoxy(currcons,0,y-par[0]); + break; + case 'd': + if (par[0]) par[0]--; + gotoxy(currcons,x,par[0]); + break; + case 'H': case 'f': + if (par[0]) par[0]--; + if (par[1]) par[1]--; + gotoxy(currcons,par[1],par[0]); + break; + case 'J': + csi_J(currcons,par[0]); + break; + case 'K': + csi_K(currcons,par[0]); + break; + case 'L': + csi_L(currcons,par[0]); + break; + case 'M': + csi_M(currcons,par[0]); + break; + case 'P': + csi_P(currcons,par[0]); + break; + case '@': + csi_at(currcons,par[0]); + break; + case 'm': + csi_m(currcons); + break; + case 'r': + if (par[0]) par[0]--; + if (!par[1]) par[1] = video_num_lines; + if (par[0] < par[1] && + par[1] <= video_num_lines) { + top=par[0]; + bottom=par[1]; + } + break; + case 's': + save_cur(currcons); + break; + case 'u': + restore_cur(currcons); + break; + case 'l': /* blank interval */ + case 'b': /* bold attribute */ + if (!((npar >= 2) && + ((par[1]-13) == par[0]) && + ((par[2]-17) == par[0]))) + break; + if ((c=='l')&&(par[0]>=0)&&(par[0]<=60)) + { + blankinterval = HZ*60*par[0]; + blankcount = blankinterval; + } + if (c=='b') + vc_cons[currcons].vc_bold_attr + = par[0]; + } + break; + case ESfunckey: + state = ESnormal; + break; + case ESsetterm: /* Setterm functions. */ + state = ESnormal; + if (c == 'S') { + def_attr = attr; + video_erase_char = (video_erase_char&0x0ff) | (def_attr<<8); + } else if (c == 'L') + ; /*linewrap on*/ + else if (c == 'l') + ; /*linewrap off*/ + break; + case ESsetgraph: + state = ESnormal; + if (c == '0') + translate = GRAF_TRANS; + else if (c == 'B') + translate = NORM_TRANS; + break; + default: + state = ESnormal; + } + } + set_cursor(currcons); +} + +/* + * void con_init(void); + * + * This routine initalizes console interrupts, and does nothing + * else. If you want the screen to clear, call tty_write with + * the appropriate escape-sequece. + * + * Reads the information preserved by setup.s to determine the current display + * type and sets everything accordingly. + */ +void con_init(void) +{ + register unsigned char a; + char *display_desc = "????"; + char *display_ptr; + int currcons = 0; + long base, term; + long video_memory; + + video_num_columns = ORIG_VIDEO_COLS; + video_size_row = video_num_columns * 2; + video_num_lines = ORIG_VIDEO_LINES; + video_page = ORIG_VIDEO_PAGE; + video_erase_char = 0x0720; + blankcount = blankinterval; + + if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */ + { + video_mem_base = 0xb0000; + video_port_reg = 0x3b4; + video_port_val = 0x3b5; + if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) + { + video_type = VIDEO_TYPE_EGAM; + video_mem_term = 0xb8000; + display_desc = "EGAm"; + } + else + { + video_type = VIDEO_TYPE_MDA; + video_mem_term = 0xb2000; + display_desc = "*MDA"; + } + } + else /* If not, it is color. */ + { + can_do_colour = 1; + video_mem_base = 0xb8000; + video_port_reg = 0x3d4; + video_port_val = 0x3d5; + if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) + { + video_type = VIDEO_TYPE_EGAC; + video_mem_term = 0xc0000; + display_desc = "EGAc"; + } + else + { + video_type = VIDEO_TYPE_CGA; + video_mem_term = 0xba000; + display_desc = "*CGA"; + } + } + video_memory = video_mem_term - video_mem_base; + NR_CONSOLES = video_memory / (video_num_lines * video_size_row); + if (NR_CONSOLES > MAX_CONSOLES) + NR_CONSOLES = MAX_CONSOLES; + if (!NR_CONSOLES) + NR_CONSOLES = 1; + video_memory /= NR_CONSOLES; + + /* Let the user known what kind of display driver we are using */ + + display_ptr = ((char *)video_mem_base) + video_size_row - 8; + while (*display_desc) + { + *display_ptr++ = *display_desc++; + display_ptr++; + } + + /* Initialize the variables used for scrolling (mostly EGA/VGA) */ + + base = origin = video_mem_start = video_mem_base; + term = video_mem_end = base + video_memory; + scr_end = video_mem_start + video_num_lines * video_size_row; + top = 0; + bottom = video_num_lines; + attr = 0x07; + def_attr = 0x07; + restate = state = ESnormal; + checkin = 0; + ques = 0; + iscolor = 0; + translate = NORM_TRANS; + vc_cons[0].vc_bold_attr = -1; + + gotoxy(currcons,ORIG_X,ORIG_Y); + for (currcons = 1; currconsNR_CONSOLES)) + return -EIO; + currcons--; + sptr = (char *) origin; + for (l=video_num_lines*video_num_columns; l>0 ; l--) + put_fs_byte(*sptr++,buf++); + return(0); +} + +void blank_screen() +{ + if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM) + return; +/* blank here. I can't find out how to do it, though */ +} + +void unblank_screen() +{ + if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM) + return; +/* unblank here */ +} + +void console_print(const char * b) +{ + int currcons = fg_console; + char c; + + while (c = *(b++)) { + if (c == 10) { + cr(currcons); + lf(currcons); + continue; + } + if (c == 13) { + cr(currcons); + continue; + } + if (x>=video_num_columns) { + x -= video_num_columns; + pos -= video_size_row; + lf(currcons); + } + __asm__("movb %2,%%ah\n\t" + "movw %%ax,%1\n\t" + ::"a" (c), + "m" (*(short *)pos), + "m" (attr) + :"ax"); + pos += 2; + x++; + } + set_cursor(currcons); +} diff --git a/kernel/0.1x/linux-0.12/kernel/chr_drv/keyboard.S b/kernel/0.1x/linux-0.12/kernel/chr_drv/keyboard.S new file mode 100644 index 00000000..47721022 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/chr_drv/keyboard.S @@ -0,0 +1,599 @@ +/* + * linux/kernel/keyboard.S + * + * (C) 1991 Linus Torvalds + */ + +/* + * Thanks to Alfred Leung for US keyboard patches + * Wolfgang Thiel for German keyboard patches + * Marc Corsini for the French keyboard + */ + +/* KBD_FINNISH for Finnish keyboards + * KBD_US for US-type + * KBD_GR for German keyboards + * KBD_FR for Frech keyboard + */ +#define KBD_FINNISH + +.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 + movl _blankinterval,%eax + movl %eax,_blankcount + xorl %eax,%eax /* %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: + testb $0x03,mode + je 1f + call _show_mem + jmp 2f +1: call _show_state +2: xorb $1,leds + jmp set_leds +num: xorb $2,leds + jmp set_leds + +/* + * curosr-key/numeric keypad cursor keys are handled here. + * checking for numeric keypad etc. + */ +cursor: + subb $0x47,%al + jb 1f + cmpb $12,%al + ja 1f + jne cur2 /* check for ctrl-alt-del */ + testb $0x0c,mode + je cur2 + testb $0x30,mode + jne reboot +cur2: cmpb $0x01,e0 /* e0 forces cursor movement */ + je cur + testb $0x02,leds /* not num-lock forces cursor */ + je cur + testb $0x03,mode /* shift forces cursor */ + jne cur + xorl %ebx,%ebx + movb num_table(%eax),%al + jmp put_queue +1: ret + +cur: movb cur_table(%eax),%al + cmpb $'9,%al + ja ok_cur + movb $'~,%ah +ok_cur: shll $16,%eax + movw $0x5b1b,%ax + xorl %ebx,%ebx + jmp put_queue + +#if defined(KBD_FR) +num_table: + .ascii "789 456 1230." +#else +num_table: + .ascii "789 456 1230," +#endif +cur_table: + .ascii "HA5 DGC YB623" + +/* + * this routine handles function keys + */ +func: + 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: + testb $0x10,mode + jne alt_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 +alt_func: + pushl %eax + call _change_console + popl %eax +end_func: + ret + +/* + * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc. + */ +func_table: + .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b + .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b + .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b + +#if defined(KBD_FINNISH) +key_map: + .byte 0,27 + .ascii "1234567890+'" + .byte 127,9 + .ascii "qwertyuiop}" + .byte 0,13,0 + .ascii "asdfghjkl|{" + .byte 0,0 + .ascii "'zxcvbnm,.-" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + +shift_map: + .byte 0,27 + .ascii "!\"#$%&/()=?`" + .byte 127,9 + .ascii "QWERTYUIOP]^" + .byte 13,0 + .ascii "ASDFGHJKL\\[" + .byte 0,0 + .ascii "*ZXCVBNM;:_" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#elif defined(KBD_US) + +key_map: + .byte 0,27 + .ascii "1234567890-=" + .byte 127,9 + .ascii "qwertyuiop[]" + .byte 13,0 + .ascii "asdfghjkl;'" + .byte '`,0 + .ascii "\\zxcvbnm,./" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + + +shift_map: + .byte 0,27 + .ascii "!@#$%^&*()_+" + .byte 127,9 + .ascii "QWERTYUIOP{}" + .byte 13,0 + .ascii "ASDFGHJKL:\"" + .byte '~,0 + .ascii "|ZXCVBNM<>?" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#elif defined(KBD_GR) + +key_map: + .byte 0,27 + .ascii "1234567890\\'" + .byte 127,9 + .ascii "qwertzuiop@+" + .byte 13,0 + .ascii "asdfghjkl[]^" + .byte 0,'# + .ascii "yxcvbnm,.-" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + + +shift_map: + .byte 0,27 + .ascii "!\"#$%&/()=?`" + .byte 127,9 + .ascii "QWERTZUIOP\\*" + .byte 13,0 + .ascii "ASDFGHJKL{}~" + .byte 0,'' + .ascii "YXCVBNM;:_" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte '@,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + + +#elif defined(KBD_FR) + +key_map: + .byte 0,27 + .ascii "&{\"'(-}_/@)=" + .byte 127,9 + .ascii "azertyuiop^$" + .byte 13,0 + .ascii "qsdfghjklm|" + .byte '`,0,42 /* coin sup gauche, don't know, [*|mu] */ + .ascii "wxcvbn,;:!" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + +shift_map: + .byte 0,27 + .ascii "1234567890]+" + .byte 127,9 + .ascii "AZERTYUIOP<>" + .byte 13,0 + .ascii "QSDFGHJKLM%" + .byte '~,0,'# + .ascii "WXCVBN?./\\" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0~#{[|`\\^@]}" + .byte 0,0 + .byte '@,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#else +#error "KBD-type not defined" +#endif +/* + * do_self handles "normal" keys, ie keys that don't change meaning + * and which have just one character returns. + */ +do_self: + lea alt_map,%ebx + testb $0x20,mode /* alt-gr */ + jne 1f + lea shift_map,%ebx + testb $0x03,mode + jne 1f + lea key_map,%ebx +1: movb (%ebx,%eax),%al + orb %al,%al + je none + testb $0x4c,mode /* ctrl or caps */ + je 2f + cmpb $'a,%al + jb 2f + cmpb $'},%al + ja 2f + subb $32,%al +2: testb $0x0c,mode /* ctrl */ + je 3f + cmpb $64,%al + jb 3f + cmpb $64+32,%al + jae 3f + subb $64,%al +3: testb $0x10,mode /* left alt */ + je 4f + orb $0x80,%al +4: andl $0xff,%eax + xorl %ebx,%ebx + call put_queue +none: ret + +/* + * minus has a routine of it's own, as a 'E0h' before + * the scan code for minus means that the numeric keypad + * slash was pushed. + */ +minus: cmpb $1,e0 + jne do_self + movl $'/,%eax + xorl %ebx,%ebx + jmp put_queue + +/* + * This table decides which routine to call when a scan-code has been + * gotten. Most routines just call do_self, or none, depending if + * they are make or break. + */ +key_table: + .long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */ + .long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */ + .long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */ + .long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */ + .long do_self,do_self,do_self,do_self /* 10-13 q w e r */ + .long do_self,do_self,do_self,do_self /* 14-17 t y u i */ + .long do_self,do_self,do_self,do_self /* 18-1B o p } ^ */ + .long do_self,ctrl,do_self,do_self /* 1C-1F enter ctrl a s */ + .long do_self,do_self,do_self,do_self /* 20-23 d f g h */ + .long do_self,do_self,do_self,do_self /* 24-27 j k l | */ + .long do_self,do_self,lshift,do_self /* 28-2B { para lshift , */ + .long do_self,do_self,do_self,do_self /* 2C-2F z x c v */ + .long do_self,do_self,do_self,do_self /* 30-33 b n m , */ + .long do_self,minus,rshift,do_self /* 34-37 . - rshift * */ + .long alt,do_self,caps,func /* 38-3B alt sp caps f1 */ + .long func,func,func,func /* 3C-3F f2 f3 f4 f5 */ + .long func,func,func,func /* 40-43 f6 f7 f8 f9 */ + .long func,num,scroll,cursor /* 44-47 f10 num scr home */ + .long cursor,cursor,do_self,cursor /* 48-4B up pgup - left */ + .long cursor,cursor,do_self,cursor /* 4C-4F n5 right + end */ + .long cursor,cursor,cursor,cursor /* 50-53 dn pgdn ins del */ + .long none,none,do_self,func /* 54-57 sysreq ? < f11 */ + .long func,none,none,none /* 58-5B f12 ? ? ? */ + .long none,none,none,none /* 5C-5F ? ? ? ? */ + .long none,none,none,none /* 60-63 ? ? ? ? */ + .long none,none,none,none /* 64-67 ? ? ? ? */ + .long none,none,none,none /* 68-6B ? ? ? ? */ + .long none,none,none,none /* 6C-6F ? ? ? ? */ + .long none,none,none,none /* 70-73 ? ? ? ? */ + .long none,none,none,none /* 74-77 ? ? ? ? */ + .long none,none,none,none /* 78-7B ? ? ? ? */ + .long none,none,none,none /* 7C-7F ? ? ? ? */ + .long none,none,none,none /* 80-83 ? br br br */ + .long none,none,none,none /* 84-87 br br br br */ + .long none,none,none,none /* 88-8B br br br br */ + .long none,none,none,none /* 8C-8F br br br br */ + .long none,none,none,none /* 90-93 br br br br */ + .long none,none,none,none /* 94-97 br br br br */ + .long none,none,none,none /* 98-9B br br br br */ + .long none,unctrl,none,none /* 9C-9F br unctrl br br */ + .long none,none,none,none /* A0-A3 br br br br */ + .long none,none,none,none /* A4-A7 br br br br */ + .long none,none,unlshift,none /* A8-AB br br unlshift br */ + .long none,none,none,none /* AC-AF br br br br */ + .long none,none,none,none /* B0-B3 br br br br */ + .long none,none,unrshift,none /* B4-B7 br br unrshift br */ + .long unalt,none,uncaps,none /* B8-BB unalt br uncaps br */ + .long none,none,none,none /* BC-BF br br br br */ + .long none,none,none,none /* C0-C3 br br br br */ + .long none,none,none,none /* C4-C7 br br br br */ + .long none,none,none,none /* C8-CB br br br br */ + .long none,none,none,none /* CC-CF br br br br */ + .long none,none,none,none /* D0-D3 br br br br */ + .long none,none,none,none /* D4-D7 br br br br */ + .long none,none,none,none /* D8-DB br ? ? ? */ + .long none,none,none,none /* DC-DF ? ? ? ? */ + .long none,none,none,none /* E0-E3 e0 e1 ? ? */ + .long none,none,none,none /* E4-E7 ? ? ? ? */ + .long none,none,none,none /* E8-EB ? ? ? ? */ + .long none,none,none,none /* EC-EF ? ? ? ? */ + .long none,none,none,none /* F0-F3 ? ? ? ? */ + .long none,none,none,none /* F4-F7 ? ? ? ? */ + .long none,none,none,none /* F8-FB ? ? ? ? */ + .long none,none,none,none /* FC-FF ? ? ? ? */ + +/* + * kb_wait waits for the keyboard controller buffer to empty. + * there is no timeout - if the buffer doesn't empty, we hang. + */ +kb_wait: + pushl %eax +1: inb $0x64,%al + testb $0x02,%al + jne 1b + popl %eax + ret +/* + * This routine reboots the machine by asking the keyboard + * controller to pulse the reset-line low. + */ +reboot: + call kb_wait + movw $0x1234,0x472 /* don't do memory check */ + movb $0xfc,%al /* pulse reset and A20 low */ + outb %al,$0x64 +die: jmp die diff --git a/kernel/0.1x/linux-0.12/kernel/chr_drv/pty.c b/kernel/0.1x/linux-0.12/kernel/chr_drv/pty.c new file mode 100644 index 00000000..bddfada4 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/chr_drv/pty.c @@ -0,0 +1,63 @@ +/* + * linux/kernel/chr_drv/pty.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * pty.c + * + * This module implements the pty functions + * void mpty_write(struct tty_struct * queue); + * void spty_write(struct tty_struct * queue); + */ + +#include +#include +#include +#include + +static inline void pty_copy(struct tty_struct * from, struct tty_struct * to) +{ + char c; + + while (!from->stopped && !EMPTY(from->write_q)) { + if (FULL(to->read_q)) { + if (FULL(to->secondary)) + break; + copy_to_cooked(to); + continue; + } + GETCH(from->write_q,c); + PUTCH(c,to->read_q); + if (current->signal & ~current->blocked) + break; + } + copy_to_cooked(to); + wake_up(&from->write_q->proc_list); +} + +/* + * This routine gets called when tty_write has put something into + * the write_queue. It copies the input to the output-queue of it's + * slave. + */ +void mpty_write(struct tty_struct * tty) +{ + int nr = tty - tty_table; + + if ((nr >> 6) != 2) + printk("bad mpty\n\r"); + else + pty_copy(tty,tty+64); +} + +void spty_write(struct tty_struct * tty) +{ + int nr = tty - tty_table; + + if ((nr >> 6) != 3) + printk("bad spty\n\r"); + else + pty_copy(tty,tty-64); +} diff --git a/kernel/0.1x/linux-0.12/kernel/chr_drv/rs_io.s b/kernel/0.1x/linux-0.12/kernel/chr_drv/rs_io.s new file mode 100644 index 00000000..b6fc2f3e --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/chr_drv/rs_io.s @@ -0,0 +1,148 @@ +/* + * linux/kernel/rs_io.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * rs_io.s + * + * This module implements the rs232 io interrupts. + */ + +.text +.globl _rs1_interrupt,_rs2_interrupt + +size = 1024 /* must be power of two ! + and must match the value + in tty_io.c!!! */ + +/* these are the offsets into the read/write buffer structures */ +rs_addr = 0 +head = 4 +tail = 8 +proc_list = 12 +buf = 16 + +startup = 256 /* chars left in write queue when we restart it */ + +/* + * These are the actual interrupt routines. They look where + * the interrupt is coming from, and take appropriate action. + */ +.align 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) +1: addl $63,%edx + pushl %edx + call _do_tty_interrupt + addl $4,%esp + 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/kernel/0.1x/linux-0.12/kernel/chr_drv/serial.c b/kernel/0.1x/linux-0.12/kernel/chr_drv/serial.c new file mode 100644 index 00000000..4b8dd156 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/chr_drv/serial.c @@ -0,0 +1,59 @@ +/* + * linux/kernel/serial.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * serial.c + * + * This module implements the rs232 io functions + * void rs_write(struct tty_struct * queue); + * void rs_init(void); + * and all interrupts pertaining to serial IO. + */ + +#include +#include +#include +#include + +#define WAKEUP_CHARS (TTY_BUF_SIZE/4) + +extern void rs1_interrupt(void); +extern void rs2_interrupt(void); + +static void init(int port) +{ + outb_p(0x80,port+3); /* set DLAB of line control reg */ + outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */ + outb_p(0x00,port+1); /* MS of divisor */ + outb_p(0x03,port+3); /* reset DLAB */ + outb_p(0x0b,port+4); /* set DTR,RTS, OUT_2 */ + outb_p(0x0d,port+1); /* enable all intrs but writes */ + (void)inb(port); /* read data port to reset things (?) */ +} + +void rs_init(void) +{ + set_intr_gate(0x24,rs1_interrupt); + set_intr_gate(0x23,rs2_interrupt); + init(tty_table[64].read_q->data); + init(tty_table[65].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/kernel/0.1x/linux-0.12/kernel/chr_drv/tty_io.c b/kernel/0.1x/linux-0.12/kernel/chr_drv/tty_io.c new file mode 100644 index 00000000..a6df4dfa --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/chr_drv/tty_io.c @@ -0,0 +1,484 @@ +/* + * linux/kernel/tty_io.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles + * or rs-channels. It also implements echoing, cooked mode etc. + * + * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. + */ + +#include +#include +#include +#include + +#define ALRMMASK (1<<(SIGALRM-1)) + +#include +#include +#include +#include + +int kill_pg(int pgrp, int sig, int priv); +int is_orphaned_pgrp(int pgrp); + +#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 L_TOSTOP(tty) _L_FLAG((tty),TOSTOP) + +#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 I_IXON(tty) _I_FLAG((tty),IXON) + +#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) + +#define C_SPEED(tty) ((tty)->termios.c_cflag & CBAUD) +#define C_HUP(tty) (C_SPEED((tty)) == B0) + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define QUEUES (3*(MAX_CONSOLES+NR_SERIALS+2*NR_PTYS)) +static struct tty_queue tty_queues[QUEUES]; +struct tty_struct tty_table[256]; + +#define con_queues tty_queues +#define rs_queues ((3*MAX_CONSOLES) + tty_queues) +#define mpty_queues ((3*(MAX_CONSOLES+NR_SERIALS)) + tty_queues) +#define spty_queues ((3*(MAX_CONSOLES+NR_SERIALS+NR_PTYS)) + tty_queues) + +#define con_table tty_table +#define rs_table (64+tty_table) +#define mpty_table (128+tty_table) +#define spty_table (192+tty_table) + +int fg_console = 0; + +/* + * these are the tables used by the machine code handlers. + * you can implement virtual consoles. + */ +struct tty_queue * table_list[]={ + con_queues + 0, con_queues + 1, + rs_queues + 0, rs_queues + 1, + rs_queues + 3, rs_queues + 4 + }; + +void change_console(unsigned int new_console) +{ + if (new_console == fg_console || new_console >= NR_CONSOLES) + return; + fg_console = new_console; + table_list[0] = con_queues + 0 + fg_console*3; + table_list[1] = con_queues + 1 + fg_console*3; + update_screen(); +} + +static void sleep_if_empty(struct tty_queue * queue) +{ + cli(); + while (!(current->signal & ~current->blocked) && 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 & ~current->blocked) && LEFT(queue)<128) + interruptible_sleep_on(&queue->proc_list); + sti(); +} + +void wait_for_keypress(void) +{ + sleep_if_empty(tty_table[fg_console].secondary); +} + +void copy_to_cooked(struct tty_struct * tty) +{ + signed char c; + + if (!(tty->read_q || tty->write_q || tty->secondary)) { + printk("copy_to_cooked: missing queues\n\r"); + return; + } + while (1) { + if (EMPTY(tty->read_q)) + break; + if (FULL(tty->secondary)) + break; + GETCH(tty->read_q,c); + if (c==13) { + if (I_CRNL(tty)) + c=10; + else if (I_NOCR(tty)) + continue; + } else if (c==10 && I_NLCR(tty)) + c=13; + if (I_UCLC(tty)) + c=tolower(c); + if (L_CANON(tty)) { + if ((KILL_CHAR(tty) != _POSIX_VDISABLE) && + (c==KILL_CHAR(tty))) { + /* deal with killing the input line */ + while(!(EMPTY(tty->secondary) || + (c=LAST(tty->secondary))==10 || + ((EOF_CHAR(tty) != _POSIX_VDISABLE) && + (c==EOF_CHAR(tty))))) { + if (L_ECHO(tty)) { + if (c<32) + PUTCH(127,tty->write_q); + PUTCH(127,tty->write_q); + tty->write(tty); + } + DEC(tty->secondary->head); + } + continue; + } + if ((ERASE_CHAR(tty) != _POSIX_VDISABLE) && + (c==ERASE_CHAR(tty))) { + if (EMPTY(tty->secondary) || + (c=LAST(tty->secondary))==10 || + ((EOF_CHAR(tty) != _POSIX_VDISABLE) && + (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 (I_IXON(tty)) { + if ((STOP_CHAR(tty) != _POSIX_VDISABLE) && + (c==STOP_CHAR(tty))) { + tty->stopped=1; + tty->write(tty); + continue; + } + if ((START_CHAR(tty) != _POSIX_VDISABLE) && + (c==START_CHAR(tty))) { + tty->stopped=0; + tty->write(tty); + continue; + } + } + if (L_ISIG(tty)) { + if ((INTR_CHAR(tty) != _POSIX_VDISABLE) && + (c==INTR_CHAR(tty))) { + kill_pg(tty->pgrp, SIGINT, 1); + continue; + } + if ((QUIT_CHAR(tty) != _POSIX_VDISABLE) && + (c==QUIT_CHAR(tty))) { + kill_pg(tty->pgrp, SIGQUIT, 1); + continue; + } + if ((SUSPEND_CHAR(tty) != _POSIX_VDISABLE) && + (c==SUSPEND_CHAR(tty))) { + if (!is_orphaned_pgrp(tty->pgrp)) + kill_pg(tty->pgrp, SIGTSTP, 1); + continue; + } + } + if (c==10 || (EOF_CHAR(tty) != _POSIX_VDISABLE && + 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); +} + +/* + * Called when we need to send a SIGTTIN or SIGTTOU to our process + * group + * + * We only request that a system call be restarted if there was if the + * default signal handler is being used. The reason for this is that if + * a job is catching SIGTTIN or SIGTTOU, the signal handler may not want + * the system call to be restarted blindly. If there is no way to reset the + * terminal pgrp back to the current pgrp (perhaps because the controlling + * tty has been released on logout), we don't want to be in an infinite loop + * while restarting the system call, and have it always generate a SIGTTIN + * or SIGTTOU. The default signal handler will cause the process to stop + * thus avoiding the infinite loop problem. Presumably the job-control + * cognizant parent will fix things up before continuging its child process. + */ +int tty_signal(int sig, struct tty_struct *tty) +{ + if (is_orphaned_pgrp(current->pgrp)) + return -EIO; /* don't stop an orphaned pgrp */ + (void) kill_pg(current->pgrp,sig,1); + if ((current->blocked & (1<<(sig-1))) || + ((int) current->sigaction[sig-1].sa_handler == 1)) + return -EIO; /* Our signal will be ignored */ + else if (current->sigaction[sig-1].sa_handler) + return -EINTR; /* We _will_ be interrupted :-) */ + else + return -ERESTARTSYS; /* We _will_ be interrupted :-) */ + /* (but restart after we continue) */ +} + +int tty_read(unsigned channel, char * buf, int nr) +{ + struct tty_struct * tty; + struct tty_struct * other_tty = NULL; + char c, * b=buf; + int minimum,time; + + if (channel > 255) + return -EIO; + tty = TTY_TABLE(channel); + if (!(tty->write_q || tty->read_q || tty->secondary)) + return -EIO; + if ((current->tty == channel) && (tty->pgrp != current->pgrp)) + return(tty_signal(SIGTTIN, tty)); + if (channel & 0x80) + other_tty = tty_table + (channel ^ 0x40); + time = 10L*tty->termios.c_cc[VTIME]; + minimum = tty->termios.c_cc[VMIN]; + if (L_CANON(tty)) { + minimum = nr; + current->timeout = 0xffffffff; + time = 0; + } else if (minimum) + current->timeout = 0xffffffff; + else { + minimum = nr; + if (time) + current->timeout = time + jiffies; + time = 0; + } + if (minimum>nr) + minimum = nr; + while (nr>0) { + if (other_tty) + other_tty->write(other_tty); + cli(); + if (EMPTY(tty->secondary) || (L_CANON(tty) && + !FULL(tty->read_q) && !tty->secondary->data)) { + if (!current->timeout || + (current->signal & ~current->blocked)) { + sti(); + break; + } + if (IS_A_PTY_SLAVE(channel) && C_HUP(other_tty)) + break; + interruptible_sleep_on(&tty->secondary->proc_list); + sti(); + continue; + } + sti(); + do { + GETCH(tty->secondary,c); + if ((EOF_CHAR(tty) != _POSIX_VDISABLE && + c==EOF_CHAR(tty)) || c==10) + tty->secondary->data--; + if ((EOF_CHAR(tty) != _POSIX_VDISABLE && + c==EOF_CHAR(tty)) && L_CANON(tty)) + break; + else { + put_fs_byte(c,b++); + if (!--nr) + break; + } + if (c==10 && L_CANON(tty)) + break; + } while (nr>0 && !EMPTY(tty->secondary)); + wake_up(&tty->read_q->proc_list); + if (time) + current->timeout = time+jiffies; + if (L_CANON(tty) || b-buf >= minimum) + break; + } + current->timeout = 0; + if ((current->signal & ~current->blocked) && !(b-buf)) + return -ERESTARTSYS; + 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 > 255) + return -EIO; + tty = TTY_TABLE(channel); + if (!(tty->write_q || tty->read_q || tty->secondary)) + return -EIO; + if (L_TOSTOP(tty) && + (current->tty == channel) && (tty->pgrp != current->pgrp)) + return(tty_signal(SIGTTOU, tty)); + while (nr>0) { + sleep_if_full(tty->write_q); + if (current->signal & ~current->blocked) + break; + while (nr>0 && !FULL(tty->write_q)) { + c=get_fs_byte(b); + if (O_POST(tty)) { + if (c=='\r' && O_CRNL(tty)) + c='\n'; + else if (c=='\n' && O_NLRET(tty)) + c='\r'; + if (c=='\n' && !cr_flag && O_NLCR(tty)) { + cr_flag = 1; + PUTCH(13,tty->write_q); + continue; + } + if (O_LCUC(tty)) + c=toupper(c); + } + b++; nr--; + cr_flag = 0; + PUTCH(c,tty->write_q); + } + tty->write(tty); + if (nr>0) + schedule(); + } + return (b-buf); +} + +/* + * Jeh, sometimes I really like the 386. + * This routine is called from an interrupt, + * and there should be absolutely no problem + * with sleeping even in an interrupt (I hope). + * Of course, if somebody proves me wrong, I'll + * hate intel for all time :-). We'll have to + * be careful and see to reinstating the interrupt + * chips before calling this, though. + * + * I don't think we sleep here under normal circumstances + * anyway, which is good, as the task sleeping might be + * totally innocent. + */ +void do_tty_interrupt(int tty) +{ + copy_to_cooked(TTY_TABLE(tty)); +} + +void chr_dev_init(void) +{ +} + +void tty_init(void) +{ + int i; + + for (i=0 ; i < QUEUES ; i++) + tty_queues[i] = (struct tty_queue) {0,0,0,0,""}; + rs_queues[0] = (struct tty_queue) {0x3f8,0,0,0,""}; + rs_queues[1] = (struct tty_queue) {0x3f8,0,0,0,""}; + rs_queues[3] = (struct tty_queue) {0x2f8,0,0,0,""}; + rs_queues[4] = (struct tty_queue) {0x2f8,0,0,0,""}; + for (i=0 ; i<256 ; i++) { + tty_table[i] = (struct tty_struct) { + {0, 0, 0, 0, 0, INIT_C_CC}, + 0, 0, 0, NULL, NULL, NULL, NULL + }; + } + con_init(); + for (i = 0 ; i +#include + +#include +#include +#include + +#include +#include +#include + +extern int session_of_pgrp(int pgrp); +extern int tty_signal(int sig, struct tty_struct *tty); + +static unsigned short quotient[] = { + 0, 2304, 1536, 1047, 857, + 768, 576, 384, 192, 96, + 64, 48, 24, 12, 6, 3 +}; + +static void change_speed(struct tty_struct * tty) +{ + unsigned short port,quot; + + if (!(port = tty->read_q->data)) + return; + quot = quotient[tty->termios.c_cflag & CBAUD]; + cli(); + outb_p(0x80,port+3); /* set DLAB */ + outb_p(quot & 0xff,port); /* LS of divisor */ + outb_p(quot >> 8,port+1); /* MS of divisor */ + outb(0x03,port+3); /* reset DLAB */ + sti(); +} + +static void flush(struct tty_queue * queue) +{ + cli(); + queue->head = queue->tail; + sti(); +} + +static void wait_until_sent(struct tty_struct * tty) +{ + /* do nothing - not implemented */ +} + +static void send_break(struct tty_struct * tty) +{ + /* do nothing - not implemented */ +} + +static int get_termios(struct tty_struct * tty, struct termios * termios) +{ + int i; + + verify_area(termios, sizeof (*termios)); + for (i=0 ; i< (sizeof (*termios)) ; i++) + put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios ); + return 0; +} + +static int set_termios(struct tty_struct * tty, struct termios * termios, + int channel) +{ + int i, retsig; + + /* If we try to set the state of terminal and we're not in the + foreground, send a SIGTTOU. If the signal is blocked or + ignored, go ahead and perform the operation. POSIX 7.2) */ + if ((current->tty == channel) && (tty->pgrp != current->pgrp)) { + retsig = tty_signal(SIGTTOU, tty); + if (retsig == -ERESTARTSYS || retsig == -EINTR) + return retsig; + } + for (i=0 ; i< (sizeof (*termios)) ; i++) + ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios); + change_speed(tty); + return 0; +} + +static int get_termio(struct tty_struct * tty, struct termio * termio) +{ + int i; + struct termio tmp_termio; + + verify_area(termio, sizeof (*termio)); + tmp_termio.c_iflag = tty->termios.c_iflag; + tmp_termio.c_oflag = tty->termios.c_oflag; + tmp_termio.c_cflag = tty->termios.c_cflag; + tmp_termio.c_lflag = tty->termios.c_lflag; + tmp_termio.c_line = tty->termios.c_line; + for(i=0 ; i < NCC ; i++) + tmp_termio.c_cc[i] = tty->termios.c_cc[i]; + for (i=0 ; i< (sizeof (*termio)) ; i++) + put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio ); + return 0; +} + +/* + * This only works as the 386 is low-byt-first + */ +static int set_termio(struct tty_struct * tty, struct termio * termio, + int channel) +{ + int i, retsig; + struct termio tmp_termio; + + if ((current->tty == channel) && (tty->pgrp != current->pgrp)) { + retsig = tty_signal(SIGTTOU, tty); + if (retsig == -ERESTARTSYS || retsig == -EINTR) + return retsig; + } + for (i=0 ; i< (sizeof (*termio)) ; i++) + ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio); + *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag; + *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag; + *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag; + *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag; + tty->termios.c_line = tmp_termio.c_line; + for(i=0 ; i < NCC ; i++) + tty->termios.c_cc[i] = tmp_termio.c_cc[i]; + change_speed(tty); + return 0; +} + +int tty_ioctl(int dev, int cmd, int arg) +{ + struct tty_struct * tty; + int pgrp; + + if (MAJOR(dev) == 5) { + dev=current->tty; + if (dev<0) + panic("tty_ioctl: dev<0"); + } else + dev=MINOR(dev); + tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console); + 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, dev); + 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, dev); + case TCSBRK: + if (!arg) { + wait_until_sent(tty); + send_break(tty); + } + return 0; + case TCXONC: + switch (arg) { + case TCOOFF: + tty->stopped = 1; + tty->write(tty); + return 0; + case TCOON: + tty->stopped = 0; + tty->write(tty); + return 0; + case TCIOFF: + if (STOP_CHAR(tty)) + PUTCH(STOP_CHAR(tty),tty->write_q); + return 0; + case TCION: + if (START_CHAR(tty)) + PUTCH(START_CHAR(tty),tty->write_q); + return 0; + } + 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: + if ((current->tty < 0) || + (current->tty != dev) || + (tty->session != current->session)) + return -ENOTTY; + pgrp=get_fs_long((unsigned long *) arg); + if (pgrp < 0) + return -EINVAL; + if (session_of_pgrp(pgrp) != current->session) + return -EPERM; + tty->pgrp = pgrp; + return 0; + case TIOCOUTQ: + verify_area((void *) arg,4); + put_fs_long(CHARS(tty->write_q),(unsigned long *) arg); + return 0; + case TIOCINQ: + verify_area((void *) arg,4); + put_fs_long(CHARS(tty->secondary), + (unsigned long *) arg); + return 0; + case TIOCSTI: + return -EINVAL; /* not implemented */ + case TIOCGWINSZ: + return -EINVAL; /* not implemented */ + case TIOCSWINSZ: + return -EINVAL; /* not implemented */ + case TIOCMGET: + return -EINVAL; /* not implemented */ + case TIOCMBIS: + return -EINVAL; /* not implemented */ + case TIOCMBIC: + return -EINVAL; /* not implemented */ + case TIOCMSET: + return -EINVAL; /* not implemented */ + case TIOCGSOFTCAR: + return -EINVAL; /* not implemented */ + case TIOCSSOFTCAR: + return -EINVAL; /* not implemented */ + default: + return -EINVAL; + } +} diff --git a/kernel/0.1x/linux-0.12/kernel/exit.c b/kernel/0.1x/linux-0.12/kernel/exit.c new file mode 100644 index 00000000..bd0e9f03 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/exit.c @@ -0,0 +1,430 @@ +/* + * linux/kernel/exit.c + * + * (C) 1991 Linus Torvalds + */ + +#define DEBUG_PROC_TREE + +#include +#include +#include + +#include +#include +#include +#include + +int sys_pause(void); +int sys_close(int fd); + +void release(struct task_struct * p) +{ + int i; + + if (!p) + return; + if (p == current) { + printk("task releasing itself\n\r"); + return; + } + for (i=1 ; ip_osptr) + p->p_osptr->p_ysptr = p->p_ysptr; + if (p->p_ysptr) + p->p_ysptr->p_osptr = p->p_osptr; + else + p->p_pptr->p_cptr = p->p_osptr; + free_page((long)p); + schedule(); + return; + } + panic("trying to release non-existent task"); +} + +#ifdef DEBUG_PROC_TREE +/* + * Check to see if a task_struct pointer is present in the task[] array + * Return 0 if found, and 1 if not found. + */ +int bad_task_ptr(struct task_struct *p) +{ + int i; + + if (!p) + return 0; + for (i=0 ; ip_pptr)) + printk("Warning, pid %d's parent link is bad\n", + task[i]->pid); + if (bad_task_ptr(task[i]->p_cptr)) + printk("Warning, pid %d's child link is bad\n", + task[i]->pid); + if (bad_task_ptr(task[i]->p_ysptr)) + printk("Warning, pid %d's ys link is bad\n", + task[i]->pid); + if (bad_task_ptr(task[i]->p_osptr)) + printk("Warning, pid %d's os link is bad\n", + task[i]->pid); + if (task[i]->p_pptr == task[i]) + printk("Warning, pid %d parent link points to self\n"); + if (task[i]->p_cptr == task[i]) + printk("Warning, pid %d child link points to self\n"); + if (task[i]->p_ysptr == task[i]) + printk("Warning, pid %d ys link points to self\n"); + if (task[i]->p_osptr == task[i]) + printk("Warning, pid %d os link points to self\n"); + if (task[i]->p_osptr) { + if (task[i]->p_pptr != task[i]->p_osptr->p_pptr) + printk( + "Warning, pid %d older sibling %d parent is %d\n", + task[i]->pid, task[i]->p_osptr->pid, + task[i]->p_osptr->p_pptr->pid); + if (task[i]->p_osptr->p_ysptr != task[i]) + printk( + "Warning, pid %d older sibling %d has mismatched ys link\n", + task[i]->pid, task[i]->p_osptr->pid); + } + if (task[i]->p_ysptr) { + if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr) + printk( + "Warning, pid %d younger sibling %d parent is %d\n", + task[i]->pid, task[i]->p_osptr->pid, + task[i]->p_osptr->p_pptr->pid); + if (task[i]->p_ysptr->p_osptr != task[i]) + printk( + "Warning, pid %d younger sibling %d has mismatched os link\n", + task[i]->pid, task[i]->p_ysptr->pid); + } + if (task[i]->p_cptr) { + if (task[i]->p_cptr->p_pptr != task[i]) + printk( + "Warning, pid %d youngest child %d has mismatched parent link\n", + task[i]->pid, task[i]->p_cptr->pid); + if (task[i]->p_cptr->p_ysptr) + printk( + "Warning, pid %d youngest child %d has non-NULL ys link\n", + task[i]->pid, task[i]->p_cptr->pid); + } + } +} +#endif /* DEBUG_PROC_TREE */ + +static inline int send_sig(long sig,struct task_struct * p,int priv) +{ + if (!p) + return -EINVAL; + if (!priv && (current->euid!=p->euid) && !suser()) + return -EPERM; + if ((sig == SIGKILL) || (sig == SIGCONT)) { + if (p->state == TASK_STOPPED) + p->state = TASK_RUNNING; + p->exit_code = 0; + p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) | + (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) ); + } + /* If the signal will be ignored, don't even post it */ + if ((int) p->sigaction[sig-1].sa_handler == 1) + return 0; + /* Depends on order SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU */ + if ((sig >= SIGSTOP) && (sig <= SIGTTOU)) + p->signal &= ~(1<<(SIGCONT-1)); + /* Actually deliver the signal */ + p->signal |= (1<<(sig-1)); + return 0; +} + +int session_of_pgrp(int pgrp) +{ + struct task_struct **p; + + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if ((*p)->pgrp == pgrp) + return((*p)->session); + return -1; +} + +int kill_pg(int pgrp, int sig, int priv) +{ + struct task_struct **p; + int err,retval = -ESRCH; + int found = 0; + + if (sig<1 || sig>32 || pgrp<=0) + return -EINVAL; + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if ((*p)->pgrp == pgrp) { + if (sig && (err = send_sig(sig,*p,priv))) + retval = err; + else + found++; + } + return(found ? 0 : retval); +} + +int kill_proc(int pid, int sig, int priv) +{ + struct task_struct **p; + + if (sig<1 || sig>32) + return -EINVAL; + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if ((*p)->pid == pid) + return(sig ? send_sig(sig,*p,priv) : 0); + return(-ESRCH); +} + +/* + * POSIX specifies that kill(-1,sig) is unspecified, but what we have + * is probably wrong. Should make it like BSD or SYSV. + */ +int sys_kill(int pid,int sig) +{ + struct task_struct **p = NR_TASKS + task; + int err, retval = 0; + + if (!pid) + return(kill_pg(current->pid,sig,0)); + if (pid == -1) { + while (--p > &FIRST_TASK) + if (err = send_sig(sig,*p,0)) + retval = err; + return(retval); + } + if (pid < 0) + return(kill_pg(-pid,sig,0)); + /* Normal kill */ + return(kill_proc(pid,sig,0)); +} + +/* + * Determine if a process group is "orphaned", according to the POSIX + * definition in 2.2.2.52. Orphaned process groups are not to be affected + * by terminal-generated stop signals. Newly orphaned process groups are + * to receive a SIGHUP and a SIGCONT. + * + * "I ask you, have you ever known what it is to be an orphan?" + */ +int is_orphaned_pgrp(int pgrp) +{ + struct task_struct **p; + + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if (!(*p) || + ((*p)->pgrp != pgrp) || + ((*p)->state == TASK_ZOMBIE) || + ((*p)->p_pptr->pid == 1)) + continue; + if (((*p)->p_pptr->pgrp != pgrp) && + ((*p)->p_pptr->session == (*p)->session)) + return 0; + } + return(1); /* (sighing) "Often!" */ +} + +static int has_stopped_jobs(int pgrp) +{ + struct task_struct ** p; + + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if ((*p)->pgrp != pgrp) + continue; + if ((*p)->state == TASK_STOPPED) + return(1); + } + return(0); +} + +volatile void do_exit(long code) +{ + struct task_struct *p; + 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 ; ifilp[i]) + sys_close(i); + iput(current->pwd); + current->pwd = NULL; + iput(current->root); + current->root = NULL; + iput(current->executable); + current->executable = NULL; + iput(current->library); + current->library = NULL; + current->state = TASK_ZOMBIE; + current->exit_code = code; + /* + * Check to see if any process groups have become orphaned + * as a result of our exiting, and if they have any stopped + * jobs, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2) + * + * Case i: Our father is in a different pgrp than we are + * and we were the only connection outside, so our pgrp + * is about to become orphaned. + */ + if ((current->p_pptr->pgrp != current->pgrp) && + (current->p_pptr->session == current->session) && + is_orphaned_pgrp(current->pgrp) && + has_stopped_jobs(current->pgrp)) { + kill_pg(current->pgrp,SIGHUP,1); + kill_pg(current->pgrp,SIGCONT,1); + } + /* Let father know we died */ + current->p_pptr->signal |= (1<<(SIGCHLD-1)); + + /* + * This loop does two things: + * + * A. Make init inherit all the child processes + * B. Check to see if any process groups have become orphaned + * as a result of our exiting, and if they have any stopped + * jons, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2) + */ + if (p = current->p_cptr) { + while (1) { + p->p_pptr = task[1]; + if (p->state == TASK_ZOMBIE) + task[1]->signal |= (1<<(SIGCHLD-1)); + /* + * process group orphan check + * Case ii: Our child is in a different pgrp + * than we are, and it was the only connection + * outside, so the child pgrp is now orphaned. + */ + if ((p->pgrp != current->pgrp) && + (p->session == current->session) && + is_orphaned_pgrp(p->pgrp) && + has_stopped_jobs(p->pgrp)) { + kill_pg(p->pgrp,SIGHUP,1); + kill_pg(p->pgrp,SIGCONT,1); + } + if (p->p_osptr) { + p = p->p_osptr; + continue; + } + /* + * This is it; link everything into init's children + * and leave + */ + p->p_osptr = task[1]->p_cptr; + task[1]->p_cptr->p_ysptr = p; + task[1]->p_cptr = current->p_cptr; + current->p_cptr = 0; + break; + } + } + if (current->leader) { + struct task_struct **p; + struct tty_struct *tty; + + if (current->tty >= 0) { + tty = TTY_TABLE(current->tty); + if (tty->pgrp>0) + kill_pg(tty->pgrp, SIGHUP, 1); + tty->pgrp = 0; + tty->session = 0; + } + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if ((*p)->session == current->session) + (*p)->tty = -1; + } + if (last_task_used_math == current) + last_task_used_math = NULL; +#ifdef DEBUG_PROC_TREE + audit_ptree(); +#endif + schedule(); +} + +int sys_exit(int error_code) +{ + do_exit((error_code&0xff)<<8); +} + +int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options) +{ + int flag; + struct task_struct *p; + unsigned long oldblocked; + + verify_area(stat_addr,4); +repeat: + flag=0; + for (p = current->p_cptr ; p ; p = p->p_osptr) { + if (pid>0) { + if (p->pid != pid) + continue; + } else if (!pid) { + if (p->pgrp != current->pgrp) + continue; + } else if (pid != -1) { + if (p->pgrp != -pid) + continue; + } + switch (p->state) { + case TASK_STOPPED: + if (!(options & WUNTRACED) || + !p->exit_code) + continue; + put_fs_long((p->exit_code << 8) | 0x7f, + stat_addr); + p->exit_code = 0; + return p->pid; + case TASK_ZOMBIE: + current->cutime += p->utime; + current->cstime += p->stime; + flag = p->pid; + put_fs_long(p->exit_code, stat_addr); + release(p); +#ifdef DEBUG_PROC_TREE + audit_ptree(); +#endif + return flag; + default: + flag=1; + continue; + } + } + if (flag) { + if (options & WNOHANG) + return 0; + current->state=TASK_INTERRUPTIBLE; + oldblocked = current->blocked; + current->blocked &= ~(1<<(SIGCHLD-1)); + schedule(); + current->blocked = oldblocked; + if (current->signal & ~(current->blocked | (1<<(SIGCHLD-1)))) + return -ERESTARTSYS; + else + goto repeat; + } + return -ECHILD; +} + + diff --git a/kernel/0.1x/linux-0.12/kernel/fork.c b/kernel/0.1x/linux-0.12/kernel/fork.c new file mode 100644 index 00000000..01dcbbad --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/fork.c @@ -0,0 +1,157 @@ +/* + * linux/kernel/fork.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'fork.c' contains the help-routines for the 'fork' system call + * (see also system_call.s), and some misc functions ('verify_area'). + * Fork is rather simple, once you get the hang of it, but the memory + * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()' + */ +#include + +#include +#include +#include +#include + +extern void write_verify(unsigned long address); + +long last_pid=0; + +void verify_area(void * addr,int size) +{ + unsigned long start; + + start = (unsigned long) addr; + size += start & 0xfff; + start &= 0xfffff000; + start += get_base(current->ldt[2]); + while (size>0) { + size -= 4096; + write_verify(start); + start += 4096; + } +} + +int copy_mem(int nr,struct task_struct * p) +{ + unsigned long old_data_base,new_data_base,data_limit; + unsigned long old_code_base,new_code_base,code_limit; + + code_limit=get_limit(0x0f); + data_limit=get_limit(0x17); + old_code_base = get_base(current->ldt[1]); + old_data_base = get_base(current->ldt[2]); + if (old_data_base != old_code_base) + panic("We don't support separate I&D"); + if (data_limit < code_limit) + panic("Bad data_limit"); + new_data_base = new_code_base = nr * TASK_SIZE; + p->start_code = new_code_base; + set_base(p->ldt[1],new_code_base); + set_base(p->ldt[2],new_data_base); + if (copy_page_tables(old_data_base,new_data_base,data_limit)) { + free_page_tables(new_data_base,data_limit); + return -ENOMEM; + } + return 0; +} + +/* + * Ok, this is the main fork-routine. It copies the system process + * information (task[nr]) and sets up the necessary registers. It + * also copies the data segment in it's entirety. + */ +int copy_process(int nr,long ebp,long edi,long esi,long gs,long none, + long ebx,long ecx,long edx, long orig_eax, + long fs,long es,long ds, + long eip,long cs,long eflags,long esp,long ss) +{ + struct task_struct *p; + int i; + struct file *f; + + p = (struct task_struct *) get_free_page(); + if (!p) + return -EAGAIN; + task[nr] = p; + *p = *current; /* NOTE! this doesn't copy the supervisor stack */ + p->state = TASK_UNINTERRUPTIBLE; + p->pid = last_pid; + p->counter = p->priority; + p->signal = 0; + p->alarm = 0; + p->leader = 0; /* process leadership doesn't inherit */ + p->utime = p->stime = 0; + p->cutime = p->cstime = 0; + p->start_time = jiffies; + p->tss.back_link = 0; + p->tss.esp0 = PAGE_SIZE + (long) p; + p->tss.ss0 = 0x10; + p->tss.eip = eip; + p->tss.eflags = eflags; + p->tss.eax = 0; + p->tss.ecx = ecx; + p->tss.edx = edx; + p->tss.ebx = ebx; + p->tss.esp = esp; + p->tss.ebp = ebp; + p->tss.esi = esi; + p->tss.edi = edi; + p->tss.es = es & 0xffff; + p->tss.cs = cs & 0xffff; + p->tss.ss = ss & 0xffff; + p->tss.ds = ds & 0xffff; + p->tss.fs = fs & 0xffff; + p->tss.gs = gs & 0xffff; + p->tss.ldt = _LDT(nr); + p->tss.trace_bitmap = 0x80000000; + if (last_task_used_math == current) + __asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387)); + if (copy_mem(nr,p)) { + task[nr] = NULL; + free_page((long) p); + return -EAGAIN; + } + for (i=0; ifilp[i]) + f->f_count++; + if (current->pwd) + current->pwd->i_count++; + if (current->root) + current->root->i_count++; + if (current->executable) + current->executable->i_count++; + if (current->library) + current->library->i_count++; + set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss)); + set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt)); + p->p_pptr = current; + p->p_cptr = 0; + p->p_ysptr = 0; + p->p_osptr = current->p_cptr; + if (p->p_osptr) + p->p_osptr->p_ysptr = p; + current->p_cptr = p; + p->state = TASK_RUNNING; /* do this last, just in case */ + return last_pid; +} + +int find_empty_process(void) +{ + int i; + + repeat: + if ((++last_pid)<0) last_pid=1; + for(i=0 ; ipid == last_pid) || + (task[i]->pgrp == last_pid))) + goto repeat; + for(i=1 ; i 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: +add.s add.o : add.c ../../include/linux/math_emu.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/signal.h +compare.s compare.o : compare.c ../../include/linux/math_emu.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/signal.h +convert.s convert.o : convert.c ../../include/linux/math_emu.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/signal.h +div.s div.o : div.c ../../include/linux/math_emu.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/signal.h +ea.s ea.o : ea.c ../../include/stddef.h ../../include/linux/math_emu.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/signal.h \ + ../../include/asm/segment.h +error.s error.o : error.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/linux/kernel.h +get_put.s get_put.o : get_put.c ../../include/signal.h ../../include/sys/types.h \ + ../../include/linux/math_emu.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 +math_emulate.s math_emulate.o : math_emulate.c ../../include/signal.h \ + ../../include/sys/types.h ../../include/linux/math_emu.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 +mul.s mul.o : mul.c ../../include/linux/math_emu.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/signal.h diff --git a/kernel/0.1x/linux-0.12/kernel/math/add.c b/kernel/0.1x/linux-0.12/kernel/math/add.c new file mode 100644 index 00000000..ec9b1213 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/math/add.c @@ -0,0 +1,92 @@ +/* + * linux/kernel/math/add.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * temporary real addition routine. + * + * NOTE! These aren't exact: they are only 62 bits wide, and don't do + * correct rounding. Fast hack. The reason is that we shift right the + * values by two, in order not to have overflow (1 bit), and to be able + * to move the sign into the mantissa (1 bit). Much simpler algorithms, + * and 62 bits (61 really - no rounding) accuracy is usually enough. The + * only time you should notice anything weird is when adding 64-bit + * integers together. When using doubles (52 bits accuracy), the + * 61-bit accuracy never shows at all. + */ + +#include + +#define NEGINT(a) \ +__asm__("notl %0 ; notl %1 ; addl $1,%0 ; adcl $0,%1" \ + :"=r" (a->a),"=r" (a->b) \ + :"0" (a->a),"1" (a->b)) + +static void signify(temp_real * a) +{ + a->exponent += 2; + __asm__("shrdl $2,%1,%0 ; shrl $2,%1" + :"=r" (a->a),"=r" (a->b) + :"0" (a->a),"1" (a->b)); + if (a->exponent < 0) + NEGINT(a); + a->exponent &= 0x7fff; +} + +static void unsignify(temp_real * a) +{ + if (!(a->a || a->b)) { + a->exponent = 0; + return; + } + a->exponent &= 0x7fff; + if (a->b < 0) { + NEGINT(a); + a->exponent |= 0x8000; + } + while (a->b >= 0) { + a->exponent--; + __asm__("addl %0,%0 ; adcl %1,%1" + :"=r" (a->a),"=r" (a->b) + :"0" (a->a),"1" (a->b)); + } +} + +void fadd(const temp_real * src1, const temp_real * src2, temp_real * result) +{ + temp_real a,b; + int x1,x2,shift; + + x1 = src1->exponent & 0x7fff; + x2 = src2->exponent & 0x7fff; + if (x1 > x2) { + a = *src1; + b = *src2; + shift = x1-x2; + } else { + a = *src2; + b = *src1; + shift = x2-x1; + } + if (shift >= 64) { + *result = a; + return; + } + if (shift >= 32) { + b.a = b.b; + b.b = 0; + shift -= 32; + } + __asm__("shrdl %4,%1,%0 ; shrl %4,%1" + :"=r" (b.a),"=r" (b.b) + :"0" (b.a),"1" (b.b),"c" ((char) shift)); + signify(&a); + signify(&b); + __asm__("addl %4,%0 ; adcl %5,%1" + :"=r" (a.a),"=r" (a.b) + :"0" (a.a),"1" (a.b),"g" (b.a),"g" (b.b)); + unsignify(&a); + *result = a; +} diff --git a/kernel/0.1x/linux-0.12/kernel/math/compare.c b/kernel/0.1x/linux-0.12/kernel/math/compare.c new file mode 100644 index 00000000..6d4d53ae --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/math/compare.c @@ -0,0 +1,60 @@ +/* + * linux/kernel/math/compare.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * temporary real comparison routines + */ + +#include + +#define clear_Cx() (I387.swd &= ~0x4500) + +static void normalize(temp_real * a) +{ + int i = a->exponent & 0x7fff; + int sign = a->exponent & 0x8000; + + if (!(a->a || a->b)) { + a->exponent = 0; + return; + } + while (i && a->b >= 0) { + i--; + __asm__("addl %0,%0 ; adcl %1,%1" + :"=r" (a->a),"=r" (a->b) + :"0" (a->a),"1" (a->b)); + } + a->exponent = i | sign; +} + +void ftst(const temp_real * a) +{ + temp_real b; + + clear_Cx(); + b = *a; + normalize(&b); + if (b.a || b.b || b.exponent) { + if (b.exponent < 0) + set_C0(); + } else + set_C3(); +} + +void fcom(const temp_real * src1, const temp_real * src2) +{ + temp_real a; + + a = *src1; + a.exponent ^= 0x8000; + fadd(&a,src2,&a); + ftst(&a); +} + +void fucom(const temp_real * src1, const temp_real * src2) +{ + fcom(src1,src2); +} diff --git a/kernel/0.1x/linux-0.12/kernel/math/convert.c b/kernel/0.1x/linux-0.12/kernel/math/convert.c new file mode 100644 index 00000000..155ab579 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/math/convert.c @@ -0,0 +1,185 @@ +/* + * linux/kernel/math/convert.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +/* + * NOTE!!! There is some "non-obvious" optimisations in the temp_to_long + * and temp_to_short conversion routines: don't touch them if you don't + * know what's going on. They are the adding of one in the rounding: the + * overflow bit is also used for adding one into the exponent. Thus it + * looks like the overflow would be incorrectly handled, but due to the + * way the IEEE numbers work, things are correct. + * + * There is no checking for total overflow in the conversions, though (ie + * if the temp-real number simply won't fit in a short- or long-real.) + */ + +void short_to_temp(const short_real * a, temp_real * b) +{ + if (!(*a & 0x7fffffff)) { + b->a = b->b = 0; + if (*a) + b->exponent = 0x8000; + else + b->exponent = 0; + return; + } + b->exponent = ((*a>>23) & 0xff)-127+16383; + if (*a<0) + b->exponent |= 0x8000; + b->b = (*a<<8) | 0x80000000; + b->a = 0; +} + +void long_to_temp(const long_real * a, temp_real * b) +{ + if (!a->a && !(a->b & 0x7fffffff)) { + b->a = b->b = 0; + if (a->b) + b->exponent = 0x8000; + else + b->exponent = 0; + return; + } + b->exponent = ((a->b >> 20) & 0x7ff)-1023+16383; + if (a->b<0) + b->exponent |= 0x8000; + b->b = 0x80000000 | (a->b<<11) | (((unsigned long)a->a)>>21); + b->a = a->a<<11; +} + +void temp_to_short(const temp_real * a, short_real * b) +{ + if (!(a->exponent & 0x7fff)) { + *b = (a->exponent)?0x80000000:0; + return; + } + *b = ((((long) a->exponent)-16383+127) << 23) & 0x7f800000; + if (a->exponent < 0) + *b |= 0x80000000; + *b |= (a->b >> 8) & 0x007fffff; + switch (ROUNDING) { + case ROUND_NEAREST: + if ((a->b & 0xff) > 0x80) + ++*b; + break; + case ROUND_DOWN: + if ((a->exponent & 0x8000) && (a->b & 0xff)) + ++*b; + break; + case ROUND_UP: + if (!(a->exponent & 0x8000) && (a->b & 0xff)) + ++*b; + break; + } +} + +void temp_to_long(const temp_real * a, long_real * b) +{ + if (!(a->exponent & 0x7fff)) { + b->a = 0; + b->b = (a->exponent)?0x80000000:0; + return; + } + b->b = (((0x7fff & (long) a->exponent)-16383+1023) << 20) & 0x7ff00000; + if (a->exponent < 0) + b->b |= 0x80000000; + b->b |= (a->b >> 11) & 0x000fffff; + b->a = a->b << 21; + b->a |= (a->a >> 11) & 0x001fffff; + switch (ROUNDING) { + case ROUND_NEAREST: + if ((a->a & 0x7ff) > 0x400) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + case ROUND_DOWN: + if ((a->exponent & 0x8000) && (a->b & 0xff)) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + case ROUND_UP: + if (!(a->exponent & 0x8000) && (a->b & 0xff)) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + } +} + +void real_to_int(const temp_real * a, temp_int * b) +{ + int shift = 16383 + 63 - (a->exponent & 0x7fff); + unsigned long underflow; + + b->a = b->b = underflow = 0; + b->sign = (a->exponent < 0); + if (shift < 0) { + set_OE(); + return; + } + if (shift < 32) { + b->b = a->b; b->a = a->a; + } else if (shift < 64) { + b->a = a->b; underflow = a->a; + shift -= 32; + } else if (shift < 96) { + underflow = a->b; + shift -= 64; + } else + return; + __asm__("shrdl %2,%1,%0" + :"=r" (underflow),"=r" (b->a) + :"c" ((char) shift),"0" (underflow),"1" (b->a)); + __asm__("shrdl %2,%1,%0" + :"=r" (b->a),"=r" (b->b) + :"c" ((char) shift),"0" (b->a),"1" (b->b)); + __asm__("shrl %1,%0" + :"=r" (b->b) + :"c" ((char) shift),"0" (b->b)); + switch (ROUNDING) { + case ROUND_NEAREST: + __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b) + ,"r" (0x7fffffff + (b->a & 1)) + ,"m" (*&underflow)); + break; + case ROUND_UP: + if (!b->sign && underflow) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + case ROUND_DOWN: + if (b->sign && underflow) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + } +} + +void int_to_real(const temp_int * a, temp_real * b) +{ + b->a = a->a; + b->b = a->b; + if (b->a || b->b) + b->exponent = 16383 + 63 + (a->sign? 0x8000:0); + else { + b->exponent = 0; + return; + } + while (b->b >= 0) { + b->exponent--; + __asm__("addl %0,%0 ; adcl %1,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + } +} diff --git a/kernel/0.1x/linux-0.12/kernel/math/div.c b/kernel/0.1x/linux-0.12/kernel/math/div.c new file mode 100644 index 00000000..19138f9a --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/math/div.c @@ -0,0 +1,109 @@ +/* + * linux/kernel/math/div.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * temporary real division routine. + */ + +#include + +static void shift_left(int * c) +{ + __asm__ __volatile__("movl (%0),%%eax ; addl %%eax,(%0)\n\t" + "movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t" + "movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t" + "movl 12(%0),%%eax ; adcl %%eax,12(%0)" + ::"r" ((long) c):"ax"); +} + +static void shift_right(int * c) +{ + __asm__("shrl $1,12(%0) ; rcrl $1,8(%0) ; rcrl $1,4(%0) ; rcrl $1,(%0)" + ::"r" ((long) c)); +} + +static int try_sub(int * a, int * b) +{ + char ok; + + __asm__ __volatile__("movl (%1),%%eax ; subl %%eax,(%2)\n\t" + "movl 4(%1),%%eax ; sbbl %%eax,4(%2)\n\t" + "movl 8(%1),%%eax ; sbbl %%eax,8(%2)\n\t" + "movl 12(%1),%%eax ; sbbl %%eax,12(%2)\n\t" + "setae %%al":"=a" (ok):"c" ((long) a),"d" ((long) b)); + return ok; +} + +static void div64(int * a, int * b, int * c) +{ + int tmp[4]; + int i; + unsigned int mask = 0; + + c += 4; + for (i = 0 ; i<64 ; i++) { + if (!(mask >>= 1)) { + c--; + mask = 0x80000000; + } + tmp[0] = a[0]; tmp[1] = a[1]; + tmp[2] = a[2]; tmp[3] = a[3]; + if (try_sub(b,tmp)) { + *c |= mask; + a[0] = tmp[0]; a[1] = tmp[1]; + a[2] = tmp[2]; a[3] = tmp[3]; + } + shift_right(b); + } +} + +void fdiv(const temp_real * src1, const temp_real * src2, temp_real * result) +{ + int i,sign; + int a[4],b[4],tmp[4] = {0,0,0,0}; + + sign = (src1->exponent ^ src2->exponent) & 0x8000; + if (!(src2->a || src2->b)) { + set_ZE(); + return; + } + i = (src1->exponent & 0x7fff) - (src2->exponent & 0x7fff) + 16383; + if (i<0) { + set_UE(); + result->exponent = sign; + result->a = result->b = 0; + return; + } + a[0] = a[1] = 0; + a[2] = src1->a; + a[3] = src1->b; + b[0] = b[1] = 0; + b[2] = src2->a; + b[3] = src2->b; + while (b[3] >= 0) { + i++; + shift_left(b); + } + div64(a,b,tmp); + if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) { + while (i && tmp[3] >= 0) { + i--; + shift_left(tmp); + } + if (tmp[3] >= 0) + set_DE(); + } else + i = 0; + if (i>0x7fff) { + set_OE(); + return; + } + if (tmp[0] || tmp[1]) + set_PE(); + result->exponent = i | sign; + result->a = tmp[2]; + result->b = tmp[3]; +} diff --git a/kernel/0.1x/linux-0.12/kernel/math/ea.c b/kernel/0.1x/linux-0.12/kernel/math/ea.c new file mode 100644 index 00000000..506dfcbb --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/math/ea.c @@ -0,0 +1,92 @@ +/* + * linux/kernel/math/ea.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * Calculate the effective address. + */ + +#include + +#include +#include + +static int __regoffset[] = { + offsetof(struct info,___eax), + offsetof(struct info,___ecx), + offsetof(struct info,___edx), + offsetof(struct info,___ebx), + offsetof(struct info,___esp), + offsetof(struct info,___ebp), + offsetof(struct info,___esi), + offsetof(struct info,___edi) +}; + +#define REG(x) (*(long *)(__regoffset[(x)]+(char *) info)) + +static char * sib(struct info * info, int mod) +{ + unsigned char ss,index,base; + long offset = 0; + + base = get_fs_byte((char *) EIP); + EIP++; + ss = base >> 6; + index = (base >> 3) & 7; + base &= 7; + if (index == 4) + offset = 0; + else + offset = REG(index); + offset <<= ss; + if (mod || base != 5) + offset += REG(base); + if (mod == 1) { + offset += (signed char) get_fs_byte((char *) EIP); + EIP++; + } else if (mod == 2 || base == 5) { + offset += (signed) get_fs_long((unsigned long *) EIP); + EIP += 4; + } + I387.foo = offset; + I387.fos = 0x17; + return (char *) offset; +} + +char * ea(struct info * info, unsigned short code) +{ + unsigned char mod,rm; + long * tmp = &EAX; + int offset = 0; + + mod = (code >> 6) & 3; + rm = code & 7; + if (rm == 4 && mod != 3) + return sib(info,mod); + if (rm == 5 && !mod) { + offset = get_fs_long((unsigned long *) EIP); + EIP += 4; + I387.foo = offset; + I387.fos = 0x17; + return (char *) offset; + } + tmp = & REG(rm); + switch (mod) { + case 0: offset = 0; break; + case 1: + offset = (signed char) get_fs_byte((char *) EIP); + EIP++; + break; + case 2: + offset = (signed) get_fs_long((unsigned long *) EIP); + EIP += 4; + break; + case 3: + math_abort(info,1<<(SIGILL-1)); + } + I387.foo = offset; + I387.fos = 0x17; + return offset + (char *) *tmp; +} diff --git a/kernel/0.1x/linux-0.12/kernel/math/error.c b/kernel/0.1x/linux-0.12/kernel/math/error.c new file mode 100644 index 00000000..c0dd9c0c --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/math/error.c @@ -0,0 +1,16 @@ +/* + * linux/kernel/math/error.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include + +void math_error(void) +{ + __asm__("fnclex"); + if (last_task_used_math) + last_task_used_math->signal |= 1<<(SIGFPE-1); +} diff --git a/kernel/0.1x/linux-0.12/kernel/math/get_put.c b/kernel/0.1x/linux-0.12/kernel/math/get_put.c new file mode 100644 index 00000000..88372e99 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/math/get_put.c @@ -0,0 +1,240 @@ +/* + * linux/kernel/math/get_put.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This file handles all accesses to user memory: getting and putting + * ints/reals/BCD etc. This is the only part that concerns itself with + * other than temporary real format. All other cals are strictly temp_real. + */ +#include + +#include +#include +#include + +void get_short_real(temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + short_real sr; + + addr = ea(info,code); + sr = get_fs_long((unsigned long *) addr); + short_to_temp(&sr,tmp); +} + +void get_long_real(temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + long_real lr; + + addr = ea(info,code); + lr.a = get_fs_long((unsigned long *) addr); + lr.b = get_fs_long(1 + (unsigned long *) addr); + long_to_temp(&lr,tmp); +} + +void get_temp_real(temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + + addr = ea(info,code); + tmp->a = get_fs_long((unsigned long *) addr); + tmp->b = get_fs_long(1 + (unsigned long *) addr); + tmp->exponent = get_fs_word(4 + (unsigned short *) addr); +} + +void get_short_int(temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + ti.a = (signed short) get_fs_word((unsigned short *) addr); + ti.b = 0; + if (ti.sign = (ti.a < 0)) + ti.a = - ti.a; + int_to_real(&ti,tmp); +} + +void get_long_int(temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + ti.a = get_fs_long((unsigned long *) addr); + ti.b = 0; + if (ti.sign = (ti.a < 0)) + ti.a = - ti.a; + int_to_real(&ti,tmp); +} + +void get_longlong_int(temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + ti.a = get_fs_long((unsigned long *) addr); + ti.b = get_fs_long(1 + (unsigned long *) addr); + if (ti.sign = (ti.b < 0)) + __asm__("notl %0 ; notl %1\n\t" + "addl $1,%0 ; adcl $0,%1" + :"=r" (ti.a),"=r" (ti.b) + :"0" (ti.a),"1" (ti.b)); + int_to_real(&ti,tmp); +} + +#define MUL10(low,high) \ +__asm__("addl %0,%0 ; adcl %1,%1\n\t" \ +"movl %0,%%ecx ; movl %1,%%ebx\n\t" \ +"addl %0,%0 ; adcl %1,%1\n\t" \ +"addl %0,%0 ; adcl %1,%1\n\t" \ +"addl %%ecx,%0 ; adcl %%ebx,%1" \ +:"=a" (low),"=d" (high) \ +:"0" (low),"1" (high):"cx","bx") + +#define ADD64(val,low,high) \ +__asm__("addl %4,%0 ; adcl $0,%1":"=r" (low),"=r" (high) \ +:"0" (low),"1" (high),"r" ((unsigned long) (val))) + +void get_BCD(temp_real * tmp, struct info * info, unsigned short code) +{ + int k; + char * addr; + temp_int i; + unsigned char c; + + addr = ea(info,code); + addr += 9; + i.sign = 0x80 & get_fs_byte(addr--); + i.a = i.b = 0; + for (k = 0; k < 9; k++) { + c = get_fs_byte(addr--); + MUL10(i.a, i.b); + ADD64((c>>4), i.a, i.b); + MUL10(i.a, i.b); + ADD64((c&0xf), i.a, i.b); + } + int_to_real(&i,tmp); +} + +void put_short_real(const temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + short_real sr; + + addr = ea(info,code); + verify_area(addr,4); + temp_to_short(tmp,&sr); + put_fs_long(sr,(unsigned long *) addr); +} + +void put_long_real(const temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + long_real lr; + + addr = ea(info,code); + verify_area(addr,8); + temp_to_long(tmp,&lr); + put_fs_long(lr.a, (unsigned long *) addr); + put_fs_long(lr.b, 1 + (unsigned long *) addr); +} + +void put_temp_real(const temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + + addr = ea(info,code); + verify_area(addr,10); + put_fs_long(tmp->a, (unsigned long *) addr); + put_fs_long(tmp->b, 1 + (unsigned long *) addr); + put_fs_word(tmp->exponent, 4 + (short *) addr); +} + +void put_short_int(const temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + real_to_int(tmp,&ti); + verify_area(addr,2); + if (ti.sign) + ti.a = -ti.a; + put_fs_word(ti.a,(short *) addr); +} + +void put_long_int(const temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + real_to_int(tmp,&ti); + verify_area(addr,4); + if (ti.sign) + ti.a = -ti.a; + put_fs_long(ti.a,(unsigned long *) addr); +} + +void put_longlong_int(const temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + real_to_int(tmp,&ti); + verify_area(addr,8); + if (ti.sign) + __asm__("notl %0 ; notl %1\n\t" + "addl $1,%0 ; adcl $0,%1" + :"=r" (ti.a),"=r" (ti.b) + :"0" (ti.a),"1" (ti.b)); + put_fs_long(ti.a,(unsigned long *) addr); + put_fs_long(ti.b,1 + (unsigned long *) addr); +} + +#define DIV10(low,high,rem) \ +__asm__("divl %6 ; xchgl %1,%2 ; divl %6" \ + :"=d" (rem),"=a" (low),"=b" (high) \ + :"0" (0),"1" (high),"2" (low),"c" (10)) + +void put_BCD(const temp_real * tmp,struct info * info, unsigned short code) +{ + int k,rem; + char * addr; + temp_int i; + unsigned char c; + + addr = ea(info,code); + verify_area(addr,10); + real_to_int(tmp,&i); + if (i.sign) + put_fs_byte(0x80, addr+9); + else + put_fs_byte(0, addr+9); + for (k = 0; k < 9; k++) { + DIV10(i.a,i.b,rem); + c = rem; + DIV10(i.a,i.b,rem); + c += rem<<4; + put_fs_byte(c,addr++); + } +} diff --git a/kernel/0.1x/linux-0.12/kernel/math/math_emulate.c b/kernel/0.1x/linux-0.12/kernel/math/math_emulate.c new file mode 100644 index 00000000..f6bdedae --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/math/math_emulate.c @@ -0,0 +1,529 @@ +/* + * linux/kernel/math/math_emulate.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * Limited emulation 27.12.91 - mostly loads/stores, which gcc wants + * even for soft-float, unless you use bruce evans' patches. The patches + * are great, but they have to be re-applied for every version, and the + * library is different for soft-float and 80387. So emulation is more + * practical, even though it's slower. + * + * 28.12.91 - loads/stores work, even BCD. I'll have to start thinking + * about add/sub/mul/div. Urgel. I should find some good source, but I'll + * just fake up something. + * + * 30.12.91 - add/sub/mul/div/com seem to work mostly. I should really + * test every possible combination. + */ + +/* + * This file is full of ugly macros etc: one problem was that gcc simply + * didn't want to make the structures as they should be: it has to try to + * align them. Sickening code, but at least I've hidden the ugly things + * in this one file: the other files don't need to know about these things. + * + * The other files also don't care about ST(x) etc - they just get addresses + * to 80-bit temporary reals, and do with them as they please. I wanted to + * hide most of the 387-specific things here. + */ + +#include + +#define __ALIGNED_TEMP_REAL 1 +#include +#include +#include + +#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x)) +#define ST(x) (*__st((x))) +#define PST(x) ((const temp_real *) __st((x))) + +/* + * We don't want these inlined - it gets too messy in the machine-code. + */ +static void fpop(void); +static void fpush(void); +static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b); +static temp_real_unaligned * __st(int i); + +static void do_emu(struct info * info) +{ + unsigned short code; + temp_real tmp; + char * address; + + if (I387.cwd & I387.swd & 0x3f) + I387.swd |= 0x8000; + else + I387.swd &= 0x7fff; + ORIG_EIP = EIP; +/* 0x0007 means user code space */ + if (CS != 0x000F) { + printk("math_emulate: %04x:%08x\n\r",CS,EIP); + panic("Math emulation needed in kernel"); + } + code = get_fs_word((unsigned short *) EIP); + bswapw(code); + code &= 0x7ff; + I387.fip = EIP; + *(unsigned short *) &I387.fcs = CS; + *(1+(unsigned short *) &I387.fcs) = code; + EIP += 2; + switch (code) { + case 0x1d0: /* fnop */ + return; + case 0x1d1: case 0x1d2: case 0x1d3: + case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7: + math_abort(info,1<<(SIGILL-1)); + case 0x1e0: + ST(0).exponent ^= 0x8000; + return; + case 0x1e1: + ST(0).exponent &= 0x7fff; + return; + case 0x1e2: case 0x1e3: + math_abort(info,1<<(SIGILL-1)); + case 0x1e4: + ftst(PST(0)); + return; + case 0x1e5: + printk("fxam not implemented\n\r"); + math_abort(info,1<<(SIGILL-1)); + case 0x1e6: case 0x1e7: + math_abort(info,1<<(SIGILL-1)); + case 0x1e8: + fpush(); + ST(0) = CONST1; + return; + case 0x1e9: + fpush(); + ST(0) = CONSTL2T; + return; + case 0x1ea: + fpush(); + ST(0) = CONSTL2E; + return; + case 0x1eb: + fpush(); + ST(0) = CONSTPI; + return; + case 0x1ec: + fpush(); + ST(0) = CONSTLG2; + return; + case 0x1ed: + fpush(); + ST(0) = CONSTLN2; + return; + case 0x1ee: + fpush(); + ST(0) = CONSTZ; + return; + case 0x1ef: + math_abort(info,1<<(SIGILL-1)); + case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3: + case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7: + case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb: + case 0x1fc: case 0x1fd: case 0x1fe: case 0x1ff: + printk("%04x fxxx not implemented\n\r",code + 0xc800); + math_abort(info,1<<(SIGILL-1)); + case 0x2e9: + fucom(PST(1),PST(0)); + fpop(); fpop(); + return; + case 0x3d0: case 0x3d1: + return; + case 0x3e2: + I387.swd &= 0x7f00; + return; + case 0x3e3: + I387.cwd = 0x037f; + I387.swd = 0x0000; + I387.twd = 0x0000; + return; + case 0x3e4: + return; + case 0x6d9: + fcom(PST(1),PST(0)); + fpop(); fpop(); + return; + case 0x7e0: + *(short *) &EAX = I387.swd; + return; + } + switch (code >> 3) { + case 0x18: + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x19: + fmul(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x1a: + fcom(PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x1b: + fcom(PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + fpop(); + return; + case 0x1c: + real_to_real(&ST(code & 7),&tmp); + tmp.exponent ^= 0x8000; + fadd(PST(0),&tmp,&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x1d: + ST(0).exponent ^= 0x8000; + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x1e: + fdiv(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x1f: + fdiv(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x38: + fpush(); + ST(0) = ST((code & 7)+1); + return; + case 0x39: + fxchg(&ST(0),&ST(code & 7)); + return; + case 0x3b: + ST(code & 7) = ST(0); + fpop(); + return; + case 0x98: + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return; + case 0x99: + fmul(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return; + case 0x9a: + fcom(PST(code & 7),PST(0)); + return; + case 0x9b: + fcom(PST(code & 7),PST(0)); + fpop(); + return; + case 0x9c: + ST(code & 7).exponent ^= 0x8000; + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return; + case 0x9d: + real_to_real(&ST(0),&tmp); + tmp.exponent ^= 0x8000; + fadd(PST(code & 7),&tmp,&tmp); + real_to_real(&tmp,&ST(code & 7)); + return; + case 0x9e: + fdiv(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return; + case 0x9f: + fdiv(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return; + case 0xb8: + printk("ffree not implemented\n\r"); + math_abort(info,1<<(SIGILL-1)); + case 0xb9: + fxchg(&ST(0),&ST(code & 7)); + return; + case 0xba: + ST(code & 7) = ST(0); + return; + case 0xbb: + ST(code & 7) = ST(0); + fpop(); + return; + case 0xbc: + fucom(PST(code & 7),PST(0)); + return; + case 0xbd: + fucom(PST(code & 7),PST(0)); + fpop(); + return; + case 0xd8: + fadd(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return; + case 0xd9: + fmul(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return; + case 0xda: + fcom(PST(code & 7),PST(0)); + fpop(); + return; + case 0xdc: + ST(code & 7).exponent ^= 0x8000; + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return; + case 0xdd: + real_to_real(&ST(0),&tmp); + tmp.exponent ^= 0x8000; + fadd(PST(code & 7),&tmp,&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return; + case 0xde: + fdiv(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return; + case 0xdf: + fdiv(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return; + case 0xf8: + printk("ffree not implemented\n\r"); + math_abort(info,1<<(SIGILL-1)); + fpop(); + return; + case 0xf9: + fxchg(&ST(0),&ST(code & 7)); + return; + case 0xfa: + case 0xfb: + ST(code & 7) = ST(0); + fpop(); + return; + } + switch ((code>>3) & 0xe7) { + case 0x22: + put_short_real(PST(0),info,code); + return; + case 0x23: + put_short_real(PST(0),info,code); + fpop(); + return; + case 0x24: + address = ea(info,code); + for (code = 0 ; code < 7 ; code++) { + ((long *) & I387)[code] = + get_fs_long((unsigned long *) address); + address += 4; + } + return; + case 0x25: + address = ea(info,code); + *(unsigned short *) &I387.cwd = + get_fs_word((unsigned short *) address); + return; + case 0x26: + address = ea(info,code); + verify_area(address,28); + for (code = 0 ; code < 7 ; code++) { + put_fs_long( ((long *) & I387)[code], + (unsigned long *) address); + address += 4; + } + return; + case 0x27: + address = ea(info,code); + verify_area(address,2); + put_fs_word(I387.cwd,(short *) address); + return; + case 0x62: + put_long_int(PST(0),info,code); + return; + case 0x63: + put_long_int(PST(0),info,code); + fpop(); + return; + case 0x65: + fpush(); + get_temp_real(&tmp,info,code); + real_to_real(&tmp,&ST(0)); + return; + case 0x67: + put_temp_real(PST(0),info,code); + fpop(); + return; + case 0xa2: + put_long_real(PST(0),info,code); + return; + case 0xa3: + put_long_real(PST(0),info,code); + fpop(); + return; + case 0xa4: + address = ea(info,code); + for (code = 0 ; code < 27 ; code++) { + ((long *) & I387)[code] = + get_fs_long((unsigned long *) address); + address += 4; + } + return; + case 0xa6: + address = ea(info,code); + verify_area(address,108); + for (code = 0 ; code < 27 ; code++) { + put_fs_long( ((long *) & I387)[code], + (unsigned long *) address); + address += 4; + } + I387.cwd = 0x037f; + I387.swd = 0x0000; + I387.twd = 0x0000; + return; + case 0xa7: + address = ea(info,code); + verify_area(address,2); + put_fs_word(I387.swd,(short *) address); + return; + case 0xe2: + put_short_int(PST(0),info,code); + return; + case 0xe3: + put_short_int(PST(0),info,code); + fpop(); + return; + case 0xe4: + fpush(); + get_BCD(&tmp,info,code); + real_to_real(&tmp,&ST(0)); + return; + case 0xe5: + fpush(); + get_longlong_int(&tmp,info,code); + real_to_real(&tmp,&ST(0)); + return; + case 0xe6: + put_BCD(PST(0),info,code); + fpop(); + return; + case 0xe7: + put_longlong_int(PST(0),info,code); + fpop(); + return; + } + switch (code >> 9) { + case 0: + get_short_real(&tmp,info,code); + break; + case 1: + get_long_int(&tmp,info,code); + break; + case 2: + get_long_real(&tmp,info,code); + break; + case 4: + get_short_int(&tmp,info,code); + } + switch ((code>>3) & 0x27) { + case 0: + fadd(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 1: + fmul(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 2: + fcom(&tmp,PST(0)); + return; + case 3: + fcom(&tmp,PST(0)); + fpop(); + return; + case 4: + tmp.exponent ^= 0x8000; + fadd(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 5: + ST(0).exponent ^= 0x8000; + fadd(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 6: + fdiv(PST(0),&tmp,&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 7: + fdiv(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return; + } + if ((code & 0x138) == 0x100) { + fpush(); + real_to_real(&tmp,&ST(0)); + return; + } + printk("Unknown math-insns: %04x:%08x %04x\n\r",CS,EIP,code); + math_abort(info,1<<(SIGFPE-1)); +} + +void math_emulate(long ___false) +{ + if (!current->used_math) { + current->used_math = 1; + I387.cwd = 0x037f; + I387.swd = 0x0000; + I387.twd = 0x0000; + } +/* &___false points to info->___orig_eip, so subtract 1 to get info */ + do_emu((struct info *) ((&___false) - 1)); +} + +void __math_abort(struct info * info, unsigned int signal) +{ + EIP = ORIG_EIP; + current->signal |= signal; + __asm__("movl %0,%%esp ; ret"::"g" ((long) info)); +} + +static void fpop(void) +{ + unsigned long tmp; + + tmp = I387.swd & 0xffffc7ff; + I387.swd += 0x00000800; + I387.swd &= 0x00003800; + I387.swd |= tmp; +} + +static void fpush(void) +{ + unsigned long tmp; + + tmp = I387.swd & 0xffffc7ff; + I387.swd += 0x00003800; + I387.swd &= 0x00003800; + I387.swd |= tmp; +} + +static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b) +{ + temp_real_unaligned c; + + c = *a; + *a = *b; + *b = c; +} + +static temp_real_unaligned * __st(int i) +{ + i += I387.swd >> 11; + i &= 7; + return (temp_real_unaligned *) (i*10 + (char *)(I387.st_space)); +} diff --git a/kernel/0.1x/linux-0.12/kernel/math/mul.c b/kernel/0.1x/linux-0.12/kernel/math/mul.c new file mode 100644 index 00000000..8bb53e3b --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/math/mul.c @@ -0,0 +1,73 @@ +/* + * linux/kernel/math/mul.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * temporary real multiplication routine. + */ + +#include + +static void shift(int * c) +{ + __asm__("movl (%0),%%eax ; addl %%eax,(%0)\n\t" + "movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t" + "movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t" + "movl 12(%0),%%eax ; adcl %%eax,12(%0)" + ::"r" ((long) c):"ax"); +} + +static void mul64(const temp_real * a, const temp_real * b, int * c) +{ + __asm__("movl (%0),%%eax\n\t" + "mull (%1)\n\t" + "movl %%eax,(%2)\n\t" + "movl %%edx,4(%2)\n\t" + "movl 4(%0),%%eax\n\t" + "mull 4(%1)\n\t" + "movl %%eax,8(%2)\n\t" + "movl %%edx,12(%2)\n\t" + "movl (%0),%%eax\n\t" + "mull 4(%1)\n\t" + "addl %%eax,4(%2)\n\t" + "adcl %%edx,8(%2)\n\t" + "adcl $0,12(%2)\n\t" + "movl 4(%0),%%eax\n\t" + "mull (%1)\n\t" + "addl %%eax,4(%2)\n\t" + "adcl %%edx,8(%2)\n\t" + "adcl $0,12(%2)" + ::"b" ((long) a),"c" ((long) b),"D" ((long) c) + :"ax","dx"); +} + +void fmul(const temp_real * src1, const temp_real * src2, temp_real * result) +{ + int i,sign; + int tmp[4] = {0,0,0,0}; + + sign = (src1->exponent ^ src2->exponent) & 0x8000; + i = (src1->exponent & 0x7fff) + (src2->exponent & 0x7fff) - 16383 + 1; + if (i<0) { + result->exponent = sign; + result->a = result->b = 0; + return; + } + if (i>0x7fff) { + set_OE(); + return; + } + mul64(src1,src2,tmp); + if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) + while (i && tmp[3] >= 0) { + i--; + shift(tmp); + } + else + i = 0; + result->exponent = i | sign; + result->a = tmp[2]; + result->b = tmp[3]; +} diff --git a/kernel/0.1x/linux-0.12/kernel/mktime.c b/kernel/0.1x/linux-0.12/kernel/mktime.c new file mode 100644 index 00000000..ccb7cb22 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/mktime.c @@ -0,0 +1,58 @@ +/* + * linux/kernel/mktime.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +/* + * This isn't the library routine, it is only used in the kernel. + * as such, we don't care about years<1970 etc, but assume everything + * is ok. Similarly, TZ etc is happily ignored. We just do everything + * as easily as possible. Let's find something public for the library + * routines (although I think minix times is public). + */ +/* + * PS. I hate whoever though up the year 1970 - couldn't they have gotten + * a leap-year instead? I also hate Gregorius, pope or no. I'm grumpy. + */ +#define MINUTE 60 +#define HOUR (60*MINUTE) +#define DAY (24*HOUR) +#define YEAR (365*DAY) + +/* interestingly, we assume leap-years */ +static int month[12] = { + 0, + DAY*(31), + DAY*(31+29), + DAY*(31+29+31), + DAY*(31+29+31+30), + DAY*(31+29+31+30+31), + DAY*(31+29+31+30+31+30), + DAY*(31+29+31+30+31+30+31), + DAY*(31+29+31+30+31+30+31+31), + DAY*(31+29+31+30+31+30+31+31+30), + DAY*(31+29+31+30+31+30+31+31+30+31), + DAY*(31+29+31+30+31+30+31+31+30+31+30) +}; + +long kernel_mktime(struct tm * tm) +{ + long res; + int year; + + 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/kernel/0.1x/linux-0.12/kernel/panic.c b/kernel/0.1x/linux-0.12/kernel/panic.c new file mode 100644 index 00000000..6624d505 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/panic.c @@ -0,0 +1,24 @@ +/* + * linux/kernel/panic.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This function is used through-out the kernel (includeinh mm and fs) + * to indicate a major problem. + */ +#include +#include + +void sys_sync(void); /* it's really int */ + +volatile void panic(const char * s) +{ + printk("Kernel panic: %s\n\r",s); + if (current == task[0]) + printk("In swapper task - not syncing\n\r"); + else + sys_sync(); + for(;;); +} diff --git a/kernel/0.1x/linux-0.12/kernel/printk.c b/kernel/0.1x/linux-0.12/kernel/printk.c new file mode 100644 index 00000000..a5b1529c --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/printk.c @@ -0,0 +1,31 @@ +/* + * linux/kernel/printk.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * When in kernel-mode, we cannot use printf, as fs is liable to + * point to 'interesting' things. Make a printf with fs-saving, and + * all is well. + */ +#include +#include + +#include + +static char buf[1024]; + +extern int vsprintf(char * buf, const char * fmt, va_list args); + +int printk(const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + console_print(buf); + return i; +} diff --git a/kernel/0.1x/linux-0.12/kernel/sched.c b/kernel/0.1x/linux-0.12/kernel/sched.c new file mode 100644 index 00000000..7032dd89 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/sched.c @@ -0,0 +1,444 @@ +/* + * linux/kernel/sched.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'sched.c' is the main kernel file. It contains scheduling primitives + * (sleep_on, wakeup, schedule etc) as well as a number of simple system + * call functions (type getpid(), which just extracts a field from + * current-task + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#define _S(nr) (1<<((nr)-1)) +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + +void show_task(int nr,struct task_struct * p) +{ + int i,j = 4096-sizeof(struct task_struct); + + printk("%d: pid=%d, state=%d, father=%d, child=%d, ",nr,p->pid, + p->state, p->p_pptr->pid, p->p_cptr ? p->p_cptr->pid : -1); + i=0; + while (ip_ysptr || p->p_osptr) + printk(" Younger sib=%d, older sib=%d\n\r", + p->p_ysptr ? p->p_ysptr->pid : -1, + p->p_osptr ? p->p_osptr->pid : -1); + else + printk("\n\r"); +} + +void show_state(void) +{ + int i; + + printk("\rTask-info:\n\r"); + for (i=0;i>2 ] ; + +struct { + long * a; + short b; + } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 }; +/* + * 'math_state_restore()' saves the current math information in the + * old math state array, and gets the new ones from the current task + */ +void math_state_restore() +{ + if (last_task_used_math == current) + return; + __asm__("fwait"); + if (last_task_used_math) { + __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387)); + } + last_task_used_math=current; + if (current->used_math) { + __asm__("frstor %0"::"m" (current->tss.i387)); + } else { + __asm__("fninit"::); + current->used_math=1; + } +} + +/* + * 'schedule()' is the scheduler function. This is GOOD CODE! There + * probably won't be any reason to change this, as it should work well + * in all circumstances (ie gives IO-bound processes good response etc). + * The one thing you might take a look at is the signal-handler code here. + * + * NOTE!! Task 0 is the 'idle' task, which gets called when no other + * tasks can run. It can not be killed, and it cannot sleep. The 'state' + * information in task[0] is never used. + */ +void schedule(void) +{ + int i,next,c; + struct task_struct ** p; + +/* check alarm, wake up any interruptible tasks that have got a signal */ + + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if (*p) { + if ((*p)->timeout && (*p)->timeout < jiffies) { + (*p)->timeout = 0; + if ((*p)->state == TASK_INTERRUPTIBLE) + (*p)->state = TASK_RUNNING; + } + if ((*p)->alarm && (*p)->alarm < jiffies) { + (*p)->signal |= (1<<(SIGALRM-1)); + (*p)->alarm = 0; + } + if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) && + (*p)->state==TASK_INTERRUPTIBLE) + (*p)->state=TASK_RUNNING; + } + +/* this is the scheduler proper: */ + + while (1) { + c = -1; + next = 0; + i = NR_TASKS; + p = &task[NR_TASKS]; + while (--i) { + if (!*--p) + continue; + if ((*p)->state == TASK_RUNNING && (*p)->counter > c) + c = (*p)->counter, next = i; + } + if (c) break; + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if (*p) + (*p)->counter = ((*p)->counter >> 1) + + (*p)->priority; + } + switch_to(next); +} + +int sys_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return 0; +} + +static inline void __sleep_on(struct task_struct **p, int state) +{ + struct task_struct *tmp; + + if (!p) + return; + if (current == &(init_task.task)) + panic("task[0] trying to sleep"); + tmp = *p; + *p = current; + current->state = state; +repeat: schedule(); + if (*p && *p != current) { + (**p).state = 0; + current->state = TASK_UNINTERRUPTIBLE; + goto repeat; + } + if (!*p) + printk("Warning: *P = NULL\n\r"); + if (*p = tmp) + tmp->state=0; +} + +void interruptible_sleep_on(struct task_struct **p) +{ + __sleep_on(p,TASK_INTERRUPTIBLE); +} + +void sleep_on(struct task_struct **p) +{ + __sleep_on(p,TASK_UNINTERRUPTIBLE); +} + +void wake_up(struct task_struct **p) +{ + if (p && *p) { + if ((**p).state == TASK_STOPPED) + printk("wake_up: TASK_STOPPED"); + if ((**p).state == TASK_ZOMBIE) + printk("wake_up: TASK_ZOMBIE"); + (**p).state=0; + } +} + +/* + * OK, here are some floppy things that shouldn't be in the kernel + * proper. They are here because the floppy needs a timer, and this + * was the easiest way of doing it. + */ +static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL}; +static int mon_timer[4]={0,0,0,0}; +static int moff_timer[4]={0,0,0,0}; +unsigned char current_DOR = 0x0C; + +int ticks_to_floppy_on(unsigned int nr) +{ + extern unsigned char selected; + unsigned char mask = 0x10 << nr; + + if (nr>3) + panic("floppy_on: nr>3"); + moff_timer[nr]=10000; /* 100 s = very big :-) */ + cli(); /* use floppy_off to turn it off */ + mask |= current_DOR; + if (!selected) { + mask &= 0xFC; + mask |= nr; + } + if (mask != current_DOR) { + outb(mask,FD_DOR); + if ((mask ^ current_DOR) & 0xf0) + mon_timer[nr] = HZ/2; + else if (mon_timer[nr] < 2) + mon_timer[nr] = 2; + current_DOR = mask; + } + sti(); + return mon_timer[nr]; +} + +void floppy_on(unsigned int nr) +{ + cli(); + while (ticks_to_floppy_on(nr)) + sleep_on(nr+wait_motor); + sti(); +} + +void floppy_off(unsigned int nr) +{ + moff_timer[nr]=3*HZ; +} + +void do_floppy_timer(void) +{ + int i; + unsigned char mask = 0x10; + + for (i=0 ; i<4 ; i++,mask <<= 1) { + if (!(mask & current_DOR)) + continue; + if (mon_timer[i]) { + if (!--mon_timer[i]) + wake_up(i+wait_motor); + } else if (!moff_timer[i]) { + current_DOR &= ~mask; + outb(current_DOR,FD_DOR); + } else + moff_timer[i]--; + } +} + +#define TIME_REQUESTS 64 + +static struct timer_list { + long jiffies; + void (*fn)(); + struct timer_list * next; +} timer_list[TIME_REQUESTS], * next_timer = NULL; + +void add_timer(long jiffies, void (*fn)(void)) +{ + struct timer_list * p; + + if (!fn) + return; + cli(); + if (jiffies <= 0) + (fn)(); + else { + for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++) + if (!p->fn) + break; + if (p >= timer_list + TIME_REQUESTS) + panic("No more time requests free"); + p->fn = fn; + p->jiffies = jiffies; + p->next = next_timer; + next_timer = p; + while (p->next && p->next->jiffies < p->jiffies) { + p->jiffies -= p->next->jiffies; + fn = p->fn; + p->fn = p->next->fn; + p->next->fn = fn; + jiffies = p->jiffies; + p->jiffies = p->next->jiffies; + p->next->jiffies = jiffies; + p = p->next; + } + } + sti(); +} + +void do_timer(long cpl) +{ + static int blanked = 0; + + if (blankcount || !blankinterval) { + if (blanked) + unblank_screen(); + if (blankcount) + blankcount--; + blanked = 0; + } else if (!blanked) { + blank_screen(); + blanked = 1; + } + if (hd_timeout) + if (!--hd_timeout) + hd_times_out(); + + if (beepcount) + if (!--beepcount) + sysbeepstop(); + + if (cpl) + current->utime++; + else + current->stime++; + + if (next_timer) { + next_timer->jiffies--; + while (next_timer && next_timer->jiffies <= 0) { + void (*fn)(void); + + fn = next_timer->fn; + next_timer->fn = NULL; + next_timer = next_timer->next; + (fn)(); + } + } + if (current_DOR & 0xf0) + do_floppy_timer(); + if ((--current->counter)>0) return; + current->counter=0; + if (!cpl) return; + schedule(); +} + +int sys_alarm(long seconds) +{ + int old = current->alarm; + + if (old) + old = (old - jiffies) / HZ; + current->alarm = (seconds>0)?(jiffies+HZ*seconds):0; + return (old); +} + +int sys_getpid(void) +{ + return current->pid; +} + +int sys_getppid(void) +{ + return current->p_pptr->pid; +} + +int sys_getuid(void) +{ + return current->uid; +} + +int sys_geteuid(void) +{ + return current->euid; +} + +int sys_getgid(void) +{ + return current->gid; +} + +int sys_getegid(void) +{ + return current->egid; +} + +int sys_nice(long increment) +{ + if (current->priority-increment>0) + current->priority -= increment; + return 0; +} + +void sched_init(void) +{ + int i; + struct desc_struct * p; + + if (sizeof(struct sigaction) != 16) + panic("Struct sigaction MUST be 16 bytes"); + set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); + set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); + p = gdt+2+FIRST_TSS_ENTRY; + for(i=1;ia=p->b=0; + p++; + p->a=p->b=0; + p++; + } +/* Clear NT, so that we won't have troubles with that later on */ + __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); + ltr(0); + lldt(0); + outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */ + outb_p(LATCH & 0xff , 0x40); /* LSB */ + outb(LATCH >> 8 , 0x40); /* MSB */ + set_intr_gate(0x20,&timer_interrupt); + outb(inb_p(0x21)&~0x01,0x21); + set_system_gate(0x80,&system_call); +} diff --git a/kernel/0.1x/linux-0.12/kernel/signal.c b/kernel/0.1x/linux-0.12/kernel/signal.c new file mode 100644 index 00000000..79e1af94 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/signal.c @@ -0,0 +1,209 @@ +/* + * linux/kernel/signal.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include + +int sys_sgetmask() +{ + return current->blocked; +} + +int sys_ssetmask(int newmask) +{ + int old=current->blocked; + + current->blocked = newmask & ~(1<<(SIGKILL-1)) & ~(1<<(SIGSTOP-1)); + return old; +} + +int sys_sigpending(sigset_t *set) +{ + /* fill in "set" with signals pending but blocked. */ + verify_area(set,4); + put_fs_long(current->blocked & current->signal, (unsigned long *)set); + return 0; +} + +/* atomically swap in the new signal mask, and wait for a signal. + * + * we need to play some games with syscall restarting. We get help + * from the syscall library interface. Note that we need to coordinate + * the calling convention with the libc routine. + * + * "set" is just the sigmask as described in 1003.1-1988, 3.3.7. + * It is assumed that sigset_t can be passed as a 32 bit quantity. + * + * "restart" holds a restart indication. If it's non-zero, then we + * install the old mask, and return normally. If it's zero, we store + * the current mask in old_mask and block until a signal comes in. + */ +int sys_sigsuspend(int restart, unsigned long old_mask, unsigned long set) +{ + extern int sys_pause(void); + + if (restart) { + /* we're restarting */ + current->blocked = old_mask; + return -EINTR; + } + /* we're not restarting. do the work */ + *(&restart) = 1; + *(&old_mask) = current->blocked; + current->blocked = set; + (void) sys_pause(); /* return after a signal arrives */ + return -ERESTARTNOINTR; /* handle the signal, and come back */ +} + +static inline void save_old(char * from,char * to) +{ + int i; + + verify_area(to, sizeof(struct sigaction)); + for (i=0 ; i< sizeof(struct sigaction) ; i++) { + put_fs_byte(*from,to); + from++; + to++; + } +} + +static inline void get_new(char * from,char * to) +{ + int i; + + for (i=0 ; i< sizeof(struct sigaction) ; i++) + *(to++) = get_fs_byte(from++); +} + +int sys_signal(int signum, long handler, long restorer) +{ + struct sigaction tmp; + + if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP) + return -EINVAL; + tmp.sa_handler = (void (*)(int)) handler; + tmp.sa_mask = 0; + tmp.sa_flags = SA_ONESHOT | SA_NOMASK; + tmp.sa_restorer = (void (*)(void)) restorer; + handler = (long) current->sigaction[signum-1].sa_handler; + current->sigaction[signum-1] = tmp; + return handler; +} + +int sys_sigaction(int signum, const struct sigaction * action, + struct sigaction * oldaction) +{ + struct sigaction tmp; + + if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP) + return -EINVAL; + tmp = current->sigaction[signum-1]; + get_new((char *) action, + (char *) (signum-1+current->sigaction)); + if (oldaction) + save_old((char *) &tmp,(char *) oldaction); + if (current->sigaction[signum-1].sa_flags & SA_NOMASK) + current->sigaction[signum-1].sa_mask = 0; + else + current->sigaction[signum-1].sa_mask |= (1<<(signum-1)); + return 0; +} + +/* + * Routine writes a core dump image in the current directory. + * Currently not implemented. + */ +int core_dump(long signr) +{ + return(0); /* We didn't do a dump */ +} + +int do_signal(long signr,long eax,long ebx, long ecx, long edx, long orig_eax, + long fs, long es, long ds, + long eip, long cs, long eflags, + unsigned long * esp, long ss) +{ + unsigned long sa_handler; + long old_eip=eip; + struct sigaction * sa = current->sigaction + signr - 1; + int longs; + + unsigned long * tmp_esp; + +#ifdef notdef + printk("pid: %d, signr: %x, eax=%d, oeax = %d, int=%d\n", + current->pid, signr, eax, orig_eax, + sa->sa_flags & SA_INTERRUPT); +#endif + if ((orig_eax != -1) && + ((eax == -ERESTARTSYS) || (eax == -ERESTARTNOINTR))) { + if ((eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT) || + signr < SIGCONT || signr > SIGTTOU)) + *(&eax) = -EINTR; + else { + *(&eax) = orig_eax; + *(&eip) = old_eip -= 2; + } + } + sa_handler = (unsigned long) sa->sa_handler; + if (sa_handler==1) + return(1); /* Ignore, see if there are more signals... */ + if (!sa_handler) { + switch (signr) { + case SIGCONT: + case SIGCHLD: + return(1); /* Ignore, ... */ + + case SIGSTOP: + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + current->state = TASK_STOPPED; + current->exit_code = signr; + if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & + SA_NOCLDSTOP)) + current->p_pptr->signal |= (1<<(SIGCHLD-1)); + return(1); /* Reschedule another event */ + + case SIGQUIT: + case SIGILL: + case SIGTRAP: + case SIGIOT: + case SIGFPE: + case SIGSEGV: + if (core_dump(signr)) + do_exit(signr|0x80); + /* fall through */ + default: + do_exit(signr); + } + } + /* + * OK, we're invoking a handler + */ + if (sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; + *(&eip) = sa_handler; + longs = (sa->sa_flags & SA_NOMASK)?7:8; + *(&esp) -= longs; + verify_area(esp,longs*4); + tmp_esp=esp; + put_fs_long((long) sa->sa_restorer,tmp_esp++); + put_fs_long(signr,tmp_esp++); + if (!(sa->sa_flags & SA_NOMASK)) + put_fs_long(current->blocked,tmp_esp++); + put_fs_long(eax,tmp_esp++); + put_fs_long(ecx,tmp_esp++); + put_fs_long(edx,tmp_esp++); + put_fs_long(eflags,tmp_esp++); + put_fs_long(old_eip,tmp_esp++); + current->blocked |= sa->sa_mask; + return(0); /* Continue, execute handler */ +} diff --git a/kernel/0.1x/linux-0.12/kernel/sys.c b/kernel/0.1x/linux-0.12/kernel/sys.c new file mode 100644 index 00000000..3caf88cc --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/sys.c @@ -0,0 +1,522 @@ +/* + * linux/kernel/sys.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The timezone where the local system is located. Used as a default by some + * programs who obtain this value by using gettimeofday. + */ +struct timezone sys_tz = { 0, 0}; + +extern int session_of_pgrp(int pgrp); + +int sys_ftime() +{ + return -ENOSYS; +} + +int sys_break() +{ + return -ENOSYS; +} + +int sys_ptrace() +{ + return -ENOSYS; +} + +int sys_stty() +{ + return -ENOSYS; +} + +int sys_gtty() +{ + return -ENOSYS; +} + +int sys_rename() +{ + return -ENOSYS; +} + +int sys_prof() +{ + return -ENOSYS; +} + +/* + * This is done BSD-style, with no consideration of the saved gid, except + * that if you set the effective gid, it sets the saved gid too. This + * makes it possible for a setgid program to completely drop its privileges, + * which is often a useful assertion to make when you are doing a security + * audit over a program. + * + * The general idea is that a program which uses just setregid() will be + * 100% compatible with BSD. A program which uses just setgid() will be + * 100% compatible with POSIX w/ Saved ID's. + */ +int sys_setregid(int rgid, int egid) +{ + if (rgid>0) { + if ((current->gid == rgid) || + suser()) + current->gid = rgid; + else + return(-EPERM); + } + if (egid>0) { + if ((current->gid == egid) || + (current->egid == egid) || + suser()) { + current->egid = egid; + current->sgid = egid; + } else + return(-EPERM); + } + return 0; +} + +/* + * setgid() is implemeneted like SysV w/ SAVED_IDS + */ +int sys_setgid(int gid) +{ + if (suser()) + current->gid = current->egid = current->sgid = gid; + else if ((gid == current->gid) || (gid == current->sgid)) + current->egid = gid; + else + return -EPERM; + return 0; +} + +int sys_acct() +{ + return -ENOSYS; +} + +int sys_phys() +{ + return -ENOSYS; +} + +int sys_lock() +{ + return -ENOSYS; +} + +int sys_mpx() +{ + return -ENOSYS; +} + +int sys_ulimit() +{ + return -ENOSYS; +} + +int sys_time(long * tloc) +{ + int i; + + i = CURRENT_TIME; + if (tloc) { + verify_area(tloc,4); + put_fs_long(i,(unsigned long *)tloc); + } + return i; +} + +/* + * Unprivileged users may change the real user id to the effective uid + * or vice versa. (BSD-style) + * + * When you set the effective uid, it sets the saved uid too. This + * makes it possible for a setuid program to completely drop its privileges, + * which is often a useful assertion to make when you are doing a security + * audit over a program. + * + * The general idea is that a program which uses just setreuid() will be + * 100% compatible with BSD. A program which uses just setuid() will be + * 100% compatible with POSIX w/ Saved ID's. + */ +int sys_setreuid(int ruid, int euid) +{ + int old_ruid = current->uid; + + if (ruid>0) { + if ((current->euid==ruid) || + (old_ruid == ruid) || + suser()) + current->uid = ruid; + else + return(-EPERM); + } + if (euid>0) { + if ((old_ruid == euid) || + (current->euid == euid) || + suser()) { + current->euid = euid; + current->suid = euid; + } else { + current->uid = old_ruid; + return(-EPERM); + } + } + return 0; +} + +/* + * setuid() is implemeneted like SysV w/ SAVED_IDS + * + * Note that SAVED_ID's is deficient in that a setuid root program + * like sendmail, for example, cannot set its uid to be a normal + * user and then switch back, because if you're root, setuid() sets + * the saved uid too. If you don't like this, blame the bright people + * in the POSIX commmittee and/or USG. Note that the BSD-style setreuid() + * will allow a root program to temporarily drop privileges and be able to + * regain them by swapping the real and effective uid. + */ +int sys_setuid(int uid) +{ + if (suser()) + current->uid = current->euid = current->suid = uid; + else if ((uid == current->uid) || (uid == current->suid)) + current->euid = uid; + else + return -EPERM; + return(0); +} + +int sys_stime(long * tptr) +{ + if (!suser()) + return -EPERM; + startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ; + jiffies_offset = 0; + return 0; +} + +int sys_times(struct tms * tbuf) +{ + if (tbuf) { + verify_area(tbuf,sizeof *tbuf); + put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime); + put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime); + put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime); + put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime); + } + return jiffies; +} + +int sys_brk(unsigned long end_data_seg) +{ + if (end_data_seg >= current->end_code && + end_data_seg < current->start_stack - 16384) + current->brk = end_data_seg; + return current->brk; +} + +/* + * This needs some heave checking ... + * I just haven't get the stomach for it. I also don't fully + * understand sessions/pgrp etc. Let somebody who does explain it. + * + * OK, I think I have the protection semantics right.... this is really + * only important on a multi-user system anyway, to make sure one user + * can't send a signal to a process owned by another. -TYT, 12/12/91 + */ +int sys_setpgid(int pid, int pgid) +{ + int i; + + if (!pid) + pid = current->pid; + if (!pgid) + pgid = current->pid; + if (pgid < 0) + return -EINVAL; + for (i=0 ; ipid == pid) && + ((task[i]->p_pptr == current) || + (task[i] == current))) { + if (task[i]->leader) + return -EPERM; + if ((task[i]->session != current->session) || + ((pgid != pid) && + (session_of_pgrp(pgid) != current->session))) + return -EPERM; + task[i]->pgrp = pgid; + return 0; + } + return -ESRCH; +} + +int sys_getpgrp(void) +{ + return current->pgrp; +} + +int sys_setsid(void) +{ + if (current->leader && !suser()) + return -EPERM; + current->leader = 1; + current->session = current->pgrp = current->pid; + current->tty = -1; + return current->pgrp; +} + +/* + * Supplementary group ID's + */ +int sys_getgroups(int gidsetsize, gid_t *grouplist) +{ + int i; + + if (gidsetsize) + verify_area(grouplist, sizeof(gid_t) * gidsetsize); + + for (i = 0; (i < NGROUPS) && (current->groups[i] != NOGROUP); + i++, grouplist++) { + if (gidsetsize) { + if (i >= gidsetsize) + return -EINVAL; + put_fs_word(current->groups[i], (short *) grouplist); + } + } + return(i); +} + +int sys_setgroups(int gidsetsize, gid_t *grouplist) +{ + int i; + + if (!suser()) + return -EPERM; + if (gidsetsize > NGROUPS) + return -EINVAL; + for (i = 0; i < gidsetsize; i++, grouplist++) { + current->groups[i] = get_fs_word((unsigned short *) grouplist); + } + if (i < NGROUPS) + current->groups[i] = NOGROUP; + return 0; +} + +int in_group_p(gid_t grp) +{ + int i; + + if (grp == current->egid) + return 1; + + for (i = 0; i < NGROUPS; i++) { + if (current->groups[i] == NOGROUP) + break; + if (current->groups[i] == grp) + return 1; + } + return 0; +} + +static struct utsname thisname = { + UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION, UTS_MACHINE +}; + +int sys_uname(struct utsname * name) +{ + int i; + + if (!name) return -ERROR; + verify_area(name,sizeof *name); + for(i=0;i MAXHOSTNAMELEN) + return -EINVAL; + for (i=0; i < len; i++) { + if ((thisname.nodename[i] = get_fs_byte(name+i)) == 0) + break; + } + if (thisname.nodename[i]) { + thisname.nodename[i>MAXHOSTNAMELEN ? MAXHOSTNAMELEN : i] = 0; + } + return 0; +} + +int sys_getrlimit(int resource, struct rlimit *rlim) +{ + if (resource >= RLIM_NLIMITS) + return -EINVAL; + verify_area(rlim,sizeof *rlim); + put_fs_long(current->rlim[resource].rlim_cur, + (unsigned long *) rlim); + put_fs_long(current->rlim[resource].rlim_max, + ((unsigned long *) rlim)+1); + return 0; +} + +int sys_setrlimit(int resource, struct rlimit *rlim) +{ + struct rlimit new, *old; + + if (resource >= RLIM_NLIMITS) + return -EINVAL; + old = current->rlim + resource; + new.rlim_cur = get_fs_long((unsigned long *) rlim); + new.rlim_max = get_fs_long(((unsigned long *) rlim)+1); + if (((new.rlim_cur > old->rlim_max) || + (new.rlim_max > old->rlim_max)) && + !suser()) + return -EPERM; + *old = new; + return 0; +} + +/* + * It would make sense to put struct rusuage in the task_struct, + * except that would make the task_struct be *really big*. After + * task_struct gets moved into malloc'ed memory, it would + * make sense to do this. It will make moving the rest of the information + * a lot simpler! (Which we're not doing right now because we're not + * measuring them yet). + */ +int sys_getrusage(int who, struct rusage *ru) +{ + struct rusage r; + unsigned long *lp, *lpend, *dest; + + if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN) + return -EINVAL; + verify_area(ru, sizeof *ru); + memset((char *) &r, 0, sizeof(r)); + if (who == RUSAGE_SELF) { + r.ru_utime.tv_sec = CT_TO_SECS(current->utime); + r.ru_utime.tv_usec = CT_TO_USECS(current->utime); + r.ru_stime.tv_sec = CT_TO_SECS(current->stime); + r.ru_stime.tv_usec = CT_TO_USECS(current->stime); + } else { + r.ru_utime.tv_sec = CT_TO_SECS(current->cutime); + r.ru_utime.tv_usec = CT_TO_USECS(current->cutime); + r.ru_stime.tv_sec = CT_TO_SECS(current->cstime); + r.ru_stime.tv_usec = CT_TO_USECS(current->cstime); + } + lp = (unsigned long *) &r; + lpend = (unsigned long *) (&r+1); + dest = (unsigned long *) ru; + for (; lp < lpend; lp++, dest++) + put_fs_long(*lp, dest); + return(0); +} + +int sys_gettimeofday(struct timeval *tv, struct timezone *tz) +{ + if (tv) { + verify_area(tv, sizeof *tv); + put_fs_long(startup_time + CT_TO_SECS(jiffies+jiffies_offset), + (unsigned long *) tv); + put_fs_long(CT_TO_USECS(jiffies+jiffies_offset), + ((unsigned long *) tv)+1); + } + if (tz) { + verify_area(tz, sizeof *tz); + put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz); + put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1); + } + return 0; +} + +/* + * The first time we set the timezone, we will warp the clock so that + * it is ticking GMT time instead of local time. Presumably, + * if someone is setting the timezone then we are running in an + * environment where the programs understand about timezones. + * This should be done at boot time in the /etc/rc script, as + * soon as possible, so that the clock can be set right. Otherwise, + * various programs will get confused when the clock gets warped. + */ +int sys_settimeofday(struct timeval *tv, struct timezone *tz) +{ + static int firsttime = 1; + void adjust_clock(); + + if (!suser()) + return -EPERM; + if (tz) { + sys_tz.tz_minuteswest = get_fs_long((unsigned long *) tz); + sys_tz.tz_dsttime = get_fs_long(((unsigned long *) tz)+1); + if (firsttime) { + firsttime = 0; + if (!tv) + adjust_clock(); + } + } + if (tv) { + int sec, usec; + + sec = get_fs_long((unsigned long *)tv); + usec = get_fs_long(((unsigned long *)tv)+1); + + startup_time = sec - jiffies/HZ; + jiffies_offset = usec * HZ / 1000000 - jiffies%HZ; + } + return 0; +} + +/* + * Adjust the time obtained from the CMOS to be GMT time instead of + * local time. + * + * This is ugly, but preferable to the alternatives. Otherwise we + * would either need to write a program to do it in /etc/rc (and risk + * confusion if the program gets run more than once; it would also be + * hard to make the program warp the clock precisely n hours) or + * compile in the timezone information into the kernel. Bad, bad.... + * + * XXX Currently does not adjust for daylight savings time. May not + * need to do anything, depending on how smart (dumb?) the BIOS + * is. Blast it all.... the best thing to do not depend on the CMOS + * clock at all, but get the time via NTP or timed if you're on a + * network.... - TYT, 1/1/92 + */ +void adjust_clock() +{ + startup_time += sys_tz.tz_minuteswest*60; +} + +int sys_umask(int mask) +{ + int old = current->umask; + + current->umask = mask & 0777; + return (old); +} + diff --git a/kernel/0.1x/linux-0.12/kernel/sys_call.s b/kernel/0.1x/linux-0.12/kernel/sys_call.s new file mode 100644 index 00000000..a10901b7 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/sys_call.s @@ -0,0 +1,300 @@ +/* + * linux/kernel/system_call.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * system_call.s contains the system-call low-level handling routines. + * This also contains the timer-interrupt handler, as some of the code is + * the same. The hd- and flopppy-interrupts are also here. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. Ordinary interrupts + * don't handle signal-recognition, as that would clutter them up totally + * unnecessarily. + * + * Stack layout in 'ret_from_system_call': + * + * 0(%esp) - %eax + * 4(%esp) - %ebx + * 8(%esp) - %ecx + * C(%esp) - %edx + * 10(%esp) - original %eax (-1 if not system call) + * 14(%esp) - %fs + * 18(%esp) - %es + * 1C(%esp) - %ds + * 20(%esp) - %eip + * 24(%esp) - %cs + * 28(%esp) - %eflags + * 2C(%esp) - %oldesp + * 30(%esp) - %oldss + */ + +SIG_CHLD = 17 + +EAX = 0x00 +EBX = 0x04 +ECX = 0x08 +EDX = 0x0C +ORIG_EAX = 0x10 +FS = 0x14 +ES = 0x18 +DS = 0x1C +EIP = 0x20 +CS = 0x24 +EFLAGS = 0x28 +OLDESP = 0x2C +OLDSS = 0x30 + +state = 0 # these are offsets into the task-struct. +counter = 4 +priority = 8 +signal = 12 +sigaction = 16 # MUST be 16 (=len of sigaction) +blocked = (33*16) + +# offsets within sigaction +sa_handler = 0 +sa_mask = 4 +sa_flags = 8 +sa_restorer = 12 + +nr_system_calls = 82 + +ENOSYS = 38 + +/* + * Ok, I get parallel printer interrupts while using the floppy for some + * strange reason. Urgel. Now I just ignore them. + */ +.globl _system_call,_sys_fork,_timer_interrupt,_sys_execve +.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt +.globl _device_not_available, _coprocessor_error + +.align 2 +bad_sys_call: + pushl $-ENOSYS + jmp ret_from_sys_call +.align 2 +reschedule: + pushl $ret_from_sys_call + jmp _schedule +.align 2 +_system_call: + push %ds + push %es + push %fs + pushl %eax # save the orig_eax + 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 + cmpl _NR_syscalls,%eax + jae bad_sys_call + call _sys_call_table(,%eax,4) + pushl %eax +2: + movl _current,%eax + cmpl $0,state(%eax) # state + jne reschedule + cmpl $0,counter(%eax) # counter + je reschedule +ret_from_sys_call: + movl _current,%eax + cmpl _task,%eax # task[0] cannot have signals + je 3f + cmpw $0x0f,CS(%esp) # was old code segment supervisor ? + jne 3f + cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ? + jne 3f + movl signal(%eax),%ebx + movl blocked(%eax),%ecx + notl %ecx + andl %ebx,%ecx + bsfl %ecx,%ecx + je 3f + btrl %ecx,%ebx + movl %ebx,signal(%eax) + incl %ecx + pushl %ecx + call _do_signal + popl %ecx + testl %eax, %eax + jne 2b # see if we need to switch tasks, or do more signals +3: popl %eax + popl %ebx + popl %ecx + popl %edx + addl $4, %esp # skip orig_eax + pop %fs + pop %es + pop %ds + iret + +.align 2 +_coprocessor_error: + push %ds + push %es + push %fs + pushl $-1 # fill in -1 for orig_eax + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + pushl $ret_from_sys_call + jmp _math_error + +.align 2 +_device_not_available: + push %ds + push %es + push %fs + pushl $-1 # fill in -1 for orig_eax + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + pushl $ret_from_sys_call + clts # clear TS so that we can use math + movl %cr0,%eax + testl $0x4,%eax # EM (math emulation bit) + je _math_state_restore + pushl %ebp + pushl %esi + pushl %edi + pushl $0 # temporary storage for ORIG_EIP + call _math_emulate + addl $4,%esp + popl %edi + popl %esi + popl %ebp + ret + +.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 $-1 # fill in -1 for orig_eax + 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,$0xA0 # EOI to interrupt controller #1 + jmp 1f # give port chance to breathe +1: jmp 1f +1: xorl %edx,%edx + movl %edx,_hd_timeout + xchgl _do_hd,%edx + testl %edx,%edx + jne 1f + movl $_unexpected_hd_interrupt,%edx +1: outb %al,$0x20 + call *%edx # "interesting" way of handling intr. + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +_floppy_interrupt: + pushl %eax + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + movb $0x20,%al + outb %al,$0x20 # EOI to interrupt controller #1 + xorl %eax,%eax + xchgl _do_floppy,%eax + testl %eax,%eax + jne 1f + movl $_unexpected_floppy_interrupt,%eax +1: call *%eax # "interesting" way of handling intr. + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +_parallel_interrupt: + pushl %eax + movb $0x20,%al + outb %al,$0x20 + popl %eax + iret diff --git a/kernel/0.1x/linux-0.12/kernel/traps.c b/kernel/0.1x/linux-0.12/kernel/traps.c new file mode 100644 index 00000000..f4d13cf4 --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/traps.c @@ -0,0 +1,213 @@ +/* + * linux/kernel/traps.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'asm.s'. Currently mostly a debugging-aid, will be extended + * to mainly kill the offending process (probably by giving it a signal, + * but possibly by killing it outright if necessary). + */ +#include + +#include +#include +#include +#include +#include +#include + +#define get_seg_byte(seg,addr) ({ \ +register char __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define get_seg_long(seg,addr) ({ \ +register unsigned long __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define _fs() ({ \ +register unsigned short __res; \ +__asm__("mov %%fs,%%ax":"=a" (__res):); \ +__res;}) + +void page_exception(void); + +void divide_error(void); +void debug(void); +void nmi(void); +void int3(void); +void overflow(void); +void bounds(void); +void invalid_op(void); +void device_not_available(void); +void double_fault(void); +void coprocessor_segment_overrun(void); +void invalid_TSS(void); +void segment_not_present(void); +void stack_segment(void); +void general_protection(void); +void page_fault(void); +void coprocessor_error(void); +void reserved(void); +void parallel_interrupt(void); +void irq13(void); +void alignment_check(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_alignment_check(long esp, long error_code) +{ + die("alignment check",esp,error_code); +} + +void do_divide_error(long esp, long error_code) +{ + die("divide error",esp,error_code); +} + +void do_int3(long * esp, long error_code, + long fs,long es,long ds, + long ebp,long esi,long edi, + long edx,long ecx,long ebx,long eax) +{ + int tr; + + __asm__("str %%ax":"=a" (tr):"0" (0)); + printk("eax\t\tebx\t\tecx\t\tedx\n\r%8x\t%8x\t%8x\t%8x\n\r", + eax,ebx,ecx,edx); + printk("esi\t\tedi\t\tebp\t\tesp\n\r%8x\t%8x\t%8x\t%8x\n\r", + esi,edi,ebp,(long) esp); + printk("\n\rds\tes\tfs\ttr\n\r%4x\t%4x\t%4x\t%4x\n\r", + ds,es,fs,tr); + printk("EIP: %8x CS: %4x EFLAGS: %8x\n\r",esp[0],esp[1],esp[2]); +} + +void do_nmi(long esp, long error_code) +{ + die("nmi",esp,error_code); +} + +void do_debug(long esp, long error_code) +{ + die("debug",esp,error_code); +} + +void do_overflow(long esp, long error_code) +{ + die("overflow",esp,error_code); +} + +void do_bounds(long esp, long error_code) +{ + die("bounds",esp,error_code); +} + +void do_invalid_op(long esp, long error_code) +{ + die("invalid operand",esp,error_code); +} + +void do_device_not_available(long esp, long error_code) +{ + die("device not available",esp,error_code); +} + +void do_coprocessor_segment_overrun(long esp, long error_code) +{ + die("coprocessor segment overrun",esp,error_code); +} + +void do_invalid_TSS(long esp,long error_code) +{ + die("invalid TSS",esp,error_code); +} + +void do_segment_not_present(long esp,long error_code) +{ + die("segment not present",esp,error_code); +} + +void do_stack_segment(long esp,long error_code) +{ + die("stack segment",esp,error_code); +} + +void do_coprocessor_error(long esp, long error_code) +{ + if (last_task_used_math != current) + return; + die("coprocessor error",esp,error_code); +} + +void do_reserved(long esp, long error_code) +{ + die("reserved (15,17-47) error",esp,error_code); +} + +void trap_init(void) +{ + int i; + + set_trap_gate(0,÷_error); + set_trap_gate(1,&debug); + set_trap_gate(2,&nmi); + set_system_gate(3,&int3); /* int3-5 can be called from all */ + set_system_gate(4,&overflow); + set_system_gate(5,&bounds); + set_trap_gate(6,&invalid_op); + set_trap_gate(7,&device_not_available); + set_trap_gate(8,&double_fault); + set_trap_gate(9,&coprocessor_segment_overrun); + set_trap_gate(10,&invalid_TSS); + set_trap_gate(11,&segment_not_present); + set_trap_gate(12,&stack_segment); + set_trap_gate(13,&general_protection); + set_trap_gate(14,&page_fault); + set_trap_gate(15,&reserved); + set_trap_gate(16,&coprocessor_error); + set_trap_gate(17,&alignment_check); + for (i=18;i<48;i++) + set_trap_gate(i,&reserved); + set_trap_gate(45,&irq13); + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xdf,0xA1); + set_trap_gate(39,¶llel_interrupt); +} diff --git a/kernel/0.1x/linux-0.12/kernel/vsprintf.c b/kernel/0.1x/linux-0.12/kernel/vsprintf.c new file mode 100644 index 00000000..9bfd010b --- /dev/null +++ b/kernel/0.1x/linux-0.12/kernel/vsprintf.c @@ -0,0 +1,233 @@ +/* + * linux/kernel/vsprintf.c + * + * (C) 1991 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include +#include + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ + +#define do_div(n,base) ({ \ +int __res; \ +__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ +__res; }) + +static char * number(char * str, int num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[36]; + const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + + if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; + if (type&LEFT) type &= ~ZEROPAD; + if (base<2 || base>36) + return 0; + c = (type & ZEROPAD) ? '0' : ' ' ; + if (type&SIGN && num<0) { + sign='-'; + num = -num; + } else + sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); + if (sign) size--; + if (type&SPECIAL) + if (base==16) size -= 2; + else if (base==8) size--; + i=0; + if (num==0) + tmp[i++]='0'; + else while (num!=0) + tmp[i++]=digits[do_div(num,base)]; + if (i>precision) precision=i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type&SPECIAL) + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + if (!(type&LEFT)) + while(size-->0) + *str++ = c; + while(i0) + *str++ = tmp[i]; + while(size-->0) + *str++ = ' '; + return str; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + int i; + char * str; + char *s; + int *ip; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + break; + + case 's': + s = va_arg(args, char *); + len = strlen(s); + if (precision < 0) + precision = len; + else if (len > precision) + len = precision; + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + break; + + case 'o': + str = number(str, va_arg(args, unsigned long), 8, + field_width, precision, flags); + break; + + case 'p': + if (field_width == -1) { + field_width = 8; + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + break; + + case 'x': + flags |= SMALL; + case 'X': + str = number(str, va_arg(args, unsigned long), 16, + field_width, precision, flags); + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + str = number(str, va_arg(args, unsigned long), 10, + field_width, precision, flags); + break; + + case 'n': + ip = va_arg(args, int *); + *ip = (str - buf); + break; + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + break; + } + } + *str = '\0'; + return str-buf; +} diff --git a/kernel/0.1x/linux-0.12/lib/Makefile b/kernel/0.1x/linux-0.12/lib/Makefile new file mode 100644 index 00000000..2bf36663 --- /dev/null +++ b/kernel/0.1x/linux-0.12/lib/Makefile @@ -0,0 +1,73 @@ +# +# Makefile for some libs needed in the kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =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 malloc.o + +lib.a: $(OBJS) + $(AR) rcs lib.a $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +_exit.s _exit.o : _exit.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +close.s close.o : close.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +ctype.s ctype.o : ctype.c ../include/ctype.h +dup.s dup.o : dup.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +errno.s errno.o : errno.c +execve.s execve.o : execve.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +malloc.s malloc.o : malloc.c ../include/linux/kernel.h ../include/linux/mm.h \ + ../include/asm/system.h +open.s open.o : open.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h ../include/stdarg.h +setsid.s setsid.o : setsid.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +string.s string.o : string.c ../include/string.h +wait.s wait.o : wait.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h ../include/sys/wait.h +write.s write.o : write.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h diff --git a/kernel/0.1x/linux-0.12/lib/_exit.c b/kernel/0.1x/linux-0.12/lib/_exit.c new file mode 100644 index 00000000..50f1c8fa --- /dev/null +++ b/kernel/0.1x/linux-0.12/lib/_exit.c @@ -0,0 +1,13 @@ +/* + * linux/lib/_exit.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +volatile void _exit(int exit_code) +{ + __asm__("int $0x80"::"a" (__NR_exit),"b" (exit_code)); +} diff --git a/kernel/0.1x/linux-0.12/lib/close.c b/kernel/0.1x/linux-0.12/lib/close.c new file mode 100644 index 00000000..98e5ceee --- /dev/null +++ b/kernel/0.1x/linux-0.12/lib/close.c @@ -0,0 +1,10 @@ +/* + * linux/lib/close.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall1(int,close,int,fd) diff --git a/kernel/0.1x/linux-0.12/lib/ctype.c b/kernel/0.1x/linux-0.12/lib/ctype.c new file mode 100644 index 00000000..9ac21819 --- /dev/null +++ b/kernel/0.1x/linux-0.12/lib/ctype.c @@ -0,0 +1,35 @@ +/* + * linux/lib/ctype.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +char _ctmp; +unsigned char _ctype[] = {0x00, /* EOF */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */ + diff --git a/kernel/0.1x/linux-0.12/lib/dup.c b/kernel/0.1x/linux-0.12/lib/dup.c new file mode 100644 index 00000000..d56d6d07 --- /dev/null +++ b/kernel/0.1x/linux-0.12/lib/dup.c @@ -0,0 +1,10 @@ +/* + * linux/lib/dup.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall1(int,dup,int,fd) diff --git a/kernel/0.1x/linux-0.12/lib/errno.c b/kernel/0.1x/linux-0.12/lib/errno.c new file mode 100644 index 00000000..b6d10473 --- /dev/null +++ b/kernel/0.1x/linux-0.12/lib/errno.c @@ -0,0 +1,7 @@ +/* + * linux/lib/errno.c + * + * (C) 1991 Linus Torvalds + */ + +int errno; diff --git a/kernel/0.1x/linux-0.12/lib/execve.c b/kernel/0.1x/linux-0.12/lib/execve.c new file mode 100644 index 00000000..67f22cb0 --- /dev/null +++ b/kernel/0.1x/linux-0.12/lib/execve.c @@ -0,0 +1,10 @@ +/* + * linux/lib/execve.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall3(int,execve,const char *,file,char **,argv,char **,envp) diff --git a/kernel/0.1x/linux-0.12/lib/malloc.c b/kernel/0.1x/linux-0.12/lib/malloc.c new file mode 100644 index 00000000..d3df5519 --- /dev/null +++ b/kernel/0.1x/linux-0.12/lib/malloc.c @@ -0,0 +1,232 @@ +/* + * malloc.c --- a general purpose kernel memory allocator for Linux. + * + * Written by Theodore Ts'o (tytso@mit.edu), 11/29/91 + * + * This routine is written to be as fast as possible, so that it + * can be called from the interrupt level. + * + * Limitations: maximum size of memory we can allocate using this routine + * is 4k, the size of a page in Linux. + * + * The general game plan is that each page (called a bucket) will only hold + * objects of a given size. When all of the object on a page are released, + * the page can be returned to the general free pool. When malloc() is + * called, it looks for the smallest bucket size which will fulfill its + * request, and allocate a piece of memory from that bucket pool. + * + * Each bucket has as its control block a bucket descriptor which keeps + * track of how many objects are in use on that page, and the free list + * for that page. Like the buckets themselves, bucket descriptors are + * stored on pages requested from get_free_page(). However, unlike buckets, + * pages devoted to bucket descriptor pages are never released back to the + * system. Fortunately, a system should probably only need 1 or 2 bucket + * descriptor pages, since a page can hold 256 bucket descriptors (which + * corresponds to 1 megabyte worth of bucket pages.) If the kernel is using + * that much allocated memory, it's probably doing something wrong. :-) + * + * Note: malloc() and free() both call get_free_page() and free_page() + * in sections of code where interrupts are turned off, to allow + * malloc() and free() to be safely called from an interrupt routine. + * (We will probably need this functionality when networking code, + * particularily things like NFS, is added to Linux.) However, this + * presumes that get_free_page() and free_page() are interrupt-level + * safe, which they may not be once paging is added. If this is the + * case, we will need to modify malloc() to keep a few unused pages + * "pre-allocated" so that it can safely draw upon those pages if + * it is called from an interrupt routine. + * + * Another concern is that get_free_page() should not sleep; if it + * does, the code is carefully ordered so as to avoid any race + * conditions. The catch is that if malloc() is called re-entrantly, + * there is a chance that unecessary pages will be grabbed from the + * system. Except for the pages for the bucket descriptor page, the + * extra pages will eventually get released back to the system, though, + * so it isn't all that bad. + */ + +#include +#include +#include + +struct bucket_desc { /* 16 bytes */ + void *page; + struct bucket_desc *next; + void *freeptr; + unsigned short refcnt; + unsigned short bucket_size; +}; + +struct _bucket_dir { /* 8 bytes */ + int size; + struct bucket_desc *chain; +}; + +/* + * The following is the where we store a pointer to the first bucket + * descriptor for a given size. + * + * If it turns out that the Linux kernel allocates a lot of objects of a + * specific size, then we may want to add that specific size to this list, + * since that will allow the memory to be allocated more efficiently. + * However, since an entire page must be dedicated to each specific size + * on this list, some amount of temperance must be exercised here. + * + * Note that this list *must* be kept in order. + */ +struct _bucket_dir bucket_dir[] = { + { 16, (struct bucket_desc *) 0}, + { 32, (struct bucket_desc *) 0}, + { 64, (struct bucket_desc *) 0}, + { 128, (struct bucket_desc *) 0}, + { 256, (struct bucket_desc *) 0}, + { 512, (struct bucket_desc *) 0}, + { 1024, (struct bucket_desc *) 0}, + { 2048, (struct bucket_desc *) 0}, + { 4096, (struct bucket_desc *) 0}, + { 0, (struct bucket_desc *) 0}}; /* End of list marker */ + +/* + * This contains a linked list of free bucket descriptor blocks + */ +struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0; + +/* + * This routine initializes a bucket description page. + */ +static inline void init_bucket_desc() +{ + struct bucket_desc *bdesc, *first; + int i; + + first = bdesc = (struct bucket_desc *) get_free_page(); + if (!bdesc) + panic("Out of memory in init_bucket_desc()"); + for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) { + bdesc->next = bdesc+1; + bdesc++; + } + /* + * This is done last, to avoid race conditions in case + * get_free_page() sleeps and this routine gets called again.... + */ + bdesc->next = free_bucket_desc; + free_bucket_desc = first; +} + +void *malloc(unsigned int len) +{ + struct _bucket_dir *bdir; + struct bucket_desc *bdesc; + void *retval; + + /* + * First we search the bucket_dir to find the right bucket change + * for this request. + */ + for (bdir = bucket_dir; bdir->size; bdir++) + if (bdir->size >= len) + break; + if (!bdir->size) { + printk("malloc called with impossibly large argument (%d)\n", + len); + panic("malloc: bad arg"); + } + /* + * Now we search for a bucket descriptor which has free space + */ + cli(); /* Avoid race conditions */ + for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) + if (bdesc->freeptr) + break; + /* + * If we didn't find a bucket with free space, then we'll + * allocate a new one. + */ + if (!bdesc) { + char *cp; + int i; + + if (!free_bucket_desc) + init_bucket_desc(); + bdesc = free_bucket_desc; + free_bucket_desc = bdesc->next; + bdesc->refcnt = 0; + bdesc->bucket_size = bdir->size; + bdesc->page = bdesc->freeptr = (void *) cp = get_free_page(); + if (!cp) + panic("Out of memory in kernel malloc()"); + /* Set up the chain of free objects */ + for (i=PAGE_SIZE/bdir->size; i > 1; i--) { + *((char **) cp) = cp + bdir->size; + cp += bdir->size; + } + *((char **) cp) = 0; + bdesc->next = bdir->chain; /* OK, link it in! */ + bdir->chain = bdesc; + } + retval = (void *) bdesc->freeptr; + bdesc->freeptr = *((void **) retval); + bdesc->refcnt++; + sti(); /* OK, we're safe again */ + return(retval); +} + +/* + * Here is the free routine. If you know the size of the object that you + * are freeing, then free_s() will use that information to speed up the + * search for the bucket descriptor. + * + * We will #define a macro so that "free(x)" is becomes "free_s(x, 0)" + */ +void free_s(void *obj, int size) +{ + void *page; + struct _bucket_dir *bdir; + struct bucket_desc *bdesc, *prev; + + /* Calculate what page this object lives in */ + page = (void *) ((unsigned long) obj & 0xfffff000); + /* Now search the buckets looking for that page */ + for (bdir = bucket_dir; bdir->size; bdir++) { + prev = 0; + /* If size is zero then this conditional is always false */ + if (bdir->size < size) + continue; + for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) { + if (bdesc->page == page) + goto found; + prev = bdesc; + } + } + panic("Bad address passed to kernel free_s()"); +found: + cli(); /* To avoid race conditions */ + *((void **)obj) = bdesc->freeptr; + bdesc->freeptr = obj; + bdesc->refcnt--; + if (bdesc->refcnt == 0) { + /* + * We need to make sure that prev is still accurate. It + * may not be, if someone rudely interrupted us.... + */ + if ((prev && (prev->next != bdesc)) || + (!prev && (bdir->chain != bdesc))) + for (prev = bdir->chain; prev; prev = prev->next) + if (prev->next == bdesc) + break; + if (prev) + prev->next = bdesc->next; + else { + if (bdir->chain != bdesc) + panic("malloc bucket chains corrupted"); + bdir->chain = bdesc->next; + } + free_page((unsigned long) bdesc->page); + bdesc->next = free_bucket_desc; + free_bucket_desc = bdesc; + } + sti(); + return; +} + diff --git a/kernel/0.1x/linux-0.12/lib/open.c b/kernel/0.1x/linux-0.12/lib/open.c new file mode 100644 index 00000000..9b95a8f3 --- /dev/null +++ b/kernel/0.1x/linux-0.12/lib/open.c @@ -0,0 +1,25 @@ +/* + * linux/lib/open.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +int open(const char * filename, int flag, ...) +{ + register int res; + va_list arg; + + va_start(arg,flag); + __asm__("int $0x80" + :"=a" (res) + :"0" (__NR_open),"b" (filename),"c" (flag), + "d" (va_arg(arg,int))); + if (res>=0) + return res; + errno = -res; + return -1; +} diff --git a/kernel/0.1x/linux-0.12/lib/setsid.c b/kernel/0.1x/linux-0.12/lib/setsid.c new file mode 100644 index 00000000..b47a358f --- /dev/null +++ b/kernel/0.1x/linux-0.12/lib/setsid.c @@ -0,0 +1,10 @@ +/* + * linux/lib/setsid.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall0(pid_t,setsid) diff --git a/kernel/0.1x/linux-0.12/lib/string.c b/kernel/0.1x/linux-0.12/lib/string.c new file mode 100644 index 00000000..e4ef9257 --- /dev/null +++ b/kernel/0.1x/linux-0.12/lib/string.c @@ -0,0 +1,14 @@ +/* + * linux/lib/string.c + * + * (C) 1991 Linus Torvalds + */ + +#ifndef __GNUC__ +#error I want gcc! +#endif + +#define extern +#define inline +#define __LIBRARY__ +#include diff --git a/kernel/0.1x/linux-0.12/lib/wait.c b/kernel/0.1x/linux-0.12/lib/wait.c new file mode 100644 index 00000000..72f27313 --- /dev/null +++ b/kernel/0.1x/linux-0.12/lib/wait.c @@ -0,0 +1,16 @@ +/* + * linux/lib/wait.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +_syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) + +pid_t wait(int * wait_stat) +{ + return waitpid(-1,wait_stat,0); +} diff --git a/kernel/0.1x/linux-0.12/lib/write.c b/kernel/0.1x/linux-0.12/lib/write.c new file mode 100644 index 00000000..68ea9cf9 --- /dev/null +++ b/kernel/0.1x/linux-0.12/lib/write.c @@ -0,0 +1,10 @@ +/* + * linux/lib/write.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall3(int,write,int,fd,const char *,buf,off_t,count) diff --git a/kernel/0.1x/linux-0.12/mm/Makefile b/kernel/0.1x/linux-0.12/mm/Makefile new file mode 100644 index 00000000..dadc8b04 --- /dev/null +++ b/kernel/0.1x/linux-0.12/mm/Makefile @@ -0,0 +1,44 @@ +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 swap.o page.o + +all: mm.o + +mm.o: $(OBJS) + $(LD) -r -o mm.o $(OBJS) + +clean: + rm -f core *.o *.a tmp_make + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +memory.o : memory.c ../include/signal.h ../include/sys/types.h \ + ../include/asm/system.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h +swap.o : swap.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/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h diff --git a/kernel/0.1x/linux-0.12/mm/memory.c b/kernel/0.1x/linux-0.12/mm/memory.c new file mode 100644 index 00000000..7a157ce7 --- /dev/null +++ b/kernel/0.1x/linux-0.12/mm/memory.c @@ -0,0 +1,502 @@ +/* + * linux/mm/memory.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * demand-loading started 01.12.91 - seems it is high on the list of + * things wanted, and it should be easy to implement. - Linus + */ + +/* + * Ok, demand-loading was easy, shared pages a little bit tricker. Shared + * pages started 02.12.91, seems to work. - Linus. + * + * Tested sharing by executing about 30 /bin/sh: under the old kernel it + * would have taken more than the 6M I have free, but it worked well as + * far as I could see. + * + * Also corrected some "invalidate()"s - I wasn't doing enough of them. + */ + +/* + * Real VM (paging to/from disk) started 18.12.91. Much more work and + * thought has to go into this. Oh, well.. + * 19.12.91 - works, somewhat. Sometimes I get faults, don't know why. + * Found it. Everything seems to work now. + * 20.12.91 - Ok, making the swap-device changeable like the root. + */ + +#include + +#include + +#include +#include +#include + +#define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \ +current->start_code + current->end_code) + +unsigned long HIGH_MEMORY = 0; + +#define copy_page(from,to) \ +__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si") + +unsigned char mem_map [ PAGING_PAGES ] = {0,}; + +/* + * 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 (*pg_table) { + if (1 & *pg_table) + free_page(0xfffff000 & *pg_table); + else + swap_free(*pg_table >> 1); + *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 new_page; + 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 (!this_page) + continue; + if (!(1 & this_page)) { + if (!(new_page = get_free_page())) + return -1; + read_swap_page(this_page>>1, (char *) new_page); + *to_page_table = this_page; + *from_page_table = new_page | (PAGE_DIRTY | 7); + 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.) + */ +static unsigned long put_page(unsigned long page,unsigned long address) +{ + unsigned long tmp, *page_table; + +/* NOTE !!! This uses the fact that _pg_dir=0 */ + + if (page < LOW_MEM || page >= HIGH_MEMORY) + printk("Trying to put page %p at %p\n",page,address); + if (mem_map[(page-LOW_MEM)>>12] != 1) + printk("mem_map disagrees with %p at %p\n",page,address); + page_table = (unsigned long *) ((address>>20) & 0xffc); + if ((*page_table)&1) + page_table = (unsigned long *) (0xfffff000 & *page_table); + else { + if (!(tmp=get_free_page())) + return 0; + *page_table = tmp | 7; + page_table = (unsigned long *) tmp; + } + page_table[(address>>12) & 0x3ff] = page | 7; +/* no need for invalidate */ + return page; +} + +/* + * The previous function doesn't work very well if you also want to mark + * the page dirty: exec.c wants this, as it has earlier changed the page, + * and we want the dirty-status to be correct (for VM). Thus the same + * routine, but this time we mark it dirty too. + */ +unsigned long put_dirty_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 | (PAGE_DIRTY | 7); +/* no need for invalidate */ + return page; +} + +void un_wp_page(unsigned long * table_entry) +{ + unsigned long old_page,new_page; + + old_page = 0xfffff000 & *table_entry; + if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) { + *table_entry |= 2; + invalidate(); + return; + } + if (!(new_page=get_free_page())) + oom(); + if (old_page >= LOW_MEM) + mem_map[MAP_NR(old_page)]--; + copy_page(old_page,new_page); + *table_entry = new_page | 7; + invalidate(); +} + +/* + * This routine handles present pages, when users try to write + * to a shared page. It is done by copying the page to a new address + * and decrementing the shared-page counter for the old page. + * + * If it's in code space we exit with a segment error. + */ +void do_wp_page(unsigned long error_code,unsigned long address) +{ + if (address < TASK_SIZE) + printk("\n\rBAD! KERNEL MEMORY WP-ERR!\n\r"); + if (address - current->start_code > TASK_SIZE) { + printk("Bad things happen: page error in do_wp_page\n\r"); + do_exit(SIGSEGV); + } +#if 0 +/* we cannot do this yet: the estdio library writes to code space */ +/* stupid, stupid. I really want the libc.a from GNU */ + if (CODE_SPACE(address)) + do_exit(SIGSEGV); +#endif + un_wp_page((unsigned long *) + (((address>>10) & 0xffc) + (0xfffff000 & + *((unsigned long *) ((address>>20) &0xffc))))); + +} + +void write_verify(unsigned long address) +{ + unsigned long page; + + if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1)) + return; + page &= 0xfffff000; + page += ((address>>10) & 0xffc); + if ((3 & *(unsigned long *) page) == 1) /* non-writeable, present */ + un_wp_page((unsigned long *) page); + return; +} + +void get_empty_page(unsigned long address) +{ + unsigned long tmp; + + if (!(tmp=get_free_page()) || !put_page(tmp,address)) { + free_page(tmp); /* 0 is ok - ignored */ + oom(); + } +} + +/* + * try_to_share() checks the page at address "address" in the task "p", + * to see if it exists, and if it is clean. If so, share it with the current + * task. + * + * NOTE! This assumes we have checked that p != current, and that they + * share the same executable or library. + */ +static int try_to_share(unsigned long address, struct task_struct * p) +{ + unsigned long from; + unsigned long to; + unsigned long from_page; + unsigned long to_page; + unsigned long phys_addr; + + from_page = to_page = ((address>>20) & 0xffc); + from_page += ((p->start_code>>20) & 0xffc); + to_page += ((current->start_code>>20) & 0xffc); +/* is there a page-directory at from? */ + from = *(unsigned long *) from_page; + if (!(from & 1)) + return 0; + from &= 0xfffff000; + from_page = from + ((address>>10) & 0xffc); + phys_addr = *(unsigned long *) from_page; +/* is the page clean and present? */ + if ((phys_addr & 0x41) != 0x01) + return 0; + phys_addr &= 0xfffff000; + if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM) + return 0; + to = *(unsigned long *) to_page; + if (!(to & 1)) + if (to = get_free_page()) + *(unsigned long *) to_page = to | 7; + else + oom(); + to &= 0xfffff000; + to_page = to + ((address>>10) & 0xffc); + if (1 & *(unsigned long *) to_page) + panic("try_to_share: to_page already exists"); +/* share them: write-protect */ + *(unsigned long *) from_page &= ~2; + *(unsigned long *) to_page = *(unsigned long *) from_page; + invalidate(); + phys_addr -= LOW_MEM; + phys_addr >>= 12; + mem_map[phys_addr]++; + return 1; +} + +/* + * share_page() tries to find a process that could share a page with + * the current one. Address is the address of the wanted page relative + * to the current data space. + * + * We first check if it is at all feasible by checking executable->i_count. + * It should be >1 if there are other tasks sharing this inode. + */ +static int share_page(struct m_inode * inode, unsigned long address) +{ + struct task_struct ** p; + + if (inode->i_count < 2 || !inode) + return 0; + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if (!*p) + continue; + if (current == *p) + continue; + if (address < LIBRARY_OFFSET) { + if (inode != (*p)->executable) + continue; + } else { + if (inode != (*p)->library) + continue; + } + if (try_to_share(address,*p)) + return 1; + } + return 0; +} + +void do_no_page(unsigned long error_code,unsigned long address) +{ + int nr[4]; + unsigned long tmp; + unsigned long page; + int block,i; + struct m_inode * inode; + + if (address < TASK_SIZE) + printk("\n\rBAD!! KERNEL PAGE MISSING\n\r"); + if (address - current->start_code > TASK_SIZE) { + printk("Bad things happen: nonexistent page error in do_no_page\n\r"); + do_exit(SIGSEGV); + } + page = *(unsigned long *) ((address >> 20) & 0xffc); + if (page & 1) { + page &= 0xfffff000; + page += (address >> 10) & 0xffc; + tmp = *(unsigned long *) page; + if (tmp && !(1 & tmp)) { + swap_in((unsigned long *) page); + return; + } + } + address &= 0xfffff000; + tmp = address - current->start_code; + if (tmp >= LIBRARY_OFFSET ) { + inode = current->library; + block = 1 + (tmp-LIBRARY_OFFSET) / BLOCK_SIZE; + } else if (tmp < current->end_data) { + inode = current->executable; + block = 1 + tmp / BLOCK_SIZE; + } else { + inode = NULL; + block = 0; + } + if (!inode) { + get_empty_page(address); + return; + } + if (share_page(inode,tmp)) + return; + if (!(page = get_free_page())) + oom(); +/* remember that 1 block is used for header */ + for (i=0 ; i<4 ; block++,i++) + nr[i] = bmap(inode,block); + bread_page(page,inode->i_dev,nr); + i = tmp + 4096 - current->end_data; + if (i>4095) + i = 0; + tmp = page + 4096; + while (i-- > 0) { + tmp--; + *(char *)tmp = 0; + } + if (put_page(page,address)) + return; + free_page(page); + oom(); +} + +void mem_init(long start_mem, long end_mem) +{ + int i; + + HIGH_MEMORY = end_mem; + for (i=0 ; i>= 12; + while (end_mem-->0) + mem_map[i++]=0; +} + +void show_mem(void) +{ + int i,j,k,free=0,total=0; + int shared=0; + unsigned long * pg_tbl; + + printk("Mem-info:\n\r"); + for(i=0 ; iHIGH_MEMORY) { + printk("page directory[%d]: %08X\n\r", + i,pg_dir[i]); + continue; + } + if (pg_dir[i]>LOW_MEM) + free++,k++; + pg_tbl=(unsigned long *) (0xfffff000 & pg_dir[i]); + for(j=0 ; j<1024 ; j++) + if ((pg_tbl[j]&1) && pg_tbl[j]>LOW_MEM) + if (pg_tbl[j]>HIGH_MEMORY) + printk("page_dir[%d][%d]: %08X\n\r", + i,j, pg_tbl[j]); + else + k++,free++; + } + i++; + if (!(i&15) && k) { + k++,free++; /* one page/process for task_struct */ + printk("Process %d: %d pages\n\r",(i>>4)-1,k); + k = 0; + } + } + printk("Memory found: %d (%d)\n\r",free-shared,total); +} diff --git a/kernel/0.1x/linux-0.12/mm/page.s b/kernel/0.1x/linux-0.12/mm/page.s new file mode 100644 index 00000000..4808f5bc --- /dev/null +++ b/kernel/0.1x/linux-0.12/mm/page.s @@ -0,0 +1,40 @@ +/* + * linux/mm/page.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * 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/kernel/0.1x/linux-0.12/mm/swap.c b/kernel/0.1x/linux-0.12/mm/swap.c new file mode 100644 index 00000000..5d34a07a --- /dev/null +++ b/kernel/0.1x/linux-0.12/mm/swap.c @@ -0,0 +1,253 @@ +/* + * linux/mm/swap.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This file should contain most things doing the swapping from/to disk. + * Started 18.12.91 + */ + +#include + +#include +#include +#include +#include + +#define SWAP_BITS (4096<<3) + +#define bitop(name,op) \ +static inline int name(char * addr,unsigned int nr) \ +{ \ +int __res; \ +__asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \ +:"=g" (__res) \ +:"r" (nr),"m" (*(addr)),"0" (0)); \ +return __res; \ +} + +bitop(bit,"") +bitop(setbit,"s") +bitop(clrbit,"r") + +static char * swap_bitmap = NULL; +int SWAP_DEV = 0; + +/* + * We never page the pages in task[0] - kernel memory. + * We page all other pages. + */ +#define FIRST_VM_PAGE (TASK_SIZE>>12) +#define LAST_VM_PAGE (1024*1024) +#define VM_PAGES (LAST_VM_PAGE - FIRST_VM_PAGE) + +static int get_swap_page(void) +{ + int nr; + + if (!swap_bitmap) + return 0; + for (nr = 1; nr < 32768 ; nr++) + if (clrbit(swap_bitmap,nr)) + return nr; + return 0; +} + +void swap_free(int swap_nr) +{ + if (!swap_nr) + return; + if (swap_bitmap && swap_nr < SWAP_BITS) + if (!setbit(swap_bitmap,swap_nr)) + return; + printk("Swap-space bad (swap_free())\n\r"); + return; +} + +void swap_in(unsigned long *table_ptr) +{ + int swap_nr; + unsigned long page; + + if (!swap_bitmap) { + printk("Trying to swap in without swap bit-map"); + return; + } + if (1 & *table_ptr) { + printk("trying to swap in present page\n\r"); + return; + } + swap_nr = *table_ptr >> 1; + if (!swap_nr) { + printk("No swap page in swap_in\n\r"); + return; + } + if (!(page = get_free_page())) + oom(); + read_swap_page(swap_nr, (char *) page); + if (setbit(swap_bitmap,swap_nr)) + printk("swapping in multiply from same page\n\r"); + *table_ptr = page | (PAGE_DIRTY | 7); +} + +int try_to_swap_out(unsigned long * table_ptr) +{ + unsigned long page; + unsigned long swap_nr; + + page = *table_ptr; + if (!(PAGE_PRESENT & page)) + return 0; + if (page - LOW_MEM > PAGING_MEMORY) + return 0; + if (PAGE_DIRTY & page) { + page &= 0xfffff000; + if (mem_map[MAP_NR(page)] != 1) + return 0; + if (!(swap_nr = get_swap_page())) + return 0; + *table_ptr = swap_nr<<1; + invalidate(); + write_swap_page(swap_nr, (char *) page); + free_page(page); + return 1; + } + *table_ptr = 0; + invalidate(); + free_page(page); + return 1; +} + +/* + * Ok, this has a rather intricate logic - the idea is to make good + * and fast machine code. If we didn't worry about that, things would + * be easier. + */ +int swap_out(void) +{ + static int dir_entry = FIRST_VM_PAGE>>10; + static int page_entry = -1; + int counter = VM_PAGES; + int pg_table; + + while (counter>0) { + pg_table = pg_dir[dir_entry]; + if (pg_table & 1) + break; + counter -= 1024; + dir_entry++; + if (dir_entry >= 1024) + dir_entry = FIRST_VM_PAGE>>10; + } + pg_table &= 0xfffff000; + while (counter-- > 0) { + page_entry++; + if (page_entry >= 1024) { + page_entry = 0; + repeat: + dir_entry++; + if (dir_entry >= 1024) + dir_entry = FIRST_VM_PAGE>>10; + pg_table = pg_dir[dir_entry]; + if (!(pg_table&1)) + if ((counter -= 1024) > 0) + goto repeat; + else + break; + pg_table &= 0xfffff000; + } + if (try_to_swap_out(page_entry + (unsigned long *) pg_table)) + return 1; + } + printk("Out of swap-memory\n\r"); + return 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"); + +repeat: + __asm__("std ; repne ; scasb\n\t" + "jne 1f\n\t" + "movb $1,1(%%edi)\n\t" + "sall $12,%%ecx\n\t" + "addl %2,%%ecx\n\t" + "movl %%ecx,%%edx\n\t" + "movl $1024,%%ecx\n\t" + "leal 4092(%%edx),%%edi\n\t" + "rep ; stosl\n\t" + "movl %%edx,%%eax\n" + "1:" + :"=a" (__res) + :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES), + "D" (mem_map+PAGING_PAGES-1) + :"di","cx","dx"); + if (__res >= HIGH_MEMORY) + goto repeat; + if (!__res && swap_out()) + goto repeat; + return __res; +} + +void init_swapping(void) +{ + extern int *blk_size[]; + int swap_size,i,j; + + if (!SWAP_DEV) + return; + if (!blk_size[MAJOR(SWAP_DEV)]) { + printk("Unable to get size of swap device\n\r"); + return; + } + swap_size = blk_size[MAJOR(SWAP_DEV)][MINOR(SWAP_DEV)]; + if (!swap_size) + return; + if (swap_size < 100) { + printk("Swap device too small (%d blocks)\n\r",swap_size); + return; + } + swap_size >>= 2; + if (swap_size > SWAP_BITS) + swap_size = SWAP_BITS; + swap_bitmap = (char *) get_free_page(); + if (!swap_bitmap) { + printk("Unable to start swapping: out of memory :-)\n\r"); + return; + } + read_swap_page(0,swap_bitmap); + if (strncmp("SWAP-SPACE",swap_bitmap+4086,10)) { + printk("Unable to find swap-space signature\n\r"); + free_page((long) swap_bitmap); + swap_bitmap = NULL; + return; + } + memset(swap_bitmap+4086,0,10); + for (i = 0 ; i < SWAP_BITS ; i++) { + if (i == 1) + i = swap_size; + if (bit(swap_bitmap,i)) { + printk("Bad swap-space bit-map\n\r"); + free_page((long) swap_bitmap); + swap_bitmap = NULL; + return; + } + } + j = 0; + for (i = 1 ; i < swap_size ; i++) + if (bit(swap_bitmap,i)) + j++; + if (!j) { + free_page((long) swap_bitmap); + swap_bitmap = NULL; + return; + } + printk("Swap device ok: %d pages (%d bytes) swap-space\n\r",j,j*4096); +} diff --git a/kernel/0.1x/linux-0.12/tools/build.c b/kernel/0.1x/linux-0.12/tools/build.c new file mode 100644 index 00000000..a36c1c11 --- /dev/null +++ b/kernel/0.1x/linux-0.12/tools/build.c @@ -0,0 +1,198 @@ +/* + * linux/tools/build.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This file builds a disk-image from three different files: + * + * - bootsect: max 510 bytes of 8086 machine code, loads the rest + * - setup: max 4 sectors of 8086 machine code, sets up system parm + * - system: 80386 code for actual system + * + * It does some checking that all files are of the correct type, and + * just writes the result to stdout, removing headers and padding to + * the right amount. It also writes some system data to stderr. + */ + +/* + * Changes by tytso to allow root device specification + * + * Added swap-device specification: Linux 20.12.91 + */ + +#include /* fprintf */ +#include +#include /* contains exit */ +#include /* unistd.h needs this */ +#include +#include +#include /* contains read/write */ +#include + +#define MINIX_HEADER 32 +#define GCC_HEADER 1024 + +#define SYS_SIZE 0x3000 + +#define DEFAULT_MAJOR_ROOT 3 +#define DEFAULT_MINOR_ROOT 6 + +#define DEFAULT_MAJOR_SWAP 0 +#define DEFAULT_MINOR_SWAP 0 + +/* max nr of sectors of setup: don't change unless you also change + * bootsect etc */ +#define SETUP_SECTS 4 + +#define STRINGIFY(x) #x + +void die(char * str) +{ + fprintf(stderr,"%s\n",str); + exit(1); +} + +void usage(void) +{ + die("Usage: build bootsect setup system [rootdev] [> image]"); +} + +int main(int argc, char ** argv) +{ + int i,c,id; + char buf[1024]; + char major_root, minor_root; + char major_swap, minor_swap; + struct stat sb; + + if ((argc < 4) || (argc > 6)) + usage(); + if (argc > 4) { + if (strcmp(argv[4], "FLOPPY")) { + if (stat(argv[4], &sb)) { + perror(argv[4]); + die("Couldn't stat root device."); + } + major_root = MAJOR(sb.st_rdev); + minor_root = MINOR(sb.st_rdev); + } else { + major_root = 0; + minor_root = 0; + } + } else { + major_root = DEFAULT_MAJOR_ROOT; + minor_root = DEFAULT_MINOR_ROOT; + } + if (argc == 6) { + if (strcmp(argv[5], "NONE")) { + if (stat(argv[5], &sb)) { + perror(argv[5]); + die("Couldn't stat root device."); + } + major_swap = MAJOR(sb.st_rdev); + minor_swap = MINOR(sb.st_rdev); + } else { + major_swap = 0; + minor_swap = 0; + } + } else { + major_swap = DEFAULT_MAJOR_SWAP; + minor_swap = DEFAULT_MINOR_SWAP; + } + fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); + fprintf(stderr, "Swap device is (%d, %d)\n", major_swap, minor_swap); + if ((major_root != 2) && (major_root != 3) && + (major_root != 0)) { + fprintf(stderr, "Illegal root device (major = %d)\n", + major_root); + die("Bad root device --- major #"); + } + if (major_swap && major_swap != 3) { + fprintf(stderr, "Illegal swap device (major = %d)\n", + major_swap); + die("Bad root device --- major #"); + } + for (i=0;i0 ; i+=c ) + if (write(1,buf,c)!=c) + die("Write call failed"); + close (id); + if (i > SETUP_SECTS*512) + die("Setup exceeds " STRINGIFY(SETUP_SECTS) + " sectors - rewrite build/boot/setup"); + fprintf(stderr,"Setup is %d bytes.\n",i); + for (c=0 ; c sizeof(buf)) + c = sizeof(buf); + if (write(1,buf,c) != c) + die("Write call failed"); + i += c; + } + + if ((id=open(argv[3],O_RDONLY,0))<0) + die("Unable to open 'system'"); + if (read(id,buf,GCC_HEADER) != GCC_HEADER) + die("Unable to read header of 'system'"); + if (((long *) buf)[5] != 0) + die("Non-GCC header of 'system'"); + for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c ) + if (write(1,buf,c)!=c) + die("Write call failed"); + close(id); + fprintf(stderr,"System is %d bytes.\n",i); + if (i > SYS_SIZE*16) + die("System is too big"); + return(0); +} diff --git a/kernel/0.95/README b/kernel/0.95/README new file mode 100644 index 00000000..458c23e2 --- /dev/null +++ b/kernel/0.95/README @@ -0,0 +1,55 @@ +To: Linux-Activists@BLOOM-PICAYUNE.MIT.EDU +From: torvalds@klaava.Helsinki.FI (Linus Benedict Torvalds) +Crossposted-To: alt.os.linux +Subject: Second 0.95a alpha-patch, part 1/2 +Date: 4 Apr 92 14:42:10 GMT + +This is the promised patch to 0.95a, which hopefully corrects some of +the problems encountered. This is /not/ an offical new release: it's +just a set of patches to get the same kernel I am currently running. + +Bugfixes: + +- extended partitions should finally work correctly (this release also + contains code for the hd-ioctl call, needed for fdisk). Code mostly + by hedrick. + +- I corrected my original ptrace-fix (writing a long word to another + process' data space could fail with my original patches) + +- 387-emulation bug with the instructions "fcom[p] %st(x)" which + resulted in bad results on non-387 machines with newer versions of + gcc. The emulation is still ugly, but it seems to work. + +- the cooked mode deletion/linekill bugs should be fixed. + +- various error-returns were wrong: I correted some of them (thanks to + bruce evans who pointed them out). The bad error-values resulted in + incorrect or spurious error-messages from 'rm' etc. + +- various minor fixes (including some in the hd-driver: this might help + persons with unexpected-interrupt and/or timeout errors) + +Additionally this version contains VFS-code from entropy, and a +readdir() system call needed for the VFS. The latter was inspired by +patches sent by Remy Card, who did it with a getdirents sys-call. My +version is slightly simpler, but is probably slower. Things might yet +change. + +The installation has also changed slightly: the keyboard type and +math-emulation are specified in the main Makefile. That one also +contains the -fcombine-regs flag needed for 1.40. The other makefiles +should no longer need editing. + +I've also incorporated the ps095 kernel patches: to get the actual +user-level stuff you still have to get the ps-distribution. Printer +ports /still/ aren't in there, but this time I positively /promise/ to +put it in next week. Really. + +People who have been patching their kernel might have problems getting +this patch to work: it was made against a clean 0.95a kernel. I'll +consider a patched-up kernel version 0.95c - and I'd appreciate if +future patches to me would be sent against this version. I'll still +accept older patches, or course. + + Linus diff --git a/kernel/0.95/RELNOTES-0.95 b/kernel/0.95/RELNOTES-0.95 new file mode 100644 index 00000000..c97f5e4c --- /dev/null +++ b/kernel/0.95/RELNOTES-0.95 @@ -0,0 +1,265 @@ + + + RELEASE NOTES FOR LINUX v0.95 + Linus Torvalds, March 7, 1992 + + +This is file mostly contains info on changed features of Linux, and +using old versions as a help-reference might be a good idea. + + + COPYRIGHT + +Linux-0.95 is NOT public domain software, but is copyrighted by me. The +copyright conditions are the same as those imposed by the GNU copyleft: +get a copy of the GNU copyleft at any major ftp-site (if it carries +linux, it probably carries a lot of GNU software anyway, and they all +contain the copyright). + +The copyleft is pretty detailed, but it mostly just means that you may +freely copy linux for your own use, and redistribute all/parts of it, as +long as you make source available (not necessarily in the same +distribution, but you make it clear how people can get it for nothing +more than copying costs). Any changes you make that you distribute will +also automatically fall under the GNU copyleft. + +NOTE! The linux unistd library-functions (the low-level interface to +linux: system calls etc) are excempt from the copyright - you may use +them as you wish, and using those in your binary files won't mean that +your files are automatically under the GNU copyleft. This concerns +/only/ the unistd-library and those (few) other library functions I have +written: most of the rest of the library has it's own copyrights (or is +public domain). See the library sources for details of those. + + + INSTALLATION + +This is a SHORT install-note. The installation is very similar to 0.11 +and 0.12, so you should read INSTALL-0.11 too. There are a couple of +programs you will need to install linux: something that writes disk +images (rawrite.exe or NU or...) and something that can create harddisk +partitions (fdisk under xenix or older versions of dos, edpart.exe or +something like that). + +NOTE! Repartitioning your harddisk will destroy all data on it (well, +not exactly, but if you know enough to get back the data you probably +didn't need this warning). So be careful. + +READ THIS THROUGH, THEN READ INSTALL-0.11, AND IF YOU ARE SURE YOU KNOW +WHAT YOU ARE DOING, CONTINUE. OTHERWISE, PANIC. OR WRITE ME FOR +EXPLANATIONS. OR DO ANYTHING BUT INSTALL LINUX - IT'S VERY SIMPLE, BUT +IF YOU DON'T KNOW WHAT YOU ARE DOING YOU'LL PROBABLY BE SORRY. I'D +RATHER ANSWER A FEW UNNECESSARY MAILS THAN GET MAIL SAYING "YOU KILLED +MY HARDDISK, BASTARD. I'M GOING TO FIND YOU, AND YOU'LL BE SORRY WHEN I +DO". + +Minumum files needed: + + RELNOTES-0.95 (this file) + INSTALL-0.11 (+ any other docs you might find: the FAQ etc) + bootimage-0.96.Z + rootimage-0.95.Z + rootimage-0.12.Z (for tar+compress) + rawrite.exe + some disk partitioner + +1) back up everything you have on your harddisk - linux-0.95 is still in + beta and might do weird things. The only thing I guarantee is that + it has worked fine on /my/ machine - for all I know it might eat your + harddisk and spit it out in small pieces on any other hardware. + +2) Test out the linux boot-disk with the root file system. If it + doesn't work, check the hardware requirements, and mail me if you + still think it should work. I might not be able to help you, but + your bug-report would still be appreciated. + + Linux-0.95 now has an init/login: there should be 4 logins started on + the first 4 virtual consoles. Log in as root (no password), and test + it out. Change to the other logins by pressing left-alt + FN[1-4]. + Note that booting up with a floppy as root is S..L..O..W.. - the + floppy driver has been optimized for sequential access (backups etc), + and trashes somewhat with demand-loading. + + Test that linux can read your harddisk at least partly: run the fdisk + program on the root-disk, and see if it barfs. If it tells you about + any partitions at all, linux can successfully read at least part of + your harddisk. + + NOTE! Harddisk device names and numbers have changed between versions + 0.12 and 0.95: the new numbering system was needed for the extended + partitions, and a new naming scheme was in order so that people + wouldn't cunfuse the old devices with the new ones. + + The new harddisk device names are: /dev/hd followed by an 'a' for the + first drive, or a 'b' for the second one. After that comes the + partition number, 1-4 for the primary partitions, 5- for possible + extended partitions. No number means the complete disk. Like this: + + /dev/hda the whole first harddisk (old: /dev/hd0) + /dev/hdb3 partition nr 3 on the second disk (old: /dev/hd8) + +3) Make sure that you have a free /primary/ partition. There can be 4 + primary partitions per drive: newer DOS fdisks seem to be able to + create only 2 (one primary and one extended). In that case use some + other partitioning software: edpart.exe etc. Linux fdisk currently + only tells you the partition info - it doesn't write to the disk. + + Remember to check how big your partition was, as that can be used to + tell which device Linux thinks it is. + + NOTE! Linux-0.95 /might/ recognize extended partitions: but the code + for this is utterly untested, as I don't have any of those. Do NOT + use the extended partitions unless you can verify that they are + indeed correctly set up - if my routines are wrong, writing to the + extended partitions might just overwrite some other partition + instead. Not nice. + +4) Boot up linux again, fdisk to make sure you now have the new + partition, and use mkfs to make a filesystem on one of the partitions + fdisk reports. Write "mkfs -c /dev/hdX nnn" where X is the device + number reported by linux fdisk, and nnn is the size - also reported + by fdisk. nnn is the size in /blocks/, ie kilobytes. You should be + able to use the size info to determine which partition is represented + by which device name. + +5) Mount the new disk partition: "mount /dev/hdX /mnt". Copy over the + root filesystem to the harddisk, eg like this: + + # for i in bin dev etc usr tmp + # do + # cp +recursive /$i /mnt + # done + + You caanot use just "cp +recursive / /mnt", as that will result in a + loop. + +6) Sync the filesystem after you have played around enough, and reboot. + + # sync + # lo + + (none) login: sync + + ctrl-alt-del + + THIS IS IMPORTANT! NEVER EVER FORGET TO SYNC BEFORE KILLING THE MACHINE. + +7) Change the bootdisk to understand which partition it should use as a + root filesystem. See INSTALL-0.11: it's still the word at offset + 508 into the image. You should be up and running. + + +8) When you've successfully started up with your harddisk as root, you + can mount the older rootimage (rootimage-0.12) from a floppy, and + copy over any files you find there that weren't on the newer + root-image. + + Mounting a floppy is easy: make the directory /floppy, and write: + + # mount /dev/PS0 /floppy (if you have a 3.5" drive) + + or + + # mount /dev/at0 /floppy (for 5.25" floppies) + + After that the files can be copied to your harddisk, eg: + + # cp /floppy/usr/bin/compress /usr/bin + # ln -s /usr/bin/compress /usr/bin/compress + # cp /floppy/usr/bin/tar.Z /usr/bin + # uncompress /usr/bin/tar.Z + +That's it. Now go back and read the INSTALL-0.11, until you are sure you +know what you are doing. + + + New features of 0.95, in order of appearance + (ie in the order you see them) + + Init/login + +Yeah, thanks to poe (Peter Orbaeck (sp?)), linux now boots up like a +real unix with a login-prompt. Login as root (no passwd), and change +your /etc/passwd to your hearts delight (and add other logins in +/etc/inittab etc). + + Bash is even bigger + +It's really a bummer to boot up from floppies: bash takes a long time to +load. Bash is also now so big that I couldn't fit compress and tar onto +the root-floppy: You'll probably want the old rootimage-0.12 just in +order to get tar+compress onto your harddisk. If anybody has pointers +to a simple shell that is freely distributable, it might be a good idea +to use that for the root-diskette. + +Especially with a small buffer-cache, things aren't fun. Don't worry: +linux runs much better on a harddisk. + + Virtual consoles on any (?) hardware. + +You can select one of several consoles by pressing the left alt-key and +a function key at the same time. Linux should report the number of +virtual consoles available upon bootup. /dev/tty0 is now "the current" +screen, /dev/tty1 is the main console, and /dev/tty2-8 can exist +depending on your text-mode or card. + +The virtual consoles also have some new screen-handling commands: they +confirm even better to vt200 control codes than 0.11. Special graphic +characters etc: you can well use them as terminals to VMS (although +that's a shameful waste of resources), and the PF1-4 keys work somewhat +in the application-key mode. + + Symbolic links. + +0.95 now allows symlinks to point to other symlinks etc (the maximum +depth is a rather arbitrary 5 links). 0.12 didn't like more than one +level of indirection. + + Virtual memory. + +VM under 0.95 should be better than under 0.12: no more lockups (as far +as I have seen), and you can now swap to the filesystem as well as to a +special partition. There are two programs to handle this: mkswap to set +up a swap-file/partition and swapon to start up swapping. + +mkswap needs either a partition or a file that already exists to make a +swap-area. To make a swap-file, do this: + + # dd bs=1024 count=NN if=/dev/hda of=swapfile + # mkswap swapfile NN + +The first command just makes a file that is NN blocks long (initializing +it from /dev/hda, but that could be anything). The second command then +writes the necessary setup-info into the file. To start swapping, write + + # swapon swapfile + +NOTE! 'dd' isn't on the rootdisk: you have to install some things onto +the harddisk before you can get up and running. + +NOTE2! When linux runs totally out of virtual memory, things slow down +dramatically. It tries to keep on running as long as it can, but at +least it shouldn't lock up any more. ^C should work, although you might +have to wait a while for it.. + + Faster floppies + +Ok, you don't notice this much when booting up from a floppy: bash has +grown, so it takes longer to load, and the optimizations work mostly +with sequential accesses. When you start un-taring floppies to get the +programs onto your harddisk, you'll notice that it's much faster now. +That should be about the only use for floppies under a unix: nobody in +their right mind uses floppies as filesystems. + + Better FS-independence + +Hopefully you'll never even notice this, but the filesystem has been +partly rewritten to make it less minix-fs-specific. I haven't +implemented all the VFS-patches I got, so it's still not ready, but it's +getting there, slowly. + + And that's it, I think. + +Happy hacking. + + Linus (torvalds@kruuna.helsinki.fi) diff --git a/kernel/0.95/RELNOTES-0.95a b/kernel/0.95/RELNOTES-0.95a new file mode 100644 index 00000000..c69cb412 --- /dev/null +++ b/kernel/0.95/RELNOTES-0.95a @@ -0,0 +1,148 @@ +Please FIRST read the RELNOTES-0.95 file, then read this. This is only +a listing of the differences between this release and the last. [-mkj] + +CHANGES IN THE LINUX v0.95a ROOT DISKETTE +Jim Winstead Jr. - March 17, 1992 + +This file mostly contains info about the changes in the root diskette +from Linux v0.95/0.12 to Linux v0.95a. + +CHANGES + +With the release of Linux v0.95a, the maintenance of the root diskette +has been assumed by Jim Winstead Jr. (jwinstea@jarthur.Claremont.EDU). +This means there are a few large changes between the Linux 0.95 and +0.12 root floppies and the Linux 0.95a root floppy. These are +detailed (as much as I remember them) below: + +- 'bash' has been replaced with 'ash', the BSD 4.3 /bin/sh. This + freed up nearly 200k on the root floppy. However, there are + some problems with 'ash' that haven't been resolved: + + - sometimes the backspace key will not work on a virtual + console. I've found that it usually works on all _but_ one + console, so this is only a minor hinderance. + + - 'ash 'supports BSD-style job control, and this has not yet been + adapted to Linux's more POSIXish job control. This means + that 'ash' does not yet support job control, but it's being + worked upon. + +- 'tar' and 'compress' are back on the root floppy. 'tar' is + compressed, and both utilities are in /bin. + +- 'pfdisk', a disk partitioner, was added to the root floppy. + This makes it (almost) possible to install Linux on a machine + without looking at another OS. + +- the file pager 'more' has been added to the floppy. This was + added because of the addition of some documentation files on + the root floppy. + +- 'cat' has been added to /bin. + +- many utilities have been moved from /usr/bin to /bin, to + conform to the Linux Directory Structure Standard (v1.0). + These utilities are ones that are 'vital to the restoration of + other file systems in the case of a corrupting crash.' + +- 'init' and 'update' have been moved to /etc from /bin. This + was done because neither program should be executed from the + command line by any user, including root. (That means don't + put /etc in your PATH!) This has been a matter of some + controversy, but this is how it will stand until the Linux + Standards mailing list/committee decides otherwise. + +- tty64, tty65, etc, have been renamed to ttys1, ttys2, etc. + +- the directory /INSTALL was added, which contains some + documentation, and three simple shell scripts to make + installing Linux on a hard drive partition easier. These are: + + - 'mktree', which makes a directory tree on the specified + mounted device. + - 'mkdev' which creates the standard devices in the dev + directory of the specified mounted device + - 'install' which installs the programs on the root diskette + to the specified mounted device + + These programs will normally be called with ' /mnt'. + +- rootdev is different than the one on v0.95. A couple of days + after the release of 0.95, a program called 'rdev' was posted + to alt.os.linux that duplicated and extended the functionality + of rootdev. This was renamed to rootdev and replaces the old + rootdev. + +- agetty was renamed to getty, to be consistent with common Unix + practice. + +- an improved fdisk was added that correctly reports extended + partitions, (Thanks to Linus!) + +- /dev is complete, or at least more complete than the last few + releases of the root diskette, which always seemed to be a + major complaint. :) + +- /etc/issue and /etc/motd have been expanded to be a little + more informative. (Yeah, I know, big deal! :) + +- chgrp was removed. You can use chown to get the same effect, + but you just have to specify an owner, too. + +Many of these changes were discussed on alt.os.linux, or the Linux +Standards group, so they may look familiar. + +If you have questions, problems, or complaints about the root +diskette, either post to alt.os.linux, or send mail to me at +jwinstea@jarthur.Claremont.EDU. + +If you have questions, problems, or complaints about the boot diskette +or the kernel itself, post to alt.os.linux or send mail to Linus +Torvalds at torvalds@cc.helsinki.fi. + +Remember, the only stupid questions are the ones you don't ask. + +FUTURE CHANGES + +I'm already anticipating some changes for the next release, so here's +a sneak preview: + +- shared libraries. These are currently in alpha testing, and + will hopefully free up some more room on the root floppy for + more goodies. + +- a generic mtools might be added to the root floppy. + +- a better fdisk to replace the current fdisk/pfdisk pair. You + won't need to know your drive's geometry for this, and it will + know about Linux extended partitions. + +- an improved sh. I'm working on the backspace problem, and + adding job control. I'm also going to look at using the GNU + readline library for input, as long as it doesn't add + substantially to the size of sh. + +- init/getty/login may be removed from the root floppy. The + main reason they'll still on there is the backspace problem + with ash. + +- improved installation documentation. People have started work + on this already - read alt.os.linux for previews. + +- more robust installation scripts. The current ones are quick + and dirty, and work well, but I'd like to add better ones. + +- miscellaneous utilities added. I'd really like to add an + editor to the root disk, but I haven't found one small enough. + Any suggestions? + +- various other things that I can't remember right now. + +Again, mail your questions, comments and suggestions about the root +diskette to me at jwinstea@jarthur.Claremont.EDU. +-- +Jim Winstead Jr. (CSci '95) | "Catch a fish!" +Harvey Mudd College | -Geddy Lee, +jwinstea@jarthur.Claremont.EDU | San Diego Sports Arena +Disclaimer: Mine, not theirs! | January 20, 1992 diff --git a/kernel/0.95/diffs b/kernel/0.95/diffs new file mode 100644 index 00000000..3a320fec --- /dev/null +++ b/kernel/0.95/diffs @@ -0,0 +1,5168 @@ +*** ../0.95a/linux/Makefile Tue Mar 17 00:08:56 1992 +--- linux/Makefile Sat Apr 4 17:33:02 1992 +*************** +*** 1,7 **** +--- 1,44 ---- + # ++ # comment this line if you don't want the emulation-code ++ # ++ ++ MATH_EMULATION = -DKERNEL_MATH_EMULATION ++ ++ # ++ # uncomment the correct keyboard: ++ # ++ ++ KEYBOARD = -DKBD_FINNISH ++ # KEYBOARD = -DKBD_US ++ # KEYBOARD = -DKBD_GR ++ # KEYBOARD = -DKBD_FR ++ # KEYBOARD = -DKBD_UK ++ # KEYBOARD = -DKBD_DK ++ ++ # ++ # uncomment this line if you are using gcc-1.40 ++ # ++ #GCC_OPT = -fcombine-regs ++ ++ # ++ # standard CFLAGS ++ # ++ ++ CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) ++ ++ # ++ # ROOT_DEV specifies the default root-device when making the image. ++ # This can be either FLOPPY, /dev/xxxx or empty, in which case the ++ # default of FLOPPY is used by 'build'. ++ # ++ ++ ROOT_DEV = /dev/hdb1 ++ ++ # + # if you want the ram-disk device, define this to be the + # size in blocks. + # ++ + #RAMDISK = -DRAMDISK=512 + + AS86 =as86 -0 -a +*************** +*** 9,26 **** + + AS =as + LD =ld +! LDFLAGS =-s -x -M + CC =gcc $(RAMDISK) +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer + CPP =cpp -nostdinc -Iinclude + +- # +- # ROOT_DEV specifies the default root-device when making the image. +- # This can be either FLOPPY, /dev/xxxx or empty, in which case the +- # default of FLOPPY is used by 'build'. +- # +- ROOT_DEV=/dev/hdb1 +- + ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o + FILESYSTEMS =fs/minix/minix.o + DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a +--- 46,57 ---- + + AS =as + LD =ld +! #LDFLAGS =-s -x -M +! LDFLAGS = -M + CC =gcc $(RAMDISK) +! MAKE =make CFLAGS="$(CFLAGS)" + CPP =cpp -nostdinc -Iinclude + + ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o + FILESYSTEMS =fs/minix/minix.o + DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a +*************** +*** 39,45 **** + all: Image + + Image: boot/bootsect boot/setup tools/system tools/build +! tools/build boot/bootsect boot/setup tools/system $(ROOT_DEV) > Image + sync + + disk: Image +--- 70,79 ---- + all: Image + + Image: boot/bootsect boot/setup tools/system tools/build +! cp tools/system system.tmp +! strip system.tmp +! tools/build boot/bootsect boot/setup system.tmp $(ROOT_DEV) > Image +! rm system.tmp + sync + + disk: Image +*************** +*** 62,89 **** + -o tools/system > System.map + + kernel/math/math.a: dummy +! (cd kernel/math; make) + + kernel/blk_drv/blk_drv.a: dummy +! (cd kernel/blk_drv; make) + + kernel/chr_drv/chr_drv.a: dummy +! (cd kernel/chr_drv; make) + + kernel/kernel.o: dummy +! (cd kernel; make) + + mm/mm.o: dummy +! (cd mm; make) + + fs/fs.o: dummy +! (cd fs; make) + + fs/minix/minix.o: dummy +! (cd fs/minix; make) + + lib/lib.a: dummy +! (cd lib; make) + + boot/setup: boot/setup.s + $(AS86) -o boot/setup.o boot/setup.s +--- 96,123 ---- + -o tools/system > System.map + + kernel/math/math.a: dummy +! (cd kernel/math; $(MAKE) MATH_EMULATION="$(MATH_EMULATION)") + + kernel/blk_drv/blk_drv.a: dummy +! (cd kernel/blk_drv; $(MAKE)) + + kernel/chr_drv/chr_drv.a: dummy +! (cd kernel/chr_drv; $(MAKE) KEYBOARD="$(KEYBOARD)") + + kernel/kernel.o: dummy +! (cd kernel; $(MAKE)) + + mm/mm.o: dummy +! (cd mm; $(MAKE)) + + fs/fs.o: dummy +! (cd fs; $(MAKE)) + + fs/minix/minix.o: dummy +! (cd fs/minix; $(MAKE)) + + lib/lib.a: dummy +! (cd lib; $(MAKE)) + + boot/setup: boot/setup.s + $(AS86) -o boot/setup.o boot/setup.s +*************** +*** 127,133 **** + include/sys/types.h include/sys/time.h include/time.h include/sys/times.h \ + include/sys/utsname.h include/sys/param.h include/sys/resource.h \ + include/utime.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/linux/kernel.h include/signal.h include/asm/system.h \ +! include/asm/io.h include/stddef.h include/stdarg.h include/fcntl.h \ +! include/string.h +--- 161,167 ---- + include/sys/types.h include/sys/time.h include/time.h include/sys/times.h \ + include/sys/utsname.h include/sys/param.h include/sys/resource.h \ + include/utime.h include/linux/tty.h include/termios.h include/linux/sched.h \ +! include/linux/head.h include/linux/fs.h include/sys/dirent.h \ +! include/limits.h include/linux/mm.h include/linux/kernel.h include/signal.h \ +! include/asm/system.h include/asm/io.h include/stddef.h include/stdarg.h \ +! include/fcntl.h include/string.h +*** ../0.95a/linux/boot/bootsect.S Sat Jan 18 19:01:36 1992 +--- linux/boot/bootsect.S Thu Apr 2 23:18:19 1992 +*************** +*** 8,17 **** + ! + ! bootsect.s (C) 1991 Linus Torvalds + ! modified by Drew Eckhardt + ! + ! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves +! ! iself out of the way to address 0x90000, and jumps there. + ! + ! It then loads 'setup' directly after itself (0x90200), and the system + ! at 0x10000, using BIOS interrupts. + ! +--- 8,21 ---- + ! + ! bootsect.s (C) 1991 Linus Torvalds + ! modified by Drew Eckhardt ++ ! modified by Bruce Evans (bde) + ! + ! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves +! ! itself out of the way to address 0x90000, and jumps there. + ! ++ ! bde - should not jump blindly, there may be systems with only 512K low ++ ! memory. Use int 0x12 to get the top of memory, etc. ++ ! + ! It then loads 'setup' directly after itself (0x90200), and the system + ! at 0x10000, using BIOS interrupts. + ! +*************** +*** 22,51 **** + ! + ! The loader has been made as simple as possible, and continuos + ! read errors will result in a unbreakable loop. Reboot by hand. It +! ! loads pretty fast by getting whole sectors at a time whenever possible. + +- .globl begtext, begdata, begbss, endtext, enddata, endbss + .text +- begtext: +- .data +- begdata: +- .bss +- begbss: +- .text + +! SETUPLEN = 4 ! nr of setup-sectors +! BOOTSEG = 0x07c0 ! original address of boot-sector +! INITSEG = DEF_INITSEG ! we move boot here - out of the way +! SETUPSEG = DEF_SETUPSEG ! setup starts here +! SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). +! ENDSEG = SYSSEG + SYSSIZE ! where to stop loading + + ! ROOT_DEV & SWAP_DEV are now written by "build". + ROOT_DEV = 0 + SWAP_DEV = 0 + +! entry start +! start: + mov ax,#BOOTSEG + mov ds,ax + mov ax,#INITSEG +--- 26,52 ---- + ! + ! The loader has been made as simple as possible, and continuos + ! read errors will result in a unbreakable loop. Reboot by hand. It +! ! loads pretty fast by getting whole tracks at a time whenever possible. + + .text + +! SETUPSECS = 4 ! nr of setup-sectors +! BOOTSEG = 0x07C0 ! original address of boot-sector +! INITSEG = DEF_INITSEG ! we move boot here - out of the way +! SETUPSEG = DEF_SETUPSEG ! setup starts here +! SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). +! ENDSEG = SYSSEG + SYSSIZE ! where to stop loading + + ! ROOT_DEV & SWAP_DEV are now written by "build". + ROOT_DEV = 0 + SWAP_DEV = 0 + +! ! ld86 requires an entry symbol. This may as well be the usual one. +! .globl _main +! _main: +! #if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */ +! int 3 +! #endif + mov ax,#BOOTSEG + mov ds,ax + mov ax,#INITSEG +*************** +*** 55,71 **** + sub di,di + cld + rep +! movw + jmpi go,INITSEG + + go: mov ax,cs +! mov dx,#0xfef4 ! arbitrary value >>512 - disk parm size + + mov ds,ax + mov es,ax + push ax + +! mov ss,ax ! put stack at 0x9ff00 - 12. + mov sp,dx + /* + * Many BIOS's default disk parameter tables will not +--- 56,80 ---- + sub di,di + cld + rep +! movsw + jmpi go,INITSEG + + go: mov ax,cs +! mov dx,#0x4000-12 ! 0x4000 is arbitrary value >= length of +! ! bootsect + length of setup + room for stack +! ! 12 is disk parm size + ++ ! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We ++ ! wouldn't have to worry about this if we checked the top of memory. Also ++ ! my BIOS can be configured to put the wini drive tables in high memory ++ ! instead of in the vector table. The old stack might have clobbered the ++ ! drive table. ++ + mov ds,ax + mov es,ax + push ax + +! mov ss,ax ! put stack at INITSEG:0x4000-12. + mov sp,dx + /* + * Many BIOS's default disk parameter tables will not +*************** +*** 96,102 **** + + rep + seg gs +! movw + + mov di,dx + movb 4(di),*18 ! patch sector count +--- 105,111 ---- + + rep + seg gs +! movsw + + mov di,dx + movb 4(di),*18 ! patch sector count +*************** +*** 121,127 **** + xor dx, dx ! drive 0, head 0 + mov cx,#0x0002 ! sector 2, track 0 + mov bx,#0x0200 ! address = 512, in INITSEG +! mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors + int 0x13 ! read it + jnc ok_load_setup ! ok - continue + +--- 130,137 ---- + xor dx, dx ! drive 0, head 0 + mov cx,#0x0002 ! sector 2, track 0 + mov bx,#0x0200 ! address = 512, in INITSEG +! mov ax,#0x0200+SETUPSECS ! service 2, nr of sectors +! ! (assume all on head 0, track 0) + int 0x13 ! read it + jnc ok_load_setup ! ok - continue + +*************** +*** 134,149 **** + xor dl, dl ! reset FDC + xor ah, ah + int 0x13 +! j load_setup + + ok_load_setup: + + ! Get disk drive parameters, specifically nr of sectors/track + + xor dl,dl + mov ah,#0x08 ! AH=8 is get drive parameters + int 0x13 + xor ch,ch + seg cs + mov sectors,cx + mov ax,#INITSEG +--- 144,186 ---- + xor dl, dl ! reset FDC + xor ah, ah + int 0x13 +! jmp load_setup + + ok_load_setup: + + ! Get disk drive parameters, specifically nr of sectors/track + ++ #if 0 ++ ++ ! bde - the Phoenix BIOS manual says function 0x08 only works for fixed ++ ! disks. It doesn't work for one of my BIOS's (1987 Award). It was ++ ! fatal not to check the error code. ++ + xor dl,dl + mov ah,#0x08 ! AH=8 is get drive parameters + int 0x13 + xor ch,ch ++ #else ++ ++ ! It seems that there is no BIOS call to get the number of sectors. Guess ++ ! 18 sectors if sector 18 can be read, 15 if sector 15 can be read. ++ ! Otherwise guess 9. ++ ++ xor dx, dx ! drive 0, head 0 ++ mov cx,#0x0012 ! sector 18, track 0 ++ mov bx,#0x0200+SETUPSECS*0x200 ! address after setup (es = cs) ++ mov ax,#0x0201 ! service 2, 1 sector ++ int 0x13 ++ jnc got_sectors ++ mov cl,#0x0f ! sector 15 ++ mov ax,#0x0201 ! service 2, 1 sector ++ int 0x13 ++ jnc got_sectors ++ mov cl,#0x09 ++ ++ #endif ++ ++ got_sectors: + seg cs + mov sectors,cx + mov ax,#INITSEG +*************** +*** 205,211 **** + ! + ! in: es - starting address segment (normally 0x1000) + ! +! sread: .word 1+SETUPLEN ! sectors read of current track + head: .word 0 ! current head + track: .word 0 ! current track + +--- 242,248 ---- + ! + ! in: es - starting address segment (normally 0x1000) + ! +! sread: .word 1+SETUPSECS ! sectors read of current track + head: .word 0 ! current head + track: .word 0 ! current track + +*************** +*** 264,277 **** + int 0x10 + popa + +! mov dx,track +! mov cx,sread +! inc cx +! mov ch,dl +! mov dx,head +! mov dh,dl +! and dx,#0x0100 +! mov ah,#2 + + push dx ! save for error dump + push cx +--- 301,314 ---- + int 0x10 + popa + +! mov dx,track +! mov cx,sread +! inc cx +! mov ch,dl +! mov dx,head +! mov dh,dl +! and dx,#0x0100 +! mov ah,#2 + + push dx ! save for error dump + push cx +*************** +*** 278,286 **** + push bx + push ax + +! int 0x13 +! jc bad_rt +! add sp, #8 + popa + ret + +--- 315,323 ---- + push bx + push ax + +! int 0x13 +! jc bad_rt +! add sp, #8 + popa + ret + +*************** +*** 317,332 **** + print_loop: + push cx ! save count left + call print_nl ! nl for readability + jae no_reg ! see if register name is needed + +! mov ax, #0xe05 + 0x41 - 1 + sub al, cl + int 0x10 + +! mov al, #0x58 ! X + int 0x10 + +! mov al, #0x3a ! : + int 0x10 + + no_reg: +--- 354,371 ---- + print_loop: + push cx ! save count left + call print_nl ! nl for readability ++ ++ cmp cl, 5 + jae no_reg ! see if register name is needed + +! mov ax, #0xe05 + 'A - 1 + sub al, cl + int 0x10 + +! mov al, #'X + int 0x10 + +! mov al, #': + int 0x10 + + no_reg: +*************** +*** 356,365 **** + mov ah, #0xe + mov al, dl ! mask off so we have only next nibble + and al, #0xf +! add al, #0x30 ! convert to 0 based digit, '0' +! cmp al, #0x39 ! check for overflow + jbe good_digit +! add al, #0x41 - 0x30 - 0xa ! 'A' - '0' - 0xa + + good_digit: + int 0x10 +--- 395,404 ---- + mov ah, #0xe + mov al, dl ! mask off so we have only next nibble + and al, #0xf +! add al, #'0 ! convert to 0-based digit +! cmp al, #'9 ! check for overflow + jbe good_digit +! add al, #'A - '0 - 10 + + good_digit: + int 0x10 +*************** +*** 394,404 **** + .word ROOT_DEV + boot_flag: + .word 0xAA55 +- +- .text +- endtext: +- .data +- enddata: +- .bss +- endbss: +- +--- 433,435 ---- +*** ../0.95a/linux/boot/setup.S Sat Mar 14 23:13:30 1992 +--- linux/boot/setup.S Wed Mar 25 02:30:42 1992 +*************** +*** 217,222 **** +--- 217,238 ---- + jnz empty_8042 ! yes - loop + ret + ++ getkey: ++ in al,#0x60 ! Quick and dirty... ++ .word 0x00eb,0x00eb ! jmp $+2, jmp $+2 ++ mov bl,al ++ in al,#0x61 ++ .word 0x00eb,0x00eb ++ mov ah,al ++ or al,#0x80 ++ out #0x61,al ++ .word 0x00eb,0x00eb ++ mov al,ah ++ out #0x61,al ++ .word 0x00eb,0x00eb ++ mov al,bl ++ ret ++ + ! Routine trying to recognize type of SVGA-board present (if any) + ! and if it recognize one gives the choices of resolution it offers. + ! If one is found the resolution chosen is given by al,ah (rows,cols). +*************** +*** 233,239 **** + cmp al,#0x82 + jb nokey + jmp flush +! nokey: in al,#0x60 + cmp al,#0x82 + jb nokey + cmp al,#0xe0 +--- 249,255 ---- + cmp al,#0x82 + jb nokey + jmp flush +! nokey: call getkey + cmp al,#0x82 + jb nokey + cmp al,#0xe0 +*************** +*** 481,487 **** + call prtstr + pop si + add cl,#0x80 +! nonum: in al,#0x60 ! Quick and dirty... + cmp al,#0x82 + jb nonum + cmp al,#0x8b +--- 497,503 ---- + call prtstr + pop si + add cl,#0x80 +! nonum: call getkey + cmp al,#0x82 + jb nonum + cmp al,#0x8b +*** ../0.95a/linux/fs/Makefile Thu Mar 5 23:36:44 1992 +--- linux/fs/Makefile Sat Apr 4 17:33:10 1992 +*************** +*** 1,10 **** + AR =ar + AS =as +- CC =gcc + LD =ld +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ +! -fno-defer-pop -nostdinc -I../include +! CPP =gcc -E -nostdinc -I../include + + .c.s: + $(CC) $(CFLAGS) \ +--- 1,17 ---- ++ # ++ # Makefile for the linux filesystem. ++ # ++ # 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). ++ # ++ # Note 2! The CFLAGS definitions are now in the main makefile... ++ + AR =ar + AS =as + LD =ld +! CC =gcc -nostdinc -I../include +! CPP =cpp -nostdinc -I../include + + .c.s: + $(CC) $(CFLAGS) \ +*************** +*** 36,118 **** + ### Dependencies: + block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h + buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ +! ../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/asm/system.h \ +! ../include/asm/io.h +! char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \ +! ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/segment.h ../include/asm/io.h + exec.o : exec.c ../include/signal.h ../include/sys/types.h \ + ../include/errno.h ../include/string.h ../include/sys/stat.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/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.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/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \ +! ../include/fcntl.h ../include/sys/stat.h +! file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h + inode.o : inode.c ../include/string.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/linux/minix_fs.h \ +! ../include/asm/system.h + ioctl.o : ioctl.c ../include/string.h ../include/errno.h \ + ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \ +! ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.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/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/linux/minix_fs.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/kernel.h ../include/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/segment.h + pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \ + ../include/errno.h ../include/termios.h ../include/fcntl.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ +! ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/segment.h +! read_write.o : read_write.c ../include/sys/stat.h ../include/sys/types.h \ +! ../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \ +! ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/segment.h + select.o : select.c ../include/linux/fs.h ../include/sys/types.h \ +! ../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \ +! ../include/linux/sched.h ../include/linux/head.h ../include/linux/mm.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \ +! ../include/asm/system.h ../include/sys/stat.h ../include/string.h \ +! ../include/const.h ../include/errno.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/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.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 ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/linux/minix_fs.h \ +! ../include/asm/system.h ../include/errno.h ../include/sys/stat.h +--- 43,137 ---- + ### Dependencies: + block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/segment.h ../include/asm/system.h + buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ +! ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \ + ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/system.h ../include/asm/io.h +! char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \ +! ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/segment.h ../include/asm/io.h + exec.o : exec.c ../include/signal.h ../include/sys/types.h \ + ../include/errno.h ../include/string.h ../include/sys/stat.h \ +! ../include/a.out.h ../include/linux/fs.h ../include/sys/dirent.h \ +! ../include/limits.h ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.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/sys/dirent.h ../include/limits.h \ +! ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/segment.h ../include/fcntl.h \ +! ../include/sys/stat.h +! file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h \ +! ../include/sys/dirent.h ../include/limits.h + inode.o : inode.c ../include/string.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \ +! ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.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/sys/dirent.h \ +! ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h + namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \ +! ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.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/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/segment.h + pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \ + ../include/errno.h ../include/termios.h ../include/fcntl.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/segment.h ++ read_write.o : read_write.c ../include/errno.h ../include/sys/types.h \ ++ ../include/sys/stat.h ../include/sys/dirent.h ../include/limits.h \ ++ ../include/linux/kernel.h ../include/linux/sched.h ../include/linux/head.h \ ++ ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \ ++ ../include/sys/param.h ../include/sys/time.h ../include/time.h \ ++ ../include/sys/resource.h ../include/linux/minix_fs.h \ ++ ../include/asm/segment.h + select.o : select.c ../include/linux/fs.h ../include/sys/types.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/kernel.h \ +! ../include/linux/tty.h ../include/termios.h ../include/linux/sched.h \ +! ../include/linux/head.h ../include/linux/mm.h ../include/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h \ +! ../include/sys/stat.h ../include/string.h ../include/const.h \ +! ../include/errno.h + stat.o : stat.c ../include/errno.h ../include/sys/stat.h \ +! ../include/sys/types.h ../include/linux/fs.h ../include/sys/dirent.h \ +! ../include/limits.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.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/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/linux/minix_fs.h ../include/asm/system.h ../include/errno.h \ +! ../include/sys/stat.h +*** ../0.95a/linux/fs/read_write.c Tue Mar 3 00:16:10 1992 +--- linux/fs/read_write.c Fri Apr 3 20:20:36 1992 +*************** +*** 4,22 **** + * (C) 1991 Linus Torvalds + */ + +- #include + #include + #include + + #include + #include + #include + +! int sys_lseek(unsigned int fd,off_t offset, unsigned int origin) + { + struct file * file; +! int tmp; + + if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode)) + return -EBADF; + if (origin > 2) +--- 4,37 ---- + * (C) 1991 Linus Torvalds + */ + + #include + #include ++ #include ++ #include + + #include + #include ++ #include + #include + +! int sys_readdir(unsigned int fd, struct dirent * dirent) + { + struct file * file; +! struct inode * inode; + ++ if (fd >= NR_OPEN || !(file = current->filp[fd]) || ++ !(inode = file->f_inode)) ++ return -EBADF; ++ if (file->f_op && file->f_op->readdir) ++ return file->f_op->readdir(inode,file,dirent); ++ return -EBADF; ++ } ++ ++ int sys_lseek(unsigned int fd, off_t offset, unsigned int origin) ++ { ++ struct file * file; ++ int tmp, mem_dev; ++ + if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode)) + return -EBADF; + if (origin > 2) +*************** +*** 25,45 **** + return -ESPIPE; + if (file->f_op && file->f_op->lseek) + return file->f_op->lseek(file->f_inode,file,offset,origin); + /* this is the default handler if no lseek handler is present */ + 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; + } + return file->f_pos; + } + +--- 40,64 ---- + return -ESPIPE; + if (file->f_op && file->f_op->lseek) + return file->f_op->lseek(file->f_inode,file,offset,origin); ++ mem_dev = S_ISCHR(file->f_inode->i_mode); ++ + /* this is the default handler if no lseek handler is present */ + switch (origin) { + case 0: +! if (offset<0 && !mem_dev) return -EINVAL; + file->f_pos=offset; + break; + case 1: +! if (file->f_pos+offset<0 && !mem_dev) return -EINVAL; + file->f_pos += offset; + break; + case 2: +! if ((tmp=file->f_inode->i_size+offset)<0 && !mem_dev) + return -EINVAL; + file->f_pos = tmp; + } ++ if (mem_dev && file->f_pos < 0) ++ return 0; + return file->f_pos; + } + +*** ../0.95a/linux/fs/buffer.c Fri Mar 13 19:06:26 1992 +--- linux/fs/buffer.c Wed Apr 1 02:06:48 1992 +*************** +*** 27,34 **** + #include + + 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; +--- 27,34 ---- + #include + + extern int end; +! static struct buffer_head * start_buffer = (struct buffer_head *) &end; +! static struct buffer_head * hash_table[NR_HASH]; + static struct buffer_head * free_list; + static struct task_struct * buffer_wait = NULL; + int NR_BUFFERS = 0; +*************** +*** 406,411 **** +--- 406,415 ---- + else + b = (void *) buffer_end; + while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) { ++ if (((unsigned long) (h+1)) > 0xA0000) { ++ printk("buffer-list doesn't fit in low meg - contact Linus\n"); ++ break; ++ } + h->b_dev = 0; + h->b_dirt = 0; + h->b_count = 0; +*** ../0.95a/linux/fs/inode.c Sat Mar 14 19:33:21 1992 +--- linux/fs/inode.c Fri Apr 3 16:09:27 1992 +*************** +*** 8,14 **** + #include + + #include +- #include + #include + #include + #include +--- 8,13 ---- +*************** +*** 15,23 **** + + struct inode inode_table[NR_INODE]={{0,},}; + +- extern void minix_read_inode(struct inode * inode); +- extern void minix_write_inode(struct inode * inode); +- + static inline void wait_on_inode(struct inode * inode) + { + cli(); +--- 14,19 ---- +*************** +*** 48,54 **** + unlock_inode(inode); + return; + } +! minix_write_inode(inode); + unlock_inode(inode); + } + +--- 44,51 ---- + unlock_inode(inode); + return; + } +! if (inode->i_op && inode->i_op->write_inode) +! inode->i_op->write_inode(inode); + unlock_inode(inode); + } + +*************** +*** 55,67 **** + static void read_inode(struct inode * inode) + { + lock_inode(inode); +! minix_read_inode(inode); + unlock_inode(inode); + } + + int bmap(struct inode * inode, int block) + { +! return minix_bmap(inode,block); + } + + void invalidate_inodes(int dev) +--- 52,77 ---- + static void read_inode(struct inode * inode) + { + lock_inode(inode); +! if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->read_inode) +! inode->i_sb->s_op->read_inode(inode); + unlock_inode(inode); + } + ++ /* ++ * bmap is needed for demand-loading and paging: if this function ++ * doesn't exist for a filesystem, then those things are impossible: ++ * executables cannot be run from the filesystem etc... ++ * ++ * This isn't as bad as it sounds: the read-routines might still work, ++ * so the filesystem would be otherwise ok (for example, you might have ++ * a DOS filesystem, which doesn't lend itself to bmap very well, but ++ * you could still transfer files to/from the filesystem) ++ */ + int bmap(struct inode * inode, int block) + { +! if (inode->i_op && inode->i_op->bmap) +! return inode->i_op->bmap(inode,block); +! return 0; + } + + void invalidate_inodes(int dev) +*************** +*** 127,134 **** + return; + } + if (!inode->i_nlink) { +! minix_truncate(inode); +! minix_free_inode(inode); + return; + } + if (inode->i_dirt) { +--- 137,144 ---- + return; + } + if (!inode->i_nlink) { +! if (inode->i_op && inode->i_op->put_inode) +! inode->i_op->put_inode(inode); + return; + } + if (inode->i_dirt) { +*** ../0.95a/linux/fs/open.c Mon Mar 2 23:52:07 1992 +--- linux/fs/open.c Thu Apr 2 23:41:50 1992 +*************** +*** 29,34 **** +--- 29,39 ---- + if (!(inode=namei(filename))) + return -ENOENT; + if (times) { ++ if (current->euid != inode->i_uid && ++ !permission(inode,MAY_WRITE)) { ++ iput(inode); ++ return -EPERM; ++ } + actime = get_fs_long((unsigned long *) ×->actime); + modtime = get_fs_long((unsigned long *) ×->modtime); + } else +*** ../0.95a/linux/fs/char_dev.c Mon Mar 2 04:16:20 1992 +--- linux/fs/char_dev.c Wed Apr 1 01:26:11 1992 +*************** +*** 38,63 **** + + static int rw_mem(int rw,char * buf, int count, off_t * pos) + { +! return -EIO; + } + + static int rw_kmem(int rw,char * buf, int count, off_t * pos) + { +! /* kmem by Damiano */ +! int i = *pos; /* Current position where to read */ + +! /* i can go from 0 to LOW_MEM (See include/linux/mm.h */ +! /* I am not shure about it but it doesn't mem fault :-) */ +! while ( (count-- > 0) && (i > 20 & 0xffc); +! if (((pte = *((unsigned long *) pde)) & 1) == 0) +! return 0; /* page table not present */ +! pte &= 0xfffff000; +! pte += *pos >> 10 & 0xffc; +! if (((tmp = *((unsigned long *) pte)) & 1) == 0) +! return 0; +! if (rw == WRITE && (tmp & 2) == 0) +! un_wp_page((unsigned long *) pte); +! p = (char *) ((tmp & 0xfffff000) + (*pos & 0xfff)); +! while (1) { +! if (rw == WRITE) +! *p++ = get_fs_byte(buf++); +! else +! put_fs_byte(*p++, buf++); +! +! if (--i == 0) +! break; +! +! if (count && ((unsigned long) p & 0xfff) == 0) { +! if (((pte += 4) & 0xfff) == 0) { +! if (((pde += 4) & 0xfff) == 0) +! break; +! if (((pte = *((unsigned long *) pde)) & 1) == 0) +! break; +! pte &= 0xfffff000; +! } +! if (((tmp = *((unsigned long *) pte)) & 1) == 0) +! break; +! +! if (rw == WRITE && (tmp & 2) == 0) +! un_wp_page((unsigned long *) pte); +! p = (char *) (tmp & 0xfffff000); +! } +! } +! return(count - i); + } + + static int rw_kmem(int rw,char * buf, int count, off_t * pos) + { +! char *p=(char *) *pos; + +! if ((unsigned long) *pos > HIGH_MEMORY) +! return 0; +! if ((unsigned long) *pos + count > HIGH_MEMORY) +! count = HIGH_MEMORY - *pos; +! +! switch (rw) { +! case READ: +! while ((count -= 4) >= 0) +! put_fs_long(*((unsigned long *) p)++, +! ((unsigned long *) buf)++); +! count += 4; +! while (--count >= 0) +! put_fs_byte(*p++, buf++); +! break; +! case WRITE: +! while (--count >= 0) +! *p++ = get_fs_byte(buf++); +! break; +! default: +! return -EINVAL; + } +! p -= *pos; +! *pos += (int) p; +! return (int) p; + } + + static int rw_port(int rw,char * buf, int count, off_t * pos) +*** ../0.95a/linux/fs/exec.c Wed Mar 4 06:24:51 1992 +--- linux/fs/exec.c Wed Apr 1 01:26:36 1992 +*************** +*** 216,221 **** +--- 216,222 ---- + int retval; + int sh_bang = 0; + unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4; ++ int ch; + + if ((0xffff & eip[1]) != 0x000f) + panic("execve called from supervisor mode"); +*************** +*** 348,353 **** +--- 349,363 ---- + } + /* OK, This is the point of no return */ + /* note that current->library stays unchanged by an exec */ ++ for (i=0; (ch = get_fs_byte(filename++)) != '\0';) ++ if (ch == '/') ++ i = 0; ++ else ++ if (i < 8) ++ current->comm[i++] = ch; ++ if (i < 8) ++ current->comm[i] = '\0'; ++ + if (current->executable) + iput(current->executable); + current->executable = inode; +*************** +*** 374,379 **** +--- 384,390 ---- + (current->end_data = ex.a_data + + (current->end_code = ex.a_text)); + current->start_stack = p; ++ current->rss = (LIBRARY_OFFSET - p + PAGE_SIZE-1) / PAGE_SIZE; + current->suid = current->euid = e_uid; + current->sgid = current->egid = e_gid; + eip[0] = ex.a_entry; /* eip, magic happens :-) */ +*** ../0.95a/linux/fs/super.c Fri Feb 28 19:01:44 1992 +--- linux/fs/super.c Fri Apr 3 16:22:05 1992 +*************** +*** 29,36 **** + /* this is initialized in init/main.c */ + int ROOT_DEV = 0; + +! static void lock_super(struct super_block * sb) + { + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); +--- 29,55 ---- + /* this is initialized in init/main.c */ + int ROOT_DEV = 0; + +! /* Move into include file later */ +! +! static struct file_system_type file_systems[] = { +! {minix_read_super,"minix"}, +! {NULL,NULL} +! }; +! +! /* end of include file */ +! +! struct file_system_type *get_fs_type(char *name) + { ++ int a; ++ ++ for(a = 0 ; file_systems[a].read_super ; a++) ++ if (!strcmp(name,file_systems[a].name)) ++ return(&file_systems[a]); ++ return(NULL); ++ } ++ ++ void lock_super(struct super_block * sb) ++ { + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); +*************** +*** 38,44 **** + sti(); + } + +! static void free_super(struct super_block * sb) + { + cli(); + sb->s_lock = 0; +--- 57,63 ---- + sti(); + } + +! void free_super(struct super_block * sb) + { + cli(); + sb->s_lock = 0; +*************** +*** 46,52 **** + sti(); + } + +! static void wait_on_super(struct super_block * sb) + { + cli(); + while (sb->s_lock) +--- 65,71 ---- + sti(); + } + +! void wait_on_super(struct super_block * sb) + { + cli(); + while (sb->s_lock) +*************** +*** 75,81 **** + void put_super(int dev) + { + struct super_block * sb; +- int i; + + if (dev == ROOT_DEV) { + printk("root diskette changed: prepare for armageddon\n\r"); +--- 94,99 ---- +*************** +*** 87,107 **** + printk("Mounted disk changed - tssk, tssk\n\r"); + return; + } +! lock_super(sb); +! sb->s_dev = 0; +! for(i=0;is_imap[i]); +! for(i=0;is_zmap[i]); +! free_super(sb); +! return; + } + +! static struct super_block * read_super(int dev) + { + struct super_block * s; +! struct buffer_head * bh; +! int i,block; + + if (!dev) + return NULL; +--- 105,118 ---- + printk("Mounted disk changed - tssk, tssk\n\r"); + return; + } +! if (sb->s_op && sb->s_op->put_super) +! sb->s_op->put_super(sb); + } + +! static struct super_block * read_super(int dev,char *name,void *data) + { + struct super_block * s; +! struct file_system_type *type; + + if (!dev) + return NULL; +*************** +*** 108,113 **** +--- 119,128 ---- + check_disk_change(dev); + if (s = get_super(dev)) + return s; ++ if (!(type=get_fs_type(name))) { ++ printk("get fs type failed %s\n",name); ++ return NULL; ++ } + for (s = 0+super_block ;; s++) { + if (s >= NR_SUPER+super_block) + return NULL; +*************** +*** 115,167 **** + break; + } + s->s_dev = dev; +! s->s_mounted = NULL; + s->s_covered = NULL; + s->s_time = 0; + s->s_rd_only = 0; + s->s_dirt = 0; +! lock_super(s); +! if (!(bh = bread(dev,1))) { +! s->s_dev=0; +! free_super(s); +! return NULL; +! } +! *((struct minix_super_block *) s) = +! *((struct minix_super_block *) bh->b_data); +! brelse(bh); +! if (s->s_magic != MINIX_SUPER_MAGIC) { +! s->s_dev = 0; +! free_super(s); +! return NULL; +! } +! for (i=0;i < MINIX_I_MAP_SLOTS;i++) +! s->s_imap[i] = NULL; +! for (i=0;i < MINIX_Z_MAP_SLOTS;i++) +! s->s_zmap[i] = NULL; +! block=2; +! for (i=0 ; i < s->s_imap_blocks ; i++) +! if (s->s_imap[i]=bread(dev,block)) +! block++; +! else +! break; +! for (i=0 ; i < s->s_zmap_blocks ; i++) +! if (s->s_zmap[i]=bread(dev,block)) +! block++; +! else +! break; +! if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) { +! for(i=0;is_imap[i]); +! for(i=0;is_zmap[i]); +! s->s_dev=0; +! free_super(s); +! return NULL; +! } +! s->s_imap[0]->b_data[0] |= 1; +! s->s_zmap[0]->b_data[0] |= 1; +! free_super(s); +! return s; + } + + int sys_umount(char * dev_name) +--- 130,143 ---- + break; + } + s->s_dev = dev; +! if (!type->read_super(s,data)) +! return(NULL); +! s->s_dev = dev; + s->s_covered = NULL; + s->s_time = 0; + s->s_rd_only = 0; + s->s_dirt = 0; +! return(s); + } + + int sys_umount(char * dev_name) +*************** +*** 184,190 **** + return -ENOENT; + if (!sb->s_covered->i_mount) + printk("Mounted inode has i_mount=0\n"); +! for (inode=inode_table+0 ; inodei_dev==dev && inode->i_count) + if (inode == sb->s_mounted && inode->i_count == 1) + continue; +--- 160,166 ---- + return -ENOENT; + if (!sb->s_covered->i_mount) + printk("Mounted inode has i_mount=0\n"); +! for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) + if (inode->i_dev==dev && inode->i_count) + if (inode == sb->s_mounted && inode->i_count == 1) + continue; +*************** +*** 195,202 **** + sb->s_covered = NULL; + iput(sb->s_mounted); + sb->s_mounted = NULL; +! put_super(dev); +! sync_dev(dev); + return 0; + } + +--- 171,178 ---- + sb->s_covered = NULL; + iput(sb->s_mounted); + sb->s_mounted = NULL; +! put_super(dev); +! sync_dev(dev); + return 0; + } + +*************** +*** 224,231 **** + iput(dir_i); + return -EPERM; + } +! if (!(sb=read_super(dev))) { + iput(dir_i); + return -EBUSY; + } + if (sb->s_covered) { +--- 200,211 ---- + iput(dir_i); + return -EPERM; + } +! if (dir_i->i_mount) { + iput(dir_i); ++ return -EPERM; ++ } ++ if (!(sb=read_super(dev,"minix",NULL))) { ++ iput(dir_i); + return -EBUSY; + } + if (sb->s_covered) { +*************** +*** 232,248 **** + iput(dir_i); + return -EBUSY; + } +! if (dir_i->i_mount) { +! iput(dir_i); +! return -EPERM; +! } +! if (!(sb->s_mounted = iget(dev,MINIX_ROOT_INO))) { +! iput(dir_i); +! return -EPERM; +! } +! sb->s_covered=dir_i; +! dir_i->i_mount=1; +! dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */ + return 0; /* we do that in umount */ + } + +--- 212,220 ---- + iput(dir_i); + return -EBUSY; + } +! sb->s_covered = dir_i; +! dir_i->i_mount = 1; +! dir_i->i_dirt = 1; /* NOTE! we don't iput(dir_i) */ + return 0; /* we do that in umount */ + } + +*************** +*** 265,274 **** + p->s_lock = 0; + p->s_wait = NULL; + } +! if (!(p=read_super(ROOT_DEV))) + panic("Unable to mount root"); + if (!(mi=iget(ROOT_DEV,MINIX_ROOT_INO))) + panic("Unable to read root i-node"); + mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ + p->s_mounted = p->s_covered = mi; + current->pwd = mi; +--- 237,249 ---- + p->s_lock = 0; + p->s_wait = NULL; + } +! if (!(p=read_super(ROOT_DEV,"minix",NULL))) + panic("Unable to mount root"); ++ /*wait_for_keypress(); + if (!(mi=iget(ROOT_DEV,MINIX_ROOT_INO))) + panic("Unable to read root i-node"); ++ wait_for_keypress();*/ ++ mi=p->s_mounted; + mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ + p->s_mounted = p->s_covered = mi; + current->pwd = mi; +*** ../0.95a/linux/fs/namei.c Fri Mar 6 19:04:09 1992 +--- linux/fs/namei.c Fri Apr 3 16:15:56 1992 +*************** +*** 9,15 **** + */ + + #include +- #include + #include + #include + +--- 9,14 ---- +*************** +*** 249,255 **** + } + inode->i_atime = CURRENT_TIME; + if (flag & O_TRUNC) +! minix_truncate(inode); + *res_inode = inode; + return 0; + } +--- 248,255 ---- + } + inode->i_atime = CURRENT_TIME; + if (flag & O_TRUNC) +! if (inode->i_op && inode->i_op->truncate) +! inode->i_op->truncate(inode); + *res_inode = inode; + return 0; + } +*************** +*** 270,276 **** + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EPERM; + } + if (!dir->i_op || !dir->i_op->mknod) { + iput(dir); +--- 270,276 ---- + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EACCES; + } + if (!dir->i_op || !dir->i_op->mknod) { + iput(dir); +*************** +*** 293,299 **** + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EPERM; + } + if (!dir->i_op || !dir->i_op->mkdir) { + iput(dir); +--- 293,299 ---- + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EACCES; + } + if (!dir->i_op || !dir->i_op->mkdir) { + iput(dir); +*************** +*** 316,322 **** + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EPERM; + } + if (!dir->i_op || !dir->i_op->rmdir) { + iput(dir); +--- 316,322 ---- + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EACCES; + } + if (!dir->i_op || !dir->i_op->rmdir) { + iput(dir); +*************** +*** 335,345 **** + return -ENOENT; + if (!namelen) { + iput(dir); +! return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EPERM; + } + if (!dir->i_op || !dir->i_op->unlink) { + iput(dir); +--- 335,345 ---- + return -ENOENT; + if (!namelen) { + iput(dir); +! return -EPERM; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EACCES; + } + if (!dir->i_op || !dir->i_op->unlink) { + iput(dir); +*************** +*** 356,369 **** + + dir = dir_namei(newname,&namelen,&basename, NULL); + if (!dir) +! return -EACCES; + if (!namelen) { + iput(dir); +! return -EPERM; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EPERM; + } + if (!dir->i_op || !dir->i_op->symlink) { + iput(dir); +--- 356,369 ---- + + dir = dir_namei(newname,&namelen,&basename, NULL); + if (!dir) +! return -ENOENT; + if (!namelen) { + iput(dir); +! return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EACCES; + } + if (!dir->i_op || !dir->i_op->symlink) { + iput(dir); +*** ../0.95a/linux/fs/ioctl.c Thu Feb 20 17:01:12 1992 +--- linux/fs/ioctl.c Tue Mar 31 20:52:08 1992 +*************** +*** 10,15 **** +--- 10,16 ---- + + #include + ++ extern int hd_ioctl(int dev, int cmd, int arg); + extern int tty_ioctl(int dev, int cmd, int arg); + extern int pipe_ioctl(struct inode *pino, int cmd, int arg); + +*************** +*** 21,27 **** + NULL, /* nodev */ + NULL, /* /dev/mem */ + NULL, /* /dev/fd */ +! NULL, /* /dev/hd */ + tty_ioctl, /* /dev/ttyx */ + tty_ioctl, /* /dev/tty */ + NULL, /* /dev/lp */ +--- 22,28 ---- + NULL, /* nodev */ + NULL, /* /dev/mem */ + NULL, /* /dev/fd */ +! hd_ioctl, /* /dev/hd */ + tty_ioctl, /* /dev/ttyx */ + tty_ioctl, /* /dev/tty */ + NULL, /* /dev/lp */ +*** ../0.95a/linux/fs/pipe.c Fri Mar 6 15:04:16 1992 +--- linux/fs/pipe.c Fri Mar 27 11:18:57 1992 +*************** +*** 41,47 **** + put_fs_byte(((char *)inode->i_size)[size++],buf++); + } + wake_up(& PIPE_WRITE_WAIT(*inode)); +! return read; + } + + int pipe_write(struct inode * inode, struct file * filp, char * buf, int count) +--- 41,47 ---- + put_fs_byte(((char *)inode->i_size)[size++],buf++); + } + wake_up(& PIPE_WRITE_WAIT(*inode)); +! return read?read:-EAGAIN; + } + + int pipe_write(struct inode * inode, struct file * filp, char * buf, int count) +*** ../0.95a/linux/fs/minix/Makefile Thu Mar 5 23:36:47 1992 +--- linux/fs/minix/Makefile Sat Apr 4 17:33:13 1992 +*************** +*** 1,10 **** + AR =ar + AS =as +- CC =gcc + LD =ld +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ +! -nostdinc -I../../include +! CPP =gcc -E -nostdinc -I../../include + + .c.s: + $(CC) $(CFLAGS) \ +--- 1,17 ---- ++ # ++ # Makefile for the linux minix-filesystem routines. ++ # ++ # 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). ++ # ++ # Note 2! The CFLAGS definitions are now in the main makefile... ++ + AR =ar + AS =as + LD =ld +! CC =gcc -nostdinc -I../../include +! CPP =cpp -nostdinc -I../../include + + .c.s: + $(CC) $(CFLAGS) \ +*************** +*** 32,43 **** + ### 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 ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/linux/minix_fs.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +--- 39,52 ---- + ### 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/sys/dirent.h ../../include/limits.h \ +! ../../include/linux/mm.h ../../include/linux/kernel.h \ +! ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/linux/minix_fs.h + file_dev.o : file_dev.c ../../include/errno.h ../../include/fcntl.h \ +! ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \ +! ../../include/sys/stat.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/linux/mm.h ../../include/linux/kernel.h \ + ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +*************** +*** 46,59 **** + inode.o : inode.c ../../include/string.h ../../include/sys/stat.h \ + ../../include/sys/types.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/linux/mm.h ../../include/linux/kernel.h \ +! ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/linux/minix_fs.h ../../include/asm/system.h + minix_op.o : minix_op.c ../../include/linux/fs.h ../../include/sys/types.h \ + ../../include/linux/minix_fs.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/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/minix_fs.h \ +--- 55,71 ---- + inode.o : inode.c ../../include/string.h ../../include/sys/stat.h \ + ../../include/sys/types.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/linux/minix_fs.h \ +! ../../include/asm/system.h + minix_op.o : minix_op.c ../../include/linux/fs.h ../../include/sys/types.h \ ++ ../../include/sys/dirent.h ../../include/limits.h \ + ../../include/linux/minix_fs.h + namei.o : namei.c ../../include/linux/sched.h ../../include/linux/head.h \ +! ../../include/linux/fs.h ../../include/sys/types.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/minix_fs.h \ +*************** +*** 61,69 **** + ../../include/errno.h ../../include/const.h ../../include/sys/stat.h + truncate.o : truncate.c ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/types.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/linux/minix_fs.h \ +! ../../include/linux/tty.h ../../include/termios.h ../../include/errno.h \ +! ../../include/fcntl.h ../../include/sys/stat.h +--- 73,82 ---- + ../../include/errno.h ../../include/const.h ../../include/sys/stat.h + truncate.o : truncate.c ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \ +! ../../include/linux/mm.h ../../include/linux/kernel.h \ +! ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/linux/minix_fs.h ../../include/linux/tty.h \ +! ../../include/termios.h ../../include/errno.h ../../include/fcntl.h \ +! ../../include/sys/stat.h +*** ../0.95a/linux/fs/minix/inode.c Mon Mar 2 01:15:17 1992 +--- linux/fs/minix/inode.c Fri Apr 3 16:20:06 1992 +*************** +*** 13,27 **** + #include + #include + +! static int _bmap(struct 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_data[block]) + if (inode->i_data[block]=minix_new_block(inode->i_dev)) { +--- 13,112 ---- + #include + #include + +! int sync_dev(int dev); +! +! void minix_put_super(struct super_block *sb) + { ++ int i; ++ ++ lock_super(sb); ++ sb->s_dev = 0; ++ for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++) ++ brelse(sb->s_imap[i]); ++ for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++) ++ brelse(sb->s_zmap[i]); ++ free_super(sb); ++ return; ++ } ++ ++ static struct super_operations minix_sops = { ++ minix_read_inode, ++ minix_put_super ++ }; ++ ++ struct super_block *minix_read_super(struct super_block *s,void *data) ++ { ++ struct buffer_head *bh; ++ int i,dev=s->s_dev,block; ++ ++ lock_super(s); ++ if (!(bh = bread(dev,1))) { ++ s->s_dev=0; ++ free_super(s); ++ printk("bread failed\n"); ++ return NULL; ++ } ++ *((struct minix_super_block *) s) = ++ *((struct minix_super_block *) bh->b_data); ++ brelse(bh); ++ if (s->s_magic != MINIX_SUPER_MAGIC) { ++ s->s_dev = 0; ++ free_super(s); ++ printk("magic match failed\n"); ++ return NULL; ++ } ++ for (i=0;i < MINIX_I_MAP_SLOTS;i++) ++ s->s_imap[i] = NULL; ++ for (i=0;i < MINIX_Z_MAP_SLOTS;i++) ++ s->s_zmap[i] = NULL; ++ block=2; ++ for (i=0 ; i < s->s_imap_blocks ; i++) ++ if (s->s_imap[i]=bread(dev,block)) ++ block++; ++ else ++ break; ++ for (i=0 ; i < s->s_zmap_blocks ; i++) ++ if (s->s_zmap[i]=bread(dev,block)) ++ block++; ++ else ++ break; ++ if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) { ++ for(i=0;is_imap[i]); ++ for(i=0;is_zmap[i]); ++ s->s_dev=0; ++ free_super(s); ++ printk("block failed\n"); ++ return NULL; ++ } ++ s->s_imap[0]->b_data[0] |= 1; ++ s->s_zmap[0]->b_data[0] |= 1; ++ free_super(s); ++ /* set up enough so that it can read an inode */ ++ s->s_dev = dev; ++ s->s_op = &minix_sops; ++ if (!(s->s_mounted = iget(dev,MINIX_ROOT_INO))) { ++ s->s_dev=0; ++ printk("get root inode failed\n"); ++ return NULL; ++ } ++ return s; ++ } ++ ++ static int _minix_bmap(struct inode * inode,int block,int create) ++ { + struct buffer_head * bh; + int i; + +! if (block<0) { +! printk("_minix_bmap: block<0"); +! return 0; +! } +! if (block >= 7+512+512*512) { +! printk("_minix_bmap: block>big"); +! return 0; +! } + if (block<7) { + if (create && !inode->i_data[block]) + if (inode->i_data[block]=minix_new_block(inode->i_dev)) { +*************** +*** 83,94 **** + + int minix_bmap(struct inode * inode,int block) + { +! return _bmap(inode,block,0); + } + + int minix_create_block(struct inode * inode, int block) + { +! return _bmap(inode,block,1); + } + + void minix_read_inode(struct inode * inode) +--- 168,179 ---- + + int minix_bmap(struct inode * inode,int block) + { +! return _minix_bmap(inode,block,0); + } + + int minix_create_block(struct inode * inode, int block) + { +! return _minix_bmap(inode,block,1); + } + + void minix_read_inode(struct inode * inode) +*** ../0.95a/linux/fs/minix/namei.c Tue Mar 3 19:39:35 1992 +--- linux/fs/minix/namei.c Fri Apr 3 16:11:22 1992 +*************** +*** 15,24 **** + #include + #include + +- extern int permission(struct inode * inode,int mask); +- extern struct inode * _namei(const char * filename, struct inode * base, +- int follow_links); +- + /* + * comment out this line if you want names > MINIX_NAME_LEN chars to be + * truncated. Else they will be disallowed. +--- 15,20 ---- +*************** +*** 89,95 **** + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; +! if (!(block = bmap(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK)) || + !(bh = bread(dir->i_dev,block))) { + i += MINIX_DIR_ENTRIES_PER_BLOCK; + continue; +--- 85,91 ---- + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; +! if (!(block = minix_bmap(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK)) || + !(bh = bread(dir->i_dev,block))) { + i += MINIX_DIR_ENTRIES_PER_BLOCK; + continue; +*************** +*** 398,404 **** + while (nr= (void *) (bh->b_data+BLOCK_SIZE)) { + brelse(bh); +! block=bmap(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK); + if (!block) { + nr += MINIX_DIR_ENTRIES_PER_BLOCK; + continue; +--- 394,400 ---- + while (nr= (void *) (bh->b_data+BLOCK_SIZE)) { + brelse(bh); +! block = minix_bmap(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK); + if (!block) { + nr += MINIX_DIR_ENTRIES_PER_BLOCK; + continue; +*** ../0.95a/linux/fs/minix/minix_op.c Tue Mar 3 00:18:39 1992 +--- linux/fs/minix/minix_op.c Fri Apr 3 20:19:03 1992 +*************** +*** 7,12 **** +--- 7,18 ---- + #include + #include + ++ void minix_put_inode(struct inode *inode) ++ { ++ minix_truncate(inode); ++ minix_free_inode(inode); ++ } ++ + /* + * These are the low-level inode operations for minix filesystem inodes. + */ +*************** +*** 23,38 **** + minix_readlink, + minix_open, + minix_release, +! minix_follow_link + }; + + /* +! * We have just NULL's here: the current defaults are ok for + * the minix filesystem. + */ + struct file_operations minix_file_operations = { + NULL, /* lseek */ + NULL, /* read */ +! NULL /* write */ + }; + +--- 29,49 ---- + minix_readlink, + minix_open, + minix_release, +! minix_follow_link, +! minix_bmap, +! minix_truncate, +! minix_write_inode, +! minix_put_inode + }; + + /* +! * We have mostly NULL's here: the current defaults are ok for + * the minix filesystem. + */ + struct file_operations minix_file_operations = { + NULL, /* lseek */ + NULL, /* read */ +! NULL, /* write */ +! minix_readdir + }; + +*** ../0.95a/linux/fs/minix/file_dev.c Tue Mar 17 03:41:53 1992 +--- linux/fs/minix/file_dev.c Fri Apr 3 21:35:21 1992 +*************** +*** 6,11 **** +--- 6,13 ---- + + #include + #include ++ #include ++ #include + + #include + #include +*************** +*** 15,20 **** +--- 17,64 ---- + #define MIN(a,b) (((a)<(b))?(a):(b)) + #define MAX(a,b) (((a)>(b))?(a):(b)) + ++ int minix_readdir(struct inode * inode, struct file * filp, struct dirent * dirent) ++ { ++ unsigned int block,offset,i; ++ char c; ++ struct buffer_head * bh; ++ struct minix_dir_entry * de; ++ ++ if (!S_ISDIR(inode->i_mode)) ++ return -EBADF; ++ if (filp->f_pos & 15) ++ return -EBADF; ++ while (filp->f_pos < inode->i_size) { ++ offset = filp->f_pos & 1023; ++ block = minix_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS); ++ if (!block || !(bh = bread(inode->i_dev,block))) { ++ filp->f_pos += 1024-offset; ++ continue; ++ } ++ de = (struct minix_dir_entry *) (offset + bh->b_data); ++ while (offset < 1024 && filp->f_pos < inode->i_size) { ++ offset += 16; ++ filp->f_pos += 16; ++ if (de->inode) { ++ for (i = 0; i < 14; i++) ++ if (c = de->name[i]) ++ put_fs_byte(c,i+dirent->d_name); ++ else ++ break; ++ if (i) { ++ put_fs_long(de->inode,&dirent->d_ino); ++ put_fs_byte(0,i+dirent->d_name); ++ put_fs_word(i,&dirent->d_reclen); ++ return i; ++ } ++ } ++ de++; ++ } ++ brelse(bh); ++ } ++ return 0; ++ } ++ + int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count) + { + int read,left,chars,nr; +*************** +*** 28,34 **** + left = count; + read = 0; + while (left > 0) { +! if (nr = bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS)) { + if (!(bh=bread(inode->i_dev,nr))) + return read?read:-EIO; + } else +--- 72,78 ---- + left = count; + read = 0; + while (left > 0) { +! if (nr = minix_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS)) { + if (!(bh=bread(inode->i_dev,nr))) + return read?read:-EIO; + } else +*************** +*** 98,104 **** + if (!(filp->f_flags & O_APPEND)) { + filp->f_pos = pos; + inode->i_ctime = CURRENT_TIME; +- inode->i_dirt = 1; + } + return written; + } +--- 142,148 ---- + if (!(filp->f_flags & O_APPEND)) { + filp->f_pos = pos; + inode->i_ctime = CURRENT_TIME; + } ++ inode->i_dirt = 1; + return written; + } +*** ../0.95a/linux/kernel/Makefile Thu Mar 5 23:36:55 1992 +--- linux/kernel/Makefile Sat Apr 4 17:33:20 1992 +*************** +*** 5,23 **** + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # + +- # gcc2 doesn't have these: +- #GCC_OPT = -fcombine-regs +- + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) \ +! -finline-functions -nostdinc -I../include +! CPP =gcc -E -nostdinc -I../include + + .c.s: + $(CC) $(CFLAGS) \ + -S -o $*.s $< +--- 5,20 ---- + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # ++ # Note 2! The CFLAGS definitions are now in the main makefile... + + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc -nostdinc -I../include +! CPP =cpp -nostdinc -I../include + ++ + .c.s: + $(CC) $(CFLAGS) \ + -S -o $*.s $< +*************** +*** 35,40 **** +--- 32,40 ---- + $(LD) -r -o kernel.o $(OBJS) + sync + ++ sched.o: sched.c ++ $(CC) $(CFLAGS) -fno-omit-frame-pointer -c $< ++ + clean: + rm -f core *.o *.a tmp_make keyboard.s + for i in *.c;do rm -f `basename $$i .c`.s;done +*************** +*** 53,103 **** + ### Dependencies: + exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \ + ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \ +! ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.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/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h + mktime.s mktime.o : mktime.c ../include/time.h + panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/linux/mm.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h + printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \ + ../include/linux/kernel.h + ptrace.s ptrace.o : ptrace.c ../include/linux/head.h ../include/linux/kernel.h \ + ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/linux/mm.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/errno.h ../include/asm/segment.h ../include/asm/system.h \ +! ../include/sys/ptrace.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/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/linux/timer.h ../include/linux/sys.h ../include/linux/fdreg.h \ +! ../include/asm/system.h ../include/asm/io.h ../include/asm/segment.h \ +! ../include/errno.h + signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/segment.h ../include/sys/wait.h ../include/errno.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/kernel.h ../include/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/linux/tty.h ../include/termios.h \ +! ../include/linux/config.h ../include/asm/segment.h ../include/sys/times.h \ +! ../include/sys/utsname.h ../include/string.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/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/system.h ../include/asm/segment.h \ +! ../include/asm/io.h ../include/errno.h + vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h +--- 53,109 ---- + ### Dependencies: + exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \ + ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \ +! ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \ +! ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.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/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/segment.h ../include/asm/system.h + mktime.s mktime.o : mktime.c ../include/time.h + panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h + printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \ + ../include/linux/kernel.h + ptrace.s ptrace.o : ptrace.c ../include/linux/head.h ../include/linux/kernel.h \ + ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/errno.h \ +! ../include/asm/segment.h ../include/asm/system.h ../include/sys/ptrace.h + sched.s sched.o : sched.c ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \ +! ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/linux/timer.h \ +! ../include/linux/sys.h ../include/linux/fdreg.h ../include/asm/system.h \ +! ../include/asm/io.h ../include/asm/segment.h ../include/errno.h + signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \ +! ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \ +! ../include/sys/wait.h ../include/errno.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/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/linux/tty.h ../include/termios.h ../include/linux/config.h \ +! ../include/asm/segment.h ../include/sys/times.h ../include/sys/utsname.h \ +! ../include/string.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/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/system.h ../include/asm/segment.h ../include/asm/io.h \ +! ../include/errno.h + vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h +*** ../0.95a/linux/kernel/sched.c Sat Mar 14 16:55:48 1992 +--- linux/kernel/sched.c Tue Mar 24 00:57:35 1992 +*************** +*** 46,57 **** + + void show_state(void) + { + int i; + + printk("\rTask-info:\n\r"); +! for (i=0;istate == TASK_INTERRUPTIBLE || p->state == TASK_RUNNING) + p->state = TASK_STOPPED; +- +- if (p == current) +- schedule(); + } + return 0; + } +--- 48,53 ---- +*************** +*** 218,232 **** + int sys_kill(int pid,int sig) + { + struct task_struct **p = NR_TASKS + task; +! int err, retval = 0; + + if (!pid) +! return(kill_pg(current->pid,sig,0)); + if (pid == -1) { + while (--p > &FIRST_TASK) +! if (err = send_sig(sig,*p,0)) +! retval = err; +! return(retval); + } + if (pid < 0) + return(kill_pg(-pid,sig,0)); +--- 215,232 ---- + int sys_kill(int pid,int sig) + { + struct task_struct **p = NR_TASKS + task; +! int err, retval = 0, count = 0; + + if (!pid) +! return(kill_pg(current->pgrp,sig,0)); + if (pid == -1) { + while (--p > &FIRST_TASK) +! if ((*p)->pid > 1 && *p != current) { +! ++count; +! if ((err = send_sig(sig,*p,0)) != -EPERM) +! retval = err; +! } +! return(count ? retval : -ESRCH); + } + if (pid < 0) + return(kill_pg(-pid,sig,0)); +*************** +*** 292,297 **** +--- 292,298 ---- + current->library = NULL; + current->state = TASK_ZOMBIE; + current->exit_code = code; ++ current->rss = 0; + /* + * Check to see if any process groups have become orphaned + * as a result of our exiting, and if they have any stopped +*************** +*** 413,420 **** + p->exit_code = 0; + return p->pid; + case TASK_ZOMBIE: +! current->cutime += p->utime; +! current->cstime += p->stime; + flag = p->pid; + if (stat_addr) + put_fs_long(p->exit_code, stat_addr); +--- 414,423 ---- + p->exit_code = 0; + return p->pid; + case TASK_ZOMBIE: +! current->cutime += p->utime + p->cutime; +! current->cstime += p->stime + p->cstime; +! current->cmin_flt += p->min_flt + p->cmin_flt; +! current->cmaj_flt += p->maj_flt + p->cmaj_flt; + flag = p->pid; + if (stat_addr) + put_fs_long(p->exit_code, stat_addr); +*** ../0.95a/linux/kernel/fork.c Wed Mar 4 14:11:24 1992 +--- linux/kernel/fork.c Wed Apr 1 01:27:04 1992 +*************** +*** 112,117 **** +--- 112,119 ---- + p->leader = 0; /* process leadership doesn't inherit */ + p->utime = p->stime = 0; + p->cutime = p->cstime = 0; ++ p->min_flt = p->maj_flt = 0; ++ p->cmin_flt = p->cmaj_flt = 0; + p->start_time = jiffies; + p->tss.back_link = 0; + p->tss.esp0 = PAGE_SIZE + (long) p; +*** ../0.95a/linux/kernel/sys.c Thu Feb 27 18:42:09 1992 +--- linux/kernel/sys.c Wed Apr 1 01:27:27 1992 +*************** +*** 457,467 **** +--- 457,471 ---- + r.ru_utime.tv_usec = CT_TO_USECS(current->utime); + r.ru_stime.tv_sec = CT_TO_SECS(current->stime); + r.ru_stime.tv_usec = CT_TO_USECS(current->stime); ++ r.ru_minflt = current->min_flt; ++ r.ru_majflt = current->maj_flt; + } else { + r.ru_utime.tv_sec = CT_TO_SECS(current->cutime); + r.ru_utime.tv_usec = CT_TO_USECS(current->cutime); + r.ru_stime.tv_sec = CT_TO_SECS(current->cstime); + r.ru_stime.tv_usec = CT_TO_USECS(current->cstime); ++ r.ru_minflt = current->cmin_flt; ++ r.ru_majflt = current->cmaj_flt; + } + lp = (unsigned long *) &r; + lpend = (unsigned long *) (&r+1); +*** ../0.95a/linux/kernel/chr_drv/keyboard.S Sun Mar 15 02:43:22 1992 +--- linux/kernel/chr_drv/keyboard.S Sat Apr 4 16:30:36 1992 +*************** +*** 19,25 **** + * KBD_UK for British extended keyboard + * KBD_DK for Danish keyboard + */ +- #define KBD_FINNISH + + .text + .globl _hard_reset_now +--- 19,24 ---- +*** ../0.95a/linux/kernel/chr_drv/Makefile Thu Mar 5 23:37:00 1992 +--- linux/kernel/chr_drv/Makefile Sat Apr 4 17:33:24 1992 +*************** +*** 5,22 **** + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # + +- # gcc2 doesn't understand this option: +- #GCC_OPT = -fcombine-regs +- + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) \ +! -finline-functions -nostdinc -I../../include +! CPP =gcc -E -nostdinc -I../../include + + .c.s: + $(CC) $(CFLAGS) \ +--- 5,20 ---- + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # ++ # Note 2! The CFLAGS definitions are now inherited from the ++ # parent makes.. ++ # + + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc -nostdinc -I../../include +! CPP =cpp -nostdinc -I../../include + + .c.s: + $(CC) $(CFLAGS) \ +*************** +*** 35,41 **** + sync + + keyboard.s: keyboard.S +! $(CPP) -traditional keyboard.S -o keyboard.s + + clean: + rm -f core *.o *.a tmp_make keyboard.s +--- 33,39 ---- + sync + + keyboard.s: keyboard.S +! $(CPP) $(KEYBOARD) -traditional keyboard.S -o keyboard.s + + clean: + rm -f core *.o *.a tmp_make keyboard.s +*************** +*** 50,78 **** + ### 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/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/linux/timer.h \ +! ../../include/linux/tty.h ../../include/termios.h \ +! ../../include/linux/config.h ../../include/asm/io.h \ + ../../include/asm/system.h ../../include/asm/segment.h \ + ../../include/string.h ../../include/errno.h + pty.s pty.o : pty.c ../../include/linux/tty.h ../../include/termios.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/asm/system.h ../../include/asm/io.h + serial.s serial.o : serial.c ../../include/linux/tty.h ../../include/termios.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/linux/timer.h ../../include/asm/system.h \ +! ../../include/asm/io.h + tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \ + ../../include/signal.h ../../include/sys/types.h ../../include/unistd.h \ + ../../include/sys/stat.h ../../include/sys/time.h ../../include/time.h \ +--- 48,77 ---- + ### Dependencies: + console.s console.o : console.c ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \ +! ../../include/linux/mm.h ../../include/linux/kernel.h \ +! ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/linux/timer.h ../../include/linux/tty.h \ +! ../../include/termios.h ../../include/linux/config.h ../../include/asm/io.h \ + ../../include/asm/system.h ../../include/asm/segment.h \ + ../../include/string.h ../../include/errno.h + pty.s pty.o : pty.c ../../include/linux/tty.h ../../include/termios.h \ + ../../include/sys/types.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/asm/system.h \ +! ../../include/asm/io.h + serial.s serial.o : serial.c ../../include/linux/tty.h ../../include/termios.h \ + ../../include/sys/types.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/linux/timer.h \ +! ../../include/asm/system.h ../../include/asm/io.h + tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \ + ../../include/signal.h ../../include/sys/types.h ../../include/unistd.h \ + ../../include/sys/stat.h ../../include/sys/time.h ../../include/time.h \ +*************** +*** 80,93 **** + ../../include/sys/param.h ../../include/sys/resource.h \ + ../../include/utime.h ../../include/fcntl.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 ../../include/asm/system.h + tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h ../../include/linux/tty.h \ + ../../include/asm/io.h ../../include/asm/segment.h \ + ../../include/asm/system.h +--- 79,94 ---- + ../../include/sys/param.h ../../include/sys/resource.h \ + ../../include/utime.h ../../include/fcntl.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/linux/tty.h \ +! ../../include/termios.h ../../include/asm/segment.h \ +! ../../include/asm/system.h + tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.h \ + ../../include/sys/types.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/linux/tty.h \ + ../../include/asm/io.h ../../include/asm/segment.h \ + ../../include/asm/system.h +*** ../0.95a/linux/kernel/chr_drv/console.c Fri Mar 13 00:37:07 1992 +--- linux/kernel/chr_drv/console.c Thu Mar 19 21:15:03 1992 +*************** +*** 456,462 **** + p++; + } + sti(); +! copy_to_cooked(tty); + } + + static void insert_char(int currcons) +--- 456,462 ---- + p++; + } + sti(); +! TTY_READ_FLUSH(tty); + } + + static void insert_char(int currcons) +*************** +*** 823,829 **** + + void do_keyboard_interrupt(void) + { +! copy_to_cooked(TTY_TABLE(0)); + timer_active &= ~(1<stopped = 1; +! TTY_WRITE(tty); + return 0; + case TCOON: + tty->stopped = 0; +! TTY_WRITE(tty); + return 0; + case TCIOFF: + if (STOP_CHAR(tty)) +--- 260,270 ---- + switch (arg) { + case TCOOFF: + tty->stopped = 1; +! TTY_WRITE_FLUSH(tty); + return 0; + case TCOON: + tty->stopped = 0; +! TTY_WRITE_FLUSH(tty); + return 0; + case TCIOFF: + if (STOP_CHAR(tty)) +*** ../0.95a/linux/kernel/chr_drv/tty_io.c Tue Mar 17 22:46:46 1992 +--- linux/kernel/chr_drv/tty_io.c Sat Apr 4 02:47:57 1992 +*************** +*** 129,141 **** + printk("copy_to_cooked: missing queues\n\r"); + return; + } +- cli(); +- if (tty->busy) { +- sti(); +- return; +- } +- tty->busy = 1; +- sti(); + while (1) { + if (EMPTY(tty->read_q)) + break; +--- 129,134 ---- +*************** +*** 167,172 **** +--- 160,166 ---- + if (c<32) + PUTCH(127,tty->write_q); + PUTCH(127,tty->write_q); ++ TTY_WRITE_FLUSH(tty); + } + DEC(tty->secondary->head); + } +*************** +*** 183,188 **** +--- 177,183 ---- + if (c<32) + PUTCH(127,tty->write_q); + PUTCH(127,tty->write_q); ++ TTY_WRITE_FLUSH(tty); + } + DEC(tty->secondary->head); + continue; +*************** +*** 197,202 **** +--- 192,198 ---- + if ((START_CHAR(tty) != _POSIX_VDISABLE) && + (c==START_CHAR(tty))) { + tty->stopped=0; ++ TTY_WRITE_FLUSH(tty); + continue; + } + } +*************** +*** 232,242 **** + PUTCH(c,tty->write_q); + } + PUTCH(c,tty->secondary); + } +! tty->write(tty); +! tty->busy = 0; + if (!EMPTY(tty->secondary)) + wake_up(&tty->secondary->proc_list); + } + + /* +--- 228,240 ---- + PUTCH(c,tty->write_q); + } + PUTCH(c,tty->secondary); ++ TTY_WRITE_FLUSH(tty); + } +! TTY_WRITE_FLUSH(tty); + if (!EMPTY(tty->secondary)) + wake_up(&tty->secondary->proc_list); ++ if (LEFT(tty->write_q) > TTY_BUF_SIZE/2) ++ wake_up(&tty->write_q->proc_list); + } + + /* +*************** +*** 305,314 **** + time = current->timeout = 0; + if (minimum>nr) + minimum = nr; +! copy_to_cooked(tty); + while (nr>0) { + if (other_tty && other_tty->write) +! TTY_WRITE(other_tty); + cli(); + if (EMPTY(tty->secondary) || (L_CANON(tty) && + !FULL(tty->read_q) && !tty->secondary->data)) { +--- 303,312 ---- + time = current->timeout = 0; + if (minimum>nr) + minimum = nr; +! TTY_READ_FLUSH(tty); + while (nr>0) { + if (other_tty && other_tty->write) +! TTY_WRITE_FLUSH(other_tty); + cli(); + if (EMPTY(tty->secondary) || (L_CANON(tty) && + !FULL(tty->read_q) && !tty->secondary->data)) { +*************** +*** 320,326 **** + break; + interruptible_sleep_on(&tty->secondary->proc_list); + sti(); +! copy_to_cooked(tty); + continue; + } + sti(); +--- 318,324 ---- + break; + interruptible_sleep_on(&tty->secondary->proc_list); + sti(); +! TTY_READ_FLUSH(tty); + continue; + } + sti(); +*************** +*** 398,404 **** + cr_flag = 0; + PUTCH(c,tty->write_q); + } +! TTY_WRITE(tty); + if (nr>0) + schedule(); + } +--- 396,402 ---- + cr_flag = 0; + PUTCH(c,tty->write_q); + } +! TTY_WRITE_FLUSH(tty); + if (nr>0) + schedule(); + } +*** ../0.95a/linux/kernel/chr_drv/serial.c Sat Mar 14 20:16:21 1992 +--- linux/kernel/chr_drv/serial.c Thu Mar 19 21:15:03 1992 +*************** +*** 26,47 **** + + static void com1_timer(void) + { +! copy_to_cooked(tty_table+64); + } + + static void com2_timer(void) + { +! copy_to_cooked(tty_table+65); + } + + static void com3_timer(void) + { +! copy_to_cooked(tty_table+66); + } + + static void com4_timer(void) + { +! copy_to_cooked(tty_table+67); + } + + static inline void do_rs_write(unsigned int port) +--- 26,47 ---- + + static void com1_timer(void) + { +! TTY_READ_FLUSH(tty_table+64); + } + + static void com2_timer(void) + { +! TTY_READ_FLUSH(tty_table+65); + } + + static void com3_timer(void) + { +! TTY_READ_FLUSH(tty_table+66); + } + + static void com4_timer(void) + { +! TTY_READ_FLUSH(tty_table+67); + } + + static inline void do_rs_write(unsigned int port) +*** ../0.95a/linux/kernel/chr_drv/pty.c Sat Jan 11 01:56:45 1992 +--- linux/kernel/chr_drv/pty.c Thu Mar 19 21:15:03 1992 +*************** +*** 25,31 **** + if (FULL(to->read_q)) { + if (FULL(to->secondary)) + break; +! copy_to_cooked(to); + continue; + } + GETCH(from->write_q,c); +--- 25,31 ---- + if (FULL(to->read_q)) { + if (FULL(to->secondary)) + break; +! TTY_READ_FLUSH(to); + continue; + } + GETCH(from->write_q,c); +*************** +*** 33,39 **** + if (current->signal & ~current->blocked) + break; + } +! copy_to_cooked(to); + wake_up(&from->write_q->proc_list); + } + +--- 33,39 ---- + if (current->signal & ~current->blocked) + break; + } +! TTY_READ_FLUSH(to); + wake_up(&from->write_q->proc_list); + } + +*** ../0.95a/linux/kernel/math/Makefile Wed Mar 4 06:14:15 1992 +--- linux/kernel/math/Makefile Sat Apr 4 17:06:02 1992 +*************** +*** 10,27 **** + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ +! -finline-functions -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 = math_emulate.o error.o convert.o ea.o get_put.o \ +--- 10,25 ---- + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc -nostdinc -I../../include +! CPP =cpp -nostdinc -I../../include + + .c.s: +! $(CC) $(CFLAGS) $(MATH_EMULATION) \ + -S -o $*.s $< + .s.o: + $(AS) -c -o $*.o $< + .c.o: +! $(CC) $(CFLAGS) $(MATH_EMULATION) \ + -c -o $*.o $< + + OBJS = math_emulate.o error.o convert.o ea.o get_put.o \ +*** ../0.95a/linux/kernel/math/math_emulate.c Thu Mar 5 22:32:44 1992 +--- linux/kernel/math/math_emulate.c Sat Apr 4 17:05:42 1992 +*************** +*** 30,37 **** + * hide most of the 387-specific things here. + */ + +- #include +- + #ifdef KERNEL_MATH_EMULATION + + #include +--- 30,35 ---- +*************** +*** 172,183 **** + real_to_real(&tmp,&ST(0)); + return; + case 0x1a: +! fcom(PST(code & 7),&tmp); +! real_to_real(&tmp,&ST(0)); + return; + case 0x1b: +! fcom(PST(code & 7),&tmp); +! real_to_real(&tmp,&ST(0)); + fpop(); + return; + case 0x1c: +--- 170,179 ---- + real_to_real(&tmp,&ST(0)); + return; + case 0x1a: +! fcom(PST(code & 7),PST(0)); + return; + case 0x1b: +! fcom(PST(code & 7),PST(0)); + fpop(); + return; + case 0x1c: +*************** +*** 201,207 **** + return; + case 0x38: + fpush(); +! ST(0) = ST((code & 7)+1); + return; + case 0x39: + fxchg(&ST(0),&ST(code & 7)); +--- 197,203 ---- + return; + case 0x38: + fpush(); +! ST(0) = ST((code+1) & 7); + return; + case 0x39: + fxchg(&ST(0),&ST(code & 7)); +*** ../0.95a/linux/kernel/blk_drv/hd.c Sun Mar 15 20:46:53 1992 +--- linux/kernel/blk_drv/hd.c Sat Apr 4 14:42:37 1992 +*************** +*** 16,21 **** +--- 16,23 ---- + * in the early extended-partition checks and added DM partitions + */ + ++ #include ++ + #include + #include + #include +*************** +*** 43,49 **** + static void bad_rw_intr(void); + + static int recalibrate = 0; +! static int reset = 1; + + /* + * This struct defines the HD's and their types. +--- 45,51 ---- + static void bad_rw_intr(void); + + static int recalibrate = 0; +! static int reset = 0; + + /* + * This struct defines the HD's and their types. +*************** +*** 77,104 **** + + static unsigned int current_minor; + + static void check_partition(unsigned int dev) + { +! int minor, i; + struct buffer_head *bh; + struct partition *p; + + if (!(bh = bread(dev,0))) { + printk("Unable to read partition table of device %04x\n",dev); + return; + } +! minor = current_minor; + if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { + p = 0x1BE + (void *)bh->b_data; +! for (i=0 ; i<4 ; i++,p++) { +! if (!(hd[i+minor].nr_sects = p->nr_sects)) + continue; +! hd[i+minor].start_sect = p->start_sect; + if ((current_minor & 0x3f) >= 60) + continue; + if (p->sys_ind == EXTENDED_PARTITION) { +! current_minor += 4; +! check_partition(0x0300 | (i+minor)); + } + } + /* +--- 79,181 ---- + + static unsigned int current_minor; + ++ /* ++ * Create devices for each logical partition in an extended partition. ++ * The logical partitions form a linked list, with each entry being ++ * a partition table with two entries. The first entry ++ * is the real data partition (with a start relative to the partition ++ * table start). The second is a pointer to the next logical partition ++ * (with a start relative to the entire extended partition). ++ * We do not create a Linux partition for the partition tables, but ++ * only for the actual data partitions. ++ */ ++ static void extended_partition(unsigned int dev) ++ { ++ struct buffer_head *bh; ++ struct partition *p; ++ unsigned long first_sector, this_sector; ++ ++ first_sector = hd[MINOR(dev)].start_sect; ++ this_sector = first_sector; ++ ++ while (1) { ++ if ((current_minor & 0x3f) >= 60) ++ return; ++ if (!(bh = bread(dev,0))) { ++ printk("Unable to read partition table of device %04x\n",dev); ++ return; ++ } ++ /* ++ * This block is from a device that we're about to stomp on. ++ * So make sure nobody thinks this block is usable. ++ */ ++ bh->b_dirt=0; ++ bh->b_uptodate=0; ++ if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { ++ p = 0x1BE + (void *)bh->b_data; ++ /* ++ * Process the first entry, which should be the real ++ * data partition. ++ */ ++ if (p->sys_ind == EXTENDED_PARTITION || ++ !(hd[current_minor].nr_sects = p->nr_sects)) ++ goto done; /* shouldn't happen */ ++ hd[current_minor].start_sect = this_sector + p->start_sect; ++ printk(" Logical part %d start %d size %d end %d\n\r", ++ current_minor, hd[current_minor].start_sect, ++ hd[current_minor].nr_sects, ++ hd[current_minor].start_sect + ++ hd[current_minor].nr_sects); ++ current_minor++; ++ p++; ++ /* ++ * Process the second entry, which should be a link ++ * to the next logical partition. Create a minor ++ * for this just long enough to get the next partition ++ * table. The minor will be reused for the real ++ * data partition. ++ */ ++ if (p->sys_ind != EXTENDED_PARTITION || ++ !(hd[current_minor].nr_sects = p->nr_sects)) ++ goto done; /* no more logicals in this partition */ ++ hd[current_minor].start_sect = first_sector + p->start_sect; ++ this_sector = first_sector + p->start_sect; ++ dev = 0x0300 | current_minor; ++ brelse(bh); ++ } else ++ goto done; ++ } ++ done: ++ brelse(bh); ++ } ++ + static void check_partition(unsigned int dev) + { +! int i, minor = current_minor; + struct buffer_head *bh; + struct partition *p; ++ unsigned long first_sector; + ++ first_sector = hd[MINOR(dev)].start_sect; + if (!(bh = bread(dev,0))) { + printk("Unable to read partition table of device %04x\n",dev); + return; + } +! printk("Drive %d:\n\r",minor >> 6); +! current_minor += 4; /* first "extra" minor */ + if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { + p = 0x1BE + (void *)bh->b_data; +! for (i=1 ; i<=4 ; minor++,i++,p++) { +! if (!(hd[minor].nr_sects = p->nr_sects)) + continue; +! hd[minor].start_sect = first_sector + p->start_sect; +! printk(" part %d start %d size %d end %d \n\r", i, +! hd[minor].start_sect, hd[minor].nr_sects, +! hd[minor].start_sect + hd[minor].nr_sects); + if ((current_minor & 0x3f) >= 60) + continue; + if (p->sys_ind == EXTENDED_PARTITION) { +! extended_partition(0x0300 | minor); + } + } + /* +*************** +*** 106,119 **** + */ + if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) { + p = 0x1BE + (void *)bh->b_data; +! for (i=4; i<16; i++) { + p--; + if ((current_minor & 0x3f) >= 60) + break; +! if (!(hd[current_minor+4].start_sect = p->start_sect)) + continue; +! hd[current_minor+4].nr_sects = p->nr_sects; +! current_minor++; + } + } + } else +--- 183,202 ---- + */ + if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) { + p = 0x1BE + (void *)bh->b_data; +! for (i = 4 ; i < 16 ; i++, current_minor++) { + p--; + if ((current_minor & 0x3f) >= 60) + break; +! if (!(p->start_sect && p->nr_sects)) + continue; +! hd[current_minor].start_sect = p->start_sect; +! hd[current_minor].nr_sects = p->nr_sects; +! printk(" DM part %d start %d size %d end %d\n\r", +! current_minor, +! hd[current_minor].start_sect, +! hd[current_minor].nr_sects, +! hd[current_minor].start_sect + +! hd[current_minor].nr_sects); + } + } + } else +*************** +*** 141,156 **** + hd_info[drive].sect = *(unsigned char *) (14+BIOS); + BIOS += 16; + } +- if (hd_info[1].cyl) +- NR_HD=2; +- else +- NR_HD=1; +- #endif +- for (i=0 ; ierrors >= MAX_ERRORS) + end_request(0); + if (CURRENT->errors > MAX_ERRORS/2) +*************** +*** 361,366 **** +--- 448,457 ---- + do_hd_request(); + } + ++ /* ++ * This is another of the error-routines I don't know what to do with. The ++ * best idea seems to just set reset, and start all over again. ++ */ + static void hd_times_out(void) + { + do_hd = NULL; +*************** +*** 367,379 **** + reset = 1; + if (!CURRENT) + return; +! printk("HD timeout"); + if (++CURRENT->errors >= MAX_ERRORS) + end_request(0); + do_hd_request(); + } + +! void do_hd_request(void) + { + int i,r; + unsigned int block,dev; +--- 458,471 ---- + reset = 1; + if (!CURRENT) + return; +! printk("HD timeout\n\r"); +! cli(); + if (++CURRENT->errors >= MAX_ERRORS) + end_request(0); + do_hd_request(); + } + +! static void do_hd_request(void) + { + int i,r; + unsigned int block,dev; +*************** +*** 434,437 **** +--- 526,553 ---- + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xbf,0xA1); + timer_table[HD_TIMER].fn = hd_times_out; ++ } ++ ++ int hd_ioctl(int dev, int cmd, int arg) ++ { ++ struct hd_geometry *loc = (void *) arg; ++ ++ if (!loc) ++ return -EINVAL; ++ dev = MINOR(dev) >> 6; ++ if (dev >= NR_HD) ++ return -EINVAL; ++ ++ switch (cmd) { ++ case HDIO_REQ: ++ put_fs_byte(hd_info[dev].head, ++ (char *) &loc->heads); ++ put_fs_byte(hd_info[dev].sect, ++ (char *) &loc->sectors); ++ put_fs_word(hd_info[dev].cyl, ++ (short *) &loc->cylinders); ++ return 0; ++ default: ++ return -EINVAL; ++ } + } +*** ../0.95a/linux/kernel/blk_drv/ll_rw_blk.c Fri Mar 6 03:04:44 1992 +--- linux/kernel/blk_drv/ll_rw_blk.c Sat Mar 21 12:42:01 1992 +*************** +*** 83,90 **** + req->bh->b_dirt = 0; + if (!(tmp = dev->current_request)) { + dev->current_request = req; +- sti(); + (dev->request_fn)(); + return; + } + for ( ; tmp->next ; tmp = tmp->next) { +--- 83,90 ---- + req->bh->b_dirt = 0; + if (!(tmp = dev->current_request)) { + dev->current_request = req; + (dev->request_fn)(); ++ sti(); + return; + } + for ( ; tmp->next ; tmp = tmp->next) { +*** ../0.95a/linux/kernel/blk_drv/Makefile Thu Mar 5 23:37:04 1992 +--- linux/kernel/blk_drv/Makefile Sat Apr 4 17:33:28 1992 +*************** +*** 5,19 **** + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # + + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ +! -finline-functions -nostdinc -I../../include +! CPP =gcc -E -nostdinc -I../../include + + .c.s: + $(CC) $(CFLAGS) \ +--- 5,20 ---- + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # ++ # Note 2! The CFLAGS definition is now inherited from the ++ # parent makefile. ++ # + + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc -nostdinc -I../../include +! CPP =cpp -nostdinc -I../../include + + .c.s: + $(CC) $(CFLAGS) \ +*************** +*** 42,56 **** + + ### Dependencies: + floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h \ +! ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/fdreg.h \ + ../../include/asm/system.h ../../include/asm/io.h \ + ../../include/asm/segment.h blk.h +! hd.s hd.o : hd.c ../../include/linux/config.h ../../include/linux/sched.h \ +! ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/timer.h \ +--- 43,59 ---- + + ### Dependencies: + floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h \ +! ../../include/linux/fs.h ../../include/sys/types.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/fdreg.h \ + ../../include/asm/system.h ../../include/asm/io.h \ + ../../include/asm/segment.h blk.h +! hd.s hd.o : hd.c ../../include/errno.h ../../include/linux/config.h \ +! ../../include/linux/sched.h ../../include/linux/head.h \ +! ../../include/linux/fs.h ../../include/sys/types.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/timer.h \ +*************** +*** 58,70 **** + ../../include/asm/io.h ../../include/asm/segment.h blk.h + ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/types.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/asm/system.h blk.h + ramdisk.s ramdisk.o : ramdisk.c ../../include/string.h ../../include/linux/config.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ +! ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/minix_fs.h \ +--- 61,75 ---- + ../../include/asm/io.h ../../include/asm/segment.h blk.h + ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \ +! ../../include/linux/mm.h ../../include/linux/kernel.h \ +! ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/asm/system.h blk.h + ramdisk.s ramdisk.o : ramdisk.c ../../include/string.h ../../include/linux/config.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ +! ../../include/linux/fs.h ../../include/sys/types.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/minix_fs.h \ +*** ../0.95a/linux/kernel/blk_drv/blk.h Thu Mar 12 03:42:41 1992 +--- linux/kernel/blk_drv/blk.h Fri Apr 3 15:28:31 1992 +*************** +*** 78,87 **** + #define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) + + #elif (MAJOR_NR == 3) +! /* harddisk */ + #define DEVICE_NAME "harddisk" + #define DEVICE_INTR do_hd + #define DEVICE_TIMEOUT HD_TIMER + #define DEVICE_REQUEST do_hd_request + #define DEVICE_NR(device) (MINOR(device)>>6) + #define DEVICE_ON(device) +--- 78,88 ---- + #define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) + + #elif (MAJOR_NR == 3) +! /* harddisk: timeout is 6 seconds.. */ + #define DEVICE_NAME "harddisk" + #define DEVICE_INTR do_hd + #define DEVICE_TIMEOUT HD_TIMER ++ #define TIMEOUT_VALUE 600 + #define DEVICE_REQUEST do_hd_request + #define DEVICE_NR(device) (MINOR(device)>>6) + #define DEVICE_ON(device) +*************** +*** 101,110 **** + #endif + #ifdef DEVICE_TIMEOUT + +! #define SET_INTR(x) if (DEVICE_INTR = (x)) { \ +! timer_table[DEVICE_TIMEOUT].expires = jiffies + 200; \ +! timer_active |= 1< + #include +*************** +*** 22,30 **** + /* set's the trap flag. */ + #define TRAP_FLAG 0x100 + +- /* check's for granularity. */ +- #define GRANULARITY 0x00800000 +- + /* + * this is the number to subtract from the top of the stack. To find + * the local frame. +--- 23,28 ---- +*************** +*** 51,58 **** + * the offset is how far from the base addr as stored in the TSS. + * this routine assumes that all the priviledged stacks are in our + * data space. +! */ +! + static inline int get_stack_long(struct task_struct *task, int offset) + { + unsigned char *stack; +--- 49,55 ---- + * the offset is how far from the base addr as stored in the TSS. + * this routine assumes that all the priviledged stacks are in our + * data space. +! */ + static inline int get_stack_long(struct task_struct *task, int offset) + { + unsigned char *stack; +*************** +*** 69,213 **** + * data space. + */ + static inline int put_stack_long(struct task_struct *task, int offset, +! unsigned short data) + { + unsigned char * stack; + + stack = (unsigned char *) task->tss.esp0; + stack += offset; +! *(int *) stack = data; + return 0; + } + + /* +! * this routine will get a word out of an arbitrary +! * tasks data space. It likes to have the task number +! * rather than the task pointer. Perhaps the number +! * should be included in the pointer. + */ +! /* seg = 0 if I space */ +! static inline int get_long(int tsk, long addr, unsigned seg, int *data) + { +- int i; +- int limit; +- int cur; +- unsigned long address; + unsigned long page; +- unsigned oldfs; + +! /* find the task number of the current task. */ +! for (i = 0; i < NR_TASKS ; i ++) { +! if (task[i] == current) break; + } +- if (i == NR_TASKS) { +- printk("PTRACE: Can't find current task\n"); +- do_exit(SIGSEGV); +- } +- cur = i; +- +- /* we will need to check the readability of the segment +- and then the byte in order to avoid segment violations. */ +- seg++; +- limit = (task[tsk]->ldt[seg].a) & 0xffff; +- /* this should be constant amound all of our segments, but we +- had better check anyway. */ +- if (task[tsk]->ldt[seg].b & GRANULARITY) +- limit = limit << 12; +- +- if (limit <= addr+4) +- return -EIO; +- +- /* Now compute the address, and make sure that it is present. */ +- address = task[tsk]->start_code + addr; +- +- page = *((unsigned long*) ((address >> 20) & 0xffc)); +- /* see if it is present. */ + if (!(page & PAGE_PRESENT)) { +! do_no_page(0, address, task[tsk]); + } +! +! oldfs = get_fs(); +! /* now convert seg to the right format. */ +! seg = (seg << 3) | 0x4; +! +! cli(); /* we are about to change our ldt, we better do it +! with interrupts off. Perhaps we should call schedule +! first so that we won't be taking too much extra time. */ +! lldt(tsk); +! set_fs(seg); +! *data = get_fs_long((void *)addr); /* we are assuming kernel space +! is in the gdt here. */ +! lldt(cur); +! set_fs(oldfs); +! sti(); +! return 0; + } + + /* +! * this routine will get a word out of an arbitrary +! * tasks data space. It likes to have the task number +! * rather than the task pointer. Perhaps the number +! * should be included in the pointer. + */ +! /* seg = 0 if I space */ +! static inline int put_long(int tsk, long addr, int data, unsigned seg) + { +- int i; +- int limit; +- unsigned oldfs; +- unsigned long address; + unsigned long page; +- int cur; + +! /* find the task number of the current task. */ +! for (i = 0; i < NR_TASKS ; i++) { +! if (task[i] == current) break; + } +! if (i == NR_TASKS) { +! printk("PTRACE: Can't find current task\n"); +! do_exit(SIGSEGV); + } +! cur = i; + +! /* we will need to check the readability of the segment +! and then the byte in order to avoid segment violations. */ +! seg++; +! limit = (task[tsk]->ldt[seg].a) & 0xffff; +! /* this should be constant amound all of our segments, but we +! had better check anyway. */ +! if (task[tsk]->ldt[seg].b & GRANULARITY) +! limit = limit << 12; + +! if (limit <= addr+4) + return -EIO; + +! /* Now compute the address, and make sure that it is present. */ +! address = task[tsk]->start_code + addr; + +! page = *((unsigned long*) ((address >> 20) & 0xffc)); +! /* see if it is present. */ +! if (!(page & PAGE_PRESENT)) { +! do_no_page(0, address, task[tsk]); +! } +! write_verify(address); +! +! oldfs=get_fs(); +! /* now convert seg to the right format. */ +! seg = (seg << 3) | 0x4; +! +! cli(); /* we are about to change our ldt, we better do it +! with interrupts off. Perhaps we should call schedule +! first so that we won't be taking too much extra time. */ +! lldt(tsk); +! set_fs(seg); +! put_fs_long(data,(void *)addr); +! lldt(cur); +! set_fs(oldfs); +! sti(); + return 0; + } + +- + /* Perform ptrace(request, pid, addr, data) syscall */ + int sys_ptrace(unsigned long *buffer) + { +--- 66,224 ---- + * data space. + */ + static inline int put_stack_long(struct task_struct *task, int offset, +! unsigned long data) + { + unsigned char * stack; + + stack = (unsigned char *) task->tss.esp0; + stack += offset; +! *(unsigned long *) stack = data; + return 0; + } + + /* +! * This routine gets a long from any process space by following the page +! * tables. NOTE! You should check that the long isn't on a page boundary, +! * and that it is in the task area before calling this: this routine does +! * no checking. +! * +! * NOTE2! This uses "tsk->tss.cr3" even though we know it's currently always +! * zero. This routine shouldn't have to change when we make a better mm. + */ +! static unsigned long get_long(struct task_struct * tsk, +! unsigned long addr) + { + unsigned long page; + +! addr += tsk->start_code; +! repeat: +! page = tsk->tss.cr3 + ((addr >> 20) & 0xffc); +! page = *(unsigned long *) page; +! if (page & PAGE_PRESENT) { +! page &= 0xfffff000; +! page += (addr >> 10) & 0xffc; +! page = *((unsigned long *) page); + } + if (!(page & PAGE_PRESENT)) { +! do_no_page(0,addr,tsk); +! goto repeat; + } +! page &= 0xfffff000; +! page += addr & 0xfff; +! return *(unsigned long *) page; + } + + /* +! * This routine puts a long into any process space by following the page +! * tables. NOTE! You should check that the long isn't on a page boundary, +! * and that it is in the task area before calling this: this routine does +! * no checking. + */ +! static void put_long(struct task_struct * tsk, unsigned long addr, +! unsigned long data) + { + unsigned long page; + +! addr += tsk->start_code; +! repeat: +! page = tsk->tss.cr3 + ((addr >> 20) & 0xffc); +! page = *(unsigned long *) page; +! if (page & PAGE_PRESENT) { +! page &= 0xfffff000; +! page += (addr >> 10) & 0xffc; +! page = *((unsigned long *) page); + } +! if (!(page & PAGE_PRESENT)) { +! do_no_page(0,addr,tsk); +! goto repeat; + } +! if (!(page & PAGE_RW)) { +! write_verify(addr); +! goto repeat; +! } +! page &= 0xfffff000; +! page += addr & 0xfff; +! *(unsigned long *) page = data; +! } + +! /* +! * This routine checks the page boundaries, and that the offset is +! * within the task area. It then calls get_long() to read a long. +! */ +! static int read_long(struct task_struct * tsk, unsigned long addr, +! unsigned long * result) +! { +! unsigned long low,high; + +! if (addr > TASK_SIZE-4) + return -EIO; ++ if ((addr & 0xfff) > PAGE_SIZE-4) { ++ low = get_long(tsk,addr & 0xfffffffc); ++ high = get_long(tsk,(addr+4) & 0xfffffffc); ++ switch (addr & 3) { ++ case 1: ++ low >>= 8; ++ low |= high << 24; ++ break; ++ case 2: ++ low >>= 16; ++ low |= high << 16; ++ break; ++ case 3: ++ low >>= 24; ++ low |= high << 8; ++ break; ++ } ++ *result = low; ++ } else ++ *result = get_long(tsk,addr); ++ return 0; ++ } + +! /* +! * This routine checks the page boundaries, and that the offset is +! * within the task area. It then calls put_long() to write a long. +! */ +! static int write_long(struct task_struct * tsk, unsigned long addr, +! unsigned long data) +! { +! unsigned long low,high; + +! if (addr > TASK_SIZE-4) +! return -EIO; +! if ((addr & 0xfff) > PAGE_SIZE-4) { +! low = get_long(tsk,addr & 0xfffffffc); +! high = get_long(tsk,(addr+4) & 0xfffffffc); +! switch (addr & 3) { +! case 0: /* shouldn't happen, but safety first */ +! low = data; +! break; +! case 1: +! low &= 0x000000ff; +! low |= data << 8; +! high &= 0xffffff00; +! high |= data >> 24; +! break; +! case 2: +! low &= 0x0000ffff; +! low |= data << 16; +! high &= 0xffff0000; +! high |= data >> 16; +! break; +! case 3: +! low &= 0x00ffffff; +! low |= data << 24; +! high &= 0xff000000; +! high |= data >> 8; +! break; +! } +! put_long(tsk,addr & 0xfffffffc,low); +! put_long(tsk,(addr+4) & 0xfffffffc,high); +! } else +! put_long(tsk,addr,data); + return 0; + } + + /* Perform ptrace(request, pid, addr, data) syscall */ + int sys_ptrace(unsigned long *buffer) + { +*************** +*** 244,250 **** + case 2: { + int tmp,res; + +! res = get_long(childno, addr, 1, &tmp); + if (res < 0) + return res; + verify_area((void *) data, 4); +--- 255,261 ---- + case 2: { + int tmp,res; + +! res = read_long(task[childno], addr, &tmp); + if (res < 0) + return res; + verify_area((void *) data, 4); +*************** +*** 267,280 **** + /* when I and D space are seperate, this will have to be fixed. */ + case 4: /* write the word at location addr. */ + case 5: +! if (put_long(childno, addr, data, 1)) +! return -EIO; +! return 0; + + case 6: /* write the word at location addr in the USER area */ + addr = addr >> 2; /* temproary hack. */ + if (addr < 0 || addr >= 17) +! return -EIO; + if (addr == ORIG_EAX) + return -EIO; + if (addr == EFL) { /* flags. */ +--- 278,289 ---- + /* when I and D space are seperate, this will have to be fixed. */ + case 4: /* write the word at location addr. */ + case 5: +! return write_long(task[childno],addr,data); + + case 6: /* write the word at location addr in the USER area */ + addr = addr >> 2; /* temproary hack. */ + if (addr < 0 || addr >= 17) +! return -EIO; + if (addr == ORIG_EAX) + return -EIO; + if (addr == EFL) { /* flags. */ +*************** +*** 281,287 **** + data &= FLAG_MASK; + data |= get_stack_long(child, EFL*4-MAGICNUMBER) & ~FLAG_MASK; + } +- + if (put_stack_long(child, 4*addr-MAGICNUMBER, data)) + return -EIO; + return 0; +--- 290,295 ---- +*** ../0.95a/linux/lib/Makefile Thu Mar 5 20:23:23 1992 +--- linux/lib/Makefile Sat Apr 4 17:00:10 1992 +*************** +*** 6,22 **** + # unless it's something special (ie not a .c file). + # + +- # gcc2 doesn't understand some options.. +- # GCC_OPT = -fcombine-regs +- + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) \ +! -finline-functions -nostdinc -I../include +! CPP =gcc -E -nostdinc -I../include + + .c.s: + $(CC) $(CFLAGS) \ +--- 6,17 ---- + # unless it's something special (ie not a .c file). + # + + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc -nostdinc -I../include +! CPP =cpp -nostdinc -I../include + + .c.s: + $(CC) $(CFLAGS) \ +*** ../0.95a/linux/mm/Makefile Tue Mar 17 11:57:15 1992 +--- linux/mm/Makefile Sat Apr 4 17:33:29 1992 +*************** +*** 1,10 **** +! CC =gcc +! CFLAGS =-O -Wall -fstrength-reduce -fomit-frame-pointer \ +! -finline-functions -nostdinc -I../include + AS =as + AR =ar + LD =ld +! CPP =gcc -E -nostdinc -I../include + + .c.o: + $(CC) $(CFLAGS) \ +--- 1,17 ---- +! # +! # Makefile for the linux memory manager. +! # +! # 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). +! # +! # Note 2! The CFLAGS definition is now in the main makefile... +! + AS =as + AR =ar + LD =ld +! CC =gcc -nostdinc -I../include +! CPP =cpp -nostdinc -I../include + + .c.o: + $(CC) $(CFLAGS) \ +*************** +*** 32,42 **** + ### Dependencies: + memory.o : memory.c ../include/signal.h ../include/sys/types.h \ + ../include/asm/system.h ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h + swap.o : swap.c ../include/string.h ../include/errno.h \ + ../include/linux/mm.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/stat.h \ +! ../include/linux/sched.h ../include/linux/head.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h +--- 39,50 ---- + ### Dependencies: + memory.o : memory.c ../include/signal.h ../include/sys/types.h \ + ../include/asm/system.h ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \ +! ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h + swap.o : swap.c ../include/string.h ../include/errno.h \ + ../include/linux/mm.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/stat.h ../include/linux/sched.h \ +! ../include/linux/head.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h +*** ../0.95a/linux/mm/memory.c Tue Mar 17 22:35:13 1992 +--- linux/mm/memory.c Wed Apr 1 01:28:30 1992 +*************** +*** 165,170 **** +--- 165,171 ---- + if (!(1 & this_page)) { + if (!(new_page = get_free_page())) + return -1; ++ ++current->rss; + read_swap_page(this_page>>1, (char *) new_page); + *to_page_table = this_page; + *from_page_table = new_page | (PAGE_DIRTY | 7); +*************** +*** 316,321 **** +--- 317,323 ---- + printk("Bad things happen: page error in do_wp_page\n\r"); + do_exit(SIGSEGV); + } ++ ++current->min_flt; + un_wp_page((unsigned long *) + (((address>>10) & 0xffc) + (0xfffff000 & + *((unsigned long *) ((address>>20) &0xffc))))); +*************** +*** 429,436 **** + return 0; + } + +! void do_no_page(unsigned long error_code, +! unsigned long address, struct task_struct *tsk) + { + static unsigned int last_checked = 0; + int nr[4]; +--- 431,438 ---- + return 0; + } + +! void do_no_page(unsigned long error_code, unsigned long address, +! struct task_struct *tsk) + { + static unsigned int last_checked = 0; + int nr[4]; +*************** +*** 439,445 **** + int block,i; + struct inode * inode; + +! /* Trashing ? Make it interruptible, but don't penalize otherwise */ + for (i = 0; i < CHECK_LAST_NR; i++) + if ((address & 0xfffff000) == last_pages[i]) { + current->counter = 0; +--- 441,447 ---- + int block,i; + struct inode * inode; + +! /* Thrashing ? Make it interruptible, but don't penalize otherwise */ + for (i = 0; i < CHECK_LAST_NR; i++) + if ((address & 0xfffff000) == last_pages[i]) { + current->counter = 0; +*************** +*** 457,462 **** +--- 459,465 ---- + printk("Bad things happen: nonexistent page error in do_no_page\n\r"); + do_exit(SIGSEGV); + } ++ ++tsk->rss; + page = *(unsigned long *) ((address >> 20) & 0xffc); + /* check the page directory: make a page dir entry if no such exists */ + if (page & 1) { +*************** +*** 464,469 **** +--- 467,473 ---- + page += (address >> 10) & 0xffc; + tmp = *(unsigned long *) page; + if (tmp && !(1 & tmp)) { ++ ++tsk->maj_flt; + swap_in((unsigned long *) page); + return; + } +*************** +*** 488,499 **** + block = 0; + } + if (!inode) { + get_empty_page(address); + return; + } + if (tsk == current) +! if (share_page(inode,tmp)) +! return; + if (!(page = get_free_page())) + oom(); + /* remember that 1 block is used for header */ +--- 492,510 ---- + block = 0; + } + if (!inode) { ++ ++tsk->min_flt; ++ if (tmp > tsk->brk && tsk == current && ++ LIBRARY_OFFSET - tmp > tsk->rlim[RLIMIT_STACK].rlim_max) ++ do_exit(SIGSEGV); + get_empty_page(address); + return; + } + if (tsk == current) +! if (share_page(inode,tmp)) { +! ++tsk->min_flt; +! return; +! } +! ++tsk->maj_flt; + if (!(page = get_free_page())) + oom(); + /* remember that 1 block is used for header */ +*************** +*** 533,541 **** + void show_mem(void) + { + int i,j,k,free=0,total=0; +! int shared=0; + unsigned long * pg_tbl; + + printk("Mem-info:\n\r"); + for(i=0 ; i ++ ++ struct dirent { ++ long d_ino; ++ off_t d_off; ++ unsigned short d_reclen; ++ char d_name[NAME_MAX+1]; ++ }; ++ ++ #endif +*** ../0.95a/linux/include/unistd.h Wed Mar 4 12:56:06 1992 +--- linux/include/unistd.h Fri Apr 3 19:55:41 1992 +*************** +*** 50,55 **** +--- 50,61 ---- + #define _PC_VDISABLE 8 + #define _PC_CHOWN_RESTRICTED 9 + ++ #if 0 ++ /* XXX - illegally already. ++ * The rest of these includes are also illegal (too much pollution). ++ */ ++ #include ++ #endif + #include + #include + #include +*************** +*** 148,154 **** +--- 154,162 ---- + #define __NR_uselib 86 + #define __NR_swapon 87 + #define __NR_reboot 88 ++ #define __NR_readdir 89 + ++ /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ + #define _syscall0(type,name) \ + type name(void) \ + { \ +*************** +*** 206,224 **** + + #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); +--- 214,239 ---- + + #endif /* __LIBRARY__ */ + ++ /* XXX - illegal. */ + extern int errno; + +! /* XXX - several non-POSIX functions here, and POSIX functions that are +! * supposed to be declared elsewhere. Non-promotion of short types in +! * prototypes may cause trouble. Arg names should be prefixed by +! * underscores. +! */ +! int access(const char * filename, mode_t mode); /* XXX - short type */ + int acct(const char * filename); + int brk(void * end_data_segment); ++ /* XXX - POSIX says unsigned alarm(unsigned sec) */ ++ int alarm(int sec); + void * sbrk(ptrdiff_t increment); + int chdir(const char * filename); +! int chmod(const char * filename, mode_t mode); /* XXX - short type */ +! int chown(const char * filename, uid_t owner, gid_t group); /* XXX - shorts */ + int chroot(const char * filename); + int close(int fildes); +! int creat(const char * filename, mode_t mode); /* XXX - short type */ + int dup(int fildes); + int execve(const char * filename, char ** argv, char ** envp); + int execv(const char * pathname, char ** argv); +*************** +*** 229,255 **** + 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); +--- 244,271 ---- + volatile void exit(int status); + volatile void _exit(int status); + int fcntl(int fildes, int cmd, ...); +! pid_t fork(void); +! pid_t getpid(void); +! uid_t getuid(void); +! uid_t geteuid(void); +! gid_t getgid(void); +! gid_t getegid(void); + int ioctl(int fildes, int cmd, ...); + int kill(pid_t pid, int signal); + int link(const char * filename1, const char * filename2); +! off_t lseek(int fildes, off_t offset, int origin); +! int mknod(const char * filename, mode_t mode, dev_t dev); /* XXX - shorts */ + 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); ++ /* XXX**2 - POSIX says unsigned count */ + int read(int fildes, char * buf, off_t count); + int setpgrp(void); +! int setpgid(pid_t pid,pid_t pgid); /* XXX - short types */ +! int setuid(uid_t uid); /* XXX - short type */ +! int setgid(gid_t gid); /* XXX - short type */ + 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); +*************** +*** 266,271 **** +--- 282,288 ---- + 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); ++ /* XXX**2 - POSIX says unsigned count */ + int write(int fildes, const char * buf, off_t count); + int dup2(int oldfd, int newfd); + int getppid(void); +*** ../0.95a/linux/include/a.out.h Tue Sep 17 18:10:49 1991 +--- linux/include/a.out.h Sat Apr 4 00:41:52 1992 +*************** +*** 1,10 **** +! #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 */ +--- 1,13 ---- +! #ifndef __A_OUT_GNU_H__ +! #define __A_OUT_GNU_H__ + + #define __GNU_EXEC_MACROS__ + +! #ifndef __STRUCT_EXEC_OVERRIDE__ +! +! struct exec +! { +! unsigned long a_info; /* 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 */ +*************** +*** 14,24 **** + 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. */ +--- 17,70 ---- + unsigned a_drsize; /* length of relocation info for data, in bytes */ + }; + +! #endif /* __STRUCT_EXEC_OVERRIDE__ */ +! +! /* these go in the N_MACHTYPE field */ +! enum machine_type { +! #if defined (M_OLDSUN2) +! M__OLDSUN2 = M_OLDSUN2, +! #else +! M_OLDSUN2 = 0, + #endif ++ #if defined (M_68010) ++ M__68010 = M_68010, ++ #else ++ M_68010 = 1, ++ #endif ++ #if defined (M_68020) ++ M__68020 = M_68020, ++ #else ++ M_68020 = 2, ++ #endif ++ #if defined (M_SPARC) ++ M__SPARC = M_SPARC, ++ #else ++ M_SPARC = 3, ++ #endif ++ /* skip a bunch so we don't run into any of sun's numbers */ ++ M_386 = 100, ++ }; + +! #if !defined (N_MAGIC) +! #define N_MAGIC(exec) ((exec).a_info & 0xffff) +! #endif +! #define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) +! #define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) +! #define N_SET_INFO(exec, magic, type, flags) \ +! ((exec).a_info = ((magic) & 0xffff) \ +! | (((int)(type) & 0xff) << 16) \ +! | (((flags) & 0xff) << 24)) +! #define N_SET_MAGIC(exec, magic) \ +! ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) +! +! #define N_SET_MACHTYPE(exec, machtype) \ +! ((exec).a_info = \ +! ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) +! +! #define N_SET_FLAGS(exec, flags) \ +! ((exec).a_info = \ +! ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) +! + /* Code indicating object file or impure executable. */ + #define OMAGIC 0407 + /* Code indicating pure executable. */ +*************** +*** 25,33 **** + #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) +--- 71,78 ---- + #define NMAGIC 0410 + /* Code indicating demand-paged executable. */ + #define ZMAGIC 0413 + +! #if !defined (N_BADMAG) + #define N_BADMAG(x) \ + (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) +*************** +*** 37,71 **** + (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 + +--- 82,116 ---- + (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) + +! #define _N_HDROFF(x) (1024 - sizeof (struct exec)) + +! #if !defined (N_TXTOFF) + #define N_TXTOFF(x) \ + (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec)) + #endif + +! #if !defined (N_DATOFF) + #define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) + #endif + +! #if !defined (N_TRELOFF) + #define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data) + #endif + +! #if !defined (N_DRELOFF) + #define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize) + #endif + +! #if !defined (N_SYMOFF) + #define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize) + #endif + +! #if !defined (N_STROFF) + #define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms) + #endif + + /* Address of text segment in memory after it is loaded. */ +! #if !defined (N_TXTADDR) + #define N_TXTADDR(x) 0 + #endif + +*************** +*** 73,83 **** + 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. */ +--- 118,125 ---- + 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 sony + #define SEGMENT_SIZE 0x2000 + #endif /* Sony. */ +*************** +*** 89,96 **** + #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)) + +--- 131,140 ---- + #define SEGMENT_SIZE PAGE_SIZE + #endif + +! #ifdef linux +! #define PAGE_SIZE 4096 +! #define SEGMENT_SIZE 1024 +! #endif + + #define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1)) + +*************** +*** 103,113 **** + #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; +--- 147,157 ---- + #endif + + /* Address of bss segment in memory after it is loaded. */ +! #if !defined (N_BSSADDR) + #define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) + #endif +! +! #if !defined (N_NLIST_DECLARED) + struct nlist { + union { + char *n_name; +*************** +*** 119,155 **** + 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 + +--- 163,196 ---- + short n_desc; + unsigned long n_value; + }; +! #endif /* no N_NLIST_DECLARED. */ + +! #if !defined (N_UNDF) + #define N_UNDF 0 + #endif +! #if !defined (N_ABS) + #define N_ABS 2 + #endif +! #if !defined (N_TEXT) + #define N_TEXT 4 + #endif +! #if !defined (N_DATA) + #define N_DATA 6 + #endif +! #if !defined (N_BSS) + #define N_BSS 8 + #endif +! #if !defined (N_FN) + #define N_FN 15 + #endif + +! #if !defined (N_EXT) + #define N_EXT 1 + #endif +! #if !defined (N_TYPE) + #define N_TYPE 036 + #endif +! #if !defined (N_STAB) + #define N_STAB 0340 + #endif + +*************** +*** 182,190 **** + + /* 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. +--- 223,230 ---- + + /* This is output from LD. */ + #define N_SETV 0x1C /* Pointer to set vector in data area. */ +! +! #if !defined (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. +*************** +*** 212,218 **** +--- 252,264 ---- + unsigned int r_extern:1; + /* Four bits that aren't used, but when writing an object file + it is desirable to clear them. */ ++ #ifdef NS32K ++ unsigned r_bsr:1; ++ unsigned r_disp:1; ++ unsigned r_pad:2; ++ #else + unsigned int r_pad:4; ++ #endif + }; + #endif /* no N_RELOCATION_INFO_DECLARED. */ + +*** ../0.95a/linux/include/linux/hdreg.h Sat Feb 1 16:04:35 1992 +--- linux/include/linux/hdreg.h Tue Mar 31 20:50:13 1992 +*************** +*** 64,67 **** +--- 64,73 ---- + unsigned int nr_sects; /* nr of sectors in partition */ + }; + ++ #define HDIO_REQ 0x301 ++ struct hd_geometry { ++ unsigned char heads; ++ unsigned char sectors; ++ unsigned short cylinders; ++ }; + #endif +*** ../0.95a/linux/include/linux/sched.h Sat Mar 14 14:21:14 1992 +--- linux/include/linux/sched.h Wed Apr 1 01:37:45 1992 +*************** +*** 129,137 **** +--- 129,141 ---- + unsigned short gid,egid,sgid; + unsigned long timeout,alarm; + long utime,stime,cutime,cstime,start_time; ++ unsigned long min_flt, maj_flt; ++ unsigned long cmin_flt, cmaj_flt; + struct rlimit rlim[RLIM_NLIMITS]; + unsigned int flags; /* per process flags, defined below */ + unsigned short used_math; ++ unsigned short rss; /* number of resident pages */ ++ char comm[8]; + /* file system info */ + int link_count; + int tty; /* -1 if no tty, so it must be signed */ +*************** +*** 171,181 **** +--- 175,188 ---- + /* proc links*/ &init_task.task,NULL,NULL,NULL,NULL, \ + /* uid etc */ 0,0,0,0,0,0, \ + /* timeout */ 0,0,0,0,0,0,0, \ ++ /* min_flt */ 0,0,0,0, \ + /* rlimits */ { {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \ + {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \ + {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}}, \ + /* flags */ 0, \ + /* math */ 0, \ ++ /* rss */ 2, \ ++ /* comm */ "swapper", \ + /* fs info */ 0,-1,0022,NULL,NULL,NULL,NULL,0, \ + /* filp */ {NULL,}, \ + { \ +*** ../0.95a/linux/include/linux/sys.h Thu Feb 27 18:24:26 1992 +--- linux/include/linux/sys.h Fri Apr 3 19:56:16 1992 +*************** +*** 91,96 **** +--- 91,97 ---- + extern int sys_uselib(); + extern int sys_swapon(); + extern int sys_reboot(); ++ extern int sys_readdir(); + + 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, +*************** +*** 107,113 **** + sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_sethostname, + sys_setrlimit, sys_getrlimit, sys_getrusage, sys_gettimeofday, + sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink, +! sys_lstat, sys_readlink, sys_uselib, sys_swapon, sys_reboot }; + + /* So we don't have to do any more manual updating.... */ + int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); +--- 108,114 ---- + sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_sethostname, + sys_setrlimit, sys_getrlimit, sys_getrusage, sys_gettimeofday, + sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink, +! sys_lstat, sys_readlink, sys_uselib, sys_swapon, sys_reboot, sys_readdir }; + + /* So we don't have to do any more manual updating.... */ + int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); +*** ../0.95a/linux/include/linux/tty.h Sun Mar 15 02:43:54 1992 +--- linux/include/linux/tty.h Thu Mar 19 21:16:26 1992 +*************** +*** 68,83 **** + struct tty_queue *secondary; + }; + +! #define TTY_WRITE(tty) \ + do { \ + cli(); \ +! if (!(tty)->busy) { \ +! (tty)->busy = 1; \ + sti(); \ + (tty)->write((tty)); \ +! (tty)->busy = 0; \ +! } else \ + sti(); \ + } while (0) + + extern struct tty_struct tty_table[]; +--- 68,105 ---- + struct tty_queue *secondary; + }; + +! /* +! * so that interrupts won't be able to mess up the +! * queues, copy_to_cooked must be atomic with repect +! * to itself, as must tty->write. +! */ +! #define TTY_WRITE_BUSY 1 +! #define TTY_READ_BUSY 2 +! +! #define TTY_WRITE_FLUSH(tty) \ + do { \ + cli(); \ +! if (!EMPTY((tty)->write_q) && !(TTY_WRITE_BUSY & (tty)->busy)) { \ +! (tty)->busy |= TTY_WRITE_BUSY; \ + sti(); \ + (tty)->write((tty)); \ +! cli(); \ +! (tty)->busy &= ~TTY_WRITE_BUSY; \ +! } \ +! sti(); \ +! } while (0) +! +! #define TTY_READ_FLUSH(tty) \ +! do { \ +! cli(); \ +! if (!EMPTY((tty)->read_q) && !(TTY_READ_BUSY & (tty)->busy)) { \ +! (tty)->busy |= TTY_READ_BUSY; \ + sti(); \ ++ copy_to_cooked((tty)); \ ++ cli(); \ ++ (tty)->busy &= ~TTY_READ_BUSY; \ ++ } \ ++ sti(); \ + } while (0) + + extern struct tty_struct tty_table[]; +*** ../0.95a/linux/include/linux/fs.h Fri Mar 13 18:55:15 1992 +--- linux/include/linux/fs.h Fri Apr 3 20:51:17 1992 +*************** +*** 7,12 **** +--- 7,13 ---- + #define _FS_H + + #include ++ #include + + /* devices are as follows: (same as minix, so we can use the minix + * file system. These are major numbers.) +*************** +*** 134,139 **** +--- 135,142 ---- + unsigned char s_lock; + unsigned char s_rd_only; + unsigned char s_dirt; ++ /* TUBE */ ++ struct super_operations *s_op; + }; + + struct file_operations { +*************** +*** 140,145 **** +--- 143,149 ---- + int (*lseek) (struct inode *, struct file *, off_t, int); + int (*read) (struct inode *, struct file *, char *, int); + int (*write) (struct inode *, struct file *, char *, int); ++ int (*readdir) (struct inode *, struct file *, struct dirent *); + }; + + struct inode_operations { +*************** +*** 156,163 **** +--- 160,184 ---- + int (*open) (struct inode *, struct file *); + void (*release) (struct inode *, struct file *); + struct inode * (*follow_link) (struct inode *, struct inode *); ++ int (*bmap) (struct inode *,int); ++ void (*truncate) (struct inode *); ++ /* added by entropy */ ++ void (*write_inode)(struct inode *inode); ++ void (*put_inode)(struct inode *inode); + }; + ++ struct super_operations { ++ void (*read_inode)(struct inode *inode); ++ void (*put_super)(struct super_block *sb); ++ }; ++ ++ struct file_system_type { ++ struct super_block *(*read_super)(struct super_block *sb,void *mode); ++ char *name; ++ }; ++ ++ extern struct file_system_type *get_fs_type(char *name); ++ + extern struct inode inode_table[NR_INODE]; + extern struct file file_table[NR_FILE]; + extern struct super_block super_block[NR_SUPER]; +*************** +*** 175,180 **** +--- 196,204 ---- + extern int bmap(struct inode * inode,int block); + extern struct inode * namei(const char * pathname); + extern struct inode * lnamei(const char * pathname); ++ extern int permission(struct inode * inode,int mask); ++ extern struct inode * _namei(const char * filename, struct inode * base, ++ int follow_links); + extern int open_namei(const char * pathname, int flag, int mode, + struct inode ** res_inode); + extern void iput(struct inode * inode); +*************** +*** 195,207 **** + extern int ROOT_DEV; + + extern void mount_root(void); + +- extern int minix_file_read(struct inode *, struct file *, char *, int); + extern int pipe_read(struct inode *, struct file *, char *, int); + extern int char_read(struct inode *, struct file *, char *, int); + extern int block_read(struct inode *, struct file *, char *, int); + +- extern int minix_file_write(struct inode *, struct file *, char *, int); + extern int pipe_write(struct inode *, struct file *, char *, int); + extern int char_write(struct inode *, struct file *, char *, int); + extern int block_write(struct inode *, struct file *, char *, int); +--- 219,231 ---- + extern int ROOT_DEV; + + extern void mount_root(void); ++ extern void lock_super(struct super_block * sb); ++ extern void free_super(struct super_block * sb); + + extern int pipe_read(struct inode *, struct file *, char *, int); + extern int char_read(struct inode *, struct file *, char *, int); + extern int block_read(struct inode *, struct file *, char *, int); + + extern int pipe_write(struct inode *, struct file *, char *, int); + extern int char_write(struct inode *, struct file *, char *, int); + extern int block_write(struct inode *, struct file *, char *, int); +*** ../0.95a/linux/include/linux/minix_fs.h Mon Mar 2 23:52:27 1992 +--- linux/include/linux/minix_fs.h Fri Apr 3 20:52:29 1992 +*************** +*** 68,76 **** +--- 68,85 ---- + extern int minix_create_block(struct inode * inode, int block); + extern int minix_bmap(struct inode * inode,int block); + ++ extern void minix_truncate(struct inode * inode); ++ extern void minix_put_super(struct super_block *sb); ++ extern struct super_block *minix_read_super(struct super_block *s,void *data); ++ extern void minix_read_inode(struct inode * inode); ++ extern void minix_write_inode(struct inode * inode); ++ + extern int minix_lseek(struct inode * inode, struct file * filp, off_t offset, int origin); + extern int minix_read(struct inode * inode, struct file * filp, char * buf, int count); + extern int minix_write(struct inode * inode, struct file * filp, char * buf, int count); ++ extern int minix_readdir(struct inode * inode, struct file * filp, struct dirent * dirent); ++ extern int minix_file_read(struct inode *, struct file *, char *, int); ++ extern int minix_file_write(struct inode *, struct file *, char *, int); + + extern struct inode_operations minix_inode_operations; + extern struct file_operations minix_file_operations; +*** ../0.95a/linux/include/asm/io.h Fri Mar 13 00:44:31 1992 +--- linux/include/asm/io.h Wed Apr 1 02:12:14 1992 +*************** +*** 1,10 **** +! static void inline outb(char value, unsigned short port) + { + __asm__ volatile ("outb %0,%1" + ::"a" ((char) value),"d" ((unsigned short) port)); + } + +! static void inline outb_p(char value, unsigned short port) + { + __asm__ volatile ("outb %0,%1\n" + "\tjmp 1f\n" +--- 1,13 ---- +! #ifndef _ASM_IO_H +! #define _ASM_IO_H +! +! extern void inline outb(char value, unsigned short port) + { + __asm__ volatile ("outb %0,%1" + ::"a" ((char) value),"d" ((unsigned short) port)); + } + +! extern void inline outb_p(char value, unsigned short port) + { + __asm__ volatile ("outb %0,%1\n" + "\tjmp 1f\n" +*************** +*** 15,21 **** + ::"a" ((char) value),"d" ((unsigned short) port)); + } + +! static unsigned char inline inb(unsigned short port) + { + unsigned char _v; + __asm__ volatile ("inb %1,%0" +--- 18,24 ---- + ::"a" ((char) value),"d" ((unsigned short) port)); + } + +! extern unsigned char inline inb(unsigned short port) + { + unsigned char _v; + __asm__ volatile ("inb %1,%0" +*************** +*** 23,29 **** + return _v; + } + +! static unsigned char inb_p(unsigned short port) + { + unsigned char _v; + __asm__ volatile ("inb %1,%0\n" +--- 26,32 ---- + return _v; + } + +! extern unsigned char inline inb_p(unsigned short port) + { + unsigned char _v; + __asm__ volatile ("inb %1,%0\n" +*************** +*** 35,37 **** +--- 38,42 ---- + :"=a" (_v):"d" ((unsigned short) port)); + return _v; + } ++ ++ #endif +*** /dev/null Sat Apr 4 17:07:54 1992 +--- linux/include/limits.h Fri Apr 3 20:08:43 1992 +*************** +*** 0 **** +--- 1,62 ---- ++ #ifndef _LIMITS_H ++ #define _LIMITS_H ++ ++ #define RAND_MAX 0x7ffffffd /* don't ask - see rand.c */ ++ ++ #define CHAR_BIT 8 ++ #define MB_LEN_MAX 1 ++ ++ #define SCHAR_MIN (-128) ++ #define SCHAR_MAX 127 ++ ++ #define UCHAR_MAX 255U ++ ++ #ifdef __CHAR_UNSIGNED__ ++ #define CHAR_MIN 0 ++ #define CHAR_MAX UCHAR_MAX ++ #else ++ #define CHAR_MIN SCHAR_MIN ++ #define CHAR_MAX SCHAR_MAX ++ #endif ++ ++ #define SHRT_MIN (-32768) ++ #define SHRT_MAX 32767 ++ ++ #define USHRT_MAX 65535U ++ ++ #define INT_MIN (-2147483648) ++ #define INT_MAX 2147483647 ++ ++ #define UINT_MAX 4294967295U ++ ++ #define LONG_MIN (-2147483648) ++ #define LONG_MAX 2147483647 ++ ++ #define ULONG_MAX 4294967295U ++ ++ /* ++ * Why are these different from the section below? -- TYT ++ */ ++ #define _POSIX_ARG_MAX 40960 /* exec() may have 40K worth of args */ ++ #define _POSIX_CHILD_MAX 6 /* a process may have 6 children */ ++ #define _POSIX_LINK_MAX 8 /* a file may have 8 links */ ++ #define _POSIX_MAX_CANON 255 /* size of the canonical input queue */ ++ #define _POSIX_MAX_INPUT 255 /* you can type 255 chars ahead */ ++ #define _POSIX_NAME_MAX 14 /* a file name may have 14 chars */ ++ #define _POSIX_NGROUPS_MAX 32 /* supplementary group IDs are optional */ ++ #define _POSIX_OPEN_MAX 16 /* a process may have 16 files open */ ++ #define _POSIX_PATH_MAX 255 /* a pathname may contain 255 chars */ ++ #define _POSIX_PIPE_BUF 512 /* pipes writes of 512 bytes must be atomic */ ++ ++ #define NGROUPS_MAX 32 /* supplemental group IDs are available */ ++ #define ARG_MAX 40960 /* # bytes of args + environ for exec() */ ++ #define CHILD_MAX 999 /* no limit :-) */ ++ #define OPEN_MAX 20 /* # open files a process may have */ ++ #define LINK_MAX 127 /* # links a file may have */ ++ #define MAX_CANON 255 /* size of the canonical input queue */ ++ #define MAX_INPUT 255 /* size of the type-ahead buffer */ ++ #define NAME_MAX 255 /* # chars in a file name */ ++ #define PATH_MAX 1024 /* # chars in a path name */ ++ #define PIPE_BUF 4095 /* # bytes in atomic write to a pipe */ ++ ++ #endif diff --git a/kernel/0.95/linux-0.95.tar b/kernel/0.95/linux-0.95.tar new file mode 100644 index 00000000..8b13c9a5 Binary files /dev/null and b/kernel/0.95/linux-0.95.tar differ diff --git a/kernel/0.95/linux-0.95.tar.gz b/kernel/0.95/linux-0.95.tar.gz new file mode 100644 index 00000000..5930ee03 Binary files /dev/null and b/kernel/0.95/linux-0.95.tar.gz differ diff --git a/kernel/0.95/linux-0.95/Makefile b/kernel/0.95/linux-0.95/Makefile new file mode 100644 index 00000000..8bedb81b --- /dev/null +++ b/kernel/0.95/linux-0.95/Makefile @@ -0,0 +1,131 @@ +# +# if you want the ram-disk device, define this to be the +# size in blocks. +# +#RAMDISK = -DRAMDISK=512 + +AS86 =as86 -0 -a +LD86 =ld86 -0 + +AS =as +LD =ld +LDFLAGS =-s -x -M +CC =gcc $(RAMDISK) +CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer +CPP =cpp -nostdinc -Iinclude + +# +# ROOT_DEV specifies the default root-device when making the image. +# This can be either FLOPPY, /dev/xxxx or empty, in which case the +# default of FLOPPY is used by 'build'. +# +ROOT_DEV=/dev/hdb1 + +ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o +FILESYSTEMS =fs/minix/minix.o +DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a +MATH =kernel/math/math.a +LIBS =lib/lib.a + +.c.s: + $(CC) $(CFLAGS) \ + -nostdinc -Iinclude -S -o $*.s $< +.s.o: + $(AS) -c -o $*.o $< +.c.o: + $(CC) $(CFLAGS) \ + -nostdinc -Iinclude -c -o $*.o $< + +all: Image + +Image: boot/bootsect boot/setup tools/system tools/build + tools/build boot/bootsect boot/setup tools/system $(ROOT_DEV) > Image + sync + +disk: Image + dd bs=8192 if=Image of=/dev/PS0 + +tools/build: tools/build.c + $(CC) $(CFLAGS) \ + -o tools/build tools/build.c + +boot/head.o: boot/head.s + +tools/system: boot/head.o init/main.o \ + $(ARCHIVES) $(FILESYSTEMS) $(DRIVERS) $(MATH) $(LIBS) + $(LD) $(LDFLAGS) boot/head.o init/main.o \ + $(ARCHIVES) \ + $(FILESYSTEMS) \ + $(DRIVERS) \ + $(MATH) \ + $(LIBS) \ + -o tools/system > System.map + +kernel/math/math.a: + (cd kernel/math; make) + +kernel/blk_drv/blk_drv.a: + (cd kernel/blk_drv; make) + +kernel/chr_drv/chr_drv.a: + (cd kernel/chr_drv; make) + +kernel/kernel.o: + (cd kernel; make) + +mm/mm.o: + (cd mm; make) + +fs/fs.o: + (cd fs; make) + +fs/minix/minix.o: + (cd fs/minix; make) + +lib/lib.a: + (cd lib; make) + +boot/setup: boot/setup.s + $(AS86) -o boot/setup.o boot/setup.s + $(LD86) -s -o boot/setup boot/setup.o + +boot/setup.s: boot/setup.S include/linux/config.h + $(CPP) -traditional boot/setup.S -o boot/setup.s + +boot/bootsect.s: boot/bootsect.S include/linux/config.h + $(CPP) -traditional boot/bootsect.S -o boot/bootsect.s + +boot/bootsect: boot/bootsect.s + $(AS86) -o boot/bootsect.o boot/bootsect.s + $(LD86) -s -o boot/bootsect boot/bootsect.o + +clean: + rm -f Image System.map tmp_make core boot/bootsect boot/setup \ + boot/bootsect.s boot/setup.s init/main.s + rm -f init/*.o tools/system tools/build boot/*.o + (cd mm;make clean) + (cd fs;make clean) + (cd kernel;make clean) + (cd lib;make clean) + +backup: clean + (cd .. ; tar cf - linux | compress - > 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/time.h include/time.h include/sys/times.h \ + include/sys/utsname.h include/sys/param.h include/sys/resource.h \ + include/utime.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/linux/kernel.h include/signal.h include/asm/system.h \ + include/asm/io.h include/stddef.h include/stdarg.h include/fcntl.h \ + include/string.h diff --git a/kernel/0.95/linux-0.95/boot/bootsect.S b/kernel/0.95/linux-0.95/boot/bootsect.S new file mode 100644 index 00000000..8a8ecb89 --- /dev/null +++ b/kernel/0.95/linux-0.95/boot/bootsect.S @@ -0,0 +1,404 @@ +! +! SYS_SIZE is the number of clicks (16 bytes) to be loaded. +! 0x3000 is 0x30000 bytes = 196kB, more than enough for current +! versions of linux +! +#include +SYSSIZE = DEF_SYSSIZE +! +! bootsect.s (C) 1991 Linus Torvalds +! modified by Drew Eckhardt +! +! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves +! iself out of the way to address 0x90000, and jumps there. +! +! It then loads 'setup' directly after itself (0x90200), and the system +! at 0x10000, using BIOS interrupts. +! +! NOTE! currently system is at most 8*65536 bytes long. This should be no +! problem, even in the future. I want to keep it simple. This 512 kB +! kernel size should be enough, especially as this doesn't contain the +! buffer cache as in minix +! +! The loader has been made as simple as possible, and continuos +! read errors will result in a unbreakable loop. Reboot by hand. It +! loads pretty fast by getting whole sectors at a time whenever possible. + +.globl begtext, begdata, begbss, endtext, enddata, endbss +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +SETUPLEN = 4 ! nr of setup-sectors +BOOTSEG = 0x07c0 ! original address of boot-sector +INITSEG = DEF_INITSEG ! we move boot here - out of the way +SETUPSEG = DEF_SETUPSEG ! setup starts here +SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). +ENDSEG = SYSSEG + SYSSIZE ! where to stop loading + +! ROOT_DEV & SWAP_DEV are now written by "build". +ROOT_DEV = 0 +SWAP_DEV = 0 + +entry start +start: + mov ax,#BOOTSEG + mov ds,ax + mov ax,#INITSEG + mov es,ax + mov cx,#256 + sub si,si + sub di,di + cld + rep + movw + jmpi go,INITSEG + +go: mov ax,cs + mov dx,#0xfef4 ! arbitrary value >>512 - disk parm size + + mov ds,ax + mov es,ax + push ax + + mov ss,ax ! put stack at 0x9ff00 - 12. + mov sp,dx +/* + * Many BIOS's default disk parameter tables will not + * recognize multi-sector reads beyond the maximum sector number + * specified in the default diskette parameter tables - this may + * mean 7 sectors in some cases. + * + * Since single sector reads are slow and out of the question, + * we must take care of this by creating new parameter tables + * (for the first disk) in RAM. We will set the maximum sector + * count to 18 - the most we will encounter on an HD 1.44. + * + * High doesn't hurt. Low does. + * + * Segments are as follows: ds=es=ss=cs - INITSEG, + * fs = 0, gs = parameter table segment + */ + + push #0 + pop fs + mov bx,#0x78 ! fs:bx is parameter table address + seg fs + lgs si,(bx) ! gs:si is source + + mov di,dx ! es:di is destination + mov cx,#6 ! copy 12 bytes + cld + + rep + seg gs + movw + + mov di,dx + movb 4(di),*18 ! patch sector count + + seg fs + mov (bx),di + seg fs + mov 2(bx),es + + pop ax + mov fs,ax + mov gs,ax + + xor ah,ah ! reset FDC + xor dl,dl + int 0x13 + +! load the setup-sectors directly after the bootblock. +! Note that 'es' is already set up. + +load_setup: + xor dx, dx ! drive 0, head 0 + mov cx,#0x0002 ! sector 2, track 0 + mov bx,#0x0200 ! address = 512, in INITSEG + mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors + int 0x13 ! read it + jnc ok_load_setup ! ok - continue + + push ax ! dump error code + call print_nl + mov bp, sp + call print_hex + pop ax + + xor dl, dl ! reset FDC + xor ah, ah + int 0x13 + j load_setup + +ok_load_setup: + +! Get disk drive parameters, specifically nr of sectors/track + + xor dl,dl + mov ah,#0x08 ! AH=8 is get drive parameters + int 0x13 + xor ch,ch + seg cs + mov sectors,cx + mov ax,#INITSEG + mov es,ax + +! Print some inane message + + mov ah,#0x03 ! read cursor pos + xor bh,bh + int 0x10 + + mov cx,#9 + 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 + call print_nl + +! After that we check which root-device to use. If the device is +! defined (!= 0), nothing is done and the given device is used. +! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending +! on the number of sectors that the BIOS reports currently. + + seg cs + mov ax,root_dev + or ax,ax + jne root_defined + seg cs + mov bx,sectors + mov ax,#0x0208 ! /dev/ps0 - 1.2Mb + cmp bx,#15 + je root_defined + mov ax,#0x021c ! /dev/PS0 - 1.44Mb + cmp bx,#18 + je root_defined +undef_root: + jmp undef_root +root_defined: + seg cs + mov root_dev,ax + +! after that (everyting loaded), we jump to +! the setup-routine loaded directly after +! the bootblock: + + jmpi 0,SETUPSEG + +! This routine loads the system at address 0x10000, making sure +! no 64kB boundaries are crossed. We try to load it as fast as +! possible, loading whole tracks whenever we can. +! +! in: es - starting address segment (normally 0x1000) +! +sread: .word 1+SETUPLEN ! sectors read of current track +head: .word 0 ! current head +track: .word 0 ! current track + +read_it: + mov ax,es + test ax,#0x0fff +die: jne die ! es must be at 64kB boundary + xor bx,bx ! bx is starting address within segment +rp_read: + mov ax,es + cmp ax,#ENDSEG ! have we loaded all yet? + jb ok1_read + ret +ok1_read: + seg cs + mov ax,sectors + sub ax,sread + mov cx,ax + shl cx,#9 + add cx,bx + jnc ok2_read + je ok2_read + xor ax,ax + sub ax,bx + shr ax,#9 +ok2_read: + call read_track + mov cx,ax + add ax,sread + seg cs + cmp ax,sectors + jne ok3_read + mov ax,#1 + sub ax,head + jne ok4_read + inc track +ok4_read: + mov head,ax + xor ax,ax +ok3_read: + mov sread,ax + shl cx,#9 + add bx,cx + jnc rp_read + mov ax,es + add ah,#0x10 + mov es,ax + xor bx,bx + jmp rp_read + +read_track: + pusha + pusha + mov ax, #0xe2e ! loading... message 2e = . + mov bx, #7 + int 0x10 + popa + + mov dx,track + mov cx,sread + inc cx + mov ch,dl + mov dx,head + mov dh,dl + and dx,#0x0100 + mov ah,#2 + + push dx ! save for error dump + push cx + push bx + push ax + + int 0x13 + jc bad_rt + add sp, #8 + popa + ret + +bad_rt: push ax ! save error code + call print_all ! ah = error, al = read + + + xor ah,ah + xor dl,dl + int 0x13 + + + add sp, #10 + popa + jmp read_track + +/* + * print_all is for debugging purposes. + * It will print out all of the registers. The assumption is that this is + * called from a routine, with a stack frame like + * dx + * cx + * bx + * ax + * error + * ret <- sp + * +*/ + +print_all: + mov cx, #5 ! error code + 4 registers + mov bp, sp + +print_loop: + push cx ! save count left + call print_nl ! nl for readability + jae no_reg ! see if register name is needed + + mov ax, #0xe05 + 0x41 - 1 + sub al, cl + int 0x10 + + mov al, #0x58 ! X + int 0x10 + + mov al, #0x3a ! : + int 0x10 + +no_reg: + add bp, #2 ! next register + call print_hex ! print it + pop cx + loop print_loop + ret + +print_nl: + mov ax, #0xe0d ! CR + int 0x10 + mov al, #0xa ! LF + int 0x10 + ret + +/* + * print_hex is for debugging purposes, and prints the word + * pointed to by ss:bp in hexadecmial. +*/ + +print_hex: + mov cx, #4 ! 4 hex digits + mov dx, (bp) ! load word into dx +print_digit: + rol dx, #4 ! rotate so that lowest 4 bits are used + mov ah, #0xe + mov al, dl ! mask off so we have only next nibble + and al, #0xf + add al, #0x30 ! convert to 0 based digit, '0' + cmp al, #0x39 ! check for overflow + jbe good_digit + add al, #0x41 - 0x30 - 0xa ! 'A' - '0' - 0xa + +good_digit: + int 0x10 + loop print_digit + ret + + +/* + * 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 + xor al, al + outb + pop dx + ret + +sectors: + .word 0 + +msg1: + .byte 13,10 + .ascii "Loading" + +.org 506 +swap_dev: + .word SWAP_DEV +root_dev: + .word ROOT_DEV +boot_flag: + .word 0xAA55 + +.text +endtext: +.data +enddata: +.bss +endbss: + diff --git a/kernel/0.95/linux-0.95/boot/head.s b/kernel/0.95/linux-0.95/boot/head.s new file mode 100644 index 00000000..03771394 --- /dev/null +++ b/kernel/0.95/linux-0.95/boot/head.s @@ -0,0 +1,271 @@ +/* + * linux/boot/head.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * head.s contains the 32-bit startup code. + * + * NOTE!!! Startup happens at absolute address 0x00000000, which is also where + * the page directory will exist. The startup code will be overwritten by + * the page directory. + */ +.text +.globl _idt,_gdt,_pg_dir,_tmp_floppy_area,_floppy_track_buffer +_pg_dir: +startup_32: + cld + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + mov %ax,%gs + lss _stack_start,%esp + call setup_idt + call setup_gdt + movl $0x10,%eax # reload all the segment registers + mov %ax,%ds # after changing gdt. CS was already + mov %ax,%es # reloaded in 'setup_gdt' + mov %ax,%fs + mov %ax,%gs + lss _stack_start,%esp + xorl %eax,%eax +1: incl %eax # check that A20 really IS enabled + movl %eax,0x000000 # loop forever if it isn't + cmpl %eax,0x100000 + je 1b +/* check if it is 486 or 386. */ + movl %esp,%edi # save stack pointer + andl $0xfffffffc,%esp # align stack to avoid AC fault + pushfl # push EFLAGS + popl %eax # get EFLAGS + movl %eax,%ecx # save original EFLAGS + xorl $0x40000,%eax # flip AC bit in EFLAGS + pushl %eax # copy to EFLAGS + popfl # set EFLAGS + pushfl # get new EFLAGS + popl %eax # put it in eax + xorl %ecx,%eax # check if AC bit is changed. zero is 486. + jz 1f # 486 + pushl %ecx # restore original EFLAGS + popfl + movl %edi,%esp # restore esp + movl %cr0,%eax # 386 + andl $0x80000011,%eax # Save PG,PE,ET + orl $2,%eax # set MP + jmp 2f +/* + * NOTE! 486 should set bit 16, to check for write-protect in supervisor + * mode. Then it would be unnecessary with the "verify_area()"-calls. + * 486 users probably want to set the NE (#5) bit also, so as to use + * int 16 for math errors. + */ +1: pushl %ecx # restore original EFLAGS + popfl + movl %edi,%esp # restore esp + movl %cr0,%eax # 486 + andl $0x80000011,%eax # Save PG,PE,ET + orl $0x10022,%eax # set NE and MP +2: movl %eax,%cr0 + call check_x87 + jmp after_page_tables + +/* + * We depend on ET to be correct. This checks for 287/387. + */ +check_x87: + fninit + fstsw %ax + cmpb $0,%al + je 1f + movl %cr0,%eax /* no coprocessor: have to set bits */ + xorl $6,%eax /* reset MP, set EM */ + movl %eax,%cr0 + ret +.align 2 +1: .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ + ret + +/* + * setup_idt + * + * sets up a idt with 256 entries pointing to + * ignore_int, interrupt gates. It then loads + * idt. Everything that wants to install itself + * in the idt-table may do so themselves. Interrupts + * are enabled elsewhere, when we can be relatively + * sure everything is ok. This routine will be over- + * written by the page tables. + */ +setup_idt: + lea ignore_int,%edx + movl $0x00080000,%eax + movw %dx,%ax /* selector = 0x0008 = cs */ + movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ + + lea _idt,%edi + mov $256,%ecx +rp_sidt: + movl %eax,(%edi) + movl %edx,4(%edi) + addl $8,%edi + dec %ecx + jne rp_sidt + lidt idt_descr + ret + +/* + * setup_gdt + * + * This routines sets up a new gdt and loads it. + * Only two entries are currently built, the same + * ones that were built in init.s. The routine + * is VERY complicated at two whole lines, so this + * rather long comment is certainly needed :-). + * This routine will beoverwritten by the page tables. + */ +setup_gdt: + lgdt gdt_descr + ret + +/* + * I put the kernel page tables right after the page directory, + * using 4 of them to span 16 Mb of physical memory. People with + * more than 16MB will have to expand this. + */ +.org 0x1000 +pg0: + +.org 0x2000 +pg1: + +.org 0x3000 +pg2: + +.org 0x4000 +pg3: + +.org 0x5000 +/* + * tmp_floppy_area is used by the floppy-driver when DMA cannot + * reach to a buffer-block. It needs to be aligned, so that it isn't + * on a 64kB border. + */ +_tmp_floppy_area: + .fill 1024,1,0 +/* + * floppy_track_buffer is used to buffer one track of floppy data: it + * has to be separate from the tmp_floppy area, as otherwise a single- + * sector read/write can mess it up. It can contain one full track of + * data (18*2*512 bytes). + */ +_floppy_track_buffer: + .fill 512*2*18,1,0 + +after_page_tables: + call setup_paging + pushl $0 # These are the parameters to main :-) + pushl $0 + pushl $0 + cld # gcc2 wants the direction flag cleared at all times + call _start_kernel +L6: + jmp L6 # main should never return here, but + # just in case, we know what happens. + +/* This is the default interrupt "handler" :-) */ +int_msg: + .asciz "Unknown interrupt\n\r" +.align 2 +ignore_int: + cld + pushl %eax + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + pushl $int_msg + call _printk + popl %eax + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + + +/* + * Setup_paging + * + * This routine sets up paging by setting the page bit + * in cr0. The page tables are set up, identity-mapping + * the first 16MB. The pager assumes that no illegal + * addresses are produced (ie >4Mb on a 4Mb machine). + * + * NOTE! Although all physical memory should be identity + * mapped by this routine, only the kernel page functions + * use the >1Mb addresses directly. All "normal" functions + * use just the lower 1Mb, or the local data space, which + * will be mapped to some other place - mm keeps track of + * that. + * + * For those with more memory than 16 Mb - tough luck. I've + * not got it, why should you :-) The source is here. Change + * it. (Seriously - it shouldn't be too difficult. Mostly + * change some constants etc. I left it at 16Mb, as my machine + * even cannot be extended past that (ok, but it was cheap :-) + * I've tried to show which constants to change by having + * some kind of marker at them (search for "16Mb"), but I + * won't guarantee that's all :-( ) + */ +.align 2 +setup_paging: + movl $1024*5,%ecx /* 5 pages - pg_dir+4 page tables */ + xorl %eax,%eax + xorl %edi,%edi /* pg_dir is at 0x000 */ + cld;rep;stosl + movl $pg0+7,_pg_dir /* set present bit/user r/w */ + movl $pg1+7,_pg_dir+4 /* --------- " " --------- */ + movl $pg2+7,_pg_dir+8 /* --------- " " --------- */ + movl $pg3+7,_pg_dir+12 /* --------- " " --------- */ + movl $pg3+4092,%edi + movl $0xfff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */ + std +1: stosl /* fill pages backwards - more efficient :-) */ + subl $0x1000,%eax + jge 1b + cld + 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 0x00c09a0000000fff /* 16Mb */ + .quad 0x00c0920000000fff /* 16Mb */ + .quad 0x0000000000000000 /* TEMPORARY - don't use */ + .fill 252,8,0 /* space for LDT's and TSS's etc */ diff --git a/kernel/0.95/linux-0.95/boot/setup.S b/kernel/0.95/linux-0.95/boot/setup.S new file mode 100644 index 00000000..1befd14f --- /dev/null +++ b/kernel/0.95/linux-0.95/boot/setup.S @@ -0,0 +1,640 @@ +! +! setup.s (C) 1991 Linus Torvalds +! +! setup.s is responsible for getting the system data from the BIOS, +! and putting them into the appropriate places in system memory. +! both setup.s and system has been loaded by the bootblock. +! +! This code asks the bios for memory/disk/other parameters, and +! puts them in a "safe" place: 0x90000-0x901FF, ie where the +! boot-block used to be. It is then up to the protected mode +! system to read them from there before the area is overwritten +! for buffer-blocks. +! + +! NOTE! These had better be the same as in bootsect.s! +#include + +INITSEG = DEF_INITSEG ! we move boot here - out of the way +SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). +SETUPSEG = DEF_SETUPSEG ! this is the current segment + +.globl begtext, begdata, begbss, endtext, enddata, endbss +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +entry start +start: + +! ok, the read went well so we get current cursor position and save it for +! posterity. + + mov ax,#INITSEG ! this is done in bootsect already, but... + mov ds,ax + +! Get memory size (extended mem, kB) + + mov ah,#0x88 + int 0x15 + mov [2],ax + +! check for EGA/VGA and some config parameters + + mov ah,#0x12 + mov bl,#0x10 + int 0x10 + mov [8],ax + mov [10],bx + mov [12],cx + mov ax,#0x5019 + cmp bl,#0x10 + je novga + call chsvga +novga: mov [14],ax + mov ah,#0x03 ! read cursor pos + xor bh,bh + int 0x10 ! save it in known place, con_init fetches + mov [0],dx ! it from 0x90000. + +! Get video-card data: + + mov ah,#0x0f + int 0x10 + mov [4],bx ! bh = display page + mov [6],ax ! al = video mode, ah = window width + +! Get hd0 data + + mov ax,#0x0000 + mov ds,ax + lds si,[4*0x41] + mov ax,#INITSEG + mov es,ax + mov di,#0x0080 + mov cx,#0x10 + cld + rep + movsb + +! Get hd1 data + + mov ax,#0x0000 + mov ds,ax + lds si,[4*0x46] + mov ax,#INITSEG + mov es,ax + mov di,#0x0090 + mov cx,#0x10 + cld + rep + movsb + +! Check that there IS a hd1 :-) + + mov ax,#0x01500 + mov dl,#0x81 + int 0x13 + jc no_disk1 + cmp ah,#3 + je is_disk1 +no_disk1: + mov ax,#INITSEG + mov es,ax + mov di,#0x0090 + mov cx,#0x10 + mov ax,#0x00 + cld + rep + stosb +is_disk1: + +! 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 + jmp do_move + +! then we load the segment descriptors + +end_move: + mov ax,#SETUPSEG ! 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 + +! Routine trying to recognize type of SVGA-board present (if any) +! and if it recognize one gives the choices of resolution it offers. +! If one is found the resolution chosen is given by al,ah (rows,cols). + +chsvga: cld + push ds + push cs + pop ds + mov ax,#0xc000 + mov es,ax + lea si,msg1 + call prtstr +flush: in al,#0x60 ! Flush the keyboard buffer + cmp al,#0x82 + jb nokey + jmp flush +nokey: in al,#0x60 + cmp al,#0x82 + jb nokey + cmp al,#0xe0 + ja nokey + cmp al,#0x9c + je svga + mov ax,#0x5019 + pop ds + ret +svga: cld + lea si,idati ! Check ATI 'clues' + mov di,#0x31 + mov cx,#0x09 + repe + cmpsb + jne noati + lea si,dscati + lea di,moati + lea cx,selmod + jmp cx +noati: mov ax,#0x200f ! Check Ahead 'clues' + mov dx,#0x3ce + out dx,ax + inc dx + in al,dx + cmp al,#0x20 + je isahed + cmp al,#0x21 + jne noahed +isahed: lea si,dscahead + lea di,moahead + lea cx,selmod + jmp cx +noahed: mov dx,#0x3c3 ! Check Chips & Tech. 'clues' + in al,dx + or al,#0x10 + out dx,al + mov dx,#0x104 + in al,dx + mov bl,al + mov dx,#0x3c3 + in al,dx + and al,#0xef + out dx,al + cmp bl,[idcandt] + jne nocant + lea si,dsccandt + lea di,mocandt + lea cx,selmod + jmp cx +nocant: mov dx,#0x3d4 ! Check Cirrus 'clues' + mov al,#0x0c + out dx,al + inc dx + in al,dx + mov bl,al + xor al,al + out dx,al + dec dx + mov al,#0x1f + out dx,al + inc dx + in al,dx + mov bh,al + xor ah,ah + shl al,#4 + mov cx,ax + mov al,bh + shr al,#4 + add cx,ax + shl cx,#8 + add cx,#6 + mov ax,cx + mov dx,#0x3c4 + out dx,ax + inc dx + in al,dx + and al,al + jnz nocirr + mov al,bh + out dx,al + in al,dx + cmp al,#0x01 + jne nocirr + call rst3d4 + lea si,dsccirrus + lea di,mocirrus + lea cx,selmod + jmp cx +rst3d4: mov dx,#0x3d4 + mov al,bl + xor ah,ah + shl ax,#8 + add ax,#0x0c + out dx,ax + ret +nocirr: call rst3d4 ! Check Everex 'clues' + mov ax,#0x7000 + xor bx,bx + int 0x10 + cmp al,#0x70 + jne noevrx + shr dx,#4 + cmp dx,#0x678 + je istrid + cmp dx,#0x236 + je istrid + lea si,dsceverex + lea di,moeverex + lea cx,selmod + jmp cx +istrid: lea cx,ev2tri + jmp cx +noevrx: lea si,idgenoa ! Check Genoa 'clues' + xor ax,ax + seg es + mov al,[0x37] + mov di,ax + mov cx,#0x04 + dec si + dec di +l1: inc si + inc di + mov al,(si) + seg es + and al,(di) + cmp al,(si) + loope l1 + cmp cx,#0x00 + jne nogen + lea si,dscgenoa + lea di,mogenoa + lea cx,selmod + jmp cx +nogen: cld + lea si,idparadise ! Check Paradise 'clues' + mov di,#0x7d + mov cx,#0x04 + repe + cmpsb + jne nopara + lea si,dscparadise + lea di,moparadise + lea cx,selmod + jmp cx +nopara: mov dx,#0x3c4 ! Check Trident 'clues' + mov al,#0x0e + out dx,al + inc dx + in al,dx + xchg ah,al + mov al,#0x00 + out dx,al + in al,dx + xchg al,ah + mov bl,al ! Strange thing ... in the book this wasn't + and bl,#0x02 ! necessary but it worked on my card which + jz setb2 ! is a trident. Without it the screen goes + and al,#0xfd ! blurred ... + jmp clrb2 ! +setb2: or al,#0x02 ! +clrb2: out dx,al + and ah,#0x0f + cmp ah,#0x02 + jne notrid +ev2tri: lea si,dsctrident + lea di,motrident + lea cx,selmod + jmp cx +notrid: mov dx,#0x3cd ! Check Tseng 'clues' + in al,dx ! Could things be this simple ! :-) + mov bl,al + mov al,#0x55 + out dx,al + in al,dx + mov ah,al + mov al,bl + out dx,al + cmp ah,#0x55 + jne notsen + lea si,dsctseng + lea di,motseng + lea cx,selmod + jmp cx +notsen: mov dx,#0x3cc ! Check Video7 'clues' + in al,dx + mov dx,#0x3b4 + and al,#0x01 + jz even7 + mov dx,#0x3d4 +even7: mov al,#0x0c + out dx,al + inc dx + in al,dx + mov bl,al + mov al,#0x55 + out dx,al + in al,dx + dec dx + mov al,#0x1f + out dx,al + inc dx + in al,dx + mov bh,al + dec dx + mov al,#0x0c + out dx,al + inc dx + mov al,bl + out dx,al + mov al,#0x55 + xor al,#0xea + cmp al,bh + jne novid7 + lea si,dscvideo7 + lea di,movideo7 +selmod: push si + lea si,msg2 + call prtstr + xor cx,cx + mov cl,(di) + pop si + push si + push cx +tbl: pop bx + push bx + mov al,bl + sub al,cl + call dprnt + call spcing + lodsw + xchg al,ah + call dprnt + xchg ah,al + push ax + mov al,#0x78 + call prnt1 + pop ax + call dprnt + call docr + loop tbl + pop cx + call docr + lea si,msg3 + call prtstr + pop si + add cl,#0x80 +nonum: in al,#0x60 ! Quick and dirty... + cmp al,#0x82 + jb nonum + cmp al,#0x8b + je zero + cmp al,cl + ja nonum + jmp nozero +zero: sub al,#0x0a +nozero: sub al,#0x80 + dec al + xor ah,ah + add di,ax + inc di + push ax + mov al,(di) + int 0x10 + pop ax + shl ax,#1 + add si,ax + lodsw + pop ds + ret +novid7: pop ds ! Here could be code to support standard 80x50,80x30 + mov ax,#0x5019 + ret + +! Routine that 'tabs' to next col. + +spcing: mov al,#0x2e + call prnt1 + mov al,#0x20 + call prnt1 + mov al,#0x20 + call prnt1 + mov al,#0x20 + call prnt1 + mov al,#0x20 + call prnt1 + ret + +! Routine to print asciiz-string at DS:SI + +prtstr: lodsb + and al,al + jz fin + call prnt1 + jmp prtstr +fin: ret + +! Routine to print a decimal value on screen, the value to be +! printed is put in al (i.e 0-255). + +dprnt: push ax + push cx + mov ah,#0x00 + mov cl,#0x0a + idiv cl + cmp al,#0x09 + jbe lt100 + call dprnt + jmp skip10 +lt100: add al,#0x30 + call prnt1 +skip10: mov al,ah + add al,#0x30 + call prnt1 + pop cx + pop ax + ret + +! Part of above routine, this one just prints ascii al + +prnt1: push ax + push cx + mov bh,#0x00 + mov cx,#0x01 + mov ah,#0x0e + int 0x10 + pop cx + pop ax + ret + +! Prints + + +docr: push ax + push cx + mov bh,#0x00 + mov ah,#0x0e + mov al,#0x0a + mov cx,#0x01 + int 0x10 + mov al,#0x0d + int 0x10 + pop cx + pop ax + 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 512+gdt,0x9 ! gdt base = 0X9xxxx + +msg1: .ascii "Press to see SVGA-modes available or any other key to continue." + db 0x0d, 0x0a, 0x0a, 0x00 +msg2: .ascii "Mode: COLSxROWS:" + db 0x0d, 0x0a, 0x0a, 0x00 +msg3: .ascii "Choose mode by pressing the corresponding number." + db 0x0d, 0x0a, 0x00 + +idati: .ascii "761295520" +idcandt: .byte 0xa5 +idgenoa: .byte 0x77, 0x00, 0x66, 0x99 +idparadise: .ascii "VGA=" + +! Manufacturer: Numofmodes: Mode: + +moati: .byte 0x02, 0x23, 0x33 +moahead: .byte 0x05, 0x22, 0x23, 0x24, 0x2f, 0x34 +mocandt: .byte 0x02, 0x60, 0x61 +mocirrus: .byte 0x04, 0x1f, 0x20, 0x22, 0x31 +moeverex: .byte 0x0a, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40 +mogenoa: .byte 0x0a, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78 +moparadise: .byte 0x02, 0x55, 0x54 +motrident: .byte 0x07, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a +motseng: .byte 0x05, 0x26, 0x2a, 0x23, 0x24, 0x22 +movideo7: .byte 0x06, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45 + +! msb = Cols lsb = Rows: + +dscati: .word 0x8419, 0x842c +dscahead: .word 0x842c, 0x8419, 0x841c, 0xa032, 0x5042 +dsccandt: .word 0x8419, 0x8432 +dsccirrus: .word 0x8419, 0x842c, 0x841e, 0x6425 +dsceverex: .word 0x5022, 0x503c, 0x642b, 0x644b, 0x8419, 0x842c, 0x501e, 0x641b, 0xa040, 0x841e +dscgenoa: .word 0x5020, 0x642a, 0x8419, 0x841d, 0x8420, 0x842c, 0x843c, 0x503c, 0x5042, 0x644b +dscparadise: .word 0x8419, 0x842b +dsctrident: .word 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c +dsctseng: .word 0x503c, 0x6428, 0x8419, 0x841c, 0x842c +dscvideo7: .word 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c + +.text +endtext: +.data +enddata: +.bss +endbss: diff --git a/kernel/0.95/linux-0.95/fs/Makefile b/kernel/0.95/linux-0.95/fs/Makefile new file mode 100644 index 00000000..55bcd62b --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/Makefile @@ -0,0 +1,118 @@ +AR =ar +AS =as +CC =gcc +LD =ld +CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ + -fno-defer-pop -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 stat.o exec.o pipe.o namei.o \ + fcntl.o ioctl.o select.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 + cd minix; make clean + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + cd minix; make dep + +### Dependencies: +block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h +buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \ + ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/system.h \ + ../include/asm/io.h +char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/asm/segment.h ../include/asm/io.h +exec.o : exec.c ../include/signal.h ../include/sys/types.h \ + ../include/errno.h ../include/string.h ../include/sys/stat.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/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.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/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \ + ../include/fcntl.h ../include/sys/stat.h +file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h +inode.o : inode.c ../include/string.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \ + ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/linux/minix_fs.h \ + ../include/asm/system.h +ioctl.o : ioctl.c ../include/string.h ../include/errno.h \ + ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.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/signal.h ../include/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ + ../include/linux/minix_fs.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/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/asm/segment.h +pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \ + ../include/errno.h ../include/termios.h ../include/fcntl.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ + ../include/asm/segment.h +read_write.o : read_write.c ../include/sys/stat.h ../include/sys/types.h \ + ../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/segment.h +select.o : select.c ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/mm.h \ + ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \ + ../include/asm/system.h ../include/sys/stat.h ../include/string.h \ + ../include/const.h ../include/errno.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/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.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 ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/linux/minix_fs.h \ + ../include/asm/system.h ../include/errno.h ../include/sys/stat.h diff --git a/kernel/0.95/linux-0.95/fs/block_dev.c b/kernel/0.95/linux-0.95/fs/block_dev.c new file mode 100644 index 00000000..e4a4e9ed --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/block_dev.c @@ -0,0 +1,93 @@ +/* + * linux/fs/block_dev.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include +#include +#include + +extern int *blk_size[]; + +int block_write(struct inode * inode, struct file * filp, char * buf, int count) +{ + int block = filp->f_pos >> BLOCK_SIZE_BITS; + int offset = filp->f_pos & (BLOCK_SIZE-1); + int chars; + int written = 0; + int size; + unsigned int dev; + struct buffer_head * bh; + register char * p; + + dev = inode->i_rdev; + if (blk_size[MAJOR(dev)]) + size = blk_size[MAJOR(dev)][MINOR(dev)]; + else + size = 0x7fffffff; + while (count>0) { + if (block >= size) + return written; + chars = BLOCK_SIZE - offset; + if (chars > count) + chars=count; + if (chars == BLOCK_SIZE) + bh = getblk(dev,block); + else + bh = breada(dev,block,block+1,block+2,-1); + block++; + if (!bh) + return written?written:-EIO; + p = offset + bh->b_data; + offset = 0; + filp->f_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(struct inode * inode, struct file * filp, char * buf, int count) +{ + unsigned int block = filp->f_pos >> BLOCK_SIZE_BITS; + unsigned int offset = filp->f_pos & (BLOCK_SIZE-1); + unsigned int chars; + unsigned int size; + unsigned int dev; + int read = 0; + struct buffer_head * bh; + register char * p; + + dev = inode->i_rdev; + if (blk_size[MAJOR(dev)]) + size = blk_size[MAJOR(dev)][MINOR(dev)]; + else + size = 0x7fffffff; + while (count>0) { + if (block >= size) + return read; + chars = BLOCK_SIZE-offset; + if (chars > count) + chars = count; + if (!(bh = breada(dev,block,block+1,block+2,-1))) + return read?read:-EIO; + block++; + p = offset + bh->b_data; + offset = 0; + filp->f_pos += chars; + read += chars; + count -= chars; + while (chars-->0) + put_fs_byte(*(p++),buf++); + brelse(bh); + } + return read; +} diff --git a/kernel/0.95/linux-0.95/fs/buffer.c b/kernel/0.95/linux-0.95/fs/buffer.c new file mode 100644 index 00000000..2ece7792 --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/buffer.c @@ -0,0 +1,426 @@ +/* + * linux/fs/buffer.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'buffer.c' implements the buffer-cache functions. Race-conditions have + * been avoided by NEVER letting a interrupt change a buffer (except for the + * data, of course), but instead letting the caller do it. NOTE! As interrupts + * can wake up a caller, some cli-sti sequences are needed to check for + * sleep-on-calls. These should be extremely quick, though (I hope). + */ + +/* + * NOTE! There is one discordant note here: checking floppies for + * disk change. This is where it fits best, I think, as it should + * invalidate changed floppy-disk-caches. + */ + +#include + +#include +#include +#include +#include +#include + +extern 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(); +} + +static void sync_buffers(int dev) +{ + int i; + struct buffer_head * bh; + + bh = free_list; + for (i=0 ; ib_next_free) { +#if 0 + if (dev && (bh->b_dev != dev)) + continue; +#endif + wait_on_buffer(bh); +#if 0 + if (dev && (bh->b_dev != dev)) + continue; +#endif + if (bh->b_dirt) + ll_rw_block(WRITE,bh); + } +} + +int sys_sync(void) +{ + sync_inodes(); /* write out inodes into buffers */ + sync_buffers(0); + return 0; +} + +int sync_dev(int dev) +{ + sync_buffers(dev); + sync_inodes(); + sync_buffers(dev); + return 0; +} + +void inline invalidate_buffers(int dev) +{ + int i; + struct buffer_head * bh; + + bh = start_buffer; + for (i=0 ; ib_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev) + bh->b_uptodate = bh->b_dirt = 0; + } +} + +/* + * This routine checks whether a floppy has been changed, and + * invalidates all buffer-cache-entries in that case. This + * is a relatively slow routine, so we have to try to minimize using + * it. Thus it is called only upon a 'mount' or 'open'. This + * is the best way of combining speed and utility, I think. + * People changing diskettes in the middle of an operation deserve + * to loose :-) + * + * NOTE! Although currently this is only for floppies, the idea is + * that any additional removable block-device will use this routine, + * and that mount/open needn't know that floppies/whatever are + * special. + */ +void check_disk_change(int dev) +{ + int i; + + if (MAJOR(dev) != 2) + return; + if (!floppy_change(dev & 0x03)) + return; + for (i=0 ; ib_next) + bh->b_next->b_prev = bh->b_prev; + if (bh->b_prev) + bh->b_prev->b_next = bh->b_next; + if (hash(bh->b_dev,bh->b_blocknr) == bh) + hash(bh->b_dev,bh->b_blocknr) = bh->b_next; + bh->b_next = bh->b_prev = NULL; +} + +static inline void remove_from_free_list(struct buffer_head * bh) +{ + 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; + bh->b_next_free = bh->b_prev_free = NULL; +} + +static inline void remove_from_queues(struct buffer_head * bh) +{ + remove_from_hash_queue(bh); + remove_from_free_list(bh); +} + +static inline void put_first_free(struct buffer_head * bh) +{ + if (!bh || (bh == free_list)) + return; + remove_from_free_list(bh); +/* add to front 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; + free_list = bh; +} + +static inline void put_last_free(struct buffer_head * bh) +{ + if (!bh) + return; + if (bh == free_list) { + free_list = bh->b_next_free; + return; + } + remove_from_free_list(bh); +/* add to back 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; +} + +static inline void insert_into_queues(struct buffer_head * bh) +{ +/* put at end of free list */ + bh->b_next_free = free_list; + bh->b_prev_free = free_list->b_prev_free; + free_list->b_prev_free->b_next_free = bh; + free_list->b_prev_free = bh; +/* put the buffer in new hash-queue if it has a device */ + bh->b_prev = NULL; + bh->b_next = NULL; + if (!bh->b_dev) + return; + bh->b_next = hash(bh->b_dev,bh->b_blocknr); + hash(bh->b_dev,bh->b_blocknr) = bh; + bh->b_next->b_prev = bh; +} + +static struct buffer_head * find_buffer(int dev, int block) +{ + struct buffer_head * tmp; + + for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next) + if (tmp->b_dev==dev && tmp->b_blocknr==block) + return tmp; + return NULL; +} + +/* + * Why like this, I hear you say... The reason is race-conditions. + * As we don't lock buffers (unless we are readint them, that is), + * something might happen to it while we sleep (ie a read-error + * will force it bad). This shouldn't really happen currently, but + * the code is ready. + */ +struct buffer_head * get_hash_table(int dev, int block) +{ + struct buffer_head * bh; + + for (;;) { + if (!(bh=find_buffer(dev,block))) + return NULL; + bh->b_count++; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_blocknr == block) { + put_last_free(bh); + return bh; + } + bh->b_count--; + } +} + +/* + * Ok, this is getblk, and it isn't very clear, again to hinder + * race-conditions. Most of the code is seldom used, (ie repeating), + * so it should be much more efficient than it looks. + * + * The algoritm is changed: hopefully better, and an elusive bug removed. + * + * 14.02.92: changed it to sync dirty buffers a bit: better performance + * when the filesystem starts to get full of dirty blocks (I hope). + */ +#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock) +struct buffer_head * getblk(int dev,int block) +{ + struct buffer_head * bh, * tmp; + int buffers; + +repeat: + if (bh = get_hash_table(dev,block)) + return bh; + buffers = NR_BUFFERS; + tmp = free_list; + do { + tmp = tmp->b_next_free; + if (tmp->b_count) + continue; + if (!bh || BADNESS(tmp)b_dirt) + ll_rw_block(WRITEA,tmp); +/* and repeat until we find something good */ + } while (buffers--); + if (!bh) { + sleep_on(&buffer_wait); + goto repeat; + } + wait_on_buffer(bh); + if (bh->b_count) + goto repeat; + while (bh->b_dirt) { + sync_dev(bh->b_dev); + wait_on_buffer(bh); + if (bh->b_count) + goto repeat; + } +/* NOTE!! While we slept waiting for this block, somebody else might */ +/* already have added "this" block to the cache. check it */ + if (find_buffer(dev,block)) + goto repeat; +/* OK, FINALLY we know that this buffer is the only one of it's kind, */ +/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */ + bh->b_count=1; + bh->b_dirt=0; + bh->b_uptodate=0; + remove_from_queues(bh); + bh->b_dev=dev; + bh->b_blocknr=block; + insert_into_queues(bh); + return bh; +} + +void brelse(struct buffer_head * buf) +{ + if (!buf) + return; + wait_on_buffer(buf); + if (!(buf->b_count--)) + panic("Trying to free free buffer"); + wake_up(&buffer_wait); +} + +/* + * bread() reads a specified block and returns the buffer that contains + * it. It returns NULL if the block was unreadable. + */ +struct buffer_head * bread(int dev,int block) +{ + struct buffer_head * bh; + + if (!(bh=getblk(dev,block))) + panic("bread: getblk returned NULL\n"); + if (bh->b_uptodate) + return bh; + ll_rw_block(READ,bh); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return NULL; +} + +#define COPYBLK(from,to) \ +__asm__("cld\n\t" \ + "rep\n\t" \ + "movsl\n\t" \ + ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \ + :"cx","di","si") + +/* + * bread_page reads four buffers into memory at the desired address. It's + * a function of its own, as there is some speed to be got by reading them + * all at the same time, not waiting for one to be read, and then another + * etc. + */ +void bread_page(unsigned long address,int dev,int b[4]) +{ + struct buffer_head * bh[4]; + int i; + + for (i=0 ; i<4 ; i++) + if (b[i]) { + if (bh[i] = getblk(dev,b[i])) + if (!bh[i]->b_uptodate) + ll_rw_block(READ,bh[i]); + } else + bh[i] = NULL; + for (i=0 ; i<4 ; i++,address += BLOCK_SIZE) + if (bh[i]) { + wait_on_buffer(bh[i]); + if (bh[i]->b_uptodate) + COPYBLK((unsigned long) bh[i]->b_data,address); + brelse(bh[i]); + } +} + +/* + * Ok, breada can be used as bread, but additionally to mark other + * blocks for reading as well. End the argument list with a negative + * number. + */ +struct buffer_head * breada(int dev,int first, ...) +{ + va_list args; + struct buffer_head * bh, *tmp; + + va_start(args,first); + if (!(bh=getblk(dev,first))) + panic("bread: getblk returned NULL\n"); + if (!bh->b_uptodate) + ll_rw_block(READ,bh); + while ((first=va_arg(args,int))>=0) { + tmp=getblk(dev,first); + if (tmp) { + if (!tmp->b_uptodate) + ll_rw_block(READA,bh); + tmp->b_count--; + } + } + va_end(args); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return (NULL); +} + +void buffer_init(long buffer_end) +{ + struct buffer_head * h = start_buffer; + void * b; + int i; + + if (buffer_end == 1<<20) + b = (void *) (640*1024); + else + b = (void *) buffer_end; + while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) { + h->b_dev = 0; + h->b_dirt = 0; + h->b_count = 0; + h->b_lock = 0; + h->b_uptodate = 0; + h->b_wait = NULL; + h->b_next = NULL; + h->b_prev = NULL; + h->b_data = (char *) b; + h->b_prev_free = h-1; + h->b_next_free = h+1; + h++; + NR_BUFFERS++; + if (b == (void *) 0x100000) + b = (void *) 0xA0000; + } + h--; + free_list = start_buffer; + free_list->b_prev_free = h; + h->b_next_free = free_list; + for (i=0;i +#include + +#include +#include + +#include +#include + +extern int tty_read(unsigned minor,char * buf,int count,unsigned short flags); +extern int tty_write(unsigned minor,char * buf,int count); + +typedef (*crw_ptr)(int,unsigned,char *,int,off_t *,unsigned short); + +static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos, unsigned short flags) +{ + return ((rw==READ)?tty_read(minor,buf,count,flags): + tty_write(minor,buf,count)); +} + +static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos, unsigned short flags) +{ + if (current->tty<0) + return -EPERM; + return rw_ttyx(rw,current->tty,buf,count,pos,flags); +} + +static int rw_ram(int rw,char * buf, int count, off_t *pos) +{ + return -EIO; +} + +static int rw_mem(int rw,char * buf, int count, off_t * pos) +{ + return -EIO; +} + +static int rw_kmem(int rw,char * buf, int count, off_t * pos) +{ + /* kmem by Damiano */ + int i = *pos; /* Current position where to read */ + + /* i can go from 0 to LOW_MEM (See include/linux/mm.h */ + /* I am not shure about it but it doesn't mem fault :-) */ + while ( (count-- > 0) && (i 0 && i<65536) { + if (rw==READ) + put_fs_byte(inb(i),buf++); + else + outb(get_fs_byte(buf++),i); + i++; + } + i -= *pos; + *pos += i; + return i; +} + +static int rw_memory(int rw, unsigned minor, char * buf, int count, + off_t * pos, unsigned short flags) +{ + switch(minor) { + case 0: + return rw_ram(rw,buf,count,pos); + case 1: + return rw_mem(rw,buf,count,pos); + case 2: + return rw_kmem(rw,buf,count,pos); + case 3: + return (rw==READ)?0:count; /* rw_null */ + case 4: + return rw_port(rw,buf,count,pos); + default: + return -EIO; + } +} + +#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr))) + +static crw_ptr crw_table[]={ + NULL, /* nodev */ + rw_memory, /* /dev/mem etc */ + NULL, /* /dev/fd */ + NULL, /* /dev/hd */ + rw_ttyx, /* /dev/ttyx */ + rw_tty, /* /dev/tty */ + NULL, /* /dev/lp */ + NULL}; /* unnamed pipes */ + +int char_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + unsigned int major,minor; + crw_ptr call_addr; + + major = MAJOR(inode->i_rdev); + minor = MINOR(inode->i_rdev); + if (major >= NRDEVS) + return -ENODEV; + if (!(call_addr = crw_table[major])) + return -ENODEV; + return call_addr(READ,minor,buf,count,&filp->f_pos,filp->f_flags); +} + +int char_write(struct inode * inode, struct file * filp, char * buf, int count) +{ + unsigned int major,minor; + crw_ptr call_addr; + + major = MAJOR(inode->i_rdev); + minor = MINOR(inode->i_rdev); + if (major >= NRDEVS) + return -ENODEV; + if (!(call_addr=crw_table[major])) + return -ENODEV; + return call_addr(WRITE,minor,buf,count,&filp->f_pos,filp->f_flags); +} diff --git a/kernel/0.95/linux-0.95/fs/exec.c b/kernel/0.95/linux-0.95/fs/exec.c new file mode 100644 index 00000000..2195ff99 --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/exec.c @@ -0,0 +1,390 @@ +/* + * linux/fs/exec.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * #!-checking implemented by tytso. + */ + +/* + * Demand-loading implemented 01.12.91 - no need to read anything but + * the header into memory. The inode of the executable is put into + * "current->executable", and page faults do the actual loading. Clean. + * + * Once more I can proudly say that linux stood up to being changed: it + * was less than 2 hours work to get demand-loading completely implemented. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 + +int sys_uselib(const char * library) +{ + struct inode * inode; + unsigned long base; + + if (get_limit(0x17) != TASK_SIZE) + return -EINVAL; + if (library) { + if (!(inode=namei(library))) /* get library inode */ + return -ENOENT; + } else + inode = NULL; +/* we should check filetypes (headers etc), but we don't */ + iput(current->library); + current->library = NULL; + base = get_base(current->ldt[2]); + base += LIBRARY_OFFSET; + free_page_tables(base,LIBRARY_SIZE); + current->library = inode; + return 0; +} + +/* + * create_tables() parses the env- and arg-strings in new user + * memory and creates the pointer tables from them, and puts their + * addresses on the "stack", returning the new stack pointer value. + */ +static unsigned long * create_tables(char * p,int argc,int envc) +{ + unsigned long *argv,*envp; + unsigned long * sp; + + sp = (unsigned long *) (0xfffffffc & (unsigned long) p); + sp -= envc+1; + envp = sp; + sp -= argc+1; + argv = sp; + put_fs_long((unsigned long)envp,--sp); + put_fs_long((unsigned long)argv,--sp); + put_fs_long((unsigned long)argc,--sp); + while (argc-->0) { + put_fs_long((unsigned long) p,argv++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,argv); + while (envc-->0) { + put_fs_long((unsigned long) p,envp++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,envp); + return sp; +} + +/* + * count() counts the number of arguments/envelopes + */ +static int count(char ** argv) +{ + int i=0; + char ** tmp; + + if (tmp = argv) + while (get_fs_long((unsigned long *) (tmp++))) + i++; + + return i; +} + +/* + * 'copy_string()' copies argument/envelope strings from user + * memory to free pages in kernel mem. These are in a format ready + * to be put directly into the top of new user memory. + * + * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies + * whether the string and the string array are from user or kernel segments: + * + * from_kmem argv * argv ** + * 0 user space user space + * 1 kernel space user space + * 2 kernel space kernel space + * + * We do this by playing games with the fs segment register. Since it + * it is expensive to load a segment register, we try to avoid calling + * set_fs() unless we absolutely have to. + */ +static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, + unsigned long p, int from_kmem) +{ + char *tmp, *pag; + int len, offset = 0; + unsigned long old_fs, new_fs; + + if (!p) + return 0; /* bullet-proofing */ + new_fs = get_ds(); + old_fs = get_fs(); + if (from_kmem==2) + set_fs(new_fs); + while (argc-- > 0) { + if (from_kmem == 1) + set_fs(new_fs); + if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc))) + panic("argc is wrong"); + if (from_kmem == 1) + set_fs(old_fs); + len=0; /* remember zero-padding */ + do { + len++; + } while (get_fs_byte(tmp++)); + if (p < len) { /* this shouldn't happen - 128kB */ + set_fs(old_fs); + return 0; + } + while (len) { + --p; --tmp; --len; + if (--offset < 0) { + offset = p % PAGE_SIZE; + if (from_kmem==2) + set_fs(old_fs); + if (!(pag = (char *) page[p/PAGE_SIZE]) && + !(pag = (char *) page[p/PAGE_SIZE] = + (unsigned long *) get_free_page())) + return 0; + if (from_kmem==2) + set_fs(new_fs); + + } + *(pag + offset) = get_fs_byte(tmp); + } + } + if (from_kmem==2) + set_fs(old_fs); + return p; +} + +static unsigned long change_ldt(unsigned long text_size,unsigned long * page) +{ + unsigned long code_limit,data_limit,code_base,data_base; + int i; + + code_limit = TASK_SIZE; + data_limit = TASK_SIZE; + 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 - LIBRARY_SIZE; + for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) { + data_base -= PAGE_SIZE; + if (page[i]) + put_dirty_page(page[i],data_base); + } + return data_limit; +} + +/* + * 'do_execve()' executes a new program. + * + * NOTE! We leave 4MB free at the top of the data-area for a loadable + * library. + */ +int do_execve(unsigned long * eip,long tmp,char * filename, + char ** argv, char ** envp) +{ + struct inode * inode; + struct buffer_head * bh; + struct exec ex; + unsigned long page[MAX_ARG_PAGES]; + int i,argc,envc; + int e_uid, e_gid; + int retval; + int sh_bang = 0; + unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4; + + if ((0xffff & eip[1]) != 0x000f) + panic("execve called from supervisor mode"); + for (i=0 ; ii_mode)) { /* must be regular file */ + retval = -EACCES; + goto exec_error2; + } + i = inode->i_mode; + /* make sure we don't let suid, sgid files be ptraced. */ + if (current->flags & PF_PTRACED) { + e_uid = current->euid; + e_gid = current->egid; + } else { + e_uid = (i & S_ISUID) ? inode->i_uid : current->euid; + e_gid = (i & S_ISGID) ? inode->i_gid : current->egid; + } + if (current->euid == inode->i_uid) + i >>= 6; + else if (in_group_p(inode->i_gid)) + i >>= 3; + if (!(i & 1) && + !((inode->i_mode & 0111) && suser())) { + retval = -EACCES; + goto exec_error2; + } + if (!(bh = bread(inode->i_dev,inode->i_data[0]))) { + retval = -EACCES; + goto exec_error2; + } + ex = *((struct exec *) bh->b_data); /* read exec-header */ + if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) { + /* + * This section does the #! interpretation. + * Sorta complicated, but hopefully it will work. -TYT + */ + + char buf[128], *cp, *interp, *i_name, *i_arg; + unsigned long old_fs; + + strncpy(buf, bh->b_data+2, 127); + brelse(bh); + iput(inode); + buf[127] = '\0'; + if (cp = strchr(buf, '\n')) { + *cp = '\0'; + for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++); + } + if (!cp || *cp == '\0') { + retval = -ENOEXEC; /* No interpreter name found */ + goto exec_error1; + } + interp = i_name = cp; + i_arg = 0; + for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) { + if (*cp == '/') + i_name = cp+1; + } + if (*cp) { + *cp++ = '\0'; + i_arg = cp; + } + /* + * OK, we've parsed out the interpreter name and + * (optional) argument. + */ + if (sh_bang++ == 0) { + p = copy_strings(envc, envp, page, p, 0); + p = copy_strings(--argc, argv+1, page, p, 0); + } + /* + * Splice in (1) the interpreter's name for argv[0] + * (2) (optional) argument to interpreter + * (3) filename of shell script + * + * This is done in reverse order, because of how the + * user environment and arguments are stored. + */ + p = copy_strings(1, &filename, page, p, 1); + argc++; + if (i_arg) { + p = copy_strings(1, &i_arg, page, p, 2); + argc++; + } + p = copy_strings(1, &i_name, page, p, 2); + argc++; + if (!p) { + retval = -ENOMEM; + goto exec_error1; + } + /* + * OK, now restart the process with the interpreter's inode. + */ + old_fs = get_fs(); + set_fs(get_ds()); + if (!(inode=namei(interp))) { /* get executables inode */ + set_fs(old_fs); + retval = -ENOENT; + goto exec_error1; + } + set_fs(old_fs); + goto restart_interp; + } + brelse(bh); + if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize || + ex.a_text+ex.a_data+ex.a_bss>0x3000000 || + inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { + retval = -ENOEXEC; + goto exec_error2; + } + if (N_TXTOFF(ex) != BLOCK_SIZE) { + printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename); + retval = -ENOEXEC; + goto exec_error2; + } + if (!sh_bang) { + p = copy_strings(envc,envp,page,p,0); + p = copy_strings(argc,argv,page,p,0); + if (!p) { + retval = -ENOMEM; + goto exec_error2; + } + } +/* OK, This is the point of no return */ +/* note that current->library stays unchanged by an exec */ + if (current->executable) + iput(current->executable); + current->executable = inode; + current->signal = 0; + for (i=0 ; i<32 ; i++) { + current->sigaction[i].sa_mask = 0; + current->sigaction[i].sa_flags = 0; + if (current->sigaction[i].sa_handler != SIG_IGN) + current->sigaction[i].sa_handler = NULL; + } + for (i=0 ; iclose_on_exec>>i)&1) + sys_close(i); + current->close_on_exec = 0; + free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); + free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); + if (last_task_used_math == current) + last_task_used_math = NULL; + current->used_math = 0; + p += change_ldt(ex.a_text,page); + p -= LIBRARY_SIZE + 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; + current->suid = current->euid = e_uid; + current->sgid = current->egid = e_gid; + eip[0] = ex.a_entry; /* eip, magic happens :-) */ + eip[3] = p; /* stack pointer */ + if (current->flags & PF_PTRACED) + send_sig(SIGTRAP, current, 0); + return 0; +exec_error2: + iput(inode); +exec_error1: + for (i=0 ; i +#include +#include +#include +#include + +#include +#include + +extern int sys_close(int fd); + +static int dupfd(unsigned int fd, unsigned int arg) +{ + if (fd >= NR_OPEN || !current->filp[fd]) + return -EBADF; + if (arg >= NR_OPEN) + return -EINVAL; + while (arg < NR_OPEN) + if (current->filp[arg]) + arg++; + else + break; + if (arg >= NR_OPEN) + return -EMFILE; + current->close_on_exec &= ~(1<filp[arg] = current->filp[fd])->f_count++; + return arg; +} + +int sys_dup2(unsigned int oldfd, unsigned int newfd) +{ + if (newfd == oldfd) + return newfd; + sys_close(newfd); + return dupfd(oldfd,newfd); +} + +int sys_dup(unsigned int fildes) +{ + return dupfd(fildes,0); +} + +int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + switch (cmd) { + case F_DUPFD: + return dupfd(fd,arg); + case F_GETFD: + return (current->close_on_exec>>fd)&1; + case F_SETFD: + if (arg&1) + current->close_on_exec |= (1<close_on_exec &= ~(1<f_flags; + case F_SETFL: + filp->f_flags &= ~(O_APPEND | O_NONBLOCK); + filp->f_flags |= arg & (O_APPEND | O_NONBLOCK); + return 0; + case F_GETLK: case F_SETLK: case F_SETLKW: + return -ENOSYS; + default: + return -EINVAL; + } +} diff --git a/kernel/0.95/linux-0.95/fs/file_table.c b/kernel/0.95/linux-0.95/fs/file_table.c new file mode 100644 index 00000000..e0589acf --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/file_table.c @@ -0,0 +1,9 @@ +/* + * linux/fs/file_table.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +struct file file_table[NR_FILE]; diff --git a/kernel/0.95/linux-0.95/fs/inode.c b/kernel/0.95/linux-0.95/fs/inode.c new file mode 100644 index 00000000..dd68b1d2 --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/inode.c @@ -0,0 +1,246 @@ +/* + * linux/fs/inode.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include +#include + +struct inode inode_table[NR_INODE]={{0,},}; + +extern void minix_read_inode(struct inode * inode); +extern void minix_write_inode(struct inode * inode); + +static inline void wait_on_inode(struct inode * inode) +{ + cli(); + while (inode->i_lock) + sleep_on(&inode->i_wait); + sti(); +} + +static inline void lock_inode(struct inode * inode) +{ + cli(); + while (inode->i_lock) + sleep_on(&inode->i_wait); + inode->i_lock=1; + sti(); +} + +static inline void unlock_inode(struct inode * inode) +{ + inode->i_lock=0; + wake_up(&inode->i_wait); +} + +static void write_inode(struct inode * inode) +{ + lock_inode(inode); + if (!inode->i_dirt || !inode->i_dev) { + unlock_inode(inode); + return; + } + minix_write_inode(inode); + unlock_inode(inode); +} + +static void read_inode(struct inode * inode) +{ + lock_inode(inode); + minix_read_inode(inode); + unlock_inode(inode); +} + +int bmap(struct inode * inode, int block) +{ + return minix_bmap(inode,block); +} + +void invalidate_inodes(int dev) +{ + int i; + struct inode * inode; + + inode = 0+inode_table; + for(i=0 ; ii_dev == dev) { + if (inode->i_count) + printk("inode in use on removed disk\n\r"); + inode->i_dev = inode->i_dirt = 0; + } + } +} + +void sync_inodes(void) +{ + int i; + struct inode * inode; + + inode = 0+inode_table; + for(i=0 ; ii_dirt && !inode->i_pipe) + write_inode(inode); + } +} + +void iput(struct 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); + wake_up(&inode->i_wait2); + if (--inode->i_count) + return; + free_page(inode->i_size); + inode->i_count=0; + inode->i_dirt=0; + inode->i_pipe=0; + return; + } + if (!inode->i_dev) { + inode->i_count--; + return; + } + if (S_ISBLK(inode->i_mode)) { + sync_dev(inode->i_rdev); + wait_on_inode(inode); + } +repeat: + if (inode->i_count>1) { + inode->i_count--; + return; + } + if (!inode->i_nlink) { + minix_truncate(inode); + minix_free_inode(inode); + return; + } + if (inode->i_dirt) { + write_inode(inode); /* we can sleep - so do again */ + wait_on_inode(inode); + goto repeat; + } + inode->i_count--; + return; +} + +struct inode * get_empty_inode(void) +{ + struct inode * inode; + static struct inode * last_inode = inode_table; + int i; + + do { + inode = NULL; + for (i = NR_INODE; i ; i--) { + if (++last_inode >= inode_table + NR_INODE) + last_inode = inode_table; + if (!last_inode->i_count) { + inode = last_inode; + if (!inode->i_dirt && !inode->i_lock) + break; + } + } + if (!inode) { + for (i=0 ; ii_dirt) { + write_inode(inode); + wait_on_inode(inode); + } + } while (inode->i_count); + memset(inode,0,sizeof(*inode)); + inode->i_count = 1; + return inode; +} + +struct inode * get_pipe_inode(void) +{ + struct 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 inode * iget(int dev,int nr) +{ + struct 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_ino != nr) { + inode++; + continue; + } + wait_on_inode(inode); + if (inode->i_dev != dev || inode->i_ino != nr) { + inode = inode_table; + continue; + } + inode->i_count++; + if (inode->i_mount) { + int i; + + for (i = 0 ; i= NR_SUPER) { + printk("Mounted inode hasn't got sb\n"); + if (empty) + iput(empty); + return inode; + } + iput(inode); + if (!(inode = super_block[i].s_mounted)) + printk("iget: mounted dev has no rootinode\n"); + else { + inode->i_count++; + wait_on_inode(inode); + } + } + if (empty) + iput(empty); + return inode; + } + if (!empty) + return (NULL); + inode = empty; + if (!(inode->i_sb = get_super(dev))) { + printk("iget: gouldn't get super-block\n\t"); + iput(inode); + return NULL; + } + inode->i_dev = dev; + inode->i_ino = nr; + read_inode(inode); + return inode; +} diff --git a/kernel/0.95/linux-0.95/fs/ioctl.c b/kernel/0.95/linux-0.95/fs/ioctl.c new file mode 100644 index 00000000..d293a929 --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/ioctl.c @@ -0,0 +1,49 @@ +/* + * linux/fs/ioctl.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include + +extern int tty_ioctl(int dev, int cmd, int arg); +extern int pipe_ioctl(struct inode *pino, 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; + if (filp->f_inode->i_pipe) + return (filp->f_mode&1)?pipe_ioctl(filp->f_inode,cmd,arg):-EBADF; + mode=filp->f_inode->i_mode; + if (!S_ISCHR(mode) && !S_ISBLK(mode)) + return -EINVAL; + dev = filp->f_inode->i_rdev; + if (MAJOR(dev) >= NRDEVS) + return -ENODEV; + if (!ioctl_table[MAJOR(dev)]) + return -ENOTTY; + return ioctl_table[MAJOR(dev)](dev,cmd,arg); +} diff --git a/kernel/0.95/linux-0.95/fs/minix/Makefile b/kernel/0.95/linux-0.95/fs/minix/Makefile new file mode 100644 index 00000000..967bda58 --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/minix/Makefile @@ -0,0 +1,69 @@ +AR =ar +AS =as +CC =gcc +LD =ld +CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ + -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= minix_op.o bitmap.o truncate.o namei.o inode.o file_dev.o + +minix.o: $(OBJS) + $(LD) -r -o minix.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 ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/minix_fs.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ + ../../include/time.h ../../include/sys/resource.h \ + ../../include/linux/minix_fs.h ../../include/asm/segment.h +inode.o : inode.c ../../include/string.h ../../include/sys/stat.h \ + ../../include/sys/types.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/linux/mm.h ../../include/linux/kernel.h \ + ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \ + ../../include/time.h ../../include/sys/resource.h \ + ../../include/linux/minix_fs.h ../../include/asm/system.h +minix_op.o : minix_op.c ../../include/linux/fs.h ../../include/sys/types.h \ + ../../include/linux/minix_fs.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/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/minix_fs.h \ + ../../include/asm/segment.h ../../include/string.h ../../include/fcntl.h \ + ../../include/errno.h ../../include/const.h ../../include/sys/stat.h +truncate.o : truncate.c ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/minix_fs.h \ + ../../include/linux/tty.h ../../include/termios.h ../../include/errno.h \ + ../../include/fcntl.h ../../include/sys/stat.h diff --git a/kernel/0.95/linux-0.95/fs/minix/bitmap.c b/kernel/0.95/linux-0.95/fs/minix/bitmap.c new file mode 100644 index 00000000..645db74b --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/minix/bitmap.c @@ -0,0 +1,184 @@ +/* + * linux/fs/bitmap.c + * + * (C) 1991 Linus Torvalds + */ + +/* bitmap.c contains the code that handles the inode and block bitmaps */ +#include + +#include +#include +#include + +#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) ({\ +char res; \ +__asm__ __volatile__("btsl %1,%2\n\tsetb %0": \ +"=q" (res):"r" (nr),"m" (*(addr))); \ +res;}) + +#define clear_bit(nr,addr) ({\ +char res; \ +__asm__ __volatile__("btrl %1,%2\n\tsetnb %0": \ +"=q" (res):"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" \ + "jne 2f\n\t" \ + "addl $32,%%ecx\n\t" \ + "cmpl $8192,%%ecx\n\t" \ + "jl 1b\n\t" \ + "xorl %%edx,%%edx\n" \ + "2:\taddl %%edx,%%ecx" \ + :"=c" (__res):"0" (0),"S" (addr):"ax","dx","si"); \ +__res;}) + +int minix_free_block(int dev, int block) +{ + struct super_block * sb; + struct buffer_head * bh; + unsigned int bit,zone; + + 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) { + brelse(bh); + return 0; + } + bh->b_dirt=0; + bh->b_uptodate=0; + if (bh->b_count) + brelse(bh); + } + zone = block - sb->s_firstdatazone + 1; + bit = zone & 8191; + zone >>= 13; + bh = sb->s_zmap[zone]; + if (clear_bit(bit,bh->b_data)) + printk("free_block (%04x:%d): bit already cleared\n",dev,block); + bh->b_dirt = 1; + return 1; +} + +int minix_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 minix_free_inode(struct inode * inode) +{ + struct buffer_head * bh; + + if (!inode) + return; + if (!inode->i_dev) { + memset(inode,0,sizeof(*inode)); + return; + } + if (inode->i_count>1) { + printk("free_inode: inode has count=%d\n",inode->i_count); + return; + } + if (inode->i_nlink) { + printk("free_inode: inode has nlink=%d\n",inode->i_nlink); + return; + } + if (!inode->i_sb) { + printk("free_inode: inode on nonexistent device\n"); + return; + } + if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->s_ninodes) { + printk("free_inode: inode 0 or nonexistent inode\n"); + return; + } + if (!(bh=inode->i_sb->s_imap[inode->i_ino>>13])) { + printk("free_inode: nonexistent imap in superblock\n"); + return; + } + if (clear_bit(inode->i_ino&8191,bh->b_data)) + printk("free_inode: bit already cleared.\n\r"); + bh->b_dirt = 1; + memset(inode,0,sizeof(*inode)); +} + +struct inode * minix_new_inode(int dev) +{ + struct inode * inode; + struct buffer_head * bh; + int i,j; + + if (!(inode=get_empty_inode())) + return NULL; + if (!(inode->i_sb = get_super(dev))) { + printk("new_inode: unknown device\n"); + iput(inode); + return NULL; + } + j = 8192; + for (i=0 ; i<8 ; i++) + if (bh=inode->i_sb->s_imap[i]) + if ((j=find_first_zero(bh->b_data))<8192) + break; + if (!bh || j >= 8192 || j+i*8192 > inode->i_sb->s_ninodes) { + iput(inode); + return NULL; + } + if (set_bit(j,bh->b_data)) { /* shouldn't happen */ + printk("new_inode: bit already set"); + iput(inode); + return NULL; + } + bh->b_dirt = 1; + inode->i_count = 1; + inode->i_nlink = 1; + inode->i_dev = dev; + inode->i_uid = current->euid; + inode->i_gid = current->egid; + inode->i_dirt = 1; + inode->i_ino = j + i*8192; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_op = &minix_inode_operations; + return inode; +} diff --git a/kernel/0.95/linux-0.95/fs/minix/file_dev.c b/kernel/0.95/linux-0.95/fs/minix/file_dev.c new file mode 100644 index 00000000..646ba0e2 --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/minix/file_dev.c @@ -0,0 +1,105 @@ +/* + * linux/fs/file_dev.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + int read,left,chars,nr; + struct buffer_head * bh; + + if (filp->f_pos > inode->i_size) + left = 0; + else + left = inode->i_size - filp->f_pos; + if (left > count) + left = count; + read = 0; + while (left > 0) { + if (nr = bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS)) { + if (!(bh=bread(inode->i_dev,nr))) + return read?read:-EIO; + } else + bh = NULL; + nr = filp->f_pos & (BLOCK_SIZE-1); + chars = MIN( BLOCK_SIZE-nr , left ); + filp->f_pos += chars; + left -= chars; + read += 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 read; +} + +int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count) +{ + off_t pos; + int written,block,c; + struct buffer_head * bh; + char * p; + +/* + * 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; + written = 0; + while (writteni_dev,block))) { + if (!written) + written = -EIO; + break; + } + c = pos % BLOCK_SIZE; + p = c + bh->b_data; + bh->b_dirt = 1; + c = BLOCK_SIZE-c; + if (c > count-written) + c = count-written; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + written += 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; + inode->i_dirt = 1; + } + return written; +} diff --git a/kernel/0.95/linux-0.95/fs/minix/inode.c b/kernel/0.95/linux-0.95/fs/minix/inode.c new file mode 100644 index 00000000..a4dab053 --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/minix/inode.c @@ -0,0 +1,145 @@ +/* + * linux/fs/minix/inode.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include +#include + +static int _bmap(struct 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_data[block]) + if (inode->i_data[block]=minix_new_block(inode->i_dev)) { + inode->i_ctime=CURRENT_TIME; + inode->i_dirt=1; + } + return inode->i_data[block]; + } + block -= 7; + if (block<512) { + if (create && !inode->i_data[7]) + if (inode->i_data[7]=minix_new_block(inode->i_dev)) { + inode->i_dirt=1; + inode->i_ctime=CURRENT_TIME; + } + if (!inode->i_data[7]) + return 0; + if (!(bh = bread(inode->i_dev,inode->i_data[7]))) + return 0; + i = ((unsigned short *) (bh->b_data))[block]; + if (create && !i) + if (i=minix_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_data[8]) + if (inode->i_data[8]=minix_new_block(inode->i_dev)) { + inode->i_dirt=1; + inode->i_ctime=CURRENT_TIME; + } + if (!inode->i_data[8]) + return 0; + if (!(bh=bread(inode->i_dev,inode->i_data[8]))) + return 0; + i = ((unsigned short *)bh->b_data)[block>>9]; + if (create && !i) + if (i=minix_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=minix_new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block&511]=i; + bh->b_dirt=1; + } + brelse(bh); + return i; +} + +int minix_bmap(struct inode * inode,int block) +{ + return _bmap(inode,block,0); +} + +int minix_create_block(struct inode * inode, int block) +{ + return _bmap(inode,block,1); +} + +void minix_read_inode(struct inode * inode) +{ + struct buffer_head * bh; + struct minix_inode * raw_inode; + int block; + + block = 2 + inode->i_sb->s_imap_blocks + inode->i_sb->s_zmap_blocks + + (inode->i_ino-1)/MINIX_INODES_PER_BLOCK; + if (!(bh=bread(inode->i_dev,block))) + panic("unable to read i-node block"); + raw_inode = ((struct minix_inode *) bh->b_data) + + (inode->i_ino-1)%MINIX_INODES_PER_BLOCK; + inode->i_mode = raw_inode->i_mode; + inode->i_uid = raw_inode->i_uid; + inode->i_gid = raw_inode->i_gid; + inode->i_nlink = raw_inode->i_nlinks; + inode->i_size = raw_inode->i_size; + inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + inode->i_rdev = raw_inode->i_zone[0]; + else for (block = 0; block < 9; block++) + inode->i_data[block] = raw_inode->i_zone[block]; + brelse(bh); + inode->i_op = &minix_inode_operations; +} + +void minix_write_inode(struct inode * inode) +{ + struct buffer_head * bh; + struct minix_inode * raw_inode; + int block; + + block = 2 + inode->i_sb->s_imap_blocks + inode->i_sb->s_zmap_blocks + + (inode->i_ino-1)/MINIX_INODES_PER_BLOCK; + if (!(bh=bread(inode->i_dev,block))) + panic("unable to read i-node block"); + raw_inode = ((struct minix_inode *)bh->b_data) + + (inode->i_ino-1)%MINIX_INODES_PER_BLOCK; + raw_inode->i_mode = inode->i_mode; + raw_inode->i_uid = inode->i_uid; + raw_inode->i_gid = inode->i_gid; + raw_inode->i_nlinks = inode->i_nlink; + raw_inode->i_size = inode->i_size; + raw_inode->i_time = inode->i_mtime; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + raw_inode->i_zone[0] = inode->i_rdev; + else for (block = 0; block < 9; block++) + raw_inode->i_zone[block] = inode->i_data[block]; + bh->b_dirt=1; + inode->i_dirt=0; + brelse(bh); +} diff --git a/kernel/0.95/linux-0.95/fs/minix/minix_op.c b/kernel/0.95/linux-0.95/fs/minix/minix_op.c new file mode 100644 index 00000000..a85e3a89 --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/minix/minix_op.c @@ -0,0 +1,38 @@ +/* + * linux/fs/minix/minix_op.c + * + * structures for the minix super_block/inode/file-operations + */ + +#include +#include + +/* + * These are the low-level inode operations for minix filesystem inodes. + */ +struct inode_operations minix_inode_operations = { + minix_create, + minix_lookup, + minix_link, + minix_unlink, + minix_symlink, + minix_mkdir, + minix_rmdir, + minix_mknod, + minix_rename, + minix_readlink, + minix_open, + minix_release, + minix_follow_link +}; + +/* + * We have just NULL's here: the current defaults are ok for + * the minix filesystem. + */ +struct file_operations minix_file_operations = { + NULL, /* lseek */ + NULL, /* read */ + NULL /* write */ +}; + diff --git a/kernel/0.95/linux-0.95/fs/minix/namei.c b/kernel/0.95/linux-0.95/fs/minix/namei.c new file mode 100644 index 00000000..d3c0224c --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/minix/namei.c @@ -0,0 +1,795 @@ +/* + * linux/fs/minix/namei.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern int permission(struct inode * inode,int mask); +extern struct inode * _namei(const char * filename, struct inode * base, + int follow_links); + +/* + * comment out this line if you want names > MINIX_NAME_LEN chars to be + * truncated. Else they will be disallowed. + */ +/* #define NO_TRUNCATE */ + +/* + * ok, we cannot use strncmp, as the name is not in our data space. + * Thus we'll have to use minix_match. No big problem. Match also makes + * some sanity tests. + * + * NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure. + */ +static int minix_match(int len,const char * name,struct minix_dir_entry * de) +{ + register int same __asm__("ax"); + + if (!de || !de->inode || len > MINIX_NAME_LEN) + return 0; + /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ + if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) + return 1; + if (len < MINIX_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; +} + +/* + * minix_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + */ +static struct buffer_head * minix_find_entry(struct inode * dir, + const char * name, int namelen, struct minix_dir_entry ** res_dir) +{ + int entries; + int block,i; + struct buffer_head * bh; + struct minix_dir_entry * de; + + *res_dir = NULL; + if (!dir) + return NULL; +#ifdef NO_TRUNCATE + if (namelen > MINIX_NAME_LEN) + return NULL; +#else + if (namelen > MINIX_NAME_LEN) + namelen = MINIX_NAME_LEN; +#endif + entries = dir->i_size / (sizeof (struct minix_dir_entry)); + if (!(block = dir->i_data[0])) + return NULL; + if (!(bh = bread(dir->i_dev,block))) + return NULL; + i = 0; + de = (struct minix_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/MINIX_DIR_ENTRIES_PER_BLOCK)) || + !(bh = bread(dir->i_dev,block))) { + i += MINIX_DIR_ENTRIES_PER_BLOCK; + continue; + } + de = (struct minix_dir_entry *) bh->b_data; + } + if (minix_match(namelen,name,de)) { + *res_dir = de; + return bh; + } + de++; + i++; + } + brelse(bh); + return NULL; +} + +struct inode * minix_follow_link(struct inode * dir, struct inode * inode) +{ + unsigned short fs; + struct buffer_head * bh; + + if (!dir) { + dir = current->root; + dir->i_count++; + } + if (!inode) { + iput(dir); + return NULL; + } + if (!S_ISLNK(inode->i_mode)) { + iput(dir); + return inode; + } + __asm__("mov %%fs,%0":"=r" (fs)); + if ((current->link_count > 5) || !inode->i_data[0] || + !(bh = bread(inode->i_dev, inode->i_data[0]))) { + iput(dir); + iput(inode); + return NULL; + } + iput(inode); + __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); + current->link_count++; + inode = _namei(bh->b_data,dir,1); + current->link_count--; + __asm__("mov %0,%%fs"::"r" (fs)); + brelse(bh); + return inode; +} + +int minix_lookup(struct inode * dir,const char * name, int len, + struct inode ** result) +{ + int ino; + struct minix_dir_entry * de; + struct buffer_head * bh; + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + if (!(bh = minix_find_entry(dir,name,len,&de))) { + iput(dir); + return -ENOENT; + } + ino = de->inode; + brelse(bh); + if (!(*result = iget(dir->i_dev,ino))) { + iput(dir); + return -EACCES; + } + iput(dir); + return 0; +} + +/* + * minix_add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as minix_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 * minix_add_entry(struct inode * dir, + const char * name, int namelen, struct minix_dir_entry ** res_dir) +{ + int block,i; + struct buffer_head * bh; + struct minix_dir_entry * de; + + *res_dir = NULL; + if (!dir) + return NULL; +#ifdef NO_TRUNCATE + if (namelen > MINIX_NAME_LEN) + return NULL; +#else + if (namelen > MINIX_NAME_LEN) + namelen = MINIX_NAME_LEN; +#endif + if (!namelen) + return NULL; + if (!(block = dir->i_data[0])) + return NULL; + if (!(bh = bread(dir->i_dev,block))) + return NULL; + i = 0; + de = (struct minix_dir_entry *) bh->b_data; + while (1) { + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; + block = minix_create_block(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK); + if (!block) + return NULL; + if (!(bh = bread(dir->i_dev,block))) { + i += MINIX_DIR_ENTRIES_PER_BLOCK; + continue; + } + de = (struct minix_dir_entry *) bh->b_data; + } + if (i*sizeof(struct minix_dir_entry) >= dir->i_size) { + de->inode=0; + dir->i_size = (i+1)*sizeof(struct minix_dir_entry); + dir->i_dirt = 1; + dir->i_ctime = CURRENT_TIME; + } + if (!de->inode) { + dir->i_mtime = CURRENT_TIME; + for (i=0; i < MINIX_NAME_LEN ; i++) + de->name[i]=(ib_dirt = 1; + *res_dir = de; + return bh; + } + de++; + i++; + } + brelse(bh); + return NULL; +} + +int minix_create(struct inode * dir,const char * name, int len, int mode, + struct inode ** result) +{ + struct inode * inode; + struct buffer_head * bh; + struct minix_dir_entry * de; + + *result = NULL; + if (!dir) + return -ENOENT; + inode = minix_new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_mode = mode; + inode->i_dirt = 1; + bh = minix_add_entry(dir,name,len,&de); + if (!bh) { + inode->i_nlink--; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + *result = inode; + return 0; +} + +int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev) +{ + struct inode * inode; + struct buffer_head * bh; + struct minix_dir_entry * de; + + if (!dir) + return -ENOENT; + bh = minix_find_entry(dir,name,len,&de); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = minix_new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_uid = current->euid; + inode->i_mode = mode; + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_rdev = rdev; + inode->i_mtime = inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + bh = minix_add_entry(dir,name,len,&de); + if (!bh) { + inode->i_nlink--; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + iput(inode); + return 0; +} + +int minix_mkdir(struct inode * dir, const char * name, int len, int mode) +{ + struct inode * inode; + struct buffer_head * bh, *dir_block; + struct minix_dir_entry * de; + + bh = minix_find_entry(dir,name,len,&de); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = minix_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_data[0] = minix_new_block(inode->i_dev))) { + iput(dir); + inode->i_nlink--; + iput(inode); + return -ENOSPC; + } + inode->i_dirt = 1; + if (!(dir_block = bread(inode->i_dev,inode->i_data[0]))) { + iput(dir); + inode->i_nlink--; + iput(inode); + return -ERROR; + } + de = (struct minix_dir_entry *) dir_block->b_data; + de->inode=inode->i_ino; + strcpy(de->name,"."); + de++; + de->inode = dir->i_ino; + strcpy(de->name,".."); + inode->i_nlink = 2; + dir_block->b_dirt = 1; + brelse(dir_block); + inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask); + inode->i_dirt = 1; + bh = minix_add_entry(dir,name,len,&de); + if (!bh) { + iput(dir); + inode->i_nlink=0; + iput(inode); + return -ENOSPC; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + dir->i_nlink++; + 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 inode * inode) +{ + int nr,block; + int len; + struct buffer_head * bh; + struct minix_dir_entry * de; + + len = inode->i_size / sizeof (struct minix_dir_entry); + if (len<2 || !inode->i_data[0] || + !(bh=bread(inode->i_dev,inode->i_data[0]))) { + printk("warning - bad directory on dev %04x\n",inode->i_dev); + return 0; + } + de = (struct minix_dir_entry *) bh->b_data; + if (de[0].inode != inode->i_ino || !de[1].inode || + strcmp(".",de[0].name) || strcmp("..",de[1].name)) { + printk("warning - bad directory on dev %04x\n",inode->i_dev); + return 0; + } + nr = 2; + de += 2; + while (nr= (void *) (bh->b_data+BLOCK_SIZE)) { + brelse(bh); + block=bmap(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK); + if (!block) { + nr += MINIX_DIR_ENTRIES_PER_BLOCK; + continue; + } + if (!(bh=bread(inode->i_dev,block))) + return 0; + de = (struct minix_dir_entry *) bh->b_data; + } + if (de->inode) { + brelse(bh); + return 0; + } + de++; + nr++; + } + brelse(bh); + return 1; +} + +int minix_rmdir(struct inode * dir, const char * name, int len) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct minix_dir_entry * de; + + inode = NULL; + bh = minix_find_entry(dir,name,len,&de); + retval = -ENOENT; + if (!bh) + goto end_rmdir; + retval = -EPERM; + if (!(inode = iget(dir->i_dev, de->inode))) + goto end_rmdir; + if ((dir->i_mode & S_ISVTX) && current->euid && + inode->i_uid != current->euid) + goto end_rmdir; + if (inode->i_dev != dir->i_dev) + goto end_rmdir; + if (inode == dir) /* we may not delete ".", but "../dir" is ok */ + goto end_rmdir; + if (!S_ISDIR(inode->i_mode)) { + retval = -ENOTDIR; + goto end_rmdir; + } + if (!empty_dir(inode)) { + retval = -ENOTEMPTY; + goto end_rmdir; + } + if (inode->i_count > 1) { + retval = -EBUSY; + goto end_rmdir; + } + if (inode->i_nlink != 2) + printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink); + de->inode = 0; + bh->b_dirt = 1; + inode->i_nlink=0; + inode->i_dirt=1; + dir->i_nlink--; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt=1; + retval = 0; +end_rmdir: + iput(dir); + iput(inode); + brelse(bh); + return retval; +} + +int minix_unlink(struct inode * dir, const char * name, int len) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct minix_dir_entry * de; + + retval = -ENOENT; + inode = NULL; + bh = minix_find_entry(dir,name,len,&de); + if (!bh) + goto end_unlink; + if (!(inode = iget(dir->i_dev, de->inode))) + goto end_unlink; + retval = -EPERM; + if ((dir->i_mode & S_ISVTX) && !suser() && + current->euid != inode->i_uid && + current->euid != dir->i_uid) + goto end_unlink; + if (S_ISDIR(inode->i_mode)) + goto end_unlink; + if (!inode->i_nlink) { + printk("Deleting nonexistent file (%04x:%d), %d\n", + inode->i_dev,inode->i_ino,inode->i_nlink); + inode->i_nlink=1; + } + de->inode = 0; + bh->b_dirt = 1; + inode->i_nlink--; + inode->i_dirt = 1; + inode->i_ctime = CURRENT_TIME; + retval = 0; +end_unlink: + brelse(bh); + iput(inode); + iput(dir); + return retval; +} + +int minix_symlink(struct inode * dir, const char * name, int len, const char * symname) +{ + struct minix_dir_entry * de; + struct inode * inode = NULL; + struct buffer_head * bh = NULL, * name_block = NULL; + int i; + char c; + + if (!(inode = minix_new_inode(dir->i_dev))) { + iput(dir); + return -ENOSPC; + } + inode->i_mode = S_IFLNK | 0777; + inode->i_dirt = 1; + if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) { + iput(dir); + inode->i_nlink--; + iput(inode); + return -ENOSPC; + } + inode->i_dirt = 1; + if (!(name_block = bread(inode->i_dev,inode->i_data[0]))) { + iput(dir); + inode->i_nlink--; + iput(inode); + return -ERROR; + } + i = 0; + while (i < 1023 && (c=get_fs_byte(symname++))) + name_block->b_data[i++] = c; + name_block->b_data[i] = 0; + name_block->b_dirt = 1; + brelse(name_block); + inode->i_size = i; + inode->i_dirt = 1; + bh = minix_find_entry(dir,name,len,&de); + if (bh) { + inode->i_nlink--; + iput(inode); + brelse(bh); + iput(dir); + return -EEXIST; + } + bh = minix_add_entry(dir,name,len,&de); + if (!bh) { + inode->i_nlink--; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + iput(inode); + return 0; +} + +int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len) +{ + struct minix_dir_entry * de; + struct buffer_head * bh; + + if (S_ISDIR(oldinode->i_mode)) { + iput(oldinode); + iput(dir); + return -EPERM; + } + bh = minix_find_entry(dir,name,len,&de); + if (bh) { + brelse(bh); + iput(dir); + iput(oldinode); + return -EEXIST; + } + bh = minix_add_entry(dir,name,len,&de); + if (!bh) { + iput(dir); + iput(oldinode); + return -ENOSPC; + } + de->inode = oldinode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + oldinode->i_nlink++; + oldinode->i_ctime = CURRENT_TIME; + oldinode->i_dirt = 1; + iput(oldinode); + return 0; +} + +static int subdir(struct inode * new, struct inode * old) +{ + unsigned short fs; + int ino; + int result; + + __asm__("mov %%fs,%0":"=r" (fs)); + __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); + new->i_count++; + result = 0; + for (;;) { + if (new == old) { + result = 1; + break; + } + if (new->i_dev != old->i_dev) + break; + ino = new->i_ino; + if (minix_lookup(new,"..",2,&new)) + break; + if (new->i_ino == ino) + break; + } + iput(new); + __asm__("mov %0,%%fs"::"r" (fs)); + return result; +} + +#define PARENT_INO(buffer) \ +(((struct minix_dir_entry *) (buffer))[1].inode) + +#define PARENT_NAME(buffer) \ +(((struct minix_dir_entry *) (buffer))[1].name) + +/* + * rename uses retrying to avoid race-conditions: at least they should be minimal. + * it tries to allocate all the blocks, then sanity-checks, and if the sanity- + * checks fail, it tries to restart itself again. Very practical - no changes + * are done until we know everything works ok.. and then all the changes can be + * done in one fell swoop when we have claimed all the buffers needed. + * + * Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ +static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) +{ + struct inode * old_inode, * new_inode; + struct buffer_head * old_bh, * new_bh, * dir_bh; + struct minix_dir_entry * old_de, * new_de; + int retval; + + goto start_up; +try_again: + brelse(old_bh); + brelse(new_bh); + brelse(dir_bh); + iput(old_inode); + iput(new_inode); + current->counter = 0; + schedule(); +start_up: + old_inode = new_inode = NULL; + old_bh = new_bh = dir_bh = NULL; + old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de); + retval = -ENOENT; + if (!old_bh) + goto end_rename; + old_inode = iget(old_dir->i_dev, old_de->inode); + if (!old_inode) + goto end_rename; + new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de); + if (new_bh) { + new_inode = iget(new_dir->i_dev, new_de->inode); + if (!new_inode) { + brelse(new_bh); + new_bh = NULL; + } + } + if (new_inode == old_inode) { + retval = 0; + goto end_rename; + } + if (S_ISDIR(old_inode->i_mode)) { + retval = -EEXIST; + if (new_bh) + goto end_rename; + retval = -EACCES; + if (!permission(old_inode, MAY_WRITE)) + goto end_rename; + retval = -EINVAL; + if (subdir(new_dir, old_inode)) + goto end_rename; + retval = -EIO; + if (!old_inode->i_data[0]) + goto end_rename; + if (!(dir_bh = bread(old_inode->i_dev, old_inode->i_data[0]))) + goto end_rename; + if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) + goto end_rename; + } + if (!new_bh) + new_bh = minix_add_entry(new_dir,new_name,new_len,&new_de); + retval = -ENOSPC; + if (!new_bh) + goto end_rename; +/* sanity checking before doing the rename - avoid races */ + if (new_inode && (new_de->inode != new_inode->i_ino)) + goto try_again; + if (new_de->inode && !new_inode) + goto try_again; + if (old_de->inode != old_inode->i_ino) + goto try_again; +/* ok, that's it */ + old_de->inode = 0; + new_de->inode = old_inode->i_ino; + if (new_inode) + new_inode->i_nlink--; + old_bh->b_dirt = 1; + new_bh->b_dirt = 1; + if (dir_bh) { + PARENT_INO(dir_bh->b_data) = new_dir->i_ino; + dir_bh->b_dirt = 1; + old_dir->i_nlink--; + new_dir->i_nlink++; + old_dir->i_dirt = 1; + new_dir->i_dirt = 1; + } + retval = 0; +end_rename: + brelse(dir_bh); + brelse(old_bh); + brelse(new_bh); + iput(old_inode); + iput(new_inode); + iput(old_dir); + iput(new_dir); + return retval; +} + +/* + * Ok, rename also locks out other renames, as they can change the parent of + * a directory, and we don't want any races. Other races are checked for by + * "do_rename()", which restarts if there are inconsistencies. + * + * Note that there is no race between different filesystems: it's only within + * the same device that races occur: many renames can happen at once, as long + * as they are on different partitions. + */ +int minix_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) +{ + static struct task_struct * wait = NULL; + static int lock = 0; + int result; + + while (lock) + sleep_on(&wait); + lock = 1; + result = do_minix_rename(old_dir, old_name, old_len, + new_dir, new_name, new_len); + lock = 0; + wake_up(&wait); + return result; +} + +int minix_readlink(struct inode * inode, char * buffer, int buflen) +{ + struct buffer_head * bh; + int i; + char c; + + if (!S_ISLNK(inode->i_mode)) { + iput(inode); + return -EINVAL; + } + if (buflen > 1023) + buflen = 1023; + if (inode->i_data[0]) + bh = bread(inode->i_dev, inode->i_data[0]); + else + bh = NULL; + iput(inode); + if (!bh) + return 0; + i = 0; + while (ib_data[i])) { + i++; + put_fs_byte(c,buffer++); + } + brelse(bh); + return i; +} diff --git a/kernel/0.95/linux-0.95/fs/minix/truncate.c b/kernel/0.95/linux-0.95/fs/minix/truncate.c new file mode 100644 index 00000000..4f163bd1 --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/minix/truncate.c @@ -0,0 +1,154 @@ +/* + * linux/fs/truncate.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include +#include + +static int minix_free_ind(int dev,int block) +{ + struct buffer_head * bh; + unsigned short * p; + int i; + int block_busy; + + if (!block) + return 1; + block_busy = 0; + if (bh=bread(dev,block)) { + p = (unsigned short *) bh->b_data; + for (i=0;i<512;i++,p++) + if (*p) + if (minix_free_block(dev,*p)) { + *p = 0; + bh->b_dirt = 1; + } else + block_busy = 1; + brelse(bh); + } + if (block_busy) + return 0; + else + return minix_free_block(dev,block); +} + +static int minix_free_dind(int dev,int block) +{ + struct buffer_head * bh; + unsigned short * p; + int i; + int block_busy; + + if (!block) + return 1; + block_busy = 0; + if (bh=bread(dev,block)) { + p = (unsigned short *) bh->b_data; + for (i=0;i<512;i++,p++) + if (*p) + if (minix_free_ind(dev,*p)) { + *p = 0; + bh->b_dirt = 1; + } else + block_busy = 1; + brelse(bh); + } + if (block_busy) + return 0; + else + return minix_free_block(dev,block); +} + +void minix_truncate(struct inode * inode) +{ + int i; + int block_busy; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; +repeat: + block_busy = 0; + for (i=0;i<7;i++) + if (inode->i_data[i]) { + if (minix_free_block(inode->i_dev,inode->i_data[i])) + inode->i_data[i]=0; + else + block_busy = 1; + } + if (minix_free_ind(inode->i_dev,inode->i_data[7])) + inode->i_data[7] = 0; + else + block_busy = 1; + if (minix_free_dind(inode->i_dev,inode->i_data[8])) + inode->i_data[8] = 0; + else + block_busy = 1; + inode->i_dirt = 1; + if (block_busy) { + current->counter = 0; + schedule(); + goto repeat; + } + inode->i_size = 0; + inode->i_mtime = inode->i_ctime = CURRENT_TIME; +} + +/* + * Called when a inode is released. Note that this is different + * from minix_open: open gets called at every open, but release + * gets called only when /all/ the files are closed. + */ +void minix_release(struct inode * inode, struct file * filp) +{ + printk("minix_release not implemented\n"); +} + +static int check_char_dev(struct inode * inode, struct file * filp) +{ + struct tty_struct *tty; + int min, dev; + + dev = inode->i_rdev; + if (MAJOR(dev) == 4 || MAJOR(dev) == 5) { + if (MAJOR(dev) == 5) + min = current->tty; + else + min = MINOR(dev); + if (min < 0) + return -1; + if ((IS_A_PTY_MASTER(min)) && (inode->i_count>1)) + return -1; + tty = TTY_TABLE(min); + if (!(filp->f_flags & O_NOCTTY) && + current->leader && + current->tty<0 && + tty->session==0) { + current->tty = min; + tty->session= current->session; + tty->pgrp = current->pgrp; + } + } + return 0; +} + +/* + * Called every time a minix-file is opened + */ +int minix_open(struct inode * inode, struct file * filp) +{ + if (S_ISCHR(inode->i_mode)) { + if (check_char_dev(inode,filp)) + return -EAGAIN; + } else if (S_ISBLK(inode->i_mode)) + check_disk_change(inode->i_rdev); + filp->f_op = &minix_file_operations; + return 0; +} diff --git a/kernel/0.95/linux-0.95/fs/namei.c b/kernel/0.95/linux-0.95/fs/namei.c new file mode 100644 index 00000000..f1a0e8f6 --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/namei.c @@ -0,0 +1,460 @@ +/* + * linux/fs/namei.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * Some corrections by tytso. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct inode * _namei(const char * filename, struct inode * base, + int follow_links); + +#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE]) + +/* + * comment out this line if you want names > MINIX_NAME_LEN chars to be + * truncated. Else they will be disallowed. + */ +/* #define NO_TRUNCATE */ + +/* + * 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. + */ +int permission(struct 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_nlink) + return 0; + else if (current->euid == inode->i_uid) + mode >>= 6; + else if (in_group_p(inode->i_gid)) + mode >>= 3; + if (((mode & mask & 0007) == mask) || suser()) + return 1; + return 0; +} + +/* + * lookup() looks up one part of a pathname, using the fs-dependent + * routines (currently minix_lookup) for it. It also checks for + * fathers (pseudo-roots, mount-points) + */ +int lookup(struct inode * dir,const char * name, int len, + struct inode ** result) +{ + struct super_block * sb; + + *result = NULL; + if (len==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') { + if (dir == current->root) + len = 1; + else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) { + sb = dir->i_sb; + iput(dir); + if (dir = sb->s_covered) + dir->i_count++; + } + } + if (!dir) + return -ENOENT; + if (!permission(dir,MAY_EXEC)) { + iput(dir); + return -EACCES; + } + if (!len) { + *result = dir; + return 0; + } + if (!dir->i_op || !dir->i_op->lookup) { + iput(dir); + return -ENOENT; + } + return dir->i_op->lookup(dir,name,len,result); +} + +struct inode * follow_link(struct inode * dir, struct inode * inode) +{ + if (!dir || !inode) { + iput(dir); + iput(inode); + return NULL; + } + if (!inode->i_op || !inode->i_op->follow_link) { + iput(dir); + return inode; + } + return inode->i_op->follow_link(dir,inode); +} + +/* + * dir_namei() + * + * dir_namei() returns the inode of the directory of the + * specified name, and the name within that directory. + */ +static struct inode * dir_namei(const char * pathname, + int * namelen, const char ** name, struct inode * base) +{ + char c; + const char * thisname; + int len,error; + struct inode * inode; + + if (!base) { + base = current->pwd; + base->i_count++; + } + if ((c=get_fs_byte(pathname))=='/') { + iput(base); + base = current->root; + pathname++; + base->i_count++; + } + while (1) { + thisname = pathname; + for(len=0;(c=get_fs_byte(pathname++))&&(c!='/');len++) + /* nothing */ ; + if (!c) + break; + base->i_count++; + error = lookup(base,thisname,len,&inode); + if (error) { + iput(base); + return NULL; + } + if (!(base = follow_link(base,inode))) + return NULL; + } + *name = thisname; + *namelen = len; + return base; +} + +struct inode * _namei(const char * pathname, struct inode * base, + int follow_links) +{ + const char * basename; + int namelen,error; + struct inode * inode; + + if (!(base = dir_namei(pathname,&namelen,&basename,base))) + return NULL; + base->i_count++; /* lookup uses up base */ + error = lookup(base,basename,namelen,&inode); + if (error) { + iput(base); + return NULL; + } + if (follow_links) + inode = follow_link(base,inode); + else + iput(base); + if (inode) { + inode->i_atime=CURRENT_TIME; + inode->i_dirt=1; + } + return inode; +} + +struct inode * lnamei(const char * pathname) +{ + return _namei(pathname, NULL, 0); +} + +/* + * 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 inode * namei(const char * pathname) +{ + return _namei(pathname,NULL,1); +} + +/* + * 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 inode ** res_inode) +{ + const char * basename; + int namelen,error; + struct inode * dir, *inode; + + if ((flag & O_TRUNC) && !(flag & O_ACCMODE)) + flag |= O_WRONLY; + mode &= 0777 & ~current->umask; + mode |= I_REGULAR; + if (!(dir = dir_namei(pathname,&namelen,&basename,NULL))) + 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; + } + dir->i_count++; /* lookup eats the dir */ + error = lookup(dir,basename,namelen,&inode); + if (error) { + if (!(flag & O_CREAT)) { + iput(dir); + return error; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EACCES; + } + if (!dir->i_op || !dir->i_op->create) { + iput(dir); + return -EACCES; + } + return dir->i_op->create(dir,basename,namelen,mode,res_inode); + } + if (flag & O_EXCL) { + iput(dir); + iput(inode); + return -EEXIST; + } + if (!(inode = follow_link(dir,inode))) + return -ELOOP; + if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) || + !permission(inode,ACC_MODE(flag))) { + iput(inode); + return -EPERM; + } + inode->i_atime = CURRENT_TIME; + if (flag & O_TRUNC) + minix_truncate(inode); + *res_inode = inode; + return 0; +} + +int sys_mknod(const char * filename, int mode, int dev) +{ + const char * basename; + int namelen; + struct inode * dir; + + if (!suser()) + return -EPERM; + if (!(dir = dir_namei(filename,&namelen,&basename, NULL))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + if (!dir->i_op || !dir->i_op->mknod) { + iput(dir); + return -EPERM; + } + return dir->i_op->mknod(dir,basename,namelen,mode,dev); +} + +int sys_mkdir(const char * pathname, int mode) +{ + const char * basename; + int namelen; + struct inode * dir; + + if (!(dir = dir_namei(pathname,&namelen,&basename, NULL))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + if (!dir->i_op || !dir->i_op->mkdir) { + iput(dir); + return -EPERM; + } + return dir->i_op->mkdir(dir,basename,namelen,mode); +} + +int sys_rmdir(const char * name) +{ + const char * basename; + int namelen; + struct inode * dir; + + if (!(dir = dir_namei(name,&namelen,&basename, NULL))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + if (!dir->i_op || !dir->i_op->rmdir) { + iput(dir); + return -EPERM; + } + return dir->i_op->rmdir(dir,basename,namelen); +} + +int sys_unlink(const char * name) +{ + const char * basename; + int namelen; + struct inode * dir; + + if (!(dir = dir_namei(name,&namelen,&basename, NULL))) + return -ENOENT; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + if (!dir->i_op || !dir->i_op->unlink) { + iput(dir); + return -EPERM; + } + return dir->i_op->unlink(dir,basename,namelen); +} + +int sys_symlink(const char * oldname, const char * newname) +{ + struct inode * dir; + const char * basename; + int namelen; + + dir = dir_namei(newname,&namelen,&basename, NULL); + if (!dir) + return -EACCES; + if (!namelen) { + iput(dir); + return -EPERM; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EPERM; + } + if (!dir->i_op || !dir->i_op->symlink) { + iput(dir); + return -EPERM; + } + return dir->i_op->symlink(dir,basename,namelen,oldname); +} + +int sys_link(const char * oldname, const char * newname) +{ + struct inode * oldinode, * dir; + const char * basename; + int namelen; + + oldinode = namei(oldname); + if (!oldinode) + return -ENOENT; + dir = dir_namei(newname,&namelen,&basename, NULL); + 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; + } + if (!dir->i_op || !dir->i_op->link) { + iput(dir); + iput(oldinode); + return -EPERM; + } + return dir->i_op->link(oldinode, dir, basename, namelen); +} + +int sys_rename(const char * oldname, const char * newname) +{ + struct inode * old_dir, * new_dir; + const char * old_base, * new_base; + int old_len, new_len; + + old_dir = dir_namei(oldname,&old_len,&old_base, NULL); + if (!old_dir) + return -ENOENT; + if (!permission(old_dir,MAY_WRITE)) { + iput(old_dir); + return -EACCES; + } + if (!old_len || (get_fs_byte(old_base) == '.' && + (old_len == 1 || (get_fs_byte(old_base+1) == '.' && + old_len == 2)))) { + iput(old_dir); + return -EPERM; + } + new_dir = dir_namei(newname,&new_len,&new_base, NULL); + if (!new_dir) { + iput(old_dir); + return -ENOENT; + } + if (!permission(new_dir,MAY_WRITE)) { + iput(old_dir); + iput(new_dir); + return -EACCES; + } + if (!new_len || (get_fs_byte(new_base) == '.' && + (new_len == 1 || (get_fs_byte(new_base+1) == '.' && + new_len == 2)))) { + iput(old_dir); + iput(new_dir); + return -EPERM; + } + if (new_dir->i_dev != old_dir->i_dev) { + iput(old_dir); + iput(new_dir); + return -EXDEV; + } + if (!old_dir->i_op || !old_dir->i_op->rename) { + iput(old_dir); + iput(new_dir); + return -EPERM; + } + return old_dir->i_op->rename(old_dir, old_base, old_len, + new_dir, new_base, new_len); +} diff --git a/kernel/0.95/linux-0.95/fs/open.c b/kernel/0.95/linux-0.95/fs/open.c new file mode 100644 index 00000000..9653b834 --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/open.c @@ -0,0 +1,198 @@ +/* + * linux/fs/open.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +int sys_ustat(int dev, struct ustat * ubuf) +{ + return -ENOSYS; +} + +int sys_utime(char * filename, struct utimbuf * times) +{ + struct inode * inode; + long actime,modtime; + + if (!(inode=namei(filename))) + return -ENOENT; + if (times) { + actime = get_fs_long((unsigned long *) ×->actime); + modtime = get_fs_long((unsigned long *) ×->modtime); + } else + actime = modtime = CURRENT_TIME; + inode->i_atime = actime; + inode->i_mtime = modtime; + inode->i_dirt = 1; + iput(inode); + return 0; +} + +/* + * XXX should we use the real or effective uid? BSD uses the real uid, + * so as to make this call useful to setuid programs. + */ +int sys_access(const char * filename,int mode) +{ + struct inode * inode; + int res, i_mode; + + mode &= 0007; + if (!(inode=namei(filename))) + return -EACCES; + i_mode = res = inode->i_mode & 0777; + iput(inode); + if (current->uid == inode->i_uid) + res >>= 6; + else if (current->gid == inode->i_gid) + res >>= 6; + if ((res & 0007 & mode) == mode) + return 0; + /* + * XXX we are doing this test last because we really should be + * swapping the effective with the real user id (temporarily), + * and then calling suser() routine. If we do call the + * suser() routine, it needs to be called last. + */ + if ((!current->uid) && + (!(mode & 1) || (i_mode & 0111))) + return 0; + return -EACCES; +} + +int sys_chdir(const char * filename) +{ + struct 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 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 inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if ((current->euid != inode->i_uid) && !suser()) { + iput(inode); + return -EACCES; + } + inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777); + inode->i_dirt = 1; + iput(inode); + return 0; +} + +int sys_chown(const char * filename,int uid,int gid) +{ + struct inode * inode; + + if (!(inode=namei(filename))) + return -ENOENT; + if (!suser()) { + iput(inode); + return -EACCES; + } + inode->i_uid=uid; + inode->i_gid=gid; + inode->i_dirt=1; + iput(inode); + return 0; +} + +int sys_open(const char * filename,int flag,int mode) +{ + struct inode * inode; + struct file * f; + int i,fd; + + for(fd=0 ; fdfilp[fd]) + break; + if (fd>=NR_OPEN) + return -EINVAL; + current->close_on_exec &= ~(1<f_count) break; + if (i>=NR_FILE) + return -EINVAL; + (current->filp[fd]=f)->f_count++; + if ((i=open_namei(filename,flag,mode,&inode))<0) { + current->filp[fd]=NULL; + f->f_count=0; + return i; + } + f->f_op = NULL; + f->f_mode = "\001\002\003\000"[flag & O_ACCMODE]; + f->f_flags = flag; + f->f_count = 1; + f->f_inode = inode; + f->f_pos = 0; + if (inode->i_op && inode->i_op->open) + if (i = inode->i_op->open(inode,f)) { + iput(inode); + f->f_count=0; + current->filp[fd]=NULL; + return i; + } + return (fd); +} + +int sys_creat(const char * pathname, int mode) +{ + return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); +} + +int sys_close(unsigned int fd) +{ + struct file * filp; + + if (fd >= NR_OPEN) + return -EINVAL; + current->close_on_exec &= ~(1<filp[fd])) + return -EINVAL; + current->filp[fd] = NULL; + if (filp->f_count == 0) + panic("Close: file count is 0"); + if (--filp->f_count) + return (0); + iput(filp->f_inode); + return (0); +} diff --git a/kernel/0.95/linux-0.95/fs/pipe.c b/kernel/0.95/linux-0.95/fs/pipe.c new file mode 100644 index 00000000..d1b6e7c7 --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/pipe.c @@ -0,0 +1,131 @@ +/* + * linux/fs/pipe.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include +#include + +#include +#include +#include + +int pipe_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + int chars, size, read = 0; + + if (!(filp->f_flags & O_NONBLOCK)) + while (!PIPE_SIZE(*inode)) { + wake_up(& PIPE_WRITE_WAIT(*inode)); + if (inode->i_count != 2) /* are there any writers? */ + return 0; + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + interruptible_sleep_on(& PIPE_READ_WAIT(*inode)); + } + while (count>0 && (size = PIPE_SIZE(*inode))) { + chars = PAGE_SIZE-PIPE_TAIL(*inode); + if (chars > count) + chars = count; + if (chars > size) + chars = size; + count -= chars; + read += chars; + size = PIPE_TAIL(*inode); + PIPE_TAIL(*inode) += chars; + PIPE_TAIL(*inode) &= (PAGE_SIZE-1); + while (chars-->0) + put_fs_byte(((char *)inode->i_size)[size++],buf++); + } + wake_up(& PIPE_WRITE_WAIT(*inode)); + return read; +} + +int pipe_write(struct inode * inode, struct file * filp, char * buf, int count) +{ + int chars, size, written = 0; + + while (count>0) { + while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) { + wake_up(& PIPE_READ_WAIT(*inode)); + if (inode->i_count != 2) { /* no readers */ + current->signal |= (1<<(SIGPIPE-1)); + return written?written:-EINTR; + } + if (current->signal & ~current->blocked) + return written?written:-EINTR; + interruptible_sleep_on(&PIPE_WRITE_WAIT(*inode)); + } + chars = PAGE_SIZE-PIPE_HEAD(*inode); + if (chars > count) + chars = count; + if (chars > size) + chars = size; + count -= chars; + written += chars; + size = PIPE_HEAD(*inode); + PIPE_HEAD(*inode) += chars; + PIPE_HEAD(*inode) &= (PAGE_SIZE-1); + while (chars-->0) + ((char *)inode->i_size)[size++]=get_fs_byte(buf++); + } + wake_up(& PIPE_READ_WAIT(*inode)); + return written; +} + +int sys_pipe(unsigned long * fildes) +{ + struct inode * inode; + struct file * f[2]; + int fd[2]; + int i,j; + + j=0; + for(i=0;j<2 && if_count++; + if (j==1) + f[0]->f_count=0; + if (j<2) + return -1; + j=0; + for(i=0;j<2 && ifilp[i]) { + current->filp[ fd[j]=i ] = f[j]; + j++; + } + if (j==1) + current->filp[fd[0]]=NULL; + if (j<2) { + f[0]->f_count=f[1]->f_count=0; + return -1; + } + if (!(inode=get_pipe_inode())) { + current->filp[fd[0]] = + current->filp[fd[1]] = NULL; + f[0]->f_count = f[1]->f_count = 0; + return -1; + } + f[0]->f_inode = f[1]->f_inode = inode; + f[0]->f_pos = f[1]->f_pos = 0; + f[0]->f_mode = 1; /* read */ + f[1]->f_mode = 2; /* write */ + put_fs_long(fd[0],0+fildes); + put_fs_long(fd[1],1+fildes); + return 0; +} + +int pipe_ioctl(struct inode *pino, int cmd, int arg) +{ + switch (cmd) { + case FIONREAD: + verify_area((void *) arg,4); + put_fs_long(PIPE_SIZE(*pino),(unsigned long *) arg); + return 0; + default: + return -EINVAL; + } +} diff --git a/kernel/0.95/linux-0.95/fs/read_write.c b/kernel/0.95/linux-0.95/fs/read_write.c new file mode 100644 index 00000000..da81a6fb --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/read_write.c @@ -0,0 +1,97 @@ +/* + * linux/fs/read_write.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include +#include + +int sys_lseek(unsigned int fd,off_t offset, unsigned int origin) +{ + struct file * file; + int tmp; + + if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode)) + return -EBADF; + if (origin > 2) + return -EINVAL; + if (file->f_inode->i_pipe) + return -ESPIPE; + if (file->f_op && file->f_op->lseek) + return file->f_op->lseek(file->f_inode,file,offset,origin); +/* this is the default handler if no lseek handler is present */ + 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; + } + return file->f_pos; +} + +int sys_read(unsigned int fd,char * buf,unsigned int count) +{ + struct file * file; + struct inode * inode; + + if (fd>=NR_OPEN || !(file=current->filp[fd]) || !(inode=file->f_inode)) + return -EBADF; + if (!(file->f_mode & 1)) + return -EBADF; + if (!count) + return 0; + verify_area(buf,count); + if (file->f_op && file->f_op->read) + return file->f_op->read(inode,file,buf,count); +/* these are the default read-functions */ + if (inode->i_pipe) + return pipe_read(inode,file,buf,count); + if (S_ISCHR(inode->i_mode)) + return char_read(inode,file,buf,count); + if (S_ISBLK(inode->i_mode)) + return block_read(inode,file,buf,count); + if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) + return minix_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,unsigned int count) +{ + struct file * file; + struct inode * inode; + + if (fd>=NR_OPEN || !(file=current->filp[fd]) || !(inode=file->f_inode)) + return -EBADF; + if (!(file->f_mode&2)) + return -EBADF; + if (!count) + return 0; + if (file->f_op && file->f_op->write) + return file->f_op->write(inode,file,buf,count); +/* these are the default read-functions */ + if (inode->i_pipe) + return pipe_write(inode,file,buf,count); + if (S_ISCHR(inode->i_mode)) + return char_write(inode,file,buf,count); + if (S_ISBLK(inode->i_mode)) + return block_write(inode,file,buf,count); + if (S_ISREG(inode->i_mode)) + return minix_file_write(inode,file,buf,count); + printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode); + return -EINVAL; +} diff --git a/kernel/0.95/linux-0.95/fs/select.c b/kernel/0.95/linux-0.95/fs/select.c new file mode 100644 index 00000000..053b1ab3 --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/select.c @@ -0,0 +1,282 @@ +/* + * This file contains the procedures for the handling of select + * + * Created for Linux based loosely upon Mathius Lattner's minix + * patches by Peter MacDonald. Heavily edited by Linus. + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * Ok, Peter made a complicated, but straightforward multiple_wait() function. + * I have rewritten this, taking some shortcuts: This code may not be easy to + * follow, but it should be free of race-conditions, and it's practical. If you + * understand what I'm doing here, then you understand how the linux sleep/wakeup + * mechanism works. + * + * Two very simple procedures, add_wait() and free_wait() make all the work. We + * have to have interrupts disabled throughout the select, but that's not really + * such a loss: sleeping automatically frees interrupts when we aren't in this + * task. + */ + +typedef struct { + struct task_struct * old_task; + struct task_struct ** wait_address; +} wait_entry; + +typedef struct { + int nr; + wait_entry entry[NR_OPEN*3]; +} select_table; + +static void add_wait(struct task_struct ** wait_address, select_table * p) +{ + int i; + + if (!wait_address) + return; + for (i = 0 ; i < p->nr ; i++) + if (p->entry[i].wait_address == wait_address) + return; + p->entry[p->nr].wait_address = wait_address; + p->entry[p->nr].old_task = * wait_address; + *wait_address = current; + p->nr++; +} + +static void free_wait(select_table * p) +{ + int i; + struct task_struct ** tpp; + + for (i = 0; i < p->nr ; i++) { + tpp = p->entry[i].wait_address; + while (*tpp && *tpp != current) { + (*tpp)->state = 0; + current->state = TASK_UNINTERRUPTIBLE; + schedule(); + } + if (!*tpp) + printk("free_wait: NULL"); + if (*tpp = p->entry[i].old_task) + (**tpp).state = 0; + } + p->nr = 0; +} + +static struct tty_struct * get_tty(struct inode * inode) +{ + int major, minor; + + if (!S_ISCHR(inode->i_mode)) + return NULL; + if ((major = MAJOR(inode->i_rdev)) != 5 && major != 4) + return NULL; + if (major == 5) + minor = current->tty; + else + minor = MINOR(inode->i_rdev); + if (minor < 0) + return NULL; + return TTY_TABLE(minor); +} + +/* + * The check_XX functions check out a file. We know it's either + * a pipe, a character device or a fifo (fifo's not implemented) + */ +static int check_in(select_table * wait, struct inode * inode) +{ + struct tty_struct * tty; + + if (tty = get_tty(inode)) + if (!EMPTY(tty->secondary)) + return 1; + else + add_wait(&tty->secondary->proc_list, wait); + else if (inode->i_pipe) + if (!PIPE_EMPTY(*inode) || inode->i_count < 2) + return 1; + else + add_wait(&inode->i_wait, wait); + return 0; +} + +static int check_out(select_table * wait, struct inode * inode) +{ + struct tty_struct * tty; + + if (tty = get_tty(inode)) + if (!FULL(tty->write_q)) + return 1; + else + add_wait(&tty->write_q->proc_list, wait); + else if (inode->i_pipe) + if (!PIPE_FULL(*inode)) + return 1; + else + add_wait(&inode->i_wait, wait); + return 0; +} + +static int check_ex(select_table * wait, struct inode * inode) +{ + struct tty_struct * tty; + + if (tty = get_tty(inode)) + if (!FULL(tty->write_q)) + return 0; + else + return 0; + else if (inode->i_pipe) + if (inode->i_count < 2) + return 1; + else + add_wait(&inode->i_wait,wait); + return 0; +} + +int do_select(fd_set in, fd_set out, fd_set ex, + fd_set *inp, fd_set *outp, fd_set *exp) +{ + int count; + select_table wait_table; + int i; + fd_set mask; + + mask = in | out | ex; + for (i = 0 ; i < NR_OPEN ; i++,mask >>= 1) { + if (!(mask & 1)) + continue; + if (!current->filp[i]) + return -EBADF; + if (!current->filp[i]->f_inode) + return -EBADF; + if (current->filp[i]->f_inode->i_pipe) + continue; + if (S_ISCHR(current->filp[i]->f_inode->i_mode)) + continue; + if (S_ISFIFO(current->filp[i]->f_inode->i_mode)) + continue; + return -EBADF; + } +repeat: + wait_table.nr = 0; + *inp = *outp = *exp = 0; + count = 0; + mask = 1; + for (i = 0 ; i < NR_OPEN ; i++, mask += mask) { + if (mask & in) + if (check_in(&wait_table,current->filp[i]->f_inode)) { + *inp |= mask; + count++; + } + if (mask & out) + if (check_out(&wait_table,current->filp[i]->f_inode)) { + *outp |= mask; + count++; + } + if (mask & ex) + if (check_ex(&wait_table,current->filp[i]->f_inode)) { + *exp |= mask; + count++; + } + } + if (!(current->signal & ~current->blocked) && + current->timeout && !count) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + free_wait(&wait_table); + goto repeat; + } + free_wait(&wait_table); + return count; +} + +/* + * Note that we cannot return -ERESTARTSYS, as we change our input + * parameters. Sad, but there you are. We could do some tweaking in + * the library function ... + */ +int sys_select( unsigned long *buffer ) +{ +/* Perform the select(nd, in, out, ex, tv) system call. */ + int i; + fd_set res_in, in = 0, *inp; + fd_set res_out, out = 0, *outp; + fd_set res_ex, ex = 0, *exp; + fd_set mask; + struct timeval *tvp; + unsigned long timeout; + + mask = get_fs_long(buffer++); + if (mask >= 32) + mask = ~0; + else + mask = ~((~0) << mask); + inp = (fd_set *) get_fs_long(buffer++); + outp = (fd_set *) get_fs_long(buffer++); + exp = (fd_set *) get_fs_long(buffer++); + tvp = (struct timeval *) get_fs_long(buffer); + + if (inp) + in = mask & get_fs_long(inp); + if (outp) + out = mask & get_fs_long(outp); + if (exp) + ex = mask & get_fs_long(exp); + timeout = 0xffffffff; + if (tvp) { + timeout = get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ); + timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ; + timeout += jiffies; + } + current->timeout = timeout; + cli(); + i = do_select(in, out, ex, &res_in, &res_out, &res_ex); + if (current->timeout > jiffies) + timeout = current->timeout - jiffies; + else + timeout = 0; + sti(); + current->timeout = 0; + if (i < 0) + return i; + if (inp) { + verify_area(inp, 4); + put_fs_long(res_in,inp); + } + if (outp) { + verify_area(outp,4); + put_fs_long(res_out,outp); + } + if (exp) { + verify_area(exp,4); + put_fs_long(res_ex,exp); + } + if (tvp) { + verify_area(tvp, sizeof(*tvp)); + put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec); + timeout %= HZ; + timeout *= (1000000/HZ); + put_fs_long(timeout, (unsigned long *) &tvp->tv_usec); + } + if (!i && (current->signal & ~current->blocked)) + return -EINTR; + return i; +} diff --git a/kernel/0.95/linux-0.95/fs/stat.c b/kernel/0.95/linux-0.95/fs/stat.c new file mode 100644 index 00000000..029ec2ff --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/stat.c @@ -0,0 +1,83 @@ +/* + * linux/fs/stat.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include + +static void cp_stat(struct inode * inode, struct stat * statbuf) +{ + struct stat tmp; + int i; + + verify_area(statbuf,sizeof (struct stat)); + tmp.st_dev = inode->i_dev; + tmp.st_ino = inode->i_ino; + tmp.st_mode = inode->i_mode; + tmp.st_nlink = inode->i_nlink; + tmp.st_uid = inode->i_uid; + tmp.st_gid = inode->i_gid; + tmp.st_rdev = inode->i_rdev; + tmp.st_size = inode->i_size; + tmp.st_atime = inode->i_atime; + tmp.st_mtime = inode->i_mtime; + tmp.st_ctime = inode->i_ctime; + for (i=0 ; i= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode)) + return -EBADF; + cp_stat(inode,statbuf); + return 0; +} + +int sys_readlink(const char * path, char * buf, int bufsiz) +{ + struct inode * inode; + + if (bufsiz <= 0) + return -EINVAL; + verify_area(buf,bufsiz); + if (!(inode = lnamei(path))) + return -ENOENT; + if (!inode->i_op || !inode->i_op->readlink) { + iput(inode); + return -EINVAL; + } + return inode->i_op->readlink(inode,buf,bufsiz); +} diff --git a/kernel/0.95/linux-0.95/fs/super.c b/kernel/0.95/linux-0.95/fs/super.c new file mode 100644 index 00000000..eedff32e --- /dev/null +++ b/kernel/0.95/linux-0.95/fs/super.c @@ -0,0 +1,288 @@ +/* + * linux/fs/super.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * super.c contains code to handle the super-block tables. + */ +#include +#include +#include +#include +#include + +#include +#include + +int sync_dev(int dev); +void wait_for_keypress(void); + +/* set_bit uses setb, as gas doesn't recognize setc */ +#define set_bit(bitnr,addr) ({ \ +register int __res __asm__("ax"); \ +__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \ +__res; }) + +struct super_block super_block[NR_SUPER]; +/* this is initialized in init/main.c */ +int ROOT_DEV = 0; + +static void lock_super(struct super_block * sb) +{ + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); + sb->s_lock = 1; + sti(); +} + +static void free_super(struct super_block * sb) +{ + cli(); + sb->s_lock = 0; + wake_up(&(sb->s_wait)); + sti(); +} + +static void wait_on_super(struct super_block * sb) +{ + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); + sti(); +} + +struct super_block * get_super(int dev) +{ + struct super_block * s; + + if (!dev) + return NULL; + s = 0+super_block; + while (s < NR_SUPER+super_block) + if (s->s_dev == dev) { + wait_on_super(s); + if (s->s_dev == dev) + return s; + s = 0+super_block; + } else + s++; + return NULL; +} + +void put_super(int dev) +{ + struct super_block * sb; + int i; + + if (dev == ROOT_DEV) { + printk("root diskette changed: prepare for armageddon\n\r"); + return; + } + if (!(sb = get_super(dev))) + return; + if (sb->s_covered) { + printk("Mounted disk changed - tssk, tssk\n\r"); + return; + } + lock_super(sb); + sb->s_dev = 0; + for(i=0;is_imap[i]); + for(i=0;is_zmap[i]); + free_super(sb); + return; +} + +static struct super_block * read_super(int dev) +{ + struct super_block * s; + struct buffer_head * bh; + int i,block; + + if (!dev) + return NULL; + check_disk_change(dev); + if (s = get_super(dev)) + return s; + for (s = 0+super_block ;; s++) { + if (s >= NR_SUPER+super_block) + return NULL; + if (!s->s_dev) + break; + } + s->s_dev = dev; + s->s_mounted = NULL; + s->s_covered = NULL; + s->s_time = 0; + s->s_rd_only = 0; + s->s_dirt = 0; + lock_super(s); + if (!(bh = bread(dev,1))) { + s->s_dev=0; + free_super(s); + return NULL; + } + *((struct minix_super_block *) s) = + *((struct minix_super_block *) bh->b_data); + brelse(bh); + if (s->s_magic != MINIX_SUPER_MAGIC) { + s->s_dev = 0; + free_super(s); + return NULL; + } + for (i=0;i < MINIX_I_MAP_SLOTS;i++) + s->s_imap[i] = NULL; + for (i=0;i < MINIX_Z_MAP_SLOTS;i++) + s->s_zmap[i] = NULL; + block=2; + for (i=0 ; i < s->s_imap_blocks ; i++) + if (s->s_imap[i]=bread(dev,block)) + block++; + else + break; + for (i=0 ; i < s->s_zmap_blocks ; i++) + if (s->s_zmap[i]=bread(dev,block)) + block++; + else + break; + if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) { + for(i=0;is_imap[i]); + for(i=0;is_zmap[i]); + s->s_dev=0; + free_super(s); + return NULL; + } + s->s_imap[0]->b_data[0] |= 1; + s->s_zmap[0]->b_data[0] |= 1; + free_super(s); + return s; +} + +int sys_umount(char * dev_name) +{ + struct inode * inode; + struct super_block * sb; + int dev; + + if (!(inode=namei(dev_name))) + return -ENOENT; + dev = inode->i_rdev; + if (!S_ISBLK(inode->i_mode)) { + iput(inode); + return -ENOTBLK; + } + iput(inode); + if (dev==ROOT_DEV) + return -EBUSY; + if (!(sb=get_super(dev)) || !(sb->s_covered)) + return -ENOENT; + if (!sb->s_covered->i_mount) + printk("Mounted inode has i_mount=0\n"); + for (inode=inode_table+0 ; inodei_dev==dev && inode->i_count) + if (inode == sb->s_mounted && inode->i_count == 1) + continue; + else + return -EBUSY; + sb->s_covered->i_mount=0; + iput(sb->s_covered); + sb->s_covered = NULL; + iput(sb->s_mounted); + sb->s_mounted = NULL; + put_super(dev); + sync_dev(dev); + return 0; +} + +int sys_mount(char * dev_name, char * dir_name, int rw_flag) +{ + struct inode * dev_i, * dir_i; + struct super_block * sb; + int dev; + + if (!(dev_i=namei(dev_name))) + return -ENOENT; + dev = dev_i->i_rdev; + if (!S_ISBLK(dev_i->i_mode)) { + iput(dev_i); + return -EPERM; + } + iput(dev_i); + if (!(dir_i=namei(dir_name))) + return -ENOENT; + if (dir_i->i_count != 1 || dir_i->i_ino == MINIX_ROOT_INO) { + iput(dir_i); + return -EBUSY; + } + if (!S_ISDIR(dir_i->i_mode)) { + iput(dir_i); + return -EPERM; + } + if (!(sb=read_super(dev))) { + iput(dir_i); + return -EBUSY; + } + if (sb->s_covered) { + iput(dir_i); + return -EBUSY; + } + if (dir_i->i_mount) { + iput(dir_i); + return -EPERM; + } + if (!(sb->s_mounted = iget(dev,MINIX_ROOT_INO))) { + iput(dir_i); + return -EPERM; + } + sb->s_covered=dir_i; + dir_i->i_mount=1; + dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */ + return 0; /* we do that in umount */ +} + +void mount_root(void) +{ + int i,free; + struct super_block * p; + struct inode * mi; + + if (32 != sizeof (struct minix_inode)) + panic("bad i-node size"); + for(i=0;is_dev = 0; + p->s_lock = 0; + p->s_wait = NULL; + } + if (!(p=read_super(ROOT_DEV))) + panic("Unable to mount root"); + if (!(mi=iget(ROOT_DEV,MINIX_ROOT_INO))) + panic("Unable to read root i-node"); + mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ + p->s_mounted = p->s_covered = 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/kernel/0.95/linux-0.95/include/a.out.h b/kernel/0.95/linux-0.95/include/a.out.h new file mode 100644 index 00000000..3e67974c --- /dev/null +++ b/kernel/0.95/linux-0.95/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/kernel/0.95/linux-0.95/include/asm/io.h b/kernel/0.95/linux-0.95/include/asm/io.h new file mode 100644 index 00000000..118249ac --- /dev/null +++ b/kernel/0.95/linux-0.95/include/asm/io.h @@ -0,0 +1,27 @@ +static void inline outb(char value, unsigned short port) +{ +__asm__ volatile ("outb %0,%1"::"a" (value),"d" (port)); +} + +static void inline outb_p(char value, unsigned short port) +{ +__asm__ volatile ("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:" + ::"a" (value),"d" (port)); +} + +static unsigned char inline inb(unsigned short port) +{ + unsigned char _v; + __asm__ volatile ("inb %1,%0":"=a" (_v):"d" (port)); + return _v; +} + +static unsigned char inb_p(unsigned short port) +{ + unsigned char _v; + __asm__ volatile ("inb %1,%0\n" + "\tjmp 1f\n" + "1:\tjmp 1f\n" + "1:":"=a" (_v):"d" ((unsigned short) port)); + return _v; +} diff --git a/kernel/0.95/linux-0.95/include/asm/memory.h b/kernel/0.95/linux-0.95/include/asm/memory.h new file mode 100644 index 00000000..4b0a98e7 --- /dev/null +++ b/kernel/0.95/linux-0.95/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/kernel/0.95/linux-0.95/include/asm/segment.h b/kernel/0.95/linux-0.95/include/asm/segment.h new file mode 100644 index 00000000..5efc9e7b --- /dev/null +++ b/kernel/0.95/linux-0.95/include/asm/segment.h @@ -0,0 +1,65 @@ +extern inline unsigned char get_fs_byte(const char * addr) +{ + unsigned register char _v; + + __asm__ ("movb %%fs:%1,%0":"=q" (_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"::"q" (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)); +} + +/* + * Someone who knows GNU asm better than I should double check the followig. + * It seems to work, but I don't know if I'm doing something subtly wrong. + * --- TYT, 11/24/91 + * [ nothing wrong here, Linus: I just changed the ax to be any reg ] + */ + +extern inline unsigned long get_fs() +{ + unsigned short _v; + __asm__("mov %%fs,%0":"=r" (_v):); + return _v; +} + +extern inline unsigned long get_ds() +{ + unsigned short _v; + __asm__("mov %%ds,%0":"=r" (_v):); + return _v; +} + +extern inline void set_fs(unsigned long val) +{ + __asm__("mov %0,%%fs"::"r" ((unsigned short) val)); +} + diff --git a/kernel/0.95/linux-0.95/include/asm/system.h b/kernel/0.95/linux-0.95/include/asm/system.h new file mode 100644 index 00000000..6f5f670b --- /dev/null +++ b/kernel/0.95/linux-0.95/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" \ + "mov %%ax,%%ds\n\t" \ + "mov %%ax,%%es\n\t" \ + "mov %%ax,%%fs\n\t" \ + "mov %%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))), \ + "m" (*((char *) (gate_addr))), \ + "m" (*(4+(char *) (gate_addr))), \ + "d" ((char *) (addr)),"a" (0x00080000) \ + :"ax","dx") + +#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/kernel/0.95/linux-0.95/include/const.h b/kernel/0.95/linux-0.95/include/const.h new file mode 100644 index 00000000..7828e613 --- /dev/null +++ b/kernel/0.95/linux-0.95/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/kernel/0.95/linux-0.95/include/ctype.h b/kernel/0.95/linux-0.95/include/ctype.h new file mode 100644 index 00000000..7acf55d1 --- /dev/null +++ b/kernel/0.95/linux-0.95/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/kernel/0.95/linux-0.95/include/errno.h b/kernel/0.95/linux-0.95/include/errno.h new file mode 100644 index 00000000..a38b78fd --- /dev/null +++ b/kernel/0.95/linux-0.95/include/errno.h @@ -0,0 +1,65 @@ +#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 +#define ELOOP 40 + +/* Should never be seen by user programs */ +#define ERESTARTSYS 512 +#define ERESTARTNOINTR 513 + +#endif diff --git a/kernel/0.95/linux-0.95/include/fcntl.h b/kernel/0.95/linux-0.95/include/fcntl.h new file mode 100644 index 00000000..4bc0c10c --- /dev/null +++ b/kernel/0.95/linux-0.95/include/fcntl.h @@ -0,0 +1,55 @@ +#ifndef _FCNTL_H +#define _FCNTL_H + +#include + +/* open/fcntl - NOCTTY, NDELAY isn't implemented yet */ +#define O_ACCMODE 00003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 00100 /* not fcntl */ +#define O_EXCL 00200 /* not fcntl */ +#define O_NOCTTY 00400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#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/kernel/0.95/linux-0.95/include/linux/config.h b/kernel/0.95/linux-0.95/include/linux/config.h new file mode 100644 index 00000000..ca364b62 --- /dev/null +++ b/kernel/0.95/linux-0.95/include/linux/config.h @@ -0,0 +1,64 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +/* + * Define this if you want the math-emulation code: if this is undefined, + * the kernel will be smaller, but you'll get FPU exceptions if you don't + * have a 387 and are trying to use math. + */ + +#define KERNEL_MATH_EMULATION + + +/* + * Defines for what uname() should return + */ +#define UTS_SYSNAME "Linux" +#define UTS_NODENAME "(none)" /* set by sethostname() */ +#define UTS_RELEASE "0" /* patchlevel */ +#define UTS_VERSION "0.12" +#define UTS_MACHINE "i386" /* hardware type */ + +/* Don't touch these, unless you really know what your doing. */ +#define DEF_INITSEG 0x9000 +#define DEF_SYSSEG 0x1000 +#define DEF_SETUPSEG 0x9020 +#define DEF_SYSSIZE 0x4000 + +/* + * The root-device is no longer hard-coded. You can change the default + * root-device by changing the line ROOT_DEV = XXX in boot/bootsect.s + */ + +/* + * The keyboard is now defined in kernel/chr_dev/keyboard.S + */ + +/* + * Normally, Linux can get the drive parameters from the BIOS at + * startup, but if this for some unfathomable reason fails, you'd + * be left stranded. For this case, you can define HD_TYPE, which + * contains all necessary info on your harddisk. + * + * The HD_TYPE macro should look like this: + * + * #define HD_TYPE { head, sect, cyl, wpcom, lzone, ctl} + * + * In case of two harddisks, the info should be sepatated by + * commas: + * + * #define HD_TYPE { h,s,c,wpcom,lz,ctl },{ h,s,c,wpcom,lz,ctl } + */ +/* + This is an example, two drives, first is type 2, second is type 3: + +#define HD_TYPE { 4,17,615,300,615,8 }, { 6,17,615,300,615,0 } + + NOTE: ctl is 0 for all drives with heads<=8, and ctl=8 for drives + with more than 8 heads. + + If you want the BIOS to tell what kind of drive you have, just + leave HD_TYPE undefined. This is the normal thing to do. +*/ + +#endif diff --git a/kernel/0.95/linux-0.95/include/linux/fdreg.h b/kernel/0.95/linux-0.95/include/linux/fdreg.h new file mode 100644 index 00000000..01355af4 --- /dev/null +++ b/kernel/0.95/linux-0.95/include/linux/fdreg.h @@ -0,0 +1,71 @@ +/* + * This file contains some defines for the floppy disk controller. + * Various sources. Mostly "IBM Microcomputers: A Programmers + * Handbook", Sanches and Canton. + */ +#ifndef _FDREG_H +#define _FDREG_H + +extern int ticks_to_floppy_on(unsigned int nr); +extern void floppy_on(unsigned int nr); +extern void floppy_off(unsigned int nr); +extern void floppy_select(unsigned int nr); +extern void floppy_deselect(unsigned int nr); + +/* Fd controller regs. S&C, about page 340 */ +#define FD_STATUS 0x3f4 +#define FD_DATA 0x3f5 +#define FD_DOR 0x3f2 /* Digital Output Register */ +#define FD_DIR 0x3f7 /* Digital Input Register (read) */ +#define FD_DCR 0x3f7 /* Diskette Control Register (write)*/ + +/* Bits of main status register */ +#define STATUS_BUSYMASK 0x0F /* drive busy mask */ +#define STATUS_BUSY 0x10 /* FDC busy */ +#define STATUS_DMA 0x20 /* 0- DMA mode */ +#define STATUS_DIR 0x40 /* 0- cpu->fdc */ +#define STATUS_READY 0x80 /* Data reg ready */ + +/* Bits of FD_ST0 */ +#define ST0_DS 0x03 /* drive select mask */ +#define ST0_HA 0x04 /* Head (Address) */ +#define ST0_NR 0x08 /* Not Ready */ +#define ST0_ECE 0x10 /* Equipment chech error */ +#define ST0_SE 0x20 /* Seek end */ +#define ST0_INTR 0xC0 /* Interrupt code mask */ + +/* Bits of FD_ST1 */ +#define ST1_MAM 0x01 /* Missing Address Mark */ +#define ST1_WP 0x02 /* Write Protect */ +#define ST1_ND 0x04 /* No Data - unreadable */ +#define ST1_OR 0x10 /* OverRun */ +#define ST1_CRC 0x20 /* CRC error in data or addr */ +#define ST1_EOC 0x80 /* End Of Cylinder */ + +/* Bits of FD_ST2 */ +#define ST2_MAM 0x01 /* Missing Addess Mark (again) */ +#define ST2_BC 0x02 /* Bad Cylinder */ +#define ST2_SNS 0x04 /* Scan Not Satisfied */ +#define ST2_SEH 0x08 /* Scan Equal Hit */ +#define ST2_WC 0x10 /* Wrong Cylinder */ +#define ST2_CRC 0x20 /* CRC error in data field */ +#define ST2_CM 0x40 /* Control Mark = deleted */ + +/* Bits of FD_ST3 */ +#define ST3_HA 0x04 /* Head (Address) */ +#define ST3_TZ 0x10 /* Track Zero signal (1=track 0) */ +#define ST3_WP 0x40 /* Write Protect */ + +/* Values for FD_COMMAND */ +#define FD_RECALIBRATE 0x07 /* move to track 0 */ +#define FD_SEEK 0x0F /* seek track */ +#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */ +#define FD_WRITE 0xC5 /* write with MT, MFM */ +#define FD_SENSEI 0x08 /* Sense Interrupt Status */ +#define FD_SPECIFY 0x03 /* specify HUT etc */ + +/* DMA commands */ +#define DMA_READ 0x46 +#define DMA_WRITE 0x4A + +#endif diff --git a/kernel/0.95/linux-0.95/include/linux/fs.h b/kernel/0.95/linux-0.95/include/linux/fs.h new file mode 100644 index 00000000..0c7b2e9b --- /dev/null +++ b/kernel/0.95/linux-0.95/include/linux/fs.h @@ -0,0 +1,209 @@ +/* + * This file has definitions for some important file table + * structures etc. + */ + +#ifndef _FS_H +#define _FS_H + +#include + +/* devices are as follows: (same as minix, so we can use the minix + * file system. These are major numbers.) + * + * 0 - unused (nodev) + * 1 - /dev/mem + * 2 - /dev/fd + * 3 - /dev/hd + * 4 - /dev/ttyx + * 5 - /dev/tty + * 6 - /dev/lp + * 7 - unnamed pipes + */ + +#define IS_SEEKABLE(x) ((x)>=1 && (x)<=3) + +#define MAY_EXEC 1 +#define MAY_WRITE 2 +#define MAY_READ 4 + +#define READ 0 +#define WRITE 1 +#define READA 2 /* read-ahead - don't pause */ +#define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */ + +void buffer_init(long buffer_end); + +#define MAJOR(a) (((unsigned)(a))>>8) +#define MINOR(a) ((a)&0xff) + +#define NR_OPEN 20 +#define NR_INODE 128 +#define NR_FILE 64 +#define NR_SUPER 8 +#define NR_HASH 307 +#define NR_BUFFERS nr_buffers +#define BLOCK_SIZE 1024 +#define BLOCK_SIZE_BITS 10 +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#define PIPE_READ_WAIT(inode) ((inode).i_wait) +#define PIPE_WRITE_WAIT(inode) ((inode).i_wait2) +#define PIPE_HEAD(inode) ((inode).i_data[0]) +#define PIPE_TAIL(inode) ((inode).i_data[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 NIL_FILP ((struct file *)0) +#define SEL_IN 1 +#define SEL_OUT 2 +#define SEL_EX 4 + +typedef char buffer_block[BLOCK_SIZE]; + +struct buffer_head { + char * b_data; /* pointer to data block (1024 bytes) */ + unsigned long b_blocknr; /* block number */ + unsigned short b_dev; /* device (0 = free) */ + unsigned char b_uptodate; + unsigned char b_dirt; /* 0-clean,1-dirty */ + unsigned char b_count; /* users using this block */ + unsigned char b_lock; /* 0 - ok, 1 -locked */ + struct task_struct * b_wait; + struct buffer_head * b_prev; + struct buffer_head * b_next; + struct buffer_head * b_prev_free; + struct buffer_head * b_next_free; +}; + +struct inode { + dev_t i_dev; + ino_t i_ino; + umode_t i_mode; + nlink_t i_nlink; + uid_t i_uid; + gid_t i_gid; + dev_t i_rdev; + off_t i_size; + time_t i_atime; + time_t i_mtime; + time_t i_ctime; + unsigned long i_data[16]; + struct inode_operations * i_op; + struct super_block * i_sb; + struct task_struct * i_wait; + struct task_struct * i_wait2; /* for pipes */ + unsigned short i_count; + unsigned char i_lock; + unsigned char i_dirt; + unsigned char i_pipe; + unsigned char i_mount; + unsigned char i_seek; + unsigned char i_update; +}; + +struct file { + unsigned short f_mode; + unsigned short f_flags; + unsigned short f_count; + struct inode * f_inode; + struct file_operations * f_op; + 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 inode * s_covered; + struct inode * s_mounted; + unsigned long s_time; + struct task_struct * s_wait; + unsigned char s_lock; + unsigned char s_rd_only; + unsigned char s_dirt; +}; + +struct file_operations { + int (*lseek) (struct inode *, struct file *, off_t, int); + int (*read) (struct inode *, struct file *, char *, int); + int (*write) (struct inode *, struct file *, char *, int); +}; + +struct inode_operations { + int (*create) (struct inode *,const char *,int,int,struct inode **); + int (*lookup) (struct inode *,const char *,int,struct inode **); + int (*link) (struct inode *,struct inode *,const char *,int); + int (*unlink) (struct inode *,const char *,int); + int (*symlink) (struct inode *,const char *,int,const char *); + int (*mkdir) (struct inode *,const char *,int,int); + int (*rmdir) (struct inode *,const char *,int); + int (*mknod) (struct inode *,const char *,int,int,int); + int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int); + int (*readlink) (struct inode *,char *,int); + int (*open) (struct inode *, struct file *); + void (*release) (struct inode *, struct file *); + struct inode * (*follow_link) (struct inode *, struct inode *); +}; + +extern struct inode inode_table[NR_INODE]; +extern struct file file_table[NR_FILE]; +extern struct super_block super_block[NR_SUPER]; +extern struct buffer_head * start_buffer; +extern int nr_buffers; + +extern void check_disk_change(int dev); +extern int floppy_change(unsigned int nr); +extern int ticks_to_floppy_on(unsigned int dev); +extern void floppy_on(unsigned int dev); +extern void floppy_off(unsigned int dev); +extern void truncate(struct inode * inode); +extern void sync_inodes(void); +extern void wait_on(struct inode * inode); +extern int bmap(struct inode * inode,int block); +extern struct inode * namei(const char * pathname); +extern struct inode * lnamei(const char * pathname); +extern int open_namei(const char * pathname, int flag, int mode, + struct inode ** res_inode); +extern void iput(struct inode * inode); +extern struct inode * iget(int dev,int nr); +extern struct inode * get_empty_inode(void); +extern struct 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 ll_rw_page(int rw, int dev, int nr, char * buffer); +extern void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buffer); +extern void brelse(struct buffer_head * buf); +extern struct buffer_head * bread(int dev,int block); +extern void bread_page(unsigned long addr,int dev,int b[4]); +extern struct buffer_head * breada(int dev,int block,...); +extern int sync_dev(int dev); +extern struct super_block * get_super(int dev); +extern int ROOT_DEV; + +extern void mount_root(void); + +extern int minix_file_read(struct inode *, struct file *, char *, int); +extern int pipe_read(struct inode *, struct file *, char *, int); +extern int char_read(struct inode *, struct file *, char *, int); +extern int block_read(struct inode *, struct file *, char *, int); + +extern int minix_file_write(struct inode *, struct file *, char *, int); +extern int pipe_write(struct inode *, struct file *, char *, int); +extern int char_write(struct inode *, struct file *, char *, int); +extern int block_write(struct inode *, struct file *, char *, int); + +#endif diff --git a/kernel/0.95/linux-0.95/include/linux/hdreg.h b/kernel/0.95/linux-0.95/include/linux/hdreg.h new file mode 100644 index 00000000..883c7ae7 --- /dev/null +++ b/kernel/0.95/linux-0.95/include/linux/hdreg.h @@ -0,0 +1,67 @@ +/* + * This file contains some defines for the AT-hd-controller. + * Various sources. Check out some definitions (see comments with + * a ques). + */ +#ifndef _HDREG_H +#define _HDREG_H + +/* Hd controller regs. Ref: IBM AT Bios-listing */ +#define HD_DATA 0x1f0 /* _CTL when writing */ +#define HD_ERROR 0x1f1 /* see err-bits */ +#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */ +#define HD_SECTOR 0x1f3 /* starting sector */ +#define HD_LCYL 0x1f4 /* starting cylinder */ +#define HD_HCYL 0x1f5 /* high byte of starting cyl */ +#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */ +#define HD_STATUS 0x1f7 /* see status-bits */ +#define HD_PRECOMP HD_ERROR /* same io address, read=error, write=precomp */ +#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */ + +#define HD_CMD 0x3f6 + +/* Bits of HD_STATUS */ +#define ERR_STAT 0x01 +#define INDEX_STAT 0x02 +#define ECC_STAT 0x04 /* Corrected error */ +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Values for HD_COMMAND */ +#define WIN_RESTORE 0x10 +#define WIN_READ 0x20 +#define WIN_WRITE 0x30 +#define WIN_VERIFY 0x40 +#define WIN_FORMAT 0x50 +#define WIN_INIT 0x60 +#define WIN_SEEK 0x70 +#define WIN_DIAGNOSE 0x90 +#define WIN_SPECIFY 0x91 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark ? */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* ? */ +#define ID_ERR 0x10 /* ? */ +#define ECC_ERR 0x40 /* ? */ +#define BBD_ERR 0x80 /* ? */ + +#define EXTENDED_PARTITION 5 + +struct partition { + unsigned char boot_ind; /* 0x80 - active */ + unsigned char head; /* starting head */ + unsigned char sector; /* starting sector */ + unsigned char cyl; /* starting cylinder */ + unsigned char sys_ind; /* What partition type */ + unsigned char end_head; /* end head */ + unsigned char end_sector; /* end sector */ + unsigned char end_cyl; /* end cylinder */ + unsigned int start_sect; /* starting sector counting from 0 */ + unsigned int nr_sects; /* nr of sectors in partition */ +}; + +#endif diff --git a/kernel/0.95/linux-0.95/include/linux/head.h b/kernel/0.95/linux-0.95/include/linux/head.h new file mode 100644 index 00000000..db3dda26 --- /dev/null +++ b/kernel/0.95/linux-0.95/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/kernel/0.95/linux-0.95/include/linux/kernel.h b/kernel/0.95/linux-0.95/include/linux/kernel.h new file mode 100644 index 00000000..eab299bc --- /dev/null +++ b/kernel/0.95/linux-0.95/include/linux/kernel.h @@ -0,0 +1,24 @@ +/* + * 'kernel.h' contains some often-used function prototypes etc + */ +void verify_area(void * addr,int count); +volatile void panic(const char * str); +volatile void do_exit(long error_code); +int printf(const char * fmt, ...); +int printk(const char * fmt, ...); +void console_print(const char * str); +int tty_write(unsigned ch,char * buf,int count); +void * malloc(unsigned int size); +void free_s(void * obj, int size); + +#define free(x) free_s((x), 0) + +/* + * This is defined as a macro, but at some point this might become a + * real subroutine that sets a flag if it returns true (to do + * BSD-style accounting where the process is flagged if it uses root + * privs). The implication of this is that you should do normal + * permissions checks first, and check suser() last. + */ +#define suser() (current->euid == 0) + diff --git a/kernel/0.95/linux-0.95/include/linux/math_emu.h b/kernel/0.95/linux-0.95/include/linux/math_emu.h new file mode 100644 index 00000000..c5501b6e --- /dev/null +++ b/kernel/0.95/linux-0.95/include/linux/math_emu.h @@ -0,0 +1,186 @@ +/* + * linux/include/linux/math_emu.h + * + * (C) 1991 Linus Torvalds + */ +#ifndef _LINUX_MATH_EMU_H +#define _LINUX_MATH_EMU_H + +#include + +struct info { + long ___orig_eip; + long ___ret_from_system_call; + long ___ebx; + long ___ecx; + long ___edx; + long ___esi; + long ___edi; + long ___ebp; + long ___eax; + long ___ds; + long ___es; + long ___fs; + long ___gs; + long ___orig_eax; + long ___eip; + long ___cs; + long ___eflags; + long ___esp; + long ___ss; +}; + +#define EAX (info->___eax) +#define EBX (info->___ebx) +#define ECX (info->___ecx) +#define EDX (info->___edx) +#define ESI (info->___esi) +#define EDI (info->___edi) +#define EBP (info->___ebp) +#define ESP (info->___esp) +#define EIP (info->___eip) +#define ORIG_EIP (info->___orig_eip) +#define EFLAGS (info->___eflags) +#define DS (*(unsigned short *) &(info->___ds)) +#define ES (*(unsigned short *) &(info->___es)) +#define FS (*(unsigned short *) &(info->___fs)) +#define CS (*(unsigned short *) &(info->___cs)) +#define SS (*(unsigned short *) &(info->___ss)) + +void __math_abort(struct info *, unsigned int); + +#define math_abort(x,y) \ +(((volatile void (*)(struct info *,unsigned int)) __math_abort)((x),(y))) + +/* + * Gcc forces this stupid alignment problem: I want to use only two longs + * for the temporary real 64-bit mantissa, but then gcc aligns out the + * structure to 12 bytes which breaks things in math_emulate.c. Shit. I + * want some kind of "no-alignt" pragma or something. + */ + +typedef struct { + long a,b; + short exponent; +} temp_real; + +typedef struct { + short m0,m1,m2,m3; + short exponent; +} temp_real_unaligned; + +#define real_to_real(a,b) \ +((*(long long *) (b) = *(long long *) (a)),((b)->exponent = (a)->exponent)) + +typedef struct { + long a,b; +} long_real; + +typedef long short_real; + +typedef struct { + long a,b; + short sign; +} temp_int; + +struct swd { + int ie:1; + int de:1; + int ze:1; + int oe:1; + int ue:1; + int pe:1; + int sf:1; + int ir:1; + int c0:1; + int c1:1; + int c2:1; + int top:3; + int c3:1; + int b:1; +}; + +#define I387 (current->tss.i387) +#define SWD (*(struct swd *) &I387.swd) +#define ROUNDING ((I387.cwd >> 10) & 3) +#define PRECISION ((I387.cwd >> 8) & 3) + +#define BITS24 0 +#define BITS53 2 +#define BITS64 3 + +#define ROUND_NEAREST 0 +#define ROUND_DOWN 1 +#define ROUND_UP 2 +#define ROUND_0 3 + +#define CONSTZ (temp_real_unaligned) {0x0000,0x0000,0x0000,0x0000,0x0000} +#define CONST1 (temp_real_unaligned) {0x0000,0x0000,0x0000,0x8000,0x3FFF} +#define CONSTPI (temp_real_unaligned) {0xC235,0x2168,0xDAA2,0xC90F,0x4000} +#define CONSTLN2 (temp_real_unaligned) {0x79AC,0xD1CF,0x17F7,0xB172,0x3FFE} +#define CONSTLG2 (temp_real_unaligned) {0xF799,0xFBCF,0x9A84,0x9A20,0x3FFD} +#define CONSTL2E (temp_real_unaligned) {0xF0BC,0x5C17,0x3B29,0xB8AA,0x3FFF} +#define CONSTL2T (temp_real_unaligned) {0x8AFE,0xCD1B,0x784B,0xD49A,0x4000} + +#define set_IE() (I387.swd |= 1) +#define set_DE() (I387.swd |= 2) +#define set_ZE() (I387.swd |= 4) +#define set_OE() (I387.swd |= 8) +#define set_UE() (I387.swd |= 16) +#define set_PE() (I387.swd |= 32) + +#define set_C0() (I387.swd |= 0x0100) +#define set_C1() (I387.swd |= 0x0200) +#define set_C2() (I387.swd |= 0x0400) +#define set_C3() (I387.swd |= 0x4000) + +/* ea.c */ + +char * ea(struct info * __info, unsigned short __code); + +/* convert.c */ + +void frndint(const temp_real * __a, temp_real * __b); +void short_to_temp(const short_real * __a, temp_real * __b); +void long_to_temp(const long_real * __a, temp_real * __b); +void temp_to_short(const temp_real * __a, short_real * __b); +void temp_to_long(const temp_real * __a, long_real * __b); +void real_to_int(const temp_real * __a, temp_int * __b); +void int_to_real(const temp_int * __a, temp_real * __b); + +/* get_put.c */ + +void get_short_real(temp_real *, struct info *, unsigned short); +void get_long_real(temp_real *, struct info *, unsigned short); +void get_temp_real(temp_real *, struct info *, unsigned short); +void get_short_int(temp_real *, struct info *, unsigned short); +void get_long_int(temp_real *, struct info *, unsigned short); +void get_longlong_int(temp_real *, struct info *, unsigned short); +void get_BCD(temp_real *, struct info *, unsigned short); +void put_short_real(const temp_real *, struct info *, unsigned short); +void put_long_real(const temp_real *, struct info *, unsigned short); +void put_temp_real(const temp_real *, struct info *, unsigned short); +void put_short_int(const temp_real *, struct info *, unsigned short); +void put_long_int(const temp_real *, struct info *, unsigned short); +void put_longlong_int(const temp_real *, struct info *, unsigned short); +void put_BCD(const temp_real *, struct info *, unsigned short); + +/* add.c */ + +void fadd(const temp_real *, const temp_real *, temp_real *); + +/* mul.c */ + +void fmul(const temp_real *, const temp_real *, temp_real *); + +/* div.c */ + +void fdiv(const temp_real *, const temp_real *, temp_real *); + +/* compare.c */ + +void fcom(const temp_real *, const temp_real *); +void fucom(const temp_real *, const temp_real *); +void ftst(const temp_real *); + +#endif diff --git a/kernel/0.95/linux-0.95/include/linux/minix_fs.h b/kernel/0.95/linux-0.95/include/linux/minix_fs.h new file mode 100644 index 00000000..4ccb8458 --- /dev/null +++ b/kernel/0.95/linux-0.95/include/linux/minix_fs.h @@ -0,0 +1,78 @@ +/* + * The minix filesystem constants/structures + */ + +#ifndef _MINIX_FS_H +#define _MINIX_FS_H + +#include + +#define MINIX_NAME_LEN 14 +#define MINIX_ROOT_INO 1 + +#define MINIX_I_MAP_SLOTS 8 +#define MINIX_Z_MAP_SLOTS 8 +#define MINIX_SUPER_MAGIC 0x137F + +#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) +#define MINIX_DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_dir_entry))) + +struct minix_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 minix_super_block { + unsigned short s_ninodes; + unsigned short s_nzones; + unsigned short s_imap_blocks; + unsigned short s_zmap_blocks; + unsigned short s_firstdatazone; + unsigned short s_log_zone_size; + unsigned long s_max_size; + unsigned short s_magic; +}; + +struct minix_dir_entry { + unsigned short inode; + char name[MINIX_NAME_LEN]; +}; + +extern int minix_open(struct inode * inode, struct file * filp); +extern void minix_release(struct inode * inode, struct file * filp); +extern struct inode * minix_follow_link(struct inode * dir, struct inode * inode); +extern int minix_lookup(struct inode * dir,const char * name, int len, + struct inode ** result); +extern int minix_create(struct inode * dir,const char * name, int len, int mode, + struct inode ** result); +extern int minix_mkdir(struct inode * dir, const char * name, int len, int mode); +extern int minix_rmdir(struct inode * dir, const char * name, int len); +extern int minix_unlink(struct inode * dir, const char * name, int len); +extern int minix_symlink(struct inode * inode, const char * name, int len, + const char * symname); +extern int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len); +extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); +extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len); +extern int minix_readlink(struct inode * inode, char * buffer, int buflen); +extern struct inode * minix_new_inode(int dev); +extern void minix_free_inode(struct inode * inode); +extern int minix_new_block(int dev); +extern int minix_free_block(int dev, int block); + +extern int minix_create_block(struct inode * inode, int block); +extern int minix_bmap(struct inode * inode,int block); + +extern int minix_lseek(struct inode * inode, struct file * filp, off_t offset, int origin); +extern int minix_read(struct inode * inode, struct file * filp, char * buf, int count); +extern int minix_write(struct inode * inode, struct file * filp, char * buf, int count); + +extern struct inode_operations minix_inode_operations; +extern struct file_operations minix_file_operations; + +#endif diff --git a/kernel/0.95/linux-0.95/include/linux/mm.h b/kernel/0.95/linux-0.95/include/linux/mm.h new file mode 100644 index 00000000..e1eacea9 --- /dev/null +++ b/kernel/0.95/linux-0.95/include/linux/mm.h @@ -0,0 +1,51 @@ +#ifndef _MM_H +#define _MM_H + +#define PAGE_SIZE 4096 + +#include +#include +#include + +extern unsigned int swap_device; +extern struct inode * swap_file; + +extern void rw_swap_page(int rw, unsigned int nr, char * buf); + +#define read_swap_page(nr,buf) \ + rw_swap_page(READ,(nr),(buf)) +#define write_swap_page(nr,buf) \ + rw_swap_page(WRITE,(nr),(buf)) + +extern unsigned long get_free_page(void); +extern unsigned long put_dirty_page(unsigned long page,unsigned long address); +extern void free_page(unsigned long addr); +void swap_free(int page_nr); +void swap_in(unsigned long *table_ptr); + +extern inline volatile void oom(void) +{ + printk("out of memory\n\r"); + do_exit(SIGSEGV); +} + +#define invalidate() \ +__asm__("movl %%eax,%%cr3"::"a" (0)) + +/* these are not to be changed without changing head.s etc */ +#define LOW_MEM 0x100000 +extern unsigned long HIGH_MEMORY; +#define PAGING_MEMORY (15*1024*1024) +#define PAGING_PAGES (PAGING_MEMORY>>12) +#define MAP_NR(addr) (((addr)-LOW_MEM)>>12) +#define USED 100 + +extern unsigned char mem_map [ PAGING_PAGES ]; + +#define PAGE_DIRTY 0x40 +#define PAGE_ACCESSED 0x20 +#define PAGE_USER 0x04 +#define PAGE_RW 0x02 +#define PAGE_PRESENT 0x01 + +#endif diff --git a/kernel/0.95/linux-0.95/include/linux/sched.h b/kernel/0.95/linux-0.95/include/linux/sched.h new file mode 100644 index 00000000..d903e2da --- /dev/null +++ b/kernel/0.95/linux-0.95/include/linux/sched.h @@ -0,0 +1,295 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#define HZ 100 + +#define NR_TASKS 64 +#define TASK_SIZE 0x04000000 +#define LIBRARY_SIZE 0x00400000 + +#if (TASK_SIZE & 0x3fffff) +#error "TASK_SIZE must be multiple of 4M" +#endif + +#if (LIBRARY_SIZE & 0x3fffff) +#error "LIBRARY_SIZE must be a multiple of 4M" +#endif + +#if (LIBRARY_SIZE >= (TASK_SIZE/2)) +#error "LIBRARY_SIZE too damn big!" +#endif + +#if (((TASK_SIZE>>16)*NR_TASKS) != 0x10000) +#error "TASK_SIZE*NR_TASKS must be 4GB" +#endif + +#define LIBRARY_OFFSET (TASK_SIZE - LIBRARY_SIZE) + +#define CT_TO_SECS(x) ((x) / HZ) +#define CT_TO_USECS(x) (((x) % HZ) * 1000000/HZ) + +#define FIRST_TASK task[0] +#define LAST_TASK task[NR_TASKS-1] + +#include +#include +#include +#include +#include +#include +#include + +#if (NR_OPEN > 32) +#error "Currently the close-on-exec-flags and select masks are in one long, max 32 files/proc" +#endif + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_ZOMBIE 3 +#define TASK_STOPPED 4 + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +extern int copy_page_tables(unsigned long from, unsigned long to, long size); +extern int free_page_tables(unsigned long from, unsigned long size); + +extern void sched_init(void); +extern void schedule(void); +extern void trap_init(void); +extern void panic(const char * str); +extern int tty_write(unsigned minor,char * buf,int count); + +typedef int (*fn_ptr)(); + +struct i387_struct { + long cwd; + long swd; + long twd; + long fip; + long fcs; + long foo; + long fos; + long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ +}; + +struct tss_struct { + long back_link; /* 16 high bits zero */ + long esp0; + long ss0; /* 16 high bits zero */ + long esp1; + long ss1; /* 16 high bits zero */ + long esp2; + long ss2; /* 16 high bits zero */ + long cr3; + long eip; + long eflags; + long eax,ecx,edx,ebx; + long esp; + long ebp; + long esi; + long edi; + long es; /* 16 high bits zero */ + long cs; /* 16 high bits zero */ + long ss; /* 16 high bits zero */ + long ds; /* 16 high bits zero */ + long fs; /* 16 high bits zero */ + long gs; /* 16 high bits zero */ + long ldt; /* 16 high bits zero */ + long trace_bitmap; /* bits: trace 0, bitmap 16-31 */ + struct i387_struct i387; +}; + +struct task_struct { +/* these are hardcoded - don't touch */ + long state; /* -1 unrunnable, 0 runnable, >0 stopped */ + long counter; + long priority; + long signal; + struct sigaction sigaction[32]; + long blocked; /* bitmap of masked signals */ +/* various fields */ + int exit_code; + unsigned long start_code,end_code,end_data,brk,start_stack; + long pid,pgrp,session,leader; + int groups[NGROUPS]; + /* + * pointers to parent process, youngest child, younger sibling, + * older sibling, respectively. (p->father can be replaced with + * p->p_pptr->pid) + */ + struct task_struct *p_pptr, *p_cptr, *p_ysptr, *p_osptr; + unsigned short uid,euid,suid; + unsigned short gid,egid,sgid; + unsigned long timeout,alarm; + long utime,stime,cutime,cstime,start_time; + struct rlimit rlim[RLIM_NLIMITS]; + unsigned int flags; /* per process flags, defined below */ + unsigned short used_math; +/* file system info */ + int link_count; + int tty; /* -1 if no tty, so it must be signed */ + unsigned short umask; + struct inode * pwd; + struct inode * root; + struct inode * executable; + struct inode * library; + 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; +}; + +/* + * Per process flags + */ +#define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */ + /* Not implemented yet, only for 486*/ +#define PF_PTRACED 0x00000010 /* set if ptrace (0) has been called. */ +#define PF_VM86 0x00000020 /* set if process can execute a vm86 */ + /* task. */ + /* not impelmented. */ + +/* + * INIT_TASK is used to set up the first task table, touch at + * your own risk!. Base=0, limit=0x9ffff (=640kB) + */ +#define INIT_TASK \ +/* state etc */ { 0,15,15, \ +/* signals */ 0,{{},},0, \ +/* ec,brk... */ 0,0,0,0,0,0, \ +/* pid etc.. */ 0,0,0,0, \ +/* suppl grps*/ {NOGROUP,}, \ +/* proc links*/ &init_task.task,0,0,0, \ +/* uid etc */ 0,0,0,0,0,0, \ +/* timeout */ 0,0,0,0,0,0,0, \ +/* rlimits */ { {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \ + {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \ + {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}}, \ +/* flags */ 0, \ +/* math */ 0, \ +/* fs info */ 0,-1,0022,NULL,NULL,NULL,NULL,0, \ +/* filp */ {NULL,}, \ + { \ + {0,0}, \ +/* ldt */ {0x9f,0xc0fa00}, \ + {0x9f,0xc0f200}, \ + }, \ +/*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\ + 0,0,0,0,0,0,0,0, \ + 0,0,0x17,0x17,0x17,0x17,0x17,0x17, \ + _LDT(0),0x80000000, \ + {} \ + }, \ +} + +extern struct task_struct *task[NR_TASKS]; +extern struct task_struct *last_task_used_math; +extern struct task_struct *current; +extern unsigned long volatile jiffies; +extern unsigned long startup_time; +extern int jiffies_offset; + +#define CURRENT_TIME (startup_time+(jiffies+jiffies_offset)/HZ) + +extern void add_timer(long jiffies, void (*fn)(void)); +extern void sleep_on(struct task_struct ** p); +extern void interruptible_sleep_on(struct task_struct ** p); +extern void wake_up(struct task_struct ** p); +extern int in_group_p(gid_t grp); + +/* + * 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) \ + :"0" (0),"i" (FIRST_TSS_ENTRY<<3)) +/* + * switch_to(n) should switch tasks to task nr n, first + * checking that n isn't the current task, in which case it does nothing. + * This also clears the TS-flag if the task we switched to has used + * tha math co-processor latest. + */ +#define switch_to(n) {\ +struct {long a,b;} __tmp; \ +__asm__("cmpl %%ecx,_current\n\t" \ + "je 1f\n\t" \ + "movw %%dx,%1\n\t" \ + "xchgl %%ecx,_current\n\t" \ + "ljmp %0\n\t" \ + "cmpl %%ecx,_last_task_used_math\n\t" \ + "jne 1f\n\t" \ + "clts\n" \ + "1:" \ + ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ + "d" (_TSS(n)),"c" ((long) task[n]) \ + :"cx"); \ +} + +#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 ) + +static unsigned long inline _get_base(char * addr) +{ + unsigned long __base; + __asm__("movb %3,%%dh\n\t" + "movb %2,%%dl\n\t" + "shll $16,%%edx\n\t" + "movw %1,%%dx" + :"=&d" (__base) + :"m" (*((addr)+2)), + "m" (*((addr)+4)), + "m" (*((addr)+7))); + return __base; +} + +#define get_base(ldt) _get_base( ((char *)&(ldt)) ) + +static unsigned long inline get_limit(unsigned long segment) +{ + unsigned long __limit; + __asm__("lsll %1,%0" + :"=r" (__limit):"r" (segment)); + return __limit+1; +} + +#endif diff --git a/kernel/0.95/linux-0.95/include/linux/sys.h b/kernel/0.95/linux-0.95/include/linux/sys.h new file mode 100644 index 00000000..1e6f2c3d --- /dev/null +++ b/kernel/0.95/linux-0.95/include/linux/sys.h @@ -0,0 +1,113 @@ +/* + * Why isn't this a .c file? Enquiring minds.... + */ + +extern int sys_setup(); +extern int sys_exit(); +extern int sys_fork(); +extern int sys_read(); +extern int sys_write(); +extern int sys_open(); +extern int sys_close(); +extern int sys_waitpid(); +extern int sys_creat(); +extern int sys_link(); +extern int sys_unlink(); +extern int sys_execve(); +extern int sys_chdir(); +extern int sys_time(); +extern int sys_mknod(); +extern int sys_chmod(); +extern int sys_chown(); +extern int sys_break(); +extern int sys_stat(); +extern int sys_lseek(); +extern int sys_getpid(); +extern int sys_mount(); +extern int sys_umount(); +extern int sys_setuid(); +extern int sys_getuid(); +extern int sys_stime(); +extern int sys_ptrace(); +extern int sys_alarm(); +extern int sys_fstat(); +extern int sys_pause(); +extern int sys_utime(); +extern int sys_stty(); +extern int sys_gtty(); +extern int sys_access(); +extern int sys_nice(); +extern int sys_ftime(); +extern int sys_sync(); +extern int sys_kill(); +extern int sys_rename(); +extern int sys_mkdir(); +extern int sys_rmdir(); +extern int sys_dup(); +extern int sys_pipe(); +extern int sys_times(); +extern int sys_prof(); +extern int sys_brk(); +extern int sys_setgid(); +extern int sys_getgid(); +extern int sys_signal(); +extern int sys_geteuid(); +extern int sys_getegid(); +extern int sys_acct(); +extern int sys_phys(); +extern int sys_lock(); +extern int sys_ioctl(); +extern int sys_fcntl(); +extern int sys_mpx(); +extern int sys_setpgid(); +extern int sys_ulimit(); +extern int sys_uname(); +extern int sys_umask(); +extern int sys_chroot(); +extern int sys_ustat(); +extern int sys_dup2(); +extern int sys_getppid(); +extern int sys_getpgrp(); +extern int sys_setsid(); +extern int sys_sigaction(); +extern int sys_sgetmask(); +extern int sys_ssetmask(); +extern int sys_setreuid(); +extern int sys_setregid(); +extern int sys_sigpending(); +extern int sys_sigsuspend(); +extern int sys_sethostname(); +extern int sys_setrlimit(); +extern int sys_getrlimit(); +extern int sys_getrusage(); +extern int sys_gettimeofday(); +extern int sys_settimeofday(); +extern int sys_getgroups(); +extern int sys_setgroups(); +extern int sys_select(); +extern int sys_symlink(); +extern int sys_lstat(); +extern int sys_readlink(); +extern int sys_uselib(); +extern int sys_swapon(); +extern int sys_reboot(); + +fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read, +sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link, +sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod, +sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount, +sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm, +sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access, +sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir, +sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid, +sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys, +sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit, +sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid, +sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask, +sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_sethostname, +sys_setrlimit, sys_getrlimit, sys_getrusage, sys_gettimeofday, +sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink, +sys_lstat, sys_readlink, sys_uselib, sys_swapon, sys_reboot }; + +/* So we don't have to do any more manual updating.... */ +int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); diff --git a/kernel/0.95/linux-0.95/include/linux/timer.h b/kernel/0.95/linux-0.95/include/linux/timer.h new file mode 100644 index 00000000..295738e6 --- /dev/null +++ b/kernel/0.95/linux-0.95/include/linux/timer.h @@ -0,0 +1,44 @@ +#ifndef _TIMER_H +#define _TIMER_H + +/* + * DON'T CHANGE THESE!! Most of them are hardcoded into some assembly language + * as well as being defined here. + */ + +/* + * The timers are: + * + * BLANK_TIMER console screen-saver timer + * + * BEEP_TIMER console beep timer + * + * SERx_TIMER serial incoming characters timer + * + * SERx_TIMEOUT timeout for serial writes + * + * HD_TIMER harddisk timer + * + * FLOPPY_TIMER floppy disk timer (not used right now) + */ + +#define BLANK_TIMER 0 +#define BEEP_TIMER 1 +#define SER1_TIMER 2 +#define SER2_TIMER 3 + +#define SER1_TIMEOUT 8 +#define SER2_TIMEOUT 9 + +#define HD_TIMER 16 +#define FLOPPY_TIMER 17 + +struct timer_struct { + unsigned long expires; + void (*fn)(void); +}; + +extern unsigned long timer_active; +extern struct timer_struct timer_table[32]; + +#endif diff --git a/kernel/0.95/linux-0.95/include/linux/tty.h b/kernel/0.95/linux-0.95/include/linux/tty.h new file mode 100644 index 00000000..4812f85a --- /dev/null +++ b/kernel/0.95/linux-0.95/include/linux/tty.h @@ -0,0 +1,103 @@ +/* + * '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 + +#define MAX_CONSOLES 8 +#define NR_SERIALS 2 +#define NR_PTYS 4 + +extern int NR_CONSOLES; + +#include + +#define TTY_BUF_SIZE 1024 + +struct tty_queue { + unsigned long data; + unsigned long head; + unsigned long tail; + struct task_struct * proc_list; + char buf[TTY_BUF_SIZE]; +}; + +#define IS_A_CONSOLE(min) (((min) & 0xC0) == 0x00) +#define IS_A_SERIAL(min) (((min) & 0xC0) == 0x40) +#define IS_A_PTY(min) ((min) & 0x80) +#define IS_A_PTY_MASTER(min) (((min) & 0xC0) == 0x80) +#define IS_A_PTY_SLAVE(min) (((min) & 0xC0) == 0xC0) +#define PTY_OTHER(min) ((min) ^ 0x40) + +#define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1)) +#define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1)) +#define EMPTY(a) ((a)->head == (a)->tail) +#define LEFT(a) (((a)->tail-(a)->head-1)&(TTY_BUF_SIZE-1)) +#define LAST(a) ((a)->buf[(TTY_BUF_SIZE-1)&((a)->head-1)]) +#define FULL(a) (!LEFT(a)) +#define CHARS(a) (((a)->head-(a)->tail)&(TTY_BUF_SIZE-1)) +#define GETCH(queue,c) \ +(void)({c=(queue)->buf[(queue)->tail];INC((queue)->tail);}) +#define PUTCH(c,queue) \ +(void)({(queue)->buf[(queue)->head]=(c);INC((queue)->head);}) + +#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR]) +#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT]) +#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE]) +#define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL]) +#define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF]) +#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART]) +#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP]) +#define SUSPEND_CHAR(tty) ((tty)->termios.c_cc[VSUSP]) + +struct tty_struct { + struct termios termios; + int pgrp; + int session; + int stopped; + struct winsize winsize; + 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[]; +extern int fg_console; +extern unsigned long video_num_columns; +extern unsigned long video_num_lines; + + +#define TTY_TABLE(nr) \ +(tty_table + ((nr) ? (((nr) < 64)? (nr)-1:(nr)) : fg_console)) + +/* intr=^C quit=^| erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" + +void rs_init(void); +void con_init(void); +void tty_init(void); + +int tty_read(unsigned c, char * buf, int n, unsigned short flags); +int tty_write(unsigned c, char * buf, int n); + +void con_write(struct tty_struct * tty); +void rs_write(struct tty_struct * tty); +void mpty_write(struct tty_struct * tty); +void spty_write(struct tty_struct * tty); + +void copy_to_cooked(struct tty_struct * tty); + +void update_screen(int new_console); + +#endif diff --git a/kernel/0.95/linux-0.95/include/signal.h b/kernel/0.95/linux-0.95/include/signal.h new file mode 100644 index 00000000..e4126d33 --- /dev/null +++ b/kernel/0.95/linux-0.95/include/signal.h @@ -0,0 +1,95 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include + +typedef int sig_atomic_t; +typedef unsigned int sigset_t; /* 32 bits */ + +#define _NSIG 32 +#define NSIG _NSIG + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGUNUSED 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 + +/* + * Most of these aren't used yet (and perhaps never will), + * so they are commented out. + */ + +/* +#define SIGIO 23 +#define SIGPOLL SIGIO +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +*/ + +#define SIGWINCH 28 + +/* +#define SIGLOST 29 +*/ + +/* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */ +#define SA_NOCLDSTOP 1 +#define SA_INTERRUPT 0x20000000 +#define SA_NOMASK 0x40000000 +#define SA_ONESHOT 0x80000000 + +#define SIG_BLOCK 0 /* for blocking signals */ +#define SIG_UNBLOCK 1 /* for unblocking signals */ +#define SIG_SETMASK 2 /* for setting the signal mask */ + +#define SIG_DFL ((void (*)(int))0) /* default signal handling */ +#define SIG_IGN ((void (*)(int))1) /* ignore signal */ +#define SIG_ERR ((void (*)(int))-1) /* error return from signal */ + +#ifdef notdef +#define sigemptyset(mask) ((*(mask) = 0), 1) +#define sigfillset(mask) ((*(mask) = ~0), 1) +#endif + +struct sigaction { + void (*sa_handler)(int); + sigset_t sa_mask; + int sa_flags; + void (*sa_restorer)(void); +}; + +void (*signal(int _sig, void (*_func)(int)))(int); +int raise(int sig); +int kill(pid_t pid, int sig); +int sigaddset(sigset_t *mask, int signo); +int sigdelset(sigset_t *mask, int signo); +int sigemptyset(sigset_t *mask); +int sigfillset(sigset_t *mask); +int sigismember(sigset_t *mask, int signo); /* 1 - is, 0 - not, -1 error */ +int sigpending(sigset_t *set); +int sigprocmask(int how, sigset_t *set, sigset_t *oldset); +int sigsuspend(sigset_t *sigmask); +int sigaction(int sig, struct sigaction *act, struct sigaction *oldact); + +#endif /* _SIGNAL_H */ diff --git a/kernel/0.95/linux-0.95/include/stdarg.h b/kernel/0.95/linux-0.95/include/stdarg.h new file mode 100755 index 00000000..fd79ec09 --- /dev/null +++ b/kernel/0.95/linux-0.95/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/kernel/0.95/linux-0.95/include/stddef.h b/kernel/0.95/linux-0.95/include/stddef.h new file mode 100644 index 00000000..697c4f4a --- /dev/null +++ b/kernel/0.95/linux-0.95/include/stddef.h @@ -0,0 +1,18 @@ +#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/kernel/0.95/linux-0.95/include/string.h b/kernel/0.95/linux-0.95/include/string.h new file mode 100644 index 00000000..7da1793d --- /dev/null +++ b/kernel/0.95/linux-0.95/include/string.h @@ -0,0 +1,411 @@ +#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,size_t 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,size_t 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,size_t 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 size_t 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 size_t 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 size_t 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:" +#if __GNUC__ == 2 + :"=r" (__res) +#else + :"=b" (__res) +#endif + ,"=S" (___strtok) + :"0" (___strtok),"1" (s),"g" (ct) + :"ax","cx","dx","di"); +return __res; +} + +extern inline void * memcpy(void * dest,const void * src, size_t 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, size_t n) +{ +if (dest + +struct stat { + dev_t st_dev; + ino_t st_ino; + umode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +}; + +#define S_IFMT 00170000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +extern int chmod(const char *_path, mode_t mode); +extern int fstat(int fildes, struct stat *stat_buf); +extern int mkdir(const char *_path, mode_t mode); +extern int mkfifo(const char *_path, mode_t mode); +extern int stat(const char *filename, struct stat *stat_buf); +extern mode_t umask(mode_t mask); + +#endif diff --git a/kernel/0.95/linux-0.95/include/sys/time.h b/kernel/0.95/linux-0.95/include/sys/time.h new file mode 100644 index 00000000..1165c263 --- /dev/null +++ b/kernel/0.95/linux-0.95/include/sys/time.h @@ -0,0 +1,64 @@ +#ifndef _SYS_TIME_H +#define _SYS_TIME_H + +/* gettimofday returns this */ +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* microseconds */ +}; + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +#define DST_NONE 0 /* not on dst */ +#define DST_USA 1 /* USA style dst */ +#define DST_AUST 2 /* Australian style dst */ +#define DST_WET 3 /* Western European dst */ +#define DST_MET 4 /* Middle European dst */ +#define DST_EET 5 /* Eastern European dst */ +#define DST_CAN 6 /* Canada */ +#define DST_GB 7 /* Great Britain and Eire */ +#define DST_RUM 8 /* Rumania */ +#define DST_TUR 9 /* Turkey */ +#define DST_AUSTALT 10 /* Australian style with shift in 1986 */ + +#define FD_SETSIZE (8*sizeof(fd_set)) +#define FD_SET(fd,fdsetp) (*(fdsetp) |= (1 << (fd))) +#define FD_CLR(fd,fdsetp) (*(fdsetp) &= ~(1 << (fd))) +#define FD_ISSET(fd,fdsetp) ((*(fdsetp) >> fd) & 1) +#define FD_ZERO(fdsetp) (*(fdsetp) = 0) + +/* + * Operations on timevals. + * + * NB: timercmp does not work for >= or <=. + */ +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#define timercmp(tvp, uvp, cmp) \ + ((tvp)->tv_sec cmp (uvp)->tv_sec || \ + (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) +#define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0) + +/* + * Names of the interval timers, and structure + * defining a timer setting. + */ +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +struct itimerval { + struct timeval it_interval; /* timer interval */ + struct timeval it_value; /* current value */ +}; + +#include +#include + +int gettimeofday(struct timeval * tp, struct timezone * tz); +int select(int width, fd_set * readfds, fd_set * writefds, + fd_set * exceptfds, struct timeval * timeout); + +#endif /*_SYS_TIME_H*/ diff --git a/kernel/0.95/linux-0.95/include/sys/times.h b/kernel/0.95/linux-0.95/include/sys/times.h new file mode 100644 index 00000000..68d5bfb2 --- /dev/null +++ b/kernel/0.95/linux-0.95/include/sys/times.h @@ -0,0 +1,15 @@ +#ifndef _TIMES_H +#define _TIMES_H + +#include + +struct tms { + time_t tms_utime; + time_t tms_stime; + time_t tms_cutime; + time_t tms_cstime; +}; + +extern time_t times(struct tms * tp); + +#endif diff --git a/kernel/0.95/linux-0.95/include/sys/types.h b/kernel/0.95/linux-0.95/include/sys/types.h new file mode 100644 index 00000000..5e220faa --- /dev/null +++ b/kernel/0.95/linux-0.95/include/sys/types.h @@ -0,0 +1,53 @@ +#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 short gid_t; +typedef unsigned short dev_t; +typedef unsigned short ino_t; +typedef unsigned short mode_t; +typedef unsigned short umode_t; +typedef unsigned short nlink_t; +typedef int daddr_t; +typedef long off_t; +typedef unsigned char u_char; +typedef unsigned short ushort; +typedef char *caddr_t; + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned long tcflag_t; + +typedef unsigned long fd_set; + +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/kernel/0.95/linux-0.95/include/sys/utsname.h b/kernel/0.95/linux-0.95/include/sys/utsname.h new file mode 100644 index 00000000..0e6aef8b --- /dev/null +++ b/kernel/0.95/linux-0.95/include/sys/utsname.h @@ -0,0 +1,17 @@ +#ifndef _SYS_UTSNAME_H +#define _SYS_UTSNAME_H + +#include +#include + +struct utsname { + char sysname[9]; + char nodename[MAXHOSTNAMELEN+1]; + char release[9]; + char version[9]; + char machine[9]; +}; + +extern int uname(struct utsname * utsbuf); + +#endif diff --git a/kernel/0.95/linux-0.95/include/sys/wait.h b/kernel/0.95/linux-0.95/include/sys/wait.h new file mode 100644 index 00000000..d6c33605 --- /dev/null +++ b/kernel/0.95/linux-0.95/include/sys/wait.h @@ -0,0 +1,24 @@ +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include + +#define _LOW(v) ( (v) & 0377) +#define _HIGH(v) ( ((v) >> 8) & 0377) + +/* options for waitpid, WUNTRACED not supported */ +#define WNOHANG 1 +#define WUNTRACED 2 + +#define WIFEXITED(s) (!((s)&0xFF)) +#define WIFSTOPPED(s) (((s)&0xFF)==0x7F) +#define WEXITSTATUS(s) (((s)>>8)&0xFF) +#define WTERMSIG(s) ((s)&0x7F) +#define WCOREDUMP(s) ((s)&0x80) +#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/kernel/0.95/linux-0.95/include/termios.h b/kernel/0.95/linux-0.95/include/termios.h new file mode 100644 index 00000000..faa6e53e --- /dev/null +++ b/kernel/0.95/linux-0.95/include/termios.h @@ -0,0 +1,227 @@ +#ifndef _TERMIOS_H +#define _TERMIOS_H + +#include + +#define TTY_BUF_SIZE 1024 + +/* 0x54 is just a magic number to make these relatively uniqe ('T') */ + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C + +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 { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0040000 +#define FF0 0000000 +#define FF1 0040000 + +/* c_cflag bit meaning */ +#define CBAUD 0000017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 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 + +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/kernel/0.95/linux-0.95/include/time.h b/kernel/0.95/linux-0.95/include/time.h new file mode 100644 index 00000000..f7e7ba19 --- /dev/null +++ b/kernel/0.95/linux-0.95/include/time.h @@ -0,0 +1,49 @@ +#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 + +#ifndef NULL +#define NULL ((void *) 0) +#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; +}; + +#define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + +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/kernel/0.95/linux-0.95/include/unistd.h b/kernel/0.95/linux-0.95/include/unistd.h new file mode 100644 index 00000000..622aa6f1 --- /dev/null +++ b/kernel/0.95/linux-0.95/include/unistd.h @@ -0,0 +1,285 @@ +#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 1 /* only root can do a chown (I think..) */ +#define _POSIX_NO_TRUNC 1 /* no pathname truncation (but see kernel) */ +#define _POSIX_VDISABLE '\0' /* character to disable things like ^C */ +#define _POSIX_JOB_CONTROL 1 +#define _POSIX_SAVED_IDS 1 /* Implemented, for whatever good it is */ + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#ifndef NULL +#define NULL ((void *)0) +#endif + +/* access */ +#define F_OK 0 +#define X_OK 1 +#define W_OK 2 +#define R_OK 4 + +/* lseek */ +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +/* _SC stands for System Configuration. We don't use them much */ +#define _SC_ARG_MAX 1 +#define _SC_CHILD_MAX 2 +#define _SC_CLOCKS_PER_SEC 3 +#define _SC_NGROUPS_MAX 4 +#define _SC_OPEN_MAX 5 +#define _SC_JOB_CONTROL 6 +#define _SC_SAVED_IDS 7 +#define _SC_VERSION 8 + +/* more (possibly) configurable things - now pathnames */ +#define _PC_LINK_MAX 1 +#define _PC_MAX_CANON 2 +#define _PC_MAX_INPUT 3 +#define _PC_NAME_MAX 4 +#define _PC_PATH_MAX 5 +#define _PC_PIPE_BUF 6 +#define _PC_NO_TRUNC 7 +#define _PC_VDISABLE 8 +#define _PC_CHOWN_RESTRICTED 9 + +#include +#include +#include +#include +#include +#include + +#ifdef __LIBRARY__ + +#define __NR_setup 0 /* used only by init, to get system going */ +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_stat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_fstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_phys 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_uname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_lstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 + +#define _syscall0(type,name) \ +type name(void) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name)); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall1(type,name,atype,a) \ +type name(atype a) \ +{ \ +long __res; \ +__asm__ volatile ("movl %2,%%ebx\n\t" \ + "int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"g" ((long)(a)):"bx"); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall2(type,name,atype,a,btype,b) \ +type name(atype a,btype b) \ +{ \ +long __res; \ +__asm__ volatile ("movl %2,%%ebx\n\t" \ + "int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"g" ((long)(a)),"c" ((long)(b)):"bx"); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall3(type,name,atype,a,btype,b,ctype,c) \ +type name(atype a,btype b,ctype c) \ +{ \ +long __res; \ +__asm__ volatile ("movl %2,%%ebx\n\t" \ + "int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"g" ((long)(a)),"c" ((long)(b)),"d" ((long)(c)):"bx"); \ +if (__res>=0) \ + return (type) __res; \ +errno=-__res; \ +return -1; \ +} + +#endif /* __LIBRARY__ */ + +extern int errno; + +int access(const char * filename, mode_t mode); +int acct(const char * filename); +int alarm(int sec); +int brk(void * end_data_segment); +void * sbrk(ptrdiff_t increment); +int chdir(const char * filename); +int chmod(const char * filename, mode_t mode); +int chown(const char * filename, uid_t owner, gid_t group); +int chroot(const char * filename); +int close(int fildes); +int creat(const char * filename, mode_t mode); +int dup(int fildes); +int execve(const char * filename, char ** argv, char ** envp); +int execv(const char * pathname, char ** argv); +int execvp(const char * file, char ** argv); +int execl(const char * pathname, char * arg0, ...); +int execlp(const char * file, char * arg0, ...); +int execle(const char * pathname, char * arg0, ...); +volatile void exit(int status); +volatile void _exit(int status); +int fcntl(int fildes, int cmd, ...); +int fork(void); +int getpid(void); +int getuid(void); +int geteuid(void); +int getgid(void); +int getegid(void); +int ioctl(int fildes, int cmd, ...); +int kill(pid_t pid, int signal); +int link(const char * filename1, const char * filename2); +int lseek(int fildes, off_t offset, int origin); +int mknod(const char * filename, mode_t mode, dev_t dev); +int mount(const char * specialfile, const char * dir, int rwflag); +int nice(int val); +int open(const char * filename, int flag, ...); +int pause(void); +int pipe(int * fildes); +int read(int fildes, char * buf, off_t count); +int setpgrp(void); +int setpgid(pid_t pid,pid_t pgid); +int setuid(uid_t uid); +int setgid(gid_t gid); +void (*signal(int sig, void (*fn)(int)))(int); +int stat(const char * filename, struct stat * stat_buf); +int fstat(int fildes, struct stat * stat_buf); +int stime(time_t * tptr); +int sync(void); +time_t time(time_t * tloc); +time_t times(struct tms * tbuf); +int ulimit(int cmd, long limit); +mode_t umask(mode_t mask); +int umount(const char * specialfile); +int uname(struct utsname * name); +int unlink(const char * filename); +int ustat(dev_t dev, struct ustat * ubuf); +int utime(const char * filename, struct utimbuf * times); +pid_t waitpid(pid_t pid,int * wait_stat,int options); +pid_t wait(int * wait_stat); +int write(int fildes, const char * buf, off_t count); +int dup2(int oldfd, int newfd); +int getppid(void); +pid_t getpgrp(void); +pid_t setsid(void); +int sethostname(char *name, int len); +int setrlimit(int resource, struct rlimit *rlp); +int getrlimit(int resource, struct rlimit *rlp); +int getrusage(int who, struct rusage *rusage); +int gettimeofday(struct timeval *tv, struct timezone *tz); +int settimeofday(struct timeval *tv, struct timezone *tz); +int getgroups(int gidsetlen, gid_t *gidset); +int setgroups(int gidsetlen, gid_t *gidset); +int select(int width, fd_set * readfds, fd_set * writefds, + fd_set * exceptfds, struct timeval * timeout); +int swapon(const char * specialfile); +#endif diff --git a/kernel/0.95/linux-0.95/include/utime.h b/kernel/0.95/linux-0.95/include/utime.h new file mode 100644 index 00000000..83f07c7b --- /dev/null +++ b/kernel/0.95/linux-0.95/include/utime.h @@ -0,0 +1,13 @@ +#ifndef _UTIME_H +#define _UTIME_H + +#include /* I know - shouldn't do this, but .. */ + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +extern int utime(const char *filename, struct utimbuf *times); + +#endif diff --git a/kernel/0.95/linux-0.95/init/main.c b/kernel/0.95/linux-0.95/init/main.c new file mode 100644 index 00000000..1739de5d --- /dev/null +++ b/kernel/0.95/linux-0.95/init/main.c @@ -0,0 +1,239 @@ +/* + * linux/init/main.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ +static inline _syscall0(int,fork) +static inline _syscall0(int,pause) +static inline _syscall1(int,setup,void *,BIOS) +static inline _syscall0(int,sync) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +static char printbuf[1024]; + +extern char *strcpy(); +extern int vsprintf(); +extern void init(void); +extern void blk_dev_init(void); +extern void chr_dev_init(void); +extern void hd_init(void); +extern void floppy_init(void); +extern void mem_init(long start, long end); +extern long rd_init(long mem_start, int length); +extern long kernel_mktime(struct tm * tm); + +static int sprintf(char * str, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i = vsprintf(str, fmt, args); + va_end(args); + return i; +} + +/* + * This is set up by the setup-routine at boot-time + */ +#define EXT_MEM_K (*(unsigned short *)0x90002) +#define CON_ROWS ((*(unsigned short *)0x9000e) & 0xff) +#define CON_COLS (((*(unsigned short *)0x9000e) & 0xff00) >> 8) +#define DRIVE_INFO (*(struct drive_info *)0x90080) +#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC) + +/* + * Yeah, yeah, it's ugly, but I cannot find how to do this correctly + * and this seems to work. I anybody has more info on the real-time + * clock I'd be interested. Most of this was trial and error, and some + * bios-listing reading. Urghh. + */ + +#define CMOS_READ(addr) ({ \ +outb_p(0x80|addr,0x70); \ +inb_p(0x71); \ +}) + +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) + +static void time_init(void) +{ + struct tm time; + + do { + time.tm_sec = CMOS_READ(0); + time.tm_min = CMOS_READ(2); + time.tm_hour = CMOS_READ(4); + time.tm_mday = CMOS_READ(7); + time.tm_mon = CMOS_READ(8); + time.tm_year = CMOS_READ(9); + } while (time.tm_sec != CMOS_READ(0)); + BCD_TO_BIN(time.tm_sec); + BCD_TO_BIN(time.tm_min); + BCD_TO_BIN(time.tm_hour); + BCD_TO_BIN(time.tm_mday); + BCD_TO_BIN(time.tm_mon); + BCD_TO_BIN(time.tm_year); + time.tm_mon--; + startup_time = kernel_mktime(&time); +} + +static long memory_end = 0; +static long buffer_memory_end = 0; +static long main_memory_start = 0; +static char term[32]; + +static char * argv_init[] = { "/bin/init", NULL }; +static char * envp_init[] = { "HOME=/", NULL, NULL }; + +static char * argv_rc[] = { "/bin/sh", NULL }; +static char * envp_rc[] = { "HOME=/", NULL ,NULL }; + +static char * argv[] = { "-/bin/sh",NULL }; +static char * envp[] = { "HOME=/usr/root", NULL, NULL }; + +struct drive_info { char dummy[32]; } drive_info; + +void start_kernel(void) +{ +/* + * Interrupts are still disabled. Do necessary setups, then + * enable them + */ + ROOT_DEV = ORIG_ROOT_DEV; + sprintf(term, "TERM=con%dx%d", CON_COLS, CON_ROWS); + envp[1] = term; + envp_rc[1] = term; + envp_init[1] = term; + drive_info = DRIVE_INFO; + memory_end = (1<<20) + (EXT_MEM_K<<10); + memory_end &= 0xfffff000; + if (memory_end > 16*1024*1024) + memory_end = 16*1024*1024; + if (memory_end >= 12*1024*1024) + buffer_memory_end = 4*1024*1024; + else if (memory_end >= 6*1024*1024) + buffer_memory_end = 2*1024*1024; + else if (memory_end >= 4*1024*1024) + buffer_memory_end = 3*512*1024; + else + buffer_memory_end = 1*1024*1024; + main_memory_start = buffer_memory_end; +#ifdef RAMDISK + main_memory_start += rd_init(main_memory_start, RAMDISK*1024); +#endif + mem_init(main_memory_start,memory_end); + trap_init(); + blk_dev_init(); + chr_dev_init(); + tty_init(); + time_init(); + sched_init(); + buffer_init(buffer_memory_end); + hd_init(); + floppy_init(); + sti(); + move_to_user_mode(); + if (!fork()) { /* we count on this going ok */ + init(); + } +/* + * NOTE!! For any other task 'pause()' would mean we have to get a + * signal to awaken, but task0 is the sole exception (see 'schedule()') + * as task 0 gets activated at every idle moment (when no other tasks + * can run). For task0 'pause()' just means we go check if some other + * task can run, and if not we return here. + */ + for(;;) + __asm__("int $0x80"::"a" (__NR_pause):"ax"); +} + +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; +} + +void init(void) +{ + int pid,i; + + setup((void *) &drive_info); + (void) open("/dev/tty1",O_RDWR,0); + (void) dup(0); + (void) dup(0); + printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS, + NR_BUFFERS*BLOCK_SIZE); + printf("Free mem: %d bytes\n\r",memory_end-main_memory_start); + + execve("/bin/init",argv_init,envp_init); + /* if this fails, fall through to original stuff */ + + if (!(pid=fork())) { + close(0); + if (open("/etc/rc",O_RDONLY,0)) + _exit(1); + execve("/bin/sh",argv_rc,envp_rc); + _exit(2); + } + if (pid>0) + while (pid != wait(&i)) + /* nothing */; + while (1) { + if ((pid=fork())<0) { + printf("Fork failed in init\r\n"); + continue; + } + if (!pid) { + close(0);close(1);close(2); + setsid(); + (void) open("/dev/tty1",O_RDWR,0); + (void) dup(0); + (void) dup(0); + _exit(execve("/bin/sh",argv,envp)); + } + while (1) + if (pid == wait(&i)) + break; + printf("\n\rchild %d died with code %04x\n\r",pid,i); + sync(); + } + _exit(0); /* NOTE! _exit, not exit() */ +} diff --git a/kernel/0.95/linux-0.95/kernel/Makefile b/kernel/0.95/linux-0.95/kernel/Makefile new file mode 100644 index 00000000..5a5444f0 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/Makefile @@ -0,0 +1,103 @@ +# +# Makefile for the linux 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). +# + +# gcc2 doesn't have these: +#GCC_OPT = -fcombine-regs + +AR =ar +AS =as +LD =ld +LDFLAGS =-s -x +CC =gcc +CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) \ + -finline-functions -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 sys_call.o traps.o asm.o fork.o \ + panic.o printk.o vsprintf.o sys.o exit.o \ + signal.o mktime.o ptrace.o + +kernel.o: $(OBJS) + $(LD) -r -o kernel.o $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make keyboard.s + for i in *.c;do rm -f `basename $$i .c`.s;done + (cd chr_drv; make clean) + (cd blk_drv; make clean) + (cd math; make clean) + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + (cd chr_drv; make dep) + (cd blk_drv; make dep) + +### Dependencies: +exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \ + ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.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/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h +mktime.s mktime.o : mktime.c ../include/time.h +panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.h +printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \ + ../include/linux/kernel.h +ptrace.s ptrace.o : ptrace.c ../include/linux/head.h ../include/linux/kernel.h \ + ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/mm.h ../include/signal.h ../include/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ + ../include/errno.h ../include/asm/segment.h ../include/asm/system.h \ + ../include/sys/ptrace.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/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ + ../include/linux/timer.h ../include/linux/sys.h ../include/linux/fdreg.h \ + ../include/asm/system.h ../include/asm/io.h ../include/asm/segment.h \ + ../include/errno.h +signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ + ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ + ../include/asm/segment.h ../include/sys/wait.h ../include/errno.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/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/linux/tty.h ../include/termios.h \ + ../include/linux/config.h ../include/asm/segment.h ../include/sys/times.h \ + ../include/sys/utsname.h ../include/string.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/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h ../include/asm/system.h ../include/asm/segment.h \ + ../include/asm/io.h ../include/errno.h +vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h diff --git a/kernel/0.95/linux-0.95/kernel/asm.s b/kernel/0.95/linux-0.95/kernel/asm.s new file mode 100644 index 00000000..299e4a95 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/asm.s @@ -0,0 +1,142 @@ +/* + * linux/kernel/asm.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * asm.s contains the low-level code for most hardware faults. + * page_exception is handled by the mm, so that isn't here. This + * file also handles (hopefully) fpu-exceptions due to TS-bit, as + * the fpu must be properly saved/resored. This hasn't been tested. + */ + +.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op +.globl _double_fault,_coprocessor_segment_overrun +.globl _invalid_TSS,_segment_not_present,_stack_segment +.globl _general_protection,_coprocessor_error,_irq13,_reserved +.globl _alignment_check +.globl _page_fault + +_divide_error: + pushl $0 # no error code + pushl $_do_divide_error +error_code: + push %fs + push %es + push %ds + pushl %eax + pushl %ebp + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + cld + movl $-1, %eax + xchgl %eax, 0x2c(%esp) # orig_eax (get the error code. ) + xorl %ebx,%ebx # zero ebx + mov %gs,%bx # get the lower order bits of gs + xchgl %ebx, 0x28(%esp) # get the address and save gs. + pushl %eax # push the error code + lea 52(%esp),%edx + pushl %edx + movl $0x10,%edx + mov %dx,%ds + mov %dx,%es + mov %dx,%fs + call *%ebx + addl $8,%esp + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + popl %eax + pop %ds + pop %es + pop %fs + pop %gs + addl $4,%esp + iret + +_debug: + pushl $0 + pushl $_do_int3 # _do_debug + jmp error_code + +_nmi: + pushl $0 + pushl $_do_nmi + jmp error_code + +_int3: + pushl $0 + pushl $_do_int3 + jmp error_code + +_overflow: + pushl $0 + pushl $_do_overflow + jmp error_code + +_bounds: + pushl $0 + pushl $_do_bounds + jmp error_code + +_invalid_op: + pushl $0 + pushl $_do_invalid_op + jmp error_code + +_coprocessor_segment_overrun: + pushl $0 + pushl $_do_coprocessor_segment_overrun + jmp error_code + +_reserved: + pushl $0 + pushl $_do_reserved + jmp error_code + +_irq13: + pushl %eax + xorb %al,%al + outb %al,$0xF0 + movb $0x20,%al + outb %al,$0x20 + jmp 1f +1: jmp 1f +1: outb %al,$0xA0 + popl %eax + jmp _coprocessor_error + +_double_fault: + pushl $_do_double_fault + jmp error_code + +_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 + +_alignment_check: + pushl $_do_alignment_check + jmp error_code + +_page_fault: + pushl $_do_page_fault + jmp error_code diff --git a/kernel/0.95/linux-0.95/kernel/blk_drv/Makefile b/kernel/0.95/linux-0.95/kernel/blk_drv/Makefile new file mode 100644 index 00000000..ee05aaab --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/blk_drv/Makefile @@ -0,0 +1,72 @@ +# +# Makefile for the kernel block device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =ar +AS =as +LD =ld +LDFLAGS =-s -x +CC =gcc +CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ + -finline-functions -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 = ll_rw_blk.o floppy.o hd.o ramdisk.o + +blk_drv.a: $(OBJS) + $(AR) rcs blk_drv.a $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/fdreg.h \ + ../../include/asm/system.h ../../include/asm/io.h \ + ../../include/asm/segment.h blk.h +hd.s hd.o : hd.c ../../include/linux/config.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/timer.h \ + ../../include/linux/hdreg.h ../../include/asm/system.h \ + ../../include/asm/io.h ../../include/asm/segment.h blk.h +ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/asm/system.h blk.h +ramdisk.s ramdisk.o : ramdisk.c ../../include/string.h ../../include/linux/config.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ + ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/minix_fs.h \ + ../../include/asm/system.h ../../include/asm/segment.h \ + ../../include/asm/memory.h blk.h diff --git a/kernel/0.95/linux-0.95/kernel/blk_drv/blk.h b/kernel/0.95/linux-0.95/kernel/blk_drv/blk.h new file mode 100644 index 00000000..28e37d57 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/blk_drv/blk.h @@ -0,0 +1,165 @@ +#ifndef _BLK_H +#define _BLK_H + +#define NR_BLK_DEV 7 +/* + * NR_REQUEST is the number of entries in the request-queue. + * NOTE that writes may use only the low 2/3 of these: reads + * take precedence. + * + * 32 seems to be a reasonable number: enough to get some benefit + * from the elevator-mechanism, but not so much as to lock a lot of + * buffers when they are in the queue. 64 seems to be too many (easily + * long pauses in reading when heavy writing/syncing is going on) + */ +#define NR_REQUEST 32 + +/* + * Ok, this is an expanded form so that we can use the same + * request for paging requests when that is implemented. In + * paging, 'bh' is NULL, and 'waiting' is used to wait for + * read/write completion. + */ +struct request { + int dev; /* -1 if no request */ + int cmd; /* READ or WRITE */ + int errors; + unsigned long sector; + unsigned long nr_sectors; + char * buffer; + struct task_struct * waiting; + struct buffer_head * bh; + struct request * next; +}; + +/* + * This is used in the elevator algorithm: Note that + * reads always go before writes. This is natural: reads + * are much more time-critical than writes. + */ +#define IN_ORDER(s1,s2) \ +((s1)->cmd<(s2)->cmd || ((s1)->cmd==(s2)->cmd && \ +((s1)->dev < (s2)->dev || (((s1)->dev == (s2)->dev && \ +(s1)->sector < (s2)->sector))))) + +struct blk_dev_struct { + void (*request_fn)(void); + struct request * current_request; +}; + +extern struct blk_dev_struct blk_dev[NR_BLK_DEV]; +extern struct request request[NR_REQUEST]; +extern struct task_struct * wait_for_request; + +extern int * blk_size[NR_BLK_DEV]; + +#ifdef MAJOR_NR + +/* + * Add entries as needed. Currently the only block devices + * supported are hard-disks and floppies. + */ + +#if (MAJOR_NR == 1) +/* ram disk */ +#define DEVICE_NAME "ramdisk" +#define DEVICE_REQUEST do_rd_request +#define DEVICE_NR(device) ((device) & 7) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == 2) +/* floppy */ +#define DEVICE_NAME "floppy" +#define DEVICE_INTR do_floppy +#define DEVICE_REQUEST do_fd_request +#define DEVICE_NR(device) ((device) & 3) +#define DEVICE_ON(device) floppy_on(DEVICE_NR(device)) +#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) + +#elif (MAJOR_NR == 3) +/* harddisk */ +#define DEVICE_NAME "harddisk" +#define DEVICE_INTR do_hd +#define DEVICE_TIMEOUT HD_TIMER +#define DEVICE_REQUEST do_hd_request +#define DEVICE_NR(device) (MINOR(device)>>6) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif +/* unknown blk device */ +#error "unknown blk device" + +#endif + +#define CURRENT (blk_dev[MAJOR_NR].current_request) +#define CURRENT_DEV DEVICE_NR(CURRENT->dev) + +#ifdef DEVICE_INTR +void (*DEVICE_INTR)(void) = NULL; +#endif +#ifdef DEVICE_TIMEOUT +#define SET_INTR(x) (DEVICE_INTR = (x), \ + timer_table[DEVICE_TIMEOUT].expires = jiffies + 200, \ + timer_active |= 1<b_lock) + printk(DEVICE_NAME ": free buffer being unlocked\n"); + bh->b_lock=0; + wake_up(&bh->b_wait); +} + +extern inline void end_request(int uptodate) +{ + DEVICE_OFF(CURRENT->dev); + if (CURRENT->bh) { + CURRENT->bh->b_uptodate = uptodate; + unlock_buffer(CURRENT->bh); + } + if (!uptodate) { + printk(DEVICE_NAME " I/O error\n\r"); + printk("dev %04x, block %d\n\r",CURRENT->dev, + CURRENT->bh->b_blocknr); + } + wake_up(&CURRENT->waiting); + wake_up(&wait_for_request); + CURRENT->dev = -1; + CURRENT = CURRENT->next; +} + +#ifdef DEVICE_TIMEOUT +#define CLEAR_DEVICE_TIMEOUT timer_active &= ~(1<dev) != MAJOR_NR) \ + panic(DEVICE_NAME ": request list destroyed"); \ + if (CURRENT->bh) { \ + if (!CURRENT->bh->b_lock) \ + panic(DEVICE_NAME ": block not locked"); \ + } + +#endif + +#endif diff --git a/kernel/0.95/linux-0.95/kernel/blk_drv/floppy.c b/kernel/0.95/linux-0.95/kernel/blk_drv/floppy.c new file mode 100644 index 00000000..92881e5b --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/blk_drv/floppy.c @@ -0,0 +1,530 @@ +/* + * linux/kernel/floppy.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 02.12.91 - Changed to static variables to indicate need for reset + * and recalibrate. This makes some things easier (output_byte reset + * checking etc), and means less interrupt jumping in case of errors, + * so the code is hopefully easier to understand. + */ + +/* + * This file is certainly a mess. I've tried my best to get it working, + * but I don't like programming floppies, and I have only one anyway. + * Urgel. I should check for more errors, and do more graceful error + * recovery. Seems there are problems with several drives. I've tried to + * correct them. No promises. + */ + +/* + * As with hd.c, all routines within this file can (and will) be called + * by interrupts, so extreme caution is needed. A hardware interrupt + * handler may not sleep, or a kernel panic will happen. Thus I cannot + * call "floppy-on" directly, but have to set a special timer interrupt + * etc. + */ + +/* + * 28.02.92 - made track-buffering routines, based on the routines written + * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 2 +#include "blk.h" + +static int recalibrate = 0; +static int reset = 0; +static int seek = 0; + +extern unsigned char current_DOR; + +#define immoutb_p(val,port) \ +__asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port)) + +#define TYPE(x) ((x)>>2) +#define DRIVE(x) ((x)&0x03) +/* + * Note that MAX_ERRORS=X doesn't imply that we retry every bad read + * max X times - some types of errors increase the errorcount by 2, + * so we might actually retry only X/2 times before giving up. + */ +#define MAX_ERRORS 12 + +/* + * globals used by 'result()' + */ +#define MAX_REPLIES 7 +static unsigned char reply_buffer[MAX_REPLIES]; +#define ST0 (reply_buffer[0]) +#define ST1 (reply_buffer[1]) +#define ST2 (reply_buffer[2]) +#define ST3 (reply_buffer[3]) + +/* + * This struct defines the different floppy types. Unlike minix + * linux doesn't have a "search for right type"-type, as the code + * for that is convoluted and weird. I've got enough problems with + * this driver as it is. + * + * The 'stretch' tells if the tracks need to be boubled for some + * types (ie 360kB diskette in 1.2MB drive etc). Others should + * be self-explanatory. + */ +struct floppy_struct { + unsigned int size, sect, head, track, stretch; + unsigned char gap,rate,spec1; +}; + +static struct floppy_struct floppy_type[] = { + { 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */ + { 720, 9,2,40,0,0x2A,0x02,0xDF }, /* 360kB PC diskettes */ + { 2400,15,2,80,0,0x1B,0x00,0xDF }, /* 1.2 MB AT-diskettes */ + { 720, 9,2,40,1,0x2A,0x02,0xDF }, /* 360kB in 720kB drive */ + { 1440, 9,2,80,0,0x2A,0x02,0xDF }, /* 3.5" 720kB diskette */ + { 720, 9,2,40,1,0x23,0x01,0xDF }, /* 360kB in 1.2MB drive */ + { 1440, 9,2,80,0,0x23,0x01,0xDF }, /* 720kB in 1.2MB drive */ + { 2880,18,2,80,0,0x1B,0x00,0xCF }, /* 1.44MB diskette */ +}; + +/* + * Rate is 0 for 500kb/s, 2 for 300kbps, 1 for 250kbps + * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc), + * H is head unload time (1=16ms, 2=32ms, etc) + * + * Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms etc) + * and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA). + */ + +extern void floppy_interrupt(void); +extern char tmp_floppy_area[1024]; +extern char floppy_track_buffer[512*2*18]; + +/* + * These are global variables, as that's the easiest way to give + * information to interrupts. They are the data used for the current + * request. + */ +static int read_track = 0; /* flag to indicate if we want to read all track */ +static int buffer_track = -1; +static int buffer_drive = -1; +static int cur_spec1 = -1; +static int cur_rate = -1; +static struct floppy_struct * floppy = floppy_type; +static unsigned char current_drive = 0; +static unsigned char sector = 0; +static unsigned char head = 0; +static unsigned char track = 0; +static unsigned char seek_track = 0; +static unsigned char current_track = 255; +static unsigned char command = 0; +unsigned char selected = 0; +struct task_struct * wait_on_floppy_select = NULL; + +void floppy_deselect(unsigned int nr) +{ + if (nr != (current_DOR & 3)) + printk("floppy_deselect: drive not selected\n\r"); + selected = 0; + wake_up(&wait_on_floppy_select); +} + +/* + * floppy-change is never called from an interrupt, so we can relax a bit + * here, sleep etc. Note that floppy-on tries to set current_DOR to point + * to the desired drive, but it will probably not survive the sleep if + * several floppies are used at the same time: thus the loop. + */ +int floppy_change(unsigned int nr) +{ +repeat: + floppy_on(nr); + while ((current_DOR & 3) != nr && selected) + sleep_on(&wait_on_floppy_select); + if ((current_DOR & 3) != nr) + goto repeat; + if (inb(FD_DIR) & 0x80) { + floppy_off(nr); + buffer_track = -1; + return 1; + } + floppy_off(nr); + return 0; +} + +#define copy_buffer(from,to) \ +__asm__("cld ; rep ; movsl" \ + ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \ + :"cx","di","si") + +static void setup_DMA(void) +{ + unsigned long addr = (long) CURRENT->buffer; + unsigned long count = 1024; + + cli(); + if (read_track) { +/* mark buffer-track bad, in case all this fails.. */ + buffer_drive = buffer_track = -1; + count = floppy->sect*2*512; + addr = (long) floppy_track_buffer; + } else if (addr >= 0x100000) { + addr = (long) tmp_floppy_area; + if (command == FD_WRITE) + copy_buffer(CURRENT->buffer,tmp_floppy_area); + } +/* mask DMA 2 */ + immoutb_p(4|2,10); +/* output command byte. I don't know why, but everyone (minix, */ +/* sanches & canton) output this twice, first to 12 then to 11 */ + __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t" + "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:":: + "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE))); +/* 8 low bits of addr */ + immoutb_p(addr,4); + addr >>= 8; +/* bits 8-15 of addr */ + immoutb_p(addr,4); + addr >>= 8; +/* bits 16-19 of addr */ + immoutb_p(addr,0x81); +/* low 8 bits of count-1 */ + count--; + immoutb_p(count,5); + count >>= 8; +/* high 8 bits of count-1 */ + immoutb_p(count,5); +/* activate DMA 2 */ + immoutb_p(0|2,10); + sti(); +} + +static void output_byte(char byte) +{ + int counter; + unsigned char status; + + if (reset) + return; + for(counter = 0 ; counter < 10000 ; counter++) { + status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR); + if (status == STATUS_READY) { + outb(byte,FD_DATA); + return; + } + } + reset = 1; + printk("Unable to send byte to FDC\n\r"); +} + +static int result(void) +{ + int i = 0, counter, status; + + if (reset) + return -1; + for (counter = 0 ; counter < 10000 ; counter++) { + status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY); + if (status == STATUS_READY) + return i; + if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) { + if (i >= MAX_REPLIES) + break; + reply_buffer[i++] = inb_p(FD_DATA); + } + } + reset = 1; + printk("Getstatus times out\n\r"); + return -1; +} + +static void bad_flp_intr(void) +{ + current_track = -1; + CURRENT->errors++; + if (CURRENT->errors > MAX_ERRORS) { + floppy_deselect(current_drive); + end_request(0); + } + if (CURRENT->errors > MAX_ERRORS/2) + reset = 1; +} + +/* + * Ok, this interrupt is called after a DMA read/write has succeeded, + * so we check the results, and copy any buffers. + */ +static void rw_interrupt(void) +{ + char * buffer_area; + + if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73)) { + if (ST1 & 0x02) { + printk("Drive %d is write protected\n\r",current_drive); + floppy_deselect(current_drive); + end_request(0); + } else + bad_flp_intr(); + do_fd_request(); + return; + } + if (read_track) { + buffer_track = seek_track; + buffer_drive = current_drive; + buffer_area = floppy_track_buffer + + ((sector-1 + head*floppy->sect)<<9); + copy_buffer(buffer_area,CURRENT->buffer); + } else if (command == FD_READ && + (unsigned long)(CURRENT->buffer) >= 0x100000) + copy_buffer(tmp_floppy_area,CURRENT->buffer); + floppy_deselect(current_drive); + end_request(1); + do_fd_request(); +} + +/* + * We try to read tracks, but if we get too many errors, we + * go back to reading just one sector at a time. + * + * This means we should be able to read a sector even if there + * are other bad sectors on this track. + */ +inline void setup_rw_floppy(void) +{ + setup_DMA(); + do_floppy = rw_interrupt; + output_byte(command); + if (read_track) { + output_byte(current_drive); + output_byte(track); + output_byte(0); + output_byte(1); + } else { + output_byte(head<<2 | current_drive); + output_byte(track); + output_byte(head); + output_byte(sector); + } + output_byte(2); /* sector size = 512 */ + output_byte(floppy->sect); + output_byte(floppy->gap); + output_byte(0xFF); /* sector size (0xff when n!=0 ?) */ + if (reset) + do_fd_request(); +} + +/* + * This is the routine called after every seek (or recalibrate) interrupt + * from the floppy controller. Note that the "unexpected interrupt" routine + * also does a recalibrate, but doesn't come here. + */ +static void seek_interrupt(void) +{ +/* sense drive status */ + output_byte(FD_SENSEI); + if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) { + recalibrate = 1; + bad_flp_intr(); + do_fd_request(); + return; + } + current_track = ST1; + setup_rw_floppy(); +} + +/* + * This routine is called when everything should be correctly set up + * for the transfer (ie floppy motor is on and the correct floppy is + * selected). + */ +static void transfer(void) +{ + read_track = (command == FD_READ) && (CURRENT->errors < 4); + if (cur_spec1 != floppy->spec1) { + cur_spec1 = floppy->spec1; + output_byte(FD_SPECIFY); + output_byte(cur_spec1); /* hut etc */ + output_byte(6); /* Head load time =6ms, DMA */ + } + if (cur_rate != floppy->rate) + outb_p(cur_rate = floppy->rate,FD_DCR); + if (reset) { + do_fd_request(); + return; + } + if (!seek) { + setup_rw_floppy(); + return; + } + do_floppy = seek_interrupt; + output_byte(FD_SEEK); + if (read_track) + output_byte(current_drive); + else + output_byte((head<<2) | current_drive); + output_byte(seek_track); + if (reset) + do_fd_request(); +} + +/* + * Special case - used after a unexpected interrupt (or reset) + */ +static void recal_interrupt(void) +{ + output_byte(FD_SENSEI); + if (result()!=2 || (ST0 & 0xE0) == 0x60) + reset = 1; + else + recalibrate = 0; + do_fd_request(); +} + +void unexpected_floppy_interrupt(void) +{ + output_byte(FD_SENSEI); + if (result()!=2 || (ST0 & 0xE0) == 0x60) + reset = 1; + else + recalibrate = 1; +} + +static void recalibrate_floppy(void) +{ + recalibrate = 0; + current_track = 0; + do_floppy = recal_interrupt; + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); + if (reset) + do_fd_request(); +} + +static void reset_interrupt(void) +{ + output_byte(FD_SENSEI); + (void) result(); + output_byte(FD_SPECIFY); + output_byte(cur_spec1); /* hut etc */ + output_byte(6); /* Head load time =6ms, DMA */ + do_fd_request(); +} + +/* + * reset is done by pulling bit 2 of DOR low for a while. + */ +static void reset_floppy(void) +{ + int i; + + reset = 0; + cur_spec1 = -1; + cur_rate = -1; + recalibrate = 1; + printk("Reset-floppy called\n\r"); + cli(); + do_floppy = reset_interrupt; + outb_p(current_DOR & ~0x04,FD_DOR); + for (i=0 ; i<100 ; i++) + __asm__("nop"); + outb(current_DOR,FD_DOR); + sti(); +} + +static void floppy_on_interrupt(void) +{ +/* We cannot do a floppy-select, as that might sleep. We just force it */ + selected = 1; + if (current_drive != (current_DOR & 3)) { + current_DOR &= 0xFC; + current_DOR |= current_drive; + outb(current_DOR,FD_DOR); + add_timer(2,&transfer); + } else + transfer(); +} + +void do_fd_request(void) +{ + unsigned int block; + char * buffer_area; + + seek = 0; + if (reset) { + reset_floppy(); + return; + } + if (recalibrate) { + recalibrate_floppy(); + return; + } + INIT_REQUEST; + floppy = (MINOR(CURRENT->dev)>>2) + floppy_type; + if (current_drive != CURRENT_DEV) + seek = 1; + current_drive = CURRENT_DEV; + block = CURRENT->sector; + if (block+2 > floppy->size) { + end_request(0); + goto repeat; + } + sector = block % floppy->sect; + block /= floppy->sect; + head = block % floppy->head; + track = block / floppy->head; + seek_track = track << floppy->stretch; + if (CURRENT->cmd == READ) + command = FD_READ; + else if (CURRENT->cmd == WRITE) + command = FD_WRITE; + else { + printk("do_fd_request: unknown command\n"); + end_request(0); + goto repeat; + } + if ((seek_track == buffer_track) && + (current_drive == buffer_drive)) { + buffer_area = floppy_track_buffer + + ((sector + head*floppy->sect)<<9); + if (command == FD_READ) { + copy_buffer(buffer_area,CURRENT->buffer); + end_request(1); + goto repeat; + } else + copy_buffer(CURRENT->buffer,buffer_area); + } + if (seek_track != current_track) + seek = 1; + sector++; + add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt); +} + +static int floppy_sizes[] ={ + 0, 0, 0, 0, + 360, 360 ,360, 360, + 1200,1200,1200,1200, + 360, 360, 360, 360, + 720, 720, 720, 720, + 360, 360, 360, 360, + 720, 720, 720, 720, + 1440,1440,1440,1440 +}; + +void floppy_init(void) +{ + outb(current_DOR,FD_DOR); + blk_size[MAJOR_NR] = floppy_sizes; + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + set_intr_gate(0x26,&floppy_interrupt); + outb(inb_p(0x21)&~0x40,0x21); +} diff --git a/kernel/0.95/linux-0.95/kernel/blk_drv/hd.c b/kernel/0.95/linux-0.95/kernel/blk_drv/hd.c new file mode 100644 index 00000000..b75b1765 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/blk_drv/hd.c @@ -0,0 +1,411 @@ +/* + * linux/kernel/hd.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This is the low-level hd interrupt support. It traverses the + * request-list, using interrupts to jump between functions. As + * all the functions are called within interrupts, we may not + * sleep. Special care is recommended. + * + * modified by Drew Eckhardt to check nr of hd's from the CMOS. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 3 +#include "blk.h" + +#define CMOS_READ(addr) ({ \ +outb_p(0x80|addr,0x70); \ +inb_p(0x71); \ +}) + +/* Max read/write errors/sector */ +#define MAX_ERRORS 7 +#define MAX_HD 2 + +static void recal_intr(void); +static void bad_rw_intr(void); + +static int recalibrate = 0; +static int reset = 0; + +/* + * This struct defines the HD's and their types. + */ +struct hd_i_struct { + unsigned int head,sect,cyl,wpcom,lzone,ctl; + }; +#ifdef HD_TYPE +struct hd_i_struct hd_info[] = { HD_TYPE }; +#define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct))) +#else +struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} }; +static int NR_HD = 0; +#endif + +static struct hd_struct { + long start_sect; + long nr_sects; +} hd[MAX_HD<<6]={{0,0},}; + +static int hd_sizes[MAX_HD<<6] = {0, }; + +#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); +extern void rd_load(void); + +static unsigned int current_minor; + +static void check_partition(unsigned int dev) +{ + int minor, i; + struct buffer_head *bh; + struct partition *p; + + if (!(bh = bread(dev,0))) { + printk("Unable to read partition table of device %04x\n",dev); + return; + } + minor = current_minor; + if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { + p = 0x1BE + (void *)bh->b_data; + for (i=0 ; i<4 ; i++,p++) { + hd[i+minor].start_sect = p->start_sect; + hd[i+minor].nr_sects = p->nr_sects; + } + if (p->nr_sects && p->sys_ind == EXTENDED_PARTITION) { + current_minor += 4; + check_partition(i+minor); + } + } else + printk("Bad partition table on dev %04x\n",dev); + brelse(bh); +} + +/* This may be used only once, enforced by 'static int callable' */ +int sys_setup(void * BIOS) +{ + static int callable = 1; + int i,drive; + unsigned char cmos_disks; + + if (!callable) + return -1; + callable = 0; +#ifndef HD_TYPE + for (drive=0 ; drive<2 ; drive++) { + hd_info[drive].cyl = *(unsigned short *) BIOS; + hd_info[drive].head = *(unsigned char *) (2+BIOS); + hd_info[drive].wpcom = *(unsigned short *) (5+BIOS); + hd_info[drive].ctl = *(unsigned char *) (8+BIOS); + hd_info[drive].lzone = *(unsigned short *) (12+BIOS); + hd_info[drive].sect = *(unsigned char *) (14+BIOS); + BIOS += 16; + } + if (hd_info[1].cyl) + NR_HD=2; + else + NR_HD=1; +#endif + for (i=0 ; i are the primary drives in the system, and + the ones reflected as drive 1 or 2. + + The first drive is stored in the high nibble of CMOS + byte 0x12, the second in the low nibble. This will be + either a 4 bit drive type or 0xf indicating use byte 0x19 + for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. + + Needless to say, a non-zero value means we have + an AT controller hard disk for that drive. + + + */ + + if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) + if (cmos_disks & 0x0f) + NR_HD = 2; + else + NR_HD = 1; + else + NR_HD = 0; + for (i = NR_HD ; i < 2 ; i++) { + hd[i<<6].start_sect = 0; + hd[i<<6].nr_sects = 0; + } + for (drive=0 ; drive>1 ; + blk_size[MAJOR_NR] = hd_sizes; + if (NR_HD) + printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":""); + rd_load(); + mount_root(); + return (0); +} + +static int controller_ready(void) +{ + int retries = 100000; + + while (--retries && (inb_p(HD_STATUS)&0x80)) + /* nothing */; + if (!retries) + printk("controller_ready: status = %02x\n\r", + (unsigned char) inb_p(HD_STATUS)); + return (retries); +} + +static int win_result(void) +{ + int i=inb_p(HD_STATUS); + + if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)) + == (READY_STAT | SEEK_STAT)) + return(0); /* ok */ + if (i&1) i=inb(HD_ERROR); + return (1); +} + +static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect, + unsigned int head,unsigned int cyl,unsigned int cmd, + void (*intr_addr)(void)) +{ + unsigned short port; + + if (drive>1 || head>15) + panic("Trying to write bad sector"); + if (reset || !controller_ready()) { + reset = 1; + return; + } + SET_INTR(intr_addr); + outb_p(hd_info[drive].ctl,HD_CMD); + port=HD_DATA; + outb_p(hd_info[drive].wpcom>>2,++port); + outb_p(nsect,++port); + outb_p(sect,++port); + outb_p(cyl,++port); + outb_p(cyl>>8,++port); + outb_p(0xA0|(drive<<4)|head,++port); + outb(cmd,++port); +} + +static int drive_busy(void) +{ + unsigned int i; + unsigned char c; + + for (i = 0; i < 50000; i++) { + c = inb_p(HD_STATUS); + c &= (BUSY_STAT | READY_STAT | SEEK_STAT); + if (c == (READY_STAT | SEEK_STAT)) + return 0; + } + printk("HD controller times out, c=%02x\n\r",c); + return(1); +} + +static void reset_controller(void) +{ + int i; + + outb(4,HD_CMD); + for(i = 0; i < 1000; i++) nop(); + outb(hd_info[0].ctl & 0x0f ,HD_CMD); + if (drive_busy()) + printk("HD-controller still busy\n\r"); + if ((i = inb(HD_ERROR)) != 1) + printk("HD-controller reset failed: %02x\n\r",i); +} + +static void reset_hd(void) +{ + static int i; + +repeat: + if (reset) { + reset = 0; + i = -1; + reset_controller(); + } else if (win_result()) { + bad_rw_intr(); + if (reset) + goto repeat; + } + i++; + if (i < NR_HD) { + hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1, + hd_info[i].cyl,WIN_SPECIFY,&reset_hd); + if (reset) + goto repeat; + } else + do_hd_request(); +} + +void unexpected_hd_interrupt(void) +{ + printk("Unexpected HD interrupt\n\r"); + reset = 1; + do_hd_request(); +} + +static void bad_rw_intr(void) +{ + if (++CURRENT->errors >= MAX_ERRORS) + end_request(0); + if (CURRENT->errors > MAX_ERRORS/2) + reset = 1; +} + +static void read_intr(void) +{ + if (win_result()) { + bad_rw_intr(); + do_hd_request(); + return; + } + port_read(HD_DATA,CURRENT->buffer,256); + CURRENT->errors = 0; + CURRENT->buffer += 512; + CURRENT->sector++; + if (--CURRENT->nr_sectors) { + SET_INTR(&read_intr); + return; + } + end_request(1); + do_hd_request(); +} + +static void write_intr(void) +{ + if (win_result()) { + bad_rw_intr(); + do_hd_request(); + return; + } + if (--CURRENT->nr_sectors) { + CURRENT->sector++; + CURRENT->buffer += 512; + SET_INTR(&write_intr); + port_write(HD_DATA,CURRENT->buffer,256); + return; + } + end_request(1); + do_hd_request(); +} + +static void recal_intr(void) +{ + if (win_result()) + bad_rw_intr(); + do_hd_request(); +} + +static void hd_times_out(void) +{ + if (!CURRENT) + return; + printk("HD timeout"); + if (++CURRENT->errors >= MAX_ERRORS) + end_request(0); + SET_INTR(NULL); + reset = 1; + do_hd_request(); +} + +void do_hd_request(void) +{ + int i,r; + unsigned int block,dev; + unsigned int sec,head,cyl; + unsigned int nsect; + + INIT_REQUEST; + dev = MINOR(CURRENT->dev); + block = CURRENT->sector; + if (dev >= (NR_HD<<6) || block+2 > hd[dev].nr_sects) { + end_request(0); + goto repeat; + } + block += hd[dev].start_sect; + dev >>= 6; + sec = block % hd_info[dev].sect; + block /= hd_info[dev].sect; + head = block % hd_info[dev].head; + cyl = block / hd_info[dev].head; + sec++; + nsect = CURRENT->nr_sectors; + if (reset) { + recalibrate = 1; + reset_hd(); + return; + } + if (recalibrate) { + recalibrate = 0; + hd_out(dev,hd_info[CURRENT_DEV].sect,0,0,0, + WIN_RESTORE,&recal_intr); + if (reset) + goto repeat; + return; + } + if (CURRENT->cmd == WRITE) { + hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr); + if (reset) + goto repeat; + for(i=0 ; i<10000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++) + /* nothing */ ; + if (!r) { + bad_rw_intr(); + goto repeat; + } + port_write(HD_DATA,CURRENT->buffer,256); + } else if (CURRENT->cmd == READ) { + hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr); + if (reset) + goto repeat; + } else + panic("unknown hd-command"); +} + +void hd_init(void) +{ + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + set_trap_gate(0x2E,&hd_interrupt); + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xbf,0xA1); + timer_table[HD_TIMER].fn = hd_times_out; +} diff --git a/kernel/0.95/linux-0.95/kernel/blk_drv/ll_rw_blk.c b/kernel/0.95/linux-0.95/kernel/blk_drv/ll_rw_blk.c new file mode 100644 index 00000000..777dcc3f --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/blk_drv/ll_rw_blk.c @@ -0,0 +1,268 @@ +/* + * linux/kernel/blk_dev/ll_rw.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This handles all read/write requests to block devices + */ +#include +#include +#include +#include + +#include "blk.h" + +/* + * The request-struct contains all necessary data + * to load a nr of sectors into memory + */ +struct request request[NR_REQUEST]; + +/* + * used to wait on when there are no free requests + */ +struct task_struct * wait_for_request = NULL; + +/* blk_dev_struct is: + * do_request-address + * next-request + */ +struct blk_dev_struct blk_dev[NR_BLK_DEV] = { + { NULL, NULL }, /* no_dev */ + { NULL, NULL }, /* dev mem */ + { NULL, NULL }, /* dev fd */ + { NULL, NULL }, /* dev hd */ + { NULL, NULL }, /* dev ttyx */ + { NULL, NULL }, /* dev tty */ + { NULL, NULL } /* dev lp */ +}; + +/* + * blk_size contains the size of all block-devices: + * + * blk_size[MAJOR][MINOR] + * + * if (!blk_size[MAJOR]) then no minor size checking is done. + */ +int * blk_size[NR_BLK_DEV] = { NULL, NULL, }; + +static inline void lock_buffer(struct buffer_head * bh) +{ + cli(); + while (bh->b_lock) + sleep_on(&bh->b_wait); + bh->b_lock=1; + sti(); +} + +static inline void unlock_buffer(struct buffer_head * bh) +{ + if (!bh->b_lock) + printk("ll_rw_block.c: buffer not locked\n\r"); + bh->b_lock = 0; + wake_up(&bh->b_wait); +} + +/* + * add-request adds a request to the linked list. + * It disables interrupts so that it can muck with the + * request-lists in peace. + * + * Note that swapping requests always go before other requests, + * and are done in the order they appear. + */ +static void add_request(struct blk_dev_struct * dev, struct request * req) +{ + struct request * tmp; + + req->next = NULL; + cli(); + if (req->bh) + req->bh->b_dirt = 0; + if (!(tmp = dev->current_request)) { + dev->current_request = req; + sti(); + (dev->request_fn)(); + return; + } + for ( ; tmp->next ; tmp = tmp->next) { + if (!req->bh) + if (tmp->next->bh) + break; + else + continue; + if ((IN_ORDER(tmp,req) || + !IN_ORDER(tmp,tmp->next)) && + IN_ORDER(req,tmp->next)) + break; + } + req->next = tmp->next; + tmp->next = req; + sti(); +} + +static void make_request(int major,int rw, struct buffer_head * bh) +{ + struct request * req; + int rw_ahead; + +/* WRITEA/READA is special case - it is not really needed, so if the */ +/* buffer is locked, we just forget about it, else it's a normal read */ + if (rw_ahead = (rw == READA || rw == WRITEA)) { + if (bh->b_lock) + return; + if (rw == READA) + rw = READ; + else + rw = WRITE; + } + if (rw!=READ && rw!=WRITE) { + printk("Bad block dev command, must be R/W/RA/WA\n"); + return; + } + lock_buffer(bh); + if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) { + unlock_buffer(bh); + return; + } +repeat: +/* we don't allow the write-requests to fill up the queue completely: + * we want some room for reads: they take precedence. The last third + * of the requests are only for reads. + */ + if (rw == READ) + req = request+NR_REQUEST; + else + req = request+((NR_REQUEST*2)/3); +/* find an empty request */ + cli(); + while (--req >= request) + if (req->dev < 0) + goto found; +/* if none found, sleep on new requests: check for rw_ahead */ + if (rw_ahead) { + sti(); + unlock_buffer(bh); + return; + } + sleep_on(&wait_for_request); + sti(); + goto repeat; + +found: sti(); +/* fill up the request-info, and add it to the queue */ + req->dev = bh->b_dev; + req->cmd = rw; + req->errors=0; + req->sector = bh->b_blocknr<<1; + req->nr_sectors = 2; + req->buffer = bh->b_data; + req->waiting = NULL; + req->bh = bh; + req->next = NULL; + add_request(major+blk_dev,req); +} + +void ll_rw_page(int rw, int dev, int page, char * buffer) +{ + struct request * req; + unsigned int major = MAJOR(dev); + + if (major >= NR_BLK_DEV || !(blk_dev[major].request_fn)) { + printk("Trying to read nonexistent block-device\n\r"); + return; + } + if (rw!=READ && rw!=WRITE) + panic("Bad block dev command, must be R/W"); + cli(); +repeat: + req = request+NR_REQUEST; + while (--req >= request) + if (req->dev<0) + break; + if (req < request) { + sleep_on(&wait_for_request); + goto repeat; + } + sti(); +/* fill up the request-info, and add it to the queue */ + req->dev = dev; + req->cmd = rw; + req->errors = 0; + req->sector = page<<3; + req->nr_sectors = 8; + req->buffer = buffer; + req->waiting = current; + req->bh = NULL; + req->next = NULL; + current->state = TASK_UNINTERRUPTIBLE; + add_request(major+blk_dev,req); + schedule(); +} + +void ll_rw_block(int rw, struct buffer_head * bh) +{ + unsigned int major; + + if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || + !(blk_dev[major].request_fn)) { + printk("ll_rw_block: Trying to read nonexistent block-device\n\r"); + return; + } + make_request(major,rw,bh); +} + +void blk_dev_init(void) +{ + int i; + + for (i=0 ; i= NR_BLK_DEV || !(blk_dev[major].request_fn)) { + printk("ll_rw_swap_file: trying to swap nonexistent block-device\n\r"); + return; + } + + if (rw!=READ && rw!=WRITE) { + printk("ll_rw_swap: bad block dev command, must be R/W"); + return; + } + + for (i=0; i= request) + if (req->dev<0) + break; + if (req < request) { + sleep_on(&wait_for_request); + goto repeat; + } + + req->dev = dev; + req->cmd = rw; + req->errors = 0; + req->sector = b[i] << 1; + req->nr_sectors = 2; + req->buffer = buf; + req->waiting = current; + req->bh = NULL; + req->next = NULL; + current->state = TASK_UNINTERRUPTIBLE; + add_request(major+blk_dev,req); + schedule(); + } +} diff --git a/kernel/0.95/linux-0.95/kernel/blk_drv/ramdisk.c b/kernel/0.95/linux-0.95/kernel/blk_drv/ramdisk.c new file mode 100644 index 00000000..a7d86fbb --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/blk_drv/ramdisk.c @@ -0,0 +1,126 @@ +/* + * linux/kernel/blk_drv/ramdisk.c + * + * Written by Theodore Ts'o, 12/2/91 + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR 1 +#include "blk.h" + +char *rd_start; +int rd_length = 0; + +void do_rd_request(void) +{ + int len; + char *addr; + + INIT_REQUEST; + addr = rd_start + (CURRENT->sector << 9); + len = CURRENT->nr_sectors << 9; + if ((MINOR(CURRENT->dev) != 1) || (addr+len > rd_start+rd_length)) { + end_request(0); + goto repeat; + } + if (CURRENT-> cmd == WRITE) { + (void ) memcpy(addr, + CURRENT->buffer, + len); + } else if (CURRENT->cmd == READ) { + (void) memcpy(CURRENT->buffer, + addr, + len); + } else + panic("unknown ramdisk-command"); + end_request(1); + goto repeat; +} + +/* + * Returns amount of memory which needs to be reserved. + */ +long rd_init(long mem_start, int length) +{ + int i; + char *cp; + + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + rd_start = (char *) mem_start; + rd_length = length; + cp = rd_start; + for (i=0; i < length; i++) + *cp++ = '\0'; + return(length); +} + +/* + * If the root device is the ram disk, try to load it. + * In order to do this, the root device is originally set to the + * floppy, and we later change it to be ram disk. + */ +void rd_load(void) +{ + struct buffer_head *bh; + struct super_block s; + int block = 256; /* Start at block 256 */ + int i = 1; + int nblocks; + char *cp; /* Move pointer */ + + if (!rd_length) + return; + printk("Ram disk: %d bytes, starting at 0x%x\n", rd_length, + (int) rd_start); + if (MAJOR(ROOT_DEV) != 2) + return; + bh = breada(ROOT_DEV,block+1,block,block+2,-1); + if (!bh) { + printk("Disk error while looking for ramdisk!\n"); + return; + } + *((struct minix_super_block *) &s) = *((struct minix_super_block *) bh->b_data); + brelse(bh); + if (s.s_magic != MINIX_SUPER_MAGIC) + /* No ram disk image present, assume normal floppy boot */ + return; + nblocks = s.s_nzones << s.s_log_zone_size; + if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) { + printk("Ram disk image too big! (%d blocks, %d avail)\n", + nblocks, rd_length >> BLOCK_SIZE_BITS); + return; + } + printk("Loading %d bytes into ram disk... 0000k", + nblocks << BLOCK_SIZE_BITS); + cp = rd_start; + while (nblocks) { + if (nblocks > 2) + bh = breada(ROOT_DEV, block, block+1, block+2, -1); + else + bh = bread(ROOT_DEV, block); + if (!bh) { + printk("I/O error on block %d, aborting load\n", + block); + return; + } + (void) memcpy(cp, bh->b_data, BLOCK_SIZE); + brelse(bh); + printk("\010\010\010\010\010%4dk",i); + cp += BLOCK_SIZE; + block++; + nblocks--; + i++; + } + printk("\010\010\010\010\010done \n"); + ROOT_DEV=0x0101; +} diff --git a/kernel/0.95/linux-0.95/kernel/chr_drv/Makefile b/kernel/0.95/linux-0.95/kernel/chr_drv/Makefile new file mode 100644 index 00000000..4c28f9c1 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/chr_drv/Makefile @@ -0,0 +1,93 @@ +# +# Makefile for the kernel character device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +# gcc2 doesn't understand this option: +#GCC_OPT = -fcombine-regs + +AR =ar +AS =as +LD =ld +LDFLAGS =-s -x +CC =gcc +CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) \ + -finline-functions -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 = tty_io.o console.o keyboard.o serial.o rs_io.o \ + tty_ioctl.o pty.o + +chr_drv.a: $(OBJS) + $(AR) rcs chr_drv.a $(OBJS) + sync + +keyboard.s: keyboard.S + $(CPP) -traditional keyboard.S -o keyboard.s + +clean: + rm -f core *.o *.a tmp_make keyboard.s + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +console.s console.o : console.c ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/timer.h \ + ../../include/linux/tty.h ../../include/termios.h \ + ../../include/linux/config.h ../../include/asm/io.h \ + ../../include/asm/system.h ../../include/asm/segment.h \ + ../../include/string.h ../../include/errno.h +pty.s pty.o : pty.c ../../include/linux/tty.h ../../include/termios.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ + ../../include/time.h ../../include/sys/resource.h \ + ../../include/asm/system.h ../../include/asm/io.h +serial.s serial.o : serial.c ../../include/linux/tty.h ../../include/termios.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ + ../../include/time.h ../../include/sys/resource.h \ + ../../include/linux/timer.h ../../include/asm/system.h \ + ../../include/asm/io.h +tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \ + ../../include/signal.h ../../include/sys/types.h ../../include/unistd.h \ + ../../include/sys/stat.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/times.h ../../include/sys/utsname.h \ + ../../include/sys/param.h ../../include/sys/resource.h \ + ../../include/utime.h ../../include/fcntl.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 ../../include/asm/system.h +tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ + ../../include/time.h ../../include/sys/resource.h ../../include/linux/tty.h \ + ../../include/asm/io.h ../../include/asm/segment.h \ + ../../include/asm/system.h diff --git a/kernel/0.95/linux-0.95/kernel/chr_drv/console.c b/kernel/0.95/linux-0.95/kernel/chr_drv/console.c new file mode 100644 index 00000000..3de86488 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/chr_drv/console.c @@ -0,0 +1,1200 @@ +/* + * linux/kernel/console.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * console.c + * + * This module implements the console io functions + * 'void con_init(void)' + * 'void con_write(struct tty_queue * queue)' + * Hopefully this will be a rather complete VT102 implementation. + * + * Beeping thanks to John T Kohl. + * + * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics + * Chars, and VT100 enhancements by Peter MacDonald. + */ + +/* + * NOTE!!! We sometimes disable and enable interrupts for a short while + * (to put a word in video IO), but this will work even for keyboard + * interrupts. We know interrupts aren't enabled when getting a keyboard + * interrupt, as we use trap-gates. Hopefully all is well. + */ + +/* + * Code to check for different video-cards mostly by Galen Hunt, + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define DEF_TERMIOS \ +(struct termios) { \ + ICRNL, \ + OPOST | ONLCR, \ + 0, \ + IXON | ISIG | ICANON | ECHO | ECHOCTL | ECHOKE, \ + 0, \ + INIT_C_CC \ +} + +static void blank_screen(void); +static void unblank_screen(void); + +/* + * These are set up by the setup-routine at boot-time: + */ + +#define ORIG_X (*(unsigned char *)0x90000) +#define ORIG_Y (*(unsigned char *)0x90001) +#define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004) +#define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff) +#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8) +#define ORIG_VIDEO_LINES ((*(unsigned short *)0x9000e) & 0xff) +#define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008) +#define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a) +#define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c) + +#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ +#define VIDEO_TYPE_CGA 0x11 /* CGA Display */ +#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */ +#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */ + +#define NPAR 16 + +int NR_CONSOLES = 0; + +extern void keyboard_interrupt(void); +extern void set_leds(void); +extern unsigned char kapplic; +extern unsigned char kleds; +extern unsigned char kmode; + +unsigned long video_num_columns; /* Number of text columns */ +unsigned long video_num_lines; /* Number of test lines */ + +static unsigned char video_type; /* Type of display being used */ +static unsigned long video_mem_base; /* Base of video memory */ +static unsigned long video_mem_term; /* End of video memory */ +static unsigned long video_size_row; /* Bytes per row */ +static unsigned char video_page; /* Initial video page */ +static unsigned short video_port_reg; /* Video register select port */ +static unsigned short video_port_val; /* Video register value port */ +static int can_do_colour = 0; + +static struct { + unsigned short vc_video_erase_char; + unsigned char vc_attr; + unsigned char vc_def_attr; + int vc_bold_attr; + unsigned long vc_ques; + unsigned long vc_state; + char * vc_restate; + unsigned long vc_checkin; + unsigned long vc_origin; /* Used for EGA/VGA fast scroll */ + unsigned long vc_scr_end; /* Used for EGA/VGA fast scroll */ + unsigned long vc_pos; + unsigned long vc_x,vc_y; + unsigned long vc_top,vc_bottom; + unsigned long vc_npar,vc_par[NPAR]; + unsigned long vc_video_mem_start; /* Start of video RAM */ + unsigned long vc_video_mem_end; /* End of video RAM (sort of) */ + unsigned int vc_saved_x; + unsigned int vc_saved_y; + unsigned int vc_iscolor; + unsigned char vc_kbdapplic; + unsigned char vc_kbdleds; + unsigned char vc_kbdmode; + char * vc_translate; +} vc_cons [MAX_CONSOLES]; + +#define MEM_BUFFER_SIZE (2*80*50*8) + +unsigned short *vc_scrbuf[MAX_CONSOLES]; +unsigned short vc_scrmembuf[MEM_BUFFER_SIZE/2]; +static int console_blanked = 0; + +#define origin (vc_cons[currcons].vc_origin) +#define scr_end (vc_cons[currcons].vc_scr_end) +#define pos (vc_cons[currcons].vc_pos) +#define top (vc_cons[currcons].vc_top) +#define bottom (vc_cons[currcons].vc_bottom) +#define x (vc_cons[currcons].vc_x) +#define y (vc_cons[currcons].vc_y) +#define state (vc_cons[currcons].vc_state) +#define restate (vc_cons[currcons].vc_restate) +#define checkin (vc_cons[currcons].vc_checkin) +#define npar (vc_cons[currcons].vc_npar) +#define par (vc_cons[currcons].vc_par) +#define ques (vc_cons[currcons].vc_ques) +#define attr (vc_cons[currcons].vc_attr) +#define saved_x (vc_cons[currcons].vc_saved_x) +#define saved_y (vc_cons[currcons].vc_saved_y) +#define translate (vc_cons[currcons].vc_translate) +#define video_mem_start (vc_cons[currcons].vc_video_mem_start) +#define video_mem_end (vc_cons[currcons].vc_video_mem_end) +#define def_attr (vc_cons[currcons].vc_def_attr) +#define video_erase_char (vc_cons[currcons].vc_video_erase_char) +#define iscolor (vc_cons[currcons].vc_iscolor) +#define kbdapplic (vc_cons[currcons].vc_kbdapplic) +#define kbdmode (vc_cons[currcons].vc_kbdmode) +#define kbdleds (vc_cons[currcons].vc_kbdleds) + +int blankinterval = 5*60*HZ; +static int screen_size = 0; + +static void sysbeep(void); + +/* + * this is what the terminal answers to a ESC-Z or csi0c + * query (= vt100 response). + */ +#define RESPONSE "\033[?1;2c" + +static char * translations[] = { +/* normal 7-bit ascii */ + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~ ", +/* vt100 graphics */ + " !\"#$%&'()*+,-./\333123456789:;<=>?" + "@ABCDEFGH\017JKLMNOPQRSTUVWXYZ[\\]^ " + /* ' a b c d e f g h i j k l m n o */ + "\004\261\007\007\007\007\370\361\040\007\331\277\332\300\305\007" + /* p q r s t u v w x y z { | } ~ */ + "\007\304\007\007\303\264\301\302\263\007\007\007\007\007\234 " + + /*"\004\261\007\007\007\007\370\361\007\007\275\267\326\323\327\304" + "\304\304\304\304\307\266\320\322\272\363\362\343\\007\234\007 " */ +}; + +#define NORM_TRANS (translations[0]) +#define GRAF_TRANS (translations[1]) + +/* NOTE! gotoxy thinks x==video_num_columns is ok */ +static inline void gotoxy(int currcons, int new_x,unsigned int new_y) +{ + if (new_x > video_num_columns || new_y >= video_num_lines) + return; + x = new_x; + y = new_y; + pos = origin + y*video_size_row + (x<<1); +} + +static inline void set_origin(int currcons) +{ + if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM) + return; + if (currcons != fg_console) + return; + cli(); + outb_p(12, video_port_reg); + outb_p(0xff&((origin-video_mem_base)>>9), video_port_val); + outb_p(13, video_port_reg); + outb_p(0xff&((origin-video_mem_base)>>1), video_port_val); + sti(); +} + +static void scrup(int currcons) +{ + unsigned int oldbottom, oldtop; + + oldbottom = bottom; + oldtop = top; + if (y < top) { + top = 0; + bottom = y + 1; + } else if (y > bottom) { + bottom = video_num_lines; + top = y; + } + if (top > video_num_lines) + top = 0; + if (bottom > video_num_lines) + bottom = video_num_lines; + if (bottom <= top) { + bottom = oldbottom; + top = oldtop; + return; + } + if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) + { + if (!top && bottom == video_num_lines) { + origin += video_size_row; + pos += video_size_row; + scr_end += video_size_row; + if (scr_end > video_mem_end) { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl _video_num_columns,%1\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((video_num_lines-1)*video_num_columns>>1), + "D" (video_mem_start), + "S" (origin) + :"cx","di","si"); + scr_end -= origin-video_mem_start; + pos -= origin-video_mem_start; + origin = video_mem_start; + } else { + __asm__("cld\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" (video_num_columns), + "D" (scr_end-video_size_row) + :"cx","di"); + } + set_origin(currcons); + } else { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl _video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*top), + "S" (origin+video_size_row*(top+1)) + :"cx","di","si"); + } + } + else /* Not EGA/VGA */ + { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl _video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*top), + "S" (origin+video_size_row*(top+1)) + :"cx","di","si"); + } + bottom = oldbottom; + top = oldtop; +} + +static void scrdown(int currcons) +{ + unsigned int oldbottom, oldtop; + + oldbottom = bottom; + oldtop = top; + if (y < top) { + top = 0; + bottom = y + 1; + } else if (y > bottom) { + bottom = video_num_lines; + top = y; + } + if (top > video_num_lines) + top = 0; + if (bottom > video_num_lines) + bottom = video_num_lines; + if (bottom<=top) { + bottom = oldbottom; + top = oldtop; + return; + } + __asm__("std\n\t" + "rep\n\t" + "movsl\n\t" + "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ + "movl _video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw\n\t" + "cld" + ::"a" (video_erase_char), + "c" ((bottom-top-1)*video_num_columns>>1), + "D" (origin+video_size_row*bottom-4), + "S" (origin+video_size_row*(bottom-1)-4) + :"ax","cx","di","si"); + bottom = oldbottom; + top = oldtop; +} + +static void lf(int currcons) +{ + if (y+1top) { + y--; + pos -= video_size_row; + return; + } else + scrdown(currcons); +} + +static void cr(int currcons) +{ + pos -= x<<1; + x=0; +} + +static void del(int currcons) +{ + if (x) { + pos -= 2; + x--; + *(unsigned short *)pos = video_erase_char; + } +} + +static void csi_J(int currcons, int vpar) +{ + long count; + long start; + + switch (vpar) { + case 0: /* erase from cursor to end of display */ + count = (scr_end-pos)>>1; + start = pos; + break; + case 1: /* erase from start to cursor */ + count = (pos-origin)>>1; + start = origin; + break; + case 2: /* erase whole display */ + count = video_num_columns * video_num_lines; + start = origin; + break; + default: + return; + } + __asm__("cld\n\t" + "rep\n\t" + "stosw\n\t" + ::"c" (count), + "D" (start),"a" (video_erase_char) + :"cx","di"); +} + +static void csi_K(int currcons, int vpar) +{ + long count; + long start; + + switch (vpar) { + case 0: /* erase from cursor to end of line */ + if (x>=video_num_columns) + return; + count = video_num_columns-x; + start = pos; + break; + case 1: /* erase from start of line to cursor */ + start = pos - (x<<1); + count = (x>4)&0xf)? + (attr&0xf0)|(((attr&0xf)+1)%0xf): + newattr); + } + } + break; + case 5: attr=attr|0x80;break; /* blinking */ + case 7: attr=(attr<<4)|(attr>>4);break; /* negative */ + case 22: attr=attr&0xf7;break; /* not bold */ + case 24: attr=attr&0xfe;break; /* not underline */ + case 25: attr=attr&0x7f;break; /* not blinking */ + case 27: attr=def_attr;break; /* positive image */ + case 39: attr=(attr & 0xf0)|(def_attr & 0x0f); break; + case 49: attr=(attr & 0x0f)|(def_attr & 0xf0); break; + default: + if (!can_do_colour) + break; + iscolor = 1; + if ((par[i]>=30) && (par[i]<=37)) + attr = (attr & 0xf0) | conv_table[par[i]-30]; + else /* Background color */ + if ((par[i]>=40) && (par[i]<=47)) + attr = (attr & 0x0f) | (conv_table[par[i]-40]<<4); + else + break; + } +} + +static inline void set_cursor(int currcons) +{ + if (currcons != fg_console) + return; + cli(); + outb_p(14, video_port_reg); + outb_p(0xff&((pos-video_mem_base)>>9), video_port_val); + outb_p(15, video_port_reg); + outb_p(0xff&((pos-video_mem_base)>>1), video_port_val); + sti(); +} + +static inline void hide_cursor(int currcons) +{ + outb_p(14, video_port_reg); + outb_p(0xff&((scr_end-video_mem_base)>>9), video_port_val); + outb_p(15, video_port_reg); + outb_p(0xff&((scr_end-video_mem_base)>>1), video_port_val); +} + +static void respond(int currcons, 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(int currcons) +{ + int i=x; + unsigned short tmp, old = video_erase_char; + unsigned short * p = (unsigned short *) pos; + + while (i++=video_num_columns) + return; + i = x; + while (++i < video_num_columns) { + *p = *(p+1); + p++; + } + *p = video_erase_char; +} + +static void delete_line(int currcons) +{ + int oldtop,oldbottom; + + oldtop=top; + oldbottom=bottom; + top=y; + bottom = video_num_lines; + scrup(currcons); + top=oldtop; + bottom=oldbottom; +} + +static void csi_at(int currcons, unsigned int nr) +{ + if (nr > video_num_columns) + nr = video_num_columns; + else if (!nr) + nr = 1; + while (nr--) + insert_char(currcons); +} + +static void csi_L(int currcons, unsigned int nr) +{ + if (nr > video_num_lines) + nr = video_num_lines; + else if (!nr) + nr = 1; + while (nr--) + insert_line(currcons); +} + +static void csi_P(int currcons, unsigned int nr) +{ + if (nr > video_num_columns) + nr = video_num_columns; + else if (!nr) + nr = 1; + while (nr--) + delete_char(currcons); +} + +static void csi_M(int currcons, unsigned int nr) +{ + if (nr > video_num_lines) + nr = video_num_lines; + else if (!nr) + nr=1; + while (nr--) + delete_line(currcons); +} + +static void save_cur(int currcons) +{ + saved_x=x; + saved_y=y; +} + +static void restore_cur(int currcons) +{ + gotoxy(currcons,saved_x, saved_y); +} + + +enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, + ESsetterm, ESsetgraph, ESgraph, ESgresc, ESignore }; + +void con_write(struct tty_struct * tty) +{ + int nr; + char c; + int currcons; + + wake_up(&tty->write_q->proc_list); + currcons = tty - tty_table; + if ((currcons>=MAX_CONSOLES) || (currcons<0)) { + printk("con_write: illegal tty\n\r"); + return; + } + nr = CHARS(tty->write_q); + while (nr--) { + if (tty->stopped) + break; + GETCH(tty->write_q,c); + if (c == 24 || c == 26) + state = ESnormal; + switch(state) { + case ESnormal: + if (c>31 && c<127) { + if (x>=video_num_columns) { + x -= video_num_columns; + pos -= video_size_row; + lf(currcons); + } + *(char *) pos = translate[c-32]; + pos++; + *(char *) pos = attr; + pos++; + x++; + } else if (c==27) + state = ESesc; + else if (c==10 || c==11 || c==12) + lf(currcons); + else if (c==13) + cr(currcons); + else if (c==127) + del(currcons); + else if (c==8) { + if (x) { + x--; + pos -= 2; + } + } else if (c==9) { + c = 8-(x&7); + x += c; + pos += c<<1; + if (x>video_num_columns) { + x -= video_num_columns; + pos -= video_size_row; + lf(currcons); + } + c=9; + } else if (c==7) + sysbeep(); + else if (c == 14) { + checkin = 1; + translate = restate; + } else if (c == 15) { + translate = NORM_TRANS; + checkin = 0; + } + break; + case ESesc: + state = ESnormal; + switch (c) { + case '[': + state = ESsquare; + break; + case 'E': + gotoxy(currcons,0,y+1); + break; + case 'M': + ri(currcons); + break; + case 'D': + lf(currcons); + break; + case 'Z': + respond(currcons,tty); + break; + case '7': + save_cur(currcons); + break; + case '8': + restore_cur(currcons); + break; + case '(': + case ')': + state = ESsetgraph; + break; + case 'P': + state = ESsetterm; + break; + case '#': + state = -1; + break; + case 'c': + tty->termios = DEF_TERMIOS; + state = ESnormal; + restate = NORM_TRANS; + checkin = 0; + top = 0; + bottom = video_num_lines; + translate = NORM_TRANS; + case '>': /* Numeric keypad */ + kbdapplic = 0; + if (currcons == fg_console) + kapplic = 0; + break; + case '=': /* Appl. keypad */ + kbdapplic = 1; + if (currcons == fg_console) + kapplic = 1; + break; + } + break; + case ESsquare: + for(npar = 0 ; npar < NPAR ; npar++) + par[npar]=0; + npar = 0; + state = ESgetpars; + if (c == '[') { /* Function key */ + state=ESfunckey; + break; + } + if (ques=(c=='?')) + break; + case ESgetpars: + if (c==';' && npar='0' && c<='9') { + par[npar]=10*par[npar]+c-'0'; + break; + } else state=ESgotpars; + case ESgotpars: + state = ESnormal; + if (ques) { + ques = 0; + break; + } + switch(c) { + case 'G': case '`': + if (par[0]) par[0]--; + gotoxy(currcons,par[0],y); + break; + case 'A': + if (!par[0]) par[0]++; + gotoxy(currcons,x,y-par[0]); + break; + case 'B': case 'e': + if (!par[0]) par[0]++; + gotoxy(currcons,x,y+par[0]); + break; + case 'C': case 'a': + if (!par[0]) par[0]++; + gotoxy(currcons,x+par[0],y); + break; + case 'D': + if (!par[0]) par[0]++; + gotoxy(currcons,x-par[0],y); + break; + case 'E': + if (!par[0]) par[0]++; + gotoxy(currcons,0,y+par[0]); + break; + case 'F': + if (!par[0]) par[0]++; + gotoxy(currcons,0,y-par[0]); + break; + case 'd': + if (par[0]) par[0]--; + gotoxy(currcons,x,par[0]); + break; + case 'H': case 'f': + if (par[0]) par[0]--; + if (par[1]) par[1]--; + gotoxy(currcons,par[1],par[0]); + break; + case 'J': + csi_J(currcons,par[0]); + break; + case 'K': + csi_K(currcons,par[0]); + break; + case 'L': + csi_L(currcons,par[0]); + break; + case 'M': + csi_M(currcons,par[0]); + break; + case 'P': + csi_P(currcons,par[0]); + break; + case '@': + csi_at(currcons,par[0]); + break; + case 'm': + csi_m(currcons); + break; + case 'r': + if (par[0]) par[0]--; + if (!par[1]) par[1] = video_num_lines; + if (par[0] < par[1] && + par[1] <= video_num_lines) { + top=par[0]; + bottom=par[1]; + } + break; + case 's': + save_cur(currcons); + break; + case 'u': + restore_cur(currcons); + break; + case 'l': /* blank interval */ + case 'b': /* bold attribute */ + if (!((npar >= 2) && + ((par[1]-13) == par[0]) && + ((par[2]-17) == par[0]))) + break; + if ((c=='l') && (par[0]<=60)) { + blankinterval = HZ*60*par[0]; + } + if (c=='b') + vc_cons[currcons].vc_bold_attr + = par[0]; + } + break; + case ESfunckey: + state = ESnormal; + break; + case ESsetterm: /* Setterm functions. */ + state = ESnormal; + if (c == 'S') { + def_attr = attr; + video_erase_char = (video_erase_char&0x0ff) | (def_attr<<8); + } else if (c == 'L') + /*linewrap on*/; + else if (c == 'l') + /*linewrap off*/; + break; + case ESsetgraph: + if (c == '0') { + if (checkin) + translate = GRAF_TRANS; + restate = GRAF_TRANS; + } else if (c == 'B') + translate = restate = NORM_TRANS; + state = ESnormal; + break; + default: + state = ESnormal; + } + } + set_cursor(currcons); + timer_active &= ~(1< MAX_CONSOLES) + NR_CONSOLES = MAX_CONSOLES; + if (!NR_CONSOLES) + NR_CONSOLES = 1; + video_memory = screen_size; + + /* Initialize the variables used for scrolling (mostly EGA/VGA) */ + + base = origin = video_mem_start = video_mem_base; + term = video_mem_end = base + video_memory; + scr_end = video_mem_start + screen_size; + top = 0; + bottom = video_num_lines; + attr = 0x07; + def_attr = 0x07; + restate = NORM_TRANS; + state = ESnormal; + checkin = 0; + ques = 0; + iscolor = 0; + translate = NORM_TRANS; + kbdleds = 2; + kbdmode = 0; + kbdapplic = 0; + vc_cons[0].vc_bold_attr = -1; + + gotoxy(currcons,ORIG_X,ORIG_Y); + for (currcons = 1; currconsNR_CONSOLES)) + return -EIO; + put_fs_byte((char)(video_num_lines),buf++); + put_fs_byte((char)(video_num_columns),buf++); + currcons = (currcons ? currcons-1 : fg_console); + sptr = (char *) origin; + for (l=video_num_lines*video_num_columns; l>0 ; l--, sptr++) + put_fs_byte(*sptr++,buf++); + return(0); +} + +void console_print(const char * b) +{ + int currcons = fg_console; + char c; + + if (currcons<0 || currcons>=NR_CONSOLES) + currcons = 0; + while (c = *(b++)) { + if (c == 10) { + cr(currcons); + lf(currcons); + continue; + } + if (c == 13) { + cr(currcons); + continue; + } + if (x>=video_num_columns) { + x -= video_num_columns; + pos -= video_size_row; + lf(currcons); + } + *(char *) pos = c; + pos++; + *(char *) pos = attr; + pos++; + x++; + } + set_cursor(currcons); +} diff --git a/kernel/0.95/linux-0.95/kernel/chr_drv/keyboard.S b/kernel/0.95/linux-0.95/kernel/chr_drv/keyboard.S new file mode 100644 index 00000000..0177e068 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/chr_drv/keyboard.S @@ -0,0 +1,805 @@ +/* + * linux/kernel/keyboard.S + * + * (C) 1991 Linus Torvalds + */ + +/* + * Thanks to Alfred Leung for US keyboard patches + * Wolfgang Thiel for German keyboard patches + * Marc Corsini for the French keyboard + * LeBlanc@mcc.ac.uk for the UK keyboard + * Tommy Thorn (tthorn@daimi.aau.dk) for Danish keyboard + */ + +/* KBD_FINNISH for Finnish keyboards + * KBD_US for US-type + * KBD_GR for German keyboards + * KBD_FR for Frech keyboard + * KBD_UK for British extended keyboard + * KBD_DK for Danish keyboard + */ +#define KBD_FINNISH + +.text +.globl _hard_reset_now +.globl _keyboard_interrupt +.globl _kapplic +.globl _kmode +.globl _kleds +.globl _set_leds + +/* + * 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 + +_kapplic: .byte 0 +_kmode: .byte 0 /* caps, alt, ctrl and shift mode */ +_kleds: .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: + cld + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + push %ds + push %es + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + xorl %eax,%eax /* %eax is scan code */ + inb $0x60,%al + pushl %eax + 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 + jmp 1f +1: jmp 1f +1: movb $0x20,%al + outb %al,$0x20 + popl %eax + movl $1,%ebx + cmpb $0xE0,%al + je end_intr + movl $2,%ebx + cmpb $0xE1,%al + je end_intr + sti + call key_table(,%eax,4) + call _do_keyboard_interrupt + movl $0,%ebx +end_intr: + movb %bl,e0 + pop %es + pop %ds + popl %edx + popl %ecx + popl %ebx + popl %eax + iret + +/* + * 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,_kmode + 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,_kmode + ret + +lshift: + orb $0x01,_kmode + ret +unlshift: + andb $0xfe,_kmode + ret +rshift: + orb $0x02,_kmode + ret +unrshift: + andb $0xfd,_kmode + ret + +old_leds: + .byte 2 + +caps: testb $0x80,_kmode + jne 1f + xorb $4,_kleds + xorb $0x40,_kmode + orb $0x80,_kmode +_set_leds: + movb _kleds,%al + cmpb old_leds,%al + je 1f + movb %al,old_leds + call kb_wait + movb $0xed,%al /* set leds command */ + outb %al,$0x60 + call kb_wait + movb _kleds,%al + outb %al,$0x60 +1: ret +uncaps: andb $0x7f,_kmode + ret +scroll: + testb $0x03,_kmode + je 1f + call _show_mem + jmp 2f +1: call _show_state +2: xorb $1,_kleds + jmp _set_leds + +num: cmpb $0x01,_kapplic + jne notappl + movw $0x0050,%ax +applkey: + shll $16,%eax + movw $0x4f1b,%ax + xorl %ebx,%ebx + jmp put_queue + +notappl: + xorb $2,_kleds + jmp _set_leds + +/* + * cursor-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,_kmode + je cur2 + testb $0x30,_kmode + jne _ctrl_alt_del +cur2: cmpb $0x01,e0 /* e0 forces cursor movement */ + je cur + testb $0x03,_kmode /* shift forces cursor */ + jne cur + cmpb $0x01,_kapplic + jne notcappl + movb appl_table(%eax),%al + jmp applkey +notcappl: + testb $0x02,_kleds /* not num-lock forces cursor */ + je cur + xorl %ebx,%ebx + movb num_table(%eax),%al + jmp put_queue +1: ret + +/* + * cursor keys send ^[ [ x if normal, ^[ O x if application mode + */ +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 + cmpb $0x01,_kapplic + jne put_queue + movb $0x4f,%ah + jmp put_queue + +#if defined(KBD_FR) /* || defined(KBD_DK) correct, but .. */ +num_table: + .ascii "789-456+1230." +#else +num_table: + .ascii "789-456+1230," +#endif +cur_table: + .ascii "HA5-DGC+YB623" + +/* + Keypad / 35 B7 Q + Keypad * (PrtSc) 37 B7 R + Keypad NumLock 45 ?? P + Keypad 7 (Home) 47 C7 w + Keypad 8 (Up arrow) 48 C8 x + Keypad 9 (PgUp) 49 C9 y + Keypad - 4A CA S + Keypad 4 (Left arrow) 4B CB t + Keypad 5 4C CC u + Keypad 6 (Right arrow) 4D CD v + Keypad + 4E CE l + Keypad 1 (End) 4F CF q + Keypad 2 (Down arrow) 50 D0 r + Keypad 3 (PgDn) 51 D1 s + Keypad 0 (Ins) 52 D2 p + Keypad . (Del) 53 D3 n +*/ + +appl_table: + .ascii "wxyStuvlqrspn" + +/* + * 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: + testb $0x10,_kmode + jne alt_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 +alt_func: + pushl %eax + call _change_console + popl %eax +end_func: + ret + +/* + * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc. + */ +func_table: + .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b + .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b + .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b + +#if defined(KBD_FINNISH) +key_map: + .byte 0,27 + .ascii "1234567890+'" + .byte 127,9 + .ascii "qwertyuiop}" + .byte 0,13,0 + .ascii "asdfghjkl|{" + .byte 0,0 + .ascii "'zxcvbnm,.-" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + +shift_map: + .byte 0,27 + .ascii "!\"#$%&/()=?`" + .byte 127,9 + .ascii "QWERTYUIOP]^" + .byte 13,0 + .ascii "ASDFGHJKL\\[" + .byte 0,0 + .ascii "*ZXCVBNM;:_" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#elif defined(KBD_US) + +key_map: + .byte 0,27 + .ascii "1234567890-=" + .byte 127,9 + .ascii "qwertyuiop[]" + .byte 13,0 + .ascii "asdfghjkl;'" + .byte '`,0 + .ascii "\\zxcvbnm,./" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + +shift_map: + .byte 0,27 + .ascii "!@#$%^&*()_+" + .byte 127,9 + .ascii "QWERTYUIOP{}" + .byte 13,0 + .ascii "ASDFGHJKL:\"" + .byte '~,0 + .ascii "|ZXCVBNM<>?" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#elif defined(KBD_UK) + +key_map: + .byte 0,27 + .ascii "1234567890-=" + .byte 127,9 + .ascii "qwertyuiop[]" + .byte 13,0 + .ascii "asdfghjkl;'" + .byte '`,0 + .ascii "#zxcvbnm,./" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .ascii "\\" + .fill 10,1,0 + +shift_map: + .byte 0,27 + .ascii "!\"#$%%&*()_+" + .byte 127,9 + .ascii "QWERTYUIOP{}" + .byte 13,0 + .ascii "ASDFGHJKL:@" + .byte '~,0 + .ascii "~ZXCVBNM<>?" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#elif defined(KBD_GR) + +key_map: + .byte 0,27 + .ascii "1234567890\\'" + .byte 127,9 + .ascii "qwertzuiop@+" + .byte 13,0 + .ascii "asdfghjkl[]^" + .byte 0,'# + .ascii "yxcvbnm,.-" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + +shift_map: + .byte 0,27 + .ascii "!\"#$%&/()=?`" + .byte 127,9 + .ascii "QWERTZUIOP\\*" + .byte 13,0 + .ascii "ASDFGHJKL{}~" + .byte 0,'' + .ascii "YXCVBNM;:_" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\\\0" + .byte 0,0 + .byte '@,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#elif defined(KBD_FR) + +key_map: + .byte 0,27 + .ascii "&{\"'(-}_/@)=" + .byte 127,9 + .ascii "azertyuiop^$" + .byte 13,0 + .ascii "qsdfghjklm|" + .byte '`,0,42 /* coin sup gauche, don't know, [*|mu] */ + .ascii "wxcvbn,;:!" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '< + .fill 10,1,0 + +shift_map: + .byte 0,27 + .ascii "1234567890]+" + .byte 127,9 + .ascii "AZERTYUIOP<>" + .byte 13,0 + .ascii "QSDFGHJKLM%" + .byte '~,0,'# + .ascii "WXCVBN?./\\" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0~#{[|`\\^@]}" + .byte 0,0 + .byte '@,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '| + .fill 10,1,0 + +#elif defined(KBD_DK) + +key_map: + .byte 0,27 + .ascii "1234567890+'" + .byte 127,9 + .ascii "qwertyuiop" + .byte 134,0,13,0 /* This is IBM-PC, change it to latin-1 */ + .ascii "asdfghjkl" + .byte 145,155,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 143,94,13,0 + .ascii "ASDFGHJKL" + .byte 146,157,0,0 + .ascii "*ZXCVBNM;:_" + .byte 0,'*,0,32 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte '-,0,0,0,'+ /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .byte '> + .fill 10,1,0 + +alt_map: + .byte 0,0 + .ascii "\0@\0$\0\0{[]}\0" + .byte '|,0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte '~,13,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0 + .byte 0,0,0,0,0,0,0,0,0,0,0 + .byte 0,0,0,0 /* 36-39 */ + .fill 16,1,0 /* 3A-49 */ + .byte 0,0,0,0,0 /* 4A-4E */ + .byte 0,0,0,0,0,0,0 /* 4F-55 */ + .ascii "\\" + .fill 10,1,0 + +#else +#error "KBD-type not defined" +#endif +/* + * do_self handles "normal" keys, ie keys that don't change meaning + * and which have just one character returns. + */ +do_self: + lea alt_map,%ebx + testb $0x20,_kmode /* alt-gr */ + jne 1f + lea shift_map,%ebx + testb $0x03,_kmode + jne 1f + lea key_map,%ebx +1: movb (%ebx,%eax),%al + orb %al,%al + je none + testb $0x4c,_kmode /* ctrl or caps */ + je 2f + cmpb $'a,%al + jb 2f + cmpb $'},%al + ja 2f + subb $32,%al +2: testb $0x0c,_kmode /* ctrl */ + je 3f + cmpb $64,%al + jb 3f + cmpb $64+32,%al + jae 3f + subb $64,%al +3: testb $0x10,_kmode /* left alt */ + je 4f + orb $0x80,%al +4: andl $0xff,%eax + xorl %ebx,%ebx + call put_queue +none: ret + +/* + * slash and star have routines of their own, as a 'E0h' before + * the scan code for slash means that the numeric keypad + * slash was pushed. + */ +slash: cmpb $1,e0 + jne do_self + cmpb $1,_kapplic + jne notmapplic + movw $'Q,%ax + jmp applkey + +notmapplic: + movl $'/,%eax + xorl %ebx,%ebx + jmp put_queue + +star: cmpb $1,_kapplic + jne do_self + movw $'R,%ax + jmp applkey + +notsapplic: + movl $'*,%eax + xorl %ebx,%ebx + jmp put_queue + +enter: cmpb $1,e0 + jne do_self + cmpb $1,_kapplic + jne do_self + movw $'M,%ax + jmp applkey + +minus: cmpb $1,_kapplic + jne do_self + movw $'S,%ax + jmp applkey + +plus: cmpb $1,_kapplic + jne do_self + movw $'l,%ax + jmp applkey + +/* + * 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 enter,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,slash,rshift,star /* 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,minus,cursor /* 48-4B up pgup - left */ + .long cursor,cursor,plus,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. + */ +kb_wait: + pushl %eax + pushl %ebx + movl $10000,%ebx +1: inb $0x64,%al + testb $0x02,%al + je 2f + decl %ebx + jne 1b +2: popl %ebx + popl %eax + ret + +no_idt: + .long 0,0 +/* + * This routine reboots the machine by asking the keyboard + * controller to pulse the reset-line low. We try that for a while, + * and if it doesn't work, we do some other stupid things. + */ +_hard_reset_now: + sti + movl $100,%ebx +1: call kb_wait + movw $0x1234,0x472 /* don't do memory check */ + movb $0xfe,%al /* pulse reset low */ + outb %al,$0x64 + decl %ebx + jne 1b + lidt no_idt /* zero-length idt: should triple-fault */ + jmp _hard_reset_now diff --git a/kernel/0.95/linux-0.95/kernel/chr_drv/pty.c b/kernel/0.95/linux-0.95/kernel/chr_drv/pty.c new file mode 100644 index 00000000..43407dc7 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/chr_drv/pty.c @@ -0,0 +1,63 @@ +/* + * linux/kernel/chr_drv/pty.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * pty.c + * + * This module implements the pty functions + * void mpty_write(struct tty_struct * queue); + * void spty_write(struct tty_struct * queue); + */ + +#include +#include +#include +#include + +static inline void pty_copy(struct tty_struct * from, struct tty_struct * to) +{ + char c; + + while (!from->stopped && !EMPTY(from->write_q)) { + if (FULL(to->read_q)) { + if (FULL(to->secondary)) + break; + copy_to_cooked(to); + continue; + } + GETCH(from->write_q,c); + PUTCH(c,to->read_q); + if (current->signal & ~current->blocked) + break; + } + copy_to_cooked(to); + wake_up(&from->write_q->proc_list); +} + +/* + * This routine gets called when tty_write has put something into + * the write_queue. It copies the input to the output-queue of it's + * slave. + */ +void mpty_write(struct tty_struct * tty) +{ + int nr = tty - tty_table; + + if ((nr >> 6) != 2) + printk("bad mpty\n\r"); + else + pty_copy(tty,tty+64); +} + +void spty_write(struct tty_struct * tty) +{ + int nr = tty - tty_table; + + if ((nr >> 6) != 3) + printk("bad spty\n\r"); + else + pty_copy(tty,tty-64); +} diff --git a/kernel/0.95/linux-0.95/kernel/chr_drv/rs_io.s b/kernel/0.95/linux-0.95/kernel/chr_drv/rs_io.s new file mode 100644 index 00000000..f147cecb --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/chr_drv/rs_io.s @@ -0,0 +1,151 @@ +/* + * linux/kernel/rs_io.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * rs_io.s + * + * This module implements the rs232 io interrupts. + */ + +.text +.globl _rs1_interrupt,_rs2_interrupt + +size = 1024 /* must be power of two ! + and must match the value + in tty_io.c!!! */ + +/* these are the offsets into the read/write buffer structures */ +rs_addr = 0 +head = 4 +tail = 8 +proc_list = 12 +buf = 16 + +startup = 256 /* chars left in write queue when we restart it */ + +/* + * These are the actual interrupt routines. They look where + * the interrupt is coming from, and take appropriate action. + */ +.align 2 +_rs1_interrupt: + pushl $_table_list+8 + jmp rs_int +.align 2 +_rs2_interrupt: + pushl $_table_list+16 +rs_int: + cld + 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) +1: movl mask_table(,%edx,4),%edx + orl %edx,_timer_active + ret + +.align 2 +mask_table: + .long 0,4,8 + +.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/kernel/0.95/linux-0.95/kernel/chr_drv/serial.c b/kernel/0.95/linux-0.95/kernel/chr_drv/serial.c new file mode 100644 index 00000000..2334e50a --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/chr_drv/serial.c @@ -0,0 +1,113 @@ +/* + * linux/kernel/serial.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * serial.c + * + * This module implements the rs232 io functions + * void rs_write(struct tty_struct * queue); + * void rs_init(void); + * and all interrupts pertaining to serial IO. + */ + +#include +#include +#include +#include +#include + +#define WAKEUP_CHARS (TTY_BUF_SIZE/4) + +extern void rs1_interrupt(void); +extern void rs2_interrupt(void); + +static void com1_timer(void) +{ + copy_to_cooked(tty_table+64); +} + +static void com2_timer(void) +{ + copy_to_cooked(tty_table+65); +} + +static inline void do_rs_write(unsigned int port) +{ + char c; + +#define TTY (tty_table[64+port].write_q) +#define TIMER (SER1_TIMEOUT+port) + cli(); + if (!EMPTY(TTY)) { + outb_p(inb_p(TTY->data+1)|0x02,TTY->data+1); + if (inb(TTY->data+5) & 0x20) { + GETCH(TTY,c); + outb(c,TTY->data); + } + timer_table[TIMER].expires = jiffies + 50; + timer_active |= 1 << TIMER; + } else + timer_active &= ~(1 << TIMER); + sti(); +#undef TIMER +#undef TTY +} + +static void com1_timeout(void) +{ + do_rs_write(0); +} + +static void com2_timeout(void) +{ + do_rs_write(1); +} + +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) +{ +/* SERx_TIMER timers are used for receiving: timeout is always 0 (immediate) */ + timer_table[SER1_TIMER].fn = com1_timer; + timer_table[SER1_TIMER].expires = 0; + timer_table[SER2_TIMER].fn = com2_timer; + timer_table[SER2_TIMER].expires = 0; +/* SERx_TIMEOUT timers are used for writing: prevent serial lockups */ + timer_table[SER1_TIMEOUT].fn = com1_timeout; + timer_table[SER1_TIMEOUT].expires = 0; + timer_table[SER2_TIMEOUT].fn = com2_timeout; + timer_table[SER2_TIMEOUT].expires = 0; + set_intr_gate(0x24,rs1_interrupt); + set_intr_gate(0x23,rs2_interrupt); + init(tty_table[64].read_q->data); + init(tty_table[65].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_p(inb_p(tty->write_q->data+1)|0x02,tty->write_q->data+1); + timer_active |= 3 << SER1_TIMEOUT; + sti(); +} diff --git a/kernel/0.95/linux-0.95/kernel/chr_drv/tty_io.c b/kernel/0.95/linux-0.95/kernel/chr_drv/tty_io.c new file mode 100644 index 00000000..18ea2615 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/chr_drv/tty_io.c @@ -0,0 +1,478 @@ +/* + * linux/kernel/tty_io.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles + * or rs-channels. It also implements echoing, cooked mode etc. + * + * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. + */ + +#include +#include +#include +#include +#include + +#define ALRMMASK (1<<(SIGALRM-1)) + +#include +#include +#include +#include + +int kill_pg(int pgrp, int sig, int priv); +int is_orphaned_pgrp(int pgrp); + +#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_ECHONL(tty) _L_FLAG((tty),ECHONL) +#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL) +#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE) +#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP) + +#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 I_IXON(tty) _I_FLAG((tty),IXON) + +#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) + +#define C_SPEED(tty) ((tty)->termios.c_cflag & CBAUD) +#define C_HUP(tty) (C_SPEED((tty)) == B0) + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define QUEUES (3*(MAX_CONSOLES+NR_SERIALS+2*NR_PTYS)) +static struct tty_queue tty_queues[QUEUES]; +struct tty_struct tty_table[256]; + +#define con_queues tty_queues +#define rs_queues ((3*MAX_CONSOLES) + tty_queues) +#define mpty_queues ((3*(MAX_CONSOLES+NR_SERIALS)) + tty_queues) +#define spty_queues ((3*(MAX_CONSOLES+NR_SERIALS+NR_PTYS)) + tty_queues) + +#define con_table tty_table +#define rs_table (64+tty_table) +#define mpty_table (128+tty_table) +#define spty_table (192+tty_table) + +int fg_console = 0; + +/* + * these are the tables used by the machine code handlers. + * you can implement virtual consoles. + */ +struct tty_queue * table_list[]={ + con_queues + 0, con_queues + 1, + rs_queues + 0, rs_queues + 1, + rs_queues + 3, rs_queues + 4 + }; + +void change_console(unsigned int new_console) +{ + if (new_console == fg_console || new_console >= NR_CONSOLES) + return; + table_list[0] = con_queues + 0 + new_console*3; + table_list[1] = con_queues + 1 + new_console*3; + update_screen(new_console); +} + +static void sleep_if_empty(struct tty_queue * queue) +{ + cli(); + while (!(current->signal & ~current->blocked) && 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 & ~current->blocked) && LEFT(queue)<128) + interruptible_sleep_on(&queue->proc_list); + sti(); +} + +void wait_for_keypress(void) +{ + sleep_if_empty(tty_table[fg_console].secondary); +} + +void copy_to_cooked(struct tty_struct * tty) +{ + unsigned char c; + + if (!(tty->read_q || tty->write_q || tty->secondary)) { + printk("copy_to_cooked: missing queues\n\r"); + return; + } + while (1) { + if (EMPTY(tty->read_q)) + break; + if (FULL(tty->secondary)) + break; + GETCH(tty->read_q,c); + if (c==13) { + if (I_CRNL(tty)) + c=10; + else if (I_NOCR(tty)) + continue; + } else if (c==10 && I_NLCR(tty)) + c=13; + if (I_UCLC(tty)) + c=tolower(c); + if (L_CANON(tty)) { + if ((KILL_CHAR(tty) != _POSIX_VDISABLE) && + (c==KILL_CHAR(tty))) { + /* deal with killing the input line */ + while(!(EMPTY(tty->secondary) || + (c=LAST(tty->secondary))==10 || + ((EOF_CHAR(tty) != _POSIX_VDISABLE) && + (c==EOF_CHAR(tty))))) { + if (L_ECHO(tty)) { + if (c<32) + PUTCH(127,tty->write_q); + PUTCH(127,tty->write_q); + tty->write(tty); + } + DEC(tty->secondary->head); + } + continue; + } + if ((ERASE_CHAR(tty) != _POSIX_VDISABLE) && + (c==ERASE_CHAR(tty))) { + if (EMPTY(tty->secondary) || + (c=LAST(tty->secondary))==10 || + ((EOF_CHAR(tty) != _POSIX_VDISABLE) && + (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 (I_IXON(tty)) { + if ((STOP_CHAR(tty) != _POSIX_VDISABLE) && + (c==STOP_CHAR(tty))) { + tty->stopped=1; + tty->write(tty); + continue; + } + if ((START_CHAR(tty) != _POSIX_VDISABLE) && + (c==START_CHAR(tty))) { + tty->stopped=0; + tty->write(tty); + continue; + } + } + if (L_ISIG(tty)) { + if ((INTR_CHAR(tty) != _POSIX_VDISABLE) && + (c==INTR_CHAR(tty))) { + kill_pg(tty->pgrp, SIGINT, 1); + continue; + } + if ((QUIT_CHAR(tty) != _POSIX_VDISABLE) && + (c==QUIT_CHAR(tty))) { + kill_pg(tty->pgrp, SIGQUIT, 1); + continue; + } + if ((SUSPEND_CHAR(tty) != _POSIX_VDISABLE) && + (c==SUSPEND_CHAR(tty))) { + if (!is_orphaned_pgrp(tty->pgrp)) + kill_pg(tty->pgrp, SIGTSTP, 1); + continue; + } + } + if (c==10 || (EOF_CHAR(tty) != _POSIX_VDISABLE && + c==EOF_CHAR(tty))) + tty->secondary->data++; + if ((L_ECHO(tty) || L_ECHONL(tty)) && (c==10)) { + PUTCH(10,tty->write_q); + PUTCH(13,tty->write_q); + } else if (L_ECHO(tty)) { + if (c<32 && 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); +} + +/* + * Called when we need to send a SIGTTIN or SIGTTOU to our process + * group + * + * We only request that a system call be restarted if there was if the + * default signal handler is being used. The reason for this is that if + * a job is catching SIGTTIN or SIGTTOU, the signal handler may not want + * the system call to be restarted blindly. If there is no way to reset the + * terminal pgrp back to the current pgrp (perhaps because the controlling + * tty has been released on logout), we don't want to be in an infinite loop + * while restarting the system call, and have it always generate a SIGTTIN + * or SIGTTOU. The default signal handler will cause the process to stop + * thus avoiding the infinite loop problem. Presumably the job-control + * cognizant parent will fix things up before continuging its child process. + */ +int tty_signal(int sig, struct tty_struct *tty) +{ + if (is_orphaned_pgrp(current->pgrp)) + return -EIO; /* don't stop an orphaned pgrp */ + (void) kill_pg(current->pgrp,sig,1); + if ((current->blocked & (1<<(sig-1))) || + ((int) current->sigaction[sig-1].sa_handler == 1)) + return -EIO; /* Our signal will be ignored */ + else if (current->sigaction[sig-1].sa_handler) + return -EINTR; /* We _will_ be interrupted :-) */ + else + return -ERESTARTSYS; /* We _will_ be interrupted :-) */ + /* (but restart after we continue) */ +} + +int tty_read(unsigned channel, char * buf, int nr, unsigned short flags) +{ + struct tty_struct * tty; + struct tty_struct * other_tty = NULL; + unsigned char c; + char * b=buf; + int minimum,time; + + if (channel > 255) + return -EIO; + tty = TTY_TABLE(channel); + if (!(tty->read_q && tty->secondary)) + return -EIO; + if ((current->tty == channel) && (tty->pgrp != current->pgrp)) + return(tty_signal(SIGTTIN, tty)); + if (channel & 0x80) + other_tty = tty_table + (channel ^ 0x40); + time = 10L*tty->termios.c_cc[VTIME]; + minimum = tty->termios.c_cc[VMIN]; + if (L_CANON(tty)) { + minimum = nr; + current->timeout = 0xffffffff; + time = 0; + } else if (minimum) + current->timeout = 0xffffffff; + else { + minimum = nr; + if (time) + current->timeout = time + jiffies; + time = 0; + } + if (flags & O_NONBLOCK) + time = current->timeout = 0; + if (minimum>nr) + minimum = nr; + copy_to_cooked(tty); + while (nr>0) { + if (other_tty && other_tty->write) + other_tty->write(other_tty); + cli(); + if (EMPTY(tty->secondary) || (L_CANON(tty) && + !FULL(tty->read_q) && !tty->secondary->data)) { + if (!current->timeout || + (current->signal & ~current->blocked)) { + sti(); + break; + } + if (IS_A_PTY_SLAVE(channel) && C_HUP(other_tty)) + break; + interruptible_sleep_on(&tty->secondary->proc_list); + sti(); + copy_to_cooked(tty); + continue; + } + sti(); + do { + GETCH(tty->secondary,c); + if ((EOF_CHAR(tty) != _POSIX_VDISABLE && + c==EOF_CHAR(tty)) || c==10) + tty->secondary->data--; + if ((EOF_CHAR(tty) != _POSIX_VDISABLE && + c==EOF_CHAR(tty)) && L_CANON(tty)) + break; + else { + put_fs_byte(c,b++); + if (!--nr) + break; + } + if (c==10 && L_CANON(tty)) + break; + } while (nr>0 && !EMPTY(tty->secondary)); + wake_up(&tty->read_q->proc_list); + if (time) + current->timeout = time+jiffies; + if (L_CANON(tty) || b-buf >= minimum) + break; + } + current->timeout = 0; + if (b-buf) + return b-buf; + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + if (flags & O_NONBLOCK) + return -EAGAIN; + return 0; +} + +int tty_write(unsigned channel, char * buf, int nr) +{ + static cr_flag=0; + struct tty_struct * tty; + char c, *b=buf; + + if (channel > 255) + return -EIO; + tty = TTY_TABLE(channel); + if (!(tty->write_q && tty->write)) + return -EIO; + if (L_TOSTOP(tty) && + (current->tty == channel) && (tty->pgrp != current->pgrp)) + return(tty_signal(SIGTTOU, tty)); + while (nr>0) { + sleep_if_full(tty->write_q); + if (current->signal & ~current->blocked) + 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); +} + +void chr_dev_init(void) +{ +} + +void tty_init(void) +{ + int i; + + for (i=0 ; i < QUEUES ; i++) + tty_queues[i] = (struct tty_queue) {0,0,0,0,""}; + rs_queues[0] = (struct tty_queue) {0x3f8,0,0,0,""}; + rs_queues[1] = (struct tty_queue) {0x3f8,0,0,0,""}; + rs_queues[3] = (struct tty_queue) {0x2f8,0,0,0,""}; + rs_queues[4] = (struct tty_queue) {0x2f8,0,0,0,""}; + for (i=0 ; i<256 ; i++) { + tty_table[i] = (struct tty_struct) { + {0, 0, 0, 0, 0, INIT_C_CC}, + 0, 0, 0, {0,0,0,0}, + NULL, NULL, NULL, NULL + }; + } + con_init(); + for (i = 0 ; i +#include + +#include +#include +#include + +#include +#include +#include + +extern int session_of_pgrp(int pgrp); +extern int do_screendump(int arg); +extern int kill_pg(int pgrp, int sig, int priv); +extern int tty_signal(int sig, struct tty_struct *tty); + +static unsigned short quotient[] = { + 0, 2304, 1536, 1047, 857, + 768, 576, 384, 192, 96, + 64, 48, 24, 12, 6, 3 +}; + +static void change_speed(struct tty_struct * tty) +{ + unsigned short port,quot; + + if (!(port = tty->read_q->data)) + return; + quot = quotient[tty->termios.c_cflag & CBAUD]; + cli(); + outb_p(0x80,port+3); /* set DLAB */ + outb_p(quot & 0xff,port); /* LS of divisor */ + outb_p(quot >> 8,port+1); /* MS of divisor */ + outb(0x03,port+3); /* reset DLAB */ + sti(); +} + +static void flush(struct tty_queue * queue) +{ + if (queue) { + cli(); + queue->head = queue->tail; + sti(); + wake_up(&queue->proc_list); + } +} + +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 do_get_ps_info(int arg) +{ + struct tstruct { + int flag; + int present[NR_TASKS]; + struct task_struct tasks[NR_TASKS]; + }; + struct tstruct *ts = (struct tstruct *)arg; + struct task_struct **p; + char *c, *d; + int i, n = 0; + + verify_area((void *)arg, sizeof(struct tstruct)); + + for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++) + if (*p) + { + c = (char *)(*p); + d = (char *)(ts->tasks+n); + for (i=0 ; ipresent+n)); + } + else + put_fs_long(0, (unsigned long *)(ts->present+n)); + return(0); +} + +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 channel) +{ + int i, retsig; + + /* If we try to set the state of terminal and we're not in the + foreground, send a SIGTTOU. If the signal is blocked or + ignored, go ahead and perform the operation. POSIX 7.2) */ + if ((current->tty == channel) && (tty->pgrp != current->pgrp)) { + retsig = tty_signal(SIGTTOU, tty); + if (retsig == -ERESTARTSYS || retsig == -EINTR) + return retsig; + } + for (i=0 ; i< (sizeof (*termios)) ; i++) + ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios); + change_speed(tty); + return 0; +} + +static int get_termio(struct tty_struct * tty, struct termio * termio) +{ + int i; + struct termio tmp_termio; + + verify_area(termio, sizeof (*termio)); + tmp_termio.c_iflag = tty->termios.c_iflag; + tmp_termio.c_oflag = tty->termios.c_oflag; + tmp_termio.c_cflag = tty->termios.c_cflag; + tmp_termio.c_lflag = tty->termios.c_lflag; + tmp_termio.c_line = tty->termios.c_line; + for(i=0 ; i < NCC ; i++) + tmp_termio.c_cc[i] = tty->termios.c_cc[i]; + for (i=0 ; i< (sizeof (*termio)) ; i++) + put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio ); + return 0; +} + +/* + * This only works as the 386 is low-byt-first + */ +static int set_termio(struct tty_struct * tty, struct termio * termio, + int channel) +{ + int i, retsig; + struct termio tmp_termio; + + if ((current->tty == channel) && (tty->pgrp != current->pgrp)) { + retsig = tty_signal(SIGTTOU, tty); + if (retsig == -ERESTARTSYS || retsig == -EINTR) + return retsig; + } + for (i=0 ; i< (sizeof (*termio)) ; i++) + ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio); + *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag; + *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag; + *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag; + *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag; + tty->termios.c_line = tmp_termio.c_line; + for(i=0 ; i < NCC ; i++) + tty->termios.c_cc[i] = tmp_termio.c_cc[i]; + change_speed(tty); + return 0; +} + +static int set_window_size(struct tty_struct * tty, struct winsize * ws) +{ + int i,changed; + char c, * tmp; + + if (!ws) + return -EINVAL; + tmp = (char *) &tty->winsize; + changed = 0; + for (i = 0; i < sizeof (*ws) ; i++,tmp++) { + c = get_fs_byte(i + (char *) ws); + if (c == *tmp) + continue; + changed = 1; + *tmp = c; + } + if (changed) + kill_pg(tty->pgrp, SIGWINCH, 1); + return 0; +} + +static int get_window_size(struct tty_struct * tty, struct winsize * ws) +{ + int i; + char * tmp; + + if (!ws) + return -EINVAL; + verify_area(ws, sizeof (*ws)); + tmp = (char *) ws; + for (i = 0; i < sizeof (struct winsize) ; i++,tmp++) + put_fs_byte(((char *) &tty->winsize)[i], tmp); + return 0; +} + +int tty_ioctl(int dev, int cmd, int arg) +{ + struct tty_struct * tty; + struct tty_struct * other_tty; + int pgrp; + + if (MAJOR(dev) == 5) { + dev = current->tty; + if (dev<0) + return -EINVAL; + } else + dev=MINOR(dev); + tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console); + + if (IS_A_PTY(dev)) + other_tty = tty_table + PTY_OTHER(dev); + else + other_tty = NULL; + + if (!(tty->write_q && tty->read_q && tty->secondary && tty->write)) + return -EINVAL; + switch (cmd) { + case TCGETS: + return get_termios(tty,(struct termios *) arg); + case TCSETSF: + flush(tty->read_q); + flush(tty->secondary); + if (other_tty) + flush(other_tty->write_q); + /* fallthrough */ + case TCSETSW: + wait_until_sent(tty); + /* fallthrough */ + case TCSETS: + return set_termios(tty,(struct termios *) arg, dev); + case TCGETA: + return get_termio(tty,(struct termio *) arg); + case TCSETAF: + flush(tty->read_q); + flush(tty->secondary); + if (other_tty) + flush(other_tty->write_q); + /* fallthrough */ + case TCSETAW: + wait_until_sent(tty); /* fallthrough */ + case TCSETA: + return set_termio(tty,(struct termio *) arg, dev); + case TCSBRK: + if (!arg) { + wait_until_sent(tty); + send_break(tty); + } + return 0; + case TCXONC: + switch (arg) { + case TCOOFF: + tty->stopped = 1; + tty->write(tty); + return 0; + case TCOON: + tty->stopped = 0; + tty->write(tty); + return 0; + case TCIOFF: + if (STOP_CHAR(tty)) + PUTCH(STOP_CHAR(tty),tty->write_q); + return 0; + case TCION: + if (START_CHAR(tty)) + PUTCH(START_CHAR(tty),tty->write_q); + return 0; + } + return -EINVAL; /* not implemented */ + case TCFLSH: + if (arg==0) { + flush(tty->read_q); + flush(tty->secondary); + if (other_tty) + flush(other_tty->write_q); + } else if (arg==1) + flush(tty->write_q); + else if (arg==2) { + flush(tty->read_q); + flush(tty->secondary); + flush(tty->write_q); + if (other_tty) + flush(other_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: + if ((current->tty < 0) || + (current->tty != dev) || + (tty->session != current->session)) + return -ENOTTY; + pgrp=get_fs_long((unsigned long *) arg); + if (pgrp < 0) + return -EINVAL; + if (session_of_pgrp(pgrp) != current->session) + return -EPERM; + tty->pgrp = pgrp; + return 0; + case TIOCOUTQ: + verify_area((void *) arg,4); + put_fs_long(CHARS(tty->write_q),(unsigned long *) arg); + return 0; + case TIOCINQ: + verify_area((void *) arg,4); + put_fs_long(CHARS(tty->secondary), + (unsigned long *) arg); + return 0; + case TIOCSTI: + return -EINVAL; /* not implemented */ + case TIOCGWINSZ: + return get_window_size(tty,(struct winsize *) arg); + case TIOCSWINSZ: + if (other_tty) + set_window_size(other_tty,(struct winsize *) arg); + return set_window_size(tty,(struct winsize *) arg); + 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 */ + case TIOCLINUX: + switch (get_fs_byte((char *)arg)) + { + case 0: + return do_screendump(arg); + case 1: + return do_get_ps_info(arg); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} diff --git a/kernel/0.95/linux-0.95/kernel/exit.c b/kernel/0.95/linux-0.95/kernel/exit.c new file mode 100644 index 00000000..e81319a9 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/exit.c @@ -0,0 +1,447 @@ +/* + * linux/kernel/exit.c + * + * (C) 1991 Linus Torvalds + */ + +#define DEBUG_PROC_TREE + +#include +#include +#include + +#include +#include +#include +#include + +int sys_close(int fd); + +inline int send_sig(long sig,struct task_struct * p,int priv) +{ + if (!p || (sig < 0) || (sig > 32)) + return -EINVAL; + if (!priv && (current->euid!=p->euid) && !suser()) + return -EPERM; + if (!sig) + return 0; + if ((sig == SIGKILL) || (sig == SIGCONT)) { + if (p->state == TASK_STOPPED) + p->state = TASK_RUNNING; + p->exit_code = 0; + p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) | + (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) ); + } + /* Depends on order SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU */ + if ((sig >= SIGSTOP) && (sig <= SIGTTOU)) + p->signal &= ~(1<<(SIGCONT-1)); + /* Actually deliver the signal */ + p->signal |= (1<<(sig-1)); + if (p->flags & PF_PTRACED) { + /* save the signal number for wait. */ + p->exit_code = sig; + + /* we have to make sure the parent is awake. */ + if (p->p_pptr != NULL && p->p_pptr->state == TASK_INTERRUPTIBLE) + p->p_pptr->state = TASK_RUNNING; + + /* we have to make sure that the process stops. */ + if (p->state == TASK_INTERRUPTIBLE || p->state == TASK_RUNNING) + p->state = TASK_STOPPED; + + if (p == current) + schedule(); + } + return 0; +} + +void release(struct task_struct * p) +{ + int i; + + if (!p) + return; + if (p == current) { + printk("task releasing itself\n\r"); + return; + } + for (i=1 ; ip_osptr) + p->p_osptr->p_ysptr = p->p_ysptr; + if (p->p_ysptr) + p->p_ysptr->p_osptr = p->p_osptr; + else + p->p_pptr->p_cptr = p->p_osptr; + free_page((long)p); + schedule(); + return; + } + panic("trying to release non-existent task"); +} + +#ifdef DEBUG_PROC_TREE +/* + * Check to see if a task_struct pointer is present in the task[] array + * Return 0 if found, and 1 if not found. + */ +int bad_task_ptr(struct task_struct *p) +{ + int i; + + if (!p) + return 0; + for (i=0 ; ip_pptr)) + printk("Warning, pid %d's parent link is bad\n", + task[i]->pid); + if (bad_task_ptr(task[i]->p_cptr)) + printk("Warning, pid %d's child link is bad\n", + task[i]->pid); + if (bad_task_ptr(task[i]->p_ysptr)) + printk("Warning, pid %d's ys link is bad\n", + task[i]->pid); + if (bad_task_ptr(task[i]->p_osptr)) + printk("Warning, pid %d's os link is bad\n", + task[i]->pid); + if (task[i]->p_pptr == task[i]) + printk("Warning, pid %d parent link points to self\n"); + if (task[i]->p_cptr == task[i]) + printk("Warning, pid %d child link points to self\n"); + if (task[i]->p_ysptr == task[i]) + printk("Warning, pid %d ys link points to self\n"); + if (task[i]->p_osptr == task[i]) + printk("Warning, pid %d os link points to self\n"); + if (task[i]->p_osptr) { + if (task[i]->p_pptr != task[i]->p_osptr->p_pptr) + printk( + "Warning, pid %d older sibling %d parent is %d\n", + task[i]->pid, task[i]->p_osptr->pid, + task[i]->p_osptr->p_pptr->pid); + if (task[i]->p_osptr->p_ysptr != task[i]) + printk( + "Warning, pid %d older sibling %d has mismatched ys link\n", + task[i]->pid, task[i]->p_osptr->pid); + } + if (task[i]->p_ysptr) { + if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr) + printk( + "Warning, pid %d younger sibling %d parent is %d\n", + task[i]->pid, task[i]->p_osptr->pid, + task[i]->p_osptr->p_pptr->pid); + if (task[i]->p_ysptr->p_osptr != task[i]) + printk( + "Warning, pid %d younger sibling %d has mismatched os link\n", + task[i]->pid, task[i]->p_ysptr->pid); + } + if (task[i]->p_cptr) { + if (task[i]->p_cptr->p_pptr != task[i]) + printk( + "Warning, pid %d youngest child %d has mismatched parent link\n", + task[i]->pid, task[i]->p_cptr->pid); + if (task[i]->p_cptr->p_ysptr) + printk( + "Warning, pid %d youngest child %d has non-NULL ys link\n", + task[i]->pid, task[i]->p_cptr->pid); + } + } +} +#endif /* DEBUG_PROC_TREE */ + +int session_of_pgrp(int pgrp) +{ + struct task_struct **p; + + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if ((*p)->pgrp == pgrp) + return((*p)->session); + return -1; +} + +int kill_pg(int pgrp, int sig, int priv) +{ + struct task_struct **p; + int err,retval = -ESRCH; + int found = 0; + + if (sig<0 || sig>32 || pgrp<=0) + return -EINVAL; + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if ((*p)->pgrp == pgrp) { + if (sig && (err = send_sig(sig,*p,priv))) + retval = err; + else + found++; + } + return(found ? 0 : retval); +} + +int kill_proc(int pid, int sig, int priv) +{ + struct task_struct **p; + + if (sig<0 || sig>32) + return -EINVAL; + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if ((*p)->pid == pid) + return(sig ? send_sig(sig,*p,priv) : 0); + return(-ESRCH); +} + +/* + * POSIX specifies that kill(-1,sig) is unspecified, but what we have + * is probably wrong. Should make it like BSD or SYSV. + */ +int sys_kill(int pid,int sig) +{ + struct task_struct **p = NR_TASKS + task; + int err, retval = 0; + + if (!pid) + return(kill_pg(current->pid,sig,0)); + if (pid == -1) { + while (--p > &FIRST_TASK) + if (err = send_sig(sig,*p,0)) + retval = err; + return(retval); + } + if (pid < 0) + return(kill_pg(-pid,sig,0)); + /* Normal kill */ + return(kill_proc(pid,sig,0)); +} + +/* + * Determine if a process group is "orphaned", according to the POSIX + * definition in 2.2.2.52. Orphaned process groups are not to be affected + * by terminal-generated stop signals. Newly orphaned process groups are + * to receive a SIGHUP and a SIGCONT. + * + * "I ask you, have you ever known what it is to be an orphan?" + */ +int is_orphaned_pgrp(int pgrp) +{ + struct task_struct **p; + + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if (!(*p) || + ((*p)->pgrp != pgrp) || + ((*p)->state == TASK_ZOMBIE) || + ((*p)->p_pptr->pid == 1)) + continue; + if (((*p)->p_pptr->pgrp != pgrp) && + ((*p)->p_pptr->session == (*p)->session)) + return 0; + } + return(1); /* (sighing) "Often!" */ +} + +static int has_stopped_jobs(int pgrp) +{ + struct task_struct ** p; + + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if ((*p)->pgrp != pgrp) + continue; + if ((*p)->state == TASK_STOPPED) + return(1); + } + return(0); +} + +volatile void do_exit(long code) +{ + struct task_struct *p; + 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 ; ifilp[i]) + sys_close(i); + iput(current->pwd); + current->pwd = NULL; + iput(current->root); + current->root = NULL; + iput(current->executable); + current->executable = NULL; + iput(current->library); + current->library = NULL; + current->state = TASK_ZOMBIE; + current->exit_code = code; + /* + * Check to see if any process groups have become orphaned + * as a result of our exiting, and if they have any stopped + * jobs, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2) + * + * Case i: Our father is in a different pgrp than we are + * and we were the only connection outside, so our pgrp + * is about to become orphaned. + */ + if ((current->p_pptr->pgrp != current->pgrp) && + (current->p_pptr->session == current->session) && + is_orphaned_pgrp(current->pgrp) && + has_stopped_jobs(current->pgrp)) { + kill_pg(current->pgrp,SIGHUP,1); + kill_pg(current->pgrp,SIGCONT,1); + } + /* Let father know we died */ + send_sig (SIGCHLD, current->p_pptr, 1); + + /* + * This loop does two things: + * + * A. Make init inherit all the child processes + * B. Check to see if any process groups have become orphaned + * as a result of our exiting, and if they have any stopped + * jons, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2) + */ + if (p = current->p_cptr) { + while (1) { + p->flags &= ~PF_PTRACED; + p->p_pptr = task[1]; + if (p->state == TASK_ZOMBIE) + task[1]->signal |= (1<<(SIGCHLD-1)); + /* + * process group orphan check + * Case ii: Our child is in a different pgrp + * than we are, and it was the only connection + * outside, so the child pgrp is now orphaned. + */ + if ((p->pgrp != current->pgrp) && + (p->session == current->session) && + is_orphaned_pgrp(p->pgrp) && + has_stopped_jobs(p->pgrp)) { + kill_pg(p->pgrp,SIGHUP,1); + kill_pg(p->pgrp,SIGCONT,1); + } + if (p->p_osptr) { + p = p->p_osptr; + continue; + } + /* + * This is it; link everything into init's children + * and leave + */ + p->p_osptr = task[1]->p_cptr; + task[1]->p_cptr->p_ysptr = p; + task[1]->p_cptr = current->p_cptr; + current->p_cptr = 0; + break; + } + } + if (current->leader) { + struct task_struct **p; + struct tty_struct *tty; + + if (current->tty >= 0) { + tty = TTY_TABLE(current->tty); + if (tty->pgrp>0) + kill_pg(tty->pgrp, SIGHUP, 1); + tty->pgrp = 0; + tty->session = 0; + } + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if ((*p)->session == current->session) + (*p)->tty = -1; + } + if (last_task_used_math == current) + last_task_used_math = NULL; +#ifdef DEBUG_PROC_TREE + audit_ptree(); +#endif + schedule(); +} + +int sys_exit(int error_code) +{ + do_exit((error_code&0xff)<<8); +} + +int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options) +{ + int flag; + struct task_struct *p; + unsigned long oldblocked; + + if (stat_addr) + verify_area(stat_addr,4); +repeat: + flag=0; + for (p = current->p_cptr ; p ; p = p->p_osptr) { + if (pid>0) { + if (p->pid != pid) + continue; + } else if (!pid) { + if (p->pgrp != current->pgrp) + continue; + } else if (pid != -1) { + if (p->pgrp != -pid) + continue; + } + switch (p->state) { + case TASK_STOPPED: + if (!(options & WUNTRACED) || + !p->exit_code) + continue; + if (stat_addr) + put_fs_long((p->exit_code << 8) | 0x7f, + stat_addr); + p->exit_code = 0; + return p->pid; + case TASK_ZOMBIE: + current->cutime += p->utime; + current->cstime += p->stime; + flag = p->pid; + if (stat_addr) + put_fs_long(p->exit_code, stat_addr); + release(p); +#ifdef DEBUG_PROC_TREE + audit_ptree(); +#endif + return flag; + default: + flag=1; + continue; + } + } + if (flag) { + if (options & WNOHANG) + return 0; + current->state=TASK_INTERRUPTIBLE; + oldblocked = current->blocked; + current->blocked &= ~(1<<(SIGCHLD-1)); + schedule(); + current->blocked = oldblocked; + if (current->signal & ~(current->blocked | (1<<(SIGCHLD-1)))) + return -ERESTARTSYS; + else + goto repeat; + } + return -ECHILD; +} + + diff --git a/kernel/0.95/linux-0.95/kernel/fork.c b/kernel/0.95/linux-0.95/kernel/fork.c new file mode 100644 index 00000000..e3e1e67d --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/fork.c @@ -0,0 +1,166 @@ +/* + * linux/kernel/fork.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'fork.c' contains the help-routines for the 'fork' system call + * (see also system_call.s), and some misc functions ('verify_area'). + * Fork is rather simple, once you get the hang of it, but the memory + * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()' + */ +#include + +#include +#include +#include +#include + +extern void write_verify(unsigned long address); + +long last_pid=0; + +void verify_area(void * addr,int size) +{ + unsigned long start; + + start = (unsigned long) addr; + size += start & 0xfff; + start &= 0xfffff000; + start += get_base(current->ldt[2]); + while (size>0) { + size -= 4096; + write_verify(start); + start += 4096; + } +} + +int copy_mem(int nr,struct task_struct * p) +{ + unsigned long old_data_base,new_data_base,data_limit; + unsigned long old_code_base,new_code_base,code_limit; + + code_limit=get_limit(0x0f); + data_limit=get_limit(0x17); + old_code_base = get_base(current->ldt[1]); + old_data_base = get_base(current->ldt[2]); + if (old_data_base != old_code_base) { + printk("ldt[0]: %08x %08x\n",current->ldt[0].a,current->ldt[0].b); + printk("ldt[1]: %08x %08x\n",current->ldt[1].a,current->ldt[1].b); + printk("ldt[2]: %08x %08x\n",current->ldt[2].a,current->ldt[2].b); + panic("We don't support separate I&D"); + } + if (data_limit < code_limit) + panic("Bad data_limit"); + new_data_base = new_code_base = nr * TASK_SIZE; + p->start_code = new_code_base; + set_base(p->ldt[1],new_code_base); + set_base(p->ldt[2],new_data_base); + if (copy_page_tables(old_data_base,new_data_base,data_limit)) { + free_page_tables(new_data_base,data_limit); + return -ENOMEM; + } + return 0; +} + +static int find_empty_process(void) +{ + int i; + + repeat: + if ((++last_pid)<0) last_pid=1; + for(i=0 ; ipid == last_pid) || + (task[i]->pgrp == last_pid))) + goto repeat; + for(i=1 ; istate = TASK_UNINTERRUPTIBLE; + p->pid = last_pid; + p->counter = p->priority; + p->signal = 0; + p->alarm = 0; + p->leader = 0; /* process leadership doesn't inherit */ + p->utime = p->stime = 0; + p->cutime = p->cstime = 0; + p->start_time = jiffies; + p->tss.back_link = 0; + p->tss.esp0 = PAGE_SIZE + (long) p; + p->tss.ss0 = 0x10; + p->tss.eip = eip; + p->tss.eflags = eflags; + p->tss.eax = 0; + p->tss.ecx = ecx; + p->tss.edx = edx; + p->tss.ebx = ebx; + p->tss.esp = esp; + p->tss.ebp = ebp; + p->tss.esi = esi; + p->tss.edi = edi; + p->tss.es = es & 0xffff; + p->tss.cs = cs & 0xffff; + p->tss.ss = ss & 0xffff; + p->tss.ds = ds & 0xffff; + p->tss.fs = fs & 0xffff; + p->tss.gs = gs & 0xffff; + p->tss.ldt = _LDT(nr); + p->tss.trace_bitmap = 0x80000000; + if (last_task_used_math == current) + __asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387)); + if (copy_mem(nr,p)) { + task[nr] = NULL; + free_page((long) p); + return -EAGAIN; + } + for (i=0; ifilp[i]) + f->f_count++; + if (current->pwd) + current->pwd->i_count++; + if (current->root) + current->root->i_count++; + if (current->executable) + current->executable->i_count++; + if (current->library) + current->library->i_count++; + set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss)); + set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt)); + p->p_pptr = current; + p->p_cptr = 0; + p->p_ysptr = 0; + p->p_osptr = current->p_cptr; + if (p->p_osptr) + p->p_osptr->p_ysptr = p; + current->p_cptr = p; + p->state = TASK_RUNNING; /* do this last, just in case */ + return p->pid; +} diff --git a/kernel/0.95/linux-0.95/kernel/math/Makefile b/kernel/0.95/linux-0.95/kernel/math/Makefile new file mode 100644 index 00000000..d136ef5d --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/math/Makefile @@ -0,0 +1,92 @@ +# +# Makefile for the kernel math emulation routines +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +AR =ar +AS =as +LD =ld +LDFLAGS =-s -x +CC =gcc +CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ + -finline-functions -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 = math_emulate.o error.o convert.o ea.o get_put.o \ + add.o mul.o div.o compare.o + +math.a: $(OBJS) + $(AR) rcs math.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: +add.s add.o : add.c ../../include/linux/math_emu.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/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h +compare.s compare.o : compare.c ../../include/linux/math_emu.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/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h +convert.s convert.o : convert.c ../../include/linux/math_emu.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/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h +div.s div.o : div.c ../../include/linux/math_emu.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/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h +ea.s ea.o : ea.c ../../include/stddef.h ../../include/linux/math_emu.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/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/asm/segment.h +error.s error.o : error.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/linux/kernel.h ../../include/sys/param.h \ + ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h +get_put.s get_put.o : get_put.c ../../include/signal.h ../../include/sys/types.h \ + ../../include/linux/math_emu.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/linux/mm.h ../../include/linux/kernel.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/asm/segment.h +math_emulate.s math_emulate.o : math_emulate.c ../../include/linux/config.h +mul.s mul.o : mul.c ../../include/linux/math_emu.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/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h diff --git a/kernel/0.95/linux-0.95/kernel/math/add.c b/kernel/0.95/linux-0.95/kernel/math/add.c new file mode 100644 index 00000000..5cf84ef6 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/math/add.c @@ -0,0 +1,92 @@ +/* + * linux/kernel/math/add.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * temporary real addition routine. + * + * NOTE! These aren't exact: they are only 62 bits wide, and don't do + * correct rounding. Fast hack. The reason is that we shift right the + * values by two, in order not to have overflow (1 bit), and to be able + * to move the sign into the mantissa (1 bit). Much simpler algorithms, + * and 62 bits (61 really - no rounding) accuracy is usually enough. The + * only time you should notice anything weird is when adding 64-bit + * integers together. When using doubles (52 bits accuracy), the + * 61-bit accuracy never shows at all. + */ + +#include + +#define NEGINT(a) \ +__asm__("notl %0 ; notl %1 ; addl $1,%0 ; adcl $0,%1" \ + :"=r" (a->a),"=r" (a->b) \ + :"0" (a->a),"1" (a->b)) + +static void signify(temp_real * a) +{ + a->exponent += 2; + __asm__("shrdl $2,%1,%0 ; shrl $2,%1" + :"=r" (a->a),"=r" (a->b) + :"0" (a->a),"1" (a->b)); + if (a->exponent < 0) + NEGINT(a); + a->exponent &= 0x7fff; +} + +static void unsignify(temp_real * a) +{ + if (!(a->a || a->b)) { + a->exponent = 0; + return; + } + a->exponent &= 0x7fff; + if (a->b < 0) { + NEGINT(a); + a->exponent |= 0x8000; + } + while (a->b >= 0) { + a->exponent--; + __asm__("addl %0,%0 ; adcl %1,%1" + :"=r" (a->a),"=r" (a->b) + :"0" (a->a),"1" (a->b)); + } +} + +void fadd(const temp_real * src1, const temp_real * src2, temp_real * result) +{ + temp_real a,b; + int x1,x2,shift; + + x1 = src1->exponent & 0x7fff; + x2 = src2->exponent & 0x7fff; + if (x1 > x2) { + a = *src1; + b = *src2; + shift = x1-x2; + } else { + a = *src2; + b = *src1; + shift = x2-x1; + } + if (shift >= 64) { + *result = a; + return; + } + if (shift >= 32) { + b.a = b.b; + b.b = 0; + shift -= 32; + } + __asm__("shrdl %4,%1,%0 ; shrl %4,%1" + :"=r" (b.a),"=r" (b.b) + :"0" (b.a),"1" (b.b),"c" ((char) shift)); + signify(&a); + signify(&b); + __asm__("addl %4,%0 ; adcl %5,%1" + :"=r" (a.a),"=r" (a.b) + :"0" (a.a),"1" (a.b),"g" (b.a),"g" (b.b)); + unsignify(&a); + *result = a; +} diff --git a/kernel/0.95/linux-0.95/kernel/math/compare.c b/kernel/0.95/linux-0.95/kernel/math/compare.c new file mode 100644 index 00000000..4f1dfac0 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/math/compare.c @@ -0,0 +1,60 @@ +/* + * linux/kernel/math/compare.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * temporary real comparison routines + */ + +#include + +#define clear_Cx() (I387.swd &= ~0x4500) + +static void normalize(temp_real * a) +{ + int i = a->exponent & 0x7fff; + int sign = a->exponent & 0x8000; + + if (!(a->a || a->b)) { + a->exponent = 0; + return; + } + while (i && a->b >= 0) { + i--; + __asm__("addl %0,%0 ; adcl %1,%1" + :"=r" (a->a),"=r" (a->b) + :"0" (a->a),"1" (a->b)); + } + a->exponent = i | sign; +} + +void ftst(const temp_real * a) +{ + temp_real b; + + clear_Cx(); + b = *a; + normalize(&b); + if (b.a || b.b || b.exponent) { + if (b.exponent < 0) + set_C0(); + } else + set_C3(); +} + +void fcom(const temp_real * src1, const temp_real * src2) +{ + temp_real a; + + a = *src1; + a.exponent ^= 0x8000; + fadd(&a,src2,&a); + ftst(&a); +} + +void fucom(const temp_real * src1, const temp_real * src2) +{ + fcom(src1,src2); +} diff --git a/kernel/0.95/linux-0.95/kernel/math/convert.c b/kernel/0.95/linux-0.95/kernel/math/convert.c new file mode 100644 index 00000000..e9383242 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/math/convert.c @@ -0,0 +1,254 @@ +/* + * linux/kernel/math/convert.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +/* + * NOTE!!! There is some "non-obvious" optimisations in the temp_to_long + * and temp_to_short conversion routines: don't touch them if you don't + * know what's going on. They are the adding of one in the rounding: the + * overflow bit is also used for adding one into the exponent. Thus it + * looks like the overflow would be incorrectly handled, but due to the + * way the IEEE numbers work, things are correct. + * + * There is no checking for total overflow in the conversions, though (ie + * if the temp-real number simply won't fit in a short- or long-real.) + */ + +void short_to_temp(const short_real * a, temp_real * b) +{ + if (!(*a & 0x7fffffff)) { + b->a = b->b = 0; + if (*a) + b->exponent = 0x8000; + else + b->exponent = 0; + return; + } + b->exponent = ((*a>>23) & 0xff)-127+16383; + if (*a<0) + b->exponent |= 0x8000; + b->b = (*a<<8) | 0x80000000; + b->a = 0; +} + +void long_to_temp(const long_real * a, temp_real * b) +{ + if (!a->a && !(a->b & 0x7fffffff)) { + b->a = b->b = 0; + if (a->b) + b->exponent = 0x8000; + else + b->exponent = 0; + return; + } + b->exponent = ((a->b >> 20) & 0x7ff)-1023+16383; + if (a->b<0) + b->exponent |= 0x8000; + b->b = 0x80000000 | (a->b<<11) | (((unsigned long)a->a)>>21); + b->a = a->a<<11; +} + +void temp_to_short(const temp_real * a, short_real * b) +{ + if (!(a->exponent & 0x7fff)) { + *b = (a->exponent)?0x80000000:0; + return; + } + *b = ((((long) a->exponent)-16383+127) << 23) & 0x7f800000; + if (a->exponent < 0) + *b |= 0x80000000; + *b |= (a->b >> 8) & 0x007fffff; + switch (ROUNDING) { + case ROUND_NEAREST: + if ((a->b & 0xff) > 0x80) + ++*b; + break; + case ROUND_DOWN: + if ((a->exponent & 0x8000) && (a->b & 0xff)) + ++*b; + break; + case ROUND_UP: + if (!(a->exponent & 0x8000) && (a->b & 0xff)) + ++*b; + break; + } +} + +void temp_to_long(const temp_real * a, long_real * b) +{ + if (!(a->exponent & 0x7fff)) { + b->a = 0; + b->b = (a->exponent)?0x80000000:0; + return; + } + b->b = (((0x7fff & (long) a->exponent)-16383+1023) << 20) & 0x7ff00000; + if (a->exponent < 0) + b->b |= 0x80000000; + b->b |= (a->b >> 11) & 0x000fffff; + b->a = a->b << 21; + b->a |= (a->a >> 11) & 0x001fffff; + switch (ROUNDING) { + case ROUND_NEAREST: + if ((a->a & 0x7ff) > 0x400) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + case ROUND_DOWN: + if ((a->exponent & 0x8000) && (a->b & 0xff)) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + case ROUND_UP: + if (!(a->exponent & 0x8000) && (a->b & 0xff)) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + } +} + +void frndint(const temp_real * a, temp_real * b) +{ + int shift = 16383 + 63 - (a->exponent & 0x7fff); + unsigned long underflow; + + if ((shift < 0) || (shift == 16383+63)) { + *b = *a; + return; + } + b->a = b->b = underflow = 0; + b->exponent = a->exponent; + if (shift < 32) { + b->b = a->b; b->a = a->a; + } else if (shift < 64) { + b->a = a->b; underflow = a->a; + shift -= 32; + b->exponent += 32; + } else if (shift < 96) { + underflow = a->b; + shift -= 64; + b->exponent += 64; + } else { + underflow = 1; + shift = 0; + } + b->exponent += shift; + __asm__("shrdl %2,%1,%0" + :"=r" (underflow),"=r" (b->a) + :"c" ((char) shift),"0" (underflow),"1" (b->a)); + __asm__("shrdl %2,%1,%0" + :"=r" (b->a),"=r" (b->b) + :"c" ((char) shift),"0" (b->a),"1" (b->b)); + __asm__("shrl %1,%0" + :"=r" (b->b) + :"c" ((char) shift),"0" (b->b)); + switch (ROUNDING) { + case ROUND_NEAREST: + __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b) + ,"r" (0x7fffffff + (b->a & 1)) + ,"m" (*&underflow)); + break; + case ROUND_UP: + if ((b->exponent >= 0) && underflow) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + case ROUND_DOWN: + if ((b->exponent < 0) && underflow) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + } + if (b->a || b->b) + while (b->b >= 0) { + b->exponent--; + __asm__("addl %0,%0 ; adcl %1,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + } + else + b->exponent = 0; +} + +void real_to_int(const temp_real * a, temp_int * b) +{ + int shift = 16383 + 63 - (a->exponent & 0x7fff); + unsigned long underflow; + + b->a = b->b = underflow = 0; + b->sign = (a->exponent < 0); + if (shift < 0) { + set_OE(); + return; + } + if (shift < 32) { + b->b = a->b; b->a = a->a; + } else if (shift < 64) { + b->a = a->b; underflow = a->a; + shift -= 32; + } else if (shift < 96) { + underflow = a->b; + shift -= 64; + } else { + underflow = 1; + shift = 0; + } + __asm__("shrdl %2,%1,%0" + :"=r" (underflow),"=r" (b->a) + :"c" ((char) shift),"0" (underflow),"1" (b->a)); + __asm__("shrdl %2,%1,%0" + :"=r" (b->a),"=r" (b->b) + :"c" ((char) shift),"0" (b->a),"1" (b->b)); + __asm__("shrl %1,%0" + :"=r" (b->b) + :"c" ((char) shift),"0" (b->b)); + switch (ROUNDING) { + case ROUND_NEAREST: + __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b) + ,"r" (0x7fffffff + (b->a & 1)) + ,"m" (*&underflow)); + break; + case ROUND_UP: + if (!b->sign && underflow) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + case ROUND_DOWN: + if (b->sign && underflow) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + } +} + +void int_to_real(const temp_int * a, temp_real * b) +{ + b->a = a->a; + b->b = a->b; + if (b->a || b->b) + b->exponent = 16383 + 63 + (a->sign? 0x8000:0); + else { + b->exponent = 0; + return; + } + while (b->b >= 0) { + b->exponent--; + __asm__("addl %0,%0 ; adcl %1,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + } +} diff --git a/kernel/0.95/linux-0.95/kernel/math/div.c b/kernel/0.95/linux-0.95/kernel/math/div.c new file mode 100644 index 00000000..e485fd97 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/math/div.c @@ -0,0 +1,109 @@ +/* + * linux/kernel/math/div.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * temporary real division routine. + */ + +#include + +static void shift_left(int * c) +{ + __asm__ __volatile__("movl (%0),%%eax ; addl %%eax,(%0)\n\t" + "movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t" + "movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t" + "movl 12(%0),%%eax ; adcl %%eax,12(%0)" + ::"r" ((long) c):"ax"); +} + +static void shift_right(int * c) +{ + __asm__("shrl $1,12(%0) ; rcrl $1,8(%0) ; rcrl $1,4(%0) ; rcrl $1,(%0)" + ::"r" ((long) c)); +} + +static int try_sub(int * a, int * b) +{ + char ok; + + __asm__ __volatile__("movl (%1),%%eax ; subl %%eax,(%2)\n\t" + "movl 4(%1),%%eax ; sbbl %%eax,4(%2)\n\t" + "movl 8(%1),%%eax ; sbbl %%eax,8(%2)\n\t" + "movl 12(%1),%%eax ; sbbl %%eax,12(%2)\n\t" + "setae %%al":"=a" (ok):"c" ((long) a),"d" ((long) b)); + return ok; +} + +static void div64(int * a, int * b, int * c) +{ + int tmp[4]; + int i; + unsigned int mask = 0; + + c += 4; + for (i = 0 ; i<64 ; i++) { + if (!(mask >>= 1)) { + c--; + mask = 0x80000000; + } + tmp[0] = a[0]; tmp[1] = a[1]; + tmp[2] = a[2]; tmp[3] = a[3]; + if (try_sub(b,tmp)) { + *c |= mask; + a[0] = tmp[0]; a[1] = tmp[1]; + a[2] = tmp[2]; a[3] = tmp[3]; + } + shift_right(b); + } +} + +void fdiv(const temp_real * src1, const temp_real * src2, temp_real * result) +{ + int i,sign; + int a[4],b[4],tmp[4] = {0,0,0,0}; + + sign = (src1->exponent ^ src2->exponent) & 0x8000; + if (!(src2->a || src2->b)) { + set_ZE(); + return; + } + i = (src1->exponent & 0x7fff) - (src2->exponent & 0x7fff) + 16383; + if (i<0) { + set_UE(); + result->exponent = sign; + result->a = result->b = 0; + return; + } + a[0] = a[1] = 0; + a[2] = src1->a; + a[3] = src1->b; + b[0] = b[1] = 0; + b[2] = src2->a; + b[3] = src2->b; + while (b[3] >= 0) { + i++; + shift_left(b); + } + div64(a,b,tmp); + if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) { + while (i && tmp[3] >= 0) { + i--; + shift_left(tmp); + } + if (tmp[3] >= 0) + set_DE(); + } else + i = 0; + if (i>0x7fff) { + set_OE(); + return; + } + if (tmp[0] || tmp[1]) + set_PE(); + result->exponent = i | sign; + result->a = tmp[2]; + result->b = tmp[3]; +} diff --git a/kernel/0.95/linux-0.95/kernel/math/ea.c b/kernel/0.95/linux-0.95/kernel/math/ea.c new file mode 100644 index 00000000..85a1131c --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/math/ea.c @@ -0,0 +1,92 @@ +/* + * linux/kernel/math/ea.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * Calculate the effective address. + */ + +#include + +#include +#include + +static int __regoffset[] = { + offsetof(struct info,___eax), + offsetof(struct info,___ecx), + offsetof(struct info,___edx), + offsetof(struct info,___ebx), + offsetof(struct info,___esp), + offsetof(struct info,___ebp), + offsetof(struct info,___esi), + offsetof(struct info,___edi) +}; + +#define REG(x) (*(long *)(__regoffset[(x)]+(char *) info)) + +static char * sib(struct info * info, int mod) +{ + unsigned char ss,index,base; + long offset = 0; + + base = get_fs_byte((char *) EIP); + EIP++; + ss = base >> 6; + index = (base >> 3) & 7; + base &= 7; + if (index == 4) + offset = 0; + else + offset = REG(index); + offset <<= ss; + if (mod || base != 5) + offset += REG(base); + if (mod == 1) { + offset += (signed char) get_fs_byte((char *) EIP); + EIP++; + } else if (mod == 2 || base == 5) { + offset += (signed) get_fs_long((unsigned long *) EIP); + EIP += 4; + } + I387.foo = offset; + I387.fos = 0x17; + return (char *) offset; +} + +char * ea(struct info * info, unsigned short code) +{ + unsigned char mod,rm; + long * tmp = &EAX; + int offset = 0; + + mod = (code >> 6) & 3; + rm = code & 7; + if (rm == 4 && mod != 3) + return sib(info,mod); + if (rm == 5 && !mod) { + offset = get_fs_long((unsigned long *) EIP); + EIP += 4; + I387.foo = offset; + I387.fos = 0x17; + return (char *) offset; + } + tmp = & REG(rm); + switch (mod) { + case 0: offset = 0; break; + case 1: + offset = (signed char) get_fs_byte((char *) EIP); + EIP++; + break; + case 2: + offset = (signed) get_fs_long((unsigned long *) EIP); + EIP += 4; + break; + case 3: + math_abort(info,1<<(SIGILL-1)); + } + I387.foo = offset; + I387.fos = 0x17; + return offset + (char *) *tmp; +} diff --git a/kernel/0.95/linux-0.95/kernel/math/error.c b/kernel/0.95/linux-0.95/kernel/math/error.c new file mode 100644 index 00000000..5f1c1c2c --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/math/error.c @@ -0,0 +1,16 @@ +/* + * linux/kernel/math/error.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include + +void math_error(void) +{ + if (last_task_used_math) + last_task_used_math->signal |= 1<<(SIGFPE-1); + __asm__("fnclex"); +} diff --git a/kernel/0.95/linux-0.95/kernel/math/get_put.c b/kernel/0.95/linux-0.95/kernel/math/get_put.c new file mode 100644 index 00000000..39063fee --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/math/get_put.c @@ -0,0 +1,240 @@ +/* + * linux/kernel/math/get_put.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This file handles all accesses to user memory: getting and putting + * ints/reals/BCD etc. This is the only part that concerns itself with + * other than temporary real format. All other cals are strictly temp_real. + */ +#include + +#include +#include +#include + +void get_short_real(temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + short_real sr; + + addr = ea(info,code); + sr = get_fs_long((unsigned long *) addr); + short_to_temp(&sr,tmp); +} + +void get_long_real(temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + long_real lr; + + addr = ea(info,code); + lr.a = get_fs_long((unsigned long *) addr); + lr.b = get_fs_long(1 + (unsigned long *) addr); + long_to_temp(&lr,tmp); +} + +void get_temp_real(temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + + addr = ea(info,code); + tmp->a = get_fs_long((unsigned long *) addr); + tmp->b = get_fs_long(1 + (unsigned long *) addr); + tmp->exponent = get_fs_word(4 + (unsigned short *) addr); +} + +void get_short_int(temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + ti.a = (signed short) get_fs_word((unsigned short *) addr); + ti.b = 0; + if (ti.sign = (ti.a < 0)) + ti.a = - ti.a; + int_to_real(&ti,tmp); +} + +void get_long_int(temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + ti.a = get_fs_long((unsigned long *) addr); + ti.b = 0; + if (ti.sign = (ti.a < 0)) + ti.a = - ti.a; + int_to_real(&ti,tmp); +} + +void get_longlong_int(temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + ti.a = get_fs_long((unsigned long *) addr); + ti.b = get_fs_long(1 + (unsigned long *) addr); + if (ti.sign = (ti.b < 0)) + __asm__("notl %0 ; notl %1\n\t" + "addl $1,%0 ; adcl $0,%1" + :"=r" (ti.a),"=r" (ti.b) + :"0" (ti.a),"1" (ti.b)); + int_to_real(&ti,tmp); +} + +#define MUL10(low,high) \ +__asm__("addl %0,%0 ; adcl %1,%1\n\t" \ +"movl %0,%%ecx ; movl %1,%%ebx\n\t" \ +"addl %0,%0 ; adcl %1,%1\n\t" \ +"addl %0,%0 ; adcl %1,%1\n\t" \ +"addl %%ecx,%0 ; adcl %%ebx,%1" \ +:"=a" (low),"=d" (high) \ +:"0" (low),"1" (high):"cx","bx") + +#define ADD64(val,low,high) \ +__asm__("addl %4,%0 ; adcl $0,%1":"=r" (low),"=r" (high) \ +:"0" (low),"1" (high),"r" ((unsigned long) (val))) + +void get_BCD(temp_real * tmp, struct info * info, unsigned short code) +{ + int k; + char * addr; + temp_int i; + unsigned char c; + + addr = ea(info,code); + addr += 9; + i.sign = 0x80 & get_fs_byte(addr--); + i.a = i.b = 0; + for (k = 0; k < 9; k++) { + c = get_fs_byte(addr--); + MUL10(i.a, i.b); + ADD64((c>>4), i.a, i.b); + MUL10(i.a, i.b); + ADD64((c&0xf), i.a, i.b); + } + int_to_real(&i,tmp); +} + +void put_short_real(const temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + short_real sr; + + addr = ea(info,code); + verify_area(addr,4); + temp_to_short(tmp,&sr); + put_fs_long(sr,(unsigned long *) addr); +} + +void put_long_real(const temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + long_real lr; + + addr = ea(info,code); + verify_area(addr,8); + temp_to_long(tmp,&lr); + put_fs_long(lr.a, (unsigned long *) addr); + put_fs_long(lr.b, 1 + (unsigned long *) addr); +} + +void put_temp_real(const temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + + addr = ea(info,code); + verify_area(addr,10); + put_fs_long(tmp->a, (unsigned long *) addr); + put_fs_long(tmp->b, 1 + (unsigned long *) addr); + put_fs_word(tmp->exponent, 4 + (short *) addr); +} + +void put_short_int(const temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + real_to_int(tmp,&ti); + verify_area(addr,2); + if (ti.sign) + ti.a = -ti.a; + put_fs_word(ti.a,(short *) addr); +} + +void put_long_int(const temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + real_to_int(tmp,&ti); + verify_area(addr,4); + if (ti.sign) + ti.a = -ti.a; + put_fs_long(ti.a,(unsigned long *) addr); +} + +void put_longlong_int(const temp_real * tmp, + struct info * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + real_to_int(tmp,&ti); + verify_area(addr,8); + if (ti.sign) + __asm__("notl %0 ; notl %1\n\t" + "addl $1,%0 ; adcl $0,%1" + :"=r" (ti.a),"=r" (ti.b) + :"0" (ti.a),"1" (ti.b)); + put_fs_long(ti.a,(unsigned long *) addr); + put_fs_long(ti.b,1 + (unsigned long *) addr); +} + +#define DIV10(low,high,rem) \ +__asm__("divl %6 ; xchgl %1,%2 ; divl %6" \ + :"=d" (rem),"=a" (low),"=r" (high) \ + :"0" (0),"1" (high),"2" (low),"c" (10)) + +void put_BCD(const temp_real * tmp,struct info * info, unsigned short code) +{ + int k,rem; + char * addr; + temp_int i; + unsigned char c; + + addr = ea(info,code); + verify_area(addr,10); + real_to_int(tmp,&i); + if (i.sign) + put_fs_byte(0x80, addr+9); + else + put_fs_byte(0, addr+9); + for (k = 0; k < 9; k++) { + DIV10(i.a,i.b,rem); + c = rem; + DIV10(i.a,i.b,rem); + c += rem<<4; + put_fs_byte(c,addr++); + } +} diff --git a/kernel/0.95/linux-0.95/kernel/math/math_emulate.c b/kernel/0.95/linux-0.95/kernel/math/math_emulate.c new file mode 100644 index 00000000..6fb6e6f0 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/math/math_emulate.c @@ -0,0 +1,549 @@ +/* + * linux/kernel/math/math_emulate.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * Limited emulation 27.12.91 - mostly loads/stores, which gcc wants + * even for soft-float, unless you use bruce evans' patches. The patches + * are great, but they have to be re-applied for every version, and the + * library is different for soft-float and 80387. So emulation is more + * practical, even though it's slower. + * + * 28.12.91 - loads/stores work, even BCD. I'll have to start thinking + * about add/sub/mul/div. Urgel. I should find some good source, but I'll + * just fake up something. + * + * 30.12.91 - add/sub/mul/div/com seem to work mostly. I should really + * test every possible combination. + */ + +/* + * This file is full of ugly macros etc: one problem was that gcc simply + * didn't want to make the structures as they should be: it has to try to + * align them. Sickening code, but at least I've hidden the ugly things + * in this one file: the other files don't need to know about these things. + * + * The other files also don't care about ST(x) etc - they just get addresses + * to 80-bit temporary reals, and do with them as they please. I wanted to + * hide most of the 387-specific things here. + */ + +#include + +#ifdef KERNEL_MATH_EMULATION + +#include + +#define __ALIGNED_TEMP_REAL 1 +#include +#include +#include + +#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x)) +#define ST(x) (*__st((x))) +#define PST(x) ((const temp_real *) __st((x))) + +/* + * We don't want these inlined - it gets too messy in the machine-code. + */ +static void fpop(void); +static void fpush(void); +static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b); +static temp_real_unaligned * __st(int i); + +static void do_emu(struct info * info) +{ + unsigned short code; + temp_real tmp; + char * address; + + if (I387.cwd & I387.swd & 0x3f) + I387.swd |= 0x8000; + else + I387.swd &= 0x7fff; + ORIG_EIP = EIP; +/* 0x0007 means user code space */ + if (CS != 0x000F) { + printk("math_emulate: %04x:%08x\n\r",CS,EIP); + panic("Math emulation needed in kernel"); + } + code = get_fs_word((unsigned short *) EIP); + bswapw(code); + code &= 0x7ff; + I387.fip = EIP; + *(unsigned short *) &I387.fcs = CS; + *(1+(unsigned short *) &I387.fcs) = code; + EIP += 2; + switch (code) { + case 0x1d0: /* fnop */ + return; + case 0x1d1: case 0x1d2: case 0x1d3: + case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7: + math_abort(info,1<<(SIGILL-1)); + case 0x1e0: + ST(0).exponent ^= 0x8000; + return; + case 0x1e1: + ST(0).exponent &= 0x7fff; + return; + case 0x1e2: case 0x1e3: + math_abort(info,1<<(SIGILL-1)); + case 0x1e4: + ftst(PST(0)); + return; + case 0x1e5: + printk("fxam not implemented\n\r"); + math_abort(info,1<<(SIGILL-1)); + case 0x1e6: case 0x1e7: + math_abort(info,1<<(SIGILL-1)); + case 0x1e8: + fpush(); + ST(0) = CONST1; + return; + case 0x1e9: + fpush(); + ST(0) = CONSTL2T; + return; + case 0x1ea: + fpush(); + ST(0) = CONSTL2E; + return; + case 0x1eb: + fpush(); + ST(0) = CONSTPI; + return; + case 0x1ec: + fpush(); + ST(0) = CONSTLG2; + return; + case 0x1ed: + fpush(); + ST(0) = CONSTLN2; + return; + case 0x1ee: + fpush(); + ST(0) = CONSTZ; + return; + case 0x1ef: + math_abort(info,1<<(SIGILL-1)); + case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3: + case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7: + case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb: + case 0x1fd: case 0x1fe: case 0x1ff: + printk("%04x fxxx not implemented\n\r",code + 0xd800); + math_abort(info,1<<(SIGILL-1)); + case 0x1fc: + frndint(PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x2e9: + fucom(PST(1),PST(0)); + fpop(); fpop(); + return; + case 0x3d0: case 0x3d1: + return; + case 0x3e2: + I387.swd &= 0x7f00; + return; + case 0x3e3: + I387.cwd = 0x037f; + I387.swd = 0x0000; + I387.twd = 0x0000; + return; + case 0x3e4: + return; + case 0x6d9: + fcom(PST(1),PST(0)); + fpop(); fpop(); + return; + case 0x7e0: + *(short *) &EAX = I387.swd; + return; + } + switch (code >> 3) { + case 0x18: + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x19: + fmul(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x1a: + fcom(PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x1b: + fcom(PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + fpop(); + return; + case 0x1c: + real_to_real(&ST(code & 7),&tmp); + tmp.exponent ^= 0x8000; + fadd(PST(0),&tmp,&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x1d: + ST(0).exponent ^= 0x8000; + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x1e: + fdiv(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x1f: + fdiv(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 0x38: + fpush(); + ST(0) = ST((code & 7)+1); + return; + case 0x39: + fxchg(&ST(0),&ST(code & 7)); + return; + case 0x3b: + ST(code & 7) = ST(0); + fpop(); + return; + case 0x98: + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return; + case 0x99: + fmul(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return; + case 0x9a: + fcom(PST(code & 7),PST(0)); + return; + case 0x9b: + fcom(PST(code & 7),PST(0)); + fpop(); + return; + case 0x9c: + ST(code & 7).exponent ^= 0x8000; + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return; + case 0x9d: + real_to_real(&ST(0),&tmp); + tmp.exponent ^= 0x8000; + fadd(PST(code & 7),&tmp,&tmp); + real_to_real(&tmp,&ST(code & 7)); + return; + case 0x9e: + fdiv(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return; + case 0x9f: + fdiv(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return; + case 0xb8: + printk("ffree not implemented\n\r"); + math_abort(info,1<<(SIGILL-1)); + case 0xb9: + fxchg(&ST(0),&ST(code & 7)); + return; + case 0xba: + ST(code & 7) = ST(0); + return; + case 0xbb: + ST(code & 7) = ST(0); + fpop(); + return; + case 0xbc: + fucom(PST(code & 7),PST(0)); + return; + case 0xbd: + fucom(PST(code & 7),PST(0)); + fpop(); + return; + case 0xd8: + fadd(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return; + case 0xd9: + fmul(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return; + case 0xda: + fcom(PST(code & 7),PST(0)); + fpop(); + return; + case 0xdc: + ST(code & 7).exponent ^= 0x8000; + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return; + case 0xdd: + real_to_real(&ST(0),&tmp); + tmp.exponent ^= 0x8000; + fadd(PST(code & 7),&tmp,&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return; + case 0xde: + fdiv(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return; + case 0xdf: + fdiv(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return; + case 0xf8: + printk("ffree not implemented\n\r"); + math_abort(info,1<<(SIGILL-1)); + fpop(); + return; + case 0xf9: + fxchg(&ST(0),&ST(code & 7)); + return; + case 0xfa: + case 0xfb: + ST(code & 7) = ST(0); + fpop(); + return; + } + switch ((code>>3) & 0xe7) { + case 0x22: + put_short_real(PST(0),info,code); + return; + case 0x23: + put_short_real(PST(0),info,code); + fpop(); + return; + case 0x24: + address = ea(info,code); + for (code = 0 ; code < 7 ; code++) { + ((long *) & I387)[code] = + get_fs_long((unsigned long *) address); + address += 4; + } + return; + case 0x25: + address = ea(info,code); + *(unsigned short *) &I387.cwd = + get_fs_word((unsigned short *) address); + return; + case 0x26: + address = ea(info,code); + verify_area(address,28); + for (code = 0 ; code < 7 ; code++) { + put_fs_long( ((long *) & I387)[code], + (unsigned long *) address); + address += 4; + } + return; + case 0x27: + address = ea(info,code); + verify_area(address,2); + put_fs_word(I387.cwd,(short *) address); + return; + case 0x62: + put_long_int(PST(0),info,code); + return; + case 0x63: + put_long_int(PST(0),info,code); + fpop(); + return; + case 0x65: + fpush(); + get_temp_real(&tmp,info,code); + real_to_real(&tmp,&ST(0)); + return; + case 0x67: + put_temp_real(PST(0),info,code); + fpop(); + return; + case 0xa2: + put_long_real(PST(0),info,code); + return; + case 0xa3: + put_long_real(PST(0),info,code); + fpop(); + return; + case 0xa4: + address = ea(info,code); + for (code = 0 ; code < 27 ; code++) { + ((long *) & I387)[code] = + get_fs_long((unsigned long *) address); + address += 4; + } + return; + case 0xa6: + address = ea(info,code); + verify_area(address,108); + for (code = 0 ; code < 27 ; code++) { + put_fs_long( ((long *) & I387)[code], + (unsigned long *) address); + address += 4; + } + I387.cwd = 0x037f; + I387.swd = 0x0000; + I387.twd = 0x0000; + return; + case 0xa7: + address = ea(info,code); + verify_area(address,2); + put_fs_word(I387.swd,(short *) address); + return; + case 0xe2: + put_short_int(PST(0),info,code); + return; + case 0xe3: + put_short_int(PST(0),info,code); + fpop(); + return; + case 0xe4: + fpush(); + get_BCD(&tmp,info,code); + real_to_real(&tmp,&ST(0)); + return; + case 0xe5: + fpush(); + get_longlong_int(&tmp,info,code); + real_to_real(&tmp,&ST(0)); + return; + case 0xe6: + put_BCD(PST(0),info,code); + fpop(); + return; + case 0xe7: + put_longlong_int(PST(0),info,code); + fpop(); + return; + } + switch (code >> 9) { + case 0: + get_short_real(&tmp,info,code); + break; + case 1: + get_long_int(&tmp,info,code); + break; + case 2: + get_long_real(&tmp,info,code); + break; + case 4: + get_short_int(&tmp,info,code); + } + switch ((code>>3) & 0x27) { + case 0: + fadd(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 1: + fmul(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 2: + fcom(&tmp,PST(0)); + return; + case 3: + fcom(&tmp,PST(0)); + fpop(); + return; + case 4: + tmp.exponent ^= 0x8000; + fadd(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 5: + ST(0).exponent ^= 0x8000; + fadd(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 6: + fdiv(PST(0),&tmp,&tmp); + real_to_real(&tmp,&ST(0)); + return; + case 7: + fdiv(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return; + } + if ((code & 0x138) == 0x100) { + fpush(); + real_to_real(&tmp,&ST(0)); + return; + } + printk("Unknown math-insns: %04x:%08x %04x\n\r",CS,EIP,code); + math_abort(info,1<<(SIGFPE-1)); +} + +void math_emulate(long ___false) +{ + if (!current->used_math) { + current->used_math = 1; + I387.cwd = 0x037f; + I387.swd = 0x0000; + I387.twd = 0x0000; + } + do_emu((struct info *) &___false); +} + +void __math_abort(struct info * info, unsigned int signal) +{ + EIP = ORIG_EIP; + current->signal |= signal; + __asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4)); +} + +static void fpop(void) +{ + unsigned long tmp; + + tmp = I387.swd & 0xffffc7ff; + I387.swd += 0x00000800; + I387.swd &= 0x00003800; + I387.swd |= tmp; +} + +static void fpush(void) +{ + unsigned long tmp; + + tmp = I387.swd & 0xffffc7ff; + I387.swd += 0x00003800; + I387.swd &= 0x00003800; + I387.swd |= tmp; +} + +static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b) +{ + temp_real_unaligned c; + + c = *a; + *a = *b; + *b = c; +} + +static temp_real_unaligned * __st(int i) +{ + i += I387.swd >> 11; + i &= 7; + return (temp_real_unaligned *) (i*10 + (char *)(I387.st_space)); +} + +#else /* no math emulation */ + +#include +#include + +void math_emulate(long ___false) +{ + current->signal |= 1<<(SIGFPE-1); + schedule(); +} + +#endif /* KERNEL_MATH_EMULATION */ diff --git a/kernel/0.95/linux-0.95/kernel/math/mul.c b/kernel/0.95/linux-0.95/kernel/math/mul.c new file mode 100644 index 00000000..ae85e705 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/math/mul.c @@ -0,0 +1,73 @@ +/* + * linux/kernel/math/mul.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * temporary real multiplication routine. + */ + +#include + +static void shift(int * c) +{ + __asm__("movl (%0),%%eax ; addl %%eax,(%0)\n\t" + "movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t" + "movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t" + "movl 12(%0),%%eax ; adcl %%eax,12(%0)" + ::"r" ((long) c):"ax"); +} + +static void mul64(const temp_real * a, const temp_real * b, int * c) +{ + __asm__("movl (%0),%%eax\n\t" + "mull (%1)\n\t" + "movl %%eax,(%2)\n\t" + "movl %%edx,4(%2)\n\t" + "movl 4(%0),%%eax\n\t" + "mull 4(%1)\n\t" + "movl %%eax,8(%2)\n\t" + "movl %%edx,12(%2)\n\t" + "movl (%0),%%eax\n\t" + "mull 4(%1)\n\t" + "addl %%eax,4(%2)\n\t" + "adcl %%edx,8(%2)\n\t" + "adcl $0,12(%2)\n\t" + "movl 4(%0),%%eax\n\t" + "mull (%1)\n\t" + "addl %%eax,4(%2)\n\t" + "adcl %%edx,8(%2)\n\t" + "adcl $0,12(%2)" + ::"S" ((long) a),"c" ((long) b),"D" ((long) c) + :"ax","dx"); +} + +void fmul(const temp_real * src1, const temp_real * src2, temp_real * result) +{ + int i,sign; + int tmp[4] = {0,0,0,0}; + + sign = (src1->exponent ^ src2->exponent) & 0x8000; + i = (src1->exponent & 0x7fff) + (src2->exponent & 0x7fff) - 16383 + 1; + if (i<0) { + result->exponent = sign; + result->a = result->b = 0; + return; + } + if (i>0x7fff) { + set_OE(); + return; + } + mul64(src1,src2,tmp); + if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) + while (i && tmp[3] >= 0) { + i--; + shift(tmp); + } + else + i = 0; + result->exponent = i | sign; + result->a = tmp[2]; + result->b = tmp[3]; +} diff --git a/kernel/0.95/linux-0.95/kernel/mktime.c b/kernel/0.95/linux-0.95/kernel/mktime.c new file mode 100644 index 00000000..a67db96f --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/mktime.c @@ -0,0 +1,58 @@ +/* + * linux/kernel/mktime.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +/* + * This isn't the library routine, it is only used in the kernel. + * as such, we don't care about years<1970 etc, but assume everything + * is ok. Similarly, TZ etc is happily ignored. We just do everything + * as easily as possible. Let's find something public for the library + * routines (although I think minix times is public). + */ +/* + * PS. I hate whoever though up the year 1970 - couldn't they have gotten + * a leap-year instead? I also hate Gregorius, pope or no. I'm grumpy. + */ +#define MINUTE 60 +#define HOUR (60*MINUTE) +#define DAY (24*HOUR) +#define YEAR (365*DAY) + +/* interestingly, we assume leap-years */ +static int month[12] = { + 0, + DAY*(31), + DAY*(31+29), + DAY*(31+29+31), + DAY*(31+29+31+30), + DAY*(31+29+31+30+31), + DAY*(31+29+31+30+31+30), + DAY*(31+29+31+30+31+30+31), + DAY*(31+29+31+30+31+30+31+31), + DAY*(31+29+31+30+31+30+31+31+30), + DAY*(31+29+31+30+31+30+31+31+30+31), + DAY*(31+29+31+30+31+30+31+31+30+31+30) +}; + +long kernel_mktime(struct tm * tm) +{ + long res; + int year; + + 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/kernel/0.95/linux-0.95/kernel/panic.c b/kernel/0.95/linux-0.95/kernel/panic.c new file mode 100644 index 00000000..7d8a06ba --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/panic.c @@ -0,0 +1,24 @@ +/* + * linux/kernel/panic.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This function is used through-out the kernel (includeinh mm and fs) + * to indicate a major problem. + */ +#include +#include + +void sys_sync(void); /* it's really int */ + +volatile void panic(const char * s) +{ + printk("Kernel panic: %s\n\r",s); + if (current == task[0]) + printk("In swapper task - not syncing\n\r"); + else + sys_sync(); + for(;;); +} diff --git a/kernel/0.95/linux-0.95/kernel/printk.c b/kernel/0.95/linux-0.95/kernel/printk.c new file mode 100644 index 00000000..ebce88c6 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/printk.c @@ -0,0 +1,31 @@ +/* + * linux/kernel/printk.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * When in kernel-mode, we cannot use printf, as fs is liable to + * point to 'interesting' things. Make a printf with fs-saving, and + * all is well. + */ +#include +#include + +#include + +static char buf[1024]; + +extern int vsprintf(char * buf, const char * fmt, va_list args); + +int printk(const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + console_print(buf); + return i; +} diff --git a/kernel/0.95/linux-0.95/kernel/ptrace.c b/kernel/0.95/linux-0.95/kernel/ptrace.c new file mode 100644 index 00000000..1dab2614 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/ptrace.c @@ -0,0 +1,322 @@ +/* ptrace.c */ +/* By Ross Biro 1/23/92 */ + +#include +#include +#include +#include +#include +#include +#include +#include +/* does not yet catch signals sent when the child dies. in + exit.c or in signal.c. */ + +/* determines which flags the user has access to. */ +/* 1 = access 0 = no access */ +#define FLAG_MASK 0x00000dd9 + +/* set's the trap flag. */ +#define TRAP_FLAG 0x100 + +/* check's for granularity. */ +#define GRANULARITY 0x00800000 + +/* this is the number to subtract from the top of the stack. To find + the local frame. */ + +#define MAGICNUMBER 68 + +void do_no_page (unsigned long, unsigned long, struct task_struct *); +void write_verify (unsigned long); + +/* change a pid into a task struct. */ +static inline int get_task(int pid) +{ + int i; + for (i =0; i < NR_TASKS; i++) + { + if (task[i] != NULL && (task[i]->pid == pid)) return (i); + } + return (-1); +} + +/* this routine will get a word off of the processes priviledged stack. + the offset is how far from the base addr as stored in the TSS. + this routine assumes that all the priviledged stacks are in our + data space. */ + +static inline int +get_stack_long(struct task_struct *task, int offset) +{ + unsigned char *stack; + stack = (unsigned char *)task->tss.esp0; + stack += offset; + return (*((int *)stack)); + +} + +/* this routine will put a word on the processes priviledged stack. + the offset is how far from the base addr as stored in the TSS. + this routine assumes that all the priviledged stacks are in our + data space. */ + +static inline int +put_stack_long(struct task_struct *task, int offset, unsigned short data) +{ + unsigned char *stack; + stack = (unsigned char *)task->tss.esp0; + stack += offset; + *(int *)stack = data; + return (0); + +} + +/* this routine will get a word out of an arbitrary + tasks data space. It likes to have the task number + rather than the task pointer. Perhaps the number + should be included in the pointer. */ +/* seg = 0 if I space */ +static inline int get_long (int tsk, long addr, unsigned seg, int *data) +{ + int i; + int limit; + int cur; + unsigned long address; + unsigned long page; + unsigned oldfs; + /* find the task number of the current task. */ + for (i = 0; i < NR_TASKS ; i ++) + { + if (task[i] == current) break; + } + if (i == NR_TASKS) + { + panic ("PTRACE: Can't find current task\n"); + } + cur = i; + + /* we will need to check the redaability of the segment + and then the byte in order to avoid segment violations. */ + seg++; + limit=(task[tsk]->ldt[seg].a) & 0xffff; + /* this should be constant amound all of our segments, but we + had better check anyway. */ + if (task[tsk]->ldt[seg].b & GRANULARITY) limit = limit << 12; + + if (limit <= addr+4) return (-EIO); + + /* Now compute the address, and make sure that it is present. */ + address = ((task[tsk]->ldt[seg].a & 0xffff000) >> 8) | + ((task[tsk]->ldt[seg].b & 0xff) << 16 ) | + (task[tsk]->ldt[seg].b & 0xff000000); + + page = *((unsigned long*) ((address >> 20) & 0xffc)); + /* see if it is present. */ + if (! (page & PAGE_PRESENT)) + { + do_no_page (0, address, task[tsk]); + } + + oldfs=get_fs(); + /* now convert seg to the right format. */ + seg = seg << 3 | 0x4; + + cli(); /* we are about to change our ldt, we better do it + with interrupts off. Perhaps we should call schedule + first so that we won't be taking too much extra time. */ + lldt(tsk); + set_fs(seg); + *data = get_fs_long((void *)addr); /* we are assuming kernel space + is in the gdt here. */ + lldt(cur); + set_fs(oldfs); + sti(); + return (0); +} + +/* this routine will get a word out of an arbitrary + tasks data space. It likes to have the task number + rather than the task pointer. Perhaps the number + should be included in the pointer. */ +/* seg = 0 if I space */ +static inline int put_long (int tsk, long addr, int data, unsigned seg) +{ + int i; + int limit; + unsigned oldfs; + unsigned long address; + unsigned long page; + int cur; + /* find the task number of the current task. */ + for (i = 0; i < NR_TASKS ; i ++) + { + if (task[i] == current) break; + } + if (i == NR_TASKS) + { + panic ("PTRACE: Can't find current task\n"); + } + cur = i; + + /* we will need to check the readability of the segment + and then the byte in order to avoid segment violations. */ + seg++; + limit=(task[tsk]->ldt[seg].a) & 0xffff; + /* this should be constant amound all of our segments, but we + had better check anyway. */ + if (task[tsk]->ldt[seg].b & GRANULARITY) limit = limit << 12; + + if (limit <= addr+4) return (-EIO); + + /* Now compute the address, and make sure that it is present. */ + address = ((task[tsk]->ldt[seg].a & 0xffff000) >> 8) | + ((task[tsk]->ldt[seg].b & 0xff) << 16 ) | + (task[tsk]->ldt[seg].b & 0xff000000); + + page = *((unsigned long*) ((address >> 20) & 0xffc)); + /* see if it is present. */ + if (! (page & PAGE_PRESENT)) + { + do_no_page (0, address, task[tsk]); + } + write_verify (address); + + oldfs=get_fs(); + /* now convert seg to the right format. */ + seg = seg << 3 | 0x4; + + cli(); /* we are about to change our ldt, we better do it + with interrupts off. Perhaps we should call schedule + first so that we won't be taking too much extra time. */ + lldt(tsk); + set_fs(seg); + put_fs_long(data,(void *)addr); + lldt(cur); + set_fs(oldfs); + sti(); + return (0); +} + + +int +sys_ptrace( unsigned long *buffer) +/* Perform ptrace(request, pid, addr, data) syscall */ +{ + long request, pid, data; + long addr; + struct task_struct *child; + int childno; + + request = get_fs_long(buffer++); + pid = get_fs_long(buffer++); + addr = get_fs_long(buffer++); /* assume long = void * */ + data = get_fs_long(buffer++); + + if (request == 0) + { + /* set the ptrace bit in the proccess flags. */ + current->flags |= PF_PTRACED; + return (0); + } + + childno=get_task(pid); + + if (childno < 0) + return (-ESRCH); + else + child = task[childno]; + + if (child->p_pptr != current || + !(child->flags & PF_PTRACED) || child->state != TASK_STOPPED) + return (-ESRCH); + + switch (request) + { + /* when I and D space are seperate, these will need to be fixed. */ + case 1: /* read word at location addr. */ + case 2: { + int tmp; + int res; + res = get_long(childno, addr, 1, &tmp); + if (res < 0) + return res; + verify_area(data, 4); + put_fs_long( tmp, (unsigned long *)data); + return 0; + } + + case 3: /* read the word at location addr in the USER area. */ + { + int tmp; + addr = addr >> 2; /* temporary hack. */ + if (addr < 0 || addr >= 17) + return (-EIO); + verify_area(data, 4); + tmp = get_stack_long (child, 4*addr-MAGICNUMBER); + put_fs_long(tmp,(unsigned long *)data); + return (0); + } + case 4: /* write the word at location addr. */ + case 5: + /* when I and D space are seperate, this will have to be fixed. */ + if (put_long(childno, addr, data, 1)) return (-EIO); + return (0); + + case 6: /* write the word at location addr in the USER area */ + addr = addr >> 2; /* temproary hack. */ + if (addr < 0 || addr >= 17) return (-EIO); + if (addr == ORIG_EAX) return (-EIO); + if (addr == EFL) /* flags. */ + { + data &= FLAG_MASK; + data |= get_stack_long(child, EFL*4-MAGICNUMBER) & ~FLAG_MASK; + } + + if (put_stack_long(child, 4*addr-MAGICNUMBER, data)) return (-EIO); + return (0); + + case 7: /* restart after signal. */ + { + long tmp; + child->signal=0; + if (data > 0 && data <= NSIG) + child->signal = 1<<(data-1); + child->state = 0; + /* make sure the single step bit is not set. */ + tmp = get_stack_long (child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG; + put_stack_long(child, 4*EFL-MAGICNUMBER,tmp); + return (0); + } + + case 8: /* make the child exit. Best I can do is send it a sigkill. + perhaps it should be put in the status that it want's to + exit. */ + { + long tmp; + child->state = 0; + child->signal = 1 << (SIGKILL -1 ); + /* make sure the single step bit is not set. */ + tmp = get_stack_long (child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG; + put_stack_long(child, 4*EFL-MAGICNUMBER,tmp); + return (0); + } + + case 9: /* set the trap flag. */ + { + long tmp; + tmp = get_stack_long (child, 4*EFL-MAGICNUMBER) | TRAP_FLAG; + put_stack_long(child, 4*EFL-MAGICNUMBER,tmp); + child->state = 0; + child->signal=0; + if (data > 0 && data signal= 1<<(data-1); + /* give it a chance to run. */ + return (0); + } + + default: + return (-EIO); + } + +} diff --git a/kernel/0.95/linux-0.95/kernel/sched.c b/kernel/0.95/linux-0.95/kernel/sched.c new file mode 100644 index 00000000..335551d6 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/sched.c @@ -0,0 +1,457 @@ +/* + * linux/kernel/sched.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'sched.c' is the main kernel file. It contains scheduling primitives + * (sleep_on, wakeup, schedule etc) as well as a number of simple system + * call functions (type getpid(), which just extracts a field from + * current-task + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define _S(nr) (1<<((nr)-1)) +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + +void show_task(int nr,struct task_struct * p) +{ + int i,j = 4096-sizeof(struct task_struct); + + printk("%d: pid=%d, state=%d, father=%d, child=%d, ",nr,p->pid, + p->state, p->p_pptr->pid, p->p_cptr ? p->p_cptr->pid : -1); + i=0; + while (ip_ysptr || p->p_osptr) + printk(" Younger sib=%d, older sib=%d\n\r", + p->p_ysptr ? p->p_ysptr->pid : -1, + p->p_osptr ? p->p_osptr->pid : -1); + else + printk("\n\r"); +} + +void show_state(void) +{ + int i; + + printk("\rTask-info:\n\r"); + for (i=0;i>2 ] ; + +struct { + long * a; + short b; + } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 }; +/* + * 'math_state_restore()' saves the current math information in the + * old math state array, and gets the new ones from the current task + */ +void math_state_restore() +{ + if (last_task_used_math == current) + return; + __asm__("fwait"); + if (last_task_used_math) { + __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387)); + } + last_task_used_math=current; + if (current->used_math) { + __asm__("frstor %0"::"m" (current->tss.i387)); + } else { + __asm__("fninit"::); + current->used_math=1; + } +} + +/* + * 'schedule()' is the scheduler function. It's a very simple and nice + * scheduler: it's not perfect, but certainly works for most things. + * 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)->timeout && (*p)->timeout < jiffies) { + (*p)->timeout = 0; + if ((*p)->state == TASK_INTERRUPTIBLE) + (*p)->state = TASK_RUNNING; + } + if ((*p)->alarm && (*p)->alarm < jiffies) { + (*p)->signal |= (1<<(SIGALRM-1)); + (*p)->alarm = 0; + } + if (((*p)->signal & ~(*p)->blocked) && + (*p)->state==TASK_INTERRUPTIBLE) + (*p)->state=TASK_RUNNING; + } + +/* this is the scheduler proper: */ + + while (1) { + c = -1; + next = 0; + i = NR_TASKS; + p = &task[NR_TASKS]; + while (--i) { + if (!*--p) + continue; + if ((*p)->state == TASK_RUNNING && (*p)->counter > c) + c = (*p)->counter, next = i; + } + if (c) break; + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if (*p) + (*p)->counter = ((*p)->counter >> 1) + + (*p)->priority; + } + switch_to(next); +} + +int sys_pause(void) +{ + unsigned long old_blocked; + unsigned long mask; + struct sigaction * sa = current->sigaction; + + old_blocked = current->blocked; + for (mask=1 ; mask ; sa++,mask += mask) + if (sa->sa_handler == SIG_IGN) + current->blocked |= mask; + current->state = TASK_INTERRUPTIBLE; + schedule(); + current->blocked = old_blocked; + return -EINTR; +} + +static inline void __sleep_on(struct task_struct **p, int state) +{ + struct task_struct *tmp; + unsigned int flags; + + if (!p) + return; + if (current == &(init_task.task)) + panic("task[0] trying to sleep"); + __asm__("pushfl ; popl %0":"=r" (flags)); + tmp = *p; + *p = current; + current->state = state; +/* make sure interrupts are enabled: there should be no more races here */ + sti(); +repeat: schedule(); + if (*p && *p != current) { + current->state = TASK_UNINTERRUPTIBLE; + (**p).state = 0; + goto repeat; + } + if (*p = tmp) + tmp->state=0; + __asm__("pushl %0 ; popfl"::"r" (flags)); +} + +void interruptible_sleep_on(struct task_struct **p) +{ + __sleep_on(p,TASK_INTERRUPTIBLE); +} + +void sleep_on(struct task_struct **p) +{ + __sleep_on(p,TASK_UNINTERRUPTIBLE); +} + +void wake_up(struct task_struct **p) +{ + if (p && *p) { + if ((**p).state == TASK_STOPPED) + printk("wake_up: TASK_STOPPED"); + if ((**p).state == TASK_ZOMBIE) + printk("wake_up: TASK_ZOMBIE"); + (**p).state=0; + } +} + +/* + * OK, here are some floppy things that shouldn't be in the kernel + * proper. They are here because the floppy needs a timer, and this + * was the easiest way of doing it. + */ +static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL}; +static int mon_timer[4]={0,0,0,0}; +static int moff_timer[4]={0,0,0,0}; +unsigned char current_DOR = 0x0C; + +int ticks_to_floppy_on(unsigned int nr) +{ + extern unsigned char selected; + unsigned char mask = 0x10 << nr; + + if (nr>3) + panic("floppy_on: nr>3"); + moff_timer[nr]=10000; /* 100 s = very big :-) */ + cli(); /* use floppy_off to turn it off */ + mask |= current_DOR; + if (!selected) { + mask &= 0xFC; + mask |= nr; + } + if (mask != current_DOR) { + outb(mask,FD_DOR); + if ((mask ^ current_DOR) & 0xf0) + mon_timer[nr] = HZ/2; + else if (mon_timer[nr] < 2) + mon_timer[nr] = 2; + current_DOR = mask; + } + sti(); + return mon_timer[nr]; +} + +void floppy_on(unsigned int nr) +{ + cli(); + while (ticks_to_floppy_on(nr)) + sleep_on(nr+wait_motor); + sti(); +} + +void floppy_off(unsigned int nr) +{ + moff_timer[nr]=3*HZ; +} + +void do_floppy_timer(void) +{ + int i; + unsigned char mask = 0x10; + + for (i=0 ; i<4 ; i++,mask <<= 1) { + if (!(mask & current_DOR)) + continue; + if (mon_timer[i]) { + if (!--mon_timer[i]) + wake_up(i+wait_motor); + } else if (!moff_timer[i]) { + current_DOR &= ~mask; + outb(current_DOR,FD_DOR); + } else + moff_timer[i]--; + } +} + +#define TIME_REQUESTS 64 + +static struct timer_list { + long jiffies; + void (*fn)(); + struct timer_list * next; +} timer_list[TIME_REQUESTS], * next_timer = NULL; + +void add_timer(long jiffies, void (*fn)(void)) +{ + struct timer_list * p; + + if (!fn) + return; + cli(); + if (jiffies <= 0) + (fn)(); + else { + for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++) + if (!p->fn) + break; + if (p >= timer_list + TIME_REQUESTS) + panic("No more time requests free"); + p->fn = fn; + p->jiffies = jiffies; + p->next = next_timer; + next_timer = p; + while (p->next && p->next->jiffies < p->jiffies) { + p->jiffies -= p->next->jiffies; + fn = p->fn; + p->fn = p->next->fn; + p->next->fn = fn; + jiffies = p->jiffies; + p->jiffies = p->next->jiffies; + p->next->jiffies = jiffies; + p = p->next; + } + } + sti(); +} + +unsigned long timer_active = 0; +struct timer_struct timer_table[32]; + +void do_timer(long cpl) +{ + unsigned long mask; + struct timer_struct *tp = timer_table+0; + + for (mask = 1 ; mask ; tp++,mask += mask) { + if (mask > timer_active) + break; + if (!(mask & timer_active)) + continue; + if (tp->expires > jiffies) + continue; + timer_active &= ~mask; + tp->fn(); + } + + if (cpl) + current->utime++; + else + current->stime++; + + if (next_timer) { + next_timer->jiffies--; + while (next_timer && next_timer->jiffies <= 0) { + void (*fn)(void); + + fn = next_timer->fn; + next_timer->fn = NULL; + next_timer = next_timer->next; + (fn)(); + } + } + if (current_DOR & 0xf0) + do_floppy_timer(); + if ((--current->counter)>0) return; + current->counter=0; + if (!cpl) return; + schedule(); +} + +int sys_alarm(long seconds) +{ + int old = current->alarm; + + if (old) + old = (old - jiffies) / HZ; + current->alarm = (seconds>0)?(jiffies+HZ*seconds):0; + return (old); +} + +int sys_getpid(void) +{ + return current->pid; +} + +int sys_getppid(void) +{ + return current->p_pptr->pid; +} + +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 (increment < 0 && !suser()) + return -EPERM; + if (increment > current->priority) + increment = current->priority-1; + current->priority -= increment; + return 0; +} + +void sched_init(void) +{ + int i; + struct desc_struct * p; + + if (sizeof(struct sigaction) != 16) + panic("Struct sigaction MUST be 16 bytes"); + set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); + set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); + p = gdt+2+FIRST_TSS_ENTRY; + for(i=1 ; ia=p->b=0; + p++; + p->a=p->b=0; + p++; + } +/* Clear NT, so that we won't have troubles with that later on */ + __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); + ltr(0); + lldt(0); + outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */ + outb_p(LATCH & 0xff , 0x40); /* LSB */ + outb(LATCH >> 8 , 0x40); /* MSB */ + set_intr_gate(0x20,&timer_interrupt); + outb(inb_p(0x21)&~0x01,0x21); + set_system_gate(0x80,&system_call); +} diff --git a/kernel/0.95/linux-0.95/kernel/signal.c b/kernel/0.95/linux-0.95/kernel/signal.c new file mode 100644 index 00000000..cf0aa01b --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/signal.c @@ -0,0 +1,226 @@ +/* + * linux/kernel/signal.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include +#include + +int send_sig (int, struct task_struct *, int); + +int sys_sgetmask() +{ + return current->blocked; +} + +int sys_ssetmask(int newmask) +{ + int old=current->blocked; + + current->blocked = newmask & ~(1<<(SIGKILL-1)) & ~(1<<(SIGSTOP-1)); + return old; +} + +int sys_sigpending(sigset_t *set) +{ + /* fill in "set" with signals pending but blocked. */ + verify_area(set,4); + put_fs_long(current->blocked & current->signal, (unsigned long *)set); + return 0; +} + +/* atomically swap in the new signal mask, and wait for a signal. + * + * we need to play some games with syscall restarting. We get help + * from the syscall library interface. Note that we need to coordinate + * the calling convention with the libc routine. + * + * "set" is just the sigmask as described in 1003.1-1988, 3.3.7. + * It is assumed that sigset_t can be passed as a 32 bit quantity. + * + * "restart" holds a restart indication. If it's non-zero, then we + * install the old mask, and return normally. If it's zero, we store + * the current mask in old_mask and block until a signal comes in. + */ +int sys_sigsuspend(int restart, unsigned long old_mask, unsigned long set) +{ + extern int sys_pause(void); + + if (restart) { + /* we're restarting */ + current->blocked = old_mask; + return -EINTR; + } + /* we're not restarting. do the work */ + *(&restart) = 1; + *(&old_mask) = current->blocked; + current->blocked = set; + (void) sys_pause(); /* return after a signal arrives */ + return -ERESTARTNOINTR; /* handle the signal, and come back */ +} + +static inline void save_old(char * from,char * to) +{ + int i; + + verify_area(to, sizeof(struct sigaction)); + for (i=0 ; i< sizeof(struct sigaction) ; i++) { + put_fs_byte(*from,to); + from++; + to++; + } +} + +static inline void get_new(char * from,char * to) +{ + int i; + + for (i=0 ; i< sizeof(struct sigaction) ; i++) + *(to++) = get_fs_byte(from++); +} + +int sys_signal(int signum, long handler, long restorer) +{ + struct sigaction tmp; + + if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP) + return -EINVAL; + tmp.sa_handler = (void (*)(int)) handler; + tmp.sa_mask = 0; + tmp.sa_flags = SA_ONESHOT | SA_NOMASK; + tmp.sa_restorer = (void (*)(void)) restorer; + handler = (long) current->sigaction[signum-1].sa_handler; + current->sigaction[signum-1] = tmp; + return handler; +} + +int sys_sigaction(int signum, const struct sigaction * action, + struct sigaction * oldaction) +{ + struct sigaction tmp; + + if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP) + return -EINVAL; + tmp = current->sigaction[signum-1]; + get_new((char *) action, + (char *) (signum-1+current->sigaction)); + if (oldaction) + save_old((char *) &tmp,(char *) oldaction); + if (current->sigaction[signum-1].sa_flags & SA_NOMASK) + current->sigaction[signum-1].sa_mask = 0; + else + current->sigaction[signum-1].sa_mask |= (1<<(signum-1)); + return 0; +} + +/* + * Routine writes a core dump image in the current directory. + * Currently not implemented. + */ +int core_dump(long signr) +{ + return(0); /* We didn't do a dump */ +} + +extern int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); + +int do_signal(long signr,long ebx, long ecx, long edx, + long esi, long edi, long ebp, long eax, + long ds, long es, long fs, long gs, + long orig_eax, + long eip, long cs, long eflags, + unsigned long * esp, long ss) +{ + unsigned long sa_handler; + long old_eip=eip; + struct sigaction * sa = current->sigaction + signr - 1; + int longs; + + unsigned long * tmp_esp; + +#ifdef notdef + printk("pid: %d, signr: %x, eax=%d, oeax = %d, int=%d\n", + current->pid, signr, eax, orig_eax, + sa->sa_flags & SA_INTERRUPT); +#endif + if ((orig_eax != -1) && + ((eax == -ERESTARTSYS) || (eax == -ERESTARTNOINTR))) { + if ((eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT) || + signr < SIGCONT || signr > SIGTTOU)) + *(&eax) = -EINTR; + else { + *(&eax) = orig_eax; + *(&eip) = old_eip -= 2; + } + } + sa_handler = (unsigned long) sa->sa_handler; + if (sa_handler==1) { +/* check for SIGCHLD: it's special */ + if (signr == SIGCHLD) + while (sys_waitpid(-1,NULL,WNOHANG) > 0) + /* nothing */; + return(1); /* Ignore, see if there are more signals... */ + } + if (!sa_handler) { + switch (signr) { + case SIGCONT: + case SIGCHLD: + case SIGWINCH: + return(1); /* Ignore, ... */ + + case SIGSTOP: + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + current->state = TASK_STOPPED; + current->exit_code = signr; + if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & + SA_NOCLDSTOP)) + send_sig(SIGCHLD, current->p_pptr, 1); +/* current->p_pptr->signal |= (1<<(SIGCHLD-1));*/ + + return(1); /* Reschedule another event */ + + case SIGQUIT: + case SIGILL: + case SIGTRAP: + case SIGIOT: + case SIGFPE: + case SIGSEGV: + if (core_dump(signr)) + do_exit(signr|0x80); + /* fall through */ + default: + do_exit(signr); + } + } + /* + * OK, we're invoking a handler + */ + if (sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; + *(&eip) = sa_handler; + longs = (sa->sa_flags & SA_NOMASK)?7:8; + *(&esp) -= longs; + verify_area(esp,longs*4); + tmp_esp=esp; + put_fs_long((long) sa->sa_restorer,tmp_esp++); + put_fs_long(signr,tmp_esp++); + if (!(sa->sa_flags & SA_NOMASK)) + put_fs_long(current->blocked,tmp_esp++); + put_fs_long(eax,tmp_esp++); + put_fs_long(ecx,tmp_esp++); + put_fs_long(edx,tmp_esp++); + put_fs_long(eflags,tmp_esp++); + put_fs_long(old_eip,tmp_esp++); + current->blocked |= sa->sa_mask; +/* force a supervisor-mode page-in of the signal handler to reduce races */ + __asm__("testb $0,%%fs:%0"::"m" (*(char *) sa_handler)); + return(0); /* Continue, execute handler */ +} diff --git a/kernel/0.95/linux-0.95/kernel/sys.c b/kernel/0.95/linux-0.95/kernel/sys.c new file mode 100644 index 00000000..40b8b401 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/sys.c @@ -0,0 +1,556 @@ +/* + * linux/kernel/sys.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * this indicates wether you can reboot with ctrl-alt-del: the deault is yes + */ +static int C_A_D = 1; + +/* + * The timezone where the local system is located. Used as a default by some + * programs who obtain this value by using gettimeofday. + */ +struct timezone sys_tz = { 0, 0}; + +extern int session_of_pgrp(int pgrp); + +int sys_ftime() +{ + return -ENOSYS; +} + +int sys_break() +{ + return -ENOSYS; +} + +int sys_stty() +{ + return -ENOSYS; +} + +int sys_gtty() +{ + return -ENOSYS; +} + +int sys_prof() +{ + return -ENOSYS; +} + +extern void hard_reset_now(void); + +/* + * Reboot system call: for obvious reasons only root may call it, + * and even root needs to set up some magic numbers in the registers + * so that some mistake won't make this reboot the whole machine. + * You can also set the meaning of the ctrl-alt-del-key here. + * + * reboot doesn't sync: do that yourself before calling this. + */ +int sys_reboot(int magic, int magic_too, int flag) +{ + if (!suser()) + return -EPERM; + if (magic != 0xfee1dead || magic_too != 672274793) + return -EINVAL; + if (flag == 0x01234567) + hard_reset_now(); + else if (flag == 0x89ABCDEF) + C_A_D = 1; + else if (!flag) + C_A_D = 0; + else + return -EINVAL; + return (0); +} + +/* + * This function gets called by ctrl-alt-del - ie the keyboard interrupt. + * As it's called within an interrupt, it may NOT sync: the only choice + * is wether to reboot at once, or just ignore the ctrl-alt-del. + */ +void ctrl_alt_del(void) +{ + if (C_A_D) + hard_reset_now(); +} + + +/* + * This is done BSD-style, with no consideration of the saved gid, except + * that if you set the effective gid, it sets the saved gid too. This + * makes it possible for a setgid program to completely drop its privileges, + * which is often a useful assertion to make when you are doing a security + * audit over a program. + * + * The general idea is that a program which uses just setregid() will be + * 100% compatible with BSD. A program which uses just setgid() will be + * 100% compatible with POSIX w/ Saved ID's. + */ +int sys_setregid(int rgid, int egid) +{ + if (rgid>0) { + if ((current->gid == rgid) || + suser()) + current->gid = rgid; + else + return(-EPERM); + } + if (egid>0) { + if ((current->gid == egid) || + (current->egid == egid) || + suser()) { + current->egid = egid; + current->sgid = egid; + } else + return(-EPERM); + } + return 0; +} + +/* + * setgid() is implemeneted like SysV w/ SAVED_IDS + */ +int sys_setgid(int gid) +{ + if (suser()) + current->gid = current->egid = current->sgid = gid; + else if ((gid == current->gid) || (gid == current->sgid)) + current->egid = gid; + else + return -EPERM; + return 0; +} + +int sys_acct() +{ + return -ENOSYS; +} + +int sys_phys() +{ + return -ENOSYS; +} + +int sys_lock() +{ + return -ENOSYS; +} + +int sys_mpx() +{ + return -ENOSYS; +} + +int sys_ulimit() +{ + return -ENOSYS; +} + +int sys_time(long * tloc) +{ + int i; + + i = CURRENT_TIME; + if (tloc) { + verify_area(tloc,4); + put_fs_long(i,(unsigned long *)tloc); + } + return i; +} + +/* + * Unprivileged users may change the real user id to the effective uid + * or vice versa. (BSD-style) + * + * When you set the effective uid, it sets the saved uid too. This + * makes it possible for a setuid program to completely drop its privileges, + * which is often a useful assertion to make when you are doing a security + * audit over a program. + * + * The general idea is that a program which uses just setreuid() will be + * 100% compatible with BSD. A program which uses just setuid() will be + * 100% compatible with POSIX w/ Saved ID's. + */ +int sys_setreuid(int ruid, int euid) +{ + int old_ruid = current->uid; + + if (ruid>0) { + if ((current->euid==ruid) || + (old_ruid == ruid) || + suser()) + current->uid = ruid; + else + return(-EPERM); + } + if (euid>0) { + if ((old_ruid == euid) || + (current->euid == euid) || + suser()) { + current->euid = euid; + current->suid = euid; + } else { + current->uid = old_ruid; + return(-EPERM); + } + } + return 0; +} + +/* + * setuid() is implemeneted like SysV w/ SAVED_IDS + * + * Note that SAVED_ID's is deficient in that a setuid root program + * like sendmail, for example, cannot set its uid to be a normal + * user and then switch back, because if you're root, setuid() sets + * the saved uid too. If you don't like this, blame the bright people + * in the POSIX commmittee and/or USG. Note that the BSD-style setreuid() + * will allow a root program to temporarily drop privileges and be able to + * regain them by swapping the real and effective uid. + */ +int sys_setuid(int uid) +{ + if (suser()) + current->uid = current->euid = current->suid = uid; + else if ((uid == current->uid) || (uid == current->suid)) + current->euid = uid; + else + return -EPERM; + return(0); +} + +int sys_stime(long * tptr) +{ + if (!suser()) + return -EPERM; + startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ; + jiffies_offset = 0; + return 0; +} + +int sys_times(struct tms * tbuf) +{ + if (tbuf) { + verify_area(tbuf,sizeof *tbuf); + put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime); + put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime); + put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime); + put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime); + } + return jiffies; +} + +int sys_brk(unsigned long end_data_seg) +{ + if (end_data_seg >= current->end_code && + end_data_seg < current->start_stack - 16384) + current->brk = end_data_seg; + return current->brk; +} + +/* + * This needs some heave checking ... + * I just haven't get the stomach for it. I also don't fully + * understand sessions/pgrp etc. Let somebody who does explain it. + * + * OK, I think I have the protection semantics right.... this is really + * only important on a multi-user system anyway, to make sure one user + * can't send a signal to a process owned by another. -TYT, 12/12/91 + */ +int sys_setpgid(int pid, int pgid) +{ + int i; + + if (!pid) + pid = current->pid; + if (!pgid) + pgid = current->pid; + if (pgid < 0) + return -EINVAL; + for (i=0 ; ipid == pid) && + ((task[i]->p_pptr == current) || + (task[i] == current))) { + if (task[i]->leader) + return -EPERM; + if ((task[i]->session != current->session) || + ((pgid != pid) && + (session_of_pgrp(pgid) != current->session))) + return -EPERM; + task[i]->pgrp = pgid; + return 0; + } + return -ESRCH; +} + +int sys_getpgrp(void) +{ + return current->pgrp; +} + +int sys_setsid(void) +{ + if (current->leader && !suser()) + return -EPERM; + current->leader = 1; + current->session = current->pgrp = current->pid; + current->tty = -1; + return current->pgrp; +} + +/* + * Supplementary group ID's + */ +int sys_getgroups(int gidsetsize, gid_t *grouplist) +{ + int i; + + if (gidsetsize) + verify_area(grouplist, sizeof(gid_t) * gidsetsize); + + for (i = 0; (i < NGROUPS) && (current->groups[i] != NOGROUP); + i++, grouplist++) { + if (gidsetsize) { + if (i >= gidsetsize) + return -EINVAL; + put_fs_word(current->groups[i], (short *) grouplist); + } + } + return(i); +} + +int sys_setgroups(int gidsetsize, gid_t *grouplist) +{ + int i; + + if (!suser()) + return -EPERM; + if (gidsetsize > NGROUPS) + return -EINVAL; + for (i = 0; i < gidsetsize; i++, grouplist++) { + current->groups[i] = get_fs_word((unsigned short *) grouplist); + } + if (i < NGROUPS) + current->groups[i] = NOGROUP; + return 0; +} + +int in_group_p(gid_t grp) +{ + int i; + + if (grp == current->egid) + return 1; + + for (i = 0; i < NGROUPS; i++) { + if (current->groups[i] == NOGROUP) + break; + if (current->groups[i] == grp) + return 1; + } + return 0; +} + +static struct utsname thisname = { + UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION, UTS_MACHINE +}; + +int sys_uname(struct utsname * name) +{ + int i; + + if (!name) return -ERROR; + verify_area(name,sizeof *name); + for(i=0;i MAXHOSTNAMELEN) + return -EINVAL; + for (i=0; i < len; i++) { + if ((thisname.nodename[i] = get_fs_byte(name+i)) == 0) + break; + } + if (thisname.nodename[i]) { + thisname.nodename[i>MAXHOSTNAMELEN ? MAXHOSTNAMELEN : i] = 0; + } + return 0; +} + +int sys_getrlimit(int resource, struct rlimit *rlim) +{ + if (resource >= RLIM_NLIMITS) + return -EINVAL; + verify_area(rlim,sizeof *rlim); + put_fs_long(current->rlim[resource].rlim_cur, + (unsigned long *) rlim); + put_fs_long(current->rlim[resource].rlim_max, + ((unsigned long *) rlim)+1); + return 0; +} + +int sys_setrlimit(int resource, struct rlimit *rlim) +{ + struct rlimit new, *old; + + if (resource >= RLIM_NLIMITS) + return -EINVAL; + old = current->rlim + resource; + new.rlim_cur = get_fs_long((unsigned long *) rlim); + new.rlim_max = get_fs_long(((unsigned long *) rlim)+1); + if (((new.rlim_cur > old->rlim_max) || + (new.rlim_max > old->rlim_max)) && + !suser()) + return -EPERM; + *old = new; + return 0; +} + +/* + * It would make sense to put struct rusuage in the task_struct, + * except that would make the task_struct be *really big*. After + * task_struct gets moved into malloc'ed memory, it would + * make sense to do this. It will make moving the rest of the information + * a lot simpler! (Which we're not doing right now because we're not + * measuring them yet). + */ +int sys_getrusage(int who, struct rusage *ru) +{ + struct rusage r; + unsigned long *lp, *lpend, *dest; + + if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN) + return -EINVAL; + verify_area(ru, sizeof *ru); + memset((char *) &r, 0, sizeof(r)); + if (who == RUSAGE_SELF) { + r.ru_utime.tv_sec = CT_TO_SECS(current->utime); + r.ru_utime.tv_usec = CT_TO_USECS(current->utime); + r.ru_stime.tv_sec = CT_TO_SECS(current->stime); + r.ru_stime.tv_usec = CT_TO_USECS(current->stime); + } else { + r.ru_utime.tv_sec = CT_TO_SECS(current->cutime); + r.ru_utime.tv_usec = CT_TO_USECS(current->cutime); + r.ru_stime.tv_sec = CT_TO_SECS(current->cstime); + r.ru_stime.tv_usec = CT_TO_USECS(current->cstime); + } + lp = (unsigned long *) &r; + lpend = (unsigned long *) (&r+1); + dest = (unsigned long *) ru; + for (; lp < lpend; lp++, dest++) + put_fs_long(*lp, dest); + return(0); +} + +int sys_gettimeofday(struct timeval *tv, struct timezone *tz) +{ + if (tv) { + verify_area(tv, sizeof *tv); + put_fs_long(startup_time + CT_TO_SECS(jiffies+jiffies_offset), + (unsigned long *) tv); + put_fs_long(CT_TO_USECS(jiffies+jiffies_offset), + ((unsigned long *) tv)+1); + } + if (tz) { + verify_area(tz, sizeof *tz); + put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz); + put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1); + } + return 0; +} + +/* + * The first time we set the timezone, we will warp the clock so that + * it is ticking GMT time instead of local time. Presumably, + * if someone is setting the timezone then we are running in an + * environment where the programs understand about timezones. + * This should be done at boot time in the /etc/rc script, as + * soon as possible, so that the clock can be set right. Otherwise, + * various programs will get confused when the clock gets warped. + */ +int sys_settimeofday(struct timeval *tv, struct timezone *tz) +{ + static int firsttime = 1; + void adjust_clock(); + + if (!suser()) + return -EPERM; + if (tz) { + sys_tz.tz_minuteswest = get_fs_long((unsigned long *) tz); + sys_tz.tz_dsttime = get_fs_long(((unsigned long *) tz)+1); + if (firsttime) { + firsttime = 0; + if (!tv) + adjust_clock(); + } + } + if (tv) { + int sec, usec; + + sec = get_fs_long((unsigned long *)tv); + usec = get_fs_long(((unsigned long *)tv)+1); + + startup_time = sec - jiffies/HZ; + jiffies_offset = usec * HZ / 1000000 - jiffies%HZ; + } + return 0; +} + +/* + * Adjust the time obtained from the CMOS to be GMT time instead of + * local time. + * + * This is ugly, but preferable to the alternatives. Otherwise we + * would either need to write a program to do it in /etc/rc (and risk + * confusion if the program gets run more than once; it would also be + * hard to make the program warp the clock precisely n hours) or + * compile in the timezone information into the kernel. Bad, bad.... + * + * XXX Currently does not adjust for daylight savings time. May not + * need to do anything, depending on how smart (dumb?) the BIOS + * is. Blast it all.... the best thing to do not depend on the CMOS + * clock at all, but get the time via NTP or timed if you're on a + * network.... - TYT, 1/1/92 + */ +void adjust_clock() +{ + startup_time += sys_tz.tz_minuteswest*60; +} + +int sys_umask(int mask) +{ + int old = current->umask; + + current->umask = mask & 0777; + return (old); +} + diff --git a/kernel/0.95/linux-0.95/kernel/sys_call.s b/kernel/0.95/linux-0.95/kernel/sys_call.s new file mode 100644 index 00000000..8d7a982a --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/sys_call.s @@ -0,0 +1,320 @@ +/* + * linux/kernel/system_call.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * system_call.s contains the system-call low-level handling routines. + * This also contains the timer-interrupt handler, as some of the code is + * the same. The hd- and flopppy-interrupts are also here. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. Ordinary interrupts + * don't handle signal-recognition, as that would clutter them up totally + * unnecessarily. + * + * Stack layout in 'ret_from_system_call': + * ptrace needs to have all regs on the stack. + * if the order here is changed, it needs to be + * updated in fork.c:copy_process, signal.c:do_signal, + * ptrace.c ptrace.h + * + * 0(%esp) - %ebx + * 4(%esp) - %ecx + * 8(%esp) - %edx + * C(%esp) - %esi + * 10(%esp) - %edi + * 14(%esp) - %ebp + * 18(%esp) - %eax + * 1C(%esp) - %ds + * 20(%esp) - %es + * 24(%esp) - %fs + * 28(%esp) - %gs + * 2C(%esp) - orig_eax + * 30(%esp) - %eip + * 34(%esp) - %cs + * 38(%esp) - %eflags + * 3C(%esp) - %oldesp + * 40(%esp) - %oldss + */ + +SIG_CHLD = 17 + +EBX = 0x00 +ECX = 0x04 +EDX = 0x08 +ESI = 0x0C +EDI = 0x10 +EBP = 0x14 +EAX = 0x18 +DS = 0x1C +ES = 0x20 +FS = 0x24 +GS = 0x28 +ORIG_EAX = 0x2C +EIP = 0x30 +CS = 0x34 +EFLAGS = 0x38 +OLDESP = 0x3C +OLDSS = 0x40 + +state = 0 # these are offsets into the task-struct. +counter = 4 +priority = 8 +signal = 12 +sigaction = 16 # MUST be 16 (=len of sigaction) +blocked = (33*16) + +# offsets within sigaction +sa_handler = 0 +sa_mask = 4 +sa_flags = 8 +sa_restorer = 12 + +nr_system_calls = 82 + +ENOSYS = 38 + +/* + * Ok, I get parallel printer interrupts while using the floppy for some + * strange reason. Urgel. Now I just ignore them. + */ +.globl _system_call,_timer_interrupt,_sys_execve +.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt +.globl _device_not_available, _coprocessor_error + +.align 2 +bad_sys_call: + pushl $-ENOSYS + jmp ret_from_sys_call +.align 2 +reschedule: + pushl $ret_from_sys_call + jmp _schedule +.align 2 +_system_call: + cld + pushl %eax # save orig_eax + push %gs + push %fs + push %es + push %ds + pushl %eax # save eax. The return value will be put here. + pushl %ebp + pushl %edi + pushl %esi + 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 + cmpl _NR_syscalls,%eax + jae bad_sys_call + call _sys_call_table(,%eax,4) + movl %eax,EAX(%esp) # save the return value +2: movl _current,%eax + cmpl $0,state(%eax) # state + jne reschedule + cmpl $0,counter(%eax) # counter + je reschedule +ret_from_sys_call: + movl _current,%eax + cmpl _task,%eax # task[0] cannot have signals + je 3f + cmpw $0x0f,CS(%esp) # was old code segment supervisor ? + jne 3f + cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ? + jne 3f + movl signal(%eax),%ebx + movl blocked(%eax),%ecx + notl %ecx + andl %ebx,%ecx + bsfl %ecx,%ecx + je 3f + btrl %ecx,%ebx + movl %ebx,signal(%eax) + incl %ecx + pushl %ecx + call _do_signal + popl %ecx + testl %eax, %eax + jne 2b # see if we need to switch tasks, or do more signals +3: + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + popl %eax + pop %ds + pop %es + pop %fs + pop %gs + addl $4,%esp # skip the orig_eax + iret + +.align 2 +_coprocessor_error: + cld + pushl $-1 # mark this as an int. + push %gs + push %fs + push %es + push %ds + pushl %eax # save eax. + pushl %ebp + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + pushl $ret_from_sys_call + jmp _math_error + +.align 2 +_device_not_available: + cld + pushl $-1 # mark this as an int + push %gs + push %fs + push %es + push %ds + pushl %eax + pushl %ebp + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + pushl $ret_from_sys_call + clts # clear TS so that we can use math + movl %cr0,%eax + testl $0x4,%eax # EM (math emulation bit) + je _math_state_restore + pushl $0 # temporary storage for ORIG_EIP + call _math_emulate + addl $4,%esp + ret + +.align 2 +_timer_interrupt: + cld + pushl $-1 # mark this as an int + push %gs + push %fs + push %es + push %ds + pushl %eax + pushl %ebp + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + 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+4)(%esp),%eax # don't forget about the return address. + pushl %eax + call _do_execve + addl $4,%esp + ret + +_hd_interrupt: + cld + pushl %eax + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + movb $0x20,%al + outb %al,$0xA0 # EOI to interrupt controller #1 + jmp 1f # give port chance to breathe +1: jmp 1f +1: outb %al,$0x20 + andl $0xfffeffff,_timer_active + xorl %edx,%edx + xchgl _do_hd,%edx + testl %edx,%edx + jne 1f + movl $_unexpected_hd_interrupt,%edx +1: call *%edx # "interesting" way of handling intr. + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +_floppy_interrupt: + cld + pushl %eax + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + movb $0x20,%al + outb %al,$0x20 # EOI to interrupt controller #1 + xorl %eax,%eax + xchgl _do_floppy,%eax + testl %eax,%eax + jne 1f + movl $_unexpected_floppy_interrupt,%eax +1: call *%eax # "interesting" way of handling intr. + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +_parallel_interrupt: + cld + pushl %eax + movb $0x20,%al + outb %al,$0x20 + popl %eax + iret diff --git a/kernel/0.95/linux-0.95/kernel/traps.c b/kernel/0.95/linux-0.95/kernel/traps.c new file mode 100644 index 00000000..797bb79d --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/traps.c @@ -0,0 +1,205 @@ +/* + * linux/kernel/traps.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'asm.s'. Currently mostly a debugging-aid, will be extended + * to mainly kill the offending process (probably by giving it a signal, + * but possibly by killing it outright if necessary). + */ +#include + +#include +#include +#include +#include +#include +#include +#include + + +#define get_seg_byte(seg,addr) ({ \ +register char __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define get_seg_long(seg,addr) ({ \ +register unsigned long __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define _fs() ({ \ +register unsigned short __res; \ +__asm__("mov %%fs,%%ax":"=a" (__res):); \ +__res;}) + +void page_exception(void); + +void divide_error(void); +void debug(void); +void nmi(void); +void int3(void); +void overflow(void); +void bounds(void); +void invalid_op(void); +void device_not_available(void); +void double_fault(void); +void coprocessor_segment_overrun(void); +void invalid_TSS(void); +void segment_not_present(void); +void stack_segment(void); +void general_protection(void); +void page_fault(void); +void coprocessor_error(void); +void reserved(void); +void parallel_interrupt(void); +void irq13(void); +void alignment_check(void); +int send_sig(long, struct task_struct *, int); + +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: %04x:%p\nEFLAGS: %p\n", 0xffff & esp[1],esp[0],esp[2]); + if ((0xffff & esp[1]) == 0xf) + printk("ESP: %04x:%p\n",0xffff & esp[4],esp[3]); + printk("fs: %04x\n",_fs()); + printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x17)); + if ((0xffff & esp[1]) == 0xf) { + 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_alignment_check(long esp, long error_code) +{ + die("alignment check",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) +{ + send_sig(SIGTRAP, current, 0); +} + +void do_nmi(long esp, long error_code) +{ + die("nmi",esp,error_code); +} + +void do_debug(long esp, long error_code) +{ + send_sig(SIGTRAP, current, 0); +} + +void do_overflow(long esp, long error_code) +{ + die("overflow",esp,error_code); +} + +void do_bounds(long esp, long error_code) +{ + die("bounds",esp,error_code); +} + +void do_invalid_op(long esp, long error_code) +{ + die("invalid operand",esp,error_code); +} + +void do_device_not_available(long esp, long error_code) +{ + die("device not available",esp,error_code); +} + +void do_coprocessor_segment_overrun(long esp, long error_code) +{ + die("coprocessor segment overrun",esp,error_code); +} + +void do_invalid_TSS(long esp,long error_code) +{ + die("invalid TSS",esp,error_code); +} + +void do_segment_not_present(long esp,long error_code) +{ + die("segment not present",esp,error_code); +} + +void do_stack_segment(long esp,long error_code) +{ + die("stack segment",esp,error_code); +} + +void do_coprocessor_error(long esp, long error_code) +{ + if (last_task_used_math != current) + return; + die("coprocessor error",esp,error_code); +} + +void do_reserved(long esp, long error_code) +{ + die("reserved (15,17-47) error",esp,error_code); +} + +void trap_init(void) +{ + int i; + + set_trap_gate(0,÷_error); + set_trap_gate(1,&debug); + set_trap_gate(2,&nmi); + set_system_gate(3,&int3); /* int3-5 can be called from all */ + set_system_gate(4,&overflow); + set_system_gate(5,&bounds); + set_trap_gate(6,&invalid_op); + set_trap_gate(7,&device_not_available); + set_trap_gate(8,&double_fault); + set_trap_gate(9,&coprocessor_segment_overrun); + set_trap_gate(10,&invalid_TSS); + set_trap_gate(11,&segment_not_present); + set_trap_gate(12,&stack_segment); + set_trap_gate(13,&general_protection); + set_trap_gate(14,&page_fault); + set_trap_gate(15,&reserved); + set_trap_gate(16,&coprocessor_error); + set_trap_gate(17,&alignment_check); + for (i=18;i<48;i++) + set_trap_gate(i,&reserved); + set_trap_gate(45,&irq13); + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xdf,0xA1); + set_trap_gate(39,¶llel_interrupt); +} diff --git a/kernel/0.95/linux-0.95/kernel/vsprintf.c b/kernel/0.95/linux-0.95/kernel/vsprintf.c new file mode 100644 index 00000000..06b910e5 --- /dev/null +++ b/kernel/0.95/linux-0.95/kernel/vsprintf.c @@ -0,0 +1,233 @@ +/* + * linux/kernel/vsprintf.c + * + * (C) 1991 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include +#include + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ + +#define do_div(n,base) ({ \ +int __res; \ +__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ +__res; }) + +static char * number(char * str, int num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[36]; + const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + + if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; + if (type&LEFT) type &= ~ZEROPAD; + if (base<2 || base>36) + return 0; + c = (type & ZEROPAD) ? '0' : ' ' ; + if (type&SIGN && num<0) { + sign='-'; + num = -num; + } else + sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); + if (sign) size--; + if (type&SPECIAL) + if (base==16) size -= 2; + else if (base==8) size--; + i=0; + if (num==0) + tmp[i++]='0'; + else while (num!=0) + tmp[i++]=digits[do_div(num,base)]; + if (i>precision) precision=i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type&SPECIAL) + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + if (!(type&LEFT)) + while(size-->0) + *str++ = c; + while(i0) + *str++ = tmp[i]; + while(size-->0) + *str++ = ' '; + return str; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + int i; + char * str; + char *s; + int *ip; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + break; + + case 's': + s = va_arg(args, char *); + len = strlen(s); + if (precision < 0) + precision = len; + else if (len > precision) + len = precision; + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + break; + + case 'o': + str = number(str, va_arg(args, unsigned long), 8, + field_width, precision, flags); + break; + + case 'p': + if (field_width == -1) { + field_width = 8; + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + break; + + case 'x': + flags |= SMALL; + case 'X': + str = number(str, va_arg(args, unsigned long), 16, + field_width, precision, flags); + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + str = number(str, va_arg(args, unsigned long), 10, + field_width, precision, flags); + break; + + case 'n': + ip = va_arg(args, int *); + *ip = (str - buf); + break; + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + break; + } + } + *str = '\0'; + return str-buf; +} diff --git a/kernel/0.95/linux-0.95/lib/Makefile b/kernel/0.95/linux-0.95/lib/Makefile new file mode 100644 index 00000000..9f678c8f --- /dev/null +++ b/kernel/0.95/linux-0.95/lib/Makefile @@ -0,0 +1,76 @@ +# +# 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). +# + +# gcc2 doesn't understand some options.. +# GCC_OPT = -fcombine-regs + +AR =ar +AS =as +LD =ld +LDFLAGS =-s -x +CC =gcc +CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) \ + -finline-functions -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 malloc.o + +lib.a: $(OBJS) + $(AR) rcs lib.a $(OBJS) + sync + +clean: + rm -f core *.o *.a tmp_make + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ + $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +_exit.s _exit.o : _exit.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +close.s close.o : close.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +ctype.s ctype.o : ctype.c ../include/ctype.h +dup.s dup.o : dup.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +errno.s errno.o : errno.c +execve.s execve.o : execve.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +malloc.s malloc.o : malloc.c ../include/linux/kernel.h ../include/linux/mm.h \ + ../include/asm/system.h +open.s open.o : open.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h ../include/stdarg.h +setsid.s setsid.o : setsid.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h +string.s string.o : string.c ../include/string.h +wait.s wait.o : wait.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h ../include/sys/wait.h +write.s write.o : write.c ../include/unistd.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ + ../include/utime.h diff --git a/kernel/0.95/linux-0.95/lib/_exit.c b/kernel/0.95/linux-0.95/lib/_exit.c new file mode 100644 index 00000000..ac48d1aa --- /dev/null +++ b/kernel/0.95/linux-0.95/lib/_exit.c @@ -0,0 +1,14 @@ +/* + * linux/lib/_exit.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +volatile void _exit(int exit_code) +{ + __asm__("movl %1,%%ebx\n\t" + "int $0x80"::"a" (__NR_exit),"g" (exit_code)); +} diff --git a/kernel/0.95/linux-0.95/lib/close.c b/kernel/0.95/linux-0.95/lib/close.c new file mode 100644 index 00000000..afd8364f --- /dev/null +++ b/kernel/0.95/linux-0.95/lib/close.c @@ -0,0 +1,10 @@ +/* + * linux/lib/close.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall1(int,close,int,fd) diff --git a/kernel/0.95/linux-0.95/lib/ctype.c b/kernel/0.95/linux-0.95/lib/ctype.c new file mode 100644 index 00000000..877e629c --- /dev/null +++ b/kernel/0.95/linux-0.95/lib/ctype.c @@ -0,0 +1,35 @@ +/* + * linux/lib/ctype.c + * + * (C) 1991 Linus Torvalds + */ + +#include + +char _ctmp; +unsigned char _ctype[] = {0x00, /* EOF */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */ + diff --git a/kernel/0.95/linux-0.95/lib/dup.c b/kernel/0.95/linux-0.95/lib/dup.c new file mode 100644 index 00000000..dd13414a --- /dev/null +++ b/kernel/0.95/linux-0.95/lib/dup.c @@ -0,0 +1,10 @@ +/* + * linux/lib/dup.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall1(int,dup,int,fd) diff --git a/kernel/0.95/linux-0.95/lib/errno.c b/kernel/0.95/linux-0.95/lib/errno.c new file mode 100644 index 00000000..50aca2ee --- /dev/null +++ b/kernel/0.95/linux-0.95/lib/errno.c @@ -0,0 +1,7 @@ +/* + * linux/lib/errno.c + * + * (C) 1991 Linus Torvalds + */ + +int errno; diff --git a/kernel/0.95/linux-0.95/lib/execve.c b/kernel/0.95/linux-0.95/lib/execve.c new file mode 100644 index 00000000..a89726de --- /dev/null +++ b/kernel/0.95/linux-0.95/lib/execve.c @@ -0,0 +1,10 @@ +/* + * linux/lib/execve.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall3(int,execve,const char *,file,char **,argv,char **,envp) diff --git a/kernel/0.95/linux-0.95/lib/malloc.c b/kernel/0.95/linux-0.95/lib/malloc.c new file mode 100644 index 00000000..42723a76 --- /dev/null +++ b/kernel/0.95/linux-0.95/lib/malloc.c @@ -0,0 +1,232 @@ +/* + * malloc.c --- a general purpose kernel memory allocator for Linux. + * + * Written by Theodore Ts'o (tytso@mit.edu), 11/29/91 + * + * This routine is written to be as fast as possible, so that it + * can be called from the interrupt level. + * + * Limitations: maximum size of memory we can allocate using this routine + * is 4k, the size of a page in Linux. + * + * The general game plan is that each page (called a bucket) will only hold + * objects of a given size. When all of the object on a page are released, + * the page can be returned to the general free pool. When malloc() is + * called, it looks for the smallest bucket size which will fulfill its + * request, and allocate a piece of memory from that bucket pool. + * + * Each bucket has as its control block a bucket descriptor which keeps + * track of how many objects are in use on that page, and the free list + * for that page. Like the buckets themselves, bucket descriptors are + * stored on pages requested from get_free_page(). However, unlike buckets, + * pages devoted to bucket descriptor pages are never released back to the + * system. Fortunately, a system should probably only need 1 or 2 bucket + * descriptor pages, since a page can hold 256 bucket descriptors (which + * corresponds to 1 megabyte worth of bucket pages.) If the kernel is using + * that much allocated memory, it's probably doing something wrong. :-) + * + * Note: malloc() and free() both call get_free_page() and free_page() + * in sections of code where interrupts are turned off, to allow + * malloc() and free() to be safely called from an interrupt routine. + * (We will probably need this functionality when networking code, + * particularily things like NFS, is added to Linux.) However, this + * presumes that get_free_page() and free_page() are interrupt-level + * safe, which they may not be once paging is added. If this is the + * case, we will need to modify malloc() to keep a few unused pages + * "pre-allocated" so that it can safely draw upon those pages if + * it is called from an interrupt routine. + * + * Another concern is that get_free_page() should not sleep; if it + * does, the code is carefully ordered so as to avoid any race + * conditions. The catch is that if malloc() is called re-entrantly, + * there is a chance that unecessary pages will be grabbed from the + * system. Except for the pages for the bucket descriptor page, the + * extra pages will eventually get released back to the system, though, + * so it isn't all that bad. + */ + +#include +#include +#include + +struct bucket_desc { /* 16 bytes */ + void *page; + struct bucket_desc *next; + void *freeptr; + unsigned short refcnt; + unsigned short bucket_size; +}; + +struct _bucket_dir { /* 8 bytes */ + int size; + struct bucket_desc *chain; +}; + +/* + * The following is the where we store a pointer to the first bucket + * descriptor for a given size. + * + * If it turns out that the Linux kernel allocates a lot of objects of a + * specific size, then we may want to add that specific size to this list, + * since that will allow the memory to be allocated more efficiently. + * However, since an entire page must be dedicated to each specific size + * on this list, some amount of temperance must be exercised here. + * + * Note that this list *must* be kept in order. + */ +struct _bucket_dir bucket_dir[] = { + { 16, (struct bucket_desc *) 0}, + { 32, (struct bucket_desc *) 0}, + { 64, (struct bucket_desc *) 0}, + { 128, (struct bucket_desc *) 0}, + { 256, (struct bucket_desc *) 0}, + { 512, (struct bucket_desc *) 0}, + { 1024, (struct bucket_desc *) 0}, + { 2048, (struct bucket_desc *) 0}, + { 4096, (struct bucket_desc *) 0}, + { 0, (struct bucket_desc *) 0}}; /* End of list marker */ + +/* + * This contains a linked list of free bucket descriptor blocks + */ +struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0; + +/* + * This routine initializes a bucket description page. + */ +static inline void init_bucket_desc() +{ + struct bucket_desc *bdesc, *first; + int i; + + first = bdesc = (struct bucket_desc *) get_free_page(); + if (!bdesc) + panic("Out of memory in init_bucket_desc()"); + for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) { + bdesc->next = bdesc+1; + bdesc++; + } + /* + * This is done last, to avoid race conditions in case + * get_free_page() sleeps and this routine gets called again.... + */ + bdesc->next = free_bucket_desc; + free_bucket_desc = first; +} + +void *malloc(unsigned int len) +{ + struct _bucket_dir *bdir; + struct bucket_desc *bdesc; + void *retval; + + /* + * First we search the bucket_dir to find the right bucket change + * for this request. + */ + for (bdir = bucket_dir; bdir->size; bdir++) + if (bdir->size >= len) + break; + if (!bdir->size) { + printk("malloc called with impossibly large argument (%d)\n", + len); + panic("malloc: bad arg"); + } + /* + * Now we search for a bucket descriptor which has free space + */ + cli(); /* Avoid race conditions */ + for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) + if (bdesc->freeptr) + break; + /* + * If we didn't find a bucket with free space, then we'll + * allocate a new one. + */ + if (!bdesc) { + char *cp; + int i; + + if (!free_bucket_desc) + init_bucket_desc(); + bdesc = free_bucket_desc; + free_bucket_desc = bdesc->next; + bdesc->refcnt = 0; + bdesc->bucket_size = bdir->size; + bdesc->page = bdesc->freeptr = (void *) cp = get_free_page(); + if (!cp) + panic("Out of memory in kernel malloc()"); + /* Set up the chain of free objects */ + for (i=PAGE_SIZE/bdir->size; i > 1; i--) { + *((char **) cp) = cp + bdir->size; + cp += bdir->size; + } + *((char **) cp) = 0; + bdesc->next = bdir->chain; /* OK, link it in! */ + bdir->chain = bdesc; + } + retval = (void *) bdesc->freeptr; + bdesc->freeptr = *((void **) retval); + bdesc->refcnt++; + sti(); /* OK, we're safe again */ + return(retval); +} + +/* + * Here is the free routine. If you know the size of the object that you + * are freeing, then free_s() will use that information to speed up the + * search for the bucket descriptor. + * + * We will #define a macro so that "free(x)" is becomes "free_s(x, 0)" + */ +void free_s(void *obj, int size) +{ + void *page; + struct _bucket_dir *bdir; + struct bucket_desc *bdesc, *prev; + + /* Calculate what page this object lives in */ + page = (void *) ((unsigned long) obj & 0xfffff000); + /* Now search the buckets looking for that page */ + for (bdir = bucket_dir; bdir->size; bdir++) { + prev = 0; + /* If size is zero then this conditional is always false */ + if (bdir->size < size) + continue; + for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) { + if (bdesc->page == page) + goto found; + prev = bdesc; + } + } + panic("Bad address passed to kernel free_s()"); +found: + cli(); /* To avoid race conditions */ + *((void **)obj) = bdesc->freeptr; + bdesc->freeptr = obj; + bdesc->refcnt--; + if (bdesc->refcnt == 0) { + /* + * We need to make sure that prev is still accurate. It + * may not be, if someone rudely interrupted us.... + */ + if ((prev && (prev->next != bdesc)) || + (!prev && (bdir->chain != bdesc))) + for (prev = bdir->chain; prev; prev = prev->next) + if (prev->next == bdesc) + break; + if (prev) + prev->next = bdesc->next; + else { + if (bdir->chain != bdesc) + panic("malloc bucket chains corrupted"); + bdir->chain = bdesc->next; + } + free_page((unsigned long) bdesc->page); + bdesc->next = free_bucket_desc; + free_bucket_desc = bdesc; + } + sti(); + return; +} + diff --git a/kernel/0.95/linux-0.95/lib/open.c b/kernel/0.95/linux-0.95/lib/open.c new file mode 100644 index 00000000..59728071 --- /dev/null +++ b/kernel/0.95/linux-0.95/lib/open.c @@ -0,0 +1,26 @@ +/* + * linux/lib/open.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +int open(const char * filename, int flag, ...) +{ + register int res; + va_list arg; + + va_start(arg,flag); + __asm__("movl %2,%%ebx\n\t" + "int $0x80" + :"=a" (res) + :"0" (__NR_open),"g" ((long)(filename)),"c" (flag), + "d" (va_arg(arg,int))); + if (res>=0) + return res; + errno = -res; + return -1; +} diff --git a/kernel/0.95/linux-0.95/lib/setsid.c b/kernel/0.95/linux-0.95/lib/setsid.c new file mode 100644 index 00000000..68516c7e --- /dev/null +++ b/kernel/0.95/linux-0.95/lib/setsid.c @@ -0,0 +1,10 @@ +/* + * linux/lib/setsid.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall0(pid_t,setsid) diff --git a/kernel/0.95/linux-0.95/lib/string.c b/kernel/0.95/linux-0.95/lib/string.c new file mode 100644 index 00000000..1182e635 --- /dev/null +++ b/kernel/0.95/linux-0.95/lib/string.c @@ -0,0 +1,14 @@ +/* + * linux/lib/string.c + * + * (C) 1991 Linus Torvalds + */ + +#ifndef __GNUC__ +#error I want gcc! +#endif + +#define extern +#define inline +#define __LIBRARY__ +#include diff --git a/kernel/0.95/linux-0.95/lib/wait.c b/kernel/0.95/linux-0.95/lib/wait.c new file mode 100644 index 00000000..2815c16a --- /dev/null +++ b/kernel/0.95/linux-0.95/lib/wait.c @@ -0,0 +1,16 @@ +/* + * linux/lib/wait.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +_syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) + +pid_t wait(int * wait_stat) +{ + return waitpid(-1,wait_stat,0); +} diff --git a/kernel/0.95/linux-0.95/lib/write.c b/kernel/0.95/linux-0.95/lib/write.c new file mode 100644 index 00000000..df52e74d --- /dev/null +++ b/kernel/0.95/linux-0.95/lib/write.c @@ -0,0 +1,10 @@ +/* + * linux/lib/write.c + * + * (C) 1991 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall3(int,write,int,fd,const char *,buf,off_t,count) diff --git a/kernel/0.95/linux-0.95/mm/Makefile b/kernel/0.95/linux-0.95/mm/Makefile new file mode 100644 index 00000000..44c38abb --- /dev/null +++ b/kernel/0.95/linux-0.95/mm/Makefile @@ -0,0 +1,44 @@ +CC =gcc +CFLAGS =-O -Wall -fstrength-reduce -fomit-frame-pointer \ + -finline-functions -nostdinc -I../include +AS =as +AR =ar +LD =ld +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 swap.o + +all: mm.o + +mm.o: $(OBJS) + $(LD) -r -o mm.o $(OBJS) + +clean: + rm -f core *.o *.a tmp_make + for i in *.c;do rm -f `basename $$i .c`.s;done + +dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + (for i in *.c;do $(CPP) -M $$i;done) >> tmp_make + cp tmp_make Makefile + +### Dependencies: +memory.o : memory.c ../include/signal.h ../include/sys/types.h \ + ../include/asm/system.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ + ../include/sys/resource.h +swap.o : swap.c ../include/string.h ../include/errno.h \ + ../include/linux/mm.h ../include/linux/fs.h ../include/sys/types.h \ + ../include/linux/kernel.h ../include/signal.h ../include/sys/stat.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/sys/param.h \ + ../include/sys/time.h ../include/time.h ../include/sys/resource.h diff --git a/kernel/0.95/linux-0.95/mm/memory.c b/kernel/0.95/linux-0.95/mm/memory.c new file mode 100644 index 00000000..a77f26f6 --- /dev/null +++ b/kernel/0.95/linux-0.95/mm/memory.c @@ -0,0 +1,583 @@ +/* + * linux/mm/memory.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * demand-loading started 01.12.91 - seems it is high on the list of + * things wanted, and it should be easy to implement. - Linus + */ + +/* + * Ok, demand-loading was easy, shared pages a little bit tricker. Shared + * pages started 02.12.91, seems to work. - Linus. + * + * Tested sharing by executing about 30 /bin/sh: under the old kernel it + * would have taken more than the 6M I have free, but it worked well as + * far as I could see. + * + * Also corrected some "invalidate()"s - I wasn't doing enough of them. + */ + +/* + * Real VM (paging to/from disk) started 18.12.91. Much more work and + * thought has to go into this. Oh, well.. + * 19.12.91 - works, somewhat. Sometimes I get faults, don't know why. + * Found it. Everything seems to work now. + * 20.12.91 - Ok, making the swap-device changeable like the root. + */ + +#include + +#include + +#include +#include +#include + +#define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \ +current->start_code + current->end_code) + +unsigned long HIGH_MEMORY = 0; + +#define copy_page(from,to) \ +__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si") + +#define CHECK_LAST_NR 16 + +static unsigned long last_pages[CHECK_LAST_NR] = { 0, }; + +unsigned char mem_map [ PAGING_PAGES ] = {0,}; + +/* + * 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) { + addr -= LOW_MEM; + addr >>= 12; + if (mem_map[addr]--) + return; + mem_map[addr]=0; + } + printk("trying to free free page: memory probably corrupted"); +} + +/* + * 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 page; + unsigned long page_dir; + 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 (!(page_dir = *dir)) + continue; + *dir = 0; + if (!(page_dir & 1)) { + printk("free_page_tables: bad page directory."); + continue; + } + pg_table = (unsigned long *) (0xfffff000 & page_dir); + for (nr=0 ; nr<1024 ; nr++,pg_table++) { + if (!(page = *pg_table)) + continue; + *pg_table = 0; + if (1 & page) + free_page(0xfffff000 & page); + else + swap_free(page >> 1); + } + free_page(0xfffff000 & page_dir); + } + invalidate(); + for (page = 0; page < CHECK_LAST_NR ; page++) + last_pages[page] = 0; + 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 new_page; + 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 (*to_dir) + printk("copy_page_tables: already exist, " + "probable memory corruption\n"); + if (!*from_dir) + continue; + if (!(1 & *from_dir)) { + printk("copy_page_tables: page table swapped out, " + "probable memory corruption"); + *from_dir = 0; + 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 (!this_page) + continue; + if (!(1 & this_page)) { + if (!(new_page = get_free_page())) + return -1; + read_swap_page(this_page>>1, (char *) new_page); + *to_page_table = this_page; + *from_page_table = new_page | (PAGE_DIRTY | 7); + 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.) + */ +static 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("put_page: trying to put page %p at %p\n",page,address); + return 0; + } + if (mem_map[(page-LOW_MEM)>>12] != 1) { + printk("mem_map disagrees with %p at %p\n",page,address); + return 0; + } + page_table = (unsigned long *) ((address>>20) & 0xffc); + if ((*page_table)&1) + page_table = (unsigned long *) (0xfffff000 & *page_table); + else { + if (!(tmp=get_free_page())) + return 0; + *page_table = tmp | 7; + page_table = (unsigned long *) tmp; + } + page_table[(address>>12) & 0x3ff] = page | 7; +/* no need for invalidate */ + return page; +} + +/* + * The previous function doesn't work very well if you also want to mark + * the page dirty: exec.c wants this, as it has earlier changed the page, + * and we want the dirty-status to be correct (for VM). Thus the same + * routine, but this time we mark it dirty too. + */ +unsigned long put_dirty_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("put_dirty_page: 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 | (PAGE_DIRTY | 7); +/* no need for invalidate */ + return page; +} + +void un_wp_page(unsigned long * table_entry) +{ + unsigned long old_page; + unsigned long new_page = 0; + unsigned long dirty; + +repeat: + old_page = *table_entry; + dirty = old_page & PAGE_DIRTY; + if (!(old_page & 1)) { + if (new_page) + free_page(new_page); + return; + } + old_page &= 0xfffff000; + if (old_page >= HIGH_MEMORY) { + if (new_page) + free_page(new_page); + printk("bad page address\n\r"); + do_exit(SIGSEGV); + } + if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) { + *table_entry |= 2; + invalidate(); + if (new_page) + free_page(new_page); + return; + } + if (!new_page) { + if (!(new_page=get_free_page())) + oom(); + goto repeat; + } + copy_page(old_page,new_page); + *table_entry = new_page | dirty | 7; + free_page(old_page); + invalidate(); +} + +/* + * This routine handles present pages, when users try to write + * to a shared page. It is done by copying the page to a new address + * and decrementing the shared-page counter for the old page. + * + * If it's in code space we exit with a segment error. + */ +void do_wp_page(unsigned long error_code,unsigned long address) +{ + if (address < TASK_SIZE) + printk("\n\rBAD! KERNEL MEMORY WP-ERR!\n\r"); + if (address - current->start_code >= TASK_SIZE) { + printk("Bad things happen: page error in do_wp_page\n\r"); + do_exit(SIGSEGV); + } + un_wp_page((unsigned long *) + (((address>>10) & 0xffc) + (0xfffff000 & + *((unsigned long *) ((address>>20) &0xffc))))); + +} + +void write_verify(unsigned long address) +{ + unsigned long page; + + if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1)) + return; + page &= 0xfffff000; + page += ((address>>10) & 0xffc); + if ((3 & *(unsigned long *) page) == 1) /* non-writeable, present */ + un_wp_page((unsigned long *) page); + return; +} + +void get_empty_page(unsigned long address) +{ + unsigned long tmp; + + if (!(tmp=get_free_page()) || !put_page(tmp,address)) { + free_page(tmp); /* 0 is ok - ignored */ + oom(); + } +} + +/* + * try_to_share() checks the page at address "address" in the task "p", + * to see if it exists, and if it is clean. If so, share it with the current + * task. + * + * NOTE! This assumes we have checked that p != current, and that they + * share the same executable or library. + */ +static int try_to_share(unsigned long address, struct task_struct * p) +{ + unsigned long from; + unsigned long to; + unsigned long from_page; + unsigned long to_page; + unsigned long phys_addr; + + from_page = to_page = ((address>>20) & 0xffc); + from_page += ((p->start_code>>20) & 0xffc); + to_page += ((current->start_code>>20) & 0xffc); +/* is there a page-directory at from? */ + from = *(unsigned long *) from_page; + if (!(from & 1)) + return 0; + from &= 0xfffff000; + from_page = from + ((address>>10) & 0xffc); + phys_addr = *(unsigned long *) from_page; +/* is the page clean and present? */ + if ((phys_addr & 0x41) != 0x01) + return 0; + phys_addr &= 0xfffff000; + if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM) + return 0; + to = *(unsigned long *) to_page; + if (!(to & 1)) { + if (to = get_free_page()) + *(unsigned long *) to_page = to | 7; + else + oom(); + } + to &= 0xfffff000; + to_page = to + ((address>>10) & 0xffc); + if (1 & *(unsigned long *) to_page) + panic("try_to_share: to_page already exists"); +/* share them: write-protect */ + *(unsigned long *) from_page &= ~2; + *(unsigned long *) to_page = *(unsigned long *) from_page; + invalidate(); + phys_addr -= LOW_MEM; + phys_addr >>= 12; + mem_map[phys_addr]++; + return 1; +} + +/* + * share_page() tries to find a process that could share a page with + * the current one. Address is the address of the wanted page relative + * to the current data space. + * + * We first check if it is at all feasible by checking executable->i_count. + * It should be >1 if there are other tasks sharing this inode. + */ +static int share_page(struct inode * inode, unsigned long address) +{ + struct task_struct ** p; + + if (inode->i_count < 2 || !inode) + return 0; + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if (!*p) + continue; + if (current == *p) + continue; + if (address < LIBRARY_OFFSET) { + if (inode != (*p)->executable) + continue; + } else { + if (inode != (*p)->library) + continue; + } + if (try_to_share(address,*p)) + return 1; + } + return 0; +} + +void do_no_page(unsigned long error_code, + unsigned long address, struct task_struct *tsk) +{ + static unsigned int last_checked = 0; + int nr[4]; + unsigned long tmp; + unsigned long page; + int block,i; + struct inode * inode; + + /* Trashing ? Make it interruptible, but don't penalize otherwise */ + for (i = 0; i < CHECK_LAST_NR; i++) + if ((address & 0xfffff000) == last_pages[i]) { + current->counter = 0; + schedule(); + } + last_checked++; + if (last_checked >= CHECK_LAST_NR) + last_checked = 0; + last_pages[last_checked] = address & 0xfffff000; + if (address < TASK_SIZE) + printk("\n\rBAD!! KERNEL PAGE MISSING\n\r"); + if (address - tsk->start_code >= TASK_SIZE) { + printk("Bad things happen: nonexistent page error in do_no_page\n\r"); + do_exit(SIGSEGV); + } + page = *(unsigned long *) ((address >> 20) & 0xffc); +/* check the page directory: make a page dir entry if no such exists */ + if (page & 1) { + page &= 0xfffff000; + page += (address >> 10) & 0xffc; + tmp = *(unsigned long *) page; + if (tmp && !(1 & tmp)) { + swap_in((unsigned long *) page); + return; + } + } else { + if (page) + printk("do_no_page: bad page directory\n"); + if (!(page = get_free_page())) + oom(); + page |= 7; + *(unsigned long *) ((address >> 20) & 0xffc) = page; + } + address &= 0xfffff000; + tmp = address - tsk->start_code; + if (tmp >= LIBRARY_OFFSET ) { + inode = tsk->library; + block = 1 + (tmp-LIBRARY_OFFSET) / BLOCK_SIZE; + } else if (tmp < tsk->end_data) { + inode = tsk->executable; + block = 1 + tmp / BLOCK_SIZE; + } else { + inode = NULL; + block = 0; + } + if (!inode) { + get_empty_page(address); + return; + } + if (tsk == current) + if (share_page(inode,tmp)) + return; + if (!(page = get_free_page())) + oom(); +/* remember that 1 block is used for header */ + for (i=0 ; i<4 ; block++,i++) + nr[i] = bmap(inode,block); + bread_page(page,inode->i_dev,nr); + i = tmp + 4096 - tsk->end_data; + if (i>4095) + i = 0; + tmp = page + 4096; + while (i-- > 0) { + tmp--; + *(char *)tmp = 0; + } + if (put_page(page,address)) + return; + free_page(page); + oom(); +} + +void mem_init(long start_mem, long end_mem) +{ + int i; + + swap_device = 0; + swap_file = NULL; + HIGH_MEMORY = end_mem; + for (i=0 ; i>= 12; + while (end_mem-->0) + mem_map[i++]=0; +} + +void show_mem(void) +{ + int i,j,k,free=0,total=0; + int shared=0; + unsigned long * pg_tbl; + + printk("Mem-info:\n\r"); + for(i=0 ; iHIGH_MEMORY) { + printk("page directory[%d]: %08X\n\r", + i,pg_dir[i]); + i++; + continue; + } + if (pg_dir[i]>LOW_MEM) + free++,k++; + pg_tbl=(unsigned long *) (0xfffff000 & pg_dir[i]); + for(j=0 ; j<1024 ; j++) + if ((pg_tbl[j]&1) && pg_tbl[j]>LOW_MEM) + if (pg_tbl[j]>HIGH_MEMORY) + printk("page_dir[%d][%d]: %08X\n\r", + i,j, pg_tbl[j]); + else + k++,free++; + } + i++; + if (!(i&15) && k) { + k++,free++; /* one page/process for task_struct */ + printk("Process %d: %d pages\n\r",(i>>4)-1,k); + k = 0; + } + } + printk("Memory found: %d (%d)\n\r",free-shared,total); +} + + +/* This routine handles page faults. It determines the address, + and the problem then passes it off to one of the appropriate + routines. */ +void do_page_fault (unsigned long *esp, unsigned long error_code) +{ + unsigned long address; + /* get the address */ + + __asm__ ("movl %%cr2,%0":"=r" (address)); + if (!(error_code & 1)) { + do_no_page(error_code, address, current); + return; + } else { + do_wp_page(error_code, address); + return; + } +} diff --git a/kernel/0.95/linux-0.95/mm/swap.c b/kernel/0.95/linux-0.95/mm/swap.c new file mode 100644 index 00000000..4c621d01 --- /dev/null +++ b/kernel/0.95/linux-0.95/mm/swap.c @@ -0,0 +1,290 @@ +/* + * linux/mm/swap.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This file should contain most things doing the swapping from/to disk. + * Started 18.12.91 + */ + +#include +#include + +#include +#include +#include +#include +#include + +#define SWAP_BITS (4096<<3) + +#define bitop(name,op) \ +static inline int name(char * addr,unsigned int nr) \ +{ \ +int __res; \ +__asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \ +:"=g" (__res) \ +:"r" (nr),"m" (*(addr)),"0" (0)); \ +return __res; \ +} + +bitop(bit,"") +bitop(setbit,"s") +bitop(clrbit,"r") + +static char * swap_bitmap = NULL; +unsigned int swap_device = 0; +struct inode * swap_file = NULL; + +void rw_swap_page(int rw, unsigned int nr, char * buf) +{ + unsigned int zones[4]; + int i; + + if (swap_device) { + ll_rw_page(rw,swap_device,nr,buf); + return; + } + if (swap_file) { + nr <<= 2; + for (i = 0; i < 4; i++) + if (!(zones[i] = bmap(swap_file,nr++))) { + printk("rw_swap_page: bad swap file\n"); + return; + } + ll_rw_swap_file(rw,swap_file->i_dev, zones,4,buf); + return; + } + printk("ll_swap_page: no swap file or device\n"); +} + +/* + * We never page the pages in task[0] - kernel memory. + * We page all other pages. + */ +#define FIRST_VM_PAGE (TASK_SIZE>>12) +#define LAST_VM_PAGE (1024*1024) +#define VM_PAGES (LAST_VM_PAGE - FIRST_VM_PAGE) + +static int get_swap_page(void) +{ + int nr; + + if (!swap_bitmap) + return 0; + for (nr = 1; nr < SWAP_BITS ; nr++) + if (clrbit(swap_bitmap,nr)) + return nr; + return 0; +} + +void swap_free(int swap_nr) +{ + if (!swap_nr) + return; + if (swap_bitmap && swap_nr < SWAP_BITS) + if (!setbit(swap_bitmap,swap_nr)) + return; + printk("swap_free: swap-space bitmap bad\n"); + return; +} + +void swap_in(unsigned long *table_ptr) +{ + int swap_nr; + unsigned long page; + + if (!swap_bitmap) { + printk("Trying to swap in without swap bit-map"); + return; + } + if (1 & *table_ptr) { + printk("trying to swap in present page\n\r"); + return; + } + swap_nr = *table_ptr >> 1; + if (!swap_nr) { + printk("No swap page in swap_in\n\r"); + return; + } + if (!(page = get_free_page())) + oom(); + read_swap_page(swap_nr, (char *) page); + if (setbit(swap_bitmap,swap_nr)) + printk("swapping in multiply from same page\n\r"); + *table_ptr = page | (PAGE_DIRTY | 7); +} + +int try_to_swap_out(unsigned long * table_ptr) +{ + unsigned long page; + unsigned long swap_nr; + + page = *table_ptr; + if (!(PAGE_PRESENT & page)) + return 0; + if (page - LOW_MEM > PAGING_MEMORY) + return 0; + if (PAGE_DIRTY & page) { + page &= 0xfffff000; + if (mem_map[MAP_NR(page)] != 1) + return 0; + if (!(swap_nr = get_swap_page())) + return 0; + *table_ptr = swap_nr<<1; + invalidate(); + write_swap_page(swap_nr, (char *) page); + free_page(page); + return 1; + } + page &= 0xfffff000; + *table_ptr = 0; + invalidate(); + free_page(page); + return 1; +} + +/* + * Go through the page tables, searching for a user page that + * we can swap out. + */ +int swap_out(void) +{ + static int dir_entry = 1024; + static int page_entry = -1; + int counter = VM_PAGES; + int pg_table = 0; + +repeat: + while (counter > 0) { + counter -= 1024; + dir_entry++; + if (dir_entry >= 1024) + dir_entry = FIRST_VM_PAGE>>10; + if (pg_table = pg_dir[dir_entry]) + break; + } + if (counter <= 0) { + printk("Out of swap-memory\n"); + return 0; + } + if (!(pg_table & 1)) { + printk("bad page-table at pg_dir[%d]: %08x\n\r",dir_entry, + pg_table); + return 0; + } + pg_table &= 0xfffff000; + while (counter > 0) { + counter--; + page_entry++; + if (page_entry >= 1024) { + page_entry = -1; + goto repeat; + } + if (try_to_swap_out(page_entry + (unsigned long *) pg_table)) + return 1; + } + printk("Out of swap-memory\n\r"); + return 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) +{ + unsigned long result; + +repeat: + __asm__("std ; repne ; scasb\n\t" + "jne 1f\n\t" + "movb $1,1(%%edi)\n\t" + "sall $12,%%ecx\n\t" + "addl %2,%%ecx\n\t" + "movl %%ecx,%%edx\n\t" + "movl $1024,%%ecx\n\t" + "leal 4092(%%edx),%%edi\n\t" + "rep ; stosl\n\t" + "movl %%edx,%%eax\n" + "1:\tcld" + :"=a" (result) + :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES), + "D" (mem_map+PAGING_PAGES-1) + :"di","cx","dx"); + if (result >= HIGH_MEMORY) + goto repeat; + if ((result && result < LOW_MEM) || (result & 0xfff)) { + printk("weird result: %08x\n",result); + result = 0; + } + if (!result && swap_out()) + goto repeat; + return result; +} + +/* + * Written 01/25/92 by Simmule Turner, heavily changed by Linus. + * + * The swapon system call + */ + +int sys_swapon(const char * specialfile) +{ + struct inode * swap_inode; + int i,j; + + if (!suser()) + return -EPERM; + if (!(swap_inode = namei(specialfile))) + return -ENOENT; + if (swap_file || swap_device || swap_bitmap) { + iput(swap_inode); + return -EBUSY; + } + if (S_ISBLK(swap_inode->i_mode)) { + swap_device = swap_inode->i_rdev; + iput(swap_inode); + } else if (S_ISREG(swap_inode->i_mode)) + swap_file = swap_inode; + else { + iput(swap_inode); + return -EINVAL; + } + swap_bitmap = (char *) get_free_page(); + if (!swap_bitmap) { + iput(swap_file); + swap_device = 0; + swap_file = NULL; + printk("Unable to start swapping: out of memory :-)\n"); + return -ENOMEM; + } + read_swap_page(0,swap_bitmap); + if (strncmp("SWAP-SPACE",swap_bitmap+4086,10)) { + printk("Unable to find swap-space signature\n\r"); + free_page((long) swap_bitmap); + iput(swap_file); + swap_device = 0; + swap_file = NULL; + swap_bitmap = NULL; + return -EINVAL; + } + memset(swap_bitmap+4086,0,10); + j = 0; + for (i = 1 ; i < SWAP_BITS ; i++) + if (bit(swap_bitmap,i)) + j++; + if (!j) { + printk("Empty swap-file\n"); + free_page((long) swap_bitmap); + iput(swap_file); + swap_device = 0; + swap_file = NULL; + swap_bitmap = NULL; + return -EINVAL; + } + printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096); + return 0; +} diff --git a/kernel/0.95/linux-0.95/tools/build.c b/kernel/0.95/linux-0.95/tools/build.c new file mode 100644 index 00000000..1fa477ba --- /dev/null +++ b/kernel/0.95/linux-0.95/tools/build.c @@ -0,0 +1,168 @@ +/* + * linux/tools/build.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This file builds a disk-image from three different files: + * + * - bootsect: max 510 bytes of 8086 machine code, loads the rest + * - setup: max 4 sectors of 8086 machine code, sets up system parm + * - system: 80386 code for actual system + * + * It does some checking that all files are of the correct type, and + * just writes the result to stdout, removing headers and padding to + * the right amount. It also writes some system data to stderr. + */ + +/* + * Changes by tytso to allow root device specification + */ + +#include /* fprintf */ +#include +#include /* contains exit */ +#include /* unistd.h needs this */ +#include +#include +#include /* contains read/write */ +#include + +#define MINIX_HEADER 32 +#define GCC_HEADER 1024 + +#define SYS_SIZE 0x4000 + +#define DEFAULT_MAJOR_ROOT 0 +#define DEFAULT_MINOR_ROOT 0 + +/* max nr of sectors of setup: don't change unless you also change + * bootsect etc */ +#define SETUP_SECTS 4 + +#define STRINGIFY(x) #x + +void die(char * str) +{ + fprintf(stderr,"%s\n",str); + exit(1); +} + +void usage(void) +{ + die("Usage: build bootsect setup system [rootdev] [> image]"); +} + +int main(int argc, char ** argv) +{ + int i,c,id; + char buf[1024]; + char major_root, minor_root; + struct stat sb; + + if ((argc < 4) || (argc > 5)) + usage(); + if (argc > 4) { + if (strcmp(argv[4], "FLOPPY")) { + if (stat(argv[4], &sb)) { + perror(argv[4]); + die("Couldn't stat root device."); + } + major_root = MAJOR(sb.st_rdev); + minor_root = MINOR(sb.st_rdev); + } else { + major_root = 0; + minor_root = 0; + } + } else { + major_root = DEFAULT_MAJOR_ROOT; + minor_root = DEFAULT_MINOR_ROOT; + } + fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); + if ((major_root != 2) && (major_root != 3) && + (major_root != 0)) { + fprintf(stderr, "Illegal root device (major = %d)\n", + major_root); + die("Bad root device --- major #"); + } + for (i=0;i0 ; i+=c ) + if (write(1,buf,c)!=c) + die("Write call failed"); + close (id); + if (i > SETUP_SECTS*512) + die("Setup exceeds " STRINGIFY(SETUP_SECTS) + " sectors - rewrite build/boot/setup"); + fprintf(stderr,"Setup is %d bytes.\n",i); + for (c=0 ; c sizeof(buf)) + c = sizeof(buf); + if (write(1,buf,c) != c) + die("Write call failed"); + i += c; + } + + if ((id=open(argv[3],O_RDONLY,0))<0) + die("Unable to open 'system'"); + if (read(id,buf,GCC_HEADER) != GCC_HEADER) + die("Unable to read header of 'system'"); + if (((long *) buf)[5] != 0) + die("Non-GCC header of 'system'"); + for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c ) + if (write(1,buf,c)!=c) + die("Write call failed"); + close(id); + fprintf(stderr,"System is %d bytes.\n",i); + if (i > SYS_SIZE*16) + die("System is too big"); + return(0); +} diff --git a/kernel/0.95/linux-0.95a.tar.gz b/kernel/0.95/linux-0.95a.tar.gz new file mode 100644 index 00000000..f9f73c56 Binary files /dev/null and b/kernel/0.95/linux-0.95a.tar.gz differ diff --git a/kernel/0.95/linux-0.95c+.tar.gz b/kernel/0.95/linux-0.95c+.tar.gz new file mode 100644 index 00000000..1e42cc6a Binary files /dev/null and b/kernel/0.95/linux-0.95c+.tar.gz differ diff --git a/kernel/0.96/linux-0.96a.tar.gz b/kernel/0.96/linux-0.96a.tar.gz new file mode 100644 index 00000000..66f97f59 Binary files /dev/null and b/kernel/0.96/linux-0.96a.tar.gz differ diff --git a/kernel/0.96/linux-0.96b.1.tar.gz b/kernel/0.96/linux-0.96b.1.tar.gz new file mode 100644 index 00000000..924971be Binary files /dev/null and b/kernel/0.96/linux-0.96b.1.tar.gz differ diff --git a/kernel/0.96/linux-0.96c.tar.gz b/kernel/0.96/linux-0.96c.tar.gz new file mode 100644 index 00000000..91b39af2 Binary files /dev/null and b/kernel/0.96/linux-0.96c.tar.gz differ diff --git a/kernel/0.97/RELNOTES-0.97 b/kernel/0.97/RELNOTES-0.97 new file mode 100644 index 00000000..7d8cb2f4 --- /dev/null +++ b/kernel/0.97/RELNOTES-0.97 @@ -0,0 +1,75 @@ +Changes in 0.97: + + - The VESA-support was removed. I'd be happy to put it back once it + works on all hardware. Instead of the VESA-code, I finally put in + the automatic SVGA setup patches. See the top-level Makefile. + + - The IRQ code has solidified, and should work on all machines. Not + all of the SCSI drivers use it yet, so I expect patches for that.. + + - Serial interrupts are handled slightly differently, and performance + should be up. I've sent out a few alpha-releases, and testing seems + to indicate that's actually true this time. Reactions have ranged + from "nice" to "wonderful" :-) + + - The buffer-cache and memory management code has been edited quite a + bit. ps/free etc programs that reads kernel memory directly no + longer work, and even a recompilation won't be enough. They actually + need editing before they work. + + The buffer-cache now grows and shrinks dynamically depending on how + much free memory there is. Shift+PrintScreen will give some memory + statistics. (Ctrl+PrSc gives task-info, ALT+PrSc gives current + register values). + + The mm code changes removed some race-conditions in the VM code, and + I also tried to make the Out-of-swapspace error less severe (better + thrashing-detection etc). + + - The super-block code has been cleaned up. Especially the extended fs + needs to be edited a bit to take advantage of the new setup, and I + expect Remy Card will have a patch out eventually. + + - include-files have been moved around some more: there are still some + names that clash with the standard headers, but not many. + + - Unswappable processes implemented: by default only 'init' is + unswappable. This is a bit safer in low-memory conditions, as at + least init won't die due to low memory. I also made killing init + impossible: if init doesn't recognize a signal, it simply won't get + it. Some other changes ("while (1) fork();" won't kill the machine + for non-root users etc) + + - The new SCSI drivers are in. These make the kernel noticeably + bigger, but you can leave them out if you don't want them. + + - The floppy- and hd-drivers print out more debugging-info in case of + errors: this might be irritating if you have hardware that works, but + often gives soft-errors. On the other hand, some old debugging-info + was removed - notably for user-level protection errors etc. + + - Various minor fixes. I haven't made cdiffs (and I haven't gotten any + requests for them, so I probably never will), but they would be + pretty big. + +Things that I didn't have time for: + + - I wanted to rewrite the tty drivers to be more "streams-like" (ie not + an actual streams-implementation, but some of the ideas from + streams). I never got around to it: there was simply too much else + to do. + + - I got a lot of patches, and some went in, others didn't. If you + think your patch was important, please re-send it relative to the new + version. + +I'd like comments on the new system: performance / clarity of code etc. +0.97 should correct all known bugs (at least the ones I know about), but +I guess that's just wishful thinking. + +Note that the dynamic buffer-code also handles differently-sized +buffers, but that the rest of the system (block device drivers, +filesystem code etc) cannot yet take advantage of this - there is still +some coding needed. + + Linus diff --git a/kernel/0.97/linux-0.97.6.tar.gz b/kernel/0.97/linux-0.97.6.tar.gz new file mode 100644 index 00000000..8728dc3b Binary files /dev/null and b/kernel/0.97/linux-0.97.6.tar.gz differ diff --git a/kernel/0.97/linux-0.97.patch1.gz b/kernel/0.97/linux-0.97.patch1.gz new file mode 100644 index 00000000..4bcf8c09 Binary files /dev/null and b/kernel/0.97/linux-0.97.patch1.gz differ diff --git a/kernel/0.97/linux-0.97.patch2.gz b/kernel/0.97/linux-0.97.patch2.gz new file mode 100644 index 00000000..d4b1e94c Binary files /dev/null and b/kernel/0.97/linux-0.97.patch2.gz differ diff --git a/kernel/0.97/linux-0.97.patch3.gz b/kernel/0.97/linux-0.97.patch3.gz new file mode 100644 index 00000000..8cc25125 Binary files /dev/null and b/kernel/0.97/linux-0.97.patch3.gz differ diff --git a/kernel/0.97/linux-0.97.patch4.gz b/kernel/0.97/linux-0.97.patch4.gz new file mode 100644 index 00000000..e6b74936 Binary files /dev/null and b/kernel/0.97/linux-0.97.patch4.gz differ diff --git a/kernel/0.97/linux-0.97.patch5.gz b/kernel/0.97/linux-0.97.patch5.gz new file mode 100644 index 00000000..71e673ab Binary files /dev/null and b/kernel/0.97/linux-0.97.patch5.gz differ diff --git a/kernel/0.97/linux-0.97.patch6.gz b/kernel/0.97/linux-0.97.patch6.gz new file mode 100644 index 00000000..b333271e Binary files /dev/null and b/kernel/0.97/linux-0.97.patch6.gz differ diff --git a/kernel/0.97/linux-0.97.tar.gz b/kernel/0.97/linux-0.97.tar.gz new file mode 100644 index 00000000..de6ad622 Binary files /dev/null and b/kernel/0.97/linux-0.97.tar.gz differ diff --git a/kernel/0.98/linux-0.98.1.tar.gz b/kernel/0.98/linux-0.98.1.tar.gz new file mode 100644 index 00000000..3d449152 Binary files /dev/null and b/kernel/0.98/linux-0.98.1.tar.gz differ diff --git a/kernel/0.98/linux-0.98.2.tar.gz b/kernel/0.98/linux-0.98.2.tar.gz new file mode 100644 index 00000000..360db4c7 Binary files /dev/null and b/kernel/0.98/linux-0.98.2.tar.gz differ diff --git a/kernel/0.98/linux-0.98.3.tar.gz b/kernel/0.98/linux-0.98.3.tar.gz new file mode 100644 index 00000000..6754b283 Binary files /dev/null and b/kernel/0.98/linux-0.98.3.tar.gz differ diff --git a/kernel/0.98/linux-0.98.4.tar.gz b/kernel/0.98/linux-0.98.4.tar.gz new file mode 100644 index 00000000..bb218c3f Binary files /dev/null and b/kernel/0.98/linux-0.98.4.tar.gz differ diff --git a/kernel/0.98/linux-0.98.5.tar.gz b/kernel/0.98/linux-0.98.5.tar.gz new file mode 100644 index 00000000..8398788a Binary files /dev/null and b/kernel/0.98/linux-0.98.5.tar.gz differ diff --git a/kernel/0.98/linux-0.98.6.tar.gz b/kernel/0.98/linux-0.98.6.tar.gz new file mode 100644 index 00000000..8deb10a7 Binary files /dev/null and b/kernel/0.98/linux-0.98.6.tar.gz differ diff --git a/kernel/0.98/linux-0.98.patch1.gz b/kernel/0.98/linux-0.98.patch1.gz new file mode 100644 index 00000000..2c93f17c Binary files /dev/null and b/kernel/0.98/linux-0.98.patch1.gz differ diff --git a/kernel/0.98/linux-0.98.patch2.gz b/kernel/0.98/linux-0.98.patch2.gz new file mode 100644 index 00000000..71ab7b0e Binary files /dev/null and b/kernel/0.98/linux-0.98.patch2.gz differ diff --git a/kernel/0.98/linux-0.98.patch3.gz b/kernel/0.98/linux-0.98.patch3.gz new file mode 100644 index 00000000..cb5aaf30 Binary files /dev/null and b/kernel/0.98/linux-0.98.patch3.gz differ diff --git a/kernel/0.98/linux-0.98.patch4.gz b/kernel/0.98/linux-0.98.patch4.gz new file mode 100644 index 00000000..b9a87deb Binary files /dev/null and b/kernel/0.98/linux-0.98.patch4.gz differ diff --git a/kernel/0.98/linux-0.98.patch5.gz b/kernel/0.98/linux-0.98.patch5.gz new file mode 100644 index 00000000..fca40c57 Binary files /dev/null and b/kernel/0.98/linux-0.98.patch5.gz differ diff --git a/kernel/0.98/linux-0.98.patch6.gz b/kernel/0.98/linux-0.98.patch6.gz new file mode 100644 index 00000000..19f3c3cd Binary files /dev/null and b/kernel/0.98/linux-0.98.patch6.gz differ diff --git a/kernel/0.98/linux-0.98.tar.gz b/kernel/0.98/linux-0.98.tar.gz new file mode 100644 index 00000000..3c91a955 Binary files /dev/null and b/kernel/0.98/linux-0.98.tar.gz differ diff --git a/kernel/0.99/linux-0.99.tar.Z b/kernel/0.99/linux-0.99.tar.Z new file mode 100644 index 00000000..b880308b Binary files /dev/null and b/kernel/0.99/linux-0.99.tar.Z differ diff --git a/kernel/0.99/linux-0.99.zip b/kernel/0.99/linux-0.99.zip new file mode 100644 index 00000000..fb6d09fd Binary files /dev/null and b/kernel/0.99/linux-0.99.zip differ diff --git a/kernel/1.00/linux-1.0.tar.gz b/kernel/1.00/linux-1.0.tar.gz new file mode 100644 index 00000000..2a664f38 Binary files /dev/null and b/kernel/1.00/linux-1.0.tar.gz differ diff --git a/kernel/Historic/linux-0.01.tar.bz2 b/kernel/Historic/linux-0.01.tar.bz2 new file mode 100644 index 00000000..819ac3f3 Binary files /dev/null and b/kernel/Historic/linux-0.01.tar.bz2 differ diff --git a/kernel/Historic/linux-0.01.tar.bz2.sign b/kernel/Historic/linux-0.01.tar.bz2.sign new file mode 100644 index 00000000..8f19edce --- /dev/null +++ b/kernel/Historic/linux-0.01.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf1yGugalF9Dw4RAmZfAJ9Hj9AKeNfK48RILzrEaI+PeyATmQCfT1C2 +au5ArT97dLwVBBIEGU5o74s= +=N0uc +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/linux-0.01.tar.gz b/kernel/Historic/linux-0.01.tar.gz new file mode 100644 index 00000000..ed6029bb Binary files /dev/null and b/kernel/Historic/linux-0.01.tar.gz differ diff --git a/kernel/Historic/linux-0.01.tar.gz.sign b/kernel/Historic/linux-0.01.tar.gz.sign new file mode 100644 index 00000000..130df441 --- /dev/null +++ b/kernel/Historic/linux-0.01.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf0yGugalF9Dw4RAqelAJ9lafFni4f/QyJ2IqDXzW2nz/ZIogCfRPtg +uYpWffOhkyByfhUt8Lcelec= +=KnLA +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/linux-0.01.tar.sign b/kernel/Historic/linux-0.01.tar.sign new file mode 100644 index 00000000..375a6a4a --- /dev/null +++ b/kernel/Historic/linux-0.01.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLMyGugalF9Dw4RAgjQAJ9t6Be8g0FjsMybeXawbDu1FxbWLACfZLhy +0ZzxBVYDSaz+6lGqYAoGaew= +=ZJXo +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/README b/kernel/Historic/old-versions/README new file mode 100644 index 00000000..458c23e2 --- /dev/null +++ b/kernel/Historic/old-versions/README @@ -0,0 +1,55 @@ +To: Linux-Activists@BLOOM-PICAYUNE.MIT.EDU +From: torvalds@klaava.Helsinki.FI (Linus Benedict Torvalds) +Crossposted-To: alt.os.linux +Subject: Second 0.95a alpha-patch, part 1/2 +Date: 4 Apr 92 14:42:10 GMT + +This is the promised patch to 0.95a, which hopefully corrects some of +the problems encountered. This is /not/ an offical new release: it's +just a set of patches to get the same kernel I am currently running. + +Bugfixes: + +- extended partitions should finally work correctly (this release also + contains code for the hd-ioctl call, needed for fdisk). Code mostly + by hedrick. + +- I corrected my original ptrace-fix (writing a long word to another + process' data space could fail with my original patches) + +- 387-emulation bug with the instructions "fcom[p] %st(x)" which + resulted in bad results on non-387 machines with newer versions of + gcc. The emulation is still ugly, but it seems to work. + +- the cooked mode deletion/linekill bugs should be fixed. + +- various error-returns were wrong: I correted some of them (thanks to + bruce evans who pointed them out). The bad error-values resulted in + incorrect or spurious error-messages from 'rm' etc. + +- various minor fixes (including some in the hd-driver: this might help + persons with unexpected-interrupt and/or timeout errors) + +Additionally this version contains VFS-code from entropy, and a +readdir() system call needed for the VFS. The latter was inspired by +patches sent by Remy Card, who did it with a getdirents sys-call. My +version is slightly simpler, but is probably slower. Things might yet +change. + +The installation has also changed slightly: the keyboard type and +math-emulation are specified in the main Makefile. That one also +contains the -fcombine-regs flag needed for 1.40. The other makefiles +should no longer need editing. + +I've also incorporated the ps095 kernel patches: to get the actual +user-level stuff you still have to get the ps-distribution. Printer +ports /still/ aren't in there, but this time I positively /promise/ to +put it in next week. Really. + +People who have been patching their kernel might have problems getting +this patch to work: it was made against a clean 0.95a kernel. I'll +consider a patched-up kernel version 0.95c - and I'd appreciate if +future patches to me would be sent against this version. I'll still +accept older patches, or course. + + Linus diff --git a/kernel/Historic/old-versions/RELNOTES-0.01 b/kernel/Historic/old-versions/RELNOTES-0.01 new file mode 100644 index 00000000..54a5f013 --- /dev/null +++ b/kernel/Historic/old-versions/RELNOTES-0.01 @@ -0,0 +1,254 @@ + + + + Notes for linux release 0.01 + + + 0. Contents of this directory + +linux-0.01.tar.Z - sources to the kernel +bash.Z - compressed bash binary if you want to test it +update.Z - compressed update binary +RELNOTES-0.01 - this file + + + 1. Short intro + + +This is a free minix-like kernel for i386(+) based AT-machines. Full +source is included, and this source has been used to produce a running +kernel on two different machines. Currently there are no kernel +binaries for public viewing, as they have to be recompiled for different +machines. You need to compile it with gcc (I use 1.40, don't know if +1.37.1 will handle all __asm__-directives), after having changed the +relevant configuration file(s). + +As the version number (0.01) suggests this is not a mature product. +Currently only a subset of AT-hardware is supported (hard-disk, screen, +keyboard and serial lines), and some of the system calls are not yet +fully implemented (notably mount/umount aren't even implemented). See +comments or readme's in the code. + +This version is also meant mostly for reading - ie if you are interested +in how the system looks like currently. It will compile and produce a +working kernel, and though I will help in any way I can to get it +working on your machine (mail me), it isn't really supported. Changes +are frequent, and the first "production" version will probably differ +wildly from this pre-alpha-release. + +Hardware needed for running linux: + - 386 AT + - VGA/EGA screen + - AT-type harddisk controller (IDE is fine) + - Finnish keyboard (oh, you can use a US keyboard, but not + without some practise :-) + +The Finnish keyboard is hard-wired, and as I don't have a US one I +cannot change it without major problems. See kernel/keyboard.s for +details. If anybody is willing to make an even partial port, I'd be +grateful. Shouldn't be too hard, as it's tabledriven (it's assembler +though, so ...) + +Although linux is a complete kernel, and uses no code from minix or +other sources, almost none of the support routines have yet been coded. +Thus you currently need minix to bootstrap the system. It might be +possible to use the free minix demo-disk to make a filesystem and run +linux without having minix, but I don't know... + + + 2. Copyrights etc + + +This kernel is (C) 1991 Linus Torvalds, but all or part of it may be +redistributed provided you do the following: + + - Full source must be available (and free), if not with the + distribution then at least on asking for it. + + - Copyright notices must be intact. (In fact, if you distribute + only parts of it you may have to add copyrights, as there aren't + (C)'s in all files.) Small partial excerpts may be copied + without bothering with copyrights. + + - You may not distibute this for a fee, not even "handling" + costs. + +Mail me at "torvalds@kruuna.helsinki.fi" if you have any questions. + +Sadly, a kernel by itself gets you nowhere. To get a working system you +need a shell, compilers, a library etc. These are separate parts and may +be under a stricter (or even looser) copyright. Most of the tools used +with linux are GNU software and are under the GNU copyleft. These tools +aren't in the distribution - ask me (or GNU) for more info. + + + 3. Short technical overview of the kernel. + + +The linux kernel has been made under minix, and it was my original idea +to make it binary compatible with minix. That was dropped, as the +differences got bigger, but the system still resembles minix a great +deal. Some of the key points are: + + - Efficient use of the possibilities offered by the 386 chip. + Minix was written on a 8088, and later ported to other + machines - linux takes full advantage of the 386 (which is + nice if you /have/ a 386, but makes porting very difficult) + + - No message passing, this is a more traditional approach to + unix. System calls are just that - calls. This might or might + not be faster, but it does mean we can dispense with some of + the problems with messages (message queues etc). Of course, we + also miss the nice features :-p. + + - Multithreaded FS - a direct consequence of not using messages. + This makes the filesystem a bit (a lot) more complicated, but + much nicer. Coupled with a better scheduler, this means that + you can actually run several processes concurrently without + the performance hit induced by minix. + + - Minimal task switching. This too is a consequence of not using + messages. We task switch only when we really want to switch + tasks - unlike minix which task-switches whatever you do. This + means we can more easily implement 387 support (indeed this is + already mostly implemented) + + - Interrupts aren't hidden. Some people (among them Tanenbaum) + think interrupts are ugly and should be hidden. Not so IMHO. + Due to practical reasons interrupts must be mainly handled by + machine code, which is a pity, but they are a part of the code + like everything else. Especially device drivers are mostly + interrupt routines - see kernel/hd.c etc. + + - There is no distinction between kernel/fs/mm, and they are all + linked into the same heap of code. This has it's good sides as + well as bad. The code isn't as modular as the minix code, but + on the other hand some things are simpler. The different parts + of the kernel are under different sub-directories in the + source tree, but when running everything happens in the same + data/code space. + +The guiding line when implementing linux was: get it working fast. I +wanted the kernel simple, yet powerful enough to run most unix software. +The file system I couldn't do much about - it needed to be minix +compatible for practical reasons, and the minix filesystem was simple +enough as it was. The kernel and mm could be simplified, though: + + - Just one data structure for tasks. "Real" unices have task + information in several places, I wanted everything in one + place. + + - A very simple memory management algorithm, using both the + paging and segmentation capabilities of the i386. Currently + MM is just two files - memory.c and page.s, just a couple of + hundreds of lines of code. + +These decisions seem to have worked out well - bugs were easy to spot, +and things work. + + + 4. The "kernel proper" + + +All the routines handling tasks are in the subdirectory "kernel". These +include things like 'fork' and 'exit' as well as scheduling and minor +system calls like 'getpid' etc. Here are also the handlers for most +exceptions and traps (not page faults, they are in mm), and all +low-level device drivers (get_hd_block, tty_write etc). Currently all +faults lead to a exit with error code 11 (Segmentation fault), and the +system seems to be relatively stable ("crashme" hasn't - yet). + + + 5. Memory management + + +This is the simplest of all parts, and should need only little changes. +It contains entry-points for some things that the rest of the kernel +needs, but mostly copes on it's own, handling page faults as they +happen. Indeed, the rest of the kernel usually doesn't actively allocate +pages, and just writes into user space, letting mm handle any possible +'page-not-present' errors. + +Memory is dealt with in two completely different ways - by paging and +segmentation. First the 386 VM-space (4GB) is divided into a number of +segments (currently 64 segments of 64Mb each), the first of which is the +kernel memory segment, with the complete physical memory identity-mapped +into it. All kernel functions live within this area. + +Tasks are then given one segment each, to use as they wish. The paging +mechanism sees to filling the segment with the appropriate pages, +keeping track of any duplicate copies (created at a 'fork'), and making +copies on any write. The rest of the system doesn't need to know about +all this. + + + 6. The file system + + +As already mentioned, the linux FS is the same as in minix. This makes +crosscompiling from minix easy, and means you can mount a linux +partition from minix (or the other way around as soon as I implement +mount :-). This is only on the logical level though - the actual +routines are very different. + + NOTE! Minix-1.6.16 seems to have a new FS, with minor + modifications to the 1.5.10 I've been using. Linux + won't understand the new system. + +The main difference is in the fact that minix has a single-threaded +file-system and linux hasn't. Implementing a single-threaded FS is much +easier as you don't need to worry about other processes allocating +buffer blocks etc while you do something else. It also means that you +lose some of the multiprocessing so important to unix. + +There are a number of problems (deadlocks/raceconditions) that the linux +kernel needed to address due to multi-threading. One way to inhibit +race-conditions is to lock everything you need, but as this can lead to +unnecessary blocking I decided never to lock any data structures (unless +actually reading or writing to a physical device). This has the nice +property that dead-locks cannot happen. + +Sadly it has the not so nice property that race-conditions can happen +almost everywhere. These are handled by double-checking allocations etc +(see fs/buffer.c and fs/inode.c). Not letting the kernel schedule a +task while it is in supervisor mode (standard unix practise), means that +all kernel/fs/mm actions are atomic (not counting interrupts, and we are +careful when writing those) if you don't call 'sleep', so that is one of +the things we can count on. + + + 7. Apologies :-) + + +This isn't yet the "mother of all operating systems", and anyone who +hoped for that will have to wait for the first real release (1.0), and +even then you might not want to change from minix. This is a source +release for those that are interested in seeing what linux looks like, +and it's not really supported yet. Anyone with questions or suggestions +(even bug-reports if you decide to get it working on your system) is +encouraged to mail me. + + + 8. Getting it working + + +Most hardware dependancies will have to be compiled into the system, and +there a number of defines in the file "include/linux/config.h" that you +have to change to get a personalized kernel. Also you must uncomment +the right "equ" in the file boot/boot.s, telling the bootup-routine what +kind of device your A-floppy is. After that a simple "make" should make +the file "Image", which you can copy to a floppy (cp Image /dev/PS0 is +what I use with a 1.44Mb floppy). That's it. + +Without any programs to run, though, the kernel cannot do anything. You +should find binaries for 'update' and 'bash' at the same place you found +this, which will have to be put into the '/bin' directory on the +specified root-device (specified in config.h). Bash must be found under +the name '/bin/sh', as that's what the kernel currently executes. Happy +hacking. + + + Linus Torvalds "torvalds@kruuna.helsinki.fi" + Petersgatan 2 A 2 + 00140 Helsingfors 14 + FINLAND diff --git a/kernel/Historic/old-versions/RELNOTES-0.12 b/kernel/Historic/old-versions/RELNOTES-0.12 new file mode 100644 index 00000000..16e35cee --- /dev/null +++ b/kernel/Historic/old-versions/RELNOTES-0.12 @@ -0,0 +1,191 @@ + + + RELEASE NOTES FOR LINUX v0.12 + + +This is file mostly contains info on changed features of Linux, and +using old versions as a help-reference might be a good idea. + + + COPYRIGHT + +The Linux copyright will change: I've had a couple of requests to make +it compatible with the GNU copyleft, removing the "you may not +distribute it for money" condition. I agree. I propose that the +copyright be changed so that it confirms to GNU - pending approval of +the persons who have helped write code. I assume this is going to be no +problem for anybody: If you have grievances ("I wrote that code assuming +the copyright would stay the same") mail me. Otherwise The GNU copyleft +takes effect as of the first of February. If you do not know the gist +of the GNU copyright - read it. + + + INSTALLATION + +This is a SHORT install-note. The installation is very similar to 0.11, +so read that (INSTALL-0.11) too. There are a couple of programs you will +need to install linux: something that writes disk images (rawrite.exe or +NU or...) and something that can create harddisk partitions (fdisk under +xenix or older versions of dos, edpart.exe or something like that). + +NOTE! Repartitioning your harddisk will destroy all data on it (well, +not exactly, but if you know enough to get back the data you probably +didn't need this warning). So be careful. + +READ THIS THROUGH, THEN READ INSTALL-0.11, AND IF YOU ARE SURE YOU KNOW +WHAT YOU ARE DOING, CONTINUE. OTHERWISE, PANIC. OR WRITE ME FOR +EXPLANATIONS. OR DO ANYTHING BUT INSTALL LINUX - IT'S VERY SIMPLE, BUT +IF YOU DON'T KNOW WHAT YOU ARE DOING YOU'LL PROBABLY BE SORRY. I'D +RATHER ANSWER A FEW UNNECESSARY MAILS THAN GET MAIL SAYING "YOU KILLED +MY HARDDISK, BASTARD. I'M GOING TO FIND YOU, AND YOU'LL BE SORRY WHEN I +DO". + +1) back up everything you have on your harddisk - linux-0.12 is still in + beta and might do weird things. The only thing I guarantee is that + it has worked fine on /my/ machine - for all I know it might eat your + harddisk and spit it out in small pieces on any other hardware. + +2) Test out the linux boot-disk with the root file system. If it + doesn't work, check the hardware requirements, and mail me if you + still think it should work. I might not be able to help you, but + your bug-report would still be appreciated. + + Test that linux can read your harddisk at least partly: run the fdisk + program on the root-disk, and see if it barfs. If it tells you about + any partitions at all, linux can successfully read at least part of + your harddisk. + +3) Make sure that you have a free /primary/ partition. There can be 4 + primary partitions per drive: newer DOS fdisks seem to be able to + create only 2 (one primary and one extended). In that case use some + other partitioning software: edpart.exe etc. Linux fdisk currently + only tells you the partition info - it doesn't write to the disk. + + Remember to check how big your partition was, as that can be used to + tell which device Linux thinks it is. + +4) Boot up linux again, fdisk to make sure you now have the new + partition, and use mkfs to make a filesystem on one of the partitions + fdisk reports. Write "mkfs -c /dev/hdX nnn" where X is the device + number reported by linux fdisk, and nnn is the size - also reported + by fdisk. nnn is the size in /blocks/, ie kilobytes. You should be + able to use the size info to determine which partition is represented + by which device name. + +5) Mount the new disk partition: "mount /dev/hdX /user". Copy over the + root filesystem to the harddisk, eg like this: + + # for i in bin dev etc usr tmp + # do + # cp +recursive /$i /user + # done + + You caanot use just "cp +recursive / /user", as that will result in a + loop. + +6) Sync the filesystem after you have played around enough, and reboot. + + # sync + + ctrl-alt-del + + The folklore says you should do this three times before rebooting: + once should be enough, but I admit I do it three times anyway :) THIS + IS IMPORTANT! NEVER EVER FORGET TO SYNC BEFORE KILLING THE MACHINE. + +7) Change the bootdisk to understand which partition it should use as a + root filesystem. See INSTALL-0.11: it's still the word at offset + 508 into the image. You should be up and running. + + +That's it. Go back and read the INSTALL-0.11 + + + New features of 0.12, in order of appearance + (ie in the order you see them) + + Linux now prints cute dots when loading + +WoW. Run, don't walk, to see this :). Seriously, it should hopefully now +load even on machines that never got off the ground before, but +otherwise the loading hasn't changed. Implemented by drew. + + Super-VGA detection for extended alphamun modes + +I cannot guarantee it, I didn't write it, but it works great on a ET400 +SVGA card. I'm addicted to the new look with 100x40 character editing, +instead of a cramped 80x25. This only works on VGA-cards that support +higher text-resolutions, and which are correctly identified. Implemented +by d88-man. + + Job Control. + +Ok, everybody used to typing ^Z after they started a long command, and +forgot to put it in the background - now it works on linux too. Bash +knows the usualy job-control commands: bg, fg, jobs & kill. I hope +there will be no nasty surprises. Job control was implemented by +tytso@athena.mit.edu. + + Virtual consoles on EGA/VGA screens. + +You can select one of several consoles by pressing the left alt-key and +a function key at the same time. Linux should report the number of +virtual consoles available upon bootup. /dev/tty0 is now "the current" +screen, /dev/tty1 is the main console, and /dev/tty2-8 can exist +depending on your text-mode or card. + +NOTE! Scrolling is noticeably much slower with virtual consoles on a +EGA/VGA. The reason is that no longer does linux use all the screen +memory as a long buffer, but crams in several consoles in it. I think +it's worth it. + +The virtual consoles also have some new screen-handling commands: they +confirm even better to vt200 control codes than 0.11. Special graphic +characters etc: you can well use them as terminals to VMS (although +that's a shameful waste of resources). + + pty's + +Ok. I have to admit that I didn't get the hangup-code working correctly, +but that should be easy to add. The general things are there. + + select + +I've never used it, so I cannot say how well it works. My minor testing +seems to indicate that it works ok. vc's, pty's and select were +implemented by pmacdona, although I hacked it heavily. + + 387-emulation. + +It's not complete, but it works well enough to run those gcc2.0 compiled +programs I tested (few). None of the "heavy" math-functions are +implemented yet. + + Symbolic links. + +Try out a few "ln -s xx yy", and ls -l. Note that I think tar should be +recompiled to know anout them, and probably some other programs too. The +0.12 rootimage-disk has most of the recompiled fileutilities. + + Virtual memory. + +In addition to the "mkfs" program, there is now a "mkswap" program on +the root disk. The syntax is identical: "mkswap -c /dev/hdX nnn", and +again: this writes over the partition, so be careful. Swapping can then +be enabled by changing the word at offset 506 in the bootimage to the +desired device. Use the same program as for setting the root file +system (but change the 508 offset to 506 of course). + +NOTE! This has been tested by Robert Blum, who has a 2M machine, and it +allows you to run gcc without much memory. HOWEVER, I had to stop using +it, as my diskspace was eaten up by the beta-gcc-2.0, so I'd like to +hear that it still works: I've been totally unable to make a +swap-partition for even rudimentary testing since about christmastime. +Thus the new changes could possibly just have backfired on the VM, but I +doubt it. + + And that's it, I think. + +Happy hacking. + + Linus diff --git a/kernel/Historic/old-versions/RELNOTES-0.95 b/kernel/Historic/old-versions/RELNOTES-0.95 new file mode 100644 index 00000000..c97f5e4c --- /dev/null +++ b/kernel/Historic/old-versions/RELNOTES-0.95 @@ -0,0 +1,265 @@ + + + RELEASE NOTES FOR LINUX v0.95 + Linus Torvalds, March 7, 1992 + + +This is file mostly contains info on changed features of Linux, and +using old versions as a help-reference might be a good idea. + + + COPYRIGHT + +Linux-0.95 is NOT public domain software, but is copyrighted by me. The +copyright conditions are the same as those imposed by the GNU copyleft: +get a copy of the GNU copyleft at any major ftp-site (if it carries +linux, it probably carries a lot of GNU software anyway, and they all +contain the copyright). + +The copyleft is pretty detailed, but it mostly just means that you may +freely copy linux for your own use, and redistribute all/parts of it, as +long as you make source available (not necessarily in the same +distribution, but you make it clear how people can get it for nothing +more than copying costs). Any changes you make that you distribute will +also automatically fall under the GNU copyleft. + +NOTE! The linux unistd library-functions (the low-level interface to +linux: system calls etc) are excempt from the copyright - you may use +them as you wish, and using those in your binary files won't mean that +your files are automatically under the GNU copyleft. This concerns +/only/ the unistd-library and those (few) other library functions I have +written: most of the rest of the library has it's own copyrights (or is +public domain). See the library sources for details of those. + + + INSTALLATION + +This is a SHORT install-note. The installation is very similar to 0.11 +and 0.12, so you should read INSTALL-0.11 too. There are a couple of +programs you will need to install linux: something that writes disk +images (rawrite.exe or NU or...) and something that can create harddisk +partitions (fdisk under xenix or older versions of dos, edpart.exe or +something like that). + +NOTE! Repartitioning your harddisk will destroy all data on it (well, +not exactly, but if you know enough to get back the data you probably +didn't need this warning). So be careful. + +READ THIS THROUGH, THEN READ INSTALL-0.11, AND IF YOU ARE SURE YOU KNOW +WHAT YOU ARE DOING, CONTINUE. OTHERWISE, PANIC. OR WRITE ME FOR +EXPLANATIONS. OR DO ANYTHING BUT INSTALL LINUX - IT'S VERY SIMPLE, BUT +IF YOU DON'T KNOW WHAT YOU ARE DOING YOU'LL PROBABLY BE SORRY. I'D +RATHER ANSWER A FEW UNNECESSARY MAILS THAN GET MAIL SAYING "YOU KILLED +MY HARDDISK, BASTARD. I'M GOING TO FIND YOU, AND YOU'LL BE SORRY WHEN I +DO". + +Minumum files needed: + + RELNOTES-0.95 (this file) + INSTALL-0.11 (+ any other docs you might find: the FAQ etc) + bootimage-0.96.Z + rootimage-0.95.Z + rootimage-0.12.Z (for tar+compress) + rawrite.exe + some disk partitioner + +1) back up everything you have on your harddisk - linux-0.95 is still in + beta and might do weird things. The only thing I guarantee is that + it has worked fine on /my/ machine - for all I know it might eat your + harddisk and spit it out in small pieces on any other hardware. + +2) Test out the linux boot-disk with the root file system. If it + doesn't work, check the hardware requirements, and mail me if you + still think it should work. I might not be able to help you, but + your bug-report would still be appreciated. + + Linux-0.95 now has an init/login: there should be 4 logins started on + the first 4 virtual consoles. Log in as root (no password), and test + it out. Change to the other logins by pressing left-alt + FN[1-4]. + Note that booting up with a floppy as root is S..L..O..W.. - the + floppy driver has been optimized for sequential access (backups etc), + and trashes somewhat with demand-loading. + + Test that linux can read your harddisk at least partly: run the fdisk + program on the root-disk, and see if it barfs. If it tells you about + any partitions at all, linux can successfully read at least part of + your harddisk. + + NOTE! Harddisk device names and numbers have changed between versions + 0.12 and 0.95: the new numbering system was needed for the extended + partitions, and a new naming scheme was in order so that people + wouldn't cunfuse the old devices with the new ones. + + The new harddisk device names are: /dev/hd followed by an 'a' for the + first drive, or a 'b' for the second one. After that comes the + partition number, 1-4 for the primary partitions, 5- for possible + extended partitions. No number means the complete disk. Like this: + + /dev/hda the whole first harddisk (old: /dev/hd0) + /dev/hdb3 partition nr 3 on the second disk (old: /dev/hd8) + +3) Make sure that you have a free /primary/ partition. There can be 4 + primary partitions per drive: newer DOS fdisks seem to be able to + create only 2 (one primary and one extended). In that case use some + other partitioning software: edpart.exe etc. Linux fdisk currently + only tells you the partition info - it doesn't write to the disk. + + Remember to check how big your partition was, as that can be used to + tell which device Linux thinks it is. + + NOTE! Linux-0.95 /might/ recognize extended partitions: but the code + for this is utterly untested, as I don't have any of those. Do NOT + use the extended partitions unless you can verify that they are + indeed correctly set up - if my routines are wrong, writing to the + extended partitions might just overwrite some other partition + instead. Not nice. + +4) Boot up linux again, fdisk to make sure you now have the new + partition, and use mkfs to make a filesystem on one of the partitions + fdisk reports. Write "mkfs -c /dev/hdX nnn" where X is the device + number reported by linux fdisk, and nnn is the size - also reported + by fdisk. nnn is the size in /blocks/, ie kilobytes. You should be + able to use the size info to determine which partition is represented + by which device name. + +5) Mount the new disk partition: "mount /dev/hdX /mnt". Copy over the + root filesystem to the harddisk, eg like this: + + # for i in bin dev etc usr tmp + # do + # cp +recursive /$i /mnt + # done + + You caanot use just "cp +recursive / /mnt", as that will result in a + loop. + +6) Sync the filesystem after you have played around enough, and reboot. + + # sync + # lo + + (none) login: sync + + ctrl-alt-del + + THIS IS IMPORTANT! NEVER EVER FORGET TO SYNC BEFORE KILLING THE MACHINE. + +7) Change the bootdisk to understand which partition it should use as a + root filesystem. See INSTALL-0.11: it's still the word at offset + 508 into the image. You should be up and running. + + +8) When you've successfully started up with your harddisk as root, you + can mount the older rootimage (rootimage-0.12) from a floppy, and + copy over any files you find there that weren't on the newer + root-image. + + Mounting a floppy is easy: make the directory /floppy, and write: + + # mount /dev/PS0 /floppy (if you have a 3.5" drive) + + or + + # mount /dev/at0 /floppy (for 5.25" floppies) + + After that the files can be copied to your harddisk, eg: + + # cp /floppy/usr/bin/compress /usr/bin + # ln -s /usr/bin/compress /usr/bin/compress + # cp /floppy/usr/bin/tar.Z /usr/bin + # uncompress /usr/bin/tar.Z + +That's it. Now go back and read the INSTALL-0.11, until you are sure you +know what you are doing. + + + New features of 0.95, in order of appearance + (ie in the order you see them) + + Init/login + +Yeah, thanks to poe (Peter Orbaeck (sp?)), linux now boots up like a +real unix with a login-prompt. Login as root (no passwd), and change +your /etc/passwd to your hearts delight (and add other logins in +/etc/inittab etc). + + Bash is even bigger + +It's really a bummer to boot up from floppies: bash takes a long time to +load. Bash is also now so big that I couldn't fit compress and tar onto +the root-floppy: You'll probably want the old rootimage-0.12 just in +order to get tar+compress onto your harddisk. If anybody has pointers +to a simple shell that is freely distributable, it might be a good idea +to use that for the root-diskette. + +Especially with a small buffer-cache, things aren't fun. Don't worry: +linux runs much better on a harddisk. + + Virtual consoles on any (?) hardware. + +You can select one of several consoles by pressing the left alt-key and +a function key at the same time. Linux should report the number of +virtual consoles available upon bootup. /dev/tty0 is now "the current" +screen, /dev/tty1 is the main console, and /dev/tty2-8 can exist +depending on your text-mode or card. + +The virtual consoles also have some new screen-handling commands: they +confirm even better to vt200 control codes than 0.11. Special graphic +characters etc: you can well use them as terminals to VMS (although +that's a shameful waste of resources), and the PF1-4 keys work somewhat +in the application-key mode. + + Symbolic links. + +0.95 now allows symlinks to point to other symlinks etc (the maximum +depth is a rather arbitrary 5 links). 0.12 didn't like more than one +level of indirection. + + Virtual memory. + +VM under 0.95 should be better than under 0.12: no more lockups (as far +as I have seen), and you can now swap to the filesystem as well as to a +special partition. There are two programs to handle this: mkswap to set +up a swap-file/partition and swapon to start up swapping. + +mkswap needs either a partition or a file that already exists to make a +swap-area. To make a swap-file, do this: + + # dd bs=1024 count=NN if=/dev/hda of=swapfile + # mkswap swapfile NN + +The first command just makes a file that is NN blocks long (initializing +it from /dev/hda, but that could be anything). The second command then +writes the necessary setup-info into the file. To start swapping, write + + # swapon swapfile + +NOTE! 'dd' isn't on the rootdisk: you have to install some things onto +the harddisk before you can get up and running. + +NOTE2! When linux runs totally out of virtual memory, things slow down +dramatically. It tries to keep on running as long as it can, but at +least it shouldn't lock up any more. ^C should work, although you might +have to wait a while for it.. + + Faster floppies + +Ok, you don't notice this much when booting up from a floppy: bash has +grown, so it takes longer to load, and the optimizations work mostly +with sequential accesses. When you start un-taring floppies to get the +programs onto your harddisk, you'll notice that it's much faster now. +That should be about the only use for floppies under a unix: nobody in +their right mind uses floppies as filesystems. + + Better FS-independence + +Hopefully you'll never even notice this, but the filesystem has been +partly rewritten to make it less minix-fs-specific. I haven't +implemented all the VFS-patches I got, so it's still not ready, but it's +getting there, slowly. + + And that's it, I think. + +Happy hacking. + + Linus (torvalds@kruuna.helsinki.fi) diff --git a/kernel/Historic/old-versions/RELNOTES-0.95a b/kernel/Historic/old-versions/RELNOTES-0.95a new file mode 100644 index 00000000..c69cb412 --- /dev/null +++ b/kernel/Historic/old-versions/RELNOTES-0.95a @@ -0,0 +1,148 @@ +Please FIRST read the RELNOTES-0.95 file, then read this. This is only +a listing of the differences between this release and the last. [-mkj] + +CHANGES IN THE LINUX v0.95a ROOT DISKETTE +Jim Winstead Jr. - March 17, 1992 + +This file mostly contains info about the changes in the root diskette +from Linux v0.95/0.12 to Linux v0.95a. + +CHANGES + +With the release of Linux v0.95a, the maintenance of the root diskette +has been assumed by Jim Winstead Jr. (jwinstea@jarthur.Claremont.EDU). +This means there are a few large changes between the Linux 0.95 and +0.12 root floppies and the Linux 0.95a root floppy. These are +detailed (as much as I remember them) below: + +- 'bash' has been replaced with 'ash', the BSD 4.3 /bin/sh. This + freed up nearly 200k on the root floppy. However, there are + some problems with 'ash' that haven't been resolved: + + - sometimes the backspace key will not work on a virtual + console. I've found that it usually works on all _but_ one + console, so this is only a minor hinderance. + + - 'ash 'supports BSD-style job control, and this has not yet been + adapted to Linux's more POSIXish job control. This means + that 'ash' does not yet support job control, but it's being + worked upon. + +- 'tar' and 'compress' are back on the root floppy. 'tar' is + compressed, and both utilities are in /bin. + +- 'pfdisk', a disk partitioner, was added to the root floppy. + This makes it (almost) possible to install Linux on a machine + without looking at another OS. + +- the file pager 'more' has been added to the floppy. This was + added because of the addition of some documentation files on + the root floppy. + +- 'cat' has been added to /bin. + +- many utilities have been moved from /usr/bin to /bin, to + conform to the Linux Directory Structure Standard (v1.0). + These utilities are ones that are 'vital to the restoration of + other file systems in the case of a corrupting crash.' + +- 'init' and 'update' have been moved to /etc from /bin. This + was done because neither program should be executed from the + command line by any user, including root. (That means don't + put /etc in your PATH!) This has been a matter of some + controversy, but this is how it will stand until the Linux + Standards mailing list/committee decides otherwise. + +- tty64, tty65, etc, have been renamed to ttys1, ttys2, etc. + +- the directory /INSTALL was added, which contains some + documentation, and three simple shell scripts to make + installing Linux on a hard drive partition easier. These are: + + - 'mktree', which makes a directory tree on the specified + mounted device. + - 'mkdev' which creates the standard devices in the dev + directory of the specified mounted device + - 'install' which installs the programs on the root diskette + to the specified mounted device + + These programs will normally be called with ' /mnt'. + +- rootdev is different than the one on v0.95. A couple of days + after the release of 0.95, a program called 'rdev' was posted + to alt.os.linux that duplicated and extended the functionality + of rootdev. This was renamed to rootdev and replaces the old + rootdev. + +- agetty was renamed to getty, to be consistent with common Unix + practice. + +- an improved fdisk was added that correctly reports extended + partitions, (Thanks to Linus!) + +- /dev is complete, or at least more complete than the last few + releases of the root diskette, which always seemed to be a + major complaint. :) + +- /etc/issue and /etc/motd have been expanded to be a little + more informative. (Yeah, I know, big deal! :) + +- chgrp was removed. You can use chown to get the same effect, + but you just have to specify an owner, too. + +Many of these changes were discussed on alt.os.linux, or the Linux +Standards group, so they may look familiar. + +If you have questions, problems, or complaints about the root +diskette, either post to alt.os.linux, or send mail to me at +jwinstea@jarthur.Claremont.EDU. + +If you have questions, problems, or complaints about the boot diskette +or the kernel itself, post to alt.os.linux or send mail to Linus +Torvalds at torvalds@cc.helsinki.fi. + +Remember, the only stupid questions are the ones you don't ask. + +FUTURE CHANGES + +I'm already anticipating some changes for the next release, so here's +a sneak preview: + +- shared libraries. These are currently in alpha testing, and + will hopefully free up some more room on the root floppy for + more goodies. + +- a generic mtools might be added to the root floppy. + +- a better fdisk to replace the current fdisk/pfdisk pair. You + won't need to know your drive's geometry for this, and it will + know about Linux extended partitions. + +- an improved sh. I'm working on the backspace problem, and + adding job control. I'm also going to look at using the GNU + readline library for input, as long as it doesn't add + substantially to the size of sh. + +- init/getty/login may be removed from the root floppy. The + main reason they'll still on there is the backspace problem + with ash. + +- improved installation documentation. People have started work + on this already - read alt.os.linux for previews. + +- more robust installation scripts. The current ones are quick + and dirty, and work well, but I'd like to add better ones. + +- miscellaneous utilities added. I'd really like to add an + editor to the root disk, but I haven't found one small enough. + Any suggestions? + +- various other things that I can't remember right now. + +Again, mail your questions, comments and suggestions about the root +diskette to me at jwinstea@jarthur.Claremont.EDU. +-- +Jim Winstead Jr. (CSci '95) | "Catch a fish!" +Harvey Mudd College | -Geddy Lee, +jwinstea@jarthur.Claremont.EDU | San Diego Sports Arena +Disclaimer: Mine, not theirs! | January 20, 1992 diff --git a/kernel/Historic/old-versions/RELNOTES-0.97 b/kernel/Historic/old-versions/RELNOTES-0.97 new file mode 100644 index 00000000..7d8cb2f4 --- /dev/null +++ b/kernel/Historic/old-versions/RELNOTES-0.97 @@ -0,0 +1,75 @@ +Changes in 0.97: + + - The VESA-support was removed. I'd be happy to put it back once it + works on all hardware. Instead of the VESA-code, I finally put in + the automatic SVGA setup patches. See the top-level Makefile. + + - The IRQ code has solidified, and should work on all machines. Not + all of the SCSI drivers use it yet, so I expect patches for that.. + + - Serial interrupts are handled slightly differently, and performance + should be up. I've sent out a few alpha-releases, and testing seems + to indicate that's actually true this time. Reactions have ranged + from "nice" to "wonderful" :-) + + - The buffer-cache and memory management code has been edited quite a + bit. ps/free etc programs that reads kernel memory directly no + longer work, and even a recompilation won't be enough. They actually + need editing before they work. + + The buffer-cache now grows and shrinks dynamically depending on how + much free memory there is. Shift+PrintScreen will give some memory + statistics. (Ctrl+PrSc gives task-info, ALT+PrSc gives current + register values). + + The mm code changes removed some race-conditions in the VM code, and + I also tried to make the Out-of-swapspace error less severe (better + thrashing-detection etc). + + - The super-block code has been cleaned up. Especially the extended fs + needs to be edited a bit to take advantage of the new setup, and I + expect Remy Card will have a patch out eventually. + + - include-files have been moved around some more: there are still some + names that clash with the standard headers, but not many. + + - Unswappable processes implemented: by default only 'init' is + unswappable. This is a bit safer in low-memory conditions, as at + least init won't die due to low memory. I also made killing init + impossible: if init doesn't recognize a signal, it simply won't get + it. Some other changes ("while (1) fork();" won't kill the machine + for non-root users etc) + + - The new SCSI drivers are in. These make the kernel noticeably + bigger, but you can leave them out if you don't want them. + + - The floppy- and hd-drivers print out more debugging-info in case of + errors: this might be irritating if you have hardware that works, but + often gives soft-errors. On the other hand, some old debugging-info + was removed - notably for user-level protection errors etc. + + - Various minor fixes. I haven't made cdiffs (and I haven't gotten any + requests for them, so I probably never will), but they would be + pretty big. + +Things that I didn't have time for: + + - I wanted to rewrite the tty drivers to be more "streams-like" (ie not + an actual streams-implementation, but some of the ideas from + streams). I never got around to it: there was simply too much else + to do. + + - I got a lot of patches, and some went in, others didn't. If you + think your patch was important, please re-send it relative to the new + version. + +I'd like comments on the new system: performance / clarity of code etc. +0.97 should correct all known bugs (at least the ones I know about), but +I guess that's just wishful thinking. + +Note that the dynamic buffer-code also handles differently-sized +buffers, but that the rest of the system (block device drivers, +filesystem code etc) cannot yet take advantage of this - there is still +some coding needed. + + Linus diff --git a/kernel/Historic/old-versions/impure/linux-0.11.tar.bz2 b/kernel/Historic/old-versions/impure/linux-0.11.tar.bz2 new file mode 100644 index 00000000..1a6408a1 Binary files /dev/null and b/kernel/Historic/old-versions/impure/linux-0.11.tar.bz2 differ diff --git a/kernel/Historic/old-versions/impure/linux-0.11.tar.bz2.sign b/kernel/Historic/old-versions/impure/linux-0.11.tar.bz2.sign new file mode 100644 index 00000000..fdd1392e --- /dev/null +++ b/kernel/Historic/old-versions/impure/linux-0.11.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfxyGugalF9Dw4RAq8hAJ0cS3g7U74kca3oQhWAiqsQmPd7bQCghJPD +KmPbu7j9voD47NlxVSafG2g= +=sloi +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/impure/linux-0.11.tar.gz b/kernel/Historic/old-versions/impure/linux-0.11.tar.gz new file mode 100644 index 00000000..9fe5ed8c Binary files /dev/null and b/kernel/Historic/old-versions/impure/linux-0.11.tar.gz differ diff --git a/kernel/Historic/old-versions/impure/linux-0.11.tar.gz.sign b/kernel/Historic/old-versions/impure/linux-0.11.tar.gz.sign new file mode 100644 index 00000000..a37fe1e2 --- /dev/null +++ b/kernel/Historic/old-versions/impure/linux-0.11.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfxyGugalF9Dw4RAk3tAJ9DodkF35xtv5ZcldjSWEUpZywT9ACfSYS3 ++2f+epG+81mY0UaQ89iV2Q0= +=4Cph +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/impure/linux-0.11.tar.sign b/kernel/Historic/old-versions/impure/linux-0.11.tar.sign new file mode 100644 index 00000000..a1cc736c --- /dev/null +++ b/kernel/Historic/old-versions/impure/linux-0.11.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLHyGugalF9Dw4RAhV3AJsGANBdjpLEIa6Wr4bXaYsFYwNjRgCfUePq +A1atohMQb553mcb91Wnpp6A= +=fgel +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/impure/linux-0.12.tar.bz2 b/kernel/Historic/old-versions/impure/linux-0.12.tar.bz2 new file mode 100644 index 00000000..400ff4fb Binary files /dev/null and b/kernel/Historic/old-versions/impure/linux-0.12.tar.bz2 differ diff --git a/kernel/Historic/old-versions/impure/linux-0.12.tar.bz2.sign b/kernel/Historic/old-versions/impure/linux-0.12.tar.bz2.sign new file mode 100644 index 00000000..819e59fc --- /dev/null +++ b/kernel/Historic/old-versions/impure/linux-0.12.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfxyGugalF9Dw4RAryDAJsHHPPb4YyFwAm6fc5imYYkNSSC7ACeJN0w +h+7H98HPdZPQ4SydDGw1ll0= +=dKU7 +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/impure/linux-0.12.tar.gz b/kernel/Historic/old-versions/impure/linux-0.12.tar.gz new file mode 100644 index 00000000..26c11167 Binary files /dev/null and b/kernel/Historic/old-versions/impure/linux-0.12.tar.gz differ diff --git a/kernel/Historic/old-versions/impure/linux-0.12.tar.gz.sign b/kernel/Historic/old-versions/impure/linux-0.12.tar.gz.sign new file mode 100644 index 00000000..07db7c1f --- /dev/null +++ b/kernel/Historic/old-versions/impure/linux-0.12.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfxyGugalF9Dw4RAkNRAKCS6WirGqMA4bGI25lqZ/va10fOZACeMO4W +1p/+5zPViLGPUvD9MYHMw14= +=MJ6n +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/impure/linux-0.12.tar.sign b/kernel/Historic/old-versions/impure/linux-0.12.tar.sign new file mode 100644 index 00000000..f514f843 --- /dev/null +++ b/kernel/Historic/old-versions/impure/linux-0.12.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLHyGugalF9Dw4RAppBAJ9UDCLPys98H/wK18ByaN5yyXQDbQCfRsxY +djE3+UFdt7qbdQQWV9XcS88= +=wi8Q +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/impure/linux-0.95c.tar.bz2 b/kernel/Historic/old-versions/impure/linux-0.95c.tar.bz2 new file mode 100644 index 00000000..a6aecbb2 Binary files /dev/null and b/kernel/Historic/old-versions/impure/linux-0.95c.tar.bz2 differ diff --git a/kernel/Historic/old-versions/impure/linux-0.95c.tar.bz2.sign b/kernel/Historic/old-versions/impure/linux-0.95c.tar.bz2.sign new file mode 100644 index 00000000..c1d8fa47 --- /dev/null +++ b/kernel/Historic/old-versions/impure/linux-0.95c.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfwyGugalF9Dw4RAnsxAJ9/6iAmioS47mLdojpRRhJpUEnmTACfZF1b +h+tVsx+793Y2kSLBX2Ryfzo= +=hh1O +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/impure/linux-0.95c.tar.gz b/kernel/Historic/old-versions/impure/linux-0.95c.tar.gz new file mode 100644 index 00000000..9abad253 Binary files /dev/null and b/kernel/Historic/old-versions/impure/linux-0.95c.tar.gz differ diff --git a/kernel/Historic/old-versions/impure/linux-0.95c.tar.gz.sign b/kernel/Historic/old-versions/impure/linux-0.95c.tar.gz.sign new file mode 100644 index 00000000..28e871f0 --- /dev/null +++ b/kernel/Historic/old-versions/impure/linux-0.95c.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfwyGugalF9Dw4RAmDXAJ4uIfbZfNQ3kz3BUgVaL4GPLd63AgCff1xB +pBCoMVtC/4s1CzuES+RtnmU= +=cIGL +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/impure/linux-0.95c.tar.sign b/kernel/Historic/old-versions/impure/linux-0.95c.tar.sign new file mode 100644 index 00000000..e2c6cf48 --- /dev/null +++ b/kernel/Historic/old-versions/impure/linux-0.95c.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLHyGugalF9Dw4RAga1AJoCKmGVM6eCbw0yQAeXA9GkwF0GcwCfXei4 +5gsqO/Hr4G1CVzV1HBvnc9Y= +=02pz +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.11.tar.bz2 b/kernel/Historic/old-versions/linux-0.11.tar.bz2 new file mode 100644 index 00000000..0d1070b6 Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.11.tar.bz2 differ diff --git a/kernel/Historic/old-versions/linux-0.11.tar.bz2.sign b/kernel/Historic/old-versions/linux-0.11.tar.bz2.sign new file mode 100644 index 00000000..3b463188 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.11.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfyyGugalF9Dw4RAgRJAJ94tY3f7Oo10tDvpWgcKggvy3BseACdGmbP +5KBxTc/By3zzHlnA4ia6J9U= +=TyO6 +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.11.tar.gz b/kernel/Historic/old-versions/linux-0.11.tar.gz new file mode 100644 index 00000000..e6461824 Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.11.tar.gz differ diff --git a/kernel/Historic/old-versions/linux-0.11.tar.gz.sign b/kernel/Historic/old-versions/linux-0.11.tar.gz.sign new file mode 100644 index 00000000..6cacb860 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.11.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfyyGugalF9Dw4RAiK1AJwO9fD82BasA3HIiHNEFhGRRNZdbgCfa/rY +kGDmKQ16lCyLanQsoVovRTw= +=fPZ9 +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.11.tar.sign b/kernel/Historic/old-versions/linux-0.11.tar.sign new file mode 100644 index 00000000..ca703dd2 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.11.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLIyGugalF9Dw4RAsQEAJ9/givvJj6X/awIv+K4nPA39kbbCwCcDh3i +mjyUKwW9SIoXeOQ+w/Zub04= +=vlms +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.12.tar.bz2 b/kernel/Historic/old-versions/linux-0.12.tar.bz2 new file mode 100644 index 00000000..923dd7fd Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.12.tar.bz2 differ diff --git a/kernel/Historic/old-versions/linux-0.12.tar.bz2.sign b/kernel/Historic/old-versions/linux-0.12.tar.bz2.sign new file mode 100644 index 00000000..98373208 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.12.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfyyGugalF9Dw4RAsdMAJ4+Y8J5BihshA25vGFtCp4aYg8SVwCfUkF9 +sTNGMmV4WVbEQ7WZdOSZhv0= +=g12J +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.12.tar.gz b/kernel/Historic/old-versions/linux-0.12.tar.gz new file mode 100644 index 00000000..e6d9969b Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.12.tar.gz differ diff --git a/kernel/Historic/old-versions/linux-0.12.tar.gz.sign b/kernel/Historic/old-versions/linux-0.12.tar.gz.sign new file mode 100644 index 00000000..2e60dff9 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.12.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfyyGugalF9Dw4RAqjSAKCDCmQ644kZi+9LzxgLbhNcPsmJzQCeK1ic +SXNYni5DRzsN7Kh6XkMqPAg= +=SfxW +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.12.tar.sign b/kernel/Historic/old-versions/linux-0.12.tar.sign new file mode 100644 index 00000000..d30013b2 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.12.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLIyGugalF9Dw4RAlQ/AJ4g5ub4aJW2EOK12zvEn72ZjmNBEQCfVB+S +xPYNNAAiqWkGlPxineYyKgI= +=52Gj +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.95.tar.bz2 b/kernel/Historic/old-versions/linux-0.95.tar.bz2 new file mode 100644 index 00000000..65a7abf9 Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.95.tar.bz2 differ diff --git a/kernel/Historic/old-versions/linux-0.95.tar.bz2.sign b/kernel/Historic/old-versions/linux-0.95.tar.bz2.sign new file mode 100644 index 00000000..442f1349 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.95.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf0yGugalF9Dw4RAvXTAJ4zZ7VSRsfeHaKsrUFZSCz2jL+FVQCcDEYM +JEO7fv2MEAZ+j3ULjmMnu+c= +=DUdZ +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.95.tar.gz b/kernel/Historic/old-versions/linux-0.95.tar.gz new file mode 100644 index 00000000..5930ee03 Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.95.tar.gz differ diff --git a/kernel/Historic/old-versions/linux-0.95.tar.gz.sign b/kernel/Historic/old-versions/linux-0.95.tar.gz.sign new file mode 100644 index 00000000..5e3feed1 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.95.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf0yGugalF9Dw4RAutOAJ9gyVDrN29V+KrQ8yo6CQdMTq6XFgCffq5P +v5IDQOvL/wKKESgJETCetJs= +=VhAz +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.95.tar.sign b/kernel/Historic/old-versions/linux-0.95.tar.sign new file mode 100644 index 00000000..78a6ddc9 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.95.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLJyGugalF9Dw4RAjlTAKCGRO1rMNAv2WLnUfDcrq2ZtwyCogCcDZGY +ttc55w2r9WEyrGQ4WAYnxPA= +=fE1n +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.95a.tar.bz2 b/kernel/Historic/old-versions/linux-0.95a.tar.bz2 new file mode 100644 index 00000000..4a2d4e67 Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.95a.tar.bz2 differ diff --git a/kernel/Historic/old-versions/linux-0.95a.tar.bz2.sign b/kernel/Historic/old-versions/linux-0.95a.tar.bz2.sign new file mode 100644 index 00000000..d270313a --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.95a.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf0yGugalF9Dw4RAgMSAJ40K0V7umMcrPFPlKvR5ZPVjnQYWACff1Np +xOKli+G43Of0gJOHgxpTg8A= +=RLiV +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.95a.tar.gz b/kernel/Historic/old-versions/linux-0.95a.tar.gz new file mode 100644 index 00000000..3b71528a Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.95a.tar.gz differ diff --git a/kernel/Historic/old-versions/linux-0.95a.tar.gz.sign b/kernel/Historic/old-versions/linux-0.95a.tar.gz.sign new file mode 100644 index 00000000..9175a1af --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.95a.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf0yGugalF9Dw4RAmotAJ9P+1AHSltEKC7R4cHwW/qzwWIV7wCeJja3 +JDPcAFn25KKQo2uyi8Eyauo= +=G9cK +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.95a.tar.sign b/kernel/Historic/old-versions/linux-0.95a.tar.sign new file mode 100644 index 00000000..5e138ef5 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.95a.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLJyGugalF9Dw4RAgt5AJ9cN2JvOvZOYkJOkiwoUilV8h3oigCfSFGs +TzkfkhMbLTGKRr3/R5qTcWI= +=NN4b +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96a.patch2.bz2 b/kernel/Historic/old-versions/linux-0.96a.patch2.bz2 new file mode 100644 index 00000000..5375eb6e Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96a.patch2.bz2 differ diff --git a/kernel/Historic/old-versions/linux-0.96a.patch2.bz2.sign b/kernel/Historic/old-versions/linux-0.96a.patch2.bz2.sign new file mode 100644 index 00000000..23e738f0 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96a.patch2.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf0yGugalF9Dw4RAr/qAJ4nVh1pspLj1vHSsQGe/qYQiUhgywCdGbuU +DHbIoDQMVLmkqjs0Df+jD2I= +=D7NJ +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96a.patch2.gz b/kernel/Historic/old-versions/linux-0.96a.patch2.gz new file mode 100644 index 00000000..d4d4aeec Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96a.patch2.gz differ diff --git a/kernel/Historic/old-versions/linux-0.96a.patch2.gz.sign b/kernel/Historic/old-versions/linux-0.96a.patch2.gz.sign new file mode 100644 index 00000000..62567732 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96a.patch2.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf0yGugalF9Dw4RAohXAJ0euzgZwdxB18V3D+1qf/epUYQPXwCePYCe +OQGw5CupnNGDvPS1DAEez2o= +=IB0E +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96a.patch2.sign b/kernel/Historic/old-versions/linux-0.96a.patch2.sign new file mode 100644 index 00000000..7e7393c4 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96a.patch2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLJyGugalF9Dw4RAqunAJ4h675FxDkZb7nEmHLhxmp6Pv2xGwCeP+VD +ha5p9n9/j6oRfVOpfGJpoqU= +=ENNx +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96a.patch3.bz2 b/kernel/Historic/old-versions/linux-0.96a.patch3.bz2 new file mode 100644 index 00000000..1aa9f78d Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96a.patch3.bz2 differ diff --git a/kernel/Historic/old-versions/linux-0.96a.patch3.bz2.sign b/kernel/Historic/old-versions/linux-0.96a.patch3.bz2.sign new file mode 100644 index 00000000..132a950d --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96a.patch3.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfzyGugalF9Dw4RAnn2AKCI6esY78SCmRnmHo23E0Wviyhz4wCcCXf6 +n2RfJiNmGCLaFqcCBEqo95A= +=h2Cj +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96a.patch3.gz b/kernel/Historic/old-versions/linux-0.96a.patch3.gz new file mode 100644 index 00000000..6cc4edac Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96a.patch3.gz differ diff --git a/kernel/Historic/old-versions/linux-0.96a.patch3.gz.sign b/kernel/Historic/old-versions/linux-0.96a.patch3.gz.sign new file mode 100644 index 00000000..7d2fa31f --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96a.patch3.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfzyGugalF9Dw4RAgCUAJ9c5ztqcv9/F8MJ0OYvdgNlrVVYqACfYI1u +DvZVbU5SVJSdWGCh9+yOGz8= +=rb+3 +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96a.patch3.sign b/kernel/Historic/old-versions/linux-0.96a.patch3.sign new file mode 100644 index 00000000..7f6a7666 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96a.patch3.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLJyGugalF9Dw4RAq6JAJ9anw1mRmy3/8ebtC2hAIyH3eRLxQCfdg2R +VwEoFa119A2xE/dlwHPIoOw= +=DSsl +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96a.patch4.bz2 b/kernel/Historic/old-versions/linux-0.96a.patch4.bz2 new file mode 100644 index 00000000..fcbd2802 Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96a.patch4.bz2 differ diff --git a/kernel/Historic/old-versions/linux-0.96a.patch4.bz2.sign b/kernel/Historic/old-versions/linux-0.96a.patch4.bz2.sign new file mode 100644 index 00000000..0d8d2b33 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96a.patch4.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfzyGugalF9Dw4RAriNAKCUSCNWetKvopVZ5vR4buBLrt1RgwCeIRsO +AZwaD0EmSBw2fp8ZCgEiyWM= +=8VvK +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96a.patch4.gz b/kernel/Historic/old-versions/linux-0.96a.patch4.gz new file mode 100644 index 00000000..1ece3d13 Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96a.patch4.gz differ diff --git a/kernel/Historic/old-versions/linux-0.96a.patch4.gz.sign b/kernel/Historic/old-versions/linux-0.96a.patch4.gz.sign new file mode 100644 index 00000000..c9313400 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96a.patch4.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfzyGugalF9Dw4RAi9tAKCHfWSHJgzxP9LNBoNHOlNnGMOYMACeK8hg +ys3jmHlEZGkFE0e2kfU47Vo= +=mHCt +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96a.patch4.sign b/kernel/Historic/old-versions/linux-0.96a.patch4.sign new file mode 100644 index 00000000..0fbc0b83 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96a.patch4.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLJyGugalF9Dw4RAoa+AJ41QH9Ilxok4ohyQ22+OOZB6LgYnwCfb1df +yL04KwwdO03JpxZPWbVsKSk= +=r3xI +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96a.tar.bz2 b/kernel/Historic/old-versions/linux-0.96a.tar.bz2 new file mode 100644 index 00000000..6440736c Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96a.tar.bz2 differ diff --git a/kernel/Historic/old-versions/linux-0.96a.tar.bz2.sign b/kernel/Historic/old-versions/linux-0.96a.tar.bz2.sign new file mode 100644 index 00000000..4fd958d1 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96a.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfyyGugalF9Dw4RAkQzAJ90wqlWjO0vpB0kuLXl3d0AHWE4CgCeKmLH +KcHPIBclEHkKkNHdCXc0kQc= +=iyFd +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96a.tar.gz b/kernel/Historic/old-versions/linux-0.96a.tar.gz new file mode 100644 index 00000000..66f97f59 Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96a.tar.gz differ diff --git a/kernel/Historic/old-versions/linux-0.96a.tar.gz.sign b/kernel/Historic/old-versions/linux-0.96a.tar.gz.sign new file mode 100644 index 00000000..2fd1a9ff --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96a.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfxyGugalF9Dw4RAv9/AJ4k2aJr2Q+G9Nkejj2Pks5cFxejAACfSDYq +w4JAkXqaLDKsPRMMqsmXaXY= +=sTt3 +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96a.tar.sign b/kernel/Historic/old-versions/linux-0.96a.tar.sign new file mode 100644 index 00000000..85d27c4e --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96a.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLJyGugalF9Dw4RAs2JAJ90wOlHj+uf7aVS2E8TLwTWBT42HwCghSiG +FpR3161vKSRMtQVyYK14+2E= +=D2CE +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96b.patch1.bz2 b/kernel/Historic/old-versions/linux-0.96b.patch1.bz2 new file mode 100644 index 00000000..2a7534f1 Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96b.patch1.bz2 differ diff --git a/kernel/Historic/old-versions/linux-0.96b.patch1.bz2.sign b/kernel/Historic/old-versions/linux-0.96b.patch1.bz2.sign new file mode 100644 index 00000000..d765cc8b --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96b.patch1.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf0yGugalF9Dw4RAmf9AJ41kyu/1wzPs3Sjz0KJAYy8hHrdIwCfRB8b +29mp+j5hsEV986Kcu64ydVY= +=EeM1 +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96b.patch1.gz b/kernel/Historic/old-versions/linux-0.96b.patch1.gz new file mode 100644 index 00000000..19ed2326 Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96b.patch1.gz differ diff --git a/kernel/Historic/old-versions/linux-0.96b.patch1.gz.sign b/kernel/Historic/old-versions/linux-0.96b.patch1.gz.sign new file mode 100644 index 00000000..98e1b9d1 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96b.patch1.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfzyGugalF9Dw4RApZzAKCQlkBZj2z6r+TQ6wELS3bKTkGIBgCfZwlP +6u7oODCQE4jLUf4MyErmH6E= +=JyKh +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96b.patch1.sign b/kernel/Historic/old-versions/linux-0.96b.patch1.sign new file mode 100644 index 00000000..5f10dead --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96b.patch1.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLJyGugalF9Dw4RAgeQAKCJV1vWyVcdH3XSlIHgKVmNR02dLACfYdzK +ACvdB0TzY2glZjTd+q/ClB4= +=2vpP +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96b.patch2.bz2 b/kernel/Historic/old-versions/linux-0.96b.patch2.bz2 new file mode 100644 index 00000000..3b83f9a2 Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96b.patch2.bz2 differ diff --git a/kernel/Historic/old-versions/linux-0.96b.patch2.bz2.sign b/kernel/Historic/old-versions/linux-0.96b.patch2.bz2.sign new file mode 100644 index 00000000..46d65cbb --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96b.patch2.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfzyGugalF9Dw4RAozrAJ44FNxssyTOgruu2VatdRLIh6+p7gCfRaDC +YMvbMeSfnT7Fs8c2/oB2SOI= +=f6cj +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96b.patch2.gz b/kernel/Historic/old-versions/linux-0.96b.patch2.gz new file mode 100644 index 00000000..f452754f Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96b.patch2.gz differ diff --git a/kernel/Historic/old-versions/linux-0.96b.patch2.gz.sign b/kernel/Historic/old-versions/linux-0.96b.patch2.gz.sign new file mode 100644 index 00000000..b811ec02 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96b.patch2.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfzyGugalF9Dw4RAkSGAKCFNWaJY5cuS4YwfPat3Zi7NES2jgCfZGyf +3MZ4Z1a+1E8LfMXxlw4sn9A= +=wdgO +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96b.patch2.sign b/kernel/Historic/old-versions/linux-0.96b.patch2.sign new file mode 100644 index 00000000..a468e962 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96b.patch2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLKyGugalF9Dw4RAqKgAJoDoHiM3PsMTSaiKyCL2Ph+Eo4dugCgi+Pv +t+SlOE7KcT+Lu7zZjIdd/9E= +=3rsI +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96b.tar.bz2 b/kernel/Historic/old-versions/linux-0.96b.tar.bz2 new file mode 100644 index 00000000..58e8075d Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96b.tar.bz2 differ diff --git a/kernel/Historic/old-versions/linux-0.96b.tar.bz2.sign b/kernel/Historic/old-versions/linux-0.96b.tar.bz2.sign new file mode 100644 index 00000000..05e0e15d --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96b.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfzyGugalF9Dw4RAl5XAJ4+zugYxhoTB8tqPcNNiz8nGEy9cACfYvUz +saBdKilyuCy/7zyeAPgxmqk= +=CpFW +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96b.tar.gz b/kernel/Historic/old-versions/linux-0.96b.tar.gz new file mode 100644 index 00000000..f3b34611 Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96b.tar.gz differ diff --git a/kernel/Historic/old-versions/linux-0.96b.tar.gz.sign b/kernel/Historic/old-versions/linux-0.96b.tar.gz.sign new file mode 100644 index 00000000..c0cda4bd --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96b.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfyyGugalF9Dw4RAhumAJ909b0dcAF75RB/Uw9eLIHMPviiVQCfdNBJ +vAUEiVOy2r3qBmNNO9zaW7I= +=aEdO +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96b.tar.sign b/kernel/Historic/old-versions/linux-0.96b.tar.sign new file mode 100644 index 00000000..b7ed0757 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96b.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLKyGugalF9Dw4RArjkAJ47qIYDTahmK73inJDiDp2oRUY5nACdEaHg +N80Iz+x5Ik9NN3l0PpD8+Vs= +=g5UO +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96c.patch1 b/kernel/Historic/old-versions/linux-0.96c.patch1 new file mode 100644 index 00000000..7425d7d7 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96c.patch1 @@ -0,0 +1,4265 @@ +*** 0.96c/linux/Makefile Sun Jul 5 03:09:23 1992 +--- linux/Makefile Sat Jul 11 20:11:52 1992 +*************** +*** 89,95 **** + + Version: + @./makever.sh +! @echo \#define UTS_RELEASE \"0.96c-`cat .version`\" > include/linux/config_rel.h + @echo \#define UTS_VERSION \"`date +%D`\" > include/linux/config_ver.h + touch include/linux/config.h + +--- 89,95 ---- + + Version: + @./makever.sh +! @echo \#define UTS_RELEASE \"0.96c.pl1-`cat .version`\" > include/linux/config_rel.h + @echo \#define UTS_VERSION \"`date +%D`\" > include/linux/config_ver.h + touch include/linux/config.h + +*** 0.96c/linux/boot/setup.S Tue May 19 03:36:58 1992 +--- linux/boot/setup.S Thu Jul 9 14:41:55 1992 +*************** +*** 189,197 **** + 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 :-). +--- 189,198 ---- + out #0xA1,al + .word 0x00eb,0x00eb + mov al,#0xFF ! mask off all interrupts for now + out #0xA1,al ++ .word 0x00eb,0x00eb ++ mov al,#0xFB ! mask all irq's but irq2 which ++ out #0x21,al ! is cascaded + + ! well, that certainly wasn't fun :-(. Hopefully it works, and we don't + ! need no steenking BIOS anyway (except for the initial loading :-). +*************** +*** 241,250 **** + push ds + push cs + pop ds +! mov ax,#0xc000 + mov es,ax + lea si,msg1 +! call prtstr + flush: in al,#0x60 ! Flush the keyboard buffer + cmp al,#0x82 + jb nokey +--- 242,316 ---- + push ds + push cs + pop ds +! +! ! First try and execute a VESA BIOS call +! +! mov ax,#0x4f00 ! AX = VESA BIOS func RETURN SVGA Info +! push cs +! pop es +! lea di,vib ! ES:[DI] -> VESA Information Block Ptr +! int 0x10 +! +! cmp ax,#0x004f ! Check result status +! jne novesa ! VESA BIOS not supported or failed +! +! ! OK! We got a VESA BIOS, let's figure out what we can do! +! +! ! Print out the VESA information from the VIB +! +! lea si,vib ! This should print out VESA +! lodsb +! call prnt1 +! lodsb +! call prnt1 +! lodsb +! call prnt1 +! lodsb +! call prnt1 +! call space +! +! mov al,vib+5 ! This is the version of VESA supported +! call dprnt +! mov al,#0x2e +! call prnt1 +! mov al,vib+4 +! call dprnt +! call space +! +! push ds +! lds si,vib+6 ! This prints out the OEM string +! call prtstr +! call space +! pop ds +! +! mov al,vib+10 ! This prints out the Vesa Capabilities +! call dprnt +! mov al,vib+11 +! call dprnt +! mov al,vib+12 +! call dprnt +! mov al,vib+13 +! call dprnt +! +! push ds ! Finally, go through the list of modes +! lds si,vib+14 +! model: lodsw ! Get mode number +! cmp ax,#0xFFFF +! je isvesa +! call addmod ! Check to see if this is a TEXT mode +! jmp model +! +! isvesa: call docr +! pop ds +! lea si,dscvesa +! lea di,movesa +! lea cx,selmod +! jmp cx +! +! novesa: mov ax,#0xc000 + mov es,ax + lea si,msg1 +! call prtstr ! Press to see SVGA-modes ... + flush: in al,#0x60 ! Flush the keyboard buffer + cmp al,#0x82 + jb nokey +*************** +*** 463,485 **** + mov al,#0x55 + xor al,#0xea + cmp al,bh +! jne novid7 + lea si,dscvideo7 + lea di,movideo7 + selmod: push si +! lea si,msg2 + call prtstr +! xor cx,cx +! mov cl,(di) + pop si + push si + push cx + tbl: pop bx + push bx +! mov al,bl +! sub al,cl +! call dprnt + call spcing + lodsw + xchg al,ah + call dprnt +--- 529,566 ---- + mov al,#0x55 + xor al,#0xea + cmp al,bh +! je isvideo7 +! lea cx,set8x8 +! jmp cx +! isvideo7: + lea si,dscvideo7 + lea di,movideo7 ++ ++ ! Upon Entry to SELMOD, SI -> list of Modes, DI -> List of Mode Numbers ++ + selmod: push si +! lea si,msg2 ! Numb: Mode: COLSxROWS + call prtstr +! mov cx,(di) ! This gets Number of Modes in list + pop si + push si + push cx + tbl: pop bx + push bx +! mov ax,bx +! sub ax,cx +! call hprntl ! Print out selection number +! push ax + call spcing ++ pop ax ++ push di ++ add ax,ax ++ add ax,#2 ++ add di,ax ++ mov ax,(di) ++ call hprntl ! Print out MODE number ++ call spcing ++ pop di + lodsw + xchg al,ah + call dprnt +*************** +*** 493,499 **** + loop tbl + pop cx + call docr +! lea si,msg3 + call prtstr + pop si + add cl,#0x80 +--- 574,580 ---- + loop tbl + pop cx + call docr +! lea si,msg3 ! Choose Mode Number + call prtstr + pop si + add cl,#0x80 +*************** +*** 509,526 **** + nozero: sub al,#0x80 + dec al + xor ah,ah + add di,ax + inc di +! push ax +! mov al,(di) +! int 0x10 + pop ax +- shl ax,#1 + add si,ax +! lodsw + pop ds + ret +! novid7: + mov ax,#0x1112 + mov bl,#0 + int 0x10 ! use 8x8 font set (50 lines on VGA) +--- 590,627 ---- + nozero: sub al,#0x80 + dec al + xor ah,ah ++ shl ax,#1 ++ push ax + add di,ax + inc di +! inc di +! mov ax,(di) ! AX = Mode +! cmp ah,#0 +! jne setvesa +! int 0x10 ! Set OLD style mode +! +! retmode: + pop ax + add si,ax +! lodsw ! Get COLSxROWS + pop ds + ret +! +! setvesa: +! pop bx +! cmp ah,#0xFF ! Special, mode FF, set 8x8 font +! je set8x8 +! +! push bx +! mov bx,ax ! Mode to set +! mov ax,#0x4f02 ! Set VESA mode +! int 0x10 +! +! jmp retmode +! +! ! If we can't find the adapter in the table, at least set 80x50 +! +! set8x8: + mov ax,#0x1112 + mov bl,#0 + int 0x10 ! use 8x8 font set (50 lines on VGA) +*************** +*** 541,557 **** + mov ax,#0x5032 ! return 80x50 + ret + + ! Routine that 'tabs' to next col. + + spcing: mov al,#0x2e +- call prnt1 +- mov al,#0x20 + call prnt1 +! mov al,#0x20 + call prnt1 +! mov al,#0x20 + call prnt1 +! mov al,#0x20 + call prnt1 + ret + +--- 642,724 ---- + mov ax,#0x5032 ! return 80x50 + ret + ++ ! Routine to add mode in ax to VESA selection table ++ ++ addmod: push cx ++ push ds ++ push es ++ push di ++ push bx ++ push dx ++ push ax ++ ++ mov cx,ax ! CX = VESA mode number ++ push cs ++ pop es ++ lea di,mib ! ES:[DI] -> Mode Information Block ++ mov ax,#0x4f01 ! AX = Get VESA Mode Info ++ int 0x10 ++ ++ cmp ax,#0x004f ! If fails, assume it's not a TEXT mode ++ jne adfail ++ ++ push cs ++ pop ds ! Make DS contain something reasonable ++ ++ mov ax,mib ! Get Mode Attributes field ++ and al,#0x12 ! Mask Text and Extended bits ++ cmp al,#0x02 ! Text and Extended info available? ++ jne adfail ++ ++ call space ++ ++ mov ax,mib+18 ! Horizontal Resolution ++ mov bl,mib+22 ! X Char Size ++ div bl ++ ! HACK: For some reason, my Diamond Stealth card returns 160 cols for its ++ ! 132 coloumn modes, so don't return any sizes > 132? ++ sub al,#132 ++ jbe orgcol ++ sub al,al ++ orgcol: add al,#132 ! MIN(cols, 132) ++ mov dh,al ! Put num cols in DH ++ mov ax,mib+20 ! Vertical Resolution ++ mov bl,mib+23 ! Y Char Size ++ div bl ++ mov dl,al ! Put num rows in DL ++ ++ mov bx,movesa ! Get current number of video modes ++ lea di,movesa ++ inc (di) ! This is a NEW mode ++ add bx,bx ++ add di,bx ++ add di,#2 ++ pop ax ! Get Mode number back ++ push ax ++ mov (di),ax ! Mode number ++ lea di,dscvesa ++ add di,bx ++ mov (di),dx ! Screen resolution ++ ++ adfail: pop ax ++ pop dx ++ pop bx ++ pop di ++ pop es ++ pop ds ++ pop cx ++ ++ ret ++ + ! Routine that 'tabs' to next col. + + spcing: mov al,#0x2e + call prnt1 +! space3: mov al,#0x20 + call prnt1 +! space2: mov al,#0x20 + call prnt1 +! space: mov al,#0x20 + call prnt1 + ret + +*************** +*** 564,569 **** +--- 731,769 ---- + jmp prtstr + fin: ret + ++ ! Routine to print out HEX values on screen. ++ ! The value to be printed is in the AX register. ++ ++ hprntl: xchg ah,al ++ call hprnt ++ xchg ah,al ++ call hprnt ++ ret ++ ++ ! Routine to print out HEX values on the screen ++ ! The valueto be printed is in the AL register. AH is preserved. ++ ++ hprnt: push ax ++ shr al,4 ++ and al,#0xf ++ call hprnt1 ++ pop ax ++ push ax ++ and al,#0xf ++ call hprnt1 ++ pop ax ++ ret ++ ++ ! Routine to print out one HEX digit on the screen. ++ ! The value to be printed is in al (0-F) ++ ++ hprnt1: cmp al,#10 ++ jl hdec ++ add al,#7 ! Convert 10-15 to A-F ++ hdec: add al,#0x30 ! Convert to ASCII ++ call prnt1 ! print it ++ ret ++ + ! Routine to print a decimal value on screen, the value to be + ! printed is put in al (i.e 0-255). + +*************** +*** 635,641 **** + + msg1: .ascii "Press to see SVGA-modes available or any other key to continue." + db 0x0d, 0x0a, 0x0a, 0x00 +! msg2: .ascii "Mode: COLSxROWS:" + db 0x0d, 0x0a, 0x0a, 0x00 + msg3: .ascii "Choose mode by pressing the corresponding number." + db 0x0d, 0x0a, 0x00 +--- 835,841 ---- + + msg1: .ascii "Press to see SVGA-modes available or any other key to continue." + db 0x0d, 0x0a, 0x0a, 0x00 +! msg2: .ascii "Numb: Mode: COLSxROWS:" + db 0x0d, 0x0a, 0x0a, 0x00 + msg3: .ascii "Choose mode by pressing the corresponding number." + db 0x0d, 0x0a, 0x00 +*************** +*** 647,662 **** + + ! Manufacturer: Numofmodes: Mode: + +! moati: .byte 0x02, 0x23, 0x33 +! moahead: .byte 0x05, 0x22, 0x23, 0x24, 0x2f, 0x34 +! mocandt: .byte 0x02, 0x60, 0x61 +! mocirrus: .byte 0x04, 0x1f, 0x20, 0x22, 0x31 +! moeverex: .byte 0x0a, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40 +! mogenoa: .byte 0x0a, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78 +! moparadise: .byte 0x02, 0x55, 0x54 +! motrident: .byte 0x07, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a +! motseng: .byte 0x05, 0x26, 0x2a, 0x23, 0x24, 0x22 +! movideo7: .byte 0x06, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45 + + ! msb = Cols lsb = Rows: + +--- 847,863 ---- + + ! Manufacturer: Numofmodes: Mode: + +! moati: .word 0x02, 0x23, 0x33 +! moahead: .word 0x05, 0x22, 0x23, 0x24, 0x2f, 0x34 +! mocandt: .word 0x02, 0x60, 0x61 +! mocirrus: .word 0x04, 0x1f, 0x20, 0x22, 0x31 +! moeverex: .word 0x0a, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40 +! mogenoa: .word 0x0a, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78 +! moparadise: .word 0x02, 0x55, 0x54 +! motrident: .word 0x07, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a +! motseng: .word 0x05, 0x26, 0x2a, 0x23, 0x24, 0x22 +! movideo7: .word 0x06, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45 +! movesa: .word 0x02, 0x03, 0xFFFF, 254*0 + + ! msb = Cols lsb = Rows: + +*************** +*** 670,676 **** +--- 871,881 ---- + dsctrident: .word 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c + dsctseng: .word 0x503c, 0x6428, 0x8419, 0x841c, 0x842c + dscvideo7: .word 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c ++ dscvesa: .word 0x5019, 0x5032, 254*0 + ++ vib: .word 256*0 ++ mib: .word 256*0 ++ + .text + endtext: + .data +*** 0.96c/linux/fs/inode.c Thu Jul 2 00:42:04 1992 +--- linux/fs/inode.c Sat Jul 11 01:37:05 1992 +*************** +*** 252,257 **** +--- 252,258 ---- + } + inode->i_dev = dev; + inode->i_ino = nr; ++ inode->i_flags = inode->i_sb->s_flags; + read_inode(inode); + return inode; + } +*** 0.96c/linux/fs/open.c Thu Jul 2 00:42:04 1992 +--- linux/fs/open.c Sat Jul 11 03:58:46 1992 +*************** +*** 73,78 **** +--- 73,82 ---- + iput(inode); + return -EACCES; + } ++ if (IS_RDONLY(inode)) { ++ iput(inode); ++ return -EROFS; ++ } + inode->i_size = length; + if (inode->i_op && inode->i_op->truncate) + inode->i_op->truncate(inode); +*************** +*** 91,97 **** + return -EBADF; + if (!(inode = file->f_inode)) + return -ENOENT; +! if (S_ISDIR(inode->i_mode) || !(file->f_flags & 2)) + return -EACCES; + inode->i_size = length; + if (inode->i_op && inode->i_op->truncate) +--- 95,101 ---- + return -EBADF; + if (!(inode = file->f_inode)) + return -ENOENT; +! if (S_ISDIR(inode->i_mode) || !(file->f_mode & 2)) + return -EACCES; + inode->i_size = length; + if (inode->i_op && inode->i_op->truncate) +*************** +*** 112,117 **** +--- 116,125 ---- + + if (!(inode=namei(filename))) + return -ENOENT; ++ if (IS_RDONLY(inode)) { ++ iput(inode); ++ return -EROFS; ++ } + if (times) { + if ((current->euid != inode->i_uid) && !suser()) { + iput(inode); +*************** +*** 215,220 **** +--- 223,230 ---- + return -ENOENT; + if ((current->euid != inode->i_uid) && !suser()) + return -EPERM; ++ if (IS_RDONLY(inode)) ++ return -EROFS; + inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777); + inode->i_dirt = 1; + return 0; +*************** +*** 230,235 **** +--- 240,249 ---- + iput(inode); + return -EPERM; + } ++ if (IS_RDONLY(inode)) { ++ iput(inode); ++ return -EROFS; ++ } + inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777); + inode->i_dirt = 1; + iput(inode); +*************** +*** 245,250 **** +--- 259,266 ---- + return -EBADF; + if (!(inode = file->f_inode)) + return -ENOENT; ++ if (IS_RDONLY(inode)) ++ return -EROFS; + if ((current->euid == inode->i_uid && user == inode->i_uid && + (in_group_p(group) || group == inode->i_gid)) || + suser()) { +*************** +*** 262,267 **** +--- 278,287 ---- + + if (!(inode = lnamei(filename))) + return -ENOENT; ++ if (IS_RDONLY(inode)) { ++ iput(inode); ++ return -EROFS; ++ } + if ((current->euid == inode->i_uid && user == inode->i_uid && + (in_group_p(group) || group == inode->i_gid)) || + suser()) { +*************** +*** 325,330 **** +--- 345,351 ---- + int sys_close(unsigned int fd) + { + struct file * filp; ++ struct inode * inode; + + if (fd >= NR_OPEN) + return -EINVAL; +*************** +*** 340,348 **** + filp->f_count--; + return 0; + } + if (filp->f_op && filp->f_op->release) +! filp->f_op->release(filp->f_inode,filp); +! iput(filp->f_inode); + filp->f_count--; + return 0; + } +--- 361,370 ---- + filp->f_count--; + return 0; + } ++ inode = filp->f_inode; + if (filp->f_op && filp->f_op->release) +! filp->f_op->release(inode,filp); + filp->f_count--; ++ iput(inode); + return 0; + } +*** 0.96c/linux/fs/exec.c Thu Jul 2 01:30:00 1992 +--- linux/fs/exec.c Sat Jul 11 00:49:32 1992 +*************** +*** 183,189 **** + iput(inode); + return -EACCES; + } +! if (!(bh = bread(inode->i_dev,inode->i_data[0]))) { + iput(inode); + return -EACCES; + } +--- 183,189 ---- + iput(inode); + return -EACCES; + } +! if (!(bh = bread(inode->i_dev,bmap(inode,0)))) { + iput(inode); + return -EACCES; + } +*************** +*** 406,412 **** +--- 406,422 ---- + retval = -EACCES; + goto exec_error2; + } ++ if (IS_NOEXEC(inode)) { /* FS mustn't be mounted noexec */ ++ retval = -EPERM; ++ goto exec_error2; ++ } + i = inode->i_mode; ++ if (IS_NOSUID(inode) && (((i & S_ISUID) && inode->i_uid != current-> ++ euid) || ((i & S_ISGID) && inode->i_gid != current->egid)) && ++ !suser()) { ++ retval = -EPERM; ++ goto exec_error2; ++ } + /* make sure we don't let suid, sgid files be ptraced. */ + if (current->flags & PF_PTRACED) { + e_uid = current->euid; +*************** +*** 424,430 **** + retval = -EACCES; + goto exec_error2; + } +! if (!(bh = bread(inode->i_dev,inode->i_data[0]))) { + retval = -EACCES; + goto exec_error2; + } +--- 434,440 ---- + retval = -EACCES; + goto exec_error2; + } +! if (!(bh = bread(inode->i_dev,bmap(inode,0)))) { + retval = -EACCES; + goto exec_error2; + } +*** 0.96c/linux/fs/super.c Fri Jul 3 03:09:37 1992 +--- linux/fs/super.c Sat Jul 11 15:56:17 1992 +*************** +*** 11,16 **** +--- 11,17 ---- + #include + #include + #include ++ /* #include */ + #include + #include + #include +*************** +*** 18,23 **** +--- 19,25 ---- + + #include + ++ + int sync_dev(int dev); + void wait_for_keypress(void); + +*************** +*** 36,41 **** +--- 38,44 ---- + static struct file_system_type file_systems[] = { + {minix_read_super,"minix"}, + {ext_read_super,"ext"}, ++ /* {msdos_read_super,"msdos"}, */ + {NULL,NULL} + }; + +*************** +*** 112,118 **** + sb->s_op->put_super(sb); + } + +! static struct super_block * read_super(int dev,char *name,void *data) + { + struct super_block * s; + struct file_system_type *type; +--- 115,121 ---- + sb->s_op->put_super(sb); + } + +! static struct super_block * read_super(int dev,char *name,int flags,void *data) + { + struct super_block * s; + struct file_system_type *type; +*************** +*** 133,138 **** +--- 136,142 ---- + break; + } + s->s_dev = dev; ++ s->s_flags = flags; + if (!type->read_super(s,data)) + return(NULL); + s->s_dev = dev; +*************** +*** 183,209 **** + return 0; + } + +! int sys_mount(char * dev_name, char * dir_name, char * type, int rw_flag) + { +! struct inode * dev_i, * dir_i; + struct super_block * sb; +- int dev; +- char tmp[100],*t; +- int i; + +! if (!suser()) +! return -EPERM; +! if (!(dev_i = namei(dev_name))) + return -ENOENT; +! dev = dev_i->i_rdev; +! if (!S_ISBLK(dev_i->i_mode)) { +! iput(dev_i); +! return -EPERM; +! } +! iput(dev_i); +! if (!(dir_i=namei(dir_name))) +! return -ENOENT; +! if (dir_i->i_count != 1 || dir_i->i_ino == MINIX_ROOT_INO) { + iput(dir_i); + return -EBUSY; + } +--- 187,209 ---- + return 0; + } + +! /* +! * do_mount() does the actual mounting after sys_mount has done the ugly +! * parameter parsing. When enough time has gone by, and everything uses the +! * new mount() parameters, sys_mount() can then be cleaned up. +! * +! * We cannot mount a filesystem if it has active, used, or dirty inodes. +! * We also have to flush all inode-data for this device, as the new mount +! * might need new info. +! */ +! static int do_mount(int dev, const char * dir, char * type, int flags, void * data) + { +! struct inode * inode, * dir_i; + struct super_block * sb; + +! if (!(dir_i = namei(dir))) + return -ENOENT; +! if (dir_i->i_count != 1 || dir_i->i_mount) { + iput(dir_i); + return -EBUSY; + } +*************** +*** 211,239 **** + iput(dir_i); + return -EPERM; + } +! if (dir_i->i_mount) { + iput(dir_i); + return -EPERM; + } + if (type) { +! i = 0; +! while (i < 100 && (tmp[i] = get_fs_byte(type++))) +! i++; + t = tmp; + } else + t = "minix"; +! if (!(sb = read_super(dev,t,NULL))) { +! iput(dir_i); +! return -EBUSY; +! } +! if (sb->s_covered) { +! iput(dir_i); +! return -EBUSY; +! } +! sb->s_covered = dir_i; +! dir_i->i_mount = 1; +! dir_i->i_dirt = 1; /* NOTE! we don't iput(dir_i) */ +! return 0; /* we do that in umount */ + } + + void mount_root(void) +--- 211,292 ---- + iput(dir_i); + return -EPERM; + } +! for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) { +! if (inode->i_dev != dev) +! continue; +! if (inode->i_count || inode->i_dirt || inode->i_lock) { +! iput(dir_i); +! return -EBUSY; +! } +! inode->i_dev = 0; +! } +! sb = read_super(dev,type,flags,data); +! if (!sb || sb->s_covered) { + iput(dir_i); ++ return -EBUSY; ++ } ++ sb->s_flags = flags; ++ sb->s_covered = dir_i; ++ dir_i->i_mount = 1; ++ return 0; /* we don't iput(dir_i) - see umount */ ++ } ++ ++ /* ++ * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to ++ * be given to the mount() call (ie: read-only, no-dev, no-suid etc). ++ * ++ * data is a (void *) that can point to any structure up to 4095 bytes, which ++ * can contain arbitrary fs-dependent information (or be NULL). ++ * ++ * NOTE! As old versions of mount() didn't use this setup, the flags has to have ++ * a special 16-bit magic number in the hight word: 0xC0ED. If this magic word ++ * isn't present, the flags and data info isn't used, as the syscall assumes we ++ * are talking to an older version that didn't understand them. ++ */ ++ int sys_mount(char * dev_name, char * dir_name, char * type, ++ unsigned long new_flags, void *data) ++ { ++ struct inode * inode; ++ int dev; ++ int retval = 0; ++ char tmp[100],*t; ++ int i; ++ unsigned long flags = 0; ++ unsigned long page = 0; ++ ++ if (!suser()) + return -EPERM; ++ if (!(inode = namei(dev_name))) ++ return -ENOENT; ++ dev = inode->i_rdev; ++ if (!S_ISBLK(inode->i_mode)) ++ retval = -EPERM; ++ else if (IS_NODEV(inode)) ++ retval = -EACCES; ++ iput(inode); ++ if (retval) ++ return retval; ++ if ((new_flags & 0xffff0000) == 0xC0ED0000) { ++ flags = new_flags & 0xffff; ++ if (data && (unsigned long) data < TASK_SIZE) ++ page = get_free_page(); + } ++ if (page) { ++ i = TASK_SIZE - (unsigned long) data; ++ if (i < 0 || i > 4095) ++ i = 4095; ++ memcpy_fromfs((void *) page,data,i); ++ } + if (type) { +! for (i = 0 ; i < 100 ; i++) +! if (!(tmp[i] = get_fs_byte(type++))) +! break; + t = tmp; + } else + t = "minix"; +! retval = do_mount(dev,dir_name,t,flags,(void *) page); +! free_page(page); +! return retval; + } + + void mount_root(void) +*************** +*** 255,261 **** + p->s_lock = 0; + p->s_wait = NULL; + } +! if (!(p=read_super(ROOT_DEV,"minix",NULL))) + panic("Unable to mount root"); + /*wait_for_keypress(); + if (!(mi=iget(ROOT_DEV,MINIX_ROOT_INO))) +--- 308,314 ---- + p->s_lock = 0; + p->s_wait = NULL; + } +! if (!(p=read_super(ROOT_DEV,"minix",0,NULL))) + panic("Unable to mount root"); + /*wait_for_keypress(); + if (!(mi=iget(ROOT_DEV,MINIX_ROOT_INO))) +*************** +*** 264,269 **** +--- 317,323 ---- + mi=p->s_mounted; + mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ + p->s_mounted = p->s_covered = mi; ++ p->s_flags = 0; + current->pwd = mi; + current->root = mi; + free=0; +*** 0.96c/linux/fs/namei.c Thu Jul 2 00:42:04 1992 +--- linux/fs/namei.c Sat Jul 11 03:57:49 1992 +*************** +*** 229,234 **** +--- 229,238 ---- + iput(dir); + return -EACCES; + } ++ if (IS_RDONLY(dir)) { ++ iput(dir); ++ return -EROFS; ++ } + return dir->i_op->create(dir,basename,namelen,mode,res_inode); + } + if (flag & O_EXCL) { +*************** +*** 238,254 **** + } + if (!(inode = follow_link(dir,inode))) + return -ELOOP; + if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) || + !permission(inode,ACC_MODE(flag))) { + iput(inode); + return -EPERM; + } +- inode->i_atime = CURRENT_TIME; + if (flag & O_TRUNC) + if (inode->i_op && inode->i_op->truncate) { + inode->i_size = 0; + inode->i_op->truncate(inode); + } + *res_inode = inode; + return 0; + } +--- 242,272 ---- + } + if (!(inode = follow_link(dir,inode))) + return -ELOOP; ++ if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { ++ if (IS_NODEV(inode)) { ++ iput(inode); ++ return -EACCES; ++ } ++ } else { ++ if (IS_RDONLY(inode) && (flag & (O_TRUNC | O_ACCMODE))) { ++ iput(inode); ++ return -EROFS; ++ } ++ } + if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) || + !permission(inode,ACC_MODE(flag))) { + iput(inode); + return -EPERM; + } + if (flag & O_TRUNC) + if (inode->i_op && inode->i_op->truncate) { + inode->i_size = 0; + inode->i_op->truncate(inode); + } ++ if (!IS_RDONLY(inode)) { ++ inode->i_atime = CURRENT_TIME; ++ inode->i_dirt = 1; ++ } + *res_inode = inode; + return 0; + } +*************** +*** 265,270 **** +--- 283,292 ---- + iput(dir); + return -ENOENT; + } ++ if (IS_RDONLY(dir)) { ++ iput(dir); ++ return -EROFS; ++ } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EACCES; +*************** +*** 295,300 **** +--- 317,326 ---- + iput(dir); + return -ENOENT; + } ++ if (IS_RDONLY(dir)) { ++ iput(dir); ++ return -EROFS; ++ } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EACCES; +*************** +*** 318,323 **** +--- 344,353 ---- + iput(dir); + return -ENOENT; + } ++ if (IS_RDONLY(dir)) { ++ iput(dir); ++ return -EROFS; ++ } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EACCES; +*************** +*** 341,346 **** +--- 371,380 ---- + iput(dir); + return -EPERM; + } ++ if (IS_RDONLY(dir)) { ++ iput(dir); ++ return -EROFS; ++ } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EACCES; +*************** +*** 365,370 **** +--- 399,408 ---- + iput(dir); + return -ENOENT; + } ++ if (IS_RDONLY(dir)) { ++ iput(dir); ++ return -EROFS; ++ } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EACCES; +*************** +*** 395,400 **** +--- 433,443 ---- + iput(dir); + return -EPERM; + } ++ if (IS_RDONLY(dir)) { ++ iput(oldinode); ++ iput(dir); ++ return -EROFS; ++ } + if (dir->i_dev != oldinode->i_dev) { + iput(dir); + iput(oldinode); +*************** +*** 453,458 **** +--- 496,506 ---- + iput(old_dir); + iput(new_dir); + return -EXDEV; ++ } ++ if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) { ++ iput(old_dir); ++ iput(new_dir); ++ return -EROFS; + } + if (!old_dir->i_op || !old_dir->i_op->rename) { + iput(old_dir); +*** 0.96c/linux/fs/ioctl.c Thu Jul 2 00:42:04 1992 +--- linux/fs/ioctl.c Sat Jul 11 00:49:32 1992 +*************** +*** 6,11 **** +--- 6,12 ---- + + #include + ++ #include + #include + #include + #include +*************** +*** 13,21 **** +--- 14,30 ---- + int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) + { + struct file * filp; ++ int block; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; ++ if (S_ISREG(filp->f_inode->i_mode) && cmd == BMAP_IOCTL && ++ filp->f_inode->i_op->bmap) { ++ block = get_fs_long((long *) arg); ++ block = filp->f_inode->i_op->bmap(filp->f_inode,block); ++ put_fs_long(block,(long *) arg); ++ return 0; ++ } + if (filp->f_op && filp->f_op->ioctl) + return filp->f_op->ioctl(filp->f_inode, filp, cmd,arg); + return -EINVAL; +*** 0.96c/linux/fs/ext/bitmap.c Fri Jul 3 03:18:53 1992 +--- linux/fs/ext/bitmap.c Sat Jul 11 05:04:14 1992 +*************** +*** 203,208 **** +--- 203,209 ---- + iput(inode); + return NULL; + } ++ inode->i_flags = inode->i_sb->s_flags; + j = 8192; + for (i=0 ; i<8 ; i++) + if (bh=inode->i_sb->s_imap[i]) +*** 0.96c/linux/fs/ext/file.c Fri Jul 3 16:24:07 1992 +--- linux/fs/ext/file.c Sat Jul 11 00:49:32 1992 +*************** +*** 153,160 **** + } while (left > 0); + if (!read) + return -EIO; +! inode->i_atime = CURRENT_TIME; +! inode->i_dirt = 1; + return read; + } + +--- 153,162 ---- + } while (left > 0); + if (!read) + return -EIO; +! if (!IS_RDONLY(inode)) { +! inode->i_atime = CURRENT_TIME; +! inode->i_dirt = 1; +! } + return read; + } + +*** 0.96c/linux/fs/ext/freelists.c Fri Jul 3 03:08:06 1992 +--- linux/fs/ext/freelists.c Sat Jul 11 05:04:14 1992 +*************** +*** 70,81 **** + if (bh->b_count) + brelse(bh); + } +! efb = (struct ext_free_block *) sb->s_zmap[1]->b_data; +! if (efb->count == 254) { + #ifdef EXTFS_DEBUG + printk("ext_free_block: block full, skipping to %d\n", block); + #endif +! brelse (sb->s_zmap[1]); + if (!(sb->s_zmap[1] = bread (dev, block))) + panic ("ext_free_block: unable to read block to free\n"); + efb = (struct ext_free_block *) sb->s_zmap[1]->b_data; +--- 70,83 ---- + if (bh->b_count) + brelse(bh); + } +! if (sb->s_zmap[1]) +! efb = (struct ext_free_block *) sb->s_zmap[1]->b_data; +! if (!sb->s_zmap[1] || efb->count == 254) { + #ifdef EXTFS_DEBUG + printk("ext_free_block: block full, skipping to %d\n", block); + #endif +! if (sb->s_zmap[1]) +! brelse (sb->s_zmap[1]); + if (!(sb->s_zmap[1] = bread (dev, block))) + panic ("ext_free_block: unable to read block to free\n"); + efb = (struct ext_free_block *) sb->s_zmap[1]->b_data; +*************** +*** 209,221 **** + free_super (inode->i_sb); + return; + } +! efi = ((struct ext_free_inode *) inode->i_sb->s_imap[1]->b_data) + +! (((unsigned long) inode->i_sb->s_imap[0])-1)%EXT_INODES_PER_BLOCK; +! if (efi->count == 14) { + #ifdef EXTFS_DEBUG + printk("ext_free_inode: inode full, skipping to %d\n", inode->i_ino); + #endif +! brelse (inode->i_sb->s_imap[1]); + block = 2 + (inode->i_ino - 1) / EXT_INODES_PER_BLOCK; + if (!(bh = bread(inode->i_dev, block))) + panic("ext_free_inode: unable to read inode block\n"); +--- 211,225 ---- + free_super (inode->i_sb); + return; + } +! if (inode->i_sb->s_imap[1]) +! efi = ((struct ext_free_inode *) inode->i_sb->s_imap[1]->b_data) + +! (((unsigned long) inode->i_sb->s_imap[0])-1)%EXT_INODES_PER_BLOCK; +! if (!inode->i_sb->s_imap[1] || efi->count == 14) { + #ifdef EXTFS_DEBUG + printk("ext_free_inode: inode full, skipping to %d\n", inode->i_ino); + #endif +! if (inode->i_sb->s_imap[1]) +! brelse (inode->i_sb->s_imap[1]); + block = 2 + (inode->i_ino - 1) / EXT_INODES_PER_BLOCK; + if (!(bh = bread(inode->i_dev, block))) + panic("ext_free_inode: unable to read inode block\n"); +*************** +*** 249,254 **** +--- 253,259 ---- + iput(inode); + return NULL; + } ++ inode->i_flags = inode->i_sb->s_flags; + if (!inode->i_sb->s_imap[1]) + return 0; + lock_super (inode->i_sb); +*** 0.96c/linux/fs/ext/namei.c Fri Jul 3 16:28:36 1992 +--- linux/fs/ext/namei.c Sat Jul 11 12:35:28 1992 +*************** +*** 808,813 **** +--- 808,817 ---- + retval = 0; + goto end_rename; + } ++ if (S_ISDIR(new_inode->i_mode)) { ++ retval = -EEXIST; ++ goto end_rename; ++ } + if (S_ISDIR(old_inode->i_mode)) { + retval = -EEXIST; + if (new_bh) +*** 0.96c/linux/fs/minix/bitmap.c Thu Jul 2 00:44:28 1992 +--- linux/fs/minix/bitmap.c Sat Jul 11 05:03:11 1992 +*************** +*** 191,196 **** +--- 191,197 ---- + iput(inode); + return NULL; + } ++ inode->i_flags = inode->i_sb->s_flags; + j = 8192; + for (i=0 ; i<8 ; i++) + if (bh=inode->i_sb->s_imap[i]) +*** 0.96c/linux/fs/minix/file.c Thu Jul 2 00:44:28 1992 +--- linux/fs/minix/file.c Sat Jul 11 00:49:33 1992 +*************** +*** 153,160 **** + } while (left > 0); + if (!read) + return -EIO; +! inode->i_atime = CURRENT_TIME; +! inode->i_dirt = 1; + return read; + } + +--- 153,162 ---- + } while (left > 0); + if (!read) + return -EIO; +! if (!IS_RDONLY(inode)) { +! inode->i_atime = CURRENT_TIME; +! inode->i_dirt = 1; +! } + return read; + } + +*** 0.96c/linux/fs/minix/namei.c Fri Jul 3 16:28:36 1992 +--- linux/fs/minix/namei.c Sat Jul 11 12:35:28 1992 +*************** +*** 676,681 **** +--- 676,685 ---- + retval = 0; + goto end_rename; + } ++ if (S_ISDIR(new_inode->i_mode)) { ++ retval = -EEXIST; ++ goto end_rename; ++ } + if (S_ISDIR(old_inode->i_mode)) { + retval = -EEXIST; + if (new_bh) +*** 0.96c/linux/init/main.c Sun Jul 5 00:57:47 1992 +--- linux/init/main.c Tue Jul 7 17:06:59 1992 +*************** +*** 53,58 **** +--- 53,59 ---- + + extern int vsprintf(); + extern void init(void); ++ extern void init_IRQ(void); + extern long blk_dev_init(long,long); + extern long chr_dev_init(long,long); + extern void hd_init(void); +*************** +*** 164,169 **** +--- 165,171 ---- + buffer_memory_end = 1*1024*1024; + main_memory_start = buffer_memory_end; + trap_init(); ++ init_IRQ(); + sched_init(); + main_memory_start = chr_dev_init(main_memory_start,memory_end); + main_memory_start = blk_dev_init(main_memory_start,memory_end); +*************** +*** 183,196 **** + 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(;;) +! __asm__("int $0x80"::"a" (__NR_pause):"ax"); + } + + static int printf(const char *fmt, ...) +--- 185,200 ---- + init(); + } + /* +! * task[0] is meant to be used as an "idle" task: it may not sleep, but +! * it might do some general things like count free pages or it could be +! * used to implement a reasonable LRU algorithm for the paging routines: +! * anything that can be useful, but shouldn't take time from the real +! * processes. +! * +! * Right now task[0] just does a infinite loop in user mode. + */ + for(;;) +! /* nothing */ ; + } + + static int printf(const char *fmt, ...) +*** 0.96c/linux/kernel/Makefile Sun Jul 5 03:09:42 1992 +--- linux/kernel/Makefile Sat Jul 11 20:12:09 1992 +*************** +*** 18,24 **** + + SUBDIRS = chr_drv blk_drv math + +! OBJS = sched.o sys_call.o traps.o asm.o fork.o \ + panic.o printk.o vsprintf.o sys.o exit.o \ + signal.o mktime.o ptrace.o ioport.o itimer.o + +--- 18,24 ---- + + SUBDIRS = chr_drv blk_drv math + +! OBJS = sched.o sys_call.o traps.o irq.o fork.o \ + panic.o printk.o vsprintf.o sys.o exit.o \ + signal.o mktime.o ptrace.o ioport.o itimer.o + +*************** +*** 73,78 **** +--- 73,85 ---- + /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/signal.h \ + /usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h /usr/src/linux/include/time.h \ + /usr/src/linux/include/sys/resource.h /usr/src/linux/include/errno.h ++ irq.o : irq.c /usr/src/linux/include/signal.h /usr/src/linux/include/sys/types.h \ ++ /usr/src/linux/include/stddef.h /usr/src/linux/include/errno.h /usr/src/linux/include/sys/ptrace.h \ ++ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \ ++ /usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \ ++ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/sys/param.h \ ++ /usr/src/linux/include/sys/time.h /usr/src/linux/include/time.h /usr/src/linux/include/sys/resource.h \ ++ /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/io.h /usr/src/linux/include/asm/irq.h + itimer.o : itimer.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \ + /usr/src/linux/include/linux/fs.h /usr/src/linux/include/sys/types.h /usr/src/linux/include/stddef.h \ + /usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \ +*** 0.96c/linux/kernel/sched.c Sun Jul 5 01:27:18 1992 +--- linux/kernel/sched.c Tue Jul 7 18:53:54 1992 +*************** +*** 10,15 **** +--- 10,18 ---- + * call functions (type getpid(), which just extracts a field from + * current-task + */ ++ ++ #define TIMER_IRQ 0 ++ + #include + #include + #include +*************** +*** 369,375 **** + unsigned long timer_active = 0; + struct timer_struct timer_table[32]; + +! void do_timer(long cpl) + { + unsigned long mask; + struct timer_struct *tp = timer_table+0; +--- 372,378 ---- + unsigned long timer_active = 0; + struct timer_struct timer_table[32]; + +! static void do_timer(int cpl) + { + unsigned long mask; + struct timer_struct *tp = timer_table+0; +*************** +*** 376,393 **** + struct task_struct ** task_p; + static int avg_cnt = 0; + +! for (mask = 1 ; mask ; tp++,mask += mask) { +! if (mask > timer_active) +! break; +! if (!(mask & timer_active)) +! continue; +! if (tp->expires > jiffies) +! continue; +! timer_active &= ~mask; +! tp->fn(); +! sti(); + } +! + /* Update ITIMER_REAL for every task */ + for (task_p = &LAST_TASK; task_p >= &FIRST_TASK; task_p--) + if (*task_p && (*task_p)->it_real_value +--- 379,397 ---- + struct task_struct ** task_p; + static int avg_cnt = 0; + +! jiffies++; +! if (!cpl) +! current->stime++; +! else +! current->utime++; +! if (--avg_cnt < 0) { +! avg_cnt = 500; +! update_avg(); + } +! if ((--current->counter)<=0) { +! current->counter=0; +! need_resched = 1; +! } + /* Update ITIMER_REAL for every task */ + for (task_p = &LAST_TASK; task_p >= &FIRST_TASK; task_p--) + if (*task_p && (*task_p)->it_real_value +*************** +*** 402,417 **** + send_sig(SIGPROF,current,1); + } + /* Update ITIMER_VIRT for current task if not in a system call */ +! if (cpl && current->it_virt_value && !(--current->it_virt_value)) { + current->it_virt_value = current->it_virt_incr; + send_sig(SIGVTALRM,current,1); + } +! +! if (cpl) +! current->utime++; +! else +! current->stime++; +! + if (next_timer) { + next_timer->jiffies--; + while (next_timer && next_timer->jiffies <= 0) { +--- 406,426 ---- + send_sig(SIGPROF,current,1); + } + /* Update ITIMER_VIRT for current task if not in a system call */ +! if (current->it_virt_value && !(--current->it_virt_value)) { + current->it_virt_value = current->it_virt_incr; + send_sig(SIGVTALRM,current,1); + } +! for (mask = 1 ; mask ; tp++,mask += mask) { +! if (mask > timer_active) +! break; +! if (!(mask & timer_active)) +! continue; +! if (tp->expires > jiffies) +! continue; +! timer_active &= ~mask; +! tp->fn(); +! sti(); +! } + if (next_timer) { + next_timer->jiffies--; + while (next_timer && next_timer->jiffies <= 0) { +*************** +*** 425,438 **** + } + if (current_DOR & 0xf0) + do_floppy_timer(); +- if (--avg_cnt < 0) { +- avg_cnt = 500; +- update_avg(); +- } +- if ((--current->counter)<=0) { +- current->counter=0; +- need_resched = 1; +- } + } + + int sys_alarm(long seconds) +--- 434,439 ---- +*************** +*** 496,501 **** +--- 497,503 ---- + panic("Struct sigaction MUST be 16 bytes"); + set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); + set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); ++ set_system_gate(0x80,&system_call); + p = gdt+2+FIRST_TSS_ENTRY; + for(i=1 ; i> 8 , 0x40); /* MSB */ +! set_intr_gate(0x20,&timer_interrupt); +! outb(inb_p(0x21)&~0x01,0x21); +! set_system_gate(0x80,&system_call); + } +--- 513,517 ---- + outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */ + outb_p(LATCH & 0xff , 0x40); /* LSB */ + outb(LATCH >> 8 , 0x40); /* MSB */ +! request_irq(TIMER_IRQ,do_timer); + } +*** 0.96c/linux/kernel/traps.c Thu May 21 12:53:42 1992 +--- linux/kernel/traps.c Fri Jul 10 16:34:12 1992 +*************** +*** 57,63 **** + void page_fault(void); + void coprocessor_error(void); + void reserved(void); +- void parallel_interrupt(void); + void irq13(void); + void alignment_check(void); + +--- 57,62 ---- +*************** +*** 116,122 **** + + void do_nmi(long esp, long error_code) + { +! die("nmi",esp,error_code); + } + + void do_debug(long esp, long error_code) +--- 115,121 ---- + + void do_nmi(long esp, long error_code) + { +! printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n"); + } + + void do_debug(long esp, long error_code) +*************** +*** 201,207 **** + for (i=18;i<48;i++) + set_trap_gate(i,&reserved); + set_trap_gate(45,&irq13); +- outb_p(inb_p(0x21)&0xfb,0x21); +- outb(inb_p(0xA1)&0xdf,0xA1); +- set_trap_gate(39,¶llel_interrupt); + } +--- 200,203 ---- +*** 0.96c/linux/kernel/chr_drv/keyboard.c Sun Jul 5 01:20:58 1992 +--- linux/kernel/chr_drv/keyboard.c Tue Jul 7 18:33:38 1992 +*************** +*** 58,64 **** + static void kb_wait(void), kb_ack(void); + static unsigned int handle_diacr(unsigned int); + +! void do_keyboard(void) + { + static unsigned char rep = 0xff, repke0 = 0; + unsigned char scancode, x; +--- 58,64 ---- + static void kb_wait(void), kb_ack(void); + static unsigned int handle_diacr(unsigned int); + +! void keyboard_interrupt(int cpl) + { + static unsigned char rep = 0xff, repke0 = 0; + unsigned char scancode, x; +*************** +*** 874,880 **** + } + + +! #if defined KBD_FR || defined KBD_US + static unsigned char num_table[] = "789-456+1230."; + #else + static unsigned char num_table[] = "789-456+1230,"; +--- 874,880 ---- + } + + +! #if defined KBD_FR || defined KBD_US || defined KBD_UK + static unsigned char num_table[] = "789-456+1230."; + #else + static unsigned char num_table[] = "789-456+1230,"; +*** 0.96c/linux/kernel/chr_drv/console.c Mon Jun 29 05:10:41 1992 +--- linux/kernel/chr_drv/console.c Sat Jul 11 12:41:53 1992 +*************** +*** 30,35 **** +--- 30,37 ---- + * + */ + ++ #define KEYBOARD_IRQ 1 ++ + #include + #include + #include +*************** +*** 68,74 **** + #define NPAR 16 + + extern void vt_init(void); +! extern void keyboard_interrupt(void); + extern void set_leds(void); + extern unsigned char kapplic; + extern unsigned char ckmode; +--- 70,76 ---- + #define NPAR 16 + + extern void vt_init(void); +! extern void keyboard_interrupt(int cpl); + extern void set_leds(void); + extern unsigned char kapplic; + extern unsigned char ckmode; +*************** +*** 241,248 **** + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ " +! "\004\261\007\007\007\007\370\361\007\007\275\267\326\323\327\304" +! "\304\304\304\304\307\266\320\322\272\363\362\343\007\234\007\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\040\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376" +--- 243,250 ---- + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ " +! "\004\261\007\007\007\007\370\361\040\007\331\277\332\300\305\007" +! "\007\304\007\007\303\264\301\302\263\007\007\007\007\007\234\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\040\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376" +*************** +*** 250,260 **** + "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376" + "\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341" + "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213" +! "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230" + }; + + #define NORM_TRANS (translations[0]) + #define GRAF_TRANS (translations[1]) + + static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, + 8,12,10,14, 9,13,11,15 }; +--- 252,280 ---- + "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376" + "\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341" + "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213" +! "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230", +! /* IBM grapgics: minimal translations (CR, LF, LL and ESC) */ +! "\000\001\002\003\004\005\006\007\010\011\000\013\000\000\016\017" +! "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037" +! "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" +! "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" +! "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" +! "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" +! "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" +! "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" +! "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" +! "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" +! "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" +! "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" +! "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" +! "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" +! "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" +! "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" + }; + + #define NORM_TRANS (translations[0]) + #define GRAF_TRANS (translations[1]) ++ #define NULL_TRANS (translations[2]) + + static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, + 8,12,10,14, 9,13,11,15 }; +*************** +*** 605,611 **** + static void respond_string(char * p, int currcons, struct tty_struct * tty) + { + while (*p) { +! PUTCH(*p,tty->read_q); + p++; + } + TTY_READ_FLUSH(tty); +--- 625,631 ---- + static void respond_string(char * p, int currcons, struct tty_struct * tty) + { + while (*p) { +! put_tty_queue(*p,tty->read_q); + p++; + } + TTY_READ_FLUSH(tty); +*************** +*** 621,627 **** + n /= 10; + } while(n && i < 3); /* We'll take no chances */ + while (i--) { +! PUTCH(buff[i],tty->read_q); + } + /* caller must flush */ + } +--- 641,647 ---- + n /= 10; + } while(n && i < 3); /* We'll take no chances */ + while (i--) { +! put_tty_queue(buff[i],tty->read_q); + } + /* caller must flush */ + } +*************** +*** 628,639 **** + + static void cursor_report(int currcons, struct tty_struct * tty) + { +! PUTCH('\033', tty->read_q); +! PUTCH('[', tty->read_q); + respond_num(y + (decom ? top+1 : 1), currcons, tty); +! PUTCH(';', tty->read_q); + respond_num(x+1, currcons, tty); +! PUTCH('R', tty->read_q); + TTY_READ_FLUSH(tty); + } + +--- 648,659 ---- + + static void cursor_report(int currcons, struct tty_struct * tty) + { +! put_tty_queue('\033', tty->read_q); +! put_tty_queue('[', tty->read_q); + respond_num(y + (decom ? top+1 : 1), currcons, tty); +! put_tty_queue(';', tty->read_q); + respond_num(x+1, currcons, tty); +! put_tty_queue('R', tty->read_q); + TTY_READ_FLUSH(tty); + } + +*************** +*** 905,911 **** + printk("con_write: illegal tty\n\r"); + return; + } +! while (!tty->stopped && (c = GETCH(tty->write_q)) >= 0) { + if (state == ESnormal && translate[c]) { + if (need_wrap) { + cr(currcons); +--- 925,931 ---- + printk("con_write: illegal tty\n\r"); + return; + } +! while (!tty->stopped && (c = get_tty_queue(tty->write_q)) >= 0) { + if (state == ESnormal && translate[c]) { + if (need_wrap) { + cr(currcons); +*************** +*** 1176,1181 **** +--- 1196,1203 ---- + G0_charset = GRAF_TRANS; + else if (c == 'B') + G0_charset = NORM_TRANS; ++ else if (c == 'U') ++ G0_charset = NULL_TRANS; + if (charset == 0) + translate = G0_charset; + state = ESnormal; +*************** +*** 1185,1190 **** +--- 1207,1214 ---- + G1_charset = GRAF_TRANS; + else if (c == 'B') + G1_charset = NORM_TRANS; ++ else if (c == 'U') ++ G1_charset = NULL_TRANS; + if (charset == 1) + translate = G1_charset; + state = ESnormal; +*************** +*** 1338,1345 **** + gotoxy(currcons,orig_x,orig_y); + update_screen(fg_console); + +! set_trap_gate(0x21,&keyboard_interrupt); +! outb_p(inb_p(0x21)&0xfd,0x21); + a=inb_p(0x61); + outb_p(a|0x80,0x61); + outb_p(a,0x61); +--- 1362,1369 ---- + gotoxy(currcons,orig_x,orig_y); + update_screen(fg_console); + +! if (request_irq(KEYBOARD_IRQ,keyboard_interrupt)) +! printk("Unable to get IRQ%d for keyboard driver\n",KEYBOARD_IRQ); + a=inb_p(0x61); + outb_p(a|0x80,0x61); + outb_p(a,0x61); +*** 0.96c/linux/kernel/chr_drv/tty_ioctl.c Fri Jul 3 04:26:08 1992 +--- linux/kernel/chr_drv/tty_ioctl.c Wed Jul 8 17:12:50 1992 +*************** +*** 65,71 **** + } + } + +! static void wait_until_sent(struct tty_struct * tty) + { + while (!(current->signal & ~current->blocked) && !EMPTY(tty->write_q)) { + TTY_WRITE_FLUSH(tty); +--- 65,71 ---- + } + } + +! void wait_until_sent(struct tty_struct * tty) + { + while (!(current->signal & ~current->blocked) && !EMPTY(tty->write_q)) { + TTY_WRITE_FLUSH(tty); +*************** +*** 122,127 **** +--- 122,128 ---- + int channel) + { + int i; ++ unsigned short old_cflag = tty->termios.c_cflag; + + /* If we try to set the state of terminal and we're not in the + foreground, send a SIGTTOU. If the signal is blocked or +*************** +*** 135,141 **** + } + for (i=0 ; i< (sizeof (*termios)) ; i++) + ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios); +! if (IS_A_SERIAL(channel)) + change_speed(channel-64); + return 0; + } +--- 136,142 ---- + } + for (i=0 ; i< (sizeof (*termios)) ; i++) + ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios); +! if (IS_A_SERIAL(channel) && tty->termios.c_cflag != old_cflag) + change_speed(channel-64); + return 0; + } +*************** +*** 166,171 **** +--- 167,173 ---- + { + int i; + struct termio tmp_termio; ++ unsigned short old_cflag = tty->termios.c_cflag; + + if ((current->tty == channel) && + (tty->pgrp > 0) && +*************** +*** 184,190 **** + tty->termios.c_line = tmp_termio.c_line; + for(i=0 ; i < NCC ; i++) + tty->termios.c_cc[i] = tmp_termio.c_cc[i]; +! if (IS_A_SERIAL(channel)) + change_speed(channel-64); + return 0; + } +--- 186,192 ---- + tty->termios.c_line = tmp_termio.c_line; + for(i=0 ; i < NCC ; i++) + tty->termios.c_cc[i] = tmp_termio.c_cc[i]; +! if (IS_A_SERIAL(channel) && tty->termios.c_cflag != old_cflag) + change_speed(channel-64); + return 0; + } +*************** +*** 232,243 **** + int pgrp; + int dev; + +! if (MAJOR(inode->i_rdev) == 5) { +! dev = current->tty; +! if (dev<0) +! return -EINVAL; +! } else +! dev = MINOR(inode->i_rdev); + tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console); + + if (IS_A_PTY(dev)) +--- 234,244 ---- + int pgrp; + int dev; + +! if (MAJOR(file->f_rdev) != 4) { +! printk("tty_ioctl: tty pseudo-major != 4\n"); +! return -EINVAL; +! } +! dev = MINOR(file->f_rdev); + tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console); + + if (IS_A_PTY(dev)) +*************** +*** 286,296 **** + return 0; + case TCIOFF: + if (STOP_CHAR(tty)) +! PUTCH(STOP_CHAR(tty),tty->write_q); + return 0; + case TCION: + if (START_CHAR(tty)) +! PUTCH(START_CHAR(tty),tty->write_q); + return 0; + } + return -EINVAL; /* not implemented */ +--- 287,297 ---- + return 0; + case TCIOFF: + if (STOP_CHAR(tty)) +! put_tty_queue(STOP_CHAR(tty),tty->write_q); + return 0; + case TCION: + if (START_CHAR(tty)) +! put_tty_queue(START_CHAR(tty),tty->write_q); + return 0; + } + return -EINVAL; /* not implemented */ +*** 0.96c/linux/kernel/chr_drv/tty_io.c Sat Jul 4 03:21:41 1992 +--- linux/kernel/chr_drv/tty_io.c Wed Jul 8 18:00:50 1992 +*************** +*** 154,160 **** + while (1) { + if (FULL(tty->secondary)) + break; +! c = GETCH(tty->read_q); + if (c < 0) + break; + if (I_STRP(tty)) +--- 154,160 ---- + while (1) { + if (FULL(tty->secondary)) + break; +! c = get_tty_queue(tty->read_q); + if (c < 0) + break; + if (I_STRP(tty)) +*************** +*** 178,190 **** + (c==EOF_CHAR(tty))))) { + if (L_ECHO(tty)) { + if (c<32) { +! PUTCH(8,tty->write_q); +! PUTCH(' ',tty->write_q); +! PUTCH(8,tty->write_q); + } +! PUTCH(8,tty->write_q); +! PUTCH(' ',tty->write_q); +! PUTCH(8,tty->write_q); + TTY_WRITE_FLUSH(tty); + } + DEC(tty->secondary->head); +--- 178,190 ---- + (c==EOF_CHAR(tty))))) { + if (L_ECHO(tty)) { + if (c<32) { +! put_tty_queue(8,tty->write_q); +! put_tty_queue(' ',tty->write_q); +! put_tty_queue(8,tty->write_q); + } +! put_tty_queue(8,tty->write_q); +! put_tty_queue(' ',tty->write_q); +! put_tty_queue(8,tty->write_q); + TTY_WRITE_FLUSH(tty); + } + DEC(tty->secondary->head); +*************** +*** 200,212 **** + continue; + if (L_ECHO(tty)) { + if (c<32) { +! PUTCH(8,tty->write_q); +! PUTCH(' ',tty->write_q); +! PUTCH(8,tty->write_q); + } +! PUTCH(8,tty->write_q); +! PUTCH(32,tty->write_q); +! PUTCH(8,tty->write_q); + TTY_WRITE_FLUSH(tty); + } + DEC(tty->secondary->head); +--- 200,212 ---- + continue; + if (L_ECHO(tty)) { + if (c<32) { +! put_tty_queue(8,tty->write_q); +! put_tty_queue(' ',tty->write_q); +! put_tty_queue(8,tty->write_q); + } +! put_tty_queue(8,tty->write_q); +! put_tty_queue(32,tty->write_q); +! put_tty_queue(8,tty->write_q); + TTY_WRITE_FLUSH(tty); + } + DEC(tty->secondary->head); +*************** +*** 250,265 **** + c==EOF_CHAR(tty))) + tty->secondary->data++; + if ((L_ECHO(tty) || (L_CANON(tty) && L_ECHONL(tty))) && (c==10)) { +! PUTCH(10,tty->write_q); +! PUTCH(13,tty->write_q); + } else if (L_ECHO(tty)) { + if (c<32 && L_ECHOCTL(tty)) { +! PUTCH('^',tty->write_q); +! PUTCH(c+64,tty->write_q); + } else +! PUTCH(c,tty->write_q); + } +! PUTCH(c,tty->secondary); + TTY_WRITE_FLUSH(tty); + } + TTY_WRITE_FLUSH(tty); +--- 250,265 ---- + c==EOF_CHAR(tty))) + tty->secondary->data++; + if ((L_ECHO(tty) || (L_CANON(tty) && L_ECHONL(tty))) && (c==10)) { +! put_tty_queue(10,tty->write_q); +! put_tty_queue(13,tty->write_q); + } else if (L_ECHO(tty)) { + if (c<32 && L_ECHOCTL(tty)) { +! put_tty_queue('^',tty->write_q); +! put_tty_queue(c+64,tty->write_q); + } else +! put_tty_queue(c,tty->write_q); + } +! put_tty_queue(c,tty->secondary); + TTY_WRITE_FLUSH(tty); + } + TTY_WRITE_FLUSH(tty); +*************** +*** 299,305 **** + static int read_chan(unsigned int channel, struct file * file, char * buf, int nr) + { + struct tty_struct * tty; +- struct tty_struct * other_tty = NULL; + int c; + char * b=buf; + int minimum,time; +--- 299,304 ---- +*************** +*** 316,323 **** + return -EIO; + else + return(tty_signal(SIGTTIN, tty)); +- if (channel & 0x80) +- other_tty = tty_table + (channel ^ 0x40); + time = 10L*tty->termios.c_cc[VTIME]; + minimum = tty->termios.c_cc[VMIN]; + if (L_CANON(tty)) { +--- 315,320 ---- +*************** +*** 338,345 **** + minimum = nr; + TTY_READ_FLUSH(tty); + while (nr>0) { +! if (other_tty && other_tty->write) +! TTY_WRITE_FLUSH(other_tty); + cli(); + if (EMPTY(tty->secondary) || (L_CANON(tty) && + !FULL(tty->read_q) && !tty->secondary->data)) { +--- 335,342 ---- + minimum = nr; + TTY_READ_FLUSH(tty); + while (nr>0) { +! if (tty->link && tty->link->write) +! TTY_WRITE_FLUSH(tty->link); + cli(); + if (EMPTY(tty->secondary) || (L_CANON(tty) && + !FULL(tty->read_q) && !tty->secondary->data)) { +*************** +*** 347,356 **** + break; + if (current->signal & ~current->blocked) + break; +! if (IS_A_PTY_SLAVE(channel) && C_HUP(other_tty)) + break; +- if (other_tty && !other_tty->count) +- break; + interruptible_sleep_on(&tty->secondary->proc_list); + sti(); + TTY_READ_FLUSH(tty); +--- 344,351 ---- + break; + if (current->signal & ~current->blocked) + break; +! if (tty->link && !tty->link->count) + break; + interruptible_sleep_on(&tty->secondary->proc_list); + sti(); + TTY_READ_FLUSH(tty); +*************** +*** 358,364 **** + } + sti(); + do { +! c = GETCH(tty->secondary); + if ((EOF_CHAR(tty) != __DISABLED_CHAR && + c==EOF_CHAR(tty)) || c==10) + tty->secondary->data--; +--- 353,359 ---- + } + sti(); + do { +! c = get_tty_queue(tty->secondary); + if ((EOF_CHAR(tty) != __DISABLED_CHAR && + c==EOF_CHAR(tty)) || c==10) + tty->secondary->data--; +*************** +*** 381,388 **** + } + sti(); + TTY_READ_FLUSH(tty); +! if (other_tty && other_tty->write) +! TTY_WRITE_FLUSH(other_tty); + current->timeout = 0; + if (b-buf) + return b-buf; +--- 376,383 ---- + } + sti(); + TTY_READ_FLUSH(tty); +! if (tty->link && tty->link->write) +! TTY_WRITE_FLUSH(tty->link); + current->timeout = 0; + if (b-buf) + return b-buf; +*************** +*** 419,424 **** +--- 414,423 ---- + while (nr>0) { + if (current->signal & ~current->blocked) + break; ++ if (tty->link && !tty->link->count) { ++ send_sig(SIGPIPE,current,0); ++ break; ++ } + if (FULL(tty->write_q)) { + TTY_WRITE_FLUSH(tty); + cli(); +*************** +*** 436,442 **** + c='\r'; + if (c=='\n' && !(tty->flags & TTY_CR_PENDING) && O_NLCR(tty)) { + tty->flags |= TTY_CR_PENDING; +! PUTCH(13,tty->write_q); + continue; + } + if (O_LCUC(tty)) +--- 435,441 ---- + c='\r'; + if (c=='\n' && !(tty->flags & TTY_CR_PENDING) && O_NLCR(tty)) { + tty->flags |= TTY_CR_PENDING; +! put_tty_queue(13,tty->write_q); + continue; + } + if (O_LCUC(tty)) +*************** +*** 444,450 **** + } + b++; nr--; + tty->flags &= ~TTY_CR_PENDING; +! PUTCH(c,tty->write_q); + } + if (nr>0) + schedule(); +--- 443,449 ---- + } + b++; nr--; + tty->flags &= ~TTY_CR_PENDING; +! put_tty_queue(c,tty->write_q); + } + if (nr>0) + schedule(); +*************** +*** 452,457 **** +--- 451,458 ---- + TTY_WRITE_FLUSH(tty); + if (b-buf) + return b-buf; ++ if (tty->link && !tty->link->count) ++ return -EPIPE; + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + return 0; +*************** +*** 460,477 **** + static int tty_read(struct inode * inode, struct file * file, char * buf, int count) + { + int i; +- +- i = read_chan(current->tty,file,buf,count); +- if (i > 0) +- inode->i_atime = CURRENT_TIME; +- return i; +- } + +! static int ttyx_read(struct inode * inode, struct file * file, char * buf, int count) +! { +! int i; +! +! i = read_chan(MINOR(inode->i_rdev),file,buf,count); + if (i > 0) + inode->i_atime = CURRENT_TIME; + return i; +--- 461,472 ---- + static int tty_read(struct inode * inode, struct file * file, char * buf, int count) + { + int i; + +! if (MAJOR(file->f_rdev) != 4) { +! printk("tty_read: pseudo-major != 4\n"); +! return -EINVAL; +! } +! i = read_chan(MINOR(file->f_rdev),file,buf,count); + if (i > 0) + inode->i_atime = CURRENT_TIME; + return i; +*************** +*** 481,502 **** + { + int i; + +! i = write_chan(current->tty,file,buf,count); + if (i > 0) + inode->i_mtime = CURRENT_TIME; + return i; + } + +- static int ttyx_write(struct inode * inode, struct file * file, char * buf, int count) +- { +- int i; +- +- i = write_chan(MINOR(inode->i_rdev),file,buf,count); +- if (i > 0) +- inode->i_mtime = CURRENT_TIME; +- return i; +- } +- + static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig) + { + return -EBADF; +--- 476,491 ---- + { + int i; + +! if (MAJOR(file->f_rdev) != 4) { +! printk("tty_write: pseudo-major != 4\n"); +! return -EINVAL; +! } +! i = write_chan(MINOR(file->f_rdev),file,buf,count); + if (i > 0) + inode->i_mtime = CURRENT_TIME; + return i; + } + + static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig) + { + return -EBADF; +*************** +*** 522,536 **** + dev = MINOR(dev); + if (dev < 0) + return -ENODEV; + tty = TTY_TABLE(dev); + if (IS_A_PTY_MASTER(dev)) { + if (tty->count) + return -EAGAIN; + } +- if (!tty->count && (!tty->link || !tty->link->count)) { +- flush_input(tty); +- flush_output(tty); +- } + tty->count++; + retval = 0; + if (!(filp->f_flags & O_NOCTTY) && +--- 511,528 ---- + dev = MINOR(dev); + if (dev < 0) + return -ENODEV; ++ filp->f_rdev = 0x0400 | dev; + tty = TTY_TABLE(dev); ++ if (!tty->count && !(tty->link && tty->link->count)) { ++ flush_input(tty); ++ flush_output(tty); ++ } + if (IS_A_PTY_MASTER(dev)) { + if (tty->count) + return -EAGAIN; ++ if (tty->link) ++ tty->link->count++; + } + tty->count++; + retval = 0; + if (!(filp->f_flags & O_NOCTTY) && +*************** +*** 541,576 **** + tty->session = current->session; + tty->pgrp = current->pgrp; + } +! if (IS_A_SERIAL(dev)) + retval = serial_open(dev-64,filp); + else if (IS_A_PTY(dev)) + retval = pty_open(dev,filp); +! if (retval) + tty->count--; + return retval; + } + + static void tty_release(struct inode * inode, struct file * filp) + { + int dev; + struct tty_struct * tty; + +! dev = inode->i_rdev; +! if (MAJOR(dev) == 5) +! dev = current->tty; +! else +! dev = MINOR(dev); +! if (dev < 0) + return; + tty = TTY_TABLE(dev); +! if (--tty->count) + return; +! if (tty == redirect) +! redirect = NULL; +! if (IS_A_SERIAL(dev)) + serial_close(dev-64,filp); +! else if (IS_A_PTY(dev)) + pty_close(dev,filp); + } + + static struct file_operations tty_fops = { +--- 533,582 ---- + tty->session = current->session; + tty->pgrp = current->pgrp; + } +! if (IS_A_SERIAL(dev) && tty->count < 2) + retval = serial_open(dev-64,filp); + else if (IS_A_PTY(dev)) + retval = pty_open(dev,filp); +! if (retval) { + tty->count--; ++ if (IS_A_PTY_MASTER(dev) && tty->link) ++ tty->link->count++; ++ } + return retval; + } + ++ /* ++ * Note that releasing a pty master also releases the child, so ++ * we have to make the redirection checks after that and on both ++ * sides of a pty. ++ */ + static void tty_release(struct inode * inode, struct file * filp) + { + int dev; + struct tty_struct * tty; + +! dev = filp->f_rdev; +! if (MAJOR(dev) != 4) { +! printk("tty_close: tty pseudo-major != 4\n"); + return; ++ } ++ dev = MINOR(filp->f_rdev); + tty = TTY_TABLE(dev); +! if (IS_A_PTY_MASTER(dev) && tty->link) +! tty->link->count--; +! tty->count--; +! if (tty->count) + return; +! if (IS_A_SERIAL(dev)) { +! wait_until_sent(tty); + serial_close(dev-64,filp); +! } else if (IS_A_PTY(dev)) + pty_close(dev,filp); ++ if (!tty->count && (tty == redirect)) ++ redirect = NULL; ++ if (tty = tty->link) ++ if (!tty->count && (tty == redirect)) ++ redirect = NULL; + } + + static struct file_operations tty_fops = { +*************** +*** 584,600 **** + tty_release + }; + +- static struct file_operations ttyx_fops = { +- tty_lseek, +- ttyx_read, +- ttyx_write, +- NULL, /* ttyx_readdir */ +- NULL, /* ttyx_select */ +- tty_ioctl, /* ttyx_ioctl */ +- tty_open, +- tty_release +- }; +- + long tty_init(long kmem_start) + { + int i; +--- 590,595 ---- +*************** +*** 603,609 **** + kmem_start += QUEUES * (sizeof (struct tty_queue)); + table_list[0] = con_queues + 0; + table_list[1] = con_queues + 1; +! chrdev_fops[4] = &ttyx_fops; + chrdev_fops[5] = &tty_fops; + for (i=0 ; i < QUEUES ; i++) + tty_queues[i] = (struct tty_queue) {0,0,0,0,""}; +--- 598,604 ---- + kmem_start += QUEUES * (sizeof (struct tty_queue)); + table_list[0] = con_queues + 0; + table_list[1] = con_queues + 1; +! chrdev_fops[4] = &tty_fops; + chrdev_fops[5] = &tty_fops; + for (i=0 ; i < QUEUES ; i++) + tty_queues[i] = (struct tty_queue) {0,0,0,0,""}; +*** 0.96c/linux/kernel/chr_drv/serial.c Thu Jun 25 18:22:24 1992 +--- linux/kernel/chr_drv/serial.c Tue Jul 7 18:32:46 1992 +*************** +*** 26,41 **** + + #define WAKEUP_CHARS (3*TTY_BUF_SIZE/4) + +- /* +- * note that IRQ9 is what many docs call IRQ2 - on the AT hardware +- * the old IRQ2 line has been changed to IRQ9. The serial_table +- * structure considers IRQ2 to be the same as IRQ9. +- */ +- extern void IRQ9_interrupt(void); +- extern void IRQ3_interrupt(void); +- extern void IRQ4_interrupt(void); +- extern void IRQ5_interrupt(void); +- + struct serial_struct serial_table[NR_SERIALS] = { + { PORT_UNKNOWN, 0, 0x3F8, 4, NULL}, + { PORT_UNKNOWN, 1, 0x2F8, 3, NULL}, +--- 26,31 ---- +*************** +*** 43,62 **** + { PORT_UNKNOWN, 3, 0x2E8, 3, NULL}, + }; + +- static struct serial_struct * irq_info[16] = { NULL, }; +- + static void modem_status_intr(struct serial_struct * info) + { + unsigned char status = inb(info->port+6); + +! if ((status & 0x88) == 0x08 && info->tty->pgrp > 0) +! kill_pg(info->tty->pgrp,SIGHUP,1); + #if 0 +! if ((status & 0x10) == 0x10) +! info->tty->stopped = 0; +! else +! info->tty->stopped = 1; + #endif + } + + void send_break(unsigned int line) +--- 33,52 ---- + { PORT_UNKNOWN, 3, 0x2E8, 3, NULL}, + }; + + static void modem_status_intr(struct serial_struct * info) + { + unsigned char status = inb(info->port+6); + +! if (!(info->tty->termios.c_cflag & CLOCAL)) { +! if ((status & 0x88) == 0x08 && info->tty->pgrp > 0) +! kill_pg(info->tty->pgrp,SIGHUP,1); + #if 0 +! if ((status & 0x10) == 0x10) +! info->tty->stopped = 0; +! else +! info->tty->stopped = 1; + #endif ++ } + } + + void send_break(unsigned int line) +*************** +*** 94,108 **** + int c, i = 0; + + timer_active &= ~(1 << timer); +! do { +! if ((c = GETCH(queue)) < 0) +! return; + outb(c,port); +! i++; +! } while (info->type == PORT_16550A && +! i < 14 && !EMPTY(queue)); + timer_table[timer].expires = jiffies + 10; + timer_active |= 1 << timer; + if (LEFT(queue) > WAKEUP_CHARS) + wake_up(&queue->proc_list); + } +--- 84,102 ---- + int c, i = 0; + + timer_active &= ~(1 << timer); +! while (inb_p(info->port+5) & 0x20) { +! if (queue->tail == queue->head) +! goto end_send; +! c = queue->buf[queue->tail]; +! queue->tail++; +! queue->tail &= TTY_BUF_SIZE-1; + outb(c,port); +! if ((info->type != PORT_16550A) || (++i >= 14)) +! break; +! } + timer_table[timer].expires = jiffies + 10; + timer_active |= 1 << timer; ++ end_send: + if (LEFT(queue) > WAKEUP_CHARS) + wake_up(&queue->proc_list); + } +*************** +*** 111,120 **** + { + unsigned short port = info->port; + struct tty_queue * queue = info->tty->read_q; + + do { +! PUTCH(inb(port),queue); + } while (inb(port+5) & 1); + timer_active |= (1<line; + } + +--- 105,122 ---- + { + unsigned short port = info->port; + struct tty_queue * queue = info->tty->read_q; ++ int head = queue->head; ++ int maxhead = (queue->tail-1) & (TTY_BUF_SIZE-1); + ++ timer_active &= ~((1<line); + do { +! queue->buf[head] = inb(port); +! if (head != maxhead) { +! head++; +! head &= TTY_BUF_SIZE-1; +! } + } while (inb(port+5) & 1); ++ queue->head = head; + timer_active |= (1<line; + } + +*************** +*** 149,159 **** + } + } + +! void do_IRQ(int irq) + { +! check_tty(irq_info[irq]); + } + + static void com1_timer(void) + { + TTY_READ_FLUSH(tty_table+64); +--- 151,197 ---- + } + } + +! /* +! * Again, we disable interrupts to be sure there aren't any races: +! * see send_intr for details. +! */ +! static inline void do_rs_write(struct serial_struct * info) + { +! if (!info->tty || !info->port) +! return; +! if (!info->tty->write_q || EMPTY(info->tty->write_q)) +! return; +! cli(); +! send_intr(info); +! sti(); + } + ++ /* ++ * IRQ routines: one per line ++ */ ++ static void com1_IRQ(int cpl) ++ { ++ check_tty(serial_table+0); ++ } ++ ++ static void com2_IRQ(int cpl) ++ { ++ check_tty(serial_table+1); ++ } ++ ++ static void com3_IRQ(int cpl) ++ { ++ check_tty(serial_table+2); ++ } ++ ++ static void com4_IRQ(int cpl) ++ { ++ check_tty(serial_table+3); ++ } ++ ++ /* ++ * Receive timer routines: one per line ++ */ + static void com1_timer(void) + { + TTY_READ_FLUSH(tty_table+64); +*************** +*** 175,201 **** + } + + /* +! * Again, we disable interrupts to be sure there aren't any races: +! * see send_intr for details. + */ +- static inline void do_rs_write(struct serial_struct * info) +- { +- if (!info->tty || !info->port) +- return; +- if (!info->tty->write_q || EMPTY(info->tty->write_q)) +- return; +- cli(); +- if (inb_p(info->port+5) & 0x20) +- send_intr(info); +- else { +- unsigned int timer = SER1_TIMEOUT+info->line; +- +- timer_table[timer].expires = jiffies + 10; +- timer_active |= 1 << timer; +- } +- sti(); +- } +- + static void com1_timeout(void) + { + do_rs_write(serial_table); +--- 213,220 ---- + } + + /* +! * Send timeout routines: one per line + */ + static void com1_timeout(void) + { + do_rs_write(serial_table); +*************** +*** 276,288 **** + irq = info->irq; + if (irq == 2) + irq = 9; +! if (irq_info[irq] == info) { +! irq_info[irq] = NULL; +! if (irq < 8) +! outb(inb_p(0x21) | (1<irq; + if (irq == 2) + irq = 9; +! free_irq(irq); + } + + static void startup(unsigned short port) +*************** +*** 300,306 **** + { + struct serial_struct * info; + unsigned short port,quot; +! unsigned cflag; + static unsigned short quotient[] = { + 0, 2304, 1536, 1047, 857, + 768, 576, 384, 192, 96, +--- 313,319 ---- + { + struct serial_struct * info; + unsigned short port,quot; +! unsigned cflag,cval; + static unsigned short quotient[] = { + 0, 2304, 1536, 1047, 857, + 768, 576, 384, 192, 96, +*************** +*** 318,339 **** + outb(0x00,port+4); + else if (!inb(port+4)) + startup(port); + cli(); +! outb_p(0x80,port+3); /* set DLAB */ + outb_p(quot & 0xff,port); /* LS of divisor */ + outb_p(quot >> 8,port+1); /* MS of divisor */ +! outb(0x03,port+3); /* reset DLAB */ + sti(); +- /* set byte size and parity */ +- quot = cflag & (CSIZE | CSTOPB); +- quot >>= 4; +- if (cflag & PARENB) +- quot |= 8; +- if (!(cflag & PARODD)) +- quot |= 16; +- outb(quot,port+3); + } + + /* + * this routine enables interrupts on 'line', and disables them for any + * other serial line that shared the same IRQ. Braindamaged AT hardware. +--- 331,355 ---- + outb(0x00,port+4); + else if (!inb(port+4)) + startup(port); ++ /* byte size and parity */ ++ cval = cflag & (CSIZE | CSTOPB); ++ cval >>= 4; ++ if (cflag & PARENB) ++ cval |= 8; ++ if (!(cflag & PARODD)) ++ cval |= 16; + cli(); +! outb_p(cval | 0x80,port+3); /* set DLAB */ + outb_p(quot & 0xff,port); /* LS of divisor */ + outb_p(quot >> 8,port+1); /* MS of divisor */ +! outb(cval,port+3); /* reset DLAB */ + sti(); + } + ++ static void (*serial_handler[NR_SERIALS])(int) = { ++ com1_IRQ,com2_IRQ,com3_IRQ,com4_IRQ ++ }; ++ + /* + * this routine enables interrupts on 'line', and disables them for any + * other serial line that shared the same IRQ. Braindamaged AT hardware. +*************** +*** 341,348 **** + int serial_open(unsigned line, struct file * filp) + { + struct serial_struct * info; +! int irq; + unsigned short port; + + if (line >= NR_SERIALS) + return -ENODEV; +--- 357,365 ---- + int serial_open(unsigned line, struct file * filp) + { + struct serial_struct * info; +! int irq,retval; + unsigned short port; ++ void (*handler)(int) = serial_handler[line]; + + if (line >= NR_SERIALS) + return -ENODEV; +*************** +*** 352,367 **** + irq = info->irq; + if (irq == 2) + irq = 9; +! if (irq_info[irq] && irq_info[irq] != info) +! return -EBUSY; +! cli(); + startup(port); +- irq_info[irq] = info; +- if (irq < 8) +- outb(inb_p(0x21) & ~(1<irq; + if (irq == 2) + irq = 9; +! if (retval = request_irq(irq,handler)) +! return retval; + startup(port); + return 0; + } + +*************** +*** 380,385 **** +--- 390,397 ---- + struct serial_struct tmp; + unsigned new_port; + unsigned irq,new_irq; ++ int retval; ++ void (*handler)(int) = serial_handler[line]; + + if (!suser()) + return -EPERM; +*************** +*** 401,420 **** + if (irq == 2) + irq = 9; + if (irq != new_irq) { +! if (irq_info[new_irq]) +! return -EBUSY; +! cli(); +! irq_info[new_irq] = irq_info[irq]; +! irq_info[irq] = NULL; +! info->irq = new_irq; +! if (irq < 8) +! outb(inb_p(0x21) | (1<port) { +--- 413,422 ---- + if (irq == 2) + irq = 9; + if (irq != new_irq) { +! retval = request_irq(new_irq,handler); +! if (retval) +! return retval; +! free_irq(irq); + } + cli(); + if (new_port != info->port) { +*************** +*** 450,459 **** + timer_table[SER3_TIMEOUT].expires = 0; + timer_table[SER4_TIMEOUT].fn = com4_timeout; + timer_table[SER4_TIMEOUT].expires = 0; +- set_intr_gate(0x23,IRQ3_interrupt); +- set_intr_gate(0x24,IRQ4_interrupt); +- set_intr_gate(0x25,IRQ5_interrupt); +- set_intr_gate(0x29,IRQ9_interrupt); + for (i = 0, info = serial_table; i < NR_SERIALS; i++,info++) { + info->tty = (tty_table+64) + i; + init(info); +--- 452,457 ---- +*** 0.96c/linux/kernel/chr_drv/pty.c Sun Jul 5 03:15:12 1992 +--- linux/kernel/chr_drv/pty.c Wed Jul 8 14:18:16 1992 +*************** +*** 31,40 **** + wake_up(&tty->read_q->proc_list); + if (filp->f_flags & O_NDELAY) + return 0; +- if (IS_A_PTY_MASTER(dev)) { +- tty->link->count++; +- return 0; +- } + while (!tty->link->count && !(current->signal & ~current->blocked)) + interruptible_sleep_on(&tty->link->read_q->proc_list); + if (!tty->link->count) +--- 31,36 ---- +*************** +*** 48,55 **** + + tty = tty_table + dev; + wake_up(&tty->read_q->proc_list); + if (IS_A_PTY_MASTER(dev)) { +- tty->link->count--; + if (tty->link->pgrp > 0) + kill_pg(tty->link->pgrp,SIGHUP,1); + } +--- 44,51 ---- + + tty = tty_table + dev; + wake_up(&tty->read_q->proc_list); ++ wake_up(&tty->link->write_q->proc_list); + if (IS_A_PTY_MASTER(dev)) { + if (tty->link->pgrp > 0) + kill_pg(tty->link->pgrp,SIGHUP,1); + } +*************** +*** 66,73 **** + TTY_READ_FLUSH(to); + continue; + } +! c = GETCH(from->write_q); +! PUTCH(c,to->read_q); + if (current->signal & ~current->blocked) + break; + } +--- 62,69 ---- + TTY_READ_FLUSH(to); + continue; + } +! c = get_tty_queue(from->write_q); +! put_tty_queue(c,to->read_q); + if (current->signal & ~current->blocked) + break; + } +*** 0.96c/linux/kernel/blk_drv/hd.c Wed Jun 3 04:00:19 1992 +--- linux/kernel/blk_drv/hd.c Sat Jul 11 00:49:35 1992 +*************** +*** 16,22 **** +--- 16,25 ---- + * in the early extended-partition checks and added DM partitions + */ + ++ #define HD_IRQ 14 ++ + #include ++ #include + + #include + #include +*************** +*** 82,88 **** + #define port_write(port,buf,nr) \ + __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si") + +- extern void hd_interrupt(void); + extern void rd_load(void); + + static unsigned int current_minor; +--- 85,90 ---- +*************** +*** 279,285 **** +--- 281,289 ---- + blk_size[MAJOR_NR] = hd_sizes; + if (NR_HD) + printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":""); ++ #ifdef RAMDISK + rd_load(); ++ #endif + mount_root(); + return (0); + } +*************** +*** 517,523 **** + */ + static void hd_times_out(void) + { +! do_hd = NULL; + reset = 1; + if (!CURRENT) + return; +--- 521,527 ---- + */ + static void hd_times_out(void) + { +! DEVICE_INTR = NULL; + reset = 1; + if (!CURRENT) + return; +*************** +*** 601,607 **** +--- 605,614 ---- + (char *) &loc->sectors); + put_fs_word(hd_info[dev].cyl, + (short *) &loc->cylinders); ++ put_fs_long(hd[MINOR(inode->i_rdev)].start_sect, ++ (long *) &loc->start); + return 0; ++ RO_IOCTLS(inode->i_rdev,arg); + default: + return -EINVAL; + } +*************** +*** 627,638 **** + hd_release /* release */ + }; + + void hd_init(void) + { + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blkdev_fops[MAJOR_NR] = &hd_fops; +! set_intr_gate(0x2E,&hd_interrupt); +! outb_p(inb_p(0x21)&0xfb,0x21); +! outb(inb_p(0xA1)&0xbf,0xA1); + timer_table[HD_TIMER].fn = hd_times_out; + } +--- 634,668 ---- + hd_release /* release */ + }; + ++ static void hd_interrupt(int cpl) ++ { ++ void (*handler)(void) = DEVICE_INTR; ++ ++ DEVICE_INTR = NULL; ++ timer_active &= ~(1< ++ #include + #include + #include + #include +*************** +*** 70,75 **** +--- 71,101 ---- + wake_up(&bh->b_wait); + } + ++ /* RO fail safe mechanism */ ++ ++ static long ro_bits[NR_BLK_DEV][8]; ++ ++ int is_read_only(int dev) ++ { ++ int minor,major; ++ ++ major = MAJOR(dev); ++ minor = MINOR(dev); ++ if (major < 0 || major >= NR_BLK_DEV) return 0; ++ return ro_bits[major][minor >> 5] & (1 << (minor & 31)); ++ } ++ ++ void set_device_ro(int dev,int flag) ++ { ++ int minor,major; ++ ++ major = MAJOR(dev); ++ minor = MINOR(dev); ++ if (major < 0 || major >= NR_BLK_DEV) return; ++ if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31); ++ else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31)); ++ } ++ + /* + * add-request adds a request to the linked list. + * It disables interrupts so that it can muck with the +*************** +*** 203,208 **** +--- 229,238 ---- + } + if (rw!=READ && rw!=WRITE) + panic("Bad block dev command, must be R/W"); ++ if (rw == WRITE && is_read_only(dev)) { ++ printk("Can't page to read-only device 0x%X\n\r",dev); ++ return; ++ } + cli(); + repeat: + req = request+NR_REQUEST; +*************** +*** 238,245 **** +--- 268,281 ---- + if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || + !(blk_dev[major].request_fn)) { + printk("ll_rw_block: Trying to read nonexistent block-device\n\r"); ++ bh->b_dirt = bh->b_uptodate = 0; + return; + } ++ if ((rw == WRITE || rw == WRITEA) && is_read_only(bh->b_dev)) { ++ printk("Can't write to read-only device 0x%X\n\r",bh->b_dev); ++ bh->b_dirt = bh->b_uptodate = 0; ++ return; ++ } + make_request(major,rw,bh); + } + +*************** +*** 251,256 **** +--- 287,293 ---- + request[i].dev = -1; + request[i].next = NULL; + } ++ memset(ro_bits,0,sizeof(ro_bits)); + #ifdef RAMDISK + mem_start += rd_init(mem_start, RAMDISK*1024); + #endif +*************** +*** 270,275 **** +--- 307,316 ---- + + if (rw!=READ && rw!=WRITE) { + printk("ll_rw_swap: bad block dev command, must be R/W"); ++ return; ++ } ++ if (rw == WRITE && is_read_only(dev)) { ++ printk("Can't swap to read-only device 0x%X\n\r",dev); + return; + } + +*** 0.96c/linux/kernel/blk_drv/floppy.c Sat Jul 4 20:44:26 1992 +--- linux/kernel/blk_drv/floppy.c Sat Jul 11 00:49:35 1992 +*************** +*** 38,43 **** +--- 38,45 ---- + * the floppy-change signal detection. + */ + ++ #define FLOPPY_IRQ 6 ++ + #include + #include + #include +*************** +*** 205,211 **** + * and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA). + */ + +- extern void floppy_interrupt(void); + extern char tmp_floppy_area[1024]; + extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS]; + +--- 207,212 ---- +*************** +*** 560,566 **** + else redo_fd_request(); + } + +! void unexpected_floppy_interrupt(void) + { + current_track = NO_TRACK; + output_byte(FD_SENSEI); +--- 561,567 ---- + else redo_fd_request(); + } + +! static void unexpected_floppy_interrupt(void) + { + current_track = NO_TRACK; + output_byte(FD_SENSEI); +*************** +*** 831,836 **** +--- 832,840 ---- + int drive,cnt,okay; + struct floppy_struct *this; + ++ switch (cmd) { ++ RO_IOCTLS(inode->i_rdev,param); ++ } + if (!suser()) return -EPERM; + drive = MINOR(inode->i_rdev); + switch (cmd) { +*************** +*** 975,980 **** +--- 979,1006 ---- + floppy_release /* release */ + }; + ++ static void floppy_interrupt(int cpl) ++ { ++ void (*handler)(void) = DEVICE_INTR; ++ ++ DEVICE_INTR = NULL; ++ if (!handler) ++ handler = unexpected_floppy_interrupt; ++ handler(); ++ } ++ ++ /* ++ * This is the harddisk IRQ descruption. The SA_INTERRUPT in sa_flags ++ * means we run the IRQ-handler with interrupts disabled: this is bad for ++ * interrupt latency, but may be safer... ++ */ ++ static struct sigaction floppy_sigaction = { ++ floppy_interrupt, ++ 0, ++ SA_INTERRUPT, ++ NULL ++ }; ++ + void floppy_init(void) + { + outb(current_DOR,FD_DOR); +*************** +*** 984,989 **** + timer_table[FLOPPY_TIMER].fn = floppy_shutdown; + timer_active &= ~(1 << FLOPPY_TIMER); + config_types(); +! set_intr_gate(0x26,&floppy_interrupt); +! outb(inb_p(0x21)&~0x40,0x21); + } +--- 1010,1015 ---- + timer_table[FLOPPY_TIMER].fn = floppy_shutdown; + timer_active &= ~(1 << FLOPPY_TIMER); + config_types(); +! if (irqaction(FLOPPY_IRQ,&floppy_sigaction)) +! printk("Unable to grab IRQ%d for the floppy driver\n",FLOPPY_IRQ); + } +*** 0.96c/linux/kernel/blk_drv/blk.h Wed Jun 3 04:23:19 1992 +--- linux/kernel/blk_drv/blk.h Sat Jul 11 00:49:34 1992 +*************** +*** 54,59 **** +--- 54,67 ---- + + extern int * blk_size[NR_BLK_DEV]; + ++ extern int is_read_only(int dev); ++ extern void set_device_ro(int dev,int flag); ++ ++ #define RO_IOCTLS(dev,where) \ ++ case BLKROSET: if (!suser()) return -EPERM; \ ++ set_device_ro((dev),get_fs_long((long *) (where))); return 0; \ ++ case BLKROGET: put_fs_long(is_read_only(dev),(long *) (where)); return 0; ++ + #ifdef MAJOR_NR + + /* +*** 0.96c/linux/kernel/blk_drv/ramdisk.c Thu Jun 18 14:16:39 1992 +--- linux/kernel/blk_drv/ramdisk.c Tue Jul 7 16:03:33 1992 +*************** +*** 84,90 **** + void rd_load(void) + { + struct buffer_head *bh; +! struct super_block s; + int block = 256; /* Start at block 256 */ + int i = 1; + int nblocks; +--- 84,90 ---- + void rd_load(void) + { + struct buffer_head *bh; +! struct minix_super_block s; + int block = 256; /* Start at block 256 */ + int i = 1; + int nblocks; +*** 0.96c/linux/kernel/blk_drv/scsi/aha1542.c Thu Jul 2 01:54:30 1992 +--- linux/kernel/blk_drv/scsi/aha1542.c Thu Jul 9 19:44:56 1992 +*************** +*** 8,13 **** +--- 8,14 ---- + #include + #include + #include ++ #include + #include + #include + #include +*************** +*** 34,40 **** + long WAITtimeout, WAITnexttimeout = 3000000; + + void (*do_done)() = NULL; +- extern void aha1542_interrupt(); + + #define aha1542_intr_reset() outb(IRST, CONTROL) + #define aha1542_enable_intr() outb(inb_p(0xA1) & ~8, 0xA1) +--- 35,40 ---- +*************** +*** 192,198 **** + } + + /* A "high" level interrupt handler */ +! void aha1542_intr_handle(void) + { + int flag = inb(INTRFLAGS); + void (*my_done)() = do_done; +--- 192,198 ---- + } + + /* A "high" level interrupt handler */ +! static void aha1542_interrupt(int cpl) + { + int flag = inb(INTRFLAGS); + void (*my_done)() = do_done; +*************** +*** 200,206 **** + + do_done = NULL; + #ifdef DEBUG +! printk("aha1542_intr_handle: "); + if (!(flag&ANYINTR)) printk("no interrupt?"); + if (flag&MBIF) printk("MBIF "); + if (flag&MBOA) printk("MBOF "); +--- 200,206 ---- + + do_done = NULL; + #ifdef DEBUG +! printk("aha1542_interrupt: "); + if (!(flag&ANYINTR)) printk("no interrupt?"); + if (flag&MBIF) printk("MBIF "); + if (flag&MBOA) printk("MBOF "); +*************** +*** 212,218 **** + #endif + aha1542_intr_reset(); + if (!my_done) { +! printk("aha1542_intr_handle: Unexpected interrupt\n"); + return; + } + +--- 212,218 ---- + #endif + aha1542_intr_reset(); + if (!my_done) { +! printk("aha1542_interrupt: Unexpected interrupt\n"); + return; + } + +*************** +*** 219,225 **** + /* is there mail :-) */ + + if (!mb[1].status) { +! DEB(printk("aha1542_intr_handle: strange: mbif but no mail!\n")); + my_done(DID_TIME_OUT << 16); + return; + } +--- 219,225 ---- + /* is there mail :-) */ + + if (!mb[1].status) { +! DEB(printk("aha1542_interrupt: strange: mbif but no mail!\n")); + my_done(DID_TIME_OUT << 16); + return; + } +*************** +*** 235,252 **** + + if (ccb.tarstat == 2) { + int i; +! DEB(printk("aha1542_intr_handle: sense:")); + for (i = 0; i < 12; i++) + printk("%02x ", ccb.cdb[ccb.cdblen+i]); + printk("\n"); + /* +! DEB(printk("aha1542_intr_handle: buf:")); + for (i = 0; i < bufflen; i++) + printk("%02x ", ((unchar *)buff)[i]); + printk("\n"); + */ + } +! DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus)); + my_done(errstatus); + return; + } +--- 235,252 ---- + + if (ccb.tarstat == 2) { + int i; +! DEB(printk("aha1542_interrupt: sense:")); + for (i = 0; i < 12; i++) + printk("%02x ", ccb.cdb[ccb.cdblen+i]); + printk("\n"); + /* +! DEB(printk("aha1542_interrupt: buf:")); + for (i = 0; i < bufflen; i++) + printk("%02x ", ((unchar *)buff)[i]); + printk("\n"); + */ + } +! DEB(if (errstatus) printk("aha1542_interrupt: returning %6x\n", errstatus)); + my_done(errstatus); + return; + } +*************** +*** 355,361 **** + + void call_buh() + { +! set_intr_gate(0x2b,&aha1542_interrupt); + } + + /* return non-zero on detection */ +--- 355,368 ---- + + void call_buh() + { +! struct sigaction sa; +! +! sa.sa_handler = aha1542_interrupt; +! sa.sa_flags = SA_INTERRUPT; +! sa.sa_mask = 0; +! sa.sa_restorer = NULL; +! if (irqaction(intr_chan,&sa)) +! printk("Unable to allocate IRQ%d for aha controller\n", intr_chan); + } + + /* return non-zero on detection */ +*************** +*** 448,482 **** + DEB(printk("aha1542_reset called\n")); + return 0; + } +- +- __asm__(" +- _aha1542_interrupt: +- cld +- pushl %eax +- pushl %ecx +- pushl %edx +- push %ds +- push %es +- push %fs +- movl $0x10,%eax +- mov %ax,%ds +- mov %ax,%es +- movl $0x17,%eax +- mov %ax,%fs +- movb $0x20,%al +- outb %al,$0xA0 # EOI to interrupt controller #1 +- jmp 1f # give port chance to breathe +- 1: jmp 1f +- 1: outb %al,$0x20 +- # Please, someone, change this to use the timer +- # andl $0xfffeffff,_timer_active +- movl $_aha1542_intr_handle,%edx +- call *%edx # ``interesting'' way of handling intr. +- pop %fs +- pop %es +- pop %ds +- popl %edx +- popl %ecx +- popl %eax +- iret +- "); +--- 455,457 ---- +*** 0.96c/linux/kernel/blk_drv/scsi/sd_ioctl.c Sat May 2 18:37:38 1992 +--- linux/kernel/blk_drv/scsi/sd_ioctl.c Sat Jul 11 00:49:36 1992 +*************** +*** 3,8 **** +--- 3,11 ---- + #include + #include + #include ++ #include ++ #include "../blk.h" ++ #include + #include "scsi.h" + #include "sd.h" + +*************** +*** 13,18 **** +--- 16,22 ---- + int dev = inode->i_rdev; + + switch (cmd) { ++ RO_IOCTLS(dev,arg); + default: + return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device,cmd,(void *) arg); + } +*** 0.96c/linux/kernel/blk_drv/scsi/ultrastor.c Fri May 29 00:26:06 1992 +--- linux/kernel/blk_drv/scsi/ultrastor.c Thu Jul 9 19:27:15 1992 +*************** +*** 156,162 **** + }; + #endif + +! void ultrastor_interrupt(void); + + static void (*ultrastor_done)(int, int) = 0; + +--- 156,162 ---- + }; + #endif + +! void ultrastor_interrupt(int cpl); + + static void (*ultrastor_done)(int, int) = 0; + +*************** +*** 293,303 **** + host_number = hostnum; + scsi_hosts[hostnum].this_id = config.ha_scsi_id; + #if USE_QUEUECOMMAND +! set_intr_gate(0x20 + config.interrupt, ultrastor_interrupt); +! /* gate to PIC 2 */ +! outb_p(inb_p(0x21) & ~BIT(2), 0x21); +! /* enable the interrupt */ +! outb(inb_p(0xA1) & ~BIT(config.interrupt - 8), 0xA1); + #endif + return TRUE; + } +--- 293,309 ---- + host_number = hostnum; + scsi_hosts[hostnum].this_id = config.ha_scsi_id; + #if USE_QUEUECOMMAND +! { +! struct sigaction sa; +! sa.sa_handler = ultrastor_interrupt; +! sa.sa_flags = SA_INTERRUPT; +! sa.sa_mask = 0; +! sa.sa_restorer = NULL; +! if (irqaction(config.interrupt,&sa)) { +! printk("unable to get IRQ%d for ultrastor controller\n",config.interrupt); +! return FALSE; +! } +! } + #endif + return TRUE; + } +*************** +*** 421,427 **** + } + + #if USE_QUEUECOMMAND +! void ultrastor_interrupt_service(void) + { + if (ultrastor_done == 0) { + printk("US14F: unexpected ultrastor interrupt\n\r"); +--- 427,433 ---- + } + + #if USE_QUEUECOMMAND +! void ultrastor_interrupt(int cpl) + { + if (ultrastor_done == 0) { + printk("US14F: unexpected ultrastor interrupt\n\r"); +*************** +*** 434,470 **** + (mscp.adapter_status << 16) | mscp.target_status); + ultrastor_done = 0; + } +- +- __asm__(" +- _ultrastor_interrupt: +- cld +- pushl %eax +- pushl %ecx +- pushl %edx +- push %ds +- push %es +- push %fs +- movl $0x10,%eax +- mov %ax,%ds +- mov %ax,%es +- movl $0x17,%eax +- mov %ax,%fs +- movb $0x20,%al +- outb %al,$0xA0 # EOI to interrupt controller #1 +- outb %al,$0x80 # give port chance to breathe +- outb %al,$0x80 +- outb %al,$0x80 +- outb %al,$0x80 +- outb %al,$0x20 +- call _ultrastor_interrupt_service +- pop %fs +- pop %es +- pop %ds +- popl %edx +- popl %ecx +- popl %eax +- iret +- "); + #endif + + #endif +--- 440,445 ---- +*** 0.96c/linux/kernel/sys_call.S Thu Jun 25 16:40:29 1992 +--- linux/kernel/sys_call.S Tue Jul 7 18:39:02 1992 +*************** +*** 81,87 **** + * Ok, I get parallel printer interrupts while using the floppy for some + * strange reason. Urgel. Now I just ignore them. + */ +! .globl _system_call,_timer_interrupt,_sys_execve + .globl _device_not_available, _coprocessor_error + .globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op + .globl _double_fault,_coprocessor_segment_overrun +--- 81,87 ---- + * Ok, I get parallel printer interrupts while using the floppy for some + * strange reason. Urgel. Now I just ignore them. + */ +! .globl _system_call,_sys_execve + .globl _device_not_available, _coprocessor_error + .globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op + .globl _double_fault,_coprocessor_segment_overrun +*************** +*** 88,95 **** + .globl _invalid_TSS,_segment_not_present,_stack_segment + .globl _general_protection,_irq13,_reserved + .globl _alignment_check,_page_fault +! .globl _keyboard_interrupt,_hd_interrupt +! .globl _IRQ3_interrupt,_IRQ4_interrupt,_IRQ5_interrupt,_IRQ9_interrupt + + #define SAVE_ALL \ + cld; \ +--- 88,94 ---- + .globl _invalid_TSS,_segment_not_present,_stack_segment + .globl _general_protection,_irq13,_reserved + .globl _alignment_check,_page_fault +! .globl ret_from_sys_call + + #define SAVE_ALL \ + cld; \ +*************** +*** 170,184 **** + jne 2f + cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ? + jne 2f +! 1: movl _current,%eax +! cmpl _task,%eax # task[0] cannot have signals +! je 2f +! cmpl $0,_need_resched + jne reschedule + cmpl $0,state(%eax) # state + jne reschedule + cmpl $0,counter(%eax) # counter + je reschedule + movl signal(%eax),%ebx + movl blocked(%eax),%ecx + notl %ecx +--- 169,185 ---- + jne 2f + cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ? + jne 2f +! 1: cmpl $0,_need_resched + jne reschedule ++ movl _current,%eax + cmpl $0,state(%eax) # state + jne reschedule + cmpl $0,counter(%eax) # counter + je reschedule ++ movl $1,_need_resched ++ cmpl _task,%eax # task[0] cannot have signals ++ je 2f ++ movl $0,_need_resched + movl signal(%eax),%ebx + movl blocked(%eax),%ecx + notl %ecx +*************** +*** 240,340 **** + call _math_emulate + addl $4,%esp + ret +- +- .align 2 +- _keyboard_interrupt: +- pushl $-1 +- SAVE_ALL +- ACK_FIRST(0x02) +- sti +- call _do_keyboard +- cli +- UNBLK_FIRST(0x02) +- jmp ret_from_sys_call +- +- .align 2 +- _IRQ3_interrupt: +- pushl $-1 +- SAVE_ALL +- ACK_FIRST(0x08) +- sti +- pushl $3 +- call _do_IRQ +- addl $4,%esp +- cli +- UNBLK_FIRST(0x08) +- jmp ret_from_sys_call +- +- .align 2 +- _IRQ4_interrupt: +- pushl $-1 +- SAVE_ALL +- ACK_FIRST(0x10) +- sti +- pushl $4 +- call _do_IRQ +- addl $4,%esp +- cli +- UNBLK_FIRST(0x10) +- jmp ret_from_sys_call +- +- .align 2 +- _IRQ5_interrupt: +- pushl $-1 +- SAVE_ALL +- ACK_FIRST(0x20) +- sti +- pushl $5 +- call _do_IRQ +- addl $4,%esp +- cli +- UNBLK_FIRST(0x20) +- jmp ret_from_sys_call +- +- .align 2 +- _IRQ9_interrupt: +- pushl $-1 +- SAVE_ALL +- ACK_SECOND(0x02) +- sti +- pushl $9 +- call _do_IRQ +- addl $4,%esp +- cli +- UNBLK_SECOND(0x02) +- jmp ret_from_sys_call +- +- .align 2 +- _timer_interrupt: +- pushl $-1 # mark this as an int +- SAVE_ALL +- ACK_FIRST(0x01) +- sti +- incl _jiffies +- 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 ... +- cli +- UNBLK_FIRST(0x01) +- jmp ret_from_sys_call +- +- .align 2 +- _hd_interrupt: +- pushl $-1 +- SAVE_ALL +- ACK_SECOND(0x40) +- andl $0xfffeffff,_timer_active +- xorl %edx,%edx +- xchgl _do_hd,%edx +- testl %edx,%edx +- jne 1f +- movl $_unexpected_hd_interrupt,%edx +- 1: call *%edx # "interesting" way of handling intr. +- cli +- UNBLK_SECOND(0x40) +- jmp ret_from_sys_call + + .align 2 + _sys_execve: +--- 241,246 ---- +*** /dev/null Sat Jul 11 22:43:15 1992 +--- linux/kernel/irq.c Thu Jul 9 14:43:34 1992 +*************** +*** 0 **** +--- 1,171 ---- ++ /* ++ * linux/kernel/irq.c ++ * ++ * (C) 1992 Linus Torvalds ++ * ++ * This file contains the code used by various IRQ handling routines: ++ * asking for different IRQ's should be done through these routines ++ * instead of just grabbing them. Thus setups with different IRQ numbers ++ * shouldn't result in any weird surprises, and installing new handlers ++ * should be easier. ++ */ ++ ++ /* ++ * IRQ's are in fact implemented a bit like signal handlers for the kernel. ++ * The same sigaction struct is used, and with similar semantics (ie there ++ * is a SA_INTERRUPT flag etc). Naturally it's not a 1:1 relation, but there ++ * are similarities. ++ * ++ * sa_handler(int irq_NR) is the default function called. ++ * sa_mask is 0 if nothing uses this IRQ ++ * sa_flags contains various info: SA_INTERRUPT etc ++ * sa_restorer is the unused ++ */ ++ ++ #include ++ #include ++ ++ #include ++ ++ #include ++ #include ++ #include ++ #include ++ ++ struct sigaction irq_sigaction[16] = { ++ { NULL, 0, 0, NULL }, ++ }; ++ ++ /* ++ * This builds up the IRQ handler stubs using some ugly macros in irq.h ++ */ ++ BUILD_IRQ(FIRST,0,0x01) ++ BUILD_IRQ(FIRST,1,0x02) ++ BUILD_IRQ(FIRST,2,0x04) ++ BUILD_IRQ(FIRST,3,0x08) ++ BUILD_IRQ(FIRST,4,0x10) ++ BUILD_IRQ(FIRST,5,0x20) ++ BUILD_IRQ(FIRST,6,0x40) ++ BUILD_IRQ(FIRST,7,0x80) ++ BUILD_IRQ(SECOND,8,0x01) ++ BUILD_IRQ(SECOND,9,0x02) ++ BUILD_IRQ(SECOND,10,0x04) ++ BUILD_IRQ(SECOND,11,0x08) ++ BUILD_IRQ(SECOND,12,0x10) ++ BUILD_IRQ(SECOND,13,0x20) ++ BUILD_IRQ(SECOND,14,0x40) ++ BUILD_IRQ(SECOND,15,0x80) ++ ++ /* ++ * This routine gets called at every IRQ request. Interrupts ++ * are enabled, the interrupt has been accnowledged and this ++ * particular interrupt is disabled when this is called. ++ * ++ * The routine has to call the appropriate handler (disabling ++ * interrupts if needed first), and then re-enable this interrupt- ++ * line if the handler was ok. If no handler exists, the IRQ isn't ++ * re-enabled. ++ * ++ * Note similarities on a very low level between this and the ++ * do_signal() function. Naturally this is simplified, but they ++ * get similar arguments, use them similarly etc... Note that ++ * unlike the signal-handlers, the IRQ-handlers don't get the IRQ ++ * (signal) number as argument, but the cpl value at the time of ++ * the interrupt. ++ */ ++ void do_IRQ(int irq, struct pt_regs * regs) ++ { ++ struct sigaction * sa = irq + irq_sigaction; ++ void (*handler)(int); ++ ++ if (!(handler = sa->sa_handler)) ++ return; ++ if (sa->sa_flags & SA_INTERRUPT) ++ cli(); ++ handler(regs->cs & 3); ++ cli(); ++ if (irq < 8) ++ outb(inb_p(0x21) & ~(1< 15) ++ return -EINVAL; ++ if (irq == 2) ++ irq = 9; ++ sa = irq + irq_sigaction; ++ if (sa->sa_mask) ++ return -EBUSY; ++ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags)); ++ *sa = *new; ++ sa->sa_mask = 1; ++ if (irq < 8) ++ outb(inb_p(0x21) & ~(1< 15) { ++ printk("Trying to free IRQ%d\n",irq); ++ return; ++ } ++ if (!sa->sa_mask) { ++ printk("Trying to free free IRQ%d\n",irq); ++ return; ++ } ++ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags)); ++ if (irq < 8) ++ outb(inb_p(0x21) | (1<sa_handler = NULL; ++ sa->sa_flags = 0; ++ sa->sa_mask = 0; ++ sa->sa_restorer = NULL; ++ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags)); ++ } ++ ++ void init_IRQ(void) ++ { ++ set_trap_gate(0x20,IRQ0_interrupt); ++ set_trap_gate(0x21,IRQ1_interrupt); ++ set_trap_gate(0x22,IRQ2_interrupt); ++ set_trap_gate(0x23,IRQ3_interrupt); ++ set_trap_gate(0x24,IRQ4_interrupt); ++ set_trap_gate(0x25,IRQ5_interrupt); ++ set_trap_gate(0x26,IRQ6_interrupt); ++ set_trap_gate(0x27,IRQ7_interrupt); ++ set_trap_gate(0x28,IRQ8_interrupt); ++ set_trap_gate(0x29,IRQ10_interrupt); ++ set_trap_gate(0x2a,IRQ10_interrupt); ++ set_trap_gate(0x2b,IRQ11_interrupt); ++ set_trap_gate(0x2c,IRQ12_interrupt); ++ set_trap_gate(0x2d,IRQ13_interrupt); ++ set_trap_gate(0x2e,IRQ14_interrupt); ++ set_trap_gate(0x2f,IRQ15_interrupt); ++ } +*** 0.96c/linux/kernel/ptrace.c Wed Jun 17 13:37:55 1992 +--- linux/kernel/ptrace.c Thu Jul 9 19:18:53 1992 +*************** +*** 39,45 **** + { + int i; + +! for (i = 0; i < NR_TASKS; i++) { + if (task[i] != NULL && (task[i]->pid == pid)) + return task[i]; + } +--- 39,45 ---- + { + int i; + +! for (i = 1; i < NR_TASKS; i++) { + if (task[i] != NULL && (task[i]->pid == pid)) + return task[i]; + } +*************** +*** 238,243 **** +--- 238,245 ---- + if (request == PTRACE_ATTACH) { + long tmp; + ++ if (child == current) ++ return -EPERM; + if ((!current->dumpable || (current->uid != child->euid) || + (current->gid != child->egid)) && !suser()) + return -EPERM; +*** 0.96c/linux/lib/Makefile Sun Jul 5 03:11:58 1992 +--- linux/lib/Makefile Sat Jul 11 20:14:30 1992 +*************** +*** 14,20 **** + $(CC) $(CFLAGS) -c $< + + OBJS = ctype.o _exit.o open.o close.o errno.o write.o dup.o setsid.o \ +! execve.o wait.o string.o malloc.o itimer.o + + lib.a: $(OBJS) + $(AR) rcs lib.a $(OBJS) +--- 14,20 ---- + $(CC) $(CFLAGS) -c $< + + OBJS = ctype.o _exit.o open.o close.o errno.o write.o dup.o setsid.o \ +! execve.o wait.o string.o malloc.o + + lib.a: $(OBJS) + $(AR) rcs lib.a $(OBJS) +*************** +*** 36,43 **** + dup.o : dup.c /usr/src/linux/include/linux/unistd.h + errno.o : errno.c + execve.o : execve.c /usr/src/linux/include/linux/unistd.h +- itimer.o : itimer.c /usr/src/linux/include/linux/unistd.h /usr/src/linux/include/sys/time.h \ +- /usr/src/linux/include/time.h /usr/src/linux/include/sys/types.h /usr/src/linux/include/stddef.h + malloc.o : malloc.c /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/mm.h \ + /usr/src/linux/include/linux/fs.h /usr/src/linux/include/sys/types.h /usr/src/linux/include/stddef.h \ + /usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \ +--- 36,41 ---- +*** 0.96c/linux/include/sys/time.h Mon May 25 22:18:54 1992 +--- linux/include/sys/time.h Wed Jul 8 15:17:52 1992 +*************** +*** 55,61 **** + }; + + int getitimer(int which, struct itimerval *value); +! int setitimer(int which, struct itimerval *value, struct itimerval *ovalue); + + #include + #include +--- 55,61 ---- + }; + + int getitimer(int which, struct itimerval *value); +! int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue); + + #include + #include +*** 0.96c/linux/include/linux/hdreg.h Fri Apr 24 18:26:25 1992 +--- linux/include/linux/hdreg.h Sat Jul 11 00:49:34 1992 +*************** +*** 69,73 **** +--- 69,74 ---- + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; ++ unsigned long start; + }; + #endif +*** 0.96c/linux/include/linux/sched.h Sun Jul 5 01:27:18 1992 +--- linux/include/linux/sched.h Mon Jul 6 00:18:21 1992 +*************** +*** 228,233 **** +--- 228,237 ---- + extern void wake_up(struct task_struct ** p); + extern int in_group_p(gid_t grp); + ++ extern int request_irq(unsigned int irq,void (*handler)(int)); ++ extern void free_irq(unsigned int irq); ++ extern int irqaction(unsigned int irq,struct sigaction * new); ++ + /* + * Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall + * 4-TSS0, 5-LDT0, 6-TSS1 etc ... +*** 0.96c/linux/include/linux/tty.h Sat Jul 4 03:28:16 1992 +--- linux/include/linux/tty.h Tue Jul 7 14:54:51 1992 +*************** +*** 69,76 **** + extern void put_tty_queue(char c, struct tty_queue * queue); + extern int get_tty_queue(struct tty_queue * queue); + +- #define PUTCH(c,queue) put_tty_queue((c),(queue)) +- #define GETCH(queue) get_tty_queue(queue) + #define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR]) + #define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT]) + #define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE]) +--- 69,74 ---- +*************** +*** 166,171 **** +--- 164,170 ---- + + extern void flush_input(struct tty_struct * tty); + extern void flush_output(struct tty_struct * tty); ++ extern void wait_until_sent(struct tty_struct * tty); + extern void copy_to_cooked(struct tty_struct * tty); + + extern int tty_ioctl(struct inode *, struct file *, unsigned int, unsigned int); +*** 0.96c/linux/include/linux/fs.h Fri Jul 3 03:09:37 1992 +--- linux/include/linux/fs.h Sat Jul 11 01:27:13 1992 +*************** +*** 43,49 **** + + #define NR_OPEN 32 + #define NR_INODE 128 +! #define NR_FILE 64 + #define NR_SUPER 8 + #define NR_HASH 307 + #define NR_BUFFERS nr_buffers +--- 43,49 ---- + + #define NR_OPEN 32 + #define NR_INODE 128 +! #define NR_FILE 128 + #define NR_SUPER 8 + #define NR_HASH 307 + #define NR_BUFFERS nr_buffers +*************** +*** 71,76 **** +--- 71,103 ---- + #define SEL_OUT 2 + #define SEL_EX 4 + ++ /* ++ * These are the fs-independent mount-flags: up to 16 flags are supported ++ */ ++ #define MS_RDONLY 1 /* mount read-only */ ++ #define MS_NOSUID 2 /* ignore suid and sgid bits */ ++ #define MS_NODEV 4 /* disallow access to device special files */ ++ #define MS_NOEXEC 8 /* disallow program execution */ ++ ++ /* ++ * Note that read-only etc flags are inode-specific: setting some file-system ++ * flags just means all the inodes inherit those flags by default. It might be ++ * possible to overrride it sevelctively if you really wanted to with some ++ * ioctl() that is not currently implemented. ++ */ ++ #define IS_RDONLY(inode) ((inode)->i_flags & MS_RDONLY) ++ #define IS_NOSUID(inode) ((inode)->i_flags & MS_NOSUID) ++ #define IS_NODEV(inode) ((inode)->i_flags & MS_NODEV) ++ #define IS_NOEXEC(inode) ((inode)->i_flags & MS_NOEXEC) ++ ++ /* the read-only stuff doesn't really belong here, but any other place is ++ probably as bad and I don't want to create yet another include file. */ ++ ++ #define BLKROSET 4701 /* set device read-only (0 = read-write) */ ++ #define BLKROGET 4702 /* get read-only status (0 = read_write) */ ++ ++ #define BMAP_IOCTL 1 ++ + typedef char buffer_block[BLOCK_SIZE]; + + struct buffer_head { +*************** +*** 107,112 **** +--- 134,140 ---- + struct task_struct * i_wait; + struct task_struct * i_wait2; /* for pipes */ + unsigned short i_count; ++ unsigned short i_flags; + unsigned char i_lock; + unsigned char i_dirt; + unsigned char i_pipe; +*************** +*** 120,125 **** +--- 148,154 ---- + unsigned short f_flags; + unsigned short f_count; + unsigned short f_reada; ++ unsigned short f_rdev; /* needed for /dev/tty */ + struct inode * f_inode; + struct file_operations * f_op; + off_t f_pos; +*************** +*** 159,164 **** +--- 188,194 ---- + unsigned char s_dirt; + /* TUBE */ + struct super_operations *s_op; ++ int s_flags; + }; + + struct file_operations { +*** 0.96c/linux/include/linux/config.h Sun Jul 5 01:28:18 1992 +--- linux/include/linux/config.h Sat Jul 11 20:16:04 1992 +*************** +*** 26,32 **** + #define DEF_INITSEG 0x9000 + #define DEF_SYSSEG 0x1000 + #define DEF_SETUPSEG 0x9020 +! #define DEF_SYSSIZE 0x4000 + + /* + * The root-device is no longer hard-coded. You can change the default +--- 26,32 ---- + #define DEF_INITSEG 0x9000 + #define DEF_SYSSEG 0x1000 + #define DEF_SETUPSEG 0x9020 +! #define DEF_SYSSIZE 0x5000 + + /* + * The root-device is no longer hard-coded. You can change the default +*** /dev/null Sat Jul 11 22:43:15 1992 +--- linux/include/asm/irq.h Tue Jul 7 18:45:48 1992 +*************** +*** 0 **** +--- 1,75 ---- ++ #ifndef _ASM_IRQ_H ++ #define _ASM_IRQ_H ++ ++ /* ++ * linux/include/asm/irq.h ++ * ++ * (C) 1992 Linus Torvalds ++ */ ++ ++ #define SAVE_ALL \ ++ "cld\n\t" \ ++ "push %gs\n\t" \ ++ "push %fs\n\t" \ ++ "push %es\n\t" \ ++ "push %ds\n\t" \ ++ "pushl %eax\n\t" \ ++ "pushl %ebp\n\t" \ ++ "pushl %edi\n\t" \ ++ "pushl %esi\n\t" \ ++ "pushl %edx\n\t" \ ++ "pushl %ecx\n\t" \ ++ "pushl %ebx\n\t" \ ++ "movl $0x10,%edx\n\t" \ ++ "mov %dx,%ds\n\t" \ ++ "mov %dx,%es\n\t" \ ++ "movl $0x17,%edx\n\t" \ ++ "mov %dx,%fs\n\t" ++ ++ #define ACK_FIRST(mask) \ ++ "inb $0x21,%al\n\t" \ ++ "jmp 1f\n" \ ++ "1:\tjmp 1f\n" \ ++ "1:\torb $" #mask ",%al\n\t" \ ++ "outb %al,$0x21\n\t" \ ++ "jmp 1f\n" \ ++ "1:\tjmp 1f\n" \ ++ "1:\tmovb $0x20,%al\n\t" \ ++ "outb %al,$0x20\n\t" ++ ++ #define ACK_SECOND(mask) \ ++ "inb $0xA1,%al\n\t" \ ++ "jmp 1f\n" \ ++ "1:\tjmp 1f\n" \ ++ "1:\torb $" #mask ",%al\n\t" \ ++ "outb %al,$0xA1\n\t" \ ++ "jmp 1f\n" \ ++ "1:\tjmp 1f\n" \ ++ "1:\tmovb $0x20,%al\n\t" \ ++ "outb %al,$0xA0" \ ++ "jmp 1f\n" \ ++ "1:\tjmp 1f\n" \ ++ "1:\toutb %al,$0x20\n\t" ++ ++ #define IRQ_NAME2(nr) nr##_interrupt() ++ #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) ++ ++ #define BUILD_IRQ(chip,nr,mask) \ ++ extern void IRQ_NAME(nr); \ ++ __asm__( \ ++ "\n.align 2\n" \ ++ ".globl _IRQ" #nr "_interrupt\n" \ ++ "_IRQ" #nr "_interrupt:\n\t" \ ++ "pushl $-1\n\t" \ ++ SAVE_ALL \ ++ "cli\n\t" \ ++ ACK_##chip(mask) \ ++ "sti\n\t" \ ++ "movl %esp,%ebx\n\t" \ ++ "pushl %ebx\n\t" \ ++ "pushl $" #nr "\n\t" \ ++ "call _do_IRQ\n\t" \ ++ "addl $8,%esp\n\t" \ ++ "jmp ret_from_sys_call"); ++ ++ #endif diff --git a/kernel/Historic/old-versions/linux-0.96c.patch2 b/kernel/Historic/old-versions/linux-0.96c.patch2 new file mode 100644 index 00000000..02663e0e --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96c.patch2 @@ -0,0 +1,5509 @@ +*** 0.96c.pl1/linux/Makefile Sat Jul 18 22:27:57 1992 +--- linux/Makefile Thu Jul 16 02:34:48 1992 +*************** +*** 34,39 **** +--- 34,41 ---- + # KEYBOARD = -DKBD_DK -DKBDFLAGS=0 + # KEYBOARD = -DKBD_DK_LATIN1 -DKBDFLAGS=0x9F + # KEYBOARD = -DKBD_DVORAK -DKBDFLAGS=0 ++ # KEYBOARD = -DKBD_SG -DKBDFLAGS=0 ++ # KEYBOARD = -DKBD_SG_LATIN1 -DKBDFLAGS=0x9F + + # + # comment this line if you don't want the emulation-code +*************** +*** 66,72 **** + AR =ar + + ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o +! FILESYSTEMS =fs/minix/minix.o fs/ext/ext.o + DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a \ + kernel/blk_drv/scsi/scsi.a + MATH =kernel/math/math.a +--- 68,74 ---- + AR =ar + + ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o +! FILESYSTEMS =fs/minix/minix.o fs/ext/ext.o fs/msdos/msdos.o + DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a \ + kernel/blk_drv/scsi/scsi.a + MATH =kernel/math/math.a +*************** +*** 89,95 **** + + Version: + @./makever.sh +! @echo \#define UTS_RELEASE \"0.96c.pl1-`cat .version`\" > include/linux/config_rel.h + @echo \#define UTS_VERSION \"`date +%D`\" > include/linux/config_ver.h + touch include/linux/config.h + +--- 91,97 ---- + + Version: + @./makever.sh +! @echo \#define UTS_RELEASE \"0.96c.pl2-`cat .version`\" > include/linux/config_rel.h + @echo \#define UTS_VERSION \"`date +%D`\" > include/linux/config_ver.h + touch include/linux/config.h + +*** 0.96c.pl1/linux/fs/Makefile Sun Jul 5 03:11:06 1992 +--- linux/fs/Makefile Thu Jul 16 02:36:05 1992 +*************** +*** 7,13 **** + # + # Note 2! The CFLAGS definitions are now in the main makefile... + +! SUBDIRS =minix ext + + .c.s: + $(CC) $(CFLAGS) -S $< +--- 7,13 ---- + # + # Note 2! The CFLAGS definitions are now in the main makefile... + +! SUBDIRS =minix ext msdos + + .c.s: + $(CC) $(CFLAGS) -S $< +*** 0.96c.pl1/linux/fs/buffer.c Fri Jul 3 03:09:37 1992 +--- linux/fs/buffer.c Wed Jul 15 16:07:16 1992 +*************** +*** 30,36 **** + static struct buffer_head * start_buffer = (struct buffer_head *) &end; + static 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) +--- 30,36 ---- + static struct buffer_head * start_buffer = (struct buffer_head *) &end; + static struct buffer_head * hash_table[NR_HASH]; + static struct buffer_head * free_list; +! static struct wait_queue * buffer_wait = NULL; + int NR_BUFFERS = 0; + + static inline void wait_on_buffer(struct buffer_head * bh) +*** 0.96c.pl1/linux/fs/exec.c Sat Jul 18 22:27:57 1992 +--- linux/fs/exec.c Fri Jul 17 04:30:30 1992 +*************** +*** 101,106 **** +--- 101,107 ---- + has_dumped = 1; + /* write and seek example: from kernel space */ + __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); ++ dump.magic = CMAGIC; + dump.u_tsize = current->end_code / PAGE_SIZE; + dump.u_dsize = (current->brk - current->end_code) / PAGE_SIZE; + dump.u_ssize =((current->start_stack +(PAGE_SIZE-1)) / PAGE_SIZE) - +*************** +*** 168,173 **** +--- 169,176 ---- + struct inode * inode; + struct buffer_head * bh; + struct exec ex; ++ int i; ++ struct file * f; + + if (get_limit(0x17) != TASK_SIZE) + return -EINVAL; +*************** +*** 183,188 **** +--- 186,200 ---- + iput(inode); + return -EACCES; + } ++ if (inode->i_count > 1) { /* check for writers */ ++ f=0+file_table; ++ for (i=0 ; if_count && (f->f_mode & 2)) ++ if (inode == f->f_inode) { ++ iput(inode); ++ return -ETXTBSY; ++ } ++ } + if (!(bh = bread(inode->i_dev,bmap(inode,0)))) { + iput(inode); + return -EACCES; +*************** +*** 391,396 **** +--- 403,409 ---- + int sh_bang = 0; + unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4; + int ch; ++ struct file * f; + + if ((0xffff & eip[1]) != 0x000f) + panic("execve called from supervisor mode"); +*************** +*** 398,403 **** +--- 411,425 ---- + page[i]=0; + if (!(inode=namei(filename))) /* get executables inode */ + return -ENOENT; ++ if (inode->i_count > 1) { /* check for writers */ ++ f=0+file_table; ++ for (i=0 ; if_count && (f->f_mode & 2)) ++ if (inode == f->f_inode) { ++ retval = -ETXTBSY; ++ goto exec_error2; ++ } ++ } + argc = count(argv); + envc = count(envp); + +*** 0.96c.pl1/linux/fs/super.c Sat Jul 18 22:27:57 1992 +--- linux/fs/super.c Wed Jul 15 07:19:47 1992 +*************** +*** 11,17 **** + #include + #include + #include +! /* #include */ + #include + #include + #include +--- 11,17 ---- + #include + #include + #include +! #include + #include + #include + #include +*************** +*** 38,44 **** + static struct file_system_type file_systems[] = { + {minix_read_super,"minix"}, + {ext_read_super,"ext"}, +! /* {msdos_read_super,"msdos"}, */ + {NULL,NULL} + }; + +--- 38,44 ---- + static struct file_system_type file_systems[] = { + {minix_read_super,"minix"}, + {ext_read_super,"ext"}, +! {msdos_read_super,"msdos"}, + {NULL,NULL} + }; + +*************** +*** 65,74 **** + + void free_super(struct super_block * sb) + { +- cli(); + sb->s_lock = 0; + wake_up(&(sb->s_wait)); +- sti(); + } + + void wait_on_super(struct super_block * sb) +--- 65,72 ---- +*** 0.96c.pl1/linux/fs/namei.c Sat Jul 18 22:27:58 1992 +--- linux/fs/namei.c Wed Jul 15 03:05:09 1992 +*************** +*** 197,204 **** + struct inode ** res_inode) + { + const char * basename; +! int namelen,error; + struct inode * dir, *inode; + + if ((flag & O_TRUNC) && !(flag & O_ACCMODE)) + flag |= O_WRONLY; +--- 197,205 ---- + struct inode ** res_inode) + { + const char * basename; +! int namelen,error,i; + struct inode * dir, *inode; ++ struct task_struct ** p; + + if ((flag & O_TRUNC) && !(flag & O_ACCMODE)) + flag |= O_WRONLY; +*************** +*** 258,263 **** +--- 259,278 ---- + iput(inode); + return -EPERM; + } ++ if ((inode->i_count > 1) && (flag & O_ACCMODE)) ++ for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { ++ if (!*p) ++ continue; ++ if (inode == (*p)->executable) { ++ iput(inode); ++ return -ETXTBSY; ++ } ++ for (i=0; i < (*p)->numlibraries; i++) ++ if (inode == (*p)->libraries[i].library) { ++ iput(inode); ++ return -ETXTBSY; ++ } ++ } + if (flag & O_TRUNC) + if (inode->i_op && inode->i_op->truncate) { + inode->i_size = 0; +*** 0.96c.pl1/linux/fs/pipe.c Thu Jul 2 00:42:04 1992 +--- linux/fs/pipe.c Wed Jul 15 04:24:46 1992 +*************** +*** 117,122 **** +--- 117,144 ---- + } + } + ++ static int pipe_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait) ++ { ++ switch (sel_type) { ++ case SEL_IN: ++ if (!PIPE_EMPTY(*inode) || !PIPE_WRITERS(*inode)) ++ return 1; ++ select_wait(&PIPE_READ_WAIT(*inode), wait); ++ return 0; ++ case SEL_OUT: ++ if (!PIPE_FULL(*inode) || !PIPE_WRITERS(*inode)) ++ return 1; ++ select_wait(&PIPE_WRITE_WAIT(*inode), wait); ++ return 0; ++ case SEL_EX: ++ if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode)) ++ return 1; ++ select_wait(&inode->i_wait,wait); ++ return 0; ++ } ++ return 0; ++ } ++ + /* + * Ok, these three routines NOW keep track of readers/writers, + * Linus previously did it with inode->i_count checking. +*************** +*** 150,156 **** + pipe_read, + bad_pipe_rw, + pipe_readdir, +! NULL, /* pipe_select */ + pipe_ioctl, + NULL, /* no special open code */ + pipe_read_release +--- 172,178 ---- + pipe_read, + bad_pipe_rw, + pipe_readdir, +! pipe_select, + pipe_ioctl, + NULL, /* no special open code */ + pipe_read_release +*************** +*** 161,167 **** + bad_pipe_rw, + pipe_write, + pipe_readdir, +! NULL, /* pipe_select */ + pipe_ioctl, + NULL, /* no special open code */ + pipe_write_release +--- 183,189 ---- + bad_pipe_rw, + pipe_write, + pipe_readdir, +! pipe_select, + pipe_ioctl, + NULL, /* no special open code */ + pipe_write_release +*************** +*** 172,178 **** + pipe_read, + pipe_write, + pipe_readdir, +! NULL, /* pipe_select */ + pipe_ioctl, + NULL, /* no special open code */ + pipe_rdwr_release +--- 194,200 ---- + pipe_read, + pipe_write, + pipe_readdir, +! pipe_select, + pipe_ioctl, + NULL, /* no special open code */ + pipe_rdwr_release +*** 0.96c.pl1/linux/fs/select.c Sat Jun 27 16:14:28 1992 +--- linux/fs/select.c Wed Jul 15 16:46:59 1992 +*************** +*** 7,13 **** + + #include + #include +- #include + #include + #include + #include +--- 7,12 ---- +*************** +*** 29,183 **** + * understand what I'm doing here, then you understand how the linux sleep/wakeup + * mechanism works. + * +! * Two very simple procedures, add_wait() and free_wait() make all the work. We +! * have to have interrupts disabled throughout the select, but that's not really +! * such a loss: sleeping automatically frees interrupts when we aren't in this +! * task. + */ + + static select_table * sel_tables = NULL; + +- static void add_wait(struct task_struct ** wait_address, select_table * p) +- { +- int i; +- +- if (!wait_address) +- return; +- for (i = 0 ; i < p->nr ; i++) +- if (p->entry[i].wait_address == wait_address) +- return; +- current->next_wait = NULL; +- p->entry[p->nr].wait_address = wait_address; +- p->entry[p->nr].old_task = *wait_address; +- *wait_address = current; +- p->nr++; +- } +- +- /* +- * free_wait removes the current task from any wait-queues and then +- * wakes up the queues. +- */ +- static void free_one_table(select_table * p) +- { +- int i; +- struct task_struct ** tpp; +- +- for(tpp = &LAST_TASK ; tpp > &FIRST_TASK ; --tpp) +- if (*tpp && ((*tpp)->next_wait == p->current)) +- (*tpp)->next_wait = NULL; +- if (!p->nr) +- return; +- for (i = 0; i < p->nr ; i++) { +- wake_up(p->entry[i].wait_address); +- wake_up(&p->entry[i].old_task); +- } +- p->nr = 0; +- } +- + static void free_wait(select_table * p) + { +! select_table * tmp; + +! if (p->woken) +! return; +! p = sel_tables; +! sel_tables = NULL; +! while (p) { +! wake_up(&p->current); +! p->woken = 1; +! tmp = p->next_table; +! p->next_table = NULL; +! free_one_table(p); +! p = tmp; + } + } + +- static struct tty_struct * get_tty(struct inode * inode) +- { +- int major, minor; +- +- if (!S_ISCHR(inode->i_mode)) +- return NULL; +- if ((major = MAJOR(inode->i_rdev)) != 5 && major != 4) +- return NULL; +- if (major == 5) +- minor = current->tty; +- else +- minor = MINOR(inode->i_rdev); +- if (minor < 0) +- return NULL; +- return TTY_TABLE(minor); +- } +- + /* + * The check_XX functions check out a file. We know it's either +! * a pipe, a character device or a fifo (fifo's not implemented) + */ +! static int check_in(select_table * wait, struct inode * inode) + { +! struct tty_struct * tty; +! +! if (tty = get_tty(inode)) +! if (!EMPTY(tty->secondary)) +! return 1; +! else if (tty->link && !tty->link->count) +! return 1; +! else +! add_wait(&tty->secondary->proc_list, wait); +! else if (inode->i_pipe) +! if (!PIPE_EMPTY(*inode) || !PIPE_WRITERS(*inode)) +! return 1; +! else +! add_wait(&inode->i_wait, wait); +! else if (S_ISSOCK(inode->i_mode)) +! if (sock_select(inode, NULL, SEL_IN, wait)) +! return 1; +! else +! add_wait(&inode->i_wait, wait); + return 0; + } + +! static int check_out(select_table * wait, struct inode * inode) + { +! struct tty_struct * tty; +! +! if (tty = get_tty(inode)) +! if (!FULL(tty->write_q)) +! return 1; +! else +! add_wait(&tty->write_q->proc_list, wait); +! else if (inode->i_pipe) +! if (!PIPE_FULL(*inode)) +! return 1; +! else +! add_wait(&inode->i_wait, wait); +! else if (S_ISSOCK(inode->i_mode)) +! if (sock_select(inode, NULL, SEL_OUT, wait)) +! return 1; +! else +! add_wait(&inode->i_wait, wait); + return 0; + } + +! static int check_ex(select_table * wait, struct inode * inode) + { +! struct tty_struct * tty; +! +! if (tty = get_tty(inode)) +! if (!FULL(tty->write_q)) +! return 0; +! else +! return 0; +! else if (inode->i_pipe) +! if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode)) +! return 1; +! else +! add_wait(&inode->i_wait,wait); +! else if (S_ISSOCK(inode->i_mode)) +! if (sock_select(inode, NULL, SEL_EX, wait)) +! return 1; +! else +! add_wait(&inode->i_wait, wait); + return 0; + } + +--- 28,73 ---- + * understand what I'm doing here, then you understand how the linux sleep/wakeup + * mechanism works. + * +! * Two very simple procedures, select_wait() and free_wait() make all the work. +! * select_wait() is a inline-function defined in , as all select +! * functions have to call it to add an entry to the select table. + */ + + static select_table * sel_tables = NULL; + + static void free_wait(select_table * p) + { +! struct select_table_entry * entry = p->entry + p->nr; + +! while (p->nr > 0) { +! p->nr--; +! entry--; +! remove_wait_queue(entry->wait_address,&entry->wait); + } + } + + /* + * The check_XX functions check out a file. We know it's either +! * a pipe, a character device or a fifo + */ +! static int check_in(select_table * wait, struct inode * inode, struct file * file) + { +! if (file->f_op && file->f_op->select) +! return file->f_op->select(inode,file,SEL_IN,wait); + return 0; + } + +! static int check_out(select_table * wait, struct inode * inode, struct file * file) + { +! if (file->f_op && file->f_op->select) +! return file->f_op->select(inode,file,SEL_OUT,wait); + return 0; + } + +! static int check_ex(select_table * wait, struct inode * inode, struct file * file) + { +! if (file->f_op && file->f_op->select) +! return file->f_op->select(inode,file,SEL_EX,wait); + return 0; + } + +*************** +*** 186,191 **** +--- 76,82 ---- + { + int count; + select_table wait_table; ++ struct file * file; + int i; + fd_set mask; + +*************** +*** 209,235 **** + } + repeat: + wait_table.nr = 0; +- wait_table.woken = 0; +- wait_table.current = current; +- wait_table.next_table = sel_tables; +- sel_tables = &wait_table; + *inp = *outp = *exp = 0; + count = 0; + current->state = TASK_INTERRUPTIBLE; + mask = 1; + for (i = 0 ; i < NR_OPEN ; i++, mask += mask) { + if (mask & in) +! if (check_in(&wait_table,current->filp[i]->f_inode)) { + *inp |= mask; + count++; + } + if (mask & out) +! if (check_out(&wait_table,current->filp[i]->f_inode)) { + *outp |= mask; + count++; + } + if (mask & ex) +! if (check_ex(&wait_table,current->filp[i]->f_inode)) { + *exp |= mask; + count++; + } +--- 100,123 ---- + } + repeat: + wait_table.nr = 0; + *inp = *outp = *exp = 0; + count = 0; + current->state = TASK_INTERRUPTIBLE; + mask = 1; + for (i = 0 ; i < NR_OPEN ; i++, mask += mask) { ++ file = current->filp[i]; + if (mask & in) +! if (check_in(&wait_table,file->f_inode,file)) { + *inp |= mask; + count++; + } + if (mask & out) +! if (check_out(&wait_table,file->f_inode,file)) { + *outp |= mask; + count++; + } + if (mask & ex) +! if (check_ex(&wait_table,file->f_inode,file)) { + *exp |= mask; + count++; + } +*** 0.96c.pl1/linux/fs/ext/namei.c Sat Jul 18 22:28:06 1992 +--- linux/fs/ext/namei.c Wed Jul 15 16:11:22 1992 +*************** +*** 885,891 **** + int ext_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) + { +! static struct task_struct * wait = NULL; + static int lock = 0; + int result; + +--- 885,891 ---- + int ext_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) + { +! static struct wait_queue * wait = NULL; + static int lock = 0; + int result; + +*** /dev/null Sat Jul 18 22:26:09 1992 +--- linux/fs/msdos/Makefile Thu Jul 16 02:36:33 1992 +*************** +*** 0 **** +--- 1,77 ---- ++ # ++ # Makefile for the linux MS-DOS-filesystem routines. ++ # ++ # 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). ++ # ++ # Note 2! The CFLAGS definitions are now in the main makefile... ++ ++ .c.s: ++ $(CC) $(CFLAGS) \ ++ -S -o $*.s $< ++ .c.o: ++ $(CC) $(CFLAGS) -c -o $*.o $< ++ .s.o: ++ $(AS) -o $*.o $< ++ ++ OBJS= namei.o inode.o file.o dir.o misc.o fat.o ++ ++ msdos.o: $(OBJS) ++ $(LD) -r -o msdos.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: ++ dir.o : dir.c /usr/src/linux/include/errno.h /usr/src/linux/include/asm/segment.h \ ++ /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \ ++ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/sys/types.h /usr/src/linux/include/stddef.h \ ++ /usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \ ++ /usr/src/linux/include/linux/msdos_fs.h /usr/src/linux/include/linux/sched.h \ ++ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h \ ++ /usr/src/linux/include/signal.h /usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h \ ++ /usr/src/linux/include/time.h /usr/src/linux/include/sys/resource.h ++ fat.o : fat.c /usr/src/linux/include/errno.h /usr/src/linux/include/linux/stat.h \ ++ /usr/src/linux/include/linux/msdos_fs.h /usr/src/linux/include/sys/types.h /usr/src/linux/include/stddef.h \ ++ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \ ++ /usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \ ++ /usr/src/linux/include/linux/kernel.h ++ file.o : file.c /usr/src/linux/include/errno.h /usr/src/linux/include/asm/segment.h \ ++ /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/sys/types.h \ ++ /usr/src/linux/include/stddef.h /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/sched.h \ ++ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \ ++ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h \ ++ /usr/src/linux/include/sys/vfs.h /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h \ ++ /usr/src/linux/include/signal.h /usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h \ ++ /usr/src/linux/include/time.h /usr/src/linux/include/sys/resource.h /usr/src/linux/include/linux/msdos_fs.h ++ inode.o : inode.c /usr/src/linux/include/errno.h /usr/src/linux/include/linux/string.h \ ++ /usr/src/linux/include/sys/types.h /usr/src/linux/include/stddef.h /usr/src/linux/include/linux/stat.h \ ++ /usr/src/linux/include/linux/msdos_fs.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \ ++ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h \ ++ /usr/src/linux/include/sys/vfs.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/sched.h \ ++ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/mm.h /usr/src/linux/include/signal.h \ ++ /usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h /usr/src/linux/include/time.h \ ++ /usr/src/linux/include/sys/resource.h /usr/src/linux/include/asm/segment.h ++ misc.o : misc.c /usr/src/linux/include/errno.h /usr/src/linux/include/limits.h \ ++ /usr/src/linux/include/linux/string.h /usr/src/linux/include/sys/types.h /usr/src/linux/include/stddef.h \ ++ /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/msdos_fs.h \ ++ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \ ++ /usr/src/linux/include/sys/dirent.h /usr/src/linux/include/sys/vfs.h /usr/src/linux/include/linux/sched.h \ ++ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h \ ++ /usr/src/linux/include/signal.h /usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h \ ++ /usr/src/linux/include/time.h /usr/src/linux/include/sys/resource.h ++ namei.o : namei.c /usr/src/linux/include/errno.h /usr/src/linux/include/asm/segment.h \ ++ /usr/src/linux/include/linux/string.h /usr/src/linux/include/sys/types.h /usr/src/linux/include/stddef.h \ ++ /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \ ++ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \ ++ /usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \ ++ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/signal.h \ ++ /usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h /usr/src/linux/include/time.h \ ++ /usr/src/linux/include/sys/resource.h /usr/src/linux/include/linux/msdos_fs.h +*** /dev/null Sat Jul 18 22:26:09 1992 +--- linux/fs/msdos/dir.c Thu Jul 16 00:35:11 1992 +*************** +*** 0 **** +--- 1,128 ---- ++ /* ++ * linux/fs/msdos/dir.c ++ * ++ * Written 1992 by Werner Almesberger ++ * ++ * MS-DOS directory handling functions ++ */ ++ ++ #include ++ #include ++ #include ++ #include ++ #include ++ ++ /* for compatibility warnings */ ++ #include ++ ++ static int msdos_dummy_read(struct inode *inode,struct file *filp,char *buf, ++ int count); ++ static int msdos_readdir(struct inode *inode,struct file *filp, ++ struct dirent *dirent,int count); ++ ++ ++ static struct file_operations msdos_dir_operations = { ++ NULL, /* lseek - default */ ++ msdos_dummy_read, /* read */ ++ NULL, /* write - bad */ ++ msdos_readdir, /* readdir */ ++ NULL, /* select - default */ ++ NULL, /* ioctl - default */ ++ NULL, /* no special open code */ ++ NULL /* no special release code */ ++ }; ++ ++ struct inode_operations msdos_dir_inode_operations = { ++ &msdos_dir_operations, /* default directory file-ops */ ++ msdos_create, /* create */ ++ msdos_lookup, /* lookup */ ++ NULL, /* link */ ++ msdos_unlink, /* unlink */ ++ NULL, /* symlink */ ++ msdos_mkdir, /* mkdir */ ++ msdos_rmdir, /* rmdir */ ++ NULL, /* mknod */ ++ msdos_rename, /* rename */ ++ NULL, /* readlink */ ++ NULL, /* follow_link */ ++ msdos_bmap, /* bmap */ ++ NULL /* truncate */ ++ }; ++ ++ ++ /* So grep * doesn't complain in the presence of directories. */ ++ ++ static int msdos_dummy_read(struct inode *inode,struct file *filp,char *buf, ++ int count) ++ { ++ static long last_warning = 0; ++ ++ if (CURRENT_TIME-last_warning >= 10) { ++ printk("COMPATIBILITY WARNING: reading a directory\r\n"); ++ last_warning = CURRENT_TIME; ++ } ++ return 0; ++ } ++ ++ ++ static int msdos_readdir(struct inode *inode,struct file *filp, ++ struct dirent *dirent,int count) ++ { ++ int ino,i,i2,last; ++ char c,*walk; ++ struct buffer_head *bh; ++ struct msdos_dir_entry *de; ++ ++ if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; ++ if (inode->i_ino == MSDOS_ROOT_INO) { ++ /* Fake . and .. for the root directory. */ ++ if (filp->f_pos == 2) filp->f_pos = 0; ++ else if (filp->f_pos < 2) { ++ walk = filp->f_pos++ ? ".." : "."; ++ for (i = 0; *walk; walk++) ++ put_fs_byte(*walk,dirent->d_name+i++); ++ put_fs_long(MSDOS_ROOT_INO,&dirent->d_ino); ++ put_fs_byte(0,dirent->d_name+i); ++ put_fs_word(i,&dirent->d_reclen); ++ return i; ++ } ++ } ++ if (filp->f_pos & (sizeof(struct msdos_dir_entry)-1)) return -ENOENT; ++ bh = NULL; ++ while ((ino = msdos_get_entry(inode,&filp->f_pos,&bh,&de)) > -1) { ++ if (de->name[0] && ((unsigned char *) (de->name))[0] != ++ DELETED_FLAG && !(de->attr & ATTR_VOLUME)) { ++ for (i = last = 0; i < 8; i++) { ++ if (!(c = de->name[i])) break; ++ if (c >= 'A' && c <= 'Z') c += 32; ++ if (c != ' ') last = i+1; ++ put_fs_byte(c,i+dirent->d_name); ++ } ++ i = last; ++ if (de->ext[0] && de->ext[0] != ' ') { ++ put_fs_byte('.',i+dirent->d_name); ++ i++; ++ for (i2 = 0; i2 < 3; i2++) { ++ if (!(c = de->ext[i2])) break; ++ if (c >= 'A' && c <= 'Z') c += 32; ++ put_fs_byte(c,i+dirent->d_name); ++ i++; ++ if (c != ' ') last = i; ++ } ++ } ++ if (i = last) { ++ if (!strcmp(de->name,MSDOS_DOT)) ++ ino = inode->i_ino; ++ else if (!strcmp(de->name,MSDOS_DOTDOT)) ++ ino = msdos_parent_ino(inode,0); ++ put_fs_long(ino,&dirent->d_ino); ++ put_fs_byte(0,i+dirent->d_name); ++ put_fs_word(i,&dirent->d_reclen); ++ brelse(bh); ++ return i; ++ } ++ } ++ } ++ if (bh) brelse(bh); ++ return 0; ++ } +*** /dev/null Sat Jul 18 22:26:09 1992 +--- linux/fs/msdos/file.c Thu Jul 16 00:35:11 1992 +*************** +*** 0 **** +--- 1,210 ---- ++ /* ++ * linux/fs/msdos/file.c ++ * ++ * Written 1992 by Werner Almesberger ++ * ++ * MS-DOS regular file handling primitives ++ */ ++ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ ++ ++ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) ++ #define MAX(a,b) (((a) > (b)) ? (a) : (b)) ++ ++ ++ static int msdos_file_read(struct inode *inode,struct file *filp,char *buf, ++ int count); ++ static int msdos_file_write(struct inode *inode,struct file *filp,char *buf, ++ int count); ++ ++ ++ static struct file_operations msdos_file_operations = { ++ NULL, /* lseek - default */ ++ msdos_file_read, /* read */ ++ msdos_file_write, /* write */ ++ NULL, /* readdir - bad */ ++ NULL, /* select - default */ ++ NULL, /* ioctl - default */ ++ NULL, /* no special open is needed */ ++ NULL /* release */ ++ }; ++ ++ struct inode_operations msdos_file_inode_operations = { ++ &msdos_file_operations, /* default file operations */ ++ NULL, /* create */ ++ NULL, /* lookup */ ++ NULL, /* link */ ++ NULL, /* unlink */ ++ NULL, /* symlink */ ++ NULL, /* mkdir */ ++ NULL, /* rmdir */ ++ NULL, /* mknod */ ++ NULL, /* rename */ ++ NULL, /* readlink */ ++ NULL, /* follow_link */ ++ msdos_bmap, /* bmap */ ++ msdos_truncate /* truncate */ ++ }; ++ ++ /* No bmap for MS-DOS FS' that don't align data at kByte boundaries. */ ++ ++ struct inode_operations msdos_file_inode_operations_no_bmap = { ++ &msdos_file_operations, /* default file operations */ ++ NULL, /* create */ ++ NULL, /* lookup */ ++ NULL, /* link */ ++ NULL, /* unlink */ ++ NULL, /* symlink */ ++ NULL, /* mkdir */ ++ NULL, /* rmdir */ ++ NULL, /* mknod */ ++ NULL, /* rename */ ++ NULL, /* readlink */ ++ NULL, /* follow_link */ ++ NULL, /* bmap */ ++ msdos_truncate /* truncate */ ++ }; ++ ++ ++ static int msdos_file_read(struct inode *inode,struct file *filp,char *buf, ++ int count) ++ { ++ char *start; ++ int left,offset,size,sector,cnt; ++ char ch; ++ struct buffer_head *bh; ++ void *data; ++ ++ /* printk("msdos_file_read\r\n"); */ ++ if (!inode) { ++ printk("msdos_file_read: inode = NULL\r\n"); ++ return -EINVAL; ++ } ++ if (!S_ISREG(inode->i_mode)) { ++ printk("msdos_file_read: mode = %07o\n",inode->i_mode); ++ return -EINVAL; ++ } ++ if (filp->f_pos >= inode->i_size || count <= 0) return 0; ++ start = buf; ++ while (left = MIN(inode->i_size-filp->f_pos,count-(buf-start))) { ++ if (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS))) ++ break; ++ offset = filp->f_pos & (SECTOR_SIZE-1); ++ if (!(bh = msdos_sread(inode->i_dev,sector,&data))) break; ++ filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left)); ++ if (inode->i_data[D_BINARY]) { ++ memcpy_tofs(buf,data+offset,size); ++ buf += size; ++ } ++ else for (cnt = size; cnt; cnt--) { ++ if ((ch = *((char *) data+offset++)) == '\r') ++ size--; ++ else { ++ if (ch != 26) put_fs_byte(ch,buf++); ++ else { ++ filp->f_pos = inode->i_size; ++ brelse(bh); ++ return buf-start; ++ } ++ } ++ } ++ brelse(bh); ++ } ++ if (start == buf) return -EIO; ++ return buf-start; ++ } ++ ++ ++ static int msdos_file_write(struct inode *inode,struct file *filp,char *buf, ++ int count) ++ { ++ int sector,offset,size,left,written; ++ int error,carry; ++ char *start,*to,ch; ++ struct buffer_head *bh; ++ void *data; ++ ++ if (!inode) { ++ printk("msdos_file_write: inode = NULL\n"); ++ return -EINVAL; ++ } ++ if (!S_ISREG(inode->i_mode)) { ++ printk("msdos_file_write: mode = %07o\n",inode->i_mode); ++ return -EINVAL; ++ } ++ /* ++ * 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) filp->f_pos = inode->i_size; ++ if (count <= 0) return 0; ++ error = carry = 0; ++ for (start = buf; count || carry; count -= size) { ++ while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS))) ++ if ((error = msdos_add_cluster(inode)) < 0) break; ++ if (error) break; ++ offset = filp->f_pos & (SECTOR_SIZE-1); ++ size = MIN(SECTOR_SIZE-offset,MAX(carry,count)); ++ if (!(bh = msdos_sread(inode->i_dev,sector,&data))) { ++ error = -EIO; ++ break; ++ } ++ if (inode->i_data[D_BINARY]) { ++ memcpy_fromfs(data+(filp->f_pos & (SECTOR_SIZE-1)), ++ buf,written = size); ++ buf += size; ++ } ++ else { ++ written = left = SECTOR_SIZE-offset; ++ to = data+(filp->f_pos & (SECTOR_SIZE-1)); ++ if (carry) { ++ *to++ = '\n'; ++ left--; ++ carry = 0; ++ } ++ for (size = 0; size < count && left; size++) { ++ if ((ch = get_fs_byte(buf++)) == '\n') { ++ *to++ = '\r'; ++ left--; ++ } ++ if (!left) carry = 1; ++ else { ++ *to++ = ch; ++ left--; ++ } ++ } ++ written -= left; ++ } ++ filp->f_pos += written; ++ if (filp->f_pos > inode->i_size) { ++ inode->i_size = filp->f_pos; ++ inode->i_dirt = 1; ++ } ++ bh->b_dirt = 1; ++ brelse(bh); ++ } ++ inode->i_mtime = inode->i_ctime = CURRENT_TIME; ++ inode->i_data[D_ATTRS] |= ATTR_ARCH; ++ inode->i_dirt = 1; ++ return start == buf ? error : buf-start; ++ } ++ ++ ++ void msdos_truncate(struct inode *inode) ++ { ++ int cluster; ++ ++ if (!S_ISREG(inode->i_mode)) return; ++ cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size; ++ (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster); ++ inode->i_data[D_ATTRS] |= ATTR_ARCH; ++ inode->i_dirt = 1; ++ } +*** /dev/null Sat Jul 18 22:26:09 1992 +--- linux/fs/msdos/inode.c Thu Jul 16 00:35:11 1992 +*************** +*** 0 **** +--- 1,275 ---- ++ /* ++ * linux/fs/msdos/inode.c ++ * ++ * Written 1992 by Werner Almesberger ++ */ ++ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ ++ ++ void msdos_put_inode(struct inode *inode) ++ { ++ struct inode *depend; ++ ++ inode->i_size = 0; ++ msdos_truncate(inode); ++ depend = (struct inode *) inode->i_data[D_DEPEND]; ++ memset(inode,0,sizeof(struct inode)); ++ if (depend) { ++ if ((struct inode *) depend->i_data[D_OLD] != inode) { ++ printk("Invalid link (0x%X): expected 0x%X, got " ++ "0x%X\r\n",(int) depend,(int) inode, ++ depend->i_data[D_OLD]); ++ panic("That's fatal"); ++ } ++ depend->i_data[D_OLD] = 0; ++ iput(depend); ++ } ++ } ++ ++ ++ void msdos_put_super(struct super_block *sb) ++ { ++ cache_inval_dev(sb->s_dev); ++ lock_super(sb); ++ sb->s_dev = 0; ++ free_super(sb); ++ return; ++ } ++ ++ ++ static struct super_operations msdos_sops = { ++ msdos_read_inode, ++ msdos_write_inode, ++ msdos_put_inode, ++ msdos_put_super, ++ NULL, /* added in 0.96c */ ++ msdos_statfs ++ }; ++ ++ ++ static int parse_options(char *options,char *check,char *conversion) ++ { ++ char *this,*value; ++ ++ *check = 'n'; ++ *conversion = 'b'; ++ if (!options) return 1; ++ for (this = strtok(options,","); this; this = strtok(NULL,",")) { ++ if (value = strchr(this,'=')) *value++ = 0; ++ if (!strcmp(this,"check") && value) { ++ if (value[0] && !value[1] && strchr("rns",*value)) ++ *check = *value; ++ else if (!strcmp(value,"releaxed")) *check = 'r'; ++ else if (!strcmp(value,"normal")) *check = 'n'; ++ else if (!strcmp(value,"strict")) *check = 's'; ++ else return 0; ++ } ++ else if (!strcmp(this,"conv") && value) { ++ if (value[0] && !value[1] && strchr("bta",*value)) ++ *conversion = *value; ++ else if (!strcmp(value,"binary")) *conversion = 'b'; ++ else if (!strcmp(value,"text")) *conversion = 't'; ++ else if (!strcmp(value,"auto")) *conversion = 'a'; ++ else return 0; ++ } ++ else return 0; ++ } ++ return 1; ++ } ++ ++ ++ /* Read the super block of an MS-DOS FS. */ ++ ++ struct super_block *msdos_read_super(struct super_block *s,void *data) ++ { ++ struct buffer_head *bh; ++ struct msdos_boot_sector *b; ++ int data_sectors; ++ char check,conversion; ++ ++ if (!parse_options((char *) data,&check,&conversion)) { ++ s->s_dev = 0; ++ return NULL; ++ } ++ cache_init(); ++ lock_super(s); ++ bh = bread(s->s_dev,0); ++ free_super(s); ++ if (bh == NULL) { ++ s->s_dev = 0; ++ printk("MSDOS bread failed\r\n"); ++ return NULL; ++ } ++ b = (struct msdos_boot_sector *) bh->b_data; ++ MSDOS_SB(s)->cluster_size = b->cluster_size; ++ MSDOS_SB(s)->fats = b->fats; ++ MSDOS_SB(s)->fat_start = b->reserved; ++ MSDOS_SB(s)->fat_length = b->fat_length; ++ MSDOS_SB(s)->dir_start = b->reserved+b->fats*b->fat_length; ++ MSDOS_SB(s)->dir_entries = *((unsigned short *) &b->dir_entries); ++ MSDOS_SB(s)->data_start = MSDOS_SB(s)->dir_start+((MSDOS_SB(s)-> ++ dir_entries << 5) >> 9); ++ data_sectors = (*((unsigned short *) &b->sectors) ? *((unsigned short *) ++ &b->sectors) : b->total_sect)-MSDOS_SB(s)->data_start; ++ MSDOS_SB(s)->clusters = b->cluster_size ? data_sectors/b->cluster_size : ++ 0; ++ MSDOS_SB(s)->fat_bits = MSDOS_SB(s)->clusters > MSDOS_FAT12 ? 16 : 12; ++ brelse(bh); ++ printk("[MS-DOS FS Rel. alpha.5, FAT %d, check=%c, conv=%c]\r\n", ++ MSDOS_SB(s)->fat_bits,check,conversion); ++ printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\r\n", ++ b->media,MSDOS_SB(s)->cluster_size,MSDOS_SB(s)->fats,MSDOS_SB(s)->fat_start, ++ MSDOS_SB(s)->fat_length,MSDOS_SB(s)->dir_start,MSDOS_SB(s)->dir_entries, ++ MSDOS_SB(s)->data_start,*(unsigned short *) &b->sectors,b->total_sect); ++ if (!MSDOS_SB(s)->fats || (MSDOS_SB(s)->dir_entries & (MSDOS_DPS-1)) ++ || !b->cluster_size || MSDOS_SB(s)->clusters+2 > MSDOS_SB(s)-> ++ fat_length*SECTOR_SIZE*8/MSDOS_SB(s)->fat_bits) { ++ s->s_dev = 0; ++ printk("Unsupported FS parameters\r\n"); ++ return NULL; ++ } ++ if (!MSDOS_CAN_BMAP(MSDOS_SB(s))) printk("No bmap support\r\n"); ++ s->s_magic = MSDOS_SUPER_MAGIC; ++ MSDOS_SB(s)->name_check = check; ++ MSDOS_SB(s)->conversion = conversion; ++ /* set up enough so that it can read an inode */ ++ s->s_op = &msdos_sops; ++ MSDOS_SB(s)->fs_uid = current->uid; ++ MSDOS_SB(s)->fs_gid = current->gid; ++ MSDOS_SB(s)->fs_umask = current->umask; ++ if (!(s->s_mounted = iget(s->s_dev,MSDOS_ROOT_INO))) { ++ s->s_dev = 0; ++ printk("get root inode failed\n"); ++ return NULL; ++ } ++ return s; ++ } ++ ++ ++ void msdos_statfs(struct super_block *sb,struct statfs *buf) ++ { ++ int cluster_size,free,this; ++ ++ cluster_size = MSDOS_SB(sb)->cluster_size; ++ put_fs_long(sb->s_magic,&buf->f_type); ++ put_fs_long(SECTOR_SIZE,&buf->f_bsize); ++ put_fs_long(MSDOS_SB(sb)->clusters*cluster_size,&buf->f_blocks); ++ free = 0; ++ for (this = 2; this < MSDOS_SB(sb)->clusters+2; this++) ++ if (!fat_access(sb,this,-1)) free++; ++ free *= cluster_size; ++ put_fs_long(free,&buf->f_bfree); ++ put_fs_long(free,&buf->f_bavail); ++ put_fs_long(0,&buf->f_files); ++ put_fs_long(0,&buf->f_ffree); ++ } ++ ++ ++ int msdos_bmap(struct inode *inode,int block) ++ { ++ struct msdos_sb_info *sb; ++ int cluster,offset; ++ ++ sb = MSDOS_SB(inode->i_sb); ++ if ((sb->cluster_size & 1) || (sb->data_start & 1)) return 0; ++ if (inode->i_ino == MSDOS_ROOT_INO) { ++ if (sb->dir_start & 1) return 0; ++ return (sb->dir_start >> 1)+block; ++ } ++ cluster = (block*2)/sb->cluster_size; ++ offset = (block*2) % sb->cluster_size; ++ if (!(cluster = get_cluster(inode,cluster))) return 0; ++ return ((cluster-2)*sb->cluster_size+sb->data_start+offset) >> 1; ++ } ++ ++ ++ void msdos_read_inode(struct inode *inode) ++ { ++ struct buffer_head *bh; ++ struct msdos_dir_entry *raw_entry; ++ int this; ++ ++ /* printk("read inode %d\r\n",inode->i_ino); */ ++ inode->i_data[D_BUSY] = inode->i_data[D_DEPEND] = ++ inode->i_data[D_OLD] = 0; ++ inode->i_data[D_BINARY] = 1; ++ inode->i_uid = MSDOS_SB(inode->i_sb)->fs_uid; ++ inode->i_gid = MSDOS_SB(inode->i_sb)->fs_gid; ++ if (inode->i_ino == MSDOS_ROOT_INO) { ++ inode->i_mode = (0777 & ~MSDOS_SB(inode->i_sb)->fs_umask) | ++ S_IFDIR; ++ inode->i_op = &msdos_dir_inode_operations; ++ inode->i_nlink = 1; ++ inode->i_size = MSDOS_SB(inode->i_sb)->dir_entries* ++ sizeof(struct msdos_dir_entry); ++ inode->i_data[D_START] = 0; ++ inode->i_data[D_ATTRS] = 0; ++ inode->i_mtime = inode->i_atime = inode->i_ctime = 0; ++ return; ++ } ++ if (!(bh = bread(inode->i_dev,inode->i_ino >> MSDOS_DPB_BITS))) ++ panic("unable to read i-node block"); ++ raw_entry = &((struct msdos_dir_entry *) (bh->b_data)) ++ [inode->i_ino & (MSDOS_DPB-1)]; ++ if (raw_entry->attr & ATTR_DIR) { ++ inode->i_mode = MSDOS_MKMODE(raw_entry->attr,0777 & ++ ~MSDOS_SB(inode->i_sb)->fs_umask) | S_IFDIR; ++ inode->i_op = &msdos_dir_inode_operations; ++ inode->i_nlink = 3; ++ inode->i_size = 0; ++ for (this = raw_entry->start; this && this != -1; this = ++ fat_access(inode->i_sb,this,-1)) ++ inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)-> ++ cluster_size; ++ } ++ else { ++ inode->i_mode = MSDOS_MKMODE(raw_entry->attr,0666 & ++ ~MSDOS_SB(inode->i_sb)->fs_umask) | S_IFREG; ++ inode->i_op = MSDOS_CAN_BMAP(MSDOS_SB(inode->i_sb)) ? ++ &msdos_file_inode_operations : ++ &msdos_file_inode_operations_no_bmap; ++ inode->i_nlink = 1; ++ inode->i_size = raw_entry->size; ++ } ++ inode->i_data[D_BINARY] = is_binary(MSDOS_SB(inode->i_sb)->conversion, ++ raw_entry->ext); ++ inode->i_data[D_START] = raw_entry->start; ++ inode->i_data[D_ATTRS] = raw_entry->attr & ATTR_UNUSED; ++ inode->i_mtime = inode->i_atime = inode->i_ctime = ++ date_dos2unix(raw_entry->time,raw_entry->date); ++ brelse(bh); ++ } ++ ++ ++ void msdos_write_inode(struct inode *inode) ++ { ++ struct buffer_head *bh; ++ struct msdos_dir_entry *raw_entry; ++ ++ inode->i_dirt = 0; ++ if (inode->i_ino == MSDOS_ROOT_INO || !inode->i_nlink) return; ++ if (!(bh = bread(inode->i_dev,inode->i_ino >> MSDOS_DPB_BITS))) ++ panic("unable to read i-node block"); ++ raw_entry = &((struct msdos_dir_entry *) (bh->b_data)) ++ [inode->i_ino & (MSDOS_DPB-1)]; ++ if (S_ISDIR(inode->i_mode)) { ++ raw_entry->attr = ATTR_DIR; ++ raw_entry->size = 0; ++ } ++ else { ++ raw_entry->attr = ATTR_NONE; ++ raw_entry->size = inode->i_size; ++ } ++ raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) | inode->i_data[D_ATTRS]; ++ raw_entry->start = inode->i_data[D_START]; ++ date_unix2dos(inode->i_mtime,&raw_entry->time,&raw_entry->date); ++ bh->b_dirt = 1; ++ brelse(bh); ++ } +*** /dev/null Sat Jul 18 22:26:09 1992 +--- linux/fs/msdos/misc.c Thu Jul 16 00:38:36 1992 +*************** +*** 0 **** +--- 1,365 ---- ++ /* ++ * linux/fs/msdos/misc.c ++ * ++ * Written 1992 by Werner Almesberger ++ */ ++ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ ++ ++ static char bin_extensions[] = ++ "EXECOMAPPSYSOVLOBJLIB" /* program code */ ++ "ARCZIPLHALZHZOOTARZ ARJ" /* common archivers */ ++ "GIFBMPTIFGL JPG" /* graphics */ ++ "TFMVF GF PK PXLDVI"; /* TeX */ ++ ++ ++ /* Select binary/text conversion */ ++ ++ int is_binary(char conversion,char *extension) ++ { ++ char *walk; ++ ++ switch (conversion) { ++ case 'b': ++ return 1; ++ case 't': ++ return 0; ++ case 'a': ++ for (walk = bin_extensions; *walk; walk += 3) ++ if (!strncmp(extension,walk,3)) return 1; ++ return 0; ++ default: ++ panic("Invalid conversion mode"); ++ } ++ } ++ ++ ++ static struct wait_queue *creation_wait = NULL; ++ static creation_lock = 0; ++ ++ ++ void lock_creation(void) ++ { ++ while (creation_lock) sleep_on(&creation_wait); ++ creation_lock = 1; ++ } ++ ++ ++ void unlock_creation(void) ++ { ++ creation_lock = 0; ++ wake_up(&creation_wait); ++ } ++ ++ ++ int msdos_add_cluster(struct inode *inode) ++ { ++ static struct wait_queue *wait = NULL; ++ static int lock = 0; ++ static int previous = 0; /* works best if one FS is being used */ ++ int count,this,limit,last,current,sector; ++ void *data; ++ struct buffer_head *bh; ++ ++ if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC; ++ while (lock) sleep_on(&wait); ++ lock = 1; ++ limit = MSDOS_SB(inode->i_sb)->clusters; ++ this = limit; /* to keep GCC happy */ ++ for (count = 0; count < limit; count++) { ++ this = ((count+previous) % limit)+2; ++ if (fat_access(inode->i_sb,this,-1) == 0) break; ++ } ++ #ifdef DEBUG ++ printk("free cluster: %d\r\n",this); ++ #endif ++ previous = (count+previous+1) % limit; ++ if (count >= limit) { ++ lock = 0; ++ wake_up(&wait); ++ return -ENOSPC; ++ } ++ fat_access(inode->i_sb,this,MSDOS_SB(inode->i_sb)->fat_bits == 12 ? ++ 0xff8 : 0xfff8); ++ lock = 0; ++ wake_up(&wait); ++ #ifdef DEBUG ++ printk("set to %x\r\n",fat_access(inode->i_sb,this,-1)); ++ #endif ++ if (!S_ISDIR(inode->i_mode)) { ++ last = inode->i_size ? get_cluster(inode,(inode->i_size-1)/ ++ SECTOR_SIZE/MSDOS_SB(inode->i_sb)->cluster_size) : 0; ++ } ++ else { ++ last = 0; ++ if (current = inode->i_data[D_START]) { ++ cache_lookup(inode,INT_MAX,&last,¤t); ++ while (current && current != -1) ++ if (!(current = fat_access(inode->i_sb, ++ last = current,-1))) ++ panic("File without EOF"); ++ } ++ } ++ #ifdef DEBUG ++ printk("last = %d\r\n",last); ++ #endif ++ if (last) fat_access(inode->i_sb,last,this); ++ else { ++ inode->i_data[D_START] = this; ++ inode->i_dirt = 1; ++ } ++ #ifdef DEBUG ++ if (last) printk("next set to %d\r\n",fat_access(inode->i_sb,last,-1)); ++ #endif ++ for (current = 0; current < MSDOS_SB(inode->i_sb)->cluster_size; ++ current++) { ++ sector = MSDOS_SB(inode->i_sb)->data_start+(this-2)* ++ MSDOS_SB(inode->i_sb)->cluster_size+current; ++ #ifdef DEBUG ++ printk("zeroing sector %d\r\n",sector); ++ #endif ++ if (current < MSDOS_SB(inode->i_sb)->cluster_size-1 && ++ !(sector & 1)) { ++ if (!(bh = getblk(inode->i_dev,sector >> 1))) ++ printk("getblk failed\r\n"); ++ else { ++ memset(bh->b_data,0,BLOCK_SIZE); ++ bh->b_uptodate = 1; ++ } ++ current++; ++ } ++ else { ++ if (!(bh = msdos_sread(inode->i_dev,sector,&data))) ++ printk("msdos_sread failed\r\n"); ++ else memset(data,0,SECTOR_SIZE); ++ } ++ if (bh) { ++ bh->b_dirt = 1; ++ brelse(bh); ++ } ++ } ++ if (S_ISDIR(inode->i_mode)) { ++ if (inode->i_size & (SECTOR_SIZE-1)) ++ panic("Odd directory size"); ++ inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)-> ++ cluster_size; ++ #ifdef DEBUG ++ printk("size is %d now (%x)\r\n",inode->i_size,inode); ++ #endif ++ inode->i_dirt = 1; ++ } ++ return 0; ++ } ++ ++ ++ /* Linear day numbers of the respective 1sts in non-leap years. */ ++ ++ static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 }; ++ /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ ++ ++ ++ /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ ++ ++ int date_dos2unix(unsigned short time,unsigned short date) ++ { ++ int month,year; ++ ++ month = ((date >> 5) & 4)-1; ++ year = date >> 9; ++ return (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* ++ ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && ++ month < 2 ? 1 : 0)+3653); ++ /* days since 1.1.70 plus 80's leap day */ ++ } ++ ++ ++ /* Convert linear UNIX date to a MS-DOS time/date pair. */ ++ ++ void date_unix2dos(int unix_date,unsigned short *time, ++ unsigned short *date) ++ { ++ int day,year,nl_day,month; ++ ++ *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+ ++ (((unix_date/3600) % 24) << 11); ++ day = unix_date/86400-3652; ++ year = day/365; ++ if ((year+3)/4+365*year > day) year--; ++ day -= (year+3)/4+365*year; ++ if (day == 59 && !(year & 3)) { ++ nl_day = day; ++ month = 2; ++ } ++ else { ++ nl_day = (year & 3) || day <= 59 ? day : day-1; ++ for (month = 0; month < 12; month++) ++ if (day_n[month] > nl_day) break; ++ } ++ *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9); ++ } ++ ++ ++ /* Returns the inode number of the directory entry at offset pos. If bh is ++ non-NULL, it is brelse'd before. Pos is incremented. The buffer header is ++ returned in bh. */ ++ ++ int msdos_get_entry(struct inode *dir,int *pos,struct buffer_head **bh, ++ struct msdos_dir_entry **de) ++ { ++ int sector,offset; ++ void *data; ++ ++ while (1) { ++ offset = *pos; ++ if ((sector = msdos_smap(dir,*pos >> SECTOR_BITS)) == -1) ++ return -1; ++ if (!sector) return -1; /* FAT error ... */ ++ *pos += sizeof(struct msdos_dir_entry); ++ if (*bh) brelse(*bh); ++ if (!(*bh = msdos_sread(dir->i_dev,sector,&data))) continue; ++ *de = (struct msdos_dir_entry *) (data+(offset & ++ (SECTOR_SIZE-1))); ++ return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >> ++ MSDOS_DIR_BITS); ++ } ++ } ++ ++ ++ /* Scans a directory for a given file (name points to its formatted name) or ++ for an empty directory slot (name is NULL). Returns the inode number. */ ++ ++ int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh, ++ struct msdos_dir_entry **res_de,int *ino) ++ { ++ int pos; ++ struct msdos_dir_entry *de; ++ struct inode *inode; ++ ++ pos = 0; ++ *res_bh = NULL; ++ while ((*ino = msdos_get_entry(dir,&pos,res_bh,&de)) > -1) { ++ if (name) { ++ if (de->name[0] && ((unsigned char *) (de->name))[0] ++ != DELETED_FLAG && !(de->attr & ATTR_VOLUME) && ++ !strncmp(de->name,name,MSDOS_NAME)) break; ++ } ++ else if (!de->name[0] || ((unsigned char *) (de->name))[0] == ++ DELETED_FLAG) { ++ if (!(inode = iget(dir->i_dev,*ino))) break; ++ if (!inode->i_data[D_BUSY]) { ++ iput(inode); ++ break; ++ } ++ /* skip deleted files that haven't been closed yet */ ++ iput(inode); ++ } ++ } ++ if (*ino == -1) { ++ if (*res_bh) brelse(*res_bh); ++ *res_bh = NULL; ++ return name ? -ENOENT : -ENOSPC; ++ } ++ *res_de = de; ++ return 0; ++ } ++ ++ ++ /* Now an ugly part: this set of directory scan routines works on clusters ++ rather than on inodes and sectors. They are necessary to locate the '..' ++ directory "inode". */ ++ ++ ++ static int raw_found(struct super_block *sb,int sector,char *name,int number, ++ int *ino) ++ { ++ struct buffer_head *bh; ++ struct msdos_dir_entry *data; ++ int entry,start; ++ ++ if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO; ++ for (entry = 0; entry < MSDOS_DPS; entry++) ++ if (name ? !strncmp(data[entry].name,name,MSDOS_NAME) : ++ *(unsigned char *) data[entry].name != DELETED_FLAG && ++ data[entry].start == number) { ++ if (ino) *ino = sector*MSDOS_DPS+entry; ++ start = data[entry].start; ++ brelse(bh); ++ return start; ++ } ++ brelse(bh); ++ return -1; ++ } ++ ++ ++ static int raw_scan_root(struct super_block *sb,char *name,int number,int *ino) ++ { ++ int count,cluster; ++ ++ for (count = 0; count < MSDOS_SB(sb)->dir_entries/MSDOS_DPS; count++) { ++ if ((cluster = raw_found(sb,MSDOS_SB(sb)->dir_start+count,name, ++ number,ino)) >= 0) return cluster; ++ } ++ return -ENOENT; ++ } ++ ++ ++ static int raw_scan_nonroot(struct super_block *sb,int start,char *name, ++ int number,int *ino) ++ { ++ int count,cluster; ++ ++ do { ++ for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) { ++ if ((cluster = raw_found(sb,(start-2)*MSDOS_SB(sb)-> ++ cluster_size+MSDOS_SB(sb)->data_start+count,name, ++ number,ino)) >= 0) return cluster; ++ } ++ if (!(start = fat_access(sb,start,-1))) panic("FAT error"); ++ } ++ while (start != -1); ++ return -ENOENT; ++ } ++ ++ ++ static int raw_scan(struct super_block *sb,int start,char *name,int number, ++ int *ino) ++ { ++ if (start) return raw_scan_nonroot(sb,start,name,number,ino); ++ else return raw_scan_root(sb,name,number,ino); ++ } ++ ++ ++ int msdos_parent_ino(struct inode *dir,int locked) ++ { ++ int error,current,prev,this; ++ ++ if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i"); ++ if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino; ++ if (!locked) lock_creation(); /* prevent renames */ ++ if ((current = raw_scan(dir->i_sb,dir->i_data[D_START],MSDOS_DOTDOT,0, ++ NULL)) < 0) { ++ if (!locked) unlock_creation(); ++ return current; ++ } ++ if (!current) this = MSDOS_ROOT_INO; ++ else { ++ if ((prev = raw_scan(dir->i_sb,current,MSDOS_DOTDOT,0,NULL)) < ++ 0) { ++ if (!locked) unlock_creation(); ++ return prev; ++ } ++ if ((error = raw_scan(dir->i_sb,prev,NULL,current,&this)) < 0) { ++ if (!locked) unlock_creation(); ++ return error; ++ } ++ } ++ if (!locked) unlock_creation(); ++ return this; ++ } +*** /dev/null Sat Jul 18 22:26:09 1992 +--- linux/fs/msdos/namei.c Thu Jul 16 00:35:11 1992 +*************** +*** 0 **** +--- 1,512 ---- ++ /* ++ * linux/fs/msdos/namei.c ++ * ++ * Written 1992 by Werner Almesberger ++ */ ++ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ ++ ++ /* MS-DOS "device special files" */ ++ ++ static char *reserved_names[] = { ++ "CON ","PRN ","NUL ","AUX ", ++ "LPT1 ","LPT2 ","LPT3 ","LPT4 ", ++ "COM1 ","COM2 ","COM3 ","COM4 ", ++ NULL }; ++ ++ ++ /* Formats an MS-DOS file name. Rejects invalid names. */ ++ ++ static int msdos_format_name(char conv,const char *name,int len,char *res) ++ { ++ char *walk,**reserved; ++ char c; ++ int space; ++ ++ if (get_fs_byte(name) == DELETED_FLAG) return -EINVAL; ++ if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 && ++ get_fs_byte(name+1) == '.'))) { ++ memset(res+1,' ',10); ++ while (len--) *res++ = '.'; ++ return 0; ++ } ++ space = 0; /* to make GCC happy */ ++ c = 0; ++ for (walk = res; len && walk-res < 8; walk++) { ++ c = get_fs_byte(name++); ++ len--; ++ if (c == ' ' && conv != 'r') return -EINVAL; ++ if (c >= 'A' && c <= 'Z') { ++ if (conv != 'r') return -EINVAL; ++ c += 32; ++ } ++ if (c < ' ' || c == ':' || c == '\\') return -EINVAL; ++ if (c == '.') break; ++ space = c == ' '; ++ *walk = c >= 'a' && c <= 'z' ? c-32 : c; ++ } ++ if (space) return -EINVAL; ++ if (conv == 's' && len && c != '.') { ++ c = get_fs_byte(name++); ++ len--; ++ if (c != '.') return -EINVAL; ++ } ++ while (c != '.' && len--) c = get_fs_byte(name++); ++ if (walk == res) return -EINVAL; ++ if (c == '.') { ++ while (walk-res < 8) *walk++ = ' '; ++ while (len > 0 && walk-res < MSDOS_NAME) { ++ c = get_fs_byte(name++); ++ len--; ++ if (c == ' ' && conv != 'r') return -EINVAL; ++ if (c < ' ' || c == ':' || c == '\\' || c == '.') ++ return -EINVAL; ++ if (c >= 'A' && c <= 'Z') { ++ if (conv != 'r') return -EINVAL; ++ c += 32; ++ } ++ space = c == ' '; ++ *walk++ = c >= 'a' && c <= 'z' ? c-32 : c; ++ } ++ if (space) return -EINVAL; ++ if (conv == 's' && len) return -EINVAL; ++ } ++ while (walk-res < MSDOS_NAME) *walk++ = ' '; ++ for (reserved = reserved_names; *reserved; reserved++) ++ if (!strncmp(res,*reserved,8)) return -EINVAL; ++ return 0; ++ } ++ ++ ++ /* Locates a directory entry. */ ++ ++ static int msdos_find(struct inode *dir,const char *name,int len, ++ struct buffer_head **bh,struct msdos_dir_entry **de,int *ino) ++ { ++ char msdos_name[MSDOS_NAME]; ++ int res; ++ ++ if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len, ++ msdos_name)) < 0) return res; ++ return msdos_scan(dir,msdos_name,bh,de,ino); ++ } ++ ++ ++ int msdos_lookup(struct inode *dir,const char *name,int len, ++ struct inode **result) ++ { ++ int ino,res; ++ struct msdos_dir_entry *de; ++ struct buffer_head *bh; ++ struct inode *next; ++ ++ *result = NULL; ++ if (!dir) return -ENOENT; ++ if (!S_ISDIR(dir->i_mode)) { ++ iput(dir); ++ return -ENOENT; ++ } ++ if (len == 1 && get_fs_byte(name) == '.') { ++ *result = dir; ++ return 0; ++ } ++ if (len == 2 && get_fs_byte(name) == '.' && get_fs_byte(name+1) == '.') ++ { ++ ino = msdos_parent_ino(dir,0); ++ iput(dir); ++ if (ino < 0) return ino; ++ if (!(*result = iget(dir->i_dev,ino))) return -EACCES; ++ return 0; ++ } ++ if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) { ++ iput(dir); ++ return res; ++ } ++ if (bh) brelse(bh); ++ /* printk("lookup: ino=%d\r\n",ino); */ ++ if (!(*result = iget(dir->i_dev,ino))) { ++ iput(dir); ++ return -EACCES; ++ } ++ if ((*result)->i_data[D_BUSY]) { /* mkdir in progress */ ++ iput(*result); ++ iput(dir); ++ return -ENOENT; ++ } ++ while ((*result)->i_data[D_OLD]) { ++ next = (struct inode *) ((*result)->i_data[D_OLD]); ++ iput(*result); ++ if (!(*result = iget(next->i_dev,next->i_ino))) ++ panic("msdos_lookup: Can't happen"); ++ } ++ iput(dir); ++ return 0; ++ } ++ ++ ++ /* Creates a directory entry (name is already formatted). */ ++ ++ static int msdos_create_entry(struct inode *dir,char *name,int is_dir, ++ struct inode **result) ++ { ++ struct buffer_head *bh; ++ struct msdos_dir_entry *de; ++ int res,ino; ++ ++ if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) { ++ if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC; ++ if ((res = msdos_add_cluster(dir)) < 0) return res; ++ if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res; ++ } ++ memcpy(de->name,name,MSDOS_NAME); ++ de->attr = is_dir ? ATTR_DIR : ATTR_ARCH; ++ de->start = 0; ++ date_unix2dos(CURRENT_TIME,&de->time,&de->date); ++ de->size = 0; ++ bh->b_dirt = 1; ++ if (*result = iget(dir->i_dev,ino)) msdos_read_inode(*result); ++ brelse(bh); ++ if (!*result) return -EIO; ++ (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime = ++ CURRENT_TIME; ++ (*result)->i_dirt = 1; ++ return 0; ++ } ++ ++ ++ int msdos_create(struct inode *dir,const char *name,int len,int mode, ++ struct inode **result) ++ { ++ struct buffer_head *bh; ++ struct msdos_dir_entry *de; ++ char msdos_name[MSDOS_NAME]; ++ int ino,res; ++ ++ if (!dir) return -ENOENT; ++ if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len, ++ msdos_name)) < 0) { ++ iput(dir); ++ return res; ++ } ++ lock_creation(); ++ if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) { ++ unlock_creation(); ++ brelse(bh); ++ iput(dir); ++ return -EEXIST; ++ } ++ res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),result); ++ unlock_creation(); ++ iput(dir); ++ return res; ++ } ++ ++ ++ int msdos_mkdir(struct inode *dir,const char *name,int len,int mode) ++ { ++ struct buffer_head *bh; ++ struct msdos_dir_entry *de; ++ struct inode *inode,*dot; ++ char msdos_name[MSDOS_NAME]; ++ int ino,res; ++ ++ if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len, ++ msdos_name)) < 0) { ++ iput(dir); ++ return res; ++ } ++ lock_creation(); ++ if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) { ++ unlock_creation(); ++ brelse(bh); ++ iput(dir); ++ return -EEXIST; ++ } ++ if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) { ++ unlock_creation(); ++ iput(dir); ++ return res; ++ } ++ inode->i_data[D_BUSY] = 1; /* prevent lookups */ ++ if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error; ++ if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0) ++ goto mkdir_error; ++ dot->i_size = inode->i_size; ++ dot->i_data[D_START] = inode->i_data[D_START]; ++ dot->i_dirt = 1; ++ iput(dot); ++ if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0) ++ goto mkdir_error; ++ unlock_creation(); ++ dot->i_size = dir->i_size; ++ dot->i_data[D_START] = dir->i_data[D_START]; ++ dot->i_dirt = 1; ++ inode->i_data[D_BUSY] = 0; ++ iput(dot); ++ iput(inode); ++ iput(dir); ++ return 0; ++ mkdir_error: ++ iput(inode); ++ if (msdos_rmdir(dir,name,len) < 0) panic("rmdir in mkdir failed"); ++ unlock_creation(); ++ return res; ++ } ++ ++ ++ int msdos_rmdir(struct inode *dir,const char *name,int len) ++ { ++ int res,ino,pos; ++ struct buffer_head *bh,*dbh; ++ struct msdos_dir_entry *de,*dde; ++ struct inode *inode; ++ ++ bh = NULL; ++ inode = NULL; ++ res = -EINVAL; ++ if (len == 1 && get_fs_byte(name) == '.') goto rmdir_done; ++ if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done; ++ res = -ENOENT; ++ if (!(inode = iget(dir->i_dev,ino))) goto rmdir_done; ++ res = -ENOTDIR; ++ if (!S_ISDIR(inode->i_mode)) goto rmdir_done; ++ res = -EBUSY; ++ if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done; ++ if (inode->i_count > 1) goto rmdir_done; ++ res = -ENOTEMPTY; ++ pos = 0; ++ dbh = NULL; ++ while (msdos_get_entry(inode,&pos,&dbh,&dde) > -1) ++ if (dde->name[0] && ((unsigned char *) dde->name)[0] != ++ DELETED_FLAG && strncmp(dde->name,MSDOS_DOT,MSDOS_NAME) && ++ strncmp(dde->name,MSDOS_DOTDOT,MSDOS_NAME)) goto rmdir_done; ++ if (dbh) brelse(dbh); ++ inode->i_nlink = 0; ++ dir->i_mtime = CURRENT_TIME; ++ inode->i_dirt = dir->i_dirt = 1; ++ de->name[0] = DELETED_FLAG; ++ bh->b_dirt = 1; ++ res = 0; ++ rmdir_done: ++ brelse(bh); ++ iput(dir); ++ iput(inode); ++ return res; ++ } ++ ++ ++ int msdos_unlink(struct inode *dir,const char *name,int len) ++ { ++ int res,ino; ++ struct buffer_head *bh; ++ struct msdos_dir_entry *de; ++ struct inode *inode; ++ ++ bh = NULL; ++ inode = NULL; ++ if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) ++ goto unlink_done; ++ if (!(inode = iget(dir->i_dev,ino))) { ++ res = -ENOENT; ++ goto unlink_done; ++ } ++ if (!S_ISREG(inode->i_mode)) { ++ res = -EPERM; ++ goto unlink_done; ++ } ++ inode->i_nlink = 0; ++ inode->i_data[D_BUSY] = 1; ++ inode->i_dirt = 1; ++ de->name[0] = DELETED_FLAG; ++ bh->b_dirt = 1; ++ unlink_done: ++ brelse(bh); ++ iput(inode); ++ iput(dir); ++ return res; ++ } ++ ++ ++ static int rename_same_dir(struct inode *old_dir,char *old_name, ++ struct inode *new_dir,char *new_name,struct buffer_head *old_bh, ++ struct msdos_dir_entry *old_de,int old_ino) ++ { ++ struct buffer_head *new_bh; ++ struct msdos_dir_entry *new_de; ++ struct inode *new_inode,*old_inode; ++ int new_ino; ++ int exists; ++ ++ if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0; ++ exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0; ++ if (*(unsigned char *) old_de->name == DELETED_FLAG) { ++ if (exists) brelse(new_bh); ++ return -ENOENT; ++ } ++ if (exists) { ++ if (!(new_inode = iget(new_dir->i_dev,new_ino))) { ++ brelse(new_bh); ++ return -EIO; ++ } ++ if (S_ISDIR(new_inode->i_mode)) { ++ iput(new_inode); ++ brelse(new_bh); ++ return -EPERM; ++ } ++ new_inode->i_nlink = 0; ++ new_inode->i_data[D_BUSY] = 1; ++ new_inode->i_dirt = 1; ++ new_de->name[0] = DELETED_FLAG; ++ new_bh->b_dirt = 1; ++ iput(new_inode); ++ brelse(new_bh); ++ } ++ memcpy(old_de->name,new_name,MSDOS_NAME); ++ old_bh->b_dirt = 1; ++ if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */ ++ if (old_inode = iget(old_dir->i_dev,old_ino)) { ++ msdos_read_inode(old_inode); ++ iput(old_inode); ++ } ++ return 0; ++ } ++ ++ ++ static int rename_diff_dir(struct inode *old_dir,char *old_name, ++ struct inode *new_dir,char *new_name,struct buffer_head *old_bh, ++ struct msdos_dir_entry *old_de,int old_ino) ++ { ++ struct buffer_head *new_bh,*free_bh,*dotdot_bh; ++ struct msdos_dir_entry *new_de,*free_de,*dotdot_de; ++ struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk; ++ int new_ino,free_ino,dotdot_ino; ++ int error,exists,ino; ++ ++ if (old_dir->i_dev != new_dir->i_dev) return -EINVAL; ++ if (old_ino == new_dir->i_ino) return -EINVAL; ++ if (!(walk = iget(new_dir->i_dev,new_dir->i_ino))) return -EIO; ++ while (walk->i_ino != MSDOS_ROOT_INO) { ++ ino = msdos_parent_ino(walk,1); ++ iput(walk); ++ if (ino < 0) return ino; ++ if (ino == old_ino) return -EINVAL; ++ if (!(walk = iget(new_dir->i_dev,ino))) return -EIO; ++ } ++ iput(walk); ++ if ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) < 0) ++ return error; ++ exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) ++ >= 0; ++ if (!(old_inode = iget(old_dir->i_dev,old_ino))) { ++ brelse(free_bh); ++ if (exists) brelse(new_bh); ++ return -EIO; ++ } ++ if (*(unsigned char *) old_de->name == DELETED_FLAG) { ++ iput(old_inode); ++ brelse(free_bh); ++ if (exists) brelse(new_bh); ++ return -ENOENT; ++ } ++ new_inode = NULL; /* to make GCC happy */ ++ if (exists) { ++ if (!(new_inode = iget(new_dir->i_dev,new_ino))) { ++ iput(old_inode); ++ brelse(new_bh); ++ return -EIO; ++ } ++ if (S_ISDIR(new_inode->i_mode)) { ++ iput(new_inode); ++ iput(old_inode); ++ brelse(new_bh); ++ return -EPERM; ++ } ++ new_inode->i_nlink = 0; ++ new_inode->i_data[D_BUSY] = 1; ++ new_inode->i_dirt = 1; ++ new_de->name[0] = DELETED_FLAG; ++ new_bh->b_dirt = 1; ++ } ++ memcpy(free_de,old_de,sizeof(struct msdos_dir_entry)); ++ memcpy(free_de->name,new_name,MSDOS_NAME); ++ if (!(free_inode = iget(new_dir->i_dev,free_ino))) { ++ free_de->name[0] = DELETED_FLAG; ++ /* Don't mark free_bh as dirty. Both states are supposed to be equivalent. */ ++ brelse(free_bh); ++ if (exists) { ++ iput(new_inode); ++ brelse(new_bh); ++ } ++ return -EIO; ++ } ++ msdos_read_inode(free_inode); ++ old_inode->i_data[D_BUSY] = 1; ++ old_inode->i_dirt = 1; ++ old_de->name[0] = DELETED_FLAG; ++ old_bh->b_dirt = 1; ++ free_bh->b_dirt = 1; ++ if (!exists) iput(free_inode); ++ else { ++ new_inode->i_data[D_DEPEND] = (int) free_inode; ++ free_inode->i_data[D_OLD] = (int) new_inode; ++ /* free_inode is put when putting new_inode */ ++ iput(new_inode); ++ brelse(new_bh); ++ } ++ if (S_ISDIR(old_inode->i_mode)) { ++ if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh, ++ &dotdot_de,&dotdot_ino)) < 0) goto rename_done; ++ if (!(dotdot_inode = iget(old_inode->i_dev,dotdot_ino))) { ++ brelse(dotdot_bh); ++ error = -EIO; ++ goto rename_done; ++ } ++ dotdot_de->start = dotdot_inode->i_data[D_START] = ++ new_dir->i_data[D_START]; ++ dotdot_inode->i_dirt = 1; ++ dotdot_bh->b_dirt = 1; ++ iput(dotdot_inode); ++ brelse(dotdot_bh); ++ } ++ error = 0; ++ rename_done: ++ brelse(free_bh); ++ iput(old_inode); ++ return error; ++ } ++ ++ ++ int msdos_rename(struct inode *old_dir,const char *old_name,int old_len, ++ struct inode *new_dir,const char *new_name,int new_len) ++ { ++ char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME]; ++ struct buffer_head *old_bh; ++ struct msdos_dir_entry *old_de; ++ int old_ino,error; ++ ++ if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check, ++ old_name,old_len,old_msdos_name)) < 0) goto rename_done; ++ if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check, ++ new_name,new_len,new_msdos_name)) < 0) goto rename_done; ++ if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de, ++ &old_ino)) < 0) goto rename_done; ++ lock_creation(); ++ if (old_dir == new_dir) ++ error = rename_same_dir(old_dir,old_msdos_name,new_dir, ++ new_msdos_name,old_bh,old_de,old_ino); ++ else error = rename_diff_dir(old_dir,old_msdos_name,new_dir, ++ new_msdos_name,old_bh,old_de,old_ino); ++ unlock_creation(); ++ brelse(old_bh); ++ rename_done: ++ iput(old_dir); ++ iput(new_dir); ++ return error; ++ } +*** /dev/null Sat Jul 18 22:26:09 1992 +--- linux/fs/msdos/fat.c Thu Jul 16 00:35:11 1992 +*************** +*** 0 **** +--- 1,277 ---- ++ /* ++ * linux/fs/msdos/fat.c ++ * ++ * Written 1992 by Werner Almesberger ++ */ ++ ++ #include ++ #include ++ #include ++ #include ++ ++ ++ static struct fat_cache *fat_cache,cache[FAT_CACHE]; ++ ++ ++ /* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If ++ new_value is != -1, that FAT entry is replaced by it. */ ++ ++ int fat_access(struct super_block *sb,int this,int new_value) ++ { ++ struct buffer_head *bh,*bh2,*c_bh,*c_bh2; ++ unsigned char *p_first,*p_last; ++ void *data,*data2,*c_data,*c_data2; ++ int first,last,next,copy; ++ ++ if (MSDOS_SB(sb)->fat_bits == 16) first = last = this*2; ++ else { ++ first = this*3/2; ++ last = first+1; ++ } ++ if (!(bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >> ++ SECTOR_BITS),&data))) { ++ printk("bread in fat_access failed\r\n"); ++ return 0; ++ } ++ if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS)) { ++ bh2 = bh; ++ data2 = data; ++ } ++ else { ++ if (!(bh2 = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last ++ >> SECTOR_BITS),&data2))) { ++ brelse(bh); ++ printk("bread in fat_access failed\r\n"); ++ return 0; ++ } ++ } ++ if (MSDOS_SB(sb)->fat_bits == 16) { ++ next = ((unsigned short *) data)[(first & (SECTOR_SIZE-1)) ++ >> 1]; ++ if (next >= 0xfff8) next = -1; ++ } ++ else { ++ p_first = &((unsigned char *) data)[first & (SECTOR_SIZE-1)]; ++ p_last = &((unsigned char *) data2)[(first+1) & ++ (SECTOR_SIZE-1)]; ++ if (this & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff; ++ else next = (*p_first+(*p_last << 8)) & 0xfff; ++ if (next >= 0xff8) next = -1; ++ } ++ if (new_value != -1) { ++ if (MSDOS_SB(sb)->fat_bits == 16) ++ ((unsigned short *) data)[(first & (SECTOR_SIZE-1)) >> ++ 1] = new_value; ++ else { ++ if (this & 1) { ++ *p_first = (*p_first & 0xf) | (new_value << 4); ++ *p_last = new_value >> 4; ++ } ++ else { ++ *p_first = new_value & 0xff; ++ *p_last = (*p_last & 0xf0) | (new_value >> 8); ++ } ++ bh2->b_dirt = 1; ++ } ++ bh->b_dirt = 1; ++ for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) { ++ if (!(c_bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)-> ++ fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)-> ++ fat_length*copy,&c_data))) break; ++ memcpy(c_data,data,SECTOR_SIZE); ++ c_bh->b_dirt = 1; ++ if (data != data2 || bh != bh2) { ++ if (!(c_bh2 = msdos_sread(sb->s_dev, ++ MSDOS_SB(sb)->fat_start+(first >> ++ SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy ++ +1,&c_data2))) { ++ brelse(c_bh); ++ break; ++ } ++ memcpy(c_data2,data2,SECTOR_SIZE); ++ brelse(c_bh2); ++ } ++ brelse(c_bh); ++ } ++ } ++ brelse(bh); ++ if (data != data2) brelse(bh2); ++ return next; ++ } ++ ++ ++ void cache_init(void) ++ { ++ static int initialized = 0; ++ int count; ++ ++ if (initialized) return; ++ fat_cache = &cache[0]; ++ for (count = 0; count < FAT_CACHE; count++) { ++ cache[count].device = 0; ++ cache[count].next = count == FAT_CACHE-1 ? NULL : ++ &cache[count+1]; ++ } ++ initialized = 1; ++ } ++ ++ ++ void cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu) ++ { ++ struct fat_cache *walk; ++ ++ #ifdef DEBUG ++ printk("cache lookup: %d\r\n",*f_clu); ++ #endif ++ for (walk = fat_cache; walk; walk = walk->next) ++ if (inode->i_dev == walk->device && walk->ino == inode->i_ino && ++ walk->file_cluster <= cluster && walk->file_cluster > ++ *f_clu) { ++ *d_clu = walk->disk_cluster; ++ #ifdef DEBUG ++ printk("cache hit: %d (%d)\r\n",walk->file_cluster,*d_clu); ++ #endif ++ if ((*f_clu = walk->file_cluster) == cluster) return; ++ } ++ } ++ ++ ++ #ifdef DEBUG ++ static void list_cache(void) ++ { ++ struct fat_cache *walk; ++ ++ for (walk = fat_cache; walk; walk = walk->next) { ++ if (walk->device) printk("(%d,%d) ",walk->file_cluster, ++ walk->disk_cluster); ++ else printk("-- "); ++ } ++ printk("\r\n"); ++ } ++ #endif ++ ++ ++ void cache_add(struct inode *inode,int f_clu,int d_clu) ++ { ++ struct fat_cache *walk,*last; ++ ++ #ifdef DEBUG ++ printk("cache add: %d (%d)\r\n",f_clu,d_clu); ++ #endif ++ last = NULL; ++ for (walk = fat_cache; walk->next; walk = (last = walk)->next) ++ if (inode->i_dev == walk->device && walk->ino == inode->i_ino && ++ walk->file_cluster == f_clu) { ++ if (walk->disk_cluster != d_clu) ++ panic("FAT cache corruption"); ++ /* update LRU */ ++ if (last == NULL) return; ++ last->next = walk->next; ++ walk->next = fat_cache; ++ fat_cache = walk; ++ #ifdef DEBUG ++ list_cache(); ++ #endif ++ return; ++ } ++ walk->device = inode->i_dev; ++ walk->ino = inode->i_ino; ++ walk->file_cluster = f_clu; ++ walk->disk_cluster = d_clu; ++ last->next = NULL; ++ walk->next = fat_cache; ++ fat_cache = walk; ++ #ifdef DEBUG ++ list_cache(); ++ #endif ++ } ++ ++ ++ /* Cache invalidation occurs rarely, thus the LRU chain is not updated. It ++ fixes itself after a while. */ ++ ++ void cache_inval_inode(struct inode *inode) ++ { ++ struct fat_cache *walk; ++ ++ for (walk = fat_cache; walk; walk = walk->next) ++ if (walk->device == inode->i_dev && walk->ino == inode->i_ino) ++ walk->device = 0; ++ } ++ ++ ++ void cache_inval_dev(int device) ++ { ++ struct fat_cache *walk; ++ ++ for (walk = fat_cache; walk; walk = walk->next) ++ if (walk->device == device) walk->device = 0; ++ } ++ ++ ++ int get_cluster(struct inode *inode,int cluster) ++ { ++ int this,count; ++ ++ if (!(this = inode->i_data[D_START])) return 0; ++ if (!cluster) return this; ++ count = 0; ++ for (cache_lookup(inode,cluster,&count,&this); count < cluster; ++ count++) { ++ if ((this = fat_access(inode->i_sb,this,-1)) == -1) return 0; ++ if (!this) return 0; ++ } ++ cache_add(inode,cluster,this); ++ return this; ++ } ++ ++ ++ int msdos_smap(struct inode *inode,int sector) ++ { ++ struct msdos_sb_info *sb; ++ int cluster,offset; ++ ++ sb = MSDOS_SB(inode->i_sb); ++ if (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) && ++ !inode->i_data[D_START])) { ++ if (sector >= sb->dir_entries >> MSDOS_DPS_BITS) return 0; ++ return sector+sb->dir_start; ++ } ++ cluster = sector/sb->cluster_size; ++ offset = sector % sb->cluster_size; ++ if (!(cluster = get_cluster(inode,cluster))) return 0; ++ return (cluster-2)*sb->cluster_size+sb->data_start+offset; ++ } ++ ++ ++ /* Free all clusters after the skip'th cluster. Doesn't use the cache, ++ because this way we get an additional sanity check. */ ++ ++ int fat_free(struct inode *inode,int skip) ++ { ++ int this,last; ++ ++ if (!(this = inode->i_data[D_START])) return 0; ++ last = 0; ++ while (skip--) { ++ last = this; ++ if ((this = fat_access(inode->i_sb,this,-1)) == -1) ++ return 0; ++ if (!this) { ++ printk("fat_free: skipped EOF\r\n"); ++ return -EIO; ++ } ++ } ++ if (last) ++ fat_access(inode->i_sb,last,MSDOS_SB(inode->i_sb)->fat_bits == ++ 12 ? 0xff8 : 0xfff8); ++ else { ++ inode->i_data[D_START] = 0; ++ inode->i_dirt = 1; ++ } ++ while (this != -1) ++ if (!(this = fat_access(inode->i_sb,this,0))) ++ panic("fat_free: deleting beyond EOF"); ++ cache_inval_inode(inode); ++ return 0; ++ } +*** 0.96c.pl1/linux/fs/minix/namei.c Sat Jul 18 22:28:14 1992 +--- linux/fs/minix/namei.c Wed Jul 15 16:11:22 1992 +*************** +*** 751,757 **** + int minix_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) + { +! static struct task_struct * wait = NULL; + static int lock = 0; + int result; + +--- 751,757 ---- + int minix_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) + { +! static struct wait_queue * wait = NULL; + static int lock = 0; + int result; + +*** 0.96c.pl1/linux/kernel/sched.c Sat Jul 18 22:28:23 1992 +--- linux/kernel/sched.c Wed Jul 15 16:28:36 1992 +*************** +*** 35,41 **** + { + int i,j = 4096-sizeof(struct task_struct); + +! printk("%d: pid=%d, state=%d, father=%d, child=%d, ",nr,p->pid, + p->state, p->p_pptr->pid, p->p_cptr ? p->p_cptr->pid : -1); + i=0; + while (ipid, + p->state, p->p_pptr->pid, p->p_cptr ? p->p_cptr->pid : -1); + i=0; + while (itimeout && (*p)->timeout < jiffies) + if ((*p)->state == TASK_INTERRUPTIBLE) { + (*p)->timeout = 0; +! (*p)->state = TASK_RUNNING; + } + if (((*p)->signal & ~(*p)->blocked) && +! (*p)->state==TASK_INTERRUPTIBLE) +! (*p)->state=TASK_RUNNING; + } + + /* this is the scheduler proper: */ +--- 136,146 ---- + if ((*p)->timeout && (*p)->timeout < jiffies) + if ((*p)->state == TASK_INTERRUPTIBLE) { + (*p)->timeout = 0; +! wake_one_task(*p); + } + if (((*p)->signal & ~(*p)->blocked) && +! (*p)->state==TASK_INTERRUPTIBLE) +! wake_one_task(*p); + } + + /* this is the scheduler proper: */ +*************** +*** 181,239 **** + return -EINTR; + } + + /* + * wake_up doesn't wake up stopped processes - they have to be awakened + * with signals or similar. + */ +! void wake_up(struct task_struct **p) + { +! struct task_struct * wakeup_ptr, * tmp; + +! if (p && *p) { +! wakeup_ptr = *p; +! *p = NULL; +! while (wakeup_ptr && wakeup_ptr != task[0]) { +! if (wakeup_ptr->state == TASK_ZOMBIE) + printk("wake_up: TASK_ZOMBIE\n"); +! else if (wakeup_ptr->state != TASK_STOPPED) { +! wakeup_ptr->state = TASK_RUNNING; +! if (wakeup_ptr->counter > current->counter) + need_resched = 1; + } +- tmp = wakeup_ptr->next_wait; +- wakeup_ptr->next_wait = task[0]; +- wakeup_ptr = tmp; + } +! } + } + +! static inline void __sleep_on(struct task_struct **p, int state) + { +! unsigned int flags; + + if (!p) + return; + if (current == task[0]) + panic("task[0] trying to sleep"); +! __asm__("pushfl ; popl %0":"=r" (flags)); +! current->next_wait = *p; +! task[0]->next_wait = NULL; +! *p = current; + current->state = state; + sti(); + schedule(); +! if (current->next_wait != task[0]) +! wake_up(p); +! current->next_wait = NULL; + __asm__("pushl %0 ; popfl"::"r" (flags)); + } + +! void interruptible_sleep_on(struct task_struct **p) + { + __sleep_on(p,TASK_INTERRUPTIBLE); + } + +! void sleep_on(struct task_struct **p) + { + __sleep_on(p,TASK_UNINTERRUPTIBLE); + } +--- 181,248 ---- + return -EINTR; + } + ++ void wake_one_task(struct task_struct * p) ++ { ++ p->state = TASK_RUNNING; ++ if (p->counter > current->counter) ++ need_resched = 1; ++ } ++ + /* + * wake_up doesn't wake up stopped processes - they have to be awakened + * with signals or similar. + */ +! void wake_up(struct wait_queue **q) + { +! struct wait_queue *tmp, *next; +! struct task_struct * p; +! unsigned long flags; + +! if (!q || !(next = *q)) +! return; +! __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags)); +! do { +! tmp = next; +! next = tmp->next; +! if (p = tmp->task) { +! if (p->state == TASK_ZOMBIE) + printk("wake_up: TASK_ZOMBIE\n"); +! else if (p->state != TASK_STOPPED) { +! p->state = TASK_RUNNING; +! if (p->counter > current->counter) + need_resched = 1; + } + } +! tmp->next = NULL; +! } while (next && next != *q); +! __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags)); + } + +! static inline void __sleep_on(struct wait_queue **p, int state) + { +! unsigned long flags; + + if (!p) + return; + if (current == task[0]) + panic("task[0] trying to sleep"); +! if (current->wait.next) +! printk("__sleep_on: wait->next exists\n"); +! __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags)); + current->state = state; ++ add_wait_queue(p,¤t->wait); + sti(); + schedule(); +! remove_wait_queue(p,¤t->wait); + __asm__("pushl %0 ; popfl"::"r" (flags)); + } + +! void interruptible_sleep_on(struct wait_queue **p) + { + __sleep_on(p,TASK_INTERRUPTIBLE); + } + +! void sleep_on(struct wait_queue **p) + { + __sleep_on(p,TASK_UNINTERRUPTIBLE); + } +*************** +*** 243,249 **** + * proper. They are here because the floppy needs a timer, and this + * was the easiest way of doing it. + */ +! static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL}; + static int mon_timer[4]={0,0,0,0}; + static int moff_timer[4]={0,0,0,0}; + unsigned char current_DOR = 0x0C; +--- 252,258 ---- + * proper. They are here because the floppy needs a timer, and this + * was the easiest way of doing it. + */ +! static struct wait_queue * wait_motor[4] = {NULL,NULL,NULL,NULL}; + static int mon_timer[4]={0,0,0,0}; + static int moff_timer[4]={0,0,0,0}; + unsigned char current_DOR = 0x0C; +*** 0.96c.pl1/linux/kernel/exit.c Sun Jul 5 01:22:27 1992 +--- linux/kernel/exit.c Tue Jul 14 02:59:22 1992 +*************** +*** 421,426 **** +--- 421,427 ---- + if (stat_addr) + verify_area(stat_addr,4); + repeat: ++ current->signal &= ~(1<<(SIGCHLD-1)); + flag=0; + for (p = current->p_cptr ; p ; p = p->p_osptr) { + if (pid>0) { +*** 0.96c.pl1/linux/kernel/fork.c Sun Jul 5 01:20:58 1992 +--- linux/kernel/fork.c Thu Jul 16 12:54:00 1992 +*************** +*** 66,72 **** + + static int find_empty_process(void) + { +! int i; + + repeat: + if ((++last_pid) & 0xffff0000) +--- 66,72 ---- + + static int find_empty_process(void) + { +! int i, task_nr; + + repeat: + if ((++last_pid) & 0xffff0000) +*************** +*** 75,83 **** + if (task[i] && ((task[i]->pid == last_pid) || + (task[i]->pgrp == last_pid))) + goto repeat; + for(i=1 ; ipid == last_pid) || + (task[i]->pgrp == last_pid))) + goto repeat; ++ /* Only the super-user can fill the last available slot */ ++ task_nr = 0; + for(i=1 ; iwait.task = p; ++ p->wait.next = NULL; + p->state = TASK_UNINTERRUPTIBLE; + p->flags &= ~PF_PTRACED; + p->pid = last_pid; +*************** +*** 125,131 **** + 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; +--- 134,140 ---- + p->tss.esp0 = PAGE_SIZE + (long) p; + p->tss.ss0 = 0x10; + p->tss.eip = eip; +! p->tss.eflags = eflags & 0xffffcfff; /* iopl is always 0 for a new process */ + p->tss.eax = 0; + p->tss.ecx = ecx; + p->tss.edx = edx; +*** 0.96c.pl1/linux/kernel/traps.c Sat Jul 18 22:28:23 1992 +--- linux/kernel/traps.c Tue Jul 14 15:04:54 1992 +*************** +*** 57,63 **** + void page_fault(void); + void coprocessor_error(void); + void reserved(void); +- void irq13(void); + void alignment_check(void); + + static void die(char * str,long esp_ptr,long nr) +--- 57,62 ---- +*************** +*** 199,203 **** + set_trap_gate(17,&alignment_check); + for (i=18;i<48;i++) + set_trap_gate(i,&reserved); +- set_trap_gate(45,&irq13); + } +--- 198,201 ---- +*** 0.96c.pl1/linux/kernel/printk.c Sun May 17 17:07:00 1992 +--- linux/kernel/printk.c Wed Jul 15 15:49:43 1992 +*************** +*** 22,28 **** + static unsigned long log_page = 0; + static unsigned long log_start = 0; + static unsigned long log_size = 0; +! static struct task_struct * log_wait = NULL; + + int sys_syslog(int type, char * buf, int len) + { +--- 22,28 ---- + static unsigned long log_page = 0; + static unsigned long log_start = 0; + static unsigned long log_size = 0; +! static struct wait_queue * log_wait = NULL; + + int sys_syslog(int type, char * buf, int len) + { +*** 0.96c.pl1/linux/kernel/chr_drv/keyboard.c Sat Jul 18 22:28:23 1992 +--- linux/kernel/chr_drv/keyboard.c Thu Jul 16 02:31:56 1992 +*************** +*** 126,133 **** + qp->buf[qp->head]=ch; + if ((new_head=(qp->head+1)&(TTY_BUF_SIZE-1)) != qp->tail) + qp->head=new_head; +! if (qp->proc_list != NULL) +! qp->proc_list->state=0; + } + + static void puts_queue(char *cp) +--- 126,132 ---- + qp->buf[qp->head]=ch; + if ((new_head=(qp->head+1)&(TTY_BUF_SIZE-1)) != qp->tail) + qp->head=new_head; +! wake_up(&qp->proc_list); + } + + static void puts_queue(char *cp) +*************** +*** 142,149 **** + != qp->tail) + qp->head=new_head; + } +! if (qp->proc_list != NULL) +! qp->proc_list->state=0; + } + + static void ctrl(int sc) +--- 141,147 ---- + != qp->tail) + qp->head=new_head; + } +! wake_up(&qp->proc_list); + } + + static void ctrl(int sc) +*************** +*** 777,782 **** +--- 775,866 ---- + 0, 0, 0, 0, 0, 0, 0, 0, + 0 }; + ++ #elif defined KBD_SG ++ static unsigned char key_map[] = { ++ 0, 27, '1', '2', '3', '4', '5', '6', ++ '7', '8', '9', '0', '\'', '^', 127, 9, ++ 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', ++ 'o', 'p', 0, 0, 13, 0, 'a', 's', ++ 'd', 'f', 'g', 'h', 'j', 'k', 'l', 0, ++ 0, 0, 0, '$', 'y', 'x', 'c', 'v', ++ 'b', 'n', 'm', ',', '.', '-', 0, '*', ++ 0, 32, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, '-', 0, 0, 0, '+', 0, ++ 0, 0, 0, 0, 0, 0, '<', 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0 }; ++ static unsigned char shift_map[] = { ++ 0, 27, '+', '"', '*', 0, '%', '&', ++ '/', '(', ')', '=', '?', '`', 127, 9, ++ 'Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I', ++ 'O', 'P', 0, '!', 13, 0, 'A', 'S', ++ 'D', 'F', 'G', 'H', 'J', 'K', 'L', 0, ++ 0, 0, 0, 0, 'Y', 'X', 'C', 'V', ++ 'B', 'N', 'M', ';', ':', '_', 0, '*', ++ 0, 32, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, '-', 0, 0, 0, '+', 0, ++ 0, 0, 0, 0, 0, 0, '>', 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0 }; ++ static unsigned char alt_map[] = { ++ 0, 0, 0, '@', '#', 0, 0, 0, ++ '|', 0, 0, 0, '\'', '~', 0, 0, ++ '@', 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, '[', ']', 13, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ '{', 0, 0, '}', 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, '\\', 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0 }; ++ #elif defined KBD_SG_LATIN1 ++ static unsigned char key_map[] = { ++ 0, 27, '1', '2', '3', '4', '5', '6', ++ '7', '8', '9', '0', '\'', '^', 127, 9, ++ 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', ++ 'o', 'p', 252, 0, 13, 0, 'a', 's', ++ 'd', 'f', 'g', 'h', 'j', 'k', 'l', 246, ++ 228, 167, 0, '$', 'y', 'x', 'c', 'v', ++ 'b', 'n', 'm', ',', '.', '-', 0, '*', ++ 0, 32, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, '-', 0, 0, 0, '+', 0, ++ 0, 0, 0, 0, 0, 0, '<', 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0 }; ++ static unsigned char shift_map[] = { ++ 0, 27, '+', '"', '*', 231, '%', '&', ++ '/', '(', ')', '=', '?', '`', 127, 9, ++ 'Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I', ++ 'O', 'P', 220, '!', 13, 0, 'A', 'S', ++ 'D', 'F', 'G', 'H', 'J', 'K', 'L', 214, ++ 196, 176, 0, 163, 'Y', 'X', 'C', 'V', ++ 'B', 'N', 'M', ';', ':', '_', 0, '*', ++ 0, 32, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, '-', 0, 0, 0, '+', 0, ++ 0, 0, 0, 0, 0, 0, '>', 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0 }; ++ static unsigned char alt_map[] = { ++ 0, 0, 0, '@', '#', 0, 0, 172, ++ '|', 162, 0, 0, '\'', '~', 0, 0, ++ '@', 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, '[', ']', 13, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 233, ++ '{', 0, 0, '}', 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, '\\', 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0 }; + #else + #error "KBD-type not defined" + #endif +*** 0.96c.pl1/linux/kernel/chr_drv/Makefile Sun Jul 5 03:10:08 1992 +--- linux/kernel/chr_drv/Makefile Thu Jul 16 02:35:31 1992 +*************** +*** 17,23 **** + $(CC) $(CFLAGS) -c $< + + OBJS = tty_io.o console.o keyboard.o serial.o \ +! tty_ioctl.o pty.o lp.o vt.o mem.o + + chr_drv.a: $(OBJS) + $(AR) rcs chr_drv.a $(OBJS) +--- 17,23 ---- + $(CC) $(CFLAGS) -c $< + + OBJS = tty_io.o console.o keyboard.o serial.o \ +! tty_ioctl.o pty.o lp.o vt.o mem.o mouse.o + + chr_drv.a: $(OBJS) + $(AR) rcs chr_drv.a $(OBJS) +*** 0.96c.pl1/linux/kernel/chr_drv/console.c Sat Jul 18 22:28:23 1992 +--- linux/kernel/chr_drv/console.c Wed Jul 15 08:15:19 1992 +*************** +*** 212,218 **** + if (currcons == fg_console) \ + (fg) = (v) + +! int blankinterval = 5*60*HZ; + static int screen_size = 0; + + static void sysbeep(void); +--- 212,218 ---- + if (currcons == fg_console) \ + (fg) = (v) + +! int blankinterval = 10*60*HZ; + static int screen_size = 0; + + static void sysbeep(void); +*************** +*** 315,321 **** + { + if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM) + return; +! if (currcons != fg_console || vtmode == KD_GRAPHICS) + return; + cli(); + outb_p(12, video_port_reg); +--- 315,321 ---- + { + if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM) + return; +! if (currcons != fg_console || console_blanked || vtmode == KD_GRAPHICS) + return; + cli(); + outb_p(12, video_port_reg); +*************** +*** 609,615 **** + + static inline void set_cursor(int currcons) + { +! if (currcons != fg_console) + return; + cli(); + if (deccm) { +--- 609,615 ---- + + static inline void set_cursor(int currcons) + { +! if (currcons != fg_console || console_blanked) + return; + cli(); + if (deccm) { +*************** +*** 1217,1234 **** + state = ESnormal; + } + } +- timer_active &= ~(1<write_q) && !(TTY_WRITE_BUSY & tty->flags)) { +! tty->flags |= TTY_WRITE_BUSY; +! __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags)); +! tty->write(tty); +! cli(); +! tty->flags &= ~TTY_WRITE_BUSY; +! } +! __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags)); + } + + void tty_read_flush(struct tty_struct * tty) + { +! unsigned long flags; +! +! __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags)); +! if (!EMPTY(tty->read_q) && !(TTY_READ_BUSY & tty->flags)) { +! tty->flags |= TTY_READ_BUSY; +! __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags)); +! copy_to_cooked(tty); +! cli(); +! tty->flags &= ~TTY_READ_BUSY; +! } +! __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags)); + } + + void change_console(unsigned int new_console) +--- 90,113 ---- + + void tty_write_flush(struct tty_struct * tty) + { +! if (EMPTY(tty->write_q)) +! return; +! if (set_bit(TTY_WRITE_BUSY,&tty->flags)) +! return; +! tty->write(tty); +! if (clear_bit(TTY_WRITE_BUSY,&tty->flags)) +! printk("tty_write_flush: bit already cleared\n"); + } + + void tty_read_flush(struct tty_struct * tty) + { +! if (EMPTY(tty->read_q)) +! return; +! if (set_bit(TTY_READ_BUSY, &tty->flags)) +! return; +! copy_to_cooked(tty); +! if (clear_bit(TTY_READ_BUSY, &tty->flags)) +! printk("tty_read_flush: bit already cleared\n"); + } + + void change_console(unsigned int new_console) +*************** +*** 296,301 **** +--- 288,315 ---- + return -ERESTARTSYS; + } + ++ static void wait_for_canon_input(struct tty_struct * tty) ++ { ++ while (1) { ++ TTY_READ_FLUSH(tty); ++ if (tty->link) ++ if (tty->link->count) ++ TTY_WRITE_FLUSH(tty->link); ++ else ++ return; ++ if (current->signal & ~current->blocked) ++ return; ++ if (FULL(tty->read_q)) ++ return; ++ if (tty->secondary->data) ++ return; ++ cli(); ++ if (!tty->secondary->data) ++ interruptible_sleep_on(&tty->secondary->proc_list); ++ sti(); ++ } ++ } ++ + static int read_chan(unsigned int channel, struct file * file, char * buf, int nr) + { + struct tty_struct * tty; +*************** +*** 315,359 **** + return -EIO; + else + return(tty_signal(SIGTTIN, tty)); +! time = 10L*tty->termios.c_cc[VTIME]; +! minimum = tty->termios.c_cc[VMIN]; +! if (L_CANON(tty)) { +! minimum = nr; +! current->timeout = 0xffffffff; +! time = 0; +! } else if (minimum) +! current->timeout = 0xffffffff; + else { +! minimum = nr; +! if (time) +! current->timeout = time + jiffies; +! time = 0; + } + if (file->f_flags & O_NONBLOCK) + time = current->timeout = 0; + if (minimum>nr) + minimum = nr; +- TTY_READ_FLUSH(tty); + while (nr>0) { +! if (tty->link && tty->link->write) + TTY_WRITE_FLUSH(tty->link); +! cli(); +! if (EMPTY(tty->secondary) || (L_CANON(tty) && +! !FULL(tty->read_q) && !tty->secondary->data)) { +! if (!current->timeout) +! break; +! if (current->signal & ~current->blocked) +! break; +! if (tty->link && !tty->link->count) +! break; +! interruptible_sleep_on(&tty->secondary->proc_list); +! sti(); +! TTY_READ_FLUSH(tty); +! continue; +! } +! sti(); +! do { +! c = get_tty_queue(tty->secondary); + if ((EOF_CHAR(tty) != __DISABLED_CHAR && + c==EOF_CHAR(tty)) || c==10) + tty->secondary->data--; +--- 329,361 ---- + return -EIO; + else + return(tty_signal(SIGTTIN, tty)); +! if (L_CANON(tty)) +! minimum = time = current->timeout = 0; + else { +! time = 10L*tty->termios.c_cc[VTIME]; +! minimum = tty->termios.c_cc[VMIN]; +! if (minimum) +! current->timeout = 0xffffffff; +! else { +! if (time) +! current->timeout = time + jiffies; +! else +! current->timeout = 0; +! time = 0; +! minimum = 1; +! } + } + if (file->f_flags & O_NONBLOCK) + time = current->timeout = 0; ++ else if (L_CANON(tty)) ++ wait_for_canon_input(tty); + if (minimum>nr) + minimum = nr; + while (nr>0) { +! TTY_READ_FLUSH(tty); +! if (tty->link) + TTY_WRITE_FLUSH(tty->link); +! while (nr > 0 && ((c = get_tty_queue(tty->secondary)) >= 0)) { + if ((EOF_CHAR(tty) != __DISABLED_CHAR && + c==EOF_CHAR(tty)) || c==10) + tty->secondary->data--; +*************** +*** 360,380 **** + if ((EOF_CHAR(tty) != __DISABLED_CHAR && + c==EOF_CHAR(tty)) && L_CANON(tty)) + break; +! else { +! put_fs_byte(c,b++); +! if (!--nr) +! break; +! } + if (c==10 && L_CANON(tty)) + break; +! } while (nr>0 && !EMPTY(tty->secondary)); + wake_up(&tty->read_q->proc_list); +! if (L_CANON(tty) || b-buf >= minimum) + break; +! if (time) +! current->timeout = time+jiffies; + } +- sti(); + TTY_READ_FLUSH(tty); + if (tty->link && tty->link->write) + TTY_WRITE_FLUSH(tty->link); +--- 362,389 ---- + if ((EOF_CHAR(tty) != __DISABLED_CHAR && + c==EOF_CHAR(tty)) && L_CANON(tty)) + break; +! put_fs_byte(c,b++); +! nr--; +! if (time) +! current->timeout = time+jiffies; + if (c==10 && L_CANON(tty)) + break; +! }; + wake_up(&tty->read_q->proc_list); +! if (b-buf >= minimum || !current->timeout) + break; +! if (current->signal & ~current->blocked) +! break; +! if (tty->link && !tty->link->count) +! break; +! TTY_READ_FLUSH(tty); +! if (tty->link) +! TTY_WRITE_FLUSH(tty->link); +! cli(); +! if (EMPTY(tty->secondary)) +! interruptible_sleep_on(&tty->secondary->proc_list); +! sti(); + } + TTY_READ_FLUSH(tty); + if (tty->link && tty->link->write) + TTY_WRITE_FLUSH(tty->link); +*************** +*** 433,440 **** + c='\n'; + else if (c=='\n' && O_NLRET(tty)) + c='\r'; +! if (c=='\n' && !(tty->flags & TTY_CR_PENDING) && O_NLCR(tty)) { +! tty->flags |= TTY_CR_PENDING; + put_tty_queue(13,tty->write_q); + continue; + } +--- 442,449 ---- + c='\n'; + else if (c=='\n' && O_NLRET(tty)) + c='\r'; +! if (c=='\n' && O_NLCR(tty) && +! !set_bit(TTY_CR_PENDING,&tty->flags)) { + put_tty_queue(13,tty->write_q); + continue; + } +*************** +*** 442,448 **** + c=toupper(c); + } + b++; nr--; +! tty->flags &= ~TTY_CR_PENDING; + put_tty_queue(c,tty->write_q); + } + if (nr>0) +--- 451,457 ---- + c=toupper(c); + } + b++; nr--; +! clear_bit(TTY_CR_PENDING,&tty->flags); + put_tty_queue(c,tty->write_q); + } + if (nr>0) +*************** +*** 516,521 **** +--- 525,531 ---- + if (!tty->count && !(tty->link && tty->link->count)) { + flush_input(tty); + flush_output(tty); ++ tty->stopped = 0; + } + if (IS_A_PTY_MASTER(dev)) { + if (tty->count) +*************** +*** 540,546 **** + if (retval) { + tty->count--; + if (IS_A_PTY_MASTER(dev) && tty->link) +! tty->link->count++; + } + return retval; + } +--- 550,556 ---- + if (retval) { + tty->count--; + if (IS_A_PTY_MASTER(dev) && tty->link) +! tty->link->count--; + } + return retval; + } +*************** +*** 579,590 **** + redirect = NULL; + } + + static struct file_operations tty_fops = { + tty_lseek, + tty_read, + tty_write, + NULL, /* tty_readdir */ +! NULL, /* tty_select */ + tty_ioctl, + tty_open, + tty_release +--- 589,633 ---- + redirect = NULL; + } + ++ static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait) ++ { ++ int dev; ++ struct tty_struct * tty; ++ ++ dev = filp->f_rdev; ++ if (MAJOR(dev) != 4) { ++ printk("tty_select: tty pseudo-major != 4\n"); ++ return 0; ++ } ++ dev = MINOR(filp->f_rdev); ++ tty = TTY_TABLE(dev); ++ switch (sel_type) { ++ case SEL_IN: ++ if (!EMPTY(tty->secondary)) ++ return 1; ++ if (tty->link && !tty->link->count) ++ return 1; ++ select_wait(&tty->secondary->proc_list, wait); ++ return 0; ++ case SEL_OUT: ++ if (!FULL(tty->write_q)) ++ return 1; ++ select_wait(&tty->write_q->proc_list, wait); ++ return 0; ++ case SEL_EX: ++ if (tty->link && !tty->link->count) ++ return 1; ++ return 0; ++ } ++ return 0; ++ } ++ + static struct file_operations tty_fops = { + tty_lseek, + tty_read, + tty_write, + NULL, /* tty_readdir */ +! tty_select, + tty_ioctl, + tty_open, + tty_release +*** 0.96c.pl1/linux/kernel/chr_drv/serial.c Sat Jul 18 22:28:31 1992 +--- linux/kernel/chr_drv/serial.c Thu Jul 16 12:39:10 1992 +*************** +*** 33,38 **** +--- 33,40 ---- + { PORT_UNKNOWN, 3, 0x2E8, 3, NULL}, + }; + ++ static void send_intr(struct serial_struct * info); ++ + static void modem_status_intr(struct serial_struct * info) + { + unsigned char status = inb(info->port+6); +*************** +*** 40,51 **** + if (!(info->tty->termios.c_cflag & CLOCAL)) { + if ((status & 0x88) == 0x08 && info->tty->pgrp > 0) + kill_pg(info->tty->pgrp,SIGHUP,1); +! #if 0 +! if ((status & 0x10) == 0x10) +! info->tty->stopped = 0; +! else +! info->tty->stopped = 1; +! #endif + } + } + +--- 42,53 ---- + if (!(info->tty->termios.c_cflag & CLOCAL)) { + if ((status & 0x88) == 0x08 && info->tty->pgrp > 0) + kill_pg(info->tty->pgrp,SIGHUP,1); +! +! if (info->tty->termios.c_cflag & CRTSCTS) +! info->tty->stopped = !(status & 0x10); +! +! if (!info->tty->stopped) +! send_intr(info); + } + } + +*************** +*** 83,88 **** +--- 85,92 ---- + struct tty_queue * queue = info->tty->write_q; + int c, i = 0; + ++ if (info->tty->stopped) return; ++ + timer_active &= ~(1 << timer); + while (inb_p(info->port+5) & 0x20) { + if (queue->tail == queue->head) +*************** +*** 90,97 **** + c = queue->buf[queue->tail]; + queue->tail++; + queue->tail &= TTY_BUF_SIZE-1; +! outb(c,port); +! if ((info->type != PORT_16550A) || (++i >= 14)) + break; + } + timer_table[timer].expires = jiffies + 10; +--- 94,101 ---- + c = queue->buf[queue->tail]; + queue->tail++; + queue->tail &= TTY_BUF_SIZE-1; +! outb(c,port); +! if ((info->type != PORT_16550A) || (++i >= 14) || info->tty->stopped) + break; + } + timer_table[timer].expires = jiffies + 10; +*************** +*** 303,312 **** + outb_p(0x03,port+3); /* reset DLAB */ + outb_p(0x0f,port+4); /* set DTR,RTS, OUT_2 */ + outb_p(0x0f,port+1); /* enable all intrs */ +! inb_p(port+5); +! inb_p(port+0); + inb_p(port+6); +! inb(port+2); + } + + void change_speed(unsigned int line) +--- 307,321 ---- + outb_p(0x03,port+3); /* reset DLAB */ + outb_p(0x0f,port+4); /* set DTR,RTS, OUT_2 */ + outb_p(0x0f,port+1); /* enable all intrs */ +! inb_p(port+2); + inb_p(port+6); +! inb_p(port+2); +! inb_p(port+5); +! do { /* drain all of the stuck characters out of the port */ +! inb_p(port+0); +! } while (inb_p(port+5) & 1 == 1); +! inb_p(port+2); +! inb_p(port+5); + } + + void change_speed(unsigned int line) +*************** +*** 416,421 **** +--- 425,431 ---- + retval = request_irq(new_irq,handler); + if (retval) + return retval; ++ info->irq = new_irq; + free_irq(irq); + } + cli(); +*************** +*** 455,472 **** + for (i = 0, info = serial_table; i < NR_SERIALS; i++,info++) { + info->tty = (tty_table+64) + i; + init(info); + switch (info->type) { + case PORT_8250: +! printk("serial port at 0x%04x is a 8250\n", info->port); + break; + case PORT_16450: +! printk("serial port at 0x%04x is a 16450\n", info->port); + break; + case PORT_16550: +! printk("serial port at 0x%04x is a 16550\n", info->port); + break; + case PORT_16550A: +! printk("serial port at 0x%04x is a 16550A\n", info->port); + break; + } + } +--- 465,488 ---- + for (i = 0, info = serial_table; i < NR_SERIALS; i++,info++) { + info->tty = (tty_table+64) + i; + init(info); ++ if (info->type == PORT_UNKNOWN) ++ continue; ++ printk("serial port at 0x%04x (irq = %d)",info->port,info->irq); + switch (info->type) { + case PORT_8250: +! printk(" is a 8250\n"); + break; + case PORT_16450: +! printk(" is a 16450\n"); + break; + case PORT_16550: +! printk(" is a 16550\n"); + break; + case PORT_16550A: +! printk(" is a 16550A\n"); +! break; +! default: +! printk("\n"); + break; + } + } +*** /dev/null Sat Jul 18 22:26:09 1992 +--- linux/kernel/chr_drv/mouse.c Wed Jul 15 04:46:19 1992 +*************** +*** 0 **** +--- 1,177 ---- ++ /* ++ * Logitech Bus Mouse Driver for Linux ++ * by James Banks ++ * ++ * Heavily modified by David Giller ++ * changed from queue- to counter- driven ++ * hacked out a (probably incorrect) mouse_select ++ * ++ * Modified again by Nathan Laredo to interface with ++ * 0.96c-pl1 IRQ handling changes (13JUL92) ++ * didn't bother touching select code. ++ * ++ * Modified the select() code blindly to conform to the VFS ++ * requirements. 92.07.14 - Linus. Somebody should test it out. ++ * ++ * version 0.1 ++ */ ++ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ ++ static struct mouse_status mouse; ++ ++ static void mouse_interrupt(int cpl) ++ { ++ char dx, dy, buttons; ++ ++ MSE_INT_OFF(); ++ ++ outb(MSE_READ_X_LOW, MSE_CONTROL_PORT); ++ dx = (inb(MSE_DATA_PORT) & 0xf); ++ ++ outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT); ++ dx |= (inb(MSE_DATA_PORT) & 0xf) << 4; ++ ++ outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT ); ++ dy = (inb(MSE_DATA_PORT) & 0xf); ++ ++ outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT); ++ buttons = inb(MSE_DATA_PORT); ++ ++ dy |= (buttons & 0xf) << 4; ++ buttons = ((buttons >> 5) & 0x07); ++ ++ mouse.buttons = buttons; ++ mouse.latch_buttons |= buttons; ++ mouse.dx += dx; ++ mouse.dy += dy; ++ mouse.ready = 1; ++ if (mouse.inode && mouse.inode->i_wait) ++ wake_up(&mouse.inode->i_wait); ++ ++ MSE_INT_ON(); ++ } ++ ++ static void release_mouse(struct inode * inode, struct file * file) ++ { ++ MSE_INT_OFF(); ++ mouse.active = 0; ++ mouse.ready = 0; ++ mouse.inode = NULL; ++ free_irq(MOUSE_IRQ); ++ } ++ ++ static int open_mouse(struct inode * inode, struct file * file) ++ { ++ if (mouse.active) ++ return -EBUSY; ++ if (!mouse.present) ++ return -EINVAL; ++ if (request_irq(MOUSE_IRQ, mouse_interrupt)) ++ return -EBUSY; ++ mouse.active = 1; ++ mouse.ready = 0; ++ mouse.inode = inode; ++ mouse.dx = 0; ++ mouse.dy = 0; ++ mouse.buttons = mouse.latch_buttons = 0x80; ++ MSE_INT_ON(); ++ return 0; ++ } ++ ++ static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count) ++ { ++ return -EINVAL; ++ } ++ ++ static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count) ++ { ++ int i; ++ ++ if (count < 3) return -EINVAL; ++ if (!mouse.ready) return -EAGAIN; ++ ++ MSE_INT_OFF(); ++ ++ put_fs_byte(mouse.latch_buttons | 0x80, buffer); ++ ++ if (mouse.dx < -127) mouse.dx = -127; ++ if (mouse.dx > 127) mouse.dx = 127; ++ ++ put_fs_byte((char)mouse.dx, buffer + 1); ++ ++ if (mouse.dy < -127) mouse.dy = -127; ++ if (mouse.dy > 127) mouse.dy = 127; ++ ++ put_fs_byte((char) -mouse.dy, buffer + 2); ++ ++ for (i = 3; i < count; i++) ++ put_fs_byte(0x00, buffer + i); ++ ++ mouse.dx = 0; ++ mouse.dy = 0; ++ mouse.latch_buttons = mouse.buttons; ++ mouse.ready = 0; ++ ++ MSE_INT_ON(); ++ return i; ++ } ++ ++ static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) ++ { ++ if (sel_type != SEL_IN) ++ return 0; ++ if (mouse.ready) ++ return 1; ++ select_wait(&inode->i_wait,wait); ++ return 0; ++ } ++ ++ static struct file_operations mouse_fops = { ++ NULL, /* mouse_seek */ ++ read_mouse, ++ write_mouse, ++ NULL, /* mouse_readdir */ ++ mouse_select, /* mouse_select */ ++ NULL, /* mouse_ioctl */ ++ open_mouse, ++ release_mouse, ++ }; ++ ++ long mouse_init(long kmem_start) ++ { ++ int i; ++ ++ outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT); ++ outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT); ++ ++ for (i = 0; i < 100000; i++); /* busy loop */ ++ if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) { ++ printk("No bus mouse detected.\n"); ++ mouse.present = 0; ++ return kmem_start; ++ } ++ chrdev_fops[10] = &mouse_fops; ++ outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT); ++ ++ MSE_INT_OFF(); ++ ++ mouse.present = 1; ++ mouse.active = 0; ++ mouse.ready = 0; ++ mouse.buttons = mouse.latch_buttons = 0x80; ++ mouse.dx = 0; ++ mouse.dy = 0; ++ printk("Bus mouse detected and installed.\n"); ++ return kmem_start; ++ } +*** 0.96c.pl1/linux/kernel/chr_drv/mem.c Sun Jul 5 00:47:51 1992 +--- linux/kernel/chr_drv/mem.c Wed Jul 15 00:35:55 1992 +*************** +*** 246,250 **** +--- 246,251 ---- + chrdev_fops[1] = &mem_fops; + mem_start = tty_init(mem_start); + mem_start = lp_init(mem_start); ++ mem_start = mouse_init(mem_start); + return mem_start; + } +*** 0.96c.pl1/linux/kernel/blk_drv/ll_rw_blk.c Sat Jul 18 22:28:40 1992 +--- linux/kernel/blk_drv/ll_rw_blk.c Wed Jul 15 16:02:43 1992 +*************** +*** 26,32 **** + /* + * used to wait on when there are no free requests + */ +! struct task_struct * wait_for_request = NULL; + + /* blk_dev_struct is: + * do_request-address +--- 26,32 ---- + /* + * used to wait on when there are no free requests + */ +! struct wait_queue * wait_for_request = NULL; + + /* blk_dev_struct is: + * do_request-address +*************** +*** 207,213 **** + /* fill up the request-info, and add it to the queue */ + req->dev = bh->b_dev; + req->cmd = rw; +! req->errors=0; + req->sector = bh->b_blocknr<<1; + req->nr_sectors = 2; + req->buffer = bh->b_data; +--- 207,213 ---- + /* fill up the request-info, and add it to the queue */ + req->dev = bh->b_dev; + req->cmd = rw; +! req->errors = 0; + req->sector = bh->b_blocknr<<1; + req->nr_sectors = 2; + req->buffer = bh->b_data; +*************** +*** 251,257 **** + req->sector = page<<3; + req->nr_sectors = 8; + req->buffer = buffer; +! req->waiting = current; + req->bh = NULL; + req->next = NULL; + current->state = TASK_UNINTERRUPTIBLE; +--- 251,257 ---- + req->sector = page<<3; + req->nr_sectors = 8; + req->buffer = buffer; +! req->waiting = ¤t->wait; + req->bh = NULL; + req->next = NULL; + current->state = TASK_UNINTERRUPTIBLE; +*************** +*** 332,338 **** + req->sector = b[i] << 1; + req->nr_sectors = 2; + req->buffer = buf; +! req->waiting = current; + req->bh = NULL; + req->next = NULL; + current->state = TASK_UNINTERRUPTIBLE; +--- 332,338 ---- + req->sector = b[i] << 1; + req->nr_sectors = 2; + req->buffer = buf; +! req->waiting = ¤t->wait; + req->bh = NULL; + req->next = NULL; + current->state = TASK_UNINTERRUPTIBLE; +*** 0.96c.pl1/linux/kernel/blk_drv/floppy.c Sat Jul 18 22:28:40 1992 +--- linux/kernel/blk_drv/floppy.c Wed Jul 15 16:00:15 1992 +*************** +*** 177,183 **** + /* Synchronization of FDC access. */ + + static volatile int format_status = FORMAT_NONE, fdc_busy = 0; +! static struct task_struct *fdc_wait = NULL, *format_done = NULL; + + /* Errors during formatting are counted here. */ + +--- 177,183 ---- + /* Synchronization of FDC access. */ + + static volatile int format_status = FORMAT_NONE, fdc_busy = 0; +! static struct wait_queue *fdc_wait = NULL, *format_done = NULL; + + /* Errors during formatting are counted here. */ + +*************** +*** 233,239 **** + static unsigned char current_track = NO_TRACK; + static unsigned char command = 0; + unsigned char selected = 0; +! struct task_struct * wait_on_floppy_select = NULL; + + void floppy_deselect(unsigned int nr) + { +--- 233,239 ---- + static unsigned char current_track = NO_TRACK; + static unsigned char command = 0; + unsigned char selected = 0; +! struct wait_queue * wait_on_floppy_select = NULL; + + void floppy_deselect(unsigned int nr) + { +*** 0.96c.pl1/linux/kernel/blk_drv/blk.h Sat Jul 18 22:28:48 1992 +--- linux/kernel/blk_drv/blk.h Wed Jul 15 15:59:24 1992 +*************** +*** 27,33 **** + unsigned long sector; + unsigned long nr_sectors; + char * buffer; +! struct task_struct * waiting; + struct buffer_head * bh; + struct buffer_head * bhtail; + struct request * next; +--- 27,33 ---- + unsigned long sector; + unsigned long nr_sectors; + char * buffer; +! struct wait_queue * waiting; + struct buffer_head * bh; + struct buffer_head * bhtail; + struct request * next; +*************** +*** 50,56 **** + + extern struct blk_dev_struct blk_dev[NR_BLK_DEV]; + extern struct request request[NR_REQUEST]; +! extern struct task_struct * wait_for_request; + + extern int * blk_size[NR_BLK_DEV]; + +--- 50,56 ---- + + extern struct blk_dev_struct blk_dev[NR_BLK_DEV]; + extern struct request request[NR_REQUEST]; +! extern struct wait_queue * wait_for_request; + + extern int * blk_size[NR_BLK_DEV]; + +*** 0.96c.pl1/linux/kernel/sys_call.S Sat Jul 18 22:28:57 1992 +--- linux/kernel/sys_call.S Tue Jul 14 15:11:03 1992 +*************** +*** 37,44 **** + * 40(%esp) - %oldss + */ + +- SIG_CHLD = 17 +- + EBX = 0x00 + ECX = 0x04 + EDX = 0x08 +--- 37,42 ---- +*************** +*** 86,92 **** + .globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op + .globl _double_fault,_coprocessor_segment_overrun + .globl _invalid_TSS,_segment_not_present,_stack_segment +! .globl _general_protection,_irq13,_reserved + .globl _alignment_check,_page_fault + .globl ret_from_sys_call + +--- 84,90 ---- + .globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op + .globl _double_fault,_coprocessor_segment_overrun + .globl _invalid_TSS,_segment_not_present,_stack_segment +! .globl _general_protection,_reserved + .globl _alignment_check,_page_fault + .globl ret_from_sys_call + +*************** +*** 109,167 **** + movl $0x17,%edx; \ + mov %dx,%fs + +- #define ACK_FIRST(mask) \ +- inb $0x21,%al; \ +- jmp 1f; \ +- 1: jmp 1f; \ +- 1: orb $(mask),%al; \ +- outb %al,$0x21; \ +- jmp 1f; \ +- 1: jmp 1f; \ +- 1: movb $0x20,%al; \ +- outb %al,$0x20 +- +- #define ACK_SECOND(mask) \ +- inb $0xA1,%al; \ +- jmp 1f; \ +- 1: jmp 1f; \ +- 1: orb $(mask),%al; \ +- outb %al,$0xA1; \ +- jmp 1f; \ +- 1: jmp 1f; \ +- 1: movb $0x20,%al; \ +- outb %al,$0xA0 \ +- jmp 1f; \ +- 1: jmp 1f; \ +- 1: outb %al,$0x20 +- +- #define UNBLK_FIRST(mask) \ +- inb $0x21,%al; \ +- jmp 1f; \ +- 1: jmp 1f; \ +- 1: andb $~(mask),%al; \ +- outb %al,$0x21 +- +- #define UNBLK_SECOND(mask) \ +- inb $0xA1,%al; \ +- jmp 1f; \ +- 1: jmp 1f; \ +- 1: andb $~(mask),%al; \ +- outb %al,$0xA1 +- + .align 2 +- bad_sys_call: +- movl $-ENOSYS,EAX(%esp) +- jmp ret_from_sys_call +- .align 2 + reschedule: + pushl $ret_from_sys_call + jmp _schedule + .align 2 + _system_call: +! pushl %eax # save orig_eax + SAVE_ALL + cmpl _NR_syscalls,%eax +! jae bad_sys_call + call _sys_call_table(,%eax,4) + movl %eax,EAX(%esp) # save the return value + ret_from_sys_call: +--- 107,123 ---- + movl $0x17,%edx; \ + mov %dx,%fs + + .align 2 + reschedule: + pushl $ret_from_sys_call + jmp _schedule + .align 2 + _system_call: +! pushl %eax # save orig_eax + SAVE_ALL ++ movl $-ENOSYS,EAX(%esp) + cmpl _NR_syscalls,%eax +! jae ret_from_sys_call + call _sys_call_table(,%eax,4) + movl %eax,EAX(%esp) # save the return value + ret_from_sys_call: +*************** +*** 212,227 **** + iret + + .align 2 +- _irq13: +- pushl %eax +- xorb %al,%al +- outb %al,$0xF0 +- movb $0x20,%al +- outb %al,$0x20 +- jmp 1f +- 1: jmp 1f +- 1: outb %al,$0xA0 +- popl %eax + _coprocessor_error: + pushl $-1 # mark this as an int. + SAVE_ALL +--- 168,173 ---- +*** 0.96c.pl1/linux/kernel/ioport.c Tue Apr 21 19:24:55 1992 +--- linux/kernel/ioport.c Wed Jul 15 21:13:36 1992 +*************** +*** 92,94 **** +--- 92,121 ---- + } + return 0; + } ++ ++ unsigned int *stack; ++ ++ /* ++ * sys_iopl has to be used when you want to access the IO ports ++ * beyond the 0x3ff range: to get the full 65536 ports bitmapped ++ * you'd need 8kB of bitmaps/process, which is a bit excessive. ++ * ++ * Here we just change the eflags value on the stack: we allow ++ * only the super-user to do it. This depends on the stack-layout ++ * on system-call entry - see also fork() and the signal handling ++ * code. ++ */ ++ int sys_iopl(long ebx,long ecx,long edx, ++ long esi, long edi, long ebp, long eax, long ds, ++ long es, long fs, long gs, long orig_eax, ++ long eip,long cs,long eflags,long esp,long ss) ++ { ++ unsigned int level = ebx; ++ ++ if (level > 3) ++ return -EINVAL; ++ if (!suser()) ++ return -EPERM; ++ *(&eflags) = (eflags & 0xffffcfff) | (level << 12); ++ return 0; ++ } +*** 0.96c.pl1/linux/kernel/irq.c Sat Jul 18 22:28:57 1992 +--- linux/kernel/irq.c Thu Jul 16 12:32:26 1992 +*************** +*** 36,43 **** +--- 36,50 ---- + { NULL, 0, 0, NULL }, + }; + ++ void irq13(void); ++ + /* + * This builds up the IRQ handler stubs using some ugly macros in irq.h ++ * ++ * These macros create the low-level assembly IRQ routines that do all ++ * the operations that are needed to keep the AT interrupt-controller ++ * happy. They are also written to be fast - and to disable interrupts ++ * as little as humanly possible. + */ + BUILD_IRQ(FIRST,0,0x01) + BUILD_IRQ(FIRST,1,0x02) +*************** +*** 62,70 **** + * particular interrupt is disabled when this is called. + * + * The routine has to call the appropriate handler (disabling +! * interrupts if needed first), and then re-enable this interrupt- +! * line if the handler was ok. If no handler exists, the IRQ isn't +! * re-enabled. + * + * Note similarities on a very low level between this and the + * do_signal() function. Naturally this is simplified, but they +--- 69,77 ---- + * particular interrupt is disabled when this is called. + * + * The routine has to call the appropriate handler (disabling +! * interrupts if needed first). If no handler exists, we return +! * an error value, telling the low-level IRQ routines not to +! * re-enable this IRQ line. + * + * Note similarities on a very low level between this and the + * do_signal() function. Naturally this is simplified, but they +*************** +*** 73,94 **** + * (signal) number as argument, but the cpl value at the time of + * the interrupt. + */ +! void do_IRQ(int irq, struct pt_regs * regs) + { + struct sigaction * sa = irq + irq_sigaction; + void (*handler)(int); + + if (!(handler = sa->sa_handler)) +! return; + if (sa->sa_flags & SA_INTERRUPT) + cli(); + handler(regs->cs & 3); +- cli(); +- if (irq < 8) +- outb(inb_p(0x21) & ~(1<sa_handler)) +! return -1; /* the irq isn't re-enabled */ +! __asm__ __volatile__("movl %%esp,%0":"=r" (esp)); +! if (esp < 200+(unsigned long)(current+1)) { +! printk("Stack overflow on IRQ%d: shutting down\n",irq); +! return -1; +! } + if (sa->sa_flags & SA_INTERRUPT) + cli(); + handler(regs->cs & 3); + sti(); ++ return 0; /* re-enable the irq when returning */ + } + + int irqaction(unsigned int irq, struct sigaction * new) +*************** +*** 150,155 **** +--- 159,172 ---- + __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags)); + } + ++ extern void math_error(void); ++ ++ static void math_error_irq(int cpl) ++ { ++ outb(0,0xF0); ++ math_error(); ++ } ++ + void init_IRQ(void) + { + set_trap_gate(0x20,IRQ0_interrupt); +*************** +*** 161,167 **** + set_trap_gate(0x26,IRQ6_interrupt); + set_trap_gate(0x27,IRQ7_interrupt); + set_trap_gate(0x28,IRQ8_interrupt); +! set_trap_gate(0x29,IRQ10_interrupt); + set_trap_gate(0x2a,IRQ10_interrupt); + set_trap_gate(0x2b,IRQ11_interrupt); + set_trap_gate(0x2c,IRQ12_interrupt); +--- 178,184 ---- + set_trap_gate(0x26,IRQ6_interrupt); + set_trap_gate(0x27,IRQ7_interrupt); + set_trap_gate(0x28,IRQ8_interrupt); +! set_trap_gate(0x29,IRQ9_interrupt); + set_trap_gate(0x2a,IRQ10_interrupt); + set_trap_gate(0x2b,IRQ11_interrupt); + set_trap_gate(0x2c,IRQ12_interrupt); +*************** +*** 168,171 **** +--- 185,190 ---- + set_trap_gate(0x2d,IRQ13_interrupt); + set_trap_gate(0x2e,IRQ14_interrupt); + set_trap_gate(0x2f,IRQ15_interrupt); ++ if (request_irq(13,math_error_irq)) ++ printk("Unable to get IRQ13 for math-error handler\n"); + } +*** 0.96c.pl1/linux/kernel/ptrace.c Sat Jul 18 22:28:57 1992 +--- linux/kernel/ptrace.c Fri Jul 17 03:39:50 1992 +*************** +*** 240,246 **** + + if (child == current) + return -EPERM; +! if ((!current->dumpable || (current->uid != child->euid) || + (current->gid != child->egid)) && !suser()) + return -EPERM; + /* the same process cannot be attached many times */ +--- 240,246 ---- + + if (child == current) + return -EPERM; +! if ((!child->dumpable || (current->uid != child->euid) || + (current->gid != child->egid)) && !suser()) + return -EPERM; + /* the same process cannot be attached many times */ +*** 0.96c.pl1/linux/tools/build.c Tue May 26 19:40:55 1992 +--- linux/tools/build.c Thu Jul 16 00:40:25 1992 +*************** +*** 32,38 **** + #define MINIX_HEADER 32 + #define GCC_HEADER 1024 + +! #define SYS_SIZE 0x4000 + + #define DEFAULT_MAJOR_ROOT 0 + #define DEFAULT_MINOR_ROOT 0 +--- 32,38 ---- + #define MINIX_HEADER 32 + #define GCC_HEADER 1024 + +! #define SYS_SIZE 0x5000 + + #define DEFAULT_MAJOR_ROOT 0 + #define DEFAULT_MINOR_ROOT 0 +*** 0.96c.pl1/linux/include/sys/user.h Wed Jun 10 15:24:39 1992 +--- linux/include/sys/user.h Fri Jul 17 04:30:30 1992 +*************** +*** 62,67 **** +--- 62,68 ---- + struct pt_regs * u_ar0; /* Used by gdb to help find the values for */ + /* the registers. */ + struct user_i387_struct* u_fpstate; /* Math Co-processor pointer. */ ++ unsigned long magic; /* To uniquely identify a core file */ + }; + #define NBPG 4096 + #define UPAGES 1 +*** 0.96c.pl1/linux/include/a.out.h Fri Apr 24 18:26:25 1992 +--- linux/include/a.out.h Fri Jul 17 04:30:30 1992 +*************** +*** 72,77 **** +--- 72,79 ---- + /* Code indicating demand-paged executable. */ + #define ZMAGIC 0413 + ++ /* Code indicating core file. */ ++ #define CMAGIC 0421 + #if !defined (N_BADMAG) + #define N_BADMAG(x) \ + (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \ +*** 0.96c.pl1/linux/include/linux/sched.h Sat Jul 18 22:29:05 1992 +--- linux/include/linux/sched.h Wed Jul 15 16:46:48 1992 +*************** +*** 128,136 **** + */ + struct task_struct *p_opptr,*p_pptr, *p_cptr, *p_ysptr, *p_osptr; + /* +! * sleep makes a singly linked list with this. + */ +! struct task_struct *next_wait; + unsigned short uid,euid,suid; + unsigned short gid,egid,sgid; + unsigned long timeout; +--- 128,137 ---- + */ + struct task_struct *p_opptr,*p_pptr, *p_cptr, *p_ysptr, *p_osptr; + /* +! * For ease of programming... Normal sleeps don't need to +! * keep track of a wait-queue: every task has an entry of it's own + */ +! struct wait_queue wait; + unsigned short uid,euid,suid; + unsigned short gid,egid,sgid; + unsigned long timeout; +*************** +*** 185,191 **** + /* ec,brk... */ 0,0,0,0,0,0,0, \ + /* pid etc.. */ 0,0,0,0, \ + /* suppl grps*/ {NOGROUP,}, \ +! /* proc links*/ &init_task.task,&init_task.task,NULL,NULL,NULL,NULL, \ + /* uid etc */ 0,0,0,0,0,0, \ + /* timeout */ 0,0,0,0,0,0,0,0,0,0,0,0, \ + /* min_flt */ 0,0,0,0, \ +--- 186,193 ---- + /* ec,brk... */ 0,0,0,0,0,0,0, \ + /* pid etc.. */ 0,0,0,0, \ + /* suppl grps*/ {NOGROUP,}, \ +! /* proc links*/ &init_task.task,&init_task.task,NULL,NULL,NULL, \ +! /* wait queue*/ {&init_task.task,NULL}, \ + /* uid etc */ 0,0,0,0,0,0, \ + /* timeout */ 0,0,0,0,0,0,0,0,0,0,0,0, \ + /* min_flt */ 0,0,0,0, \ +*************** +*** 222,231 **** + #define CURRENT_TIME (startup_time+(jiffies+jiffies_offset)/HZ) + + extern void add_timer(long jiffies, void (*fn)(void)); +! extern void sleep_on(struct task_struct ** p); + extern int send_sig(long sig,struct task_struct * p,int priv); +- extern void interruptible_sleep_on(struct task_struct ** p); +- extern void wake_up(struct task_struct ** p); + extern int in_group_p(gid_t grp); + + extern int request_irq(unsigned int irq,void (*handler)(int)); +--- 224,236 ---- + #define CURRENT_TIME (startup_time+(jiffies+jiffies_offset)/HZ) + + extern void add_timer(long jiffies, void (*fn)(void)); +! +! extern void sleep_on(struct wait_queue ** p); +! extern void interruptible_sleep_on(struct wait_queue ** p); +! extern void wake_up(struct wait_queue ** p); +! extern void wake_one_task(struct task_struct * p); +! + extern int send_sig(long sig,struct task_struct * p,int priv); + extern int in_group_p(gid_t grp); + + extern int request_irq(unsigned int irq,void (*handler)(int)); +*************** +*** 259,266 **** +--- 264,273 ---- + __asm__("cmpl %%ecx,_current\n\t" \ + "je 1f\n\t" \ + "movw %%dx,%1\n\t" \ ++ "cli\n\t" \ + "xchgl %%ecx,_current\n\t" \ + "ljmp %0\n\t" \ ++ "sti\n\t" \ + "cmpl %%ecx,_last_task_used_math\n\t" \ + "jne 1f\n\t" \ + "clts\n" \ +*************** +*** 297,302 **** +--- 304,354 ---- + + #define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base ) + #define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 ) ++ ++ extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wait) ++ { ++ unsigned long flags; ++ struct wait_queue * tmp; ++ ++ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags)); ++ wait->next = *p; ++ tmp = wait; ++ while (tmp->next) ++ if ((tmp = tmp->next)->next == *p) ++ break; ++ *p = tmp->next = wait; ++ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags)); ++ } ++ ++ extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait) ++ { ++ unsigned long flags; ++ struct wait_queue * tmp; ++ ++ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags)); ++ if (*p == wait) ++ if ((*p = wait->next) == wait) ++ *p = NULL; ++ tmp = wait; ++ while (tmp && tmp->next != wait) ++ tmp = tmp->next; ++ if (tmp) ++ tmp->next = wait->next; ++ wait->next = NULL; ++ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags)); ++ } ++ ++ extern inline void select_wait(struct wait_queue ** wait_address, select_table * p) ++ { ++ struct select_table_entry * entry = p->entry + p->nr; ++ ++ if (!wait_address) ++ return; ++ entry->wait_address = wait_address; ++ entry->wait.task = current; ++ add_wait_queue(wait_address,&entry->wait); ++ p->nr++; ++ } + + static unsigned long inline _get_base(char * addr) + { +*** 0.96c.pl1/linux/include/linux/sys.h Wed Jun 17 05:25:11 1992 +--- linux/include/linux/sys.h Wed Jul 15 21:01:13 1992 +*************** +*** 112,117 **** +--- 112,118 ---- + extern int sys_newlstat(); + extern int sys_newfstat(); + extern int sys_newuname(); ++ extern int sys_iopl(); + + 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, +*************** +*** 133,139 **** + sys_truncate, sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, + sys_setpriority, sys_profil, sys_statfs, sys_fstatfs, sys_ioperm, + sys_socketcall, sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, +! sys_newlstat, sys_newfstat, sys_newuname }; + + /* So we don't have to do any more manual updating.... */ + int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); +--- 134,140 ---- + sys_truncate, sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, + sys_setpriority, sys_profil, sys_statfs, sys_fstatfs, sys_ioperm, + sys_socketcall, sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, +! sys_newlstat, sys_newfstat, sys_newuname, sys_iopl }; + + /* So we don't have to do any more manual updating.... */ + int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); +*** 0.96c.pl1/linux/include/linux/tty.h Sat Jul 18 22:29:05 1992 +--- linux/include/linux/tty.h Wed Jul 15 15:51:40 1992 +*************** +*** 30,36 **** + unsigned long data; + unsigned long head; + unsigned long tail; +! struct task_struct * proc_list; + unsigned char buf[TTY_BUF_SIZE]; + }; + +--- 30,36 ---- + unsigned long data; + unsigned long head; + unsigned long tail; +! struct wait_queue * proc_list; + unsigned char buf[TTY_BUF_SIZE]; + }; + +*************** +*** 126,136 **** + /* + * so that interrupts won't be able to mess up the + * queues, copy_to_cooked must be atomic with repect +! * to itself, as must tty->write. These are the flag bits. + */ +! #define TTY_WRITE_BUSY 1 +! #define TTY_READ_BUSY 2 +! #define TTY_CR_PENDING 4 + + #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty)) + #define TTY_READ_FLUSH(tty) tty_read_flush((tty)) +--- 126,161 ---- + /* + * so that interrupts won't be able to mess up the + * queues, copy_to_cooked must be atomic with repect +! * to itself, as must tty->write. These are the flag +! * bit-numbers. Use the set_bit() and clear_bit() +! * macros to make it all atomic. + */ +! #define TTY_WRITE_BUSY 0 +! #define TTY_READ_BUSY 1 +! #define TTY_CR_PENDING 2 +! +! /* +! * These have to be done with inline assembly: that way the bit-setting +! * is guaranteed to be atomic. Both set_bit and clear_bit return 0 +! * if the bit-setting went ok, != 0 if the bit already was set/cleared. +! */ +! extern inline int set_bit(int nr,int * addr) +! { +! char ok; +! +! __asm__ __volatile__("btsl %1,%2\n\tsetb %0": +! "=q" (ok):"r" (nr),"m" (*(addr))); +! return ok; +! } +! +! extern inline int clear_bit(int nr, int * addr) +! { +! char ok; +! +! __asm__ __volatile__("btrl %1,%2\n\tsetnb %0": +! "=q" (ok):"r" (nr),"m" (*(addr))); +! return ok; +! } + + #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty)) + #define TTY_READ_FLUSH(tty) tty_read_flush((tty)) +*** 0.96c.pl1/linux/include/linux/fs.h Sat Jul 18 22:29:05 1992 +--- linux/include/linux/fs.h Wed Jul 15 15:19:53 1992 +*************** +*** 6,11 **** +--- 6,14 ---- + #ifndef _FS_H + #define _FS_H + ++ #include ++ #include ++ + #include + #include + #include +*************** +*** 41,57 **** + #define MAJOR(a) (((unsigned)(a))>>8) + #define MINOR(a) ((a)&0xff) + +- #define NR_OPEN 32 +- #define NR_INODE 128 +- #define NR_FILE 128 +- #define NR_SUPER 8 +- #define NR_HASH 307 +- #define NR_BUFFERS nr_buffers +- #define BLOCK_SIZE 1024 +- #define BLOCK_SIZE_BITS 10 +- #define MAX_CHRDEV 16 +- #define MAX_BLKDEV 16 +- + #ifndef NULL + #define NULL ((void *) 0) + #endif +--- 44,49 ---- +*************** +*** 78,83 **** +--- 70,76 ---- + #define MS_NOSUID 2 /* ignore suid and sgid bits */ + #define MS_NODEV 4 /* disallow access to device special files */ + #define MS_NOEXEC 8 /* disallow program execution */ ++ #define MS_SYNC 16 /* writes are synced at once */ + + /* + * Note that read-only etc flags are inode-specific: setting some file-system +*************** +*** 89,94 **** +--- 82,88 ---- + #define IS_NOSUID(inode) ((inode)->i_flags & MS_NOSUID) + #define IS_NODEV(inode) ((inode)->i_flags & MS_NODEV) + #define IS_NOEXEC(inode) ((inode)->i_flags & MS_NOEXEC) ++ #define IS_SYNC(inode) ((inode)->i_flags & MS_SYNC) + + /* the read-only stuff doesn't really belong here, but any other place is + probably as bad and I don't want to create yet another include file. */ +*************** +*** 108,114 **** + 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; +--- 102,108 ---- + 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 wait_queue * b_wait; + struct buffer_head * b_prev; + struct buffer_head * b_next; + struct buffer_head * b_prev_free; +*************** +*** 131,138 **** + unsigned long i_data[16]; + struct inode_operations * i_op; + struct super_block * i_sb; +! struct task_struct * i_wait; +! struct task_struct * i_wait2; /* for pipes */ + unsigned short i_count; + unsigned short i_flags; + unsigned char i_lock; +--- 125,132 ---- + unsigned long i_data[16]; + struct inode_operations * i_op; + struct super_block * i_sb; +! struct wait_queue * i_wait; +! struct wait_queue * i_wait2; /* for pipes */ + unsigned short i_count; + unsigned short i_flags; + unsigned char i_lock; +*************** +*** 154,171 **** + off_t f_pos; + }; + +- typedef struct { +- struct task_struct * old_task; +- struct task_struct ** wait_address; +- } wait_entry; +- +- typedef struct select_table_struct { +- int nr, woken; +- struct task_struct * current; +- struct select_table_struct * next_table; +- wait_entry entry[NR_OPEN*3]; +- } select_table; +- + struct super_block { + unsigned long s_ninodes; + unsigned long s_nzones; +--- 148,153 ---- +*************** +*** 182,188 **** + struct inode * s_covered; + struct inode * s_mounted; + unsigned long s_time; +! struct task_struct * s_wait; + unsigned char s_lock; + unsigned char s_rd_only; + unsigned char s_dirt; +--- 164,170 ---- + struct inode * s_covered; + struct inode * s_mounted; + unsigned long s_time; +! struct wait_queue * s_wait; + unsigned char s_lock; + unsigned char s_rd_only; + unsigned char s_dirt; +*** 0.96c.pl1/linux/include/linux/string.h Thu Jul 2 01:06:49 1992 +--- linux/include/linux/string.h Wed Jul 15 06:58:53 1992 +*************** +*** 273,279 **** + + 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" +--- 273,279 ---- + + extern inline char * strtok(char * s,const char * ct) + { +! register char * __res; + __asm__("testl %1,%1\n\t" + "jne 1f\n\t" + "testl %0,%0\n\t" +*************** +*** 324,335 **** + "jne 8f\n\t" + "movl %0,%1\n" + "8:" +! #if __GNUC__ == 2 +! :"=r" (__res) +! #else +! :"=b" (__res) +! #endif +! ,"=S" (___strtok) + :"0" (___strtok),"1" (s),"g" (ct) + :"ax","cx","dx","di"); + return __res; +--- 324,330 ---- + "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; +*** 0.96c.pl1/linux/include/linux/unistd.h Wed Jun 17 14:41:25 1992 +--- linux/include/linux/unistd.h Wed Jul 15 20:58:31 1992 +*************** +*** 116,121 **** +--- 116,122 ---- + #define __NR_lstat 107 + #define __NR_fstat 108 + #define __NR_uname 109 ++ #define __NR_iopl 110 + + extern int errno; + +*** 0.96c.pl1/linux/include/linux/fcntl.h Thu Jul 2 00:56:39 1992 +--- linux/include/linux/fcntl.h Tue Jul 14 16:04:33 1992 +*************** +*** 3,20 **** + + #include + +! /* open/fcntl - NOCTTY, NDELAY isn't implemented yet */ +! #define O_ACCMODE 00003 +! #define O_RDONLY 00 +! #define O_WRONLY 01 +! #define O_RDWR 02 +! #define O_CREAT 00100 /* not fcntl */ +! #define O_EXCL 00200 /* not fcntl */ +! #define O_NOCTTY 00400 /* not fcntl */ +! #define O_TRUNC 01000 /* not fcntl */ +! #define O_APPEND 02000 +! #define O_NONBLOCK 04000 + #define O_NDELAY O_NONBLOCK + + /* Defines for fcntl-commands. Note that currently + * locking isn't supported, and other things aren't really +--- 3,21 ---- + + #include + +! /* open/fcntl - O_SYNC isn't implemented yet */ +! #define O_ACCMODE 0003 +! #define O_RDONLY 00 +! #define O_WRONLY 01 +! #define O_RDWR 02 +! #define O_CREAT 0100 /* not fcntl */ +! #define O_EXCL 0200 /* not fcntl */ +! #define O_NOCTTY 0400 /* not fcntl */ +! #define O_TRUNC 01000 /* not fcntl */ +! #define O_APPEND 02000 +! #define O_NONBLOCK 04000 + #define O_NDELAY O_NONBLOCK ++ #define O_SYNC 010000 + + /* Defines for fcntl-commands. Note that currently + * locking isn't supported, and other things aren't really +*** /dev/null Sat Jul 18 22:26:09 1992 +--- linux/include/linux/mouse.h Wed Jul 15 04:15:55 1992 +*************** +*** 0 **** +--- 1,61 ---- ++ /* ++ * linux/include/linux/mouse.h: header file for Logitech Bus Mouse driver ++ * by James Banks ++ * ++ * based on information gleamed from various mouse drivers on the net ++ * ++ * Heavily modified by David giller (rafetmad@oxy.edu) ++ * ++ * Minor modifications for Linux 0.96c-pl1 by Nathan Laredo ++ * gt7080a@prism.gatech.edu (13JUL92) ++ * ++ */ ++ ++ #ifndef _MOUSE_H ++ #define _MOUSE_H ++ ++ #define MOUSE_IRQ 5 ++ ++ #define MSE_DATA_PORT 0x23c ++ #define MSE_SIGNATURE_PORT 0x23d ++ #define MSE_CONTROL_PORT 0x23e ++ #define MSE_INTERRUPT_PORT 0x23e ++ #define MSE_CONFIG_PORT 0x23f ++ ++ #define MSE_ENABLE_INTERRUPTS 0x00 ++ #define MSE_DISABLE_INTERRUPTS 0x10 ++ ++ #define MSE_READ_X_LOW 0x80 ++ #define MSE_READ_X_HIGH 0xa0 ++ #define MSE_READ_Y_LOW 0xc0 ++ #define MSE_READ_Y_HIGH 0xe0 ++ ++ /* Magic number used to check if the mouse exists */ ++ #define MSE_CONFIG_BYTE 0x91 ++ #define MSE_DEFAULT_MODE 0x90 ++ #define MSE_SIGNATURE_BYTE 0xa5 ++ ++ /* useful macros */ ++ ++ #define MSE_INT_OFF() outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT) ++ #define MSE_INT_ON() outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT) ++ ++ struct mouse_status ++ { ++ char buttons; ++ char latch_buttons; ++ int dx; ++ int dy; ++ ++ int present; ++ int ready; ++ int active; ++ ++ struct inode *inode; ++ }; ++ ++ /* Function Prototypes */ ++ extern long mouse_init(long); ++ ++ #endif ++ +*** /dev/null Sat Jul 18 22:26:09 1992 +--- linux/include/linux/msdos_fs.h Thu Jul 16 00:35:11 1992 +*************** +*** 0 **** +--- 1,190 ---- ++ /* ++ * The MS-DOS filesystem constants/structures ++ */ ++ ++ #ifndef _MSDOS_FS_H ++ #define _MSDOS_FS_H ++ ++ #include ++ #include ++ ++ #define MSDOS_ROOT_INO 1 ++ #define SECTOR_SIZE 512 /* sector size (bytes) */ ++ #define SECTOR_BITS 9 /* log2(SECTOR_SIZE) */ ++ #define MSDOS_DPB (MSDOS_DPS*2) /* dir entries per block */ ++ #define MSDOS_DPB_BITS 5 /* log2(MSDOS_DPB) */ ++ #define MSDOS_DPS (SECTOR_SIZE/sizeof(struct msdos_dir_entry)) ++ #define MSDOS_DPS_BITS 4 /* log2(MSDOS_DPS) */ ++ #define MSDOS_DIR_BITS 5 /* log2(sizeof(struct msdos_dir_entry)) */ ++ ++ #define MSDOS_SUPER_MAGIC 0x4d44 /* MD */ ++ ++ #define FAT_CACHE 8 /* FAT cache size */ ++ ++ #define ATTR_RO 1 /* read-only */ ++ #define ATTR_HIDDEN 2 /* hidden */ ++ #define ATTR_SYS 4 /* system */ ++ #define ATTR_VOLUME 8 /* volume label */ ++ #define ATTR_DIR 16 /* directory */ ++ #define ATTR_ARCH 32 /* archived */ ++ ++ #define ATTR_NONE 0 /* no attribute bits */ ++ #define ATTR_UNUSED (ATTR_VOLUME | ATTR_ARCH | ATTR_SYS) ++ /* attribute bits that are copied "as is" */ ++ ++ #define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */ ++ ++ #define D_START 0 /* i_data[0]: first cluster or 0 */ ++ #define D_ATTRS 1 /* i_data[1]: unused attribute bits */ ++ #define D_BUSY 2 /* i_data[2]: file is either deleted but still open, or ++ inconsistent (mkdir) */ ++ #define D_DEPEND 3 /* i_data[3]: pointer to inode that depends on the current ++ inode */ ++ #define D_OLD 4 /* i_data[4]: pointer to the old inode this inode depends ++ on */ ++ #define D_BINARY 5 /* i_data[5]: file contains non-text data */ ++ ++ #define SET_DIRTY(i) (i)->i_dirt = (i)->i_data[D_DIRT] = 1 ++ ++ #define MSDOS_SB(s) ((struct msdos_sb_info *) s) ++ ++ #define MSDOS_NAME 11 /* maximum name length */ ++ #define MSDOS_DOT ". " /* ".", padded to MSDOS_NAME chars */ ++ #define MSDOS_DOTDOT ".. " /* "..", padded to MSDOS_NAME chars */ ++ ++ #define MSDOS_FAT12 4086 /* maximum number of clusters in a 12 bit FAT */ ++ ++ struct msdos_boot_sector { ++ char ignored[13]; ++ unsigned char cluster_size; /* sectors/cluster */ ++ unsigned short reserved; /* reserved sectors */ ++ unsigned char fats; /* number of FATs */ ++ unsigned char dir_entries[2];/* root directory entries */ ++ unsigned char sectors[2]; /* number of sectors */ ++ unsigned char media; /* media code (unused) */ ++ unsigned short fat_length; /* sectors/FAT */ ++ unsigned short secs_track; /* sectors per track (unused) */ ++ unsigned short heads; /* number of heads (unused) */ ++ unsigned long hidden; /* hidden sectors (unused) */ ++ unsigned long total_sect; /* number of sectors (if sectors == 0) */ ++ }; ++ ++ struct msdos_sb_info { /* space in struct super_block is 28 bytes */ ++ unsigned short cluster_size; /* sectors/cluster */ ++ unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */ ++ unsigned short fat_start,fat_length; /* FAT start & length (sec.) */ ++ unsigned short dir_start,dir_entries; /* root dir start & entries */ ++ unsigned short data_start; /* first data sector */ ++ unsigned long clusters; /* number of clusters */ ++ uid_t fs_uid; ++ gid_t fs_gid; ++ unsigned short fs_umask; ++ unsigned char name_check; /* r = releaxed, n = normal, s = strict */ ++ unsigned char conversion; /* b = binary, t = text, a = auto */ ++ }; /* 28 bytes */ ++ ++ struct msdos_dir_entry { ++ char name[8],ext[3]; /* name and extension */ ++ unsigned char attr; /* attribute bits */ ++ char unused[10]; ++ unsigned short time,date,start; /* time, date and first cluster */ ++ unsigned long size; /* file size (in bytes) */ ++ }; ++ ++ struct fat_cache { ++ int device; /* device number. 0 means unused. */ ++ int ino; /* inode number. */ ++ int file_cluster; /* cluster number in the file. */ ++ int disk_cluster; /* cluster number on disk. */ ++ struct fat_cache *next; /* next cache entry */ ++ }; ++ ++ /* Determine whether this FS has kB-aligned data. */ ++ ++ #define MSDOS_CAN_BMAP(mib) (!(((mib)->cluster_size & 1) || \ ++ ((mib)->data_start & 1))) ++ ++ /* Convert attribute bits and a mask to the UNIX mode. */ ++ ++ #define MSDOS_MKMODE(a,m) (m & (a & ATTR_RO ? 0444 : (a & ATTR_HIDDEN ? 0 : \ ++ 0777))) ++ ++ /* Convert the UNIX mode to MS-DOS attribute bits. */ ++ ++ #define MSDOS_MKATTR(m) (!(m & 0600) ? ATTR_HIDDEN : ((m & 0600) == 0400 ? \ ++ ATTR_RO : ATTR_NONE)) ++ ++ ++ static inline struct buffer_head *msdos_sread(int dev,int sector,void **start) ++ { ++ struct buffer_head *bh; ++ ++ if (!(bh = bread(dev,sector >> 1))) return NULL; ++ *start = bh->b_data+((sector & 1) << SECTOR_BITS); ++ return bh; ++ } ++ ++ ++ /* misc.c */ ++ ++ extern int is_binary(char conversion,char *extension); ++ extern void lock_creation(void); ++ extern void unlock_creation(void); ++ extern int msdos_add_cluster(struct inode *inode); ++ extern int date_dos2unix(unsigned short time,unsigned short date); ++ extern void date_unix2dos(int unix_date,unsigned short *time, ++ unsigned short *date); ++ extern int msdos_get_entry(struct inode *dir,int *pos,struct buffer_head **bh, ++ struct msdos_dir_entry **de); ++ extern int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh, ++ struct msdos_dir_entry **res_de,int *ino); ++ extern int msdos_parent_ino(struct inode *dir,int locked); ++ ++ /* fat.c */ ++ ++ extern int fat_access(struct super_block *sb,int this,int new_value); ++ extern int msdos_smap(struct inode *inode,int sector); ++ extern int fat_free(struct inode *inode,int skip); ++ extern void cache_init(void); ++ void cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu); ++ void cache_add(struct inode *inode,int f_clu,int d_clu); ++ void cache_inval_inode(struct inode *inode); ++ void cache_inval_dev(int device); ++ int get_cluster(struct inode *inode,int cluster); ++ ++ /* namei.c */ ++ ++ extern int msdos_lookup(struct inode *dir,const char *name,int len, ++ struct inode **result); ++ extern int msdos_create(struct inode *dir,const char *name,int len,int mode, ++ struct inode **result); ++ extern int msdos_mkdir(struct inode *dir,const char *name,int len,int mode); ++ extern int msdos_rmdir(struct inode *dir,const char *name,int len); ++ extern int msdos_unlink(struct inode *dir,const char *name,int len); ++ extern int msdos_rename(struct inode *old_dir,const char *old_name,int old_len, ++ struct inode *new_dir,const char *new_name,int new_len); ++ ++ /* inode.c */ ++ ++ extern void msdos_put_inode(struct inode *inode); ++ extern void msdos_put_super(struct super_block *sb); ++ extern struct super_block *msdos_read_super(struct super_block *s,void *data); ++ extern void msdos_statfs(struct super_block *sb,struct statfs *buf); ++ extern int msdos_bmap(struct inode *inode,int block); ++ extern void msdos_read_inode(struct inode *inode); ++ extern void msdos_write_inode(struct inode *inode); ++ ++ /* dir.c */ ++ ++ extern struct file_operations msdos_dir_operations; ++ extern struct inode_operations msdos_dir_inode_operations; ++ ++ /* file.c */ ++ ++ extern struct file_operations msdos_file_operations; ++ extern struct inode_operations msdos_file_inode_operations; ++ extern struct inode_operations msdos_file_inode_operations_no_bmap; ++ ++ extern void msdos_truncate(struct inode *inode); ++ ++ #endif +*** /dev/null Sat Jul 18 22:26:09 1992 +--- linux/include/linux/wait.h Wed Jul 15 16:46:10 1992 +*************** +*** 0 **** +--- 1,19 ---- ++ #ifndef _LINUX_WAIT_H ++ #define _LINUX_WAIT_H ++ ++ #include ++ ++ struct wait_queue { ++ struct task_struct * task; ++ struct wait_queue * next; ++ }; ++ ++ typedef struct select_table_struct { ++ int nr; ++ struct select_table_entry { ++ struct wait_queue wait; ++ struct wait_queue ** wait_address; ++ } entry[NR_OPEN*3]; ++ } select_table; ++ ++ #endif +*** /dev/null Sat Jul 18 22:26:09 1992 +--- linux/include/linux/limits.h Wed Jul 15 15:19:24 1992 +*************** +*** 0 **** +--- 1,16 ---- ++ #ifndef _LINUX_LIMITS_H ++ #define _LINUX_LIMITS_H ++ ++ #define NR_OPEN 32 ++ #define NR_INODE 128 ++ #define NR_FILE 128 ++ #define NR_SUPER 8 ++ #define NR_HASH 307 ++ #define NR_BUFFERS nr_buffers ++ #define BLOCK_SIZE 1024 ++ #define BLOCK_SIZE_BITS 10 ++ #define MAX_CHRDEV 16 ++ #define MAX_BLKDEV 16 ++ ++ ++ #endif +*** 0.96c.pl1/linux/include/asm/io.h Tue Jun 2 12:25:20 1992 +--- linux/include/asm/io.h Tue Jul 14 05:15:21 1992 +*************** +*** 11,23 **** + + extern void inline outb(char value, unsigned short port) + { +! __asm__ volatile ("outb %0,%1" + ::"a" ((char) value),"d" ((unsigned short) port)); + } + + extern void inline outb_p(char value, unsigned short port) + { +! __asm__ volatile ("outb %0,%1\n\t" + #ifdef REALLY_SLOW_IO + "outb %0,$0x80\n\t" + "outb %0,$0x80\n\t" +--- 11,23 ---- + + extern void inline outb(char value, unsigned short port) + { +! __asm__ __volatile__ ("outb %0,%1" + ::"a" ((char) value),"d" ((unsigned short) port)); + } + + extern void inline outb_p(char value, unsigned short port) + { +! __asm__ __volatile__ ("outb %0,%1\n\t" + #ifdef REALLY_SLOW_IO + "outb %0,$0x80\n\t" + "outb %0,$0x80\n\t" +*************** +*** 30,36 **** + extern unsigned char inline inb(unsigned short port) + { + unsigned char _v; +! __asm__ volatile ("inb %1,%0" + :"=a" (_v):"d" ((unsigned short) port)); + return _v; + } +--- 30,36 ---- + extern unsigned char inline inb(unsigned short port) + { + unsigned char _v; +! __asm__ __volatile__ ("inb %1,%0" + :"=a" (_v):"d" ((unsigned short) port)); + return _v; + } +*************** +*** 38,44 **** + extern unsigned char inline inb_p(unsigned short port) + { + unsigned char _v; +! __asm__ volatile ("inb %1,%0\n\t" + #ifdef REALLY_SLOW_IO + "outb %0,$0x80\n\t" + "outb %0,$0x80\n\t" +--- 38,44 ---- + extern unsigned char inline inb_p(unsigned short port) + { + unsigned char _v; +! __asm__ __volatile__ ("inb %1,%0\n\t" + #ifdef REALLY_SLOW_IO + "outb %0,$0x80\n\t" + "outb %0,$0x80\n\t" +*** 0.96c.pl1/linux/include/asm/memory.h Fri Apr 24 18:26:25 1992 +--- linux/include/asm/memory.h Tue Jul 14 05:15:21 1992 +*************** +*** 7,13 **** + */ + #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; \ +--- 7,13 ---- + */ + #define memcpy(dest,src,n) ({ \ + void * _res = dest; \ +! __asm__ __volatile__ ("cld;rep;movsb" \ + ::"D" ((long)(_res)),"S" ((long)(src)),"c" ((long) (n)) \ + :"di","si","cx"); \ + _res; \ +*** 0.96c.pl1/linux/include/asm/system.h Fri Apr 24 18:26:25 1992 +--- linux/include/asm/system.h Tue Jul 14 05:13:01 1992 +*************** +*** 1,5 **** + #define move_to_user_mode() \ +! __asm__ ("movl %%esp,%%eax\n\t" \ + "pushl $0x17\n\t" \ + "pushl %%eax\n\t" \ + "pushfl\n\t" \ +--- 1,5 ---- + #define move_to_user_mode() \ +! __asm__ __volatile__ ("movl %%esp,%%eax\n\t" \ + "pushl $0x17\n\t" \ + "pushl %%eax\n\t" \ + "pushfl\n\t" \ +*************** +*** 13,26 **** + "mov %%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" \ +--- 13,26 ---- + "mov %%ax,%%gs" \ + :::"ax") + +! #define sti() __asm__ __volatile__ ("sti"::) +! #define cli() __asm__ __volatile__ ("cli"::) +! #define nop() __asm__ __volatile__ ("nop"::) + +! #define iret() __asm__ __volatile__ ("iret"::) + + #define _set_gate(gate_addr,type,dpl,addr) \ +! __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ + "movw %0,%%dx\n\t" \ + "movl %%eax,%1\n\t" \ + "movl %%edx,%2" \ +*************** +*** 50,56 **** + ((limit) & 0x0ffff); } + + #define _set_tssldt_desc(n,addr,type) \ +! __asm__ ("movw $232,%1\n\t" \ + "movw %%ax,%2\n\t" \ + "rorl $16,%%eax\n\t" \ + "movb %%al,%3\n\t" \ +--- 50,56 ---- + ((limit) & 0x0ffff); } + + #define _set_tssldt_desc(n,addr,type) \ +! __asm__ __volatile__ ("movw $232,%1\n\t" \ + "movw %%ax,%2\n\t" \ + "rorl $16,%%eax\n\t" \ + "movb %%al,%3\n\t" \ +*** 0.96c.pl1/linux/include/asm/segment.h Fri Apr 24 18:26:25 1992 +--- linux/include/asm/segment.h Tue Jul 14 05:15:21 1992 +*************** +*** 94,99 **** + + extern inline void set_fs(unsigned long val) + { +! __asm__("mov %0,%%fs"::"r" ((unsigned short) val)); + } + +--- 94,99 ---- + + extern inline void set_fs(unsigned long val) + { +! __asm__ __volatile__("mov %0,%%fs"::"r" ((unsigned short) val)); + } + +*** 0.96c.pl1/linux/include/asm/irq.h Sat Jul 18 22:29:14 1992 +--- linux/include/asm/irq.h Tue Jul 14 15:22:18 1992 +*************** +*** 46,56 **** + "jmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:\tmovb $0x20,%al\n\t" \ +! "outb %al,$0xA0" \ + "jmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:\toutb %al,$0x20\n\t" + + #define IRQ_NAME2(nr) nr##_interrupt() + #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) + +--- 46,70 ---- + "jmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:\tmovb $0x20,%al\n\t" \ +! "outb %al,$0xA0\n\t" \ + "jmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:\toutb %al,$0x20\n\t" + ++ #define UNBLK_FIRST(mask) \ ++ "inb $0x21,%al\n\t" \ ++ "jmp 1f\n" \ ++ "1:\tjmp 1f\n" \ ++ "1:\tandb $~(" #mask "),%al\n\t" \ ++ "outb %al,$0x21\n\t" ++ ++ #define UNBLK_SECOND(mask) \ ++ "inb $0xA1,%al\n\t" \ ++ "jmp 1f\n" \ ++ "1:\tjmp 1f\n" \ ++ "1:\tandb $~(" #mask "),%al\n\t" \ ++ "outb %al,$0xA1\n\t" ++ + #define IRQ_NAME2(nr) nr##_interrupt() + #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) + +*************** +*** 70,75 **** +--- 84,94 ---- + "pushl $" #nr "\n\t" \ + "call _do_IRQ\n\t" \ + "addl $8,%esp\n\t" \ ++ "testl %eax,%eax\n\t" \ ++ "jne ret_from_sys_call\n\t" \ ++ "cli\n\t" \ ++ UNBLK_##chip(mask) \ ++ "sti\n\t" \ + "jmp ret_from_sys_call"); + + #endif +*** 0.96c.pl1/linux/net/kern_sock.h Sat May 2 22:25:46 1992 +--- linux/net/kern_sock.h Wed Jul 15 16:09:48 1992 +*************** +*** 33,39 **** + struct socket *conn; /* server socket connected to */ + struct socket *iconn; /* incomplete client connections */ + struct socket *next; +! struct task_struct **wait; /* ptr to place to wait on */ + void *dummy; + }; + +--- 33,39 ---- + struct socket *conn; /* server socket connected to */ + struct socket *iconn; /* incomplete client connections */ + struct socket *next; +! struct wait_queue **wait; /* ptr to place to wait on */ + void *dummy; + }; + +*************** +*** 52,58 **** + int *usockaddr_len, int peer); + int (*read)(struct socket *sock, char *ubuf, int size, int nonblock); + int (*write)(struct socket *sock, char *ubuf, int size, int nonblock); +! int (*select)(struct socket *sock, int which); + int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg); + }; + +--- 52,58 ---- + int *usockaddr_len, int peer); + int (*read)(struct socket *sock, char *ubuf, int size, int nonblock); + int (*write)(struct socket *sock, char *ubuf, int size, int nonblock); +! int (*select)(struct socket *sock, int sel_type, select_table * wait); + int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg); + }; + +*** 0.96c.pl1/linux/net/socket.c Thu Jul 2 00:48:29 1992 +--- linux/net/socket.c Wed Jul 15 16:09:14 1992 +*************** +*** 44,51 **** + static int sock_readdir(struct inode *inode, struct file *file, + struct dirent *dirent, int count); + static void sock_close(struct inode *inode, struct file *file); +! /*static*/ int sock_select(struct inode *inode, struct file *file, int which, +! select_table *seltable); + static int sock_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned int arg); + +--- 44,50 ---- + static int sock_readdir(struct inode *inode, struct file *file, + struct dirent *dirent, int count); + static void sock_close(struct inode *inode, struct file *file); +! static int sock_select(struct inode *inode, struct file *file, int which, select_table *seltable); + static int sock_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned int arg); + +*************** +*** 64,70 **** + + static struct socket sockets[NSOCKETS]; + #define last_socket (sockets + NSOCKETS - 1) +! static struct task_struct *socket_wait_free = NULL; + + /* + * obtains the first available file descriptor and sets it up for use +--- 63,69 ---- + + static struct socket sockets[NSOCKETS]; + #define last_socket (sockets + NSOCKETS - 1) +! static struct wait_queue *socket_wait_free = NULL; + + /* + * obtains the first available file descriptor and sets it up for use +*************** +*** 289,306 **** + return sock->ops->ioctl(sock, cmd, arg); + } + +! /*static*/ int +! sock_select(struct inode *inode, struct file *file, int which, +! select_table *seltable) + { + struct socket *sock; + + PRINTK("sock_select: inode = 0x%x, kind = %s\n", inode, +! (which == SEL_IN) ? "in" : +! (which == SEL_OUT) ? "out" : "ex"); + if (!(sock = socki_lookup(inode))) { +! printk("sock_write: can't find socket for inode!\n"); +! return -EBADF; + } + + /* +--- 288,304 ---- + return sock->ops->ioctl(sock, cmd, arg); + } + +! static int +! sock_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) + { + struct socket *sock; + + PRINTK("sock_select: inode = 0x%x, kind = %s\n", inode, +! (sel_type == SEL_IN) ? "in" : +! (sel_type == SEL_OUT) ? "out" : "ex"); + if (!(sock = socki_lookup(inode))) { +! printk("sock_select: can't find socket for inode!\n"); +! return 0; + } + + /* +*************** +*** 307,325 **** + * handle server sockets specially + */ + if (sock->flags & SO_ACCEPTCON) { +! if (which == SEL_IN) { + PRINTK("sock_select: %sconnections pending\n", + sock->iconn ? "" : "no "); + return sock->iconn ? 1 : 0; + } + PRINTK("sock_select: nothing else for server socket\n"); + return 0; + } +- + /* + * we can't return errors to select, so its either yes or no. + */ +! return sock->ops->select(sock, which) ? 1 : 0; + } + + void +--- 305,328 ---- + * handle server sockets specially + */ + if (sock->flags & SO_ACCEPTCON) { +! if (sel_type == SEL_IN) { + PRINTK("sock_select: %sconnections pending\n", + sock->iconn ? "" : "no "); ++ if (sock->iconn) ++ return 1; ++ select_wait(&inode->i_wait, wait); + return sock->iconn ? 1 : 0; + } + PRINTK("sock_select: nothing else for server socket\n"); ++ select_wait(&inode->i_wait, wait); + return 0; + } + /* + * we can't return errors to select, so its either yes or no. + */ +! if (sock->ops && sock->ops->select) +! return sock->ops->select(sock, sel_type, wait); +! return 0; + } + + void +*** 0.96c.pl1/linux/net/unix.c Thu Jul 2 00:48:29 1992 +--- linux/net/unix.c Wed Jul 15 04:37:51 1992 +*************** +*** 53,59 **** + int nonblock); + static int unix_proto_write(struct socket *sock, char *ubuf, int size, + int nonblock); +! static int unix_proto_select(struct socket *sock, int which); + static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg); + +--- 53,59 ---- + int nonblock); + static int unix_proto_write(struct socket *sock, char *ubuf, int size, + int nonblock); +! static int unix_proto_select(struct socket *sock, int sel_type, select_table * wait); + static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg); + +*************** +*** 519,529 **** + } + + static int +! unix_proto_select(struct socket *sock, int which) + { + struct unix_proto_data *upd, *peerupd; + +! if (which == SEL_IN) { + upd = UN_DATA(sock); + PRINTK("unix_proto_select: there is%s data available\n", + UN_BUF_AVAIL(upd) ? "" : " no"); +--- 519,529 ---- + } + + static int +! unix_proto_select(struct socket *sock, int sel_type, select_table * wait) + { + struct unix_proto_data *upd, *peerupd; + +! if (sel_type == SEL_IN) { + upd = UN_DATA(sock); + PRINTK("unix_proto_select: there is%s data available\n", + UN_BUF_AVAIL(upd) ? "" : " no"); +*************** +*** 533,542 **** + PRINTK("unix_proto_select: socket not connected (read EOF)\n"); + return 1; + } +! else +! return 0; + } +! if (which == SEL_OUT) { + if (sock->state != SS_CONNECTED) { + PRINTK("unix_proto_select: socket not connected (write EOF)\n"); + return 1; +--- 533,542 ---- + PRINTK("unix_proto_select: socket not connected (read EOF)\n"); + return 1; + } +! select_wait(sock->wait,wait); +! return 0; + } +! if (sel_type == SEL_OUT) { + if (sock->state != SS_CONNECTED) { + PRINTK("unix_proto_select: socket not connected (write EOF)\n"); + return 1; +*************** +*** 544,550 **** + peerupd = UN_DATA(sock->conn); + PRINTK("unix_proto_select: there is%s space available\n", + UN_BUF_SPACE(peerupd) ? "" : " no"); +! return (UN_BUF_SPACE(peerupd) > 0); + } + /* SEL_EX */ + PRINTK("unix_proto_select: there are no exceptions here?!\n"); +--- 544,553 ---- + peerupd = UN_DATA(sock->conn); + PRINTK("unix_proto_select: there is%s space available\n", + UN_BUF_SPACE(peerupd) ? "" : " no"); +! if (UN_BUF_SPACE(peerupd) > 0) +! return 1; +! select_wait(sock->wait,wait); +! return 0; + } + /* SEL_EX */ + PRINTK("unix_proto_select: there are no exceptions here?!\n"); diff --git a/kernel/Historic/old-versions/linux-0.96c.tar.bz2 b/kernel/Historic/old-versions/linux-0.96c.tar.bz2 new file mode 100644 index 00000000..7543c8be Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96c.tar.bz2 differ diff --git a/kernel/Historic/old-versions/linux-0.96c.tar.bz2.sign b/kernel/Historic/old-versions/linux-0.96c.tar.bz2.sign new file mode 100644 index 00000000..f42dd5a6 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96c.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfyyGugalF9Dw4RAusRAJ9YfCqW49SuUFV858gnVkO0RAS5aACfZn1B +oh6ybQxRajMrpRkI1yErhVw= +=RFfo +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96c.tar.gz b/kernel/Historic/old-versions/linux-0.96c.tar.gz new file mode 100644 index 00000000..91b39af2 Binary files /dev/null and b/kernel/Historic/old-versions/linux-0.96c.tar.gz differ diff --git a/kernel/Historic/old-versions/linux-0.96c.tar.gz.sign b/kernel/Historic/old-versions/linux-0.96c.tar.gz.sign new file mode 100644 index 00000000..f73ae515 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96c.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfyyGugalF9Dw4RAqLaAJ9HxqjdjqoFTvwud+BvBrQRnSRSsgCfXPjY +1h/G9q2ZbyGFQrmpyR61IOI= +=6r40 +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/linux-0.96c.tar.sign b/kernel/Historic/old-versions/linux-0.96c.tar.sign new file mode 100644 index 00000000..930e7a22 --- /dev/null +++ b/kernel/Historic/old-versions/linux-0.96c.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLKyGugalF9Dw4RAkIsAJwPM9MeqT+/37nw1wZbhvqnRUU/xACggy9F +TEwuLzJvvz7xtt4OjOWNIhY= +=3Ij8 +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.bz2 b/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.bz2 new file mode 100644 index 00000000..ec8840c3 Binary files /dev/null and b/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.bz2 differ diff --git a/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.bz2.sign b/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.bz2.sign new file mode 100644 index 00000000..c076b81b --- /dev/null +++ b/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfvyGugalF9Dw4RAsmQAJ9V0VYMfaJg0L+Efz4TjVjSwlDpZwCfdq85 +gfBilkYC1hkViDL3eVhrq/k= +=1Piy +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.gz b/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.gz new file mode 100644 index 00000000..d5a213ff Binary files /dev/null and b/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.gz differ diff --git a/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.gz.sign b/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.gz.sign new file mode 100644 index 00000000..4736124a --- /dev/null +++ b/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfvyGugalF9Dw4RAigVAJ9rC6C7YVSirBYF4Xqq4WFF3L2KwgCcCgBb +Ba9jj+YiwRtWurJfm7AznuI= +=S4g3 +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.sign b/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.sign new file mode 100644 index 00000000..9c7b4cbf --- /dev/null +++ b/kernel/Historic/old-versions/old/corrupt/linux-0.95c.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLHyGugalF9Dw4RAlztAJsHStgOdrfcb3+YINQ+gNFr31DjaACgk5AF +zDi0jEl8UXEf0HB6FE0vRzU= +=BBdC +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.bz2 b/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.bz2 new file mode 100644 index 00000000..771f39e2 Binary files /dev/null and b/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.bz2 differ diff --git a/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.bz2.sign b/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.bz2.sign new file mode 100644 index 00000000..b1520ee0 --- /dev/null +++ b/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfuyGugalF9Dw4RAtNtAJ0TWeaSVoDGJ3cx3icKUcyIikA5ggCfayR8 +qpeRc8sbck0CTP0euWdNXLM= +=iPUK +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.gz b/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.gz new file mode 100644 index 00000000..ac313547 Binary files /dev/null and b/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.gz differ diff --git a/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.gz.sign b/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.gz.sign new file mode 100644 index 00000000..e70f280a --- /dev/null +++ b/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfuyGugalF9Dw4RAjpoAJ9bAfXZbcfWzpDecP5cjON/qCVDcQCfc3vl +7qelyY+ofDxfTP7gbuHf46o= +=e14z +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.sign b/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.sign new file mode 100644 index 00000000..4382e802 --- /dev/null +++ b/kernel/Historic/old-versions/old/corrupt/linux-0.97.5.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLHyGugalF9Dw4RAqmQAJ0aa22oqC8p7Sy3nm7LzRYOqa8rdACeO/Dz +FgN+Vz4AlHBwQ+0Ra+bENTM= +=2vhb +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/diffs b/kernel/Historic/old-versions/old/diffs new file mode 100644 index 00000000..3a320fec --- /dev/null +++ b/kernel/Historic/old-versions/old/diffs @@ -0,0 +1,5168 @@ +*** ../0.95a/linux/Makefile Tue Mar 17 00:08:56 1992 +--- linux/Makefile Sat Apr 4 17:33:02 1992 +*************** +*** 1,7 **** +--- 1,44 ---- + # ++ # comment this line if you don't want the emulation-code ++ # ++ ++ MATH_EMULATION = -DKERNEL_MATH_EMULATION ++ ++ # ++ # uncomment the correct keyboard: ++ # ++ ++ KEYBOARD = -DKBD_FINNISH ++ # KEYBOARD = -DKBD_US ++ # KEYBOARD = -DKBD_GR ++ # KEYBOARD = -DKBD_FR ++ # KEYBOARD = -DKBD_UK ++ # KEYBOARD = -DKBD_DK ++ ++ # ++ # uncomment this line if you are using gcc-1.40 ++ # ++ #GCC_OPT = -fcombine-regs ++ ++ # ++ # standard CFLAGS ++ # ++ ++ CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) ++ ++ # ++ # ROOT_DEV specifies the default root-device when making the image. ++ # This can be either FLOPPY, /dev/xxxx or empty, in which case the ++ # default of FLOPPY is used by 'build'. ++ # ++ ++ ROOT_DEV = /dev/hdb1 ++ ++ # + # if you want the ram-disk device, define this to be the + # size in blocks. + # ++ + #RAMDISK = -DRAMDISK=512 + + AS86 =as86 -0 -a +*************** +*** 9,26 **** + + AS =as + LD =ld +! LDFLAGS =-s -x -M + CC =gcc $(RAMDISK) +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer + CPP =cpp -nostdinc -Iinclude + +- # +- # ROOT_DEV specifies the default root-device when making the image. +- # This can be either FLOPPY, /dev/xxxx or empty, in which case the +- # default of FLOPPY is used by 'build'. +- # +- ROOT_DEV=/dev/hdb1 +- + ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o + FILESYSTEMS =fs/minix/minix.o + DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a +--- 46,57 ---- + + AS =as + LD =ld +! #LDFLAGS =-s -x -M +! LDFLAGS = -M + CC =gcc $(RAMDISK) +! MAKE =make CFLAGS="$(CFLAGS)" + CPP =cpp -nostdinc -Iinclude + + ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o + FILESYSTEMS =fs/minix/minix.o + DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a +*************** +*** 39,45 **** + all: Image + + Image: boot/bootsect boot/setup tools/system tools/build +! tools/build boot/bootsect boot/setup tools/system $(ROOT_DEV) > Image + sync + + disk: Image +--- 70,79 ---- + all: Image + + Image: boot/bootsect boot/setup tools/system tools/build +! cp tools/system system.tmp +! strip system.tmp +! tools/build boot/bootsect boot/setup system.tmp $(ROOT_DEV) > Image +! rm system.tmp + sync + + disk: Image +*************** +*** 62,89 **** + -o tools/system > System.map + + kernel/math/math.a: dummy +! (cd kernel/math; make) + + kernel/blk_drv/blk_drv.a: dummy +! (cd kernel/blk_drv; make) + + kernel/chr_drv/chr_drv.a: dummy +! (cd kernel/chr_drv; make) + + kernel/kernel.o: dummy +! (cd kernel; make) + + mm/mm.o: dummy +! (cd mm; make) + + fs/fs.o: dummy +! (cd fs; make) + + fs/minix/minix.o: dummy +! (cd fs/minix; make) + + lib/lib.a: dummy +! (cd lib; make) + + boot/setup: boot/setup.s + $(AS86) -o boot/setup.o boot/setup.s +--- 96,123 ---- + -o tools/system > System.map + + kernel/math/math.a: dummy +! (cd kernel/math; $(MAKE) MATH_EMULATION="$(MATH_EMULATION)") + + kernel/blk_drv/blk_drv.a: dummy +! (cd kernel/blk_drv; $(MAKE)) + + kernel/chr_drv/chr_drv.a: dummy +! (cd kernel/chr_drv; $(MAKE) KEYBOARD="$(KEYBOARD)") + + kernel/kernel.o: dummy +! (cd kernel; $(MAKE)) + + mm/mm.o: dummy +! (cd mm; $(MAKE)) + + fs/fs.o: dummy +! (cd fs; $(MAKE)) + + fs/minix/minix.o: dummy +! (cd fs/minix; $(MAKE)) + + lib/lib.a: dummy +! (cd lib; $(MAKE)) + + boot/setup: boot/setup.s + $(AS86) -o boot/setup.o boot/setup.s +*************** +*** 127,133 **** + include/sys/types.h include/sys/time.h include/time.h include/sys/times.h \ + include/sys/utsname.h include/sys/param.h include/sys/resource.h \ + include/utime.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/linux/kernel.h include/signal.h include/asm/system.h \ +! include/asm/io.h include/stddef.h include/stdarg.h include/fcntl.h \ +! include/string.h +--- 161,167 ---- + include/sys/types.h include/sys/time.h include/time.h include/sys/times.h \ + include/sys/utsname.h include/sys/param.h include/sys/resource.h \ + include/utime.h include/linux/tty.h include/termios.h include/linux/sched.h \ +! include/linux/head.h include/linux/fs.h include/sys/dirent.h \ +! include/limits.h include/linux/mm.h include/linux/kernel.h include/signal.h \ +! include/asm/system.h include/asm/io.h include/stddef.h include/stdarg.h \ +! include/fcntl.h include/string.h +*** ../0.95a/linux/boot/bootsect.S Sat Jan 18 19:01:36 1992 +--- linux/boot/bootsect.S Thu Apr 2 23:18:19 1992 +*************** +*** 8,17 **** + ! + ! bootsect.s (C) 1991 Linus Torvalds + ! modified by Drew Eckhardt + ! + ! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves +! ! iself out of the way to address 0x90000, and jumps there. + ! + ! It then loads 'setup' directly after itself (0x90200), and the system + ! at 0x10000, using BIOS interrupts. + ! +--- 8,21 ---- + ! + ! bootsect.s (C) 1991 Linus Torvalds + ! modified by Drew Eckhardt ++ ! modified by Bruce Evans (bde) + ! + ! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves +! ! itself out of the way to address 0x90000, and jumps there. + ! ++ ! bde - should not jump blindly, there may be systems with only 512K low ++ ! memory. Use int 0x12 to get the top of memory, etc. ++ ! + ! It then loads 'setup' directly after itself (0x90200), and the system + ! at 0x10000, using BIOS interrupts. + ! +*************** +*** 22,51 **** + ! + ! The loader has been made as simple as possible, and continuos + ! read errors will result in a unbreakable loop. Reboot by hand. It +! ! loads pretty fast by getting whole sectors at a time whenever possible. + +- .globl begtext, begdata, begbss, endtext, enddata, endbss + .text +- begtext: +- .data +- begdata: +- .bss +- begbss: +- .text + +! SETUPLEN = 4 ! nr of setup-sectors +! BOOTSEG = 0x07c0 ! original address of boot-sector +! INITSEG = DEF_INITSEG ! we move boot here - out of the way +! SETUPSEG = DEF_SETUPSEG ! setup starts here +! SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). +! ENDSEG = SYSSEG + SYSSIZE ! where to stop loading + + ! ROOT_DEV & SWAP_DEV are now written by "build". + ROOT_DEV = 0 + SWAP_DEV = 0 + +! entry start +! start: + mov ax,#BOOTSEG + mov ds,ax + mov ax,#INITSEG +--- 26,52 ---- + ! + ! The loader has been made as simple as possible, and continuos + ! read errors will result in a unbreakable loop. Reboot by hand. It +! ! loads pretty fast by getting whole tracks at a time whenever possible. + + .text + +! SETUPSECS = 4 ! nr of setup-sectors +! BOOTSEG = 0x07C0 ! original address of boot-sector +! INITSEG = DEF_INITSEG ! we move boot here - out of the way +! SETUPSEG = DEF_SETUPSEG ! setup starts here +! SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). +! ENDSEG = SYSSEG + SYSSIZE ! where to stop loading + + ! ROOT_DEV & SWAP_DEV are now written by "build". + ROOT_DEV = 0 + SWAP_DEV = 0 + +! ! ld86 requires an entry symbol. This may as well be the usual one. +! .globl _main +! _main: +! #if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */ +! int 3 +! #endif + mov ax,#BOOTSEG + mov ds,ax + mov ax,#INITSEG +*************** +*** 55,71 **** + sub di,di + cld + rep +! movw + jmpi go,INITSEG + + go: mov ax,cs +! mov dx,#0xfef4 ! arbitrary value >>512 - disk parm size + + mov ds,ax + mov es,ax + push ax + +! mov ss,ax ! put stack at 0x9ff00 - 12. + mov sp,dx + /* + * Many BIOS's default disk parameter tables will not +--- 56,80 ---- + sub di,di + cld + rep +! movsw + jmpi go,INITSEG + + go: mov ax,cs +! mov dx,#0x4000-12 ! 0x4000 is arbitrary value >= length of +! ! bootsect + length of setup + room for stack +! ! 12 is disk parm size + ++ ! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We ++ ! wouldn't have to worry about this if we checked the top of memory. Also ++ ! my BIOS can be configured to put the wini drive tables in high memory ++ ! instead of in the vector table. The old stack might have clobbered the ++ ! drive table. ++ + mov ds,ax + mov es,ax + push ax + +! mov ss,ax ! put stack at INITSEG:0x4000-12. + mov sp,dx + /* + * Many BIOS's default disk parameter tables will not +*************** +*** 96,102 **** + + rep + seg gs +! movw + + mov di,dx + movb 4(di),*18 ! patch sector count +--- 105,111 ---- + + rep + seg gs +! movsw + + mov di,dx + movb 4(di),*18 ! patch sector count +*************** +*** 121,127 **** + xor dx, dx ! drive 0, head 0 + mov cx,#0x0002 ! sector 2, track 0 + mov bx,#0x0200 ! address = 512, in INITSEG +! mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors + int 0x13 ! read it + jnc ok_load_setup ! ok - continue + +--- 130,137 ---- + xor dx, dx ! drive 0, head 0 + mov cx,#0x0002 ! sector 2, track 0 + mov bx,#0x0200 ! address = 512, in INITSEG +! mov ax,#0x0200+SETUPSECS ! service 2, nr of sectors +! ! (assume all on head 0, track 0) + int 0x13 ! read it + jnc ok_load_setup ! ok - continue + +*************** +*** 134,149 **** + xor dl, dl ! reset FDC + xor ah, ah + int 0x13 +! j load_setup + + ok_load_setup: + + ! Get disk drive parameters, specifically nr of sectors/track + + xor dl,dl + mov ah,#0x08 ! AH=8 is get drive parameters + int 0x13 + xor ch,ch + seg cs + mov sectors,cx + mov ax,#INITSEG +--- 144,186 ---- + xor dl, dl ! reset FDC + xor ah, ah + int 0x13 +! jmp load_setup + + ok_load_setup: + + ! Get disk drive parameters, specifically nr of sectors/track + ++ #if 0 ++ ++ ! bde - the Phoenix BIOS manual says function 0x08 only works for fixed ++ ! disks. It doesn't work for one of my BIOS's (1987 Award). It was ++ ! fatal not to check the error code. ++ + xor dl,dl + mov ah,#0x08 ! AH=8 is get drive parameters + int 0x13 + xor ch,ch ++ #else ++ ++ ! It seems that there is no BIOS call to get the number of sectors. Guess ++ ! 18 sectors if sector 18 can be read, 15 if sector 15 can be read. ++ ! Otherwise guess 9. ++ ++ xor dx, dx ! drive 0, head 0 ++ mov cx,#0x0012 ! sector 18, track 0 ++ mov bx,#0x0200+SETUPSECS*0x200 ! address after setup (es = cs) ++ mov ax,#0x0201 ! service 2, 1 sector ++ int 0x13 ++ jnc got_sectors ++ mov cl,#0x0f ! sector 15 ++ mov ax,#0x0201 ! service 2, 1 sector ++ int 0x13 ++ jnc got_sectors ++ mov cl,#0x09 ++ ++ #endif ++ ++ got_sectors: + seg cs + mov sectors,cx + mov ax,#INITSEG +*************** +*** 205,211 **** + ! + ! in: es - starting address segment (normally 0x1000) + ! +! sread: .word 1+SETUPLEN ! sectors read of current track + head: .word 0 ! current head + track: .word 0 ! current track + +--- 242,248 ---- + ! + ! in: es - starting address segment (normally 0x1000) + ! +! sread: .word 1+SETUPSECS ! sectors read of current track + head: .word 0 ! current head + track: .word 0 ! current track + +*************** +*** 264,277 **** + int 0x10 + popa + +! mov dx,track +! mov cx,sread +! inc cx +! mov ch,dl +! mov dx,head +! mov dh,dl +! and dx,#0x0100 +! mov ah,#2 + + push dx ! save for error dump + push cx +--- 301,314 ---- + int 0x10 + popa + +! mov dx,track +! mov cx,sread +! inc cx +! mov ch,dl +! mov dx,head +! mov dh,dl +! and dx,#0x0100 +! mov ah,#2 + + push dx ! save for error dump + push cx +*************** +*** 278,286 **** + push bx + push ax + +! int 0x13 +! jc bad_rt +! add sp, #8 + popa + ret + +--- 315,323 ---- + push bx + push ax + +! int 0x13 +! jc bad_rt +! add sp, #8 + popa + ret + +*************** +*** 317,332 **** + print_loop: + push cx ! save count left + call print_nl ! nl for readability + jae no_reg ! see if register name is needed + +! mov ax, #0xe05 + 0x41 - 1 + sub al, cl + int 0x10 + +! mov al, #0x58 ! X + int 0x10 + +! mov al, #0x3a ! : + int 0x10 + + no_reg: +--- 354,371 ---- + print_loop: + push cx ! save count left + call print_nl ! nl for readability ++ ++ cmp cl, 5 + jae no_reg ! see if register name is needed + +! mov ax, #0xe05 + 'A - 1 + sub al, cl + int 0x10 + +! mov al, #'X + int 0x10 + +! mov al, #': + int 0x10 + + no_reg: +*************** +*** 356,365 **** + mov ah, #0xe + mov al, dl ! mask off so we have only next nibble + and al, #0xf +! add al, #0x30 ! convert to 0 based digit, '0' +! cmp al, #0x39 ! check for overflow + jbe good_digit +! add al, #0x41 - 0x30 - 0xa ! 'A' - '0' - 0xa + + good_digit: + int 0x10 +--- 395,404 ---- + mov ah, #0xe + mov al, dl ! mask off so we have only next nibble + and al, #0xf +! add al, #'0 ! convert to 0-based digit +! cmp al, #'9 ! check for overflow + jbe good_digit +! add al, #'A - '0 - 10 + + good_digit: + int 0x10 +*************** +*** 394,404 **** + .word ROOT_DEV + boot_flag: + .word 0xAA55 +- +- .text +- endtext: +- .data +- enddata: +- .bss +- endbss: +- +--- 433,435 ---- +*** ../0.95a/linux/boot/setup.S Sat Mar 14 23:13:30 1992 +--- linux/boot/setup.S Wed Mar 25 02:30:42 1992 +*************** +*** 217,222 **** +--- 217,238 ---- + jnz empty_8042 ! yes - loop + ret + ++ getkey: ++ in al,#0x60 ! Quick and dirty... ++ .word 0x00eb,0x00eb ! jmp $+2, jmp $+2 ++ mov bl,al ++ in al,#0x61 ++ .word 0x00eb,0x00eb ++ mov ah,al ++ or al,#0x80 ++ out #0x61,al ++ .word 0x00eb,0x00eb ++ mov al,ah ++ out #0x61,al ++ .word 0x00eb,0x00eb ++ mov al,bl ++ ret ++ + ! Routine trying to recognize type of SVGA-board present (if any) + ! and if it recognize one gives the choices of resolution it offers. + ! If one is found the resolution chosen is given by al,ah (rows,cols). +*************** +*** 233,239 **** + cmp al,#0x82 + jb nokey + jmp flush +! nokey: in al,#0x60 + cmp al,#0x82 + jb nokey + cmp al,#0xe0 +--- 249,255 ---- + cmp al,#0x82 + jb nokey + jmp flush +! nokey: call getkey + cmp al,#0x82 + jb nokey + cmp al,#0xe0 +*************** +*** 481,487 **** + call prtstr + pop si + add cl,#0x80 +! nonum: in al,#0x60 ! Quick and dirty... + cmp al,#0x82 + jb nonum + cmp al,#0x8b +--- 497,503 ---- + call prtstr + pop si + add cl,#0x80 +! nonum: call getkey + cmp al,#0x82 + jb nonum + cmp al,#0x8b +*** ../0.95a/linux/fs/Makefile Thu Mar 5 23:36:44 1992 +--- linux/fs/Makefile Sat Apr 4 17:33:10 1992 +*************** +*** 1,10 **** + AR =ar + AS =as +- CC =gcc + LD =ld +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ +! -fno-defer-pop -nostdinc -I../include +! CPP =gcc -E -nostdinc -I../include + + .c.s: + $(CC) $(CFLAGS) \ +--- 1,17 ---- ++ # ++ # Makefile for the linux filesystem. ++ # ++ # 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). ++ # ++ # Note 2! The CFLAGS definitions are now in the main makefile... ++ + AR =ar + AS =as + LD =ld +! CC =gcc -nostdinc -I../include +! CPP =cpp -nostdinc -I../include + + .c.s: + $(CC) $(CFLAGS) \ +*************** +*** 36,118 **** + ### Dependencies: + block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h + buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ +! ../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/asm/system.h \ +! ../include/asm/io.h +! char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \ +! ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ + ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/segment.h ../include/asm/io.h + exec.o : exec.c ../include/signal.h ../include/sys/types.h \ + ../include/errno.h ../include/string.h ../include/sys/stat.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/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.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/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \ +! ../include/fcntl.h ../include/sys/stat.h +! file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h + inode.o : inode.c ../include/string.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/linux/minix_fs.h \ +! ../include/asm/system.h + ioctl.o : ioctl.c ../include/string.h ../include/errno.h \ + ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \ +! ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.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/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/linux/minix_fs.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/kernel.h ../include/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/segment.h + pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \ + ../include/errno.h ../include/termios.h ../include/fcntl.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ +! ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/segment.h +! read_write.o : read_write.c ../include/sys/stat.h ../include/sys/types.h \ +! ../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \ +! ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/segment.h + select.o : select.c ../include/linux/fs.h ../include/sys/types.h \ +! ../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \ +! ../include/linux/sched.h ../include/linux/head.h ../include/linux/mm.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \ +! ../include/asm/system.h ../include/sys/stat.h ../include/string.h \ +! ../include/const.h ../include/errno.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/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.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 ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/linux/minix_fs.h \ +! ../include/asm/system.h ../include/errno.h ../include/sys/stat.h +--- 43,137 ---- + ### Dependencies: + block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/segment.h ../include/asm/system.h + buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ +! ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \ + ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/system.h ../include/asm/io.h +! char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \ +! ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/segment.h ../include/asm/io.h + exec.o : exec.c ../include/signal.h ../include/sys/types.h \ + ../include/errno.h ../include/string.h ../include/sys/stat.h \ +! ../include/a.out.h ../include/linux/fs.h ../include/sys/dirent.h \ +! ../include/limits.h ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.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/sys/dirent.h ../include/limits.h \ +! ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/segment.h ../include/fcntl.h \ +! ../include/sys/stat.h +! file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h \ +! ../include/sys/dirent.h ../include/limits.h + inode.o : inode.c ../include/string.h ../include/sys/stat.h \ + ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \ +! ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.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/sys/dirent.h \ +! ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h + namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \ +! ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.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/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/segment.h + pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \ + ../include/errno.h ../include/termios.h ../include/fcntl.h \ + ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \ + ../include/time.h ../include/sys/resource.h ../include/asm/segment.h ++ read_write.o : read_write.c ../include/errno.h ../include/sys/types.h \ ++ ../include/sys/stat.h ../include/sys/dirent.h ../include/limits.h \ ++ ../include/linux/kernel.h ../include/linux/sched.h ../include/linux/head.h \ ++ ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \ ++ ../include/sys/param.h ../include/sys/time.h ../include/time.h \ ++ ../include/sys/resource.h ../include/linux/minix_fs.h \ ++ ../include/asm/segment.h + select.o : select.c ../include/linux/fs.h ../include/sys/types.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/kernel.h \ +! ../include/linux/tty.h ../include/termios.h ../include/linux/sched.h \ +! ../include/linux/head.h ../include/linux/mm.h ../include/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h \ +! ../include/sys/stat.h ../include/string.h ../include/const.h \ +! ../include/errno.h + stat.o : stat.c ../include/errno.h ../include/sys/stat.h \ +! ../include/sys/types.h ../include/linux/fs.h ../include/sys/dirent.h \ +! ../include/limits.h ../include/linux/sched.h ../include/linux/head.h \ + ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \ + ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.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/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/linux/minix_fs.h ../include/asm/system.h ../include/errno.h \ +! ../include/sys/stat.h +*** ../0.95a/linux/fs/read_write.c Tue Mar 3 00:16:10 1992 +--- linux/fs/read_write.c Fri Apr 3 20:20:36 1992 +*************** +*** 4,22 **** + * (C) 1991 Linus Torvalds + */ + +- #include + #include + #include + + #include + #include + #include + +! int sys_lseek(unsigned int fd,off_t offset, unsigned int origin) + { + struct file * file; +! int tmp; + + if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode)) + return -EBADF; + if (origin > 2) +--- 4,37 ---- + * (C) 1991 Linus Torvalds + */ + + #include + #include ++ #include ++ #include + + #include + #include ++ #include + #include + +! int sys_readdir(unsigned int fd, struct dirent * dirent) + { + struct file * file; +! struct inode * inode; + ++ if (fd >= NR_OPEN || !(file = current->filp[fd]) || ++ !(inode = file->f_inode)) ++ return -EBADF; ++ if (file->f_op && file->f_op->readdir) ++ return file->f_op->readdir(inode,file,dirent); ++ return -EBADF; ++ } ++ ++ int sys_lseek(unsigned int fd, off_t offset, unsigned int origin) ++ { ++ struct file * file; ++ int tmp, mem_dev; ++ + if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode)) + return -EBADF; + if (origin > 2) +*************** +*** 25,45 **** + return -ESPIPE; + if (file->f_op && file->f_op->lseek) + return file->f_op->lseek(file->f_inode,file,offset,origin); + /* this is the default handler if no lseek handler is present */ + 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; + } + return file->f_pos; + } + +--- 40,64 ---- + return -ESPIPE; + if (file->f_op && file->f_op->lseek) + return file->f_op->lseek(file->f_inode,file,offset,origin); ++ mem_dev = S_ISCHR(file->f_inode->i_mode); ++ + /* this is the default handler if no lseek handler is present */ + switch (origin) { + case 0: +! if (offset<0 && !mem_dev) return -EINVAL; + file->f_pos=offset; + break; + case 1: +! if (file->f_pos+offset<0 && !mem_dev) return -EINVAL; + file->f_pos += offset; + break; + case 2: +! if ((tmp=file->f_inode->i_size+offset)<0 && !mem_dev) + return -EINVAL; + file->f_pos = tmp; + } ++ if (mem_dev && file->f_pos < 0) ++ return 0; + return file->f_pos; + } + +*** ../0.95a/linux/fs/buffer.c Fri Mar 13 19:06:26 1992 +--- linux/fs/buffer.c Wed Apr 1 02:06:48 1992 +*************** +*** 27,34 **** + #include + + 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; +--- 27,34 ---- + #include + + extern int end; +! static struct buffer_head * start_buffer = (struct buffer_head *) &end; +! static struct buffer_head * hash_table[NR_HASH]; + static struct buffer_head * free_list; + static struct task_struct * buffer_wait = NULL; + int NR_BUFFERS = 0; +*************** +*** 406,411 **** +--- 406,415 ---- + else + b = (void *) buffer_end; + while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) { ++ if (((unsigned long) (h+1)) > 0xA0000) { ++ printk("buffer-list doesn't fit in low meg - contact Linus\n"); ++ break; ++ } + h->b_dev = 0; + h->b_dirt = 0; + h->b_count = 0; +*** ../0.95a/linux/fs/inode.c Sat Mar 14 19:33:21 1992 +--- linux/fs/inode.c Fri Apr 3 16:09:27 1992 +*************** +*** 8,14 **** + #include + + #include +- #include + #include + #include + #include +--- 8,13 ---- +*************** +*** 15,23 **** + + struct inode inode_table[NR_INODE]={{0,},}; + +- extern void minix_read_inode(struct inode * inode); +- extern void minix_write_inode(struct inode * inode); +- + static inline void wait_on_inode(struct inode * inode) + { + cli(); +--- 14,19 ---- +*************** +*** 48,54 **** + unlock_inode(inode); + return; + } +! minix_write_inode(inode); + unlock_inode(inode); + } + +--- 44,51 ---- + unlock_inode(inode); + return; + } +! if (inode->i_op && inode->i_op->write_inode) +! inode->i_op->write_inode(inode); + unlock_inode(inode); + } + +*************** +*** 55,67 **** + static void read_inode(struct inode * inode) + { + lock_inode(inode); +! minix_read_inode(inode); + unlock_inode(inode); + } + + int bmap(struct inode * inode, int block) + { +! return minix_bmap(inode,block); + } + + void invalidate_inodes(int dev) +--- 52,77 ---- + static void read_inode(struct inode * inode) + { + lock_inode(inode); +! if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->read_inode) +! inode->i_sb->s_op->read_inode(inode); + unlock_inode(inode); + } + ++ /* ++ * bmap is needed for demand-loading and paging: if this function ++ * doesn't exist for a filesystem, then those things are impossible: ++ * executables cannot be run from the filesystem etc... ++ * ++ * This isn't as bad as it sounds: the read-routines might still work, ++ * so the filesystem would be otherwise ok (for example, you might have ++ * a DOS filesystem, which doesn't lend itself to bmap very well, but ++ * you could still transfer files to/from the filesystem) ++ */ + int bmap(struct inode * inode, int block) + { +! if (inode->i_op && inode->i_op->bmap) +! return inode->i_op->bmap(inode,block); +! return 0; + } + + void invalidate_inodes(int dev) +*************** +*** 127,134 **** + return; + } + if (!inode->i_nlink) { +! minix_truncate(inode); +! minix_free_inode(inode); + return; + } + if (inode->i_dirt) { +--- 137,144 ---- + return; + } + if (!inode->i_nlink) { +! if (inode->i_op && inode->i_op->put_inode) +! inode->i_op->put_inode(inode); + return; + } + if (inode->i_dirt) { +*** ../0.95a/linux/fs/open.c Mon Mar 2 23:52:07 1992 +--- linux/fs/open.c Thu Apr 2 23:41:50 1992 +*************** +*** 29,34 **** +--- 29,39 ---- + if (!(inode=namei(filename))) + return -ENOENT; + if (times) { ++ if (current->euid != inode->i_uid && ++ !permission(inode,MAY_WRITE)) { ++ iput(inode); ++ return -EPERM; ++ } + actime = get_fs_long((unsigned long *) ×->actime); + modtime = get_fs_long((unsigned long *) ×->modtime); + } else +*** ../0.95a/linux/fs/char_dev.c Mon Mar 2 04:16:20 1992 +--- linux/fs/char_dev.c Wed Apr 1 01:26:11 1992 +*************** +*** 38,63 **** + + static int rw_mem(int rw,char * buf, int count, off_t * pos) + { +! return -EIO; + } + + static int rw_kmem(int rw,char * buf, int count, off_t * pos) + { +! /* kmem by Damiano */ +! int i = *pos; /* Current position where to read */ + +! /* i can go from 0 to LOW_MEM (See include/linux/mm.h */ +! /* I am not shure about it but it doesn't mem fault :-) */ +! while ( (count-- > 0) && (i > 20 & 0xffc); +! if (((pte = *((unsigned long *) pde)) & 1) == 0) +! return 0; /* page table not present */ +! pte &= 0xfffff000; +! pte += *pos >> 10 & 0xffc; +! if (((tmp = *((unsigned long *) pte)) & 1) == 0) +! return 0; +! if (rw == WRITE && (tmp & 2) == 0) +! un_wp_page((unsigned long *) pte); +! p = (char *) ((tmp & 0xfffff000) + (*pos & 0xfff)); +! while (1) { +! if (rw == WRITE) +! *p++ = get_fs_byte(buf++); +! else +! put_fs_byte(*p++, buf++); +! +! if (--i == 0) +! break; +! +! if (count && ((unsigned long) p & 0xfff) == 0) { +! if (((pte += 4) & 0xfff) == 0) { +! if (((pde += 4) & 0xfff) == 0) +! break; +! if (((pte = *((unsigned long *) pde)) & 1) == 0) +! break; +! pte &= 0xfffff000; +! } +! if (((tmp = *((unsigned long *) pte)) & 1) == 0) +! break; +! +! if (rw == WRITE && (tmp & 2) == 0) +! un_wp_page((unsigned long *) pte); +! p = (char *) (tmp & 0xfffff000); +! } +! } +! return(count - i); + } + + static int rw_kmem(int rw,char * buf, int count, off_t * pos) + { +! char *p=(char *) *pos; + +! if ((unsigned long) *pos > HIGH_MEMORY) +! return 0; +! if ((unsigned long) *pos + count > HIGH_MEMORY) +! count = HIGH_MEMORY - *pos; +! +! switch (rw) { +! case READ: +! while ((count -= 4) >= 0) +! put_fs_long(*((unsigned long *) p)++, +! ((unsigned long *) buf)++); +! count += 4; +! while (--count >= 0) +! put_fs_byte(*p++, buf++); +! break; +! case WRITE: +! while (--count >= 0) +! *p++ = get_fs_byte(buf++); +! break; +! default: +! return -EINVAL; + } +! p -= *pos; +! *pos += (int) p; +! return (int) p; + } + + static int rw_port(int rw,char * buf, int count, off_t * pos) +*** ../0.95a/linux/fs/exec.c Wed Mar 4 06:24:51 1992 +--- linux/fs/exec.c Wed Apr 1 01:26:36 1992 +*************** +*** 216,221 **** +--- 216,222 ---- + int retval; + int sh_bang = 0; + unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4; ++ int ch; + + if ((0xffff & eip[1]) != 0x000f) + panic("execve called from supervisor mode"); +*************** +*** 348,353 **** +--- 349,363 ---- + } + /* OK, This is the point of no return */ + /* note that current->library stays unchanged by an exec */ ++ for (i=0; (ch = get_fs_byte(filename++)) != '\0';) ++ if (ch == '/') ++ i = 0; ++ else ++ if (i < 8) ++ current->comm[i++] = ch; ++ if (i < 8) ++ current->comm[i] = '\0'; ++ + if (current->executable) + iput(current->executable); + current->executable = inode; +*************** +*** 374,379 **** +--- 384,390 ---- + (current->end_data = ex.a_data + + (current->end_code = ex.a_text)); + current->start_stack = p; ++ current->rss = (LIBRARY_OFFSET - p + PAGE_SIZE-1) / PAGE_SIZE; + current->suid = current->euid = e_uid; + current->sgid = current->egid = e_gid; + eip[0] = ex.a_entry; /* eip, magic happens :-) */ +*** ../0.95a/linux/fs/super.c Fri Feb 28 19:01:44 1992 +--- linux/fs/super.c Fri Apr 3 16:22:05 1992 +*************** +*** 29,36 **** + /* this is initialized in init/main.c */ + int ROOT_DEV = 0; + +! static void lock_super(struct super_block * sb) + { + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); +--- 29,55 ---- + /* this is initialized in init/main.c */ + int ROOT_DEV = 0; + +! /* Move into include file later */ +! +! static struct file_system_type file_systems[] = { +! {minix_read_super,"minix"}, +! {NULL,NULL} +! }; +! +! /* end of include file */ +! +! struct file_system_type *get_fs_type(char *name) + { ++ int a; ++ ++ for(a = 0 ; file_systems[a].read_super ; a++) ++ if (!strcmp(name,file_systems[a].name)) ++ return(&file_systems[a]); ++ return(NULL); ++ } ++ ++ void lock_super(struct super_block * sb) ++ { + cli(); + while (sb->s_lock) + sleep_on(&(sb->s_wait)); +*************** +*** 38,44 **** + sti(); + } + +! static void free_super(struct super_block * sb) + { + cli(); + sb->s_lock = 0; +--- 57,63 ---- + sti(); + } + +! void free_super(struct super_block * sb) + { + cli(); + sb->s_lock = 0; +*************** +*** 46,52 **** + sti(); + } + +! static void wait_on_super(struct super_block * sb) + { + cli(); + while (sb->s_lock) +--- 65,71 ---- + sti(); + } + +! void wait_on_super(struct super_block * sb) + { + cli(); + while (sb->s_lock) +*************** +*** 75,81 **** + void put_super(int dev) + { + struct super_block * sb; +- int i; + + if (dev == ROOT_DEV) { + printk("root diskette changed: prepare for armageddon\n\r"); +--- 94,99 ---- +*************** +*** 87,107 **** + printk("Mounted disk changed - tssk, tssk\n\r"); + return; + } +! lock_super(sb); +! sb->s_dev = 0; +! for(i=0;is_imap[i]); +! for(i=0;is_zmap[i]); +! free_super(sb); +! return; + } + +! static struct super_block * read_super(int dev) + { + struct super_block * s; +! struct buffer_head * bh; +! int i,block; + + if (!dev) + return NULL; +--- 105,118 ---- + printk("Mounted disk changed - tssk, tssk\n\r"); + return; + } +! if (sb->s_op && sb->s_op->put_super) +! sb->s_op->put_super(sb); + } + +! static struct super_block * read_super(int dev,char *name,void *data) + { + struct super_block * s; +! struct file_system_type *type; + + if (!dev) + return NULL; +*************** +*** 108,113 **** +--- 119,128 ---- + check_disk_change(dev); + if (s = get_super(dev)) + return s; ++ if (!(type=get_fs_type(name))) { ++ printk("get fs type failed %s\n",name); ++ return NULL; ++ } + for (s = 0+super_block ;; s++) { + if (s >= NR_SUPER+super_block) + return NULL; +*************** +*** 115,167 **** + break; + } + s->s_dev = dev; +! s->s_mounted = NULL; + s->s_covered = NULL; + s->s_time = 0; + s->s_rd_only = 0; + s->s_dirt = 0; +! lock_super(s); +! if (!(bh = bread(dev,1))) { +! s->s_dev=0; +! free_super(s); +! return NULL; +! } +! *((struct minix_super_block *) s) = +! *((struct minix_super_block *) bh->b_data); +! brelse(bh); +! if (s->s_magic != MINIX_SUPER_MAGIC) { +! s->s_dev = 0; +! free_super(s); +! return NULL; +! } +! for (i=0;i < MINIX_I_MAP_SLOTS;i++) +! s->s_imap[i] = NULL; +! for (i=0;i < MINIX_Z_MAP_SLOTS;i++) +! s->s_zmap[i] = NULL; +! block=2; +! for (i=0 ; i < s->s_imap_blocks ; i++) +! if (s->s_imap[i]=bread(dev,block)) +! block++; +! else +! break; +! for (i=0 ; i < s->s_zmap_blocks ; i++) +! if (s->s_zmap[i]=bread(dev,block)) +! block++; +! else +! break; +! if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) { +! for(i=0;is_imap[i]); +! for(i=0;is_zmap[i]); +! s->s_dev=0; +! free_super(s); +! return NULL; +! } +! s->s_imap[0]->b_data[0] |= 1; +! s->s_zmap[0]->b_data[0] |= 1; +! free_super(s); +! return s; + } + + int sys_umount(char * dev_name) +--- 130,143 ---- + break; + } + s->s_dev = dev; +! if (!type->read_super(s,data)) +! return(NULL); +! s->s_dev = dev; + s->s_covered = NULL; + s->s_time = 0; + s->s_rd_only = 0; + s->s_dirt = 0; +! return(s); + } + + int sys_umount(char * dev_name) +*************** +*** 184,190 **** + return -ENOENT; + if (!sb->s_covered->i_mount) + printk("Mounted inode has i_mount=0\n"); +! for (inode=inode_table+0 ; inodei_dev==dev && inode->i_count) + if (inode == sb->s_mounted && inode->i_count == 1) + continue; +--- 160,166 ---- + return -ENOENT; + if (!sb->s_covered->i_mount) + printk("Mounted inode has i_mount=0\n"); +! for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) + if (inode->i_dev==dev && inode->i_count) + if (inode == sb->s_mounted && inode->i_count == 1) + continue; +*************** +*** 195,202 **** + sb->s_covered = NULL; + iput(sb->s_mounted); + sb->s_mounted = NULL; +! put_super(dev); +! sync_dev(dev); + return 0; + } + +--- 171,178 ---- + sb->s_covered = NULL; + iput(sb->s_mounted); + sb->s_mounted = NULL; +! put_super(dev); +! sync_dev(dev); + return 0; + } + +*************** +*** 224,231 **** + iput(dir_i); + return -EPERM; + } +! if (!(sb=read_super(dev))) { + iput(dir_i); + return -EBUSY; + } + if (sb->s_covered) { +--- 200,211 ---- + iput(dir_i); + return -EPERM; + } +! if (dir_i->i_mount) { + iput(dir_i); ++ return -EPERM; ++ } ++ if (!(sb=read_super(dev,"minix",NULL))) { ++ iput(dir_i); + return -EBUSY; + } + if (sb->s_covered) { +*************** +*** 232,248 **** + iput(dir_i); + return -EBUSY; + } +! if (dir_i->i_mount) { +! iput(dir_i); +! return -EPERM; +! } +! if (!(sb->s_mounted = iget(dev,MINIX_ROOT_INO))) { +! iput(dir_i); +! return -EPERM; +! } +! sb->s_covered=dir_i; +! dir_i->i_mount=1; +! dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */ + return 0; /* we do that in umount */ + } + +--- 212,220 ---- + iput(dir_i); + return -EBUSY; + } +! sb->s_covered = dir_i; +! dir_i->i_mount = 1; +! dir_i->i_dirt = 1; /* NOTE! we don't iput(dir_i) */ + return 0; /* we do that in umount */ + } + +*************** +*** 265,274 **** + p->s_lock = 0; + p->s_wait = NULL; + } +! if (!(p=read_super(ROOT_DEV))) + panic("Unable to mount root"); + if (!(mi=iget(ROOT_DEV,MINIX_ROOT_INO))) + panic("Unable to read root i-node"); + mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ + p->s_mounted = p->s_covered = mi; + current->pwd = mi; +--- 237,249 ---- + p->s_lock = 0; + p->s_wait = NULL; + } +! if (!(p=read_super(ROOT_DEV,"minix",NULL))) + panic("Unable to mount root"); ++ /*wait_for_keypress(); + if (!(mi=iget(ROOT_DEV,MINIX_ROOT_INO))) + panic("Unable to read root i-node"); ++ wait_for_keypress();*/ ++ mi=p->s_mounted; + mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ + p->s_mounted = p->s_covered = mi; + current->pwd = mi; +*** ../0.95a/linux/fs/namei.c Fri Mar 6 19:04:09 1992 +--- linux/fs/namei.c Fri Apr 3 16:15:56 1992 +*************** +*** 9,15 **** + */ + + #include +- #include + #include + #include + +--- 9,14 ---- +*************** +*** 249,255 **** + } + inode->i_atime = CURRENT_TIME; + if (flag & O_TRUNC) +! minix_truncate(inode); + *res_inode = inode; + return 0; + } +--- 248,255 ---- + } + inode->i_atime = CURRENT_TIME; + if (flag & O_TRUNC) +! if (inode->i_op && inode->i_op->truncate) +! inode->i_op->truncate(inode); + *res_inode = inode; + return 0; + } +*************** +*** 270,276 **** + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EPERM; + } + if (!dir->i_op || !dir->i_op->mknod) { + iput(dir); +--- 270,276 ---- + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EACCES; + } + if (!dir->i_op || !dir->i_op->mknod) { + iput(dir); +*************** +*** 293,299 **** + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EPERM; + } + if (!dir->i_op || !dir->i_op->mkdir) { + iput(dir); +--- 293,299 ---- + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EACCES; + } + if (!dir->i_op || !dir->i_op->mkdir) { + iput(dir); +*************** +*** 316,322 **** + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EPERM; + } + if (!dir->i_op || !dir->i_op->rmdir) { + iput(dir); +--- 316,322 ---- + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EACCES; + } + if (!dir->i_op || !dir->i_op->rmdir) { + iput(dir); +*************** +*** 335,345 **** + return -ENOENT; + if (!namelen) { + iput(dir); +! return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EPERM; + } + if (!dir->i_op || !dir->i_op->unlink) { + iput(dir); +--- 335,345 ---- + return -ENOENT; + if (!namelen) { + iput(dir); +! return -EPERM; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EACCES; + } + if (!dir->i_op || !dir->i_op->unlink) { + iput(dir); +*************** +*** 356,369 **** + + dir = dir_namei(newname,&namelen,&basename, NULL); + if (!dir) +! return -EACCES; + if (!namelen) { + iput(dir); +! return -EPERM; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EPERM; + } + if (!dir->i_op || !dir->i_op->symlink) { + iput(dir); +--- 356,369 ---- + + dir = dir_namei(newname,&namelen,&basename, NULL); + if (!dir) +! return -ENOENT; + if (!namelen) { + iput(dir); +! return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); +! return -EACCES; + } + if (!dir->i_op || !dir->i_op->symlink) { + iput(dir); +*** ../0.95a/linux/fs/ioctl.c Thu Feb 20 17:01:12 1992 +--- linux/fs/ioctl.c Tue Mar 31 20:52:08 1992 +*************** +*** 10,15 **** +--- 10,16 ---- + + #include + ++ extern int hd_ioctl(int dev, int cmd, int arg); + extern int tty_ioctl(int dev, int cmd, int arg); + extern int pipe_ioctl(struct inode *pino, int cmd, int arg); + +*************** +*** 21,27 **** + NULL, /* nodev */ + NULL, /* /dev/mem */ + NULL, /* /dev/fd */ +! NULL, /* /dev/hd */ + tty_ioctl, /* /dev/ttyx */ + tty_ioctl, /* /dev/tty */ + NULL, /* /dev/lp */ +--- 22,28 ---- + NULL, /* nodev */ + NULL, /* /dev/mem */ + NULL, /* /dev/fd */ +! hd_ioctl, /* /dev/hd */ + tty_ioctl, /* /dev/ttyx */ + tty_ioctl, /* /dev/tty */ + NULL, /* /dev/lp */ +*** ../0.95a/linux/fs/pipe.c Fri Mar 6 15:04:16 1992 +--- linux/fs/pipe.c Fri Mar 27 11:18:57 1992 +*************** +*** 41,47 **** + put_fs_byte(((char *)inode->i_size)[size++],buf++); + } + wake_up(& PIPE_WRITE_WAIT(*inode)); +! return read; + } + + int pipe_write(struct inode * inode, struct file * filp, char * buf, int count) +--- 41,47 ---- + put_fs_byte(((char *)inode->i_size)[size++],buf++); + } + wake_up(& PIPE_WRITE_WAIT(*inode)); +! return read?read:-EAGAIN; + } + + int pipe_write(struct inode * inode, struct file * filp, char * buf, int count) +*** ../0.95a/linux/fs/minix/Makefile Thu Mar 5 23:36:47 1992 +--- linux/fs/minix/Makefile Sat Apr 4 17:33:13 1992 +*************** +*** 1,10 **** + AR =ar + AS =as +- CC =gcc + LD =ld +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ +! -nostdinc -I../../include +! CPP =gcc -E -nostdinc -I../../include + + .c.s: + $(CC) $(CFLAGS) \ +--- 1,17 ---- ++ # ++ # Makefile for the linux minix-filesystem routines. ++ # ++ # 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). ++ # ++ # Note 2! The CFLAGS definitions are now in the main makefile... ++ + AR =ar + AS =as + LD =ld +! CC =gcc -nostdinc -I../../include +! CPP =cpp -nostdinc -I../../include + + .c.s: + $(CC) $(CFLAGS) \ +*************** +*** 32,43 **** + ### 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 ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/linux/minix_fs.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +--- 39,52 ---- + ### 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/sys/dirent.h ../../include/limits.h \ +! ../../include/linux/mm.h ../../include/linux/kernel.h \ +! ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/linux/minix_fs.h + file_dev.o : file_dev.c ../../include/errno.h ../../include/fcntl.h \ +! ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \ +! ../../include/sys/stat.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ + ../../include/linux/mm.h ../../include/linux/kernel.h \ + ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +*************** +*** 46,59 **** + inode.o : inode.c ../../include/string.h ../../include/sys/stat.h \ + ../../include/sys/types.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/linux/mm.h ../../include/linux/kernel.h \ +! ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/linux/minix_fs.h ../../include/asm/system.h + minix_op.o : minix_op.c ../../include/linux/fs.h ../../include/sys/types.h \ + ../../include/linux/minix_fs.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/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/minix_fs.h \ +--- 55,71 ---- + inode.o : inode.c ../../include/string.h ../../include/sys/stat.h \ + ../../include/sys/types.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/linux/minix_fs.h \ +! ../../include/asm/system.h + minix_op.o : minix_op.c ../../include/linux/fs.h ../../include/sys/types.h \ ++ ../../include/sys/dirent.h ../../include/limits.h \ + ../../include/linux/minix_fs.h + namei.o : namei.c ../../include/linux/sched.h ../../include/linux/head.h \ +! ../../include/linux/fs.h ../../include/sys/types.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/minix_fs.h \ +*************** +*** 61,69 **** + ../../include/errno.h ../../include/const.h ../../include/sys/stat.h + truncate.o : truncate.c ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/types.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/linux/minix_fs.h \ +! ../../include/linux/tty.h ../../include/termios.h ../../include/errno.h \ +! ../../include/fcntl.h ../../include/sys/stat.h +--- 73,82 ---- + ../../include/errno.h ../../include/const.h ../../include/sys/stat.h + truncate.o : truncate.c ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \ +! ../../include/linux/mm.h ../../include/linux/kernel.h \ +! ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/linux/minix_fs.h ../../include/linux/tty.h \ +! ../../include/termios.h ../../include/errno.h ../../include/fcntl.h \ +! ../../include/sys/stat.h +*** ../0.95a/linux/fs/minix/inode.c Mon Mar 2 01:15:17 1992 +--- linux/fs/minix/inode.c Fri Apr 3 16:20:06 1992 +*************** +*** 13,27 **** + #include + #include + +! static int _bmap(struct 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_data[block]) + if (inode->i_data[block]=minix_new_block(inode->i_dev)) { +--- 13,112 ---- + #include + #include + +! int sync_dev(int dev); +! +! void minix_put_super(struct super_block *sb) + { ++ int i; ++ ++ lock_super(sb); ++ sb->s_dev = 0; ++ for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++) ++ brelse(sb->s_imap[i]); ++ for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++) ++ brelse(sb->s_zmap[i]); ++ free_super(sb); ++ return; ++ } ++ ++ static struct super_operations minix_sops = { ++ minix_read_inode, ++ minix_put_super ++ }; ++ ++ struct super_block *minix_read_super(struct super_block *s,void *data) ++ { ++ struct buffer_head *bh; ++ int i,dev=s->s_dev,block; ++ ++ lock_super(s); ++ if (!(bh = bread(dev,1))) { ++ s->s_dev=0; ++ free_super(s); ++ printk("bread failed\n"); ++ return NULL; ++ } ++ *((struct minix_super_block *) s) = ++ *((struct minix_super_block *) bh->b_data); ++ brelse(bh); ++ if (s->s_magic != MINIX_SUPER_MAGIC) { ++ s->s_dev = 0; ++ free_super(s); ++ printk("magic match failed\n"); ++ return NULL; ++ } ++ for (i=0;i < MINIX_I_MAP_SLOTS;i++) ++ s->s_imap[i] = NULL; ++ for (i=0;i < MINIX_Z_MAP_SLOTS;i++) ++ s->s_zmap[i] = NULL; ++ block=2; ++ for (i=0 ; i < s->s_imap_blocks ; i++) ++ if (s->s_imap[i]=bread(dev,block)) ++ block++; ++ else ++ break; ++ for (i=0 ; i < s->s_zmap_blocks ; i++) ++ if (s->s_zmap[i]=bread(dev,block)) ++ block++; ++ else ++ break; ++ if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) { ++ for(i=0;is_imap[i]); ++ for(i=0;is_zmap[i]); ++ s->s_dev=0; ++ free_super(s); ++ printk("block failed\n"); ++ return NULL; ++ } ++ s->s_imap[0]->b_data[0] |= 1; ++ s->s_zmap[0]->b_data[0] |= 1; ++ free_super(s); ++ /* set up enough so that it can read an inode */ ++ s->s_dev = dev; ++ s->s_op = &minix_sops; ++ if (!(s->s_mounted = iget(dev,MINIX_ROOT_INO))) { ++ s->s_dev=0; ++ printk("get root inode failed\n"); ++ return NULL; ++ } ++ return s; ++ } ++ ++ static int _minix_bmap(struct inode * inode,int block,int create) ++ { + struct buffer_head * bh; + int i; + +! if (block<0) { +! printk("_minix_bmap: block<0"); +! return 0; +! } +! if (block >= 7+512+512*512) { +! printk("_minix_bmap: block>big"); +! return 0; +! } + if (block<7) { + if (create && !inode->i_data[block]) + if (inode->i_data[block]=minix_new_block(inode->i_dev)) { +*************** +*** 83,94 **** + + int minix_bmap(struct inode * inode,int block) + { +! return _bmap(inode,block,0); + } + + int minix_create_block(struct inode * inode, int block) + { +! return _bmap(inode,block,1); + } + + void minix_read_inode(struct inode * inode) +--- 168,179 ---- + + int minix_bmap(struct inode * inode,int block) + { +! return _minix_bmap(inode,block,0); + } + + int minix_create_block(struct inode * inode, int block) + { +! return _minix_bmap(inode,block,1); + } + + void minix_read_inode(struct inode * inode) +*** ../0.95a/linux/fs/minix/namei.c Tue Mar 3 19:39:35 1992 +--- linux/fs/minix/namei.c Fri Apr 3 16:11:22 1992 +*************** +*** 15,24 **** + #include + #include + +- extern int permission(struct inode * inode,int mask); +- extern struct inode * _namei(const char * filename, struct inode * base, +- int follow_links); +- + /* + * comment out this line if you want names > MINIX_NAME_LEN chars to be + * truncated. Else they will be disallowed. +--- 15,20 ---- +*************** +*** 89,95 **** + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; +! if (!(block = bmap(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK)) || + !(bh = bread(dir->i_dev,block))) { + i += MINIX_DIR_ENTRIES_PER_BLOCK; + continue; +--- 85,91 ---- + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; +! if (!(block = minix_bmap(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK)) || + !(bh = bread(dir->i_dev,block))) { + i += MINIX_DIR_ENTRIES_PER_BLOCK; + continue; +*************** +*** 398,404 **** + while (nr= (void *) (bh->b_data+BLOCK_SIZE)) { + brelse(bh); +! block=bmap(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK); + if (!block) { + nr += MINIX_DIR_ENTRIES_PER_BLOCK; + continue; +--- 394,400 ---- + while (nr= (void *) (bh->b_data+BLOCK_SIZE)) { + brelse(bh); +! block = minix_bmap(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK); + if (!block) { + nr += MINIX_DIR_ENTRIES_PER_BLOCK; + continue; +*** ../0.95a/linux/fs/minix/minix_op.c Tue Mar 3 00:18:39 1992 +--- linux/fs/minix/minix_op.c Fri Apr 3 20:19:03 1992 +*************** +*** 7,12 **** +--- 7,18 ---- + #include + #include + ++ void minix_put_inode(struct inode *inode) ++ { ++ minix_truncate(inode); ++ minix_free_inode(inode); ++ } ++ + /* + * These are the low-level inode operations for minix filesystem inodes. + */ +*************** +*** 23,38 **** + minix_readlink, + minix_open, + minix_release, +! minix_follow_link + }; + + /* +! * We have just NULL's here: the current defaults are ok for + * the minix filesystem. + */ + struct file_operations minix_file_operations = { + NULL, /* lseek */ + NULL, /* read */ +! NULL /* write */ + }; + +--- 29,49 ---- + minix_readlink, + minix_open, + minix_release, +! minix_follow_link, +! minix_bmap, +! minix_truncate, +! minix_write_inode, +! minix_put_inode + }; + + /* +! * We have mostly NULL's here: the current defaults are ok for + * the minix filesystem. + */ + struct file_operations minix_file_operations = { + NULL, /* lseek */ + NULL, /* read */ +! NULL, /* write */ +! minix_readdir + }; + +*** ../0.95a/linux/fs/minix/file_dev.c Tue Mar 17 03:41:53 1992 +--- linux/fs/minix/file_dev.c Fri Apr 3 21:35:21 1992 +*************** +*** 6,11 **** +--- 6,13 ---- + + #include + #include ++ #include ++ #include + + #include + #include +*************** +*** 15,20 **** +--- 17,64 ---- + #define MIN(a,b) (((a)<(b))?(a):(b)) + #define MAX(a,b) (((a)>(b))?(a):(b)) + ++ int minix_readdir(struct inode * inode, struct file * filp, struct dirent * dirent) ++ { ++ unsigned int block,offset,i; ++ char c; ++ struct buffer_head * bh; ++ struct minix_dir_entry * de; ++ ++ if (!S_ISDIR(inode->i_mode)) ++ return -EBADF; ++ if (filp->f_pos & 15) ++ return -EBADF; ++ while (filp->f_pos < inode->i_size) { ++ offset = filp->f_pos & 1023; ++ block = minix_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS); ++ if (!block || !(bh = bread(inode->i_dev,block))) { ++ filp->f_pos += 1024-offset; ++ continue; ++ } ++ de = (struct minix_dir_entry *) (offset + bh->b_data); ++ while (offset < 1024 && filp->f_pos < inode->i_size) { ++ offset += 16; ++ filp->f_pos += 16; ++ if (de->inode) { ++ for (i = 0; i < 14; i++) ++ if (c = de->name[i]) ++ put_fs_byte(c,i+dirent->d_name); ++ else ++ break; ++ if (i) { ++ put_fs_long(de->inode,&dirent->d_ino); ++ put_fs_byte(0,i+dirent->d_name); ++ put_fs_word(i,&dirent->d_reclen); ++ return i; ++ } ++ } ++ de++; ++ } ++ brelse(bh); ++ } ++ return 0; ++ } ++ + int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count) + { + int read,left,chars,nr; +*************** +*** 28,34 **** + left = count; + read = 0; + while (left > 0) { +! if (nr = bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS)) { + if (!(bh=bread(inode->i_dev,nr))) + return read?read:-EIO; + } else +--- 72,78 ---- + left = count; + read = 0; + while (left > 0) { +! if (nr = minix_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS)) { + if (!(bh=bread(inode->i_dev,nr))) + return read?read:-EIO; + } else +*************** +*** 98,104 **** + if (!(filp->f_flags & O_APPEND)) { + filp->f_pos = pos; + inode->i_ctime = CURRENT_TIME; +- inode->i_dirt = 1; + } + return written; + } +--- 142,148 ---- + if (!(filp->f_flags & O_APPEND)) { + filp->f_pos = pos; + inode->i_ctime = CURRENT_TIME; + } ++ inode->i_dirt = 1; + return written; + } +*** ../0.95a/linux/kernel/Makefile Thu Mar 5 23:36:55 1992 +--- linux/kernel/Makefile Sat Apr 4 17:33:20 1992 +*************** +*** 5,23 **** + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # + +- # gcc2 doesn't have these: +- #GCC_OPT = -fcombine-regs +- + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) \ +! -finline-functions -nostdinc -I../include +! CPP =gcc -E -nostdinc -I../include + + .c.s: + $(CC) $(CFLAGS) \ + -S -o $*.s $< +--- 5,20 ---- + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # ++ # Note 2! The CFLAGS definitions are now in the main makefile... + + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc -nostdinc -I../include +! CPP =cpp -nostdinc -I../include + ++ + .c.s: + $(CC) $(CFLAGS) \ + -S -o $*.s $< +*************** +*** 35,40 **** +--- 32,40 ---- + $(LD) -r -o kernel.o $(OBJS) + sync + ++ sched.o: sched.c ++ $(CC) $(CFLAGS) -fno-omit-frame-pointer -c $< ++ + clean: + rm -f core *.o *.a tmp_make keyboard.s + for i in *.c;do rm -f `basename $$i .c`.s;done +*************** +*** 53,103 **** + ### Dependencies: + exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \ + ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \ +! ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.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/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h + mktime.s mktime.o : mktime.c ../include/time.h + panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/linux/mm.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h + printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \ + ../include/linux/kernel.h + ptrace.s ptrace.o : ptrace.c ../include/linux/head.h ../include/linux/kernel.h \ + ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/linux/mm.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/errno.h ../include/asm/segment.h ../include/asm/system.h \ +! ../include/sys/ptrace.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/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/linux/timer.h ../include/linux/sys.h ../include/linux/fdreg.h \ +! ../include/asm/system.h ../include/asm/io.h ../include/asm/segment.h \ +! ../include/errno.h + signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/segment.h ../include/sys/wait.h ../include/errno.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/kernel.h ../include/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/linux/tty.h ../include/termios.h \ +! ../include/linux/config.h ../include/asm/segment.h ../include/sys/times.h \ +! ../include/sys/utsname.h ../include/string.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/signal.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h ../include/asm/system.h ../include/asm/segment.h \ +! ../include/asm/io.h ../include/errno.h + vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h +--- 53,109 ---- + ### Dependencies: + exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \ + ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \ +! ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \ +! ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.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/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/segment.h ../include/asm/system.h + mktime.s mktime.o : mktime.c ../include/time.h + panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h + printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \ + ../include/linux/kernel.h + ptrace.s ptrace.o : ptrace.c ../include/linux/head.h ../include/linux/kernel.h \ + ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/errno.h \ +! ../include/asm/segment.h ../include/asm/system.h ../include/sys/ptrace.h + sched.s sched.o : sched.c ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \ +! ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/linux/timer.h \ +! ../include/linux/sys.h ../include/linux/fdreg.h ../include/asm/system.h \ +! ../include/asm/io.h ../include/asm/segment.h ../include/errno.h + signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \ +! ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \ +! ../include/sys/wait.h ../include/errno.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/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/linux/tty.h ../include/termios.h ../include/linux/config.h \ +! ../include/asm/segment.h ../include/sys/times.h ../include/sys/utsname.h \ +! ../include/string.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/sys/dirent.h ../include/limits.h ../include/linux/mm.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h \ +! ../include/asm/system.h ../include/asm/segment.h ../include/asm/io.h \ +! ../include/errno.h + vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h +*** ../0.95a/linux/kernel/sched.c Sat Mar 14 16:55:48 1992 +--- linux/kernel/sched.c Tue Mar 24 00:57:35 1992 +*************** +*** 46,57 **** + + void show_state(void) + { + int i; + + printk("\rTask-info:\n\r"); +! for (i=0;istate == TASK_INTERRUPTIBLE || p->state == TASK_RUNNING) + p->state = TASK_STOPPED; +- +- if (p == current) +- schedule(); + } + return 0; + } +--- 48,53 ---- +*************** +*** 218,232 **** + int sys_kill(int pid,int sig) + { + struct task_struct **p = NR_TASKS + task; +! int err, retval = 0; + + if (!pid) +! return(kill_pg(current->pid,sig,0)); + if (pid == -1) { + while (--p > &FIRST_TASK) +! if (err = send_sig(sig,*p,0)) +! retval = err; +! return(retval); + } + if (pid < 0) + return(kill_pg(-pid,sig,0)); +--- 215,232 ---- + int sys_kill(int pid,int sig) + { + struct task_struct **p = NR_TASKS + task; +! int err, retval = 0, count = 0; + + if (!pid) +! return(kill_pg(current->pgrp,sig,0)); + if (pid == -1) { + while (--p > &FIRST_TASK) +! if ((*p)->pid > 1 && *p != current) { +! ++count; +! if ((err = send_sig(sig,*p,0)) != -EPERM) +! retval = err; +! } +! return(count ? retval : -ESRCH); + } + if (pid < 0) + return(kill_pg(-pid,sig,0)); +*************** +*** 292,297 **** +--- 292,298 ---- + current->library = NULL; + current->state = TASK_ZOMBIE; + current->exit_code = code; ++ current->rss = 0; + /* + * Check to see if any process groups have become orphaned + * as a result of our exiting, and if they have any stopped +*************** +*** 413,420 **** + p->exit_code = 0; + return p->pid; + case TASK_ZOMBIE: +! current->cutime += p->utime; +! current->cstime += p->stime; + flag = p->pid; + if (stat_addr) + put_fs_long(p->exit_code, stat_addr); +--- 414,423 ---- + p->exit_code = 0; + return p->pid; + case TASK_ZOMBIE: +! current->cutime += p->utime + p->cutime; +! current->cstime += p->stime + p->cstime; +! current->cmin_flt += p->min_flt + p->cmin_flt; +! current->cmaj_flt += p->maj_flt + p->cmaj_flt; + flag = p->pid; + if (stat_addr) + put_fs_long(p->exit_code, stat_addr); +*** ../0.95a/linux/kernel/fork.c Wed Mar 4 14:11:24 1992 +--- linux/kernel/fork.c Wed Apr 1 01:27:04 1992 +*************** +*** 112,117 **** +--- 112,119 ---- + p->leader = 0; /* process leadership doesn't inherit */ + p->utime = p->stime = 0; + p->cutime = p->cstime = 0; ++ p->min_flt = p->maj_flt = 0; ++ p->cmin_flt = p->cmaj_flt = 0; + p->start_time = jiffies; + p->tss.back_link = 0; + p->tss.esp0 = PAGE_SIZE + (long) p; +*** ../0.95a/linux/kernel/sys.c Thu Feb 27 18:42:09 1992 +--- linux/kernel/sys.c Wed Apr 1 01:27:27 1992 +*************** +*** 457,467 **** +--- 457,471 ---- + r.ru_utime.tv_usec = CT_TO_USECS(current->utime); + r.ru_stime.tv_sec = CT_TO_SECS(current->stime); + r.ru_stime.tv_usec = CT_TO_USECS(current->stime); ++ r.ru_minflt = current->min_flt; ++ r.ru_majflt = current->maj_flt; + } else { + r.ru_utime.tv_sec = CT_TO_SECS(current->cutime); + r.ru_utime.tv_usec = CT_TO_USECS(current->cutime); + r.ru_stime.tv_sec = CT_TO_SECS(current->cstime); + r.ru_stime.tv_usec = CT_TO_USECS(current->cstime); ++ r.ru_minflt = current->cmin_flt; ++ r.ru_majflt = current->cmaj_flt; + } + lp = (unsigned long *) &r; + lpend = (unsigned long *) (&r+1); +*** ../0.95a/linux/kernel/chr_drv/keyboard.S Sun Mar 15 02:43:22 1992 +--- linux/kernel/chr_drv/keyboard.S Sat Apr 4 16:30:36 1992 +*************** +*** 19,25 **** + * KBD_UK for British extended keyboard + * KBD_DK for Danish keyboard + */ +- #define KBD_FINNISH + + .text + .globl _hard_reset_now +--- 19,24 ---- +*** ../0.95a/linux/kernel/chr_drv/Makefile Thu Mar 5 23:37:00 1992 +--- linux/kernel/chr_drv/Makefile Sat Apr 4 17:33:24 1992 +*************** +*** 5,22 **** + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # + +- # gcc2 doesn't understand this option: +- #GCC_OPT = -fcombine-regs +- + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) \ +! -finline-functions -nostdinc -I../../include +! CPP =gcc -E -nostdinc -I../../include + + .c.s: + $(CC) $(CFLAGS) \ +--- 5,20 ---- + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # ++ # Note 2! The CFLAGS definitions are now inherited from the ++ # parent makes.. ++ # + + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc -nostdinc -I../../include +! CPP =cpp -nostdinc -I../../include + + .c.s: + $(CC) $(CFLAGS) \ +*************** +*** 35,41 **** + sync + + keyboard.s: keyboard.S +! $(CPP) -traditional keyboard.S -o keyboard.s + + clean: + rm -f core *.o *.a tmp_make keyboard.s +--- 33,39 ---- + sync + + keyboard.s: keyboard.S +! $(CPP) $(KEYBOARD) -traditional keyboard.S -o keyboard.s + + clean: + rm -f core *.o *.a tmp_make keyboard.s +*************** +*** 50,78 **** + ### 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/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/linux/timer.h \ +! ../../include/linux/tty.h ../../include/termios.h \ +! ../../include/linux/config.h ../../include/asm/io.h \ + ../../include/asm/system.h ../../include/asm/segment.h \ + ../../include/string.h ../../include/errno.h + pty.s pty.o : pty.c ../../include/linux/tty.h ../../include/termios.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/asm/system.h ../../include/asm/io.h + serial.s serial.o : serial.c ../../include/linux/tty.h ../../include/termios.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/linux/timer.h ../../include/asm/system.h \ +! ../../include/asm/io.h + tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \ + ../../include/signal.h ../../include/sys/types.h ../../include/unistd.h \ + ../../include/sys/stat.h ../../include/sys/time.h ../../include/time.h \ +--- 48,77 ---- + ### Dependencies: + console.s console.o : console.c ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \ +! ../../include/linux/mm.h ../../include/linux/kernel.h \ +! ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/linux/timer.h ../../include/linux/tty.h \ +! ../../include/termios.h ../../include/linux/config.h ../../include/asm/io.h \ + ../../include/asm/system.h ../../include/asm/segment.h \ + ../../include/string.h ../../include/errno.h + pty.s pty.o : pty.c ../../include/linux/tty.h ../../include/termios.h \ + ../../include/sys/types.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/asm/system.h \ +! ../../include/asm/io.h + serial.s serial.o : serial.c ../../include/linux/tty.h ../../include/termios.h \ + ../../include/sys/types.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/linux/timer.h \ +! ../../include/asm/system.h ../../include/asm/io.h + tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \ + ../../include/signal.h ../../include/sys/types.h ../../include/unistd.h \ + ../../include/sys/stat.h ../../include/sys/time.h ../../include/time.h \ +*************** +*** 80,93 **** + ../../include/sys/param.h ../../include/sys/resource.h \ + ../../include/utime.h ../../include/fcntl.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 ../../include/asm/system.h + tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.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/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h ../../include/linux/tty.h \ + ../../include/asm/io.h ../../include/asm/segment.h \ + ../../include/asm/system.h +--- 79,94 ---- + ../../include/sys/param.h ../../include/sys/resource.h \ + ../../include/utime.h ../../include/fcntl.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/linux/tty.h \ +! ../../include/termios.h ../../include/asm/segment.h \ +! ../../include/asm/system.h + tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.h \ + ../../include/sys/types.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/linux/tty.h \ + ../../include/asm/io.h ../../include/asm/segment.h \ + ../../include/asm/system.h +*** ../0.95a/linux/kernel/chr_drv/console.c Fri Mar 13 00:37:07 1992 +--- linux/kernel/chr_drv/console.c Thu Mar 19 21:15:03 1992 +*************** +*** 456,462 **** + p++; + } + sti(); +! copy_to_cooked(tty); + } + + static void insert_char(int currcons) +--- 456,462 ---- + p++; + } + sti(); +! TTY_READ_FLUSH(tty); + } + + static void insert_char(int currcons) +*************** +*** 823,829 **** + + void do_keyboard_interrupt(void) + { +! copy_to_cooked(TTY_TABLE(0)); + timer_active &= ~(1<stopped = 1; +! TTY_WRITE(tty); + return 0; + case TCOON: + tty->stopped = 0; +! TTY_WRITE(tty); + return 0; + case TCIOFF: + if (STOP_CHAR(tty)) +--- 260,270 ---- + switch (arg) { + case TCOOFF: + tty->stopped = 1; +! TTY_WRITE_FLUSH(tty); + return 0; + case TCOON: + tty->stopped = 0; +! TTY_WRITE_FLUSH(tty); + return 0; + case TCIOFF: + if (STOP_CHAR(tty)) +*** ../0.95a/linux/kernel/chr_drv/tty_io.c Tue Mar 17 22:46:46 1992 +--- linux/kernel/chr_drv/tty_io.c Sat Apr 4 02:47:57 1992 +*************** +*** 129,141 **** + printk("copy_to_cooked: missing queues\n\r"); + return; + } +- cli(); +- if (tty->busy) { +- sti(); +- return; +- } +- tty->busy = 1; +- sti(); + while (1) { + if (EMPTY(tty->read_q)) + break; +--- 129,134 ---- +*************** +*** 167,172 **** +--- 160,166 ---- + if (c<32) + PUTCH(127,tty->write_q); + PUTCH(127,tty->write_q); ++ TTY_WRITE_FLUSH(tty); + } + DEC(tty->secondary->head); + } +*************** +*** 183,188 **** +--- 177,183 ---- + if (c<32) + PUTCH(127,tty->write_q); + PUTCH(127,tty->write_q); ++ TTY_WRITE_FLUSH(tty); + } + DEC(tty->secondary->head); + continue; +*************** +*** 197,202 **** +--- 192,198 ---- + if ((START_CHAR(tty) != _POSIX_VDISABLE) && + (c==START_CHAR(tty))) { + tty->stopped=0; ++ TTY_WRITE_FLUSH(tty); + continue; + } + } +*************** +*** 232,242 **** + PUTCH(c,tty->write_q); + } + PUTCH(c,tty->secondary); + } +! tty->write(tty); +! tty->busy = 0; + if (!EMPTY(tty->secondary)) + wake_up(&tty->secondary->proc_list); + } + + /* +--- 228,240 ---- + PUTCH(c,tty->write_q); + } + PUTCH(c,tty->secondary); ++ TTY_WRITE_FLUSH(tty); + } +! TTY_WRITE_FLUSH(tty); + if (!EMPTY(tty->secondary)) + wake_up(&tty->secondary->proc_list); ++ if (LEFT(tty->write_q) > TTY_BUF_SIZE/2) ++ wake_up(&tty->write_q->proc_list); + } + + /* +*************** +*** 305,314 **** + time = current->timeout = 0; + if (minimum>nr) + minimum = nr; +! copy_to_cooked(tty); + while (nr>0) { + if (other_tty && other_tty->write) +! TTY_WRITE(other_tty); + cli(); + if (EMPTY(tty->secondary) || (L_CANON(tty) && + !FULL(tty->read_q) && !tty->secondary->data)) { +--- 303,312 ---- + time = current->timeout = 0; + if (minimum>nr) + minimum = nr; +! TTY_READ_FLUSH(tty); + while (nr>0) { + if (other_tty && other_tty->write) +! TTY_WRITE_FLUSH(other_tty); + cli(); + if (EMPTY(tty->secondary) || (L_CANON(tty) && + !FULL(tty->read_q) && !tty->secondary->data)) { +*************** +*** 320,326 **** + break; + interruptible_sleep_on(&tty->secondary->proc_list); + sti(); +! copy_to_cooked(tty); + continue; + } + sti(); +--- 318,324 ---- + break; + interruptible_sleep_on(&tty->secondary->proc_list); + sti(); +! TTY_READ_FLUSH(tty); + continue; + } + sti(); +*************** +*** 398,404 **** + cr_flag = 0; + PUTCH(c,tty->write_q); + } +! TTY_WRITE(tty); + if (nr>0) + schedule(); + } +--- 396,402 ---- + cr_flag = 0; + PUTCH(c,tty->write_q); + } +! TTY_WRITE_FLUSH(tty); + if (nr>0) + schedule(); + } +*** ../0.95a/linux/kernel/chr_drv/serial.c Sat Mar 14 20:16:21 1992 +--- linux/kernel/chr_drv/serial.c Thu Mar 19 21:15:03 1992 +*************** +*** 26,47 **** + + static void com1_timer(void) + { +! copy_to_cooked(tty_table+64); + } + + static void com2_timer(void) + { +! copy_to_cooked(tty_table+65); + } + + static void com3_timer(void) + { +! copy_to_cooked(tty_table+66); + } + + static void com4_timer(void) + { +! copy_to_cooked(tty_table+67); + } + + static inline void do_rs_write(unsigned int port) +--- 26,47 ---- + + static void com1_timer(void) + { +! TTY_READ_FLUSH(tty_table+64); + } + + static void com2_timer(void) + { +! TTY_READ_FLUSH(tty_table+65); + } + + static void com3_timer(void) + { +! TTY_READ_FLUSH(tty_table+66); + } + + static void com4_timer(void) + { +! TTY_READ_FLUSH(tty_table+67); + } + + static inline void do_rs_write(unsigned int port) +*** ../0.95a/linux/kernel/chr_drv/pty.c Sat Jan 11 01:56:45 1992 +--- linux/kernel/chr_drv/pty.c Thu Mar 19 21:15:03 1992 +*************** +*** 25,31 **** + if (FULL(to->read_q)) { + if (FULL(to->secondary)) + break; +! copy_to_cooked(to); + continue; + } + GETCH(from->write_q,c); +--- 25,31 ---- + if (FULL(to->read_q)) { + if (FULL(to->secondary)) + break; +! TTY_READ_FLUSH(to); + continue; + } + GETCH(from->write_q,c); +*************** +*** 33,39 **** + if (current->signal & ~current->blocked) + break; + } +! copy_to_cooked(to); + wake_up(&from->write_q->proc_list); + } + +--- 33,39 ---- + if (current->signal & ~current->blocked) + break; + } +! TTY_READ_FLUSH(to); + wake_up(&from->write_q->proc_list); + } + +*** ../0.95a/linux/kernel/math/Makefile Wed Mar 4 06:14:15 1992 +--- linux/kernel/math/Makefile Sat Apr 4 17:06:02 1992 +*************** +*** 10,27 **** + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ +! -finline-functions -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 = math_emulate.o error.o convert.o ea.o get_put.o \ +--- 10,25 ---- + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc -nostdinc -I../../include +! CPP =cpp -nostdinc -I../../include + + .c.s: +! $(CC) $(CFLAGS) $(MATH_EMULATION) \ + -S -o $*.s $< + .s.o: + $(AS) -c -o $*.o $< + .c.o: +! $(CC) $(CFLAGS) $(MATH_EMULATION) \ + -c -o $*.o $< + + OBJS = math_emulate.o error.o convert.o ea.o get_put.o \ +*** ../0.95a/linux/kernel/math/math_emulate.c Thu Mar 5 22:32:44 1992 +--- linux/kernel/math/math_emulate.c Sat Apr 4 17:05:42 1992 +*************** +*** 30,37 **** + * hide most of the 387-specific things here. + */ + +- #include +- + #ifdef KERNEL_MATH_EMULATION + + #include +--- 30,35 ---- +*************** +*** 172,183 **** + real_to_real(&tmp,&ST(0)); + return; + case 0x1a: +! fcom(PST(code & 7),&tmp); +! real_to_real(&tmp,&ST(0)); + return; + case 0x1b: +! fcom(PST(code & 7),&tmp); +! real_to_real(&tmp,&ST(0)); + fpop(); + return; + case 0x1c: +--- 170,179 ---- + real_to_real(&tmp,&ST(0)); + return; + case 0x1a: +! fcom(PST(code & 7),PST(0)); + return; + case 0x1b: +! fcom(PST(code & 7),PST(0)); + fpop(); + return; + case 0x1c: +*************** +*** 201,207 **** + return; + case 0x38: + fpush(); +! ST(0) = ST((code & 7)+1); + return; + case 0x39: + fxchg(&ST(0),&ST(code & 7)); +--- 197,203 ---- + return; + case 0x38: + fpush(); +! ST(0) = ST((code+1) & 7); + return; + case 0x39: + fxchg(&ST(0),&ST(code & 7)); +*** ../0.95a/linux/kernel/blk_drv/hd.c Sun Mar 15 20:46:53 1992 +--- linux/kernel/blk_drv/hd.c Sat Apr 4 14:42:37 1992 +*************** +*** 16,21 **** +--- 16,23 ---- + * in the early extended-partition checks and added DM partitions + */ + ++ #include ++ + #include + #include + #include +*************** +*** 43,49 **** + static void bad_rw_intr(void); + + static int recalibrate = 0; +! static int reset = 1; + + /* + * This struct defines the HD's and their types. +--- 45,51 ---- + static void bad_rw_intr(void); + + static int recalibrate = 0; +! static int reset = 0; + + /* + * This struct defines the HD's and their types. +*************** +*** 77,104 **** + + static unsigned int current_minor; + + static void check_partition(unsigned int dev) + { +! int minor, i; + struct buffer_head *bh; + struct partition *p; + + if (!(bh = bread(dev,0))) { + printk("Unable to read partition table of device %04x\n",dev); + return; + } +! minor = current_minor; + if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { + p = 0x1BE + (void *)bh->b_data; +! for (i=0 ; i<4 ; i++,p++) { +! if (!(hd[i+minor].nr_sects = p->nr_sects)) + continue; +! hd[i+minor].start_sect = p->start_sect; + if ((current_minor & 0x3f) >= 60) + continue; + if (p->sys_ind == EXTENDED_PARTITION) { +! current_minor += 4; +! check_partition(0x0300 | (i+minor)); + } + } + /* +--- 79,181 ---- + + static unsigned int current_minor; + ++ /* ++ * Create devices for each logical partition in an extended partition. ++ * The logical partitions form a linked list, with each entry being ++ * a partition table with two entries. The first entry ++ * is the real data partition (with a start relative to the partition ++ * table start). The second is a pointer to the next logical partition ++ * (with a start relative to the entire extended partition). ++ * We do not create a Linux partition for the partition tables, but ++ * only for the actual data partitions. ++ */ ++ static void extended_partition(unsigned int dev) ++ { ++ struct buffer_head *bh; ++ struct partition *p; ++ unsigned long first_sector, this_sector; ++ ++ first_sector = hd[MINOR(dev)].start_sect; ++ this_sector = first_sector; ++ ++ while (1) { ++ if ((current_minor & 0x3f) >= 60) ++ return; ++ if (!(bh = bread(dev,0))) { ++ printk("Unable to read partition table of device %04x\n",dev); ++ return; ++ } ++ /* ++ * This block is from a device that we're about to stomp on. ++ * So make sure nobody thinks this block is usable. ++ */ ++ bh->b_dirt=0; ++ bh->b_uptodate=0; ++ if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { ++ p = 0x1BE + (void *)bh->b_data; ++ /* ++ * Process the first entry, which should be the real ++ * data partition. ++ */ ++ if (p->sys_ind == EXTENDED_PARTITION || ++ !(hd[current_minor].nr_sects = p->nr_sects)) ++ goto done; /* shouldn't happen */ ++ hd[current_minor].start_sect = this_sector + p->start_sect; ++ printk(" Logical part %d start %d size %d end %d\n\r", ++ current_minor, hd[current_minor].start_sect, ++ hd[current_minor].nr_sects, ++ hd[current_minor].start_sect + ++ hd[current_minor].nr_sects); ++ current_minor++; ++ p++; ++ /* ++ * Process the second entry, which should be a link ++ * to the next logical partition. Create a minor ++ * for this just long enough to get the next partition ++ * table. The minor will be reused for the real ++ * data partition. ++ */ ++ if (p->sys_ind != EXTENDED_PARTITION || ++ !(hd[current_minor].nr_sects = p->nr_sects)) ++ goto done; /* no more logicals in this partition */ ++ hd[current_minor].start_sect = first_sector + p->start_sect; ++ this_sector = first_sector + p->start_sect; ++ dev = 0x0300 | current_minor; ++ brelse(bh); ++ } else ++ goto done; ++ } ++ done: ++ brelse(bh); ++ } ++ + static void check_partition(unsigned int dev) + { +! int i, minor = current_minor; + struct buffer_head *bh; + struct partition *p; ++ unsigned long first_sector; + ++ first_sector = hd[MINOR(dev)].start_sect; + if (!(bh = bread(dev,0))) { + printk("Unable to read partition table of device %04x\n",dev); + return; + } +! printk("Drive %d:\n\r",minor >> 6); +! current_minor += 4; /* first "extra" minor */ + if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { + p = 0x1BE + (void *)bh->b_data; +! for (i=1 ; i<=4 ; minor++,i++,p++) { +! if (!(hd[minor].nr_sects = p->nr_sects)) + continue; +! hd[minor].start_sect = first_sector + p->start_sect; +! printk(" part %d start %d size %d end %d \n\r", i, +! hd[minor].start_sect, hd[minor].nr_sects, +! hd[minor].start_sect + hd[minor].nr_sects); + if ((current_minor & 0x3f) >= 60) + continue; + if (p->sys_ind == EXTENDED_PARTITION) { +! extended_partition(0x0300 | minor); + } + } + /* +*************** +*** 106,119 **** + */ + if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) { + p = 0x1BE + (void *)bh->b_data; +! for (i=4; i<16; i++) { + p--; + if ((current_minor & 0x3f) >= 60) + break; +! if (!(hd[current_minor+4].start_sect = p->start_sect)) + continue; +! hd[current_minor+4].nr_sects = p->nr_sects; +! current_minor++; + } + } + } else +--- 183,202 ---- + */ + if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) { + p = 0x1BE + (void *)bh->b_data; +! for (i = 4 ; i < 16 ; i++, current_minor++) { + p--; + if ((current_minor & 0x3f) >= 60) + break; +! if (!(p->start_sect && p->nr_sects)) + continue; +! hd[current_minor].start_sect = p->start_sect; +! hd[current_minor].nr_sects = p->nr_sects; +! printk(" DM part %d start %d size %d end %d\n\r", +! current_minor, +! hd[current_minor].start_sect, +! hd[current_minor].nr_sects, +! hd[current_minor].start_sect + +! hd[current_minor].nr_sects); + } + } + } else +*************** +*** 141,156 **** + hd_info[drive].sect = *(unsigned char *) (14+BIOS); + BIOS += 16; + } +- if (hd_info[1].cyl) +- NR_HD=2; +- else +- NR_HD=1; +- #endif +- for (i=0 ; ierrors >= MAX_ERRORS) + end_request(0); + if (CURRENT->errors > MAX_ERRORS/2) +*************** +*** 361,366 **** +--- 448,457 ---- + do_hd_request(); + } + ++ /* ++ * This is another of the error-routines I don't know what to do with. The ++ * best idea seems to just set reset, and start all over again. ++ */ + static void hd_times_out(void) + { + do_hd = NULL; +*************** +*** 367,379 **** + reset = 1; + if (!CURRENT) + return; +! printk("HD timeout"); + if (++CURRENT->errors >= MAX_ERRORS) + end_request(0); + do_hd_request(); + } + +! void do_hd_request(void) + { + int i,r; + unsigned int block,dev; +--- 458,471 ---- + reset = 1; + if (!CURRENT) + return; +! printk("HD timeout\n\r"); +! cli(); + if (++CURRENT->errors >= MAX_ERRORS) + end_request(0); + do_hd_request(); + } + +! static void do_hd_request(void) + { + int i,r; + unsigned int block,dev; +*************** +*** 434,437 **** +--- 526,553 ---- + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xbf,0xA1); + timer_table[HD_TIMER].fn = hd_times_out; ++ } ++ ++ int hd_ioctl(int dev, int cmd, int arg) ++ { ++ struct hd_geometry *loc = (void *) arg; ++ ++ if (!loc) ++ return -EINVAL; ++ dev = MINOR(dev) >> 6; ++ if (dev >= NR_HD) ++ return -EINVAL; ++ ++ switch (cmd) { ++ case HDIO_REQ: ++ put_fs_byte(hd_info[dev].head, ++ (char *) &loc->heads); ++ put_fs_byte(hd_info[dev].sect, ++ (char *) &loc->sectors); ++ put_fs_word(hd_info[dev].cyl, ++ (short *) &loc->cylinders); ++ return 0; ++ default: ++ return -EINVAL; ++ } + } +*** ../0.95a/linux/kernel/blk_drv/ll_rw_blk.c Fri Mar 6 03:04:44 1992 +--- linux/kernel/blk_drv/ll_rw_blk.c Sat Mar 21 12:42:01 1992 +*************** +*** 83,90 **** + req->bh->b_dirt = 0; + if (!(tmp = dev->current_request)) { + dev->current_request = req; +- sti(); + (dev->request_fn)(); + return; + } + for ( ; tmp->next ; tmp = tmp->next) { +--- 83,90 ---- + req->bh->b_dirt = 0; + if (!(tmp = dev->current_request)) { + dev->current_request = req; + (dev->request_fn)(); ++ sti(); + return; + } + for ( ; tmp->next ; tmp = tmp->next) { +*** ../0.95a/linux/kernel/blk_drv/Makefile Thu Mar 5 23:37:04 1992 +--- linux/kernel/blk_drv/Makefile Sat Apr 4 17:33:28 1992 +*************** +*** 5,19 **** + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # + + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \ +! -finline-functions -nostdinc -I../../include +! CPP =gcc -E -nostdinc -I../../include + + .c.s: + $(CC) $(CFLAGS) \ +--- 5,20 ---- + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # ++ # Note 2! The CFLAGS definition is now inherited from the ++ # parent makefile. ++ # + + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc -nostdinc -I../../include +! CPP =cpp -nostdinc -I../../include + + .c.s: + $(CC) $(CFLAGS) \ +*************** +*** 42,56 **** + + ### Dependencies: + floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h \ +! ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/fdreg.h \ + ../../include/asm/system.h ../../include/asm/io.h \ + ../../include/asm/segment.h blk.h +! hd.s hd.o : hd.c ../../include/linux/config.h ../../include/linux/sched.h \ +! ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/timer.h \ +--- 43,59 ---- + + ### Dependencies: + floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h \ +! ../../include/linux/fs.h ../../include/sys/types.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/fdreg.h \ + ../../include/asm/system.h ../../include/asm/io.h \ + ../../include/asm/segment.h blk.h +! hd.s hd.o : hd.c ../../include/errno.h ../../include/linux/config.h \ +! ../../include/linux/sched.h ../../include/linux/head.h \ +! ../../include/linux/fs.h ../../include/sys/types.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/timer.h \ +*************** +*** 58,70 **** + ../../include/asm/io.h ../../include/asm/segment.h blk.h + ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/types.h ../../include/linux/mm.h \ +! ../../include/linux/kernel.h ../../include/signal.h \ +! ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ +! ../../include/sys/resource.h ../../include/asm/system.h blk.h + ramdisk.s ramdisk.o : ramdisk.c ../../include/string.h ../../include/linux/config.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ +! ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/minix_fs.h \ +--- 61,75 ---- + ../../include/asm/io.h ../../include/asm/segment.h blk.h + ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \ + ../../include/linux/head.h ../../include/linux/fs.h \ +! ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \ +! ../../include/linux/mm.h ../../include/linux/kernel.h \ +! ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \ +! ../../include/time.h ../../include/sys/resource.h \ +! ../../include/asm/system.h blk.h + ramdisk.s ramdisk.o : ramdisk.c ../../include/string.h ../../include/linux/config.h \ + ../../include/linux/sched.h ../../include/linux/head.h \ +! ../../include/linux/fs.h ../../include/sys/types.h \ +! ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \ + ../../include/linux/kernel.h ../../include/signal.h \ + ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \ + ../../include/sys/resource.h ../../include/linux/minix_fs.h \ +*** ../0.95a/linux/kernel/blk_drv/blk.h Thu Mar 12 03:42:41 1992 +--- linux/kernel/blk_drv/blk.h Fri Apr 3 15:28:31 1992 +*************** +*** 78,87 **** + #define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) + + #elif (MAJOR_NR == 3) +! /* harddisk */ + #define DEVICE_NAME "harddisk" + #define DEVICE_INTR do_hd + #define DEVICE_TIMEOUT HD_TIMER + #define DEVICE_REQUEST do_hd_request + #define DEVICE_NR(device) (MINOR(device)>>6) + #define DEVICE_ON(device) +--- 78,88 ---- + #define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) + + #elif (MAJOR_NR == 3) +! /* harddisk: timeout is 6 seconds.. */ + #define DEVICE_NAME "harddisk" + #define DEVICE_INTR do_hd + #define DEVICE_TIMEOUT HD_TIMER ++ #define TIMEOUT_VALUE 600 + #define DEVICE_REQUEST do_hd_request + #define DEVICE_NR(device) (MINOR(device)>>6) + #define DEVICE_ON(device) +*************** +*** 101,110 **** + #endif + #ifdef DEVICE_TIMEOUT + +! #define SET_INTR(x) if (DEVICE_INTR = (x)) { \ +! timer_table[DEVICE_TIMEOUT].expires = jiffies + 200; \ +! timer_active |= 1< + #include +*************** +*** 22,30 **** + /* set's the trap flag. */ + #define TRAP_FLAG 0x100 + +- /* check's for granularity. */ +- #define GRANULARITY 0x00800000 +- + /* + * this is the number to subtract from the top of the stack. To find + * the local frame. +--- 23,28 ---- +*************** +*** 51,58 **** + * the offset is how far from the base addr as stored in the TSS. + * this routine assumes that all the priviledged stacks are in our + * data space. +! */ +! + static inline int get_stack_long(struct task_struct *task, int offset) + { + unsigned char *stack; +--- 49,55 ---- + * the offset is how far from the base addr as stored in the TSS. + * this routine assumes that all the priviledged stacks are in our + * data space. +! */ + static inline int get_stack_long(struct task_struct *task, int offset) + { + unsigned char *stack; +*************** +*** 69,213 **** + * data space. + */ + static inline int put_stack_long(struct task_struct *task, int offset, +! unsigned short data) + { + unsigned char * stack; + + stack = (unsigned char *) task->tss.esp0; + stack += offset; +! *(int *) stack = data; + return 0; + } + + /* +! * this routine will get a word out of an arbitrary +! * tasks data space. It likes to have the task number +! * rather than the task pointer. Perhaps the number +! * should be included in the pointer. + */ +! /* seg = 0 if I space */ +! static inline int get_long(int tsk, long addr, unsigned seg, int *data) + { +- int i; +- int limit; +- int cur; +- unsigned long address; + unsigned long page; +- unsigned oldfs; + +! /* find the task number of the current task. */ +! for (i = 0; i < NR_TASKS ; i ++) { +! if (task[i] == current) break; + } +- if (i == NR_TASKS) { +- printk("PTRACE: Can't find current task\n"); +- do_exit(SIGSEGV); +- } +- cur = i; +- +- /* we will need to check the readability of the segment +- and then the byte in order to avoid segment violations. */ +- seg++; +- limit = (task[tsk]->ldt[seg].a) & 0xffff; +- /* this should be constant amound all of our segments, but we +- had better check anyway. */ +- if (task[tsk]->ldt[seg].b & GRANULARITY) +- limit = limit << 12; +- +- if (limit <= addr+4) +- return -EIO; +- +- /* Now compute the address, and make sure that it is present. */ +- address = task[tsk]->start_code + addr; +- +- page = *((unsigned long*) ((address >> 20) & 0xffc)); +- /* see if it is present. */ + if (!(page & PAGE_PRESENT)) { +! do_no_page(0, address, task[tsk]); + } +! +! oldfs = get_fs(); +! /* now convert seg to the right format. */ +! seg = (seg << 3) | 0x4; +! +! cli(); /* we are about to change our ldt, we better do it +! with interrupts off. Perhaps we should call schedule +! first so that we won't be taking too much extra time. */ +! lldt(tsk); +! set_fs(seg); +! *data = get_fs_long((void *)addr); /* we are assuming kernel space +! is in the gdt here. */ +! lldt(cur); +! set_fs(oldfs); +! sti(); +! return 0; + } + + /* +! * this routine will get a word out of an arbitrary +! * tasks data space. It likes to have the task number +! * rather than the task pointer. Perhaps the number +! * should be included in the pointer. + */ +! /* seg = 0 if I space */ +! static inline int put_long(int tsk, long addr, int data, unsigned seg) + { +- int i; +- int limit; +- unsigned oldfs; +- unsigned long address; + unsigned long page; +- int cur; + +! /* find the task number of the current task. */ +! for (i = 0; i < NR_TASKS ; i++) { +! if (task[i] == current) break; + } +! if (i == NR_TASKS) { +! printk("PTRACE: Can't find current task\n"); +! do_exit(SIGSEGV); + } +! cur = i; + +! /* we will need to check the readability of the segment +! and then the byte in order to avoid segment violations. */ +! seg++; +! limit = (task[tsk]->ldt[seg].a) & 0xffff; +! /* this should be constant amound all of our segments, but we +! had better check anyway. */ +! if (task[tsk]->ldt[seg].b & GRANULARITY) +! limit = limit << 12; + +! if (limit <= addr+4) + return -EIO; + +! /* Now compute the address, and make sure that it is present. */ +! address = task[tsk]->start_code + addr; + +! page = *((unsigned long*) ((address >> 20) & 0xffc)); +! /* see if it is present. */ +! if (!(page & PAGE_PRESENT)) { +! do_no_page(0, address, task[tsk]); +! } +! write_verify(address); +! +! oldfs=get_fs(); +! /* now convert seg to the right format. */ +! seg = (seg << 3) | 0x4; +! +! cli(); /* we are about to change our ldt, we better do it +! with interrupts off. Perhaps we should call schedule +! first so that we won't be taking too much extra time. */ +! lldt(tsk); +! set_fs(seg); +! put_fs_long(data,(void *)addr); +! lldt(cur); +! set_fs(oldfs); +! sti(); + return 0; + } + +- + /* Perform ptrace(request, pid, addr, data) syscall */ + int sys_ptrace(unsigned long *buffer) + { +--- 66,224 ---- + * data space. + */ + static inline int put_stack_long(struct task_struct *task, int offset, +! unsigned long data) + { + unsigned char * stack; + + stack = (unsigned char *) task->tss.esp0; + stack += offset; +! *(unsigned long *) stack = data; + return 0; + } + + /* +! * This routine gets a long from any process space by following the page +! * tables. NOTE! You should check that the long isn't on a page boundary, +! * and that it is in the task area before calling this: this routine does +! * no checking. +! * +! * NOTE2! This uses "tsk->tss.cr3" even though we know it's currently always +! * zero. This routine shouldn't have to change when we make a better mm. + */ +! static unsigned long get_long(struct task_struct * tsk, +! unsigned long addr) + { + unsigned long page; + +! addr += tsk->start_code; +! repeat: +! page = tsk->tss.cr3 + ((addr >> 20) & 0xffc); +! page = *(unsigned long *) page; +! if (page & PAGE_PRESENT) { +! page &= 0xfffff000; +! page += (addr >> 10) & 0xffc; +! page = *((unsigned long *) page); + } + if (!(page & PAGE_PRESENT)) { +! do_no_page(0,addr,tsk); +! goto repeat; + } +! page &= 0xfffff000; +! page += addr & 0xfff; +! return *(unsigned long *) page; + } + + /* +! * This routine puts a long into any process space by following the page +! * tables. NOTE! You should check that the long isn't on a page boundary, +! * and that it is in the task area before calling this: this routine does +! * no checking. + */ +! static void put_long(struct task_struct * tsk, unsigned long addr, +! unsigned long data) + { + unsigned long page; + +! addr += tsk->start_code; +! repeat: +! page = tsk->tss.cr3 + ((addr >> 20) & 0xffc); +! page = *(unsigned long *) page; +! if (page & PAGE_PRESENT) { +! page &= 0xfffff000; +! page += (addr >> 10) & 0xffc; +! page = *((unsigned long *) page); + } +! if (!(page & PAGE_PRESENT)) { +! do_no_page(0,addr,tsk); +! goto repeat; + } +! if (!(page & PAGE_RW)) { +! write_verify(addr); +! goto repeat; +! } +! page &= 0xfffff000; +! page += addr & 0xfff; +! *(unsigned long *) page = data; +! } + +! /* +! * This routine checks the page boundaries, and that the offset is +! * within the task area. It then calls get_long() to read a long. +! */ +! static int read_long(struct task_struct * tsk, unsigned long addr, +! unsigned long * result) +! { +! unsigned long low,high; + +! if (addr > TASK_SIZE-4) + return -EIO; ++ if ((addr & 0xfff) > PAGE_SIZE-4) { ++ low = get_long(tsk,addr & 0xfffffffc); ++ high = get_long(tsk,(addr+4) & 0xfffffffc); ++ switch (addr & 3) { ++ case 1: ++ low >>= 8; ++ low |= high << 24; ++ break; ++ case 2: ++ low >>= 16; ++ low |= high << 16; ++ break; ++ case 3: ++ low >>= 24; ++ low |= high << 8; ++ break; ++ } ++ *result = low; ++ } else ++ *result = get_long(tsk,addr); ++ return 0; ++ } + +! /* +! * This routine checks the page boundaries, and that the offset is +! * within the task area. It then calls put_long() to write a long. +! */ +! static int write_long(struct task_struct * tsk, unsigned long addr, +! unsigned long data) +! { +! unsigned long low,high; + +! if (addr > TASK_SIZE-4) +! return -EIO; +! if ((addr & 0xfff) > PAGE_SIZE-4) { +! low = get_long(tsk,addr & 0xfffffffc); +! high = get_long(tsk,(addr+4) & 0xfffffffc); +! switch (addr & 3) { +! case 0: /* shouldn't happen, but safety first */ +! low = data; +! break; +! case 1: +! low &= 0x000000ff; +! low |= data << 8; +! high &= 0xffffff00; +! high |= data >> 24; +! break; +! case 2: +! low &= 0x0000ffff; +! low |= data << 16; +! high &= 0xffff0000; +! high |= data >> 16; +! break; +! case 3: +! low &= 0x00ffffff; +! low |= data << 24; +! high &= 0xff000000; +! high |= data >> 8; +! break; +! } +! put_long(tsk,addr & 0xfffffffc,low); +! put_long(tsk,(addr+4) & 0xfffffffc,high); +! } else +! put_long(tsk,addr,data); + return 0; + } + + /* Perform ptrace(request, pid, addr, data) syscall */ + int sys_ptrace(unsigned long *buffer) + { +*************** +*** 244,250 **** + case 2: { + int tmp,res; + +! res = get_long(childno, addr, 1, &tmp); + if (res < 0) + return res; + verify_area((void *) data, 4); +--- 255,261 ---- + case 2: { + int tmp,res; + +! res = read_long(task[childno], addr, &tmp); + if (res < 0) + return res; + verify_area((void *) data, 4); +*************** +*** 267,280 **** + /* when I and D space are seperate, this will have to be fixed. */ + case 4: /* write the word at location addr. */ + case 5: +! if (put_long(childno, addr, data, 1)) +! return -EIO; +! return 0; + + case 6: /* write the word at location addr in the USER area */ + addr = addr >> 2; /* temproary hack. */ + if (addr < 0 || addr >= 17) +! return -EIO; + if (addr == ORIG_EAX) + return -EIO; + if (addr == EFL) { /* flags. */ +--- 278,289 ---- + /* when I and D space are seperate, this will have to be fixed. */ + case 4: /* write the word at location addr. */ + case 5: +! return write_long(task[childno],addr,data); + + case 6: /* write the word at location addr in the USER area */ + addr = addr >> 2; /* temproary hack. */ + if (addr < 0 || addr >= 17) +! return -EIO; + if (addr == ORIG_EAX) + return -EIO; + if (addr == EFL) { /* flags. */ +*************** +*** 281,287 **** + data &= FLAG_MASK; + data |= get_stack_long(child, EFL*4-MAGICNUMBER) & ~FLAG_MASK; + } +- + if (put_stack_long(child, 4*addr-MAGICNUMBER, data)) + return -EIO; + return 0; +--- 290,295 ---- +*** ../0.95a/linux/lib/Makefile Thu Mar 5 20:23:23 1992 +--- linux/lib/Makefile Sat Apr 4 17:00:10 1992 +*************** +*** 6,22 **** + # unless it's something special (ie not a .c file). + # + +- # gcc2 doesn't understand some options.. +- # GCC_OPT = -fcombine-regs +- + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc +! CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) \ +! -finline-functions -nostdinc -I../include +! CPP =gcc -E -nostdinc -I../include + + .c.s: + $(CC) $(CFLAGS) \ +--- 6,17 ---- + # unless it's something special (ie not a .c file). + # + + AR =ar + AS =as + LD =ld + LDFLAGS =-s -x +! CC =gcc -nostdinc -I../include +! CPP =cpp -nostdinc -I../include + + .c.s: + $(CC) $(CFLAGS) \ +*** ../0.95a/linux/mm/Makefile Tue Mar 17 11:57:15 1992 +--- linux/mm/Makefile Sat Apr 4 17:33:29 1992 +*************** +*** 1,10 **** +! CC =gcc +! CFLAGS =-O -Wall -fstrength-reduce -fomit-frame-pointer \ +! -finline-functions -nostdinc -I../include + AS =as + AR =ar + LD =ld +! CPP =gcc -E -nostdinc -I../include + + .c.o: + $(CC) $(CFLAGS) \ +--- 1,17 ---- +! # +! # Makefile for the linux memory manager. +! # +! # 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). +! # +! # Note 2! The CFLAGS definition is now in the main makefile... +! + AS =as + AR =ar + LD =ld +! CC =gcc -nostdinc -I../include +! CPP =cpp -nostdinc -I../include + + .c.o: + $(CC) $(CFLAGS) \ +*************** +*** 32,42 **** + ### Dependencies: + memory.o : memory.c ../include/signal.h ../include/sys/types.h \ + ../include/asm/system.h ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \ +! ../include/sys/param.h ../include/sys/time.h ../include/time.h \ +! ../include/sys/resource.h + swap.o : swap.c ../include/string.h ../include/errno.h \ + ../include/linux/mm.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/linux/kernel.h ../include/signal.h ../include/sys/stat.h \ +! ../include/linux/sched.h ../include/linux/head.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h +--- 39,50 ---- + ### Dependencies: + memory.o : memory.c ../include/signal.h ../include/sys/types.h \ + ../include/asm/system.h ../include/linux/sched.h ../include/linux/head.h \ +! ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \ +! ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \ +! ../include/sys/time.h ../include/time.h ../include/sys/resource.h + swap.o : swap.c ../include/string.h ../include/errno.h \ + ../include/linux/mm.h ../include/linux/fs.h ../include/sys/types.h \ +! ../include/sys/dirent.h ../include/limits.h ../include/linux/kernel.h \ +! ../include/signal.h ../include/sys/stat.h ../include/linux/sched.h \ +! ../include/linux/head.h ../include/sys/param.h ../include/sys/time.h \ +! ../include/time.h ../include/sys/resource.h +*** ../0.95a/linux/mm/memory.c Tue Mar 17 22:35:13 1992 +--- linux/mm/memory.c Wed Apr 1 01:28:30 1992 +*************** +*** 165,170 **** +--- 165,171 ---- + if (!(1 & this_page)) { + if (!(new_page = get_free_page())) + return -1; ++ ++current->rss; + read_swap_page(this_page>>1, (char *) new_page); + *to_page_table = this_page; + *from_page_table = new_page | (PAGE_DIRTY | 7); +*************** +*** 316,321 **** +--- 317,323 ---- + printk("Bad things happen: page error in do_wp_page\n\r"); + do_exit(SIGSEGV); + } ++ ++current->min_flt; + un_wp_page((unsigned long *) + (((address>>10) & 0xffc) + (0xfffff000 & + *((unsigned long *) ((address>>20) &0xffc))))); +*************** +*** 429,436 **** + return 0; + } + +! void do_no_page(unsigned long error_code, +! unsigned long address, struct task_struct *tsk) + { + static unsigned int last_checked = 0; + int nr[4]; +--- 431,438 ---- + return 0; + } + +! void do_no_page(unsigned long error_code, unsigned long address, +! struct task_struct *tsk) + { + static unsigned int last_checked = 0; + int nr[4]; +*************** +*** 439,445 **** + int block,i; + struct inode * inode; + +! /* Trashing ? Make it interruptible, but don't penalize otherwise */ + for (i = 0; i < CHECK_LAST_NR; i++) + if ((address & 0xfffff000) == last_pages[i]) { + current->counter = 0; +--- 441,447 ---- + int block,i; + struct inode * inode; + +! /* Thrashing ? Make it interruptible, but don't penalize otherwise */ + for (i = 0; i < CHECK_LAST_NR; i++) + if ((address & 0xfffff000) == last_pages[i]) { + current->counter = 0; +*************** +*** 457,462 **** +--- 459,465 ---- + printk("Bad things happen: nonexistent page error in do_no_page\n\r"); + do_exit(SIGSEGV); + } ++ ++tsk->rss; + page = *(unsigned long *) ((address >> 20) & 0xffc); + /* check the page directory: make a page dir entry if no such exists */ + if (page & 1) { +*************** +*** 464,469 **** +--- 467,473 ---- + page += (address >> 10) & 0xffc; + tmp = *(unsigned long *) page; + if (tmp && !(1 & tmp)) { ++ ++tsk->maj_flt; + swap_in((unsigned long *) page); + return; + } +*************** +*** 488,499 **** + block = 0; + } + if (!inode) { + get_empty_page(address); + return; + } + if (tsk == current) +! if (share_page(inode,tmp)) +! return; + if (!(page = get_free_page())) + oom(); + /* remember that 1 block is used for header */ +--- 492,510 ---- + block = 0; + } + if (!inode) { ++ ++tsk->min_flt; ++ if (tmp > tsk->brk && tsk == current && ++ LIBRARY_OFFSET - tmp > tsk->rlim[RLIMIT_STACK].rlim_max) ++ do_exit(SIGSEGV); + get_empty_page(address); + return; + } + if (tsk == current) +! if (share_page(inode,tmp)) { +! ++tsk->min_flt; +! return; +! } +! ++tsk->maj_flt; + if (!(page = get_free_page())) + oom(); + /* remember that 1 block is used for header */ +*************** +*** 533,541 **** + void show_mem(void) + { + int i,j,k,free=0,total=0; +! int shared=0; + unsigned long * pg_tbl; + + printk("Mem-info:\n\r"); + for(i=0 ; i ++ ++ struct dirent { ++ long d_ino; ++ off_t d_off; ++ unsigned short d_reclen; ++ char d_name[NAME_MAX+1]; ++ }; ++ ++ #endif +*** ../0.95a/linux/include/unistd.h Wed Mar 4 12:56:06 1992 +--- linux/include/unistd.h Fri Apr 3 19:55:41 1992 +*************** +*** 50,55 **** +--- 50,61 ---- + #define _PC_VDISABLE 8 + #define _PC_CHOWN_RESTRICTED 9 + ++ #if 0 ++ /* XXX - illegally already. ++ * The rest of these includes are also illegal (too much pollution). ++ */ ++ #include ++ #endif + #include + #include + #include +*************** +*** 148,154 **** +--- 154,162 ---- + #define __NR_uselib 86 + #define __NR_swapon 87 + #define __NR_reboot 88 ++ #define __NR_readdir 89 + ++ /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ + #define _syscall0(type,name) \ + type name(void) \ + { \ +*************** +*** 206,224 **** + + #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); +--- 214,239 ---- + + #endif /* __LIBRARY__ */ + ++ /* XXX - illegal. */ + extern int errno; + +! /* XXX - several non-POSIX functions here, and POSIX functions that are +! * supposed to be declared elsewhere. Non-promotion of short types in +! * prototypes may cause trouble. Arg names should be prefixed by +! * underscores. +! */ +! int access(const char * filename, mode_t mode); /* XXX - short type */ + int acct(const char * filename); + int brk(void * end_data_segment); ++ /* XXX - POSIX says unsigned alarm(unsigned sec) */ ++ int alarm(int sec); + void * sbrk(ptrdiff_t increment); + int chdir(const char * filename); +! int chmod(const char * filename, mode_t mode); /* XXX - short type */ +! int chown(const char * filename, uid_t owner, gid_t group); /* XXX - shorts */ + int chroot(const char * filename); + int close(int fildes); +! int creat(const char * filename, mode_t mode); /* XXX - short type */ + int dup(int fildes); + int execve(const char * filename, char ** argv, char ** envp); + int execv(const char * pathname, char ** argv); +*************** +*** 229,255 **** + 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); +--- 244,271 ---- + volatile void exit(int status); + volatile void _exit(int status); + int fcntl(int fildes, int cmd, ...); +! pid_t fork(void); +! pid_t getpid(void); +! uid_t getuid(void); +! uid_t geteuid(void); +! gid_t getgid(void); +! gid_t getegid(void); + int ioctl(int fildes, int cmd, ...); + int kill(pid_t pid, int signal); + int link(const char * filename1, const char * filename2); +! off_t lseek(int fildes, off_t offset, int origin); +! int mknod(const char * filename, mode_t mode, dev_t dev); /* XXX - shorts */ + 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); ++ /* XXX**2 - POSIX says unsigned count */ + int read(int fildes, char * buf, off_t count); + int setpgrp(void); +! int setpgid(pid_t pid,pid_t pgid); /* XXX - short types */ +! int setuid(uid_t uid); /* XXX - short type */ +! int setgid(gid_t gid); /* XXX - short type */ + 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); +*************** +*** 266,271 **** +--- 282,288 ---- + 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); ++ /* XXX**2 - POSIX says unsigned count */ + int write(int fildes, const char * buf, off_t count); + int dup2(int oldfd, int newfd); + int getppid(void); +*** ../0.95a/linux/include/a.out.h Tue Sep 17 18:10:49 1991 +--- linux/include/a.out.h Sat Apr 4 00:41:52 1992 +*************** +*** 1,10 **** +! #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 */ +--- 1,13 ---- +! #ifndef __A_OUT_GNU_H__ +! #define __A_OUT_GNU_H__ + + #define __GNU_EXEC_MACROS__ + +! #ifndef __STRUCT_EXEC_OVERRIDE__ +! +! struct exec +! { +! unsigned long a_info; /* 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 */ +*************** +*** 14,24 **** + 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. */ +--- 17,70 ---- + unsigned a_drsize; /* length of relocation info for data, in bytes */ + }; + +! #endif /* __STRUCT_EXEC_OVERRIDE__ */ +! +! /* these go in the N_MACHTYPE field */ +! enum machine_type { +! #if defined (M_OLDSUN2) +! M__OLDSUN2 = M_OLDSUN2, +! #else +! M_OLDSUN2 = 0, + #endif ++ #if defined (M_68010) ++ M__68010 = M_68010, ++ #else ++ M_68010 = 1, ++ #endif ++ #if defined (M_68020) ++ M__68020 = M_68020, ++ #else ++ M_68020 = 2, ++ #endif ++ #if defined (M_SPARC) ++ M__SPARC = M_SPARC, ++ #else ++ M_SPARC = 3, ++ #endif ++ /* skip a bunch so we don't run into any of sun's numbers */ ++ M_386 = 100, ++ }; + +! #if !defined (N_MAGIC) +! #define N_MAGIC(exec) ((exec).a_info & 0xffff) +! #endif +! #define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) +! #define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) +! #define N_SET_INFO(exec, magic, type, flags) \ +! ((exec).a_info = ((magic) & 0xffff) \ +! | (((int)(type) & 0xff) << 16) \ +! | (((flags) & 0xff) << 24)) +! #define N_SET_MAGIC(exec, magic) \ +! ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) +! +! #define N_SET_MACHTYPE(exec, machtype) \ +! ((exec).a_info = \ +! ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) +! +! #define N_SET_FLAGS(exec, flags) \ +! ((exec).a_info = \ +! ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) +! + /* Code indicating object file or impure executable. */ + #define OMAGIC 0407 + /* Code indicating pure executable. */ +*************** +*** 25,33 **** + #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) +--- 71,78 ---- + #define NMAGIC 0410 + /* Code indicating demand-paged executable. */ + #define ZMAGIC 0413 + +! #if !defined (N_BADMAG) + #define N_BADMAG(x) \ + (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) +*************** +*** 37,71 **** + (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 + +--- 82,116 ---- + (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) + +! #define _N_HDROFF(x) (1024 - sizeof (struct exec)) + +! #if !defined (N_TXTOFF) + #define N_TXTOFF(x) \ + (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec)) + #endif + +! #if !defined (N_DATOFF) + #define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) + #endif + +! #if !defined (N_TRELOFF) + #define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data) + #endif + +! #if !defined (N_DRELOFF) + #define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize) + #endif + +! #if !defined (N_SYMOFF) + #define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize) + #endif + +! #if !defined (N_STROFF) + #define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms) + #endif + + /* Address of text segment in memory after it is loaded. */ +! #if !defined (N_TXTADDR) + #define N_TXTADDR(x) 0 + #endif + +*************** +*** 73,83 **** + 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. */ +--- 118,125 ---- + 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 sony + #define SEGMENT_SIZE 0x2000 + #endif /* Sony. */ +*************** +*** 89,96 **** + #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)) + +--- 131,140 ---- + #define SEGMENT_SIZE PAGE_SIZE + #endif + +! #ifdef linux +! #define PAGE_SIZE 4096 +! #define SEGMENT_SIZE 1024 +! #endif + + #define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1)) + +*************** +*** 103,113 **** + #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; +--- 147,157 ---- + #endif + + /* Address of bss segment in memory after it is loaded. */ +! #if !defined (N_BSSADDR) + #define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) + #endif +! +! #if !defined (N_NLIST_DECLARED) + struct nlist { + union { + char *n_name; +*************** +*** 119,155 **** + 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 + +--- 163,196 ---- + short n_desc; + unsigned long n_value; + }; +! #endif /* no N_NLIST_DECLARED. */ + +! #if !defined (N_UNDF) + #define N_UNDF 0 + #endif +! #if !defined (N_ABS) + #define N_ABS 2 + #endif +! #if !defined (N_TEXT) + #define N_TEXT 4 + #endif +! #if !defined (N_DATA) + #define N_DATA 6 + #endif +! #if !defined (N_BSS) + #define N_BSS 8 + #endif +! #if !defined (N_FN) + #define N_FN 15 + #endif + +! #if !defined (N_EXT) + #define N_EXT 1 + #endif +! #if !defined (N_TYPE) + #define N_TYPE 036 + #endif +! #if !defined (N_STAB) + #define N_STAB 0340 + #endif + +*************** +*** 182,190 **** + + /* 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. +--- 223,230 ---- + + /* This is output from LD. */ + #define N_SETV 0x1C /* Pointer to set vector in data area. */ +! +! #if !defined (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. +*************** +*** 212,218 **** +--- 252,264 ---- + unsigned int r_extern:1; + /* Four bits that aren't used, but when writing an object file + it is desirable to clear them. */ ++ #ifdef NS32K ++ unsigned r_bsr:1; ++ unsigned r_disp:1; ++ unsigned r_pad:2; ++ #else + unsigned int r_pad:4; ++ #endif + }; + #endif /* no N_RELOCATION_INFO_DECLARED. */ + +*** ../0.95a/linux/include/linux/hdreg.h Sat Feb 1 16:04:35 1992 +--- linux/include/linux/hdreg.h Tue Mar 31 20:50:13 1992 +*************** +*** 64,67 **** +--- 64,73 ---- + unsigned int nr_sects; /* nr of sectors in partition */ + }; + ++ #define HDIO_REQ 0x301 ++ struct hd_geometry { ++ unsigned char heads; ++ unsigned char sectors; ++ unsigned short cylinders; ++ }; + #endif +*** ../0.95a/linux/include/linux/sched.h Sat Mar 14 14:21:14 1992 +--- linux/include/linux/sched.h Wed Apr 1 01:37:45 1992 +*************** +*** 129,137 **** +--- 129,141 ---- + unsigned short gid,egid,sgid; + unsigned long timeout,alarm; + long utime,stime,cutime,cstime,start_time; ++ unsigned long min_flt, maj_flt; ++ unsigned long cmin_flt, cmaj_flt; + struct rlimit rlim[RLIM_NLIMITS]; + unsigned int flags; /* per process flags, defined below */ + unsigned short used_math; ++ unsigned short rss; /* number of resident pages */ ++ char comm[8]; + /* file system info */ + int link_count; + int tty; /* -1 if no tty, so it must be signed */ +*************** +*** 171,181 **** +--- 175,188 ---- + /* proc links*/ &init_task.task,NULL,NULL,NULL,NULL, \ + /* uid etc */ 0,0,0,0,0,0, \ + /* timeout */ 0,0,0,0,0,0,0, \ ++ /* min_flt */ 0,0,0,0, \ + /* rlimits */ { {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \ + {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \ + {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}}, \ + /* flags */ 0, \ + /* math */ 0, \ ++ /* rss */ 2, \ ++ /* comm */ "swapper", \ + /* fs info */ 0,-1,0022,NULL,NULL,NULL,NULL,0, \ + /* filp */ {NULL,}, \ + { \ +*** ../0.95a/linux/include/linux/sys.h Thu Feb 27 18:24:26 1992 +--- linux/include/linux/sys.h Fri Apr 3 19:56:16 1992 +*************** +*** 91,96 **** +--- 91,97 ---- + extern int sys_uselib(); + extern int sys_swapon(); + extern int sys_reboot(); ++ extern int sys_readdir(); + + 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, +*************** +*** 107,113 **** + sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_sethostname, + sys_setrlimit, sys_getrlimit, sys_getrusage, sys_gettimeofday, + sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink, +! sys_lstat, sys_readlink, sys_uselib, sys_swapon, sys_reboot }; + + /* So we don't have to do any more manual updating.... */ + int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); +--- 108,114 ---- + sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_sethostname, + sys_setrlimit, sys_getrlimit, sys_getrusage, sys_gettimeofday, + sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink, +! sys_lstat, sys_readlink, sys_uselib, sys_swapon, sys_reboot, sys_readdir }; + + /* So we don't have to do any more manual updating.... */ + int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); +*** ../0.95a/linux/include/linux/tty.h Sun Mar 15 02:43:54 1992 +--- linux/include/linux/tty.h Thu Mar 19 21:16:26 1992 +*************** +*** 68,83 **** + struct tty_queue *secondary; + }; + +! #define TTY_WRITE(tty) \ + do { \ + cli(); \ +! if (!(tty)->busy) { \ +! (tty)->busy = 1; \ + sti(); \ + (tty)->write((tty)); \ +! (tty)->busy = 0; \ +! } else \ + sti(); \ + } while (0) + + extern struct tty_struct tty_table[]; +--- 68,105 ---- + struct tty_queue *secondary; + }; + +! /* +! * so that interrupts won't be able to mess up the +! * queues, copy_to_cooked must be atomic with repect +! * to itself, as must tty->write. +! */ +! #define TTY_WRITE_BUSY 1 +! #define TTY_READ_BUSY 2 +! +! #define TTY_WRITE_FLUSH(tty) \ + do { \ + cli(); \ +! if (!EMPTY((tty)->write_q) && !(TTY_WRITE_BUSY & (tty)->busy)) { \ +! (tty)->busy |= TTY_WRITE_BUSY; \ + sti(); \ + (tty)->write((tty)); \ +! cli(); \ +! (tty)->busy &= ~TTY_WRITE_BUSY; \ +! } \ +! sti(); \ +! } while (0) +! +! #define TTY_READ_FLUSH(tty) \ +! do { \ +! cli(); \ +! if (!EMPTY((tty)->read_q) && !(TTY_READ_BUSY & (tty)->busy)) { \ +! (tty)->busy |= TTY_READ_BUSY; \ + sti(); \ ++ copy_to_cooked((tty)); \ ++ cli(); \ ++ (tty)->busy &= ~TTY_READ_BUSY; \ ++ } \ ++ sti(); \ + } while (0) + + extern struct tty_struct tty_table[]; +*** ../0.95a/linux/include/linux/fs.h Fri Mar 13 18:55:15 1992 +--- linux/include/linux/fs.h Fri Apr 3 20:51:17 1992 +*************** +*** 7,12 **** +--- 7,13 ---- + #define _FS_H + + #include ++ #include + + /* devices are as follows: (same as minix, so we can use the minix + * file system. These are major numbers.) +*************** +*** 134,139 **** +--- 135,142 ---- + unsigned char s_lock; + unsigned char s_rd_only; + unsigned char s_dirt; ++ /* TUBE */ ++ struct super_operations *s_op; + }; + + struct file_operations { +*************** +*** 140,145 **** +--- 143,149 ---- + int (*lseek) (struct inode *, struct file *, off_t, int); + int (*read) (struct inode *, struct file *, char *, int); + int (*write) (struct inode *, struct file *, char *, int); ++ int (*readdir) (struct inode *, struct file *, struct dirent *); + }; + + struct inode_operations { +*************** +*** 156,163 **** +--- 160,184 ---- + int (*open) (struct inode *, struct file *); + void (*release) (struct inode *, struct file *); + struct inode * (*follow_link) (struct inode *, struct inode *); ++ int (*bmap) (struct inode *,int); ++ void (*truncate) (struct inode *); ++ /* added by entropy */ ++ void (*write_inode)(struct inode *inode); ++ void (*put_inode)(struct inode *inode); + }; + ++ struct super_operations { ++ void (*read_inode)(struct inode *inode); ++ void (*put_super)(struct super_block *sb); ++ }; ++ ++ struct file_system_type { ++ struct super_block *(*read_super)(struct super_block *sb,void *mode); ++ char *name; ++ }; ++ ++ extern struct file_system_type *get_fs_type(char *name); ++ + extern struct inode inode_table[NR_INODE]; + extern struct file file_table[NR_FILE]; + extern struct super_block super_block[NR_SUPER]; +*************** +*** 175,180 **** +--- 196,204 ---- + extern int bmap(struct inode * inode,int block); + extern struct inode * namei(const char * pathname); + extern struct inode * lnamei(const char * pathname); ++ extern int permission(struct inode * inode,int mask); ++ extern struct inode * _namei(const char * filename, struct inode * base, ++ int follow_links); + extern int open_namei(const char * pathname, int flag, int mode, + struct inode ** res_inode); + extern void iput(struct inode * inode); +*************** +*** 195,207 **** + extern int ROOT_DEV; + + extern void mount_root(void); + +- extern int minix_file_read(struct inode *, struct file *, char *, int); + extern int pipe_read(struct inode *, struct file *, char *, int); + extern int char_read(struct inode *, struct file *, char *, int); + extern int block_read(struct inode *, struct file *, char *, int); + +- extern int minix_file_write(struct inode *, struct file *, char *, int); + extern int pipe_write(struct inode *, struct file *, char *, int); + extern int char_write(struct inode *, struct file *, char *, int); + extern int block_write(struct inode *, struct file *, char *, int); +--- 219,231 ---- + extern int ROOT_DEV; + + extern void mount_root(void); ++ extern void lock_super(struct super_block * sb); ++ extern void free_super(struct super_block * sb); + + extern int pipe_read(struct inode *, struct file *, char *, int); + extern int char_read(struct inode *, struct file *, char *, int); + extern int block_read(struct inode *, struct file *, char *, int); + + extern int pipe_write(struct inode *, struct file *, char *, int); + extern int char_write(struct inode *, struct file *, char *, int); + extern int block_write(struct inode *, struct file *, char *, int); +*** ../0.95a/linux/include/linux/minix_fs.h Mon Mar 2 23:52:27 1992 +--- linux/include/linux/minix_fs.h Fri Apr 3 20:52:29 1992 +*************** +*** 68,76 **** +--- 68,85 ---- + extern int minix_create_block(struct inode * inode, int block); + extern int minix_bmap(struct inode * inode,int block); + ++ extern void minix_truncate(struct inode * inode); ++ extern void minix_put_super(struct super_block *sb); ++ extern struct super_block *minix_read_super(struct super_block *s,void *data); ++ extern void minix_read_inode(struct inode * inode); ++ extern void minix_write_inode(struct inode * inode); ++ + extern int minix_lseek(struct inode * inode, struct file * filp, off_t offset, int origin); + extern int minix_read(struct inode * inode, struct file * filp, char * buf, int count); + extern int minix_write(struct inode * inode, struct file * filp, char * buf, int count); ++ extern int minix_readdir(struct inode * inode, struct file * filp, struct dirent * dirent); ++ extern int minix_file_read(struct inode *, struct file *, char *, int); ++ extern int minix_file_write(struct inode *, struct file *, char *, int); + + extern struct inode_operations minix_inode_operations; + extern struct file_operations minix_file_operations; +*** ../0.95a/linux/include/asm/io.h Fri Mar 13 00:44:31 1992 +--- linux/include/asm/io.h Wed Apr 1 02:12:14 1992 +*************** +*** 1,10 **** +! static void inline outb(char value, unsigned short port) + { + __asm__ volatile ("outb %0,%1" + ::"a" ((char) value),"d" ((unsigned short) port)); + } + +! static void inline outb_p(char value, unsigned short port) + { + __asm__ volatile ("outb %0,%1\n" + "\tjmp 1f\n" +--- 1,13 ---- +! #ifndef _ASM_IO_H +! #define _ASM_IO_H +! +! extern void inline outb(char value, unsigned short port) + { + __asm__ volatile ("outb %0,%1" + ::"a" ((char) value),"d" ((unsigned short) port)); + } + +! extern void inline outb_p(char value, unsigned short port) + { + __asm__ volatile ("outb %0,%1\n" + "\tjmp 1f\n" +*************** +*** 15,21 **** + ::"a" ((char) value),"d" ((unsigned short) port)); + } + +! static unsigned char inline inb(unsigned short port) + { + unsigned char _v; + __asm__ volatile ("inb %1,%0" +--- 18,24 ---- + ::"a" ((char) value),"d" ((unsigned short) port)); + } + +! extern unsigned char inline inb(unsigned short port) + { + unsigned char _v; + __asm__ volatile ("inb %1,%0" +*************** +*** 23,29 **** + return _v; + } + +! static unsigned char inb_p(unsigned short port) + { + unsigned char _v; + __asm__ volatile ("inb %1,%0\n" +--- 26,32 ---- + return _v; + } + +! extern unsigned char inline inb_p(unsigned short port) + { + unsigned char _v; + __asm__ volatile ("inb %1,%0\n" +*************** +*** 35,37 **** +--- 38,42 ---- + :"=a" (_v):"d" ((unsigned short) port)); + return _v; + } ++ ++ #endif +*** /dev/null Sat Apr 4 17:07:54 1992 +--- linux/include/limits.h Fri Apr 3 20:08:43 1992 +*************** +*** 0 **** +--- 1,62 ---- ++ #ifndef _LIMITS_H ++ #define _LIMITS_H ++ ++ #define RAND_MAX 0x7ffffffd /* don't ask - see rand.c */ ++ ++ #define CHAR_BIT 8 ++ #define MB_LEN_MAX 1 ++ ++ #define SCHAR_MIN (-128) ++ #define SCHAR_MAX 127 ++ ++ #define UCHAR_MAX 255U ++ ++ #ifdef __CHAR_UNSIGNED__ ++ #define CHAR_MIN 0 ++ #define CHAR_MAX UCHAR_MAX ++ #else ++ #define CHAR_MIN SCHAR_MIN ++ #define CHAR_MAX SCHAR_MAX ++ #endif ++ ++ #define SHRT_MIN (-32768) ++ #define SHRT_MAX 32767 ++ ++ #define USHRT_MAX 65535U ++ ++ #define INT_MIN (-2147483648) ++ #define INT_MAX 2147483647 ++ ++ #define UINT_MAX 4294967295U ++ ++ #define LONG_MIN (-2147483648) ++ #define LONG_MAX 2147483647 ++ ++ #define ULONG_MAX 4294967295U ++ ++ /* ++ * Why are these different from the section below? -- TYT ++ */ ++ #define _POSIX_ARG_MAX 40960 /* exec() may have 40K worth of args */ ++ #define _POSIX_CHILD_MAX 6 /* a process may have 6 children */ ++ #define _POSIX_LINK_MAX 8 /* a file may have 8 links */ ++ #define _POSIX_MAX_CANON 255 /* size of the canonical input queue */ ++ #define _POSIX_MAX_INPUT 255 /* you can type 255 chars ahead */ ++ #define _POSIX_NAME_MAX 14 /* a file name may have 14 chars */ ++ #define _POSIX_NGROUPS_MAX 32 /* supplementary group IDs are optional */ ++ #define _POSIX_OPEN_MAX 16 /* a process may have 16 files open */ ++ #define _POSIX_PATH_MAX 255 /* a pathname may contain 255 chars */ ++ #define _POSIX_PIPE_BUF 512 /* pipes writes of 512 bytes must be atomic */ ++ ++ #define NGROUPS_MAX 32 /* supplemental group IDs are available */ ++ #define ARG_MAX 40960 /* # bytes of args + environ for exec() */ ++ #define CHILD_MAX 999 /* no limit :-) */ ++ #define OPEN_MAX 20 /* # open files a process may have */ ++ #define LINK_MAX 127 /* # links a file may have */ ++ #define MAX_CANON 255 /* size of the canonical input queue */ ++ #define MAX_INPUT 255 /* size of the type-ahead buffer */ ++ #define NAME_MAX 255 /* # chars in a file name */ ++ #define PATH_MAX 1024 /* # chars in a path name */ ++ #define PIPE_BUF 4095 /* # bytes in atomic write to a pipe */ ++ ++ #endif diff --git a/kernel/Historic/old-versions/old/linux-0.95a.tar.bz2 b/kernel/Historic/old-versions/old/linux-0.95a.tar.bz2 new file mode 100644 index 00000000..4a2d4e67 Binary files /dev/null and b/kernel/Historic/old-versions/old/linux-0.95a.tar.bz2 differ diff --git a/kernel/Historic/old-versions/old/linux-0.95a.tar.bz2.sign b/kernel/Historic/old-versions/old/linux-0.95a.tar.bz2.sign new file mode 100644 index 00000000..01c2e866 --- /dev/null +++ b/kernel/Historic/old-versions/old/linux-0.95a.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfwyGugalF9Dw4RAkybAJ95lZBk+f+trY5gOEt6hOuGCPFOBQCgkdG8 +KVYsGf/jr4eJSiin2Kwrh3A= +=nRAJ +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/linux-0.95a.tar.gz b/kernel/Historic/old-versions/old/linux-0.95a.tar.gz new file mode 100644 index 00000000..f5116214 Binary files /dev/null and b/kernel/Historic/old-versions/old/linux-0.95a.tar.gz differ diff --git a/kernel/Historic/old-versions/old/linux-0.95a.tar.gz.sign b/kernel/Historic/old-versions/old/linux-0.95a.tar.gz.sign new file mode 100644 index 00000000..c6717eb1 --- /dev/null +++ b/kernel/Historic/old-versions/old/linux-0.95a.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfwyGugalF9Dw4RAlU2AKCNgfvOOvg6P/FuvofUFCne8nluMACfasgJ +h2R7KT86FEAi35PU29kkD0o= +=k1Xf +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/linux-0.95a.tar.sign b/kernel/Historic/old-versions/old/linux-0.95a.tar.sign new file mode 100644 index 00000000..723a25f5 --- /dev/null +++ b/kernel/Historic/old-versions/old/linux-0.95a.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLHyGugalF9Dw4RAs7jAJ92tBoKTu+u3S3PBK3Kg6H2NFfgfgCgiYJ4 +o3oIkb4WeKm/y4Q4MxoWC+g= +=TEwb +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/linux-0.95c+.tar.bz2 b/kernel/Historic/old-versions/old/linux-0.95c+.tar.bz2 new file mode 100644 index 00000000..b69bd5b2 Binary files /dev/null and b/kernel/Historic/old-versions/old/linux-0.95c+.tar.bz2 differ diff --git a/kernel/Historic/old-versions/old/linux-0.95c+.tar.bz2.sign b/kernel/Historic/old-versions/old/linux-0.95c+.tar.bz2.sign new file mode 100644 index 00000000..ff1a4d8d --- /dev/null +++ b/kernel/Historic/old-versions/old/linux-0.95c+.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfwyGugalF9Dw4RAhn3AKCC87Jnte7g6Rx3RZ/Y2Bw/Odtt5gCfUov4 +1H5wZbYEnho86zr1Jlo4rD0= +=H+At +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/linux-0.95c+.tar.gz b/kernel/Historic/old-versions/old/linux-0.95c+.tar.gz new file mode 100644 index 00000000..671588a7 Binary files /dev/null and b/kernel/Historic/old-versions/old/linux-0.95c+.tar.gz differ diff --git a/kernel/Historic/old-versions/old/linux-0.95c+.tar.gz.sign b/kernel/Historic/old-versions/old/linux-0.95c+.tar.gz.sign new file mode 100644 index 00000000..7776cb47 --- /dev/null +++ b/kernel/Historic/old-versions/old/linux-0.95c+.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfwyGugalF9Dw4RAv9sAJ9QrCYzpE04GGWpie2qvTmbdIYrqQCfdbUn +0pKL4vXJ42LQOwhf3BrEiTM= +=5FzW +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/linux-0.95c+.tar.sign b/kernel/Historic/old-versions/old/linux-0.95c+.tar.sign new file mode 100644 index 00000000..d89b4799 --- /dev/null +++ b/kernel/Historic/old-versions/old/linux-0.95c+.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLHyGugalF9Dw4RAuPQAJ9aFrzibEE3YGVp/Z4L6sBPcfxA8ACfRqhl +annAxNy/X32P26+0foxRN7s= +=Fmgs +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/linux-0.96c.tar.bz2 b/kernel/Historic/old-versions/old/linux-0.96c.tar.bz2 new file mode 100644 index 00000000..7543c8be Binary files /dev/null and b/kernel/Historic/old-versions/old/linux-0.96c.tar.bz2 differ diff --git a/kernel/Historic/old-versions/old/linux-0.96c.tar.bz2.sign b/kernel/Historic/old-versions/old/linux-0.96c.tar.bz2.sign new file mode 100644 index 00000000..304abda0 --- /dev/null +++ b/kernel/Historic/old-versions/old/linux-0.96c.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfvyGugalF9Dw4RAukfAJ4vjIbaD+zHhHPsoHyUR0DT/8Q/ZgCfRN18 +3gbTd6lV7nmbc7trNZtBiVk= +=2wpc +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/linux-0.96c.tar.gz b/kernel/Historic/old-versions/old/linux-0.96c.tar.gz new file mode 100644 index 00000000..ed2662cb Binary files /dev/null and b/kernel/Historic/old-versions/old/linux-0.96c.tar.gz differ diff --git a/kernel/Historic/old-versions/old/linux-0.96c.tar.gz.sign b/kernel/Historic/old-versions/old/linux-0.96c.tar.gz.sign new file mode 100644 index 00000000..03f23aaf --- /dev/null +++ b/kernel/Historic/old-versions/old/linux-0.96c.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfvyGugalF9Dw4RAntsAJ4xAsejQMenBEl9/EqEKQM71kGBbwCbBxYp +y0iDujHa/BOkRty6aoym1SA= +=iPew +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/linux-0.96c.tar.sign b/kernel/Historic/old-versions/old/linux-0.96c.tar.sign new file mode 100644 index 00000000..40d57e1b --- /dev/null +++ b/kernel/Historic/old-versions/old/linux-0.96c.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLIyGugalF9Dw4RArQyAJ0ZDsqaScmgbw4xZX5/+Cgksp10mACgi4ex +SEDQv/kuKuHKbQ+W5E5Ssec= +=LNkv +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/linux-0.97.tar.bz2 b/kernel/Historic/old-versions/old/linux-0.97.tar.bz2 new file mode 100644 index 00000000..8a967a81 Binary files /dev/null and b/kernel/Historic/old-versions/old/linux-0.97.tar.bz2 differ diff --git a/kernel/Historic/old-versions/old/linux-0.97.tar.bz2.sign b/kernel/Historic/old-versions/old/linux-0.97.tar.bz2.sign new file mode 100644 index 00000000..e869877d --- /dev/null +++ b/kernel/Historic/old-versions/old/linux-0.97.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfvyGugalF9Dw4RAqOHAJ9GlkkseBm/rnVvWqp3KV0VXvchDgCgiHkS +BRwSzrrqhuJvkLRia/Uy3Lk= +=oCcU +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/linux-0.97.tar.gz b/kernel/Historic/old-versions/old/linux-0.97.tar.gz new file mode 100644 index 00000000..891d5098 Binary files /dev/null and b/kernel/Historic/old-versions/old/linux-0.97.tar.gz differ diff --git a/kernel/Historic/old-versions/old/linux-0.97.tar.gz.sign b/kernel/Historic/old-versions/old/linux-0.97.tar.gz.sign new file mode 100644 index 00000000..3fcef0de --- /dev/null +++ b/kernel/Historic/old-versions/old/linux-0.97.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfvyGugalF9Dw4RAooaAJ9GRPo89IHsYoFq62akVYq0LuOkuACffzi/ +IWULI60Cohc0rYmjYBMDUVY= +=5KXQ +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/linux-0.97.tar.sign b/kernel/Historic/old-versions/old/linux-0.97.tar.sign new file mode 100644 index 00000000..c457a946 --- /dev/null +++ b/kernel/Historic/old-versions/old/linux-0.97.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLIyGugalF9Dw4RAukXAJ4hmpMoxb9JOfQ6Iug7UI3SMbp6LACfTOSx +3m+YvM1WF71C6VDPUj7vZIA= +=/qQ1 +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/pre-0.96.tar.bz2 b/kernel/Historic/old-versions/old/pre-0.96.tar.bz2 new file mode 100644 index 00000000..7884c7cc Binary files /dev/null and b/kernel/Historic/old-versions/old/pre-0.96.tar.bz2 differ diff --git a/kernel/Historic/old-versions/old/pre-0.96.tar.bz2.sign b/kernel/Historic/old-versions/old/pre-0.96.tar.bz2.sign new file mode 100644 index 00000000..f398b8bc --- /dev/null +++ b/kernel/Historic/old-versions/old/pre-0.96.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfwyGugalF9Dw4RAnYaAJ4rxtHOUogynAeM9z9dtqsgJLibewCePpZ2 +VdAfA57xNnD/tBjfbHaE62A= +=A+Hm +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/pre-0.96.tar.gz b/kernel/Historic/old-versions/old/pre-0.96.tar.gz new file mode 100644 index 00000000..1dd5403f Binary files /dev/null and b/kernel/Historic/old-versions/old/pre-0.96.tar.gz differ diff --git a/kernel/Historic/old-versions/old/pre-0.96.tar.gz.sign b/kernel/Historic/old-versions/old/pre-0.96.tar.gz.sign new file mode 100644 index 00000000..b6bacba3 --- /dev/null +++ b/kernel/Historic/old-versions/old/pre-0.96.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfvyGugalF9Dw4RAowcAJ0V7zX4rb2dgLedkiXKeFriNfP47QCgjP45 +tHU7XZ8nqxoY8WSwEfAWRcw= +=x40K +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/old/pre-0.96.tar.sign b/kernel/Historic/old-versions/old/pre-0.96.tar.sign new file mode 100644 index 00000000..baf0cc50 --- /dev/null +++ b/kernel/Historic/old-versions/old/pre-0.96.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLIyGugalF9Dw4RAggiAJ4l8OXQeYwd7DAl522NnBpUfkVLYwCePM5n +jjtYGqwKtICxalifInWaDqk= +=8SGs +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/tytso/linux-0.10.tar.bz2 b/kernel/Historic/old-versions/tytso/linux-0.10.tar.bz2 new file mode 100644 index 00000000..49d1e943 Binary files /dev/null and b/kernel/Historic/old-versions/tytso/linux-0.10.tar.bz2 differ diff --git a/kernel/Historic/old-versions/tytso/linux-0.10.tar.bz2.sign b/kernel/Historic/old-versions/tytso/linux-0.10.tar.bz2.sign new file mode 100644 index 00000000..0c0413cd --- /dev/null +++ b/kernel/Historic/old-versions/tytso/linux-0.10.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfxyGugalF9Dw4RAmAgAJ9jWkhsrQZ+Gcj+JpfemmAs70Sp7wCfea3t +5IlBdlTXFz2/wHgM8S+d9Y4= +=QzGV +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/tytso/linux-0.10.tar.gz b/kernel/Historic/old-versions/tytso/linux-0.10.tar.gz new file mode 100644 index 00000000..b960598d Binary files /dev/null and b/kernel/Historic/old-versions/tytso/linux-0.10.tar.gz differ diff --git a/kernel/Historic/old-versions/tytso/linux-0.10.tar.gz.sign b/kernel/Historic/old-versions/tytso/linux-0.10.tar.gz.sign new file mode 100644 index 00000000..6b5c860d --- /dev/null +++ b/kernel/Historic/old-versions/tytso/linux-0.10.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rfxyGugalF9Dw4RAusWAJ4wA+uqWKPcFC/aRSo+2oN+W+YxXACgjBDB +vkNepBFrjkAIEtPrPmFyiQM= +=GKW8 +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/old-versions/tytso/linux-0.10.tar.sign b/kernel/Historic/old-versions/tytso/linux-0.10.tar.sign new file mode 100644 index 00000000..b6800ef9 --- /dev/null +++ b/kernel/Historic/old-versions/tytso/linux-0.10.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLIyGugalF9Dw4RArPUAJ985v+PnbKTn3GLF48qJxsUFTVHGACfQ4db +EFuU2G7RRL550lQlWpGJQnc= +=EibM +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.10.tar.z b/kernel/Historic/v0.99/linux-0.99.10.tar.z new file mode 100644 index 00000000..4ac77a17 Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.10.tar.z differ diff --git a/kernel/Historic/v0.99/linux-0.99.11.tar.bz2 b/kernel/Historic/v0.99/linux-0.99.11.tar.bz2 new file mode 100644 index 00000000..64fc88fa Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.11.tar.bz2 differ diff --git a/kernel/Historic/v0.99/linux-0.99.11.tar.bz2.sign b/kernel/Historic/v0.99/linux-0.99.11.tar.bz2.sign new file mode 100644 index 00000000..297e1ecd --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.11.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf1yGugalF9Dw4RAg1GAJ9afuNJqs8RW2swBe6GHeZZ2qKVxwCdHiNG +uTM9G1kSTOf2JcsfOMni9x8= +=SxVF +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.11.tar.gz b/kernel/Historic/v0.99/linux-0.99.11.tar.gz new file mode 100644 index 00000000..4b850166 Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.11.tar.gz differ diff --git a/kernel/Historic/v0.99/linux-0.99.11.tar.gz.sign b/kernel/Historic/v0.99/linux-0.99.11.tar.gz.sign new file mode 100644 index 00000000..28833482 --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.11.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf1yGugalF9Dw4RAj+KAKCTPAE704U+mEbemR5m0vnUKnWcPgCfZ7MJ +SgJf19YFn8vOqqQCEjoqD4A= +=nURf +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.11.tar.sign b/kernel/Historic/v0.99/linux-0.99.11.tar.sign new file mode 100644 index 00000000..576427e4 --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.11.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLKyGugalF9Dw4RAnaxAKCNGFIfdO8vEmaZ6A2zC41Qrw1gSQCdGT/I +6pXq6MQEzJSTdrjxuBkaC58= +=KXxH +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.12.small-patch b/kernel/Historic/v0.99/linux-0.99.12.small-patch new file mode 100644 index 00000000..028b2003 --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.12.small-patch @@ -0,0 +1,93 @@ +From samba.oit.unc.edu!concert!news-feed-1.peachnet.edu!gatech!howland.reston.ans.net!sol.ctr.columbia.edu!caen!batcomputer!bounce-bounce Wed Aug 18 19:49:49 EDT 1993 +Article: 1022 of comp.os.linux.announce +Path: samba.oit.unc.edu!concert!news-feed-1.peachnet.edu!gatech!howland.reston.ans.net!sol.ctr.columbia.edu!caen!batcomputer!bounce-bounce +From: torvalds@cc.helsinki.fi (Linus Torvalds) +Newsgroups: comp.os.linux.announce +Subject: Very small patch to 0.99pl12 +Followup-To: comp.os.linux +Date: 18 Aug 1993 09:50:58 -0400 +Organization: University of Helsinki +Lines: 74 +Sender: mdw@TC.Cornell.EDU +Approved: linux-announce@tc.cornell.edu (Matt Welsh) +Message-ID: <24tc42$sf2@theory.TC.Cornell.EDU> +Reply-To: torvalds@cc.helsinki.fi (Linus Torvalds) +NNTP-Posting-Host: theory.tc.cornell.edu +Keywords: kernel patch + +I hate to put out patches this soon after a release, but there is one +potentially major problem in pl12 which is very simple to fix.. I'm +including patches: both in plain ascii and as a uuencoded gzip file +(it's the same patch - the uuencoded one is in case there is any +newsserver that messes up whitespace). + +The main patch is just the change from __get_free_page(GFP_BUFFER) into +get_free_page(GFP_KERNEL), and the two minor patches just add checks +that actually enforce the read-only nature of current file mmap'ings so +that any program that tries to do a write mapping at least will be told +that it won't work. + +I'd suggest anybody compiling pl12 should add at least the file_table.c +patch: thanks to Alexandre Julliard for noticing this one. + + Linus + +---------- +diff -u --recursive --new-files pl12/linux/fs/file_table.c linux/fs/file_table.c +--- pl12/linux/fs/file_table.c Mon Aug 9 17:41:22 1993 ++++ linux/fs/file_table.c Tue Aug 17 18:32:13 1993 +@@ -45,7 +45,7 @@ + struct file * file; + int i; + +- file = (struct file*) __get_free_page(GFP_BUFFER); ++ file = (struct file *) get_free_page(GFP_KERNEL); + + if (!file) + return; +diff -u --recursive --new-files pl12/linux/fs/nfs/mmap.c linux/fs/nfs/mmap.c +--- pl12/linux/fs/nfs/mmap.c Sun Aug 15 11:46:03 1993 ++++ linux/fs/nfs/mmap.c Tue Aug 17 22:39:38 1993 +@@ -50,6 +50,8 @@ + { + struct vm_area_struct * mpnt; + ++ if (prot & PAGE_RW) /* only PAGE_COW or read-only supported now */ ++ return -EINVAL; + if (off & (inode->i_sb->s_blocksize - 1)) + return -EINVAL; + if (len > high_memory || off > high_memory - len) /* avoid overflow */ +diff -u --recursive --new-files pl12/linux/mm/mmap.c linux/mm/mmap.c +--- pl12/linux/mm/mmap.c Mon Aug 9 18:02:33 1993 ++++ linux/mm/mmap.c Tue Aug 17 22:39:38 1993 +@@ -197,6 +197,8 @@ + extern struct vm_operations_struct file_mmap; + struct buffer_head * bh; + ++ if (prot & PAGE_RW) /* only PAGE_COW or read-only supported right now */ ++ return -EINVAL; + if (off & (inode->i_sb->s_blocksize - 1)) + return -EINVAL; + if (len > high_memory || off > high_memory - len) /* avoid overflow */ +---------- +begin 644 diff.gz +M'XL( &5&<2P" -637V_:,!3%GY-/Q/WVT KD! +M:XD=.0YMMW[X.0$UH465JCWM(8Y]?,^U]3M)Q.,82 &$*%P5*N=;-'.!=R3F +M">:0)=3K)%P4]YTX[Y0:T^$RP?!W0X +M]&W7=8]WM+X76%EH'^@@\+V ^CO+9 *DVSOM@UN-DXD-5JY5L=)0-H!V]1H9 +ME0L-W$QL8E4['Z#5*&P[P-@:-8L5(LO"-;8NYC?LXX_Y?+9P1K9[S 3&]=+S +M>;:XGETYY5'FU!A:[\I:QRPLA;I08F1';R(NS).F8=;D76M':->;UK=BQYKV +M@-*@>QZ<^4=8-PP-TIX7^,/ ']2D>V>GY^":<5"1_E/#WJ8L5!BR_;(-:29T +MB<"M$&1*:CB!F^G%C"UN':O3!BF2AYWPZ>LM2 7&'I%*S8LLDTIC!$+>0;MC +MFNS1 9E=7O^<7HWV:*7A> (M+F2$9,Q9OB3CG"T3N?J5\]\&*E"G0?ZY/4$! +M8]CP]8:EF$KU (^/4/8\% F80@?,I<.MY!'(+:HXV5WM#5&FZ6&,3^OG$3YM +M'/PJ@^#,!/(BOKKXU>CHL%]F5[YVX5EXK]$@J0.4&:I0] +=+.(8%=N8M$S,R\V_AZP,:OT?1/T7_';.!R@% "4 + +end + + +-- +Send submissions for comp.os.linux.announce to: linux-announce@tc.cornell.edu + + diff --git a/kernel/Historic/v0.99/linux-0.99.12.tar.bz2 b/kernel/Historic/v0.99/linux-0.99.12.tar.bz2 new file mode 100644 index 00000000..4185bc63 Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.12.tar.bz2 differ diff --git a/kernel/Historic/v0.99/linux-0.99.12.tar.bz2.sign b/kernel/Historic/v0.99/linux-0.99.12.tar.bz2.sign new file mode 100644 index 00000000..370e45ba --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.12.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf2yGugalF9Dw4RAvOyAKCK+zJnm8Rcm+SPOA/nzL/FmQHShACcD/me +0mH6IbxOyzrKES2JV4Gg+HQ= +=3h6P +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.12.tar.gz b/kernel/Historic/v0.99/linux-0.99.12.tar.gz new file mode 100644 index 00000000..893217fc Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.12.tar.gz differ diff --git a/kernel/Historic/v0.99/linux-0.99.12.tar.gz.sign b/kernel/Historic/v0.99/linux-0.99.12.tar.gz.sign new file mode 100644 index 00000000..69c6596d --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.12.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf1yGugalF9Dw4RAipGAJ405swIndEG1a8xPObcBrB8F9VVLQCggelT +8NV28Dp5NO0JQUxbrVrvlvU= +=EJ1x +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.12.tar.sign b/kernel/Historic/v0.99/linux-0.99.12.tar.sign new file mode 100644 index 00000000..4bf86e7d --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.12.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLLyGugalF9Dw4RAvYqAKCTRv0j3+SdUQleMaWFmnjYUWt3LQCgiON8 +keQe2/iAQVH4VUGyMoAP354= +=8O0I +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.13.tar.bz2 b/kernel/Historic/v0.99/linux-0.99.13.tar.bz2 new file mode 100644 index 00000000..0745f3bc Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.13.tar.bz2 differ diff --git a/kernel/Historic/v0.99/linux-0.99.13.tar.bz2.sign b/kernel/Historic/v0.99/linux-0.99.13.tar.bz2.sign new file mode 100644 index 00000000..85381066 --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.13.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf2yGugalF9Dw4RApu3AJ91y131pkm/N5jtRlZY8jvqDNOfGwCfSsme +YH0MYxqpJWYjcL6kfVqeeR0= +=aW// +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.13.tar.gz b/kernel/Historic/v0.99/linux-0.99.13.tar.gz new file mode 100644 index 00000000..6c95479b Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.13.tar.gz differ diff --git a/kernel/Historic/v0.99/linux-0.99.13.tar.gz.sign b/kernel/Historic/v0.99/linux-0.99.13.tar.gz.sign new file mode 100644 index 00000000..31f45d34 --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.13.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf2yGugalF9Dw4RArgYAJ9vsniFHV0ukDRGkuk93dhaT+qJaQCgjTnt +m0YuYsF0llXfgy/FtHxuHwQ= +=v/TK +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.13.tar.sign b/kernel/Historic/v0.99/linux-0.99.13.tar.sign new file mode 100644 index 00000000..5f02a6f2 --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.13.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLLyGugalF9Dw4RAkldAJ0fC49DRnhkCZWQkWrF0myeJpxO7gCeM2Nv +a4whAQeAGDkhTf7zQCbmy3M= +=9Kdl +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.15.tar.bz2 b/kernel/Historic/v0.99/linux-0.99.15.tar.bz2 new file mode 100644 index 00000000..7876f593 Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.15.tar.bz2 differ diff --git a/kernel/Historic/v0.99/linux-0.99.15.tar.bz2.sign b/kernel/Historic/v0.99/linux-0.99.15.tar.bz2.sign new file mode 100644 index 00000000..7d7754a3 --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.15.tar.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf3yGugalF9Dw4RAs3LAJoDEpqfHdGtkfekPayLAzRCpiyjVwCfagk/ +Pqug6dmjA1Xz4xFyMU9QeDg= +=aCHO +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.15.tar.gz b/kernel/Historic/v0.99/linux-0.99.15.tar.gz new file mode 100644 index 00000000..c12393b8 Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.15.tar.gz differ diff --git a/kernel/Historic/v0.99/linux-0.99.15.tar.gz.sign b/kernel/Historic/v0.99/linux-0.99.15.tar.gz.sign new file mode 100644 index 00000000..e532a797 --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.15.tar.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf3yGugalF9Dw4RArXLAJ97uwgxbPQJqbWpboauzxc19GkMUACcDCXV +YEb/VXa6R+WtaXI+EEKPUOY= +=iGYf +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.15.tar.sign b/kernel/Historic/v0.99/linux-0.99.15.tar.sign new file mode 100644 index 00000000..de23bb43 --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.15.tar.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLLyGugalF9Dw4RApZfAJ9jQroH+PcDGJWuAarmkbLA8kc97ACcCJEB +E1SJRQcperqS6jSfD8REs3E= +=n1IJ +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.7.tar.z b/kernel/Historic/v0.99/linux-0.99.7.tar.z new file mode 100644 index 00000000..f1f90b7f Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.7.tar.z differ diff --git a/kernel/Historic/v0.99/linux-0.99.7A.tar.z b/kernel/Historic/v0.99/linux-0.99.7A.tar.z new file mode 100644 index 00000000..42325723 Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.7A.tar.z differ diff --git a/kernel/Historic/v0.99/linux-0.99.8.tar.z b/kernel/Historic/v0.99/linux-0.99.8.tar.z new file mode 100644 index 00000000..125c1d34 Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.8.tar.z differ diff --git a/kernel/Historic/v0.99/linux-0.99.9.tar.z b/kernel/Historic/v0.99/linux-0.99.9.tar.z new file mode 100644 index 00000000..d5321ffd Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.9.tar.z differ diff --git a/kernel/Historic/v0.99/linux-0.99.patch11.tar.gz.badcrc b/kernel/Historic/v0.99/linux-0.99.patch11.tar.gz.badcrc new file mode 100644 index 00000000..f573b263 Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.patch11.tar.gz.badcrc differ diff --git a/kernel/Historic/v0.99/linux-0.99.patch12.bz2 b/kernel/Historic/v0.99/linux-0.99.patch12.bz2 new file mode 100644 index 00000000..c1961082 Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.patch12.bz2 differ diff --git a/kernel/Historic/v0.99/linux-0.99.patch12.bz2.sign b/kernel/Historic/v0.99/linux-0.99.patch12.bz2.sign new file mode 100644 index 00000000..3f12addd --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.patch12.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf3yGugalF9Dw4RAgOCAKCTbqmU0nE+7uCtSO4GgQ5HUKJBFgCffcL3 +LKeA3wbkvbu/zuJTSnmBDvM= +=Ya1D +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.patch12.gz b/kernel/Historic/v0.99/linux-0.99.patch12.gz new file mode 100644 index 00000000..4e1fcc9c Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.patch12.gz differ diff --git a/kernel/Historic/v0.99/linux-0.99.patch12.gz.sign b/kernel/Historic/v0.99/linux-0.99.patch12.gz.sign new file mode 100644 index 00000000..0fbd9b55 --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.patch12.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf3yGugalF9Dw4RAkWkAKCNZdPuaYaKutYmqsJeh/gaJ2Sp0ACeP3Fm +PZe85C90UHX6WzY/mq6Lhd8= +=VQJ5 +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.patch12.sign b/kernel/Historic/v0.99/linux-0.99.patch12.sign new file mode 100644 index 00000000..8444e5eb --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.patch12.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLMyGugalF9Dw4RAtS2AJ4zJSYwYm/w3gLjMirAZFFEZSTAjgCfY8yy +4czK56IKWhW9K1wqEXOlkE0= +=ebs7 +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.patch13.bz2 b/kernel/Historic/v0.99/linux-0.99.patch13.bz2 new file mode 100644 index 00000000..2d7f90d8 Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.patch13.bz2 differ diff --git a/kernel/Historic/v0.99/linux-0.99.patch13.bz2.sign b/kernel/Historic/v0.99/linux-0.99.patch13.bz2.sign new file mode 100644 index 00000000..54b6b6a4 --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.patch13.bz2.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf4yGugalF9Dw4RAnSBAKCL866x1BF64tG4UrRZ6vd2isYsvACgg3TO +LYlyG9GVdGtKp6+rshhdeCM= +=RmDE +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.patch13.gz b/kernel/Historic/v0.99/linux-0.99.patch13.gz new file mode 100644 index 00000000..a228ec49 Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.patch13.gz differ diff --git a/kernel/Historic/v0.99/linux-0.99.patch13.gz.sign b/kernel/Historic/v0.99/linux-0.99.patch13.gz.sign new file mode 100644 index 00000000..d036a347 --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.patch13.gz.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.0 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA54rf4yGugalF9Dw4RAlw4AJsFuSysZblDN5nd2Yo6CPHck2GeyACfbgYo +nwzfE9YHKlO7GYDgoHIAM4Q= +=YsCh +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.patch13.sign b/kernel/Historic/v0.99/linux-0.99.patch13.sign new file mode 100644 index 00000000..1d993ae1 --- /dev/null +++ b/kernel/Historic/v0.99/linux-0.99.patch13.sign @@ -0,0 +1,8 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: See http://www.kernel.org/signature.html for info + +iD8DBQA+ekLMyGugalF9Dw4RAtfQAJ92QYqzYfrGm5qnwEeIaTBD/ezM9gCeMYsD +W29/l7R5FqiRwxJppkKbbZ0= +=gA/e +-----END PGP SIGNATURE----- diff --git a/kernel/Historic/v0.99/linux-0.99.patch7.z b/kernel/Historic/v0.99/linux-0.99.patch7.z new file mode 100644 index 00000000..2388d1fc Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.patch7.z differ diff --git a/kernel/Historic/v0.99/linux-0.99.patch8.z b/kernel/Historic/v0.99/linux-0.99.patch8.z new file mode 100644 index 00000000..762ad1cd Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.patch8.z differ diff --git a/kernel/Historic/v0.99/linux-0.99.patch9.z b/kernel/Historic/v0.99/linux-0.99.patch9.z new file mode 100644 index 00000000..d80e4e54 Binary files /dev/null and b/kernel/Historic/v0.99/linux-0.99.patch9.z differ