diff -cr --new-file linux-0.07pl4/Makefile linux-0.08/Makefile *** linux-0.07pl4/Makefile Sat Mar 19 15:12:51 1994 --- linux-0.08/Makefile Tue Mar 22 16:34:04 1994 *************** *** 6,13 **** # License. See the file "README.legal" in the main directory of this archive # for more details. ! VERSION = 0.07 ! PATCHLEVEL = 4 ALPHA = all: Version vmlinux --- 6,13 ---- # License. See the file "README.legal" in the main directory of this archive # for more details. ! VERSION = 0.08 ! PATCHLEVEL = 0 ALPHA = all: Version vmlinux *************** *** 54,67 **** include MakeVars ! ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o m68k/arch.o # net/net.o FILESYSTEMS =fs/filesystems.a DRIVERS =drivers/block/block.a \ drivers/char/char.a # drivers/net/net.a \ # ibcs/ibcs.o LIBS =lib/lib.a ! SUBDIRS =kernel drivers mm fs ipc m68k lib # net ifdef CONFIG_SCSI DRIVERS := $(DRIVERS) drivers/scsi/scsi.a --- 54,67 ---- include MakeVars ! ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o m68k/arch.o net/net.o FILESYSTEMS =fs/filesystems.a DRIVERS =drivers/block/block.a \ drivers/char/char.a # drivers/net/net.a \ # ibcs/ibcs.o LIBS =lib/lib.a ! SUBDIRS =kernel drivers mm fs ipc m68k lib net ifdef CONFIG_SCSI DRIVERS := $(DRIVERS) drivers/scsi/scsi.a *************** *** 97,103 **** endif Version: dummy ! $(RM) tools/version.h config: $(CONFIG_SHELL) Configure $(OPTS) < config.in --- 97,103 ---- endif Version: dummy ! $(RM) $(RMFLAGS) tools/version.h config: $(CONFIG_SHELL) Configure $(OPTS) < config.in *************** *** 111,123 **** set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done bootstrap: $(BOOTOBJS) ! $(HOSTCC) $(HOSTFLAGS) -o tmp $(BOOTOBJS) ! ifdef CONFIG_AMIGA ! blink from tmp to bootstrap chip ! $(RM) tmp ! else ! mv tmp bootstrap ! endif tools/./version.h: tools/version.h --- 111,117 ---- set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done bootstrap: $(BOOTOBJS) ! $(HOSTCC) $(HOSTFLAGS) -o $@ $(BOOTOBJS) tools/./version.h: tools/version.h *************** *** 158,164 **** $(LIBS) \ -o vmlinux.amigados ! m68k/head.o: m68k/head.S m68k/assyms.h m68k/assyms.h: dummy make -C m68k assyms.h --- 152,158 ---- $(LIBS) \ -o vmlinux.amigados ! m68k/head.o: m68k/head.S #m68k/assyms.h m68k/assyms.h: dummy make -C m68k assyms.h diff -cr --new-file linux-0.07pl4/README.legal linux-0.08/README.legal *** linux-0.07pl4/README.legal Mon Sep 13 18:32:06 1993 --- linux-0.08/README.legal Sat Mar 19 12:11:39 1994 *************** *** 1,4 **** ! Legal information about the Amiga Linux software package All files contained in this archive are copyrighted by one or more person. They are not in the public domain. --- 1,4 ---- ! Legal information about the Linux/68k software package All files contained in this archive are copyrighted by one or more person. They are not in the public domain. *************** *** 6,50 **** Most of the files are copyrighted by Linus Torvalds, the original writer of Linux for IBM PC clone systems. Some parts are copyrighted by other IBM PC linux developers. Other parts are copyrighted by ! Amiga Linux developers. This package is subject to the terms and conditions of the GNU General Public License. A copy of this license may be found in the file named "COPYING" which should be in the same directory as this file. If the file has been omitted, you may obtain it by writing to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Portions of this product are derived from software copyrighted by the - University of California, Berkeley and its contributors. These - portions are subject to and marked by the following notice: - - ---------------------------------------------------------------------- - Copyright (c) 1990 The Regents of the University of California. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by the University of - California, Berkeley and its contributors. - 4. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. --- 6,15 ---- Most of the files are copyrighted by Linus Torvalds, the original writer of Linux for IBM PC clone systems. Some parts are copyrighted by other IBM PC linux developers. Other parts are copyrighted by ! Linux/68k developers. This package is subject to the terms and conditions of the GNU General Public License. A copy of this license may be found in the file named "COPYING" which should be in the same directory as this file. If the file has been omitted, you may obtain it by writing to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. diff -cr --new-file linux-0.07pl4/amiga/Makefile linux-0.08/amiga/Makefile *** linux-0.07pl4/amiga/Makefile Sun Aug 1 09:25:27 1993 --- linux-0.08/amiga/Makefile Sun Feb 6 15:41:00 1994 *************** *** 8,14 **** include ../MakeVars ! OBJS = config.o amikeyb.o amiints.o amicon.o font.o amipart.o amiga.o: $(OBJS) $(LD) -r -o amiga.o $(OBJS) --- 8,14 ---- include ../MakeVars ! OBJS = config.o amikeyb.o amiints.o amicon.o font.o amipart.o chipram.o amiga.o: $(OBJS) $(LD) -r -o amiga.o $(OBJS) diff -cr --new-file linux-0.07pl4/amiga/amicon.c linux-0.08/amiga/amicon.c *** linux-0.07pl4/amiga/amicon.c Sun Jan 30 11:35:26 1994 --- linux-0.08/amiga/amicon.c Wed Mar 16 16:44:52 1994 *************** *** 46,52 **** #define COP_LIST_ENTS 30 #define MEM_REQ ((SCR_WIDTH/8) * SCR_HEIGHT) ! #define COP_MEM_REQ (COPENTS*4*2) #define DIWSTRT_V (0x18 + (SCR_MAX_HEIGHT - SCR_HEIGHT)/4) #define DIWSTRT_H (0x71 + (SCR_MAX_WIDTH - SCR_WIDTH)/4) --- 46,53 ---- #define COP_LIST_ENTS 30 #define MEM_REQ ((SCR_WIDTH/8) * SCR_HEIGHT) ! #define COP_MEM_REQ (COP_LIST_ENTS*4*2) ! #define SPR_MEM_REQ (24) #define DIWSTRT_V (0x18 + (SCR_MAX_HEIGHT - SCR_HEIGHT)/4) #define DIWSTRT_H (0x71 + (SCR_MAX_WIDTH - SCR_WIDTH)/4) *************** *** 124,130 **** long scrmem = (long)disp[unit].bitplane; if (shf) ! scrmem += vc_cons[unit].cols; /* 1-2: Store bitplane address in BPL0PTx */ *cop++ = CUSTOM_OFS(bplpt[0]); --- 125,131 ---- long scrmem = (long)disp[unit].bitplane; if (shf) ! scrmem += vc_cons[unit].vc_cols; /* 1-2: Store bitplane address in BPL0PTx */ *cop++ = CUSTOM_OFS(bplpt[0]); *************** *** 160,165 **** --- 161,167 ---- { int i; int unit = conp - vc_cons; + void *chipptr; /* set up the display defaults */ disp[unit].scr_height = SCR_HEIGHT; *************** *** 177,185 **** disp[unit].bgcol = BG_COLOR; disp[unit].crsrcol = CURSOR_COLOR; ! conp->cols = SCR_WIDTH / fontwidth; ! conp->rows = SCR_HEIGHT / fontheight; /* locate the copper list */ disp[unit].coplist1 = (ushort *)COP_LIST_BASE; disp[unit].coplist2 = (ushort *)(COP_LIST_BASE + COP_LIST_ENTS * 4); --- 179,188 ---- disp[unit].bgcol = BG_COLOR; disp[unit].crsrcol = CURSOR_COLOR; ! conp->vc_cols = SCR_WIDTH / fontwidth; ! conp->vc_rows = SCR_HEIGHT / fontheight; + #if 0 /* locate the copper list */ disp[unit].coplist1 = (ushort *)COP_LIST_BASE; disp[unit].coplist2 = (ushort *)(COP_LIST_BASE + COP_LIST_ENTS * 4); *************** *** 190,195 **** --- 193,214 ---- /* locate the sprite data */ cursor = (ushort *)CURSOR_BASE; /* bitplane may be up to 704x480 */ dummy = (ushort *)(CURSOR_BASE + 12); + #else + chipptr = amiga_chip_alloc (COP_MEM_REQ + MEM_REQ + SPR_MEM_REQ); + + /* locate the copper list */ + disp[unit].coplist1 = (ushort *)chipptr; + disp[unit].coplist2 = (ushort *)((unsigned long)chipptr + + COP_LIST_ENTS * 4); + + /* locate the bitplane */ + disp[unit].bitplane = (u_char *)((unsigned long)disp[unit].coplist2 + + COP_LIST_ENTS * 4); + + /* locate the sprite data */ + cursor = (ushort *)((unsigned long)disp[unit].bitplane + MEM_REQ); + dummy = cursor + 6; + #endif /* copy the sprite data into Chip mem */ for (i=0; i<6; i++) *************** *** 200,206 **** dummy[i] = 0x0000; /* set the modulo */ ! custom.bpl1mod = conp->cols; /* set the display mode */ custom.bplcon0 = disp[unit].mode; --- 219,225 ---- dummy[i] = 0x0000; /* set the modulo */ ! custom.bpl1mod = conp->vc_cols; /* set the display mode */ custom.bplcon0 = disp[unit].mode; *************** *** 375,389 **** /* *(long *)cursor = 0;*/ } else { vs = (disp[unit].diwstrt >> 8) + ! ((conp->cury + 1) * fontheight) / 2 - 1; hs = (disp[unit].diwstrt & 0x00ff) + ! (conp->curx * fontwidth) / 2 - 1; *(long *)cursor = (vs << 24) + ((hs & 0x000001fe) << 15) + ! (((vs+1) & 0x000000ff) << 8) + (vs & 0x00000100) + ! (((vs+1) & 0x00000100) >> 1) + (hs & 0x00000001); ! conp->cursorx = conp->curx; ! conp->cursory = conp->cury; } return 0; --- 394,408 ---- /* *(long *)cursor = 0;*/ } else { vs = (disp[unit].diwstrt >> 8) + ! ((conp->vc_y + 1) * fontheight) / 2 - 1; hs = (disp[unit].diwstrt & 0x00ff) + ! (conp->vc_x * fontwidth) / 2 - 1; *(long *)cursor = (vs << 24) + ((hs & 0x000001fe) << 15) + ! (((vs+1) & 0x000000ff) << 8) + ((vs & 0x00000100) >> 6) + ! (((vs+1) & 0x00000100) >> 7) + (hs & 0x00000001); ! /* conp->cursorx = conp->vc_x; ! conp->cursory = conp->vc_y;*/ } return 0; *************** *** 398,406 **** if (dir == SM_UP) { dy = sy - count; ! height = conp->rows - sy; for (i = 0; i < height; i++) ! amicon_bmove (conp, sy + i, 0, dy + i, 0, 1, conp->cols); } return 0; --- 417,425 ---- if (dir == SM_UP) { dy = sy - count; ! height = conp->vc_rows - sy; for (i = 0; i < height; i++) ! amicon_bmove (conp, sy + i, 0, dy + i, 0, 1, conp->vc_cols); } return 0; *************** *** 418,423 **** struct consw ami_con = { amicon_init, amicon_deinit, amicon_clear, amicon_putc, ! amicon_cursor, amicon_scroll, amicon_switch }; --- 437,442 ---- struct consw ami_con = { amicon_init, amicon_deinit, amicon_clear, amicon_putc, ! amicon_cursor, amicon_scroll, amicon_bmove, amicon_switch }; diff -cr --new-file linux-0.07pl4/amiga/amikeyb.c linux-0.08/amiga/amikeyb.c *** linux-0.07pl4/amiga/amikeyb.c Sun Jan 30 11:34:45 1994 --- linux-0.08/amiga/amikeyb.c Tue Mar 15 13:56:30 1994 *************** *** 16,21 **** --- 16,22 ---- #include #include #include + #include #include #include *************** *** 71,76 **** --- 72,89 ---- /* 7C-7F */ KB_NONE, KB_NONE, KB_NONE, KB_NONE }; + static unsigned char rep_scancode; + static void amikeyb_rep (unsigned long ignore); + static struct timer_list amikeyb_rep_timer = {NULL, 0, 0, amikeyb_rep}; + + static void amikeyb_rep (unsigned long ignore) + { + unsigned char scancode = rep_scancode; + amikeyb_rep_timer.expires = HZ/20; + add_timer(&amikeyb_rep_timer); + process_scancode (scancode); + } + static void keyboard_interrupt(struct intframe *fp, void *data) { unsigned char scancode, break_flag; *************** *** 100,108 **** /* if the key is CAPS, fake a press/release. */ process_scancode (ami_kmap[AMIKEY_CAPS]); process_scancode (BREAK_MASK | ami_kmap[AMIKEY_CAPS]); ! } else process_scancode (break_flag | ami_kmap[scancode]); ! return; } --- 113,131 ---- /* if the key is CAPS, fake a press/release. */ process_scancode (ami_kmap[AMIKEY_CAPS]); process_scancode (BREAK_MASK | ami_kmap[AMIKEY_CAPS]); ! } else { ! /* handle repeat */ ! if (break_flag) { ! del_timer(&amikeyb_rep_timer); ! rep_scancode = 0; ! } else { ! del_timer(&amikeyb_rep_timer); ! rep_scancode = break_flag | ami_kmap[scancode]; ! amikeyb_rep_timer.expires = (HZ*2)/3; ! add_timer(&amikeyb_rep_timer); ! } process_scancode (break_flag | ami_kmap[scancode]); ! } return; } diff -cr --new-file linux-0.07pl4/amiga/chipram.c linux-0.08/amiga/chipram.c *** linux-0.07pl4/amiga/chipram.c Wed Dec 31 19:00:00 1969 --- linux-0.08/amiga/chipram.c Sat Feb 19 06:17:14 1994 *************** *** 0 **** --- 1,131 ---- + #include + #include + #include + #include + + struct chip_desc { + unsigned first : 1; + unsigned last : 1; + unsigned alloced : 1; + unsigned length : 24; + }; + + #define DP(ptr) ((struct chip_desc *)(ptr)) + + static unsigned long chipsize; + + void amiga_chip_init (void) + { + struct chip_desc *dp; + + chipsize = boot_info.bi_amiga.chip_size; + + /* initialize start boundary */ + dp = DP(chipaddr); + dp->first = 1; + dp->alloced = 0; + dp->length = chipsize - 2*sizeof(*dp); + + /* initialize end boundary */ + dp = DP(chipaddr + chipsize) - 1; + dp->last = 1; + dp->alloced = 0; + dp->length = chipsize - 2*sizeof(*dp); + + #ifdef DEBUG + printk ("chipram end boundary is %p, length is %d\n", dp, + dp->length); + #endif + } + + void *amiga_chip_alloc (long size) + { + /* last chunk */ + struct chip_desc *dp; + void *ptr; + + /* round off */ + size = (size + 3) & ~3; + + #ifdef DEBUG + printk ("chip_alloc: allocate %ld bytes\n", size); + #endif + + /* + * get pointer to descriptor for last chunk by + * going backwards from end chunk + */ + dp = DP(chipaddr + chipsize) - 1; + dp = DP((unsigned long)dp - dp->length) - 1; + + while ((dp->alloced || dp->length < size) + && !dp->first) + dp = DP ((unsigned long)dp - dp[-1].length) - 2; + + if (dp->alloced || dp->length < size) { + printk ("no chipmem available for %ld allocation\n", size); + return NULL; + } + + if (dp->length < (size + 2*sizeof(*dp))) { + /* length too small to split; allocate the whole thing */ + dp->alloced = 1; + ptr = (void *)(dp+1); + dp = DP((unsigned long)ptr + dp->length); + dp->alloced = 1; + #ifdef DEBUG + printk ("chip_alloc: no split\n"); + #endif + } else { + /* split the extent; use the end part */ + long newsize = dp->length - (2*sizeof(*dp) + size); + + #ifdef DEBUG + printk ("chip_alloc: splitting %d to %ld\n", dp->length, + newsize); + #endif + dp->length = newsize; + dp = DP((unsigned long)(dp+1) + newsize); + dp->first = dp->last = 0; + dp->alloced = 0; + dp->length = newsize; + dp++; + dp->first = dp->last = 0; + dp->alloced = 1; + dp->length = size; + ptr = (void *)(dp+1); + dp = DP((unsigned long)ptr + size); + dp->alloced = 1; + dp->length = size; + } + + #ifdef DEBUG + printk ("chip_alloc: returning %p\n", ptr); + #endif + return ptr; + } + + void amiga_chip_free (void *ptr) + { + struct chip_desc *sdp = DP(ptr) - 1, *dp2; + struct chip_desc *edp = DP((unsigned long)ptr + sdp->length); + + /* deallocate the chunk */ + sdp->alloced = edp->alloced = 0; + + /* check if we should merge with the previous chunk */ + if (!sdp->first && !sdp[-1].alloced) { + dp2 = DP((unsigned long)sdp - sdp[-1].length) - 2; + dp2->length += sdp->length + 2*sizeof(*sdp); + edp->length = dp2->length; + sdp = dp2; + } + + /* check if we should merge with the following chunk */ + if (!edp->last && !edp[1].alloced) { + dp2 = DP((unsigned long)edp + edp[1].length) + 2; + dp2->length += edp->length + 2*sizeof(*sdp); + sdp->length = dp2->length; + edp = dp2; + } + } diff -cr --new-file linux-0.07pl4/amiga/config.c linux-0.08/amiga/config.c *** linux-0.07pl4/amiga/config.c Sun Jan 30 11:35:06 1994 --- linux-0.08/amiga/config.c Sun Mar 13 11:01:04 1994 *************** *** 12,17 **** --- 12,18 ---- * Miscellaneous Amiga stuff */ + #include #include #include #include *************** *** 27,32 **** --- 28,34 ---- caddr_t CustomBase; caddr_t CiaABase; caddr_t CiaBBase; + caddr_t ChipRamBase; #endif void amiga_sched_init (isrfunc timer_routine) *************** *** 161,164 **** --- 163,180 ---- ; } } + } + + void dbprintf(const char *fmt , ...) + { + static char buf[1024]; + va_list args; + extern void console_print (const char *str); + extern int vsprintf(char * buf, const char * fmt, va_list args); + + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + + console_print (buf); } diff -cr --new-file linux-0.07pl4/config.in linux-0.08/config.in *** linux-0.07pl4/config.in Sat Mar 19 14:28:52 1994 --- linux-0.08/config.in Tue Mar 29 18:15:07 1994 *************** *** 9,15 **** bool 'Atari support' CONFIG_ATARI n bool 'Macintosh support' CONFIG_MAC n bool '68040 floating point software package' CONFIG_FPSP_040 y ! bool 'Normal harddisk support' CONFIG_BLK_DEV_HD n bool 'TCP/IP networking' CONFIG_INET n bool 'Limit memory to low 16MB' CONFIG_MAX_16M n * --- 9,16 ---- bool 'Atari support' CONFIG_ATARI n bool 'Macintosh support' CONFIG_MAC n bool '68040 floating point software package' CONFIG_FPSP_040 y ! bool 'PC IDE harddisk support' CONFIG_BLK_DEV_HD n ! bool 'Amiga Gayle IDE harddisk support' CONFIG_AMIGA_IDE y bool 'TCP/IP networking' CONFIG_INET n bool 'Limit memory to low 16MB' CONFIG_MAX_16M n * *************** *** 84,99 **** * bool 'Standard (minix) fs support' CONFIG_MINIX_FS y bool 'Extended fs support' CONFIG_EXT_FS n ! bool 'Second extended fs support' CONFIG_EXT2_FS n bool 'xiafs filesystem support' CONFIG_XIA_FS n bool 'msdos fs support' CONFIG_MSDOS_FS n ! bool '/proc filesystem support' CONFIG_PROC_FS n bool 'NFS filesystem support' CONFIG_NFS_FS n bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n bool 'Amiga FFS filesystem support' CONFIG_AFFS_FS y * * character devices * bool 'Keyboard meta-key sends ESC-prefix' CONFIG_KBD_META n bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML y * --- 85,102 ---- * bool 'Standard (minix) fs support' CONFIG_MINIX_FS y bool 'Extended fs support' CONFIG_EXT_FS n ! bool 'Second extended fs support' CONFIG_EXT2_FS y bool 'xiafs filesystem support' CONFIG_XIA_FS n bool 'msdos fs support' CONFIG_MSDOS_FS n ! bool '/proc filesystem support' CONFIG_PROC_FS y bool 'NFS filesystem support' CONFIG_NFS_FS n bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n bool 'Amiga FFS filesystem support' CONFIG_AFFS_FS y * * character devices * + bool 'Parallel printer support' CONFIG_PRINTER y + bool 'Amiga mouse support' CONFIG_AMIGAMOUSE y bool 'Keyboard meta-key sends ESC-prefix' CONFIG_KBD_META n bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML y * diff -cr --new-file linux-0.07pl4/drivers/block/Makefile linux-0.08/drivers/block/Makefile *** linux-0.07pl4/drivers/block/Makefile Sun Dec 12 08:56:02 1993 --- linux-0.08/drivers/block/Makefile Sun Mar 27 07:36:18 1994 *************** *** 7,19 **** # for more details. include ../../MakeVars ! ! SUBDIRS = scsi OBJS := ll_rw_blk.o floppy.o ramdisk.o genhd.o SRCS := ll_rw_blk.c floppy.c ramdisk.c genhd.c - ifdef CONFIG_CDU31A OBJS := $(OBJS) cdu31a.o SRCS := $(SRCS) cdu31a.c --- 7,17 ---- # for more details. include ../../MakeVars ! include ../../.config OBJS := ll_rw_blk.o floppy.o ramdisk.o genhd.o SRCS := ll_rw_blk.c floppy.c ramdisk.c genhd.c ifdef CONFIG_CDU31A OBJS := $(OBJS) cdu31a.o SRCS := $(SRCS) cdu31a.c *************** *** 29,39 **** SRCS := $(SRCS) hd.c endif ifdef CONFIG_BLK_DEV_XD OBJS := $(OBJS) xd.o SRCS := $(SRCS) xd.c endif ! all: block.a block.a: $(OBJS) --- 27,42 ---- SRCS := $(SRCS) hd.c endif + ifdef CONFIG_AMIGA_IDE + OBJS := $(OBJS) amihd.o + SRCS := $(SRCS) amihd.c + endif + ifdef CONFIG_BLK_DEV_XD OBJS := $(OBJS) xd.o SRCS := $(SRCS) xd.c endif ! all: block.a block.a: $(OBJS) diff -cr --new-file linux-0.07pl4/drivers/block/amihd.c linux-0.08/drivers/block/amihd.c *** linux-0.07pl4/drivers/block/amihd.c Wed Dec 31 19:00:00 1969 --- linux-0.08/drivers/block/amihd.c Sun Mar 27 07:27:22 1994 *************** *** 0 **** --- 1,812 ---- + /* + * linux/drivers/block/amihd.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + */ + + /* + * This is the low-level hd interrupt support. It traverses the + * request-list, using interrupts to jump between functions. As + * all the functions are called within interrupts, we may not + * sleep. Special care is recommended. + * + * modified by Drew Eckhardt to check nr of hd's from the CMOS. + * + * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug + * in the early extended-partition checks and added DM partitions + * + * + * Modified 1994 for A4000/40 IDE controller support by Torsten Ebeling + */ + + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + + #include + #include + #include + + #define MAJOR_NR HD_MAJOR + #include "blk.h" + + static int revalidate_hddisk(int, int); + + #define MAX_ERRORS 16 /* Max read/write errors/sector */ + #define RESET_FREQ 8 /* Reset controller every 8th retry */ + #define RECAL_FREQ 4 /* Recalibrate every 4th retry */ + #define MAX_HD 2 + + static void recal_intr(void); + static void bad_rw_intr(void); + + static char recalibrate[ MAX_HD ] = { 0, }; + static int access_count[MAX_HD] = {0, }; + static char busy[MAX_HD] = {0, }; + static struct wait_queue * busy_wait = NULL; + + static int reset = 0; + static int hd_error = 0; + + /* + * This struct defines the HD's and their types. + */ + struct hd_i_struct { + unsigned int head,sect,cyl,wpcom,lzone,ctl; + }; + struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} }; + static int NR_HD = 0; + + static struct hd_struct hd[MAX_HD<<6]={{0,0},}; + static int hd_sizes[MAX_HD<<6] = {0, }; + static int hd_blocksizes[MAX_HD<<6] = {0, }; + + #define HD_ID_RETRIES 500000 + + #define port_read(port, buf, nr) \ + __asm__ __volatile__ \ + ("move.l %0,a0; \ + move.l %1,a1; \ + move.l %2,d6; \ + 1:move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + move.w a0@,a1@+; \ + dbra d6,1b" : : "i" (port), "g" (buf), "g" (nr) : "a0", "a1", "d6"); + + #define port_write(port, buf, nr) \ + __asm__ __volatile__ \ + ("move.l %0,a0; \ + move.l %1,a1; \ + move.l %2,d6; \ + 1:move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + move.w a1@+,a0@; \ + dbra d6,1b" : : "i" (port), "g" (buf), "g" (nr) : "a0", "a1", "d6"); + + void hd_setup(char *str, int *ints) + { + int hdind = 0; + + if (ints[0] != 3) + return; + if (hd_info[0].head != 0) + hdind=1; + hd_info[hdind].head = ints[2]; + hd_info[hdind].sect = ints[3]; + hd_info[hdind].cyl = ints[1]; + hd_info[hdind].wpcom = 0; + hd_info[hdind].lzone = ints[1]; + hd_info[hdind].ctl = 0; + } + + static int win_result(void) + { + int i=inb_p(HD_STATUS); + + if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)) + == (READY_STAT | SEEK_STAT)) { + hd_error = 0; + return 0; /* ok */ + } + printk("HD: win_result: status = 0x%02x\n",i); + if (i&1) { + hd_error = inb(HD_ERROR); + printk("HD: win_result: error = 0x%02x\n",hd_error); + } + return 1; + } + + static int controller_busy(void); + static int status_ok(void); + + static int controller_ready(unsigned int drive, unsigned int head) + { + int retry = 100; + + do { + if (controller_busy() & BUSY_STAT) + return 0; + outb_p(0xA0 | (drive<<4) | head, HD_CURRENT); + if (status_ok()) + return 1; + } while (--retry); + return 0; + } + + static int status_ok(void) + { + unsigned char status = inb_p(HD_STATUS); + + if (status & BUSY_STAT) + return 1; + if (status & WRERR_STAT) + return 0; + if (!(status & READY_STAT)) + return 0; + if (!(status & SEEK_STAT)) + return 0; + return 1; + } + + static int controller_busy(void) + { + int retries = 100000; + unsigned char status; + + do { + status = inb_p(HD_STATUS); + } while ((status & BUSY_STAT) && --retries); + return status; + } + + 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)) + { + if (drive>1 || head>15) + panic("Trying to write bad sector"); + if (reset) + return; + if (!controller_ready(drive, head)) { + reset = 1; + return; + } + SET_INTR(intr_addr); + outb(hd_info[drive].ctl,HD_CMD); + outb_p(hd_info[drive].wpcom>>2,HD_PRECOMP); + outb_p(nsect,HD_NSECTOR); + outb_p(sect,HD_SECTOR); + outb_p(cyl,HD_LCYL); + outb_p(cyl>>8,HD_HCYL); + outb_p(0xA0|(drive<<4)|head,HD_CURRENT); + outb_p(cmd,HD_COMMAND); + } + + static int drive_busy(void) + { + unsigned int i; + unsigned char c; + + for (i = 0; i < 500000 ; i++) { + c = inb_p(HD_STATUS); + c &= (BUSY_STAT | READY_STAT | SEEK_STAT); + if (c == (READY_STAT | SEEK_STAT)) + return 0; + } + printk("HD controller times out, status = 0x%02x\n",c); + return 1; + } + + static void reset_controller(void) + { + int i; + + printk("HD-controller reset\n"); + outb(4,HD_CMD); + for(i = 0; i < 1000; i++) nop(); + outb(hd_info[0].ctl & 0x0f ,HD_CMD); + if (drive_busy()) + printk("HD-controller still busy\n"); + if ((hd_error = inb(HD_ERROR)) != 1) + printk("HD-controller reset failed: %02x\n",hd_error); + } + + static void reset_hd(void) + { + static int i; + + repeat: + if (reset) { + reset = 0; + i = -1; + reset_controller(); + } else if (win_result()) { + bad_rw_intr(); + if (reset) + goto repeat; + } + i++; + if (i < NR_HD) { + hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1, + hd_info[i].cyl,WIN_SPECIFY,&reset_hd); + if (reset) + goto repeat; + } else + do_hd_request(); + } + + /* + * Ok, don't know what to do with the unexpected interrupts: on some machines + * doing a reset and a retry seems to result in an eternal loop. Right now I + * ignore it, and just set the timeout. + */ + void unexpected_hd_interrupt(void) + { + printk("Unexpected HD interrupt\n"); + SET_TIMER; + } + + /* + * bad_rw_intr() now tries to be a bit smarter and does things + * according to the error returned by the controller. + * -Mika Liljeberg (liljeber@cs.Helsinki.FI) + */ + static void bad_rw_intr(void) + { + int dev; + + if (!CURRENT) + return; + dev = MINOR(CURRENT->dev) >> 6; + if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) { + end_request(0); + recalibrate[dev] = 1; + } else if (CURRENT->errors % RESET_FREQ == 0) + reset = 1; + else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0) + recalibrate[dev] = 1; + /* Otherwise just retry */ + } + + static inline int wait_DRQ(void) + { + int retries = 100000; + + while (--retries > 0) + if (inb_p(HD_STATUS) & DRQ_STAT) + return 0; + return -1; + } + + #define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT) + #define STAT_OK (READY_STAT | SEEK_STAT) + + static void read_intr(void) + { + int i; + int retries = 100000; + + do { + i = (unsigned) inb_p(HD_STATUS); + if (i & BUSY_STAT) + continue; + if ((i & STAT_MASK) != STAT_OK) + break; + if (i & DRQ_STAT) + goto ok_to_read; + } while (--retries > 0); + printk("HD: read_intr: status = 0x%02x\n",i); + if (i & ERR_STAT) { + hd_error = (unsigned) inb(HD_ERROR); + printk("HD: read_intr: error = 0x%02x\n",hd_error); + } + bad_rw_intr(); + do_hd_request(); + return; + ok_to_read: + port_read(HD_DATA,CURRENT->buffer,15); + CURRENT->errors = 0; + CURRENT->buffer += 512; + CURRENT->sector++; + i = --CURRENT->nr_sectors; + --CURRENT->current_nr_sectors; + #ifdef DEBUG + printk("hd%d : sector = %d, %d remaining to buffer = %08x\n", + MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT-> + buffer); + #endif + if (!i || (CURRENT->bh && !SUBSECTOR(i))) + end_request(1); + if (i > 0) { + SET_INTR(&read_intr); + return; + } + (void) inb_p(HD_STATUS); + #if (HD_DELAY > 0) + last_req = read_timer(); + #endif + do_hd_request(); + return; + } + + static void write_intr(void) + { + int i; + int retries = 100000; + + do { + i = (unsigned) inb_p(HD_STATUS); + if (i & BUSY_STAT) + continue; + if ((i & STAT_MASK) != STAT_OK) + break; + if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT)) + goto ok_to_write; + } while (--retries > 0); + printk("HD: write_intr: status = 0x%02x\n",i); + if (i & ERR_STAT) { + hd_error = (unsigned) inb(HD_ERROR); + printk("HD: write_intr: error = 0x%02x\n",hd_error); + } + bad_rw_intr(); + do_hd_request(); + return; + ok_to_write: + CURRENT->sector++; + i = --CURRENT->nr_sectors; + --CURRENT->current_nr_sectors; + CURRENT->buffer += 512; + if (!i || (CURRENT->bh && !SUBSECTOR(i))) + end_request(1); + if (i > 0) { + SET_INTR(&write_intr); + port_write(HD_DATA,CURRENT->buffer,15); + } else { + do_hd_request(); + } + return; + } + + static void recal_intr(void) + { + if (win_result()) + bad_rw_intr(); + do_hd_request(); + } + + /* + * This is another of the error-routines I don't know what to do with. The + * best idea seems to just set reset, and start all over again. + */ + static void hd_times_out(void) + { + DEVICE_INTR = NULL; + reset = 1; + if (!CURRENT) + return; + printk("HD timeout\n"); + if (++CURRENT->errors >= MAX_ERRORS) { + #ifdef DEBUG + printk("hd : too many errors.\n"); + #endif + end_request(0); + } + + do_hd_request(); + } + + /* + * The driver has been modified to enable interrupts a bit more: in order to + * do this we first (a) disable the timeout-interrupt and (b) clear the + * device-interrupt. This way the interrupts won't mess with out code (the + * worst that can happen is that an unexpected HD-interrupt comes in and + * sets the "reset" variable and starts the timer) + */ + static void do_hd_request(void) + { + unsigned int block,dev; + unsigned int sec,head,cyl,track; + unsigned int nsect; + + if (CURRENT && CURRENT->dev < 0) return; + + if (DEVICE_INTR) + return; + repeat: + timer_active &= ~(1<dev); + block = CURRENT->sector; + nsect = CURRENT->nr_sectors; + if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) { + #ifdef DEBUG + printk("hd%d : attempted read for sector %d past end of device at sector %d.\n", + block, hd[dev].nr_sects); + #endif + end_request(0); + goto repeat; + } + block += hd[dev].start_sect; + dev >>= 6; + sec = block % hd_info[dev].sect + 1; + track = block / hd_info[dev].sect; + head = track % hd_info[dev].head; + cyl = track / hd_info[dev].head; + #ifdef DEBUG + printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n", + dev, cyl, head, sec, CURRENT->buffer); + #endif + if (reset) { + int i; + + for (i=0; i < NR_HD; i++) + recalibrate[i] = 1; + reset_hd(); + return; + } + if (recalibrate[dev]) { + recalibrate[dev] = 0; + hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr); + if (reset) + goto repeat; + return; + } + if (CURRENT->cmd == WRITE) { + hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr); + if (reset) + goto repeat; + if (wait_DRQ()) { + printk("HD: do_hd_request: no DRQ\n"); + bad_rw_intr(); + goto repeat; + } + port_write(HD_DATA,CURRENT->buffer,15); + return; + } + if (CURRENT->cmd == READ) { + hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr); + if (reset) + goto repeat; + return; + } + panic("unknown hd-command"); + } + + static int hd_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) + { + struct hd_geometry *loc = (struct hd_geometry *) arg; + int dev, err; + + if (!inode) + return -EINVAL; + dev = MINOR(inode->i_rdev) >> 6; + if (dev >= NR_HD) + return -EINVAL; + switch (cmd) { + case HDIO_GETGEO: + if (!loc) return -EINVAL; + err = verify_area(VERIFY_WRITE, loc, sizeof(*loc)); + if (err) + return err; + put_fs_byte(hd_info[dev].head, + (char *) &loc->heads); + put_fs_byte(hd_info[dev].sect, + (char *) &loc->sectors); + put_fs_word(hd_info[dev].cyl, + (short *) &loc->cylinders); + put_fs_long(hd[MINOR(inode->i_rdev)].start_sect, + (long *) &loc->start); + return 0; + case BLKGETSIZE: /* Return device size */ + if (!arg) return -EINVAL; + err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); + if (err) + return err; + put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects, + (long *) arg); + return 0; + case BLKFLSBUF: + if(!suser()) return -EACCES; + if(!inode->i_rdev) return -EINVAL; + fsync_dev(inode->i_rdev); + invalidate_buffers(inode->i_rdev); + return 0; + + case BLKRRPART: /* Re-read partition tables */ + return revalidate_hddisk(inode->i_rdev, 1); + RO_IOCTLS(inode->i_rdev,arg); + default: + return -EINVAL; + } + } + + static int hd_open(struct inode * inode, struct file * filp) + { + int target; + target = DEVICE_NR(MINOR(inode->i_rdev)); + + while (busy[target]) + sleep_on(&busy_wait); + access_count[target]++; + return 0; + } + + /* + * Releasing a block device means we sync() it, so that it can safely + * be forgotten about... + */ + static void hd_release(struct inode * inode, struct file * file) + { + int target; + sync_dev(inode->i_rdev); + + target = DEVICE_NR(MINOR(inode->i_rdev)); + access_count[target]--; + + } + + static void hd_geninit(void); + + static struct gendisk hd_gendisk = { + MAJOR_NR, /* Major number */ + "hd", /* Major name */ + 6, /* Bits to shift to get real from partition */ + 1 << 6, /* Number of partitions per real */ + MAX_HD, /* maximum number of real */ + hd_geninit, /* init function */ + hd, /* hd struct */ + hd_sizes, /* block sizes */ + 0, /* number */ + (void *) hd_info, /* internal */ + NULL /* next */ + }; + + /*te****************************************************************** + * + * hd_interrupt routine + * Test, if this is a harddisk interrupt and call + * the irq handler + * Otherwise ignore this interrupt. + * + ********************************************************/ + static void hd_interrupt (struct intframe *fp, void *data) + { + void (*hd_irq_handler)(void) = DEVICE_INTR; + + /* Test, if this is a harddisk interrupt. MSB(0xdd2030) = 1 */ + if (inb (HD_IRQ_TEST) & 0x80) + { + DEVICE_INTR = NULL; + timer_active &= ~(1 << HD_TIMER); + + if (!hd_irq_handler) + hd_irq_handler = unexpected_hd_interrupt; + hd_irq_handler (); + + return; + } + } + + /*te****************************************************************** + * + * hd_geninit + * Scan and initialize all connected harddisks. + * + ***************************/ + static void hd_geninit (void) + { + int i; + int drive; + unsigned short Identify [256]; + unsigned char drive_found; + + printk ("Probing harddisk(s):\n"); + NR_HD = 0; + + /* Test, if it's an A4000 or an A1200 */ + if ((boot_info.bi_amiga.model != AMI_4000) && (boot_info.bi_amiga.model != AMI_1200)) + { + printk ("IDE harddisk controller not present.\n"); + hd_gendisk.nr_real = NR_HD; + return; + } + + outb (IDE_DISABLE_IRQ, HD_CMD); /* Disable HD-interrupt */ + cli (); /* Disable interrupts */ + + for (drive=0; drive<2; drive++) + { + if (drive_busy ()) + { + printk ("hd: Can't access harddisk controller.\n"); + NR_HD = 0; + break; + } + + /* select drive */ + outb_p ((unsigned char) (0xA0 | (drive<<4)), HD_CURRENT); + + /* Set identify command */ + outb_p (WIN_IDENTIFY, HD_COMMAND); + + drive_found = 0; + /* Test, if ready to read */ + for (i=0; i> 8); + + hd_info[drive].cyl = Identify [1]; + hd_info[drive].head = Identify [3]; + hd_info[drive].wpcom = 0; + hd_info[drive].ctl = 0; + hd_info[drive].lzone = Identify [1]; + hd_info[drive].sect = Identify [6]; + NR_HD++; + Identify [47] = 0x0000; + printk ("hd%d: %s\n", drive, (unsigned char *)&Identify [27]); + printk (" cyl %d, sector %d, head %d.\n", + hd_info[drive].cyl, + hd_info[drive].sect, + hd_info[drive].head); + } + else + printk ("hd%d not found.\n", drive); + } + sti (); /* Enable interrupts */ + + /* Add the interrupt handler */ + if (NR_HD) + if (!add_isr (IRQ_AMIGA_PORTS, hd_interrupt, 0, NULL)) + { + printk ("HD: Can't add interrupt handler for harddisk device.\n"); + NR_HD = 0; + } + + i = NR_HD; + while (i-- > 0) + hd[i<<6].nr_sects = hd_info[i].head * hd_info[i].sect + * hd_info[i].cyl; + + hd_gendisk.nr_real = NR_HD; + + for (i=0; i<(MAX_HD << 6); i++) + hd_blocksizes[i] = 1024; + + blksize_size [MAJOR_NR] = hd_blocksizes; + } + + static struct file_operations hd_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + hd_ioctl, /* ioctl */ + NULL, /* mmap */ + hd_open, /* open */ + hd_release, /* release */ + block_fsync /* fsync */ + }; + + unsigned long hd_init(unsigned long mem_start, unsigned long mem_end) + { + if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) { + printk("Unable to get major %d for harddisk\n",MAJOR_NR); + return mem_start; + } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ + hd_gendisk.next = gendisk_head; + gendisk_head = &hd_gendisk; + timer_table[HD_TIMER].fn = hd_times_out; + return mem_start; + } + + #define DEVICE_BUSY busy[target] + #define USAGE access_count[target] + #define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl) + /* We assume that the the bios parameters do not change, so the disk capacity + will not change */ + #undef MAYBE_REINIT + #define GENDISK_STRUCT hd_gendisk + + /* + * This routine is called to flush all partitions and partition tables + * for a changed scsi disk, and then re-read the new partition table. + * If we are revalidating a disk because of a media change, then we + * enter with usage == 0. If we are using an ioctl, we automatically have + * usage == 1 (we need an open channel to use an ioctl :-), so this + * is our limit. + */ + static int revalidate_hddisk(int dev, int maxusage) + { + int target, major; + struct gendisk * gdev; + int max_p; + int start; + int i; + + target = DEVICE_NR(MINOR(dev)); + gdev = &GENDISK_STRUCT; + + cli(); + if (DEVICE_BUSY || USAGE > maxusage) { + sti(); + return -EBUSY; + }; + DEVICE_BUSY = 1; + sti(); + + max_p = gdev->max_p; + start = target << gdev->minor_shift; + major = MAJOR_NR << 8; + + for (i=max_p - 1; i >=0 ; i--) { + sync_dev(major | start | i); + invalidate_inodes(major | start | i); + invalidate_buffers(major | start | i); + gdev->part[start+i].start_sect = 0; + gdev->part[start+i].nr_sects = 0; + }; + + #ifdef MAYBE_REINIT + MAYBE_REINIT; + #endif + + gdev->part[start].nr_sects = CAPACITY; + resetup_one_dev(gdev, target); + + DEVICE_BUSY = 0; + wake_up(&busy_wait); + return 0; + } diff -cr --new-file linux-0.07pl4/drivers/block/floppy.c linux-0.08/drivers/block/floppy.c *** linux-0.07pl4/drivers/block/floppy.c Tue Feb 22 11:26:23 1994 --- linux-0.08/drivers/block/floppy.c Sat Feb 26 08:31:42 1994 *************** *** 27,33 **** * Defines */ #define MAX_SECTORS 22 - #define RAW_BUF 900000 /* * Error codes --- 27,32 ---- *************** *** 63,71 **** #define DATA(x) ((x) >> 5) & 3) static struct fd_drive_type drive_types[] = { ! /* code name tr he rdsz wrsz sm pc1 pc2 sd st st*/ ! { FD_DD_3, "DD 3.5", 160, 2, 14716, 13630, 1, 80,161, 3000, 18000, 1000}, ! { FD_HD_3, "HD 3.5", 160, 2, 25000, 25000, 2, 80,161, 3000, 18000, 1000}, { FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]); --- 62,70 ---- #define DATA(x) ((x) >> 5) & 3) static struct fd_drive_type drive_types[] = { ! /* code name tr he rdsz wrsz sm pc1 pc2 sd st st*/ ! { FD_DD_3, "DD 3.5", 160, 2, 14716, 13630, 1, 80,161, 3000, 18000, 1000}, ! { FD_HD_3, "HD 3.5", 160, 2, 25000, 25000, 2, 80,161, 3000, 18000, 1000}, { FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]); *************** *** 86,103 **** static struct floppy_struct unit[FD_MAX_UNITS]; /* track buffer */ ! int savedtrack = -1; ! unsigned char trackdata[MAX_SECTORS * 512]; /* * These are global variables, as that's the easiest way to give * information to interrupts. They are the data used for the current * request. */ ! char block_flag = 0; ! int selected = 0; ! struct wait_queue *wait_on_floppy_select = NULL; ! struct wait_queue *wait_fd_block = NULL; /* Synchronization of FDC access. */ static volatile int fdc_busy = 0; --- 85,103 ---- static struct floppy_struct unit[FD_MAX_UNITS]; /* track buffer */ ! static int savedtrack = -1; ! static unsigned char trackdata[MAX_SECTORS * 512]; ! static char *raw_buf; /* * These are global variables, as that's the easiest way to give * information to interrupts. They are the data used for the current * request. */ ! static char block_flag = 0; ! static int selected = 0; ! static struct wait_queue *wait_on_floppy_select = NULL; ! static struct wait_queue *wait_fd_block = NULL; /* Synchronization of FDC access. */ static volatile int fdc_busy = 0; *************** *** 317,323 **** ciab.prb = prb; restore_flags (flags); ! } /*====================================================================== --- 317,323 ---- ciab.prb = prb; restore_flags (flags); ! } /*====================================================================== *************** *** 474,480 **** static unsigned long *putsec(unsigned long *raw, int track, int cnt, unsigned char *data) ! { struct header hdr; int i; --- 474,480 ---- static unsigned long *putsec(unsigned long *raw, int track, int cnt, unsigned char *data) ! { struct header hdr; int i; *************** *** 538,544 **** even = odd + len; /* prepare return pointer */ ! raw += len * 2; do { *data++ = ((*odd++ & 0x55555555) << 1) | (*even++ & 0x55555555); --- 538,544 ---- even = odd + len; /* prepare return pointer */ ! raw += len * 2; do { *data++ = ((*odd++ & 0x55555555) << 1) | (*even++ & 0x55555555); *************** *** 777,786 **** if (savedtrack == track) return 0; ! raw_read(drive, track, (char *)RAW_BUF, ! unit[drive].type->read_size); savedtrack = -1; ! error = amiga_read(drive, trackdata, RAW_BUF, track); switch (error) { case 0: savedtrack = track; --- 777,785 ---- if (savedtrack == track) return 0; ! raw_read(drive, track, raw_buf, unit[drive].type->read_size); savedtrack = -1; ! error = amiga_read(drive, trackdata, (unsigned long)raw_buf, track); switch (error) { case 0: savedtrack = track; *************** *** 879,887 **** } copy_buffer(data, trackdata + sector * 512); if (cnt == 1 || track != ((block+1)/floppy->dtype->sects)) { ! amiga_write(drive, (unsigned long)RAW_BUF, trackdata, track); ! if (!raw_write(drive, track, (char *)RAW_BUF, unit[drive].type->write_size)) { printk ("floppy disk write protected\n"); end_request(0); --- 878,886 ---- } copy_buffer(data, trackdata + sector * 512); if (cnt == 1 || track != ((block+1)/floppy->dtype->sects)) { ! amiga_write(drive, (unsigned long)raw_buf, trackdata, track); ! if (!raw_write(drive, track, raw_buf, unit[drive].type->write_size)) { printk ("floppy disk write protected\n"); end_request(0); *************** *** 1122,1127 **** --- 1121,1128 ---- timer_active &= ~(1 << FLOPPY_TIMER); config_types(); + + raw_buf = (char *)amiga_chip_alloc (30000); /* make sure that disk DMA is enabled */ custom.dmacon = DMAF_SETCLR | DMAF_DISK; diff -cr --new-file linux-0.07pl4/drivers/block/ll_rw_blk.c linux-0.08/drivers/block/ll_rw_blk.c *** linux-0.07pl4/drivers/block/ll_rw_blk.c Sat Dec 11 08:49:55 1993 --- linux-0.08/drivers/block/ll_rw_blk.c Sun Mar 27 08:02:55 1994 *************** *** 479,485 **** req->next = NULL; } memset(ro_bits,0,sizeof(ro_bits)); ! #ifdef CONFIG_BLK_DEV_HD mem_start = hd_init(mem_start,mem_end); #endif #ifdef CONFIG_CDU31A --- 479,485 ---- req->next = NULL; } memset(ro_bits,0,sizeof(ro_bits)); ! #if defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_AMIGA_IDE) mem_start = hd_init(mem_start,mem_end); #endif #ifdef CONFIG_CDU31A diff -cr --new-file linux-0.07pl4/drivers/block/ramdisk.c linux-0.08/drivers/block/ramdisk.c *** linux-0.07pl4/drivers/block/ramdisk.c Tue Feb 22 11:26:55 1994 --- linux-0.08/drivers/block/ramdisk.c Sun Mar 27 17:11:36 1994 *************** *** 202,207 **** --- 202,208 ---- #else s = *(struct minix_super_block *)(rd_start + BLOCK_SIZE); + #if 0 if (s.s_magic != MINIX_SUPER_MAGIC) { /* No ram disk image present, assume normal floppy boot */ printk ("ramdisk has no super block magic number %x\n", *************** *** 215,220 **** --- 216,224 ---- nblocks, rd_length >> BLOCK_SIZE_BITS); return; } + #else + nblocks = rd_length >> BLOCK_SIZE_BITS; + #endif printk("RAMDISK: Loading %d blocks into ram disk", nblocks); printk("\ndone\n"); /* We loaded the file system image. Prepare for mounting it. */ diff -cr --new-file linux-0.07pl4/drivers/char/Makefile linux-0.08/drivers/char/Makefile *** linux-0.07pl4/drivers/char/Makefile Sun Dec 12 08:56:13 1993 --- linux-0.08/drivers/char/Makefile Sun Mar 27 09:47:03 1994 *************** *** 16,21 **** --- 16,27 ---- tty_ioctl.c pty.c vt.c mem.c \ defkeymap.c + ifdef CONFIG_AMIGAMOUSE + M = y + OBJS := $(OBJS) amigamouse.o + SRCS := $(SRCS) amigamouse.c + endif + ifdef CONFIG_ATIXL_BUSMOUSE M = y OBJS := $(OBJS) atixlmouse.o diff -cr --new-file linux-0.07pl4/drivers/char/amigamouse.c linux-0.08/drivers/char/amigamouse.c *** linux-0.07pl4/drivers/char/amigamouse.c Wed Dec 31 19:00:00 1969 --- linux-0.08/drivers/char/amigamouse.c Sun Mar 27 09:46:15 1994 *************** *** 0 **** --- 1,282 ---- + /* + * Amiga Mouse Driver for Linux 68k by Michael Rausch + * based upon: + * + * Logitech Bus Mouse Driver for Linux + * by James Banks + * + * Mods by Matthew Dillon + * calls verify_area() + * tracks better when X is busy or paging + * + * Heavily modified by David Giller + * changed from queue- to counter- driven + * hacked out a (probably incorrect) mouse_select + * + * Modified again by Nathan Laredo to interface with + * 0.96c-pl1 IRQ handling changes (13JUL92) + * didn't bother touching select code. + * + * Modified the select() code blindly to conform to the VFS + * requirements. 92.07.14 - Linus. Somebody should test it out. + * + * Modified by Johan Myreen to make room for other mice (9AUG92) + * removed assignment chr_fops[10] = &mouse_fops; see mouse.c + * renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public. + * renamed this file mouse.c => busmouse.c + */ + + #include + #include + #include + #include + + #include + #include + #include + #include + + #include + #include + + #include + #include + + + #define MSE_INT_ON() mouseint_allowed = 1 + #define MSE_INT_OFF() mouseint_allowed = 0 + + + static struct mouse_status mouse; + + static int mouseint_allowed; + + static void mouse_interrupt(int unused) + { + static int lastdx=0, lastdy=0; + int dx, dy; + unsigned char buttons; + + unsigned short joy0dat, potgor; + + if(!mouseint_allowed) + return; + MSE_INT_OFF(); + + /* + * This routine assumes, just like Kickstart, that the mouse + * has not moved more than 127 ticks since last VBL. + */ + + joy0dat = custom.joy0dat; + + dx = -lastdx; + dx += (lastdx = joy0dat & 0xff); + if (dx < -127) + dx = -255-dx; /* underrun */ + else + if (dx > 127) + dx = 255-dx; /* overflow */ + + dy = -lastdy; + dy += (lastdy = joy0dat >> 8); + if (dy < -127) + dy = -255-dy; + else + if (dy > 127) + dy = 255-dy; + + + potgor = custom.potgor; + buttons = (ciaa.pra & 0x40 ? 4 : 0) | /* left button; note that the bits are low-active, as are the expected results -> double negation */ + #if 1 + (potgor & 0x0100 ? 2 : 0) | /* middle button; emulation goes here */ + #endif + (potgor & 0x0400 ? 1 : 0); /* right button */ + + + if (dx != 0 || dy != 0 || buttons != mouse.buttons) { + mouse.buttons = buttons; + mouse.dx += dx; + mouse.dy -= dy; + mouse.ready = 1; + wake_up_interruptible(&mouse.wait); + + /* + * keep dx/dy reasonable, but still able to track when X (or + * whatever) must page or is busy (i.e. long waits between + * reads) + */ + if (mouse.dx < -2048) + mouse.dx = -2048; + else + if (mouse.dx > 2048) + mouse.dx = 2048; + + if (mouse.dy < -2048) + mouse.dy = -2048; + else + if (mouse.dy > 2048) + mouse.dy = 2048; + } + MSE_INT_ON(); + } + + /* + * close access to the mouse (can deal with multiple + * opens if allowed in the future) + */ + + static void close_mouse(struct inode * inode, struct file * file) + { + if (--mouse.active == 0) { + MSE_INT_OFF(); + } + } + + /* + * open access to the mouse, currently only one open is + * allowed. + */ + + static int open_mouse(struct inode * inode, struct file * file) + { + if (!mouse.present) + return -EINVAL; + if (mouse.active) + return -EBUSY; + mouse.ready = 0; + mouse.dx = 0; + mouse.dy = 0; + mouse.buttons = 0x87; + mouse.active = 1; + MSE_INT_ON(); + return 0; + } + + /* + * writes are disallowed + */ + + static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count) + { + return -EINVAL; + } + + /* + * read mouse data. Currently never blocks. + */ + + static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count) + { + int r; + int dx; + int dy; + unsigned char buttons; + + if (count < 3) + return -EINVAL; + if ((r = verify_area(VERIFY_WRITE, buffer, count))) + return r; + if (!mouse.ready) + return -EAGAIN; + + /* + * Obtain the current mouse parameters and limit as appropriate for + * the return data format. Interrupts are only disabled while + * obtaining the parameters, NOT during the puts_fs_byte() calls, + * so paging in put_fs_byte() does not effect mouse tracking. + */ + + MSE_INT_OFF(); + dx = mouse.dx; + dy = mouse.dy; + if (dx < -127) + dx = -127; + else + if (dx > 127) + dx = 127; + if (dy < -127) + dy = -127; + else + if (dy > 127) + dy = 127; + buttons = mouse.buttons; + mouse.dx -= dx; + mouse.dy -= dy; + mouse.ready = 0; + MSE_INT_ON(); + + put_fs_byte(buttons | 0x80, buffer); + put_fs_byte((char)dx, buffer + 1); + put_fs_byte((char)dy, buffer + 2); + for (r = 3; r < count; r++) + put_fs_byte(0x00, buffer + r); + return r; + } + + /* + * select for mouse input, must disable the mouse interrupt while checking + * mouse.ready/select_wait() to avoid race condition (though in reality + * such a condition is not fatal to the proper operation of the mouse since + * multiple interrupts generally occur). + */ + + static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) + { + int r = 0; + + if (sel_type == SEL_IN) { + MSE_INT_OFF(); + if (mouse.ready) { + r = 1; + } else { + select_wait(&mouse.wait, wait); + } + MSE_INT_ON(); + } + return(r); + } + + struct file_operations amiga_mouse_fops = { + NULL, /* mouse_seek */ + read_mouse, + write_mouse, + NULL, /* mouse_readdir */ + mouse_select, /* mouse_select */ + NULL, /* mouse_ioctl */ + NULL, /* mouse_mmap */ + open_mouse, + close_mouse, + }; + + unsigned long amiga_mouse_init(unsigned long kmem_start) + { + + custom.joytest = 0; /* reset counters */ + + MSE_INT_OFF(); + + mouse.active = 0; + mouse.ready = 0; + mouse.buttons = 0x87; + mouse.dx = 0; + mouse.dy = 0; + mouse.wait = NULL; + + /* + * use VBL to poll mouse deltas + */ + + if(!mach_add_isr(IRQ_AMIGA_VERTB, (isrfunc)mouse_interrupt, 0, NULL)) + { + mouse.present = 0; + printk("Installing Amiga mouse failed.\n"); + return kmem_start; + } + + mouse.present = 1; + + printk("Amiga mouse installed.\n"); + return kmem_start; + } diff -cr --new-file linux-0.07pl4/drivers/char/console.c linux-0.08/drivers/char/console.c *** linux-0.07pl4/drivers/char/console.c Sun Dec 12 11:55:33 1993 --- linux-0.08/drivers/char/console.c Tue Mar 15 03:06:21 1994 *************** *** 1,14 **** /* ! ** linux/kernel/chr_drv/console.c ! ** ! ** Copyright (C) 1993 Hamish Macdonald and Greg Harp ! ** ! ** Last Modified 2/22/93 by Greg Harp ! ** ! ** This file is subject to the terms and conditions of the GNU General Public ! ** License. See the file README.legal in the main directory of this archive ! ** for more details. ! */ #include #include --- 1,46 ---- /* ! * linux/kernel/console.c ! * ! * Copyright (C) 1991, 1992 Linus Torvalds ! */ ! ! /* ! * console.c ! * ! * This module exports the console io functions: ! * ! * 'long con_init(long)' ! * 'int con_open(struct tty_struct *tty, struct file * filp)' ! * 'void update_screen(int new_console)' ! * 'void blank_screen(void)' ! * 'void unblank_screen(void)' ! * ! * Hopefully this will be a rather complete VT102 implementation. ! * ! * Beeping thanks to John T Kohl. ! * ! * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics ! * Chars, and VT100 enhancements by Peter MacDonald. ! * ! * Copy and paste function by Andrew Haylett. ! * ! * 680x0 LINUX support by Arno Griffioen (arno@usn.nl) ! * 680x0 doesn't have cut&paste support yet. Bit hard on a bitmapped ! * screen. Have to keep some sort of second (ASCII) screen in the ! * background for that. May even be used for VC's.... ! */ ! ! /* ! * NOTE!!! We sometimes disable and enable interrupts for a short while ! * (to put a word in video IO), but this will work even for keyboard ! * interrupts. We know interrupts aren't enabled when getting a keyboard ! * interrupt, as we use trap-gates. Hopefully all is well. ! */ ! ! /* ! * Code to check for different video-cards mostly by Galen Hunt, ! * ! */ #include #include *************** *** 18,260 **** #include #include #include #include "vt_kern.h" ! /* ! ** Global Variables ! */ struct condata vc_cons[NR_CONSOLES]; ! struct consw *conswitchp; /* ! ** Prototypes ! */ ! void onecon_init(unsigned int num); ! void console_print(const char *str); ! extern void register_console (void (*proc)(const char *)); ! static int can_do_color = 1; /* ! ** Functions ! */ ! long con_init(long mem_start) { ! char *display_desc = "????"; ! display_desc = "ECS"; ! /* ! * initialize the first virtual console so that the console ! * device can use it. ! */ ! onecon_init (0); ! register_console(console_print); ! #if 0 ! printk("Console: %s %s %ldx%ld, %d virtual consoles\n", ! can_do_color?"colour":"mono", ! display_desc, ! video_num_columns,video_num_lines, ! NR_CONSOLES); ! #else ! printk("Console: %s %s %dx%d, %d virtual consoles\n", ! can_do_color?"colour":"mono", ! display_desc, ! vc_cons[0].rows, vc_cons[0].cols, ! NR_CONSOLES); ! #endif ! return(mem_start); } ! void onecon_init (unsigned int connum) { ! struct condata *conp; ! if (connum >= NR_CONSOLES) ! panic ("onecon_init: Bad console number"); ! conp = &vc_cons[connum]; - if (conp->flags & CON_INITED) return; ! conp->sw = conswitchp; ! conp->curx = 0; ! conp->cury = 0; ! conp->cursorx = 0; ! conp->cursory = 0; ! conp->sw->con_init (conp); ! conp->sw->con_cursor (conp, CM_DRAW); ! conp->flags |= CON_INITED; } ! void do_keyboard_interrupt(void) { ! TTY_READ_FLUSH(TTY_TABLE(0)); ! #if 0 ! timer_active &= ~(1<curx = conp->cury = 0; ! conp->sw->con_clear (conp, 0, 0, conp->rows, conp->cols); ! conp->sw->con_cursor (conp, CM_DRAW); ! break; ! case '\b': ! if (conp->curx > 0) ! conp->curx--; ! conp->sw->con_cursor (conp, CM_MOVE); ! break; ! case '\t': ! conp->curx = (conp->curx + 8) & ~7; ! conp->sw->con_cursor (conp, CM_MOVE); ! break; ! case '\n': ! /* newline */ ! conp->curx = 0; ! if (++conp->cury == conp->rows) { ! --conp->cury; ! conp->sw->con_scroll (conp, 1, 0, 1, SM_UP); ! conp->sw->con_clear (conp, conp->cury, 0, 1, conp->cols); } ! conp->sw->con_cursor (conp, CM_DRAW); ! break; ! case '\r': ! /* carriage return */ ! conp->curx = 0; ! conp->sw->con_cursor (conp, CM_MOVE); ! break; ! case 7: ! /* bell */ ! break; ! case 127: ! /* delete */ ! break; ! default: ! conp->sw->con_putc (conp, c, conp->cury, conp->curx, DM_COPY); ! if (conp->curx < conp->cols - 1) ! conp->curx++; ! else { ! conp->curx = 0; ! if (++conp->cury == conp->rows) { ! --conp->cury; ! conp->sw->con_scroll (conp, 0, 0, 1, SM_UP); ! conp->sw->con_clear (conp, conp->cury, 0, 1, conp->cols); ! } } - conp->sw->con_cursor (conp, CM_DRAW); - break; - } } ! void con_write (struct tty_struct *tty) { ! int c; ! unsigned int currcons; ! currcons = tty->line - 1; ! if (currcons >= NR_CONSOLES) { ! printk("con_write: illegal tty (%d)\n", currcons); return; ! } ! while (!tty->stopped && (c = get_tty_queue(&tty->write_q)) >= 0) ! con_putc (c, currcons); } ! void blank_screen (void) { } ! void unblank_screen (void) { } void update_screen(int new_console) { ! static int lock = 0; ! if (new_console == fg_console || lock) return; ! lock = 1; #if 0 ! kbdsave(new_console); ! get_scrmem(fg_console); ! fg_console = new_console; ! set_scrmem(fg_console); ! set_origin(fg_console); ! set_cursor(new_console); ! set_leds(); #endif - lock = 0; } ! void console_print(const char *str) { ! while(*str) ! con_putc(*str++, 0); } /* * All we do is set the write and ioctl subroutines; later on maybe we'll * dynamically allocate the console screen memory. */ ! int con_open(struct tty_struct *tty, struct file *filp) { ! tty->write = con_write; ! tty->ioctl = vt_ioctl; ! if (tty->line > NR_CONSOLES) ! return -ENODEV; ! onecon_init (tty->line-1); ! tty->winsize.ws_row = vc_cons[tty->line-1].rows; ! tty->winsize.ws_col = vc_cons[tty->line-1].cols; ! return 0; } --- 50,1640 ---- #include #include #include + #include #include "vt_kern.h" ! #ifdef CONFIG_SELECTION ! #include ! ! /* Routines for selection control. */ ! int set_selection(const int arg); ! int paste_selection(struct tty_struct *tty); ! static void clear_selection(void); ! ! /* Variables for selection control. */ ! #define SEL_BUFFER_SIZE TTY_BUF_SIZE ! static int sel_cons; ! static int sel_start = -1; ! static int sel_end; ! static char sel_buffer[SEL_BUFFER_SIZE] = { '\0' }; ! #endif /* CONFIG_SELECTION */ ! ! extern void vt_init(void); ! extern void register_console(void (*proc)(const char *)); ! extern void compute_shiftstate(void); ! ! static int console_blanked = 0; struct condata vc_cons[NR_CONSOLES]; ! struct consw *conswitchp; + #define flags (vc_cons[currcons].vc_flags) + #define x (vc_cons[currcons].vc_x) + #define y (vc_cons[currcons].vc_y) + #define top (vc_cons[currcons].vc_top) + #define bottom (vc_cons[currcons].vc_bottom) /* ! * Arno: ! * On the 680x0 we could have screens with different sizes (at least ! * on the Amiga), so we have to store it with each console instead ! * of using a global variable like the original PC code. ! */ ! #define video_num_columns (vc_cons[currcons].vc_cols) ! #define video_num_lines (vc_cons[currcons].vc_rows) ! #define state (vc_cons[currcons].vc_state) ! #define npar (vc_cons[currcons].vc_npar) ! #define par (vc_cons[currcons].vc_par) ! #define ques (vc_cons[currcons].vc_ques) ! #define attr (vc_cons[currcons].vc_attr) ! #define saved_x (vc_cons[currcons].vc_saved_x) ! #define saved_y (vc_cons[currcons].vc_saved_y) ! #define translate (vc_cons[currcons].vc_translate) ! #define G0_charset (vc_cons[currcons].vc_G0_charset) ! #define G1_charset (vc_cons[currcons].vc_G1_charset) ! #define saved_G0 (vc_cons[currcons].vc_saved_G0) ! #define saved_G1 (vc_cons[currcons].vc_saved_G1) ! #define video_erase_char (vc_cons[currcons].vc_video_erase_char) ! #define decscnm (vc_cons[currcons].vc_decscnm) ! #define decom (vc_cons[currcons].vc_decom) ! #define decawm (vc_cons[currcons].vc_decawm) ! #define deccm (vc_cons[currcons].vc_deccm) ! #define decim (vc_cons[currcons].vc_decim) ! #define need_wrap (vc_cons[currcons].vc_need_wrap) ! #define color (vc_cons[currcons].vc_color) ! #define s_color (vc_cons[currcons].vc_s_color) ! #define def_color (vc_cons[currcons].vc_def_color) ! #define foreground (color & 0x0f) ! #define background (color & 0xf0) ! #define charset (vc_cons[currcons].vc_charset) ! #define s_charset (vc_cons[currcons].vc_s_charset) ! #define intensity (vc_cons[currcons].vc_intensity) ! #define underline (vc_cons[currcons].vc_underline) ! #define blink (vc_cons[currcons].vc_blink) ! #define reverse (vc_cons[currcons].vc_reverse) ! #define s_intensity (vc_cons[currcons].vc_s_intensity) ! #define s_underline (vc_cons[currcons].vc_s_underline) ! #define s_blink (vc_cons[currcons].vc_s_blink) ! #define s_reverse (vc_cons[currcons].vc_s_reverse) ! #define ulcolor (vc_cons[currcons].vc_ulcolor) ! #define halfcolor (vc_cons[currcons].vc_halfcolor) ! #define kbdmode (vc_cons[currcons].vc_kbdmode) ! #define tab_stop (vc_cons[currcons].vc_tab_stop) ! #define sw (vc_cons[currcons].vc_sw) ! ! #define vcmode (vt_cons[currcons].vc_mode) ! #define vtmode (vt_cons[currcons].vt_mode) ! #define vtpid (vt_cons[currcons].vt_pid) ! #define vtnewvt (vt_cons[currcons].vt_newvt) ! ! #define decarm VC_REPEAT ! #define decckm VC_CKMODE ! #define kbdapplic VC_APPLIC ! #define kbdraw VC_RAW ! #define lnm VC_CRLF ! /* ! * this is what the terminal answers to a ESC-Z or csi0c query. ! */ ! #define VT100ID "\033[?1;2c" ! #define VT102ID "\033[?6c" ! static unsigned char * translations[] = { ! /* 8-bit Latin-1 mapped to the PC charater set: '\0' means non-printable */ ! (unsigned char *) ! "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ! "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0" ! " !\"#$%&'()*+,-./0123456789:;<=>?" ! "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" ! "`abcdefghijklmnopqrstuvwxyz{|}~\0" ! "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ! "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ! "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376" ! "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250" ! "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376" ! "\376\245\376\376\376\376\231\376\350\376\376\376\232\376\376\341" ! "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213" ! "\376\244\225\242\223\376\224\366\355\227\243\226\201\376\376\230", ! /* vt100 graphics */ ! (unsigned char *) ! "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ! "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0" ! " !\"#$%&'()*+,-./0123456789:;<=>?" ! "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ " ! "\004\261\007\007\007\007\370\361\007\007\331\277\332\300\305\304" ! "\304\304\137\137\303\264\301\302\263\363\362\343\330\234\007\0" ! "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ! "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ! "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376" ! "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250" ! "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376" ! "\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341" ! "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213" ! "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230", ! /* IBM graphics: minimal translations (BS, CR, LF, LL, SO, SI and ESC) */ ! (unsigned char *) ! "\000\001\002\003\004\005\006\007\000\011\000\013\000\000\000\000" ! "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037" ! "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" ! "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" ! "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" ! "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" ! "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" ! "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" ! "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" ! "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" ! "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" ! "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" ! "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" ! "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" ! "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" ! "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" ! }; ! ! #define NORM_TRANS (translations[0]) ! #define GRAF_TRANS (translations[1]) ! #define NULL_TRANS (translations[2]) ! ! static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, ! 8,12,10,14, 9,13,11,15 }; /* ! * gotoxy() must verify all boundaries, because the arguments ! * might also be negative. If the given position is out of ! * bounds, the cursor is placed at the nearest margin. ! */ ! static void gotoxy(int currcons, int new_x, int new_y) ! { ! int max_y; ! if (new_x < 0) ! x = 0; ! else ! if (new_x >= video_num_columns) ! x = video_num_columns - 1; ! else ! x = new_x; ! if (decom) { ! new_y += top; ! max_y = bottom; ! } else ! max_y = video_num_lines; ! if (new_y < 0) ! y = 0; ! else ! if (new_y >= max_y) ! y = max_y - 1; ! else ! y = new_y; ! need_wrap = 0; ! } ! ! static void hide_cursor(int currcons) { ! sw->con_cursor(&vc_cons[currcons],CM_ERASE); ! return; ! } ! static void set_cursor(int currcons) ! { ! if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) ! return; ! if (deccm) { ! sw->con_cursor(&vc_cons[currcons],CM_DRAW); ! } else ! hide_cursor(currcons); ! return; ! } ! /* ! * Arno: ! * Why do we need these? The keyboard code doesn't seem to do anything ! * with them either... ! */ ! void scrollfront(int l) ! { ! return; ! } ! void scrollback(int l) ! { ! return; ! } ! static void scrup(int currcons, unsigned int t, unsigned int b) ! { ! if (b > video_num_lines || t >= b) ! return; ! /* ! * Arno: ! * TODO: move this code into the con_scroll code. Not done yet ! * to speed up testing process. If OK, then move to amicon.c ! */ ! sw->con_bmove(&vc_cons[currcons],t+1,0,t,0,(b-t-1),video_num_columns); ! sw->con_clear(&vc_cons[currcons],b-1,0,1,video_num_columns); ! ! return; ! } ! static void scrdown(int currcons, unsigned int t, unsigned int b) { ! int numlines; ! ! if (b > video_num_lines || t >= b) ! return; ! /* ! * Arno: ! * TODO: move this code into the con_scroll code. Not done yet ! * to speed up testing process. If OK, then move to amicon.c ! */ ! numlines=(b-t-1); ! while(numlines >= 0) ! { ! sw->con_bmove(&vc_cons[currcons], t+numlines, 0, t+numlines+1, 0, 1,video_num_columns-1); ! numlines--; ! } ! ! ! #if 0 ! /* ! * Arno: ! * Bombs out because bmove doesn't really copy the block in one ! * go, but does it piece by piece. Causes the top line to be ! * repeated until the bottom margin. Now I have to do it line-by-line ! * and back-to-front :-( ! */ ! ! sw->con_bmove(&vc_cons[currcons],t,0,t+1,0,(b-t-1),video_num_columns-1); ! #endif ! sw->con_clear(&vc_cons[currcons],t,0,1,video_num_columns); return; + } ! static void lf(int currcons) ! { ! if (y+1top) { ! y--; ! return; ! } else ! scrdown(currcons,top,bottom); ! need_wrap = 0; ! } ! static inline void cr(int currcons) ! { ! need_wrap = x = 0; } ! static inline void bs(int currcons) { ! if (x) { ! x--; ! need_wrap = 0; } ! } ! ! static inline void del(int currcons) ! { ! #if 0 ! if (x) { ! if (!need_wrap) { /* this is not the right condition */ ! x--; ! } ! need_wrap = 0; } #endif } ! static void csi_J(int currcons, int vpar) ! { ! switch (vpar) { ! case 0: /* erase from cursor to end of display */ ! /* 680x0 do in two stages */ ! sw->con_clear(&vc_cons[currcons],y,x,1,video_num_columns-x); ! sw->con_clear(&vc_cons[currcons],y+1,0,video_num_lines-y-1, video_num_columns); ! break; ! case 1: /* erase from start to cursor */ ! /* 680x0 do in two stages */ ! sw->con_clear(&vc_cons[currcons],0,0,y, video_num_columns); ! sw->con_clear(&vc_cons[currcons],y,0,1,x); ! break; ! case 2: /* erase whole display */ ! sw->con_clear(&vc_cons[currcons],0,0,video_num_lines, video_num_columns); ! break; ! default: ! return; ! } ! need_wrap = 0; ! } ! ! static void csi_K(int currcons, int vpar) ! { ! switch (vpar) { ! case 0: /* erase from cursor to end of line */ ! sw->con_clear(&vc_cons[currcons],y,x,1,video_num_columns-x); ! break; ! case 1: /* erase from start of line to cursor */ ! sw->con_clear(&vc_cons[currcons],y,0,1,x); ! break; ! case 2: /* erase whole line */ ! sw->con_clear(&vc_cons[currcons],y,0,1,video_num_columns); ! break; ! default: ! return; ! } ! need_wrap = 0; ! } ! ! /* ! * I hope this works. The monochrome part is untested. ! */ ! ! /* ! * Arno: ! * On 680x0 attributes are currently not used. This piece of code ! * seems hardware independent, but uses the EGA/VGA way of representing ! * attributes. ! * TODO: modify for 680x0 and add attribute processing to putc code. ! */ ! static void update_attr(int currcons) { + attr = color; + if (can_do_color) { + if (underline) + attr = (attr & 0xf0) | ulcolor; + else if (intensity == 0) + attr = (attr & 0xf0) | halfcolor; + } + if (reverse ^ decscnm) + attr = (attr & 0x88) | (((attr >> 4) | (attr << 4)) & 0x77); + if (blink) + attr ^= 0x80; + if (intensity == 2) + attr ^= 0x08; + if (!can_do_color) { + if (underline) + attr = (attr & 0xf8) | 0x01; + else if (intensity == 0) + attr = (attr & 0xf0) | 0x08; + } + if (decscnm) + video_erase_char = ((color & 0x88) | (((color >> 4) | + (color << 4)) & 0x77) << 8) | ' '; + else + video_erase_char = (color << 8) | ' '; } ! static void default_attr(int currcons) { + intensity = 1; + underline = 0; + reverse = 0; + blink = 0; + color = def_color; } ! static void csi_m(int currcons) { ! int i; ! for (i=0;i<=npar;i++) ! switch (par[i]) { ! case 0: /* all attributes off */ ! default_attr(currcons); ! break; ! case 1: ! intensity = 2; ! break; ! case 2: ! intensity = 0; ! break; ! case 4: ! underline = 1; ! break; ! case 5: ! blink = 1; ! break; ! case 7: ! reverse = 1; ! break; ! case 21: ! case 22: ! intensity = 1; ! break; ! case 24: ! underline = 0; ! break; ! case 25: ! blink = 0; ! break; ! case 27: ! reverse = 0; ! break; ! case 39: ! color = (def_color & 0x0f) | background; ! break; ! case 49: ! color = (def_color & 0xf0) | foreground; ! break; ! default: ! if (par[i] >= 30 && par[i] <= 37) ! color = color_table[par[i]-30] ! | background; ! else if (par[i] >= 40 && par[i] <= 47) ! color = (color_table[par[i]-40]<<4) ! | foreground; ! break; ! } ! update_attr(currcons); ! } ! static void respond_string(char * p, int currcons, struct tty_struct * tty) ! { ! while (*p) { ! put_tty_queue(*p, &tty->read_q); ! p++; ! } ! TTY_READ_FLUSH(tty); ! } ! static void respond_num(unsigned int n, int currcons, struct tty_struct * tty) ! { ! char buff[3]; ! int i = 0; ! do { ! buff[i++] = (n%10)+'0'; ! n /= 10; ! } while(n && i < 3); /* We'll take no chances */ ! while (i--) { ! put_tty_queue(buff[i], &tty->read_q); } ! /* caller must flush */ ! } ! ! static void cursor_report(int currcons, struct tty_struct * tty) ! { ! put_tty_queue('\033', &tty->read_q); ! put_tty_queue('[', &tty->read_q); ! respond_num(y + (decom ? top+1 : 1), currcons, tty); ! put_tty_queue(';', &tty->read_q); ! respond_num(x+1, currcons, tty); ! put_tty_queue('R', &tty->read_q); ! TTY_READ_FLUSH(tty); ! } ! ! static inline void status_report(int currcons, struct tty_struct * tty) ! { ! respond_string("\033[0n", currcons, tty); /* Terminal ok */ ! } ! ! static inline void respond_ID(int currcons, struct tty_struct * tty) ! { ! respond_string(VT102ID, currcons, tty); ! } ! #if 0 ! /* ! * Arno: ! * Not nice on a bit-mapped screen :-( ! * Won't implement it for now... Don't think anyone will care.. ! */ ! static void invert_screen(int currcons) { ! return; ! } ! #endif ! ! static void set_mode(int currcons, int on_off) ! { ! int i; ! for (i=0; i<=npar; i++) ! if (ques) switch(par[i]) { /* DEC private modes set/reset */ ! case 1: /* Cursor keys send ^[Ox/^[[x */ ! /* Arno: Dunno about KBD stuff... ! * Just ignire it for the moment. ! if (on_off) ! set_kbd(decckm); ! else ! clr_kbd(decckm); ! */ ! break; ! case 3: /* 80/132 mode switch unimplemented */ ! csi_J(currcons,2); ! gotoxy(currcons,0,0); ! break; ! case 5: /* Inverted screen on/off */ ! if (decscnm != on_off) { ! decscnm = on_off; ! /*invert_screen(currcons);*/ ! update_attr(currcons); ! } ! break; ! case 6: /* Origin relative/absolute */ ! decom = on_off; ! gotoxy(currcons,0,0); ! break; ! case 7: /* Autowrap on/off */ ! decawm = on_off; ! break; ! case 8: /* Autorepeat on/off */ ! /* 680x0: no kbd handling? ! if (on_off) ! set_kbd(decarm); ! else ! clr_kbd(decarm); ! */ ! break; ! case 25: /* Cursor on/off */ ! deccm = on_off; ! set_cursor(currcons); ! break; ! } else switch(par[i]) { /* ANSI modes set/reset */ ! case 4: /* Insert Mode on/off */ ! decim = on_off; ! break; ! case 20: /* Lf, Enter == CrLf/Lf */ ! /* 680x0: no kkbd handling? ! if (on_off) ! set_kbd(lnm); ! else ! clr_kbd(lnm); ! */ ! break; ! } ! } ! static void setterm_command(int currcons) ! { ! switch(par[0]) { ! case 1: /* set color for underline mode */ ! if (can_do_color && par[1] < 16) { ! ulcolor = color_table[par[1]]; ! if (underline) ! update_attr(currcons); ! } ! break; ! case 2: /* set color for half intensity mode */ ! if (can_do_color && par[1] < 16) { ! halfcolor = color_table[par[1]]; ! if (intensity == 0) ! update_attr(currcons); ! } ! break; ! case 8: /* store colors as defaults */ ! def_color = attr; ! default_attr(currcons); ! update_attr(currcons); ! break; ! case 9: /* set blanking interval */ ! /* Arno: ! * Well... How does blanking work? Can it ! * function in the 680x0 kernel? ! * blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; ! */ ! break; } } ! static void insert_char(int currcons) ! { ! /* Arno: ! * Move the remainder of the line (-1 character) one spot to the right ! */ ! sw->con_bmove(&vc_cons[currcons],y,x,y,x+1,1,(video_num_columns-x-1)); ! /* ! * Print the erase char on the current position ! */ ! sw->con_putc(&vc_cons[currcons],(video_erase_char & 0x00ff),y,x,DM_COPY); ! ! need_wrap = 0; ! } ! ! static void insert_line(int currcons) ! { ! scrdown(currcons,y,bottom); ! need_wrap = 0; ! } ! ! static void delete_char(int currcons) ! { ! /* Arno ! * Move the remainder of the line one spot to the left ! */ ! ! sw->con_bmove(&vc_cons[currcons],y,x+1,y,x,1,(video_num_columns-x-1)); ! ! /* ! * Print the erase char at the end of the line to remove any ! * remaining junk ! */ ! sw->con_putc(&vc_cons[currcons],(video_erase_char & 0x00ff),y,video_num_columns,DM_COPY); ! ! need_wrap = 0; ! } ! ! static void delete_line(int currcons) { ! scrup(currcons,y,bottom); ! need_wrap = 0; ! } ! ! static void csi_at(int currcons, unsigned int nr) ! { ! if (nr > video_num_columns) ! nr = video_num_columns; ! else if (!nr) ! nr = 1; ! while (nr--) ! insert_char(currcons); ! } ! static void csi_L(int currcons, unsigned int nr) ! { ! if (nr > video_num_lines) ! nr = video_num_lines; ! else if (!nr) ! nr = 1; ! while (nr--) ! insert_line(currcons); ! } ! ! static void csi_P(int currcons, unsigned int nr) ! { ! if (nr > video_num_columns) ! nr = video_num_columns; ! else if (!nr) ! nr = 1; ! while (nr--) ! delete_char(currcons); ! } ! ! static void csi_M(int currcons, unsigned int nr) ! { ! if (nr > video_num_lines) ! nr = video_num_lines; ! else if (!nr) ! nr=1; ! while (nr--) ! delete_line(currcons); ! } ! ! static void save_cur(int currcons) ! { ! saved_x = x; ! saved_y = y; ! s_intensity = intensity; ! s_underline = underline; ! s_blink = blink; ! s_reverse = reverse; ! s_charset = charset; ! s_color = color; ! saved_G0 = G0_charset; ! saved_G1 = G1_charset; ! } ! ! static void restore_cur(int currcons) ! { ! gotoxy(currcons,saved_x,saved_y); ! intensity = s_intensity; ! underline = s_underline; ! blink = s_blink; ! reverse = s_reverse; ! charset = s_charset; ! color = s_color; ! G0_charset = saved_G0; ! G1_charset = saved_G1; ! translate = charset ? G1_charset : G0_charset; ! update_attr(currcons); ! need_wrap = 0; ! } ! ! enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, ! EShash, ESsetG0, ESsetG1, ESignore }; ! ! static void reset_terminal(int currcons, int do_clear) ! { ! top = 0; ! bottom = video_num_lines; ! state = ESnormal; ! ques = 0; ! translate = NORM_TRANS; ! G0_charset = NORM_TRANS; ! G1_charset = GRAF_TRANS; ! charset = 0; ! need_wrap = 0; ! ! decscnm = 0; ! decom = 0; ! decawm = 1; ! deccm = 1; ! decim = 0; ! ! #if 0 ! /* ! * Arno: ! * Here's the kbd stuff again.. What part is PC specific? ! */ ! set_kbd(decarm); ! clr_kbd(decckm); ! clr_kbd(kbdapplic); ! clr_kbd(lnm); ! kbd_table[currcons].flags = ! (kbd_table[currcons].flags & ~LED_MASK) | ! (kbd_table[currcons].default_flags & LED_MASK); ! kbdmode = 0; ! set_leds(); ! ! default_attr(currcons); ! update_attr(currcons); ! #endif ! ! tab_stop[0] = 0x01010100; ! tab_stop[1] = ! tab_stop[2] = ! tab_stop[3] = ! tab_stop[4] = 0x01010101; ! ! if (do_clear) { ! gotoxy(currcons,0,0); ! csi_J(currcons,2); ! save_cur(currcons); ! } ! } ! ! void con_write(struct tty_struct * tty) ! { ! int c; ! unsigned int currcons; ! ! wake_up_interruptible(&tty->write_q.proc_list); ! currcons = tty->line - 1; ! if (currcons >= NR_CONSOLES) { ! printk("con_write: illegal tty (%d)\n", currcons); ! return; ! } ! #ifdef CONFIG_SELECTION ! /* clear the selection as soon as any characters are to be written ! out on the console holding the selection. */ ! if (!EMPTY(&tty->write_q) && currcons == sel_cons) ! clear_selection(); ! #endif /* CONFIG_SELECTION */ ! /* Arno: ! * huh? What's this? ! * disable_bh(KEYBOARD_BH); ! */ ! while (!tty->stopped && (c = get_tty_queue(&tty->write_q)) >= 0) { ! if (state == ESnormal && translate[c]) { ! if (need_wrap) { ! cr(currcons); ! lf(currcons); ! } ! if (decim) ! insert_char(currcons); ! /* Arno: ! * Translation table not really correct ! * for 680x0 charset. No translation yet. ! * TODO: build VT100 charset and enable translation. ! */ ! ! /*c = translate[c];*/ ! ! /* Arno: ! * 680x0: ignore attributes for now, just ! * print character. ! */ ! sw->con_putc(&vc_cons[currcons],c,y,x,DM_COPY); ! if (x == video_num_columns - 1) ! need_wrap = decawm; ! else { ! x++; ! } ! continue; ! } ! ! /* ! * Control characters can be used in the _middle_ ! * of an escape sequence. ! */ ! switch (c) { ! case 7: ! /* No sound on 680x0 yet... ! kd_mksound(0x637, HZ/8); ! */ ! continue; ! case 8: ! bs(currcons); ! continue; ! case 9: ! while (x < video_num_columns - 1) { ! x++; ! if (tab_stop[x >> 5] & (1 << (x & 31))) ! break; ! } ! continue; ! case 10: case 11: case 12: ! lf(currcons); ! /* KBD stuff... ! if (!is_kbd(lnm)) ! continue; ! */ ! case 13: ! cr(currcons); ! continue; ! case 14: ! charset = 1; ! translate = G1_charset; ! continue; ! case 15: ! charset = 0; ! translate = G0_charset; ! continue; ! case 24: case 26: ! state = ESnormal; ! continue; ! case 27: ! state = ESesc; ! continue; ! case 127: ! del(currcons); ! continue; ! case 128+27: ! state = ESsquare; ! continue; ! } ! switch(state) { ! case ESesc: ! state = ESnormal; ! switch (c) { ! case '[': ! state = ESsquare; ! continue; ! case 'E': ! cr(currcons); ! lf(currcons); ! continue; ! case 'M': ! ri(currcons); ! continue; ! case 'D': ! lf(currcons); ! continue; ! case 'H': ! tab_stop[x >> 5] |= (1 << (x & 31)); ! continue; ! case 'Z': ! respond_ID(currcons,tty); ! continue; ! case '7': ! save_cur(currcons); ! continue; ! case '8': ! restore_cur(currcons); ! continue; ! case '(': ! state = ESsetG0; ! continue; ! case ')': ! state = ESsetG1; ! continue; ! case '#': ! state = EShash; ! continue; ! case 'c': ! reset_terminal(currcons,1); ! continue; ! case '>': /* Numeric keypad */ ! /* ignore kbd stuff ! clr_kbd(kbdapplic); ! */ ! continue; ! case '=': /* Appl. keypad */ ! /* ignore kbd stuff ! set_kbd(kbdapplic); ! */ ! continue; ! } ! continue; ! case ESsquare: ! for(npar = 0 ; npar < NPAR ; npar++) ! par[npar] = 0; ! npar = 0; ! state = ESgetpars; ! if (c == '[') { /* Function key */ ! state=ESfunckey; ! continue; ! } ! ques = (c=='?'); ! if (ques) ! continue; ! case ESgetpars: ! if (c==';' && npar='0' && c<='9') { ! par[npar] *= 10; ! par[npar] += c-'0'; ! continue; ! } else state=ESgotpars; ! case ESgotpars: ! state = ESnormal; ! switch(c) { ! case 'h': ! set_mode(currcons,1); ! continue; ! case 'l': ! set_mode(currcons,0); ! continue; ! case 'n': ! if (!ques) ! if (par[0] == 5) ! status_report(currcons,tty); ! else if (par[0] == 6) ! cursor_report(currcons,tty); ! continue; ! } ! if (ques) { ! ques = 0; ! continue; ! } ! switch(c) { ! case 'G': case '`': ! if (par[0]) par[0]--; ! gotoxy(currcons,par[0],y); ! continue; ! case 'A': ! if (!par[0]) par[0]++; ! gotoxy(currcons,x,y-par[0]); ! continue; ! case 'B': case 'e': ! if (!par[0]) par[0]++; ! gotoxy(currcons,x,y+par[0]); ! continue; ! case 'C': case 'a': ! if (!par[0]) par[0]++; ! gotoxy(currcons,x+par[0],y); ! continue; ! case 'D': ! if (!par[0]) par[0]++; ! gotoxy(currcons,x-par[0],y); ! continue; ! case 'E': ! if (!par[0]) par[0]++; ! gotoxy(currcons,0,y+par[0]); ! continue; ! case 'F': ! if (!par[0]) par[0]++; ! gotoxy(currcons,0,y-par[0]); ! continue; ! case 'd': ! if (par[0]) par[0]--; ! gotoxy(currcons,x,par[0]); ! continue; ! case 'H': case 'f': ! if (par[0]) par[0]--; ! if (par[1]) par[1]--; ! gotoxy(currcons,par[1],par[0]); ! continue; ! case 'J': ! csi_J(currcons,par[0]); ! continue; ! case 'K': ! csi_K(currcons,par[0]); ! continue; ! case 'L': ! csi_L(currcons,par[0]); ! continue; ! case 'M': ! csi_M(currcons,par[0]); ! continue; ! case 'P': ! csi_P(currcons,par[0]); ! continue; ! case 'c': ! if (!par[0]) ! respond_ID(currcons,tty); ! continue; ! case 'g': ! if (!par[0]) ! tab_stop[x >> 5] &= ~(1 << (x & 31)); ! else if (par[0] == 3) { ! tab_stop[0] = ! tab_stop[1] = ! tab_stop[2] = ! tab_stop[3] = ! tab_stop[4] = 0; ! } ! continue; ! case 'm': ! csi_m(currcons); ! continue; ! case 'r': ! if (!par[0]) ! par[0]++; ! if (!par[1]) ! par[1] = video_num_lines; ! /* Minimum allowed region is 2 lines */ ! if (par[0] < par[1] && ! par[1] <= video_num_lines) { ! top=par[0]-1; ! bottom=par[1]; ! gotoxy(currcons,0,0); ! } ! continue; ! case 's': ! save_cur(currcons); ! continue; ! case 'u': ! restore_cur(currcons); ! continue; ! case '@': ! csi_at(currcons,par[0]); ! continue; ! case ']': /* setterm functions */ ! setterm_command(currcons); ! continue; ! } ! continue; ! case ESfunckey: ! state = ESnormal; ! continue; ! case EShash: ! state = ESnormal; ! if (c == '8') { ! /* DEC screen alignment test. kludge :-) */ ! video_erase_char = ! (video_erase_char & 0x00ff) | 'E'; ! /* Arno: ! * Doesn't work, because csi_J(c,2) ! * calls con_clear and doesn't print ! * the erase char.. ! */ ! csi_J(currcons, 2); ! video_erase_char = ! (video_erase_char & 0x00ff) | ' '; ! } ! continue; ! case ESsetG0: ! if (c == '0') ! G0_charset = GRAF_TRANS; ! else if (c == 'B') ! G0_charset = NORM_TRANS; ! else if (c == 'U') ! G0_charset = NULL_TRANS; ! if (charset == 0) ! translate = G0_charset; ! state = ESnormal; ! continue; ! case ESsetG1: ! if (c == '0') ! G1_charset = GRAF_TRANS; ! else if (c == 'B') ! G1_charset = NORM_TRANS; ! else if (c == 'U') ! G1_charset = NULL_TRANS; ! if (charset == 1) ! translate = G1_charset; ! state = ESnormal; ! continue; ! default: ! state = ESnormal; ! } ! } ! if (vcmode != KD_GRAPHICS) ! set_cursor(currcons); ! /* ! enable_bh(KEYBOARD_BH); ! */ ! } ! ! void do_keyboard_interrupt(void) ! { ! TTY_READ_FLUSH(TTY_TABLE(0)); ! #if 0 ! /* ! * Arno: ! * No blanking stuff yet. ! * Haven't looked at it.. ! */ ! timer_active &= ~(1<=NR_CONSOLES) ! return; ! while ((c = *(b++)) != 0) { ! if (c == 10 || c == 13 || need_wrap) { ! if (c != 13) ! lf(currcons); ! cr(currcons); ! if (c == 10 || c == 13) ! continue; ! } ! sw->con_putc(&vc_cons[currcons],c,y,x,DM_COPY); ! if (x == video_num_columns - 1) { ! need_wrap = 1; ! continue; ! } ! x++; ! } ! set_cursor(currcons); return; ! if (vt_cons[fg_console].vc_mode == KD_GRAPHICS) ! return; ! #if 0 ! timer_active &= ~(1<con_init or some other platform ! * specific init code instead of hard-coding this... ! */ ! display_desc="ECS"; ! can_do_color=1; ! ! sw=conswitchp; ! ! #if 0 ! /* ! * Arno: ! * first working INIT code... 'Borrowed' from original 680x0 console ! * code.. (hi Hamish!) ! */ ! sw->con_init(&vc_cons[currcons]); ! sw->con_cursor(&vc_cons[currcons], CM_DRAW); ! reset_terminal(currcons, currcons); ! register_console(console_print); ! #endif ! ! #if 0 ! timer_table[BLANK_TIMER].fn = blank_screen; ! timer_table[BLANK_TIMER].expires = 0; ! if (blankinterval) { ! timer_table[BLANK_TIMER].expires = jiffies+blankinterval; ! timer_active |= 1<con_init(&vc_cons[currcons]); ! ! #if 0 ! /* ! * Arno: ! * Strange things happen when more than 1 console is inited... ! * ! * TODO: extend low-level code for multi-console support. ! * Question: how are we going to do VC's? Save/restore bitplanes/copperlists ! * etc.? Can get memory expensive with 4 bitplane screens (in the future..) ! */ ! for (currcons = 0; currconscon_cursor(&vc_cons[currcons], CM_DRAW); ! register_console(console_print); ! printable = 1; ! ! printk("Console: %s %s %ldx%ld, %d virtual consoles\n", ! can_do_color?"colour":"mono", ! display_desc, ! video_num_columns,video_num_lines, ! NR_CONSOLES); ! ! return kmem_start; ! } ! ! /* ! * kbdsave doesn't need to do anything: it's all handled automatically ! * with the new data structures.. ! */ ! void kbdsave(int new_console) ! { } ! void blank_screen(void) { + if (console_blanked) + return; + return; + #if 0 + timer_table[BLANK_TIMER].fn = unblank_screen; + get_scrmem(fg_console); + hide_cursor(fg_console); + console_blanked = 1; + memsetw((void *)video_mem_base, 0x0020, video_mem_term-video_mem_base ); + #endif } ! void unblank_screen(void) { + if (!console_blanked) + return; + return; + #if 0 + timer_table[BLANK_TIMER].fn = blank_screen; + if (blankinterval) { + timer_table[BLANK_TIMER].expires = jiffies + blankinterval; + timer_active |= 1<NR_CONSOLES)) ! return -EIO; ! put_fs_byte((char)(video_num_lines),buf++); ! put_fs_byte((char)(video_num_columns),buf++); ! currcons = (currcons ? currcons-1 : fg_console); ! sptr = (char *) origin; ! for (l=video_num_lines*video_num_columns; l>0 ; l--, sptr++) ! put_fs_byte(*sptr++,buf++); ! return(0); } + #endif /* * All we do is set the write and ioctl subroutines; later on maybe we'll * dynamically allocate the console screen memory. */ ! int con_open(struct tty_struct *tty, struct file * filp) ! { ! tty->write = con_write; ! tty->ioctl = vt_ioctl; ! if (tty->line > NR_CONSOLES) ! return -ENODEV; ! ! tty->winsize.ws_row = vc_cons[tty->line-1].vc_rows; ! tty->winsize.ws_col = vc_cons[tty->line-1].vc_cols; ! ! return 0; ! } ! ! #ifdef CONFIG_SELECTION ! /* correction factor for when screen is hardware-scrolled */ ! #define hwscroll_offset (currcons == fg_console ? ((__real_origin - __origin) << 1) : 0) ! ! /* set reverse video on characters s-e of console with selection. */ ! static void highlight(const int currcons, const int s, const int e) ! { ! unsigned char *p, *p1, *p2; ! ! p1 = (unsigned char *)origin - hwscroll_offset + s + 1; ! p2 = (unsigned char *)origin - hwscroll_offset + e + 1; ! if (p1 > p2) ! { ! p = p1; ! p1 = p2; ! p2 = p; ! } ! for (p = p1; p <= p2; p += 2) ! *p = (*p & 0x88) | ((*p << 4) & 0x70) | ((*p >> 4) & 0x07); ! } ! ! /* is c in range [a-zA-Z0-9_]? */ ! static inline int inword(const char c) { return (isalnum(c) || c == '_'); } ! ! /* does screen address p correspond to character at LH/RH edge of screen? */ ! static inline int atedge(const int p) ! { ! return (!(p % video_size_row) || !((p + 2) % video_size_row)); ! } ! ! /* constrain v such that l <= v <= u */ ! static inline short limit(const int v, const int l, const int u) ! { ! return (v < l) ? l : ((v > u) ? u : v); ! } ! ! /* set the current selection. Invoked by ioctl(). */ ! int set_selection(const int arg) { ! unsigned short *args, xs, ys, xe, ye; ! int currcons = fg_console; ! int sel_mode, new_sel_start, new_sel_end, spc; ! char *bp, *obp, *spos; ! int i, ps, pe; ! char *off = (char *)origin - hwscroll_offset; ! ! unblank_screen(); ! args = (unsigned short *)(arg + 1); ! xs = get_fs_word(args++) - 1; ! ys = get_fs_word(args++) - 1; ! xe = get_fs_word(args++) - 1; ! ye = get_fs_word(args++) - 1; ! sel_mode = get_fs_word(args); ! ! xs = limit(xs, 0, video_num_columns - 1); ! ys = limit(ys, 0, video_num_lines - 1); ! xe = limit(xe, 0, video_num_columns - 1); ! ye = limit(ye, 0, video_num_lines - 1); ! ps = ys * video_size_row + (xs << 1); ! pe = ye * video_size_row + (xe << 1); ! ! if (ps > pe) /* make sel_start <= sel_end */ ! { ! int tmp = ps; ! ps = pe; ! pe = tmp; ! } ! switch (sel_mode) ! { ! case 0: /* character-by-character selection */ ! default: ! new_sel_start = ps; ! new_sel_end = pe; ! break; ! case 1: /* word-by-word selection */ ! spc = isspace(*(off + ps)); ! for (new_sel_start = ps; ; ps -= 2) ! { ! if ((spc && !isspace(*(off + ps))) || ! (!spc && !inword(*(off + ps)))) ! break; ! new_sel_start = ps; ! if (!(ps % video_size_row)) ! break; ! } ! spc = isspace(*(off + pe)); ! for (new_sel_end = pe; ; pe += 2) ! { ! if ((spc && !isspace(*(off + pe))) || ! (!spc && !inword(*(off + pe)))) ! break; ! new_sel_end = pe; ! if (!((pe + 2) % video_size_row)) ! break; ! } ! break; ! case 2: /* line-by-line selection */ ! new_sel_start = ps - ps % video_size_row; ! new_sel_end = pe + video_size_row ! - pe % video_size_row - 2; ! break; ! } ! /* select to end of line if on trailing space */ ! if (new_sel_end > new_sel_start && ! !atedge(new_sel_end) && isspace(*(off + new_sel_end))) ! { ! for (pe = new_sel_end + 2; ; pe += 2) ! { ! if (!isspace(*(off + pe)) || atedge(pe)) ! break; ! } ! if (isspace(*(off + pe))) ! new_sel_end = pe; ! } ! if (sel_cons != currcons) ! { ! clear_selection(); ! sel_cons = currcons; ! } ! if (sel_start == -1) /* no current selection */ ! highlight(sel_cons, new_sel_start, new_sel_end); ! else if (new_sel_start == sel_start) ! { ! if (new_sel_end == sel_end) /* no action required */ ! return 0; ! else if (new_sel_end > sel_end) /* extend to right */ ! highlight(sel_cons, sel_end + 2, new_sel_end); ! else /* contract from right */ ! highlight(sel_cons, new_sel_end + 2, sel_end); ! } ! else if (new_sel_end == sel_end) ! { ! if (new_sel_start < sel_start) /* extend to left */ ! highlight(sel_cons, new_sel_start, sel_start - 2); ! else /* contract from left */ ! highlight(sel_cons, sel_start, new_sel_start - 2); ! } ! else /* some other case; start selection from scratch */ ! { ! clear_selection(); ! highlight(sel_cons, new_sel_start, new_sel_end); ! } ! sel_start = new_sel_start; ! sel_end = new_sel_end; ! obp = bp = sel_buffer; ! for (i = sel_start; i <= sel_end; i += 2) ! { ! spos = (char *)off + i; ! *bp++ = *spos; ! if (!isspace(*spos)) ! obp = bp; ! if (! ((i + 2) % video_size_row)) ! { ! /* strip trailing blanks from line and add newline, ! unless non-space at end of line. */ ! if (obp != bp) ! { ! bp = obp; ! *bp++ = '\r'; ! } ! obp = bp; ! } ! /* check for space, leaving room for next character, possible ! newline, and null at end. */ ! if (bp - sel_buffer > SEL_BUFFER_SIZE - 3) ! break; ! } ! *bp = '\0'; ! return 0; ! } ! /* insert the contents of the selection buffer into the queue of the ! tty associated with the current console. Invoked by ioctl(). */ ! int paste_selection(struct tty_struct *tty) ! { ! char *bp = sel_buffer; ! if (! *bp) ! return 0; ! unblank_screen(); ! while (*bp) ! { ! put_tty_queue(*bp, &tty->read_q); ! bp++; ! } ! TTY_READ_FLUSH(tty); ! return 0; ! } ! /* remove the current selection highlight, if any, from the console holding ! the selection. */ ! static void clear_selection() ! { ! if (sel_start != -1) ! { ! highlight(sel_cons, sel_start, sel_end); ! sel_start = -1; ! } } + #endif /* CONFIG_SELECTION */ diff -cr --new-file linux-0.07pl4/drivers/char/keyboard.c linux-0.08/drivers/char/keyboard.c *** linux-0.07pl4/drivers/char/keyboard.c Thu Dec 9 17:35:10 1993 --- linux-0.08/drivers/char/keyboard.c Tue Mar 15 13:09:37 1994 *************** *** 17,26 **** --- 17,29 ---- * general 680x0 support by Hamish Macdonald */ + #define KEYBOARD_IRQ 1 + #include #include #include #include + #include #include #include #include *************** *** 44,54 **** --- 47,72 ---- #define KBD_DEFFLAGS (KBD_NUML | (1 << VC_REPEAT) | KBD_META) #endif + /* + * The default IO slowdown is doing 'inb()'s from 0x61, which should be + * safe. But as that is the keyboard controller chip address, we do our + * slowdowns here by doing short jumps: the keyboard controller should + * be able to keep up + */ + #define REALLY_SLOW_IO + #define SLOW_IO_BY_JUMPING + #include + #include + extern void do_keyboard_interrupt(void); + extern void ctrl_alt_del(void); extern void change_console(unsigned int new_console); extern void scrollback(int); extern void scrollfront(int); + #define fake_keyboard_interrupt() \ + __asm__ __volatile__("int $0x21") + unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */ unsigned long kbd_dead_keys = 0; *************** *** 108,113 **** --- 126,132 ---- if (!kbd_dead_keys) kbd_prev_dead_keys = 0; kbd_dead_keys = 0; + mark_bh(KEYBOARD_BH); tty = TTY_TABLE(0); kbd = kbd_table + fg_console; if (vc_kbd_flag(kbd,VC_RAW)) { *************** *** 115,121 **** memset(key_down, 0, sizeof(key_down)); shift_state = 0; put_queue (scancode); ! goto end_kbd_intr; } /* * Repeat a key only if the input buffers are empty or the --- 134,140 ---- memset(key_down, 0, sizeof(key_down)); shift_state = 0; put_queue (scancode); ! return; } /* * Repeat a key only if the input buffers are empty or the *************** *** 145,152 **** key_code = key_map[shift_state][scancode]; (*key_handler[key_code >> 8])(key_code & 0xff, break_flag); } - end_kbd_intr: - do_keyboard_interrupt(); } void put_queue(int ch) --- 164,169 ---- *************** *** 532,537 **** --- 549,618 ---- } } + #if defined(__i386__) + /* + * This routine is the bottom half of the keyboard interrupt + * routine, and runs with all interrupts enabled. It does + * console changing, led setting and copy_to_cooked, which can + * take a reasonably long time. + * + * Aside from timing (which isn't really that important for + * keyboard interrupts as they happen often), using the software + * interrupt routines for this thing allows us to easily mask + * this when we don't want any of the above to happen. Not yet + * used, but this allows for easy and efficient race-condition + * prevention later on. + */ + static void kbd_bh(void * unused) + { + static unsigned char old_leds = 0xff; + unsigned char leds = kbd_table[fg_console].flags & LED_MASK; + + if (leds != old_leds) { + old_leds = leds; + if (!send_data(0xed) || !send_data(leds)) + send_data(0xf4); /* re-enable kbd if any errors */ + } + if (want_console >= 0) { + if (want_console != fg_console) { + last_console = fg_console; + change_console(want_console); + } + want_console = -1; + } + do_keyboard_interrupt(); + cli(); + if ((inb_p(0x64) & kbd_read_mask) == 0x01) + fake_keyboard_interrupt(); + sti(); + } + #else + /* + * This routine is the bottom half of the keyboard interrupt + * routine, and runs with all interrupts enabled. It does + * console changing, led setting and copy_to_cooked, which can + * take a reasonably long time. + * + * Aside from timing (which isn't really that important for + * keyboard interrupts as they happen often), using the software + * interrupt routines for this thing allows us to easily mask + * this when we don't want any of the above to happen. Not yet + * used, but this allows for easy and efficient race-condition + * prevention later on. + */ + static void kbd_bh(void * unused) + { + if (want_console >= 0) { + if (want_console != fg_console) { + last_console = fg_console; + change_console(want_console); + } + want_console = -1; + } + do_keyboard_interrupt(); + } + #endif + unsigned long kbd_init(unsigned long kmem_start) { int i; *************** *** 542,547 **** --- 623,630 ---- kbd->flags = KBD_DEFFLAGS; kbd->default_flags = KBD_DEFFLAGS; } + bh_base[KEYBOARD_BH].routine = kbd_bh; + mark_bh(KEYBOARD_BH); return mach_keyb_init (kmem_start); } diff -cr --new-file linux-0.07pl4/drivers/char/lp.c linux-0.08/drivers/char/lp.c *** linux-0.07pl4/drivers/char/lp.c Wed Dec 31 19:00:00 1969 --- linux-0.08/drivers/char/lp.c Sun Mar 27 09:46:36 1994 *************** *** 0 **** --- 1,398 ---- + /* + * Amiga printer device by Michael Rausch (linux@uni-koblenz.de); + * based upon work from + * + * Copyright (C) 1992 by Jim Weigand and Linus Torvalds + * Copyright (C) 1992,1993 by Michael K. Johnson + * - Thanks much to Gunter Windau for pointing out to me where the error + * checking ought to be. + * Copyright (C) 1993 by Nigel Gamble (added interrupt code) + */ + + #include + #include + #include + #include + #include + #include + #include + + #include + #include + + #include + #include + + /* + * why bother around with the pio driver when the interrupt works; + * so, for "security" reasons only, it's configurable here. + * saves some bytes, at least ... + */ + #define FORCE_POLLING 0 + #define FORCE_INTERRUPT 1 + #define PREFER_INTERRUPT 2 + + #define WHICH_DRIVER FORCE_INTERRUPT + + /* + * All my debugging code assumes that you debug with only one printer at + * a time. RWWH + */ + + #undef LP_DEBUG + + #ifdef LP_DEBUG + static int lp_max_count = 1; + #endif + + + #if WHICH_DRIVER != FORCE_INTERRUPT + static int lp_char_polled(char lpchar) + { + unsigned long count = 0; + + do { + count ++; + if(need_resched) + schedule(); + } while(LP_IS_BUSY && count < LP_CHAR); + + if (count == LP_CHAR) { + return 0; + /* we timed out, and the character was /not/ printed */ + } + #ifdef LP_DEBUG + if (count > lp_max_count) { + printk("lp success after %d counts.\n",count); + lp_max_count=count; + } + #endif + LP_OUT(lpchar); /* strobe is handled in hardware */ + return 1; + } + #endif + + + #ifdef LP_DEBUG + unsigned int lp_total_chars = 0; + unsigned int lp_last_call = 0; + #endif + + + #if WHICH_DRIVER != FORCE_POLLING + static int lp_char_interrupt(char lpchar) + { + if (!LP_IS_BUSY) { + LP_OUT(lpchar); + return 1; + } + return 0; + } + + static int do_print=0; + static unsigned long copy_size, bytes_written; + + static void lp_interrupt(void) + { + if(do_print) + { + if(copy_size) + { + cli(); + if (lp_char_interrupt(lp_table.lp_buffer[bytes_written])) { + --copy_size; + ++bytes_written; + sti(); + } + else + { + do_print=0; + sti(); + wake_up(&lp_table.lp_wait_q); + } + } + else + { + do_print=0; + wake_up(&lp_table.lp_wait_q); + } + + } + } + + #if WHICH_DRIVER == FORCE_INTERRUPT + static int lp_write(struct inode * inode, struct file * file, char * buf, int count) + #else + static int lp_write_interrupt(struct inode * inode, struct file * file, char * buf, int count) + #endif + { + static unsigned long total_bytes_written = 0; + + do { + bytes_written = 0; + copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE); + memcpy_fromfs(lp_table.lp_buffer, buf, copy_size); + + do { + cli(); + do_print=1; + + /* initial output, to trigger the interrupt */ + if (lp_char_interrupt(lp_table.lp_buffer[bytes_written])) { + --copy_size; + ++bytes_written; + sti(); + + /* ok, now wait for the interrupt routine to get ready */ + current->timeout = jiffies + LP_TIMEOUT_INTERRUPT; + interruptible_sleep_on(&lp_table.lp_wait_q); + + /* just to be sure, if we timed out on this here */ + do_print=0; + } + else + { + do_print=0; + sti(); + } + + if(copy_size) { + int rc = total_bytes_written + bytes_written; + + if (LP_HAS_POUT) { + printk("lp0: out of paper\n"); + if (!rc) + rc = -ENOSPC; + } else if (!LP_IS_ONLINE) { + printk("lp0: off-line\n"); + if (!rc) + rc = -EIO; + } else if (LP_IS_BUSY) { + printk("lp0: printer error\n"); + if (!rc) + rc = -EIO; + } + if(LP_F & LP_ABORT) + return rc; + + if (current->signal & ~current->blocked) { + if (total_bytes_written + bytes_written) + return total_bytes_written + bytes_written; + else + return -EINTR; + } + + /* cli(); */ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + LP_TIMEOUT_POLLED; + schedule(); + } + } while(copy_size); + + total_bytes_written += bytes_written; + buf += bytes_written; + count -= bytes_written; + + } while (count > 0); + + return total_bytes_written; + } + #endif + + + #if WHICH_DRIVER != FORCE_INTERRUPT + #if WHICH_DRIVER == FORCE_POLLING + static int lp_write(struct inode * inode, struct file * file, char * buf, int count) + #else + static int lp_write_polled(struct inode * inode, struct file * file, + char * buf, int count) + #endif + { + char *temp = buf; + + #ifdef LP_DEBUG + if (jiffies-lp_last_call > LP_TIME) { + lp_total_chars = 0; + lp_max_count = 1; + } + lp_last_call = jiffies; + #endif + + temp = buf; + while (count > 0) { + if (lp_char_polled( get_fs_byte(temp) )) { + /* only update counting vars if character was printed */ + count--; temp++; + #ifdef LP_DEBUG + lp_total_chars++; + #endif + } else { /* if printer timed out */ + if (LP_HAS_POUT) { + printk("lp0: out of paper\n"); + if(LP_F & LP_ABORT) + return temp-buf?temp-buf:-ENOSPC; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + LP_TIMEOUT_POLLED; + schedule(); + } else + if (!LP_IS_ONLINE) { + printk("lp0: off-line\n"); + if(LP_F & LP_ABORT) + return temp-buf?temp-buf:-EIO; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + LP_TIMEOUT_POLLED; + schedule(); + } else + /* not offline or out of paper. on fire? */ + if (LP_IS_BUSY) { + printk("lp0: on fire\n"); + if(LP_F & LP_ABORT) + return temp-buf?temp-buf:-EFAULT; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + LP_TIMEOUT_POLLED; + schedule(); + } + + /* check for signals before going to sleep */ + if (current->signal & ~current->blocked) { + if (temp != buf) + return temp-buf; + else + return -EINTR; + } + #ifdef LP_DEBUG + printk("lp sleeping at %d characters for %d jiffies\n", + lp_total_chars, LP_TIME); + lp_total_chars=0; + #endif + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + LP_TIME; + schedule(); + } + } + return temp-buf; + } + #endif + + + #if WHICH_DRIVER == PREFER_INTERRUPT + static int lp_write(struct inode * inode, struct file * file, char * buf, int count) + { + if (LP_IRQ) + return lp_write_interrupt(inode, file, buf, count); + else + return lp_write_polled(inode, file, buf, count); + } + #endif + + static int lp_lseek(struct inode * inode, struct file * file, + off_t offset, int origin) + { + return -ESPIPE; + } + + static int lp_open(struct inode * inode, struct file * file) + { + if (MINOR(inode->i_rdev) >= LP_NO) + return -ENODEV; + if (!(LP_F & LP_EXIST)) + return -ENODEV; + if (LP_F & LP_BUSY) + return -EBUSY; + + LP_F |= LP_BUSY; + + ciaa.ddrb = 0xff; /* set the correct data directions */ + ciab.ddra &= 0xf8; /* maybe changed in some plip code */ + + return 0; + } + + static void lp_release(struct inode * inode, struct file * file) + { + LP_F &= ~LP_BUSY; + } + + + static int lp_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) + { + unsigned int minor = MINOR(inode->i_rdev); + int retval = 0; + + #ifdef LP_DEBUG + printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg); + #endif + if (minor >= LP_NO) + return -ENODEV; + if (!(LP_F & LP_EXIST)) + return -ENODEV; + switch ( cmd ) { + case LPTIME: + LP_TIME = arg; + break; + case LPCHAR: + LP_CHAR = arg; + break; + case LPABORT: + if (arg) + LP_F |= LP_ABORT; + else + LP_F &= ~LP_ABORT; + break; + case LPWAIT: /* set/get interrupt is ignored, strobe handled by hardware */ + case LPSETIRQ: + case LPGETIRQ: + break; + default: + retval = -EINVAL; + } + return retval; + } + + + static struct file_operations lp_fops = { + lp_lseek, + NULL, /* lp_read */ + lp_write, + NULL, /* lp_readdir */ + NULL, /* lp_select */ + lp_ioctl, + NULL, /* lp_mmap */ + lp_open, + lp_release + }; + + long lp_init(long kmem_start) + { + if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) { + printk("unable to get major %d for line printer\n", LP_MAJOR); + return kmem_start; + } + + #if WHICH_DRIVER == FORCE_POLLING + lp_table.irq = 0; + printk("lp_init: lp0 using polling driver\n"); + #else + + if((lp_table.irq = mach_add_isr(IRQ_AMIGA_CIAA_FLG, (isrfunc)lp_interrupt, 0, NULL))) + { + lp_table.lp_buffer = (char*)kmem_start; + kmem_start += LP_BUFFER_SIZE; + printk("lp_init: lp0 using cia interrupt\n"); + } + else + + #if WHICH_DRIVER == PREFER_INTERRUPT + printk("lp_init: lp0 using polling driver\n"); + #else + { + printk("cannot get cia interrupt for lp0, and polling driver not configured.\n"); + return kmem_start; + } + #endif + #endif + + LP_F |= LP_EXIST; + return kmem_start; + } diff -cr --new-file linux-0.07pl4/drivers/char/mem.c linux-0.08/drivers/char/mem.c *** linux-0.07pl4/drivers/char/mem.c Sun Dec 12 11:27:20 1993 --- linux-0.08/drivers/char/mem.c Sun Mar 27 09:42:14 1994 *************** *** 362,368 **** #endif #if defined (CONFIG_BUSMOUSE) || defined (CONFIG_82C710_MOUSE) || \ defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \ ! defined (CONFIG_ATIXL_BUSMOUSE) mem_start = mouse_init(mem_start); #endif #ifdef CONFIG_SOUND --- 362,368 ---- #endif #if defined (CONFIG_BUSMOUSE) || defined (CONFIG_82C710_MOUSE) || \ defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \ ! defined (CONFIG_ATIXL_BUSMOUSE) || defined (CONFIG_AMIGAMOUSE) mem_start = mouse_init(mem_start); #endif #ifdef CONFIG_SOUND diff -cr --new-file linux-0.07pl4/drivers/char/mouse.c linux-0.08/drivers/char/mouse.c *** linux-0.07pl4/drivers/char/mouse.c Wed Dec 31 19:00:00 1969 --- linux-0.08/drivers/char/mouse.c Sun Mar 27 09:46:21 1994 *************** *** 0 **** --- 1,72 ---- + /* + * linux/kernel/drivers/char/mouse.c + * + * Generic mouse open routine by Johan Myreen + * + * Based on code from Linus + * + * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's + * changes incorporated into 0.97pl4 + * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92) + * See busmouse.c for particulars. + * + * Made things a lot mode modular - easy to compile in just one or two + * of the mouse drivers, as they are now completely independent. Linus. + * + * Amiga mouse support by Michael Rausch + * + */ + + #include + #include + #include + #include + #include + #include + + /* + * note that you can remove any or all of the drivers by undefining + * the minor values in + */ + extern struct file_operations amiga_mouse_fops; + + extern unsigned long amiga_mouse_init(unsigned long); + + static int mouse_open(struct inode * inode, struct file * file) + { + int minor = MINOR(inode->i_rdev); + + switch (minor) { + #ifdef CONFIG_AMIGAMOUSE + case AMIGAMOUSE_MINOR: + file->f_op = &amiga_mouse_fops; + break; + #endif + default: + return -ENODEV; + } + return file->f_op->open(inode,file); + } + + static struct file_operations mouse_fops = { + NULL, /* seek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + mouse_open, + NULL /* release */ + }; + + unsigned long mouse_init(unsigned long kmem_start) + { + #ifdef CONFIG_AMIGAMOUSE + kmem_start = amiga_mouse_init(kmem_start); + #endif + if (register_chrdev(MOUSE_MAJOR,"mouse",&mouse_fops)) + printk("unable to get major %d for mouse devices\n", + MOUSE_MAJOR); + return kmem_start; + } diff -cr --new-file linux-0.07pl4/drivers/scsi/a2091.c linux-0.08/drivers/scsi/a2091.c *** linux-0.07pl4/drivers/scsi/a2091.c Sat Mar 19 15:15:05 1994 --- linux-0.08/drivers/scsi/a2091.c Sun Mar 27 09:59:31 1994 *************** *** 1,4 **** - #include #include #include #include --- 1,3 ---- *************** *** 37,43 **** restore_flags (flags); /* enable PORTS interrupt */ custom.intena = IF_SETCLR | IF_PORTS; ! } } } --- 36,42 ---- restore_flags (flags); /* enable PORTS interrupt */ custom.intena = IF_SETCLR | IF_PORTS; ! } } } *************** *** 59,65 **** /* invalidate any cache */ cache_clear (addr, cmd->SCp.this_residual); else ! /* push any dirty cache */ cache_push (addr, cmd->SCp.this_residual); /* start DMA */ --- 58,64 ---- /* invalidate any cache */ cache_clear (addr, cmd->SCp.this_residual); else ! /* push any dirty cache */ cache_push (addr, cmd->SCp.this_residual); /* start DMA */ *************** *** 114,120 **** instance->base = (unsigned char *)address; DMA(instance)->DAWR = DAWR_A2091; wd33c93_init(instance, (wd33c93_regs *)&(DMA(instance)->SASR), ! dma_setup, dma_stop, A2091_XFER_MASK, WD33C93_FS_8_10); host_nr++; if (num_a2091++ == 0) { --- 113,119 ---- instance->base = (unsigned char *)address; DMA(instance)->DAWR = DAWR_A2091; wd33c93_init(instance, (wd33c93_regs *)&(DMA(instance)->SASR), ! dma_setup, dma_stop, A2091_XFER_MASK, WD33C93_FS_8_10); host_nr++; if (num_a2091++ == 0) { *************** *** 123,129 **** add_isr(IRQ_AMIGA_PORTS, a2091_intr, 0, NULL); } DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; ! } } return num_a2091; --- 122,128 ---- add_isr(IRQ_AMIGA_PORTS, a2091_intr, 0, NULL); } DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; ! } } return num_a2091; diff -cr --new-file linux-0.07pl4/drivers/scsi/a3000.c linux-0.08/drivers/scsi/a3000.c *** linux-0.07pl4/drivers/scsi/a3000.c Sat Mar 19 15:15:05 1994 --- linux-0.08/drivers/scsi/a3000.c Sun Mar 27 09:59:21 1994 *************** *** 1,4 **** - #include #include #include #include --- 1,3 ---- *************** *** 20,26 **** unsigned long flags; if (!(status & (ISTR_INT_F|ISTR_INT_P))) ! return; if (status & ISTR_INTS) { --- 19,25 ---- unsigned long flags; if (!(status & (ISTR_INT_F|ISTR_INT_P))) ! return; if (status & ISTR_INTS) { diff -cr --new-file linux-0.07pl4/drivers/scsi/gvp11.c linux-0.08/drivers/scsi/gvp11.c *** linux-0.07pl4/drivers/scsi/gvp11.c Sat Mar 19 15:15:05 1994 --- linux-0.08/drivers/scsi/gvp11.c Sun Mar 27 09:59:28 1994 *************** *** 1,4 **** - #include #include #include #include --- 1,3 ---- diff -cr --new-file linux-0.07pl4/fs/affs/amigaffs.h linux-0.08/fs/affs/amigaffs.h *** linux-0.07pl4/fs/affs/amigaffs.h Tue Sep 7 17:18:39 1993 --- linux-0.08/fs/affs/amigaffs.h Mon Mar 28 14:06:47 1994 *************** *** 47,57 **** #define ST_USERDIR 2 #define ST_ROOT 1 ! #define PROT_ARCHIVE (1<<4) ! #define PROT_READ (1<<3) ! #define PROT_WRITE (1<<2) ! #define PROT_EXECUTE (1<<1) ! #define PROT_DELETE (1<<0) struct ffs_root_front { --- 47,67 ---- #define ST_USERDIR 2 #define ST_ROOT 1 ! #define PROT_ARCHIVE (1<<4) ! #define PROT_READ (1<<3) ! #define PROT_WRITE (1<<2) ! #define PROT_EXECUTE (1<<1) ! #define PROT_DELETE (1<<0) ! ! #define PROT_OTR_READ (1<<15) ! #define PROT_OTR_WRITE (1<<14) ! #define PROT_OTR_EXECUTE (1<<13) ! #define PROT_OTR_DELETE (1<<12) ! ! #define PROT_GRP_READ (1<<11) ! #define PROT_GRP_WRITE (1<<10) ! #define PROT_GRP_EXECUTE (1<<9) ! #define PROT_GRP_DELETE (1<<8) struct ffs_root_front { *************** *** 86,92 **** struct dir_end { ! ULONG spare1[2]; ULONG protect; ULONG spare2; UBYTE comment[92]; --- 96,104 ---- struct dir_end { ! ULONG spare1; ! UWORD uid; ! UWORD gid; ULONG protect; ULONG spare2; UBYTE comment[92]; *************** *** 111,117 **** struct file_end { ! ULONG spare1[2]; ULONG protect; ULONG byte_size; UBYTE comment[92]; --- 123,131 ---- struct file_end { ! ULONG spare1; ! UWORD uid; ! UWORD gid; ULONG protect; ULONG byte_size; UBYTE comment[92]; diff -cr --new-file linux-0.07pl4/fs/affs/inode.c linux-0.08/fs/affs/inode.c *** linux-0.07pl4/fs/affs/inode.c Mon Dec 13 14:43:12 1993 --- linux-0.08/fs/affs/inode.c Mon Mar 28 14:06:49 1994 *************** *** 1,6 **** --- 1,8 ---- /* * linux/fs/affs/inode.c * + * (C) 1994 Geert Uytterhoeven - Modified for MultiUserFileSystem + * * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. * * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. *************** *** 81,86 **** --- 83,89 ---- return 1; for (this_opt = strtok(options,","); this_opt; this_opt = strtok(NULL,",")) { if ((value = strchr(this_opt,'='))) *value++ = 0; + printk ("this_opt=%s, value=%p\n", this_opt, value); if (!strcmp(this_opt,"offset") && value) { n = simple_strtoul (value, &end, 10); if (end == value || *end != 0) *************** *** 114,124 **** for (gd_p = gendisk_head ; gd_p ; gd_p=gd_p->next) { if (gd_p->major != MAJOR(dev)) continue; ! dev_size = gd_p->sizes[MINOR(dev)]; break; } ! /* FIXME: Assumes 512 byte FFS blocks *and* 1024 byte dev blocks. */ ! return dev_size * 2; } struct super_block *affs_read_super(struct super_block *s,void *data, --- 117,126 ---- for (gd_p = gendisk_head ; gd_p ; gd_p=gd_p->next) { if (gd_p->major != MAJOR(dev)) continue; ! dev_size = gd_p->part[MINOR(dev)].nr_sects; break; } ! return dev_size; } struct super_block *affs_read_super(struct super_block *s,void *data, *************** *** 160,166 **** if (!root_block) root_block = (s->u.affs_sb.s_partition_offset ! + s->u.affs_sb.s_partition_size / 2); s->u.affs_sb.s_root_block = root_block; s->u.affs_sb.s_block_size = AFFS_BLOCK_SIZE; --- 162,169 ---- if (!root_block) root_block = (s->u.affs_sb.s_partition_offset ! + s->u.affs_sb.s_partition_size / 2 ! + (s->u.affs_sb.s_partition_size & 1)); s->u.affs_sb.s_root_block = root_block; s->u.affs_sb.s_block_size = AFFS_BLOCK_SIZE; *************** *** 245,250 **** --- 248,265 ---- /* Don't know what value to put in buf->f_fsid */ } + static int prot_table[9][2] = { + PROT_OTR_EXECUTE, PROT_OTR_EXECUTE, /* other: 1 = allowed */ + PROT_OTR_WRITE, PROT_OTR_WRITE, + PROT_OTR_READ, PROT_OTR_READ, + PROT_GRP_EXECUTE, PROT_GRP_EXECUTE, /* group: 1 = allowed */ + PROT_GRP_WRITE, PROT_GRP_WRITE, + PROT_GRP_READ, PROT_GRP_READ, + PROT_EXECUTE, 0, /* owner: 0 = allowed */ + PROT_WRITE, 0, + PROT_READ, 0 + }; + void affs_read_inode(struct inode * inode) { struct buffer_head *bh; *************** *** 252,257 **** --- 267,273 ---- void *fh_data; struct file_front *file_front; struct file_end *file_end; + int i; #ifdef DEBUG printk ("AFFS: entering affs_read_inode\n"); *************** *** 270,284 **** inode->u.affs_i.i_protect = file_end->protect; inode->u.affs_i.i_parent = swap_long (file_end->parent); ! inode->i_mode = 0444; /* Everybody gets to read the file. */ ! if (!(inode->u.affs_i.i_protect & PROT_WRITE)) ! inode->i_mode |= 0222; ! if (!(inode->u.affs_i.i_protect & PROT_EXECUTE)) ! inode->i_mode |= 0111; inode->i_nlink = 1; if (file_end->secondary_type != swap_long ((ulong)ST_FILE)) { ! inode->i_mode |= 0111 | S_IFDIR; inode->i_nlink = 2; /* There are always at least 2. It is hard to figure out what is correct*/ inode->i_size = 0; --- 286,300 ---- inode->u.affs_i.i_protect = file_end->protect; inode->u.affs_i.i_parent = swap_long (file_end->parent); ! inode->i_mode = 0; ! for (i = 0; i < 9; i++) ! if ((prot_table[i][0] & inode->u.affs_i.i_protect) == prot_table[i][1]) ! inode->i_mode |= 1<i_nlink = 1; if (file_end->secondary_type != swap_long ((ulong)ST_FILE)) { ! inode->i_mode |= ((inode->i_mode & 0444)>>2) | S_IFDIR; inode->i_nlink = 2; /* There are always at least 2. It is hard to figure out what is correct*/ inode->i_size = 0; *************** *** 287,294 **** inode->i_mode |= S_IFREG; inode->i_size = swap_long (file_end->byte_size); }; ! inode->i_uid = 0; ! inode->i_gid = 0; #ifdef DEBUG printk ("AFFS: read inode %d: size=%d\n", block, inode->i_size); --- 303,320 ---- inode->i_mode |= S_IFREG; inode->i_size = swap_long (file_end->byte_size); }; ! if (file_end->uid == 0xffff) ! inode->i_uid = 0; /* root uid */ ! else if (file_end->uid == 0x0000) ! inode->i_uid = -1; /* unknown uid */ ! else ! inode->i_uid = file_end->uid; ! if (file_end->gid == 0xffff) ! inode->i_gid = 0; /* root gid */ ! else if (file_end->gid == 0x0000) ! inode->i_gid = -1; /* unknown gid */ ! else ! inode->i_gid = file_end->gid; #ifdef DEBUG printk ("AFFS: read inode %d: size=%d\n", block, inode->i_size); diff -cr --new-file linux-0.07pl4/fs/exec.c linux-0.08/fs/exec.c *** linux-0.07pl4/fs/exec.c Tue Jan 4 18:17:03 1994 --- linux-0.08/fs/exec.c Thu Mar 10 17:25:34 1994 *************** *** 116,132 **** * field, which also makes sure the core-dumps won't be recursive if the * dumping of the process results in another error.. */ int core_dump(long signr, struct pt_regs * regs) { - #if 0 struct inode * inode = NULL; struct file file; unsigned short fs; - #endif int has_dumped = 0; - #if 0 char corefile[6+sizeof(current->comm)]; - int i; register int dump_start, dump_size; struct user dump; --- 116,131 ---- * field, which also makes sure the core-dumps won't be recursive if the * dumping of the process results in another error.. */ + extern void arch_core_dump (struct user *up, long signr, + struct pt_regs *regs); + int core_dump(long signr, struct pt_regs * regs) { struct inode * inode = NULL; struct file file; unsigned short fs; int has_dumped = 0; char corefile[6+sizeof(current->comm)]; register int dump_start, dump_size; struct user dump; *************** *** 162,205 **** if (!file.f_op->write) goto close_coredump; has_dumped = 1; /* changed the size calculations - should hopefully work better. lbt */ - dump.magic = CMAGIC; - dump.start_code = 0; - dump.start_stack = regs->esp & ~(PAGE_SIZE - 1); - dump.u_tsize = ((unsigned long) current->end_code) >> 12; - dump.u_dsize = ((unsigned long) (current->brk + (PAGE_SIZE-1))) >> 12; - dump.u_dsize -= dump.u_tsize; - dump.u_ssize = 0; - for(i=0; i<8; i++) dump.u_debugreg[i] = current->debugreg[i]; - if (dump.start_stack < TASK_SIZE) - dump.u_ssize = ((unsigned long) (TASK_SIZE - dump.start_stack)) >> 12; - /* If the size of the dump file exceeds the rlimit, then see what would happen - if we wrote the stack, but not the data area. */ - if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE > - current->rlim[RLIMIT_CORE].rlim_cur) - dump.u_dsize = 0; - /* Make sure we have enough room to write the stack and data areas. */ - if ((dump.u_ssize+1) * PAGE_SIZE > - current->rlim[RLIMIT_CORE].rlim_cur) - dump.u_ssize = 0; - strncpy(dump.u_comm, current->comm, sizeof(current->comm)); - dump.u_ar0 = (struct pt_regs *)(((int)(&dump.regs)) -((int)(&dump))); - dump.signal = signr; - dump.regs = *regs; - /* Flag indicating the math stuff is valid. We don't support this for the - soft-float routines yet */ - if (hard_math) { - if ((dump.u_fpvalid = current->used_math) != 0) { - if (last_task_used_math == current) - __asm__("clts ; fnsave %0": :"m" (dump.i387)); - else - memcpy(&dump.i387,¤t->tss.i387.hard,sizeof(dump.i387)); - } - } else { - /* we should dump the emulator state here, but we need to - convert it into standard 387 format first.. */ - dump.u_fpvalid = 0; - } set_fs(KERNEL_DS); /* struct user */ DUMP_WRITE(&dump,sizeof(dump)); --- 161,169 ---- if (!file.f_op->write) goto close_coredump; has_dumped = 1; + /* architecture specific stuff */ + arch_core_dump (&dump, signr, regs); /* changed the size calculations - should hopefully work better. lbt */ set_fs(KERNEL_DS); /* struct user */ DUMP_WRITE(&dump,sizeof(dump)); *************** *** 228,234 **** end_coredump: set_fs(fs); iput(inode); - #endif return has_dumped; } --- 192,197 ---- diff -cr --new-file linux-0.07pl4/fs/ext2/Makefile linux-0.08/fs/ext2/Makefile *** linux-0.07pl4/fs/ext2/Makefile Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/Makefile Tue Feb 1 16:43:18 1994 *************** *** 0 **** --- 1,26 ---- + # + # Makefile for the linux ext2-filesystem routines. + # + # Note! Dependencies are done automagically by 'make dep', which also + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # + # Note 2! The CFLAGS definitions are now in the main makefile... + + include ../../MakeVars + + OBJS= acl.o balloc.o bitmap.o dcache.o dir.o file.o fsync.o \ + ialloc.o inode.o ioctl.o namei.o super.o symlink.o truncate.o + + ext2.o: $(OBJS) + $(LD) -r -o ext2.o $(OBJS) + + dep: + $(CPP) -M $(INCFLAGS) *.c > .depend + + # + # include a dependency file if one exists + # + ifeq (.depend,$(wildcard .depend)) + include .depend + endif diff -cr --new-file linux-0.07pl4/fs/ext2/acl.c linux-0.08/fs/ext2/acl.c *** linux-0.07pl4/fs/ext2/acl.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/acl.c Mon Nov 22 12:17:43 1993 *************** *** 0 **** --- 1,40 ---- + /* + * linux/fs/ext2/acl.c + * + * Copyright (C) 1993 Remy Card (card@masi.ibp.fr) + */ + + /* + * This file will contain the Access Control Lists management for the + * second extended file system. + */ + + #include + #include + #include + #include + #include + #include + + /* + * ext2_permission () + * + * Check for access rights + */ + int ext2_permission (struct inode * inode, int mask) + { + unsigned short mode = inode->i_mode; + + /* Special case, access is always granted for root */ + if (suser ()) + return 1; + /* If no ACL, checks using the file mode */ + else if (current->euid == inode->i_uid) + mode >>= 6; + else if (in_group_p (inode->i_gid)) + mode >>= 3; + if (((mode & mask & S_IRWXO) == mask)) + return 1; + else + return 0; + } diff -cr --new-file linux-0.07pl4/fs/ext2/balloc.c linux-0.08/fs/ext2/balloc.c *** linux-0.07pl4/fs/ext2/balloc.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/balloc.c Sat Mar 19 12:26:27 1994 *************** *** 0 **** --- 1,738 ---- + /* + * linux/fs/ext2/balloc.c + * + * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) + * + * Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 + */ + + /* balloc.c contains the blocks allocation and deallocation routines */ + + /* + + The free blocks are managed by bitmaps. A file system contains several + blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap + block for inodes, N blocks for the inode table and data blocks. + + The file system contains group descriptors which are located after the + super block. Each descriptor contains the number of the bitmap block and + the free blocks count in the block. The descriptors are loaded in memory + when a file system is mounted (see ext2_read_super). + + */ + + #include + #include + #include + #include + #include + #include + #include + + #include + + #if defined(__i386__) + #define clear_block(addr,size) \ + __asm__("cld\n\t" \ + "rep\n\t" \ + "stosl" \ + : \ + :"a" (0), "c" (size / 4), "D" ((long) (addr)) \ + :"cx", "di") + #else + #define clear_block(addr,size) (memset(addr,0,size)) + #endif + + #if defined(__i386__) + static inline int find_first_zero_bit (unsigned long * addr, unsigned size) + { + int res; + + if (!size) + return 0; + __asm__(" + cld + movl $-1,%%eax + repe; scasl + je 1f + subl $4,%%edi + movl (%%edi),%%eax + notl %%eax + bsfl %%eax,%%edx + jmp 2f + 1: xorl %%edx,%%edx + 2: subl %%ebx,%%edi + shll $3,%%edi + addl %%edi,%%edx" + :"=d" (res) + :"c" ((size + 31) >> 5), "D" (addr), "b" (addr) + :"ax", "bx", "cx", "di"); + return res; + } + + static inline int find_next_zero_bit (unsigned long * addr, int size, + int offset) + { + unsigned long * p = ((unsigned long *) addr) + (offset >> 5); + int set = 0, bit = offset & 31, res; + + if (bit) { + /* Look for zero in first byte */ + __asm__(" + bsfl %1,%0 + jne 1f + movl $32, %0 + 1: " + : "=r" (set) + : "r" (~(*p >> bit))); + if (set < (32 - bit)) + return set + offset; + set = 32 - bit; + p++; + } + /* No zero yet, search remaining full bytes for a zero */ + res = find_first_zero_bit (p, size - 32 * (p - addr)); + return (offset + set + res); + } + + static inline char * find_first_zero_byte (char * addr, int size) + { + char *res; + + if (!size) + return 0; + __asm__(" + cld + mov $0,%%eax + repnz; scasb + jnz 1f + dec %%edi + 1: " + : "=D" (res) + : "0" (addr), "c" (size) + : "ax"); + return res; + } + + #define findbit(k,lmap) __asm__ ("bsfl %1,%0" \ + : "=r" (k) \ + : "r" (~(lmap))) + #elif defined(__mc68000__) + static inline int find_first_zero_bit(unsigned long * addr, unsigned size) + { + unsigned long res; + void *p = addr; + + if (!size) + return 0; + __asm__ __volatile__ ("1:" + " movel %1@+,d1\n\t" + " cmpl %4,d1\n\t" + " bne 2f\n\t" + " addl %5,%0\n\t" + " cmpl %6,%0\n\t" + " bcs 1b\n\t" + " bra 5f\n\t" + "2:" + " moveq #0,d2\n\t" + "3:" + " btst d2,d1\n\t" + " beq 4f\n\t" + " addql #1,d2\n\t" + " bra 3b\n\t" + "4:" + " addl d2,%0\n\t" + "5:" + : "=d" (res), "=a" (p) + : "0" (0), "1" (p), + "g" (0xffffffff), "g" (32), "g" (8192) + : "d1", "d2"); + return res; + } + + static inline int find_next_zero_bit (unsigned long * addr, int size, + int offset) + { + unsigned long * p = ((unsigned long *) addr) + (offset >> 5); + int set = 0, bit = offset & 31, res; + + if (bit) { + /* Look for zero in first byte */ + __asm__(" + moveq #0,%0 + 1: btst %0,%1 + beq 2f + addql #1,%0 + cmpb #32,%0 + bne 1b + 2: " + : "=&d" (set) + : "d" (*p >> bit)); + if (set < (32 - bit)) + return set + offset; + set = 32 - bit; + p++; + } + /* No zero yet, search remaining full bytes for a zero */ + res = find_first_zero_bit (p, size - 32 * (p - addr)); + return (offset + set + res); + } + + static inline char * find_first_zero_byte (char * addr, int size) + { + while (size--) { + if (!*addr) + break; + addr++; + } + /* + * argghh... the bits are numbered differently on the i386 and 680x0 + * (layout in memory) + * i386 -> [7-0] [15-8] [23-16][31-24] + * m68k -> [31-24][23-16][15-8] [7-0] + + * This causes problems when the caller of find_first_zero_byte * + * assumes that the bit address of the first bit in the byte is the + * byte address multiplied * by 8. This is true on the i386, but not + * on the m68k. + * Thus, we'll "massage" the return value of this function so that it + * can be multiplied by 8 to give the bit offset of the first available + * bit in the byte and hope that no-one uses this in a different manner. + */ + addr = (char *)(((unsigned long)addr & ~3) + 3-((unsigned long)addr)); + return addr; + } + + #define findbit(k,lmap) __asm__ __volatile__ (" \ + moveq #0,%0 \n\ + 1: \n\ + btst %0,%1 \n\ + beq 2f \n\ + addql #1,%0 \n\ + cmpb #32,%0 \n\ + bne 1b \n\ + 2: \n\ + nop" \ + : "=&d" (k) \ + : "d" (lmap)) + + #endif + + static void read_block_bitmap (struct super_block * sb, + unsigned int block_group, + unsigned long bitmap_nr) + { + unsigned long group_desc; + unsigned long desc; + struct ext2_group_desc * gdp; + struct buffer_head * bh; + + group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); + desc = block_group % EXT2_DESC_PER_BLOCK(sb); + if (!sb->u.ext2_sb.s_group_desc[group_desc]) + ext2_panic (sb, "read_block_bitmap", + "Group descriptor not loaded\n" + "block_group = %d, group_desc = %lu, desc = %lu", + block_group, group_desc, desc); + gdp = (struct ext2_group_desc *) + sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + bh = bread (sb->s_dev, gdp[desc].bg_block_bitmap, sb->s_blocksize); + if (!bh) + ext2_panic (sb, "read_block_bitmap", + "Cannot read block bitmap\n" + "block_group = %d, group_desc = %lu," + "desc = %lu, block_bitmap = %lu", + block_group, group_desc, desc, + gdp[desc].bg_block_bitmap); + sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group; + sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh; + } + + /* + * load_block_bitmap loads the block bitmap for a blocks group + * + * It maintains a cache for the last bitmaps loaded. This cache is managed + * with a LRU algorithm. + * + * Notes: + * 1/ There is one cache per mounted file system. + * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups, + * this function reads the bitmap without maintaining a LRU cache. + */ + static int load__block_bitmap (struct super_block * sb, + unsigned int block_group) + { + int i, j; + unsigned long block_bitmap_number; + struct buffer_head * block_bitmap; + + if (block_group >= sb->u.ext2_sb.s_groups_count) + ext2_panic (sb, "load_block_bitmap", + "block_group >= groups_count\n" + "block_group = %d, groups_count = %lu", + block_group, sb->u.ext2_sb.s_groups_count); + + if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) { + if (sb->u.ext2_sb.s_block_bitmap[block_group]) { + if (sb->u.ext2_sb.s_block_bitmap_number[block_group] != + block_group) + ext2_panic (sb, "load_block_bitmap", + "block_group != block_bitmap_number"); + else + return block_group; + } else { + read_block_bitmap (sb, block_group, block_group); + return block_group; + } + } + + for (i = 0; i < sb->u.ext2_sb.s_loaded_block_bitmaps && + sb->u.ext2_sb.s_block_bitmap_number[i] != block_group; i++) + ; + if (i < sb->u.ext2_sb.s_loaded_block_bitmaps && + sb->u.ext2_sb.s_block_bitmap_number[i] == block_group) { + block_bitmap_number = sb->u.ext2_sb.s_block_bitmap_number[i]; + block_bitmap = sb->u.ext2_sb.s_block_bitmap[i]; + for (j = i; j > 0; j--) { + sb->u.ext2_sb.s_block_bitmap_number[j] = + sb->u.ext2_sb.s_block_bitmap_number[j - 1]; + sb->u.ext2_sb.s_block_bitmap[j] = + sb->u.ext2_sb.s_block_bitmap[j - 1]; + } + sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number; + sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap; + } else { + if (sb->u.ext2_sb.s_loaded_block_bitmaps < + EXT2_MAX_GROUP_LOADED) + sb->u.ext2_sb.s_loaded_block_bitmaps++; + else + brelse (sb->u.ext2_sb.s_block_bitmap + [EXT2_MAX_GROUP_LOADED - 1]); + for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) { + sb->u.ext2_sb.s_block_bitmap_number[j] = + sb->u.ext2_sb.s_block_bitmap_number[j - 1]; + sb->u.ext2_sb.s_block_bitmap[j] = + sb->u.ext2_sb.s_block_bitmap[j - 1]; + } + read_block_bitmap (sb, block_group, 0); + } + return 0; + } + + static inline int load_block_bitmap (struct super_block * sb, + unsigned int block_group) + { + if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 && + sb->u.ext2_sb.s_block_bitmap_number[0] == block_group) + return 0; + + if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED && + sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group && + sb->u.ext2_sb.s_block_bitmap[block_group]) + return block_group; + + return load__block_bitmap (sb, block_group); + } + + void ext2_free_block (struct super_block * sb, unsigned long block) + { + struct buffer_head * bh; + struct buffer_head * bh2; + unsigned long block_group; + unsigned long bit; + unsigned long group_desc; + unsigned long desc; + int bitmap_nr; + struct ext2_group_desc * gdp; + struct ext2_super_block * es; + + if (!sb) { + printk ("ext2_free_block: nonexistent device"); + return; + } + lock_super (sb); + es = sb->u.ext2_sb.s_es; + if (block < es->s_first_data_block || block >= es->s_blocks_count) { + ext2_error (sb, "ext2_free_block", "block not in datazone"); + unlock_super (sb); + return; + } + + ext2_debug ("freeing block %lu\n", block); + + #if 0 /* XXX - This is incompatible with the secure rm implemented in 0.4 */ + bh = get_hash_table (sb->s_dev, block, sb->s_blocksize); + if (bh) + bh->b_dirt = 0; + brelse (bh); + #endif + block_group = (block - es->s_first_data_block) / + EXT2_BLOCKS_PER_GROUP(sb); + bit = (block - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb); + bitmap_nr = load_block_bitmap (sb, block_group); + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; + if (!bh) + ext2_panic (sb, "ext2_free_block", + "Unable to load group bitmap\n" + "block_group = %lu", block_group); + if (!clear_bit (bit, bh->b_data)) + ext2_warning (sb, "ext2_free_block", + "bit already cleared for block %lu", block); + else { + group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); + desc = block_group % EXT2_DESC_PER_BLOCK(sb); + bh2 = sb->u.ext2_sb.s_group_desc[group_desc]; + if (!bh2) + ext2_panic (sb, "ext2_free_block", + "Group descriptor not loaded\n" + "group_desc = %lu", group_desc); + gdp = (struct ext2_group_desc *) bh2->b_data; + gdp[desc].bg_free_blocks_count++; + bh2->b_dirt = 1; + es->s_free_blocks_count++; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + } + bh->b_dirt = 1; + if (sb->s_flags & MS_SYNC) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + sb->s_dirt = 1; + unlock_super (sb); + return; + } + + /* + * ext2_new_block uses a goal block to assist allocation. If the goal is + * free, or there is a free block within 32 blocks of the goal, that block + * is allocated. Otherwise a forward search is made for a free block; within + * each block group the search first looks for an entire free byte in the block + * bitmap, and then for any free bit if that fails. + */ + int ext2_new_block (struct super_block * sb, unsigned long goal) + { + struct buffer_head * bh; + char *p, *r; + int i, j, k; + unsigned long lmap; + unsigned long group_desc; + unsigned long desc; + int bitmap_nr; + struct ext2_group_desc * gdp; + struct ext2_super_block * es; + + #ifdef EXT2FS_DEBUG + static int goal_hits = 0, goal_attempts = 0; + #endif + if (!sb) { + printk ("ext2_new_block: nonexistent device"); + return 0; + } + lock_super (sb); + es = sb->u.ext2_sb.s_es; + if (es->s_free_blocks_count <= es->s_r_blocks_count && !suser()) { + unlock_super (sb); + return 0; + } + + ext2_debug ("goal=%lu.\n", goal); + + repeat: + /* First, test whether the goal block is free. */ + i = ((goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb)); + group_desc = i / EXT2_DESC_PER_BLOCK(sb); + desc = i % EXT2_DESC_PER_BLOCK(sb); + gdp = (struct ext2_group_desc *) + sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + if (!gdp) { + ext2_panic (sb, "ext2_new_block", + "Descriptor not loaded for group %d", i); + } + if (gdp[desc].bg_free_blocks_count > 0) { + j = ((goal - es->s_first_data_block) % + EXT2_BLOCKS_PER_GROUP(sb)); + #ifdef EXT2FS_DEBUG + if (j) + goal_attempts++; + #endif + bitmap_nr = load_block_bitmap (sb, i); + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; + if (!bh) { + ext2_panic (sb, "ext2_new_block", + "Cannot load bitmap %d", bitmap_nr); + unlock_super (sb); + return 0; + } + + ext2_debug ("goal is at %d[%lu,%lu]:%d.\n", i, group_desc, + desc, j); + if (!test_bit(j, bh->b_data)) { + #ifdef EXT2FS_DEBUG + goal_hits++; + ext2_debug ("goal bit allocated.\n"); + #endif + goto got_block; + } + if (j) { + /* The goal was occupied; search forward for a free + block within the next 32 blocks */ + lmap = ((((unsigned long *) bh->b_data)[j >> 5]) >> + ((j & 31) + 1)); + if (j < EXT2_BLOCKS_PER_GROUP(sb) - 32) + lmap |= (((unsigned long *) bh->b_data)[(j >> 5) + 1]) << + (31 - (j & 31)); + else + lmap |= 0xffffffff << (31 - (j & 31)); + if (lmap != 0xffffffffl) { + findbit(k,lmap); + k++; + if ((j + k) < EXT2_BLOCKS_PER_GROUP(sb)) { + j += k; + goto got_block; + } + } + } + + ext2_debug ("Bit not found near goal\n"); + + /* There has been no free block found in the near vicinity + of the goal: do a search forward through the block groups, + searching in each group first for an entire free byte in + the bitmap and then for any free bit. + + Search first in the remainder of the current group; then, + cyclicly search throught the rest of the groups. */ + p = ((char *) bh->b_data) + (j >> 3); + ext2_debug ("j=%d, bh->b_data=%p\n", j, bh->b_data); + r = find_first_zero_byte (p, + (EXT2_BLOCKS_PER_GROUP(sb) - j + 7) >> 3); + k = (r - ((char *) bh->b_data)) << 3; + if (k < EXT2_BLOCKS_PER_GROUP(sb)) { + j = k; + goto got_block; + } + k = find_next_zero_bit ((unsigned long *) bh->b_data, + EXT2_BLOCKS_PER_GROUP(sb), + j); + if (k < EXT2_BLOCKS_PER_GROUP(sb)) { + j = k; + goto got_block; + } + } + + ext2_debug ("Bit not found in block group %d.\n", i); + + /* Now search the rest of the groups. We assume that group_desc, desc, + i and gdp correctly point to the last group visited. */ + for (k = 0; k < sb->u.ext2_sb.s_groups_count; k++) { + i++; + if (i >= sb->u.ext2_sb.s_groups_count) { + i = 0; + group_desc = 0; + desc = 0; + gdp = (struct ext2_group_desc *) + sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + } + else { + desc++; + if (desc >= EXT2_DESC_PER_BLOCK(sb)) { + group_desc++; + desc = 0; + gdp = (struct ext2_group_desc *) + sb->u.ext2_sb.s_group_desc[group_desc] + ->b_data; + } + } + if (!gdp) { + ext2_panic (sb, "ext2_new_block", + "Descriptor not loaded for group %d", i); + } + if (gdp[desc].bg_free_blocks_count > 0) + break; + } + if (k >= sb->u.ext2_sb.s_groups_count) { + unlock_super (sb); + return 0; + } + bitmap_nr = load_block_bitmap (sb, i); + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; + if (!bh) + ext2_panic (sb, "ext2_new_block", + "Unable to load bitmap for group %d", i); + r = find_first_zero_byte (bh->b_data, + EXT2_BLOCKS_PER_GROUP(sb) >> 3); + j = (r - bh->b_data) << 3; + if (j >= EXT2_BLOCKS_PER_GROUP(sb)) + j = find_first_zero_bit ((unsigned long *) bh->b_data, + EXT2_BLOCKS_PER_GROUP(sb)); + if (j >= EXT2_BLOCKS_PER_GROUP(sb)) { + ext2_error (sb, "ext2_new_block", + "Unable to locate free bit in block group %d", i); + unlock_super (sb); + return 0; + } + + got_block: + + ext2_debug ("using block group %d(%lu,%lu,%d)\n", + i, group_desc, desc, gdp[desc].bg_free_blocks_count); + + if (set_bit (j, bh->b_data)) { + ext2_warning (sb, "ext2_new_block", + "bit already set for block %d", j); + goto repeat; + } + bh->b_dirt = 1; + if (sb->s_flags & MS_SYNC) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + + ext2_debug ("found bit %d\n", j); + + j += i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block; + if (j >= es->s_blocks_count) { + ext2_error (sb, "ext2_new_block", + "block >= blocks count\n" + "block_group = %d, block=%d", i, j); + unlock_super (sb); + return 0; + } + if (!(bh = getblk (sb->s_dev, j, sb->s_blocksize))) { + ext2_error (sb, "ext2_new_block", "cannot get block %d", j); + unlock_super (sb); + return 0; + } + clear_block (bh->b_data, sb->s_blocksize); + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse (bh); + + ext2_debug ("allocating block %d. " + "Goal hits %d of %d.\n", j, goal_hits, goal_attempts); + + gdp[desc].bg_free_blocks_count--; + sb->u.ext2_sb.s_group_desc[group_desc]->b_dirt = 1; + es->s_free_blocks_count--; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + unlock_super (sb); + return j; + } + + unsigned long ext2_count_free_blocks (struct super_block * sb) + { + #ifdef EXT2FS_DEBUG + struct ext2_super_block * es; + unsigned long desc_count, bitmap_count, x; + unsigned long group_desc; + unsigned long desc; + int bitmap_nr; + struct ext2_group_desc * gdp; + int i; + + lock_super (sb); + es = sb->u.ext2_sb.s_es; + desc_count = 0; + bitmap_count = 0; + group_desc = 0; + desc = 0; + gdp = NULL; + for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { + if (!gdp) { + if (!sb->u.ext2_sb.s_group_desc[group_desc]) { + printk ("ext2_count_free_block: " + "Descriptor not loaded\n"); + break; + } + gdp = (struct ext2_group_desc *) + sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + } + desc_count += gdp[desc].bg_free_blocks_count; + bitmap_nr = load_block_bitmap (sb, i); + if (sb->u.ext2_sb.s_block_bitmap[bitmap_nr]) + x = ext2_count_free + (sb->u.ext2_sb.s_block_bitmap[bitmap_nr], + sb->s_blocksize); + else { + x = 0; + printk ("Cannot load bitmap for group %d\n", i); + } + printk ("group %d: stored = %d, counted = %lu\n", + i, gdp[desc].bg_free_blocks_count, x); + bitmap_count += x; + desc++; + if (desc == EXT2_DESC_PER_BLOCK(sb)) { + group_desc++; + desc = 0; + gdp = NULL; + } + } + printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n", + es->s_free_blocks_count, desc_count, bitmap_count); + unlock_super (sb); + return bitmap_count; + #else + return sb->u.ext2_sb.s_es->s_free_blocks_count; + #endif + } + + void ext2_check_blocks_bitmap (struct super_block * sb) + { + struct ext2_super_block * es; + unsigned long desc_count, bitmap_count, x; + unsigned long group_desc; + unsigned long desc; + int bitmap_nr; + struct ext2_group_desc * gdp; + int i; + + lock_super (sb); + es = sb->u.ext2_sb.s_es; + desc_count = 0; + bitmap_count = 0; + group_desc = 0; + desc = 0; + gdp = NULL; + for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { + if (!gdp) { + if (!sb->u.ext2_sb.s_group_desc[group_desc]) { + ext2_error (sb, "ext2_check_blocks_bitmap", + "Descriptor not loaded for group %d", + i); + break; + } + gdp = (struct ext2_group_desc *) + sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + } + desc_count += gdp[desc].bg_free_blocks_count; + bitmap_nr = load_block_bitmap (sb, i); + if (sb->u.ext2_sb.s_block_bitmap[bitmap_nr]) + x = ext2_count_free + (sb->u.ext2_sb.s_block_bitmap[bitmap_nr], + sb->s_blocksize); + else { + x = 0; + ext2_error (sb, "ext2_check_blocks_bitmap", + "Cannot load bitmap for group %d\n", i); + } + if (gdp[desc].bg_free_blocks_count != x) + ext2_error (sb, "ext2_check_blocks_bitmap", + "Wrong free blocks count for group %d, " + "stored = %d, counted = %lu", i, + gdp[desc].bg_free_blocks_count, x); + bitmap_count += x; + desc++; + if (desc == EXT2_DESC_PER_BLOCK(sb)) { + group_desc++; + desc = 0; + gdp = NULL; + } + } + if (es->s_free_blocks_count != bitmap_count) + ext2_error (sb, "ext2_check_blocks_bitmap", + "Wrong free blocks count in super block, " + "stored = %lu, counted = %lu", + es->s_free_blocks_count, bitmap_count); + unlock_super (sb); + } diff -cr --new-file linux-0.07pl4/fs/ext2/bitmap.c linux-0.08/fs/ext2/bitmap.c *** linux-0.07pl4/fs/ext2/bitmap.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/bitmap.c Mon Nov 22 12:17:44 1993 *************** *** 0 **** --- 1,23 ---- + /* + * linux/fs/ext2/bitmap.c + * + * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) + */ + + #include + #include + + static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; + + unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars) + { + unsigned int i; + unsigned long sum = 0; + + if (!map) + return (0); + for (i = 0; i < numchars; i++) + sum += nibblemap[map->b_data[i] & 0xf] + + nibblemap[(map->b_data[i] >> 4) & 0xf]; + return (sum); + } diff -cr --new-file linux-0.07pl4/fs/ext2/dcache.c linux-0.08/fs/ext2/dcache.c *** linux-0.07pl4/fs/ext2/dcache.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/dcache.c Mon Nov 22 12:17:44 1993 *************** *** 0 **** --- 1,337 ---- + /* + * linux/fs/ext2/dcache.c + * + * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) + * + */ + + /* + * dcache.c contains the code that handles the directory cache used by + * lookup() and readdir() + */ + + #include + + #include + #include + #include + #include + + #ifndef DONT_USE_DCACHE + + #define DCACHE_NAME_LEN 32 + + struct dir_cache_entry { + unsigned short dev; + unsigned long dir; + unsigned long ino; + char name[DCACHE_NAME_LEN + 1]; + int len; + struct dir_cache_entry * queue_prev; + struct dir_cache_entry * queue_next; + struct dir_cache_entry * prev; + struct dir_cache_entry * next; + }; + + static struct dir_cache_entry * first = NULL; + static struct dir_cache_entry * last = NULL; + static struct dir_cache_entry * first_free = NULL; + static int cache_initialized = 0; + #ifdef EXT2FS_DEBUG_CACHE + static int hits = 0; + static int misses = 0; + #endif + + #define CACHE_SIZE 128 + + static struct dir_cache_entry dcache[CACHE_SIZE]; + + #define HASH_QUEUES 16 + + static struct dir_cache_entry * queue_head[HASH_QUEUES]; + static struct dir_cache_entry * queue_tail[HASH_QUEUES]; + + #define hash(dev,dir) ((dev ^ dir) % HASH_QUEUES) + + /* + * Initialize the cache + */ + static void init_cache (void) + { + int i; + + dcache[0].prev = NULL; + dcache[0].next = &dcache[1]; + dcache[0].queue_next = dcache[0].queue_prev = NULL; + for (i = 1; i < CACHE_SIZE - 1; i++) { + dcache[i].prev = &dcache[i - 1]; + dcache[i].next = &dcache[i + 1]; + dcache[i].queue_next = dcache[i].queue_prev = NULL; + } + dcache[i].prev = &dcache[i - 1]; + dcache[i].next = NULL; + dcache[i].queue_next = dcache[i].queue_prev = NULL; + first_free = &dcache[0]; + for (i = 0; i < HASH_QUEUES; i++) + queue_tail[i] = queue_head[i] = NULL; + cache_initialized = 1; + } + + /* + * Find a name in the cache + */ + static struct dir_cache_entry * find_name (int queue, unsigned short dev, + unsigned long dir, + const char * name, int len) + { + struct dir_cache_entry * p; + + for (p = queue_head[queue]; p != NULL && (p->dev != dev || + p->dir != dir || p->len != len || + strncmp (name, p->name, p->len) != 0); + p = p->queue_next) + ; + return p; + } + + #ifdef EXT2FS_DEBUG_CACHE + /* + * List the cache entries for debugging + */ + static void show_cache (const char * func_name) + { + struct dir_cache_entry * p; + + printk ("%s: cache status\n", func_name); + for (p = first; p != NULL; p = p->next) + printk ("dev:%04x, dir=%4lu, name=%s\n", + p->dev, p->dir, p->name); + } + #endif + + /* + * Add an entry at the beginning of the cache + */ + static void add_to_cache (struct dir_cache_entry * p) + { + p->prev = NULL; + p->next = first; + if (first) + first->prev = p; + if (!last) + last = p; + first = p; + } + + /* + * Add an entry at the beginning of a queue + */ + static void add_to_queue (int queue, struct dir_cache_entry * p) + { + p->queue_prev = NULL; + p->queue_next = queue_head[queue]; + if (queue_head[queue]) + queue_head[queue]->queue_prev = p; + if (!queue_tail[queue]) + queue_tail[queue] = p; + queue_head[queue] = p; + } + + /* + * Remove an entry from the cache + */ + static void remove_from_cache (struct dir_cache_entry * p) + { + if (p->prev) + p->prev->next = p->next; + else + first = p->next; + if (p->next) + p->next->prev = p->prev; + else + last = p->prev; + p->prev = NULL; + p->next = NULL; + } + + /* + * Remove an entry from a queue + */ + static void remove_from_queue (int queue, struct dir_cache_entry * p) + { + if (p->queue_prev) + p->queue_prev->queue_next = p->queue_next; + else + queue_head[queue] = p->queue_next; + if (p->queue_next) + p->queue_next->queue_prev = p->queue_prev; + else + queue_tail[queue] = p->queue_prev; + p->queue_prev = NULL; + p->queue_next = NULL; + } + + /* + * Invalidate all cache entries on a device (called by put_super() when + * a file system is unmounted) + */ + void ext2_dcache_invalidate (unsigned short dev) + { + struct dir_cache_entry * p; + struct dir_cache_entry * p2; + + if (!cache_initialized) + init_cache (); + for (p = first; p != NULL; p = p2) { + p2 = p->next; + if (p->dev == dev) { + remove_from_cache (p); + remove_from_queue (hash (p->dev, p->dir), p); + p->next = first_free; + first_free = p; + } + } + #ifdef EXT2FS_DEBUG_CACHE + show_cache ("dcache_invalidate"); + #endif + } + + /* + * Lookup a directory entry in the cache + */ + unsigned long ext2_dcache_lookup (unsigned short dev, unsigned long dir, + const char * name, int len) + { + char our_name[EXT2_NAME_LEN]; + int queue; + struct dir_cache_entry * p; + + if (!cache_initialized) + init_cache (); + if (len > DCACHE_NAME_LEN) + return 0; + memcpy (our_name, (char *) name, len); + our_name[len] = '\0'; + #ifdef EXT2FS_DEBUG_CACHE + printk ("dcache_lookup (%04x, %lu, %s, %d)\n", dev, dir, our_name, len); + #endif + queue = hash (dev, dir); + if ((p = find_name (queue, dev, dir, our_name, len))) { + if (p != first) { + remove_from_cache (p); + add_to_cache (p); + } + if (p != queue_head[queue]) { + remove_from_queue (queue, p); + add_to_queue (queue, p); + } + #ifdef EXT2FS_DEBUG_CACHE + hits++; + printk ("dcache_lookup: %s,hit,inode=%lu,hits=%d,misses=%d\n", + our_name, p->ino, hits, misses); + show_cache ("dcache_lookup"); + #endif + return p->ino; + } else { + #ifdef EXT2FS_DEBUG_CACHE + misses++; + printk ("dcache_lookup: %s,miss,hits=%d,misses=%d\n", + our_name, hits, misses); + show_cache ("dcache_lookup"); + #endif + return 0; + } + } + + /* + * Add a directory entry to the cache + * + * This function is called by ext2_lookup(), ext2_readdir() + * and the functions which create directory entries + */ + void ext2_dcache_add (unsigned short dev, unsigned long dir, const char * name, + int len, unsigned long ino) + { + struct dir_cache_entry * p; + int queue; + + if (!cache_initialized) + init_cache (); + #ifdef EXT2FS_DEBUG_CACHE + printk ("dcache_add (%04x, %lu, %s, %d, %lu)\n", + dev, dir, name, len, ino); + #endif + if (len > DCACHE_NAME_LEN) + return; + queue = hash (dev, dir); + if ((p = find_name (queue, dev, dir, name, len))) { + p->dir = dir; + p->ino = ino; + if (p != first) { + remove_from_cache (p); + add_to_cache (p); + } + if (p != queue_head[queue]) { + remove_from_queue (queue, p); + add_to_queue (queue, p); + } + } else { + if (first_free) { + p = first_free; + first_free = p->next; + } else { + if (!last) + panic ("dcache_add: last == NULL\n"); + else { + p = last; + last = p->prev; + if (last) + last->next = NULL; + remove_from_queue (hash (p->dev, p->dir), p); + } + } + p->dev = dev; + p->dir = dir; + p->ino = ino; + strncpy (p->name, name, len); + p->len = len; + p->name[len] = '\0'; + add_to_cache (p); + add_to_queue (queue, p); + } + #ifdef EXT2FS_DEBUG_CACHE + show_cache ("dcache_add"); + #endif + } + + /* + * Remove a directory from the cache + * + * This function is called by the functions which remove directory entries + */ + void ext2_dcache_remove (unsigned short dev, unsigned long dir, + const char * name, int len) + { + struct dir_cache_entry * p; + int queue; + + if (!cache_initialized) + init_cache (); + #ifdef EXT2FS_DEBUG_CACHE + printk ("dcache_remove (%04x, %lu, %s, %d)\n", dev, dir, name, len); + #endif + if (len > DCACHE_NAME_LEN) + return; + queue = hash (dev, dir); + if ((p = find_name (queue, dev, dir, name, len))) { + remove_from_cache (p); + remove_from_queue (queue, p); + p->next = first_free; + first_free = p; + } + #ifdef EXT2FS_DEBUG_CACHE + show_cache ("dcache_remove"); + #endif + } + + #endif diff -cr --new-file linux-0.07pl4/fs/ext2/dir.c linux-0.08/fs/ext2/dir.c *** linux-0.07pl4/fs/ext2/dir.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/dir.c Mon Nov 22 12:17:44 1993 *************** *** 0 **** --- 1,151 ---- + /* + * linux/fs/ext2/dir.c + * + * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) + * + * from + * + * linux/fs/minix/dir.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext2 directory handling functions + */ + + #include + + #include + #include + #include + #include + #include + + #if 0 + static int ext2_dir_read (struct inode * inode, struct file * filp, + char * buf, int count) + { + return -EISDIR; + } + #endif + + /* static */ int ext2_file_read (struct inode *, struct file *, char *, int); + static int ext2_readdir (struct inode *, struct file *, struct dirent *, int); + + static struct file_operations ext2_dir_operations = { + NULL, /* lseek - default */ + ext2_file_read, /* read */ + NULL, /* write - bad */ + ext2_readdir, /* readdir */ + NULL, /* select - default */ + ext2_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + file_fsync /* fsync */ + }; + + /* + * directories can handle most operations... + */ + struct inode_operations ext2_dir_inode_operations = { + &ext2_dir_operations, /* default directory file-ops */ + ext2_create, /* create */ + ext2_lookup, /* lookup */ + ext2_link, /* link */ + ext2_unlink, /* unlink */ + ext2_symlink, /* symlink */ + ext2_mkdir, /* mkdir */ + ext2_rmdir, /* rmdir */ + ext2_mknod, /* mknod */ + ext2_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + ext2_truncate, /* truncate */ + ext2_permission /* permission */ + }; + + int ext2_check_dir_entry (char * function, struct inode * dir, + struct ext2_dir_entry * de, struct buffer_head * bh, + unsigned long offset) + { + char * error_msg = NULL; + + if (de->rec_len < EXT2_DIR_REC_LEN(1)) + error_msg = "rec_len is smaller than minimal"; + else if (de->rec_len % 4 != 0) + error_msg = "rec_len % 4 != 0"; + else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len)) + error_msg = "rec_len is too small for name_len"; + else if (dir && ((char *) de - bh->b_data) + de->rec_len > + dir->i_sb->s_blocksize) + error_msg = "directory entry across blocks"; + + if (error_msg != NULL) + ext2_error (dir->i_sb, function, "bad directory entry: %s\n" + "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", + error_msg, offset, de->inode, de->rec_len, + de->name_len); + return error_msg == NULL ? 1 : 0; + } + + static int ext2_readdir (struct inode * inode, struct file * filp, + struct dirent * dirent, int count) + { + unsigned long offset; + int i; + struct buffer_head * bh; + struct ext2_dir_entry * de; + struct super_block * sb; + int err; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + sb = inode->i_sb; + while (filp->f_pos < inode->i_size) { + offset = filp->f_pos & (sb->s_blocksize - 1); + bh = ext2_bread (inode, (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb), + 0, &err); + if (!bh) { + filp->f_pos += sb->s_blocksize - offset; + continue; + } + de = (struct ext2_dir_entry *) (offset + bh->b_data); + while (offset < sb->s_blocksize && filp->f_pos < inode->i_size) { + if (! ext2_check_dir_entry ("ext2_readdir", inode, de, + bh, offset)) { + brelse (bh); + return 0; + } + offset += de->rec_len; + filp->f_pos += de->rec_len; + if (de->inode) { + memcpy_tofs (dirent->d_name, de->name, + de->name_len); + put_fs_long (de->inode, &dirent->d_ino); + put_fs_byte (0, de->name_len + dirent->d_name); + put_fs_word (de->name_len, &dirent->d_reclen); + #ifndef DONT_USE_DCACHE + ext2_dcache_add (inode->i_dev, inode->i_ino, + de->name, de->name_len, + de->inode); + #endif + i = de->name_len; + brelse (bh); + if (!IS_RDONLY(inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } + return i; + } + de = (struct ext2_dir_entry *) ((char *) de + + de->rec_len); + } + brelse (bh); + } + if (!IS_RDONLY(inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } + return 0; + } diff -cr --new-file linux-0.07pl4/fs/ext2/file.c linux-0.08/fs/ext2/file.c *** linux-0.07pl4/fs/ext2/file.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/file.c Mon Nov 22 12:17:44 1993 *************** *** 0 **** --- 1,271 ---- + /* + * linux/fs/ext2/file.c + * + * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) + * + * from + * + * linux/fs/minix/file.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext2 fs regular file handling primitives + */ + + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + + #define NBUF 32 + + #define MIN(a,b) (((a)<(b))?(a):(b)) + #define MAX(a,b) (((a)>(b))?(a):(b)) + + #include + #include + + /* static */ int ext2_file_read (struct inode *, struct file *, char *, int); + static int ext2_file_write (struct inode *, struct file *, char *, int); + + /* + * We have mostly NULL's here: the current defaults are ok for + * the ext2 filesystem. + */ + static struct file_operations ext2_file_operations = { + NULL, /* lseek - default */ + ext2_file_read, /* read */ + ext2_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + ext2_ioctl, /* ioctl */ + generic_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + ext2_sync_file /* fsync */ + }; + + struct inode_operations ext2_file_inode_operations = { + &ext2_file_operations,/* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + ext2_bmap, /* bmap */ + ext2_truncate, /* truncate */ + ext2_permission /* permission */ + }; + + /* static */ int ext2_file_read (struct inode * inode, struct file * filp, + char * buf, int count) + { + int read, left, chars; + int block, blocks, offset; + int bhrequest, uptodate; + struct buffer_head ** bhb, ** bhe; + struct buffer_head * bhreq[NBUF]; + struct buffer_head * buflist[NBUF]; + struct super_block * sb; + unsigned int size; + int err; + + if (!inode) { + printk ("ext2_file_read: inode = NULL\n"); + return -EINVAL; + } + sb = inode->i_sb; + if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) { + ext2_warning (sb, "ext2_file_read", "mode = %07o", + inode->i_mode); + return -EINVAL; + } + offset = filp->f_pos; + size = inode->i_size; + if (offset > size) + left = 0; + else + left = size - offset; + if (left > count) + left = count; + if (left <= 0) + return 0; + read = 0; + block = offset >> EXT2_BLOCK_SIZE_BITS(sb); + offset &= (sb->s_blocksize - 1); + size = (size + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb); + blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb); + bhb = bhe = buflist; + if (filp->f_reada) { + blocks += read_ahead[MAJOR(inode->i_dev)] >> + (EXT2_BLOCK_SIZE_BITS(sb) - 9); + if (block + blocks > size) + blocks = size - block; + } + + /* We do this in a two stage process. We first try and request + as many blocks as we can, then we wait for the first one to + complete, and then we try and wrap up as many as are actually + done. This routine is rather generic, in that it can be used + in a filesystem by substituting the appropriate function in + for getblk + + This routine is optimized to make maximum use of the various + buffers and caches. */ + + do { + bhrequest = 0; + uptodate = 1; + while (blocks) { + --blocks; + *bhb = ext2_getblk (inode, block++, 0, &err); + if (*bhb && !(*bhb)->b_uptodate) { + uptodate = 0; + bhreq[bhrequest++] = *bhb; + } + + if (++bhb == &buflist[NBUF]) + bhb = buflist; + + /* If the block we have on hand is uptodate, go ahead + and complete processing */ + if (uptodate) + break; + + if (bhb == bhe) + break; + } + + /* Now request them all */ + if (bhrequest) + ll_rw_block (READ, bhrequest, bhreq); + + do { /* Finish off all I/O that has actually completed */ + if (*bhe) { + wait_on_buffer (*bhe); + if (!(*bhe)->b_uptodate) { /* read error? */ + brelse(*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + left = 0; + break; + } + } + if (left < sb->s_blocksize - offset) + chars = left; + else + chars = sb->s_blocksize - offset; + filp->f_pos += chars; + left -= chars; + read += chars; + if (*bhe) { + memcpy_tofs (buf, offset + (*bhe)->b_data, + chars); + brelse (*bhe); + buf += chars; + } else { + while (chars-- > 0) + put_fs_byte (0, buf++); + } + offset = 0; + if (++bhe == &buflist[NBUF]) + bhe = buflist; + } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock)); + } while (left > 0); + + /* Release the read-ahead blocks */ + while (bhe != bhb) { + brelse (*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + } + if (!read) + return -EIO; + filp->f_reada = 1; + if (!IS_RDONLY(inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } + return read; + } + + static int ext2_file_write (struct inode * inode, struct file * filp, + char * buf, int count) + { + off_t pos; + int written, c; + struct buffer_head * bh; + char * p; + struct super_block * sb; + int err; + + if (!inode) { + printk("ext2_file_write: inode = NULL\n"); + return -EINVAL; + } + sb = inode->i_sb; + if (!S_ISREG(inode->i_mode)) { + ext2_warning (sb, "ext2_file_write", "mode = %07o\n", + inode->i_mode); + return -EINVAL; + } + /* + * ok, append may not work when many processes are writing at the same time + * but so what. That way leads to madness anyway. + */ + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + else + pos = filp->f_pos; + written = 0; + while (written < count) { + bh = ext2_getblk (inode, pos / sb->s_blocksize, 1, &err); + if (!bh) { + if (!written) + written = err; + break; + } + c = sb->s_blocksize - (pos % sb->s_blocksize); + if (c > count-written) + c = count - written; + if (c != sb->s_blocksize && !bh->b_uptodate) { + ll_rw_block (READ, 1, &bh); + wait_on_buffer (bh); + if (!bh->b_uptodate) { + brelse (bh); + if (!written) + written = -EIO; + break; + } + } + p = (pos % sb->s_blocksize) + bh->b_data; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + written += c; + memcpy_fromfs (p, buf, c); + buf += c; + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse (bh); + } + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + filp->f_pos = pos; + inode->i_dirt = 1; + return written; + } diff -cr --new-file linux-0.07pl4/fs/ext2/fsync.c linux-0.08/fs/ext2/fsync.c *** linux-0.07pl4/fs/ext2/fsync.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/fsync.c Mon Nov 22 12:17:44 1993 *************** *** 0 **** --- 1,194 ---- + /* + * linux/fs/ext2/fsync.c + * + * Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk) + * from + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * from + * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds + * + * ext2fs fsync primitive + */ + + #include + #include + + #include + #include + #include + #include + #include + #include + #include + + + #define blocksize (EXT2_BLOCK_SIZE(inode->i_sb)) + #define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb)) + + static int sync_block (struct inode * inode, unsigned long * block, int wait) + { + struct buffer_head * bh; + int tmp; + + if (!*block) + return 0; + tmp = *block; + bh = get_hash_table (inode->i_dev, *block, blocksize); + if (!bh) + return 0; + if (*block != tmp) { + brelse (bh); + return 1; + } + if (wait && bh->b_req && !bh->b_uptodate) { + brelse (bh); + return -1; + } + if (wait || !bh->b_uptodate || !bh->b_dirt) { + brelse (bh); + return 0; + } + ll_rw_block (WRITE, 1, &bh); + bh->b_count--; + return 0; + } + + static int sync_iblock (struct inode * inode, unsigned long * iblock, + struct buffer_head ** bh, int wait) + { + int rc, tmp; + + *bh = NULL; + tmp = *iblock; + if (!tmp) + return 0; + rc = sync_block (inode, iblock, wait); + if (rc) + return rc; + *bh = bread (inode->i_dev, tmp, blocksize); + if (tmp != *iblock) { + brelse (*bh); + *bh = NULL; + return 1; + } + if (!*bh) + return -1; + return 0; + } + + + static int sync_direct (struct inode * inode, int wait) + { + int i; + int rc, err = 0; + + for (i = 0; i < EXT2_NDIR_BLOCKS; i++) { + rc = sync_block (inode, inode->u.ext2_i.i_data + i, wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + return err; + } + + static int sync_indirect (struct inode * inode, unsigned long * iblock, + int wait) + { + int i; + struct buffer_head * ind_bh; + int rc, err = 0; + + rc = sync_iblock (inode, iblock, &ind_bh, wait); + if (rc || !ind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_block (inode, + ((unsigned long *) ind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse (ind_bh); + return err; + } + + static int sync_dindirect (struct inode * inode, unsigned long * diblock, + int wait) + { + int i; + struct buffer_head * dind_bh; + int rc, err = 0; + + rc = sync_iblock (inode, diblock, &dind_bh, wait); + if (rc || !dind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_indirect (inode, + ((unsigned long *) dind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse (dind_bh); + return err; + } + + static int sync_tindirect (struct inode * inode, unsigned long * tiblock, + int wait) + { + int i; + struct buffer_head * tind_bh; + int rc, err = 0; + + rc = sync_iblock (inode, tiblock, &tind_bh, wait); + if (rc || !tind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_dindirect (inode, + ((unsigned long *) tind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse (tind_bh); + return err; + } + + int ext2_sync_file (struct inode * inode, struct file * file) + { + int wait, err = 0; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return -EINVAL; + /* Don't sync fast links! */ + if (S_ISLNK(inode->i_mode) && !(inode->i_blocks)) + goto skip; + + for (wait=0; wait<=1; wait++) + { + err |= sync_direct (inode, wait); + err |= sync_indirect (inode, + inode->u.ext2_i.i_data+EXT2_IND_BLOCK, + wait); + err |= sync_dindirect (inode, + inode->u.ext2_i.i_data+EXT2_DIND_BLOCK, + wait); + err |= sync_tindirect (inode, + inode->u.ext2_i.i_data+EXT2_TIND_BLOCK, + wait); + } + skip: + err |= ext2_sync_inode (inode); + return (err < 0) ? -EIO : 0; + } diff -cr --new-file linux-0.07pl4/fs/ext2/ialloc.c linux-0.08/fs/ext2/ialloc.c *** linux-0.07pl4/fs/ext2/ialloc.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/ialloc.c Tue Feb 1 17:16:29 1994 *************** *** 0 **** --- 1,644 ---- + + /* + * linux/fs/ext2/ialloc.c + * + * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) + * + * BSD ufs-inspired inode and directory allocation by + * Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 + */ + + /* ialloc.c contains the inodes allocation and deallocation routines */ + + /* + + The free inodes are managed by bitmaps. A file system contains several + blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap + block for inodes, N blocks for the inode table and data blocks. + + The file system contains group descriptors which are located after the + super block. Each descriptor contains the number of the bitmap block and + the free blocks count in the block. The descriptors are loaded in memory + when a file system is mounted (see ext2_read_super). + + */ + + #include + #include + #include + #include + #include + #include + #include + + #include + + #if defined(__i386__) + static inline int find_first_zero_bit (unsigned long * addr, unsigned size) + { + int res; + + if (!size) + return 0; + __asm__(" + cld + movl $-1,%%eax + repe; scasl + je 1f + subl $4,%%edi + movl (%%edi),%%eax + notl %%eax + bsfl %%eax,%%edx + jmp 2f + 1: xorl %%edx,%%edx + 2: subl %%ebx,%%edi + shll $3,%%edi + addl %%edi,%%edx" + : "=d" (res) + : "c" ((size + 31) >> 5), "D" (addr), "b" (addr) + : "ax", "bx", "cx", "di"); + return res; + } + #elif defined(__mc68000__) + static inline int find_first_zero_bit(unsigned long * addr, unsigned size) + { + unsigned long res; + void *p = addr; + + if (!size) + return 0; + __asm__ __volatile__ ("1:" + " movel %1@+,d1\n\t" + " cmpl %4,d1\n\t" + " bne 2f\n\t" + " addl %5,%0\n\t" + " cmpl %6,%0\n\t" + " bcs 1b\n\t" + " bra 5f\n\t" + "2:" + " moveq #0,d2\n\t" + "3:" + " btst d2,d1\n\t" + " beq 4f\n\t" + " addql #1,d2\n\t" + " bra 3b\n\t" + "4:" + " addl d2,%0\n\t" + "5:" + : "=d" (res), "=a" (p) + : "0" (0), "1" (p), + "g" (0xffffffff), "g" (32), + "g" ((size + 31) & ~31) + : "d1", "d2"); + return res; + } + #endif + + static void read_inode_bitmap (struct super_block * sb, + unsigned long block_group, + unsigned int bitmap_nr) + { + unsigned long group_desc; + unsigned long desc; + struct ext2_group_desc * gdp; + struct buffer_head * bh; + + group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); + desc = block_group % EXT2_DESC_PER_BLOCK(sb); + if (!sb->u.ext2_sb.s_group_desc[group_desc]) + ext2_panic (sb, "read_inode_bitmap", + "Group descriptor not loaded\n" + "block_group = %lu, group_desc = %lu, desc = %lu", + block_group, group_desc, desc); + gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + bh = bread (sb->s_dev, gdp[desc].bg_inode_bitmap, sb->s_blocksize); + if (!bh) + ext2_panic (sb, "read_inode_bitmap", "Cannot read inode bitmap\n" + "block_group = %lu, group_desc = %lu, desc = %lu, inode_bitmap = %lu", + block_group, group_desc, desc, gdp[desc].bg_inode_bitmap); + sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group; + sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh; + } + + /* + * load_inode_bitmap loads the inode bitmap for a blocks group + * + * It maintains a cache for the last bitmaps loaded. This cache is managed + * with a LRU algorithm. + * + * Notes: + * 1/ There is one cache per mounted file system. + * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups, + * this function reads the bitmap without maintaining a LRU cache. + */ + static int load_inode_bitmap (struct super_block * sb, + unsigned int block_group) + { + int i, j; + unsigned long inode_bitmap_number; + struct buffer_head * inode_bitmap; + + if (block_group >= sb->u.ext2_sb.s_groups_count) + ext2_panic (sb, "load_inode_bitmap", + "block_group >= groups_count\n" + "block_group = %d, groups_count = %lu", + block_group, sb->u.ext2_sb.s_groups_count); + if (sb->u.ext2_sb.s_loaded_inode_bitmaps > 0 && + sb->u.ext2_sb.s_inode_bitmap_number[0] == block_group) + return 0; + if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) { + if (sb->u.ext2_sb.s_inode_bitmap[block_group]) { + if (sb->u.ext2_sb.s_inode_bitmap_number[block_group] != block_group) + ext2_panic (sb, "load_inode_bitmap", + "block_group != inode_bitmap_number"); + else + return block_group; + } else { + read_inode_bitmap (sb, block_group, block_group); + return block_group; + } + } + + for (i = 0; i < sb->u.ext2_sb.s_loaded_inode_bitmaps && + sb->u.ext2_sb.s_inode_bitmap_number[i] != block_group; + i++) + ; + if (i < sb->u.ext2_sb.s_loaded_inode_bitmaps && + sb->u.ext2_sb.s_inode_bitmap_number[i] == block_group) { + inode_bitmap_number = sb->u.ext2_sb.s_inode_bitmap_number[i]; + inode_bitmap = sb->u.ext2_sb.s_inode_bitmap[i]; + for (j = i; j > 0; j--) { + sb->u.ext2_sb.s_inode_bitmap_number[j] = + sb->u.ext2_sb.s_inode_bitmap_number[j - 1]; + sb->u.ext2_sb.s_inode_bitmap[j] = + sb->u.ext2_sb.s_inode_bitmap[j - 1]; + } + sb->u.ext2_sb.s_inode_bitmap_number[0] = inode_bitmap_number; + sb->u.ext2_sb.s_inode_bitmap[0] = inode_bitmap; + } else { + if (sb->u.ext2_sb.s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED) + sb->u.ext2_sb.s_loaded_inode_bitmaps++; + else + brelse (sb->u.ext2_sb.s_inode_bitmap[EXT2_MAX_GROUP_LOADED - 1]); + for (j = sb->u.ext2_sb.s_loaded_inode_bitmaps - 1; j > 0; j--) { + sb->u.ext2_sb.s_inode_bitmap_number[j] = + sb->u.ext2_sb.s_inode_bitmap_number[j - 1]; + sb->u.ext2_sb.s_inode_bitmap[j] = + sb->u.ext2_sb.s_inode_bitmap[j - 1]; + } + read_inode_bitmap (sb, block_group, 0); + } + return 0; + } + + /* + * This function sets the deletion time for the inode + * + * This may be used one day by an 'undelete' program + */ + static void set_inode_dtime (struct inode * inode, + struct ext2_group_desc * gdp, unsigned long desc) + { + unsigned long inode_block; + struct buffer_head * bh; + struct ext2_inode * raw_inode; + + inode_block = gdp[desc].bg_inode_table + (((inode->i_ino - 1) % + EXT2_INODES_PER_GROUP(inode->i_sb)) / + EXT2_INODES_PER_BLOCK(inode->i_sb)); + bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize); + if (!bh) + ext2_panic (inode->i_sb, "set_inode_dtime", + "Cannot load inode table block\n" + "inode=%lu, inode_block=%lu", + inode->i_ino, inode_block); + raw_inode = ((struct ext2_inode *) bh->b_data) + + (((inode->i_ino - 1) % + EXT2_INODES_PER_GROUP(inode->i_sb)) % + EXT2_INODES_PER_BLOCK(inode->i_sb)); + raw_inode->i_links_count = 0; + raw_inode->i_dtime = CURRENT_TIME; + bh->b_dirt = 1; + if (IS_SYNC(inode)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + } + + void ext2_free_inode (struct inode * inode) + { + struct super_block * sb; + struct buffer_head * bh; + struct buffer_head * bh2; + unsigned long block_group; + unsigned long bit; + unsigned long group_desc; + unsigned long desc; + int bitmap_nr; + struct ext2_group_desc * gdp; + struct ext2_super_block * es; + + if (!inode) + return; + if (!inode->i_dev) { + printk ("ext2_free_inode: inode has no device\n"); + return; + } + if (inode->i_count > 1) { + printk ("ext2_free_inode: inode has count=%d\n", + inode->i_count); + return; + } + if (inode->i_nlink) { + printk ("ext2_free_inode: inode has nlink=%d\n", + inode->i_nlink); + return; + } + if (!inode->i_sb) { + printk("ext2_free_inode: inode on nonexistent device\n"); + return; + } + + ext2_debug ("freeing inode %lu\n", inode->i_ino); + + sb = inode->i_sb; + lock_super (sb); + if (inode->i_ino < EXT2_FIRST_INO || + inode->i_ino > sb->u.ext2_sb.s_es->s_inodes_count) { + ext2_error (sb, "free_inode", + "reserved inode or nonexistent inode"); + unlock_super (sb); + return; + } + es = sb->u.ext2_sb.s_es; + block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(sb); + bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb); + bitmap_nr = load_inode_bitmap (sb, block_group); + bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; + if (!bh) + ext2_panic (sb, "ext2_free_inode", + "Unable to load bitmap for group %lu", block_group); + if (!clear_bit (bit, bh->b_data)) + ext2_warning (sb, "ext2_free_inode", + "bit already cleared for inode %lu", inode->i_ino); + else { + group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); + desc = block_group % EXT2_DESC_PER_BLOCK(sb); + bh2 = sb->u.ext2_sb.s_group_desc[group_desc]; + if (!bh2) + ext2_panic (sb, "ext2_free_inode", + "Group descriptor not loaded for group %lu", + group_desc); + gdp = (struct ext2_group_desc *) bh2->b_data; + gdp[desc].bg_free_inodes_count++; + if (S_ISDIR(inode->i_mode)) + gdp[desc].bg_used_dirs_count--; + bh2->b_dirt = 1; + es->s_free_inodes_count++; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + set_inode_dtime (inode, gdp, desc); + } + bh->b_dirt = 1; + if (sb->s_flags & MS_SYNC) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + + sb->s_dirt = 1; + clear_inode (inode); + unlock_super (sb); + } + + /* + * This function increments the inode version number + * + * This may be used one day by the NFS server + */ + static void inc_inode_version (struct inode * inode, + struct ext2_group_desc *gdp, + int mode) + { + unsigned long inode_block; + struct buffer_head * bh; + struct ext2_inode * raw_inode; + + inode_block = gdp->bg_inode_table + (((inode->i_ino - 1) % + EXT2_INODES_PER_GROUP(inode->i_sb)) / + EXT2_INODES_PER_BLOCK(inode->i_sb)); + bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize); + if (!bh) { + ext2_error (inode->i_sb, "inc_inode_version", + "Cannot load inode table block" + "inode=%lu, inode_block=%lu\n", + inode->i_ino, inode_block); + inode->u.ext2_i.i_version = 1; + return; + } + raw_inode = ((struct ext2_inode *) bh->b_data) + + (((inode->i_ino - 1) % + EXT2_INODES_PER_GROUP(inode->i_sb)) % + EXT2_INODES_PER_BLOCK(inode->i_sb)); + raw_inode->i_version++; + inode->u.ext2_i.i_version = raw_inode->i_version; + bh->b_dirt = 1; + brelse (bh); + } + + static struct ext2_group_desc * get_group_desc (struct super_block * sb, + int group) + { + struct ext2_group_desc * gdp; + + if (group >= sb->u.ext2_sb.s_groups_count || group < 0 ) + ext2_panic (sb, "get_group_desc", "Invalid group %d", group); + if (!sb->u.ext2_sb.s_group_desc[group / EXT2_DESC_PER_BLOCK(sb)]) + ext2_panic (sb, "get_group_desc", + "Descriptor not loaded for group %d", group); + gdp = (struct ext2_group_desc *) + sb->u.ext2_sb.s_group_desc[group / EXT2_DESC_PER_BLOCK(sb)] + ->b_data; + return gdp + (group % EXT2_DESC_PER_BLOCK(sb)); + } + + /* + * There are two policies for allocating an inode. If the new inode is + * a directory, then a forward search is made for a block group with both + * free space and a low directory-to-inode ratio; if that fails, then of + * the groups with above-average free space, that group with the fewest + * directories already is chosen. + * + * For other inodes, search forward from the parent directory\'s block + * group to find a free inode. + */ + struct inode * ext2_new_inode (const struct inode * dir, int mode) + { + struct super_block * sb; + struct buffer_head * bh; + int i, j, avefreei; + struct inode * inode; + int bitmap_nr; + struct ext2_group_desc * gdp, * tmp; + struct ext2_super_block * es; + + if (!dir || !(inode = get_empty_inode ())) + return NULL; + sb = dir->i_sb; + inode->i_sb = sb; + inode->i_flags = sb->s_flags; + lock_super (sb); + es = sb->u.ext2_sb.s_es; + repeat: + gdp = NULL; i=0; + + if (S_ISDIR(mode)) { + avefreei = es->s_free_inodes_count / + sb->u.ext2_sb.s_groups_count; + /* I am not yet convinced that this next bit is necessary. + i = dir->u.ext2_i.i_block_group; + for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) { + tmp = get_group_desc (sb, i); + if ((tmp->bg_used_dirs_count << 8) < + tmp->bg_free_inodes_count) { + gdp = tmp; + break; + } + else + i = ++i % sb->u.ext2_sb.s_groups_count; + } + */ + if (!gdp) { + for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) { + tmp = get_group_desc (sb, j); + if (tmp->bg_free_inodes_count && + tmp->bg_free_inodes_count >= avefreei) { + if (!gdp || + (tmp->bg_free_inodes_count > + gdp->bg_free_inodes_count)) { + i = j; + gdp = tmp; + } + } + } + } + } + else + { /* Try to place the inode in it\'s parent directory */ + i = dir->u.ext2_i.i_block_group; + tmp = get_group_desc (sb, i); + if (tmp->bg_free_inodes_count) + gdp = tmp; + else + { /* Use a quadratic hash to find a group with a free inode */ + for (j = 1; j < sb->u.ext2_sb.s_groups_count; j <<= 1) { + i += j; + if (i >= sb->u.ext2_sb.s_groups_count) + i -= sb->u.ext2_sb.s_groups_count; + tmp = get_group_desc (sb, i); + if (tmp->bg_free_inodes_count) { + gdp = tmp; + break; + } + } + } + if (!gdp) { + /* That failed: try linear search for a free inode */ + i = dir->u.ext2_i.i_block_group + 2; + for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) { + if (++i >= sb->u.ext2_sb.s_groups_count) + i = 0; + tmp = get_group_desc (sb,i); + if (tmp->bg_free_inodes_count) { + gdp = tmp; + break; + } + } + } + } + + if (!gdp) { + unlock_super (sb); + iput(inode); + return NULL; + } + bitmap_nr = load_inode_bitmap (sb, i); + bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; + if (!bh) + ext2_panic (sb, "ext2_new_inode", + "Unable to load bitmap for group %d", i); + if ((j = find_first_zero_bit ((unsigned long *) bh->b_data, + EXT2_INODES_PER_GROUP(sb))) < + EXT2_INODES_PER_GROUP(sb)) { + if (set_bit (j, bh->b_data)) { + ext2_warning (sb, "ext2_new_inode", + "bit already set for inode %d", j); + goto repeat; + } + bh->b_dirt = 1; + if (sb->s_flags & MS_SYNC) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + } else + goto repeat; + j += i * EXT2_INODES_PER_GROUP(sb) + 1; + if (j > es->s_inodes_count) { + ext2_error (sb, "ext2_new_inode", + "inode > inodes count\n" + "block_group = %d,inode=%d", i, j); + unlock_super (sb); + iput (inode); + return NULL; + } + gdp->bg_free_inodes_count--; + if (S_ISDIR(mode)) + gdp->bg_used_dirs_count++; + sb->u.ext2_sb.s_group_desc[i / EXT2_DESC_PER_BLOCK(sb)]->b_dirt = 1; + es->s_free_inodes_count--; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + inode->i_mode = mode; + inode->i_sb = sb; + inode->i_count = 1; + inode->i_nlink = 1; + inode->i_dev = sb->s_dev; + inode->i_uid = current->euid; + inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->egid; + inode->i_dirt = 1; + inode->i_ino = j; + inode->i_blksize = sb->s_blocksize; + inode->i_blocks = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags; + inode->u.ext2_i.i_faddr = 0; + inode->u.ext2_i.i_frag = 0; + inode->u.ext2_i.i_fsize = 0; + inode->u.ext2_i.i_file_acl = 0; + inode->u.ext2_i.i_dir_acl = 0; + inode->u.ext2_i.i_dtime = 0; + inode->u.ext2_i.i_block_group = i; + inode->i_op = NULL; + if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) + inode->i_flags |= MS_SYNC; + insert_inode_hash(inode); + inc_inode_version (inode, gdp, mode); + + ext2_debug ("allocating inode %lu\n", inode->i_ino); + + unlock_super (sb); + return inode; + } + + unsigned long ext2_count_free_inodes (struct super_block * sb) + { + #ifdef EXT2FS_DEBUG + struct ext2_super_block * es; + unsigned long desc_count, bitmap_count, x; + unsigned long group_desc; + unsigned long desc; + int bitmap_nr; + struct ext2_group_desc * gdp; + int i; + + lock_super (sb); + es = sb->u.ext2_sb.s_es; + desc_count = 0; + bitmap_count = 0; + group_desc = 0; + desc = 0; + gdp = NULL; + for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { + if (!gdp) { + if (!sb->u.ext2_sb.s_group_desc[group_desc]) { + printk ("ext2_count_free_inodes: Descriptor not loaded\n"); + break; + } + gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + } + desc_count += gdp[desc].bg_free_inodes_count; + bitmap_nr = load_inode_bitmap (sb, i); + if (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]) + x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], + EXT2_INODES_PER_GROUP(sb) / 8); + else { + x = 0; + printk ("Cannot load inode bitmap for group %d (bitmap = %d)\n", + i, bitmap_nr); + } + printk ("group %d: stored = %d, counted = %lu\n", + i, gdp[desc].bg_free_inodes_count, x); + bitmap_count += x; + desc++; + if (desc == EXT2_DESC_PER_BLOCK(sb)) { + group_desc++; + desc = 0; + gdp = NULL; + } + } + printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n", + es->s_free_inodes_count, desc_count, bitmap_count); + unlock_super (sb); + return desc_count; + #else + return sb->u.ext2_sb.s_es->s_free_inodes_count; + #endif + } + + void ext2_check_inodes_bitmap (struct super_block * sb) + { + struct ext2_super_block * es; + unsigned long desc_count, bitmap_count, x; + unsigned long group_desc; + unsigned long desc; + int bitmap_nr; + struct ext2_group_desc * gdp; + int i; + + lock_super (sb); + es = sb->u.ext2_sb.s_es; + desc_count = 0; + bitmap_count = 0; + group_desc = 0; + desc = 0; + gdp = NULL; + for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { + if (!gdp) { + if (!sb->u.ext2_sb.s_group_desc[group_desc]) { + ext2_error (sb, "ext2_check_inodes_bitmap", + "Descriptor not loaded for group %d", + i); + break; + } + gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + } + desc_count += gdp[desc].bg_free_inodes_count; + bitmap_nr = load_inode_bitmap (sb, i); + if (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]) + x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], + EXT2_INODES_PER_GROUP(sb) / 8); + else { + x = 0; + ext2_error (sb, "ext2_check_inodes_bitmap", + "Cannot load bitmap for group %d (bitmap = %d)", + i, bitmap_nr); + } + if (gdp[desc].bg_free_inodes_count != x) + ext2_error (sb, "ext2_check_inodes_bitmap", + "Wrong free inodes count in group %d, " + "stored = %d, counted = %lu", i, + gdp[desc].bg_free_inodes_count, x); + bitmap_count += x; + desc++; + if (desc == EXT2_DESC_PER_BLOCK(sb)) { + group_desc++; + desc = 0; + gdp = NULL; + } + } + if (es->s_free_inodes_count != bitmap_count) + ext2_error (sb, "ext2_check_inodes_bitmap", + "Wrong free inodes count in super block, " + "stored = %lu, counted = %lu", + es->s_free_inodes_count, bitmap_count); + unlock_super (sb); + } diff -cr --new-file linux-0.07pl4/fs/ext2/inode.c linux-0.08/fs/ext2/inode.c *** linux-0.07pl4/fs/ext2/inode.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/inode.c Mon Nov 22 12:17:45 1993 *************** *** 0 **** --- 1,497 ---- + /* + * linux/fs/ext2/inode.c + * + * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) + * + * from + * + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 + */ + + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + + void ext2_put_inode (struct inode * inode) + { + if (inode->i_nlink || inode->i_ino == EXT2_ACL_IDX_INO || + inode->i_ino == EXT2_ACL_DATA_INO) + return; + inode->i_size = 0; + if (inode->i_blocks) + ext2_truncate (inode); + ext2_free_inode (inode); + } + + #define inode_bmap(inode, nr) ((inode)->u.ext2_i.i_data[(nr)]) + + static int block_bmap (struct buffer_head * bh, int nr) + { + int tmp; + + if (!bh) + return 0; + tmp = ((unsigned long *) bh->b_data)[nr]; + brelse (bh); + return tmp; + } + + int ext2_bmap (struct inode * inode, int block) + { + int i; + int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + + if (block < 0) { + ext2_warning (inode->i_sb, "ext2_bmap", "block < 0"); + return 0; + } + if (block >= EXT2_NDIR_BLOCKS + addr_per_block + + addr_per_block * addr_per_block + + addr_per_block * addr_per_block * addr_per_block) { + ext2_warning (inode->i_sb, "ext2_bmap", "block > big"); + return 0; + } + if (block < EXT2_NDIR_BLOCKS) + return inode_bmap (inode, block); + block -= EXT2_NDIR_BLOCKS; + if (block < addr_per_block) { + i = inode_bmap (inode, EXT2_IND_BLOCK); + if (!i) + return 0; + return block_bmap (bread (inode->i_dev, i, + inode->i_sb->s_blocksize), block); + } + block -= addr_per_block; + if (block < addr_per_block * addr_per_block) { + i = inode_bmap (inode, EXT2_DIND_BLOCK); + if (!i) + return 0; + i = block_bmap (bread (inode->i_dev, i, + inode->i_sb->s_blocksize), + block / addr_per_block); + if (!i) + return 0; + return block_bmap (bread (inode->i_dev, i, + inode->i_sb->s_blocksize), + block & (addr_per_block - 1)); + } + block -= addr_per_block * addr_per_block; + i = inode_bmap (inode, EXT2_TIND_BLOCK); + if (!i) + return 0; + i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), + block / (addr_per_block * addr_per_block)); + if (!i) + return 0; + i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), + (block / addr_per_block) & (addr_per_block - 1)); + if (!i) + return 0; + return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), + block & (addr_per_block - 1)); + } + + static struct buffer_head * inode_getblk (struct inode * inode, int nr, + int create, int new_block, int * err) + { + int tmp, goal = 0; + unsigned long * p; + struct buffer_head * result; + int blocks = inode->i_sb->s_blocksize / 512; + + p = inode->u.ext2_i.i_data + nr; + repeat: + tmp = *p; + if (tmp) { + result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize); + if (tmp == *p) + return result; + brelse (result); + goto repeat; + } + if (!create || new_block >= + (current->rlim[RLIMIT_FSIZE].rlim_cur >> + EXT2_BLOCK_SIZE_BITS(inode->i_sb))) { + *err = -EFBIG; + return NULL; + } + if (inode->u.ext2_i.i_next_alloc_block == new_block) + goal = inode->u.ext2_i.i_next_alloc_goal; + + ext2_debug ("hint = %d,", goal); + + if (!goal) { + for (tmp = nr - 1; tmp >= 0; tmp--) { + if (inode->u.ext2_i.i_data[tmp]) { + goal = inode->u.ext2_i.i_data[tmp]; + break; + } + } + if (!goal) + goal = (inode->u.ext2_i.i_block_group * + EXT2_BLOCKS_PER_GROUP(inode->i_sb)) + + inode->i_sb->u.ext2_sb.s_es->s_first_data_block; + } + + ext2_debug ("goal = %d.\n", goal); + + tmp = ext2_new_block (inode->i_sb, goal); + if (!tmp) + return NULL; + result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize); + if (*p) { + ext2_free_block (inode->i_sb, tmp); + brelse (result); + goto repeat; + } + *p = tmp; + inode->u.ext2_i.i_next_alloc_block = new_block; + inode->u.ext2_i.i_next_alloc_goal = tmp; + inode->i_ctime = CURRENT_TIME; + inode->i_blocks += blocks; + if (IS_SYNC(inode)) + ext2_sync_inode (inode); + else + inode->i_dirt = 1; + return result; + } + + static struct buffer_head * block_getblk (struct inode * inode, + struct buffer_head * bh, int nr, + int create, int blocksize, + int new_block, int * err) + { + int tmp, goal = 0; + unsigned long * p; + struct buffer_head * result; + int blocks = inode->i_sb->s_blocksize / 512; + + if (!bh) + return NULL; + if (!bh->b_uptodate) { + ll_rw_block (READ, 1, &bh); + wait_on_buffer (bh); + if (!bh->b_uptodate) { + brelse (bh); + return NULL; + } + } + p = (unsigned long *) bh->b_data + nr; + repeat: + tmp = *p; + if (tmp) { + result = getblk (bh->b_dev, tmp, blocksize); + if (tmp == *p) { + brelse (bh); + return result; + } + brelse (result); + goto repeat; + } + if (!create || new_block >= + (current->rlim[RLIMIT_FSIZE].rlim_cur >> + EXT2_BLOCK_SIZE_BITS(inode->i_sb))) { + brelse (bh); + *err = -EFBIG; + return NULL; + } + if (inode->u.ext2_i.i_next_alloc_block == new_block) + goal = inode->u.ext2_i.i_next_alloc_goal; + if (!goal) { + for (tmp = nr - 1; tmp >= 0; tmp--) { + if (((unsigned long *) bh->b_data)[tmp]) { + goal = ((unsigned long *)bh->b_data)[tmp]; + break; + } + } + if (!goal) + goal = bh->b_blocknr + 1; + } + tmp = ext2_new_block (inode->i_sb, goal); + if (!tmp) { + brelse (bh); + return NULL; + } + result = getblk (bh->b_dev, tmp, blocksize); + if (*p) { + ext2_free_block (inode->i_sb, tmp); + brelse (result); + goto repeat; + } + *p = tmp; + bh->b_dirt = 1; + if (IS_SYNC(inode)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + inode->i_ctime = CURRENT_TIME; + inode->i_blocks += blocks; + inode->i_dirt = 1; + inode->u.ext2_i.i_next_alloc_block = new_block; + inode->u.ext2_i.i_next_alloc_goal = tmp; + brelse (bh); + return result; + } + + struct buffer_head * ext2_getblk (struct inode * inode, long block, + int create, int * err) + { + struct buffer_head * bh; + unsigned long b; + unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + + *err = -EIO; + if (block < 0) { + ext2_warning (inode->i_sb, "ext2_getblk", "block < 0"); + return NULL; + } + if (block > EXT2_NDIR_BLOCKS + addr_per_block + + addr_per_block * addr_per_block + + addr_per_block * addr_per_block * addr_per_block) { + ext2_warning (inode->i_sb, "ext2_getblk", "block > big"); + return NULL; + } + /* If this is a sequential block allocation, set the next_alloc_block + to this block now so that all the indblock and data block + allocations use the same goal zone */ + + ext2_debug ("block %lu, next %lu, goal %lu.\n", block, + inode->u.ext2_i.i_next_alloc_block, + inode->u.ext2_i.i_next_alloc_goal); + + if (block == inode->u.ext2_i.i_next_alloc_block + 1) { + inode->u.ext2_i.i_next_alloc_block++; + inode->u.ext2_i.i_next_alloc_goal++; + } + + *err = -ENOSPC; + b = block; + if (block < EXT2_NDIR_BLOCKS) + return inode_getblk (inode, block, create, b, err); + block -= EXT2_NDIR_BLOCKS; + if (block < addr_per_block) { + bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, err); + return block_getblk (inode, bh, block, create, + inode->i_sb->s_blocksize, b, err); + } + block -= addr_per_block; + if (block < addr_per_block * addr_per_block) { + bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, err); + bh = block_getblk (inode, bh, block / addr_per_block, create, + inode->i_sb->s_blocksize, b, err); + return block_getblk (inode, bh, block & (addr_per_block - 1), + create, inode->i_sb->s_blocksize, b, err); + } + block -= addr_per_block * addr_per_block; + bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, err); + bh = block_getblk (inode, bh, block/(addr_per_block * addr_per_block), + create, inode->i_sb->s_blocksize, b, err); + bh = block_getblk (inode, bh, (block/addr_per_block) & (addr_per_block - 1), + create, inode->i_sb->s_blocksize, b, err); + return block_getblk (inode, bh, block & (addr_per_block - 1), create, + inode->i_sb->s_blocksize, b, err); + } + + struct buffer_head * ext2_bread (struct inode * inode, int block, + int create, int *err) + { + struct buffer_head * bh; + + bh = ext2_getblk (inode, block, create, err); + if (!bh || bh->b_uptodate) + return bh; + ll_rw_block (READ, 1, &bh); + wait_on_buffer (bh); + if (bh->b_uptodate) + return bh; + brelse (bh); + *err = -EIO; + return NULL; + } + + void ext2_read_inode (struct inode * inode) + { + struct buffer_head * bh; + struct ext2_inode * raw_inode; + unsigned long block_group; + unsigned long group_desc; + unsigned long desc; + unsigned long block; + struct ext2_group_desc * gdp; + + if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO && + inode->i_ino != EXT2_ACL_DATA_INO && inode->i_ino < EXT2_FIRST_INO) || + inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) { + ext2_error (inode->i_sb, "ext2_read_inode", + "bad inode number: %lu", inode->i_ino); + return; + } + block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb); + if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count) + ext2_panic (inode->i_sb, "ext2_read_inode", + "group >= groups count"); + group_desc = block_group / EXT2_DESC_PER_BLOCK(inode->i_sb); + desc = block_group % EXT2_DESC_PER_BLOCK(inode->i_sb); + bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc]; + if (!bh) + ext2_panic (inode->i_sb, "ext2_read_inode", + "Descriptor not loaded"); + gdp = (struct ext2_group_desc *) bh->b_data; + block = gdp[desc].bg_inode_table + + (((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) + / EXT2_INODES_PER_BLOCK(inode->i_sb)); + if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) + ext2_panic (inode->i_sb, "ext2_read_inode", + "unable to read i-node block\n" + "inode=%lu, block=%lu", inode->i_ino, block); + raw_inode = ((struct ext2_inode *) bh->b_data) + + (inode->i_ino - 1) % EXT2_INODES_PER_BLOCK(inode->i_sb); + inode->i_mode = raw_inode->i_mode; + inode->i_uid = raw_inode->i_uid; + inode->i_gid = raw_inode->i_gid; + inode->i_nlink = raw_inode->i_links_count; + inode->i_size = raw_inode->i_size; + inode->i_atime = raw_inode->i_atime; + inode->i_ctime = raw_inode->i_ctime; + inode->i_mtime = raw_inode->i_mtime; + inode->u.ext2_i.i_dtime = raw_inode->i_dtime; + inode->i_blksize = inode->i_sb->s_blocksize; + inode->i_blocks = raw_inode->i_blocks; + inode->u.ext2_i.i_flags = raw_inode->i_flags; + inode->u.ext2_i.i_faddr = raw_inode->i_faddr; + inode->u.ext2_i.i_frag = raw_inode->i_frag; + inode->u.ext2_i.i_fsize = raw_inode->i_fsize; + inode->u.ext2_i.i_file_acl = raw_inode->i_file_acl; + inode->u.ext2_i.i_dir_acl = raw_inode->i_dir_acl; + inode->u.ext2_i.i_version = raw_inode->i_version; + inode->u.ext2_i.i_block_group = block_group; + inode->u.ext2_i.i_next_alloc_block = 0; + inode->u.ext2_i.i_next_alloc_goal = 0; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + inode->i_rdev = raw_inode->i_block[0]; + else for (block = 0; block < EXT2_N_BLOCKS; block++) + inode->u.ext2_i.i_data[block] = raw_inode->i_block[block]; + brelse (bh); + inode->i_op = NULL; + if (inode->i_ino == EXT2_ACL_IDX_INO || + inode->i_ino == EXT2_ACL_DATA_INO) + /* Nothing to do */ ; + else if (S_ISREG(inode->i_mode)) + inode->i_op = &ext2_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &ext2_dir_inode_operations; + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &ext2_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); + if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) + inode->i_flags |= MS_SYNC; + } + + static struct buffer_head * ext2_update_inode (struct inode * inode) + { + struct buffer_head * bh; + struct ext2_inode * raw_inode; + unsigned long block_group; + unsigned long group_desc; + unsigned long desc; + unsigned long block; + struct ext2_group_desc * gdp; + + if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino < EXT2_FIRST_INO) || + inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) { + ext2_error (inode->i_sb, "ext2_write_inode", + "bad inode number: %lu", inode->i_ino); + return 0; + } + block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb); + if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count) + ext2_panic (inode->i_sb, "ext2_write_inode", + "group >= groups count"); + group_desc = block_group / EXT2_DESC_PER_BLOCK(inode->i_sb); + desc = block_group % EXT2_DESC_PER_BLOCK(inode->i_sb); + bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc]; + if (!bh) + ext2_panic (inode->i_sb, "ext2_write_inode", + "Descriptor not loaded"); + gdp = (struct ext2_group_desc *) bh->b_data; + block = gdp[desc].bg_inode_table + + (((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) + / EXT2_INODES_PER_BLOCK(inode->i_sb)); + if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) + ext2_panic (inode->i_sb, "ext2_write_inode", + "unable to read i-node block\n" + "inode=%lu, block=%lu", inode->i_ino, block); + raw_inode = ((struct ext2_inode *)bh->b_data) + + (inode->i_ino - 1) % EXT2_INODES_PER_BLOCK(inode->i_sb); + raw_inode->i_mode = inode->i_mode; + raw_inode->i_uid = inode->i_uid; + raw_inode->i_gid = inode->i_gid; + raw_inode->i_links_count = inode->i_nlink; + raw_inode->i_size = inode->i_size; + raw_inode->i_atime = inode->i_atime; + raw_inode->i_ctime = inode->i_ctime; + raw_inode->i_mtime = inode->i_mtime; + raw_inode->i_blocks = inode->i_blocks; + raw_inode->i_dtime = inode->u.ext2_i.i_dtime; + raw_inode->i_flags = inode->u.ext2_i.i_flags; + raw_inode->i_faddr = inode->u.ext2_i.i_faddr; + raw_inode->i_frag = inode->u.ext2_i.i_frag; + raw_inode->i_fsize = inode->u.ext2_i.i_fsize; + raw_inode->i_file_acl = inode->u.ext2_i.i_file_acl; + raw_inode->i_dir_acl = inode->u.ext2_i.i_dir_acl; + raw_inode->i_version = inode->u.ext2_i.i_version; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + raw_inode->i_block[0] = inode->i_rdev; + else for (block = 0; block < EXT2_N_BLOCKS; block++) + raw_inode->i_block[block] = inode->u.ext2_i.i_data[block]; + bh->b_dirt = 1; + inode->i_dirt = 0; + return bh; + } + + void ext2_write_inode (struct inode * inode) + { + struct buffer_head * bh; + bh = ext2_update_inode (inode); + brelse (bh); + } + + int ext2_sync_inode (struct inode *inode) + { + int err = 0; + struct buffer_head *bh; + + bh = ext2_update_inode (inode); + if (bh && bh->b_dirt) + { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + if (bh->b_req && !bh->b_uptodate) + { + printk ("IO error syncing ext2 inode [%04x:%08lx]\n", + inode->i_dev, inode->i_ino); + err = -1; + } + } + else if (!bh) + err = -1; + brelse (bh); + return err; + } diff -cr --new-file linux-0.07pl4/fs/ext2/ioctl.c linux-0.08/fs/ext2/ioctl.c *** linux-0.07pl4/fs/ext2/ioctl.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/ioctl.c Mon Nov 22 12:17:45 1993 *************** *** 0 **** --- 1,49 ---- + /* + * linux/fs/ext2/ioctl.c + * + * Copyright (C) 1993 Remy Card (card@masi.ibp.fr) + */ + + #include + + #include + #include + #include + #include + #include + + int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + unsigned long arg) + { + + ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); + + switch (cmd) { + case EXT2_IOC_GETFLAGS: + put_fs_long (inode->u.ext2_i.i_flags, (long *) arg); + return 0; + case EXT2_IOC_SETFLAGS: + if ((current->euid != inode->i_uid) && !suser()) + return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + inode->u.ext2_i.i_flags = get_fs_long ((long *) arg); + inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + return 0; + case EXT2_IOC_GETVERSION: + put_fs_long (inode->u.ext2_i.i_version, (long *) arg); + return 0; + case EXT2_IOC_SETVERSION: + if ((current->euid != inode->i_uid) && !suser()) + return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + inode->u.ext2_i.i_version = get_fs_long ((long *) arg); + inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + return 0; + default: + return -EINVAL; + } + } diff -cr --new-file linux-0.07pl4/fs/ext2/namei.c linux-0.08/fs/ext2/namei.c *** linux-0.07pl4/fs/ext2/namei.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/namei.c Tue Feb 1 17:04:04 1994 *************** *** 0 **** --- 1,1067 ---- + /* + * linux/fs/ext2/namei.c + * + * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) + * + * from + * + * linux/fs/minix/namei.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + + #include + + #include + #include + #include + #include + #include + #include + #include + #include + #include + + /* + * comment out this line if you want names > EXT2_NAME_LEN chars to be + * truncated. Else they will be disallowed. + */ + /* #define NO_TRUNCATE */ + + /* + * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. + */ + static int ext2_match (int len, const char * const name, + struct ext2_dir_entry * de) + { + unsigned char same; + + if (!de || !de->inode || len > EXT2_NAME_LEN) + return 0; + /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ + if (!len && de->name_len == 1 && (de->name[0] == '.') && + (de->name[1] == '\0')) + return 1; + if (len != de->name_len) + return 0; + #if defined(__i386__) + /* + * Oh please.... can't strncmp suffice? Hamish Macdonald + */ + __asm__("cld\n\t" + "repe ; cmpsb\n\t" + "setz %0" + :"=q" (same) + :"S" ((long) name), "D" ((long) de->name), "c" (len) + :"cx", "di", "si"); + #else + same = !strncmp (name, de->name, len); + #endif + return (int) same; + } + + /* + * ext2_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + * + */ + static struct buffer_head * ext2_find_entry (struct inode * dir, + const char * const name, int namelen, + struct ext2_dir_entry ** res_dir) + { + unsigned long offset; + struct buffer_head * bh; + struct ext2_dir_entry * de; + struct super_block * sb; + int err; + + *res_dir = NULL; + if (!dir) + return NULL; + sb = dir->i_sb; + #ifdef NO_TRUNCATE + if (namelen > EXT2_NAME_LEN) + return NULL; + #else + if (namelen > EXT2_NAME_LEN) + namelen = EXT2_NAME_LEN; + #endif + bh = ext2_bread (dir, 0, 0, &err); + if (!bh) + return NULL; + offset = 0; + de = (struct ext2_dir_entry *) bh->b_data; + while (offset < dir->i_size) { + if (!bh || (char *)de >= sb->s_blocksize + bh->b_data) { + brelse (bh); + bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 0, &err); + if (!bh) { + offset += sb->s_blocksize; + continue; + } + de = (struct ext2_dir_entry *) bh->b_data; + } + if (! ext2_check_dir_entry ("ext2_find_entry", dir, de, bh, + offset)) { + brelse (bh); + return NULL; + } + if (de->inode != 0 && ext2_match (namelen, name, de)) { + *res_dir = de; + return bh; + } + offset += de->rec_len; + de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + } + brelse (bh); + return NULL; + } + + int ext2_lookup (struct inode * dir, const char * name, int len, + struct inode ** result) + { + unsigned long ino; + struct ext2_dir_entry * de; + struct buffer_head * bh; + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput (dir); + return -ENOENT; + } + #ifndef DONT_USE_DCACHE + if (!(ino = ext2_dcache_lookup (dir->i_dev, dir->i_ino, name, len))) { + #endif + if (!(bh = ext2_find_entry (dir, name, len, &de))) { + iput (dir); + return -ENOENT; + } + ino = de->inode; + #ifndef DONT_USE_DCACHE + ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, + de->name_len, ino); + #endif + brelse (bh); + #ifndef DONT_USE_DCACHE + } + #endif + if (!(*result = iget (dir->i_sb, ino))) { + iput (dir); + return -EACCES; + } + iput (dir); + return 0; + } + + /* + * ext2_add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as ext2_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 * ext2_add_entry (struct inode * dir, + const char * name, int namelen, + struct ext2_dir_entry ** res_dir, + int *err) + { + unsigned long offset; + unsigned short rec_len; + struct buffer_head * bh; + struct ext2_dir_entry * de, * de1; + struct super_block * sb; + + *err = -EINVAL; + *res_dir = NULL; + if (!dir) + return NULL; + sb = dir->i_sb; + #ifdef NO_TRUNCATE + if (namelen > EXT2_NAME_LEN) + return NULL; + #else + if (namelen > EXT2_NAME_LEN) + namelen = EXT2_NAME_LEN; + #endif + if (!namelen) + return NULL; + /* Is this a busy deleted directory? Can't create new files + if so */ + if (dir->i_size == 0) + { + *err = -ENOENT; + return NULL; + } + bh = ext2_bread (dir, 0, 0, err); + if (!bh) + return NULL; + rec_len = EXT2_DIR_REC_LEN(namelen); + offset = 0; + de = (struct ext2_dir_entry *) bh->b_data; + *err = -ENOSPC; + while (1) { + if ((char *)de >= sb->s_blocksize + bh->b_data) { + brelse (bh); + bh = NULL; + bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, err); + if (!bh) + return NULL; + if (dir->i_size <= offset) { + if (dir->i_size == 0) { + *err = -ENOENT; + return NULL; + } + + ext2_debug ("creating next block\n"); + + de = (struct ext2_dir_entry *) bh->b_data; + de->inode = 0; + de->rec_len = sb->s_blocksize; + dir->i_size = offset + sb->s_blocksize; + dir->i_dirt = 1; + #if 0 /* XXX don't update any times until successful completion of syscall */ + dir->i_ctime = CURRENT_TIME; + #endif + } else { + + ext2_debug ("skipping to next block\n"); + + de = (struct ext2_dir_entry *) bh->b_data; + } + } + if (! ext2_check_dir_entry ("ext2_add_entry", dir, de, bh, + offset)) { + *err = -ENOENT; + brelse (bh); + return NULL; + } + if (de->inode != 0 && ext2_match (namelen, name, de)) { + *err = -EEXIST; + brelse (bh); + return NULL; + } + if ((de->inode == 0 && de->rec_len >= rec_len) || + (de->rec_len >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) { + offset += de->rec_len; + if (de->inode) { + de1 = (struct ext2_dir_entry *) ((char *) de + + EXT2_DIR_REC_LEN(de->name_len)); + de1->rec_len = de->rec_len - + EXT2_DIR_REC_LEN(de->name_len); + de->rec_len = EXT2_DIR_REC_LEN(de->name_len); + de = de1; + } + de->inode = 0; + de->name_len = namelen; + memcpy (de->name, name, namelen); + /* + * XXX shouldn't update any times until successful + * completion of syscall, but too many callers depend + * on this. + * + * XXX similarly, too many callers depend on + * ext2_new_inode() setting the times, but error + * recovery deletes the inode, so the worst that can + * happen is that the times are slightly out of date + * and/or different from the directory change time. + */ + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->i_dirt = 1; + bh->b_dirt = 1; + *res_dir = de; + *err = 0; + return bh; + } + offset += de->rec_len; + de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + } + brelse (bh); + return NULL; + } + + /* + * ext2_delete_entry deletes a directory entry by merging it with the + * previous entry + */ + static int ext2_delete_entry (struct ext2_dir_entry * dir, + struct buffer_head * bh) + { + struct ext2_dir_entry * de, * pde; + int i; + + i = 0; + pde = NULL; + de = (struct ext2_dir_entry *) bh->b_data; + while (i < bh->b_size) { + if (! ext2_check_dir_entry ("ext2_delete_entry", NULL, + de, bh, i)) + return -EIO; + if (de == dir) { + if (pde) + pde->rec_len += dir->rec_len; + /* XXX - must zero the inode number in every case !! */ + dir->inode = 0; + return 0; + } + i += de->rec_len; + pde = de; + de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + } + return -ENOENT; + } + + int ext2_create (struct inode * dir,const char * name, int len, int mode, + struct inode ** result) + { + struct inode * inode; + struct buffer_head * bh; + struct ext2_dir_entry * de; + int err; + + *result = NULL; + if (!dir) + return -ENOENT; + inode = ext2_new_inode (dir, mode); + if (!inode) { + iput (dir); + return -ENOSPC; + } + inode->i_op = &ext2_file_inode_operations; + inode->i_mode = mode; + inode->i_dirt = 1; + bh = ext2_add_entry (dir, name, len, &de, &err); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput (inode); + iput (dir); + return err; + } + de->inode = inode->i_ino; + #ifndef DONT_USE_DCACHE + ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, + de->inode); + #endif + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + iput (dir); + *result = inode; + return 0; + } + + int ext2_mknod (struct inode * dir, const char * name, int len, int mode, + int rdev) + { + struct inode * inode; + struct buffer_head * bh; + struct ext2_dir_entry * de; + int err; + + if (!dir) + return -ENOENT; + bh = ext2_find_entry (dir, name, len, &de); + if (bh) { + brelse (bh); + iput (dir); + return -EEXIST; + } + inode = ext2_new_inode (dir, mode); + if (!inode) { + iput (dir); + return -ENOSPC; + } + inode->i_uid = current->euid; + inode->i_mode = mode; + inode->i_op = NULL; + if (S_ISREG(inode->i_mode)) + inode->i_op = &ext2_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &ext2_dir_inode_operations; + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + } + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &ext2_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_rdev = rdev; + #if 0 + /* + * XXX we may as well use the times set by ext2_new_inode(). The + * following usually does nothing, but sometimes it invalidates + * inode->i_ctime. + */ + inode->i_mtime = inode->i_atime = CURRENT_TIME; + #endif + inode->i_dirt = 1; + bh = ext2_add_entry (dir, name, len, &de, &err); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput (inode); + iput (dir); + return err; + } + de->inode = inode->i_ino; + #ifndef DONT_USE_DCACHE + ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, + de->inode); + #endif + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + iput (dir); + iput (inode); + return 0; + } + + int ext2_mkdir (struct inode * dir, const char * name, int len, int mode) + { + struct inode * inode; + struct buffer_head * bh, * dir_block; + struct ext2_dir_entry * de; + int err; + + if (!dir) + return -ENOENT; + bh = ext2_find_entry (dir, name, len, &de); + if (bh) { + brelse (bh); + iput (dir); + return -EEXIST; + } + if (dir->i_nlink >= EXT2_LINK_MAX) { + iput (dir); + return -EMLINK; + } + inode = ext2_new_inode (dir, S_IFDIR); + if (!inode) { + iput (dir); + return -ENOSPC; + } + inode->i_op = &ext2_dir_inode_operations; + inode->i_size = inode->i_sb->s_blocksize; + #if 0 /* XXX as above */ + inode->i_mtime = inode->i_atime = CURRENT_TIME; + #endif + dir_block = ext2_bread (inode, 0, 1, &err); + if (!dir_block) { + iput (dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput (inode); + return err; + } + inode->i_blocks = inode->i_sb->s_blocksize / 512; + de = (struct ext2_dir_entry *) dir_block->b_data; + de->inode = inode->i_ino; + de->name_len = 1; + de->rec_len = EXT2_DIR_REC_LEN(de->name_len); + strcpy (de->name, "."); + de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + de->inode = dir->i_ino; + de->rec_len = inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1); + de->name_len = 2; + strcpy (de->name, ".."); + inode->i_nlink = 2; + dir_block->b_dirt = 1; + brelse (dir_block); + inode->i_mode = S_IFDIR | (mode & S_IRWXUGO & ~current->umask); + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + inode->i_dirt = 1; + bh = ext2_add_entry (dir, name, len, &de, &err); + if (!bh) { + iput (dir); + inode->i_nlink = 0; + inode->i_dirt = 1; + iput (inode); + return err; + } + de->inode = inode->i_ino; + #ifndef DONT_USE_DCACHE + ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, + de->inode); + #endif + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + dir->i_nlink++; + dir->i_dirt = 1; + iput (dir); + iput (inode); + brelse (bh); + return 0; + } + + /* + * routine to check that the specified directory is empty (for rmdir) + */ + static int empty_dir (struct inode * inode) + { + unsigned long offset; + struct buffer_head * bh; + struct ext2_dir_entry * de, * de1; + struct super_block * sb; + int err; + + sb = inode->i_sb; + if (inode->i_size < EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) || + !(bh = ext2_bread (inode, 0, 0, &err))) { + ext2_warning (inode->i_sb, "empty_dir", + "bad directory (dir %lu)", inode->i_ino); + return 1; + } + de = (struct ext2_dir_entry *) bh->b_data; + de1 = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + if (de->inode != inode->i_ino || !de1->inode || + strcmp (".", de->name) || strcmp ("..", de1->name)) { + ext2_warning (inode->i_sb, "empty_dir", + "bad directory (dir %lu)", inode->i_ino); + return 1; + } + offset = de->rec_len + de1->rec_len; + de = (struct ext2_dir_entry *) ((char *) de1 + de1->rec_len); + while (offset < inode->i_size ) { + if ((void *) de >= (void *) (bh->b_data + sb->s_blocksize)) { + brelse (bh); + bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &err); + if (!bh) { + offset += sb->s_blocksize; + continue; + } + de = (struct ext2_dir_entry *) bh->b_data; + } + if (! ext2_check_dir_entry ("empty_dir", inode, de, bh, + offset)) { + brelse (bh); + return 1; + } + if (de->inode) { + brelse (bh); + return 0; + } + offset += de->rec_len; + de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + } + brelse (bh); + return 1; + } + + int ext2_rmdir (struct inode * dir, const char * name, int len) + { + int retval; + struct inode * inode; + struct buffer_head * bh; + struct ext2_dir_entry * de; + + repeat: + if (!dir) + return -ENOENT; + inode = NULL; + bh = ext2_find_entry (dir, name, len, &de); + retval = -ENOENT; + if (!bh) + goto end_rmdir; + retval = -EPERM; + if (!(inode = iget (dir->i_sb, de->inode))) + goto end_rmdir; + if (inode->i_dev != dir->i_dev) + goto end_rmdir; + if (de->inode != inode->i_ino) { + iput(inode); + brelse(bh); + current->counter = 0; + schedule(); + goto repeat; + } + if ((dir->i_mode & S_ISVTX) && current->euid && + inode->i_uid != current->euid) + goto end_rmdir; + if (inode == dir) /* we may not delete ".", but "../dir" is ok */ + goto end_rmdir; + if (!S_ISDIR(inode->i_mode)) { + retval = -ENOTDIR; + goto end_rmdir; + } + if (!empty_dir (inode)) { + retval = -ENOTEMPTY; + goto end_rmdir; + } + if (de->inode != inode->i_ino) { + retval = -ENOENT; + goto end_rmdir; + } + if (inode->i_count > 1) { + /* Are we deleting the last instance of a busy directory? + Better clean up if so. */ + /* Make directory empty (it will be truncated when finally + dereferenced). This also inhibits ext2_add_entry. */ + inode->i_size = 0; + } + retval = ext2_delete_entry (de, bh); + if (retval) + goto end_rmdir; + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + #ifndef DONT_USE_DCACHE + ext2_dcache_remove(inode->i_dev, inode->i_ino, ".", 1); + ext2_dcache_remove(inode->i_dev, inode->i_ino, "..", 2); + #endif + if (inode->i_nlink != 2) + ext2_warning (inode->i_sb, "ext2_rmdir", + "empty directory has nlink!=2 (%d)", + inode->i_nlink); + #ifndef DONT_USE_DCACHE + ext2_dcache_remove (dir->i_dev, dir->i_ino, de->name, de->name_len); + #endif + inode->i_nlink = 0; + inode->i_dirt = 1; + dir->i_nlink--; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt = 1; + end_rmdir: + iput (dir); + iput (inode); + brelse (bh); + return retval; + } + + int ext2_unlink (struct inode * dir, const char * name, int len) + { + int retval; + struct inode * inode; + struct buffer_head * bh; + struct ext2_dir_entry * de; + + repeat: + if (!dir) + return -ENOENT; + retval = -ENOENT; + inode = NULL; + bh = ext2_find_entry (dir, name, len, &de); + if (!bh) + goto end_unlink; + if (!(inode = iget (dir->i_sb, de->inode))) + goto end_unlink; + retval = -EPERM; + if (S_ISDIR(inode->i_mode)) + goto end_unlink; + if (de->inode != inode->i_ino) { + iput(inode); + brelse(bh); + current->counter = 0; + schedule(); + goto repeat; + } + if ((dir->i_mode & S_ISVTX) && !suser() && + current->euid != inode->i_uid && + current->euid != dir->i_uid) + goto end_unlink; + if (!inode->i_nlink) { + ext2_warning (inode->i_sb, "ext2_unlink", + "Deleting nonexistent file (%lu), %d", + inode->i_ino, inode->i_nlink); + inode->i_nlink = 1; + } + retval = ext2_delete_entry (de, bh); + if (retval) + goto end_unlink; + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + #ifndef DONT_USE_DCACHE + ext2_dcache_remove (dir->i_dev, dir->i_ino, de->name, de->name_len); + #endif + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt = 1; + inode->i_nlink--; + inode->i_dirt = 1; + inode->i_ctime = dir->i_ctime; + retval = 0; + end_unlink: + brelse (bh); + iput (inode); + iput (dir); + return retval; + } + + int ext2_symlink (struct inode * dir, const char * name, int len, + const char * symname) + { + struct ext2_dir_entry * de; + struct inode * inode = NULL; + struct buffer_head * bh = NULL, * name_block = NULL; + char * link; + int i, err; + int l; + char c; + + if (!(inode = ext2_new_inode (dir, S_IFLNK))) { + iput (dir); + return -ENOSPC; + } + inode->i_mode = S_IFLNK | S_IRWXUGO; + inode->i_op = &ext2_symlink_inode_operations; + for (l = 0; l < inode->i_sb->s_blocksize - 1 && + symname [l]; l++) + ; + if (l >= EXT2_N_BLOCKS * sizeof (unsigned long)) { + + ext2_debug ("l=%d, normal symlink\n", l); + + name_block = ext2_bread (inode, 0, 1, &err); + if (!name_block) { + iput (dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput (inode); + return err; + } + link = name_block->b_data; + } else { + link = (char *) inode->u.ext2_i.i_data; + + ext2_debug ("l=%d, fast symlink\n", l); + + } + i = 0; + while (i < inode->i_sb->s_blocksize - 1 && (c = *(symname++))) + link[i++] = c; + link[i] = 0; + if (name_block) { + name_block->b_dirt = 1; + brelse (name_block); + } + inode->i_size = i; + inode->i_dirt = 1; + bh = ext2_find_entry (dir, name, len, &de); + if (bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput (inode); + brelse (bh); + iput (dir); + return -EEXIST; + } + bh = ext2_add_entry (dir, name, len, &de, &err); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput (inode); + iput (dir); + return err; + } + de->inode = inode->i_ino; + #ifndef DONT_USE_DCACHE + ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, + de->inode); + #endif + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + iput (dir); + iput (inode); + return 0; + } + + int ext2_link (struct inode * oldinode, struct inode * dir, + const char * name, int len) + { + struct ext2_dir_entry * de; + struct buffer_head * bh; + int err; + + if (S_ISDIR(oldinode->i_mode)) { + iput (oldinode); + iput (dir); + return -EPERM; + } + if (oldinode->i_nlink >= EXT2_LINK_MAX) { + iput (oldinode); + iput (dir); + return -EMLINK; + } + bh = ext2_find_entry (dir, name, len, &de); + if (bh) { + brelse (bh); + iput (dir); + iput (oldinode); + return -EEXIST; + } + bh = ext2_add_entry (dir, name, len, &de, &err); + if (!bh) { + iput (dir); + iput (oldinode); + return err; + } + de->inode = oldinode->i_ino; + #ifndef DONT_USE_DCACHE + ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, + de->inode); + #endif + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + iput (dir); + oldinode->i_nlink++; + oldinode->i_ctime = CURRENT_TIME; + oldinode->i_dirt = 1; + iput (oldinode); + return 0; + } + + static int subdir (struct inode * new_inode, struct inode * old_inode) + { + int ino; + int result; + + new_inode->i_count++; + result = 0; + for (;;) { + if (new_inode == old_inode) { + result = 1; + break; + } + if (new_inode->i_dev != old_inode->i_dev) + break; + ino = new_inode->i_ino; + if (ext2_lookup (new_inode, "..", 2, &new_inode)) + break; + if (new_inode->i_ino == ino) + break; + } + iput (new_inode); + return result; + } + + #define PARENT_INO(buffer) \ + ((struct ext2_dir_entry *) ((char *) buffer + \ + ((struct ext2_dir_entry *) buffer)->rec_len))->inode + + #define PARENT_NAME(buffer) \ + ((struct ext2_dir_entry *) ((char *) buffer + \ + ((struct ext2_dir_entry *) buffer)->rec_len))->name + + /* + * rename uses retrying to avoid race-conditions: at least they should be + * minimal. + * it tries to allocate all the blocks, then sanity-checks, and if the sanity- + * checks fail, it tries to restart itself again. Very practical - no changes + * are done until we know everything works ok.. and then all the changes can be + * done in one fell swoop when we have claimed all the buffers needed. + * + * Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ + static int do_ext2_rename (struct inode * old_dir, const char * old_name, + int old_len, struct inode * new_dir, + const char * new_name, int new_len) + { + struct inode * old_inode, * new_inode; + struct buffer_head * old_bh, * new_bh, * dir_bh; + struct ext2_dir_entry * old_de, * new_de; + int retval; + + goto start_up; + try_again: + if (new_bh && new_de) + ext2_delete_entry(new_de, new_bh); + brelse (old_bh); + brelse (new_bh); + brelse (dir_bh); + iput (old_inode); + iput (new_inode); + current->counter = 0; + schedule (); + start_up: + old_inode = new_inode = NULL; + old_bh = new_bh = dir_bh = NULL; + new_de = NULL; + old_bh = ext2_find_entry (old_dir, old_name, old_len, &old_de); + retval = -ENOENT; + if (!old_bh) + goto end_rename; + old_inode = __iget (old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */ + if (!old_inode) + goto end_rename; + retval = -EPERM; + if ((old_dir->i_mode & S_ISVTX) && + current->euid != old_inode->i_uid && + current->euid != old_dir->i_uid && !suser()) + goto end_rename; + new_bh = ext2_find_entry (new_dir, new_name, new_len, &new_de); + if (new_bh) { + new_inode = __iget (new_dir->i_sb, new_de->inode, 0); /* no mntp cross */ + if (!new_inode) { + brelse (new_bh); + new_bh = NULL; + } + } + if (new_inode == old_inode) { + retval = 0; + goto end_rename; + } + if (new_inode && S_ISDIR(new_inode->i_mode)) { + retval = -EISDIR; + if (!S_ISDIR(old_inode->i_mode)) + goto end_rename; + retval = -EINVAL; + if (subdir (new_dir, old_inode)) + goto end_rename; + retval = -ENOTEMPTY; + if (!empty_dir (new_inode)) + goto end_rename; + retval = -EBUSY; + if (new_inode->i_count > 1) + goto end_rename; + } + retval = -EPERM; + if (new_inode && (new_dir->i_mode & S_ISVTX) && + current->euid != new_inode->i_uid && + current->euid != new_dir->i_uid && !suser()) + goto end_rename; + if (S_ISDIR(old_inode->i_mode)) { + retval = -ENOTDIR; + if (new_inode && !S_ISDIR(new_inode->i_mode)) + goto end_rename; + retval = -EINVAL; + if (subdir (new_dir, old_inode)) + goto end_rename; + dir_bh = ext2_bread (old_inode, 0, 0, &retval); + if (!dir_bh) + goto end_rename; + if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) + goto end_rename; + retval = -EMLINK; + if (!new_inode && new_dir->i_nlink >= EXT2_LINK_MAX) + goto end_rename; + } + if (!new_bh) + new_bh = ext2_add_entry (new_dir, new_name, new_len, &new_de, + &retval); + if (!new_bh) + goto end_rename; + /* sanity checking before doing the rename - avoid races */ + if (new_inode && (new_de->inode != new_inode->i_ino)) + goto try_again; + if (new_de->inode && !new_inode) + goto try_again; + if (old_de->inode != old_inode->i_ino) + goto try_again; + /* ok, that's it */ + new_de->inode = old_inode->i_ino; + #ifndef DONT_USE_DCACHE + ext2_dcache_remove (old_dir->i_dev, old_dir->i_ino, old_de->name, + old_de->name_len); + ext2_dcache_add (new_dir->i_dev, new_dir->i_ino, new_de->name, + new_de->name_len, new_de->inode); + #endif + retval = ext2_delete_entry (old_de, old_bh); + if (retval == -ENOENT) + goto try_again; + if (retval) + goto end_rename; + if (new_inode) { + new_inode->i_nlink--; + new_inode->i_ctime = CURRENT_TIME; + new_inode->i_dirt = 1; + } + old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; + old_dir->i_dirt = 1; + old_bh->b_dirt = 1; + if (IS_SYNC(old_dir)) { + ll_rw_block (WRITE, 1, &old_bh); + wait_on_buffer (old_bh); + } + new_bh->b_dirt = 1; + if (IS_SYNC(new_dir)) { + ll_rw_block (WRITE, 1, &new_bh); + wait_on_buffer (new_bh); + } + if (dir_bh) { + PARENT_INO(dir_bh->b_data) = new_dir->i_ino; + dir_bh->b_dirt = 1; + old_dir->i_nlink--; + old_dir->i_dirt = 1; + if (new_inode) { + new_inode->i_nlink--; + new_inode->i_dirt = 1; + } else { + new_dir->i_nlink++; + new_dir->i_dirt = 1; + } + } + retval = 0; + end_rename: + brelse (dir_bh); + brelse (old_bh); + brelse (new_bh); + iput (old_inode); + iput (new_inode); + iput (old_dir); + iput (new_dir); + return retval; + } + + /* + * Ok, rename also locks out other renames, as they can change the parent of + * a directory, and we don't want any races. Other races are checked for by + * "do_rename()", which restarts if there are inconsistencies. + * + * Note that there is no race between different filesystems: it's only within + * the same device that races occur: many renames can happen at once, as long + * as they are on different partitions. + * + * In the second extended file system, we use a lock flag stored in the memory + * super-block. This way, we really lock other renames only if they occur + * on the same file system + */ + int ext2_rename (struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) + { + int result; + + while (old_dir->i_sb->u.ext2_sb.s_rename_lock) + sleep_on (&old_dir->i_sb->u.ext2_sb.s_rename_wait); + old_dir->i_sb->u.ext2_sb.s_rename_lock = 1; + result = do_ext2_rename (old_dir, old_name, old_len, new_dir, + new_name, new_len); + old_dir->i_sb->u.ext2_sb.s_rename_lock = 0; + wake_up (&old_dir->i_sb->u.ext2_sb.s_rename_wait); + return result; + } diff -cr --new-file linux-0.07pl4/fs/ext2/super.c linux-0.08/fs/ext2/super.c *** linux-0.07pl4/fs/ext2/super.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/super.c Mon Nov 22 12:17:45 1993 *************** *** 0 **** --- 1,535 ---- + /* + * linux/fs/ext2/super.c + * + * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) + * + * from + * + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + + #include + + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + + extern int vsprintf (char *, const char *, va_list); + + void ext2_error (struct super_block * sb, const char * function, + const char * fmt, ...) + { + char buf[1024]; + va_list args; + + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS; + sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + } + va_start (args, fmt); + vsprintf (buf, fmt, args); + va_end (args); + printk ( + #ifdef KERN_ERR + KERN_ERR + #endif + "EXT2-fs error (device %d/%d): %s: %s\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf); + } + + volatile void ext2_panic (struct super_block * sb, const char * function, + const char * fmt, ...) + { + char buf[1024]; + va_list args; + + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS; + sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + } + va_start (args, fmt); + vsprintf (buf, fmt, args); + va_end (args); + panic ("EXT2-fs panic (device %d/%d): %s: %s\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf); + } + + void ext2_warning (struct super_block * sb, const char * function, + const char * fmt, ...) + { + char buf[1024]; + va_list args; + + va_start (args, fmt); + vsprintf (buf, fmt, args); + va_end (args); + printk ( + #ifdef KERN_WARNING + KERN_WARNING + #endif + "EXT2-fs warning (device %d/%d): %s: %s\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf); + } + + void ext2_put_super (struct super_block * sb) + { + int i; + + lock_super (sb); + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.ext2_sb.s_es->s_state = sb->u.ext2_sb.s_mount_state; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + } + #ifndef DONT_USE_DCACHE + ext2_dcache_invalidate (sb->s_dev); + #endif + sb->s_dev = 0; + for (i = 0; i < EXT2_MAX_GROUP_DESC; i++) + if (sb->u.ext2_sb.s_group_desc[i]) + brelse (sb->u.ext2_sb.s_group_desc[i]); + for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) + if (sb->u.ext2_sb.s_inode_bitmap[i]) + brelse (sb->u.ext2_sb.s_inode_bitmap[i]); + for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) + if (sb->u.ext2_sb.s_block_bitmap[i]) + brelse (sb->u.ext2_sb.s_block_bitmap[i]); + brelse (sb->u.ext2_sb.s_sbh); + unlock_super (sb); + return; + } + + static struct super_operations ext2_sops = { + ext2_read_inode, + NULL, + ext2_write_inode, + ext2_put_inode, + ext2_put_super, + ext2_write_super, + ext2_statfs, + ext2_remount + }; + + #ifdef EXT2FS_PRE_02B_COMPAT + + static int convert_pre_02b_fs (struct super_block * sb, + struct buffer_head * bh) + { + struct ext2_super_block * es; + struct ext2_old_group_desc old_group_desc [BLOCK_SIZE / sizeof (struct ext2_old_group_desc)]; + struct ext2_group_desc * gdp; + struct buffer_head * bh2; + int groups_count; + int i; + + es = (struct ext2_super_block *) bh->b_data; + bh2 = bread (sb->s_dev, 2, BLOCK_SIZE); + if (!bh2) { + printk ("Cannot read descriptor blocks while converting !\n"); + return 0; + } + memcpy (old_group_desc, bh2->b_data, BLOCK_SIZE); + groups_count = (sb->u.ext2_sb.s_blocks_count - + sb->u.ext2_sb.s_first_data_block + + (EXT2_BLOCK_SIZE(sb) * 8) - 1) / + (EXT2_BLOCK_SIZE(sb) * 8); + memset (bh2->b_data, 0, BLOCK_SIZE); + gdp = (struct ext2_group_desc *) bh2->b_data; + for (i = 0; i < groups_count; i++) { + gdp[i].bg_block_bitmap = old_group_desc[i].bg_block_bitmap; + gdp[i].bg_inode_bitmap = old_group_desc[i].bg_inode_bitmap; + gdp[i].bg_inode_table = old_group_desc[i].bg_inode_table; + gdp[i].bg_free_blocks_count = old_group_desc[i].bg_free_blocks_count; + gdp[i].bg_free_inodes_count = old_group_desc[i].bg_free_inodes_count; + } + bh2->b_dirt = 1; + brelse (bh2); + es->s_magic = EXT2_SUPER_MAGIC; + bh->b_dirt = 1; + sb->s_magic = EXT2_SUPER_MAGIC; + return 1; + } + + #endif + + /* + * This function has been shamelessly adapted from the msdos fs + */ + static int parse_options (char * options, unsigned long * sb_block, + unsigned long * mount_options) + { + char * this_char; + char * value; + + if (!options) + return 1; + for (this_char = strtok (options, ","); + this_char != NULL; + this_char = strtok (NULL, ",")) { + if ((value = strchr (this_char, '=')) != NULL) + *value++ = 0; + if (!strcmp (this_char, "check")) + *mount_options |= EXT2_MOUNT_CHECK; + else if (!strcmp (this_char, "sb")) { + if (!value || !*value) + return 0; + *sb_block = simple_strtoul (value, &value, 0); + if (*value) + return 0; + } + else { + printk ("EXT2-fs: Unrecognized mount option %s\n", this_char); + return 0; + } + } + return 1; + } + + struct super_block * ext2_read_super (struct super_block * s, void * data, + int silent) + { + struct buffer_head * bh; + struct ext2_super_block * es; + unsigned long sb_block = 1; + unsigned long logic_sb_block = 1; + int dev = s->s_dev; + int bh_count; + int i, j; + #ifdef EXT2FS_PRE_02B_COMPAT + int fs_converted = 0; + #endif + + s->u.ext2_sb.s_mount_opt = 0; + if (!parse_options ((char *) data, &sb_block, + &s->u.ext2_sb.s_mount_opt)) { + s->s_dev = 0; + return NULL; + } + + lock_super (s); + set_blocksize (dev, BLOCK_SIZE); + if (!(bh = bread (dev, sb_block, BLOCK_SIZE))) { + s->s_dev = 0; + unlock_super (s); + printk ("EXT2-fs: unable to read superblock\n"); + return NULL; + } + es = (struct ext2_super_block *) bh->b_data; + /* Note: s_es must be initialized s_es as soon as possible because + some ext2 macro-instructions depend on its value */ + s->u.ext2_sb.s_es = es; + s->s_magic = es->s_magic; + if (s->s_magic != EXT2_SUPER_MAGIC + #ifdef EXT2FS_PRE_02B_COMPAT + && s->s_magic != EXT2_PRE_02B_MAGIC + #endif + ) { + s->s_dev = 0; + unlock_super (s); + brelse (bh); + if (!silent) + printk ("VFS: Can't find an ext2 filesystem on dev 0x%04x.\n", + dev); + return NULL; + } + s->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size; + s->s_blocksize_bits = EXT2_BLOCK_SIZE_BITS(s); + if (s->s_blocksize != BLOCK_SIZE && + (s->s_blocksize == 1024 || s->s_blocksize == 2048 || + s->s_blocksize == 4096)) { + unsigned long offset; + + brelse (bh); + set_blocksize (dev, s->s_blocksize); + logic_sb_block = sb_block / s->s_blocksize; + offset = sb_block % s->s_blocksize; + bh = bread (dev, logic_sb_block, s->s_blocksize); + if(!bh) + return NULL; + es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); + s->u.ext2_sb.s_es = es; + if (es->s_magic != EXT2_SUPER_MAGIC) { + s->s_dev = 0; + unlock_super (s); + brelse (bh); + printk ("EXT2-fs: Magic mismatch, very weird !\n"); + return NULL; + } + } + s->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE << + es->s_log_frag_size; + if (s->u.ext2_sb.s_frag_size) + s->u.ext2_sb.s_frags_per_block = s->s_blocksize / + s->u.ext2_sb.s_frag_size; + else + s->s_magic = 0; + s->u.ext2_sb.s_blocks_per_group = es->s_blocks_per_group; + s->u.ext2_sb.s_frags_per_group = es->s_frags_per_group; + s->u.ext2_sb.s_inodes_per_group = es->s_inodes_per_group; + s->u.ext2_sb.s_inodes_per_block = s->s_blocksize / + sizeof (struct ext2_inode); + s->u.ext2_sb.s_desc_per_block = s->s_blocksize / + sizeof (struct ext2_group_desc); + s->u.ext2_sb.s_sbh = bh; + s->u.ext2_sb.s_es = es; + s->u.ext2_sb.s_mount_state = es->s_state; + s->u.ext2_sb.s_rename_lock = 0; + s->u.ext2_sb.s_rename_wait = NULL; + #ifdef EXT2FS_PRE_02B_COMPAT + if (s->s_magic == EXT2_PRE_02B_MAGIC) { + if (es->s_blocks_count > 262144) { + /* fs > 256 MB can't be converted */ + s->s_dev = 0; + unlock_super (s); + brelse (bh); + printk ("EXT2-fs: trying to mount a pre-0.2b file" + "system which cannot be converted\n"); + return NULL; + } + printk ("EXT2-fs: mounting a pre 0.2b file system, " + "will try to convert the structure\n"); + if (!(s->s_flags & MS_RDONLY)) { + s->s_dev = 0; + unlock_super (s); + brelse (bh); + printk ("EXT2-fs: cannot convert a read-only fs\n"); + return NULL; + } + if (!convert_pre_02b_fs (s, bh)) { + s->s_dev = 0; + unlock_super (s); + brelse (bh); + printk ("EXT2-fs: conversion failed !!!\n"); + return NULL; + } + printk ("EXT2-fs: conversion succeeded !!!\n"); + fs_converted = 1; + } + #endif + if (s->s_magic != EXT2_SUPER_MAGIC) { + s->s_dev = 0; + unlock_super (s); + brelse (bh); + if (!silent) + printk ("VFS: Can't find an ext2 filesystem on dev 0x%04x.\n", + dev); + return NULL; + } + if (s->s_blocksize != bh->b_size) { + s->s_dev = 0; + unlock_super (s); + brelse (bh); + if (!silent) + printk ("VFS: Unsupported blocksize on dev 0x%04x.\n", + dev); + return NULL; + } + + if (s->s_blocksize != s->u.ext2_sb.s_frag_size) { + s->s_dev = 0; + unlock_super (s); + brelse (bh); + printk ("EXT2-fs: fragsize %lu != blocksize %lu (not supported yet)\n", + s->u.ext2_sb.s_frag_size, s->s_blocksize); + return NULL; + } + + s->u.ext2_sb.s_groups_count = (es->s_blocks_count - + es->s_first_data_block + + EXT2_BLOCKS_PER_GROUP(s) - 1) / + EXT2_BLOCKS_PER_GROUP(s); + for (i = 0; i < EXT2_MAX_GROUP_DESC; i++) + s->u.ext2_sb.s_group_desc[i] = NULL; + bh_count = (s->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(s) - 1) / + EXT2_DESC_PER_BLOCK(s); + if (bh_count > EXT2_MAX_GROUP_DESC) { + s->s_dev = 0; + unlock_super (s); + brelse (bh); + printk ("EXT2-fs: file system is too big\n"); + return NULL; + } + for (i = 0; i < bh_count; i++) { + s->u.ext2_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1, + s->s_blocksize); + if (!s->u.ext2_sb.s_group_desc[i]) { + s->s_dev = 0; + unlock_super (s); + for (j = 0; j < i; j++) + brelse (s->u.ext2_sb.s_group_desc[i]); + brelse (bh); + printk ("EXT2-fs: unable to read group descriptors\n"); + return NULL; + } + } + for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) { + s->u.ext2_sb.s_inode_bitmap_number[i] = 0; + s->u.ext2_sb.s_inode_bitmap[i] = NULL; + s->u.ext2_sb.s_block_bitmap_number[i] = 0; + s->u.ext2_sb.s_block_bitmap[i] = NULL; + } + s->u.ext2_sb.s_loaded_inode_bitmaps = 0; + s->u.ext2_sb.s_loaded_block_bitmaps = 0; + unlock_super (s); + /* set up enough so that it can read an inode */ + s->s_dev = dev; + s->s_op = &ext2_sops; + if (!(s->s_mounted = iget (s, EXT2_ROOT_INO))) { + s->s_dev = 0; + for (i = 0; i < EXT2_MAX_GROUP_DESC; i++) + if (s->u.ext2_sb.s_group_desc[i]) + brelse (s->u.ext2_sb.s_group_desc[i]); + brelse (bh); + printk ("EXT2-fs: get root inode failed\n"); + return NULL; + } + if (!(s->s_flags & MS_RDONLY)) { + es->s_state &= ~EXT2_VALID_FS; + if (!es->s_max_mnt_count) + es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT; + es->s_mnt_count++; + es->s_mtime = CURRENT_TIME; + bh->b_dirt = 1; + s->s_dirt = 1; + } + #ifdef EXT2FS_PRE_02B_COMPAT + if (fs_converted) { + for (i = 0; i < bh_count; i++) + s->u.ext2_sb.s_group_desc[i]->b_dirt = 1; + s->s_dirt = 1; + } + #endif + if (!(s->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) + printk ("EXT2-fs warning: mounting unchecked file system, " + "running e2fsck is recommended\n"); + else if (s->u.ext2_sb.s_mount_state & EXT2_ERROR_FS) + printk ("EXT2-fs warning: mounting file system with errors, " + "running e2fsck is recommended\n"); + else if (es->s_mnt_count >= es->s_max_mnt_count) + printk ("EXT2-fs warning: maximal mount count reached, " + "running e2fsck is recommended\n"); + if (s->u.ext2_sb.s_mount_opt & EXT2_MOUNT_CHECK) { + printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, bpg=%lu, ipg=%lu]\n", + EXT2FS_VERSION, EXT2FS_DATE, s->s_blocksize, + s->u.ext2_sb.s_frag_size, s->u.ext2_sb.s_groups_count, + EXT2_BLOCKS_PER_GROUP(s), EXT2_INODES_PER_GROUP(s)); + ext2_check_blocks_bitmap (s); + ext2_check_inodes_bitmap (s); + } + return s; + } + + static void ext2_commit_super (struct super_block * sb, + struct ext2_super_block * es) + { + es->s_wtime = CURRENT_TIME; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 0; + } + + /* + * In the second extended file system, it is not necessary to + * write the super block since we use a mapping of the + * disk super block in a buffer. + * + * However, this function is still used to set the fs valid + * flags to 0. We need to set this flag to 0 since the fs + * may have been checked while mounted and e2fsck may have + * set s_state to EXT2_VALID_FS after some corrections. + */ + + void ext2_write_super (struct super_block * sb) + { + struct ext2_super_block * es; + + if (!(sb->s_flags & MS_RDONLY)) { + es = sb->u.ext2_sb.s_es; + + ext2_debug ("setting valid to 0\n"); + + if (es->s_state & EXT2_VALID_FS) { + es->s_state &= ~EXT2_VALID_FS; + es->s_mtime = CURRENT_TIME; + } + ext2_commit_super (sb, es); + } + sb->s_dirt = 0; + } + + int ext2_remount (struct super_block * sb, int * flags) + { + struct ext2_super_block * es; + + es = sb->u.ext2_sb.s_es; + if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) + return 0; + if (*flags & MS_RDONLY) { + if (es->s_state & EXT2_VALID_FS || + !(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) + return 0; + /* OK, we are remounting a valid rw partition rdonly, so set + the rdonly flag and then mark the partition as valid + again. */ + es->s_state = sb->u.ext2_sb.s_mount_state; + es->s_mtime = CURRENT_TIME; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + ext2_commit_super (sb, es); + } + else { + /* Mounting a RDONLY partition read-write, so reread and + store the current valid flag. (It may have been changed + by e2fsck since we originally mounted the partition.) */ + sb->u.ext2_sb.s_mount_state = es->s_state; + es->s_state &= ~EXT2_VALID_FS; + if (!es->s_max_mnt_count) + es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT; + es->s_mnt_count++; + es->s_mtime = CURRENT_TIME; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) + printk ("EXT2-fs warning: remounting unchecked fs, " + "running e2fsck is recommended\n"); + else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS)) + printk ("EXT2-fs warning: remounting fs with errors, " + "running e2fsck is recommended\n"); + else if (es->s_mnt_count >= es->s_max_mnt_count) + printk ("EXT2-fs warning: maximal mount count reached, " + "running e2fsck is recommended\n"); + } + return 0; + } + + void ext2_statfs (struct super_block * sb, struct statfs * buf) + { + long tmp; + + put_fs_long (EXT2_SUPER_MAGIC, &buf->f_type); + put_fs_long (sb->s_blocksize, &buf->f_bsize); + put_fs_long (sb->u.ext2_sb.s_es->s_blocks_count, &buf->f_blocks); + tmp = ext2_count_free_blocks (sb); + put_fs_long (tmp, &buf->f_bfree); + if (tmp >= sb->u.ext2_sb.s_es->s_r_blocks_count) + put_fs_long (tmp - sb->u.ext2_sb.s_es->s_r_blocks_count, + &buf->f_bavail); + else + put_fs_long (0, &buf->f_bavail); + put_fs_long (sb->u.ext2_sb.s_es->s_inodes_count, &buf->f_files); + put_fs_long (ext2_count_free_inodes (sb), &buf->f_ffree); + put_fs_long (EXT2_NAME_LEN, &buf->f_namelen); + /* Don't know what value to put in buf->f_fsid */ + } diff -cr --new-file linux-0.07pl4/fs/ext2/symlink.c linux-0.08/fs/ext2/symlink.c *** linux-0.07pl4/fs/ext2/symlink.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/symlink.c Mon Nov 22 12:17:46 1993 *************** *** 0 **** --- 1,124 ---- + /* + * linux/fs/ext2/symlink.c + * + * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) + * + * from + * + * linux/fs/minix/symlink.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext2 symlink handling code + */ + + #include + + #include + #include + #include + #include + #include + + static int ext2_readlink (struct inode *, char *, int); + static int ext2_follow_link (struct inode *, struct inode *, int, int, + struct inode **); + + /* + * symlinks can't do much... + */ + struct inode_operations ext2_symlink_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + ext2_readlink, /* readlink */ + ext2_follow_link, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ + }; + + static int ext2_follow_link(struct inode * dir, struct inode * inode, + int flag, int mode, struct inode ** res_inode) + { + int error; + struct buffer_head * bh = NULL; + char * link; + + *res_inode = NULL; + if (!dir) { + dir = current->root; + dir->i_count++; + } + if (!inode) { + iput (dir); + return -ENOENT; + } + if (!S_ISLNK(inode->i_mode)) { + iput (dir); + *res_inode = inode; + return 0; + } + if (current->link_count > 5) { + iput (dir); + iput (inode); + return -ELOOP; + } + if (inode->i_blocks) { + if (!(bh = ext2_bread (inode, 0, 0, &error))) { + iput (dir); + iput (inode); + return -EIO; + } + link = bh->b_data; + } else + link = (char *) inode->u.ext2_i.i_data; + current->link_count++; + error = open_namei (link, flag, mode, res_inode, dir); + current->link_count--; + iput (inode); + if (bh) + brelse (bh); + return error; + } + + static int ext2_readlink (struct inode * inode, char * buffer, int buflen) + { + struct buffer_head * bh = NULL; + char * link; + int i, err; + char c; + + if (!S_ISLNK(inode->i_mode)) { + iput (inode); + return -EINVAL; + } + if (buflen > inode->i_sb->s_blocksize - 1) + buflen = inode->i_sb->s_blocksize - 1; + if (inode->i_blocks) { + bh = ext2_bread (inode, 0, 0, &err); + if (!bh) { + iput (inode); + return 0; + } + link = bh->b_data; + } + else + link = (char *) inode->u.ext2_i.i_data; + i = 0; + while (i < buflen && (c = link[i])) { + i++; + put_fs_byte (c, buffer++); + } + iput (inode); + if (bh) + brelse (bh); + return i; + } diff -cr --new-file linux-0.07pl4/fs/ext2/truncate.c linux-0.08/fs/ext2/truncate.c *** linux-0.07pl4/fs/ext2/truncate.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/ext2/truncate.c Sat Mar 19 12:29:09 1994 *************** *** 0 **** --- 1,336 ---- + /* + * linux/fs/ext2/truncate.c + * + * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) + * + * from + * + * linux/fs/minix/truncate.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + + #include + #include + #include + #include + #include + #include + #include + + #if defined (__i386__) + /* can gcc *really* not optimize the following C version sufficiently + * enough that it could *not* be inline assembler? Hamish Macdonald + */ + #define clear_block(addr,size,value) \ + __asm__("cld\n\t" \ + "rep\n\t" \ + "stosl" \ + : \ + :"a" (value), "c" (size / 4), "D" ((long) (addr)) \ + :"cx", "di") + #else + #define clear_block(addr,size,value) { \ + int i; \ + unsigned long *p = (unsigned long *)addr; \ + for (i = 0; i < size/4; i++) \ + *p++ = (unsigned long)value; \ + } + #endif + + /* + * Truncate has the most races in the whole filesystem: coding it is + * a pain in the a**. Especially as I don't do any locking... + * + * The code may look a bit weird, but that's just because I've tried to + * handle things like file-size changes in a somewhat graceful manner. + * Anyway, truncating a file at the same time somebody else writes to it + * is likely to result in pretty weird behaviour... + * + * The new code handles normal truncates (size = 0) as well as the more + * general case (size = XXX). I hope. + */ + + static int trunc_direct (struct inode * inode) + { + int i, tmp; + unsigned long * p; + struct buffer_head * bh; + int retry = 0; + int blocks = inode->i_sb->s_blocksize / 512; + #define DIRECT_BLOCK ((inode->i_size + inode->i_sb->s_blocksize - 1) / \ + inode->i_sb->s_blocksize) + int direct_block = DIRECT_BLOCK; + + repeat: + for (i = direct_block ; i < EXT2_NDIR_BLOCKS ; i++) { + p = inode->u.ext2_i.i_data + i; + tmp = *p; + if (!tmp) + continue; + if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) + bh = getblk (inode->i_dev, tmp, + inode->i_sb->s_blocksize); + else + bh = get_hash_table (inode->i_dev, tmp, + inode->i_sb->s_blocksize); + if (i < direct_block) { + brelse (bh); + goto repeat; + } + if ((bh && bh->b_count != 1) || tmp != *p) { + retry = 1; + brelse (bh); + continue; + } + *p = 0; + inode->i_blocks -= blocks; + inode->i_dirt = 1; + if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) { + clear_block (bh->b_data, inode->i_sb->s_blocksize, + CURRENT_TIME); + bh->b_dirt = 1; + } + brelse (bh); + ext2_free_block (inode->i_sb, tmp); + } + return retry; + } + + static int trunc_indirect (struct inode * inode, int offset, unsigned long * p) + { + int i, tmp; + struct buffer_head * bh; + struct buffer_head * ind_bh; + unsigned long * ind; + int retry = 0; + int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + int blocks = inode->i_sb->s_blocksize / 512; + #define INDIRECT_BLOCK ((int)DIRECT_BLOCK - offset) + int indirect_block = INDIRECT_BLOCK; + + tmp = *p; + if (!tmp) + return 0; + ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); + if (tmp != *p) { + brelse (ind_bh); + return 1; + } + if (!ind_bh) { + *p = 0; + return 0; + } + repeat: + for (i = indirect_block ; i < addr_per_block ; i++) { + if (i < 0) + i = 0; + if (i < indirect_block) + goto repeat; + ind = i + (unsigned long *) ind_bh->b_data; + tmp = *ind; + if (!tmp) + continue; + if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) + bh = getblk (inode->i_dev, tmp, + inode->i_sb->s_blocksize); + else + bh = get_hash_table (inode->i_dev, tmp, + inode->i_sb->s_blocksize); + if (i < indirect_block) { + brelse (bh); + goto repeat; + } + if ((bh && bh->b_count != 1) || tmp != *ind) { + retry = 1; + brelse (bh); + continue; + } + *ind = 0; + ind_bh->b_dirt = 1; + if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) { + clear_block (bh->b_data, inode->i_sb->s_blocksize, + CURRENT_TIME); + bh->b_dirt = 1; + } + brelse (bh); + ext2_free_block (inode->i_sb, tmp); + inode->i_blocks -= blocks; + inode->i_dirt = 1; + } + ind = (unsigned long *) ind_bh->b_data; + for (i = 0; i < addr_per_block; i++) + if (*(ind++)) + break; + if (i >= addr_per_block) + if (ind_bh->b_count != 1) + retry = 1; + else { + tmp = *p; + *p = 0; + inode->i_blocks -= blocks; + inode->i_dirt = 1; + ext2_free_block (inode->i_sb, tmp); + } + if (IS_SYNC(inode) && ind_bh->b_dirt) { + ll_rw_block (WRITE, 1, &ind_bh); + wait_on_buffer (ind_bh); + } + brelse (ind_bh); + return retry; + } + + static int trunc_dindirect (struct inode * inode, int offset, + unsigned long * p) + { + int i, tmp; + struct buffer_head * dind_bh; + unsigned long * dind; + int retry = 0; + int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + int blocks = inode->i_sb->s_blocksize / 512; + #define DINDIRECT_BLOCK (((int)DIRECT_BLOCK - offset) / addr_per_block) + int dindirect_block = DINDIRECT_BLOCK; + + tmp = *p; + if (!tmp) + return 0; + dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); + if (tmp != *p) { + brelse (dind_bh); + return 1; + } + if (!dind_bh) { + *p = 0; + return 0; + } + repeat: + for (i = dindirect_block ; i < addr_per_block ; i++) { + if (i < 0) + i = 0; + if (i < dindirect_block) + goto repeat; + dind = i + (unsigned long *) dind_bh->b_data; + tmp = *dind; + if (!tmp) + continue; + retry |= trunc_indirect (inode, offset + (i * addr_per_block), + dind); + dind_bh->b_dirt = 1; + } + dind = (unsigned long *) dind_bh->b_data; + for (i = 0; i < addr_per_block; i++) + if (*(dind++)) + break; + if (i >= addr_per_block) + if (dind_bh->b_count != 1) + retry = 1; + else { + tmp = *p; + *p = 0; + inode->i_blocks -= blocks; + inode->i_dirt = 1; + ext2_free_block (inode->i_sb, tmp); + } + if (IS_SYNC(inode) && dind_bh->b_dirt) { + ll_rw_block (WRITE, 1, &dind_bh); + wait_on_buffer (dind_bh); + } + brelse (dind_bh); + return retry; + } + + static int trunc_tindirect (struct inode * inode) + { + int i, tmp; + struct buffer_head * tind_bh; + unsigned long * tind, * p; + int retry = 0; + int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + int blocks = inode->i_sb->s_blocksize / 512; + #define TINDIRECT_BLOCK (((int)DIRECT_BLOCK - (addr_per_block * addr_per_block + \ + addr_per_block + EXT2_NDIR_BLOCKS)) / \ + (addr_per_block * addr_per_block)) + int tindirect_block = TINDIRECT_BLOCK; + + p = inode->u.ext2_i.i_data + EXT2_TIND_BLOCK; + if (!(tmp = *p)) + return 0; + tind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); + if (tmp != *p) { + brelse (tind_bh); + return 1; + } + if (!tind_bh) { + *p = 0; + return 0; + } + repeat: + for (i = tindirect_block ; i < addr_per_block ; i++) { + if (i < 0) + i = 0; + if (i < tindirect_block) + goto repeat; + tind = i + (unsigned long *) tind_bh->b_data; + retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS + + addr_per_block + (i + 1) * addr_per_block * addr_per_block, + tind); + tind_bh->b_dirt = 1; + } + tind = (unsigned long *) tind_bh->b_data; + for (i = 0; i < addr_per_block; i++) + if (*(tind++)) + break; + if (i >= addr_per_block) + if (tind_bh->b_count != 1) + retry = 1; + else { + tmp = *p; + *p = 0; + inode->i_blocks -= blocks; + inode->i_dirt = 1; + ext2_free_block (inode->i_sb, tmp); + } + if (IS_SYNC(inode) && tind_bh->b_dirt) { + ll_rw_block (WRITE, 1, &tind_bh); + wait_on_buffer (tind_bh); + } + brelse (tind_bh); + return retry; + } + + void ext2_truncate (struct inode * inode) + { + int retry; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + while (1) { + retry = trunc_direct(inode); + retry |= trunc_indirect (inode, EXT2_IND_BLOCK, + (unsigned long *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]); + retry |= trunc_dindirect (inode, EXT2_IND_BLOCK + + EXT2_ADDR_PER_BLOCK(inode->i_sb), + (unsigned long *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]); + retry |= trunc_tindirect (inode); + if (!retry) + break; + if (IS_SYNC(inode) && inode->i_dirt) + ext2_sync_inode (inode); + current->counter = 0; + schedule (); + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + } + + /* + * Called when a inode is released. Note that this is different + * from ext2_open: open gets called at every open, but release + * gets called only when /all/ the files are closed. + */ + void ext2_release (struct inode * inode, struct file * filp) + { + printk ("ext2_release not implemented\n"); + } diff -cr --new-file linux-0.07pl4/fs/proc/Makefile linux-0.08/fs/proc/Makefile *** linux-0.07pl4/fs/proc/Makefile Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/proc/Makefile Sun Feb 27 10:37:52 1994 *************** *** 0 **** --- 1,25 ---- + # + # Makefile for the linux proc-filesystem routines. + # + # Note! Dependencies are done automagically by 'make dep', which also + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # + # Note 2! The CFLAGS definitions are now in the main makefile... + + include ../../MakeVars + + OBJS= inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o + + proc.o: $(OBJS) + $(LD) -r -o proc.o $(OBJS) + + dep: + $(CPP) -M *.c > .depend + + # + # include a dependency file if one exists + # + ifeq (.depend,$(wildcard .depend)) + include .depend + endif diff -cr --new-file linux-0.07pl4/fs/proc/array.c linux-0.08/fs/proc/array.c *** linux-0.07pl4/fs/proc/array.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/proc/array.c Wed Mar 2 16:21:13 1994 *************** *** 0 **** --- 1,607 ---- + /* + * linux/fs/proc/array.c + * + * Copyright (C) 1992 by Linus Torvalds + * based on ideas by Darren Senn + * + * stat,statm extensions by Michael K. Johnson, johnsonm@stolaf.edu + */ + + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + + #define LOAD_INT(x) ((x) >> FSHIFT) + #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) + + #ifdef CONFIG_DEBUG_MALLOC + int get_malloc(char * buffer); + #endif + + static int read_core(struct inode * inode, struct file * file,char * buf, int count) + { + unsigned long p = file->f_pos; + int read; + int count1; + char * pnt; + struct user dump; + + memset(&dump, 0, sizeof(struct user)); + dump.magic = CMAGIC; + dump.u_dsize = (high_memory - KSTART_ADDR) >> 12; + + if (count < 0) + return -EINVAL; + if (p >= (high_memory - KSTART_ADDR) + 2*PAGE_SIZE) + return 0; + if (count > (high_memory - KSTART_ADDR) - p) + count = (high_memory - KSTART_ADDR) - p; + read = 0; + + if (p < sizeof(struct user) && count > 0) { + count1 = count; + if (p + count1 > sizeof(struct user)) + count1 = sizeof(struct user)-p; + pnt = (char *) &dump + p; + memcpy_tofs(buf,(void *) pnt, count1); + buf += count1; + p += count1; + count -= count1; + read += count1; + } + + while (p < 2*PAGE_SIZE && count > 0) { + put_fs_byte(0,buf); + buf++; + p++; + count--; + read++; + } + memcpy_tofs(buf,(void *) (p + KSTART_ADDR - 2*PAGE_SIZE),count); + read += count; + file->f_pos += read; + return read; + } + + static int get_loadavg(char * buffer) + { + int a, b, c; + + a = avenrun[0] + (FIXED_1/200); + b = avenrun[1] + (FIXED_1/200); + c = avenrun[2] + (FIXED_1/200); + return sprintf(buffer,"%d.%02d %d.%02d %d.%02d\n", + LOAD_INT(a), LOAD_FRAC(a), + LOAD_INT(b), LOAD_FRAC(b), + LOAD_INT(c), LOAD_FRAC(c)); + } + + static int get_uptime(char * buffer) + { + unsigned long uptime; + unsigned long idle; + + uptime = jiffies; + idle = task[0]->utime + task[0]->stime; + return sprintf(buffer,"%lu.%02lu %lu.%02lu\n", + uptime / HZ, + uptime % HZ, + idle / HZ, + idle % HZ); + } + + static int get_meminfo(char * buffer) + { + struct sysinfo i; + + si_meminfo(&i); + si_swapinfo(&i); + return sprintf(buffer, " total: used: free: shared: buffers:\n" + "Mem: %8lu %8lu %8lu %8lu %8lu\n" + "Swap: %8lu %8lu %8lu\n", + i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, + i.totalswap, i.totalswap-i.freeswap, i.freeswap); + } + + static int get_version(char * buffer) + { + extern char *linux_banner; + + strcpy(buffer, linux_banner); + return strlen(buffer); + } + + static struct task_struct ** get_task(pid_t pid) + { + struct task_struct ** p; + + p = task; + while (++p < task+NR_TASKS) { + if (*p && (*p)->pid == pid) + return p; + } + return NULL; + } + + static unsigned long get_phys_addr(struct task_struct ** p, unsigned long ptr) + { + unsigned long page; + + if (!p || !*p || ptr >= TASK_SIZE) + return 0; + + #if defined(__i386__) + page = *PAGE_DIR_OFFSET((*p)->tss.cr3,ptr); + if (!(page & 1)) + return 0; + page &= PAGE_MASK; + page += PAGE_PTR(ptr); + page = *(unsigned long *) page; + if (!(page & 1)) + return 0; + page &= PAGE_MASK; + page += ptr & ~PAGE_MASK; + #elif defined(__mc68000__) + page = (*p)->tss.pagedir_v[L1_INDEX(ptr)]; + if (!(page & PAGE_TABLE)) + return 0; + page = PTOV(page & TABLE_MASK); + page += L2_INDEX(ptr) * sizeof(long); + page = *(unsigned long *) page; + if (!(page & PAGE_TABLE)) + return 0; + page = PTOV(page & PAGE_MASK); + page += L3_INDEX(ptr) * sizeof(long); + page = *(unsigned long *) page; + if (!(page & PAGE_PRESENT)) + return 0; + page = PTOV(page & PAGE_MASK); + page += ptr & ~PAGE_MASK; + #endif + return page; + } + + static int get_array(struct task_struct ** p, unsigned long start, unsigned long end, char * buffer) + { + unsigned long addr; + int size = 0, result = 0; + char c; + + if (start >= end) + return result; + for (;;) { + addr = get_phys_addr(p, start); + if (!addr) + return result; + do { + c = *(char *) addr; + if (!c) + result = size; + if (size < PAGE_SIZE) + buffer[size++] = c; + else + return result; + addr++; + start++; + if (start >= end) + return result; + } while (!(addr & ~PAGE_MASK)); + } + } + + static int get_env(int pid, char * buffer) + { + struct task_struct ** p = get_task(pid); + + if (!p || !*p) + return 0; + return get_array(p, (*p)->env_start, (*p)->env_end, buffer); + } + + static int get_arg(int pid, char * buffer) + { + struct task_struct ** p = get_task(pid); + + if (!p || !*p) + return 0; + return get_array(p, (*p)->arg_start, (*p)->arg_end, buffer); + } + + #if defined(__i386__) + static unsigned long get_wchan(struct task_struct *p) + { + unsigned long ebp, eip; + unsigned long stack_page; + int count = 0; + + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + stack_page = p->kernel_stack_page; + if (!stack_page) + return 0; + ebp = p->tss.ebp; + do { + if (ebp < stack_page || ebp >= 4092+stack_page) + return 0; + eip = *(unsigned long *) (ebp+4); + if ((void *)eip != sleep_on && + (void *)eip != interruptible_sleep_on) + return eip; + ebp = *(unsigned long *) ebp; + } while (count++ < 16); + return 0; + } + #elif defined(__mc68000__) + static unsigned long get_wchan(struct task_struct *p) + { + unsigned long sp, fp, pc; + unsigned long stack_page; + int count = 0; + + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + stack_page = p->kernel_stack_page; + if (!stack_page) + return 0; + sp = p->tss.regs[11]; + fp = p->tss.regs[10]; + do { + if (sp < stack_page || sp >= 4092+stack_page + || fp < stack_page || fp >= 4092+stack_page) + return 0; + pc = *(unsigned long *)sp; + if ((void *)pc != sleep_on && + (void *)pc != interruptible_sleep_on) + return pc; + sp = fp; + fp = *(unsigned long *) fp; + } while (count++ < 16); + return 0; + } + #endif + + #if defined(__i386__) + #define KSTK_EIP(stack) (((unsigned long *)stack)[1019]) + #define KSTK_ESP(stack) (((unsigned long *)stack)[1022]) + #elif defined(__mc68000__) + #define KSTK_EIP(stack) (*(unsigned long *)((stack)+4090)) + #define KSTK_ESP(stack) (*(unsigned long *)((stack)+4078)) + #endif /* arch */ + + static int get_stat(int pid, char * buffer) + { + struct task_struct ** p = get_task(pid); + unsigned long sigignore=0, sigcatch=0, bit=1, wchan; + unsigned long vsize, eip, esp; + int i,tty_pgrp; + char state; + + if (!p || !*p) + return 0; + if ((*p)->state < 0 || (*p)->state > 5) + state = '.'; + else + state = "RSDZTD"[(*p)->state]; + eip = esp = 0; + vsize = (*p)->kernel_stack_page; + if (vsize) { + eip = KSTK_EIP(vsize); + esp = KSTK_ESP(vsize); + vsize = (*p)->brk - (*p)->start_code + PAGE_SIZE-1; + if (esp) + vsize += TASK_SIZE - esp; + } + wchan = get_wchan(*p); + for(i=0; i<32; ++i) { + switch((int) (*p)->sigaction[i].sa_handler) { + case 1: sigignore |= bit; break; + case 0: break; + default: sigcatch |= bit; + } bit <<= 1; + } + tty_pgrp = (*p)->tty; + if (tty_pgrp > 0 && tty_table[tty_pgrp]) + tty_pgrp = tty_table[tty_pgrp]->pgrp; + else + tty_pgrp = -1; + return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ + %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %u %u %lu %lu %lu %lu %lu %lu \ + %lu %lu %lu %lu\n", + pid, + (*p)->comm, + state, + (*p)->p_pptr->pid, + (*p)->pgrp, + (*p)->session, + (*p)->tty, + tty_pgrp, + (*p)->flags, + (*p)->min_flt, + (*p)->cmin_flt, + (*p)->maj_flt, + (*p)->cmaj_flt, + (*p)->utime, + (*p)->stime, + (*p)->cutime, + (*p)->cstime, + (*p)->counter, /* this is the kernel priority --- + subtract 30 in your user-level program. */ + (*p)->priority, /* this is the nice value --- + subtract 15 in your user-level program. */ + (*p)->timeout, + (*p)->it_real_value, + (*p)->start_time, + vsize, + (*p)->rss, /* you might want to shift this left 3 */ + (*p)->rlim[RLIMIT_RSS].rlim_cur, + (*p)->start_code, + (*p)->end_code, + (*p)->start_stack, + esp, + eip, + (*p)->signal, + (*p)->blocked, + sigignore, + sigcatch, + wchan); + } + + static int get_statm(int pid, char * buffer) + { + struct task_struct ** p = get_task(pid); + int i, tpag; + int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; + unsigned long ptbl, *buf, *pte, *pagedir, map_nr; + + if (!p || !*p) + return 0; + tpag = (*p)->end_code / PAGE_SIZE; + if ((*p)->state != TASK_ZOMBIE) { + #if defined(__i386__) + pagedir = (unsigned long *) (*p)->tss.cr3; + for (i = 0; i < 0x300; ++i) { + if ((ptbl = pagedir[i]) == 0) { + tpag -= PTRS_PER_PAGE; + continue; + } + buf = (unsigned long *)(ptbl & PAGE_MASK); + for (pte = buf; pte < (buf + PTRS_PER_PAGE); ++pte) { + if (*pte != 0) { + ++size; + if (*pte & 1) { + ++resident; + if (tpag > 0) + ++trs; + else + ++drs; + if (i >= 15 && i < 0x2f0) { + ++lrs; + if (*pte & 0x40) + ++dt; + else + --drs; + } + map_nr = MAP_NR(*pte); + if (map_nr < ((high_memory - KSTART_ADDR) / PAGE_SIZE) && mem_map[map_nr] > 1) + ++share; + } + } + --tpag; + } + } + #elif defined(__mc68000__) + pagedir = (*p)->tss.pagedir_v; + for (i = 0; i < NUM_L1_ENTRIES-1; ++i) { + unsigned long *ptrp, *ptrpe; + if ((ptbl = pagedir[i]) == 0) { + tpag -= NUM_L2_ENTRIES * NUM_L3_ENTRIES; + continue; + } + ptrp = (unsigned long *)PTOV(ptbl & TABLE_MASK); + for (ptrpe = ptrp; ptrpe < (ptrp + NUM_L2_ENTRIES); ptrpe += 16) { + if (*ptrpe == 0) { + tpag -= NUM_L3_ENTRIES; + continue; + } + buf = (unsigned long *)PTOV(*ptrpe & PAGE_MASK); + for (pte = buf; pte < (buf + PTRS_PER_PAGE); ++pte) { + if (*pte != 0) { + ++size; + if (*pte & PAGE_PRESENT) { + ++resident; + if (tpag > 0) + ++trs; + else + ++drs; + if (i >= 2 && i < 94) { /* YUK! */ + ++lrs; + if (*pte & PAGE_DIRTY) + ++dt; + else + --drs; + } + map_nr = MAP_NR(PTOV(*pte & PAGE_MASK)); + if (map_nr < ((high_memory - KSTART_ADDR) / PAGE_SIZE) && mem_map[map_nr] > 1) + ++share; + } + } + --tpag; + } + } + } + #endif /* arch */ + } + return sprintf(buffer,"%d %d %d %d %d %d %d\n", + size, resident, share, trs, lrs, drs, dt); + } + + static int get_maps(int pid, char *buf) + { + int sz = 0; + struct task_struct **p = get_task(pid); + struct vm_area_struct *map; + + if (!p || !*p) + return 0; + + for(map = (*p)->mmap; map != NULL; map = map->vm_next) { + char str[7], *cp = str; + int prot = map->vm_page_prot; + int perms, flags; + int end = sz + 80; /* Length of line */ + dev_t dev; + unsigned long ino; + + /* + * This tries to get an "rwxsp" string out of silly + * intel page permissions. The vm_area_struct should + * probably have the original mmap args preserved. + */ + + flags = perms = 0; + + if ((prot & PAGE_READONLY) == PAGE_READONLY) + perms |= PROT_READ | PROT_EXEC; + if (prot & (PAGE_COW|PAGE_RW)) { + perms |= PROT_WRITE | PROT_READ; + flags = prot & PAGE_COW ? MAP_PRIVATE : MAP_SHARED; + } + + *cp++ = perms & PROT_READ ? 'r' : '-'; + *cp++ = perms & PROT_WRITE ? 'w' : '-'; + *cp++ = perms & PROT_EXEC ? 'x' : '-'; + *cp++ = flags & MAP_SHARED ? 's' : '-'; + *cp++ = flags & MAP_PRIVATE ? 'p' : '-'; + *cp++ = 0; + + if (end >= PAGE_SIZE) { + sprintf(buf+sz, "...\n"); + break; + } + + if (map->vm_inode != NULL) { + dev = map->vm_inode->i_dev; + ino = map->vm_inode->i_ino; + } else { + dev = 0; + ino = 0; + } + + sz += sprintf(buf+sz, "%08lx-%08lx %s %08lx %02x:%02x %lu\n", + map->vm_start, map->vm_end, str, map->vm_offset, + MAJOR(dev),MINOR(dev), ino); + if (sz > end) { + printk("get_maps: end(%d) < sz(%d)\n", end, sz); + break; + } + } + + return sz; + } + + static int array_read(struct inode * inode, struct file * file,char * buf, int count) + { + char * page; + int length; + int end; + unsigned int type, pid; + + if (count < 0) + return -EINVAL; + if (!(page = (char*) __get_free_page(GFP_KERNEL))) + return -ENOMEM; + type = inode->i_ino; + pid = type >> 16; + type &= 0x0000ffff; + switch (type) { + case 2: + length = get_loadavg(page); + break; + case 3: + length = get_uptime(page); + break; + case 4: + length = get_meminfo(page); + break; + case 6: + length = get_version(page); + break; + case 9: + length = get_env(pid, page); + break; + case 10: + length = get_arg(pid, page); + break; + case 11: + length = get_stat(pid, page); + break; + case 12: + length = get_statm(pid, page); + break; + #ifdef CONFIG_DEBUG_MALLOC + case 13: + length = get_malloc(page); + break; + #endif + case 14: + free_page((unsigned long) page); + return read_core(inode, file, buf, count); + case 15: + length = get_maps(pid, page); + break; + default: + free_page((unsigned long) page); + return -EBADF; + } + if (file->f_pos >= length) { + free_page((unsigned long) page); + return 0; + } + if (count + file->f_pos > length) + count = length - file->f_pos; + end = count + file->f_pos; + memcpy_tofs(buf, page + file->f_pos, count); + free_page((unsigned long) page); + file->f_pos = end; + return count; + } + + static struct file_operations proc_array_operations = { + NULL, /* array_lseek */ + array_read, + NULL, /* array_write */ + NULL, /* array_readdir */ + NULL, /* array_select */ + NULL, /* array_ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ + }; + + struct inode_operations proc_array_inode_operations = { + &proc_array_operations, /* default base directory file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ + }; diff -cr --new-file linux-0.07pl4/fs/proc/base.c linux-0.08/fs/proc/base.c *** linux-0.07pl4/fs/proc/base.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/proc/base.c Sun Feb 27 10:50:23 1994 *************** *** 0 **** --- 1,157 ---- + /* + * linux/fs/proc/base.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * proc base directory handling functions + */ + + #include + + #include + #include + #include + #include + #include + + static int proc_readbase(struct inode *, struct file *, struct dirent *, int); + static int proc_lookupbase(struct inode *,const char *,int,struct inode **); + + static struct file_operations proc_base_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_readbase, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ + }; + + /* + * proc directories can do almost nothing.. + */ + struct inode_operations proc_base_inode_operations = { + &proc_base_operations, /* default base directory file-ops */ + NULL, /* create */ + proc_lookupbase, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ + }; + + static struct proc_dir_entry base_dir[] = { + { 1,2,".." }, + { 2,1,"." }, + { 3,3,"mem" }, + { 4,3,"cwd" }, + { 5,4,"root" }, + { 6,3,"exe" }, + { 7,2,"fd" }, + { 8,4,"mmap" }, + { 9,7,"environ" }, + { 10,7,"cmdline" }, + { 11,4,"stat" }, + { 12,5,"statm" }, + { 15,4,"maps" } + }; + + #define NR_BASE_DIRENTRY ((sizeof (base_dir))/(sizeof (base_dir[0]))) + + int proc_match(int len,const char * name,struct proc_dir_entry * de) + { + if (!de || !de->low_ino) + return 0; + /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ + if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) + return 1; + if (de->namelen != len) + return 0; + return !strncmp(name, de->name, len); + } + + static int proc_lookupbase(struct inode * dir,const char * name, int len, + struct inode ** result) + { + unsigned int pid, ino; + int i; + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + ino = dir->i_ino; + pid = ino >> 16; + i = NR_BASE_DIRENTRY; + while (i-- > 0 && !proc_match(len,name,base_dir+i)) + /* nothing */; + if (i < 0) { + iput(dir); + return -ENOENT; + } + if (base_dir[i].low_ino == 1) + ino = 1; + else + ino = (pid << 16) + base_dir[i].low_ino; + for (i = 0 ; i < NR_TASKS ; i++) + if (task[i] && task[i]->pid == pid) + break; + if (!pid || i >= NR_TASKS) { + iput(dir); + return -ENOENT; + } + if (!(*result = iget(dir->i_sb,ino))) { + iput(dir); + return -ENOENT; + } + iput(dir); + return 0; + } + + static int proc_readbase(struct inode * inode, struct file * filp, + struct dirent * dirent, int count) + { + struct proc_dir_entry * de; + unsigned int pid, ino; + int i,j; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + ino = inode->i_ino; + pid = ino >> 16; + for (i = 0 ; i < NR_TASKS ; i++) + if (task[i] && task[i]->pid == pid) + break; + if (!pid || i >= NR_TASKS) + return 0; + if (((unsigned) filp->f_pos) < NR_BASE_DIRENTRY) { + de = base_dir + filp->f_pos; + filp->f_pos++; + i = de->namelen; + ino = de->low_ino; + if (ino != 1) + ino |= (pid << 16); + put_fs_long(ino, &dirent->d_ino); + put_fs_word(i,&dirent->d_reclen); + put_fs_byte(0,i+dirent->d_name); + j = i; + while (i--) + put_fs_byte(de->name[i], i+dirent->d_name); + return j; + } + return 0; + } diff -cr --new-file linux-0.07pl4/fs/proc/fd.c linux-0.08/fs/proc/fd.c *** linux-0.07pl4/fs/proc/fd.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/proc/fd.c Sun Feb 27 09:04:20 1994 *************** *** 0 **** --- 1,198 ---- + /* + * linux/fs/proc/fd.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * proc fd directory handling functions + */ + + #include + + #include + #include + #include + #include + + static int proc_readfd(struct inode *, struct file *, struct dirent *, int); + static int proc_lookupfd(struct inode *,const char *,int,struct inode **); + + static struct file_operations proc_fd_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_readfd, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ + }; + + /* + * proc directories can do almost nothing.. + */ + struct inode_operations proc_fd_inode_operations = { + &proc_fd_operations, /* default base directory file-ops */ + NULL, /* create */ + proc_lookupfd, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ + }; + + static int proc_lookupfd(struct inode * dir,const char * name, int len, + struct inode ** result) + { + unsigned int ino, pid, fd, c; + struct task_struct * p; + struct super_block * sb; + int i; + + *result = NULL; + ino = dir->i_ino; + pid = ino >> 16; + ino &= 0x0000ffff; + ino -= 7; + if (!dir) + return -ENOENT; + sb = dir->i_sb; + if (!pid || ino > 1 || !S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + if (!len || (name[0] == '.' && (len == 1 || + (name[1] == '.' && len == 2)))) { + if (len < 2) { + *result = dir; + return 0; + } + if (!(*result = iget(sb,(pid << 16)+2))) { + iput(dir); + return -ENOENT; + } + iput(dir); + return 0; + } + iput(dir); + fd = 0; + while (len-- > 0) { + c = *name - '0'; + name++; + if (c > 9) { + fd = 0xfffff; + break; + } + fd *= 10; + fd += c; + if (fd & 0xffff0000) { + fd = 0xfffff; + break; + } + } + for (i = 0 ; i < NR_TASKS ; i++) + if ((p = task[i]) && p->pid == pid) + break; + if (!pid || i >= NR_TASKS) + return -ENOENT; + if (!ino) { + if (fd >= NR_OPEN || !p->filp[fd] || !p->filp[fd]->f_inode) + return -ENOENT; + ino = (pid << 16) + 0x100 + fd; + } else { + int j = 0; + struct vm_area_struct * mpnt; + for (mpnt = p->mmap; mpnt; mpnt = mpnt->vm_next) + if (mpnt->vm_inode) + j++; + if (fd >= j) + return -ENOENT; + ino = (pid << 16) + 0x200 + fd; + } + if (!(*result = iget(sb,ino))) + return -ENOENT; + return 0; + } + + static int proc_readfd(struct inode * inode, struct file * filp, + struct dirent * dirent, int count) + { + struct task_struct * p; + unsigned int fd, pid, ino; + int i,j; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + ino = inode->i_ino; + pid = ino >> 16; + ino &= 0x0000ffff; + ino -= 7; + if (ino > 1) + return 0; + while (1) { + fd = filp->f_pos; + filp->f_pos++; + if (fd < 2) { + i = j = fd+1; + if (!fd) + fd = inode->i_ino; + else + fd = (inode->i_ino & 0xffff0000) | 2; + put_fs_long(fd, &dirent->d_ino); + put_fs_word(i, &dirent->d_reclen); + put_fs_byte(0, i+dirent->d_name); + while (i--) + put_fs_byte('.', i+dirent->d_name); + return j; + } + fd -= 2; + for (i = 1 ; i < NR_TASKS ; i++) + if ((p = task[i]) && p->pid == pid) + break; + if (i >= NR_TASKS) + return 0; + if (!ino) { + if (fd >= NR_OPEN) + break; + if (!p->filp[fd] || !p->filp[fd]->f_inode) + continue; + } else { + int j = 0; + struct vm_area_struct * mpnt; + for (mpnt = p->mmap ; mpnt ; mpnt = mpnt->vm_next) + if (mpnt->vm_inode) + j++; + if (fd >= j) + break; + } + j = 10; + i = 1; + while (fd >= j) { + j *= 10; + i++; + } + j = i; + if (!ino) + ino = (pid << 16) + 0x100 + fd; + else + ino = (pid << 16) + 0x200 + fd; + put_fs_long(ino, &dirent->d_ino); + put_fs_word(i, &dirent->d_reclen); + put_fs_byte(0, i+dirent->d_name); + while (i--) { + put_fs_byte('0'+(fd % 10), i+dirent->d_name); + fd /= 10; + } + return j; + } + return 0; + } diff -cr --new-file linux-0.07pl4/fs/proc/inode.c linux-0.08/fs/proc/inode.c *** linux-0.07pl4/fs/proc/inode.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/proc/inode.c Tue Mar 1 09:59:21 1994 *************** *** 0 **** --- 1,199 ---- + /* + * linux/fs/proc/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + + void proc_put_inode(struct inode *inode) + { + if (inode->i_nlink) + return; + inode->i_size = 0; + } + + void proc_put_super(struct super_block *sb) + { + lock_super(sb); + sb->s_dev = 0; + unlock_super(sb); + } + + static struct super_operations proc_sops = { + proc_read_inode, + NULL, + proc_write_inode, + proc_put_inode, + proc_put_super, + NULL, + proc_statfs, + NULL + }; + + struct super_block *proc_read_super(struct super_block *s,void *data, + int silent) + { + lock_super(s); + s->s_blocksize = 1024; + s->s_blocksize_bits = 10; + s->s_magic = PROC_SUPER_MAGIC; + s->s_op = &proc_sops; + unlock_super(s); + if (!(s->s_mounted = iget(s,PROC_ROOT_INO))) { + s->s_dev = 0; + printk("get root inode failed\n"); + return NULL; + } + return s; + } + + void proc_statfs(struct super_block *sb, struct statfs *buf) + { + put_fs_long(PROC_SUPER_MAGIC, &buf->f_type); + put_fs_long(PAGE_SIZE/sizeof(long), &buf->f_bsize); + put_fs_long(0, &buf->f_blocks); + put_fs_long(0, &buf->f_bfree); + put_fs_long(0, &buf->f_bavail); + put_fs_long(0, &buf->f_files); + put_fs_long(0, &buf->f_ffree); + put_fs_long(NAME_MAX, &buf->f_namelen); + /* Don't know what value to put in buf->f_fsid */ + } + + void proc_read_inode(struct inode * inode) + { + unsigned long ino, pid; + struct task_struct * p; + int i; + + inode->i_op = NULL; + inode->i_mode = 0; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_nlink = 1; + inode->i_size = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_blocks = inode->i_blksize = 0; + ino = inode->i_ino; + pid = ino >> 16; + p = task[0]; + for (i = 0; i < NR_TASKS ; i++) + if ((p = task[i]) && (p->pid == pid)) + break; + if (!p || i >= NR_TASKS) + return; + if (ino == PROC_ROOT_INO) { + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; + inode->i_nlink = 2; + for (i = 1 ; i < NR_TASKS ; i++) + if (task[i]) + inode->i_nlink++; + inode->i_op = &proc_root_inode_operations; + return; + } + if ((ino >= 128) && (ino <= 160)) { /* files within /proc/net */ + inode->i_mode = S_IFREG | S_IRUGO; + inode->i_op = &proc_net_inode_operations; + return; + } + if (!pid) { + switch (ino) { + case 5: + inode->i_mode = S_IFREG | S_IRUGO; + inode->i_op = &proc_kmsg_inode_operations; + break; + case 8: /* for the net directory */ + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; + inode->i_nlink = 2; + inode->i_op = &proc_net_inode_operations; + break; + case 14: + inode->i_mode = S_IFREG | S_IRUSR; + inode->i_op = &proc_array_inode_operations; + inode->i_size = high_memory - KSTART_ADDR + PAGE_SIZE; + break; + default: + inode->i_mode = S_IFREG | S_IRUGO; + inode->i_op = &proc_array_inode_operations; + break; + } + return; + } + ino &= 0x0000ffff; + inode->i_uid = p->euid; + inode->i_gid = p->egid; + switch (ino) { + case 2: + inode->i_nlink = 4; + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; + inode->i_op = &proc_base_inode_operations; + return; + case 3: + inode->i_op = &proc_mem_inode_operations; + inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; + return; + case 4: + case 5: + case 6: + inode->i_op = &proc_link_inode_operations; + inode->i_size = 64; + inode->i_mode = S_IFLNK | S_IRWXU; + return; + case 7: + case 8: + inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR; + inode->i_op = &proc_fd_inode_operations; + inode->i_nlink = 2; + return; + case 9: + case 10: + case 11: + case 12: + case 15: + inode->i_mode = S_IFREG | S_IRUGO; + inode->i_op = &proc_array_inode_operations; + return; + } + switch (ino >> 8) { + case 1: + ino &= 0xff; + if (ino >= NR_OPEN || !p->filp[ino]) + return; + inode->i_op = &proc_link_inode_operations; + inode->i_size = 64; + inode->i_mode = S_IFLNK | S_IRWXU; + return; + case 2: + ino &= 0xff; + { + int j = 0; + struct vm_area_struct * mpnt; + for (mpnt = p->mmap ; mpnt ; mpnt = mpnt->vm_next) + if(mpnt->vm_inode) + j++; + if (ino >= j) + return; + } + inode->i_op = &proc_link_inode_operations; + inode->i_size = 64; + inode->i_mode = S_IFLNK | S_IRWXU; + return; + } + return; + } + + void proc_write_inode(struct inode * inode) + { + inode->i_dirt=0; + } diff -cr --new-file linux-0.07pl4/fs/proc/kmsg.c linux-0.08/fs/proc/kmsg.c *** linux-0.07pl4/fs/proc/kmsg.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/proc/kmsg.c Sun Feb 27 09:04:20 1994 *************** *** 0 **** --- 1,77 ---- + /* + * linux/fs/proc/kmsg.c + * + * Copyright (C) 1992 by Linus Torvalds + * + */ + + #include + #include + #include + #include + #include + + #include + #include + + extern unsigned long log_size; + extern struct wait_queue * log_wait; + + asmlinkage int sys_syslog(int type, char * bug, int count); + + static int kmsg_open(struct inode * inode, struct file * file) + { + return sys_syslog(1,NULL,0); + } + + static void kmsg_release(struct inode * inode, struct file * file) + { + (void) sys_syslog(0,NULL,0); + } + + static int kmsg_read(struct inode * inode, struct file * file,char * buf, int count) + { + return sys_syslog(2,buf,count); + } + + static int kmsg_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) + { + if (sel_type != SEL_IN) + return 0; + if (log_size) + return 1; + select_wait(&log_wait, wait); + return 0; + } + + + static struct file_operations proc_kmsg_operations = { + NULL, /* kmsg_lseek */ + kmsg_read, + NULL, /* kmsg_write */ + NULL, /* kmsg_readdir */ + kmsg_select, /* kmsg_select */ + NULL, /* kmsg_ioctl */ + NULL, /* mmap */ + kmsg_open, + kmsg_release, + NULL /* can't fsync */ + }; + + struct inode_operations proc_kmsg_inode_operations = { + &proc_kmsg_operations, /* default base directory file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ + }; diff -cr --new-file linux-0.07pl4/fs/proc/link.c linux-0.08/fs/proc/link.c *** linux-0.07pl4/fs/proc/link.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/proc/link.c Sun Feb 27 09:04:19 1994 *************** *** 0 **** --- 1,125 ---- + /* + * linux/fs/proc/link.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * /proc link-file handling code + */ + + #include + + #include + #include + #include + #include + #include + + static int proc_readlink(struct inode *, char *, int); + static int proc_follow_link(struct inode *, struct inode *, int, int, struct inode **); + + /* + * links can't do much... + */ + struct inode_operations proc_link_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + proc_readlink, /* readlink */ + proc_follow_link, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ + }; + + static int proc_follow_link(struct inode * dir, struct inode * inode, + int flag, int mode, struct inode ** res_inode) + { + unsigned int pid, ino; + struct task_struct * p; + int i; + + *res_inode = NULL; + if (dir) + iput(dir); + if (!inode) + return -ENOENT; + ino = inode->i_ino; + pid = ino >> 16; + ino &= 0x0000ffff; + iput(inode); + for (i = 0 ; i < NR_TASKS ; i++) + if ((p = task[i]) && p->pid == pid) + break; + if (i >= NR_TASKS) + return -ENOENT; + inode = NULL; + switch (ino) { + case 4: + inode = p->pwd; + break; + case 5: + inode = p->root; + break; + case 6: + inode = p->executable; + break; + default: + switch (ino >> 8) { + case 1: + ino &= 0xff; + if (ino < NR_OPEN && p->filp[ino]) + inode = p->filp[ino]->f_inode; + break; + case 2: + ino &= 0xff; + { int j = ino; + struct vm_area_struct * mpnt; + for(mpnt = p->mmap; mpnt && j >= 0; + mpnt = mpnt->vm_next){ + if(mpnt->vm_inode) { + if(j == 0) { + inode = mpnt->vm_inode; + break; + }; + j--; + } + } + }; + } + } + if (!inode) + return -ENOENT; + *res_inode = inode; + inode->i_count++; + return 0; + } + + static int proc_readlink(struct inode * inode, char * buffer, int buflen) + { + int i; + unsigned int dev,ino; + char buf[64]; + + i = proc_follow_link(NULL, inode, 0, 0, &inode); + if (i) + return i; + if (!inode) + return -EIO; + dev = inode->i_dev; + ino = inode->i_ino; + iput(inode); + i = sprintf(buf,"[%04x]:%u", dev, ino); + if (buflen > i) + buflen = i; + i = 0; + while (i < buflen) + put_fs_byte(buf[i++],buffer++); + return i; + } diff -cr --new-file linux-0.07pl4/fs/proc/mem.c linux-0.08/fs/proc/mem.c *** linux-0.07pl4/fs/proc/mem.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/proc/mem.c Tue Mar 22 14:26:56 1994 *************** *** 0 **** --- 1,282 ---- + /* + * linux/fs/proc/mem.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + + #include + #include + #include + #include + + #include + #include + + /* + * mem_write isn't really a good idea right now. It needs + * to check a lot more: if the process we try to write to + * dies in the middle right now, mem_write will overwrite + * kernel memory.. This disables it altogether. + */ + #define mem_write NULL + + #if defined(__i386__) + static int mem_read(struct inode * inode, struct file * file,char * buf, int count) + { + unsigned long addr, pid, cr3; + char *tmp; + unsigned long pte, page; + int i; + + if (count < 0) + return -EINVAL; + pid = inode->i_ino; + pid >>= 16; + cr3 = 0; + for (i = 1 ; i < NR_TASKS ; i++) + if (task[i] && task[i]->pid == pid) { + cr3 = task[i]->tss.cr3; + break; + } + if (!cr3) + return -EACCES; + addr = file->f_pos; + tmp = buf; + while (count > 0) { + if (current->signal & ~current->blocked) + break; + pte = *PAGE_DIR_OFFSET(cr3,addr); + if (!(pte & PAGE_PRESENT)) + break; + pte &= PAGE_MASK; + pte += PAGE_PTR(addr); + page = *(unsigned long *) pte; + if (!(page & 1)) + break; + page &= PAGE_MASK; + page += addr & ~PAGE_MASK; + i = PAGE_SIZE-(addr & ~PAGE_MASK); + if (i > count) + i = count; + memcpy_tofs(tmp,(void *) page,i); + addr += i; + tmp += i; + count -= i; + } + file->f_pos = addr; + return tmp-buf; + } + + #ifndef mem_write + + static int mem_write(struct inode * inode, struct file * file,char * buf, int count) + { + unsigned long addr, pid, cr3; + char *tmp; + unsigned long pte, page; + int i; + + if (count < 0) + return -EINVAL; + addr = file->f_pos; + pid = inode->i_ino; + pid >>= 16; + cr3 = 0; + for (i = 1 ; i < NR_TASKS ; i++) + if (task[i] && task[i]->pid == pid) { + cr3 = task[i]->tss.cr3; + break; + } + if (!cr3) + return -EACCES; + tmp = buf; + while (count > 0) { + if (current->signal & ~current->blocked) + break; + pte = *PAGE_DIR_OFFSET(cr3,addr); + if (!(pte & PAGE_PRESENT)) + break; + pte &= PAGE_MASK; + pte += PAGE_PTR(addr); + page = *(unsigned long *) pte; + if (!(page & PAGE_PRESENT)) + break; + if (!(page & 2)) { + do_wp_page(0,addr,current,0); + continue; + } + page &= PAGE_MASK; + page += addr & ~PAGE_MASK; + i = PAGE_SIZE-(addr & ~PAGE_MASK); + if (i > count) + i = count; + memcpy_fromfs((void *) page,tmp,i); + addr += i; + tmp += i; + count -= i; + } + file->f_pos = addr; + if (tmp != buf) + return tmp-buf; + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + return 0; + } + + #endif + #elif defined(__mc68000__) + static int mem_read(struct inode * inode, struct file * file,char * buf, int count) + { + unsigned long addr, pid, *rootp, *ptrp; + char *tmp; + unsigned long pte, page; + int i; + + if (count < 0) + return -EINVAL; + pid = inode->i_ino; + pid >>= 16; + rootp = NULL; + for (i = 1 ; i < NR_TASKS ; i++) + if (task[i] && task[i]->pid == pid) { + rootp = task[i]->tss.pagedir_v; + break; + } + if (!rootp) + return -EACCES; + addr = file->f_pos; + tmp = buf; + while (count > 0) { + if (current->signal & ~current->blocked) + break; + pte = rootp[L1_INDEX(addr)]; + if (!(pte & PAGE_TABLE)) + break; + ptrp = (unsigned long *)PTOV(pte & TABLE_MASK); + pte = ptrp[L2_INDEX(addr)]; + if (!(pte & PAGE_TABLE)) + break; + pte = PTOV(pte & PAGE_MASK); + pte += PAGE_PTR(addr); + page = *(unsigned long *) pte; + if (!(page & PAGE_PRESENT)) + break; + page = PTOV(page & PAGE_MASK); + page += addr & ~PAGE_MASK; + i = PAGE_SIZE-(addr & ~PAGE_MASK); + if (i > count) + i = count; + memcpy_tofs(tmp,(void *) page,i); + addr += i; + tmp += i; + count -= i; + } + file->f_pos = addr; + return tmp-buf; + } + + #ifndef mem_write + + static int mem_write(struct inode * inode, struct file * file,char * buf, int count) + { + unsigned long addr, pid, *rootp, *ptrp; + char *tmp; + unsigned long pte, page; + int i; + + if (count < 0) + return -EINVAL; + addr = file->f_pos; + pid = inode->i_ino; + pid >>= 16; + rootp = NULL; + for (i = 1 ; i < NR_TASKS ; i++) + if (task[i] && task[i]->pid == pid) { + rootp = task[i]->tss.pagedir_v; + break; + } + if (!rootp) + return -EACCES; + tmp = buf; + while (count > 0) { + if (current->signal & ~current->blocked) + break; + pte = rootp[L1_INDEX(addr)]; + if (!(pte & PAGE_TABLE)) + break; + ptrp = (unsigned long *)PTOV(pte & TABLE_MASK); + pte = ptrp[L2_INDEX(addr)]; + if (!(pte & PAGE_TABLE)) + break; + pte = PTOV(pte & PAGE_MASK); + pte += PAGE_PTR(addr); + page = *(unsigned long *) pte; + if (!(page & (PAGE_COW|PAGE_ACCESSED)) || + !PAGE_IS_RW(page)) { + do_wp_page(0,addr,current,0); + continue; + } + page = PTOV(page & PAGE_MASK); + page += addr & ~PAGE_MASK; + i = PAGE_SIZE-(addr & ~PAGE_MASK); + if (i > count) + i = count; + memcpy_fromfs((void *) page,tmp,i); + addr += i; + tmp += i; + count -= i; + } + file->f_pos = addr; + if (tmp != buf) + return tmp-buf; + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + return 0; + } + #endif /* mem_write */ + #endif /* mc68000 */ + + static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig) + { + switch (orig) { + case 0: + file->f_pos = offset; + return file->f_pos; + case 1: + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; + } + } + + static struct file_operations proc_mem_operations = { + mem_lseek, + mem_read, + mem_write, + NULL, /* mem_readdir */ + NULL, /* mem_select */ + NULL, /* mem_ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ + }; + + struct inode_operations proc_mem_inode_operations = { + &proc_mem_operations, /* default base directory file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ + }; diff -cr --new-file linux-0.07pl4/fs/proc/net.c linux-0.08/fs/proc/net.c *** linux-0.07pl4/fs/proc/net.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/proc/net.c Sun Feb 27 09:04:20 1994 *************** *** 0 **** --- 1,210 ---- + /* + * linux/fs/proc/net.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * gjh 3/'93 heim@peanuts.informatik.uni-tuebingen.de (Gerald J. Heim) + * most of this file is stolen from base.c + * it works, but you shouldn't use it as a guideline + * for new proc-fs entries. once i'll make it better. + * fvk 3/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen) + * cleaned up the whole thing, moved "net" specific code to + * the NET kernel layer (where it belonged in the first place). + * Michael K. Johnson (johnsonm@stolaf.edu) 3/93 + * Added support from my previous inet.c. Cleaned things up + * quite a bit, modularized the code. + * fvk 4/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen) + * Renamed "route_get_info()" to "rt_get_info()" for consistency. + * + * proc net directory handling functions + */ + #include + + #include + + #include + #include + #include + #include + + /* forward references */ + static int proc_readnet(struct inode * inode, struct file * file, + char * buf, int count); + static int proc_readnetdir(struct inode *, struct file *, + struct dirent *, int); + static int proc_lookupnet(struct inode *,const char *,int,struct inode **); + + /* the get_*_info() functions are in the net code, and are configured + in via the standard mechanism... */ + #ifdef CONFIG_INET + extern int unix_get_info(char *); + extern int tcp_get_info(char *); + extern int udp_get_info(char *); + extern int raw_get_info(char *); + extern int arp_get_info(char *); + extern int dev_get_info(char *); + extern int rt_get_info(char *); + #endif /* CONFIG_INET */ + + + static struct file_operations proc_net_operations = { + NULL, /* lseek - default */ + proc_readnet, /* read - bad */ + NULL, /* write - bad */ + proc_readnetdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ + }; + + /* + * proc directories can do almost nothing.. + */ + struct inode_operations proc_net_inode_operations = { + &proc_net_operations, /* default net directory file-ops */ + NULL, /* create */ + proc_lookupnet, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ + }; + + static struct proc_dir_entry net_dir[] = { + { 1,2,".." }, + { 8,1,"." } + #ifdef CONFIG_INET + ,{ 128,4,"unix" }, + { 129,3,"arp" }, + { 130,5,"route" }, + { 131,3,"dev" }, + { 132,3,"raw" }, + { 133,3,"tcp" }, + { 134,3,"udp" } + #endif /* CONFIG_INET */ + }; + + #define NR_NET_DIRENTRY ((sizeof (net_dir))/(sizeof (net_dir[0]))) + + + static int proc_lookupnet(struct inode * dir,const char * name, int len, + struct inode ** result) + { + unsigned int ino; + int i; + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + i = NR_NET_DIRENTRY; + while (i-- > 0 && !proc_match(len,name,net_dir+i)) + /* nothing */; + if (i < 0) { + iput(dir); + return -ENOENT; + } + ino = net_dir[i].low_ino; + if (!(*result = iget(dir->i_sb,ino))) { + iput(dir); + return -ENOENT; + } + iput(dir); + return 0; + } + + static int proc_readnetdir(struct inode * inode, struct file * filp, + struct dirent * dirent, int count) + { + struct proc_dir_entry * de; + unsigned int ino; + int i,j; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + ino = inode->i_ino; + if (((unsigned) filp->f_pos) < NR_NET_DIRENTRY) { + de = net_dir + filp->f_pos; + filp->f_pos++; + i = de->namelen; + ino = de->low_ino; + put_fs_long(ino, &dirent->d_ino); + put_fs_word(i,&dirent->d_reclen); + put_fs_byte(0,i+dirent->d_name); + j = i; + while (i--) + put_fs_byte(de->name[i], i+dirent->d_name); + return j; + } + return 0; + } + + + static int proc_readnet(struct inode * inode, struct file * file, + char * buf, int count) + { + char * page; + int length; + int end; + unsigned int ino; + + if (count < 0) + return -EINVAL; + if (!(page = (char*) __get_free_page(GFP_KERNEL))) + return -ENOMEM; + ino = inode->i_ino; + switch (ino) { + #ifdef CONFIG_INET + case 128: + length = unix_get_info(page); + break; + case 129: + length = arp_get_info(page); + break; + case 130: + length = rt_get_info(page); + break; + case 131: + length = dev_get_info(page); + break; + case 132: + length = raw_get_info(page); + break; + case 133: + length = tcp_get_info(page); + break; + case 134: + length = udp_get_info(page); + break; + #endif /* CONFIG_INET */ + default: + free_page((unsigned long) page); + return -EBADF; + } + if (file->f_pos >= length) { + free_page((unsigned long) page); + return 0; + } + if (count + file->f_pos > length) + count = length - file->f_pos; + end = count + file->f_pos; + memcpy_tofs(buf, page + file->f_pos, count); + free_page((unsigned long) page); + file->f_pos = end; + return count; + + } diff -cr --new-file linux-0.07pl4/fs/proc/root.c linux-0.08/fs/proc/root.c *** linux-0.07pl4/fs/proc/root.c Wed Dec 31 19:00:00 1969 --- linux-0.08/fs/proc/root.c Sun Feb 27 09:04:19 1994 *************** *** 0 **** --- 1,177 ---- + /* + * linux/fs/proc/root.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * proc root directory handling functions + */ + + #include + + #include + #include + #include + #include + #include + + static int proc_readroot(struct inode *, struct file *, struct dirent *, int); + static int proc_lookuproot(struct inode *,const char *,int,struct inode **); + + static struct file_operations proc_root_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_readroot, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* no fsync */ + }; + + /* + * proc directories can do almost nothing.. + */ + struct inode_operations proc_root_inode_operations = { + &proc_root_operations, /* default base directory file-ops */ + NULL, /* create */ + proc_lookuproot, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ + }; + + static struct proc_dir_entry root_dir[] = { + { 1,1,"." }, + { 1,2,".." }, + { 2,7,"loadavg" }, + { 3,6,"uptime" }, + { 4,7,"meminfo" }, + { 5,4,"kmsg" }, + { 6,7,"version" }, + { 7,4,"self" }, /* will change inode # */ + { 8,3,"net" }, + #ifdef CONFIG_DEBUG_MALLOC + {13,6,"malloc" }, + #endif + {14,5,"kcore" }, + }; + + #define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0]))) + + static int proc_lookuproot(struct inode * dir,const char * name, int len, + struct inode ** result) + { + unsigned int pid, c; + int i, ino; + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + i = NR_ROOT_DIRENTRY; + while (i-- > 0 && !proc_match(len,name,root_dir+i)) + /* nothing */; + if (i >= 0) { + ino = root_dir[i].low_ino; + if (ino == 1) { + *result = dir; + return 0; + } + if (ino == 7) /* self modifying inode ... */ + ino = (current->pid << 16) + 2; + } else { + pid = 0; + while (len-- > 0) { + c = *name - '0'; + name++; + if (c > 9) { + pid = 0; + break; + } + pid *= 10; + pid += c; + if (pid & 0xffff0000) { + pid = 0; + break; + } + } + for (i = 0 ; i < NR_TASKS ; i++) + if (task[i] && task[i]->pid == pid) + break; + if (!pid || i >= NR_TASKS) { + iput(dir); + return -ENOENT; + } + ino = (pid << 16) + 2; + } + if (!(*result = iget(dir->i_sb,ino))) { + iput(dir); + return -ENOENT; + } + iput(dir); + return 0; + } + + static int proc_readroot(struct inode * inode, struct file * filp, + struct dirent * dirent, int count) + { + struct task_struct * p; + unsigned int nr,pid; + int i,j; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + repeat: + nr = filp->f_pos; + if (nr < NR_ROOT_DIRENTRY) { + struct proc_dir_entry * de = root_dir + nr; + + filp->f_pos++; + i = de->namelen; + put_fs_long(de->low_ino, &dirent->d_ino); + put_fs_word(i,&dirent->d_reclen); + put_fs_byte(0,i+dirent->d_name); + j = i; + while (i--) + put_fs_byte(de->name[i], i+dirent->d_name); + return j; + } + nr -= NR_ROOT_DIRENTRY; + if (nr >= NR_TASKS) + return 0; + filp->f_pos++; + p = task[nr]; + if (!p || !(pid = p->pid)) + goto repeat; + if (pid & 0xffff0000) + goto repeat; + j = 10; + i = 1; + while (pid >= j) { + j *= 10; + i++; + } + j = i; + put_fs_long((pid << 16)+2, &dirent->d_ino); + put_fs_word(i, &dirent->d_reclen); + put_fs_byte(0, i+dirent->d_name); + while (i--) { + put_fs_byte('0'+(pid % 10), i+dirent->d_name); + pid /= 10; + } + return j; + } diff -cr --new-file linux-0.07pl4/include/asm/bitops.h linux-0.08/include/asm/bitops.h *** linux-0.07pl4/include/asm/bitops.h Tue Oct 12 15:50:35 1993 --- linux-0.08/include/asm/bitops.h Tue Feb 1 15:00:08 1994 *************** *** 57,62 **** --- 57,102 ---- return oldbit; } + #elif defined(__mc68000__) + /* + * mc680x0 equivalents. Require 68020 or better. + */ + + extern __inline__ int set_bit(int nr,void * vaddr) + { + int retval; + + __asm__ __volatile__ ("bfset %2@{%1:#1}; sne %0 ; extbl %0" + : "=d" (retval) + : "d" ((nr & ~31) + 31 - (nr & 31)), + "a" (vaddr)); + + return retval; + } + + extern __inline__ int clear_bit(int nr, void * vaddr) + { + int retval; + + __asm__ __volatile__ ("bfclr %2@{%1:#1}; sne %0 ; extbl %0" + : "=d" (retval) + : "d" ((nr & ~31) + 31 - (nr & 31)), + "a" (vaddr)); + + return retval; + } + + extern __inline__ int test_bit(int nr, void * vaddr) + { + int retval; + + __asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0 ; extbl %0" + : "=d" (retval) + : "d" ((nr & ~31) + 31 - (nr & 31)), + "a" (vaddr)); + + return retval; + } #else /* * For the benefit of those who are trying to port Linux to another diff -cr --new-file linux-0.07pl4/include/asm/io.h linux-0.08/include/asm/io.h *** linux-0.07pl4/include/asm/io.h Mon Jan 3 17:22:51 1994 --- linux-0.08/include/asm/io.h Sun Mar 27 07:31:02 1994 *************** *** 24,29 **** --- 24,30 ---- #define SLOW_DOWN_IO __SLOW_DOWN_IO #endif + #ifdef __i386__ /* This is the more general version of outb.. */ extern inline void __outb(unsigned char value, unsigned short port) { *************** *** 31,36 **** --- 32,38 ---- : /* no outputs */ :"a" (value),"d" (port)); } + #endif /* architecture */ /* this is used for constant port numbers < 256.. */ extern inline void __outbc(unsigned char value, unsigned short port) *************** *** 40,45 **** --- 42,48 ---- :"a" (value),"i" (port)); } + #ifdef __i386__ /* general version of inb */ extern inline unsigned int __inb(unsigned short port) { *************** *** 48,53 **** --- 51,57 ---- :"=a" (_v):"d" (port),"0" (0)); return _v; } + #endif /* architecture */ /* inb with constant port nr 0-255 */ extern inline unsigned int __inbc(unsigned short port) *************** *** 58,63 **** --- 62,68 ---- return _v; } + #if defined(__i386__) extern inline void __outb_p(unsigned char value, unsigned short port) { __asm__ __volatile__ ("outb %b0,%w1" *************** *** 65,70 **** --- 70,86 ---- :"a" (value),"d" (port)); SLOW_DOWN_IO; } + #elif defined(__mc68000__) + static inline void put_user_byte_io(char val,char *addr) + { + __asm__ __volatile__ ("move.b %0,%1" + : /* no outputs */ + :"r" (val),"m" (*addr) + : "memory"); + } + #define outb_p(x,addr) put_user_byte_io((x),(char *)(addr)) + #define outb(x,addr) put_user_byte_io((x),(char *)(addr)) + #endif /* architecture */ extern inline void __outbc_p(unsigned char value, unsigned short port) { *************** *** 74,79 **** --- 90,96 ---- SLOW_DOWN_IO; } + #if defined(__i386__) extern inline unsigned int __inb_p(unsigned short port) { unsigned int _v; *************** *** 82,87 **** --- 99,115 ---- SLOW_DOWN_IO; return _v; } + #elif defined(__mc68000__) + static inline unsigned char get_user_byte_io(const char * addr) + { + register unsigned char _v; + + __asm__ __volatile__ ("move.b %1,%0":"=r" (_v):"m" (*addr)); + return _v; + } + #define inb_p(addr) get_user_byte_io((char *)(addr)) + #define inb(addr) get_user_byte_io((char *)(addr)) + #endif /* architecture */ extern inline unsigned int __inbc_p(unsigned short port) { *************** *** 92,97 **** --- 120,126 ---- return _v; } + #ifdef __i386__ /* * Note that due to the way __builtin_constant_p() works, you * - can't use it inside a inline function (it will never be true) *************** *** 116,120 **** --- 145,150 ---- ((__builtin_constant_p((port)) && (port) < 256) ? \ __inbc_p(port) : \ __inb_p(port)) + #endif /* i386 */ #endif diff -cr --new-file linux-0.07pl4/include/asm/segment.h linux-0.08/include/asm/segment.h *** linux-0.07pl4/include/asm/segment.h Sun Feb 13 21:51:52 1994 --- linux-0.08/include/asm/segment.h Tue Mar 1 09:54:55 1994 *************** *** 68,73 **** --- 68,74 ---- static inline void memcpy_tofs(void * to, const void * from, unsigned long n) { + if (n == 0) return; __asm__ __volatile__ ("movel %1,a0\n\t" "movel %2,a1\n\t" "1:\n\t" *************** *** 82,87 **** --- 83,89 ---- static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) { + if (n == 0) return; __asm__ __volatile__ ("movel %1,a0\n\t" "movel %2,a1\n\t" "1:\n\t" diff -cr --new-file linux-0.07pl4/include/linux/amigaconf.h linux-0.08/include/linux/amigaconf.h *** linux-0.07pl4/include/linux/amigaconf.h Sun Jan 30 11:37:03 1994 --- linux-0.08/include/linux/amigaconf.h Sun Feb 6 15:42:00 1994 *************** *** 32,54 **** mach_gettimeoffset = amiga_gettimeoffset; if (boot_info.bi_amiga.model == AMI_3000 || boot_info.bi_amiga.model == AMI_4000) ! mach_gettod = a3000_gettod; else ! mach_gettod = a2000_gettod; mach_check_partition = amiga_check_partition; ! conswitchp = &ami_con; #if 0 /* set up hardware bases */ ! CustomBase = (caddr_t)CUSTOM_PHYSADDR; ! CiaABase = (caddr_t)CIAA_PHYSADDR; ! CiaBBase = (caddr_t)CIAB_PHYSADDR; #endif /* clear all DMA bits */ custom.dmacon = DMAF_ALL; /* ensure that the DMA master bit is set */ custom.dmacon = DMAF_SETCLR | DMAF_MASTER; /* * if it is an A3000, set the magic bit that forces --- 32,58 ---- mach_gettimeoffset = amiga_gettimeoffset; if (boot_info.bi_amiga.model == AMI_3000 || boot_info.bi_amiga.model == AMI_4000) ! mach_gettod = a3000_gettod; else ! mach_gettod = a2000_gettod; mach_check_partition = amiga_check_partition; ! conswitchp = &ami_con; #if 0 /* set up hardware bases */ ! CustomBase = (caddr_t)CUSTOM_PHYSADDR; ! CiaABase = (caddr_t)CIAA_PHYSADDR; ! CiaBBase = (caddr_t)CIAB_PHYSADDR; ! ChipRamBase = (caddr_t)CHIP_PHYSADDR; #endif /* clear all DMA bits */ custom.dmacon = DMAF_ALL; /* ensure that the DMA master bit is set */ custom.dmacon = DMAF_SETCLR | DMAF_MASTER; + + /* initialize chipram allocator */ + amiga_chip_init (); /* * if it is an A3000, set the magic bit that forces diff -cr --new-file linux-0.07pl4/include/linux/amigahw.h linux-0.08/include/linux/amigahw.h *** linux-0.07pl4/include/linux/amigahw.h Mon Feb 21 09:20:47 1994 --- linux-0.08/include/linux/amigahw.h Sat Feb 26 08:32:01 1994 *************** *** 192,197 **** --- 192,208 ---- # define ciab ((*(volatile struct CIA *)CIAB_PHYSADDR)) #endif + #define CHIP_PHYSADDR (0x000000) + #if 0 + extern caddr_t ChipRamBase; + # define chipaddr ((unsigned long)ChipRamBase) + #else + # define chipaddr ((unsigned long)CHIP_PHYSADDR) + #endif + void amiga_chip_init (void); + void *amiga_chip_alloc (long size); + void amiga_chip_free (void *); + struct tod3000 { unsigned int :28, second2:4; /* lower digit */ unsigned int :28, second1:4; /* upper digit */ diff -cr --new-file linux-0.07pl4/include/linux/amigamouse.h linux-0.08/include/linux/amigamouse.h *** linux-0.07pl4/include/linux/amigamouse.h Wed Dec 31 19:00:00 1969 --- linux-0.08/include/linux/amigamouse.h Sun Mar 27 09:46:03 1994 *************** *** 0 **** --- 1,25 ---- + #ifndef _LINUX_AMIGAMOUSE_H + #define _LINUX_AMIGAMOUSE_H + + /* + * linux/include/linux/amigamouse.h: header file for Amiga Mouse driver + * by Michael Rausch + */ + + /* + #define MSE_INT_OFF() outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT) + #define MSE_INT_ON() outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT) + */ + + struct mouse_status { + unsigned char buttons; + unsigned char latch_buttons; + int dx; + int dy; + int present; + int ready; + int active; + struct wait_queue *wait; + }; + + #endif diff -cr --new-file linux-0.07pl4/include/linux/amihdreg.h linux-0.08/include/linux/amihdreg.h *** linux-0.07pl4/include/linux/amihdreg.h Wed Dec 31 19:00:00 1969 --- linux-0.08/include/linux/amihdreg.h Sun Mar 27 07:22:05 1994 *************** *** 0 **** --- 1,69 ---- + #ifndef _LINUX_AMIHDREG_H + #define _LINUX_AMIHDREG_H + + /* + * This file contains some defines for the Amiga IDE hd controller. + * Various sources. Check out some definitions (see comments with + * a ques). + */ + + #define IDE_DISABLE_IRQ 0x02 + #define IDE_ENABLE_IRQ 0x00 + + /* Hd controller regs. Ref: Disassembling scsi.device */ + #define HD_DATA 0xdd2020 /* _CTL when writing */ + #define HD_ERROR 0xdd2026 /* see err-bits */ + #define HD_NSECTOR 0xdd202a /* nr of sectors to read/write */ + #define HD_SECTOR 0xdd202e /* starting sector */ + #define HD_LCYL 0xdd2032 /* starting cylinder */ + #define HD_HCYL 0xdd2036 /* high byte of starting cyl */ + #define HD_CURRENT 0xdd203a /* 101dhhhh , d=drive, hhhh=head */ + #define HD_STATUS 0xdd203e /* 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_IRQ_TEST 0xdd3020 /* MSB = 1, Harddisk is source of interrupt */ + #define HD_CMD 0xdd303a + + /* 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 + #define WIN_IDENTIFY 0xec + + /* Bits for HD_ERROR */ + #define MARK_ERR 0x01 /* Bad address mark */ + #define TRK0_ERR 0x02 /* couldn't find track 0 */ + #define ABRT_ERR 0x04 /* Command aborted */ + #define ID_ERR 0x10 /* ID field not found */ + #define ECC_ERR 0x40 /* Uncorrectable ECC error */ + #define BBD_ERR 0x80 /* block marked bad */ + + + /* HDIO_GETGEO is the preferred choice - HDIO_REQ will be removed at some + later date */ + #define HDIO_REQ 0x301 + #define HDIO_GETGEO 0x301 + struct hd_geometry { + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + unsigned long start; + }; + #endif diff -cr --new-file linux-0.07pl4/include/linux/config.h linux-0.08/include/linux/config.h *** linux-0.07pl4/include/linux/config.h Fri Dec 17 13:14:13 1993 --- linux-0.08/include/linux/config.h Thu Mar 10 16:07:02 1994 *************** *** 15,21 **** * Defines for what uname() should return */ #ifndef UTS_SYSNAME ! #define UTS_SYSNAME "Linux" #endif #ifndef UTS_NODENAME --- 15,21 ---- * Defines for what uname() should return */ #ifndef UTS_SYSNAME ! #define UTS_SYSNAME "Linux/68k" #endif #ifndef UTS_NODENAME *************** *** 23,29 **** #endif #ifndef UTS_MACHINE ! #define UTS_MACHINE "amiga" /* hardware type */ #endif #ifndef UTS_DOMAINNAME --- 23,29 ---- #endif #ifndef UTS_MACHINE ! #define UTS_MACHINE "m68k" /* hardware type */ #endif #ifndef UTS_DOMAINNAME *************** *** 38,44 **** --- 38,47 ---- /* interrupt service routine function ptr type */ struct intframe; + #ifndef ISRFUNC_T typedef void (*isrfunc) (struct intframe *fp, void *data); + #define ISRFUNC_T + #endif /* ISRFUNC_T */ extern void (*mach_sched_init) (isrfunc); extern unsigned long (*mach_keyb_init) (unsigned long); diff -cr --new-file linux-0.07pl4/include/linux/console.h linux-0.08/include/linux/console.h *** linux-0.07pl4/include/linux/console.h Sun Jul 25 07:55:01 1993 --- linux-0.08/include/linux/console.h Tue Mar 15 14:09:49 1994 *************** *** 6,25 **** * This file is subject to the terms and conditions of the GNU General Public * License. See the file README.legal in the main directory of this archive * for more details. */ #ifndef _LINUX_CONSOLE_H_ #define _LINUX_CONSOLE_H_ 1 struct condata { ! int flags; ! struct consw *sw; ! short curx, cury; ! short cursorx, cursory; ! short rows, cols; ! short attribute; }; struct consw { int (*con_init)(struct condata *); int (*con_deinit)(struct condata *); --- 6,77 ---- * This file is subject to the terms and conditions of the GNU General Public * License. See the file README.legal in the main directory of this archive * for more details. + * + * Changed: + * 10-Mar-94: Arno Griffioen: Conversion for vt100 emulator port from PC LINUX */ #ifndef _LINUX_CONSOLE_H_ #define _LINUX_CONSOLE_H_ 1 + #define NPAR 16 + + static int can_do_color = 0; + static int printable = 0; + struct condata { ! unsigned short vc_flags; /* Console inited? */ ! unsigned short vc_video_erase_char; /* Background erase character */ ! unsigned char vc_attr; /* Current attributes */ ! unsigned char vc_def_color; /* Default colors */ ! unsigned char vc_color; /* Foreground & background */ ! unsigned char vc_s_color; /* Saved foreground & background */ ! unsigned char vc_ulcolor; /* Colour for underline mode */ ! unsigned char vc_halfcolor; /* Colour for half intensity mode */ ! unsigned long vc_x,vc_y; ! unsigned long vc_top,vc_bottom; ! unsigned long vc_rows,vc_cols; ! unsigned long vc_state; ! unsigned long vc_npar,vc_par[NPAR]; ! unsigned long vc_saved_x; ! unsigned long vc_saved_y; ! /* mode flags */ ! unsigned long vc_charset : 1; /* Character set G0 / G1 */ ! unsigned long vc_s_charset : 1; /* Saved character set */ ! unsigned long vc_decscnm : 1; /* Screen Mode */ ! unsigned long vc_decom : 1; /* Origin Mode */ ! unsigned long vc_decawm : 1; /* Autowrap Mode */ ! unsigned long vc_deccm : 1; /* Cursor Visible */ ! unsigned long vc_decim : 1; /* Insert Mode */ ! /* attribute flags */ ! unsigned long vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */ ! unsigned long vc_underline : 1; ! unsigned long vc_blink : 1; ! unsigned long vc_reverse : 1; ! unsigned long vc_s_intensity : 2; /* saved rendition */ ! unsigned long vc_s_underline : 1; ! unsigned long vc_s_blink : 1; ! unsigned long vc_s_reverse : 1; ! /* misc */ ! unsigned long vc_ques : 1; ! unsigned long vc_need_wrap : 1; ! unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */ ! unsigned char vc_kbdmode; ! unsigned char * vc_translate; ! unsigned char * vc_G0_charset; ! unsigned char * vc_G1_charset; ! unsigned char * vc_saved_G0; ! unsigned char * vc_saved_G1; ! struct consw *vc_sw; ! /* additional information is in vt_kern.h */ }; + /* + * this is what the terminal answers to a ESC-Z or csi0c query. + */ + #define VT100ID "\033[?1;2c" + #define VT102ID "\033[?6c" + struct consw { int (*con_init)(struct condata *); int (*con_deinit)(struct condata *); *************** *** 27,37 **** int (*con_putc)(struct condata *, int, int, int, int); int (*con_cursor)(struct condata *, int); int (*con_scroll)(struct condata *, int, int, int, int); int (*con_switch)(struct condata *); }; extern struct consw *conswitchp; - extern struct condata vc_cons[NR_CONSOLES]; /* flag bits */ --- 79,89 ---- int (*con_putc)(struct condata *, int, int, int, int); int (*con_cursor)(struct condata *, int); int (*con_scroll)(struct condata *, int, int, int, int); + int (*con_bmove)(struct condata *, int, int, int, int, int, int); int (*con_switch)(struct condata *); }; extern struct consw *conswitchp; extern struct condata vc_cons[NR_CONSOLES]; /* flag bits */ diff -cr --new-file linux-0.07pl4/include/linux/ddi.h linux-0.08/include/linux/ddi.h *** linux-0.07pl4/include/linux/ddi.h Wed Dec 31 19:00:00 1969 --- linux-0.08/include/linux/ddi.h Sat Mar 5 12:48:51 1994 *************** *** 0 **** --- 1,79 ---- + /* + * ddi.h Define the structure for linking in I/O drivers into the + * operating system kernel. This method is currently only + * used by NET layer drivers, but it will be expanded into + * a link methos for ALL kernel-resident device drivers. + * + * Version: @(#)ddi.h 1.0.2 04/22/93 + * + * Author: Fred N. van Kempen, + */ + #ifndef _LINUX_DDI_H + #define _LINUX_DDI_H + + + /* DDI control block flags. */ + #define DDI_FREADY 0x10000000 /* device is initialized */ + #define DDI_FPRESENT 0x20000000 /* device hardware is present */ + #define DDI_FBLKDEV 0x00000001 /* device has a BLK spec. file */ + #define DDI_FCHRDEV 0x00000002 /* device has a CHR spec. file */ + + /* Various constants. */ + #define DDI_MAXNAME 16 /* length of a DDI ID string */ + + + /* This structure is used to set up a DDI driver. */ + struct ddconf { + int ioaddr; /* main I/O (port) address */ + int ioaux; /* auxiliary I/O (HD, AST) */ + int irq; /* IRQ channel */ + int dma; /* DMA channel to use */ + unsigned long memsize; /* size of onboard memory */ + unsigned long memaddr; /* base address of memory */ + }; + + + /* The DDI device control block. */ + struct ddi_device { + char *title; /* title of the driver */ + char name[DDI_MAXNAME]; /* unit name of the I/O driver */ + short int unit; /* unit number of this driver */ + short int nunits; /* number of units in driver */ + int (*init)(struct ddi_device *); /* initialization func */ + int (*handler)(int, ...); /* command handler */ + short int major; /* driver major dev number */ + short int minor; /* driver minor dev number */ + unsigned long flags; /* various flags */ + struct ddconf config; /* driver HW setup */ + }; + + + /* This structure is used to set up networking protocols. */ + struct ddi_proto { + char *name; /* protocol name */ + void (*init)(struct ddi_proto *); /* initialization func */ + }; + + + /* This structure is used to link a STREAMS interface. */ + struct iflink { + char id[DDI_MAXNAME]; /* DDI ID string */ + char stream[DDI_MAXNAME]; /* STREAMS interface name */ + int family; /* address (protocol) family */ + unsigned int flags; /* any flags needed (unused) */ + }; + + + /* DDI control requests. */ + #define DDIOCSDBG 0x9000 /* set DDI debug level */ + #define DDIOCGNAME 0x9001 /* get DDI ID name */ + #define DDIOCGCONF 0x9002 /* get DDI HW config */ + #define DDIOCSCONF 0x9003 /* set DDI HW config */ + + + /* DDI global functions. */ + extern void ddi_init(void); + extern struct ddi_device *ddi_map(const char *id); + + + #endif /* _LINUX_DDI_H */ diff -cr --new-file linux-0.07pl4/include/linux/ext2_fs.h linux-0.08/include/linux/ext2_fs.h *** linux-0.07pl4/include/linux/ext2_fs.h Fri Dec 10 18:34:21 1993 --- linux-0.08/include/linux/ext2_fs.h Wed Feb 2 15:10:01 1994 *************** *** 61,79 **** * Debug code */ #ifdef EXT2FS_DEBUG ! # define ext2_debug(f, a...) { \ printk ("EXT2-fs DEBUG (%s, %d): %s:", \ __FILE__, __LINE__, __FUNCTION__); \ ! printk (f, ## a); \ } #else ! # define ext2_debug(f, a...) /**/ #endif /* * Special inodes numbers */ ! #define EXT2_BAD_INO 1 /* Bad blocks inode */ #define EXT2_ROOT_INO 2 /* Root inode */ #define EXT2_ACL_IDX_INO 3 /* ACL inode */ #define EXT2_ACL_DATA_INO 4 /* ACL inode */ --- 61,79 ---- * Debug code */ #ifdef EXT2FS_DEBUG ! # define ext2_debug(f, a...) { \ printk ("EXT2-fs DEBUG (%s, %d): %s:", \ __FILE__, __LINE__, __FUNCTION__); \ ! printk (f, ## a); \ } #else ! # define ext2_debug(f, a...) /**/ #endif /* * Special inodes numbers */ ! #define EXT2_BAD_INO 1 /* Bad blocks inode */ #define EXT2_ROOT_INO 2 /* Root inode */ #define EXT2_ACL_IDX_INO 3 /* ACL inode */ #define EXT2_ACL_DATA_INO 4 /* ACL inode */ *************** *** 96,129 **** * Macro-instructions used to manage several block sizes */ #define EXT2_MIN_BLOCK_SIZE 1024 ! #define EXT2_MAX_BLOCK_SIZE 4096 ! #define EXT2_MIN_BLOCK_LOG_SIZE 10 #ifdef __KERNEL__ ! # define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize) #else ! # define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) #endif ! #define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry)) ! #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (unsigned long)) #ifdef __KERNEL__ ! # define EXT2_BLOCK_SIZE_BITS(s) ((s)->u.ext2_sb.s_es->s_log_block_size + 10) #else ! # define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) #endif ! #define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_inode)) /* * Macro-instructions used to manage fragments */ #define EXT2_MIN_FRAG_SIZE 1024 ! #define EXT2_MAX_FRAG_SIZE 4096 #define EXT2_MIN_FRAG_LOG_SIZE 10 #ifdef __KERNEL__ ! # define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size) ! # define EXT2_FRAGS_PER_BLOCK(s) ((s)->u.ext2_sb.s_frags_per_block) #else ! # define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size) ! # define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s)) #endif /* --- 96,129 ---- * Macro-instructions used to manage several block sizes */ #define EXT2_MIN_BLOCK_SIZE 1024 ! #define EXT2_MAX_BLOCK_SIZE 4096 ! #define EXT2_MIN_BLOCK_LOG_SIZE 10 #ifdef __KERNEL__ ! # define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize) #else ! # define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) #endif ! #define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry)) ! #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (unsigned long)) #ifdef __KERNEL__ ! # define EXT2_BLOCK_SIZE_BITS(s) ((s)->u.ext2_sb.s_es->s_log_block_size + 10) #else ! # define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) #endif ! #define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_inode)) /* * Macro-instructions used to manage fragments */ #define EXT2_MIN_FRAG_SIZE 1024 ! #define EXT2_MAX_FRAG_SIZE 4096 #define EXT2_MIN_FRAG_LOG_SIZE 10 #ifdef __KERNEL__ ! # define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size) ! # define EXT2_FRAGS_PER_BLOCK(s) ((s)->u.ext2_sb.s_frags_per_block) #else ! # define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size) ! # define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s)) #endif /* *************** *** 153,160 **** */ struct ext2_old_group_desc { ! unsigned long bg_block_bitmap; /* Blocks bitmap block */ ! unsigned long bg_inode_bitmap; /* Inodes bitmap block */ unsigned long bg_inode_table; /* Inodes table block */ unsigned short bg_free_blocks_count; /* Free blocks count */ unsigned short bg_free_inodes_count; /* Free inodes count */ --- 153,160 ---- */ struct ext2_old_group_desc { ! unsigned long bg_block_bitmap; /* Blocks bitmap block */ ! unsigned long bg_inode_bitmap; /* Inodes bitmap block */ unsigned long bg_inode_table; /* Inodes table block */ unsigned short bg_free_blocks_count; /* Free blocks count */ unsigned short bg_free_inodes_count; /* Free inodes count */ *************** *** 162,169 **** struct ext2_group_desc { ! unsigned long bg_block_bitmap; /* Blocks bitmap block */ ! unsigned long bg_inode_bitmap; /* Inodes bitmap block */ unsigned long bg_inode_table; /* Inodes table block */ unsigned short bg_free_blocks_count; /* Free blocks count */ unsigned short bg_free_inodes_count; /* Free inodes count */ --- 162,169 ---- struct ext2_group_desc { ! unsigned long bg_block_bitmap; /* Blocks bitmap block */ ! unsigned long bg_inode_bitmap; /* Inodes bitmap block */ unsigned long bg_inode_table; /* Inodes table block */ unsigned short bg_free_blocks_count; /* Free blocks count */ unsigned short bg_free_inodes_count; /* Free inodes count */ *************** *** 176,214 **** * Macro-instructions used to manage group descriptors */ #ifdef __KERNEL__ ! # define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group) ! # define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block) ! # define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group) #else ! # define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) ! # define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) ! # define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) #endif /* * Constants relative to the data blocks */ ! #define EXT2_NDIR_BLOCKS 12 ! #define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS ! #define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) ! #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) ! #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) /* * Inode flags */ ! #define EXT2_SECRM_FL 0x0001 /* Secure deletion */ ! #define EXT2_UNRM_FL 0x0002 /* Undelete */ ! #define EXT2_COMPR_FL 0x0004 /* Compress file */ #define EXT2_SYNC_FL 0x0008 /* Synchronous updates */ /* * ioctl commands */ ! #define EXT2_IOC_GETFLAGS _IOR('f', 1, long) ! #define EXT2_IOC_SETFLAGS _IOW('f', 2, long) ! #define EXT2_IOC_GETVERSION _IOR('v', 1, long) ! #define EXT2_IOC_SETVERSION _IOW('v', 2, long) /* * Structure of an inode on the disk --- 176,214 ---- * Macro-instructions used to manage group descriptors */ #ifdef __KERNEL__ ! # define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group) ! # define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block) ! # define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group) #else ! # define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) ! # define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) ! # define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) #endif /* * Constants relative to the data blocks */ ! #define EXT2_NDIR_BLOCKS 12 ! #define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS ! #define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) ! #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) ! #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) /* * Inode flags */ ! #define EXT2_SECRM_FL 0x0001 /* Secure deletion */ ! #define EXT2_UNRM_FL 0x0002 /* Undelete */ ! #define EXT2_COMPR_FL 0x0004 /* Compress file */ #define EXT2_SYNC_FL 0x0008 /* Synchronous updates */ /* * ioctl commands */ ! #define EXT2_IOC_GETFLAGS _IOR('f', 1, long) ! #define EXT2_IOC_SETFLAGS _IOW('f', 2, long) ! #define EXT2_IOC_GETVERSION _IOR('v', 1, long) ! #define EXT2_IOC_SETVERSION _IOW('v', 2, long) /* * Structure of an inode on the disk *************** *** 217,238 **** unsigned short i_mode; /* File mode */ unsigned short i_uid; /* Owner Uid */ unsigned long i_size; /* Size in bytes */ ! unsigned long i_atime; /* Access time */ ! unsigned long i_ctime; /* Creation time */ ! unsigned long i_mtime; /* Modification time */ ! unsigned long i_dtime; /* Deletion Time */ unsigned short i_gid; /* Group Id */ unsigned short i_links_count; /* Links count */ unsigned long i_blocks; /* Blocks count */ ! unsigned long i_flags; /* File flags */ unsigned long i_reserved1; unsigned long i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ unsigned long i_version; /* File version (for NFS) */ unsigned long i_file_acl; /* File ACL */ unsigned long i_dir_acl; /* Directory ACL */ ! unsigned long i_faddr; /* Fragment address */ unsigned char i_frag; /* Fragment number */ ! unsigned char i_fsize; /* Fragment size */ unsigned short i_pad1; unsigned long i_reserved2[2]; }; --- 217,238 ---- unsigned short i_mode; /* File mode */ unsigned short i_uid; /* Owner Uid */ unsigned long i_size; /* Size in bytes */ ! unsigned long i_atime; /* Access time */ ! unsigned long i_ctime; /* Creation time */ ! unsigned long i_mtime; /* Modification time */ ! unsigned long i_dtime; /* Deletion Time */ unsigned short i_gid; /* Group Id */ unsigned short i_links_count; /* Links count */ unsigned long i_blocks; /* Blocks count */ ! unsigned long i_flags; /* File flags */ unsigned long i_reserved1; unsigned long i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ unsigned long i_version; /* File version (for NFS) */ unsigned long i_file_acl; /* File ACL */ unsigned long i_dir_acl; /* Directory ACL */ ! unsigned long i_faddr; /* Fragment address */ unsigned char i_frag; /* Fragment number */ ! unsigned char i_fsize; /* Fragment size */ unsigned short i_pad1; unsigned long i_reserved2[2]; }; *************** *** 240,247 **** /* * File system states */ ! #define EXT2_VALID_FS 0x0001 /* Unmounted cleany */ ! #define EXT2_ERROR_FS 0x0002 /* Errors detected */ /* * Mount flags --- 240,247 ---- /* * File system states */ ! #define EXT2_VALID_FS 0x0001 /* Unmounted cleany */ ! #define EXT2_ERROR_FS 0x0002 /* Errors detected */ /* * Mount flags *************** *** 264,280 **** unsigned long s_free_inodes_count;/* Free inodes count */ unsigned long s_first_data_block;/* First Data Block */ unsigned long s_log_block_size;/* Block size */ ! long s_log_frag_size; /* Fragment size */ unsigned long s_blocks_per_group;/* # Blocks per group */ unsigned long s_frags_per_group;/* # Fragments per group */ unsigned long s_inodes_per_group;/* # Inodes per group */ ! unsigned long s_mtime; /* Mount time */ ! unsigned long s_wtime; /* Write time */ unsigned short s_mnt_count; /* Mount count */ ! unsigned short s_max_mnt_count; /* Maximal mount count */ ! unsigned short s_magic; /* Magic signature */ ! unsigned short s_state; /* File system state */ ! unsigned long s_reserved[241]; /* Padding to the end of the block */ }; /* --- 264,280 ---- unsigned long s_free_inodes_count;/* Free inodes count */ unsigned long s_first_data_block;/* First Data Block */ unsigned long s_log_block_size;/* Block size */ ! long s_log_frag_size; /* Fragment size */ unsigned long s_blocks_per_group;/* # Blocks per group */ unsigned long s_frags_per_group;/* # Fragments per group */ unsigned long s_inodes_per_group;/* # Inodes per group */ ! unsigned long s_mtime; /* Mount time */ ! unsigned long s_wtime; /* Write time */ unsigned short s_mnt_count; /* Mount count */ ! unsigned short s_max_mnt_count; /* Maximal mount count */ ! unsigned short s_magic; /* Magic signature */ ! unsigned short s_state; /* File system state */ ! unsigned long s_reserved[241]; /* Padding to the end of the block */ }; /* *************** *** 284,292 **** struct ext2_dir_entry { unsigned long inode; /* Inode number */ ! unsigned short rec_len; /* Directory entry length */ unsigned short name_len; /* Name length */ ! char name[EXT2_NAME_LEN]; /* File name */ }; /* --- 284,292 ---- struct ext2_dir_entry { unsigned long inode; /* Inode number */ ! unsigned short rec_len; /* Directory entry length */ unsigned short name_len; /* Name length */ ! char name[EXT2_NAME_LEN]; /* File name */ }; /* *************** *** 294,302 **** * * NOTE: It must be a multiple of 4 */ ! #define EXT2_DIR_PAD 4 ! #define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) ! #define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ ~EXT2_DIR_ROUND) #ifdef __KERNEL__ --- 294,302 ---- * * NOTE: It must be a multiple of 4 */ ! #define EXT2_DIR_PAD 4 ! #define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) ! #define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ ~EXT2_DIR_ROUND) #ifdef __KERNEL__ diff -cr --new-file linux-0.07pl4/include/linux/icmp.h linux-0.08/include/linux/icmp.h *** linux-0.07pl4/include/linux/icmp.h Wed Dec 31 19:00:00 1969 --- linux-0.08/include/linux/icmp.h Thu Mar 10 15:53:11 1994 *************** *** 0 **** --- 1,81 ---- + /* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the ICMP protocol. + * + * Version: @(#)icmp.h 1.0.3 04/28/93 + * + * Author: Fred N. van Kempen, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + #ifndef _LINUX_ICMP_H + #define _LINUX_ICMP_H + + #define ICMP_ECHOREPLY 0 /* Echo Reply */ + #define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ + #define ICMP_SOURCE_QUENCH 4 /* Source Quench */ + #define ICMP_REDIRECT 5 /* Redirect (change route) */ + #define ICMP_ECHO 8 /* Echo Request */ + #define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ + #define ICMP_PARAMETERPROB 12 /* Parameter Problem */ + #define ICMP_TIMESTAMP 13 /* Timestamp Request */ + #define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ + #define ICMP_INFO_REQUEST 15 /* Information Request */ + #define ICMP_INFO_REPLY 16 /* Information Reply */ + #define ICMP_ADDRESS 17 /* Address Mask Request */ + #define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ + + + /* Codes for UNREACH. */ + #define ICMP_NET_UNREACH 0 /* Network Unreachable */ + #define ICMP_HOST_UNREACH 1 /* Host Unreachable */ + #define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ + #define ICMP_PORT_UNREACH 3 /* Port Unreachable */ + #define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ + #define ICMP_SR_FAILED 5 /* Source Route failed */ + #define ICMP_NET_UNKNOWN 6 + #define ICMP_HOST_UNKNOWN 7 + #define ICMP_HOST_ISOLATED 8 + #define ICMP_NET_ANO 9 + #define ICMP_HOST_ANO 10 + #define ICMP_NET_UNR_TOS 11 + #define ICMP_HOST_UNR_TOS 12 + + /* Codes for REDIRECT. */ + #define ICMP_REDIR_NET 0 /* Redirect Net */ + #define ICMP_REDIR_HOST 1 /* Redirect Host */ + #define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */ + #define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */ + + /* Codes for TIME_EXCEEDED. */ + #define ICMP_EXC_TTL 0 /* TTL count exceeded */ + #define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */ + + + struct icmphdr { + unsigned char type; + unsigned char code; + unsigned short checksum; + union { + struct { + unsigned short id; + unsigned short sequence; + } echo; + unsigned long gateway; + } un; + }; + + + struct icmp_err { + int errno; + unsigned fatal:1; + }; + + + #endif /* _LINUX_ICMP_H */ diff -cr --new-file linux-0.07pl4/include/linux/interrupt.h linux-0.08/include/linux/interrupt.h *** linux-0.07pl4/include/linux/interrupt.h Sun Jan 9 16:24:04 1994 --- linux-0.08/include/linux/interrupt.h Thu Mar 10 16:12:41 1994 *************** *** 43,48 **** --- 43,54 ---- #define IRQ_MACHSPEC (0x10000000L) + #ifndef ISRFUNC_T + struct intframe; + typedef void (*isrfunc) (struct intframe *fp, void *data); + #define ISRFUNC_T + #endif /* ISRFUNC_T */ + /* * This structure is used to chain together the ISRs for a particular * interrupt source (if it supports chaining). diff -cr --new-file linux-0.07pl4/include/linux/ip.h linux-0.08/include/linux/ip.h *** linux-0.07pl4/include/linux/ip.h Wed Dec 31 19:00:00 1969 --- linux-0.08/include/linux/ip.h Thu Mar 10 15:47:37 1994 *************** *** 0 **** --- 1,81 ---- + /* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the IP protocol. + * + * Version: @(#)ip.h 1.0.2 04/28/93 + * + * Authors: Fred N. van Kempen, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + #ifndef _LINUX_IP_H + #define _LINUX_IP_H + + + #define IPOPT_END 0 + #define IPOPT_NOOP 1 + #define IPOPT_SEC 130 + #define IPOPT_LSRR 131 + #define IPOPT_SSRR 137 + #define IPOPT_RR 7 + #define IPOPT_SID 136 + #define IPOPT_TIMESTAMP 68 + + + struct timestamp { + unsigned char len; + unsigned char ptr; + union { + unsigned char flags:4, + overflow:4; + unsigned char full_char; + } x; + unsigned long data[9]; + }; + + + #define MAX_ROUTE 16 + + struct route { + char route_size; + char pointer; + unsigned long route[MAX_ROUTE]; + }; + + + struct options { + struct route record_route; + struct route loose_route; + struct route strict_route; + struct timestamp tstamp; + unsigned short security; + unsigned short compartment; + unsigned short handling; + unsigned short stream; + unsigned tcc; + }; + + + struct iphdr { + unsigned char ihl:4, + version:4; + unsigned char tos; + unsigned short tot_len; + unsigned short id; + unsigned short frag_off; + unsigned char ttl; + unsigned char protocol; + unsigned short check; + unsigned long saddr; + unsigned long daddr; + /*The options start here. */ + }; + + + #endif /* _LINUX_IP_H */ diff -cr --new-file linux-0.07pl4/include/linux/lp.h linux-0.08/include/linux/lp.h *** linux-0.07pl4/include/linux/lp.h Wed Dec 31 19:00:00 1969 --- linux-0.08/include/linux/lp.h Sun Mar 27 09:45:56 1994 *************** *** 0 **** --- 1,96 ---- + #ifndef _LINUX_LP_H + #define _LINUX_LP_H + + /* + * usr/include/linux/lp.h modified for Amiga by Michael Rausch + * + * linux i386 version c.1991-1992 James Wiegand + * many modifications copyright (C) 1992 Michael K. Johnson + * Interrupt support added 1993 Nigel Gamble + */ + + /* + * Per POSIX guidelines, this module reserves the LP and lp prefixes + * These are the lp_table[minor].flags flags... + */ + #define LP_EXIST 0x0001 + #define LP_BUSY 0x0004 + #define LP_ABORT 0x0040 + + /* timeout for each character. This is relative to bus cycles -- it + * is the count in a busy loop. THIS IS THE VALUE TO CHANGE if you + * have extremely slow printing, or if the machine seems to slow down + * a lot when you print. If you have slow printing, increase this + * number and recompile, and if your system gets bogged down, decrease + * this number. This can be changed with the tunelp(8) command as well. + */ + + #define LP_INIT_CHAR 400000 + + /* This is the amount of time that the driver waits for the printer to + * catch up when the printer's buffer appears to be filled. If you + * want to tune this and have a fast printer (i.e. HPIIIP), decrease + * this number, and if you have a slow printer, increase this number. + * This is in hundredths of a second, the default 2 being .05 second. + * Or use the tunelp(8) command, which is especially nice if you want + * change back and forth between character and graphics printing, which + * are wildly different... + */ + + #define LP_INIT_TIME 2 + + /* IOCTL numbers */ + #define LPCHAR 0x0001 /* corresponds to LP_INIT_CHAR */ + #define LPTIME 0x0002 /* corresponds to LP_INIT_TIME */ + #define LPABORT 0x0004 /* call with TRUE arg to abort on error, + FALSE to retry. Default is retry. */ + #define LPSETIRQ 0x0005 /* call with new IRQ number, + or 0 for polling (no IRQ) */ + #define LPGETIRQ 0x0006 /* get the current IRQ number */ + #define LPWAIT 0x0008 /* corresponds to LP_INIT_WAIT */ + + /* timeout for printk'ing a timeout, in jiffies (100ths of a second). + This is also used for re-checking error conditions if LP_ABORT is + not set. This is the default behavior. */ + + #define LP_TIMEOUT_INTERRUPT (60 * HZ) + #define LP_TIMEOUT_POLLED (10 * HZ) + + #define LP_F lp_table.flags /* flags for busy, etc. */ + #define LP_CHAR lp_table.chars /* busy timeout */ + #define LP_TIME lp_table.time /* wait time */ + #define LP_WAIT lp_table.wait /* strobe wait */ + #define LP_IRQ lp_table.irq /* interrupt # */ + /* 0 means polled */ + + #define LP_BUFFER_SIZE 256 + + struct lp_struct { + unsigned int irq; + int flags; + unsigned int chars; + unsigned int time; + struct wait_queue *lp_wait_q; + char *lp_buffer; + }; + + struct lp_struct lp_table = { + 0, 0, LP_INIT_CHAR, LP_INIT_TIME, NULL, NULL, + }; + #define LP_NO 1 + + + #define LP_OUT(c) ciaa.prb = c + + /* busy is low-active, and so are the cia bits */ + #define LP_IS_BUSY (ciab.pra & 1) + #define LP_HAS_POUT (ciab.pra & 2) + #define LP_IS_ONLINE (ciab.pra & 4) + + /* + * function prototypes + */ + + extern long lp_init(long); + + #endif diff -cr --new-file linux-0.07pl4/include/linux/mm.h linux-0.08/include/linux/mm.h *** linux-0.07pl4/include/linux/mm.h Sun Feb 13 21:56:22 1994 --- linux-0.08/include/linux/mm.h Tue Mar 22 13:43:06 1994 *************** *** 171,179 **** extern unsigned long high_memory; #if defined(__i386__) ! # define KSTART_ADDR (0) #elif defined(__mc68000__) ! # define KSTART_ADDR (0xC0000000) #else # error Architecture not supported #endif --- 171,179 ---- extern unsigned long high_memory; #if defined(__i386__) ! # define KSTART_ADDR (0UL) #elif defined(__mc68000__) ! # define KSTART_ADDR (0xC0000000UL) #else # error Architecture not supported #endif *************** *** 257,262 **** --- 257,268 ---- & (NUM_L3_ENTRIES-1)) #define TABLE_MASK (0xfffffe00) + + /* page table routines */ + unsigned long *get_pointer_table (void); + void free_pointer_table (unsigned long *); + unsigned long *get_page_table (unsigned long *); + void free_page_table (unsigned long *ptr); /* For virtual address to physical address conversion */ extern unsigned long mm_vtop(unsigned long addr); diff -cr --new-file linux-0.07pl4/include/linux/mouse.h linux-0.08/include/linux/mouse.h *** linux-0.07pl4/include/linux/mouse.h Fri Dec 11 19:13:28 1992 --- linux-0.08/include/linux/mouse.h Sun Mar 27 09:44:10 1994 *************** *** 5,10 **** --- 5,11 ---- #define PSMOUSE_MINOR 1 #define MS_BUSMOUSE_MINOR 2 #define ATIXL_BUSMOUSE_MINOR 3 + #define AMIGAMOUSE_MINOR 4 unsigned long mouse_init(unsigned long); diff -cr --new-file linux-0.07pl4/include/linux/proc_fs.h linux-0.08/include/linux/proc_fs.h *** linux-0.07pl4/include/linux/proc_fs.h Wed Dec 31 19:00:00 1969 --- linux-0.08/include/linux/proc_fs.h Sun Feb 27 10:32:59 1994 *************** *** 0 **** --- 1,36 ---- + #ifndef _LINUX_PROC_FS_H + #define _LINUX_PROC_FS_H + + /* + * The proc filesystem constants/structures + */ + + #define PROC_ROOT_INO 1 + + #define PROC_SUPER_MAGIC 0x9fa0 + + struct proc_dir_entry { + unsigned short low_ino; + unsigned short namelen; + char * name; + }; + + extern struct super_block *proc_read_super(struct super_block *,void *,int); + extern void proc_put_inode(struct inode *); + extern void proc_put_super(struct super_block *); + extern void proc_statfs(struct super_block *, struct statfs *); + extern void proc_read_inode(struct inode *); + extern void proc_write_inode(struct inode *); + extern int proc_match(int, const char *, struct proc_dir_entry *); + + extern struct inode_operations proc_root_inode_operations; + extern struct inode_operations proc_base_inode_operations; + extern struct inode_operations proc_net_inode_operations; + extern struct inode_operations proc_mem_inode_operations; + extern struct inode_operations proc_array_inode_operations; + extern struct inode_operations proc_kmsg_inode_operations; + extern struct inode_operations proc_link_inode_operations; + extern struct inode_operations proc_fd_inode_operations; + extern struct inode_operations proc_net_inode_operations; + + #endif diff -cr --new-file linux-0.07pl4/include/linux/ptrace.h linux-0.08/include/linux/ptrace.h *** linux-0.07pl4/include/linux/ptrace.h Thu Mar 24 22:05:21 1994 --- linux-0.08/include/linux/ptrace.h Thu Mar 24 16:44:29 1994 *************** *** 34,39 **** --- 34,108 ---- /* use ptrace (3 or 6, pid, PT_EXCL, data); to read or write the processes registers. */ + #if defined(__i386__) + + #define EBX 0 + #define ECX 1 + #define EDX 2 + #define ESI 3 + #define EDI 4 + #define EBP 5 + #define EAX 6 + #define DS 7 + #define ES 8 + #define FS 9 + #define GS 10 + #define ORIG_EAX 11 + #define EIP 12 + #define CS 13 + #define EFL 14 + #define UESP 15 + #define SS 16 + + + /* this struct defines the way the registers are stored on the + stack during a system call. */ + + struct pt_regs { + long ebx; + long ecx; + long edx; + long esi; + long edi; + long ebp; + long eax; + unsigned short ds, __dsu; + unsigned short es, __esu; + unsigned short fs, __fsu; + unsigned short gs, __gsu; + long orig_eax; + long eip; + unsigned short cs, __csu; + long eflags; + long esp; + unsigned short ss, __ssu; + }; + + /* determines which flags the user has access to. */ + /* 1 = access 0 = no access */ + #define FLAG_MASK 0x00044dd5 + + /* set's the trap flag. */ + #define TRAP_FLAG 0x100 + + /* + * this is the number to subtract from the top of the stack. To find + * the local frame. + */ + #define MAGICNUMBER 68 + + #define ptrace_setsingle(child) \ + do { long tmp; \ + tmp = ptrace_get_stack_long((child), \ + sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG; \ + ptrace_put_stack_long((child),sizeof(long)*EFL-MAGICNUMBER,tmp); } while(0) + #define ptrace_clrsingle(child) \ + do { long tmp; \ + tmp = ptrace_get_stack_long((child), \ + sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; \ + ptrace_put_stack_long((child),sizeof(long)*EFL-MAGICNUMBER,tmp); } while(0) + #elif defined(__mc68000__) + #define PT_D1 0 #define PT_D2 1 #define PT_D3 2 *************** *** 82,85 **** short fmtvec; }; ! #endif --- 151,182 ---- short fmtvec; }; ! /* determines which bits in the SR the user has access to. */ ! /* 1 = access 0 = no access */ ! #define SR_MASK 0x001f ! ! /* sets the trace bits. */ ! #define TRACE_BITS 0x8000 ! ! #define ptrace_setsingle(child) \ ! do { long tmp; \ ! tmp = ptrace_get_stack_long((child), \ ! sizeof(long)*PT_SR) | TRACE_BITS; \ ! ptrace_put_stack_long((child),sizeof(long)*PT_SR,tmp); } while(0) ! #define ptrace_clrsingle(child) \ ! do { long tmp; \ ! tmp = ptrace_get_stack_long((child), \ ! sizeof(long)*PT_SR) & ~TRACE_BITS; \ ! ptrace_put_stack_long((child),sizeof(long)*PT_SR,tmp); } while(0) ! #else ! #error Architecture not supported ! #endif /* architecture */ ! ! extern int ptrace_put_stack_long (struct task_struct *, int, unsigned long); ! extern int ptrace_get_stack_long (struct task_struct *, int); ! extern int ptrace_read_long(struct task_struct *, long, unsigned long *); ! extern int ptrace_write_long(struct task_struct *, long, long); ! extern int ptrace_peekusr(struct task_struct *, long, long); ! extern int ptrace_pokeusr(struct task_struct *, long, long); ! ! #endif /* _LINUX_PTRACE_H */ diff -cr --new-file linux-0.07pl4/include/linux/sched.h linux-0.08/include/linux/sched.h *** linux-0.07pl4/include/linux/sched.h Wed Jan 12 17:10:51 1994 --- linux-0.08/include/linux/sched.h Sat Mar 26 11:00:58 1994 *************** *** 182,187 **** --- 182,188 ---- unsigned long fpregs[24]; /* fp0-fp7 registers */ unsigned long fpcntl[3]; /* fp control regs */ unsigned short fpstate[FPSTATESIZE]; /* floating point state */ + unsigned long esp0; /* points to SR of stack frame */ }; #endif *************** *** 271,276 **** --- 272,279 ---- #define PF_PTRACED 0x00000010 /* set if ptrace (0) has been called. */ #define PF_TRACESYS 0x00000020 /* tracing system calls */ + #define PF_DTRACE 0x00000040 /* delayed trace */ + /* * cloning flags: */ *************** *** 279,291 **** #define COPYFD 0x00000200 /* set if fd's should be copied, not shared (NI) */ /* - * This architecture specific function duplicates the cpu portion - * of the task during a fork, including the kernel stack. - * It returns 1 in the child, and 0 in the parent. - */ - extern int cpu_fork (struct task_struct *p); - - /* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) */ --- 282,287 ---- *************** *** 356,362 **** /* cloe */ {{ 0, }}, \ /* tss */ {{0,0,0,0,0,0,0,0,0,0,0, \ sizeof(init_kernel_stack) + (long) init_kernel_stack}, \ ! PS_S|PS_M, USER_DS, NULL, 0, {0, 0}, {0,}, {0,}, {0,} \ }, \ } #endif --- 352,358 ---- /* cloe */ {{ 0, }}, \ /* tss */ {{0,0,0,0,0,0,0,0,0,0,0, \ sizeof(init_kernel_stack) + (long) init_kernel_stack}, \ ! PS_S|PS_M, USER_DS, NULL, 0, {0, 0}, {0,}, {0,}, {0,}, 0\ }, \ } #endif diff -cr --new-file linux-0.07pl4/include/linux/string.h linux-0.08/include/linux/string.h *** linux-0.07pl4/include/linux/string.h Mon Dec 13 15:32:46 1993 --- linux-0.08/include/linux/string.h Tue Mar 15 16:05:26 1994 *************** *** 439,444 **** --- 439,461 ---- return dest; } + extern inline void * strncpy(char *dest, const void *src, size_t n) + { + __asm__("movel %2,d0\n\t" + "beq 2f\n\t" + "movel %0,a0\n\t" + "movel %1,a1\n\t" + "1:\tmoveb a1@+,a0@+\n\t" + "beq 2f\n\t" + "subql #1,d0\n\t" + "bne 1b\n\t" + "2:" + : + : "g" (dest), "g" (src), "g" (n) + : "a0", "a1", "d0" ); + return dest; + } + extern inline int strcmp(const char * cs,const char * ct) { register int __res __asm__("d0"); *************** *** 447,457 **** "movel %1,a1\n\t" /* a1 = ct */ "1:\tmoveb a0@+,d0\n\t" /* get *cs */ "cmpb a1@+,d0\n\t" /* compare a byte */ ! "jne 2f\n\t" /* not equal, break out */ "tstb d0\n\t" /* at end of cs? */ ! "jne 1b\n\t" /* no, keep going */ "moveq #0,d0\n\t" /* strings are equal */ ! "jra 3f\n\t" "2:\tsubb a1@-,d0\n\t" /* *cs - *ct */ "extw d0\n\t" "extl d0\n\t" --- 464,474 ---- "movel %1,a1\n\t" /* a1 = ct */ "1:\tmoveb a0@+,d0\n\t" /* get *cs */ "cmpb a1@+,d0\n\t" /* compare a byte */ ! "bne 2f\n\t" /* not equal, break out */ "tstb d0\n\t" /* at end of cs? */ ! "bne 1b\n\t" /* no, keep going */ "moveq #0,d0\n\t" /* strings are equal */ ! "bra 3f\n\t" "2:\tsubb a1@-,d0\n\t" /* *cs - *ct */ "extw d0\n\t" "extl d0\n\t" *************** *** 467,484 **** register int __res __asm__("d0"); __asm__("movel %2,d1\n\t" /* gccount */ ! "jeq 4f\n\t" /* nothing to do */ "movel %0,a0\n\t" /* a0 = cs */ "movel %1,a1\n\t" /* a1 = ct */ "1:\tmovb a0@+,d0\n\t" /* get *cs */ "cmpb a1@+,d0\n\t" /* compare a byte */ ! "jne 3f\n\t" /* not equal, break out */ "tstb d0\n\t" /* at end of cs? */ ! "jeq 2f\n\t" /* yes, all done */ "subql #1,d1\n\t" /* no, adjust count */ ! "jne 1b\n\t" /* more to do, keep going */ "2:\tmoveq #0,d0\n\t" /* strings are equal */ ! "jra 4f\n\t" "3:\tsubb a1@-,d0\n\t" /* *cs - *ct */ "extw d0\n\t" "extl d0\n\t" --- 484,501 ---- register int __res __asm__("d0"); __asm__("movel %2,d1\n\t" /* gccount */ ! "beq 4f\n\t" /* nothing to do */ "movel %0,a0\n\t" /* a0 = cs */ "movel %1,a1\n\t" /* a1 = ct */ "1:\tmovb a0@+,d0\n\t" /* get *cs */ "cmpb a1@+,d0\n\t" /* compare a byte */ ! "bne 3f\n\t" /* not equal, break out */ "tstb d0\n\t" /* at end of cs? */ ! "beq 2f\n\t" /* yes, all done */ "subql #1,d1\n\t" /* no, adjust count */ ! "bne 1b\n\t" /* more to do, keep going */ "2:\tmoveq #0,d0\n\t" /* strings are equal */ ! "bra 4f\n\t" "3:\tsubb a1@-,d0\n\t" /* *cs - *ct */ "extw d0\n\t" "extl d0\n\t" *************** *** 506,522 **** return(sc - s); } ! extern inline size_t strspn(const char * cs, const char * ct) { ! const char *sc1, *sc2; ! ! for( sc1 = cs; *sc1 != '\0'; ++sc1) ! for( sc2 = ct; *sc2 != '\0'; ++sc2) ! if( *sc2 == '\0') ! return( sc1 - cs); ! else if ( *sc1 == *sc2 ) ! break; ! return( sc1 - cs ); } extern inline char * strpbrk(const char * cs,const char * ct) --- 523,546 ---- return(sc - s); } ! extern inline size_t strspn(const char *s, const char *accept) { ! const char *p; ! const char *a; ! size_t count = 0; ! ! for (p = s; *p != '\0'; ++p) ! { ! for (a = accept; *a != '\0'; ++a) ! if (*p == *a) ! break; ! if (*a == '\0') ! return count; ! else ! ++count; ! } ! ! return count; } extern inline char * strpbrk(const char * cs,const char * ct) *************** *** 533,544 **** extern inline char * strtok(char * s,const char * ct) { char *sbegin, *send; ! static char *ssave = ""; ! sbegin = (s) ? s : ssave; sbegin += strspn(sbegin,ct); if (*sbegin == '\0') { ! ssave = ""; return( NULL ); } send = strpbrk( sbegin, ct); --- 557,571 ---- extern inline char * strtok(char * s,const char * ct) { char *sbegin, *send; ! static char *ssave = NULL; ! sbegin = s ? s : ssave; ! if (!sbegin) { ! return NULL; ! } sbegin += strspn(sbegin,ct); if (*sbegin == '\0') { ! ssave = NULL; return( NULL ); } send = strpbrk( sbegin, ct); *************** *** 551,562 **** extern inline void * memset(void * s,char c,size_t count) { __asm__("movel %2,d0\n\t" ! "jeq 2f\n\t" "movel %0,a0\n\t" "movel %1,d1\n\t" "1:\tmoveb d1,a0@+\n\t" "subql #1,d0\n\t" ! "jne 1b\n\t" "2:" : : "g" (s), "g" (c), "g" (count) --- 578,589 ---- extern inline void * memset(void * s,char c,size_t count) { __asm__("movel %2,d0\n\t" ! "beq 2f\n\t" "movel %0,a0\n\t" "movel %1,d1\n\t" "1:\tmoveb d1,a0@+\n\t" "subql #1,d0\n\t" ! "bne 1b\n\t" "2:" : : "g" (s), "g" (c), "g" (count) *************** *** 567,578 **** extern inline void * memcpy(void * to, const void * from, size_t n) { __asm__("movel %2,d0\n\t" ! "jeq 2f\n\t" "movel %0,a0\n\t" "movel %1,a1\n\t" "1:\tmoveb a1@+,a0@+\n\t" "subql #1,d0\n\t" ! "jne 1b\n\t" "2:" : : "g" (to), "g" (from), "g" (n) --- 594,605 ---- extern inline void * memcpy(void * to, const void * from, size_t n) { __asm__("movel %2,d0\n\t" ! "beq 2f\n\t" "movel %0,a0\n\t" "movel %1,a1\n\t" "1:\tmoveb a1@+,a0@+\n\t" "subql #1,d0\n\t" ! "bne 1b\n\t" "2:" : : "g" (to), "g" (from), "g" (n) *************** *** 584,607 **** { if (dest + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + #ifndef _LINUX_TCP_H + #define _LINUX_TCP_H + + + #define HEADER_SIZE 64 /* maximum header size */ + + + struct tcphdr { + unsigned short source; + unsigned short dest; + unsigned long seq; + unsigned long ack_seq; + unsigned short res1:4, + doff:4, + fin:1, + syn:1, + rst:1, + psh:1, + ack:1, + urg:1, + res2:2; + unsigned short window; + unsigned short check; + unsigned short urg_ptr; + }; + + + enum { + TCP_ESTABLISHED = 1, + TCP_SYN_SENT, + TCP_SYN_RECV, + #if 0 + TCP_CLOSING, /* not a valid state, just a seperator so we can use + < tcp_closing or > tcp_closing for checks. */ + #endif + TCP_FIN_WAIT1, + TCP_FIN_WAIT2, + TCP_TIME_WAIT, + TCP_CLOSE, + TCP_CLOSE_WAIT, + TCP_LAST_ACK, + TCP_LISTEN + }; + + #endif /* _LINUX_TCP_H */ diff -cr --new-file linux-0.07pl4/include/linux/traps.h linux-0.08/include/linux/traps.h *** linux-0.07pl4/include/linux/traps.h Mon Nov 15 15:00:47 1993 --- linux-0.08/include/linux/traps.h Thu Mar 24 14:42:52 1994 *************** *** 65,70 **** --- 65,71 ---- #define VECOFF(vec) ((vec)<<2) /* Status register bits */ + #define PS_T (0x8000) #define PS_S (0x2000) #define PS_M (0x1000) #define PS_C (0x0001) diff -cr --new-file linux-0.07pl4/include/linux/types.h linux-0.08/include/linux/types.h *** linux-0.07pl4/include/linux/types.h Mon Jan 3 15:26:31 1994 --- linux-0.08/include/linux/types.h Thu Mar 10 16:52:56 1994 *************** *** 97,121 **** #undef __FD_SETSIZE #define __FD_SETSIZE (__FDSET_LONGS*__NFDBITS) #undef __FD_SET #define __FD_SET(fd,fdsetp) \ ! __asm__ __volatile__("bset %1,%0": \ ! "=m" (((fd_set *) (fdsetp))->fds_bits[fd/__NFDBITS]) \ ! :"d" ((int) (fd % __NFDBITS))) #undef __FD_CLR #define __FD_CLR(fd,fdsetp) \ ! __asm__ __volatile__("bclr %1,%0": \ ! "=m" (((fd_set *) (fdsetp))->fds_bits[fd/__NFDBITS]) \ ! :"d" ((int) (fd % __NFDBITS))) #undef __FD_ISSET #define __FD_ISSET(fd,fdsetp) (__extension__ ({ \ unsigned char __result; \ ! __asm__ __volatile__("btst %1,%2 ; sne %0" \ ! :"=d" (__result) :"d" ((int) (fd % __NFDBITS)), \ ! "m" (((fd_set *) (fdsetp))->fds_bits[fd/__NFDBITS])); \ __result; })) #undef __FD_ZERO #define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp))) --- 97,128 ---- #undef __FD_SETSIZE #define __FD_SETSIZE (__FDSET_LONGS*__NFDBITS) + #if defined(__i386__) /* stupid gratuitous assembler */ #undef __FD_SET #define __FD_SET(fd,fdsetp) \ ! __asm__ __volatile__("btsl %1,%0": \ ! "=m" (*(fd_set *) (fdsetp)):"r" ((int) (fd))) #undef __FD_CLR #define __FD_CLR(fd,fdsetp) \ ! __asm__ __volatile__("btrl %1,%0": \ ! "=m" (*(fd_set *) (fdsetp)):"r" ((int) (fd))) #undef __FD_ISSET #define __FD_ISSET(fd,fdsetp) (__extension__ ({ \ unsigned char __result; \ ! __asm__ __volatile__("btl %1,%2 ; setb %0" \ ! :"=q" (__result) :"r" ((int) (fd)), \ ! "m" (*(fd_set *) (fdsetp))); \ __result; })) + #else + /* It's easier to assume 8-bit bytes than to get CHAR_BIT. */ + #define __FDELT(d) ((d) / __NFDBITS) + #define __FDMASK(d) (1 << ((d) % __NFDBITS)) + #define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) + #define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) + #define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) + #endif #undef __FD_ZERO #define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp))) diff -cr --new-file linux-0.07pl4/include/linux/udp.h linux-0.08/include/linux/udp.h *** linux-0.07pl4/include/linux/udp.h Wed Dec 31 19:00:00 1969 --- linux-0.08/include/linux/udp.h Thu Mar 10 15:47:46 1994 *************** *** 0 **** --- 1,29 ---- + /* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the UDP protocol. + * + * Version: @(#)udp.h 1.0.2 04/28/93 + * + * Author: Fred N. van Kempen, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + #ifndef _LINUX_UDP_H + #define _LINUX_UDP_H + + + struct udphdr { + unsigned short source; + unsigned short dest; + unsigned short len; + unsigned short check; + }; + + + #endif /* _LINUX_UDP_H */ diff -cr --new-file linux-0.07pl4/include/linux/un.h linux-0.08/include/linux/un.h *** linux-0.07pl4/include/linux/un.h Wed Dec 31 19:00:00 1969 --- linux-0.08/include/linux/un.h Sat Mar 5 12:50:41 1994 *************** *** 0 **** --- 1,9 ---- + #ifndef _LINUX_UN_H + #define _LINUX_UN_H + + struct sockaddr_un { + unsigned short sun_family; /* AF_UNIX */ + char sun_path[108]; /* pathname */ + }; + + #endif /* _LINUX_UN_H */ diff -cr --new-file linux-0.07pl4/include/linux/unistd.h linux-0.08/include/linux/unistd.h *** linux-0.07pl4/include/linux/unistd.h Fri Dec 10 18:42:23 1993 --- linux-0.08/include/linux/unistd.h Mon Mar 14 16:01:50 1994 *************** *** 144,262 **** #define _syscall0(type,name) \ type name(void) \ { \ ! register long __res __asm__ ("d0"); \ ! __asm__ __volatile__ ("movel %0,d0\n\t" \ ! "trap #0\n\t" \ ! "bcc 1f\n\t" \ ! "movel d0,_errno\n\t" \ ! "moveq #-1,d0\n\t" \ ! "1:" \ ! : /* no outputs */ : "i" (__NR_##name) : "d0" ); \ ! return (type) __res; \ } #define _syscall1(type,name,atype,a) \ type name(atype a) \ { \ ! register long __res __asm__ ("d0"); \ ! __asm__ __volatile__ ("movel %1,d1\n\t" \ ! "movel %0,d0\n\t" \ ! "trap #0\n\t" \ ! "bcc 1f\n\t" \ ! "movel d0,_errno\n\t" \ ! "moveq #-1,d0\n\t" \ ! "1:" \ ! : /* no outputs */ \ ! : "i" (__NR_##name), "g" ((long)(a)) : "d0", "d1" ); \ ! return (type) __res; \ } #define _syscall2(type,name,atype,a,btype,b) \ type name(atype a,btype b) \ { \ ! register long __res __asm__ ("d0"); \ ! __asm__ __volatile__ ("movel %1,d1\n\t" \ ! "movel %2,d2\n\t" \ ! "movel %0,d0\n\t" \ ! "trap #0\n\t" \ ! "bcc 1f\n\t" \ ! "movel d0,_errno\n\t" \ ! "moveq #-1,d0\n\t" \ ! "1:" \ ! : /* no outputs */ \ ! : "i" (__NR_##name), "g" ((long)(a)), \ ! "g" ((long)(b)) \ ! : "d0", "d1", "d2" ); \ ! return (type) __res; \ } #define _syscall3(type,name,atype,a,btype,b,ctype,c) \ type name(atype a,btype b,ctype c) \ { \ ! register long __res __asm__ ("d0"); \ ! __asm__ __volatile__ ("movel %1,d1\n\t" \ ! "movel %2,d2\n\t" \ ! "movel %3,d3\n\t" \ ! "movel %0,d0\n\t" \ ! "trap #0\n\t" \ ! "bcc 1f\n\t" \ ! "movel d0,_errno\n\t" \ ! "moveq #-1,d0\n\t" \ ! "1:" \ ! : /* no outputs */ \ ! : "i" (__NR_##name), "g" ((long)(a)), \ ! "g" ((long)(b)), \ ! "g" ((long)(c)) \ ! : "d0", "d1", "d2", "d3" ); \ ! return (type) __res; \ } #define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \ type name (atype a, btype b, ctype c, dtype d) \ { \ ! register long __res __asm__ ("d0"); \ ! __asm__ __volatile__ ("movel %1,d1\n\t" \ ! "movel %2,d2\n\t" \ ! "movel %3,d3\n\t" \ ! "movel %4,d4\n\t" \ ! "movel %0,d0\n\t" \ ! "trap #0\n\t" \ ! "bcc 1f\n\t" \ ! "movel d0,_errno\n\t" \ ! "moveq #-1,d0\n\t" \ ! "1:" \ ! : /* no outputs */ \ ! : "i" (__NR_##name), "g" ((long)(a)), \ ! "g" ((long)(b)), \ ! "g" ((long)(c)), \ ! "g" ((long)(d)) \ ! : "d0", "d1", "d2", "d3", "d4" ); \ ! return (type)__res; \ } #define _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \ type name (atype a,btype b,ctype c,dtype d,etype e) \ { \ ! register long __res __asm__ ("d0"); \ ! __asm__ __volatile__ ("movel %1,d1\n\t" \ ! "movel %2,d2\n\t" \ ! "movel %3,d3\n\t" \ ! "movel %4,d4\n\t" \ ! "movel %5,d5\n\t" \ ! "movel %0,d0\n\t" \ ! "trap #0\n\t" \ ! "bcc 1f\n\t" \ ! "movel d0,_errno\n\t" \ ! "moveq #-1,d0\n\t" \ ! "1:" \ ! : /* no outputs */ \ ! : "i" (__NR_##name), "g" ((long)(a)), \ ! "g" ((long)(b)), \ ! "g" ((long)(c)), \ ! "g" ((long)(d)), \ ! "g" ((long)(3)) \ ! : "d0", "d1", "d2", "d3", "d4", "d5" ); \ ! return (type) __res; \ } #endif /* _LINUX_UNISTD_H */ --- 144,252 ---- #define _syscall0(type,name) \ type name(void) \ { \ ! register long __res __asm__ ("d0") = __NR_##name; \ ! __asm__ __volatile__ ("trap #0" \ ! : "=g" (__res) \ ! : "0" (__NR_##name)); \ ! if (__res >= 0) \ ! return (type) __res; \ ! errno = -__res; \ ! return -1; \ } #define _syscall1(type,name,atype,a) \ type name(atype a) \ { \ ! register long __res __asm__ ("d0") = __NR_##name; \ ! __asm__ __volatile__ ("movel %2,d1\n\t" \ ! "trap #0" \ ! : "=g" (__res) \ ! : "0" (__NR_##name), "g" ((long)(a)) \ ! : "d1"); \ ! if (__res >= 0) \ ! return (type) __res; \ ! errno = -__res; \ ! return -1; \ } #define _syscall2(type,name,atype,a,btype,b) \ type name(atype a,btype b) \ { \ ! register long __res __asm__ ("d0") = __NR_##name; \ ! __asm__ __volatile__ ("movel %2,d1\n\t" \ ! "movel %3,d2\n\t" \ ! "trap #0" \ ! : "=g" (__res) \ ! : "0" (__NR_##name), "g" ((long)(a)), \ ! "g" ((long)(b)) \ ! : "d1", "d2"); \ ! if (__res >= 0) \ ! return (type) __res; \ ! errno = -__res; \ ! return -1; \ } #define _syscall3(type,name,atype,a,btype,b,ctype,c) \ type name(atype a,btype b,ctype c) \ { \ ! register long __res __asm__ ("d0") = __NR_##name; \ ! __asm__ __volatile__ ("movel %2,d1\n\t" \ ! "movel %3,d2\n\t" \ ! "movel %4,d3\n\t" \ ! "trap #0" \ ! : "=g" (__res) \ ! : "0" (__NR_##name), "g" ((long)(a)), \ ! "g" ((long)(b)), \ ! "g" ((long)(c)) \ ! : "d1", "d2", "d3"); \ ! if (__res >= 0) \ ! return (type) __res; \ ! errno = -__res; \ ! return -1; \ } #define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \ type name (atype a, btype b, ctype c, dtype d) \ { \ ! register long __res __asm__ ("d0") = __NR_##name; \ ! __asm__ __volatile__ ("movel %2,d1\n\t" \ ! "movel %3,d2\n\t" \ ! "movel %4,d3\n\t" \ ! "movel %5,d4\n\t" \ ! "trap #0" \ ! : "=g" (__res) \ ! : "0" (__NR_##name), "g" ((long)(a)), \ ! "g" ((long)(b)), \ ! "g" ((long)(c)), \ ! "g" ((long)(d)) \ ! : "d1", "d2", "d3", "d4"); \ ! if (__res >= 0) \ ! return (type) __res; \ ! errno = -__res; \ ! return -1; \ } #define _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \ type name (atype a,btype b,ctype c,dtype d,etype e) \ { \ ! register long __res __asm__ ("d0") = __NR_##name; \ ! __asm__ __volatile__ ("movel %2,d1\n\t" \ ! "movel %3,d2\n\t" \ ! "movel %4,d3\n\t" \ ! "movel %5,d4\n\t" \ ! "movel %6,d5\n\t" \ ! "trap #0" \ ! : "=g" (__res) \ ! : "0" (__NR_##name), "g" ((long)(a)), \ ! "g" ((long)(b)), \ ! "g" ((long)(c)), \ ! "g" ((long)(d)), \ ! "g" ((long)(e)) \ ! : "d1", "d2", "d3", "d4", "d5"); \ ! if (__res >= 0) \ ! return (type) __res; \ ! errno = -__res; \ ! return -1; \ } #endif /* _LINUX_UNISTD_H */ diff -cr --new-file linux-0.07pl4/include/linux/user.h linux-0.08/include/linux/user.h *** linux-0.07pl4/include/linux/user.h Fri Dec 10 18:42:25 1993 --- linux-0.08/include/linux/user.h Thu Mar 10 17:22:16 1994 *************** *** 46,51 **** --- 46,56 ---- long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ }; + struct user_m68kfp_struct { + unsigned long fpcntl[3]; /* fp control regs */ + unsigned long fpregs[24]; /* fp0-fp7 registers */ + }; + /* When the kernel dumps core, it starts by dumping the user struct - this will be used by gdb to figure out where the data and stack segments are within the file, and what virtual addresses to use. */ *************** *** 56,62 **** --- 61,71 ---- /* ptrace does not yet supply these. Someday.... */ int u_fpvalid; /* True if math co-processor being used. */ /* for this mess. Not yet used. */ + #if defined(__i386__) struct user_i387_struct i387; /* Math Co-processor registers. */ + #else if defined(__mc68000__) + struct user_m68kfp_struct m68kfp; /* Math Co-processor registers. */ + #endif /* The rest of this junk is to help gdb figure out what goes where */ unsigned long int u_tsize; /* Text segment size (pages). */ unsigned long int u_dsize; /* Data segment size (pages). */ *************** *** 70,79 **** --- 79,94 ---- int reserved; /* No longer used */ struct pt_regs * u_ar0; /* Used by gdb to help find the values for */ /* the registers. */ + #if defined(__i386__) struct user_i387_struct* u_fpstate; /* Math Co-processor pointer. */ + #elif defined(__mc68000__) + struct user_m68kfp_struct* u_fpstate; /* Math Co-processor pointer. */ + #endif unsigned long magic; /* To uniquely identify a core file */ char u_comm[32]; /* User command that was responsible */ + #if defined(__i386__) int u_debugreg[8]; + #endif }; #define NBPG 4096 #define UPAGES 1 diff -cr --new-file linux-0.07pl4/init/main.c linux-0.08/init/main.c *** linux-0.07pl4/init/main.c Sat Mar 19 15:12:23 1994 --- linux-0.08/init/main.c Sun Mar 27 08:02:36 1994 *************** *** 180,186 **** #ifdef CONFIG_INET { "ether=", eth_setup }, #endif ! #ifdef CONFIG_BLK_DEV_HD { "hd=", hd_setup }, #endif #ifdef CONFIG_BUSMOUSE --- 180,186 ---- #ifdef CONFIG_INET { "ether=", eth_setup }, #endif ! #if defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_AMIGA_IDE) { "hd=", hd_setup }, #endif #ifdef CONFIG_BUSMOUSE *************** *** 347,352 **** --- 347,356 ---- } #endif + #ifdef CONFIG_AMIGA + void ami_serial_print (const char *); + #endif + asmlinkage void start_kernel(void) { /* *************** *** 381,386 **** --- 385,391 ---- ramdisk_size = boot_info.ramdisk_size; strcpy(command_line,boot_info.command_line); #endif + paging_init (&memory_start, &memory_end); config_init(); *************** *** 415,423 **** buffer_init(); time_init(); floppy_init(); - #if 0 sock_init(); - #endif #ifdef CONFIG_SYSVIPC ipc_init(); #endif --- 420,426 ---- *************** *** 530,536 **** (void) open("/dev/tty1",O_RDWR,0); (void) dup(0); (void) dup(0); - printf ("execing sh.. "); i = execve("/bin/sh",argv,envp); i = errno; printf ("execve returned %d\n", i); --- 533,538 ---- diff -cr --new-file linux-0.07pl4/kernel/ptrace.c linux-0.08/kernel/ptrace.c *** linux-0.07pl4/kernel/ptrace.c Sat Dec 11 08:02:05 1993 --- linux-0.08/kernel/ptrace.c Sun Mar 27 09:38:17 1994 *************** *** 20,44 **** #include #include - #if 0 /* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. */ - /* determines which flags the user has access to. */ - /* 1 = access 0 = no access */ - #define FLAG_MASK 0x00044dd5 - - /* set's the trap flag. */ - #define TRAP_FLAG 0x100 - - /* - * this is the number to subtract from the top of the stack. To find - * the local frame. - */ - #define MAGICNUMBER 68 - /* change a pid into a task struct. */ static inline struct task_struct * get_task(int pid) { --- 20,30 ---- *************** *** 57,63 **** * this routine assumes that all the priviledged stacks are in our * data space. */ ! static inline int get_stack_long(struct task_struct *task, int offset) { unsigned char *stack; --- 43,49 ---- * this routine assumes that all the priviledged stacks are in our * data space. */ ! int ptrace_get_stack_long(struct task_struct *task, int offset) { unsigned char *stack; *************** *** 72,249 **** * this routine assumes that all the priviledged stacks are in our * data space. */ ! static inline int put_stack_long(struct task_struct *task, int offset, ! unsigned long data) { unsigned char * stack; ! stack = (unsigned char *) task->tss.esp0; stack += offset; *(unsigned long *) stack = data; return 0; } - /* - * This routine gets a long from any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - * - * NOTE2! This uses "tsk->tss.cr3" even though we know it's currently always - * zero. This routine shouldn't have to change when we make a better mm. - */ - static unsigned long get_long(struct task_struct * tsk, - unsigned long addr) - { - unsigned long page; - - repeat: - page = *PAGE_DIR_OFFSET(tsk->tss.cr3,addr); - if (page & PAGE_PRESENT) { - page &= PAGE_MASK; - page += PAGE_PTR(addr); - page = *((unsigned long *) page); - } - if (!(page & PAGE_PRESENT)) { - do_no_page(0,addr,tsk,0); - goto repeat; - } - page &= PAGE_MASK; - page += addr & ~PAGE_MASK; - return *(unsigned long *) page; - } - - /* - * This routine puts a long into any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - * - * Now keeps R/W state of page so that a text page stays readonly - * even if a debugger scribbles breakpoints into it. -M.U- - */ - static void put_long(struct task_struct * tsk, unsigned long addr, - unsigned long data) - { - unsigned long page, pte = 0; - int readonly = 0; - - repeat: - page = *PAGE_DIR_OFFSET(tsk->tss.cr3,addr); - if (page & PAGE_PRESENT) { - page &= PAGE_MASK; - page += PAGE_PTR(addr); - pte = page; - page = *((unsigned long *) page); - } - if (!(page & PAGE_PRESENT)) { - do_no_page(0 /* PAGE_RW */ ,addr,tsk,0); - goto repeat; - } - if (!PAGE_IS_RW(page)) { - if(!(page & PAGE_COW)) - readonly = 1; - do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk,0); - goto repeat; - } - /* we're bypassing pagetables, so we have to set the dirty bit ourselves */ - *(unsigned long *) pte |= (PAGE_DIRTY|PAGE_COW); - page &= PAGE_MASK; - page += addr & ~PAGE_MASK; - *(unsigned long *) page = data; - if(readonly) { - *(unsigned long *) pte &=~ (PAGE_RW|PAGE_COW); - invalidate(); - } - } - - /* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls get_long() to read a long. - */ - static int read_long(struct task_struct * tsk, unsigned long addr, - unsigned long * result) - { - unsigned long low,high; - - if (addr > TASK_SIZE-sizeof(long)) - return -EIO; - if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { - low = get_long(tsk,addr & ~(sizeof(long)-1)); - high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1)); - switch (addr & (sizeof(long)-1)) { - case 1: - low >>= 8; - low |= high << 24; - break; - case 2: - low >>= 16; - low |= high << 16; - break; - case 3: - low >>= 24; - low |= high << 8; - break; - } - *result = low; - } else - *result = get_long(tsk,addr); - return 0; - } - - /* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls put_long() to write a long. - */ - static int write_long(struct task_struct * tsk, unsigned long addr, - unsigned long data) - { - unsigned long low,high; - - if (addr > TASK_SIZE-sizeof(long)) - return -EIO; - if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { - low = get_long(tsk,addr & ~(sizeof(long)-1)); - high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1)); - switch (addr & (sizeof(long)-1)) { - case 0: /* shouldn't happen, but safety first */ - low = data; - break; - case 1: - low &= 0x000000ff; - low |= data << 8; - high &= ~0xff; - high |= data >> 24; - break; - case 2: - low &= 0x0000ffff; - low |= data << 16; - high &= ~0xffff; - high |= data >> 16; - break; - case 3: - low &= 0x00ffffff; - low |= data << 24; - high &= ~0xffffff; - high |= data >> 8; - break; - } - put_long(tsk,addr & ~(sizeof(long)-1),low); - put_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1),high); - } else - put_long(tsk,addr,data); - return 0; - } - #endif - asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { - #if 0 struct task_struct *child; - struct user * dummy; - int i; - - dummy = NULL; if (request == PTRACE_TRACEME) { /* are we already being traced? */ --- 58,77 ---- * this routine assumes that all the priviledged stacks are in our * data space. */ ! int ptrace_put_stack_long(struct task_struct *task, int offset, ! unsigned long data) { unsigned char * stack; ! stack = (unsigned char *) task->tss.esp0; stack += offset; *(unsigned long *) stack = data; return 0; } asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; if (request == PTRACE_TRACEME) { /* are we already being traced? */ *************** *** 291,297 **** unsigned long tmp; int res; ! res = read_long(child, addr, &tmp); if (res < 0) return res; res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); --- 119,125 ---- unsigned long tmp; int res; ! res = ptrace_read_long(child, addr, &tmp); if (res < 0) return res; res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); *************** *** 301,402 **** } /* read the word at location addr in the USER area. */ ! case PTRACE_PEEKUSR: { ! unsigned long tmp; ! int res; ! ! if ((addr & 3) || addr < 0 || ! addr > sizeof(struct user) - 3) ! return -EIO; ! ! res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); ! if (res) ! return res; ! tmp = 0; /* Default return condition */ ! if(addr < 17*sizeof(long)) { ! addr = addr >> 2; /* temporary hack. */ ! ! tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER); ! if (addr == DS || addr == ES || ! addr == FS || addr == GS || ! addr == CS || addr == SS) ! tmp &= 0xffff; ! }; ! if(addr >= (long) &dummy->u_debugreg[0] && ! addr <= (long) &dummy->u_debugreg[7]){ ! addr -= (long) &dummy->u_debugreg[0]; ! addr = addr >> 2; ! tmp = child->debugreg[addr]; ! }; ! put_fs_long(tmp,(unsigned long *) data); ! return 0; ! } /* when I and D space are seperate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ! return write_long(child,addr,data); case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ! if ((addr & 3) || addr < 0 || ! addr > sizeof(struct user) - 3) ! return -EIO; ! ! addr = addr >> 2; /* temproary hack. */ ! ! if (addr == ORIG_EAX) ! return -EIO; ! if (addr == DS || addr == ES || ! addr == FS || addr == GS || ! addr == CS || addr == SS) { ! data &= 0xffff; ! if (data && (data & 3) != 3) ! return -EIO; ! } ! if (addr == EFL) { /* flags. */ ! data &= FLAG_MASK; ! data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER) & ~FLAG_MASK; ! } ! /* Do not allow the user to set the debug register for kernel ! address space */ ! if(addr < 17){ ! if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data)) ! return -EIO; ! return 0; ! }; ! ! /* We need to be very careful here. We implicitly ! want to modify a portion of the task_struct, and we ! have to be selective about what portions we allow someone ! to modify. */ ! ! addr = addr << 2; /* Convert back again */ ! if(addr >= (long) &dummy->u_debugreg[0] && ! addr <= (long) &dummy->u_debugreg[7]){ ! ! if(addr == (long) &dummy->u_debugreg[4]) return -EIO; ! if(addr == (long) &dummy->u_debugreg[5]) return -EIO; ! if(addr < (long) &dummy->u_debugreg[4] && ! ((unsigned long) data) >= 0xbffffffd) return -EIO; ! ! if(addr == (long) &dummy->u_debugreg[7]) { ! data &= ~DR_CONTROL_RESERVED; ! for(i=0; i<4; i++) ! if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1) ! return -EIO; ! }; ! ! addr -= (long) &dummy->u_debugreg; ! addr = addr >> 2; ! child->debugreg[addr] = data; ! return 0; ! }; ! return -EIO; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ - long tmp; - if ((unsigned long) data > NSIG) return -EIO; if (request == PTRACE_SYSCALL) --- 129,147 ---- } /* read the word at location addr in the USER area. */ ! case PTRACE_PEEKUSR: ! return ptrace_peekusr (child, addr, data); /* when I and D space are seperate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ! return ptrace_write_long(child,addr,data); case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ! return ptrace_pokeusr (child, addr, data); case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ if ((unsigned long) data > NSIG) return -EIO; if (request == PTRACE_SYSCALL) *************** *** 406,413 **** child->exit_code = data; child->state = TASK_RUNNING; /* make sure the single step bit is not set. */ ! tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; ! put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); return 0; } --- 151,157 ---- child->exit_code = data; child->state = TASK_RUNNING; /* make sure the single step bit is not set. */ ! ptrace_clrsingle(child); return 0; } *************** *** 417,440 **** * exit. */ case PTRACE_KILL: { - long tmp; - child->state = TASK_RUNNING; child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ ! tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; ! put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); return 0; } case PTRACE_SINGLESTEP: { /* set the trap flag. */ - long tmp; - if ((unsigned long) data > NSIG) return -EIO; child->flags &= ~PF_TRACESYS; ! tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG; ! put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); child->state = TASK_RUNNING; child->exit_code = data; /* give it a chance to run. */ --- 161,178 ---- * exit. */ case PTRACE_KILL: { child->state = TASK_RUNNING; child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ ! ptrace_clrsingle (child); return 0; } case PTRACE_SINGLESTEP: { /* set the trap flag. */ if ((unsigned long) data > NSIG) return -EIO; child->flags &= ~PF_TRACESYS; ! ptrace_setsingle (child); child->state = TASK_RUNNING; child->exit_code = data; /* give it a chance to run. */ *************** *** 442,449 **** } case PTRACE_DETACH: { /* detach a process that was attached. */ - long tmp; - if ((unsigned long) data > NSIG) return -EIO; child->flags &= ~(PF_PTRACED|PF_TRACESYS); --- 180,185 ---- *************** *** 453,467 **** child->p_pptr = child->p_opptr; SET_LINKS(child); /* make sure the single step bit is not set. */ ! tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; ! put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); return 0; } default: return -EIO; } - #endif return -EIO; } --- 189,201 ---- child->p_pptr = child->p_opptr; SET_LINKS(child); /* make sure the single step bit is not set. */ ! ptrace_clrsingle(child); return 0; } default: return -EIO; } return -EIO; } diff -cr --new-file linux-0.07pl4/kernel/sched.c linux-0.08/kernel/sched.c *** linux-0.07pl4/kernel/sched.c Thu Jan 13 17:09:37 1994 --- linux-0.08/kernel/sched.c Wed Mar 9 12:08:15 1994 *************** *** 71,77 **** int hard_math = 0; /* set by boot/head.S */ int x86 = 0; /* set by boot/head.S to 3 or 4 */ int ignore_irq13 = 0; /* set if exception 16 works */ ! int wp_works_ok = 0; /* set if paging hardware honours WP */ extern int _setitimer(int, struct itimerval *, struct itimerval *); unsigned long * prof_buffer = NULL; --- 71,77 ---- int hard_math = 0; /* set by boot/head.S */ int x86 = 0; /* set by boot/head.S to 3 or 4 */ int ignore_irq13 = 0; /* set if exception 16 works */ ! int wp_works_ok = 0; /* set if paging hardware honours WP */ extern int _setitimer(int, struct itimerval *, struct itimerval *); unsigned long * prof_buffer = NULL; *************** *** 127,133 **** sys_select, sys_symlink, sys_lstat, sys_readlink, sys_uselib, sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap, sys_truncate, sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_setpriority, ! sys_profil, sys_statfs, sys_fstatfs, sys_unimp /*sys_ioperm*/, sys_unimp /*sys_socketcall*/, sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat, sys_newfstat, sys_uname, sys_unimp /*sys_iopl*/, sys_vhangup, sys_idle, sys_unimp /*sys_vm86*/, sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn, --- 127,133 ---- sys_select, sys_symlink, sys_lstat, sys_readlink, sys_uselib, sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap, sys_truncate, sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_setpriority, ! sys_profil, sys_statfs, sys_fstatfs, sys_unimp /*sys_ioperm*/, sys_socketcall, sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat, sys_newfstat, sys_uname, sys_unimp /*sys_iopl*/, sys_vhangup, sys_idle, sys_unimp /*sys_vm86*/, sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn, *************** *** 291,297 **** } } if (!tmp->next) { ! printk("wait_queue is bad (eip = %08lx)\n",((unsigned long *) &q)[-1]); printk(" q = %p\n",q); printk(" *q = %p\n",*q); printk(" tmp = %p\n",tmp); --- 291,298 ---- } } if (!tmp->next) { ! printk("wait_queue is bad (eip = %p)\n", ! __builtin_return_address(1)); printk(" q = %p\n",q); printk(" *q = %p\n",*q); printk(" tmp = %p\n",tmp); *************** *** 317,323 **** } } if (!tmp->next) { ! printk("wait_queue is bad (eip = %08lx)\n",((unsigned long *) q)[-1]); printk(" q = %p\n",q); printk(" *q = %p\n",*q); printk(" tmp = %p\n",tmp); --- 318,325 ---- } } if (!tmp->next) { ! printk("wait_queue is bad (eip = %p)\n", ! __builtin_return_address(1)); printk(" q = %p\n",q); printk(" *q = %p\n",*q); printk(" tmp = %p\n",tmp); diff -cr --new-file linux-0.07pl4/lib/open.c linux-0.08/lib/open.c *** linux-0.07pl4/lib/open.c Sun Oct 10 09:07:40 1993 --- linux-0.08/lib/open.c Mon Mar 14 16:38:35 1994 *************** *** 27,33 **** "movel %3,d3\n\t" "movel %0,d0\n\t" "trap #0\n\t" ! "bcc 1f\n\t" "movel d0,_errno\n\t" "moveq #-1,d0\n\t" "1:" --- 27,35 ---- "movel %3,d3\n\t" "movel %0,d0\n\t" "trap #0\n\t" ! "tstl d0\n\t" ! "bpl 1f\n\t" ! "negl d0\n\t" "movel d0,_errno\n\t" "moveq #-1,d0\n\t" "1:" diff -cr --new-file linux-0.07pl4/m68k/Makefile linux-0.08/m68k/Makefile *** linux-0.07pl4/m68k/Makefile Mon Dec 6 16:02:40 1993 --- linux-0.08/m68k/Makefile Tue Mar 22 15:01:47 1994 *************** *** 8,22 **** include ../MakeVars ! OBJS = machasm.o sys_call.o traps.o ints.o signal.o # machdep.o math.o arch.o: $(OBJS) $(LD) -r -o arch.o $(OBJS) machasm.o sys_call.o: assyms.h ! assyms.h: gensyms ! ./gensyms > $@ gensyms: gensyms.o $(HOSTCC) $(HOSTFLAGS) -o $@ $< --- 8,28 ---- include ../MakeVars ! OBJS = machasm.o sys_call.o traps.o ints.o signal.o ptrace.o arch.o: $(OBJS) $(LD) -r -o arch.o $(OBJS) machasm.o sys_call.o: assyms.h ! assyms.h: ../include/linux/sched.h ../include/linux/mm.h \ ! ../include/linux/param.h ../include/linux/signal.h \ ! ../include/linux/bootinfo.h ../include/linux/amigatypes.h ! @echo "You need to remake assyms.h (make do_assyms.h)" ! exit 1 ! ! do_assyms.h: gensyms ! ./gensyms > assyms.h gensyms: gensyms.o $(HOSTCC) $(HOSTFLAGS) -o $@ $< *************** *** 25,31 **** $(HOSTCC) $(HOSTFLAGS) -c $< -o $@ clean: ! $(RM) $(RMFLAGS) *.o assyms.h gensyms dep: $(CPP) -M $(INCFLAGS) *.c > .depend --- 31,37 ---- $(HOSTCC) $(HOSTFLAGS) -c $< -o $@ clean: ! $(RM) $(RMFLAGS) *.o gensyms dep: $(CPP) -M $(INCFLAGS) *.c > .depend diff -cr --new-file linux-0.07pl4/m68k/gensyms.c linux-0.08/m68k/gensyms.c *** linux-0.07pl4/m68k/gensyms.c Sun Feb 13 21:56:23 1994 --- linux-0.08/m68k/gensyms.c Tue Mar 1 10:28:16 1994 *************** *** 25,31 **** printf ("LTSS_FPCNTL = %d\n", offsetof (struct m68k_struct, fpcntl)); printf ("LTSS_FPSTATE = %d\n", offsetof (struct m68k_struct, fpstate)); ! printf ("LKSTART_ADDR = 0x%x\n", KSTART_ADDR); printf ("LFLUSH_I_AND_D = 0x%x\n", FLUSH_I_AND_D); printf ("LPAGE_PRESENT = 0x%x\n", PAGE_PRESENT); printf ("LPAGE_CACHE040 = 0x%x\n", PAGE_CACHE040); --- 25,31 ---- printf ("LTSS_FPCNTL = %d\n", offsetof (struct m68k_struct, fpcntl)); printf ("LTSS_FPSTATE = %d\n", offsetof (struct m68k_struct, fpstate)); ! printf ("LKSTART_ADDR = 0x%lx\n", KSTART_ADDR); printf ("LFLUSH_I_AND_D = 0x%x\n", FLUSH_I_AND_D); printf ("LPAGE_PRESENT = 0x%x\n", PAGE_PRESENT); printf ("LPAGE_CACHE040 = 0x%x\n", PAGE_CACHE040); diff -cr --new-file linux-0.07pl4/m68k/head.S linux-0.08/m68k/head.S *** linux-0.07pl4/m68k/head.S Mon Feb 14 09:38:52 1994 --- linux-0.08/m68k/head.S Tue Mar 22 17:36:16 1994 *************** *** 12,18 **** ** */ ! #include "assyms.h" /* * Linux startup code. --- 12,18 ---- ** */ ! /*#include "assyms.h"*/ /* * Linux startup code. *************** *** 35,45 **** * for most of this file. */ - LBIT040 = 2 - .text .globl _start, _krt, _kpt, _availmem .even _start: /* --- 35,96 ---- * for most of this file. */ .text .globl _start, _krt, _kpt, _availmem + PAGESIZE = 4096 + KSTART_ADDR = 0xC0000000 + BI_CPU = 4 + BI_MACH = 0 + BI_AMIGA_ECLK = 1234 + MACH_AMIGA = 1 + LF = 10 + CR = 13 + BIT040 = 2 + + /* Some definitions for the special registers of the 68040. + * (MMU, caches) + */ + + /* Translation control register */ + TC_ENABLE = 0x8000 + TC_PAGE8K = 0x4000 + TC_PAGE4K = 0x0000 + + /* Transparent translation registers */ + TTR_ENABLE = 0x8000 + + /* Some bits used in the page and table descriptors as well as in the + * special registers. + */ + + CM_CACHE_WT = 0x0000 /* cacheable, write-through */ + CM_CACHE_CB = 0x0020 /* cacheable, copyback */ + CM_NONCACHE_SER = 0x0040 /* noncacheable, serialized */ + CM_NONCACHE = 0x0060 /* noncacheable */ + + MODIFIED = 0x0010 + WRITE_PROT = 0x0004 + USED = 0x0008 + GLOBAL = 0x0400 + SV_ONLY = 0x0080 + PAGEDESC = 0x0001 + TABLEDESC = 0x0002 + INVALID = 0x0000 + + /* Cache enabling */ + I_ENABLE = 0x00008000 + D_ENABLE = 0x80000000 + + /* Miscellaneous definitions */ + PAGE_MASK = (~(PAGESIZE-1)) + + ROOT_TABLE_SIZE = 128 + PTR_TABLE_SIZE = 128 + PAGE_TABLE_SIZE = 64 + ROOT_INDEX_SHIFT = 25 + PAGE_INDEX_SHIFT = 12 + .even _start: /* *************** *** 54,62 **** */ bsr Lserial_init ! moveq #13,d7 bsr Lserial_putc ! moveq #10,d7 bsr Lserial_putc moveq #'A',d7 bsr Lserial_putc --- 105,113 ---- */ bsr Lserial_init ! moveq #CR,d7 bsr Lserial_putc ! moveq #LF,d7 bsr Lserial_putc moveq #'A',d7 bsr Lserial_putc *************** *** 65,71 **** * Record the CPU type. */ lea pc@(_boot_info),a0 ! movel a0@(LBI_CPU),d6 /* * Get address at end of kernel code/data/bss and --- 116,122 ---- * Record the CPU type. */ lea pc@(_boot_info),a0 ! movel a0@(BI_CPU),d6 /* * Get address at end of kernel code/data/bss and *************** *** 73,80 **** */ lea pc@(_end),a0 movel a0,d0 ! addl #0x00000fff,d0 ! andl #0xfffff000,d0 movel d0,a6 moveq #'B',d7 --- 124,131 ---- */ lea pc@(_end),a0 movel a0,d0 ! addl #(PAGESIZE-1),d0 ! andl #PAGE_MASK,d0 movel d0,a6 moveq #'B',d7 *************** *** 84,95 **** * allocate the kernel root table and initialize it. */ movel a6,a5 ! addw #LPAGE_SIZE,a6 /* clear the root table */ movel a5,a0 moveq #0,d0 ! moveq #127,d1 1: movel d0,a0@+ dbra d1,1b --- 135,146 ---- * allocate the kernel root table and initialize it. */ movel a6,a5 ! addw #PAGESIZE,a6 /* clear the root table */ movel a5,a0 moveq #0,d0 ! moveq #(ROOT_TABLE_SIZE-1),d1 1: movel d0,a0@+ dbra d1,1b *************** *** 99,107 **** * the root table. */ lea a5@(512),a0 ! addql #2,a0 ! movel #LKSTART_ADDR,d0 ! moveq #25,d1 lsrl d1,d0 movel a0,a5@(d0:l:4) --- 150,158 ---- * the root table. */ lea a5@(512),a0 ! addql #TABLEDESC,a0 ! movel #KSTART_ADDR,d0 ! moveq #ROOT_INDEX_SHIFT,d1 lsrl d1,d0 movel a0,a5@(d0:l:4) *************** *** 127,133 **** /* clear the kernel pointer table */ lea a5@(512),a0 moveq #0,d0 ! moveq #127,d1 1: movel d0,a0@+ dbra d1,1b --- 178,184 ---- /* clear the kernel pointer table */ lea a5@(512),a0 moveq #0,d0 ! moveq #(PTR_TABLE_SIZE-1),d1 1: movel d0,a0@+ dbra d1,1b *************** *** 139,159 **** * the address of the first page table (68040) * or the base address of physical memory (68030). */ ! btst #LBIT040,d6 bnes 1f /* 680[23]0 */ lea pc@(_start),a1 /* base address */ ! addql #1,a1 /* descriptor type */ movel #0x40000,d2 /* increment */ bras 2f 1: /* 68040 */ movel a6,a1 /* base address */ ! addw #LPAGE_SIZE,a6 /* allocate the page table */ lea pc@(_kpt),a3 movel a1,a3@ /* save address of page table */ ! addql #2,a1 /* descriptor type */ movel #256,d2 /* increment */ 2: movel a1,a0@+ --- 190,210 ---- * the address of the first page table (68040) * or the base address of physical memory (68030). */ ! btst #BIT040,d6 bnes 1f /* 680[23]0 */ lea pc@(_start),a1 /* base address */ ! addql #PAGEDESC,a1 /* descriptor type */ movel #0x40000,d2 /* increment */ bras 2f 1: /* 68040 */ movel a6,a1 /* base address */ ! addw #PAGESIZE,a6 /* allocate the page table */ lea pc@(_kpt),a3 movel a1,a3@ /* save address of page table */ ! addql #TABLEDESC,a1 /* descriptor type */ movel #256,d2 /* increment */ 2: movel a1,a0@+ *************** *** 171,177 **** * in the descriptors also. */ ! btst #LBIT040,d6 beqs Lnot040 moveq #'F',d7 --- 222,228 ---- * in the descriptors also. */ ! btst #BIT040,d6 beqs Lnot040 moveq #'F',d7 *************** *** 179,187 **** movel pc@(_kpt),a0 lea pc@(_start),a1 ! addw #0x421,a1 ! movew #1023,d1 ! movel #LPAGE_SIZE,d2 1: movel a1,a0@+ addl d2,a1 --- 230,238 ---- movel pc@(_kpt),a0 lea pc@(_start),a1 ! addw #(GLOBAL+CM_CACHE_CB+PAGEDESC),a1 ! movew #((PAGESIZE/4)-1),d1 ! movel #PAGESIZE,d2 1: movel a1,a0@+ addl d2,a1 *************** *** 197,203 **** lea pc@(_start),a0 movel a5,d0 /* address of root table */ subl a0,d0 /* determine offset of root table page */ ! moveq #12,d1 /* determine offset into kernel page table */ lsrl d1,d0 /* i.e. page number of the address offset */ movel pc@(_kpt),a0 lea a0@(d0:l:4),a0 --- 248,254 ---- lea pc@(_start),a0 movel a5,d0 /* address of root table */ subl a0,d0 /* determine offset of root table page */ ! moveq #PAGE_INDEX_SHIFT,d1 /* determine offset into kernel page table */ lsrl d1,d0 /* i.e. page number of the address offset */ movel pc@(_kpt),a0 lea a0@(d0:l:4),a0 *************** *** 206,223 **** bset #6,d1 movel d1,a0@+ ! movel a0@,d1 /* do the same for the kernel page table */ bclr #5,d1 /* the kernel page table resides in the */ bset #6,d1 /* page after the page containing the */ ! movel d1,a0@ /* root table */ Lnot040: /* * Do any machine specific page table initializations. */ lea pc@(_boot_info),a0 ! moveq #LMACH_AMIGA,d0 ! cmpl a0@(LBI_MACH),d0 bne Lnotami /* --- 257,274 ---- bset #6,d1 movel d1,a0@+ ! movel a0@,d1 /* do the same for the kernel page table */ bclr #5,d1 /* the kernel page table resides in the */ bset #6,d1 /* page after the page containing the */ ! movel d1,a0@ /* root table */ Lnot040: /* * Do any machine specific page table initializations. */ lea pc@(_boot_info),a0 ! moveq #MACH_AMIGA,d0 ! cmpl a0@(BI_MACH),d0 bne Lnotami /* *************** *** 230,236 **** moveq #'H',d7 bsr Lserial_putc ! btst #LBIT040,d6 bnes Lspami68040 /* --- 281,287 ---- moveq #'H',d7 bsr Lserial_putc ! btst #BIT040,d6 bnes Lspami68040 /* *************** *** 260,297 **** /* clear the amiga pointer table */ lea a5@(1024),a0 moveq #0,d0 ! moveq #127,d1 1: movel d0,a0@+ dbra d1,1b /* allocate 4 page tables */ movel a6,a3 ! addw #LPAGE_SIZE*4,a6 /* initialize the pointer table */ lea a5@(1024),a0 movel a3,a1 ! addql #2,a1 /* base descriptor */ movel #256,d2 /* increment */ ! moveq #63,d1 1: movel a1,a0@+ addl d2,a1 dbra d1,1b /* ensure that the root table points to the pointer table */ ! lea a5@(1024),a0 ! addql #2,a0 ! movel a0,a5@ /* * initialize the page tables * descriptor bits include noncachable/serialized and global bits. */ movel a3,a0 ! movew #0x441,a1 ! movel #LPAGE_SIZE,d2 ! movew #1024*4,d1 1: movel a1,a0@+ addl d2,a1 --- 311,348 ---- /* clear the amiga pointer table */ lea a5@(1024),a0 moveq #0,d0 ! moveq #(PTR_TABLE_SIZE-1),d1 1: movel d0,a0@+ dbra d1,1b /* allocate 4 page tables */ movel a6,a3 ! addw #(4*PAGESIZE),a6 /* initialize the pointer table */ lea a5@(1024),a0 movel a3,a1 ! addql #TABLEDESC,a1 /* base descriptor */ movel #256,d2 /* increment */ ! moveq #(PAGE_TABLE_SIZE-1),d1 1: movel a1,a0@+ addl d2,a1 dbra d1,1b /* ensure that the root table points to the pointer table */ ! lea a5@(1024),a0 ! addql #TABLEDESC,a0 ! movel a0,a5@ /* * initialize the page tables * descriptor bits include noncachable/serialized and global bits. */ movel a3,a0 ! movew #(GLOBAL+CM_NONCACHE_SER+PAGEDESC),a1 ! movel #PAGESIZE,d2 ! movew #(4*PAGESIZE-1),d1 1: movel a1,a0@+ addl d2,a1 *************** *** 335,347 **** clrl d5 /* indicate that no cleanup is required */ lea pc@(_boot_info),a0 ! cmpl #LMACH_AMIGA,a0@(LBI_MACH) bnes Lnophys /* other machines will probably have * to put in code and jump to it here */ /* 68040? */ ! btst #LBIT040,d6 beqs 1f movel #0x01000000,d0 /* limit for 68040 is 16M (16M mapped for --- 386,398 ---- clrl d5 /* indicate that no cleanup is required */ lea pc@(_boot_info),a0 ! cmpl #MACH_AMIGA,a0@(BI_MACH) bnes Lnophys /* other machines will probably have * to put in code and jump to it here */ /* 68040? */ ! btst #BIT040,d6 beqs 1f movel #0x01000000,d0 /* limit for 68040 is 16M (16M mapped for *************** *** 362,368 **** moveq #1,d5 /* 68040? */ ! btst #LBIT040,d6 bnes 1f /* --- 413,419 ---- moveq #1,d5 /* 68040? */ ! btst #BIT040,d6 bnes 1f /* *************** *** 398,404 **** * Setup Supervisor Root Pointer register to point to page directory, * setup translation register contents and enable translation. */ ! btst #LBIT040,d6 bnes Lmmu68040 moveq #'K',d7 --- 449,455 ---- * Setup Supervisor Root Pointer register to point to page directory, * setup translation register contents and enable translation. */ ! btst #BIT040,d6 bnes Lmmu68040 moveq #'K',d7 *************** *** 426,432 **** .word 0xf518 /* pflusha */ .long 0x4e7bd807 /* movec a5,srp */ .long 0x4e7bd806 /* movec a5,urp */ ! movel #0x8000,d0 /* enable translation, 4096 byte pages */ .long 0x4e7b0003 /* movec d0,tc */ 1: --- 477,483 ---- .word 0xf518 /* pflusha */ .long 0x4e7bd807 /* movec a5,srp */ .long 0x4e7bd806 /* movec a5,urp */ ! movel #(TC_ENABLE+TC_PAGE4K),d0 .long 0x4e7b0003 /* movec d0,tc */ 1: *************** *** 438,444 **** moveq #'M',d7 bsr Lserial_putc ! movel #LKSTART_ADDR,d0 lea pc@(_start),a0 movel _kpt,d1 --- 489,495 ---- moveq #'M',d7 bsr Lserial_putc ! movel #KSTART_ADDR,d0 lea pc@(_start),a0 movel _kpt,d1 *************** *** 459,482 **** addl d0,a5 movel a5,_krt - btst #LBIT040,d6 - beqs 1f - lea Lvirt,a0 - moveq #2,d0 - movec d0,dfc - .word 0xf568 /* ptestr a0@ */ - .long 0x4e7a0805 /* movec mmusr,d0 */ - moveq #32,d7 - bsr Lserial_putc - movel d0,d7 - bsr Lserial_putnum - moveq #32,d7 - bsr Lserial_putc - - 1: /* * Record starting address and jump into the virtual address space. */ lea pc@(_start),a0 jmp Lvirt --- 510,527 ---- addl d0,a5 movel a5,_krt /* * Record starting address and jump into the virtual address space. */ + + /* DEBUG : REMOVE ME + * Install a temporary access-fault handler + */ + moveq #0,d0 + movec d0,vbr + lea pc@(tmp_fault_handler),a0 + move.l a0,8 /* Access fault vector */ + lea pc@(_start),a0 jmp Lvirt *************** *** 491,497 **** tstl d5 beqs Lnoclean ! btst #LBIT040,d6 bnes Loff040 /* clean up physical identity mapping for 68020/68030 */ --- 536,542 ---- tstl d5 beqs Lnoclean ! btst #BIT040,d6 bnes Loff040 /* clean up physical identity mapping for 68020/68030 */ *************** *** 518,542 **** /* * Enable caches */ ! btst #LBIT040,d6 bnes Lcache68040 movel #0x00000919,d0 ! movec d0,cacr bras 1f Lcache68040: .word 0xf4d8 /* CINVA I/D */ movel #0x80008000,d0 ! /* don't enable cache on 68040 until MMU stuff works */ ! /* movec d0,cacr*/ 1: /* * Setup initial stack pointer */ ! leal _user_stack+LPAGE_SIZE,sp /* jump to memory management initialization */ --- 563,587 ---- /* * Enable caches */ ! btst #BIT040,d6 bnes Lcache68040 movel #0x00000919,d0 ! movec d0,cacr bras 1f Lcache68040: .word 0xf4d8 /* CINVA I/D */ movel #0x80008000,d0 ! /* MMU stuff works in copyback mode now, so enable the cache */ ! movec d0,cacr 1: /* * Setup initial stack pointer */ ! leal _user_stack+PAGESIZE,sp /* jump to memory management initialization */ *************** *** 547,552 **** --- 592,628 ---- bsr _start_kernel + tmp_fault_handler: + lea pc@(tfh_1st_str),a0 + bsr Lserial_puts + move.l sp@(2),d7 /* PC */ + bsr Lserial_putnum + move.w sp@(0xa),d7 + swap d7 + move.w sp@(0x6),d7 + bsr Lserial_putnum + lea pc@(tfh_2nd_str),a0 + bsr Lserial_puts + move.l sp@(0x10),d7 /* Fault address */ + bsr Lserial_putnum + moveq #CR,d7 + bsr Lserial_putc + moveq #LF,d7 + bsr Lserial_putc + 1: bra 1b + + tfh_1st_str: + .byte LF + .byte CR + .ascii "Access fault occurred. PC = " + .byte 0 + + tfh_2nd_str: + .byte LF + .byte CR + .ascii "FaultAddress = " + .byte 0 + /* * Serial port output support. */ *************** *** 563,575 **** /* * Initialize serial port hardware for 9600/8/1 */ Lserial_init: lea pc@(_boot_info),a0 ! cmpil #LMACH_AMIGA,a0@(LBI_MACH) bnes 1f bclr #LSERIAL_DTR,LSERIAL_CNTRL movew #LNTSC_PERIOD,LSERPER ! cmpl #LNTSC_ECLOCK,a0@(LBI_AMIGA_ECLK) beqs 1f movew #LPAL_PERIOD,LSERPER 1: rts --- 639,652 ---- /* * Initialize serial port hardware for 9600/8/1 */ + .even Lserial_init: lea pc@(_boot_info),a0 ! cmpil #MACH_AMIGA,a0@(BI_MACH) bnes 1f bclr #LSERIAL_DTR,LSERIAL_CNTRL movew #LNTSC_PERIOD,LSERPER ! cmpl #LNTSC_ECLOCK,a0@(BI_AMIGA_ECLK) beqs 1f movew #LPAL_PERIOD,LSERPER 1: rts *************** *** 581,587 **** Lserial_putc: movel a0,sp@- lea pc@(_boot_info),a0 ! cmpil #LMACH_AMIGA,a0@(LBI_MACH) bnes 2f andw #0x00ff,d7 oriw #0x0100,d7 --- 658,664 ---- Lserial_putc: movel a0,sp@- lea pc@(_boot_info),a0 ! cmpil #MACH_AMIGA,a0@(BI_MACH) bnes 2f andw #0x00ff,d7 oriw #0x0100,d7 *************** *** 669,677 **** movew a1@,d7 bsr Lserial_putnum ! moveq #10,d7 bsr Lserial_putc ! moveq #13,d7 bsr Lserial_putc moveml sp@+,a1/d7 --- 746,754 ---- movew a1@,d7 bsr Lserial_putnum ! moveq #LF,d7 bsr Lserial_putc ! moveq #CR,d7 bsr Lserial_putc moveml sp@+,a1/d7 diff -cr --new-file linux-0.07pl4/m68k/machasm.S linux-0.08/m68k/machasm.S *** linux-0.07pl4/m68k/machasm.S Sun Feb 13 21:56:24 1994 --- linux-0.08/m68k/machasm.S Tue Mar 1 13:02:47 1994 *************** *** 1,36 **** - #include - #include "assyms.h" LBITS_040 = LPAGE_PRESENT|LPAGE_CACHE040 .text - .even - .globl _mach_save_ctx - _mach_save_ctx: - /* argument is the task_struct */ - movel sp@(4),a0 - - /* save status register */ - movew sr,a0@(LTS_TSS+LTSS_SR) - - /* save current alternate address space */ - movec sfc,d0 - movew d0,a0@(LTS_TSS+LTSS_FS) - - /* save non-scratch registers */ - moveml d2-d7/a2-a7,a0@(LTS_TSS+LTSS_REGS) - - /* save floating point state */ - fsave a0@(LTS_TSS+LTSS_FPSTATE) - tstw a0@(LTS_TSS+LTSS_FPSTATE) - beqs 1f /* NULL state, no need to save regs */ - fmovemx fp0-fp7,a0@(LTS_TSS+LTSS_FPREGS) - fmovem fpiar/fpcr/fpsr,a0@(LTS_TSS+LTSS_FPCNTL) - 1: - - rts - .globl _resume .even --- 1,8 ---- *************** *** 119,125 **** movew a0@(LTS_TSS+LTSS_SR),sr rts - - LC0: - .ascii "sp for resumed task is %#lx (%#lx)" - .byte 10,0 --- 91,93 ---- diff -cr --new-file linux-0.07pl4/m68k/ptrace.c linux-0.08/m68k/ptrace.c *** linux-0.07pl4/m68k/ptrace.c Wed Dec 31 19:00:00 1969 --- linux-0.08/m68k/ptrace.c Thu Mar 24 17:00:50 1994 *************** *** 0 **** --- 1,229 ---- + /* + * linux/m68k/ptrace.c + * + * Copyright (C) 1994 by Hamish Macdonald + * Taken from linux/kernel/ptrace.c and modified for M680x0. + * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file README.legal in the main directory of + * this archive for more details. + */ + + #include + + #include + #include + #include + #include + #include + + /* + * This routine gets a long from any process space by following the page + * tables. NOTE! You should check that the long isn't on a page boundary, + * and that it is in the task area before calling this: this routine does + * no checking. + * + */ + static unsigned long get_long(struct task_struct * tsk, + unsigned long addr) + { + unsigned long page, *ptrp; + + repeat: + page = tsk->tss.pagedir_v[L1_INDEX(addr)]; + if (!(page & PAGE_TABLE)) { + do_no_page(0,addr,tsk,0); + goto repeat; + } + ptrp = (unsigned long *)PTOV(page & TABLE_MASK); + page = ptrp[L2_INDEX(addr)]; + if (!(page & PAGE_TABLE)) { + do_no_page(0,addr,tsk,0); + goto repeat; + } + page = PTOV(page & PAGE_MASK); + page += PAGE_PTR(addr); + page = *(unsigned long *)page; + if (!(page & PAGE_PRESENT)) { + do_no_page(0,addr,tsk,0); + goto repeat; + } + page = PTOV(page & PAGE_MASK); + page += addr & ~PAGE_MASK; + return *(unsigned long *) page; + } + + /* + * This routine puts a long into any process space by following the page + * tables. NOTE! You should check that the long isn't on a page boundary, + * and that it is in the task area before calling this: this routine does + * no checking. + * + * Now keeps R/W state of page so that a text page stays readonly + * even if a debugger scribbles breakpoints into it. -M.U- + */ + static void put_long(struct task_struct * tsk, unsigned long addr, + unsigned long data) + { + unsigned long page, pte = 0, *ptrp; + int readonly = 0; + + repeat: + page = tsk->tss.pagedir_v[L1_INDEX(addr)]; + if (!(page & PAGE_TABLE)) { + do_no_page(0,addr,tsk,0); + goto repeat; + } + ptrp = (unsigned long *)PTOV(page & TABLE_MASK); + page = ptrp[L2_INDEX(addr)]; + if (!(page & PAGE_TABLE)) { + do_no_page(0,addr,tsk,0); + goto repeat; + } + page = PTOV(page & PAGE_MASK); + page += PAGE_PTR(addr); + pte = page; + page = *(unsigned long *)page; + if (!(page & PAGE_PRESENT)) { + do_no_page(0 /* PAGE_RW */ ,addr,tsk,0); + goto repeat; + } + if (!PAGE_IS_RW(page)) { + if(!(page & PAGE_COW)) + readonly = 1; + do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk,0); + goto repeat; + } + /* we're bypassing pagetables, so we have to set the dirty bit ourselves */ + *(unsigned long *) pte |= (PAGE_DIRTY|PAGE_COW); + page = PTOV(page & PAGE_MASK); + page += addr & ~PAGE_MASK; + *(unsigned long *) page = data; + if(readonly) { + *(unsigned long *) pte &=~ (PAGE_RW|PAGE_COW); + invalidate(); + } + } + + /* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls get_long() to read a long. + */ + int ptrace_read_long(struct task_struct * tsk, long addr, + unsigned long * result) + { + unsigned long low,high; + + if (addr > TASK_SIZE-sizeof(long)) + return -EIO; + if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { + low = get_long(tsk,addr & ~(sizeof(long)-1)); + high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1)); + switch (addr & (sizeof(long)-1)) { + case 1: + low >>= 8; + low |= high << 24; + break; + case 2: + low >>= 16; + low |= high << 16; + break; + case 3: + low >>= 24; + low |= high << 8; + break; + } + *result = low; + } else + *result = get_long(tsk,addr); + return 0; + } + + /* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls put_long() to write a long. + */ + int ptrace_write_long(struct task_struct * tsk, long addr, long data) + { + unsigned long low,high; + + if (addr > TASK_SIZE-sizeof(long)) + return -EIO; + if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { + low = get_long(tsk,addr & ~(sizeof(long)-1)); + high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1)); + switch (addr & (sizeof(long)-1)) { + case 0: /* shouldn't happen, but safety first */ + low = data; + break; + case 1: + low &= 0x000000ff; + low |= data << 8; + high &= ~0xff; + high |= data >> 24; + break; + case 2: + low &= 0x0000ffff; + low |= data << 16; + high &= ~0xffff; + high |= data >> 16; + break; + case 3: + low &= 0x00ffffff; + low |= data << 24; + high &= ~0xffffff; + high |= data >> 8; + break; + } + put_long(tsk,addr & ~(sizeof(long)-1),low); + put_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1),high); + } else + put_long(tsk,addr,data); + return 0; + } + + int ptrace_peekusr (struct task_struct *tsk, long addr, long data) + { + unsigned long tmp; + int res; + + if ((addr & 3) || addr < 0 || addr > 18*sizeof(long)) + return -EIO; + + res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); + if (res) + return res; + tmp = 0; /* Default return condition */ + if(addr < 19*sizeof(long)) { + addr = addr >> 2; /* temporary hack. */ + tmp = ptrace_get_stack_long(tsk, sizeof(long)*addr); + if (addr == PT_SR) + tmp &= 0xffff; + } + put_fs_long(tmp,(unsigned long *) data); + return 0; + } + + int ptrace_pokeusr(struct task_struct *tsk, long addr, long data) + { + if ((addr & 3) || addr < 0 || addr > 18*sizeof(long)) + return -EIO; + + addr = addr >> 2; /* temporary hack. */ + + if (addr == PT_ORIG_D0) + return -EIO; + if (addr == PT_SR) { + data &= SR_MASK; + data |= ptrace_get_stack_long(tsk, PT_SR*sizeof(long)) & ~SR_MASK; + } + /* Do not allow the user to set the debug register for kernel + address space */ + if(addr < 19){ + if (ptrace_put_stack_long(tsk, sizeof(long)*addr, data)) + return -EIO; + return 0; + }; + return -EIO; + } diff -cr --new-file linux-0.07pl4/m68k/signal.c linux-0.08/m68k/signal.c *** linux-0.07pl4/m68k/signal.c Sat Dec 11 13:52:02 1993 --- linux-0.08/m68k/signal.c Sun Mar 27 09:37:02 1994 *************** *** 45,50 **** --- 45,52 ---- unsigned short sc_formatvec; }; + asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); + /* * This sets regs->usp even though we don't actually use sigstacks yet.. */ *************** *** 297,303 **** "addl #31,%1" :"=m" (current->signal),"=r" (signr) :"1" (signr)); - sa = current->sigaction + signr; signr++; --- 299,304 ---- *************** *** 325,331 **** if (signr != SIGCHLD) continue; /* check for SIGCHLD: it's special */ ! while (sys_wait4(-1,NULL,WNOHANG,NULL) > 0) /* nothing */; continue; } --- 326,332 ---- if (signr != SIGCHLD) continue; /* check for SIGCHLD: it's special */ ! while (sys_waitpid(-1,NULL,WNOHANG) > 0) /* nothing */; continue; } *************** *** 375,384 **** regs->d0 = regs->orig_d0; regs->pc -= 2; } - if (!handler_signal) /* no handler will be called - return 0 */ return 0; - pc = regs->pc; frame = (unsigned long *)regs->usp; signr = 1; --- 376,383 ---- diff -cr --new-file linux-0.07pl4/m68k/sys_call.S linux-0.08/m68k/sys_call.S *** linux-0.07pl4/m68k/sys_call.S Sun Dec 12 08:26:11 1993 --- linux-0.08/m68k/sys_call.S Sun Mar 27 06:23:56 1994 *************** *** 52,84 **** * 4C(sp) - format & vector */ ! LOFF_D1 = 0x00 ! LOFF_D2 = 0x04 ! LOFF_D3 = 0x08 ! LOFF_D4 = 0x0C ! LOFF_D5 = 0x10 ! LOFF_D6 = 0x14 ! LOFF_D7 = 0x18 ! LOFF_A0 = 0x1C ! LOFF_A1 = 0x20 ! LOFF_A2 = 0x24 ! LOFF_A3 = 0x28 ! LOFF_A4 = 0x2C ! LOFF_A5 = 0x30 ! LOFF_A6 = 0x34 ! LOFF_D0 = 0x38 ! LOFF_USP = 0x3C LOFF_ORIG_D0 = 0x40 LOFF_STKADJ = 0x44 ! LOFF_SR = 0x46 ! LOFF_PC = 0x48 LOFF_FORMAT = 0x4C ! LCF_MASK = 0x0001 LENOSYS = 38 .globl _system_call, _buserr, _trap .globl _ret_from_exception, _inthandler --- 52,86 ---- * 4C(sp) - format & vector */ ! LOFF_D1 = 0x00 ! LOFF_D2 = 0x04 ! LOFF_D3 = 0x08 ! LOFF_D4 = 0x0C ! LOFF_D5 = 0x10 ! LOFF_D6 = 0x14 ! LOFF_D7 = 0x18 ! LOFF_A0 = 0x1C ! LOFF_A1 = 0x20 ! LOFF_A2 = 0x24 ! LOFF_A3 = 0x28 ! LOFF_A4 = 0x2C ! LOFF_A5 = 0x30 ! LOFF_A6 = 0x34 ! LOFF_D0 = 0x38 ! LOFF_USP = 0x3C LOFF_ORIG_D0 = 0x40 LOFF_STKADJ = 0x44 ! LOFF_SR = 0x46 ! LOFF_PC = 0x48 LOFF_FORMAT = 0x4C ! LCF_MASK = 0x0001 LENOSYS = 38 + LESP0_OFFSET = 2436 + .globl _system_call, _buserr, _trap .globl _ret_from_exception, _inthandler *************** *** 96,101 **** --- 98,107 ---- | signifies that the stack frame | is NOT for syscall + | save top of frame + movel _current,a0 + movel sp,a0@(LESP0_OFFSET) + movel sp,sp@- | stack frame pointer argument bsr _buserr_c addql #4,sp *************** *** 113,118 **** --- 119,128 ---- movel d0,sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall + | save top of frame + movel _current,a0 + movel sp,a0@(LESP0_OFFSET) + movel sp,sp@- | stack frame pointer argument bsr _trap_c addql #4,sp *************** *** 132,153 **** movel a0,sp@(LOFF_USP) | save User Stack Pointer movel d0,sp@(LOFF_ORIG_D0) | save original D0 (syscall #) ! # debug ! btst #4,sp@(LOFF_SR) ! bne 1f ! L1: bra L1 ! /* pea Lmsg ! jbsr _panic ! Lmsg: ! .asciz "coming from user mode, not on master stack\n" ! .even ! */ ! 1: ! # end debug cmpl _NR_syscalls,d0 bgt _ret_from_exception - movel _current,a0 andw #~LCF_MASK,sp@(LOFF_SR) | assume syscall success clrl a0@(LTS_ERRNO) btst #5,a0@(LTS_FLAGS+3) | PF_TRACESYS --- 142,153 ---- movel a0,sp@(LOFF_USP) | save User Stack Pointer movel d0,sp@(LOFF_ORIG_D0) | save original D0 (syscall #) ! | save top of frame ! movel _current,a0 ! movel sp,a0@(LESP0_OFFSET) cmpl _NR_syscalls,d0 bgt _ret_from_exception andw #~LCF_MASK,sp@(LOFF_SR) | assume syscall success clrl a0@(LTS_ERRNO) btst #5,a0@(LTS_FLAGS+3) | PF_TRACESYS *************** *** 156,183 **** movel a0@(d0:l:4),a0 jbsr a0@ movel d0,sp@(LOFF_D0) | save the return value - movel _current,a0 - - # - # This commented out section should be used when system calls - # set current->errno to indicate an error, rather than just - # returning a negative value. - # - # movel a0@(LTS_ERRNO),d1 - # movel d0,d1 - # negl d1 - # beq 2f - # movel d1,sp@(LOFF_D0) - # oriw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error - - # - # This section sets the carry bit if the result is negative. - # i.e. assume a negative return value is an error... - # - tstl d0 bpl 2f ! negl d0 ! movel d0,sp@(LOFF_D0) orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error bra _ret_from_exception 1: jbsr _syscall_trace --- 156,169 ---- movel a0@(d0:l:4),a0 jbsr a0@ movel d0,sp@(LOFF_D0) | save the return value bpl 2f ! orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error ! 2: ! movel _current,a0 ! movel a0@(LTS_ERRNO),d1 ! negl d1 ! beq _ret_from_exception ! movel d1,sp@(LOFF_D0) orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error bra _ret_from_exception 1: jbsr _syscall_trace *************** *** 186,221 **** movel a0@(d0:l:4),a0 jbsr a0@ movel d0,sp@(LOFF_D0) | save the return value - movel _current,a0 - # - # This commented out section should be used when system calls - # set current->errno to indicate an error, rather than just - # returning a negative value. - # - # movel a0@(LTS_ERRNO),d1 - # movel d0,d1 - # negl d1 - # beq 2f - # movel d1,sp@(LOFF_D0) - # orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error - - # - # This section sets the carry bit if the result is negative. - # i.e. assume a negative return value is an error... - # - tstl d0 bpl 2f ! negl d0 ! movel d0,sp@(LOFF_D0) orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error 2: jbsr _syscall_trace _ret_from_exception: ! 1: tstl _need_resched bne reschedule movel _current,a0 cmpl #_task,a0 | task[0] cannot have signals beq 2f moveq #0,d0 cmpl a0@(LTS_STATE),d0 | state bne reschedule --- 172,207 ---- movel a0@(d0:l:4),a0 jbsr a0@ movel d0,sp@(LOFF_D0) | save the return value bpl 2f ! orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error ! 2: ! movel _current,a0 ! movel a0@(LTS_ERRNO),d1 ! negl d1 ! beq 2f ! movel d1,sp@(LOFF_D0) orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error 2: jbsr _syscall_trace _ret_from_exception: ! btst #5,sp@(LOFF_SR) | check if returning to kernel ! bnes 2f | if so, skip resched, signals ! tstl _need_resched bne reschedule movel _current,a0 cmpl #_task,a0 | task[0] cannot have signals beq 2f + btst #6,a0@(LTS_FLAGS+3) | check for delayed trace + beq 1f + bclr #6,a0@(LTS_FLAGS+3) | clear delayed trace bit + bclr #7,sp@(LOFF_SR) | clear trace bit in SR + pea 1 | send SIGTRAP + movel a0,sp@- + pea 5 + bsrl _send_sig + addql #8,sp + addql #4,sp + 1: moveq #0,d0 cmpl a0@(LTS_STATE),d0 | state bne reschedule *************** *** 238,250 **** movel d1,sp@- bsr _do_signal addql #8,sp ! movel sp@(LOFF_USP),a0 | return to user mode ! movec a0,usp ! moveml sp@+,d1-a6 ! movel sp@+,d0 | restore d0 ! addql #8,sp | skip the usp and orig_d0 ! addw sp@+,sp | add the stack adjustment ! rte /* --- 224,230 ---- movel d1,sp@- bsr _do_signal addql #8,sp ! bras 2b /* *************** *** 314,319 **** --- 294,304 ---- movel d0,sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall movec usp,a0 movel a0,sp@(LOFF_USP) | save usp + + | save top of frame + movel _current,a0 + movel sp,a0@(LESP0_OFFSET) + bra _ret_from_exception | deliver signals, reschedule etc.. Lspurious: addql #1,_num_spurious | increment the counter of spurious diff -cr --new-file linux-0.07pl4/m68k/traps.c linux-0.08/m68k/traps.c *** linux-0.07pl4/m68k/traps.c Tue Feb 15 13:04:29 1994 --- linux-0.08/m68k/traps.c Sun Mar 27 09:37:40 1994 *************** *** 1,5 **** /* ! * linux/kernel/traps.c * * Copyright (C) 1993, 1994 by Hamish Macdonald * --- 1,5 ---- /* ! * linux/m68k/traps.c * * Copyright (C) 1993, 1994 by Hamish Macdonald * *************** *** 22,27 **** --- 22,30 ---- #include #include #include + #include + #include + #include #include /* assembler routines */ *************** *** 183,189 **** */ if(ssw & MA_040) { ! wba_2ndpage = wba + ((wbs & WBSIZ_040)==BA_SIZE_WORD)?1:3; mmusr = probe040 (1, wbs & WBTM_040, wba_2ndpage); if (mmusr & MMU_R_040) do_page_fault (fp, wba_2ndpage, 1); --- 186,193 ---- */ if(ssw & MA_040) { ! /* Added missing parentheses (MA) */ ! wba_2ndpage = wba + (((wbs & WBSIZ_040)==BA_SIZE_WORD)?1:3); mmusr = probe040 (1, wbs & WBTM_040, wba_2ndpage); if (mmusr & MMU_R_040) do_page_fault (fp, wba_2ndpage, 1); *************** *** 230,249 **** else do_page_fault (fp, addr, 0); /* not resident */ - /* - * MR: create the atc entry anew; (this one's been a weirdo to figure out !!!!) - * - * background is as follows: when the actual data has been paged in, - * the mmu sometimes had no time to update the corresponding atc entry - * (i.e. when some printk stuff is placed around here in the routine, - * this probe040() is obsolete. *sigh* kinda heisenbug.) - * this bug is most probably originated somewhere in the flow of - * do_no_page(), an appropriate pflush command missing or so ... - * so this is a work-around unless I work out where exactly the bug is - * located. - */ - (void) probe040 (!(ssw & RW_040), ssw & TM_040, addr); - } else { printk ("68040 access error, ssw=%x\n", ssw); trap_c (fp); --- 234,239 ---- *************** *** 417,426 **** } ! asmlinkage void trap_c(struct frame *fp) { unsigned long isp; - int sig; /* fetch interrupt stack pointer */ __asm__ __volatile__ ("movec isp,%0" : "=g" (isp)); --- 407,415 ---- } ! void bad_super_trap (struct frame *fp) { unsigned long isp; /* fetch interrupt stack pointer */ __asm__ __volatile__ ("movec isp,%0" : "=g" (isp)); *************** *** 429,436 **** printk ("*** %s *** FORMAT=%X\n", vec_names[fp->vector >> 2], fp->format); else ! printk ("*** Exception %d *** FORMAT=%X\n", fp->vector >> 2, ! fp->format); printk ("PC=%#010lx SR=%#06x SP=%#010lx ISP=%#010lx\n", fp->pc, fp->sr, (ulong)fp, isp); --- 418,425 ---- printk ("*** %s *** FORMAT=%X\n", vec_names[fp->vector >> 2], fp->format); else ! printk ("*** Exception %d *** FORMAT=%X\n", ! fp->vector >> 2, fp->format); printk ("PC=%#010lx SR=%#06x SP=%#010lx ISP=%#010lx\n", fp->pc, fp->sr, (ulong)fp, isp); *************** *** 463,495 **** fp->un.fmtb.daddr, space_names[ssw & DFC], fp->pc); ! if (fp->sr & PS_S) { ! /* kernel fault must be a data fault to user space */ ! if (!(ssw & DF) || (ssw & DFC) != USER_DATA) ! /* instruction fault! BAD */ ! panic ("BAD KERNEL ADDRESS ERROR"); ! } else { ! /* user fault */ ! if (!(ssw & (RC | RB)) && !(ssw & DF)) ! /* not an instruction fault or data fault! */ ! panic ("USER ADDRERR w/o instruction or" ! " data fault"); ! } } ! /*if ((fp->vector >> 2) == VEC_ADDRERR)*/ { ! unsigned short iw; ! ! if (fp->sr & PS_S) ! iw = *(ushort *)fp->pc; ! else ! iw = get_fs_word ((ushort *)fp->pc); ! ! printk ("Word at pc is %#x\n", iw); ! } ! if (fp->sr & PS_S) ! panic ("BAD KERNEL TRAP"); /* send the appropriate signal to the user program */ switch (fp->vector >> 2) { --- 452,476 ---- fp->un.fmtb.daddr, space_names[ssw & DFC], fp->pc); ! printk ("Word at pc is %#x\n", *(ushort *)fp->pc); } + panic ("BAD KERNEL TRAP"); + } ! asmlinkage void trap_c(struct frame *fp) ! { ! int sig; ! if ((fp->sr & PS_S) && (fp->vector >> 2) == VEC_TRACE ! && !(fp->sr & PS_T)) { ! /* traced a trapping instruction */ ! unsigned char *lp = ((unsigned char *)&fp->un.fmt2) + 4; ! current->flags |= PF_DTRACE; ! /* clear the trace bit */ ! (*(unsigned short *)lp) &= ~PS_T; ! return; ! } else if (fp->sr & PS_S) ! bad_super_trap(fp); /* send the appropriate signal to the user program */ switch (fp->vector >> 2) { *************** *** 516,522 **** case VEC_TRAP12: case VEC_TRAP13: case VEC_TRAP14: - case VEC_TRAP15: sig = SIGILL; break; case VEC_ZERODIV: --- 497,502 ---- *************** *** 529,534 **** --- 509,519 ---- case VEC_FPNAN: sig = SIGFPE; break; + case VEC_TRACE: /* ptrace single step */ + fp->sr &= ~PS_T; + case VEC_TRAP15: /* breakpoint */ + sig = SIGTRAP; + break; default: sig = SIGILL; break; *************** *** 554,585 **** do_exit(SIGSEGV); } ! #if 0 ! void showwierd(struct frame *fp) { ! ulong reg; ! ! printk ("Current pid is %d\n", current->pid); ! ! __asm__ __volatile__ ("movew sr,%0" : "=d" (reg)); ! printk ("Current sr is %#06x\n", reg); ! ! printk ("Format is %#x, vector is %d\n", fp->format, ! fp->vector >> 2); ! ! __asm__ __volatile__ ("movec isp,%0" : "=d" (reg)); ! ! printk ("PC=%#010x SR=%#06x SP=%p ISP=%#010x\n", ! fp->pc, fp->sr, fp, reg); ! printk ("D0=%#010x D1=%#010x D2=%#010x D3=%#010x\n", ! fp->d0, fp->regs[0], fp->regs[1], fp->regs[2]); ! printk ("D4=%#010x D5=%#010x D6=%#010x D7=%#010x\n", ! fp->regs[3], fp->regs[4], fp->regs[5], fp->regs[6]); ! printk ("A0=%#010x A1=%#010x A2=%#010x A3=%#010x\n", ! fp->regs[7], fp->regs[8], fp->regs[9], fp->regs[10]); ! printk ("A4=%#010x A5=%#010x A6=%#010x USP=%#010x\n", ! fp->regs[11], fp->regs[12], fp->regs[13], fp->usp); ! ! printk ("orig_d0=%#010x stkadj=%#06x\n", fp->orig_d0, fp->stkadj); } - #endif --- 539,574 ---- do_exit(SIGSEGV); } ! void arch_core_dump (struct user *up, long signr, struct pt_regs *regs) { ! up->magic = CMAGIC; ! up->start_code = 0; ! up->start_stack = regs->usp & ~(PAGE_SIZE - 1); ! up->u_tsize = ((unsigned long) current->end_code) >> 12; ! up->u_dsize = ((unsigned long) (current->brk + (PAGE_SIZE-1))) >> 12; ! up->u_dsize -= up->u_tsize; ! up->u_ssize = 0; ! if (up->start_stack < TASK_SIZE) ! up->u_ssize = ((unsigned long) (TASK_SIZE - up->start_stack)) >> 12; ! /* If the size of the dump file exceeds the rlimit, then see what would happen ! if we wrote the stack, but not the data area. */ ! if ((up->u_dsize+up->u_ssize+1) * PAGE_SIZE > ! current->rlim[RLIMIT_CORE].rlim_cur) ! up->u_dsize = 0; ! /* Make sure we have enough room to write the stack and data areas. */ ! if ((up->u_ssize+1) * PAGE_SIZE > ! current->rlim[RLIMIT_CORE].rlim_cur) ! up->u_ssize = 0; ! strncpy(up->u_comm, current->comm, sizeof(current->comm)); ! up->u_ar0 = (struct pt_regs *)(((int)(&up->regs)) -((int)(up))); ! up->signal = signr; ! up->regs = *regs; ! /* floating point stuff valid */ ! up->u_fpvalid = 1; ! /* save floating point registers */ ! asm volatile ("fmovem fpiar/fpcr/fpsr,%0@" ! :: "a" (up->m68kfp.fpcntl)); ! asm volatile ("fmovemx fp0-fp7,%0@" ! :: "a" (up->m68kfp.fpregs) ! : "memory"); } diff -cr --new-file linux-0.07pl4/mm/memory.c linux-0.08/mm/memory.c *** linux-0.07pl4/mm/memory.c Mon Mar 21 10:00:08 1994 --- linux-0.08/mm/memory.c Sun Mar 27 07:24:12 1994 *************** *** 12,17 **** --- 12,18 ---- * Heavily modified 1993 by Hamish Macdonald for MC680X0 support * * 68040 fixes by Michael Rausch + * 68040 fixes by Martin Apel */ /* *************** *** 76,86 **** unsigned short * mem_map = NULL; ! static unsigned long *get_pointer_table (void); #define get_root_table() get_pointer_table() ! static void free_pointer_table (unsigned long *); #define free_root_table(ptr) free_pointer_table((ptr)) ! static unsigned long *get_page_table (unsigned long *); /* * oom() prints a message (so that the user knows why the process died), --- 77,87 ---- unsigned short * mem_map = NULL; ! unsigned long *get_pointer_table (void); #define get_root_table() get_pointer_table() ! void free_pointer_table (unsigned long *); #define free_root_table(ptr) free_pointer_table((ptr)) ! unsigned long *get_page_table (unsigned long *); /* * oom() prints a message (so that the user knows why the process died), *************** *** 705,720 **** *ptr_table = BAD_PAGETABLE | PAGE_TABLE; return 0; } page_table += L3_INDEX(address); if (*page_table) { printk("put_page: page already exists\n"); *page_table = 0; - invalidate(); } *page_table = VTOP(page) | prot; - /* no need for invalidate (why not?) */ - return page; } --- 706,722 ---- *ptr_table = BAD_PAGETABLE | PAGE_TABLE; return 0; } + /* An 'invalidate' has to be done anyway, and as it affects only + * user entries, it can be done here. (MA) + */ + invalidate(); page_table += L3_INDEX(address); if (*page_table) { printk("put_page: page already exists\n"); *page_table = 0; } *page_table = VTOP(page) | prot; return page; } *************** *** 755,768 **** printk("put_dirty_page: bad pointer table entry\n"); return 0; } page_table += L3_INDEX(address); if (*page_table) { printk("put_dirty_page: page already exists\n"); *page_table = 0; - invalidate(); } ! *page_table = VTOP(page) | (PAGE_DIRTY | PAGE_PRIVATE); ! /* no need for invalidate */ return page; } --- 757,772 ---- printk("put_dirty_page: bad pointer table entry\n"); return 0; } + /* An 'invalidate' has to be done anyway, and as it affects only + * user entries, it can be done here. (MA) + */ + invalidate(); page_table += L3_INDEX(address); if (*page_table) { printk("put_dirty_page: page already exists\n"); *page_table = 0; } ! *page_table = VTOP(page) | (PAGE_DIRTY | PAGE_PRIVATE | PAGE_ACCESSED); /* MA */ return page; } *************** *** 905,911 **** if (user_usp && tsk == current) { #if 1 /*def DEBUG*/ if (boot_info.cputype & CPU_68040) ! printk("do_wp_page: (oh no! probably once again '040 ATC inconsistency)\n"); #endif send_sig(SIGSEGV, tsk, 1); return; --- 909,915 ---- if (user_usp && tsk == current) { #if 1 /*def DEBUG*/ if (boot_info.cputype & CPU_68040) ! printk("do_wp_page: (oh no! probably once again '040 ATC inconsistency)\n"); #endif send_sig(SIGSEGV, tsk, 1); return; *************** *** 1097,1103 **** #define PD_MARKUSED(dp,i) ((dp)->alloced |= (1<<(i))) #define PD_MARKFREE(dp,i) ((dp)->alloced &= ~(1<<(i))) ! static unsigned long *get_pointer_table (void) { unsigned long table = 0, flags; struct ptable_desc *dp = ptable_list.next; --- 1101,1107 ---- #define PD_MARKUSED(dp,i) ((dp)->alloced |= (1<<(i))) #define PD_MARKFREE(dp,i) ((dp)->alloced &= ~(1<<(i))) ! unsigned long *get_pointer_table (void) { unsigned long table = 0, flags; struct ptable_desc *dp = ptable_list.next; *************** *** 1159,1165 **** return (unsigned long *)table; } ! static void free_pointer_table (unsigned long *ptable) { struct ptable_desc *dp; unsigned long page = (unsigned long)ptable & PAGE_MASK; --- 1163,1169 ---- return (unsigned long *)table; } ! void free_pointer_table (unsigned long *ptable) { struct ptable_desc *dp; unsigned long page = (unsigned long)ptable & PAGE_MASK; *************** *** 1206,1212 **** } } ! static unsigned long *get_page_table (unsigned long *ptr) { unsigned long page, tmp; int i; --- 1210,1216 ---- } } ! unsigned long *get_page_table (unsigned long *ptr) { unsigned long page, tmp; int i; *************** *** 1227,1232 **** --- 1231,1250 ---- return NULL; } + void free_page_table (unsigned long *ptr) + { + unsigned long page; + int i; + + if (!(PAGE_TABLE & *ptr)) + return; + page = PTOV(*ptr & PAGE_MASK); + for (i = 0; i < 16; i++) + ptr[i] = 0; + cache_page (page); + free_page (page); + } + /* * fill in an empty page-table if none exists. */ *************** *** 1300,1309 **** /* page was swapped out, flag major fault and swap it in */ if (tmp) { ++tsk->maj_flt; ! swap_in((unsigned long *) page); return; } ! address &= 0xfffff000; tmp = 0; for (mpnt = tsk->mmap ; mpnt != NULL; mpnt = mpnt->vm_next) { if (address < mpnt->vm_start) --- 1318,1327 ---- /* page was swapped out, flag major fault and swap it in */ if (tmp) { ++tsk->maj_flt; ! swap_in(&p[L3_INDEX(address)]); return; } ! address &= PAGE_MASK; tmp = 0; for (mpnt = tsk->mmap ; mpnt != NULL; mpnt = mpnt->vm_next) { if (address < mpnt->vm_start) *************** *** 1360,1366 **** do_no_page (error_code, address, current, user_esp); return; } ! printk("Unable to handle kernel paging request at address %08lx\n",address); die_if_kernel("Oops", fp, error_code); do_exit(SIGKILL); } --- 1378,1384 ---- do_no_page (error_code, address, current, user_esp); return; } ! printk("Unable to handle kernel paging request at address %08lx from %lx\n",address, fp->pc); die_if_kernel("Oops", fp, error_code); do_exit(SIGKILL); } *************** *** 1396,1401 **** --- 1414,1420 ---- if (error_code & 1) prot = (prot & ~PAGE_RONLY) | PAGE_DIRTY; page = bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, prot); + cache_push (VTOP(page), PAGE_SIZE); /* MA */ if (prot & PAGE_RONLY) { if (share_page(area, area->vm_task, inode, address, error_code, page)) return; *************** *** 1676,1681 **** --- 1695,1715 ---- int i; unsigned long ktable; + /* Don't map the first 4 MB again. The pagetables + * for this range have already been initialized + * in m68k/head.s. Otherwise the pages used for + * tables would be reinitialized to copyback mode. + */ + + if (mem_mapped < 4 * ONEMEG) + { + #ifdef DEBUG + printk ("Already initialized\n"); + #endif + physaddr += ONEMEG; + pindex += 4; + continue; + } #ifdef DEBUG printk ("[setup table]"); #endif *************** *** 1702,1708 **** for (i = 0; i < 256; i++) { ktablep[i] = physaddr | PAGE_PRESENT | PAGE_CACHE040 | PAGE_GLOBAL040; ! physaddr += 4096; } ktablep += 256; --- 1736,1742 ---- for (i = 0; i < 256; i++) { ktablep[i] = physaddr | PAGE_PRESENT | PAGE_CACHE040 | PAGE_GLOBAL040; ! physaddr += PAGE_SIZE; } ktablep += 256; *************** *** 1985,1996 **** { unsigned long i; ! i = high_memory >> PAGE_SHIFT; val->totalram = 0; val->freeram = 0; val->sharedram = 0; val->bufferram = buffermem; ! while (i-- > (KSTART_ADDR >> PAGE_SHIFT)) { if (mem_map[i] & MAP_PAGE_RESERVED) continue; val->totalram++; --- 2019,2030 ---- { unsigned long i; ! i = (high_memory - KSTART_ADDR) >> PAGE_SHIFT; val->totalram = 0; val->freeram = 0; val->sharedram = 0; val->bufferram = buffermem; ! while (i-- > 0) { if (mem_map[i] & MAP_PAGE_RESERVED) continue; val->totalram++; diff -cr --new-file linux-0.07pl4/mm/swap.c linux-0.08/mm/swap.c *** linux-0.07pl4/mm/swap.c Fri Dec 17 13:04:35 1993 --- linux-0.08/mm/swap.c Mon Mar 21 16:37:51 1994 *************** *** 203,211 **** unsigned long entry; unsigned long page; - panic ("swap_in called"); - entry = *table_ptr; if (PAGE_PRESENT & entry) { printk("trying to swap in present page\n"); return; --- 203,212 ---- unsigned long entry; unsigned long page; entry = *table_ptr; + dbprintf ("process %d swapping in entry %ld\n", current->pid, + entry); + if (PAGE_PRESENT & entry) { printk("trying to swap in present page\n"); return; *************** *** 226,234 **** if (*table_ptr != entry) { free_page(page); return; *table_ptr = VTOP(page) | (PAGE_DIRTY | PAGE_PRIVATE); swap_free(entry); - } } static inline int try_to_swap_out(unsigned long * table_ptr) --- 227,236 ---- if (*table_ptr != entry) { free_page(page); return; + } + invalidate(); *table_ptr = VTOP(page) | (PAGE_DIRTY | PAGE_PRIVATE); swap_free(entry); } static inline int try_to_swap_out(unsigned long * table_ptr) *************** *** 357,363 **** unsigned long desc, *ptr; desc = L1_SWAP_INDEX(p->tss.pagedir_v,table); ! if(!desc || PTOV(desc & PAGE_MASK) >= high_memory) continue; if(!(PAGE_TABLE & desc)) { printk("swap_out: bad page-table at pg_dir[%d]: %08lx\n", --- 359,365 ---- unsigned long desc, *ptr; desc = L1_SWAP_INDEX(p->tss.pagedir_v,table); ! if(!desc || PTOV(desc & TABLE_MASK) >= high_memory) continue; if(!(PAGE_TABLE & desc)) { printk("swap_out: bad page-table at pg_dir[%d]: %08lx\n", *************** *** 365,371 **** L1_SWAP_INDEX(p->tss.pagedir_v,table) = 0; continue; } ! ptr = (unsigned long *)PTOV(desc & PAGE_MASK); pg_table = L2_SWAP_INDEX(ptr,table); if (!pg_table || PTOV(pg_table & PAGE_MASK) >= high_memory) continue; --- 367,373 ---- L1_SWAP_INDEX(p->tss.pagedir_v,table) = 0; continue; } ! ptr = (unsigned long *)PTOV(desc & TABLE_MASK); pg_table = L2_SWAP_INDEX(ptr,table); if (!pg_table || PTOV(pg_table & PAGE_MASK) >= high_memory) continue; *************** *** 394,399 **** --- 396,402 ---- p->swap_page = page + 1; if((--p->swap_cnt) == 0) swap_task++; + dbprintf ("swapped out a page from pid %d\n", p->pid); return 1; default: *************** *** 457,463 **** swap_table++; goto check_dir; } ! ptr = (unsigned long *)PTOV(desc & PAGE_MASK); if ((unsigned long)ptr >= high_memory || (mem_map[MAP_NR(ptr)] & MAP_PAGE_RESERVED)) { swap_table++; goto check_dir; --- 460,466 ---- swap_table++; goto check_dir; } ! ptr = (unsigned long *)PTOV(desc & TABLE_MASK); if ((unsigned long)ptr >= high_memory || (mem_map[MAP_NR(ptr)] & MAP_PAGE_RESERVED)) { swap_table++; goto check_dir; *************** *** 682,695 **** if (!p) continue; for (pgt = 0 ; pgt < PTRS_PER_PAGE ; pgt++) { ! desc = p->tss.pagedir_v[pgt >> 3]; if (!desc) continue; ! if (!(desc & PAGE_TABLE) || PTOV(desc & PAGE_MASK) >= high_memory) continue; ! ptr = (unsigned long *)PTOV(desc & PAGE_MASK); ! ppage = (pgt & 0x7) + ptr; ! page = *ppage; if (!page) continue; if (!(page & PAGE_PRESENT) || (PTOV(page & PAGE_MASK) >= high_memory)) --- 685,697 ---- if (!p) continue; for (pgt = 0 ; pgt < PTRS_PER_PAGE ; pgt++) { ! desc = L1_SWAP_INDEX(p->tss.pagedir_v,pgt); if (!desc) continue; ! if (!(desc & PAGE_TABLE) || PTOV(desc & TABLE_MASK) >= high_memory) continue; ! ptr = (unsigned long *)PTOV(desc & TABLE_MASK); ! page = L2_SWAP_INDEX(ptr,pgt); if (!page) continue; if (!(page & PAGE_PRESENT) || (PTOV(page & PAGE_MASK) >= high_memory)) *************** *** 706,718 **** if (SWP_TYPE(page) != type) continue; if (!tmp) { ! if (!(tmp = __get_free_page(GFP_KERNEL))) return -ENOMEM; goto repeat; } read_swap_page(page, (char *) tmp); if (*ppage == page) { ! *ppage = tmp | (PAGE_DIRTY | PAGE_PRIVATE); ++p->rss; swap_free(page); tmp = 0; --- 708,722 ---- if (SWP_TYPE(page) != type) continue; if (!tmp) { ! if (!(tmp = __get_free_page(GFP_KERNEL))) { ! invalidate(); return -ENOMEM; + } goto repeat; } read_swap_page(page, (char *) tmp); if (*ppage == page) { ! *ppage = VTOP(tmp) | (PAGE_DIRTY | PAGE_PRIVATE); ++p->rss; swap_free(page); tmp = 0; *************** *** 722,727 **** --- 726,732 ---- } } free_page(tmp); + invalidate(); return 0; } diff -cr --new-file linux-0.07pl4/mm/vmalloc.c linux-0.08/mm/vmalloc.c *** linux-0.07pl4/mm/vmalloc.c Thu Jan 13 17:21:20 1994 --- linux-0.08/mm/vmalloc.c Sun Mar 20 10:32:51 1994 *************** *** 27,35 **** #define VMALLOC_OFFSET (8*1024*1024) static inline void set_pgdir(unsigned long dindex, unsigned long value) { - #ifdef __i386__ struct task_struct * p; p = &init_task; --- 27,36 ---- #define VMALLOC_OFFSET (8*1024*1024) + #ifdef __i386__ + static inline void set_pgdir(unsigned long dindex, unsigned long value) { struct task_struct * p; p = &init_task; *************** *** 37,51 **** ((unsigned long *) p->tss.cr3)[dindex] = value; p = p->next_task; } while (p != &init_task); - #else - #endif } static int free_area_pages(unsigned long dindex, unsigned long index, unsigned long nr) { unsigned long page, *pte; - #ifdef __i386__ if (!(PAGE_PRESENT & (page = swapper_pg_dir[dindex]))) return 0; page &= PAGE_MASK; --- 38,49 ---- *************** *** 65,80 **** mem_map[MAP_NR(page)] &= ~MAP_PAGE_RESERVED; free_page(page); return 0; - #else - return -ENOMEM; - #endif } static int alloc_area_pages(unsigned long dindex, unsigned long index, unsigned long nr) { unsigned long page, *pte; - #ifdef __i386__ page = swapper_pg_dir[dindex]; if (!page) { page = get_free_page(GFP_KERNEL); --- 63,74 ---- *************** *** 99,107 **** *pte = pg | PAGE_SHARED; } return 0; - #else - return -ENOMEM; - #endif } static int do_area(void * addr, unsigned long size, --- 93,98 ---- *************** *** 126,131 **** --- 117,222 ---- return 0; } + #elif defined(__mc68000__) + + static int free_area_pages(unsigned long dindex, unsigned long index, unsigned long nr) + { + unsigned long ptr, *ptrp, page, *pte; + extern unsigned long *krt; + + if (!(PAGE_TABLE & (ptr = krt[dindex >> 3]))) + return 0; + ptrp = (unsigned long *)PTOV(ptr & TABLE_MASK); + ptrp += (16*sizeof(long))*(dindex & (NUM_L2_ENTRIES-1)); + if (!(PAGE_TABLE & (page = ptrp[16*(dindex & (NUM_L2_ENTRIES-1))]))) + return 0; + page = PTOV(page & PAGE_MASK); + pte = index + (unsigned long *) page; + for ( ; nr > 0 ; nr--, pte++) { + unsigned long pg = *pte; + *pte = 0; + if (!(pg & PAGE_PRESENT)) + continue; + free_page(PTOV(pg & PAGE_MASK)); + } + pte = (unsigned long *) page; + for (nr = 0 ; nr < PTRS_PER_PAGE ; nr++, pte++) + if (*pte) + return 0; + mem_map[MAP_NR(page)] &= ~MAP_PAGE_RESERVED; + free_page_table(&ptrp[16*(dindex & (NUM_L2_ENTRIES-1))]); + return 0; + } + + static unsigned long get_pt (unsigned long dindex) + { + unsigned long ptr, *ptrp, page; + extern unsigned long *krt; + + ptr = krt[dindex >> 3]; + if (!ptr) { + ptrp = get_pointer_table(); + if (!ptrp) + return -ENOMEM; + if (krt[dindex >> 3]) { + free_pointer_table(ptrp); + ptr = krt[dindex >> 3]; + } else + krt[dindex >> 3] = VTOP(ptrp) | PAGE_TABLE; + } else + ptrp = (unsigned long *)PTOV(ptr & TABLE_MASK); + page = ptrp[16*(dindex & (NUM_L2_ENTRIES-1))]; + if (!page) { + page = (unsigned long)get_page_table (&ptrp[16*(dindex & (NUM_L2_ENTRIES-1))]); + if (!page) + return -ENOMEM; + else + mem_map[MAP_NR(page)] |= MAP_PAGE_RESERVED; + } else + page = PTOV(page & PAGE_MASK); + return page; + } + + static int alloc_area_pages(unsigned long dindex, unsigned long index, unsigned long nr) + { + unsigned long page, *pte; + + page = get_pt(dindex); + pte = index + (unsigned long *) page; + *pte = PAGE_SHARED; /* remove a race with vfree() */ + for ( ; nr > 0 ; nr--, pte++) { + unsigned long pg = get_free_page(GFP_KERNEL); + + if (!pg) + return -ENOMEM; + *pte = VTOP(pg) | PAGE_SHARED; + } + return 0; + } + + static int do_area(void * addr, unsigned long size, + int (*area_fn)(unsigned long,unsigned long,unsigned long)) + { + unsigned long nr, dindex, index; + + nr = size >> PAGE_SHIFT; + dindex = ((unsigned long) addr) >> 22; + index = (((unsigned long) addr) >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); + while (nr > 0) { + unsigned long i = PTRS_PER_PAGE - index; + + if (i > nr) + i = nr; + if (area_fn(dindex, index, i)) + return -1; + nr -= i; + index = 0; + dindex++; + } + return 0; + } + #endif + void vfree(void * addr) { struct vm_struct **p, *tmp; *************** *** 151,158 **** { void * addr; struct vm_struct **p, *tmp, *area; - - panic ("vmalloc called!\n"); size = PAGE_ALIGN(size); if (!size || size > high_memory) --- 242,247 ---- diff -cr --new-file linux-0.07pl4/net/Makefile linux-0.08/net/Makefile *** linux-0.07pl4/net/Makefile Wed Dec 31 19:00:00 1969 --- linux-0.08/net/Makefile Sat Mar 5 14:23:23 1994 *************** *** 0 **** --- 1,47 ---- + # + # Makefile for the linux networking. + # + # Note! Dependencies are done automagically by 'make dep', which also + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # + # Note 2! The CFLAGS definition is now in the main makefile... + + include ../.config + include ../MakeVars + + # only these two lines should need to be changed to remove inet sockets. + # (and the inet/tcpip.o in net.o) + + SUBDIRS := unix # inet + + SUBOBJS := $(foreach f,$(SUBDIRS),$f/$f.o) + + OBJS = Space.o ddi.o socket.o + + all: subdirs net.o + + net.o: $(OBJS) network.a + $(LD) -r -o net.o $(OBJS) network.a + + network.a: $(SUBOBJS) + rm -f $@ + $(AR) rcs $@ $(SUBOBJS) + $(RANLIB) $@ + + subdirs: dummy + set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done + + dep: + $(CPP) -M *.c > .depend + set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done + + dummy: + + # + # include a dependency file if one exists + # + ifeq (.depend,$(wildcard .depend)) + include .depend + endif + diff -cr --new-file linux-0.07pl4/net/Space.c linux-0.08/net/Space.c *** linux-0.07pl4/net/Space.c Wed Dec 31 19:00:00 1969 --- linux-0.08/net/Space.c Sat Mar 5 12:07:40 1994 *************** *** 0 **** --- 1,83 ---- + /* + * Space.c Defines which protocol modules and I/O device drivers get + * linked into the LINUX kernel. Currently, this is only used + * by the NET layer of LINUX, but it eventually might move to + * an upper directory of the system. + * + * Version: @(#)Space.c 1.0.2 04/22/93 + * + * Author: Fred N. van Kempen, + */ + #include + #include + #include + #include + + + #define CONFIG_UNIX YES /* always present... */ + + + /* + * Section A: Networking Protocol Handlers. + * This section defines which networking protocols get + * linked into the SOCKET layer of the Linux kernel. + * Currently, these are AF_UNIX (always) and AF_INET. + */ + #ifdef CONFIG_UNIX + # include "unix/unix.h" + #endif + #ifdef CONFIG_INET + # include "inet/inet.h" + #endif + + struct ddi_proto protocols[] = { + #ifdef CONFIG_UNIX + { "UNIX", unix_proto_init }, + #endif + #ifdef CONFIG_INET + { "INET", inet_proto_init }, + #endif + { NULL, NULL } + }; + + + /* + * Section B: Device Driver Modules. + * This section defines which network device drivers + * get linked into the Linux kernel. It is currently + * only used by the INET protocol. Any takers for the + * other protocols like XNS or Novell? + * + * WARNING: THIS SECTION IS NOT YET USED BY THE DRIVERS !!!!! + */ + /*#include "drv/we8003/we8003.h" Western Digital WD-80[01]3 */ + /*#include "drv/dp8390/dp8390.h" Donald Becker's DP8390 kit */ + /*#inclde "drv/slip/slip.h" Laurence Culhane's SLIP kit */ + + + struct ddi_device devices[] = { + #if CONF_WE8003 + { "WD80x3[EBT]", + "", 0, 1, we8003_init, NULL, + 19, 0, DDI_FCHRDEV, + { 0x280, 0, 15, 0, 32768, 0xD0000 } }, + #endif + #if CONF_DP8390 + { "DP8390/WD80x3", + "", 0, 1, dpwd8003_init, NULL, + 20, 0, DDI_FCHRDEV, + { 0, 0, 0, 0, 0, 0, } }, + { "DP8390/NE-x000", + "", 0, 1, dpne2000_init, NULL, + 20, 8, DDI_FCHRDEV, + { 0, 0, 0, 0, 0, 0, } }, + { "DP8390/3C50x", + "", 0, 1, dpec503_init, NULL, + 20, 16, DDI_FCHRDEV, + { 0, 0, 0, 0, 0, 0, } }, + #endif + { NULL, + "", 0, 0, NULL, NULL, + 0, 0, 0, + { 0, 0, 0, 0, 0, 0 } } + }; diff -cr --new-file linux-0.07pl4/net/ddi.c linux-0.08/net/ddi.c *** linux-0.07pl4/net/ddi.c Wed Dec 31 19:00:00 1969 --- linux-0.08/net/ddi.c Sat Mar 5 12:07:40 1994 *************** *** 0 **** --- 1,91 ---- + /* + * ddi.c Implement the Device Driver Interface (DDI) routines. + * Currently, this is only used by the NET layer of LINUX, + * but it eventually might move to an upper directory of + * the system. + * + * Version: @(#)ddi.c 1.0.5 04/22/93 + * + * Author: Fred N. van Kempen, + */ + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + + #undef DDI_DEBUG + #ifdef DDI_DEBUG + # define PRINTK(x) printk x + #else + # define PRINTK(x) /**/ + #endif + + + extern struct ddi_device devices[]; /* device driver map */ + extern struct ddi_proto protocols[]; /* network protocols */ + + + /* + * This function gets called with an ASCII string representing the + * ID of some DDI driver. We loop through the DDI Devices table + * and return the address of the control block that has a matching + * "name" field. It is used by upper-level layers that want to + * dynamically bind some UNIX-domain "/dev/XXXX" file name to a + * DDI device driver. The "iflink(8)" program is an example of + * this behaviour. + */ + struct ddi_device * + ddi_map(const char *id) + { + register struct ddi_device *dev; + + PRINTK (("DDI: MAP: looking for \"%s\": ", id)); + dev = devices; + while (dev->title != NULL) { + if (strncmp(dev->name, id, DDI_MAXNAME) == 0) { + PRINTK (("OK at 0x%X\n", dev)); + return(dev); + } + dev++; + } + PRINTK (("NOT FOUND\n")); + return(NULL); + } + + + /* + * This is the function that is called by a kernel routine during + * system startup. Its purpose is to walk trough the "devices" + * table (defined above), and to call all moduled defined in it. + */ + void + ddi_init(void) + { + struct ddi_proto *pro; + struct ddi_device *dev; + + PRINTK (("DDI: Starting up!\n")); + + /* First off, kick all configured protocols. */ + pro = protocols; + while (pro->name != NULL) { + (*pro->init)(pro); + pro++; + } + + /* Done. Now kick all configured device drivers. */ + dev = devices; + while (dev->title != NULL) { + (*dev->init)(dev); + dev++; + } + + /* We're all done... */ + } diff -cr --new-file linux-0.07pl4/net/socket.c linux-0.08/net/socket.c *** linux-0.07pl4/net/socket.c Wed Dec 31 19:00:00 1969 --- linux-0.08/net/socket.c Sat Mar 5 12:07:47 1994 *************** *** 0 **** --- 1,1082 ---- + /* + * NET An implementation of the SOCKET network access protocol. + * + * Version: @(#)socket.c 1.0.5 05/25/93 + * + * Authors: Orest Zborowski, + * Ross Biro, + * Fred N. van Kempen, + * + * Fixes: + * Anonymous : NOTSOCK/BADF cleanup. Error fix in + * shutdown() + * Alan Cox : verify_area() fixes + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + + #undef SOCK_DEBUG + + #ifdef SOCK_DEBUG + #include + #define DPRINTF(x) dprintf x + #else + #define DPRINTF(x) /**/ + #endif + + static int sock_lseek(struct inode *inode, struct file *file, off_t offset, + int whence); + static int sock_read(struct inode *inode, struct file *file, char *buf, + int size); + static int sock_write(struct inode *inode, struct file *file, char *buf, + int size); + static int sock_readdir(struct inode *inode, struct file *file, + struct dirent *dirent, int count); + static void sock_close(struct inode *inode, struct file *file); + static int sock_select(struct inode *inode, struct file *file, int which, select_table *seltable); + static int sock_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + + + static struct file_operations socket_file_ops = { + sock_lseek, + sock_read, + sock_write, + sock_readdir, + sock_select, + sock_ioctl, + NULL, /* mmap */ + NULL, /* no special open code... */ + sock_close + }; + struct socket sockets[NSOCKETS]; + static struct wait_queue *socket_wait_free = NULL; + static struct proto_ops *pops[NPROTO]; + static int net_debug = 0; + + + #ifdef SOCK_DEBUG + /* Module debugging. */ + static void + dprintf(int level, char *fmt, ...) + { + char buff[1024]; + va_list args; + extern int vsprintf(char * buf, const char * fmt, va_list args); + + if (level == 0) return; + va_start(args, fmt); + vsprintf(buff, fmt, args); + va_end(args); + printk(buff); + } + #endif + + /* Obtains the first available file descriptor and sets it up for use. */ + static int + get_fd(struct inode *inode) + { + int fd; + struct file *file; + + /* Find a file descriptor suitable for return to the user. */ + file = get_empty_filp(); + if (!file) return(-1); + for (fd = 0; fd < NR_OPEN; ++fd) + if (!current->filp[fd]) break; + if (fd == NR_OPEN) { + file->f_count = 0; + return(-1); + } + FD_CLR(fd, ¤t->close_on_exec); + current->filp[fd] = file; + file->f_op = &socket_file_ops; + file->f_mode = 3; + file->f_flags = 0; + file->f_count = 1; + file->f_inode = inode; + if (inode) inode->i_count++; + file->f_pos = 0; + return(fd); + } + + + /* + * Reverses the action of get_fd() by releasing the file. it closes + * the descriptor, but makes sure it does nothing more. Called when + * an incomplete socket must be closed, along with sock_release(). + */ + static inline void + toss_fd(int fd) + { + sys_close(fd); /* the count protects us from iput */ + } + + + struct socket * + socki_lookup(struct inode *inode) + { + struct socket *sock; + + for (sock = sockets; sock <= last_socket; ++sock) + if (sock->state != SS_FREE && SOCK_INODE(sock) == inode) return(sock); + return(NULL); + } + + + static inline struct socket * + sockfd_lookup(int fd, struct file **pfile) + { + struct file *file; + + if (fd < 0 || fd >= NR_OPEN || !(file = current->filp[fd])) return(NULL); + if (pfile) *pfile = file; + return(socki_lookup(file->f_inode)); + } + + + static struct socket * + sock_alloc(int wait) + { + struct socket *sock; + + while (1) { + cli(); + for (sock = sockets; sock <= last_socket; ++sock) { + if (sock->state == SS_FREE) { + sock->state = SS_UNCONNECTED; + sti(); + sock->flags = 0; + sock->ops = NULL; + sock->data = NULL; + sock->conn = NULL; + sock->iconn = NULL; + + /* + * This really shouldn't be necessary, but everything + * else depends on inodes, so we grab it. + * Sleeps are also done on the i_wait member of this + * inode. The close system call will iput this inode + * for us. + */ + if (!(SOCK_INODE(sock) = get_empty_inode())) { + printk("NET: sock_alloc: no more inodes\n"); + sock->state = SS_FREE; + return(NULL); + } + SOCK_INODE(sock)->i_mode = S_IFSOCK; + SOCK_INODE(sock)->i_uid = current->euid; + SOCK_INODE(sock)->i_gid = current->egid; + + sock->wait = &SOCK_INODE(sock)->i_wait; + DPRINTF((net_debug, + "NET: sock_alloc: sk 0x%x, ino 0x%x\n", + sock, SOCK_INODE(sock))); + return(sock); + } + } + sti(); + if (!wait) return(NULL); + DPRINTF((net_debug, "NET: sock_alloc: no free sockets, sleeping...\n")); + interruptible_sleep_on(&socket_wait_free); + if (current->signal & ~current->blocked) { + DPRINTF((net_debug, "NET: sock_alloc: sleep was interrupted\n")); + return(NULL); + } + DPRINTF((net_debug, "NET: sock_alloc: wakeup... trying again...\n")); + } + } + + + static inline void + sock_release_peer(struct socket *peer) + { + peer->state = SS_DISCONNECTING; + wake_up(peer->wait); + } + + + static void + sock_release(struct socket *sock) + { + int oldstate; + struct socket *peersock, *nextsock; + + DPRINTF((net_debug, "NET: sock_release: socket 0x%x, inode 0x%x\n", + sock, SOCK_INODE(sock))); + if ((oldstate = sock->state) != SS_UNCONNECTED) + sock->state = SS_DISCONNECTING; + + /* Wake up anyone waiting for connections. */ + for (peersock = sock->iconn; peersock; peersock = nextsock) { + nextsock = peersock->next; + sock_release_peer(peersock); + } + + /* + * Wake up anyone we're connected to. First, we release the + * protocol, to give it a chance to flush data, etc. + */ + peersock = (oldstate == SS_CONNECTED) ? sock->conn : NULL; + if (sock->ops) sock->ops->release(sock, peersock); + if (peersock) sock_release_peer(peersock); + sock->state = SS_FREE; /* this really releases us */ + wake_up(&socket_wait_free); + + /* We need to do this. If sock alloc was called we already have an inode. */ + iput(SOCK_INODE(sock)); + } + + + static int + sock_lseek(struct inode *inode, struct file *file, off_t offset, int whence) + { + DPRINTF((net_debug, "NET: sock_lseek: huh?\n")); + return(-ESPIPE); + } + + + static int + sock_read(struct inode *inode, struct file *file, char *ubuf, int size) + { + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_read: buf=0x%x, size=%d\n", ubuf, size)); + if (!(sock = socki_lookup(inode))) { + printk("NET: sock_read: can't find socket for inode!\n"); + return(-EBADF); + } + if (sock->flags & SO_ACCEPTCON) return(-EINVAL); + return(sock->ops->read(sock, ubuf, size, (file->f_flags & O_NONBLOCK))); + } + + + static int + sock_write(struct inode *inode, struct file *file, char *ubuf, int size) + { + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_write: buf=0x%x, size=%d\n", ubuf, size)); + if (!(sock = socki_lookup(inode))) { + printk("NET: sock_write: can't find socket for inode!\n"); + return(-EBADF); + } + if (sock->flags & SO_ACCEPTCON) return(-EINVAL); + return(sock->ops->write(sock, ubuf, size,(file->f_flags & O_NONBLOCK))); + } + + + static int + sock_readdir(struct inode *inode, struct file *file, struct dirent *dirent, + int count) + { + DPRINTF((net_debug, "NET: sock_readdir: huh?\n")); + return(-EBADF); + } + + + int + sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) + { + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_ioctl: inode=0x%x cmd=0x%x arg=%d\n", + inode, cmd, arg)); + if (!(sock = socki_lookup(inode))) { + printk("NET: sock_ioctl: can't find socket for inode!\n"); + return(-EBADF); + } + return(sock->ops->ioctl(sock, cmd, arg)); + } + + + static int + sock_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) + { + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_select: inode = 0x%x, kind = %s\n", inode, + (sel_type == SEL_IN) ? "in" : + (sel_type == SEL_OUT) ? "out" : "ex")); + if (!(sock = socki_lookup(inode))) { + printk("NET: sock_select: can't find socket for inode!\n"); + return(0); + } + + /* We can't return errors to select, so its either yes or no. */ + if (sock->ops && sock->ops->select) + return(sock->ops->select(sock, sel_type, wait)); + return(0); + } + + + void + sock_close(struct inode *inode, struct file *file) + { + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_close: inode=0x%x (cnt=%d)\n", + inode, inode->i_count)); + + /* It's possible the inode is NULL if we're closing an unfinished socket. */ + if (!inode) return; + if (!(sock = socki_lookup(inode))) { + printk("NET: sock_close: can't find socket for inode!\n"); + return; + } + sock_release(sock); + } + + + int + sock_awaitconn(struct socket *mysock, struct socket *servsock) + { + struct socket *last; + + DPRINTF((net_debug, + "NET: sock_awaitconn: trying to connect socket 0x%x to 0x%x\n", + mysock, servsock)); + if (!(servsock->flags & SO_ACCEPTCON)) { + DPRINTF((net_debug, + "NET: sock_awaitconn: server not accepting connections\n")); + return(-EINVAL); + } + + /* Put ourselves on the server's incomplete connection queue. */ + mysock->next = NULL; + cli(); + if (!(last = servsock->iconn)) servsock->iconn = mysock; + else { + while (last->next) last = last->next; + last->next = mysock; + } + mysock->state = SS_CONNECTING; + mysock->conn = servsock; + sti(); + + /* + * Wake up server, then await connection. server will set state to + * SS_CONNECTED if we're connected. + */ + wake_up(servsock->wait); + if (mysock->state != SS_CONNECTED) { + interruptible_sleep_on(mysock->wait); + if (mysock->state != SS_CONNECTED && + mysock->state != SS_DISCONNECTING) { + /* + * if we're not connected we could have been + * 1) interrupted, so we need to remove ourselves + * from the server list + * 2) rejected (mysock->conn == NULL), and have + * already been removed from the list + */ + if (mysock->conn == servsock) { + cli(); + if ((last = servsock->iconn) == mysock) + servsock->iconn = mysock->next; + else { + while (last->next != mysock) last = last->next; + last->next = mysock->next; + } + sti(); + } + return(mysock->conn ? -EINTR : -EACCES); + } + } + return(0); + } + + + /* + * Perform the socket system call. we locate the appropriate + * family, then create a fresh socket. + */ + static int + sock_socket(int family, int type, int protocol) + { + int i, fd; + struct socket *sock; + struct proto_ops *ops; + + DPRINTF((net_debug, + "NET: sock_socket: family = %d, type = %d, protocol = %d\n", + family, type, protocol)); + + /* Locate the correct protocol family. */ + for (i = 0; i < NPROTO; ++i) { + if (pops[i] == NULL) continue; + if (pops[i]->family == family) break; + } + if (i == NPROTO) { + DPRINTF((net_debug, "NET: sock_socket: family not found\n")); + return(-EINVAL); + } + ops = pops[i]; + + /* + * Check that this is a type that we know how to manipulate and + * the protocol makes sense here. The family can still reject the + * protocol later. + */ + if ((type != SOCK_STREAM && type != SOCK_DGRAM && + type != SOCK_SEQPACKET && type != SOCK_RAW && + type != SOCK_PACKET) || protocol < 0) + return(-EINVAL); + + /* + * allocate the socket and allow the family to set things up. if + * the protocol is 0, the family is instructed to select an appropriate + * default. + */ + if (!(sock = sock_alloc(1))) { + printk("sock_socket: no more sockets\n"); + return(-EAGAIN); + } + sock->type = type; + sock->ops = ops; + if ((i = sock->ops->create(sock, protocol)) < 0) { + sock_release(sock); + return(i); + } + + if ((fd = get_fd(SOCK_INODE(sock))) < 0) { + sock_release(sock); + return(-EINVAL); + } + + return(fd); + } + + + static int + sock_socketpair(int family, int type, int protocol, unsigned long usockvec[2]) + { + int fd1, fd2, i; + struct socket *sock1, *sock2; + int er; + + DPRINTF((net_debug, + "NET: sock_socketpair: family = %d, type = %d, protocol = %d\n", + family, type, protocol)); + + /* + * Obtain the first socket and check if the underlying protocol + * supports the socketpair call. + */ + if ((fd1 = sock_socket(family, type, protocol)) < 0) return(fd1); + sock1 = sockfd_lookup(fd1, NULL); + if (!sock1->ops->socketpair) { + sys_close(fd1); + return(-EINVAL); + } + + /* Now grab another socket and try to connect the two together. */ + if ((fd2 = sock_socket(family, type, protocol)) < 0) { + sys_close(fd1); + return(-EINVAL); + } + sock2 = sockfd_lookup(fd2, NULL); + if ((i = sock1->ops->socketpair(sock1, sock2)) < 0) { + sys_close(fd1); + sys_close(fd2); + return(i); + } + sock1->conn = sock2; + sock2->conn = sock1; + sock1->state = SS_CONNECTED; + sock2->state = SS_CONNECTED; + + er=verify_area(VERIFY_WRITE, usockvec, 2 * sizeof(int)); + if(er) + return er; + put_fs_long(fd1, &usockvec[0]); + put_fs_long(fd2, &usockvec[1]); + + return(0); + } + + + /* + * Bind a name to a socket. Nothing much to do here since its + * the protocol's responsibility to handle the local address. + */ + static int + sock_bind(int fd, struct sockaddr *umyaddr, int addrlen) + { + struct socket *sock; + int i; + + DPRINTF((net_debug, "NET: sock_bind: fd = %d\n", fd)); + if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + if ((i = sock->ops->bind(sock, umyaddr, addrlen)) < 0) { + DPRINTF((net_debug, "NET: sock_bind: bind failed\n")); + return(i); + } + return(0); + } + + + /* + * Perform a listen. Basically, we allow the protocol to do anything + * necessary for a listen, and if that works, we mark the socket as + * ready for listening. + */ + static int + sock_listen(int fd, int backlog) + { + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_listen: fd = %d\n", fd)); + if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + if (sock->state != SS_UNCONNECTED) { + DPRINTF((net_debug, "NET: sock_listen: socket isn't unconnected\n")); + return(-EINVAL); + } + if (sock->ops && sock->ops->listen) sock->ops->listen(sock, backlog); + sock->flags |= SO_ACCEPTCON; + return(0); + } + + + /* + * For accept, we attempt to create a new socket, set up the link + * with the client, wake up the client, then return the new + * connected fd. + */ + static int + sock_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen) + { + struct file *file; + struct socket *sock, *newsock; + int i; + + DPRINTF((net_debug, "NET: sock_accept: fd = %d\n", fd)); + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + + if (!(sock = sockfd_lookup(fd, &file))) return(-ENOTSOCK); + if (sock->state != SS_UNCONNECTED) { + DPRINTF((net_debug, "NET: sock_accept: socket isn't unconnected\n")); + return(-EINVAL); + } + if (!(sock->flags & SO_ACCEPTCON)) { + DPRINTF((net_debug, + "NET: sock_accept: socket not accepting connections!\n")); + return(-EINVAL); + } + + if (!(newsock = sock_alloc(0))) { + printk("NET: sock_accept: no more sockets\n"); + return(-EAGAIN); + } + newsock->type = sock->type; + newsock->ops = sock->ops; + if ((i = sock->ops->dup(newsock, sock)) < 0) { + sock_release(newsock); + return(i); + } + + i = newsock->ops->accept(sock, newsock, file->f_flags); + if ( i < 0) { + sock_release(newsock); + return(i); + } + + if ((fd = get_fd(SOCK_INODE(newsock))) < 0) { + sock_release(newsock); + return(-EINVAL); + } + + DPRINTF((net_debug, "NET: sock_accept: connected socket 0x%x via 0x%x\n", + sock, newsock)); + + if (upeer_sockaddr) + newsock->ops->getname(newsock, upeer_sockaddr, upeer_addrlen, 1); + + return(fd); + } + + + /* Attempt to connect to a socket with the server address. */ + static int + sock_connect(int fd, struct sockaddr *uservaddr, int addrlen) + { + struct socket *sock; + struct file *file; + int i; + + DPRINTF((net_debug, "NET: sock_connect: fd = %d\n", fd)); + if (fd < 0 || fd >= NR_OPEN || (file=current->filp[fd]) == NULL) + return(-EBADF); + + if (!(sock = sockfd_lookup(fd, &file))) return(-ENOTSOCK); + switch(sock->state) { + case SS_UNCONNECTED: + /* This is ok... continue with connect */ + break; + case SS_CONNECTED: + /* Socket is already connected */ + return -EISCONN; + case SS_CONNECTING: + /* Not yet connected... we will check this. */ + return(sock->ops->connect(sock, uservaddr, + addrlen, file->f_flags)); + default: + DPRINTF((net_debug, + "NET: sock_connect: socket not unconnected\n")); + return(-EINVAL); + } + i = sock->ops->connect(sock, uservaddr, addrlen, file->f_flags); + if (i < 0) { + DPRINTF((net_debug, "NET: sock_connect: connect failed\n")); + return(i); + } + return(0); + } + + + static int + sock_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len) + { + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_getsockname: fd = %d\n", fd)); + if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + return(sock->ops->getname(sock, usockaddr, usockaddr_len, 0)); + } + + + static int + sock_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len) + { + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_getpeername: fd = %d\n", fd)); + if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + return(sock->ops->getname(sock, usockaddr, usockaddr_len, 1)); + } + + + static int + sock_send(int fd, void * buff, int len, unsigned flags) + { + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, + "NET: sock_send(fd = %d, buff = %X, len = %d, flags = %X)\n", + fd, buff, len, flags)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + return(sock->ops->send(sock, buff, len, (file->f_flags & O_NONBLOCK), flags)); + } + + + static int + sock_sendto(int fd, void * buff, int len, unsigned flags, + struct sockaddr *addr, int addr_len) + { + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, + "NET: sock_sendto(fd = %d, buff = %X, len = %d, flags = %X," + " addr=%X, alen = %d\n", fd, buff, len, flags, addr, addr_len)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + return(sock->ops->sendto(sock, buff, len, (file->f_flags & O_NONBLOCK), + flags, addr, addr_len)); + } + + + static int + sock_recv(int fd, void * buff, int len, unsigned flags) + { + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, + "NET: sock_recv(fd = %d, buff = %X, len = %d, flags = %X)\n", + fd, buff, len, flags)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + return(sock->ops->recv(sock, buff, len,(file->f_flags & O_NONBLOCK), flags)); + } + + + static int + sock_recvfrom(int fd, void * buff, int len, unsigned flags, + struct sockaddr *addr, int *addr_len) + { + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, + "NET: sock_recvfrom(fd = %d, buff = %X, len = %d, flags = %X," + " addr=%X, alen=%X\n", fd, buff, len, flags, addr, addr_len)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + return(sock->ops->recvfrom(sock, buff, len, (file->f_flags & O_NONBLOCK), + flags, addr, addr_len)); + } + + + static int + sock_setsockopt(int fd, int level, int optname, char *optval, int optlen) + { + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, "NET: sock_setsockopt(fd=%d, level=%d, optname=%d,\n", + fd, level, optname)); + DPRINTF((net_debug, " optval = %X, optlen = %d)\n", + optval, optlen)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + return(sock->ops->setsockopt(sock, level, optname, optval, optlen)); + } + + + static int + sock_getsockopt(int fd, int level, int optname, char *optval, int *optlen) + { + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, "NET: sock_getsockopt(fd=%d, level=%d, optname=%d,\n", + fd, level, optname)); + DPRINTF((net_debug, " optval = %X, optlen = %X)\n", + optval, optlen)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + if (!sock->ops || !sock->ops->getsockopt) return(0); + return(sock->ops->getsockopt(sock, level, optname, optval, optlen)); + } + + + static int + sock_shutdown(int fd, int how) + { + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, "NET: sock_shutdown(fd = %d, how = %d)\n", fd, how)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + return(sock->ops->shutdown(sock, how)); + } + + + int + sock_fcntl(struct file *filp, unsigned int cmd, unsigned long arg) + { + struct socket *sock; + + sock = socki_lookup (filp->f_inode); + if (sock != NULL && sock->ops != NULL && sock->ops->fcntl != NULL) + return(sock->ops->fcntl(sock, cmd, arg)); + return(-EINVAL); + } + + + /* + * System call vectors. Since I (RIB) want to rewrite sockets as streams, + * we have this level of indirection. Not a lot of overhead, since more of + * the work is done via read/write/select directly. + */ + asmlinkage int + sys_socketcall(int call, unsigned long *args) + { + int er; + switch(call) { + case SYS_SOCKET: + er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); + if(er) + return er; + return(sock_socket(get_fs_long(args+0), + get_fs_long(args+1), + get_fs_long(args+2))); + case SYS_BIND: + er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); + if(er) + return er; + return(sock_bind(get_fs_long(args+0), + (struct sockaddr *)get_fs_long(args+1), + get_fs_long(args+2))); + case SYS_CONNECT: + er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); + if(er) + return er; + return(sock_connect(get_fs_long(args+0), + (struct sockaddr *)get_fs_long(args+1), + get_fs_long(args+2))); + case SYS_LISTEN: + er=verify_area(VERIFY_READ, args, 2 * sizeof(long)); + if(er) + return er; + return(sock_listen(get_fs_long(args+0), + get_fs_long(args+1))); + case SYS_ACCEPT: + er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); + if(er) + return er; + return(sock_accept(get_fs_long(args+0), + (struct sockaddr *)get_fs_long(args+1), + (int *)get_fs_long(args+2))); + case SYS_GETSOCKNAME: + er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); + if(er) + return er; + return(sock_getsockname(get_fs_long(args+0), + (struct sockaddr *)get_fs_long(args+1), + (int *)get_fs_long(args+2))); + case SYS_GETPEERNAME: + er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); + if(er) + return er; + return(sock_getpeername(get_fs_long(args+0), + (struct sockaddr *)get_fs_long(args+1), + (int *)get_fs_long(args+2))); + case SYS_SOCKETPAIR: + er=verify_area(VERIFY_READ, args, 4 * sizeof(long)); + if(er) + return er; + return(sock_socketpair(get_fs_long(args+0), + get_fs_long(args+1), + get_fs_long(args+2), + (unsigned long *)get_fs_long(args+3))); + case SYS_SEND: + er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long)); + if(er) + return er; + return(sock_send(get_fs_long(args+0), + (void *)get_fs_long(args+1), + get_fs_long(args+2), + get_fs_long(args+3))); + case SYS_SENDTO: + er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long)); + if(er) + return er; + return(sock_sendto(get_fs_long(args+0), + (void *)get_fs_long(args+1), + get_fs_long(args+2), + get_fs_long(args+3), + (struct sockaddr *)get_fs_long(args+4), + get_fs_long(args+5))); + case SYS_RECV: + er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long)); + if(er) + return er; + return(sock_recv(get_fs_long(args+0), + (void *)get_fs_long(args+1), + get_fs_long(args+2), + get_fs_long(args+3))); + case SYS_RECVFROM: + er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long)); + if(er) + return er; + return(sock_recvfrom(get_fs_long(args+0), + (void *)get_fs_long(args+1), + get_fs_long(args+2), + get_fs_long(args+3), + (struct sockaddr *)get_fs_long(args+4), + (int *)get_fs_long(args+5))); + case SYS_SHUTDOWN: + er=verify_area(VERIFY_READ, args, 2* sizeof(unsigned long)); + if(er) + return er; + return(sock_shutdown(get_fs_long(args+0), + get_fs_long(args+1))); + case SYS_SETSOCKOPT: + er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long)); + if(er) + return er; + return(sock_setsockopt(get_fs_long(args+0), + get_fs_long(args+1), + get_fs_long(args+2), + (char *)get_fs_long(args+3), + get_fs_long(args+4))); + case SYS_GETSOCKOPT: + er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long)); + if(er) + return er; + return(sock_getsockopt(get_fs_long(args+0), + get_fs_long(args+1), + get_fs_long(args+2), + (char *)get_fs_long(args+3), + (int *)get_fs_long(args+4))); + default: + return(-EINVAL); + } + } + + + static int + net_ioctl(unsigned int cmd, unsigned long arg) + { + int er; + switch(cmd) { + case DDIOCSDBG: + er=verify_area(VERIFY_READ, (void *)arg, sizeof(long)); + if(er) + return er; + net_debug = get_fs_long((long *)arg); + if (net_debug != 0 && net_debug != 1) { + net_debug = 0; + return(-EINVAL); + } + return(0); + default: + return(-EINVAL); + } + /*NOTREACHED*/ + return(0); + } + + + /* + * Handle the IOCTL system call for the NET devices. This basically + * means I/O control for the SOCKET layer (future expansions could be + * a variable number of socket table entries, et al), and for the more + * general protocols like ARP. The latter currently lives in the INET + * module, so we have to get ugly a tiny little bit. Later... -FvK + */ + static int + net_fioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) + { + extern int arp_ioctl(unsigned int, void *); + + /* Dispatch on the minor device. */ + switch(MINOR(inode->i_rdev)) { + case 0: /* NET (SOCKET) */ + DPRINTF((net_debug, "NET: SOCKET level I/O control request.\n")); + return(net_ioctl(cmd, arg)); + #ifdef CONFIG_INET + case 1: /* ARP */ + DPRINTF((net_debug, "NET: ARP level I/O control request.\n")); + return(arp_ioctl(cmd, (void *) arg)); + #endif + default: + return(-ENODEV); + } + /*NOTREACHED*/ + return(-EINVAL); + } + + + static struct file_operations net_fops = { + NULL, /* LSEEK */ + NULL, /* READ */ + NULL, /* WRITE */ + NULL, /* READDIR */ + NULL, /* SELECT */ + net_fioctl, /* IOCTL */ + NULL, /* MMAP */ + NULL, /* OPEN */ + NULL /* CLOSE */ + }; + + + /* + * This function is called by a protocol handler that wants to + * advertise its address family, and have it linked into the + * SOCKET module. + */ + int + sock_register(int family, struct proto_ops *ops) + { + int i; + + cli(); + for(i = 0; i < NPROTO; i++) { + if (pops[i] != NULL) continue; + pops[i] = ops; + pops[i]->family = family; + sti(); + DPRINTF((net_debug, "NET: Installed protocol %d in slot %d (0x%X)\n", + family, i, (long)ops)); + return(i); + } + sti(); + return(-ENOMEM); + } + + + void + sock_init(void) + { + struct socket *sock; + int i; + + /* Set up our SOCKET VFS major device. */ + if (register_chrdev(SOCKET_MAJOR, "socket", &net_fops) < 0) { + printk("NET: cannot register major device %d!\n", SOCKET_MAJOR); + return; + } + + /* Release all sockets. */ + for (sock = sockets; sock <= last_socket; ++sock) sock->state = SS_FREE; + + /* Initialize all address (protocol) families. */ + for (i = 0; i < NPROTO; ++i) pops[i] = NULL; + + /* Initialize the DDI module. */ + ddi_init(); + + /* Initialize the ARP module. */ + #if 0 + arp_init(); + #endif + } diff -cr --new-file linux-0.07pl4/net/unix/Makefile linux-0.08/net/unix/Makefile *** linux-0.07pl4/net/unix/Makefile Wed Dec 31 19:00:00 1969 --- linux-0.08/net/unix/Makefile Sat Mar 5 12:49:39 1994 *************** *** 0 **** --- 1,26 ---- + # + # Makefile for the UNIX Protocol Family. + # + # Note! Dependencies are done automagically by 'make dep', which also + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # + # Note 2! The CFLAGS definition is now in the main makefile... + + include ../../.config + include ../../MakeVars + + OBJS = sock.o proc.o + + unix.o: $(OBJS) + $(LD) -r -o unix.o $(OBJS) + + dep: + $(CPP) -M *.c > .depend + + # + # include a dependency file if one exists + # + ifeq (.depend,$(wildcard .depend)) + include .depend + endif diff -cr --new-file linux-0.07pl4/net/unix/proc.c linux-0.08/net/unix/proc.c *** linux-0.07pl4/net/unix/proc.c Wed Dec 31 19:00:00 1969 --- linux-0.08/net/unix/proc.c Sat Mar 5 12:07:47 1994 *************** *** 0 **** --- 1,78 ---- + /* + * UNIX An implementation of the AF_UNIX network domain for the + * LINUX operating system. UNIX is implemented using the + * BSD Socket interface as the means of communication with + * the user level. + * + * The functions in this file provide an interface between + * the PROC file system and the "unix" family of networking + * protocols. It is mainly used for debugging and statistics. + * + * Version: @(#)proc.c 1.0.4 05/23/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Gerald J. Heim, + * Fred Baumgarten, + * + * Fixes: + * Andriews Brouwer : Comment errors + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + #include + #include + #include + #include + #include + #include + #include + #include + #include "unix.h" + + + /* Called from PROCfs. */ + int unix_get_info(char *buffer) + { + char *pos; + int i; + + pos = buffer; + pos += sprintf(pos, "Num RefCount Protocol Flags Type St Path\n"); + + for(i = 0; i < NSOCKETS; i++) { + if (unix_datas[i].refcnt) { + pos += sprintf(pos, "%2d: %08X %08X %08lX %04X %02X", i, + unix_datas[i].refcnt, + unix_datas[i].protocol, + unix_datas[i].socket->flags, + unix_datas[i].socket->type, + unix_datas[i].socket->state + ); + + /* If socket is bound to a filename, we'll print it. */ + if(unix_datas[i].sockaddr_len>0) { + pos += sprintf(pos, " %s\n", + unix_datas[i].sockaddr_un.sun_path); + } else { /* just add a newline */ + *pos='\n'; + pos++; + *pos='\0'; + } + + /* + * Check whether buffer _may_ overflow in the next loop. + * Since sockets may have very very long paths, we make + * PATH_MAX+80 the minimum space left for a new line. + */ + if (pos > buffer+PAGE_SIZE-80-PATH_MAX) { + printk("UNIX: netinfo: oops, too many sockets.\n"); + return(pos - buffer); + } + } + } + return(pos - buffer); + } diff -cr --new-file linux-0.07pl4/net/unix/sock.c linux-0.08/net/unix/sock.c *** linux-0.07pl4/net/unix/sock.c Wed Dec 31 19:00:00 1969 --- linux-0.08/net/unix/sock.c Mon Mar 14 17:34:49 1994 *************** *** 0 **** --- 1,902 ---- + /* + * UNIX An implementation of the AF_UNIX network domain for the + * LINUX operating system. UNIX is implemented using the + * BSD Socket interface as the means of communication with + * the user level. + * + * Version: @(#)sock.c 1.0.5 05/25/93 + * + * Authors: Orest Zborowski, + * Ross Biro, + * Fred N. van Kempen, + * + * Fixes: + * Alan Cox : Verify Area + * + * BUGS + * Page faults on read while another process reads could lose data. + * Page faults on write happen to interleave data (probably not allowed) + * with any other simultaneous writers on the socket but dont cause harm. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or(at your option) any later version. + */ + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + + #include + + #include "unix.h" + + struct unix_proto_data unix_datas[NSOCKETS]; + static int unix_debug = 0; + + + static int unix_proto_create(struct socket *sock, int protocol); + static int unix_proto_dup(struct socket *newsock, struct socket *oldsock); + static int unix_proto_release(struct socket *sock, struct socket *peer); + static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr, + int sockaddr_len); + static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr, + int sockaddr_len, int flags); + static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2); + static int unix_proto_accept(struct socket *sock, struct socket *newsock, + int flags); + static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr, + int *usockaddr_len, int peer); + static int unix_proto_read(struct socket *sock, char *ubuf, int size, + int nonblock); + static int unix_proto_write(struct socket *sock, char *ubuf, int size, + int nonblock); + static int unix_proto_select(struct socket *sock, int sel_type, select_table * wait); + static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg); + static int unix_proto_listen(struct socket *sock, int backlog); + static int unix_proto_send(struct socket *sock, void *buff, int len, + int nonblock, unsigned flags); + static int unix_proto_recv(struct socket *sock, void *buff, int len, + int nonblock, unsigned flags); + static int unix_proto_sendto(struct socket *sock, void *buff, int len, + int nonblock, unsigned flags, + struct sockaddr *addr, int addr_len); + static int unix_proto_recvfrom(struct socket *sock, void *buff, int len, + int nonblock, unsigned flags, + struct sockaddr *addr, int *addr_len); + + static int unix_proto_shutdown(struct socket *sock, int how); + + static int unix_proto_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen); + static int unix_proto_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen); + + + static void + dprintf(int level, char *fmt, ...) + { + va_list args; + char *buff; + extern int vsprintf(char * buf, const char * fmt, va_list args); + + if (level != unix_debug) return; + + buff = (char *) kmalloc(256, GFP_KERNEL); + if (buff != NULL) { + va_start(args, fmt); + vsprintf(buff, fmt, args); + va_end(args); + printk(buff); + kfree(buff); + } + } + + + static inline int + min(int a, int b) + { + if (a < b) return(a); + return(b); + } + + + void + sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len) + { + char buf[sizeof(sockun->sun_path) + 1]; + + if (unix_debug == 0) return; + + sockaddr_len -= UN_PATH_OFFSET; + if (sockun->sun_family != AF_UNIX) + printk("UNIX: Badd addr family %d>\n", sockun->sun_family); + else if (sockaddr_len <= 0 || sockaddr_len >= sizeof(buf)) + printk("UNIX: Bad addr len %d>\n", sockaddr_len); + else { + memcpy(buf, sockun->sun_path, sockaddr_len); + buf[sockaddr_len] = '\0'; + printk("\"%s\"[%lu]\n", buf, sockaddr_len + UN_PATH_OFFSET); + } + } + + + /* don't have to do anything. */ + static int + unix_proto_listen(struct socket *sock, int backlog) + { + return(0); + } + + + static int + unix_proto_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen) + { + return(-EOPNOTSUPP); + } + + + static int + unix_proto_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen) + { + return(-EOPNOTSUPP); + } + + static int + unix_proto_sendto(struct socket *sock, void *buff, int len, int nonblock, + unsigned flags, struct sockaddr *addr, int addr_len) + { + return(-EOPNOTSUPP); + } + + static int + unix_proto_recvfrom(struct socket *sock, void *buff, int len, int nonblock, + unsigned flags, struct sockaddr *addr, int *addr_len) + { + return(-EOPNOTSUPP); + } + + + static int + unix_proto_shutdown(struct socket *sock, int how) + { + return(-EOPNOTSUPP); + } + + + /* This error needs to be checked. */ + static int + unix_proto_send(struct socket *sock, void *buff, int len, int nonblock, + unsigned flags) + { + if (flags != 0) return(-EINVAL); + return(unix_proto_write(sock, (char *) buff, len, nonblock)); + } + + + /* This error needs to be checked. */ + static int + unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock, + unsigned flags) + { + if (flags != 0) return(-EINVAL); + return(unix_proto_read(sock, (char *) buff, len, nonblock)); + } + + + static struct unix_proto_data * + unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len, + struct inode *inode) + { + struct unix_proto_data *upd; + + for(upd = unix_datas; upd <= last_unix_data; ++upd) { + if (upd->refcnt && upd->socket && + upd->socket->state == SS_UNCONNECTED && + upd->sockaddr_un.sun_family == sockun->sun_family && + upd->inode == inode) return(upd); + } + return(NULL); + } + + + static struct unix_proto_data * + unix_data_alloc(void) + { + struct unix_proto_data *upd; + + cli(); + for(upd = unix_datas; upd <= last_unix_data; ++upd) { + if (!upd->refcnt) { + upd->refcnt = 1; + sti(); + upd->socket = NULL; + upd->sockaddr_len = 0; + upd->sockaddr_un.sun_family = 0; + upd->buf = NULL; + upd->bp_head = upd->bp_tail = 0; + upd->inode = NULL; + upd->peerupd = NULL; + return(upd); + } + } + sti(); + return(NULL); + } + + + static inline void + unix_data_ref(struct unix_proto_data *upd) + { + if (!upd) { + dprintf(1, "UNIX: data_ref: upd = NULL\n"); + return; + } + ++upd->refcnt; + dprintf(1, "UNIX: data_ref: refing data 0x%x(%d)\n", upd, upd->refcnt); + } + + + static void + unix_data_deref(struct unix_proto_data *upd) + { + if (!upd) { + dprintf(1, "UNIX: data_deref: upd = NULL\n"); + return; + } + if (upd->refcnt == 1) { + dprintf(1, "UNIX: data_deref: releasing data 0x%x\n", upd); + if (upd->buf) { + free_page((unsigned long)upd->buf); + upd->buf = NULL; + upd->bp_head = upd->bp_tail = 0; + } + } + --upd->refcnt; + } + + + /* + * Upon a create, we allocate an empty protocol data, + * and grab a page to buffer writes. + */ + static int + unix_proto_create(struct socket *sock, int protocol) + { + struct unix_proto_data *upd; + + dprintf(1, "UNIX: create: socket 0x%x, proto %d\n", sock, protocol); + if (protocol != 0) { + dprintf(1, "UNIX: create: protocol != 0\n"); + return(-EINVAL); + } + if (!(upd = unix_data_alloc())) { + printk("UNIX: create: can't allocate buffer\n"); + return(-ENOMEM); + } + if (!(upd->buf = (char*) get_free_page(GFP_USER))) { + printk("UNIX: create: can't get page!\n"); + unix_data_deref(upd); + return(-ENOMEM); + } + upd->protocol = protocol; + upd->socket = sock; + UN_DATA(sock) = upd; + dprintf(1, "UNIX: create: allocated data 0x%x\n", upd); + return(0); + } + + + static int + unix_proto_dup(struct socket *newsock, struct socket *oldsock) + { + struct unix_proto_data *upd = UN_DATA(oldsock); + + return(unix_proto_create(newsock, upd->protocol)); + } + + + static int + unix_proto_release(struct socket *sock, struct socket *peer) + { + struct unix_proto_data *upd = UN_DATA(sock); + + dprintf(1, "UNIX: release: socket 0x%x, unix_data 0x%x\n", sock, upd); + if (!upd) return(0); + if (upd->socket != sock) { + printk("UNIX: release: socket link mismatch!\n"); + return(-EINVAL); + } + if (upd->inode) { + dprintf(1, "UNIX: release: releasing inode 0x%x\n", upd->inode); + iput(upd->inode); + upd->inode = NULL; + } + UN_DATA(sock) = NULL; + upd->socket = NULL; + if (upd->peerupd) unix_data_deref(upd->peerupd); + unix_data_deref(upd); + return(0); + } + + + /* + * Bind a name to a socket. + * This is where much of the work is done: we allocate a fresh page for + * the buffer, grab the appropriate inode and set things up. + * + * FIXME: what should we do if an address is already bound? + * Here we return EINVAL, but it may be necessary to re-bind. + * I think thats what BSD does in the case of datagram sockets... + */ + static int + unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr, + int sockaddr_len) + { + char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1]; + struct unix_proto_data *upd = UN_DATA(sock); + unsigned long old_fs; + int i; + int er; + + dprintf(1, "UNIX: bind: socket 0x%x, len=%d\n", sock, sockaddr_len); + if (sockaddr_len <= UN_PATH_OFFSET || + sockaddr_len > sizeof(struct sockaddr_un)) { + dprintf(1, "UNIX: bind: bad length %d\n", sockaddr_len); + return(-EINVAL); + } + if (upd->sockaddr_len || upd->inode) { + printk("UNIX: bind: already bound!\n"); + return(-EINVAL); + } + er=verify_area(VERIFY_WRITE, umyaddr, sockaddr_len); + if(er) + return er; + memcpy_fromfs(&upd->sockaddr_un, umyaddr, sockaddr_len); + upd->sockaddr_un.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0'; + if (upd->sockaddr_un.sun_family != AF_UNIX) { + dprintf(1, "UNIX: bind: family is %d, not AF_UNIX(%d)\n", + upd->sockaddr_un.sun_family, AF_UNIX); + return(-EINVAL); + } + + memcpy(fname, upd->sockaddr_un.sun_path, sockaddr_len-UN_PATH_OFFSET); + fname[sockaddr_len-UN_PATH_OFFSET] = '\0'; + old_fs = get_fs(); + set_fs(get_ds()); + i = do_mknod(fname, S_IFSOCK | S_IRWXUGO, 0); + if (i == 0) i = open_namei(fname, 0, S_IFSOCK, &upd->inode, NULL); + set_fs(old_fs); + if (i < 0) { + printk("UNIX: bind: can't open socket %s\n", fname); + return(i); + } + upd->sockaddr_len = sockaddr_len; /* now its legal */ + + dprintf(1, "UNIX: bind: bound socket address: "); + sockaddr_un_printk(&upd->sockaddr_un, upd->sockaddr_len); + dprintf(1, "to inode 0x%x\n", upd->inode); + return(0); + } + + + /* + * Perform a connection. we can only connect to unix sockets + * (I can't for the life of me find an application where that + * wouldn't be the case!) + */ + static int + unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr, + int sockaddr_len, int flags) + { + char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1]; + struct sockaddr_un sockun; + struct unix_proto_data *serv_upd; + struct inode *inode; + unsigned long old_fs; + int i; + int er; + + dprintf(1, "UNIX: connect: socket 0x%x, servlen=%d\n", sock, sockaddr_len); + + if (sockaddr_len <= UN_PATH_OFFSET || + sockaddr_len > sizeof(struct sockaddr_un)) { + dprintf(1, "UNIX: connect: bad length %d\n", sockaddr_len); + return(-EINVAL); + } + if (sock->state == SS_CONNECTING) return(-EINPROGRESS); + if (sock->state == SS_CONNECTED) return(-EISCONN); + + er=verify_area(VERIFY_READ, uservaddr, sockaddr_len); + if(er) + return er; + memcpy_fromfs(&sockun, uservaddr, sockaddr_len); + sockun.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0'; + if (sockun.sun_family != AF_UNIX) { + dprintf(1, "UNIX: connect: family is %d, not AF_UNIX(%d)\n", + sockun.sun_family, AF_UNIX); + return(-EINVAL); + } + + /* + * Try to open the name in the filesystem - this is how we + * identify ourselves and our server. Note that we don't + * hold onto the inode that long, just enough to find our + * server. When we're connected, we mooch off the server. + */ + memcpy(fname, sockun.sun_path, sockaddr_len-UN_PATH_OFFSET); + fname[sockaddr_len-UN_PATH_OFFSET] = '\0'; + old_fs = get_fs(); + set_fs(get_ds()); + i = open_namei(fname, 0, S_IFSOCK, &inode, NULL); + set_fs(old_fs); + if (i < 0) { + dprintf(1, "UNIX: connect: can't open socket %s\n", fname); + return(i); + } + serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode); + iput(inode); + if (!serv_upd) { + dprintf(1, "UNIX: connect: can't locate peer %s at inode 0x%x\n", + fname, inode); + return(-EINVAL); + } + if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) { + dprintf(1, "UNIX: connect: can't await connection\n"); + return(i); + } + if (sock->conn) { + unix_data_ref(UN_DATA(sock->conn)); + UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */ + } + return(0); + } + + + /* + * To do a socketpair, we just connect the two datas, easy! + * Since we always wait on the socket inode, they're no contention + * for a wait area, and deadlock prevention in the case of a process + * writing to itself is, ignored, in true unix fashion! + */ + static int + unix_proto_socketpair(struct socket *sock1, struct socket *sock2) + { + struct unix_proto_data *upd1 = UN_DATA(sock1), *upd2 = UN_DATA(sock2); + + unix_data_ref(upd1); + unix_data_ref(upd2); + upd1->peerupd = upd2; + upd2->peerupd = upd1; + return(0); + } + + + /* On accept, we ref the peer's data for safe writes. */ + static int + unix_proto_accept(struct socket *sock, struct socket *newsock, int flags) + { + struct socket *clientsock; + + dprintf(1, "UNIX: accept: socket 0x%x accepted via socket 0x%x\n", + sock, newsock); + + /* + * If there aren't any sockets awaiting connection, + * then wait for one, unless nonblocking. + */ + while(!(clientsock = sock->iconn)) { + if (flags & O_NONBLOCK) return(-EAGAIN); + interruptible_sleep_on(sock->wait); + if (current->signal & ~current->blocked) { + dprintf(1, "UNIX: accept: sleep was interrupted\n"); + return(-ERESTARTSYS); + } + } + + /* + * Great. Finish the connection relative to server and client, + * wake up the client and return the new fd to the server. + */ + sock->iconn = clientsock->next; + clientsock->next = NULL; + newsock->conn = clientsock; + clientsock->conn = newsock; + clientsock->state = SS_CONNECTED; + newsock->state = SS_CONNECTED; + unix_data_ref(UN_DATA(clientsock)); + UN_DATA(newsock)->peerupd = UN_DATA(clientsock); + UN_DATA(newsock)->sockaddr_un = UN_DATA(sock)->sockaddr_un; + UN_DATA(newsock)->sockaddr_len = UN_DATA(sock)->sockaddr_len; + wake_up(clientsock->wait); + return(0); + } + + + /* Gets the current name or the name of the connected socket. */ + static int + unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr, + int *usockaddr_len, int peer) + { + struct unix_proto_data *upd; + int len; + int er; + + dprintf(1, "UNIX: getname: socket 0x%x for %s\n", sock, peer?"peer":"self"); + if (peer) { + if (sock->state != SS_CONNECTED) { + dprintf(1, "UNIX: getname: socket not connected\n"); + return(-EINVAL); + } + upd = UN_DATA(sock->conn); + } else + upd = UN_DATA(sock); + + er=verify_area(VERIFY_WRITE, usockaddr_len, sizeof(*usockaddr_len)); + if(er) + return er; + if ((len = get_fs_long(usockaddr_len)) <= 0) return(-EINVAL); + if (len > upd->sockaddr_len) len = upd->sockaddr_len; + if (len) { + er=verify_area(VERIFY_WRITE, usockaddr, len); + if(er) + return er; + memcpy_tofs(usockaddr, &upd->sockaddr_un, len); + } + put_fs_long(len, usockaddr_len); + return(0); + } + + + /* We read from our own buf. */ + static int + unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock) + { + struct unix_proto_data *upd; + int todo, avail; + int er; + + if ((todo = size) <= 0) return(0); + upd = UN_DATA(sock); + while(!(avail = UN_BUF_AVAIL(upd))) { + if (sock->state != SS_CONNECTED) { + dprintf(1, "UNIX: read: socket not connected\n"); + return((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL); + } + dprintf(1, "UNIX: read: no data available...\n"); + if (nonblock) return(-EAGAIN); + interruptible_sleep_on(sock->wait); + if (current->signal & ~current->blocked) { + dprintf(1, "UNIX: read: interrupted\n"); + return(-ERESTARTSYS); + } + } + + /* + * Copy from the read buffer into the user's buffer, + * watching for wraparound. Then we wake up the writer. + */ + do { + int part, cando; + + if (avail <= 0) { + printk("UNIX: read: AVAIL IS NEGATIVE!!!\n"); + send_sig(SIGKILL, current, 1); + return(-EPIPE); + } + + if ((cando = todo) > avail) cando = avail; + if (cando >(part = BUF_SIZE - upd->bp_tail)) cando = part; + dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n", + avail, todo, cando); + if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0) + return er; + memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando); + upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1); + ubuf += cando; + todo -= cando; + if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait); + avail = UN_BUF_AVAIL(upd); + } while(todo && avail); + return(size - todo); + } + + + /* + * We write to our peer's buf. When we connected we ref'd this + * peer so we are safe that the buffer remains, even after the + * peer has disconnected, which we check other ways. + */ + static int + unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock) + { + struct unix_proto_data *pupd; + int todo, space; + int er; + + if ((todo = size) <= 0) return(0); + if (sock->state != SS_CONNECTED) { + dprintf(1, "UNIX: write: socket not connected\n"); + if (sock->state == SS_DISCONNECTING) { + send_sig(SIGPIPE, current, 1); + return(-EPIPE); + } + return(-EINVAL); + } + pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */ + + while(!(space = UN_BUF_SPACE(pupd))) { + dprintf(1, "UNIX: write: no space left...\n"); + if (nonblock) return(-EAGAIN); + interruptible_sleep_on(sock->wait); + if (current->signal & ~current->blocked) { + dprintf(1, "UNIX: write: interrupted\n"); + return(-ERESTARTSYS); + } + if (sock->state == SS_DISCONNECTING) { + dprintf(1, "UNIX: write: disconnected(SIGPIPE)\n"); + send_sig(SIGPIPE, current, 1); + return(-EPIPE); + } + } + + /* + * Copy from the user's buffer to the write buffer, + * watching for wraparound. Then we wake up the reader. + */ + do { + int part, cando; + + if (space <= 0) { + printk("UNIX: write: SPACE IS NEGATIVE!!!\n"); + send_sig(SIGKILL, current, 1); + return(-EPIPE); + } + + /* + * We may become disconnected inside this loop, so watch + * for it (peerupd is safe until we close). + */ + if (sock->state == SS_DISCONNECTING) { + send_sig(SIGPIPE, current, 1); + return(-EPIPE); + } + if ((cando = todo) > space) cando = space; + if (cando >(part = BUF_SIZE - pupd->bp_head)) cando = part; + dprintf(1, "UNIX: write: space=%d, todo=%d, cando=%d\n", + space, todo, cando); + er=verify_area(VERIFY_READ, ubuf, cando); + if(er) + return er; + memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando); + pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1); + ubuf += cando; + todo -= cando; + if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait); + space = UN_BUF_SPACE(pupd); + } while(todo && space); + return(size - todo); + } + + + static int + unix_proto_select(struct socket *sock, int sel_type, select_table * wait) + { + struct unix_proto_data *upd, *peerupd; + + /* Handle server sockets specially. */ + if (sock->flags & SO_ACCEPTCON) { + if (sel_type == SEL_IN) { + dprintf(1, "UNIX: select: %sconnections pending\n", + sock->iconn ? "" : "no "); + if (sock->iconn) return(1); + select_wait(sock->wait, wait); + return(sock->iconn ? 1 : 0); + } + dprintf(1, "UNIX: select: nothing else for server socket\n"); + select_wait(sock->wait, wait); + return(0); + } + + if (sel_type == SEL_IN) { + upd = UN_DATA(sock); + dprintf(1, "UNIX: select: there is%s data available\n", + UN_BUF_AVAIL(upd) ? "" : " no"); + if (UN_BUF_AVAIL(upd)) /* even if disconnected */ + return(1); + else if (sock->state != SS_CONNECTED) { + dprintf(1, "UNIX: select: socket not connected(read EOF)\n"); + return(1); + } + select_wait(sock->wait,wait); + return(0); + } + if (sel_type == SEL_OUT) { + if (sock->state != SS_CONNECTED) { + dprintf(1, "UNIX: select: socket not connected(write EOF)\n"); + return(1); + } + peerupd = UN_DATA(sock->conn); + dprintf(1, "UNIX: select: there is%s space available\n", + UN_BUF_SPACE(peerupd) ? "" : " no"); + if (UN_BUF_SPACE(peerupd) > 0) return(1); + select_wait(sock->wait,wait); + return(0); + } + + /* SEL_EX */ + dprintf(1, "UNIX: select: there are no exceptions here?!\n"); + return(0); + } + + + static int + unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) + { + struct unix_proto_data *upd, *peerupd; + int er; + + upd = UN_DATA(sock); + peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL; + + switch(cmd) { + case TIOCINQ: + if (sock->flags & SO_ACCEPTCON) return(-EINVAL); + er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long)); + if(er) + return er; + if (UN_BUF_AVAIL(upd) || peerupd) + put_fs_long(UN_BUF_AVAIL(upd),(unsigned long *)arg); + else + put_fs_long(0,(unsigned long *)arg); + break; + case TIOCOUTQ: + if (sock->flags & SO_ACCEPTCON) return(-EINVAL); + er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long)); + if(er) + return er; + if (peerupd) put_fs_long(UN_BUF_SPACE(peerupd), + (unsigned long *)arg); + else + put_fs_long(0,(unsigned long *)arg); + break; + default: + return(-EINVAL); + } + return(0); + } + + + static int + unix_open(struct inode * inode, struct file * file) + { + int minor; + + dprintf(1, "UNIX: open\n"); + minor = MINOR(inode->i_rdev); + if (minor != 0) return(-ENODEV); + + return(0); + } + + + static void + unix_close(struct inode * inode, struct file * file) + { + dprintf(1, "UNIX: close\n"); + } + + + static int + unix_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) + { + int minor, ret; + int er; + + dprintf(1, "UNIX: ioctl(0x%X, 0x%X)\n", cmd, arg); + minor = MINOR(inode->i_rdev); + if (minor != 0) return(-ENODEV); + + ret = -EINVAL; + switch(cmd) { + case DDIOCSDBG: + er=verify_area(VERIFY_READ,(void *)arg, sizeof(int)); + if(er) + return er; + unix_debug = get_fs_long((int *)arg); + if (unix_debug != 0 && unix_debug != 1) { + unix_debug = 0; + return(-EINVAL); + } + return(0); + case SIOCSIFLINK: + printk("UNIX: cannot link streams!\n"); + break; + default: + break; + } + return(ret); + } + + + static struct file_operations unix_fops = { + NULL, /* LSEEK */ + NULL, /* READ */ + NULL, /* WRITE */ + NULL, /* READDIR */ + NULL, /* SELECT */ + unix_ioctl, /* IOCTL */ + NULL, /* MMAP */ + unix_open, /* OPEN */ + unix_close /* CLOSE */ + }; + + + static struct proto_ops unix_proto_ops = { + AF_UNIX, + unix_proto_create, + unix_proto_dup, + unix_proto_release, + unix_proto_bind, + unix_proto_connect, + unix_proto_socketpair, + unix_proto_accept, + unix_proto_getname, + unix_proto_read, + unix_proto_write, + unix_proto_select, + unix_proto_ioctl, + unix_proto_listen, + unix_proto_send, + unix_proto_recv, + unix_proto_sendto, + unix_proto_recvfrom, + unix_proto_shutdown, + unix_proto_setsockopt, + unix_proto_getsockopt, + NULL /* unix_proto_fcntl */ + }; + + + void + unix_proto_init(struct ddi_proto *pro) + { + struct unix_proto_data *upd; + + dprintf(1, "%s: init: initializing...\n", pro->name); + if (register_chrdev(AF_UNIX_MAJOR, "af_unix", &unix_fops) < 0) { + printk("%s: cannot register major device %d!\n", + pro->name, AF_UNIX_MAJOR); + return; + } + + /* Tell SOCKET that we are alive... */ + (void) sock_register(unix_proto_ops.family, &unix_proto_ops); + + for(upd = unix_datas; upd <= last_unix_data; ++upd) { + upd->refcnt = 0; + } + } diff -cr --new-file linux-0.07pl4/net/unix/unix.h linux-0.08/net/unix/unix.h *** linux-0.07pl4/net/unix/unix.h Wed Dec 31 19:00:00 1969 --- linux-0.08/net/unix/unix.h Sat Mar 5 12:07:48 1994 *************** *** 0 **** --- 1,63 ---- + /* + * UNIX An implementation of the AF_UNIX network domain for the + * LINUX operating system. UNIX is implemented using the + * BSD Socket interface as the means of communication with + * the user level. + * + * This file descibes some things of the UNIX protocol family + * module. It is mainly used for the "proc" sub-module now, + * but it may be useful for cleaning up the UNIX module as a + * whole later. + * + * Version: @(#)unix.h 1.0.3 05/25/93 + * + * Authors: Orest Zborowski, + * Ross Biro, + * Fred N. van Kempen, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + + + #ifdef _LINUX_UN_H + + + struct unix_proto_data { + int refcnt; /* cnt of reference 0=free */ + struct socket *socket; /* socket we're bound to */ + int protocol; + struct sockaddr_un sockaddr_un; + short sockaddr_len; /* >0 if name bound */ + char *buf; + int bp_head, bp_tail; + struct inode *inode; + struct unix_proto_data *peerupd; + }; + + extern struct unix_proto_data unix_datas[NSOCKETS]; + + + #define last_unix_data (unix_datas + NSOCKETS - 1) + + + #define UN_DATA(SOCK) ((struct unix_proto_data *)(SOCK)->data) + #define UN_PATH_OFFSET ((unsigned long)((struct sockaddr_un *)0) \ + ->sun_path) + + /* + * Buffer size must be power of 2. buffer mgmt inspired by pipe code. + * note that buffer contents can wraparound, and we can write one byte less + * than full size to discern full vs empty. + */ + #define BUF_SIZE PAGE_SIZE + #define UN_BUF_AVAIL(UPD) (((UPD)->bp_head - (UPD)->bp_tail) & \ + (BUF_SIZE-1)) + #define UN_BUF_SPACE(UPD) ((BUF_SIZE-1) - UN_BUF_AVAIL(UPD)) + + #endif /* _LINUX_UN_H */ + + + extern void unix_proto_init(struct ddi_proto *pro); diff -cr --new-file linux-0.07pl4/tools/amiga/bootstrap.c linux-0.08/tools/amiga/bootstrap.c *** linux-0.07pl4/tools/amiga/bootstrap.c Tue Feb 22 09:44:46 1994 --- linux-0.08/tools/amiga/bootstrap.c Sat Mar 26 10:54:45 1994 *************** *** 1,5 **** /* ! ** bootstrap.c -- This program loads the Amiga Linux kernel and launches it. ** ** Copyright 1993 by Hamish Macdonald, Greg Harp ** --- 1,6 ---- /* ! ** bootstrap.c -- This program loads the Linux/68k kernel into an Amiga ! ** and and launches it. ** ** Copyright 1993 by Hamish Macdonald, Greg Harp ** *************** *** 20,26 **** /* Amiga bootstrap include file */ #include "bootstrap.h" ! /* required Amiga linux include files */ #include #include --- 21,27 ---- /* Amiga bootstrap include file */ #include "bootstrap.h" ! /* required Linux/68k include files */ #include #include *************** *** 34,50 **** struct exec kexec; char *memptr; struct ExpansionBase *ExpansionBase; struct GfxBase *GfxBase; ! struct bootinfo bi, *kbi; caddr_t CustomBase = (caddr_t)CUSTOM_PHYSADDR; - #define START_MEM (bi.memory[0].addr) - #define MEM_SIZE (bi.memory[0].size) - void usage(void) { fprintf (stderr, "Usage:\n" --- 35,51 ---- struct exec kexec; char *memptr; + u_long start_mem; + u_long mem_size; + u_long rd_size; struct ExpansionBase *ExpansionBase; struct GfxBase *GfxBase; ! struct bootinfo bi; caddr_t CustomBase = (caddr_t)CUSTOM_PHYSADDR; void usage(void) { fprintf (stderr, "Usage:\n" *************** *** 53,58 **** --- 54,116 ---- exit (EXIT_FAILURE); } + /* + * This assembler code is copied to chip ram, and + * then executed. + * It copies the kernel (and ramdisk) to their + * final resting place. + */ + #ifndef __GNUC__ + #error GNU CC is required to compile the bootstrap program + #endif + asm(" + .text + .globl _copyall, _copyallend + _copyall: + | /* copy kernel text and data */ + movel _memptr,a0 | src = (u_long *)memptr; + movel a0,a2 | limit = (u_long *)(memptr + kexec.a_text + kexec.a_data); + lea _kexec,a3 + addl a3@(4),a2 + addl a3@(8),a2 + movel _start_mem,a1 | dest = (u_long *)start_mem; + 1: cmpl a0,a2 + beqs 2f | while (src < limit) + moveb a0@+,a1@+ | *dest++ = *src++; + bras 1b + 2: + + | /* clear kernel bss */ + movel a1,a0 | dest = (u_long *)(start_mem + kexec.a_text + kexec.a_data); + movel a1,a2 | limit = dest + kexec.a_bss / sizeof(u_long); + addl a3@(12),a2 + 1: cmpl a0,a2 + beqs 2f | while (dest < limit) + clrb a0@+ | *dest++ = 0; + bras 1b + 2: + + | /* copy the ramdisk to the top of memory (from back to front) */ + movel _start_mem,a1 | dest = (u_long *)(start_mem + mem_size); + addl _mem_size,a1 + movel _memptr,a2 | limit = (u_long *)(memptr + kexec.a_text + kexec.a_data); + addl a3@(4),a2 + addl a3@(8),a2 + movel a2,a0 | src = (u_long *)((u_long)limit + rd_size); + addl _rd_size,a0 + 1: cmpl a0,a2 + beqs 2f | while (src > limit) + moveb a0@-,a1@- | *--dest = *--src; + bras 1b + 2: + | /* jump to start of kernel */ + movel _start_mem,a0 | jump_to (START_MEM); + jsr a0@ + _copyallend: + "); + + extern char copyall, copyallend; + int main(int argc, char *argv[]) { int ch, debugflag = 0, kfd, rfd = -1, i; *************** *** 63,72 **** char *ramdisk_name = NULL; u_long memreq; struct nlist *nl; ! u_long *stack; /* print the greet message */ ! puts(" Amiga Linux Bootstrap version 1.5"); puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n"); /* machine is Amiga */ --- 121,132 ---- char *ramdisk_name = NULL; u_long memreq; struct nlist *nl; ! void (*startfunc)(void); ! long startcodesize; ! u_long *stack, kbi_offset; /* print the greet message */ ! puts(" Linux/68k Amiga Bootstrap version 1.6"); puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n"); /* machine is Amiga */ *************** *** 161,167 **** size = (u_long)mh.mh_Upper - (u_long)mh.mh_Lower; /* mask off to a 1M increment */ ! size = (size + 0xfffff) & 0xfff00000; fast_total += size; --- 221,227 ---- size = (u_long)mh.mh_Upper - (u_long)mh.mh_Lower; /* mask off to a 1M increment */ ! size &= 0xfff00000; fast_total += size; *************** *** 189,195 **** /* determine chipset */ bi.bi_amiga.chipset = CS_STONEAGE; if(GfxBase) ! { if(GfxBase->ChipRevBits0 & GFXG_AGA) { bi.bi_amiga.chipset = CS_AGA; --- 249,255 ---- /* determine chipset */ bi.bi_amiga.chipset = CS_STONEAGE; if(GfxBase) ! { if(GfxBase->ChipRevBits0 & GFXG_AGA) { bi.bi_amiga.chipset = CS_AGA; *************** *** 227,233 **** printf ("Amiga 4000 "); break; case AMI_1200: /* this implies an upgraded model */ ! printf ("Amiga 1200 "); /* equipped with at least 68030 !!! */ break; } --- 287,293 ---- printf ("Amiga 4000 "); break; case AMI_1200: /* this implies an upgraded model */ ! printf ("Amiga 1200 "); /* equipped with at least 68030 !!! */ break; } *************** *** 265,274 **** break; case CS_OCS: printf(", OCS"); ! break; case CS_ECS: printf(", ECS"); ! break; case CS_AGA: printf(", AGA chipset"); break; --- 325,334 ---- break; case CS_OCS: printf(", OCS"); ! break; case CS_ECS: printf(", ECS"); ! break; case CS_AGA: printf(", AGA chipset"); break; *************** *** 325,332 **** /* display chip memory size */ printf ("%ldK of CHIP memory\n", bi.bi_amiga.chip_size >> 10); /* tell us where the kernel will go */ ! printf("\nThe kernel will be located at %08lx\n", START_MEM); /* verify that there is enough Chip RAM */ if (bi.bi_amiga.chip_size < 512*1024) { --- 385,395 ---- /* display chip memory size */ printf ("%ldK of CHIP memory\n", bi.bi_amiga.chip_size >> 10); + start_mem = bi.memory[0].addr; + mem_size = bi.memory[0].size; + /* tell us where the kernel will go */ ! printf("\nThe kernel will be located at %08lx\n", start_mem); /* verify that there is enough Chip RAM */ if (bi.bi_amiga.chip_size < 512*1024) { *************** *** 363,378 **** } else bi.ramdisk_size = 0; /* find offset to boot_info structure */ if (!(nl = get_nlist (kernel_name, "_boot_info"))) { perror ("get_nlist"); exit (EXIT_FAILURE); } else { ! kbi = (struct bootinfo *)(START_MEM + nl->n_value - kexec.a_entry); free (nl); } ! memreq = kexec.a_text + kexec.a_data + (bi.ramdisk_size << 10); if (!(memptr = (char *)AllocMem (memreq, MEMF_FAST | MEMF_CLEAR))) { fprintf (stderr, "Unable to allocate memory\n"); exit (EXIT_FAILURE); --- 426,444 ---- } else bi.ramdisk_size = 0; + rd_size = bi.ramdisk_size << 10; + bi.ramdisk_addr = (u_long)start_mem + mem_size - rd_size; + /* find offset to boot_info structure */ if (!(nl = get_nlist (kernel_name, "_boot_info"))) { perror ("get_nlist"); exit (EXIT_FAILURE); } else { ! kbi_offset = nl->n_value - kexec.a_entry; free (nl); } ! memreq = kexec.a_text + kexec.a_data + rd_size; if (!(memptr = (char *)AllocMem (memreq, MEMF_FAST | MEMF_CLEAR))) { fprintf (stderr, "Unable to allocate memory\n"); exit (EXIT_FAILURE); *************** *** 400,405 **** --- 466,474 ---- } close (kfd); + /* copy the boot_info struct to the kernel image */ + memcpy ((void *)(memptr + kbi_offset), &bi, sizeof(bi)); + if (rfd != -1) { if (lseek (rfd, 0, L_SET) == -1) { fprintf (stderr, "Failed to seek to beginning of ramdisk file\n"); *************** *** 407,413 **** exit (EXIT_FAILURE); } if (read (rfd, memptr + kexec.a_text + kexec.a_data, ! bi.ramdisk_size << 10) != (bi.ramdisk_size << 10)) { fprintf (stderr, "Failed to read ramdisk file\n"); FreeMem ((void *)memptr, memreq); exit (EXIT_FAILURE); --- 476,482 ---- exit (EXIT_FAILURE); } if (read (rfd, memptr + kexec.a_text + kexec.a_data, ! rd_size) != rd_size) { fprintf (stderr, "Failed to read ramdisk file\n"); FreeMem ((void *)memptr, memreq); exit (EXIT_FAILURE); *************** *** 423,428 **** --- 492,510 ---- exit (EXIT_FAILURE); } + /* allocate chip ram for copy of startup code */ + startcodesize = ©allend - ©all; + startfunc = (void (*)(void))AllocMem( startcodesize, MEMF_CHIP); + if (!startfunc) { + fprintf (stderr, "Unable to allocate memory for code\n"); + FreeMem ((void *)memptr, memreq); + FreeMem ((void *)stack, TEMP_STACKSIZE); + exit (EXIT_FAILURE); + } + + /* copy startup code to CHIP RAM */ + memcpy (startfunc, ©all, startcodesize); + if (debugflag) { if (bi.ramdisk_size) printf ("RAM disk at %#lx, size is %ldK\n", *************** *** 430,452 **** bi.ramdisk_size); printf ("\nKernel text at %#lx, code size %d\n", ! START_MEM + N_TXTADDR(kexec), kexec.a_text); printf ("Kernel data at %#lx, data size %d\n", ! START_MEM + N_DATADDR(kexec), kexec.a_data ); printf ("Kernel bss at %#lx, bss size %d\n", ! START_MEM + N_BSSADDR(kexec), kexec.a_bss ); ! ! printf ("\nKernel boot_info is at %#lx physical, %#lx virtual\n", ! (u_long)kbi, (u_long)kbi - START_MEM + kexec.a_entry); printf ("\nKernel entry is %#x\n", kexec.a_entry ); ! printf ("ramdisk dest top is %#lx\n", START_MEM + MEM_SIZE); printf ("ramdisk lower limit is %#lx\n", (u_long)(memptr + kexec.a_text + kexec.a_data)); printf ("ramdisk src top is %#lx\n", (u_long)(memptr + kexec.a_text + kexec.a_data) ! + (bi.ramdisk_size << 10)); printf ("Type a key to continue the Linux boot..."); fflush (stdout); --- 512,531 ---- bi.ramdisk_size); printf ("\nKernel text at %#lx, code size %d\n", ! start_mem + N_TXTADDR(kexec), kexec.a_text); printf ("Kernel data at %#lx, data size %d\n", ! start_mem + N_DATADDR(kexec), kexec.a_data ); printf ("Kernel bss at %#lx, bss size %d\n", ! start_mem + N_BSSADDR(kexec), kexec.a_bss ); printf ("\nKernel entry is %#x\n", kexec.a_entry ); ! printf ("ramdisk dest top is %#lx\n", start_mem + mem_size); printf ("ramdisk lower limit is %#lx\n", (u_long)(memptr + kexec.a_text + kexec.a_data)); printf ("ramdisk src top is %#lx\n", (u_long)(memptr + kexec.a_text + kexec.a_data) ! + rd_size); printf ("Type a key to continue the Linux boot..."); fflush (stdout); *************** *** 479,530 **** /* turn off any mmu translation */ disable_mmu (); ! { ! /* ! * there may be problems here if the compiler optimizer ! * doesn't put these variables in registers, and the ! * stack space was allocated at the beginning of the function ! * and we've changed the stack. ! */ ! u_long *src, *dest, *limit; ! u_char *csrc, *cdest, *climit; ! ! /* ! * copy the kernel text and data to their final resting place. ! * The text is padded out (in the a.out file) to a multiple of ! * the page size. ! */ ! ! src = (u_long *)memptr; ! dest = (u_long *)START_MEM; ! limit = (u_long *)(memptr + kexec.a_text + kexec.a_data); ! while (src < limit) ! *dest++ = *src++; ! ! /* clear kernel bss */ ! dest = (u_long *)(START_MEM + kexec.a_text + kexec.a_data); ! limit = dest + kexec.a_bss / sizeof(u_long); ! while (dest < limit) ! *dest++ = 0; ! ! /* copy the ramdisk to the top of memory (from back to front) */ ! dest = (u_long *)(START_MEM + MEM_SIZE); ! limit = (u_long *)(memptr + kexec.a_text + kexec.a_data); ! src = (u_long *)((u_long)limit + (bi.ramdisk_size << 10)); ! while (src > limit) ! *--dest = *--src; ! bi.ramdisk_addr = (u_long)dest; ! ! /* copy the boot_info struct to the correct location */ ! cdest = (u_char *)kbi; ! climit = cdest + sizeof (bi); ! csrc = (u_char *)&bi; ! while (cdest < climit) ! *cdest++ = *csrc++; ! } ! ! /* jump to start of kernel */ ! jump_to (START_MEM); /* NOTREACHED */ } --- 558,565 ---- /* turn off any mmu translation */ disable_mmu (); ! /* execute the copy-and-go code (from CHIP RAM) */ ! startfunc(); /* NOTREACHED */ } diff -cr --new-file linux-0.07pl4/tools/version.c linux-0.08/tools/version.c *** linux-0.07pl4/tools/version.c Sun Jul 25 07:54:49 1993 --- linux-0.08/tools/version.c Sun Feb 13 05:03:15 1994 *************** *** 21,26 **** }; char *linux_banner = ! "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST "." LINUX_COMPILE_DOMAIN ") " UTS_VERSION " : " LINUX_COMPILE_TIME "\n"; --- 21,26 ---- }; char *linux_banner = ! "Linux/68k version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST "." LINUX_COMPILE_DOMAIN ") " UTS_VERSION " : " LINUX_COMPILE_TIME "\n";