Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Makefile
- #
- # 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
- ------------------------------------------------------------------------
- boot/boot.s
- |
- | 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:
- ------------------------------------------------------------------------
- boot/head.s
- /*
- * 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 */
- ------------------------------------------------------------------------
- fs/bitmap.c
- /* bitmap.c contains the code that handles the inode and block bitmaps */
- #include <string.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #define clear_block(addr) \
- __asm__("cld\n\t" \
- "rep\n\t" \
- "stosl" \
- ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
- #define set_bit(nr,addr) ({\
- register int res __asm__("ax"); \
- __asm__("btsl %2,%3\n\tsetb %%al":"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
- res;})
- #define clear_bit(nr,addr) ({\
- register int res __asm__("ax"); \
- __asm__("btrl %2,%3\n\tsetnb %%al":"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
- res;})
- #define find_first_zero(addr) ({ \
- int __res; \
- __asm__("cld\n" \
- "1:\tlodsl\n\t" \
- "notl %%eax\n\t" \
- "bsfl %%eax,%%edx\n\t" \
- "je 2f\n\t" \
- "addl %%edx,%%ecx\n\t" \
- "jmp 3f\n" \
- "2:\taddl $32,%%ecx\n\t" \
- "cmpl $8192,%%ecx\n\t" \
- "jl 1b\n" \
- "3:" \
- :"=c" (__res):"c" (0),"S" (addr):"ax","dx","si"); \
- __res;})
- void free_block(int dev, int block)
- {
- struct super_block * sb;
- struct buffer_head * bh;
- if (!(sb = get_super(dev)))
- panic("trying to free block on nonexistent device");
- if (block < sb->s_firstdatazone || block >= sb->s_nzones)
- panic("trying to free block not in datazone");
- bh = get_hash_table(dev,block);
- if (bh) {
- if (bh->b_count != 1) {
- printk("trying to free block (%04x:%d), count=%d\n",
- dev,block,bh->b_count);
- return;
- }
- bh->b_dirt=0;
- bh->b_uptodate=0;
- brelse(bh);
- }
- block -= sb->s_firstdatazone - 1 ;
- if (clear_bit(block&8191,sb->s_zmap[block/8192]->b_data)) {
- printk("block (%04x:%d) ",dev,block+sb->s_firstdatazone-1);
- panic("free_block: bit already cleared");
- }
- sb->s_zmap[block/8192]->b_dirt = 1;
- }
- int new_block(int dev)
- {
- struct buffer_head * bh;
- struct super_block * sb;
- int i,j;
- if (!(sb = get_super(dev)))
- panic("trying to get new block from nonexistant device");
- j = 8192;
- for (i=0 ; i<8 ; i++)
- if (bh=sb->s_zmap[i])
- if ((j=find_first_zero(bh->b_data))<8192)
- break;
- if (i>=8 || !bh || j>=8192)
- return 0;
- if (set_bit(j,bh->b_data))
- panic("new_block: bit already set");
- bh->b_dirt = 1;
- j += i*8192 + sb->s_firstdatazone-1;
- if (j >= sb->s_nzones)
- return 0;
- if (!(bh=getblk(dev,j)))
- panic("new_block: cannot get block");
- if (bh->b_count != 1)
- panic("new block: count is != 1");
- clear_block(bh->b_data);
- bh->b_uptodate = 1;
- bh->b_dirt = 1;
- brelse(bh);
- return j;
- }
- void free_inode(struct m_inode * inode)
- {
- struct super_block * sb;
- struct buffer_head * bh;
- if (!inode)
- return;
- if (!inode->i_dev) {
- memset(inode,0,sizeof(*inode));
- return;
- }
- if (inode->i_count>1) {
- printk("trying to free inode with count=%d\n",inode->i_count);
- panic("free_inode");
- }
- if (inode->i_nlinks)
- panic("trying to free inode with links");
- if (!(sb = get_super(inode->i_dev)))
- panic("trying to free inode on nonexistent device");
- if (inode->i_num < 1 || inode->i_num > sb->s_ninodes)
- panic("trying to free inode 0 or nonexistant inode");
- if (!(bh=sb->s_imap[inode->i_num>>13]))
- panic("nonexistent imap in superblock");
- if (clear_bit(inode->i_num&8191,bh->b_data))
- panic("free_inode: bit already cleared");
- bh->b_dirt = 1;
- memset(inode,0,sizeof(*inode));
- }
- struct m_inode * new_inode(int dev)
- {
- struct m_inode * inode;
- struct super_block * sb;
- struct buffer_head * bh;
- int i,j;
- if (!(inode=get_empty_inode()))
- return NULL;
- if (!(sb = get_super(dev)))
- panic("new_inode with unknown device");
- j = 8192;
- for (i=0 ; i<8 ; i++)
- if (bh=sb->s_imap[i])
- if ((j=find_first_zero(bh->b_data))<8192)
- break;
- if (!bh || j >= 8192 || j+i*8192 > sb->s_ninodes) {
- iput(inode);
- return NULL;
- }
- if (set_bit(j,bh->b_data))
- panic("new_inode: bit already set");
- bh->b_dirt = 1;
- inode->i_count=1;
- inode->i_nlinks=1;
- inode->i_dev=dev;
- inode->i_dirt=1;
- inode->i_num = j + i*8192;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- return inode;
- }
- ------------------------------------------------------------------------
- fs/block_dev.c
- #include <errno.h>
- #include <linux/fs.h>
- #include <linux/kernel.h>
- #include <asm/segment.h>
- #define NR_BLK_DEV ((sizeof (rd_blk))/(sizeof (rd_blk[0])))
- int block_write(int dev, long * pos, char * buf, int count)
- {
- int block = *pos / BLOCK_SIZE;
- int offset = *pos % BLOCK_SIZE;
- int chars;
- int written = 0;
- struct buffer_head * bh;
- register char * p;
- while (count>0) {
- bh = bread(dev,block);
- if (!bh)
- return written?written:-EIO;
- chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE;
- p = offset + bh->b_data;
- offset = 0;
- block++;
- *pos += chars;
- written += chars;
- count -= chars;
- while (chars-->0)
- *(p++) = get_fs_byte(buf++);
- bh->b_dirt = 1;
- brelse(bh);
- }
- return written;
- }
- int block_read(int dev, unsigned long * pos, char * buf, int count)
- {
- int block = *pos / BLOCK_SIZE;
- int offset = *pos % BLOCK_SIZE;
- int chars;
- int read = 0;
- struct buffer_head * bh;
- register char * p;
- while (count>0) {
- bh = bread(dev,block);
- if (!bh)
- return read?read:-EIO;
- chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE;
- p = offset + bh->b_data;
- offset = 0;
- block++;
- *pos += chars;
- read += chars;
- count -= chars;
- while (chars-->0)
- put_fs_byte(*(p++),buf++);
- bh->b_dirt = 1;
- brelse(bh);
- }
- return read;
- }
- extern void rw_hd(int rw, struct buffer_head * bh);
- typedef void (*blk_fn)(int rw, struct buffer_head * bh);
- static blk_fn rd_blk[]={
- NULL, /* nodev */
- NULL, /* dev mem */
- NULL, /* dev fd */
- rw_hd, /* dev hd */
- NULL, /* dev ttyx */
- NULL, /* dev tty */
- NULL}; /* dev lp */
- void ll_rw_block(int rw, struct buffer_head * bh)
- {
- blk_fn blk_addr;
- unsigned int major;
- if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || !(blk_addr=rd_blk[major]))
- panic("Trying to read nonexistent block-device");
- blk_addr(rw, bh);
- }
- ------------------------------------------------------------------------
- fs/buffer.c
- /*
- * 'buffer.c' implements the buffer-cache functions. Race-conditions have
- * been avoided by NEVER letting a interrupt change a buffer (except for the
- * data, of course), but instead letting the caller do it. NOTE! As interrupts
- * can wake up a caller, some cli-sti sequences are needed to check for
- * sleep-on-calls. These should be extremely quick, though (I hope).
- */
- #include <linux/config.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <asm/system.h>
- #if (BUFFER_END & 0xfff)
- #error "Bad BUFFER_END value"
- #endif
- #if (BUFFER_END > 0xA0000 && BUFFER_END <= 0x100000)
- #error "Bad BUFFER_END value"
- #endif
- extern int end;
- struct buffer_head * start_buffer = (struct buffer_head *) &end;
- struct buffer_head * hash_table[NR_HASH];
- static struct buffer_head * free_list;
- static struct task_struct * buffer_wait = NULL;
- int NR_BUFFERS = 0;
- static inline void wait_on_buffer(struct buffer_head * bh)
- {
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
- }
- int sys_sync(void)
- {
- int i;
- struct buffer_head * bh;
- sync_inodes(); /* write out inodes into buffers */
- bh = start_buffer;
- for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
- wait_on_buffer(bh);
- if (bh->b_dirt)
- ll_rw_block(WRITE,bh);
- }
- return 0;
- }
- static int sync_dev(int dev)
- {
- int i;
- struct buffer_head * bh;
- bh = start_buffer;
- for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
- if (bh->b_dev != dev)
- continue;
- wait_on_buffer(bh);
- if (bh->b_dirt)
- ll_rw_block(WRITE,bh);
- }
- return 0;
- }
- #define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
- #define hash(dev,block) hash_table[_hashfn(dev,block)]
- static inline void remove_from_queues(struct buffer_head * bh)
- {
- /* remove from hash-queue */
- if (bh->b_next)
- bh->b_next->b_prev = bh->b_prev;
- if (bh->b_prev)
- bh->b_prev->b_next = bh->b_next;
- if (hash(bh->b_dev,bh->b_blocknr) == bh)
- hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
- /* remove from free list */
- if (!(bh->b_prev_free) || !(bh->b_next_free))
- panic("Free block list corrupted");
- bh->b_prev_free->b_next_free = bh->b_next_free;
- bh->b_next_free->b_prev_free = bh->b_prev_free;
- if (free_list == bh)
- free_list = bh->b_next_free;
- }
- static inline void insert_into_queues(struct buffer_head * bh)
- {
- /* put at end of free list */
- bh->b_next_free = free_list;
- bh->b_prev_free = free_list->b_prev_free;
- free_list->b_prev_free->b_next_free = bh;
- free_list->b_prev_free = bh;
- /* put the buffer in new hash-queue if it has a device */
- bh->b_prev = NULL;
- bh->b_next = NULL;
- if (!bh->b_dev)
- return;
- bh->b_next = hash(bh->b_dev,bh->b_blocknr);
- hash(bh->b_dev,bh->b_blocknr) = bh;
- bh->b_next->b_prev = bh;
- }
- static struct buffer_head * find_buffer(int dev, int block)
- {
- struct buffer_head * tmp;
- for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
- if (tmp->b_dev==dev && tmp->b_blocknr==block)
- return tmp;
- return NULL;
- }
- /*
- * Why like this, I hear you say... The reason is race-conditions.
- * As we don't lock buffers (unless we are readint them, that is),
- * something might happen to it while we sleep (ie a read-error
- * will force it bad). This shouldn't really happen currently, but
- * the code is ready.
- */
- struct buffer_head * get_hash_table(int dev, int block)
- {
- struct buffer_head * bh;
- repeat:
- if (!(bh=find_buffer(dev,block)))
- return NULL;
- bh->b_count++;
- wait_on_buffer(bh);
- if (bh->b_dev != dev || bh->b_blocknr != block) {
- brelse(bh);
- goto repeat;
- }
- return bh;
- }
- /*
- * Ok, this is getblk, and it isn't very clear, again to hinder
- * race-conditions. Most of the code is seldom used, (ie repeating),
- * so it should be much more efficient than it looks.
- */
- struct buffer_head * getblk(int dev,int block)
- {
- struct buffer_head * tmp;
- repeat:
- if (tmp=get_hash_table(dev,block))
- return tmp;
- tmp = free_list;
- do {
- if (!tmp->b_count) {
- wait_on_buffer(tmp); /* we still have to wait */
- if (!tmp->b_count) /* on it, it might be dirty */
- break;
- }
- tmp = tmp->b_next_free;
- } while (tmp != free_list || (tmp=NULL));
- /* Kids, don't try THIS at home ^^^^^. Magic */
- if (!tmp) {
- printk("Sleeping on free buffer ..");
- sleep_on(&buffer_wait);
- printk("ok\n");
- goto repeat;
- }
- tmp->b_count++;
- remove_from_queues(tmp);
- /*
- * Now, when we know nobody can get to this node (as it's removed from the
- * free list), we write it out. We can sleep here without fear of race-
- * conditions.
- */
- if (tmp->b_dirt)
- sync_dev(tmp->b_dev);
- /* update buffer contents */
- tmp->b_dev=dev;
- tmp->b_blocknr=block;
- tmp->b_dirt=0;
- tmp->b_uptodate=0;
- /* NOTE!! While we possibly slept in sync_dev(), somebody else might have
- * added "this" block already, so check for that. Thank God for goto's.
- */
- if (find_buffer(dev,block)) {
- tmp->b_dev=0; /* ok, someone else has beaten us */
- tmp->b_blocknr=0; /* to it - free this block and */
- tmp->b_count=0; /* try again */
- insert_into_queues(tmp);
- goto repeat;
- }
- /* and then insert into correct position */
- insert_into_queues(tmp);
- return tmp;
- }
- void brelse(struct buffer_head * buf)
- {
- if (!buf)
- return;
- wait_on_buffer(buf);
- if (!(buf->b_count--))
- panic("Trying to free free buffer");
- wake_up(&buffer_wait);
- }
- /*
- * bread() reads a specified block and returns the buffer that contains
- * it. It returns NULL if the block was unreadable.
- */
- struct buffer_head * bread(int dev,int block)
- {
- struct buffer_head * bh;
- if (!(bh=getblk(dev,block)))
- panic("bread: getblk returned NULL\n");
- if (bh->b_uptodate)
- return bh;
- ll_rw_block(READ,bh);
- if (bh->b_uptodate)
- return bh;
- brelse(bh);
- return (NULL);
- }
- void buffer_init(void)
- {
- struct buffer_head * h = start_buffer;
- void * b = (void *) BUFFER_END;
- int i;
- while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
- h->b_dev = 0;
- h->b_dirt = 0;
- h->b_count = 0;
- h->b_lock = 0;
- h->b_uptodate = 0;
- h->b_wait = NULL;
- h->b_next = NULL;
- h->b_prev = NULL;
- h->b_data = (char *) b;
- h->b_prev_free = h-1;
- h->b_next_free = h+1;
- h++;
- NR_BUFFERS++;
- if (b == (void *) 0x100000)
- b = (void *) 0xA0000;
- }
- h--;
- free_list = start_buffer;
- free_list->b_prev_free = h;
- h->b_next_free = free_list;
- for (i=0;i<NR_HASH;i++)
- hash_table[i]=NULL;
- }
- ------------------------------------------------------------------------
- fs/char_dev.c
- #include <errno.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- extern int tty_read(unsigned minor,char * buf,int count);
- extern int tty_write(unsigned minor,char * buf,int count);
- static int rw_ttyx(int rw,unsigned minor,char * buf,int count);
- static int rw_tty(int rw,unsigned minor,char * buf,int count);
- typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count);
- #define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr)))
- static crw_ptr crw_table[]={
- NULL, /* nodev */
- NULL, /* /dev/mem */
- NULL, /* /dev/fd */
- NULL, /* /dev/hd */
- rw_ttyx, /* /dev/ttyx */
- rw_tty, /* /dev/tty */
- NULL, /* /dev/lp */
- NULL}; /* unnamed pipes */
- static int rw_ttyx(int rw,unsigned minor,char * buf,int count)
- {
- return ((rw==READ)?tty_read(minor,buf,count):
- tty_write(minor,buf,count));
- }
- static int rw_tty(int rw,unsigned minor,char * buf,int count)
- {
- if (current->tty<0)
- return -EPERM;
- return rw_ttyx(rw,current->tty,buf,count);
- }
- int rw_char(int rw,int dev, char * buf, int count)
- {
- crw_ptr call_addr;
- if (MAJOR(dev)>=NRDEVS)
- panic("rw_char: dev>NRDEV");
- if (!(call_addr=crw_table[MAJOR(dev)])) {
- printk("dev: %04x\n",dev);
- panic("Trying to r/w from/to nonexistent character device");
- }
- return call_addr(rw,MINOR(dev),buf,count);
- }
- ------------------------------------------------------------------------
- fs/exec.c
- #include <errno.h>
- #include <sys/stat.h>
- #include <a.out.h>
- #include <linux/fs.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <linux/mm.h>
- #include <asm/segment.h>
- extern int sys_exit(int exit_code);
- extern int sys_close(int fd);
- /*
- * MAX_ARG_PAGES defines the number of pages allocated for arguments
- * and envelope for the new program. 32 should suffice, this gives
- * a maximum env+arg of 128kB !
- */
- #define MAX_ARG_PAGES 32
- #define cp_block(from,to) \
- __asm__("pushl $0x10\n\t" \
- "pushl $0x17\n\t" \
- "pop %%es\n\t" \
- "cld\n\t" \
- "rep\n\t" \
- "movsl\n\t" \
- "pop %%es" \
- ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
- :"cx","di","si")
- /*
- * read_head() reads blocks 1-6 (not 0). Block 0 has already been
- * read for header information.
- */
- int read_head(struct m_inode * inode,int blocks)
- {
- struct buffer_head * bh;
- int count;
- if (blocks>6)
- blocks=6;
- for(count = 0 ; count<blocks ; count++) {
- if (!inode->i_zone[count+1])
- continue;
- if (!(bh=bread(inode->i_dev,inode->i_zone[count+1])))
- return -1;
- cp_block(bh->b_data,count*BLOCK_SIZE);
- brelse(bh);
- }
- return 0;
- }
- int read_ind(int dev,int ind,long size,unsigned long offset)
- {
- struct buffer_head * ih, * bh;
- unsigned short * table,block;
- if (size<=0)
- panic("size<=0 in read_ind");
- if (size>512*BLOCK_SIZE)
- size=512*BLOCK_SIZE;
- if (!ind)
- return 0;
- if (!(ih=bread(dev,ind)))
- return -1;
- table = (unsigned short *) ih->b_data;
- while (size>0) {
- if (block=*(table++))
- if (!(bh=bread(dev,block))) {
- brelse(ih);
- return -1;
- } else {
- cp_block(bh->b_data,offset);
- brelse(bh);
- }
- size -= BLOCK_SIZE;
- offset += BLOCK_SIZE;
- }
- brelse(ih);
- return 0;
- }
- /*
- * read_area() reads an area into %fs:mem.
- */
- int read_area(struct m_inode * inode,long size)
- {
- struct buffer_head * dind;
- unsigned short * table;
- int i,count;
- if ((i=read_head(inode,(size+BLOCK_SIZE-1)/BLOCK_SIZE)) ||
- (size -= BLOCK_SIZE*6)<=0)
- return i;
- if ((i=read_ind(inode->i_dev,inode->i_zone[7],size,BLOCK_SIZE*6)) ||
- (size -= BLOCK_SIZE*512)<=0)
- return i;
- if (!(i=inode->i_zone[8]))
- return 0;
- if (!(dind = bread(inode->i_dev,i)))
- return -1;
- table = (unsigned short *) dind->b_data;
- for(count=0 ; count<512 ; count++)
- if ((i=read_ind(inode->i_dev,*(table++),size,
- BLOCK_SIZE*(518+count))) || (size -= BLOCK_SIZE*512)<=0)
- return i;
- panic("Impossibly long executable");
- }
- /*
- * create_tables() parses the env- and arg-strings in new user
- * memory and creates the pointer tables from them, and puts their
- * addresses on the "stack", returning the new stack pointer value.
- */
- static unsigned long * create_tables(char * p,int argc,int envc)
- {
- unsigned long *argv,*envp;
- unsigned long * sp;
- sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
- sp -= envc+1;
- envp = sp;
- sp -= argc+1;
- argv = sp;
- put_fs_long((unsigned long)envp,--sp);
- put_fs_long((unsigned long)argv,--sp);
- put_fs_long((unsigned long)argc,--sp);
- while (argc-->0) {
- put_fs_long((unsigned long) p,argv++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,argv);
- while (envc-->0) {
- put_fs_long((unsigned long) p,envp++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,envp);
- return sp;
- }
- /*
- * count() counts the number of arguments/envelopes
- */
- static int count(char ** argv)
- {
- int i=0;
- char ** tmp;
- if (tmp = argv)
- while (get_fs_long((unsigned long *) (tmp++)))
- i++;
- return i;
- }
- /*
- * 'copy_string()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- */
- static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
- unsigned long p)
- {
- int len,i;
- char *tmp;
- while (argc-- > 0) {
- if (!(tmp = (char *)get_fs_long(((unsigned long *) argv)+argc)))
- panic("argc is wrong");
- len=0; /* remember zero-padding */
- do {
- len++;
- } while (get_fs_byte(tmp++));
- if (p-len < 0) /* this shouldn't happen - 128kB */
- return 0;
- i = ((unsigned) (p-len)) >> 12;
- while (i<MAX_ARG_PAGES && !page[i]) {
- if (!(page[i]=get_free_page()))
- return 0;
- i++;
- }
- do {
- --p;
- if (!page[p/PAGE_SIZE])
- panic("nonexistent page in exec.c");
- ((char *) page[p/PAGE_SIZE])[p%PAGE_SIZE] =
- get_fs_byte(--tmp);
- } while (--len);
- }
- return p;
- }
- static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
- {
- unsigned long code_limit,data_limit,code_base,data_base;
- int i;
- code_limit = text_size+PAGE_SIZE -1;
- code_limit &= 0xFFFFF000;
- data_limit = 0x4000000;
- code_base = get_base(current->ldt[1]);
- data_base = code_base;
- set_base(current->ldt[1],code_base);
- set_limit(current->ldt[1],code_limit);
- set_base(current->ldt[2],data_base);
- set_limit(current->ldt[2],data_limit);
- /* make sure fs points to the NEW data segment */
- __asm__("pushl $0x17\n\tpop %%fs"::);
- data_base += data_limit;
- for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
- data_base -= PAGE_SIZE;
- if (page[i])
- put_page(page[i],data_base);
- }
- return data_limit;
- }
- /*
- * 'do_execve()' executes a new program.
- */
- int do_execve(unsigned long * eip,long tmp,char * filename,
- char ** argv, char ** envp)
- {
- struct m_inode * inode;
- struct buffer_head * bh;
- struct exec ex;
- unsigned long page[MAX_ARG_PAGES];
- int i,argc,envc;
- unsigned long p;
- if ((0xffff & eip[1]) != 0x000f)
- panic("execve called from supervisor mode");
- for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
- page[i]=0;
- if (!(inode=namei(filename))) /* get executables inode */
- return -ENOENT;
- if (!S_ISREG(inode->i_mode)) { /* must be regular file */
- iput(inode);
- return -EACCES;
- }
- i = inode->i_mode;
- if (current->uid && current->euid) {
- if (current->euid == inode->i_uid)
- i >>= 6;
- else if (current->egid == inode->i_gid)
- i >>= 3;
- } else if (i & 0111)
- i=1;
- if (!(i & 1)) {
- iput(inode);
- return -ENOEXEC;
- }
- if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
- iput(inode);
- return -EACCES;
- }
- ex = *((struct exec *) bh->b_data); /* read exec-header */
- brelse(bh);
- if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
- ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
- inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
- iput(inode);
- return -ENOEXEC;
- }
- if (N_TXTOFF(ex) != BLOCK_SIZE)
- panic("N_TXTOFF != BLOCK_SIZE. See a.out.h.");
- argc = count(argv);
- envc = count(envp);
- p = copy_strings(envc,envp,page,PAGE_SIZE*MAX_ARG_PAGES-4);
- p = copy_strings(argc,argv,page,p);
- if (!p) {
- for (i=0 ; i<MAX_ARG_PAGES ; i++)
- free_page(page[i]);
- iput(inode);
- return -1;
- }
- /* OK, This is the point of no return */
- for (i=0 ; i<32 ; i++)
- current->sig_fn[i] = NULL;
- for (i=0 ; i<NR_OPEN ; i++)
- if ((current->close_on_exec>>i)&1)
- sys_close(i);
- current->close_on_exec = 0;
- free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
- free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
- if (last_task_used_math == current)
- last_task_used_math = NULL;
- current->used_math = 0;
- p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
- p = (unsigned long) create_tables((char *)p,argc,envc);
- current->brk = ex.a_bss +
- (current->end_data = ex.a_data +
- (current->end_code = ex.a_text));
- current->start_stack = p & 0xfffff000;
- i = read_area(inode,ex.a_text+ex.a_data);
- iput(inode);
- if (i<0)
- sys_exit(-1);
- i = ex.a_text+ex.a_data;
- while (i&0xfff)
- put_fs_byte(0,(char *) (i++));
- eip[0] = ex.a_entry; /* eip, magic happens :-) */
- eip[3] = p; /* stack pointer */
- return 0;
- }
- ------------------------------------------------------------------------
- fs/fcntl.c
- #include <string.h>
- #include <errno.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <asm/segment.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- extern int sys_close(int fd);
- static int dupfd(unsigned int fd, unsigned int arg)
- {
- if (fd >= NR_OPEN || !current->filp[fd])
- return -EBADF;
- if (arg >= NR_OPEN)
- return -EINVAL;
- while (arg < NR_OPEN)
- if (current->filp[arg])
- arg++;
- else
- break;
- if (arg >= NR_OPEN)
- return -EMFILE;
- current->close_on_exec &= ~(1<<arg);
- (current->filp[arg] = current->filp[fd])->f_count++;
- return arg;
- }
- int sys_dup2(unsigned int oldfd, unsigned int newfd)
- {
- sys_close(newfd);
- return dupfd(oldfd,newfd);
- }
- int sys_dup(unsigned int fildes)
- {
- return dupfd(fildes,0);
- }
- int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
- {
- struct file * filp;
- if (fd >= NR_OPEN || !(filp = current->filp[fd]))
- return -EBADF;
- switch (cmd) {
- case F_DUPFD:
- return dupfd(fd,arg);
- case F_GETFD:
- return (current->close_on_exec>>fd)&1;
- case F_SETFD:
- if (arg&1)
- current->close_on_exec |= (1<<fd);
- else
- current->close_on_exec &= ~(1<<fd);
- return 0;
- case F_GETFL:
- return filp->f_flags;
- case F_SETFL:
- filp->f_flags &= ~(O_APPEND | O_NONBLOCK);
- filp->f_flags |= arg & (O_APPEND | O_NONBLOCK);
- return 0;
- case F_GETLK: case F_SETLK: case F_SETLKW:
- return -1;
- default:
- return -1;
- }
- }
- ------------------------------------------------------------------------
- fs/file_dev.c
- #include <errno.h>
- #include <fcntl.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <asm/segment.h>
- #define MIN(a,b) (((a)<(b))?(a):(b))
- #define MAX(a,b) (((a)>(b))?(a):(b))
- int file_read(struct m_inode * inode, struct file * filp, char * buf, int count)
- {
- int left,chars,nr;
- struct buffer_head * bh;
- if ((left=count)<=0)
- return 0;
- while (left) {
- if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) {
- if (!(bh=bread(inode->i_dev,nr)))
- break;
- } else
- bh = NULL;
- nr = filp->f_pos % BLOCK_SIZE;
- chars = MIN( BLOCK_SIZE-nr , left );
- filp->f_pos += chars;
- left -= chars;
- if (bh) {
- char * p = nr + bh->b_data;
- while (chars-->0)
- put_fs_byte(*(p++),buf++);
- brelse(bh);
- } else {
- while (chars-->0)
- put_fs_byte(0,buf++);
- }
- }
- inode->i_atime = CURRENT_TIME;
- return (count-left)?(count-left):-ERROR;
- }
- int file_write(struct m_inode * inode, struct file * filp, char * buf, int count)
- {
- off_t pos;
- int block,c;
- struct buffer_head * bh;
- char * p;
- int i=0;
- /*
- * ok, append may not work when many processes are writing at the same time
- * but so what. That way leads to madness anyway.
- */
- if (filp->f_flags & O_APPEND)
- pos = inode->i_size;
- else
- pos = filp->f_pos;
- while (i<count) {
- if (!(block = create_block(inode,pos/BLOCK_SIZE)))
- break;
- if (!(bh=bread(inode->i_dev,block)))
- break;
- c = pos % BLOCK_SIZE;
- p = c + bh->b_data;
- bh->b_dirt = 1;
- c = BLOCK_SIZE-c;
- if (c > count-i) c = count-i;
- pos += c;
- if (pos > inode->i_size) {
- inode->i_size = pos;
- inode->i_dirt = 1;
- }
- i += c;
- while (c-->0)
- *(p++) = get_fs_byte(buf++);
- brelse(bh);
- }
- inode->i_mtime = CURRENT_TIME;
- if (!(filp->f_flags & O_APPEND)) {
- filp->f_pos = pos;
- inode->i_ctime = CURRENT_TIME;
- }
- return (i?i:-1);
- }
- ------------------------------------------------------------------------
- fs/file_table.c
- #include <linux/fs.h>
- struct file file_table[NR_FILE];
- ------------------------------------------------------------------------
- fs/inode.c
- #include <string.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <linux/mm.h>
- #include <asm/system.h>
- struct m_inode inode_table[NR_INODE]={{0,},};
- static void read_inode(struct m_inode * inode);
- static void write_inode(struct m_inode * inode);
- static inline void wait_on_inode(struct m_inode * inode)
- {
- cli();
- while (inode->i_lock)
- sleep_on(&inode->i_wait);
- sti();
- }
- static inline void lock_inode(struct m_inode * inode)
- {
- cli();
- while (inode->i_lock)
- sleep_on(&inode->i_wait);
- inode->i_lock=1;
- sti();
- }
- static inline void unlock_inode(struct m_inode * inode)
- {
- inode->i_lock=0;
- wake_up(&inode->i_wait);
- }
- void sync_inodes(void)
- {
- int i;
- struct m_inode * inode;
- inode = 0+inode_table;
- for(i=0 ; i<NR_INODE ; i++,inode++) {
- wait_on_inode(inode);
- if (inode->i_dirt && !inode->i_pipe)
- write_inode(inode);
- }
- }
- static int _bmap(struct m_inode * inode,int block,int create)
- {
- struct buffer_head * bh;
- int i;
- if (block<0)
- panic("_bmap: block<0");
- if (block >= 7+512+512*512)
- panic("_bmap: block>big");
- if (block<7) {
- if (create && !inode->i_zone[block])
- if (inode->i_zone[block]=new_block(inode->i_dev)) {
- inode->i_ctime=CURRENT_TIME;
- inode->i_dirt=1;
- }
- return inode->i_zone[block];
- }
- block -= 7;
- if (block<512) {
- if (create && !inode->i_zone[7])
- if (inode->i_zone[7]=new_block(inode->i_dev)) {
- inode->i_dirt=1;
- inode->i_ctime=CURRENT_TIME;
- }
- if (!inode->i_zone[7])
- return 0;
- if (!(bh = bread(inode->i_dev,inode->i_zone[7])))
- return 0;
- i = ((unsigned short *) (bh->b_data))[block];
- if (create && !i)
- if (i=new_block(inode->i_dev)) {
- ((unsigned short *) (bh->b_data))[block]=i;
- bh->b_dirt=1;
- }
- brelse(bh);
- return i;
- }
- block -= 512;
- if (create && !inode->i_zone[8])
- if (inode->i_zone[8]=new_block(inode->i_dev)) {
- inode->i_dirt=1;
- inode->i_ctime=CURRENT_TIME;
- }
- if (!inode->i_zone[8])
- return 0;
- if (!(bh=bread(inode->i_dev,inode->i_zone[8])))
- return 0;
- i = ((unsigned short *)bh->b_data)[block>>9];
- if (create && !i)
- if (i=new_block(inode->i_dev)) {
- ((unsigned short *) (bh->b_data))[block>>9]=i;
- bh->b_dirt=1;
- }
- brelse(bh);
- if (!i)
- return 0;
- if (!(bh=bread(inode->i_dev,i)))
- return 0;
- i = ((unsigned short *)bh->b_data)[block&511];
- if (create && !i)
- if (i=new_block(inode->i_dev)) {
- ((unsigned short *) (bh->b_data))[block&511]=i;
- bh->b_dirt=1;
- }
- brelse(bh);
- return i;
- }
- int bmap(struct m_inode * inode,int block)
- {
- return _bmap(inode,block,0);
- }
- int create_block(struct m_inode * inode, int block)
- {
- return _bmap(inode,block,1);
- }
- void iput(struct m_inode * inode)
- {
- if (!inode)
- return;
- wait_on_inode(inode);
- if (!inode->i_count)
- panic("iput: trying to free free inode");
- if (inode->i_pipe) {
- wake_up(&inode->i_wait);
- if (--inode->i_count)
- return;
- free_page(inode->i_size);
- inode->i_count=0;
- inode->i_dirt=0;
- inode->i_pipe=0;
- return;
- }
- if (!inode->i_dev || inode->i_count>1) {
- inode->i_count--;
- return;
- }
- repeat:
- if (!inode->i_nlinks) {
- truncate(inode);
- free_inode(inode);
- return;
- }
- if (inode->i_dirt) {
- write_inode(inode); /* we can sleep - so do again */
- wait_on_inode(inode);
- goto repeat;
- }
- inode->i_count--;
- return;
- }
- static volatile int last_allocated_inode = 0;
- struct m_inode * get_empty_inode(void)
- {
- struct m_inode * inode;
- int inr;
- while (1) {
- inode = NULL;
- inr = last_allocated_inode;
- do {
- if (!inode_table[inr].i_count) {
- inode = inr + inode_table;
- break;
- }
- inr++;
- if (inr>=NR_INODE)
- inr=0;
- } while (inr != last_allocated_inode);
- if (!inode) {
- for (inr=0 ; inr<NR_INODE ; inr++)
- printk("%04x: %6d\t",inode_table[inr].i_dev,
- inode_table[inr].i_num);
- panic("No free inodes in mem");
- }
- last_allocated_inode = inr;
- wait_on_inode(inode);
- while (inode->i_dirt) {
- write_inode(inode);
- wait_on_inode(inode);
- }
- if (!inode->i_count)
- break;
- }
- memset(inode,0,sizeof(*inode));
- inode->i_count = 1;
- return inode;
- }
- struct m_inode * get_pipe_inode(void)
- {
- struct m_inode * inode;
- if (!(inode = get_empty_inode()))
- return NULL;
- if (!(inode->i_size=get_free_page())) {
- inode->i_count = 0;
- return NULL;
- }
- inode->i_count = 2; /* sum of readers/writers */
- PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
- inode->i_pipe = 1;
- return inode;
- }
- struct m_inode * iget(int dev,int nr)
- {
- struct m_inode * inode, * empty;
- if (!dev)
- panic("iget with dev==0");
- empty = get_empty_inode();
- inode = inode_table;
- while (inode < NR_INODE+inode_table) {
- if (inode->i_dev != dev || inode->i_num != nr) {
- inode++;
- continue;
- }
- wait_on_inode(inode);
- if (inode->i_dev != dev || inode->i_num != nr) {
- inode = inode_table;
- continue;
- }
- inode->i_count++;
- if (empty)
- iput(empty);
- return inode;
- }
- if (!empty)
- return (NULL);
- inode=empty;
- inode->i_dev = dev;
- inode->i_num = nr;
- read_inode(inode);
- return inode;
- }
- static void read_inode(struct m_inode * inode)
- {
- struct super_block * sb;
- struct buffer_head * bh;
- int block;
- lock_inode(inode);
- sb=get_super(inode->i_dev);
- block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
- (inode->i_num-1)/INODES_PER_BLOCK;
- if (!(bh=bread(inode->i_dev,block)))
- panic("unable to read i-node block");
- *(struct d_inode *)inode =
- ((struct d_inode *)bh->b_data)
- [(inode->i_num-1)%INODES_PER_BLOCK];
- brelse(bh);
- unlock_inode(inode);
- }
- static void write_inode(struct m_inode * inode)
- {
- struct super_block * sb;
- struct buffer_head * bh;
- int block;
- lock_inode(inode);
- sb=get_super(inode->i_dev);
- block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
- (inode->i_num-1)/INODES_PER_BLOCK;
- if (!(bh=bread(inode->i_dev,block)))
- panic("unable to read i-node block");
- ((struct d_inode *)bh->b_data)
- [(inode->i_num-1)%INODES_PER_BLOCK] =
- *(struct d_inode *)inode;
- bh->b_dirt=1;
- inode->i_dirt=0;
- brelse(bh);
- unlock_inode(inode);
- }
- ------------------------------------------------------------------------
- fs/ioctl.c
- #include <string.h>
- #include <errno.h>
- #include <sys/stat.h>
- #include <linux/sched.h>
- extern int tty_ioctl(int dev, int cmd, int arg);
- typedef int (*ioctl_ptr)(int dev,int cmd,int arg);
- #define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr)))
- static ioctl_ptr ioctl_table[]={
- NULL, /* nodev */
- NULL, /* /dev/mem */
- NULL, /* /dev/fd */
- NULL, /* /dev/hd */
- tty_ioctl, /* /dev/ttyx */
- tty_ioctl, /* /dev/tty */
- NULL, /* /dev/lp */
- NULL}; /* named pipes */
- int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
- {
- struct file * filp;
- int dev,mode;
- if (fd >= NR_OPEN || !(filp = current->filp[fd]))
- return -EBADF;
- mode=filp->f_inode->i_mode;
- if (!S_ISCHR(mode) && !S_ISBLK(mode))
- return -EINVAL;
- dev = filp->f_inode->i_zone[0];
- if (MAJOR(dev) >= NRDEVS)
- panic("unknown device for ioctl");
- if (!ioctl_table[MAJOR(dev)])
- return -ENOTTY;
- return ioctl_table[MAJOR(dev)](dev,cmd,arg);
- }
- ------------------------------------------------------------------------
- fs/Makefile
- 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
- ------------------------------------------------------------------------
- fs/namei.c
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <asm/segment.h>
- #include <string.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <const.h>
- #include <sys/stat.h>
- #define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
- /*
- * comment out this line if you want names > NAME_LEN chars to be
- * truncated. Else they will be disallowed.
- */
- /* #define NO_TRUNCATE */
- #define MAY_EXEC 1
- #define MAY_WRITE 2
- #define MAY_READ 4
- /*
- * permission()
- *
- * is used to check for read/write/execute permissions on a file.
- * I don't know if we should look at just the euid or both euid and
- * uid, but that should be easily changed.
- */
- static int permission(struct m_inode * inode,int mask)
- {
- int mode = inode->i_mode;
- /* special case: not even root can read/write a deleted file */
- if (inode->i_dev && !inode->i_nlinks)
- return 0;
- if (!(current->uid && current->euid))
- mode=0777;
- else if (current->uid==inode->i_uid || current->euid==inode->i_uid)
- mode >>= 6;
- else if (current->gid==inode->i_gid || current->egid==inode->i_gid)
- mode >>= 3;
- return mode & mask & 0007;
- }
- /*
- * ok, we cannot use strncmp, as the name is not in our data space.
- * Thus we'll have to use match. No big problem. Match also makes
- * some sanity tests.
- *
- * NOTE! unlike strncmp, match returns 1 for success, 0 for failure.
- */
- static int match(int len,const char * name,struct dir_entry * de)
- {
- register int same __asm__("ax");
- if (!de || !de->inode || len > NAME_LEN)
- return 0;
- if (len < NAME_LEN && de->name[len])
- return 0;
- __asm__("cld\n\t"
- "fs ; repe ; cmpsb\n\t"
- "setz %%al"
- :"=a" (same)
- :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
- :"cx","di","si");
- return same;
- }
- /*
- * find_entry()
- *
- * finds and entry in the specified directory with the wanted name. It
- * returns the cache buffer in which the entry was found, and the entry
- * itself (as a parameter - res_dir). It does NOT read the inode of the
- * entry - you'll have to do that yourself if you want to.
- */
- static struct buffer_head * find_entry(struct m_inode * dir,
- const char * name, int namelen, struct dir_entry ** res_dir)
- {
- int entries;
- int block,i;
- struct buffer_head * bh;
- struct dir_entry * de;
- #ifdef NO_TRUNCATE
- if (namelen > NAME_LEN)
- return NULL;
- #else
- if (namelen > NAME_LEN)
- namelen = NAME_LEN;
- #endif
- entries = dir->i_size / (sizeof (struct dir_entry));
- *res_dir = NULL;
- if (!namelen)
- return NULL;
- if (!(block = dir->i_zone[0]))
- return NULL;
- if (!(bh = bread(dir->i_dev,block)))
- return NULL;
- i = 0;
- de = (struct dir_entry *) bh->b_data;
- while (i < entries) {
- if ((char *)de >= BLOCK_SIZE+bh->b_data) {
- brelse(bh);
- bh = NULL;
- if (!(block = bmap(dir,i/DIR_ENTRIES_PER_BLOCK)) ||
- !(bh = bread(dir->i_dev,block))) {
- i += DIR_ENTRIES_PER_BLOCK;
- continue;
- }
- de = (struct dir_entry *) bh->b_data;
- }
- if (match(namelen,name,de)) {
- *res_dir = de;
- return bh;
- }
- de++;
- i++;
- }
- brelse(bh);
- return NULL;
- }
- /*
- * add_entry()
- *
- * adds a file entry to the specified directory, using the same
- * semantics as find_entry(). It returns NULL if it failed.
- *
- * NOTE!! The inode part of 'de' is left at 0 - which means you
- * may not sleep between calling this and putting something into
- * the entry, as someone else might have used it while you slept.
- */
- static struct buffer_head * add_entry(struct m_inode * dir,
- const char * name, int namelen, struct dir_entry ** res_dir)
- {
- int block,i;
- struct buffer_head * bh;
- struct dir_entry * de;
- *res_dir = NULL;
- #ifdef NO_TRUNCATE
- if (namelen > NAME_LEN)
- return NULL;
- #else
- if (namelen > NAME_LEN)
- namelen = NAME_LEN;
- #endif
- if (!namelen)
- return NULL;
- if (!(block = dir->i_zone[0]))
- return NULL;
- if (!(bh = bread(dir->i_dev,block)))
- return NULL;
- i = 0;
- de = (struct dir_entry *) bh->b_data;
- while (1) {
- if ((char *)de >= BLOCK_SIZE+bh->b_data) {
- brelse(bh);
- bh = NULL;
- block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK);
- if (!block)
- return NULL;
- if (!(bh = bread(dir->i_dev,block))) {
- i += DIR_ENTRIES_PER_BLOCK;
- continue;
- }
- de = (struct dir_entry *) bh->b_data;
- }
- if (i*sizeof(struct dir_entry) >= dir->i_size) {
- de->inode=0;
- dir->i_size = (i+1)*sizeof(struct dir_entry);
- dir->i_dirt = 1;
- dir->i_ctime = CURRENT_TIME;
- }
- if (!de->inode) {
- dir->i_mtime = CURRENT_TIME;
- for (i=0; i < NAME_LEN ; i++)
- de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
- bh->b_dirt = 1;
- *res_dir = de;
- return bh;
- }
- de++;
- i++;
- }
- brelse(bh);
- return NULL;
- }
- /*
- * get_dir()
- *
- * Getdir traverses the pathname until it hits the topmost directory.
- * It returns NULL on failure.
- */
- static struct m_inode * get_dir(const char * pathname)
- {
- char c;
- const char * thisname;
- struct m_inode * inode;
- struct buffer_head * bh;
- int namelen,inr,idev;
- struct dir_entry * de;
- if (!current->root || !current->root->i_count)
- panic("No root inode");
- if (!current->pwd || !current->pwd->i_count)
- panic("No cwd inode");
- if ((c=get_fs_byte(pathname))=='/') {
- inode = current->root;
- pathname++;
- } else if (c)
- inode = current->pwd;
- else
- return NULL; /* empty name is bad */
- inode->i_count++;
- while (1) {
- thisname = pathname;
- if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) {
- iput(inode);
- return NULL;
- }
- for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++)
- /* nothing */ ;
- if (!c)
- return inode;
- if (!(bh = find_entry(inode,thisname,namelen,&de))) {
- iput(inode);
- return NULL;
- }
- inr = de->inode;
- idev = inode->i_dev;
- brelse(bh);
- iput(inode);
- if (!(inode = iget(idev,inr)))
- return NULL;
- }
- }
- /*
- * dir_namei()
- *
- * dir_namei() returns the inode of the directory of the
- * specified name, and the name within that directory.
- */
- static struct m_inode * dir_namei(const char * pathname,
- int * namelen, const char ** name)
- {
- char c;
- const char * basename;
- struct m_inode * dir;
- if (!(dir = get_dir(pathname)))
- return NULL;
- basename = pathname;
- while (c=get_fs_byte(pathname++))
- if (c=='/')
- basename=pathname;
- *namelen = pathname-basename-1;
- *name = basename;
- return dir;
- }
- /*
- * namei()
- *
- * is used by most simple commands to get the inode of a specified name.
- * Open, link etc use their own routines, but this is enough for things
- * like 'chmod' etc.
- */
- struct m_inode * namei(const char * pathname)
- {
- const char * basename;
- int inr,dev,namelen;
- struct m_inode * dir;
- struct buffer_head * bh;
- struct dir_entry * de;
- if (!(dir = dir_namei(pathname,&namelen,&basename)))
- return NULL;
- if (!namelen) /* special case: '/usr/' etc */
- return dir;
- bh = find_entry(dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- return NULL;
- }
- inr = de->inode;
- dev = dir->i_dev;
- brelse(bh);
- iput(dir);
- dir=iget(dev,inr);
- if (dir) {
- dir->i_atime=CURRENT_TIME;
- dir->i_dirt=1;
- }
- return dir;
- }
- /*
- * open_namei()
- *
- * namei for open - this is in fact almost the whole open-routine.
- */
- int open_namei(const char * pathname, int flag, int mode,
- struct m_inode ** res_inode)
- {
- const char * basename;
- int inr,dev,namelen;
- struct m_inode * dir, *inode;
- struct buffer_head * bh;
- struct dir_entry * de;
- if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
- flag |= O_WRONLY;
- mode &= 0777 & ~current->umask;
- mode |= I_REGULAR;
- if (!(dir = dir_namei(pathname,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) { /* special case: '/usr/' etc */
- if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
- *res_inode=dir;
- return 0;
- }
- iput(dir);
- return -EISDIR;
- }
- bh = find_entry(dir,basename,namelen,&de);
- if (!bh) {
- if (!(flag & O_CREAT)) {
- iput(dir);
- return -ENOENT;
- }
- if (!permission(dir,MAY_WRITE)) {
- iput(dir);
- return -EACCES;
- }
- inode = new_inode(dir->i_dev);
- if (!inode) {
- iput(dir);
- return -ENOSPC;
- }
- inode->i_mode = mode;
- inode->i_dirt = 1;
- bh = add_entry(dir,basename,namelen,&de);
- if (!bh) {
- inode->i_nlinks--;
- iput(inode);
- iput(dir);
- return -ENOSPC;
- }
- de->inode = inode->i_num;
- bh->b_dirt = 1;
- brelse(bh);
- iput(dir);
- *res_inode = inode;
- return 0;
- }
- inr = de->inode;
- dev = dir->i_dev;
- brelse(bh);
- iput(dir);
- if (flag & O_EXCL)
- return -EEXIST;
- if (!(inode=iget(dev,inr)))
- return -EACCES;
- if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
- permission(inode,ACC_MODE(flag))!=ACC_MODE(flag)) {
- iput(inode);
- return -EPERM;
- }
- inode->i_atime = CURRENT_TIME;
- if (flag & O_TRUNC)
- truncate(inode);
- *res_inode = inode;
- return 0;
- }
- int sys_mkdir(const char * pathname, int mode)
- {
- const char * basename;
- int namelen;
- struct m_inode * dir, * inode;
- struct buffer_head * bh, *dir_block;
- struct dir_entry * de;
- if (current->euid && current->uid)
- return -EPERM;
- if (!(dir = dir_namei(pathname,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
- }
- if (!permission(dir,MAY_WRITE)) {
- iput(dir);
- return -EPERM;
- }
- bh = find_entry(dir,basename,namelen,&de);
- if (bh) {
- brelse(bh);
- iput(dir);
- return -EEXIST;
- }
- inode = new_inode(dir->i_dev);
- if (!inode) {
- iput(dir);
- return -ENOSPC;
- }
- inode->i_size = 32;
- inode->i_dirt = 1;
- inode->i_mtime = inode->i_atime = CURRENT_TIME;
- if (!(inode->i_zone[0]=new_block(inode->i_dev))) {
- iput(dir);
- inode->i_nlinks--;
- iput(inode);
- return -ENOSPC;
- }
- inode->i_dirt = 1;
- if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) {
- iput(dir);
- free_block(inode->i_dev,inode->i_zone[0]);
- inode->i_nlinks--;
- iput(inode);
- return -ERROR;
- }
- de = (struct dir_entry *) dir_block->b_data;
- de->inode=inode->i_num;
- strcpy(de->name,".");
- de++;
- de->inode = dir->i_num;
- strcpy(de->name,"..");
- inode->i_nlinks = 2;
- dir_block->b_dirt = 1;
- brelse(dir_block);
- inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask);
- inode->i_dirt = 1;
- bh = add_entry(dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- free_block(inode->i_dev,inode->i_zone[0]);
- inode->i_nlinks=0;
- iput(inode);
- return -ENOSPC;
- }
- de->inode = inode->i_num;
- bh->b_dirt = 1;
- dir->i_nlinks++;
- dir->i_dirt = 1;
- iput(dir);
- iput(inode);
- brelse(bh);
- return 0;
- }
- /*
- * routine to check that the specified directory is empty (for rmdir)
- */
- static int empty_dir(struct m_inode * inode)
- {
- int nr,block;
- int len;
- struct buffer_head * bh;
- struct dir_entry * de;
- len = inode->i_size / sizeof (struct dir_entry);
- if (len<2 || !inode->i_zone[0] ||
- !(bh=bread(inode->i_dev,inode->i_zone[0]))) {
- printk("warning - bad directory on dev %04x\n",inode->i_dev);
- return 0;
- }
- de = (struct dir_entry *) bh->b_data;
- if (de[0].inode != inode->i_num || !de[1].inode ||
- strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
- printk("warning - bad directory on dev %04x\n",inode->i_dev);
- return 0;
- }
- nr = 2;
- de += 2;
- while (nr<len) {
- if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
- brelse(bh);
- block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK);
- if (!block) {
- nr += DIR_ENTRIES_PER_BLOCK;
- continue;
- }
- if (!(bh=bread(inode->i_dev,block)))
- return 0;
- de = (struct dir_entry *) bh->b_data;
- }
- if (de->inode) {
- brelse(bh);
- return 0;
- }
- de++;
- nr++;
- }
- brelse(bh);
- return 1;
- }
- int sys_rmdir(const char * name)
- {
- const char * basename;
- int namelen;
- struct m_inode * dir, * inode;
- struct buffer_head * bh;
- struct dir_entry * de;
- if (current->euid && current->uid)
- return -EPERM;
- if (!(dir = dir_namei(name,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
- }
- bh = find_entry(dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- return -ENOENT;
- }
- if (!permission(dir,MAY_WRITE)) {
- iput(dir);
- brelse(bh);
- return -EPERM;
- }
- if (!(inode = iget(dir->i_dev, de->inode))) {
- iput(dir);
- brelse(bh);
- return -EPERM;
- }
- if (inode == dir) { /* we may not delete ".", but "../dir" is ok */
- iput(inode);
- iput(dir);
- brelse(bh);
- return -EPERM;
- }
- if (!S_ISDIR(inode->i_mode)) {
- iput(inode);
- iput(dir);
- brelse(bh);
- return -ENOTDIR;
- }
- if (!empty_dir(inode)) {
- iput(inode);
- iput(dir);
- brelse(bh);
- return -ENOTEMPTY;
- }
- if (inode->i_nlinks != 2)
- printk("empty directory has nlink!=2 (%d)",inode->i_nlinks);
- de->inode = 0;
- bh->b_dirt = 1;
- brelse(bh);
- inode->i_nlinks=0;
- inode->i_dirt=1;
- dir->i_nlinks--;
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_dirt=1;
- iput(dir);
- iput(inode);
- return 0;
- }
- int sys_unlink(const char * name)
- {
- const char * basename;
- int namelen;
- struct m_inode * dir, * inode;
- struct buffer_head * bh;
- struct dir_entry * de;
- if (!(dir = dir_namei(name,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
- }
- if (!permission(dir,MAY_WRITE)) {
- iput(dir);
- return -EPERM;
- }
- bh = find_entry(dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- return -ENOENT;
- }
- inode = iget(dir->i_dev, de->inode);
- if (!inode) {
- printk("iget failed in delete (%04x:%d)",dir->i_dev,de->inode);
- iput(dir);
- brelse(bh);
- return -ENOENT;
- }
- if (!S_ISREG(inode->i_mode)) {
- iput(inode);
- iput(dir);
- brelse(bh);
- return -EPERM;
- }
- if (!inode->i_nlinks) {
- printk("Deleting nonexistent file (%04x:%d), %d\n",
- inode->i_dev,inode->i_num,inode->i_nlinks);
- inode->i_nlinks=1;
- }
- de->inode = 0;
- bh->b_dirt = 1;
- brelse(bh);
- inode->i_nlinks--;
- inode->i_dirt = 1;
- inode->i_ctime = CURRENT_TIME;
- iput(inode);
- iput(dir);
- return 0;
- }
- int sys_link(const char * oldname, const char * newname)
- {
- struct dir_entry * de;
- struct m_inode * oldinode, * dir;
- struct buffer_head * bh;
- const char * basename;
- int namelen;
- oldinode=namei(oldname);
- if (!oldinode)
- return -ENOENT;
- if (!S_ISREG(oldinode->i_mode)) {
- iput(oldinode);
- return -EPERM;
- }
- dir = dir_namei(newname,&namelen,&basename);
- if (!dir) {
- iput(oldinode);
- return -EACCES;
- }
- if (!namelen) {
- iput(oldinode);
- iput(dir);
- return -EPERM;
- }
- if (dir->i_dev != oldinode->i_dev) {
- iput(dir);
- iput(oldinode);
- return -EXDEV;
- }
- if (!permission(dir,MAY_WRITE)) {
- iput(dir);
- iput(oldinode);
- return -EACCES;
- }
- bh = find_entry(dir,basename,namelen,&de);
- if (bh) {
- brelse(bh);
- iput(dir);
- iput(oldinode);
- return -EEXIST;
- }
- bh = add_entry(dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- iput(oldinode);
- return -ENOSPC;
- }
- de->inode = oldinode->i_num;
- bh->b_dirt = 1;
- brelse(bh);
- iput(dir);
- oldinode->i_nlinks++;
- oldinode->i_ctime = CURRENT_TIME;
- oldinode->i_dirt = 1;
- iput(oldinode);
- return 0;
- }
- ------------------------------------------------------------------------
- fs/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/tty.h>
- #include <linux/kernel.h>
- #include <asm/segment.h>
- int sys_utime(char * filename, struct utimbuf * times)
- {
- struct m_inode * inode;
- long actime,modtime;
- if (!(inode=namei(filename)))
- return -ENOENT;
- if (times) {
- actime = get_fs_long((unsigned long *) ×->actime);
- modtime = get_fs_long((unsigned long *) ×->modtime);
- } else
- actime = modtime = CURRENT_TIME;
- inode->i_atime = actime;
- inode->i_mtime = modtime;
- inode->i_dirt = 1;
- iput(inode);
- return 0;
- }
- int sys_access(const char * filename,int mode)
- {
- struct m_inode * inode;
- int res;
- mode &= 0007;
- if (!(inode=namei(filename)))
- return -EACCES;
- res = inode->i_mode & 0777;
- iput(inode);
- if (!(current->euid && current->uid))
- if (res & 0111)
- res = 0777;
- else
- res = 0666;
- if (current->euid == inode->i_uid)
- res >>= 6;
- else if (current->egid == inode->i_gid)
- res >>= 6;
- if ((res & 0007 & mode) == mode)
- return 0;
- return -EACCES;
- }
- int sys_chdir(const char * filename)
- {
- struct m_inode * inode;
- if (!(inode = namei(filename)))
- return -ENOENT;
- if (!S_ISDIR(inode->i_mode)) {
- iput(inode);
- return -ENOTDIR;
- }
- iput(current->pwd);
- current->pwd = inode;
- return (0);
- }
- int sys_chroot(const char * filename)
- {
- struct m_inode * inode;
- if (!(inode=namei(filename)))
- return -ENOENT;
- if (!S_ISDIR(inode->i_mode)) {
- iput(inode);
- return -ENOTDIR;
- }
- iput(current->root);
- current->root = inode;
- return (0);
- }
- int sys_chmod(const char * filename,int mode)
- {
- struct m_inode * inode;
- if (!(inode=namei(filename)))
- return -ENOENT;
- if (current->uid && current->euid)
- if (current->uid!=inode->i_uid && current->euid!=inode->i_uid) {
- iput(inode);
- return -EACCES;
- } else
- mode = (mode & 0777) | (inode->i_mode & 07000);
- inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
- inode->i_dirt = 1;
- iput(inode);
- return 0;
- }
- int sys_chown(const char * filename,int uid,int gid)
- {
- struct m_inode * inode;
- if (!(inode=namei(filename)))
- return -ENOENT;
- if (current->uid && current->euid) {
- iput(inode);
- return -EACCES;
- }
- inode->i_uid=uid;
- inode->i_gid=gid;
- inode->i_dirt=1;
- iput(inode);
- return 0;
- }
- int sys_open(const char * filename,int flag,int mode)
- {
- struct m_inode * inode;
- struct file * f;
- int i,fd;
- mode &= 0777 & ~current->umask;
- for(fd=0 ; fd<NR_OPEN ; fd++)
- if (!current->filp[fd])
- break;
- if (fd>=NR_OPEN)
- return -EINVAL;
- current->close_on_exec &= ~(1<<fd);
- f=0+file_table;
- for (i=0 ; i<NR_FILE ; i++,f++)
- if (!f->f_count) break;
- if (i>=NR_FILE)
- return -EINVAL;
- (current->filp[fd]=f)->f_count++;
- if ((i=open_namei(filename,flag,mode,&inode))<0) {
- current->filp[fd]=NULL;
- f->f_count=0;
- return i;
- }
- /* ttys are somewhat special (ttyxx major==4, tty major==5) */
- if (S_ISCHR(inode->i_mode))
- if (MAJOR(inode->i_zone[0])==4) {
- if (current->leader && current->tty<0) {
- current->tty = MINOR(inode->i_zone[0]);
- tty_table[current->tty].pgrp = current->pgrp;
- }
- } else if (MAJOR(inode->i_zone[0])==5)
- if (current->tty<0) {
- iput(inode);
- current->filp[fd]=NULL;
- f->f_count=0;
- return -EPERM;
- }
- f->f_mode = inode->i_mode;
- f->f_flags = flag;
- f->f_count = 1;
- f->f_inode = inode;
- f->f_pos = 0;
- return (fd);
- }
- int sys_creat(const char * pathname, int mode)
- {
- return sys_open(pathname, O_CREAT | O_TRUNC, mode);
- }
- int sys_close(unsigned int fd)
- {
- struct file * filp;
- if (fd >= NR_OPEN)
- return -EINVAL;
- current->close_on_exec &= ~(1<<fd);
- if (!(filp = current->filp[fd]))
- return -EINVAL;
- current->filp[fd] = NULL;
- if (filp->f_count == 0)
- panic("Close: file count is 0");
- if (--filp->f_count)
- return (0);
- iput(filp->f_inode);
- return (0);
- }
- ------------------------------------------------------------------------
- fs/pipe.c
- #include <signal.h>
- #include <linux/sched.h>
- #include <linux/mm.h> /* for get_free_page */
- #include <asm/segment.h>
- int read_pipe(struct m_inode * inode, char * buf, int count)
- {
- char * b=buf;
- while (PIPE_EMPTY(*inode)) {
- wake_up(&inode->i_wait);
- if (inode->i_count != 2) /* are there any writers left? */
- return 0;
- sleep_on(&inode->i_wait);
- }
- while (count>0 && !(PIPE_EMPTY(*inode))) {
- count --;
- put_fs_byte(((char *)inode->i_size)[PIPE_TAIL(*inode)],b++);
- INC_PIPE( PIPE_TAIL(*inode) );
- }
- wake_up(&inode->i_wait);
- return b-buf;
- }
- int write_pipe(struct m_inode * inode, char * buf, int count)
- {
- char * b=buf;
- wake_up(&inode->i_wait);
- if (inode->i_count != 2) { /* no readers */
- current->signal |= (1<<(SIGPIPE-1));
- return -1;
- }
- while (count-->0) {
- while (PIPE_FULL(*inode)) {
- wake_up(&inode->i_wait);
- if (inode->i_count != 2) {
- current->signal |= (1<<(SIGPIPE-1));
- return b-buf;
- }
- sleep_on(&inode->i_wait);
- }
- ((char *)inode->i_size)[PIPE_HEAD(*inode)] = get_fs_byte(b++);
- INC_PIPE( PIPE_HEAD(*inode) );
- wake_up(&inode->i_wait);
- }
- wake_up(&inode->i_wait);
- return b-buf;
- }
- int sys_pipe(unsigned long * fildes)
- {
- struct m_inode * inode;
- struct file * f[2];
- int fd[2];
- int i,j;
- j=0;
- for(i=0;j<2 && i<NR_FILE;i++)
- if (!file_table[i].f_count)
- (f[j++]=i+file_table)->f_count++;
- if (j==1)
- f[0]->f_count=0;
- if (j<2)
- return -1;
- j=0;
- for(i=0;j<2 && i<NR_OPEN;i++)
- if (!current->filp[i]) {
- current->filp[ fd[j]=i ] = f[j];
- j++;
- }
- if (j==1)
- current->filp[fd[0]]=NULL;
- if (j<2) {
- f[0]->f_count=f[1]->f_count=0;
- return -1;
- }
- if (!(inode=get_pipe_inode())) {
- current->filp[fd[0]] =
- current->filp[fd[1]] = NULL;
- f[0]->f_count = f[1]->f_count = 0;
- return -1;
- }
- f[0]->f_inode = f[1]->f_inode = inode;
- f[0]->f_pos = f[1]->f_pos = 0;
- f[0]->f_mode = 1; /* read */
- f[1]->f_mode = 2; /* write */
- put_fs_long(fd[0],0+fildes);
- put_fs_long(fd[1],1+fildes);
- return 0;
- }
- ------------------------------------------------------------------------
- fs/read_write.c
- #include <sys/stat.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <asm/segment.h>
- extern int rw_char(int rw,int dev, char * buf, int count);
- extern int read_pipe(struct m_inode * inode, char * buf, int count);
- extern int write_pipe(struct m_inode * inode, char * buf, int count);
- extern int block_read(int dev, off_t * pos, char * buf, int count);
- extern int block_write(int dev, off_t * pos, char * buf, int count);
- extern int file_read(struct m_inode * inode, struct file * filp,
- char * buf, int count);
- extern int file_write(struct m_inode * inode, struct file * filp,
- char * buf, int count);
- int sys_lseek(unsigned int fd,off_t offset, int origin)
- {
- struct file * file;
- int tmp;
- if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode)
- || !IS_BLOCKDEV(MAJOR(file->f_inode->i_dev)))
- return -EBADF;
- if (file->f_inode->i_pipe)
- return -ESPIPE;
- switch (origin) {
- case 0:
- if (offset<0) return -EINVAL;
- file->f_pos=offset;
- break;
- case 1:
- if (file->f_pos+offset<0) return -EINVAL;
- file->f_pos += offset;
- break;
- case 2:
- if ((tmp=file->f_inode->i_size+offset) < 0)
- return -EINVAL;
- file->f_pos = tmp;
- break;
- default:
- return -EINVAL;
- }
- return file->f_pos;
- }
- int sys_read(unsigned int fd,char * buf,int count)
- {
- struct file * file;
- struct m_inode * inode;
- if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd]))
- return -EINVAL;
- if (!count)
- return 0;
- verify_area(buf,count);
- inode = file->f_inode;
- if (inode->i_pipe)
- return (file->f_mode&1)?read_pipe(inode,buf,count):-1;
- if (S_ISCHR(inode->i_mode))
- return rw_char(READ,inode->i_zone[0],buf,count);
- if (S_ISBLK(inode->i_mode))
- return block_read(inode->i_zone[0],&file->f_pos,buf,count);
- if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
- if (count+file->f_pos > inode->i_size)
- count = inode->i_size - file->f_pos;
- if (count<=0)
- return 0;
- return file_read(inode,file,buf,count);
- }
- printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
- return -EINVAL;
- }
- int sys_write(unsigned int fd,char * buf,int count)
- {
- struct file * file;
- struct m_inode * inode;
- if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd]))
- return -EINVAL;
- if (!count)
- return 0;
- inode=file->f_inode;
- if (inode->i_pipe)
- return (file->f_mode&2)?write_pipe(inode,buf,count):-1;
- if (S_ISCHR(inode->i_mode))
- return rw_char(WRITE,inode->i_zone[0],buf,count);
- if (S_ISBLK(inode->i_mode))
- return block_write(inode->i_zone[0],&file->f_pos,buf,count);
- if (S_ISREG(inode->i_mode))
- return file_write(inode,file,buf,count);
- printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode);
- return -EINVAL;
- }
- ------------------------------------------------------------------------
- fs/stat.c
- #include <errno.h>
- #include <sys/stat.h>
- #include <linux/fs.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <asm/segment.h>
- static int cp_stat(struct m_inode * inode, struct stat * statbuf)
- {
- struct stat tmp;
- int i;
- verify_area(statbuf,sizeof (* statbuf));
- tmp.st_dev = inode->i_dev;
- tmp.st_ino = inode->i_num;
- tmp.st_mode = inode->i_mode;
- tmp.st_nlink = inode->i_nlinks;
- tmp.st_uid = inode->i_uid;
- tmp.st_gid = inode->i_gid;
- tmp.st_rdev = inode->i_zone[0];
- tmp.st_size = inode->i_size;
- tmp.st_atime = inode->i_atime;
- tmp.st_mtime = inode->i_mtime;
- tmp.st_ctime = inode->i_ctime;
- for (i=0 ; i<sizeof (tmp) ; i++)
- put_fs_byte(((char *) &tmp)[i],&((char *) statbuf)[i]);
- return (0);
- }
- int sys_stat(char * filename, struct stat * statbuf)
- {
- int i;
- struct m_inode * inode;
- if (!(inode=namei(filename)))
- return -ENOENT;
- i=cp_stat(inode,statbuf);
- iput(inode);
- return i;
- }
- int sys_fstat(unsigned int fd, struct stat * statbuf)
- {
- struct file * f;
- struct m_inode * inode;
- if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode))
- return -ENOENT;
- return cp_stat(inode,statbuf);
- }
- ------------------------------------------------------------------------
- fs/super.c
- /*
- * super.c contains code to handle the super-block tables.
- */
- #include <linux/config.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- /* set_bit uses setb, as gas doesn't recognize setc */
- #define set_bit(bitnr,addr) ({ \
- register int __res __asm__("ax"); \
- __asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
- __res; })
- struct super_block super_block[NR_SUPER];
- struct super_block * do_mount(int dev)
- {
- struct super_block * p;
- struct buffer_head * bh;
- int i,block;
- for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++ )
- if (!(p->s_dev))
- break;
- p->s_dev = -1; /* mark it in use */
- if (p >= &super_block[NR_SUPER])
- return NULL;
- if (!(bh = bread(dev,1)))
- return NULL;
- *p = *((struct super_block *) bh->b_data);
- brelse(bh);
- if (p->s_magic != SUPER_MAGIC) {
- p->s_dev = 0;
- return NULL;
- }
- for (i=0;i<I_MAP_SLOTS;i++)
- p->s_imap[i] = NULL;
- for (i=0;i<Z_MAP_SLOTS;i++)
- p->s_zmap[i] = NULL;
- block=2;
- for (i=0 ; i < p->s_imap_blocks ; i++)
- if (p->s_imap[i]=bread(dev,block))
- block++;
- else
- break;
- for (i=0 ; i < p->s_zmap_blocks ; i++)
- if (p->s_zmap[i]=bread(dev,block))
- block++;
- else
- break;
- if (block != 2+p->s_imap_blocks+p->s_zmap_blocks) {
- for(i=0;i<I_MAP_SLOTS;i++)
- brelse(p->s_imap[i]);
- for(i=0;i<Z_MAP_SLOTS;i++)
- brelse(p->s_zmap[i]);
- p->s_dev=0;
- return NULL;
- }
- p->s_imap[0]->b_data[0] |= 1;
- p->s_zmap[0]->b_data[0] |= 1;
- p->s_dev = dev;
- p->s_isup = NULL;
- p->s_imount = NULL;
- p->s_time = 0;
- p->s_rd_only = 0;
- p->s_dirt = 0;
- return p;
- }
- void mount_root(void)
- {
- int i,free;
- struct super_block * p;
- struct m_inode * mi;
- if (32 != sizeof (struct d_inode))
- panic("bad i-node size");
- for(i=0;i<NR_FILE;i++)
- file_table[i].f_count=0;
- for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++)
- p->s_dev = 0;
- if (!(p=do_mount(ROOT_DEV)))
- panic("Unable to mount root");
- if (!(mi=iget(ROOT_DEV,1)))
- panic("Unable to read root i-node");
- mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
- p->s_isup = p->s_imount = mi;
- current->pwd = mi;
- current->root = mi;
- free=0;
- i=p->s_nzones;
- while (-- i >= 0)
- if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data))
- free++;
- printk("%d/%d free blocks\n\r",free,p->s_nzones);
- free=0;
- i=p->s_ninodes+1;
- while (-- i >= 0)
- if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))
- free++;
- printk("%d/%d free inodes\n\r",free,p->s_ninodes);
- }
- ------------------------------------------------------------------------
- fs/truncate.c
- #include <linux/sched.h>
- #include <sys/stat.h>
- static void free_ind(int dev,int block)
- {
- struct buffer_head * bh;
- unsigned short * p;
- int i;
- if (!block)
- return;
- if (bh=bread(dev,block)) {
- p = (unsigned short *) bh->b_data;
- for (i=0;i<512;i++,p++)
- if (*p)
- free_block(dev,*p);
- brelse(bh);
- }
- free_block(dev,block);
- }
- static void free_dind(int dev,int block)
- {
- struct buffer_head * bh;
- unsigned short * p;
- int i;
- if (!block)
- return;
- if (bh=bread(dev,block)) {
- p = (unsigned short *) bh->b_data;
- for (i=0;i<512;i++,p++)
- if (*p)
- free_ind(dev,*p);
- brelse(bh);
- }
- free_block(dev,block);
- }
- void truncate(struct m_inode * inode)
- {
- int i;
- if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
- return;
- for (i=0;i<7;i++)
- if (inode->i_zone[i]) {
- free_block(inode->i_dev,inode->i_zone[i]);
- inode->i_zone[i]=0;
- }
- free_ind(inode->i_dev,inode->i_zone[7]);
- free_dind(inode->i_dev,inode->i_zone[8]);
- inode->i_zone[7] = inode->i_zone[8] = 0;
- inode->i_size = 0;
- inode->i_dirt = 1;
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- }
- ------------------------------------------------------------------------
- fs/tty_ioctl.c
- #include <errno.h>
- #include <termios.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <linux/tty.h>
- #include <asm/segment.h>
- #include <asm/system.h>
- static void flush(struct tty_queue * queue)
- {
- cli();
- queue->head = queue->tail;
- sti();
- }
- static void wait_until_sent(struct tty_struct * tty)
- {
- /* do nothing - not implemented */
- }
- static void send_break(struct tty_struct * tty)
- {
- /* do nothing - not implemented */
- }
- static int get_termios(struct tty_struct * tty, struct termios * termios)
- {
- int i;
- verify_area(termios, sizeof (*termios));
- for (i=0 ; i< (sizeof (*termios)) ; i++)
- put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios );
- return 0;
- }
- static int set_termios(struct tty_struct * tty, struct termios * termios)
- {
- int i;
- for (i=0 ; i< (sizeof (*termios)) ; i++)
- ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
- return 0;
- }
- static int get_termio(struct tty_struct * tty, struct termio * termio)
- {
- int i;
- struct termio tmp_termio;
- verify_area(termio, sizeof (*termio));
- tmp_termio.c_iflag = tty->termios.c_iflag;
- tmp_termio.c_oflag = tty->termios.c_oflag;
- tmp_termio.c_cflag = tty->termios.c_cflag;
- tmp_termio.c_lflag = tty->termios.c_lflag;
- tmp_termio.c_line = tty->termios.c_line;
- for(i=0 ; i < NCC ; i++)
- tmp_termio.c_cc[i] = tty->termios.c_cc[i];
- for (i=0 ; i< (sizeof (*termio)) ; i++)
- put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
- return 0;
- }
- static int set_termio(struct tty_struct * tty, struct termio * termio)
- {
- int i;
- struct termio tmp_termio;
- for (i=0 ; i< (sizeof (*termio)) ; i++)
- ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
- *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag;
- *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag;
- *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag;
- *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag;
- tty->termios.c_line = tmp_termio.c_line;
- for(i=0 ; i < NCC ; i++)
- tty->termios.c_cc[i] = tmp_termio.c_cc[i];
- return 0;
- }
- int tty_ioctl(int dev, int cmd, int arg)
- {
- struct tty_struct * tty;
- if (MAJOR(dev) == 5) {
- dev=current->tty;
- if (dev<0)
- panic("tty_ioctl: dev<0");
- } else
- dev=MINOR(dev);
- tty = dev + tty_table;
- switch (cmd) {
- case TCGETS:
- return get_termios(tty,(struct termios *) arg);
- case TCSETSF:
- flush(&tty->read_q); /* fallthrough */
- case TCSETSW:
- wait_until_sent(tty); /* fallthrough */
- case TCSETS:
- return set_termios(tty,(struct termios *) arg);
- case TCGETA:
- return get_termio(tty,(struct termio *) arg);
- case TCSETAF:
- flush(&tty->read_q); /* fallthrough */
- case TCSETAW:
- wait_until_sent(tty); /* fallthrough */
- case TCSETA:
- return set_termio(tty,(struct termio *) arg);
- case TCSBRK:
- if (!arg) {
- wait_until_sent(tty);
- send_break(tty);
- }
- return 0;
- case TCXONC:
- return -EINVAL; /* not implemented */
- case TCFLSH:
- if (arg==0)
- flush(&tty->read_q);
- else if (arg==1)
- flush(&tty->write_q);
- else if (arg==2) {
- flush(&tty->read_q);
- flush(&tty->write_q);
- } else
- return -EINVAL;
- return 0;
- case TIOCEXCL:
- return -EINVAL; /* not implemented */
- case TIOCNXCL:
- return -EINVAL; /* not implemented */
- case TIOCSCTTY:
- return -EINVAL; /* set controlling term NI */
- case TIOCGPGRP:
- verify_area((void *) arg,4);
- put_fs_long(tty->pgrp,(unsigned long *) arg);
- return 0;
- case TIOCSPGRP:
- tty->pgrp=get_fs_long((unsigned long *) arg);
- return 0;
- case TIOCOUTQ:
- verify_area((void *) arg,4);
- put_fs_long(CHARS(tty->write_q),(unsigned long *) arg);
- return 0;
- case TIOCSTI:
- return -EINVAL; /* not implemented */
- case TIOCGWINSZ:
- return -EINVAL; /* not implemented */
- case TIOCSWINSZ:
- return -EINVAL; /* not implemented */
- case TIOCMGET:
- return -EINVAL; /* not implemented */
- case TIOCMBIS:
- return -EINVAL; /* not implemented */
- case TIOCMBIC:
- return -EINVAL; /* not implemented */
- case TIOCMSET:
- return -EINVAL; /* not implemented */
- case TIOCGSOFTCAR:
- return -EINVAL; /* not implemented */
- case TIOCSSOFTCAR:
- return -EINVAL; /* not implemented */
- default:
- return -EINVAL;
- }
- }
- ------------------------------------------------------------------------
- include/a.out.h
- #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__ */
- ------------------------------------------------------------------------
- include/asm/io.h
- #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; \
- })
- ------------------------------------------------------------------------
- include/asm/memory.h
- /*
- * 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; \
- })
- ------------------------------------------------------------------------
- include/asm/segment.h
- 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));
- }
- ------------------------------------------------------------------------
- include/asm/system.h
- #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")
- ------------------------------------------------------------------------
- include/const.h
- #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
- ------------------------------------------------------------------------
- include/ctype.h
- #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
- ------------------------------------------------------------------------
- include/errno.h
- #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
- ------------------------------------------------------------------------
- include/fcntl.h
- #ifndef _FCNTL_H
- #define _FCNTL_H
- #include <sys/types.h>
- /* open/fcntl - NOCTTY, NDELAY isn't implemented yet */
- #define O_ACCMODE 00003
- #define O_RDONLY 00
- #define O_WRONLY 01
- #define O_RDWR 02
- #define O_CREAT 00100 /* not fcntl */
- #define O_EXCL 00200 /* not fcntl */
- #define O_NOCTTY 00400 /* not fcntl */
- #define O_TRUNC 01000 /* not fcntl */
- #define O_APPEND 02000
- #define O_NONBLOCK 04000 /* not fcntl */
- #define O_NDELAY O_NONBLOCK
- /* Defines for fcntl-commands. Note that currently
- * locking isn't supported, and other things aren't really
- * tested.
- */
- #define F_DUPFD 0 /* dup */
- #define F_GETFD 1 /* get f_flags */
- #define F_SETFD 2 /* set f_flags */
- #define F_GETFL 3 /* more flags (cloexec) */
- #define F_SETFL 4
- #define F_GETLK 5 /* not implemented */
- #define F_SETLK 6
- #define F_SETLKW 7
- /* for F_[GET|SET]FL */
- #define FD_CLOEXEC 1 /* actually anything with low bit set goes */
- /* Ok, these are locking features, and aren't implemented at any
- * level. POSIX wants them.
- */
- #define F_RDLCK 0
- #define F_WRLCK 1
- #define F_UNLCK 2
- /* Once again - not implemented, but ... */
- struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
- };
- extern int creat(const char * filename,mode_t mode);
- extern int fcntl(int fildes,int cmd, ...);
- extern int open(const char * filename, int flags, ...);
- #endif
- ------------------------------------------------------------------------
- include/linux/config.h
- #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
- ------------------------------------------------------------------------
- include/linux/fs.h
- /*
- * This file has definitions for some important file table
- * structures etc.
- */
- #ifndef _FS_H
- #define _FS_H
- #include <sys/types.h>
- /* devices are as follows: (same as minix, so we can use the minix
- * file system. These are major numbers.)
- *
- * 0 - unused (nodev)
- * 1 - /dev/mem
- * 2 - /dev/fd
- * 3 - /dev/hd
- * 4 - /dev/ttyx
- * 5 - /dev/tty
- * 6 - /dev/lp
- * 7 - unnamed pipes
- */
- #define IS_BLOCKDEV(x) ((x)==2 || (x)==3)
- #define READ 0
- #define WRITE 1
- void buffer_init(void);
- #define MAJOR(a) (((unsigned)(a))>>8)
- #define MINOR(a) ((a)&0xff)
- #define NAME_LEN 14
- #define I_MAP_SLOTS 8
- #define Z_MAP_SLOTS 8
- #define SUPER_MAGIC 0x137F
- #define NR_OPEN 20
- #define NR_INODE 32
- #define NR_FILE 64
- #define NR_SUPER 8
- #define NR_HASH 307
- #define NR_BUFFERS nr_buffers
- #define BLOCK_SIZE 1024
- #ifndef NULL
- #define NULL ((void *) 0)
- #endif
- #define INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct d_inode)))
- #define DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct dir_entry)))
- typedef char buffer_block[BLOCK_SIZE];
- struct buffer_head {
- char * b_data; /* pointer to data block (1024 bytes) */
- unsigned short b_dev; /* device (0 = free) */
- unsigned short b_blocknr; /* block number */
- unsigned char b_uptodate;
- unsigned char b_dirt; /* 0-clean,1-dirty */
- unsigned char b_count; /* users using this block */
- unsigned char b_lock; /* 0 - ok, 1 -locked */
- struct task_struct * b_wait;
- struct buffer_head * b_prev;
- struct buffer_head * b_next;
- struct buffer_head * b_prev_free;
- struct buffer_head * b_next_free;
- };
- struct d_inode {
- unsigned short i_mode;
- unsigned short i_uid;
- unsigned long i_size;
- unsigned long i_time;
- unsigned char i_gid;
- unsigned char i_nlinks;
- unsigned short i_zone[9];
- };
- struct m_inode {
- unsigned short i_mode;
- unsigned short i_uid;
- unsigned long i_size;
- unsigned long i_mtime;
- unsigned char i_gid;
- unsigned char i_nlinks;
- unsigned short i_zone[9];
- /* these are in memory also */
- struct task_struct * i_wait;
- unsigned long i_atime;
- unsigned long i_ctime;
- unsigned short i_dev;
- unsigned short i_num;
- unsigned short i_count;
- unsigned char i_lock;
- unsigned char i_dirt;
- unsigned char i_pipe;
- unsigned char i_mount;
- unsigned char i_seek;
- unsigned char i_update;
- };
- #define PIPE_HEAD(inode) (((long *)((inode).i_zone))[0])
- #define PIPE_TAIL(inode) (((long *)((inode).i_zone))[1])
- #define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1))
- #define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode))
- #define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1))
- #define INC_PIPE(head) \
- __asm__("incl %0\n\tandl $4095,%0"::"m" (head))
- struct file {
- unsigned short f_mode;
- unsigned short f_flags;
- unsigned short f_count;
- struct m_inode * f_inode;
- off_t f_pos;
- };
- struct super_block {
- unsigned short s_ninodes;
- unsigned short s_nzones;
- unsigned short s_imap_blocks;
- unsigned short s_zmap_blocks;
- unsigned short s_firstdatazone;
- unsigned short s_log_zone_size;
- unsigned long s_max_size;
- unsigned short s_magic;
- /* These are only in memory */
- struct buffer_head * s_imap[8];
- struct buffer_head * s_zmap[8];
- unsigned short s_dev;
- struct m_inode * s_isup;
- struct m_inode * s_imount;
- unsigned long s_time;
- unsigned char s_rd_only;
- unsigned char s_dirt;
- };
- struct dir_entry {
- unsigned short inode;
- char name[NAME_LEN];
- };
- extern struct m_inode inode_table[NR_INODE];
- extern struct file file_table[NR_FILE];
- extern struct super_block super_block[NR_SUPER];
- extern struct buffer_head * start_buffer;
- extern int nr_buffers;
- extern void truncate(struct m_inode * inode);
- extern void sync_inodes(void);
- extern void wait_on(struct m_inode * inode);
- extern int bmap(struct m_inode * inode,int block);
- extern int create_block(struct m_inode * inode,int block);
- extern struct m_inode * namei(const char * pathname);
- extern int open_namei(const char * pathname, int flag, int mode,
- struct m_inode ** res_inode);
- extern void iput(struct m_inode * inode);
- extern struct m_inode * iget(int dev,int nr);
- extern struct m_inode * get_empty_inode(void);
- extern struct m_inode * get_pipe_inode(void);
- extern struct buffer_head * get_hash_table(int dev, int block);
- extern struct buffer_head * getblk(int dev, int block);
- extern void ll_rw_block(int rw, struct buffer_head * bh);
- extern void brelse(struct buffer_head * buf);
- extern struct buffer_head * bread(int dev,int block);
- extern int new_block(int dev);
- extern void free_block(int dev, int block);
- extern struct m_inode * new_inode(int dev);
- extern void free_inode(struct m_inode * inode);
- extern void mount_root(void);
- extern inline struct super_block * get_super(int dev)
- {
- struct super_block * s;
- for(s = 0+super_block;s < NR_SUPER+super_block; s++)
- if (s->s_dev == dev)
- return s;
- return NULL;
- }
- #endif
- ------------------------------------------------------------------------
- include/linux/hdreg.h
- /*
- * 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
- ------------------------------------------------------------------------
- include/linux/head.h
- #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
- ------------------------------------------------------------------------
- include/linux/kernel.h
- /*
- * '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);
- ------------------------------------------------------------------------
- include/linux/mm.h
- #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
- ------------------------------------------------------------------------
- include/linux/sched.h
- #ifndef _SCHED_H
- #define _SCHED_H
- #define NR_TASKS 64
- #define HZ 100
- #define FIRST_TASK task[0]
- #define LAST_TASK task[NR_TASKS-1]
- #include <linux/head.h>
- #include <linux/fs.h>
- #include <linux/mm.h>
- #if (NR_OPEN > 32)
- #error "Currently the close-on-exec-flags are in one word, max 32 files/proc"
- #endif
- #define TASK_RUNNING 0
- #define TASK_INTERRUPTIBLE 1
- #define TASK_UNINTERRUPTIBLE 2
- #define TASK_ZOMBIE 3
- #define TASK_STOPPED 4
- #ifndef NULL
- #define NULL ((void *) 0)
- #endif
- extern int copy_page_tables(unsigned long from, unsigned long to, long size);
- extern int free_page_tables(unsigned long from, long size);
- extern void sched_init(void);
- extern void schedule(void);
- extern void trap_init(void);
- extern void panic(const char * str);
- extern int tty_write(unsigned minor,char * buf,int count);
- typedef int (*fn_ptr)();
- struct i387_struct {
- long cwd;
- long swd;
- long twd;
- long fip;
- long fcs;
- long foo;
- long fos;
- long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
- };
- struct tss_struct {
- long back_link; /* 16 high bits zero */
- long esp0;
- long ss0; /* 16 high bits zero */
- long esp1;
- long ss1; /* 16 high bits zero */
- long esp2;
- long ss2; /* 16 high bits zero */
- long cr3;
- long eip;
- long eflags;
- long eax,ecx,edx,ebx;
- long esp;
- long ebp;
- long esi;
- long edi;
- long es; /* 16 high bits zero */
- long cs; /* 16 high bits zero */
- long ss; /* 16 high bits zero */
- long ds; /* 16 high bits zero */
- long fs; /* 16 high bits zero */
- long gs; /* 16 high bits zero */
- long ldt; /* 16 high bits zero */
- long trace_bitmap; /* bits: trace 0, bitmap 16-31 */
- struct i387_struct i387;
- };
- struct task_struct {
- /* these are hardcoded - don't touch */
- long state; /* -1 unrunnable, 0 runnable, >0 stopped */
- long counter;
- long priority;
- long signal;
- fn_ptr sig_restorer;
- fn_ptr sig_fn[32];
- /* various fields */
- int exit_code;
- unsigned long end_code,end_data,brk,start_stack;
- long pid,father,pgrp,session,leader;
- unsigned short uid,euid,suid;
- unsigned short gid,egid,sgid;
- long alarm;
- long utime,stime,cutime,cstime,start_time;
- unsigned short used_math;
- /* file system info */
- int tty; /* -1 if no tty, so it must be signed */
- unsigned short umask;
- struct m_inode * pwd;
- struct m_inode * root;
- unsigned long close_on_exec;
- struct file * filp[NR_OPEN];
- /* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
- struct desc_struct ldt[3];
- /* tss for this task */
- struct tss_struct tss;
- };
- /*
- * INIT_TASK is used to set up the first task table, touch at
- * your own risk!. Base=0, limit=0x9ffff (=640kB)
- */
- #define INIT_TASK \
- /* state etc */ { 0,15,15, \
- /* signals */ 0,NULL,{(fn_ptr) 0,}, \
- /* ec,brk... */ 0,0,0,0,0, \
- /* pid etc.. */ 0,-1,0,0,0, \
- /* uid etc */ 0,0,0,0,0,0, \
- /* alarm */ 0,0,0,0,0,0, \
- /* math */ 0, \
- /* fs info */ -1,0133,NULL,NULL,0, \
- /* filp */ {NULL,}, \
- { \
- {0,0}, \
- /* ldt */ {0x9f,0xc0fa00}, \
- {0x9f,0xc0f200}, \
- }, \
- /*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\
- 0,0,0,0,0,0,0,0, \
- 0,0,0x17,0x17,0x17,0x17,0x17,0x17, \
- _LDT(0),0x80000000, \
- {} \
- }, \
- }
- extern struct task_struct *task[NR_TASKS];
- extern struct task_struct *last_task_used_math;
- extern struct task_struct *current;
- extern long volatile jiffies;
- extern long startup_time;
- #define CURRENT_TIME (startup_time+jiffies/HZ)
- extern void sleep_on(struct task_struct ** p);
- extern void interruptible_sleep_on(struct task_struct ** p);
- extern void wake_up(struct task_struct ** p);
- /*
- * Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall
- * 4-TSS0, 5-LDT0, 6-TSS1 etc ...
- */
- #define FIRST_TSS_ENTRY 4
- #define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
- #define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
- #define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
- #define ltr(n) __asm__("ltr %%ax"::"a" (_TSS(n)))
- #define lldt(n) __asm__("lldt %%ax"::"a" (_LDT(n)))
- #define str(n) \
- __asm__("str %%ax\n\t" \
- "subl %2,%%eax\n\t" \
- "shrl $4,%%eax" \
- :"=a" (n) \
- :"a" (0),"i" (FIRST_TSS_ENTRY<<3))
- /*
- * switch_to(n) should switch tasks to task nr n, first
- * checking that n isn't the current task, in which case it does nothing.
- * This also clears the TS-flag if the task we switched to has used
- * tha math co-processor latest.
- */
- #define switch_to(n) {\
- struct {long a,b;} __tmp; \
- __asm__("cmpl %%ecx,_current\n\t" \
- "je 1f\n\t" \
- "xchgl %%ecx,_current\n\t" \
- "movw %%dx,%1\n\t" \
- "ljmp %0\n\t" \
- "cmpl %%ecx,%2\n\t" \
- "jne 1f\n\t" \
- "clts\n" \
- "1:" \
- ::"m" (*&__tmp.a),"m" (*&__tmp.b), \
- "m" (last_task_used_math),"d" _TSS(n),"c" ((long) task[n])); \
- }
- #define PAGE_ALIGN(n) (((n)+0xfff)&0xfffff000)
- #define _set_base(addr,base) \
- __asm__("movw %%dx,%0\n\t" \
- "rorl $16,%%edx\n\t" \
- "movb %%dl,%1\n\t" \
- "movb %%dh,%2" \
- ::"m" (*((addr)+2)), \
- "m" (*((addr)+4)), \
- "m" (*((addr)+7)), \
- "d" (base) \
- :"dx")
- #define _set_limit(addr,limit) \
- __asm__("movw %%dx,%0\n\t" \
- "rorl $16,%%edx\n\t" \
- "movb %1,%%dh\n\t" \
- "andb $0xf0,%%dh\n\t" \
- "orb %%dh,%%dl\n\t" \
- "movb %%dl,%1" \
- ::"m" (*(addr)), \
- "m" (*((addr)+6)), \
- "d" (limit) \
- :"dx")
- #define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )
- #define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 )
- #define _get_base(addr) ({\
- unsigned long __base; \
- __asm__("movb %3,%%dh\n\t" \
- "movb %2,%%dl\n\t" \
- "shll $16,%%edx\n\t" \
- "movw %1,%%dx" \
- :"=d" (__base) \
- :"m" (*((addr)+2)), \
- "m" (*((addr)+4)), \
- "m" (*((addr)+7))); \
- __base;})
- #define get_base(ldt) _get_base( ((char *)&(ldt)) )
- #define get_limit(segment) ({ \
- unsigned long __limit; \
- __asm__("lsll %1,%0\n\tincl %0":"=r" (__limit):"r" (segment)); \
- __limit;})
- #endif
- ------------------------------------------------------------------------
- include/linux/sys.h
- 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};
- ------------------------------------------------------------------------
- include/linux/tty.h
- /*
- * 'tty.h' defines some structures used by tty_io.c and some defines.
- *
- * NOTE! Don't touch this without checking that nothing in rs_io.s or
- * con_io.s breaks. Some constants are hardwired into the system (mainly
- * offsets into 'tty_queue'
- */
- #ifndef _TTY_H
- #define _TTY_H
- #include <termios.h>
- #define TTY_BUF_SIZE 1024
- struct tty_queue {
- unsigned long data;
- unsigned long head;
- unsigned long tail;
- struct task_struct * proc_list;
- char buf[TTY_BUF_SIZE];
- };
- #define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1))
- #define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1))
- #define EMPTY(a) ((a).head == (a).tail)
- #define LEFT(a) (((a).tail-(a).head-1)&(TTY_BUF_SIZE-1))
- #define LAST(a) ((a).buf[(TTY_BUF_SIZE-1)&((a).head-1)])
- #define FULL(a) (!LEFT(a))
- #define CHARS(a) (((a).head-(a).tail)&(TTY_BUF_SIZE-1))
- #define GETCH(queue,c) \
- (void)({c=(queue).buf[(queue).tail];INC((queue).tail);})
- #define PUTCH(c,queue) \
- (void)({(queue).buf[(queue).head]=(c);INC((queue).head);})
- #define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF])
- #define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR])
- #define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP])
- #define START_CHAR(tty) ((tty)->termios.c_cc[VSTART])
- #define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE])
- struct tty_struct {
- struct termios termios;
- int pgrp;
- int stopped;
- void (*write)(struct tty_struct * tty);
- struct tty_queue read_q;
- struct tty_queue write_q;
- struct tty_queue secondary;
- };
- extern struct tty_struct tty_table[];
- /* intr=^C quit=^| erase=del kill=^U
- eof=^D vtime=\0 vmin=\1 sxtc=\0
- start=^Q stop=^S susp=^Y eol=\0
- reprint=^R discard=^U werase=^W lnext=^V
- eol2=\0
- */
- #define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\031\0\022\017\027\026\0"
- void rs_init(void);
- void con_init(void);
- void tty_init(void);
- int tty_read(unsigned c, char * buf, int n);
- int tty_write(unsigned c, char * buf, int n);
- void rs_write(struct tty_struct * tty);
- void con_write(struct tty_struct * tty);
- void copy_to_cooked(struct tty_struct * tty);
- #endif
- ------------------------------------------------------------------------
- include/signal.h
- #ifndef _SIGNAL_H
- #define _SIGNAL_H
- #include <sys/types.h>
- typedef int sig_atomic_t;
- typedef unsigned int sigset_t; /* 32 bits */
- #define _NSIG 32
- #define NSIG _NSIG
- #define SIGHUP 1
- #define SIGINT 2
- #define SIGQUIT 3
- #define SIGILL 4
- #define SIGTRAP 5
- #define SIGABRT 6
- #define SIGIOT 6
- #define SIGUNUSED 7
- #define SIGFPE 8
- #define SIGKILL 9
- #define SIGUSR1 10
- #define SIGSEGV 11
- #define SIGUSR2 12
- #define SIGPIPE 13
- #define SIGALRM 14
- #define SIGTERM 15
- #define SIGSTKFLT 16
- #define SIGCHLD 17
- #define SIGCONT 18
- #define SIGSTOP 19
- #define SIGTSTP 20
- #define SIGTTIN 21
- #define SIGTTOU 22
- /* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */
- #define SA_NOCLDSTOP 1
- #define SIG_BLOCK 0 /* for blocking signals */
- #define SIG_UNBLOCK 1 /* for unblocking signals */
- #define SIG_SETMASK 2 /* for setting the signal mask */
- #define SIG_DFL ((void (*)(int))0) /* default signal handling */
- #define SIG_IGN ((void (*)(int))1) /* ignore signal */
- struct sigaction {
- void (*sa_handler)(int);
- sigset_t sa_mask;
- int sa_flags;
- };
- void (*signal(int _sig, void (*_func)(int)))(int);
- int raise(int sig);
- int kill(pid_t pid, int sig);
- int sigaddset(sigset_t *mask, int signo);
- int sigdelset(sigset_t *mask, int signo);
- int sigemptyset(sigset_t *mask);
- int sigfillset(sigset_t *mask);
- int sigismember(sigset_t *mask, int signo); /* 1 - is, 0 - not, -1 error */
- int sigpending(sigset_t *set);
- int sigprocmask(int how, sigset_t *set, sigset_t *oldset);
- int sigsuspend(sigset_t *sigmask);
- int sigaction(int sig, struct sigaction *act, struct sigaction *oldact);
- #endif /* _SIGNAL_H */
- ------------------------------------------------------------------------
- include/stdarg.h
- #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 */
- ------------------------------------------------------------------------
- include/stddef.h
- #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
- ------------------------------------------------------------------------
- include/string.h
- #ifndef _STRING_H_
- #define _STRING_H_
- #ifndef NULL
- #define NULL ((void *) 0)
- #endif
- #ifndef _SIZE_T
- #define _SIZE_T
- typedef unsigned int size_t;
- #endif
- extern char * strerror(int errno);
- /*
- * This string-include defines all string functions as inline
- * functions. Use gcc. It also assumes ds=es=data space, this should be
- * normal. Most of the string-functions are rather heavily hand-optimized,
- * see especially strtok,strstr,str[c]spn. They should work, but are not
- * very easy to understand. Everything is done entirely within the register
- * set, making the functions fast and clean. String instructions have been
- * used through-out, making for "slightly" unclear code :-)
- *
- * (C) 1991 Linus Torvalds
- */
- extern inline char * strcpy(char * dest,const char *src)
- {
- __asm__("cld\n"
- "1:\tlodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b"
- ::"S" (src),"D" (dest):"si","di","ax");
- return dest;
- }
- extern inline char * strncpy(char * dest,const char *src,int count)
- {
- __asm__("cld\n"
- "1:\tdecl %2\n\t"
- "js 2f\n\t"
- "lodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n\t"
- "rep\n\t"
- "stosb\n"
- "2:"
- ::"S" (src),"D" (dest),"c" (count):"si","di","ax","cx");
- return dest;
- }
- extern inline char * strcat(char * dest,const char * src)
- {
- __asm__("cld\n\t"
- "repne\n\t"
- "scasb\n\t"
- "decl %1\n"
- "1:\tlodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b"
- ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
- return dest;
- }
- extern inline char * strncat(char * dest,const char * src,int count)
- {
- __asm__("cld\n\t"
- "repne\n\t"
- "scasb\n\t"
- "decl %1\n\t"
- "movl %4,%3\n"
- "1:\tdecl %3\n\t"
- "js 2f\n\t"
- "lodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n"
- "2:\txorl %2,%2\n\t"
- "stosb"
- ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
- :"si","di","ax","cx");
- return dest;
- }
- extern inline int strcmp(const char * cs,const char * ct)
- {
- register int __res __asm__("ax");
- __asm__("cld\n"
- "1:\tlodsb\n\t"
- "scasb\n\t"
- "jne 2f\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n\t"
- "xorl %%eax,%%eax\n\t"
- "jmp 3f\n"
- "2:\tmovl $1,%%eax\n\t"
- "jl 3f\n\t"
- "negl %%eax\n"
- "3:"
- :"=a" (__res):"D" (cs),"S" (ct):"si","di");
- return __res;
- }
- extern inline int strncmp(const char * cs,const char * ct,int count)
- {
- register int __res __asm__("ax");
- __asm__("cld\n"
- "1:\tdecl %3\n\t"
- "js 2f\n\t"
- "lodsb\n\t"
- "scasb\n\t"
- "jne 3f\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n"
- "2:\txorl %%eax,%%eax\n\t"
- "jmp 4f\n"
- "3:\tmovl $1,%%eax\n\t"
- "jl 4f\n\t"
- "negl %%eax\n"
- "4:"
- :"=a" (__res):"D" (cs),"S" (ct),"c" (count):"si","di","cx");
- return __res;
- }
- extern inline char * strchr(const char * s,char c)
- {
- register char * __res __asm__("ax");
- __asm__("cld\n\t"
- "movb %%al,%%ah\n"
- "1:\tlodsb\n\t"
- "cmpb %%ah,%%al\n\t"
- "je 2f\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n\t"
- "movl $1,%1\n"
- "2:\tmovl %1,%0\n\t"
- "decl %0"
- :"=a" (__res):"S" (s),"0" (c):"si");
- return __res;
- }
- extern inline char * strrchr(const char * s,char c)
- {
- register char * __res __asm__("dx");
- __asm__("cld\n\t"
- "movb %%al,%%ah\n"
- "1:\tlodsb\n\t"
- "cmpb %%ah,%%al\n\t"
- "jne 2f\n\t"
- "movl %%esi,%0\n\t"
- "decl %0\n"
- "2:\ttestb %%al,%%al\n\t"
- "jne 1b"
- :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
- return __res;
- }
- extern inline int strspn(const char * cs, const char * ct)
- {
- register char * __res __asm__("si");
- __asm__("cld\n\t"
- "movl %4,%%edi\n\t"
- "repne\n\t"
- "scasb\n\t"
- "notl %%ecx\n\t"
- "decl %%ecx\n\t"
- "movl %%ecx,%%edx\n"
- "1:\tlodsb\n\t"
- "testb %%al,%%al\n\t"
- "je 2f\n\t"
- "movl %4,%%edi\n\t"
- "movl %%edx,%%ecx\n\t"
- "repne\n\t"
- "scasb\n\t"
- "je 1b\n"
- "2:\tdecl %0"
- :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
- :"ax","cx","dx","di");
- return __res-cs;
- }
- extern inline int strcspn(const char * cs, const char * ct)
- {
- register char * __res __asm__("si");
- __asm__("cld\n\t"
- "movl %4,%%edi\n\t"
- "repne\n\t"
- "scasb\n\t"
- "notl %%ecx\n\t"
- "decl %%ecx\n\t"
- "movl %%ecx,%%edx\n"
- "1:\tlodsb\n\t"
- "testb %%al,%%al\n\t"
- "je 2f\n\t"
- "movl %4,%%edi\n\t"
- "movl %%edx,%%ecx\n\t"
- "repne\n\t"
- "scasb\n\t"
- "jne 1b\n"
- "2:\tdecl %0"
- :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
- :"ax","cx","dx","di");
- return __res-cs;
- }
- extern inline char * strpbrk(const char * cs,const char * ct)
- {
- register char * __res __asm__("si");
- __asm__("cld\n\t"
- "movl %4,%%edi\n\t"
- "repne\n\t"
- "scasb\n\t"
- "notl %%ecx\n\t"
- "decl %%ecx\n\t"
- "movl %%ecx,%%edx\n"
- "1:\tlodsb\n\t"
- "testb %%al,%%al\n\t"
- "je 2f\n\t"
- "movl %4,%%edi\n\t"
- "movl %%edx,%%ecx\n\t"
- "repne\n\t"
- "scasb\n\t"
- "jne 1b\n\t"
- "decl %0\n\t"
- "jmp 3f\n"
- "2:\txorl %0,%0\n"
- "3:"
- :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
- :"ax","cx","dx","di");
- return __res;
- }
- extern inline char * strstr(const char * cs,const char * ct)
- {
- register char * __res __asm__("ax");
- __asm__("cld\n\t" \
- "movl %4,%%edi\n\t"
- "repne\n\t"
- "scasb\n\t"
- "notl %%ecx\n\t"
- "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */
- "movl %%ecx,%%edx\n"
- "1:\tmovl %4,%%edi\n\t"
- "movl %%esi,%%eax\n\t"
- "movl %%edx,%%ecx\n\t"
- "repe\n\t"
- "cmpsb\n\t"
- "je 2f\n\t" /* also works for empty string, see above */
- "xchgl %%eax,%%esi\n\t"
- "incl %%esi\n\t"
- "cmpb $0,-1(%%eax)\n\t"
- "jne 1b\n\t"
- "xorl %%eax,%%eax\n\t"
- "2:"
- :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
- :"cx","dx","di","si");
- return __res;
- }
- extern inline int strlen(const char * s)
- {
- register int __res __asm__("cx");
- __asm__("cld\n\t"
- "repne\n\t"
- "scasb\n\t"
- "notl %0\n\t"
- "decl %0"
- :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di");
- return __res;
- }
- extern char * ___strtok;
- extern inline char * strtok(char * s,const char * ct)
- {
- register char * __res __asm__("si");
- __asm__("testl %1,%1\n\t"
- "jne 1f\n\t"
- "testl %0,%0\n\t"
- "je 8f\n\t"
- "movl %0,%1\n"
- "1:\txorl %0,%0\n\t"
- "movl $-1,%%ecx\n\t"
- "xorl %%eax,%%eax\n\t"
- "cld\n\t"
- "movl %4,%%edi\n\t"
- "repne\n\t"
- "scasb\n\t"
- "notl %%ecx\n\t"
- "decl %%ecx\n\t"
- "je 7f\n\t" /* empty delimeter-string */
- "movl %%ecx,%%edx\n"
- "2:\tlodsb\n\t"
- "testb %%al,%%al\n\t"
- "je 7f\n\t"
- "movl %4,%%edi\n\t"
- "movl %%edx,%%ecx\n\t"
- "repne\n\t"
- "scasb\n\t"
- "je 2b\n\t"
- "decl %1\n\t"
- "cmpb $0,(%1)\n\t"
- "je 7f\n\t"
- "movl %1,%0\n"
- "3:\tlodsb\n\t"
- "testb %%al,%%al\n\t"
- "je 5f\n\t"
- "movl %4,%%edi\n\t"
- "movl %%edx,%%ecx\n\t"
- "repne\n\t"
- "scasb\n\t"
- "jne 3b\n\t"
- "decl %1\n\t"
- "cmpb $0,(%1)\n\t"
- "je 5f\n\t"
- "movb $0,(%1)\n\t"
- "incl %1\n\t"
- "jmp 6f\n"
- "5:\txorl %1,%1\n"
- "6:\tcmpb $0,(%0)\n\t"
- "jne 7f\n\t"
- "xorl %0,%0\n"
- "7:\ttestl %0,%0\n\t"
- "jne 8f\n\t"
- "movl %0,%1\n"
- "8:"
- :"=b" (__res),"=S" (___strtok)
- :"0" (___strtok),"1" (s),"g" (ct)
- :"ax","cx","dx","di");
- return __res;
- }
- extern inline void * memcpy(void * dest,const void * src, int n)
- {
- __asm__("cld\n\t"
- "rep\n\t"
- "movsb"
- ::"c" (n),"S" (src),"D" (dest)
- :"cx","si","di");
- return dest;
- }
- extern inline void * memmove(void * dest,const void * src, int n)
- {
- if (dest<src)
- __asm__("cld\n\t"
- "rep\n\t"
- "movsb"
- ::"c" (n),"S" (src),"D" (dest)
- :"cx","si","di");
- else
- __asm__("std\n\t"
- "rep\n\t"
- "movsb"
- ::"c" (n),"S" (src+n-1),"D" (dest+n-1)
- :"cx","si","di");
- return dest;
- }
- extern inline int memcmp(const void * cs,const void * ct,int count)
- {
- register int __res __asm__("ax");
- __asm__("cld\n\t"
- "repe\n\t"
- "cmpsb\n\t"
- "je 1f\n\t"
- "movl $1,%%eax\n\t"
- "jl 1f\n\t"
- "negl %%eax\n"
- "1:"
- :"=a" (__res):"0" (0),"D" (cs),"S" (ct),"c" (count)
- :"si","di","cx");
- return __res;
- }
- extern inline void * memchr(const void * cs,char c,int count)
- {
- register void * __res __asm__("di");
- if (!count)
- return NULL;
- __asm__("cld\n\t"
- "repne\n\t"
- "scasb\n\t"
- "je 1f\n\t"
- "movl $1,%0\n"
- "1:\tdecl %0"
- :"=D" (__res):"a" (c),"D" (cs),"c" (count)
- :"cx");
- return __res;
- }
- extern inline void * memset(void * s,char c,int count)
- {
- __asm__("cld\n\t"
- "rep\n\t"
- "stosb"
- ::"a" (c),"D" (s),"c" (count)
- :"cx","di");
- return s;
- }
- #endif
- ------------------------------------------------------------------------
- include/sys/stat.h
- #ifndef _SYS_STAT_H
- #define _SYS_STAT_H
- #include <sys/types.h>
- struct stat {
- dev_t st_dev;
- ino_t st_ino;
- umode_t st_mode;
- nlink_t st_nlink;
- uid_t st_uid;
- gid_t st_gid;
- dev_t st_rdev;
- off_t st_size;
- time_t st_atime;
- time_t st_mtime;
- time_t st_ctime;
- };
- #define S_IFMT 00170000
- #define S_IFREG 0100000
- #define S_IFBLK 0060000
- #define S_IFDIR 0040000
- #define S_IFCHR 0020000
- #define S_IFIFO 0010000
- #define S_ISUID 0004000
- #define S_ISGID 0002000
- #define S_ISVTX 0001000
- #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
- #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
- #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
- #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
- #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
- #define S_IRWXU 00700
- #define S_IRUSR 00400
- #define S_IWUSR 00200
- #define S_IXUSR 00100
- #define S_IRWXG 00070
- #define S_IRGRP 00040
- #define S_IWGRP 00020
- #define S_IXGRP 00010
- #define S_IRWXO 00007
- #define S_IROTH 00004
- #define S_IWOTH 00002
- #define S_IXOTH 00001
- extern int chmod(const char *_path, mode_t mode);
- extern int fstat(int fildes, struct stat *stat_buf);
- extern int mkdir(const char *_path, mode_t mode);
- extern int mkfifo(const char *_path, mode_t mode);
- extern int stat(const char *filename, struct stat *stat_buf);
- extern mode_t umask(mode_t mask);
- #endif
- ------------------------------------------------------------------------
- include/sys/times.h
- #ifndef _TIMES_H
- #define _TIMES_H
- #include <sys/types.h>
- struct tms {
- time_t tms_utime;
- time_t tms_stime;
- time_t tms_cutime;
- time_t tms_cstime;
- };
- extern time_t times(struct tms * tp);
- #endif
- ------------------------------------------------------------------------
- include/sys/types.h
- #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
- ------------------------------------------------------------------------
- include/sys/utsname.h
- #ifndef _SYS_UTSNAME_H
- #define _SYS_UTSNAME_H
- #include <sys/types.h>
- struct utsname {
- char sysname[9];
- char nodename[9];
- char release[9];
- char version[9];
- char machine[9];
- };
- extern int uname(struct utsname * utsbuf);
- #endif
- ------------------------------------------------------------------------
- include/sys/wait.h
- #ifndef _SYS_WAIT_H
- #define _SYS_WAIT_H
- #include <sys/types.h>
- #define _LOW(v) ( (v) & 0377)
- #define _HIGH(v) ( ((v) >> 8) & 0377)
- /* options for waitpid, WUNTRACED not supported */
- #define WNOHANG 1
- #define WUNTRACED 2
- #define WIFEXITED(s) (!((s)&0xFF)
- #define WIFSTOPPED(s) (((s)&0xFF)==0x7F)
- #define WEXITSTATUS(s) (((s)>>8)&0xFF)
- #define WTERMSIG(s) ((s)&0x7F)
- #define WSTOPSIG(s) (((s)>>8)&0xFF)
- #define WIFSIGNALED(s) (((unsigned int)(s)-1 & 0xFFFF) < 0xFF)
- pid_t wait(int *stat_loc);
- pid_t waitpid(pid_t pid, int *stat_loc, int options);
- #endif
- ------------------------------------------------------------------------
- include/termios.h
- #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
- ------------------------------------------------------------------------
- include/time.h
- #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
- ------------------------------------------------------------------------
- include/unistd.h
- #ifndef _UNISTD_H
- #define _UNISTD_H
- /* ok, this may be a joke, but I'm working on it */
- #define _POSIX_VERSION 198808L
- #define _POSIX_CHOWN_RESTRICTED /* only root can do a chown (I think..) */
- /* #define _POSIX_NO_TRUNC*/ /* pathname truncation (but see in kernel) */
- #define _POSIX_VDISABLE '\0' /* character to disable things like ^C */
- /*#define _POSIX_SAVED_IDS */ /* we'll get to this yet */
- /*#define _POSIX_JOB_CONTROL */ /* we aren't there quite yet. Soon hopefully */
- #define STDIN_FILENO 0
- #define STDOUT_FILENO 1
- #define STDERR_FILENO 2
- #ifndef NULL
- #define NULL ((void *)0)
- #endif
- /* access */
- #define F_OK 0
- #define X_OK 1
- #define W_OK 2
- #define R_OK 4
- /* lseek */
- #define SEEK_SET 0
- #define SEEK_CUR 1
- #define SEEK_END 2
- /* _SC stands for System Configuration. We don't use them much */
- #define _SC_ARG_MAX 1
- #define _SC_CHILD_MAX 2
- #define _SC_CLOCKS_PER_SEC 3
- #define _SC_NGROUPS_MAX 4
- #define _SC_OPEN_MAX 5
- #define _SC_JOB_CONTROL 6
- #define _SC_SAVED_IDS 7
- #define _SC_VERSION 8
- /* more (possibly) configurable things - now pathnames */
- #define _PC_LINK_MAX 1
- #define _PC_MAX_CANON 2
- #define _PC_MAX_INPUT 3
- #define _PC_NAME_MAX 4
- #define _PC_PATH_MAX 5
- #define _PC_PIPE_BUF 6
- #define _PC_NO_TRUNC 7
- #define _PC_VDISABLE 8
- #define _PC_CHOWN_RESTRICTED 9
- #include <sys/stat.h>
- #include <sys/times.h>
- #include <sys/utsname.h>
- #include <utime.h>
- #ifdef __LIBRARY__
- #define __NR_setup 0 /* used only by init, to get system going */
- #define __NR_exit 1
- #define __NR_fork 2
- #define __NR_read 3
- #define __NR_write 4
- #define __NR_open 5
- #define __NR_close 6
- #define __NR_waitpid 7
- #define __NR_creat 8
- #define __NR_link 9
- #define __NR_unlink 10
- #define __NR_execve 11
- #define __NR_chdir 12
- #define __NR_time 13
- #define __NR_mknod 14
- #define __NR_chmod 15
- #define __NR_chown 16
- #define __NR_break 17
- #define __NR_stat 18
- #define __NR_lseek 19
- #define __NR_getpid 20
- #define __NR_mount 21
- #define __NR_umount 22
- #define __NR_setuid 23
- #define __NR_getuid 24
- #define __NR_stime 25
- #define __NR_ptrace 26
- #define __NR_alarm 27
- #define __NR_fstat 28
- #define __NR_pause 29
- #define __NR_utime 30
- #define __NR_stty 31
- #define __NR_gtty 32
- #define __NR_access 33
- #define __NR_nice 34
- #define __NR_ftime 35
- #define __NR_sync 36
- #define __NR_kill 37
- #define __NR_rename 38
- #define __NR_mkdir 39
- #define __NR_rmdir 40
- #define __NR_dup 41
- #define __NR_pipe 42
- #define __NR_times 43
- #define __NR_prof 44
- #define __NR_brk 45
- #define __NR_setgid 46
- #define __NR_getgid 47
- #define __NR_signal 48
- #define __NR_geteuid 49
- #define __NR_getegid 50
- #define __NR_acct 51
- #define __NR_phys 52
- #define __NR_lock 53
- #define __NR_ioctl 54
- #define __NR_fcntl 55
- #define __NR_mpx 56
- #define __NR_setpgid 57
- #define __NR_ulimit 58
- #define __NR_uname 59
- #define __NR_umask 60
- #define __NR_chroot 61
- #define __NR_ustat 62
- #define __NR_dup2 63
- #define __NR_getppid 64
- #define __NR_getpgrp 65
- #define __NR_setsid 66
- #define _syscall0(type,name) \
- type name(void) \
- { \
- type __res; \
- __asm__ volatile ("int $0x80" \
- : "=a" (__res) \
- : "0" (__NR_##name)); \
- if (__res >= 0) \
- return __res; \
- errno = -__res; \
- return -1; \
- }
- #define _syscall1(type,name,atype,a) \
- type name(atype a) \
- { \
- type __res; \
- __asm__ volatile ("int $0x80" \
- : "=a" (__res) \
- : "0" (__NR_##name),"b" (a)); \
- if (__res >= 0) \
- return __res; \
- errno = -__res; \
- return -1; \
- }
- #define _syscall2(type,name,atype,a,btype,b) \
- type name(atype a,btype b) \
- { \
- type __res; \
- __asm__ volatile ("int $0x80" \
- : "=a" (__res) \
- : "0" (__NR_##name),"b" (a),"c" (b)); \
- if (__res >= 0) \
- return __res; \
- errno = -__res; \
- return -1; \
- }
- #define _syscall3(type,name,atype,a,btype,b,ctype,c) \
- type name(atype a,btype b,ctype c) \
- { \
- type __res; \
- __asm__ volatile ("int $0x80" \
- : "=a" (__res) \
- : "0" (__NR_##name),"b" (a),"c" (b),"d" (c)); \
- if (__res<0) \
- errno=-__res , __res = -1; \
- return __res;\
- }
- #endif /* __LIBRARY__ */
- extern int errno;
- int access(const char * filename, mode_t mode);
- int acct(const char * filename);
- int alarm(int sec);
- int brk(void * end_data_segment);
- void * sbrk(ptrdiff_t increment);
- int chdir(const char * filename);
- int chmod(const char * filename, mode_t mode);
- int chown(const char * filename, uid_t owner, gid_t group);
- int chroot(const char * filename);
- int close(int fildes);
- int creat(const char * filename, mode_t mode);
- int dup(int fildes);
- int execve(const char * filename, char ** argv, char ** envp);
- int execv(const char * pathname, char ** argv);
- int execvp(const char * file, char ** argv);
- int execl(const char * pathname, char * arg0, ...);
- int execlp(const char * file, char * arg0, ...);
- int execle(const char * pathname, char * arg0, ...);
- volatile void exit(int status);
- volatile void _exit(int status);
- int fcntl(int fildes, int cmd, ...);
- int fork(void);
- int getpid(void);
- int getuid(void);
- int geteuid(void);
- int getgid(void);
- int getegid(void);
- int ioctl(int fildes, int cmd, ...);
- int kill(pid_t pid, int signal);
- int link(const char * filename1, const char * filename2);
- int lseek(int fildes, off_t offset, int origin);
- int mknod(const char * filename, mode_t mode, dev_t dev);
- int mount(const char * specialfile, const char * dir, int rwflag);
- int nice(int val);
- int open(const char * filename, int flag, ...);
- int pause(void);
- int pipe(int * fildes);
- int read(int fildes, char * buf, off_t count);
- int setpgrp(void);
- int setpgid(pid_t pid,pid_t pgid);
- int setuid(uid_t uid);
- int setgid(gid_t gid);
- void (*signal(int sig, void (*fn)(int)))(int);
- int stat(const char * filename, struct stat * stat_buf);
- int fstat(int fildes, struct stat * stat_buf);
- int stime(time_t * tptr);
- int sync(void);
- time_t time(time_t * tloc);
- time_t times(struct tms * tbuf);
- int ulimit(int cmd, long limit);
- mode_t umask(mode_t mask);
- int umount(const char * specialfile);
- int uname(struct utsname * name);
- int unlink(const char * filename);
- int ustat(dev_t dev, struct ustat * ubuf);
- int utime(const char * filename, struct utimbuf * times);
- pid_t waitpid(pid_t pid,int * wait_stat,int options);
- pid_t wait(int * wait_stat);
- int write(int fildes, const char * buf, off_t count);
- int dup2(int oldfd, int newfd);
- int getppid(void);
- pid_t getpgrp(void);
- pid_t setsid(void);
- #endif
- ------------------------------------------------------------------------
- include/utime.h
- #ifndef _UTIME_H
- #define _UTIME_H
- #include <sys/types.h> /* I know - shouldn't do this, but .. */
- struct utimbuf {
- time_t actime;
- time_t modtime;
- };
- extern int utime(const char *filename, struct utimbuf *times);
- #endif
- ------------------------------------------------------------------------
- init/main.c
- #define __LIBRARY__
- #include <unistd.h>
- #include <time.h>
- /*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
- static inline _syscall0(int,fork)
- static inline _syscall0(int,pause)
- static inline _syscall0(int,setup)
- static inline _syscall0(int,sync)
- #include <linux/tty.h>
- #include <linux/sched.h>
- #include <linux/head.h>
- #include <asm/system.h>
- #include <asm/io.h>
- #include <stddef.h>
- #include <stdarg.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <linux/fs.h>
- static char printbuf[1024];
- extern int vsprintf();
- extern void init(void);
- extern void hd_init(void);
- extern long kernel_mktime(struct tm * tm);
- extern long startup_time;
- /*
- * Yeah, yeah, it's ugly, but I cannot find how to do this correctly
- * and this seems to work. I anybody has more info on the real-time
- * clock I'd be interested. Most of this was trial and error, and some
- * bios-listing reading. Urghh.
- */
- #define CMOS_READ(addr) ({ \
- outb_p(0x80|addr,0x70); \
- inb_p(0x71); \
- })
- #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
- static void time_init(void)
- {
- struct tm time;
- do {
- time.tm_sec = CMOS_READ(0);
- time.tm_min = CMOS_READ(2);
- time.tm_hour = CMOS_READ(4);
- time.tm_mday = CMOS_READ(7);
- time.tm_mon = CMOS_READ(8)-1;
- time.tm_year = CMOS_READ(9);
- } while (time.tm_sec != CMOS_READ(0));
- BCD_TO_BIN(time.tm_sec);
- BCD_TO_BIN(time.tm_min);
- BCD_TO_BIN(time.tm_hour);
- BCD_TO_BIN(time.tm_mday);
- BCD_TO_BIN(time.tm_mon);
- BCD_TO_BIN(time.tm_year);
- startup_time = kernel_mktime(&time);
- }
- void main(void) /* This really IS void, no error here. */
- { /* The startup routine assumes (well, ...) this */
- /*
- * Interrupts are still disabled. Do necessary setups, then
- * enable them
- */
- time_init();
- tty_init();
- trap_init();
- sched_init();
- buffer_init();
- hd_init();
- sti();
- move_to_user_mode();
- if (!fork()) { /* we count on this going ok */
- init();
- }
- /*
- * NOTE!! For any other task 'pause()' would mean we have to get a
- * signal to awaken, but task0 is the sole exception (see 'schedule()')
- * as task 0 gets activated at every idle moment (when no other tasks
- * can run). For task0 'pause()' just means we go check if some other
- * task can run, and if not we return here.
- */
- for(;;) pause();
- }
- static int printf(const char *fmt, ...)
- {
- va_list args;
- int i;
- va_start(args, fmt);
- write(1,printbuf,i=vsprintf(printbuf, fmt, args));
- va_end(args);
- return i;
- }
- static char * argv[] = { "-",NULL };
- static char * envp[] = { "HOME=/usr/root", NULL };
- void init(void)
- {
- int i,j;
- setup();
- if (!fork())
- _exit(execve("/bin/update",NULL,NULL));
- (void) open("/dev/tty0",O_RDWR,0);
- (void) dup(0);
- (void) dup(0);
- printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,
- NR_BUFFERS*BLOCK_SIZE);
- printf(" Ok.\n\r");
- if ((i=fork())<0)
- printf("Fork failed in init\r\n");
- else if (!i) {
- close(0);close(1);close(2);
- setsid();
- (void) open("/dev/tty0",O_RDWR,0);
- (void) dup(0);
- (void) dup(0);
- _exit(execve("/bin/sh",argv,envp));
- }
- j=wait(&i);
- printf("child %d died with code %04x\n",j,i);
- sync();
- _exit(0); /* NOTE! _exit, not exit() */
- }
- ------------------------------------------------------------------------
- kernel/asm.s
- /*
- * 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
- ------------------------------------------------------------------------
- kernel/console.c
- /*
- * console.c
- *
- * This module implements the console io functions
- * 'void con_init(void)'
- * 'void con_write(struct tty_queue * queue)'
- * Hopefully this will be a rather complete VT102 implementation.
- *
- */
- /*
- * NOTE!!! We sometimes disable and enable interrupts for a short while
- * (to put a word in video IO), but this will work even for keyboard
- * interrupts. We know interrupts aren't enabled when getting a keyboard
- * interrupt, as we use trap-gates. Hopefully all is well.
- */
- #include <linux/sched.h>
- #include <linux/tty.h>
- #include <asm/io.h>
- #include <asm/system.h>
- #define SCREEN_START 0xb8000
- #define SCREEN_END 0xc0000
- #define LINES 25
- #define COLUMNS 80
- #define NPAR 16
- extern void keyboard_interrupt(void);
- static unsigned long origin=SCREEN_START;
- static unsigned long scr_end=SCREEN_START+LINES*COLUMNS*2;
- static unsigned long pos;
- static unsigned long x,y;
- static unsigned long top=0,bottom=LINES;
- static unsigned long lines=LINES,columns=COLUMNS;
- static unsigned long state=0;
- static unsigned long npar,par[NPAR];
- static unsigned long ques=0;
- static unsigned char attr=0x07;
- /*
- * this is what the terminal answers to a ESC-Z or csi0c
- * query (= vt100 response).
- */
- #define RESPONSE "\033[?1;2c"
- static inline void gotoxy(unsigned int new_x,unsigned int new_y)
- {
- if (new_x>=columns || new_y>=lines)
- return;
- x=new_x;
- y=new_y;
- pos=origin+((y*columns+x)<<1);
- }
- static inline void set_origin(void)
- {
- cli();
- outb_p(12,0x3d4);
- outb_p(0xff&((origin-SCREEN_START)>>9),0x3d5);
- outb_p(13,0x3d4);
- outb_p(0xff&((origin-SCREEN_START)>>1),0x3d5);
- sti();
- }
- static void scrup(void)
- {
- if (!top && bottom==lines) {
- origin += columns<<1;
- pos += columns<<1;
- scr_end += columns<<1;
- if (scr_end>SCREEN_END) {
- __asm__("cld\n\t"
- "rep\n\t"
- "movsl\n\t"
- "movl _columns,%1\n\t"
- "rep\n\t"
- "stosw"
- ::"a" (0x0720),
- "c" ((lines-1)*columns>>1),
- "D" (SCREEN_START),
- "S" (origin)
- :"cx","di","si");
- scr_end -= origin-SCREEN_START;
- pos -= origin-SCREEN_START;
- origin = SCREEN_START;
- } else {
- __asm__("cld\n\t"
- "rep\n\t"
- "stosl"
- ::"a" (0x07200720),
- "c" (columns>>1),
- "D" (scr_end-(columns<<1))
- :"cx","di");
- }
- set_origin();
- } else {
- __asm__("cld\n\t"
- "rep\n\t"
- "movsl\n\t"
- "movl _columns,%%ecx\n\t"
- "rep\n\t"
- "stosw"
- ::"a" (0x0720),
- "c" ((bottom-top-1)*columns>>1),
- "D" (origin+(columns<<1)*top),
- "S" (origin+(columns<<1)*(top+1))
- :"cx","di","si");
- }
- }
- static void scrdown(void)
- {
- __asm__("std\n\t"
- "rep\n\t"
- "movsl\n\t"
- "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
- "movl _columns,%%ecx\n\t"
- "rep\n\t"
- "stosw"
- ::"a" (0x0720),
- "c" ((bottom-top-1)*columns>>1),
- "D" (origin+(columns<<1)*bottom-4),
- "S" (origin+(columns<<1)*(bottom-1)-4)
- :"ax","cx","di","si");
- }
- static void lf(void)
- {
- if (y+1<bottom) {
- y++;
- pos += columns<<1;
- return;
- }
- scrup();
- }
- static void ri(void)
- {
- if (y>top) {
- y--;
- pos -= columns<<1;
- return;
- }
- scrdown();
- }
- static void cr(void)
- {
- pos -= x<<1;
- x=0;
- }
- static void del(void)
- {
- if (x) {
- pos -= 2;
- x--;
- *(unsigned short *)pos = 0x0720;
- }
- }
- static void csi_J(int par)
- {
- long count __asm__("cx");
- long start __asm__("di");
- switch (par) {
- case 0: /* erase from cursor to end of display */
- count = (scr_end-pos)>>1;
- start = pos;
- break;
- case 1: /* erase from start to cursor */
- count = (pos-origin)>>1;
- start = origin;
- break;
- case 2: /* erase whole display */
- count = columns*lines;
- start = origin;
- break;
- default:
- return;
- }
- __asm__("cld\n\t"
- "rep\n\t"
- "stosw\n\t"
- ::"c" (count),
- "D" (start),"a" (0x0720)
- :"cx","di");
- }
- static void csi_K(int par)
- {
- long count __asm__("cx");
- long start __asm__("di");
- switch (par) {
- case 0: /* erase from cursor to end of line */
- if (x>=columns)
- return;
- count = columns-x;
- start = pos;
- break;
- case 1: /* erase from start of line to cursor */
- start = pos - (x<<1);
- count = (x<columns)?x:columns;
- break;
- case 2: /* erase whole line */
- start = pos - (x<<1);
- count = columns;
- break;
- default:
- return;
- }
- __asm__("cld\n\t"
- "rep\n\t"
- "stosw\n\t"
- ::"c" (count),
- "D" (start),"a" (0x0720)
- :"cx","di");
- }
- void csi_m(void)
- {
- int i;
- for (i=0;i<=npar;i++)
- switch (par[i]) {
- case 0:attr=0x07;break;
- case 1:attr=0x0f;break;
- case 4:attr=0x0f;break;
- case 7:attr=0x70;break;
- case 27:attr=0x07;break;
- }
- }
- static inline void set_cursor(void)
- {
- cli();
- outb_p(14,0x3d4);
- outb_p(0xff&((pos-SCREEN_START)>>9),0x3d5);
- outb_p(15,0x3d4);
- outb_p(0xff&((pos-SCREEN_START)>>1),0x3d5);
- sti();
- }
- static void respond(struct tty_struct * tty)
- {
- char * p = RESPONSE;
- cli();
- while (*p) {
- PUTCH(*p,tty->read_q);
- p++;
- }
- sti();
- copy_to_cooked(tty);
- }
- static void insert_char(void)
- {
- int i=x;
- unsigned short tmp,old=0x0720;
- unsigned short * p = (unsigned short *) pos;
- while (i++<columns) {
- tmp=*p;
- *p=old;
- old=tmp;
- p++;
- }
- }
- static void insert_line(void)
- {
- int oldtop,oldbottom;
- oldtop=top;
- oldbottom=bottom;
- top=y;
- bottom=lines;
- scrdown();
- top=oldtop;
- bottom=oldbottom;
- }
- static void delete_char(void)
- {
- int i;
- unsigned short * p = (unsigned short *) pos;
- if (x>=columns)
- return;
- i = x;
- while (++i < columns) {
- *p = *(p+1);
- p++;
- }
- *p=0x0720;
- }
- static void delete_line(void)
- {
- int oldtop,oldbottom;
- oldtop=top;
- oldbottom=bottom;
- top=y;
- bottom=lines;
- scrup();
- top=oldtop;
- bottom=oldbottom;
- }
- static void csi_at(int nr)
- {
- if (nr>columns)
- nr=columns;
- else if (!nr)
- nr=1;
- while (nr--)
- insert_char();
- }
- static void csi_L(int nr)
- {
- if (nr>lines)
- nr=lines;
- else if (!nr)
- nr=1;
- while (nr--)
- insert_line();
- }
- static void csi_P(int nr)
- {
- if (nr>columns)
- nr=columns;
- else if (!nr)
- nr=1;
- while (nr--)
- delete_char();
- }
- static void csi_M(int nr)
- {
- if (nr>lines)
- nr=lines;
- else if (!nr)
- nr=1;
- while (nr--)
- delete_line();
- }
- static int saved_x=0;
- static int saved_y=0;
- static void save_cur(void)
- {
- saved_x=x;
- saved_y=y;
- }
- static void restore_cur(void)
- {
- x=saved_x;
- y=saved_y;
- pos=origin+((y*columns+x)<<1);
- }
- void con_write(struct tty_struct * tty)
- {
- int nr;
- char c;
- nr = CHARS(tty->write_q);
- while (nr--) {
- GETCH(tty->write_q,c);
- switch(state) {
- case 0:
- if (c>31 && c<127) {
- if (x>=columns) {
- x -= columns;
- pos -= columns<<1;
- lf();
- }
- __asm__("movb _attr,%%ah\n\t"
- "movw %%ax,%1\n\t"
- ::"a" (c),"m" (*(short *)pos)
- :"ax");
- pos += 2;
- x++;
- } else if (c==27)
- state=1;
- else if (c==10 || c==11 || c==12)
- lf();
- else if (c==13)
- cr();
- else if (c==ERASE_CHAR(tty))
- del();
- else if (c==8) {
- if (x) {
- x--;
- pos -= 2;
- }
- } else if (c==9) {
- c=8-(x&7);
- x += c;
- pos += c<<1;
- if (x>columns) {
- x -= columns;
- pos -= columns<<1;
- lf();
- }
- c=9;
- }
- break;
- case 1:
- state=0;
- if (c=='[')
- state=2;
- else if (c=='E')
- gotoxy(0,y+1);
- else if (c=='M')
- ri();
- else if (c=='D')
- lf();
- else if (c=='Z')
- respond(tty);
- else if (x=='7')
- save_cur();
- else if (x=='8')
- restore_cur();
- break;
- case 2:
- for(npar=0;npar<NPAR;npar++)
- par[npar]=0;
- npar=0;
- state=3;
- if (ques=(c=='?'))
- break;
- case 3:
- if (c==';' && npar<NPAR-1) {
- npar++;
- break;
- } else if (c>='0' && c<='9') {
- par[npar]=10*par[npar]+c-'0';
- break;
- } else state=4;
- case 4:
- state=0;
- switch(c) {
- case 'G': case '`':
- if (par[0]) par[0]--;
- gotoxy(par[0],y);
- break;
- case 'A':
- if (!par[0]) par[0]++;
- gotoxy(x,y-par[0]);
- break;
- case 'B': case 'e':
- if (!par[0]) par[0]++;
- gotoxy(x,y+par[0]);
- break;
- case 'C': case 'a':
- if (!par[0]) par[0]++;
- gotoxy(x+par[0],y);
- break;
- case 'D':
- if (!par[0]) par[0]++;
- gotoxy(x-par[0],y);
- break;
- case 'E':
- if (!par[0]) par[0]++;
- gotoxy(0,y+par[0]);
- break;
- case 'F':
- if (!par[0]) par[0]++;
- gotoxy(0,y-par[0]);
- break;
- case 'd':
- if (par[0]) par[0]--;
- gotoxy(x,par[0]);
- break;
- case 'H': case 'f':
- if (par[0]) par[0]--;
- if (par[1]) par[1]--;
- gotoxy(par[1],par[0]);
- break;
- case 'J':
- csi_J(par[0]);
- break;
- case 'K':
- csi_K(par[0]);
- break;
- case 'L':
- csi_L(par[0]);
- break;
- case 'M':
- csi_M(par[0]);
- break;
- case 'P':
- csi_P(par[0]);
- break;
- case '@':
- csi_at(par[0]);
- break;
- case 'm':
- csi_m();
- break;
- case 'r':
- if (par[0]) par[0]--;
- if (!par[1]) par[1]=lines;
- if (par[0] < par[1] &&
- par[1] <= lines) {
- top=par[0];
- bottom=par[1];
- }
- break;
- case 's':
- save_cur();
- break;
- case 'u':
- restore_cur();
- break;
- }
- }
- }
- set_cursor();
- }
- /*
- * void con_init(void);
- *
- * This routine initalizes console interrupts, and does nothing
- * else. If you want the screen to clear, call tty_write with
- * the appropriate escape-sequece.
- */
- void con_init(void)
- {
- register unsigned char a;
- gotoxy(*(unsigned char *)(0x90000+510),*(unsigned char *)(0x90000+511));
- set_trap_gate(0x21,&keyboard_interrupt);
- outb_p(inb_p(0x21)&0xfd,0x21);
- a=inb_p(0x61);
- outb_p(a|0x80,0x61);
- outb(a,0x61);
- }
- ------------------------------------------------------------------------
- kernel/exit.c
- #include <errno.h>
- #include <signal.h>
- #include <sys/wait.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <linux/tty.h>
- #include <asm/segment.h>
- int sys_pause(void);
- int sys_close(int fd);
- void release(struct task_struct * p)
- {
- int i;
- if (!p)
- return;
- for (i=1 ; i<NR_TASKS ; i++)
- if (task[i]==p) {
- task[i]=NULL;
- free_page((long)p);
- schedule();
- return;
- }
- panic("trying to release non-existent task");
- }
- static inline void send_sig(long sig,struct task_struct * p,int priv)
- {
- if (!p || sig<1 || sig>32)
- return;
- if (priv ||
- current->uid==p->uid ||
- current->euid==p->uid ||
- current->uid==p->euid ||
- current->euid==p->euid)
- p->signal |= (1<<(sig-1));
- }
- void do_kill(long pid,long sig,int priv)
- {
- struct task_struct **p = NR_TASKS + task;
- if (!pid) while (--p > &FIRST_TASK) {
- if (*p && (*p)->pgrp == current->pid)
- send_sig(sig,*p,priv);
- } else if (pid>0) while (--p > &FIRST_TASK) {
- if (*p && (*p)->pid == pid)
- send_sig(sig,*p,priv);
- } else if (pid == -1) while (--p > &FIRST_TASK)
- send_sig(sig,*p,priv);
- else while (--p > &FIRST_TASK)
- if (*p && (*p)->pgrp == -pid)
- send_sig(sig,*p,priv);
- }
- int sys_kill(int pid,int sig)
- {
- do_kill(pid,sig,!(current->uid || current->euid));
- return 0;
- }
- int do_exit(long code)
- {
- int i;
- free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
- free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
- for (i=0 ; i<NR_TASKS ; i++)
- if (task[i] && task[i]->father == current->pid)
- task[i]->father = 0;
- for (i=0 ; i<NR_OPEN ; i++)
- if (current->filp[i])
- sys_close(i);
- iput(current->pwd);
- current->pwd=NULL;
- iput(current->root);
- current->root=NULL;
- if (current->leader && current->tty >= 0)
- tty_table[current->tty].pgrp = 0;
- if (last_task_used_math == current)
- last_task_used_math = NULL;
- if (current->father) {
- current->state = TASK_ZOMBIE;
- do_kill(current->father,SIGCHLD,1);
- current->exit_code = code;
- } else
- release(current);
- schedule();
- return (-1); /* just to suppress warnings */
- }
- int sys_exit(int error_code)
- {
- return do_exit((error_code&0xff)<<8);
- }
- int sys_waitpid(pid_t pid,int * stat_addr, int options)
- {
- int flag=0;
- struct task_struct ** p;
- verify_area(stat_addr,4);
- repeat:
- for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
- if (*p && *p != current &&
- (pid==-1 || (*p)->pid==pid ||
- (pid==0 && (*p)->pgrp==current->pgrp) ||
- (pid<0 && (*p)->pgrp==-pid)))
- if ((*p)->father == current->pid) {
- flag=1;
- if ((*p)->state==TASK_ZOMBIE) {
- put_fs_long((*p)->exit_code,
- (unsigned long *) stat_addr);
- current->cutime += (*p)->utime;
- current->cstime += (*p)->stime;
- flag = (*p)->pid;
- release(*p);
- return flag;
- }
- }
- if (flag) {
- if (options & WNOHANG)
- return 0;
- sys_pause();
- if (!(current->signal &= ~(1<<(SIGCHLD-1))))
- goto repeat;
- else
- return -EINTR;
- }
- return -ECHILD;
- }
- ------------------------------------------------------------------------
- kernel/fork.c
- /*
- * 'fork.c' contains the help-routines for the 'fork' system call
- * (see also system_call.s), and some misc functions ('verify_area').
- * Fork is rather simple, once you get the hang of it, but the memory
- * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
- */
- #include <errno.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <asm/segment.h>
- #include <asm/system.h>
- extern void write_verify(unsigned long address);
- long last_pid=0;
- void verify_area(void * addr,int size)
- {
- unsigned long start;
- start = (unsigned long) addr;
- size += start & 0xfff;
- start &= 0xfffff000;
- start += get_base(current->ldt[2]);
- while (size>0) {
- size -= 4096;
- write_verify(start);
- start += 4096;
- }
- }
- int copy_mem(int nr,struct task_struct * p)
- {
- unsigned long old_data_base,new_data_base,data_limit;
- unsigned long old_code_base,new_code_base,code_limit;
- code_limit=get_limit(0x0f);
- data_limit=get_limit(0x17);
- old_code_base = get_base(current->ldt[1]);
- old_data_base = get_base(current->ldt[2]);
- if (old_data_base != old_code_base)
- panic("We don't support separate I&D");
- if (data_limit < code_limit)
- panic("Bad data_limit");
- new_data_base = new_code_base = nr * 0x4000000;
- set_base(p->ldt[1],new_code_base);
- set_base(p->ldt[2],new_data_base);
- if (copy_page_tables(old_data_base,new_data_base,data_limit)) {
- free_page_tables(new_data_base,data_limit);
- return -ENOMEM;
- }
- return 0;
- }
- /*
- * Ok, this is the main fork-routine. It copies the system process
- * information (task[nr]) and sets up the necessary registers. It
- * also copies the data segment in it's entirety.
- */
- int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
- long ebx,long ecx,long edx,
- long fs,long es,long ds,
- long eip,long cs,long eflags,long esp,long ss)
- {
- struct task_struct *p;
- int i;
- struct file *f;
- p = (struct task_struct *) get_free_page();
- if (!p)
- return -EAGAIN;
- *p = *current; /* NOTE! this doesn't copy the supervisor stack */
- p->state = TASK_RUNNING;
- p->pid = last_pid;
- p->father = current->pid;
- p->counter = p->priority;
- p->signal = 0;
- p->alarm = 0;
- p->leader = 0; /* process leadership doesn't inherit */
- p->utime = p->stime = 0;
- p->cutime = p->cstime = 0;
- p->start_time = jiffies;
- p->tss.back_link = 0;
- p->tss.esp0 = PAGE_SIZE + (long) p;
- p->tss.ss0 = 0x10;
- p->tss.eip = eip;
- p->tss.eflags = eflags;
- p->tss.eax = 0;
- p->tss.ecx = ecx;
- p->tss.edx = edx;
- p->tss.ebx = ebx;
- p->tss.esp = esp;
- p->tss.ebp = ebp;
- p->tss.esi = esi;
- p->tss.edi = edi;
- p->tss.es = es & 0xffff;
- p->tss.cs = cs & 0xffff;
- p->tss.ss = ss & 0xffff;
- p->tss.ds = ds & 0xffff;
- p->tss.fs = fs & 0xffff;
- p->tss.gs = gs & 0xffff;
- p->tss.ldt = _LDT(nr);
- p->tss.trace_bitmap = 0x80000000;
- if (last_task_used_math == current)
- __asm__("fnsave %0"::"m" (p->tss.i387));
- if (copy_mem(nr,p)) {
- free_page((long) p);
- return -EAGAIN;
- }
- for (i=0; i<NR_OPEN;i++)
- if (f=p->filp[i])
- f->f_count++;
- if (current->pwd)
- current->pwd->i_count++;
- if (current->root)
- current->root->i_count++;
- set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
- set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
- task[nr] = p; /* do this last, just in case */
- return last_pid;
- }
- int find_empty_process(void)
- {
- int i;
- repeat:
- if ((++last_pid)<0) last_pid=1;
- for(i=0 ; i<NR_TASKS ; i++)
- if (task[i] && task[i]->pid == last_pid) goto repeat;
- for(i=1 ; i<NR_TASKS ; i++)
- if (!task[i])
- return i;
- return -EAGAIN;
- }
- ------------------------------------------------------------------------
- kernel/hd.c
- #include <linux/config.h>
- #include <linux/sched.h>
- #include <linux/fs.h>
- #include <linux/kernel.h>
- #include <linux/hdreg.h>
- #include <asm/system.h>
- #include <asm/io.h>
- #include <asm/segment.h>
- /*
- * This code handles all hd-interrupts, and read/write requests to
- * the hard-disk. It is relatively straigthforward (not obvious maybe,
- * but interrupts never are), while still being efficient, and never
- * disabling interrupts (except to overcome possible race-condition).
- * The elevator block-seek algorithm doesn't need to disable interrupts
- * due to clever programming.
- */
- /* Max read/write errors/sector */
- #define MAX_ERRORS 5
- #define MAX_HD 2
- #define NR_REQUEST 32
- /*
- * This struct defines the HD's and their types.
- * Currently defined for CP3044's, ie a modified
- * type 17.
- */
- static struct hd_i_struct{
- int head,sect,cyl,wpcom,lzone,ctl;
- } hd_info[]= { HD_TYPE };
- #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
- static struct hd_struct {
- long start_sect;
- long nr_sects;
- } hd[5*MAX_HD]={{0,0},};
- static struct hd_request {
- int hd; /* -1 if no request */
- int nsector;
- int sector;
- int head;
- int cyl;
- int cmd;
- int errors;
- struct buffer_head * bh;
- struct hd_request * next;
- } request[NR_REQUEST];
- #define IN_ORDER(s1,s2) \
- ((s1)->hd<(s2)->hd || (s1)->hd==(s2)->hd && \
- ((s1)->cyl<(s2)->cyl || (s1)->cyl==(s2)->cyl && \
- ((s1)->head<(s2)->head || (s1)->head==(s2)->head && \
- ((s1)->sector<(s2)->sector))))
- static struct hd_request * this_request = NULL;
- static int sorting=0;
- static void do_request(void);
- static void reset_controller(void);
- static void rw_abs_hd(int rw,unsigned int nr,unsigned int sec,unsigned int head,
- unsigned int cyl,struct buffer_head * bh);
- void hd_init(void);
- #define port_read(port,buf,nr) \
- __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
- #define port_write(port,buf,nr) \
- __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
- extern void hd_interrupt(void);
- static struct task_struct * wait_for_request=NULL;
- static inline void lock_buffer(struct buffer_head * bh)
- {
- if (bh->b_lock)
- printk("hd.c: buffer multiply locked\n");
- bh->b_lock=1;
- }
- static inline void unlock_buffer(struct buffer_head * bh)
- {
- if (!bh->b_lock)
- printk("hd.c: free buffer being unlocked\n");
- bh->b_lock=0;
- wake_up(&bh->b_wait);
- }
- static inline void wait_on_buffer(struct buffer_head * bh)
- {
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
- }
- void rw_hd(int rw, struct buffer_head * bh)
- {
- unsigned int block,dev;
- unsigned int sec,head,cyl;
- block = bh->b_blocknr << 1;
- dev = MINOR(bh->b_dev);
- if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects)
- return;
- block += hd[dev].start_sect;
- dev /= 5;
- __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
- "r" (hd_info[dev].sect));
- __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
- "r" (hd_info[dev].head));
- rw_abs_hd(rw,dev,sec+1,head,cyl,bh);
- }
- /* This may be used only once, enforced by 'static int callable' */
- int sys_setup(void)
- {
- static int callable = 1;
- int i,drive;
- struct partition *p;
- if (!callable)
- return -1;
- callable = 0;
- for (drive=0 ; drive<NR_HD ; drive++) {
- rw_abs_hd(READ,drive,1,0,0,(struct buffer_head *) start_buffer);
- if (!start_buffer->b_uptodate) {
- printk("Unable to read partition table of drive %d\n\r",
- drive);
- panic("");
- }
- if (start_buffer->b_data[510] != 0x55 || (unsigned char)
- start_buffer->b_data[511] != 0xAA) {
- printk("Bad partition table on drive %d\n\r",drive);
- panic("");
- }
- p = 0x1BE + (void *)start_buffer->b_data;
- for (i=1;i<5;i++,p++) {
- hd[i+5*drive].start_sect = p->start_sect;
- hd[i+5*drive].nr_sects = p->nr_sects;
- }
- }
- printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
- mount_root();
- return (0);
- }
- /*
- * This is the pointer to a routine to be executed at every hd-interrupt.
- * Interesting way of doing things, but should be rather practical.
- */
- void (*do_hd)(void) = NULL;
- static int controller_ready(void)
- {
- int retries=1000;
- while (--retries && (inb(HD_STATUS)&0xc0)!=0x40);
- return (retries);
- }
- static int win_result(void)
- {
- int i=inb(HD_STATUS);
- if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
- == (READY_STAT | SEEK_STAT))
- return(0); /* ok */
- if (i&1) i=inb(HD_ERROR);
- return (1);
- }
- static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
- unsigned int head,unsigned int cyl,unsigned int cmd,
- void (*intr_addr)(void))
- {
- register int port asm("dx");
- if (drive>1 || head>15)
- panic("Trying to write bad sector");
- if (!controller_ready())
- panic("HD controller not ready");
- do_hd = intr_addr;
- outb(_CTL,HD_CMD);
- port=HD_DATA;
- outb_p(_WPCOM,++port);
- outb_p(nsect,++port);
- outb_p(sect,++port);
- outb_p(cyl,++port);
- outb_p(cyl>>8,++port);
- outb_p(0xA0|(drive<<4)|head,++port);
- outb(cmd,++port);
- }
- static int drive_busy(void)
- {
- unsigned int i;
- for (i = 0; i < 100000; i++)
- if (READY_STAT == (inb(HD_STATUS) & (BUSY_STAT | READY_STAT)))
- break;
- i = inb(HD_STATUS);
- i &= BUSY_STAT | READY_STAT | SEEK_STAT;
- if (i == READY_STAT | SEEK_STAT)
- return(0);
- printk("HD controller times out\n\r");
- return(1);
- }
- static void reset_controller(void)
- {
- int i;
- outb(4,HD_CMD);
- for(i = 0; i < 1000; i++) nop();
- outb(0,HD_CMD);
- for(i = 0; i < 10000 && drive_busy(); i++) /* nothing */;
- if (drive_busy())
- printk("HD-controller still busy\n\r");
- if((i = inb(ERR_STAT)) != 1)
- printk("HD-controller reset failed: %02x\n\r",i);
- }
- static void reset_hd(int nr)
- {
- reset_controller();
- hd_out(nr,_SECT,_SECT,_HEAD-1,_CYL,WIN_SPECIFY,&do_request);
- }
- void unexpected_hd_interrupt(void)
- {
- panic("Unexpected HD interrupt\n\r");
- }
- static void bad_rw_intr(void)
- {
- int i = this_request->hd;
- if (this_request->errors++ >= MAX_ERRORS) {
- this_request->bh->b_uptodate = 0;
- unlock_buffer(this_request->bh);
- wake_up(&wait_for_request);
- this_request->hd = -1;
- this_request=this_request->next;
- }
- reset_hd(i);
- }
- static void read_intr(void)
- {
- if (win_result()) {
- bad_rw_intr();
- return;
- }
- port_read(HD_DATA,this_request->bh->b_data+
- 512*(this_request->nsector&1),256);
- this_request->errors = 0;
- if (--this_request->nsector)
- return;
- this_request->bh->b_uptodate = 1;
- this_request->bh->b_dirt = 0;
- wake_up(&wait_for_request);
- unlock_buffer(this_request->bh);
- this_request->hd = -1;
- this_request=this_request->next;
- do_request();
- }
- static void write_intr(void)
- {
- if (win_result()) {
- bad_rw_intr();
- return;
- }
- if (--this_request->nsector) {
- port_write(HD_DATA,this_request->bh->b_data+512,256);
- return;
- }
- this_request->bh->b_uptodate = 1;
- this_request->bh->b_dirt = 0;
- wake_up(&wait_for_request);
- unlock_buffer(this_request->bh);
- this_request->hd = -1;
- this_request=this_request->next;
- do_request();
- }
- static void do_request(void)
- {
- int i,r;
- if (sorting)
- return;
- if (!this_request) {
- do_hd=NULL;
- return;
- }
- if (this_request->cmd == WIN_WRITE) {
- hd_out(this_request->hd,this_request->nsector,this_request->
- sector,this_request->head,this_request->cyl,
- this_request->cmd,&write_intr);
- for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
- /* nothing */ ;
- if (!r) {
- reset_hd(this_request->hd);
- return;
- }
- port_write(HD_DATA,this_request->bh->b_data+
- 512*(this_request->nsector&1),256);
- } else if (this_request->cmd == WIN_READ) {
- hd_out(this_request->hd,this_request->nsector,this_request->
- sector,this_request->head,this_request->cyl,
- this_request->cmd,&read_intr);
- } else
- panic("unknown hd-command");
- }
- /*
- * add-request adds a request to the linked list.
- * It sets the 'sorting'-variable when doing something
- * that interrupts shouldn't touch.
- */
- static void add_request(struct hd_request * req)
- {
- struct hd_request * tmp;
- if (req->nsector != 2)
- panic("nsector!=2 not implemented");
- /*
- * Not to mess up the linked lists, we never touch the two first
- * entries (not this_request, as it is used by current interrups,
- * and not this_request->next, as it can be assigned to this_request).
- * This is not too high a price to pay for the ability of not
- * disabling interrupts.
- */
- sorting=1;
- if (!(tmp=this_request))
- this_request=req;
- else {
- if (!(tmp->next))
- tmp->next=req;
- else {
- tmp=tmp->next;
- for ( ; tmp->next ; tmp=tmp->next)
- if ((IN_ORDER(tmp,req) ||
- !IN_ORDER(tmp,tmp->next)) &&
- IN_ORDER(req,tmp->next))
- break;
- req->next=tmp->next;
- tmp->next=req;
- }
- }
- sorting=0;
- /*
- * NOTE! As a result of sorting, the interrupts may have died down,
- * as they aren't redone due to locking with sorting=1. They might
- * also never have started, if this is the first request in the queue,
- * so we restart them if necessary.
- */
- if (!do_hd)
- do_request();
- }
- void rw_abs_hd(int rw,unsigned int nr,unsigned int sec,unsigned int head,
- unsigned int cyl,struct buffer_head * bh)
- {
- struct hd_request * req;
- if (rw!=READ && rw!=WRITE)
- panic("Bad hd command, must be R/W");
- lock_buffer(bh);
- repeat:
- for (req=0+request ; req<NR_REQUEST+request ; req++)
- if (req->hd<0)
- break;
- if (req==NR_REQUEST+request) {
- sleep_on(&wait_for_request);
- goto repeat;
- }
- req->hd=nr;
- req->nsector=2;
- req->sector=sec;
- req->head=head;
- req->cyl=cyl;
- req->cmd = ((rw==READ)?WIN_READ:WIN_WRITE);
- req->bh=bh;
- req->errors=0;
- req->next=NULL;
- add_request(req);
- wait_on_buffer(bh);
- }
- void hd_init(void)
- {
- int i;
- for (i=0 ; i<NR_REQUEST ; i++) {
- request[i].hd = -1;
- request[i].next = NULL;
- }
- for (i=0 ; i<NR_HD ; i++) {
- hd[i*5].start_sect = 0;
- hd[i*5].nr_sects = hd_info[i].head*
- hd_info[i].sect*hd_info[i].cyl;
- }
- set_trap_gate(0x2E,&hd_interrupt);
- outb_p(inb_p(0x21)&0xfb,0x21);
- outb(inb_p(0xA1)&0xbf,0xA1);
- }
- ------------------------------------------------------------------------
- kernel/keyboard.s
- /*
- * keyboard.s
- */
- .text
- .globl _keyboard_interrupt
- /*
- * these are for the keyboard read functions
- */
- size = 1024 /* must be a power of two ! And MUST be the same
- as in tty_io.c !!!! */
- head = 4
- tail = 8
- proc_list = 12
- buf = 16
- mode: .byte 0 /* caps, alt, ctrl and shift mode */
- leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */
- e0: .byte 0
- /*
- * con_int is the real interrupt routine that reads the
- * keyboard scan-code and converts it into the appropriate
- * ascii character(s).
- */
- _keyboard_interrupt:
- pushl %eax
- pushl %ebx
- pushl %ecx
- pushl %edx
- push %ds
- push %es
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- xorl %al,%al /* %eax is scan code */
- inb $0x60,%al
- cmpb $0xe0,%al
- je set_e0
- cmpb $0xe1,%al
- je set_e1
- call key_table(,%eax,4)
- movb $0,e0
- e0_e1: inb $0x61,%al
- jmp 1f
- 1: jmp 1f
- 1: orb $0x80,%al
- jmp 1f
- 1: jmp 1f
- 1: outb %al,$0x61
- jmp 1f
- 1: jmp 1f
- 1: andb $0x7F,%al
- outb %al,$0x61
- movb $0x20,%al
- outb %al,$0x20
- pushl $0
- call _do_tty_interrupt
- addl $4,%esp
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- popl %ebx
- popl %eax
- iret
- set_e0: movb $1,e0
- jmp e0_e1
- set_e1: movb $2,e0
- jmp e0_e1
- /*
- * This routine fills the buffer with max 8 bytes, taken from
- * %ebx:%eax. (%edx is high). The bytes are written in the
- * order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero.
- */
- put_queue:
- pushl %ecx
- pushl %edx
- movl _table_list,%edx # read-queue for console
- movl head(%edx),%ecx
- 1: movb %al,buf(%edx,%ecx)
- incl %ecx
- andl $size-1,%ecx
- cmpl tail(%edx),%ecx # buffer full - discard everything
- je 3f
- shrdl $8,%ebx,%eax
- je 2f
- shrl $8,%ebx
- jmp 1b
- 2: movl %ecx,head(%edx)
- movl proc_list(%edx),%ecx
- testl %ecx,%ecx
- je 3f
- movl $0,(%ecx)
- 3: popl %edx
- popl %ecx
- ret
- ctrl: movb $0x04,%al
- jmp 1f
- alt: movb $0x10,%al
- 1: cmpb $0,e0
- je 2f
- addb %al,%al
- 2: orb %al,mode
- ret
- unctrl: movb $0x04,%al
- jmp 1f
- unalt: movb $0x10,%al
- 1: cmpb $0,e0
- je 2f
- addb %al,%al
- 2: notb %al
- andb %al,mode
- ret
- lshift:
- orb $0x01,mode
- ret
- unlshift:
- andb $0xfe,mode
- ret
- rshift:
- orb $0x02,mode
- ret
- unrshift:
- andb $0xfd,mode
- ret
- caps: testb $0x80,mode
- jne 1f
- xorb $4,leds
- xorb $0x40,mode
- orb $0x80,mode
- set_leds:
- call kb_wait
- movb $0xed,%al /* set leds command */
- outb %al,$0x60
- call kb_wait
- movb leds,%al
- outb %al,$0x60
- ret
- uncaps: andb $0x7f,mode
- ret
- scroll:
- xorb $1,leds
- jmp set_leds
- num: xorb $2,leds
- jmp set_leds
- /*
- * curosr-key/numeric keypad cursor keys are handled here.
- * checking for numeric keypad etc.
- */
- cursor:
- subb $0x47,%al
- jb 1f
- cmpb $12,%al
- ja 1f
- jne cur2 /* check for ctrl-alt-del */
- testb $0x0c,mode
- je cur2
- testb $0x30,mode
- jne reboot
- cur2: cmpb $0x01,e0 /* e0 forces cursor movement */
- je cur
- testb $0x02,leds /* not num-lock forces cursor */
- je cur
- testb $0x03,mode /* shift forces cursor */
- jne cur
- xorl %ebx,%ebx
- movb num_table(%eax),%al
- jmp put_queue
- 1: ret
- cur: movb cur_table(%eax),%al
- cmpb $'9,%al
- ja ok_cur
- movb $'~,%ah
- ok_cur: shll $16,%eax
- movw $0x5b1b,%ax
- xorl %ebx,%ebx
- jmp put_queue
- num_table:
- .ascii "789 456 1230,"
- cur_table:
- .ascii "HA5 DGC YB623"
- /*
- * this routine handles function keys
- */
- func:
- subb $0x3B,%al
- jb end_func
- cmpb $9,%al
- jbe ok_func
- subb $18,%al
- cmpb $10,%al
- jb end_func
- cmpb $11,%al
- ja end_func
- ok_func:
- cmpl $4,%ecx /* check that there is enough room */
- jl end_func
- movl func_table(,%eax,4),%eax
- xorl %ebx,%ebx
- jmp put_queue
- end_func:
- ret
- /*
- * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc.
- */
- func_table:
- .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b
- .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b
- .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b
- key_map:
- .byte 0,27
- .ascii "1234567890+'"
- .byte 127,9
- .ascii "qwertyuiop}"
- .byte 0,10,0
- .ascii "asdfghjkl|{"
- .byte 0,0
- .ascii "'zxcvbnm,.-"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '<
- .fill 10,1,0
- shift_map:
- .byte 0,27
- .ascii "!\"#$%&/()=?`"
- .byte 127,9
- .ascii "QWERTYUIOP]^"
- .byte 10,0
- .ascii "ASDFGHJKL\\["
- .byte 0,0
- .ascii "*ZXCVBNM;:_"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '>
- .fill 10,1,0
- alt_map:
- .byte 0,0
- .ascii "\0@\0$\0\0{[]}\\\0"
- .byte 0,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte '~,10,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0,0,0 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte 0,0,0,0,0 /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '|
- .fill 10,1,0
- /*
- * do_self handles "normal" keys, ie keys that don't change meaning
- * and which have just one character returns.
- */
- do_self:
- lea alt_map,%ebx
- testb $0x20,mode /* alt-gr */
- jne 1f
- lea shift_map,%ebx
- testb $0x03,mode
- jne 1f
- lea key_map,%ebx
- 1: movb (%ebx,%eax),%al
- orb %al,%al
- je none
- testb $0x4c,mode /* ctrl or caps */
- je 2f
- cmpb $'a,%al
- jb 2f
- cmpb $'z,%al
- ja 2f
- subb $32,%al
- 2: testb $0x0c,mode /* ctrl */
- je 3f
- cmpb $64,%al
- jb 3f
- cmpb $64+32,%al
- jae 3f
- subb $64,%al
- 3: testb $0x10,mode /* left alt */
- je 4f
- orb $0x80,%al
- 4: andl $0xff,%eax
- xorl %ebx,%ebx
- call put_queue
- none: ret
- /*
- * minus has a routine of it's own, as a 'E0h' before
- * the scan code for minus means that the numeric keypad
- * slash was pushed.
- */
- minus: cmpb $1,e0
- jne do_self
- movl $'/,%eax
- xorl %ebx,%ebx
- jmp put_queue
- /*
- * This table decides which routine to call when a scan-code has been
- * gotten. Most routines just call do_self, or none, depending if
- * they are make or break.
- */
- key_table:
- .long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */
- .long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */
- .long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */
- .long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */
- .long do_self,do_self,do_self,do_self /* 10-13 q w e r */
- .long do_self,do_self,do_self,do_self /* 14-17 t y u i */
- .long do_self,do_self,do_self,do_self /* 18-1B o p } ^ */
- .long do_self,ctrl,do_self,do_self /* 1C-1F enter ctrl a s */
- .long do_self,do_self,do_self,do_self /* 20-23 d f g h */
- .long do_self,do_self,do_self,do_self /* 24-27 j k l | */
- .long do_self,do_self,lshift,do_self /* 28-2B { para lshift , */
- .long do_self,do_self,do_self,do_self /* 2C-2F z x c v */
- .long do_self,do_self,do_self,do_self /* 30-33 b n m , */
- .long do_self,minus,rshift,do_self /* 34-37 . - rshift * */
- .long alt,do_self,caps,func /* 38-3B alt sp caps f1 */
- .long func,func,func,func /* 3C-3F f2 f3 f4 f5 */
- .long func,func,func,func /* 40-43 f6 f7 f8 f9 */
- .long func,num,scroll,cursor /* 44-47 f10 num scr home */
- .long cursor,cursor,do_self,cursor /* 48-4B up pgup - left */
- .long cursor,cursor,do_self,cursor /* 4C-4F n5 right + end */
- .long cursor,cursor,cursor,cursor /* 50-53 dn pgdn ins del */
- .long none,none,do_self,func /* 54-57 sysreq ? < f11 */
- .long func,none,none,none /* 58-5B f12 ? ? ? */
- .long none,none,none,none /* 5C-5F ? ? ? ? */
- .long none,none,none,none /* 60-63 ? ? ? ? */
- .long none,none,none,none /* 64-67 ? ? ? ? */
- .long none,none,none,none /* 68-6B ? ? ? ? */
- .long none,none,none,none /* 6C-6F ? ? ? ? */
- .long none,none,none,none /* 70-73 ? ? ? ? */
- .long none,none,none,none /* 74-77 ? ? ? ? */
- .long none,none,none,none /* 78-7B ? ? ? ? */
- .long none,none,none,none /* 7C-7F ? ? ? ? */
- .long none,none,none,none /* 80-83 ? br br br */
- .long none,none,none,none /* 84-87 br br br br */
- .long none,none,none,none /* 88-8B br br br br */
- .long none,none,none,none /* 8C-8F br br br br */
- .long none,none,none,none /* 90-93 br br br br */
- .long none,none,none,none /* 94-97 br br br br */
- .long none,none,none,none /* 98-9B br br br br */
- .long none,unctrl,none,none /* 9C-9F br unctrl br br */
- .long none,none,none,none /* A0-A3 br br br br */
- .long none,none,none,none /* A4-A7 br br br br */
- .long none,none,unlshift,none /* A8-AB br br unlshift br */
- .long none,none,none,none /* AC-AF br br br br */
- .long none,none,none,none /* B0-B3 br br br br */
- .long none,none,unrshift,none /* B4-B7 br br unrshift br */
- .long unalt,none,uncaps,none /* B8-BB unalt br uncaps br */
- .long none,none,none,none /* BC-BF br br br br */
- .long none,none,none,none /* C0-C3 br br br br */
- .long none,none,none,none /* C4-C7 br br br br */
- .long none,none,none,none /* C8-CB br br br br */
- .long none,none,none,none /* CC-CF br br br br */
- .long none,none,none,none /* D0-D3 br br br br */
- .long none,none,none,none /* D4-D7 br br br br */
- .long none,none,none,none /* D8-DB br ? ? ? */
- .long none,none,none,none /* DC-DF ? ? ? ? */
- .long none,none,none,none /* E0-E3 e0 e1 ? ? */
- .long none,none,none,none /* E4-E7 ? ? ? ? */
- .long none,none,none,none /* E8-EB ? ? ? ? */
- .long none,none,none,none /* EC-EF ? ? ? ? */
- .long none,none,none,none /* F0-F3 ? ? ? ? */
- .long none,none,none,none /* F4-F7 ? ? ? ? */
- .long none,none,none,none /* F8-FB ? ? ? ? */
- .long none,none,none,none /* FC-FF ? ? ? ? */
- /*
- * kb_wait waits for the keyboard controller buffer to empty.
- * there is no timeout - if the buffer doesn't empty, we hang.
- */
- kb_wait:
- pushl %eax
- 1: inb $0x64,%al
- testb $0x02,%al
- jne 1b
- popl %eax
- ret
- /*
- * This routine reboots the machine by asking the keyboard
- * controller to pulse the reset-line low.
- */
- reboot:
- call kb_wait
- movw $0x1234,0x472 /* don't do memory check */
- movb $0xfc,%al /* pulse reset and A20 low */
- outb %al,$0x64
- die: jmp die
- ------------------------------------------------------------------------
- kernel/Makefile
- #
- # 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
- ------------------------------------------------------------------------
- kernel/mktime.c
- #include <time.h>
- /*
- * This isn't the library routine, it is only used in the kernel.
- * as such, we don't care about years<1970 etc, but assume everything
- * is ok. Similarly, TZ etc is happily ignored. We just do everything
- * as easily as possible. Let's find something public for the library
- * routines (although I think minix times is public).
- */
- /*
- * PS. I hate whoever though up the year 1970 - couldn't they have gotten
- * a leap-year instead? I also hate Gregorius, pope or no. I'm grumpy.
- */
- #define MINUTE 60
- #define HOUR (60*MINUTE)
- #define DAY (24*HOUR)
- #define YEAR (365*DAY)
- /* interestingly, we assume leap-years */
- static int month[12] = {
- 0,
- DAY*(31),
- DAY*(31+29),
- DAY*(31+29+31),
- DAY*(31+29+31+30),
- DAY*(31+29+31+30+31),
- DAY*(31+29+31+30+31+30),
- DAY*(31+29+31+30+31+30+31),
- DAY*(31+29+31+30+31+30+31+31),
- DAY*(31+29+31+30+31+30+31+31+30),
- DAY*(31+29+31+30+31+30+31+31+30+31),
- DAY*(31+29+31+30+31+30+31+31+30+31+30)
- };
- long kernel_mktime(struct tm * tm)
- {
- long res;
- int year;
- year = tm->tm_year - 70;
- /* magic offsets (y+1) needed to get leapyears right.*/
- res = YEAR*year + DAY*((year+1)/4);
- res += month[tm->tm_mon];
- /* and (y+2) here. If it wasn't a leap-year, we have to adjust */
- if (tm->tm_mon>1 && ((year+2)%4))
- res -= DAY;
- res += DAY*(tm->tm_mday-1);
- res += HOUR*tm->tm_hour;
- res += MINUTE*tm->tm_min;
- res += tm->tm_sec;
- return res;
- }
- ------------------------------------------------------------------------
- kernel/panic.c
- /*
- * This function is used through-out the kernel (includeinh mm and fs)
- * to indicate a major problem.
- */
- #include <linux/kernel.h>
- volatile void panic(const char * s)
- {
- printk("Kernel panic: %s\n\r",s);
- for(;;);
- }
- ------------------------------------------------------------------------
- kernel/printk.c
- /*
- * When in kernel-mode, we cannot use printf, as fs is liable to
- * point to 'interesting' things. Make a printf with fs-saving, and
- * all is well.
- */
- #include <stdarg.h>
- #include <stddef.h>
- #include <linux/kernel.h>
- static char buf[1024];
- int printk(const char *fmt, ...)
- {
- va_list args;
- int i;
- va_start(args, fmt);
- i=vsprintf(buf,fmt,args);
- va_end(args);
- __asm__("push %%fs\n\t"
- "push %%ds\n\t"
- "pop %%fs\n\t"
- "pushl %0\n\t"
- "pushl $_buf\n\t"
- "pushl $0\n\t"
- "call _tty_write\n\t"
- "addl $8,%%esp\n\t"
- "popl %0\n\t"
- "pop %%fs"
- ::"r" (i):"ax","cx","dx");
- return i;
- }
- ------------------------------------------------------------------------
- kernel/rs_io.s
- /*
- * 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
- ------------------------------------------------------------------------
- kernel/sched.c
- /*
- * 'sched.c' is the main kernel file. It contains scheduling primitives
- * (sleep_on, wakeup, schedule etc) as well as a number of simple system
- * call functions (type getpid(), which just extracts a field from
- * current-task
- */
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <signal.h>
- #include <linux/sys.h>
- #include <asm/system.h>
- #include <asm/io.h>
- #include <asm/segment.h>
- #define LATCH (1193180/HZ)
- extern void mem_use(void);
- extern int timer_interrupt(void);
- extern int system_call(void);
- union task_union {
- struct task_struct task;
- char stack[PAGE_SIZE];
- };
- static union task_union init_task = {INIT_TASK,};
- long volatile jiffies=0;
- long startup_time=0;
- struct task_struct *current = &(init_task.task), *last_task_used_math = NULL;
- struct task_struct * task[NR_TASKS] = {&(init_task.task), };
- long user_stack [ PAGE_SIZE>>2 ] ;
- struct {
- long * a;
- short b;
- } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
- /*
- * 'math_state_restore()' saves the current math information in the
- * old math state array, and gets the new ones from the current task
- */
- void math_state_restore()
- {
- if (last_task_used_math)
- __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
- if (current->used_math)
- __asm__("frstor %0"::"m" (current->tss.i387));
- else {
- __asm__("fninit"::);
- current->used_math=1;
- }
- last_task_used_math=current;
- }
- /*
- * 'schedule()' is the scheduler function. This is GOOD CODE! There
- * probably won't be any reason to change this, as it should work well
- * in all circumstances (ie gives IO-bound processes good response etc).
- * The one thing you might take a look at is the signal-handler code here.
- *
- * NOTE!! Task 0 is the 'idle' task, which gets called when no other
- * tasks can run. It can not be killed, and it cannot sleep. The 'state'
- * information in task[0] is never used.
- */
- void schedule(void)
- {
- int i,next,c;
- struct task_struct ** p;
- /* check alarm, wake up any interruptible tasks that have got a signal */
- for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
- if (*p) {
- if ((*p)->alarm && (*p)->alarm < jiffies) {
- (*p)->signal |= (1<<(SIGALRM-1));
- (*p)->alarm = 0;
- }
- if ((*p)->signal && (*p)->state==TASK_INTERRUPTIBLE)
- (*p)->state=TASK_RUNNING;
- }
- /* this is the scheduler proper: */
- while (1) {
- c = -1;
- next = 0;
- i = NR_TASKS;
- p = &task[NR_TASKS];
- while (--i) {
- if (!*--p)
- continue;
- if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
- c = (*p)->counter, next = i;
- }
- if (c) break;
- for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
- if (*p)
- (*p)->counter = ((*p)->counter >> 1) +
- (*p)->priority;
- }
- switch_to(next);
- }
- int sys_pause(void)
- {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- return 0;
- }
- void sleep_on(struct task_struct **p)
- {
- struct task_struct *tmp;
- if (!p)
- return;
- if (current == &(init_task.task))
- panic("task[0] trying to sleep");
- tmp = *p;
- *p = current;
- current->state = TASK_UNINTERRUPTIBLE;
- schedule();
- if (tmp)
- tmp->state=0;
- }
- void interruptible_sleep_on(struct task_struct **p)
- {
- struct task_struct *tmp;
- if (!p)
- return;
- if (current == &(init_task.task))
- panic("task[0] trying to sleep");
- tmp=*p;
- *p=current;
- repeat: current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (*p && *p != current) {
- (**p).state=0;
- goto repeat;
- }
- *p=NULL;
- if (tmp)
- tmp->state=0;
- }
- void wake_up(struct task_struct **p)
- {
- if (p && *p) {
- (**p).state=0;
- *p=NULL;
- }
- }
- void do_timer(long cpl)
- {
- if (cpl)
- current->utime++;
- else
- current->stime++;
- if ((--current->counter)>0) return;
- current->counter=0;
- if (!cpl) return;
- schedule();
- }
- int sys_alarm(long seconds)
- {
- current->alarm = (seconds>0)?(jiffies+HZ*seconds):0;
- return seconds;
- }
- int sys_getpid(void)
- {
- return current->pid;
- }
- int sys_getppid(void)
- {
- return current->father;
- }
- int sys_getuid(void)
- {
- return current->uid;
- }
- int sys_geteuid(void)
- {
- return current->euid;
- }
- int sys_getgid(void)
- {
- return current->gid;
- }
- int sys_getegid(void)
- {
- return current->egid;
- }
- int sys_nice(long increment)
- {
- if (current->priority-increment>0)
- current->priority -= increment;
- return 0;
- }
- int sys_signal(long signal,long addr,long restorer)
- {
- long i;
- switch (signal) {
- case SIGHUP: case SIGINT: case SIGQUIT: case SIGILL:
- case SIGTRAP: case SIGABRT: case SIGFPE: case SIGUSR1:
- case SIGSEGV: case SIGUSR2: case SIGPIPE: case SIGALRM:
- case SIGCHLD:
- i=(long) current->sig_fn[signal-1];
- current->sig_fn[signal-1] = (fn_ptr) addr;
- current->sig_restorer = (fn_ptr) restorer;
- return i;
- default: return -1;
- }
- }
- void sched_init(void)
- {
- int i;
- struct desc_struct * p;
- set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
- set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
- p = gdt+2+FIRST_TSS_ENTRY;
- for(i=1;i<NR_TASKS;i++) {
- task[i] = NULL;
- p->a=p->b=0;
- p++;
- p->a=p->b=0;
- p++;
- }
- ltr(0);
- lldt(0);
- outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
- outb_p(LATCH & 0xff , 0x40); /* LSB */
- outb(LATCH >> 8 , 0x40); /* MSB */
- set_intr_gate(0x20,&timer_interrupt);
- outb(inb_p(0x21)&~0x01,0x21);
- set_system_gate(0x80,&system_call);
- }
- ------------------------------------------------------------------------
- kernel/serial.c
- /*
- * serial.c
- *
- * This module implements the rs232 io functions
- * void rs_write(struct tty_struct * queue);
- * void rs_init(void);
- * and all interrupts pertaining to serial IO.
- */
- #include <linux/tty.h>
- #include <linux/sched.h>
- #include <asm/system.h>
- #include <asm/io.h>
- #define WAKEUP_CHARS (TTY_BUF_SIZE/4)
- extern void rs1_interrupt(void);
- extern void rs2_interrupt(void);
- static void init(int port)
- {
- outb_p(0x80,port+3); /* set DLAB of line control reg */
- outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */
- outb_p(0x00,port+1); /* MS of divisor */
- outb_p(0x03,port+3); /* reset DLAB */
- outb_p(0x0b,port+4); /* set DTR,RTS, OUT_2 */
- outb_p(0x0d,port+1); /* enable all intrs but writes */
- (void)inb(port); /* read data port to reset things (?) */
- }
- void rs_init(void)
- {
- set_intr_gate(0x24,rs1_interrupt);
- set_intr_gate(0x23,rs2_interrupt);
- init(tty_table[1].read_q.data);
- init(tty_table[2].read_q.data);
- outb(inb_p(0x21)&0xE7,0x21);
- }
- /*
- * This routine gets called when tty_write has put something into
- * the write_queue. It must check wheter the queue is empty, and
- * set the interrupt register accordingly
- *
- * void _rs_write(struct tty_struct * tty);
- */
- void rs_write(struct tty_struct * tty)
- {
- cli();
- if (!EMPTY(tty->write_q))
- outb(inb_p(tty->write_q.data+1)|0x02,tty->write_q.data+1);
- sti();
- }
- ------------------------------------------------------------------------
- kernel/sys.c
- #include <errno.h>
- #include <linux/sched.h>
- #include <linux/tty.h>
- #include <linux/kernel.h>
- #include <asm/segment.h>
- #include <sys/times.h>
- #include <sys/utsname.h>
- int sys_ftime()
- {
- return -ENOSYS;
- }
- int sys_mknod()
- {
- return -ENOSYS;
- }
- int sys_break()
- {
- return -ENOSYS;
- }
- int sys_mount()
- {
- return -ENOSYS;
- }
- int sys_umount()
- {
- return -ENOSYS;
- }
- int sys_ustat(int dev,struct ustat * ubuf)
- {
- return -1;
- }
- int sys_ptrace()
- {
- return -ENOSYS;
- }
- int sys_stty()
- {
- return -ENOSYS;
- }
- int sys_gtty()
- {
- return -ENOSYS;
- }
- int sys_rename()
- {
- return -ENOSYS;
- }
- int sys_prof()
- {
- return -ENOSYS;
- }
- int sys_setgid(int gid)
- {
- if (current->euid && current->uid)
- if (current->gid==gid || current->sgid==gid)
- current->egid=gid;
- else
- return -EPERM;
- else
- current->gid=current->egid=gid;
- return 0;
- }
- int sys_acct()
- {
- return -ENOSYS;
- }
- int sys_phys()
- {
- return -ENOSYS;
- }
- int sys_lock()
- {
- return -ENOSYS;
- }
- int sys_mpx()
- {
- return -ENOSYS;
- }
- int sys_ulimit()
- {
- return -ENOSYS;
- }
- int sys_time(long * tloc)
- {
- int i;
- i = CURRENT_TIME;
- if (tloc) {
- verify_area(tloc,4);
- put_fs_long(i,(unsigned long *)tloc);
- }
- return i;
- }
- int sys_setuid(int uid)
- {
- if (current->euid && current->uid)
- if (uid==current->uid || current->suid==current->uid)
- current->euid=uid;
- else
- return -EPERM;
- else
- current->euid=current->uid=uid;
- return 0;
- }
- int sys_stime(long * tptr)
- {
- if (current->euid && current->uid)
- return -1;
- startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ;
- return 0;
- }
- int sys_times(struct tms * tbuf)
- {
- if (!tbuf)
- return jiffies;
- verify_area(tbuf,sizeof *tbuf);
- put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime);
- put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime);
- put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime);
- put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime);
- return jiffies;
- }
- int sys_brk(unsigned long end_data_seg)
- {
- if (end_data_seg >= current->end_code &&
- end_data_seg < current->start_stack - 16384)
- current->brk = end_data_seg;
- return current->brk;
- }
- /*
- * This needs some heave checking ...
- * I just haven't get the stomach for it. I also don't fully
- * understand sessions/pgrp etc. Let somebody who does explain it.
- */
- int sys_setpgid(int pid, int pgid)
- {
- int i;
- if (!pid)
- pid = current->pid;
- if (!pgid)
- pgid = pid;
- for (i=0 ; i<NR_TASKS ; i++)
- if (task[i] && task[i]->pid==pid) {
- if (task[i]->leader)
- return -EPERM;
- if (task[i]->session != current->session)
- return -EPERM;
- task[i]->pgrp = pgid;
- return 0;
- }
- return -ESRCH;
- }
- int sys_getpgrp(void)
- {
- return current->pgrp;
- }
- int sys_setsid(void)
- {
- if (current->uid && current->euid)
- return -EPERM;
- if (current->leader)
- return -EPERM;
- current->leader = 1;
- current->session = current->pgrp = current->pid;
- current->tty = -1;
- return current->pgrp;
- }
- int sys_uname(struct utsname * name)
- {
- static struct utsname thisname = {
- "linux .0","nodename","release ","version ","machine "
- };
- int i;
- if (!name) return -1;
- verify_area(name,sizeof *name);
- for(i=0;i<sizeof *name;i++)
- put_fs_byte(((char *) &thisname)[i],i+(char *) name);
- return (0);
- }
- int sys_umask(int mask)
- {
- int old = current->umask;
- current->umask = mask & 0777;
- return (old);
- }
- ------------------------------------------------------------------------
- kernel/system_call.s
- /*
- * 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
- ------------------------------------------------------------------------
- kernel/traps.c
- /*
- * 'Traps.c' handles hardware traps and faults after we have saved some
- * state in 'asm.s'. Currently mostly a debugging-aid, will be extended
- * to mainly kill the offending process (probably by giving it a signal,
- * but possibly by killing it outright if necessary).
- */
- #include <string.h>
- #include <linux/head.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <asm/system.h>
- #include <asm/segment.h>
- #define get_seg_byte(seg,addr) ({ \
- register char __res; \
- __asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \
- :"=a" (__res):"0" (seg),"m" (*(addr))); \
- __res;})
- #define get_seg_long(seg,addr) ({ \
- register unsigned long __res; \
- __asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \
- :"=a" (__res):"0" (seg),"m" (*(addr))); \
- __res;})
- #define _fs() ({ \
- register unsigned short __res; \
- __asm__("mov %%fs,%%ax":"=a" (__res):); \
- __res;})
- int do_exit(long code);
- void page_exception(void);
- void divide_error(void);
- void debug(void);
- void nmi(void);
- void int3(void);
- void overflow(void);
- void bounds(void);
- void invalid_op(void);
- void device_not_available(void);
- void double_fault(void);
- void coprocessor_segment_overrun(void);
- void invalid_TSS(void);
- void segment_not_present(void);
- void stack_segment(void);
- void general_protection(void);
- void page_fault(void);
- void coprocessor_error(void);
- void reserved(void);
- static void die(char * str,long esp_ptr,long nr)
- {
- long * esp = (long *) esp_ptr;
- int i;
- printk("%s: %04x\n\r",str,nr&0xffff);
- printk("EIP:\t%04x:%p\nEFLAGS:\t%p\nESP:\t%04x:%p\n",
- esp[1],esp[0],esp[2],esp[4],esp[3]);
- printk("fs: %04x\n",_fs());
- printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x17));
- if (esp[4] == 0x17) {
- printk("Stack: ");
- for (i=0;i<4;i++)
- printk("%p ",get_seg_long(0x17,i+(long *)esp[3]));
- printk("\n");
- }
- str(i);
- printk("Pid: %d, process nr: %d\n\r",current->pid,0xffff & i);
- for(i=0;i<10;i++)
- printk("%02x ",0xff & get_seg_byte(esp[1],(i+(char *)esp[0])));
- printk("\n\r");
- do_exit(11); /* play segment exception */
- }
- void do_double_fault(long esp, long error_code)
- {
- die("double fault",esp,error_code);
- }
- void do_general_protection(long esp, long error_code)
- {
- die("general protection",esp,error_code);
- }
- void do_divide_error(long esp, long error_code)
- {
- die("divide error",esp,error_code);
- }
- void do_int3(long * esp, long error_code,
- long fs,long es,long ds,
- long ebp,long esi,long edi,
- long edx,long ecx,long ebx,long eax)
- {
- int tr;
- __asm__("str %%ax":"=a" (tr):"0" (0));
- printk("eax\t\tebx\t\tecx\t\tedx\n\r%8x\t%8x\t%8x\t%8x\n\r",
- eax,ebx,ecx,edx);
- printk("esi\t\tedi\t\tebp\t\tesp\n\r%8x\t%8x\t%8x\t%8x\n\r",
- esi,edi,ebp,(long) esp);
- printk("\n\rds\tes\tfs\ttr\n\r%4x\t%4x\t%4x\t%4x\n\r",
- ds,es,fs,tr);
- printk("EIP: %8x CS: %4x EFLAGS: %8x\n\r",esp[0],esp[1],esp[2]);
- }
- void do_nmi(long esp, long error_code)
- {
- die("nmi",esp,error_code);
- }
- void do_debug(long esp, long error_code)
- {
- die("debug",esp,error_code);
- }
- void do_overflow(long esp, long error_code)
- {
- die("overflow",esp,error_code);
- }
- void do_bounds(long esp, long error_code)
- {
- die("bounds",esp,error_code);
- }
- void do_invalid_op(long esp, long error_code)
- {
- die("invalid operand",esp,error_code);
- }
- void do_device_not_available(long esp, long error_code)
- {
- die("device not available",esp,error_code);
- }
- void do_coprocessor_segment_overrun(long esp, long error_code)
- {
- die("coprocessor segment overrun",esp,error_code);
- }
- void do_invalid_TSS(long esp,long error_code)
- {
- die("invalid TSS",esp,error_code);
- }
- void do_segment_not_present(long esp,long error_code)
- {
- die("segment not present",esp,error_code);
- }
- void do_stack_segment(long esp,long error_code)
- {
- die("stack segment",esp,error_code);
- }
- void do_coprocessor_error(long esp, long error_code)
- {
- die("coprocessor error",esp,error_code);
- }
- void do_reserved(long esp, long error_code)
- {
- die("reserved (15,17-31) error",esp,error_code);
- }
- void trap_init(void)
- {
- int i;
- set_trap_gate(0,÷_error);
- set_trap_gate(1,&debug);
- set_trap_gate(2,&nmi);
- set_system_gate(3,&int3); /* int3-5 can be called from all */
- set_system_gate(4,&overflow);
- set_system_gate(5,&bounds);
- set_trap_gate(6,&invalid_op);
- set_trap_gate(7,&device_not_available);
- set_trap_gate(8,&double_fault);
- set_trap_gate(9,&coprocessor_segment_overrun);
- set_trap_gate(10,&invalid_TSS);
- set_trap_gate(11,&segment_not_present);
- set_trap_gate(12,&stack_segment);
- set_trap_gate(13,&general_protection);
- set_trap_gate(14,&page_fault);
- set_trap_gate(15,&reserved);
- set_trap_gate(16,&coprocessor_error);
- for (i=17;i<32;i++)
- set_trap_gate(i,&reserved);
- /* __asm__("movl $0x3ff000,%%eax\n\t"
- "movl %%eax,%%db0\n\t"
- "movl $0x000d0303,%%eax\n\t"
- "movl %%eax,%%db7"
- :::"ax");*/
- }
- ------------------------------------------------------------------------
- kernel/tty_io.c
- /*
- * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
- * or rs-channels. It also implements echoing, cooked mode etc (well,
- * not currently, but ...)
- */
- #include <ctype.h>
- #include <errno.h>
- #include <signal.h>
- #define ALRMMASK (1<<(SIGALRM-1))
- #include <linux/sched.h>
- #include <linux/tty.h>
- #include <asm/segment.h>
- #include <asm/system.h>
- #define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f)
- #define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f)
- #define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f)
- #define L_CANON(tty) _L_FLAG((tty),ICANON)
- #define L_ISIG(tty) _L_FLAG((tty),ISIG)
- #define L_ECHO(tty) _L_FLAG((tty),ECHO)
- #define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
- #define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
- #define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
- #define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
- #define I_UCLC(tty) _I_FLAG((tty),IUCLC)
- #define I_NLCR(tty) _I_FLAG((tty),INLCR)
- #define I_CRNL(tty) _I_FLAG((tty),ICRNL)
- #define I_NOCR(tty) _I_FLAG((tty),IGNCR)
- #define O_POST(tty) _O_FLAG((tty),OPOST)
- #define O_NLCR(tty) _O_FLAG((tty),ONLCR)
- #define O_CRNL(tty) _O_FLAG((tty),OCRNL)
- #define O_NLRET(tty) _O_FLAG((tty),ONLRET)
- #define O_LCUC(tty) _O_FLAG((tty),OLCUC)
- struct tty_struct tty_table[] = {
- {
- {0,
- OPOST|ONLCR, /* change outgoing NL to CRNL */
- 0,
- ICANON | ECHO | ECHOCTL | ECHOKE,
- 0, /* console termio */
- INIT_C_CC},
- 0, /* initial pgrp */
- 0, /* initial stopped */
- con_write,
- {0,0,0,0,""}, /* console read-queue */
- {0,0,0,0,""}, /* console write-queue */
- {0,0,0,0,""} /* console secondary queue */
- },{
- {0, /*IGNCR*/
- OPOST | ONLRET, /* change outgoing NL to CR */
- B2400 | CS8,
- 0,
- 0,
- INIT_C_CC},
- 0,
- 0,
- rs_write,
- {0x3f8,0,0,0,""}, /* rs 1 */
- {0x3f8,0,0,0,""},
- {0,0,0,0,""}
- },{
- {0, /*IGNCR*/
- OPOST | ONLRET, /* change outgoing NL to CR */
- B2400 | CS8,
- 0,
- 0,
- INIT_C_CC},
- 0,
- 0,
- rs_write,
- {0x2f8,0,0,0,""}, /* rs 2 */
- {0x2f8,0,0,0,""},
- {0,0,0,0,""}
- }
- };
- /*
- * these are the tables used by the machine code handlers.
- * you can implement pseudo-tty's or something by changing
- * them. Currently not done.
- */
- struct tty_queue * table_list[]={
- &tty_table[0].read_q, &tty_table[0].write_q,
- &tty_table[1].read_q, &tty_table[1].write_q,
- &tty_table[2].read_q, &tty_table[2].write_q
- };
- void tty_init(void)
- {
- rs_init();
- con_init();
- }
- void tty_intr(struct tty_struct * tty, int signal)
- {
- int i;
- if (tty->pgrp <= 0)
- return;
- for (i=0;i<NR_TASKS;i++)
- if (task[i] && task[i]->pgrp==tty->pgrp)
- task[i]->signal |= 1<<(signal-1);
- }
- static void sleep_if_empty(struct tty_queue * queue)
- {
- cli();
- while (!current->signal && EMPTY(*queue))
- interruptible_sleep_on(&queue->proc_list);
- sti();
- }
- static void sleep_if_full(struct tty_queue * queue)
- {
- if (!FULL(*queue))
- return;
- cli();
- while (!current->signal && LEFT(*queue)<128)
- interruptible_sleep_on(&queue->proc_list);
- sti();
- }
- void copy_to_cooked(struct tty_struct * tty)
- {
- signed char c;
- while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) {
- GETCH(tty->read_q,c);
- if (c==13)
- if (I_CRNL(tty))
- c=10;
- else if (I_NOCR(tty))
- continue;
- else ;
- else if (c==10 && I_NLCR(tty))
- c=13;
- if (I_UCLC(tty))
- c=tolower(c);
- if (L_CANON(tty)) {
- if (c==ERASE_CHAR(tty)) {
- if (EMPTY(tty->secondary) ||
- (c=LAST(tty->secondary))==10 ||
- c==EOF_CHAR(tty))
- continue;
- if (L_ECHO(tty)) {
- if (c<32)
- PUTCH(127,tty->write_q);
- PUTCH(127,tty->write_q);
- tty->write(tty);
- }
- DEC(tty->secondary.head);
- continue;
- }
- if (c==STOP_CHAR(tty)) {
- tty->stopped=1;
- continue;
- }
- if (c==START_CHAR(tty)) {
- tty->stopped=0;
- continue;
- }
- }
- if (!L_ISIG(tty)) {
- if (c==INTR_CHAR(tty)) {
- tty_intr(tty,SIGINT);
- continue;
- }
- }
- if (c==10 || c==EOF_CHAR(tty))
- tty->secondary.data++;
- if (L_ECHO(tty)) {
- if (c==10) {
- PUTCH(10,tty->write_q);
- PUTCH(13,tty->write_q);
- } else if (c<32) {
- if (L_ECHOCTL(tty)) {
- PUTCH('^',tty->write_q);
- PUTCH(c+64,tty->write_q);
- }
- } else
- PUTCH(c,tty->write_q);
- tty->write(tty);
- }
- PUTCH(c,tty->secondary);
- }
- wake_up(&tty->secondary.proc_list);
- }
- int tty_read(unsigned channel, char * buf, int nr)
- {
- struct tty_struct * tty;
- char c, * b=buf;
- int minimum,time,flag=0;
- long oldalarm;
- if (channel>2 || nr<0) return -1;
- tty = &tty_table[channel];
- oldalarm = current->alarm;
- time = (unsigned) 10*tty->termios.c_cc[VTIME];
- minimum = (unsigned) tty->termios.c_cc[VMIN];
- if (time && !minimum) {
- minimum=1;
- if (flag=(!oldalarm || time+jiffies<oldalarm))
- current->alarm = time+jiffies;
- }
- if (minimum>nr)
- minimum=nr;
- while (nr>0) {
- if (flag && (current->signal & ALRMMASK)) {
- current->signal &= ~ALRMMASK;
- break;
- }
- if (current->signal)
- break;
- if (EMPTY(tty->secondary) || (L_CANON(tty) &&
- !tty->secondary.data && LEFT(tty->secondary)>20)) {
- sleep_if_empty(&tty->secondary);
- continue;
- }
- do {
- GETCH(tty->secondary,c);
- if (c==EOF_CHAR(tty) || c==10)
- tty->secondary.data--;
- if (c==EOF_CHAR(tty) && L_CANON(tty))
- return (b-buf);
- else {
- put_fs_byte(c,b++);
- if (!--nr)
- break;
- }
- } while (nr>0 && !EMPTY(tty->secondary));
- if (time && !L_CANON(tty))
- if (flag=(!oldalarm || time+jiffies<oldalarm))
- current->alarm = time+jiffies;
- else
- current->alarm = oldalarm;
- if (L_CANON(tty)) {
- if (b-buf)
- break;
- } else if (b-buf >= minimum)
- break;
- }
- current->alarm = oldalarm;
- if (current->signal && !(b-buf))
- return -EINTR;
- return (b-buf);
- }
- int tty_write(unsigned channel, char * buf, int nr)
- {
- static cr_flag=0;
- struct tty_struct * tty;
- char c, *b=buf;
- if (channel>2 || nr<0) return -1;
- tty = channel + tty_table;
- while (nr>0) {
- sleep_if_full(&tty->write_q);
- if (current->signal)
- break;
- while (nr>0 && !FULL(tty->write_q)) {
- c=get_fs_byte(b);
- if (O_POST(tty)) {
- if (c=='\r' && O_CRNL(tty))
- c='\n';
- else if (c=='\n' && O_NLRET(tty))
- c='\r';
- if (c=='\n' && !cr_flag && O_NLCR(tty)) {
- cr_flag = 1;
- PUTCH(13,tty->write_q);
- continue;
- }
- if (O_LCUC(tty))
- c=toupper(c);
- }
- b++; nr--;
- cr_flag = 0;
- PUTCH(c,tty->write_q);
- }
- tty->write(tty);
- if (nr>0)
- schedule();
- }
- return (b-buf);
- }
- /*
- * Jeh, sometimes I really like the 386.
- * This routine is called from an interrupt,
- * and there should be absolutely no problem
- * with sleeping even in an interrupt (I hope).
- * Of course, if somebody proves me wrong, I'll
- * hate intel for all time :-). We'll have to
- * be careful and see to reinstating the interrupt
- * chips before calling this, though.
- */
- void do_tty_interrupt(int tty)
- {
- copy_to_cooked(tty_table+tty);
- }
- ------------------------------------------------------------------------
- kernel/vsprintf.c
- /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
- /*
- * Wirzenius wrote this portably, Torvalds fucked it up :-)
- */
- #include <stdarg.h>
- #include <string.h>
- /* we use this so that we can do without the ctype library */
- #define is_digit(c) ((c) >= '0' && (c) <= '9')
- static int skip_atoi(const char **s)
- {
- int i=0;
- while (is_digit(**s))
- i = i*10 + *((*s)++) - '0';
- return i;
- }
- #define ZEROPAD 1 /* pad with zero */
- #define SIGN 2 /* unsigned/signed long */
- #define PLUS 4 /* show plus */
- #define SPACE 8 /* space if plus */
- #define LEFT 16 /* left justified */
- #define SPECIAL 32 /* 0x */
- #define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */
- #define do_div(n,base) ({ \
- int __res; \
- __asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \
- __res; })
- static char * number(char * str, int num, int base, int size, int precision
- ,int type)
- {
- char c,sign,tmp[36];
- const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- int i;
- if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz";
- if (type&LEFT) type &= ~ZEROPAD;
- if (base<2 || base>36)
- return 0;
- c = (type & ZEROPAD) ? '0' : ' ' ;
- if (type&SIGN && num<0) {
- sign='-';
- num = -num;
- } else
- sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0);
- if (sign) size--;
- if (type&SPECIAL)
- if (base==16) size -= 2;
- else if (base==8) size--;
- i=0;
- if (num==0)
- tmp[i++]='0';
- else while (num!=0)
- tmp[i++]=digits[do_div(num,base)];
- if (i>precision) precision=i;
- size -= precision;
- if (!(type&(ZEROPAD+LEFT)))
- while(size-->0)
- *str++ = ' ';
- if (sign)
- *str++ = sign;
- if (type&SPECIAL)
- if (base==8)
- *str++ = '0';
- else if (base==16) {
- *str++ = '0';
- *str++ = digits[33];
- }
- if (!(type&LEFT))
- while(size-->0)
- *str++ = c;
- while(i<precision--)
- *str++ = '0';
- while(i-->0)
- *str++ = tmp[i];
- while(size-->0)
- *str++ = ' ';
- return str;
- }
- int vsprintf(char *buf, const char *fmt, va_list args)
- {
- int len;
- int i;
- char * str;
- char *s;
- int *ip;
- int flags; /* flags to number() */
- int field_width; /* width of output field */
- int precision; /* min. # of digits for integers; max
- number of chars for from string */
- int qualifier; /* 'h', 'l', or 'L' for integer fields */
- for (str=buf ; *fmt ; ++fmt) {
- if (*fmt != '%') {
- *str++ = *fmt;
- continue;
- }
- /* process flags */
- flags = 0;
- repeat:
- ++fmt; /* this also skips first '%' */
- switch (*fmt) {
- case '-': flags |= LEFT; goto repeat;
- case '+': flags |= PLUS; goto repeat;
- case ' ': flags |= SPACE; goto repeat;
- case '#': flags |= SPECIAL; goto repeat;
- case '0': flags |= ZEROPAD; goto repeat;
- }
- /* get field width */
- field_width = -1;
- if (is_digit(*fmt))
- field_width = skip_atoi(&fmt);
- else if (*fmt == '*') {
- /* it's the next argument */
- field_width = va_arg(args, int);
- if (field_width < 0) {
- field_width = -field_width;
- flags |= LEFT;
- }
- }
- /* get the precision */
- precision = -1;
- if (*fmt == '.') {
- ++fmt;
- if (is_digit(*fmt))
- precision = skip_atoi(&fmt);
- else if (*fmt == '*') {
- /* it's the next argument */
- precision = va_arg(args, int);
- }
- if (precision < 0)
- precision = 0;
- }
- /* get the conversion qualifier */
- qualifier = -1;
- if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
- qualifier = *fmt;
- ++fmt;
- }
- switch (*fmt) {
- case 'c':
- if (!(flags & LEFT))
- while (--field_width > 0)
- *str++ = ' ';
- *str++ = (unsigned char) va_arg(args, int);
- while (--field_width > 0)
- *str++ = ' ';
- break;
- case 's':
- s = va_arg(args, char *);
- len = strlen(s);
- if (precision < 0)
- precision = len;
- else if (len > precision)
- len = precision;
- if (!(flags & LEFT))
- while (len < field_width--)
- *str++ = ' ';
- for (i = 0; i < len; ++i)
- *str++ = *s++;
- while (len < field_width--)
- *str++ = ' ';
- break;
- case 'o':
- str = number(str, va_arg(args, unsigned long), 8,
- field_width, precision, flags);
- break;
- case 'p':
- if (field_width == -1) {
- field_width = 8;
- flags |= ZEROPAD;
- }
- str = number(str,
- (unsigned long) va_arg(args, void *), 16,
- field_width, precision, flags);
- break;
- case 'x':
- flags |= SMALL;
- case 'X':
- str = number(str, va_arg(args, unsigned long), 16,
- field_width, precision, flags);
- break;
- case 'd':
- case 'i':
- flags |= SIGN;
- case 'u':
- str = number(str, va_arg(args, unsigned long), 10,
- field_width, precision, flags);
- break;
- case 'n':
- ip = va_arg(args, int *);
- *ip = (str - buf);
- break;
- default:
- if (*fmt != '%')
- *str++ = '%';
- if (*fmt)
- *str++ = *fmt;
- else
- --fmt;
- break;
- }
- }
- *str = '\0';
- return str-buf;
- }
- ------------------------------------------------------------------------
- lib/close.c
- #define __LIBRARY__
- #include <unistd.h>
- _syscall1(int,close,int,fd)
- ------------------------------------------------------------------------
- lib/ctype.c
- #include <ctype.h>
- char _ctmp;
- unsigned char _ctype[] = {0x00, /* EOF */
- _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
- _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
- _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
- _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
- _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
- _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
- _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
- _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
- _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
- _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
- _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
- _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
- _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
- _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
- _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
- _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */
- ------------------------------------------------------------------------
- lib/dup.c
- #define __LIBRARY__
- #include <unistd.h>
- _syscall1(int,dup,int,fd)
- ------------------------------------------------------------------------
- lib/errno.c
- int errno;
- ------------------------------------------------------------------------
- lib/execve.c
- #define __LIBRARY__
- #include <unistd.h>
- _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
- ------------------------------------------------------------------------
- lib/_exit.c
- #define __LIBRARY__
- #include <unistd.h>
- volatile void _exit(int exit_code)
- {
- __asm__("int $0x80"::"a" (__NR_exit),"b" (exit_code));
- }
- ------------------------------------------------------------------------
- lib/Makefile
- #
- # 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:
- ------------------------------------------------------------------------
- lib/open.c
- #define __LIBRARY__
- #include <unistd.h>
- #include <stdarg.h>
- int open(const char * filename, int flag, ...)
- {
- register int res;
- va_list arg;
- va_start(arg,flag);
- __asm__("int $0x80"
- :"=a" (res)
- :"0" (__NR_open),"b" (filename),"c" (flag),
- "d" (va_arg(arg,int)));
- if (res>=0)
- return res;
- errno = -res;
- return -1;
- }
- ------------------------------------------------------------------------
- lib/setsid.c
- #define __LIBRARY__
- #include <unistd.h>
- _syscall0(pid_t,setsid)
- ------------------------------------------------------------------------
- lib/string.c
- #ifndef __GNUC__
- #error I want gcc!
- #endif
- #define extern
- #define inline
- #define __LIBRARY__
- #include <string.h>
- ------------------------------------------------------------------------
- lib/wait.c
- #define __LIBRARY__
- #include <unistd.h>
- #include <sys/wait.h>
- _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
- pid_t wait(int * wait_stat)
- {
- return waitpid(-1,wait_stat,0);
- }
- ------------------------------------------------------------------------
- lib/write.c
- #define __LIBRARY__
- #include <unistd.h>
- _syscall3(int,write,int,fd,const char *,buf,off_t,count)
- ------------------------------------------------------------------------
- mm/Makefile
- 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
- ------------------------------------------------------------------------
- mm/memory.c
- #include <signal.h>
- #include <linux/config.h>
- #include <linux/head.h>
- #include <linux/kernel.h>
- #include <asm/system.h>
- int do_exit(long code);
- #define invalidate() \
- __asm__("movl %%eax,%%cr3"::"a" (0))
- #if (BUFFER_END < 0x100000)
- #define LOW_MEM 0x100000
- #else
- #define LOW_MEM BUFFER_END
- #endif
- /* these are not to be changed - thay are calculated from the above */
- #define PAGING_MEMORY (HIGH_MEMORY - LOW_MEM)
- #define PAGING_PAGES (PAGING_MEMORY/4096)
- #define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
- #if (PAGING_PAGES < 10)
- #error "Won't work"
- #endif
- #define copy_page(from,to) \
- __asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
- static unsigned short mem_map [ PAGING_PAGES ] = {0,};
- /*
- * Get physical address of first (actually last :-) free page, and mark it
- * used. If no free pages left, return 0.
- */
- unsigned long get_free_page(void)
- {
- register unsigned long __res asm("ax");
- __asm__("std ; repne ; scasw\n\t"
- "jne 1f\n\t"
- "movw $1,2(%%edi)\n\t"
- "sall $12,%%ecx\n\t"
- "movl %%ecx,%%edx\n\t"
- "addl %2,%%edx\n\t"
- "movl $1024,%%ecx\n\t"
- "leal 4092(%%edx),%%edi\n\t"
- "rep ; stosl\n\t"
- "movl %%edx,%%eax\n"
- "1:"
- :"=a" (__res)
- :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
- "D" (mem_map+PAGING_PAGES-1)
- :"di","cx","dx");
- return __res;
- }
- /*
- * Free a page of memory at physical address 'addr'. Used by
- * 'free_page_tables()'
- */
- void free_page(unsigned long addr)
- {
- if (addr<LOW_MEM) return;
- if (addr>HIGH_MEMORY)
- panic("trying to free nonexistent page");
- addr -= LOW_MEM;
- addr >>= 12;
- if (mem_map[addr]--) return;
- mem_map[addr]=0;
- panic("trying to free free page");
- }
- /*
- * This function frees a continuos block of page tables, as needed
- * by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks.
- */
- int free_page_tables(unsigned long from,unsigned long size)
- {
- unsigned long *pg_table;
- unsigned long * dir, nr;
- if (from & 0x3fffff)
- panic("free_page_tables called with wrong alignment");
- if (!from)
- panic("Trying to free up swapper memory space");
- size = (size + 0x3fffff) >> 22;
- dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
- for ( ; size-->0 ; dir++) {
- if (!(1 & *dir))
- continue;
- pg_table = (unsigned long *) (0xfffff000 & *dir);
- for (nr=0 ; nr<1024 ; nr++) {
- if (1 & *pg_table)
- free_page(0xfffff000 & *pg_table);
- *pg_table = 0;
- pg_table++;
- }
- free_page(0xfffff000 & *dir);
- *dir = 0;
- }
- invalidate();
- return 0;
- }
- /*
- * Well, here is one of the most complicated functions in mm. It
- * copies a range of linerar addresses by copying only the pages.
- * Let's hope this is bug-free, 'cause this one I don't want to debug :-)
- *
- * Note! We don't copy just any chunks of memory - addresses have to
- * be divisible by 4Mb (one page-directory entry), as this makes the
- * function easier. It's used only by fork anyway.
- *
- * NOTE 2!! When from==0 we are copying kernel space for the first
- * fork(). Then we DONT want to copy a full page-directory entry, as
- * that would lead to some serious memory waste - we just copy the
- * first 160 pages - 640kB. Even that is more than we need, but it
- * doesn't take any more memory - we don't copy-on-write in the low
- * 1 Mb-range, so the pages can be shared with the kernel. Thus the
- * special case for nr=xxxx.
- */
- int copy_page_tables(unsigned long from,unsigned long to,long size)
- {
- unsigned long * from_page_table;
- unsigned long * to_page_table;
- unsigned long this_page;
- unsigned long * from_dir, * to_dir;
- unsigned long nr;
- if ((from&0x3fffff) || (to&0x3fffff))
- panic("copy_page_tables called with wrong alignment");
- from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
- to_dir = (unsigned long *) ((to>>20) & 0xffc);
- size = ((unsigned) (size+0x3fffff)) >> 22;
- for( ; size-->0 ; from_dir++,to_dir++) {
- if (1 & *to_dir)
- panic("copy_page_tables: already exist");
- if (!(1 & *from_dir))
- continue;
- from_page_table = (unsigned long *) (0xfffff000 & *from_dir);
- if (!(to_page_table = (unsigned long *) get_free_page()))
- return -1; /* Out of memory, see freeing */
- *to_dir = ((unsigned long) to_page_table) | 7;
- nr = (from==0)?0xA0:1024;
- for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {
- this_page = *from_page_table;
- if (!(1 & this_page))
- continue;
- this_page &= ~2;
- *to_page_table = this_page;
- if (this_page > LOW_MEM) {
- *from_page_table = this_page;
- this_page -= LOW_MEM;
- this_page >>= 12;
- mem_map[this_page]++;
- }
- }
- }
- invalidate();
- return 0;
- }
- /*
- * This function puts a page in memory at the wanted address.
- * It returns the physical address of the page gotten, 0 if
- * out of memory (either when trying to access page-table or
- * page.)
- */
- unsigned long put_page(unsigned long page,unsigned long address)
- {
- unsigned long tmp, *page_table;
- /* NOTE !!! This uses the fact that _pg_dir=0 */
- if (page < LOW_MEM || page > HIGH_MEMORY)
- printk("Trying to put page %p at %p\n",page,address);
- if (mem_map[(page-LOW_MEM)>>12] != 1)
- printk("mem_map disagrees with %p at %p\n",page,address);
- page_table = (unsigned long *) ((address>>20) & 0xffc);
- if ((*page_table)&1)
- page_table = (unsigned long *) (0xfffff000 & *page_table);
- else {
- if (!(tmp=get_free_page()))
- return 0;
- *page_table = tmp|7;
- page_table = (unsigned long *) tmp;
- }
- page_table[(address>>12) & 0x3ff] = page | 7;
- return page;
- }
- void un_wp_page(unsigned long * table_entry)
- {
- unsigned long old_page,new_page;
- old_page = 0xfffff000 & *table_entry;
- if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) {
- *table_entry |= 2;
- return;
- }
- if (!(new_page=get_free_page()))
- do_exit(SIGSEGV);
- if (old_page >= LOW_MEM)
- mem_map[MAP_NR(old_page)]--;
- *table_entry = new_page | 7;
- copy_page(old_page,new_page);
- }
- /*
- * This routine handles present pages, when users try to write
- * to a shared page. It is done by copying the page to a new address
- * and decrementing the shared-page counter for the old page.
- */
- void do_wp_page(unsigned long error_code,unsigned long address)
- {
- un_wp_page((unsigned long *)
- (((address>>10) & 0xffc) + (0xfffff000 &
- *((unsigned long *) ((address>>20) &0xffc)))));
- }
- void write_verify(unsigned long address)
- {
- unsigned long page;
- if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1))
- return;
- page &= 0xfffff000;
- page += ((address>>10) & 0xffc);
- if ((3 & *(unsigned long *) page) == 1) /* non-writeable, present */
- un_wp_page((unsigned long *) page);
- return;
- }
- void do_no_page(unsigned long error_code,unsigned long address)
- {
- unsigned long tmp;
- if (tmp=get_free_page())
- if (put_page(tmp,address))
- return;
- do_exit(SIGSEGV);
- }
- void calc_mem(void)
- {
- int i,j,k,free=0;
- long * pg_tbl;
- for(i=0 ; i<PAGING_PAGES ; i++)
- if (!mem_map[i]) free++;
- printk("%d pages free (of %d)\n\r",free,PAGING_PAGES);
- for(i=2 ; i<1024 ; i++) {
- if (1&pg_dir[i]) {
- pg_tbl=(long *) (0xfffff000 & pg_dir[i]);
- for(j=k=0 ; j<1024 ; j++)
- if (pg_tbl[j]&1)
- k++;
- printk("Pg-dir[%d] uses %d pages\n",i,k);
- }
- }
- }
- ------------------------------------------------------------------------
- mm/page.s
- /*
- * 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
- ------------------------------------------------------------------------
- tools/build.c
- #include <stdio.h> /* fprintf */
- #include <stdlib.h> /* contains exit */
- #include <sys/types.h> /* unistd.h needs this */
- #include <unistd.h> /* contains read/write */
- #include <fcntl.h>
- #define MINIX_HEADER 32
- #define GCC_HEADER 1024
- void die(char * str)
- {
- fprintf(stderr,"%s\n",str);
- exit(1);
- }
- void usage(void)
- {
- die("Usage: build boot system [> image]");
- }
- int main(int argc, char ** argv)
- {
- int i,c,id;
- char buf[1024];
- if (argc != 3)
- usage();
- for (i=0;i<sizeof buf; i++) buf[i]=0;
- if ((id=open(argv[1],O_RDONLY,0))<0)
- die("Unable to open 'boot'");
- if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
- die("Unable to read header of 'boot'");
- if (((long *) buf)[0]!=0x04100301)
- die("Non-Minix header of 'boot'");
- if (((long *) buf)[1]!=MINIX_HEADER)
- die("Non-Minix header of 'boot'");
- if (((long *) buf)[3]!=0)
- die("Illegal data segment in 'boot'");
- if (((long *) buf)[4]!=0)
- die("Illegal bss in 'boot'");
- if (((long *) buf)[5] != 0)
- die("Non-Minix header of 'boot'");
- if (((long *) buf)[7] != 0)
- die("Illegal symbol table in 'boot'");
- i=read(id,buf,sizeof buf);
- fprintf(stderr,"Boot sector %d bytes.\n",i);
- if (i>510)
- die("Boot block may not exceed 510 bytes");
- buf[510]=0x55;
- buf[511]=0xAA;
- i=write(1,buf,512);
- if (i!=512)
- die("Write call failed");
- close (id);
- if ((id=open(argv[2],O_RDONLY,0))<0)
- die("Unable to open 'system'");
- if (read(id,buf,GCC_HEADER) != GCC_HEADER)
- die("Unable to read header of 'system'");
- if (((long *) buf)[5] != 0)
- die("Non-GCC header of 'system'");
- for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
- if (write(1,buf,c)!=c)
- die("Write call failed");
- close(id);
- fprintf(stderr,"System %d bytes.\n",i);
- return(0);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement