PDP11: Properly range check DMA access to the I/O page

Make sure that DMA access to the I/O page can only see addresses on the
Qbus/Unibus and not internal CPU registers
This commit is contained in:
Mark Pizzolato 2018-09-06 11:03:45 -07:00
parent 5f0370749e
commit 7677dad67d
16 changed files with 56 additions and 22 deletions

View file

@ -528,6 +528,8 @@ struct pdp_dib {
/* DEVICE structure (e.g., DZ, VH, DL, DC). */ /* DEVICE structure (e.g., DZ, VH, DL, DC). */
/* Populated by auto-configure */ /* Populated by auto-configure */
struct pdp_dib *next; /* devices with more than one DIB can chain them */ struct pdp_dib *next; /* devices with more than one DIB can chain them */
DEVICE *dptr; /* back pointer to related device */
/* Populated by auto-configure */
}; };
typedef struct pdp_dib DIB; typedef struct pdp_dib DIB;

View file

@ -66,6 +66,7 @@ extern void fixup_mbus_tab (void);
t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md); t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md);
t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md);
DIB *iodibp[IOPAGESIZE >> 1];
int32 int_vec[IPL_HLVL][32]; /* int req to vector */ int32 int_vec[IPL_HLVL][32]; /* int req to vector */
int32 (*int_ack[IPL_HLVL][32])(void); /* int ack routines */ int32 (*int_ack[IPL_HLVL][32])(void); /* int ack routines */
@ -119,6 +120,23 @@ if (iodispW[idx]) {
return SCPE_NXM; return SCPE_NXM;
} }
/* I/O page CPU register verifier
Inputs:
pa = address
Outputs:
status = TRUE or FALSE
*/
t_bool iopageCPUReg (uint32 pa)
{
int32 idx;
DIB *dibp;
idx = (pa & IOPAGEMASK) >> 1;
dibp = iodibp[idx];
return (dibp && (dibp->dptr == &cpu_dev));
}
/* Calculate interrupt outstanding /* Calculate interrupt outstanding
In a Qbus system, all device interrupts are treated as BR4 */ In a Qbus system, all device interrupts are treated as BR4 */
@ -237,11 +255,12 @@ int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf)
{ {
uint32 alim, lim, ma; uint32 alim, lim, ma;
if (ba >= IOPAGEBASE) { if (ba >= (IOPAGEBASE & BUSMASK)) {
int32 value; int32 value;
while (bc) { while (bc) {
if (iopageR( &value, (ba & ~1), READ) != SCPE_OK) if (iopageCPUReg (ba) ||
(iopageR( &value, (ba & ~1), READ) != SCPE_OK))
break; break;
*buf++ = (uint8) (((ba & 1)? (value >> 8): value) & 0xff); *buf++ = (uint8) (((ba & 1)? (value >> 8): value) & 0xff);
ba++; ba++;
@ -277,12 +296,13 @@ int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf)
{ {
uint32 alim, lim, ma; uint32 alim, lim, ma;
if (ba >= IOPAGEBASE) { if (ba >= (IOPAGEBASE & BUSMASK)) {
int32 value; int32 value;
if ((ba & 1) || (bc & 1)) if ((ba & 1) || (bc & 1))
return bc; return bc;
while (bc) { while (bc) {
if (iopageR( &value, ba, READ) != SCPE_OK) if (iopageCPUReg (ba) ||
(iopageR( &value, ba, READ) != SCPE_OK))
break; break;
*buf++ = (uint16) (value & 0xffff); *buf++ = (uint16) (value & 0xffff);
ba += 2; ba += 2;
@ -318,9 +338,10 @@ int32 Map_WriteB (uint32 ba, int32 bc, const uint8 *buf)
{ {
uint32 alim, lim, ma; uint32 alim, lim, ma;
if (ba >= IOPAGEBASE) { if (ba >= (IOPAGEBASE & BUSMASK)) {
while (bc) { while (bc) {
if (iopageW( ((int32) *buf++) & 0xff, ba, WRITEB) != SCPE_OK) if (iopageCPUReg (ba) ||
(iopageW( ((int32) *buf++) & 0xff, ba, WRITEB) != SCPE_OK))
break; break;
ba++; ba++;
bc--; bc--;
@ -355,11 +376,12 @@ int32 Map_WriteW (uint32 ba, int32 bc, const uint16 *buf)
{ {
uint32 alim, lim, ma; uint32 alim, lim, ma;
if (ba >= IOPAGEBASE) { if (ba >= (IOPAGEBASE & BUSMASK)) {
if ((ba & 1) || (bc & 1)) if ((ba & 1) || (bc & 1))
return bc; return bc;
while (bc) { while (bc) {
if (iopageW( ((int32) *buf++) & 0xffff, ba, WRITE) != SCPE_OK) if (iopageCPUReg (ba) ||
(iopageW( ((int32) *buf++) & 0xffff, ba, WRITE) != SCPE_OK))
break; break;
ba += 2; ba += 2;
bc -= 2; bc -= 2;

View file

@ -47,11 +47,10 @@ extern int32 int_vec_set[IPL_HLVL][32]; /* bits to set in vector
extern int32 (*int_ack[IPL_HLVL][32])(void); extern int32 (*int_ack[IPL_HLVL][32])(void);
extern t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md); extern t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md);
extern t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); extern t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md);
extern DIB *iodibp[IOPAGESIZE >> 1];
extern t_stat build_dib_tab (void); extern t_stat build_dib_tab (void);
static DIB *iodibp[IOPAGESIZE >> 1];
static void build_vector_tab (void); static void build_vector_tab (void);
#if !defined(UNIMEMSIZE) #if !defined(UNIMEMSIZE)
@ -307,6 +306,7 @@ const char *cdname;
if ((dptr == NULL) || (dibp == NULL)) /* validate args */ if ((dptr == NULL) || (dibp == NULL)) /* validate args */
return SCPE_IERR; return SCPE_IERR;
dibp->dptr = dptr; /* save back pointer */
if (dibp->vnum > VEC_DEVMAX) if (dibp->vnum > VEC_DEVMAX)
return SCPE_IERR; return SCPE_IERR;
vec = dibp->vec; vec = dibp->vec;
@ -453,12 +453,7 @@ for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */
size_t l; size_t l;
if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */ if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */
dibp = iodibp[i]; /* DIB for block */ dibp = iodibp[i]; /* DIB for block */
for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) { dptr = dibp->dptr;
if (((DIB*) sim_devices[j]->ctxt) == dibp) {
dptr = sim_devices[j]; /* locate device */
break;
} /* end if */
} /* end for j */
if ((dibp->ba+ dibp->lnt - 1) > maxaddr) if ((dibp->ba+ dibp->lnt - 1) > maxaddr)
maxaddr = dibp->ba+ dibp->lnt - 1; maxaddr = dibp->ba+ dibp->lnt - 1;
if (dibp->vec > maxvec) if (dibp->vec > maxvec)
@ -522,12 +517,7 @@ fputc ('\n', st);
for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */ for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */
if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */ if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */
dibp = iodibp[i]; /* DIB for block */ dibp = iodibp[i]; /* DIB for block */
for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) { dptr = dibp->dptr; /* locate device */
if (((DIB*) sim_devices[j]->ctxt) == dibp) {
dptr = sim_devices[j]; /* locate device */
break;
} /* end if */
} /* end for j */
fprint_val (st, (t_value) dibp->ba, DEV_RDX, 32, PV_LEFT); fprint_val (st, (t_value) dibp->ba, DEV_RDX, 32, PV_LEFT);
fprintf (st, " - "); fprintf (st, " - ");
fprint_val (st, (t_value) dibp->ba + dibp->lnt - 1, DEV_RDX, 32, PV_LEFT); fprint_val (st, (t_value) dibp->ba + dibp->lnt - 1, DEV_RDX, 32, PV_LEFT);

View file

@ -206,6 +206,8 @@ typedef struct {
/* simulated through a single */ /* simulated through a single */
/* DEVICE structure (e.g., DZ, VH, DL, DC). */ /* DEVICE structure (e.g., DZ, VH, DL, DC). */
/* Populated by auto-configure */ /* Populated by auto-configure */
DEVICE *dptr; /* back pointer to related device */
/* Populated by auto-configure */
} DIB; } DIB;
/* Qbus I/O page layout - see pdp11_io_lib.c for address layout details */ /* Qbus I/O page layout - see pdp11_io_lib.c for address layout details */

View file

@ -80,6 +80,7 @@ DEVICE qba_dev = {
t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md); t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md);
t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md);
DIB *iodibp[IOPAGESIZE >> 1];
/* Interrupt request to interrupt action map */ /* Interrupt request to interrupt action map */

View file

@ -256,6 +256,8 @@ typedef struct {
/* simulated through a single */ /* simulated through a single */
/* DEVICE structure (e.g., DZ, VH, DL, DC). */ /* DEVICE structure (e.g., DZ, VH, DL, DC). */
/* Populated by auto-configure */ /* Populated by auto-configure */
DEVICE *dptr; /* back pointer to related device */
/* Populated by auto-configure */
} DIB; } DIB;
/* Qbus I/O page layout - see pdp11_io_lib.c for address layout details */ /* Qbus I/O page layout - see pdp11_io_lib.c for address layout details */

View file

@ -151,6 +151,7 @@ DEVICE qba_dev = {
t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md); t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md);
t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md);
DIB *iodibp[IOPAGESIZE >> 1];
/* Interrupt request to interrupt action map */ /* Interrupt request to interrupt action map */

View file

@ -249,6 +249,8 @@ typedef struct {
/* simulated through a single */ /* simulated through a single */
/* DEVICE structure (e.g., DZ, VH, DL, DC). */ /* DEVICE structure (e.g., DZ, VH, DL, DC). */
/* Populated by auto-configure */ /* Populated by auto-configure */
DEVICE *dptr; /* back pointer to related device */
/* Populated by auto-configure */
} DIB; } DIB;
/* Unibus I/O page layout - see pdp11_io_lib.c for address layout details */ /* Unibus I/O page layout - see pdp11_io_lib.c for address layout details */

View file

@ -117,6 +117,7 @@ extern t_stat rb_wr32 (int32 data, int32 PA, int32 access);
t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md); t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md);
t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md);
DIB *iodibp[IOPAGESIZE >> 1];
/* Unibus interrupt request to interrupt action map */ /* Unibus interrupt request to interrupt action map */

View file

@ -289,6 +289,8 @@ typedef struct {
/* simulated through a single */ /* simulated through a single */
/* DEVICE structure (e.g., DZ, VH, DL, DC). */ /* DEVICE structure (e.g., DZ, VH, DL, DC). */
/* Populated by auto-configure */ /* Populated by auto-configure */
DEVICE *dptr; /* back pointer to related device */
/* Populated by auto-configure */
} DIB; } DIB;
/* Unibus I/O page layout - see pdp11_io_lib.c for address layout details /* Unibus I/O page layout - see pdp11_io_lib.c for address layout details

View file

@ -105,6 +105,7 @@ extern void cmi_set_tmo (void);
t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md); t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md);
t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md);
DIB *iodibp[IOPAGESIZE >> 1];
/* Unibus interrupt request to interrupt action map */ /* Unibus interrupt request to interrupt action map */

View file

@ -305,6 +305,8 @@ typedef struct {
/* simulated through a single */ /* simulated through a single */
/* DEVICE structure (e.g., DZ, VH, DL, DC). */ /* DEVICE structure (e.g., DZ, VH, DL, DC). */
/* Populated by auto-configure */ /* Populated by auto-configure */
DEVICE *dptr; /* back pointer to related device */
/* Populated by auto-configure */
} DIB; } DIB;
/* Unibus I/O page layout - see pdp11_io_lib.c for address layout details /* Unibus I/O page layout - see pdp11_io_lib.c for address layout details

View file

@ -209,6 +209,7 @@ extern t_stat build_dib_tab (void);
t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md); t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md);
t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md);
DIB *iodibp[IOPAGESIZE >> 1];
/* Unibus interrupt request to interrupt action map */ /* Unibus interrupt request to interrupt action map */

View file

@ -333,6 +333,8 @@ typedef struct {
/* simulated through a single */ /* simulated through a single */
/* DEVICE structure (e.g., DZ, VH, DL, DC). */ /* DEVICE structure (e.g., DZ, VH, DL, DC). */
/* Populated by auto-configure */ /* Populated by auto-configure */
DEVICE *dptr; /* back pointer to related device */
/* Populated by auto-configure */
} DIB; } DIB;
/* Unibus I/O page layout - XUB,RQB,RQC,RQD float based on number of DZ's /* Unibus I/O page layout - XUB,RQB,RQC,RQD float based on number of DZ's

View file

@ -190,6 +190,7 @@ DEVICE qba_dev = {
t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md); t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md);
t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md);
DIB *iodibp[IOPAGESIZE >> 1];
/* Interrupt request to interrupt action map */ /* Interrupt request to interrupt action map */

View file

@ -308,6 +308,8 @@ typedef struct {
/* simulated through a single */ /* simulated through a single */
/* DEVICE structure (e.g., DZ, VH, DL, DC). */ /* DEVICE structure (e.g., DZ, VH, DL, DC). */
/* Populated by auto-configure */ /* Populated by auto-configure */
DEVICE *dptr; /* back pointer to related device */
/* Populated by auto-configure */
} DIB; } DIB;
/* Qbus I/O page layout - see pdp11_io_lib.c for address layout details */ /* Qbus I/O page layout - see pdp11_io_lib.c for address layout details */