From c0718054e9b98ee092c3e2afaabc5a3360202b1d Mon Sep 17 00:00:00 2001 From: Jorrit Herder Date: Wed, 20 Jul 2005 15:25:38 +0000 Subject: [PATCH] Various fixes and improvements. - fixed bug that caused IDLE to panic (irq hook inconsistency); - kprintf() now accepts multiple arguments; moved to utility.c; - prepare_shutdown() signals system processes with SIGKSTOP; - phys_fill() renamed to phys_memset(), argument order changed; - kmemset() removed in favor of phys_kmemset(); - kstrncpy() removed in favor of phys_copy(); - katoi, kstrncmp replaced by normal library procedure again; - rm_irq_handler() interface changed (simply pass hook pointer); --- kernel/Makefile | 2 +- kernel/config.h | 2 +- kernel/debug.c | 16 ++-- kernel/exception.c | 11 ++- kernel/i8259.c | 19 ++-- kernel/klib386.s | 19 ++-- kernel/klibc.c | 177 -------------------------------------- kernel/main.c | 62 +++++++------ kernel/priv.h | 4 +- kernel/proc.h | 1 + kernel/proto.h | 25 ++---- kernel/start.c | 13 +-- kernel/system.c | 61 ++++++------- kernel/system/do_exec.c | 5 +- kernel/system/do_exit.c | 4 +- kernel/system/do_irqctl.c | 4 +- kernel/system/do_memset.c | 6 +- kernel/type.h | 5 -- kernel/utility.c | 125 +++++++++++++++++++++++++-- 19 files changed, 243 insertions(+), 318 deletions(-) delete mode 100644 kernel/klibc.c diff --git a/kernel/Makefile b/kernel/Makefile index dd6d21473..3d1b42260 100755 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -14,7 +14,7 @@ CFLAGS = -I$i LDFLAGS = -i HEAD = mpx.o -OBJS = start.o protect.o klibc.o klib.o table.o main.o proc.o \ +OBJS = start.o protect.o klib.o table.o main.o proc.o \ i8259.o exception.o system.o clock.o utility.o debug.o SYSTEM = system.a LIBS = -ltimers diff --git a/kernel/config.h b/kernel/config.h index 31e7e6bc6..eb5676b8e 100644 --- a/kernel/config.h +++ b/kernel/config.h @@ -53,7 +53,7 @@ * a system server is notified and a copy of the buffer can be retrieved to * display the message. The buffers size can safely be reduced. */ -#define KMESS_BUF_SIZE 128 +#define KMESS_BUF_SIZE 256 /* Buffer to gather randomness. This is used to generate a random stream by * the MEMORY driver when reading from /dev/random. diff --git a/kernel/debug.c b/kernel/debug.c index 05ad2716b..d4b485859 100644 --- a/kernel/debug.c +++ b/kernel/debug.c @@ -120,35 +120,35 @@ check_runqueues(char *when) for (q=0; q < NR_SCHED_QUEUES; q++) { if(rdy_head[q] && !rdy_tail[q]) { - kprintf("head but no tail: %s", (karg_t) when); + kprintf("head but no tail: %s", when); panic("scheduling error", NO_NUM); } if(!rdy_head[q] && rdy_tail[q]) { - kprintf("tail but no head: %s", (karg_t) when); + kprintf("tail but no head: %s", when); panic("scheduling error", NO_NUM); } if(rdy_tail[q] && rdy_tail[q]->p_nextready != NIL_PROC) { - kprintf("tail and tail->next not null; %s", (karg_t) when); + kprintf("tail and tail->next not null; %s", when); panic("scheduling error", NO_NUM); } for(xp = rdy_head[q]; xp != NIL_PROC; xp = xp->p_nextready) { if (!xp->p_ready) { - kprintf("scheduling error: unready on runq: %s\n", (karg_t) when); + kprintf("scheduling error: unready on runq: %s\n", when); panic("found unready process on run queue", NO_NUM); } if(xp->p_priority != q) { - kprintf("scheduling error: wrong priority: %s\n", (karg_t) when); + kprintf("scheduling error: wrong priority: %s\n", when); panic("wrong priority", NO_NUM); } if(xp->p_found) { - kprintf("scheduling error: double scheduling: %s\n", (karg_t) when); + kprintf("scheduling error: double scheduling: %s\n", when); panic("proc more than once on scheduling queue", NO_NUM); } xp->p_found = 1; if(xp->p_nextready == NIL_PROC && rdy_tail[q] != xp) { - kprintf("scheduling error: last element not tail: %s\n", (karg_t) when); + kprintf("scheduling error: last element not tail: %s\n", when); panic("scheduling error", NO_NUM); } if(l++ > PROCLIMIT) panic("loop in schedule queue?", NO_NUM); @@ -157,7 +157,7 @@ check_runqueues(char *when) for (xp = BEG_PROC_ADDR; xp < END_PROC_ADDR; ++xp) { if(! isemptyp(xp) && xp->p_ready && ! xp->p_found) { - kprintf("scheduling error: ready not on queue: %s\n", (karg_t) when); + kprintf("scheduling error: ready not on queue: %s\n", when); panic("ready proc not on scheduling queue", NO_NUM); if(l++ > PROCLIMIT) { panic("loop in proc.t?", NO_NUM); } } diff --git a/kernel/exception.c b/kernel/exception.c index 59eb67553..f822154e7 100755 --- a/kernel/exception.c +++ b/kernel/exception.c @@ -65,13 +65,12 @@ unsigned vec_nr; if (ep->msg == NIL_PTR || machine.processor < ep->minprocessor) kprintf("\nIntel-reserved exception %d\n", vec_nr); else - kprintf("\n%s\n", karg(ep->msg)); - kprintf("process number %d ", proc_nr(saved_proc)); - kprintf("(%s), ", saved_proc->p_name); - kprintf("pc = %d:", (unsigned) saved_proc->p_reg.cs); - kprintf("0x%x\n", (unsigned) saved_proc->p_reg.pc); + kprintf("\n%s\n", ep->msg); + kprintf("k_reenter = %d ", k_reenter); + kprintf("process %d (%s)", proc_nr(saved_proc), saved_proc->p_name); + kprintf("pc = %d:0x%x", (unsigned) saved_proc->p_reg.cs, + (unsigned) saved_proc->p_reg.pc); - kernel_exception = TRUE; /* directly shutdown */ panic("exception in a kernel task", NO_NUM); } diff --git a/kernel/i8259.c b/kernel/i8259.c index 71d0f3bbb..f6ea9d8d1 100755 --- a/kernel/i8259.c +++ b/kernel/i8259.c @@ -123,29 +123,30 @@ irq_handler_t handler; /*=========================================================================* * rm_irq_handler * *=========================================================================*/ -PUBLIC int rm_irq_handler(irq, id) -int irq; -int id; +PUBLIC void rm_irq_handler(hook) +irq_hook_t *hook; { /* Unregister an interrupt handler. */ + int irq = hook->irq; + int id = hook->id; irq_hook_t **line; - if (irq < 0 || irq >= NR_IRQ_VECTORS) return(EINVAL); + if (irq < 0 || irq >= NR_IRQ_VECTORS) + panic("invalid call to rm_irq_handler", irq); line = &irq_handlers[irq]; while (*line != NULL) { if((*line)->id == id) { (*line) = (*line)->next; - if(! irq_handlers[irq]) - irq_use &= ~(1 << irq); - return(OK); + if(! irq_handlers[irq]) irq_use &= ~(1 << irq); + return; } line = &(*line)->next; } - - return(ENOENT); + /* When the handler is not found, normally return here. */ } + /*==========================================================================* * intr_handle * *==========================================================================*/ diff --git a/kernel/klib386.s b/kernel/klib386.s index 8439aff8e..dc2084183 100755 --- a/kernel/klib386.s +++ b/kernel/klib386.s @@ -26,7 +26,7 @@ .define _enable_irq ! enable an irq at the 8259 controller .define _disable_irq ! disable an irq .define _phys_copy ! copy data from anywhere to anywhere in memory -.define _phys_fill ! zero data anywhere in memory +.define _phys_memset ! write pattern anywhere in memory .define _mem_rdw ! copy one word from [segment:offset] .define _reset ! reset the system .define _idle_task ! task executed when there is no work @@ -440,25 +440,24 @@ pc_small: ret !*===========================================================================* -!* phys_fill * +!* phys_memset * !*===========================================================================* -! PUBLIC void phys_fill(phys_bytes source, phys_bytes bytecount, -! unsigned long pattern); +! PUBLIC void phys_memset(phys_bytes source, unsigned long pattern, +! phys_bytes bytecount); ! Fill a block of physical memory with pattern. .align 16 - -_phys_fill: +_phys_memset: push ebp mov ebp, esp push esi push ebx push ds mov esi, 8(ebp) - mov eax, 12(ebp) + mov eax, 16(ebp) mov ebx, FLAT_DS_SELECTOR mov ds, bx - mov ebx, 16(ebp) + mov ebx, 12(ebp) shr eax, 2 fill_start: mov (esi), ebx @@ -466,12 +465,12 @@ fill_start: dec eax jnz fill_start ! Any remaining bytes? - mov eax, 12(ebp) + mov eax, 16(ebp) and eax, 3 remain_fill: cmp eax, 0 jz fill_done - movb bl, 16(ebp) + movb bl, 12(ebp) movb (esi), bl add esi, 1 inc ebp diff --git a/kernel/klibc.c b/kernel/klibc.c deleted file mode 100644 index ab885b952..000000000 --- a/kernel/klibc.c +++ /dev/null @@ -1,177 +0,0 @@ -/* This file contains simplified versions of the standard libary functions for - * use with the kernel. This way the kernel sources remain separate from user - * sources and can easily be verified. Note that the functionality provided - * can be slightly different. - * March 2005, Jorrit N. Herder. - * Entrypoints into this file: - * kmemcpy: copy n bytes from pointer p1 to pointer p2 - * kmemset: set n bytes to c starting at pointer p - * kprintf: printf for the kernel (see working below) - * kstrcmp: lexicographical comparison of two strings - * kstrncpy: copy string and pad or copy up to n chars - * - * This file contains the routines that take care of kernel messages, i.e., - * diagnostic output within the kernel. Kernel messages are not directly - * displayed on the console, because this must be done by the PRINT driver. - * Instead, the kernel accumulates characters in a buffer and notifies the - * output driver when a new message is ready. - */ - -#include "kernel.h" - -#include -#include - -#define isdigit(c) ((unsigned) ((c) - '0') < (unsigned) 10) -#define END_OF_KMESS -1 -FORWARD _PROTOTYPE(void kputc, (int c)); - - -/*=========================================================================* - * kmemcpy * - *=========================================================================*/ -PUBLIC void *kmemcpy(void *s1, const void *s2, register size_t n) -{ - register char *p1 = s1; - register const char *p2 = s2; - - while (n-- > 0) - *p1++ = *p2++; - return s1; -} - - -/*=========================================================================* - * kmemset * - *=========================================================================*/ -PUBLIC void *kmemset(void *s, register int c, register size_t n) -{ - register char *s1 = s; - if (n++>0) { /* optimized for speed */ - while (--n > 0) - *s1++ = c; - } - return s; -} - - -/*===========================================================================* - * kprintf * - *===========================================================================*/ -PUBLIC void kprintf(fmt, arg) -const char *fmt; /* format string to be printed */ -karg_t arg; /* argument for format string */ -{ - int c; /* next character in fmt */ - unsigned long u; /* hold number argument */ - int base; /* base of number arg */ - int negative = 0; /* print minus sign */ - static char x2c[] = "0123456789ABCDEF"; /* nr conversion table */ - char ascii[8 * sizeof(long) / 3 + 2]; /* string for ascii number */ - char *s = NULL; /* string to be printed */ - - while((c=*fmt++) != 0) { - - if (c == '%') { /* expect format '%key' */ - switch(c = *fmt++) { /* determine what to do */ - - /* Known keys are %d, %u, %x, %s, and %%. This is easily extended - * with number types like %b and %o by providing a different base. - * Number type keys don't set a string to 's', but use the general - * conversion after the switch statement. - */ - case 'd': /* output decimal */ - u = arg < 0 ? -arg : arg; - if (arg < 0) negative = 1; - base = 10; - break; - case 'u': /* output unsigned long */ - u = (unsigned long) arg; - base = 10; - break; - case 'x': /* output hexadecimal */ - u = (unsigned long) arg; - base = 0x10; - break; - case 's': /* output string */ - if ((s=(char *)arg) == NULL) - s = "(null)"; - break; - case '%': /* output percent */ - s = "%"; - break; - - /* Unrecognized key. */ - default: /* echo back %key */ - s = "%?"; - s[1] = c; /* set unknown key */ - } - - /* Assume a number if no string is set. Convert to ascii. */ - if (s == NULL) { - s = ascii + sizeof(ascii)-1; - *s = 0; - do { *--s = x2c[(u % base)]; } /* work backwards */ - while ((u /= base) > 0); - } - - /* This is where the actual output for format "%key" is done. */ - if (negative) kputc('-'); /* print sign if negative */ - while(*s != 0) { kputc(*s++); } /* print string/ number */ - } - else { - kputc(c); /* print and continue */ - } - } - kputc(END_OF_KMESS); /* terminate output */ -} - - -/*===========================================================================* - * kputc * - *===========================================================================*/ -PRIVATE void kputc(c) -int c; /* character to append */ -{ -/* Accumulate a single character for a kernel message. Send a notification - * the to PRINTF_PROC driver if an END_OF_KMESS is encountered. - */ - if (c != END_OF_KMESS) { - kmess.km_buf[kmess.km_next] = c; /* put normal char in buffer */ - if (kmess.km_size < KMESS_BUF_SIZE) - kmess.km_size += 1; - kmess.km_next = (kmess.km_next + 1) % KMESS_BUF_SIZE; - } else { - send_sig(PRINTF_PROC, SIGKMESS); - } -} - - - -/*=========================================================================* - * kstrcmp * - *=========================================================================*/ -int kstrcmp(register const char *s1, register const char *s2) -{ - while (*s1 == *s2++) - if (*s1++ == '\0') return 0; - if (*s1 == '\0') return -1; - if (*--s2 == '\0') return 1; - return (unsigned char) *s1 - (unsigned char) *s2; -} - - -/*=========================================================================* - * kstrncpy * - *=========================================================================*/ -PUBLIC char *kstrncpy(char *ret, register const char *s2, register ssize_t n) -{ - register char *s1 = ret; - while((n-- > 0) && (*s1++ = *s2++)) /* copy up to n chars */ - /* EMPTY */ ; - while(n-- > 0) /* possibly pad target */ - *s1++ = '\0'; - return ret; -} - - diff --git a/kernel/main.c b/kernel/main.c index 27cedbe3d..7f13a77c1 100755 --- a/kernel/main.c +++ b/kernel/main.c @@ -14,6 +14,7 @@ */ #include "kernel.h" #include +#include #include #include #include @@ -24,6 +25,8 @@ FORWARD _PROTOTYPE( void announce, (void)); FORWARD _PROTOTYPE( void shutdown, (timer_t *tp)); +#define SHUTDOWN_TICKS 5 /* time allowed to do cleanup */ + /*===========================================================================* * main * @@ -31,15 +34,14 @@ FORWARD _PROTOTYPE( void shutdown, (timer_t *tp)); PUBLIC void main() { /* Start the ball rolling. */ - register struct proc *rp; - register struct priv *sp; - register int i,s; + struct system_image *ip; /* boot image pointer */ + register struct proc *rp; /* process pointer */ + register struct priv *sp; /* privilege structure pointer */ + register int i, s; int hdrindex; /* index to array of a.out headers */ phys_clicks text_base; - vir_clicks text_clicks; - vir_clicks data_clicks; + vir_clicks text_clicks, data_clicks; reg_t ktsb; /* kernel task stack base */ - struct system_image *ip; /* boot image pointer */ struct exec e_hdr; /* for a copy of an a.out header */ /* Initialize the interrupt controller. */ @@ -73,9 +75,13 @@ PUBLIC void main() for (i=0; i < NR_BOOT_PROCS; ++i) { ip = &image[i]; /* process' attributes */ - (void) init_proc(ip->proc_nr, NONE); /* initialize new process */ rp = proc_addr(ip->proc_nr); /* get process pointer */ - kstrncpy(rp->p_name, ip->proc_name, P_NAME_LEN); /* set name */ + (void) init_proc(rp, NIL_SYS_PROC); +#if DEAD_CODE + (ip->flags & SYS_PROC) ? + NIL_SYS_PROC : NIL_PROC); /* initialize new process */ +#endif + strncpy(rp->p_name, ip->proc_name, P_NAME_LEN); /* set name */ rp->p_name[P_NAME_LEN-1] = '\0'; /* just for safety */ rp->p_max_priority = ip->priority; /* max scheduling priority */ rp->p_priority = ip->priority; /* current priority */ @@ -106,7 +112,7 @@ PUBLIC void main() /* Convert addresses to clicks and build process memory map */ text_base = e_hdr.a_syms >> CLICK_SHIFT; text_clicks = (e_hdr.a_text + CLICK_SIZE-1) >> CLICK_SHIFT; - if (!(e_hdr.a_flags & A_SEP)) text_clicks = 0; /* Common I&D */ + if (!(e_hdr.a_flags & A_SEP)) text_clicks = 0; /* common I&D */ data_clicks = (e_hdr.a_total + CLICK_SIZE-1) >> CLICK_SHIFT; rp->p_memmap[T].mem_phys = text_base; rp->p_memmap[T].mem_len = text_clicks; @@ -168,13 +174,13 @@ PUBLIC void main() PRIVATE void announce(void) { /* Display the MINIX startup banner. */ - kprintf("MINIX %s. Copyright 2001 Prentice-Hall, Inc.\n", - karg(OS_RELEASE "." OS_VERSION)); + kprintf("MINIX %s.%s. Copyright 2001 Prentice-Hall, Inc.\n", + OS_RELEASE, OS_VERSION); #if (CHIP == INTEL) /* Real mode, or 16/32-bit protected mode? */ kprintf("Executing in %s mode\n\n", - machine.protected ? karg("32-bit protected") : karg("real")); + machine.protected ? "32-bit protected" : "real"); #endif } @@ -189,6 +195,7 @@ int how; /* reason to shut down */ * sure it is only executed once. Unless a CPU exception occurred, the */ static timer_t shutdown_timer; /* timer for watchdog function */ + register struct proc *rp; message m; /* Show debugging dumps on panics. Make sure that the TTY task is still @@ -201,21 +208,26 @@ int how; /* reason to shut down */ return; /* await sys_abort() from TTY */ } - /* Send signal to TTY so that it can switch to the primary console. */ - send_sig(TTY, SIGKSTOP); - - /* Allow processes to be scheduled to clean up, unless a CPU exception - * occurred. This is done by setting a timer. The timer argument passes - * the shutdown status. + /* Send a signal to all system processes that are still alive to inform + * them that the MINIX kernel is shutting down. A proper shutdown sequence + * should be implemented by a user-space server. This mechanism is useful + * as a backup in case of system panics, so that system processes can still + * run their shutdown code, e.g, to synchronize the FS or to let the TTY + * switch to the first console. */ - tmr_arg(&shutdown_timer)->ta_int = how; /* pass how in timer */ - if (kernel_exception) { /* set in exception() */ - kprintf("\nAn exception occured; skipping stop sequence.\n", NO_NUM); - shutdown(&shutdown_timer); /* TTY isn't scheduled */ - } else { - kprintf("\nNotifying system services about MINIX shutdown.\n", NO_NUM); - set_timer(&shutdown_timer, get_uptime(), shutdown); + for (rp=BEG_PROC_ADDR; rps_flags & SYS_PROC) && ! iskernelp(rp)) + send_sig(proc_nr(rp), SIGKSTOP); } + + /* Notify system processes of the upcoming shutdown and allow them to be + * scheduled by setting a watchog timer that calls shutdown(). The timer + * argument passes the shutdown status. + */ + kprintf("Informed system about upcoming shutdown with SIGKSTOP signal.\n"); + kprintf("Time for cleanup is allowed. MINIX will now be brought down.\n"); + tmr_arg(&shutdown_timer)->ta_int = how; /* pass how in timer */ + set_timer(&shutdown_timer, get_uptime() + SHUTDOWN_TICKS, shutdown); } diff --git a/kernel/priv.h b/kernel/priv.h index 37dc89254..ce66e41b8 100755 --- a/kernel/priv.h +++ b/kernel/priv.h @@ -61,7 +61,9 @@ struct priv { EXTERN struct priv priv[NR_SYS_PROCS]; /* system properties table */ EXTERN struct priv *ppriv_addr[NR_SYS_PROCS]; /* direct slot pointers */ -/* Unprivileged user processes all share the same privilege structure. */ +/* Unprivileged user processes all share the same privilege structure. + * This id must be fixed because it is used to check send mask entries. + */ #define USER_PRIV_ID 0 /* Make sure the system can boot. The following sanity check verifies that diff --git a/kernel/proc.h b/kernel/proc.h index e1050e159..250157205 100755 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -88,6 +88,7 @@ struct proc { #define END_PROC_ADDR (&proc[NR_TASKS + NR_PROCS]) #define NIL_PROC ((struct proc *) 0) +#define NIL_SYS_PROC ((struct proc *) 1) #define cproc_addr(n) (&(proc + NR_TASKS)[(n)]) #define proc_addr(n) (pproc_addr + NR_TASKS)[(n)] #define proc_nr(p) ((p)->p_nr) diff --git a/kernel/proto.h b/kernel/proto.h index 265ce8e70..74fd12509 100755 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -15,24 +15,14 @@ _PROTOTYPE( unsigned long read_clock, (void) ); _PROTOTYPE( void set_timer, (struct timer *tp, clock_t t, tmr_func_t f) ); _PROTOTYPE( void reset_timer, (struct timer *tp) ); -/* klibc.c */ -_PROTOTYPE( void *kmemcpy, (void *s1, const void *s2, register size_t n)); -_PROTOTYPE( void *kmemset, (void *s, register int c, register size_t n)); -_PROTOTYPE( int kstrcmp, (register const char *s1, register const char *s2)); -_PROTOTYPE( char *kstrncpy, - (char *s1, register const char *s2, register const ssize_t n)); -#define karg(arg) (karg_t) (arg) -_PROTOTYPE( void kprintf, (const char *fmt, karg_t arg) ); - /* main.c */ _PROTOTYPE( void main, (void) ); _PROTOTYPE( void prepare_shutdown, (int how) ); _PROTOTYPE( void stop_sequence, (struct timer *tp) ); /* utility.c */ +_PROTOTYPE( void kprintf, (const char *fmt, ...) ); _PROTOTYPE( void panic, (_CONST char *s, int n) ); -_PROTOTYPE( void safe_lock, (int c, char *v) ); -_PROTOTYPE( void safe_unlock, (void) ); _PROTOTYPE( int alloc_bit, (bitchunk_t *map, bit_t nr_bits) ); _PROTOTYPE( void free_bit, (bit_t nr, bitchunk_t *map, bit_t nr_bits) ); @@ -51,8 +41,8 @@ _PROTOTYPE( void cstart, (U16_t cs, U16_t ds, U16_t mds, /* system.c */ _PROTOTYPE( void send_sig, (int proc_nr, int sig_nr) ); _PROTOTYPE( void cause_sig, (int proc_nr, int sig_nr) ); -_PROTOTYPE( int init_proc, (int proc_nr, int proto_nr) ); -_PROTOTYPE( void clear_proc, (int proc_nr) ); +_PROTOTYPE( int init_proc, (register struct proc *rc, struct proc *rp) ); +_PROTOTYPE( void clear_proc, (register struct proc *rc) ); _PROTOTYPE( phys_bytes numap_local, (int proc_nr, vir_bytes vir_addr, vir_bytes bytes) ); _PROTOTYPE( void sys_task, (void) ); @@ -77,7 +67,7 @@ _PROTOTYPE( void intr_init, (int mine) ); _PROTOTYPE( void intr_handle, (irq_hook_t *hook) ); _PROTOTYPE( void put_irq_handler, (irq_hook_t *hook, int irq, irq_handler_t handler) ); -_PROTOTYPE( int rm_irq_handler, (int irq, int id) ); +_PROTOTYPE( void rm_irq_handler, (irq_hook_t *hook) ); /* klib*.s */ _PROTOTYPE( void int86, (void) ); @@ -88,11 +78,12 @@ _PROTOTYPE( int disable_irq, (irq_hook_t *hook) ); _PROTOTYPE( u16_t mem_rdw, (U16_t segm, vir_bytes offset) ); _PROTOTYPE( void phys_copy, (phys_bytes source, phys_bytes dest, phys_bytes count) ); -_PROTOTYPE( void phys_fill, (phys_bytes source, phys_bytes count, unsigned long pattern) ); +_PROTOTYPE( void phys_memset, (phys_bytes source, unsigned long pattern, + phys_bytes count) ); _PROTOTYPE( void phys_insb, (U16_t port, phys_bytes buf, size_t count) ); _PROTOTYPE( void phys_insw, (U16_t port, phys_bytes buf, size_t count) ); -_PROTOTYPE( void phys_outsb, (U16_t port, phys_bytes buf, size_t count)); -_PROTOTYPE( void phys_outsw, (U16_t port, phys_bytes buf, size_t count)); +_PROTOTYPE( void phys_outsb, (U16_t port, phys_bytes buf, size_t count) ); +_PROTOTYPE( void phys_outsw, (U16_t port, phys_bytes buf, size_t count) ); _PROTOTYPE( void reset, (void) ); _PROTOTYPE( void level0, (void (*func)(void)) ); _PROTOTYPE( void monitor, (void) ); diff --git a/kernel/start.c b/kernel/start.c index ab7d83214..1f9472bda 100755 --- a/kernel/start.c +++ b/kernel/start.c @@ -12,6 +12,7 @@ #include "protect.h" #include "proc.h" #include +#include FORWARD _PROTOTYPE( char *get_value, (_CONST char *params, _CONST char *key)); @@ -56,9 +57,9 @@ U16_t parmoff, parmsize; /* boot parameters offset and length */ /* Record miscellaneous information for user-space servers. */ kinfo.nr_procs = NR_PROCS; kinfo.nr_tasks = NR_TASKS; - kstrncpy(kinfo.release, OS_RELEASE, sizeof(kinfo.release)); + strncpy(kinfo.release, OS_RELEASE, sizeof(kinfo.release)); kinfo.release[sizeof(kinfo.release)-1] = '\0'; - kstrncpy(kinfo.version, OS_VERSION, sizeof(kinfo.version)); + strncpy(kinfo.version, OS_VERSION, sizeof(kinfo.version)); kinfo.version[sizeof(kinfo.version)-1] = '\0'; kinfo.proc_addr = (vir_bytes) proc; kinfo.kmem_base = vir2phys(0); @@ -75,16 +76,16 @@ U16_t parmoff, parmsize; /* boot parameters offset and length */ /* XT, AT or MCA bus? */ value = get_value(params, "bus"); - if (value == NIL_PTR || kstrcmp(value, "at") == 0) { + if (value == NIL_PTR || strcmp(value, "at") == 0) { machine.pc_at = TRUE; /* PC-AT compatible hardware */ - } else if (kstrcmp(value, "mca") == 0) { + } else if (strcmp(value, "mca") == 0) { machine.pc_at = machine.ps_mca = TRUE; /* PS/2 with micro channel */ } /* Type of VDU: */ value = get_value(params, "video"); /* EGA or VGA video unit */ - if (kstrcmp(value, "ega") == 0) machine.vdu_ega = TRUE; - if (kstrcmp(value, "vga") == 0) machine.vdu_vga = machine.vdu_ega = TRUE; + if (strcmp(value, "ega") == 0) machine.vdu_ega = TRUE; + if (strcmp(value, "vga") == 0) machine.vdu_vga = machine.vdu_ega = TRUE; /* Return to assembler code to switch to protected mode (if 286), * reload selectors and call main(). diff --git a/kernel/system.c b/kernel/system.c index bfe596895..ebd463a44 100755 --- a/kernel/system.c +++ b/kernel/system.c @@ -92,7 +92,7 @@ PUBLIC void sys_task() if (result != EDONTREPLY) { m.m_type = result; /* report status of call */ if (OK != lock_send(m.m_source, &m)) { - kprintf("Warning, SYSTASK couldn't reply to request from %d\n", + kprintf("Warning, SYSTASK couldn't reply to request from %d.\n", m.m_source); } } @@ -171,34 +171,36 @@ PRIVATE void initialize(void) /*===========================================================================* * init_proc * *===========================================================================*/ -PUBLIC int init_proc(proc_nr, proto_nr) -int proc_nr; /* slot of process to initialize */ -int proto_nr; /* prototype process to copy from */ +PUBLIC int init_proc(rc, rp) +register struct proc *rc; /* new (child) process pointer */ +struct proc *rp; /* prototype (parent) process */ { - register struct proc *rc, *rp; - register struct priv *sp; + register struct priv *sp; /* process' privilege structure */ int i; - /* Get a pointer to the process to initialize. */ - rc = proc_addr(proc_nr); - /* If there is a prototype process to initialize from, use it. Otherwise, * assume the caller will take care of initialization, but make sure that * the new process gets a pointer to a system properties structure. */ - if (isokprocn(proto_nr)) { - kprintf("INIT proc from prototype %d\n", proto_nr); - - } else { + if (rp == NIL_PROC) { /* new user process */ + kprintf("init_proc() for new user proc %d\n", proc_nr(rc)); + sp = &priv[USER_PRIV_ID]; + sp->s_proc_nr = ANY; /* misuse for users */ + rc->p_priv = sp; /* assign to process */ + return(OK); + } else if (rp == NIL_SYS_PROC) { /* new system process */ for (sp = BEG_PRIV_ADDR, i = 0; sp < END_PRIV_ADDR; ++sp, ++i) { if (sp->s_proc_nr == NONE) { /* found free slot */ - sp->s_proc_nr = proc_nr; /* set association */ + sp->s_proc_nr = proc_nr(rc); /* set association */ rc->p_priv = sp; /* assign to process */ return(OK); } } kprintf("No free PRIV structure!\n", NO_NUM); return(ENOSPC); /* out of resources */ + } else { /* forked process */ + + kprintf("init_proc() from prototype %d\n", proc_nr(rp)); } } @@ -206,26 +208,22 @@ int proto_nr; /* prototype process to copy from */ /*===========================================================================* * clear_proc * *===========================================================================*/ -PUBLIC void clear_proc(proc_nr) -int proc_nr; /* slot of process to clean up */ +PUBLIC void clear_proc(rc) +register struct proc *rc; /* slot of process to clean up */ { - register struct proc *rp, *rc; + register struct proc *rp; /* iterate over process table */ register struct proc **xpp; /* iterate over caller queue */ int i; - /* Get a pointer to the process that exited. */ - rc = proc_addr(proc_nr); - /* Turn off any alarm timers at the clock. */ reset_timer(&priv(rc)->s_alarm_timer); - /* Make sure the exiting process is no longer scheduled. */ + /* Make sure that the exiting process is no longer scheduled. */ if (rc->p_rts_flags == 0) lock_unready(rc); /* If the process being terminated happens to be queued trying to send a * message (e.g., the process was killed by a signal, rather than it doing - * an exit or it is forcibly shutdown in the stop sequence), then it must - * be removed from the message queues. + * a normal exit), then it must be removed from the message queues. */ if (rc->p_rts_flags & SENDING) { /* Check all proc slots to see if the exiting process is queued. */ @@ -245,26 +243,19 @@ int proc_nr; /* slot of process to clean up */ /* Check the table with IRQ hooks to see if hooks should be released. */ for (i=0; i < NR_IRQ_HOOKS; i++) { - if (irq_hooks[i].proc_nr == proc_nr) - irq_hooks[i].proc_nr = NONE; + if (irq_hooks[i].proc_nr == proc_nr(rc)) { + rm_irq_handler(&irq_hooks[i]); /* remove interrupt handler */ + irq_hooks[i].proc_nr = NONE; /* mark hook as free */ + } } -#if TEMP_CODE - /* Check if there are pending notifications. Release the buffers. */ - while (rc->p_ntf_q != NULL) { - i = (int) (rc->p_ntf_q - ¬ify_buffer[0]); - free_bit(i, notify_bitmap, NR_NOTIFY_BUFS); - rc->p_ntf_q = rc->p_ntf_q->n_next; - } -#endif - /* Now it is safe to release the process table slot. If this is a system * process, also release its privilege structure. Further cleanup is not * needed at this point. All important fields are reinitialized when the * slots are assigned to another, new process. */ rc->p_rts_flags = SLOT_FREE; - if (priv(rp)->s_flags & SYS_PROC) priv(rp)->s_proc_nr = NONE; + if (priv(rc)->s_flags & SYS_PROC) priv(rc)->s_proc_nr = NONE; } diff --git a/kernel/system/do_exec.c b/kernel/system/do_exec.c index b7ba512e0..fa5828cb3 100644 --- a/kernel/system/do_exec.c +++ b/kernel/system/do_exec.c @@ -8,6 +8,7 @@ * m1_p3: PR_IP_PTR (new instruction pointer) */ #include "../system.h" +#include #include #if USE_EXEC @@ -35,7 +36,7 @@ register message *m_ptr; /* pointer to request message */ #endif #endif #if (CHIP == INTEL) /* wipe extra LDT entries */ - kmemset(&rp->p_ldt[EXTRA_LDT_INDEX], 0, + phys_memset(vir2phys(&rp->p_ldt[EXTRA_LDT_INDEX]), 0, (LDT_SIZE - EXTRA_LDT_INDEX) * sizeof(rp->p_ldt[0])); #endif rp->p_reg.pc = (reg_t) m_ptr->PR_IP_PTR; /* set pc */ @@ -50,7 +51,7 @@ register message *m_ptr; /* pointer to request message */ for (np = rp->p_name; (*np & BYTE) >= ' '; np++) {} *np = 0; /* mark end */ } else { - kstrncpy(rp->p_name, "", P_NAME_LEN); + strncpy(rp->p_name, "", P_NAME_LEN); } return(OK); } diff --git a/kernel/system/do_exit.c b/kernel/system/do_exit.c index c690b0914..b17091639 100644 --- a/kernel/system/do_exit.c +++ b/kernel/system/do_exit.c @@ -28,13 +28,13 @@ message *m_ptr; /* pointer to request message */ exit_proc_nr = m_ptr->PR_PROC_NR; /* get exiting process */ if (exit_proc_nr != SELF) { /* PM tries to exit self */ if (! isokprocn(exit_proc_nr)) return(EINVAL); - clear_proc(exit_proc_nr); /* exit a user process */ + clear_proc(proc_addr(exit_proc_nr)); /* exit a user process */ return(OK); /* report back to PM */ } } /* The PM or some other system process requested to be exited. */ - clear_proc(m_ptr->m_source); + clear_proc(proc_addr(m_ptr->m_source)); return(EDONTREPLY); } #endif /* USE_EXIT */ diff --git a/kernel/system/do_irqctl.c b/kernel/system/do_irqctl.c index a30a06895..c87b21597 100644 --- a/kernel/system/do_irqctl.c +++ b/kernel/system/do_irqctl.c @@ -80,9 +80,9 @@ register message *m_ptr; /* pointer to request message */ return(EINVAL); } else if (m_ptr->m_source != irq_hooks[irq_hook_id].proc_nr) { return(EPERM); - } else { - r = rm_irq_handler(irq_vec, irq_hooks[irq_hook_id].id); } + /* Remove the handler and return. */ + rm_irq_handler(&irq_hooks[irq_hook_id]); break; default: diff --git a/kernel/system/do_memset.c b/kernel/system/do_memset.c index 224c43724..65e825dc5 100644 --- a/kernel/system/do_memset.c +++ b/kernel/system/do_memset.c @@ -18,10 +18,10 @@ PUBLIC int do_memset(m_ptr) register message *m_ptr; { /* Handle sys_memset(). */ - unsigned long pat; + unsigned long p; unsigned char c = m_ptr->MEM_CHAR; - pat = c | (c << 8) | (c << 16) | (c << 24); - phys_fill((phys_bytes) m_ptr->MEM_PTR, (phys_bytes) m_ptr->MEM_COUNT, pat); + p = c | (c << 8) | (c << 16) | (c << 24); + phys_memset((phys_bytes) m_ptr->MEM_PTR, p, (phys_bytes) m_ptr->MEM_COUNT); return(OK); } diff --git a/kernel/type.h b/kernel/type.h index c65e25fa6..98c16a094 100755 --- a/kernel/type.h +++ b/kernel/type.h @@ -3,11 +3,6 @@ typedef _PROTOTYPE( void task_t, (void) ); -/* Type accepted by kprintf(). This is a hack to accept both integers and - * char pointers in the same argument. - */ -typedef long karg_t; /* use largest type here */ - /* Process table and system property related types. */ typedef int proc_nr_t; /* process table entry number */ typedef short sys_id_t; /* system process index */ diff --git a/kernel/utility.c b/kernel/utility.c index 7d8753fa4..f8b827941 100755 --- a/kernel/utility.c +++ b/kernel/utility.c @@ -1,34 +1,143 @@ /* This file contains a collection of miscellaneous procedures: - * panic abort MINIX due to a fatal error + * panic: abort MINIX due to a fatal error + * kprintf: diagnostic output for the kernel + * + * Changes: + * simple printing to circular buffer (Jorrit N. Herder) + * + * This file contains the routines that take care of kernel messages, i.e., + * diagnostic output within the kernel. Kernel messages are not directly + * displayed on the console, because this must be done by the PRINT driver. + * Instead, the kernel accumulates characters in a buffer and notifies the + * output driver when a new message is ready. */ #include "kernel.h" -#include "assert.h" #include +#include +#include +#include +#include #include +#define END_OF_KMESS -1 +FORWARD _PROTOTYPE(void kputc, (int c)); /*===========================================================================* * panic * *===========================================================================*/ -PUBLIC void panic(s,n) -_CONST char *s; -int n; +PUBLIC void panic(mess,nr) +_CONST char *mess; +int nr; { /* The system has run aground of a fatal kernel error. Terminate execution. */ static int panicking = 0; if (panicking ++) return; /* prevent recursive panics */ - if (s != NULL) { - kprintf("\nKernel panic: %s", karg(s)); - if (n != NO_NUM) kprintf(" %d", n); + if (mess != NULL) { + kprintf("\nKernel panic: %s", mess); + if (nr != NO_NUM) kprintf(" %d", nr); kprintf("\n",NO_NUM); } prepare_shutdown(RBT_PANIC); } +/*===========================================================================* + * kprintf * + *===========================================================================*/ +PUBLIC void kprintf(const char *fmt, ...) /* format to be printed */ +{ + int c; /* next character in fmt */ + unsigned long u; /* hold number argument */ + int base; /* base of number arg */ + int negative = 0; /* print minus sign */ + static char x2c[] = "0123456789ABCDEF"; /* nr conversion table */ + char ascii[8 * sizeof(long) / 3 + 2]; /* string for ascii number */ + char *s = NULL; /* string to be printed */ + va_list argp; /* optional arguments */ + + va_start(argp, fmt); /* init variable arguments */ + + while((c=*fmt++) != 0) { + + if (c == '%') { /* expect format '%key' */ + switch(c = *fmt++) { /* determine what to do */ + + /* Known keys are %d, %u, %x, %s, and %%. This is easily extended + * with number types like %b and %o by providing a different base. + * Number type keys don't set a string to 's', but use the general + * conversion after the switch statement. + */ + case 'd': /* output decimal */ + u = va_arg(argp, int); + if (u < 0) { negative = 1; u = -u; } + base = 10; + break; + case 'u': /* output unsigned long */ + u = va_arg(argp, unsigned long); + base = 10; + break; + case 'x': /* output hexadecimal */ + u = va_arg(argp, unsigned long); + base = 0x10; + break; + case 's': /* output string */ + s = va_arg(argp, char *); + if (s == NULL) s = "(null)"; + break; + case '%': /* output percent */ + s = "%"; + break; + + /* Unrecognized key. */ + default: /* echo back %key */ + s = "%?"; + s[1] = c; /* set unknown key */ + } + + /* Assume a number if no string is set. Convert to ascii. */ + if (s == NULL) { + s = ascii + sizeof(ascii)-1; + *s = 0; + do { *--s = x2c[(u % base)]; } /* work backwards */ + while ((u /= base) > 0); + } + + /* This is where the actual output for format "%key" is done. */ + if (negative) kputc('-'); /* print sign if negative */ + while(*s != 0) { kputc(*s++); } /* print string/ number */ + } + else { + kputc(c); /* print and continue */ + } + } + kputc(END_OF_KMESS); /* terminate output */ + va_end(argp); /* end variable arguments */ +} + + +/*===========================================================================* + * kputc * + *===========================================================================*/ +PRIVATE void kputc(c) +int c; /* character to append */ +{ +/* Accumulate a single character for a kernel message. Send a notification + * the to PRINTF_PROC driver if an END_OF_KMESS is encountered. + */ + if (c != END_OF_KMESS) { + kmess.km_buf[kmess.km_next] = c; /* put normal char in buffer */ + if (kmess.km_size < KMESS_BUF_SIZE) + kmess.km_size += 1; + kmess.km_next = (kmess.km_next + 1) % KMESS_BUF_SIZE; + } else { + send_sig(PRINTF_PROC, SIGKMESS); + } +} + + #if TEMP_CODE