Skip to content

Commit dc647ee

Browse files
Jinglin-lyuopsiff
authored andcommitted
HAOC: Fix conflict between IEE and KPTI while modifying ASID
community inclusion category: bugfix -------------------------------- Fix 2 bugs: Bug 1: Crash upon resume from suspend. This issue occurred due to missing the proper use of the ISB (Instruction Synchronization Barrier) instruction after writing to the TTBR0 register via the IEE SIP interface. The absence of ISB prevented the modification from immediately taking effect, causing errors in subsequent code accessing addresses within the TTBR0 range. The problem was fixed by adding an ISB instruction in the IEE SIP gate. Bug 2: IEE ASID usage incompatible with KPTI. When Kernel Page Table Isolation (KPTI) was enabled along with HAOC initialization, conflicts in the Translation Lookaside Buffer (TLB) due to ASID handling incompatibility led to hangs during initialization. To resolve this, the modifications by IEE to the original ARM kernel ASID handling logic were reverted. Now, the storage of the IEE ASID has been shifted from TTBR1 to TTBR0, while the kernel continues to use TTBR1 to store user ASIDs. Fixes: 6d2d4fa ("HAOC: Add support for AArch64 Isolated Execution Environment(IEE).") Signed-off-by: Lyu Jinglin <lvjl2022@zgclab.edu.cn> Signed-off-by: Liu Zhehui <liuzhh@zgclab.edu.cn>
1 parent 7618412 commit dc647ee

9 files changed

Lines changed: 91 additions & 79 deletions

File tree

arch/arm64/include/asm/haoc/iee-asm.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,9 @@
1717

1818
#define ASID_BIT (UL(1) << 48)
1919
/*
20-
* We reserves the bigest ASID for IEE and always stores it in TTBR1. As KPTI also reserves
21-
* odd ASIDs for user-viewed TTBR1, we should use even number for IEE ASID to allow KPTI to
22-
* switch between them at kernel entry/exit.
20+
* We reserves the bigest ASID for IEE and always stores it in TTBR0.
2321
*/
24-
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
25-
#define IEE_ASID 0xfffe
26-
#else
2722
#define IEE_ASID 0xffff
28-
#endif
2923
#define IEE_ASM_ASID (UL(IEE_ASID) << 48)
3024

3125
#define TCR_HPD1 (UL(1) << 42)

arch/arm64/include/asm/haoc/iee-si.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ enum {
1313
IEE_SI_SET_VBAR,
1414
IEE_SI_SET_TTBR0,
1515
IEE_SI_CONTEXT_SWITCH,
16+
IEE_SI_CONTEXT_SWITCH_PRE_INIT,
1617
IEE_SI_FLAGS
1718
};
1819

@@ -37,9 +38,4 @@ extern u64 __iee_si_text_start[];
3738
extern u64 __iee_si_text_end[];
3839
extern u64 iee_si_reserved_pg_dir;
3940

40-
static inline void iee_si_setup_data(void)
41-
{
42-
iee_si_reserved_pg_dir = phys_to_ttbr(__pa_symbol(reserved_pg_dir));
43-
}
44-
4541
#endif

arch/arm64/include/asm/mmu_context.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ static inline void cpu_set_reserved_ttbr0_nosync(void)
5757
#ifdef CONFIG_IEE_SIP
5858
iee_rwx_gate(IEE_SI_SET_TTBR0, ttbr);
5959
#else
60+
#ifdef CONFIG_IEE
61+
if (iee_init_done)
62+
ttbr |= FIELD_PREP(TTBR_ASID_MASK, IEE_ASID);
63+
#endif
6064
write_sysreg(ttbr, ttbr0_el1);
6165
#endif
6266
}
@@ -166,6 +170,10 @@ static inline void cpu_install_ttbr0(phys_addr_t ttbr0, unsigned long t0sz)
166170
#ifdef CONFIG_IEE_SIP
167171
iee_rwx_gate(IEE_SI_SET_TTBR0, ttbr0);
168172
#else
173+
#ifdef CONFIG_IEE
174+
if (iee_init_done)
175+
ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, IEE_ASID);
176+
#endif
169177
write_sysreg(ttbr0, ttbr0_el1);
170178
isb();
171179
#endif
@@ -196,10 +204,6 @@ static inline void cpu_replace_ttbr1(pgd_t *pgdp, pgd_t *idmap)
196204
*/
197205
ttbr1 |= TTBR_CNP_BIT;
198206
}
199-
#ifdef CONFIG_IEE
200-
if (iee_init_done)
201-
ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, IEE_ASID);
202-
#endif
203207

204208
replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1);
205209

arch/arm64/kernel/haoc/iee/iee-gate.S

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ SYM_FUNC_START(iee_protected_rw_gate)
5050
/* entry gate */
5151
mrs x12, tcr_el1
5252
orr x12, x12, #TCR_HPD1
53-
orr x12, x12, #TCR_A1
53+
bic x12, x12, #TCR_A1
5454
msr tcr_el1, x12
5555
isb
5656
/* Check TCR */
@@ -79,7 +79,7 @@ SYM_FUNC_START(iee_protected_rw_gate)
7979
/* exit gate */
8080
mrs x12, tcr_el1
8181
bic x12, x12, #TCR_HPD1
82-
bic x12, x12, #TCR_A1
82+
orr x12, x12, #TCR_A1
8383
msr tcr_el1, x12
8484
isb
8585
/* Check TCR */

arch/arm64/kernel/haoc/iee/iee-init.c

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,12 @@ static void __init iee_stack_alloc(void)
4040
flush_tlb_all();
4141
}
4242

43-
/* Setup TCR for this cpu and move ASID from ttbr1 to ttbr0 */
4443
void iee_setup_asid(void)
4544
{
46-
unsigned long asid, ttbr0, ttbr1;
47-
48-
ttbr1 = read_sysreg(ttbr1_el1);
49-
asid = FIELD_GET(TTBR_ASID_MASK, ttbr1);
50-
ttbr0 = read_sysreg(ttbr0_el1) | FIELD_PREP(TTBR_ASID_MASK, asid);
51-
ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, IEE_ASID);
52-
write_sysreg(ttbr1, ttbr1_el1);
45+
unsigned long ttbr0 = read_sysreg(ttbr0_el1) | FIELD_PREP(TTBR_ASID_MASK, IEE_ASID);
46+
/* Load IEE ASID into ttbr0 to use it in IEE. */
5347
write_sysreg(ttbr0, ttbr0_el1);
54-
write_sysreg(read_sysreg(tcr_el1) & ~TCR_A1, tcr_el1);
5548
isb();
56-
57-
/* Flush tlb to enable IEE. */
58-
local_flush_tlb_all();
59-
}
60-
61-
static void iee_setup_init_data(void){
62-
for (u64 addr = (u64)iee_init_data_begin; addr < (u64)iee_init_data_end;
63-
addr += PAGE_SIZE)
64-
iee_set_logical_mem(addr, 0, true);
6549
}
6650

6751
void __init iee_init_post(void)
@@ -82,7 +66,6 @@ void __init iee_init_post(void)
8266
extern void iee_si_init(void);
8367
iee_si_init();
8468
#endif
85-
iee_setup_init_data();
8669
}
8770

8871
void __init iee_stack_init(void)

arch/arm64/kernel/haoc/iee/iee-mmu.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,12 @@ void __init iee_init_tcr(void)
6060

6161
__set_fixmap(FIX_PTE, __pa_symbol(&kernel_tcr), FIXMAP_PAGE_NORMAL);
6262
ptr += (unsigned long)(&kernel_tcr) & (PAGE_SIZE - 1);
63-
*((u64 *)ptr) = read_sysreg(tcr_el1) & IEE_TCR_MASK & ~(TCR_HPD1 | TCR_A1);
63+
*((u64 *)ptr) = read_sysreg(tcr_el1) & IEE_TCR_MASK & ~TCR_HPD1;
6464
clear_fixmap(FIX_PTE);
6565
ptr = (unsigned long)(fix_to_virt(FIX_PTE));
6666
__set_fixmap(FIX_PTE, __pa_symbol(&iee_tcr), FIXMAP_PAGE_NORMAL);
6767
ptr += (unsigned long)(&iee_tcr) & (PAGE_SIZE - 1);
68-
*((u64 *)ptr) = kernel_tcr | TCR_HPD1 | TCR_A1;
68+
*((u64 *)ptr) = (kernel_tcr | TCR_HPD1) & ~TCR_A1;
6969
clear_fixmap(FIX_PTE);
7070
}
7171

arch/arm64/kernel/haoc/iee/iee-si-gate.S

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ SYM_FUNC_START(iee_rwx_gate)
2020
bl iee_si_handler
2121
ldp x29, x30, [sp, #16]
2222
ldr x13, [sp], #32
23+
isb
2324
b 2f
2425
1:
2526
stp x29, x30, [sp, #-16]!
@@ -40,7 +41,7 @@ SYM_FUNC_START(iee_rwx_gate_tramp)
4041
/* entry gate */
4142
mrs x12, tcr_el1
4243
orr x12, x12, #TCR_HPD1
43-
orr x12, x12, #TCR_A1
44+
bic x12, x12, #TCR_A1
4445
msr tcr_el1, x12
4546
isb
4647
/* Check TCR */
@@ -66,7 +67,7 @@ SYM_FUNC_START(iee_rwx_gate_tramp)
6667
/* exit gate */
6768
mrs x12, tcr_el1
6869
bic x12, x12, #TCR_HPD1
69-
bic x12, x12, #TCR_A1
70+
orr x12, x12, #TCR_A1
7071
msr tcr_el1, x12
7172
isb
7273
/* Check TCR */

arch/arm64/kernel/haoc/iee/iee-si.c

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,30 @@ static inline unsigned long iee_si_mask(unsigned long mask,
1616
return (new_val & mask) | (old_val & ~mask);
1717
}
1818

19+
#ifdef CONFIG_IEE_PTRP
20+
static inline void iee_si_check_ttbr0(void)
21+
{
22+
u64 old_ttbr0 = read_sysreg(ttbr0_el1);
23+
u64 old_phys = (old_ttbr0 & PAGE_MASK) & ~TTBR_ASID_MASK;
24+
struct task_token *token = (struct task_token *)__addr_to_iee(current);
25+
/* Phys in TTBR0 shall be the same with current->mm->pgd. */
26+
if (!(current == &init_task) && token->pgd
27+
&& old_phys != iee_si_reserved_pg_dir) {
28+
u64 token_phys = __pa(token->pgd);
29+
30+
if (old_phys != token_phys)
31+
pr_err("IEE: Pgd set error. old ttbr0:%llx, token ttbr0:%llx",
32+
old_phys, token_phys);
33+
}
34+
}
35+
#else
36+
static inline void iee_si_check_ttbr0(void) {}
37+
#endif
38+
1939
unsigned long __iee_si_code iee_si_handler(int flag, ...)
2040
{
2141
va_list pArgs;
22-
unsigned long old_val, new_val;
42+
unsigned long old_val, new_val, ttbr1, ttbr0;
2343

2444
va_start(pArgs, flag);
2545
switch (flag) {
@@ -32,33 +52,38 @@ unsigned long __iee_si_code iee_si_handler(int flag, ...)
3252
write_sysreg(new_val, sctlr_el1);
3353
break;
3454
case IEE_SI_SET_TTBR0:
55+
ttbr0 = va_arg(pArgs, u64) & ~TTBR_ASID_MASK;
56+
/* Skip checking before init IEE. */
57+
if (iee_init_done)
58+
iee_si_check_ttbr0();
59+
/* Load the reserved IEE ASID into TTBR0.*/
60+
ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, IEE_ASID);
61+
write_sysreg(ttbr0, ttbr0_el1);
62+
break;
3563
case IEE_SI_CONTEXT_SWITCH:
36-
old_val = read_sysreg(ttbr0_el1);
37-
new_val = va_arg(pArgs, u64);
64+
ttbr1 = va_arg(pArgs, u64);
65+
ttbr0 = va_arg(pArgs, u64) & ~TTBR_ASID_MASK;
66+
ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, IEE_ASID);
3867
/* Skip checking before init IEE. */
39-
if (iee_tcr != 0) {
40-
u64 new_asid;
68+
if (iee_init_done) {
69+
u64 new_asid = ttbr1 >> 48;
4170
/* ASID shall not be the one reserved for IEE. */
42-
new_asid = new_val >> 48;
4371
if (new_asid == IEE_ASID)
4472
panic("IEE SI: Using reserved IEE ASID in TTRB0.");
4573

46-
#ifdef CONFIG_IEE_PTRP
47-
u64 old_phys;
48-
struct task_token *token = (struct task_token *)__addr_to_iee(current);
49-
/* Phys in TTBR0 shall be the same with current->mm->pgd. */
50-
old_phys = (old_val & PAGE_MASK) & ~TTBR_ASID_MASK;
51-
if (!(current == &init_task) && token->pgd
52-
&& old_phys != iee_si_reserved_pg_dir) {
53-
u64 token_phys = __pa(token->pgd);
54-
55-
if (old_phys != token_phys)
56-
panic("IEE: Pgd set error. old ttbr0:%llx, token ttbr0:%llx",
57-
old_phys, token_phys);
58-
}
59-
#endif
74+
iee_si_check_ttbr0();
6075
}
61-
write_sysreg(new_val, ttbr0_el1);
76+
write_sysreg(ttbr1, ttbr1_el1);
77+
write_sysreg(ttbr0, ttbr0_el1);
78+
break;
79+
case IEE_SI_CONTEXT_SWITCH_PRE_INIT:
80+
ttbr1 = va_arg(pArgs, u64);
81+
ttbr0 = va_arg(pArgs, u64);
82+
83+
if (iee_init_done)
84+
panic("IEE: Using legacy context switch after IEE init.");
85+
write_sysreg(ttbr1, ttbr1_el1);
86+
write_sysreg(ttbr0, ttbr0_el1);
6287
break;
6388
case IEE_SI_SET_VBAR:
6489
new_val = va_arg(pArgs, u64);
@@ -77,6 +102,11 @@ unsigned long __iee_si_code iee_si_handler(int flag, ...)
77102
return 0;
78103
}
79104

105+
static inline void iee_si_setup_data(void)
106+
{
107+
iee_si_reserved_pg_dir = phys_to_ttbr(__pa_symbol(reserved_pg_dir));
108+
}
109+
80110
/* Map iee si code PXNTable=1 on pmd page tables. */
81111
static int __init iee_si_init_code(void)
82112
{

arch/arm64/mm/context.c

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -368,30 +368,34 @@ void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm)
368368
ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, asid);
369369

370370
#ifdef CONFIG_IEE
371-
if (iee_init_done) {
372-
/*
373-
* IEE requires the reserved ASID stored in TTBR1 and User ASID stored
374-
* in TTBR0 to support ASID switch by changing TCR.A1.
375-
*/
376-
ttbr0 &= ~TTBR_ASID_MASK;
377-
ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, asid);
371+
/* Set ASID in TTBR1 since TCR.A1 is set */
372+
ttbr1 &= ~TTBR_ASID_MASK;
373+
ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
378374

379-
cpu_set_reserved_ttbr0_nosync();
375+
cpu_set_reserved_ttbr0_nosync();
376+
/*
377+
* IEE requires the reserved IEE ASID stored in TTBR0_EL1 so that IEE can
378+
* switch the ASID by setting TCR_EL1.A1 from 1 to 0 in IEE gate to avoid
379+
* tlb entry disclosure when calling IEE functions.
380+
*/
381+
if (iee_init_done) {
380382
#ifdef CONFIG_IEE_SIP
381-
iee_rwx_gate(IEE_SI_CONTEXT_SWITCH, ttbr0);
383+
iee_rwx_gate(IEE_SI_CONTEXT_SWITCH, ttbr1, ttbr0);
382384
#else
385+
ttbr0 &= ~TTBR_ASID_MASK;
386+
ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, IEE_ASID);
387+
write_sysreg(ttbr1, ttbr1_el1);
383388
write_sysreg(ttbr0, ttbr0_el1);
384389
isb();
385390
#endif
386391
} else {
387-
/* Set ASID in TTBR1 since TCR.A1 is set */
388-
ttbr1 &= ~TTBR_ASID_MASK;
389-
ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
390-
391-
cpu_set_reserved_ttbr0_nosync();
392+
#ifdef CONFIG_IEE_SIP
393+
iee_rwx_gate(IEE_SI_CONTEXT_SWITCH_PRE_INIT, ttbr1, ttbr0);
394+
#else
392395
write_sysreg(ttbr1, ttbr1_el1);
393396
write_sysreg(ttbr0, ttbr0_el1);
394397
isb();
398+
#endif
395399
}
396400
#else
397401
/* Set ASID in TTBR1 since TCR.A1 is set */
@@ -417,7 +421,7 @@ static int asids_update_limit(void)
417421
#ifdef CONFIG_IEE
418422
if (haoc_enabled && pinned_asid_map) {
419423
__set_bit(ctxid2asid(IEE_ASID), pinned_asid_map);
420-
__set_bit(ctxid2asid(IEE_ASID | ASID_BIT), pinned_asid_map);
424+
__set_bit(ctxid2asid(IEE_ASID & ~ASID_BIT), pinned_asid_map);
421425
}
422426
#endif
423427
}
@@ -461,8 +465,8 @@ static int asids_init(void)
461465
#ifdef CONFIG_IEE
462466
if (haoc_enabled) {
463467
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
464-
__set_bit(ctxid2asid(IEE_ASID | ASID_BIT), asid_map);
465-
__set_bit(ctxid2asid(IEE_ASID | ASID_BIT), pinned_asid_map);
468+
__set_bit(ctxid2asid(IEE_ASID & ~ASID_BIT), asid_map);
469+
__set_bit(ctxid2asid(IEE_ASID & ~ASID_BIT), pinned_asid_map);
466470
#endif
467471
__set_bit(ctxid2asid(IEE_ASID), asid_map);
468472
__set_bit(ctxid2asid(IEE_ASID), pinned_asid_map);

0 commit comments

Comments
 (0)