Skip to content

Commit e835b94

Browse files
Coreforgegeerlingguy
authored andcommitted
added 32/64bit str
1 parent 3c50026 commit e835b94

File tree

2 files changed

+121
-12
lines changed

2 files changed

+121
-12
lines changed

arch/arm64/kernel/compat_alignment.c

Lines changed: 118 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

394407
struct 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

410425
static 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

666768
int 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
}

arch/arm64/mm/fault.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,9 @@ static int do_alignment_fault(unsigned long far, unsigned long esr,
726726

727727
if(user_mode(regs)){
728728
// aarch64 user mode
729-
return do_alignment_fixup(far, regs);
729+
if(!do_alignment_fixup(far, regs)){
730+
return 0;
731+
}
730732
}
731733
do_bad_area(far, esr, regs);
732734
return 0;

0 commit comments

Comments
 (0)