static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) { if (dtrace_here) { printk("copycheck: uaddr=%p kaddr=%p size=%d\n", (void *) uaddr, (void*) kaddr, (int) size); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) if (__range_not_ok(uaddr, size)) { #else if (!addr_valid(uaddr) || !addr_valid(uaddr + size)) { #endif //printk("uaddr=%p size=%d\n", uaddr, size); DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[cpu_get_id()].cpuc_dtrace_illval = uaddr; return (0); } return (1); } # endif void dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { if (dtrace_memcpy_with_error((void *) kaddr, (void *) uaddr, size) == 0) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); return; } } void dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { if (dtrace_memcpy_with_error((void *) uaddr, (void *) kaddr, size) == 0) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); return; } } void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { if (dtrace_memcpy_with_error((void *) kaddr, (void *) uaddr, size) == 0) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); return; } } void dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { if (dtrace_memcpy_with_error((void *) kaddr, (void *) uaddr, size) == 0) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); return; } } uint8_t dtrace_fuword8(void *uaddr) { extern uint8_t dtrace_fuword8_nocheck(void *); if (!access_ok(VERIFY_READ, uaddr, 1)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); printk("dtrace_fuword8: uaddr=%p CPU_DTRACE_BADADDR\n", uaddr); cpu_core[cpu_get_id()].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword8_nocheck(uaddr)); } uint16_t dtrace_fuword16(void *uaddr) { extern uint16_t dtrace_fuword16_nocheck(void *); if (!access_ok(VERIFY_WRITE, uaddr, 2)) { printk("dtrace_fuword16: uaddr=%p CPU_DTRACE_BADADDR\n", uaddr); DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[cpu_get_id()].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword16_nocheck(uaddr)); } uint32_t dtrace_fuword32(void *uaddr) { extern uint32_t dtrace_fuword32_nocheck(void *); if (!addr_valid(uaddr)) { HERE2(); DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[cpu_get_id()].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword32_nocheck(uaddr)); } uint64_t dtrace_fuword64(void *uaddr) { extern uint64_t dtrace_fuword64_nocheck(void *); if (!addr_valid(uaddr)) { HERE2(); DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[cpu_get_id()].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword64_nocheck(uaddr)); }
/* write fn to device */ int nrf_program_nrf24lu(devp dev, const char *fn){ unsigned char cmd[2], data[64], *flash_copy, dirty_bv[64]; FILE *fp = NULL; int ecode, block, page, rc; unsigned int first_addr, last_addr; IHexRecord record; printf("Programming nRF24LU\n"); /* read the entire ROM into memory * * Why? Because Nordic doesn't have decent software. Their flash write * command erases the page first, instead of letting me decide if the page * should be erased first. * * Byte-level writing is offered by using a read-modify-write operation. * It would be smarter to operate on a per-page basis, but Intel HEX files * are not guaranteed to have sequential addressing. Since Nordic screwed * up and wild IHX files are adhoc, let's work with the whole 32k flash * memory at once. */ if((flash_copy = malloc(FLASH_SIZE)) == NULL){ ecode = -4; goto err; } printf("[*] Reading device.\n"); for(block = 0; block < 0x200; block++){ /* set address MSB */ if((block % 0x100) == 0){ cmd[0] = 0x06; cmd[1] = (unsigned char)(block / 256); if(nrf_cmd(dev, cmd, 2, data, 1)){ ecode = -2; goto err; } } /* request the block */ cmd[0] = 0x03; cmd[1] = (unsigned char)block; if(nrf_cmd(dev, cmd, 2, &flash_copy[block2addr(block)], 64)){ ecode = -2; goto err; } } /* overwrite in-memory with IHX contents */ if((fp = fopen(fn, "r")) == NULL){ ecode = -1; goto err; } memset(dirty_bv, 0, sizeof(dirty_bv)); while((rc = Read_IHexRecord(&record, fp)) == IHEX_OK && record.type != IHEX_TYPE_01){ if(record.type != IHEX_TYPE_00){ /* we cannot process segment or linear ihex files */ printf("[!] IHX file contains segment or linear addressing.\n"); ecode = -5; goto err; } /* first and last byte that is touched by this record */ first_addr = record.address; last_addr = record.address + record.dataLen - 1; if(!addr_valid(first_addr) || !addr_valid(last_addr)){ printf("[!] IHX record touches invalid or protected bytes: " "0x%04X - 0x%04X\n", first_addr, last_addr); ecode = -6; goto err; } /* only write if the ihx record changes memory */ if(memcmp(&flash_copy[first_addr], record.data, record.dataLen)){ /* copy record into memory */ memcpy(&flash_copy[first_addr], record.data, record.dataLen); /* mark dirty blocks */ for(block = addr2block(first_addr); block <= addr2block(last_addr); block++){ /* check the block since we might have some *really* long * record */ if(!addr_valid(block2addr(block))){ printf("[!] IHX record touches invalid or protected bytes:" " 0x%04X\n", block2addr(block)); ecode = -6; goto err; } bitset(dirty_bv, block); } } } if(rc != IHEX_OK && rc != IHEX_ERROR_EOF){ /* we had an error that isn't EOF */ ecode = -4; goto err; } /* write to flash */ printf("[*] Writing device"); fflush(stdout); for(page = 0; page < 64; page++){ /* Each page is 8 blocks, which conviently maps to our dirty bit vector * on byte boundries. */ if(dirty_bv[page]){ printf("."); fflush(stdout); if(nrf_write_page(dev, page, &flash_copy[page2addr(page)])){ printf("\n[!] Write failed.\n"); ecode = -7; goto err; } } } printf("\n"); /* verify */ printf("[*] Verifying device"); fflush(stdout); for(block = 0; block < 512; block++){ if(bitisset(dirty_bv, block)){ if(nrf_compare_block(dev, block, &flash_copy[block2addr(block)])){ printf("\n[!] Block %d failed.\n", block); ecode = -8; goto err; } else { printf("."); fflush(stdout); } } } printf("\n"); ecode = 0; err: if(flash_copy){ free(flash_copy); } if(fp){ fclose(fp); } return ecode; }