int main(void) { unsigned int va; unsigned int stack_addr = (unsigned int) &va & ~(PAGE_SIZE - 1); // Map code & data for (va = 0; va < 0x10000; va += PAGE_SIZE) { add_itlb_mapping(va, va); add_dtlb_mapping(va, va | TLB_WRITABLE); } add_dtlb_mapping(stack_addr, stack_addr | TLB_WRITABLE); add_dtlb_mapping(IO_REGION_BASE, IO_REGION_BASE | TLB_WRITABLE); // Enable MMU and disable supervisor mode in flags register __builtin_nyuzi_write_control_reg(CR_FAULT_HANDLER, general_fault_handler); __builtin_nyuzi_write_control_reg(CR_TLB_MISS_HANDLER, tlb_fault_handler); __builtin_nyuzi_write_control_reg(CR_FLAGS, FLAG_MMU_EN); // This will fault because the thread is in user mode. Then the general // fault handler will read the address to ensure the mapping wasn't inserted. // That should cause a TLB fault. add_dtlb_mapping(data, ((unsigned int)data) | TLB_WRITABLE); // CHECK: general fault 10 // CHECK: TLB fault printf("FAIL: executed instruction\n"); }
int main(void) { unsigned int va; unsigned int stack_addr = (unsigned int) &va & ~(PAGE_SIZE - 1); // Map code & data for (va = 0; va < 0x10000; va += PAGE_SIZE) { add_itlb_mapping(va, va); add_dtlb_mapping(va, va | TLB_WRITABLE); } add_dtlb_mapping(stack_addr, stack_addr | TLB_WRITABLE); add_dtlb_mapping(IO_REGION_BASE, IO_REGION_BASE | TLB_WRITABLE); // A data region. Enter a few bogus mapping first, then the proper // one, which should replace them. add_dtlb_mapping(data_addr, 0x101000 | TLB_WRITABLE); add_dtlb_mapping(data_addr, 0x102000 | TLB_WRITABLE); add_dtlb_mapping(data_addr, 0x103000 | TLB_WRITABLE); add_dtlb_mapping(data_addr, 0x104000 | TLB_WRITABLE); add_dtlb_mapping(data_addr, ((unsigned int) data_addr) | TLB_WRITABLE); // Enable MMU in flags register __builtin_nyuzi_write_control_reg(CR_TLB_MISS_HANDLER, tlb_miss_handler); __builtin_nyuzi_write_control_reg(CR_FLAGS, FLAG_MMU_EN | FLAG_SUPERVISOR_EN); *data_addr = 0x1f6818aa; printf("data value %08x\n", *data_addr); // CHECK: data value 1f6818aa return 0; }
void faultHandler() { __builtin_nyuzi_write_control_reg(CR_SCRATCHPAD0, 0x88cf70b4); __builtin_nyuzi_write_control_reg(CR_SCRATCHPAD1, 0x78662516); // This will cause a nested TLB miss fault *EXTPTR = 0; // We've returned from the TLB miss handler. Ensure all of the control registers // have been restored to the values for the original fault. printf("reason %d\n", __builtin_nyuzi_read_control_reg(CR_FAULT_REASON)); // CHECK: reason 2 printf("fault address %08x\n", __builtin_nyuzi_read_control_reg(CR_FAULT_ADDRESS)); // CHECK: 00000017 printf("flags %02x\n", __builtin_nyuzi_read_control_reg(CR_SAVED_FLAGS)); // CHECK: flags 06 printf("subcycle %d\n", __builtin_nyuzi_read_control_reg(CR_SUBCYCLE)); // CHECK: subcycle 6 if (__builtin_nyuzi_read_control_reg(CR_FAULT_PC) < (unsigned int) &tlb_miss_handler) printf("fault pc ok\n"); // CHECK: fault pc ok else printf("fault pc bad (%08x)\n", __builtin_nyuzi_read_control_reg(CR_FAULT_PC)); printf("CR_SCRATCHPAD0 %08x\n", __builtin_nyuzi_read_control_reg(CR_SCRATCHPAD0)); // CHECK: CR_SCRATCHPAD0 88cf70b4 printf("CR_SCRATCHPAD1 %08x\n", __builtin_nyuzi_read_control_reg(CR_SCRATCHPAD1)); // CHECK: CR_SCRATCHPAD1 78662516 exit(0); }
// Each thread starts here and performs 16 hashes simultaneously. With four // threads, there are 64 hashes in flight at a time. Each thread repeats this // four times. The total number of hashes performed is 256. int main() { __builtin_nyuzi_write_control_reg(30, 0xffffffff); // Start other threads const int kSourceBlockSize = 128; const int kHashSize = 32; const int kNumBuffers = 2; const int kNumLanes = 16; unsigned int basePtr = 0x100000 + __builtin_nyuzi_read_control_reg(0) * (kHashSize * kNumLanes * kNumBuffers) + (kSourceBlockSize * kNumLanes); const vecu16_t kStepVector = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; vecu16_t inputPtr = __builtin_nyuzi_makevectori(basePtr) + (kStepVector * __builtin_nyuzi_makevectori(kHashSize)); vecu16_t tmpPtr = inputPtr + __builtin_nyuzi_makevectori(kSourceBlockSize * kNumLanes); vecu16_t outputPtr = tmpPtr + __builtin_nyuzi_makevectori(kHashSize * kNumLanes); for (int i = 0; i < 4; i++) { // Double sha-2 hash sha2Hash(inputPtr, kSourceBlockSize / kHashSize, outputPtr); sha2Hash(tmpPtr, 1, outputPtr); } return 0; }
int main(int argc, const char *argv[]) { __builtin_nyuzi_write_control_reg(1, fault_handler); switch_to_user_mode(); // This will fault asm("eret"); // CHECK: FAULT 10 current flags 04 prev flags 00 }
int main(void) { unsigned int va; int asid; unsigned int stack_addr = (unsigned int) &va & ~(PAGE_SIZE - 1); // Map code & data for (va = 0; va < 0x10000; va += PAGE_SIZE) { add_itlb_mapping(va, va | TLB_GLOBAL | TLB_EXECUTABLE | TLB_PRESENT); add_dtlb_mapping(va, va | TLB_WRITABLE | TLB_GLOBAL | TLB_PRESENT); } add_dtlb_mapping(stack_addr, stack_addr | TLB_WRITABLE | TLB_GLOBAL | TLB_PRESENT); add_dtlb_mapping(IO_REGION_BASE, IO_REGION_BASE | TLB_WRITABLE | TLB_GLOBAL | TLB_PRESENT); // Map a private page into address space 1 set_asid(1); add_dtlb_mapping(VADDR1, PADDR1 | TLB_PRESENT); *((unsigned int*) PADDR1) = 0xdeadbeef; // Map a private page into address space 2 set_asid(2); add_dtlb_mapping(VADDR1, PADDR2 | TLB_PRESENT); *((unsigned int*) PADDR2) = 0xabcdefed; // Enable MMU in flags register __builtin_nyuzi_write_control_reg(CR_FAULT_HANDLER, fault_handler); __builtin_nyuzi_write_control_reg(CR_TLB_MISS_HANDLER, fault_handler); __builtin_nyuzi_write_control_reg(CR_FLAGS, FLAG_MMU_EN | FLAG_SUPERVISOR_EN); // Read value from first address space set_asid(1); printf("A1 %08x\n", *((volatile unsigned int*) VADDR1)); // CHECK: A1 deadbeef // Read value from the second address space set_asid(2); printf("A2 %08x\n", *((volatile unsigned int*) VADDR1)); // CHECK: A2 abcdefed return 0; }
int main(void) { mapProgramAndStack(); addDtlbMapping(IO_REGION_BASE, IO_REGION_BASE | TLB_WRITABLE | TLB_PRESENT); // Enable MMU in flags register __builtin_nyuzi_write_control_reg(CR_TLB_MISS_HANDLER, (unsigned int) dumpFaultInfo); __builtin_nyuzi_write_control_reg(CR_FLAGS, FLAG_MMU_EN | FLAG_SUPERVISOR_EN); printf("Working correctly so far\n"); // CHECK: Working correctly so far asm("tlbinvalall"); printf("should_not_be_here\n"); // CHECK: FAULT // CHECKN: should_not_be_here return 0; }
int main(void) { __builtin_nyuzi_write_control_reg(1, trap_handler); __builtin_nyuzi_write_control_reg(4, 1); // Enable interrupts while (interruptCount < 5) ; // CHECK: trap 10 // CHECK: trap 11 // CHECK: trap 12 // CHECK: trap 13 // CHECK: trap 14 // Check that this process is running correctly and interrupt // flag is cleared. printf("Back in main\n"); // CHECK: Back in main return 0; }
int main(void) { __builtin_nyuzi_write_control_reg(1, faultHandler); // Initialize scratchpad0 __builtin_nyuzi_write_control_reg(11, 0x12345678); // Switch to user mode, but leave MMU active switchToUserMode(); // Check two things: // - That we raise a fault // - That the control register isn't updated. Since the fault check and update // use different logic, it's possible to update the register *and* fault, // which is still a security hole. __builtin_nyuzi_write_control_reg(11, 0xdeadbeef); // CHECK: FAULT 10 current flags 04 prev flags 00 // CHECK: scratchpad = 12345678 printf("should_not_be_here\n"); // CHECKN: should_not_be_here }
int main(void) { mapProgramAndStack(); addDtlbMapping(IO_REGION_BASE, IO_REGION_BASE | TLB_WRITABLE | TLB_PRESENT); // Data region that doesn't have the present bit set. addDtlbMapping((unsigned int) dataAddr, ((unsigned int)dataAddr) | TLB_WRITABLE); __builtin_nyuzi_write_control_reg(CR_FAULT_HANDLER, (unsigned int) dumpFaultInfo); // Turn on MMU and switch to user mode __builtin_nyuzi_write_control_reg(CR_FLAGS, FLAG_MMU_EN); // Flush pipeline usleep(0); *dataAddr = 0x12345678; // CHECK: FAULT 3 00100000 current flags 06 prev flags 02 printf("should_not_be_here\n"); // CHECKN: should_not_be_here }
int main(void) { unsigned int va; unsigned int stack_addr = (unsigned int) &va & ~(PAGE_SIZE - 1); // Map code & data for (va = 0; va < 0x10000; va += PAGE_SIZE) { add_itlb_mapping(va, va | TLB_GLOBAL); add_dtlb_mapping(va, va | TLB_WRITABLE | TLB_GLOBAL); } add_dtlb_mapping(stack_addr, stack_addr | TLB_WRITABLE); add_dtlb_mapping(data_addr, ((unsigned int)data_addr) | TLB_WRITABLE); // Writable *data_addr2 = 0x12345678; add_dtlb_mapping(data_addr2, data_addr2); // Not writable add_dtlb_mapping(IO_REGION_BASE, IO_REGION_BASE | TLB_WRITABLE); // I/O // Enable MMU in flags register __builtin_nyuzi_write_control_reg(CR_FAULT_HANDLER, fault_handler); __builtin_nyuzi_write_control_reg(CR_TLB_MISS_HANDLER, fault_handler); __builtin_nyuzi_write_control_reg(CR_FLAGS, FLAG_MMU_EN | FLAG_SUPERVISOR_EN); // This should write successfully *data_addr = 0x1f6818aa; printf("data value %08x\n", *data_addr); // CHECK: data value 1f6818aa // Attempt to write to write protected page will fail. *data_addr2 = 0xdeadbeef; // Ensure two things: // - that a fault is raised // - that the value isn't actually written // CHECK: FAULT 7 00101000 // CHECK: data value = 12345678 printf("should_not_be_here\n"); // CHECKN: should_not_be_here return 0; }
int main(void) { veci16_t pointers = { &foo, &foo, &foo, &foo, &foo, &foo, 0x17, &foo, &foo, &foo, &foo, &foo, &foo, &foo, &foo, &foo }; __builtin_nyuzi_write_control_reg(CR_FAULT_HANDLER, (unsigned int) faultHandler); __builtin_nyuzi_write_control_reg(CR_TLB_MISS_HANDLER, (unsigned int) tlb_miss_handler); __builtin_nyuzi_write_control_reg(CR_FLAGS, FLAG_MMU_EN | FLAG_SUPERVISOR_EN); // This ensures the libc functions are mapped into the TLB so we don't generate // multiple TLB misses in the fault handler (doesn't break the test, just makes // debugging cleaner) printf("Starting test %d\n", 12); // This will cause an alignment fault on the 6th lane and jump to 'faultHandler'. // Use scatter store rather than a normal scalar store to ensure the // subcycle counter is saved correctly. __builtin_nyuzi_scatter_storei(pointers, __builtin_nyuzi_makevectori(0)); printf("should_not_be_here\n"); // CHECKN: should_not_be_here return 0; }
int main(void) { unsigned int va; int asid; unsigned int stack_addr = (unsigned int) &va & ~(PAGE_SIZE - 1); // Map code & data for (va = 0; va < 0x10000; va += PAGE_SIZE) { add_itlb_mapping(va, va); add_dtlb_mapping(va, va | TLB_WRITABLE | TLB_GLOBAL); } add_dtlb_mapping(stack_addr, stack_addr | TLB_WRITABLE); add_dtlb_mapping(IO_REGION_BASE, IO_REGION_BASE | TLB_SUPERVISOR | TLB_WRITABLE); // Alias mapping that we will use for test (the normal mapped region is used // to halt the test). add_dtlb_mapping(0x100000, IO_REGION_BASE | TLB_SUPERVISOR | TLB_WRITABLE); __builtin_nyuzi_write_control_reg(CR_FAULT_HANDLER, fault_handler); __builtin_nyuzi_write_control_reg(CR_FLAGS, FLAG_MMU_EN | FLAG_SUPERVISOR_EN); // Can write to page in supervisor mode globaltmp = *((volatile unsigned int*) 0x100000); printf("check1\n"); // CHECK: check1 // Switch to user mode, but leave MMU active switch_to_user_mode(); *((volatile unsigned int*) 0x100000) = 0x12; // CHECK: FAULT 8 00100000 current flags 06 prev flags 02 // XXX no way to verify that the write wasn't sent to external bus }
void panic(const char *format, ...) { va_list args; kprintf("KERNEL PANIC: "); va_start(args, format); vprintf(format, args); va_end(args); putchar('\n'); __builtin_nyuzi_write_control_reg(CR_SUSPEND_THREAD, -1); while (1); }
// Make this a call to flush the pipeline void __attribute__((noinline)) switchToUserMode(void) { __builtin_nyuzi_write_control_reg(4, 0); }
void unmask_interrupt(int interrupt) { int hwthid = current_hw_thread(); enabled_interrupts[hwthid] |= 1 << interrupt; __builtin_nyuzi_write_control_reg(CR_INTERRUPT_MASK, enabled_interrupts[hwthid]); }
void ack_interrupt(int interrupt) { __builtin_nyuzi_write_control_reg(CR_INTERRUPT_ACK, 1 << interrupt); }