Commit 6cd3649b authored by Linus Torvalds's avatar Linus Torvalds

patch3....

Ok, I already announced it on the kernel mailing-list, but I might as
well go all the way. I put out patch3 to 0.96a yesterday, and it's
available on banjo in pub/Linux/Linus, and I'll upload it to the other
normal ftp-sites tonight.

NOTE! Patch3 is (like patch2) more of a kernel-hacker patch: it's just
in case you want to keep up with my kernel. It has some problems with
some serial lines, and if you experience them, I'd like to know what
type of chip you are running (and what linux reports on bootup). If you
don't think patching the kernel is fun, you might as well forget this
and wait for a real release (next month?).

Patch 3 contains:

- support for attaching and detaching processes under gdb (but you need
  a gdb that knows about this).
- 16550A support
- full core-dumping (again, you need a gdb that supports it)
- sockets have no problems with non-root binding etc
- /dev/zero implemented (mknod /dev/zero c 1 5)

None of the patches are very big (the whole patch is 17kB compressed,
most of it attach/detach code), but they are all pretty useful.

The 16550A support means that with the appropriate chip you now should
be able to use the serial ports at much higher speeds, but as mentioned,
it seems to break on some machines.

The detaching isn't perfect yet (I noticed only after making the diffs
that I had forgotten to do some cleanups), but it's not generally a
problem (the code just forgets to give the process back to it's rightful
father).

The patch is relative to the pl2 kernel, so you have to use the earlier
patches first. This time, I've added the lib/itimer.c code.

16550A support was written by tdavis, the correct format of the
core-dumps was written by eric (who also wrote the attach/detach code I
used as an example when implementing it), /dev/zero was written by
almesber. Nice to see good patches: I just did the socket-thing and
rewrote the attaching to suit me.

            Linus
parent 24c9da66
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/segment.h> #include <asm/segment.h>
#include <sys/user.h>
extern int sys_exit(int exit_code); extern int sys_exit(int exit_code);
extern int sys_close(int fd); extern int sys_close(int fd);
...@@ -69,10 +70,14 @@ int core_dump(long signr, struct pt_regs * regs) ...@@ -69,10 +70,14 @@ int core_dump(long signr, struct pt_regs * regs)
struct file file; struct file file;
unsigned short fs; unsigned short fs;
int has_dumped = 0; int has_dumped = 0;
register int dump_start, dump_size;
struct user dump;
if (!current->dumpable) if (!current->dumpable)
return 0; return 0;
current->dumpable = 0; current->dumpable = 0;
/* See if we have enough room to write the upage. */
if(current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE/1024) return 0;
__asm__("mov %%fs,%0":"=r" (fs)); __asm__("mov %%fs,%0":"=r" (fs));
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
if (open_namei("core",O_CREAT | O_WRONLY | O_TRUNC,0600,&inode)) if (open_namei("core",O_CREAT | O_WRONLY | O_TRUNC,0600,&inode))
...@@ -96,22 +101,52 @@ int core_dump(long signr, struct pt_regs * regs) ...@@ -96,22 +101,52 @@ int core_dump(long signr, struct pt_regs * regs)
has_dumped = 1; has_dumped = 1;
/* write and seek example: from kernel space */ /* write and seek example: from kernel space */
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
DUMP_WRITE("core-dump, regs=\n",17); dump.u_tsize = current->end_code / PAGE_SIZE;
DUMP_SEEK(64); dump.u_dsize = (current->brk - current->end_code) / PAGE_SIZE;
DUMP_WRITE(regs,sizeof(*regs)); dump.u_ssize =((current->start_stack +(PAGE_SIZE-1)) / PAGE_SIZE) -
if (current->used_math) { (regs->esp/ PAGE_SIZE);
/* If the size of the dump file exceeds the rlimit, then see what would happen
if we wrote the stack, but not the data area. */
if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE/1024 >
current->rlim[RLIMIT_CORE].rlim_cur)
dump.u_dsize = 0;
/* Make sure we have enough room to write the stack and data areas. */
if ((dump.u_ssize+1) * PAGE_SIZE / 1024 >
current->rlim[RLIMIT_CORE].rlim_cur)
dump.u_ssize = 0;
dump.u_comm = 0;
dump.u_ar0 = (struct pt_regs *)(((int)(&dump.regs)) -((int)(&dump)));
dump.signal = signr;
dump.regs = *regs;
dump.start_code = 0;
dump.start_stack = regs->esp & ~(PAGE_SIZE - 1);
/* Flag indicating the math stuff is valid. */
if (dump.u_fpvalid = current->used_math) {
if (last_task_used_math == current) if (last_task_used_math == current)
__asm__("clts ; fnsave %0"::"m" (current->tss.i387)); __asm__("clts ; fnsave %0"::"m" (dump.i387));
DUMP_SEEK(1024); else
DUMP_WRITE("floating-point regs=\n",21); memcpy(&dump.i387,&current->tss.i387,sizeof(dump.i387));
DUMP_SEEK(1088); };
DUMP_WRITE(&current->tss.i387,sizeof(current->tss.i387)); DUMP_WRITE(&dump,sizeof(dump));
} DUMP_SEEK(sizeof(dump));
/* Dump the task struct. Not be used by gdb, but could be useful */
DUMP_WRITE(current,sizeof(*current));
/* Now dump all of the user data. Include malloced stuff as well */
DUMP_SEEK(PAGE_SIZE);
/* now we start writing out the user space info */ /* now we start writing out the user space info */
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x17)); __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x17));
/* the dummy dump-file contains the first block of user space... */ /* Dump the data area */
DUMP_SEEK(2048); if (dump.u_dsize != 0) {
DUMP_WRITE(0,1024); dump_start = current->end_code;
dump_size = current->brk - current->end_code;
DUMP_WRITE(dump_start,dump_size);
};
/* Now prepare to dump the stack area */
if (dump.u_ssize != 0) {
dump_start = regs->esp & ~(PAGE_SIZE - 1);
dump_size = dump.u_ssize * PAGE_SIZE;
DUMP_WRITE(dump_start,dump_size);
};
close_coredump: close_coredump:
if (file.f_op->release) if (file.f_op->release)
file.f_op->release(inode,&file); file.f_op->release(inode,&file);
......
...@@ -58,8 +58,6 @@ struct super_block *minix_read_super(struct super_block *s,void *data) ...@@ -58,8 +58,6 @@ struct super_block *minix_read_super(struct super_block *s,void *data)
printk("bread failed\n"); printk("bread failed\n");
return NULL; return NULL;
} }
/* *((struct minix_super_block *) s) =
*((struct minix_super_block *) bh->b_data); */
ms = (struct minix_super_block *) bh->b_data; ms = (struct minix_super_block *) bh->b_data;
s->s_ninodes = ms->s_ninodes; s->s_ninodes = ms->s_ninodes;
s->s_nzones = ms->s_nzones; s->s_nzones = ms->s_nzones;
......
...@@ -252,14 +252,12 @@ int open_namei(const char * pathname, int flag, int mode, ...@@ -252,14 +252,12 @@ int open_namei(const char * pathname, int flag, int mode,
return 0; return 0;
} }
int sys_mknod(const char * filename, int mode, int dev) int do_mknod(const char * filename, int mode, int dev)
{ {
const char * basename; const char * basename;
int namelen; int namelen;
struct inode * dir; struct inode * dir;
if (!suser())
return -EPERM;
if (!(dir = dir_namei(filename,&namelen,&basename, NULL))) if (!(dir = dir_namei(filename,&namelen,&basename, NULL)))
return -ENOENT; return -ENOENT;
if (!namelen) { if (!namelen) {
...@@ -277,6 +275,13 @@ int sys_mknod(const char * filename, int mode, int dev) ...@@ -277,6 +275,13 @@ int sys_mknod(const char * filename, int mode, int dev)
return dir->i_op->mknod(dir,basename,namelen,mode,dev); return dir->i_op->mknod(dir,basename,namelen,mode,dev);
} }
int sys_mknod(const char * filename, int mode, int dev)
{
if (suser())
return do_mknod(filename,mode,dev);
return -EPERM;
}
int sys_mkdir(const char * pathname, int mode) int sys_mkdir(const char * pathname, int mode)
{ {
const char * basename; const char * basename;
......
...@@ -49,11 +49,15 @@ static int pipe_write(struct inode * inode, struct file * filp, char * buf, int ...@@ -49,11 +49,15 @@ static int pipe_write(struct inode * inode, struct file * filp, char * buf, int
{ {
int chars, size, written = 0; int chars, size, written = 0;
if (inode->i_count != 2) { /* no readers */
send_sig(SIGPIPE,current,0);
return -EINTR;
}
while (count>0) { while (count>0) {
while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) { while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) {
wake_up(& PIPE_READ_WAIT(*inode)); wake_up(& PIPE_READ_WAIT(*inode));
if (inode->i_count != 2) { /* no readers */ if (inode->i_count != 2) { /* no readers */
current->signal |= (1<<(SIGPIPE-1)); send_sig(SIGPIPE,current,0);
return written?written:-EINTR; return written?written:-EINTR;
} }
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked)
......
...@@ -41,7 +41,7 @@ void buffer_init(long buffer_end); ...@@ -41,7 +41,7 @@ void buffer_init(long buffer_end);
#define MAJOR(a) (((unsigned)(a))>>8) #define MAJOR(a) (((unsigned)(a))>>8)
#define MINOR(a) ((a)&0xff) #define MINOR(a) ((a)&0xff)
#define NR_OPEN 20 #define NR_OPEN 32
#define NR_INODE 128 #define NR_INODE 128
#define NR_FILE 64 #define NR_FILE 64
#define NR_SUPER 8 #define NR_SUPER 8
...@@ -226,6 +226,7 @@ extern struct inode * _namei(const char * filename, struct inode * base, ...@@ -226,6 +226,7 @@ extern struct inode * _namei(const char * filename, struct inode * base,
int follow_links); int follow_links);
extern int open_namei(const char * pathname, int flag, int mode, extern int open_namei(const char * pathname, int flag, int mode,
struct inode ** res_inode); struct inode ** res_inode);
extern int do_mknod(const char * filename, int mode, int dev);
extern void iput(struct inode * inode); extern void iput(struct inode * inode);
extern struct inode * iget(int dev,int nr); extern struct inode * iget(int dev,int nr);
extern struct inode * get_empty_inode(void); extern struct inode * get_empty_inode(void);
......
...@@ -124,11 +124,11 @@ struct task_struct { ...@@ -124,11 +124,11 @@ struct task_struct {
long pid,pgrp,session,leader; long pid,pgrp,session,leader;
int groups[NGROUPS]; int groups[NGROUPS];
/* /*
* pointers to parent process, youngest child, younger sibling, * pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with * older sibling, respectively. (p->father can be replaced with
* p->p_pptr->pid) * p->p_pptr->pid)
*/ */
struct task_struct *p_pptr, *p_cptr, *p_ysptr, *p_osptr; struct task_struct *p_opptr,*p_pptr, *p_cptr, *p_ysptr, *p_osptr;
/* /*
* sleep makes a singly linked list with this. * sleep makes a singly linked list with this.
*/ */
...@@ -187,7 +187,7 @@ struct task_struct { ...@@ -187,7 +187,7 @@ struct task_struct {
/* ec,brk... */ 0,0,0,0,0,0,0, \ /* ec,brk... */ 0,0,0,0,0,0,0, \
/* pid etc.. */ 0,0,0,0, \ /* pid etc.. */ 0,0,0,0, \
/* suppl grps*/ {NOGROUP,}, \ /* suppl grps*/ {NOGROUP,}, \
/* proc links*/ &init_task.task,NULL,NULL,NULL,NULL, \ /* proc links*/ &init_task.task,&init_task.task,NULL,NULL,NULL,NULL, \
/* uid etc */ 0,0,0,0,0,0, \ /* uid etc */ 0,0,0,0,0,0, \
/* timeout */ 0,0,0,0,0,0,0,0,0,0,0,0, \ /* timeout */ 0,0,0,0,0,0,0,0,0,0,0,0, \
/* min_flt */ 0,0,0,0, \ /* min_flt */ 0,0,0,0, \
...@@ -320,4 +320,18 @@ static unsigned long inline get_limit(unsigned long segment) ...@@ -320,4 +320,18 @@ static unsigned long inline get_limit(unsigned long segment)
return __limit+1; return __limit+1;
} }
#define REMOVE_LINKS(p) \
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
#define SET_LINKS(p) \
(p)->p_ysptr = NULL; \
if ((p)->p_osptr = (p)->p_pptr->p_cptr) \
(p)->p_osptr->p_ysptr = p; \
(p)->p_pptr->p_cptr = p
#endif #endif
...@@ -4,6 +4,21 @@ ...@@ -4,6 +4,21 @@
#ifndef _SYS_PTRACE_H #ifndef _SYS_PTRACE_H
#define _SYS_PTRACE_H #define _SYS_PTRACE_H
/* has the defines to get at the registers. */ /* has the defines to get at the registers. */
#define PTRACE_TRACEME 0
#define PTRACE_PEEKTEXT 1
#define PTRACE_PEEKDATA 2
#define PTRACE_PEEKUSR 3
#define PTRACE_POKETEXT 4
#define PTRACE_POKEDATA 5
#define PTRACE_POKEUSR 6
#define PTRACE_CONT 7
#define PTRACE_KILL 8
#define PTRACE_SINGLESTEP 9
#define PTRACE_ATTACH 0x10
#define PTRACE_DETACH 0x11
/* use ptrace (3 or 6, pid, PT_EXCL, data); to read or write /* use ptrace (3 or 6, pid, PT_EXCL, data); to read or write
the processes registers. */ the processes registers. */
......
#include <sys/ptrace.h>
/* Core file format: The core file is written in such a way that gdb
can understand it and provide useful information to the user (under
linux we use the 'trad-core' bfd). There are quite a number of
obstacles to being able to view the contents of the floating point
registers, and until these are solved you will not be able to view the
contents of them. Actually, you can read in the core file and look at
the contents of the user struct to find out what the floating point
registers contain.
The actual file contents are as follows:
UPAGE: 1 page consisting of a user struct that tells gdb what is present
in the file. Directly after this is a copy of the task_struct, which
is currently not used by gdb, but it may come in useful at some point.
All of the registers are stored as part of the upage. The upage should
always be only one page.
DATA: The data area is stored. We use current->end_text to
current->brk to pick up all of the user variables, plus any memory
that may have been malloced. No attempt is made to determine if a page
is demand-zero or if a page is totally unused, we just cover the entire
range. All of the addresses are rounded in such a way that an integral
number of pages is written.
STACK: We need the stack information in order to get a meaningful
backtrace. We need to write the data from (esp) to
current->start_stack, so we round each of these off in order to be able
to write an integer number of pages.
The minimum core file size is 3 pages, or 12288 bytes.
*/
struct user_i387_struct {
long cwd;
long swd;
long twd;
long fip;
long fcs;
long foo;
long fos;
long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
};
/* When the kernel dumps core, it starts by dumping the user struct -
this will be used by gdb to figure out where the data and stack segments
are within the file, and what virtual addresses to use. */
struct user{
/* We start with the registers, to mimic the way that "memory" is returned
from the ptrace(3,...) function. */
struct pt_regs regs; /* Where the registers are actually stored */
/* ptrace does not yet supply these. Someday.... */
int u_fpvalid; /* True if math co-processor being used. */
/* for this mess. Not yet used. */
struct user_i387_struct i387; /* Math Co-processor registers. */
/* The rest of this junk is to help gdb figure out what goes where */
unsigned long int u_tsize; /* Text segment size (pages). */
unsigned long int u_dsize; /* Data segment size (pages). */
unsigned long int u_ssize; /* Stack segment size (pages). */
unsigned long start_code; /* Starting virtual address of text. */
unsigned long start_stack; /* Starting virtual address of stack area.
This is actually the bottom of the stack,
the top of the stack is always found in the
esp register. */
long int signal; /* Signal that caused the core dump. */
char * u_comm; /* User command that was responsible */
struct pt_regs * u_ar0; /* Used by gdb to help find the values for */
/* the registers. */
struct user_i387_struct* u_fpstate; /* Math Co-processor pointer. */
};
#define NBPG 4096
#define UPAGES 1
#define HOST_TEXT_START_ADDR (u.start_code)
#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
...@@ -154,6 +154,17 @@ static int write_port(struct inode * inode,struct file * file,char * buf, int co ...@@ -154,6 +154,17 @@ static int write_port(struct inode * inode,struct file * file,char * buf, int co
return tmp-buf; return tmp-buf;
} }
static int read_zero(struct inode *node,struct file *file,char *buf,int count)
{
int left;
for (left = count; left > 0; left--) {
put_fs_byte(0,buf);
buf++;
}
return count;
}
/* /*
* The memory devices use the full 32 bits of the offset, and so we cannot * The memory devices use the full 32 bits of the offset, and so we cannot
* check against negative addresses: they are ok. The return value is weird, * check against negative addresses: they are ok. The return value is weird,
...@@ -192,6 +203,8 @@ static int mem_read(struct inode * inode, struct file * file, char * buf, int co ...@@ -192,6 +203,8 @@ static int mem_read(struct inode * inode, struct file * file, char * buf, int co
return 0; /* /dev/null */ return 0; /* /dev/null */
case 4: case 4:
return read_port(inode,file,buf,count); return read_port(inode,file,buf,count);
case 5:
return read_zero(inode,file,buf,count);
default: default:
return -ENODEV; return -ENODEV;
} }
...@@ -210,6 +223,8 @@ static int mem_write(struct inode * inode, struct file * file, char * buf, int c ...@@ -210,6 +223,8 @@ static int mem_write(struct inode * inode, struct file * file, char * buf, int c
return count; /* /dev/null */ return count; /* /dev/null */
case 4: case 4:
return write_port(inode,file,buf,count); return write_port(inode,file,buf,count);
case 5:
return count; /* /dev/zero */
default: default:
return -ENODEV; return -ENODEV;
} }
......
...@@ -27,12 +27,32 @@ ...@@ -27,12 +27,32 @@
extern void IRQ3_interrupt(void); extern void IRQ3_interrupt(void);
extern void IRQ4_interrupt(void); extern void IRQ4_interrupt(void);
#define PORT_UNKNOWN 0
#define PORT_8250 1
#define PORT_16450 2
#define PORT_16550 3
#define PORT_16550A 4
int port_table[] = {
PORT_UNKNOWN,
PORT_UNKNOWN,
PORT_UNKNOWN,
PORT_UNKNOWN,
PORT_UNKNOWN
};
static void modem_status_intr(unsigned line, unsigned port, struct tty_struct * tty) static void modem_status_intr(unsigned line, unsigned port, struct tty_struct * tty)
{ {
unsigned char status = inb(port+6); unsigned char status = inb(port+6);
if ((status & 0x88) == 0x08 && tty->pgrp > 0) if ((status & 0x88) == 0x08 && tty->pgrp > 0)
kill_pg(tty->pgrp,SIGHUP,1); kill_pg(tty->pgrp,SIGHUP,1);
if ((status & 0x10) == 0x10)
tty->stopped = 0;
else
tty->stopped = 1;
} }
/* /*
...@@ -46,13 +66,20 @@ static void modem_status_intr(unsigned line, unsigned port, struct tty_struct * ...@@ -46,13 +66,20 @@ static void modem_status_intr(unsigned line, unsigned port, struct tty_struct *
*/ */
static void send_intr(unsigned line, unsigned port, struct tty_struct * tty) static void send_intr(unsigned line, unsigned port, struct tty_struct * tty)
{ {
int c; int c, i = 0;
#define TIMER ((SER1_TIMEOUT-1)+line) #define TIMER ((SER1_TIMEOUT-1)+line)
timer_active &= ~(1 << TIMER); timer_active &= ~(1 << TIMER);
if ((c = GETCH(tty->write_q)) < 0) if (!tty->stopped) {
return; do {
outb(c,port); if ((c = GETCH(tty->write_q)) < 0)
return;
outb(c,port);
i++;
} while ( port_table[line] == PORT_16550A && \
i < 14 && !EMPTY(tty->write_q) && \
!tty->stopped);
}
timer_table[TIMER].expires = jiffies + 10; timer_table[TIMER].expires = jiffies + 10;
timer_active |= 1 << TIMER; timer_active |= 1 << TIMER;
if (LEFT(tty->write_q) > WAKEUP_CHARS) if (LEFT(tty->write_q) > WAKEUP_CHARS)
...@@ -64,7 +91,15 @@ static void receive_intr(unsigned line, unsigned port, struct tty_struct * tty) ...@@ -64,7 +91,15 @@ static void receive_intr(unsigned line, unsigned port, struct tty_struct * tty)
{ {
if (FULL(tty->read_q)) if (FULL(tty->read_q))
return; return;
PUTCH(inb(port),tty->read_q);
outb_p((inb(port+4) & 0x0d), port+4);
do {
PUTCH(inb(port),tty->read_q);
} while ((inb(port+5) & 0x01 != 0) && !FULL(tty->read_q));
outb_p((inb(port+4) | 0x02), port+4);
timer_active |= (1<<(SER1_TIMER-1))<<line; timer_active |= (1<<(SER1_TIMER-1))<<line;
} }
...@@ -90,7 +125,7 @@ static void check_tty(unsigned line,struct tty_struct * tty) ...@@ -90,7 +125,7 @@ static void check_tty(unsigned line,struct tty_struct * tty)
if (!(port = tty->read_q->data)) if (!(port = tty->read_q->data))
return; return;
while (1) { while (1) {
ident = inb(port+2); ident = inb(port+2) & 7;
if (ident & 1) if (ident & 1)
return; return;
ident >>= 1; ident >>= 1;
...@@ -182,8 +217,43 @@ static void com4_timeout(void) ...@@ -182,8 +217,43 @@ static void com4_timeout(void)
do_rs_write(4,tty_table+67); do_rs_write(4,tty_table+67);
} }
static void init(int port) static void init(int port, int line)
{ {
unsigned char status1, status2, scratch;
if (inb(port+5) == 0xff) {
port_table[line] = PORT_UNKNOWN;
return;
}
scratch = inb(port+7);
outb_p(0xa5, port+7);
status1 = inb(port+7);
outb_p(0x5a, port+7);
status2 = inb(port+7);
if (status1 == 0xa5 && status2 == 0x5a) {
outb_p(scratch, port+7);
outb_p(0x01, port+2);
scratch = inb(port+2) >> 6;
switch (scratch) {
case 0: printk("serial port at 0x%04x is a 16450\n", port);
port_table[line] = PORT_16450;
break;
case 1: printk("serial port at 0x%04x is unknown\n", port);
port_table[line] = PORT_UNKNOWN;
break;
case 2: printk("serial port at 0x%04x is a 16550 (FIFO's disabled)\n", port);
port_table[line] = PORT_16550;
outb_p(0x00, port+2);
break;
case 3: printk("serial port at 0x%04x is a 16550a (FIFO's enabled)\n", port);
port_table[line] = PORT_16550A;
outb_p(0xc7, port+2);
break;
}
} else
printk("serial port at 0x%04x is a 8250\n", port);
outb_p(0x80,port+3); /* set DLAB of line control reg */ outb_p(0x80,port+3); /* set DLAB of line control reg */
outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */ outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */
outb_p(0x00,port+1); /* MS of divisor */ outb_p(0x00,port+1); /* MS of divisor */
...@@ -243,10 +313,10 @@ void rs_init(void) ...@@ -243,10 +313,10 @@ void rs_init(void)
timer_table[SER4_TIMEOUT].expires = 0; timer_table[SER4_TIMEOUT].expires = 0;
set_intr_gate(0x23,IRQ3_interrupt); set_intr_gate(0x23,IRQ3_interrupt);
set_intr_gate(0x24,IRQ4_interrupt); set_intr_gate(0x24,IRQ4_interrupt);
init(tty_table[64].read_q->data); init(tty_table[64].read_q->data, 1);
init(tty_table[65].read_q->data); init(tty_table[65].read_q->data, 2);
init(tty_table[66].read_q->data); init(tty_table[66].read_q->data, 3);
init(tty_table[67].read_q->data); init(tty_table[67].read_q->data, 4);
outb(inb_p(0x21)&0xE7,0x21); outb(inb_p(0x21)&0xE7,0x21);
} }
......
...@@ -22,7 +22,7 @@ int send_sig(long sig,struct task_struct * p,int priv) ...@@ -22,7 +22,7 @@ int send_sig(long sig,struct task_struct * p,int priv)
if (!p || (sig < 0) || (sig > 32)) if (!p || (sig < 0) || (sig > 32))
return -EINVAL; return -EINVAL;
if (!priv && ((sig != SIGCONT) || (current->session != p->session)) && if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
(current->euid != p->euid) && !suser()) (current->euid != p->euid) && (current->uid != p->uid) && !suser())
return -EPERM; return -EPERM;
if (!sig) if (!sig)
return 0; return 0;
...@@ -42,7 +42,7 @@ int send_sig(long sig,struct task_struct * p,int priv) ...@@ -42,7 +42,7 @@ int send_sig(long sig,struct task_struct * p,int priv)
/* save the signal number for wait. */ /* save the signal number for wait. */
p->exit_code = sig; p->exit_code = sig;
/* we have to make sure the parent is awake. */ /* we have to make sure the parent process is awake. */
if (p->p_pptr != NULL && p->p_pptr->state == TASK_INTERRUPTIBLE) if (p->p_pptr != NULL && p->p_pptr->state == TASK_INTERRUPTIBLE)
p->p_pptr->state = TASK_RUNNING; p->p_pptr->state = TASK_RUNNING;
...@@ -66,13 +66,7 @@ void release(struct task_struct * p) ...@@ -66,13 +66,7 @@ void release(struct task_struct * p)
for (i=1 ; i<NR_TASKS ; i++) for (i=1 ; i<NR_TASKS ; i++)
if (task[i] == p) { if (task[i] == p) {
task[i] = NULL; task[i] = NULL;
/* Update links */ REMOVE_LINKS(p);
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); free_page((long) p);
return; return;
} }
...@@ -284,6 +278,15 @@ static int has_stopped_jobs(int pgrp) ...@@ -284,6 +278,15 @@ static int has_stopped_jobs(int pgrp)
return(0); return(0);
} }
static void forget_original_parent(struct task_struct * father)
{
struct task_struct ** p;
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p && (*p)->p_opptr == father)
(*p)->p_opptr = task[1];
}
volatile void do_exit(long code) volatile void do_exit(long code)
{ {
struct task_struct *p; struct task_struct *p;
...@@ -294,6 +297,7 @@ volatile void do_exit(long code) ...@@ -294,6 +297,7 @@ volatile void do_exit(long code)
for (i=0 ; i<NR_OPEN ; i++) for (i=0 ; i<NR_OPEN ; i++)
if (current->filp[i]) if (current->filp[i])
sys_close(i); sys_close(i);
forget_original_parent(current);
iput(current->pwd); iput(current->pwd);
current->pwd = NULL; current->pwd = NULL;
iput(current->root); iput(current->root);
...@@ -332,18 +336,18 @@ volatile void do_exit(long code) ...@@ -332,18 +336,18 @@ volatile void do_exit(long code)
* A. Make init inherit all the child processes * A. Make init inherit all the child processes
* B. Check to see if any process groups have become orphaned * B. Check to see if any process groups have become orphaned
* as a result of our exiting, and if they have any stopped * 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) * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2)
*/ */
while (p = current->p_cptr) { while (p = current->p_cptr) {
current->p_cptr = p->p_osptr; current->p_cptr = p->p_osptr;
p->p_ysptr = NULL; p->p_ysptr = NULL;
p->flags &= ~PF_PTRACED; p->flags &= ~PF_PTRACED;
p->p_pptr = task[1]; p->p_pptr = task[1];
p->p_osptr = task[1]->p_cptr; p->p_osptr = p->p_pptr->p_cptr;
task[1]->p_cptr->p_ysptr = p; p->p_osptr->p_ysptr = p;
task[1]->p_cptr = p; p->p_pptr->p_cptr = p;
if (p->state == TASK_ZOMBIE) if (p->state == TASK_ZOMBIE)
task[1]->signal |= (1<<(SIGCHLD-1)); p->p_pptr->signal |= (1<<(SIGCHLD-1));
/* /*
* process group orphan check * process group orphan check
* Case ii: Our child is in a different pgrp * Case ii: Our child is in a different pgrp
...@@ -396,7 +400,7 @@ int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options) ...@@ -396,7 +400,7 @@ int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
verify_area(stat_addr,4); verify_area(stat_addr,4);
repeat: repeat:
flag=0; flag=0;
for (p = current->p_cptr ; p ; p = p->p_osptr) { for (p = current->p_cptr ; p ; p = p->p_osptr) {
if (pid>0) { if (pid>0) {
if (p->pid != pid) if (p->pid != pid)
continue; continue;
...@@ -426,7 +430,13 @@ int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options) ...@@ -426,7 +430,13 @@ int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
flag = p->pid; flag = p->pid;
if (stat_addr) if (stat_addr)
put_fs_long(p->exit_code, stat_addr); put_fs_long(p->exit_code, stat_addr);
release(p); if (p->p_opptr != p->p_pptr) {
REMOVE_LINKS(p);
p->p_pptr = p->p_opptr;
SET_LINKS(p);
send_sig(SIGCHLD,p->p_pptr,1);
} else
release(p);
#ifdef DEBUG_PROC_TREE #ifdef DEBUG_PROC_TREE
audit_ptree(); audit_ptree();
#endif #endif
...@@ -451,5 +461,3 @@ int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options) ...@@ -451,5 +461,3 @@ int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
} }
return -ECHILD; return -ECHILD;
} }
...@@ -107,13 +107,11 @@ int sys_fork(long ebx,long ecx,long edx, ...@@ -107,13 +107,11 @@ int sys_fork(long ebx,long ecx,long edx,
task[nr] = p; task[nr] = p;
*p = *current; /* NOTE! this doesn't copy the supervisor stack */ *p = *current; /* NOTE! this doesn't copy the supervisor stack */
p->state = TASK_UNINTERRUPTIBLE; p->state = TASK_UNINTERRUPTIBLE;
p->flags &= ~PF_PTRACED;
p->pid = last_pid; p->pid = last_pid;
p->p_pptr = current; p->p_pptr = p->p_opptr = current;
p->p_cptr = NULL; p->p_cptr = NULL;
p->p_ysptr = NULL; SET_LINKS(p);
if (p->p_osptr = current->p_cptr)
p->p_osptr->p_ysptr = p;
current->p_cptr = p;
p->counter = p->priority; p->counter = p->priority;
p->signal = 0; p->signal = 0;
p->it_real_value = p->it_virt_value = p->it_prof_value = 0; p->it_real_value = p->it_virt_value = p->it_prof_value = 0;
...@@ -151,12 +149,7 @@ int sys_fork(long ebx,long ecx,long edx, ...@@ -151,12 +149,7 @@ int sys_fork(long ebx,long ecx,long edx,
__asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387)); __asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387));
if (copy_mem(nr,p)) { if (copy_mem(nr,p)) {
task[nr] = NULL; task[nr] = NULL;
if (p->p_pptr->p_cptr == p) REMOVE_LINKS(p);
p->p_pptr->p_cptr = p->p_osptr;
if (p->p_osptr)
p->p_osptr->p_ysptr = p->p_ysptr;
if (p->p_ysptr)
p->p_ysptr->p_osptr = p->p_osptr;
free_page((long) p); free_page((long) p);
return -EAGAIN; return -EAGAIN;
} }
......
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
static unsigned long tvtojiffies(struct timeval *value) static unsigned long tvtojiffies(struct timeval *value)
{ {
return((unsigned long )value->tv_sec * HZ + return((unsigned long )value->tv_sec * HZ +
(unsigned long )value->tv_usec / (1000000 / HZ)); (unsigned long )(value->tv_usec + (1000000 / HZ - 1)) /
(1000000 / HZ));
} }
static void jiffiestotv(unsigned long jiffies, struct timeval *value) static void jiffiestotv(unsigned long jiffies, struct timeval *value)
...@@ -100,8 +101,9 @@ int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) ...@@ -100,8 +101,9 @@ int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
int k; int k;
if (!value) if (!value)
return -EFAULT; memset((char *) &set_buffer, 0, sizeof(set_buffer));
memcpy_fromfs(&set_buffer, value, sizeof(set_buffer)); else
memcpy_fromfs(&set_buffer, value, sizeof(set_buffer));
k = _setitimer(which, &set_buffer, ovalue ? &get_buffer : 0); k = _setitimer(which, &set_buffer, ovalue ? &get_buffer : 0);
if (k < 0 || !ovalue) if (k < 0 || !ovalue)
return k; return k;
......
...@@ -6,9 +6,11 @@ ...@@ -6,9 +6,11 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <errno.h>
#include <asm/segment.h> #include <asm/segment.h>
#include <asm/system.h> #include <asm/system.h>
#include <errno.h>
#include <sys/ptrace.h> #include <sys/ptrace.h>
/* /*
...@@ -33,15 +35,15 @@ void do_no_page(unsigned long, unsigned long, struct task_struct *, unsigned lon ...@@ -33,15 +35,15 @@ void do_no_page(unsigned long, unsigned long, struct task_struct *, unsigned lon
void write_verify(unsigned long); void write_verify(unsigned long);
/* change a pid into a task struct. */ /* change a pid into a task struct. */
static inline int get_task(int pid) static inline struct task_struct * get_task(int pid)
{ {
int i; int i;
for (i = 0; i < NR_TASKS; i++) { for (i = 0; i < NR_TASKS; i++) {
if (task[i] != NULL && (task[i]->pid == pid)) if (task[i] != NULL && (task[i]->pid == pid))
return i; return task[i];
} }
return -1; return NULL;
} }
/* /*
...@@ -222,32 +224,50 @@ static int write_long(struct task_struct * tsk, unsigned long addr, ...@@ -222,32 +224,50 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
int sys_ptrace(long request, long pid, long addr, long data) int sys_ptrace(long request, long pid, long addr, long data)
{ {
struct task_struct *child; struct task_struct *child;
int childno;
if (request == 0) { if (request == PTRACE_TRACEME) {
/* are we already being traced? */
if (current->flags & PF_PTRACED)
return -EPERM;
/* set the ptrace bit in the proccess flags. */ /* set the ptrace bit in the proccess flags. */
current->flags |= PF_PTRACED; current->flags |= PF_PTRACED;
return 0; return 0;
} }
if (!(child = get_task(pid)))
childno = get_task(pid);
if (childno < 0)
return -ESRCH; return -ESRCH;
else if (request == PTRACE_ATTACH) {
child = task[childno]; long tmp;
if (child->p_pptr != current || !(child->flags & PF_PTRACED) || if ((!current->dumpable || (current->uid != child->euid) ||
child->state != TASK_STOPPED) (current->gid != child->egid)) && !suser())
return -EPERM;
/* the same process cannot be attached many times */
if (child->flags & PF_PTRACED)
return -EPERM;
child->flags |= PF_PTRACED;
if (child->p_pptr != current) {
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
}
tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
if (child->state == TASK_INTERRUPTIBLE ||
child->state == TASK_STOPPED)
child->state = TASK_RUNNING;
child->signal = 0;
return 0;
}
if (!(child->flags & PF_PTRACED) || child->state != TASK_STOPPED)
return -ESRCH; return -ESRCH;
switch (request) { switch (request) {
/* when I and D space are seperate, these will need to be fixed. */ /* when I and D space are seperate, these will need to be fixed. */
case 1: /* read word at location addr. */ case PTRACE_PEEKTEXT: /* read word at location addr. */
case 2: { case PTRACE_PEEKDATA: {
int tmp,res; int tmp,res;
res = read_long(task[childno], addr, &tmp); res = read_long(child, addr, &tmp);
if (res < 0) if (res < 0)
return res; return res;
verify_area((void *) data, 4); verify_area((void *) data, 4);
...@@ -256,7 +276,7 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -256,7 +276,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
} }
/* read the word at location addr in the USER area. */ /* read the word at location addr in the USER area. */
case 3: { case PTRACE_PEEKUSR: {
int tmp; int tmp;
addr = addr >> 2; /* temporary hack. */ addr = addr >> 2; /* temporary hack. */
if (addr < 0 || addr >= 17) if (addr < 0 || addr >= 17)
...@@ -268,11 +288,11 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -268,11 +288,11 @@ int sys_ptrace(long request, long pid, long addr, long data)
} }
/* when I and D space are seperate, this will have to be fixed. */ /* when I and D space are seperate, this will have to be fixed. */
case 4: /* write the word at location addr. */ case PTRACE_POKETEXT: /* write the word at location addr. */
case 5: case PTRACE_POKEDATA:
return write_long(task[childno],addr,data); return write_long(child,addr,data);
case 6: /* write the word at location addr in the USER area */ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
addr = addr >> 2; /* temproary hack. */ addr = addr >> 2; /* temproary hack. */
if (addr < 0 || addr >= 17) if (addr < 0 || addr >= 17)
return -EIO; return -EIO;
...@@ -286,13 +306,13 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -286,13 +306,13 @@ int sys_ptrace(long request, long pid, long addr, long data)
return -EIO; return -EIO;
return 0; return 0;
case 7: { /* restart after signal. */ case PTRACE_CONT: { /* restart after signal. */
long tmp; long tmp;
child->signal=0; child->signal = 0;
if (data > 0 && data <= NSIG) if (data > 0 && data <= NSIG)
child->signal = 1<<(data-1); child->signal = 1<<(data-1);
child->state = 0; child->state = TASK_RUNNING;
/* make sure the single step bit is not set. */ /* make sure the single step bit is not set. */
tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG; tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
put_stack_long(child, 4*EFL-MAGICNUMBER,tmp); put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
...@@ -304,10 +324,10 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -304,10 +324,10 @@ int sys_ptrace(long request, long pid, long addr, long data)
* perhaps it should be put in the status that it want's to * perhaps it should be put in the status that it want's to
* exit. * exit.
*/ */
case 8: { case PTRACE_KILL: {
long tmp; long tmp;
child->state = 0; child->state = TASK_RUNNING;
child->signal = 1 << (SIGKILL-1); child->signal = 1 << (SIGKILL-1);
/* make sure the single step bit is not set. */ /* make sure the single step bit is not set. */
tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG; tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
...@@ -315,19 +335,31 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -315,19 +335,31 @@ int sys_ptrace(long request, long pid, long addr, long data)
return 0; return 0;
} }
case 9: { /* set the trap flag. */ case PTRACE_SINGLESTEP: { /* set the trap flag. */
long tmp; long tmp;
tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG; tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
put_stack_long(child, 4*EFL-MAGICNUMBER,tmp); put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
child->state = 0; child->state = TASK_RUNNING;
child->signal = 0; child->signal = 0;
if (data > 0 && data <NSIG) if (data > 0 && data <= NSIG)
child->signal= 1<<(data-1); child->signal= 1<<(data-1);
/* give it a chance to run. */ /* give it a chance to run. */
return 0; return 0;
} }
case PTRACE_DETACH: { /* detach a process that was attached. */
long tmp;
child->flags &= ~PF_PTRACED;
child->signal=0;
child->state = 0;
/* make sure the single step bit is not set. */
tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
return 0;
}
default: default:
return -EIO; return -EIO;
} }
......
...@@ -137,8 +137,7 @@ int do_signal(long signr,struct pt_regs * regs) ...@@ -137,8 +137,7 @@ int do_signal(long signr,struct pt_regs * regs)
#endif #endif
if ((regs->orig_eax != -1) && if ((regs->orig_eax != -1) &&
((regs->eax == -ERESTARTSYS) || (regs->eax == -ERESTARTNOINTR))) { ((regs->eax == -ERESTARTSYS) || (regs->eax == -ERESTARTNOINTR))) {
if ((regs->eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT) || if ((regs->eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT)))
signr < SIGCONT || signr > SIGTTOU))
regs->eax = -EINTR; regs->eax = -EINTR;
else { else {
regs->eax = regs->orig_eax; regs->eax = regs->orig_eax;
...@@ -168,9 +167,7 @@ int do_signal(long signr,struct pt_regs * regs) ...@@ -168,9 +167,7 @@ int do_signal(long signr,struct pt_regs * regs)
current->exit_code = signr; current->exit_code = signr;
if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP)) SA_NOCLDSTOP))
send_sig(SIGCHLD, current->p_pptr, 1); send_sig(SIGCHLD, current->p_pptr, 1);
/* current->p_pptr->signal |= (1<<(SIGCHLD-1));*/
return(1); /* Reschedule another event */ return(1); /* Reschedule another event */
case SIGQUIT: case SIGQUIT:
......
/*
* linux/lib/itimer.c
*
* (C) 1992 Darren Senn
*/
#define __LIBRARY__
#include <unistd.h>
#include <sys/time.h>
_syscall2(int,getitimer,int,which,struct itimerval *,value)
_syscall3(int,setitimer,int,which,struct itimerval *,value,struct itimerval *,ovalue)
...@@ -233,7 +233,6 @@ unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr, ...@@ -233,7 +233,6 @@ unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1]; char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
int i; int i;
unsigned long old_fs; unsigned long old_fs;
unsigned short old_euid;
PRINTK("unix_proto_bind: socket 0x%x, len=%d\n", sock, PRINTK("unix_proto_bind: socket 0x%x, len=%d\n", sock,
sockaddr_len); sockaddr_len);
...@@ -254,21 +253,11 @@ unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr, ...@@ -254,21 +253,11 @@ unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
return -EINVAL; return -EINVAL;
} }
/*
* W A R N I N G
* this is a terrible hack. i want to create a socket in the
* filesystem and get its inode. sys_mknod() can create one for
* me, but it needs superuser privs and doesn't give me the inode.
* we fake suser here and get the file created... ugh.
*/
memcpy(fname, upd->sockaddr_un.sun_path, sockaddr_len-UN_PATH_OFFSET); memcpy(fname, upd->sockaddr_un.sun_path, sockaddr_len-UN_PATH_OFFSET);
fname[sockaddr_len-UN_PATH_OFFSET] = '\0'; fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
old_fs = get_fs(); old_fs = get_fs();
set_fs(get_ds()); set_fs(get_ds());
old_euid = current->euid; i = do_mknod(fname, S_IFSOCK | 0777, 0);
current->euid = 0;
i = sys_mknod(fname, S_IFSOCK, 0);
current->euid = old_euid;
if (i == 0) if (i == 0)
i = open_namei(fname, 0, S_IFSOCK, &upd->inode); i = open_namei(fname, 0, S_IFSOCK, &upd->inode);
set_fs(old_fs); set_fs(old_fs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment