S: 7546 JA Enschede
S: Netherlands
+N: David S. Miller
+E: davem@caip.rutgers.edu
+D: Sparc hacker
+D: New Linux-Activists maintainer
+D: Linux Emacs elf/qmagic support + other libc/gcc things
+D: Yee bore de yee bore! ;-)
+S: 2 Bristol Court
+S: East Brunswick, New Jersey 08816
+S: USA
+
N: Rick Miller
E: rick@discus.mil.wi.us
D: Linux Device Registrar (Major/minor numbers), "au-play", "bwBASIC"
VERSION = 1
PATCHLEVEL = 1
-SUBLEVEL = 74
+SUBLEVEL = 75
ARCH = i386
-all: Version zImage
-
.EXPORT_ALL_VARIABLES:
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else echo sh; fi ; fi)
TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
+all: do-it-all
+
#
# Make "config" the default target if there is no configuration file or
# "depend" the target if there is no top-level dependency information.
include .config
ifeq (.depend,$(wildcard .depend))
include .depend
+do-it-all: Version arch-all
else
CONFIGURATION = depend
+do-it-all: depend
endif
else
CONFIGURATION = config
+do-it-all: config
endif
#
# standard CFLAGS
#
-CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe
+CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
ifdef CONFIG_CPP
CFLAGS := $(CFLAGS) -x c++
$(CPP) -traditional $< -o $@
tools/version.o: tools/version.c include/linux/version.h
+ $(CC) $(CFLAGS) -DUTS_MACHINE='"$(ARCH)"' -c -o tools/version.o tools/version.c
init/main.o: $(CONFIGURE) init/main.c
$(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $<
AR =ar
STRIP =strip
-zBoot/zSystem: zBoot/*.c zBoot/*.S tools/zSystem
- $(MAKE) -C zBoot
-
-zImage: $(CONFIGURE) boot/bootsect boot/setup zBoot/zSystem tools/build
- tools/build boot/bootsect boot/setup zBoot/zSystem $(ROOT_DEV) > zImage
- sync
-
-zdisk: zImage
- dd bs=8192 if=zImage of=/dev/fd0
-
-zlilo: $(CONFIGURE) zImage
- if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
- if [ -f $(INSTALL_PATH)/zSystem.map ]; then mv $(INSTALL_PATH)/zSystem.map $(INSTALL_PATH)/zSystem.old; fi
- cat zImage > $(INSTALL_PATH)/vmlinuz
- cp zSystem.map $(INSTALL_PATH)/
- if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
+arch-all: tools/system
tools/system: boot/head.o init/main.o tools/version.o linuxsubdirs
$(LD) $(LOWLDFLAGS) boot/head.o init/main.o tools/version.o \
nm tools/zSystem | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | \
sort > System.map
-boot/setup.o: boot/setup.s
- $(AS) -o $@ $<
-
-boot/setup.s: boot/setup.S $(CONFIGURE) include/linux/config.h Makefile
- $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
-
-boot/bootsect.s: boot/bootsect.S $(CONFIGURE) include/linux/config.h Makefile
- $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
-
-tools/zSystem: boot/head.o init/main.o tools/version.o linuxsubdirs
- $(LD) $(HIGHLDFLAGS) boot/head.o init/main.o tools/version.o \
- $(ARCHIVES) \
- $(FILESYSTEMS) \
- $(DRIVERS) \
- $(LIBS) \
- -o tools/zSystem
- nm tools/zSystem | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | \
- sort > zSystem.map
#
# Leave these dummy entries for now to tell people that they are going away..
@exit 1
archclean:
- rm -f boot/bootsect boot/setup
+ @rm -f boot/head.o
#include <asm/system.h>
+#undef halt
#define halt .long PAL_halt
/*
AR =ar
STRIP =strip
+CFLAGS := $(CFLAGS) -pipe
+
ifdef CONFIG_M486
CFLAGS := $(CFLAGS) -m486
else
endif
endif
+arch-all: zImage
+
zBoot/zSystem: zBoot/*.c zBoot/*.S tools/zSystem
$(MAKE) -C zBoot
mov %ax,%es
mov %ax,%fs
mov %ax,%gs
- lss _stack_start,%esp
+ lss stack_start,%esp
/*
* Clear BSS first so that there are no surprises...
*/
mov %ax,%es
mov %ax,%fs
mov %ax,%gs
- lss _stack_start,%esp
+ lss stack_start,%esp
xorl %eax,%eax
lldt %ax
pushl %eax # These are the parameters to main :-)
*/
_floppy_track_buffer:
.fill 512*2*MAX_BUFFER_SECTORS,1,0
+
+stack_start:
+ .long _init_user_stack+4096
+ .long KERNEL_DS
/* This is the default interrupt "handler" :-) */
int_msg:
*/
int * blksize_size[MAX_BLKDEV] = { NULL, NULL, };
+/*
+ * hardsect_size contains the size of the hardware sector of a device.
+ *
+ * hardsect_size[MAJOR][MINOR]
+ *
+ * if (!hardsect_size[MAJOR])
+ * then 512 bytes is assumed.
+ * else
+ * sector_size is hardsect_size[MAJOR][MINOR]
+ * This is currently set by some scsi device and read by the msdos fs driver
+ * This might be a some uses later.
+ */
+int * hardsect_size[MAX_BLKDEV] = { NULL, NULL, };
+
/*
* look for a free request in the first N entries.
* NOTE: interrupts must be disabled on the way in, and will still
* 2.9 Fulfilled the Longshine LCS-7260 support; with great help and
* experiments by Serge Robyns.
* First attempts to support the TEAC CD-55A drives; but still not
- * useable yet.
+ * usable yet.
* Implemented the CDROMMULTISESSION and CDROMMULTISESSION_SYS ioctls;
* this is an attempt to handle multi session CDs more "transparent"
* (redirection handling has to be done within the isofs routines, and
* linux/fs/isofs/inode.c
* if set to 0 here
*/
-#define TEAC 0 /* if 1: enable TEAC CD-55A support (not useable yet) */
+#define TEAC 0 /* if 1: enable TEAC CD-55A support (not usable yet) */
#define JUKEBOX 1 /* tray control: eject tray if no disk is in */
#define EJECT 1 /* tray control: eject tray after last use */
#define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */
}
/*
- * DDI interface: runtime trace bit pattern maintainance
+ * DDI interface: runtime trace bit pattern maintenance
*/
static int sbpcd_dbg_ioctl(unsigned long arg, int level)
{
#endif
switch(mode) {
case 0:
- sptr = (char *) origin;
+ sptr = (char *) origin;
for (l=chcount; l>0 ; l--, sptr++)
- put_fs_byte(*sptr++,buf++);
+ put_fs_byte(*sptr++,buf++);
break;
case 1:
put_fs_byte((char)x,buf++); put_fs_byte((char)y,buf++);
memcpy_tofs(buf,(char *)origin,2*chcount);
break;
case 2:
+ gotoxy(currcons, get_fs_byte(buf+2), get_fs_byte(buf+3));
buf+=4; /* ioctl#, console#, x,y */
memcpy_fromfs((char *)origin,buf,2*chcount);
break;
}
/* constrain v such that v <= u */
-static inline short limit(const unsigned short v, const unsigned short u)
+static inline unsigned short limit(const unsigned short v, const unsigned short u)
{
- return ((v > u) ? u : v);
+/* gcc miscompiles the ?: operator, so don't use it.. */
+ if (v > u)
+ return u;
+ return v;
}
/* invoked via ioctl(TIOCLINUX) */
*
* $Log: cyclades.c,v $
* Revision 1.35 1994/12/16 13:54:18 steffen
- * addditional patch by Marcio Saito for board detection
+ * additional patch by Marcio Saito for board detection
* Accidently left out in 1.34
*
* Revision 1.34 1994/12/10 12:37:12 steffen
static struct semaphore tmp_buf_sem = MUTEX;
/*
- * This is used to look up the divsor speeds and the timeouts
+ * This is used to look up the divisor speeds and the timeouts
* We're normally limited to 15 distinct baud rates. The extra
* are accessed via settings in info->flags.
* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15};
-static char baud_cor3[] = { /* receive threashold */
+static char baud_cor3[] = { /* receive threshold */
0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
0x0a, 0x0a, 0x0a, 0x08, 0x04, 0x02, 0x01, 0x01, 0x01, 0x01};
case TIOCMSET:
ret_val = set_modem_info(info, cmd, (unsigned int *) arg);
-/* The following commands are imcompletely implemented!!! */
+/* The following commands are incompletely implemented!!! */
case TIOCGSOFTCAR:
error = verify_area(VERIFY_WRITE, (void *) arg
,sizeof(unsigned int *));
info->count = 1;
}
#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: decrmenting count to %d\n", __LINE__, info->count - 1);
+ printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count - 1);
#endif
if (--info->count < 0) {
printk("cy_close: bad serial port count for ttys%d: %d\n",
#endif
info->count--;
#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: decrmenting count to %d\n", __LINE__, info->count);
+ printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);
#endif
info->blocked_open++;
if (!tty_hung_up_p(filp)){
info->count++;
#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: incrmenting count to %d\n", __LINE__, info->count);
+ printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
#endif
}
info->blocked_open--;
/*
* This routine is called whenever a serial port is opened. It
- * performs the serial-specific initalization for the tty structure.
+ * performs the serial-specific initialization for the tty structure.
*/
int
cy_open(struct tty_struct *tty, struct file * filp)
#endif
info->count++;
#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: incrmenting count to %d\n", __LINE__, info->count);
+ printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
#endif
tty->driver_data = info;
info->tty = tty;
#define _KBD_KERN_H
#include <linux/interrupt.h>
-#define set_leds() mark_bh(KEYBOARD_BH)
-
#include <linux/keyboard.h>
extern char *func_table[MAX_NR_FUNC];
extern unsigned char getledstate(void);
extern void setledstate(struct kbd_struct *kbd, unsigned int led);
+extern inline void set_leds(void)
+{
+ /* con_init calls (indirectly) set_leds before kbd_init
+ has been called; ignore these early calls */
+ if (bh_base[KEYBOARD_BH].routine)
+ mark_bh(KEYBOARD_BH);
+}
+
extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
{
return ((kbd->modeflags >> flag) & 1);
int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
- int i;
+ int i, perm;
unsigned int console;
unsigned char ucval;
struct kbd_struct * kbd;
if (!vc_cons_allocated(console)) /* impossible? */
return -ENOIOCTLCMD;
+ /*
+ * To have permissions to do most of the vt ioctls, we either have
+ * to be the owner of the tty, or super-user.
+ */
+ perm = 0;
+ if (current->tty == tty || suser())
+ perm = 1;
+
kbd = kbd_table + console;
switch (cmd) {
case KIOCSOUND:
+ if (!perm)
+ return -EPERM;
kd_mksound((unsigned int)arg, 0);
return 0;
case KDMKTONE:
+ if (!perm)
+ return -EPERM;
{
unsigned int ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
* doesn't do a whole lot. i'm not sure if it should do any
* restoration of modes or what...
*/
- if (!suser())
+ if (!perm)
return -EPERM;
switch (arg) {
case KD_GRAPHICS:
return -EINVAL;
case KDSKBMODE:
- if (!suser())
+ if (!perm)
return -EPERM;
switch(arg) {
case K_RAW:
struct kbkeycode * const a = (struct kbkeycode *)arg;
unsigned int sc, kc;
- if (!suser())
+ if (!perm)
return -EPERM;
i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbkeycode));
if (i)
u_char s;
u_short v;
- if (!suser())
+ if (!perm)
return -EPERM;
i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbentry));
if (i)
u_char *p;
char *q;
- if (!suser())
+ if (!perm)
return -EPERM;
i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbsentry));
if (i)
struct kbdiacrs *a = (struct kbdiacrs *)arg;
unsigned int ct;
- if (!suser())
+ if (!perm)
return -EPERM;
i = verify_area(VERIFY_READ, (void *) a, sizeof(struct kbdiacrs));
if (i)
return 0;
case KDSKBLED:
- if (!suser())
+ if (!perm)
return -EPERM;
if (arg & ~0x77)
return -EINVAL;
struct vt_mode *vtmode = (struct vt_mode *)arg;
char mode;
- if (!suser())
+ if (!perm)
return -EPERM;
i = verify_area(VERIFY_WRITE, (void *)vtmode, sizeof(struct vt_mode));
if (i)
* to preserve sanity).
*/
case VT_ACTIVATE:
- if (!suser())
+ if (!perm)
return -EPERM;
if (arg == 0 || arg > MAX_NR_CONSOLES)
return -ENXIO;
* wait until the specified VT has been activated
*/
case VT_WAITACTIVE:
- if (!suser())
+ if (!perm)
return -EPERM;
if (arg == 0 || arg > MAX_NR_CONSOLES)
return -ENXIO;
* 2: completed switch-to OK
*/
case VT_RELDISP:
- if (!suser())
+ if (!perm)
return -EPERM;
if (vt_cons[console]->vt_mode.mode != VT_PROCESS)
return -EINVAL;
* Disallocate memory associated to VT (but leave VT1)
*/
case VT_DISALLOCATE:
- if (!suser())
+ if (!perm)
return -EPERM;
if (arg > MAX_NR_CONSOLES)
return -ENXIO;
{
struct vt_sizes *vtsizes = (struct vt_sizes *) arg;
ushort ll,cc;
- if (!suser())
+ if (!perm)
return -EPERM;
i = verify_area(VERIFY_READ, (void *)vtsizes, sizeof(struct vt_sizes));
if (i)
}
case PIO_FONT:
- if (!suser())
+ if (!perm)
return -EPERM;
return con_set_font((char *)arg);
/* con_set_font() defined in console.c */
/* con_get_font() defined in console.c */
case PIO_SCRNMAP:
- if (!suser())
+ if (!perm)
return -EPERM;
return con_set_trans((char *)arg);
/* con_set_trans() defined in console.c */
* Dmitry Gorodchanin : SLIP memory leaks
* Dmitry Gorodchanin : Code cleanup. Reduce tty driver
* buffering from 4096 to 256 bytes.
- * Improving SLIP responce time.
+ * Improving SLIP response time.
* CONFIG_SLIP_MODE_SLIP6.
* ifconfig sl? up & down now works correctly.
* Modularization.
unsigned long rx_packets; /* inbound frames counter */
unsigned long tx_packets; /* outbound frames counter */
unsigned long rx_errors; /* Parity, etc. errors */
- unsigned long tx_errors; /* Palnned stuff */
+ unsigned long tx_errors; /* Planned stuff */
unsigned long rx_dropped; /* No memory for skb */
unsigned long tx_dropped; /* When MTU change */
unsigned long rx_over_errors; /* Frame bigger then SLIP buf. */
with a MIDI card, which frequently also uses 0x330.
This can also be overridden on the command line to the kernel, via LILO or
- LODLIN. */
+ LOADLIN. */
static unsigned short bases[7] = {
#ifdef BUSLOGIC_PORT_OVERRIDE
BUSLOGIC_PORT_OVERRIDE,
{"MEDIAVIS","CDR-H93MV","1.31"}, /* Locks up if polled for lun != 0 */
{"SANKYO", "CP525","6.64"}, /* causes failed REQ SENSE, extra reset */
{"HP", "C1750A", "3226"}, /* scanjet iic */
+ {"HP", "C1790A", ""}, /* scanjet iip */
+ {"HP", "C2500A", ""}, /* scanjet iicx */
{NULL, NULL, NULL}};
static int blacklisted(unsigned char * response_data){
}
/*
- * Similarily, this entry point should be called by a loadable module if it
+ * Similarly, this entry point should be called by a loadable module if it
* is trying to remove a low level scsi driver from the system.
*/
static void scsi_unregister_host(Scsi_Host_Template * tpnt)
Scsi_Disk * rscsi_disks;
static int * sd_sizes;
static int * sd_blocksizes;
+static int * sd_hardsizes; /* Hardware sector size */
extern int sd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
return i;
};
}
+ {
+ /*
+ The msdos fs need to know the hardware sector size
+ So I have created this table. See ll_rw_blk.c
+ Jacques Gelinas (Jacques@solucorp.qc.ca)
+ */
+ int m;
+ int hard_sector = rscsi_disks[i].sector_size;
+ /* There is 16 minor allocated for each devices */
+ for (m=i<<4; m<((i+1)<<4); m++){
+ sd_hardsizes[m] = hard_sector;
+ }
+ printk ("SCSI Hardware sector size is %d bytes on device sd%c\n"
+ ,hard_sector,i+'a');
+ }
if(rscsi_disks[i].sector_size == 1024)
rscsi_disks[i].capacity <<= 1; /* Change this into 512 byte sectors */
if(rscsi_disks[i].sector_size == 256)
sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
sizeof(int));
- for(i=0;i<(sd_template.dev_max << 4);i++) sd_blocksizes[i] = 1024;
+ sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
+ sizeof(int));
+ for(i=0;i<(sd_template.dev_max << 4);i++){
+ sd_blocksizes[i] = 1024;
+ sd_hardsizes[i] = 512;
+ }
blksize_size[MAJOR_NR] = sd_blocksizes;
-
+ hardsect_size[MAJOR_NR] = sd_hardsizes;
sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) *
sizeof(struct hd_struct));
static inline int find_and_clear_bit_16(unsigned short *field)
{
int rv;
+ unsigned long flags;
+
+ save_flags(flags);
cli();
if (*field == 0) panic("No free mscp");
asm("xorl %0,%0\n0:\tbsfw %1,%w0\n\tbtr %0,%1\n\tjnc 0b"
: "=&r" (rv), "=m" (*field) : "1" (*field));
- sti();
+ restore_flags(flags);
return rv;
}
* to be short.
*/
#define DCACHE_NAME_LEN 15
-#define DCACHE_SIZE 64
+#define DCACHE_SIZE 128
struct hash_list {
struct dir_cache_entry * next;
#include <linux/malloc.h>
#include <linux/errno.h>
-#define MULTISESSION /* emoenke@gwdg.de */
-#ifdef MULTISESSION
-#include <linux/cdrom.h>
-#endif MULTISESSION
-
#include <asm/system.h>
#include <asm/segment.h>
unsigned int blocksize_bits;
int high_sierra;
int dev=s->s_dev;
-#ifdef MULTISESSION
- int i;
- unsigned int vol_desc_start;
- unsigned int *p_vol_desc_start=&vol_desc_start;
- struct inode inode_fake;
- struct file file_fake;
- extern struct file_operations * get_blkfops(unsigned int);
-#endif MULTISESSION
struct iso_volume_descriptor *vdp;
struct hs_volume_descriptor *hdp;
s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */
-#ifdef MULTISESSION
- /*
- * look if the driver can tell the multi session redirection
- * value; this allows to do the redirection if we are looking
- * for the volume descriptor, and to avoid it during "raw" access.
- */
- vol_desc_start=0;
- inode_fake.i_rdev=dev;
- i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
- &file_fake,
- CDROMMULTISESSION_SYS,
- (unsigned long) p_vol_desc_start);
- if (i!=0) vol_desc_start=0;
-#if 0
- printk("isofs.inode: CDROMMULTISESSION_SYS rc=%d\n",i);
- printk("isofs.inode: vol_desc_start = %d\n", vol_desc_start);
-#endif
- for (iso_blknum = vol_desc_start+16; iso_blknum < vol_desc_start+100; iso_blknum++) {
-#else
for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) {
-#endif MULTISESSION
if (!(bh = bread(dev, iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits), opt.blocksize))) {
s->s_dev=0;
printk("isofs_read_super: bread failed, dev 0x%x iso_blknum %d\n",
.s.o:
$(AS) -o $*.o $<
-OBJS= namei.o inode.o file.o dir.o misc.o fat.o
+OBJS= buffer.o namei.o inode.o file.o dir.o misc.o fat.o mmap.o
msdos.o: $(OBJS)
$(LD) -r -o msdos.o $(OBJS)
--- /dev/null
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/msdos_fs.h>
+
+struct buffer_head *msdos_bread (
+ struct super_block *sb,
+ int block)
+{
+ struct buffer_head *ret = NULL;
+ if (sb->s_blocksize == 512){
+ ret = bread (sb->s_dev,block,512);
+ }else{
+ struct buffer_head *real = bread (sb->s_dev,block>>1,1024);
+ if (real != NULL){
+ ret = (struct buffer_head *)kmalloc (sizeof(struct buffer_head)
+ ,GFP_KERNEL);
+ if (ret != NULL){
+ /* #Specification: msdos / strategy / special device / dummy blocks
+ Many special device (Scsi optical disk for one) use
+ larger hardware sector size. This allows for higher
+ capacity.
+
+ Most of the time, the MsDOS file system that sit
+ on this device is totally unaligned. It use logically
+ 512 bytes sector size, with logical sector starting
+ in the middle of a hardware block. The bad news is
+ that a hardware sector may hold data own by two
+ different files. This means that the hardware sector
+ must be read, patch and written allmost all the time.
+
+ Needless to say that it kills write performance
+ on all OS.
+
+ Internally the linux msdos fs is using 512 bytes
+ logical sector. When accessing such a device, we
+ allocate dummy buffer cache blocks, that we stuff
+ with the information of a real one (1k large).
+
+ This strategy is used to hide this difference to
+ the core of the msdos fs. The slowdown is not
+ hidden though!
+ */
+ /*
+ THe memset is there only to catch errors. The msdos
+ fs is only unsing b_data
+ */
+ memset (ret,0,sizeof(*ret));
+ ret->b_data = real->b_data;
+ if (block & 1) ret->b_data += 512;
+ ret->b_next = real;
+ }else{
+ brelse (real);
+ }
+ }
+ }
+ return ret;
+}
+struct buffer_head *msdos_getblk (
+ struct super_block *sb,
+ int block)
+{
+ struct buffer_head *ret = NULL;
+ if (sb->s_blocksize == 512){
+ ret = getblk (sb->s_dev,block,512);
+ }else{
+ /* #Specification: msdos / special device / writing
+ A write is always preceded by a read of the complete block
+ (large hardware sector size). This defeat write performance.
+ There is a possibility to optimize this when writing large
+ chunk by making sure we are filling large block. Volunter ?
+ */
+ ret = msdos_bread (sb,block);
+ }
+ return ret;
+}
+
+void msdos_brelse (
+ struct super_block *sb,
+ struct buffer_head *bh)
+{
+ if (bh != NULL){
+ if (sb->s_blocksize == 512){
+ brelse (bh);
+ }else{
+ brelse (bh->b_next);
+ /* We can free the dummy because a new one is allocated at
+ each msdos_getblk() and msdos_bread().
+ */
+ kfree (bh);
+ }
+ }
+}
+
+void msdos_mark_buffer_dirty (
+ struct super_block *sb,
+ struct buffer_head *bh,
+ int dirty_val)
+{
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+ mark_buffer_dirty (bh,dirty_val);
+}
+
+void msdos_set_uptodate (
+ struct super_block *sb,
+ struct buffer_head *bh,
+ int val)
+{
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+ bh->b_uptodate = val;
+}
+int msdos_is_uptodate (
+ struct super_block *sb,
+ struct buffer_head *bh)
+{
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+ return bh->b_uptodate;
+}
+
+void msdos_ll_rw_block (
+ struct super_block *sb,
+ int opr,
+ int nbreq,
+ struct buffer_head *bh[32])
+{
+ if (sb->s_blocksize == 512){
+ ll_rw_block(opr,nbreq,bh);
+ }else{
+ struct buffer_head *tmp[32];
+ int i;
+ for (i=0; i<nbreq; i++){
+ tmp[i] = bh[i]->b_next;
+ }
+ ll_rw_block(opr,nbreq,tmp);
+ }
+}
+
#include <linux/stat.h>
#include <linux/string.h>
+#include "msbuffer.h"
+
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
#define ROUND_UP(x) (((x)+3) & ~3)
struct dirent *dirent, /* dirent in user space */
int count)
{
+ struct super_block *sb = inode->i_sb;
int ino,i,i2,last;
char c,*walk;
struct buffer_head *bh;
#include <linux/string.h>
#include <linux/stat.h>
+#include "msbuffer.h"
static struct fat_cache *fat_cache,cache[FAT_CACHE];
first = nr*3/2;
last = first+1;
}
- if (!(bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
- SECTOR_BITS)))) {
+ if (!(bh = bread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
+ SECTOR_BITS),SECTOR_SIZE))) {
printk("bread in fat_access failed\n");
return 0;
}
if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS))
bh2 = bh;
else {
- if (!(bh2 = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
- >> SECTOR_BITS)))) {
+ if (!(bh2 = bread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
+ >> SECTOR_BITS),SECTOR_SIZE))) {
brelse(bh);
printk("bread in fat_access failed\n");
return 0;
}
mark_buffer_dirty(bh, 1);
for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) {
- if (!(c_bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->
+ if (!(c_bh = bread(sb->s_dev,MSDOS_SB(sb)->
fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)->
- fat_length*copy))) break;
+ fat_length*copy,SECTOR_SIZE))) break;
memcpy(c_bh->b_data,bh->b_data,SECTOR_SIZE);
mark_buffer_dirty(c_bh, 1);
if (bh != bh2) {
- if (!(c_bh2 = msdos_sread(sb->s_dev,
+ if (!(c_bh2 = bread(sb->s_dev,
MSDOS_SB(sb)->fat_start+(first >>
SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy
- +1))) {
+ +1,SECTOR_SIZE))) {
brelse(c_bh);
break;
}
#include <linux/stat.h>
#include <linux/string.h>
+#include "msbuffer.h"
+
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
NULL, /* permission */
NULL /* smap */
};
+/* #Specification: msdos / special devices / mmap
+ Mmapping does work because a special mmap is provide in that case.
+ Note that it is much less efficient than the generic_mmap normally
+ used since it allocate extra buffer. generic_mmap is used for
+ normal device (512 bytes hardware sectors).
+*/
+static struct file_operations msdos_file_operations_1024 = {
+ NULL, /* lseek - default */
+ msdos_file_read, /* read */
+ msdos_file_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ msdos_mmap, /* mmap */
+ NULL, /* no special open is needed */
+ NULL, /* release */
+ file_fsync /* fsync */
+};
+
+/* #Specification: msdos / special devices / swap file
+ Swap file can't work on special devices with a large sector
+ size (1024 bytes hard sector). Those devices have a weird
+ MsDOS filesystem layout. Generally a single hardware sector
+ may contain 2 unrelated logical sector. This mean that there is
+ no easy way to do a mapping between disk sector of a file and virtual
+ memory. So swap file is difficult (not available right now)
+ on those devices. Off course, Ext2 does not have this problem.
+*/
+struct inode_operations msdos_file_inode_operations_1024 = {
+ &msdos_file_operations_1024, /* default file operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ msdos_truncate, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
+};
#define MSDOS_PREFETCH 32
struct msdos_pre {
struct msdos_pre *pre,
int nb) /* How many must be prefetch at once */
{
+ struct super_block *sb = inode->i_sb;
struct buffer_head *bhreq[MSDOS_PREFETCH]; /* Buffers not */
/* already read */
int nbreq=0; /* Number of buffers in bhreq */
bh = getblk(inode->i_dev,sector,SECTOR_SIZE);
if (bh == NULL) break;
pre->bhlist[pre->nblist++] = bh;
- if (!bh->b_uptodate) bhreq[nbreq++] = bh;
+ if (!msdos_is_uptodate(sb,bh)) bhreq[nbreq++] = bh;
}else{
break;
}
}
- if (nbreq > 0) ll_rw_block (READ,nbreq,bhreq);
+ if (nbreq > 0) msdos_ll_rw_block (sb,READ,nbreq,bhreq);
for (i=pre->nblist; i<MSDOS_PREFETCH; i++) pre->bhlist[i] = NULL;
}
char *buf,
int count)
{
+ struct super_block *sb = inode->i_sb;
char *start = buf;
char *end = buf + count;
int i;
}
PRINTK (("file_read pos %ld nblist %d %d %d\n",filp->f_pos,pre.nblist,pre.fetched,count));
wait_on_buffer(bh);
- if (!bh->b_uptodate){
+ if (!msdos_is_uptodate(sb,bh)){
/* read error ? */
brelse (bh);
break;
char *buf,
int count)
{
+ struct super_block *sb = inode->i_sb;
int sector,offset,size,left,written;
int error,carry;
char *start,*to,ch;
error = -EIO;
break;
}
- }else if (!(bh = msdos_sread(inode->i_dev,sector))) {
+ }else if (!(bh = bread(inode->i_dev,sector,SECTOR_SIZE))) {
error = -EIO;
break;
}
inode->i_size = filp->f_pos;
inode->i_dirt = 1;
}
- bh->b_uptodate = 1;
+ msdos_set_uptodate(sb,bh,1);
mark_buffer_dirty(bh, 0);
brelse(bh);
}
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/major.h>
+#include <linux/blkdev.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/locks.h>
+#include "msbuffer.h"
+
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
- gid_t *gid,int *umask,int *debug,int *fat,int *quiet)
+ gid_t *gid,int *umask,int *debug,int *fat,int *quiet,
+ int *blksize)
{
char *this_char,*value;
if (value) return 0;
*quiet = 1;
}
+ else if (!strcmp(this_char,"blocksize")) {
+ *blksize = simple_strtoul(value,&value,0);
+ if (*value)
+ return 0;
+ if (*blksize != 512 && *blksize != 1024){
+ printk ("MSDOS FS: Invalid blocksize (512 or 1024)\n");
+ }
+ }
else return 0;
}
return 1;
/* Read the super block of an MS-DOS FS. */
-struct super_block *msdos_read_super(struct super_block *s,void *data,
+struct super_block *msdos_read_super(struct super_block *sb,void *data,
int silent)
{
struct buffer_head *bh;
uid_t uid;
gid_t gid;
int umask;
-
+ int blksize = 512;
+ if (hardsect_size[MAJOR(sb->s_dev)] != NULL){
+ blksize = hardsect_size[MAJOR(sb->s_dev)][MINOR(sb->s_dev)];
+ if (blksize != 512){
+ printk ("MSDOS: Hardware sector size is %d\n",blksize);
+ }
+ }
if (!parse_options((char *) data,&check,&conversion,&uid,&gid,&umask,
- &debug,&fat,&quiet)) {
- s->s_dev = 0;
+ &debug,&fat,&quiet,&blksize)
+ || (blksize != 512 && blksize != 1024)) {
+ sb->s_dev = 0;
return NULL;
}
cache_init();
- lock_super(s);
- set_blocksize(s->s_dev, SECTOR_SIZE);
- bh = bread(s->s_dev, 0, SECTOR_SIZE);
- unlock_super(s);
- if (bh == NULL) {
- s->s_dev = 0;
+ lock_super(sb);
+ /* The first read is always 1024 bytes */
+ sb->s_blocksize = 1024;
+ set_blocksize(sb->s_dev, 1024);
+ bh = bread(sb->s_dev, 0, 1024);
+ unlock_super(sb);
+ if (bh == NULL || !msdos_is_uptodate(sb,bh)) {
+ brelse (bh);
+ sb->s_dev = 0;
printk("MSDOS bread failed\n");
return NULL;
}
b = (struct msdos_boot_sector *) bh->b_data;
- s->s_blocksize = 512; /* Using this small block size solve the */
- /* the misfit with buffer cache and cluster */
- /* because cluster (DOS) are often aligned */
- /* on odd sector */
- s->s_blocksize_bits = 9; /* we cannot handle anything else yet */
+ set_blocksize(sb->s_dev, blksize);
/*
* The DOS3 partition size limit is *not* 32M as many people think.
* Instead, it is 64K sectors (with the usual sector size being
logical_sector_size = CF_LE_W(*(unsigned short *) &b->sector_size);
sector_mult = logical_sector_size >> SECTOR_BITS;
- MSDOS_SB(s)->cluster_size = b->cluster_size*sector_mult;
- MSDOS_SB(s)->fats = b->fats;
- MSDOS_SB(s)->fat_start = CF_LE_W(b->reserved)*sector_mult;
- MSDOS_SB(s)->fat_length = CF_LE_W(b->fat_length)*sector_mult;
- MSDOS_SB(s)->dir_start = (CF_LE_W(b->reserved)+b->fats*CF_LE_W(
+ MSDOS_SB(sb)->cluster_size = b->cluster_size*sector_mult;
+ MSDOS_SB(sb)->fats = b->fats;
+ MSDOS_SB(sb)->fat_start = CF_LE_W(b->reserved)*sector_mult;
+ MSDOS_SB(sb)->fat_length = CF_LE_W(b->fat_length)*sector_mult;
+ MSDOS_SB(sb)->dir_start = (CF_LE_W(b->reserved)+b->fats*CF_LE_W(
b->fat_length))*sector_mult;
- MSDOS_SB(s)->dir_entries = CF_LE_W(*((unsigned short *) &b->dir_entries
+ MSDOS_SB(sb)->dir_entries = CF_LE_W(*((unsigned short *) &b->dir_entries
));
- MSDOS_SB(s)->data_start = MSDOS_SB(s)->dir_start+ROUND_TO_MULTIPLE((
- MSDOS_SB(s)->dir_entries << MSDOS_DIR_BITS) >> SECTOR_BITS,
+ MSDOS_SB(sb)->data_start = MSDOS_SB(sb)->dir_start+ROUND_TO_MULTIPLE((
+ MSDOS_SB(sb)->dir_entries << MSDOS_DIR_BITS) >> SECTOR_BITS,
sector_mult);
data_sectors = (CF_LE_W(*((unsigned short *) &b->sectors)) ?
CF_LE_W(*((unsigned short *) &b->sectors)) :
- CF_LE_L(b->total_sect))*sector_mult-MSDOS_SB(s)->data_start;
+ CF_LE_L(b->total_sect))*sector_mult-MSDOS_SB(sb)->data_start;
error = !b->cluster_size || !sector_mult;
if (!error) {
- MSDOS_SB(s)->clusters = b->cluster_size ? data_sectors/
+ MSDOS_SB(sb)->clusters = b->cluster_size ? data_sectors/
b->cluster_size/sector_mult : 0;
- MSDOS_SB(s)->fat_bits = fat ? fat : MSDOS_SB(s)->clusters >
+ MSDOS_SB(sb)->fat_bits = fat ? fat : MSDOS_SB(sb)->clusters >
MSDOS_FAT12 ? 16 : 12;
- error = !MSDOS_SB(s)->fats || (MSDOS_SB(s)->dir_entries &
- (MSDOS_DPS-1)) || MSDOS_SB(s)->clusters+2 > MSDOS_SB(s)->
- fat_length*SECTOR_SIZE*8/MSDOS_SB(s)->fat_bits ||
+ error = !MSDOS_SB(sb)->fats || (MSDOS_SB(sb)->dir_entries &
+ (MSDOS_DPS-1)) || MSDOS_SB(sb)->clusters+2 > MSDOS_SB(sb)->
+ fat_length*SECTOR_SIZE*8/MSDOS_SB(sb)->fat_bits ||
(logical_sector_size & (SECTOR_SIZE-1)) || !b->secs_track ||
!b->heads;
}
brelse(bh);
+ /*
+ This must be done after the brelse because the bh is a dummy
+ allocated by msdos_bread (see buffer.c)
+ */
+ sb->s_blocksize = blksize; /* Using this small block size solve the */
+ /* the misfit with buffer cache and cluster */
+ /* because cluster (DOS) are often aligned */
+ /* on odd sector */
+ sb->s_blocksize_bits = blksize == 512 ? 9 : 10;
if (error || debug) {
/* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
- "uid=%d,gid=%d,umask=%03o%s]\n",MSDOS_SB(s)->fat_bits,check,
- conversion,uid,gid,umask,MSDOS_CAN_BMAP(MSDOS_SB(s)) ?
+ "uid=%d,gid=%d,umask=%03o%s]\n",MSDOS_SB(sb)->fat_bits,check,
+ conversion,uid,gid,umask,MSDOS_CAN_BMAP(MSDOS_SB(sb)) ?
",bmap" : "");
printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,"
- "se=%d,ts=%ld,ls=%d]\n",b->media,MSDOS_SB(s)->cluster_size,
- MSDOS_SB(s)->fats,MSDOS_SB(s)->fat_start,MSDOS_SB(s)->
- fat_length,MSDOS_SB(s)->dir_start,MSDOS_SB(s)->dir_entries,
- MSDOS_SB(s)->data_start,CF_LE_W(*(unsigned short *) &b->
+ "se=%d,ts=%ld,ls=%d]\n",b->media,MSDOS_SB(sb)->cluster_size,
+ MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start,MSDOS_SB(sb)->
+ fat_length,MSDOS_SB(sb)->dir_start,MSDOS_SB(sb)->dir_entries,
+ MSDOS_SB(sb)->data_start,CF_LE_W(*(unsigned short *) &b->
sectors),b->total_sect,logical_sector_size);
+ printk ("Transaction block size = %d\n",blksize);
}
if (error) {
if (!silent)
printk("VFS: Can't find a valid MSDOS filesystem on dev 0x%04x.\n",
- s->s_dev);
- s->s_dev = 0;
+ sb->s_dev);
+ sb->s_dev = 0;
return NULL;
}
- s->s_magic = MSDOS_SUPER_MAGIC;
- MSDOS_SB(s)->name_check = check;
- MSDOS_SB(s)->conversion = conversion;
+ sb->s_magic = MSDOS_SUPER_MAGIC;
+ MSDOS_SB(sb)->name_check = check;
+ MSDOS_SB(sb)->conversion = conversion;
/* set up enough so that it can read an inode */
- s->s_op = &msdos_sops;
- MSDOS_SB(s)->fs_uid = uid;
- MSDOS_SB(s)->fs_gid = gid;
- MSDOS_SB(s)->fs_umask = umask;
- MSDOS_SB(s)->quiet = quiet;
- MSDOS_SB(s)->free_clusters = -1; /* don't know yet */
- MSDOS_SB(s)->fat_wait = NULL;
- MSDOS_SB(s)->fat_lock = 0;
- MSDOS_SB(s)->prev_free = 0;
- if (!(s->s_mounted = iget(s,MSDOS_ROOT_INO))) {
- s->s_dev = 0;
+ sb->s_op = &msdos_sops;
+ MSDOS_SB(sb)->fs_uid = uid;
+ MSDOS_SB(sb)->fs_gid = gid;
+ MSDOS_SB(sb)->fs_umask = umask;
+ MSDOS_SB(sb)->quiet = quiet;
+ MSDOS_SB(sb)->free_clusters = -1; /* don't know yet */
+ MSDOS_SB(sb)->fat_wait = NULL;
+ MSDOS_SB(sb)->fat_lock = 0;
+ MSDOS_SB(sb)->prev_free = 0;
+ if (!(sb->s_mounted = iget(sb,MSDOS_ROOT_INO))) {
+ sb->s_dev = 0;
printk("get root inode failed\n");
return NULL;
}
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
- return s;
+ return sb;
}
void msdos_read_inode(struct inode *inode)
{
+ struct super_block *sb = inode->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *raw_entry;
int nr;
inode->i_mode = MSDOS_MKMODE(raw_entry->attr,(IS_NOEXEC(inode)
? S_IRUGO|S_IWUGO : S_IRWXUGO) & ~MSDOS_SB(inode->i_sb)->fs_umask) |
S_IFREG;
- inode->i_op = &msdos_file_inode_operations; /* Now can always bmap */
+ inode->i_op = sb->s_blocksize == 1024
+ ? &msdos_file_inode_operations_1024
+ : &msdos_file_inode_operations;
MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start);
inode->i_nlink = 1;
inode->i_size = CF_LE_L(raw_entry->size);
void msdos_write_inode(struct inode *inode)
{
+ struct super_block *sb = inode->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *raw_entry;
#include <linux/string.h>
#include <linux/stat.h>
+#include "msbuffer.h"
#define PRINTK(x)
/* Well-known binary file extensions */
int msdos_add_cluster(struct inode *inode)
{
+ struct super_block *sb = inode->i_sb;
int count,nr,limit,last,current,sector,last_sector;
struct buffer_head *bh;
int cluster_size = MSDOS_SB(inode->i_sb)->cluster_size;
printk("getblk failed\n");
else {
memset(bh->b_data,0,SECTOR_SIZE);
- bh->b_uptodate = 1;
+ msdos_set_uptodate(sb,bh,1);
mark_buffer_dirty(bh, 1);
brelse(bh);
}
int msdos_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
struct msdos_dir_entry **de)
{
+ struct super_block *sb = dir->i_sb;
int sector,offset;
while (1) {
if (*bh)
brelse(*bh);
PRINTK (("get_entry sector apres brelse\n"));
- if (!(*bh = msdos_sread(dir->i_dev,sector))) {
+ if (!(*bh = bread(dir->i_dev,sector,SECTOR_SIZE))) {
printk("Directory sread (sector %d) failed\n",sector);
continue;
}
struct inode *inode;
int entry,start,done;
- if (!(bh = msdos_sread(sb->s_dev,sector))) return -EIO;
+ if (!(bh = bread(sb->s_dev,sector,SECTOR_SIZE))) return -EIO;
data = (struct msdos_dir_entry *) bh->b_data;
for (entry = 0; entry < MSDOS_DPS; entry++) {
if (name) RSS_NAME
--- /dev/null
+/*
+ * fs/msdos/mmap.c
+ *
+ * Written by Jacques Gelinas (jacques@solucorp.qc.ca)
+ * Inspired by fs/nfs/mmap.c (Jaon Tombs 15 Aug 1993)
+ *
+ * msdos mmap handling
+ */
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/shm.h>
+#include <linux/errno.h>
+#include <linux/mman.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/msdos_fs.h>
+
+/*
+ * Fill in the supplied page for mmap
+ */
+static unsigned long msdos_file_mmap_nopage(
+ struct vm_area_struct * area,
+ unsigned long address,
+ unsigned long page,
+ int error_code)
+{
+ struct inode * inode = area->vm_inode;
+ unsigned int clear;
+ int pos;
+ long gap; /* distance from eof to pos */
+
+ address &= PAGE_MASK;
+ pos = address - area->vm_start + area->vm_offset;
+
+ clear = 0;
+ gap = inode->i_size - pos;
+ if (gap <= 0){
+ /* mmaping beyond end of file */
+ clear = PAGE_SIZE;
+ }else{
+ int cur_read;
+ int need_read;
+ struct file filp;
+ if (gap < PAGE_SIZE){
+ clear = PAGE_SIZE - gap;
+ }
+ filp.f_reada = 0;
+ filp.f_pos = pos;
+ need_read = PAGE_SIZE - clear;
+ {
+ unsigned long cur_fs = get_fs();
+ set_fs (KERNEL_DS);
+ cur_read = msdos_file_read (inode,&filp,(char*)page
+ ,need_read);
+ set_fs (cur_fs);
+ }
+ if (cur_read != need_read){
+ printk ("MSDOS: Error while reading an mmap file %d <> %d\n"
+ ,cur_read,need_read);
+ }
+ }
+ if (clear > 0){
+ memset ((char*)page+PAGE_SIZE-clear,0,clear);
+ }
+ return page;
+}
+
+struct vm_operations_struct msdos_file_mmap = {
+ NULL, /* open */
+ NULL, /* close */
+ NULL, /* unmap */
+ NULL, /* protect */
+ NULL, /* sync */
+ NULL, /* advise */
+ msdos_file_mmap_nopage, /* nopage */
+ NULL, /* wppage */
+ NULL, /* swapout */
+ NULL, /* swapin */
+};
+
+/*
+ * This is used for a general mmap of an msdos file
+ * Returns 0 if ok, or a negative error code if not.
+ */
+int msdos_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
+{
+ if (vma->vm_page_prot & PAGE_RW) /* only PAGE_COW or read-only supported now */
+ return -EINVAL;
+ if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
+ return -EINVAL;
+ if (!inode->i_sb || !S_ISREG(inode->i_mode))
+ return -EACCES;
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
+
+ vma->vm_inode = inode;
+ inode->i_count++;
+ vma->vm_ops = &msdos_file_mmap;
+ return 0;
+}
+
--- /dev/null
+/* buffer.c 13/12/94 20.19.10 */
+struct buffer_head *msdos_bread (struct super_block *sb, int block);
+struct buffer_head *msdos_getblk (struct super_block *sb, int block);
+void msdos_brelse (struct super_block *sb, struct buffer_head *bh);
+void msdos_mark_buffer_dirty (struct super_block *sb,
+ struct buffer_head *bh,
+ int dirty_val);
+void msdos_set_uptodate (struct super_block *sb,
+ struct buffer_head *bh,
+ int val);
+int msdos_is_uptodate (struct super_block *sb, struct buffer_head *bh);
+void msdos_ll_rw_block (struct super_block *sb, int opr,
+ int nbreq, struct buffer_head *bh[32]);
+
+/* These macros exist to avoid modifying all the code */
+/* They should be removed one day I guess */
+
+#define brelse(b) msdos_brelse(sb,b)
+#define bread(d,b,s) msdos_bread(sb,b)
+#define getblk(d,b,s) msdos_getblk(sb,b)
+#define mark_buffer_dirty(b,v) msdos_mark_buffer_dirty(sb,b,v)
+
#include <linux/string.h>
#include <linux/stat.h>
+#include "msbuffer.h"
+
#define PRINTK(x)
/* MS-DOS "device special files" */
int msdos_lookup(struct inode *dir,const char *name,int len,
struct inode **result)
{
+ struct super_block *sb = dir->i_sb;
int ino,res;
struct msdos_dir_entry *de;
struct buffer_head *bh;
static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
struct inode **result)
{
+ struct super_block *sb = dir->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *de;
int res,ino;
int msdos_create(struct inode *dir,const char *name,int len,int mode,
struct inode **result)
{
+ struct super_block *sb = dir->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *de;
char msdos_name[MSDOS_NAME];
int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
{
+ struct super_block *sb = dir->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *de;
struct inode *inode,*dot;
static int msdos_empty(struct inode *dir)
{
+ struct super_block *sb = dir->i_sb;
loff_t pos;
struct buffer_head *bh;
struct msdos_dir_entry *de;
int msdos_rmdir(struct inode *dir,const char *name,int len)
{
+ struct super_block *sb = dir->i_sb;
int res,ino;
struct buffer_head *bh;
struct msdos_dir_entry *de;
int len,
int nospc) /* Flag special file ? */
{
+ struct super_block *sb = dir->i_sb;
int res,ino;
struct buffer_head *bh;
struct msdos_dir_entry *de;
struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
struct msdos_dir_entry *old_de,int old_ino)
{
+ struct super_block *sb = old_dir->i_sb;
struct buffer_head *new_bh;
struct msdos_dir_entry *new_de;
struct inode *new_inode,*old_inode;
struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
struct msdos_dir_entry *old_de,int old_ino)
{
+ struct super_block *sb = old_dir->i_sb;
struct buffer_head *new_bh,*free_bh,*dotdot_bh;
struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
struct inode *new_dir,const char *new_name,int new_len)
{
+ struct super_block *sb = old_dir->i_sb;
char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
struct buffer_head *old_bh;
struct msdos_dir_entry *old_de;
static int get_cpuinfo(char * buffer)
{
- /* to conserve memory, we define the strins yes and no in
- advance */
- char *yes="yes";
- char *no="no";
char *model[2][9]={{"DX","SX","DX/2","4","SX/2","6",
"7","DX/4"},
{"Pentium 60/66","Pentium 90/100","3",
"4","5","6","7","8"}};
+ char mask[2];
+ mask[0] = x86_mask+'@';
+ mask[1] = '\0';
return sprintf(buffer,"cpu\t\t: %c86\n"
"model\t\t: %s\n"
- "mask\t\t: %c\n"
+ "mask\t\t: %s\n"
"vid\t\t: %s\n"
"fdiv_bug\t: %s\n"
"math\t\t: %s\n"
"CMPXCHGB8B\t: %s\n",
x86+'0',
x86_model ? model[x86-4][x86_model-1] : "Unknown",
- x86_mask+'@',
+ x86_mask ? mask : "Unknown",
x86_vendor_id,
- fdiv_bug ? yes : no,
- hard_math ? yes : no,
- hlt_works_ok ? yes : no,
- wp_works_ok ? yes : no,
- x86_capability & 1 ? yes : no,
- x86_capability & 2 ? yes : no,
- x86_capability & 4 ? yes : no,
- x86_capability & 8 ? yes : no,
- x86_capability & 16 ? yes : no,
- x86_capability & 32 ? yes : no,
- x86_capability & 128 ? yes : no,
- x86_capability & 256 ? yes : no
+ fdiv_bug ? "yes" : "no",
+ hard_math ? "yes" : "no",
+ hlt_works_ok ? "yes" : "no",
+ wp_works_ok ? "yes" : "no",
+ x86_capability & 1 ? "yes" : "no",
+ x86_capability & 2 ? "yes" : "no",
+ x86_capability & 4 ? "yes" : "no",
+ x86_capability & 8 ? "yes" : "no",
+ x86_capability & 16 ? "yes" : "no",
+ x86_capability & 32 ? "yes" : "no",
+ x86_capability & 128 ? "yes" : "no",
+ x86_capability & 256 ? "yes" : "no"
);
}
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 %lu %u %lu %lu %lu %lu %lu %lu \
+%lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu \
%lu %lu %lu %lu\n",
pid,
(*p)->comm,
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
inode->i_dirt = 1;
}
-/*
- See inode.c
-
- Some entry point are filled dynamically with function pointers
- from the msdos file_operations and file_inode_operations.
-
- The idea is to have the code as independent as possible from
- the msdos file system.
-*/
+/* Function for normal file system (512 bytes hardware sector size) */
struct file_operations umsdos_file_operations = {
NULL, /* lseek - default */
UMSDOS_file_read, /* read */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ msdos_bmap, /* bmap */
UMSDOS_truncate,/* truncate */
NULL, /* permission */
msdos_smap /* smap */
};
+/* For other with larger and unaligned file system */
+struct file_operations umsdos_file_operations_no_bmap = {
+ NULL, /* lseek - default */
+ UMSDOS_file_read, /* read */
+ UMSDOS_file_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ msdos_mmap, /* mmap */
+ NULL, /* no special open is needed */
+ NULL, /* release */
+ file_fsync /* fsync */
+};
+struct inode_operations umsdos_file_inode_operations_no_bmap = {
+ &umsdos_file_operations_no_bmap, /* default file operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ UMSDOS_truncate,/* truncate */
+ NULL, /* permission */
+ NULL, /* smap */
+};
PRINTK (("put inode %x owner %x pos %d dir %x\n",inode
,inode->u.umsdos_i.i_emd_owner,inode->u.umsdos_i.pos
,inode->u.umsdos_i.i_emd_dir));
+ if (inode != NULL && inode == pseudo_root){
+ printk ("Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n");
+ }
msdos_put_inode(inode);
}
if (!umsdos_isinit(inode)){
inode->u.umsdos_i.i_emd_dir = 0;
if (S_ISREG(inode->i_mode)){
- static char is_init = 0;
- if (!is_init){
- /*
- I don't want to change the msdos file system code
- so I get the address of some subroutine dynamically
- once.
- */
- umsdos_file_inode_operations.bmap = inode->i_op->bmap;
+ if (inode->i_op->bmap != NULL){
inode->i_op = &umsdos_file_inode_operations;
- is_init = 1;
+ }else{
+ inode->i_op = &umsdos_file_inode_operations_no_bmap;
}
- inode->i_op = &umsdos_file_inode_operations;
}else if (S_ISDIR(inode->i_mode)){
if (dir != NULL){
umsdos_setup_dir_inode(inode);
msdos directory, with all limitation of msdos.
*/
struct super_block *sb = msdos_read_super(s,data,silent);
- printk ("UMSDOS Alpha 0.5a (compatibility level %d.%d, fast msdos)\n"
+ printk ("UMSDOS Beta 0.6 (compatibility level %d.%d, fast msdos)\n"
,UMSDOS_VERSION,UMSDOS_RELEASE);
if (sb != NULL){
sb->s_op = &umsdos_sops;
with a special character as the first character
of the extension will be mangled. This solve the
following problem:
-
+
+ #
touch FILE
# FILE is invalid for DOS, so mangling is applied
# file.{_1 is created in the DOS directory
touch file.{_1
# To UMSDOS file point to a single DOS entry.
# So file.{_1 has to be mangled.
+ #
*/
static char special[]={
SPECIAL_MANGLING,'\0'
Control character are converted to #.
Space are converted to #.
The following character are also converted to #.
+ #
" * + , / : ; < = > ? [ \ ] | ~
+ #
Sometime, the problem is not in MsDOS itself but in
command.com.
Here is the list of DOS pseudo devices:
+ #
"prn","con","aux","nul",
"lpt1","lpt2","lpt3","lpt4",
"com1","com2","com3","com4",
"clock$"
+ #
and some standard ones for common DOS programs
Given a file /foo/file
+ #
ln /foo/file /tmp/file2
become internally
mv /foo/file /foo/-LINK1
ln -s /foo/-LINK1 /foo/file
ln -s /foo/-LINK1 /tmp/file2
+ #
Using this strategy, we can operate on /foo/file or /foo/file2.
We can remove one and keep the other, like a normal Unix hard link.
The strategy for hard link introduces a side effect that
may or may not be acceptable. Here is the sequence
+ #
mkdir subdir1
touch subdir1/file
mkdir subdir2
rm subdir1/file
rmdir subdir1
rmdir: subdir1: Directory not empty
+ #
This happen because there is an invisible file (--link) in
subdir1 which is referenced by subdir2/file.
Another weakness of hard link come from the fact that
it is based on hidden symbolic links. Here is an example.
+ #
mkdir /subdir1
touch /subdir1/file
mkdir /subdir2
ln /subdir1/file subdir2/file
mv /subdir1 subdir3
ls -l /subdir2/file
+ #
Since /subdir2/file is a hidden symbolic link
to /subdir1/..hlinkNNN, accessing it will fail since
but you rapidly get iput() all around. Here is an exemple
of what I am trying to avoid.
+ #
if (a){
...
if(b){
}
// Was iput finally done ?
return status;
+ #
Here is the style I am using. Still sometime I do the
first when things are very simple (or very complicated :-( )
+ #
if (a){
if (b){
...
...
}
return status;
+ #
Again, while this help clarifying the code, I often get a lot
of iput(), unlike the first style, where I can place few
where an iput() is done, the inode is simply nulled, disabling
the last one.
+ #
if (a){
if (b){
...
}
iput (dir);
return status;
+ #
Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
pair goes against this practice of "forgetting" the inode as soon
--- /dev/null
+/*
+ * include/asm-alpha/bugs.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ */
+
+/*
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Needs:
+ * void check_bugs(void);
+ */
+
+/*
+ * I don't know of any alpha bugs yet.. Nice chip
+ */
+
+static void check_bugs(void)
+{
+}
--- /dev/null
+/*
+ * include/asm-i386/processor.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ */
+
+#ifndef __ASM_I386_PROCESSOR_H
+#define __ASM_I386_PROCESSOR_H
+
+/*
+ * Bus types
+ */
+extern int EISA_bus;
+#define MCA_bus 0
+
+struct thread_struct {
+ unsigned long ksp;
+ unsigned long usp;
+ unsigned long ptbr;
+ unsigned int pcc;
+ unsigned int asn;
+ unsigned long unique;
+ unsigned long flags;
+ unsigned long res1, res2;
+};
+
+#define INIT_TSS { \
+ 0, 0, 0, \
+ 0, 0, 0, \
+ 0, 0, 0, \
+}
+
+#endif /* __ASM_I386_PROCESSOR_H */
#define PAL_rtsys 61
#define PAL_rti 63
+#define halt() __asm__ __volatile__(".long 0");
+#define move_to_user_mode() halt()
+#define switch_to(x) halt()
+
#ifndef mb
#define mb() __asm__ __volatile__("mb": : :"memory")
#endif
: "$0", "$1", "$16", "$22", "$23", "$24", "$25"); \
__old_ipl; })
+#define cli() swpipl(7)
+#define sti() swpipl(0)
+#define save_flags(flags) do { flags = swpipl(7); } while (0)
+#define restore_flags(flags) swpipl(flags)
+
+extern inline unsigned long xchg_u32(int * m, unsigned long val)
+{
+ unsigned long dummy, dummy2;
+
+ __asm__ __volatile__(
+ "\n1:\t"
+ "ldl_l %0,%1\n\t"
+ "bis %2,%2,%3\n\t"
+ "stl_c %3,%1\n\t"
+ "beq %3,1b\n"
+ : "=r" (val), "=m" (*m), "=r" (dummy), "=r" (dummy2)
+ : "1" (*m), "2" (val));
+ return val;
+}
+
+extern inline unsigned long xchg_u64(long * m, unsigned long val)
+{
+ unsigned long dummy, dummy2;
+
+ __asm__ __volatile__(
+ "\n1:\t"
+ "ldq_l %0,%1\n\t"
+ "bis %2,%2,%3\n\t"
+ "stq_c %3,%1\n\t"
+ "beq %3,1b\n"
+ : "=r" (val), "=m" (*m), "=r" (dummy), "=r" (dummy2)
+ : "1" (*m), "2" (val));
+ return val;
+}
+
+extern inline void * xchg_ptr(void *m, void *val)
+{
+ return (void *) xchg_u64((long *) m, (unsigned long) val);
+}
+
#endif
* header files exported to user space
*/
-typedef signed char __s8;
+typedef __signed__ char __s8;
typedef unsigned char __u8;
-typedef signed short __s16;
+typedef __signed__ short __s16;
typedef unsigned short __u16;
-typedef signed int __s32;
+typedef __signed__ int __s32;
typedef unsigned int __u32;
/*
*/
#if ((~0UL) == 0xffffffff)
-#ifndef __STRICT_ANSI__
-typedef signed long long __s64;
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __signed__ long long __s64;
typedef unsigned long long __u64;
#endif
#else
-typedef signed long __s64;
+typedef __signed__ long __s64;
typedef unsigned long __u64;
#endif
+++ /dev/null
-/*
- * include/asm-generic/string.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_GENERIC_STRING_H_
-#define _ASM_GENERIC_STRING_H_
-
-/*
- * Portable string functions. These are not complete:
- * memcpy() and memmove() are still missing.
- */
-
-#ifdef __USE_PORTABLE_strcpy
-extern inline char * strcpy(char * dest,const char *src)
-{
- char *xdest = dest;
-
- while(*dest++ = *src++);
-
- return xdest;
-}
-#endif
-
-#ifdef __USE_PORTABLE_strncpy
-extern inline char * strncpy(char * dest,const char *src,size_t count)
-{
- char *xdest = dest;
-
- while((*dest++ = *src++) && --count);
-
- return dest;
-}
-#endif
-
-#ifdef __USE_PORTABLE_strcat
-extern inline char * strcat(char * dest, const char * src)
-{
- char *tmp = dest;
-
- while (*dest)
- dest++;
- while ((*dest++ = *src++))
- ;
-
- return tmp;
-}
-#endif
-
-#ifdef __USE_PORTABLE_strncat
-extern inline char * strncat(char *dest, const char *src, size_t count)
-{
- char *tmp = dest;
-
- if (count) {
- while (*dest)
- dest++;
- while ((*dest++ = *src++)) {
- if (--count == 0)
- break;
- }
- }
-
- return tmp;
-}
-#endif
-
-#ifdef __USE_PORTABLE_strcmp
-extern int strcmp(const char * cs,const char * ct)
-{
- register char __res;
-
- while(1) {
- if(__res = *cs - *ct++ && *cs++)
- break;
- }
-
- return __res;
-}
-#endif
-
-#ifdef __USE_PORTABLE_strncmp
-extern inline int strncmp(const char * cs,const char * ct,size_t count)
-{
- register char __res;
-
- while(count) {
- if(__res = *cs - *ct++ || !*cs++)
- break;
- count--;
- }
-
- return __res;
-}
-#endif
-
-#ifdef __USE_PORTABLE_strchr
-extern inline char * strchr(const char * s,char c)
-{
- const char ch = c;
-
- for(; *s != ch; ++s)
- if (*s == '\0')
- return( NULL );
- return( (char *) s);
-}
-#endif
-
-#ifdef __USE_PORTABLE_strlen
-extern inline size_t strlen(const char * s)
-{
- const char *sc;
- for (sc = s; *sc != '\0'; ++sc) ;
- return(sc - s);
-}
-#endif
-
-#ifdef __USE_PORTABLE_strspn
-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;
-}
-#endif
-
-#ifdef __USE_PORTABLE_strpbrk
-extern inline char * strpbrk(const char * cs,const char * ct)
-{
- const char *sc1,*sc2;
-
- for( sc1 = cs; *sc1 != '\0'; ++sc1)
- for( sc2 = ct; *sc2 != '\0'; ++sc2)
- if (*sc1 == *sc2)
- return((char *) sc1);
- return( NULL );
-}
-#endif
-
-#ifdef __USE_PORTABLE_strtok
-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);
- if (send && *send != '\0')
- *send++ = '\0';
- ssave = send;
- return (sbegin);
-}
-#endif
-
-#ifdef __USE_PORTABLE_memset
-extern inline void * memset(void * s,char c,size_t count)
-{
- void *xs = s;
-
- while(n--)
- *s++ = c;
-
- return xs;
-}
-#endif
-
-#ifdef __USE_PORTABLE_memcpy
-#error "Portable memcpy() not implemented yet"
-#endif
-
-#ifdef __USE_PORTABLE_memmove
-#error "Portable memmove() not implemented yet"
-#endif
-
-#ifdef __USE_PORTABLE_memcmp
-extern inline int memcmp(const void * cs,const void * ct,size_t count)
-{
- const unsigned char *su1, *su2;
-
- for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
- if (*su1 != *su2)
- return((*su1 < *su2) ? -1 : +1);
- return(0);
-}
-#endif
-
-#endif /* _ASM_GENERIC_STRING_H_ */
--- /dev/null
+/*
+ * include/asm-i386/bugs.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ */
+
+/*
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Needs:
+ * void check_bugs(void);
+ */
+
+#define CONFIG_BUGi386
+
+static void no_halt(char *s, int *ints)
+{
+ hlt_works_ok = 0;
+}
+
+static void no_387(char *s, int *ints)
+{
+ hard_math = 0;
+ __asm__("movl %%cr0,%%eax\n\t"
+ "orl $0xE,%%eax\n\t"
+ "movl %%eax,%%cr0\n\t" : : : "ax");
+}
+
+static char fpu_error = 0;
+
+static void copro_timeout(void)
+{
+ fpu_error = 1;
+ timer_table[COPRO_TIMER].expires = jiffies+100;
+ timer_active |= 1<<COPRO_TIMER;
+ printk("387 failed: trying to reset\n");
+ send_sig(SIGFPE, last_task_used_math, 1);
+ outb_p(0,0xf1);
+ outb_p(0,0xf0);
+}
+
+static void check_fpu(void)
+{
+ static double x = 4195835.0;
+ static double y = 3145727.0;
+ unsigned short control_word;
+
+ if (!hard_math) {
+#ifndef CONFIG_MATH_EMULATION
+ printk("No coprocessor found and no math emulation present.\n");
+ printk("Giving up.\n");
+ for (;;) ;
+#endif
+ return;
+ }
+ /*
+ * check if exception 16 works correctly.. This is truly evil
+ * code: it disables the high 8 interrupts to make sure that
+ * the irq13 doesn't happen. But as this will lead to a lockup
+ * if no exception16 arrives, it depends on the fact that the
+ * high 8 interrupts will be re-enabled by the next timer tick.
+ * So the irq13 will happen eventually, but the exception 16
+ * should get there first..
+ */
+ printk("Checking 386/387 coupling... ");
+ timer_table[COPRO_TIMER].expires = jiffies+50;
+ timer_table[COPRO_TIMER].fn = copro_timeout;
+ timer_active |= 1<<COPRO_TIMER;
+ __asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word));
+ control_word &= 0xffc0;
+ __asm__("fldcw %0 ; fwait": :"m" (*&control_word));
+ outb_p(inb_p(0x21) | (1 << 2), 0x21);
+ __asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait");
+ timer_active &= ~(1<<COPRO_TIMER);
+ if (fpu_error)
+ return;
+ if (!ignore_irq13) {
+ printk("Ok, fpu using old IRQ13 error reporting\n");
+ return;
+ }
+ __asm__("fninit\n\t"
+ "fldl %1\n\t"
+ "fdivl %2\n\t"
+ "fmull %2\n\t"
+ "fldl %1\n\t"
+ "fsubp %%st,%%st(1)\n\t"
+ "fistpl %0\n\t"
+ "fwait\n\t"
+ "fninit"
+ : "=m" (*&fdiv_bug)
+ : "m" (*&x), "m" (*&y));
+ if (!fdiv_bug) {
+ printk("Ok, fpu using exception 16 error reporting.\n");
+ return;
+
+ }
+ printk("Ok, FDIV bug i%c86 system\n", '0'+x86);
+}
+
+static void check_hlt(void)
+{
+ printk("Checking 'hlt' instruction... ");
+ if (!hlt_works_ok) {
+ printk("disabled\n");
+ return;
+ }
+ __asm__ __volatile__("hlt ; hlt ; hlt ; hlt");
+ printk("Ok.\n");
+}
+
+static void check_bugs(void)
+{
+ check_fpu();
+ check_hlt();
+ system_utsname.machine[1] = '0' + x86;
+}
--- /dev/null
+/*
+ * include/asm-i386/processor.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ */
+
+#ifndef __ASM_I386_PROCESSOR_H
+#define __ASM_I386_PROCESSOR_H
+
+/*
+ * System setup and hardware bug flags..
+ */
+extern char hard_math;
+extern char x86; /* lower 4 bits */
+extern char x86_vendor_id[13];
+extern char x86_model; /* lower 4 bits */
+extern char x86_mask; /* lower 4 bits */
+extern int x86_capability; /* field of flags */
+extern int fdiv_bug;
+extern char ignore_irq13;
+extern char wp_works_ok; /* doesn't work on a 386 */
+extern char hlt_works_ok; /* problems on some 486Dx4's and old 386's */
+
+#define start_bh_atomic() \
+__asm__ __volatile__("incl _intr_count")
+
+#define end_bh_atomic() \
+__asm__ __volatile__("decl _intr_count")
+
+/*
+ * Bus types (default is ISA, but people can check others with these..)
+ * MCA_bus hardcoded to 0 for now.
+ */
+extern int EISA_bus;
+#define MCA_bus 0
+
+/*
+ * User space process size: 3GB. This is hardcoded into a few places,
+ * so don't change it unless you know what you are doing.
+ */
+#define TASK_SIZE 0xc0000000
+
+/*
+ * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
+ */
+#define IO_BITMAP_SIZE 32
+
+struct i387_hard_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+struct i387_soft_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long top;
+ struct fpu_reg regs[8]; /* 8*16 bytes for each FP-reg = 128 bytes */
+ unsigned char lookahead;
+ struct info *info;
+ unsigned long entry_eip;
+};
+
+union i387_union {
+ struct i387_hard_struct hard;
+ struct i387_soft_struct soft;
+};
+
+struct thread_struct {
+ unsigned short back_link,__blh;
+ unsigned long esp0;
+ unsigned short ss0,__ss0h;
+ unsigned long esp1;
+ unsigned short ss1,__ss1h;
+ unsigned long esp2;
+ unsigned short ss2,__ss2h;
+ unsigned long cr3;
+ unsigned long eip;
+ unsigned long eflags;
+ unsigned long eax,ecx,edx,ebx;
+ unsigned long esp;
+ unsigned long ebp;
+ unsigned long esi;
+ unsigned long edi;
+ unsigned short es, __esh;
+ unsigned short cs, __csh;
+ unsigned short ss, __ssh;
+ unsigned short ds, __dsh;
+ unsigned short fs, __fsh;
+ unsigned short gs, __gsh;
+ unsigned short ldt, __ldth;
+ unsigned short trace, bitmap;
+ unsigned long io_bitmap[IO_BITMAP_SIZE+1];
+ unsigned long tr;
+ unsigned long cr2, trap_no, error_code;
+/* floating point info */
+ union i387_union i387;
+/* virtual 86 mode info */
+ struct vm86_struct * vm86_info;
+ unsigned long screen_bitmap;
+ unsigned long v86flags, v86mask, v86mode;
+};
+
+#define INIT_TSS { \
+ 0,0, \
+ sizeof(init_kernel_stack) + (long) &init_kernel_stack, \
+ KERNEL_DS, 0, \
+ 0,0,0,0,0,0, \
+ (long) &swapper_pg_dir, \
+ 0,0,0,0,0,0,0,0,0,0, \
+ USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0, \
+ _LDT(0),0, \
+ 0, 0x8000, \
+ {~0, }, /* ioperm */ \
+ _TSS(0), 0, 0,0, \
+ { { 0, }, }, /* 387 state */ \
+ NULL, 0, 0, 0, 0 /* vm86_info */ \
+}
+
+#endif /* __ASM_I386_PROCESSOR_H */
"mov %%ax,%%gs" \
: /* no outputs */ :"i" (USER_DS), "i" (USER_CS):"ax")
+/*
+ * Entry into gdt where to find first TSS. GDT layout:
+ * 0 - nul
+ * 1 - kernel code segment
+ * 2 - kernel data segment
+ * 3 - user code segment
+ * 4 - user data segment
+ * ...
+ * 8 - TSS #0
+ * 9 - LDT #0
+ * 10 - TSS #1
+ * 11 - LDT #1
+ */
+#define FIRST_TSS_ENTRY 8
+#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
+#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
+#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
+#define load_TR(n) __asm__("ltr %%ax": /* no output */ :"a" (_TSS(n)))
+#define load_ldt(n) __asm__("lldt %%ax": /* no output */ :"a" (_LDT(n)))
+#define store_TR(n) \
+__asm__("str %%ax\n\t" \
+ "subl %2,%%eax\n\t" \
+ "shrl $4,%%eax" \
+ :"=a" (n) \
+ :"0" (0),"i" (FIRST_TSS_ENTRY<<3))
+
+/* This special macro can be used to load a debugging register */
+
+#define loaddebug(register) \
+ __asm__("movl %0,%%edx\n\t" \
+ "movl %%edx,%%db" #register "\n\t" \
+ : /* no output */ \
+ :"m" (current->debugreg[register]) \
+ :"dx");
+
+
+/*
+ * switch_to(n) should switch tasks to task nr n, first
+ * checking that n isn't the current task, in which case it does nothing.
+ * This also clears the TS-flag if the task we switched to has used
+ * the math co-processor latest.
+ *
+ * It also reloads the debug regs if necessary..
+ */
+#define switch_to(tsk) do { \
+__asm__("cli\n\t" \
+ "xchgl %%ecx,_current\n\t" \
+ "ljmp %0\n\t" \
+ "sti\n\t" \
+ "cmpl %%ecx,_last_task_used_math\n\t" \
+ "jne 1f\n\t" \
+ "clts\n" \
+ "1:" \
+ : /* no output */ \
+ :"m" (*(((char *)&tsk->tss.tr)-4)), \
+ "c" (tsk) \
+ :"cx"); \
+ /* Now maybe reload the debug registers */ \
+ if(current->debugreg[7]){ \
+ loaddebug(0); \
+ loaddebug(1); \
+ loaddebug(2); \
+ loaddebug(3); \
+ loaddebug(6); \
+ } \
+} while (0)
+
+#define _set_base(addr,base) \
+__asm__("movw %%dx,%0\n\t" \
+ "rorl $16,%%edx\n\t" \
+ "movb %%dl,%1\n\t" \
+ "movb %%dh,%2" \
+ : /* no output */ \
+ :"m" (*((addr)+2)), \
+ "m" (*((addr)+4)), \
+ "m" (*((addr)+7)), \
+ "d" (base) \
+ :"dx")
+
+#define _set_limit(addr,limit) \
+__asm__("movw %%dx,%0\n\t" \
+ "rorl $16,%%edx\n\t" \
+ "movb %1,%%dh\n\t" \
+ "andb $0xf0,%%dh\n\t" \
+ "orb %%dh,%%dl\n\t" \
+ "movb %%dl,%1" \
+ : /* no output */ \
+ :"m" (*(addr)), \
+ "m" (*((addr)+6)), \
+ "d" (limit) \
+ :"dx")
+
+#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )
+#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 )
+
+static inline unsigned long _get_base(char * addr)
+{
+ unsigned long __base;
+ __asm__("movb %3,%%dh\n\t"
+ "movb %2,%%dl\n\t"
+ "shll $16,%%edx\n\t"
+ "movw %1,%%dx"
+ :"=&d" (__base)
+ :"m" (*((addr)+2)),
+ "m" (*((addr)+4)),
+ "m" (*((addr)+7)));
+ return __base;
+}
+
+#define get_base(ldt) _get_base( ((char *)&(ldt)) )
+
+static inline unsigned long get_limit(unsigned long segment)
+{
+ unsigned long __limit;
+ __asm__("lsll %1,%0"
+ :"=r" (__limit):"r" (segment));
+ return __limit+1;
+}
+
#define nop() __asm__ __volatile__ ("nop")
/*
:"ax")
+extern inline unsigned long xchg_u8(char * m, unsigned long val)
+{
+ __asm__("xchgb %b0,%1":"=q" (val),"=m" (*m):"0" (val):"memory");
+ return val;
+}
+
+extern inline unsigned long xchg_u16(short * m, unsigned long val)
+{
+ __asm__("xchgw %w0,%1":"=r" (val),"=m" (*m):"0" (val):"memory");
+ return val;
+}
+
+extern inline unsigned long xchg_u32(long * m, unsigned long val)
+{
+ __asm__("xchgl %0,%1":"=r" (val),"=m" (*m):"0" (val):"memory");
+ return val;
+}
+
extern inline int tas(char * m)
{
- char res;
+ return xchg_u8(m,1);
+}
- __asm__("xchgb %0,%1":"=q" (res),"=m" (*m):"0" (0x1));
- return res;
+extern inline void * xchg_ptr(void * m, void * val)
+{
+ return (void *) xchg_u32(m, (unsigned long) val);
}
#define sti() __asm__ __volatile__ ("sti": : :"memory")
#define set_ldt_desc(n,addr,size) \
_set_tssldt_desc(((char *) (n)),((int)(addr)),((size << 3) - 1),"0x82")
+/*
+ * This is the ldt that every process will get unless we need
+ * something other than this.
+ */
+extern struct desc_struct default_ldt;
#endif
typedef __signed__ long __s32;
typedef unsigned long __u32;
-#ifndef __STRICT_ANSI__
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
typedef __signed__ long long __s64;
typedef unsigned long long __u64;
#endif
--- /dev/null
+/* include/asm-sparc/bugs.h: Sparc probes for various bugs.
+ *
+ * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/*
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Needs:
+ * void check_bugs(void);
+ */
+
+#define CONFIG_BUGSPARC
+
+#include <asm/openprom.h>
+
+extern struct promvec *romvec;
+extern int tbase_needs_unmapping; /* We do the bug workaround in pagetables.c */
+
+static void check_mmu()
+{
+ register struct promvec *romvec;
+ register int root_node;
+ register unsigned int present;
+
+ root_node = (*(romvec->pv_nodeops->no_nextnode))(0);
+ tbase_needs_unmapping=0;
+
+ present = 0;
+ (*(romvec->pv_nodeops->no_getprop))(root_node, "buserr-type",
+ (char *) &present);
+ if(present == 1)
+ {
+ tbase_needs_unmapping=1;
+ printk("MMU bug found: not allowing trapbase to be cached\n");
+ }
+
+ return;
+}
+
+
+static void
+check_bugs(void)
+{
+ check_mmu();
+}
+#ifndef _SPARC_OPENPROM_H
+#define _SPARC_OPENPROM_H
+
/* openprom.h: Prom structures and defines for access to the OPENBOOT
prom routines and data areas.
#define LINUX_OPPROM_MAGIC 0x10010407
/* The device functions structure for the v0 prom. Nice and neat, open,
- close, read & write divied up between net + block + char devices. We
+ close, read & write divvied up between net + block + char devices. We
also have a seek routine only usable for block devices. The divide
and conquer strategy of this struct becomes unnecessary for v2.
the time can be a pain in the rear after a while. Why v2 has memory
allocations in here are beyond me. Perhaps they figure that if you
are going to use only the prom's device drivers then your memory
- management is either non-existant or pretty sad. :-)
+ management is either non-existent or pretty sad. :-)
*/
struct linux_dev_v2_funcs {
caddr_t (*v2_dumb_mem_alloc)(caddr_t va, unsigned sz);
void (*v2_dumb_mem_free)(caddr_t va, unsigned sz);
- /* "dumb" mmap() munmap(), copy on write? whats that? */
+ /* "dumb" mmap() munmap(), copy on write? what's that? */
caddr_t (*v2_dumb_mmap)(caddr_t virta, int asi, unsigned prot, unsigned sz);
void (*v2_dumb_munmap)(caddr_t virta, unsigned size);
struct linux_mlist_v0 **v0_available; /* what phys. is left over */
};
-/* Arguements sent to the kernel from the boot prompt. */
+/* Arguments sent to the kernel from the boot prompt. */
struct linux_arguments_v0 {
char *argv[8]; /* argv format for boot string */
int (*no_setprop)(int node, caddr_t name, caddr_t val, int len);
caddr_t (*no_nextprop)(int node, caddr_t name);
};
+
+#endif /* !(_SPARC_OPENPROM_H) */
* however this won't be for a while.
*/
-typedef signed char __s8;
+typedef __signed__ char __s8;
typedef unsigned char __u8;
-typedef signed short __s16;
+typedef __signed__ short __s16;
typedef unsigned short __u16;
-typedef signed int __s32;
+typedef __signed__ int __s32;
typedef unsigned int __u32;
/* Only 32-bit sparcs for now so.... */
-typedef signed long long __s64;
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __signed__ long long __s64;
typedef unsigned long long __s64;
+#endif
#ifdef __KERNEL__
extern int * blksize_size[MAX_BLKDEV];
+extern int * hardsect_size[MAX_BLKDEV];
+
#endif
#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif
-#ifndef UTS_NODENAME
-#define UTS_NODENAME "(none)" /* set by sethostname() */
-#endif
#ifndef UTS_MACHINE
-#define UTS_MACHINE "i386" /* hardware type */
+#define UTS_MACHINE "unknown"
+#endif
+
+#ifndef UTS_NODENAME
+#define UTS_NODENAME "(none)" /* set by sethostname() */
#endif
#ifndef UTS_DOMAINNAME
extern unsigned long int htonl(unsigned long int);
extern unsigned short int htons(unsigned short int);
+extern unsigned long int __ntohl(unsigned long int);
+extern unsigned short int __ntohs(unsigned short int);
+extern unsigned long int __constant_ntohl(unsigned long int);
+extern unsigned short int __constant_ntohs(unsigned short int);
+
extern __inline__ unsigned long int
__ntohl(unsigned long int x)
{
#ifndef _LINUX_INTERRUPT_H
#define _LINUX_INTERRUPT_H
+#include <asm/bitops.h>
+
struct bh_struct {
void (*routine)(void *);
void *data;
extern inline void mark_bh(int nr)
{
- __asm__ __volatile__("orl %1,%0":"=m" (bh_active):"ir" (1<<nr));
+ set_bit(nr, &bh_active);
}
extern inline void disable_bh(int nr)
{
- __asm__ __volatile__("andl %1,%0":"=m" (bh_mask):"ir" (~(1<<nr)));
+ clear_bit(nr, &bh_mask);
}
extern inline void enable_bh(int nr)
{
- __asm__ __volatile__("orl %1,%0":"=m" (bh_mask):"ir" (1<<nr));
+ set_bit(nr, &bh_mask);
}
#endif
#ifdef __KERNEL__
-static inline struct buffer_head *msdos_sread(int dev,int sector)
-{
- return bread(dev,sector,SECTOR_SIZE);
-}
-
-
/* misc.c */
extern void fs_panic(struct super_block *s,char *msg);
/* file.c */
extern struct inode_operations msdos_file_inode_operations;
+extern struct inode_operations msdos_file_inode_operations_1024;
extern int msdos_file_read(struct inode *, struct file *, char *, int);
extern int msdos_file_write(struct inode *, struct file *, char *, int);
extern struct inode_operations msdos_file_inode_operations_no_bmap;
PROC_KSYMS,
PROC_DMA,
PROC_IOPORTS,
- PROC_PROFILE /* wether enabled or not */
+ PROC_PROFILE /* whether enabled or not */
};
enum pid_directory_inos {
#define RLIM_INFINITY ((long)(~0UL>>1))
struct rlimit {
- int rlim_cur;
- int rlim_max;
+ long rlim_cur;
+ long rlim_max;
};
#define PRIO_MIN (-99)
#define HZ 100
-/*
- * System setup and hardware bug flags..
- */
-extern char hard_math;
-extern char x86; /* lower 4 bits */
-extern char x86_vendor_id[13];
-extern char x86_model; /* lower 4 bits */
-extern char x86_mask; /* lower 4 bits */
-extern int x86_capability; /* field of flags */
-extern int fdiv_bug;
-extern char ignore_irq13;
-extern char wp_works_ok; /* doesn't work on a 386 */
-extern char hlt_works_ok; /* problems on some 486Dx4's and old 386's */
-
extern unsigned long intr_count;
extern unsigned long event;
-#define start_bh_atomic() \
-__asm__ __volatile__("incl _intr_count")
-
-#define end_bh_atomic() \
-__asm__ __volatile__("decl _intr_count")
-
-/*
- * Bus types (default is ISA, but people can check others with these..)
- * MCA_bus hardcoded to 0 for now.
- */
-extern int EISA_bus;
-#define MCA_bus 0
-
#include <linux/binfmts.h>
#include <linux/personality.h>
#include <linux/tasks.h>
#include <asm/system.h>
-/*
- * User space process size: 3GB. This is hardcoded into a few places,
- * so don't change it unless you know what you are doing.
- */
-#define TASK_SIZE 0xc0000000
-
-/*
- * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
- */
-#define IO_BITMAP_SIZE 32
-
/*
* These are the constant used to fake the fixed-point load-average
* counting. Some notes:
#include <linux/math_emu.h>
#include <linux/ptrace.h>
+#include <asm/processor.h>
+
#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
#endif /* __KERNEL__ */
-struct i387_hard_struct {
- long cwd;
- long swd;
- long twd;
- long fip;
- long fcs;
- long foo;
- long fos;
- long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
-};
-
-struct i387_soft_struct {
- long cwd;
- long swd;
- long twd;
- long fip;
- long fcs;
- long foo;
- long fos;
- long top;
- struct fpu_reg regs[8]; /* 8*16 bytes for each FP-reg = 128 bytes */
- unsigned char lookahead;
- struct info *info;
- unsigned long entry_eip;
-};
-
-union i387_union {
- struct i387_hard_struct hard;
- struct i387_soft_struct soft;
-};
-
-struct tss_struct {
- unsigned short back_link,__blh;
- unsigned long esp0;
- unsigned short ss0,__ss0h;
- unsigned long esp1;
- unsigned short ss1,__ss1h;
- unsigned long esp2;
- unsigned short ss2,__ss2h;
- unsigned long cr3;
- unsigned long eip;
- unsigned long eflags;
- unsigned long eax,ecx,edx,ebx;
- unsigned long esp;
- unsigned long ebp;
- unsigned long esi;
- unsigned long edi;
- unsigned short es, __esh;
- unsigned short cs, __csh;
- unsigned short ss, __ssh;
- unsigned short ds, __dsh;
- unsigned short fs, __fsh;
- unsigned short gs, __gsh;
- unsigned short ldt, __ldth;
- unsigned short trace, bitmap;
- unsigned long io_bitmap[IO_BITMAP_SIZE+1];
- unsigned long tr;
- unsigned long cr2, trap_no, error_code;
- union i387_union i387;
-};
-
-#define INIT_TSS { \
- 0,0, \
- sizeof(init_kernel_stack) + (long) &init_kernel_stack, \
- KERNEL_DS, 0, \
- 0,0,0,0,0,0, \
- (long) &swapper_pg_dir, \
- 0,0,0,0,0,0,0,0,0,0, \
- USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0, \
- _LDT(0),0, \
- 0, 0x8000, \
- {~0, }, /* ioperm */ \
- _TSS(0), 0, 0,0, \
- { { 0, }, } /* 387 state */ \
-}
-
struct files_struct {
int count;
fd_set close_on_exec;
struct rlimit rlim[RLIM_NLIMITS];
unsigned short used_math;
char comm[16];
-/* virtual 86 mode stuff */
- struct vm86_struct * vm86_info;
- unsigned long screen_bitmap;
- unsigned long v86flags, v86mask, v86mode;
/* file system info */
int link_count;
struct tty_struct *tty; /* NULL if no tty */
/* ldt for this task - used by Wine. If NULL, default_ldt is used */
struct desc_struct *ldt;
/* tss for this task */
- struct tss_struct tss;
+ struct thread_struct tss;
/* filesystem information */
struct fs_struct fs[1];
/* open file information */
{ 0, LONG_MAX}, {LONG_MAX, LONG_MAX}}, \
/* math */ 0, \
/* comm */ "swapper", \
-/* vm86_info */ NULL, 0, 0, 0, 0, \
/* fs info */ 0,NULL, \
/* ipc */ NULL, \
/* ldt */ NULL, \
extern int request_irq(unsigned int irq,void (*handler)(int), unsigned long flags, const char *device);
extern void free_irq(unsigned int irq);
-/*
- * Entry into gdt where to find first TSS. GDT layout:
- * 0 - nul
- * 1 - kernel code segment
- * 2 - kernel data segment
- * 3 - user code segment
- * 4 - user data segment
- * ...
- * 8 - TSS #0
- * 9 - LDT #0
- * 10 - TSS #1
- * 11 - LDT #1
- */
-#define FIRST_TSS_ENTRY 8
-#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
-#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
-#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
-#define load_TR(n) __asm__("ltr %%ax": /* no output */ :"a" (_TSS(n)))
-#define load_ldt(n) __asm__("lldt %%ax": /* no output */ :"a" (_LDT(n)))
-#define store_TR(n) \
-__asm__("str %%ax\n\t" \
- "subl %2,%%eax\n\t" \
- "shrl $4,%%eax" \
- :"=a" (n) \
- :"0" (0),"i" (FIRST_TSS_ENTRY<<3))
-/*
- * switch_to(n) should switch tasks to task nr n, first
- * checking that n isn't the current task, in which case it does nothing.
- * This also clears the TS-flag if the task we switched to has used
- * tha math co-processor latest.
- */
-#define switch_to(tsk) \
-__asm__("cli\n\t" \
- "xchgl %%ecx,_current\n\t" \
- "ljmp %0\n\t" \
- "sti\n\t" \
- "cmpl %%ecx,_last_task_used_math\n\t" \
- "jne 1f\n\t" \
- "clts\n" \
- "1:" \
- : /* no output */ \
- :"m" (*(((char *)&tsk->tss.tr)-4)), \
- "c" (tsk) \
- :"cx")
-
-#define _set_base(addr,base) \
-__asm__("movw %%dx,%0\n\t" \
- "rorl $16,%%edx\n\t" \
- "movb %%dl,%1\n\t" \
- "movb %%dh,%2" \
- : /* no output */ \
- :"m" (*((addr)+2)), \
- "m" (*((addr)+4)), \
- "m" (*((addr)+7)), \
- "d" (base) \
- :"dx")
-
-#define _set_limit(addr,limit) \
-__asm__("movw %%dx,%0\n\t" \
- "rorl $16,%%edx\n\t" \
- "movb %1,%%dh\n\t" \
- "andb $0xf0,%%dh\n\t" \
- "orb %%dh,%%dl\n\t" \
- "movb %%dl,%1" \
- : /* no output */ \
- :"m" (*(addr)), \
- "m" (*((addr)+6)), \
- "d" (limit) \
- :"dx")
-
-#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )
-#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 )
-
/*
* The wait-queues are circular lists, and you have to be *very* sure
* to keep them correct. Use only these two functions to add/remove
wake_up(&sem->wait);
}
-static inline unsigned long _get_base(char * addr)
-{
- unsigned long __base;
- __asm__("movb %3,%%dh\n\t"
- "movb %2,%%dl\n\t"
- "shll $16,%%edx\n\t"
- "movw %1,%%dx"
- :"=&d" (__base)
- :"m" (*((addr)+2)),
- "m" (*((addr)+4)),
- "m" (*((addr)+7)));
- return __base;
-}
-
-#define get_base(ldt) _get_base( ((char *)&(ldt)) )
-
-static inline unsigned long get_limit(unsigned long segment)
-{
- unsigned long __limit;
- __asm__("lsll %1,%0"
- :"=r" (__limit):"r" (segment));
- return __limit+1;
-}
-
#define REMOVE_LINKS(p) do { unsigned long flags; \
save_flags(flags) ; cli(); \
(p)->next_task->prev_task = (p)->prev_task; \
#define for_each_task(p) \
for (p = &init_task ; (p = p->next_task) != &init_task ; )
-/*
- * This is the ldt that every process will get unless we need
- * something other than this.
- */
-extern struct desc_struct default_ldt;
-
-/* This special macro can be used to load a debugging register */
-
-#define loaddebug(register) \
- __asm__("movl %0,%%edx\n\t" \
- "movl %%edx,%%db" #register "\n\t" \
- : /* no output */ \
- :"m" (current->debugreg[register]) \
- :"dx");
-
#endif /* __KERNEL__ */
#endif
extern "C" {
#endif
+extern char * strcpy(char *,const char *);
+extern char * strncpy(char *,const char *,size_t);
+extern char * strcat(char *, const char *);
+extern char * strncat(char *, const char *, size_t);
+extern char * strchr(const char *,char);
+extern char * strpbrk(const char *,const char *);
+extern char * strtok(char *,const char *);
+extern size_t strlen(const char *);
+extern size_t strspn(const char *,const char *);
+extern int strcmp(const char *,const char *);
+extern int strncmp(const char *,const char *,size_t);
+
+extern void * memset(void *,char,size_t);
+extern void * memcpy(void *,const void *,size_t);
+extern void * memmove(void *,const void *,size_t);
+extern int memcmp(const void *,const void *,size_t);
+
/*
* Include machine specific inline routines
*/
#include <asm/string.h>
-#ifdef __USE_PORTABLE_STRINGS_H_
-/*
- * include/generic/string.h imports all the string functions,
- * for which no appropriate assembler replacements have been provided.
- */
-#include <asm-generic/string.h>
-#endif
-
#ifdef __cplusplus
}
#endif
void (*f) (void *);
while(1) {
- p = &tq_last;
- __asm__ __volatile__("xchgl %0,%2" : "=r" (p) :
- "0" (p), "m" (*list) : "memory");
+ p = xchg_ptr(list,&tq_last);
if(p == &tq_last)
break;
typedef int daddr_t;
typedef long off_t;
-#ifndef __STRICT_ANSI__
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define _LOFF_T
typedef long long loff_t;
#endif
#include <linux/utsname.h>
#include <linux/ioport.h>
+#include <asm/bugs.h>
+
extern unsigned long * prof_buffer;
extern unsigned long prof_len;
extern char etext, end;
extern char *linux_banner;
-asmlinkage void lcall7(void);
-struct desc_struct default_ldt;
/*
* we need this inline - forking from kernel space will result
int ramdisk_size;
int root_mountflags = 0;
-static char fpu_error = 0;
-
static char command_line[COMMAND_LINE_SIZE] = { 0, };
char *get_options(char *str, int *ints)
} bootsetups[] = {
{ "reserve=", reserve_setup },
{ "ramdisk=", ramdisk_setup },
+#ifdef CONFIG_BUGi386
+ { "no-hlt", no_halt },
+ { "no387", no_387 },
+#endif
#ifdef CONFIG_INET
{ "ether=", eth_setup },
#endif
console_loglevel = 10;
continue;
}
- if (!strcmp(line,"no-hlt")) {
- hlt_works_ok = 0;
- continue;
- }
- if (!strcmp(line,"no387")) {
- hard_math = 0;
- __asm__("movl %%cr0,%%eax\n\t"
- "orl $0xE,%%eax\n\t"
- "movl %%eax,%%cr0\n\t" : : : "ax");
- continue;
- }
if (checksetup(line))
continue;
/*
*to = '\0';
}
-static void copro_timeout(void)
-{
- fpu_error = 1;
- timer_table[COPRO_TIMER].expires = jiffies+100;
- timer_active |= 1<<COPRO_TIMER;
- printk("387 failed: trying to reset\n");
- send_sig(SIGFPE, last_task_used_math, 1);
- outb_p(0,0xf1);
- outb_p(0,0xf0);
-}
-
-static void check_fpu(void)
-{
- static double x = 4195835.0;
- static double y = 3145727.0;
- unsigned short control_word;
-
- if (!hard_math) {
-#ifndef CONFIG_MATH_EMULATION
- printk("No coprocessor found and no math emulation present.\n");
- printk("Giving up.\n");
- for (;;) ;
-#endif
- return;
- }
- /*
- * check if exception 16 works correctly.. This is truly evil
- * code: it disables the high 8 interrupts to make sure that
- * the irq13 doesn't happen. But as this will lead to a lockup
- * if no exception16 arrives, it depends on the fact that the
- * high 8 interrupts will be re-enabled by the next timer tick.
- * So the irq13 will happen eventually, but the exception 16
- * should get there first..
- */
- printk("Checking 386/387 coupling... ");
- timer_table[COPRO_TIMER].expires = jiffies+50;
- timer_table[COPRO_TIMER].fn = copro_timeout;
- timer_active |= 1<<COPRO_TIMER;
- __asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word));
- control_word &= 0xffc0;
- __asm__("fldcw %0 ; fwait": :"m" (*&control_word));
- outb_p(inb_p(0x21) | (1 << 2), 0x21);
- __asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait");
- timer_active &= ~(1<<COPRO_TIMER);
- if (fpu_error)
- return;
- if (!ignore_irq13) {
- printk("Ok, fpu using old IRQ13 error reporting\n");
- return;
- }
- __asm__("fninit\n\t"
- "fldl %1\n\t"
- "fdivl %2\n\t"
- "fmull %2\n\t"
- "fldl %1\n\t"
- "fsubp %%st,%%st(1)\n\t"
- "fistpl %0\n\t"
- "fwait\n\t"
- "fninit"
- : "=m" (*&fdiv_bug)
- : "m" (*&x), "m" (*&y));
- if (!fdiv_bug) {
- printk("Ok, fpu using exception 16 error reporting.\n");
- return;
-
- }
- printk("Ok, FDIV bug i%c86 system\n", '0'+x86);
-}
-
-static void check_hlt(void)
-{
- printk("Checking 'hlt' instruction... ");
- if (!hlt_works_ok) {
- printk("disabled\n");
- return;
- }
- __asm__ __volatile__("hlt ; hlt ; hlt ; hlt");
- printk("Ok.\n");
-}
-
-static void check_bugs(void)
-{
- check_fpu();
- check_hlt();
-}
+extern void check_bugs(void);
asmlinkage void start_kernel(void)
{
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
- set_call_gate(&default_ldt,lcall7);
ROOT_DEV = ORIG_ROOT_DEV;
drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO;
sti();
check_bugs();
- system_utsname.machine[1] = '0' + x86;
printk(linux_banner);
move_to_user_mode();
if (p->ldt != NULL)
memcpy(p->ldt, current->ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
}
- p->tss.bitmap = offsetof(struct tss_struct,io_bitmap);
+ p->tss.bitmap = offsetof(struct thread_struct,io_bitmap);
for (i = 0; i < IO_BITMAP_SIZE+1 ; i++) /* IO bitmap is actually SIZE+1 */
p->tss.io_bitmap[i] = ~0;
if (last_task_used_math == current)
X(block_fsync),
X(wait_for_request),
X(blksize_size),
+ X(hardsect_size),
X(blk_size),
X(blk_dev),
X(is_read_only),
extern void mem_use(void);
extern int timer_interrupt(void);
-asmlinkage int system_call(void);
-
+
static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
+unsigned long init_user_stack[1024] = { STACK_MAGIC, };
static struct vm_area_struct init_mmap = INIT_MMAP;
struct task_struct init_task = INIT_TASK;
struct task_struct * task[NR_TASKS] = {&init_task, };
-long user_stack [ PAGE_SIZE>>2 ] = { STACK_MAGIC, };
-
-struct {
- long * a;
- short b;
- } stack_start = { & user_stack [PAGE_SIZE>>2] , KERNEL_DS };
-
struct kernel_stat kstat = { 0 };
-/*
- * 'math_state_restore()' saves the current math information in the
- * old math state array, and gets the new ones from the current task
- *
- * Careful.. There are problems with IBM-designed IRQ13 behaviour.
- * Don't touch unless you *really* know how it works.
- */
-asmlinkage void math_state_restore(void)
-{
- __asm__ __volatile__("clts");
- if (last_task_used_math == current)
- return;
- timer_table[COPRO_TIMER].expires = jiffies+50;
- timer_active |= 1<<COPRO_TIMER;
- if (last_task_used_math)
- __asm__("fnsave %0":"=m" (last_task_used_math->tss.i387));
- else
- __asm__("fnclex");
- last_task_used_math = current;
- if (current->used_math) {
- __asm__("frstor %0": :"m" (current->tss.i387));
- } else {
- __asm__("fninit");
- current->used_math=1;
- }
- timer_active &= ~(1<<COPRO_TIMER);
-}
-
-#ifndef CONFIG_MATH_EMULATION
-
-asmlinkage void math_emulate(long arg)
-{
- printk("math-emulation not enabled and no coprocessor found.\n");
- printk("killing %s.\n",current->comm);
- send_sig(SIGFPE,current,1);
- schedule();
-}
-
-#endif /* CONFIG_MATH_EMULATION */
-
unsigned long itimer_ticks = 0;
unsigned long itimer_next = ~0;
return;
kstat.context_swtch++;
switch_to(next);
- /* Now maybe reload the debug registers */
- if(current->debugreg[7]){
- loaddebug(0);
- loaddebug(1);
- loaddebug(2);
- loaddebug(3);
- loaddebug(6);
- };
}
asmlinkage int sys_pause(void)
printk(stat_nam[p->state]);
else
printk(" ");
+#ifdef __i386__
if (p == current)
printk(" current ");
else
printk(" %08lX ", ((unsigned long *)p->tss.esp)[3]);
+#endif
for (free = 1; free < 1024 ; free++) {
if (((unsigned long *)p->kernel_stack_page)[free])
break;
void sched_init(void)
{
- int i;
- struct desc_struct * p;
-
bh_base[TIMER_BH].routine = timer_bh;
bh_base[TQUEUE_BH].routine = tqueue_bh;
bh_base[IMMEDIATE_BH].routine = immediate_bh;
if (sizeof(struct sigaction) != 16)
panic("Struct sigaction MUST be 16 bytes");
- set_tss_desc(gdt+FIRST_TSS_ENTRY,&init_task.tss);
- set_ldt_desc(gdt+FIRST_LDT_ENTRY,&default_ldt,1);
- set_system_gate(0x80,&system_call);
- p = gdt+2+FIRST_TSS_ENTRY;
- for(i=1 ; i<NR_TASKS ; i++) {
- task[i] = NULL;
- p->a=p->b=0;
- p++;
- p->a=p->b=0;
- p++;
- }
-/* Clear NT, so that we won't have troubles with that later on */
- __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
- load_TR(0);
- load_ldt(0);
outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
outb_p(LATCH & 0xff , 0x40); /* LSB */
outb(LATCH >> 8 , 0x40); /* MSB */
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
+#include <linux/config.h>
+#include <linux/timer.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
+asmlinkage int system_call(void);
+asmlinkage void lcall7(void);
+struct desc_struct default_ldt;
+
static inline void console_verbose(void)
{
extern int console_loglevel;
math_error();
}
+/*
+ * 'math_state_restore()' saves the current math information in the
+ * old math state array, and gets the new ones from the current task
+ *
+ * Careful.. There are problems with IBM-designed IRQ13 behaviour.
+ * Don't touch unless you *really* know how it works.
+ */
+asmlinkage void math_state_restore(void)
+{
+ __asm__ __volatile__("clts");
+ if (last_task_used_math == current)
+ return;
+ timer_table[COPRO_TIMER].expires = jiffies+50;
+ timer_active |= 1<<COPRO_TIMER;
+ if (last_task_used_math)
+ __asm__("fnsave %0":"=m" (last_task_used_math->tss.i387));
+ else
+ __asm__("fnclex");
+ last_task_used_math = current;
+ if (current->used_math) {
+ __asm__("frstor %0": :"m" (current->tss.i387));
+ } else {
+ __asm__("fninit");
+ current->used_math=1;
+ }
+ timer_active &= ~(1<<COPRO_TIMER);
+}
+
+#ifndef CONFIG_MATH_EMULATION
+
+asmlinkage void math_emulate(long arg)
+{
+ printk("math-emulation not enabled and no coprocessor found.\n");
+ printk("killing %s.\n",current->comm);
+ send_sig(SIGFPE,current,1);
+ schedule();
+}
+
+#endif /* CONFIG_MATH_EMULATION */
+
void trap_init(void)
{
int i;
+ struct desc_struct * p;
+ set_call_gate(&default_ldt,lcall7);
set_trap_gate(0,÷_error);
set_trap_gate(1,&debug);
set_trap_gate(2,&nmi);
set_trap_gate(17,&alignment_check);
for (i=18;i<48;i++)
set_trap_gate(i,&reserved);
+ set_system_gate(0x80,&system_call);
+/* set up GDT task & ldt entries */
+ p = gdt+FIRST_TSS_ENTRY;
+ set_tss_desc(p, &init_task.tss);
+ p++;
+ set_ldt_desc(p, &default_ldt, 1);
+ p++;
+ for(i=1 ; i<NR_TASKS ; i++) {
+ p->a=p->b=0;
+ p++;
+ p->a=p->b=0;
+ p++;
+ }
+/* Clear NT, so that we won't have troubles with that later on */
+ __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
+ load_TR(0);
+ load_ldt(0);
}
/*
* virtual flags (16 and 32-bit versions)
*/
-#define VFLAGS (*(unsigned short *)&(current->v86flags))
-#define VEFLAGS (current->v86flags)
+#define VFLAGS (*(unsigned short *)&(current->tss.v86flags))
+#define VEFLAGS (current->tss.v86flags)
#define set_flags(X,new,mask) \
((X) = ((X) & ~(mask)) | ((new) & (mask)))
{
unsigned long tmp;
- if (!current->vm86_info) {
+ if (!current->tss.vm86_info) {
printk("no vm86_info: BAD\n");
do_exit(SIGSEGV);
}
- set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->v86mask);
- memcpy_tofs(¤t->vm86_info->regs,regs,sizeof(*regs));
- put_fs_long(current->screen_bitmap,¤t->vm86_info->screen_bitmap);
+ set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->tss.v86mask);
+ memcpy_tofs(¤t->tss.vm86_info->regs,regs,sizeof(*regs));
+ put_fs_long(current->tss.screen_bitmap,¤t->tss.vm86_info->screen_bitmap);
tmp = current->tss.esp0;
current->tss.esp0 = current->saved_kernel_stack;
current->saved_kernel_stack = 0;
switch (info.cpu_type) {
case CPU_286:
- current->v86mask = 0;
+ current->tss.v86mask = 0;
break;
case CPU_386:
- current->v86mask = NT_MASK | IOPL_MASK;
+ current->tss.v86mask = NT_MASK | IOPL_MASK;
break;
case CPU_486:
- current->v86mask = AC_MASK | NT_MASK | IOPL_MASK;
+ current->tss.v86mask = AC_MASK | NT_MASK | IOPL_MASK;
break;
default:
- current->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
+ current->tss.v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
break;
}
pt_regs->eax = 0;
current->saved_kernel_stack = current->tss.esp0;
current->tss.esp0 = (unsigned long) pt_regs;
- current->vm86_info = v86;
+ current->tss.vm86_info = v86;
- current->screen_bitmap = info.screen_bitmap;
+ current->tss.screen_bitmap = info.screen_bitmap;
if (info.flags & VM86_SCREEN_BITMAP)
mark_screen_rdonly(current);
__asm__ __volatile__("movl %0,%%esp\n\t"
static inline void set_vflags_long(unsigned long eflags, struct vm86_regs * regs)
{
- set_flags(VEFLAGS, eflags, current->v86mask);
+ set_flags(VEFLAGS, eflags, current->tss.v86mask);
set_flags(regs->eflags, eflags, SAFE_MASK);
if (eflags & IF_MASK)
set_IF(regs);
static inline void set_vflags_short(unsigned short flags, struct vm86_regs * regs)
{
- set_flags(VFLAGS, flags, current->v86mask);
+ set_flags(VFLAGS, flags, current->tss.v86mask);
set_flags(regs->eflags, flags, SAFE_MASK);
if (flags & IF_MASK)
set_IF(regs);
if (VEFLAGS & VIF_MASK)
flags |= IF_MASK;
- return flags | (VEFLAGS & current->v86mask);
+ return flags | (VEFLAGS & current->tss.v86mask);
}
static inline int is_revectored(int nr, struct revectored_struct * bitmap)
unsigned short seg = get_fs_word((void *) ((i<<2)+2));
if (seg == BIOSSEG || regs->cs == BIOSSEG ||
- is_revectored(i, ¤t->vm86_info->int_revectored))
+ is_revectored(i, ¤t->tss.vm86_info->int_revectored))
return_to_32bit(regs, VM86_INTx + (i << 8));
- if (i==0x21 && is_revectored(AH(regs),¤t->vm86_info->int21_revectored))
+ if (i==0x21 && is_revectored(AH(regs),¤t->tss.vm86_info->int21_revectored))
return_to_32bit(regs, VM86_INTx + (i << 8));
pushw(ssp, sp, get_vflags(regs));
pushw(ssp, sp, regs->cs);
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/string.h>
-
-/* all the actual functions should be inline anyway, so.. */
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ */
+
+#include <linux/types.h>
char * ___strtok = NULL;
+
+char * strcpy(char * dest,const char *src)
+{
+ char *tmp = dest;
+
+ while ((*dest++ = *src++) != '\0')
+ /* nothing */;
+ return tmp;
+}
+
+char * strncpy(char * dest,const char *src,size_t count)
+{
+ char *tmp = dest;
+
+ while ((*dest++ = *src++) != '\0' && --count)
+ /* nothing */;
+
+ return tmp;
+}
+
+char * strcat(char * dest, const char * src)
+{
+ char *tmp = dest;
+
+ while (*dest)
+ dest++;
+ while ((*dest++ = *src++) != '\0')
+ ;
+
+ return tmp;
+}
+
+char * strncat(char *dest, const char *src, size_t count)
+{
+ char *tmp = dest;
+
+ if (count) {
+ while (*dest)
+ dest++;
+ while ((*dest++ = *src++)) {
+ if (--count == 0)
+ break;
+ }
+ }
+
+ return tmp;
+}
+
+int strcmp(const char * cs,const char * ct)
+{
+ register char __res;
+
+ while (1) {
+ if ((__res = *cs - *ct++) != 0 && *cs++)
+ break;
+ }
+
+ return __res;
+}
+
+int strncmp(const char * cs,const char * ct,size_t count)
+{
+ register char __res = 0;
+
+ while (count) {
+ if ((__res = *cs - *ct++) != 0 || !*cs++)
+ break;
+ count--;
+ }
+
+ return __res;
+}
+
+char * strchr(const char * s,char c)
+{
+ const char ch = c;
+
+ for(; *s != ch; ++s)
+ if (*s == '\0')
+ return NULL;
+ return (char *) s;
+}
+
+size_t strlen(const char * s)
+{
+ const char *sc;
+
+ for (sc = s; *sc != '\0'; ++sc)
+ /* nothing */;
+ return sc - s;
+}
+
+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;
+ ++count;
+ }
+
+ return count;
+}
+
+char * strpbrk(const char * cs,const char * ct)
+{
+ const char *sc1,*sc2;
+
+ for( sc1 = cs; *sc1 != '\0'; ++sc1) {
+ for( sc2 = ct; *sc2 != '\0'; ++sc2) {
+ if (*sc1 == *sc2)
+ return (char *) sc1;
+ }
+ }
+ return NULL;
+}
+
+char * strtok(char * s,const char * ct)
+{
+ char *sbegin, *send;
+
+ sbegin = s ? s : ___strtok;
+ if (!sbegin) {
+ return NULL;
+ }
+ sbegin += strspn(sbegin,ct);
+ if (*sbegin == '\0') {
+ ___strtok = NULL;
+ return( NULL );
+ }
+ send = strpbrk( sbegin, ct);
+ if (send && *send != '\0')
+ *send++ = '\0';
+ ___strtok = send;
+ return (sbegin);
+}
+
+void * memset(void * s,char c,size_t count)
+{
+ char *xs = (char *) s;
+
+ while (count--)
+ *xs++ = c;
+
+ return s;
+}
+
+void * memcpy(void * dest,const void *src,size_t count)
+{
+ char *tmp = (char *) dest, *s = (char *) src;
+
+ while (count--)
+ *tmp++ = *s++;
+
+ return dest;
+}
+
+void * memmove(void * dest,const void *src,size_t count)
+{
+ char *tmp = (char *) dest, *s = (char *) src;
+
+ while (count--)
+ *tmp++ = *s++;
+
+ return dest;
+}
+
+int memcmp(const void * cs,const void * ct,size_t count)
+{
+ const unsigned char *su1, *su2;
+
+ for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+ if (*su1 != *su2)
+ return((*su1 < *su2) ? -1 : +1);
+ return(0);
+}
if (regs->eflags & VM_MASK) {
unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
if (bit < 32)
- current->screen_bitmap |= 1 << bit;
+ current->tss.screen_bitmap |= 1 << bit;
}
if (!(vma->vm_page_prot & PAGE_USER))
goto bad_area;
return 0;
}
#endif
+ case IP_MULTICAST_LOOP:
+ {
+ unsigned char ucval;
+
+ ucval=get_fs_byte((unsigned char *)optval);
+ if(ucval!=0 && ucval!=1)
+ return -EINVAL;
+ sk->ip_mc_loop=(int)ucval;
+ return 0;
+ }
case IP_MULTICAST_IF:
{
/* Not fully tested */
case IP_MULTICAST_TTL:
val=sk->ip_mc_ttl;
break;
+ case IP_MULTICAST_LOOP:
+ val=sk->ip_mc_loop;
+ break;
case IP_MULTICAST_IF:
err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
if(err)
timer_active = del_timer(&sp->timer);
if (!timer_active)
sp->timer.expires = 0;
- len+=sprintf(buffer+len, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d\n",
+ len+=sprintf(buffer+len, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d %d\n",
i, src, srcp, dest, destp, sp->state,
format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc,
format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
timer_active, sp->timer.expires, (unsigned) sp->retransmits,
- sp->socket?SOCK_INODE(sp->socket)->i_uid:0);
+ sp->socket?SOCK_INODE(sp->socket)->i_uid:0,
+ timer_active?sp->timeout:0);
if (timer_active)
add_timer(&sp->timer);
/*
if(sk->debug)
printk("TCP sk=%p, State %s -> %s\n",sk, statename[sk->state],statename[state]);
#endif
- /* This is a hack but it doesnt occur often and its going to
+ /* This is a hack but it doesn't occur often and its going to
be a real to fix nicely */
if(state==TCP_ESTABLISHED && sk->state==TCP_SYN_RECV)
return(0);
}
- counted = sk->copied_seq+1; /* Where we are at the moment */
+ counted = sk->copied_seq; /* Where we are at the moment */
amount = 0;
/* Do until a push or until we are out of data. */
* listening socket has a receive queue of sockets to accept.
*/
-static int tcp_select(struct sock *sk, int sel_type, select_table *wait)
+static int do_tcp_select(struct sock *sk, int sel_type, select_table *wait)
{
- sk->inuse = 1;
-
switch(sel_type)
{
case SEL_IN:
- select_wait(sk->sleep, wait);
- if(sk->state==TCP_LISTEN)
+ if (sk->err)
+ return 1;
+ if (sk->state == TCP_LISTEN) {
select_wait(&master_select_wakeup,wait);
- if (skb_peek(&sk->receive_queue) != NULL)
- {
- if ((sk->state == TCP_LISTEN && tcp_find_established(sk)) || tcp_readable(sk))
- {
- release_sock(sk);
- return(1);
- }
+ return (tcp_find_established(sk) != NULL);
}
- if (sk->err != 0) /* Receiver error */
- {
- release_sock(sk);
- return(1);
- }
- if (sk->shutdown & RCV_SHUTDOWN)
- {
- release_sock(sk);
- return(1);
- }
- release_sock(sk);
- return(0);
+ if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
+ return 0;
+ if (sk->acked_seq != sk->copied_seq)
+ return 1;
+ if (sk->shutdown & RCV_SHUTDOWN)
+ return 1;
+ return 0;
+
case SEL_OUT:
- select_wait(sk->sleep, wait);
- if (sk->shutdown & SEND_SHUTDOWN)
- {
+ if (sk->shutdown & SEND_SHUTDOWN) {
/* FIXME: should this return an error? */
- release_sock(sk);
- return(0);
+ return 0;
}
/*
if (sk->prot->wspace(sk) >= sk->mtu+128+sk->prot->max_header)
{
- release_sock(sk);
/* This should cause connect to work ok. */
if (sk->state == TCP_SYN_RECV ||
- sk->state == TCP_SYN_SENT) return(0);
- return(1);
+ sk->state == TCP_SYN_SENT) return 0;
+ return 1;
}
- release_sock(sk);
- return(0);
+ return 0;
+
case SEL_EX:
- select_wait(sk->sleep,wait);
- if (sk->err || sk->urg_data)
- {
- release_sock(sk);
- return(1);
- }
- release_sock(sk);
- return(0);
+ if (sk->err || sk->urg_data)
+ return 1;
+ return 0;
}
-
- release_sock(sk);
- return(0);
+ return 0;
}
+static int tcp_select(struct sock *sk, int sel_type, select_table *wait)
+{
+ int retval;
+
+ sk->inuse = 1;
+ select_wait(sk->sleep, wait);
+ retval = do_tcp_select(sk, sel_type, wait);
+ release_sock(sk);
+ return retval;
+}
int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
}
case SIOCATMARK:
{
- int answ = sk->urg_data && sk->urg_seq == sk->copied_seq+1;
+ int answ = sk->urg_data && sk->urg_seq == sk->copied_seq;
err = verify_area(VERIFY_WRITE,(void *) arg,
sizeof(unsigned long));
/*
* are we at urgent data? Stop if we have read anything.
*/
- if (copied && sk->urg_data && sk->urg_seq == 1+*seq)
+ if (copied && sk->urg_data && sk->urg_seq == *seq)
break;
current->state = TASK_INTERRUPTIBLE;
{
if (!skb)
break;
- if (before(1+*seq, skb->h.th->seq))
+ if (before(*seq, skb->h.th->seq))
break;
- offset = 1 + *seq - skb->h.th->seq;
+ offset = *seq - skb->h.th->seq;
if (skb->h.th->syn)
offset--;
if (offset < skb->len)
goto found_ok_skb;
+ if (skb->h.th->fin)
+ goto found_fin_ok;
if (!(flags & MSG_PEEK))
skb->used = 1;
skb = skb->next;
/* do we have urgent data here? */
if (sk->urg_data)
{
- unsigned long urg_offset = sk->urg_seq - (1 + *seq);
+ unsigned long urg_offset = sk->urg_seq - *seq;
if (urg_offset < used)
{
if (!urg_offset)
len -= used;
to += used;
*seq += used;
- if (after(sk->copied_seq+1,sk->urg_seq))
+ if (after(sk->copied_seq,sk->urg_seq))
sk->urg_data = 0;
- if (!(flags & MSG_PEEK) && (used + offset >= skb->len))
- skb->used = 1;
+ if (used + offset < skb->len)
+ continue;
+ if (skb->h.th->fin)
+ goto found_fin_ok;
+ if (flags & MSG_PEEK)
+ continue;
+ skb->used = 1;
+ continue;
+
+ found_fin_ok:
+ ++*seq;
+ if (flags & MSG_PEEK)
+ break;
+ skb->used = 1;
+ sk->shutdown |= RCV_SHUTDOWN;
+ break;
+
}
remove_wait_queue(sk->sleep, &wait);
current->state = TASK_RUNNING;
newsk->shutdown = 0;
newsk->ack_backlog = 0;
newsk->acked_seq = skb->h.th->seq+1;
+ newsk->copied_seq = skb->h.th->seq+1;
newsk->fin_seq = skb->h.th->seq;
- newsk->copied_seq = skb->h.th->seq;
newsk->state = TCP_SYN_RECV;
newsk->timeout = 0;
newsk->write_seq = seq;
newsk->dummy_th.urg = 0;
newsk->dummy_th.res2 = 0;
newsk->acked_seq = skb->h.th->seq + 1;
- newsk->copied_seq = skb->h.th->seq;
+ newsk->copied_seq = skb->h.th->seq + 1;
newsk->socket = NULL;
/*
sk->send_tail = NULL;
/*
- * This is an artefact of a flawed concept. We want one
+ * This is an artifact of a flawed concept. We want one
* queue and a smarter send routine when we send all.
*/
tcp_set_state(sk, TCP_ESTABLISHED);
tcp_options(sk,th);
sk->dummy_th.dest=th->source;
- sk->copied_seq=sk->acked_seq-1;
+ sk->copied_seq = sk->acked_seq;
if(!sk->dead)
sk->state_change(sk);
if(sk->max_window==0)
{
/*
* FIXME: BSD has some magic to avoid sending resets to
- * broken 4.2 BSD keepalives. Much to my suprise a few none
+ * broken 4.2 BSD keepalives. Much to my surprise a few non
* BSD stacks still have broken keepalives so we want to
* cope with it.
*/
skb->acked = 1;
/*
- * When we ack the fin, we turn on the RCV_SHUTDOWN flag. Also do the FIN
+ * When we ack the fin, we do the FIN
* processing.
*/
if (skb->h.th->fin)
{
- if (!sk->dead)
- sk->state_change(sk);
- sk->shutdown |= RCV_SHUTDOWN;
tcp_fin(skb,sk,skb->h.th);
}
}
skb2->acked = 1;
/*
- * When we ack the fin, we turn on
- * the RCV_SHUTDOWN flag.
+ * When we ack the fin, we do
+ * the fin handling.
*/
if (skb2->h.th->fin)
{
- sk->shutdown |= RCV_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
tcp_fin(skb,sk,skb->h.th);
}
ptr += th->seq;
/* ignore urgent data that we've already seen and read */
- if (after(sk->copied_seq+1, ptr))
+ if (after(sk->copied_seq, ptr))
return;
/* do we already have a newer (or duplicate) urgent pointer? */
/*
* This basically follows the flow suggested by RFC793, with the corrections in RFC1122. We
* don't implement precedence and we process URG incorrectly (deliberately so) for BSD bug
- * compatibility. We also set up variables more throughroughly [Karn notes in the
+ * compatibility. We also set up variables more thoroughly [Karn notes in the
* KA9Q code the RFC793 incoming segment rules don't initialise the variables for all paths].
*/
return 0;
}
+ /* retransmitted SYN? */
+ if (sk->state == TCP_SYN_RECV && th->syn && th->seq+1 == sk->acked_seq)
+ {
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return 0;
+ }
+
/*
* SYN sent means we have to look for a suitable ack and either reset
* for bad matches or go to connected
*/
- else if(sk->state==TCP_SYN_SENT)
+ if(sk->state==TCP_SYN_SENT)
{
/* Crossed SYN or previous junk segment */
if(th->ack)
tcp_set_state(sk, TCP_ESTABLISHED);
tcp_options(sk,th);
sk->dummy_th.dest=th->source;
- sk->copied_seq=sk->acked_seq-1;
+ sk->copied_seq = sk->acked_seq;
if(!sk->dead)
sk->state_change(sk);
if(sk->max_window==0)
*/
goto rfc_step6;
}
-
- }
-
- /* BSD has a funny hack with TIME_WAIT and fast reuse of a port. We
- don't use it, we don't need it and its not in the spec. There is
+
+ /* BSD has a funny hack with TIME_WAIT and fast reuse of a port. There is
a more complex suggestion for fixing these reuse issues in RFC1644
but not yet ready for general use. Also see RFC1379.*/
- /* We are now in normal data flow (see the step list in the RFC) */
- /* Note most of these are inline now. I'll inline the lot when
- I have time to test it hard and look at what gcc outputs */
-
#define BSD_TIME_WAIT
#ifdef BSD_TIME_WAIT
- if (sk->state == TCP_TIME_WAIT && th->syn && sk->dead &&
- after(th->seq, sk->acked_seq) && !th->rst)
- {
- long seq=sk->write_seq;
- if(sk->debug)
- printk("Doing a BSD time wait\n");
- tcp_statistics.TcpEstabResets++;
- sk->rmem_alloc -= skb->mem_len;
- skb->sk = NULL;
- sk->err=ECONNRESET;
- tcp_set_state(sk, TCP_CLOSE);
- sk->shutdown = SHUTDOWN_MASK;
- release_sock(sk);
- sk=get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);
- if(sk && sk->state==TCP_LISTEN)
+ if (sk->state == TCP_TIME_WAIT && th->syn && sk->dead &&
+ after(th->seq, sk->acked_seq) && !th->rst)
{
- sk->inuse=1;
- skb->sk = sk;
- sk->rmem_alloc += skb->mem_len;
- tcp_conn_request(sk, skb, daddr, saddr,opt, dev,seq+128000);
+ long seq=sk->write_seq;
+ if(sk->debug)
+ printk("Doing a BSD time wait\n");
+ tcp_statistics.TcpEstabResets++;
+ sk->rmem_alloc -= skb->mem_len;
+ skb->sk = NULL;
+ sk->err=ECONNRESET;
+ tcp_set_state(sk, TCP_CLOSE);
+ sk->shutdown = SHUTDOWN_MASK;
release_sock(sk);
+ sk=get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);
+ if (sk && sk->state==TCP_LISTEN)
+ {
+ sk->inuse=1;
+ skb->sk = sk;
+ sk->rmem_alloc += skb->mem_len;
+ tcp_conn_request(sk, skb, daddr, saddr,opt, dev,seq+128000);
+ release_sock(sk);
+ return 0;
+ }
+ kfree_skb(skb, FREE_READ);
return 0;
}
- kfree_skb(skb, FREE_READ);
- return 0;
- }
#endif
+ }
+
+ /* We are now in normal data flow (see the step list in the RFC) */
+ /* Note most of these are inline now. I'll inline the lot when
+ I have time to test it hard and look at what gcc outputs */
- if(/*sk->state!=TCP_SYN_RECV &&*/ !tcp_sequence(sk,th,len,opt,saddr,dev))
+ if(!tcp_sequence(sk,th,len,opt,saddr,dev))
{
kfree_skb(skb, FREE_READ);
+ release_sock(sk);
return 0;
}
}
/*
- * A window probe timeout has occured.
+ * A window probe timeout has occurred.
*/
void tcp_send_probe0(struct sock *sk)