Skip to content

Commit 9c03af8

Browse files
committed
ldr, DOOM Eternal now works
1 parent 4766add commit 9c03af8

1 file changed

Lines changed: 92 additions & 22 deletions

File tree

arch/arm64/kernel/compat_alignment.c

Lines changed: 92 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -515,28 +515,47 @@ void read_simd_reg(int reg, u64 dst[2]){
515515
kernel_neon_end();
516516
}
517517

518+
519+
void write_simd_reg(int reg, u64 src[2]){
520+
521+
if(!may_use_simd()){
522+
printk("may_use_simd returned false!\n");
523+
}
524+
kernel_neon_begin();
525+
if(current->thread.sve_state){
526+
printk("SVE state is not NULL!\n");
527+
}
528+
529+
*((u64*)(&current->thread.uw.fpsimd_state.vregs[reg])) = src[0];
530+
*(((u64*)(&current->thread.uw.fpsimd_state.vregs[reg])) + 1) = src[1];
531+
532+
kernel_neon_end();
533+
}
534+
518535
int do_ls_fixup(u32 instr, struct pt_regs *regs, struct fixupDescription* desc){
519536
int r;
520-
u64 data1[2];
521-
u64 data2[2];
537+
u64 data1[2] = {0,0};
538+
u64 data2[2] = {0,0};
522539

523540
// the reg indices have to always be valid, even if the reg isn't being used
524-
if(desc->simd){
525-
// At least currently, there aren't any simd instructions supported that use more than one data register
526-
//__uint128_t tmp;
527-
528-
// probably better for performance to read both registers with one function to kernel_neon_* doesn't have to be called more than once
529-
read_simd_reg(desc->reg1, data1);
530-
read_simd_reg(desc->reg2, data2);
531-
//data1[0] = tmp;
532-
//data1[1] = *(((u64*)&tmp) + 1);
533-
///printk("SIMD: storing 0x%llx %llx (%d bits) at 0x%px", data1[1], data1[0], desc->width, desc->addr);
534-
if(desc->width < 128){
535-
return -1;
541+
if(!desc->load){
542+
if(desc->simd){
543+
// At least currently, there aren't any simd instructions supported that use more than one data register
544+
//__uint128_t tmp;
545+
546+
// probably better for performance to read both registers with one function to kernel_neon_* doesn't have to be called more than once
547+
read_simd_reg(desc->reg1, data1);
548+
read_simd_reg(desc->reg2, data2);
549+
//data1[0] = tmp;
550+
//data1[1] = *(((u64*)&tmp) + 1);
551+
///printk("SIMD: storing 0x%llx %llx (%d bits) at 0x%px", data1[1], data1[0], desc->width, desc->addr);
552+
/*if(desc->width < 128){
553+
return -1;
554+
}*/
555+
} else {
556+
data1[0] = regs->regs[desc->reg1];
557+
data2[0] = regs->regs[desc->reg2];
536558
}
537-
} else {
538-
data1[0] = regs->regs[desc->reg1];
539-
data2[0] = regs->regs[desc->reg2];
540559
}
541560

542561
/*if(desc->width > 64){
@@ -573,8 +592,54 @@ int do_ls_fixup(u32 instr, struct pt_regs *regs, struct fixupDescription* desc){
573592
}
574593
arm64_skip_faulting_instruction(regs, 4);
575594
} else {
576-
printk("Loading is currently not implemented (addr 0x%px)\n", desc->addr);
577-
return -1;
595+
//printk("Loading is currently not implemented (addr 0x%px)\n", desc->addr);
596+
597+
uint8_t* addr = desc->addr;
598+
int bcount = desc->width / 8; // since the field stores the width in bits. Honestly, there's no particular reason for that
599+
600+
//printk("Storing %d bytes (pair: %d) to 0x%llx",bcount, desc->pair, desc->addr);
601+
int addrIt = 0;
602+
for(int i = 0; i < bcount; i++){
603+
uint8_t val;
604+
if((r=get_user( val, (uint8_t __user *)addr))){
605+
printk("Failed to write data at 0x%px (base was 0x%px)\n", addr, desc->addr);
606+
return r;
607+
}
608+
*(((uint8_t*)data1) + addrIt) = val;
609+
//desc->data1 >>= 8;
610+
addrIt++;
611+
addr++;
612+
}
613+
614+
if(desc->simd){
615+
write_simd_reg(desc->reg1, data1);
616+
} else {
617+
regs->regs[desc->reg1] = data1[0];
618+
}
619+
620+
addrIt = 0;
621+
if(desc->pair){
622+
for(int i = 0; i < bcount; i++){
623+
uint8_t val;
624+
if((r=get_user(val, (uint8_t __user *)addr))){
625+
printk("Failed to write data at 0x%px (base was 0x%px)\n", addr, desc->addr);
626+
return r;
627+
}
628+
*(((uint8_t*)data2) + addrIt) = val;
629+
//desc->data2 >>= 8;
630+
addrIt++;
631+
addr++;
632+
}
633+
634+
if(desc->simd){
635+
write_simd_reg(desc->reg2, data1);
636+
} else {
637+
regs->regs[desc->reg2] = data1[0];
638+
}
639+
}
640+
arm64_skip_faulting_instruction(regs, 4);
641+
642+
578643
}
579644
return 0;
580645
}
@@ -734,7 +799,7 @@ int ls_reg_unsigned_imm(u32 instr, struct pt_regs *regs, struct fixupDescription
734799
if((size & 1) && simd && (opc & 2)){
735800
return 1;
736801
}
737-
802+
desc->load = load;
738803
desc->reg1 = Rt;
739804
desc->simd = simd;
740805
desc->extendSign = extend_sign;
@@ -850,9 +915,10 @@ int lsr_unscaled_immediate_fixup(u32 instr, struct pt_regs *regs, struct fixupDe
850915
desc->pair = 0;
851916

852917
int load = opc & 1;
853-
if(load){
918+
desc->load = load;
919+
/*if(load){
854920
return 1;
855-
}
921+
}*/
856922
desc->reg1 = Rt;
857923
if(simd){
858924
desc->simd = 1;
@@ -863,6 +929,10 @@ int lsr_unscaled_immediate_fixup(u32 instr, struct pt_regs *regs, struct fixupDe
863929
desc->data1 = tmp;
864930
desc->data1_simd = *(((u64*)&tmp) + 1);*/
865931
return do_ls_fixup(instr, regs, desc);
932+
} else {
933+
desc->simd = 0;
934+
desc->width = 8 << size;
935+
return do_ls_fixup(instr, regs, desc);
866936
}
867937
///printk("SIMD: %d\n", simd);
868938
return 1;

0 commit comments

Comments
 (0)