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
* 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.
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);
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); }
}
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);
}
/*=========================================================================*
* 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 *
*==========================================================================*/
.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
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
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
+++ /dev/null
-/* 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 <signal.h>
-#include <minix/com.h>
-
-#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;
-}
-
-
*/
#include "kernel.h"
#include <signal.h>
+#include <string.h>
#include <unistd.h>
#include <a.out.h>
#include <minix/callnr.h>
FORWARD _PROTOTYPE( void announce, (void));
FORWARD _PROTOTYPE( void shutdown, (timer_t *tp));
+#define SHUTDOWN_TICKS 5 /* time allowed to do cleanup */
+
/*===========================================================================*
* main *
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. */
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 */
/* 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;
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
}
* 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
return; /* await sys_abort() from TTY */
}
- /* Send signal to TTY so that it can switch to the primary console. */
- send_sig(TTY, SIGKSTOP);
+ /* 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.
+ */
+ for (rp=BEG_PROC_ADDR; rp<END_PROC_ADDR; rp++) {
+ if (! isemptyp(rp) && (priv(rp)->s_flags & SYS_PROC) && ! iskernelp(rp))
+ send_sig(proc_nr(rp), 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.
+ /* 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 */
- 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);
- }
+ set_timer(&shutdown_timer, get_uptime() + SHUTDOWN_TICKS, shutdown);
}
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
#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)
_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) );
/* 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) );
_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) );
_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) );
#include "protect.h"
#include "proc.h"
#include <stdlib.h>
+#include <string.h>
FORWARD _PROTOTYPE( char *get_value, (_CONST char *params, _CONST char *key));
/* 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);
/* 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().
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);
}
}
/*===========================================================================*
* 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));
}
}
/*===========================================================================*
* 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. */
/* 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 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;
+ 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 */
+ }
}
-#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
* 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;
}
* m1_p3: PR_IP_PTR (new instruction pointer)
*/
#include "../system.h"
+#include <string.h>
#include <signal.h>
#if USE_EXEC
#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 */
for (np = rp->p_name; (*np & BYTE) >= ' '; np++) {}
*np = 0; /* mark end */
} else {
- kstrncpy(rp->p_name, "<unset>", P_NAME_LEN);
+ strncpy(rp->p_name, "<unset>", P_NAME_LEN);
}
return(OK);
}
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 */
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:
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);
}
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 */
/* 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 <unistd.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <signal.h>
#include <minix/com.h>
+#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