1be9b007bSLaurent Vivier /* 2be9b007bSLaurent Vivier * Test some powerpc instructions 3be9b007bSLaurent Vivier */ 4be9b007bSLaurent Vivier 5be9b007bSLaurent Vivier #include <libcflat.h> 6be9b007bSLaurent Vivier #include <asm/processor.h> 7be9b007bSLaurent Vivier 8be9b007bSLaurent Vivier static int verbose; 9be9b007bSLaurent Vivier static int volatile is_invalid; 10c6699676SLaurent Vivier static int volatile alignment; 11be9b007bSLaurent Vivier 12be9b007bSLaurent Vivier static void program_check_handler(struct pt_regs *regs, void *opaque) 13be9b007bSLaurent Vivier { 14be9b007bSLaurent Vivier int *data = opaque; 15be9b007bSLaurent Vivier 16be9b007bSLaurent Vivier if (verbose) { 17be9b007bSLaurent Vivier printf("Detected invalid instruction 0x%016lx: %08x\n", 18be9b007bSLaurent Vivier regs->nip, *(uint32_t*)regs->nip); 19be9b007bSLaurent Vivier } 20be9b007bSLaurent Vivier 21be9b007bSLaurent Vivier /* the result is bit 16 to 19 of SRR1 22be9b007bSLaurent Vivier * bit 0: SRR0 contains the address of the next instruction 23be9b007bSLaurent Vivier * bit 1: Trap 24be9b007bSLaurent Vivier * bit 2: Privileged instruction 25be9b007bSLaurent Vivier * bit 3: Illegal instruction 26be9b007bSLaurent Vivier * bit 4: FP enabled exception type 27be9b007bSLaurent Vivier */ 28be9b007bSLaurent Vivier 29be9b007bSLaurent Vivier *data = regs->msr >> 16; 30be9b007bSLaurent Vivier 31be9b007bSLaurent Vivier regs->nip += 4; 32be9b007bSLaurent Vivier } 33be9b007bSLaurent Vivier 34c6699676SLaurent Vivier static void alignment_handler(struct pt_regs *regs, void *opaque) 35c6699676SLaurent Vivier { 36c6699676SLaurent Vivier int *data = opaque; 37c6699676SLaurent Vivier 38*0fd70fe3SLaurent Vivier if (verbose) { 39c6699676SLaurent Vivier printf("Detected alignment exception 0x%016lx: %08x\n", 40c6699676SLaurent Vivier regs->nip, *(uint32_t*)regs->nip); 41*0fd70fe3SLaurent Vivier } 42c6699676SLaurent Vivier 43c6699676SLaurent Vivier *data = 1; 44c6699676SLaurent Vivier 45c6699676SLaurent Vivier regs->nip += 4; 46c6699676SLaurent Vivier } 47c6699676SLaurent Vivier 48be9b007bSLaurent Vivier static void test_illegal(void) 49be9b007bSLaurent Vivier { 50be9b007bSLaurent Vivier report_prefix_push("invalid"); 51be9b007bSLaurent Vivier 52be9b007bSLaurent Vivier is_invalid = 0; 53be9b007bSLaurent Vivier 54be9b007bSLaurent Vivier asm volatile (".long 0"); 55be9b007bSLaurent Vivier 56be9b007bSLaurent Vivier report("exception", is_invalid == 8); /* illegal instruction */ 57be9b007bSLaurent Vivier 58be9b007bSLaurent Vivier report_prefix_pop(); 59be9b007bSLaurent Vivier } 60be9b007bSLaurent Vivier 618260a156SLaurent Vivier static void test_64bit(void) 628260a156SLaurent Vivier { 638260a156SLaurent Vivier uint64_t msr; 648260a156SLaurent Vivier 658260a156SLaurent Vivier report_prefix_push("64bit"); 668260a156SLaurent Vivier 678260a156SLaurent Vivier asm("mfmsr %[msr]": [msr] "=r" (msr)); 688260a156SLaurent Vivier 698260a156SLaurent Vivier report("detected", msr & 0x8000000000000000UL); 708260a156SLaurent Vivier 718260a156SLaurent Vivier report_prefix_pop(); 728260a156SLaurent Vivier } 738260a156SLaurent Vivier 74a46c6196SLaurent Vivier /* 75a46c6196SLaurent Vivier * lswx: Load String Word Indexed X-form 76a46c6196SLaurent Vivier * 77a46c6196SLaurent Vivier * lswx RT,RA,RB 78a46c6196SLaurent Vivier * 79a46c6196SLaurent Vivier * EA = (RA|0) + RB 80a46c6196SLaurent Vivier * n = XER 81a46c6196SLaurent Vivier * 82a46c6196SLaurent Vivier * Load n bytes from address EA into (n / 4) consecutive registers, 83a46c6196SLaurent Vivier * throught RT -> RT + (n / 4) - 1. 84a46c6196SLaurent Vivier * - Data are loaded into 4 low order bytes of registers (Word). 85a46c6196SLaurent Vivier * - The unfilled bytes are set to 0. 86a46c6196SLaurent Vivier * - The sequence of registers wraps around to GPR0. 87a46c6196SLaurent Vivier * - if n == 0, content of RT is undefined 88a46c6196SLaurent Vivier * - RT <= RA or RB < RT + (n + 4) is invalid or result is undefined 89a46c6196SLaurent Vivier * - RT == RA == 0 is invalid 90a46c6196SLaurent Vivier * 91c6699676SLaurent Vivier * For lswx in little-endian mode, an alignment interrupt always occurs. 92c6699676SLaurent Vivier * 93a46c6196SLaurent Vivier */ 94a46c6196SLaurent Vivier 95a46c6196SLaurent Vivier static void test_lswx(void) 96a46c6196SLaurent Vivier { 97a46c6196SLaurent Vivier int i; 98a46c6196SLaurent Vivier char addr[128]; 99a46c6196SLaurent Vivier uint64_t regs[32]; 100a46c6196SLaurent Vivier 101a46c6196SLaurent Vivier report_prefix_push("lswx"); 102a46c6196SLaurent Vivier 103a46c6196SLaurent Vivier /* fill memory with sequence */ 104a46c6196SLaurent Vivier 105a46c6196SLaurent Vivier for (i = 0; i < 128; i++) 106a46c6196SLaurent Vivier addr[i] = 1 + i; 107a46c6196SLaurent Vivier 108a46c6196SLaurent Vivier /* check incomplete register filling */ 109a46c6196SLaurent Vivier 110c6699676SLaurent Vivier alignment = 0; 111a46c6196SLaurent Vivier asm volatile ("mtxer %[len];" 112a46c6196SLaurent Vivier "li r12,-1;" 113a46c6196SLaurent Vivier "mr r11, r12;" 114a46c6196SLaurent Vivier "lswx r11, 0, %[addr];" 115a46c6196SLaurent Vivier "std r11, 0*8(%[regs]);" 116a46c6196SLaurent Vivier "std r12, 1*8(%[regs]);" 117a46c6196SLaurent Vivier :: 118a46c6196SLaurent Vivier [len] "r" (3), 119a46c6196SLaurent Vivier [addr] "r" (addr), 120a46c6196SLaurent Vivier [regs] "r" (regs) 121a46c6196SLaurent Vivier : 122a46c6196SLaurent Vivier "xer", "r11", "r12", "memory"); 123a46c6196SLaurent Vivier 124c6699676SLaurent Vivier #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 125c6699676SLaurent Vivier report("alignment", alignment); 126c6699676SLaurent Vivier return; 127c6699676SLaurent Vivier #else 128a46c6196SLaurent Vivier report("partial", regs[0] == 0x01020300 && regs[1] == (uint64_t)-1); 129c6699676SLaurent Vivier #endif 130a46c6196SLaurent Vivier 131a46c6196SLaurent Vivier /* check an old know bug: the number of bytes is used as 132a46c6196SLaurent Vivier * the number of registers, so try 32 bytes. 133a46c6196SLaurent Vivier */ 134a46c6196SLaurent Vivier 135a46c6196SLaurent Vivier asm volatile ("mtxer %[len];" 136a46c6196SLaurent Vivier "li r19,-1;" 137a46c6196SLaurent Vivier "mr r11, r19; mr r12, r19; mr r13, r19;" 138a46c6196SLaurent Vivier "mr r14, r19; mr r15, r19; mr r16, r19;" 139a46c6196SLaurent Vivier "mr r17, r19; mr r18, r19;" 140a46c6196SLaurent Vivier "lswx r11, 0, %[addr];" 141a46c6196SLaurent Vivier "std r11, 0*8(%[regs]);" 142a46c6196SLaurent Vivier "std r12, 1*8(%[regs]);" 143a46c6196SLaurent Vivier "std r13, 2*8(%[regs]);" 144a46c6196SLaurent Vivier "std r14, 3*8(%[regs]);" 145a46c6196SLaurent Vivier "std r15, 4*8(%[regs]);" 146a46c6196SLaurent Vivier "std r16, 5*8(%[regs]);" 147a46c6196SLaurent Vivier "std r17, 6*8(%[regs]);" 148a46c6196SLaurent Vivier "std r18, 7*8(%[regs]);" 149a46c6196SLaurent Vivier "std r19, 8*8(%[regs]);" 150a46c6196SLaurent Vivier :: 151a46c6196SLaurent Vivier [len] "r" (32), 152a46c6196SLaurent Vivier [addr] "r" (addr), 153a46c6196SLaurent Vivier [regs] "r" (regs) 154a46c6196SLaurent Vivier : 155a46c6196SLaurent Vivier /* as 32 is the number of bytes, 156a46c6196SLaurent Vivier * we should modify 32/4 = 8 regs, from r11 to r18 157a46c6196SLaurent Vivier * We check r19 is unmodified by filling it with 1s 158a46c6196SLaurent Vivier * before the instruction. 159a46c6196SLaurent Vivier */ 160a46c6196SLaurent Vivier "xer", "r11", "r12", "r13", "r14", "r15", "r16", "r17", 161a46c6196SLaurent Vivier "r18", "r19", "memory"); 162a46c6196SLaurent Vivier 163a46c6196SLaurent Vivier report("length", regs[0] == 0x01020304 && regs[1] == 0x05060708 && 164a46c6196SLaurent Vivier regs[2] == 0x090a0b0c && regs[3] == 0x0d0e0f10 && 165a46c6196SLaurent Vivier regs[4] == 0x11121314 && regs[5] == 0x15161718 && 166a46c6196SLaurent Vivier regs[6] == 0x191a1b1c && regs[7] == 0x1d1e1f20 && 167a46c6196SLaurent Vivier regs[8] == (uint64_t)-1); 168a46c6196SLaurent Vivier 169a46c6196SLaurent Vivier /* check wrap around to r0 */ 170a46c6196SLaurent Vivier 171a46c6196SLaurent Vivier asm volatile ("mtxer %[len];" 172a46c6196SLaurent Vivier "li r31,-1;" 173a46c6196SLaurent Vivier "mr r0, r31;" 174a46c6196SLaurent Vivier "lswx r31, 0, %[addr];" 175a46c6196SLaurent Vivier "std r31, 0*8(%[regs]);" 176a46c6196SLaurent Vivier "std r0, 1*8(%[regs]);" 177a46c6196SLaurent Vivier :: 178a46c6196SLaurent Vivier [len] "r" (8), 179a46c6196SLaurent Vivier [addr] "r" (addr), 180a46c6196SLaurent Vivier [regs] "r" (regs) 181a46c6196SLaurent Vivier : 182a46c6196SLaurent Vivier /* modify two registers from r31, wrap around to r0 */ 183a46c6196SLaurent Vivier "xer", "r31", "r0", "memory"); 184a46c6196SLaurent Vivier 185a46c6196SLaurent Vivier report("wrap around to r0", regs[0] == 0x01020304 && 186a46c6196SLaurent Vivier regs[1] == 0x05060708); 187a46c6196SLaurent Vivier 188a46c6196SLaurent Vivier /* check wrap around to r0 over RB doesn't break RB */ 189a46c6196SLaurent Vivier 190a46c6196SLaurent Vivier asm volatile ("mtxer %[len];" 191a46c6196SLaurent Vivier "mr r29,r1;" 192a46c6196SLaurent Vivier "li r31,-1;" 193a46c6196SLaurent Vivier "mr r1,r31;" 194a46c6196SLaurent Vivier "mr r0, %[addr];" 195a46c6196SLaurent Vivier "lswx r31, 0, r0;" 196a46c6196SLaurent Vivier "std r31, 0*8(%[regs]);" 197a46c6196SLaurent Vivier "std r0, 1*8(%[regs]);" 198a46c6196SLaurent Vivier "std r1, 2*8(%[regs]);" 199a46c6196SLaurent Vivier "mr r1,r29;" 200a46c6196SLaurent Vivier :: 201a46c6196SLaurent Vivier [len] "r" (12), 202a46c6196SLaurent Vivier [addr] "r" (addr), 203a46c6196SLaurent Vivier [regs] "r" (regs) 204a46c6196SLaurent Vivier : 205a46c6196SLaurent Vivier /* loading three registers from r31 wraps around to r1, 206a46c6196SLaurent Vivier * r1 is saved to r29, as adding it to the clobber 207a46c6196SLaurent Vivier * list doesn't protect it 208a46c6196SLaurent Vivier */ 209a46c6196SLaurent Vivier "xer", "r31", "r0", "r29", "memory"); 210a46c6196SLaurent Vivier 211a46c6196SLaurent Vivier /* doc says it is invalid, real proc stops when it comes to 212a46c6196SLaurent Vivier * overwrite the register. 213a46c6196SLaurent Vivier * In all the cases, the register must stay untouched 214a46c6196SLaurent Vivier */ 215a46c6196SLaurent Vivier report("Don't overwrite Rb", regs[1] == (uint64_t)addr); 216a46c6196SLaurent Vivier 217a46c6196SLaurent Vivier report_prefix_pop(); 218a46c6196SLaurent Vivier } 219a46c6196SLaurent Vivier 220be9b007bSLaurent Vivier int main(int argc, char **argv) 221be9b007bSLaurent Vivier { 222be9b007bSLaurent Vivier int i; 223be9b007bSLaurent Vivier 224be9b007bSLaurent Vivier handle_exception(0x700, program_check_handler, (void *)&is_invalid); 225c6699676SLaurent Vivier handle_exception(0x600, alignment_handler, (void *)&alignment); 226be9b007bSLaurent Vivier 227be9b007bSLaurent Vivier for (i = 0; i < argc; i++) { 228be9b007bSLaurent Vivier if (strcmp(argv[i], "-v") == 0) { 229be9b007bSLaurent Vivier verbose = 1; 230be9b007bSLaurent Vivier } 231be9b007bSLaurent Vivier } 232be9b007bSLaurent Vivier 233be9b007bSLaurent Vivier report_prefix_push("emulator"); 234be9b007bSLaurent Vivier 2358260a156SLaurent Vivier test_64bit(); 236be9b007bSLaurent Vivier test_illegal(); 237a46c6196SLaurent Vivier test_lswx(); 238be9b007bSLaurent Vivier 239be9b007bSLaurent Vivier report_prefix_pop(); 240be9b007bSLaurent Vivier 241be9b007bSLaurent Vivier return report_summary(); 242be9b007bSLaurent Vivier } 243