- Kernel call handlers cleaned up. More strict checking of input parameters.
- Moved generic_handler() from system.c to system/do_irqctl.c. - Set privileges of system processes somewhat stricter.
This commit is contained in:
@@ -25,7 +25,7 @@ OBJECTS = \
|
||||
$(SYSTEM)(do_trace.o) \
|
||||
$(SYSTEM)(do_nice.o) \
|
||||
$(SYSTEM)(do_times.o) \
|
||||
$(SYSTEM)(do_alarm.o) \
|
||||
$(SYSTEM)(do_setalarm.o) \
|
||||
$(SYSTEM)(do_irqctl.o) \
|
||||
$(SYSTEM)(do_devio.o) \
|
||||
$(SYSTEM)(do_vdevio.o) \
|
||||
@@ -82,8 +82,8 @@ $(SYSTEM)(do_nice.o): do_nice.c
|
||||
$(SYSTEM)(do_times.o): do_times.c
|
||||
$(CC) do_times.c
|
||||
|
||||
$(SYSTEM)(do_alarm.o): do_alarm.c
|
||||
$(CC) do_alarm.c
|
||||
$(SYSTEM)(do_setalarm.o): do_setalarm.c
|
||||
$(CC) do_setalarm.c
|
||||
|
||||
$(SYSTEM)(do_irqctl.o): do_irqctl.c
|
||||
$(CC) do_irqctl.c
|
||||
|
||||
@@ -20,23 +20,25 @@ 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
|
||||
* PM (normal abort or panic) or FS (panic), or TTY (user issued CTRL-ALT-DEL
|
||||
* or ESC after debugging dumps).
|
||||
* PM (normal abort or panic) or FS (panic), or TTY (after CTRL-ALT-DEL).
|
||||
*/
|
||||
int how = m_ptr->ABRT_HOW;
|
||||
int proc_nr;
|
||||
int length;
|
||||
phys_bytes src_phys;
|
||||
|
||||
/* See if the monitor is to run the specified instructions. */
|
||||
if (how == RBT_MONITOR) {
|
||||
int proc_nr = m_ptr->ABRT_MON_PROC;
|
||||
int length = m_ptr->ABRT_MON_LEN + 1;
|
||||
vir_bytes src_vir = (vir_bytes) m_ptr->ABRT_MON_ADDR;
|
||||
phys_bytes src_phys = numap_local(proc_nr, src_vir, length);
|
||||
|
||||
/* Validate length and address of shutdown code before copying. */
|
||||
if (length > kinfo.params_size || src_phys == 0)
|
||||
phys_copy(vir2phys("delay;boot"), kinfo.params_base, 11);
|
||||
else
|
||||
phys_copy(src_phys, kinfo.params_base, (phys_bytes) length);
|
||||
proc_nr = m_ptr->ABRT_MON_PROC;
|
||||
if (! isokprocn(proc_nr)) return(EINVAL);
|
||||
length = m_ptr->ABRT_MON_LEN + 1;
|
||||
if (length > kinfo.params_size) return(E2BIG);
|
||||
src_phys = numap_local(proc_nr,(vir_bytes)m_ptr->ABRT_MON_ADDR,length);
|
||||
if (! src_phys) return(EFAULT);
|
||||
|
||||
/* Parameters seem ok, copy them and prepare shutting down. */
|
||||
phys_copy(src_phys, kinfo.params_base, (phys_bytes) length);
|
||||
}
|
||||
|
||||
/* Now prepare to shutdown MINIX. */
|
||||
|
||||
@@ -23,8 +23,11 @@ message *m_ptr; /* pointer to request message */
|
||||
*/
|
||||
register struct proc *rp;
|
||||
|
||||
/* Get process pointer and verify that it had signals pending. If the
|
||||
* process is already dead its flags will be reset.
|
||||
*/
|
||||
rp = proc_addr(m_ptr->SIG_PROC);
|
||||
if (isemptyp(rp)) return(EINVAL); /* process already dead? */
|
||||
if (! (rp->p_rts_flags & SIG_PENDING)) return(EINVAL);
|
||||
|
||||
/* PM has finished one kernel signal. Perhaps process is ready now? */
|
||||
if (! (rp->p_rts_flags & SIGNALED)) /* new signal arrived */
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* 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 PM)
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
@@ -33,6 +32,18 @@ register message *m_ptr; /* pointer to request message */
|
||||
rpc = proc_addr(m_ptr->PR_PROC_NR);
|
||||
if (isemptyp(rpp) || ! isemptyp(rpc)) return(EINVAL);
|
||||
|
||||
/* If this is a system process, make sure the child process gets its own
|
||||
* privilege structure for accounting. This is the only part that can fail,
|
||||
* so do this before allocating the process table slot.
|
||||
*/
|
||||
if (priv(rpc)->s_flags & SYS_PROC) {
|
||||
if (OK != (i=get_priv(rpc, SYS_PROC))) return(i); /* get structure */
|
||||
for (i=0; i< BITMAP_CHUNKS(NR_SYS_PROCS); i++) /* remove pending: */
|
||||
priv(rpc)->s_notify_pending.chunk[i] = 0; /* - notifications */
|
||||
priv(rpc)->s_int_pending = 0; /* - interrupts */
|
||||
sigemptyset(&priv(rpc)->s_sig_pending); /* - signals */
|
||||
}
|
||||
|
||||
/* Copy parent 'proc' struct to child. And reinitialize some fields. */
|
||||
#if (CHIP == INTEL)
|
||||
old_ldt_sel = rpc->p_ldt_sel; /* backup local descriptors */
|
||||
@@ -52,16 +63,6 @@ register message *m_ptr; /* pointer to request message */
|
||||
rpc->p_user_time = 0; /* set all the accounting times to 0 */
|
||||
rpc->p_sys_time = 0;
|
||||
|
||||
/* If this is a system process, make sure the child process gets its own
|
||||
* privilege structure for accounting.
|
||||
*/
|
||||
if (priv(rpc)->s_flags & SYS_PROC) {
|
||||
if (OK != (i=get_priv(rpc, SYS_PROC))) return(i); /* get structure */
|
||||
for (i=0; i< BITMAP_CHUNKS(NR_SYS_PROCS); i++) /* remove pending: */
|
||||
priv(rpc)->s_notify_pending.chunk[i] = 0; /* - notifications */
|
||||
priv(rpc)->s_int_pending = 0; /* - interrupts */
|
||||
sigemptyset(&priv(rpc)->s_sig_pending); /* - signals */
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*
|
||||
* 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_VAL_PTR2 (second, optional pointer)
|
||||
@@ -47,7 +46,7 @@ register message *m_ptr; /* pointer to request message */
|
||||
break;
|
||||
}
|
||||
case GET_IMAGE: {
|
||||
length = sizeof(struct system_image) * NR_BOOT_PROCS;
|
||||
length = sizeof(struct boot_image) * NR_BOOT_PROCS;
|
||||
src_phys = vir2phys(image);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
* m5_c1: IRQ_REQUEST (control operation to perform)
|
||||
* m5_c2: IRQ_VECTOR (irq line that must be controlled)
|
||||
* m5_i1: IRQ_POLICY (irq policy allows reenabling interrupts)
|
||||
* m5_l3: IRQ_HOOK_ID (index of irq hook assigned at kernel)
|
||||
* m5_l3: IRQ_HOOK_ID (provides index to be returned on interrupt)
|
||||
* ,, ,, (returns index of irq hook assigned at kernel)
|
||||
*
|
||||
* Author:
|
||||
* Jorrit N. Herder <jnherder@cs.vu.nl>
|
||||
@@ -13,8 +14,11 @@
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
|
||||
#if USE_IRQCTL
|
||||
|
||||
FORWARD _PROTOTYPE(int generic_handler, (irq_hook_t *hook));
|
||||
|
||||
/*===========================================================================*
|
||||
* do_irqctl *
|
||||
*===========================================================================*/
|
||||
@@ -99,5 +103,33 @@ register message *m_ptr; /* pointer to request message */
|
||||
return(r);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* generic_handler *
|
||||
*===========================================================================*/
|
||||
PRIVATE int generic_handler(hook)
|
||||
irq_hook_t *hook;
|
||||
{
|
||||
/* This function handles hardware interrupt in a simple and generic way. All
|
||||
* interrupts are transformed into messages to a driver. The IRQ line will be
|
||||
* reenabled if the policy says so.
|
||||
*/
|
||||
|
||||
/* As a side-effect, the interrupt handler gathers random information by
|
||||
* timestamping the interrupt events. This is used for /dev/random.
|
||||
*/
|
||||
get_randomness(hook->irq);
|
||||
|
||||
/* Add a bit for this interrupt to the process' pending interrupts. When
|
||||
* sending the notification message, this bit map will be magically set
|
||||
* as an argument.
|
||||
*/
|
||||
priv(proc_addr(hook->proc_nr))->s_int_pending |= (1 << hook->notify_id);
|
||||
|
||||
/* Build notification message and return. */
|
||||
lock_notify(HARDWARE, hook->proc_nr);
|
||||
return(hook->policy & IRQ_REENABLE);
|
||||
}
|
||||
|
||||
#endif /* USE_IRQCTL */
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ message *m_ptr; /* pointer to request message */
|
||||
int sig_nr = m_ptr->SIG_NUMBER;
|
||||
|
||||
if (! isokprocn(proc_nr) || sig_nr > _NSIG) return(EINVAL);
|
||||
if (iskerneln(proc_nr)) return(EPERM);
|
||||
|
||||
if (m_ptr->m_source == PM_PROC_NR) {
|
||||
/* Directly send signal notification to a system process. */
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
* m_type: SYS_MEMSET
|
||||
*
|
||||
* The parameters for this system call are:
|
||||
* m1_p1: MEM_PTR (virtual address)
|
||||
* m1_i1: MEM_COUNT (returns physical address)
|
||||
* m1_i2: MEM_PATTERN (size of datastructure)
|
||||
* m2_p1: MEM_PTR (virtual address)
|
||||
* m2_l1: MEM_COUNT (returns physical address)
|
||||
* m2_l2: MEM_PATTERN (size of datastructure)
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
@@ -26,6 +26,7 @@ message *m_ptr; /* pointer to request message */
|
||||
caller = m_ptr->m_source;
|
||||
map_ptr = (struct mem_map *) m_ptr->PR_MEM_PTR;
|
||||
if (! isokprocn(m_ptr->PR_PROC_NR)) return(EINVAL);
|
||||
if (iskerneln(m_ptr->PR_PROC_NR)) return(EPERM);
|
||||
rp = proc_addr(m_ptr->PR_PROC_NR);
|
||||
|
||||
/* Copy the map from PM. */
|
||||
|
||||
@@ -23,6 +23,7 @@ PUBLIC int do_nice(message *m_ptr)
|
||||
/* Extract the message parameters and do sanity checking. */
|
||||
proc_nr = m_ptr->PR_PROC_NR;
|
||||
if (! isokprocn(proc_nr)) return(EINVAL);
|
||||
if (iskerneln(proc_nr)) return(EPERM);
|
||||
pri = m_ptr->PR_PRIORITY;
|
||||
if (pri < PRIO_MIN || pri > PRIO_MAX) return(EINVAL);
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ message *m_ptr; /* pointer to request message */
|
||||
|
||||
/* Make sure this process has its own privileges structure. */
|
||||
if (! (priv(rp)->s_flags & SYS_PROC))
|
||||
get_priv(rp, SYS_PROC);
|
||||
if ((i=get_priv(rp, SYS_PROC)) != OK) return(i);
|
||||
|
||||
/* Now update the process' privileges as requested. */
|
||||
rp->p_priv->s_call_mask = FILLED_MASK;
|
||||
|
||||
@@ -26,10 +26,13 @@ register message *m_ptr; /* pointer to request message */
|
||||
long port = m_ptr->DIO_PORT;
|
||||
phys_bytes phys_buf;
|
||||
|
||||
/* Check if process number is OK. */
|
||||
/* Check if process number is OK. A process number is allowed here, because
|
||||
* driver may directly provide a pointer to a buffer at the user-process
|
||||
* that initiated the device I/O. Kernel processes, of course, are denied.
|
||||
*/
|
||||
if (proc_nr == SELF) proc_nr = m_ptr->m_source;
|
||||
if (! isokprocn(proc_nr))
|
||||
return(EINVAL);
|
||||
if (! isokprocn(proc_nr)) return(EINVAL);
|
||||
if (iskerneln(proc_nr)) return(EPERM);
|
||||
|
||||
/* Get and check physical address. */
|
||||
if ((phys_buf = numap_local(proc_nr, (vir_bytes) m_ptr->DIO_VEC_ADDR, count)) == 0)
|
||||
|
||||
@@ -23,6 +23,7 @@ PUBLIC int do_setalarm(m_ptr)
|
||||
message *m_ptr; /* pointer to request message */
|
||||
{
|
||||
/* A process requests a synchronous alarm, or wants to cancel its alarm. */
|
||||
register struct proc *rp; /* pointer to requesting process */
|
||||
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 */
|
||||
@@ -30,12 +31,14 @@ message *m_ptr; /* pointer to request message */
|
||||
clock_t uptime; /* placeholder for current uptime */
|
||||
|
||||
/* Extract shared parameters from the request message. */
|
||||
proc_nr = m_ptr->m_source; /* process to interrupt later */
|
||||
exp_time = m_ptr->ALRM_EXP_TIME; /* alarm's expiration time */
|
||||
use_abs_time = m_ptr->ALRM_ABS_TIME; /* flag for absolute time */
|
||||
proc_nr = m_ptr->m_source; /* process to interrupt later */
|
||||
rp = proc_addr(proc_nr);
|
||||
if (! (priv(rp)->s_flags & SYS_PROC)) return(EPERM);
|
||||
|
||||
/* Get the timer structure and set the parameters for this alarm. */
|
||||
tp = &(proc_addr(proc_nr)->p_priv->s_alarm_timer);
|
||||
tp = &(priv(rp)->s_alarm_timer);
|
||||
tmr_arg(tp)->ta_int = proc_nr;
|
||||
tp->tmr_func = cause_alarm;
|
||||
|
||||
@@ -27,6 +27,8 @@ message *m_ptr; /* pointer to request message */
|
||||
register struct proc *rp;
|
||||
phys_bytes src_phys;
|
||||
|
||||
if (! isokprocn(m_ptr->SIG_PROC)) return(EINVAL);
|
||||
if (iskerneln(m_ptr->SIG_PROC)) return(EPERM);
|
||||
rp = proc_addr(m_ptr->SIG_PROC);
|
||||
|
||||
/* Copy in the sigcontext structure. */
|
||||
|
||||
@@ -29,6 +29,8 @@ message *m_ptr; /* pointer to request message */
|
||||
struct sigcontext sc, *scp;
|
||||
struct sigframe fr, *frp;
|
||||
|
||||
if (! isokprocn(m_ptr->SIG_PROC)) return(EINVAL);
|
||||
if (iskerneln(m_ptr->SIG_PROC)) return(EPERM);
|
||||
rp = proc_addr(m_ptr->SIG_PROC);
|
||||
|
||||
/* Get the sigmsg structure into our address space. */
|
||||
|
||||
@@ -47,6 +47,9 @@ register message *m_ptr;
|
||||
int tr_proc_nr = m_ptr->CTL_PROC_NR;
|
||||
int i;
|
||||
|
||||
if (! isokprocn(tr_proc_nr)) return(EINVAL);
|
||||
if (iskerneln(tr_proc_nr)) return(EPERM);
|
||||
|
||||
rp = proc_addr(tr_proc_nr);
|
||||
if (isemptyp(rp)) return(EIO);
|
||||
switch (tr_request) {
|
||||
|
||||
@@ -2,13 +2,9 @@
|
||||
* m_type: SYS_VIRVCOPY, SYS_PHYSVCOPY
|
||||
*
|
||||
* 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
|
||||
* m1_i3: VCP_VEC_SIZE size of copy request vector
|
||||
* m1_p1: VCP_VEC_ADDR address of vector at caller
|
||||
* m1_i2: VCP_NR_OK number of successfull copies
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
@@ -52,16 +48,17 @@ register message *m_ptr; /* pointer to request message */
|
||||
phys_copy(caller_phys, kernel_phys, (phys_bytes) bytes);
|
||||
|
||||
/* Assume vector with requests is correct. Try to copy everything. */
|
||||
m_ptr->VCP_NR_OK = 0;
|
||||
for (i=0; i<nr_req; i++) {
|
||||
|
||||
req = &vir_cp_req[i];
|
||||
|
||||
/* Check if physical addressing is used without SYS_PHYSVCOPY. */
|
||||
if (((req->src.segment | req->dst.segment) & PHYS_SEG) &&
|
||||
m_ptr->m_type != SYS_PHYSVCOPY)
|
||||
return(EPERM);
|
||||
m_ptr->m_type != SYS_PHYSVCOPY) return(EPERM);
|
||||
if ((s=virtual_copy(&req->src, &req->dst, req->count)) != OK)
|
||||
return(s);
|
||||
m_ptr->VCP_NR_OK ++;
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
@@ -14,16 +14,11 @@
|
||||
#if USE_VDEVIO
|
||||
|
||||
/* Buffer for SYS_VDEVIO to copy (port,value)-pairs from/ to user. */
|
||||
PRIVATE char vdevio_pv_buf[VDEVIO_BUF_SIZE];
|
||||
PRIVATE char vdevio_buf[VDEVIO_BUF_SIZE];
|
||||
PRIVATE pvb_pair_t *pvb = (pvb_pair_t *) vdevio_buf;
|
||||
PRIVATE pvw_pair_t *pvw = (pvw_pair_t *) vdevio_buf;
|
||||
PRIVATE pvl_pair_t *pvl = (pvl_pair_t *) vdevio_buf;
|
||||
|
||||
/* 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 *
|
||||
@@ -37,88 +32,57 @@ register message *m_ptr; /* pointer to request message */
|
||||
* 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;
|
||||
int caller_proc; /* process number 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_proc = m_ptr->m_source;
|
||||
caller_vir = (vir_bytes) m_ptr->DIO_VEC_ADDR;
|
||||
caller_phys = umap_local(proc_addr(caller_proc), 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(13, "do_vdevio");
|
||||
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(13);
|
||||
int vec_size; /* size of vector */
|
||||
int io_in; /* true if input */
|
||||
size_t bytes; /* # bytes to be copied */
|
||||
int caller_proc; /* process number of caller */
|
||||
vir_bytes caller_vir; /* virtual address at caller */
|
||||
phys_bytes caller_phys; /* physical address at caller */
|
||||
int i;
|
||||
|
||||
/* 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);
|
||||
/* Get the request, size of the request vector, and check the values. */
|
||||
if (m_ptr->DIO_REQUEST == DIO_INPUT) io_in = TRUE;
|
||||
else if (m_ptr->DIO_REQUEST == DIO_OUTPUT) io_in = FALSE;
|
||||
else return(EINVAL);
|
||||
if ((vec_size = m_ptr->DIO_VEC_SIZE) <= 0) return(EINVAL);
|
||||
switch (m_ptr->DIO_TYPE) {
|
||||
case DIO_BYTE: bytes = vec_size * sizeof(pvb_pair_t); break;
|
||||
case DIO_WORD: bytes = vec_size * sizeof(pvw_pair_t); break;
|
||||
case DIO_LONG: bytes = vec_size * sizeof(pvl_pair_t); break;
|
||||
default: return(EINVAL); /* check type once and for all */
|
||||
}
|
||||
if (bytes > sizeof(vdevio_buf)) return(E2BIG);
|
||||
|
||||
/* Calculate physical addresses and copy (port,value)-pairs from user. */
|
||||
caller_proc = m_ptr->m_source;
|
||||
caller_vir = (vir_bytes) m_ptr->DIO_VEC_ADDR;
|
||||
caller_phys = umap_local(proc_addr(caller_proc), D, caller_vir, bytes);
|
||||
if (0 == caller_phys) return(EFAULT);
|
||||
phys_copy(caller_phys, vir2phys(vdevio_buf), (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.
|
||||
*/
|
||||
lock(13, "do_vdevio");
|
||||
switch (m_ptr->DIO_TYPE) {
|
||||
case DIO_BYTE: /* byte values */
|
||||
if (io_in) for (i=0; i<vec_size; i++) pvb[i].value = inb(pvb[i].port);
|
||||
else for (i=0; i<vec_size; i++) outb(pvb[i].port, pvb[i].value);
|
||||
break;
|
||||
case DIO_WORD: /* word values */
|
||||
if (io_in) for (i=0; i<vec_size; i++) pvw[i].value = inw(pvw[i].port);
|
||||
else for (i=0; i<vec_size; i++) outw(pvw[i].port, pvw[i].value);
|
||||
break;
|
||||
default: /* long values */
|
||||
if (io_in) for (i=0; i<vec_size; i++) pvl[i].value = inl(pvl[i].port);
|
||||
else for (i=0; i<vec_size; i++) outl(pvb[i].port, pvl[i].value);
|
||||
}
|
||||
unlock(13);
|
||||
|
||||
/* Almost done, copy back results for input requests. */
|
||||
if (io_in) phys_copy(vir2phys(vdevio_buf), caller_phys, (phys_bytes) bytes);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
#endif /* USE_VDEVIO */
|
||||
|
||||
Reference in New Issue
Block a user