1
0
mirror of https://github.com/prirun/p50em.git synced 2026-04-02 19:40:10 +00:00

RP ring bits weren't being preserved when executing code in registers.

This caused a HLT instruction in the register to halt the machine from ring 3
This commit is contained in:
Jim
2007-10-09 00:00:00 -04:00
parent 4779beb25e
commit 36254e2fba
3 changed files with 90 additions and 44 deletions

View File

@@ -59,7 +59,7 @@ static inline ea_t ea64v (unsigned short inst, ea_t earp) {
return MAKEVA(ea_s, ea_w);
}
TRACE(T_EAV, " Live register '%o\n", ea_w);
return 0x80000000 | ea_w;
return 0x80000000 | ea_w | (RP & RINGMASK32);
}
i = inst & 0100000; /* indirect is bit 1 (left/MS bit) */
@@ -110,7 +110,7 @@ static inline ea_t ea64v (unsigned short inst, ea_t earp) {
}
TRACE(T_EAV, " Live register '%o\n", ea_w);
return 0x80000000 | ea_w;
return 0x80000000 | ea_w | (RP & RINGMASK32);
/* here for long, 2-word, V-mode memory reference */

124
em.c
View File

@@ -384,32 +384,35 @@ typedef struct {
to hold the virtual page address and corresponding MEM[] pointer
for a few special pages:
- the 4 base registers (PBBR, SBBR, LBBR, XBBR)
- the current instruction page (RPBR)
- sector zero (S0BR) of the current procedure
- the 4 base registers (PBBR, SBBR, LBBR, XBBR)
- field address registers 0 and 1 (F0BR, F1BR)
- "unknown", used for indirect references (UNBR)
When an effective address is calculated, eap is set to point to
one of these cache entries. If the reference is a write reference,
mapva always is called to do access checking. But for reads, the
mapva call might be bypassed if the EA is within the page pointed
to by the eap entry. If the mapva call is not bypassed for read,
then the eap entry is updated.
When an effective address is calculated, eap is set to point to one
of these cache entries. If the EA, which is a virtual address,
references the same page as the cache entry pointed to by eap, then
the mapva call can be bypassed and the physical memory address
calculated using the cache. If the cache can't be used, either
because the entry is invalid or the access isn't allowed (only for
writes), mapva is called to do the mapping and (assuming it doesn't
fault) the eap cache entry is updated.
This special cache is invalidated whenever the STLB is changed,
whenever a ring change occurs, and whenever a process exchange
occurs; no access checking is done when the cache is used: the
cache entry is either valid, meaning that the program has at least
read access to the page, or the cache entry is invalid (special
value of 0x000000FF, which is not a virtual page address - the
right 10 bits must be zero for the start of a page), in which case
mapva is called.
occurs. For reads, no access checking is needed when the cache is
used: the cache entry is either valid, meaning that the program has
at least read access to the page, or the cache entry is invalid
(special value of 0x000000FF, which is not a virtual page address -
the right 10 bits must be zero for the start of a page), in which
case mapva is called.
The special cache could also be used for write references if each
entry were extended to have a "write okay" flag. This would be
set when mapva is called and returns an access of 3 (WACC) instead
of 2 (RACC), and putxx routines could check for write access before
using the cache entry.
The special cache is also be used for write references. Bits 2-4
of the cache entry vpn are the access bits from mapva, so bit 4
being 1 means that writes are allowed.
IMPORTANT NOTE: bit 4 MUST BE CHECKED before all write references!
*/
#define PBBR 0
@@ -431,7 +434,10 @@ typedef struct {
PCL and PRTN when the ring changes).
Storing the access bits in the vpn allows use of of the brp
cache for write accesses as well as read accesses. */
cache for write accesses as well as read accesses. Only bit
4 (write allowed) is used, but since a 3-bit value comes back
from mapva, it's easier just to put it all in vpn.
*/
typedef struct {
unsigned short *memp; /* MEM[] physical page address */
@@ -443,7 +449,7 @@ void *disp_gen[4096]; /* generic dispatch table */
/* "gv" is a static structure used to hold "hot" global variables. These
are pointed to by a dedicated register, so that the usual PowerPC global
variable instructions aren't needed: these variables can be directly
referenced by instructions */
referenced by instructions as long as the structure is < 16K bytes. */
typedef struct {
@@ -475,7 +481,7 @@ typedef struct {
int csoffset; /* concealed stack segment offset */
int livereglim; /* 010 if seg enabled, 040 if disabled */
unsigned int livereglim; /* 010 if seg enabled, 040 if disabled */
int mapvacalls; /* # of mapva calls */
int mapvamisses; /* STLB misses */
@@ -1930,7 +1936,7 @@ static ea_t ea16s (unsigned short inst) {
}
va = MAKEVA(RPH, ea);
if (ea < gvp->livereglim) /* flag live register ea */
return va | 0x80000000;
return 0x80000000 | va | (RP & RINGMASK32);
return va;
}
@@ -1968,7 +1974,7 @@ static ea_t ea32s (unsigned short inst) {
ea &= amask;
va = MAKEVA(RPH, ea);
if (ea < gvp->livereglim) /* flag live register ea */
return va | 0x80000000;
return 0x80000000 | va | (RP & RINGMASK32);
return va;
}
@@ -2032,7 +2038,7 @@ static inline ea_t ea32r64r (ea_t earp, unsigned short inst) {
ea &= amask;
va = MAKEVA(rph, ea);
if (ea < gvp->livereglim) /* flag live register ea */
return va | 0x80000000;
return 0x80000000 | va | (RP & RINGMASK32);
return va;
special:
@@ -2136,7 +2142,7 @@ special:
va = MAKEVA(rph, ea);
if (ea >= gvp->livereglim)
return va;
return va | 0x80000000; /* flag live register ea */
return 0x80000000 | va | (RP & RINGMASK32); /* flag live register ea */
}
#include "ea64v.h"
@@ -4681,6 +4687,7 @@ fetch:
}
gvp->prevpc = RP;
#if 0
/* NOTE: Rev 21 Sys Arch Guide, 2nd Ed, pg 3-32 says:
@@ -4689,23 +4696,32 @@ fetch:
instruction, an address trap always occurs. The only exception
to this is if the machine is operating in 32I mode."
However, if this code is enabled, the Primos boot fails very
early, before verifying memory.
NOTE 8/21/07: I think the problem here is that the test should
be:
The line below is equivalent to:
ea = RP
if !i-mode
if segmented and ealow < 010 or !segmented and ealow < 040
set ea to trap
NOTE 10/9/2007 (JW):
iget16 has checks for RP < 0 to indicate an address trap, and all
of the EA calculations can generate traps (and set the high-order
bit) except 32I.
If it's a bad idea for RP to have the high-order bit set, then
this code can be enabled, along with special handling in JMP,
JSXB, JSY, JSX, and JST that is currently disabled. I couldn't
see that one way worked better than the other, except enabling
this check on every instruction fetch is more overhead. Setting
the HO bit of RP does expose this to Primos when a fault occurs
while executing code in registers.
*/
ea = RP;
if ((ea & 0xFFFF) < 010)
ea = 0x80000000 | (ea & 0xFFFF);
inst = iget16(RP | ((RPL >= gvp->livereglim || (crs[KEYS] & 0016000) == 010000) ? 0 : 0x80000000));
#else
inst = iget16(RP);
#endif
inst = iget16(RP);
INCRP;
/* while a process is running, RP is the real program counter, PBH
@@ -4897,7 +4913,7 @@ d_lfli0: /* 001303 */
TRACE(T_FLOW, " LFLI 0\n");
utempa = iget16(RP);
PUTFLR(0,utempa);
RP++;
INCRP;
TRACE(T_FLOW, " Load Field length with %d, FLR=%x, actual = %d\n", utempa, crsl[FLR0], GETFLR(0));
goto fetch;
@@ -5812,6 +5828,7 @@ d_cea: /* 000111 */
ea += crs[X];
if (!i) /* not indirect */
break;
/* XXX: should this be gvp->livereglim? */
if (ea < 040)
m = get16(0x80000000|ea);
else
@@ -5826,6 +5843,7 @@ d_cea: /* 000111 */
case 3: /* 32R */
while (crs[A] & 0100000) {
ea = crs[A] & 077777;
/* XXX: should this be gvp->livereglim? */
if (ea < 040)
crs[A] = get16(0x80000000|ea);
else
@@ -8968,7 +8986,12 @@ d_stadst: /* 00400 (R-mode) */
d_jmp: /* 00100 */
TRACE(T_FLOW, " JMP\n");
RP = ea;
#if 0
if (*(int *)&ea < 0) /* jumping to register address */
RPL = ea; /* preserve segment number in RP */
else
#endif
RP = ea;
goto fetch;
d_ana: /* 00300 */
@@ -9071,7 +9094,13 @@ d_jst: /* 01000 */
else
m = (get16t(ea) & ~gvp->amask) | RPL;
put16t(m, ea);
RP = INCVA(ea,1);
#if 0
if (*(int *)&ea < 0) /* jumping to register address */
RPL = ea; /* preserve segment number in RP */
else
#endif
RP = ea;
INCRP;
gvp->brp[RPBR] = *eap;
if ((RP & RINGMASK32) == 0)
gvp->inhcount = 1;
@@ -9133,13 +9162,23 @@ d_ima: /* 01300 */
d_jsy: /* 01400 */
TRACE(T_FLOW, " JSY\n");
crs[Y] = RPL;
RP = ea;
#if 0
if (*(int *)&ea < 0) /* jumping to register address */
RPL = ea; /* preserve segment number in RP */
else
#endif
RP = ea;
goto fetch;
d_jsxb: /* 01402 */
TRACE(T_FLOW, " JSXB\n");
*(unsigned int *)(crs+XB) = RP;
RP = ea;
#if 0
if (*(int *)&ea < 0) /* jumping to register address */
RPL = ea; /* preserve segment number in RP */
else
#endif
RP = ea;
goto fetch;
d_stx: /* 01500 */
@@ -9366,7 +9405,12 @@ d_ldy: /* 03501 */
d_jsx: /* 03503 */
TRACE(T_FLOW, " JSX\n");
crs[X] = RPL;
RP = ea;
#if 0
if (*(int *)&ea < 0) /* jumping to register address */
RPL = ea; /* preserve segment number in RP */
else
#endif
RP = ea;
goto fetch;
/* XXX: this should set the L bit like subtract */

View File

@@ -450,8 +450,8 @@ readasr:
if (gvp->savetraceflags == 0) {
TRACEA("\nTRACE ENABLED:\n\n");
gvp->savetraceflags = ~TB_MAP;
gvp->savetraceflags = ~0;
gvp->savetraceflags = TB_FLOW;
gvp->savetraceflags = ~0;
} else {
TRACEA("\nTRACE DISABLED:\n\n");
gvp->savetraceflags = 0;
@@ -1504,10 +1504,11 @@ int devcp (int class, int func, int device) {
the correct time. In addition to lowering overhead, slower
clock tick rates make catching up much faster. */
#ifndef FIXEDCLOCK
if (abs(ticks-targetticks) > 5000 && datnowea != 0)
ticks = -1;
else if (ticks < targetticks)
devpoll[device] = 100; /* behind, so catch-up */
devpoll[device] = 200; /* behind, so catch-up */
else if (ticks > targetticks)
devpoll[device] = devpoll[device]*2; /* ahead, so slow down */
else { /* just right! */
@@ -1516,6 +1517,7 @@ int devcp (int class, int func, int device) {
ticks = 0;
}
}
#endif
/* update instpermsec every 5 seconds. Check for instcount
overflow and reset when it occurs.