Initial revision

This commit is contained in:
Ben Gras
2005-04-21 14:53:53 +00:00
commit 9865aeaa79
2264 changed files with 411685 additions and 0 deletions

183
kernel/Makefile Executable file
View File

@@ -0,0 +1,183 @@
# Makefile for kernel
# Directories
u = /usr
i = $u/include
s = $i/sys
h = $i/minix
b = $i/ibm
l = $u/lib
n = $i/net
g = $n/gen
# Programs, flags, etc.
CC = exec cc
CPP = $l/cpp
LD = $(CC) -.o
CFLAGS = -I$i
LDFLAGS = -i
LIBS = -lsys -lutils -ltimers
HEAD = mpx.o
OBJS = start.o protect.o klibc.o klib.o table.o main.o proc.o \
i8259.o exception.o system.o clock.o memory.o misc.o \
dummy.o \
rtl8139.o pci.o pci_table.o
SYS = system/system.a
# What to make.
kernel build: $(HEAD) $(OBJS) $(SYS)
$(LD) $(LDFLAGS) -o $@ $(HEAD) $(OBJS) $(SYS) $(CLOCK) $(LIBS)
install -S 0 $@
$(SYS):
cd system && $(MAKE)
all install:
cd system && $(MAKE) -$(MAKEFLAGS) $@
clean:
cd system && $(MAKE) -$(MAKEFLAGS) $@
rm -f *.o *.bak kernel
# Dependencies
a = kernel.h const.h type.h proto.h glo.h \
$h/config.h $h/const.h $h/type.h $h/ipc.h \
$s/types.h \
$i/string.h $i/limits.h $i/errno.h $i/timers.h \
$b/portio.h $b/interrupt.h $b/bios.h $b/ports.h
klibc.o: $a
klib.o: $h/config.h $h/const.h const.h sconst.h protect.h
klib.o: klib88.s klib386.s
mpx.o: $h/config.h $h/const.h $h/com.h const.h protect.h sconst.h
mpx.o: mpx88.s mpx386.s
mpx.o: mpx88.s mpx386.s
clock.o: $a
clock.o: $i/signal.h
clock.o: $h/callnr.h
clock.o: $h/com.h
clock.o: proc.h
start.o: $a
start.o: $i/stdlib.h
start.o: protect.h
exception.o: $a
exception.o: $i/signal.h
exception.o: $h/com.h
exception.o: proc.h
driver.o: $a $d
driver.o: $h/ioctl.h
driver.o: $s/ioc_disk.h
drvlib.o: $a $d $(dl)
i8259.o: $a
main.o: $a
main.o: $i/unistd.h
main.o: $i/signal.h
main.o: $i/a.out.h
main.o: $h/callnr.h
main.o: $h/com.h
main.o: proc.h
main.o: sendmask.h
memory.o: $a
memory.o: proc.h
memory.o: protect.h
misc.o: $a
misc.o: $i/stdlib.h
misc.o: $h/com.h
misc.o: assert.h
printer.o: $a
printer.o: $h/callnr.h
printer.o: $h/com.h
printer.o: proc.h
proc.o: $a
proc.o: $h/callnr.h
proc.o: $h/com.h
proc.o: proc.h
proc.o: sendmask.h
protect.o: $a
protect.o: $h/com.h
protect.o: proc.h
protect.o: protect.h
system.o: $a
system.o: $i/stdlib.h
system.o: $i/signal.h
system.o: $i/unistd.h
system.o: $s/sigcontext.h
system.o: $s/ptrace.h
system.o: $h/ioctl.h
system.o: $s/svrctl.h
system.o: $h/callnr.h
system.o: $h/com.h
system.o: system.h
system.o: proc.h
system.o: protect.h
system.o: assert.h
system.o: sendmask.h
table.o: $a
table.o: $i/stdlib.h
table.o: $i/termios.h
table.o: $h/com.h
table.o: proc.h
table.o: sendmask.h
table.o: $b/int86.h
rtl8139.o: $a
rtl8139.o: $h/com.h
rtl8139.o: $n/hton.h
rtl8139.o: $g/ether.h
rtl8139.o: $g/eth_io.h
rtl8139.o: $i/stddef.h
rtl8139.o: assert.h
rtl8139.o: pci.h
rtl8139.o: proc.h
rtl8139.o: rtl8139.h
pci.o: $a
pci.o: assert.h
pci.o: pci.h
pci.o: pci_amd.h
pci.o: pci_intel.h
pci.o: pci_via.h
pci.o: pci_sis.h
pci_table.o: $a
pci_table.o: pci.h
dummy.o: $a
system/system.a: $a $h/devio.h $h/com.h
system/system.a: proc.h protect.h system.h sendmask.h
system/system.a: $s/ptrace.h $s/sigcontext.h
system/system.a: $i/signal.h $i/unistd.h
system/system.a: system/alarms.c
system/system.a: system/copying.c
system/system.a: system/devio.c
system/system.a: system/irqctl.c
system/system.a: system/misc.c
system/system.a: system/proctl.c
system/system.a: system/sigctl.c
system/system.a: system/srvrctl.c
system/system.a: system/tracing.c
system/system.a: system/debugging.c
system/system.a: system/do_copy.c
system/system.a: system/do_vcopy.c

25
kernel/assert.h Executable file
View File

@@ -0,0 +1,25 @@
/* assert.h */
#ifndef NDEBUG /* 8086 must do without training wheels. */
#define NDEBUG (_WORD_SIZE == 2)
#endif
#if !NDEBUG
#define INIT_ASSERT static char *assert_file= __FILE__;
void bad_assertion(char *file, int line, char *what);
void bad_compare(char *file, int line, int lhs, char *what, int rhs);
#define assert(x) (!(x) ? bad_assertion(assert_file, __LINE__, #x) \
: (void) 0)
#define compare(a,t,b) (!((a) t (b)) ? bad_compare(assert_file, __LINE__, \
(a), #a " " #t " " #b, (b)) : (void) 0)
#else /* NDEBUG */
#define INIT_ASSERT /* nothing */
#define assert(x) (void)0
#define compare(a,t,b) (void)0
#endif /* NDEBUG */

BIN
kernel/build Executable file

Binary file not shown.

362
kernel/clock.c Executable file
View File

@@ -0,0 +1,362 @@
/* 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.
* The CLOCK offers a direct interface to kernel processes. System services
* can access its services through system calls, such as sys_syncalrm(). The
* CLOCK task thus is hidden for the outside.
*
* Changes:
* Mar 18, 2004 clock interface moved to SYSTEM task (Jorrit N. Herder)
* Oct 10, 2004 call vector + return values allowed (Jorrit N. Herder)
* Sep 30, 2004 source code documentation updated (Jorrit N. Herder)
* Sep 24, 2004 redesigned timers and alarms (Jorrit N. Herder)
* Jun 04, 2004 new timeout flag alarm functionality (Jorrit N. Herder)
*
* The function do_clocktick() is not triggered from the clock library, but
* by the clock's interrupt handler when a watchdog timer has expired or
* another user process must be scheduled.
*
* In addition to the main clock_task() entry point, which starts the main
* loop, there are several other minor entry points:
* clock_stop: called just before MINIX shutdown
* get_uptime: get realtime since boot in clock ticks
* set_timer: set a watchdog timer (*, see note below!)
* reset_timer: reset a watchdog timer (*)
* calc_elapsed: do timing measurements: get delta ticks and pulses
* read_clock: read the counter of channel 0 of the 8253A timer
*
* (*) The CLOCK task keeps tracks of watchdog timers for the entire kernel.
* The watchdog functions of expired timers are executed in do_clocktick().
* It is crucial that watchdog functions cannot block, or the CLOCK task may
* be blocked. Do not send() a message when the receiver is not expecting it.
* The use of notify(), which always returns, is strictly preferred!
*/
#include "kernel.h"
#include "proc.h"
#include <signal.h>
#include <minix/com.h>
/* Function prototype for PRIVATE functions. */
FORWARD _PROTOTYPE( void init_clock, (void) );
FORWARD _PROTOTYPE( int clock_handler, (irq_hook_t *hook) );
FORWARD _PROTOTYPE( int do_clocktick, (message *m_ptr) );
/* Constant definitions. */
#define SCHED_RATE (MILLISEC*HZ/1000) /* number of ticks per schedule */
#define MILLISEC 100 /* how often to call the scheduler */
/* Clock parameters. */
#if (CHIP == INTEL)
#define COUNTER_FREQ (2*TIMER_FREQ) /* counter frequency using square wave */
#define LATCH_COUNT 0x00 /* cc00xxxx, c = channel, x = any */
#define SQUARE_WAVE 0x36 /* ccaammmb, a = access, m = mode, b = BCD */
/* 11x11, 11 = LSB then MSB, x11 = sq wave */
#define TIMER_COUNT ((unsigned) (TIMER_FREQ/HZ)) /* initial value for counter*/
#define TIMER_FREQ 1193182L /* clock frequency for timer in PC and AT */
#define CLOCK_ACK_BIT 0x80 /* PS/2 clock interrupt acknowledge bit */
#endif
#if (CHIP == M68000)
#define TIMER_FREQ 2457600L /* timer 3 input clock frequency */
#endif
/* The CLOCK's timers queue. The functions in <timers.h> operate on this.
* The process structure contains one timer per type of alarm (SIGNALRM,
* SYNCALRM, and FLAGALRM), which means that a process can have a single
* outstanding timer for each alarm type.
* If other kernel parts want to use additional timers, they must declare
* their own persistent timer structure, which can be passed to the clock
* via (re)set_timer().
* When a timer expires its watchdog function is run by the CLOCK task.
*/
PRIVATE timer_t *clock_timers; /* queue of CLOCK timers */
PRIVATE clock_t next_timeout; /* realtime that next timer expires */
/* The boot time and the current real time. The real time is incremented by
* the clock on each clock tick. The boot time is set by a utility program
* after system startup to prevent troubles reading the CMOS.
*/
PRIVATE clock_t realtime; /* real time clock */
/* Variables changed by interrupt handler. */
PRIVATE clock_t pending_ticks; /* ticks seen by low level only */
PRIVATE int sched_ticks = SCHED_RATE; /* counter: when 0, call scheduler */
PRIVATE struct proc *prev_ptr; /* last user process run by clock */
/*===========================================================================*
* clock_task *
*===========================================================================*/
PUBLIC void clock_task()
{
/* Main program of clock task. It corrects realtime by adding pending ticks
* seen only by the interrupt service, then it determines which call this is
* by looking at the message type and dispatches.
*/
message m; /* message buffer for both input and output */
int result;
init_clock(); /* initialize clock task */
/* Main loop of the clock task. Get work, process it, sometimes reply. */
while (TRUE) {
/* Go get a message. */
receive(ANY, &m);
/* Transfer ticks seen by the low level handler. */
lock();
realtime += pending_ticks;
pending_ticks = 0;
unlock();
/* Handle the request. */
switch (m.m_type) {
case HARD_INT:
result = do_clocktick(&m); /* handle clock tick */
break;
default: /* illegal message type */
kprintf("CLOCK got illegal request from %d.\n", m.m_source);
result = EBADREQUEST;
}
/* Send reply, unless inhibited, e.g. by do_clocktick(). */
if (result != EDONTREPLY) {
m.m_type = result;
send(m.m_source, &m);
}
}
}
/*===========================================================================*
* do_clocktick *
*===========================================================================*/
PRIVATE int do_clocktick(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Despite its name, this routine is not called on every clock tick. It
* is called on those clock ticks when a lot of work needs to be done.
*/
register struct proc *rp;
register int proc_nr;
timer_t *tp;
struct proc *p;
/* Check if a clock timer expired and run its watchdog function. */
if (next_timeout <= realtime) {
tmrs_exptimers(&clock_timers, realtime);
next_timeout = clock_timers == NULL ?
TMR_NEVER : clock_timers->tmr_exp_time;
}
/* If a user process has been running too long, pick another one. */
if (--sched_ticks == 0) {
if (bill_ptr == prev_ptr) lock_sched(); /* process has run too long */
sched_ticks = SCHED_RATE; /* reset quantum */
prev_ptr = bill_ptr; /* new previous process */
}
/* Inhibit sending a reply. */
return(EDONTREPLY);
}
/*===========================================================================*
* clock_handler *
*===========================================================================*/
PRIVATE int clock_handler(hook)
irq_hook_t *hook;
{
/* This executes on every clock tick (i.e., every time the timer chip
* generates an interrupt). It does a little bit of work so the clock
* task does not have to be called on every tick.
*
* Switch context to do_clocktick() if an alarm has gone off.
* Also switch there to reschedule if the reschedule will do something.
* This happens when
* (1) quantum has expired
* (2) current process received full quantum (as clock sampled it!)
* (3) something else is ready to run.
*
* Many global global and static variables are accessed here. The safety
* of this must be justified. Most of them are not changed here:
* k_reenter:
* This safely tells if the clock interrupt is nested.
* proc_ptr, bill_ptr:
* These are used for accounting. It does not matter if proc.c
* is changing them, provided they are always valid pointers,
* since at worst the previous process would be billed.
* next_timeout, realtime, sched_ticks, bill_ptr, prev_ptr
* rdy_head[PPRI_USER]
* These are tested to decide whether to call notify(). It
* does not matter if the test is sometimes (rarely) backwards
* due to a race, since this will only delay the high-level
* processing by one tick, or call the high level unnecessarily.
* The variables which are changed require more care:
* rp->user_time, rp->sys_time:
* These are protected by explicit locks in system.c. They are
* not properly protected in dmp.c (the increment here is not
* atomic) but that hardly matters.
* 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.
* lost_ticks:
* Clock ticks counted outside the clock task.
* sched_ticks, prev_ptr:
* Updating these competes with similar code in do_clocktick().
* No lock is necessary, because if bad things happen here
* (like sched_ticks going negative), the code in do_clocktick()
* will restore the variables to reasonable values, and an
* occasional missed or extra sched() is harmless.
*
* Are these complications worth the trouble? Well, they make the system 15%
* faster on a 5MHz 8088, and make task debugging much easier since there are
* no task switches on an inactive system.
*/
register struct proc *rp;
register unsigned ticks;
clock_t now;
/* Acknowledge the PS/2 clock interrupt. */
if (ps_mca) outb(PORT_B, inb(PORT_B) | CLOCK_ACK_BIT);
/* Update user and system accounting times. Charge the current process for
* user time. If the current process is not billable, that is, if a non-user
* 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.
*/
ticks = lost_ticks + 1;
lost_ticks = 0;
pending_ticks += ticks;
now = realtime + pending_ticks;
rp = (k_reenter == 0) ? proc_ptr : proc_addr(HARDWARE);
rp->user_time += ticks;
if (rp != bill_ptr && rp != proc_addr(IDLE)) bill_ptr->sys_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 (next_timeout <= now || (sched_ticks == 1 && bill_ptr == prev_ptr
&& rdy_head[PPRI_USER] != NIL_PROC))
{
notify(CLOCK, HARD_INT);
}
else if (--sched_ticks == 0) {
sched_ticks = SCHED_RATE; /* reset quantum */
prev_ptr = bill_ptr; /* new previous process */
}
return 1; /* reenable clock interrupts */
}
/*===========================================================================*
* get_uptime *
*===========================================================================*/
PUBLIC clock_t get_uptime()
{
/* Get and return the current clock uptime in ticks.
* Be careful about pending_ticks.
*/
clock_t uptime;
lock();
uptime = realtime + pending_ticks;
unlock();
return(uptime);
}
/*===========================================================================*
* set_timer *
*===========================================================================*/
PUBLIC void set_timer(tp, exp_time, watchdog)
struct timer *tp; /* pointer to timer structure */
clock_t exp_time; /* expiration realtime */
tmr_func_t watchdog; /* watchdog to be called */
{
/* Insert the new timer in the active timers list. Always update the
* next timeout time by setting it to the front of the active list.
*/
tmrs_settimer(&clock_timers, tp, exp_time, watchdog);
next_timeout = clock_timers->tmr_exp_time;
}
/*===========================================================================*
* reset_timer *
*===========================================================================*/
PUBLIC void reset_timer(tp)
struct timer *tp; /* pointer to timer structure */
{
/* The timer pointed to by 'tp' is no longer needed. Remove it from both the
* active and expired lists. Always update the next timeout time by setting
* it to the front of the active list.
*/
tmrs_clrtimer(&clock_timers, tp);
next_timeout = (clock_timers == NULL) ?
TMR_NEVER : clock_timers->tmr_exp_time;
}
#if (CHIP == INTEL)
/*===========================================================================*
* init_clock *
*===========================================================================*/
PRIVATE void init_clock()
{
/* Initialize channel 0 of the 8253A timer to, e.g., 60 Hz. */
static irq_hook_t clock_hook;
outb(TIMER_MODE, SQUARE_WAVE); /* set timer to run continuously */
outb(TIMER0, TIMER_COUNT); /* load timer low byte */
outb(TIMER0, TIMER_COUNT >> 8); /* load timer high byte */
put_irq_handler(&clock_hook, CLOCK_IRQ, clock_handler);/* register handler */
enable_irq(&clock_hook); /* ready for clock interrupts */
}
/*===========================================================================*
* clock_stop *
*===========================================================================*/
PUBLIC void clock_stop()
{
/* Reset the clock to the BIOS rate. (For rebooting) */
outb(TIMER_MODE, 0x36);
outb(TIMER0, 0);
outb(TIMER0, 0);
}
/*===========================================================================*
* read_clock *
*===========================================================================*/
PUBLIC unsigned long read_clock()
{
/* Read the counter of channel 0 of the 8253A timer. This counter counts
* down at a rate of TIMER_FREQ and restarts at TIMER_COUNT-1 when it
* reaches zero. A hardware interrupt (clock tick) occurs when the counter
* gets to zero and restarts its cycle.
*/
unsigned count;
lock();
outb(TIMER_MODE, LATCH_COUNT);
count = inb(TIMER0);
count |= (inb(TIMER0) << 8);
unlock();
return count;
}
#endif /* (CHIP == INTEL) */
#if (CHIP == M68000)
/* Initialize the timer C in the MFP 68901: implement init_clock() here. */
#endif /* (CHIP == M68000) */

55
kernel/const.h Executable file
View File

@@ -0,0 +1,55 @@
/* General constants used by the kernel. */
#include <ibm/interrupt.h> /* interrupt numbers and hardware vectors */
#include <ibm/ports.h> /* port addresses and magic numbers */
#include <ibm/bios.h> /* BIOS addresses, sizes and magic numbers */
#if (CHIP == INTEL)
/* To translate an address in kernel space to a physical address. This is
* the same as umap_local(proc_ptr, D, vir, sizeof(*vir)), but less costly.
*/
#define vir2phys(vir) (data_base + (vir_bytes) (vir))
/* Constants used in virtual_copy(). Values must be 0 and 1, respectively! */
#define _SRC_ 0
#define _DST_ 1
/* Translate a pointer to a field in a structure to a pointer to the structure
* itself. So it translates '&struct_ptr->field' back to 'struct_ptr'.
*/
#define structof(type, field, ptr) \
((type *) (((char *) (ptr)) - offsetof(type, field)))
/* How many bytes for the kernel stack. Space allocated in mpx.s. */
#define K_STACK_BYTES 1024
/* How many bytes for (port,value)-pairs vector to copy in. */
#define VDEVIO_BUF_SIZE 128
/* Program stack words and masks. */
#define INIT_PSW 0x0200 /* initial psw */
#define INIT_TASK_PSW 0x1200 /* initial psw for tasks (with IOPL 1) */
#define TRACEBIT 0x100 /* OR this with psw in proc[] for tracing */
#define SETPSW(rp, new) /* permits only certain bits to be set */ \
((rp)->p_reg.psw = (rp)->p_reg.psw & ~0xCD5 | (new) & 0xCD5)
#define IF_MASK 0x00000200
#define IOPL_MASK 0x003000
/* Disable/Enable hardware interrupts. */
#define lock() intr_disable()
#define unlock() intr_enable()
/* Sizes of memory tables. The boot monitor distinguishes three memory areas,
* namely low mem below 1M, 1M-16M, and mem after 16M. More chunks are needed
* for DOS MINIX.
*/
#define NR_MEMS 8 /* number of chunks of memory */
#endif /* (CHIP == INTEL) */
#if (CHIP == M68000)
/* M68000 specific constants go here. */
#endif /* (CHIP == M68000) */

86
kernel/dummy.c Normal file
View File

@@ -0,0 +1,86 @@
/* A dummy task. Used to safely remove old tasks, and get notices if they get
* called by accident (i.e., because of some bug...).
*
* Created:
* Jul 27, 2004 by Jorrit N. Herder
*/
#include "kernel.h"
#include "proc.h"
#include <minix/com.h>
/* Allocated space for the global variables. */
message m_in; /* the input message itself */
message m_out; /* the output message used for reply */
int who; /* caller's proc number */
int callnr; /* system call number */
/* Declare some local functions. */
FORWARD _PROTOTYPE(void get_work, (void) );
FORWARD _PROTOTYPE(void reply, (int whom, int result) );
/*===========================================================================*
* dummy_task *
*===========================================================================*/
PUBLIC void dummy_task()
{
/* This is the main routine of this service. In principle this should block
* forever on getting new work - the dummy task is not supposed to be called.
* If new work is received, somehow, diagnostics are printed.
*/
int result;
/* kprintf("DUMMY: do nothing kernel task started (proc. nr %d).\n",
proc_number(proc_ptr)); */
/* Main loop - get work and do it, forever. */
while (TRUE) {
/* Wait for incoming message, sets 'callnr' and 'who'. */
get_work();
/* There is work to do! (re)set some variables first. */
result = EINVAL; /* illegal send to dummy task */
/* Print diagnostics: this was not supposed to happen. */
kprintf("Dummy task: request received from %d.\n", who);
/* Finally send reply message, unless disabled. */
if (result != EDONTREPLY) {
reply(who, result);
}
}
}
/*===========================================================================*
* get_work *
*===========================================================================*/
PRIVATE void get_work()
{
int status = 0;
status = receive(ANY, &m_in); /* this blocks until message arrives */
if (OK != status)
kprintf("Dummy task failed to receive message: %d", status);
who = m_in.m_source; /* message arrived! set sender */
callnr = m_in.m_type; /* set function call number */
}
/*===========================================================================*
* reply *
*===========================================================================*/
PRIVATE void reply(who, result)
int who; /* destination */
int result; /* report result to replyee */
{
int send_status;
m_out.m_type = result; /* build reply message */
send_status = send(who, &m_out); /* send the message */
if (OK != send_status)
kprintf("Dummy task unable to send reply: %d", send_status);
}

88
kernel/exception.c Executable file
View File

@@ -0,0 +1,88 @@
/* This file contains a simple exception handler. Exceptions in user
* processes are converted to signals. Exceptions in the kernel, MM and
* FS cause a panic.
*
* Changes:
* Sep 28, 2004: skip_stop_sequence on exceptions in system processes
*/
#include "kernel.h"
#include <signal.h>
#include "proc.h"
/*==========================================================================*
* exception *
*==========================================================================*/
PUBLIC void exception(vec_nr)
unsigned vec_nr;
{
/* An exception or unexpected interrupt has occurred. */
struct ex_s {
char *msg;
int signum;
int minprocessor;
};
static struct ex_s ex_data[] = {
"Divide error", SIGFPE, 86,
"Debug exception", SIGTRAP, 86,
"Nonmaskable interrupt", SIGBUS, 86,
"Breakpoint", SIGEMT, 86,
"Overflow", SIGFPE, 86,
"Bounds check", SIGFPE, 186,
"Invalid opcode", SIGILL, 186,
"Coprocessor not available", SIGFPE, 186,
"Double fault", SIGBUS, 286,
"Copressor segment overrun", SIGSEGV, 286,
"Invalid TSS", SIGSEGV, 286,
"Segment not present", SIGSEGV, 286,
"Stack exception", SIGSEGV, 286, /* STACK_FAULT already used */
"General protection", SIGSEGV, 286,
"Page fault", SIGSEGV, 386, /* not close */
NIL_PTR, SIGILL, 0, /* probably software trap */
"Coprocessor error", SIGFPE, 386,
};
register struct ex_s *ep;
struct proc *saved_proc;
/* Save proc_ptr, because it may be changed by debug statements. */
saved_proc = proc_ptr;
ep = &ex_data[vec_nr];
if (vec_nr == 2) { /* spurious NMI on some machines */
kprintf("got spurious NMI\n",NO_ARG);
return;
}
if (k_reenter == 0 && isuserp(saved_proc)) {
unlock(); /* this is protected like sys_call() */
cause_sig(proc_number(saved_proc), ep->signum);
return;
}
/* Exception in system code. This is not supposed to happen. */
if (ep->msg == NIL_PTR || processor < ep->minprocessor)
kprintf("\nIntel-reserved exception %d\n", vec_nr);
else
kprintf("\n%s\n", karg(ep->msg));
kprintf("process number %d", proc_number(saved_proc));
kprintf("pc = %d:", (unsigned) saved_proc->p_reg.cs);
kprintf("%d\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 */
skip_stop_sequence = 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));
}
}

80
kernel/glo.h Executable file
View File

@@ -0,0 +1,80 @@
/* Global variables used in the kernel. This file contains the declarations;
* storage space for the variables is allocated in table.c, because EXTERN is
* defined as extern unless the _TABLE definition is seen.
*/
#ifdef _TABLE
#undef EXTERN
#define EXTERN
#endif
/* MINIX' shutdown sequence uses watchdog timers to stop system services. The
* flag shutting_down must be initialized to FALSE. We rely on the compiler's
* default initialization (0) of global variables here.
*/
EXTERN int skip_stop_sequence; /* set to TRUE in case of an exception() */
EXTERN int shutting_down; /* TRUE if the system is shutting down */
EXTERN struct proc *shutdown_process; /* process awaiting shutdown of */
EXTERN timer_t shutdown_timer; /* watchdog function called after timeout */
/* Kernel memory. */
EXTERN phys_bytes code_base; /* base of kernel code */
EXTERN phys_bytes data_base; /* base of kernel data */
EXTERN phys_bytes aout; /* address of a.out headers */
/* Low level notifications may be put on the 'held' queue to prevent races. */
EXTERN struct proc *held_head; /* head of queue of held-up interrupts */
EXTERN struct proc *held_tail; /* tail of queue of held-up interrupts */
EXTERN unsigned char k_reenter; /* kernel reentry count (entry count less 1)*/
/* Process table. Here to stop too many things having to include proc.h. */
EXTERN struct proc *proc_ptr; /* pointer to currently running process */
/* Memory sizes. */
EXTERN struct memory mem[NR_MEMS]; /* base and size of chunks of memory */
EXTERN phys_clicks tot_mem_size; /* total system memory size */
/* Miscellaneous. */
EXTERN unsigned lost_ticks; /* clock ticks counted outside the clock task */
#if (CHIP == INTEL)
/* Machine type. */
EXTERN int pc_at; /* PC-AT compatible hardware interface */
EXTERN int ps_mca; /* PS/2 with Micro Channel */
EXTERN unsigned int processor; /* 86, 186, 286, 386, ... */
#if _WORD_SIZE == 2
EXTERN int protected_mode; /* nonzero if running in Intel protected mode*/
#else
#define protected_mode 1 /* 386 mode implies protected mode */
#endif
/* Video card types. */
EXTERN int ega; /* nonzero if console is EGA */
EXTERN int vga; /* nonzero if console is VGA */
/* Interrupt related variables. */
EXTERN struct irqtab irqtab[NR_IRQ_VECTORS]; /* table with IRQ policies */
EXTERN irq_hook_t *irq_hooks[NR_IRQ_VECTORS]; /* list of IRQ handlers */
EXTERN int irq_actids[NR_IRQ_VECTORS]; /* IRQ ID bits active */
EXTERN int irq_use; /* bit map of all in-use irq's */
/* Miscellaneous. */
EXTERN struct kmessages kmess; /* diagnostic messages in kernel */
EXTERN reg_t mon_ss, mon_sp; /* monitor stack */
EXTERN int mon_return; /* true if return to the monitor possible */
EXTERN phys_bytes mon_params; /* boot parameter block passed in/out */
EXTERN size_t mon_parmsize; /* boot parameter block size */
/* Variables that are initialized elsewhere are just extern here. */
extern struct system_image image[]; /* system image processes (table.c) */
extern char *t_stack[]; /* stack space for kernel tasks (table.c) */
extern struct segdesc_s gdt[]; /* protected mode global descriptor (protect.c) */
EXTERN _PROTOTYPE( void (*level0_func), (void) );
#endif /* (CHIP == INTEL) */
#if (CHIP == M68000)
/* M68000 specific variables go here. */
#endif

163
kernel/i8259.c Executable file
View File

@@ -0,0 +1,163 @@
/* This file contains routines for initializing the 8259 interrupt controller:
* put_irq_handler: register an interrupt handler
* intr_handle: handle a hardware interrupt
* intr_init: initialize the interrupt controller(s)
*/
#include "kernel.h"
#define ICW1_AT 0x11 /* edge triggered, cascade, need ICW4 */
#define ICW1_PC 0x13 /* edge triggered, no cascade, need ICW4 */
#define ICW1_PS 0x19 /* level triggered, cascade, need ICW4 */
#define ICW4_AT 0x01 /* not SFNM, not buffered, normal EOI, 8086 */
#define ICW4_PC 0x09 /* not SFNM, buffered, normal EOI, 8086 */
#if _WORD_SIZE == 2
typedef _PROTOTYPE( void (*vecaddr_t), (void) );
FORWARD _PROTOTYPE( void set_vec, (int vec_nr, vecaddr_t addr) );
PRIVATE vecaddr_t int_vec[] = {
int00, int01, int02, int03, int04, int05, int06, int07,
};
PRIVATE vecaddr_t irq_vec[] = {
hwint00, hwint01, hwint02, hwint03, hwint04, hwint05, hwint06, hwint07,
hwint08, hwint09, hwint10, hwint11, hwint12, hwint13, hwint14, hwint15,
};
#else
#define set_vec(nr, addr) ((void)0)
#endif
/*==========================================================================*
* intr_init *
*==========================================================================*/
PUBLIC void intr_init(mine)
int mine;
{
/* 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.
*/
int i;
lock();
if (protected_mode) {
/* The AT and newer PS/2 have two interrupt controllers, one master,
* one slaved at IRQ 2. (We don't have to deal with the PC that
* has just one controller, because it must run in real mode.)
*/
outb(INT_CTL, ps_mca ? ICW1_PS : ICW1_AT);
outb(INT_CTLMASK, mine ? IRQ0_VECTOR : BIOS_IRQ0_VEC);
/* ICW2 for master */
outb(INT_CTLMASK, (1 << CASCADE_IRQ)); /* ICW3 tells slaves */
outb(INT_CTLMASK, ICW4_AT);
outb(INT_CTLMASK, ~(1 << CASCADE_IRQ)); /* IRQ 0-7 mask */
outb(INT2_CTL, ps_mca ? ICW1_PS : ICW1_AT);
outb(INT2_CTLMASK, mine ? IRQ8_VECTOR : BIOS_IRQ8_VEC);
/* ICW2 for slave */
outb(INT2_CTLMASK, CASCADE_IRQ); /* ICW3 is slave nr */
outb(INT2_CTLMASK, ICW4_AT);
outb(INT2_CTLMASK, ~0); /* IRQ 8-15 mask */
/* Copy the BIOS vectors from the BIOS to the Minix location, so we
* can still make BIOS calls without reprogramming the i8259s.
*/
#if IRQ0_VECTOR != BIOS_IRQ0_VEC
phys_copy(BIOS_VECTOR(0) * 4L, VECTOR(0) * 4L, 8 * 4L);
#endif
#if IRQ8_VECTOR != BIOS_IRQ8_VEC
phys_copy(BIOS_VECTOR(8) * 4L, VECTOR(8) * 4L, 8 * 4L);
#endif
} else {
/* Use the BIOS interrupt vectors in real mode. We only reprogram the
* exceptions here, the interrupt vectors are reprogrammed on demand.
* SYS_VECTOR is the Minix system call for message passing.
*/
for (i = 0; i < 8; i++) set_vec(i, int_vec[i]);
set_vec(SYS_VECTOR, s_call);
}
}
/*=========================================================================*
* put_irq_handler *
*=========================================================================*/
PUBLIC void put_irq_handler(hook, irq, handler)
irq_hook_t *hook;
int irq;
irq_handler_t handler;
{
/* Register an interrupt handler. */
int id;
irq_hook_t **line;
if ((unsigned) irq >= NR_IRQ_VECTORS)
panic("invalid call to put_irq_handler", irq);
line = &irq_hooks[irq];
id = 1;
while (*line != NULL) {
if (hook == *line) return; /* extra initialization */
line = &(*line)->next;
id <<= 1;
}
if (id == 0) panic("Too many handlers for irq", irq);
hook->next = NULL;
hook->handler = handler;
hook->irq = irq;
hook->id = id;
*line = hook;
irq_use |= 1 << irq;
}
/*==========================================================================*
* intr_handle *
*==========================================================================*/
PUBLIC void intr_handle(hook)
irq_hook_t *hook;
{
/* Call the interrupt handlers for an interrupt with the given hook list.
* The assembly part of the handler has already masked the IRQ, reenabled the
* controller(s) and enabled interrupts.
*/
/* Call list of handlers for an IRQ. */
while (hook != NULL) {
/* For each handler in the list, mark it active by setting its ID bit,
* call the function, and unmark it if the function returns true.
*/
irq_actids[hook->irq] |= hook->id;
if ((*hook->handler)(hook)) irq_actids[hook->irq] &= ~hook->id;
hook = hook->next;
}
/* The assembly code will now disable interrupts, unmask the IRQ if and only
* if all active ID bits are cleared, and restart a process.
*/
}
#if _WORD_SIZE == 2
/*===========================================================================*
* set_vec *
*===========================================================================*/
PRIVATE void set_vec(vec_nr, addr)
int vec_nr; /* which vector */
vecaddr_t addr; /* where to start */
{
/* Set up a real mode interrupt vector. */
u16_t vec[2];
/* Build the vector in the array 'vec'. */
vec[0] = (u16_t) addr;
vec[1] = (u16_t) physb_to_hclick(code_base);
/* Copy the vector into place. */
phys_copy(vir2phys(vec), vec_nr * 4L, 4L);
}
#endif /* _WORD_SIZE == 2 */

26
kernel/kernel.h Executable file
View File

@@ -0,0 +1,26 @@
/* This is the master header for the kernel. It includes some other files
* and defines the principal constants.
*/
#define _POSIX_SOURCE 1 /* tell headers to include POSIX stuff */
#define _MINIX 1 /* tell headers to include MINIX stuff */
#define _SYSTEM 1 /* tell headers that this is the kernel */
/* The following are so basic, all the *.c files get them automatically. */
#include <minix/config.h> /* global configuration, MUST be first */
#include <ansi.h> /* C style: ANSI or K&R, MUST be second */
#include <sys/types.h> /* general system types */
#include <minix/const.h> /* MINIX specific constants */
#include <minix/type.h> /* MINIX specific types, e.g. message */
#include <minix/ipc.h> /* MINIX run-time system */
#include <timers.h> /* watchdog timer management */
#include <errno.h> /* return codes and error numbers */
#if (CHIP == INTEL)
#include <ibm/portio.h> /* device I/O and toggle interrupts */
#endif
#include "const.h" /* kernel constants */
#include "type.h" /* kernel type definitions */
#include "proto.h" /* kernel function prototypes */
#include "glo.h" /* kernel global variables */

9
kernel/klib.s Executable file
View File

@@ -0,0 +1,9 @@
#
! Chooses between the 8086 and 386 versions of the low level kernel code.
#include <minix/config.h>
#if _WORD_SIZE == 2
#include "klib88.s"
#else
#include "klib386.s"
#endif

497
kernel/klib386.s Executable file
View File

@@ -0,0 +1,497 @@
#
! sections
.sect .text; .sect .rom; .sect .data; .sect .bss
#include <minix/config.h>
#include <minix/const.h>
#include "const.h"
#include "sconst.h"
#include "protect.h"
! This file contains a number of assembly code utility routines needed by the
! kernel. They are:
.define _monitor ! exit Minix and return to the monitor
.define _int86 ! let the monitor make an 8086 interrupt call
.define _cp_mess ! copies messages from source to destination
.define _exit ! dummy for library routines
.define __exit ! dummy for library routines
.define ___exit ! dummy for library routines
.define ___main ! dummy for GCC
.define _phys_insw ! transfer data from (disk controller) port to memory
.define _phys_insb ! likewise byte by byte
.define _phys_outsw ! transfer data from memory to (disk controller) port
.define _phys_outsb ! likewise byte by byte
.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 _mem_rdw ! copy one word from [segment:offset]
.define _reset ! reset the system
.define _idle_task ! task executed when there is no work
.define _level0 ! call a function at level 0
! The routines only guarantee to preserve the registers the C compiler
! expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and
! direction bit in the flags).
.sect .text
!*===========================================================================*
!* monitor *
!*===========================================================================*
! PUBLIC void monitor();
! Return to the monitor.
_monitor:
mov esp, (_mon_sp) ! restore monitor stack pointer
o16 mov dx, SS_SELECTOR ! monitor data segment
mov ds, dx
mov es, dx
mov fs, dx
mov gs, dx
mov ss, dx
pop edi
pop esi
pop ebp
o16 retf ! return to the monitor
!*===========================================================================*
!* int86 *
!*===========================================================================*
! PUBLIC void int86();
_int86:
cmpb (_mon_return), 0 ! is the monitor there?
jnz 0f
movb ah, 0x01 ! an int 13 error seems appropriate
movb (_reg86+ 0), ah ! reg86.w.f = 1 (set carry flag)
movb (_reg86+13), ah ! reg86.b.ah = 0x01 = "invalid command"
ret
0: push ebp ! save C registers
push esi
push edi
push ebx
pushf ! save flags
cli ! no interruptions
inb INT2_CTLMASK
movb ah, al
inb INT_CTLMASK
push eax ! save interrupt masks
mov eax, (_irq_use) ! map of in-use IRQ`s
and eax, ~[1<<CLOCK_IRQ] ! keep the clock ticking
outb INT_CTLMASK ! enable all unused IRQ`s and vv.
movb al, ah
outb INT2_CTLMASK
mov eax, SS_SELECTOR ! monitor data segment
mov ss, ax
xchg esp, (_mon_sp) ! switch stacks
push (_reg86+36) ! parameters used in INT call
push (_reg86+32)
push (_reg86+28)
push (_reg86+24)
push (_reg86+20)
push (_reg86+16)
push (_reg86+12)
push (_reg86+ 8)
push (_reg86+ 4)
push (_reg86+ 0)
mov ds, ax ! remaining data selectors
mov es, ax
mov fs, ax
mov gs, ax
push cs
push return ! kernel return address and selector
o16 jmpf 20+2*4+10*4+2*4(esp) ! make the call
return:
pop (_reg86+ 0)
pop (_reg86+ 4)
pop (_reg86+ 8)
pop (_reg86+12)
pop (_reg86+16)
pop (_reg86+20)
pop (_reg86+24)
pop (_reg86+28)
pop (_reg86+32)
pop (_reg86+36)
lgdt (_gdt+GDT_SELECTOR) ! reload global descriptor table
jmpf CS_SELECTOR:csinit ! restore everything
csinit: mov eax, DS_SELECTOR
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
xchg esp, (_mon_sp) ! unswitch stacks
lidt (_gdt+IDT_SELECTOR) ! reload interrupt descriptor table
andb (_gdt+TSS_SELECTOR+DESC_ACCESS), ~0x02 ! clear TSS busy bit
mov eax, TSS_SELECTOR
ltr ax ! set TSS register
pop eax
outb INT_CTLMASK ! restore interrupt masks
movb al, ah
outb INT2_CTLMASK
add (_lost_ticks), ecx ! record lost clock ticks
popf ! restore flags
pop ebx ! restore C registers
pop edi
pop esi
pop ebp
ret
!*===========================================================================*
!* cp_mess *
!*===========================================================================*
! PUBLIC void cp_mess(int src, phys_clicks src_clicks, vir_bytes src_offset,
! phys_clicks dst_clicks, vir_bytes dst_offset);
! This routine makes a fast copy of a message from anywhere in the address
! space to anywhere else. It also copies the source address provided as a
! parameter to the call into the first word of the destination message.
!
! Note that the message size, "Msize" is in DWORDS (not bytes) and must be set
! correctly. Changing the definition of message in the type file and not
! changing it here will lead to total disaster.
CM_ARGS = 4 + 4 + 4 + 4 + 4 ! 4 + 4 + 4 + 4 + 4
! es ds edi esi eip proc scl sof dcl dof
.align 16
_cp_mess:
cld
push esi
push edi
push ds
push es
mov eax, FLAT_DS_SELECTOR
mov ds, ax
mov es, ax
mov esi, CM_ARGS+4(esp) ! src clicks
shl esi, CLICK_SHIFT
add esi, CM_ARGS+4+4(esp) ! src offset
mov edi, CM_ARGS+4+4+4(esp) ! dst clicks
shl edi, CLICK_SHIFT
add edi, CM_ARGS+4+4+4+4(esp) ! dst offset
mov eax, CM_ARGS(esp) ! process number of sender
stos ! copy number of sender to dest message
add esi, 4 ! do not copy first word
mov ecx, Msize - 1 ! remember, first word does not count
rep
movs ! copy the message
pop es
pop ds
pop edi
pop esi
ret ! that is all folks!
!*===========================================================================*
!* exit *
!*===========================================================================*
! PUBLIC void exit();
! Some library routines use exit, so provide a dummy version.
! Actual calls to exit cannot occur in the kernel.
! GNU CC likes to call ___main from main() for nonobvious reasons.
_exit:
__exit:
___exit:
sti
jmp ___exit
___main:
ret
!*===========================================================================*
!* phys_insw *
!*===========================================================================*
! PUBLIC void phys_insw(Port_t port, phys_bytes buf, size_t count);
! Input an array from an I/O port. Absolute address version of insw().
_phys_insw:
push ebp
mov ebp, esp
cld
push edi
push es
mov ecx, FLAT_DS_SELECTOR
mov es, cx
mov edx, 8(ebp) ! port to read from
mov edi, 12(ebp) ! destination addr
mov ecx, 16(ebp) ! byte count
shr ecx, 1 ! word count
rep o16 ins ! input many words
pop es
pop edi
pop ebp
ret
!*===========================================================================*
!* phys_insb *
!*===========================================================================*
! PUBLIC void phys_insb(Port_t port, phys_bytes buf, size_t count);
! Input an array from an I/O port. Absolute address version of insb().
_phys_insb:
push ebp
mov ebp, esp
cld
push edi
push es
mov ecx, FLAT_DS_SELECTOR
mov es, cx
mov edx, 8(ebp) ! port to read from
mov edi, 12(ebp) ! destination addr
mov ecx, 16(ebp) ! byte count
shr ecx, 1 ! word count
rep insb ! input many bytes
pop es
pop edi
pop ebp
ret
!*===========================================================================*
!* phys_outsw *
!*===========================================================================*
! PUBLIC void phys_outsw(Port_t port, phys_bytes buf, size_t count);
! Output an array to an I/O port. Absolute address version of outsw().
.align 16
_phys_outsw:
push ebp
mov ebp, esp
cld
push esi
push ds
mov ecx, FLAT_DS_SELECTOR
mov ds, cx
mov edx, 8(ebp) ! port to write to
mov esi, 12(ebp) ! source addr
mov ecx, 16(ebp) ! byte count
shr ecx, 1 ! word count
rep o16 outs ! output many words
pop ds
pop esi
pop ebp
ret
!*===========================================================================*
!* phys_outsb *
!*===========================================================================*
! PUBLIC void phys_outsb(Port_t port, phys_bytes buf, size_t count);
! Output an array to an I/O port. Absolute address version of outsb().
.align 16
_phys_outsb:
push ebp
mov ebp, esp
cld
push esi
push ds
mov ecx, FLAT_DS_SELECTOR
mov ds, cx
mov edx, 8(ebp) ! port to write to
mov esi, 12(ebp) ! source addr
mov ecx, 16(ebp) ! byte count
rep outsb ! output many bytes
pop ds
pop esi
pop ebp
ret
!*==========================================================================*
!* enable_irq *
!*==========================================================================*/
! PUBLIC void enable_irq(irq_hook_t *hook)
! Enable an interrupt request line by clearing an 8259 bit.
! Equivalent C code for hook->irq < 8:
! if ((irq_actids[hook->irq] &= ~hook->id) == 0)
! outb(INT_CTLMASK, inb(INT_CTLMASK) & ~(1 << irq));
.align 16
_enable_irq:
push ebp
mov ebp, esp
pushf
cli
mov eax, 8(ebp) ! hook
mov ecx, 8(eax) ! irq
mov eax, 12(eax) ! id bit
not eax
and _irq_actids(ecx*4), eax ! clear this id bit
jnz en_done ! still masked by other handlers?
movb ah, ~1
rolb ah, cl ! ah = ~(1 << (irq % 8))
mov edx, INT_CTLMASK ! enable irq < 8 at the master 8259
cmpb cl, 8
jb 0f
mov edx, INT2_CTLMASK ! enable irq >= 8 at the slave 8259
0: inb dx
andb al, ah
outb dx ! clear bit at the 8259
en_done:popf
leave
ret
!*==========================================================================*
!* disable_irq *
!*==========================================================================*/
! PUBLIC int disable_irq(irq_hook_t *hook)
! Disable an interrupt request line by setting an 8259 bit.
! Equivalent C code for irq < 8:
! irq_actids[hook->irq] |= hook->id;
! outb(INT_CTLMASK, inb(INT_CTLMASK) | (1 << irq));
! Returns true iff the interrupt was not already disabled.
.align 16
_disable_irq:
push ebp
mov ebp, esp
pushf
cli
mov eax, 8(ebp) ! hook
mov ecx, 8(eax) ! irq
mov eax, 12(eax) ! id bit
or _irq_actids(ecx*4), eax ! set this id bit
movb ah, 1
rolb ah, cl ! ah = (1 << (irq % 8))
mov edx, INT_CTLMASK ! disable irq < 8 at the master 8259
cmpb cl, 8
jb 0f
mov edx, INT2_CTLMASK ! disable irq >= 8 at the slave 8259
0: inb dx
testb al, ah
jnz dis_already ! already disabled?
orb al, ah
outb dx ! set bit at the 8259
mov eax, 1 ! disabled by this function
popf
leave
ret
dis_already:
xor eax, eax ! already disabled
popf
leave
ret
!*===========================================================================*
!* phys_copy *
!*===========================================================================*
! PUBLIC void phys_copy(phys_bytes source, phys_bytes destination,
! phys_bytes bytecount);
! Copy a block of physical memory.
PC_ARGS = 4 + 4 + 4 + 4 ! 4 + 4 + 4
! es edi esi eip src dst len
.align 16
_phys_copy:
cld
push esi
push edi
push es
mov eax, FLAT_DS_SELECTOR
mov es, ax
mov esi, PC_ARGS(esp)
mov edi, PC_ARGS+4(esp)
mov eax, PC_ARGS+4+4(esp)
cmp eax, 10 ! avoid align overhead for small counts
jb pc_small
mov ecx, esi ! align source, hope target is too
neg ecx
and ecx, 3 ! count for alignment
sub eax, ecx
rep
eseg movsb
mov ecx, eax
shr ecx, 2 ! count of dwords
rep
eseg movs
and eax, 3
pc_small:
xchg ecx, eax ! remainder
rep
eseg movsb
pop es
pop edi
pop esi
ret
!*===========================================================================*
!* mem_rdw *
!*===========================================================================*
! PUBLIC u16_t mem_rdw(U16_t segment, u16_t *offset);
! Load and return word at far pointer segment:offset.
.align 16
_mem_rdw:
mov cx, ds
mov ds, 4(esp) ! segment
mov eax, 4+4(esp) ! offset
movzx eax, (eax) ! word to return
mov ds, cx
ret
!*===========================================================================*
!* reset *
!*===========================================================================*
! PUBLIC void reset();
! Reset the system by loading IDT with offset 0 and interrupting.
_reset:
lidt (idt_zero)
int 3 ! anything goes, the 386 will not like it
.sect .data
idt_zero: .data4 0, 0
.sect .text
!*===========================================================================*
!* idle_task *
!*===========================================================================*
_idle_task:
! This task is called when the system has nothing else to do. The HLT
! instruction puts the processor in a state where it draws minimum power.
push halt
call _level0 ! level0(halt)
pop eax
jmp _idle_task
halt:
sti
hlt
cli
ret
!*===========================================================================*
!* level0 *
!*===========================================================================*
! PUBLIC void level0(void (*func)(void))
! Call a function at permission level 0. This allows kernel tasks to do
! things that are only possible at the most privileged CPU level.
!
_level0:
mov eax, 4(esp)
mov (_level0_func), eax
int LEVEL0_VECTOR
ret

1057
kernel/klib88.s Executable file

File diff suppressed because it is too large Load Diff

267
kernel/klibc.c Normal file
View File

@@ -0,0 +1,267 @@
/* 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:
* katoi: convert string to integer
* 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
* 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
* displayed on the console, because this must be done by the TTY driver.
* Instead, the kernel accumulates characters in a buffer and notifies the
* TTY driver when a new message is ready.
*/
#include "kernel.h"
#include <minix/com.h> /* need TTY process number */
#define isdigit(c) ((unsigned) ((c) - '0') < (unsigned) 10)
#define END_OF_KMESS -1
FORWARD _PROTOTYPE(void kputc, (int c));
/*=========================================================================*
* katoi *
*=========================================================================*/
PUBLIC int katoi(register const char *s)
{
int value = 0; /* default value */
int sign = 1; /* assume positive */
while(*s == ' ') s++; /* skip spaces */
if (*s == '-') { sign = -1; s++; } /* detect sign */
while(isdigit(*s)) /* get integer */
value = value*10 + (*s++) -'0';
return(sign * value); /* return result */
}
/*=========================================================================*
* 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 TTY driver if the buffer if a 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 {
notify(TTY, NEW_KMESS); /* let TTY display the message */
}
}
/*=========================================================================*
* kstrlen *
*=========================================================================*/
PUBLIC size_t kstrlen(const char *org)
{
register const char *s = org;
while (*s++)
/* EMPTY */ ;
return --s - org;
}
/*=========================================================================*
* 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;
}
/*=========================================================================*
* kstrncmp *
*=========================================================================*/
PUBLIC int kstrncmp(register const char *s1, register const char *s2, register size_t n)
{
while (n > 0 && *s1 == *s2++) {
if (*s1++ == '\0') return 0;
n--;
}
if (n > 0) {
if (*s1 == '\0') return -1;
if (*--s2 == '\0') return 1;
return (unsigned char) *s1 - (unsigned char) *s2;
}
return 0;
}
/*=========================================================================*
* kstrncpy *
*=========================================================================*/
PUBLIC char *kstrncpy(char *ret, register const char *s2, register size_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;
}
/*=========================================================================*
* 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;
}

354
kernel/main.c Executable file
View File

@@ -0,0 +1,354 @@
/* This file contains the main program of MINIX as well as its shutdown code.
* The routine main() initializes the system and starts the ball rolling by
* setting up the process table, interrupt vectors, and scheduling each task
* to run to initialize itself.
* The routine prepare_shutdown() tries to cleanly shuts down MINIX by running
* the stop_sequence() to notify all system services and allowing them some
* time to finalize. In case of an exception(), the stop sequence is skipped.
*
* The entries into this file are:
* main: MINIX main program
* prepare_shutdown: prepare to take MINIX down
* stop_sequence: take down all system services
*
* Changes:
* Nov 24, 2004 simplified main() with system image (Jorrit N. Herder)
* Oct 21, 2004 moved copyright to announce() (Jorrit N. Herder)
* Sep 30, 2004 moved mem_init() to this file (Jorrit N. Herder)
* Sep 04, 2004 created stop_sequence() to cleanup (Jorrit N. Herder)
* Aug 20, 2004 split wreboot() and shutdown() (Jorrit N. Herder)
* Jun 15, 2004 moved wreboot() to this file (Jorrit N. Herder)
*/
#include "kernel.h"
#include <signal.h>
#include <unistd.h>
#include <a.out.h>
#include <minix/callnr.h>
#include <minix/com.h>
#include "proc.h"
#include "sendmask.h"
/* Prototype declarations for PRIVATE function. */
FORWARD _PROTOTYPE( void announce, (void)); /* display user message */
#define STOP_TICKS (5*HZ) /* time allowed to stop */
/*===========================================================================*
* main *
*===========================================================================*/
PUBLIC void main()
{
/* Start the ball rolling. */
register struct proc *rp;
register int i;
int hdrindex; /* index to array of a.out headers */
phys_clicks text_base;
vir_clicks text_clicks;
vir_clicks data_clicks;
reg_t ktsb; /* kernel task stack base */
struct memory *memp;
struct system_image *ttp;
struct exec e_hdr; /* for a copy of an a.out header */
/* Initialize the interrupt controller. */
intr_init(1);
/* Make free memory list from memory sizes passed by boot monitor. */
mem_init();
/* Clear the process table. Anounce each slot as empty and
* set up mappings for proc_addr() and proc_number() macros.
*/
for (rp = BEG_PROC_ADDR, i = -NR_TASKS; rp < END_PROC_ADDR; ++rp, ++i) {
rp->p_type = P_NONE; /* isemptyp() tests on this */
rp->p_nr = i; /* proc number from ptr */
(pproc_addr + NR_TASKS)[i] = rp; /* proc ptr from number */
}
/* Set up proc table entries for tasks and servers. The stacks of the
* kernel tasks are initialized to an array in data space. The stacks
* of the servers have been added to the data segment by the monitor, so
* the stack pointer is set to the end of the data segment. All the
* processes are in low memory on the 8086. On the 386 only the kernel
* is in low memory, the rest is loaded in extended memory.
*/
/* Task stacks. */
ktsb = (reg_t) t_stack;
for (i=0; i < IMAGE_SIZE; ++i) {
ttp = &image[i]; /* t's task attributes */
rp = proc_addr(ttp->proc_nr); /* t's process slot */
kstrncpy(rp->p_name, ttp->name, PROC_NAME_LEN); /* set name */
rp->p_type = ttp->type; /* type of process */
rp->p_priority = ttp->priority; /* scheduling priority */
rp->p_sendmask = ttp->sendmask; /* sendmask protection */
if (i-NR_TASKS < 0) { /* part of the kernel? */
if (ttp->stksize > 0) { /* HARDWARE stack size is 0 */
rp->p_stguard = (reg_t *) ktsb;
*rp->p_stguard = STACK_GUARD;
}
ktsb += ttp->stksize; /* point to high end of stack */
rp->p_reg.sp = ktsb; /* this task's initial stack ptr */
text_base = code_base >> CLICK_SHIFT;
/* processes that are in the kernel */
hdrindex = 0; /* all use the first a.out header */
} else {
hdrindex = 1 + i-NR_TASKS; /* drivers, servers, INIT follow */
}
/* The bootstrap loader created an array of the a.out headers at
* absolute address 'aout'. Get one element to e_hdr.
*/
phys_copy(aout + hdrindex * A_MINHDR, vir2phys(&e_hdr),
(phys_bytes) A_MINHDR);
/* 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 */
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;
rp->p_memmap[D].mem_phys = text_base + text_clicks;
rp->p_memmap[D].mem_len = data_clicks;
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
*/
rp->p_reg.pc = (reg_t) ttp->initial_pc;
rp->p_reg.psw = (isidlep(rp)||istaskp(rp)) ? INIT_TASK_PSW : INIT_PSW;
/* Initialize the server stack pointer. Take it down one word
* to give crtso.s something to use as "argc".
*/
if (i-NR_TASKS >= 0) {
rp->p_reg.sp = (rp->p_memmap[S].mem_vir +
rp->p_memmap[S].mem_len) << CLICK_SHIFT;
rp->p_reg.sp -= sizeof(reg_t);
}
/* Set ready. The HARDWARE task is never ready. */
if (rp->p_nr != HARDWARE) lock_ready(rp);
rp->p_flags = 0;
/* Code and data segments must be allocated in protected mode. */
alloc_segments(rp);
}
bill_ptr = proc_addr(IDLE); /* it has to point somewhere */
/* This actually is not needed, because ready() already set 'proc_ptr' to
* first task that was announced ready.
*/
lock_pick_proc();
/* Expect an image of the root FS to be loaded into memory as well. The
* root FS image is located directly after the programs.
*/
hdrindex ++;
phys_copy(aout+hdrindex * A_MINHDR, vir2phys(&e_hdr), (phys_bytes) A_MINHDR);
kprintf("Root FS image found: %s\n", (e_hdr.a_flags&A_IMG)? "yes" : "no");
if (e_hdr.a_flags & A_IMG) {
kprintf("Size of root FS: %u, ", e_hdr.a_data);
kprintf("base : %u, ", e_hdr.a_syms);
kprintf("header size : %u, ", e_hdr.a_hdrlen);
rp = proc_addr(MEMORY);
rp->p_farmem[0].mem_phys = e_hdr.a_syms;
rp->p_farmem[0].mem_len = e_hdr.a_data;
/* Remove from free list, to prevent being overwritten. */
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 */
data_clicks = (e_hdr.a_total + CLICK_SIZE-1) >> CLICK_SHIFT;
for (memp = mem; memp < &mem[NR_MEMS]; memp++) {
if (memp->base == text_base) {
kprintf("Memory removed from free list.\n", NO_ARG);
memp->base += text_clicks + data_clicks;
memp->size -= text_clicks + data_clicks;
}
}
}
/* MINIX and all system services have been loaded. Announce to the user.
* Then go to the assembly code to start running the current process.
*/
announce();
restart();
}
/*==========================================================================*
* announce *
*==========================================================================*/
PRIVATE void announce(void)
{
/* Display the MINIX startup banner. */
kprintf("MINIX %s Copyright 2001 Prentice-Hall, Inc.\n",
karg(OS_RELEASE "." OS_VERSION));
#if (CHIP == INTEL)
/* Real mode, or 16/32-bit protected mode? */
kprintf("Executing in %s mode\n\n",
protected_mode ? karg("32-bit protected") : karg("real"));
#endif
}
/*==========================================================================*
* prepare_shutdown *
*==========================================================================*/
PUBLIC void prepare_shutdown(how)
int how; /* 0 = halt, 1 = reboot, 2 = panic!, ... */
{
/* This function prepares to shutdown MINIX. It uses a global flag to make
* sure it is only executed once. Unless a CPU exception occurred, the
* stop_sequence() is started.
*/
if (shutting_down)
return;
/* Show debugging dumps on panics. Make sure that the TTY task is still
* available to handle them. This is done with help of a non-blocking send.
* We rely on TTY to call sys_abort() when it is done with the dumps.
*/
if (how == RBT_PANIC) {
message m;
m.m_type = PANIC_DUMPS;
if (nb_send(TTY, &m) == OK) /* don't block if TTY isn't ready */
return; /* await sys_abort() from TTY */
}
/* The TTY expects two HARD_STOP notifications. One to switch to the
* primary console for stop sequence output, and one to actually exit.
*/
notify(TTY, HARD_STOP); /* let TTY switch to console 0 */
/* Run the stop sequence. The timer argument passes the shutdown status.
* The stop sequence is skipped for fatal CPU exceptions.
*/
shutting_down = TRUE; /* flag for sys_exit() */
tmr_arg(&shutdown_timer)->ta_int = how; /* pass how in timer */
if (skip_stop_sequence) { /* set in exception() */
kprintf("\nAn exception occured; skipping stop sequence.\n", NO_ARG);
shutdown(&shutdown_timer); /* TTY isn't scheduled */
} else {
kprintf("\nNotifying system services about MINIX shutdown.\n", NO_ARG);
stop_sequence(&shutdown_timer);
}
}
/*==========================================================================*
* stop_sequence *
*==========================================================================*/
PUBLIC void stop_sequence(tp)
timer_t *tp;
{
/* Try to cleanly stop all system services before shutting down. For each
* process type, all processes are notified and given STOP_TICKS to cleanly
* shutdown. The notification order is servers, drivers, tasks. The variable
* 'shutdown_process' is set globally to indicate the process next to stop
* so that the stop sequence can directly continue if it has exited. Only if
* stop sequence has finished, MINIX is brought down.
*/
static int level = P_SERVER; /* start at the highest level */
static struct proc *p = NIL_PROC; /* next process to stop */
static char *types[] = {"task","system","driver","server","user"};
/* See if the last process' shutdown was successfull. Else, force exit. */
if (p != NIL_PROC) {
kprintf("[%s]\n", isalivep(p) ? "FAILED" : "OK");
if (isalivep(p))
clear_proc(p->p_nr); /* now force process to exit */
}
/* Find the next process that must be stopped. Continue where last search
* ended or start at begin. Possibly go to next level while searching. If
* the last level is completely searched, shutdown MINIX. Processes are
* stopped in the order of dependencies, that is, from the highest level to
* the lowest level so that, for example, the file system can still rely on
* device drivers to cleanly shutdown.
*/
if (p == NIL_PROC) p = BEG_PROC_ADDR;
while (TRUE) {
if (isalivep(p) && p->p_type == level) { /* found a process */
kprintf("- Stopping %s ", p->p_name);
kprintf("%s ... ", types[p->p_type]);
shutdown_process = p; /* directly continue if exited */
notify(proc_number(p), HARD_STOP);
set_timer(tp, get_uptime()+STOP_TICKS, stop_sequence);
return; /* allow the process to shut down */
}
p++; /* proceed to next process */
if (p >= END_PROC_ADDR) { /* proceed to next level */
p = BEG_PROC_ADDR;
level = level - 1;
if (level == P_TASK) { /* done; tasks must remain alive */
set_timer(tp, get_uptime()+HZ, shutdown); /* shutdown MINIX */
return; /* user can inspect output */
}
}
}
}
/*==========================================================================*
* shutdown *
*==========================================================================*/
PUBLIC void shutdown(tp)
timer_t *tp;
{
/* This function is called from prepare_shutdown or stop_sequence to bring
* down MINIX. How to shutdown is in the argument: RBT_REBOOT, RBT_HALT,
* RBT_RESET.
*/
int quiet, code;
static u16_t magic = STOP_MEM_CHECK;
int how = tmr_arg(tp)->ta_int;
/* Now mask all interrupts, including the clock, and stop the clock. */
outb(INT_CTLMASK, ~0);
clock_stop();
if (mon_return && how != RBT_RESET) {
/* Reinitialize the interrupt controllers to the BIOS defaults. */
intr_init(0);
outb(INT_CTLMASK, 0);
outb(INT2_CTLMASK, 0);
/* Return to the boot monitor. Set the program for the boot monitor.
* For RBT_MONITOR, the MM has provided the program.
*/
if (how == RBT_HALT) {
phys_copy(vir2phys(" "), mon_params, 2);
} else if (how == RBT_REBOOT) {
phys_copy(vir2phys("delay;boot"), mon_params, 11);
}
level0(monitor);
}
/* Stop BIOS memory test. */
phys_copy(vir2phys(&magic), (phys_bytes) ADR_MEM_CHECK, LEN_MEM_CHECK);
/* Reset the system by jumping to the reset address (real mode), or by
* forcing a processor shutdown (protected mode).
*/
level0(reset);
}

120
kernel/memory.c Executable file
View File

@@ -0,0 +1,120 @@
/* Entry points into this file:
* mem_init: create a list a free memory
* alloc_segments: allocate segments for 8088 or higher processor
*/
#include "kernel.h"
#include "protect.h"
#include "proc.h"
#if (CHIP == INTEL)
/* 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 *
*=========================================================================*/
PUBLIC void mem_init()
{
/* 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 = getkenv("memory"); /* get memory boot variable */
tot_mem_size = 0;
for (i = 0; i < NR_MEMS; i++) {
memp = &mem[i]; /* result is stored here */
base = size = 0;
if (*s != 0) { /* end of boot variable */
/* Expect base to be read (end != s) and ':' as next char. */
base = kstrtoul(s, &end, 0x10); /* get number */
if (end != s && *end == ':') s = ++end; /* skip ':' */
else *s=0; /* fake end for next; should not happen */
/* Expect size to be read and skip ',', unless at end. */
size = kstrtoul(s, &end, 0x10); /* get number */
if (end != s && *end == ',') s = ++end; /* skip ',' */
else if (end != s && *end == 0) s = end; /* end found */
else *s=0; /* fake end for next; should not happen */
}
limit = base + size;
#if _WORD_SIZE == 2
max_address = protected_mode ? 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;
tot_mem_size += memp->size;
}
}
/*==========================================================================*
* alloc_segments *
*==========================================================================*/
PUBLIC void alloc_segments(rp)
register struct proc *rp;
{
/* This is called at system initialization from main() and by do_newmap().
* The code has a separate function because of all hardware-dependencies.
* Note that IDLE is part of the kernel and gets TASK_PRIVILEGE here.
*/
phys_bytes code_bytes;
phys_bytes data_bytes;
int privilege;
if (protected_mode) {
data_bytes = (phys_bytes) (rp->p_memmap[S].mem_vir +
rp->p_memmap[S].mem_len) << CLICK_SHIFT;
if (rp->p_memmap[T].mem_len == 0)
code_bytes = data_bytes; /* common I&D, poor protect */
else
code_bytes = (phys_bytes) rp->p_memmap[T].mem_len << CLICK_SHIFT;
privilege = (isidlep(rp) || istaskp(rp)) ?
TASK_PRIVILEGE : USER_PRIVILEGE;
init_codeseg(&rp->p_ldt[CS_LDT_INDEX],
(phys_bytes) rp->p_memmap[T].mem_phys << CLICK_SHIFT,
code_bytes, privilege);
init_dataseg(&rp->p_ldt[DS_LDT_INDEX],
(phys_bytes) rp->p_memmap[D].mem_phys << CLICK_SHIFT,
data_bytes, privilege);
rp->p_reg.cs = (CS_LDT_INDEX * DESC_SIZE) | TI | privilege;
#if _WORD_SIZE == 4
rp->p_reg.gs =
rp->p_reg.fs =
#endif
rp->p_reg.ss =
rp->p_reg.es =
rp->p_reg.ds = (DS_LDT_INDEX*DESC_SIZE) | TI | privilege;
} else {
rp->p_reg.cs = click_to_hclick(rp->p_memmap[T].mem_phys);
rp->p_reg.ss =
rp->p_reg.es =
rp->p_reg.ds = click_to_hclick(rp->p_memmap[D].mem_phys);
}
}
#endif /* (CHIP == INTEL) */

74
kernel/misc.c Executable file
View File

@@ -0,0 +1,74 @@
/* This file contains a collection of miscellaneous procedures:
* panic abort MINIX due to a fatal error
* bad_assertion for debugging
* bad_compare for debugging
*
* Changes:
* Oct 04, 2004 moved panic() to this file (Jorrit N. Herder)
* Sep 30, 2004 removed mem_init(), env_parse to lib (Jorrit N. Herder)
*/
#include "kernel.h"
#include "assert.h"
#include <unistd.h>
#include <minix/com.h>
/*===========================================================================*
* panic *
*===========================================================================*/
PUBLIC void panic(s,n)
_CONST char *s;
int n;
{
/* The system has run aground of a fatal error. Terminate execution.
* If the panic originated in MM or FS, the string will be empty and the
* file system already syncked. If the panic originates in the kernel, we are
* kind of stuck.
*/
static int panicking = 0;
if (panicking ++) /* prevent recursive panics */
return;
if (s != NULL) {
kprintf("\nKernel panic: %s", karg(s));
if (n != NO_NUM) kprintf(" %d", n);
kprintf("\n",NO_ARG);
}
prepare_shutdown(RBT_PANIC);
}
#if !NDEBUG
/*=========================================================================*
* bad_assertion *
*=========================================================================*/
PUBLIC void bad_assertion(file, line, what)
char *file;
int line;
char *what;
{
kprintf("panic at %s", karg(file));
kprintf(" (line %d): ", line);
kprintf("assertion \"%s\" failed.\n", karg(what));
panic(NULL, NO_NUM);
}
/*=========================================================================*
* bad_compare *
*=========================================================================*/
PUBLIC void bad_compare(file, line, lhs, what, rhs)
char *file;
int line;
int lhs;
char *what;
int rhs;
{
kprintf("panic at %s", karg(file));
kprintf(" (line %d): ", line);
kprintf("compare (%d)", lhs);
kprintf(" %s ", karg(what));
kprintf("(%d) failed.\n", rhs);
panic(NULL, NO_NUM);
}
#endif /* !NDEBUG */

9
kernel/mpx.s Executable file
View File

@@ -0,0 +1,9 @@
#
! Chooses between the 8086 and 386 versions of the Minix startup code.
#include <minix/config.h>
#if _WORD_SIZE == 2
#include "mpx88.s"
#else
#include "mpx386.s"
#endif

553
kernel/mpx386.s Executable file
View File

@@ -0,0 +1,553 @@
#
! This file, mpx386.s, is included by mpx.s when Minix is compiled for
! 32-bit Intel CPUs. The alternative mpx88.s is compiled for 16-bit CPUs.
!
! This contains the assembler startup code for Minix and the 32-bit
! interrupt handlers. It cooperates with start.c to set up a good
! environment for main().
! This file is part of the lowest layer of the MINIX kernel. The other part
! is "proc.c". The lowest layer does process switching and message handling.
! Every transition to the kernel goes through this file. Transitions are
! caused by sending/receiving messages and by most interrupts. (RS232
! interrupts may be handled in the file "rs2.s" and then they rarely enter
! the kernel.)
! Transitions to the kernel may be nested. The initial entry may be with a
! system call, exception or hardware interrupt; reentries may only be made
! by hardware interrupts. The count of reentries is kept in "k_reenter".
! It is important for deciding whether to switch to the kernel stack and
! for protecting the message passing code in "proc.c".
! For the message passing trap, most of the machine state is saved in the
! proc table. (Some of the registers need not be saved.) Then the stack is
! switched to "k_stack", and interrupts are reenabled. Finally, the system
! call handler (in C) is called. When it returns, interrupts are disabled
! again and the code falls into the restart routine, to finish off held-up
! interrupts and run the process or task whose pointer is in "proc_ptr".
! Hardware interrupt handlers do the same, except (1) The entire state must
! be saved. (2) There are too many handlers to do this inline, so the save
! routine is called. A few cycles are saved by pushing the address of the
! appropiate restart routine for a return later. (3) A stack switch is
! avoided when the stack is already switched. (4) The (master) 8259 interrupt
! controller is reenabled centrally in save(). (5) Each interrupt handler
! masks its interrupt line using the 8259 before enabling (other unmasked)
! interrupts, and unmasks it after servicing the interrupt. This limits the
! nest level to the number of lines and protects the handler from itself.
! For communication with the boot monitor at startup time some constant
! data are compiled into the beginning of the text segment. This facilitates
! reading the data at the start of the boot process, since only the first
! sector of the file needs to be read.
! Some data storage is also allocated at the end of this file. This data
! will be at the start of the data segment of the kernel and will be read
! and modified by the boot monitor before the kernel starts.
! sections
.sect .text
begtext:
.sect .rom
begrom:
.sect .data
begdata:
.sect .bss
begbss:
#include <minix/config.h>
#include <minix/const.h>
#include <minix/com.h>
#include "const.h"
#include "protect.h"
#include "sconst.h"
/* Selected 386 tss offsets. */
#define TSS3_S_SP0 4
! Exported functions
! Note: in assembly language the .define statement applied to a function name
! is loosely equivalent to a prototype in C code -- it makes it possible to
! link to an entity declared in the assembly code but does not create
! the entity.
.define _restart
.define save
.define _divide_error
.define _single_step_exception
.define _nmi
.define _breakpoint_exception
.define _overflow
.define _bounds_check
.define _inval_opcode
.define _copr_not_available
.define _double_fault
.define _copr_seg_overrun
.define _inval_tss
.define _segment_not_present
.define _stack_exception
.define _general_protection
.define _page_fault
.define _copr_error
.define _hwint00 ! handlers for hardware interrupts
.define _hwint01
.define _hwint02
.define _hwint03
.define _hwint04
.define _hwint05
.define _hwint06
.define _hwint07
.define _hwint08
.define _hwint09
.define _hwint10
.define _hwint11
.define _hwint12
.define _hwint13
.define _hwint14
.define _hwint15
.define _s_call
.define _p_s_call
.define _level0_call
! Exported variables.
.define begbss
.define begdata
.sect .text
!*===========================================================================*
!* MINIX *
!*===========================================================================*
MINIX: ! this is the entry point for the MINIX kernel
jmp over_flags ! skip over the next few bytes
.data2 CLICK_SHIFT ! for the monitor: memory granularity
flags:
.data2 0x01FD ! boot monitor flags:
! call in 386 mode, make bss, make stack,
! load high, don`t patch, will return,
! uses generic INT, memory vector,
! new boot code return
nop ! extra byte to sync up disassembler
over_flags:
! Set up a C stack frame on the monitor stack. (The monitor sets cs and ds
! right. The ss descriptor still references the monitor data segment.)
movzx esp, sp ! monitor stack is a 16 bit stack
push ebp
mov ebp, esp
push esi
push edi
cmp 4(ebp), 0 ! monitor return vector is
jz noret ! nonzero if return possible
inc (_mon_return)
noret: mov (_mon_sp), esp ! save stack pointer for later return
! Copy the monitor global descriptor table to the address space of kernel and
! switch over to it. Prot_init() can then update it with immediate effect.
sgdt (_gdt+GDT_SELECTOR) ! get the monitor gdtr
mov esi, (_gdt+GDT_SELECTOR+2) ! absolute address of GDT
mov ebx, _gdt ! address of kernel GDT
mov ecx, 8*8 ! copying eight descriptors
copygdt:
eseg movb al, (esi)
movb (ebx), al
inc esi
inc ebx
loop copygdt
mov eax, (_gdt+DS_SELECTOR+2) ! base of kernel data
and eax, 0x00FFFFFF ! only 24 bits
add eax, _gdt ! eax = vir2phys(gdt)
mov (_gdt+GDT_SELECTOR+2), eax ! set base of GDT
lgdt (_gdt+GDT_SELECTOR) ! switch over to kernel GDT
! Locate boot parameters, set up kernel segment registers and stack.
mov ebx, 8(ebp) ! boot parameters offset
mov edx, 12(ebp) ! boot parameters length
mov eax, 16(ebp) ! address of a.out headers
mov (_aout), eax
mov ax, ds ! kernel data
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, k_stktop ! set sp to point to the top of kernel stack
! Call C startup code to set up a proper environment to run main().
push edx
push ebx
push SS_SELECTOR
push DS_SELECTOR
push CS_SELECTOR
call _cstart ! cstart(cs, ds, mds, parmoff, parmlen)
add esp, 5*4
! Reload gdtr, idtr and the segment registers to global descriptor table set
! up by prot_init().
lgdt (_gdt+GDT_SELECTOR)
lidt (_gdt+IDT_SELECTOR)
jmpf CS_SELECTOR:csinit
csinit:
o16 mov ax, DS_SELECTOR
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
o16 mov ax, TSS_SELECTOR ! no other TSS is used
ltr ax
push 0 ! set flags to known good state
popf ! esp, clear nested task and int enable
jmp _main ! main()
!*===========================================================================*
!* interrupt handlers *
!* interrupt handlers for 386 32-bit protected mode *
!*===========================================================================*
!*===========================================================================*
!* hwint00 - 07 *
!*===========================================================================*
! Note this is a macro, it just looks like a subroutine.
#define hwint_master(irq) \
call save /* save interrupted process state */;\
inb INT_CTLMASK ;\
orb al, [1<<irq] ;\
outb INT_CTLMASK /* disable the irq */;\
movb al, ENABLE ;\
outb INT_CTL /* reenable master 8259 */;\
push (_irq_hooks+4*irq) /* irq_hooks[irq] */;\
sti /* enable interrupts */;\
call _intr_handle /* intr_handle(irq_hooks[irq]) */;\
cli /* disable interrupts */;\
pop ecx ;\
cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\
jnz 0f ;\
inb INT_CTLMASK ;\
andb al, ~[1<<irq] ;\
outb INT_CTLMASK /* enable the irq */;\
0: ret /* restart (another) process */
! Each of these entry points is an expansion of the hwint_master macro
.align 16
_hwint00: ! Interrupt routine for irq 0 (the clock).
hwint_master(0)
.align 16
_hwint01: ! Interrupt routine for irq 1 (keyboard)
hwint_master(1)
.align 16
_hwint02: ! Interrupt routine for irq 2 (cascade!)
hwint_master(2)
.align 16
_hwint03: ! Interrupt routine for irq 3 (second serial)
hwint_master(3)
.align 16
_hwint04: ! Interrupt routine for irq 4 (first serial)
hwint_master(4)
.align 16
_hwint05: ! Interrupt routine for irq 5 (XT winchester)
hwint_master(5)
.align 16
_hwint06: ! Interrupt routine for irq 6 (floppy)
hwint_master(6)
.align 16
_hwint07: ! Interrupt routine for irq 7 (printer)
hwint_master(7)
!*===========================================================================*
!* hwint08 - 15 *
!*===========================================================================*
! Note this is a macro, it just looks like a subroutine.
#define hwint_slave(irq) \
call save /* save interrupted process state */;\
inb INT2_CTLMASK ;\
orb al, [1<<[irq-8]] ;\
outb INT2_CTLMASK /* disable the irq */;\
movb al, ENABLE ;\
outb INT_CTL /* reenable master 8259 */;\
push (_irq_hooks+4*irq) /* irq_hooks[irq] */;\
outb INT2_CTL /* reenable slave 8259 */;\
sti /* enable interrupts */;\
call _intr_handle /* intr_handle(irq_hooks[irq]) */;\
cli /* disable interrupts */;\
pop ecx ;\
cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\
jnz 0f ;\
inb INT2_CTLMASK ;\
andb al, ~[1<<[irq-8]] ;\
outb INT2_CTLMASK /* enable the irq */;\
0: ret /* restart (another) process */
! Each of these entry points is an expansion of the hwint_slave macro
.align 16
_hwint08: ! Interrupt routine for irq 8 (realtime clock)
hwint_slave(8)
.align 16
_hwint09: ! Interrupt routine for irq 9 (irq 2 redirected)
hwint_slave(9)
.align 16
_hwint10: ! Interrupt routine for irq 10
hwint_slave(10)
.align 16
_hwint11: ! Interrupt routine for irq 11
hwint_slave(11)
.align 16
_hwint12: ! Interrupt routine for irq 12
hwint_slave(12)
.align 16
_hwint13: ! Interrupt routine for irq 13 (FPU exception)
hwint_slave(13)
.align 16
_hwint14: ! Interrupt routine for irq 14 (AT winchester)
hwint_slave(14)
.align 16
_hwint15: ! Interrupt routine for irq 15
hwint_slave(15)
!*===========================================================================*
!* save *
!*===========================================================================*
! Save for protected mode.
! This is much simpler than for 8086 mode, because the stack already points
! into the process table, or has already been switched to the kernel stack.
.align 16
save:
cld ! set direction flag to a known value
pushad ! save "general" registers
o16 push ds ! save ds
o16 push es ! save es
o16 push fs ! save fs
o16 push gs ! save gs
mov dx, ss ! ss is kernel data segment
mov ds, dx ! load rest of kernel segments
mov es, dx ! kernel does not use fs, gs
mov eax, esp ! prepare to return
incb (_k_reenter) ! from -1 if not reentering
jnz set_restart1 ! stack is already kernel stack
mov esp, k_stktop
push _restart ! build return address for int handler
xor ebp, ebp ! for stacktrace
jmp RETADR-P_STACKBASE(eax)
.align 4
set_restart1:
push restart1
jmp RETADR-P_STACKBASE(eax)
!*===========================================================================*
!* _s_call *
!*===========================================================================*
.align 16
_s_call:
_p_s_call:
cld ! set direction flag to a known value
sub esp, 6*4 ! skip RETADR, eax, ecx, edx, ebx, est
push ebp ! stack already points into proc table
push esi
push edi
o16 push ds
o16 push es
o16 push fs
o16 push gs
mov dx, ss
mov ds, dx
mov es, dx
incb (_k_reenter)
mov esi, esp ! assumes P_STACKBASE == 0
mov esp, k_stktop
xor ebp, ebp ! for stacktrace
! end of inline save
sti ! allow SWITCHER to be interrupted
! now set up parameters for sys_call()
push ebx ! pointer to user message
push eax ! src/dest
push ecx ! SEND/RECEIVE/BOTH
call _sys_call ! sys_call(function, src_dest, m_ptr)
! caller is now explicitly in proc_ptr
mov AXREG(esi), eax ! sys_call MUST PRESERVE si
cli ! disable interrupts
! Fall into code to restart proc/task running.
!*===========================================================================*
!* restart *
!*===========================================================================*
_restart:
! Flush any held-up interrupts.
! This reenables interrupts, so the current interrupt handler may reenter.
! This does not matter, because the current handler is about to exit and no
! other handlers can reenter since flushing is only done when k_reenter == 0.
cmp (_held_head), 0 ! do fast test to usually avoid function call
jz over_call_unhold
call _unhold ! this is rare so overhead acceptable
over_call_unhold:
mov esp, (_proc_ptr) ! will assume P_STACKBASE == 0
lldt P_LDT_SEL(esp) ! enable segment descriptors for task
lea eax, P_STACKTOP(esp) ! arrange for next interrupt
mov (_tss+TSS3_S_SP0), eax ! to save state in process table
restart1:
decb (_k_reenter)
o16 pop gs
o16 pop fs
o16 pop es
o16 pop ds
popad
add esp, 4 ! skip return adr
iretd ! continue process
!*===========================================================================*
!* exception handlers *
!*===========================================================================*
_divide_error:
push DIVIDE_VECTOR
jmp exception
_single_step_exception:
push DEBUG_VECTOR
jmp exception
_nmi:
push NMI_VECTOR
jmp exception
_breakpoint_exception:
push BREAKPOINT_VECTOR
jmp exception
_overflow:
push OVERFLOW_VECTOR
jmp exception
_bounds_check:
push BOUNDS_VECTOR
jmp exception
_inval_opcode:
push INVAL_OP_VECTOR
jmp exception
_copr_not_available:
push COPROC_NOT_VECTOR
jmp exception
_double_fault:
push DOUBLE_FAULT_VECTOR
jmp errexception
_copr_seg_overrun:
push COPROC_SEG_VECTOR
jmp exception
_inval_tss:
push INVAL_TSS_VECTOR
jmp errexception
_segment_not_present:
push SEG_NOT_VECTOR
jmp errexception
_stack_exception:
push STACK_FAULT_VECTOR
jmp errexception
_general_protection:
push PROTECTION_VECTOR
jmp errexception
_page_fault:
push PAGE_FAULT_VECTOR
jmp errexception
_copr_error:
push COPROC_ERR_VECTOR
jmp exception
!*===========================================================================*
!* exception *
!*===========================================================================*
! This is called for all exceptions which do not push an error code.
.align 16
exception:
sseg mov (trap_errno), 0 ! clear trap_errno
sseg pop (ex_number)
jmp exception1
!*===========================================================================*
!* errexception *
!*===========================================================================*
! This is called for all exceptions which push an error code.
.align 16
errexception:
sseg pop (ex_number)
sseg pop (trap_errno)
exception1: ! Common for all exceptions.
push eax ! eax is scratch register
mov eax, 0+4(esp) ! old eip
sseg mov (old_eip), eax
movzx eax, 4+4(esp) ! old cs
sseg mov (old_cs), eax
mov eax, 8+4(esp) ! old eflags
sseg mov (old_eflags), eax
pop eax
call save
push (old_eflags)
push (old_cs)
push (old_eip)
push (trap_errno)
push (ex_number)
call _exception ! (ex_number, trap_errno, old_eip,
! old_cs, old_eflags)
add esp, 5*4
cli
ret
!*===========================================================================*
!* level0_call *
!*===========================================================================*
_level0_call:
call save
jmp (_level0_func)
!*===========================================================================*
!* data *
!*===========================================================================*
.sect .rom ! Before the string table please
.data2 0x526F ! this must be the first data entry (magic #)
.sect .bss
k_stack:
.space K_STACK_BYTES ! kernel stack
k_stktop: ! top of kernel stack
.comm ex_number, 4
.comm trap_errno, 4
.comm old_eip, 4
.comm old_cs, 4
.comm old_eflags, 4

762
kernel/mpx88.s Executable file
View File

@@ -0,0 +1,762 @@
#
! This file, mpx88.s, is included by mpx.s when Minix is compiled for
! 16-bit Intel CPUs. The alternative mpx386.s is compiled for 32-bit CPUs.
!
! This file contains the assembler startup code for Minix and the 16-bit
! interrupt handlers. It cooperates with cstart.c to set up a good
! environment for main().
! This file is part of the lowest layer of the MINIX kernel. The other part
! is "proc.c". The lowest layer does process switching and message handling.
! Every transition to the kernel goes through this file. Transitions are
! caused by sending/receiving messages and by most interrupts. (RS232
! interrupts may be handled in the file "rs2.s" and then they rarely enter
! the kernel.)
! Transitions to the kernel may be nested. The initial entry may be with a
! system call, exception or hardware interrupt; reentries may only be made
! by hardware interrupts. The count of reentries is kept in "k_reenter".
! It is important for deciding whether to switch to the kernel stack and
! for protecting the message passing code in "proc.c".
! For the message passing trap, most of the machine state is saved in the
! proc table. (Some of the registers need not be saved.) Then the stack is
! switched to "k_stack", and interrupts are reenabled. Finally, the system
! call handler (in C) is called. When it returns, interrupts are disabled
! again and the code falls into the restart routine, to finish off held-up
! interrupts and run the process or task whose pointer is in "proc_ptr".
! Hardware interrupt handlers do the same, except (1) The entire state must
! be saved. (2) There are too many handlers to do this inline, so the save
! routine is called. A few cycles are saved by pushing the address of the
! appropiate restart routine for a return later. (3) A stack switch is
! avoided when the stack is already switched. (4) The (master) 8259 interrupt
! controller is reenabled centrally in save(). (5) Each interrupt handler
! masks its interrupt line using the 8259 before enabling (other unmasked)
! interrupts, and unmasks it after servicing the interrupt. This limits the
! nest level to the number of lines and protects the handler from itself.
! For communication with the boot monitor at startup time some constant
! data are compiled into the beginning of the text segment. This facilitates
! reading the data at the start of the boot process, since only the first
! sector of the file needs to be read.
! Some data storage is also allocated at the end of this file. This data
! will be at the start of the data segment of the kernel and will be read
! and modified by the boot monitor before the kernel starts.
#include <minix/config.h>
#include <minix/const.h>
#include <minix/com.h>
#include "const.h"
#include "sconst.h"
#include "protect.h"
! The external entry points into this file are:
! Note: in assembly language the .define statement applied to a function name
! is loosely equivalent to a prototype in C code -- it makes it possible to
! link to an entity declared in the assembly code but does not create
! the entity.
.define _int00 ! handlers for traps and exceptions
.define _int01
.define _int02
.define _int03
.define _int04
.define _int05
.define _int06
.define _int07
.define _hwint00 ! handlers for hardware interrupts
.define _hwint01
.define _hwint02
.define _hwint03
.define _hwint04
.define _hwint05
.define _hwint06
.define _hwint07
.define _hwint08
.define _hwint09
.define _hwint10
.define _hwint11
.define _hwint12
.define _hwint13
.define _hwint14
.define _hwint15
.define _restart ! start running a task or process
.define save ! save the machine state in the proc table
.define _s_call ! process or task wants to send or receive a message
! Exported variables.
.define kernel_ds
.define begbss
.define begdata
.text
!*===========================================================================*
!* MINIX *
!*===========================================================================*
MINIX: ! this is the entry point for the MINIX kernel
jmp over_kernel_ds ! skip over the next few bytes
.data2 CLICK_SHIFT ! for the monitor: memory granularity
kernel_ds:
.data2 0x01B4 ! boot monitor flags: (later kernel DS)
! call in 8086 mode, make bss, make stack,
! load low, don`t patch, will return,
! (has own INT calls), memory vector,
! new boot code return
over_kernel_ds:
! Set up a C stack frame on the monitor stack. (The monitor sets cs and ds
! right. The ss register still references the monitor data segment.)
push bp
mov bp, sp
push si
push di
cmp 4(bp), #0 ! monitor code segment is
jz noret ! nonzero if return possible
inc _mon_return
noret: mov _mon_ss, ss ! save stack location for later return
mov _mon_sp, sp
! Locate boot parameters, set up kernel segment registers and stack.
mov bx, 6(bp) ! boot parameters offset
mov dx, 8(bp) ! boot parameters length
mov ax, 10(bp) ! address of a.out headers
mov _aout+0, ax
mov ax, 12(bp)
mov _aout+2, ax
mov ax, ds ! kernel data
mov es, ax
mov ss, ax
mov sp, #k_stktop ! set sp to point to the top of kernel stack
! Real mode needs to get kernel DS from the code segment. Protected mode
! needs CS in the jump back to real mode.
cseg mov kernel_cs, cs
cseg mov kernel_ds, ds
! Call C startup code to set up a proper environment to run main().
push dx
push bx
push _mon_ss
push ds
push cs
call _cstart ! cstart(cs, ds, mds, parmoff, parmlen)
add sp, #5*2
cmp _protected_mode, #0
jz nosw ! ok to switch to protected mode?
call klib_init_prot ! initialize klib functions for protected mode
call real2prot ! switch to protected mode
push #0 ! set flags to known good state
popf ! especially, clear nested task and int enable
nosw:
jmp _main ! main()
!*===========================================================================*
!* interrupt handlers *
!*===========================================================================*
!*===========================================================================*
!* hwint00 - 07 *
!*===========================================================================*
! Note that the first few lines are a macro
#define hwint_master(irq) \
call save /* save interrupted process state */;\
mov si, *[2*irq] /* load array index offset */;\
mov di, *[1<<irq] /* irq mask bit */;\
jmp hwint_master /* continue with common code */
hwint_master:
inb INT_CTLMASK
or ax, di ! al |= (1 << irq)
outb INT_CTLMASK ! disable the irq
movb al, *ENABLE
outb INT_CTL ! reenable master 8259
mov cx, _irq_hooks(si) ! irq_hooks[irq]
push cx
sti ! enable interrupts
call _intr_handle ! intr_handle(irq_hooks[irq])
cli ! disable interrupts
pop cx
cmp _irq_actids(si), *0 ! interrupt still active?
jnz 0f
inb INT_CTLMASK
not di
and ax, di ! al &= ~(1 << irq)
outb INT_CTLMASK ! enable the irq
0: ret ! restart (another) process
! Each of these entry points is an expansion of the hwint_master macro
_hwint00: ! Interrupt routine for irq 0 (the clock).
hwint_master(0)
_hwint01: ! Interrupt routine for irq 1 (keyboard)
hwint_master(1)
_hwint02: ! Interrupt routine for irq 2 (cascade!)
hwint_master(2)
_hwint03: ! Interrupt routine for irq 3 (second serial)
hwint_master(3)
_hwint04: ! Interrupt routine for irq 4 (first serial)
hwint_master(4)
_hwint05: ! Interrupt routine for irq 5 (XT winchester)
hwint_master(5)
_hwint06: ! Interrupt routine for irq 6 (floppy)
hwint_master(6)
_hwint07: ! Interrupt routine for irq 7 (printer)
hwint_master(7)
!*===========================================================================*
!* hwint08 - 15 *
!*===========================================================================*
! Note that the first few lines are a macro
#define hwint_slave(irq) \
call save /* save interrupted process state */;\
mov si, *[2*irq] /* load array index offset */;\
mov di, *[1<<[irq-8]] /* irq mask bit */;\
jmp hwint_slave /* continue with common code */
hwint_slave:
inb INT2_CTLMASK
or ax, di ! al |= (1 << (irq-8))
outb INT2_CTLMASK ! disable the irq
movb al, *ENABLE
outb INT_CTL ! reenable master 8259
mov cx, _irq_hooks(si) ! irq_hooks[irq]
outb INT2_CTL ! reenable slave 8259
push cx
sti ! enable interrupts
call _intr_handle ! intr_handle(irq_hooks[irq])
cli ! disable interrupts
pop cx
cmp _irq_actids(si), *0 ! interrupt still active?
jnz 0f
inb INT2_CTLMASK
not di
and ax, di ! al &= ~(1 << (irq-8))
outb INT2_CTLMASK ! enable the irq
0: ret ! restart (another) process
! Each of these entry points is an expansion of the hwint_slave macro
_hwint08: ! Interrupt routine for irq 8 (realtime clock)
hwint_slave(8)
_hwint09: ! Interrupt routine for irq 9 (irq 2 redirected)
hwint_slave(9)
_hwint10: ! Interrupt routine for irq 10
hwint_slave(10)
_hwint11: ! Interrupt routine for irq 11
hwint_slave(11)
_hwint12: ! Interrupt routine for irq 12
hwint_slave(12)
_hwint13: ! Interrupt routine for irq 13 (FPU exception)
hwint_slave(13)
_hwint14: ! Interrupt routine for irq 14 (AT winchester)
hwint_slave(14)
_hwint15: ! Interrupt routine for irq 15
hwint_slave(15)
!*===========================================================================*
!* save *
!*===========================================================================*
save: ! save the machine state in the proc table.
! In protected mode a jump to p_save is patched over the following
! code during initialization.
cld ! set direction flag to a known value
push ds
push si
cseg mov ds,kernel_ds
incb _k_reenter ! from -1 if not reentering
jnz push_current_stack ! stack is already kernel stack
mov si,_proc_ptr
mov AXREG(si),ax
mov BXREG(si),bx
mov CXREG(si),cx
mov DXREG(si),dx
pop SIREG(si)
mov DIREG(si),di
mov BPREG(si),bp
mov ESREG(si),es
pop DSREG(si)
pop bx ! return adr
pop PCREG(si)
pop CSREG(si)
pop PSWREG(si)
mov SPREG(si),sp
mov SSREG(si),ss
mov dx,ds
mov ss,dx
mov sp,#k_stktop
mov ax,#_restart ! build return address for interrupt handler
push ax
stack_switched:
mov es,dx
jmp (bx)
push_current_stack:
push es
push bp
push di
push dx
push cx
push bx
push ax
mov bp,sp
mov bx,18(bp) ! get the return adr; it becomes junk on stack
mov ax,#restart1
push ax
mov dx,ss
mov ds,dx
jmp stack_switched
!*===========================================================================*
!* s_call *
!*===========================================================================*
! This is real mode version. Alternate (_p_s_call) will be used in
! protected mode
_s_call: ! System calls are vectored here.
! Do save routine inline for speed,
! but do not save ax, bx, cx, dx,
! since C does not require preservation,
! and ax returns the result code anyway.
! Regs bp, si, di get saved by sys_call as
! well, but it is impractical not to preserve
! them here, in case context gets switched.
! Some special-case code in pick_proc()
! could avoid this.
cld ! set direction flag to a known value
push ds
push si
cseg mov ds,kernel_ds
incb _k_reenter
mov si,_proc_ptr
pop SIREG(si)
mov DIREG(si),di
mov BPREG(si),bp
mov ESREG(si),es
pop DSREG(si)
pop PCREG(si)
pop CSREG(si)
pop PSWREG(si)
mov SPREG(si),sp
mov SSREG(si),ss
mov dx,ds
mov es,dx
mov ss,dx ! interrupt handlers may not make system calls
mov sp,#k_stktop ! so stack is not already switched
! end of inline save
! now set up parameters for C routine sys_call
push bx ! pointer to user message
push ax ! src/dest
push cx ! SEND/RECEIVE/BOTH
sti ! allow SWITCHER to be interrupted
call _sys_call ! sys_call(function, src_dest, m_ptr)
! caller is now explicitly in proc_ptr
mov AXREG(si),ax ! sys_call MUST PRESERVE si
cli
! Fall into code to restart proc/task running.
!*===========================================================================*
!* restart *
!*===========================================================================*
_restart:
! Flush any held-up interrupts.
! This reenables interrupts, so the current interrupt handler may reenter.
! This does not matter, because the current handler is about to exit and no
! other handlers can reenter since flushing is only done when k_reenter == 0.
! In protected mode a jump to p_restart is patched over the following
! code during initialization.
cmp _held_head,#0 ! do fast test to usually avoid function call
jz over_call_unhold
call _unhold ! this is rare so overhead is acceptable
over_call_unhold:
mov si,_proc_ptr
decb _k_reenter
mov ax,AXREG(si) ! start restoring registers from proc table
! could make AXREG == 0 to use lodw here
mov bx,BXREG(si)
mov cx,CXREG(si)
mov dx,DXREG(si)
mov di,DIREG(si)
mov bp,BPREG(si)
mov es,ESREG(si)
mov ss,SSREG(si)
mov sp,SPREG(si)
push PSWREG(si) ! fake interrupt stack frame
push CSREG(si)
push PCREG(si)
! could put si:ds together to use
! lds si,SIREG(si)
push DSREG(si)
mov si,SIREG(si)
pop ds
iret
restart1:
decb _k_reenter
pop ax
pop bx
pop cx
pop dx
pop di
pop bp
pop es
pop si
pop ds
add sp,#2 ! skip return adr
iret
!*===========================================================================*
!* int00-07 *
!*===========================================================================*
! These are entry points for exceptions (processor generated interrupts,
! usually caused by error conditions such as an attempt to divide by zero)
_int00: ! interrupt through vector 0
push ax
movb al,#0
jmp exception
_int01: ! interrupt through vector 1, etc
push ax
movb al,#1
jmp exception
_int02:
push ax
movb al,#2
jmp exception
_int03:
push ax
movb al,#3
jmp exception
_int04:
push ax
movb al,#4
jmp exception
_int05:
push ax
movb al,#5
jmp exception
_int06:
push ax
movb al,#6
jmp exception
_int07:
push ax
movb al,#7
!jmp exception
exception:
cseg movb ex_number,al ! it is cumbersome to get this into dseg
pop ax
call save
cseg push ex_number ! high byte is constant 0
call _exception ! do whatever is necessary (sti only if safe)
add sp,#2
cli
ret
!*===========================================================================*
!* level0_call *
!*===========================================================================*
_level0_call:
call save
jmp @_level0_func
!*===========================================================================*
!* data *
!*===========================================================================*
! NB some variables are stored in code segment.
ex_number: ! exception number
.space 2
!*===========================================================================*
!* variants for 286 protected mode *
!*===========================================================================*
! Most routines are different in 286 protected mode.
! The only essential difference is that an interrupt in protected mode
! (usually) switches the stack, so there is less to do in software.
! These functions are reached along jumps patched in by klib_init_prot():
.define p_restart ! replaces _restart
.define p_save ! replaces save
! These exception and software-interrupt handlers are enabled by the new
! interrupt vector table set up in protect.c:
.define _divide_error ! _int00
.define _single_step_exception ! _int01
.define _nmi ! _int02
.define _breakpoint_exception ! _int03
.define _overflow ! _int04
.define _bounds_check ! _int05
.define _inval_opcode ! _int06
.define _copr_not_available ! _int07
.define _double_fault ! (286 trap)
.define _copr_seg_overrun ! (etc)
.define _inval_tss
.define _segment_not_present
.define _stack_exception
.define _general_protection
.define _p_s_call ! _s_call
.define _level0_call
! The hardware interrupt handlers need not be altered apart from putting
! them in the new table (save() handles the differences).
! Some of the intxx handlers (those for exceptions which do not push an
! error code) need not have been replaced, but the names here are better.
#include "protect.h"
/* Selected 286 tss offsets. */
#define TSS2_S_SP0 2
! imported variables
.extern _tss
.extern _level0_func
!*===========================================================================*
!* p_save *
!*===========================================================================*
! Save for 286 protected mode.
! This is much simpler than for 8086 mode, because the stack already points
! into process table, or has already been switched to the kernel stack.
p_save:
cld ! set direction flag to a known value
pusha ! save "general" registers
push ds ! save ds
push es ! save es
mov dx,ss ! ss is kernel data segment
mov ds,dx ! load rest of kernel segments
mov es,dx
mov bp,sp ! prepare to return
incb _k_reenter ! from -1 if not reentering
jnz set_p1_restart ! stack is already kernel stack
mov sp,#k_stktop
push #p_restart ! build return address for interrupt handler
jmp @RETADR-P_STACKBASE(bp)
set_p1_restart:
push #p1_restart
jmp @RETADR-P_STACKBASE(bp)
!*===========================================================================*
!* p_s_call *
!*===========================================================================*
_p_s_call:
cld ! set direction flag to a known value
sub sp,#6*2 ! skip RETADR, ax, cx, dx, bx, st
push bp ! stack already points into process table
push si
push di
push ds
push es
mov dx,ss
mov ds,dx
mov es,dx
incb _k_reenter
mov si,sp ! assumes P_STACKBASE == 0
mov sp,#k_stktop
! end of inline save
sti ! allow SWITCHER to be interrupted
! now set up parameters for C routine sys_call
push bx ! pointer to user message
push ax ! src/dest
push cx ! SEND/RECEIVE/BOTH
call _sys_call ! sys_call(function, src_dest, m_ptr)
! caller is now explicitly in proc_ptr
mov AXREG(si),ax ! sys_call MUST PRESERVE si
cli
! Fall into code to restart proc/task running.
p_restart:
! Flush any held-up interrupts.
! This reenables interrupts, so the current interrupt handler may reenter.
! This does not matter, because the current handler is about to exit and no
! other handlers can reenter since flushing is only done when k_reenter == 0.
cmp _held_head,#0 ! do fast test to usually avoid function call
jz p_over_call_unhold
call _unhold ! this is rare so overhead is acceptable
p_over_call_unhold:
mov si,_proc_ptr
lldt P_LDT_SEL(si) ! enable segment descriptors for task
lea ax,P_STACKTOP(si) ! arrange for next interrupt
mov _tss+TSS2_S_SP0,ax ! to save state in process table
mov sp,si ! assumes P_STACKBASE == 0
p1_restart:
decb _k_reenter
pop es
pop ds
popa
add sp,#2 ! skip return adr
iret ! continue process
!*===========================================================================*
!* exception handlers *
!*===========================================================================*
_divide_error:
push #DIVIDE_VECTOR
jmp p_exception
_single_step_exception:
push #DEBUG_VECTOR
jmp p_exception
_nmi:
push #NMI_VECTOR
jmp p_exception
_breakpoint_exception:
push #BREAKPOINT_VECTOR
jmp p_exception
_overflow:
push #OVERFLOW_VECTOR
jmp p_exception
_bounds_check:
push #BOUNDS_VECTOR
jmp p_exception
_inval_opcode:
push #INVAL_OP_VECTOR
jmp p_exception
_copr_not_available:
push #COPROC_NOT_VECTOR
jmp p_exception
_double_fault:
push #DOUBLE_FAULT_VECTOR
jmp errexception
_copr_seg_overrun:
push #COPROC_SEG_VECTOR
jmp p_exception
_inval_tss:
push #INVAL_TSS_VECTOR
jmp errexception
_segment_not_present:
push #SEG_NOT_VECTOR
jmp errexception
_stack_exception:
push #STACK_FAULT_VECTOR
jmp errexception
_general_protection:
push #PROTECTION_VECTOR
jmp errexception
!*===========================================================================*
!* p_exception *
!*===========================================================================*
! This is called for all exceptions which do not push an error code.
p_exception:
sseg pop ds_ex_number
call p_save
jmp p1_exception
!*===========================================================================*
!* errexception *
!*===========================================================================*
! This is called for all exceptions which push an error code.
errexception:
sseg pop ds_ex_number
sseg pop trap_errno
call p_save
p1_exception: ! Common for all exceptions.
push ds_ex_number
call _exception
add sp,#2
cli
ret
!*===========================================================================*
!* data *
!*===========================================================================*
.data
begdata:
.data2 0x526F ! this must be the first data entry (magic #)
.bss
begbss:
k_stack:
.space K_STACK_BYTES ! kernel stack
k_stktop: ! top of kernel stack
.comm ds_ex_number, 2
.comm trap_errno, 2

1224
kernel/pci.c Executable file

File diff suppressed because it is too large Load Diff

97
kernel/pci.h Executable file
View File

@@ -0,0 +1,97 @@
/*
pci.h
Created: Jan 2000 by Philip Homburg <philip@cs.vu.nl>
*/
#define PCI_VID 0x00 /* Vendor ID, 16-bit */
#define PCI_DID 0x02 /* Device ID, 16-bit */
#define PCI_CR 0x04 /* Command Register, 16-bit */
#define PCI_PCISTS 0x06 /* PCI status, 16-bit */
#define PSR_SSE 0x4000 /* Signaled System Error */
#define PSR_RMAS 0x2000 /* Received Master Abort Status */
#define PSR_RTAS 0x1000 /* Received Target Abort Status */
#define PCI_PIFR 0x09 /* Prog. Interface Register */
#define PCI_SCR 0x0A /* Sub-Class Register */
#define PCI_BCR 0x0B /* Base-Class Register */
#define PCI_HEADT 0x0E /* Header type, 8-bit */
#define PHT_MULTIFUNC 0x80 /* Multiple functions */
#define PCI_BAR 0x10 /* Base Address Register */
#define PCI_ILR 0x3C /* Interrupt Line Register */
#define PCI_IPR 0x3D /* Interrupt Pin Register */
/* PCI bridge devices (AGP) */
#define PPB_SBUSN 0x19 /* Secondary Bus Number */
/* Intel compatible PCI bridge devices (AGP) */
#define PPB_SSTS 0x1E /* Secondary PCI-to-PCI Status Register */
#define NO_VID 0xffff /* No PCI card present */
struct pci_vendor
{
u16_t vid;
char *name;
};
struct pci_device
{
u16_t vid;
u16_t did;
char *name;
};
struct pci_baseclass
{
u8_t baseclass;
char *name;
};
struct pci_subclass
{
u8_t baseclass;
u8_t subclass;
u16_t infclass;
char *name;
};
struct pci_intel_ctrl
{
u16_t vid;
u16_t did;
};
struct pci_isabridge
{
u16_t vid;
u16_t did;
int checkclass;
int type;
};
struct pci_pcibridge
{
u16_t vid;
u16_t did;
int type;
};
#define PCI_IB_PIIX 1 /* Intel PIIX compatible ISA bridge */
#define PCI_IB_VIA 2 /* VIA compatible ISA bridge */
#define PCI_IB_AMD 3 /* AMD compatible ISA bridge */
#define PCI_IB_SIS 4 /* SIS compatible ISA bridge */
#define PCI_AGPB_INTEL 1 /* Intel compatible AGP bridge */
#define PCI_AGPB_VIA 2 /* VIA compatible AGP bridge */
extern struct pci_vendor pci_vendor_table[];
extern struct pci_device pci_device_table[];
extern struct pci_baseclass pci_baseclass_table[];
extern struct pci_subclass pci_subclass_table[];
extern struct pci_intel_ctrl pci_intel_ctrl[];
extern struct pci_isabridge pci_isabridge[];
extern struct pci_pcibridge pci_pcibridge[];
/*
* $PchId: pci.h,v 1.4 2001/12/06 20:21:22 philip Exp $
*/

21
kernel/pci_amd.h Executable file
View File

@@ -0,0 +1,21 @@
/*
pci_amd.h
Created: Nov 2001 by Philip Homburg <philip@cs.vu.nl>
*/
#define AMD_ISABR_FUNC 3 /* Registers are in function 3 */
#define AMD_ISABR_PCIIRQ_LEV 0x54
#define AMD_PCILEV_INTA 0x1
#define AMD_PCILEV_INTB 0x2
#define AMD_PCILEV_INTC 4x2
#define AMD_PCILEV_INTD 4x8
#define AMD_ISABR_PCIIRQ_ROUTE 0x56
#define AMD_PCIIRQ_INTA_MASK 0x000F
#define AMD_PCIIRQ_INTB_MASK 0x00F0
#define AMD_PCIIRQ_INTC_MASK 0x0F00
#define AMD_PCIIRQ_INTD_MASK 0xF000
/*
* $PchId: pci_amd.h,v 1.1 2001/11/09 19:57:37 philip Exp $
*/

58
kernel/pci_intel.h Executable file
View File

@@ -0,0 +1,58 @@
/*
pci_intel.h
Created: Jan 2000 by Philip Homburg <philip@cs.vu.nl>
*/
#define PCII_CONFADD 0xCF8
#define PCIIC_CODE 0x80000000
#define PCIIC_BUSNUM_MASK 0xff0000
#define PCIIC_BUSNUM_SHIFT 16
#define PCIIC_DEVNUM_MASK 0xf800
#define PCIIC_DEVNUM_SHIFT 11
#define PCIIC_FUNCNUM_MASK 0x700
#define PCIIC_FUNCNUM_SHIFT 8
#define PCIIC_REGNUM_MASK 0xfc
#define PCIIC_REGNUM_SHIFT 2
#define PCII_CONFDATA 0xCFC
#define PCII_SELREG_(bus, dev, func, reg) \
(PCIIC_CODE | \
(((bus) << PCIIC_BUSNUM_SHIFT) & PCIIC_BUSNUM_MASK) | \
(((dev) << PCIIC_DEVNUM_SHIFT) & PCIIC_DEVNUM_MASK) | \
(((func) << PCIIC_FUNCNUM_SHIFT) & PCIIC_FUNCNUM_MASK) | \
((((reg)/4) << PCIIC_REGNUM_SHIFT) & PCIIC_REGNUM_MASK))
#define PCII_UNSEL (0)
#define PCII_RREG8_(bus, dev, func, reg) \
(outl(PCII_CONFADD, PCII_SELREG_(bus, dev, func, reg)), \
inb(PCII_CONFDATA+((reg)&3)))
#define PCII_RREG16_(bus, dev, func, reg) \
(PCII_RREG8_(bus, dev, func, reg) | \
(PCII_RREG8_(bus, dev, func, reg+1) << 8))
#define PCII_RREG32_(bus, dev, func, reg) \
(PCII_RREG16_(bus, dev, func, reg) | \
(PCII_RREG16_(bus, dev, func, reg+2) << 16))
#define PCII_WREG8_(bus, dev, func, reg, val) \
(outl(PCII_CONFADD, PCII_SELREG_(bus, dev, func, reg)), \
outb(PCII_CONFDATA+((reg)&3), (val)))
#define PCII_WREG16_(bus, dev, func, reg, val) \
(PCII_WREG8_(bus, dev, func, reg, (val)), \
(PCII_WREG8_(bus, dev, func, reg+1, (val) >> 8)))
#define PCII_WREG32_(bus, dev, func, reg, val) \
(PCII_WREG16_(bus, dev, func, reg, (val)), \
(PCII_WREG16_(bus, dev, func, reg+2, (val) >> 16)))
/* PIIX configuration registers */
#define PIIX_PIRQRCA 0x60
#define PIIX_IRQ_DI 0x80
#define PIIX_IRQ_MASK 0x0F
/* PIIX extensions to the PIC */
#define PIIX_ELCR1 0x4D0
#define PIIX_ELCR2 0x4D1
/*
* $PchId: pci_intel.h,v 1.1 2000/08/12 11:20:17 philip Exp $
*/

17
kernel/pci_sis.h Executable file
View File

@@ -0,0 +1,17 @@
/*
pci_sis.h
Created: Nov 2001 by Philip Homburg <philip@cs.vu.nl>
*/
/* Constants are taken from pci-irq.c in the Linux kernel source */
#define SIS_ISABR_IRQ_A 0x41 /* IRQA routing */
#define SIS_ISABR_IRQ_B 0x42 /* IRQB routing */
#define SIS_ISABR_IRQ_C 0x43 /* IRQC routing */
#define SIS_ISABR_IRQ_D 0x44 /* IRQD routing */
#define SIS_IRQ_DISABLED 0x80
#define SIS_IRQ_MASK 0x0F
/*
* $PchId: pci_sis.h,v 1.1 2001/12/06 20:22:52 philip Exp $
*/

251
kernel/pci_table.c Executable file
View File

@@ -0,0 +1,251 @@
/*
pci_table.c
Tables with PCI vendor and device identifiers
Created: Jan 2000 by Philip Homburg <philip@cs.vu.nl>
See the Linux PCI ID Repository <http://pciids.sourceforge.net/>.
*/
/* Changes from original Minix 2.0.4 version (2003-09-05):
* 2003-11-30 (kjb) Minix 2.0.4 FIX.TAZ add D-Link RTL8139 (0x1186, 0x1300)
* 2004-08-08 (asw) add Intel 82371AB (0x8086, 0x7100)
*/
#include "kernel.h"
#include "pci.h"
#if __minix_vmd
#include "config.h"
#endif
#if ENABLE_PCI
struct pci_vendor pci_vendor_table[]=
{
{ 0x1000, "NCR" },
{ 0x1002, "ATI Technologies" },
{ 0x100B, "National Semiconductor Corporation" },
{ 0x1013, "Cirrus Logic" },
{ 0x1022, "Advanced Micro Devices" },
{ 0x102B, "Matrox Graphics, Inc." },
{ 0x1039, "Silicon Integrated Systems (SiS)" },
{ 0x104C, "Texas Instruments" },
{ 0x105A, "Promise Technology" },
{ 0x10B7, "3Com Corporation" },
{ 0x10B9, "AcerLabs (ALI)" },
{ 0x10DE, "nVidia Corporation" },
{ 0x10EC, "Realtek" },
{ 0x1106, "VIA" },
{ 0x110A, "Siemens Nixdorf AG" },
{ 0x125D, "ESS Technology" },
{ 0x1274, "Ensoniq" },
{ 0x5333, "S3" },
{ 0x8086, "Intel" },
{ 0x9004, "Adaptec" },
{ 0x9005, "Adaptec" },
{ 0x0000, NULL }
};
struct pci_device pci_device_table[]=
{
{ 0x1000, 0x0001, "NCR 53C810" },
{ 0x1000, 0x000F, "NCR 53C875" },
{ 0x1002, 0x4752, "ATI Rage XL PCI" },
{ 0x100B, 0xD001, "Nat. Semi. 87410" },
{ 0x1013, 0x00B8, "Cirrus Logic GD 5446" },
{ 0x1013, 0x6003, "Cirrus Logic CS4614/22/24 CrystalClear" },
{ 0x1022, 0x700C, "AMD-762 CPU to PCI Bridge (SMP chipset)" },
{ 0x1022, 0x700D, "AMD-762 CPU to PCI Bridge (AGP 4x)" },
{ 0x1022, 0x7410, "AMD-766 PCI to ISA/LPC Bridge" },
{ 0x1022, 0x7411, "AMD-766 EIDE Controller" },
{ 0x102B, 0x051B, "Matrox MGA 2164W [Millennium II]" },
{ 0x102B, 0x0525, "Matrox MGA G400 AGP" },
{ 0x1039, 0x0008, "SiS 85C503/5513" },
{ 0x1039, 0x0200, "SiS 5597/5598 VGA" },
{ 0x1039, 0x0406, "SiS 85C501/2" },
{ 0x1039, 0x5597, "SiS 5582" },
{ 0x104C, 0xAC1C, "TI PCI1225" },
{ 0x105A, 0x0D30, "Promise Technology 20265" },
{ 0x10B7, 0x9058, "3Com 3c905B-Combo" },
{ 0x10B7, 0x9805, "3Com 3c980-TX Python-T" },
{ 0x10B9, 0x1533, "ALI M1533 ISA-bridge [Aladdin IV]" },
{ 0x10B9, 0x1541, "ALI M1541" },
{ 0x10B9, 0x5229, "ALI M5229 (IDE)" },
{ 0x10B9, 0x5243, "ALI M5243" },
{ 0x10B9, 0x7101, "ALI M7101 PMU" },
{ 0x10DE, 0x0020, "nVidia Riva TnT [NV04]" },
{ 0x10DE, 0x0110, "nVidia GeForce2 MX [NV11]" },
{ 0x10EC, 0x8029, "Realtek RTL8029" },
{ 0x10EC, 0x8139, "Realtek RTL8139" },
{ 0x1106, 0x0305, "VIA VT8363/8365 [KT133/KM133]" },
{ 0x1106, 0x0571, "VIA IDE controller" },
{ 0x1106, 0x0686, "VIA VT82C686 (Apollo South Bridge)" },
{ 0x1106, 0x3038, "VT83C572 PCI USB Controller" },
{ 0x1106, 0x3057, "VT82C686A ACPI Power Management Controller" },
{ 0x1106, 0x3058, "VIA AC97 Audio Controller" },
{ 0x1106, 0x3059, "VIA AC97 Audio Controller" },
{ 0x1106, 0x3074, "VIA VT8233" },
{ 0x1106, 0x3099, "VIA VT8367 [KT266]" },
{ 0x1106, 0x8305, "VIA VT8365 [KM133 AGP]" },
{ 0x1106, 0xB099, "VIA VT8367 [KT266 AGP]" },
{ 0x110A, 0x0005, "Siemens Nixdorf Tulip Cntlr., Power Management" },
{ 0x1186, 0x1300, "D-Link RTL8139" },
{ 0x125D, 0x1969, "ESS ES1969 Solo-1 Audiodrive" },
{ 0x1274, 0x1371, "Ensoniq ES1371 [AudioPCI-97]" },
{ 0x1274, 0x5000, "Ensoniq ES1370" },
{ 0x1274, 0x5880, "Ensoniq CT5880 [AudioPCI]" },
{ 0x5333, 0x8811, "S3 86c764/765 [Trio32/64/64V+]" },
{ 0x5333, 0x883d, "S3 Virge/VX" },
{ 0x5333, 0x88d0, "S3 Vision 964 vers 0" },
{ 0x5333, 0x8a01, "S3 Virge/DX or /GX" },
{ 0x8086, 0x1004, "Intel 82543GC Gigabit Ethernet Controller" },
{ 0x8086, 0x1229, "Intel 82557" },
{ 0x8086, 0x122D, "Intel 82437FX" },
{ 0x8086, 0x122E, "Intel 82371FB (PIIX)" },
{ 0x8086, 0x1230, "Intel 82371FB (IDE)" },
{ 0x8086, 0x1237, "Intel 82441FX (440FX)" },
{ 0x8086, 0x1250, "Intel 82439HX" },
{ 0x8086, 0x7000, "Intel 82371SB" },
{ 0x8086, 0x7010, "Intel 82371SB (IDE)" },
{ 0x8086, 0x7020, "Intel 82371SB (USB)" },
{ 0x8086, 0x7100, "Intel 82371AB" },
{ 0x8086, 0x7110, "Intel 82371AB (PIIX4)" },
{ 0x8086, 0x7111, "Intel 82371AB (IDE)" },
{ 0x8086, 0x7112, "Intel 82371AB (USB)" },
{ 0x8086, 0x7113, "Intel 82371AB (Power)" },
{ 0x8086, 0x7190, "Intel 82443BX" },
{ 0x8086, 0x7191, "Intel 82443BX (AGP bridge)" },
{ 0x9004, 0x8178, "Adaptec AHA-2940U/2940UW Ultra/Ultra-Wide SCSI Ctrlr" },
{ 0x9005, 0x0080, "Adaptec AIC-7892A Ultra160/m PCI SCSI Controller" },
{ 0x0000, 0x0000, NULL }
};
struct pci_baseclass pci_baseclass_table[]=
{
{ 0x00, "No device class" },
{ 0x01, "Mass storage controller" },
{ 0x02, "Network controller" },
{ 0x03, "Display controller" },
{ 0x04, "Multimedia device" },
{ 0x05, "Memory controller" },
{ 0x06, "Bridge device" },
{ 0x07, "Simple comm. controller" },
{ 0x08, "Base system peripheral" },
{ 0x09, "Input device" },
{ 0x0A, "Docking station" },
{ 0x0B, "Processor" },
{ 0x0C, "Serial bus controller" },
{ 0x0d, "Wireless controller" },
{ 0x0e, "Intelligent I/O controller" },
{ 0x0f, "Satellite comm. controller" },
{ 0x10, "Encryption/decryption controller" },
{ 0x11, "Data acquisition controller" },
{ 0xff, "Misc. device" },
{ 0x00, NULL }
};
/* -1 in the infclass field is a wildcard for infclass */
struct pci_subclass pci_subclass_table[]=
{
{ 0x00, 0x01, 0x00, "VGA-compatible device" },
{ 0x01, 0x00, 0x00, "SCSI bus controller" },
{ 0x01, 0x01, -1, "IDE controller" },
{ 0x01, 0x02, 0x00, "Floppy disk controller" },
{ 0x01, 0x03, 0x00, "IPI controller" },
{ 0x01, 0x04, 0x00, "RAID controller" },
{ 0x01, 0x80, 0x00, "Other mass storage controller" },
{ 0x02, 0x00, 0x00, "Ethernet controller" },
{ 0x02, 0x01, 0x00, "Token Ring controller" },
{ 0x02, 0x02, 0x00, "FDDI controller" },
{ 0x02, 0x03, 0x00, "ATM controller" },
{ 0x02, 0x04, 0x00, "ISDN controller" },
{ 0x02, 0x80, 0x00, "Other network controller" },
{ 0x03, 0x00, 0x00, "VGA-compatible controller" },
{ 0x03, 0x00, 0x01, "8514-compatible controller" },
{ 0x03, 0x01, 0x00, "XGA controller" },
{ 0x03, 0x02, 0x00, "3D controller" },
{ 0x03, 0x80, 0x00, "Other display controller" },
{ 0x04, 0x00, 0x00, "Video device" },
{ 0x04, 0x01, 0x00, "Audio device" },
{ 0x04, 0x02, 0x00, "Computer telephony device" },
{ 0x04, 0x80, 0x00, "Other multimedia device" },
{ 0x06, 0x00, 0x00, "Host bridge" },
{ 0x06, 0x01, 0x00, "ISA bridge" },
{ 0x06, 0x02, 0x00, "EISA bridge" },
{ 0x06, 0x03, 0x00, "MCA bridge" },
{ 0x06, 0x04, 0x00, "PCI-to-PCI bridge" },
{ 0x06, 0x04, 0x01, "Subtractive decode PCI-to-PCI bridge" },
{ 0x06, 0x05, 0x00, "PCMCIA bridge" },
{ 0x06, 0x06, 0x00, "NuBus bridge" },
{ 0x06, 0x07, 0x00, "CardBus bridge" },
{ 0x06, 0x08, -1, "RACEway bridge" },
{ 0x06, 0x09, -1, "Semi-transparent PCI-to-PCI bridge" },
{ 0x06, 0x80, 0x00, "Other bridge device" },
{ 0x0C, 0x00, 0x00, "IEEE 1394 (FireWire)" },
{ 0x0C, 0x00, 0x10, "IEEE 1394 (OpenHCI)" },
{ 0x0C, 0x01, 0x00, "ACCESS bus" },
{ 0x0C, 0x02, 0x00, "SSA" },
{ 0x0C, 0x03, 0x00, "USB (with UHC)" },
{ 0x0C, 0x03, 0x10, "USB (with OHC)" },
{ 0x0C, 0x03, 0x80, "USB (other host inf.)" },
{ 0x0C, 0x03, 0xFE, "USB device" },
{ 0x0C, 0x04, 0x00, "Fibre Channel" },
{ 0x0C, 0x05, 0x00, "SMBus" },
{ 0x00, 0x00, 0x00, NULL }
};
struct pci_intel_ctrl pci_intel_ctrl[]=
{
{ 0x1022, 0x700C, }, /* AMD-762 */
{ 0x1039, 0x0406, }, /* SiS 85C501/2 */
{ 0x1039, 0x5597, }, /* SiS 5582 */
{ 0x10B9, 0x1541, }, /* ALI M1541 */
{ 0x1106, 0x0305, }, /* VIA VT8363/8365 */
{ 0x1106, 0x3099, }, /* VIA VT8367 [KT266] */
{ 0x1106, 0x3188, }, /* VIA */
{ 0x1106, 0x0204, }, /* VIA VT8367 [KT266] */
{ 0x8086, 0x122D, }, /* Intel 82437FX */
{ 0x8086, 0x1237, }, /* Intel 82441FX */
{ 0x8086, 0x1250, }, /* Intel 82439HX */
{ 0x8086, 0x7100, }, /* Intel 82371AB */
{ 0x8086, 0x7190, }, /* Intel 82443BX */
{ 0x0000, 0x0000, },
};
struct pci_isabridge pci_isabridge[]=
{
{ 0x1022, 0x7410, 1, PCI_IB_AMD, }, /* AMD-766 */
{ 0x1039, 0x0008, 1, PCI_IB_SIS, }, /* SiS 85C503/5513 */
{ 0x10B9, 0x1533, 1, PCI_IB_PIIX, }, /* ALI M1533 */
{ 0x1106, 0x0686, 1, PCI_IB_VIA, }, /* VIA VT82C686 */
{ 0x1106, 0x3074, 1, PCI_IB_VIA, }, /* VIA VT8233 */
{ 0x1106, 0x3227, 1, PCI_IB_VIA, }, /* VIA */
{ 0x8086, 0x122E, 1, PCI_IB_PIIX, }, /* Intel 82371FB */
{ 0x8086, 0x7000, 1, PCI_IB_PIIX, }, /* Intel 82371SB */
{ 0x8086, 0x7100, 1, PCI_IB_PIIX, }, /* Intel 82371AB */
{ 0x8086, 0x7110, 1, PCI_IB_PIIX, }, /* Intel PIIX4 */
{ 0x0000, 0x0000, 0, 0, },
};
struct pci_pcibridge pci_pcibridge[]=
{
{ 0x8086, 0x7191, PCI_AGPB_INTEL, }, /* Intel 82443BX (AGP bridge) */
{ 0x1022, 0x700D, PCI_AGPB_INTEL, }, /* AMD-762 (AGP 4x) */
{ 0x10B9, 0x5243, PCI_AGPB_INTEL, }, /* ALI M5243 */
{ 0x1106, 0x8305, PCI_AGPB_VIA, }, /* VIA VT8365 [KM133 AGP] */
{ 0x0000, 0x0000, 0, },
};
#endif /* ENABLE_PCI */
/*
* $PchId: pci_table.c,v 1.7 2003/09/05 10:53:22 philip Exp $
*/

27
kernel/pci_via.h Executable file
View File

@@ -0,0 +1,27 @@
/*
pci_via.h
Created: Jun 2001 by Philip Homburg <philip@cs.vu.nl>
*/
#define VIA_ISABR_EL 0x54 /* Edge or level triggered */
#define VIA_ISABR_EL_INTA 0x08 /* Edge (1) or level (0) */
#define VIA_ISABR_EL_INTB 0x04
#define VIA_ISABR_EL_INTC 0x02
#define VIA_ISABR_EL_INTD 0x01
#define VIA_ISABR_IRQ_R1 0x55 /* IRQ routing 1 */
#define VIA_ISABR_IRQ_INTD 0xf0 /* routing for INTD */
#define VIA_ISABR_IRQ_INT0 0x0f /* routing for INT0 */
#define VIA_ISABR_IRQ_R2 0x56 /* IRQ routing 2 */
#define VIA_ISABR_IRQ_INTA 0xf0 /* routing for INTA */
#define VIA_ISABR_IRQ_INTB 0x0f /* routing for INTB */
#define VIA_ISABR_IRQ_R3 0x57 /* IRQ routing 3 */
#define VIA_ISABR_IRQ_INTC 0xf0 /* routing for INTC */
#define VIA_ISABR_IRQ_INT1 0x0f /* routing for INT1 */
#define VIA_ISABR_IRQ_R4 0x58 /* IRQ routing 4 */
#define VIA_ISABR_IRQ_INT2 0x0f /* routing for INT2 */
/*
* $PchId: pci_via.h,v 1.1 2001/06/20 15:50:25 philip Exp $
*/

595
kernel/proc.c Executable file
View File

@@ -0,0 +1,595 @@
/* This file contains essentially all of the process and message handling.
* It has two main entry points from the outside:
*
* sys_call: a system call, that is, the kernel is trapped with an INT
* notify: notify process of a system event (notifications aren't queued)
*
* It also has several minor entry points:
*
* 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)
* unhold: repeat all held-up notifications
*
* Changes:
* Nov 05, 2004 removed lock_mini_send() (Jorrit N. Herder)
* Oct 28, 2004 non-blocking SEND and RECEIVE (Jorrit N. Herder)
* Oct 28, 2004 rewrite of sys_call() (Jorrit N. Herder)
* Oct 10, 2004 require BOTH for kernel sys_call() (Jorrit N. Herder)
* (to protect kernel tasks from being blocked)
* Sep 25, 2004 generalized notify() function (Jorrit N. Herder)
* Sep 23, 2004 removed MM sig check in mini_rec() (Jorrit N. Herder)
* Aug 19, 2004 generalized ready()/unready() (Jorrit N. Herder)
* Aug 18, 2004 added notify() function (Jorrit N. Herder)
* May 01, 2004 check p_sendmask in mini_send() (Jorrit N. Herder)
*/
#include "kernel.h"
#include <minix/callnr.h>
#include <minix/com.h>
#include "proc.h"
#include "sendmask.h"
PRIVATE unsigned char switching; /* nonzero to inhibit notify() */
FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dest,
message *m_ptr, int may_block) );
FORWARD _PROTOTYPE( int mini_rec, (struct proc *caller_ptr, int src,
message *m_ptr, int may_block) );
FORWARD _PROTOTYPE( void ready, (struct proc *rp) );
FORWARD _PROTOTYPE( void sched, (void) );
FORWARD _PROTOTYPE( void unready, (struct proc *rp) );
FORWARD _PROTOTYPE( void pick_proc, (void) );
#if (CHIP == M68000)
FORWARD _PROTOTYPE( void cp_mess, (int src, struct proc *src_p, message *src_m,
struct proc *dst_p, message *dst_m) );
#endif
#if (CHIP == INTEL)
#define CopyMess(s,sp,sm,dp,dm) \
cp_mess(s, (sp)->p_memmap[D].mem_phys, (vir_bytes)sm, (dp)->p_memmap[D].mem_phys, (vir_bytes)dm)
#endif /* (CHIP == INTEL) */
#if (CHIP == M68000)
/* M68000 does not have cp_mess() in assembly like INTEL. Declare prototype
* for cp_mess() here and define the function below. Also define CopyMess.
*/
#endif /* (CHIP == M68000) */
/* Bit mask operations used to bits of the notification mask. */
#define set_bit(mask, n) ((mask) |= (1 << (n)))
#define clear_bit(mask, n) ((mask) &= ~(1 << (n)))
#define isset_bit(mask, n) ((mask) & (1 << (n)))
/*===========================================================================*
* notify *
*===========================================================================*/
PUBLIC void notify(proc_nr, notify_type)
int proc_nr; /* number of process to be started */
int notify_type; /* notification to be sent */
{
/* A system event has occurred. Send a notification with source HARDWARE to
* the given process. The notify() function was carefully designed so that it
* (1) can be used safely from both interrupt handlers and the task level, and
* (2) realizes asynchronous message passing with at least once semantics,
* that is, the notifications are not queued. If a race condition occurs, the
* notification is queued and repeated later by unhold(). If the receiver is
* not ready, the notification is blocked and checked later in receive().
*/
register struct proc *rp; /* pointer to task's proc entry */
message m; /* message to send the notification */
unsigned int notify_bit; /* bit for this notification */
/* Get notify bit and process pointer. */
notify_bit = (unsigned int) (notify_type - NOTIFICATION);
rp = proc_addr(proc_nr);
/* If this call would compete with other process-switching functions, put
* it on the 'held' queue to be flushed at the next non-competing restart().
* The competing conditions are:
* (1) k_reenter == (typeof k_reenter) -1:
* Call from the task level, typically from an output interrupt
* routine. An interrupt handler might reenter notify(). Rare,
* so not worth special treatment.
* (2) k_reenter > 0:
* Call from a nested interrupt handler. A previous interrupt
* handler might be inside notify() or sys_call().
* (3) switching != 0:
* A process-switching function other than notify() is being called
* from the task level, typically sched() from CLOCK. An interrupt
* handler might call notify() and pass the 'k_reenter' test.
*/
if (k_reenter != 0 || switching) {
lock();
if (! rp->p_ntf_held) { /* already on held queue? */
if (held_head != NIL_PROC)
held_tail->p_ntf_nextheld = rp;
else
held_head = rp;
held_tail = rp;
rp->p_ntf_nextheld = NIL_PROC;
}
set_bit(rp->p_ntf_held, notify_bit); /* add bit to held mask */
unlock();
return;
}
switching = TRUE;
/* If process is not waiting for a notification, record the blockage. */
if ( (rp->p_flags & (RECEIVING | SENDING)) != RECEIVING ||
!isrxhardware(rp->p_getfrom)) {
set_bit(rp->p_ntf_blocked, notify_bit); /* add bit to blocked mask */
switching = FALSE;
return;
}
/* Destination is waiting for a notification. Send it a message with source
* HARDWARE and type 'notify_type'. No more information can be reliably
* provided since notifications are not queued.
*/
m.m_source = HARDWARE; /* direct copy does not work for servers */
m.m_type = notify_type;
CopyMess(HARDWARE, proc_addr(HARDWARE), &m, rp, rp->p_messbuf);
rp->p_flags &= ~RECEIVING;
clear_bit(rp->p_ntf_blocked, notify_bit);
/* Announce the process ready and select a fresh process to run. */
ready(rp);
pick_proc();
switching = FALSE;
}
/*===========================================================================*
* sys_call *
*===========================================================================*/
PUBLIC int sys_call(call_nr, src_dst, m_ptr)
int call_nr; /* (NB_)SEND, (NB_)RECEIVE, BOTH */
int src_dst; /* source to receive from or dest to send to */
message *m_ptr; /* pointer to message in the caller's space */
{
/* System calls are done by trapping to the kernel with an INT instruction.
* The trap is caught and sys_call() is called to send or receive a message
* (or both). The caller is always given by 'proc_ptr'.
*/
register struct proc *caller_ptr = proc_ptr; /* get pointer to caller */
int function = call_nr & SYSCALL_FUNC; /* get system call function */
int may_block = ! (call_nr & NON_BLOCKING); /* (dis)allow blocking? */
int mask_entry; /* bit to check in send mask */
int result; /* the system call's result */
/* Calls directed to the kernel may only be sendrec(), because tasks always
* reply and may not block if the caller doesn't do receive(). Users also
* may only use sendrec() to protect the MM and FS.
*/
if ((iskernel(src_dst) || isuserp(caller_ptr)) && function != BOTH) {
result = ECALLDENIED; /* BOTH was required */
}
/* Verify that requested source and/ or destination is a valid process. */
else if (! isoksrc_dst(src_dst)) {
result = EBADSRCDST; /* invalid process number */
}
/* Now check if the call is known and try to perform the request. The only
* system calls that exist in MINIX are sending and receiving messages.
* Receiving is straightforward. Sending requires checks to see if sending
* is allowed by the caller's send mask and to see if the destination is
* alive.
*/
else {
switch(function) {
case SEND:
/* fall through, SEND is done in BOTH */
case BOTH:
if (! isalive(src_dst)) {
result = EDEADDST; /* cannot send to the dead */
break;
}
mask_entry = isuser(src_dst) ? USER_PROC_NR : src_dst;
if (! isallowed(caller_ptr->p_sendmask, mask_entry)) {
kprintf("WARNING: sys_call denied %d ", caller_ptr->p_nr);
kprintf("sending to %d\n", proc_addr(src_dst)->p_nr);
result = ECALLDENIED; /* call denied by send mask */
break;
}
result = mini_send(caller_ptr, src_dst, m_ptr, may_block);
if (function == SEND || result != OK) {
break; /* done, or SEND failed */
} /* fall through for BOTH */
case RECEIVE:
result = mini_rec(caller_ptr, src_dst, m_ptr, may_block);
break;
default:
result = EBADCALL; /* illegal system call */
}
}
/* Now, return the result of the system call to the caller. */
return(result);
}
/*===========================================================================*
* mini_send *
*===========================================================================*/
PRIVATE int mini_send(caller_ptr, dest, m_ptr, may_block)
register struct proc *caller_ptr; /* who is trying to send a message? */
int dest; /* to whom is message being sent? */
message *m_ptr; /* pointer to message buffer */
int may_block; /* (dis)allow blocking */
{
/* Send a message from 'caller_ptr' to 'dest'. If 'dest' is blocked waiting
* for this message, copy the message to it and unblock 'dest'. If 'dest' is
* not waiting at all, or is waiting for another source, queue 'caller_ptr'.
*/
register struct proc *dest_ptr, *next_ptr;
vir_bytes vb; /* message buffer pointer as vir_bytes */
vir_clicks vlo, vhi; /* virtual clicks containing message to send */
dest_ptr = proc_addr(dest); /* pointer to destination's proc entry */
#if ALLOW_GAP_MESSAGES
/* This check allows a message to be anywhere in data or stack or gap.
* It will have to be made more elaborate later for machines which
* don't have the gap mapped.
*/
vb = (vir_bytes) m_ptr;
vlo = vb >> CLICK_SHIFT; /* vir click for bottom of message */
vhi = (vb + MESS_SIZE - 1) >> CLICK_SHIFT; /* vir click for top of msg */
if (vlo < caller_ptr->p_memmap[D].mem_vir || vlo > vhi ||
vhi >= caller_ptr->p_memmap[S].mem_vir + caller_ptr->p_memmap[S].mem_len)
return(EFAULT);
#else
/* Check for messages wrapping around top of memory or outside data seg. */
vb = (vir_bytes) m_ptr;
vlo = vb >> CLICK_SHIFT; /* vir click for bottom of message */
vhi = (vb + MESS_SIZE - 1) >> CLICK_SHIFT; /* vir click for top of msg */
if (vhi < vlo ||
vhi - caller_ptr->p_memmap[D].mem_vir >= caller_ptr->p_memmap[D].mem_len)
return(EFAULT);
#endif
/* Check for deadlock by 'caller_ptr' and 'dest' sending to each other. */
if (dest_ptr->p_flags & SENDING) {
next_ptr = proc_addr(dest_ptr->p_sendto);
while (TRUE) {
if (next_ptr == caller_ptr) return(ELOCKED);
if (next_ptr->p_flags & SENDING)
next_ptr = proc_addr(next_ptr->p_sendto);
else
break;
}
}
/* Check to see if 'dest' is blocked waiting for this message. */
if ( (dest_ptr->p_flags & (RECEIVING | SENDING)) == RECEIVING &&
(dest_ptr->p_getfrom == ANY ||
dest_ptr->p_getfrom == proc_number(caller_ptr))) {
/* Destination is indeed waiting for this message. */
CopyMess(proc_number(caller_ptr), caller_ptr, m_ptr, dest_ptr,
dest_ptr->p_messbuf);
dest_ptr->p_flags &= ~RECEIVING; /* deblock destination */
if (dest_ptr->p_flags == 0) ready(dest_ptr);
} else if (may_block) {
/* Destination is not waiting. Block and queue caller. */
caller_ptr->p_messbuf = m_ptr;
if (caller_ptr->p_flags == 0) unready(caller_ptr);
caller_ptr->p_flags |= SENDING;
caller_ptr->p_sendto= dest;
/* Process is now blocked. Put in on the destination's queue. */
if ( (next_ptr = dest_ptr->p_callerq) == NIL_PROC)
dest_ptr->p_callerq = caller_ptr;
else {
while (next_ptr->p_sendlink != NIL_PROC)
next_ptr = next_ptr->p_sendlink;
next_ptr->p_sendlink = caller_ptr;
}
caller_ptr->p_sendlink = NIL_PROC;
} else {
return(ENOTREADY);
}
return(OK);
}
/*===========================================================================*
* mini_rec *
*===========================================================================*/
PRIVATE int mini_rec(caller_ptr, src, m_ptr, may_block)
register struct proc *caller_ptr; /* process trying to get message */
int src; /* which message source is wanted */
message *m_ptr; /* pointer to message buffer */
int may_block; /* (dis)allow blocking */
{
/* A process or task wants to get a message. If one is already queued,
* acquire it and deblock the sender. If no message from the desired source
* is available, block the caller.
*/
register struct proc *sender_ptr;
register struct proc *previous_ptr;
message m;
int i;
/* Check to see if a message from desired source is already available. */
if (!(caller_ptr->p_flags & SENDING)) {
/* Check caller queue. */
for (sender_ptr = caller_ptr->p_callerq; sender_ptr != NIL_PROC;
previous_ptr = sender_ptr, sender_ptr = sender_ptr->p_sendlink) {
if (src == ANY || src == proc_number(sender_ptr)) {
/* An acceptable message has been found. */
CopyMess(proc_number(sender_ptr), sender_ptr,
sender_ptr->p_messbuf, caller_ptr, m_ptr);
if (sender_ptr == caller_ptr->p_callerq)
caller_ptr->p_callerq = sender_ptr->p_sendlink;
else
previous_ptr->p_sendlink = sender_ptr->p_sendlink;
if ((sender_ptr->p_flags &= ~SENDING) == 0)
ready(sender_ptr); /* deblock sender */
return(OK);
}
}
/* Check bit mask for blocked notifications. If multiple bits are set,
* send the first notification encountered; the rest is handled later.
* This effectively prioritizes notifications. Notification also have
* priority of other messages.
*/
if (caller_ptr->p_ntf_blocked && isrxhardware(src)) {
for (i=0; i<NR_NOTIFICATIONS; i++) {
if (isset_bit(caller_ptr->p_ntf_blocked, i)) {
m.m_source = HARDWARE;
m.m_type = NOTIFICATION + i;
CopyMess(HARDWARE, proc_addr(HARDWARE), &m, caller_ptr, m_ptr);
clear_bit(caller_ptr->p_ntf_blocked, i);
return(OK);
}
}
}
}
/* No suitable message is available. Block the process trying to receive,
* unless this is not allowed by the system call.
*/
if (may_block) {
caller_ptr->p_getfrom = src;
caller_ptr->p_messbuf = m_ptr;
if (caller_ptr->p_flags == 0) unready(caller_ptr);
caller_ptr->p_flags |= RECEIVING;
return(OK);
} else {
return(ENOTREADY);
}
}
/*===========================================================================*
* pick_proc *
*===========================================================================*/
PRIVATE void pick_proc()
{
/* Decide who to run now. A new process is selected by setting 'proc_ptr'.
* When a fresh user (or idle) process is selected, record it in 'bill_ptr',
* so the clock task can tell who to bill for system time.
*/
register struct proc *rp; /* process to run */
int q; /* iterate over queues */
/* Check each of the scheduling queues for ready processes. The number of
* queues is defined in proc.h, and priorities are set in the task table.
* The lowest queue contains IDLE, which is always ready.
*/
for (q=0; q < NR_SCHED_QUEUES; q++) {
if ( (rp = rdy_head[q]) != NIL_PROC) {
proc_ptr = rp; /* run process 'rp' next */
if (isuserp(rp) || isidlep(rp)) /* possible bill 'rp' */
bill_ptr = rp;
return;
}
}
}
/*===========================================================================*
* ready *
*===========================================================================*/
PRIVATE void ready(rp)
register struct proc *rp; /* this process is now runnable */
{
/* Add 'rp' to one of the queues of runnable processes. */
int q = rp->p_priority; /* scheduling queue to use */
/* Processes, in principle, are added to the end of the queue. However,
* user processes are added in front of the queue, because this is a bit
* fairer to I/O bound processes.
*/
if (isuserp(rp)) { /* add to front of queue */
if (rdy_head[q] == NIL_PROC)
rdy_tail[q] = rp;
rp->p_nextready = rdy_head[q]; /* add to front of queue */
rdy_head[q] = rp;
}
else {
if (rdy_head[q] != NIL_PROC)
rdy_tail[q]->p_nextready = rp; /* add to end of queue */
else
rdy_head[q] = rp; /* add to empty queue */
rdy_tail[q] = rp;
rp->p_nextready = NIL_PROC;
}
/* Run 'rp' next if it has a higher priority than 'proc_ptr'. This actually
* should be done via pick_proc(), but mini_send() and mini_rec() rely
* on this side-effect.
*/
if (rp->p_priority < proc_ptr->p_priority) proc_ptr = rp;
}
/*===========================================================================*
* unready *
*===========================================================================*/
PRIVATE void unready(rp)
register struct proc *rp; /* this process is no longer runnable */
{
/* A process has blocked. See ready for a description of the queues. */
register struct proc *xp;
register struct proc **qtail; /* queue's rdy_tail */
int q = rp->p_priority; /* queue to use */
/* Side-effect for tasks: check if the task's stack still is ok? */
if (istaskp(rp)) {
if (*rp->p_stguard != STACK_GUARD)
panic("stack overrun by task", proc_number(rp));
}
/* Now make sure that the process is not in its ready queue. Remove the
* process if it is found. The easy part is to check the front of the queue.
*/
if ( (xp = rdy_head[q]) == NIL_PROC) return;
if (xp == rp) {
rdy_head[q] = xp->p_nextready; /* remove head of queue */
if (rp == proc_ptr) /* current process removed */
pick_proc(); /* pick new process to run */
return;
}
/* No match yet. Search body of queue. A process can be made unready even
* if it is not running by being sent a signal that kills it.
*/
while (xp->p_nextready != rp)
if ( (xp = xp->p_nextready) == NIL_PROC) return;
xp->p_nextready = xp->p_nextready->p_nextready;
qtail = &rdy_tail[q];
if (*qtail == rp) *qtail = xp;
}
/*===========================================================================*
* sched *
*===========================================================================*/
PRIVATE void sched()
{
/* The current process has run too long. If another low priority (user)
* process is runnable, put the current process on the end of the user queue,
* possibly promoting another user to head of the queue.
*/
if (rdy_head[PPRI_USER] == NIL_PROC) return;
/* One or more user processes queued. */
rdy_tail[PPRI_USER]->p_nextready = rdy_head[PPRI_USER];
rdy_tail[PPRI_USER] = rdy_head[PPRI_USER];
rdy_head[PPRI_USER] = rdy_head[PPRI_USER]->p_nextready;
rdy_tail[PPRI_USER]->p_nextready = NIL_PROC;
pick_proc();
}
/*==========================================================================*
* lock_pick_proc *
*==========================================================================*/
PUBLIC void lock_pick_proc()
{
/* Safe gateway to pick_proc() for tasks. */
switching = TRUE;
pick_proc();
switching = FALSE;
}
/*==========================================================================*
* lock_ready *
*==========================================================================*/
PUBLIC void lock_ready(rp)
struct proc *rp; /* this process is now runnable */
{
/* Safe gateway to ready() for tasks. */
switching = TRUE;
ready(rp);
switching = FALSE;
}
/*==========================================================================*
* lock_unready *
*==========================================================================*/
PUBLIC void lock_unready(rp)
struct proc *rp; /* this process is no longer runnable */
{
/* Safe gateway to unready() for tasks. */
switching = TRUE;
unready(rp);
switching = FALSE;
}
/*==========================================================================*
* lock_sched *
*==========================================================================*/
PUBLIC void lock_sched()
{
/* Safe gateway to sched() for tasks. */
switching = TRUE;
sched();
switching = FALSE;
}
/*==========================================================================*
* unhold *
*==========================================================================*/
PUBLIC void unhold()
{
/* Flush any held-up notifications. 'k_reenter' must be 0. 'held_head' must
* not be NIL_PROC. Interrupts must be disabled. They will be enabled but
* will be disabled when this returns.
*/
register struct proc *rp; /* current head of held queue */
int i;
if (switching) return;
rp = held_head;
do {
for (i=0; i<NR_NOTIFICATIONS; i++) {
if (isset_bit(rp->p_ntf_held,i)) {
clear_bit(rp->p_ntf_held,i);
if (! rp->p_ntf_held) /* proceed to next in queue? */
if ( (held_head = rp->p_ntf_nextheld) == NIL_PROC)
held_tail = NIL_PROC;
unlock(); /* reduce latency; held queue may change! */
notify(proc_number(rp), NOTIFICATION + i);
lock(); /* protect the held queue again */
}
}
}
while ( (rp = held_head) != NIL_PROC);
}
#if (CHIP == M68000)
/*==========================================================================*
* cp_mess *
*==========================================================================*/
PRIVATE void cp_mess(src, src_p, src_m, dst_p, dst_m)
int src; /* sender process */
register struct proc *src_p; /* source proc entry */
message *src_m; /* source message */
register struct proc *dst_p; /* destination proc entry */
message *dst_m; /* destination buffer */
{
/* convert virtual address to physical address */
/* The caller has already checked if all addresses are within bounds */
src_m = (message *)((char *)src_m + (((phys_bytes)src_p->p_map[D].mem_phys
- src_p->p_map[D].mem_vir) << CLICK_SHIFT));
dst_m = (message *)((char *)dst_m + (((phys_bytes)dst_p->p_map[D].mem_phys
- dst_p->p_map[D].mem_vir) << CLICK_SHIFT));
#ifdef NEEDFSTRUCOPY
phys_copy(src_m,dst_m,(phys_bytes) sizeof(message));
#else
*dst_m = *src_m;
#endif
dst_m->m_source = src;
}
#endif

154
kernel/proc.h Executable file
View File

@@ -0,0 +1,154 @@
#ifndef PROC_H
#define PROC_H
/* Here is the declaration of the process table. It contains the process'
* registers, memory map, accounting, and message send/receive information.
* Many assembly code routines reference fields in it. The offsets to these
* fields are defined in the assembler include file sconst.h. When changing
* 'proc', be sure to change sconst.h to match.
*
* Changes:
* Nov 10, 2004 separated process types/ priorities (Jorrit N. Herder)
* Sep 30, 2004 bit masks for notifications (Jorrit N. Herder)
* Sep 24, 2004 one timer per type of alarm (Jorrit N. Herder)
* May 01, 2004 new p_sendmask to protect syscalls (Jorrit N. Herder)
*/
#include <minix/com.h>
#include "const.h"
struct proc {
struct stackframe_s p_reg; /* process' registers saved in stack frame */
#if (CHIP == INTEL)
reg_t p_ldt_sel; /* selector in gdt giving ldt base and limit*/
struct segdesc_s p_ldt[4]; /* local descriptors for code and data */
/* 4 is LDT_SIZE - avoid include protect.h */
#endif /* (CHIP == INTEL) */
#if (CHIP == M68000)
/* M68000 specific registers and FPU details go here. */
#endif /* (CHIP == M68000) */
reg_t *p_stguard; /* stack guard word */
int p_nr; /* number of this process (for fast access) */
notify_mask_t p_ntf_blocked; /* bit mask for blocked notifications */
notify_mask_t p_ntf_held; /* bit mask for held up notify() calls */
struct proc *p_ntf_nextheld; /* next in chain of held-up int processes */
int p_flags; /* SENDING, RECEIVING, etc. */
struct mem_map p_memmap[NR_LOCAL_SEGS]; /* local memory map (T, D, S) */
struct far_mem p_farmem[NR_REMOTE_SEGS]; /* remote memory map */
short p_type; /* task, system, driver, server, user, idle */
short p_priority; /* scheduling priority */
clock_t user_time; /* user time in ticks */
clock_t sys_time; /* sys time in ticks */
clock_t child_utime; /* cumulative user time of children */
clock_t child_stime; /* cumulative sys time of children */
timer_t p_signalrm; /* signal alarm timer */
timer_t p_flagalrm; /* flag alarm timer */
timer_t p_syncalrm; /* synchronous alarm timer */
send_mask_t p_sendmask; /* mask indicating to whom proc may send */
struct proc *p_callerq; /* head of list of procs wishing to send */
struct proc *p_sendlink; /* link to next proc wishing to send */
message *p_messbuf; /* pointer to message buffer */
int p_getfrom; /* from whom does process want to receive? */
int p_sendto; /* to whom does process want to send? */
struct proc *p_nextready; /* pointer to next ready process */
sigset_t p_pending; /* bit map for pending signals */
unsigned p_pendcount; /* count of pending and unfinished signals */
char p_name[PROC_NAME_LEN]; /* name of the process, including \0 */
#if ENABLE_MESSAGE_STATS
int msg_unreplied[NR_TASKS+NR_PROCS];
#endif
};
/* Guard word for task stacks. */
#define STACK_GUARD ((reg_t) (sizeof(reg_t) == 2 ? 0xBEEF : 0xDEADBEEF))
/* Bits for p_flags in proc[]. A process is runnable iff p_flags == 0. */
#define NO_MAP 0x01 /* keeps unmapped forked child from running */
#define SENDING 0x02 /* set when process blocked trying to send */
#define RECEIVING 0x04 /* set when process blocked trying to recv */
#define PENDING 0x08 /* set when inform() of signal pending */
#define SIG_PENDING 0x10 /* keeps to-be-signalled proc from running */
#define P_STOP 0x20 /* set when process is being traced */
/* Values for p_type. Non-negative values represent active process types.
* Process types are important to model inter-process relationships. When
* MINIX is shutdown, all system services are notified in order of possible
* dependencies, so that, e.g., the FS can rely on drivers to synchronize.
*/
#define P_RESERVED -2 /* slot is not in use, but reserved */
#define P_NONE -1 /* slot is not in use, and free */
#define P_TASK 0 /* kernel process */
#define P_SYSTEM 1 /* low-level system service */
#define P_DRIVER 2 /* device driver */
#define P_SERVER 3 /* system service outside the kernel */
#define P_USER 4 /* user process */
#define P_IDLE 5 /* idle process */
/* Scheduling priorities for p_priority. Values must start at zero and
* increment. Priorities of system services can be set in the task table.
* Task, user, and idle priorities are fixed; the rest can be selected.
*/
#define PPRI_TASK 0 /* reserved for kernel tasks */
#define PPRI_HIGHER 1
#define PPRI_HIGH 2
#define PPRI_NORMAL 3
#define PPRI_LOW 4
#define PPRI_LOWER 5
#define PPRI_USER 6 /* reserved for user processes */
#define PPRI_IDLE 7 /* only IDLE process goes here */
#define NR_SCHED_QUEUES 8 /* MUST equal minimum priority + 1 */
/* Magic process table addresses. */
#define BEG_PROC_ADDR (&proc[0])
#define BEG_USER_ADDR (&proc[NR_TASKS])
#define END_PROC_ADDR (&proc[NR_TASKS + NR_PROCS])
#define NIL_PROC ((struct proc *) 0)
#define isidlehardware(n) ((n) == IDLE || (n) == HARDWARE)
#define isokprocn(n) ((unsigned) ((n) + NR_TASKS) < NR_PROCS + NR_TASKS)
#define isokprocp(p) ((p) >= BEG_PROC_ADDR && (p) < END_PROC_ADDR)
#define isoksrc_dst(n) (isokprocn(n) || (n) == ANY)
#define isalive(n) (proc_addr(n)->p_type > P_NONE)
#define isalivep(p) ((p)->p_type > P_NONE)
#define isrxhardware(n) ((n) == ANY || (n) == HARDWARE)
#define iskernel(n) ((n) == CLOCK || (n) == SYSTASK)
#define issysentn(n) ((n) == FS_PROC_NR || (n) == MM_PROC_NR)
#define issysentp(p) (issysentn((p)->p_nr))
#define isreservedp(p) ((p)->p_type == P_RESERVED)
#define isemptyp(p) ((p)->p_type == P_NONE)
#define istaskp(p) ((p)->p_type == P_TASK)
#define isdriverp(p) ((p)->p_type == P_DRIVER)
#define isserverp(p) ((p)->p_type == P_SERVER)
#define isuserp(p) ((p)->p_type == P_USER)
#define isuser(n) (proc_addr(n)->p_type == P_USER)
#define isidlep(p) ((p)->p_type == P_IDLE)
#define proc_addr(n) (pproc_addr + NR_TASKS)[(n)]
#define cproc_addr(n) (&(proc + NR_TASKS)[(n)])
#define proc_number(p) ((p)->p_nr)
#define proc_vir2phys(p, vir) \
(((phys_bytes)(p)->p_map[D].mem_phys << CLICK_SHIFT) \
+ (vir_bytes) (vir))
/* The process table and pointers to process table slots. The pointers allow
* faster access because now a process entry can be found by indexing the
* pproc_addr array, while accessing an element i requires a multiplication
* with sizeof(struct proc) to determine the address.
*/
EXTERN struct proc proc[NR_TASKS + NR_PROCS]; /* process table */
EXTERN struct proc *pproc_addr[NR_TASKS + NR_PROCS];
EXTERN struct proc *bill_ptr; /* ptr to process to bill for clock ticks */
EXTERN struct proc *rdy_head[NR_SCHED_QUEUES]; /* ptrs to ready list headers */
EXTERN struct proc *rdy_tail[NR_SCHED_QUEUES]; /* ptrs to ready list tails */
#endif /* PROC_H */

344
kernel/protect.c Executable file
View File

@@ -0,0 +1,344 @@
/* This file contains code for initialization of protected mode, to initialize
* code and data segment descriptors, and to initialize global descriptors
* for local descriptors in the process table.
*/
#include "kernel.h"
#include "proc.h"
#include "protect.h"
#if _WORD_SIZE == 4
#define INT_GATE_TYPE (INT_286_GATE | DESC_386_BIT)
#define TSS_TYPE (AVL_286_TSS | DESC_386_BIT)
#else
#define INT_GATE_TYPE INT_286_GATE
#define TSS_TYPE AVL_286_TSS
#endif
struct desctableptr_s {
char limit[sizeof(u16_t)];
char base[sizeof(u32_t)]; /* really u24_t + pad for 286 */
};
struct gatedesc_s {
u16_t offset_low;
u16_t selector;
u8_t pad; /* |000|XXXXX| ig & trpg, |XXXXXXXX| task g */
u8_t p_dpl_type; /* |P|DL|0|TYPE| */
u16_t offset_high;
};
struct tss_s {
reg_t backlink;
reg_t sp0; /* stack pointer to use during interrupt */
reg_t ss0; /* " segment " " " " */
reg_t sp1;
reg_t ss1;
reg_t sp2;
reg_t ss2;
#if _WORD_SIZE == 4
reg_t cr3;
#endif
reg_t ip;
reg_t flags;
reg_t ax;
reg_t cx;
reg_t dx;
reg_t bx;
reg_t sp;
reg_t bp;
reg_t si;
reg_t di;
reg_t es;
reg_t cs;
reg_t ss;
reg_t ds;
#if _WORD_SIZE == 4
reg_t fs;
reg_t gs;
#endif
reg_t ldt;
#if _WORD_SIZE == 4
u16_t trap;
u16_t iobase;
/* u8_t iomap[0]; */
#endif
};
PUBLIC struct segdesc_s gdt[GDT_SIZE]; /* used in klib.s and mpx.s */
PRIVATE struct gatedesc_s idt[IDT_SIZE]; /* zero-init so none present */
PUBLIC struct tss_s tss; /* zero init */
FORWARD _PROTOTYPE( void int_gate, (unsigned vec_nr, vir_bytes offset,
unsigned dpl_type) );
FORWARD _PROTOTYPE( void sdesc, (struct segdesc_s *segdp, phys_bytes base,
vir_bytes size) );
/*=========================================================================*
* prot_init *
*=========================================================================*/
PUBLIC void prot_init()
{
/* Set up tables for protected mode.
* All GDT slots are allocated at compile time.
*/
extern int etext, end;
#define code_bytes ((vir_bytes) &etext) /* Size of code segment. */
#define data_bytes ((vir_bytes) &end) /* Size of data segment. */
struct gate_table_s *gtp;
struct desctableptr_s *dtp;
unsigned ldt_index;
register struct proc *rp;
static struct gate_table_s {
_PROTOTYPE( void (*gate), (void) );
unsigned char vec_nr;
unsigned char privilege;
}
gate_table[] = {
divide_error, DIVIDE_VECTOR, INTR_PRIVILEGE,
single_step_exception, DEBUG_VECTOR, INTR_PRIVILEGE,
nmi, NMI_VECTOR, INTR_PRIVILEGE,
breakpoint_exception, BREAKPOINT_VECTOR, USER_PRIVILEGE,
overflow, OVERFLOW_VECTOR, USER_PRIVILEGE,
bounds_check, BOUNDS_VECTOR, INTR_PRIVILEGE,
inval_opcode, INVAL_OP_VECTOR, INTR_PRIVILEGE,
copr_not_available, COPROC_NOT_VECTOR, INTR_PRIVILEGE,
double_fault, DOUBLE_FAULT_VECTOR, INTR_PRIVILEGE,
copr_seg_overrun, COPROC_SEG_VECTOR, INTR_PRIVILEGE,
inval_tss, INVAL_TSS_VECTOR, INTR_PRIVILEGE,
segment_not_present, SEG_NOT_VECTOR, INTR_PRIVILEGE,
stack_exception, STACK_FAULT_VECTOR, INTR_PRIVILEGE,
general_protection, PROTECTION_VECTOR, INTR_PRIVILEGE,
#if _WORD_SIZE == 4
page_fault, PAGE_FAULT_VECTOR, INTR_PRIVILEGE,
copr_error, COPROC_ERR_VECTOR, INTR_PRIVILEGE,
#endif
{ hwint00, VECTOR( 0), INTR_PRIVILEGE },
{ hwint01, VECTOR( 1), INTR_PRIVILEGE },
{ hwint02, VECTOR( 2), INTR_PRIVILEGE },
{ hwint03, VECTOR( 3), INTR_PRIVILEGE },
{ hwint04, VECTOR( 4), INTR_PRIVILEGE },
{ hwint05, VECTOR( 5), INTR_PRIVILEGE },
{ hwint06, VECTOR( 6), INTR_PRIVILEGE },
{ hwint07, VECTOR( 7), INTR_PRIVILEGE },
{ hwint08, VECTOR( 8), INTR_PRIVILEGE },
{ hwint09, VECTOR( 9), INTR_PRIVILEGE },
{ hwint10, VECTOR(10), INTR_PRIVILEGE },
{ hwint11, VECTOR(11), INTR_PRIVILEGE },
{ hwint12, VECTOR(12), INTR_PRIVILEGE },
{ hwint13, VECTOR(13), INTR_PRIVILEGE },
{ hwint14, VECTOR(14), INTR_PRIVILEGE },
{ hwint15, VECTOR(15), INTR_PRIVILEGE },
#if _WORD_SIZE == 2
{ p_s_call, SYS_VECTOR, USER_PRIVILEGE }, /* 286 system call */
#else
{ s_call, SYS386_VECTOR, USER_PRIVILEGE }, /* 386 system call */
#endif
{ level0_call, LEVEL0_VECTOR, TASK_PRIVILEGE },
};
/* Build gdt and idt pointers in GDT where the BIOS expects them. */
dtp= (struct desctableptr_s *) &gdt[GDT_INDEX];
* (u16_t *) dtp->limit = (sizeof gdt) - 1;
* (u32_t *) dtp->base = vir2phys(gdt);
dtp= (struct desctableptr_s *) &gdt[IDT_INDEX];
* (u16_t *) dtp->limit = (sizeof idt) - 1;
* (u32_t *) dtp->base = vir2phys(idt);
/* Build segment descriptors for tasks and interrupt handlers. */
init_codeseg(&gdt[CS_INDEX], code_base, code_bytes, INTR_PRIVILEGE);
init_dataseg(&gdt[DS_INDEX], data_base, data_bytes, INTR_PRIVILEGE);
init_dataseg(&gdt[ES_INDEX], 0L, 0, TASK_PRIVILEGE);
/* Build scratch descriptors for functions in klib88. */
init_dataseg(&gdt[DS_286_INDEX], 0L, 0, TASK_PRIVILEGE);
init_dataseg(&gdt[ES_286_INDEX], 0L, 0, TASK_PRIVILEGE);
/* Build local descriptors in GDT for LDT's in process table.
* The LDT's are allocated at compile time in the process table, and
* initialized whenever a process' map is initialized or changed.
*/
for (rp = BEG_PROC_ADDR, ldt_index = FIRST_LDT_INDEX;
rp < END_PROC_ADDR; ++rp, ldt_index++) {
init_dataseg(&gdt[ldt_index], vir2phys(rp->p_ldt),
sizeof(rp->p_ldt), INTR_PRIVILEGE);
gdt[ldt_index].access = PRESENT | LDT;
rp->p_ldt_sel = ldt_index * DESC_SIZE;
}
/* Build main TSS.
* This is used only to record the stack pointer to be used after an
* interrupt.
* The pointer is set up so that an interrupt automatically saves the
* current process's registers ip:cs:f:sp:ss in the correct slots in the
* process table.
*/
tss.ss0 = DS_SELECTOR;
init_dataseg(&gdt[TSS_INDEX], vir2phys(&tss), sizeof(tss), INTR_PRIVILEGE);
gdt[TSS_INDEX].access = PRESENT | (INTR_PRIVILEGE << DPL_SHIFT) | TSS_TYPE;
/* Build descriptors for interrupt gates in IDT. */
for (gtp = &gate_table[0];
gtp < &gate_table[sizeof gate_table / sizeof gate_table[0]]; ++gtp) {
int_gate(gtp->vec_nr, (vir_bytes) gtp->gate,
PRESENT | INT_GATE_TYPE | (gtp->privilege << DPL_SHIFT));
}
#if _WORD_SIZE == 4
/* Complete building of main TSS. */
tss.iobase = sizeof tss; /* empty i/o permissions map */
#endif
}
/*=========================================================================*
* init_codeseg *
*=========================================================================*/
PUBLIC void init_codeseg(segdp, base, size, privilege)
register struct segdesc_s *segdp;
phys_bytes base;
vir_bytes size;
int privilege;
{
/* Build descriptor for a code segment. */
sdesc(segdp, base, size);
segdp->access = (privilege << DPL_SHIFT)
| (PRESENT | SEGMENT | EXECUTABLE | READABLE);
/* CONFORMING = 0, ACCESSED = 0 */
}
/*=========================================================================*
* init_dataseg *
*=========================================================================*/
PUBLIC void init_dataseg(segdp, base, size, privilege)
register struct segdesc_s *segdp;
phys_bytes base;
vir_bytes size;
int privilege;
{
/* Build descriptor for a data segment. */
sdesc(segdp, base, size);
segdp->access = (privilege << DPL_SHIFT) | (PRESENT | SEGMENT | WRITEABLE);
/* EXECUTABLE = 0, EXPAND_DOWN = 0, ACCESSED = 0 */
}
/*=========================================================================*
* sdesc *
*=========================================================================*/
PRIVATE void sdesc(segdp, base, size)
register struct segdesc_s *segdp;
phys_bytes base;
vir_bytes size;
{
/* Fill in the size fields (base, limit and granularity) of a descriptor. */
segdp->base_low = base;
segdp->base_middle = base >> BASE_MIDDLE_SHIFT;
segdp->base_high = base >> BASE_HIGH_SHIFT;
#if _WORD_SIZE == 4
--size; /* convert to a limit, 0 size means 4G */
if (size > BYTE_GRAN_MAX) {
segdp->limit_low = size >> PAGE_GRAN_SHIFT;
segdp->granularity = GRANULAR | (size >>
(PAGE_GRAN_SHIFT + GRANULARITY_SHIFT));
} else {
segdp->limit_low = size;
segdp->granularity = size >> GRANULARITY_SHIFT;
}
segdp->granularity |= DEFAULT; /* means BIG for data seg */
#else
segdp->limit_low = size - 1;
#endif
}
/*=========================================================================*
* seg2phys *
*=========================================================================*/
PUBLIC phys_bytes seg2phys(seg)
U16_t seg;
{
/* Return the base address of a segment, with seg being either a 8086 segment
* register, or a 286/386 segment selector.
*/
phys_bytes base;
struct segdesc_s *segdp;
if (!protected_mode) {
base = hclick_to_physb(seg);
} else {
segdp = &gdt[seg >> 3];
base = ((u32_t) segdp->base_low << 0)
| ((u32_t) segdp->base_middle << 16)
| ((u32_t) segdp->base_high << 24);
}
return base;
}
/*=========================================================================*
* phys2seg *
*=========================================================================*/
PUBLIC void phys2seg(seg, off, phys)
u16_t *seg;
vir_bytes *off;
phys_bytes phys;
{
/* Return a segment selector and offset that can be used to reach a physical
* address, for use by a driver doing memory I/O in the A0000 - DFFFF range.
*/
#if _WORD_SIZE == 2
if (!protected_mode) {
*seg = phys / HCLICK_SIZE;
*off = phys % HCLICK_SIZE;
} else {
unsigned bank = phys >> 16;
unsigned index = bank - 0xA + A_INDEX;
init_dataseg(&gdt[index], (phys_bytes) bank << 16, 0, TASK_PRIVILEGE);
*seg = (index * 0x08) | TASK_PRIVILEGE;
*off = phys & 0xFFFF;
}
#else
*seg = FLAT_DS_SELECTOR;
*off = phys;
#endif
}
/*=========================================================================*
* int_gate *
*=========================================================================*/
PRIVATE void int_gate(vec_nr, offset, dpl_type)
unsigned vec_nr;
vir_bytes offset;
unsigned dpl_type;
{
/* Build descriptor for an interrupt gate. */
register struct gatedesc_s *idp;
idp = &idt[vec_nr];
idp->offset_low = offset;
idp->selector = CS_SELECTOR;
idp->p_dpl_type = dpl_type;
#if _WORD_SIZE == 4
idp->offset_high = offset >> OFFSET_HIGH_SHIFT;
#endif
}
/*=========================================================================*
* enable_iop *
*=========================================================================*/
PUBLIC void enable_iop(pp)
struct proc *pp;
{
/* Allow a user process to use I/O instructions. Change the I/O Permission
* Level bits in the psw. These specify least-privileged Current Permission
* Level allowed to execute I/O instructions. Users and servers have CPL 3.
* You can't have less privilege than that. Kernel has CPL 0, tasks CPL 1.
*/
pp->p_reg.psw |= 0x3000;
}

124
kernel/protect.h Executable file
View File

@@ -0,0 +1,124 @@
/* Constants for protected mode. */
/* Table sizes. */
#define GDT_SIZE (FIRST_LDT_INDEX + NR_TASKS + NR_PROCS)
/* spec. and LDT's */
#define IDT_SIZE (IRQ8_VECTOR + 8) /* only up to the highest vector */
#define LDT_SIZE 4 /* contains CS, DS and two extras */
/* Fixed global descriptors. 1 to 7 are prescribed by the BIOS. */
#define GDT_INDEX 1 /* GDT descriptor */
#define IDT_INDEX 2 /* IDT descriptor */
#define DS_INDEX 3 /* kernel DS */
#define ES_INDEX 4 /* kernel ES (386: flag 4 Gb at startup) */
#define SS_INDEX 5 /* kernel SS (386: monitor SS at startup) */
#define CS_INDEX 6 /* kernel CS */
#define MON_CS_INDEX 7 /* temp for BIOS (386: monitor CS at startup) */
#define TSS_INDEX 8 /* kernel TSS */
#define DS_286_INDEX 9 /* scratch 16-bit source segment */
#define ES_286_INDEX 10 /* scratch 16-bit destination segment */
#define A_INDEX 11 /* 64K memory segment at A0000 */
#define B_INDEX 12 /* 64K memory segment at B0000 */
#define C_INDEX 13 /* 64K memory segment at C0000 */
#define D_INDEX 14 /* 64K memory segment at D0000 */
#define FIRST_LDT_INDEX 15 /* rest of descriptors are LDT's */
#define GDT_SELECTOR 0x08 /* (GDT_INDEX * DESC_SIZE) bad for asld */
#define IDT_SELECTOR 0x10 /* (IDT_INDEX * DESC_SIZE) */
#define DS_SELECTOR 0x18 /* (DS_INDEX * DESC_SIZE) */
#define ES_SELECTOR 0x20 /* (ES_INDEX * DESC_SIZE) */
#define FLAT_DS_SELECTOR 0x21 /* less privileged ES */
#define SS_SELECTOR 0x28 /* (SS_INDEX * DESC_SIZE) */
#define CS_SELECTOR 0x30 /* (CS_INDEX * DESC_SIZE) */
#define MON_CS_SELECTOR 0x38 /* (MON_CS_INDEX * DESC_SIZE) */
#define TSS_SELECTOR 0x40 /* (TSS_INDEX * DESC_SIZE) */
#define DS_286_SELECTOR 0x49 /* (DS_286_INDEX*DESC_SIZE + TASK_PRIVILEGE) */
#define ES_286_SELECTOR 0x51 /* (ES_286_INDEX*DESC_SIZE + TASK_PRIVILEGE) */
/* Fixed local descriptors. */
#define CS_LDT_INDEX 0 /* process CS */
#define DS_LDT_INDEX 1 /* process DS=ES=FS=GS=SS */
#define EXTRA_LDT_INDEX 2 /* first of the extra LDT entries */
/* Privileges. */
#define INTR_PRIVILEGE 0 /* kernel and interrupt handlers */
#define TASK_PRIVILEGE 1 /* kernel tasks */
#define USER_PRIVILEGE 3 /* servers and user processes */
/* 286 hardware constants. */
/* Exception vector numbers. */
#define BOUNDS_VECTOR 5 /* bounds check failed */
#define INVAL_OP_VECTOR 6 /* invalid opcode */
#define COPROC_NOT_VECTOR 7 /* coprocessor not available */
#define DOUBLE_FAULT_VECTOR 8
#define COPROC_SEG_VECTOR 9 /* coprocessor segment overrun */
#define INVAL_TSS_VECTOR 10 /* invalid TSS */
#define SEG_NOT_VECTOR 11 /* segment not present */
#define STACK_FAULT_VECTOR 12 /* stack exception */
#define PROTECTION_VECTOR 13 /* general protection */
/* Selector bits. */
#define TI 0x04 /* table indicator */
#define RPL 0x03 /* requester privilege level */
/* Descriptor structure offsets. */
#define DESC_BASE 2 /* to base_low */
#define DESC_BASE_MIDDLE 4 /* to base_middle */
#define DESC_ACCESS 5 /* to access byte */
#define DESC_SIZE 8 /* sizeof (struct segdesc_s) */
/* Base and limit sizes and shifts. */
#define BASE_MIDDLE_SHIFT 16 /* shift for base --> base_middle */
/* Access-byte and type-byte bits. */
#define PRESENT 0x80 /* set for descriptor present */
#define DPL 0x60 /* descriptor privilege level mask */
#define DPL_SHIFT 5
#define SEGMENT 0x10 /* set for segment-type descriptors */
/* Access-byte bits. */
#define EXECUTABLE 0x08 /* set for executable segment */
#define CONFORMING 0x04 /* set for conforming segment if executable */
#define EXPAND_DOWN 0x04 /* set for expand-down segment if !executable*/
#define READABLE 0x02 /* set for readable segment if executable */
#define WRITEABLE 0x02 /* set for writeable segment if !executable */
#define TSS_BUSY 0x02 /* set if TSS descriptor is busy */
#define ACCESSED 0x01 /* set if segment accessed */
/* Special descriptor types. */
#define AVL_286_TSS 1 /* available 286 TSS */
#define LDT 2 /* local descriptor table */
#define BUSY_286_TSS 3 /* set transparently to the software */
#define CALL_286_GATE 4 /* not used */
#define TASK_GATE 5 /* only used by debugger */
#define INT_286_GATE 6 /* interrupt gate, used for all vectors */
#define TRAP_286_GATE 7 /* not used */
/* Extra 386 hardware constants. */
/* Exception vector numbers. */
#define PAGE_FAULT_VECTOR 14
#define COPROC_ERR_VECTOR 16 /* coprocessor error */
/* Descriptor structure offsets. */
#define DESC_GRANULARITY 6 /* to granularity byte */
#define DESC_BASE_HIGH 7 /* to base_high */
/* Base and limit sizes and shifts. */
#define BASE_HIGH_SHIFT 24 /* shift for base --> base_high */
#define BYTE_GRAN_MAX 0xFFFFFL /* maximum size for byte granular segment */
#define GRANULARITY_SHIFT 16 /* shift for limit --> granularity */
#define OFFSET_HIGH_SHIFT 16 /* shift for (gate) offset --> offset_high */
#define PAGE_GRAN_SHIFT 12 /* extra shift for page granular limits */
/* Type-byte bits. */
#define DESC_386_BIT 0x08 /* 386 types are obtained by ORing with this */
/* LDT's and TASK_GATE's don't need it */
/* Granularity byte. */
#define GRANULAR 0x80 /* set for 4K granularilty */
#define DEFAULT 0x40 /* set for 32-bit defaults (executable seg) */
#define BIG 0x40 /* set for "BIG" (expand-down seg) */
#define AVL 0x10 /* 0 for available */
#define LIMIT_HIGH 0x0F /* mask for high bits of limit */

213
kernel/proto.h Executable file
View File

@@ -0,0 +1,213 @@
/* Function prototypes. */
#ifndef PROTO_H
#define PROTO_H
/* Struct declarations. */
#if TEMP_CODE
struct dpeth;
#endif
struct proc;
struct time_info;
struct timer;
/* dummy.c */
_PROTOTYPE( void dummy_task, (void) );
/* clock.c */
_PROTOTYPE( void clock_task, (void) );
_PROTOTYPE( void clock_stop, (void) );
_PROTOTYPE( clock_t get_uptime, (void) );
_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( int katoi, (register const char *s));
_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( size_t kstrlen, (const char *s));
_PROTOTYPE( int kstrncmp,
(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) );
/* kprintf.c */
#define NO_ARG 0
#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) );
_PROTOTYPE( void shutdown, (struct timer *tp) );
/* memory.c */
_PROTOTYPE( void mem_init, (void) );
_PROTOTYPE( void alloc_segments, (struct proc *rp) );
/* misc.c */
_PROTOTYPE( void panic, (_CONST char *s, int n) );
#if TEMP_CODE
#if ENABLE_PCI
/* pci.c */
_PROTOTYPE( void pci_init, (void) );
_PROTOTYPE( int pci_find_dev, (U8_t bus, U8_t dev, U8_t func,
int *devindp) );
_PROTOTYPE( int pci_first_dev, (int *devindp, u16_t *vidp, u16_t *didp) );
_PROTOTYPE( int pci_next_dev, (int *devindp, u16_t *vidp, u16_t *didp) );
_PROTOTYPE( void pci_reserve, (int devind) );
_PROTOTYPE( void pci_ids, (int devind, u16_t *vidp, u16_t *didp) );
_PROTOTYPE( char *pci_slot_name, (int devind) );
_PROTOTYPE( char *pci_dev_name, (U16_t vid, U16_t did) );
_PROTOTYPE( u8_t pci_attr_r8, (int devind, int port) );
_PROTOTYPE( u16_t pci_attr_r16, (int devind, int port) );
_PROTOTYPE( u32_t pci_attr_r32, (int devind, int port) );
_PROTOTYPE( void pci_attr_w16, (int devind, int port, U16_t value) );
_PROTOTYPE( void pci_attr_w32, (int devind, int port, u32_t value) );
/* rtl8029.c */
_PROTOTYPE( int rtl_probe, (struct dpeth *dep) );
#endif /* ENABLE_PCI */
/* rtl8139.c */
_PROTOTYPE( void rtl8139_task, (void) );
#endif /* TEMP_CODE */
/* proc.c */
_PROTOTYPE( int sys_call, (int function, int src_dest, message *m_ptr) );
_PROTOTYPE( void notify, (int proc_nr, int notify_type) );
_PROTOTYPE( void unhold, (void) );
_PROTOTYPE( void lock_pick_proc, (void) );
_PROTOTYPE( void lock_ready, (struct proc *rp) );
_PROTOTYPE( void lock_sched, (void) );
_PROTOTYPE( void lock_unready, (struct proc *rp) );
/* sb16_dsp.c, sb16_mixer.c */
_PROTOTYPE( void sb16dsp_task, (void) );
_PROTOTYPE( void sb16mix_task, (void) );
/* start.c */
_PROTOTYPE( void cstart, (U16_t cs, U16_t ds, U16_t mds,
U16_t parmoff, U16_t parmsize) );
_PROTOTYPE( char *getkenv, (_CONST char *key) );
/* system.c */
_PROTOTYPE( void cause_sig, (int proc_nr, int sig_nr) );
_PROTOTYPE( void clear_proc, (int proc_nr) );
_PROTOTYPE( phys_bytes numap_local, (int proc_nr, vir_bytes vir_addr,
vir_bytes bytes) );
_PROTOTYPE( void sys_task, (void) );
_PROTOTYPE( int virtual_copy, (struct vir_addr *src, struct vir_addr *dst,
vir_bytes bytes) );
_PROTOTYPE( phys_bytes umap_local, (struct proc *rp, int seg,
vir_bytes vir_addr, vir_bytes bytes) );
_PROTOTYPE( phys_bytes umap_remote, (struct proc *rp, int seg,
vir_bytes vir_addr, vir_bytes bytes) );
_PROTOTYPE( phys_bytes umap_bios, (struct proc *rp, vir_bytes vir_addr,
vir_bytes bytes) );
_PROTOTYPE( int vir_copy, (int src_proc, vir_bytes src_vir,
int dst_proc, vir_bytes dst_vir, vir_bytes bytes) );
_PROTOTYPE( int generic_handler, (irq_hook_t *hook) );
_PROTOTYPE( void timed_interrupt, (struct timer *tp) );
/* table.c */
_PROTOTYPE( void mapdrivers, (void) );
#if (CHIP == INTEL)
/* exception.c */
_PROTOTYPE( void exception, (unsigned vec_nr) );
/* i8259.c */
_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) );
/* klib*.s */
_PROTOTYPE( void int86, (void) );
_PROTOTYPE( void cp_mess, (int src,phys_clicks src_clicks,vir_bytes src_offset,
phys_clicks dst_clicks, vir_bytes dst_offset) );
_PROTOTYPE( void enable_irq, (irq_hook_t *hook) );
_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_insb, (Port_t port, phys_bytes buf, size_t count) );
_PROTOTYPE( void phys_insw, (Port_t port, phys_bytes buf, size_t count) );
_PROTOTYPE( void phys_outsb, (Port_t port, phys_bytes buf, size_t count));
_PROTOTYPE( void phys_outsw, (Port_t port, phys_bytes buf, size_t count));
_PROTOTYPE( void reset, (void) );
_PROTOTYPE( void level0, (void (*func)(void)) );
_PROTOTYPE( void monitor, (void) );
/* mpx*.s */
_PROTOTYPE( void idle_task, (void) );
_PROTOTYPE( void restart, (void) );
/* The following are never called from C (pure asm procs). */
/* Exception handlers (real or protected mode), in numerical order. */
void _PROTOTYPE( int00, (void) ), _PROTOTYPE( divide_error, (void) );
void _PROTOTYPE( int01, (void) ), _PROTOTYPE( single_step_exception, (void) );
void _PROTOTYPE( int02, (void) ), _PROTOTYPE( nmi, (void) );
void _PROTOTYPE( int03, (void) ), _PROTOTYPE( breakpoint_exception, (void) );
void _PROTOTYPE( int04, (void) ), _PROTOTYPE( overflow, (void) );
void _PROTOTYPE( int05, (void) ), _PROTOTYPE( bounds_check, (void) );
void _PROTOTYPE( int06, (void) ), _PROTOTYPE( inval_opcode, (void) );
void _PROTOTYPE( int07, (void) ), _PROTOTYPE( copr_not_available, (void) );
void _PROTOTYPE( double_fault, (void) );
void _PROTOTYPE( copr_seg_overrun, (void) );
void _PROTOTYPE( inval_tss, (void) );
void _PROTOTYPE( segment_not_present, (void) );
void _PROTOTYPE( stack_exception, (void) );
void _PROTOTYPE( general_protection, (void) );
void _PROTOTYPE( page_fault, (void) );
void _PROTOTYPE( copr_error, (void) );
/* Hardware interrupt handlers. */
_PROTOTYPE( void hwint00, (void) );
_PROTOTYPE( void hwint01, (void) );
_PROTOTYPE( void hwint02, (void) );
_PROTOTYPE( void hwint03, (void) );
_PROTOTYPE( void hwint04, (void) );
_PROTOTYPE( void hwint05, (void) );
_PROTOTYPE( void hwint06, (void) );
_PROTOTYPE( void hwint07, (void) );
_PROTOTYPE( void hwint08, (void) );
_PROTOTYPE( void hwint09, (void) );
_PROTOTYPE( void hwint10, (void) );
_PROTOTYPE( void hwint11, (void) );
_PROTOTYPE( void hwint12, (void) );
_PROTOTYPE( void hwint13, (void) );
_PROTOTYPE( void hwint14, (void) );
_PROTOTYPE( void hwint15, (void) );
/* Software interrupt handlers, in numerical order. */
_PROTOTYPE( void trp, (void) );
_PROTOTYPE( void s_call, (void) ), _PROTOTYPE( p_s_call, (void) );
_PROTOTYPE( void level0_call, (void) );
/* protect.c */
_PROTOTYPE( void prot_init, (void) );
_PROTOTYPE( void init_codeseg, (struct segdesc_s *segdp, phys_bytes base,
vir_bytes size, int privilege) );
_PROTOTYPE( void init_dataseg, (struct segdesc_s *segdp, phys_bytes base,
vir_bytes size, int privilege) );
_PROTOTYPE( phys_bytes seg2phys, (U16_t seg) );
_PROTOTYPE( void phys2seg, (u16_t *seg, vir_bytes *off, phys_bytes phys));
_PROTOTYPE( void enable_iop, (struct proc *pp) );
#endif /* (CHIP == INTEL) */
#if (CHIP == M68000)
/* M68000 specific prototypes go here. */
#endif /* (CHIP == M68000) */
#endif /* PROTO_H */

2546
kernel/rtl8139.c Executable file

File diff suppressed because it is too large Load Diff

430
kernel/rtl8139.h Executable file
View File

@@ -0,0 +1,430 @@
/*
ibm/rtl8139.h
Created: Aug 2003 by Philip Homburg <philip@cs.vu.nl>
*/
#define RL_IDR 0x00 /* Ethernet address
* Note: RL_9346CR_EEM_CONFIG mode is
* required the change the ethernet
* address.
* Note: 4-byte write access only.
*/
#define RL_N_TX 4 /* Number of transmit buffers */
#define RL_TSD0 0x010 /* Transmit Status of Descriptor 0 */
#define RL_TSD_CRS 0x80000000 /* Carrier Sense Lost */
#define RL_TSD_TABT 0x40000000 /* Transmit Abort */
#define RL_TSD_OWC 0x20000000 /* Out of Window Collision */
#define RL_TSD_CDH 0x10000000 /* CD Heart Beat */
#define RL_TSD_NCC_M 0x0F000000 /* Number of Collision Count */
#define RL_TSD_RES 0x00C00000 /* Reserved */
#define RL_TSD_ERTXTH_M 0x003F0000 /* Early Tx Threshold */
#define RL_TSD_ERTXTH_S 16 /* shift */
#define RL_TSD_ERTXTH_8 0x00000000 /* 8 bytes */
#define RL_TSD_TOK 0x00008000 /* Transmit OK */
#define RL_TSD_TUN 0x00004000 /* Transmit FIFO Underrun */
#define RL_TSD_OWN 0x00002000 /* Controller (does not) Own Buf. */
#define RL_TSD_SIZE 0x00001FFF /* Descriptor Size */
#define RL_TSAD0 0x20 /* Transmit Start Address of Descriptor 0 */
#define RL_RBSTART 0x30 /* Receive Buffer Start Address */
#define RL_CR 0x37 /* Command Register */
#define RL_CR_RES0 0xE0 /* Reserved */
#define RL_CR_RST 0x10 /* Reset */
#define RL_CR_RE 0x08 /* Receiver Enable */
#define RL_CR_TE 0x04 /* Transmitter Enable *
* Note: start with transmit buffer
* 0 after RL_CR_TE has been reset.
*/
#define RL_CR_RES1 0x02 /* Reserved */
#define RL_CR_BUFE 0x01 /* Receive Buffer Empty */
#define RL_CAPR 0x38 /* Current Address of Packet Read */
#define RL_CAPR_DATA_OFF 0x10 /* Packet Starts at Offset */
#define RL_CBR 0x3A /* Current Buffer Address */
#define RL_IMR 0x3C /* Interrupt Mask Register */
#define RL_IMR_SERR 0x8000 /* System Error */
#define RL_IMR_TIMEOUT 0x4000 /* Time Out */
#define RL_IMR_LENCHG 0x2000 /* Cable Length Change */
#define RL_IMR_RES 0x1F80 /* Reserved */
#define RL_IMR_FOVW 0x0040 /* Rx FIFO Overflow */
#define RL_IMR_PUN 0x0020 /* Packet Underrun / Link Change */
#define RL_IMR_RXOVW 0x0010 /* Rx Buffer Overflow */
#define RL_IMR_TER 0x0008 /* Transmit Error */
#define RL_IMR_TOK 0x0004 /* Transmit OK */
#define RL_IMR_RER 0x0002 /* Receive Error */
#define RL_IMR_ROK 0x0001 /* Receive OK */
#define RL_ISR 0x3E /* Interrupt Status Register */
#define RL_ISR_SERR 0x8000 /* System Error */
#define RL_ISR_TIMEOUT 0x4000 /* Time Out */
#define RL_ISR_LENCHG 0x2000 /* Cable Length Change */
#define RL_ISR_RES 0x1F80 /* Reserved */
#define RL_ISR_FOVW 0x0040 /* Rx FIFO Overflow */
#define RL_ISR_PUN 0x0020 /* Packet Underrun / Link Change */
#define RL_ISR_RXOVW 0x0010 /* Rx Buffer Overflow */
#define RL_ISR_TER 0x0008 /* Transmit Error */
#define RL_ISR_TOK 0x0004 /* Transmit OK */
#define RL_ISR_RER 0x0002 /* Receive Error */
#define RL_ISR_ROK 0x0001 /* Receive OK */
#define RL_TCR 0x40 /* Transmit Configuration Register
* Note: RL_CR_TE has to be set to
* set/change RL_TCR.
*/
#define RL_TCR_RES0 0x80000000 /* Reserved */
#define RL_TCR_HWVER_AM 0x7C000000 /* Hardware Version ID A */
#define RL_TCR_IFG_M 0x03000000 /* Interframe Gap Time */
#define RL_TCR_IFG_STD 0x03000000 /* IEEE 802.3 std */
#if 0
#undef RL_TCR_IFG_STD
#define RL_TCR_IFG_STD 0x00000000
#endif
#define RL_TCR_HWVER_BM 0x00C00000 /* Hardware Version ID B */
#define RL_TCR_HWVER_RTL8139 0x60000000 /* RTL8139 */
#define RL_TCR_HWVER_RTL8139A 0x70000000 /* RTL8139A */
#define RL_TCR_HWVER_RTL8139AG 0x74000000 /* RTL8139A-G */
#define RL_TCR_HWVER_RTL8139B 0x78000000 /* RTL8139B */
#define RL_TCR_HWVER_RTL8130 0x78000000 /* RTL8130 (dup) */
#define RL_TCR_HWVER_RTL8139C 0x74000000 /* RTL8139C (dup) */
#define RL_TCR_HWVER_RTL8100 0x78800000 /* RTL8100 */
#define RL_TCR_HWVER_RTL8100B 0x74400000 /* RTL8100B /
RTL8139D */
#define RL_TCR_HWVER_RTL8139CP 0x74800000 /* RTL8139C+ */
#define RL_TCR_HWVER_RTL8101 0x74C00000 /* RTL8101 */
#define RL_TCR_RES1 0x00380000 /* Reserved */
#define RL_TCR_LBK_M 0x00060000 /* Loopback Test */
#define RL_TCR_LBK_NORMAL 0x00000000 /* Normal */
#define RL_TCR_LBK_LOOKBOCK 0x00060000 /* Loopback Mode */
#define RL_TCR_CRC 0x00010000 /* (Do not) Append CRC */
#define RL_TCR_RES2 0x0000F800 /* Reserved */
#define RL_TCR_MXDMA_M 0x00000700 /* Max DMA Burst Size Tx */
#define RL_TCR_MXDMA_16 0x00000000 /* 16 bytes */
#define RL_TCR_MXDMA_32 0x00000100 /* 32 bytes */
#define RL_TCR_MXDMA_64 0x00000200 /* 64 bytes */
#define RL_TCR_MXDMA_128 0x00000300 /* 128 bytes */
#define RL_TCR_MXDMA_128 0x00000300 /* 128 bytes */
#define RL_TCR_MXDMA_256 0x00000400 /* 256 bytes */
#define RL_TCR_MXDMA_512 0x00000500 /* 512 bytes */
#define RL_TCR_MXDMA_1024 0x00000600 /* 1024 bytes */
#define RL_TCR_MXDMA_2048 0x00000700 /* 2048 bytes */
#define RL_TCR_TXRR_M 0x000000F0 /* Tx Retry Count */
#define RL_TCR_RES3 0x0000000E /* Reserved */
#define RL_TCR_CLRABT 0x00000001 /* Clear Abort */
#define RL_RCR 0x44 /* Receive Configuration Register
* Note: RL_CR_RE has to be set to
* set/change RL_RCR.
*/
#define RL_RCR_RES0 0xF0000000 /& Reserved */
#define RL_RCR_ERTH_M 0x0F000000 /* Early Rx Threshold */
#define RL_RCR_ERTH_0 0x00000000 /* No threshold */
#define RL_RCR_ERTH_1 0x01000000 /* 1/16 */
#define RL_RCR_ERTH_2 0x02000000 /* 2/16 */
#define RL_RCR_ERTH_3 0x03000000 /* 3/16 */
#define RL_RCR_ERTH_4 0x04000000 /* 4/16 */
#define RL_RCR_ERTH_5 0x05000000 /* 5/16 */
#define RL_RCR_ERTH_6 0x06000000 /* 6/16 */
#define RL_RCR_ERTH_7 0x07000000 /* 7/16 */
#define RL_RCR_ERTH_8 0x08000000 /* 8/16 */
#define RL_RCR_ERTH_9 0x09000000 /* 9/16 */
#define RL_RCR_ERTH_10 0x0A000000 /* 10/16 */
#define RL_RCR_ERTH_11 0x0B000000 /* 11/16 */
#define RL_RCR_ERTH_12 0x0C000000 /* 12/16 */
#define RL_RCR_ERTH_13 0x0D000000 /* 13/16 */
#define RL_RCR_ERTH_14 0x0E000000 /* 14/16 */
#define RL_RCR_ERTH_15 0x0F000000 /* 15/16 */
#define RL_RCR_RES1 0x00FC0000 /* Reserved */
#define RL_RCR_MULERINT 0x00020000 /* Multiple Early Int Select */
#define RL_RCR_RER8 0x00010000 /* Receive small error packet */
#define RL_RCR_RXFTH_M 0x0000E000 /* Rx FIFO Threshold */
#define RL_RCR_RXFTH_16 0x00000000 /* 16 bytes */
#define RL_RCR_RXFTH_32 0x00002000 /* 32 bytes */
#define RL_RCR_RXFTH_64 0x00004000 /* 64 bytes */
#define RL_RCR_RXFTH_128 0x00006000 /* 128 bytes */
#define RL_RCR_RXFTH_256 0x00008000 /* 256 bytes */
#define RL_RCR_RXFTH_512 0x0000A000 /* 512 bytes */
#define RL_RCR_RXFTH_1024 0x0000C000 /* 1024 bytes */
#define RL_RCR_RXFTH_UNLIM 0x0000E000 /* unlimited */
#define RL_RCR_RBLEM_M 0x00001800 /* Rx Buffer Length */
#define RL_RCR_RBLEN_8K 0x00000000 /* 8KB + 16 bytes */
#define RL_RCR_RBLEN_8K_SIZE (8*1024)
#define RL_RCR_RBLEN_16K 0x00000800 /* 16KB + 16 bytes */
#define RL_RCR_RBLEN_16K_SIZE (16*1024)
#define RL_RCR_RBLEN_32K 0x00001000 /* 32KB + 16 bytes */
#define RL_RCR_RBLEN_32K_SIZE (32*1024)
#define RL_RCR_RBLEN_64K 0x00001800 /* 64KB + 16 bytes */
#define RL_RCR_RBLEN_64K_SIZE (64*1024)
/* Note: the documentation for the RTL8139C(L) or
* for the RTL8139D(L) claims that the buffer should
* be 16 bytes larger. Multiples of 8KB are the
* correct values.
*/
#define RL_RCR_MXDMA_M 0x00000700 /* Rx DMA burst size */
#define RL_RCR_MXDMA_16 0x00000000 /* 16 bytes */
#define RL_RCR_MXDMA_32 0x00000100 /* 32 bytes */
#define RL_RCR_MXDMA_64 0x00000200 /* 64 bytes */
#define RL_RCR_MXDMA_128 0x00000300 /* 128 bytes */
#define RL_RCR_MXDMA_256 0x00000400 /* 256 bytes */
#define RL_RCR_MXDMA_512 0x00000500 /* 512 bytes */
#define RL_RCR_MXDMA_1024 0x00000600 /* 1024 bytes */
#define RL_RCR_MXDMA_UNLIM 0x00000700 /* unlimited */
#define RL_RCR_WRAP 0x00000080 /* (Do not) Wrap on receive */
#define RL_RCR_RES2 0x00000040 /* EEPROM type? */
#define RL_RCR_AER 0x00000020 /* Accept Error Packets */
#define RL_RCR_AR 0x00000010 /* Accept Runt Packets */
#define RL_RCR_AB 0x00000008 /* Accept Broadcast Packets */
#define RL_RCR_AM 0x00000004 /* Accept Multicast Packets */
#define RL_RCR_APM 0x00000002 /* Accept Physical Match Packets */
#define RL_RCR_AAP 0x00000001 /* Accept All Packets */
#define RL_MPC 0x4c /* Missed Packet Counter */
#define RL_9346CR 0x50 /* 93C46 Command Register */
#define RL_9346CR_EEM_M 0xC0 /* Operating Mode */
#define RL_9346CR_EEM_NORMAL 0x00 /* Normal Mode */
#define RL_9346CR_EEM_AUTOLOAD 0x40 /* Load from 93C46 */
#define RL_9346CR_EEM_PROG 0x80 /* 93C46 Programming */
#define RL_9346CR_EEM_CONFIG 0xC0 /* Config Write Enable */
#define RL_9346CR_RES 0x30 /* Reserved */
#define RL_9346CR_EECS 0x08 /* EECS Pin */
#define RL_9346CR_EESK 0x04 /* EESK Pin */
#define RL_9346CR_EEDI 0x02 /* EEDI Pin */
#define RL_9346CR_EEDO 0x01 /* EEDO Pin */
#define RL_CONFIG0 0x51 /* Configuration Register 0 */
#define RL_CONFIG1 0x52 /* Configuration Register 1 */
#define RL_MSR 0x58 /* Media Status Register */
#define RL_MSR_TXFCE 0x80 /* Tx Flow Control Enable */
#define RL_MSR_RXFCE 0x40 /* Rx Flow Control Enable */
#define RL_MSR_RES 0x20 /* Reserved */
#define RL_MSR_AUXSTAT 0x10 /* Aux. Power Present */
#define RL_MSR_SPEED_10 0x08 /* In 10 Mbps mode */
#define RL_MSR_LINKB 0x04 /* link Failed */
#define RL_MSR_TXPF 0x02 /* Sent Pause Packet */
#define RL_MSR_RXPF 0x01 /* Received Pause Packet */
#define RL_CONFIG3 0x59 /* Configuration Register 3 */
#define RL_CONFIG4 0x5A /* Configuration Register 4 */
/* 0x5B */ /* Reserved */
#define RL_REVID 0x5E /* PCI Revision ID */
/* 0x5F */ /* Reserved */
#define RL_TSAD 0x60 /* Transmit Status of All Descriptors */
#define RL_TSAD_TOK3 0x8000 /* TOK bit of Descriptor 3 */
#define RL_TSAD_TOK2 0x4000 /* TOK bit of Descriptor 2 */
#define RL_TSAD_TOK1 0x2000 /* TOK bit of Descriptor 1 */
#define RL_TSAD_TOK0 0x1000 /* TOK bit of Descriptor 0 */
#define RL_TSAD_TUN3 0x0800 /* TUN bit of Descriptor 3 */
#define RL_TSAD_TUN2 0x0400 /* TUN bit of Descriptor 2 */
#define RL_TSAD_TUN1 0x0200 /* TUN bit of Descriptor 1 */
#define RL_TSAD_TUN0 0x0100 /* TUN bit of Descriptor 0 */
#define RL_TSAD_TABT3 0x0080 /* TABT bit of Descriptor 3 */
#define RL_TSAD_TABT2 0x0040 /* TABT bit of Descriptor 2 */
#define RL_TSAD_TABT1 0x0020 /* TABT bit of Descriptor 1 */
#define RL_TSAD_TABT0 0x0010 /* TABT bit of Descriptor 0 */
#define RL_TSAD_OWN3 0x0008 /* OWN bit of Descriptor 3 */
#define RL_TSAD_OWN2 0x0004 /* OWN bit of Descriptor 2 */
#define RL_TSAD_OWN1 0x0002 /* OWN bit of Descriptor 1 */
#define RL_TSAD_OWN0 0x0001 /* OWN bit of Descriptor 0 */
#define RL_BMCR 0x62 /* Basic Mode Control Register (MII_CTRL) */
#define RL_BMSR 0x64 /* Basic Mode Status Register (MII_STATUS) */
#define RL_ANAR 0x66 /* Auto-Neg Advertisement Register (MII_ANA) */
#define RL_ANLPAR 0x68 /* Auto-Neg Link Partner Register (MII_ANLPA) */
#define RL_ANER 0x6a /* Auto-Neg Expansion Register (MII_ANE) */
#define RL_NWAYTR 0x70 /* N-way Test Register */
#define RL_CSCR 0x74 /* CS Configuration Register */
#define RL_CONFIG5 0xD8 /* Configuration Register 5 */
/* Status word in receive buffer */
#define RL_RXS_LEN_M 0xFFFF0000 /* Length Field, Excl. Status word */
#define RL_RXS_LEN_S 16 /* Shift For Length */
#define RL_RXS_MAR 0x00008000 /* Multicast Address Received */
#define RL_RXS_PAR 0x00004000 /* Physical Address Matched */
#define RL_RXS_BAR 0x00002000 /* Broadcast Address Received */
#define RL_RXS_RES_M 0x00001FC0 /* Reserved */
#define RL_RXS_ISE 0x00000020 /* Invalid Symbol Error */
#define RL_RXS_RUNT 0x00000010 /* Runt Packet Received */
#define RL_RXS_LONG 0x00000008 /* Long (>4KB) Packet */
#define RL_RXS_CRC 0x00000004 /* CRC Error */
#define RL_RXS_FAE 0x00000002 /* Frame Alignment Error */
#define RL_RXS_ROK 0x00000001 /* Receive OK */
/* Registers in the Machine Independent Interface (MII) to the PHY.
* IEEE 802.3 (2000 Edition) Clause 22.
*/
#define MII_CTRL 0x0 /* Control Register (basic) */
#define MII_CTRL_RST 0x8000 /* Reset PHY */
#define MII_CTRL_LB 0x4000 /* Enable Loopback Mode */
#define MII_CTRL_SP_LSB 0x2000 /* Speed Selection (LSB) */
#define MII_CTRL_ANE 0x1000 /* Auto Negotiation Enable */
#define MII_CTRL_PD 0x0800 /* Power Down */
#define MII_CTRL_ISO 0x0400 /* Isolate */
#define MII_CTRL_RAN 0x0200 /* Restart Auto-Negotiation Process */
#define MII_CTRL_DM 0x0100 /* Full Duplex */
#define MII_CTRL_CT 0x0080 /* Enable COL Signal Test */
#define MII_CTRL_SP_MSB 0x0040 /* Speed Selection (MSB) */
#define MII_CTRL_SP_10 0x0000 /* 10 Mb/s */
#define MII_CTRL_SP_100 0x2000 /* 100 Mb/s */
#define MII_CTRL_SP_1000 0x0040 /* 1000 Mb/s */
#define MII_CTRL_SP_RES 0x2040 /* Reserved */
#define MII_CTRL_RES 0x003F /* Reserved */
#define MII_STATUS 0x1 /* Status Register (basic) */
#define MII_STATUS_100T4 0x8000 /* 100Base-T4 support */
#define MII_STATUS_100XFD 0x4000 /* 100Base-X FD support */
#define MII_STATUS_100XHD 0x2000 /* 100Base-X HD support */
#define MII_STATUS_10FD 0x1000 /* 10 Mb/s FD support */
#define MII_STATUS_10HD 0x0800 /* 10 Mb/s HD support */
#define MII_STATUS_100T2FD 0x0400 /* 100Base-T2 FD support */
#define MII_STATUS_100T2HD 0x0200 /* 100Base-T2 HD support */
#define MII_STATUS_EXT_STAT 0x0100 /* Supports MII_EXT_STATUS */
#define MII_STATUS_RES 0x0080 /* Reserved */
#define MII_STATUS_MFPS 0x0040 /* MF Preamble Suppression */
#define MII_STATUS_ANC 0x0020 /* Auto-Negotiation Completed */
#define MII_STATUS_RF 0x0010 /* Remote Fault Detected */
#define MII_STATUS_ANA 0x0008 /* Auto-Negotiation Ability */
#define MII_STATUS_LS 0x0004 /* Link Up */
#define MII_STATUS_JD 0x0002 /* Jabber Condition Detected */
#define MII_STATUS_EC 0x0001 /* Ext Register Capabilities */
#define MII_PHYID_H 0x2 /* PHY ID (high) */
#define MII_PHYID_L 0x3 /* PHY ID (low) */
#define MII_ANA 0x4 /* Auto-Negotiation Advertisement */
#define MII_ANA_NP 0x8000 /* Next PAge */
#define MII_ANA_RES 0x4000 /* Reserved */
#define MII_ANA_RF 0x2000 /* Remote Fault */
#define MII_ANA_TAF_M 0x1FE0 /* Technology Ability Field */
#define MII_ANA_TAF_S 5 /* Shift */
#define MII_ANA_TAF_RES 0x1000 /* Reserved */
#define MII_ANA_PAUSE_ASYM 0x0800 /* Asym. Pause */
#define MII_ANA_PAUSE_SYM 0x0400 /* Sym. Pause */
#define MII_ANA_100T4 0x0200 /* 100Base-T4 */
#define MII_ANA_100TXFD 0x0100 /* 100Base-TX FD */
#define MII_ANA_100TXHD 0x0080 /* 100Base-TX HD */
#define MII_ANA_10TFD 0x0040 /* 10Base-T FD */
#define MII_ANA_10THD 0x0020 /* 10Base-T HD */
#define MII_ANA_SEL_M 0x001F /* Selector Field */
#define MII_ANA_SEL_802_3 0x0001 /* 802.3 */
#define MII_ANLPA 0x5 /* Auto-Neg Link Partner Ability Register */
#define MII_ANLPA_NP 0x8000 /* Next Page */
#define MII_ANLPA_ACK 0x4000 /* Acknowledge */
#define MII_ANLPA_RF 0x2000 /* Remote Fault */
#define MII_ANLPA_TAF_M 0x1FC0 /* Technology Ability Field */
#define MII_ANLPA_SEL_M 0x001F /* Selector Field */
#define MII_ANE 0x6 /* Auto-Negotiation Expansion */
#define MII_ANE_RES 0xFFE0 /* Reserved */
#define MII_ANE_PDF 0x0010 /* Parallel Detection Fault */
#define MII_ANE_LPNPA 0x0008 /* Link Partner is Next Page Able */
#define MII_ANE_NPA 0x0002 /* Local Device is Next Page Able */
#define MII_ANE_PR 0x0002 /* New Page has been received */
#define MII_ANE_LPANA 0x0001 /* Link Partner is Auto-Neg.able */
#define MII_ANNPT 0x7 /* Auto-Negotiation Next Page Transmit */
#define MII_ANLPRNP 0x8 /* Auto-Neg Link Partner Received Next Page */
#define MII_MS_CTRL 0x9 /* MASTER-SLAVE Control Register */
#define MII_MS_STATUS 0xA /* MASTER-SLAVE Status Register */
/* 0xB ... 0xE */ /* Reserved */
#define MII_EXT_STATUS 0xF /* Extended Status */
#define MII_ESTAT_1000XFD 0x8000 /* 1000Base-X Full Duplex */
#define MII_ESTAT_1000XHD 0x4000 /* 1000Base-X Half Duplex */
#define MII_ESTAT_1000TFD 0x2000 /* 1000Base-T Full Duplex */
#define MII_ESTAT_1000THD 0x1000 /* 1000Base-T Half Duplex */
#define MII_ESTAT_RES 0x0FFF /* Reserved */
/* 0x10 ... 0x1F */ /* Vendor Specific */
#if 0
34-35 R ERBCR Early Receive (Rx) Byte Count Register
36 R ERSR Early Rx Status Register
7-4 reserved
3 R ERGood Early Rx Good packet
2 R ERBad Early Rx Bad packet
1 R EROVW Early Rx OverWrite
0 R EROK Early Rx OK
51 R/W CONFIG0 Configuration Register 0
7 R SCR Scrambler Mode
6 R PCS PCS Mode
5 R T10 10 Mbps Mode
4-3 R PL[1-0] Select 10 Mbps medium type
2-0 R BS[2-0] Select Boot ROM size
52 R/W CONFIG1 Configuration Register 1
7-6 R/W LEDS[1-0] LED PIN
5 R/W DVRLOAD Driver Load
4 R/W LWACT LWAKE active mode
3 R MEMMAP Memory Mapping
2 R IOMAP I/O Mapping
1 R/W VPD Set to enable Vital Product Data
0 R/W PMEn Power Management Enable
59 R/W CONFIG3 Configuration Register 3
7 R GNTSel Gnt Select
6 R/W PARM_En Parameter Enable
5 R/W Magic Magic Packet
4 R/W LinkUp Link Up
3 reserved
2 R CLKRUN_En CLKRUN Enable
1 reserved
0 R FBtBEn Fast Back to Back Enable
5a R/W CONFIG4 Configuration Register 4
7 R/W RxFIFOAutoClr Auto Clear the Rx FIFO on overflow
6 R/W AnaOff Analog Power Off
5 R/W LongWF Long Wake-up Frame
4 R/W LWPME LANWAKE vs PMEB
3 reserved
2 R/W LWPTN LWAKE pattern
1 reserved
0 R/W PBWakeup Pre-Boot Wakeup
5c-5d R/W MULINT Multiple Interrupt Select
15-12 reserved
11-0 R/W MISR[11-0] Multiple Interrupt Select
68-69 R ANLPAR Auto-Negotiation Link Partnet Register
15 R NP Next Page bit
14 R ACK acknowledge received from link partner
13 R/W RF received remote fault detection capability
12-11 reserved
10 R Pause Flow control is supported
9 R T4 100Base-T4 is supported
8 R/W TXFD 100Base-TX full duplex is supported
7 R/W TX 100Base-TX is supported
6 R/W 10FD 10Base-T full duplex is supported
5 R/W 10 10Base-T is supported
4-0 R/W Selector Binary encoded selector
6a-6b R ANER Auto-Negotiation Expansion Register
15-5 reserved
4 R MLF Multiple link fault occured
3 R LP_NP_ABLE Link partner supports Next Page
2 R NP_ABLE Local node is able to send add. Next Pages
1 R PAGE_RX Link Code Word Page received
0 R LP_NW_ABLE Link partner supports NWay auto-negotiation
70-71 R/W NWAYTR N-way Test Register
15-8 reserved
7 R/W NWLPBK NWay loopback mode
6-4 reserved
3 R ENNWLE LED0 pin indicates linkpulse
2 R FLAGABD Auto-neg experienced ability detect state
1 R FLAGPDF Auto-neg exp. par. detection fault state
0 R FLAGLSC Auto-neg experienced link status check state
74-75 R/W CSCR CS Configuration Register
15 W Testfun Auto-neg speeds up internal timer
14-10 reserved
9 R/W LD Active low TPI link disable signal
8 R/W HEARTBEAT HEART BEAT enable
7 R/W JBEN Enable jabber function
6 R/W F_LINK_100 Force 100 Mbps
5 R/W F_Conect Bypass disconnect function
4 reserved
3 R Con_status Connected link detected
2 R/W Con_status_En Configures LED1 to indicate conn. stat.
1 reserved
0 R/W PASS_SCR Bypass scramble
76-77 reserved
78-7b R/W PHY1_PARM PHY parameter 1
7c-7f R/W TW_PARM Twister parameter
80 R/W PHY2_PARM PHY parameter 2
81-83 reserved
84-8b R/W CRC[0-7] Power Management CRC reg.[0-7] for frame[0-7]
8c-cb R/W Wakeup[0-7] Power Management wakeup frame[0-7] (64 bit)
cc-d3 R/W LSBCRC[0-7] LSB of the mask byte of makeup frame[0-7]
d4-d7 reserved
d8 R/W Config5 Configuration register 5
7 reserved
6 R/W BWF Broadcast Wakeup Frame
5 R/W MWF Multicast Wakeup Frame
4 R/W UWF Unicast Wakeup Frame
3 R/W FifoAddrPtr FIFO Address Pointer
2 R/W LDPS Link Down Power Saving mode
1 R/W LANWake LANWake Signal
0 R/W PME_STS PME_Status bit
d9-ff reserved
#endif
/*
* $PchId: rtl8139.h,v 1.1 2003/09/05 10:58:50 philip Exp $
*/

36
kernel/sconst.h Executable file
View File

@@ -0,0 +1,36 @@
! Miscellaneous constants used in assembler code.
W = _WORD_SIZE ! Machine word size.
! Offsets in struct proc. They MUST match proc.h.
P_STACKBASE = 0
#if _WORD_SIZE == 2
ESREG = P_STACKBASE
#else
GSREG = P_STACKBASE
FSREG = GSREG + 2 ! 386 introduces FS and GS segments
ESREG = FSREG + 2
#endif
DSREG = ESREG + 2
DIREG = DSREG + 2
SIREG = DIREG + W
BPREG = SIREG + W
STREG = BPREG + W ! hole for another SP
BXREG = STREG + W
DXREG = BXREG + W
CXREG = DXREG + W
AXREG = CXREG + W
RETADR = AXREG + W ! return address for save() call
PCREG = RETADR + W
CSREG = PCREG + W
PSWREG = CSREG + W
SPREG = PSWREG + W
SSREG = SPREG + W
P_STACKTOP = SSREG + W
P_LDT_SEL = P_STACKTOP
P_LDT = P_LDT_SEL + W
#if _WORD_SIZE == 2
Msize = 12 ! size of a message in 16-bit words
#else
Msize = 9 ! size of a message in 32-bit words
#endif

168
kernel/sendmask.h Normal file
View File

@@ -0,0 +1,168 @@
/* Definition of the 'p_sendmask' bit mask used in the process table. The bit
* mask of process is checked in mini_send() to see if the caller is allowed
* to send to the destination. The bit masks accomodate bits for NR_TASKS +
* (LOW_USER+1) + 1. This means that there are bits for each task, driver, and
* server process, INIT, and one bit to represent all ordinary user processes.
*
* NOTE: the send masks definitions must be updated!!!
*
* Changes:
* May 01, 2004 created and sendmask definitions (Jorrit N. Herder)
*/
#ifndef SENDMASK_H
#define SENDMASK_H
/* Define type for sendmask, if not already done. */
#include "type.h"
/* Constants to support the bitmask operations. */
#define BIT_0 (send_mask_t) 1
#define MASK_ENTRIES NR_TASKS + (LOW_USER+1) + 1
#define USER_PROC_NR LOW_USER+1 /* used to set bit for user procs */
#define ALLOW_ALL_MASK (send_mask_t) -1
#define DENY_ALL_MASK (send_mask_t) 0
/* Check if given process number is in range. */
#define isvalid(n) ((unsigned) ((n)+NR_TASKS) <= MASK_ENTRIES -1)
/* Default masks and bit operations that easily allow to construct bit masks.
* Note the one always must start with a default mask like allow_all_mask.
* From that point, one can, for example, deny several processes.
*/
#define allow_all_mask ALLOW_ALL_MASK
#define deny_all_mask DENY_ALL_MASK
#define allow(enabled,n) | (enabled << ((n) + NR_TASKS))
#define deny(enabled,n) & ~(enabled << ((n) + NR_TASKS))
#define send_mask_allow(mask,n) ((mask) |= (1 << ((n) + NR_TASKS)))
#define send_mask_deny(mask,n) ((mask) &= ~(1 << ((n) + NR_TASKS)))
/* Check if the bit for the given process number is set. */
#define isallowed(mask,n) ((mask) & (BIT_0 << ((n) + NR_TASKS)))
/* The masks below match the processes (and order) in src/kernel/table.c.
* Note that the masks are made effective the inclusion in the task table
* which is used to set up the process table on start up.
*/
#define TTY_SENDMASK \
allow_all_mask
#define DP8390_SENDMASK \
allow_all_mask
#define RTL8139_SENDMASK \
deny_all_mask \
allow(1, USER_PROC_NR) /* inet server starts as user process */ \
allow(1, TTY) /* need to register function key */ \
allow(1, SYSTASK) /* need system functionality */ \
allow(1, CLOCK) /* need clock functionality */
#define IDLE_SENDMASK \
deny_all_mask
/* The tasktab in src/kernel/table.c supports up to 4 controllers
* it is possible to define separate masks for them here, but then
* a small update in table.c is required to make them effective
*/
#define CTRLR_SENDMASK \
allow_all_mask
#define SB16DSP_SENDMASK \
allow_all_mask
#define SB16MIX_SENDMASK \
allow_all_mask
#define FLOPPY_SENDMASK \
allow_all_mask
#define CLOCK_SENDMASK \
allow_all_mask
#define SYSTEM_SENDMASK \
allow_all_mask
#define HARDWARE_SENDMASK \
allow_all_mask \
deny(1, USER_PROC_NR)
#define MM_SENDMASK \
deny_all_mask \
allow(1, IS_PROC_NR) /* output diagnostics */ \
allow(1, SYSTASK) \
allow(1, TTY) \
allow(1, CLOCK) \
allow(1, INIT_PROC_NR) \
allow(1, FS_PROC_NR) \
allow(1, USER_PROC_NR) /* reply to system calls */
#define AT_SENDMASK \
allow_all_mask
#define FS_SENDMASK \
allow_all_mask
#if 0
deny_all_mask \
allow(1, IS_PROC_NR) /* output diagnostics */ \
allow(1, SYSTASK) /* need system functionality */ \
allow(1, CLOCK) /* need clock functionality */ \
allow(1, IS_PROC_NR) /* output diagnostics */ \
allow(1, TTY) /* a.o. observe function keys */ \
allow(1, FLOPPY) \
allow(ENABLE_SB16, SB16DSP ) \
allow(ENABLE_SB16, SB16MIX ) \
allow(ENABLE_PRINTER, PRINTER ) \
allow(1, MEMORY ) \
allow((NR_CTRLRS >= 1), CTRLR(0)) \
allow((NR_CTRLRS >= 2), CTRLR(1)) \
allow((NR_CTRLRS >= 3), CTRLR(2)) \
allow((NR_CTRLRS >= 4), CTRLR(3)) \
allow(1, INIT_PROC_NR) \
allow(1, MM_PROC_NR) /* cooperates with memory manager */ \
allow(1, USER_PROC_NR) /* reply to system calls */
#endif
#define IS_SENDMASK \
allow_all_mask /* IS handles all diagnostic messages */
#if 0
deny_all_mask \
allow(1, CLOCK) /* clock delays and flag alarm needed */ \
allow(1, FS_PROC_NR) /* open /dev/mem to read CMOS clock */ \
allow(1, SYSTASK) /* copy tables from kernel space */ \
allow(1, TTY) /* request function key notifications */ \
allow(1, USER_PROC_NR) /* reply to system calls */
#endif
#define MEM_SENDMASK \
deny_all_mask \
allow(1, IS_PROC_NR) /* output diagnostics */ \
allow(1, SYSTASK) /* system functionality needed */ \
allow(1, CLOCK) /* check clock alarms */ \
allow(1, TTY) /* output diagnostics */ \
allow(1, FS_PROC_NR) /* FS is interface to the driver */
#define PRN_SENDMASK \
deny_all_mask \
allow(1, IS_PROC_NR) /* output diagnostics */ \
allow(1, SYSTASK) /* device port I/O needed */ \
allow(1, TTY) /* output diagnostics */ \
allow(1, CLOCK) /* need small delays */ \
allow(1, FS_PROC_NR) /* FS is interface to the driver */
#define INIT_SENDMASK \
deny_all_mask \
allow(1, FS_PROC_NR) /* init makes system calls to FS and MM */ \
allow(1, MM_PROC_NR)
#define USER_PROC_SENDMASK \
deny_all_mask \
allow(1, FS_PROC_NR) /* users can only make system calls */ \
allow(1, MM_PROC_NR) \
allow(1, IS_PROC_NR) \
allow(ENABLE_TASKSERVER, TS_PROC_NR)
#endif /* SENDMASK_H */

95
kernel/start.c Executable file
View File

@@ -0,0 +1,95 @@
/* This file contains the C startup code for Minix on Intel processors.
* It cooperates with mpx.s to set up a good environment for main().
*
* This code runs in real mode for a 16 bit kernel and may have to switch
* to protected mode for a 286.
*
* For a 32 bit kernel this already runs in protected mode, but the selectors
* are still those given by the BIOS with interrupts disabled, so the
* descriptors need to be reloaded and interrupt descriptors made.
*/
#include "kernel.h"
#include "protect.h"
/* Environment strings passed by loader. */
PRIVATE char k_environ[128*sizeof(char *)];
/*==========================================================================*
* cstart *
*==========================================================================*/
PUBLIC void cstart(cs, ds, mds, parmoff, parmsize)
U16_t cs, ds; /* kernel code and data segment */
U16_t mds; /* monitor data segment */
U16_t parmoff, parmsize; /* boot parameters offset and length */
{
/* Perform system initializations prior to calling main(). Most settings are
* determined with help of the environment strings passed by MINIX' loader.
*/
register char *envp;
unsigned mon_start;
/* Record where the kernel and the monitor are. */
code_base = seg2phys(cs);
data_base = seg2phys(ds);
/* Initialize protected mode descriptors. */
prot_init();
/* Copy the boot parameters to kernel memory. */
mon_params = seg2phys(mds) + parmoff;
mon_parmsize = MAX(parmsize,sizeof(k_environ));
if (parmsize > sizeof k_environ - 2) parmsize = sizeof k_environ - 2;
phys_copy(mon_params, vir2phys(k_environ), (phys_bytes) parmsize);
/* Type of VDU: */
envp = getkenv("video");
if (kstrcmp(envp, "ega") == 0) ega = TRUE;
if (kstrcmp(envp, "vga") == 0) vga = ega = TRUE;
/* Processor? */
processor = katoi(getkenv("processor")); /* 86, 186, 286, 386, ... */
/* XT, AT or MCA bus? */
envp = getkenv("bus");
if (envp == NIL_PTR || kstrcmp(envp, "at") == 0) {
pc_at = TRUE;
} else
if (kstrcmp(envp, "mca") == 0) {
pc_at = ps_mca = TRUE;
}
/* Decide if mode is protected. */
#if _WORD_SIZE == 2
protected_mode = processor >= 286;
if (!protected_mode) mon_return = 0;
#endif
/* Return to assembler code to switch to protected mode (if 286), reload
* selectors and call main().
*/
}
/*==========================================================================*
* getkenv *
*==========================================================================*/
PUBLIC char *getkenv(name)
_CONST char *name;
{
/* Get environment value - kernel version of getenv to avoid setting up the
* usual environment array.
*/
register _CONST char *namep;
register char *envp;
for (envp = k_environ; *envp != 0;) {
for (namep = name; *namep != 0 && *namep == *envp; namep++, envp++)
;
if (*namep == '\0' && *envp == '=') return(envp + 1);
while (*envp++ != 0)
;
}
return(NIL_PTR);
}

532
kernel/system.c Executable file
View File

@@ -0,0 +1,532 @@
/* This task handles the interface between the kernel and user-level servers.
* System services can be accessed by doing a system call. System calls are
* transformed into request messages, which are handled by this task. By
* convention, a sys_call() is transformed in a SYS_CALL request message that
* is handled in a function named do_call().
*
* A private call vector is used to map all system calls to the functions that
* handle them. The actual handler functions are contained in separate files
* to keep this file clean. The call vector is used in the system task's main
* loop to handle all incoming requests.
*
* In addition to the main sys_task() entry point, which starts the main loop,
* there are several other minor entry points:
* cause_sig: take action to cause a signal to occur
* clear_proc: clean up a process in the process table, e.g. on exit
* umap_local: map virtual address in LOCAL_SEG to physical
* umap_remote: map virtual address in REMOTE_SEG to physical
* umap_bios: map virtual address in BIOS_SEG to physical
* numap_local: umap_local D segment from proc nr instead of pointer
* virtual_copy: copy bytes from one virtual address to another
* vir_copy: copy bytes from one process to another
* generic_handler: interrupt handler for user-level device drivers
*
* Changes:
* Oct 29, 2004 new clear_proc() function (Jorrit N. Herder)
* Oct 17, 2004 generic handler and IRQ policies (Jorrit N. Herder)
* Oct 10, 2004 dispatch system calls from call vector (Jorrit N. Herder)
* Sep 30, 2004 source code documentation updated (Jorrit N. Herder)
* Sep 10, 2004 system call functions in library (Jorrit N. Herder)
* 2003/2004 various new syscalls (see syslib.h) (Jorrit N. Herder)
*/
#include "kernel.h"
#include "system.h"
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/sigcontext.h>
#include <sys/svrctl.h>
#include <minix/callnr.h>
#include "sendmask.h"
#if (CHIP == INTEL)
#include "protect.h"
#endif
FORWARD _PROTOTYPE( void initialize, (void));
/* Declaration of the call vector that defines the mapping of system calls to
* handler functions. The order of the do_call handler functions must match
* the SYS_CALL numbering defined in <minix/com.h>.
*/
PUBLIC _PROTOTYPE (int (*call_vec[]), (message *m_ptr) ) = {
do_times, /* 0: get uptime and process CPU time consumption */
do_xit, /* 1: informs kernel that a process has exited */
do_unused, /* 2: unused */
do_sigctl, /* 3: MM signal control (incl. POSIX style handling) */
do_fork, /* 4: informs kernel that a process has forked */
do_newmap, /* 5: allows MM to set up a process memory map */
do_copy, /* 6: copy a block of data between processes */
do_exec, /* 7: sets program counter and stack pointer after EXEC */
do_unused, /* 8: unused */
do_abort, /* 9: MM or FS cannot go on; abort MINIX */
do_kill, /* 10: cause a signal to be sent via MM */
do_umap, /* 11: compute the physical address for a virtual address */
do_unused, /* 12: returns the next free chunk of physical memory */
do_trace, /* 13: request a trace operation */
do_vcopy, /* 14: request a series of data blocks to be copied */
do_signalrm, /* 15: schedule an alarm that causes an alarm signal */
do_syncalrm, /* 16: schedule an alarm that sends a notification message */
do_flagalrm, /* 17: schedule an alarm that sets a timeout flag to 1 */
do_unused, /* 18: unused */
do_svrctl, /* 19: handles miscelleneous kernel control functions */
do_sdevio, /* 20: device I/O: phys_insb, _insw, _outsb, _outsw */
do_unused, /* 21: unused */
do_getinfo, /* 22: request some kind of system information */
do_devio, /* 23: device I/O: inb, inw, inl, outb, outw, outl */
do_vdevio, /* 24: device I/O: vector with in[b|w|l], out[b|w|l] */
do_irqctl, /* 25: request an interrupt control operation */
do_kmalloc, /* 26: request allocation of (DMA) buffer in mem chunk */
do_iopenable, /* 27: allow a user process to use I/O instructions */
do_phys2seg, /* 28: do a phys addr to segment selector/ offset conversion */
do_exit, /* 29: an server or driver requests to be aborted */
do_vircopy, /* 30: copy from process to process (virtual addressing) */
do_physcopy, /* 31: copy from anywhere to anywhere (physical addressing) */
};
/* Check if system call table is correct. This should not fail. No space is
* allocated here, because the dummy is declared extern. If the call vector
* is unbalanced, the array size will be negative and this won't compile.
*/
extern int dummy[sizeof(call_vec)==NR_SYS_CALLS*sizeof(call_vec[0]) ? 1 : -1];
/* Some system task variables. */
PRIVATE message m; /* used to receive requests */
/*===========================================================================*
* sys_task *
*===========================================================================*/
PUBLIC void sys_task()
{
/* Main entry point of sys_task. Get the message and dispatch on type. */
register int result;
/* Initialize the system task. */
initialize();
while (TRUE) {
/* Get work. */
receive(ANY, &m);
/* Handle the request. */
if ((unsigned) m.m_type < NR_SYS_CALLS) {
result = (*call_vec[m.m_type])(&m); /* do system call */
} else {
kprintf("SYS task got illegal request from %d.\n", m.m_source);
result = EBADREQUEST; /* illegal message type */
}
/* Send a reply, unless inhibited by a handler function. */
if (result != EDONTREPLY) {
m.m_type = result; /* report status of call */
send(m.m_source, &m); /* send reply to caller */
}
}
}
/*===========================================================================*
* initialize *
*===========================================================================*/
PRIVATE void initialize(void)
{
register struct proc *rp;
int i;
/* Initialize IRQ table. */
for (i=0; i<NR_IRQ_VECTORS; i++)
irqtab[i].proc_nr = NONE;
/* Initialize all alarm timers for all processes. */
for (rp=BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
tmr_inittimer(&(rp->p_signalrm));
tmr_inittimer(&(rp->p_syncalrm));
tmr_inittimer(&(rp->p_flagalrm));
}
}
/*===========================================================================*
* clear_proc *
*===========================================================================*/
PUBLIC void clear_proc(proc_nr)
int proc_nr; /* slot of process to clean up */
{
register struct proc *rp, *rc;
struct proc *np, *xp;
/* Get a pointer to the process that exited. */
rc = proc_addr(proc_nr);
/* Turn off any alarm timers at the clock. */
reset_timer(&rc->p_signalrm);
reset_timer(&rc->p_flagalrm);
reset_timer(&rc->p_syncalrm);
/* Make sure the exiting process is no longer scheduled. */
if (rc->p_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.
*/
if (rc->p_flags & SENDING) {
/* Check all proc slots to see if the exiting process is queued. */
for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
if (rp->p_callerq == NIL_PROC) continue;
if (rp->p_callerq == rc) {
/* Exiting process is on front of this queue. */
rp->p_callerq = rc->p_sendlink;
break;
} else {
/* See if exiting process is in middle of queue. */
np = rp->p_callerq;
while ( ( xp = np->p_sendlink) != NIL_PROC) {
if (xp == rc) {
np->p_sendlink = xp->p_sendlink;
break;
} else {
np = xp;
}
}
}
}
}
/* Now clean up the process table entry. Reset to defaults. */
kstrncpy(rc->p_name, "<noname>", PROC_NAME_LEN); /* unset name */
sigemptyset(&rc->p_pending); /* remove pending signals */
rc->p_pendcount = 0; /* all signals are gone */
rc->p_flags = 0; /* remove all flags */
rc->p_type = P_NONE; /* announce slot empty */
rc->p_sendmask = DENY_ALL_MASK; /* set most restrictive mask */
#if (CHIP == M68000)
pmmu_delete(rc); /* we're done, remove tables */
#endif
}
/*===========================================================================*
* generic_handler *
*===========================================================================*/
PUBLIC int generic_handler(hook)
irq_hook_t *hook;
{
/* This function handles hardware interrupt in a generic way, according to
* the policy set with SYS_IRQCTL. This is rather complicated since different
* devices require different actions. Options are (1) do nothing, (2a) read a
* port and optionally (2b) strobe the port high or (2c) low with the value
* read, or (3) write a value to a port. Finally, the policy may or may not
* reenable IRQs. A notification is sent in all cases.
*/
irq_policy_t policy = irqtab[hook->irq].policy;
int proc_nr = irqtab[hook->irq].proc_nr;
long port = irqtab[hook->irq].port;
phys_bytes addr = irqtab[hook->irq].addr;
long mask_val = irqtab[hook->irq].mask_val;
/* Read a value from the given port. Possibly also strobe the port with the
* read value. Strobe it high by using the mask provided by the caller;
* strobe it low by writing back the value we read.
*/
if (policy & (IRQ_READ_PORT|IRQ_STROBE|IRQ_ECHO_VAL)) {
switch(policy & (IRQ_BYTE|IRQ_WORD|IRQ_LONG)) {
case IRQ_BYTE: { /* byte values */
u8_t byteval = inb(port);
if (policy & IRQ_STROBE) outb(port, byteval | mask_val);
if (policy & IRQ_ECHO_VAL) outb(port, byteval);
if (policy & IRQ_READ_PORT)
phys_copy(vir2phys(&byteval), addr, sizeof(u8_t));
break;
} case IRQ_WORD: { /* word values */
u16_t wordval = inw(port);
if (policy & IRQ_STROBE) outw(port, wordval | mask_val);
if (policy & IRQ_ECHO_VAL) outw(port, wordval);
if (policy & IRQ_READ_PORT)
phys_copy(vir2phys(&wordval), addr, sizeof(u16_t));
break;
} case IRQ_LONG: { /* long values */
u32_t longval = inl(port);
if (policy & IRQ_STROBE) outl(port, longval | mask_val);
if (policy & IRQ_ECHO_VAL) outl(port, longval);
if (policy & IRQ_READ_PORT)
phys_copy(vir2phys(&longval), addr, sizeof(u32_t));
break;
} default: /* do nothing */ ; /* wrong type flags */
}
}
/* Write a value to some port. This is straightforward. Note that both
* reading and writing is not possible, hence 'else if' instead of 'if'.
*/
else if (policy & (IRQ_WRITE_PORT)) {
switch(policy & (IRQ_BYTE|IRQ_WORD|IRQ_LONG)) {
case IRQ_BYTE: outb(port, (u8_t) mask_val); break;
case IRQ_WORD: outw(port, (u16_t) mask_val); break;
case IRQ_LONG: outl(port, (u32_t) mask_val); break;
default: /* do nothing */ ; /* wrong type flags */
}
}
/* Almost done, send a HARD_INT notification to allow further processing
* and possibly reenable interrupts - this depends on the policy given.
*/
notify(proc_nr, HARD_INT);
return(policy & IRQ_REENABLE);
}
/*===========================================================================*
* cause_sig *
*===========================================================================*/
PUBLIC void cause_sig(proc_nr, sig_nr)
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:
* 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 MM. This central function handles the
* signals and makes sure the MM gets them by sending a notification. The
* process being signaled is blocked while MM has not finished all signals
* for it. These signals are counted in p_pendcount, and the SIG_PENDING
* flag is kept nonzero while there are some. It is not sufficient to ready
* the process when MM is informed, because MM can block waiting for FS to
* do a core dump.
*/
register struct proc *rp, *mmp;
rp = proc_addr(proc_nr);
if (sigismember(&rp->p_pending, sig_nr))
return; /* this signal already pending */
sigaddset(&rp->p_pending, sig_nr);
++rp->p_pendcount; /* count new signal pending */
if (rp->p_flags & PENDING)
return; /* another signal already pending */
if (rp->p_flags == 0) lock_unready(rp);
rp->p_flags |= PENDING | SIG_PENDING;
notify(MM_PROC_NR, KSIG_PENDING);
}
/*===========================================================================*
* umap_bios *
*===========================================================================*/
PUBLIC phys_bytes umap_bios(rp, vir_addr, bytes)
register struct proc *rp; /* pointer to proc table entry for process */
vir_bytes vir_addr; /* virtual address in BIOS segment */
vir_bytes bytes; /* # of bytes to be copied */
{
/* Calculate the physical memory address at the BIOS. */
phys_bytes phys_addr;
phys_addr = (phys_bytes) vir_addr; /* no check currently! */
return phys_addr;
}
/*===========================================================================*
* umap_local *
*===========================================================================*/
PUBLIC phys_bytes umap_local(rp, seg, vir_addr, bytes)
register struct proc *rp; /* pointer to proc table entry for process */
int seg; /* T, D, or S segment */
vir_bytes vir_addr; /* virtual address in bytes within the seg */
vir_bytes bytes; /* # of bytes to be copied */
{
/* Calculate the physical memory address for a given virtual address. */
vir_clicks vc; /* the virtual address in clicks */
phys_bytes pa; /* intermediate variables as phys_bytes */
#if (CHIP == INTEL)
phys_bytes seg_base;
#endif
/* If 'seg' is D it could really be S and vice versa. T really means T.
* If the virtual address falls in the gap, it causes a problem. On the
* 8088 it is probably a legal stack reference, since "stackfaults" are
* not detected by the hardware. On 8088s, the gap is called S and
* accepted, but on other machines it is called D and rejected.
* The Atari ST behaves like the 8088 in this respect.
*/
if (bytes <= 0) return( (phys_bytes) 0);
vc = (vir_addr + bytes - 1) >> CLICK_SHIFT; /* last click of data */
#if (CHIP == INTEL) || (CHIP == M68000)
if (seg != T)
seg = (vc < rp->p_memmap[D].mem_vir + rp->p_memmap[D].mem_len ? D : S);
#else
if (seg != T)
seg = (vc < rp->p_memmap[S].mem_vir ? D : S);
#endif
if((vir_addr>>CLICK_SHIFT) >= rp->p_memmap[seg].mem_vir +
rp->p_memmap[seg].mem_len) return( (phys_bytes) 0 );
#if (CHIP == INTEL)
seg_base = (phys_bytes) rp->p_memmap[seg].mem_phys;
seg_base = seg_base << CLICK_SHIFT; /* segment origin in bytes */
#endif
pa = (phys_bytes) vir_addr;
#if (CHIP != M68000)
pa -= rp->p_memmap[seg].mem_vir << CLICK_SHIFT;
return(seg_base + pa);
#endif
#if (CHIP == M68000)
pa -= (phys_bytes)rp->p_memmap[seg].mem_vir << CLICK_SHIFT;
pa += (phys_bytes)rp->p_memmap[seg].mem_phys << CLICK_SHIFT;
return(pa);
#endif
}
/*==========================================================================*
* numap_local *
*==========================================================================*/
PUBLIC phys_bytes numap_local(proc_nr, vir_addr, bytes)
int proc_nr; /* process number to be mapped */
vir_bytes vir_addr; /* virtual address in bytes within D seg */
vir_bytes bytes; /* # of bytes required in segment */
{
/* Do umap_local() starting from a process number instead of a pointer.
* This function is used by device drivers, so they need not know about the
* process table. To save time, there is no 'seg' parameter. The segment
* is always D.
*/
return(umap_local(proc_addr(proc_nr), D, vir_addr, bytes));
}
#if ENABLE_MESSAGE_STATS
/*===========================================================================*
* do_mstats *
*===========================================================================*/
PRIVATE int do_mstats(m_ptr)
message *m_ptr; /* pointer to request message */
{
int r = 0;
if(m_ptr->m1_i1 > 0) {
struct message_statentry *dest;
struct proc *p;
p = proc_addr(m_ptr->m1_i3);
dest = proc_vir2phys(p, m_ptr->m1_p1);
r = mstat_copy(dest, m_ptr->m1_i1);
}
if(m_ptr->m1_i2) {
mstat_reset();
}
return r;
}
#endif /* ENABLE_MESSAGE_STATS */
/*===========================================================================*
* umap_remote *
*===========================================================================*/
PUBLIC phys_bytes umap_remote(rp, seg, vir_addr, bytes)
register struct proc *rp; /* pointer to proc table entry for process */
int seg; /* index of remote segment */
vir_bytes vir_addr; /* virtual address in bytes within the seg */
vir_bytes bytes; /* # of bytes to be copied */
{
/* Calculate the physical memory address for a given virtual address. */
phys_bytes phys_addr;
phys_addr = (phys_bytes) 0; /* no yet supported currently! */
return phys_addr;
}
/*==========================================================================*
* virtual_copy *
*==========================================================================*/
PUBLIC int virtual_copy(src_addr, dst_addr, bytes)
struct vir_addr *src_addr; /* source virtual address */
struct vir_addr *dst_addr; /* destination virtual address */
vir_bytes bytes; /* # of bytes to copy */
{
/* Copy bytes from virtual address src_addr to virtual address dst_addr.
* Virtual addresses can be in LOCAL_SEG, REMOTE_SEG, or BIOS_SEG.
*/
struct vir_addr *vir_addr[2]; /* virtual source and destination address */
phys_bytes phys_addr[2]; /* absolute source and destination */
int seg_index;
int i;
/* Check copy count. */
if (bytes <= 0) {
kprintf("v_cp: copy count problem <= 0\n", NO_ARG);
return(EDOM);
}
/* Do some more checks and map virtual addresses to physical addresses. */
vir_addr[_SRC_] = src_addr;
vir_addr[_DST_] = dst_addr;
for (i=_SRC_; i<=_DST_; i++) {
/* Get physical address. */
switch((vir_addr[i]->segment & SEGMENT_TYPE)) {
case LOCAL_SEG:
seg_index = vir_addr[i]->segment & SEGMENT_INDEX;
phys_addr[i] = umap_local( proc_addr(vir_addr[i]->proc_nr),
seg_index, vir_addr[i]->offset, bytes );
break;
case REMOTE_SEG:
seg_index = vir_addr[i]->segment & SEGMENT_INDEX;
phys_addr[i] = umap_remote( proc_addr(vir_addr[i]->proc_nr),
seg_index, vir_addr[i]->offset, bytes );
break;
case BIOS_SEG:
phys_addr[i] = umap_bios( proc_addr(vir_addr[i]->proc_nr),
vir_addr[i]->offset, bytes );
break;
default:
kprintf("v_cp: Unknown segment type: %d\n",
vir_addr[i]->segment & SEGMENT_TYPE);
return(EINVAL);
}
/* Check if mapping succeeded. */
if (phys_addr[i] <= 0) {
kprintf("v_cp: Mapping failed ... phys <= 0\n", NO_ARG);
return(EFAULT);
}
}
/* Now copy bytes between physical addresseses. */
phys_copy(phys_addr[_SRC_], phys_addr[_DST_], (phys_bytes) bytes);
return(OK);
}
/*==========================================================================*
* vir_copy *
*==========================================================================*/
PUBLIC int vir_copy(src_proc, src_vir, dst_proc, dst_vir, bytes)
int src_proc; /* source process */
vir_bytes src_vir; /* source virtual address within D seg */
int dst_proc; /* destination process */
vir_bytes dst_vir; /* destination virtual address within D seg */
vir_bytes bytes; /* # of bytes to copy */
{
/* Copy bytes from one process to another. Meant for the easy cases, where
* speed isn't required. (One can normally do without one of the umaps.)
*/
phys_bytes src_phys, dst_phys;
src_phys = umap_local(proc_addr(src_proc), D, src_vir, bytes);
dst_phys = umap_local(proc_addr(dst_proc), D, dst_vir, bytes);
if (src_phys == 0 || dst_phys == 0) return(EFAULT);
phys_copy(src_phys, dst_phys, (phys_bytes) bytes);
return(OK);
}

67
kernel/system.h Normal file
View File

@@ -0,0 +1,67 @@
/* Function prototypes for the system library. The implementation is contained
* in src/kernel/system/. The system library allows to access system services
* by doing a system call. System calls are transformed into request messages
* to the SYS task that is responsible for handling the call. By convention, a
* sys_call() is transformed into a message with type SYS_CALL that is handled
* in a function named do_call().
*/
#ifndef SYSTEM_H
#define SYSTEM_H
/* Common includes for the system library. */
#include <minix/com.h>
#include "proc.h"
#include "assert.h"
_PROTOTYPE( int do_exec, (message *m_ptr) ); /* process control */
_PROTOTYPE( int do_fork, (message *m_ptr) );
_PROTOTYPE( int do_newmap, (message *m_ptr) );
_PROTOTYPE( int do_xit, (message *m_ptr) );
_PROTOTYPE( int do_vircopy, (message *m_ptr) ); /* copying */
_PROTOTYPE( int do_physcopy, (message *m_ptr) );
_PROTOTYPE( int do_umap, (message *m_ptr) );
_PROTOTYPE( int do_vcopy, (message *m_ptr) );
_PROTOTYPE( int do_copy, (message *m_ptr) );
_PROTOTYPE( int do_unused, (message *m_ptr) ); /* miscellaneous */
_PROTOTYPE( int do_abort, (message *m_ptr) );
_PROTOTYPE( int do_times, (message *m_ptr) );
_PROTOTYPE( int do_getinfo, (message *m_ptr) );
_PROTOTYPE( int do_exit, (message *m_ptr) ); /* server control */
_PROTOTYPE( int do_svrctl, (message *m_ptr) );
_PROTOTYPE( int do_kmalloc, (message *m_ptr) );
_PROTOTYPE( int do_iopenable, (message *m_ptr) );
_PROTOTYPE( int do_phys2seg, (message *m_ptr) );
_PROTOTYPE( int do_devio, (message *m_ptr) ); /* device I/O */
_PROTOTYPE( int do_vdevio, (message *m_ptr) );
_PROTOTYPE( int do_sdevio, (message *m_ptr) );
_PROTOTYPE( int do_irqctl, (message *m_ptr) ); /* interrupt control */
_PROTOTYPE( int do_kill, (message *m_ptr) ); /* signal handling */
_PROTOTYPE( int do_sigctl, (message *m_ptr) );
_PROTOTYPE( int do_setalarm, (message *m_ptr) ); /* alarm functions */
#define do_flagalrm do_setalarm
#define do_signalrm do_setalarm
#define do_syncalrm do_setalarm
#if ENABLE_K_TRACING
_PROTOTYPE( int do_trace, (message *m_ptr) ); /* process tracing */
#else
#define do_trace do_unused
#endif
#if ENABLE_K_DEBUGGING /* debugging */
#else
#endif
_PROTOTYPE( int do_vircopy, (message *m_ptr) );
_PROTOTYPE( int do_physcopy, (message *m_ptr) );
_PROTOTYPE( int do_biosio, (message *m_ptr) );
#endif /* SYSTEM_H */

58
kernel/system/Makefile Normal file
View File

@@ -0,0 +1,58 @@
# Makefile for system library implementation
# Directories
u = /usr
i = $u/include
s = $i/sys
h = $i/minix
m = $i/ibm
l = $u/lib
n = $i/net
g = $n/gen
x = .
k = ..
# Programs, flags, etc.
CC = exec cc
CPP = $l/cpp
LD = $(CC) -.o
CFLAGS = -I$i
LDFLAGS = -i
SYS = alarms.o copying.o debugging.o devio.o irqctl.o proctl.o \
srvrctl.o misc.o sigctl.o tracing.o \
do_copy.o do_vcopy.o
# What to make.
all build: $(SYS)
aal cr system.a $(SYS)
clean:
rm -f *.a *.o *.bak
# Dependencies from src/kernel/kernel.h
a = $h/config.h $h/const.h $h/type.h $h/ipc.h \
$i/string.h $i/limits.h $i/errno.h $i/stddef.h \
$s/types.h \
$m/portio.h \
$k/proc.h $k/const.h $k/type.h $k/proto.h $k/glo.h
# Dependencies from src/kernel/system.h
b = $k/system.h $h/com.h $k/proc.h $k/assert.h
alarms.o: $a $b
copying.o: $a $b
debugging.o: $a $b
devio.o: $a $b $h/devio.h
irqctl.o: $a $b
misc.o: $a $b $i/unistd.h
proctl.o: $a $b $k/sendmask.h $k/protect.h $i/signal.h
sigctl.o: $a $b $i/signal.h $s/sigcontext.h
srvrctl.o: $a $b $s/svrctl.h $k/sendmask.h
tracing.o: $a $b $s/ptrace.h
do_copy.o: $a $b
do_vcopy.o: $a $b

130
kernel/system/alarms.c Normal file
View File

@@ -0,0 +1,130 @@
/* The system call implemented in this file:
* m_type: CLK_SIGNALRM, CLK_SYNCALRM, CLK_FLAGALRM
*
* The parameters for this system call are:
* m2_i1: ALRM_PROC_NR (set alarm for this process)
* m2_l1: ALRM_EXP_TIME (alarm's expiration time)
* m2_i2: ALRM_ABS_TIME (expiration time is absolute?)
* m2_l1: ALRM_SEC_LEFT (return seconds left of previous)
* m2_p1: ALRM_FLAG_PTR (virtual addr of alarm flag)
*
* Changes:
* Aug 25, 2004 fully rewritten to unite all alarms (Jorrit N. Herder)
* May 02, 2004 added new timeout flag alarm (Jorrit N. Herder)
*/
#include "../kernel.h"
#include "../system.h"
#include <signal.h>
FORWARD _PROTOTYPE( void cause_syncalrm, (timer_t *tp) );
FORWARD _PROTOTYPE( void cause_flagalrm, (timer_t *tp) );
FORWARD _PROTOTYPE( void cause_signalrm, (timer_t *tp) );
/*===========================================================================*
* do_setalarm *
*===========================================================================*/
PUBLIC int do_setalarm(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* A process requests an alarm, or wants to cancel its alarm. This function
* is shared used for all of SYS_SIGNALRM, SYS_SYNCALRM, and SYS_FLAGALRM.
*/
int proc_nr; /* which process wants the alarm */
long exp_time; /* expiration time for this alarm */
int use_abs_time; /* use absolute or relative time */
timer_t *tp; /* the process' timer structure */
clock_t uptime; /* placeholder for current uptime */
/* Extract shared parameters from the request message. */
proc_nr = m_ptr->ALRM_PROC_NR; /* process to interrupt later */
if (SELF == proc_nr) proc_nr = m_ptr->m_source;
if (! isokprocn(proc_nr)) return(EINVAL);
exp_time = m_ptr->ALRM_EXP_TIME; /* alarm's expiration time */
use_abs_time = m_ptr->ALRM_ABS_TIME; /* flag for absolute time */
/* Get the timer structure and set the parameters for this alarm. */
switch (m_ptr->m_type) {
case SYS_SYNCALRM: /* notify with SYN_ALARM message */
tp = &(proc_addr(proc_nr)->p_syncalrm);
tmr_arg(tp)->ta_int = proc_nr;
tp->tmr_func = cause_syncalrm;
break;
case SYS_SIGNALRM: /* send process a SIGALRM signal */
tp = &(proc_addr(proc_nr)->p_signalrm);
tmr_arg(tp)->ta_int = proc_nr;
tp->tmr_func = cause_signalrm;
break;
case SYS_FLAGALRM: /* set caller's timeout flag to 1 */
tp = &(proc_addr(proc_nr)->p_flagalrm);
tmr_arg(tp)->ta_long =
numap_local(proc_nr,(vir_bytes) m_ptr->ALRM_FLAG_PTR,sizeof(int));
if (! tmr_arg(tp)->ta_long) return(EFAULT);
tp->tmr_func = cause_flagalrm;
break;
default: /* invalid alarm type */
return(EINVAL);
}
/* Return the ticks left on the previous alarm. */
uptime = get_uptime();
if ((tp->tmr_exp_time == TMR_NEVER) || (tp->tmr_exp_time < uptime) ) {
m_ptr->ALRM_TIME_LEFT = 0;
} else {
m_ptr->ALRM_TIME_LEFT = (tp->tmr_exp_time - uptime);
}
/* Finally, (re)set the timer depending on 'exp_time'. */
if (exp_time == 0) {
reset_timer(tp);
} else {
tp->tmr_exp_time = (use_abs_time) ? exp_time : exp_time + get_uptime();
set_timer(tp, tp->tmr_exp_time, tp->tmr_func);
}
return(OK);
}
/*===========================================================================*
* cause_signalrm *
*===========================================================================*/
PRIVATE void cause_signalrm(tp)
timer_t *tp;
{
/* Routine called if a timer goes off for a process that requested an SIGALRM
* signal using the alarm(2) system call. The timer argument 'ta_int' contains
* the process number of the process to signal.
*/
cause_sig(tmr_arg(tp)->ta_int, SIGALRM);
}
/*===========================================================================*
* cause_flagalrm *
*===========================================================================*/
PRIVATE void cause_flagalrm(tp)
timer_t *tp;
{
/* Routine called if a timer goes off for a process that requested a timeout
* flag to be set when the alarm expires. The timer argument 'ta_long' gives
* the physical address of the timeout flag. No validity check was done when
* setting the alarm, so check for 0 here.
*/
int timeout = 1;
phys_bytes timeout_flag = (phys_bytes) tmr_arg(tp)->ta_long;
phys_copy(vir2phys(&timeout), tmr_arg(tp)->ta_long, sizeof(int));
}
/*===========================================================================*
* cause_syncalrm *
*===========================================================================*/
PRIVATE void cause_syncalrm(tp)
timer_t *tp;
{
/* Routine called if a timer goes off and the process requested a synchronous
* alarm. The process number is stored in timer argument 'ta_int'. Notify that
* process given with a SYN_ALARM message.
*/
notify(tmr_arg(tp)->ta_int, SYN_ALARM);
}

133
kernel/system/copying.c Normal file
View File

@@ -0,0 +1,133 @@
/* The system call implemented in this file:
* m_type: SYS_VIRCOPY
*
* The parameters for this system call are:
* m5_c1: CP_SRC_SPACE
* m5_l1: CP_SRC_ADDR
* m5_i1: CP_SRC_PROC_NR
* m5_c2: CP_DST_SPACE
* m5_l2: CP_DST_ADDR
* m5_i2: CP_DST_PROC_NR
* m5_l3: CP_NR_BYTES
*/
#include "../kernel.h"
#include "../system.h"
/*===========================================================================*
* do_vircopy *
*===========================================================================*/
PUBLIC int do_vircopy(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Handle sys_vircopy(). Copy data by using virtual addressing. */
struct vir_addr vir_addr[2]; /* virtual source and destination address */
vir_bytes bytes; /* number of bytes to copy */
int i;
/* Dismember the command message. */
vir_addr[_SRC_].proc_nr = m_ptr->CP_SRC_PROC_NR;
vir_addr[_SRC_].segment = m_ptr->CP_SRC_SPACE;
vir_addr[_SRC_].offset = (vir_bytes) m_ptr->CP_SRC_ADDR;
vir_addr[_DST_].proc_nr = m_ptr->CP_DST_PROC_NR;
vir_addr[_DST_].segment = m_ptr->CP_DST_SPACE;
vir_addr[_DST_].offset = (vir_bytes) m_ptr->CP_DST_ADDR;
bytes = (phys_bytes) m_ptr->CP_NR_BYTES;
/* Now do some checks for both the source and destination virtual address.
* This is done once for _SRC_, then once for _DST_.
*/
for (i=_SRC_; i<=_DST_; i++) {
/* 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)) {
kprintf("do_vircopy: illegal proc nr\n",NO_ARG);
return(EINVAL);
}
/* Copying from or to special segments can only done by the owner. */
if ((vir_addr[i].segment & SEGMENT_TYPE) != LOCAL_SEG &&
vir_addr[i].proc_nr != m_ptr->m_source) {
kprintf("do_vircopy: special seg permission denied\n", NO_ARG);
return(EPERM);
}
}
/* Check for overflow. This would happen for 64K segments and 16-bit
* vir_bytes. Especially copying by the MM on do_fork() is affected.
*/
if (bytes != (vir_bytes) bytes) {
kprintf("do_vircopy: overflow\n", NO_ARG);
return(E2BIG);
}
/* Now try to make the actual virtual copy. */
return( virtual_copy(&vir_addr[_SRC_], &vir_addr[_DST_], bytes) );
}
/* The system call implemented in this file:
* m_type: SYS_PHYSCOPY
*
* The parameters for this system call are:
* m5_l1: CP_SRC_ADDR (physical source address)
* m5_l2: CP_DST_ADDR (physical destination address)
* m5_l3: CP_NR_BYTES (number of bytes to copy)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
/*===========================================================================*
* do_physcopy *
*===========================================================================*/
PUBLIC int do_physcopy(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Handle sys_physcopy(). Copy data by using physical addressing. */
phys_bytes src_phys, dst_phys, bytes;
/* Dismember the command message. */
src_phys = (phys_bytes) m_ptr->CP_SRC_ADDR;
dst_phys = (phys_bytes) m_ptr->CP_DST_ADDR;
bytes = (phys_bytes) m_ptr->CP_NR_BYTES;
/* Do some checks and copy the data. */
if (src_phys == 0 || dst_phys == 0) return(EFAULT);
phys_copy(src_phys, dst_phys, bytes);
return(OK);
}
/* The system call implemented in this file:
* m_type: SYS_UMAP
*
* The parameters for this system call are:
* m5_i1: CP_SRC_PROC_NR (process number)
* m5_c1: CP_SRC_SPACE (segment where address is: T, D, or S)
* m5_l1: CP_SRC_ADDR (virtual address)
* m5_l2: CP_DST_ADDR (returns physical address)
* m5_l3: CP_NR_BYTES (size of datastructure)
*/
/*==========================================================================*
* do_umap *
*==========================================================================*/
PUBLIC int do_umap(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Same as umap_local(), for non-kernel processes. */
int proc_nr = (int) m_ptr->CP_SRC_PROC_NR;
if (proc_nr == SELF) proc_nr = m_ptr->m_source;
if (! isokprocn(proc_nr)) return(EINVAL);
m_ptr->CP_DST_ADDR = umap_local(proc_addr(proc_nr),
(int) m_ptr->CP_SRC_SPACE,
(vir_bytes) m_ptr->CP_SRC_ADDR,
(vir_bytes) m_ptr->CP_NR_BYTES);
return(OK);
}

16
kernel/system/debugging.c Normal file
View File

@@ -0,0 +1,16 @@
/* The system call implemented in this file:
* m_type: SYS_DEBUG
*
* The parameters for this system call are:
*/
#include "../kernel.h"
#include "../system.h"
#if ENABLE_K_DEBUGGING /* only include code if enabled */
/*==========================================================================*
* do_debug *
*==========================================================================*/
#endif /* ENABLE_K_DEBUGGING */

215
kernel/system/devio.c Normal file
View File

@@ -0,0 +1,215 @@
/* The system call implemented in this file:
* m_type: SYS_DEVIO
*
* The parameters for this system call are:
* m2_i3: DIO_REQUEST (request input or output)
* m2_i1: DIO_TYPE (flag indicating byte, word, or long)
* m2_l1: DIO_PORT (port to read/ write)
* m2_l2: DIO_VALUE (value to write/ return value read)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
#include "../kernel.h"
#include "../system.h"
#include <minix/devio.h>
/*===========================================================================*
* do_devio *
*===========================================================================*/
PUBLIC int do_devio(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* perform actual device I/O for byte, word, and long values */
if (m_ptr->DIO_REQUEST == DIO_INPUT) {
switch (m_ptr->DIO_TYPE) {
case DIO_BYTE: m_ptr->DIO_VALUE = inb(m_ptr->DIO_PORT); break;
case DIO_WORD: m_ptr->DIO_VALUE = inw(m_ptr->DIO_PORT); break;
case DIO_LONG: m_ptr->DIO_VALUE = inl(m_ptr->DIO_PORT); break;
default: return(EINVAL);
}
} else {
switch (m_ptr->DIO_TYPE) {
case DIO_BYTE: outb(m_ptr->DIO_PORT, m_ptr->DIO_VALUE); break;
case DIO_WORD: outw(m_ptr->DIO_PORT, m_ptr->DIO_VALUE); break;
case DIO_LONG: outl(m_ptr->DIO_PORT, m_ptr->DIO_VALUE); break;
default: return(EINVAL);
}
}
return(OK);
}
/* The system call implemented in this file:
* m_type: SYS_SDEVIO
*
* The parameters for this system call are:
* m2_i3: DIO_REQUEST (request input or output)
* m2_i1: DIO_TYPE (flag indicating byte, word, or long)
* m2_l1: DIO_PORT (port to read/ write)
* m2_p1: DIO_VEC_ADDR (virtual address of buffer)
* m2_l2: DIO_VEC_SIZE (number of elements)
* m2_i2: DIO_VEC_PROC (process where buffer is)
*/
/*===========================================================================*
* do_sdevio *
*===========================================================================*/
PUBLIC int do_sdevio(m_ptr)
register message *m_ptr; /* pointer to request message */
{
int proc_nr = m_ptr->DIO_VEC_PROC;
int count = m_ptr->DIO_VEC_SIZE;
long port = m_ptr->DIO_PORT;
phys_bytes phys_buf;
/* Check if process number is OK. */
if (proc_nr == SELF) proc_nr = m_ptr->m_source;
if (! isokprocn(proc_nr))
return(EINVAL);
/* Get and check physical address. */
if ((phys_buf = numap_local(proc_nr, (vir_bytes) m_ptr->DIO_VEC_ADDR, count)) == 0)
return(EFAULT);
/* Perform device I/O for bytes and words. Longs are not supported. */
if (m_ptr->DIO_REQUEST == DIO_INPUT) {
switch (m_ptr->DIO_TYPE) {
case DIO_BYTE: phys_insb(port, phys_buf, count); break;
case DIO_WORD: phys_insw(port, phys_buf, count); break;
default: return(EINVAL);
}
} else if (m_ptr->DIO_REQUEST == DIO_OUTPUT) {
switch (m_ptr->DIO_TYPE) {
case DIO_BYTE: phys_outsb(port, phys_buf, count); break;
case DIO_WORD: phys_outsw(port, phys_buf, count); break;
default: return(EINVAL);
}
}
else {
return(EINVAL);
}
return(OK);
}
/* The system call implemented in this file:
* m_type: SYS_VDEVIO
*
* The parameters for this system call are:
* m2_i3: DIO_REQUEST (request input or output)
* m2_i1: DIO_TYPE (flag indicating byte, word, or long)
* m2_p1: DIO_VEC_ADDR (pointer to port/ value pairs)
* m2_i2: DIO_VEC_SIZE (number of ports to read or write)
*/
/* Buffer for SYS_VDEVIO to copy (port,value)-pairs from/ to user. */
PRIVATE char vdevio_pv_buf[VDEVIO_BUF_SIZE];
/* SYS_VDEVIO sends a pointer to a (port,value)-pairs vector at the caller.
* Define the maximum number of (port,value)-pairs that can be handled in a
* in a single SYS_VDEVIO system call based on the struct definitions.
*/
#define MAX_PVB_PAIRS ((VDEVIO_BUF_SIZE * sizeof(char)) / sizeof(pvb_pair_t))
#define MAX_PVW_PAIRS ((VDEVIO_BUF_SIZE * sizeof(char)) / sizeof(pvw_pair_t))
#define MAX_PVL_PAIRS ((VDEVIO_BUF_SIZE * sizeof(char)) / sizeof(pvl_pair_t))
/*===========================================================================*
* do_vdevio *
*===========================================================================*/
PUBLIC int do_vdevio(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Perform a series of device I/O on behalf of a non-kernel process. The
* I/O addresses and I/O values are fetched from and returned to some buffer
* in user space. The actual I/O is wrapped by lock() and unlock() to prevent
* that I/O batch from being interrrupted.
* This is the counterpart of do_devio, which performs a single device I/O.
*/
pvb_pair_t *pvb_pairs; /* needed for byte values */
pvw_pair_t *pvw_pairs; /* needed for word values */
pvl_pair_t *pvl_pairs; /* needed for long values */
int i;
pid_t caller_pid; /* process id of caller */
size_t bytes; /* # bytes to be copied */
vir_bytes caller_vir; /* virtual address at caller */
phys_bytes caller_phys; /* physical address at caller */
phys_bytes kernel_phys; /* physical address in kernel */
/* Check if nr of ports is ok and get size of (port,value) data. */
if (m_ptr->DIO_VEC_SIZE <= 0) return(EINVAL);
switch(m_ptr->DIO_TYPE) {
case DIO_BYTE:
if (m_ptr->DIO_VEC_SIZE > MAX_PVB_PAIRS) return(EINVAL);
bytes = (size_t) (m_ptr->DIO_VEC_SIZE * sizeof(pvb_pair_t));
break;
case DIO_WORD:
if (m_ptr->DIO_VEC_SIZE > MAX_PVW_PAIRS) return(EINVAL);
bytes = (size_t) (m_ptr->DIO_VEC_SIZE * sizeof(pvw_pair_t));
break;
case DIO_LONG:
if (m_ptr->DIO_VEC_SIZE > MAX_PVL_PAIRS) return(EINVAL);
bytes = (size_t) (m_ptr->DIO_VEC_SIZE * sizeof(pvl_pair_t));
break;
default: /* this once and for all checks for a correct type */
return(EINVAL);
}
/* Calculate physical addresses and copy (port,value)-pairs from user. */
caller_pid = (pid_t) m_ptr->m_source;
caller_vir = (vir_bytes) m_ptr->DIO_VEC_ADDR;
caller_phys = umap_local(proc_addr(caller_pid), D, caller_vir, bytes);
if (0 == caller_phys) return EFAULT;
kernel_phys = vir2phys(vdevio_pv_buf);
phys_copy(caller_phys, kernel_phys, (phys_bytes) bytes);
/* Perform actual device I/O for byte, word, and long values. Note that
* the entire switch is wrapped in lock() and unlock() to prevent the I/O
* batch from being interrupted. It may be cleaner to do this just around
* the for loops, but this results in rather lenghty code.
*/
lock();
switch (m_ptr->DIO_TYPE) {
case DIO_BYTE: /* byte values */
pvb_pairs = (pvb_pair_t *) vdevio_pv_buf;
if (DIO_INPUT == m_ptr->DIO_REQUEST) {
for (i=0; i < m_ptr->DIO_VEC_SIZE; i++)
pvb_pairs[i].value = inb(pvb_pairs[i].port);
} else {
for (i=0; i < m_ptr->DIO_VEC_SIZE; i++)
outb(pvb_pairs[i].port, pvb_pairs[i].value);
}
break;
case DIO_WORD: /* word values */
pvw_pairs = (pvw_pair_t *) vdevio_pv_buf;
if (DIO_INPUT == m_ptr->DIO_REQUEST) {
for (i=0; i < m_ptr->DIO_VEC_SIZE; i++)
pvw_pairs[i].value = inw(pvw_pairs[i].port);
} else {
for (i=0; i < m_ptr->DIO_VEC_SIZE; i++)
outw(pvw_pairs[i].port, pvw_pairs[i].value);
}
break;
case DIO_LONG: /* fall through: long values */
default: /* only DIO_LONG can arrive here, see above switch */
pvl_pairs = (pvl_pair_t *) vdevio_pv_buf;
if (DIO_INPUT == m_ptr->DIO_REQUEST) {
for (i=0; i < m_ptr->DIO_VEC_SIZE; i++)
pvl_pairs[i].value = inl(pvl_pairs[i].port);
} else {
for (i=0; i < m_ptr->DIO_VEC_SIZE; i++)
outl(pvb_pairs[i].port, pvl_pairs[i].value);
}
}
unlock();
/* Almost done, copy back results for input requests. */
if (DIO_INPUT == m_ptr->REQUEST)
phys_copy(kernel_phys, caller_phys, (phys_bytes) bytes);
return(OK);
}

69
kernel/system/do_copy.c Normal file
View File

@@ -0,0 +1,69 @@
/* The system call implemented in this file:
* m_type: SYS_COPY
*
* The parameters for this system call are:
* m5_c1: CP_SRC_SPACE
* m5_i1: CP_SRC_PROC_NR
* m5_l1: CP_SRC_ADDR
* m5_c2: CP_DST_SPACE
* m5_i2: CP_DST_PROC_NR
* m5_l2: CP_DST_ADDR
* m5_l3: CP_NR_BYTES
*/
#include "../kernel.h"
#include "../system.h"
/*===========================================================================*
* do_copy *
*===========================================================================*/
PUBLIC int do_copy(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Handle sys_copy(). Copy data by using virtual or physical addressing. */
int src_proc, dst_proc, src_space, dst_space;
vir_bytes src_vir, dst_vir;
phys_bytes src_phys, dst_phys, bytes;
/* Dismember the command message. */
src_proc = m_ptr->CP_SRC_PROC_NR;
dst_proc = m_ptr->CP_DST_PROC_NR;
src_space = m_ptr->CP_SRC_SPACE;
dst_space = m_ptr->CP_DST_SPACE;
src_vir = (vir_bytes) m_ptr->CP_SRC_ADDR;
dst_vir = (vir_bytes) m_ptr->CP_DST_ADDR;
bytes = (phys_bytes) m_ptr->CP_NR_BYTES;
/* Check if process number was given implicitly with SELF. */
if (src_proc == SELF) src_proc = m_ptr->m_source;
if (dst_proc == SELF) dst_proc = m_ptr->m_source;
/* Compute the source and destination addresses and do the copy. */
if (src_proc == ABS) {
src_phys = (phys_bytes) m_ptr->CP_SRC_ADDR;
} else {
if (bytes != (vir_bytes) bytes) {
/* This would happen for 64K segments and 16-bit vir_bytes.
* It would happen a lot for do_fork except MM uses ABS
* copies for that case.
*/
panic("overflow in count in do_copy", NO_NUM);
}
src_phys = umap_local(proc_addr(src_proc), src_space, src_vir,
(vir_bytes) bytes);
}
if (dst_proc == ABS) {
dst_phys = (phys_bytes) m_ptr->CP_DST_ADDR;
} else {
dst_phys = umap_local(proc_addr(dst_proc), dst_space, dst_vir,
(vir_bytes) bytes);
}
if (src_phys == 0 || dst_phys == 0) return(EFAULT);
phys_copy(src_phys, dst_phys, bytes);
return(OK);
}

55
kernel/system/do_vcopy.c Normal file
View File

@@ -0,0 +1,55 @@
/* The system call implemented in this file:
* m_type: SYS_VCOPY
*
* The parameters for this system call are:
* m1_i1: VCP_SRC_PROC (source process number)
* m1_i2: VCP_DST_PROC (destination process number)
* m1_i3: VCP_VEC_SIZE (vector size)
* m1_p1: VCP_VEC_ADDR (pointer to vector)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
#include "../kernel.h"
#include "../system.h"
/*===========================================================================*
* do_vcopy *
*===========================================================================*/
PUBLIC int do_vcopy(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Handle sys_vcopy(). Copy multiple blocks of memory */
int src_proc, dst_proc, vect_s, i;
vir_bytes src_vir, dst_vir, vect_addr;
phys_bytes src_phys, dst_phys, bytes;
cpvec_t cpvec_table[CPVEC_NR];
/* Dismember the command message. */
src_proc = m_ptr->VCP_SRC_PROC;
dst_proc = m_ptr->VCP_DST_PROC;
vect_s = m_ptr->VCP_VEC_SIZE;
vect_addr = (vir_bytes)m_ptr->VCP_VEC_ADDR;
if (vect_s > CPVEC_NR) return EDOM;
src_phys= numap_local(m_ptr->m_source, vect_addr, vect_s * sizeof(cpvec_t));
if (!src_phys) return EFAULT;
phys_copy(src_phys, vir2phys(cpvec_table),
(phys_bytes) (vect_s * sizeof(cpvec_t)));
for (i = 0; i < vect_s; i++) {
src_vir= cpvec_table[i].cpv_src;
dst_vir= cpvec_table[i].cpv_dst;
bytes= cpvec_table[i].cpv_size;
src_phys = numap_local(src_proc,src_vir,(vir_bytes)bytes);
dst_phys = numap_local(dst_proc,dst_vir,(vir_bytes)bytes);
if (src_phys == 0 || dst_phys == 0) return(EFAULT);
phys_copy(src_phys, dst_phys, bytes);
}
return(OK);
}

106
kernel/system/irqctl.c Normal file
View File

@@ -0,0 +1,106 @@
/* The system call implemented in this file:
* m_type: SYS_IRQCTL
*
* The parameters for this system call are:
* m5_c1: IRQ_REQUEST (control operation to perform)
* m5_c2: IRQ_VECTOR (irq line that must be controlled)
* m5_i1: IRQ_POLICY (flags to control the IRQCTL request)
* m5_i2: IRQ_PROC_NR (process number to notify)
* m5_l1: IRQ_PORT (port to write to / read from)
* m5_l2: IRQ_VIR_ADDR (virtual address at caller)
* m5_l3: IRQ_MASK_VAL (value to be written or strobe mask)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
#include "../kernel.h"
#include "../system.h"
/*===========================================================================*
* do_irqctl *
*===========================================================================*/
PUBLIC int do_irqctl(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Dismember the request message. */
int irq = m_ptr->IRQ_VECTOR; /* which IRQ vector */
int policy = m_ptr->IRQ_POLICY; /* policy field with flags */
long port = m_ptr->IRQ_PORT; /* port to read or write */
vir_bytes vir_addr = m_ptr->IRQ_VIR_ADDR; /* address at caller */
phys_bytes phys_addr = 0; /* calculate physical address */
long mask_val = m_ptr->IRQ_MASK_VAL; /* mask or value to be written */
int proc_nr = m_ptr->IRQ_PROC_NR; /* process number to forward to */
/* Check if IRQ line is acceptable. */
if ((unsigned) irq >= NR_IRQ_VECTORS) {
kprintf("ST: irq line %d is not acceptable!\n", irq);
return(EINVAL);
}
/* See what is requested and take needed actions. */
switch(m_ptr->IRQ_REQUEST) {
/* Enable or disable IRQs. This is straightforward. */
case IRQ_ENABLE: {
enable_irq(&irqtab[irq].hook);
break;
}
case IRQ_DISABLE: {
disable_irq(&irqtab[irq].hook);
break;
}
/* Control IRQ policies. Set a policy and needed details in the IRQ table.
* This policy is used by a generic function to handle hardware interrupts.
* The generic_handler() is contained in system.c.
*/
case IRQ_SETPOLICY: {
if (proc_nr == NONE) { /* remove irqtab entry */
if (irqtab[irq].proc_nr != m_ptr->m_source) {
return(EPERM); /* only owner may do so */
}
kprintf("ST: notify: cannot remove entry for IRQ %d\n",irq);
return(ENOSYS); /* not yet supported */
}
else { /* install generic handler */
if (irqtab[irq].proc_nr != NONE) { /* IRQ entry already taken */
kprintf("ST: notify: slot for IRQ %d already taken\n", irq);
return(EBUSY); /* cannot overwrite entry */
}
if (proc_nr == SELF) /* check for magic proc nr */
proc_nr = m_ptr->m_source; /* set caller's proc nr */
if (! isokprocn(proc_nr)) { /* check if proc nr is ok */
kprintf("ST: notify: invalid proc_nr: %d\n", proc_nr);
return(EINVAL);
}
if (policy & IRQ_READ_PORT) { /* get phys_addr at caller */
switch(policy & (IRQ_BYTE|IRQ_WORD|IRQ_LONG)) {
case IRQ_BYTE: phys_addr=numap_local(proc_nr,vir_addr,sizeof( u8_t));
break;
case IRQ_WORD: phys_addr=numap_local(proc_nr,vir_addr,sizeof(u16_t));
break;
case IRQ_LONG: phys_addr=numap_local(proc_nr,vir_addr,sizeof(u32_t));
break;
default: return(EINVAL); /* wrong type flags */
}
if (phys_addr==0) return(EFAULT); /* invalid address */
}
/* Arguments seem to be OK, register them in the IRQ table. */
irqtab[irq].policy = policy; /* policy for interrupts */
irqtab[irq].proc_nr = proc_nr; /* process number to notify */
irqtab[irq].port = port; /* port to read or write */
irqtab[irq].addr = phys_addr; /* address to store status */
irqtab[irq].mask_val = mask_val; /* strobe mask or value */
put_irq_handler(&irqtab[irq].hook, irq, generic_handler);
}
break;
}
default:
return(EINVAL); /* invalid IRQ_REQUEST */
}
return(OK);
}

234
kernel/system/misc.c Normal file
View File

@@ -0,0 +1,234 @@
/* The system call implemented in this file:
* m_type: SYS_TIMES
*
* The parameters for this system call are:
* m4_l1: T_PROC_NR (get info for this process)
* m4_l1: T_USER_TIME (return values ...)
* m4_l2: T_SYSTEM_TIME
* m4_l3: T_CHILD_UTIME
* m4_l4: T_CHILD_STIME
* m4_l5: T_BOOT_TICKS
*/
#include "../kernel.h"
#include "../system.h"
#include <unistd.h>
INIT_ASSERT
/*===========================================================================*
* do_times *
*===========================================================================*/
PUBLIC int do_times(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Handle sys_times(). Retrieve the accounting information. */
register struct proc *rp;
int proc_nr;
/* Insert the times needed by the SYS_TIMES system call in the message. */
proc_nr = (m_ptr->T_PROC_NR == SELF) ? m_ptr->m_source : m_ptr->T_PROC_NR;
if (isokprocn(proc_nr)) {
rp = proc_addr(m_ptr->T_PROC_NR);
lock(); /* halt the volatile time counters in rp */
m_ptr->T_USER_TIME = rp->user_time;
m_ptr->T_SYSTEM_TIME = rp->sys_time;
unlock();
m_ptr->T_CHILD_UTIME = rp->child_utime;
m_ptr->T_CHILD_STIME = rp->child_stime;
}
m_ptr->T_BOOT_TICKS = get_uptime();
return(OK);
}
/*===========================================================================*
* do_unused *
*===========================================================================*/
PUBLIC int do_unused(m)
message *m; /* pointer to request message */
{
kprintf("SYS task got illegal request from %d.", m->m_source);
return(EBADREQUEST); /* illegal message type */
}
/* The system call implemented in this file:
* m_type: SYS_ABORT
*
* The parameters for this system call are:
* m1_i1: ABRT_HOW (how to abort, possibly fetch monitor params)
* m1_i2: ABRT_MON_PROC (proc nr to get monitor params from)
* m1_i3: ABRT_MON_LEN (length of monitor params)
* m1_p1: ABRT_MON_ADDR (virtual address of params)
*/
/*===========================================================================*
* do_abort *
*===========================================================================*/
PUBLIC int do_abort(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Handle sys_abort. MINIX is unable to continue. This can originate in the
* MM (normal abort or panic) or FS (panic), or TTY (a CTRL-ALT-DEL or ESC
* after debugging dumps).
*/
register struct proc *rp;
phys_bytes src_phys;
vir_bytes len;
int how = m_ptr->ABRT_HOW;
rp = proc_addr(m_ptr->m_source);
if (how == RBT_MONITOR) {
/* The monitor is to run user specified instructions. */
len = m_ptr->ABRT_MON_LEN + 1;
assert(len <= mon_parmsize);
src_phys = numap_local(m_ptr->ABRT_MON_PROC,
(vir_bytes) m_ptr->ABRT_MON_ADDR, len);
assert(src_phys != 0);
phys_copy(src_phys, mon_params, (phys_bytes) len);
}
prepare_shutdown(how);
return(OK); /* pro-forma (really EDISASTER) */
}
/* The system call implemented in this file:
* m_type: SYS_GETINFO
*
* The parameters for this system call are:
* m1_i3: I_REQUEST (what info to get)
* m1_i4: I_PROC_NR (process to store value at)
* m1_p1: I_VAL_PTR (where to put it)
* m1_i1: I_VAL_LEN (maximum length expected, optional)
* m1_p2: I_KEY_PTR (environment variable key)
* m1_i2: I_KEY_LEN (lenght of environment variable key)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
/*===========================================================================*
* do_getinfo *
*===========================================================================*/
PUBLIC int do_getinfo(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Request system information to be copied to caller's address space. */
size_t length;
phys_bytes src_phys;
phys_bytes dst_phys;
int proc_nr, nr;
/* Set source address and length based on request type. */
switch (m_ptr->I_REQUEST) {
case GET_KENVIRON: {
struct kenviron kenv;
extern int end;
kenv.pc_at = pc_at; kenv.ps_mca = ps_mca;
kenv.processor = processor; kenv.protected = protected_mode;
kenv.ega = ega; kenv.vga = vga;
kenv.proc_addr = (vir_bytes) proc;
kenv.params_base = mon_params;
kenv.params_size = mon_parmsize;
kenv.kmem_base = vir2phys(0);
kenv.kmem_size = vir2phys(&end) - vir2phys(0) + 1;
kenv.bootfs_base = proc_addr(MEMORY)->p_farmem[0].mem_phys;
kenv.bootfs_size = proc_addr(MEMORY)->p_farmem[0].mem_len;
length = sizeof(struct kenviron);
src_phys = vir2phys(&kenv);
break;
}
case GET_IMAGE: {
length = sizeof(struct system_image) * IMAGE_SIZE;
src_phys = vir2phys(image);
break;
}
case GET_IRQTAB: {
length = sizeof(struct irqtab) * NR_IRQ_VECTORS;
src_phys = vir2phys(irqtab);
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.
* Copy the queue heads and fall through to copy the process table.
*/
length = sizeof(struct proc *) * NR_SCHED_QUEUES;
src_phys = vir2phys(rdy_head);
dst_phys = numap_local(m_ptr->m_source, (vir_bytes) m_ptr->I_KEY_PTR,
length);
if (src_phys == 0 || dst_phys == 0) return(EFAULT);
phys_copy(src_phys, dst_phys, length);
}
case GET_PROCTAB: {
length = sizeof(struct proc) * (NR_PROCS + NR_TASKS);
src_phys = vir2phys(proc);
break;
}
case GET_PROC: {
nr = (m_ptr->I_KEY_LEN == SELF) ? m_ptr->m_source : m_ptr->I_KEY_LEN;
if (! isokprocn(nr)) return(EINVAL);
length = sizeof(struct proc);
src_phys = vir2phys(proc_addr(nr));
break;
}
case GET_MONPARAMS: {
src_phys = mon_params; /* already is a physical address! */
length = mon_parmsize;
break;
}
case GET_PROCNR: {
length = sizeof(int);
if (m_ptr->I_KEY_LEN == 0) { /* get own process nr */
kprintf("GET_PROCNR (own) from %d\n", m_ptr->m_source);
src_phys = vir2phys(&proc_nr);
} else { /* lookup nr by name */
int proc_found = FALSE;
struct proc *pp;
char key[8]; /* storage for process name to lookup */
kprintf("GET_PROCNR (others) from %d\n", m_ptr->m_source);
proc_nr = m_ptr->m_source; /* only caller can request copy */
if (m_ptr->I_KEY_LEN > sizeof(key)) return(EINVAL);
if (vir_copy(proc_nr, (vir_bytes) m_ptr->I_KEY_PTR, SYSTASK,
(vir_bytes) key, m_ptr->I_KEY_LEN) != OK) return(EFAULT);
for (pp=BEG_PROC_ADDR; pp<END_PROC_ADDR; pp++) {
if (kstrncmp(pp->p_name, key, m_ptr->I_KEY_LEN) == 0) {
src_phys = vir2phys(&(pp->p_nr));
proc_found = TRUE;
break;
}
}
if (! proc_found) return(ESRCH);
}
break;
}
case GET_KMESSAGES: {
length = sizeof(struct kmessages);
src_phys = vir2phys(&kmess);
break;
}
default:
return(EINVAL);
}
/* Try to make the actual copy for the requested data. */
if (m_ptr->I_VAL_LEN > 0 && length > m_ptr->I_VAL_LEN) return (E2BIG);
proc_nr = m_ptr->m_source; /* only caller can request copy */
dst_phys = numap_local(proc_nr, (vir_bytes) m_ptr->I_VAL_PTR, length);
if (src_phys == 0 || dst_phys == 0) return(EFAULT);
phys_copy(src_phys, dst_phys, length);
return(OK);
}

View File

@@ -0,0 +1,45 @@
/* The system call implemented in this file:
* m_type: SYS_ABORT
*
* The parameters for this system call are:
* m1_i1: ABRT_HOW (how to abort, possibly fetch monitor params)
* m1_i2: ABRT_MON_PROC (proc nr to get monitor params from)
* m1_i3: ABRT_MON_LEN (length of monitor params)
* m1_p1: ABRT_MON_ADDR (virtual address of params)
*/
#include "../kernel.h"
#include "../system.h"
#include <unistd.h>
INIT_ASSERT
/*===========================================================================*
* do_abort *
*===========================================================================*/
PUBLIC int do_abort(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Handle sys_abort. MINIX is unable to continue. This can originate in the
* MM (normal abort or panic) or FS (panic), or TTY (a CTRL-ALT-DEL or ESC
* after debugging dumps).
*/
register struct proc *rp;
phys_bytes src_phys;
vir_bytes len;
int how = m_ptr->ABRT_HOW;
rp = proc_addr(m_ptr->m_source);
if (how == RBT_MONITOR) {
/* The monitor is to run user specified instructions. */
len = m_ptr->ABRT_MON_LEN + 1;
assert(len <= mon_parmsize);
src_phys = numap_local(m_ptr->ABRT_MON_PROC,
(vir_bytes) m_ptr->ABRT_MON_ADDR, len);
assert(src_phys != 0);
phys_copy(src_phys, mon_params, (phys_bytes) len);
}
prepare_shutdown(how);
return(OK); /* pro-forma (really EDISASTER) */
}

View File

@@ -0,0 +1,34 @@
/* The system call implemented in this file:
* m_type: SYS_ENDSIG
*
* The parameters for this system call are:
* m2_i1: SIG_PROC (process that was signaled)
*/
#include "../kernel.h"
#include "../system.h"
INIT_ASSERT
/*===========================================================================*
* do_endsig *
*===========================================================================*/
PUBLIC int do_endsig(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Finish up after a KSIG-type signal, caused by a SYS_KILL message or a call
* to cause_sig by a task
*/
register struct proc *rp;
rp = proc_addr(m_ptr->SIG_PROC);
if (isemptyp(rp)) return(EINVAL); /* process already dead? */
assert(isuserp(rp));
/* MM has finished one KSIG. */
if (rp->p_pendcount != 0 && --rp->p_pendcount == 0
&& (rp->p_flags &= ~SIG_PENDING) == 0)
lock_ready(rp);
return(OK);
}

View File

@@ -0,0 +1,65 @@
/* The system call implemented in this file:
* m_type: SYS_EXEC
*
* The parameters for this system call are:
* m1_i1: PR_PROC_NR (process that did exec call)
* m1_i3: PR_TRACING (flag to indicate tracing is on/ off)
* m1_p1: PR_STACK_PTR (new stack pointer)
* m1_p2: PR_NAME_PTR (pointer to program name)
* m1_p3: PR_IP_PTR (new instruction pointer)
*/
#include "../kernel.h"
#include "../system.h"
#include <signal.h>
#if (CHIP == INTEL)
#include "../protect.h"
#endif
INIT_ASSERT
/*===========================================================================*
* do_exec *
*===========================================================================*/
PUBLIC int do_exec(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Handle sys_exec(). A process has done a successful EXEC. Patch it up. */
register struct proc *rp;
reg_t sp; /* new sp */
phys_bytes phys_name;
char *np;
#define NLEN (sizeof(rp->p_name)-1)
rp = proc_addr(m_ptr->PR_PROC_NR);
assert(isuserp(rp));
if (m_ptr->PR_TRACING) cause_sig(m_ptr->PR_PROC_NR, SIGTRAP);
sp = (reg_t) m_ptr->PR_STACK_PTR;
rp->p_reg.sp = sp; /* set the stack pointer */
#if (CHIP == M68000)
rp->p_splow = sp; /* set the stack pointer low water */
#ifdef FPP
/* Initialize fpp for this process */
fpp_new_state(rp);
#endif
#endif
#if (CHIP == INTEL) /* wipe extra LDT entries */
memset(&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 */
rp->p_flags &= ~RECEIVING; /* MM does not reply to EXEC call */
if (rp->p_flags == 0) lock_ready(rp);
/* Save command name for debugging, ps(1) output, etc. */
phys_name = numap_local(m_ptr->m_source, (vir_bytes) m_ptr->PR_NAME_PTR,
(vir_bytes) NLEN);
if (phys_name != 0) {
phys_copy(phys_name, vir2phys(rp->p_name), (phys_bytes) NLEN);
for (np = rp->p_name; (*np & BYTE) >= ' '; np++) {}
*np = 0;
}
return(OK);
}

View File

@@ -0,0 +1,45 @@
/* The system call implemented in this file:
* m_type: SYS_EXIT
*
* The parameters for this system call are:
* m1_i1: EXIT_STATUS (exit status, 0 if normal exit)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
#include "../kernel.h"
#include "../system.h"
/*===========================================================================*
* do_exit *
*===========================================================================*/
PUBLIC int do_exit(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Handle sys_exit. A server or driver wants to exit. This may happen
* on a panic, but also is done when MINIX is shutdown.
*/
register struct proc *rp;
int proc_nr = m_ptr->m_source; /* can only exit own process */
if (m_ptr->EXIT_STATUS != 0) {
kprintf("WARNING: system process %d exited with an error.\n", proc_nr );
}
/* Now call the routine to clean up of the process table slot. This cancels
* outstanding timers, possibly removes the process from the message queues,
* and reset important process table fields.
*/
clear_proc(proc_nr);
/* If the shutdown sequence is active, see if it was awaiting the shutdown
* of this system service. If so, directly continue the stop sequence.
*/
if (shutting_down && shutdown_process == proc_addr(proc_nr)) {
stop_sequence(&shutdown_timer);
}
return(EDONTREPLY); /* no reply is sent */
}

View File

@@ -0,0 +1,64 @@
/* The system call implemented in this file:
* m_type: SYS_FORK
*
* The parameters for this system call are:
* m1_i1: PR_PROC_NR (child's process table slot)
* m1_i2: PR_PPROC_NR (parent, process that forked)
* m1_i3: PR_PID (child pid received from MM)
*/
#include "../kernel.h"
#include "../system.h"
#include <signal.h>
#include "../sendmask.h"
INIT_ASSERT
/*===========================================================================*
* do_fork *
*===========================================================================*/
PUBLIC int do_fork(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Handle sys_fork(). PR_PPROC_NR has forked. The child is PR_PROC_NR. */
#if (CHIP == INTEL)
reg_t old_ldt_sel;
#endif
register struct proc *rpc;
struct proc *rpp;
rpp = proc_addr(m_ptr->PR_PPROC_NR);
assert(isuserp(rpp));
rpc = proc_addr(m_ptr->PR_PROC_NR);
assert(isemptyp(rpc));
/* Copy parent 'proc' struct to child. */
#if (CHIP == INTEL)
old_ldt_sel = rpc->p_ldt_sel; /* stop this being obliterated by copy */
#endif
*rpc = *rpp; /* copy 'proc' struct */
#if (CHIP == INTEL)
rpc->p_ldt_sel = old_ldt_sel;
#endif
rpc->p_nr = m_ptr->PR_PROC_NR; /* this was obliterated by copy */
rpc->p_flags |= NO_MAP; /* inhibit the process from running */
rpc->p_flags &= ~(PENDING | SIG_PENDING | P_STOP);
/* Only 1 in group should have PENDING, child does not inherit trace status*/
sigemptyset(&rpc->p_pending);
rpc->p_pendcount = 0;
rpc->p_reg.retreg = 0; /* child sees pid = 0 to know it is child */
rpc->user_time = 0; /* set all the accounting times to 0 */
rpc->sys_time = 0;
rpc->child_utime = 0;
rpc->child_stime = 0;
return(OK);
}

View File

@@ -0,0 +1,148 @@
/* The system call implemented in this file:
* m_type: SYS_GETINFO
*
* The parameters for this system call are:
* m1_i3: I_REQUEST (what info to get)
* m1_i4: I_PROC_NR (process to store value at)
* m1_p1: I_VAL_PTR (where to put it)
* m1_i1: I_VAL_LEN (maximum length expected, optional)
* m1_p2: I_KEY_PTR (environment variable key)
* m1_i2: I_KEY_LEN (lenght of environment variable key)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
#include "../kernel.h"
#include "../system.h"
/*===========================================================================*
* do_getinfo *
*===========================================================================*/
PUBLIC int do_getinfo(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Request system information to be copied to caller's address space. */
size_t length;
phys_bytes src_phys;
phys_bytes dst_phys;
int proc_nr;
/* First get the process number and verify it. */
proc_nr = (m_ptr->I_PROC_NR == SELF) ? m_ptr->m_source : m_ptr->I_PROC_NR;
if (! isokprocn(proc_nr)) {
printf("Invalid process number: %d from %d\n", proc_nr, m_ptr->m_source);
return(EINVAL);
}
/* Set source address and length based on request type. */
switch (m_ptr->I_REQUEST) {
case GET_KENVIRON: {
struct kenviron kenv;
extern int end;
kenv.pc_at = pc_at; kenv.ps_mca = ps_mca;
kenv.processor = processor; kenv.protected = protected_mode;
kenv.ega = ega; kenv.vga = vga;
kenv.proc_addr = (vir_bytes) proc;
kenv.kmem_start = vir2phys(0);
kenv.kmem_end = vir2phys(&end);
length = sizeof(struct kenviron);
src_phys = vir2phys(&kenv);
break;
}
case GET_IMAGE: {
length = sizeof(struct system_image) * IMAGE_SIZE;
src_phys = vir2phys(image);
break;
}
case GET_IRQTAB: {
length = sizeof(struct irqtab) * NR_IRQ_VECTORS;
src_phys = vir2phys(irqtab);
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 several variables
* at once, otherwise the scheduling information may be incorrect.
*/
length = sizeof(struct proc *) * NR_SCHED_QUEUES;
src_phys = vir2phys(rdy_head);
dst_phys = numap_local(m_ptr->m_source, (vir_bytes) m_ptr->I_KEY_PTR,
length);
if (src_phys == 0 || dst_phys == 0) return(EFAULT);
phys_copy(src_phys, dst_phys, length);
/* Fall through to also get a copy of the process table. */
}
case GET_PROCTAB: {
length = sizeof(struct proc) * (NR_PROCS + NR_TASKS);
src_phys = vir2phys(proc);
break;
}
case GET_PROC: {
if (! isokprocn(m_ptr->I_KEY_LEN)) return(EINVAL);
length = sizeof(struct proc);
src_phys = vir2phys(proc_addr(m_ptr->I_KEY_LEN));
break;
}
case GET_MONPARAMS: {
src_phys = mon_params; /* already is a physical address! */
length = mon_parmsize;
break;
}
case GET_KENV: { /* get one string by name */
char key[32]; /* boot variable key provided by caller */
char *val; /* pointer to actual boot variable value */
if (m_ptr->I_KEY_LEN > sizeof(key)) return(EINVAL);
if (vir_copy(proc_nr, (vir_bytes) m_ptr->I_KEY_PTR,
SYSTASK, (vir_bytes) key, m_ptr->I_KEY_LEN) != OK) return(EFAULT);
if ((val=getkenv(key)) == NULL) return(ESRCH);
length = strlen(val) + 1;
src_phys = vir2phys(val);
break;
}
case GET_PROCNR: {
length = sizeof(int);
if (m_ptr->I_KEY_LEN == 0) { /* get own process nr */
src_phys = vir2phys(&proc_nr);
} else { /* lookup nr by name */
int proc_found = FALSE;
struct proc *pp;
char key[8]; /* storage for process name to lookup */
if (m_ptr->I_KEY_LEN > sizeof(key)) return(EINVAL);
if (vir_copy(proc_nr, (vir_bytes) m_ptr->I_KEY_PTR, SYSTASK,
(vir_bytes) key, m_ptr->I_KEY_LEN) != OK) return(EFAULT);
for (pp= BEG_PROC_ADDR; pp<END_PROC_ADDR; pp++) {
if (strncmp(pp->p_name, key, m_ptr->I_KEY_LEN) == 0) {
src_phys = vir2phys(&(pp->p_nr));
proc_found = TRUE;
break;
}
}
if (! proc_found) return(ESRCH);
}
break;
}
case GET_KMESSAGES: {
length = sizeof(struct kmessages);
src_phys = vir2phys(&kmess);
break;
}
default:
return(EINVAL);
}
/* Try to make the actual copy for the requested data. */
if (m_ptr->I_VAL_LEN > 0 && length > m_ptr->I_VAL_LEN) return (E2BIG);
dst_phys = numap_local(proc_nr, (vir_bytes) m_ptr->I_VAL_PTR, length);
if (src_phys == 0 || dst_phys == 0) return(EFAULT);
phys_copy(src_phys, dst_phys, length);
return(OK);
}

View File

@@ -0,0 +1,44 @@
/* The system call implemented in this file:
* m_type: SYS_GETMAP
*
* The parameters for this system call are:
* m1_i1: PR_PROC_NR (process to get map of)
* m1_p1: PR_MEM_PTR (copy the memory map here)
*/
#include "../kernel.h"
#include "../system.h"
INIT_ASSERT
/*===========================================================================*
* do_getmap *
*===========================================================================*/
PUBLIC int do_getmap(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Handle sys_getmap(). Report the memory map to MM. */
register struct proc *rp;
phys_bytes dst_phys;
int caller; /* where the map has to be stored */
int k; /* process whose map is to be loaded */
struct mem_map *map_ptr; /* virtual address of map inside caller (MM) */
/* Extract message parameters and copy new memory map to MM. */
caller = m_ptr->m_source;
k = m_ptr->PR_PROC_NR;
map_ptr = (struct mem_map *) m_ptr->PR_MEM_PTR;
assert(isokprocn(k)); /* unlikely: MM sends a bad proc nr. */
rp = proc_addr(k); /* ptr to entry of the map */
/* Copy the map to MM. */
dst_phys = umap_local(proc_addr(caller), D, (vir_bytes) map_ptr, sizeof(rp->p_map));
assert(dst_phys != 0);
phys_copy(vir2phys(rp->p_map), dst_phys, sizeof(rp->p_map));
return(OK);
}

View File

@@ -0,0 +1,46 @@
/* The system call implemented in this file:
* m_type: SYS_GETSIG
*
* The parameters for this system call are:
* m2_i1: SIG_PROC (return proc nr or NONE here)
* m2_l1: SIG_MAP (return signal map here)
*/
#include "../kernel.h"
#include "../system.h"
#include <signal.h>
/*===========================================================================*
* do_getsig *
*===========================================================================*/
PUBLIC int do_getsig(m_ptr)
message *m_ptr; /* pointer to the request message */
{
/* MM is ready to accept signals and repeatedly does a system call to get one
* Find a process with pending signals. If no more signals are available,
* return NONE in the process number field.
*/
register struct proc *rp;
/* Only the MM is allowed to request pending signals. */
if (m_ptr->m_source != MM_PROC_NR)
return(EPERM);
/* Find the next process with pending signals. */
for (rp = BEG_SERV_ADDR; rp < END_PROC_ADDR; rp++) {
if (rp->p_flags & PENDING) {
m_ptr->SIG_PROC = proc_number(rp);
m_ptr->SIG_MAP = rp->p_pending;
sigemptyset(&rp->p_pending); /* the ball is now in MM's court */
rp->p_flags &= ~PENDING; /* remains inhibited by SIG_PENDING */
return(OK);
}
}
/* No process with pending signals was found. */
m_ptr->SIG_PROC = NONE;
return(OK);
}

View File

@@ -0,0 +1,32 @@
/* The system call implemented in this file:
* m_type: SYS_GETSP
*
* The parameters for this system call are:
* m1_i1: PR_PROC_NR (process to get stack pointer of)
* m1_p1: PR_STACK_PTR (return stack pointer here)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
#include "../kernel.h"
#include "../system.h"
INIT_ASSERT
/*===========================================================================*
* do_getsp *
*===========================================================================*/
PUBLIC int do_getsp(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Handle sys_getsp(). MM wants to know what sp is. */
register struct proc *rp;
rp = proc_addr(m_ptr->PR_PROC_NR);
assert(isuserp(rp));
m_ptr->PR_STACK_PTR = (char *) rp->p_reg.sp; /* return sp here (bad type) */
return(OK);
}

View File

@@ -0,0 +1,28 @@
/* The system call implemented in this file:
* m_type: SYS_IOPENABLE
*
* The parameters for this system call are:
* m2_i2: PROC_NR (process to give I/O Protection Level bits)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
#include "../kernel.h"
#include "../system.h"
/*===========================================================================*
* do_iopenable *
*===========================================================================*/
PUBLIC int do_iopenable(m_ptr)
register message *m_ptr; /* pointer to request message */
{
#if ENABLE_USERPRIV && ENABLE_USERIOPL
enable_iop(proc_addr(m_ptr->PROC_NR));
return(OK);
#else
return(EPERM);
#endif
}

View File

@@ -0,0 +1,15 @@
#include "../kernel.h"
#include "../system.h"
PUBLIC int do_kill(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Handle sys_kill(). Cause a signal to be sent to a process via MM.
* Note that this has nothing to do with the kill (2) system call, this
* is how the FS (and possibly other servers) get access to cause_sig.
*/
cause_sig(m_ptr->SIG_PROC, m_ptr->SIG_NUMBER);
return(OK);
}

View File

@@ -0,0 +1,36 @@
/* The system call implemented in this file:
* m_type: SYS_KMALLOC
*
* The parameters for this system call are:
* m4_l2: MEM_CHUNK_SIZE (request a buffer of this size)
* m4_l1: MEM_CHUNK_BASE (return physical address on success)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
#include "../kernel.h"
#include "../system.h"
/*===========================================================================*
* do_kmalloc *
*===========================================================================*/
PUBLIC int do_kmalloc(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Request a (DMA) buffer to be allocated in one of the memory chunks. */
phys_clicks tot_clicks;
struct memory *memp;
tot_clicks = (m_ptr->MEM_CHUNK_SIZE + CLICK_SIZE-1) >> CLICK_SHIFT;
memp = &mem[NR_MEMS];
while ((--memp)->size < tot_clicks) {
if (memp == mem) {
return(ENOMEM);
}
}
memp->size -= tot_clicks;
m_ptr->MEM_CHUNK_BASE = (memp->base + memp->size) << CLICK_SHIFT;
return(OK);
}

View File

@@ -0,0 +1,33 @@
/* The system call implemented in this file:
* m_type: SYS_MEM
*
* The parameters for this system call are:
* m4_l1: MEM_CHUNK_BASE (memory base)
* m4_l2: MEM_CHUNK_SIZE (memory size)
* m4_l3: MEM_TOT_SIZE (total memory)
*/
#include "../kernel.h"
#include "../system.h"
/*===========================================================================*
* do_mem *
*===========================================================================*/
PUBLIC int do_mem(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Return the base and size of the next chunk of memory. */
struct memory *memp;
for (memp = mem; memp < &mem[NR_MEMS]; ++memp) {
m_ptr->MEM_CHUNK_BASE = memp->base;
m_ptr->MEM_CHUNK_SIZE = memp->size;
m_ptr->MEM_TOT_SIZE = tot_mem_size;
memp->size = 0;
if (m_ptr->MEM_CHUNK_SIZE != 0) break; /* found a chunk */
}
return(OK);
}

View File

@@ -0,0 +1,52 @@
/* The system call implemented in this file:
* m_type: SYS_NEWMAP
*
* The parameters for this system call are:
* m1_i1: PR_PROC_NR (install new map for this process)
* m1_p1: PR_MEM_PTR (pointer to memory map)
*/
#include "../kernel.h"
#include "../system.h"
INIT_ASSERT
/*===========================================================================*
* do_newmap *
*===========================================================================*/
PUBLIC int do_newmap(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Handle sys_newmap(). Fetch the memory map from MM. */
register struct proc *rp;
phys_bytes src_phys;
int caller; /* whose space has the new map (usually MM) */
int k; /* process whose map is to be loaded */
int old_flags; /* value of flags before modification */
struct mem_map *map_ptr; /* virtual address of map inside caller (MM) */
/* Extract message parameters and copy new memory map from MM. */
caller = m_ptr->m_source;
k = m_ptr->PR_PROC_NR;
map_ptr = (struct mem_map *) m_ptr->PR_MEM_PTR;
if (!isokprocn(k)) return(EINVAL);
rp = proc_addr(k); /* ptr to entry of user getting new map */
/* Copy the map from MM. */
src_phys = umap_local(proc_addr(caller), D, (vir_bytes) map_ptr, sizeof(rp->p_map));
assert(src_phys != 0);
phys_copy(src_phys, vir2phys(rp->p_map), (phys_bytes) sizeof(rp->p_map));
#if (CHIP != M68000)
alloc_segments(rp);
#else
pmmu_init_proc(rp);
#endif
old_flags = rp->p_flags; /* save the previous value of the flags */
rp->p_flags &= ~NO_MAP;
if (old_flags != 0 && rp->p_flags == 0) lock_ready(rp);
return(OK);
}

View File

@@ -0,0 +1,86 @@
/* The system call implemented in this file:
* m_type: SYS_PHYS2SEG
*
* The parameters for this system call are:
* m4_l1: SEG_SELECT (return segment selector here)
* m4_l2: SEG_OFFSET (return offset within segment here)
* m4_l3: SEG_PHYS (physical address to convert)
* m4_l4: SEG_SIZE (size of segment)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
#include "../kernel.h"
#include "../system.h"
#include "../protect.h"
/*===========================================================================*
* do_phys2seg *
*===========================================================================*/
PUBLIC int do_phys2seg(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Return a segment selector and offset that can be used to reach a physical
* address, for use by a driver doing memory I/O in the A0000 - DFFFF range.
*/
u16_t selector;
vir_bytes offset;
register struct proc *rp;
phys_bytes phys = (phys_bytes) m_ptr->SEG_PHYS;
vir_bytes size = (vir_bytes) m_ptr->SEG_SIZE;
int result;
#if 0
kprintf("FLAT DS SELECTOR used\n", NO_ARG);
selector = FLAT_DS_SELECTOR;
offset = phys;
#else
kprintf("Using Experimental LDT selector for video memory\n", NO_ARG);
if (!protected_mode) {
selector = phys / HCLICK_SIZE;
offset = phys % HCLICK_SIZE;
result = OK;
} else {
/* Check if the segment size can be recorded in bytes, that is, check
* if descriptor's limit field can delimited the allowed memory region
* precisely. This works up to 1MB. If the size is larger, 4K pages
* instead of bytes are used.
*/
if (size < BYTE_GRAN_MAX) {
rp = proc_addr(m_ptr->m_source);
init_dataseg(&rp->p_ldt[EXTRA_LDT_INDEX], phys, size,
USER_PRIVILEGE);
selector = (EXTRA_LDT_INDEX * 0x08) | (1 * 0x04) | USER_PRIVILEGE;
offset = 0;
result = OK;
} else {
#if ENABLE_USERPRIV && ENABLE_LOOSELDT
rp = proc_addr(m_ptr->m_source);
init_dataseg(&rp->p_ldt[EXTRA_LDT_INDEX], phys & ~0xFFFF, 0,
USER_PRIVILEGE);
selector = (EXTRA_LDT_INDEX * 0x08) | (1 * 0x04) | USER_PRIVILEGE;
offset = phys & 0xFFFF;
result = OK;
#else
result = E2BIG; /* allow settings only */
#endif
}
}
#endif
#if 0
kprintf("do_phys2seg: proc %d", m_ptr->m_source);
kprintf(" phys %u", phys);
kprintf(" size %u", size);
kprintf(" sel %u", selector);
kprintf(" off %u\n", offset);
#endif
m_ptr->SEG_SELECT = selector;
m_ptr->SEG_OFFSET = offset;
return(result);
}

View File

@@ -0,0 +1,37 @@
/* The system call implemented in this file:
* m_type: SYS_PHYSCOPY
*
* The parameters for this system call are:
* m5_l1: CP_SRC_ADDR (physical source address)
* m5_l2: CP_DST_ADDR (physical destination address)
* m5_l3: CP_NR_BYTES (number of bytes to copy)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
#include "../kernel.h"
#include "../system.h"
/*===========================================================================*
* do_physcopy *
*===========================================================================*/
PUBLIC int do_physcopy(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Handle sys_physcopy(). Copy data by using physical addressing. */
phys_bytes src_phys, dst_phys, bytes;
/* Dismember the command message. */
src_phys = (phys_bytes) m_ptr->CP_SRC_ADDR;
dst_phys = (phys_bytes) m_ptr->CP_DST_ADDR;
bytes = (phys_bytes) m_ptr->CP_NR_BYTES;
/* Do some checks and copy the data. */
if (src_phys == 0 || dst_phys == 0) return(EFAULT);
phys_copy(src_phys, dst_phys, bytes);
return(OK);
}

View File

@@ -0,0 +1,60 @@
/* The system call implemented in this file:
* m_type: SYS_SDEVIO
*
* The parameters for this system call are:
* m2_i3: DIO_REQUEST (request input or output)
* m2_i1: DIO_TYPE (flag indicating byte, word, or long)
* m2_l1: DIO_PORT (port to read/ write)
* m2_p1: DIO_VEC_ADDR (virtual address of buffer)
* m2_l2: DIO_VEC_SIZE (number of elements)
* m2_i2: DIO_VEC_PROC (process where buffer is)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
#include "../kernel.h"
#include "../system.h"
#include <minix/devio.h>
/*===========================================================================*
* do_sdevio *
*===========================================================================*/
PUBLIC int do_sdevio(m_ptr)
register message *m_ptr; /* pointer to request message */
{
int proc_nr = m_ptr->DIO_VEC_PROC;
int count = m_ptr->DIO_VEC_SIZE;
long port = m_ptr->DIO_PORT;
phys_bytes phys_buf;
/* Check if process number is OK. */
if (proc_nr == SELF) proc_nr = m_ptr->m_source;
if (! isokprocn(proc_nr))
return(EINVAL);
/* Get and check physical address. */
if ((phys_buf = numap_local(proc_nr, (vir_bytes) m_ptr->DIO_VEC_ADDR, count)) == 0)
return(EFAULT);
/* Perform device I/O for bytes and words. Longs are not supported. */
if (m_ptr->DIO_REQUEST == DIO_INPUT) {
switch (m_ptr->DIO_TYPE) {
case DIO_BYTE: phys_insb(port, phys_buf, count); break;
case DIO_WORD: phys_insw(port, phys_buf, count); break;
default: return(EINVAL);
}
} else if (m_ptr->DIO_REQUEST == DIO_OUTPUT) {
switch (m_ptr->DIO_TYPE) {
case DIO_BYTE: phys_outsb(port, phys_buf, count); break;
case DIO_WORD: phys_outsw(port, phys_buf, count); break;
default: return(EINVAL);
}
}
else {
return(EINVAL);
}
return(OK);
}

View File

@@ -0,0 +1,72 @@
/* The system call implemented in this file:
* m_type: SYS_SIGRETURN
*
* The parameters for this system call are:
* m2_i1: SIG_PROC (process number)
* m2_i3: SIG_FLAGS (sig return flags) (unused)
* m2_p1: SIG_CTXT_PTR (pointer to sigcontext structure)
*/
#include "../kernel.h"
#include "../system.h"
#include <signal.h>
#include <sys/sigcontext.h>
INIT_ASSERT
/*===========================================================================*
* do_sigreturn *
*===========================================================================*/
PUBLIC int do_sigreturn(m_ptr)
register message *m_ptr;
{
/* POSIX style signals require sys_sigreturn to put things in order before the
* signalled process can resume execution
*/
struct sigcontext sc;
register struct proc *rp;
phys_bytes src_phys;
rp = proc_addr(m_ptr->SIG_PROC);
if (! isuserp(rp))
printf("message source: %d; rp: %d\n", m_ptr->m_source, rp->p_nr);
assert(isuserp(rp));
/* Copy in the sigcontext structure. */
src_phys = umap_local(rp, D, (vir_bytes) m_ptr->SIG_CTXT_PTR,
(vir_bytes) sizeof(struct sigcontext));
if (src_phys == 0) return(EFAULT);
phys_copy(src_phys, vir2phys(&sc), (phys_bytes) sizeof(struct sigcontext));
/* Make sure that this is not just a jmp_buf. */
if ((sc.sc_flags & SC_SIGCONTEXT) == 0) return(EINVAL);
/* Fix up only certain key registers if the compiler doesn't use
* register variables within functions containing setjmp.
*/
if (sc.sc_flags & SC_NOREGLOCALS) {
rp->p_reg.retreg = sc.sc_retreg;
rp->p_reg.fp = sc.sc_fp;
rp->p_reg.pc = sc.sc_pc;
rp->p_reg.sp = sc.sc_sp;
return (OK);
}
sc.sc_psw = rp->p_reg.psw;
#if (CHIP == INTEL)
/* Don't panic kernel if user gave bad selectors. */
sc.sc_cs = rp->p_reg.cs;
sc.sc_ds = rp->p_reg.ds;
sc.sc_es = rp->p_reg.es;
#if _WORD_SIZE == 4
sc.sc_fs = rp->p_reg.fs;
sc.sc_gs = rp->p_reg.gs;
#endif
#endif
/* Restore the registers. */
memcpy(&rp->p_reg, (char *)&sc.sc_regs, sizeof(struct sigregs));
return(OK);
}

View File

@@ -0,0 +1,67 @@
/* The system call implemented in this file:
* m_type: SYS_SVRCTL
*
* The parameters for this system call are:
* m2_i1: CTL_PROC_NR (process number of caller)
* m2_i2: CTL_REQUEST (request type)
* m2_i3: CTL_MM_PRIV (privilege)
* m2_l1: CTL_SEND_MASK (new send mask to be installed)
* m2_l2: CTL_PROC_TYPE (new process type)
* m2_p1: CTL_ARG_PTR (argument pointer)
*/
#include "../kernel.h"
#include "../system.h"
#include <sys/svrctl.h>
#include "../sendmask.h"
/*===========================================================================*
* do_svrctl *
*===========================================================================*/
PUBLIC int do_svrctl(m_ptr)
message *m_ptr; /* pointer to request message */
{
register struct proc *rp;
int proc_nr, priv;
int request;
vir_bytes argp;
/* Extract message parameters. */
proc_nr = m_ptr->CTL_PROC_NR;
if (proc_nr == SELF) proc_nr = m_ptr->m_source;
if (! isokprocn(proc_nr)) return(EINVAL);
request = m_ptr->CTL_REQUEST;
priv = m_ptr->CTL_MM_PRIV;
argp = (vir_bytes) m_ptr->CTL_ARG_PTR;
rp = proc_addr(proc_nr);
/* Check if the MM privileges are super user. */
if (!priv || !isuserp(rp))
return(EPERM);
/* See what is requested and handle the request. */
switch (request) {
case SYSSIGNON: {
/* Make this process a server. The system processes should be able
* to communicate with this new server, so update their send masks
* as well.
*/
/* fall through */
}
case SYSSENDMASK: {
rp->p_type = P_SERVER;
rp->p_sendmask = ALLOW_ALL_MASK;
send_mask_allow(proc_addr(RTL8139)->p_sendmask, proc_nr);
send_mask_allow(proc_addr(MM_PROC_NR)->p_sendmask, proc_nr);
send_mask_allow(proc_addr(FS_PROC_NR)->p_sendmask, proc_nr);
send_mask_allow(proc_addr(IS_PROC_NR)->p_sendmask, proc_nr);
send_mask_allow(proc_addr(CLOCK)->p_sendmask, proc_nr);
send_mask_allow(proc_addr(SYSTASK)->p_sendmask, proc_nr);
return(OK);
}
default:
return(EINVAL);
}
}

View File

@@ -0,0 +1,33 @@
/* The system call implemented in this file:
* m_type: SYS_UMAP
*
* The parameters for this system call are:
* m5_i1: CP_SRC_PROC_NR (process number)
* m5_c1: CP_SRC_SPACE (segment where address is: T, D, or S)
* m5_l1: CP_SRC_ADDR (virtual address)
* m5_l2: CP_DST_ADDR (returns physical address)
* m5_l3: CP_NR_BYTES (size of datastructure)
*/
#include "../kernel.h"
#include "../system.h"
/*==========================================================================*
* do_umap *
*==========================================================================*/
PUBLIC int do_umap(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Same as umap_local(), for non-kernel processes. */
int proc_nr = (int) m_ptr->CP_SRC_PROC_NR;
if (proc_nr == SELF) proc_nr = m_ptr->m_source;
if (! isokprocn(proc_nr)) return(EINVAL);
m_ptr->CP_DST_ADDR = umap_local(proc_addr(proc_nr),
(int) m_ptr->CP_SRC_SPACE,
(vir_bytes) m_ptr->CP_SRC_ADDR,
(vir_bytes) m_ptr->CP_NR_BYTES);
return(OK);
}

View File

@@ -0,0 +1,126 @@
/* The system call implemented in this file:
* m_type: SYS_VDEVIO
*
* The parameters for this system call are:
* m2_i3: DIO_REQUEST (request input or output)
* m2_i1: DIO_TYPE (flag indicating byte, word, or long)
* m2_p1: DIO_VEC_ADDR (pointer to port/ value pairs)
* m2_i2: DIO_VEC_SIZE (number of ports to read or write)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
#include "../kernel.h"
#include "../system.h"
#include <minix/devio.h>
/* Buffer for SYS_VDEVIO to copy (port,value)-pairs from/ to user. */
PRIVATE char vdevio_pv_buf[VDEVIO_BUF_SIZE];
/* SYS_VDEVIO sends a pointer to a (port,value)-pairs vector at the caller.
* Define the maximum number of (port,value)-pairs that can be handled in a
* in a single SYS_VDEVIO system call based on the struct definitions.
*/
#define MAX_PVB_PAIRS ((VDEVIO_BUF_SIZE * sizeof(char)) / sizeof(pvb_pair_t))
#define MAX_PVW_PAIRS ((VDEVIO_BUF_SIZE * sizeof(char)) / sizeof(pvw_pair_t))
#define MAX_PVL_PAIRS ((VDEVIO_BUF_SIZE * sizeof(char)) / sizeof(pvl_pair_t))
/*===========================================================================*
* do_vdevio *
*===========================================================================*/
PUBLIC int do_vdevio(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Perform a series of device I/O on behalf of a non-kernel process. The
* I/O addresses and I/O values are fetched from and returned to some buffer
* in user space. The actual I/O is wrapped by lock() and unlock() to prevent
* that I/O batch from being interrrupted.
* This is the counterpart of do_devio, which performs a single device I/O.
*/
pvb_pair_t *pvb_pairs; /* needed for byte values */
pvw_pair_t *pvw_pairs; /* needed for word values */
pvl_pair_t *pvl_pairs; /* needed for long values */
int i;
pid_t caller_pid; /* process id of caller */
size_t bytes; /* # bytes to be copied */
vir_bytes caller_vir; /* virtual address at caller */
phys_bytes caller_phys; /* physical address at caller */
phys_bytes kernel_phys; /* physical address in kernel */
/* Check if nr of ports is ok and get size of (port,value) data. */
if (m_ptr->DIO_VEC_SIZE <= 0) return(EINVAL);
switch(m_ptr->DIO_TYPE) {
case DIO_BYTE:
if (m_ptr->DIO_VEC_SIZE > MAX_PVB_PAIRS) return(EINVAL);
bytes = (size_t) (m_ptr->DIO_VEC_SIZE * sizeof(pvb_pair_t));
break;
case DIO_WORD:
if (m_ptr->DIO_VEC_SIZE > MAX_PVW_PAIRS) return(EINVAL);
bytes = (size_t) (m_ptr->DIO_VEC_SIZE * sizeof(pvw_pair_t));
break;
case DIO_LONG:
if (m_ptr->DIO_VEC_SIZE > MAX_PVL_PAIRS) return(EINVAL);
bytes = (size_t) (m_ptr->DIO_VEC_SIZE * sizeof(pvl_pair_t));
break;
default: /* this once and for all checks for a correct type */
return(EINVAL);
}
/* Calculate physical addresses and copy (port,value)-pairs from user. */
caller_pid = (pid_t) m_ptr->m_source;
caller_vir = (vir_bytes) m_ptr->DIO_VEC_ADDR;
caller_phys = umap_local(proc_addr(caller_pid), D, caller_vir, bytes);
if (0 == caller_phys) return EFAULT;
kernel_phys = vir2phys(vdevio_pv_buf);
phys_copy(caller_phys, kernel_phys, (phys_bytes) bytes);
/* Perform actual device I/O for byte, word, and long values. Note that
* the entire switch is wrapped in lock() and unlock() to prevent the I/O
* batch from being interrupted. It may be cleaner to do this just around
* the for loops, but this results in rather lenghty code.
*/
lock();
switch (m_ptr->DIO_TYPE) {
case DIO_BYTE: /* byte values */
pvb_pairs = (pvb_pair_t *) vdevio_pv_buf;
if (DIO_INPUT == m_ptr->DIO_REQUEST) {
for (i=0; i < m_ptr->DIO_VEC_SIZE; i++)
pvb_pairs[i].value = inb(pvb_pairs[i].port);
} else {
for (i=0; i < m_ptr->DIO_VEC_SIZE; i++)
outb(pvb_pairs[i].port, pvb_pairs[i].value);
}
break;
case DIO_WORD: /* word values */
pvw_pairs = (pvw_pair_t *) vdevio_pv_buf;
if (DIO_INPUT == m_ptr->DIO_REQUEST) {
for (i=0; i < m_ptr->DIO_VEC_SIZE; i++)
pvw_pairs[i].value = inw(pvw_pairs[i].port);
} else {
for (i=0; i < m_ptr->DIO_VEC_SIZE; i++)
outw(pvw_pairs[i].port, pvw_pairs[i].value);
}
break;
case DIO_LONG: /* fall through: long values */
default: /* only DIO_LONG can arrive here, see above switch */
pvl_pairs = (pvl_pair_t *) vdevio_pv_buf;
if (DIO_INPUT == m_ptr->DIO_REQUEST) {
for (i=0; i < m_ptr->DIO_VEC_SIZE; i++)
pvl_pairs[i].value = inl(pvl_pairs[i].port);
} else {
for (i=0; i < m_ptr->DIO_VEC_SIZE; i++)
outl(pvb_pairs[i].port, pvl_pairs[i].value);
}
}
unlock();
/* Almost done, copy back results for input requests. */
if (DIO_INPUT == m_ptr->REQUEST)
phys_copy(kernel_phys, caller_phys, (phys_bytes) bytes);
return(OK);
}

View File

@@ -0,0 +1,69 @@
/* The system call implemented in this file:
* m_type: SYS_VIRCOPY
*
* The parameters for this system call are:
* m5_c1: CP_SRC_SPACE
* m5_l1: CP_SRC_ADDR
* m5_i1: CP_SRC_PROC_NR
* m5_c2: CP_DST_SPACE
* m5_l2: CP_DST_ADDR
* m5_i2: CP_DST_PROC_NR
* m5_l3: CP_NR_BYTES
*/
#include "../kernel.h"
#include "../system.h"
/*===========================================================================*
* do_vircopy *
*===========================================================================*/
PUBLIC int do_vircopy(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Handle sys_vircopy(). Copy data by using virtual addressing. */
struct vir_addr vir_addr[2]; /* virtual source and destination address */
vir_bytes bytes; /* number of bytes to copy */
int i;
/* Dismember the command message. */
vir_addr[_SRC_].proc_nr = m_ptr->CP_SRC_PROC_NR;
vir_addr[_SRC_].segment = m_ptr->CP_SRC_SPACE;
vir_addr[_SRC_].offset = (vir_bytes) m_ptr->CP_SRC_ADDR;
vir_addr[_DST_].proc_nr = m_ptr->CP_DST_PROC_NR;
vir_addr[_DST_].segment = m_ptr->CP_DST_SPACE;
vir_addr[_DST_].offset = (vir_bytes) m_ptr->CP_DST_ADDR;
bytes = (phys_bytes) m_ptr->CP_NR_BYTES;
/* Now do some checks for both the source and destination virtual address.
* This is done once for _SRC_, then once for _DST_.
*/
for (i=_SRC_; i<=_DST_; i++) {
/* 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)) {
kprintf("do_vircopy: illegal proc nr\n",NO_ARG);
return(EINVAL);
}
/* Copying from or to special segments can only done by the owner. */
if ((vir_addr[i].segment & SEGMENT_TYPE) != LOCAL_SEG &&
vir_addr[i].proc_nr != m_ptr->m_source) {
kprintf("do_vircopy: special seg permission denied\n", NO_ARG);
return(EPERM);
}
}
/* Check for overflow. This would happen for 64K segments and 16-bit
* vir_bytes. Especially copying by the MM on do_fork() is affected.
*/
if (bytes != (vir_bytes) bytes) {
kprintf("do_vircopy: overflow\n", NO_ARG);
return(E2BIG);
}
/* Now try to make the actual virtual copy. */
return( virtual_copy(&vir_addr[_SRC_], &vir_addr[_DST_], bytes) );
}

View File

@@ -0,0 +1,38 @@
/*===========================================================================*
* do_xit *
*===========================================================================*/
PUBLIC int do_xit(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Handle sys_exit. A user process has exited (the MM sent the request).
*/
register struct proc *rp, *rc;
struct proc *np, *xp;
int exit_proc_nr;
/* Get a pointer to the process that exited. */
exit_proc_nr = m_ptr->PR_PROC_NR;
if (exit_proc_nr == SELF) exit_proc_nr = m_ptr->m_source;
if (! isokprocn(exit_proc_nr)) return(EINVAL);
rc = proc_addr(exit_proc_nr);
/* If this is a user process and the MM passed in a valid parent process,
* accumulate the child times at the parent.
*/
if (isuserp(rc) && isokprocn(m_ptr->PR_PPROC_NR)) {
rp = proc_addr(m_ptr->PR_PPROC_NR);
lock();
rp->child_utime += rc->user_time + rc->child_utime;
rp->child_stime += rc->sys_time + rc->child_stime;
unlock();
}
/* Now call the routine to clean up of the process table slot. This cancels
* outstanding timers, possibly removes the process from the message queues,
* and resets important process table fields.
*/
clear_proc(exit_proc_nr);
return(OK); /* tell MM that cleanup succeeded */
}

223
kernel/system/proctl.c Normal file
View File

@@ -0,0 +1,223 @@
/* The system call implemented in this file:
* m_type: SYS_FORK
*
* The parameters for this system call are:
* m1_i1: PR_PROC_NR (child's process table slot)
* m1_i2: PR_PPROC_NR (parent, process that forked)
* m1_i3: PR_PID (child pid received from MM)
*/
#include "../kernel.h"
#include "../system.h"
#include "../sendmask.h"
#include <signal.h>
#if (CHIP == INTEL)
#include "../protect.h"
#endif
INIT_ASSERT
/*===========================================================================*
* do_fork *
*===========================================================================*/
PUBLIC int do_fork(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Handle sys_fork(). PR_PPROC_NR has forked. The child is PR_PROC_NR. */
#if (CHIP == INTEL)
reg_t old_ldt_sel;
#endif
register struct proc *rpc;
struct proc *rpp;
rpp = proc_addr(m_ptr->PR_PPROC_NR);
assert(isuserp(rpp));
rpc = proc_addr(m_ptr->PR_PROC_NR);
assert(isemptyp(rpc));
/* Copy parent 'proc' struct to child. */
#if (CHIP == INTEL)
old_ldt_sel = rpc->p_ldt_sel; /* stop this being obliterated by copy */
#endif
*rpc = *rpp; /* copy 'proc' struct */
#if (CHIP == INTEL)
rpc->p_ldt_sel = old_ldt_sel;
#endif
rpc->p_nr = m_ptr->PR_PROC_NR; /* this was obliterated by copy */
rpc->p_flags |= NO_MAP; /* inhibit the process from running */
rpc->p_flags &= ~(PENDING | SIG_PENDING | P_STOP);
/* Only 1 in group should have PENDING, child does not inherit trace status*/
sigemptyset(&rpc->p_pending);
rpc->p_pendcount = 0;
rpc->p_reg.retreg = 0; /* child sees pid = 0 to know it is child */
rpc->user_time = 0; /* set all the accounting times to 0 */
rpc->sys_time = 0;
rpc->child_utime = 0;
rpc->child_stime = 0;
return(OK);
}
/* The system call implemented in this file:
* m_type: SYS_NEWMAP
*
* The parameters for this system call are:
* m1_i1: PR_PROC_NR (install new map for this process)
* m1_p1: PR_MEM_PTR (pointer to memory map)
*/
/*===========================================================================*
* do_newmap *
*===========================================================================*/
PUBLIC int do_newmap(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Handle sys_newmap(). Fetch the memory map from MM. */
register struct proc *rp;
phys_bytes src_phys;
int caller; /* whose space has the new map (usually MM) */
int k; /* process whose map is to be loaded */
int old_flags; /* value of flags before modification */
struct mem_map *map_ptr; /* virtual address of map inside caller (MM) */
/* Extract message parameters and copy new memory map from MM. */
caller = m_ptr->m_source;
k = m_ptr->PR_PROC_NR;
map_ptr = (struct mem_map *) m_ptr->PR_MEM_PTR;
if (!isokprocn(k)) return(EINVAL);
rp = proc_addr(k); /* ptr to entry of user getting new map */
/* Copy the map from MM. */
src_phys = umap_local(proc_addr(caller), D, (vir_bytes) map_ptr,
sizeof(rp->p_memmap));
assert(src_phys != 0);
phys_copy(src_phys,vir2phys(rp->p_memmap),(phys_bytes)sizeof(rp->p_memmap));
#if (CHIP != M68000)
alloc_segments(rp);
#else
pmmu_init_proc(rp);
#endif
old_flags = rp->p_flags; /* save the previous value of the flags */
rp->p_flags &= ~NO_MAP;
if (old_flags != 0 && rp->p_flags == 0) lock_ready(rp);
return(OK);
}
/* The system call implemented in this file:
* m_type: SYS_EXEC
*
* The parameters for this system call are:
* m1_i1: PR_PROC_NR (process that did exec call)
* m1_i3: PR_TRACING (flag to indicate tracing is on/ off)
* m1_p1: PR_STACK_PTR (new stack pointer)
* m1_p2: PR_NAME_PTR (pointer to program name)
* m1_p3: PR_IP_PTR (new instruction pointer)
*/
/*===========================================================================*
* do_exec *
*===========================================================================*/
PUBLIC int do_exec(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Handle sys_exec(). A process has done a successful EXEC. Patch it up. */
register struct proc *rp;
reg_t sp; /* new sp */
phys_bytes phys_name;
char *np;
#define NLEN (sizeof(rp->p_name)-1)
rp = proc_addr(m_ptr->PR_PROC_NR);
assert(isuserp(rp));
if (m_ptr->PR_TRACING) cause_sig(m_ptr->PR_PROC_NR, SIGTRAP);
sp = (reg_t) m_ptr->PR_STACK_PTR;
rp->p_reg.sp = sp; /* set the stack pointer */
#if (CHIP == M68000)
rp->p_splow = sp; /* set the stack pointer low water */
#ifdef FPP
/* Initialize fpp for this process */
fpp_new_state(rp);
#endif
#endif
#if (CHIP == INTEL) /* wipe extra LDT entries */
kmemset(&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 */
rp->p_flags &= ~RECEIVING; /* MM does not reply to EXEC call */
if (rp->p_flags == 0) lock_ready(rp);
/* Save command name for debugging, ps(1) output, etc. */
phys_name = numap_local(m_ptr->m_source, (vir_bytes) m_ptr->PR_NAME_PTR,
(vir_bytes) NLEN);
if (phys_name != 0) {
phys_copy(phys_name, vir2phys(rp->p_name), (phys_bytes) NLEN);
for (np = rp->p_name; (*np & BYTE) >= ' '; np++) {}
*np = 0;
}
return(OK);
}
/* The system call implemented in this file:
* m_type: SYS_XIT
*
* The parameters for this system call are:
* m1_i1: PR_PROC_NR (slot number of exiting process)
* m1_i2: PR_PPROC_NR (slot number of parent process)
*/
/*===========================================================================*
* do_xit *
*===========================================================================*/
PUBLIC int do_xit(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Handle sys_exit. A user process has exited (the MM sent the request).
*/
register struct proc *rp, *rc;
struct proc *np, *xp;
int exit_proc_nr;
/* Get a pointer to the process that exited. */
exit_proc_nr = m_ptr->PR_PROC_NR;
if (exit_proc_nr == SELF) exit_proc_nr = m_ptr->m_source;
if (! isokprocn(exit_proc_nr)) return(EINVAL);
rc = proc_addr(exit_proc_nr);
/* If this is a user process and the MM passed in a valid parent process,
* accumulate the child times at the parent.
*/
if (isuserp(rc) && isokprocn(m_ptr->PR_PPROC_NR)) {
rp = proc_addr(m_ptr->PR_PPROC_NR);
lock();
rp->child_utime += rc->user_time + rc->child_utime;
rp->child_stime += rc->sys_time + rc->child_stime;
unlock();
}
/* Now call the routine to clean up of the process table slot. This cancels
* outstanding timers, possibly removes the process from the message queues,
* and resets important process table fields.
*/
clear_proc(exit_proc_nr);
return(OK); /* tell MM that cleanup succeeded */
}

227
kernel/system/sigctl.c Normal file
View File

@@ -0,0 +1,227 @@
/* The system call that is implemented in this file:
* SYS_SIGCTL # signal handling functionality
*
* The parameters and types for this system call are:
* SIG_REQUEST # request to perform (long)
* SIG_PROC # process to signal/ pending (int)
* SIG_CTXT_PTR # pointer to sigcontext structure (pointer)
* SIG_FLAGS # flags for S_SIGRETURN call (int)
* SIG_MAP # bit map with pending signals (long)
* SIG_NUMBER # signal number to send to process (int)
*
* Supported request types are in the parameter SIG_REQUEST:
* S_GETSIG # get a pending kernel signal
* S_ENDSIG # signal has been processed
* S_SENDSIG # deliver a POSIX-style signal
* S_SIGRETURN # return from a POSIX-style signal
* S_KILL # send a signal to a process
*/
#include "../kernel.h"
#include "../system.h"
#include <signal.h>
#include <sys/sigcontext.h>
INIT_ASSERT
/*===========================================================================*
* do_sigctl *
*===========================================================================*/
PUBLIC int do_sigctl(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Only the MM and FS are allowed to use signal control operations. */
if (m_ptr->m_source != MM_PROC_NR && m_ptr->m_source != FS_PROC_NR)
return(EPERM);
/* Now see what request we got. The supported requests are S_GETSIG,
* S_ENDSIG, S_SENDSIG, S_SIGRETURN, and S_KILL. Unsupported requests
* result in an EINVAL error.
*/
switch(m_ptr->SIG_REQUEST) {
/* MM is ready to accept signals and repeatedly does a system call to get
* one. Find a process with pending signals. If no signals are available,
* return NONE in the process number field.
*/
case S_GETSIG: {
register struct proc *rp;
/* Find the next process with pending signals. */
for (rp = BEG_USER_ADDR; rp < END_PROC_ADDR; rp++) {
if (rp->p_flags & PENDING) {
m_ptr->SIG_PROC = proc_number(rp);
m_ptr->SIG_MAP = rp->p_pending;
sigemptyset(&rp->p_pending); /* ball is in MM's court */
rp->p_flags &= ~PENDING; /* blocked by SIG_PENDING */
return(OK);
}
}
/* No process with pending signals was found. */
m_ptr->SIG_PROC = NONE;
return(OK);
}
/* Finish up after a KSIG-type signal, caused by a SYS_KILL message or a
* call to cause_sig by a task
*/
case S_ENDSIG: {
register struct proc *rp;
rp = proc_addr(m_ptr->SIG_PROC);
if (isemptyp(rp)) return(EINVAL); /* process already dead? */
assert(isuserp(rp));
/* MM has finished one KSIG. Perhaps process is ready now? */
if (rp->p_pendcount != 0 && --rp->p_pendcount == 0
&& (rp->p_flags &= ~SIG_PENDING) == 0)
lock_ready(rp);
return(OK);
}
/* Handle sys_sendsig, POSIX-style signal handling.
*/
case S_SENDSIG: {
struct sigmsg smsg;
register struct proc *rp;
phys_bytes src_phys, dst_phys;
struct sigcontext sc, *scp;
struct sigframe fr, *frp;
rp = proc_addr(m_ptr->SIG_PROC);
assert(isuserp(rp));
/* Get the sigmsg structure into our address space. */
src_phys = umap_local(proc_addr(MM_PROC_NR), D, (vir_bytes)
m_ptr->SIG_CTXT_PTR, (vir_bytes) sizeof(struct sigmsg));
assert(src_phys != 0);
phys_copy(src_phys,vir2phys(&smsg),(phys_bytes) sizeof(struct sigmsg));
/* Compute the user stack pointer where sigcontext will be stored. */
scp = (struct sigcontext *) smsg.sm_stkptr - 1;
/* Copy the registers to the sigcontext structure. */
kmemcpy(&sc.sc_regs, &rp->p_reg, sizeof(struct sigregs));
/* Finish the sigcontext initialization. */
sc.sc_flags = SC_SIGCONTEXT;
sc.sc_mask = smsg.sm_mask;
/* Copy the sigcontext structure to the user's stack. */
dst_phys = umap_local(rp, D, (vir_bytes) scp,
(vir_bytes) sizeof(struct sigcontext));
if (dst_phys == 0) return(EFAULT);
phys_copy(vir2phys(&sc), dst_phys,
(phys_bytes) sizeof(struct sigcontext));
/* Initialize the sigframe structure. */
frp = (struct sigframe *) scp - 1;
fr.sf_scpcopy = scp;
fr.sf_retadr2= (void (*)()) rp->p_reg.pc;
fr.sf_fp = rp->p_reg.fp;
rp->p_reg.fp = (reg_t) &frp->sf_fp;
fr.sf_scp = scp;
fr.sf_code = 0; /* XXX - should be used for type of FP exception */
fr.sf_signo = smsg.sm_signo;
fr.sf_retadr = (void (*)()) smsg.sm_sigreturn;
/* Copy the sigframe structure to the user's stack. */
dst_phys = umap_local(rp, D, (vir_bytes) frp,
(vir_bytes) sizeof(struct sigframe));
if (dst_phys == 0) return(EFAULT);
phys_copy(vir2phys(&fr), dst_phys,
(phys_bytes) sizeof(struct sigframe));
/* Reset user registers to execute the signal handler. */
rp->p_reg.sp = (reg_t) frp;
rp->p_reg.pc = (reg_t) smsg.sm_sighandler;
return(OK);
}
/* POSIX style signals require sys_sigreturn to put things in order before
* the signalled process can resume execution
*/
case S_SIGRETURN: {
struct sigcontext sc;
register struct proc *rp;
phys_bytes src_phys;
rp = proc_addr(m_ptr->SIG_PROC);
if (! isuserp(rp)) {
kprintf("S_SIGRETURN: message source: %d; ", m_ptr->m_source);
kprintf("got non-user process rp: %d\n", rp->p_nr);
}
assert(isuserp(rp));
/* Copy in the sigcontext structure. */
src_phys = umap_local(rp, D, (vir_bytes) m_ptr->SIG_CTXT_PTR,
(vir_bytes) sizeof(struct sigcontext));
if (src_phys == 0) return(EFAULT);
phys_copy(src_phys, vir2phys(&sc),
(phys_bytes) sizeof(struct sigcontext));
/* Make sure that this is not just a jmp_buf. */
if ((sc.sc_flags & SC_SIGCONTEXT) == 0) return(EINVAL);
/* Fix up only certain key registers if the compiler doesn't use
* register variables within functions containing setjmp.
*/
if (sc.sc_flags & SC_NOREGLOCALS) {
rp->p_reg.retreg = sc.sc_retreg;
rp->p_reg.fp = sc.sc_fp;
rp->p_reg.pc = sc.sc_pc;
rp->p_reg.sp = sc.sc_sp;
return(OK);
}
sc.sc_psw = rp->p_reg.psw;
#if (CHIP == INTEL)
/* Don't panic kernel if user gave bad selectors. */
sc.sc_cs = rp->p_reg.cs;
sc.sc_ds = rp->p_reg.ds;
sc.sc_es = rp->p_reg.es;
#if _WORD_SIZE == 4
sc.sc_fs = rp->p_reg.fs;
sc.sc_gs = rp->p_reg.gs;
#endif
#endif
/* Restore the registers. */
kmemcpy(&rp->p_reg, (char *)&sc.sc_regs, sizeof(struct sigregs));
return(OK);
}
/* Handle sys_kill(). Cause a signal to be sent to a process via MM.
* Note that this has nothing to do with the kill(2) system call, this
* is how the FS (and possibly other servers) get access to cause_sig.
*/
case S_KILL: {
cause_sig(m_ptr->SIG_PROC, m_ptr->SIG_NUMBER);
return(OK);
}
default:
return(EINVAL);
}
}
PUBLIC int do_kill(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Handle sys_kill(). Cause a signal to be sent to a process via MM.
* Note that this has nothing to do with the kill (2) system call, this
* is how the FS (and possibly other servers) get access to cause_sig.
*/
cause_sig(m_ptr->SIG_PROC, m_ptr->SIG_NUMBER);
return(OK);
}

241
kernel/system/srvrctl.c Normal file
View File

@@ -0,0 +1,241 @@
/* The system call implemented in this file:
* m_type: SYS_EXIT
*
* The parameters for this system call are:
* m1_i1: EXIT_STATUS (exit status, 0 if normal exit)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
#include "../kernel.h"
#include "../system.h"
#include "../protect.h"
#include <sys/svrctl.h>
#include "../sendmask.h"
/*===========================================================================*
* do_exit *
*===========================================================================*/
PUBLIC int do_exit(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Handle sys_exit. A server or driver wants to exit. This may happen
* on a panic, but also is done when MINIX is shutdown.
*/
register struct proc *rp;
int proc_nr = m_ptr->m_source; /* can only exit own process */
if (m_ptr->EXIT_STATUS != 0) {
kprintf("WARNING: system process %d exited with an error.\n", proc_nr );
}
/* Now call the routine to clean up of the process table slot. This cancels
* outstanding timers, possibly removes the process from the message queues,
* and reset important process table fields.
*/
clear_proc(proc_nr);
/* If the shutdown sequence is active, see if it was awaiting the shutdown
* of this system service. If so, directly continue the stop sequence.
*/
if (shutting_down && shutdown_process == proc_addr(proc_nr)) {
stop_sequence(&shutdown_timer);
}
return(EDONTREPLY); /* no reply is sent */
}
/* The system call implemented in this file:
* m_type: SYS_SVRCTL
*
* The parameters for this system call are:
* m2_i1: CTL_PROC_NR (process number of caller)
* m2_i2: CTL_REQUEST (request type)
* m2_i3: CTL_MM_PRIV (privilege)
* m2_l1: CTL_SEND_MASK (new send mask to be installed)
* m2_l2: CTL_PROC_TYPE (new process type)
* m2_p1: CTL_ARG_PTR (argument pointer)
*/
/*===========================================================================*
* do_svrctl *
*===========================================================================*/
PUBLIC int do_svrctl(m_ptr)
message *m_ptr; /* pointer to request message */
{
register struct proc *rp;
int proc_nr, priv;
int request;
vir_bytes argp;
/* Extract message parameters. */
proc_nr = m_ptr->CTL_PROC_NR;
if (proc_nr == SELF) proc_nr = m_ptr->m_source;
if (! isokprocn(proc_nr)) return(EINVAL);
request = m_ptr->CTL_REQUEST;
priv = m_ptr->CTL_MM_PRIV;
argp = (vir_bytes) m_ptr->CTL_ARG_PTR;
rp = proc_addr(proc_nr);
/* Check if the MM privileges are super user. */
if (!priv || !isuserp(rp))
return(EPERM);
/* See what is requested and handle the request. */
switch (request) {
case SYSSIGNON: {
/* Make this process a server. The system processes should be able
* to communicate with this new server, so update their send masks
* as well.
*/
/* fall through */
}
case SYSSENDMASK: {
rp->p_type = P_SERVER;
rp->p_sendmask = ALLOW_ALL_MASK;
send_mask_allow(proc_addr(RTL8139)->p_sendmask, proc_nr);
send_mask_allow(proc_addr(MM_PROC_NR)->p_sendmask, proc_nr);
send_mask_allow(proc_addr(FS_PROC_NR)->p_sendmask, proc_nr);
send_mask_allow(proc_addr(IS_PROC_NR)->p_sendmask, proc_nr);
send_mask_allow(proc_addr(CLOCK)->p_sendmask, proc_nr);
send_mask_allow(proc_addr(SYSTASK)->p_sendmask, proc_nr);
return(OK);
}
default:
return(EINVAL);
}
}
/* The system call implemented in this file:
* m_type: SYS_MEMCTL
*
* The parameters for this system call are:
* m4_l3: SEG_PHYS (physical base address)
* m4_l4: SEG_SIZE (size of segment)
* m4_l1: SEG_SELECT (return segment selector here)
* m4_l2: SEG_OFFSET (return offset within segment here)
* m4_l5: SEG_INDEX (return index into remote memory map here)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
/*===========================================================================*
* do_phys2seg *
*===========================================================================*/
PUBLIC int do_phys2seg(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Return a segment selector and offset that can be used to reach a physical
* address, for use by a driver doing memory I/O in the A0000 - DFFFF range.
*/
u16_t selector;
vir_bytes offset;
register struct proc *rp;
phys_bytes phys = (phys_bytes) m_ptr->SEG_PHYS;
vir_bytes size = (vir_bytes) m_ptr->SEG_SIZE;
int result;
kprintf("Using Experimental LDT selector for video memory\n", NO_ARG);
if (!protected_mode) {
selector = phys / HCLICK_SIZE;
offset = phys % HCLICK_SIZE;
result = OK;
} else {
/* Check if the segment size can be recorded in bytes, that is, check
* if descriptor's limit field can delimited the allowed memory region
* precisely. This works up to 1MB. If the size is larger, 4K pages
* instead of bytes are used.
*/
if (size < BYTE_GRAN_MAX) {
rp = proc_addr(m_ptr->m_source);
init_dataseg(&rp->p_ldt[EXTRA_LDT_INDEX], phys, size,
USER_PRIVILEGE);
selector = (EXTRA_LDT_INDEX * 0x08) | (1 * 0x04) | USER_PRIVILEGE;
offset = 0;
result = OK;
} else {
#if ENABLE_USERPRIV && ENABLE_LOOSELDT
rp = proc_addr(m_ptr->m_source);
init_dataseg(&rp->p_ldt[EXTRA_LDT_INDEX], phys & ~0xFFFF, 0,
USER_PRIVILEGE);
selector = (EXTRA_LDT_INDEX * 0x08) | (1 * 0x04) | USER_PRIVILEGE;
offset = phys & 0xFFFF;
result = OK;
#else
result = E2BIG; /* allow settings only */
#endif
}
}
m_ptr->SEG_SELECT = selector;
m_ptr->SEG_OFFSET = offset;
return(result);
}
/* The system call implemented in this file:
* m_type: SYS_IOPENABLE
*
* The parameters for this system call are:
* m2_i2: PROC_NR (process to give I/O Protection Level bits)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
/*===========================================================================*
* do_iopenable *
*===========================================================================*/
PUBLIC int do_iopenable(m_ptr)
register message *m_ptr; /* pointer to request message */
{
#if ENABLE_USERPRIV && ENABLE_USERIOPL
enable_iop(proc_addr(m_ptr->PROC_NR));
return(OK);
#else
return(EPERM);
#endif
}
/* The system call implemented in this file:
* m_type: SYS_KMALLOC
*
* The parameters for this system call are:
* m4_l2: MEM_CHUNK_SIZE (request a buffer of this size)
* m4_l1: MEM_CHUNK_BASE (return physical address on success)
*
* Author:
* Jorrit N. Herder <jnherder@cs.vu.nl>
*/
/*===========================================================================*
* do_kmalloc *
*===========================================================================*/
PUBLIC int do_kmalloc(m_ptr)
register message *m_ptr; /* pointer to request message */
{
/* Request a (DMA) buffer to be allocated in one of the memory chunks. */
phys_clicks tot_clicks;
struct memory *memp;
tot_clicks = (m_ptr->MEM_CHUNK_SIZE + CLICK_SIZE-1) >> CLICK_SHIFT;
memp = &mem[NR_MEMS];
while ((--memp)->size < tot_clicks) {
if (memp == mem) {
return(ENOMEM);
}
}
memp->size -= tot_clicks;
m_ptr->MEM_CHUNK_BASE = (memp->base + memp->size) << CLICK_SHIFT;
return(OK);
}

142
kernel/system/tracing.c Normal file
View File

@@ -0,0 +1,142 @@
/* The system call implemented in this file:
* m_type: SYS_TRACE
*
* The parameters for this system call are:
* m2_i1: CTL_PROC_NR process that is traced
* m2_i2: CTL_REQUEST trace request
* m2_l1: CTL_ADDRESS address at traced process' space
* m2_l2: CTL_DATA data to be written or returned here
*/
#include "../kernel.h"
#include "../system.h"
#include <sys/ptrace.h>
#if ENABLE_K_TRACING /* only include code if tracing is enabled */
/*==========================================================================*
* do_trace *
*==========================================================================*/
#define TR_VLSIZE ((vir_bytes) sizeof(long))
PUBLIC int do_trace(m_ptr)
register message *m_ptr;
{
/* Handle the debugging commands supported by the ptrace system call
* The commands are:
* T_STOP stop the process
* T_OK enable tracing by parent for this process
* T_GETINS return value from instruction space
* T_GETDATA return value from data space
* T_GETUSER return value from user process table
* T_SETINS set value from instruction space
* T_SETDATA set value from data space
* T_SETUSER set value in user process table
* T_RESUME resume execution
* T_EXIT exit
* T_STEP set trace bit
*
* The T_OK and T_EXIT commands are handled completely by the memory manager,
* all others come here.
*/
register struct proc *rp;
phys_bytes src, dst;
vir_bytes tr_addr = (vir_bytes) m_ptr->CTL_ADDRESS;
long tr_data = m_ptr->CTL_DATA;
int tr_request = m_ptr->CTL_REQUEST;
int tr_proc_nr = m_ptr->CTL_PROC_NR;
int i;
rp = proc_addr(tr_proc_nr);
if (isemptyp(rp)) return(EIO);
switch (tr_request) {
case T_STOP: /* stop process */
if (rp->p_flags == 0) lock_unready(rp);
rp->p_flags |= P_STOP;
rp->p_reg.psw &= ~TRACEBIT; /* clear trace bit */
return(OK);
case T_GETINS: /* return value from instruction space */
if (rp->p_memmap[T].mem_len != 0) {
if ((src = umap_local(rp, T, tr_addr, TR_VLSIZE)) == 0) return(EIO);
phys_copy(src, vir2phys(&tr_data), (phys_bytes) sizeof(long));
break;
}
/* Text space is actually data space - fall through. */
case T_GETDATA: /* return value from data space */
if ((src = umap_local(rp, D, tr_addr, TR_VLSIZE)) == 0) return(EIO);
phys_copy(src, vir2phys(&tr_data), (phys_bytes) sizeof(long));
break;
case T_GETUSER: /* return value from process table */
if ((tr_addr & (sizeof(long) - 1)) != 0 ||
tr_addr > sizeof(struct proc) - sizeof(long))
return(EIO);
tr_data = *(long *) ((char *) rp + (int) tr_addr);
break;
case T_SETINS: /* set value in instruction space */
if (rp->p_memmap[T].mem_len != 0) {
if ((dst = umap_local(rp, T, tr_addr, TR_VLSIZE)) == 0) return(EIO);
phys_copy(vir2phys(&tr_data), dst, (phys_bytes) sizeof(long));
tr_data = 0;
break;
}
/* Text space is actually data space - fall through. */
case T_SETDATA: /* set value in data space */
if ((dst = umap_local(rp, D, tr_addr, TR_VLSIZE)) == 0) return(EIO);
phys_copy(vir2phys(&tr_data), dst, (phys_bytes) sizeof(long));
tr_data = 0;
break;
case T_SETUSER: /* set value in process table */
if ((tr_addr & (sizeof(reg_t) - 1)) != 0 ||
tr_addr > sizeof(struct stackframe_s) - sizeof(reg_t))
return(EIO);
i = (int) tr_addr;
#if (CHIP == INTEL)
/* Altering segment registers might crash the kernel when it
* tries to load them prior to restarting a process, so do
* not allow it.
*/
if (i == (int) &((struct proc *) 0)->p_reg.cs ||
i == (int) &((struct proc *) 0)->p_reg.ds ||
i == (int) &((struct proc *) 0)->p_reg.es ||
#if _WORD_SIZE == 4
i == (int) &((struct proc *) 0)->p_reg.gs ||
i == (int) &((struct proc *) 0)->p_reg.fs ||
#endif
i == (int) &((struct proc *) 0)->p_reg.ss)
return(EIO);
#endif
if (i == (int) &((struct proc *) 0)->p_reg.psw)
/* only selected bits are changeable */
SETPSW(rp, tr_data);
else
*(reg_t *) ((char *) &rp->p_reg + i) = (reg_t) tr_data;
tr_data = 0;
break;
case T_RESUME: /* resume execution */
rp->p_flags &= ~P_STOP;
if (rp->p_flags == 0) lock_ready(rp);
tr_data = 0;
break;
case T_STEP: /* set trace bit */
rp->p_reg.psw |= TRACEBIT;
rp->p_flags &= ~P_STOP;
if (rp->p_flags == 0) lock_ready(rp);
tr_data = 0;
break;
default:
return(EIO);
}
return(OK);
}
#endif /* ENABLE_K_TRACING */

96
kernel/table.c Executable file
View File

@@ -0,0 +1,96 @@
/* The object file of "table.c" contains most kernel data. Variables that
* are declared in the *.h files appear with EXTERN in front of them, as in
*
* EXTERN int x;
*
* Normally EXTERN is defined as extern, so when they are included in another
* file, no storage is allocated. If EXTERN were not present, but just say,
*
* int x;
*
* then including this file in several source files would cause 'x' to be
* declared several times. While some linkers accept this, others do not,
* so they are declared extern when included normally. However, it must be
* declared for real somewhere. That is done here, by redefining EXTERN as
* the null string, so that inclusion of all *.h files in table.c actually
* generates storage for them.
*
* Various variables could not be declared EXTERN, but are declared PUBLIC
* or PRIVATE. The reason for this is that extern variables cannot have a
* default initialization. If such variables are shared, they must also be
* declared in one of the *.h files without the initialization. Examples
* include 'tasktab' (this file) and 'idt'/'gdt' (protect.c).
*
* Changes:
* Nov 10, 2004 removed controller->driver mappings (Jorrit N. Herder)
* Oct 17, 2004 updated above and tasktab comments (Jorrit N. Herder)
* Aug 18, 2004 included p_type in tasktab (Jorrit N. Herder)
* May 01, 2004 included p_sendmask in tasktab (Jorrit N. Herder)
*/
#define _TABLE
#include "kernel.h"
#include "proc.h"
#include "sendmask.h"
#include <minix/com.h>
#include <ibm/int86.h>
/* Define stack sizes for all tasks included in the system image. */
#define NO_STACK 0
#define SMALL_STACK (128 * sizeof(char *))
#if (CHIP == INTEL)
#define IDLE_STACK ((3+3+4) * sizeof(char *)) /* 3 intr, 3 temps, 4 db */
#else
#define IDLE_STACK SMALL_STACK
#endif
#define HARDWARE_STACK NO_STACK /* dummy task, uses kernel stack */
#define SYS_STACK SMALL_STACK
#define CLOCK_STACK SMALL_STACK
#define RTL8139_STACK (2 * SMALL_STACK * ENABLE_RTL8139)
/* Stack space for all the task stacks. Declared as (char *) to align it. */
#define TOT_STACK_SPACE (IDLE_STACK + HARDWARE_STACK + CLOCK_STACK + SYS_STACK \
+ RTL8139_STACK )
PUBLIC char *t_stack[TOT_STACK_SPACE / sizeof(char *)];
/* The system image table lists all programs that are part of the boot image.
* The order of the entries here MUST agree with the order of the programs
* in the boot image and all kernel tasks must come first.
* Each entry provides the process number, type, scheduling priority, send
* mask, and a name for the process table. For kernel processes, the startup
* routine and stack size is also provided.
*/
PUBLIC struct system_image image[] = {
#if ENABLE_RTL8139
{ RTL8139, rtl8139_task, P_TASK, PPRI_TASK, RTL8139_STACK, RTL8139_SENDMASK, "RTL8139" },
#endif
{ IDLE, idle_task, P_IDLE, PPRI_IDLE, IDLE_STACK, IDLE_SENDMASK, "IDLE" },
{ CLOCK, clock_task, P_TASK, PPRI_TASK, CLOCK_STACK, CLOCK_SENDMASK, "CLOCK" },
{ SYSTASK, sys_task, P_TASK, PPRI_TASK, SYS_STACK, SYSTEM_SENDMASK, "SYS" },
{ HARDWARE, 0, P_TASK, PPRI_TASK, HARDWARE_STACK,HARDWARE_SENDMASK,"HARDWAR" },
{ MM_PROC_NR, 0, P_SERVER, PPRI_NORMAL, 0, MM_SENDMASK, "MM" },
{ FS_PROC_NR, 0, P_SERVER, PPRI_NORMAL, 0, FS_SENDMASK, "FS" },
{ IS_PROC_NR, 0, P_SYSTEM, PPRI_HIGHER, 0, IS_SENDMASK, "IS" },
{ TTY, 0, P_SYSTEM, PPRI_HIGHER, 0, TTY_SENDMASK, "TTY" },
{ MEMORY, 0, P_DRIVER, PPRI_HIGH, 0, MEM_SENDMASK, "MEMORY" },
#if ENABLE_AT_WINI
{ AT_WINI, 0, P_DRIVER, PPRI_HIGHER, 0, AT_SENDMASK, "AT_WINI" },
#endif
#if ENABLE_FLOPPY
{ FLOPPY, 0, P_DRIVER, PPRI_HIGH, 0, FLOPPY_SENDMASK, "FLOPPY" },
#endif
#if ENABLE_PRINTER
{ PRINTER, 0, P_DRIVER, PPRI_NORMAL, 0, PRN_SENDMASK, "PRINTER" },
#endif
{ INIT_PROC_NR, 0, P_USER, PPRI_USER, 0, INIT_SENDMASK, "INIT" },
};
/* Verify the size of the system image table at compile time. If the number
* is not correct, the size of the 'dummy' array will be negative, causing
* a compile time error. Note that no space is allocated because 'dummy' is
* declared extern.
*/
extern int dummy[(IMAGE_SIZE==sizeof(image)/sizeof(struct system_image))?1:-1];

119
kernel/type.h Executable file
View File

@@ -0,0 +1,119 @@
#ifndef TYPE_H
#define TYPE_H
typedef _PROTOTYPE( void task_t, (void) );
typedef _PROTOTYPE( int (*rdwt_t), (message *m_ptr) );
typedef _PROTOTYPE( void (*watchdog_t), (void) );
/* This is used within the kernel to handle virtual copying. */
struct vir_addr {
int proc_nr;
int segment;
vir_bytes offset;
};
/* 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 */
typedef unsigned int notify_mask_t; /* bit mask for notifications */
typedef unsigned long send_mask_t; /* bit mask for sender */
struct system_image {
int proc_nr; /* process number to use */
task_t *initial_pc; /* start function for tasks */
int type; /* type of process */
int priority; /* scheduling priority */
int stksize; /* stack size for tasks */
send_mask_t sendmask; /* send mask protection */
char name[PROC_NAME_LEN]; /* name in process table */
};
struct memory {
phys_clicks base; /* start address of chunk */
phys_clicks size; /* size of memory chunk */
};
struct bios {
phys_bytes bios_addr; /* physical address at BIOS */
size_t bios_length; /* size of value */
};
#if (CHIP == INTEL)
typedef u16_t port_t;
typedef U16_t Port_t;
typedef unsigned reg_t; /* machine register */
/* The stack frame layout is determined by the software, but for efficiency
* it is laid out so the assembly code to use it is as simple as possible.
* 80286 protected mode and all real modes use the same frame, built with
* 16-bit registers. Real mode lacks an automatic stack switch, so little
* is lost by using the 286 frame for it. The 386 frame differs only in
* having 32-bit registers and more segment registers. The same names are
* used for the larger registers to avoid differences in the code.
*/
struct stackframe_s { /* proc_ptr points here */
#if _WORD_SIZE == 4
u16_t gs; /* last item pushed by save */
u16_t fs; /* ^ */
#endif
u16_t es; /* | */
u16_t ds; /* | */
reg_t di; /* di through cx are not accessed in C */
reg_t si; /* order is to match pusha/popa */
reg_t fp; /* bp */
reg_t st; /* hole for another copy of sp */
reg_t bx; /* | */
reg_t dx; /* | */
reg_t cx; /* | */
reg_t retreg; /* ax and above are all pushed by save */
reg_t retadr; /* return address for assembly code save() */
reg_t pc; /* ^ last item pushed by interrupt */
reg_t cs; /* | */
reg_t psw; /* | */
reg_t sp; /* | */
reg_t ss; /* these are pushed by CPU during interrupt */
};
struct segdesc_s { /* segment descriptor for protected mode */
u16_t limit_low;
u16_t base_low;
u8_t base_middle;
u8_t access; /* |P|DL|1|X|E|R|A| */
u8_t granularity; /* |G|X|0|A|LIMT| */
u8_t base_high;
};
typedef struct irq_hook {
struct irq_hook *next;
int (*handler)(struct irq_hook *);
int irq;
int id;
} irq_hook_t;
typedef int (*irq_handler_t)(struct irq_hook *);
/* The IRQ table is used to handle harware interrupts based on a policy set
* by a device driver. The policy is stored with a SYS_IRQCTL system call and
* used by a generic function to handle hardware interrupts in an appropriate
* way for the device.
*/
typedef unsigned long irq_policy_t;
struct irqtab {
irq_hook_t hook; /* its irq hook */
irq_policy_t policy; /* bit mask for the policy */
int proc_nr; /* process number to be notified */
long port; /* port to be read or written */
phys_bytes addr; /* absolute address to store or get value */
long mask_val; /* mask for strobing or value to be written */
};
#endif /* (CHIP == INTEL) */
#if (CHIP == M68000)
/* M68000 specific types go here. */
#endif /* (CHIP == M68000) */
#endif /* TYPE_H */