|
12 | 12 | #include <asm/ptrace.h>
|
13 | 13 | #include <asm/traps.h>
|
14 | 14 |
|
| 15 | +#include <asm/fpsimd.h> |
| 16 | + |
15 | 17 | /*
|
16 | 18 | * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998
|
17 | 19 | *
|
@@ -399,14 +401,18 @@ int do_compat_alignment_fixup(unsigned long addr, struct pt_regs *regs)
|
399 | 401 | *
|
400 | 402 | *[ 555.449674] Load/Store: op0 0x3 op1 0x1 op2 0x1 op3 0x3 op4 0x0
|
401 | 403 | [ 555.449677] Faulting instruction: 0x3c830021
|
| 404 | +
|
| 405 | +stur q1, [x1, #16] |
| 406 | +potentially also ldur q0, [x1, #32] and ldur q1, [x1, #48] |
402 | 407 | *
|
403 | 408 | *
|
404 | 409 | *
|
405 | 410 | */
|
406 | 411 |
|
407 | 412 | struct fixupDescription{
|
408 | 413 | void* addr;
|
409 |
| - // |
| 414 | + |
| 415 | + // datax_simd has to be located directly after datax in memory |
410 | 416 | u64 data1;
|
411 | 417 | u64 data1_simd;
|
412 | 418 | u64 data2;
|
@@ -474,24 +480,40 @@ static int alignment_get_arm64(struct pt_regs *regs, __le64 __user *ip, u32 *ins
|
474 | 480 | return 0;
|
475 | 481 | }*/
|
476 | 482 |
|
| 483 | +// saves the contents of the simd register reg to dst |
| 484 | +void read_simd_reg(int reg, __uint128_t* dst){ |
| 485 | + struct user_fpsimd_state st; |
| 486 | + fpsimd_save_state(&st); |
| 487 | + *dst = st.vregs[reg]; |
| 488 | +} |
| 489 | + |
477 | 490 | int do_ls_fixup(u32 instr, struct pt_regs *regs, struct fixupDescription* desc){
|
478 | 491 | int r;
|
| 492 | + /*if(desc->width > 64){ |
| 493 | + printk("Currently cannot process ls_fixup with a size of %d bits\n", desc->width); |
| 494 | + return 1; |
| 495 | + }*/ |
479 | 496 | if(!desc->load){
|
480 | 497 | uint8_t* addr = desc->addr;
|
481 | 498 | int bcount = desc->width / 8; // since the field stores the width in bits. Honestly, there's no particular reason for that
|
| 499 | + |
482 | 500 | //printk("Storing %d bytes (pair: %d) to 0x%llx",bcount, desc->pair, desc->addr);
|
| 501 | + int addrIt = 0; |
483 | 502 | for(int i = 0; i < bcount; i++){
|
484 |
| - if((r=put_user(desc->data1 & 0xff, (uint8_t __user *)addr))) |
| 503 | + if((r=put_user( (*(((uint8_t*)(&desc->data1)) + addrIt) & 0xff), (uint8_t __user *)addr))) |
485 | 504 | return r;
|
486 |
| - desc->data1 >>= 8; |
| 505 | + //desc->data1 >>= 8; |
| 506 | + addrIt++; |
487 | 507 | addr++;
|
488 | 508 | }
|
489 | 509 |
|
| 510 | + addrIt = 0; |
490 | 511 | if(desc->pair){
|
491 | 512 | for(int i = 0; i < bcount; i++){
|
492 |
| - if((r=put_user(desc->data2 & 0xff, (uint8_t __user *)addr))) |
| 513 | + if((r=put_user((*(((uint8_t*)(&desc->data2)) + addrIt) & 0xff) & 0xff, (uint8_t __user *)addr))) |
493 | 514 | return r;
|
494 |
| - desc->data2 >>= 8; |
| 515 | + //desc->data2 >>= 8; |
| 516 | + addrIt++; |
495 | 517 | addr++;
|
496 | 518 | }
|
497 | 519 | }
|
@@ -722,6 +744,43 @@ int lsr_offset_fixup(u32 instr, struct pt_regs *regs, struct fixupDescription* d
|
722 | 744 | return 0;
|
723 | 745 | }
|
724 | 746 |
|
| 747 | +int lsr_unscaled_immediate_fixup(u32 instr, struct pt_regs *regs, struct fixupDescription* desc){ |
| 748 | + uint8_t size = (instr >> 30) & 3; |
| 749 | + uint8_t simd = (instr >> 26) & 1; |
| 750 | + uint8_t opc = (instr >> 22) & 3; |
| 751 | + uint16_t imm9 = (instr >> 12) & 0x1ff; |
| 752 | + uint8_t Rn = (instr >> 5) & 0x1f; |
| 753 | + uint8_t Rt = instr & 0x1f; |
| 754 | + |
| 755 | + int16_t fullImm = 0; |
| 756 | + // sign extend it |
| 757 | + if(imm9 & 0x100){ |
| 758 | + fullImm = 0xfe00 | imm9; |
| 759 | + } else { |
| 760 | + fullImm = imm9; |
| 761 | + } |
| 762 | + u64 addr = regs->regs[Rn]; |
| 763 | + desc->addr = addr + fullImm; |
| 764 | + desc->pair = 0; |
| 765 | + |
| 766 | + int load = opc & 1; |
| 767 | + if(load){ |
| 768 | + return 1; |
| 769 | + } |
| 770 | + if(simd){ |
| 771 | + desc->simd = 1; |
| 772 | + desc->width = 8 << (size | (opc << 1)); |
| 773 | + // assuming store |
| 774 | + __uint128_t tmp; |
| 775 | + read_simd_reg(Rt, &tmp); |
| 776 | + desc->data1 = tmp; |
| 777 | + desc->data1_simd = *(((u64*)&tmp) + 1); |
| 778 | + return do_ls_fixup(instr, regs, desc); |
| 779 | + } |
| 780 | + printk("SIMD: %d\n", simd); |
| 781 | + return 1; |
| 782 | +} |
| 783 | + |
725 | 784 | int ls_fixup(u32 instr, struct pt_regs *regs, struct fixupDescription* desc){
|
726 | 785 | uint8_t op0;
|
727 | 786 | uint8_t op1;
|
@@ -759,6 +818,16 @@ int ls_fixup(u32 instr, struct pt_regs *regs, struct fixupDescription* desc){
|
759 | 818 | // register offset load/store
|
760 | 819 | r = lsr_offset_fixup(instr, regs, desc);
|
761 | 820 | }
|
| 821 | + if((op0 & 3) == 3 && (op2 & 2) == 0 && (op3 & 0x20) == 0x0 && op4 == 0){ |
| 822 | + // register load/store unscaled immediate |
| 823 | + r = lsr_unscaled_immediate_fixup(instr, regs, desc); |
| 824 | + printk("Likely SIMD stuff, which isn't being handled properly at all!\n"); |
| 825 | + if(r){ |
| 826 | + arm64_skip_faulting_instruction(regs, 4); |
| 827 | + // skip anyways |
| 828 | + } |
| 829 | + //r = 0; |
| 830 | + } |
762 | 831 | if(r){
|
763 | 832 | printk("Load/Store: op0 0x%x op1 0x%x op2 0x%x op3 0x%x op4 0x%x\n", op0, op1, op2, op3, op4);
|
764 | 833 | }
|
|
0 commit comments