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

debug-exceptions.c (6647B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <test_util.h>
      3#include <kvm_util.h>
      4#include <processor.h>
      5
      6#define VCPU_ID 0
      7
      8#define MDSCR_KDE	(1 << 13)
      9#define MDSCR_MDE	(1 << 15)
     10#define MDSCR_SS	(1 << 0)
     11
     12#define DBGBCR_LEN8	(0xff << 5)
     13#define DBGBCR_EXEC	(0x0 << 3)
     14#define DBGBCR_EL1	(0x1 << 1)
     15#define DBGBCR_E	(0x1 << 0)
     16
     17#define DBGWCR_LEN8	(0xff << 5)
     18#define DBGWCR_RD	(0x1 << 3)
     19#define DBGWCR_WR	(0x2 << 3)
     20#define DBGWCR_EL1	(0x1 << 1)
     21#define DBGWCR_E	(0x1 << 0)
     22
     23#define SPSR_D		(1 << 9)
     24#define SPSR_SS		(1 << 21)
     25
     26extern unsigned char sw_bp, sw_bp2, hw_bp, hw_bp2, bp_svc, bp_brk, hw_wp, ss_start;
     27static volatile uint64_t sw_bp_addr, hw_bp_addr;
     28static volatile uint64_t wp_addr, wp_data_addr;
     29static volatile uint64_t svc_addr;
     30static volatile uint64_t ss_addr[4], ss_idx;
     31#define  PC(v)  ((uint64_t)&(v))
     32
     33static void reset_debug_state(void)
     34{
     35	asm volatile("msr daifset, #8");
     36
     37	write_sysreg(0, osdlr_el1);
     38	write_sysreg(0, oslar_el1);
     39	isb();
     40
     41	write_sysreg(0, mdscr_el1);
     42	/* This test only uses the first bp and wp slot. */
     43	write_sysreg(0, dbgbvr0_el1);
     44	write_sysreg(0, dbgbcr0_el1);
     45	write_sysreg(0, dbgwcr0_el1);
     46	write_sysreg(0, dbgwvr0_el1);
     47	isb();
     48}
     49
     50static void enable_os_lock(void)
     51{
     52	write_sysreg(1, oslar_el1);
     53	isb();
     54
     55	GUEST_ASSERT(read_sysreg(oslsr_el1) & 2);
     56}
     57
     58static void install_wp(uint64_t addr)
     59{
     60	uint32_t wcr;
     61	uint32_t mdscr;
     62
     63	wcr = DBGWCR_LEN8 | DBGWCR_RD | DBGWCR_WR | DBGWCR_EL1 | DBGWCR_E;
     64	write_sysreg(wcr, dbgwcr0_el1);
     65	write_sysreg(addr, dbgwvr0_el1);
     66	isb();
     67
     68	asm volatile("msr daifclr, #8");
     69
     70	mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_MDE;
     71	write_sysreg(mdscr, mdscr_el1);
     72	isb();
     73}
     74
     75static void install_hw_bp(uint64_t addr)
     76{
     77	uint32_t bcr;
     78	uint32_t mdscr;
     79
     80	bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E;
     81	write_sysreg(bcr, dbgbcr0_el1);
     82	write_sysreg(addr, dbgbvr0_el1);
     83	isb();
     84
     85	asm volatile("msr daifclr, #8");
     86
     87	mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_MDE;
     88	write_sysreg(mdscr, mdscr_el1);
     89	isb();
     90}
     91
     92static void install_ss(void)
     93{
     94	uint32_t mdscr;
     95
     96	asm volatile("msr daifclr, #8");
     97
     98	mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_SS;
     99	write_sysreg(mdscr, mdscr_el1);
    100	isb();
    101}
    102
    103static volatile char write_data;
    104
    105static void guest_code(void)
    106{
    107	GUEST_SYNC(0);
    108
    109	/* Software-breakpoint */
    110	reset_debug_state();
    111	asm volatile("sw_bp: brk #0");
    112	GUEST_ASSERT_EQ(sw_bp_addr, PC(sw_bp));
    113
    114	GUEST_SYNC(1);
    115
    116	/* Hardware-breakpoint */
    117	reset_debug_state();
    118	install_hw_bp(PC(hw_bp));
    119	asm volatile("hw_bp: nop");
    120	GUEST_ASSERT_EQ(hw_bp_addr, PC(hw_bp));
    121
    122	GUEST_SYNC(2);
    123
    124	/* Hardware-breakpoint + svc */
    125	reset_debug_state();
    126	install_hw_bp(PC(bp_svc));
    127	asm volatile("bp_svc: svc #0");
    128	GUEST_ASSERT_EQ(hw_bp_addr, PC(bp_svc));
    129	GUEST_ASSERT_EQ(svc_addr, PC(bp_svc) + 4);
    130
    131	GUEST_SYNC(3);
    132
    133	/* Hardware-breakpoint + software-breakpoint */
    134	reset_debug_state();
    135	install_hw_bp(PC(bp_brk));
    136	asm volatile("bp_brk: brk #0");
    137	GUEST_ASSERT_EQ(sw_bp_addr, PC(bp_brk));
    138	GUEST_ASSERT_EQ(hw_bp_addr, PC(bp_brk));
    139
    140	GUEST_SYNC(4);
    141
    142	/* Watchpoint */
    143	reset_debug_state();
    144	install_wp(PC(write_data));
    145	write_data = 'x';
    146	GUEST_ASSERT_EQ(write_data, 'x');
    147	GUEST_ASSERT_EQ(wp_data_addr, PC(write_data));
    148
    149	GUEST_SYNC(5);
    150
    151	/* Single-step */
    152	reset_debug_state();
    153	install_ss();
    154	ss_idx = 0;
    155	asm volatile("ss_start:\n"
    156		     "mrs x0, esr_el1\n"
    157		     "add x0, x0, #1\n"
    158		     "msr daifset, #8\n"
    159		     : : : "x0");
    160	GUEST_ASSERT_EQ(ss_addr[0], PC(ss_start));
    161	GUEST_ASSERT_EQ(ss_addr[1], PC(ss_start) + 4);
    162	GUEST_ASSERT_EQ(ss_addr[2], PC(ss_start) + 8);
    163
    164	GUEST_SYNC(6);
    165
    166	/* OS Lock does not block software-breakpoint */
    167	reset_debug_state();
    168	enable_os_lock();
    169	sw_bp_addr = 0;
    170	asm volatile("sw_bp2: brk #0");
    171	GUEST_ASSERT_EQ(sw_bp_addr, PC(sw_bp2));
    172
    173	GUEST_SYNC(7);
    174
    175	/* OS Lock blocking hardware-breakpoint */
    176	reset_debug_state();
    177	enable_os_lock();
    178	install_hw_bp(PC(hw_bp2));
    179	hw_bp_addr = 0;
    180	asm volatile("hw_bp2: nop");
    181	GUEST_ASSERT_EQ(hw_bp_addr, 0);
    182
    183	GUEST_SYNC(8);
    184
    185	/* OS Lock blocking watchpoint */
    186	reset_debug_state();
    187	enable_os_lock();
    188	write_data = '\0';
    189	wp_data_addr = 0;
    190	install_wp(PC(write_data));
    191	write_data = 'x';
    192	GUEST_ASSERT_EQ(write_data, 'x');
    193	GUEST_ASSERT_EQ(wp_data_addr, 0);
    194
    195	GUEST_SYNC(9);
    196
    197	/* OS Lock blocking single-step */
    198	reset_debug_state();
    199	enable_os_lock();
    200	ss_addr[0] = 0;
    201	install_ss();
    202	ss_idx = 0;
    203	asm volatile("mrs x0, esr_el1\n\t"
    204		     "add x0, x0, #1\n\t"
    205		     "msr daifset, #8\n\t"
    206		     : : : "x0");
    207	GUEST_ASSERT_EQ(ss_addr[0], 0);
    208
    209	GUEST_DONE();
    210}
    211
    212static void guest_sw_bp_handler(struct ex_regs *regs)
    213{
    214	sw_bp_addr = regs->pc;
    215	regs->pc += 4;
    216}
    217
    218static void guest_hw_bp_handler(struct ex_regs *regs)
    219{
    220	hw_bp_addr = regs->pc;
    221	regs->pstate |= SPSR_D;
    222}
    223
    224static void guest_wp_handler(struct ex_regs *regs)
    225{
    226	wp_data_addr = read_sysreg(far_el1);
    227	wp_addr = regs->pc;
    228	regs->pstate |= SPSR_D;
    229}
    230
    231static void guest_ss_handler(struct ex_regs *regs)
    232{
    233	GUEST_ASSERT_1(ss_idx < 4, ss_idx);
    234	ss_addr[ss_idx++] = regs->pc;
    235	regs->pstate |= SPSR_SS;
    236}
    237
    238static void guest_svc_handler(struct ex_regs *regs)
    239{
    240	svc_addr = regs->pc;
    241}
    242
    243static int debug_version(struct kvm_vm *vm)
    244{
    245	uint64_t id_aa64dfr0;
    246
    247	get_reg(vm, VCPU_ID, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), &id_aa64dfr0);
    248	return id_aa64dfr0 & 0xf;
    249}
    250
    251int main(int argc, char *argv[])
    252{
    253	struct kvm_vm *vm;
    254	struct ucall uc;
    255	int stage;
    256
    257	vm = vm_create_default(VCPU_ID, 0, guest_code);
    258	ucall_init(vm, NULL);
    259
    260	vm_init_descriptor_tables(vm);
    261	vcpu_init_descriptor_tables(vm, VCPU_ID);
    262
    263	if (debug_version(vm) < 6) {
    264		print_skip("Armv8 debug architecture not supported.");
    265		kvm_vm_free(vm);
    266		exit(KSFT_SKIP);
    267	}
    268
    269	vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
    270				ESR_EC_BRK_INS, guest_sw_bp_handler);
    271	vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
    272				ESR_EC_HW_BP_CURRENT, guest_hw_bp_handler);
    273	vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
    274				ESR_EC_WP_CURRENT, guest_wp_handler);
    275	vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
    276				ESR_EC_SSTEP_CURRENT, guest_ss_handler);
    277	vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
    278				ESR_EC_SVC64, guest_svc_handler);
    279
    280	for (stage = 0; stage < 11; stage++) {
    281		vcpu_run(vm, VCPU_ID);
    282
    283		switch (get_ucall(vm, VCPU_ID, &uc)) {
    284		case UCALL_SYNC:
    285			TEST_ASSERT(uc.args[1] == stage,
    286				"Stage %d: Unexpected sync ucall, got %lx",
    287				stage, (ulong)uc.args[1]);
    288			break;
    289		case UCALL_ABORT:
    290			TEST_FAIL("%s at %s:%ld\n\tvalues: %#lx, %#lx",
    291				(const char *)uc.args[0],
    292				__FILE__, uc.args[1], uc.args[2], uc.args[3]);
    293			break;
    294		case UCALL_DONE:
    295			goto done;
    296		default:
    297			TEST_FAIL("Unknown ucall %lu", uc.cmd);
    298		}
    299	}
    300
    301done:
    302	kvm_vm_free(vm);
    303	return 0;
    304}