Compare commits
2 Commits
Author | SHA1 | Date |
---|---|---|
|
efb4932730 | 3 years ago |
|
bd387181be | 3 years ago |
@ -0,0 +1,539 @@
|
||||
/*
|
||||
* linux/fs/exec.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* #!-checking implemented by tytso.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Demand-loading implemented 01.12.91 - no need to read anything but
|
||||
* the header into memory. The inode of the executable is put into
|
||||
* "current->executable", and page faults do the actual loading. Clean.
|
||||
*
|
||||
* Once more I can proudly say that linux stood up to being changed: it
|
||||
* was less than 2 hours work to get demand-loading completely implemented.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <a.out.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
extern int sys_exit(int exit_code);
|
||||
extern int sys_close(int fd);
|
||||
|
||||
/*
|
||||
* MAX_ARG_PAGES defines the number of pages allocated for arguments
|
||||
* and envelope for the new program. 32 should suffice, this gives
|
||||
* a maximum env+arg of 128kB !
|
||||
*/
|
||||
#define MAX_ARG_PAGES 32
|
||||
|
||||
|
||||
int sys_uselib()
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/*
|
||||
* create_tables() parses the env- and arg-strings in new user
|
||||
* memory and creates the pointer tables from them, and puts their
|
||||
* addresses on the "stack", returning the new stack pointer value.
|
||||
*/
|
||||
static unsigned long * create_tables(char * p,int argc,int envc)
|
||||
{
|
||||
unsigned long *argv,*envp;
|
||||
unsigned long * sp;
|
||||
|
||||
sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
|
||||
sp -= envc+1;
|
||||
envp = sp;
|
||||
sp -= argc+1;
|
||||
argv = sp;
|
||||
put_fs_long((unsigned long)envp,--sp);
|
||||
put_fs_long((unsigned long)argv,--sp);
|
||||
put_fs_long((unsigned long)argc,--sp);
|
||||
while (argc-->0) {
|
||||
put_fs_long((unsigned long) p,argv++);
|
||||
while (get_fs_byte(p++)) /* nothing */ ;
|
||||
}
|
||||
put_fs_long(0,argv);
|
||||
while (envc-->0) {
|
||||
put_fs_long((unsigned long) p,envp++);
|
||||
while (get_fs_byte(p++)) /* nothing */ ;
|
||||
}
|
||||
put_fs_long(0,envp);
|
||||
return sp;
|
||||
}
|
||||
|
||||
/*
|
||||
* count() counts the number of arguments/envelopes
|
||||
*/
|
||||
static int count(char ** argv)
|
||||
{
|
||||
int i=0;
|
||||
char ** tmp;
|
||||
|
||||
if (tmp = argv)
|
||||
while (get_fs_long((unsigned long *) (tmp++)))
|
||||
i++;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'copy_string()' copies argument/envelope strings from user
|
||||
* memory to free pages in kernel mem. These are in a format ready
|
||||
* to be put directly into the top of new user memory.
|
||||
*
|
||||
* Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies
|
||||
* whether the string and the string array are from user or kernel segments:
|
||||
*
|
||||
* from_kmem argv * argv **
|
||||
* 0 user space user space
|
||||
* 1 kernel space user space
|
||||
* 2 kernel space kernel space
|
||||
*
|
||||
* We do this by playing games with the fs segment register. Since it
|
||||
* it is expensive to load a segment register, we try to avoid calling
|
||||
* set_fs() unless we absolutely have to.
|
||||
*/
|
||||
static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
|
||||
unsigned long p, int from_kmem)
|
||||
{
|
||||
char *tmp, *pag;
|
||||
int len, offset = 0;
|
||||
unsigned long old_fs, new_fs;
|
||||
|
||||
if (!p)
|
||||
return 0; /* bullet-proofing */
|
||||
new_fs = get_ds();
|
||||
old_fs = get_fs();
|
||||
if (from_kmem==2)
|
||||
set_fs(new_fs);
|
||||
while (argc-- > 0) {
|
||||
if (from_kmem == 1)
|
||||
set_fs(new_fs);
|
||||
if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))
|
||||
panic("argc is wrong");
|
||||
if (from_kmem == 1)
|
||||
set_fs(old_fs);
|
||||
len=0; /* remember zero-padding */
|
||||
do {
|
||||
len++;
|
||||
} while (get_fs_byte(tmp++));
|
||||
if (p-len < 0) { /* this shouldn't happen - 128kB */
|
||||
set_fs(old_fs);
|
||||
return 0;
|
||||
}
|
||||
while (len) {
|
||||
--p; --tmp; --len;
|
||||
if (--offset < 0) {
|
||||
offset = p % PAGE_SIZE;
|
||||
if (from_kmem==2)
|
||||
set_fs(old_fs);
|
||||
if (!(pag = (char *) page[p/PAGE_SIZE]) &&
|
||||
!(pag = (char *) (page[p/PAGE_SIZE] =
|
||||
(unsigned long *) get_free_page())))
|
||||
return 0;
|
||||
if (from_kmem==2)
|
||||
set_fs(new_fs);
|
||||
|
||||
}
|
||||
*(pag + offset) = get_fs_byte(tmp);
|
||||
}
|
||||
}
|
||||
if (from_kmem==2)
|
||||
set_fs(old_fs);
|
||||
return p;
|
||||
}
|
||||
|
||||
static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
|
||||
{
|
||||
unsigned long code_limit,data_limit,code_base,data_base;
|
||||
int i;
|
||||
|
||||
code_limit = text_size+PAGE_SIZE -1;
|
||||
code_limit &= 0xFFFFF000;
|
||||
data_limit = 0x4000000;
|
||||
code_base = get_base(current->ldt[1]);
|
||||
data_base = code_base;
|
||||
set_base(current->ldt[1],code_base);
|
||||
set_limit(current->ldt[1],code_limit);
|
||||
set_base(current->ldt[2],data_base);
|
||||
set_limit(current->ldt[2],data_limit);
|
||||
/* make sure fs points to the NEW data segment */
|
||||
__asm__("pushl $0x17\n\tpop %%fs"::);
|
||||
data_base += data_limit;
|
||||
for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
|
||||
data_base -= PAGE_SIZE;
|
||||
if (page[i])
|
||||
put_page(page[i],data_base);
|
||||
}
|
||||
return data_limit;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'do_execve()' executes a new program.
|
||||
*/
|
||||
int do_execve(unsigned long * eip,long tmp,char * filename,
|
||||
char ** argv, char ** envp)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
struct buffer_head * bh;
|
||||
struct exec ex;
|
||||
unsigned long page[MAX_ARG_PAGES];
|
||||
int i,argc,envc;
|
||||
int e_uid, e_gid;
|
||||
int retval;
|
||||
int sh_bang = 0;
|
||||
unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
|
||||
|
||||
if ((0xffff & eip[1]) != 0x000f)
|
||||
panic("execve called from supervisor mode");
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
|
||||
page[i]=0;
|
||||
if (!(inode=namei(filename))) /* get executables inode */
|
||||
return -ENOENT;
|
||||
argc = count(argv);
|
||||
envc = count(envp);
|
||||
|
||||
restart_interp:
|
||||
if (!S_ISREG(inode->i_mode)) { /* must be regular file */
|
||||
retval = -EACCES;
|
||||
goto exec_error2;
|
||||
}
|
||||
i = inode->i_mode;
|
||||
e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
|
||||
e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
|
||||
if (current->euid == inode->i_uid)
|
||||
i >>= 6;
|
||||
else if (current->egid == inode->i_gid)
|
||||
i >>= 3;
|
||||
if (!(i & 1) &&
|
||||
!((inode->i_mode & 0111) && suser())) {
|
||||
retval = -ENOEXEC;
|
||||
goto exec_error2;
|
||||
}
|
||||
if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
|
||||
retval = -EACCES;
|
||||
goto exec_error2;
|
||||
}
|
||||
ex = *((struct exec *) bh->b_data); /* read exec-header */
|
||||
if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
|
||||
/*
|
||||
* This section does the #! interpretation.
|
||||
* Sorta complicated, but hopefully it will work. -TYT
|
||||
*/
|
||||
|
||||
char buf[1023], *cp, *interp, *i_name, *i_arg;
|
||||
unsigned long old_fs;
|
||||
|
||||
strncpy(buf, bh->b_data+2, 1022);
|
||||
brelse(bh);
|
||||
iput(inode);
|
||||
buf[1022] = '\0';
|
||||
if (cp = strchr(buf, '\n')) {
|
||||
*cp = '\0';
|
||||
for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
|
||||
}
|
||||
if (!cp || *cp == '\0') {
|
||||
retval = -ENOEXEC; /* No interpreter name found */
|
||||
goto exec_error1;
|
||||
}
|
||||
interp = i_name = cp;
|
||||
i_arg = 0;
|
||||
for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
|
||||
if (*cp == '/')
|
||||
i_name = cp+1;
|
||||
}
|
||||
if (*cp) {
|
||||
*cp++ = '\0';
|
||||
i_arg = cp;
|
||||
}
|
||||
/*
|
||||
* OK, we've parsed out the interpreter name and
|
||||
* (optional) argument.
|
||||
*/
|
||||
if (sh_bang++ == 0) {
|
||||
p = copy_strings(envc, envp, page, p, 0);
|
||||
p = copy_strings(--argc, argv+1, page, p, 0);
|
||||
}
|
||||
/*
|
||||
* Splice in (1) the interpreter's name for argv[0]
|
||||
* (2) (optional) argument to interpreter
|
||||
* (3) filename of shell script
|
||||
*
|
||||
* This is done in reverse order, because of how the
|
||||
* user environment and arguments are stored.
|
||||
*/
|
||||
p = copy_strings(1, &filename, page, p, 1);
|
||||
argc++;
|
||||
if (i_arg) {
|
||||
p = copy_strings(1, &i_arg, page, p, 2);
|
||||
argc++;
|
||||
}
|
||||
p = copy_strings(1, &i_name, page, p, 2);
|
||||
argc++;
|
||||
if (!p) {
|
||||
retval = -ENOMEM;
|
||||
goto exec_error1;
|
||||
}
|
||||
/*
|
||||
* OK, now restart the process with the interpreter's inode.
|
||||
*/
|
||||
old_fs = get_fs();
|
||||
set_fs(get_ds());
|
||||
if (!(inode=namei(interp))) { /* get executables inode */
|
||||
set_fs(old_fs);
|
||||
retval = -ENOENT;
|
||||
goto exec_error1;
|
||||
}
|
||||
set_fs(old_fs);
|
||||
goto restart_interp;
|
||||
}
|
||||
brelse(bh);
|
||||
if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
|
||||
ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
|
||||
inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
|
||||
retval = -ENOEXEC;
|
||||
goto exec_error2;
|
||||
}
|
||||
if (N_TXTOFF(ex) != BLOCK_SIZE) {
|
||||
printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
|
||||
retval = -ENOEXEC;
|
||||
goto exec_error2;
|
||||
}
|
||||
if (!sh_bang) {
|
||||
p = copy_strings(envc,envp,page,p,0);
|
||||
p = copy_strings(argc,argv,page,p,0);
|
||||
if (!p) {
|
||||
retval = -ENOMEM;
|
||||
goto exec_error2;
|
||||
}
|
||||
}
|
||||
/* OK, This is the point of no return */
|
||||
if (current->executable)
|
||||
iput(current->executable);
|
||||
current->executable = inode;
|
||||
for (i=0 ; i<32 ; i++)
|
||||
current->sigaction[i].sa_handler = NULL;
|
||||
for (i=0 ; i<NR_OPEN ; i++)
|
||||
if ((current->close_on_exec>>i)&1)
|
||||
sys_close(i);
|
||||
current->close_on_exec = 0;
|
||||
free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
|
||||
free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
|
||||
if (last_task_used_math == current)
|
||||
last_task_used_math = NULL;
|
||||
current->used_math = 0;
|
||||
p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
|
||||
p = (unsigned long) create_tables((char *)p,argc,envc);
|
||||
current->brk = ex.a_bss +
|
||||
(current->end_data = ex.a_data +
|
||||
(current->end_code = ex.a_text));
|
||||
current->start_stack = p & 0xfffff000;
|
||||
current->euid = e_uid;
|
||||
current->egid = e_gid;
|
||||
i = ex.a_text+ex.a_data;
|
||||
while (i&0xfff)
|
||||
put_fs_byte(0,(char *) (i++));
|
||||
eip[0] = ex.a_entry; /* eip, magic happens :-) */
|
||||
eip[3] = p; /* stack pointer */
|
||||
|
||||
return 0;
|
||||
exec_error2:
|
||||
iput(inode);
|
||||
exec_error1:
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++)
|
||||
free_page(page[i]);
|
||||
return(retval);
|
||||
}
|
||||
|
||||
int do_execve2(unsigned long * eip,long tmp,char * filename,
|
||||
char ** argv, char ** envp)
|
||||
{
|
||||
struct m_inode * inode;
|
||||
struct buffer_head * bh;
|
||||
struct exec ex;
|
||||
unsigned long page[MAX_ARG_PAGES];
|
||||
int i,argc,envc;
|
||||
int e_uid, e_gid;
|
||||
int retval;
|
||||
int sh_bang = 0;
|
||||
unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
|
||||
|
||||
if ((0xffff & eip[1]) != 0x000f)
|
||||
panic("execve2 called from supervisor mode");
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
|
||||
page[i]=0;
|
||||
if (!(inode=namei(filename))) /* get executables inode */
|
||||
return -ENOENT;
|
||||
argc = count(argv);
|
||||
envc = count(envp);
|
||||
|
||||
restart_interp:
|
||||
if (!S_ISREG(inode->i_mode)) { /* must be regular file */
|
||||
retval = -EACCES;
|
||||
goto exec_error2;
|
||||
}
|
||||
i = inode->i_mode;
|
||||
e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
|
||||
e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
|
||||
if (current->euid == inode->i_uid)
|
||||
i >>= 6;
|
||||
else if (current->egid == inode->i_gid)
|
||||
i >>= 3;
|
||||
if (!(i & 1) &&
|
||||
!((inode->i_mode & 0111) && suser())) {
|
||||
retval = -ENOEXEC;
|
||||
goto exec_error2;
|
||||
}
|
||||
if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
|
||||
retval = -EACCES;
|
||||
goto exec_error2;
|
||||
}
|
||||
ex = *((struct exec *) bh->b_data); /* read exec-header */
|
||||
if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
|
||||
/*
|
||||
* This section does the #! interpretation.
|
||||
* Sorta complicated, but hopefully it will work. -TYT
|
||||
*/
|
||||
|
||||
char buf[1023], *cp, *interp, *i_name, *i_arg;
|
||||
unsigned long old_fs;
|
||||
|
||||
strncpy(buf, bh->b_data+2, 1022);
|
||||
brelse(bh);
|
||||
iput(inode);
|
||||
buf[1022] = '\0';
|
||||
if (cp = strchr(buf, '\n')) {
|
||||
*cp = '\0';
|
||||
for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
|
||||
}
|
||||
if (!cp || *cp == '\0') {
|
||||
retval = -ENOEXEC; /* No interpreter name found */
|
||||
goto exec_error1;
|
||||
}
|
||||
interp = i_name = cp;
|
||||
i_arg = 0;
|
||||
for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
|
||||
if (*cp == '/')
|
||||
i_name = cp+1;
|
||||
}
|
||||
if (*cp) {
|
||||
*cp++ = '\0';
|
||||
i_arg = cp;
|
||||
}
|
||||
/*
|
||||
* OK, we've parsed out the interpreter name and
|
||||
* (optional) argument.
|
||||
*/
|
||||
if (sh_bang++ == 0) {
|
||||
p = copy_strings(envc, envp, page, p, 0);
|
||||
p = copy_strings(--argc, argv+1, page, p, 0);
|
||||
}
|
||||
/*
|
||||
* Splice in (1) the interpreter's name for argv[0]
|
||||
* (2) (optional) argument to interpreter
|
||||
* (3) filename of shell script
|
||||
*
|
||||
* This is done in reverse order, because of how the
|
||||
* user environment and arguments are stored.
|
||||
*/
|
||||
p = copy_strings(1, &filename, page, p, 1);
|
||||
argc++;
|
||||
if (i_arg) {
|
||||
p = copy_strings(1, &i_arg, page, p, 2);
|
||||
argc++;
|
||||
}
|
||||
p = copy_strings(1, &i_name, page, p, 2);
|
||||
argc++;
|
||||
if (!p) {
|
||||
retval = -ENOMEM;
|
||||
goto exec_error1;
|
||||
}
|
||||
/*
|
||||
* OK, now restart the process with the interpreter's inode.
|
||||
*/
|
||||
old_fs = get_fs();
|
||||
set_fs(get_ds());
|
||||
if (!(inode=namei(interp))) { /* get executables inode */
|
||||
set_fs(old_fs);
|
||||
retval = -ENOENT;
|
||||
goto exec_error1;
|
||||
}
|
||||
set_fs(old_fs);
|
||||
goto restart_interp;
|
||||
}
|
||||
brelse(bh);
|
||||
if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
|
||||
ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
|
||||
inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
|
||||
retval = -ENOEXEC;
|
||||
goto exec_error2;
|
||||
}
|
||||
if (N_TXTOFF(ex) != BLOCK_SIZE) {
|
||||
printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
|
||||
retval = -ENOEXEC;
|
||||
goto exec_error2;
|
||||
}
|
||||
if (!sh_bang) {
|
||||
p = copy_strings(envc,envp,page,p,0);
|
||||
p = copy_strings(argc,argv,page,p,0);
|
||||
if (!p) {
|
||||
retval = -ENOMEM;
|
||||
goto exec_error2;
|
||||
}
|
||||
}
|
||||
/* OK, This is the point of no return */
|
||||
if (current->executable)
|
||||
iput(current->executable);
|
||||
current->executable = inode;
|
||||
for (i=0 ; i<32 ; i++)
|
||||
current->sigaction[i].sa_handler = NULL;
|
||||
for (i=0 ; i<NR_OPEN ; i++)
|
||||
if ((current->close_on_exec>>i)&1)
|
||||
sys_close(i);
|
||||
current->close_on_exec = 0;
|
||||
free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
|
||||
free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
|
||||
if (last_task_used_math == current)
|
||||
last_task_used_math = NULL;
|
||||
current->used_math = 0;
|
||||
p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
|
||||
p = (unsigned long) create_tables((char *)p,argc,envc);
|
||||
current->brk = ex.a_bss +
|
||||
(current->end_data = ex.a_data +
|
||||
(current->end_code = ex.a_text));
|
||||
current->start_stack = p & 0xfffff000;
|
||||
current->euid = e_uid;
|
||||
current->egid = e_gid;
|
||||
i = ex.a_text+ex.a_data;
|
||||
while (i&0xfff)
|
||||
put_fs_byte(0,(char *) (i++));
|
||||
eip[0] = ex.a_entry; /* eip, magic happens :-) */
|
||||
eip[3] = p; /* stack pointer */
|
||||
|
||||
char* tmp_buf;
|
||||
for(tmp_buf=0;tmp_buf<=current->brk;tmp_buf+=4096)
|
||||
do_no_page(4, current->start_code+tmp_buf);
|
||||
|
||||
|
||||
return 0;
|
||||
exec_error2:
|
||||
iput(inode);
|
||||
exec_error1:
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++)
|
||||
free_page(page[i]);
|
||||
return(retval);
|
||||
}
|
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* 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) - %fs
|
||||
* 14(%esp) - %es
|
||||
* 18(%esp) - %ds
|
||||
* 1C(%esp) - %eip
|
||||
* 20(%esp) - %cs
|
||||
* 24(%esp) - %eflags
|
||||
* 28(%esp) - %oldesp
|
||||
* 2C(%esp) - %oldss
|
||||
*/
|
||||
|
||||
SIG_CHLD = 17
|
||||
|
||||
EAX = 0x00
|
||||
EBX = 0x04
|
||||
ECX = 0x08
|
||||
EDX = 0x0C
|
||||
FS = 0x10
|
||||
ES = 0x14
|
||||
DS = 0x18
|
||||
EIP = 0x1C
|
||||
CS = 0x20
|
||||
EFLAGS = 0x24
|
||||
OLDESP = 0x28
|
||||
OLDSS = 0x2C
|
||||
|
||||
state = 0 # these are offsets into the task-struct.
|
||||
counter = 4
|
||||
priority = 8
|
||||
signal = 12
|
||||
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 = 100 /* 72 */
|
||||
|
||||
/*
|
||||
* 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,sys_execve2
|
||||
.globl hd_interrupt,floppy_interrupt,parallel_interrupt
|
||||
.globl device_not_available, coprocessor_error
|
||||
|
||||
.align 4
|
||||
bad_sys_call:
|
||||
movl $-1,%eax
|
||||
iret
|
||||
.align 4
|
||||
reschedule:
|
||||
pushl $ret_from_sys_call
|
||||
jmp schedule
|
||||
.align 4
|
||||
system_call:
|
||||
cmpl $nr_system_calls-1,%eax
|
||||
ja bad_sys_call
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
pushl %edx
|
||||
pushl %ecx # push %ebx,%ecx,%edx as parameters
|
||||
pushl %ebx # to the system call
|
||||
movl $0x10,%edx # set up ds,es to kernel space
|
||||
mov %dx,%ds
|
||||
mov %dx,%es
|
||||
movl $0x17,%edx # fs points to local data space
|
||||
mov %dx,%fs
|
||||
|
||||
pushl %eax #by wyj
|
||||
call print_nr
|
||||
popl %eax
|
||||
|
||||
call sys_call_table(,%eax,4)
|
||||
pushl %eax
|
||||
movl current,%eax
|
||||
cmpl $0,state(%eax) # state
|
||||
jne reschedule
|
||||
cmpl $0,counter(%eax) # counter
|
||||
je reschedule
|
||||
ret_from_sys_call:
|
||||
movl current,%eax # task[0] cannot have signals
|
||||
cmpl task,%eax
|
||||
je 3f
|
||||
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 %eax
|
||||
3: popl %eax
|
||||
popl %ebx
|
||||
popl %ecx
|
||||
popl %edx
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
iret
|
||||
|
||||
.align 4
|
||||
coprocessor_error:
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
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 %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
|
||||
call math_emulate
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
.align 4
|
||||
timer_interrupt:
|
||||
push %ds # save ds,es and put kernel data space
|
||||
push %es # into them. %fs is used by _system_call
|
||||
push %fs
|
||||
pushl %edx # we save %eax,%ecx,%edx as gcc doesn't
|
||||
pushl %ecx # save those across function calls. %ebx
|
||||
pushl %ebx # is saved as we use that in ret_sys_call
|
||||
pushl %eax
|
||||
movl $0x10,%eax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
movl $0x17,%eax
|
||||
mov %ax,%fs
|
||||
incl jiffies
|
||||
movb $0x20,%al # EOI to interrupt controller #1
|
||||
outb %al,$0x20
|
||||
movl CS(%esp),%eax
|
||||
andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor)
|
||||
pushl %eax
|
||||
call do_timer # 'do_timer(long CPL)' does everything from
|
||||
addl $4,%esp # task switching to accounting ...
|
||||
jmp ret_from_sys_call
|
||||
|
||||
.align 4
|
||||
sys_execve:
|
||||
lea EIP(%esp),%eax
|
||||
pushl %eax
|
||||
call do_execve
|
||||
addl $4,%esp
|
||||
ret
|
||||
|
||||
.align 4
|
||||
sys_execve2:
|
||||
lea EIP(%esp),%eax
|
||||
pushl %eax
|
||||
call do_execve2
|
||||
addl $4,%esp
|
||||
ret
|
||||
|
||||
.align 4
|
||||
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
|
||||
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
|
Loading…
Reference in new issue