diff options
| author | Nick Barnes | 2001-10-31 14:40:56 +0000 |
|---|---|---|
| committer | Nick Barnes | 2001-10-31 14:40:56 +0000 |
| commit | 7acfca905d76140f4cc0b09c9a12de237de364cd (patch) | |
| tree | 3ed8babfa3a73d30f29e08ca5d5adcda4ca4e826 /mps/code/proti3.c | |
| parent | b7ce4893f9902d57cd67ac9a92fa6c3d5a8fc833 (diff) | |
| download | emacs-7acfca905d76140f4cc0b09c9a12de237de364cd.tar.gz emacs-7acfca905d76140f4cc0b09c9a12de237de364cd.zip | |
Branch imports for masters.
Copied from Perforce
Change: 23678
ServerID: perforce.ravenbrook.com
Diffstat (limited to 'mps/code/proti3.c')
| -rw-r--r-- | mps/code/proti3.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/mps/code/proti3.c b/mps/code/proti3.c new file mode 100644 index 00000000000..1056ec5a96e --- /dev/null +++ b/mps/code/proti3.c | |||
| @@ -0,0 +1,240 @@ | |||
| 1 | /* impl.c.proti3: PROTECTION MUTATOR CONTEXT (INTEL 386) | ||
| 2 | * | ||
| 3 | * $HopeName: MMsrc!proti3.c(trunk.1) $ | ||
| 4 | * Copyright (C) 1999 Harlequin Limited. All rights reserved. | ||
| 5 | * | ||
| 6 | * .design: See design.mps.prot for the generic design of the interface | ||
| 7 | * which is implemented in this module, including the contracts for the | ||
| 8 | * functions. | ||
| 9 | * | ||
| 10 | * .purpose: This module implements the part of the protection module | ||
| 11 | * that implements the MutatorFaultContext type. | ||
| 12 | * | ||
| 13 | * .requirements: Current requirements are for limited support only, for | ||
| 14 | * stepping the sorts of instructions that the Dylan compiler might | ||
| 15 | * generate for table vector access - i.e., a restricted subset of MOV | ||
| 16 | * addressing modes. This avoids the need to scan entire weak tables at | ||
| 17 | * an inappropriate rank when a page fault occurs. | ||
| 18 | * | ||
| 19 | * | ||
| 20 | * SOURCES | ||
| 21 | * | ||
| 22 | * .source.i486: Intel486 Microprocessor Family Programmer's | ||
| 23 | * Reference Manual | ||
| 24 | * | ||
| 25 | * .source.dylan: Dylan table code implementation. Especially the | ||
| 26 | * following HOPE units: | ||
| 27 | * D-lib-dylan!table.dylan (class <entry-vector>, slot entry-element) | ||
| 28 | * D-dfmc-harp-cg!harp-primitives.dylan (method op--repeated-slot-element) | ||
| 29 | * D-harp-pentium-harp!moves.dylan (pentium-template ld-index) | ||
| 30 | * | ||
| 31 | * | ||
| 32 | * ASSUMPTIONS | ||
| 33 | * | ||
| 34 | * .assume.null: It's always safe for Prot*StepInstruction to return | ||
| 35 | * ResUNIMPL. A null implementation of this module would be overly | ||
| 36 | * conservative but otherwise correct. | ||
| 37 | * | ||
| 38 | * .assume.want: The Dylan implementation is likely to access a | ||
| 39 | * weak table vector using either MOV r/m32,r32 or MOV r32,r/m32 | ||
| 40 | * instructions, where the r/m32 operand will be of one of the forms | ||
| 41 | * disp8[reg], disp8[reg1][reg2], disp8[reg1][reg2*4] (see .source.dylan | ||
| 42 | * and .source.i486) | ||
| 43 | * | ||
| 44 | * .assume.i3: Assume the following about the i386 environment: | ||
| 45 | * Steppable instructions (.assume.want) use the CS, DS & SS | ||
| 46 | * segment registers only (see .source.i486 Table 2-3). | ||
| 47 | * The procesor runs in 32 bit mode. | ||
| 48 | * The CS, DS and SS segment registers all describe identical 32- | ||
| 49 | * bit flat address spaces. | ||
| 50 | */ | ||
| 51 | |||
| 52 | #include "mpm.h" | ||
| 53 | #include "prmci3.h" | ||
| 54 | |||
| 55 | SRCID(proti3, "$HopeName$"); | ||
| 56 | |||
| 57 | |||
| 58 | /* DecodeCB -- Decode an Intel x86 control byte into Hi, Medium & Low fields */ | ||
| 59 | |||
| 60 | static void DecodeCB(unsigned int *hReturn, | ||
| 61 | unsigned int *mReturn, | ||
| 62 | unsigned int *lReturn, | ||
| 63 | Byte op) | ||
| 64 | { | ||
| 65 | /* see .source.i486 Figure 26-2 */ | ||
| 66 | unsigned int uop = (unsigned int)op; | ||
| 67 | *lReturn = uop & 7; | ||
| 68 | uop = uop >> 3; | ||
| 69 | *mReturn = uop & 7; | ||
| 70 | uop = uop >> 3; | ||
| 71 | *hReturn = uop & 3; | ||
| 72 | } | ||
| 73 | |||
| 74 | |||
| 75 | /* DecodeSIB -- Decode a Scale Index Base byte for an Intel x86 instruction */ | ||
| 76 | |||
| 77 | static void DecodeSIB(unsigned int *sReturn, | ||
| 78 | unsigned int *iReturn, | ||
| 79 | unsigned int *bReturn, | ||
| 80 | Byte op) | ||
| 81 | { | ||
| 82 | DecodeCB(sReturn, iReturn, bReturn, op); | ||
| 83 | } | ||
| 84 | |||
| 85 | |||
| 86 | /* DecodeModRM -- Decode a ModR/M byte for an Intel x86 instruction */ | ||
| 87 | |||
| 88 | static void DecodeModRM(unsigned int *modReturn, | ||
| 89 | unsigned int *rReturn, | ||
| 90 | unsigned int *mReturn, | ||
| 91 | Byte op) | ||
| 92 | { | ||
| 93 | DecodeCB(modReturn, rReturn, mReturn, op); | ||
| 94 | } | ||
| 95 | |||
| 96 | |||
| 97 | /* RegValue -- Return the value of a machine register from a context */ | ||
| 98 | |||
| 99 | static Word RegValue(MutatorFaultContext context, unsigned int regnum) | ||
| 100 | { | ||
| 101 | MRef addr; | ||
| 102 | |||
| 103 | addr = Prmci3AddressHoldingReg(context, regnum); | ||
| 104 | return *addr; | ||
| 105 | } | ||
| 106 | |||
| 107 | |||
| 108 | /* Return a byte element of an instruction vector as a | ||
| 109 | * Word value, with sign extension | ||
| 110 | */ | ||
| 111 | static Word SignedInsElt(Byte insvec[], Count i) | ||
| 112 | { | ||
| 113 | signed char eltb; | ||
| 114 | |||
| 115 | eltb = ((signed char*)insvec)[i]; | ||
| 116 | return (Word)eltb; | ||
| 117 | } | ||
| 118 | |||
| 119 | |||
| 120 | /* If a MOV instruction is a sufficiently simple example of a | ||
| 121 | * move between a register and memory (in either direction), | ||
| 122 | * then find the register, the effective address and the size | ||
| 123 | * of the instruction. The instruction is considered sufficiently | ||
| 124 | * simple if it uses a single byte displacement, a base register, | ||
| 125 | * and either no index or a (possibly scaled) register. | ||
| 126 | */ | ||
| 127 | static Bool DecodeSimpleMov(unsigned int *regnumReturn, | ||
| 128 | MRef *memReturn, | ||
| 129 | Size *inslenReturn, | ||
| 130 | MutatorFaultContext context, | ||
| 131 | Byte insvec[]) | ||
| 132 | { | ||
| 133 | unsigned int mod; | ||
| 134 | unsigned int r; | ||
| 135 | unsigned int m; | ||
| 136 | |||
| 137 | DecodeModRM(&mod, &r, &m, insvec[1]); /* .source.i486 Table 26-3 */ | ||
| 138 | if (1 == mod) { | ||
| 139 | /* only know about single byte displacements, .assume.want */ | ||
| 140 | Word base; | ||
| 141 | Word index; | ||
| 142 | Word disp; | ||
| 143 | |||
| 144 | if (4 == m) { | ||
| 145 | /* There is an index */ | ||
| 146 | unsigned int s; | ||
| 147 | unsigned int i; | ||
| 148 | unsigned int b; | ||
| 149 | |||
| 150 | DecodeSIB(&s, &i, &b, insvec[2]); /* .source.i486 Table 26-3 */ | ||
| 151 | if (4 == i) | ||
| 152 | return FALSE; /* degenerate SIB form - unused by Dylan compiler */ | ||
| 153 | disp = SignedInsElt(insvec, 3); | ||
| 154 | base = RegValue(context, b); | ||
| 155 | index = RegValue(context, i) << s; | ||
| 156 | *inslenReturn = 4; | ||
| 157 | } else { | ||
| 158 | /* MOV with reg1 & [reg2+byte] parameters */ | ||
| 159 | disp = SignedInsElt(insvec, 2); | ||
| 160 | base = RegValue(context, m); | ||
| 161 | index = 0; | ||
| 162 | *inslenReturn = 3; | ||
| 163 | } | ||
| 164 | *regnumReturn = r; | ||
| 165 | *memReturn = (MRef)(base + index + disp); /* .assume.i3 */ | ||
| 166 | return TRUE; | ||
| 167 | } | ||
| 168 | |||
| 169 | return FALSE; | ||
| 170 | } | ||
| 171 | |||
| 172 | |||
| 173 | static Bool IsSimpleMov(Size *inslenReturn, | ||
| 174 | MRef *srcReturn, | ||
| 175 | MRef *destReturn, | ||
| 176 | MutatorFaultContext context) | ||
| 177 | { | ||
| 178 | Byte *insvec; | ||
| 179 | unsigned int regnum; | ||
| 180 | MRef mem; | ||
| 181 | MRef faultmem; | ||
| 182 | |||
| 183 | Prmci3DecodeFaultContext(&faultmem, &insvec, context); | ||
| 184 | |||
| 185 | /* .assume.want */ | ||
| 186 | /* .source.i486 Page 26-210 */ | ||
| 187 | if ((Byte)0x8b == insvec[0]) { | ||
| 188 | /* This is an instruction of type MOV reg, r/m32 */ | ||
| 189 | if (DecodeSimpleMov(®num, &mem, inslenReturn, context, insvec)) { | ||
| 190 | AVER(faultmem == mem); /* Ensure computed address matches exception */ | ||
| 191 | *srcReturn = mem; | ||
| 192 | *destReturn = Prmci3AddressHoldingReg(context, regnum); | ||
| 193 | return TRUE; | ||
| 194 | } | ||
| 195 | } else if ((Byte)0x89 == insvec[0]) { | ||
| 196 | /* This is an instruction of type MOV r/m32, reg */ | ||
| 197 | if (DecodeSimpleMov(®num, &mem, inslenReturn, context, insvec)) { | ||
| 198 | AVER(faultmem == mem); /* Ensure computed address matches exception */ | ||
| 199 | *destReturn = mem; | ||
| 200 | *srcReturn = Prmci3AddressHoldingReg(context, regnum); | ||
| 201 | return TRUE; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | return FALSE; | ||
| 206 | } | ||
| 207 | |||
| 208 | |||
| 209 | Bool ProtCanStepInstruction(MutatorFaultContext context) | ||
| 210 | { | ||
| 211 | Size inslen; | ||
| 212 | MRef src; | ||
| 213 | MRef dest; | ||
| 214 | |||
| 215 | /* .assume.null */ | ||
| 216 | /* .assume.want */ | ||
| 217 | if (IsSimpleMov(&inslen, &src, &dest, context)) { | ||
| 218 | return TRUE; | ||
| 219 | } | ||
| 220 | |||
| 221 | return FALSE; | ||
| 222 | } | ||
| 223 | |||
| 224 | |||
| 225 | Res ProtStepInstruction(MutatorFaultContext context) | ||
| 226 | { | ||
| 227 | Size inslen; | ||
| 228 | MRef src; | ||
| 229 | MRef dest; | ||
| 230 | |||
| 231 | /* .assume.null */ | ||
| 232 | /* .assume.want */ | ||
| 233 | if (IsSimpleMov(&inslen, &src, &dest, context)) { | ||
| 234 | *dest = *src; | ||
| 235 | Prmci3StepOverIns(context, inslen); | ||
| 236 | return ResOK; | ||
| 237 | } | ||
| 238 | |||
| 239 | return ResUNIMPL; | ||
| 240 | } | ||