cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tlbex.S (12189B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2/*
      3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
      4 */
      5#include <asm/asm.h>
      6#include <asm/export.h>
      7#include <asm/loongarch.h>
      8#include <asm/page.h>
      9#include <asm/pgtable.h>
     10#include <asm/regdef.h>
     11#include <asm/stackframe.h>
     12
     13	.macro tlb_do_page_fault, write
     14	SYM_FUNC_START(tlb_do_page_fault_\write)
     15	SAVE_ALL
     16	csrrd	a2, LOONGARCH_CSR_BADV
     17	move	a0, sp
     18	REG_S	a2, sp, PT_BVADDR
     19	li.w	a1, \write
     20	la.abs	t0, do_page_fault
     21	jirl    ra, t0, 0
     22	RESTORE_ALL_AND_RET
     23	SYM_FUNC_END(tlb_do_page_fault_\write)
     24	.endm
     25
     26	tlb_do_page_fault 0
     27	tlb_do_page_fault 1
     28
     29SYM_FUNC_START(handle_tlb_protect)
     30	BACKUP_T0T1
     31	SAVE_ALL
     32	move	a0, sp
     33	move	a1, zero
     34	csrrd	a2, LOONGARCH_CSR_BADV
     35	REG_S	a2, sp, PT_BVADDR
     36	la.abs	t0, do_page_fault
     37	jirl    ra, t0, 0
     38	RESTORE_ALL_AND_RET
     39SYM_FUNC_END(handle_tlb_protect)
     40
     41SYM_FUNC_START(handle_tlb_load)
     42	csrwr	t0, EXCEPTION_KS0
     43	csrwr	t1, EXCEPTION_KS1
     44	csrwr	ra, EXCEPTION_KS2
     45
     46	/*
     47	 * The vmalloc handling is not in the hotpath.
     48	 */
     49	csrrd	t0, LOONGARCH_CSR_BADV
     50	blt	t0, $r0, vmalloc_load
     51	csrrd	t1, LOONGARCH_CSR_PGDL
     52
     53vmalloc_done_load:
     54	/* Get PGD offset in bytes */
     55	srli.d	t0, t0, PGDIR_SHIFT
     56	andi	t0, t0, (PTRS_PER_PGD - 1)
     57	slli.d	t0, t0, 3
     58	add.d	t1, t1, t0
     59#if CONFIG_PGTABLE_LEVELS > 3
     60	csrrd	t0, LOONGARCH_CSR_BADV
     61	ld.d	t1, t1, 0
     62	srli.d	t0, t0, PUD_SHIFT
     63	andi	t0, t0, (PTRS_PER_PUD - 1)
     64	slli.d	t0, t0, 3
     65	add.d	t1, t1, t0
     66#endif
     67#if CONFIG_PGTABLE_LEVELS > 2
     68	csrrd	t0, LOONGARCH_CSR_BADV
     69	ld.d	t1, t1, 0
     70	srli.d	t0, t0, PMD_SHIFT
     71	andi	t0, t0, (PTRS_PER_PMD - 1)
     72	slli.d	t0, t0, 3
     73	add.d	t1, t1, t0
     74#endif
     75	ld.d	ra, t1, 0
     76
     77	/*
     78	 * For huge tlb entries, pmde doesn't contain an address but
     79	 * instead contains the tlb pte. Check the PAGE_HUGE bit and
     80	 * see if we need to jump to huge tlb processing.
     81	 */
     82	andi	t0, ra, _PAGE_HUGE
     83	bne	t0, $r0, tlb_huge_update_load
     84
     85	csrrd	t0, LOONGARCH_CSR_BADV
     86	srli.d	t0, t0, (PAGE_SHIFT + PTE_ORDER)
     87	andi	t0, t0, (PTRS_PER_PTE - 1)
     88	slli.d	t0, t0, _PTE_T_LOG2
     89	add.d	t1, ra, t0
     90
     91#ifdef CONFIG_SMP
     92smp_pgtable_change_load:
     93#endif
     94#ifdef CONFIG_SMP
     95	ll.d	t0, t1, 0
     96#else
     97	ld.d	t0, t1, 0
     98#endif
     99	tlbsrch
    100
    101	srli.d	ra, t0, _PAGE_PRESENT_SHIFT
    102	andi	ra, ra, 1
    103	beq	ra, $r0, nopage_tlb_load
    104
    105	ori	t0, t0, _PAGE_VALID
    106#ifdef CONFIG_SMP
    107	sc.d	t0, t1, 0
    108	beq	t0, $r0, smp_pgtable_change_load
    109#else
    110	st.d	t0, t1, 0
    111#endif
    112	ori	t1, t1, 8
    113	xori	t1, t1, 8
    114	ld.d	t0, t1, 0
    115	ld.d	t1, t1, 8
    116	csrwr	t0, LOONGARCH_CSR_TLBELO0
    117	csrwr	t1, LOONGARCH_CSR_TLBELO1
    118	tlbwr
    119leave_load:
    120	csrrd	t0, EXCEPTION_KS0
    121	csrrd	t1, EXCEPTION_KS1
    122	csrrd	ra, EXCEPTION_KS2
    123	ertn
    124#ifdef CONFIG_64BIT
    125vmalloc_load:
    126	la.abs	t1, swapper_pg_dir
    127	b	vmalloc_done_load
    128#endif
    129
    130	/*
    131	 * This is the entry point when build_tlbchange_handler_head
    132	 * spots a huge page.
    133	 */
    134tlb_huge_update_load:
    135#ifdef CONFIG_SMP
    136	ll.d	t0, t1, 0
    137#else
    138	ld.d	t0, t1, 0
    139#endif
    140	srli.d	ra, t0, _PAGE_PRESENT_SHIFT
    141	andi	ra, ra, 1
    142	beq	ra, $r0, nopage_tlb_load
    143	tlbsrch
    144
    145	ori	t0, t0, _PAGE_VALID
    146#ifdef CONFIG_SMP
    147	sc.d	t0, t1, 0
    148	beq	t0, $r0, tlb_huge_update_load
    149	ld.d	t0, t1, 0
    150#else
    151	st.d	t0, t1, 0
    152#endif
    153	addu16i.d	t1, $r0, -(CSR_TLBIDX_EHINV >> 16)
    154	addi.d	ra, t1, 0
    155	csrxchg	ra, t1, LOONGARCH_CSR_TLBIDX
    156	tlbwr
    157
    158	csrxchg	$r0, t1, LOONGARCH_CSR_TLBIDX
    159
    160	/*
    161	 * A huge PTE describes an area the size of the
    162	 * configured huge page size. This is twice the
    163	 * of the large TLB entry size we intend to use.
    164	 * A TLB entry half the size of the configured
    165	 * huge page size is configured into entrylo0
    166	 * and entrylo1 to cover the contiguous huge PTE
    167	 * address space.
    168	 */
    169	/* Huge page: Move Global bit */
    170	xori	t0, t0, _PAGE_HUGE
    171	lu12i.w	t1, _PAGE_HGLOBAL >> 12
    172	and	t1, t0, t1
    173	srli.d	t1, t1, (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT)
    174	or	t0, t0, t1
    175
    176	addi.d	ra, t0, 0
    177	csrwr	t0, LOONGARCH_CSR_TLBELO0
    178	addi.d	t0, ra, 0
    179
    180	/* Convert to entrylo1 */
    181	addi.d	t1, $r0, 1
    182	slli.d	t1, t1, (HPAGE_SHIFT - 1)
    183	add.d	t0, t0, t1
    184	csrwr	t0, LOONGARCH_CSR_TLBELO1
    185
    186	/* Set huge page tlb entry size */
    187	addu16i.d	t0, $r0, (CSR_TLBIDX_PS >> 16)
    188	addu16i.d	t1, $r0, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
    189	csrxchg		t1, t0, LOONGARCH_CSR_TLBIDX
    190
    191	tlbfill
    192
    193	addu16i.d	t0, $r0, (CSR_TLBIDX_PS >> 16)
    194	addu16i.d	t1, $r0, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
    195	csrxchg		t1, t0, LOONGARCH_CSR_TLBIDX
    196
    197nopage_tlb_load:
    198	dbar	0
    199	csrrd	ra, EXCEPTION_KS2
    200	la.abs	t0, tlb_do_page_fault_0
    201	jirl	$r0, t0, 0
    202SYM_FUNC_END(handle_tlb_load)
    203
    204SYM_FUNC_START(handle_tlb_store)
    205	csrwr	t0, EXCEPTION_KS0
    206	csrwr	t1, EXCEPTION_KS1
    207	csrwr	ra, EXCEPTION_KS2
    208
    209	/*
    210	 * The vmalloc handling is not in the hotpath.
    211	 */
    212	csrrd	t0, LOONGARCH_CSR_BADV
    213	blt	t0, $r0, vmalloc_store
    214	csrrd	t1, LOONGARCH_CSR_PGDL
    215
    216vmalloc_done_store:
    217	/* Get PGD offset in bytes */
    218	srli.d	t0, t0, PGDIR_SHIFT
    219	andi	t0, t0, (PTRS_PER_PGD - 1)
    220	slli.d	t0, t0, 3
    221	add.d	t1, t1, t0
    222
    223#if CONFIG_PGTABLE_LEVELS > 3
    224	csrrd	t0, LOONGARCH_CSR_BADV
    225	ld.d	t1, t1, 0
    226	srli.d	t0, t0, PUD_SHIFT
    227	andi	t0, t0, (PTRS_PER_PUD - 1)
    228	slli.d	t0, t0, 3
    229	add.d	t1, t1, t0
    230#endif
    231#if CONFIG_PGTABLE_LEVELS > 2
    232	csrrd	t0, LOONGARCH_CSR_BADV
    233	ld.d	t1, t1, 0
    234	srli.d	t0, t0, PMD_SHIFT
    235	andi	t0, t0, (PTRS_PER_PMD - 1)
    236	slli.d	t0, t0, 3
    237	add.d	t1, t1, t0
    238#endif
    239	ld.d	ra, t1, 0
    240
    241	/*
    242	 * For huge tlb entries, pmde doesn't contain an address but
    243	 * instead contains the tlb pte. Check the PAGE_HUGE bit and
    244	 * see if we need to jump to huge tlb processing.
    245	 */
    246	andi	t0, ra, _PAGE_HUGE
    247	bne	t0, $r0, tlb_huge_update_store
    248
    249	csrrd	t0, LOONGARCH_CSR_BADV
    250	srli.d	t0, t0, (PAGE_SHIFT + PTE_ORDER)
    251	andi	t0, t0, (PTRS_PER_PTE - 1)
    252	slli.d	t0, t0, _PTE_T_LOG2
    253	add.d	t1, ra, t0
    254
    255#ifdef CONFIG_SMP
    256smp_pgtable_change_store:
    257#endif
    258#ifdef CONFIG_SMP
    259	ll.d	t0, t1, 0
    260#else
    261	ld.d	t0, t1, 0
    262#endif
    263	tlbsrch
    264
    265	srli.d	ra, t0, _PAGE_PRESENT_SHIFT
    266	andi	ra, ra, ((_PAGE_PRESENT | _PAGE_WRITE) >> _PAGE_PRESENT_SHIFT)
    267	xori	ra, ra, ((_PAGE_PRESENT | _PAGE_WRITE) >> _PAGE_PRESENT_SHIFT)
    268	bne	ra, $r0, nopage_tlb_store
    269
    270	ori	t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
    271#ifdef CONFIG_SMP
    272	sc.d	t0, t1, 0
    273	beq	t0, $r0, smp_pgtable_change_store
    274#else
    275	st.d	t0, t1, 0
    276#endif
    277
    278	ori	t1, t1, 8
    279	xori	t1, t1, 8
    280	ld.d	t0, t1, 0
    281	ld.d	t1, t1, 8
    282	csrwr	t0, LOONGARCH_CSR_TLBELO0
    283	csrwr	t1, LOONGARCH_CSR_TLBELO1
    284	tlbwr
    285leave_store:
    286	csrrd	t0, EXCEPTION_KS0
    287	csrrd	t1, EXCEPTION_KS1
    288	csrrd	ra, EXCEPTION_KS2
    289	ertn
    290#ifdef CONFIG_64BIT
    291vmalloc_store:
    292	la.abs	t1, swapper_pg_dir
    293	b	vmalloc_done_store
    294#endif
    295
    296	/*
    297	 * This is the entry point when build_tlbchange_handler_head
    298	 * spots a huge page.
    299	 */
    300tlb_huge_update_store:
    301#ifdef CONFIG_SMP
    302	ll.d	t0, t1, 0
    303#else
    304	ld.d	t0, t1, 0
    305#endif
    306	srli.d	ra, t0, _PAGE_PRESENT_SHIFT
    307	andi	ra, ra, ((_PAGE_PRESENT | _PAGE_WRITE) >> _PAGE_PRESENT_SHIFT)
    308	xori	ra, ra, ((_PAGE_PRESENT | _PAGE_WRITE) >> _PAGE_PRESENT_SHIFT)
    309	bne	ra, $r0, nopage_tlb_store
    310
    311	tlbsrch
    312	ori	t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
    313
    314#ifdef CONFIG_SMP
    315	sc.d	t0, t1, 0
    316	beq	t0, $r0, tlb_huge_update_store
    317	ld.d	t0, t1, 0
    318#else
    319	st.d	t0, t1, 0
    320#endif
    321	addu16i.d	t1, $r0, -(CSR_TLBIDX_EHINV >> 16)
    322	addi.d	ra, t1, 0
    323	csrxchg	ra, t1, LOONGARCH_CSR_TLBIDX
    324	tlbwr
    325
    326	csrxchg	$r0, t1, LOONGARCH_CSR_TLBIDX
    327	/*
    328	 * A huge PTE describes an area the size of the
    329	 * configured huge page size. This is twice the
    330	 * of the large TLB entry size we intend to use.
    331	 * A TLB entry half the size of the configured
    332	 * huge page size is configured into entrylo0
    333	 * and entrylo1 to cover the contiguous huge PTE
    334	 * address space.
    335	 */
    336	/* Huge page: Move Global bit */
    337	xori	t0, t0, _PAGE_HUGE
    338	lu12i.w	t1, _PAGE_HGLOBAL >> 12
    339	and	t1, t0, t1
    340	srli.d	t1, t1, (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT)
    341	or	t0, t0, t1
    342
    343	addi.d	ra, t0, 0
    344	csrwr	t0, LOONGARCH_CSR_TLBELO0
    345	addi.d	t0, ra, 0
    346
    347	/* Convert to entrylo1 */
    348	addi.d	t1, $r0, 1
    349	slli.d	t1, t1, (HPAGE_SHIFT - 1)
    350	add.d	t0, t0, t1
    351	csrwr	t0, LOONGARCH_CSR_TLBELO1
    352
    353	/* Set huge page tlb entry size */
    354	addu16i.d	t0, $r0, (CSR_TLBIDX_PS >> 16)
    355	addu16i.d	t1, $r0, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
    356	csrxchg		t1, t0, LOONGARCH_CSR_TLBIDX
    357
    358	tlbfill
    359
    360	/* Reset default page size */
    361	addu16i.d	t0, $r0, (CSR_TLBIDX_PS >> 16)
    362	addu16i.d	t1, $r0, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
    363	csrxchg		t1, t0, LOONGARCH_CSR_TLBIDX
    364
    365nopage_tlb_store:
    366	dbar	0
    367	csrrd	ra, EXCEPTION_KS2
    368	la.abs	t0, tlb_do_page_fault_1
    369	jirl	$r0, t0, 0
    370SYM_FUNC_END(handle_tlb_store)
    371
    372SYM_FUNC_START(handle_tlb_modify)
    373	csrwr	t0, EXCEPTION_KS0
    374	csrwr	t1, EXCEPTION_KS1
    375	csrwr	ra, EXCEPTION_KS2
    376
    377	/*
    378	 * The vmalloc handling is not in the hotpath.
    379	 */
    380	csrrd	t0, LOONGARCH_CSR_BADV
    381	blt	t0, $r0, vmalloc_modify
    382	csrrd	t1, LOONGARCH_CSR_PGDL
    383
    384vmalloc_done_modify:
    385	/* Get PGD offset in bytes */
    386	srli.d	t0, t0, PGDIR_SHIFT
    387	andi	t0, t0, (PTRS_PER_PGD - 1)
    388	slli.d	t0, t0, 3
    389	add.d	t1, t1, t0
    390#if CONFIG_PGTABLE_LEVELS > 3
    391	csrrd	t0, LOONGARCH_CSR_BADV
    392	ld.d	t1, t1, 0
    393	srli.d	t0, t0, PUD_SHIFT
    394	andi	t0, t0, (PTRS_PER_PUD - 1)
    395	slli.d	t0, t0, 3
    396	add.d	t1, t1, t0
    397#endif
    398#if CONFIG_PGTABLE_LEVELS > 2
    399	csrrd	t0, LOONGARCH_CSR_BADV
    400	ld.d	t1, t1, 0
    401	srli.d	t0, t0, PMD_SHIFT
    402	andi	t0, t0, (PTRS_PER_PMD - 1)
    403	slli.d	t0, t0, 3
    404	add.d	t1, t1, t0
    405#endif
    406	ld.d	ra, t1, 0
    407
    408	/*
    409	 * For huge tlb entries, pmde doesn't contain an address but
    410	 * instead contains the tlb pte. Check the PAGE_HUGE bit and
    411	 * see if we need to jump to huge tlb processing.
    412	 */
    413	andi	t0, ra, _PAGE_HUGE
    414	bne	t0, $r0, tlb_huge_update_modify
    415
    416	csrrd	t0, LOONGARCH_CSR_BADV
    417	srli.d	t0, t0, (PAGE_SHIFT + PTE_ORDER)
    418	andi	t0, t0, (PTRS_PER_PTE - 1)
    419	slli.d	t0, t0, _PTE_T_LOG2
    420	add.d	t1, ra, t0
    421
    422#ifdef CONFIG_SMP
    423smp_pgtable_change_modify:
    424#endif
    425#ifdef CONFIG_SMP
    426	ll.d	t0, t1, 0
    427#else
    428	ld.d	t0, t1, 0
    429#endif
    430	tlbsrch
    431
    432	srli.d	ra, t0, _PAGE_WRITE_SHIFT
    433	andi	ra, ra, 1
    434	beq	ra, $r0, nopage_tlb_modify
    435
    436	ori	t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
    437#ifdef CONFIG_SMP
    438	sc.d	t0, t1, 0
    439	beq	t0, $r0, smp_pgtable_change_modify
    440#else
    441	st.d	t0, t1, 0
    442#endif
    443	ori	t1, t1, 8
    444	xori	t1, t1, 8
    445	ld.d	t0, t1, 0
    446	ld.d	t1, t1, 8
    447	csrwr	t0, LOONGARCH_CSR_TLBELO0
    448	csrwr	t1, LOONGARCH_CSR_TLBELO1
    449	tlbwr
    450leave_modify:
    451	csrrd	t0, EXCEPTION_KS0
    452	csrrd	t1, EXCEPTION_KS1
    453	csrrd	ra, EXCEPTION_KS2
    454	ertn
    455#ifdef CONFIG_64BIT
    456vmalloc_modify:
    457	la.abs  t1, swapper_pg_dir
    458	b	vmalloc_done_modify
    459#endif
    460
    461	/*
    462	 * This is the entry point when
    463	 * build_tlbchange_handler_head spots a huge page.
    464	 */
    465tlb_huge_update_modify:
    466#ifdef CONFIG_SMP
    467	ll.d	t0, t1, 0
    468#else
    469	ld.d	t0, t1, 0
    470#endif
    471
    472	srli.d	ra, t0, _PAGE_WRITE_SHIFT
    473	andi	ra, ra, 1
    474	beq	ra, $r0, nopage_tlb_modify
    475
    476	tlbsrch
    477	ori	t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
    478
    479#ifdef CONFIG_SMP
    480	sc.d	t0, t1, 0
    481	beq	t0, $r0, tlb_huge_update_modify
    482	ld.d	t0, t1, 0
    483#else
    484	st.d	t0, t1, 0
    485#endif
    486	/*
    487	 * A huge PTE describes an area the size of the
    488	 * configured huge page size. This is twice the
    489	 * of the large TLB entry size we intend to use.
    490	 * A TLB entry half the size of the configured
    491	 * huge page size is configured into entrylo0
    492	 * and entrylo1 to cover the contiguous huge PTE
    493	 * address space.
    494	 */
    495	/* Huge page: Move Global bit */
    496	xori	t0, t0, _PAGE_HUGE
    497	lu12i.w	t1, _PAGE_HGLOBAL >> 12
    498	and	t1, t0, t1
    499	srli.d	t1, t1, (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT)
    500	or	t0, t0, t1
    501
    502	addi.d	ra, t0, 0
    503	csrwr	t0, LOONGARCH_CSR_TLBELO0
    504	addi.d	t0, ra, 0
    505
    506	/* Convert to entrylo1 */
    507	addi.d	t1, $r0, 1
    508	slli.d	t1, t1, (HPAGE_SHIFT - 1)
    509	add.d	t0, t0, t1
    510	csrwr	t0, LOONGARCH_CSR_TLBELO1
    511
    512	/* Set huge page tlb entry size */
    513	addu16i.d	t0, $r0, (CSR_TLBIDX_PS >> 16)
    514	addu16i.d	t1, $r0, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
    515	csrxchg	t1, t0, LOONGARCH_CSR_TLBIDX
    516
    517	tlbwr
    518
    519	/* Reset default page size */
    520	addu16i.d	t0, $r0, (CSR_TLBIDX_PS >> 16)
    521	addu16i.d	t1, $r0, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
    522	csrxchg	t1, t0, LOONGARCH_CSR_TLBIDX
    523
    524nopage_tlb_modify:
    525	dbar	0
    526	csrrd	ra, EXCEPTION_KS2
    527	la.abs	t0, tlb_do_page_fault_1
    528	jirl	$r0, t0, 0
    529SYM_FUNC_END(handle_tlb_modify)
    530
    531SYM_FUNC_START(handle_tlb_refill)
    532	csrwr	t0, LOONGARCH_CSR_TLBRSAVE
    533	csrrd	t0, LOONGARCH_CSR_PGD
    534	lddir	t0, t0, 3
    535#if CONFIG_PGTABLE_LEVELS > 3
    536	lddir	t0, t0, 2
    537#endif
    538#if CONFIG_PGTABLE_LEVELS > 2
    539	lddir	t0, t0, 1
    540#endif
    541	ldpte	t0, 0
    542	ldpte	t0, 1
    543	tlbfill
    544	csrrd	t0, LOONGARCH_CSR_TLBRSAVE
    545	ertn
    546SYM_FUNC_END(handle_tlb_refill)