@@ -385,10 +385,23 @@ int do_compat_alignment_fixup(unsigned long addr, struct pt_regs *regs)
385385// arm64#
386386
387387/*
388- *Happens with The Long Dark
388+ *Happens with The Long Dark (also with steam)
389389 *
390390 *[ 6012.660803] Faulting instruction: 0x3d800020
391391[ 6012.660813] Load/Store: op0 0x3 op1 0x1 op2 0x3 op3 0x0 op4 0x0
392+ *
393+ *[ 555.449651] Load/Store: op0 0x3 op1 0x1 op2 0x1 op3 0x1 op4 0x0
394+ [ 555.449654] Faulting instruction: 0x3c810021
395+ *
396+ *
397+ *[ 555.449663] Load/Store: op0 0x3 op1 0x1 op2 0x1 op3 0x2 op4 0x0
398+ [ 555.449666] Faulting instruction: 0x3c820020
399+ *
400+ *[ 555.449674] Load/Store: op0 0x3 op1 0x1 op2 0x1 op3 0x3 op4 0x0
401+ [ 555.449677] Faulting instruction: 0x3c830021
402+ *
403+ *
404+ *
392405 */
393406
394407struct fixupDescription {
@@ -405,6 +418,8 @@ struct fixupDescription{
405418 int load ; // 1 is it's a load, 0 if it's a store
406419 int pair ; // 1 if it's a l/s pair instruction
407420 int width ; // width of the access in bits
421+ int extendSign ;
422+ int extend_width ;
408423};
409424
410425static int alignment_get_arm64 (struct pt_regs * regs , __le64 __user * ip , u32 * inst )
@@ -464,7 +479,7 @@ int do_ls_fixup(u32 instr, struct pt_regs *regs, struct fixupDescription* desc){
464479 if (!desc -> load ){
465480 uint8_t * addr = desc -> addr ;
466481 int bcount = desc -> width / 8 ; // since the field stores the width in bits. Honestly, there's no particular reason for that
467- printk ("Storing %d bytes (pair: %d) to 0x%llx" ,bcount , desc -> pair , desc -> addr );
482+ // printk("Storing %d bytes (pair: %d) to 0x%llx",bcount, desc->pair, desc->addr);
468483 for (int i = 0 ; i < bcount ; i ++ ){
469484 if ((r = put_user (desc -> data1 & 0xff , (uint8_t __user * )addr )))
470485 return r ;
@@ -626,6 +641,84 @@ int ls_reg_unsigned_imm(u32 instr, struct pt_regs *regs, struct fixupDescription
626641 desc -> width = 64 ;
627642 break ;
628643 }
644+ return 1 ;
645+ }
646+
647+
648+ u64 extend_reg (u64 reg , int type , int shift ){
649+
650+ uint8_t is_signed = (type & 4 ) >> 2 ;
651+ uint8_t input_width = type & 1 ;
652+
653+ u64 tmp ;
654+ if (!is_signed ){
655+ tmp = reg ;
656+ } else {
657+ if (input_width == 0 ){
658+ // 32bit, needs to be extended to 64
659+ // I hope the compiler just does this kind of automatically with these types
660+ int32_t stmpw = reg ;
661+ int64_t stmpdw = stmpw ;
662+ tmp = (u64 )stmpdw ;
663+ }
664+ }
665+
666+ return tmp << shift ;
667+ }
668+
669+ int lsr_offset_fixup (u32 instr , struct pt_regs * regs , struct fixupDescription * desc ){
670+ uint8_t size = (instr >> 30 ) & 3 ;
671+ uint8_t simd = (instr >> 26 ) & 1 ;
672+ uint8_t opc = (instr >> 22 ) & 3 ;
673+ uint8_t option = (instr >> 13 ) & 5 ;
674+ uint8_t Rm = (instr >> 16 ) & 0x1f ;
675+ uint8_t Rn = (instr >> 5 ) & 0x1f ;
676+ uint8_t Rt = instr & 0x1f ;
677+ uint8_t S = (instr >> 12 ) & 1 ;
678+ // size==0 seems to be a bit special
679+ // opc&2 is sign, opc&1 is load (for most instructions anyways)
680+
681+ uint8_t load = opc & 1 ;
682+ uint8_t extend_sign = (opc & 2 ) >> 1 ;
683+ desc -> pair = 0 ;
684+
685+ desc -> simd = simd ;
686+ desc -> width = 8 << size ;
687+
688+ // the simd instructions make this a bit weird
689+ if (!simd ){
690+ if (extend_sign ){
691+ if (load ){
692+ desc -> extend_width = 32 ;
693+ } else {
694+ desc -> extend_width = 64 ;
695+ }
696+ desc -> load = 1 ;
697+ } else {
698+ desc -> load = load ;
699+ }
700+
701+ desc -> extendSign = extend_sign ; // needed for load, which isn't implemented yet
702+
703+
704+ u64 addr = regs -> regs [Rn ];
705+
706+ int shift = 0 ;
707+ if (S ) shift = 2 << ((size & 1 ) & ((size >> 1 ) & 1 ));
708+
709+ u64 offset = extend_reg (regs -> regs [Rm ], option , S );
710+
711+ addr += offset ;
712+
713+ desc -> data1 = regs -> regs [Rt ];
714+ desc -> addr = (void * )addr ;
715+
716+ return do_ls_fixup (instr , regs , desc );
717+
718+ } else {
719+ printk ("Load/Store register offset decode doesn't support simd yet\n" );
720+ return 1 ;
721+ }
629722 return 0 ;
630723}
631724
@@ -636,19 +729,21 @@ int ls_fixup(u32 instr, struct pt_regs *regs, struct fixupDescription* desc){
636729 uint8_t op3 ;
637730 uint8_t op4 ;
638731
732+ int r = 1 ;
733+
639734 op0 = (instr >> 28 ) & 0xf ;
640735 op1 = (instr >> 26 ) & 1 ;
641736 op2 = (instr >> 23 ) & 3 ;
642737 op3 = (instr >> 16 ) & 0x3f ;
643738 op4 = (instr >> 10 ) & 3 ;
644- printk ( "Load/Store: op0 0x%x op1 0x%x op2 0x%x op3 0x%x op4 0x%x\n" , op0 , op1 , op2 , op3 , op4 );
739+
645740 if ((op0 & 3 ) == 2 ){
646741 desc -> pair = 1 ;
647- return ls_pair_fixup (instr , regs , desc );
742+ r = ls_pair_fixup (instr , regs , desc );
648743 }
649744 if ((op0 & 3 ) == 0 && op1 == 0 && op2 == 1 && (op3 & 0x20 ) == 0x20 ){
650745 // compare and swap
651- return ls_cas_fixup (instr , regs , desc );
746+ r = ls_cas_fixup (instr , regs , desc );
652747 }
653748 if ((op0 & 3 ) == 3 && (op2 & 3 ) == 3 ){
654749 //load/store unsigned immediate
@@ -658,35 +753,47 @@ int ls_fixup(u32 instr, struct pt_regs *regs, struct fixupDescription* desc){
658753 if ((op0 & 3 ) == 2 && (op2 == 2 )){
659754 // Load/store pair offset
660755 //ldpstp_offset_fixup(instr, regs);
661- return ls_reg_unsigned_imm (instr , regs , desc );
756+ //r = ls_reg_unsigned_imm(instr, regs, desc);
662757 }
663- return 0 ;
758+ if ((op0 & 3 ) == 3 && (op2 & 2 ) == 0 && (op3 & 0x20 ) == 0x20 && op4 == 2 ){
759+ // register offset load/store
760+ r = lsr_offset_fixup (instr , regs , desc );
761+ }
762+ if (r ){
763+ 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+ }
765+ return r ;
664766}
665767
666768int do_alignment_fixup (unsigned long addr , struct pt_regs * regs ){
667769 unsigned long long instrptr ;
668770 u32 instr = 0 ;
669771
670772 instrptr = instruction_pointer (regs );
671- printk ("Alignment fixup\n" );
773+ // printk("Alignment fixup\n");
672774
673775 if (alignment_get_arm64 (regs , (__le64 __user * )instrptr , & instr )){
674776 printk ("Failed to get aarch64 instruction\n" );
675777 return 1 ;
676778 }
677- printk ( "Faulting instruction: 0x%lx\n" , instr );
779+
678780 /**
679781 * List of seen faults: 020c00a9 (0xa9000c02) stp x2, x3, [x0]
680782 *
681783 */
682784
683785 uint8_t op0 ;
786+ int r ;
684787 struct fixupDescription desc = {0 };
685788
686789 op0 = ((instr & 0x1E000000 ) >> 25 );
687790 if ((op0 & 5 ) == 0x4 ){
688- printk ("Load/Store\n" );
689- return ls_fixup (instr , regs , & desc );
791+ //printk("Load/Store\n");
792+ r = ls_fixup (instr , regs , & desc );
793+ if (r ){
794+ printk ("Faulting instruction: 0x%lx\n" , instr );
795+ }
796+ return r ;
690797 } else {
691798 printk ("Not handling instruction with op0 0x%x " ,op0 );
692799 }
0 commit comments