initial version
This commit is contained in:
93
Book-Lite/linux-0.12/kernel/Makefile
Normal file
93
Book-Lite/linux-0.12/kernel/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
#
|
||||
# Makefile for the FREAX-kernel.
|
||||
#
|
||||
# Note! Dependencies are done automagically by 'make dep', which also
|
||||
# removes any old dependencies. DON'T put your own dependencies here
|
||||
# unless it's something special (ie not a .c file).
|
||||
#
|
||||
|
||||
AR =gar
|
||||
AS =gas
|
||||
LD =gld
|
||||
LDFLAGS =-s -x
|
||||
CC =gcc
|
||||
CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
|
||||
-finline-functions -mstring-insns -nostdinc -I../include
|
||||
CPP =gcc -E -nostdinc -I../include
|
||||
|
||||
.c.s:
|
||||
$(CC) $(CFLAGS) \
|
||||
-S -o $*.s $<
|
||||
.s.o:
|
||||
$(AS) -c -o $*.o $<
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) \
|
||||
-c -o $*.o $<
|
||||
|
||||
OBJS = sched.o sys_call.o traps.o asm.o fork.o \
|
||||
panic.o printk.o vsprintf.o sys.o exit.o \
|
||||
signal.o mktime.o
|
||||
|
||||
kernel.o: $(OBJS)
|
||||
$(LD) -r -o kernel.o $(OBJS)
|
||||
sync
|
||||
|
||||
clean:
|
||||
rm -f core *.o *.a tmp_make keyboard.s
|
||||
for i in *.c;do rm -f `basename $$i .c`.s;done
|
||||
(cd chr_drv; make clean)
|
||||
(cd blk_drv; make clean)
|
||||
(cd math; make clean)
|
||||
|
||||
dep:
|
||||
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
|
||||
(for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \
|
||||
$(CPP) -M $$i;done) >> tmp_make
|
||||
cp tmp_make Makefile
|
||||
(cd chr_drv; make dep)
|
||||
(cd blk_drv; make dep)
|
||||
|
||||
### Dependencies:
|
||||
exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \
|
||||
../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \
|
||||
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
|
||||
../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \
|
||||
../include/time.h ../include/sys/resource.h ../include/linux/tty.h \
|
||||
../include/termios.h ../include/asm/segment.h
|
||||
fork.s fork.o : fork.c ../include/errno.h ../include/linux/sched.h \
|
||||
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
|
||||
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
|
||||
../include/sys/param.h ../include/sys/time.h ../include/time.h \
|
||||
../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h
|
||||
mktime.s mktime.o : mktime.c ../include/time.h
|
||||
panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \
|
||||
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
|
||||
../include/linux/mm.h ../include/signal.h ../include/sys/param.h \
|
||||
../include/sys/time.h ../include/time.h ../include/sys/resource.h
|
||||
printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \
|
||||
../include/linux/kernel.h
|
||||
sched.s sched.o : sched.c ../include/linux/sched.h ../include/linux/head.h \
|
||||
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
|
||||
../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
|
||||
../include/sys/time.h ../include/time.h ../include/sys/resource.h \
|
||||
../include/linux/sys.h ../include/linux/fdreg.h ../include/asm/system.h \
|
||||
../include/asm/io.h ../include/asm/segment.h
|
||||
signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \
|
||||
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
|
||||
../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
|
||||
../include/sys/time.h ../include/time.h ../include/sys/resource.h \
|
||||
../include/asm/segment.h ../include/errno.h
|
||||
sys.s sys.o : sys.c ../include/errno.h ../include/linux/sched.h \
|
||||
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
|
||||
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
|
||||
../include/sys/param.h ../include/sys/time.h ../include/time.h \
|
||||
../include/sys/resource.h ../include/linux/tty.h ../include/termios.h \
|
||||
../include/linux/config.h ../include/asm/segment.h ../include/sys/times.h \
|
||||
../include/sys/utsname.h ../include/string.h
|
||||
traps.s traps.o : traps.c ../include/string.h ../include/linux/head.h \
|
||||
../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \
|
||||
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
|
||||
../include/sys/param.h ../include/sys/time.h ../include/time.h \
|
||||
../include/sys/resource.h ../include/asm/system.h ../include/asm/segment.h \
|
||||
../include/asm/io.h
|
||||
vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h
|
||||
151
Book-Lite/linux-0.12/kernel/asm.s
Normal file
151
Book-Lite/linux-0.12/kernel/asm.s
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* linux/kernel/asm.s
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* asm.s contains the low-level code for most hardware faults.
|
||||
* page_exception is handled by the mm, so that isn't here. This
|
||||
* file also handles (hopefully) fpu-exceptions due to TS-bit, as
|
||||
* the fpu must be properly saved/resored. This hasn't been tested.
|
||||
*/
|
||||
|
||||
.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
|
||||
.globl _double_fault,_coprocessor_segment_overrun
|
||||
.globl _invalid_TSS,_segment_not_present,_stack_segment
|
||||
.globl _general_protection,_coprocessor_error,_irq13,_reserved
|
||||
.globl _alignment_check
|
||||
|
||||
_divide_error:
|
||||
pushl $_do_divide_error
|
||||
no_error_code:
|
||||
xchgl %eax,(%esp)
|
||||
pushl %ebx
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
pushl %edi
|
||||
pushl %esi
|
||||
pushl %ebp
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
pushl $0 # "error code"
|
||||
lea 44(%esp),%edx
|
||||
pushl %edx
|
||||
movl $0x10,%edx
|
||||
mov %dx,%ds
|
||||
mov %dx,%es
|
||||
mov %dx,%fs
|
||||
call *%eax
|
||||
addl $8,%esp
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
popl %ebp
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
popl %eax
|
||||
iret
|
||||
|
||||
_debug:
|
||||
pushl $_do_int3 # _do_debug
|
||||
jmp no_error_code
|
||||
|
||||
_nmi:
|
||||
pushl $_do_nmi
|
||||
jmp no_error_code
|
||||
|
||||
_int3:
|
||||
pushl $_do_int3
|
||||
jmp no_error_code
|
||||
|
||||
_overflow:
|
||||
pushl $_do_overflow
|
||||
jmp no_error_code
|
||||
|
||||
_bounds:
|
||||
pushl $_do_bounds
|
||||
jmp no_error_code
|
||||
|
||||
_invalid_op:
|
||||
pushl $_do_invalid_op
|
||||
jmp no_error_code
|
||||
|
||||
_coprocessor_segment_overrun:
|
||||
pushl $_do_coprocessor_segment_overrun
|
||||
jmp no_error_code
|
||||
|
||||
_reserved:
|
||||
pushl $_do_reserved
|
||||
jmp no_error_code
|
||||
|
||||
_irq13:
|
||||
pushl %eax
|
||||
xorb %al,%al
|
||||
outb %al,$0xF0
|
||||
movb $0x20,%al
|
||||
outb %al,$0x20
|
||||
jmp 1f
|
||||
1: jmp 1f
|
||||
1: outb %al,$0xA0
|
||||
popl %eax
|
||||
jmp _coprocessor_error
|
||||
|
||||
_double_fault:
|
||||
pushl $_do_double_fault
|
||||
error_code:
|
||||
xchgl %eax,4(%esp) # error code <-> %eax
|
||||
xchgl %ebx,(%esp) # &function <-> %ebx
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
pushl %edi
|
||||
pushl %esi
|
||||
pushl %ebp
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
pushl %eax # error code
|
||||
lea 44(%esp),%eax # offset
|
||||
pushl %eax
|
||||
movl $0x10,%eax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
mov %ax,%fs
|
||||
call *%ebx
|
||||
addl $8,%esp
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
popl %ebp
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
popl %eax
|
||||
iret
|
||||
|
||||
_invalid_TSS:
|
||||
pushl $_do_invalid_TSS
|
||||
jmp error_code
|
||||
|
||||
_segment_not_present:
|
||||
pushl $_do_segment_not_present
|
||||
jmp error_code
|
||||
|
||||
_stack_segment:
|
||||
pushl $_do_stack_segment
|
||||
jmp error_code
|
||||
|
||||
_general_protection:
|
||||
pushl $_do_general_protection
|
||||
jmp error_code
|
||||
|
||||
_alignment_check:
|
||||
pushl $_do_alignment_check
|
||||
jmp error_code
|
||||
|
||||
71
Book-Lite/linux-0.12/kernel/blk_drv/Makefile
Normal file
71
Book-Lite/linux-0.12/kernel/blk_drv/Makefile
Normal file
@@ -0,0 +1,71 @@
|
||||
#
|
||||
# Makefile for the FREAX-kernel block device drivers.
|
||||
#
|
||||
# Note! Dependencies are done automagically by 'make dep', which also
|
||||
# removes any old dependencies. DON'T put your own dependencies here
|
||||
# unless it's something special (ie not a .c file).
|
||||
#
|
||||
|
||||
AR =gar
|
||||
AS =gas
|
||||
LD =gld
|
||||
LDFLAGS =-s -x
|
||||
CC =gcc
|
||||
CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
|
||||
-finline-functions -mstring-insns -nostdinc -I../../include
|
||||
CPP =gcc -E -nostdinc -I../../include
|
||||
|
||||
.c.s:
|
||||
$(CC) $(CFLAGS) \
|
||||
-S -o $*.s $<
|
||||
.s.o:
|
||||
$(AS) -c -o $*.o $<
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) \
|
||||
-c -o $*.o $<
|
||||
|
||||
OBJS = ll_rw_blk.o floppy.o hd.o ramdisk.o
|
||||
|
||||
blk_drv.a: $(OBJS)
|
||||
$(AR) rcs blk_drv.a $(OBJS)
|
||||
sync
|
||||
|
||||
clean:
|
||||
rm -f core *.o *.a tmp_make
|
||||
for i in *.c;do rm -f `basename $$i .c`.s;done
|
||||
|
||||
dep:
|
||||
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
|
||||
(for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \
|
||||
$(CPP) -M $$i;done) >> tmp_make
|
||||
cp tmp_make Makefile
|
||||
|
||||
### Dependencies:
|
||||
floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h \
|
||||
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h \
|
||||
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
|
||||
../../include/sys/resource.h ../../include/linux/fdreg.h \
|
||||
../../include/asm/system.h ../../include/asm/io.h \
|
||||
../../include/asm/segment.h blk.h
|
||||
hd.s hd.o : hd.c ../../include/linux/config.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h \
|
||||
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
|
||||
../../include/sys/resource.h ../../include/linux/hdreg.h \
|
||||
../../include/asm/system.h ../../include/asm/io.h \
|
||||
../../include/asm/segment.h blk.h
|
||||
ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h \
|
||||
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
|
||||
../../include/sys/resource.h ../../include/asm/system.h blk.h
|
||||
ramdisk.s ramdisk.o : ramdisk.c ../../include/string.h ../../include/linux/config.h \
|
||||
../../include/linux/sched.h ../../include/linux/head.h \
|
||||
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h \
|
||||
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
|
||||
../../include/sys/resource.h ../../include/asm/system.h \
|
||||
../../include/asm/segment.h ../../include/asm/memory.h blk.h
|
||||
164
Book-Lite/linux-0.12/kernel/blk_drv/blk.h
Normal file
164
Book-Lite/linux-0.12/kernel/blk_drv/blk.h
Normal file
@@ -0,0 +1,164 @@
|
||||
#ifndef _BLK_H
|
||||
#define _BLK_H
|
||||
|
||||
#define NR_BLK_DEV 7
|
||||
/*
|
||||
* NR_REQUEST is the number of entries in the request-queue.
|
||||
* NOTE that writes may use only the low 2/3 of these: reads
|
||||
* take precedence.
|
||||
*
|
||||
* 32 seems to be a reasonable number: enough to get some benefit
|
||||
* from the elevator-mechanism, but not so much as to lock a lot of
|
||||
* buffers when they are in the queue. 64 seems to be too many (easily
|
||||
* long pauses in reading when heavy writing/syncing is going on)
|
||||
*/
|
||||
#define NR_REQUEST 32
|
||||
|
||||
/*
|
||||
* Ok, this is an expanded form so that we can use the same
|
||||
* request for paging requests when that is implemented. In
|
||||
* paging, 'bh' is NULL, and 'waiting' is used to wait for
|
||||
* read/write completion.
|
||||
*/
|
||||
struct request {
|
||||
int dev; /* -1 if no request */
|
||||
int cmd; /* READ or WRITE */
|
||||
int errors;
|
||||
unsigned long sector;
|
||||
unsigned long nr_sectors;
|
||||
char * buffer;
|
||||
struct task_struct * waiting;
|
||||
struct buffer_head * bh;
|
||||
struct request * next;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is used in the elevator algorithm: Note that
|
||||
* reads always go before writes. This is natural: reads
|
||||
* are much more time-critical than writes.
|
||||
*/
|
||||
#define IN_ORDER(s1,s2) \
|
||||
((s1)->cmd<(s2)->cmd || (s1)->cmd==(s2)->cmd && \
|
||||
((s1)->dev < (s2)->dev || ((s1)->dev == (s2)->dev && \
|
||||
(s1)->sector < (s2)->sector)))
|
||||
|
||||
struct blk_dev_struct {
|
||||
void (*request_fn)(void);
|
||||
struct request * current_request;
|
||||
};
|
||||
|
||||
extern struct blk_dev_struct blk_dev[NR_BLK_DEV];
|
||||
extern struct request request[NR_REQUEST];
|
||||
extern struct task_struct * wait_for_request;
|
||||
|
||||
extern int * blk_size[NR_BLK_DEV];
|
||||
|
||||
#ifdef MAJOR_NR
|
||||
|
||||
/*
|
||||
* Add entries as needed. Currently the only block devices
|
||||
* supported are hard-disks and floppies.
|
||||
*/
|
||||
|
||||
#if (MAJOR_NR == 1)
|
||||
/* ram disk */
|
||||
#define DEVICE_NAME "ramdisk"
|
||||
#define DEVICE_REQUEST do_rd_request
|
||||
#define DEVICE_NR(device) ((device) & 7)
|
||||
#define DEVICE_ON(device)
|
||||
#define DEVICE_OFF(device)
|
||||
|
||||
#elif (MAJOR_NR == 2)
|
||||
/* floppy */
|
||||
#define DEVICE_NAME "floppy"
|
||||
#define DEVICE_INTR do_floppy
|
||||
#define DEVICE_REQUEST do_fd_request
|
||||
#define DEVICE_NR(device) ((device) & 3)
|
||||
#define DEVICE_ON(device) floppy_on(DEVICE_NR(device))
|
||||
#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
|
||||
|
||||
#elif (MAJOR_NR == 3)
|
||||
/* harddisk */
|
||||
#define DEVICE_NAME "harddisk"
|
||||
#define DEVICE_INTR do_hd
|
||||
#define DEVICE_TIMEOUT hd_timeout
|
||||
#define DEVICE_REQUEST do_hd_request
|
||||
#define DEVICE_NR(device) (MINOR(device)/5)
|
||||
#define DEVICE_ON(device)
|
||||
#define DEVICE_OFF(device)
|
||||
|
||||
#elif
|
||||
/* unknown blk device */
|
||||
#error "unknown blk device"
|
||||
|
||||
#endif
|
||||
|
||||
#define CURRENT (blk_dev[MAJOR_NR].current_request)
|
||||
#define CURRENT_DEV DEVICE_NR(CURRENT->dev)
|
||||
|
||||
#ifdef DEVICE_INTR
|
||||
void (*DEVICE_INTR)(void) = NULL;
|
||||
#endif
|
||||
#ifdef DEVICE_TIMEOUT
|
||||
int DEVICE_TIMEOUT = 0;
|
||||
#define SET_INTR(x) (DEVICE_INTR = (x),DEVICE_TIMEOUT = 200)
|
||||
#else
|
||||
#define SET_INTR(x) (DEVICE_INTR = (x))
|
||||
#endif
|
||||
static void (DEVICE_REQUEST)(void);
|
||||
|
||||
extern inline void unlock_buffer(struct buffer_head * bh)
|
||||
{
|
||||
if (!bh->b_lock)
|
||||
printk(DEVICE_NAME ": free buffer being unlocked\n");
|
||||
bh->b_lock=0;
|
||||
wake_up(&bh->b_wait);
|
||||
}
|
||||
|
||||
extern inline void end_request(int uptodate)
|
||||
{
|
||||
DEVICE_OFF(CURRENT->dev);
|
||||
if (CURRENT->bh) {
|
||||
CURRENT->bh->b_uptodate = uptodate;
|
||||
unlock_buffer(CURRENT->bh);
|
||||
}
|
||||
if (!uptodate) {
|
||||
printk(DEVICE_NAME " I/O error\n\r");
|
||||
printk("dev %04x, block %d\n\r",CURRENT->dev,
|
||||
CURRENT->bh->b_blocknr);
|
||||
}
|
||||
wake_up(&CURRENT->waiting);
|
||||
wake_up(&wait_for_request);
|
||||
CURRENT->dev = -1;
|
||||
CURRENT = CURRENT->next;
|
||||
}
|
||||
|
||||
#ifdef DEVICE_TIMEOUT
|
||||
#define CLEAR_DEVICE_TIMEOUT DEVICE_TIMEOUT = 0;
|
||||
#else
|
||||
#define CLEAR_DEVICE_TIMEOUT
|
||||
#endif
|
||||
|
||||
#ifdef DEVICE_INTR
|
||||
#define CLEAR_DEVICE_INTR DEVICE_INTR = 0;
|
||||
#else
|
||||
#define CLEAR_DEVICE_INTR
|
||||
#endif
|
||||
|
||||
#define INIT_REQUEST \
|
||||
repeat: \
|
||||
if (!CURRENT) {\
|
||||
CLEAR_DEVICE_INTR \
|
||||
CLEAR_DEVICE_TIMEOUT \
|
||||
return; \
|
||||
} \
|
||||
if (MAJOR(CURRENT->dev) != MAJOR_NR) \
|
||||
panic(DEVICE_NAME ": request list destroyed"); \
|
||||
if (CURRENT->bh) { \
|
||||
if (!CURRENT->bh->b_lock) \
|
||||
panic(DEVICE_NAME ": block not locked"); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
475
Book-Lite/linux-0.12/kernel/blk_drv/floppy.c
Normal file
475
Book-Lite/linux-0.12/kernel/blk_drv/floppy.c
Normal file
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
* linux/kernel/floppy.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* 02.12.91 - Changed to static variables to indicate need for reset
|
||||
* and recalibrate. This makes some things easier (output_byte reset
|
||||
* checking etc), and means less interrupt jumping in case of errors,
|
||||
* so the code is hopefully easier to understand.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is certainly a mess. I've tried my best to get it working,
|
||||
* but I don't like programming floppies, and I have only one anyway.
|
||||
* Urgel. I should check for more errors, and do more graceful error
|
||||
* recovery. Seems there are problems with several drives. I've tried to
|
||||
* correct them. No promises.
|
||||
*/
|
||||
|
||||
/*
|
||||
* As with hd.c, all routines within this file can (and will) be called
|
||||
* by interrupts, so extreme caution is needed. A hardware interrupt
|
||||
* handler may not sleep, or a kernel panic will happen. Thus I cannot
|
||||
* call "floppy-on" directly, but have to set a special timer interrupt
|
||||
* etc.
|
||||
*
|
||||
* Also, I'm not certain this works on more than 1 floppy. Bugs may
|
||||
* abund.
|
||||
*/
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fdreg.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
#define MAJOR_NR 2
|
||||
#include "blk.h"
|
||||
|
||||
static int recalibrate = 0;
|
||||
static int reset = 0;
|
||||
static int seek = 0;
|
||||
|
||||
extern unsigned char current_DOR;
|
||||
|
||||
#define immoutb_p(val,port) \
|
||||
__asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port))
|
||||
|
||||
#define TYPE(x) ((x)>>2)
|
||||
#define DRIVE(x) ((x)&0x03)
|
||||
/*
|
||||
* Note that MAX_ERRORS=8 doesn't imply that we retry every bad read
|
||||
* max 8 times - some types of errors increase the errorcount by 2,
|
||||
* so we might actually retry only 5-6 times before giving up.
|
||||
*/
|
||||
#define MAX_ERRORS 8
|
||||
|
||||
/*
|
||||
* globals used by 'result()'
|
||||
*/
|
||||
#define MAX_REPLIES 7
|
||||
static unsigned char reply_buffer[MAX_REPLIES];
|
||||
#define ST0 (reply_buffer[0])
|
||||
#define ST1 (reply_buffer[1])
|
||||
#define ST2 (reply_buffer[2])
|
||||
#define ST3 (reply_buffer[3])
|
||||
|
||||
/*
|
||||
* This struct defines the different floppy types. Unlike minix
|
||||
* linux doesn't have a "search for right type"-type, as the code
|
||||
* for that is convoluted and weird. I've got enough problems with
|
||||
* this driver as it is.
|
||||
*
|
||||
* The 'stretch' tells if the tracks need to be boubled for some
|
||||
* types (ie 360kB diskette in 1.2MB drive etc). Others should
|
||||
* be self-explanatory.
|
||||
*/
|
||||
static struct floppy_struct {
|
||||
unsigned int size, sect, head, track, stretch;
|
||||
unsigned char gap,rate,spec1;
|
||||
} floppy_type[] = {
|
||||
{ 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */
|
||||
{ 720, 9,2,40,0,0x2A,0x02,0xDF }, /* 360kB PC diskettes */
|
||||
{ 2400,15,2,80,0,0x1B,0x00,0xDF }, /* 1.2 MB AT-diskettes */
|
||||
{ 720, 9,2,40,1,0x2A,0x02,0xDF }, /* 360kB in 720kB drive */
|
||||
{ 1440, 9,2,80,0,0x2A,0x02,0xDF }, /* 3.5" 720kB diskette */
|
||||
{ 720, 9,2,40,1,0x23,0x01,0xDF }, /* 360kB in 1.2MB drive */
|
||||
{ 1440, 9,2,80,0,0x23,0x01,0xDF }, /* 720kB in 1.2MB drive */
|
||||
{ 2880,18,2,80,0,0x1B,0x00,0xCF }, /* 1.44MB diskette */
|
||||
};
|
||||
|
||||
/*
|
||||
* Rate is 0 for 500kb/s, 2 for 300kbps, 1 for 250kbps
|
||||
* Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
|
||||
* H is head unload time (1=16ms, 2=32ms, etc)
|
||||
*
|
||||
* Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms etc)
|
||||
* and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA).
|
||||
*/
|
||||
|
||||
extern void floppy_interrupt(void);
|
||||
extern char tmp_floppy_area[1024];
|
||||
|
||||
/*
|
||||
* These are global variables, as that's the easiest way to give
|
||||
* information to interrupts. They are the data used for the current
|
||||
* request.
|
||||
*/
|
||||
static int cur_spec1 = -1;
|
||||
static int cur_rate = -1;
|
||||
static struct floppy_struct * floppy = floppy_type;
|
||||
static unsigned char current_drive = 0;
|
||||
static unsigned char sector = 0;
|
||||
static unsigned char head = 0;
|
||||
static unsigned char track = 0;
|
||||
static unsigned char seek_track = 0;
|
||||
static unsigned char current_track = 255;
|
||||
static unsigned char command = 0;
|
||||
unsigned char selected = 0;
|
||||
struct task_struct * wait_on_floppy_select = NULL;
|
||||
|
||||
void floppy_deselect(unsigned int nr)
|
||||
{
|
||||
if (nr != (current_DOR & 3))
|
||||
printk("floppy_deselect: drive not selected\n\r");
|
||||
selected = 0;
|
||||
wake_up(&wait_on_floppy_select);
|
||||
}
|
||||
|
||||
/*
|
||||
* floppy-change is never called from an interrupt, so we can relax a bit
|
||||
* here, sleep etc. Note that floppy-on tries to set current_DOR to point
|
||||
* to the desired drive, but it will probably not survive the sleep if
|
||||
* several floppies are used at the same time: thus the loop.
|
||||
*/
|
||||
int floppy_change(unsigned int nr)
|
||||
{
|
||||
repeat:
|
||||
floppy_on(nr);
|
||||
while ((current_DOR & 3) != nr && selected)
|
||||
sleep_on(&wait_on_floppy_select);
|
||||
if ((current_DOR & 3) != nr)
|
||||
goto repeat;
|
||||
if (inb(FD_DIR) & 0x80) {
|
||||
floppy_off(nr);
|
||||
return 1;
|
||||
}
|
||||
floppy_off(nr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define copy_buffer(from,to) \
|
||||
__asm__("cld ; rep ; movsl" \
|
||||
::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \
|
||||
:"cx","di","si")
|
||||
|
||||
static void setup_DMA(void)
|
||||
{
|
||||
long addr = (long) CURRENT->buffer;
|
||||
|
||||
cli();
|
||||
if (addr >= 0x100000) {
|
||||
addr = (long) tmp_floppy_area;
|
||||
if (command == FD_WRITE)
|
||||
copy_buffer(CURRENT->buffer,tmp_floppy_area);
|
||||
}
|
||||
/* mask DMA 2 */
|
||||
immoutb_p(4|2,10);
|
||||
/* output command byte. I don't know why, but everyone (minix, */
|
||||
/* sanches & canton) output this twice, first to 12 then to 11 */
|
||||
__asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t"
|
||||
"outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:"::
|
||||
"a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE)));
|
||||
/* 8 low bits of addr */
|
||||
immoutb_p(addr,4);
|
||||
addr >>= 8;
|
||||
/* bits 8-15 of addr */
|
||||
immoutb_p(addr,4);
|
||||
addr >>= 8;
|
||||
/* bits 16-19 of addr */
|
||||
immoutb_p(addr,0x81);
|
||||
/* low 8 bits of count-1 (1024-1=0x3ff) */
|
||||
immoutb_p(0xff,5);
|
||||
/* high 8 bits of count-1 */
|
||||
immoutb_p(3,5);
|
||||
/* activate DMA 2 */
|
||||
immoutb_p(0|2,10);
|
||||
sti();
|
||||
}
|
||||
|
||||
static void output_byte(char byte)
|
||||
{
|
||||
int counter;
|
||||
unsigned char status;
|
||||
|
||||
if (reset)
|
||||
return;
|
||||
for(counter = 0 ; counter < 10000 ; counter++) {
|
||||
status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR);
|
||||
if (status == STATUS_READY) {
|
||||
outb(byte,FD_DATA);
|
||||
return;
|
||||
}
|
||||
}
|
||||
reset = 1;
|
||||
printk("Unable to send byte to FDC\n\r");
|
||||
}
|
||||
|
||||
static int result(void)
|
||||
{
|
||||
int i = 0, counter, status;
|
||||
|
||||
if (reset)
|
||||
return -1;
|
||||
for (counter = 0 ; counter < 10000 ; counter++) {
|
||||
status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY);
|
||||
if (status == STATUS_READY)
|
||||
return i;
|
||||
if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
|
||||
if (i >= MAX_REPLIES)
|
||||
break;
|
||||
reply_buffer[i++] = inb_p(FD_DATA);
|
||||
}
|
||||
}
|
||||
reset = 1;
|
||||
printk("Getstatus times out\n\r");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void bad_flp_intr(void)
|
||||
{
|
||||
CURRENT->errors++;
|
||||
if (CURRENT->errors > MAX_ERRORS) {
|
||||
floppy_deselect(current_drive);
|
||||
end_request(0);
|
||||
}
|
||||
if (CURRENT->errors > MAX_ERRORS/2)
|
||||
reset = 1;
|
||||
else
|
||||
recalibrate = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, this interrupt is called after a DMA read/write has succeeded,
|
||||
* so we check the results, and copy any buffers.
|
||||
*/
|
||||
static void rw_interrupt(void)
|
||||
{
|
||||
if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73)) {
|
||||
if (ST1 & 0x02) {
|
||||
printk("Drive %d is write protected\n\r",current_drive);
|
||||
floppy_deselect(current_drive);
|
||||
end_request(0);
|
||||
} else
|
||||
bad_flp_intr();
|
||||
do_fd_request();
|
||||
return;
|
||||
}
|
||||
if (command == FD_READ && (unsigned long)(CURRENT->buffer) >= 0x100000)
|
||||
copy_buffer(tmp_floppy_area,CURRENT->buffer);
|
||||
floppy_deselect(current_drive);
|
||||
end_request(1);
|
||||
do_fd_request();
|
||||
}
|
||||
|
||||
inline void setup_rw_floppy(void)
|
||||
{
|
||||
setup_DMA();
|
||||
do_floppy = rw_interrupt;
|
||||
output_byte(command);
|
||||
output_byte(head<<2 | current_drive);
|
||||
output_byte(track);
|
||||
output_byte(head);
|
||||
output_byte(sector);
|
||||
output_byte(2); /* sector size = 512 */
|
||||
output_byte(floppy->sect);
|
||||
output_byte(floppy->gap);
|
||||
output_byte(0xFF); /* sector size (0xff when n!=0 ?) */
|
||||
if (reset)
|
||||
do_fd_request();
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the routine called after every seek (or recalibrate) interrupt
|
||||
* from the floppy controller. Note that the "unexpected interrupt" routine
|
||||
* also does a recalibrate, but doesn't come here.
|
||||
*/
|
||||
static void seek_interrupt(void)
|
||||
{
|
||||
/* sense drive status */
|
||||
output_byte(FD_SENSEI);
|
||||
if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) {
|
||||
bad_flp_intr();
|
||||
do_fd_request();
|
||||
return;
|
||||
}
|
||||
current_track = ST1;
|
||||
setup_rw_floppy();
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is called when everything should be correctly set up
|
||||
* for the transfer (ie floppy motor is on and the correct floppy is
|
||||
* selected).
|
||||
*/
|
||||
static void transfer(void)
|
||||
{
|
||||
if (cur_spec1 != floppy->spec1) {
|
||||
cur_spec1 = floppy->spec1;
|
||||
output_byte(FD_SPECIFY);
|
||||
output_byte(cur_spec1); /* hut etc */
|
||||
output_byte(6); /* Head load time =6ms, DMA */
|
||||
}
|
||||
if (cur_rate != floppy->rate)
|
||||
outb_p(cur_rate = floppy->rate,FD_DCR);
|
||||
if (reset) {
|
||||
do_fd_request();
|
||||
return;
|
||||
}
|
||||
if (!seek) {
|
||||
setup_rw_floppy();
|
||||
return;
|
||||
}
|
||||
do_floppy = seek_interrupt;
|
||||
if (seek_track) {
|
||||
output_byte(FD_SEEK);
|
||||
output_byte(head<<2 | current_drive);
|
||||
output_byte(seek_track);
|
||||
} else {
|
||||
output_byte(FD_RECALIBRATE);
|
||||
output_byte(head<<2 | current_drive);
|
||||
}
|
||||
if (reset)
|
||||
do_fd_request();
|
||||
}
|
||||
|
||||
/*
|
||||
* Special case - used after a unexpected interrupt (or reset)
|
||||
*/
|
||||
static void recal_interrupt(void)
|
||||
{
|
||||
output_byte(FD_SENSEI);
|
||||
if (result()!=2 || (ST0 & 0xE0) == 0x60)
|
||||
reset = 1;
|
||||
else
|
||||
recalibrate = 0;
|
||||
do_fd_request();
|
||||
}
|
||||
|
||||
void unexpected_floppy_interrupt(void)
|
||||
{
|
||||
output_byte(FD_SENSEI);
|
||||
if (result()!=2 || (ST0 & 0xE0) == 0x60)
|
||||
reset = 1;
|
||||
else
|
||||
recalibrate = 1;
|
||||
}
|
||||
|
||||
static void recalibrate_floppy(void)
|
||||
{
|
||||
recalibrate = 0;
|
||||
current_track = 0;
|
||||
do_floppy = recal_interrupt;
|
||||
output_byte(FD_RECALIBRATE);
|
||||
output_byte(head<<2 | current_drive);
|
||||
if (reset)
|
||||
do_fd_request();
|
||||
}
|
||||
|
||||
static void reset_interrupt(void)
|
||||
{
|
||||
output_byte(FD_SENSEI);
|
||||
(void) result();
|
||||
output_byte(FD_SPECIFY);
|
||||
output_byte(cur_spec1); /* hut etc */
|
||||
output_byte(6); /* Head load time =6ms, DMA */
|
||||
do_fd_request();
|
||||
}
|
||||
|
||||
/*
|
||||
* reset is done by pulling bit 2 of DOR low for a while.
|
||||
*/
|
||||
static void reset_floppy(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
reset = 0;
|
||||
cur_spec1 = -1;
|
||||
cur_rate = -1;
|
||||
recalibrate = 1;
|
||||
printk("Reset-floppy called\n\r");
|
||||
cli();
|
||||
do_floppy = reset_interrupt;
|
||||
outb_p(current_DOR & ~0x04,FD_DOR);
|
||||
for (i=0 ; i<100 ; i++)
|
||||
__asm__("nop");
|
||||
outb(current_DOR,FD_DOR);
|
||||
sti();
|
||||
}
|
||||
|
||||
static void floppy_on_interrupt(void)
|
||||
{
|
||||
/* We cannot do a floppy-select, as that might sleep. We just force it */
|
||||
selected = 1;
|
||||
if (current_drive != (current_DOR & 3)) {
|
||||
current_DOR &= 0xFC;
|
||||
current_DOR |= current_drive;
|
||||
outb(current_DOR,FD_DOR);
|
||||
add_timer(2,&transfer);
|
||||
} else
|
||||
transfer();
|
||||
}
|
||||
|
||||
void do_fd_request(void)
|
||||
{
|
||||
unsigned int block;
|
||||
|
||||
seek = 0;
|
||||
if (reset) {
|
||||
reset_floppy();
|
||||
return;
|
||||
}
|
||||
if (recalibrate) {
|
||||
recalibrate_floppy();
|
||||
return;
|
||||
}
|
||||
INIT_REQUEST;
|
||||
floppy = (MINOR(CURRENT->dev)>>2) + floppy_type;
|
||||
if (current_drive != CURRENT_DEV)
|
||||
seek = 1;
|
||||
current_drive = CURRENT_DEV;
|
||||
block = CURRENT->sector;
|
||||
if (block+2 > floppy->size) {
|
||||
end_request(0);
|
||||
goto repeat;
|
||||
}
|
||||
sector = block % floppy->sect;
|
||||
block /= floppy->sect;
|
||||
head = block % floppy->head;
|
||||
track = block / floppy->head;
|
||||
seek_track = track << floppy->stretch;
|
||||
if (seek_track != current_track)
|
||||
seek = 1;
|
||||
sector++;
|
||||
if (CURRENT->cmd == READ)
|
||||
command = FD_READ;
|
||||
else if (CURRENT->cmd == WRITE)
|
||||
command = FD_WRITE;
|
||||
else
|
||||
panic("do_fd_request: unknown command");
|
||||
add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt);
|
||||
}
|
||||
|
||||
static int floppy_sizes[] ={
|
||||
0, 0, 0, 0,
|
||||
360, 360 ,360, 360,
|
||||
1200,1200,1200,1200,
|
||||
360, 360, 360, 360,
|
||||
720, 720, 720, 720,
|
||||
360, 360, 360, 360,
|
||||
720, 720, 720, 720,
|
||||
1440,1440,1440,1440
|
||||
};
|
||||
|
||||
void floppy_init(void)
|
||||
{
|
||||
blk_size[MAJOR_NR] = floppy_sizes;
|
||||
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
|
||||
set_trap_gate(0x26,&floppy_interrupt);
|
||||
outb(inb_p(0x21)&~0x40,0x21);
|
||||
}
|
||||
384
Book-Lite/linux-0.12/kernel/blk_drv/hd.c
Normal file
384
Book-Lite/linux-0.12/kernel/blk_drv/hd.c
Normal file
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
* linux/kernel/hd.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the low-level hd interrupt support. It traverses the
|
||||
* request-list, using interrupts to jump between functions. As
|
||||
* all the functions are called within interrupts, we may not
|
||||
* sleep. Special care is recommended.
|
||||
*
|
||||
* modified by Drew Eckhardt to check nr of hd's from the CMOS.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
#define MAJOR_NR 3
|
||||
#include "blk.h"
|
||||
|
||||
#define CMOS_READ(addr) ({ \
|
||||
outb_p(0x80|addr,0x70); \
|
||||
inb_p(0x71); \
|
||||
})
|
||||
|
||||
/* Max read/write errors/sector */
|
||||
#define MAX_ERRORS 7
|
||||
#define MAX_HD 2
|
||||
|
||||
static void recal_intr(void);
|
||||
static void bad_rw_intr(void);
|
||||
|
||||
static int recalibrate = 0;
|
||||
static int reset = 0;
|
||||
|
||||
/*
|
||||
* This struct defines the HD's and their types.
|
||||
*/
|
||||
struct hd_i_struct {
|
||||
int head,sect,cyl,wpcom,lzone,ctl;
|
||||
};
|
||||
#ifdef HD_TYPE
|
||||
struct hd_i_struct hd_info[] = { HD_TYPE };
|
||||
#define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
|
||||
#else
|
||||
struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
|
||||
static int NR_HD = 0;
|
||||
#endif
|
||||
|
||||
static struct hd_struct {
|
||||
long start_sect;
|
||||
long nr_sects;
|
||||
} hd[5*MAX_HD]={{0,0},};
|
||||
|
||||
static int hd_sizes[5*MAX_HD] = {0, };
|
||||
|
||||
#define port_read(port,buf,nr) \
|
||||
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
|
||||
|
||||
#define port_write(port,buf,nr) \
|
||||
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
|
||||
|
||||
extern void hd_interrupt(void);
|
||||
extern void rd_load(void);
|
||||
|
||||
/* This may be used only once, enforced by 'static int callable' */
|
||||
int sys_setup(void * BIOS)
|
||||
{
|
||||
static int callable = 1;
|
||||
int i,drive;
|
||||
unsigned char cmos_disks;
|
||||
struct partition *p;
|
||||
struct buffer_head * bh;
|
||||
|
||||
if (!callable)
|
||||
return -1;
|
||||
callable = 0;
|
||||
#ifndef HD_TYPE
|
||||
for (drive=0 ; drive<2 ; drive++) {
|
||||
hd_info[drive].cyl = *(unsigned short *) BIOS;
|
||||
hd_info[drive].head = *(unsigned char *) (2+BIOS);
|
||||
hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
|
||||
hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
|
||||
hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
|
||||
hd_info[drive].sect = *(unsigned char *) (14+BIOS);
|
||||
BIOS += 16;
|
||||
}
|
||||
if (hd_info[1].cyl)
|
||||
NR_HD=2;
|
||||
else
|
||||
NR_HD=1;
|
||||
#endif
|
||||
for (i=0 ; i<NR_HD ; i++) {
|
||||
hd[i*5].start_sect = 0;
|
||||
hd[i*5].nr_sects = hd_info[i].head*
|
||||
hd_info[i].sect*hd_info[i].cyl;
|
||||
}
|
||||
|
||||
/*
|
||||
We querry CMOS about hard disks : it could be that
|
||||
we have a SCSI/ESDI/etc controller that is BIOS
|
||||
compatable with ST-506, and thus showing up in our
|
||||
BIOS table, but not register compatable, and therefore
|
||||
not present in CMOS.
|
||||
|
||||
Furthurmore, we will assume that our ST-506 drives
|
||||
<if any> are the primary drives in the system, and
|
||||
the ones reflected as drive 1 or 2.
|
||||
|
||||
The first drive is stored in the high nibble of CMOS
|
||||
byte 0x12, the second in the low nibble. This will be
|
||||
either a 4 bit drive type or 0xf indicating use byte 0x19
|
||||
for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
|
||||
|
||||
Needless to say, a non-zero value means we have
|
||||
an AT controller hard disk for that drive.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
|
||||
if (cmos_disks & 0x0f)
|
||||
NR_HD = 2;
|
||||
else
|
||||
NR_HD = 1;
|
||||
else
|
||||
NR_HD = 0;
|
||||
for (i = NR_HD ; i < 2 ; i++) {
|
||||
hd[i*5].start_sect = 0;
|
||||
hd[i*5].nr_sects = 0;
|
||||
}
|
||||
for (drive=0 ; drive<NR_HD ; drive++) {
|
||||
if (!(bh = bread(0x300 + drive*5,0))) {
|
||||
printk("Unable to read partition table of drive %d\n\r",
|
||||
drive);
|
||||
panic("");
|
||||
}
|
||||
if (bh->b_data[510] != 0x55 || (unsigned char)
|
||||
bh->b_data[511] != 0xAA) {
|
||||
printk("Bad partition table on drive %d\n\r",drive);
|
||||
panic("");
|
||||
}
|
||||
p = 0x1BE + (void *)bh->b_data;
|
||||
for (i=1;i<5;i++,p++) {
|
||||
hd[i+5*drive].start_sect = p->start_sect;
|
||||
hd[i+5*drive].nr_sects = p->nr_sects;
|
||||
}
|
||||
brelse(bh);
|
||||
}
|
||||
for (i=0 ; i<5*MAX_HD ; i++)
|
||||
hd_sizes[i] = hd[i].nr_sects>>1 ;
|
||||
blk_size[MAJOR_NR] = hd_sizes;
|
||||
if (NR_HD)
|
||||
printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
|
||||
rd_load();
|
||||
init_swapping();
|
||||
mount_root();
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int controller_ready(void)
|
||||
{
|
||||
int retries = 100000;
|
||||
|
||||
while (--retries && (inb_p(HD_STATUS)&0xc0)!=0x40);
|
||||
return (retries);
|
||||
}
|
||||
|
||||
static int win_result(void)
|
||||
{
|
||||
int i=inb_p(HD_STATUS);
|
||||
|
||||
if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
|
||||
== (READY_STAT | SEEK_STAT))
|
||||
return(0); /* ok */
|
||||
if (i&1) i=inb(HD_ERROR);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
|
||||
unsigned int head,unsigned int cyl,unsigned int cmd,
|
||||
void (*intr_addr)(void))
|
||||
{
|
||||
register int port asm("dx");
|
||||
|
||||
if (drive>1 || head>15)
|
||||
panic("Trying to write bad sector");
|
||||
if (!controller_ready())
|
||||
panic("HD controller not ready");
|
||||
SET_INTR(intr_addr);
|
||||
outb_p(hd_info[drive].ctl,HD_CMD);
|
||||
port=HD_DATA;
|
||||
outb_p(hd_info[drive].wpcom>>2,++port);
|
||||
outb_p(nsect,++port);
|
||||
outb_p(sect,++port);
|
||||
outb_p(cyl,++port);
|
||||
outb_p(cyl>>8,++port);
|
||||
outb_p(0xA0|(drive<<4)|head,++port);
|
||||
outb(cmd,++port);
|
||||
}
|
||||
|
||||
static int drive_busy(void)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned char c;
|
||||
|
||||
for (i = 0; i < 50000; i++) {
|
||||
c = inb_p(HD_STATUS);
|
||||
c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
|
||||
if (c == (READY_STAT | SEEK_STAT))
|
||||
return 0;
|
||||
}
|
||||
printk("HD controller times out\n\r");
|
||||
return(1);
|
||||
}
|
||||
|
||||
static void reset_controller(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
outb(4,HD_CMD);
|
||||
for(i = 0; i < 1000; i++) nop();
|
||||
outb(hd_info[0].ctl & 0x0f ,HD_CMD);
|
||||
if (drive_busy())
|
||||
printk("HD-controller still busy\n\r");
|
||||
if ((i = inb(HD_ERROR)) != 1)
|
||||
printk("HD-controller reset failed: %02x\n\r",i);
|
||||
}
|
||||
|
||||
static void reset_hd(void)
|
||||
{
|
||||
static int i;
|
||||
|
||||
repeat:
|
||||
if (reset) {
|
||||
reset = 0;
|
||||
i = -1;
|
||||
reset_controller();
|
||||
} else if (win_result()) {
|
||||
bad_rw_intr();
|
||||
if (reset)
|
||||
goto repeat;
|
||||
}
|
||||
i++;
|
||||
if (i < NR_HD) {
|
||||
hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
|
||||
hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
|
||||
} else
|
||||
do_hd_request();
|
||||
}
|
||||
|
||||
void unexpected_hd_interrupt(void)
|
||||
{
|
||||
printk("Unexpected HD interrupt\n\r");
|
||||
reset = 1;
|
||||
do_hd_request();
|
||||
}
|
||||
|
||||
static void bad_rw_intr(void)
|
||||
{
|
||||
if (++CURRENT->errors >= MAX_ERRORS)
|
||||
end_request(0);
|
||||
if (CURRENT->errors > MAX_ERRORS/2)
|
||||
reset = 1;
|
||||
}
|
||||
|
||||
static void read_intr(void)
|
||||
{
|
||||
if (win_result()) {
|
||||
bad_rw_intr();
|
||||
do_hd_request();
|
||||
return;
|
||||
}
|
||||
port_read(HD_DATA,CURRENT->buffer,256);
|
||||
CURRENT->errors = 0;
|
||||
CURRENT->buffer += 512;
|
||||
CURRENT->sector++;
|
||||
if (--CURRENT->nr_sectors) {
|
||||
SET_INTR(&read_intr);
|
||||
return;
|
||||
}
|
||||
end_request(1);
|
||||
do_hd_request();
|
||||
}
|
||||
|
||||
static void write_intr(void)
|
||||
{
|
||||
if (win_result()) {
|
||||
bad_rw_intr();
|
||||
do_hd_request();
|
||||
return;
|
||||
}
|
||||
if (--CURRENT->nr_sectors) {
|
||||
CURRENT->sector++;
|
||||
CURRENT->buffer += 512;
|
||||
SET_INTR(&write_intr);
|
||||
port_write(HD_DATA,CURRENT->buffer,256);
|
||||
return;
|
||||
}
|
||||
end_request(1);
|
||||
do_hd_request();
|
||||
}
|
||||
|
||||
static void recal_intr(void)
|
||||
{
|
||||
if (win_result())
|
||||
bad_rw_intr();
|
||||
do_hd_request();
|
||||
}
|
||||
|
||||
void hd_times_out(void)
|
||||
{
|
||||
if (!CURRENT)
|
||||
return;
|
||||
printk("HD timeout");
|
||||
if (++CURRENT->errors >= MAX_ERRORS)
|
||||
end_request(0);
|
||||
SET_INTR(NULL);
|
||||
reset = 1;
|
||||
do_hd_request();
|
||||
}
|
||||
|
||||
void do_hd_request(void)
|
||||
{
|
||||
int i,r;
|
||||
unsigned int block,dev;
|
||||
unsigned int sec,head,cyl;
|
||||
unsigned int nsect;
|
||||
|
||||
INIT_REQUEST;
|
||||
dev = MINOR(CURRENT->dev);
|
||||
block = CURRENT->sector;
|
||||
if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) {
|
||||
end_request(0);
|
||||
goto repeat;
|
||||
}
|
||||
block += hd[dev].start_sect;
|
||||
dev /= 5;
|
||||
__asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
|
||||
"r" (hd_info[dev].sect));
|
||||
__asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
|
||||
"r" (hd_info[dev].head));
|
||||
sec++;
|
||||
nsect = CURRENT->nr_sectors;
|
||||
if (reset) {
|
||||
recalibrate = 1;
|
||||
reset_hd();
|
||||
return;
|
||||
}
|
||||
if (recalibrate) {
|
||||
recalibrate = 0;
|
||||
hd_out(dev,hd_info[CURRENT_DEV].sect,0,0,0,
|
||||
WIN_RESTORE,&recal_intr);
|
||||
return;
|
||||
}
|
||||
if (CURRENT->cmd == WRITE) {
|
||||
hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
|
||||
for(i=0 ; i<10000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
|
||||
/* nothing */ ;
|
||||
if (!r) {
|
||||
bad_rw_intr();
|
||||
goto repeat;
|
||||
}
|
||||
port_write(HD_DATA,CURRENT->buffer,256);
|
||||
} else if (CURRENT->cmd == READ) {
|
||||
hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
|
||||
} else
|
||||
panic("unknown hd-command");
|
||||
}
|
||||
|
||||
void hd_init(void)
|
||||
{
|
||||
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
|
||||
set_intr_gate(0x2E,&hd_interrupt);
|
||||
outb_p(inb_p(0x21)&0xfb,0x21);
|
||||
outb(inb_p(0xA1)&0xbf,0xA1);
|
||||
}
|
||||
218
Book-Lite/linux-0.12/kernel/blk_drv/ll_rw_blk.c
Normal file
218
Book-Lite/linux-0.12/kernel/blk_drv/ll_rw_blk.c
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* linux/kernel/blk_dev/ll_rw.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* This handles all read/write requests to block devices
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include "blk.h"
|
||||
|
||||
/*
|
||||
* The request-struct contains all necessary data
|
||||
* to load a nr of sectors into memory
|
||||
*/
|
||||
struct request request[NR_REQUEST];
|
||||
|
||||
/*
|
||||
* used to wait on when there are no free requests
|
||||
*/
|
||||
struct task_struct * wait_for_request = NULL;
|
||||
|
||||
/* blk_dev_struct is:
|
||||
* do_request-address
|
||||
* next-request
|
||||
*/
|
||||
struct blk_dev_struct blk_dev[NR_BLK_DEV] = {
|
||||
{ NULL, NULL }, /* no_dev */
|
||||
{ NULL, NULL }, /* dev mem */
|
||||
{ NULL, NULL }, /* dev fd */
|
||||
{ NULL, NULL }, /* dev hd */
|
||||
{ NULL, NULL }, /* dev ttyx */
|
||||
{ NULL, NULL }, /* dev tty */
|
||||
{ NULL, NULL } /* dev lp */
|
||||
};
|
||||
|
||||
/*
|
||||
* blk_size contains the size of all block-devices:
|
||||
*
|
||||
* blk_size[MAJOR][MINOR]
|
||||
*
|
||||
* if (!blk_size[MAJOR]) then no minor size checking is done.
|
||||
*/
|
||||
int * blk_size[NR_BLK_DEV] = { NULL, NULL, };
|
||||
|
||||
static inline void lock_buffer(struct buffer_head * bh)
|
||||
{
|
||||
cli();
|
||||
while (bh->b_lock)
|
||||
sleep_on(&bh->b_wait);
|
||||
bh->b_lock=1;
|
||||
sti();
|
||||
}
|
||||
|
||||
static inline void unlock_buffer(struct buffer_head * bh)
|
||||
{
|
||||
if (!bh->b_lock)
|
||||
printk("ll_rw_block.c: buffer not locked\n\r");
|
||||
bh->b_lock = 0;
|
||||
wake_up(&bh->b_wait);
|
||||
}
|
||||
|
||||
/*
|
||||
* add-request adds a request to the linked list.
|
||||
* It disables interrupts so that it can muck with the
|
||||
* request-lists in peace.
|
||||
*
|
||||
* Note that swapping requests always go before other requests,
|
||||
* and are done in the order they appear.
|
||||
*/
|
||||
static void add_request(struct blk_dev_struct * dev, struct request * req)
|
||||
{
|
||||
struct request * tmp;
|
||||
|
||||
req->next = NULL;
|
||||
cli();
|
||||
if (req->bh)
|
||||
req->bh->b_dirt = 0;
|
||||
if (!(tmp = dev->current_request)) {
|
||||
dev->current_request = req;
|
||||
sti();
|
||||
(dev->request_fn)();
|
||||
return;
|
||||
}
|
||||
for ( ; tmp->next ; tmp=tmp->next) {
|
||||
if (!req->bh)
|
||||
if (tmp->next->bh)
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
if ((IN_ORDER(tmp,req) ||
|
||||
!IN_ORDER(tmp,tmp->next)) &&
|
||||
IN_ORDER(req,tmp->next))
|
||||
break;
|
||||
}
|
||||
req->next=tmp->next;
|
||||
tmp->next=req;
|
||||
sti();
|
||||
}
|
||||
|
||||
static void make_request(int major,int rw, struct buffer_head * bh)
|
||||
{
|
||||
struct request * req;
|
||||
int rw_ahead;
|
||||
|
||||
/* WRITEA/READA is special case - it is not really needed, so if the */
|
||||
/* buffer is locked, we just forget about it, else it's a normal read */
|
||||
if (rw_ahead = (rw == READA || rw == WRITEA)) {
|
||||
if (bh->b_lock)
|
||||
return;
|
||||
if (rw == READA)
|
||||
rw = READ;
|
||||
else
|
||||
rw = WRITE;
|
||||
}
|
||||
if (rw!=READ && rw!=WRITE)
|
||||
panic("Bad block dev command, must be R/W/RA/WA");
|
||||
lock_buffer(bh);
|
||||
if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) {
|
||||
unlock_buffer(bh);
|
||||
return;
|
||||
}
|
||||
repeat:
|
||||
/* we don't allow the write-requests to fill up the queue completely:
|
||||
* we want some room for reads: they take precedence. The last third
|
||||
* of the requests are only for reads.
|
||||
*/
|
||||
if (rw == READ)
|
||||
req = request+NR_REQUEST;
|
||||
else
|
||||
req = request+((NR_REQUEST*2)/3);
|
||||
/* find an empty request */
|
||||
while (--req >= request)
|
||||
if (req->dev<0)
|
||||
break;
|
||||
/* if none found, sleep on new requests: check for rw_ahead */
|
||||
if (req < request) {
|
||||
if (rw_ahead) {
|
||||
unlock_buffer(bh);
|
||||
return;
|
||||
}
|
||||
sleep_on(&wait_for_request);
|
||||
goto repeat;
|
||||
}
|
||||
/* fill up the request-info, and add it to the queue */
|
||||
req->dev = bh->b_dev;
|
||||
req->cmd = rw;
|
||||
req->errors=0;
|
||||
req->sector = bh->b_blocknr<<1;
|
||||
req->nr_sectors = 2;
|
||||
req->buffer = bh->b_data;
|
||||
req->waiting = NULL;
|
||||
req->bh = bh;
|
||||
req->next = NULL;
|
||||
add_request(major+blk_dev,req);
|
||||
}
|
||||
|
||||
void ll_rw_page(int rw, int dev, int page, char * buffer)
|
||||
{
|
||||
struct request * req;
|
||||
unsigned int major = MAJOR(dev);
|
||||
|
||||
if (major >= NR_BLK_DEV || !(blk_dev[major].request_fn)) {
|
||||
printk("Trying to read nonexistent block-device\n\r");
|
||||
return;
|
||||
}
|
||||
if (rw!=READ && rw!=WRITE)
|
||||
panic("Bad block dev command, must be R/W");
|
||||
repeat:
|
||||
req = request+NR_REQUEST;
|
||||
while (--req >= request)
|
||||
if (req->dev<0)
|
||||
break;
|
||||
if (req < request) {
|
||||
sleep_on(&wait_for_request);
|
||||
goto repeat;
|
||||
}
|
||||
/* fill up the request-info, and add it to the queue */
|
||||
req->dev = dev;
|
||||
req->cmd = rw;
|
||||
req->errors = 0;
|
||||
req->sector = page<<3;
|
||||
req->nr_sectors = 8;
|
||||
req->buffer = buffer;
|
||||
req->waiting = current;
|
||||
req->bh = NULL;
|
||||
req->next = NULL;
|
||||
current->state = TASK_UNINTERRUPTIBLE;
|
||||
add_request(major+blk_dev,req);
|
||||
schedule();
|
||||
}
|
||||
|
||||
void ll_rw_block(int rw, struct buffer_head * bh)
|
||||
{
|
||||
unsigned int major;
|
||||
|
||||
if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV ||
|
||||
!(blk_dev[major].request_fn)) {
|
||||
printk("Trying to read nonexistent block-device\n\r");
|
||||
return;
|
||||
}
|
||||
make_request(major,rw,bh);
|
||||
}
|
||||
|
||||
void blk_dev_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<NR_REQUEST ; i++) {
|
||||
request[i].dev = -1;
|
||||
request[i].next = NULL;
|
||||
}
|
||||
}
|
||||
125
Book-Lite/linux-0.12/kernel/blk_drv/ramdisk.c
Normal file
125
Book-Lite/linux-0.12/kernel/blk_drv/ramdisk.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* linux/kernel/blk_drv/ramdisk.c
|
||||
*
|
||||
* Written by Theodore Ts'o, 12/2/91
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/memory.h>
|
||||
|
||||
#define MAJOR_NR 1
|
||||
#include "blk.h"
|
||||
|
||||
char *rd_start;
|
||||
int rd_length = 0;
|
||||
|
||||
void do_rd_request(void)
|
||||
{
|
||||
int len;
|
||||
char *addr;
|
||||
|
||||
INIT_REQUEST;
|
||||
addr = rd_start + (CURRENT->sector << 9);
|
||||
len = CURRENT->nr_sectors << 9;
|
||||
if ((MINOR(CURRENT->dev) != 1) || (addr+len > rd_start+rd_length)) {
|
||||
end_request(0);
|
||||
goto repeat;
|
||||
}
|
||||
if (CURRENT-> cmd == WRITE) {
|
||||
(void ) memcpy(addr,
|
||||
CURRENT->buffer,
|
||||
len);
|
||||
} else if (CURRENT->cmd == READ) {
|
||||
(void) memcpy(CURRENT->buffer,
|
||||
addr,
|
||||
len);
|
||||
} else
|
||||
panic("unknown ramdisk-command");
|
||||
end_request(1);
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns amount of memory which needs to be reserved.
|
||||
*/
|
||||
long rd_init(long mem_start, int length)
|
||||
{
|
||||
int i;
|
||||
char *cp;
|
||||
|
||||
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
|
||||
rd_start = (char *) mem_start;
|
||||
rd_length = length;
|
||||
cp = rd_start;
|
||||
for (i=0; i < length; i++)
|
||||
*cp++ = '\0';
|
||||
return(length);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the root device is the ram disk, try to load it.
|
||||
* In order to do this, the root device is originally set to the
|
||||
* floppy, and we later change it to be ram disk.
|
||||
*/
|
||||
void rd_load(void)
|
||||
{
|
||||
struct buffer_head *bh;
|
||||
struct super_block s;
|
||||
int block = 256; /* Start at block 256 */
|
||||
int i = 1;
|
||||
int nblocks;
|
||||
char *cp; /* Move pointer */
|
||||
|
||||
if (!rd_length)
|
||||
return;
|
||||
printk("Ram disk: %d bytes, starting at 0x%x\n", rd_length,
|
||||
(int) rd_start);
|
||||
if (MAJOR(ROOT_DEV) != 2)
|
||||
return;
|
||||
bh = breada(ROOT_DEV,block+1,block,block+2,-1);
|
||||
if (!bh) {
|
||||
printk("Disk error while looking for ramdisk!\n");
|
||||
return;
|
||||
}
|
||||
*((struct d_super_block *) &s) = *((struct d_super_block *) bh->b_data);
|
||||
brelse(bh);
|
||||
if (s.s_magic != SUPER_MAGIC)
|
||||
/* No ram disk image present, assume normal floppy boot */
|
||||
return;
|
||||
nblocks = s.s_nzones << s.s_log_zone_size;
|
||||
if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) {
|
||||
printk("Ram disk image too big! (%d blocks, %d avail)\n",
|
||||
nblocks, rd_length >> BLOCK_SIZE_BITS);
|
||||
return;
|
||||
}
|
||||
printk("Loading %d bytes into ram disk... 0000k",
|
||||
nblocks << BLOCK_SIZE_BITS);
|
||||
cp = rd_start;
|
||||
while (nblocks) {
|
||||
if (nblocks > 2)
|
||||
bh = breada(ROOT_DEV, block, block+1, block+2, -1);
|
||||
else
|
||||
bh = bread(ROOT_DEV, block);
|
||||
if (!bh) {
|
||||
printk("I/O error on block %d, aborting load\n",
|
||||
block);
|
||||
return;
|
||||
}
|
||||
(void) memcpy(cp, bh->b_data, BLOCK_SIZE);
|
||||
brelse(bh);
|
||||
printk("\010\010\010\010\010%4dk",i);
|
||||
cp += BLOCK_SIZE;
|
||||
block++;
|
||||
nblocks--;
|
||||
i++;
|
||||
}
|
||||
printk("\010\010\010\010\010done \n");
|
||||
ROOT_DEV=0x0101;
|
||||
}
|
||||
88
Book-Lite/linux-0.12/kernel/chr_drv/Makefile
Normal file
88
Book-Lite/linux-0.12/kernel/chr_drv/Makefile
Normal file
@@ -0,0 +1,88 @@
|
||||
#
|
||||
# Makefile for the FREAX-kernel character device drivers.
|
||||
#
|
||||
# Note! Dependencies are done automagically by 'make dep', which also
|
||||
# removes any old dependencies. DON'T put your own dependencies here
|
||||
# unless it's something special (ie not a .c file).
|
||||
#
|
||||
|
||||
AR =gar
|
||||
AS =gas
|
||||
LD =gld
|
||||
LDFLAGS =-s -x
|
||||
CC =gcc
|
||||
CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
|
||||
-finline-functions -mstring-insns -nostdinc -I../../include
|
||||
CPP =gcc -E -nostdinc -I../../include
|
||||
|
||||
.c.s:
|
||||
$(CC) $(CFLAGS) \
|
||||
-S -o $*.s $<
|
||||
.s.o:
|
||||
$(AS) -c -o $*.o $<
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) \
|
||||
-c -o $*.o $<
|
||||
|
||||
OBJS = tty_io.o console.o keyboard.o serial.o rs_io.o \
|
||||
tty_ioctl.o pty.o
|
||||
|
||||
chr_drv.a: $(OBJS)
|
||||
$(AR) rcs chr_drv.a $(OBJS)
|
||||
sync
|
||||
|
||||
keyboard.s: keyboard.S
|
||||
$(CPP) -traditional keyboard.S -o keyboard.s
|
||||
|
||||
clean:
|
||||
rm -f core *.o *.a tmp_make keyboard.s
|
||||
for i in *.c;do rm -f `basename $$i .c`.s;done
|
||||
|
||||
dep:
|
||||
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
|
||||
(for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \
|
||||
$(CPP) -M $$i;done) >> tmp_make
|
||||
cp tmp_make Makefile
|
||||
|
||||
### Dependencies:
|
||||
console.s console.o : console.c ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h \
|
||||
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
|
||||
../../include/sys/resource.h ../../include/linux/tty.h \
|
||||
../../include/termios.h ../../include/linux/config.h ../../include/asm/io.h \
|
||||
../../include/asm/system.h ../../include/asm/segment.h \
|
||||
../../include/string.h ../../include/errno.h
|
||||
pty.s pty.o : pty.c ../../include/linux/tty.h ../../include/termios.h \
|
||||
../../include/sys/types.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/linux/mm.h ../../include/linux/kernel.h \
|
||||
../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
|
||||
../../include/time.h ../../include/sys/resource.h \
|
||||
../../include/asm/system.h ../../include/asm/io.h
|
||||
serial.s serial.o : serial.c ../../include/linux/tty.h ../../include/termios.h \
|
||||
../../include/sys/types.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/linux/mm.h ../../include/linux/kernel.h \
|
||||
../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
|
||||
../../include/time.h ../../include/sys/resource.h \
|
||||
../../include/asm/system.h ../../include/asm/io.h
|
||||
tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \
|
||||
../../include/signal.h ../../include/sys/types.h ../../include/unistd.h \
|
||||
../../include/sys/stat.h ../../include/sys/time.h ../../include/time.h \
|
||||
../../include/sys/times.h ../../include/sys/utsname.h \
|
||||
../../include/sys/param.h ../../include/sys/resource.h \
|
||||
../../include/utime.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/linux/mm.h ../../include/linux/kernel.h \
|
||||
../../include/linux/tty.h ../../include/termios.h \
|
||||
../../include/asm/segment.h ../../include/asm/system.h
|
||||
tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.h \
|
||||
../../include/sys/types.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/linux/mm.h ../../include/linux/kernel.h \
|
||||
../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
|
||||
../../include/time.h ../../include/sys/resource.h ../../include/linux/tty.h \
|
||||
../../include/asm/io.h ../../include/asm/segment.h \
|
||||
../../include/asm/system.h
|
||||
1025
Book-Lite/linux-0.12/kernel/chr_drv/console.c
Normal file
1025
Book-Lite/linux-0.12/kernel/chr_drv/console.c
Normal file
File diff suppressed because it is too large
Load Diff
599
Book-Lite/linux-0.12/kernel/chr_drv/keyboard.S
Normal file
599
Book-Lite/linux-0.12/kernel/chr_drv/keyboard.S
Normal file
@@ -0,0 +1,599 @@
|
||||
/*
|
||||
* linux/kernel/keyboard.S
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* Thanks to Alfred Leung for US keyboard patches
|
||||
* Wolfgang Thiel for German keyboard patches
|
||||
* Marc Corsini for the French keyboard
|
||||
*/
|
||||
|
||||
/* KBD_FINNISH for Finnish keyboards
|
||||
* KBD_US for US-type
|
||||
* KBD_GR for German keyboards
|
||||
* KBD_FR for Frech keyboard
|
||||
*/
|
||||
#define KBD_FINNISH
|
||||
|
||||
.text
|
||||
.globl _keyboard_interrupt
|
||||
|
||||
/*
|
||||
* these are for the keyboard read functions
|
||||
*/
|
||||
size = 1024 /* must be a power of two ! And MUST be the same
|
||||
as in tty_io.c !!!! */
|
||||
head = 4
|
||||
tail = 8
|
||||
proc_list = 12
|
||||
buf = 16
|
||||
|
||||
mode: .byte 0 /* caps, alt, ctrl and shift mode */
|
||||
leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */
|
||||
e0: .byte 0
|
||||
|
||||
/*
|
||||
* con_int is the real interrupt routine that reads the
|
||||
* keyboard scan-code and converts it into the appropriate
|
||||
* ascii character(s).
|
||||
*/
|
||||
_keyboard_interrupt:
|
||||
pushl %eax
|
||||
pushl %ebx
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
push %ds
|
||||
push %es
|
||||
movl $0x10,%eax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
movl _blankinterval,%eax
|
||||
movl %eax,_blankcount
|
||||
xorl %eax,%eax /* %eax is scan code */
|
||||
inb $0x60,%al
|
||||
cmpb $0xe0,%al
|
||||
je set_e0
|
||||
cmpb $0xe1,%al
|
||||
je set_e1
|
||||
call key_table(,%eax,4)
|
||||
movb $0,e0
|
||||
e0_e1: inb $0x61,%al
|
||||
jmp 1f
|
||||
1: jmp 1f
|
||||
1: orb $0x80,%al
|
||||
jmp 1f
|
||||
1: jmp 1f
|
||||
1: outb %al,$0x61
|
||||
jmp 1f
|
||||
1: jmp 1f
|
||||
1: andb $0x7F,%al
|
||||
outb %al,$0x61
|
||||
movb $0x20,%al
|
||||
outb %al,$0x20
|
||||
pushl $0
|
||||
call _do_tty_interrupt
|
||||
addl $4,%esp
|
||||
pop %es
|
||||
pop %ds
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
popl %eax
|
||||
iret
|
||||
set_e0: movb $1,e0
|
||||
jmp e0_e1
|
||||
set_e1: movb $2,e0
|
||||
jmp e0_e1
|
||||
|
||||
/*
|
||||
* This routine fills the buffer with max 8 bytes, taken from
|
||||
* %ebx:%eax. (%edx is high). The bytes are written in the
|
||||
* order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero.
|
||||
*/
|
||||
put_queue:
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
movl _table_list,%edx # read-queue for console
|
||||
movl head(%edx),%ecx
|
||||
1: movb %al,buf(%edx,%ecx)
|
||||
incl %ecx
|
||||
andl $size-1,%ecx
|
||||
cmpl tail(%edx),%ecx # buffer full - discard everything
|
||||
je 3f
|
||||
shrdl $8,%ebx,%eax
|
||||
je 2f
|
||||
shrl $8,%ebx
|
||||
jmp 1b
|
||||
2: movl %ecx,head(%edx)
|
||||
movl proc_list(%edx),%ecx
|
||||
testl %ecx,%ecx
|
||||
je 3f
|
||||
movl $0,(%ecx)
|
||||
3: popl %edx
|
||||
popl %ecx
|
||||
ret
|
||||
|
||||
ctrl: movb $0x04,%al
|
||||
jmp 1f
|
||||
alt: movb $0x10,%al
|
||||
1: cmpb $0,e0
|
||||
je 2f
|
||||
addb %al,%al
|
||||
2: orb %al,mode
|
||||
ret
|
||||
unctrl: movb $0x04,%al
|
||||
jmp 1f
|
||||
unalt: movb $0x10,%al
|
||||
1: cmpb $0,e0
|
||||
je 2f
|
||||
addb %al,%al
|
||||
2: notb %al
|
||||
andb %al,mode
|
||||
ret
|
||||
|
||||
lshift:
|
||||
orb $0x01,mode
|
||||
ret
|
||||
unlshift:
|
||||
andb $0xfe,mode
|
||||
ret
|
||||
rshift:
|
||||
orb $0x02,mode
|
||||
ret
|
||||
unrshift:
|
||||
andb $0xfd,mode
|
||||
ret
|
||||
|
||||
caps: testb $0x80,mode
|
||||
jne 1f
|
||||
xorb $4,leds
|
||||
xorb $0x40,mode
|
||||
orb $0x80,mode
|
||||
set_leds:
|
||||
call kb_wait
|
||||
movb $0xed,%al /* set leds command */
|
||||
outb %al,$0x60
|
||||
call kb_wait
|
||||
movb leds,%al
|
||||
outb %al,$0x60
|
||||
ret
|
||||
uncaps: andb $0x7f,mode
|
||||
ret
|
||||
scroll:
|
||||
testb $0x03,mode
|
||||
je 1f
|
||||
call _show_mem
|
||||
jmp 2f
|
||||
1: call _show_state
|
||||
2: xorb $1,leds
|
||||
jmp set_leds
|
||||
num: xorb $2,leds
|
||||
jmp set_leds
|
||||
|
||||
/*
|
||||
* curosr-key/numeric keypad cursor keys are handled here.
|
||||
* checking for numeric keypad etc.
|
||||
*/
|
||||
cursor:
|
||||
subb $0x47,%al
|
||||
jb 1f
|
||||
cmpb $12,%al
|
||||
ja 1f
|
||||
jne cur2 /* check for ctrl-alt-del */
|
||||
testb $0x0c,mode
|
||||
je cur2
|
||||
testb $0x30,mode
|
||||
jne reboot
|
||||
cur2: cmpb $0x01,e0 /* e0 forces cursor movement */
|
||||
je cur
|
||||
testb $0x02,leds /* not num-lock forces cursor */
|
||||
je cur
|
||||
testb $0x03,mode /* shift forces cursor */
|
||||
jne cur
|
||||
xorl %ebx,%ebx
|
||||
movb num_table(%eax),%al
|
||||
jmp put_queue
|
||||
1: ret
|
||||
|
||||
cur: movb cur_table(%eax),%al
|
||||
cmpb $'9,%al
|
||||
ja ok_cur
|
||||
movb $'~,%ah
|
||||
ok_cur: shll $16,%eax
|
||||
movw $0x5b1b,%ax
|
||||
xorl %ebx,%ebx
|
||||
jmp put_queue
|
||||
|
||||
#if defined(KBD_FR)
|
||||
num_table:
|
||||
.ascii "789 456 1230."
|
||||
#else
|
||||
num_table:
|
||||
.ascii "789 456 1230,"
|
||||
#endif
|
||||
cur_table:
|
||||
.ascii "HA5 DGC YB623"
|
||||
|
||||
/*
|
||||
* this routine handles function keys
|
||||
*/
|
||||
func:
|
||||
subb $0x3B,%al
|
||||
jb end_func
|
||||
cmpb $9,%al
|
||||
jbe ok_func
|
||||
subb $18,%al
|
||||
cmpb $10,%al
|
||||
jb end_func
|
||||
cmpb $11,%al
|
||||
ja end_func
|
||||
ok_func:
|
||||
testb $0x10,mode
|
||||
jne alt_func
|
||||
cmpl $4,%ecx /* check that there is enough room */
|
||||
jl end_func
|
||||
movl func_table(,%eax,4),%eax
|
||||
xorl %ebx,%ebx
|
||||
jmp put_queue
|
||||
alt_func:
|
||||
pushl %eax
|
||||
call _change_console
|
||||
popl %eax
|
||||
end_func:
|
||||
ret
|
||||
|
||||
/*
|
||||
* function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc.
|
||||
*/
|
||||
func_table:
|
||||
.long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b
|
||||
.long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b
|
||||
.long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b
|
||||
|
||||
#if defined(KBD_FINNISH)
|
||||
key_map:
|
||||
.byte 0,27
|
||||
.ascii "1234567890+'"
|
||||
.byte 127,9
|
||||
.ascii "qwertyuiop}"
|
||||
.byte 0,13,0
|
||||
.ascii "asdfghjkl|{"
|
||||
.byte 0,0
|
||||
.ascii "'zxcvbnm,.-"
|
||||
.byte 0,'*,0,32 /* 36-39 */
|
||||
.fill 16,1,0 /* 3A-49 */
|
||||
.byte '-,0,0,0,'+ /* 4A-4E */
|
||||
.byte 0,0,0,0,0,0,0 /* 4F-55 */
|
||||
.byte '<
|
||||
.fill 10,1,0
|
||||
|
||||
shift_map:
|
||||
.byte 0,27
|
||||
.ascii "!\"#$%&/()=?`"
|
||||
.byte 127,9
|
||||
.ascii "QWERTYUIOP]^"
|
||||
.byte 13,0
|
||||
.ascii "ASDFGHJKL\\["
|
||||
.byte 0,0
|
||||
.ascii "*ZXCVBNM;:_"
|
||||
.byte 0,'*,0,32 /* 36-39 */
|
||||
.fill 16,1,0 /* 3A-49 */
|
||||
.byte '-,0,0,0,'+ /* 4A-4E */
|
||||
.byte 0,0,0,0,0,0,0 /* 4F-55 */
|
||||
.byte '>
|
||||
.fill 10,1,0
|
||||
|
||||
alt_map:
|
||||
.byte 0,0
|
||||
.ascii "\0@\0$\0\0{[]}\\\0"
|
||||
.byte 0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte '~,13,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0 /* 36-39 */
|
||||
.fill 16,1,0 /* 3A-49 */
|
||||
.byte 0,0,0,0,0 /* 4A-4E */
|
||||
.byte 0,0,0,0,0,0,0 /* 4F-55 */
|
||||
.byte '|
|
||||
.fill 10,1,0
|
||||
|
||||
#elif defined(KBD_US)
|
||||
|
||||
key_map:
|
||||
.byte 0,27
|
||||
.ascii "1234567890-="
|
||||
.byte 127,9
|
||||
.ascii "qwertyuiop[]"
|
||||
.byte 13,0
|
||||
.ascii "asdfghjkl;'"
|
||||
.byte '`,0
|
||||
.ascii "\\zxcvbnm,./"
|
||||
.byte 0,'*,0,32 /* 36-39 */
|
||||
.fill 16,1,0 /* 3A-49 */
|
||||
.byte '-,0,0,0,'+ /* 4A-4E */
|
||||
.byte 0,0,0,0,0,0,0 /* 4F-55 */
|
||||
.byte '<
|
||||
.fill 10,1,0
|
||||
|
||||
|
||||
shift_map:
|
||||
.byte 0,27
|
||||
.ascii "!@#$%^&*()_+"
|
||||
.byte 127,9
|
||||
.ascii "QWERTYUIOP{}"
|
||||
.byte 13,0
|
||||
.ascii "ASDFGHJKL:\""
|
||||
.byte '~,0
|
||||
.ascii "|ZXCVBNM<>?"
|
||||
.byte 0,'*,0,32 /* 36-39 */
|
||||
.fill 16,1,0 /* 3A-49 */
|
||||
.byte '-,0,0,0,'+ /* 4A-4E */
|
||||
.byte 0,0,0,0,0,0,0 /* 4F-55 */
|
||||
.byte '>
|
||||
.fill 10,1,0
|
||||
|
||||
alt_map:
|
||||
.byte 0,0
|
||||
.ascii "\0@\0$\0\0{[]}\\\0"
|
||||
.byte 0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte '~,13,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0 /* 36-39 */
|
||||
.fill 16,1,0 /* 3A-49 */
|
||||
.byte 0,0,0,0,0 /* 4A-4E */
|
||||
.byte 0,0,0,0,0,0,0 /* 4F-55 */
|
||||
.byte '|
|
||||
.fill 10,1,0
|
||||
|
||||
#elif defined(KBD_GR)
|
||||
|
||||
key_map:
|
||||
.byte 0,27
|
||||
.ascii "1234567890\\'"
|
||||
.byte 127,9
|
||||
.ascii "qwertzuiop@+"
|
||||
.byte 13,0
|
||||
.ascii "asdfghjkl[]^"
|
||||
.byte 0,'#
|
||||
.ascii "yxcvbnm,.-"
|
||||
.byte 0,'*,0,32 /* 36-39 */
|
||||
.fill 16,1,0 /* 3A-49 */
|
||||
.byte '-,0,0,0,'+ /* 4A-4E */
|
||||
.byte 0,0,0,0,0,0,0 /* 4F-55 */
|
||||
.byte '<
|
||||
.fill 10,1,0
|
||||
|
||||
|
||||
shift_map:
|
||||
.byte 0,27
|
||||
.ascii "!\"#$%&/()=?`"
|
||||
.byte 127,9
|
||||
.ascii "QWERTZUIOP\\*"
|
||||
.byte 13,0
|
||||
.ascii "ASDFGHJKL{}~"
|
||||
.byte 0,''
|
||||
.ascii "YXCVBNM;:_"
|
||||
.byte 0,'*,0,32 /* 36-39 */
|
||||
.fill 16,1,0 /* 3A-49 */
|
||||
.byte '-,0,0,0,'+ /* 4A-4E */
|
||||
.byte 0,0,0,0,0,0,0 /* 4F-55 */
|
||||
.byte '>
|
||||
.fill 10,1,0
|
||||
|
||||
alt_map:
|
||||
.byte 0,0
|
||||
.ascii "\0@\0$\0\0{[]}\\\0"
|
||||
.byte 0,0
|
||||
.byte '@,0,0,0,0,0,0,0,0,0,0
|
||||
.byte '~,13,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0 /* 36-39 */
|
||||
.fill 16,1,0 /* 3A-49 */
|
||||
.byte 0,0,0,0,0 /* 4A-4E */
|
||||
.byte 0,0,0,0,0,0,0 /* 4F-55 */
|
||||
.byte '|
|
||||
.fill 10,1,0
|
||||
|
||||
|
||||
#elif defined(KBD_FR)
|
||||
|
||||
key_map:
|
||||
.byte 0,27
|
||||
.ascii "&{\"'(-}_/@)="
|
||||
.byte 127,9
|
||||
.ascii "azertyuiop^$"
|
||||
.byte 13,0
|
||||
.ascii "qsdfghjklm|"
|
||||
.byte '`,0,42 /* coin sup gauche, don't know, [*|mu] */
|
||||
.ascii "wxcvbn,;:!"
|
||||
.byte 0,'*,0,32 /* 36-39 */
|
||||
.fill 16,1,0 /* 3A-49 */
|
||||
.byte '-,0,0,0,'+ /* 4A-4E */
|
||||
.byte 0,0,0,0,0,0,0 /* 4F-55 */
|
||||
.byte '<
|
||||
.fill 10,1,0
|
||||
|
||||
shift_map:
|
||||
.byte 0,27
|
||||
.ascii "1234567890]+"
|
||||
.byte 127,9
|
||||
.ascii "AZERTYUIOP<>"
|
||||
.byte 13,0
|
||||
.ascii "QSDFGHJKLM%"
|
||||
.byte '~,0,'#
|
||||
.ascii "WXCVBN?./\\"
|
||||
.byte 0,'*,0,32 /* 36-39 */
|
||||
.fill 16,1,0 /* 3A-49 */
|
||||
.byte '-,0,0,0,'+ /* 4A-4E */
|
||||
.byte 0,0,0,0,0,0,0 /* 4F-55 */
|
||||
.byte '>
|
||||
.fill 10,1,0
|
||||
|
||||
alt_map:
|
||||
.byte 0,0
|
||||
.ascii "\0~#{[|`\\^@]}"
|
||||
.byte 0,0
|
||||
.byte '@,0,0,0,0,0,0,0,0,0,0
|
||||
.byte '~,13,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0 /* 36-39 */
|
||||
.fill 16,1,0 /* 3A-49 */
|
||||
.byte 0,0,0,0,0 /* 4A-4E */
|
||||
.byte 0,0,0,0,0,0,0 /* 4F-55 */
|
||||
.byte '|
|
||||
.fill 10,1,0
|
||||
|
||||
#else
|
||||
#error "KBD-type not defined"
|
||||
#endif
|
||||
/*
|
||||
* do_self handles "normal" keys, ie keys that don't change meaning
|
||||
* and which have just one character returns.
|
||||
*/
|
||||
do_self:
|
||||
lea alt_map,%ebx
|
||||
testb $0x20,mode /* alt-gr */
|
||||
jne 1f
|
||||
lea shift_map,%ebx
|
||||
testb $0x03,mode
|
||||
jne 1f
|
||||
lea key_map,%ebx
|
||||
1: movb (%ebx,%eax),%al
|
||||
orb %al,%al
|
||||
je none
|
||||
testb $0x4c,mode /* ctrl or caps */
|
||||
je 2f
|
||||
cmpb $'a,%al
|
||||
jb 2f
|
||||
cmpb $'},%al
|
||||
ja 2f
|
||||
subb $32,%al
|
||||
2: testb $0x0c,mode /* ctrl */
|
||||
je 3f
|
||||
cmpb $64,%al
|
||||
jb 3f
|
||||
cmpb $64+32,%al
|
||||
jae 3f
|
||||
subb $64,%al
|
||||
3: testb $0x10,mode /* left alt */
|
||||
je 4f
|
||||
orb $0x80,%al
|
||||
4: andl $0xff,%eax
|
||||
xorl %ebx,%ebx
|
||||
call put_queue
|
||||
none: ret
|
||||
|
||||
/*
|
||||
* minus has a routine of it's own, as a 'E0h' before
|
||||
* the scan code for minus means that the numeric keypad
|
||||
* slash was pushed.
|
||||
*/
|
||||
minus: cmpb $1,e0
|
||||
jne do_self
|
||||
movl $'/,%eax
|
||||
xorl %ebx,%ebx
|
||||
jmp put_queue
|
||||
|
||||
/*
|
||||
* This table decides which routine to call when a scan-code has been
|
||||
* gotten. Most routines just call do_self, or none, depending if
|
||||
* they are make or break.
|
||||
*/
|
||||
key_table:
|
||||
.long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */
|
||||
.long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */
|
||||
.long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */
|
||||
.long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */
|
||||
.long do_self,do_self,do_self,do_self /* 10-13 q w e r */
|
||||
.long do_self,do_self,do_self,do_self /* 14-17 t y u i */
|
||||
.long do_self,do_self,do_self,do_self /* 18-1B o p } ^ */
|
||||
.long do_self,ctrl,do_self,do_self /* 1C-1F enter ctrl a s */
|
||||
.long do_self,do_self,do_self,do_self /* 20-23 d f g h */
|
||||
.long do_self,do_self,do_self,do_self /* 24-27 j k l | */
|
||||
.long do_self,do_self,lshift,do_self /* 28-2B { para lshift , */
|
||||
.long do_self,do_self,do_self,do_self /* 2C-2F z x c v */
|
||||
.long do_self,do_self,do_self,do_self /* 30-33 b n m , */
|
||||
.long do_self,minus,rshift,do_self /* 34-37 . - rshift * */
|
||||
.long alt,do_self,caps,func /* 38-3B alt sp caps f1 */
|
||||
.long func,func,func,func /* 3C-3F f2 f3 f4 f5 */
|
||||
.long func,func,func,func /* 40-43 f6 f7 f8 f9 */
|
||||
.long func,num,scroll,cursor /* 44-47 f10 num scr home */
|
||||
.long cursor,cursor,do_self,cursor /* 48-4B up pgup - left */
|
||||
.long cursor,cursor,do_self,cursor /* 4C-4F n5 right + end */
|
||||
.long cursor,cursor,cursor,cursor /* 50-53 dn pgdn ins del */
|
||||
.long none,none,do_self,func /* 54-57 sysreq ? < f11 */
|
||||
.long func,none,none,none /* 58-5B f12 ? ? ? */
|
||||
.long none,none,none,none /* 5C-5F ? ? ? ? */
|
||||
.long none,none,none,none /* 60-63 ? ? ? ? */
|
||||
.long none,none,none,none /* 64-67 ? ? ? ? */
|
||||
.long none,none,none,none /* 68-6B ? ? ? ? */
|
||||
.long none,none,none,none /* 6C-6F ? ? ? ? */
|
||||
.long none,none,none,none /* 70-73 ? ? ? ? */
|
||||
.long none,none,none,none /* 74-77 ? ? ? ? */
|
||||
.long none,none,none,none /* 78-7B ? ? ? ? */
|
||||
.long none,none,none,none /* 7C-7F ? ? ? ? */
|
||||
.long none,none,none,none /* 80-83 ? br br br */
|
||||
.long none,none,none,none /* 84-87 br br br br */
|
||||
.long none,none,none,none /* 88-8B br br br br */
|
||||
.long none,none,none,none /* 8C-8F br br br br */
|
||||
.long none,none,none,none /* 90-93 br br br br */
|
||||
.long none,none,none,none /* 94-97 br br br br */
|
||||
.long none,none,none,none /* 98-9B br br br br */
|
||||
.long none,unctrl,none,none /* 9C-9F br unctrl br br */
|
||||
.long none,none,none,none /* A0-A3 br br br br */
|
||||
.long none,none,none,none /* A4-A7 br br br br */
|
||||
.long none,none,unlshift,none /* A8-AB br br unlshift br */
|
||||
.long none,none,none,none /* AC-AF br br br br */
|
||||
.long none,none,none,none /* B0-B3 br br br br */
|
||||
.long none,none,unrshift,none /* B4-B7 br br unrshift br */
|
||||
.long unalt,none,uncaps,none /* B8-BB unalt br uncaps br */
|
||||
.long none,none,none,none /* BC-BF br br br br */
|
||||
.long none,none,none,none /* C0-C3 br br br br */
|
||||
.long none,none,none,none /* C4-C7 br br br br */
|
||||
.long none,none,none,none /* C8-CB br br br br */
|
||||
.long none,none,none,none /* CC-CF br br br br */
|
||||
.long none,none,none,none /* D0-D3 br br br br */
|
||||
.long none,none,none,none /* D4-D7 br br br br */
|
||||
.long none,none,none,none /* D8-DB br ? ? ? */
|
||||
.long none,none,none,none /* DC-DF ? ? ? ? */
|
||||
.long none,none,none,none /* E0-E3 e0 e1 ? ? */
|
||||
.long none,none,none,none /* E4-E7 ? ? ? ? */
|
||||
.long none,none,none,none /* E8-EB ? ? ? ? */
|
||||
.long none,none,none,none /* EC-EF ? ? ? ? */
|
||||
.long none,none,none,none /* F0-F3 ? ? ? ? */
|
||||
.long none,none,none,none /* F4-F7 ? ? ? ? */
|
||||
.long none,none,none,none /* F8-FB ? ? ? ? */
|
||||
.long none,none,none,none /* FC-FF ? ? ? ? */
|
||||
|
||||
/*
|
||||
* kb_wait waits for the keyboard controller buffer to empty.
|
||||
* there is no timeout - if the buffer doesn't empty, we hang.
|
||||
*/
|
||||
kb_wait:
|
||||
pushl %eax
|
||||
1: inb $0x64,%al
|
||||
testb $0x02,%al
|
||||
jne 1b
|
||||
popl %eax
|
||||
ret
|
||||
/*
|
||||
* This routine reboots the machine by asking the keyboard
|
||||
* controller to pulse the reset-line low.
|
||||
*/
|
||||
reboot:
|
||||
call kb_wait
|
||||
movw $0x1234,0x472 /* don't do memory check */
|
||||
movb $0xfc,%al /* pulse reset and A20 low */
|
||||
outb %al,$0x64
|
||||
die: jmp die
|
||||
63
Book-Lite/linux-0.12/kernel/chr_drv/pty.c
Normal file
63
Book-Lite/linux-0.12/kernel/chr_drv/pty.c
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* linux/kernel/chr_drv/pty.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* pty.c
|
||||
*
|
||||
* This module implements the pty functions
|
||||
* void mpty_write(struct tty_struct * queue);
|
||||
* void spty_write(struct tty_struct * queue);
|
||||
*/
|
||||
|
||||
#include <linux/tty.h>
|
||||
#include <linux/sched.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
|
||||
{
|
||||
char c;
|
||||
|
||||
while (!from->stopped && !EMPTY(from->write_q)) {
|
||||
if (FULL(to->read_q)) {
|
||||
if (FULL(to->secondary))
|
||||
break;
|
||||
copy_to_cooked(to);
|
||||
continue;
|
||||
}
|
||||
GETCH(from->write_q,c);
|
||||
PUTCH(c,to->read_q);
|
||||
if (current->signal & ~current->blocked)
|
||||
break;
|
||||
}
|
||||
copy_to_cooked(to);
|
||||
wake_up(&from->write_q->proc_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine gets called when tty_write has put something into
|
||||
* the write_queue. It copies the input to the output-queue of it's
|
||||
* slave.
|
||||
*/
|
||||
void mpty_write(struct tty_struct * tty)
|
||||
{
|
||||
int nr = tty - tty_table;
|
||||
|
||||
if ((nr >> 6) != 2)
|
||||
printk("bad mpty\n\r");
|
||||
else
|
||||
pty_copy(tty,tty+64);
|
||||
}
|
||||
|
||||
void spty_write(struct tty_struct * tty)
|
||||
{
|
||||
int nr = tty - tty_table;
|
||||
|
||||
if ((nr >> 6) != 3)
|
||||
printk("bad spty\n\r");
|
||||
else
|
||||
pty_copy(tty,tty-64);
|
||||
}
|
||||
148
Book-Lite/linux-0.12/kernel/chr_drv/rs_io.s
Normal file
148
Book-Lite/linux-0.12/kernel/chr_drv/rs_io.s
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* linux/kernel/rs_io.s
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* rs_io.s
|
||||
*
|
||||
* This module implements the rs232 io interrupts.
|
||||
*/
|
||||
|
||||
.text
|
||||
.globl _rs1_interrupt,_rs2_interrupt
|
||||
|
||||
size = 1024 /* must be power of two !
|
||||
and must match the value
|
||||
in tty_io.c!!! */
|
||||
|
||||
/* these are the offsets into the read/write buffer structures */
|
||||
rs_addr = 0
|
||||
head = 4
|
||||
tail = 8
|
||||
proc_list = 12
|
||||
buf = 16
|
||||
|
||||
startup = 256 /* chars left in write queue when we restart it */
|
||||
|
||||
/*
|
||||
* These are the actual interrupt routines. They look where
|
||||
* the interrupt is coming from, and take appropriate action.
|
||||
*/
|
||||
.align 2
|
||||
_rs1_interrupt:
|
||||
pushl $_table_list+8
|
||||
jmp rs_int
|
||||
.align 2
|
||||
_rs2_interrupt:
|
||||
pushl $_table_list+16
|
||||
rs_int:
|
||||
pushl %edx
|
||||
pushl %ecx
|
||||
pushl %ebx
|
||||
pushl %eax
|
||||
push %es
|
||||
push %ds /* as this is an interrupt, we cannot */
|
||||
pushl $0x10 /* know that bs is ok. Load it */
|
||||
pop %ds
|
||||
pushl $0x10
|
||||
pop %es
|
||||
movl 24(%esp),%edx
|
||||
movl (%edx),%edx
|
||||
movl rs_addr(%edx),%edx
|
||||
addl $2,%edx /* interrupt ident. reg */
|
||||
rep_int:
|
||||
xorl %eax,%eax
|
||||
inb %dx,%al
|
||||
testb $1,%al
|
||||
jne end
|
||||
cmpb $6,%al /* this shouldn't happen, but ... */
|
||||
ja end
|
||||
movl 24(%esp),%ecx
|
||||
pushl %edx
|
||||
subl $2,%edx
|
||||
call jmp_table(,%eax,2) /* NOTE! not *4, bit0 is 0 already */
|
||||
popl %edx
|
||||
jmp rep_int
|
||||
end: movb $0x20,%al
|
||||
outb %al,$0x20 /* EOI */
|
||||
pop %ds
|
||||
pop %es
|
||||
popl %eax
|
||||
popl %ebx
|
||||
popl %ecx
|
||||
popl %edx
|
||||
addl $4,%esp # jump over _table_list entry
|
||||
iret
|
||||
|
||||
jmp_table:
|
||||
.long modem_status,write_char,read_char,line_status
|
||||
|
||||
.align 2
|
||||
modem_status:
|
||||
addl $6,%edx /* clear intr by reading modem status reg */
|
||||
inb %dx,%al
|
||||
ret
|
||||
|
||||
.align 2
|
||||
line_status:
|
||||
addl $5,%edx /* clear intr by reading line status reg. */
|
||||
inb %dx,%al
|
||||
ret
|
||||
|
||||
.align 2
|
||||
read_char:
|
||||
inb %dx,%al
|
||||
movl %ecx,%edx
|
||||
subl $_table_list,%edx
|
||||
shrl $3,%edx
|
||||
movl (%ecx),%ecx # read-queue
|
||||
movl head(%ecx),%ebx
|
||||
movb %al,buf(%ecx,%ebx)
|
||||
incl %ebx
|
||||
andl $size-1,%ebx
|
||||
cmpl tail(%ecx),%ebx
|
||||
je 1f
|
||||
movl %ebx,head(%ecx)
|
||||
1: addl $63,%edx
|
||||
pushl %edx
|
||||
call _do_tty_interrupt
|
||||
addl $4,%esp
|
||||
ret
|
||||
|
||||
.align 2
|
||||
write_char:
|
||||
movl 4(%ecx),%ecx # write-queue
|
||||
movl head(%ecx),%ebx
|
||||
subl tail(%ecx),%ebx
|
||||
andl $size-1,%ebx # nr chars in queue
|
||||
je write_buffer_empty
|
||||
cmpl $startup,%ebx
|
||||
ja 1f
|
||||
movl proc_list(%ecx),%ebx # wake up sleeping process
|
||||
testl %ebx,%ebx # is there any?
|
||||
je 1f
|
||||
movl $0,(%ebx)
|
||||
1: movl tail(%ecx),%ebx
|
||||
movb buf(%ecx,%ebx),%al
|
||||
outb %al,%dx
|
||||
incl %ebx
|
||||
andl $size-1,%ebx
|
||||
movl %ebx,tail(%ecx)
|
||||
cmpl head(%ecx),%ebx
|
||||
je write_buffer_empty
|
||||
ret
|
||||
.align 2
|
||||
write_buffer_empty:
|
||||
movl proc_list(%ecx),%ebx # wake up sleeping process
|
||||
testl %ebx,%ebx # is there any?
|
||||
je 1f
|
||||
movl $0,(%ebx)
|
||||
1: incl %edx
|
||||
inb %dx,%al
|
||||
jmp 1f
|
||||
1: jmp 1f
|
||||
1: andb $0xd,%al /* disable transmit interrupt */
|
||||
outb %al,%dx
|
||||
ret
|
||||
59
Book-Lite/linux-0.12/kernel/chr_drv/serial.c
Normal file
59
Book-Lite/linux-0.12/kernel/chr_drv/serial.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* linux/kernel/serial.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* serial.c
|
||||
*
|
||||
* This module implements the rs232 io functions
|
||||
* void rs_write(struct tty_struct * queue);
|
||||
* void rs_init(void);
|
||||
* and all interrupts pertaining to serial IO.
|
||||
*/
|
||||
|
||||
#include <linux/tty.h>
|
||||
#include <linux/sched.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define WAKEUP_CHARS (TTY_BUF_SIZE/4)
|
||||
|
||||
extern void rs1_interrupt(void);
|
||||
extern void rs2_interrupt(void);
|
||||
|
||||
static void init(int port)
|
||||
{
|
||||
outb_p(0x80,port+3); /* set DLAB of line control reg */
|
||||
outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */
|
||||
outb_p(0x00,port+1); /* MS of divisor */
|
||||
outb_p(0x03,port+3); /* reset DLAB */
|
||||
outb_p(0x0b,port+4); /* set DTR,RTS, OUT_2 */
|
||||
outb_p(0x0d,port+1); /* enable all intrs but writes */
|
||||
(void)inb(port); /* read data port to reset things (?) */
|
||||
}
|
||||
|
||||
void rs_init(void)
|
||||
{
|
||||
set_intr_gate(0x24,rs1_interrupt);
|
||||
set_intr_gate(0x23,rs2_interrupt);
|
||||
init(tty_table[64].read_q->data);
|
||||
init(tty_table[65].read_q->data);
|
||||
outb(inb_p(0x21)&0xE7,0x21);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine gets called when tty_write has put something into
|
||||
* the write_queue. It must check wheter the queue is empty, and
|
||||
* set the interrupt register accordingly
|
||||
*
|
||||
* void _rs_write(struct tty_struct * tty);
|
||||
*/
|
||||
void rs_write(struct tty_struct * tty)
|
||||
{
|
||||
cli();
|
||||
if (!EMPTY(tty->write_q))
|
||||
outb(inb_p(tty->write_q->data+1)|0x02,tty->write_q->data+1);
|
||||
sti();
|
||||
}
|
||||
484
Book-Lite/linux-0.12/kernel/chr_drv/tty_io.c
Normal file
484
Book-Lite/linux-0.12/kernel/chr_drv/tty_io.c
Normal file
@@ -0,0 +1,484 @@
|
||||
/*
|
||||
* linux/kernel/tty_io.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
|
||||
* or rs-channels. It also implements echoing, cooked mode etc.
|
||||
*
|
||||
* Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define ALRMMASK (1<<(SIGALRM-1))
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/tty.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
int kill_pg(int pgrp, int sig, int priv);
|
||||
int is_orphaned_pgrp(int pgrp);
|
||||
|
||||
#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f)
|
||||
#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f)
|
||||
#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f)
|
||||
|
||||
#define L_CANON(tty) _L_FLAG((tty),ICANON)
|
||||
#define L_ISIG(tty) _L_FLAG((tty),ISIG)
|
||||
#define L_ECHO(tty) _L_FLAG((tty),ECHO)
|
||||
#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
|
||||
#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
|
||||
#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
|
||||
#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
|
||||
#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
|
||||
|
||||
#define I_UCLC(tty) _I_FLAG((tty),IUCLC)
|
||||
#define I_NLCR(tty) _I_FLAG((tty),INLCR)
|
||||
#define I_CRNL(tty) _I_FLAG((tty),ICRNL)
|
||||
#define I_NOCR(tty) _I_FLAG((tty),IGNCR)
|
||||
#define I_IXON(tty) _I_FLAG((tty),IXON)
|
||||
|
||||
#define O_POST(tty) _O_FLAG((tty),OPOST)
|
||||
#define O_NLCR(tty) _O_FLAG((tty),ONLCR)
|
||||
#define O_CRNL(tty) _O_FLAG((tty),OCRNL)
|
||||
#define O_NLRET(tty) _O_FLAG((tty),ONLRET)
|
||||
#define O_LCUC(tty) _O_FLAG((tty),OLCUC)
|
||||
|
||||
#define C_SPEED(tty) ((tty)->termios.c_cflag & CBAUD)
|
||||
#define C_HUP(tty) (C_SPEED((tty)) == B0)
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define QUEUES (3*(MAX_CONSOLES+NR_SERIALS+2*NR_PTYS))
|
||||
static struct tty_queue tty_queues[QUEUES];
|
||||
struct tty_struct tty_table[256];
|
||||
|
||||
#define con_queues tty_queues
|
||||
#define rs_queues ((3*MAX_CONSOLES) + tty_queues)
|
||||
#define mpty_queues ((3*(MAX_CONSOLES+NR_SERIALS)) + tty_queues)
|
||||
#define spty_queues ((3*(MAX_CONSOLES+NR_SERIALS+NR_PTYS)) + tty_queues)
|
||||
|
||||
#define con_table tty_table
|
||||
#define rs_table (64+tty_table)
|
||||
#define mpty_table (128+tty_table)
|
||||
#define spty_table (192+tty_table)
|
||||
|
||||
int fg_console = 0;
|
||||
|
||||
/*
|
||||
* these are the tables used by the machine code handlers.
|
||||
* you can implement virtual consoles.
|
||||
*/
|
||||
struct tty_queue * table_list[]={
|
||||
con_queues + 0, con_queues + 1,
|
||||
rs_queues + 0, rs_queues + 1,
|
||||
rs_queues + 3, rs_queues + 4
|
||||
};
|
||||
|
||||
void change_console(unsigned int new_console)
|
||||
{
|
||||
if (new_console == fg_console || new_console >= NR_CONSOLES)
|
||||
return;
|
||||
fg_console = new_console;
|
||||
table_list[0] = con_queues + 0 + fg_console*3;
|
||||
table_list[1] = con_queues + 1 + fg_console*3;
|
||||
update_screen();
|
||||
}
|
||||
|
||||
static void sleep_if_empty(struct tty_queue * queue)
|
||||
{
|
||||
cli();
|
||||
while (!(current->signal & ~current->blocked) && EMPTY(queue))
|
||||
interruptible_sleep_on(&queue->proc_list);
|
||||
sti();
|
||||
}
|
||||
|
||||
static void sleep_if_full(struct tty_queue * queue)
|
||||
{
|
||||
if (!FULL(queue))
|
||||
return;
|
||||
cli();
|
||||
while (!(current->signal & ~current->blocked) && LEFT(queue)<128)
|
||||
interruptible_sleep_on(&queue->proc_list);
|
||||
sti();
|
||||
}
|
||||
|
||||
void wait_for_keypress(void)
|
||||
{
|
||||
sleep_if_empty(tty_table[fg_console].secondary);
|
||||
}
|
||||
|
||||
void copy_to_cooked(struct tty_struct * tty)
|
||||
{
|
||||
signed char c;
|
||||
|
||||
if (!(tty->read_q || tty->write_q || tty->secondary)) {
|
||||
printk("copy_to_cooked: missing queues\n\r");
|
||||
return;
|
||||
}
|
||||
while (1) {
|
||||
if (EMPTY(tty->read_q))
|
||||
break;
|
||||
if (FULL(tty->secondary))
|
||||
break;
|
||||
GETCH(tty->read_q,c);
|
||||
if (c==13) {
|
||||
if (I_CRNL(tty))
|
||||
c=10;
|
||||
else if (I_NOCR(tty))
|
||||
continue;
|
||||
} else if (c==10 && I_NLCR(tty))
|
||||
c=13;
|
||||
if (I_UCLC(tty))
|
||||
c=tolower(c);
|
||||
if (L_CANON(tty)) {
|
||||
if ((KILL_CHAR(tty) != _POSIX_VDISABLE) &&
|
||||
(c==KILL_CHAR(tty))) {
|
||||
/* deal with killing the input line */
|
||||
while(!(EMPTY(tty->secondary) ||
|
||||
(c=LAST(tty->secondary))==10 ||
|
||||
((EOF_CHAR(tty) != _POSIX_VDISABLE) &&
|
||||
(c==EOF_CHAR(tty))))) {
|
||||
if (L_ECHO(tty)) {
|
||||
if (c<32)
|
||||
PUTCH(127,tty->write_q);
|
||||
PUTCH(127,tty->write_q);
|
||||
tty->write(tty);
|
||||
}
|
||||
DEC(tty->secondary->head);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ((ERASE_CHAR(tty) != _POSIX_VDISABLE) &&
|
||||
(c==ERASE_CHAR(tty))) {
|
||||
if (EMPTY(tty->secondary) ||
|
||||
(c=LAST(tty->secondary))==10 ||
|
||||
((EOF_CHAR(tty) != _POSIX_VDISABLE) &&
|
||||
(c==EOF_CHAR(tty))))
|
||||
continue;
|
||||
if (L_ECHO(tty)) {
|
||||
if (c<32)
|
||||
PUTCH(127,tty->write_q);
|
||||
PUTCH(127,tty->write_q);
|
||||
tty->write(tty);
|
||||
}
|
||||
DEC(tty->secondary->head);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (I_IXON(tty)) {
|
||||
if ((STOP_CHAR(tty) != _POSIX_VDISABLE) &&
|
||||
(c==STOP_CHAR(tty))) {
|
||||
tty->stopped=1;
|
||||
tty->write(tty);
|
||||
continue;
|
||||
}
|
||||
if ((START_CHAR(tty) != _POSIX_VDISABLE) &&
|
||||
(c==START_CHAR(tty))) {
|
||||
tty->stopped=0;
|
||||
tty->write(tty);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (L_ISIG(tty)) {
|
||||
if ((INTR_CHAR(tty) != _POSIX_VDISABLE) &&
|
||||
(c==INTR_CHAR(tty))) {
|
||||
kill_pg(tty->pgrp, SIGINT, 1);
|
||||
continue;
|
||||
}
|
||||
if ((QUIT_CHAR(tty) != _POSIX_VDISABLE) &&
|
||||
(c==QUIT_CHAR(tty))) {
|
||||
kill_pg(tty->pgrp, SIGQUIT, 1);
|
||||
continue;
|
||||
}
|
||||
if ((SUSPEND_CHAR(tty) != _POSIX_VDISABLE) &&
|
||||
(c==SUSPEND_CHAR(tty))) {
|
||||
if (!is_orphaned_pgrp(tty->pgrp))
|
||||
kill_pg(tty->pgrp, SIGTSTP, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (c==10 || (EOF_CHAR(tty) != _POSIX_VDISABLE &&
|
||||
c==EOF_CHAR(tty)))
|
||||
tty->secondary->data++;
|
||||
if (L_ECHO(tty)) {
|
||||
if (c==10) {
|
||||
PUTCH(10,tty->write_q);
|
||||
PUTCH(13,tty->write_q);
|
||||
} else if (c<32) {
|
||||
if (L_ECHOCTL(tty)) {
|
||||
PUTCH('^',tty->write_q);
|
||||
PUTCH(c+64,tty->write_q);
|
||||
}
|
||||
} else
|
||||
PUTCH(c,tty->write_q);
|
||||
tty->write(tty);
|
||||
}
|
||||
PUTCH(c,tty->secondary);
|
||||
}
|
||||
wake_up(&tty->secondary->proc_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when we need to send a SIGTTIN or SIGTTOU to our process
|
||||
* group
|
||||
*
|
||||
* We only request that a system call be restarted if there was if the
|
||||
* default signal handler is being used. The reason for this is that if
|
||||
* a job is catching SIGTTIN or SIGTTOU, the signal handler may not want
|
||||
* the system call to be restarted blindly. If there is no way to reset the
|
||||
* terminal pgrp back to the current pgrp (perhaps because the controlling
|
||||
* tty has been released on logout), we don't want to be in an infinite loop
|
||||
* while restarting the system call, and have it always generate a SIGTTIN
|
||||
* or SIGTTOU. The default signal handler will cause the process to stop
|
||||
* thus avoiding the infinite loop problem. Presumably the job-control
|
||||
* cognizant parent will fix things up before continuging its child process.
|
||||
*/
|
||||
int tty_signal(int sig, struct tty_struct *tty)
|
||||
{
|
||||
if (is_orphaned_pgrp(current->pgrp))
|
||||
return -EIO; /* don't stop an orphaned pgrp */
|
||||
(void) kill_pg(current->pgrp,sig,1);
|
||||
if ((current->blocked & (1<<(sig-1))) ||
|
||||
((int) current->sigaction[sig-1].sa_handler == 1))
|
||||
return -EIO; /* Our signal will be ignored */
|
||||
else if (current->sigaction[sig-1].sa_handler)
|
||||
return -EINTR; /* We _will_ be interrupted :-) */
|
||||
else
|
||||
return -ERESTARTSYS; /* We _will_ be interrupted :-) */
|
||||
/* (but restart after we continue) */
|
||||
}
|
||||
|
||||
int tty_read(unsigned channel, char * buf, int nr)
|
||||
{
|
||||
struct tty_struct * tty;
|
||||
struct tty_struct * other_tty = NULL;
|
||||
char c, * b=buf;
|
||||
int minimum,time;
|
||||
|
||||
if (channel > 255)
|
||||
return -EIO;
|
||||
tty = TTY_TABLE(channel);
|
||||
if (!(tty->write_q || tty->read_q || tty->secondary))
|
||||
return -EIO;
|
||||
if ((current->tty == channel) && (tty->pgrp != current->pgrp))
|
||||
return(tty_signal(SIGTTIN, tty));
|
||||
if (channel & 0x80)
|
||||
other_tty = tty_table + (channel ^ 0x40);
|
||||
time = 10L*tty->termios.c_cc[VTIME];
|
||||
minimum = tty->termios.c_cc[VMIN];
|
||||
if (L_CANON(tty)) {
|
||||
minimum = nr;
|
||||
current->timeout = 0xffffffff;
|
||||
time = 0;
|
||||
} else if (minimum)
|
||||
current->timeout = 0xffffffff;
|
||||
else {
|
||||
minimum = nr;
|
||||
if (time)
|
||||
current->timeout = time + jiffies;
|
||||
time = 0;
|
||||
}
|
||||
if (minimum>nr)
|
||||
minimum = nr;
|
||||
while (nr>0) {
|
||||
if (other_tty)
|
||||
other_tty->write(other_tty);
|
||||
cli();
|
||||
if (EMPTY(tty->secondary) || (L_CANON(tty) &&
|
||||
!FULL(tty->read_q) && !tty->secondary->data)) {
|
||||
if (!current->timeout ||
|
||||
(current->signal & ~current->blocked)) {
|
||||
sti();
|
||||
break;
|
||||
}
|
||||
if (IS_A_PTY_SLAVE(channel) && C_HUP(other_tty))
|
||||
break;
|
||||
interruptible_sleep_on(&tty->secondary->proc_list);
|
||||
sti();
|
||||
continue;
|
||||
}
|
||||
sti();
|
||||
do {
|
||||
GETCH(tty->secondary,c);
|
||||
if ((EOF_CHAR(tty) != _POSIX_VDISABLE &&
|
||||
c==EOF_CHAR(tty)) || c==10)
|
||||
tty->secondary->data--;
|
||||
if ((EOF_CHAR(tty) != _POSIX_VDISABLE &&
|
||||
c==EOF_CHAR(tty)) && L_CANON(tty))
|
||||
break;
|
||||
else {
|
||||
put_fs_byte(c,b++);
|
||||
if (!--nr)
|
||||
break;
|
||||
}
|
||||
if (c==10 && L_CANON(tty))
|
||||
break;
|
||||
} while (nr>0 && !EMPTY(tty->secondary));
|
||||
wake_up(&tty->read_q->proc_list);
|
||||
if (time)
|
||||
current->timeout = time+jiffies;
|
||||
if (L_CANON(tty) || b-buf >= minimum)
|
||||
break;
|
||||
}
|
||||
current->timeout = 0;
|
||||
if ((current->signal & ~current->blocked) && !(b-buf))
|
||||
return -ERESTARTSYS;
|
||||
return (b-buf);
|
||||
}
|
||||
|
||||
int tty_write(unsigned channel, char * buf, int nr)
|
||||
{
|
||||
static cr_flag=0;
|
||||
struct tty_struct * tty;
|
||||
char c, *b=buf;
|
||||
|
||||
if (channel > 255)
|
||||
return -EIO;
|
||||
tty = TTY_TABLE(channel);
|
||||
if (!(tty->write_q || tty->read_q || tty->secondary))
|
||||
return -EIO;
|
||||
if (L_TOSTOP(tty) &&
|
||||
(current->tty == channel) && (tty->pgrp != current->pgrp))
|
||||
return(tty_signal(SIGTTOU, tty));
|
||||
while (nr>0) {
|
||||
sleep_if_full(tty->write_q);
|
||||
if (current->signal & ~current->blocked)
|
||||
break;
|
||||
while (nr>0 && !FULL(tty->write_q)) {
|
||||
c=get_fs_byte(b);
|
||||
if (O_POST(tty)) {
|
||||
if (c=='\r' && O_CRNL(tty))
|
||||
c='\n';
|
||||
else if (c=='\n' && O_NLRET(tty))
|
||||
c='\r';
|
||||
if (c=='\n' && !cr_flag && O_NLCR(tty)) {
|
||||
cr_flag = 1;
|
||||
PUTCH(13,tty->write_q);
|
||||
continue;
|
||||
}
|
||||
if (O_LCUC(tty))
|
||||
c=toupper(c);
|
||||
}
|
||||
b++; nr--;
|
||||
cr_flag = 0;
|
||||
PUTCH(c,tty->write_q);
|
||||
}
|
||||
tty->write(tty);
|
||||
if (nr>0)
|
||||
schedule();
|
||||
}
|
||||
return (b-buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Jeh, sometimes I really like the 386.
|
||||
* This routine is called from an interrupt,
|
||||
* and there should be absolutely no problem
|
||||
* with sleeping even in an interrupt (I hope).
|
||||
* Of course, if somebody proves me wrong, I'll
|
||||
* hate intel for all time :-). We'll have to
|
||||
* be careful and see to reinstating the interrupt
|
||||
* chips before calling this, though.
|
||||
*
|
||||
* I don't think we sleep here under normal circumstances
|
||||
* anyway, which is good, as the task sleeping might be
|
||||
* totally innocent.
|
||||
*/
|
||||
void do_tty_interrupt(int tty)
|
||||
{
|
||||
copy_to_cooked(TTY_TABLE(tty));
|
||||
}
|
||||
|
||||
void chr_dev_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void tty_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i < QUEUES ; i++)
|
||||
tty_queues[i] = (struct tty_queue) {0,0,0,0,""};
|
||||
rs_queues[0] = (struct tty_queue) {0x3f8,0,0,0,""};
|
||||
rs_queues[1] = (struct tty_queue) {0x3f8,0,0,0,""};
|
||||
rs_queues[3] = (struct tty_queue) {0x2f8,0,0,0,""};
|
||||
rs_queues[4] = (struct tty_queue) {0x2f8,0,0,0,""};
|
||||
for (i=0 ; i<256 ; i++) {
|
||||
tty_table[i] = (struct tty_struct) {
|
||||
{0, 0, 0, 0, 0, INIT_C_CC},
|
||||
0, 0, 0, NULL, NULL, NULL, NULL
|
||||
};
|
||||
}
|
||||
con_init();
|
||||
for (i = 0 ; i<NR_CONSOLES ; i++) {
|
||||
con_table[i] = (struct tty_struct) {
|
||||
{ICRNL, /* change incoming CR to NL */
|
||||
OPOST|ONLCR, /* change outgoing NL to CRNL */
|
||||
0,
|
||||
IXON | ISIG | ICANON | ECHO | ECHOCTL | ECHOKE,
|
||||
0, /* console termio */
|
||||
INIT_C_CC},
|
||||
0, /* initial pgrp */
|
||||
0, /* initial session */
|
||||
0, /* initial stopped */
|
||||
con_write,
|
||||
con_queues+0+i*3,con_queues+1+i*3,con_queues+2+i*3
|
||||
};
|
||||
}
|
||||
for (i = 0 ; i<NR_SERIALS ; i++) {
|
||||
rs_table[i] = (struct tty_struct) {
|
||||
{0, /* no translation */
|
||||
0, /* no translation */
|
||||
B2400 | CS8,
|
||||
0,
|
||||
0,
|
||||
INIT_C_CC},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
rs_write,
|
||||
rs_queues+0+i*3,rs_queues+1+i*3,rs_queues+2+i*3
|
||||
};
|
||||
}
|
||||
for (i = 0 ; i<NR_PTYS ; i++) {
|
||||
mpty_table[i] = (struct tty_struct) {
|
||||
{0, /* no translation */
|
||||
0, /* no translation */
|
||||
B9600 | CS8,
|
||||
0,
|
||||
0,
|
||||
INIT_C_CC},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
mpty_write,
|
||||
mpty_queues+0+i*3,mpty_queues+1+i*3,mpty_queues+2+i*3
|
||||
};
|
||||
spty_table[i] = (struct tty_struct) {
|
||||
{0, /* no translation */
|
||||
0, /* no translation */
|
||||
B9600 | CS8,
|
||||
IXON | ISIG | ICANON,
|
||||
0,
|
||||
INIT_C_CC},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
spty_write,
|
||||
spty_queues+0+i*3,spty_queues+1+i*3,spty_queues+2+i*3
|
||||
};
|
||||
}
|
||||
rs_init();
|
||||
printk("%d virtual consoles\n\r",NR_CONSOLES);
|
||||
printk("%d pty's\n\r",NR_PTYS);
|
||||
}
|
||||
251
Book-Lite/linux-0.12/kernel/chr_drv/tty_ioctl.c
Normal file
251
Book-Lite/linux-0.12/kernel/chr_drv/tty_ioctl.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* linux/kernel/chr_drv/tty_ioctl.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/tty.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
extern int session_of_pgrp(int pgrp);
|
||||
extern int tty_signal(int sig, struct tty_struct *tty);
|
||||
|
||||
static unsigned short quotient[] = {
|
||||
0, 2304, 1536, 1047, 857,
|
||||
768, 576, 384, 192, 96,
|
||||
64, 48, 24, 12, 6, 3
|
||||
};
|
||||
|
||||
static void change_speed(struct tty_struct * tty)
|
||||
{
|
||||
unsigned short port,quot;
|
||||
|
||||
if (!(port = tty->read_q->data))
|
||||
return;
|
||||
quot = quotient[tty->termios.c_cflag & CBAUD];
|
||||
cli();
|
||||
outb_p(0x80,port+3); /* set DLAB */
|
||||
outb_p(quot & 0xff,port); /* LS of divisor */
|
||||
outb_p(quot >> 8,port+1); /* MS of divisor */
|
||||
outb(0x03,port+3); /* reset DLAB */
|
||||
sti();
|
||||
}
|
||||
|
||||
static void flush(struct tty_queue * queue)
|
||||
{
|
||||
cli();
|
||||
queue->head = queue->tail;
|
||||
sti();
|
||||
}
|
||||
|
||||
static void wait_until_sent(struct tty_struct * tty)
|
||||
{
|
||||
/* do nothing - not implemented */
|
||||
}
|
||||
|
||||
static void send_break(struct tty_struct * tty)
|
||||
{
|
||||
/* do nothing - not implemented */
|
||||
}
|
||||
|
||||
static int get_termios(struct tty_struct * tty, struct termios * termios)
|
||||
{
|
||||
int i;
|
||||
|
||||
verify_area(termios, sizeof (*termios));
|
||||
for (i=0 ; i< (sizeof (*termios)) ; i++)
|
||||
put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_termios(struct tty_struct * tty, struct termios * termios,
|
||||
int channel)
|
||||
{
|
||||
int i, retsig;
|
||||
|
||||
/* If we try to set the state of terminal and we're not in the
|
||||
foreground, send a SIGTTOU. If the signal is blocked or
|
||||
ignored, go ahead and perform the operation. POSIX 7.2) */
|
||||
if ((current->tty == channel) && (tty->pgrp != current->pgrp)) {
|
||||
retsig = tty_signal(SIGTTOU, tty);
|
||||
if (retsig == -ERESTARTSYS || retsig == -EINTR)
|
||||
return retsig;
|
||||
}
|
||||
for (i=0 ; i< (sizeof (*termios)) ; i++)
|
||||
((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
|
||||
change_speed(tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_termio(struct tty_struct * tty, struct termio * termio)
|
||||
{
|
||||
int i;
|
||||
struct termio tmp_termio;
|
||||
|
||||
verify_area(termio, sizeof (*termio));
|
||||
tmp_termio.c_iflag = tty->termios.c_iflag;
|
||||
tmp_termio.c_oflag = tty->termios.c_oflag;
|
||||
tmp_termio.c_cflag = tty->termios.c_cflag;
|
||||
tmp_termio.c_lflag = tty->termios.c_lflag;
|
||||
tmp_termio.c_line = tty->termios.c_line;
|
||||
for(i=0 ; i < NCC ; i++)
|
||||
tmp_termio.c_cc[i] = tty->termios.c_cc[i];
|
||||
for (i=0 ; i< (sizeof (*termio)) ; i++)
|
||||
put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This only works as the 386 is low-byt-first
|
||||
*/
|
||||
static int set_termio(struct tty_struct * tty, struct termio * termio,
|
||||
int channel)
|
||||
{
|
||||
int i, retsig;
|
||||
struct termio tmp_termio;
|
||||
|
||||
if ((current->tty == channel) && (tty->pgrp != current->pgrp)) {
|
||||
retsig = tty_signal(SIGTTOU, tty);
|
||||
if (retsig == -ERESTARTSYS || retsig == -EINTR)
|
||||
return retsig;
|
||||
}
|
||||
for (i=0 ; i< (sizeof (*termio)) ; i++)
|
||||
((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
|
||||
*(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag;
|
||||
*(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag;
|
||||
*(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag;
|
||||
*(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag;
|
||||
tty->termios.c_line = tmp_termio.c_line;
|
||||
for(i=0 ; i < NCC ; i++)
|
||||
tty->termios.c_cc[i] = tmp_termio.c_cc[i];
|
||||
change_speed(tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tty_ioctl(int dev, int cmd, int arg)
|
||||
{
|
||||
struct tty_struct * tty;
|
||||
int pgrp;
|
||||
|
||||
if (MAJOR(dev) == 5) {
|
||||
dev=current->tty;
|
||||
if (dev<0)
|
||||
panic("tty_ioctl: dev<0");
|
||||
} else
|
||||
dev=MINOR(dev);
|
||||
tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console);
|
||||
switch (cmd) {
|
||||
case TCGETS:
|
||||
return get_termios(tty,(struct termios *) arg);
|
||||
case TCSETSF:
|
||||
flush(tty->read_q); /* fallthrough */
|
||||
case TCSETSW:
|
||||
wait_until_sent(tty); /* fallthrough */
|
||||
case TCSETS:
|
||||
return set_termios(tty,(struct termios *) arg, dev);
|
||||
case TCGETA:
|
||||
return get_termio(tty,(struct termio *) arg);
|
||||
case TCSETAF:
|
||||
flush(tty->read_q); /* fallthrough */
|
||||
case TCSETAW:
|
||||
wait_until_sent(tty); /* fallthrough */
|
||||
case TCSETA:
|
||||
return set_termio(tty,(struct termio *) arg, dev);
|
||||
case TCSBRK:
|
||||
if (!arg) {
|
||||
wait_until_sent(tty);
|
||||
send_break(tty);
|
||||
}
|
||||
return 0;
|
||||
case TCXONC:
|
||||
switch (arg) {
|
||||
case TCOOFF:
|
||||
tty->stopped = 1;
|
||||
tty->write(tty);
|
||||
return 0;
|
||||
case TCOON:
|
||||
tty->stopped = 0;
|
||||
tty->write(tty);
|
||||
return 0;
|
||||
case TCIOFF:
|
||||
if (STOP_CHAR(tty))
|
||||
PUTCH(STOP_CHAR(tty),tty->write_q);
|
||||
return 0;
|
||||
case TCION:
|
||||
if (START_CHAR(tty))
|
||||
PUTCH(START_CHAR(tty),tty->write_q);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL; /* not implemented */
|
||||
case TCFLSH:
|
||||
if (arg==0)
|
||||
flush(tty->read_q);
|
||||
else if (arg==1)
|
||||
flush(tty->write_q);
|
||||
else if (arg==2) {
|
||||
flush(tty->read_q);
|
||||
flush(tty->write_q);
|
||||
} else
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
case TIOCEXCL:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCNXCL:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCSCTTY:
|
||||
return -EINVAL; /* set controlling term NI */
|
||||
case TIOCGPGRP:
|
||||
verify_area((void *) arg,4);
|
||||
put_fs_long(tty->pgrp,(unsigned long *) arg);
|
||||
return 0;
|
||||
case TIOCSPGRP:
|
||||
if ((current->tty < 0) ||
|
||||
(current->tty != dev) ||
|
||||
(tty->session != current->session))
|
||||
return -ENOTTY;
|
||||
pgrp=get_fs_long((unsigned long *) arg);
|
||||
if (pgrp < 0)
|
||||
return -EINVAL;
|
||||
if (session_of_pgrp(pgrp) != current->session)
|
||||
return -EPERM;
|
||||
tty->pgrp = pgrp;
|
||||
return 0;
|
||||
case TIOCOUTQ:
|
||||
verify_area((void *) arg,4);
|
||||
put_fs_long(CHARS(tty->write_q),(unsigned long *) arg);
|
||||
return 0;
|
||||
case TIOCINQ:
|
||||
verify_area((void *) arg,4);
|
||||
put_fs_long(CHARS(tty->secondary),
|
||||
(unsigned long *) arg);
|
||||
return 0;
|
||||
case TIOCSTI:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCGWINSZ:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCSWINSZ:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCMGET:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCMBIS:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCMBIC:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCMSET:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCGSOFTCAR:
|
||||
return -EINVAL; /* not implemented */
|
||||
case TIOCSSOFTCAR:
|
||||
return -EINVAL; /* not implemented */
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
430
Book-Lite/linux-0.12/kernel/exit.c
Normal file
430
Book-Lite/linux-0.12/kernel/exit.c
Normal file
@@ -0,0 +1,430 @@
|
||||
/*
|
||||
* linux/kernel/exit.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
#define DEBUG_PROC_TREE
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/tty.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
int sys_pause(void);
|
||||
int sys_close(int fd);
|
||||
|
||||
void release(struct task_struct * p)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!p)
|
||||
return;
|
||||
if (p == current) {
|
||||
printk("task releasing itself\n\r");
|
||||
return;
|
||||
}
|
||||
for (i=1 ; i<NR_TASKS ; i++)
|
||||
if (task[i]==p) {
|
||||
task[i]=NULL;
|
||||
/* Update links */
|
||||
if (p->p_osptr)
|
||||
p->p_osptr->p_ysptr = p->p_ysptr;
|
||||
if (p->p_ysptr)
|
||||
p->p_ysptr->p_osptr = p->p_osptr;
|
||||
else
|
||||
p->p_pptr->p_cptr = p->p_osptr;
|
||||
free_page((long)p);
|
||||
schedule();
|
||||
return;
|
||||
}
|
||||
panic("trying to release non-existent task");
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PROC_TREE
|
||||
/*
|
||||
* Check to see if a task_struct pointer is present in the task[] array
|
||||
* Return 0 if found, and 1 if not found.
|
||||
*/
|
||||
int bad_task_ptr(struct task_struct *p)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!p)
|
||||
return 0;
|
||||
for (i=0 ; i<NR_TASKS ; i++)
|
||||
if (task[i] == p)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine scans the pid tree and make sure the rep invarient still
|
||||
* holds. Used for debugging only, since it's very slow....
|
||||
*
|
||||
* It looks a lot scarier than it really is.... we're doing <20>nothing more
|
||||
* than verifying the doubly-linked list found<6E>in p_ysptr and p_osptr,
|
||||
* and checking it corresponds with the process tree defined by p_cptr and
|
||||
* p_pptr;
|
||||
*/
|
||||
void audit_ptree()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=1 ; i<NR_TASKS ; i++) {
|
||||
if (!task[i])
|
||||
continue;
|
||||
if (bad_task_ptr(task[i]->p_pptr))
|
||||
printk("Warning, pid %d's parent link is bad\n",
|
||||
task[i]->pid);
|
||||
if (bad_task_ptr(task[i]->p_cptr))
|
||||
printk("Warning, pid %d's child link is bad\n",
|
||||
task[i]->pid);
|
||||
if (bad_task_ptr(task[i]->p_ysptr))
|
||||
printk("Warning, pid %d's ys link is bad\n",
|
||||
task[i]->pid);
|
||||
if (bad_task_ptr(task[i]->p_osptr))
|
||||
printk("Warning, pid %d's os link is bad\n",
|
||||
task[i]->pid);
|
||||
if (task[i]->p_pptr == task[i])
|
||||
printk("Warning, pid %d parent link points to self\n");
|
||||
if (task[i]->p_cptr == task[i])
|
||||
printk("Warning, pid %d child link points to self\n");
|
||||
if (task[i]->p_ysptr == task[i])
|
||||
printk("Warning, pid %d ys link points to self\n");
|
||||
if (task[i]->p_osptr == task[i])
|
||||
printk("Warning, pid %d os link points to self\n");
|
||||
if (task[i]->p_osptr) {
|
||||
if (task[i]->p_pptr != task[i]->p_osptr->p_pptr)
|
||||
printk(
|
||||
"Warning, pid %d older sibling %d parent is %d\n",
|
||||
task[i]->pid, task[i]->p_osptr->pid,
|
||||
task[i]->p_osptr->p_pptr->pid);
|
||||
if (task[i]->p_osptr->p_ysptr != task[i])
|
||||
printk(
|
||||
"Warning, pid %d older sibling %d has mismatched ys link\n",
|
||||
task[i]->pid, task[i]->p_osptr->pid);
|
||||
}
|
||||
if (task[i]->p_ysptr) {
|
||||
if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr)
|
||||
printk(
|
||||
"Warning, pid %d younger sibling %d parent is %d\n",
|
||||
task[i]->pid, task[i]->p_osptr->pid,
|
||||
task[i]->p_osptr->p_pptr->pid);
|
||||
if (task[i]->p_ysptr->p_osptr != task[i])
|
||||
printk(
|
||||
"Warning, pid %d younger sibling %d has mismatched os link\n",
|
||||
task[i]->pid, task[i]->p_ysptr->pid);
|
||||
}
|
||||
if (task[i]->p_cptr) {
|
||||
if (task[i]->p_cptr->p_pptr != task[i])
|
||||
printk(
|
||||
"Warning, pid %d youngest child %d has mismatched parent link\n",
|
||||
task[i]->pid, task[i]->p_cptr->pid);
|
||||
if (task[i]->p_cptr->p_ysptr)
|
||||
printk(
|
||||
"Warning, pid %d youngest child %d has non-NULL ys link\n",
|
||||
task[i]->pid, task[i]->p_cptr->pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG_PROC_TREE */
|
||||
|
||||
static inline int send_sig(long sig,struct task_struct * p,int priv)
|
||||
{
|
||||
if (!p)
|
||||
return -EINVAL;
|
||||
if (!priv && (current->euid!=p->euid) && !suser())
|
||||
return -EPERM;
|
||||
if ((sig == SIGKILL) || (sig == SIGCONT)) {
|
||||
if (p->state == TASK_STOPPED)
|
||||
p->state = TASK_RUNNING;
|
||||
p->exit_code = 0;
|
||||
p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
|
||||
(1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
|
||||
}
|
||||
/* If the signal will be ignored, don't even post it */
|
||||
if ((int) p->sigaction[sig-1].sa_handler == 1)
|
||||
return 0;
|
||||
/* Depends on order SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU */
|
||||
if ((sig >= SIGSTOP) && (sig <= SIGTTOU))
|
||||
p->signal &= ~(1<<(SIGCONT-1));
|
||||
/* Actually deliver the signal */
|
||||
p->signal |= (1<<(sig-1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int session_of_pgrp(int pgrp)
|
||||
{
|
||||
struct task_struct **p;
|
||||
|
||||
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
|
||||
if ((*p)->pgrp == pgrp)
|
||||
return((*p)->session);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int kill_pg(int pgrp, int sig, int priv)
|
||||
{
|
||||
struct task_struct **p;
|
||||
int err,retval = -ESRCH;
|
||||
int found = 0;
|
||||
|
||||
if (sig<1 || sig>32 || pgrp<=0)
|
||||
return -EINVAL;
|
||||
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
|
||||
if ((*p)->pgrp == pgrp) {
|
||||
if (sig && (err = send_sig(sig,*p,priv)))
|
||||
retval = err;
|
||||
else
|
||||
found++;
|
||||
}
|
||||
return(found ? 0 : retval);
|
||||
}
|
||||
|
||||
int kill_proc(int pid, int sig, int priv)
|
||||
{
|
||||
struct task_struct **p;
|
||||
|
||||
if (sig<1 || sig>32)
|
||||
return -EINVAL;
|
||||
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
|
||||
if ((*p)->pid == pid)
|
||||
return(sig ? send_sig(sig,*p,priv) : 0);
|
||||
return(-ESRCH);
|
||||
}
|
||||
|
||||
/*
|
||||
* POSIX specifies that kill(-1,sig) is unspecified, but what we have
|
||||
* is probably wrong. Should make it like BSD or SYSV.
|
||||
*/
|
||||
int sys_kill(int pid,int sig)
|
||||
{
|
||||
struct task_struct **p = NR_TASKS + task;
|
||||
int err, retval = 0;
|
||||
|
||||
if (!pid)
|
||||
return(kill_pg(current->pid,sig,0));
|
||||
if (pid == -1) {
|
||||
while (--p > &FIRST_TASK)
|
||||
if (err = send_sig(sig,*p,0))
|
||||
retval = err;
|
||||
return(retval);
|
||||
}
|
||||
if (pid < 0)
|
||||
return(kill_pg(-pid,sig,0));
|
||||
/* Normal kill */
|
||||
return(kill_proc(pid,sig,0));
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if a process group is "orphaned", according to the POSIX
|
||||
* definition in 2.2.2.52. Orphaned process groups are not to be affected
|
||||
* by terminal-generated stop signals. Newly orphaned process groups are
|
||||
* to receive a SIGHUP and a SIGCONT.
|
||||
*
|
||||
* "I ask you, have you ever known what it is to be an orphan?"
|
||||
*/
|
||||
int is_orphaned_pgrp(int pgrp)
|
||||
{
|
||||
struct task_struct **p;
|
||||
|
||||
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
|
||||
if (!(*p) ||
|
||||
((*p)->pgrp != pgrp) ||
|
||||
((*p)->state == TASK_ZOMBIE) ||
|
||||
((*p)->p_pptr->pid == 1))
|
||||
continue;
|
||||
if (((*p)->p_pptr->pgrp != pgrp) &&
|
||||
((*p)->p_pptr->session == (*p)->session))
|
||||
return 0;
|
||||
}
|
||||
return(1); /* (sighing) "Often!" */
|
||||
}
|
||||
|
||||
static int has_stopped_jobs(int pgrp)
|
||||
{
|
||||
struct task_struct ** p;
|
||||
|
||||
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
|
||||
if ((*p)->pgrp != pgrp)
|
||||
continue;
|
||||
if ((*p)->state == TASK_STOPPED)
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
volatile void do_exit(long code)
|
||||
{
|
||||
struct task_struct *p;
|
||||
int i;
|
||||
|
||||
free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
|
||||
free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
|
||||
for (i=0 ; i<NR_OPEN ; i++)
|
||||
if (current->filp[i])
|
||||
sys_close(i);
|
||||
iput(current->pwd);
|
||||
current->pwd = NULL;
|
||||
iput(current->root);
|
||||
current->root = NULL;
|
||||
iput(current->executable);
|
||||
current->executable = NULL;
|
||||
iput(current->library);
|
||||
current->library = NULL;
|
||||
current->state = TASK_ZOMBIE;
|
||||
current->exit_code = code;
|
||||
/*
|
||||
* Check to see if any process groups have become orphaned
|
||||
* as a result of our exiting, and if they have any stopped
|
||||
* jobs, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2)
|
||||
*
|
||||
* Case i: Our father is in a different pgrp than we are
|
||||
* and we were the only connection outside, so our pgrp
|
||||
* is about to become orphaned.
|
||||
*/
|
||||
if ((current->p_pptr->pgrp != current->pgrp) &&
|
||||
(current->p_pptr->session == current->session) &&
|
||||
is_orphaned_pgrp(current->pgrp) &&
|
||||
has_stopped_jobs(current->pgrp)) {
|
||||
kill_pg(current->pgrp,SIGHUP,1);
|
||||
kill_pg(current->pgrp,SIGCONT,1);
|
||||
}
|
||||
/* Let father know we died */
|
||||
current->p_pptr->signal |= (1<<(SIGCHLD-1));
|
||||
|
||||
/*
|
||||
* This loop does two things:
|
||||
*
|
||||
* A. Make init inherit all the child processes
|
||||
* B. Check to see if any process groups have become orphaned
|
||||
* as a result of our exiting, and if they have any stopped
|
||||
* jons, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2)
|
||||
*/
|
||||
if (p = current->p_cptr) {
|
||||
while (1) {
|
||||
p->p_pptr = task[1];
|
||||
if (p->state == TASK_ZOMBIE)
|
||||
task[1]->signal |= (1<<(SIGCHLD-1));
|
||||
/*
|
||||
* process group orphan check
|
||||
* Case ii: Our child is in a different pgrp
|
||||
* than we are, and it was the only connection
|
||||
* outside, so the child pgrp is now orphaned.
|
||||
*/
|
||||
if ((p->pgrp != current->pgrp) &&
|
||||
(p->session == current->session) &&
|
||||
is_orphaned_pgrp(p->pgrp) &&
|
||||
has_stopped_jobs(p->pgrp)) {
|
||||
kill_pg(p->pgrp,SIGHUP,1);
|
||||
kill_pg(p->pgrp,SIGCONT,1);
|
||||
}
|
||||
if (p->p_osptr) {
|
||||
p = p->p_osptr;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* This is it; link everything into init's children
|
||||
* and leave
|
||||
*/
|
||||
p->p_osptr = task[1]->p_cptr;
|
||||
task[1]->p_cptr->p_ysptr = p;
|
||||
task[1]->p_cptr = current->p_cptr;
|
||||
current->p_cptr = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (current->leader) {
|
||||
struct task_struct **p;
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (current->tty >= 0) {
|
||||
tty = TTY_TABLE(current->tty);
|
||||
if (tty->pgrp>0)
|
||||
kill_pg(tty->pgrp, SIGHUP, 1);
|
||||
tty->pgrp = 0;
|
||||
tty->session = 0;
|
||||
}
|
||||
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
|
||||
if ((*p)->session == current->session)
|
||||
(*p)->tty = -1;
|
||||
}
|
||||
if (last_task_used_math == current)
|
||||
last_task_used_math = NULL;
|
||||
#ifdef DEBUG_PROC_TREE
|
||||
audit_ptree();
|
||||
#endif
|
||||
schedule();
|
||||
}
|
||||
|
||||
int sys_exit(int error_code)
|
||||
{
|
||||
do_exit((error_code&0xff)<<8);
|
||||
}
|
||||
|
||||
int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
|
||||
{
|
||||
int flag;
|
||||
struct task_struct *p;
|
||||
unsigned long oldblocked;
|
||||
|
||||
verify_area(stat_addr,4);
|
||||
repeat:
|
||||
flag=0;
|
||||
for (p = current->p_cptr ; p ; p = p->p_osptr) {
|
||||
if (pid>0) {
|
||||
if (p->pid != pid)
|
||||
continue;
|
||||
} else if (!pid) {
|
||||
if (p->pgrp != current->pgrp)
|
||||
continue;
|
||||
} else if (pid != -1) {
|
||||
if (p->pgrp != -pid)
|
||||
continue;
|
||||
}
|
||||
switch (p->state) {
|
||||
case TASK_STOPPED:
|
||||
if (!(options & WUNTRACED) ||
|
||||
!p->exit_code)
|
||||
continue;
|
||||
put_fs_long((p->exit_code << 8) | 0x7f,
|
||||
stat_addr);
|
||||
p->exit_code = 0;
|
||||
return p->pid;
|
||||
case TASK_ZOMBIE:
|
||||
current->cutime += p->utime;
|
||||
current->cstime += p->stime;
|
||||
flag = p->pid;
|
||||
put_fs_long(p->exit_code, stat_addr);
|
||||
release(p);
|
||||
#ifdef DEBUG_PROC_TREE
|
||||
audit_ptree();
|
||||
#endif
|
||||
return flag;
|
||||
default:
|
||||
flag=1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
if (options & WNOHANG)
|
||||
return 0;
|
||||
current->state=TASK_INTERRUPTIBLE;
|
||||
oldblocked = current->blocked;
|
||||
current->blocked &= ~(1<<(SIGCHLD-1));
|
||||
schedule();
|
||||
current->blocked = oldblocked;
|
||||
if (current->signal & ~(current->blocked | (1<<(SIGCHLD-1))))
|
||||
return -ERESTARTSYS;
|
||||
else
|
||||
goto repeat;
|
||||
}
|
||||
return -ECHILD;
|
||||
}
|
||||
|
||||
|
||||
157
Book-Lite/linux-0.12/kernel/fork.c
Normal file
157
Book-Lite/linux-0.12/kernel/fork.c
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* linux/kernel/fork.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* 'fork.c' contains the help-routines for the 'fork' system call
|
||||
* (see also system_call.s), and some misc functions ('verify_area').
|
||||
* Fork is rather simple, once you get the hang of it, but the memory
|
||||
* management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
|
||||
*/
|
||||
#include <errno.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
extern void write_verify(unsigned long address);
|
||||
|
||||
long last_pid=0;
|
||||
|
||||
void verify_area(void * addr,int size)
|
||||
{
|
||||
unsigned long start;
|
||||
|
||||
start = (unsigned long) addr;
|
||||
size += start & 0xfff;
|
||||
start &= 0xfffff000;
|
||||
start += get_base(current->ldt[2]);
|
||||
while (size>0) {
|
||||
size -= 4096;
|
||||
write_verify(start);
|
||||
start += 4096;
|
||||
}
|
||||
}
|
||||
|
||||
int copy_mem(int nr,struct task_struct * p)
|
||||
{
|
||||
unsigned long old_data_base,new_data_base,data_limit;
|
||||
unsigned long old_code_base,new_code_base,code_limit;
|
||||
|
||||
code_limit=get_limit(0x0f);
|
||||
data_limit=get_limit(0x17);
|
||||
old_code_base = get_base(current->ldt[1]);
|
||||
old_data_base = get_base(current->ldt[2]);
|
||||
if (old_data_base != old_code_base)
|
||||
panic("We don't support separate I&D");
|
||||
if (data_limit < code_limit)
|
||||
panic("Bad data_limit");
|
||||
new_data_base = new_code_base = nr * TASK_SIZE;
|
||||
p->start_code = new_code_base;
|
||||
set_base(p->ldt[1],new_code_base);
|
||||
set_base(p->ldt[2],new_data_base);
|
||||
if (copy_page_tables(old_data_base,new_data_base,data_limit)) {
|
||||
free_page_tables(new_data_base,data_limit);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, this is the main fork-routine. It copies the system process
|
||||
* information (task[nr]) and sets up the necessary registers. It
|
||||
* also copies the data segment in it's entirety.
|
||||
*/
|
||||
int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
|
||||
long ebx,long ecx,long edx, long orig_eax,
|
||||
long fs,long es,long ds,
|
||||
long eip,long cs,long eflags,long esp,long ss)
|
||||
{
|
||||
struct task_struct *p;
|
||||
int i;
|
||||
struct file *f;
|
||||
|
||||
p = (struct task_struct *) get_free_page();
|
||||
if (!p)
|
||||
return -EAGAIN;
|
||||
task[nr] = p;
|
||||
*p = *current; /* NOTE! this doesn't copy the supervisor stack */
|
||||
p->state = TASK_UNINTERRUPTIBLE;
|
||||
p->pid = last_pid;
|
||||
p->counter = p->priority;
|
||||
p->signal = 0;
|
||||
p->alarm = 0;
|
||||
p->leader = 0; /* process leadership doesn't inherit */
|
||||
p->utime = p->stime = 0;
|
||||
p->cutime = p->cstime = 0;
|
||||
p->start_time = jiffies;
|
||||
p->tss.back_link = 0;
|
||||
p->tss.esp0 = PAGE_SIZE + (long) p;
|
||||
p->tss.ss0 = 0x10;
|
||||
p->tss.eip = eip;
|
||||
p->tss.eflags = eflags;
|
||||
p->tss.eax = 0;
|
||||
p->tss.ecx = ecx;
|
||||
p->tss.edx = edx;
|
||||
p->tss.ebx = ebx;
|
||||
p->tss.esp = esp;
|
||||
p->tss.ebp = ebp;
|
||||
p->tss.esi = esi;
|
||||
p->tss.edi = edi;
|
||||
p->tss.es = es & 0xffff;
|
||||
p->tss.cs = cs & 0xffff;
|
||||
p->tss.ss = ss & 0xffff;
|
||||
p->tss.ds = ds & 0xffff;
|
||||
p->tss.fs = fs & 0xffff;
|
||||
p->tss.gs = gs & 0xffff;
|
||||
p->tss.ldt = _LDT(nr);
|
||||
p->tss.trace_bitmap = 0x80000000;
|
||||
if (last_task_used_math == current)
|
||||
__asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387));
|
||||
if (copy_mem(nr,p)) {
|
||||
task[nr] = NULL;
|
||||
free_page((long) p);
|
||||
return -EAGAIN;
|
||||
}
|
||||
for (i=0; i<NR_OPEN;i++)
|
||||
if (f=p->filp[i])
|
||||
f->f_count++;
|
||||
if (current->pwd)
|
||||
current->pwd->i_count++;
|
||||
if (current->root)
|
||||
current->root->i_count++;
|
||||
if (current->executable)
|
||||
current->executable->i_count++;
|
||||
if (current->library)
|
||||
current->library->i_count++;
|
||||
set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
|
||||
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
|
||||
p->p_pptr = current;
|
||||
p->p_cptr = 0;
|
||||
p->p_ysptr = 0;
|
||||
p->p_osptr = current->p_cptr;
|
||||
if (p->p_osptr)
|
||||
p->p_osptr->p_ysptr = p;
|
||||
current->p_cptr = p;
|
||||
p->state = TASK_RUNNING; /* do this last, just in case */
|
||||
return last_pid;
|
||||
}
|
||||
|
||||
int find_empty_process(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
repeat:
|
||||
if ((++last_pid)<0) last_pid=1;
|
||||
for(i=0 ; i<NR_TASKS ; i++)
|
||||
if (task[i] && ((task[i]->pid == last_pid) ||
|
||||
(task[i]->pgrp == last_pid)))
|
||||
goto repeat;
|
||||
for(i=1 ; i<NR_TASKS ; i++)
|
||||
if (!task[i])
|
||||
return i;
|
||||
return -EAGAIN;
|
||||
}
|
||||
83
Book-Lite/linux-0.12/kernel/math/Makefile
Normal file
83
Book-Lite/linux-0.12/kernel/math/Makefile
Normal file
@@ -0,0 +1,83 @@
|
||||
#
|
||||
# Makefile for the FREAX-kernel character device drivers.
|
||||
#
|
||||
# Note! Dependencies are done automagically by 'make dep', which also
|
||||
# removes any old dependencies. DON'T put your own dependencies here
|
||||
# unless it's something special (ie not a .c file).
|
||||
#
|
||||
|
||||
AR =gar
|
||||
AS =gas
|
||||
LD =gld
|
||||
LDFLAGS =-s -x
|
||||
CC =gcc
|
||||
CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
|
||||
-finline-functions -mstring-insns -nostdinc -I../../include
|
||||
CPP =gcc -E -nostdinc -I../../include
|
||||
|
||||
.c.s:
|
||||
$(CC) $(CFLAGS) \
|
||||
-S -o $*.s $<
|
||||
.s.o:
|
||||
$(AS) -c -o $*.o $<
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) \
|
||||
-c -o $*.o $<
|
||||
|
||||
OBJS = math_emulate.o error.o convert.o ea.o get_put.o \
|
||||
add.o mul.o div.o compare.o
|
||||
|
||||
math.a: $(OBJS)
|
||||
$(AR) rcs math.a $(OBJS)
|
||||
sync
|
||||
|
||||
clean:
|
||||
rm -f core *.o *.a tmp_make
|
||||
for i in *.c;do rm -f `basename $$i .c`.s;done
|
||||
|
||||
dep:
|
||||
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
|
||||
(for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \
|
||||
$(CPP) -M $$i;done) >> tmp_make
|
||||
cp tmp_make Makefile
|
||||
|
||||
### Dependencies:
|
||||
add.s add.o : add.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h
|
||||
compare.s compare.o : compare.c ../../include/linux/math_emu.h \
|
||||
../../include/linux/sched.h ../../include/linux/head.h \
|
||||
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h
|
||||
convert.s convert.o : convert.c ../../include/linux/math_emu.h \
|
||||
../../include/linux/sched.h ../../include/linux/head.h \
|
||||
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h
|
||||
div.s div.o : div.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h
|
||||
ea.s ea.o : ea.c ../../include/stddef.h ../../include/linux/math_emu.h \
|
||||
../../include/linux/sched.h ../../include/linux/head.h \
|
||||
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h \
|
||||
../../include/asm/segment.h
|
||||
error.s error.o : error.c ../../include/signal.h ../../include/sys/types.h \
|
||||
../../include/linux/sched.h ../../include/linux/head.h \
|
||||
../../include/linux/fs.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h
|
||||
get_put.s get_put.o : get_put.c ../../include/signal.h ../../include/sys/types.h \
|
||||
../../include/linux/math_emu.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/linux/mm.h ../../include/linux/kernel.h \
|
||||
../../include/asm/segment.h
|
||||
math_emulate.s math_emulate.o : math_emulate.c ../../include/signal.h \
|
||||
../../include/sys/types.h ../../include/linux/math_emu.h \
|
||||
../../include/linux/sched.h ../../include/linux/head.h \
|
||||
../../include/linux/fs.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/asm/segment.h
|
||||
mul.s mul.o : mul.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h
|
||||
92
Book-Lite/linux-0.12/kernel/math/add.c
Normal file
92
Book-Lite/linux-0.12/kernel/math/add.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* linux/kernel/math/add.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* temporary real addition routine.
|
||||
*
|
||||
* NOTE! These aren't exact: they are only 62 bits wide, and don't do
|
||||
* correct rounding. Fast hack. The reason is that we shift right the
|
||||
* values by two, in order not to have overflow (1 bit), and to be able
|
||||
* to move the sign into the mantissa (1 bit). Much simpler algorithms,
|
||||
* and 62 bits (61 really - no rounding) accuracy is usually enough. The
|
||||
* only time you should notice anything weird is when adding 64-bit
|
||||
* integers together. When using doubles (52 bits accuracy), the
|
||||
* 61-bit accuracy never shows at all.
|
||||
*/
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
|
||||
#define NEGINT(a) \
|
||||
__asm__("notl %0 ; notl %1 ; addl $1,%0 ; adcl $0,%1" \
|
||||
:"=r" (a->a),"=r" (a->b) \
|
||||
:"0" (a->a),"1" (a->b))
|
||||
|
||||
static void signify(temp_real * a)
|
||||
{
|
||||
a->exponent += 2;
|
||||
__asm__("shrdl $2,%1,%0 ; shrl $2,%1"
|
||||
:"=r" (a->a),"=r" (a->b)
|
||||
:"0" (a->a),"1" (a->b));
|
||||
if (a->exponent < 0)
|
||||
NEGINT(a);
|
||||
a->exponent &= 0x7fff;
|
||||
}
|
||||
|
||||
static void unsignify(temp_real * a)
|
||||
{
|
||||
if (!(a->a || a->b)) {
|
||||
a->exponent = 0;
|
||||
return;
|
||||
}
|
||||
a->exponent &= 0x7fff;
|
||||
if (a->b < 0) {
|
||||
NEGINT(a);
|
||||
a->exponent |= 0x8000;
|
||||
}
|
||||
while (a->b >= 0) {
|
||||
a->exponent--;
|
||||
__asm__("addl %0,%0 ; adcl %1,%1"
|
||||
:"=r" (a->a),"=r" (a->b)
|
||||
:"0" (a->a),"1" (a->b));
|
||||
}
|
||||
}
|
||||
|
||||
void fadd(const temp_real * src1, const temp_real * src2, temp_real * result)
|
||||
{
|
||||
temp_real a,b;
|
||||
int x1,x2,shift;
|
||||
|
||||
x1 = src1->exponent & 0x7fff;
|
||||
x2 = src2->exponent & 0x7fff;
|
||||
if (x1 > x2) {
|
||||
a = *src1;
|
||||
b = *src2;
|
||||
shift = x1-x2;
|
||||
} else {
|
||||
a = *src2;
|
||||
b = *src1;
|
||||
shift = x2-x1;
|
||||
}
|
||||
if (shift >= 64) {
|
||||
*result = a;
|
||||
return;
|
||||
}
|
||||
if (shift >= 32) {
|
||||
b.a = b.b;
|
||||
b.b = 0;
|
||||
shift -= 32;
|
||||
}
|
||||
__asm__("shrdl %4,%1,%0 ; shrl %4,%1"
|
||||
:"=r" (b.a),"=r" (b.b)
|
||||
:"0" (b.a),"1" (b.b),"c" ((char) shift));
|
||||
signify(&a);
|
||||
signify(&b);
|
||||
__asm__("addl %4,%0 ; adcl %5,%1"
|
||||
:"=r" (a.a),"=r" (a.b)
|
||||
:"0" (a.a),"1" (a.b),"g" (b.a),"g" (b.b));
|
||||
unsignify(&a);
|
||||
*result = a;
|
||||
}
|
||||
60
Book-Lite/linux-0.12/kernel/math/compare.c
Normal file
60
Book-Lite/linux-0.12/kernel/math/compare.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* linux/kernel/math/compare.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* temporary real comparison routines
|
||||
*/
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
|
||||
#define clear_Cx() (I387.swd &= ~0x4500)
|
||||
|
||||
static void normalize(temp_real * a)
|
||||
{
|
||||
int i = a->exponent & 0x7fff;
|
||||
int sign = a->exponent & 0x8000;
|
||||
|
||||
if (!(a->a || a->b)) {
|
||||
a->exponent = 0;
|
||||
return;
|
||||
}
|
||||
while (i && a->b >= 0) {
|
||||
i--;
|
||||
__asm__("addl %0,%0 ; adcl %1,%1"
|
||||
:"=r" (a->a),"=r" (a->b)
|
||||
:"0" (a->a),"1" (a->b));
|
||||
}
|
||||
a->exponent = i | sign;
|
||||
}
|
||||
|
||||
void ftst(const temp_real * a)
|
||||
{
|
||||
temp_real b;
|
||||
|
||||
clear_Cx();
|
||||
b = *a;
|
||||
normalize(&b);
|
||||
if (b.a || b.b || b.exponent) {
|
||||
if (b.exponent < 0)
|
||||
set_C0();
|
||||
} else
|
||||
set_C3();
|
||||
}
|
||||
|
||||
void fcom(const temp_real * src1, const temp_real * src2)
|
||||
{
|
||||
temp_real a;
|
||||
|
||||
a = *src1;
|
||||
a.exponent ^= 0x8000;
|
||||
fadd(&a,src2,&a);
|
||||
ftst(&a);
|
||||
}
|
||||
|
||||
void fucom(const temp_real * src1, const temp_real * src2)
|
||||
{
|
||||
fcom(src1,src2);
|
||||
}
|
||||
185
Book-Lite/linux-0.12/kernel/math/convert.c
Normal file
185
Book-Lite/linux-0.12/kernel/math/convert.c
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* linux/kernel/math/convert.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
|
||||
/*
|
||||
* NOTE!!! There is some "non-obvious" optimisations in the temp_to_long
|
||||
* and temp_to_short conversion routines: don't touch them if you don't
|
||||
* know what's going on. They are the adding of one in the rounding: the
|
||||
* overflow bit is also used for adding one into the exponent. Thus it
|
||||
* looks like the overflow would be incorrectly handled, but due to the
|
||||
* way the IEEE numbers work, things are correct.
|
||||
*
|
||||
* There is no checking for total overflow in the conversions, though (ie
|
||||
* if the temp-real number simply won't fit in a short- or long-real.)
|
||||
*/
|
||||
|
||||
void short_to_temp(const short_real * a, temp_real * b)
|
||||
{
|
||||
if (!(*a & 0x7fffffff)) {
|
||||
b->a = b->b = 0;
|
||||
if (*a)
|
||||
b->exponent = 0x8000;
|
||||
else
|
||||
b->exponent = 0;
|
||||
return;
|
||||
}
|
||||
b->exponent = ((*a>>23) & 0xff)-127+16383;
|
||||
if (*a<0)
|
||||
b->exponent |= 0x8000;
|
||||
b->b = (*a<<8) | 0x80000000;
|
||||
b->a = 0;
|
||||
}
|
||||
|
||||
void long_to_temp(const long_real * a, temp_real * b)
|
||||
{
|
||||
if (!a->a && !(a->b & 0x7fffffff)) {
|
||||
b->a = b->b = 0;
|
||||
if (a->b)
|
||||
b->exponent = 0x8000;
|
||||
else
|
||||
b->exponent = 0;
|
||||
return;
|
||||
}
|
||||
b->exponent = ((a->b >> 20) & 0x7ff)-1023+16383;
|
||||
if (a->b<0)
|
||||
b->exponent |= 0x8000;
|
||||
b->b = 0x80000000 | (a->b<<11) | (((unsigned long)a->a)>>21);
|
||||
b->a = a->a<<11;
|
||||
}
|
||||
|
||||
void temp_to_short(const temp_real * a, short_real * b)
|
||||
{
|
||||
if (!(a->exponent & 0x7fff)) {
|
||||
*b = (a->exponent)?0x80000000:0;
|
||||
return;
|
||||
}
|
||||
*b = ((((long) a->exponent)-16383+127) << 23) & 0x7f800000;
|
||||
if (a->exponent < 0)
|
||||
*b |= 0x80000000;
|
||||
*b |= (a->b >> 8) & 0x007fffff;
|
||||
switch (ROUNDING) {
|
||||
case ROUND_NEAREST:
|
||||
if ((a->b & 0xff) > 0x80)
|
||||
++*b;
|
||||
break;
|
||||
case ROUND_DOWN:
|
||||
if ((a->exponent & 0x8000) && (a->b & 0xff))
|
||||
++*b;
|
||||
break;
|
||||
case ROUND_UP:
|
||||
if (!(a->exponent & 0x8000) && (a->b & 0xff))
|
||||
++*b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void temp_to_long(const temp_real * a, long_real * b)
|
||||
{
|
||||
if (!(a->exponent & 0x7fff)) {
|
||||
b->a = 0;
|
||||
b->b = (a->exponent)?0x80000000:0;
|
||||
return;
|
||||
}
|
||||
b->b = (((0x7fff & (long) a->exponent)-16383+1023) << 20) & 0x7ff00000;
|
||||
if (a->exponent < 0)
|
||||
b->b |= 0x80000000;
|
||||
b->b |= (a->b >> 11) & 0x000fffff;
|
||||
b->a = a->b << 21;
|
||||
b->a |= (a->a >> 11) & 0x001fffff;
|
||||
switch (ROUNDING) {
|
||||
case ROUND_NEAREST:
|
||||
if ((a->a & 0x7ff) > 0x400)
|
||||
__asm__("addl $1,%0 ; adcl $0,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b));
|
||||
break;
|
||||
case ROUND_DOWN:
|
||||
if ((a->exponent & 0x8000) && (a->b & 0xff))
|
||||
__asm__("addl $1,%0 ; adcl $0,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b));
|
||||
break;
|
||||
case ROUND_UP:
|
||||
if (!(a->exponent & 0x8000) && (a->b & 0xff))
|
||||
__asm__("addl $1,%0 ; adcl $0,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void real_to_int(const temp_real * a, temp_int * b)
|
||||
{
|
||||
int shift = 16383 + 63 - (a->exponent & 0x7fff);
|
||||
unsigned long underflow;
|
||||
|
||||
b->a = b->b = underflow = 0;
|
||||
b->sign = (a->exponent < 0);
|
||||
if (shift < 0) {
|
||||
set_OE();
|
||||
return;
|
||||
}
|
||||
if (shift < 32) {
|
||||
b->b = a->b; b->a = a->a;
|
||||
} else if (shift < 64) {
|
||||
b->a = a->b; underflow = a->a;
|
||||
shift -= 32;
|
||||
} else if (shift < 96) {
|
||||
underflow = a->b;
|
||||
shift -= 64;
|
||||
} else
|
||||
return;
|
||||
__asm__("shrdl %2,%1,%0"
|
||||
:"=r" (underflow),"=r" (b->a)
|
||||
:"c" ((char) shift),"0" (underflow),"1" (b->a));
|
||||
__asm__("shrdl %2,%1,%0"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"c" ((char) shift),"0" (b->a),"1" (b->b));
|
||||
__asm__("shrl %1,%0"
|
||||
:"=r" (b->b)
|
||||
:"c" ((char) shift),"0" (b->b));
|
||||
switch (ROUNDING) {
|
||||
case ROUND_NEAREST:
|
||||
__asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b)
|
||||
,"r" (0x7fffffff + (b->a & 1))
|
||||
,"m" (*&underflow));
|
||||
break;
|
||||
case ROUND_UP:
|
||||
if (!b->sign && underflow)
|
||||
__asm__("addl $1,%0 ; adcl $0,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b));
|
||||
break;
|
||||
case ROUND_DOWN:
|
||||
if (b->sign && underflow)
|
||||
__asm__("addl $1,%0 ; adcl $0,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void int_to_real(const temp_int * a, temp_real * b)
|
||||
{
|
||||
b->a = a->a;
|
||||
b->b = a->b;
|
||||
if (b->a || b->b)
|
||||
b->exponent = 16383 + 63 + (a->sign? 0x8000:0);
|
||||
else {
|
||||
b->exponent = 0;
|
||||
return;
|
||||
}
|
||||
while (b->b >= 0) {
|
||||
b->exponent--;
|
||||
__asm__("addl %0,%0 ; adcl %1,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b));
|
||||
}
|
||||
}
|
||||
109
Book-Lite/linux-0.12/kernel/math/div.c
Normal file
109
Book-Lite/linux-0.12/kernel/math/div.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* linux/kernel/math/div.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* temporary real division routine.
|
||||
*/
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
|
||||
static void shift_left(int * c)
|
||||
{
|
||||
__asm__ __volatile__("movl (%0),%%eax ; addl %%eax,(%0)\n\t"
|
||||
"movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t"
|
||||
"movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t"
|
||||
"movl 12(%0),%%eax ; adcl %%eax,12(%0)"
|
||||
::"r" ((long) c):"ax");
|
||||
}
|
||||
|
||||
static void shift_right(int * c)
|
||||
{
|
||||
__asm__("shrl $1,12(%0) ; rcrl $1,8(%0) ; rcrl $1,4(%0) ; rcrl $1,(%0)"
|
||||
::"r" ((long) c));
|
||||
}
|
||||
|
||||
static int try_sub(int * a, int * b)
|
||||
{
|
||||
char ok;
|
||||
|
||||
__asm__ __volatile__("movl (%1),%%eax ; subl %%eax,(%2)\n\t"
|
||||
"movl 4(%1),%%eax ; sbbl %%eax,4(%2)\n\t"
|
||||
"movl 8(%1),%%eax ; sbbl %%eax,8(%2)\n\t"
|
||||
"movl 12(%1),%%eax ; sbbl %%eax,12(%2)\n\t"
|
||||
"setae %%al":"=a" (ok):"c" ((long) a),"d" ((long) b));
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void div64(int * a, int * b, int * c)
|
||||
{
|
||||
int tmp[4];
|
||||
int i;
|
||||
unsigned int mask = 0;
|
||||
|
||||
c += 4;
|
||||
for (i = 0 ; i<64 ; i++) {
|
||||
if (!(mask >>= 1)) {
|
||||
c--;
|
||||
mask = 0x80000000;
|
||||
}
|
||||
tmp[0] = a[0]; tmp[1] = a[1];
|
||||
tmp[2] = a[2]; tmp[3] = a[3];
|
||||
if (try_sub(b,tmp)) {
|
||||
*c |= mask;
|
||||
a[0] = tmp[0]; a[1] = tmp[1];
|
||||
a[2] = tmp[2]; a[3] = tmp[3];
|
||||
}
|
||||
shift_right(b);
|
||||
}
|
||||
}
|
||||
|
||||
void fdiv(const temp_real * src1, const temp_real * src2, temp_real * result)
|
||||
{
|
||||
int i,sign;
|
||||
int a[4],b[4],tmp[4] = {0,0,0,0};
|
||||
|
||||
sign = (src1->exponent ^ src2->exponent) & 0x8000;
|
||||
if (!(src2->a || src2->b)) {
|
||||
set_ZE();
|
||||
return;
|
||||
}
|
||||
i = (src1->exponent & 0x7fff) - (src2->exponent & 0x7fff) + 16383;
|
||||
if (i<0) {
|
||||
set_UE();
|
||||
result->exponent = sign;
|
||||
result->a = result->b = 0;
|
||||
return;
|
||||
}
|
||||
a[0] = a[1] = 0;
|
||||
a[2] = src1->a;
|
||||
a[3] = src1->b;
|
||||
b[0] = b[1] = 0;
|
||||
b[2] = src2->a;
|
||||
b[3] = src2->b;
|
||||
while (b[3] >= 0) {
|
||||
i++;
|
||||
shift_left(b);
|
||||
}
|
||||
div64(a,b,tmp);
|
||||
if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) {
|
||||
while (i && tmp[3] >= 0) {
|
||||
i--;
|
||||
shift_left(tmp);
|
||||
}
|
||||
if (tmp[3] >= 0)
|
||||
set_DE();
|
||||
} else
|
||||
i = 0;
|
||||
if (i>0x7fff) {
|
||||
set_OE();
|
||||
return;
|
||||
}
|
||||
if (tmp[0] || tmp[1])
|
||||
set_PE();
|
||||
result->exponent = i | sign;
|
||||
result->a = tmp[2];
|
||||
result->b = tmp[3];
|
||||
}
|
||||
92
Book-Lite/linux-0.12/kernel/math/ea.c
Normal file
92
Book-Lite/linux-0.12/kernel/math/ea.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* linux/kernel/math/ea.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* Calculate the effective address.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
static int __regoffset[] = {
|
||||
offsetof(struct info,___eax),
|
||||
offsetof(struct info,___ecx),
|
||||
offsetof(struct info,___edx),
|
||||
offsetof(struct info,___ebx),
|
||||
offsetof(struct info,___esp),
|
||||
offsetof(struct info,___ebp),
|
||||
offsetof(struct info,___esi),
|
||||
offsetof(struct info,___edi)
|
||||
};
|
||||
|
||||
#define REG(x) (*(long *)(__regoffset[(x)]+(char *) info))
|
||||
|
||||
static char * sib(struct info * info, int mod)
|
||||
{
|
||||
unsigned char ss,index,base;
|
||||
long offset = 0;
|
||||
|
||||
base = get_fs_byte((char *) EIP);
|
||||
EIP++;
|
||||
ss = base >> 6;
|
||||
index = (base >> 3) & 7;
|
||||
base &= 7;
|
||||
if (index == 4)
|
||||
offset = 0;
|
||||
else
|
||||
offset = REG(index);
|
||||
offset <<= ss;
|
||||
if (mod || base != 5)
|
||||
offset += REG(base);
|
||||
if (mod == 1) {
|
||||
offset += (signed char) get_fs_byte((char *) EIP);
|
||||
EIP++;
|
||||
} else if (mod == 2 || base == 5) {
|
||||
offset += (signed) get_fs_long((unsigned long *) EIP);
|
||||
EIP += 4;
|
||||
}
|
||||
I387.foo = offset;
|
||||
I387.fos = 0x17;
|
||||
return (char *) offset;
|
||||
}
|
||||
|
||||
char * ea(struct info * info, unsigned short code)
|
||||
{
|
||||
unsigned char mod,rm;
|
||||
long * tmp = &EAX;
|
||||
int offset = 0;
|
||||
|
||||
mod = (code >> 6) & 3;
|
||||
rm = code & 7;
|
||||
if (rm == 4 && mod != 3)
|
||||
return sib(info,mod);
|
||||
if (rm == 5 && !mod) {
|
||||
offset = get_fs_long((unsigned long *) EIP);
|
||||
EIP += 4;
|
||||
I387.foo = offset;
|
||||
I387.fos = 0x17;
|
||||
return (char *) offset;
|
||||
}
|
||||
tmp = & REG(rm);
|
||||
switch (mod) {
|
||||
case 0: offset = 0; break;
|
||||
case 1:
|
||||
offset = (signed char) get_fs_byte((char *) EIP);
|
||||
EIP++;
|
||||
break;
|
||||
case 2:
|
||||
offset = (signed) get_fs_long((unsigned long *) EIP);
|
||||
EIP += 4;
|
||||
break;
|
||||
case 3:
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
}
|
||||
I387.foo = offset;
|
||||
I387.fos = 0x17;
|
||||
return offset + (char *) *tmp;
|
||||
}
|
||||
16
Book-Lite/linux-0.12/kernel/math/error.c
Normal file
16
Book-Lite/linux-0.12/kernel/math/error.c
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* linux/kernel/math/error.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
void math_error(void)
|
||||
{
|
||||
__asm__("fnclex");
|
||||
if (last_task_used_math)
|
||||
last_task_used_math->signal |= 1<<(SIGFPE-1);
|
||||
}
|
||||
240
Book-Lite/linux-0.12/kernel/math/get_put.c
Normal file
240
Book-Lite/linux-0.12/kernel/math/get_put.c
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* linux/kernel/math/get_put.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles all accesses to user memory: getting and putting
|
||||
* ints/reals/BCD etc. This is the only part that concerns itself with
|
||||
* other than temporary real format. All other cals are strictly temp_real.
|
||||
*/
|
||||
#include <signal.h>
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
void get_short_real(temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
short_real sr;
|
||||
|
||||
addr = ea(info,code);
|
||||
sr = get_fs_long((unsigned long *) addr);
|
||||
short_to_temp(&sr,tmp);
|
||||
}
|
||||
|
||||
void get_long_real(temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
long_real lr;
|
||||
|
||||
addr = ea(info,code);
|
||||
lr.a = get_fs_long((unsigned long *) addr);
|
||||
lr.b = get_fs_long(1 + (unsigned long *) addr);
|
||||
long_to_temp(&lr,tmp);
|
||||
}
|
||||
|
||||
void get_temp_real(temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
|
||||
addr = ea(info,code);
|
||||
tmp->a = get_fs_long((unsigned long *) addr);
|
||||
tmp->b = get_fs_long(1 + (unsigned long *) addr);
|
||||
tmp->exponent = get_fs_word(4 + (unsigned short *) addr);
|
||||
}
|
||||
|
||||
void get_short_int(temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
temp_int ti;
|
||||
|
||||
addr = ea(info,code);
|
||||
ti.a = (signed short) get_fs_word((unsigned short *) addr);
|
||||
ti.b = 0;
|
||||
if (ti.sign = (ti.a < 0))
|
||||
ti.a = - ti.a;
|
||||
int_to_real(&ti,tmp);
|
||||
}
|
||||
|
||||
void get_long_int(temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
temp_int ti;
|
||||
|
||||
addr = ea(info,code);
|
||||
ti.a = get_fs_long((unsigned long *) addr);
|
||||
ti.b = 0;
|
||||
if (ti.sign = (ti.a < 0))
|
||||
ti.a = - ti.a;
|
||||
int_to_real(&ti,tmp);
|
||||
}
|
||||
|
||||
void get_longlong_int(temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
temp_int ti;
|
||||
|
||||
addr = ea(info,code);
|
||||
ti.a = get_fs_long((unsigned long *) addr);
|
||||
ti.b = get_fs_long(1 + (unsigned long *) addr);
|
||||
if (ti.sign = (ti.b < 0))
|
||||
__asm__("notl %0 ; notl %1\n\t"
|
||||
"addl $1,%0 ; adcl $0,%1"
|
||||
:"=r" (ti.a),"=r" (ti.b)
|
||||
:"0" (ti.a),"1" (ti.b));
|
||||
int_to_real(&ti,tmp);
|
||||
}
|
||||
|
||||
#define MUL10(low,high) \
|
||||
__asm__("addl %0,%0 ; adcl %1,%1\n\t" \
|
||||
"movl %0,%%ecx ; movl %1,%%ebx\n\t" \
|
||||
"addl %0,%0 ; adcl %1,%1\n\t" \
|
||||
"addl %0,%0 ; adcl %1,%1\n\t" \
|
||||
"addl %%ecx,%0 ; adcl %%ebx,%1" \
|
||||
:"=a" (low),"=d" (high) \
|
||||
:"0" (low),"1" (high):"cx","bx")
|
||||
|
||||
#define ADD64(val,low,high) \
|
||||
__asm__("addl %4,%0 ; adcl $0,%1":"=r" (low),"=r" (high) \
|
||||
:"0" (low),"1" (high),"r" ((unsigned long) (val)))
|
||||
|
||||
void get_BCD(temp_real * tmp, struct info * info, unsigned short code)
|
||||
{
|
||||
int k;
|
||||
char * addr;
|
||||
temp_int i;
|
||||
unsigned char c;
|
||||
|
||||
addr = ea(info,code);
|
||||
addr += 9;
|
||||
i.sign = 0x80 & get_fs_byte(addr--);
|
||||
i.a = i.b = 0;
|
||||
for (k = 0; k < 9; k++) {
|
||||
c = get_fs_byte(addr--);
|
||||
MUL10(i.a, i.b);
|
||||
ADD64((c>>4), i.a, i.b);
|
||||
MUL10(i.a, i.b);
|
||||
ADD64((c&0xf), i.a, i.b);
|
||||
}
|
||||
int_to_real(&i,tmp);
|
||||
}
|
||||
|
||||
void put_short_real(const temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
short_real sr;
|
||||
|
||||
addr = ea(info,code);
|
||||
verify_area(addr,4);
|
||||
temp_to_short(tmp,&sr);
|
||||
put_fs_long(sr,(unsigned long *) addr);
|
||||
}
|
||||
|
||||
void put_long_real(const temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
long_real lr;
|
||||
|
||||
addr = ea(info,code);
|
||||
verify_area(addr,8);
|
||||
temp_to_long(tmp,&lr);
|
||||
put_fs_long(lr.a, (unsigned long *) addr);
|
||||
put_fs_long(lr.b, 1 + (unsigned long *) addr);
|
||||
}
|
||||
|
||||
void put_temp_real(const temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
|
||||
addr = ea(info,code);
|
||||
verify_area(addr,10);
|
||||
put_fs_long(tmp->a, (unsigned long *) addr);
|
||||
put_fs_long(tmp->b, 1 + (unsigned long *) addr);
|
||||
put_fs_word(tmp->exponent, 4 + (short *) addr);
|
||||
}
|
||||
|
||||
void put_short_int(const temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
temp_int ti;
|
||||
|
||||
addr = ea(info,code);
|
||||
real_to_int(tmp,&ti);
|
||||
verify_area(addr,2);
|
||||
if (ti.sign)
|
||||
ti.a = -ti.a;
|
||||
put_fs_word(ti.a,(short *) addr);
|
||||
}
|
||||
|
||||
void put_long_int(const temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
temp_int ti;
|
||||
|
||||
addr = ea(info,code);
|
||||
real_to_int(tmp,&ti);
|
||||
verify_area(addr,4);
|
||||
if (ti.sign)
|
||||
ti.a = -ti.a;
|
||||
put_fs_long(ti.a,(unsigned long *) addr);
|
||||
}
|
||||
|
||||
void put_longlong_int(const temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
temp_int ti;
|
||||
|
||||
addr = ea(info,code);
|
||||
real_to_int(tmp,&ti);
|
||||
verify_area(addr,8);
|
||||
if (ti.sign)
|
||||
__asm__("notl %0 ; notl %1\n\t"
|
||||
"addl $1,%0 ; adcl $0,%1"
|
||||
:"=r" (ti.a),"=r" (ti.b)
|
||||
:"0" (ti.a),"1" (ti.b));
|
||||
put_fs_long(ti.a,(unsigned long *) addr);
|
||||
put_fs_long(ti.b,1 + (unsigned long *) addr);
|
||||
}
|
||||
|
||||
#define DIV10(low,high,rem) \
|
||||
__asm__("divl %6 ; xchgl %1,%2 ; divl %6" \
|
||||
:"=d" (rem),"=a" (low),"=b" (high) \
|
||||
:"0" (0),"1" (high),"2" (low),"c" (10))
|
||||
|
||||
void put_BCD(const temp_real * tmp,struct info * info, unsigned short code)
|
||||
{
|
||||
int k,rem;
|
||||
char * addr;
|
||||
temp_int i;
|
||||
unsigned char c;
|
||||
|
||||
addr = ea(info,code);
|
||||
verify_area(addr,10);
|
||||
real_to_int(tmp,&i);
|
||||
if (i.sign)
|
||||
put_fs_byte(0x80, addr+9);
|
||||
else
|
||||
put_fs_byte(0, addr+9);
|
||||
for (k = 0; k < 9; k++) {
|
||||
DIV10(i.a,i.b,rem);
|
||||
c = rem;
|
||||
DIV10(i.a,i.b,rem);
|
||||
c += rem<<4;
|
||||
put_fs_byte(c,addr++);
|
||||
}
|
||||
}
|
||||
529
Book-Lite/linux-0.12/kernel/math/math_emulate.c
Normal file
529
Book-Lite/linux-0.12/kernel/math/math_emulate.c
Normal file
@@ -0,0 +1,529 @@
|
||||
/*
|
||||
* linux/kernel/math/math_emulate.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* Limited emulation 27.12.91 - mostly loads/stores, which gcc wants
|
||||
* even for soft-float, unless you use bruce evans' patches. The patches
|
||||
* are great, but they have to be re-applied for every version, and the
|
||||
* library is different for soft-float and 80387. So emulation is more
|
||||
* practical, even though it's slower.
|
||||
*
|
||||
* 28.12.91 - loads/stores work, even BCD. I'll have to start thinking
|
||||
* about add/sub/mul/div. Urgel. I should find some good source, but I'll
|
||||
* just fake up something.
|
||||
*
|
||||
* 30.12.91 - add/sub/mul/div/com seem to work mostly. I should really
|
||||
* test every possible combination.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is full of ugly macros etc: one problem was that gcc simply
|
||||
* didn't want to make the structures as they should be: it has to try to
|
||||
* align them. Sickening code, but at least I've hidden the ugly things
|
||||
* in this one file: the other files don't need to know about these things.
|
||||
*
|
||||
* The other files also don't care about ST(x) etc - they just get addresses
|
||||
* to 80-bit temporary reals, and do with them as they please. I wanted to
|
||||
* hide most of the 387-specific things here.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#define __ALIGNED_TEMP_REAL 1
|
||||
#include <linux/math_emu.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
|
||||
#define ST(x) (*__st((x)))
|
||||
#define PST(x) ((const temp_real *) __st((x)))
|
||||
|
||||
/*
|
||||
* We don't want these inlined - it gets too messy in the machine-code.
|
||||
*/
|
||||
static void fpop(void);
|
||||
static void fpush(void);
|
||||
static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b);
|
||||
static temp_real_unaligned * __st(int i);
|
||||
|
||||
static void do_emu(struct info * info)
|
||||
{
|
||||
unsigned short code;
|
||||
temp_real tmp;
|
||||
char * address;
|
||||
|
||||
if (I387.cwd & I387.swd & 0x3f)
|
||||
I387.swd |= 0x8000;
|
||||
else
|
||||
I387.swd &= 0x7fff;
|
||||
ORIG_EIP = EIP;
|
||||
/* 0x0007 means user code space */
|
||||
if (CS != 0x000F) {
|
||||
printk("math_emulate: %04x:%08x\n\r",CS,EIP);
|
||||
panic("Math emulation needed in kernel");
|
||||
}
|
||||
code = get_fs_word((unsigned short *) EIP);
|
||||
bswapw(code);
|
||||
code &= 0x7ff;
|
||||
I387.fip = EIP;
|
||||
*(unsigned short *) &I387.fcs = CS;
|
||||
*(1+(unsigned short *) &I387.fcs) = code;
|
||||
EIP += 2;
|
||||
switch (code) {
|
||||
case 0x1d0: /* fnop */
|
||||
return;
|
||||
case 0x1d1: case 0x1d2: case 0x1d3:
|
||||
case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0x1e0:
|
||||
ST(0).exponent ^= 0x8000;
|
||||
return;
|
||||
case 0x1e1:
|
||||
ST(0).exponent &= 0x7fff;
|
||||
return;
|
||||
case 0x1e2: case 0x1e3:
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0x1e4:
|
||||
ftst(PST(0));
|
||||
return;
|
||||
case 0x1e5:
|
||||
printk("fxam not implemented\n\r");
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0x1e6: case 0x1e7:
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0x1e8:
|
||||
fpush();
|
||||
ST(0) = CONST1;
|
||||
return;
|
||||
case 0x1e9:
|
||||
fpush();
|
||||
ST(0) = CONSTL2T;
|
||||
return;
|
||||
case 0x1ea:
|
||||
fpush();
|
||||
ST(0) = CONSTL2E;
|
||||
return;
|
||||
case 0x1eb:
|
||||
fpush();
|
||||
ST(0) = CONSTPI;
|
||||
return;
|
||||
case 0x1ec:
|
||||
fpush();
|
||||
ST(0) = CONSTLG2;
|
||||
return;
|
||||
case 0x1ed:
|
||||
fpush();
|
||||
ST(0) = CONSTLN2;
|
||||
return;
|
||||
case 0x1ee:
|
||||
fpush();
|
||||
ST(0) = CONSTZ;
|
||||
return;
|
||||
case 0x1ef:
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3:
|
||||
case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
|
||||
case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb:
|
||||
case 0x1fc: case 0x1fd: case 0x1fe: case 0x1ff:
|
||||
printk("%04x fxxx not implemented\n\r",code + 0xc800);
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0x2e9:
|
||||
fucom(PST(1),PST(0));
|
||||
fpop(); fpop();
|
||||
return;
|
||||
case 0x3d0: case 0x3d1:
|
||||
return;
|
||||
case 0x3e2:
|
||||
I387.swd &= 0x7f00;
|
||||
return;
|
||||
case 0x3e3:
|
||||
I387.cwd = 0x037f;
|
||||
I387.swd = 0x0000;
|
||||
I387.twd = 0x0000;
|
||||
return;
|
||||
case 0x3e4:
|
||||
return;
|
||||
case 0x6d9:
|
||||
fcom(PST(1),PST(0));
|
||||
fpop(); fpop();
|
||||
return;
|
||||
case 0x7e0:
|
||||
*(short *) &EAX = I387.swd;
|
||||
return;
|
||||
}
|
||||
switch (code >> 3) {
|
||||
case 0x18:
|
||||
fadd(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x19:
|
||||
fmul(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x1a:
|
||||
fcom(PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x1b:
|
||||
fcom(PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
fpop();
|
||||
return;
|
||||
case 0x1c:
|
||||
real_to_real(&ST(code & 7),&tmp);
|
||||
tmp.exponent ^= 0x8000;
|
||||
fadd(PST(0),&tmp,&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x1d:
|
||||
ST(0).exponent ^= 0x8000;
|
||||
fadd(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x1e:
|
||||
fdiv(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x1f:
|
||||
fdiv(PST(code & 7),PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x38:
|
||||
fpush();
|
||||
ST(0) = ST((code & 7)+1);
|
||||
return;
|
||||
case 0x39:
|
||||
fxchg(&ST(0),&ST(code & 7));
|
||||
return;
|
||||
case 0x3b:
|
||||
ST(code & 7) = ST(0);
|
||||
fpop();
|
||||
return;
|
||||
case 0x98:
|
||||
fadd(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
return;
|
||||
case 0x99:
|
||||
fmul(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
return;
|
||||
case 0x9a:
|
||||
fcom(PST(code & 7),PST(0));
|
||||
return;
|
||||
case 0x9b:
|
||||
fcom(PST(code & 7),PST(0));
|
||||
fpop();
|
||||
return;
|
||||
case 0x9c:
|
||||
ST(code & 7).exponent ^= 0x8000;
|
||||
fadd(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
return;
|
||||
case 0x9d:
|
||||
real_to_real(&ST(0),&tmp);
|
||||
tmp.exponent ^= 0x8000;
|
||||
fadd(PST(code & 7),&tmp,&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
return;
|
||||
case 0x9e:
|
||||
fdiv(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
return;
|
||||
case 0x9f:
|
||||
fdiv(PST(code & 7),PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
return;
|
||||
case 0xb8:
|
||||
printk("ffree not implemented\n\r");
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0xb9:
|
||||
fxchg(&ST(0),&ST(code & 7));
|
||||
return;
|
||||
case 0xba:
|
||||
ST(code & 7) = ST(0);
|
||||
return;
|
||||
case 0xbb:
|
||||
ST(code & 7) = ST(0);
|
||||
fpop();
|
||||
return;
|
||||
case 0xbc:
|
||||
fucom(PST(code & 7),PST(0));
|
||||
return;
|
||||
case 0xbd:
|
||||
fucom(PST(code & 7),PST(0));
|
||||
fpop();
|
||||
return;
|
||||
case 0xd8:
|
||||
fadd(PST(code & 7),PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
fpop();
|
||||
return;
|
||||
case 0xd9:
|
||||
fmul(PST(code & 7),PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
fpop();
|
||||
return;
|
||||
case 0xda:
|
||||
fcom(PST(code & 7),PST(0));
|
||||
fpop();
|
||||
return;
|
||||
case 0xdc:
|
||||
ST(code & 7).exponent ^= 0x8000;
|
||||
fadd(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
fpop();
|
||||
return;
|
||||
case 0xdd:
|
||||
real_to_real(&ST(0),&tmp);
|
||||
tmp.exponent ^= 0x8000;
|
||||
fadd(PST(code & 7),&tmp,&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
fpop();
|
||||
return;
|
||||
case 0xde:
|
||||
fdiv(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
fpop();
|
||||
return;
|
||||
case 0xdf:
|
||||
fdiv(PST(code & 7),PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
fpop();
|
||||
return;
|
||||
case 0xf8:
|
||||
printk("ffree not implemented\n\r");
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
fpop();
|
||||
return;
|
||||
case 0xf9:
|
||||
fxchg(&ST(0),&ST(code & 7));
|
||||
return;
|
||||
case 0xfa:
|
||||
case 0xfb:
|
||||
ST(code & 7) = ST(0);
|
||||
fpop();
|
||||
return;
|
||||
}
|
||||
switch ((code>>3) & 0xe7) {
|
||||
case 0x22:
|
||||
put_short_real(PST(0),info,code);
|
||||
return;
|
||||
case 0x23:
|
||||
put_short_real(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
case 0x24:
|
||||
address = ea(info,code);
|
||||
for (code = 0 ; code < 7 ; code++) {
|
||||
((long *) & I387)[code] =
|
||||
get_fs_long((unsigned long *) address);
|
||||
address += 4;
|
||||
}
|
||||
return;
|
||||
case 0x25:
|
||||
address = ea(info,code);
|
||||
*(unsigned short *) &I387.cwd =
|
||||
get_fs_word((unsigned short *) address);
|
||||
return;
|
||||
case 0x26:
|
||||
address = ea(info,code);
|
||||
verify_area(address,28);
|
||||
for (code = 0 ; code < 7 ; code++) {
|
||||
put_fs_long( ((long *) & I387)[code],
|
||||
(unsigned long *) address);
|
||||
address += 4;
|
||||
}
|
||||
return;
|
||||
case 0x27:
|
||||
address = ea(info,code);
|
||||
verify_area(address,2);
|
||||
put_fs_word(I387.cwd,(short *) address);
|
||||
return;
|
||||
case 0x62:
|
||||
put_long_int(PST(0),info,code);
|
||||
return;
|
||||
case 0x63:
|
||||
put_long_int(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
case 0x65:
|
||||
fpush();
|
||||
get_temp_real(&tmp,info,code);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x67:
|
||||
put_temp_real(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
case 0xa2:
|
||||
put_long_real(PST(0),info,code);
|
||||
return;
|
||||
case 0xa3:
|
||||
put_long_real(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
case 0xa4:
|
||||
address = ea(info,code);
|
||||
for (code = 0 ; code < 27 ; code++) {
|
||||
((long *) & I387)[code] =
|
||||
get_fs_long((unsigned long *) address);
|
||||
address += 4;
|
||||
}
|
||||
return;
|
||||
case 0xa6:
|
||||
address = ea(info,code);
|
||||
verify_area(address,108);
|
||||
for (code = 0 ; code < 27 ; code++) {
|
||||
put_fs_long( ((long *) & I387)[code],
|
||||
(unsigned long *) address);
|
||||
address += 4;
|
||||
}
|
||||
I387.cwd = 0x037f;
|
||||
I387.swd = 0x0000;
|
||||
I387.twd = 0x0000;
|
||||
return;
|
||||
case 0xa7:
|
||||
address = ea(info,code);
|
||||
verify_area(address,2);
|
||||
put_fs_word(I387.swd,(short *) address);
|
||||
return;
|
||||
case 0xe2:
|
||||
put_short_int(PST(0),info,code);
|
||||
return;
|
||||
case 0xe3:
|
||||
put_short_int(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
case 0xe4:
|
||||
fpush();
|
||||
get_BCD(&tmp,info,code);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0xe5:
|
||||
fpush();
|
||||
get_longlong_int(&tmp,info,code);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0xe6:
|
||||
put_BCD(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
case 0xe7:
|
||||
put_longlong_int(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
}
|
||||
switch (code >> 9) {
|
||||
case 0:
|
||||
get_short_real(&tmp,info,code);
|
||||
break;
|
||||
case 1:
|
||||
get_long_int(&tmp,info,code);
|
||||
break;
|
||||
case 2:
|
||||
get_long_real(&tmp,info,code);
|
||||
break;
|
||||
case 4:
|
||||
get_short_int(&tmp,info,code);
|
||||
}
|
||||
switch ((code>>3) & 0x27) {
|
||||
case 0:
|
||||
fadd(&tmp,PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 1:
|
||||
fmul(&tmp,PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 2:
|
||||
fcom(&tmp,PST(0));
|
||||
return;
|
||||
case 3:
|
||||
fcom(&tmp,PST(0));
|
||||
fpop();
|
||||
return;
|
||||
case 4:
|
||||
tmp.exponent ^= 0x8000;
|
||||
fadd(&tmp,PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 5:
|
||||
ST(0).exponent ^= 0x8000;
|
||||
fadd(&tmp,PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 6:
|
||||
fdiv(PST(0),&tmp,&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 7:
|
||||
fdiv(&tmp,PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
}
|
||||
if ((code & 0x138) == 0x100) {
|
||||
fpush();
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
}
|
||||
printk("Unknown math-insns: %04x:%08x %04x\n\r",CS,EIP,code);
|
||||
math_abort(info,1<<(SIGFPE-1));
|
||||
}
|
||||
|
||||
void math_emulate(long ___false)
|
||||
{
|
||||
if (!current->used_math) {
|
||||
current->used_math = 1;
|
||||
I387.cwd = 0x037f;
|
||||
I387.swd = 0x0000;
|
||||
I387.twd = 0x0000;
|
||||
}
|
||||
/* &___false points to info->___orig_eip, so subtract 1 to get info */
|
||||
do_emu((struct info *) ((&___false) - 1));
|
||||
}
|
||||
|
||||
void __math_abort(struct info * info, unsigned int signal)
|
||||
{
|
||||
EIP = ORIG_EIP;
|
||||
current->signal |= signal;
|
||||
__asm__("movl %0,%%esp ; ret"::"g" ((long) info));
|
||||
}
|
||||
|
||||
static void fpop(void)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
tmp = I387.swd & 0xffffc7ff;
|
||||
I387.swd += 0x00000800;
|
||||
I387.swd &= 0x00003800;
|
||||
I387.swd |= tmp;
|
||||
}
|
||||
|
||||
static void fpush(void)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
tmp = I387.swd & 0xffffc7ff;
|
||||
I387.swd += 0x00003800;
|
||||
I387.swd &= 0x00003800;
|
||||
I387.swd |= tmp;
|
||||
}
|
||||
|
||||
static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b)
|
||||
{
|
||||
temp_real_unaligned c;
|
||||
|
||||
c = *a;
|
||||
*a = *b;
|
||||
*b = c;
|
||||
}
|
||||
|
||||
static temp_real_unaligned * __st(int i)
|
||||
{
|
||||
i += I387.swd >> 11;
|
||||
i &= 7;
|
||||
return (temp_real_unaligned *) (i*10 + (char *)(I387.st_space));
|
||||
}
|
||||
73
Book-Lite/linux-0.12/kernel/math/mul.c
Normal file
73
Book-Lite/linux-0.12/kernel/math/mul.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* linux/kernel/math/mul.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* temporary real multiplication routine.
|
||||
*/
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
|
||||
static void shift(int * c)
|
||||
{
|
||||
__asm__("movl (%0),%%eax ; addl %%eax,(%0)\n\t"
|
||||
"movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t"
|
||||
"movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t"
|
||||
"movl 12(%0),%%eax ; adcl %%eax,12(%0)"
|
||||
::"r" ((long) c):"ax");
|
||||
}
|
||||
|
||||
static void mul64(const temp_real * a, const temp_real * b, int * c)
|
||||
{
|
||||
__asm__("movl (%0),%%eax\n\t"
|
||||
"mull (%1)\n\t"
|
||||
"movl %%eax,(%2)\n\t"
|
||||
"movl %%edx,4(%2)\n\t"
|
||||
"movl 4(%0),%%eax\n\t"
|
||||
"mull 4(%1)\n\t"
|
||||
"movl %%eax,8(%2)\n\t"
|
||||
"movl %%edx,12(%2)\n\t"
|
||||
"movl (%0),%%eax\n\t"
|
||||
"mull 4(%1)\n\t"
|
||||
"addl %%eax,4(%2)\n\t"
|
||||
"adcl %%edx,8(%2)\n\t"
|
||||
"adcl $0,12(%2)\n\t"
|
||||
"movl 4(%0),%%eax\n\t"
|
||||
"mull (%1)\n\t"
|
||||
"addl %%eax,4(%2)\n\t"
|
||||
"adcl %%edx,8(%2)\n\t"
|
||||
"adcl $0,12(%2)"
|
||||
::"b" ((long) a),"c" ((long) b),"D" ((long) c)
|
||||
:"ax","dx");
|
||||
}
|
||||
|
||||
void fmul(const temp_real * src1, const temp_real * src2, temp_real * result)
|
||||
{
|
||||
int i,sign;
|
||||
int tmp[4] = {0,0,0,0};
|
||||
|
||||
sign = (src1->exponent ^ src2->exponent) & 0x8000;
|
||||
i = (src1->exponent & 0x7fff) + (src2->exponent & 0x7fff) - 16383 + 1;
|
||||
if (i<0) {
|
||||
result->exponent = sign;
|
||||
result->a = result->b = 0;
|
||||
return;
|
||||
}
|
||||
if (i>0x7fff) {
|
||||
set_OE();
|
||||
return;
|
||||
}
|
||||
mul64(src1,src2,tmp);
|
||||
if (tmp[0] || tmp[1] || tmp[2] || tmp[3])
|
||||
while (i && tmp[3] >= 0) {
|
||||
i--;
|
||||
shift(tmp);
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
result->exponent = i | sign;
|
||||
result->a = tmp[2];
|
||||
result->b = tmp[3];
|
||||
}
|
||||
58
Book-Lite/linux-0.12/kernel/mktime.c
Normal file
58
Book-Lite/linux-0.12/kernel/mktime.c
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* linux/kernel/mktime.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/*
|
||||
* This isn't the library routine, it is only used in the kernel.
|
||||
* as such, we don't care about years<1970 etc, but assume everything
|
||||
* is ok. Similarly, TZ etc is happily ignored. We just do everything
|
||||
* as easily as possible. Let's find something public for the library
|
||||
* routines (although I think minix times is public).
|
||||
*/
|
||||
/*
|
||||
* PS. I hate whoever though up the year 1970 - couldn't they have gotten
|
||||
* a leap-year instead? I also hate Gregorius, pope or no. I'm grumpy.
|
||||
*/
|
||||
#define MINUTE 60
|
||||
#define HOUR (60*MINUTE)
|
||||
#define DAY (24*HOUR)
|
||||
#define YEAR (365*DAY)
|
||||
|
||||
/* interestingly, we assume leap-years */
|
||||
static int month[12] = {
|
||||
0,
|
||||
DAY*(31),
|
||||
DAY*(31+29),
|
||||
DAY*(31+29+31),
|
||||
DAY*(31+29+31+30),
|
||||
DAY*(31+29+31+30+31),
|
||||
DAY*(31+29+31+30+31+30),
|
||||
DAY*(31+29+31+30+31+30+31),
|
||||
DAY*(31+29+31+30+31+30+31+31),
|
||||
DAY*(31+29+31+30+31+30+31+31+30),
|
||||
DAY*(31+29+31+30+31+30+31+31+30+31),
|
||||
DAY*(31+29+31+30+31+30+31+31+30+31+30)
|
||||
};
|
||||
|
||||
long kernel_mktime(struct tm * tm)
|
||||
{
|
||||
long res;
|
||||
int year;
|
||||
|
||||
year = tm->tm_year - 70;
|
||||
/* magic offsets (y+1) needed to get leapyears right.*/
|
||||
res = YEAR*year + DAY*((year+1)/4);
|
||||
res += month[tm->tm_mon];
|
||||
/* and (y+2) here. If it wasn't a leap-year, we have to adjust */
|
||||
if (tm->tm_mon>1 && ((year+2)%4))
|
||||
res -= DAY;
|
||||
res += DAY*(tm->tm_mday-1);
|
||||
res += HOUR*tm->tm_hour;
|
||||
res += MINUTE*tm->tm_min;
|
||||
res += tm->tm_sec;
|
||||
return res;
|
||||
}
|
||||
24
Book-Lite/linux-0.12/kernel/panic.c
Normal file
24
Book-Lite/linux-0.12/kernel/panic.c
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* linux/kernel/panic.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* This function is used through-out the kernel (includeinh mm and fs)
|
||||
* to indicate a major problem.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
void sys_sync(void); /* it's really int */
|
||||
|
||||
volatile void panic(const char * s)
|
||||
{
|
||||
printk("Kernel panic: %s\n\r",s);
|
||||
if (current == task[0])
|
||||
printk("In swapper task - not syncing\n\r");
|
||||
else
|
||||
sys_sync();
|
||||
for(;;);
|
||||
}
|
||||
31
Book-Lite/linux-0.12/kernel/printk.c
Normal file
31
Book-Lite/linux-0.12/kernel/printk.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* linux/kernel/printk.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* When in kernel-mode, we cannot use printf, as fs is liable to
|
||||
* point to 'interesting' things. Make a printf with fs-saving, and
|
||||
* all is well.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
static char buf[1024];
|
||||
|
||||
extern int vsprintf(char * buf, const char * fmt, va_list args);
|
||||
|
||||
int printk(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int i;
|
||||
|
||||
va_start(args, fmt);
|
||||
i=vsprintf(buf,fmt,args);
|
||||
va_end(args);
|
||||
console_print(buf);
|
||||
return i;
|
||||
}
|
||||
444
Book-Lite/linux-0.12/kernel/sched.c
Normal file
444
Book-Lite/linux-0.12/kernel/sched.c
Normal file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* linux/kernel/sched.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* 'sched.c' is the main kernel file. It contains scheduling primitives
|
||||
* (sleep_on, wakeup, schedule etc) as well as a number of simple system
|
||||
* call functions (type getpid(), which just extracts a field from
|
||||
* current-task
|
||||
*/
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sys.h>
|
||||
#include <linux/fdreg.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#define _S(nr) (1<<((nr)-1))
|
||||
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
|
||||
|
||||
void show_task(int nr,struct task_struct * p)
|
||||
{
|
||||
int i,j = 4096-sizeof(struct task_struct);
|
||||
|
||||
printk("%d: pid=%d, state=%d, father=%d, child=%d, ",nr,p->pid,
|
||||
p->state, p->p_pptr->pid, p->p_cptr ? p->p_cptr->pid : -1);
|
||||
i=0;
|
||||
while (i<j && !((char *)(p+1))[i])
|
||||
i++;
|
||||
printk("%d/%d chars free in kstack\n\r",i,j);
|
||||
printk(" PC=%08X.", *(1019 + (unsigned long *) p));
|
||||
if (p->p_ysptr || p->p_osptr)
|
||||
printk(" Younger sib=%d, older sib=%d\n\r",
|
||||
p->p_ysptr ? p->p_ysptr->pid : -1,
|
||||
p->p_osptr ? p->p_osptr->pid : -1);
|
||||
else
|
||||
printk("\n\r");
|
||||
}
|
||||
|
||||
void show_state(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printk("\rTask-info:\n\r");
|
||||
for (i=0;i<NR_TASKS;i++)
|
||||
if (task[i])
|
||||
show_task(i,task[i]);
|
||||
}
|
||||
|
||||
#define LATCH (1193180/HZ)
|
||||
|
||||
extern void mem_use(void);
|
||||
|
||||
extern int timer_interrupt(void);
|
||||
extern int system_call(void);
|
||||
|
||||
union task_union {
|
||||
struct task_struct task;
|
||||
char stack[PAGE_SIZE];
|
||||
};
|
||||
|
||||
static union task_union init_task = {INIT_TASK,};
|
||||
|
||||
unsigned long volatile jiffies=0;
|
||||
unsigned long startup_time=0;
|
||||
int jiffies_offset = 0; /* # clock ticks to add to get "true
|
||||
time". Should always be less than
|
||||
1 second's worth. For time fanatics
|
||||
who like to syncronize their machines
|
||||
to WWV :-) */
|
||||
|
||||
struct task_struct *current = &(init_task.task);
|
||||
struct task_struct *last_task_used_math = NULL;
|
||||
|
||||
struct task_struct * task[NR_TASKS] = {&(init_task.task), };
|
||||
|
||||
long user_stack [ PAGE_SIZE>>2 ] ;
|
||||
|
||||
struct {
|
||||
long * a;
|
||||
short b;
|
||||
} stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
|
||||
/*
|
||||
* 'math_state_restore()' saves the current math information in the
|
||||
* old math state array, and gets the new ones from the current task
|
||||
*/
|
||||
void math_state_restore()
|
||||
{
|
||||
if (last_task_used_math == current)
|
||||
return;
|
||||
__asm__("fwait");
|
||||
if (last_task_used_math) {
|
||||
__asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
|
||||
}
|
||||
last_task_used_math=current;
|
||||
if (current->used_math) {
|
||||
__asm__("frstor %0"::"m" (current->tss.i387));
|
||||
} else {
|
||||
__asm__("fninit"::);
|
||||
current->used_math=1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 'schedule()' is the scheduler function. This is GOOD CODE! There
|
||||
* probably won't be any reason to change this, as it should work well
|
||||
* in all circumstances (ie gives IO-bound processes good response etc).
|
||||
* The one thing you might take a look at is the signal-handler code here.
|
||||
*
|
||||
* NOTE!! Task 0 is the 'idle' task, which gets called when no other
|
||||
* tasks can run. It can not be killed, and it cannot sleep. The 'state'
|
||||
* information in task[0] is never used.
|
||||
*/
|
||||
void schedule(void)
|
||||
{
|
||||
int i,next,c;
|
||||
struct task_struct ** p;
|
||||
|
||||
/* check alarm, wake up any interruptible tasks that have got a signal */
|
||||
|
||||
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
|
||||
if (*p) {
|
||||
if ((*p)->timeout && (*p)->timeout < jiffies) {
|
||||
(*p)->timeout = 0;
|
||||
if ((*p)->state == TASK_INTERRUPTIBLE)
|
||||
(*p)->state = TASK_RUNNING;
|
||||
}
|
||||
if ((*p)->alarm && (*p)->alarm < jiffies) {
|
||||
(*p)->signal |= (1<<(SIGALRM-1));
|
||||
(*p)->alarm = 0;
|
||||
}
|
||||
if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
|
||||
(*p)->state==TASK_INTERRUPTIBLE)
|
||||
(*p)->state=TASK_RUNNING;
|
||||
}
|
||||
|
||||
/* this is the scheduler proper: */
|
||||
|
||||
while (1) {
|
||||
c = -1;
|
||||
next = 0;
|
||||
i = NR_TASKS;
|
||||
p = &task[NR_TASKS];
|
||||
while (--i) {
|
||||
if (!*--p)
|
||||
continue;
|
||||
if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
|
||||
c = (*p)->counter, next = i;
|
||||
}
|
||||
if (c) break;
|
||||
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
|
||||
if (*p)
|
||||
(*p)->counter = ((*p)->counter >> 1) +
|
||||
(*p)->priority;
|
||||
}
|
||||
switch_to(next);
|
||||
}
|
||||
|
||||
int sys_pause(void)
|
||||
{
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
schedule();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void __sleep_on(struct task_struct **p, int state)
|
||||
{
|
||||
struct task_struct *tmp;
|
||||
|
||||
if (!p)
|
||||
return;
|
||||
if (current == &(init_task.task))
|
||||
panic("task[0] trying to sleep");
|
||||
tmp = *p;
|
||||
*p = current;
|
||||
current->state = state;
|
||||
repeat: schedule();
|
||||
if (*p && *p != current) {
|
||||
(**p).state = 0;
|
||||
current->state = TASK_UNINTERRUPTIBLE;
|
||||
goto repeat;
|
||||
}
|
||||
if (!*p)
|
||||
printk("Warning: *P = NULL\n\r");
|
||||
if (*p = tmp)
|
||||
tmp->state=0;
|
||||
}
|
||||
|
||||
void interruptible_sleep_on(struct task_struct **p)
|
||||
{
|
||||
__sleep_on(p,TASK_INTERRUPTIBLE);
|
||||
}
|
||||
|
||||
void sleep_on(struct task_struct **p)
|
||||
{
|
||||
__sleep_on(p,TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
|
||||
void wake_up(struct task_struct **p)
|
||||
{
|
||||
if (p && *p) {
|
||||
if ((**p).state == TASK_STOPPED)
|
||||
printk("wake_up: TASK_STOPPED");
|
||||
if ((**p).state == TASK_ZOMBIE)
|
||||
printk("wake_up: TASK_ZOMBIE");
|
||||
(**p).state=0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, here are some floppy things that shouldn't be in the kernel
|
||||
* proper. They are here because the floppy needs a timer, and this
|
||||
* was the easiest way of doing it.
|
||||
*/
|
||||
static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL};
|
||||
static int mon_timer[4]={0,0,0,0};
|
||||
static int moff_timer[4]={0,0,0,0};
|
||||
unsigned char current_DOR = 0x0C;
|
||||
|
||||
int ticks_to_floppy_on(unsigned int nr)
|
||||
{
|
||||
extern unsigned char selected;
|
||||
unsigned char mask = 0x10 << nr;
|
||||
|
||||
if (nr>3)
|
||||
panic("floppy_on: nr>3");
|
||||
moff_timer[nr]=10000; /* 100 s = very big :-) */
|
||||
cli(); /* use floppy_off to turn it off */
|
||||
mask |= current_DOR;
|
||||
if (!selected) {
|
||||
mask &= 0xFC;
|
||||
mask |= nr;
|
||||
}
|
||||
if (mask != current_DOR) {
|
||||
outb(mask,FD_DOR);
|
||||
if ((mask ^ current_DOR) & 0xf0)
|
||||
mon_timer[nr] = HZ/2;
|
||||
else if (mon_timer[nr] < 2)
|
||||
mon_timer[nr] = 2;
|
||||
current_DOR = mask;
|
||||
}
|
||||
sti();
|
||||
return mon_timer[nr];
|
||||
}
|
||||
|
||||
void floppy_on(unsigned int nr)
|
||||
{
|
||||
cli();
|
||||
while (ticks_to_floppy_on(nr))
|
||||
sleep_on(nr+wait_motor);
|
||||
sti();
|
||||
}
|
||||
|
||||
void floppy_off(unsigned int nr)
|
||||
{
|
||||
moff_timer[nr]=3*HZ;
|
||||
}
|
||||
|
||||
void do_floppy_timer(void)
|
||||
{
|
||||
int i;
|
||||
unsigned char mask = 0x10;
|
||||
|
||||
for (i=0 ; i<4 ; i++,mask <<= 1) {
|
||||
if (!(mask & current_DOR))
|
||||
continue;
|
||||
if (mon_timer[i]) {
|
||||
if (!--mon_timer[i])
|
||||
wake_up(i+wait_motor);
|
||||
} else if (!moff_timer[i]) {
|
||||
current_DOR &= ~mask;
|
||||
outb(current_DOR,FD_DOR);
|
||||
} else
|
||||
moff_timer[i]--;
|
||||
}
|
||||
}
|
||||
|
||||
#define TIME_REQUESTS 64
|
||||
|
||||
static struct timer_list {
|
||||
long jiffies;
|
||||
void (*fn)();
|
||||
struct timer_list * next;
|
||||
} timer_list[TIME_REQUESTS], * next_timer = NULL;
|
||||
|
||||
void add_timer(long jiffies, void (*fn)(void))
|
||||
{
|
||||
struct timer_list * p;
|
||||
|
||||
if (!fn)
|
||||
return;
|
||||
cli();
|
||||
if (jiffies <= 0)
|
||||
(fn)();
|
||||
else {
|
||||
for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++)
|
||||
if (!p->fn)
|
||||
break;
|
||||
if (p >= timer_list + TIME_REQUESTS)
|
||||
panic("No more time requests free");
|
||||
p->fn = fn;
|
||||
p->jiffies = jiffies;
|
||||
p->next = next_timer;
|
||||
next_timer = p;
|
||||
while (p->next && p->next->jiffies < p->jiffies) {
|
||||
p->jiffies -= p->next->jiffies;
|
||||
fn = p->fn;
|
||||
p->fn = p->next->fn;
|
||||
p->next->fn = fn;
|
||||
jiffies = p->jiffies;
|
||||
p->jiffies = p->next->jiffies;
|
||||
p->next->jiffies = jiffies;
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
sti();
|
||||
}
|
||||
|
||||
void do_timer(long cpl)
|
||||
{
|
||||
static int blanked = 0;
|
||||
|
||||
if (blankcount || !blankinterval) {
|
||||
if (blanked)
|
||||
unblank_screen();
|
||||
if (blankcount)
|
||||
blankcount--;
|
||||
blanked = 0;
|
||||
} else if (!blanked) {
|
||||
blank_screen();
|
||||
blanked = 1;
|
||||
}
|
||||
if (hd_timeout)
|
||||
if (!--hd_timeout)
|
||||
hd_times_out();
|
||||
|
||||
if (beepcount)
|
||||
if (!--beepcount)
|
||||
sysbeepstop();
|
||||
|
||||
if (cpl)
|
||||
current->utime++;
|
||||
else
|
||||
current->stime++;
|
||||
|
||||
if (next_timer) {
|
||||
next_timer->jiffies--;
|
||||
while (next_timer && next_timer->jiffies <= 0) {
|
||||
void (*fn)(void);
|
||||
|
||||
fn = next_timer->fn;
|
||||
next_timer->fn = NULL;
|
||||
next_timer = next_timer->next;
|
||||
(fn)();
|
||||
}
|
||||
}
|
||||
if (current_DOR & 0xf0)
|
||||
do_floppy_timer();
|
||||
if ((--current->counter)>0) return;
|
||||
current->counter=0;
|
||||
if (!cpl) return;
|
||||
schedule();
|
||||
}
|
||||
|
||||
int sys_alarm(long seconds)
|
||||
{
|
||||
int old = current->alarm;
|
||||
|
||||
if (old)
|
||||
old = (old - jiffies) / HZ;
|
||||
current->alarm = (seconds>0)?(jiffies+HZ*seconds):0;
|
||||
return (old);
|
||||
}
|
||||
|
||||
int sys_getpid(void)
|
||||
{
|
||||
return current->pid;
|
||||
}
|
||||
|
||||
int sys_getppid(void)
|
||||
{
|
||||
return current->p_pptr->pid;
|
||||
}
|
||||
|
||||
int sys_getuid(void)
|
||||
{
|
||||
return current->uid;
|
||||
}
|
||||
|
||||
int sys_geteuid(void)
|
||||
{
|
||||
return current->euid;
|
||||
}
|
||||
|
||||
int sys_getgid(void)
|
||||
{
|
||||
return current->gid;
|
||||
}
|
||||
|
||||
int sys_getegid(void)
|
||||
{
|
||||
return current->egid;
|
||||
}
|
||||
|
||||
int sys_nice(long increment)
|
||||
{
|
||||
if (current->priority-increment>0)
|
||||
current->priority -= increment;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sched_init(void)
|
||||
{
|
||||
int i;
|
||||
struct desc_struct * p;
|
||||
|
||||
if (sizeof(struct sigaction) != 16)
|
||||
panic("Struct sigaction MUST be 16 bytes");
|
||||
set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
|
||||
set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
|
||||
p = gdt+2+FIRST_TSS_ENTRY;
|
||||
for(i=1;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");
|
||||
ltr(0);
|
||||
lldt(0);
|
||||
outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
|
||||
outb_p(LATCH & 0xff , 0x40); /* LSB */
|
||||
outb(LATCH >> 8 , 0x40); /* MSB */
|
||||
set_intr_gate(0x20,&timer_interrupt);
|
||||
outb(inb_p(0x21)&~0x01,0x21);
|
||||
set_system_gate(0x80,&system_call);
|
||||
}
|
||||
209
Book-Lite/linux-0.12/kernel/signal.c
Normal file
209
Book-Lite/linux-0.12/kernel/signal.c
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* linux/kernel/signal.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
int sys_sgetmask()
|
||||
{
|
||||
return current->blocked;
|
||||
}
|
||||
|
||||
int sys_ssetmask(int newmask)
|
||||
{
|
||||
int old=current->blocked;
|
||||
|
||||
current->blocked = newmask & ~(1<<(SIGKILL-1)) & ~(1<<(SIGSTOP-1));
|
||||
return old;
|
||||
}
|
||||
|
||||
int sys_sigpending(sigset_t *set)
|
||||
{
|
||||
/* fill in "set" with signals pending but blocked. */
|
||||
verify_area(set,4);
|
||||
put_fs_long(current->blocked & current->signal, (unsigned long *)set);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* atomically swap in the new signal mask, and wait for a signal.
|
||||
*
|
||||
* we need to play some games with syscall restarting. We get help
|
||||
* from the syscall library interface. Note that we need to coordinate
|
||||
* the calling convention with the libc routine.
|
||||
*
|
||||
* "set" is just the sigmask as described in 1003.1-1988, 3.3.7.
|
||||
* It is assumed that sigset_t can be passed as a 32 bit quantity.
|
||||
*
|
||||
* "restart" holds a restart indication. If it's non-zero, then we
|
||||
* install the old mask, and return normally. If it's zero, we store
|
||||
* the current mask in old_mask and block until a signal comes in.
|
||||
*/
|
||||
int sys_sigsuspend(int restart, unsigned long old_mask, unsigned long set)
|
||||
{
|
||||
extern int sys_pause(void);
|
||||
|
||||
if (restart) {
|
||||
/* we're restarting */
|
||||
current->blocked = old_mask;
|
||||
return -EINTR;
|
||||
}
|
||||
/* we're not restarting. do the work */
|
||||
*(&restart) = 1;
|
||||
*(&old_mask) = current->blocked;
|
||||
current->blocked = set;
|
||||
(void) sys_pause(); /* return after a signal arrives */
|
||||
return -ERESTARTNOINTR; /* handle the signal, and come back */
|
||||
}
|
||||
|
||||
static inline void save_old(char * from,char * to)
|
||||
{
|
||||
int i;
|
||||
|
||||
verify_area(to, sizeof(struct sigaction));
|
||||
for (i=0 ; i< sizeof(struct sigaction) ; i++) {
|
||||
put_fs_byte(*from,to);
|
||||
from++;
|
||||
to++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void get_new(char * from,char * to)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i< sizeof(struct sigaction) ; i++)
|
||||
*(to++) = get_fs_byte(from++);
|
||||
}
|
||||
|
||||
int sys_signal(int signum, long handler, long restorer)
|
||||
{
|
||||
struct sigaction tmp;
|
||||
|
||||
if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
|
||||
return -EINVAL;
|
||||
tmp.sa_handler = (void (*)(int)) handler;
|
||||
tmp.sa_mask = 0;
|
||||
tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
|
||||
tmp.sa_restorer = (void (*)(void)) restorer;
|
||||
handler = (long) current->sigaction[signum-1].sa_handler;
|
||||
current->sigaction[signum-1] = tmp;
|
||||
return handler;
|
||||
}
|
||||
|
||||
int sys_sigaction(int signum, const struct sigaction * action,
|
||||
struct sigaction * oldaction)
|
||||
{
|
||||
struct sigaction tmp;
|
||||
|
||||
if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
|
||||
return -EINVAL;
|
||||
tmp = current->sigaction[signum-1];
|
||||
get_new((char *) action,
|
||||
(char *) (signum-1+current->sigaction));
|
||||
if (oldaction)
|
||||
save_old((char *) &tmp,(char *) oldaction);
|
||||
if (current->sigaction[signum-1].sa_flags & SA_NOMASK)
|
||||
current->sigaction[signum-1].sa_mask = 0;
|
||||
else
|
||||
current->sigaction[signum-1].sa_mask |= (1<<(signum-1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine writes a core dump image in the current directory.
|
||||
* Currently not implemented.
|
||||
*/
|
||||
int core_dump(long signr)
|
||||
{
|
||||
return(0); /* We didn't do a dump */
|
||||
}
|
||||
|
||||
int do_signal(long signr,long eax,long ebx, long ecx, long edx, long orig_eax,
|
||||
long fs, long es, long ds,
|
||||
long eip, long cs, long eflags,
|
||||
unsigned long * esp, long ss)
|
||||
{
|
||||
unsigned long sa_handler;
|
||||
long old_eip=eip;
|
||||
struct sigaction * sa = current->sigaction + signr - 1;
|
||||
int longs;
|
||||
|
||||
unsigned long * tmp_esp;
|
||||
|
||||
#ifdef notdef
|
||||
printk("pid: %d, signr: %x, eax=%d, oeax = %d, int=%d\n",
|
||||
current->pid, signr, eax, orig_eax,
|
||||
sa->sa_flags & SA_INTERRUPT);
|
||||
#endif
|
||||
if ((orig_eax != -1) &&
|
||||
((eax == -ERESTARTSYS) || (eax == -ERESTARTNOINTR))) {
|
||||
if ((eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT) ||
|
||||
signr < SIGCONT || signr > SIGTTOU))
|
||||
*(&eax) = -EINTR;
|
||||
else {
|
||||
*(&eax) = orig_eax;
|
||||
*(&eip) = old_eip -= 2;
|
||||
}
|
||||
}
|
||||
sa_handler = (unsigned long) sa->sa_handler;
|
||||
if (sa_handler==1)
|
||||
return(1); /* Ignore, see if there are more signals... */
|
||||
if (!sa_handler) {
|
||||
switch (signr) {
|
||||
case SIGCONT:
|
||||
case SIGCHLD:
|
||||
return(1); /* Ignore, ... */
|
||||
|
||||
case SIGSTOP:
|
||||
case SIGTSTP:
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
current->state = TASK_STOPPED;
|
||||
current->exit_code = signr;
|
||||
if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
|
||||
SA_NOCLDSTOP))
|
||||
current->p_pptr->signal |= (1<<(SIGCHLD-1));
|
||||
return(1); /* Reschedule another event */
|
||||
|
||||
case SIGQUIT:
|
||||
case SIGILL:
|
||||
case SIGTRAP:
|
||||
case SIGIOT:
|
||||
case SIGFPE:
|
||||
case SIGSEGV:
|
||||
if (core_dump(signr))
|
||||
do_exit(signr|0x80);
|
||||
/* fall through */
|
||||
default:
|
||||
do_exit(signr);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* OK, we're invoking a handler
|
||||
*/
|
||||
if (sa->sa_flags & SA_ONESHOT)
|
||||
sa->sa_handler = NULL;
|
||||
*(&eip) = sa_handler;
|
||||
longs = (sa->sa_flags & SA_NOMASK)?7:8;
|
||||
*(&esp) -= longs;
|
||||
verify_area(esp,longs*4);
|
||||
tmp_esp=esp;
|
||||
put_fs_long((long) sa->sa_restorer,tmp_esp++);
|
||||
put_fs_long(signr,tmp_esp++);
|
||||
if (!(sa->sa_flags & SA_NOMASK))
|
||||
put_fs_long(current->blocked,tmp_esp++);
|
||||
put_fs_long(eax,tmp_esp++);
|
||||
put_fs_long(ecx,tmp_esp++);
|
||||
put_fs_long(edx,tmp_esp++);
|
||||
put_fs_long(eflags,tmp_esp++);
|
||||
put_fs_long(old_eip,tmp_esp++);
|
||||
current->blocked |= sa->sa_mask;
|
||||
return(0); /* Continue, execute handler */
|
||||
}
|
||||
522
Book-Lite/linux-0.12/kernel/sys.c
Normal file
522
Book-Lite/linux-0.12/kernel/sys.c
Normal file
@@ -0,0 +1,522 @@
|
||||
/*
|
||||
* linux/kernel/sys.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/config.h>
|
||||
#include <asm/segment.h>
|
||||
#include <sys/times.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/resource.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* The timezone where the local system is located. Used as a default by some
|
||||
* programs who obtain this value by using gettimeofday.
|
||||
*/
|
||||
struct timezone sys_tz = { 0, 0};
|
||||
|
||||
extern int session_of_pgrp(int pgrp);
|
||||
|
||||
int sys_ftime()
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int sys_break()
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int sys_ptrace()
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int sys_stty()
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int sys_gtty()
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int sys_rename()
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int sys_prof()
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is done BSD-style, with no consideration of the saved gid, except
|
||||
* that if you set the effective gid, it sets the saved gid too. This
|
||||
* makes it possible for a setgid program to completely drop its privileges,
|
||||
* which is often a useful assertion to make when you are doing a security
|
||||
* audit over a program.
|
||||
*
|
||||
* The general idea is that a program which uses just setregid() will be
|
||||
* 100% compatible with BSD. A program which uses just setgid() will be
|
||||
* 100% compatible with POSIX w/ Saved ID's.
|
||||
*/
|
||||
int sys_setregid(int rgid, int egid)
|
||||
{
|
||||
if (rgid>0) {
|
||||
if ((current->gid == rgid) ||
|
||||
suser())
|
||||
current->gid = rgid;
|
||||
else
|
||||
return(-EPERM);
|
||||
}
|
||||
if (egid>0) {
|
||||
if ((current->gid == egid) ||
|
||||
(current->egid == egid) ||
|
||||
suser()) {
|
||||
current->egid = egid;
|
||||
current->sgid = egid;
|
||||
} else
|
||||
return(-EPERM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* setgid() is implemeneted like SysV w/ SAVED_IDS
|
||||
*/
|
||||
int sys_setgid(int gid)
|
||||
{
|
||||
if (suser())
|
||||
current->gid = current->egid = current->sgid = gid;
|
||||
else if ((gid == current->gid) || (gid == current->sgid))
|
||||
current->egid = gid;
|
||||
else
|
||||
return -EPERM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_acct()
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int sys_phys()
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int sys_lock()
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int sys_mpx()
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int sys_ulimit()
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int sys_time(long * tloc)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = CURRENT_TIME;
|
||||
if (tloc) {
|
||||
verify_area(tloc,4);
|
||||
put_fs_long(i,(unsigned long *)tloc);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unprivileged users may change the real user id to the effective uid
|
||||
* or vice versa. (BSD-style)
|
||||
*
|
||||
* When you set the effective uid, it sets the saved uid too. This
|
||||
* makes it possible for a setuid program to completely drop its privileges,
|
||||
* which is often a useful assertion to make when you are doing a security
|
||||
* audit over a program.
|
||||
*
|
||||
* The general idea is that a program which uses just setreuid() will be
|
||||
* 100% compatible with BSD. A program which uses just setuid() will be
|
||||
* 100% compatible with POSIX w/ Saved ID's.
|
||||
*/
|
||||
int sys_setreuid(int ruid, int euid)
|
||||
{
|
||||
int old_ruid = current->uid;
|
||||
|
||||
if (ruid>0) {
|
||||
if ((current->euid==ruid) ||
|
||||
(old_ruid == ruid) ||
|
||||
suser())
|
||||
current->uid = ruid;
|
||||
else
|
||||
return(-EPERM);
|
||||
}
|
||||
if (euid>0) {
|
||||
if ((old_ruid == euid) ||
|
||||
(current->euid == euid) ||
|
||||
suser()) {
|
||||
current->euid = euid;
|
||||
current->suid = euid;
|
||||
} else {
|
||||
current->uid = old_ruid;
|
||||
return(-EPERM);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* setuid() is implemeneted like SysV w/ SAVED_IDS
|
||||
*
|
||||
* Note that SAVED_ID's is deficient in that a setuid root program
|
||||
* like sendmail, for example, cannot set its uid to be a normal
|
||||
* user and then switch back, because if you're root, setuid() sets
|
||||
* the saved uid too. If you don't like this, blame the bright people
|
||||
* in the POSIX commmittee and/or USG. Note that the BSD-style setreuid()
|
||||
* will allow a root program to temporarily drop privileges and be able to
|
||||
* regain them by swapping the real and effective uid.
|
||||
*/
|
||||
int sys_setuid(int uid)
|
||||
{
|
||||
if (suser())
|
||||
current->uid = current->euid = current->suid = uid;
|
||||
else if ((uid == current->uid) || (uid == current->suid))
|
||||
current->euid = uid;
|
||||
else
|
||||
return -EPERM;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int sys_stime(long * tptr)
|
||||
{
|
||||
if (!suser())
|
||||
return -EPERM;
|
||||
startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ;
|
||||
jiffies_offset = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_times(struct tms * tbuf)
|
||||
{
|
||||
if (tbuf) {
|
||||
verify_area(tbuf,sizeof *tbuf);
|
||||
put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime);
|
||||
put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime);
|
||||
put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime);
|
||||
put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime);
|
||||
}
|
||||
return jiffies;
|
||||
}
|
||||
|
||||
int sys_brk(unsigned long end_data_seg)
|
||||
{
|
||||
if (end_data_seg >= current->end_code &&
|
||||
end_data_seg < current->start_stack - 16384)
|
||||
current->brk = end_data_seg;
|
||||
return current->brk;
|
||||
}
|
||||
|
||||
/*
|
||||
* This needs some heave checking ...
|
||||
* I just haven't get the stomach for it. I also don't fully
|
||||
* understand sessions/pgrp etc. Let somebody who does explain it.
|
||||
*
|
||||
* OK, I think I have the protection semantics right.... this is really
|
||||
* only important on a multi-user system anyway, to make sure one user
|
||||
* can't send a signal to a process owned by another. -TYT, 12/12/91
|
||||
*/
|
||||
int sys_setpgid(int pid, int pgid)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!pid)
|
||||
pid = current->pid;
|
||||
if (!pgid)
|
||||
pgid = current->pid;
|
||||
if (pgid < 0)
|
||||
return -EINVAL;
|
||||
for (i=0 ; i<NR_TASKS ; i++)
|
||||
if (task[i] && (task[i]->pid == pid) &&
|
||||
((task[i]->p_pptr == current) ||
|
||||
(task[i] == current))) {
|
||||
if (task[i]->leader)
|
||||
return -EPERM;
|
||||
if ((task[i]->session != current->session) ||
|
||||
((pgid != pid) &&
|
||||
(session_of_pgrp(pgid) != current->session)))
|
||||
return -EPERM;
|
||||
task[i]->pgrp = pgid;
|
||||
return 0;
|
||||
}
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
int sys_getpgrp(void)
|
||||
{
|
||||
return current->pgrp;
|
||||
}
|
||||
|
||||
int sys_setsid(void)
|
||||
{
|
||||
if (current->leader && !suser())
|
||||
return -EPERM;
|
||||
current->leader = 1;
|
||||
current->session = current->pgrp = current->pid;
|
||||
current->tty = -1;
|
||||
return current->pgrp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Supplementary group ID's
|
||||
*/
|
||||
int sys_getgroups(int gidsetsize, gid_t *grouplist)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (gidsetsize)
|
||||
verify_area(grouplist, sizeof(gid_t) * gidsetsize);
|
||||
|
||||
for (i = 0; (i < NGROUPS) && (current->groups[i] != NOGROUP);
|
||||
i++, grouplist++) {
|
||||
if (gidsetsize) {
|
||||
if (i >= gidsetsize)
|
||||
return -EINVAL;
|
||||
put_fs_word(current->groups[i], (short *) grouplist);
|
||||
}
|
||||
}
|
||||
return(i);
|
||||
}
|
||||
|
||||
int sys_setgroups(int gidsetsize, gid_t *grouplist)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!suser())
|
||||
return -EPERM;
|
||||
if (gidsetsize > NGROUPS)
|
||||
return -EINVAL;
|
||||
for (i = 0; i < gidsetsize; i++, grouplist++) {
|
||||
current->groups[i] = get_fs_word((unsigned short *) grouplist);
|
||||
}
|
||||
if (i < NGROUPS)
|
||||
current->groups[i] = NOGROUP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int in_group_p(gid_t grp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (grp == current->egid)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < NGROUPS; i++) {
|
||||
if (current->groups[i] == NOGROUP)
|
||||
break;
|
||||
if (current->groups[i] == grp)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct utsname thisname = {
|
||||
UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION, UTS_MACHINE
|
||||
};
|
||||
|
||||
int sys_uname(struct utsname * name)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!name) return -ERROR;
|
||||
verify_area(name,sizeof *name);
|
||||
for(i=0;i<sizeof *name;i++)
|
||||
put_fs_byte(((char *) &thisname)[i],i+(char *) name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only sethostname; gethostname can be implemented by calling uname()
|
||||
*/
|
||||
int sys_sethostname(char *name, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!suser())
|
||||
return -EPERM;
|
||||
if (len > MAXHOSTNAMELEN)
|
||||
return -EINVAL;
|
||||
for (i=0; i < len; i++) {
|
||||
if ((thisname.nodename[i] = get_fs_byte(name+i)) == 0)
|
||||
break;
|
||||
}
|
||||
if (thisname.nodename[i]) {
|
||||
thisname.nodename[i>MAXHOSTNAMELEN ? MAXHOSTNAMELEN : i] = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_getrlimit(int resource, struct rlimit *rlim)
|
||||
{
|
||||
if (resource >= RLIM_NLIMITS)
|
||||
return -EINVAL;
|
||||
verify_area(rlim,sizeof *rlim);
|
||||
put_fs_long(current->rlim[resource].rlim_cur,
|
||||
(unsigned long *) rlim);
|
||||
put_fs_long(current->rlim[resource].rlim_max,
|
||||
((unsigned long *) rlim)+1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_setrlimit(int resource, struct rlimit *rlim)
|
||||
{
|
||||
struct rlimit new, *old;
|
||||
|
||||
if (resource >= RLIM_NLIMITS)
|
||||
return -EINVAL;
|
||||
old = current->rlim + resource;
|
||||
new.rlim_cur = get_fs_long((unsigned long *) rlim);
|
||||
new.rlim_max = get_fs_long(((unsigned long *) rlim)+1);
|
||||
if (((new.rlim_cur > old->rlim_max) ||
|
||||
(new.rlim_max > old->rlim_max)) &&
|
||||
!suser())
|
||||
return -EPERM;
|
||||
*old = new;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* It would make sense to put struct rusuage in the task_struct,
|
||||
* except that would make the task_struct be *really big*. After
|
||||
* task_struct gets moved into malloc'ed memory, it would
|
||||
* make sense to do this. It will make moving the rest of the information
|
||||
* a lot simpler! (Which we're not doing right now because we're not
|
||||
* measuring them yet).
|
||||
*/
|
||||
int sys_getrusage(int who, struct rusage *ru)
|
||||
{
|
||||
struct rusage r;
|
||||
unsigned long *lp, *lpend, *dest;
|
||||
|
||||
if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
|
||||
return -EINVAL;
|
||||
verify_area(ru, sizeof *ru);
|
||||
memset((char *) &r, 0, sizeof(r));
|
||||
if (who == RUSAGE_SELF) {
|
||||
r.ru_utime.tv_sec = CT_TO_SECS(current->utime);
|
||||
r.ru_utime.tv_usec = CT_TO_USECS(current->utime);
|
||||
r.ru_stime.tv_sec = CT_TO_SECS(current->stime);
|
||||
r.ru_stime.tv_usec = CT_TO_USECS(current->stime);
|
||||
} else {
|
||||
r.ru_utime.tv_sec = CT_TO_SECS(current->cutime);
|
||||
r.ru_utime.tv_usec = CT_TO_USECS(current->cutime);
|
||||
r.ru_stime.tv_sec = CT_TO_SECS(current->cstime);
|
||||
r.ru_stime.tv_usec = CT_TO_USECS(current->cstime);
|
||||
}
|
||||
lp = (unsigned long *) &r;
|
||||
lpend = (unsigned long *) (&r+1);
|
||||
dest = (unsigned long *) ru;
|
||||
for (; lp < lpend; lp++, dest++)
|
||||
put_fs_long(*lp, dest);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||
{
|
||||
if (tv) {
|
||||
verify_area(tv, sizeof *tv);
|
||||
put_fs_long(startup_time + CT_TO_SECS(jiffies+jiffies_offset),
|
||||
(unsigned long *) tv);
|
||||
put_fs_long(CT_TO_USECS(jiffies+jiffies_offset),
|
||||
((unsigned long *) tv)+1);
|
||||
}
|
||||
if (tz) {
|
||||
verify_area(tz, sizeof *tz);
|
||||
put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz);
|
||||
put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The first time we set the timezone, we will warp the clock so that
|
||||
* it is ticking GMT time instead of local time. Presumably,
|
||||
* if someone is setting the timezone then we are running in an
|
||||
* environment where the programs understand about timezones.
|
||||
* This should be done at boot time in the /etc/rc script, as
|
||||
* soon as possible, so that the clock can be set right. Otherwise,
|
||||
* various programs will get confused when the clock gets warped.
|
||||
*/
|
||||
int sys_settimeofday(struct timeval *tv, struct timezone *tz)
|
||||
{
|
||||
static int firsttime = 1;
|
||||
void adjust_clock();
|
||||
|
||||
if (!suser())
|
||||
return -EPERM;
|
||||
if (tz) {
|
||||
sys_tz.tz_minuteswest = get_fs_long((unsigned long *) tz);
|
||||
sys_tz.tz_dsttime = get_fs_long(((unsigned long *) tz)+1);
|
||||
if (firsttime) {
|
||||
firsttime = 0;
|
||||
if (!tv)
|
||||
adjust_clock();
|
||||
}
|
||||
}
|
||||
if (tv) {
|
||||
int sec, usec;
|
||||
|
||||
sec = get_fs_long((unsigned long *)tv);
|
||||
usec = get_fs_long(((unsigned long *)tv)+1);
|
||||
|
||||
startup_time = sec - jiffies/HZ;
|
||||
jiffies_offset = usec * HZ / 1000000 - jiffies%HZ;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the time obtained from the CMOS to be GMT time instead of
|
||||
* local time.
|
||||
*
|
||||
* This is ugly, but preferable to the alternatives. Otherwise we
|
||||
* would either need to write a program to do it in /etc/rc (and risk
|
||||
* confusion if the program gets run more than once; it would also be
|
||||
* hard to make the program warp the clock precisely n hours) or
|
||||
* compile in the timezone information into the kernel. Bad, bad....
|
||||
*
|
||||
* XXX Currently does not adjust for daylight savings time. May not
|
||||
* need to do anything, depending on how smart (dumb?) the BIOS
|
||||
* is. Blast it all.... the best thing to do not depend on the CMOS
|
||||
* clock at all, but get the time via NTP or timed if you're on a
|
||||
* network.... - TYT, 1/1/92
|
||||
*/
|
||||
void adjust_clock()
|
||||
{
|
||||
startup_time += sys_tz.tz_minuteswest*60;
|
||||
}
|
||||
|
||||
int sys_umask(int mask)
|
||||
{
|
||||
int old = current->umask;
|
||||
|
||||
current->umask = mask & 0777;
|
||||
return (old);
|
||||
}
|
||||
|
||||
300
Book-Lite/linux-0.12/kernel/sys_call.s
Normal file
300
Book-Lite/linux-0.12/kernel/sys_call.s
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* linux/kernel/system_call.s
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* system_call.s contains the system-call low-level handling routines.
|
||||
* This also contains the timer-interrupt handler, as some of the code is
|
||||
* the same. The hd- and flopppy-interrupts are also here.
|
||||
*
|
||||
* NOTE: This code handles signal-recognition, which happens every time
|
||||
* after a timer-interrupt and after each system call. Ordinary interrupts
|
||||
* don't handle signal-recognition, as that would clutter them up totally
|
||||
* unnecessarily.
|
||||
*
|
||||
* Stack layout in 'ret_from_system_call':
|
||||
*
|
||||
* 0(%esp) - %eax
|
||||
* 4(%esp) - %ebx
|
||||
* 8(%esp) - %ecx
|
||||
* C(%esp) - %edx
|
||||
* 10(%esp) - original %eax (-1 if not system call)
|
||||
* 14(%esp) - %fs
|
||||
* 18(%esp) - %es
|
||||
* 1C(%esp) - %ds
|
||||
* 20(%esp) - %eip
|
||||
* 24(%esp) - %cs
|
||||
* 28(%esp) - %eflags
|
||||
* 2C(%esp) - %oldesp
|
||||
* 30(%esp) - %oldss
|
||||
*/
|
||||
|
||||
SIG_CHLD = 17
|
||||
|
||||
EAX = 0x00
|
||||
EBX = 0x04
|
||||
ECX = 0x08
|
||||
EDX = 0x0C
|
||||
ORIG_EAX = 0x10
|
||||
FS = 0x14
|
||||
ES = 0x18
|
||||
DS = 0x1C
|
||||
EIP = 0x20
|
||||
CS = 0x24
|
||||
EFLAGS = 0x28
|
||||
OLDESP = 0x2C
|
||||
OLDSS = 0x30
|
||||
|
||||
state = 0 # these are offsets into the task-struct.
|
||||
counter = 4
|
||||
priority = 8
|
||||
signal = 12
|
||||
sigaction = 16 # MUST be 16 (=len of sigaction)
|
||||
blocked = (33*16)
|
||||
|
||||
# offsets within sigaction
|
||||
sa_handler = 0
|
||||
sa_mask = 4
|
||||
sa_flags = 8
|
||||
sa_restorer = 12
|
||||
|
||||
nr_system_calls = 82
|
||||
|
||||
ENOSYS = 38
|
||||
|
||||
/*
|
||||
* Ok, I get parallel printer interrupts while using the floppy for some
|
||||
* strange reason. Urgel. Now I just ignore them.
|
||||
*/
|
||||
.globl _system_call,_sys_fork,_timer_interrupt,_sys_execve
|
||||
.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt
|
||||
.globl _device_not_available, _coprocessor_error
|
||||
|
||||
.align 2
|
||||
bad_sys_call:
|
||||
pushl $-ENOSYS
|
||||
jmp ret_from_sys_call
|
||||
.align 2
|
||||
reschedule:
|
||||
pushl $ret_from_sys_call
|
||||
jmp _schedule
|
||||
.align 2
|
||||
_system_call:
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
pushl %eax # save the orig_eax
|
||||
pushl %edx
|
||||
pushl %ecx # push %ebx,%ecx,%edx as parameters
|
||||
pushl %ebx # to the system call
|
||||
movl $0x10,%edx # set up ds,es to kernel space
|
||||
mov %dx,%ds
|
||||
mov %dx,%es
|
||||
movl $0x17,%edx # fs points to local data space
|
||||
mov %dx,%fs
|
||||
cmpl _NR_syscalls,%eax
|
||||
jae bad_sys_call
|
||||
call _sys_call_table(,%eax,4)
|
||||
pushl %eax
|
||||
2:
|
||||
movl _current,%eax
|
||||
cmpl $0,state(%eax) # state
|
||||
jne reschedule
|
||||
cmpl $0,counter(%eax) # counter
|
||||
je reschedule
|
||||
ret_from_sys_call:
|
||||
movl _current,%eax
|
||||
cmpl _task,%eax # task[0] cannot have signals
|
||||
je 3f
|
||||
cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
|
||||
jne 3f
|
||||
cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
|
||||
jne 3f
|
||||
movl signal(%eax),%ebx
|
||||
movl blocked(%eax),%ecx
|
||||
notl %ecx
|
||||
andl %ebx,%ecx
|
||||
bsfl %ecx,%ecx
|
||||
je 3f
|
||||
btrl %ecx,%ebx
|
||||
movl %ebx,signal(%eax)
|
||||
incl %ecx
|
||||
pushl %ecx
|
||||
call _do_signal
|
||||
popl %ecx
|
||||
testl %eax, %eax
|
||||
jne 2b # see if we need to switch tasks, or do more signals
|
||||
3: popl %eax
|
||||
popl %ebx
|
||||
popl %ecx
|
||||
popl %edx
|
||||
addl $4, %esp # skip orig_eax
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
iret
|
||||
|
||||
.align 2
|
||||
_coprocessor_error:
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
pushl $-1 # fill in -1 for orig_eax
|
||||
pushl %edx
|
||||
pushl %ecx
|
||||
pushl %ebx
|
||||
pushl %eax
|
||||
movl $0x10,%eax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
movl $0x17,%eax
|
||||
mov %ax,%fs
|
||||
pushl $ret_from_sys_call
|
||||
jmp _math_error
|
||||
|
||||
.align 2
|
||||
_device_not_available:
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
pushl $-1 # fill in -1 for orig_eax
|
||||
pushl %edx
|
||||
pushl %ecx
|
||||
pushl %ebx
|
||||
pushl %eax
|
||||
movl $0x10,%eax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
movl $0x17,%eax
|
||||
mov %ax,%fs
|
||||
pushl $ret_from_sys_call
|
||||
clts # clear TS so that we can use math
|
||||
movl %cr0,%eax
|
||||
testl $0x4,%eax # EM (math emulation bit)
|
||||
je _math_state_restore
|
||||
pushl %ebp
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl $0 # temporary storage for ORIG_EIP
|
||||
call _math_emulate
|
||||
addl $4,%esp
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
.align 2
|
||||
_timer_interrupt:
|
||||
push %ds # save ds,es and put kernel data space
|
||||
push %es # into them. %fs is used by _system_call
|
||||
push %fs
|
||||
pushl $-1 # fill in -1 for orig_eax
|
||||
pushl %edx # we save %eax,%ecx,%edx as gcc doesn't
|
||||
pushl %ecx # save those across function calls. %ebx
|
||||
pushl %ebx # is saved as we use that in ret_sys_call
|
||||
pushl %eax
|
||||
movl $0x10,%eax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
movl $0x17,%eax
|
||||
mov %ax,%fs
|
||||
incl _jiffies
|
||||
movb $0x20,%al # EOI to interrupt controller #1
|
||||
outb %al,$0x20
|
||||
movl CS(%esp),%eax
|
||||
andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor)
|
||||
pushl %eax
|
||||
call _do_timer # 'do_timer(long CPL)' does everything from
|
||||
addl $4,%esp # task switching to accounting ...
|
||||
jmp ret_from_sys_call
|
||||
|
||||
.align 2
|
||||
_sys_execve:
|
||||
lea EIP(%esp),%eax
|
||||
pushl %eax
|
||||
call _do_execve
|
||||
addl $4,%esp
|
||||
ret
|
||||
|
||||
.align 2
|
||||
_sys_fork:
|
||||
call _find_empty_process
|
||||
testl %eax,%eax
|
||||
js 1f
|
||||
push %gs
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl %ebp
|
||||
pushl %eax
|
||||
call _copy_process
|
||||
addl $20,%esp
|
||||
1: ret
|
||||
|
||||
_hd_interrupt:
|
||||
pushl %eax
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
movl $0x10,%eax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
movl $0x17,%eax
|
||||
mov %ax,%fs
|
||||
movb $0x20,%al
|
||||
outb %al,$0xA0 # EOI to interrupt controller #1
|
||||
jmp 1f # give port chance to breathe
|
||||
1: jmp 1f
|
||||
1: xorl %edx,%edx
|
||||
movl %edx,_hd_timeout
|
||||
xchgl _do_hd,%edx
|
||||
testl %edx,%edx
|
||||
jne 1f
|
||||
movl $_unexpected_hd_interrupt,%edx
|
||||
1: outb %al,$0x20
|
||||
call *%edx # "interesting" way of handling intr.
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %eax
|
||||
iret
|
||||
|
||||
_floppy_interrupt:
|
||||
pushl %eax
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
movl $0x10,%eax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
movl $0x17,%eax
|
||||
mov %ax,%fs
|
||||
movb $0x20,%al
|
||||
outb %al,$0x20 # EOI to interrupt controller #1
|
||||
xorl %eax,%eax
|
||||
xchgl _do_floppy,%eax
|
||||
testl %eax,%eax
|
||||
jne 1f
|
||||
movl $_unexpected_floppy_interrupt,%eax
|
||||
1: call *%eax # "interesting" way of handling intr.
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %eax
|
||||
iret
|
||||
|
||||
_parallel_interrupt:
|
||||
pushl %eax
|
||||
movb $0x20,%al
|
||||
outb %al,$0x20
|
||||
popl %eax
|
||||
iret
|
||||
213
Book-Lite/linux-0.12/kernel/traps.c
Normal file
213
Book-Lite/linux-0.12/kernel/traps.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* linux/kernel/traps.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* 'Traps.c' handles hardware traps and faults after we have saved some
|
||||
* state in 'asm.s'. Currently mostly a debugging-aid, will be extended
|
||||
* to mainly kill the offending process (probably by giving it a signal,
|
||||
* but possibly by killing it outright if necessary).
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/head.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define get_seg_byte(seg,addr) ({ \
|
||||
register char __res; \
|
||||
__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \
|
||||
:"=a" (__res):"0" (seg),"m" (*(addr))); \
|
||||
__res;})
|
||||
|
||||
#define get_seg_long(seg,addr) ({ \
|
||||
register unsigned long __res; \
|
||||
__asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \
|
||||
:"=a" (__res):"0" (seg),"m" (*(addr))); \
|
||||
__res;})
|
||||
|
||||
#define _fs() ({ \
|
||||
register unsigned short __res; \
|
||||
__asm__("mov %%fs,%%ax":"=a" (__res):); \
|
||||
__res;})
|
||||
|
||||
void page_exception(void);
|
||||
|
||||
void divide_error(void);
|
||||
void debug(void);
|
||||
void nmi(void);
|
||||
void int3(void);
|
||||
void overflow(void);
|
||||
void bounds(void);
|
||||
void invalid_op(void);
|
||||
void device_not_available(void);
|
||||
void double_fault(void);
|
||||
void coprocessor_segment_overrun(void);
|
||||
void invalid_TSS(void);
|
||||
void segment_not_present(void);
|
||||
void stack_segment(void);
|
||||
void general_protection(void);
|
||||
void page_fault(void);
|
||||
void coprocessor_error(void);
|
||||
void reserved(void);
|
||||
void parallel_interrupt(void);
|
||||
void irq13(void);
|
||||
void alignment_check(void);
|
||||
|
||||
static void die(char * str,long esp_ptr,long nr)
|
||||
{
|
||||
long * esp = (long *) esp_ptr;
|
||||
int i;
|
||||
|
||||
printk("%s: %04x\n\r",str,nr&0xffff);
|
||||
printk("EIP:\t%04x:%p\nEFLAGS:\t%p\nESP:\t%04x:%p\n",
|
||||
esp[1],esp[0],esp[2],esp[4],esp[3]);
|
||||
printk("fs: %04x\n",_fs());
|
||||
printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x17));
|
||||
if (esp[4] == 0x17) {
|
||||
printk("Stack: ");
|
||||
for (i=0;i<4;i++)
|
||||
printk("%p ",get_seg_long(0x17,i+(long *)esp[3]));
|
||||
printk("\n");
|
||||
}
|
||||
str(i);
|
||||
printk("Pid: %d, process nr: %d\n\r",current->pid,0xffff & i);
|
||||
for(i=0;i<10;i++)
|
||||
printk("%02x ",0xff & get_seg_byte(esp[1],(i+(char *)esp[0])));
|
||||
printk("\n\r");
|
||||
do_exit(11); /* play segment exception */
|
||||
}
|
||||
|
||||
void do_double_fault(long esp, long error_code)
|
||||
{
|
||||
die("double fault",esp,error_code);
|
||||
}
|
||||
|
||||
void do_general_protection(long esp, long error_code)
|
||||
{
|
||||
die("general protection",esp,error_code);
|
||||
}
|
||||
|
||||
void do_alignment_check(long esp, long error_code)
|
||||
{
|
||||
die("alignment check",esp,error_code);
|
||||
}
|
||||
|
||||
void do_divide_error(long esp, long error_code)
|
||||
{
|
||||
die("divide error",esp,error_code);
|
||||
}
|
||||
|
||||
void do_int3(long * esp, long error_code,
|
||||
long fs,long es,long ds,
|
||||
long ebp,long esi,long edi,
|
||||
long edx,long ecx,long ebx,long eax)
|
||||
{
|
||||
int tr;
|
||||
|
||||
__asm__("str %%ax":"=a" (tr):"0" (0));
|
||||
printk("eax\t\tebx\t\tecx\t\tedx\n\r%8x\t%8x\t%8x\t%8x\n\r",
|
||||
eax,ebx,ecx,edx);
|
||||
printk("esi\t\tedi\t\tebp\t\tesp\n\r%8x\t%8x\t%8x\t%8x\n\r",
|
||||
esi,edi,ebp,(long) esp);
|
||||
printk("\n\rds\tes\tfs\ttr\n\r%4x\t%4x\t%4x\t%4x\n\r",
|
||||
ds,es,fs,tr);
|
||||
printk("EIP: %8x CS: %4x EFLAGS: %8x\n\r",esp[0],esp[1],esp[2]);
|
||||
}
|
||||
|
||||
void do_nmi(long esp, long error_code)
|
||||
{
|
||||
die("nmi",esp,error_code);
|
||||
}
|
||||
|
||||
void do_debug(long esp, long error_code)
|
||||
{
|
||||
die("debug",esp,error_code);
|
||||
}
|
||||
|
||||
void do_overflow(long esp, long error_code)
|
||||
{
|
||||
die("overflow",esp,error_code);
|
||||
}
|
||||
|
||||
void do_bounds(long esp, long error_code)
|
||||
{
|
||||
die("bounds",esp,error_code);
|
||||
}
|
||||
|
||||
void do_invalid_op(long esp, long error_code)
|
||||
{
|
||||
die("invalid operand",esp,error_code);
|
||||
}
|
||||
|
||||
void do_device_not_available(long esp, long error_code)
|
||||
{
|
||||
die("device not available",esp,error_code);
|
||||
}
|
||||
|
||||
void do_coprocessor_segment_overrun(long esp, long error_code)
|
||||
{
|
||||
die("coprocessor segment overrun",esp,error_code);
|
||||
}
|
||||
|
||||
void do_invalid_TSS(long esp,long error_code)
|
||||
{
|
||||
die("invalid TSS",esp,error_code);
|
||||
}
|
||||
|
||||
void do_segment_not_present(long esp,long error_code)
|
||||
{
|
||||
die("segment not present",esp,error_code);
|
||||
}
|
||||
|
||||
void do_stack_segment(long esp,long error_code)
|
||||
{
|
||||
die("stack segment",esp,error_code);
|
||||
}
|
||||
|
||||
void do_coprocessor_error(long esp, long error_code)
|
||||
{
|
||||
if (last_task_used_math != current)
|
||||
return;
|
||||
die("coprocessor error",esp,error_code);
|
||||
}
|
||||
|
||||
void do_reserved(long esp, long error_code)
|
||||
{
|
||||
die("reserved (15,17-47) error",esp,error_code);
|
||||
}
|
||||
|
||||
void trap_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_trap_gate(0,÷_error);
|
||||
set_trap_gate(1,&debug);
|
||||
set_trap_gate(2,&nmi);
|
||||
set_system_gate(3,&int3); /* int3-5 can be called from all */
|
||||
set_system_gate(4,&overflow);
|
||||
set_system_gate(5,&bounds);
|
||||
set_trap_gate(6,&invalid_op);
|
||||
set_trap_gate(7,&device_not_available);
|
||||
set_trap_gate(8,&double_fault);
|
||||
set_trap_gate(9,&coprocessor_segment_overrun);
|
||||
set_trap_gate(10,&invalid_TSS);
|
||||
set_trap_gate(11,&segment_not_present);
|
||||
set_trap_gate(12,&stack_segment);
|
||||
set_trap_gate(13,&general_protection);
|
||||
set_trap_gate(14,&page_fault);
|
||||
set_trap_gate(15,&reserved);
|
||||
set_trap_gate(16,&coprocessor_error);
|
||||
set_trap_gate(17,&alignment_check);
|
||||
for (i=18;i<48;i++)
|
||||
set_trap_gate(i,&reserved);
|
||||
set_trap_gate(45,&irq13);
|
||||
outb_p(inb_p(0x21)&0xfb,0x21);
|
||||
outb(inb_p(0xA1)&0xdf,0xA1);
|
||||
set_trap_gate(39,¶llel_interrupt);
|
||||
}
|
||||
233
Book-Lite/linux-0.12/kernel/vsprintf.c
Normal file
233
Book-Lite/linux-0.12/kernel/vsprintf.c
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* linux/kernel/vsprintf.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
|
||||
/*
|
||||
* Wirzenius wrote this portably, Torvalds fucked it up :-)
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
/* we use this so that we can do without the ctype library */
|
||||
#define is_digit(c) ((c) >= '0' && (c) <= '9')
|
||||
|
||||
static int skip_atoi(const char **s)
|
||||
{
|
||||
int i=0;
|
||||
|
||||
while (is_digit(**s))
|
||||
i = i*10 + *((*s)++) - '0';
|
||||
return i;
|
||||
}
|
||||
|
||||
#define ZEROPAD 1 /* pad with zero */
|
||||
#define SIGN 2 /* unsigned/signed long */
|
||||
#define PLUS 4 /* show plus */
|
||||
#define SPACE 8 /* space if plus */
|
||||
#define LEFT 16 /* left justified */
|
||||
#define SPECIAL 32 /* 0x */
|
||||
#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */
|
||||
|
||||
#define do_div(n,base) ({ \
|
||||
int __res; \
|
||||
__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \
|
||||
__res; })
|
||||
|
||||
static char * number(char * str, int num, int base, int size, int precision
|
||||
,int type)
|
||||
{
|
||||
char c,sign,tmp[36];
|
||||
const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
int i;
|
||||
|
||||
if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
if (type&LEFT) type &= ~ZEROPAD;
|
||||
if (base<2 || base>36)
|
||||
return 0;
|
||||
c = (type & ZEROPAD) ? '0' : ' ' ;
|
||||
if (type&SIGN && num<0) {
|
||||
sign='-';
|
||||
num = -num;
|
||||
} else
|
||||
sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0);
|
||||
if (sign) size--;
|
||||
if (type&SPECIAL)
|
||||
if (base==16) size -= 2;
|
||||
else if (base==8) size--;
|
||||
i=0;
|
||||
if (num==0)
|
||||
tmp[i++]='0';
|
||||
else while (num!=0)
|
||||
tmp[i++]=digits[do_div(num,base)];
|
||||
if (i>precision) precision=i;
|
||||
size -= precision;
|
||||
if (!(type&(ZEROPAD+LEFT)))
|
||||
while(size-->0)
|
||||
*str++ = ' ';
|
||||
if (sign)
|
||||
*str++ = sign;
|
||||
if (type&SPECIAL)
|
||||
if (base==8)
|
||||
*str++ = '0';
|
||||
else if (base==16) {
|
||||
*str++ = '0';
|
||||
*str++ = digits[33];
|
||||
}
|
||||
if (!(type&LEFT))
|
||||
while(size-->0)
|
||||
*str++ = c;
|
||||
while(i<precision--)
|
||||
*str++ = '0';
|
||||
while(i-->0)
|
||||
*str++ = tmp[i];
|
||||
while(size-->0)
|
||||
*str++ = ' ';
|
||||
return str;
|
||||
}
|
||||
|
||||
int vsprintf(char *buf, const char *fmt, va_list args)
|
||||
{
|
||||
int len;
|
||||
int i;
|
||||
char * str;
|
||||
char *s;
|
||||
int *ip;
|
||||
|
||||
int flags; /* flags to number() */
|
||||
|
||||
int field_width; /* width of output field */
|
||||
int precision; /* min. # of digits for integers; max
|
||||
number of chars for from string */
|
||||
int qualifier; /* 'h', 'l', or 'L' for integer fields */
|
||||
|
||||
for (str=buf ; *fmt ; ++fmt) {
|
||||
if (*fmt != '%') {
|
||||
*str++ = *fmt;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* process flags */
|
||||
flags = 0;
|
||||
repeat:
|
||||
++fmt; /* this also skips first '%' */
|
||||
switch (*fmt) {
|
||||
case '-': flags |= LEFT; goto repeat;
|
||||
case '+': flags |= PLUS; goto repeat;
|
||||
case ' ': flags |= SPACE; goto repeat;
|
||||
case '#': flags |= SPECIAL; goto repeat;
|
||||
case '0': flags |= ZEROPAD; goto repeat;
|
||||
}
|
||||
|
||||
/* get field width */
|
||||
field_width = -1;
|
||||
if (is_digit(*fmt))
|
||||
field_width = skip_atoi(&fmt);
|
||||
else if (*fmt == '*') {
|
||||
/* it's the next argument */
|
||||
field_width = va_arg(args, int);
|
||||
if (field_width < 0) {
|
||||
field_width = -field_width;
|
||||
flags |= LEFT;
|
||||
}
|
||||
}
|
||||
|
||||
/* get the precision */
|
||||
precision = -1;
|
||||
if (*fmt == '.') {
|
||||
++fmt;
|
||||
if (is_digit(*fmt))
|
||||
precision = skip_atoi(&fmt);
|
||||
else if (*fmt == '*') {
|
||||
/* it's the next argument */
|
||||
precision = va_arg(args, int);
|
||||
}
|
||||
if (precision < 0)
|
||||
precision = 0;
|
||||
}
|
||||
|
||||
/* get the conversion qualifier */
|
||||
qualifier = -1;
|
||||
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
|
||||
qualifier = *fmt;
|
||||
++fmt;
|
||||
}
|
||||
|
||||
switch (*fmt) {
|
||||
case 'c':
|
||||
if (!(flags & LEFT))
|
||||
while (--field_width > 0)
|
||||
*str++ = ' ';
|
||||
*str++ = (unsigned char) va_arg(args, int);
|
||||
while (--field_width > 0)
|
||||
*str++ = ' ';
|
||||
break;
|
||||
|
||||
case 's':
|
||||
s = va_arg(args, char *);
|
||||
len = strlen(s);
|
||||
if (precision < 0)
|
||||
precision = len;
|
||||
else if (len > precision)
|
||||
len = precision;
|
||||
|
||||
if (!(flags & LEFT))
|
||||
while (len < field_width--)
|
||||
*str++ = ' ';
|
||||
for (i = 0; i < len; ++i)
|
||||
*str++ = *s++;
|
||||
while (len < field_width--)
|
||||
*str++ = ' ';
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
str = number(str, va_arg(args, unsigned long), 8,
|
||||
field_width, precision, flags);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if (field_width == -1) {
|
||||
field_width = 8;
|
||||
flags |= ZEROPAD;
|
||||
}
|
||||
str = number(str,
|
||||
(unsigned long) va_arg(args, void *), 16,
|
||||
field_width, precision, flags);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
flags |= SMALL;
|
||||
case 'X':
|
||||
str = number(str, va_arg(args, unsigned long), 16,
|
||||
field_width, precision, flags);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
flags |= SIGN;
|
||||
case 'u':
|
||||
str = number(str, va_arg(args, unsigned long), 10,
|
||||
field_width, precision, flags);
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
ip = va_arg(args, int *);
|
||||
*ip = (str - buf);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (*fmt != '%')
|
||||
*str++ = '%';
|
||||
if (*fmt)
|
||||
*str++ = *fmt;
|
||||
else
|
||||
--fmt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*str = '\0';
|
||||
return str-buf;
|
||||
}
|
||||
Reference in New Issue
Block a user