25 #include <sys/ioctl.h>
30 #include <sys/types.h>
44 #define dbg(fmt, ...) if (g_libeasynmc_debug) { \
45 fprintf(stderr, "libeasynmc: " fmt, ##__VA_ARGS__); \
48 #define err(fmt, ...) if (g_libeasynmc_errors) { \
49 fprintf(stderr, "libeasynmc: " fmt, ##__VA_ARGS__); \
53 static uint32_t supported_startupcodes[] = {
58 static void easynmc_warn_unsupported(uint32_t codever)
60 if (codever < 0x20141128) {
61 fprintf(stderr,
"Warning: IPL version in use is outdated!\n");
62 fprintf(stderr,
"Warning: This IPL does not support easynmc_appdata_*()!\n");
63 fprintf(stderr,
"Warning: This IPL does not support EASYNMC_STATE_KILLABLE!\n");
84 for (i=0; i<
ARRAY_SIZE(supported_startupcodes); i++) {
85 if (supported_startupcodes[i] == codever)
100 struct nmc_core_stats stats;
102 ret = ioctl(h->
iofd, IOCTL_NMC3_GET_STATS, &stats);
117 easynmc_warn_unsupported(codever);
125 static const char* statuses[] = {
145 return statuses[state];
157 return ioctl(h->
iofd, IOCTL_NMC3_GET_NAME, str);
169 return ioctl(h->
iofd, IOCTL_NMC3_GET_TYPE, str);
181 return ioctl(h->
iofd, IOCTL_NMC3_SEND_IRQ, &irq);
195 return ioctl(h->
iofd, IOCTL_NMC3_RESET_STATS, NULL);
206 ioctl(h->
iofd, IOCTL_NMC3_RESET, NULL);
210 static int str2nmc(uint32_t *dst,
char* src,
int len)
221 "/usr/share/easynmc-" LIBEASYNMC_VERSION
"/ipl/ipl-%s%s.abs",
222 "/usr/local/share/easynmc-" LIBEASYNMC_VERSION
"/ipl/ipl-%s%s.abs",
241 asprintf(&tmp, iplpaths[i], name, debug ?
"-debug" :
"");
242 dbg(
"trying: %s\n", tmp)
243 if (0 == access(tmp, R_OK))
298 dbg(
"opening core %d\n", coreid);
311 sprintf(path,
"/dev/nmc%dio", coreid);
312 h->
iofd = open(path, O_RDWR);
314 err(
"Couldn't open NMC IO device\n");
318 sprintf(path,
"/dev/nmc%d", coreid);
319 h->
memfd = open(path, O_RDWR);
321 err(
"Couldn't open NMC MEM device\n");
325 if (exclusive && (flock(h->
memfd, LOCK_EX | LOCK_NB) != 0))
330 err(
"Couldn't get NMC internal memory size\n");
335 if (h->
imem == MAP_FAILED) {
336 err(
"Couldn't MMAP internal memory\n");
342 dbg(
"Opened core %d iofd %d memfd %d. mmap imem %u bytes @ 0x%lx\n",
355 err(
"Device was: %s\n", path);
377 const char* startupfile = getenv(
"NMC_STARTUPCODE");
381 err(
"core already started, will not load ipl again\n");
393 err(
"Didn't find startup code file. Did you install one?\n");
394 err(
"HINT: You can set env variable NMC_STARTUPCODE\n");
398 dbg(
"Booting core using: %s file\n", startupfile);
405 err(
"ERROR: Startup code entry point must be 0x0!\n");
406 err(
"ERROR: We have 0x%x! Cowardly refusing to go further\n", ep);
425 dbg(
"Got evt %d\n", evt);
428 case EASYNMC_EVT_TIMEOUT:
429 err(
"Timeout waiting for initcode to start\n");
431 err(
"But init code reports being ready. \n");
432 err(
"Did you mix up HP and LP interrupts in DeviceTree?\n");
438 dbg(
"Initial code loaded & ready \n");
443 err(
"Did you mix up HP and LP interrupts in DeviceTree?\n");
525 int needspace = argc + strlen(
self) + 1;
528 err(
"No argument offset found for this handle\n");
532 for (i=0; i<argc; i++)
533 needspace += strlen(argv[i]) + 1;
536 err(
"Arguments exceed available space.\n");
548 *ptroff = dataoff - h->
imem32;
549 len = str2nmc(dataoff,
self, strlen(
self)+1);
552 for (i=0; i<argc; i++) {
553 ptroff[i+1] = dataoff - h->
imem32;
554 len = str2nmc(dataoff, argv[i], strlen(argv[i])+1);
599 err(
"ERROR: Attempt to load abs when core is '%s'\n", state);
600 err(
"ERROR: Will not do that unless --force'd\n");
604 FILE* rfd = fopen(path,
"rb");
609 if ((fd = open(path, O_RDONLY)) == -1) {
615 if(elf_version(EV_CURRENT) == EV_NONE)
617 err(
"WARNING: Elf Library is out of date!\n");
620 if ((elf = elf_begin(fd, ELF_C_READ , NULL)) == NULL) {
621 err(
"elf_begin() failed: %s.",
626 if (gelf_getehdr(elf, &ehdr) == NULL) {
627 err(
"getehdr() failed: %s.",
632 if ((i = gelf_getclass(elf)) == ELFCLASSNONE) {
633 err(
"getclass() failed: %s.",
638 dbg(
"ELF Looks like a %d-bit ELF object\n",
639 i == ELFCLASS32 ? 32 : 64);
641 if ((
id = elf_getident(elf, NULL)) == NULL) {
642 err(
"getident() failed: %s.",
647 dbg(
"ELF Machine id: 0x%x\n", ehdr.e_machine);
651 elf = elf_begin(fd, ELF_C_READ , NULL);
655 while((scn = elf_nextscn(elf, scn)) != 0)
657 char* why_skip = NULL;
658 gelf_getshdr(scn, &shdr);
659 char* name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
660 int addr = shdr.sh_addr << 2;
662 if (shdr.sh_size == 0)
663 why_skip =
"(empty section)";
665 if (0==strcmp(name,
".memBankMap")) {
666 why_skip =
"(not needed)";
669 if (0==strcmp(name,
".shstrtab")) {
670 why_skip =
"(not needed)";
673 if (shdr.sh_type == SHT_NOBITS) {
674 why_skip =
"(nobits)";
675 memset(&h->
imem[addr], 0x0, shdr.sh_size);
678 if (0==strcmp(name,
".bss")) {
679 why_skip =
"(cleansing)";
680 memset(&h->
imem[addr], 0x0, shdr.sh_size);
684 dbg(
"%s section %s %s %ld bytes @ 0x%x\n",
685 why_skip ?
"Skipping" :
"Uploading",
687 why_skip ? why_skip :
"",
688 (
unsigned long) shdr.sh_size,
695 ret = fseek(rfd, shdr.sh_offset, SEEK_SET);
697 err(
"Seek failed, bad elf\n");
700 dbg(
"read to %d size %ld\n", addr, (
unsigned long) shdr.sh_size);
701 ret = fread(&h->
imem[addr], 1, shdr.sh_size, rfd);
702 if (ret != shdr.sh_size ) {
703 err(
"Ooops, failed to read all data: want %ld got %zd\n",
704 (
unsigned long) shdr.sh_size, ret);
714 while (!handled && f) {
715 dbg(
"Aplying section filter %s\n", f->
name);
723 dbg(
"Elvish loading done!\n");
787 err(
"App not running, won't stop it\n");
802 dbg(
"timeout remaining %d\n", timeout);
804 return timeout ? 0 : 1;
825 while (tail->
next != NULL)
905 FILE *fd = fopen(
"/proc/nmc",
"r");
907 err(
"/proc/nmc open failed\n");
912 while (fgets(tmp, 512, fd)) {
915 if (1 == sscanf(tmp,
"/dev/nmc%d", &coreid)) {
919 int result = core_cb(h, udata);
949 dbg(
"close core id %d \n", hndl->
id);
954 flock(hndl->
memfd, LOCK_UN);
989 ret = ioctl(t->
h->
iofd, IOCTL_NMC3_RESET_TOKEN, &t->
tok);
992 dbg(
"New token id %d\n", t->
tok.id);
1012 t->
tok.events_enabled = events;
1031 case EASYNMC_EVT_LP:
1033 case EASYNMC_EVT_HP:
1035 case EASYNMC_EVT_NMI:
1037 case EASYNMC_EVT_ERROR:
1039 case EASYNMC_EVT_CANCELLED:
1041 case EASYNMC_EVT_TIMEOUT:
1057 t->
tok.timeout = timeout;
1058 ret = ioctl(t->
h->
iofd, IOCTL_NMC3_WAIT_ON_TOKEN, &t->
tok);
1060 err(
"ioctl returned %d\n", ret);
1062 return EASYNMC_EVT_ERROR;
1064 return t->
tok.event;
1099 return ioctl(h->
iofd, IOCTL_NMC3_POLLMARK, NULL);
1148 struct easynmc_connect_info {
1154 static int connect_core_cb(
struct easynmc_handle *h,
void *udata)
1156 struct easynmc_connect_info *i = udata;
1160 if (flock(h->
memfd, LOCK_EX | LOCK_NB) != 0)
1191 struct easynmc_connect_info i;
1196 i.desth->persistent = 1;
1201 struct easynmc_appdata {
1219 if (!raw_appdata_size(h))
1222 return raw_appdata_size(h) -
sizeof(
struct easynmc_appdata);
1225 static int kernel_appdata_get(
struct easynmc_handle *h,
struct nmc_ioctl_buffer *buf)
1227 if (!raw_appdata_size(h))
1230 int ret = ioctl(h->
iofd, IOCTL_NMC3_GET_APPDATA, buf);
1231 dbg(
"kernel appdata get: %d len %zu\n", ret, buf->len);
1235 static int kernel_appdata_set(
struct easynmc_handle *h,
struct nmc_ioctl_buffer *buf)
1237 int ret = ioctl(h->
iofd, IOCTL_NMC3_SET_APPDATA, buf);
1243 dbg(
"kernel appdata set: %d len %zu\n", ret, buf->len);
1259 size_t dlen = len +
sizeof(
struct easynmc_appdata);
1260 struct easynmc_appdata *adata = alloca(dlen);
1261 struct nmc_ioctl_buffer buf;
1266 ret = kernel_appdata_get(h, &buf);
1267 if (ret == -ENODATA) {
1268 adata->appid[0]=0x0;
1272 memcpy(adata->userdata, data, len);
1273 return kernel_appdata_set(h, &buf);
1289 size_t dlen = raw_appdata_size(h);
1293 size_t actual_length = raw_appdata_size(h) -
1294 sizeof(
struct easynmc_appdata);
1296 struct easynmc_appdata *adata = alloca(dlen);
1297 struct nmc_ioctl_buffer buf;
1301 ret = kernel_appdata_get(h, &buf);
1304 size_t tocopy = (len < actual_length) ? len : actual_length;
1305 memcpy(data, adata->userdata, tocopy);
1325 h->
appid = strdup(appid);
1327 size_t rawsize = raw_appdata_size(h);
1330 rawsize =
sizeof(
struct easynmc_appdata);
1332 struct easynmc_appdata *adata = alloca(rawsize);
1333 struct nmc_ioctl_buffer buf;
1337 ret = kernel_appdata_get(h, &buf);
1338 if (ret && (ret != -ENODATA))
1346 return kernel_appdata_set(h, &buf);
1361 return (
const char*) h->
appid;
1367 size_t sz =
sizeof(
struct easynmc_appdata);
1368 struct easynmc_appdata *adata = alloca(sz);
1369 struct nmc_ioctl_buffer buf;
1372 ret = kernel_appdata_get(h, &buf);
1375 h->
appid = strdup(adata->appid);
1396 int ret = ioctl(h->
iofd, IOCTL_NMC3_NMI_ON_CLOSE, &status);