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:
parent
75520b7403
commit
1cffa69d2c
7 changed files with 279 additions and 13 deletions
|
@ -266,6 +266,215 @@ PUBLIC int mem_holes_copy(struct hole *holecopies, size_t *bytes, u32_t *hi)
|
||||||
return OK;
|
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
|
#if ENABLE_SWAP
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* swap_on *
|
* swap_on *
|
||||||
|
|
|
@ -314,7 +314,7 @@ int for_trace;
|
||||||
if (parent_waiting && right_child) {
|
if (parent_waiting && right_child) {
|
||||||
tell_parent(rmp); /* tell parent */
|
tell_parent(rmp); /* tell parent */
|
||||||
} else {
|
} 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 */
|
rmp->mp_flags |= ZOMBIE; /* parent not waiting, zombify child */
|
||||||
sig_proc(p_mp, SIGCHLD); /* send parent a "child died" signal */
|
sig_proc(p_mp, SIGCHLD); /* send parent a "child died" signal */
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,10 +155,10 @@ PUBLIC int main()
|
||||||
*/
|
*/
|
||||||
if ((rmp->mp_flags & (REPLY | ONSWAP | IN_USE | ZOMBIE)) ==
|
if ((rmp->mp_flags & (REPLY | ONSWAP | IN_USE | ZOMBIE)) ==
|
||||||
(REPLY | IN_USE)) {
|
(REPLY | IN_USE)) {
|
||||||
if ((s=send(rmp->mp_endpoint, &rmp->mp_reply)) != OK) {
|
s=sendnb(rmp->mp_endpoint, &rmp->mp_reply);
|
||||||
printf("PM can't reply to %d (%s)\n",
|
if (s != OK) {
|
||||||
rmp->mp_endpoint, rmp->mp_name);
|
printf("PM can't reply to %d (%s): %d\n",
|
||||||
panic(__FILE__, "PM can't reply", NO_NUM);
|
rmp->mp_endpoint, rmp->mp_name, s);
|
||||||
}
|
}
|
||||||
rmp->mp_flags &= ~REPLY;
|
rmp->mp_flags &= ~REPLY;
|
||||||
}
|
}
|
||||||
|
@ -713,6 +713,7 @@ message *m_ptr;
|
||||||
{
|
{
|
||||||
int r, proc_e, proc_n;
|
int r, proc_e, proc_n;
|
||||||
struct mproc *rmp;
|
struct mproc *rmp;
|
||||||
|
phys_clicks base, size;
|
||||||
|
|
||||||
switch(m_ptr->m_type)
|
switch(m_ptr->m_type)
|
||||||
{
|
{
|
||||||
|
@ -749,9 +750,23 @@ message *m_ptr;
|
||||||
free_mem(rmp->mp_seg[T].mem_phys,
|
free_mem(rmp->mp_seg[T].mem_phys,
|
||||||
rmp->mp_seg[T].mem_len);
|
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 +
|
base= rmp->mp_seg[D].mem_phys;
|
||||||
rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);
|
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 &&
|
if (m_ptr->m_type == PM_EXIT_REPLY_TR &&
|
||||||
rmp->mp_parent != INIT_PROC_NR)
|
rmp->mp_parent != INIT_PROC_NR)
|
||||||
|
@ -847,7 +862,7 @@ message *m_ptr;
|
||||||
tell_parent(rmp); /* tell parent */
|
tell_parent(rmp); /* tell parent */
|
||||||
} else {
|
} else {
|
||||||
/* parent not waiting, zombify child */
|
/* 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;
|
rmp->mp_flags |= ZOMBIE;
|
||||||
/* send parent a "child died" signal */
|
/* send parent a "child died" signal */
|
||||||
sig_proc(p_mp, SIGCHLD);
|
sig_proc(p_mp, SIGCHLD);
|
||||||
|
@ -872,9 +887,23 @@ message *m_ptr;
|
||||||
free_mem(rmp->mp_seg[T].mem_phys,
|
free_mem(rmp->mp_seg[T].mem_phys,
|
||||||
rmp->mp_seg[T].mem_len);
|
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 +
|
base= rmp->mp_seg[D].mem_phys;
|
||||||
rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);
|
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
|
/* Clean up if the parent has collected the exit
|
||||||
* status
|
* status
|
||||||
|
|
|
@ -85,6 +85,9 @@ EXTERN struct mproc {
|
||||||
#define PM_SIG_PENDING 0x4000 /* process got a signal while waiting for FS */
|
#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 PARTIAL_EXEC 0x8000 /* Process got a new map but no content */
|
||||||
#define TOLD_PARENT 0x10000 /* Parent wait() completed, ZOMBIE off */
|
#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)
|
#define NIL_MPROC ((struct mproc *) 0)
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,11 @@ struct memory;
|
||||||
_PROTOTYPE( phys_clicks alloc_mem, (phys_clicks clicks) );
|
_PROTOTYPE( phys_clicks alloc_mem, (phys_clicks clicks) );
|
||||||
_PROTOTYPE( void free_mem, (phys_clicks base, phys_clicks clicks) );
|
_PROTOTYPE( void free_mem, (phys_clicks base, phys_clicks clicks) );
|
||||||
_PROTOTYPE( void mem_init, (struct memory *chunks, phys_clicks *free) );
|
_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
|
#if ENABLE_SWAP
|
||||||
_PROTOTYPE( int swap_on, (char *file, u32_t offset, u32_t size) );
|
_PROTOTYPE( int swap_on, (char *file, u32_t offset, u32_t size) );
|
||||||
_PROTOTYPE( int swap_off, (void) );
|
_PROTOTYPE( int swap_off, (void) );
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
/* Miscellaneous */
|
/* Miscellaneous */
|
||||||
char core_name[] = "core"; /* file name where core images are produced */
|
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 */
|
no_sys, /* 0 = unused */
|
||||||
do_pm_exit, /* 1 = exit */
|
do_pm_exit, /* 1 = exit */
|
||||||
do_fork, /* 2 = fork */
|
do_fork, /* 2 = fork */
|
||||||
|
@ -115,6 +115,17 @@ _PROTOTYPE (int (*call_vec[NCALLS]), (void) ) = {
|
||||||
do_getsysinfo_up,/* 97 = getsysinfo_up */
|
do_getsysinfo_up,/* 97 = getsysinfo_up */
|
||||||
do_sprofile, /* 98 = sprofile */
|
do_sprofile, /* 98 = sprofile */
|
||||||
do_cprofile, /* 99 = cprofile */
|
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": */
|
/* This should not fail with "array size is negative": */
|
||||||
extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];
|
extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];
|
||||||
|
|
|
@ -69,6 +69,15 @@ PUBLIC int do_trace()
|
||||||
if ((child=find_proc(m_in.pid))==NIL_MPROC)
|
if ((child=find_proc(m_in.pid))==NIL_MPROC)
|
||||||
return(ESRCH);
|
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);
|
r= sys_trace(m_in.request,child->mp_endpoint,m_in.taddr,&m_in.data);
|
||||||
if (r != OK) return(r);
|
if (r != OK) return(r);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue