static void vfs_load_file_to_memory (const char *file, void **data, size_t *size) { assert(data != NULL); assert(size != NULL); errval_t err; vfs_handle_t vh; err = vfs_open(file, &vh); if (err_is_fail(err)) { USER_PANIC_ERR(err, "Error opening %s", file); } struct vfs_fileinfo info; err = vfs_stat(vh, &info); assert_err(err, "vfs_stat"); *data = malloc(info.size); assert(*data != NULL); err = vfs_read(vh, *data, info.size, size); assert_err(err, "vfs_read"); assert(*size == info.size); vfs_close(vh); }
// To reduce the number of string copies, this function calling pattern works as follows: // 1) The managed code calls GetDirentSize() to get the platform-specific // size of the dirent struct. // 2) The managed code creates a byte[] buffer of the size of the native dirent // and passes a pointer to this buffer to this function. // 3) This function passes input byte[] buffer to the OS to fill with dirent // data which makes the 1st strcpy. // 4) The ConvertDirent function will fill DirectoryEntry outputEntry with // pointers from byte[] buffer. // 5) The managed code uses DirectoryEntry outputEntry to find start of d_name // and the value of d_namelen, if avalable, to copy the name from // byte[] buffer into a managed string that the caller can use; this makes // the 2nd and final strcpy. extern "C" int32_t SystemNative_ReadDirR(DIR* dir, void* buffer, int32_t bufferSize, DirectoryEntry* outputEntry) { assert(buffer != nullptr); assert(dir != nullptr); assert(outputEntry != nullptr); if (bufferSize < static_cast<int32_t>(sizeof(dirent))) { assert(false && "Buffer size too small; use GetDirentSize to get required buffer size"); return ERANGE; } dirent* result = nullptr; dirent* entry = static_cast<dirent*>(buffer); #if HAVE_READDIR_R int error = readdir_r(dir, entry, &result); // positive error number returned -> failure if (error != 0) { assert(error > 0); *outputEntry = {}; // managed out param must be initialized return error; } // 0 returned with null result -> end-of-stream if (result == nullptr) { *outputEntry = {}; // managed out param must be initialized return -1; // shim convention for end-of-stream } // 0 returned with non-null result (guaranteed to be set to entry arg) -> success assert(result == entry); #else errno = 0; result = readdir(dir); // 0 returned with null result -> end-of-stream if (result == nullptr) { *outputEntry = {}; // managed out param must be initialized // kernel set errno -> failure if (errno != 0) { assert_err(errno == EBADF, "Invalid directory stream descriptor dir", errno); return errno; } return -1; } assert(result->d_reclen <= bufferSize); memcpy_s(entry, sizeof(dirent), result, static_cast<size_t>(result->d_reclen)); #endif ConvertDirent(*entry, outputEntry); return 0; }
int main(int argc, char* argv[]) { size_t size_wanted = 1<<20; size_t runs = 100; struct reset_opt *reset = NULL; struct measure_opt *measure = NULL; bool dump = false; assert(argc>0); if (argc == 1) { usage(argv[0]); return 0; } bool args_ok = true; for (int arg = 1; arg < argc; arg++) { if (strcmp(argv[arg], "help") == 0 || strcmp(argv[arg], "--help") == 0 || strcmp(argv[arg], "-h") == 0) { usage(argv[0]); return 0; } if (strncmp(argv[arg], "size=", 5) == 0) { size_wanted = atol(argv[arg]+5); } if (strncmp(argv[arg], "logsize=", 8) == 0) { size_t logsize = atol(argv[arg]+8); if (logsize > 31) { printf("ERROR: logsize too big\n"); args_ok = false; } else { size_wanted = 1 << logsize; } } else if (strncmp(argv[arg], "count=", 6) == 0) { size_wanted = atol(argv[arg]+6)*sizeof(struct cte); } else if (strncmp(argv[arg], "logcount=", 9) == 0) { size_t logcount = atol(argv[arg]+9); if (logcount > (31-OBJBITS_CTE)) { printf("ERROR: logcount too big\n"); args_ok = false; } else { size_wanted = (1 << logcount)*sizeof(struct cte); } } else if (strncmp(argv[arg], "runs=", 5) == 0) { runs = atol(argv[arg]+5); } else if (strncmp(argv[arg], "reset=", 6) == 0) { char *name = argv[arg]+6; int i; for (i = 0; reset_opts[i].name; i++) { if (strcmp(reset_opts[i].name, name) == 0) { reset = &reset_opts[i]; break; } } if (!reset_opts[i].name) { args_ok = false; printf("ERROR: unkown reset \"%s\"\n", name); } } else if (strncmp(argv[arg], "measure=", 8) == 0) { char *name = argv[arg]+8; if (strcmp(name, "dump") == 0) { measure = NULL; dump = true; } else { int i; for (i = 0; measure_opts[i].name; i++) { if (strcmp(measure_opts[i].name, name) == 0) { measure = &measure_opts[i]; break; } } if (measure_opts[i].name) { dump = false; } else { args_ok = false; printf("ERROR: unkown measure \"%s\"\n", name); } } } else { args_ok = false; printf("ERROR: unkown argument %s\n", argv[arg]); } } if (!args_ok) { usage(argv[0]); return 1; } assert(size_wanted > 0); assert(runs > 0); assert(reset); assert(measure || dump); errval_t err; struct capref frame; size_t size; err = frame_alloc(&frame, size_wanted, &size); assert_err(err, "alloc"); assert(size >= size_wanted); printf("got %lu bytes\n", size); struct memobj *m; struct vregion *v; void *addr; err = vspace_map_one_frame(&addr, size, frame, &m, &v); assert_err(err, "map"); if (dump) { reset_and_dump(addr, size_wanted, runs, reset->fn, reset->name); } else { bench_init(); char *bench_name = malloc(strlen(reset->name)+strlen(measure->name)+2); strcpy(bench_name, reset->name); strcat(bench_name, ":"); strcat(bench_name, measure->name); test(addr, size_wanted, runs, reset->fn, measure->fn, bench_name); free(bench_name); } printf("client done\n"); vregion_destroy(v); cap_destroy(frame); return 0; }
// To reduce the number of string copies, the caller of this function is responsible to ensure the memory // referenced by outputEntry remains valid until it is read. // If the platform supports readdir_r, the caller provides a buffer into which the data is read. // If the platform uses readdir, the caller must ensure no calls are made to readdir/closedir since those will invalidate // the current dirent. We assume the platform supports concurrent readdir calls to different DIRs. int32_t SystemNative_ReadDirR(DIR* dir, uint8_t* buffer, int32_t bufferSize, DirectoryEntry* outputEntry) { assert(dir != NULL); assert(outputEntry != NULL); #if HAVE_READDIR_R assert(buffer != NULL); // align to dirent struct dirent* entry = (struct dirent*)((size_t)(buffer + dirent_alignment - 1) & ~(dirent_alignment - 1)); // check there is dirent size available at entry if ((buffer + bufferSize) < ((uint8_t*)entry + sizeof(struct dirent))) { assert(false && "Buffer size too small; use GetReadDirRBufferSize to get required buffer size"); return ERANGE; } struct dirent* result = NULL; #ifdef _AIX // AIX returns 0 on success, but bizarrely, it returns 9 for both error and // end-of-directory. result is NULL for both cases. The API returns the // same thing for EOD/error, so disambiguation between the two is nearly // impossible without clobbering errno for yourself and seeing if the API // changed it. See: // https://www.ibm.com/support/knowledgecenter/ssw_aix_71/com.ibm.aix.basetrf2/readdir_r.htm errno = 0; // create a success condition for the API to clobber int error = readdir_r(dir, entry, &result); if (error == 9) { memset(outputEntry, 0, sizeof(*outputEntry)); // managed out param must be initialized return errno == 0 ? -1 : errno; } #else int error = readdir_r(dir, entry, &result); // positive error number returned -> failure if (error != 0) { assert(error > 0); memset(outputEntry, 0, sizeof(*outputEntry)); // managed out param must be initialized return error; } // 0 returned with null result -> end-of-stream if (result == NULL) { memset(outputEntry, 0, sizeof(*outputEntry)); // managed out param must be initialized return -1; // shim convention for end-of-stream } #endif // 0 returned with non-null result (guaranteed to be set to entry arg) -> success assert(result == entry); #else (void)buffer; // unused (void)bufferSize; // unused errno = 0; struct dirent* entry = readdir(dir); // 0 returned with null result -> end-of-stream if (entry == NULL) { memset(outputEntry, 0, sizeof(*outputEntry)); // managed out param must be initialized // kernel set errno -> failure if (errno != 0) { assert_err(errno == EBADF, "Invalid directory stream descriptor dir", errno); return errno; } return -1; } #endif ConvertDirent(entry, outputEntry); return 0; }
int main (int argc, char *argv[]) { errval_t err; char *cardName = NULL; const char *imagefile = IMAGEFILE; vfs_init(); err = timer_init(); if (err_is_fail(err)) { USER_PANIC_ERR(err, "error initialising timer client library\n"); } if (argc < 3) { printf("Usage: %s <Network card Name> <vfs mount URI> [disk image path]\n", argv[0]); printf("<Network card Name> value is ignored in this version\n"); return 1; } if(argc > 3) { imagefile = argv[3]; } cardName = argv[1]; printf("vmkitmon: start\n"); printf("Ignoring the cardname [%s], and using the default one from vfs_mount\n", cardName); vfs_mkdir(VFS_MOUNTPOINT); err = vfs_mount(VFS_MOUNTPOINT, argv[2]); if (err_is_fail(err)) { printf("vmkitmon: error mounting %s: %s\n", argv[2], err_getstring(err)); return 1; } /* Initialization */ err = realmode_init(); assert_err(err, "realmode_init"); // fetch all relevant multiboot data //load_multiboot_files(); // aquire the standard input #if 1 err = terminal_want_stdin(TERMINAL_SOURCE_SERIAL); assert_err(err, "terminal_want_stdin"); #endif // load files // FIXME: use a dynamic way to specify those arguments printf("Loading file [%s]\n", GRUB_IMG_PATH); vfs_load_file_to_memory(GRUB_IMG_PATH, &grub_image, &grub_image_size); printf("Loading file [%s]\n", imagefile); vfs_load_file_to_memory(imagefile, &hdd0_image, &hdd0_image_size); printf("Done with file loading\n"); /* Guest execution */ // perform some sanity checks if (grub_image == NULL) { printf("vmkitmon: no grub image available, abort\n"); return 1; } guest = guest_create (); assert(guest != NULL); err = guest_make_runnable(guest, true); assert_err(err, "guest_make_runnable"); printf("vmkitmon: end\n"); messages_handler_loop(); }