diff options
| -rw-r--r-- | arch/x86/mm/pf_in.c | 121 |
1 files changed, 84 insertions, 37 deletions
diff --git a/arch/x86/mm/pf_in.c b/arch/x86/mm/pf_in.c index efa1911e20ca..df3d5c861cda 100644 --- a/arch/x86/mm/pf_in.c +++ b/arch/x86/mm/pf_in.c | |||
| @@ -79,25 +79,34 @@ static unsigned int mw32[] = { 0xC7 }; | |||
| 79 | static unsigned int mw64[] = { 0x89, 0x8B }; | 79 | static unsigned int mw64[] = { 0x89, 0x8B }; |
| 80 | #endif /* not __i386__ */ | 80 | #endif /* not __i386__ */ |
| 81 | 81 | ||
| 82 | static int skip_prefix(unsigned char *addr, int *shorted, int *enlarged, | 82 | struct prefix_bits { |
| 83 | int *rexr) | 83 | unsigned shorted:1; |
| 84 | unsigned enlarged:1; | ||
| 85 | unsigned rexr:1; | ||
| 86 | unsigned rex:1; | ||
| 87 | }; | ||
| 88 | |||
| 89 | static int skip_prefix(unsigned char *addr, struct prefix_bits *prf) | ||
| 84 | { | 90 | { |
| 85 | int i; | 91 | int i; |
| 86 | unsigned char *p = addr; | 92 | unsigned char *p = addr; |
| 87 | *shorted = 0; | 93 | prf->shorted = 0; |
| 88 | *enlarged = 0; | 94 | prf->enlarged = 0; |
| 89 | *rexr = 0; | 95 | prf->rexr = 0; |
| 96 | prf->rex = 0; | ||
| 90 | 97 | ||
| 91 | restart: | 98 | restart: |
| 92 | for (i = 0; i < ARRAY_SIZE(prefix_codes); i++) { | 99 | for (i = 0; i < ARRAY_SIZE(prefix_codes); i++) { |
| 93 | if (*p == prefix_codes[i]) { | 100 | if (*p == prefix_codes[i]) { |
| 94 | if (*p == 0x66) | 101 | if (*p == 0x66) |
| 95 | *shorted = 1; | 102 | prf->shorted = 1; |
| 96 | #ifdef __amd64__ | 103 | #ifdef __amd64__ |
| 97 | if ((*p & 0xf8) == 0x48) | 104 | if ((*p & 0xf8) == 0x48) |
| 98 | *enlarged = 1; | 105 | prf->enlarged = 1; |
| 99 | if ((*p & 0xf4) == 0x44) | 106 | if ((*p & 0xf4) == 0x44) |
| 100 | *rexr = 1; | 107 | prf->rexr = 1; |
| 108 | if ((*p & 0xf0) == 0x40) | ||
| 109 | prf->rex = 1; | ||
| 101 | #endif | 110 | #endif |
| 102 | p++; | 111 | p++; |
| 103 | goto restart; | 112 | goto restart; |
| @@ -135,12 +144,12 @@ enum reason_type get_ins_type(unsigned long ins_addr) | |||
| 135 | { | 144 | { |
| 136 | unsigned int opcode; | 145 | unsigned int opcode; |
| 137 | unsigned char *p; | 146 | unsigned char *p; |
| 138 | int shorted, enlarged, rexr; | 147 | struct prefix_bits prf; |
| 139 | int i; | 148 | int i; |
| 140 | enum reason_type rv = OTHERS; | 149 | enum reason_type rv = OTHERS; |
| 141 | 150 | ||
| 142 | p = (unsigned char *)ins_addr; | 151 | p = (unsigned char *)ins_addr; |
| 143 | p += skip_prefix(p, &shorted, &enlarged, &rexr); | 152 | p += skip_prefix(p, &prf); |
| 144 | p += get_opcode(p, &opcode); | 153 | p += get_opcode(p, &opcode); |
| 145 | 154 | ||
| 146 | CHECK_OP_TYPE(opcode, reg_rop, REG_READ); | 155 | CHECK_OP_TYPE(opcode, reg_rop, REG_READ); |
| @@ -156,10 +165,11 @@ static unsigned int get_ins_reg_width(unsigned long ins_addr) | |||
| 156 | { | 165 | { |
| 157 | unsigned int opcode; | 166 | unsigned int opcode; |
| 158 | unsigned char *p; | 167 | unsigned char *p; |
| 159 | int i, shorted, enlarged, rexr; | 168 | struct prefix_bits prf; |
| 169 | int i; | ||
| 160 | 170 | ||
| 161 | p = (unsigned char *)ins_addr; | 171 | p = (unsigned char *)ins_addr; |
| 162 | p += skip_prefix(p, &shorted, &enlarged, &rexr); | 172 | p += skip_prefix(p, &prf); |
| 163 | p += get_opcode(p, &opcode); | 173 | p += get_opcode(p, &opcode); |
| 164 | 174 | ||
| 165 | for (i = 0; i < ARRAY_SIZE(rw8); i++) | 175 | for (i = 0; i < ARRAY_SIZE(rw8); i++) |
| @@ -168,7 +178,7 @@ static unsigned int get_ins_reg_width(unsigned long ins_addr) | |||
| 168 | 178 | ||
| 169 | for (i = 0; i < ARRAY_SIZE(rw32); i++) | 179 | for (i = 0; i < ARRAY_SIZE(rw32); i++) |
| 170 | if (rw32[i] == opcode) | 180 | if (rw32[i] == opcode) |
| 171 | return (shorted ? 2 : (enlarged ? 8 : 4)); | 181 | return prf.shorted ? 2 : (prf.enlarged ? 8 : 4); |
| 172 | 182 | ||
| 173 | printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode); | 183 | printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode); |
| 174 | return 0; | 184 | return 0; |
| @@ -178,10 +188,11 @@ unsigned int get_ins_mem_width(unsigned long ins_addr) | |||
| 178 | { | 188 | { |
| 179 | unsigned int opcode; | 189 | unsigned int opcode; |
| 180 | unsigned char *p; | 190 | unsigned char *p; |
| 181 | int i, shorted, enlarged, rexr; | 191 | struct prefix_bits prf; |
| 192 | int i; | ||
| 182 | 193 | ||
| 183 | p = (unsigned char *)ins_addr; | 194 | p = (unsigned char *)ins_addr; |
| 184 | p += skip_prefix(p, &shorted, &enlarged, &rexr); | 195 | p += skip_prefix(p, &prf); |
| 185 | p += get_opcode(p, &opcode); | 196 | p += get_opcode(p, &opcode); |
| 186 | 197 | ||
| 187 | for (i = 0; i < ARRAY_SIZE(mw8); i++) | 198 | for (i = 0; i < ARRAY_SIZE(mw8); i++) |
| @@ -194,11 +205,11 @@ unsigned int get_ins_mem_width(unsigned long ins_addr) | |||
| 194 | 205 | ||
| 195 | for (i = 0; i < ARRAY_SIZE(mw32); i++) | 206 | for (i = 0; i < ARRAY_SIZE(mw32); i++) |
| 196 | if (mw32[i] == opcode) | 207 | if (mw32[i] == opcode) |
| 197 | return shorted ? 2 : 4; | 208 | return prf.shorted ? 2 : 4; |
| 198 | 209 | ||
| 199 | for (i = 0; i < ARRAY_SIZE(mw64); i++) | 210 | for (i = 0; i < ARRAY_SIZE(mw64); i++) |
| 200 | if (mw64[i] == opcode) | 211 | if (mw64[i] == opcode) |
| 201 | return shorted ? 2 : (enlarged ? 8 : 4); | 212 | return prf.shorted ? 2 : (prf.enlarged ? 8 : 4); |
| 202 | 213 | ||
| 203 | printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode); | 214 | printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode); |
| 204 | return 0; | 215 | return 0; |
| @@ -238,7 +249,7 @@ enum { | |||
| 238 | #endif | 249 | #endif |
| 239 | }; | 250 | }; |
| 240 | 251 | ||
| 241 | static unsigned char *get_reg_w8(int no, struct pt_regs *regs) | 252 | static unsigned char *get_reg_w8(int no, int rex, struct pt_regs *regs) |
| 242 | { | 253 | { |
| 243 | unsigned char *rv = NULL; | 254 | unsigned char *rv = NULL; |
| 244 | 255 | ||
| @@ -255,18 +266,6 @@ static unsigned char *get_reg_w8(int no, struct pt_regs *regs) | |||
| 255 | case arg_DL: | 266 | case arg_DL: |
| 256 | rv = (unsigned char *)®s->dx; | 267 | rv = (unsigned char *)®s->dx; |
| 257 | break; | 268 | break; |
| 258 | case arg_AH: | ||
| 259 | rv = 1 + (unsigned char *)®s->ax; | ||
| 260 | break; | ||
| 261 | case arg_BH: | ||
| 262 | rv = 1 + (unsigned char *)®s->bx; | ||
| 263 | break; | ||
| 264 | case arg_CH: | ||
| 265 | rv = 1 + (unsigned char *)®s->cx; | ||
| 266 | break; | ||
| 267 | case arg_DH: | ||
| 268 | rv = 1 + (unsigned char *)®s->dx; | ||
| 269 | break; | ||
| 270 | #ifdef __amd64__ | 269 | #ifdef __amd64__ |
| 271 | case arg_R8: | 270 | case arg_R8: |
| 272 | rv = (unsigned char *)®s->r8; | 271 | rv = (unsigned char *)®s->r8; |
| @@ -294,9 +293,55 @@ static unsigned char *get_reg_w8(int no, struct pt_regs *regs) | |||
| 294 | break; | 293 | break; |
| 295 | #endif | 294 | #endif |
| 296 | default: | 295 | default: |
| 297 | printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no); | ||
| 298 | break; | 296 | break; |
| 299 | } | 297 | } |
| 298 | |||
| 299 | if (rv) | ||
| 300 | return rv; | ||
| 301 | |||
| 302 | if (rex) { | ||
| 303 | /* | ||
| 304 | * If REX prefix exists, access low bytes of SI etc. | ||
| 305 | * instead of AH etc. | ||
| 306 | */ | ||
| 307 | switch (no) { | ||
| 308 | case arg_SI: | ||
| 309 | rv = (unsigned char *)®s->si; | ||
| 310 | break; | ||
| 311 | case arg_DI: | ||
| 312 | rv = (unsigned char *)®s->di; | ||
| 313 | break; | ||
| 314 | case arg_BP: | ||
| 315 | rv = (unsigned char *)®s->bp; | ||
| 316 | break; | ||
| 317 | case arg_SP: | ||
| 318 | rv = (unsigned char *)®s->sp; | ||
| 319 | break; | ||
| 320 | default: | ||
| 321 | break; | ||
| 322 | } | ||
| 323 | } else { | ||
| 324 | switch (no) { | ||
| 325 | case arg_AH: | ||
| 326 | rv = 1 + (unsigned char *)®s->ax; | ||
| 327 | break; | ||
| 328 | case arg_BH: | ||
| 329 | rv = 1 + (unsigned char *)®s->bx; | ||
| 330 | break; | ||
| 331 | case arg_CH: | ||
| 332 | rv = 1 + (unsigned char *)®s->cx; | ||
| 333 | break; | ||
| 334 | case arg_DH: | ||
| 335 | rv = 1 + (unsigned char *)®s->dx; | ||
| 336 | break; | ||
| 337 | default: | ||
| 338 | break; | ||
| 339 | } | ||
| 340 | } | ||
| 341 | |||
| 342 | if (!rv) | ||
| 343 | printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no); | ||
| 344 | |||
| 300 | return rv; | 345 | return rv; |
| 301 | } | 346 | } |
| 302 | 347 | ||
| @@ -368,11 +413,12 @@ unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs) | |||
| 368 | unsigned char mod_rm; | 413 | unsigned char mod_rm; |
| 369 | int reg; | 414 | int reg; |
| 370 | unsigned char *p; | 415 | unsigned char *p; |
| 371 | int i, shorted, enlarged, rexr; | 416 | struct prefix_bits prf; |
| 417 | int i; | ||
| 372 | unsigned long rv; | 418 | unsigned long rv; |
| 373 | 419 | ||
| 374 | p = (unsigned char *)ins_addr; | 420 | p = (unsigned char *)ins_addr; |
| 375 | p += skip_prefix(p, &shorted, &enlarged, &rexr); | 421 | p += skip_prefix(p, &prf); |
| 376 | p += get_opcode(p, &opcode); | 422 | p += get_opcode(p, &opcode); |
| 377 | for (i = 0; i < ARRAY_SIZE(reg_rop); i++) | 423 | for (i = 0; i < ARRAY_SIZE(reg_rop); i++) |
| 378 | if (reg_rop[i] == opcode) { | 424 | if (reg_rop[i] == opcode) { |
| @@ -392,10 +438,10 @@ unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs) | |||
| 392 | 438 | ||
| 393 | do_work: | 439 | do_work: |
| 394 | mod_rm = *p; | 440 | mod_rm = *p; |
| 395 | reg = ((mod_rm >> 3) & 0x7) | (rexr << 3); | 441 | reg = ((mod_rm >> 3) & 0x7) | (prf.rexr << 3); |
| 396 | switch (get_ins_reg_width(ins_addr)) { | 442 | switch (get_ins_reg_width(ins_addr)) { |
| 397 | case 1: | 443 | case 1: |
| 398 | return *get_reg_w8(reg, regs); | 444 | return *get_reg_w8(reg, prf.rex, regs); |
| 399 | 445 | ||
| 400 | case 2: | 446 | case 2: |
| 401 | return *(unsigned short *)get_reg_w32(reg, regs); | 447 | return *(unsigned short *)get_reg_w32(reg, regs); |
| @@ -422,11 +468,12 @@ unsigned long get_ins_imm_val(unsigned long ins_addr) | |||
| 422 | unsigned char mod_rm; | 468 | unsigned char mod_rm; |
| 423 | unsigned char mod; | 469 | unsigned char mod; |
| 424 | unsigned char *p; | 470 | unsigned char *p; |
| 425 | int i, shorted, enlarged, rexr; | 471 | struct prefix_bits prf; |
| 472 | int i; | ||
| 426 | unsigned long rv; | 473 | unsigned long rv; |
| 427 | 474 | ||
| 428 | p = (unsigned char *)ins_addr; | 475 | p = (unsigned char *)ins_addr; |
| 429 | p += skip_prefix(p, &shorted, &enlarged, &rexr); | 476 | p += skip_prefix(p, &prf); |
| 430 | p += get_opcode(p, &opcode); | 477 | p += get_opcode(p, &opcode); |
| 431 | for (i = 0; i < ARRAY_SIZE(imm_wop); i++) | 478 | for (i = 0; i < ARRAY_SIZE(imm_wop); i++) |
| 432 | if (imm_wop[i] == opcode) { | 479 | if (imm_wop[i] == opcode) { |
