+#define NEW_TIME_COUNT 1
/* The file contais the clock task, which handles all time related functions.
* Important events that are handled by the CLOCK include alarm timers and
* (re)scheduling user processes.
/* Variables for and changed by the CLOCK's interrupt handler. */
PRIVATE irq_hook_t clock_hook;
+#if ! NEW_TIME_COUNT
PRIVATE clock_t pending_ticks; /* ticks seen by low level only */
+#endif
PRIVATE int sched_ticks = SCHED_RATE; /* counter: when 0, call scheduler */
PRIVATE struct proc *prev_ptr; /* last user process run by clock */
/* Go get a message. */
receive(ANY, &m);
+#if ! NEW_TIME_COUNT
/* Transfer ticks seen by the low level handler. */
lock(8, "realtime");
realtime += pending_ticks;
pending_ticks = 0;
unlock(8);
+#endif
/* Handle the request. */
switch (m.m_type) {
* The variables which are changed require more care:
* rp->p_user_time, rp->p_sys_time:
* These are protected by explicit locks in system.c.
+#if ! NEW_TIME_COUNT
* pending_ticks:
* This is protected by explicit locks in clock.c. Don't
* update realtime directly, since there are too many
* references to it to guard conveniently.
+#endif
* lost_ticks:
* Clock ticks counted outside the clock task.
* sched_ticks, prev_ptr:
register struct proc *rp;
register unsigned ticks;
message m;
+#if ! NEW_TIME_COUNT
clock_t now;
+#endif
/* Acknowledge the PS/2 clock interrupt. */
if (machine.ps_mca) outb(PORT_B, inb(PORT_B) | CLOCK_ACK_BIT);
* process is running, charge the billable process for system time as well.
* Thus the unbillable process' user time is the billable user's system time.
*/
+#if NEW_TIME_COUNT
+ ticks = lost_ticks + 1;
+ lost_ticks = 0;
+ realtime += ticks;
+#else
ticks = lost_ticks + 1;
lost_ticks = 0;
pending_ticks += ticks;
now = realtime + pending_ticks;
+#endif
/* Update administration. */
proc_ptr->p_user_time += ticks;
/* Check if do_clocktick() must be called. Done for alarms and scheduling.
* If bill_ptr == prev_ptr, there are no ready users so don't need sched().
*/
+#if NEW_TIME_COUNT
+ if (next_timeout <= realtime || (sched_ticks == 1 && bill_ptr == prev_ptr
+#else
if (next_timeout <= now || (sched_ticks == 1 && bill_ptr == prev_ptr
+#endif
&& rdy_head[PPRI_USER] != NIL_PROC))
{
m.NOTIFY_TYPE = HARD_INT;
- lock_notify(CLOCK, &m);
+ int_notify(CLOCK, &m);
}
else if (--sched_ticks <= 0) {
sched_ticks = SCHED_RATE; /* reset the quantum */
/* Get and return the current clock uptime in ticks.
* Be careful about pending_ticks.
*/
+#if NEW_TIME_COUNT
+ return(realtime);
+#else
clock_t uptime;
lock(9, "get_uptime");
uptime = realtime + pending_ticks;
unlock(9);
return(uptime);
+#endif
}
ep = &ex_data[vec_nr];
if (vec_nr == 2) { /* spurious NMI on some machines */
- kprintf("got spurious NMI\n",NO_ARG);
+ kprintf("got spurious NMI\n",NO_NUM);
return;
}
kprintf("pc = %d:", (unsigned) saved_proc->p_reg.cs);
kprintf("0x%x\n", (unsigned) saved_proc->p_reg.pc);
- /* If the exception originates in the kernel, shut down MINIX. Otherwise,
- * kill the process that caused it. If MINIX is shut down and the stop
- * sequence is skipped, the kprintf() output cannot be flushed by the TTY
- * driver. This leaves the user with a hanging system without proper
- * notification ...
- */
- if (istaskp(saved_proc)) { /* serious problem */
- kernel_exception = TRUE; /* directly shutdown */
- panic("exception in a kernel task", NO_NUM);
- } else {
- clear_proc(saved_proc->p_nr);
- kprintf("%s was killed by MINIX due to an exception",
- karg(saved_proc->p_name));
- }
+ kernel_exception = TRUE; /* directly shutdown */
+ panic("exception in a kernel task", NO_NUM);
}
EXTERN struct machine machine; /* machine information for users */
EXTERN struct kmessages kmess; /* diagnostic messages in kernel */
EXTERN struct randomness krandom; /* gather kernel random information */
-EXTERN struct memory mem[NR_MEMS]; /* base and size of chunks of memory */
/* Process scheduling information and the kernel reentry count. */
EXTERN struct proc *proc_ptr; /* pointer to currently running process */
/* Initialize the 8259s, finishing with all interrupts disabled. This is
* only done in protected mode, in real mode we don't touch the 8259s, but
* use the BIOS locations instead. The flag "mine" is set if the 8259s are
- * to be programmed for Minix, or to be reset to what the BIOS expects.
+ * to be programmed for MINIX, or to be reset to what the BIOS expects.
*/
int i;
* kstrcmp: lexicographical comparison of two strings
* kstrlen: get number of non-null characters in string
* kstrncpy: copy string and pad or copy up to n chars
- * kstrtoulb: convert string to unsigned long value
*
* This file contains the routines that take care of kernel messages, i.e.,
* diagnostic output within the kernel. Kernel messages are not directly
int c; /* character to append */
{
/* Accumulate a single character for a kernel message. Send a notification
- * the to TTY driver if the buffer if a END_OF_KMESS is encountered.
+ * the to TTY driver if an END_OF_KMESS is encountered.
*/
message m;
if (c != END_OF_KMESS) {
}
-/*=========================================================================*
- * kstrtoul *
- *=========================================================================*/
-PUBLIC unsigned long kstrtoul(strptr, endptr, base)
-const char *strptr; /* pointer to string to be parsed */
-char ** const endptr; /* store pointer to end here */
-int base;
-{
-/* A simplified version of strtoul() for the kernel to prevent including the
- * one in the ASNI library. No whitespaces are skipped, the numeric value is
- * expected at the start of 'string'.
- */
- register unsigned long val = 0;
- register int c;
- register unsigned int v;
- int overflow = 0;
-
- /* Get rid of 0x or 0X for hexidecimal values. */
- if (base==16 && *strptr=='0' && (*++strptr=='x' || *strptr=='X'))
- strptr++;
-
- /* Now parse the actual unsigned long number. */
- for (;;) {
- c = *strptr;
- if ('0' <= c && c <= '9') v = c - '0';
- else if ('a' <= c && c <= 'z') v = c - 'a' + 0xa;
- else if ('A' <= c && c <= 'Z') v = c - 'A' + 0xA;
- else break; /* end of number */
- if (v >= base) break; /* end of number */
- if (val > (ULONG_MAX - v) / base) overflow = 1;
- val = (val*base) + v;
- strptr++;
- }
-
- /* Tell caller where parsing ended unless a NULL pointer was passed. */
- if (endptr) *endptr = (char *) strptr;
-
- /* Done, return parsed value or maximum value on overflow. */
- return (overflow) ? ULONG_MAX : val;
-}
-
-
rp->p_memmap[S].mem_phys = text_base + text_clicks + data_clicks;
rp->p_memmap[S].mem_vir = data_clicks; /* empty - stack is in data */
- /* Remove server memory from the free memory list. The boot monitor
- * promises to put processes at the start of memory chunks. The
- * tasks all use same base address, so only the first task changes
- * the memory lists. The servers and init have their own memory
- * spaces and their memory will be removed from the list.
- */
- for (memp = mem; memp < &mem[NR_MEMS]; memp++) {
- if (memp->base == text_base) {
- memp->base += text_clicks + data_clicks;
- memp->size -= text_clicks + data_clicks;
- }
- }
-
/* Set initial register values. The processor status word for tasks
* is different from that of other processes because tasks can
* access I/O; this is not allowed to less-privileged processes
}
/* Set ready. The HARDWARE task is never ready. */
-
#if ENABLE_K_DEBUGGING
rp->p_ready = 0;
#endif
hdrindex ++;
phys_copy(aout + hdrindex * A_MINHDR,vir2phys(&e_hdr),(phys_bytes) A_MINHDR);
if (e_hdr.a_flags & A_IMG) {
-
kinfo.bootdev_base = e_hdr.a_syms;
kinfo.bootdev_size = e_hdr.a_data;
-
- /* Remove from free list, to prevent being overwritten. */
- bootdev_base = e_hdr.a_syms >> CLICK_SHIFT;
- bootdev_clicks = (e_hdr.a_total + CLICK_SIZE-1) >> CLICK_SHIFT;
- for (memp = mem; memp < &mem[NR_MEMS]; memp++) {
- if (memp->base == bootdev_base) {
- memp->base += bootdev_clicks;
- memp->size -= bootdev_clicks;
- }
- }
}
#endif
- /* This actually is not needed, because ready() already set 'proc_ptr.' */
- lock_pick_proc();
- bill_ptr = proc_addr(IDLE); /* it has to point somewhere */
-
- /* MINIX is now ready. Display the startup banner to the user and return
- * to the assembly code to start running the current process.
+ /* MINIX is now ready. All boot image processes are on the ready queue.
+ * Return to the assembly code to start running the current process.
*/
- announce();
+ bill_ptr = proc_addr(IDLE); /* it has to point somewhere */
+ announce(); /* print MINIX startup banner */
restart();
}
{
/* Display the MINIX startup banner. */
kprintf("MINIX %s. Copyright 2001 Prentice-Hall, Inc.\n",
- karg(kinfo.version));
+ karg(OS_RELEASE "." OS_VERSION));
#if (CHIP == INTEL)
/* Real mode, or 16/32-bit protected mode? */
shutting_down = TRUE; /* flag for sys_exit() */
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_ARG);
+ 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_ARG);
+ kprintf("\nNotifying system services about MINIX shutdown.\n", NO_NUM);
set_timer(&shutdown_timer, get_uptime(), stop_sequence);
}
}
if (s != NULL) {
kprintf("\nKernel panic: %s", karg(s));
if (n != NO_NUM) kprintf(" %d", n);
- kprintf("\n",NO_ARG);
+ kprintf("\n",NO_NUM);
}
prepare_shutdown(RBT_PANIC);
}
#define NEW_ELOCKED_CHECK 1
-#define NEW_SCHED_Q 1
+#define NEW_SCHED_Q 0
#define OLD_SEND 0
#define OLD_RECV 0
/* This file contains essentially all of the process and message handling.
* As well as several entry points used from the interrupt and task level:
*
* lock_notify: send a notification to inform a process of a system event
+ * int_notify: same as above, but from an interrupt handler (no locking)
* lock_send: send a message to a process
* lock_ready: put a process on one of the ready queues so it can be run
* lock_unready: remove a process from the ready queues
* lock_sched: a process has run too long; schedule another one
- * lock_pick_proc: pick a process to run (used by system initialization)
*
* Changes:
* , 2005 better protection in sys_call() (Jorrit N. Herder)
int dst; /* to whom is message being sent? */
message *m_ptr; /* pointer to message buffer */
{
-/* Safe gateway to mini_notify() for tasks and interrupt handlers. This
- * function checks if it is called from an interrupt handler and ensures
- * that the correct message source is put on the notification.
+/* Safe gateway to mini_notify() for tasks. Don't use this function from the
+ * interrupt level, as it will reenable interrupts (because of the unlock()
+ * call). For interrupt handlers, int_notify() is available.
*/
int result;
- struct proc *caller_ptr;
-
+ register struct proc *caller_ptr;
lock(0, "notify");
caller_ptr = (k_reenter >= 0) ? proc_addr(HARDWARE) : proc_ptr;
result = mini_notify(caller_ptr, dst, m_ptr);
return(result);
}
+
+/*==========================================================================*
+ * int_notify *
+ *==========================================================================*/
+PUBLIC int int_notify(dst, m_ptr)
+int dst; /* to whom is message being sent? */
+message *m_ptr; /* pointer to message buffer */
+{
+/* Gateway to mini_notify() for interrupt handlers. This function doesn't
+ * use lock() and unlock() because interrupts are already disabled.
+ */
+ int result;
+ register struct proc *caller_ptr = proc_addr(HARDWARE);
+ result = mini_notify(caller_ptr, dst, m_ptr);
+ return(result);
+}
+
+
/*===========================================================================*
* pick_proc *
*===========================================================================*/
xp->p_nextready = NIL_PROC; /* mark new end of queue */
#else
- rdy_tail[queue]->p_nextready = rdy_head[queue];
- rdy_tail[queue] = rdy_head[queue];
- rdy_head[queue] = rdy_head[queue]->p_nextready;
- rdy_tail[queue]->p_nextready = NIL_PROC;
+ rdy_tail[queue]->p_nextready = rdy_head[queue]; /* add expired to end */
+ rdy_tail[queue] = rdy_head[queue]; /* set new tail */
+ rdy_head[queue] = rdy_head[queue]->p_nextready; /* set new head */
+ rdy_tail[queue]->p_nextready = NIL_PROC; /* mark new end */
#endif
pick_proc();
}
-/*==========================================================================*
- * lock_pick_proc *
- *==========================================================================*/
-PUBLIC void lock_pick_proc()
-{
-/* Safe gateway to pick_proc() for tasks. */
- lock(1, "pick_proc");
- pick_proc();
- unlock(1);
-}
-
/*==========================================================================*
* lock_send *
(register const char *s1, register const char *s2, register size_t n));
_PROTOTYPE( char *kstrncpy,
(char *s1, register const char *s2, register const size_t n));
-_PROTOTYPE( unsigned long kstrtoul,
- (const char *string, char ** const end, int base) );
-#define NO_ARG 0
#define karg(arg) (karg_t) (arg)
_PROTOTYPE( void kprintf, (const char *fmt, karg_t arg) );
/* proc.c */
_PROTOTYPE( int sys_call, (int function, int src_dest, message *m_ptr) );
_PROTOTYPE( int lock_notify, (int dst, message *m_ptr) );
+_PROTOTYPE( int int_notify, (int dst, message *m_ptr) );
_PROTOTYPE( int lock_send, (int dst, message *m_ptr) );
-_PROTOTYPE( void lock_pick_proc, (void) );
_PROTOTYPE( void lock_ready, (struct proc *rp) );
_PROTOTYPE( void lock_sched, (int queue) );
_PROTOTYPE( void lock_unready, (struct proc *rp) );
#include "protect.h"
#include "proc.h"
-FORWARD _PROTOTYPE( void mem_init, (_CONST char *params));
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.version, OS_RELEASE "." OS_VERSION, 6);
+ kstrncpy(kinfo.release, OS_RELEASE, 4);
+ kstrncpy(kinfo.version, OS_VERSION, 4);
kinfo.proc_addr = (vir_bytes) proc;
kinfo.kmem_base = vir2phys(0);
kinfo.kmem_size = (phys_bytes) &end;
if (kstrcmp(value, "ega") == 0) machine.vdu_ega = TRUE;
if (kstrcmp(value, "vga") == 0) machine.vdu_vga = machine.vdu_ega = TRUE;
- /* Initialize free memory list from size passed by boot monitor. */
- mem_init(params);
-
/* Return to assembler code to switch to protected mode (if 286),
* reload selectors and call main().
*/
}
-
-/* In real mode only 1M can be addressed, and in 16-bit protected we can go
- * no further than we can count in clicks. (The 286 is further limited by
- * its 24 bit address bus, but we can assume in that case that no more than
- * 16M memory is reported by the BIOS.)
- */
-#define MAX_REAL 0x00100000L
-#define MAX_16BIT (0xFFF0L << CLICK_SHIFT)
-
-/*=========================================================================*
- * mem_init *
- *=========================================================================*/
-PRIVATE void mem_init(params)
-_CONST char *params; /* boot monitor parameters */
-{
-/* Initialize the free memory list from the 'memory' boot variable. Translate
- * the byte offsets and sizes in this list to clicks, properly truncated. Also
- * make sure that we don't exceed the maximum address space of the 286 or the
- * 8086, i.e. when running in 16-bit protected mode or real mode.
- */
- long base, size, limit;
- char *s, *end; /* use to parse boot variable */
- int i;
- struct memory *memp;
-#if _WORD_SIZE == 2
- unsigned long max_address;
-#endif
-
- /* The available memory is determined by MINIX' boot loader as a list of
- * (base:size)-pairs in boothead.s. The 'memory' boot variable is set in
- * in boot.s. The format is "b0:s0,b1:s1,b2:s2", where b0:s0 is low mem,
- * b1:s1 is mem between 1M and 16M, b2:s2 is mem above 16M. Pairs b1:s1
- * and b2:s2 are combined if the memory is adjacent.
- */
- s = get_value(params, "memory"); /* get memory boot variable */
- for (i = 0; i < NR_MEMS; i++) {
- memp = &mem[i]; /* next mem chunk is stored here */
- base = size = 0; /* initialize next base:size pair */
- if (*s != 0) { /* get fresh data, unless at end */
-
- /* Read fresh base and expect colon as next char. */
- base = kstrtoul(s, &end, 0x10); /* get number */
- if (end != s && *end == ':') s = ++end; /* skip ':' */
- else *s=0; /* terminate, should not happen */
-
- /* Read fresh size and expect comma or assume end. */
- size = kstrtoul(s, &end, 0x10); /* get number */
- if (end != s && *end == ',') s = ++end; /* skip ',' */
- else *s=0; /* found end */
- }
- limit = base + size; /* limit is used for validity check */
-#if _WORD_SIZE == 2
- max_address = kinfo.protected ? MAX_16BIT : MAX_REAL;
- if (limit > max_address) limit = max_address;
-#endif
- base = (base + CLICK_SIZE-1) & ~(long)(CLICK_SIZE-1);
- limit &= ~(long)(CLICK_SIZE-1);
- if (limit <= base) continue;
- memp->base = base >> CLICK_SHIFT;
- memp->size = (limit - base) >> CLICK_SHIFT;
- }
-}
-
-
/*==========================================================================*
* get_value *
*==========================================================================*/
/* Build notification message and return. */
m.NOTIFY_TYPE = HARD_INT;
m.NOTIFY_ARG = hook->irq;
- lock_notify(hook->proc_nr, &m);
+ int_notify(hook->proc_nr, &m);
return(hook->policy & IRQ_REENABLE);
}
int proc_nr; /* process to be signalled */
int sig_nr; /* signal to be sent, 1 to _NSIG */
{
-/* A task wants to send a signal to a process. Examples of such tasks are:
+/* A system process wants to send a signal to a process. Examples are:
* TTY wanting to cause SIGINT upon getting a DEL
* CLOCK wanting to cause SIGALRM when timer expires
- * FS also uses this to send a signal, via the SYS_KILL message. Signals are
- * handled by sending a message to PM. This central function handles the
+ * FS wanting to cause SIGPIPE for a broken pipe
+ * Signals are handled by sending a message to PM. This function handles the
* signals and makes sure the PM gets them by sending a notification. The
* process being signaled is blocked while PM has not finished all signals
* for it. These signals are counted in p_pendcount, and the SIG_PENDING
/* Check copy count. */
if (bytes <= 0) {
- kprintf("v_cp: copy count problem <= 0\n", NO_ARG);
+ kprintf("v_cp: copy count problem <= 0\n", NO_NUM);
return(EDOM);
}
/* Check if mapping succeeded. */
if (phys_addr[i] <= 0 && vir_addr[i]->segment != PHYS_SEG) {
- kprintf("v_cp: Mapping failed ... phys <= 0\n", NO_ARG);
+ kprintf("v_cp: Mapping failed ... phys <= 0\n", NO_NUM);
return(EFAULT);
}
}
/* Check if process number was given implictly with SELF and is valid. */
if (vir_addr[i].proc_nr == SELF) vir_addr[i].proc_nr = m_ptr->m_source;
if (! isokprocn(vir_addr[i].proc_nr) && vir_addr[i].segment != PHYS_SEG) {
- kprintf("do_vircopy: illegal proc nr, while not phys addr\n",NO_ARG);
+ kprintf("do_vircopy: illegal proc nr, while not phys addr\n",NO_NUM);
return(EINVAL);
}
* vir_bytes. Especially copying by the PM on do_fork() is affected.
*/
if (bytes != (vir_bytes) bytes) {
- kprintf("do_vircopy: overflow\n", NO_ARG);
+ kprintf("do_vircopy: overflow\n", NO_NUM);
return(E2BIG);
}
src_phys = vir2phys(irq_hooks);
break;
}
- case GET_MEMCHUNKS: {
- length = sizeof(struct memory) * NR_MEMS;
- src_phys = vir2phys(mem);
- break;
- }
case GET_SCHEDINFO: {
/* This is slightly complicated because we need two data structures
* at once, otherwise the scheduling information may be incorrect.