Initial revision
This commit is contained in:
183
kernel/Makefile
Executable file
183
kernel/Makefile
Executable 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
25
kernel/assert.h
Executable 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
BIN
kernel/build
Executable file
Binary file not shown.
362
kernel/clock.c
Executable file
362
kernel/clock.c
Executable 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
55
kernel/const.h
Executable 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
86
kernel/dummy.c
Normal 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
88
kernel/exception.c
Executable 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
80
kernel/glo.h
Executable 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
163
kernel/i8259.c
Executable 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
26
kernel/kernel.h
Executable 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
9
kernel/klib.s
Executable 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
497
kernel/klib386.s
Executable 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
1057
kernel/klib88.s
Executable file
File diff suppressed because it is too large
Load Diff
267
kernel/klibc.c
Normal file
267
kernel/klibc.c
Normal 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
354
kernel/main.c
Executable 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
120
kernel/memory.c
Executable 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
74
kernel/misc.c
Executable 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
9
kernel/mpx.s
Executable 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
553
kernel/mpx386.s
Executable 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
762
kernel/mpx88.s
Executable 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
1224
kernel/pci.c
Executable file
File diff suppressed because it is too large
Load Diff
97
kernel/pci.h
Executable file
97
kernel/pci.h
Executable 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
21
kernel/pci_amd.h
Executable 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
58
kernel/pci_intel.h
Executable 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
17
kernel/pci_sis.h
Executable 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
251
kernel/pci_table.c
Executable 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
27
kernel/pci_via.h
Executable 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
595
kernel/proc.c
Executable 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
154
kernel/proc.h
Executable 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
344
kernel/protect.c
Executable 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
124
kernel/protect.h
Executable 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
213
kernel/proto.h
Executable 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
2546
kernel/rtl8139.c
Executable file
File diff suppressed because it is too large
Load Diff
430
kernel/rtl8139.h
Executable file
430
kernel/rtl8139.h
Executable 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
36
kernel/sconst.h
Executable 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
168
kernel/sendmask.h
Normal 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
95
kernel/start.c
Executable 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
532
kernel/system.c
Executable 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
67
kernel/system.h
Normal 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
58
kernel/system/Makefile
Normal 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
130
kernel/system/alarms.c
Normal 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
133
kernel/system/copying.c
Normal 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
16
kernel/system/debugging.c
Normal 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
215
kernel/system/devio.c
Normal 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
69
kernel/system/do_copy.c
Normal 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
55
kernel/system/do_vcopy.c
Normal 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
106
kernel/system/irqctl.c
Normal 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
234
kernel/system/misc.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
45
kernel/system/old/do_abort.c
Normal file
45
kernel/system/old/do_abort.c
Normal 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) */
|
||||
}
|
||||
|
||||
34
kernel/system/old/do_endsig.c
Normal file
34
kernel/system/old/do_endsig.c
Normal 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);
|
||||
}
|
||||
|
||||
65
kernel/system/old/do_exec.c
Normal file
65
kernel/system/old/do_exec.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
45
kernel/system/old/do_exit.c
Normal file
45
kernel/system/old/do_exit.c
Normal 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 */
|
||||
}
|
||||
|
||||
|
||||
64
kernel/system/old/do_fork.c
Normal file
64
kernel/system/old/do_fork.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
148
kernel/system/old/do_getinfo.c
Normal file
148
kernel/system/old/do_getinfo.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
44
kernel/system/old/do_getmap.c
Normal file
44
kernel/system/old/do_getmap.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
46
kernel/system/old/do_getsig.c
Normal file
46
kernel/system/old/do_getsig.c
Normal 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);
|
||||
}
|
||||
|
||||
32
kernel/system/old/do_getsp.c
Normal file
32
kernel/system/old/do_getsp.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
28
kernel/system/old/do_iopenable.c
Normal file
28
kernel/system/old/do_iopenable.c
Normal 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
|
||||
}
|
||||
|
||||
|
||||
15
kernel/system/old/do_kill.c
Normal file
15
kernel/system/old/do_kill.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
36
kernel/system/old/do_kmalloc.c
Normal file
36
kernel/system/old/do_kmalloc.c
Normal 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);
|
||||
}
|
||||
|
||||
33
kernel/system/old/do_mem.c
Normal file
33
kernel/system/old/do_mem.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
52
kernel/system/old/do_newmap.c
Normal file
52
kernel/system/old/do_newmap.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
86
kernel/system/old/do_phys2seg.c
Normal file
86
kernel/system/old/do_phys2seg.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
37
kernel/system/old/do_physcopy.c
Normal file
37
kernel/system/old/do_physcopy.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
60
kernel/system/old/do_sdevio.c
Normal file
60
kernel/system/old/do_sdevio.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
72
kernel/system/old/do_sigreturn.c
Normal file
72
kernel/system/old/do_sigreturn.c
Normal 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);
|
||||
}
|
||||
|
||||
67
kernel/system/old/do_svrctl.c
Normal file
67
kernel/system/old/do_svrctl.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
33
kernel/system/old/do_umap.c
Normal file
33
kernel/system/old/do_umap.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
126
kernel/system/old/do_vdevio.c
Normal file
126
kernel/system/old/do_vdevio.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
69
kernel/system/old/do_vircopy.c
Normal file
69
kernel/system/old/do_vircopy.c
Normal 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) );
|
||||
}
|
||||
|
||||
|
||||
38
kernel/system/old/do_xit.c
Normal file
38
kernel/system/old/do_xit.c
Normal 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
223
kernel/system/proctl.c
Normal 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
227
kernel/system/sigctl.c
Normal 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
241
kernel/system/srvrctl.c
Normal 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
142
kernel/system/tracing.c
Normal 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
96
kernel/table.c
Executable 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
119
kernel/type.h
Executable 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 */
|
||||
Reference in New Issue
Block a user