Support for I/O MMU: do not re-use a memory segment until the I/O MMU has

removed it from its map.
This commit is contained in:
Philip Homburg 2008-02-21 16:33:34 +00:00
parent 75520b7403
commit 1cffa69d2c
7 changed files with 279 additions and 13 deletions

View file

@ -266,6 +266,215 @@ PUBLIC int mem_holes_copy(struct hole *holecopies, size_t *bytes, u32_t *hi)
return OK;
}
#define NR_DMA 16
PRIVATE struct dmatab
{
int dt_flags;
endpoint_t dt_proc;
phys_bytes dt_base;
phys_bytes dt_size;
phys_clicks dt_seg_base;
phys_clicks dt_seg_size;
} dmatab[NR_DMA];
#define DTF_INUSE 1
#define DTF_RELEASE_DMA 2
#define DTF_RELEASE_SEG 4
PRIVATE endpoint_t iommu_proc_e= ANY;
/*===========================================================================*
* do_adddma *
*===========================================================================*/
PUBLIC int do_adddma()
{
endpoint_t req_proc_e, target_proc_e;
int i, proc_n;
phys_bytes base, size;
struct mproc *rmp;
if (mp->mp_effuid != SUPER_USER)
return EPERM;
req_proc_e= m_in.m_source;
target_proc_e= m_in.m2_i1;
base= m_in.m2_l1;
size= m_in.m2_l2;
iommu_proc_e= req_proc_e;
/* Find empty slot */
for (i= 0; i<NR_DMA; i++)
{
if (!(dmatab[i].dt_flags & DTF_INUSE))
break;
}
if (i >= NR_DMA)
{
printf("pm:do_adddma: dma table full\n");
for (i= 0; i<NR_DMA; i++)
{
printf("%d: flags 0x%x proc %d base 0x%x size 0x%x\n",
i, dmatab[i].dt_flags,
dmatab[i].dt_proc,
dmatab[i].dt_base,
dmatab[i].dt_size);
}
panic(__FILE__, "adddma: table full", NO_NUM);
return ENOSPC;
}
/* Find target process */
if (pm_isokendpt(target_proc_e, &proc_n) != OK)
{
printf("pm:do_adddma: endpoint %d not found\n", target_proc_e);
return EINVAL;
}
rmp= &mproc[proc_n];
rmp->mp_flags |= HAS_DMA;
dmatab[i].dt_flags= DTF_INUSE;
dmatab[i].dt_proc= target_proc_e;
dmatab[i].dt_base= base;
dmatab[i].dt_size= size;
return OK;
}
/*===========================================================================*
* do_deldma *
*===========================================================================*/
PUBLIC int do_deldma()
{
endpoint_t req_proc_e, target_proc_e;
int i, j, proc_n;
phys_bytes base, size;
struct mproc *rmp;
if (mp->mp_effuid != SUPER_USER)
return EPERM;
req_proc_e= m_in.m_source;
target_proc_e= m_in.m2_i1;
base= m_in.m2_l1;
size= m_in.m2_l2;
iommu_proc_e= req_proc_e;
/* Find slot */
for (i= 0; i<NR_DMA; i++)
{
if (!(dmatab[i].dt_flags & DTF_INUSE))
continue;
if (dmatab[i].dt_proc == target_proc_e &&
dmatab[i].dt_base == base &&
dmatab[i].dt_size == size)
{
break;
}
}
if (i >= NR_DMA)
{
printf("pm:do_deldma: slot not found\n");
return ESRCH;
}
if (dmatab[i].dt_flags & DTF_RELEASE_SEG)
{
/* Check if we have to release the segment */
for (j= 0; j<NR_DMA; j++)
{
if (j == i)
continue;
if (!(dmatab[j].dt_flags & DTF_INUSE))
continue;
if (!(dmatab[j].dt_flags & DTF_RELEASE_SEG))
continue;
if (dmatab[i].dt_proc == target_proc_e)
break;
}
if (j >= NR_DMA)
{
/* Last segment */
free_mem(dmatab[i].dt_seg_base,
dmatab[i].dt_seg_size);
}
}
dmatab[i].dt_flags &= ~DTF_INUSE;
return OK;
}
/*===========================================================================*
* do_getdma *
*===========================================================================*/
PUBLIC int do_getdma()
{
endpoint_t req_proc_e, target_proc_e;
int i, proc_n;
phys_bytes base, size;
struct mproc *rmp;
if (mp->mp_effuid != SUPER_USER)
return EPERM;
req_proc_e= m_in.m_source;
iommu_proc_e= req_proc_e;
/* Find slot to report */
for (i= 0; i<NR_DMA; i++)
{
if (!(dmatab[i].dt_flags & DTF_INUSE))
continue;
if (!(dmatab[i].dt_flags & DTF_RELEASE_DMA))
continue;
printf("do_getdma: setting reply to 0x%x@0x%x proc %d\n",
dmatab[i].dt_size, dmatab[i].dt_base,
dmatab[i].dt_proc);
mp->mp_reply.m2_i1= dmatab[i].dt_proc;
mp->mp_reply.m2_l1= dmatab[i].dt_base;
mp->mp_reply.m2_l2= dmatab[i].dt_size;
return OK;
}
/* Nothing */
return EAGAIN;
}
/*===========================================================================*
* release_dma *
*===========================================================================*/
PUBLIC void release_dma(proc_e, base, size)
endpoint_t proc_e;
phys_clicks base;
phys_clicks size;
{
int i, found_one;;
found_one= FALSE;
for (i= 0; i<NR_DMA; i++)
{
if (!(dmatab[i].dt_flags & DTF_INUSE))
continue;
if (dmatab[i].dt_proc != proc_e)
continue;
dmatab[i].dt_flags |= DTF_RELEASE_DMA | DTF_RELEASE_SEG;
dmatab[i].dt_seg_base= base;
dmatab[i].dt_seg_size= size;
found_one= TRUE;
}
if (found_one)
notify(iommu_proc_e);
else
free_mem(base, size);
}
#if ENABLE_SWAP
/*===========================================================================*
* swap_on *

View file

@ -314,7 +314,7 @@ int for_trace;
if (parent_waiting && right_child) {
tell_parent(rmp); /* tell parent */
} else {
rmp->mp_flags &= (IN_USE|PRIV_PROC);
rmp->mp_flags &= (IN_USE|PRIV_PROC|HAS_DMA);
rmp->mp_flags |= ZOMBIE; /* parent not waiting, zombify child */
sig_proc(p_mp, SIGCHLD); /* send parent a "child died" signal */
}

View file

@ -155,10 +155,10 @@ PUBLIC int main()
*/
if ((rmp->mp_flags & (REPLY | ONSWAP | IN_USE | ZOMBIE)) ==
(REPLY | IN_USE)) {
if ((s=send(rmp->mp_endpoint, &rmp->mp_reply)) != OK) {
printf("PM can't reply to %d (%s)\n",
rmp->mp_endpoint, rmp->mp_name);
panic(__FILE__, "PM can't reply", NO_NUM);
s=sendnb(rmp->mp_endpoint, &rmp->mp_reply);
if (s != OK) {
printf("PM can't reply to %d (%s): %d\n",
rmp->mp_endpoint, rmp->mp_name, s);
}
rmp->mp_flags &= ~REPLY;
}
@ -713,6 +713,7 @@ message *m_ptr;
{
int r, proc_e, proc_n;
struct mproc *rmp;
phys_clicks base, size;
switch(m_ptr->m_type)
{
@ -749,9 +750,23 @@ message *m_ptr;
free_mem(rmp->mp_seg[T].mem_phys,
rmp->mp_seg[T].mem_len);
}
/* Free the data and stack segments. */
free_mem(rmp->mp_seg[D].mem_phys, rmp->mp_seg[S].mem_vir +
rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);
base= rmp->mp_seg[D].mem_phys;
size= rmp->mp_seg[S].mem_vir + rmp->mp_seg[S].mem_len -
rmp->mp_seg[D].mem_vir;
if (rmp->mp_flags & HAS_DMA)
{
/* Delay freeing the memory segmented until the
* DMA buffers have been released.
*/
release_dma(rmp->mp_endpoint, base, size);
}
else
{
/* Free the data and stack segments. */
free_mem(base, size);
}
if (m_ptr->m_type == PM_EXIT_REPLY_TR &&
rmp->mp_parent != INIT_PROC_NR)
@ -847,7 +862,7 @@ message *m_ptr;
tell_parent(rmp); /* tell parent */
} else {
/* parent not waiting, zombify child */
rmp->mp_flags &= (IN_USE|PRIV_PROC);
rmp->mp_flags &= (IN_USE|PRIV_PROC|HAS_DMA);
rmp->mp_flags |= ZOMBIE;
/* send parent a "child died" signal */
sig_proc(p_mp, SIGCHLD);
@ -872,9 +887,23 @@ message *m_ptr;
free_mem(rmp->mp_seg[T].mem_phys,
rmp->mp_seg[T].mem_len);
}
/* Free the data and stack segments. */
free_mem(rmp->mp_seg[D].mem_phys, rmp->mp_seg[S].mem_vir +
rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);
base= rmp->mp_seg[D].mem_phys;
size= rmp->mp_seg[S].mem_vir + rmp->mp_seg[S].mem_len -
rmp->mp_seg[D].mem_vir;
if (rmp->mp_flags & HAS_DMA)
{
/* Delay freeing the memory segmented until the
* DMA buffers have been released.
*/
release_dma(rmp->mp_endpoint, base, size);
}
else
{
/* Free the data and stack segments. */
free_mem(base, size);
}
/* Clean up if the parent has collected the exit
* status

View file

@ -85,6 +85,9 @@ EXTERN struct mproc {
#define PM_SIG_PENDING 0x4000 /* process got a signal while waiting for FS */
#define PARTIAL_EXEC 0x8000 /* Process got a new map but no content */
#define TOLD_PARENT 0x10000 /* Parent wait() completed, ZOMBIE off */
#define HAS_DMA 0x20000 /* Process directly or indirectly granted
* DMA buffers.
*/
#define NIL_MPROC ((struct mproc *) 0)

View file

@ -11,6 +11,11 @@ struct memory;
_PROTOTYPE( phys_clicks alloc_mem, (phys_clicks clicks) );
_PROTOTYPE( void free_mem, (phys_clicks base, phys_clicks clicks) );
_PROTOTYPE( void mem_init, (struct memory *chunks, phys_clicks *free) );
_PROTOTYPE( int do_adddma, (void) );
_PROTOTYPE( int do_deldma, (void) );
_PROTOTYPE( int do_getdma, (void) );
_PROTOTYPE( void release_dma, (endpoint_t proc_e, phys_clicks base,
phys_clicks size) );
#if ENABLE_SWAP
_PROTOTYPE( int swap_on, (char *file, u32_t offset, u32_t size) );
_PROTOTYPE( int swap_off, (void) );

View file

@ -13,7 +13,7 @@
/* Miscellaneous */
char core_name[] = "core"; /* file name where core images are produced */
_PROTOTYPE (int (*call_vec[NCALLS]), (void) ) = {
_PROTOTYPE (int (*call_vec[]), (void) ) = {
no_sys, /* 0 = unused */
do_pm_exit, /* 1 = exit */
do_fork, /* 2 = fork */
@ -115,6 +115,17 @@ _PROTOTYPE (int (*call_vec[NCALLS]), (void) ) = {
do_getsysinfo_up,/* 97 = getsysinfo_up */
do_sprofile, /* 98 = sprofile */
do_cprofile, /* 99 = cprofile */
no_sys, /* 100 = unused */
no_sys, /* 101 = unused */
no_sys, /* 102 = unused */
no_sys, /* 103 = unused */
no_sys, /* 104 = unused */
no_sys, /* 105 = unused */
no_sys, /* 106 = unused */
no_sys, /* 107 = unused */
do_adddma, /* 108 = adddma */
do_deldma, /* 109 = deldma */
do_getdma, /* 110 = getdma */
};
/* This should not fail with "array size is negative": */
extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];

View file

@ -69,6 +69,15 @@ PUBLIC int do_trace()
if ((child=find_proc(m_in.pid))==NIL_MPROC)
return(ESRCH);
/* Should check for shared text */
/* Make sure the text segment is not used as a source for shared
* text.
*/
child->mp_ino= 0;
child->mp_dev= 0;
child->mp_ctime= 0;
r= sys_trace(m_in.request,child->mp_endpoint,m_in.taddr,&m_in.data);
if (r != OK) return(r);